/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/CSharp/Test/Semantic/Semantics/SimpleLambdaParametersWithModifiersTests.cs
1 458 строк
58 KB
Cyrus Najmabadi
Support modifiers with simple lambda parameters. (#75400)
16 янв 2025, 04:26
Не верифицирован
16 янв 2025, 04:26
8c05cc8
Код
Авторство
О чём код?
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System; using System.Linq; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.UnitTests; using Microsoft.CodeAnalysis.Operations; using Microsoft.CodeAnalysis.Test.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.CSharp.Semantic.UnitTests.Semantics; public sealed class SimpleLambdaParametersWithModifiersTests : SemanticModelTestBase { [Fact] public void TestOneParameterWithRef() { var compilation = CreateCompilation(""" delegate void D(ref int x); class C { void M() { D d = (ref x) => { }; } } """).VerifyDiagnostics(); var tree = compilation.SyntaxTrees.Single(); var root = tree.GetRoot(); var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single(); var semanticModel = compilation.GetSemanticModel(tree); var symbol = (IMethodSymbol)semanticModel.GetSymbolInfo(lambda).Symbol!; Assert.Equal(MethodKind.LambdaMethod, symbol.MethodKind); Assert.Equal(RefKind.Ref, symbol.Parameters.Single().RefKind); Assert.Equal(SpecialType.System_Int32, symbol.Parameters.Single().Type.SpecialType); } [Fact] public void TestTwoParametersWithRef() { var compilation = CreateCompilation(""" delegate void D(string s, ref int x); class C { void M() { D d = (s, ref x) => { }; } } """).VerifyDiagnostics(); var tree = compilation.SyntaxTrees.Single(); var root = tree.GetRoot(); var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single(); var semanticModel = compilation.GetSemanticModel(tree); var symbol = (IMethodSymbol)semanticModel.GetSymbolInfo(lambda).Symbol!; Assert.Equal(MethodKind.LambdaMethod, symbol.MethodKind); Assert.True(symbol.Parameters is [{ Type.SpecialType: SpecialType.System_String, RefKind: RefKind.None }, { Type.SpecialType: SpecialType.System_Int32, RefKind: RefKind.Ref }]); } [Fact] public void TestTwoParametersWithRefAndOptionalValue() { var compilation = CreateCompilation(""" delegate void D(string s, ref int x); class C { void M() { D d = (s, ref x = 1) => { }; } } """).VerifyDiagnostics( // (7,19): error CS1741: A ref or out parameter cannot have a default value // D d = (s, ref x = 1) => { }; Diagnostic(ErrorCode.ERR_RefOutDefaultValue, "ref").WithLocation(7, 19), // (7,23): error CS9098: Implicitly typed lambda parameter 'x' cannot have a default value. // D d = (s, ref x = 1) => { }; Diagnostic(ErrorCode.ERR_ImplicitlyTypedDefaultParameter, "x").WithArguments("x").WithLocation(7, 23)); var tree = compilation.SyntaxTrees.Single(); var root = tree.GetRoot(); var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single(); var semanticModel = compilation.GetSemanticModel(tree); var symbol = (IMethodSymbol)semanticModel.GetSymbolInfo(lambda).Symbol!; Assert.Equal(MethodKind.LambdaMethod, symbol.MethodKind); Assert.True(symbol.Parameters is [ { Type.SpecialType: SpecialType.System_String, RefKind: RefKind.None }, { Type.SpecialType: SpecialType.System_Int32, RefKind: RefKind.Ref, IsOptional: false }]); } [Fact] public void TestOneParameterWithAnAttribute() { var compilation = CreateCompilation(""" using System; delegate void D(ref int x); class C { void M() { D d = ([CLSCompliant(false)] ref x) => { }; } } """).VerifyDiagnostics(); var tree = compilation.SyntaxTrees.Single(); var root = tree.GetRoot(); var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single(); var semanticModel = compilation.GetSemanticModel(tree); var symbol = (IMethodSymbol)semanticModel.GetSymbolInfo(lambda).Symbol!; Assert.Equal(MethodKind.LambdaMethod, symbol.MethodKind); Assert.Equal( symbol.Parameters.Single().GetAttributes().Single().AttributeClass, compilation.GetTypeByMetadataName(typeof(CLSCompliantAttribute).FullName).GetPublicSymbol()); } [Fact] public void TestOneParameterWithAnAttributeAndDefaultValue() { var compilation = CreateCompilation(""" using System; delegate void D(ref int x); class C { void M() { D d = ([CLSCompliant(false)] ref x = 0) => { }; } } """).VerifyDiagnostics( // (9,38): error CS1741: A ref or out parameter cannot have a default value // D d = ([CLSCompliant(false)] ref x = 0) => { }; Diagnostic(ErrorCode.ERR_RefOutDefaultValue, "ref").WithLocation(9, 38), // (9,42): error CS9098: Implicitly typed lambda parameter 'x' cannot have a default value. // D d = ([CLSCompliant(false)] ref x = 0) => { }; Diagnostic(ErrorCode.ERR_ImplicitlyTypedDefaultParameter, "x").WithArguments("x").WithLocation(9, 42)); var tree = compilation.SyntaxTrees.Single(); var root = tree.GetRoot(); var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single(); var semanticModel = compilation.GetSemanticModel(tree); var symbol = (IMethodSymbol)semanticModel.GetSymbolInfo(lambda).Symbol!; Assert.Equal(MethodKind.LambdaMethod, symbol.MethodKind); Assert.Equal( symbol.Parameters.Single().GetAttributes().Single().AttributeClass, compilation.GetTypeByMetadataName(typeof(CLSCompliantAttribute).FullName).GetPublicSymbol()); Assert.True(symbol.Parameters is [{ Type.SpecialType: SpecialType.System_Int32, RefKind: RefKind.Ref, IsOptional: false }]); } [Theory] [InlineData("[CLSCompliant(false), My]")] [InlineData("[CLSCompliant(false)][My]")] public void TestOneParameterWithMultipleAttribute(string attributeForm) { var compilation = CreateCompilation($$""" using System; [AttributeUsage(AttributeTargets.Parameter)] class MyAttribute : Attribute; delegate void D(ref int x); class C { void M() { D d = ({{attributeForm}} ref x) => { }; } } """).VerifyDiagnostics(); var tree = compilation.SyntaxTrees.Single(); var root = tree.GetRoot(); var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single(); var semanticModel = compilation.GetSemanticModel(tree); var symbol = (IMethodSymbol)semanticModel.GetSymbolInfo(lambda).Symbol!; Assert.Equal(MethodKind.LambdaMethod, symbol.MethodKind); Assert.True( symbol.Parameters.Single().GetAttributes().Any(a => a.AttributeClass!.Equals( compilation.GetTypeByMetadataName(typeof(CLSCompliantAttribute).FullName).GetPublicSymbol()))); Assert.True( symbol.Parameters.Single().GetAttributes().Any(a => a.AttributeClass!.Equals( compilation.GetTypeByMetadataName("MyAttribute").GetPublicSymbol()))); } [Fact] public void TestOneParameterWithScoped() { var compilation = CreateCompilationWithSpan(""" using System; delegate void D(scoped ReadOnlySpan<int> x); class C { void M() { D d = (scoped x) => { }; } } """).VerifyDiagnostics(); var tree = compilation.SyntaxTrees.Single(); var root = tree.GetRoot(); var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single(); var semanticModel = compilation.GetSemanticModel(tree); var symbol = (IMethodSymbol)semanticModel.GetSymbolInfo(lambda).Symbol!; Assert.Equal(MethodKind.LambdaMethod, symbol.MethodKind); Assert.Equal(ScopedKind.ScopedValue, symbol.Parameters.Single().ScopedKind); Assert.Equal(compilation.GetTypeByMetadataName(typeof(ReadOnlySpan<>).FullName).GetPublicSymbol(), symbol.Parameters.Single().Type.OriginalDefinition); } [Fact] public void TestTwoParametersWithScopedAndRef1() { var compilation = CreateCompilationWithSpan(""" using System; delegate void D(scoped ReadOnlySpan<int> a, ref ReadOnlySpan<int> b); class C { void M() { D d = (scoped a, ref b) => { }; } } """).VerifyDiagnostics(); var tree = compilation.SyntaxTrees.Single(); var root = tree.GetRoot(); var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single(); var semanticModel = compilation.GetSemanticModel(tree); var symbol = (IMethodSymbol)semanticModel.GetSymbolInfo(lambda).Symbol!; Assert.Equal(MethodKind.LambdaMethod, symbol.MethodKind); Assert.Equal(ScopedKind.ScopedValue, symbol.Parameters.First().ScopedKind); Assert.Equal(compilation.GetTypeByMetadataName(typeof(ReadOnlySpan<>).FullName).GetPublicSymbol(), symbol.Parameters.First().Type.OriginalDefinition); } [Fact] public void TestTwoParametersWithScopedAndRef2() { var compilation = CreateCompilationWithSpan(""" using System; delegate void D(scoped ReadOnlySpan<int> a, ref ReadOnlySpan<int> b); class C { void M() { D d = (a, ref b) => { }; } } """).VerifyDiagnostics( // (8,15): error CS8986: The 'scoped' modifier of parameter 'a' doesn't match target 'D'. // D d = (a, ref b) => { }; Diagnostic(ErrorCode.ERR_ScopedMismatchInParameterOfTarget, "(a, ref b) => { }").WithArguments("a", "D").WithLocation(8, 15)); var tree = compilation.SyntaxTrees.Single(); var root = tree.GetRoot(); var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single(); var semanticModel = compilation.GetSemanticModel(tree); var symbol = (IMethodSymbol)semanticModel.GetSymbolInfo(lambda).Symbol!; Assert.Equal(MethodKind.LambdaMethod, symbol.MethodKind); Assert.Equal(ScopedKind.None, symbol.Parameters.First().ScopedKind); Assert.Equal(compilation.GetTypeByMetadataName(typeof(ReadOnlySpan<>).FullName).GetPublicSymbol(), symbol.Parameters.First().Type.OriginalDefinition); } [Fact] public void TestOneParameterWithScopedAndOptionalValue() { var compilation = CreateCompilationWithSpan(""" using System; delegate void D(scoped ReadOnlySpan<int> x); class C { void M() { D d = (scoped x = default) => { }; } } """).VerifyDiagnostics( // (8,23): error CS9098: Implicitly typed lambda parameter 'x' cannot have a default value. // D d = (scoped x = default) => { }; Diagnostic(ErrorCode.ERR_ImplicitlyTypedDefaultParameter, "x").WithArguments("x").WithLocation(8, 23), // (8,23): warning CS9099: Parameter 1 has default value 'null' in lambda but '<missing>' in the target delegate type. // D d = (scoped x = default) => { }; Diagnostic(ErrorCode.WRN_OptionalParamValueMismatch, "x").WithArguments("1", "null", "<missing>").WithLocation(8, 23)); var tree = compilation.SyntaxTrees.Single(); var root = tree.GetRoot(); var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single(); var semanticModel = compilation.GetSemanticModel(tree); var symbol = (IMethodSymbol)semanticModel.GetSymbolInfo(lambda).Symbol!; Assert.Equal(MethodKind.LambdaMethod, symbol.MethodKind); Assert.Equal(ScopedKind.ScopedValue, symbol.Parameters.Single().ScopedKind); Assert.True(symbol.Parameters.Single().IsOptional); Assert.Equal(compilation.GetTypeByMetadataName(typeof(ReadOnlySpan<>).FullName).GetPublicSymbol(), symbol.Parameters.Single().Type.OriginalDefinition); } [Theory, CombinatorialData] public void TestOneParameterWithScopedAsParameterName(bool escaped) { var compilation = CreateCompilationWithSpan($$""" using System; delegate void D(scoped ReadOnlySpan<int> x); class C { void M() { D d = (scoped {{(escaped ? "@" : "")}}scoped) => { }; } } """).VerifyDiagnostics(); var tree = compilation.SyntaxTrees.Single(); var root = tree.GetRoot(); var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single(); var semanticModel = compilation.GetSemanticModel(tree); var symbol = (IMethodSymbol)semanticModel.GetSymbolInfo(lambda).Symbol!; Assert.Equal(MethodKind.LambdaMethod, symbol.MethodKind); Assert.Equal(ScopedKind.ScopedValue, symbol.Parameters.Single().ScopedKind); Assert.Equal("scoped", symbol.Parameters.Single().Name); Assert.Equal(compilation.GetTypeByMetadataName(typeof(ReadOnlySpan<>).FullName).GetPublicSymbol(), symbol.Parameters.Single().Type.OriginalDefinition); } [Fact] public void TestInconsistentUseOfTypes() { var compilation = CreateCompilation(""" delegate void D(string s, ref int x); class C { void M() { D d = (string s, ref x) => { }; } } """).VerifyDiagnostics( // (7,30): error CS0748: Inconsistent lambda parameter usage; parameter types must be all explicit or all implicit // D d = (string s, ref x) => { }; Diagnostic(ErrorCode.ERR_InconsistentLambdaParameterUsage, "x").WithLocation(7, 30)); var tree = compilation.SyntaxTrees.Single(); var root = tree.GetRoot(); var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single(); var semanticModel = compilation.GetSemanticModel(tree); var symbol = (IMethodSymbol)semanticModel.GetSymbolInfo(lambda).Symbol!; Assert.Equal(MethodKind.LambdaMethod, symbol.MethodKind); Assert.True(symbol.Parameters is [ { Type.SpecialType: SpecialType.System_String, RefKind: RefKind.None }, { Type.SpecialType: SpecialType.System_Int32, RefKind: RefKind.Ref }]); } [Fact] public void TestOneParameterWithNoModifiersAndOptionalValue() { var compilation = CreateCompilation(""" delegate void D(int x); class C { void M() { D d = (x = 1) => { }; } } """).VerifyDiagnostics( // (7,16): error CS9098: Implicitly typed lambda parameter 'x' cannot have a default value. // D d = (x = 1) => { }; Diagnostic(ErrorCode.ERR_ImplicitlyTypedDefaultParameter, "x").WithArguments("x").WithLocation(7, 16), // (7,16): warning CS9099: Parameter 1 has default value '1' in lambda but '<missing>' in the target delegate type. // D d = (x = 1) => { }; Diagnostic(ErrorCode.WRN_OptionalParamValueMismatch, "x").WithArguments("1", "1", "<missing>").WithLocation(7, 16)); var tree = compilation.SyntaxTrees.Single(); var root = tree.GetRoot(); var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single(); var semanticModel = compilation.GetSemanticModel(tree); var symbol = (IMethodSymbol)semanticModel.GetSymbolInfo(lambda).Symbol!; Assert.Equal(MethodKind.LambdaMethod, symbol.MethodKind); Assert.True(symbol.Parameters is [{ Type.SpecialType: SpecialType.System_Int32, RefKind: RefKind.None, IsOptional: true }]); } [Fact] public void TestNonParenthesizedLambdaPrecededByRef() { var compilation = CreateCompilation(""" delegate void D(ref int x); class C { void M() { D d = ref x => { }; } } """).VerifyDiagnostics( // (7,11): error CS8171: Cannot initialize a by-value variable with a reference // D d = ref x => { }; Diagnostic(ErrorCode.ERR_InitializeByValueVariableWithReference, "d = ref x => { }").WithLocation(7, 11), // (7,19): error CS1676: Parameter 1 must be declared with the 'ref' keyword // D d = ref x => { }; Diagnostic(ErrorCode.ERR_BadParamRef, "x").WithArguments("1", "ref").WithLocation(7, 19)); var tree = compilation.SyntaxTrees.Single(); var root = tree.GetRoot(); var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single(); var semanticModel = compilation.GetSemanticModel(tree); var symbol = (IMethodSymbol)semanticModel.GetSymbolInfo(lambda).Symbol!; Assert.Equal(MethodKind.LambdaMethod, symbol.MethodKind); Assert.True(symbol.Parameters is [{ Type: IErrorTypeSymbol, RefKind: RefKind.None, IsOptional: false }]); } [Fact] public void TestRefParameterMissingName() { var compilation = CreateCompilation(""" delegate void D(ref int x); class C { void M() { D d = (ref) => { }; } } """).VerifyDiagnostics( // (7,19): error CS1001: Identifier expected // D d = (ref) => { }; Diagnostic(ErrorCode.ERR_IdentifierExpected, ")").WithLocation(7, 19)); var tree = compilation.SyntaxTrees.Single(); var root = tree.GetRoot(); var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single(); var semanticModel = compilation.GetSemanticModel(tree); var symbol = (IMethodSymbol)semanticModel.GetSymbolInfo(lambda).Symbol!; Assert.Equal(MethodKind.LambdaMethod, symbol.MethodKind); Assert.True(symbol.Parameters is [{ Name: "", Type.SpecialType: SpecialType.System_Int32, RefKind: RefKind.Ref, IsOptional: false }]); } [Fact] public void TestAnonymousMethodWithRefParameter() { var compilation = CreateCompilation(""" delegate void D(ref int x); class C { void M() { D d = delegate (ref x) { }; } } """).VerifyDiagnostics( // (7,29): error CS0246: The type or namespace name 'x' could not be found (are you missing a using directive or an assembly reference?) // D d = delegate (ref x) { }; Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "x").WithArguments("x").WithLocation(7, 29), // (7,30): error CS1001: Identifier expected // D d = delegate (ref x) { }; Diagnostic(ErrorCode.ERR_IdentifierExpected, ")").WithLocation(7, 30)); var tree = compilation.SyntaxTrees.Single(); var root = tree.GetRoot(); var lambda = root.DescendantNodes().OfType<AnonymousMethodExpressionSyntax>().Single(); var semanticModel = compilation.GetSemanticModel(tree); var symbol = (IMethodSymbol)semanticModel.GetSymbolInfo(lambda).Symbol!; Assert.Equal(MethodKind.LambdaMethod, symbol.MethodKind); Assert.True(symbol.Parameters is [{ Name: "", Type: IErrorTypeSymbol { Name: "x" }, RefKind: RefKind.Ref, IsOptional: false }]); } [Fact] public void TestLocalFunctionWithRefParameter() { var compilation = CreateCompilation(""" class C { void M() { void LocalFunc(ref x) { }; } } """).VerifyDiagnostics( // (5,14): warning CS8321: The local function 'LocalFunc' is declared but never used // void LocalFunc(ref x) { }; Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "LocalFunc").WithArguments("LocalFunc").WithLocation(5, 14), // (5,28): error CS0246: The type or namespace name 'x' could not be found (are you missing a using directive or an assembly reference?) // void LocalFunc(ref x) { }; Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "x").WithArguments("x").WithLocation(5, 28), // (5,29): error CS1001: Identifier expected // void LocalFunc(ref x) { }; Diagnostic(ErrorCode.ERR_IdentifierExpected, ")").WithLocation(5, 29)); var tree = compilation.SyntaxTrees.Single(); var root = tree.GetRoot(); var lambda = root.DescendantNodes().OfType<LocalFunctionStatementSyntax>().Single(); var semanticModel = compilation.GetSemanticModel(tree); var symbol = semanticModel.GetDeclaredSymbol(lambda)!; Assert.Equal(MethodKind.LocalFunction, symbol.MethodKind); Assert.True(symbol.Parameters is [{ Name: "", Type: IErrorTypeSymbol { Name: "x" }, RefKind: RefKind.Ref, IsOptional: false }]); } [Fact] public void TestOverloadResolution1() { var compilation = CreateCompilation(""" delegate void D(ref int x); delegate void E(ref int x); class C { void M() { M1((ref x) => { }); } void M1(D d) { } void M1(E e) { } } """).VerifyDiagnostics( // (8,9): error CS0121: The call is ambiguous between the following methods or properties: 'C.M1(D)' and 'C.M1(E)' // M1((ref x) => { }); Diagnostic(ErrorCode.ERR_AmbigCall, "M1").WithArguments("C.M1(D)", "C.M1(E)").WithLocation(8, 9)); var tree = compilation.SyntaxTrees.Single(); var root = tree.GetRoot(); var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single(); var semanticModel = compilation.GetSemanticModel(tree); var symbol = (IMethodSymbol)semanticModel.GetSymbolInfo(lambda).Symbol!; Assert.Equal(MethodKind.LambdaMethod, symbol.MethodKind); Assert.True(symbol.Parameters is [{ Name: "x", Type.SpecialType: SpecialType.System_Int32, RefKind: RefKind.Ref, IsOptional: false }]); } [Theory, CombinatorialData] public void TestOverloadResolution2(bool passByRef) { var compilation = CompileAndVerify($$""" using System; delegate void D(ref int x); delegate void E(int x); class C { static void Main() { M1(({{(passByRef ? "ref" : "")}} x) => { }); } static void M1(D d) { Console.WriteLine(0); } static void M1(E e) { Console.WriteLine(1); } } """, expectedOutput: passByRef ? "0" : "1").VerifyDiagnostics().Compilation; var tree = compilation.SyntaxTrees.Single(); var root = tree.GetRoot(); var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single(); var semanticModel = compilation.GetSemanticModel(tree); var symbol = (IMethodSymbol)semanticModel.GetSymbolInfo(lambda).Symbol!; Assert.Equal(MethodKind.LambdaMethod, symbol.MethodKind); Assert.True(symbol.Parameters is [{ Name: "x", Type.SpecialType: SpecialType.System_Int32, IsOptional: false } parameter] && parameter.RefKind == (passByRef ? RefKind.Ref : RefKind.None)); } [Fact] public void TestTypeInference() { var compilation = CreateCompilation(""" delegate void D<T>(ref T x); class C { void M() { M1((ref x) => { }, ""); } void M1<T>(D<T> d, T value) { } } """).VerifyDiagnostics(); var tree = compilation.SyntaxTrees.Single(); var root = tree.GetRoot(); var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single(); var semanticModel = compilation.GetSemanticModel(tree); var symbol = (IMethodSymbol)semanticModel.GetSymbolInfo(lambda).Symbol!; Assert.Equal(MethodKind.LambdaMethod, symbol.MethodKind); Assert.True(symbol.Parameters is [{ Name: "x", Type.SpecialType: SpecialType.System_String, RefKind: RefKind.Ref, IsOptional: false }]); } [Fact] public void TestInModifier() { var compilation = CreateCompilation(""" delegate void D(in int x); class C { void M() { D d = (in x) => { }; } } """).VerifyDiagnostics(); var tree = compilation.SyntaxTrees.Single(); var root = tree.GetRoot(); var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single(); var semanticModel = compilation.GetSemanticModel(tree); var symbol = (IMethodSymbol)semanticModel.GetSymbolInfo(lambda).Symbol!; Assert.Equal(MethodKind.LambdaMethod, symbol.MethodKind); Assert.True(symbol.Parameters is [{ Name: "x", Type.SpecialType: SpecialType.System_Int32, RefKind: RefKind.In, IsOptional: false }]); } [Fact] public void TestInModifierWriteWithinLambda() { var compilation = CreateCompilation(""" delegate void D(in int x); class C { void M() { D d = (in x) => { x = 1; }; } } """).VerifyDiagnostics( // (9,13): error CS8331: Cannot assign to variable 'x' or use it as the right hand side of a ref assignment because it is a readonly variable // x = 1; Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "x").WithArguments("variable", "x").WithLocation(9, 13)); var tree = compilation.SyntaxTrees.Single(); var root = tree.GetRoot(); var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single(); var semanticModel = compilation.GetSemanticModel(tree); var symbol = (IMethodSymbol)semanticModel.GetSymbolInfo(lambda).Symbol!; Assert.Equal(MethodKind.LambdaMethod, symbol.MethodKind); Assert.True(symbol.Parameters is [{ Name: "x", Type.SpecialType: SpecialType.System_Int32, RefKind: RefKind.In, IsOptional: false }]); } [Fact] public void TestOutModifier() { var compilation = CreateCompilation(""" delegate void D(out int x); class C { void M() { D d = (out x) => { x = 1; }; } } """).VerifyDiagnostics(); var tree = compilation.SyntaxTrees.Single(); var root = tree.GetRoot(); var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single(); var semanticModel = compilation.GetSemanticModel(tree); var symbol = (IMethodSymbol)semanticModel.GetSymbolInfo(lambda).Symbol!; Assert.Equal(MethodKind.LambdaMethod, symbol.MethodKind); Assert.True(symbol.Parameters is [{ Name: "x", Type.SpecialType: SpecialType.System_Int32, RefKind: RefKind.Out, IsOptional: false }]); } [Fact] public void TestOutModifierMustBeWrittenWithinLambda() { var compilation = CreateCompilation(""" delegate void D(out int x); class C { void M() { D d = (out x) => { }; } } """).VerifyDiagnostics( // (7,26): error CS0177: The out parameter 'x' must be assigned to before control leaves the current method // D d = (out x) => { }; Diagnostic(ErrorCode.ERR_ParamUnassigned, "{ }").WithArguments("x").WithLocation(7, 26)); var tree = compilation.SyntaxTrees.Single(); var root = tree.GetRoot(); var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single(); var semanticModel = compilation.GetSemanticModel(tree); var symbol = (IMethodSymbol)semanticModel.GetSymbolInfo(lambda).Symbol!; Assert.Equal(MethodKind.LambdaMethod, symbol.MethodKind); Assert.True(symbol.Parameters is [{ Name: "x", Type.SpecialType: SpecialType.System_Int32, RefKind: RefKind.Out, IsOptional: false }]); } [Theory, CombinatorialData] public void TestExpressionTree(bool explicitType) { var compilation = CreateCompilation($$""" using System.Linq.Expressions; delegate int D(ref int x); class C { void M() { Expression<D> e = (ref {{(explicitType ? "int " : "")}}x) => 0; } } """).VerifyDiagnostics( // (9,33): error CS1951: An expression tree lambda may not contain a ref, in or out parameter // Expression<D> e = (ref x) => 0; Diagnostic(ErrorCode.ERR_ByRefParameterInExpressionTree, "x")); var tree = compilation.SyntaxTrees.Single(); var root = tree.GetRoot(); var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single(); var semanticModel = compilation.GetSemanticModel(tree); var symbol = (IMethodSymbol)semanticModel.GetSymbolInfo(lambda).Symbol!; Assert.Equal(MethodKind.LambdaMethod, symbol.MethodKind); Assert.True(symbol.Parameters is [{ Name: "x", Type.SpecialType: SpecialType.System_Int32, RefKind: RefKind.Ref, IsOptional: false }]); } [Fact] public void TestNullable1() { var compilation = CreateCompilation($$""" #nullable enable delegate void D(ref string? x); class C { void M() { D d = (ref x) => { string y = x; }; } } """).VerifyDiagnostics( // (11,24): warning CS8600: Converting null literal or possible null value to non-nullable type. // string y = x; Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "x").WithLocation(11, 24)); var tree = compilation.SyntaxTrees.Single(); var root = tree.GetRoot(); var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single(); var semanticModel = compilation.GetSemanticModel(tree); var symbol = (IMethodSymbol)semanticModel.GetSymbolInfo(lambda).Symbol!; Assert.Equal(MethodKind.LambdaMethod, symbol.MethodKind); Assert.True(symbol.Parameters is [{ Name: "x", Type.SpecialType: SpecialType.System_String, Type.NullableAnnotation: CodeAnalysis.NullableAnnotation.Annotated, RefKind: RefKind.Ref, IsOptional: false }]); } [Fact] public void TestNullable2() { var compilation = CreateCompilation($$""" #nullable enable delegate void D(ref string x); class C { void M() { D d = (ref x) => { x = null; }; } } """).VerifyDiagnostics( // (11,17): warning CS8625: Cannot convert null literal to non-nullable reference type. // x = null; Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(11, 17)); var tree = compilation.SyntaxTrees.Single(); var root = tree.GetRoot(); var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single(); var semanticModel = compilation.GetSemanticModel(tree); var symbol = (IMethodSymbol)semanticModel.GetSymbolInfo(lambda).Symbol!; Assert.Equal(MethodKind.LambdaMethod, symbol.MethodKind); Assert.True(symbol.Parameters is [{ Name: "x", Type.SpecialType: SpecialType.System_String, Type.NullableAnnotation: CodeAnalysis.NullableAnnotation.NotAnnotated, RefKind: RefKind.Ref, IsOptional: false }]); } [Fact] public void TestDynamic() { var compilation = CreateCompilation($$""" delegate void D(ref dynamic x); class C { void M() { D d = (ref x) => { x = null; x = 1; x = ""; x.NonExistent(); }; } } """).VerifyDiagnostics(); var tree = compilation.SyntaxTrees.Single(); var root = tree.GetRoot(); var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single(); var semanticModel = compilation.GetSemanticModel(tree); var symbol = (IMethodSymbol)semanticModel.GetSymbolInfo(lambda).Symbol!; Assert.Equal(MethodKind.LambdaMethod, symbol.MethodKind); Assert.True(symbol.Parameters is [{ Name: "x", Type.TypeKind: TypeKind.Dynamic, RefKind: RefKind.Ref, IsOptional: false }]); } [Theory, CombinatorialData] public void TestParams1(bool delegateIsParams) { var compilation = CreateCompilation($$""" delegate void D({{(delegateIsParams ? "params" : "")}} int[] x); class C { void M() { D d = (params x) => { }; } } """); if (delegateIsParams) { compilation.VerifyDiagnostics( // (7,16): error CS9272: Implicitly typed lambda parameter 'x' cannot have the 'params' modifier. // D d = (params x) => Diagnostic(ErrorCode.ERR_ImplicitlyTypedParamsParameter, "params").WithArguments("x").WithLocation(7, 16)); } else { compilation.VerifyDiagnostics( // (7,16): error CS9272: Implicitly typed lambda parameter 'x' cannot have the 'params' modifier. // D d = (params x) => Diagnostic(ErrorCode.ERR_ImplicitlyTypedParamsParameter, "params").WithArguments("x").WithLocation(7, 16), // (7,23): warning CS9100: Parameter 1 has params modifier in lambda but not in target delegate type. // D d = (params x) => Diagnostic(ErrorCode.WRN_ParamsArrayInLambdaOnly, "x").WithArguments("1").WithLocation(7, 23)); } var tree = compilation.SyntaxTrees.Single(); var root = tree.GetRoot(); var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single(); var semanticModel = compilation.GetSemanticModel(tree); var symbol = (IMethodSymbol)semanticModel.GetSymbolInfo(lambda).Symbol!; Assert.Equal(MethodKind.LambdaMethod, symbol.MethodKind); Assert.True(symbol.Parameters is [{ Name: "x", Type: IArrayTypeSymbol { ElementType.SpecialType: SpecialType.System_Int32 }, IsParams: true }]); } [Fact] public void TestParams2() { var compilation = CreateCompilation($$""" delegate void D(params int[] x); class C { void M() { D d = (x) => { }; } } """).VerifyDiagnostics(); var tree = compilation.SyntaxTrees.Single(); var root = tree.GetRoot(); var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single(); var semanticModel = compilation.GetSemanticModel(tree); var symbol = (IMethodSymbol)semanticModel.GetSymbolInfo(lambda).Symbol!; Assert.Equal(MethodKind.LambdaMethod, symbol.MethodKind); Assert.True(symbol.Parameters is [{ Name: "x", Type: IArrayTypeSymbol { ElementType.SpecialType: SpecialType.System_Int32 }, IsParams: false }]); } [Fact] public void TestIOperation() { var compilation = CreateCompilation(""" delegate void D(ref int x); class C { void M() { D d = (ref x) => { return; }; } } """).VerifyDiagnostics(); var tree = compilation.SyntaxTrees.Single(); var root = tree.GetRoot(); var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single(); var semanticModel = compilation.GetSemanticModel(tree); var operation = (IAnonymousFunctionOperation)semanticModel.GetOperation(lambda)!; Assert.NotNull(operation); compilation.VerifyOperationTree(lambda, """ IAnonymousFunctionOperation (Symbol: lambda expression) (OperationKind.AnonymousFunction, Type: null) (Syntax: '(ref x) => { return; }') IBlockOperation (1 statements) (OperationKind.Block, Type: null) (Syntax: '{ return; }') IReturnOperation (OperationKind.Return, Type: null) (Syntax: 'return;') ReturnedValue: null """); var symbol = operation.Symbol; Assert.Equal(MethodKind.LambdaMethod, symbol.MethodKind); Assert.Equal(RefKind.Ref, symbol.Parameters.Single().RefKind); Assert.Equal(SpecialType.System_Int32, symbol.Parameters.Single().Type.SpecialType); Assert.NotNull(operation.Body); Assert.Single(operation.Body.Operations); Assert.True(operation.Body.Operations.Single() is IReturnOperation { ReturnedValue: null }); } [Fact] public void TestParamsRef() { var compilation = CreateCompilation(""" delegate void D(ref int[] x); class C { void M() { D d = (params ref x) => { }; } } """).VerifyDiagnostics( // (7,16): error CS9272: Implicitly typed lambda parameter 'x' cannot have the 'params' modifier. // D d = (params ref x) => { }; Diagnostic(ErrorCode.ERR_ImplicitlyTypedParamsParameter, "params").WithArguments("x").WithLocation(7, 16), // (7,23): error CS1611: The params parameter cannot be declared as ref // D d = (params ref x) => { }; Diagnostic(ErrorCode.ERR_ParamsCantBeWithModifier, "ref").WithArguments("ref").WithLocation(7, 23), // (7,27): warning CS9100: Parameter 1 has params modifier in lambda but not in target delegate type. // D d = (params ref x) => { }; Diagnostic(ErrorCode.WRN_ParamsArrayInLambdaOnly, "x").WithArguments("1").WithLocation(7, 27)); var tree = compilation.SyntaxTrees.Single(); var root = tree.GetRoot(); var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single(); var semanticModel = compilation.GetSemanticModel(tree); var symbol = (IMethodSymbol)semanticModel.GetSymbolInfo(lambda).Symbol!; Assert.Equal(MethodKind.LambdaMethod, symbol.MethodKind); Assert.True(symbol.Parameters is [{ Name: "x", Type: IArrayTypeSymbol { ElementType.SpecialType: SpecialType.System_Int32 }, RefKind: RefKind.Ref, IsParams: true }]); } [Fact] public void TestRefParams() { var compilation = CreateCompilation(""" delegate void D(ref int[] x); class C { void M() { D d = (ref params x) => { }; } } """).VerifyDiagnostics( // (7,20): error CS8328: The parameter modifier 'params' cannot be used with 'ref' // D d = (ref params x) => { }; Diagnostic(ErrorCode.ERR_BadParameterModifiers, "params").WithArguments("params", "ref").WithLocation(7, 20), // (7,20): error CS9272: Implicitly typed lambda parameter 'x' cannot have the 'params' modifier. // D d = (ref params x) => { }; Diagnostic(ErrorCode.ERR_ImplicitlyTypedParamsParameter, "params").WithArguments("x").WithLocation(7, 20), // (7,27): warning CS9100: Parameter 1 has params modifier in lambda but not in target delegate type. // D d = (ref params x) => { }; Diagnostic(ErrorCode.WRN_ParamsArrayInLambdaOnly, "x").WithArguments("1").WithLocation(7, 27)); var tree = compilation.SyntaxTrees.Single(); var root = tree.GetRoot(); var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single(); var semanticModel = compilation.GetSemanticModel(tree); var symbol = (IMethodSymbol)semanticModel.GetSymbolInfo(lambda).Symbol!; Assert.Equal(MethodKind.LambdaMethod, symbol.MethodKind); Assert.True(symbol.Parameters is [{ Name: "x", Type: IArrayTypeSymbol { ElementType.SpecialType: SpecialType.System_Int32 }, RefKind: RefKind.Ref, IsParams: true }]); } [Fact] public void TestRefToOut() { var compilation = CreateCompilation(""" delegate void D(ref int x); class C { void M() { D d = (out x) => { x = 1; }; } } """).VerifyDiagnostics( // (7,20): error CS1676: Parameter 1 must be declared with the 'ref' keyword // D d = (out x) => { x = 1; }; Diagnostic(ErrorCode.ERR_BadParamRef, "x").WithArguments("1", "ref").WithLocation(7, 20)); var tree = compilation.SyntaxTrees.Single(); var root = tree.GetRoot(); var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single(); var semanticModel = compilation.GetSemanticModel(tree); var symbol = (IMethodSymbol)semanticModel.GetSymbolInfo(lambda).Symbol!; Assert.Equal(MethodKind.LambdaMethod, symbol.MethodKind); Assert.True(symbol.Parameters is [{ Name: "x", Type: IErrorTypeSymbol, RefKind: RefKind.Out, IsParams: false }]); } [Fact] public void TestOutToRef() { var compilation = CreateCompilation(""" delegate void D(out int x); class C { void M() { D d = (ref x) => { x = 1; }; } } """).VerifyDiagnostics( // (7,20): error CS1676: Parameter 1 must be declared with the 'out' keyword // D d = (ref x) => { x = 1; }; Diagnostic(ErrorCode.ERR_BadParamRef, "x").WithArguments("1", "out").WithLocation(7, 20)); var tree = compilation.SyntaxTrees.Single(); var root = tree.GetRoot(); var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single(); var semanticModel = compilation.GetSemanticModel(tree); var symbol = (IMethodSymbol)semanticModel.GetSymbolInfo(lambda).Symbol!; Assert.Equal(MethodKind.LambdaMethod, symbol.MethodKind); Assert.True(symbol.Parameters is [{ Name: "x", Type: IErrorTypeSymbol, RefKind: RefKind.Ref, IsParams: false }]); } [Theory, CombinatorialData] public void TestScopedOnDelegateNotOnLambda(bool includeType) { var compilation = CreateCompilationWithSpan($$""" using System; delegate void D(scoped ReadOnlySpan<int> x); class C { void M() { D d = ({{(includeType ? "ReadOnlySpan<int> " : "")}}x) => { }; } } """).VerifyDiagnostics(); var tree = compilation.SyntaxTrees.Single(); var root = tree.GetRoot(); var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single(); var semanticModel = compilation.GetSemanticModel(tree); var symbol = (IMethodSymbol)semanticModel.GetSymbolInfo(lambda).Symbol!; Assert.Equal(MethodKind.LambdaMethod, symbol.MethodKind); Assert.Equal(ScopedKind.None, symbol.Parameters.Single().ScopedKind); Assert.Equal("x", symbol.Parameters.Single().Name); Assert.Equal(compilation.GetTypeByMetadataName(typeof(ReadOnlySpan<>).FullName).GetPublicSymbol(), symbol.Parameters.Single().Type.OriginalDefinition); } [Theory, CombinatorialData] public void TestScopedOnLambdaNotOnDelegate(bool includeType) { var compilation = CreateCompilationWithSpan($$""" using System; delegate void D(ReadOnlySpan<int> x); class C { void M() { D d = (scoped {{(includeType ? "ReadOnlySpan<int> " : "")}}x) => { }; } } """).VerifyDiagnostics(); var tree = compilation.SyntaxTrees.Single(); var root = tree.GetRoot(); var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single(); var semanticModel = compilation.GetSemanticModel(tree); var symbol = (IMethodSymbol)semanticModel.GetSymbolInfo(lambda).Symbol!; Assert.Equal(MethodKind.LambdaMethod, symbol.MethodKind); Assert.Equal(ScopedKind.ScopedValue, symbol.Parameters.Single().ScopedKind); Assert.Equal("x", symbol.Parameters.Single().Name); Assert.Equal(compilation.GetTypeByMetadataName(typeof(ReadOnlySpan<>).FullName).GetPublicSymbol(), symbol.Parameters.Single().Type.OriginalDefinition); } [Fact] public void TestParamsOnNonParamsType() { var compilation = CreateCompilation(""" delegate void D(int x); class C { void M() { D d = (params x) => { }; } } """).VerifyDiagnostics( // (7,16): error CS9272: Implicitly typed lambda parameter 'x' cannot have the 'params' modifier. // D d = (params x) => { }; Diagnostic(ErrorCode.ERR_ImplicitlyTypedParamsParameter, "params").WithArguments("x").WithLocation(7, 16), // (7,16): error CS0225: The params parameter must have a valid collection type // D d = (params x) => { }; Diagnostic(ErrorCode.ERR_ParamsMustBeCollection, "params").WithLocation(7, 16)); var tree = compilation.SyntaxTrees.Single(); var root = tree.GetRoot(); var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single(); var semanticModel = compilation.GetSemanticModel(tree); var symbol = (IMethodSymbol)semanticModel.GetSymbolInfo(lambda).Symbol!; Assert.Equal(MethodKind.LambdaMethod, symbol.MethodKind); Assert.True(symbol.Parameters is [{ Name: "x", Type.SpecialType: SpecialType.System_Int32, IsParams: true }]); } [Fact] public void TestAccessibilityModifier1() { var compilation = CreateCompilation(""" delegate void D(ref int x); class C { void M() { D d = (public ref x) => { }; } } """).VerifyDiagnostics( // (7,16): error CS1525: Invalid expression term 'public' // D d = (public ref x) => { }; Diagnostic(ErrorCode.ERR_InvalidExprTerm, "public").WithArguments("public").WithLocation(7, 16), // (7,16): error CS1026: ) expected // D d = (public ref x) => { }; Diagnostic(ErrorCode.ERR_CloseParenExpected, "public").WithLocation(7, 16), // (7,16): error CS1002: ; expected // D d = (public ref x) => { }; Diagnostic(ErrorCode.ERR_SemicolonExpected, "public").WithLocation(7, 16), // (7,16): error CS1513: } expected // D d = (public ref x) => { }; Diagnostic(ErrorCode.ERR_RbraceExpected, "public").WithLocation(7, 16), // (7,28): error CS1519: Invalid token ')' in class, record, struct, or interface member declaration // D d = (public ref x) => { }; Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ")").WithArguments(")").WithLocation(7, 28), // (7,28): error CS1519: Invalid token ')' in class, record, struct, or interface member declaration // D d = (public ref x) => { }; Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ")").WithArguments(")").WithLocation(7, 28), // (9,1): error CS1022: Type or namespace definition, or end-of-file expected // } Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(9, 1)); } [Fact] public void TestAccessibilityModifier2() { var compilation = CreateCompilation(""" delegate void D(ref int x); class C { void M() { D d = (ref public x) => { }; } } """).VerifyDiagnostics( // (7,16): error CS1525: Invalid expression term 'ref' // D d = (ref public x) => { }; Diagnostic(ErrorCode.ERR_InvalidExprTerm, "ref ").WithArguments("ref").WithLocation(7, 16), // (7,16): error CS1073: Unexpected token 'ref' // D d = (ref public x) => { }; Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(7, 16), // (7,20): error CS1525: Invalid expression term 'public' // D d = (ref public x) => { }; Diagnostic(ErrorCode.ERR_InvalidExprTerm, "public").WithArguments("public").WithLocation(7, 20), // (7,20): error CS1026: ) expected // D d = (ref public x) => { }; Diagnostic(ErrorCode.ERR_CloseParenExpected, "public").WithLocation(7, 20), // (7,20): error CS1002: ; expected // D d = (ref public x) => { }; Diagnostic(ErrorCode.ERR_SemicolonExpected, "public").WithLocation(7, 20), // (7,20): error CS1513: } expected // D d = (ref public x) => { }; Diagnostic(ErrorCode.ERR_RbraceExpected, "public").WithLocation(7, 20), // (7,28): error CS1519: Invalid token ')' in class, record, struct, or interface member declaration // D d = (ref public x) => { }; Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ")").WithArguments(")").WithLocation(7, 28), // (7,28): error CS1519: Invalid token ')' in class, record, struct, or interface member declaration // D d = (ref public x) => { }; Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ")").WithArguments(")").WithLocation(7, 28), // (9,1): error CS1022: Type or namespace definition, or end-of-file expected // } Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(9, 1)); } [Fact] public void TestOneParameterWithReadonlyRef() { var compilation = CreateCompilation(""" delegate void D(ref int x); class C { void M() { D d = (readonly ref x) => { }; } } """).VerifyDiagnostics( // (7,16): error CS9190: 'readonly' modifier must be specified after 'ref'. // D d = (readonly ref x) => { }; Diagnostic(ErrorCode.ERR_RefReadOnlyWrongOrdering, "readonly").WithLocation(7, 16)); var tree = compilation.SyntaxTrees.Single(); var root = tree.GetRoot(); var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single(); var semanticModel = compilation.GetSemanticModel(tree); var symbol = (IMethodSymbol)semanticModel.GetSymbolInfo(lambda).Symbol!; Assert.Equal(MethodKind.LambdaMethod, symbol.MethodKind); Assert.Equal(RefKind.Ref, symbol.Parameters.Single().RefKind); Assert.Equal(SpecialType.System_Int32, symbol.Parameters.Single().Type.SpecialType); } [Fact] public void TestOneParameterWithRefReadonly1() { var compilation = CreateCompilation(""" delegate void D(ref int x); class C { void M() { D d = (ref readonly x) => { }; } } """).VerifyDiagnostics( // (7,15): warning CS9198: Reference kind modifier of parameter 'ref readonly int x' doesn't match the corresponding parameter 'ref int x' in target. // D d = (ref readonly x) => { }; Diagnostic(ErrorCode.WRN_TargetDifferentRefness, "(ref readonly x) => { }").WithArguments("ref readonly int x", "ref int x").WithLocation(7, 15)); var tree = compilation.SyntaxTrees.Single(); var root = tree.GetRoot(); var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single(); var semanticModel = compilation.GetSemanticModel(tree); var symbol = (IMethodSymbol)semanticModel.GetSymbolInfo(lambda).Symbol!; Assert.Equal(MethodKind.LambdaMethod, symbol.MethodKind); Assert.Equal(RefKind.RefReadOnlyParameter, symbol.Parameters.Single().RefKind); Assert.Equal(SpecialType.System_Int32, symbol.Parameters.Single().Type.SpecialType); } [Fact] public void TestOneParameterWithRefReadonly2() { var compilation = CreateCompilation(""" delegate void D(ref readonly int x); class C { void M() { D d = (ref readonly x) => { }; } } """).VerifyDiagnostics(); var tree = compilation.SyntaxTrees.Single(); var root = tree.GetRoot(); var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single(); var semanticModel = compilation.GetSemanticModel(tree); var symbol = (IMethodSymbol)semanticModel.GetSymbolInfo(lambda).Symbol!; Assert.Equal(MethodKind.LambdaMethod, symbol.MethodKind); Assert.Equal(RefKind.RefReadOnlyParameter, symbol.Parameters.Single().RefKind); Assert.Equal(SpecialType.System_Int32, symbol.Parameters.Single().Type.SpecialType); } [Fact] public void TestOneParameterWithRefReadonly3() { var compilation = CreateCompilation(""" delegate void D(ref readonly int x); class C { void M() { D d = (ref readonly x) => { x = 0; }; } } """).VerifyDiagnostics( // (9,13): error CS8331: Cannot assign to variable 'x' or use it as the right hand side of a ref assignment because it is a readonly variable // x = 0; Diagnostic(ErrorCode.ERR_AssignReadonlyNotField, "x").WithArguments("variable", "x").WithLocation(9, 13)); var tree = compilation.SyntaxTrees.Single(); var root = tree.GetRoot(); var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single(); var semanticModel = compilation.GetSemanticModel(tree); var symbol = (IMethodSymbol)semanticModel.GetSymbolInfo(lambda).Symbol!; Assert.Equal(MethodKind.LambdaMethod, symbol.MethodKind); Assert.Equal(RefKind.RefReadOnlyParameter, symbol.Parameters.Single().RefKind); Assert.Equal(SpecialType.System_Int32, symbol.Parameters.Single().Type.SpecialType); } [Fact] public void TestOneParameterWithRefReadonly4() { var compilation = CreateCompilation(""" delegate void D(ref readonly int x); class C { void M() { D d = (ref x) => { x = 0; }; } } """).VerifyDiagnostics( // (7,20): error CS1676: Parameter 1 must be declared with the 'ref readonly' keyword // D d = (ref x) => Diagnostic(ErrorCode.ERR_BadParamRef, "x").WithArguments("1", "ref readonly").WithLocation(7, 20)); var tree = compilation.SyntaxTrees.Single(); var root = tree.GetRoot(); var lambda = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single(); var semanticModel = compilation.GetSemanticModel(tree); var symbol = (IMethodSymbol)semanticModel.GetSymbolInfo(lambda).Symbol!; Assert.Equal(MethodKind.LambdaMethod, symbol.MethodKind); Assert.Equal(RefKind.Ref, symbol.Parameters.Single().RefKind); Assert.Equal(SpecialType.None, symbol.Parameters.Single().Type.SpecialType); } }