diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/BestTypeInferrer.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/BestTypeInferrer.cs index d3059e2cd3647..412fe53b7a8fd 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/BestTypeInferrer.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/BestTypeInferrer.cs @@ -256,8 +256,8 @@ public static NullableFlowState GetNullableState(ArrayBuilder typ } var conversionsWithoutNullability = conversions.WithNullability(false); - var t1tot2 = conversionsWithoutNullability.ClassifyImplicitConversionFromType(type1, type2, ref useSiteInfo).Exists; - var t2tot1 = conversionsWithoutNullability.ClassifyImplicitConversionFromType(type2, type1, ref useSiteInfo).Exists; + var t1tot2 = conversionsWithoutNullability.ClassifyImplicitConversionFromTypeWhenNeitherOrBothFunctionTypes(type1, type2, ref useSiteInfo).Exists; + var t2tot1 = conversionsWithoutNullability.ClassifyImplicitConversionFromTypeWhenNeitherOrBothFunctionTypes(type2, type1, ref useSiteInfo).Exists; if (t1tot2 && t2tot1) { diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs index 2fcb3c077b57d..8ece6a379b6f7 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/ConversionsBase.cs @@ -75,6 +75,7 @@ internal ConversionsBase WithNullability(bool includeNullability) internal AssemblySymbol CorLibrary { get { return corLibrary; } } +#nullable enable /// /// Determines if the source expression is convertible to the destination type via /// any built-in or user-defined implicit conversion. @@ -84,10 +85,10 @@ public Conversion ClassifyImplicitConversionFromExpression(BoundExpression sourc Debug.Assert(sourceExpression != null); Debug.Assert((object)destination != null); - var sourceType = sourceExpression.GetTypeOrFunctionType(); + var sourceType = sourceExpression.Type; //PERF: identity conversion is by far the most common implicit conversion, check for that first - if ((object)sourceType != null && HasIdentityConversionInternal(sourceType, destination)) + if (sourceType is { } && HasIdentityConversionInternal(sourceType, destination)) { return Conversion.Identity; } @@ -98,7 +99,7 @@ public Conversion ClassifyImplicitConversionFromExpression(BoundExpression sourc return conversion; } - if ((object)sourceType != null) + if (sourceType is { }) { // Try using the short-circuit "fast-conversion" path. Conversion fastConversion = FastClassifyConversion(sourceType, destination); @@ -118,6 +119,13 @@ public Conversion ClassifyImplicitConversionFromExpression(BoundExpression sourc } } } + else if (sourceExpression.GetFunctionType() is { } sourceFunctionType) + { + if (HasImplicitFunctionTypeConversion(sourceFunctionType, destination, ref useSiteInfo)) + { + return Conversion.FunctionType; + } + } conversion = GetImplicitUserDefinedConversion(sourceExpression, sourceType, destination, ref useSiteInfo); if (conversion.Exists) @@ -171,6 +179,34 @@ public Conversion ClassifyImplicitConversionFromType(TypeSymbol source, TypeSymb return GetImplicitUserDefinedConversion(null, source, destination, ref useSiteInfo); } + /// + /// Helper method that calls or + /// depending on whether the + /// types are instances. + /// Used by method type inference and best common type only. + /// + public Conversion ClassifyImplicitConversionFromTypeWhenNeitherOrBothFunctionTypes(TypeSymbol source, TypeSymbol destination, ref CompoundUseSiteInfo useSiteInfo) + { + var sourceFunctionType = source as FunctionTypeSymbol; + var destinationFunctionType = destination as FunctionTypeSymbol; + + if (sourceFunctionType is null && destinationFunctionType is null) + { + return ClassifyImplicitConversionFromType(source, destination, ref useSiteInfo); + } + + if (sourceFunctionType is { } && destinationFunctionType is { }) + { + return HasImplicitFunctionTypeToFunctionTypeConversion(sourceFunctionType, destinationFunctionType, ref useSiteInfo) ? + Conversion.FunctionType : + Conversion.NoConversion; + } + + Debug.Assert(false); + return Conversion.NoConversion; + } +#nullable disable + /// /// Determines if the source expression of given type is convertible to the destination type via /// any built-in or user-defined conversion. @@ -513,10 +549,57 @@ public Conversion ClassifyStandardConversion(BoundExpression sourceExpression, T return Conversion.NoConversion; } + private static bool IsStandardImplicitConversionFromExpression(ConversionKind kind) + { + if (IsStandardImplicitConversionFromType(kind)) + { + return true; + } + + // See comment in ClassifyStandardImplicitConversion(BoundExpression, ...) + // where the set of standard implicit conversions is extended from the spec + // to include conversions from expression. + switch (kind) + { + case ConversionKind.AnonymousFunction: + case ConversionKind.MethodGroup: + case ConversionKind.ImplicitEnumeration: + case ConversionKind.ImplicitDynamic: + case ConversionKind.ImplicitNullToPointer: + case ConversionKind.ImplicitTupleLiteral: + case ConversionKind.StackAllocToPointerType: + case ConversionKind.StackAllocToSpanType: + return true; + default: + return false; + } + } + + // See https://github.com/dotnet/csharplang/blob/main/spec/conversions.md#standard-conversions: + // "The standard conversions are those pre-defined conversions that can occur as part of a user-defined conversion." + private static bool IsStandardImplicitConversionFromType(ConversionKind kind) + { + switch (kind) + { + case ConversionKind.Identity: + case ConversionKind.ImplicitNumeric: + case ConversionKind.ImplicitNullable: + case ConversionKind.ImplicitReference: + case ConversionKind.Boxing: + case ConversionKind.ImplicitConstant: + case ConversionKind.ImplicitPointer: + case ConversionKind.ImplicitPointerToVoid: + case ConversionKind.ImplicitTuple: + return true; + default: + return false; + } + } + private Conversion ClassifyStandardImplicitConversion(BoundExpression sourceExpression, TypeSymbol source, TypeSymbol destination, ref CompoundUseSiteInfo useSiteInfo) { Debug.Assert(sourceExpression != null || (object)source != null); - Debug.Assert(sourceExpression == null || (object)sourceExpression.GetTypeOrFunctionType() == (object)source); + Debug.Assert(sourceExpression == null || (object)sourceExpression.Type == (object)source); Debug.Assert((object)destination != null); // SPEC: The following implicit conversions are classified as standard implicit conversions: @@ -550,6 +633,7 @@ private Conversion ClassifyStandardImplicitConversion(BoundExpression sourceExpr Conversion conversion = ClassifyImplicitBuiltInConversionFromExpression(sourceExpression, source, destination, ref useSiteInfo); if (conversion.Exists) { + Debug.Assert(IsStandardImplicitConversionFromExpression(conversion.Kind)); return conversion; } @@ -563,59 +647,65 @@ private Conversion ClassifyStandardImplicitConversion(BoundExpression sourceExpr private Conversion ClassifyStandardImplicitConversion(TypeSymbol source, TypeSymbol destination, ref CompoundUseSiteInfo useSiteInfo) { - Debug.Assert((object)source != null); - Debug.Assert((object)destination != null); + var conversion = classifyConversion(source, destination, ref useSiteInfo); + Debug.Assert(conversion.Kind == ConversionKind.NoConversion || IsStandardImplicitConversionFromType(conversion.Kind)); + return conversion; - if (HasIdentityConversionInternal(source, destination)) + Conversion classifyConversion(TypeSymbol source, TypeSymbol destination, ref CompoundUseSiteInfo useSiteInfo) { - return Conversion.Identity; - } + Debug.Assert((object)source != null); + Debug.Assert((object)destination != null); - if (HasImplicitNumericConversion(source, destination)) - { - return Conversion.ImplicitNumeric; - } + if (HasIdentityConversionInternal(source, destination)) + { + return Conversion.Identity; + } - var nullableConversion = ClassifyImplicitNullableConversion(source, destination, ref useSiteInfo); - if (nullableConversion.Exists) - { - return nullableConversion; - } + if (HasImplicitNumericConversion(source, destination)) + { + return Conversion.ImplicitNumeric; + } - if (source is FunctionTypeSymbol functionType) - { - return HasImplicitFunctionTypeConversion(functionType, destination, ref useSiteInfo) ? - Conversion.FunctionType : - Conversion.NoConversion; - } + var nullableConversion = ClassifyImplicitNullableConversion(source, destination, ref useSiteInfo); + if (nullableConversion.Exists) + { + return nullableConversion; + } - if (HasImplicitReferenceConversion(source, destination, ref useSiteInfo)) - { - return Conversion.ImplicitReference; - } + if (source is FunctionTypeSymbol) + { + Debug.Assert(false); + return Conversion.NoConversion; + } - if (HasBoxingConversion(source, destination, ref useSiteInfo)) - { - return Conversion.Boxing; - } + if (HasImplicitReferenceConversion(source, destination, ref useSiteInfo)) + { + return Conversion.ImplicitReference; + } - if (HasImplicitPointerToVoidConversion(source, destination)) - { - return Conversion.PointerToVoid; - } + if (HasBoxingConversion(source, destination, ref useSiteInfo)) + { + return Conversion.Boxing; + } - if (HasImplicitPointerConversion(source, destination, ref useSiteInfo)) - { - return Conversion.ImplicitPointer; - } + if (HasImplicitPointerToVoidConversion(source, destination)) + { + return Conversion.PointerToVoid; + } - var tupleConversion = ClassifyImplicitTupleConversion(source, destination, ref useSiteInfo); - if (tupleConversion.Exists) - { - return tupleConversion; - } + if (HasImplicitPointerConversion(source, destination, ref useSiteInfo)) + { + return Conversion.ImplicitPointer; + } - return Conversion.NoConversion; + var tupleConversion = ClassifyImplicitTupleConversion(source, destination, ref useSiteInfo); + if (tupleConversion.Exists) + { + return tupleConversion; + } + + return Conversion.NoConversion; + } } private Conversion ClassifyImplicitBuiltInConversionSlow(TypeSymbol source, TypeSymbol destination, ref CompoundUseSiteInfo useSiteInfo) @@ -867,7 +957,7 @@ private static bool ExplicitConversionMayDifferFromImplicit(Conversion implicitC private Conversion ClassifyImplicitBuiltInConversionFromExpression(BoundExpression sourceExpression, TypeSymbol source, TypeSymbol destination, ref CompoundUseSiteInfo useSiteInfo) { Debug.Assert(sourceExpression != null || (object)source != null); - Debug.Assert(sourceExpression == null || (object)sourceExpression.GetTypeOrFunctionType() == (object)source); + Debug.Assert(sourceExpression == null || (object)sourceExpression.Type == (object)source); Debug.Assert((object)destination != null); if (HasImplicitDynamicConversionFromExpression(source, destination)) @@ -1188,6 +1278,7 @@ internal static bool HasImplicitConstantExpressionConversion(BoundExpression sou return false; } +#nullable enable private Conversion ClassifyExplicitOnlyConversionFromExpression(BoundExpression sourceExpression, TypeSymbol destination, ref CompoundUseSiteInfo useSiteInfo, bool forCast) { Debug.Assert(sourceExpression != null); @@ -1205,8 +1296,8 @@ private Conversion ClassifyExplicitOnlyConversionFromExpression(BoundExpression } } - var sourceType = sourceExpression.GetTypeOrFunctionType(); - if ((object)sourceType != null) + var sourceType = sourceExpression.Type; + if (sourceType is { }) { // Try using the short-circuit "fast-conversion" path. Conversion fastConversion = FastClassifyConversion(sourceType, destination); @@ -1227,7 +1318,6 @@ private Conversion ClassifyExplicitOnlyConversionFromExpression(BoundExpression return GetExplicitUserDefinedConversion(sourceExpression, sourceType, destination, ref useSiteInfo); } -#nullable enable private static bool HasImplicitEnumerationConversion(BoundExpression source, TypeSymbol destination) { Debug.Assert((object)source != null); @@ -2576,7 +2666,7 @@ private bool HasImplicitFunctionTypeConversion(FunctionTypeSymbol source, TypeSy { if (destination is FunctionTypeSymbol destinationFunctionType) { - return HasImplicitSignatureConversion(source, destinationFunctionType, ref useSiteInfo); + return HasImplicitFunctionTypeToFunctionTypeConversion(source, destinationFunctionType, ref useSiteInfo); } return IsValidFunctionTypeConversionTarget(destination, ref useSiteInfo); @@ -2604,7 +2694,7 @@ internal bool IsValidFunctionTypeConversionTarget(TypeSymbol destination, ref Co return false; } - private bool HasImplicitSignatureConversion(FunctionTypeSymbol sourceType, FunctionTypeSymbol destinationType, ref CompoundUseSiteInfo useSiteInfo) + private bool HasImplicitFunctionTypeToFunctionTypeConversion(FunctionTypeSymbol sourceType, FunctionTypeSymbol destinationType, ref CompoundUseSiteInfo useSiteInfo) { var sourceDelegate = sourceType.GetInternalDelegateType(); var destinationDelegate = destinationType.GetInternalDelegateType(); diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/UserDefinedImplicitConversions.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/UserDefinedImplicitConversions.cs index 4bc7e128466c8..03b3cffe5c1b0 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/UserDefinedImplicitConversions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/Conversions/UserDefinedImplicitConversions.cs @@ -606,6 +606,7 @@ private static bool IsEncompassingImplicitConversionKind(ConversionKind kind) // Not "standard". case ConversionKind.ImplicitUserDefined: case ConversionKind.ExplicitUserDefined: + case ConversionKind.FunctionType: // Not implicit. case ConversionKind.ExplicitNumeric: diff --git a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MethodTypeInference.cs b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MethodTypeInference.cs index 13bf3163b29de..71765b500ac50 100644 --- a/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MethodTypeInference.cs +++ b/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MethodTypeInference.cs @@ -606,15 +606,15 @@ private void MakeExplicitParameterTypeInferences(BoundExpression argument, TypeW !MakeExplicitParameterTypeInferences((BoundTupleLiteral)argument, target, kind, ref useSiteInfo)) { // Either the argument is not a tuple literal, or we were unable to do the inference from its elements, let's try to infer from argument type - if (IsReallyAType(argument.GetTypeOrFunctionType())) + var argumentType = _extensions.GetTypeWithAnnotations(argument); + if (IsReallyAType(argumentType.Type)) { - ExactOrBoundsInference(kind, _extensions.GetTypeWithAnnotations(argument), target, ref useSiteInfo); + ExactOrBoundsInference(kind, argumentType, target, ref useSiteInfo); } else if (IsUnfixedTypeParameter(target) && kind is ExactOrBoundsKind.LowerBound) { var ordinal = ((TypeParameterSymbol)target.Type).Ordinal; - var typeWithAnnotations = _extensions.GetTypeWithAnnotations(argument); - _nullableAnnotationLowerBounds[ordinal] = _nullableAnnotationLowerBounds[ordinal].Join(typeWithAnnotations.NullableAnnotation); + _nullableAnnotationLowerBounds[ordinal] = _nullableAnnotationLowerBounds[ordinal].Join(argumentType.NullableAnnotation); } } } @@ -2793,7 +2793,7 @@ private static bool ImplicitConversionExists(TypeWithAnnotations sourceWithAnnot return false; } - return conversions.ClassifyImplicitConversionFromType(source, destination, ref useSiteInfo).Exists; + return conversions.ClassifyImplicitConversionFromTypeWhenNeitherOrBothFunctionTypes(source, destination, ref useSiteInfo).Exists; } #nullable disable diff --git a/src/Compilers/CSharp/Portable/Binder/UsingStatementBinder.cs b/src/Compilers/CSharp/Portable/Binder/UsingStatementBinder.cs index 00c41b9db84b3..48d24a282d272 100644 --- a/src/Compilers/CSharp/Portable/Binder/UsingStatementBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/UsingStatementBinder.cs @@ -257,9 +257,17 @@ bool populateDisposableConversionOrDisposeMethod(bool fromExpression, out Conver Conversion classifyConversion(bool fromExpression, TypeSymbol targetInterface, ref CompoundUseSiteInfo useSiteInfo) { - return fromExpression ? - originalBinder.Conversions.ClassifyImplicitConversionFromExpression(expressionOpt, targetInterface, ref useSiteInfo) : - originalBinder.Conversions.ClassifyImplicitConversionFromType(declarationTypeOpt, targetInterface, ref useSiteInfo); + var conversions = originalBinder.Conversions; + if (fromExpression) + { + Debug.Assert(expressionOpt is { }); + return conversions.ClassifyImplicitConversionFromExpression(expressionOpt, targetInterface, ref useSiteInfo); + } + else + { + Debug.Assert(declarationTypeOpt is { }); + return conversions.ClassifyImplicitConversionFromType(declarationTypeOpt, targetInterface, ref useSiteInfo); + } } TypeSymbol getDisposableInterface(bool isAsync) diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs index 5c6333648ff28..f394b0dd863f1 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs @@ -6156,6 +6156,7 @@ private static NullableAnnotation GetNullableAnnotation(BoundExpression expr) case BoundKind.MethodGroup: case BoundKind.UnboundLambda: case BoundKind.UnconvertedObjectCreationExpression: + case BoundKind.ConvertedTupleLiteral: return NullableAnnotation.NotAnnotated; default: Debug.Assert(false); // unexpected value @@ -6327,10 +6328,10 @@ private static Conversion GenerateConversion(Conversions conversions, BoundExpre return useExpression ? (fromExplicitCast ? conversions.ClassifyConversionFromExpression(sourceExpression, destinationType, ref discardedUseSiteInfo, forCast: true) : - conversions.ClassifyImplicitConversionFromExpression(sourceExpression, destinationType, ref discardedUseSiteInfo)) : + conversions.ClassifyImplicitConversionFromExpression(sourceExpression!, destinationType, ref discardedUseSiteInfo)) : (fromExplicitCast ? conversions.ClassifyConversionFromType(sourceType, destinationType, ref discardedUseSiteInfo, forCast: true) : - conversions.ClassifyImplicitConversionFromType(sourceType, destinationType, ref discardedUseSiteInfo)); + conversions.ClassifyImplicitConversionFromType(sourceType!, destinationType, ref discardedUseSiteInfo)); } /// diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs index 7ce5d30c70ade..57afe51034f20 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs @@ -6427,18 +6427,17 @@ public void SynthesizedDelegateTypes_21() delegate void D4(out object x, ref object y); class Program { + static void M(Delegate d) { Report(d); } + static void M(D2 d) { Report(d); } + static void M(D4 d) { Report(d); } static void F1(ref object x, object y) { } static void F2(object x, ref object y) { } static void Main() { - var d1 = F1; - D2 d2 = F2; - var d3 = (ref object x, out object y) => { y = null; }; - D4 d4 = (out object x, ref object y) => { x = null; }; - Report(d1); - Report(d2); - Report(d3); - Report(d4); + M(F1); + M(F2); + M((ref object x, out object y) => { y = null; }); + M((out object x, ref object y) => { x = null; }); } static void Report(Delegate d) => Console.WriteLine(d.GetType()); }"; @@ -6478,6 +6477,698 @@ private static void VerifyExpressionType(SemanticModel model, ExpressionSyntax v Assert.Equal(expectedType, type.ToTestDisplayString()); } + [Fact] + public void ClassifyConversionFromExpression() + { + var source = +@"class Program +{ + static void Main() + { + object o = () => 1; + } +}"; + + var comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + + var funcOfT = comp.GetWellKnownType(WellKnownType.System_Func_T); + var tree = comp.SyntaxTrees[0]; + var expr = tree.GetRoot().DescendantNodes().OfType().Single(); + var model = comp.GetSemanticModel(tree); + model = ((CSharpSemanticModel)model).GetMemberModel(expr); + + verifyConversions(model, expr, comp.GetSpecialType(SpecialType.System_MulticastDelegate).GetPublicSymbol(), ConversionKind.FunctionType, ConversionKind.FunctionType); + verifyConversions(model, expr, comp.GetWellKnownType(WellKnownType.System_Linq_Expressions_Expression).GetPublicSymbol(), ConversionKind.FunctionType, ConversionKind.FunctionType); + verifyConversions(model, expr, getFunctionType(funcOfT.Construct(comp.GetSpecialType(SpecialType.System_Int32))), ConversionKind.FunctionType, ConversionKind.FunctionType); + verifyConversions(model, expr, getFunctionType(funcOfT.Construct(comp.GetSpecialType(SpecialType.System_Object))), ConversionKind.NoConversion, ConversionKind.NoConversion); + + static ITypeSymbol getFunctionType(NamedTypeSymbol delegateType) + { + return new FunctionTypeSymbol_PublicModel(new FunctionTypeSymbol(delegateType)); + } + + static void verifyConversions(SemanticModel model, ExpressionSyntax expr, ITypeSymbol destination, ConversionKind expectedImplicitKind, ConversionKind expectedExplicitKind) + { + Assert.Equal(expectedImplicitKind, model.ClassifyConversion(expr, destination, isExplicitInSource: false).Kind); + Assert.Equal(expectedExplicitKind, model.ClassifyConversion(expr, destination, isExplicitInSource: true).Kind); + } + } + + private sealed class FunctionTypeSymbol_PublicModel : Symbols.PublicModel.TypeSymbol + { + private readonly FunctionTypeSymbol _underlying; + + internal FunctionTypeSymbol_PublicModel(FunctionTypeSymbol underlying) : + base(nullableAnnotation: default) + { + _underlying = underlying; + } + + internal override TypeSymbol UnderlyingTypeSymbol => _underlying; + internal override NamespaceOrTypeSymbol UnderlyingNamespaceOrTypeSymbol => _underlying; + internal override Symbol UnderlyingSymbol => _underlying; + + protected override void Accept(SymbolVisitor visitor) => throw new NotImplementedException(); + protected override TResult Accept(SymbolVisitor visitor) => throw new NotImplementedException(); + protected override ITypeSymbol WithNullableAnnotation(CodeAnalysis.NullableAnnotation nullableAnnotation) => this; + } + + [WorkItem(56407, "https://github.com/dotnet/roslyn/issues/56407")] + [Fact] + public void UserDefinedConversions_01() + { + var source = +@"using System.Linq.Expressions; + +public class Program +{ + public static void Main() + { + SomeMethod((Employee e) => e.Name); + } + + public static void SomeMethod(Field field) { } + + public class Employee + { + public string Name { get; set; } + } + + public class Field + { + public static implicit operator Field(Expression expression) => null; + } +}"; + + var expectedDiagnostics = new[] + { + // (7,20): error CS1660: Cannot convert lambda expression to type 'Program.Field' because it is not a delegate type + // SomeMethod((Employee e) => e.Name); + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "(Employee e) => e.Name").WithArguments("lambda expression", "Program.Field").WithLocation(7, 20) + }; + + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); + comp.VerifyDiagnostics(expectedDiagnostics); + + comp = CreateCompilation(source); + comp.VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void UserDefinedConversions_Implicit_01() + { + var source = +@"using System; +using System.Linq.Expressions; +class C1 +{ + public static implicit operator C1(Func f) { Console.WriteLine(""operator C1(Func f)""); return new C1(); } +} +class C2 +{ + public static implicit operator C2(Expression> e) { Console.WriteLine(""operator C2(Expression> e)""); return new C2(); } +} +class Program +{ + static int F() => 0; + static void Main() + { + C1 c1 = () => 1; + C2 c2 = () => 2; + c1 = F; + _ = (C1)(() => 1); + _ = (C2)(() => 2); + _ = (C1)F; + } +}"; + + var expectedDiagnostics = new[] + { + // (16,17): error CS1660: Cannot convert lambda expression to type 'C1' because it is not a delegate type + // C1 c1 = () => 1; + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 1").WithArguments("lambda expression", "C1").WithLocation(16, 17), + // (17,17): error CS1660: Cannot convert lambda expression to type 'C2' because it is not a delegate type + // C2 c2 = () => 2; + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 2").WithArguments("lambda expression", "C2").WithLocation(17, 17), + // (18,14): error CS0428: Cannot convert method group 'F' to non-delegate type 'C1'. Did you intend to invoke the method? + // c1 = F; + Diagnostic(ErrorCode.ERR_MethGrpToNonDel, "F").WithArguments("F", "C1").WithLocation(18, 14) + }; + + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); + comp.VerifyDiagnostics(expectedDiagnostics); + + comp = CreateCompilation(source); + comp.VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void UserDefinedConversions_Implicit_02() + { + var source = +@"using System; +class C1 +{ + public static implicit operator C1(object o) { Console.WriteLine(""operator C1(object o)""); return new C1(); } +} +class C2 +{ + public static implicit operator C2(ICloneable c) { Console.WriteLine(""operator C2(ICloneable c)""); return new C2(); } +} +class Program +{ + static int F() => 0; + static void Main() + { + C1 c1 = () => 1; + C2 c2 = () => 2; + c1 = F; + c2 = F; + _ = (C1)(() => 1); + _ = (C2)(() => 2); + _ = (C1)F; + _ = (C2)F; + } +}"; + + var expectedDiagnostics = new[] + { + // (4,37): error CS0553: 'C1.implicit operator C1(object)': user-defined conversions to or from a base type are not allowed + // public static implicit operator C1(object o) { Console.WriteLine("operator C1(object o)"); return new C1(); } + Diagnostic(ErrorCode.ERR_ConversionWithBase, "C1").WithArguments("C1.implicit operator C1(object)").WithLocation(4, 37), + // (8,37): error CS0552: 'C2.implicit operator C2(ICloneable)': user-defined conversions to or from an interface are not allowed + // public static implicit operator C2(ICloneable c) { Console.WriteLine("operator C2(ICloneable c)"); return new C2(); } + Diagnostic(ErrorCode.ERR_ConversionWithInterface, "C2").WithArguments("C2.implicit operator C2(System.ICloneable)").WithLocation(8, 37), + // (15,17): error CS1660: Cannot convert lambda expression to type 'C1' because it is not a delegate type + // C1 c1 = () => 1; + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 1").WithArguments("lambda expression", "C1").WithLocation(15, 17), + // (16,17): error CS1660: Cannot convert lambda expression to type 'C2' because it is not a delegate type + // C2 c2 = () => 2; + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 2").WithArguments("lambda expression", "C2").WithLocation(16, 17), + // (17,14): error CS0428: Cannot convert method group 'F' to non-delegate type 'C1'. Did you intend to invoke the method? + // c1 = F; + Diagnostic(ErrorCode.ERR_MethGrpToNonDel, "F").WithArguments("F", "C1").WithLocation(17, 14), + // (18,14): error CS0428: Cannot convert method group 'F' to non-delegate type 'C2'. Did you intend to invoke the method? + // c2 = F; + Diagnostic(ErrorCode.ERR_MethGrpToNonDel, "F").WithArguments("F", "C2").WithLocation(18, 14), + // (19,18): error CS1660: Cannot convert lambda expression to type 'C1' because it is not a delegate type + // _ = (C1)(() => 1); + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 1").WithArguments("lambda expression", "C1").WithLocation(19, 18), + // (20,18): error CS1660: Cannot convert lambda expression to type 'C2' because it is not a delegate type + // _ = (C2)(() => 2); + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 2").WithArguments("lambda expression", "C2").WithLocation(20, 18), + // (21,13): error CS0030: Cannot convert type 'method' to 'C1' + // _ = (C1)F; + Diagnostic(ErrorCode.ERR_NoExplicitConv, "(C1)F").WithArguments("method", "C1").WithLocation(21, 13), + // (22,13): error CS0030: Cannot convert type 'method' to 'C2' + // _ = (C2)F; + Diagnostic(ErrorCode.ERR_NoExplicitConv, "(C2)F").WithArguments("method", "C2").WithLocation(22, 13) + }; + + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); + comp.VerifyDiagnostics(expectedDiagnostics); + + comp = CreateCompilation(source); + comp.VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void UserDefinedConversions_Implicit_03() + { + var source = +@"using System; +using System.Linq.Expressions; +class C1 +{ + public static implicit operator C1(Delegate d) { Console.WriteLine(""operator C1(Delegate d)""); return new C1(); } +} +class C2 +{ + public static implicit operator C2(MulticastDelegate d) { Console.WriteLine(""operator C2(MulticastDelegate d)""); return new C2(); } +} +class C3 +{ + public static implicit operator C3(Expression e) { Console.WriteLine(""operator C3(Expression e)""); return new C3(); } +} +class C4 +{ + public static implicit operator C4(LambdaExpression e) { Console.WriteLine(""operator C4(LambdaExpression e)""); return new C4(); } +} +class Program +{ + static int F() => 0; + static void Main() + { + C1 c1 = () => 1; + C2 c2 = () => 2; + C3 c3 = () => 3; + C4 c4 = () => 4; + c1 = F; + c2 = F; + _ = (C1)(() => 1); + _ = (C2)(() => 2); + _ = (C3)(() => 3); + _ = (C4)(() => 4); + _ = (C1)F; + _ = (C2)F; + } +}"; + + var expectedDiagnostics = new[] + { + // (24,17): error CS1660: Cannot convert lambda expression to type 'C1' because it is not a delegate type + // C1 c1 = () => 1; + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 1").WithArguments("lambda expression", "C1").WithLocation(24, 17), + // (25,17): error CS1660: Cannot convert lambda expression to type 'C2' because it is not a delegate type + // C2 c2 = () => 2; + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 2").WithArguments("lambda expression", "C2").WithLocation(25, 17), + // (26,17): error CS1660: Cannot convert lambda expression to type 'C3' because it is not a delegate type + // C3 c3 = () => 3; + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 3").WithArguments("lambda expression", "C3").WithLocation(26, 17), + // (27,17): error CS1660: Cannot convert lambda expression to type 'C4' because it is not a delegate type + // C4 c4 = () => 4; + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 4").WithArguments("lambda expression", "C4").WithLocation(27, 17), + // (28,14): error CS0428: Cannot convert method group 'F' to non-delegate type 'C1'. Did you intend to invoke the method? + // c1 = F; + Diagnostic(ErrorCode.ERR_MethGrpToNonDel, "F").WithArguments("F", "C1").WithLocation(28, 14), + // (29,14): error CS0428: Cannot convert method group 'F' to non-delegate type 'C2'. Did you intend to invoke the method? + // c2 = F; + Diagnostic(ErrorCode.ERR_MethGrpToNonDel, "F").WithArguments("F", "C2").WithLocation(29, 14), + // (30,18): error CS1660: Cannot convert lambda expression to type 'C1' because it is not a delegate type + // _ = (C1)(() => 1); + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 1").WithArguments("lambda expression", "C1").WithLocation(30, 18), + // (31,18): error CS1660: Cannot convert lambda expression to type 'C2' because it is not a delegate type + // _ = (C2)(() => 2); + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 2").WithArguments("lambda expression", "C2").WithLocation(31, 18), + // (32,18): error CS1660: Cannot convert lambda expression to type 'C3' because it is not a delegate type + // _ = (C3)(() => 3); + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 3").WithArguments("lambda expression", "C3").WithLocation(32, 18), + // (33,18): error CS1660: Cannot convert lambda expression to type 'C4' because it is not a delegate type + // _ = (C4)(() => 4); + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 4").WithArguments("lambda expression", "C4").WithLocation(33, 18), + // (34,13): error CS0030: Cannot convert type 'method' to 'C1' + // _ = (C1)F; + Diagnostic(ErrorCode.ERR_NoExplicitConv, "(C1)F").WithArguments("method", "C1").WithLocation(34, 13), + // (35,13): error CS0030: Cannot convert type 'method' to 'C2' + // _ = (C2)F; + Diagnostic(ErrorCode.ERR_NoExplicitConv, "(C2)F").WithArguments("method", "C2").WithLocation(35, 13) + }; + + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); + comp.VerifyDiagnostics(expectedDiagnostics); + + comp = CreateCompilation(source); + comp.VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void UserDefinedConversions_Implicit_04() + { + var source = +@"using System; +class C +{ + public static implicit operator C(T t) { Console.WriteLine(""operator C<{0}>({0} t)"", typeof(T).FullName); return new C(); } +} +class Program +{ + static int F() => 0; + static void Main() + { + C c1 = () => 1; + C c2 = () => 2; + c1 = F; + c2 = F; + _ = (C)(() => 1); + _ = (C)(() => 2); + _ = (C)F; + _ = (C)F; + } +}"; + + var expectedDiagnostics = new[] + { + // (11,24): error CS1660: Cannot convert lambda expression to type 'C' because it is not a delegate type + // C c1 = () => 1; + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 1").WithArguments("lambda expression", "C").WithLocation(11, 24), + // (12,28): error CS1660: Cannot convert lambda expression to type 'C' because it is not a delegate type + // C c2 = () => 2; + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 2").WithArguments("lambda expression", "C").WithLocation(12, 28), + // (13,14): error CS0428: Cannot convert method group 'F' to non-delegate type 'C'. Did you intend to invoke the method? + // c1 = F; + Diagnostic(ErrorCode.ERR_MethGrpToNonDel, "F").WithArguments("F", "C").WithLocation(13, 14), + // (14,14): error CS0428: Cannot convert method group 'F' to non-delegate type 'C'. Did you intend to invoke the method? + // c2 = F; + Diagnostic(ErrorCode.ERR_MethGrpToNonDel, "F").WithArguments("F", "C").WithLocation(14, 14), + // (15,25): error CS1660: Cannot convert lambda expression to type 'C' because it is not a delegate type + // _ = (C)(() => 1); + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 1").WithArguments("lambda expression", "C").WithLocation(15, 25), + // (16,29): error CS1660: Cannot convert lambda expression to type 'C' because it is not a delegate type + // _ = (C)(() => 2); + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 2").WithArguments("lambda expression", "C").WithLocation(16, 29), + // (17,13): error CS0030: Cannot convert type 'method' to 'C' + // _ = (C)F; + Diagnostic(ErrorCode.ERR_NoExplicitConv, "(C)F").WithArguments("method", "C").WithLocation(17, 13), + // (18,13): error CS0030: Cannot convert type 'method' to 'C' + // _ = (C)F; + Diagnostic(ErrorCode.ERR_NoExplicitConv, "(C)F").WithArguments("method", "C").WithLocation(18, 13) + }; + + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); + comp.VerifyDiagnostics(expectedDiagnostics); + + comp = CreateCompilation(source); + comp.VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void UserDefinedConversions_Implicit_05() + { + var source = +@"using System; +using System.Linq.Expressions; +class C +{ + public static implicit operator C(T t) { Console.WriteLine(""operator C<{0}>({0} t)"", typeof(T).FullName); return new C(); } +} +class Program +{ + static int F() => 0; + static void Main() + { + C c1 = () => 1; + C c2 = () => 2; + C c3 = () => 3; + C c4 = () => 4; + c1 = F; + c2 = F; + _ = (C)(() => 1); + _ = (C)(() => 2); + _ = (C)(() => 3); + _ = (C)(() => 4); + _ = (C)F; + _ = (C)F; + } +}"; + + var expectedDiagnostics = new[] + { + // (12,26): error CS1660: Cannot convert lambda expression to type 'C' because it is not a delegate type + // C c1 = () => 1; + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 1").WithArguments("lambda expression", "C").WithLocation(12, 26), + // (13,35): error CS1660: Cannot convert lambda expression to type 'C' because it is not a delegate type + // C c2 = () => 2; + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 2").WithArguments("lambda expression", "C").WithLocation(13, 35), + // (14,28): error CS1660: Cannot convert lambda expression to type 'C' because it is not a delegate type + // C c3 = () => 3; + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 3").WithArguments("lambda expression", "C").WithLocation(14, 28), + // (15,34): error CS1660: Cannot convert lambda expression to type 'C' because it is not a delegate type + // C c4 = () => 4; + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 4").WithArguments("lambda expression", "C").WithLocation(15, 34), + // (16,14): error CS0428: Cannot convert method group 'F' to non-delegate type 'C'. Did you intend to invoke the method? + // c1 = F; + Diagnostic(ErrorCode.ERR_MethGrpToNonDel, "F").WithArguments("F", "C").WithLocation(16, 14), + // (17,14): error CS0428: Cannot convert method group 'F' to non-delegate type 'C'. Did you intend to invoke the method? + // c2 = F; + Diagnostic(ErrorCode.ERR_MethGrpToNonDel, "F").WithArguments("F", "C").WithLocation(17, 14), + // (18,27): error CS1660: Cannot convert lambda expression to type 'C' because it is not a delegate type + // _ = (C)(() => 1); + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 1").WithArguments("lambda expression", "C").WithLocation(18, 27), + // (19,36): error CS1660: Cannot convert lambda expression to type 'C' because it is not a delegate type + // _ = (C)(() => 2); + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 2").WithArguments("lambda expression", "C").WithLocation(19, 36), + // (20,29): error CS1660: Cannot convert lambda expression to type 'C' because it is not a delegate type + // _ = (C)(() => 3); + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 3").WithArguments("lambda expression", "C").WithLocation(20, 29), + // (21,35): error CS1660: Cannot convert lambda expression to type 'C' because it is not a delegate type + // _ = (C)(() => 4); + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 4").WithArguments("lambda expression", "C").WithLocation(21, 35), + // (22,13): error CS0030: Cannot convert type 'method' to 'C' + // _ = (C)F; + Diagnostic(ErrorCode.ERR_NoExplicitConv, "(C)F").WithArguments("method", "C").WithLocation(22, 13), + // (23,13): error CS0030: Cannot convert type 'method' to 'C' + // _ = (C)F; + Diagnostic(ErrorCode.ERR_NoExplicitConv, "(C)F").WithArguments("method", "C").WithLocation(23, 13) + }; + + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); + comp.VerifyDiagnostics(expectedDiagnostics); + + comp = CreateCompilation(source); + comp.VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void UserDefinedConversions_Explicit_01() + { + var source = +@"using System; +using System.Linq.Expressions; +class C1 +{ + public static explicit operator C1(Func f) { Console.WriteLine(""operator C1(Func f)""); return new C1(); } +} +class C2 +{ + public static explicit operator C2(Expression> e) { Console.WriteLine(""operator C2(Expression> e)""); return new C2(); } +} +class Program +{ + static int F() => 0; + static void Main() + { + _ = (C1)(() => 1); + _ = (C2)(() => 2); + _ = (C1)F; + } +}"; + + string expectedOutput = +@"operator C1(Func f) +operator C2(Expression> e) +operator C1(Func f) +"; + CompileAndVerify(source, parseOptions: TestOptions.Regular9, options: TestOptions.ReleaseExe, expectedOutput: expectedOutput); + CompileAndVerify(source, options: TestOptions.ReleaseExe, expectedOutput: expectedOutput); + } + + [Fact] + public void UserDefinedConversions_Explicit_02() + { + var source = +@"using System; +class C1 +{ + public static explicit operator C1(object o) { Console.WriteLine(""operator C1(object o)""); return new C1(); } +} +class C2 +{ + public static explicit operator C2(ICloneable c) { Console.WriteLine(""operator C2(ICloneable c)""); return new C2(); } +} +class Program +{ + static int F() => 0; + static void Main() + { + _ = (C1)(() => 1); + _ = (C2)(() => 2); + _ = (C1)F; + _ = (C2)F; + } +}"; + + var expectedDiagnostics = new[] + { + // (4,37): error CS0553: 'C1.explicit operator C1(object)': user-defined conversions to or from a base type are not allowed + // public static explicit operator C1(object o) { Console.WriteLine("operator C1(object o)"); return new C1(); } + Diagnostic(ErrorCode.ERR_ConversionWithBase, "C1").WithArguments("C1.explicit operator C1(object)").WithLocation(4, 37), + // (8,37): error CS0552: 'C2.explicit operator C2(ICloneable)': user-defined conversions to or from an interface are not allowed + // public static explicit operator C2(ICloneable c) { Console.WriteLine("operator C2(ICloneable c)"); return new C2(); } + Diagnostic(ErrorCode.ERR_ConversionWithInterface, "C2").WithArguments("C2.explicit operator C2(System.ICloneable)").WithLocation(8, 37), + // (15,18): error CS1660: Cannot convert lambda expression to type 'C1' because it is not a delegate type + // _ = (C1)(() => 1); + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 1").WithArguments("lambda expression", "C1").WithLocation(15, 18), + // (16,18): error CS1660: Cannot convert lambda expression to type 'C2' because it is not a delegate type + // _ = (C2)(() => 2); + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 2").WithArguments("lambda expression", "C2").WithLocation(16, 18), + // (17,13): error CS0030: Cannot convert type 'method' to 'C1' + // _ = (C1)F; + Diagnostic(ErrorCode.ERR_NoExplicitConv, "(C1)F").WithArguments("method", "C1").WithLocation(17, 13), + // (18,13): error CS0030: Cannot convert type 'method' to 'C2' + // _ = (C2)F; + Diagnostic(ErrorCode.ERR_NoExplicitConv, "(C2)F").WithArguments("method", "C2").WithLocation(18, 13) + }; + + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); + comp.VerifyDiagnostics(expectedDiagnostics); + + comp = CreateCompilation(source); + comp.VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void UserDefinedConversions_Explicit_03() + { + var source = +@"using System; +using System.Linq.Expressions; +class C1 +{ + public static explicit operator C1(Delegate d) { Console.WriteLine(""operator C1(Delegate d)""); return new C1(); } +} +class C2 +{ + public static explicit operator C2(MulticastDelegate d) { Console.WriteLine(""operator C2(MulticastDelegate d)""); return new C2(); } +} +class C3 +{ + public static explicit operator C3(Expression e) { Console.WriteLine(""operator C3(Expression e)""); return new C3(); } +} +class C4 +{ + public static explicit operator C4(LambdaExpression e) { Console.WriteLine(""operator C4(LambdaExpression e)""); return new C4(); } +} +class Program +{ + static int F() => 0; + static void Main() + { + _ = (C1)(() => 1); + _ = (C2)(() => 2); + _ = (C3)(() => 3); + _ = (C4)(() => 4); + _ = (C1)F; + _ = (C2)F; + } +}"; + + var expectedDiagnostics = new[] + { + // (24,18): error CS1660: Cannot convert lambda expression to type 'C1' because it is not a delegate type + // _ = (C1)(() => 1); + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 1").WithArguments("lambda expression", "C1").WithLocation(24, 18), + // (25,18): error CS1660: Cannot convert lambda expression to type 'C2' because it is not a delegate type + // _ = (C2)(() => 2); + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 2").WithArguments("lambda expression", "C2").WithLocation(25, 18), + // (26,18): error CS1660: Cannot convert lambda expression to type 'C3' because it is not a delegate type + // _ = (C3)(() => 3); + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 3").WithArguments("lambda expression", "C3").WithLocation(26, 18), + // (27,18): error CS1660: Cannot convert lambda expression to type 'C4' because it is not a delegate type + // _ = (C4)(() => 4); + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 4").WithArguments("lambda expression", "C4").WithLocation(27, 18), + // (28,13): error CS0030: Cannot convert type 'method' to 'C1' + // _ = (C1)F; + Diagnostic(ErrorCode.ERR_NoExplicitConv, "(C1)F").WithArguments("method", "C1").WithLocation(28, 13), + // (29,13): error CS0030: Cannot convert type 'method' to 'C2' + // _ = (C2)F; + Diagnostic(ErrorCode.ERR_NoExplicitConv, "(C2)F").WithArguments("method", "C2").WithLocation(29, 13) + }; + + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); + comp.VerifyDiagnostics(expectedDiagnostics); + + comp = CreateCompilation(source); + comp.VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void UserDefinedConversions_Explicit_04() + { + var source = +@"using System; +class C +{ + public static explicit operator C(T t) { Console.WriteLine(""operator C<{0}>({0} t)"", typeof(T).FullName); return new C(); } +} +class Program +{ + static int F() => 0; + static void Main() + { + _ = (C)(() => 1); + _ = (C)(() => 2); + _ = (C)F; + _ = (C)F; + } +}"; + + var expectedDiagnostics = new[] + { + // (11,25): error CS1660: Cannot convert lambda expression to type 'C' because it is not a delegate type + // _ = (C)(() => 1); + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 1").WithArguments("lambda expression", "C").WithLocation(11, 25), + // (12,29): error CS1660: Cannot convert lambda expression to type 'C' because it is not a delegate type + // _ = (C)(() => 2); + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 2").WithArguments("lambda expression", "C").WithLocation(12, 29), + // (13,13): error CS0030: Cannot convert type 'method' to 'C' + // _ = (C)F; + Diagnostic(ErrorCode.ERR_NoExplicitConv, "(C)F").WithArguments("method", "C").WithLocation(13, 13), + // (14,13): error CS0030: Cannot convert type 'method' to 'C' + // _ = (C)F; + Diagnostic(ErrorCode.ERR_NoExplicitConv, "(C)F").WithArguments("method", "C").WithLocation(14, 13) + }; + + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); + comp.VerifyDiagnostics(expectedDiagnostics); + + comp = CreateCompilation(source); + comp.VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void UserDefinedConversions_Explicit_05() + { + var source = +@"using System; +using System.Linq.Expressions; +class C +{ + public static explicit operator C(T t) { Console.WriteLine(""operator C<{0}>({0} t)"", typeof(T).FullName); return new C(); } +} +class Program +{ + static int F() => 0; + static void Main() + { + _ = (C)(() => 1); + _ = (C)(() => 2); + _ = (C)(() => 3); + _ = (C)(() => 4); + _ = (C)F; + _ = (C)F; + } +}"; + + var expectedDiagnostics = new[] + { + // (12,27): error CS1660: Cannot convert lambda expression to type 'C' because it is not a delegate type + // _ = (C)(() => 1); + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 1").WithArguments("lambda expression", "C").WithLocation(12, 27), + // (13,36): error CS1660: Cannot convert lambda expression to type 'C' because it is not a delegate type + // _ = (C)(() => 2); + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 2").WithArguments("lambda expression", "C").WithLocation(13, 36), + // (14,29): error CS1660: Cannot convert lambda expression to type 'C' because it is not a delegate type + // _ = (C)(() => 3); + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 3").WithArguments("lambda expression", "C").WithLocation(14, 29), + // (15,35): error CS1660: Cannot convert lambda expression to type 'C' because it is not a delegate type + // _ = (C)(() => 4); + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 4").WithArguments("lambda expression", "C").WithLocation(15, 35), + // (16,13): error CS0030: Cannot convert type 'method' to 'C' + // _ = (C)F; + Diagnostic(ErrorCode.ERR_NoExplicitConv, "(C)F").WithArguments("method", "C").WithLocation(16, 13), + // (17,13): error CS0030: Cannot convert type 'method' to 'C' + // _ = (C)F; + Diagnostic(ErrorCode.ERR_NoExplicitConv, "(C)F").WithArguments("method", "C").WithLocation(17, 13) + }; + + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); + comp.VerifyDiagnostics(expectedDiagnostics); + + comp = CreateCompilation(source); + comp.VerifyDiagnostics(expectedDiagnostics); + } + [Fact] public void TaskRunArgument() {