提交 a5f07bfc 编写于 作者: V vsadov

Fix missing variance checks for ref returning methods/properties

Fixes:#17140
上级 cc96e013
......@@ -740,20 +740,23 @@ internal bool MethodGroupIsCompatibleWithDelegate(BoundExpression receiverOpt, b
}
}
// - Return types "match"
var returnsMatch =
method.ReturnsVoid && delegateMethod.ReturnsVoid ||
Conversions.HasIdentityOrImplicitReferenceConversion(method.ReturnType, delegateMethod.ReturnType, ref useSiteDiagnostics);
if (!returnsMatch)
if (delegateMethod.ReturnsByRef != method.ReturnsByRef)
{
Error(diagnostics, ErrorCode.ERR_BadRetType, errorLocation, method, method.ReturnType);
Error(diagnostics, ErrorCode.ERR_DelegateRefMismatch, errorLocation, method, delegateType);
diagnostics.Add(errorLocation, useSiteDiagnostics);
return false;
}
if (method.ReturnsByRef != delegateMethod.ReturnsByRef)
bool returnsMatch = delegateMethod.ReturnsByRef?
// - Return types identity-convertible
Conversions.HasIdentityConversion(method.ReturnType, delegateMethod.ReturnType):
// - Return types "match"
method.ReturnsVoid && delegateMethod.ReturnsVoid ||
Conversions.HasIdentityOrImplicitReferenceConversion(method.ReturnType, delegateMethod.ReturnType, ref useSiteDiagnostics);
if (!returnsMatch)
{
Error(diagnostics, ErrorCode.ERR_DelegateRefMismatch, errorLocation, method, delegateType);
Error(diagnostics, ErrorCode.ERR_BadRetType, errorLocation, method, method.ReturnType);
diagnostics.Add(errorLocation, useSiteDiagnostics);
return false;
}
......
......@@ -94,7 +94,7 @@ private static void CheckMethodVarianceSafety(this MethodSymbol method, Location
IsVarianceUnsafe(
method.ReturnType,
requireOutputSafety: true,
requireInputSafety: false,
requireInputSafety: method.RefKind != RefKind.None,
context: method,
locationProvider: returnTypeLocationProvider,
locationArg: method,
......@@ -115,7 +115,7 @@ private static void CheckPropertyVarianceSafety(PropertySymbol property, Diagnos
IsVarianceUnsafe(
property.Type,
requireOutputSafety: hasGetter,
requireInputSafety: hasSetter,
requireInputSafety: hasSetter || !(property.GetMethod?.RefKind == RefKind.None),
context: property,
locationProvider: p =>
{
......
......@@ -2933,5 +2933,393 @@ public void M()
);
}
[Fact]
public void RefReturnVarianceDelegate()
{
var source = @"
using System;
delegate ref T RefFunc1<T>();
delegate ref T RefFunc2<in T>();
delegate ref T RefFunc3<out T>();
delegate ref Action<T> RefFunc1a<T>();
delegate ref Action<T> RefFunc2a<in T>();
delegate ref Action<T> RefFunc3a<out T>();
delegate ref Func<T> RefFunc1f<T>();
delegate ref Func<T> RefFunc2f<in T>();
delegate ref Func<T> RefFunc3f<out T>();
";
CreateCompilationWithMscorlib45AndCSruntime(source).VerifyEmitDiagnostics(
// (6,10): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'RefFunc3<T>.Invoke()'. 'T' is covariant.
// delegate ref T RefFunc3<out T>();
Diagnostic(ErrorCode.ERR_UnexpectedVariance, "ref T").WithArguments("RefFunc3<T>.Invoke()", "T", "covariant", "invariantly").WithLocation(6, 10),
// (5,10): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'RefFunc2<T>.Invoke()'. 'T' is contravariant.
// delegate ref T RefFunc2<in T>();
Diagnostic(ErrorCode.ERR_UnexpectedVariance, "ref T").WithArguments("RefFunc2<T>.Invoke()", "T", "contravariant", "invariantly").WithLocation(5, 10),
// (14,10): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'RefFunc3f<T>.Invoke()'. 'T' is covariant.
// delegate ref Func<T> RefFunc3f<out T>();
Diagnostic(ErrorCode.ERR_UnexpectedVariance, "ref Func<T>").WithArguments("RefFunc3f<T>.Invoke()", "T", "covariant", "invariantly").WithLocation(14, 10),
// (13,10): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'RefFunc2f<T>.Invoke()'. 'T' is contravariant.
// delegate ref Func<T> RefFunc2f<in T>();
Diagnostic(ErrorCode.ERR_UnexpectedVariance, "ref Func<T>").WithArguments("RefFunc2f<T>.Invoke()", "T", "contravariant", "invariantly").WithLocation(13, 10),
// (10,10): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'RefFunc3a<T>.Invoke()'. 'T' is covariant.
// delegate ref Action<T> RefFunc3a<out T>();
Diagnostic(ErrorCode.ERR_UnexpectedVariance, "ref Action<T>").WithArguments("RefFunc3a<T>.Invoke()", "T", "covariant", "invariantly").WithLocation(10, 10),
// (9,10): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'RefFunc2a<T>.Invoke()'. 'T' is contravariant.
// delegate ref Action<T> RefFunc2a<in T>();
Diagnostic(ErrorCode.ERR_UnexpectedVariance, "ref Action<T>").WithArguments("RefFunc2a<T>.Invoke()", "T", "contravariant", "invariantly").WithLocation(9, 10)
);
}
[Fact]
public void RefReturnVarianceMethod()
{
var source = @"
using System;
interface IM1<T> { ref T RefMethod(); }
interface IM2<in T> { ref T RefMethod(); }
interface IM3<out T> { ref T RefMethod(); }
interface IM1a<T> { ref Action<T> RefMethod(); }
interface IM2a<in T> { ref Action<T> RefMethod(); }
interface IM3a<out T> { ref Action<T> RefMethod(); }
interface IM1f<T> { ref Func<T> RefMethod(); }
interface IM2f<in T> { ref Func<T> RefMethod(); }
interface IM3f<out T> { ref Func<T> RefMethod(); }
";
CreateCompilationWithMscorlib45AndCSruntime(source).VerifyEmitDiagnostics(
// (6,24): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'IM3<T>.RefMethod()'. 'T' is covariant.
// interface IM3<out T> { ref T RefMethod(); }
Diagnostic(ErrorCode.ERR_UnexpectedVariance, "ref T").WithArguments("IM3<T>.RefMethod()", "T", "covariant", "invariantly").WithLocation(6, 24),
// (10,25): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'IM3a<T>.RefMethod()'. 'T' is covariant.
// interface IM3a<out T> { ref Action<T> RefMethod(); }
Diagnostic(ErrorCode.ERR_UnexpectedVariance, "ref Action<T>").WithArguments("IM3a<T>.RefMethod()", "T", "covariant", "invariantly").WithLocation(10, 25),
// (9,24): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'IM2a<T>.RefMethod()'. 'T' is contravariant.
// interface IM2a<in T> { ref Action<T> RefMethod(); }
Diagnostic(ErrorCode.ERR_UnexpectedVariance, "ref Action<T>").WithArguments("IM2a<T>.RefMethod()", "T", "contravariant", "invariantly").WithLocation(9, 24),
// (13,24): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'IM2f<T>.RefMethod()'. 'T' is contravariant.
// interface IM2f<in T> { ref Func<T> RefMethod(); }
Diagnostic(ErrorCode.ERR_UnexpectedVariance, "ref Func<T>").WithArguments("IM2f<T>.RefMethod()", "T", "contravariant", "invariantly").WithLocation(13, 24),
// (14,25): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'IM3f<T>.RefMethod()'. 'T' is covariant.
// interface IM3f<out T> { ref Func<T> RefMethod(); }
Diagnostic(ErrorCode.ERR_UnexpectedVariance, "ref Func<T>").WithArguments("IM3f<T>.RefMethod()", "T", "covariant", "invariantly").WithLocation(14, 25),
// (5,23): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'IM2<T>.RefMethod()'. 'T' is contravariant.
// interface IM2<in T> { ref T RefMethod(); }
Diagnostic(ErrorCode.ERR_UnexpectedVariance, "ref T").WithArguments("IM2<T>.RefMethod()", "T", "contravariant", "invariantly").WithLocation(5, 23)
);
}
[Fact]
public void RefReturnVarianceProperty()
{
var source = @"
using System;
interface IP1<T> { ref T RefProp{get;} }
interface IP2<in T> { ref T RefProp{get;} }
interface IP3<out T> { ref T RefProp{get;} }
interface IP1a<T> { ref Action<T> RefProp{get;} }
interface IP2a<in T> { ref Action<T> RefProp{get;} }
interface IP3a<out T> { ref Action<T> RefProp{get;} }
interface IP1f<T> { ref Func<T> RefProp{get;} }
interface IP2f<in T> { ref Func<T> RefProp{get;} }
interface IP3f<out T> { ref Func<T> RefProp{get;} }
";
CreateCompilationWithMscorlib45AndCSruntime(source).VerifyEmitDiagnostics(
// (5,23): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'IP2<T>.RefProp'. 'T' is contravariant.
// interface IP2<in T> { ref T RefProp{get;} }
Diagnostic(ErrorCode.ERR_UnexpectedVariance, "ref T").WithArguments("IP2<T>.RefProp", "T", "contravariant", "invariantly").WithLocation(5, 23),
// (13,24): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'IP2f<T>.RefProp'. 'T' is contravariant.
// interface IP2f<in T> { ref Func<T> RefProp{get;} }
Diagnostic(ErrorCode.ERR_UnexpectedVariance, "ref Func<T>").WithArguments("IP2f<T>.RefProp", "T", "contravariant", "invariantly").WithLocation(13, 24),
// (9,24): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'IP2a<T>.RefProp'. 'T' is contravariant.
// interface IP2a<in T> { ref Action<T> RefProp{get;} }
Diagnostic(ErrorCode.ERR_UnexpectedVariance, "ref Action<T>").WithArguments("IP2a<T>.RefProp", "T", "contravariant", "invariantly").WithLocation(9, 24),
// (10,25): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'IP3a<T>.RefProp'. 'T' is covariant.
// interface IP3a<out T> { ref Action<T> RefProp{get;} }
Diagnostic(ErrorCode.ERR_UnexpectedVariance, "ref Action<T>").WithArguments("IP3a<T>.RefProp", "T", "covariant", "invariantly").WithLocation(10, 25),
// (14,25): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'IP3f<T>.RefProp'. 'T' is covariant.
// interface IP3f<out T> { ref Func<T> RefProp{get;} }
Diagnostic(ErrorCode.ERR_UnexpectedVariance, "ref Func<T>").WithArguments("IP3f<T>.RefProp", "T", "covariant", "invariantly").WithLocation(14, 25),
// (6,24): error CS1961: Invalid variance: The type parameter 'T' must be invariantly valid on 'IP3<T>.RefProp'. 'T' is covariant.
// interface IP3<out T> { ref T RefProp{get;} }
Diagnostic(ErrorCode.ERR_UnexpectedVariance, "ref T").WithArguments("IP3<T>.RefProp", "T", "covariant", "invariantly").WithLocation(6, 24)
);
}
[Fact]
public void RefMethodGroupConversionError()
{
var source = @"
using System;
class Program
{
delegate ref T RefFunc1<T>();
static void Main()
{
RefFunc1<object> f = M1;
f() = 1;
}
static ref string M1() => ref new string[]{""qq""}[0];
}
";
CreateCompilationWithMscorlib45AndCSruntime(source).VerifyEmitDiagnostics(
// (10,30): error CS0407: 'string Program.M1()' has the wrong return type
// RefFunc1<object> f = M1;
Diagnostic(ErrorCode.ERR_BadRetType, "M1").WithArguments("Program.M1()", "string").WithLocation(10, 30)
);
}
[Fact]
public void RefMethodGroupConversionError_WihResolution()
{
var source = @"
using System;
class Base
{
public static Base Instance = new Base();
}
class Derived1: Base
{
public static new Derived1 Instance = new Derived1();
}
class Derived2: Derived1
{
}
class Derived3: Derived2
{
}
class Program
{
delegate ref TResult RefFunc1<TArg, TResult>(TArg arg);
static void Main()
{
RefFunc1<Derived2, Base> f = M1;
System.Console.WriteLine(f(null));
}
static ref Base M1(Base arg) => ref Base.Instance;
static ref Derived1 M1(Derived1 arg) => ref Derived1.Instance;
}
";
CreateCompilationWithMscorlib45AndCSruntime(source).VerifyEmitDiagnostics(
// (28,38): error CS0407: 'Derived1 Program.M1(Derived1)' has the wrong return type
// RefFunc1<Derived2, Base> f = M1;
Diagnostic(ErrorCode.ERR_BadRetType, "M1").WithArguments("Program.M1(Derived1)", "Derived1").WithLocation(28, 38)
);
}
[Fact]
public void RefMethodGroupConversionNoError_WihResolution()
{
var source = @"
using System;
class Base
{
public static Base Instance = new Base();
}
class Derived1 : Base
{
public static new Derived1 Instance = new Derived1();
}
class Derived2 : Derived1
{
public static new Derived2 Instance = new Derived2();
}
class Derived3 : Derived2
{
}
class Program
{
delegate ref TResult RefFunc1<TArg, TResult>(TArg arg);
static void Main()
{
RefFunc1<Derived2, Base> f = M1;
System.Console.WriteLine(f(null));
}
static ref Base M1(Base arg) => throw null;
static ref Base M1(Derived1 arg) => ref Base.Instance;
}
";
CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: "Base", verify: true);
}
[Fact]
public void RefMethodGroupOevrloadResolutionErr()
{
var source = @"
using System;
class Base
{
public static Base Instance = new Base();
}
class Derived1: Base
{
public static new Derived1 Instance = new Derived1();
}
class Derived2: Derived1
{
public static new Derived2 Instance = new Derived2();
}
class Derived3: Derived2
{
}
class Program
{
delegate ref TResult RefFunc1<TArg, TResult>(TArg arg);
static void Main()
{
Test(M1);
Test(M3);
}
static ref Base M1(Derived1 arg) => ref Base.Instance;
static ref Base M3(Derived2 arg) => ref Base.Instance;
static void Test(RefFunc1<Derived2, Base> arg) => Console.WriteLine(arg);
static void Test(RefFunc1<Derived2, Derived1> arg) => Console.WriteLine(arg);
}
";
CreateCompilationWithMscorlib45AndCSruntime(source).VerifyEmitDiagnostics(
// (29,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.Test(Program.RefFunc1<Derived2, Base>)' and 'Program.Test(Program.RefFunc1<Derived2, Derived1>)'
// Test(M1);
Diagnostic(ErrorCode.ERR_AmbigCall, "Test").WithArguments("Program.Test(Program.RefFunc1<Derived2, Base>)", "Program.Test(Program.RefFunc1<Derived2, Derived1>)").WithLocation(29, 9),
// (30,9): error CS0121: The call is ambiguous between the following methods or properties: 'Program.Test(Program.RefFunc1<Derived2, Base>)' and 'Program.Test(Program.RefFunc1<Derived2, Derived1>)'
// Test(M3);
Diagnostic(ErrorCode.ERR_AmbigCall, "Test").WithArguments("Program.Test(Program.RefFunc1<Derived2, Base>)", "Program.Test(Program.RefFunc1<Derived2, Derived1>)").WithLocation(30, 9)
);
}
[Fact]
public void RefMethodGroupOverloadResolution()
{
var source = @"
using System;
class Base
{
public static Base Instance = new Base();
}
class Derived1: Base
{
public static new Derived1 Instance = new Derived1();
}
class Derived2: Derived1
{
public static new Derived2 Instance = new Derived2();
}
class Derived3: Derived2
{
}
class Program
{
delegate ref TResult RefFunc1<TArg, TResult>(TArg arg);
static void Main()
{
Test(M2);
}
static ref Derived1 M2(Base arg) => ref Derived1.Instance;
static void Test(RefFunc1<Derived2, Base> arg) => Console.WriteLine(arg);
static void Test(RefFunc1<Derived2, Derived1> arg) => Console.WriteLine(arg);
}
";
CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: "Program+RefFunc1`2[Derived2,Derived1]", verify: true);
}
[Fact]
public void RefLambdaOverloadResolution2()
{
var source = @"
using System;
class Base
{
public static Base Instance = new Base();
}
class Derived1: Base
{
public static new Derived1 Instance = new Derived1();
}
class Derived2: Derived1
{
public static new Derived2 Instance = new Derived2();
}
class Program
{
delegate ref TResult RefFunc1<TArg, TResult>(TArg arg);
static void Main()
{
Test((t)=> Base.Instance);
Test((t)=> ref Base.Instance);
}
static void Test(RefFunc1<Derived1, Base> arg) => Console.WriteLine(arg);
static void Test(Func<Derived1, Base> arg) => Console.WriteLine(arg);
}
";
CompileAndVerify(source, parseOptions: TestOptions.Regular, expectedOutput: @"System.Func`2[Derived1,Base]
Program+RefFunc1`2[Derived1,Base]", verify: true);
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册