From c85df2bab34a96052642097129b4029328f8ef7f Mon Sep 17 00:00:00 2001 From: Charles Stoner <10732005+cston@users.noreply.github.com> Date: Sat, 19 Feb 2022 20:42:43 -0800 Subject: [PATCH] Additional tests for lambda attributes, explicit return type, and inferred delegate type (#59634) --- .../Semantic/Semantics/DelegateTypeTests.cs | 674 +++++++++++++++++- .../Test/Semantic/Semantics/LambdaTests.cs | 153 +++- .../Semantics/OverloadResolutionPerfTests.cs | 42 +- .../Parsing/LambdaAttributeParsingTests.cs | 97 +++ .../Parsing/LambdaReturnTypeParsingTests.cs | 45 ++ .../Syntax/Syntax/SyntaxNormalizerTests.cs | 29 + 6 files changed, 1029 insertions(+), 11 deletions(-) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs index e9ad802ad31d1..84c8031cf61f3 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/DelegateTypeTests.cs @@ -9,6 +9,7 @@ using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; @@ -1413,6 +1414,49 @@ static class B Assert.Null(symbolInfo.Symbol); } + [Fact] + public void Discard() + { + var source = +@"class Program +{ + static void F() { } + static void F(object o) { } + static void Main() + { + _ = Main; + _ = F; + _ = () => { }; + _ = x => x; + } +}"; + + var expectedDiagnostics = new[] + { + // (7,9): error CS8183: Cannot infer the type of implicitly-typed discard. + // _ = Main; + Diagnostic(ErrorCode.ERR_DiscardTypeInferenceFailed, "_").WithLocation(7, 9), + // (8,9): error CS8183: Cannot infer the type of implicitly-typed discard. + // _ = F; + Diagnostic(ErrorCode.ERR_DiscardTypeInferenceFailed, "_").WithLocation(8, 9), + // (9,9): error CS8183: Cannot infer the type of implicitly-typed discard. + // _ = () => { }; + Diagnostic(ErrorCode.ERR_DiscardTypeInferenceFailed, "_").WithLocation(9, 9), + // (10,9): error CS8183: Cannot infer the type of implicitly-typed discard. + // _ = x => x; + Diagnostic(ErrorCode.ERR_DiscardTypeInferenceFailed, "_").WithLocation(10, 9) + }; + + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); + comp.VerifyDiagnostics(expectedDiagnostics); + + comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + comp.VerifyDiagnostics(expectedDiagnostics); + + comp = CreateCompilation(source); + comp.VerifyDiagnostics(expectedDiagnostics); + } + [WorkItem(55923, "https://github.com/dotnet/roslyn/issues/55923")] [Fact] public void ConvertMethodGroupToObject_01() @@ -1986,7 +2030,7 @@ static void Main() } static Delegate F1() { - return (T t, ref int p) => { }; + return (T t, ref int i) => { }; } static Delegate F2() { @@ -2799,6 +2843,39 @@ static unsafe void Main() Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "(int* p) => p").WithArguments("System.IntPtr").WithLocation(6, 13)); } + [Fact] + public void SystemDelegate_Missing() + { + 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 { } +}"; + var sourceB = +@"class Program +{ + static void F(ref object o) { } + static void Main() + { + var d1 = F; + var d2 = (ref int i) => i; + } +}"; + var comp = CreateEmptyCompilation(new[] { sourceA, sourceB }); + comp.VerifyEmitDiagnostics( + // warning CS8021: No value for RuntimeMetadataVersion found. No assembly containing System.Object was found nor was a value for RuntimeMetadataVersion specified through options. + Diagnostic(ErrorCode.WRN_NoRuntimeMetadataVersion).WithLocation(1, 1), + // error CS0518: Predefined type 'System.MulticastDelegate' is not defined or imported + Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound).WithArguments("System.MulticastDelegate").WithLocation(1, 1)); + } + [Fact] public void SystemMulticastDelegate_Missing() { @@ -5067,7 +5144,7 @@ static void Main() } [Fact] - public void ConditionalOperator_01() + public void NullCoalescingOperator_01() { var source = @"class Program @@ -5881,6 +5958,307 @@ static void Main() Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "F2").WithArguments("Program.F2(T, in T)").WithLocation(11, 16)); } + [Fact] + public void TypeInference_Variance_01() + { + var source = +@"using System; +class Program +{ + static T F(T x, T y) => y; + static void Main() + { + Report(F(() => string.Empty, () => new object())); + } + static void Report(object obj) => Console.WriteLine(obj.GetType()); +}"; + + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); + comp.VerifyDiagnostics( + // (7,16): error CS0411: The type arguments for method 'Program.F(T, T)' cannot be inferred from the usage. Try specifying the type arguments explicitly. + // Report(F(() => string.Empty, () => new object())); + Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "F").WithArguments("Program.F(T, T)").WithLocation(7, 16)); + + CompileAndVerify(source, options: TestOptions.ReleaseExe, expectedOutput: +@"System.Func`1[System.Object] +"); + } + + [Fact] + public void TypeInference_Variance_02() + { + var source = +@"using System; +class Program +{ + static T F(T x, T y) => y; + static void Main() + { + Report(F((string s) => { }, (object o) => { })); + Report(F(string () => default, object () => default)); + } + static void Report(object obj) => Console.WriteLine(obj.GetType()); +}"; + + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); + comp.VerifyDiagnostics( + // (7,16): error CS0411: The type arguments for method 'Program.F(T, T)' cannot be inferred from the usage. Try specifying the type arguments explicitly. + // Report(F((string s) => { }, (object o) => { })); + Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "F").WithArguments("Program.F(T, T)").WithLocation(7, 16), + // (8,16): error CS0411: The type arguments for method 'Program.F(T, T)' cannot be inferred from the usage. Try specifying the type arguments explicitly. + // Report(F(string () => default, object () => default)); + Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "F").WithArguments("Program.F(T, T)").WithLocation(8, 16), + // (8,18): error CS8773: Feature 'lambda return type' is not available in C# 9.0. Please use language version 10.0 or greater. + // Report(F(string () => default, object () => default)); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "string").WithArguments("lambda return type", "10.0").WithLocation(8, 18), + // (8,40): error CS8773: Feature 'lambda return type' is not available in C# 9.0. Please use language version 10.0 or greater. + // Report(F(string () => default, object () => default)); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "object").WithArguments("lambda return type", "10.0").WithLocation(8, 40)); + + comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (7,37): error CS1661: Cannot convert lambda expression to type 'Action' because the parameter types do not match the delegate parameter types + // Report(F((string s) => { }, (object o) => { })); + Diagnostic(ErrorCode.ERR_CantConvAnonMethParams, "(object o) => { }").WithArguments("lambda expression", "System.Action").WithLocation(7, 37), + // (7,45): error CS1678: Parameter 1 is declared as type 'object' but should be 'string' + // Report(F((string s) => { }, (object o) => { })); + Diagnostic(ErrorCode.ERR_BadParamType, "o").WithArguments("1", "", "object", "", "string").WithLocation(7, 45), + // (8,18): error CS8934: Cannot convert lambda expression to type 'Func' because the return type does not match the delegate return type + // Report(F(string () => default, object () => default)); + Diagnostic(ErrorCode.ERR_CantConvAnonMethReturnType, "string () => default").WithArguments("lambda expression", "System.Func").WithLocation(8, 18)); + } + + [Fact] + public void TypeInference_Variance_03() + { + var source = +@"using System; +class Program +{ + static void F1(T t) { } + static T F2() => default; + static T F(T x, T y) => y; + static void Main() + { + Report(F(F1, F1)); + Report(F(F2, F2)); + } + static void Report(object obj) => Console.WriteLine(obj.GetType()); +}"; + + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); + comp.VerifyDiagnostics( + // (9,16): error CS0411: The type arguments for method 'Program.F(T, T)' cannot be inferred from the usage. Try specifying the type arguments explicitly. + // Report(F(F1, F1)); + Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "F").WithArguments("Program.F(T, T)").WithLocation(9, 16), + // (10,16): error CS0411: The type arguments for method 'Program.F(T, T)' cannot be inferred from the usage. Try specifying the type arguments explicitly. + // Report(F(F2, F2)); + Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "F").WithArguments("Program.F(T, T)").WithLocation(10, 16)); + + CompileAndVerify(source, options: TestOptions.ReleaseExe, expectedOutput: +@"System.Action`1[System.String] +System.Func`1[System.Object] +"); + } + + [Fact] + [WorkItem(55909, "https://github.com/dotnet/roslyn/issues/55909")] + public void TypeInference_Variance_04() + { + var source = +@"using System; +class Program +{ + static T F(T x, T y) => y; + static void Main() + { + Report(F((out string s) => { s = default; }, (out object o) => { o = default; })); + } + static void Report(object obj) => Console.WriteLine(obj.GetType()); +}"; + + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); + comp.VerifyDiagnostics( + // (7,16): error CS0411: The type arguments for method 'Program.F(T, T)' cannot be inferred from the usage. Try specifying the type arguments explicitly. + // Report(F((out string s) => { s = default; }, (out object o) => { o = default; }); + Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "F").WithArguments("Program.F(T, T)").WithLocation(7, 16)); + + comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (7,16): error CS0411: The type arguments for method 'Program.F(T, T)' cannot be inferred from the usage. Try specifying the type arguments explicitly. + // Report(F((out string s) => { s = default; }, (out object o) => { o = default; }); + Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "F").WithArguments("Program.F(T, T)").WithLocation(7, 16)); + } + + [Fact] + [WorkItem(55909, "https://github.com/dotnet/roslyn/issues/55909")] + public void TypeInference_Variance_05() + { + var source = +@"using System; +class Program +{ + static void F1(out T t) { t = default; } + static T F(T x, T y) => y; + static void Main() + { + Report(F(F1, F1)); + } + static void Report(object obj) => Console.WriteLine(obj.GetType()); +}"; + + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); + comp.VerifyDiagnostics( + // (8,16): error CS0411: The type arguments for method 'Program.F(T, T)' cannot be inferred from the usage. Try specifying the type arguments explicitly. + // Report(F(F1, F1)); + Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "F").WithArguments("Program.F(T, T)").WithLocation(8, 16)); + + // Compile and execute after fixing https://github.com/dotnet/roslyn/issues/55909. + comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (8,16): error CS0411: The type arguments for method 'Program.F(T, T)' cannot be inferred from the usage. Try specifying the type arguments explicitly. + // Report(F(F1, F1)); + Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "F").WithArguments("Program.F(T, T)").WithLocation(8, 16)); + } + + [Fact] + public void TypeInference_Variance_06() + { + var source = +@"using System; +class Program +{ + static T F(T x, T y) => y; + static void Main() + { + Report(F((ref string x) => { }, (ref object y) => { })); + } + static void Report(object obj) => Console.WriteLine(obj.GetType()); +}"; + + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); + comp.VerifyDiagnostics( + // (7,16): error CS0411: The type arguments for method 'Program.F(T, T)' cannot be inferred from the usage. Try specifying the type arguments explicitly. + // Report(F((out string s) => { s = default; }, (out object o) => { o = default; }); + Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "F").WithArguments("Program.F(T, T)").WithLocation(7, 16)); + + comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (7,16): error CS0411: The type arguments for method 'Program.F(T, T)' cannot be inferred from the usage. Try specifying the type arguments explicitly. + // Report(F((out string s) => { s = default; }, (out object o) => { o = default; }); + Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "F").WithArguments("Program.F(T, T)").WithLocation(7, 16)); + } + + [Fact] + public void TypeInference_Variance_07() + { + var source = +@"using System; +class Program +{ + static void F1(ref T t) { } + static T F(T x, T y) => y; + static void Main() + { + Report(F(F1, F1)); + } + static void Report(object obj) => Console.WriteLine(obj.GetType()); +}"; + + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); + comp.VerifyDiagnostics( + // (8,16): error CS0411: The type arguments for method 'Program.F(T, T)' cannot be inferred from the usage. Try specifying the type arguments explicitly. + // Report(F(F1, F1)); + Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "F").WithArguments("Program.F(T, T)").WithLocation(8, 16)); + + comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (8,16): error CS0411: The type arguments for method 'Program.F(T, T)' cannot be inferred from the usage. Try specifying the type arguments explicitly. + // Report(F(F1, F1)); + Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "F").WithArguments("Program.F(T, T)").WithLocation(8, 16)); + } + + [Fact] + [WorkItem(55909, "https://github.com/dotnet/roslyn/issues/55909")] + public void TypeInference_Variance_08() + { + var source = +@"using System; +class Program +{ + static T F(T x, T y) => y; + static void Main() + { + Report(F((ref int i, string s) => { }, (ref int i, object o) => { })); + Report(F(string (ref int i) => default, object (ref int i) => default)); + } + static void Report(object obj) => Console.WriteLine(obj.GetType()); +}"; + + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); + comp.VerifyDiagnostics( + // (7,16): error CS0411: The type arguments for method 'Program.F(T, T)' cannot be inferred from the usage. Try specifying the type arguments explicitly. + // Report(F((ref int i, string s) => { }, (ref int i, object o) => { })); + Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "F").WithArguments("Program.F(T, T)").WithLocation(7, 16), + // (8,16): error CS0411: The type arguments for method 'Program.F(T, T)' cannot be inferred from the usage. Try specifying the type arguments explicitly. + // Report(F(string (ref int i) => default, object (ref int i) => default)); + Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "F").WithArguments("Program.F(T, T)").WithLocation(8, 16), + // (8,18): error CS8773: Feature 'lambda return type' is not available in C# 9.0. Please use language version 10.0 or greater. + // Report(F(string (ref int i) => default, object (ref int i) => default)); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "string").WithArguments("lambda return type", "10.0").WithLocation(8, 18), + // (8,49): error CS8773: Feature 'lambda return type' is not available in C# 9.0. Please use language version 10.0 or greater. + // Report(F(string (ref int i) => default, object (ref int i) => default)); + Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion9, "object").WithArguments("lambda return type", "10.0").WithLocation(8, 49)); + + comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (7,16): error CS0411: The type arguments for method 'Program.F(T, T)' cannot be inferred from the usage. Try specifying the type arguments explicitly. + // Report(F((ref int i, string s) => { }, (ref int i, object o) => { })); + Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "F").WithArguments("Program.F(T, T)").WithLocation(7, 16), + // (8,16): error CS0411: The type arguments for method 'Program.F(T, T)' cannot be inferred from the usage. Try specifying the type arguments explicitly. + // Report(F(string (ref int i) => default, object (ref int i) => default)); + Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "F").WithArguments("Program.F(T, T)").WithLocation(8, 16)); + } + + [Fact] + [WorkItem(55909, "https://github.com/dotnet/roslyn/issues/55909")] + public void TypeInference_Variance_09() + { + var source = +@"using System; +class Program +{ + static void F1(ref int i, T t) { } + static T F2(ref int i) => default; + static T F(T x, T y) => y; + static void Main() + { + Report(F(F1, F1)); + Report(F(F2, F2)); + } + static void Report(object obj) => Console.WriteLine(obj.GetType()); +}"; + + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); + comp.VerifyDiagnostics( + // (9,16): error CS0411: The type arguments for method 'Program.F(T, T)' cannot be inferred from the usage. Try specifying the type arguments explicitly. + // Report(F(F1, F1)); + Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "F").WithArguments("Program.F(T, T)").WithLocation(9, 16), + // (10,16): error CS0411: The type arguments for method 'Program.F(T, T)' cannot be inferred from the usage. Try specifying the type arguments explicitly. + // Report(F(F2, F2)); + Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "F").WithArguments("Program.F(T, T)").WithLocation(10, 16)); + + // Compile and execute after fixing https://github.com/dotnet/roslyn/issues/55909. + comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (9,16): error CS0411: The type arguments for method 'Program.F(T, T)' cannot be inferred from the usage. Try specifying the type arguments explicitly. + // Report(F(F1, F1)); + Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "F").WithArguments("Program.F(T, T)").WithLocation(9, 16), + // (10,16): error CS0411: The type arguments for method 'Program.F(T, T)' cannot be inferred from the usage. Try specifying the type arguments explicitly. + // Report(F(F2, F2)); + Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "F").WithArguments("Program.F(T, T)").WithLocation(10, 16)); + } + [Fact] public void TypeInference_Nested_01() { @@ -7394,6 +7772,47 @@ static void Main() Diagnostic(ErrorCode.ERR_TypeInferenceFailedForImplicitlyTypedDeconstructionVariable, "y").WithArguments("y").WithLocation(6, 19)); } + [Fact] + public void ImplicitlyTypedVariables_15() + { + var source = +@"class Program +{ + static string F1() => string.Empty; + static void F2(object o) { } + static void M(bool b) + { + var d1 = b ? () => string.Empty : () => string.Empty; + var d2 = b ? F1 : () => string.Empty; + var d3 = b ? (object o) => { } : F2; + var d4 = b ? F2 : F2; + } +}"; + + var expectedDiagnostics = new[] + { + // (7,18): error CS0173: Type of conditional expression cannot be determined because there is no implicit conversion between 'lambda expression' and 'lambda expression' + // var d1 = b ? () => string.Empty : () => string.Empty; + Diagnostic(ErrorCode.ERR_InvalidQM, "b ? () => string.Empty : () => string.Empty").WithArguments("lambda expression", "lambda expression").WithLocation(7, 18), + // (8,18): error CS0173: Type of conditional expression cannot be determined because there is no implicit conversion between 'method group' and 'lambda expression' + // var d2 = b ? F1 : () => string.Empty; + Diagnostic(ErrorCode.ERR_InvalidQM, "b ? F1 : () => string.Empty").WithArguments("method group", "lambda expression").WithLocation(8, 18), + // (9,18): error CS0173: Type of conditional expression cannot be determined because there is no implicit conversion between 'lambda expression' and 'method group' + // var d3 = b ? (object o) => { } : F2; + Diagnostic(ErrorCode.ERR_InvalidQM, "b ? (object o) => { } : F2").WithArguments("lambda expression", "method group").WithLocation(9, 18), + // (10,18): error CS0173: Type of conditional expression cannot be determined because there is no implicit conversion between 'method group' and 'method group' + // var d4 = b ? F2 : F2; + Diagnostic(ErrorCode.ERR_InvalidQM, "b ? F2 : F2").WithArguments("method group", "method group").WithLocation(10, 18) + }; + + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); + comp.VerifyDiagnostics(expectedDiagnostics); + comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + comp.VerifyDiagnostics(expectedDiagnostics); + comp = CreateCompilation(source); + comp.VerifyDiagnostics(expectedDiagnostics); + } + [Fact] public void ImplicitlyTypedVariables_UseSiteErrors() { @@ -9742,6 +10161,257 @@ static void Main() Diagnostic(ErrorCode.ERR_CannotClone, "d2").WithArguments("").WithLocation(8, 14)); } + [Fact] + public void Extension_GetAwaiter_01() + { + var source = +@"using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +class Program +{ + static async Task Main() + { + Type type; + type = await Main; + Console.WriteLine(type); + type = await ((ref int x) => x); + Console.WriteLine(type); + } + static void Report(Delegate d) => Console.WriteLine(d.GetType()); +} +class Awaiter : INotifyCompletion +{ + private Delegate _d; + public Awaiter(Delegate d) { _d = d; } + public void OnCompleted(Action a) { } + public Type GetResult() => _d.GetType(); + public bool IsCompleted => true; +} +static class Extensions +{ + public static Awaiter GetAwaiter(this Delegate d) => new Awaiter(d); +}"; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (9,16): error CS4001: Cannot await 'method group' + // type = await Main; + Diagnostic(ErrorCode.ERR_BadAwaitArgIntrinsic, "await Main").WithArguments("method group").WithLocation(9, 16), + // (11,16): error CS4001: Cannot await 'lambda expression' + // type = await ((ref int x) => x); + Diagnostic(ErrorCode.ERR_BadAwaitArgIntrinsic, "await ((ref int x) => x)").WithArguments("lambda expression").WithLocation(11, 16)); + } + + [Fact] + public void Extension_GetAwaiter_02() + { + var source = +@"using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +class Program +{ + static async Task Main() + { + Type type; + type = await (Delegate)Main; + Console.WriteLine(type); + type = await (Delegate)((ref int x) => x); + Console.WriteLine(type); + } + static void Report(Delegate d) => Console.WriteLine(d.GetType()); +} +class Awaiter : INotifyCompletion +{ + private Delegate _d; + public Awaiter(Delegate d) { _d = d; } + public void OnCompleted(Action a) { } + public Type GetResult() => _d.GetType(); + public bool IsCompleted => true; +} +static class Extensions +{ + public static Awaiter GetAwaiter(this Delegate d) => new Awaiter(d); +}"; + CompileAndVerify(source, expectedOutput: +@"System.Func`1[System.Threading.Tasks.Task] +<>F{00000001}`2[System.Int32,System.Int32] +"); + } + + [Fact] + public void Extension_GetEnumerator_01() + { + var source = +@"using System; +using System.Collections.Generic; +class Program +{ + static void Main() + { + foreach(var d in Main) Report(d); + foreach(var d in (ref int x) => x) Report(d); + } + static void Report(Delegate d) => Console.WriteLine(d.GetType()); +} +static class Extensions +{ + public static IEnumerator GetEnumerator(this Delegate d) + { + yield return d; + } +}"; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (7,26): error CS0446: Foreach cannot operate on a 'method group'. Did you intend to invoke the 'method group'? + // foreach(var d in Main) Report(d); + Diagnostic(ErrorCode.ERR_AnonMethGrpInForEach, "Main").WithArguments("method group").WithLocation(7, 26), + // (8,26): error CS0446: Foreach cannot operate on a 'lambda expression'. Did you intend to invoke the 'lambda expression'? + // foreach(var d in (ref int x) => x) Report(d); + Diagnostic(ErrorCode.ERR_AnonMethGrpInForEach, "(ref int x) => x").WithArguments("lambda expression").WithLocation(8, 26)); + } + + [Fact] + public void Extension_GetEnumerator_02() + { + var source = +@"using System; +using System.Collections.Generic; +class Program +{ + static void Main() + { + foreach (var d in (Delegate)Main) Report(d); + foreach (var d in (Delegate)((ref int x) => x)) Report(d); + } + static void Report(Delegate d) => Console.WriteLine(d.GetType()); +} +static class Extensions +{ + public static IEnumerator GetEnumerator(this Delegate d) + { + yield return d; + } +}"; + CompileAndVerify(source, expectedOutput: +@"System.Action +<>F{00000001}`2[System.Int32,System.Int32] +"); + } + + [Fact] + public void Extension_Deconstruct_01() + { + var source = +@"using System; +class Program +{ + static void Main() + { + Type type; + string name; + (type, name) = Main; + Console.WriteLine(type); + (type, name) = (ref int x) => x; + Console.WriteLine(type); + } + static void Report(Delegate d) => Console.WriteLine(d.GetType()); +} +static class Extensions +{ + public static void Deconstruct(this Delegate d, out Type type, out string name) + { + type = d.GetType(); + name = d.Method.Name; + } +}"; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (8,24): error CS8131: Deconstruct assignment requires an expression with a type on the right-hand-side. + // (type, name) = Main; + Diagnostic(ErrorCode.ERR_DeconstructRequiresExpression, "Main").WithLocation(8, 24), + // (10,24): error CS8131: Deconstruct assignment requires an expression with a type on the right-hand-side. + // (type, name) = (ref int x) => x; + Diagnostic(ErrorCode.ERR_DeconstructRequiresExpression, "(ref int x) => x").WithLocation(10, 24)); + } + + [Fact] + public void Extension_Deconstruct_02() + { + var source = +@"using System; +class Program +{ + static void Main() + { + Type type; + string name; + (type, name) = (Delegate)Main; + Console.WriteLine(type); + (type, name) = (Delegate)((ref int x) => x); + Console.WriteLine(type); + } + static void Report(Delegate d) => Console.WriteLine(d.GetType()); +} +static class Extensions +{ + public static void Deconstruct(this Delegate d, out Type type, out string name) + { + type = d.GetType(); + name = d.Method.Name; + } +}"; + CompileAndVerify(source, expectedOutput: +@"System.Action +<>F{00000001}`2[System.Int32,System.Int32] +"); + } + + [Fact] + public void IOperation() + { + var source = +@"using System; +class Program +{ + static void Main() + { + Delegate d = (int x) => x.ToString(); + } +}"; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var syntax = tree.GetRoot().DescendantNodes().OfType().Single(); + var operation = (IVariableDeclaratorOperation)model.GetOperation(syntax)!; + + var actualText = OperationTreeVerifier.GetOperationTree(comp, operation); + OperationTreeVerifier.Verify( +@"IVariableDeclaratorOperation (Symbol: System.Delegate d) (OperationKind.VariableDeclarator, Type: null) (Syntax: 'd = (int x) ... .ToString()') + Initializer: + IVariableInitializerOperation (OperationKind.VariableInitializer, Type: null) (Syntax: '= (int x) = ... .ToString()') + IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Delegate, IsImplicit) (Syntax: '(int x) => x.ToString()') + Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: True, IsUserDefined: False) (MethodSymbol: null) + Operand: + IDelegateCreationOperation (OperationKind.DelegateCreation, Type: System.Func, IsImplicit) (Syntax: '(int x) => x.ToString()') + Target: + IAnonymousFunctionOperation (Symbol: lambda expression) (OperationKind.AnonymousFunction, Type: null) (Syntax: '(int x) => x.ToString()') + IBlockOperation (1 statements) (OperationKind.Block, Type: null, IsImplicit) (Syntax: 'x.ToString()') + IReturnOperation (OperationKind.Return, Type: null, IsImplicit) (Syntax: 'x.ToString()') + ReturnedValue: + IInvocationOperation (virtual System.String System.Int32.ToString()) (OperationKind.Invocation, Type: System.String) (Syntax: 'x.ToString()') + Instance Receiver: + IParameterReferenceOperation: x (OperationKind.ParameterReference, Type: System.Int32) (Syntax: 'x') + Arguments(0) +", + actualText); + + var value = ((IConversionOperation)operation.Initializer!.Value).Operand; + Assert.Equal("System.Func", value.Type.ToTestDisplayString()); + } + [Fact] public void ClassifyConversionFromExpression() { diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs index 17855adb842ae..7fe132336e9b2 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs @@ -3858,10 +3858,23 @@ static void Main() var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); - var attributeSyntaxes = tree.GetRoot().DescendantNodes().OfType(); - var actualAttributes = attributeSyntaxes.Select(a => model.GetSymbolInfo(a).Symbol.GetSymbol()).ToImmutableArray(); - var expectedAttributes = new[] { "AAttribute", "BAttribute", "CAttribute", "DAttribute" }.Select(a => comp.GetTypeByMetadataName(a).InstanceConstructors.Single()).ToImmutableArray(); - AssertEx.Equal(expectedAttributes, actualAttributes); + var attributeSyntaxes = tree.GetRoot().DescendantNodes().OfType().ToImmutableArray(); + Assert.Equal(4, attributeSyntaxes.Length); + verify(attributeSyntaxes[0], "AAttribute"); + verify(attributeSyntaxes[1], "BAttribute"); + verify(attributeSyntaxes[2], "CAttribute"); + verify(attributeSyntaxes[3], "DAttribute"); + + void verify(AttributeSyntax attributeSyntax, string expectedAttributeName) + { + var expectedAttributeConstructor = comp.GetTypeByMetadataName(expectedAttributeName).InstanceConstructors.Single().GetPublicSymbol(); + var expectedAttributeType = expectedAttributeConstructor.ContainingType; + var typeInfo = model.GetTypeInfo(attributeSyntax); + Assert.Equal(expectedAttributeType, typeInfo.Type); + Assert.Equal(expectedAttributeType, typeInfo.ConvertedType); + var symbol = model.GetSymbolInfo(attributeSyntax).Symbol; + Assert.Equal(expectedAttributeConstructor, symbol); + } } [Theory] @@ -5380,6 +5393,138 @@ static void F(string? x, string y) Diagnostic(ErrorCode.WRN_NullabilityMismatchInReturnTypeOfTargetDelegate, "string? () =>").WithArguments("lambda expression", "System.Func").WithLocation(8, 27)); } + [Fact] + public void LambdaReturnType_18() + { + var source = +@"using System; +class Program +{ + static void F(T t, U u, V v) where U : T + { + Func f1 = T () => u; + Func f2 = T () => v; + Func f3 = U () => t; + } +}"; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (7,30): error CS0029: Cannot implicitly convert type 'V' to 'T' + // Func f2 = T () => v; + Diagnostic(ErrorCode.ERR_NoImplicitConv, "v").WithArguments("V", "T").WithLocation(7, 30), + // (7,30): error CS1662: Cannot convert lambda expression to intended delegate type because some of the return types in the block are not implicitly convertible to the delegate return type + // Func f2 = T () => v; + Diagnostic(ErrorCode.ERR_CantConvAnonMethReturns, "v").WithArguments("lambda expression").WithLocation(7, 30), + // (8,30): error CS0266: Cannot implicitly convert type 'T' to 'U'. An explicit conversion exists (are you missing a cast?) + // Func f3 = U () => t; + Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "t").WithArguments("T", "U").WithLocation(8, 30), + // (8,30): error CS1662: Cannot convert lambda expression to intended delegate type because some of the return types in the block are not implicitly convertible to the delegate return type + // Func f3 = U () => t; + Diagnostic(ErrorCode.ERR_CantConvAnonMethReturns, "t").WithArguments("lambda expression").WithLocation(8, 30)); + } + + [Fact] + public void LambdaReturnType_19() + { + var source = +@"using System; +class Program +{ + static void F(T t, U u, V v) where U : T + { + Delegate d; + d = T () => u; + d = T () => v; + d = U () => t; + } +}"; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics( + // (8,21): error CS0029: Cannot implicitly convert type 'V' to 'T' + // d = T () => v; + Diagnostic(ErrorCode.ERR_NoImplicitConv, "v").WithArguments("V", "T").WithLocation(8, 21), + // (8,21): error CS1662: Cannot convert lambda expression to intended delegate type because some of the return types in the block are not implicitly convertible to the delegate return type + // d = T () => v; + Diagnostic(ErrorCode.ERR_CantConvAnonMethReturns, "v").WithArguments("lambda expression").WithLocation(8, 21), + // (9,21): error CS0266: Cannot implicitly convert type 'T' to 'U'. An explicit conversion exists (are you missing a cast?) + // d = U () => t; + Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "t").WithArguments("T", "U").WithLocation(9, 21), + // (9,21): error CS1662: Cannot convert lambda expression to intended delegate type because some of the return types in the block are not implicitly convertible to the delegate return type + // d = U () => t; + Diagnostic(ErrorCode.ERR_CantConvAnonMethReturns, "t").WithArguments("lambda expression").WithLocation(9, 21)); + } + + [Fact] + public void LambdaReturnType_20() + { + var source = +@"using System; +class Program +{ + static void F(T t, U u, V v) where U : T + { + Func f1 = T () => { if (t is null) return t; return u; }; + Func f2 = U () => { if (t is null) return t; return u; }; + Func f3 = T () => { if (t is null) return t; return v; }; + Func f4 = V () => { if (t is null) return t; return v; }; + } +}"; + var comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview); + comp.VerifyDiagnostics( + // (7,54): error CS0266: Cannot implicitly convert type 'T' to 'U'. An explicit conversion exists (are you missing a cast?) + // Func f2 = U () => { if (t is null) return t; return u; }; + Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "t").WithArguments("T", "U").WithLocation(7, 54), + // (7,54): error CS1662: Cannot convert lambda expression to intended delegate type because some of the return types in the block are not implicitly convertible to the delegate return type + // Func f2 = U () => { if (t is null) return t; return u; }; + Diagnostic(ErrorCode.ERR_CantConvAnonMethReturns, "t").WithArguments("lambda expression").WithLocation(7, 54), + // (8,64): error CS0029: Cannot implicitly convert type 'V' to 'T' + // Func f3 = T () => { if (t is null) return t; return v; }; + Diagnostic(ErrorCode.ERR_NoImplicitConv, "v").WithArguments("V", "T").WithLocation(8, 64), + // (8,64): error CS1662: Cannot convert lambda expression to intended delegate type because some of the return types in the block are not implicitly convertible to the delegate return type + // Func f3 = T () => { if (t is null) return t; return v; }; + Diagnostic(ErrorCode.ERR_CantConvAnonMethReturns, "v").WithArguments("lambda expression").WithLocation(8, 64), + // (9,54): error CS0029: Cannot implicitly convert type 'T' to 'V' + // Func f4 = V () => { if (t is null) return t; return v; }; + Diagnostic(ErrorCode.ERR_NoImplicitConv, "t").WithArguments("T", "V").WithLocation(9, 54), + // (9,54): error CS1662: Cannot convert lambda expression to intended delegate type because some of the return types in the block are not implicitly convertible to the delegate return type + // Func f4 = V () => { if (t is null) return t; return v; }; + Diagnostic(ErrorCode.ERR_CantConvAnonMethReturns, "t").WithArguments("lambda expression").WithLocation(9, 54)); + } + + [Fact] + public void LambdaReturnType_SemanticModel() + { + var source = +@"class Program +{ + static void F() + { + var x = T () => default; + } +}"; + var comp = CreateCompilation(source); + comp.VerifyEmitDiagnostics(); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + var lambdaSyntax = tree.GetRoot().DescendantNodes().OfType().Single(); + + var expectedType = comp.GetMember("Program.F").TypeParameters.Single().GetPublicSymbol(); + Assert.Equal(TypeKind.TypeParameter, expectedType.TypeKind); + Assert.Equal("T", expectedType.ToTestDisplayString()); + + var method = (IMethodSymbol)model.GetSymbolInfo(lambdaSyntax).Symbol; + Assert.Equal(MethodKind.LambdaMethod, method.MethodKind); + + var returnTypeSyntax = lambdaSyntax.ReturnType; + var typeInfo = model.GetTypeInfo(returnTypeSyntax); + Assert.Equal(expectedType, typeInfo.Type); + Assert.Equal(expectedType, typeInfo.ConvertedType); + + var symbolInfo = model.GetSymbolInfo(returnTypeSyntax); + Assert.Equal(expectedType, symbolInfo.Symbol); + } + [Fact] public void LambdaReturnType_CustomModifiers_01() { diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/OverloadResolutionPerfTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/OverloadResolutionPerfTests.cs index 32ef2edbcaf87..32e6578244253 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/OverloadResolutionPerfTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/OverloadResolutionPerfTests.cs @@ -18,7 +18,7 @@ namespace Microsoft.CodeAnalysis.CSharp.UnitTests public class OverloadResolutionPerfTests : CSharpTestBase { [WorkItem(13685, "https://github.com/dotnet/roslyn/issues/13685")] - [ConditionalFactAttribute(typeof(IsRelease), typeof(NoIOperationValidation))] + [ConditionalFact(typeof(IsRelease), typeof(NoIOperationValidation))] public void Overloads() { const int n = 3000; @@ -44,7 +44,7 @@ public void Overloads() } [WorkItem(13685, "https://github.com/dotnet/roslyn/issues/13685")] - [ConditionalFactAttribute(typeof(IsRelease), typeof(NoIOperationValidation))] + [ConditionalFact(typeof(IsRelease), typeof(NoIOperationValidation))] public void BinaryOperatorOverloads() { const int n = 3000; @@ -158,7 +158,7 @@ public void ExtensionMethodsWithLambdaAndParams() comp.VerifyDiagnostics(); } - [ConditionalFactAttribute(typeof(IsRelease), typeof(NoIOperationValidation))] + [ConditionalFact(typeof(IsRelease), typeof(NoIOperationValidation))] public void ExtensionMethodsWithLambdaAndErrors() { const int n = 200; @@ -287,7 +287,7 @@ static class Ext comp.VerifyDiagnostics(); } - [ConditionalFactAttribute(typeof(IsRelease))] + [ConditionalFact(typeof(IsRelease))] [WorkItem(40495, "https://github.com/dotnet/roslyn/issues/40495")] public void NestedLambdas_01() { @@ -311,9 +311,41 @@ static void Main() comp.VerifyDiagnostics(); } + /// + /// A variation of but with + /// explicit parameter types and return type for the lambdas. + /// + [ConditionalFact(typeof(IsRelease))] + public void NestedLambdas_WithParameterAndReturnTypes() + { + var source = +@"#nullable enable +using System.Linq; +class Program +{ + static void Main() + { + Enumerable.Range(0, 1).Sum(int (int a) => + Enumerable.Range(0, 1).Sum(int (int b) => + Enumerable.Range(0, 1).Sum(int (int c) => + Enumerable.Range(0, 1).Sum(int (int d) => + Enumerable.Range(0, 1).Sum(int (int e) => + Enumerable.Range(0, 1).Sum(int (int f) => + Enumerable.Range(0, 1).Sum(int (int g) => + Enumerable.Range(0, 1).Sum(int (int h) => + Enumerable.Range(0, 1).Sum(int (int i) => + Enumerable.Range(0, 1).Sum(int (int j) => + Enumerable.Range(0, 1).Sum(int (int k) => + Enumerable.Range(0, 1).Count(l => true)))))))))))); + } +}"; + var comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + } + // Test should complete in several seconds if UnboundLambda.ReallyBind // uses results from _returnInferenceCache. - [ConditionalFactAttribute(typeof(IsRelease))] + [ConditionalFact(typeof(IsRelease))] [WorkItem(1083969, "https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1083969")] public void NestedLambdas_02() { diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaAttributeParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaAttributeParsingTests.cs index ff4abdd5ca3a9..005d2a46705eb 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaAttributeParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaAttributeParsingTests.cs @@ -2773,6 +2773,103 @@ public void CollectionInitializer_03() EOF(); } + [Fact] + public void ObjectInitializer_01() + { + string source = "new() { P = [A] x => x, Q = [B] () => { } }"; + UsingExpression(source, TestOptions.Regular9); + verify(); + + UsingExpression(source, TestOptions.Regular10); + verify(); + + void verify() + { + N(SyntaxKind.ImplicitObjectCreationExpression); + { + N(SyntaxKind.NewKeyword); + N(SyntaxKind.ArgumentList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.ObjectInitializerExpression); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.SimpleAssignmentExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "P"); + } + N(SyntaxKind.EqualsToken); + N(SyntaxKind.SimpleLambdaExpression); + { + N(SyntaxKind.AttributeList); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "A"); + } + } + N(SyntaxKind.CloseBracketToken); + } + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "x"); + } + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.SimpleAssignmentExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Q"); + } + N(SyntaxKind.EqualsToken); + N(SyntaxKind.ParenthesizedLambdaExpression); + { + N(SyntaxKind.AttributeList); + { + N(SyntaxKind.OpenBracketToken); + N(SyntaxKind.Attribute); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "B"); + } + } + N(SyntaxKind.CloseBracketToken); + } + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + } + N(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + } + [Fact] public void AnonymousType_01() { diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaReturnTypeParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaReturnTypeParsingTests.cs index 4350d251a9d81..b0609099684ab 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaReturnTypeParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/LambdaReturnTypeParsingTests.cs @@ -5003,6 +5003,51 @@ public void Async_06() EOF(); } + [Fact] + public void Async_TopLevelStatement() + { + string source = "async MyMethod() => null;"; + UsingTree(source, TestOptions.Regular9); + verify(); + + UsingTree(source, TestOptions.Regular10); + verify(); + + void verify() + { + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.LocalFunctionStatement); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "async"); + } + N(SyntaxKind.IdentifierToken, "MyMethod"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.ArrowExpressionClause); + { + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.NullLiteralExpression); + { + N(SyntaxKind.NullKeyword); + } + } + N(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + } + [Fact] public void Dynamic_01() { diff --git a/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNormalizerTests.cs b/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNormalizerTests.cs index d72a43893e72a..1e50707c56596 100644 --- a/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNormalizerTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNormalizerTests.cs @@ -399,6 +399,35 @@ public void TestNormalizeStatement1() TestNormalizeStatement("Func f = blah;", "Func f = blah;"); } + [Theory] + [InlineData("[ return:A ]void Local( [ B ]object o){}", "[return: A]\r\nvoid Local([B] object o)\r\n{\r\n}")] + [InlineData("[A,B][C]T Local()=>default;", "[A, B]\r\n[C]\r\nT Local() => default;")] + public void TestLocalFunctionAttributes(string text, string expected) + { + TestNormalizeStatement(text, expected); + } + + [Theory] + [InlineData("( [ A ]x)=>x", "([A] x) => x")] + [InlineData("[return:A]([B]object o)=>{}", "[return: A]\r\n([B] object o) =>\r\n{\r\n}")] + [InlineData("[ A ,B ] [C]()=>x", "[A, B]\r\n[C]\r\n() => x")] + [InlineData("[A]B()=>{ }", "[A]\r\nB() =>\r\n{\r\n}")] + [WorkItem(59653, "https://github.com/dotnet/roslyn/issues/59653")] + public void TestLambdaAttributes(string text, string expected) + { + TestNormalizeExpression(text, expected); + } + + [Theory] + [InlineData("int( x )=>x", "int (x) => x")] + [InlineData("A( B b )=>{}", "A(B b) =>\r\n{\r\n}")] + [InlineData("static\r\nasync\r\nA()=>x", "static async A() => x")] + [WorkItem(59653, "https://github.com/dotnet/roslyn/issues/59653")] + public void TestLambdaReturnType(string text, string expected) + { + TestNormalizeExpression(text, expected); + } + [Theory] [InlineData("int*p;", "int* p;")] [InlineData("int *p;", "int* p;")]