diff --git a/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs index 82efcc15fda5e..cd84eff58bdf7 100644 --- a/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs +++ b/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs @@ -383,34 +383,58 @@ public static bool IsPointerOrFunctionPointer(this TypeSymbol type) } /// - /// return true if the type is constructed from System.Linq.Expressions.Expression`1 + /// Returns true if the type is constructed from a generic type named "System.Linq.Expressions.Expression" + /// with one type parameter. /// public static bool IsExpressionTree(this TypeSymbol type) { return type.IsGenericOrNonGenericExpressionType(out bool isGenericType) && isGenericType; } + /// + /// Returns true if the type is a non-generic type named "System.Linq.Expressions.Expression" + /// or "System.Linq.Expressions.LambdaExpression". + /// public static bool IsNonGenericExpressionType(this TypeSymbol type) { return type.IsGenericOrNonGenericExpressionType(out bool isGenericType) && !isGenericType; } + /// + /// Returns true if the type is constructed from a generic type named "System.Linq.Expressions.Expression" + /// with one type parameter, or if the type is a non-generic type named "System.Linq.Expressions.Expression" + /// or "System.Linq.Expressions.LambdaExpression". + /// public static bool IsGenericOrNonGenericExpressionType(this TypeSymbol _type, out bool isGenericType) { - if (_type.OriginalDefinition is NamedTypeSymbol type && - type.Name == "Expression" && - CheckFullName(type.ContainingSymbol, s_expressionsNamespaceName)) + if (_type.OriginalDefinition is NamedTypeSymbol type) { - if (type.Arity == 0) - { - isGenericType = false; - return true; - } - if (type.Arity == 1 && - type.MangleName) + switch (type.Name) { - isGenericType = true; - return true; + case "Expression": + if (IsNamespaceName(type.ContainingSymbol, s_expressionsNamespaceName)) + { + if (type.Arity == 0) + { + isGenericType = false; + return true; + } + if (type.Arity == 1 && + type.MangleName) + { + isGenericType = true; + return true; + } + } + break; + case "LambdaExpression": + if (IsNamespaceName(type.ContainingSymbol, s_expressionsNamespaceName) && + type.Arity == 0) + { + isGenericType = false; + return true; + } + break; } } isGenericType = false; @@ -446,8 +470,13 @@ public static bool IsPossibleArrayGenericInterface(this TypeSymbol type) private static readonly string[] s_expressionsNamespaceName = { "Expressions", "Linq", MetadataHelpers.SystemString, "" }; - private static bool CheckFullName(Symbol symbol, string[] names) + private static bool IsNamespaceName(Symbol symbol, string[] names) { + if (symbol.Kind != SymbolKind.Namespace) + { + return false; + } + for (int i = 0; i < names.Length; i++) { if ((object)symbol == null || symbol.Name != names[i]) return false; diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs index c203090dab768..6d9e60dc0d7cf 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs @@ -192,6 +192,8 @@ static void Main() { System.Linq.Expressions.Expression e = F; e = (System.Linq.Expressions.Expression)F; + System.Linq.Expressions.LambdaExpression l = F; + l = (System.Linq.Expressions.LambdaExpression)F; } static int F() => 1; }"; @@ -203,7 +205,13 @@ static void Main() Diagnostic(ErrorCode.ERR_MethGrpToNonDel, "F").WithArguments("F", "System.Linq.Expressions.Expression").WithLocation(5, 48), // (6,13): error CS0030: Cannot convert type 'method' to 'Expression' // e = (System.Linq.Expressions.Expression)F; - Diagnostic(ErrorCode.ERR_NoExplicitConv, "(System.Linq.Expressions.Expression)F").WithArguments("method", "System.Linq.Expressions.Expression").WithLocation(6, 13)); + Diagnostic(ErrorCode.ERR_NoExplicitConv, "(System.Linq.Expressions.Expression)F").WithArguments("method", "System.Linq.Expressions.Expression").WithLocation(6, 13), + // (7,54): error CS0428: Cannot convert method group 'F' to non-delegate type 'LambdaExpression'. Did you intend to invoke the method? + // System.Linq.Expressions.LambdaExpression l = F; + Diagnostic(ErrorCode.ERR_MethGrpToNonDel, "F").WithArguments("F", "System.Linq.Expressions.LambdaExpression").WithLocation(7, 54), + // (8,13): error CS0030: Cannot convert type 'method' to 'LambdaExpression' + // l = (System.Linq.Expressions.LambdaExpression)F; + Diagnostic(ErrorCode.ERR_NoExplicitConv, "(System.Linq.Expressions.LambdaExpression)F").WithArguments("method", "System.Linq.Expressions.LambdaExpression").WithLocation(8, 13)); comp = CreateCompilation(source); comp.VerifyDiagnostics( @@ -212,7 +220,13 @@ static void Main() Diagnostic(ErrorCode.ERR_MethGrpToNonDel, "F").WithArguments("F", "System.Linq.Expressions.Expression").WithLocation(5, 48), // (6,13): error CS0428: Cannot convert method group 'F' to non-delegate type 'Expression'. Did you intend to invoke the method? // e = (System.Linq.Expressions.Expression)F; - Diagnostic(ErrorCode.ERR_MethGrpToNonDel, "(System.Linq.Expressions.Expression)F").WithArguments("F", "System.Linq.Expressions.Expression").WithLocation(6, 13)); + Diagnostic(ErrorCode.ERR_MethGrpToNonDel, "(System.Linq.Expressions.Expression)F").WithArguments("F", "System.Linq.Expressions.Expression").WithLocation(6, 13), + // (7,54): error CS0428: Cannot convert method group 'F' to non-delegate type 'LambdaExpression'. Did you intend to invoke the method? + // System.Linq.Expressions.LambdaExpression l = F; + Diagnostic(ErrorCode.ERR_MethGrpToNonDel, "F").WithArguments("F", "System.Linq.Expressions.LambdaExpression").WithLocation(7, 54), + // (8,13): error CS0428: Cannot convert method group 'F' to non-delegate type 'LambdaExpression'. Did you intend to invoke the method? + // l = (System.Linq.Expressions.LambdaExpression)F; + Diagnostic(ErrorCode.ERR_MethGrpToNonDel, "(System.Linq.Expressions.LambdaExpression)F").WithArguments("F", "System.Linq.Expressions.LambdaExpression").WithLocation(8, 13)); } [Fact] @@ -382,6 +396,39 @@ public void LambdaConversions_04() @"using System; using System.Linq.Expressions; class Program +{ + static void Main() + { + LambdaExpression e = () => 1; + Report(e); + e = (LambdaExpression)(() => 2); + Report(e); + } + static void Report(object obj) => Console.WriteLine(obj.GetType()); +}"; + + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); + comp.VerifyDiagnostics( + // (7,30): error CS1660: Cannot convert lambda expression to type 'LambdaExpression' because it is not a delegate type + // LambdaExpression e = () => 1; + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 1").WithArguments("lambda expression", "System.Linq.Expressions.LambdaExpression").WithLocation(7, 30), + // (9,32): error CS1660: Cannot convert lambda expression to type 'LambdaExpression' because it is not a delegate type + // e = (LambdaExpression)(() => 2); + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 2").WithArguments("lambda expression", "System.Linq.Expressions.LambdaExpression").WithLocation(9, 32)); + + CompileAndVerify(source, options: TestOptions.ReleaseExe, expectedOutput: +$@"{s_expressionOfTDelegateTypeName}[System.Func`1[System.Int32]] +{s_expressionOfTDelegateTypeName}[System.Func`1[System.Int32]] +"); + } + + [Fact] + public void LambdaConversions_05() + { + var source = +@"using System; +using System.Linq.Expressions; +class Program { static void Main() { @@ -389,6 +436,8 @@ static void Main() object o = (object)(x => x); Expression e = x => x; e = (Expression)(x => x); + LambdaExpression l = x => x; + l = (LambdaExpression)(x => x); } }"; @@ -405,7 +454,13 @@ static void Main() Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "x => x").WithArguments("lambda expression", "System.Linq.Expressions.Expression").WithLocation(9, 24), // (10,26): error CS1660: Cannot convert lambda expression to type 'Expression' because it is not a delegate type // e = (Expression)(x => x); - Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "x => x").WithArguments("lambda expression", "System.Linq.Expressions.Expression").WithLocation(10, 26)); + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "x => x").WithArguments("lambda expression", "System.Linq.Expressions.Expression").WithLocation(10, 26), + // (11,30): error CS1660: Cannot convert lambda expression to type 'LambdaExpression' because it is not a delegate type + // LambdaExpression l = x => x; + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "x => x").WithArguments("lambda expression", "System.Linq.Expressions.LambdaExpression").WithLocation(11, 30), + // (12,32): error CS1660: Cannot convert lambda expression to type 'LambdaExpression' because it is not a delegate type + // l = (LambdaExpression)(x => x); + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "x => x").WithArguments("lambda expression", "System.Linq.Expressions.LambdaExpression").WithLocation(12, 32)); comp = CreateCompilation(source); comp.VerifyDiagnostics( @@ -420,11 +475,56 @@ static void Main() Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "x => x").WithLocation(9, 24), // (10,26): error CS8917: The delegate type could not be inferred. // e = (Expression)(x => x); - Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "x => x").WithLocation(10, 26)); + Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "x => x").WithLocation(10, 26), + // (11,30): error CS8917: The delegate type could not be inferred. + // LambdaExpression l = x => x; + Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "x => x").WithLocation(11, 30), + // (12,32): error CS8917: The delegate type could not be inferred. + // l = (LambdaExpression)(x => x); + Diagnostic(ErrorCode.ERR_CannotInferDelegateType, "x => x").WithLocation(12, 32)); } [Fact] - public void LambdaConversions_05() + public void LambdaConversions_06() + { + var sourceA = +@"namespace System.Linq.Expressions +{ + public class LambdaExpression + { + } +}"; + var sourceB = +@"using System; +using System.Linq.Expressions; +class Program +{ + static void Main() + { + LambdaExpression> l = () => 1; + l = (LambdaExpression>)(() => 2); + } +}"; + + var expectedDiagnostics = new[] + { + // (7,41): error CS1660: Cannot convert lambda expression to type 'LambdaExpression>' because it is not a delegate type + // LambdaExpression> l = () => 1; + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 1").WithArguments("lambda expression", "System.Linq.Expressions.LambdaExpression>").WithLocation(7, 41), + // (8,43): error CS1660: Cannot convert lambda expression to type 'LambdaExpression>' because it is not a delegate type + // l = (LambdaExpression>)(() => 2); + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 2").WithArguments("lambda expression", "System.Linq.Expressions.LambdaExpression>").WithLocation(8, 43) + }; + + var comp = CreateCompilation(new[] { sourceA, sourceB }, parseOptions: TestOptions.Regular9); + comp.VerifyDiagnostics(expectedDiagnostics); + + comp = CreateCompilation(new[] { sourceA, sourceB }); + comp.VerifyDiagnostics(expectedDiagnostics); + } + + [Fact] + public void LambdaConversions_07() { var source = @"using System; @@ -489,6 +589,53 @@ static void Main() "); } + [Fact] + public void AnonymousMethod_02() + { + var source = +@"using System.Linq.Expressions; +class Program +{ + static void Main() + { + System.Linq.Expressions.Expression e = delegate () { return 1; }; + e = (Expression)delegate () { return 2; }; + LambdaExpression l = delegate () { return 3; }; + l = (LambdaExpression)delegate () { return 4; }; + } +}"; + + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); + comp.VerifyDiagnostics( + // (6,48): error CS1660: Cannot convert anonymous method to type 'Expression' because it is not a delegate type + // System.Linq.Expressions.Expression e = delegate () { return 1; }; + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "delegate () { return 1; }").WithArguments("anonymous method", "System.Linq.Expressions.Expression").WithLocation(6, 48), + // (7,25): error CS1660: Cannot convert anonymous method to type 'Expression' because it is not a delegate type + // e = (Expression)delegate () { return 2; }; + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "delegate () { return 2; }").WithArguments("anonymous method", "System.Linq.Expressions.Expression").WithLocation(7, 25), + // (8,30): error CS1660: Cannot convert anonymous method to type 'LambdaExpression' because it is not a delegate type + // LambdaExpression l = delegate () { return 3; }; + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "delegate () { return 3; }").WithArguments("anonymous method", "System.Linq.Expressions.LambdaExpression").WithLocation(8, 30), + // (9,31): error CS1660: Cannot convert anonymous method to type 'LambdaExpression' because it is not a delegate type + // l = (LambdaExpression)delegate () { return 4; }; + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "delegate () { return 4; }").WithArguments("anonymous method", "System.Linq.Expressions.LambdaExpression").WithLocation(9, 31)); + + comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (6,48): error CS1946: An anonymous method expression cannot be converted to an expression tree + // System.Linq.Expressions.Expression e = delegate () { return 1; }; + Diagnostic(ErrorCode.ERR_AnonymousMethodToExpressionTree, "delegate () { return 1; }").WithLocation(6, 48), + // (7,13): error CS1946: An anonymous method expression cannot be converted to an expression tree + // e = (Expression)delegate () { return 2; }; + Diagnostic(ErrorCode.ERR_AnonymousMethodToExpressionTree, "(Expression)delegate () { return 2; }").WithLocation(7, 13), + // (8,30): error CS1946: An anonymous method expression cannot be converted to an expression tree + // LambdaExpression l = delegate () { return 3; }; + Diagnostic(ErrorCode.ERR_AnonymousMethodToExpressionTree, "delegate () { return 3; }").WithLocation(8, 30), + // (9,13): error CS1946: An anonymous method expression cannot be converted to an expression tree + // l = (LambdaExpression)delegate () { return 4; }; + Diagnostic(ErrorCode.ERR_AnonymousMethodToExpressionTree, "(LambdaExpression)delegate () { return 4; }").WithLocation(9, 13)); + } + [Fact] public void DynamicConversion() { @@ -2313,6 +2460,111 @@ static void Main() Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "F").WithArguments("Program.F(T)", "System.Linq.Expressions.Expression", "T", "System.Linq.Expressions.Expression>").WithLocation(6, 17)); } + /// + /// System.Linq.Expressions as a type rather than a namespace. + /// + [Fact] + public void SystemLinqExpressions_IsType() + { + var sourceA = +@"namespace System +{ + public class Object { } + public abstract class ValueType { } + public class String { } + public class Type { } + public struct Void { } + public struct Boolean { } + public struct Int32 { } + public struct IntPtr { } + public abstract class Delegate { } + public abstract class MulticastDelegate : Delegate { } + public delegate T Func(); +} +namespace System.Linq +{ + public class Expressions + { + public abstract class Expression { } + public abstract class LambdaExpression : Expression { } + public sealed class Expression : LambdaExpression { } + } +}"; + var sourceB = +@"class Program +{ + static void Main() + { + System.Linq.Expressions.Expression e1 = () => 1; + System.Linq.Expressions.LambdaExpression e2 = () => 2; + System.Linq.Expressions.Expression> e3 = () => 3; + } +}"; + var comp = CreateEmptyCompilation(new[] { sourceA, sourceB }); + comp.VerifyDiagnostics( + // (5,49): error CS1660: Cannot convert lambda expression to type 'Expressions.Expression' because it is not a delegate type + // System.Linq.Expressions.Expression e1 = () => 1; + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 1").WithArguments("lambda expression", "System.Linq.Expressions.Expression").WithLocation(5, 49), + // (6,55): error CS1660: Cannot convert lambda expression to type 'Expressions.LambdaExpression' because it is not a delegate type + // System.Linq.Expressions.LambdaExpression e2 = () => 2; + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 2").WithArguments("lambda expression", "System.Linq.Expressions.LambdaExpression").WithLocation(6, 55), + // (7,67): error CS1660: Cannot convert lambda expression to type 'Expressions.Expression>' because it is not a delegate type + // System.Linq.Expressions.Expression> e3 = () => 3; + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 3").WithArguments("lambda expression", "System.Linq.Expressions.Expression>").WithLocation(7, 67)); + } + + /// + /// System.Linq.Expressions as a nested namespace. + /// + [Fact] + public void SystemLinqExpressions_IsNestedNamespace() + { + var sourceA = +@"namespace System +{ + public class Object { } + public abstract class ValueType { } + public class String { } + public class Type { } + public struct Void { } + public struct Boolean { } + public struct Int32 { } + public struct IntPtr { } + public abstract class Delegate { } + public abstract class MulticastDelegate : Delegate { } + public delegate T Func(); +} +namespace Root.System.Linq.Expressions +{ + public abstract class Expression { } + public abstract class LambdaExpression : Expression { } + public sealed class Expression : LambdaExpression { } +}"; + var sourceB = +@"using System; +using Root.System.Linq.Expressions; +class Program +{ + static void Main() + { + Expression e1 = () => 1; + LambdaExpression e2 = () => 2; + Expression> e3 = () => 3; + } +}"; + var comp = CreateEmptyCompilation(new[] { sourceA, sourceB }); + comp.VerifyDiagnostics( + // (7,25): error CS1660: Cannot convert lambda expression to type 'Expression' because it is not a delegate type + // Expression e1 = () => 1; + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 1").WithArguments("lambda expression", "Root.System.Linq.Expressions.Expression").WithLocation(7, 25), + // (8,31): error CS1660: Cannot convert lambda expression to type 'LambdaExpression' because it is not a delegate type + // LambdaExpression e2 = () => 2; + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 2").WithArguments("lambda expression", "Root.System.Linq.Expressions.LambdaExpression").WithLocation(8, 31), + // (9,36): error CS1660: Cannot convert lambda expression to type 'Expression>' because it is not a delegate type + // Expression> e3 = () => 3; + Diagnostic(ErrorCode.ERR_AnonMethToNonDel, "() => 3").WithArguments("lambda expression", "Root.System.Linq.Expressions.Expression>").WithLocation(9, 36)); + } + [WorkItem(4674, "https://github.com/dotnet/csharplang/issues/4674")] [Fact] public void OverloadResolution_01()