/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs
11 143 строки
419 KB
Jan Jones
Unsafe evolution: allow await in unsafe context (#84616)
3 часа назад
Не верифицирован
3 часа назад
461c2ef
Код
Авторство
О чём код?
// 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. #nullable disable using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Roslyn.Utilities; using System; using System.Collections.Immutable; using System.Diagnostics; using System.Linq; using Xunit; namespace Microsoft.CodeAnalysis.CSharp.UnitTests { public class LocalFunctionsTestBase : CSharpTestBase { internal static readonly CSharpParseOptions DefaultParseOptions = TestOptions.Regular; internal static void VerifyDiagnostics(string source, params DiagnosticDescription[] expected) { var comp = CreateCompilationWithMscorlib461AndCSharp(source, options: TestOptions.ReleaseDll, parseOptions: DefaultParseOptions); comp.VerifyDiagnostics(expected); } } [CompilerTrait(CompilerFeature.LocalFunctions)] public class LocalFunctionTests : LocalFunctionsTestBase { [Fact, WorkItem(29656, "https://github.com/dotnet/roslyn/issues/29656")] public void RefReturningAsyncLocalFunction() { var source = @" public class C { async ref System.Threading.Tasks.Task M() { } public void M2() { _ = local(); async ref System.Threading.Tasks.Task local() { } } }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (4,11): error CS1073: Unexpected token 'ref' // async ref System.Threading.Tasks.Task M() { } Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(4, 11), // (10,15): error CS1073: Unexpected token 'ref' // async ref System.Threading.Tasks.Task local() { } Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(10, 15) ); } [ConditionalFact(typeof(DesktopOnly))] public void LocalFunctionResetsLockScopeFlag() { var source = @" using System; using System.Threading.Tasks; class C { static void Main() { lock (new Object()) { async Task localFunc() { Console.Write(""localFunc""); await Task.Yield(); } localFunc(); } } } "; var comp = CreateCompilationWithMscorlib46(source, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "localFunc"); } [ConditionalFact(typeof(DesktopOnly))] public void LocalFunctionResetsTryCatchFinallyScopeFlags() { var source = @" using System; using System.Collections.Generic; class C { static void Main() { try { IEnumerable<int> localFunc() { yield return 1; } foreach (int i in localFunc()) { Console.Write(i); } throw new Exception(); } catch (Exception) { IEnumerable<int> localFunc() { yield return 2; } foreach (int i in localFunc()) { Console.Write(i); } } finally { IEnumerable<int> localFunc() { yield return 3; } foreach (int i in localFunc()) { Console.Write(i); } } } } "; var comp = CreateCompilationWithMscorlib46(source, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "123"); } [ConditionalFact(typeof(DesktopOnly))] public void LocalFunctionDoesNotOverwriteInnerLockScopeFlag() { var source = @" using System; using System.Collections.Generic; using System.Threading.Tasks; class C { void M(List<Task> listOfTasks) { lock (new Object()) { async Task localFunc() { lock (new Object()) { await Task.Yield(); } } listOfTasks.Add(localFunc()); } } } "; var comp = CreateCompilationWithMscorlib46(source); comp.VerifyDiagnostics( // (16,21): error CS1996: Cannot await in the body of a lock statement // await Task.Yield(); Diagnostic(ErrorCode.ERR_BadAwaitInLock, "await Task.Yield()").WithLocation(16, 21)); } [ConditionalFact(typeof(DesktopOnly))] public void LocalFunctionDoesNotOverwriteInnerTryCatchFinallyScopeFlags() { var source = @" using System; using System.Collections.Generic; class C { void M() { try { IEnumerable<int> localFunc() { try { yield return 1; } catch (Exception) {} } localFunc(); } catch (Exception) { IEnumerable<int> localFunc() { try {} catch (Exception) { yield return 2; } } localFunc(); } finally { IEnumerable<int> localFunc() { try {} finally { yield return 3; } } localFunc(); } } } "; var comp = CreateCompilationWithMscorlib46(source); comp.VerifyDiagnostics( // (15,21): error CS1626: Cannot yield a value in the body of a try block with a catch clause // yield return 1; Diagnostic(ErrorCode.ERR_BadYieldInTryOfCatch, "yield").WithLocation(15, 21), // (29,21): error CS1631: Cannot yield a value in the body of a catch clause // yield return 2; Diagnostic(ErrorCode.ERR_BadYieldInCatch, "yield").WithLocation(29, 21), // (42,21): error CS1625: Cannot yield in the body of a finally clause // yield return 3; Diagnostic(ErrorCode.ERR_BadYieldInFinally, "yield").WithLocation(42, 21)); } [ConditionalFact(typeof(DesktopOnly))] public void RethrowingExceptionsInCatchInsideLocalFuncIsAllowed() { var source = @" using System; class C { static void Main() { try { throw new Exception(); } catch (Exception) { void localFunc() { try { throw new Exception(); } catch (Exception) { Console.Write(""localFunc""); throw; } } try { localFunc(); } catch (Exception) { Console.Write(""_thrown""); } } } } "; var comp = CreateCompilationWithMscorlib46(source, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "localFunc_thrown"); } [ConditionalFact(typeof(DesktopOnly))] public void RethrowingExceptionsInLocalFuncInsideCatchIsNotAllowed() { var source = @" using System; class C { static void Main() { try {} catch (Exception) { void localFunc() { throw; } localFunc(); } } } "; var comp = CreateCompilationWithMscorlib46(source); comp.VerifyDiagnostics( // (13,17): error CS0156: A throw statement with no arguments is not allowed outside of a catch clause // throw; Diagnostic(ErrorCode.ERR_BadEmptyThrow, "throw").WithLocation(13, 17)); } [Fact] public void LocalFunctionTypeParametersUseCorrectBinder() { var text = @" class C { static void M() { void local<[X]T>() {} } }"; var tree = SyntaxFactory.ParseSyntaxTree(text, options: TestOptions.Regular9); var comp = CreateCompilation(tree); var model = comp.GetSemanticModel(tree, ignoreAccessibility: true); var newTree = SyntaxFactory.ParseSyntaxTree(text + " "); var m = newTree.GetRoot() .DescendantNodes().OfType<MethodDeclarationSyntax>().Single(); Assert.True(model.TryGetSpeculativeSemanticModelForMethodBody(m.Body.SpanStart, m, out model)); var x = newTree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Single(); Assert.Equal("X", x.Identifier.Text); // If we aren't using the right binder here, the compiler crashes going through the binder factory var info = model.GetSymbolInfo(x); Assert.Null(info.Symbol); comp.VerifyDiagnostics( // (6,21): error CS0246: The type or namespace name 'XAttribute' could not be found (are you missing a using directive or an assembly reference?) // void local<[X]T>() {} Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "X").WithArguments("XAttribute").WithLocation(6, 21), // (6,21): error CS0246: The type or namespace name 'X' could not be found (are you missing a using directive or an assembly reference?) // void local<[X]T>() {} Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "X").WithArguments("X").WithLocation(6, 21), // (6,14): warning CS8321: The local function 'local' is declared but never used // void local<[X]T>() {} Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "local").WithArguments("local").WithLocation(6, 14)); } [Theory] [InlineData("[A] void local() { }")] [InlineData("[return: A] void local() { }")] [InlineData("void local([A] int i) { }")] [InlineData("void local<[A]T>() {}")] [InlineData("[A] int x = 123;")] public void LocalFunctionAttribute_SpeculativeSemanticModel(string statement) { string text = $@" using System; class A : Attribute {{}} class C {{ static void M() {{ {statement} }} }}"; var tree = SyntaxFactory.ParseSyntaxTree(text); var comp = (Compilation)CreateCompilation(tree); var model = comp.GetSemanticModel(tree); var a = tree.GetRoot().DescendantNodes() .OfType<IdentifierNameSyntax>().ElementAt(2); Assert.Equal("A", a.Identifier.Text); var attrInfo = model.GetSymbolInfo(a); var attrType = comp.GlobalNamespace.GetTypeMember("A"); var attrCtor = attrType.GetMember(".ctor"); Assert.Equal(attrCtor, attrInfo.Symbol); // Assert that this is also true for the speculative semantic model var newTree = SyntaxFactory.ParseSyntaxTree(text + " "); var m = newTree.GetRoot() .DescendantNodes().OfType<MethodDeclarationSyntax>().Single(); Assert.True(model.TryGetSpeculativeSemanticModelForMethodBody(m.Body.SpanStart, m, out model)); a = newTree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().ElementAt(2); Assert.Equal("A", a.Identifier.Text); var info = model.GetSymbolInfo(a); Assert.Equal(attrCtor, info.Symbol); } [Theory] [InlineData(@"[Attr(42, Name = ""hello"")] void local() { }")] [InlineData(@"[return: Attr(42, Name = ""hello"")] void local() { }")] [InlineData(@"void local([Attr(42, Name = ""hello"")] int i) { }")] [InlineData(@"void local<[Attr(42, Name = ""hello"")]T>() {}")] [InlineData(@"[Attr(42, Name = ""hello"")] int x = 123;")] public void LocalFunctionAttribute_Argument_SemanticModel(string statement) { var text = $@" class Attr {{ public Attr(int id) {{ }} public string Name {{ get; set; }} }} class C {{ static void M() {{ {statement} }} }}"; var tree = SyntaxFactory.ParseSyntaxTree(text, options: TestOptions.Regular9); var comp = CreateCompilation(tree); var model = comp.GetSemanticModel(tree, ignoreAccessibility: true); validate(model, tree); var newTree = SyntaxFactory.ParseSyntaxTree(text + " ", options: TestOptions.Regular9); var mMethod = (MethodDeclarationSyntax)newTree.FindNodeOrTokenByKind(SyntaxKind.MethodDeclaration, occurrence: 1).AsNode(); Assert.True(model.TryGetSpeculativeSemanticModelForMethodBody(mMethod.Body.SpanStart, mMethod, out var newModel)); validate(newModel, newTree); static void validate(SemanticModel model, SyntaxTree tree) { var attributeSyntax = tree.GetRoot().DescendantNodes().OfType<AttributeSyntax>().Single(); var attrArgs = attributeSyntax.ArgumentList.Arguments; var attrArg0 = attrArgs[0].Expression; Assert.Null(model.GetSymbolInfo(attrArg0).Symbol); var argType0 = model.GetTypeInfo(attrArg0).Type; Assert.Equal(SpecialType.System_Int32, argType0.SpecialType); var attrArg1 = attrArgs[1].Expression; Assert.Null(model.GetSymbolInfo(attrArg1).Symbol); var argType1 = model.GetTypeInfo(attrArg1).Type; Assert.Equal(SpecialType.System_String, argType1.SpecialType); } } [Fact] public void LocalFunctionAttribute_OnFunction() { const string text = @" using System; class A : Attribute { } class C { void M() { [A] void local() { } } } "; var comp = CreateCompilation(text, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics( // (10,14): warning CS8321: The local function 'local' is declared but never used // void local() { } Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "local").WithArguments("local").WithLocation(10, 14)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var localFunction = tree.GetRoot().DescendantNodes() .OfType<LocalFunctionStatementSyntax>() .Single(); var attributeList = localFunction.AttributeLists.Single(); Assert.Null(attributeList.Target); var attribute = attributeList.Attributes.Single(); Assert.Equal("A", ((SimpleNameSyntax)attribute.Name).Identifier.ValueText); var symbol = (IMethodSymbol)model.GetDeclaredSymbol(localFunction); Assert.NotNull(symbol); var attributes = symbol.GetAttributes().As<CSharpAttributeData>(); Assert.Equal(new[] { "A" }, GetAttributeNames(attributes)); var returnAttributes = symbol.GetReturnTypeAttributes(); Assert.Empty(returnAttributes); } [Fact] public void LocalFunctionAttribute_OnFunction_Argument() { const string text = @" using System; class A : Attribute { internal A(int i) { } } class C { void M() { [A(42)] void local() { } } } "; var comp = CreateCompilation(text, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics( // (13,14): warning CS8321: The local function 'local' is declared but never used // void local() { } Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "local").WithArguments("local").WithLocation(13, 14)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var localFunction = tree.GetRoot().DescendantNodes() .OfType<LocalFunctionStatementSyntax>() .Single(); var attributeList = localFunction.AttributeLists.Single(); Assert.Null(attributeList.Target); var attribute = attributeList.Attributes.Single(); Assert.Equal("A", ((SimpleNameSyntax)attribute.Name).Identifier.ValueText); var symbol = (IMethodSymbol)model.GetDeclaredSymbol(localFunction); Assert.NotNull(symbol); var attributes = symbol.GetAttributes(); var attributeData = attributes.Single(); var aAttribute = comp.GetTypeByMetadataName("A"); Assert.Equal(aAttribute, attributeData.AttributeClass.GetSymbol()); Assert.Equal(aAttribute.InstanceConstructors.Single(), attributeData.AttributeConstructor.GetSymbol()); Assert.Equal(42, attributeData.ConstructorArguments.Single().Value); var returnAttributes = symbol.GetReturnTypeAttributes(); Assert.Empty(returnAttributes); } [Fact] public void LocalFunctionAttribute_OnFunction_LocalArgument() { const string text = @" using System; class A : Attribute { internal A(string s) { } } class C { void M() { #pragma warning disable 0219 // Unreferenced local variable string s1 = ""hello""; const string s2 = ""world""; #pragma warning disable 8321 // Unreferenced local function [A(s1)] // 1 void local1() { } [A(nameof(s1))] void local2() { } [A(s2)] void local3() { } [A(s1.ToString())] // 2 void local4() { } static string local5() => ""hello""; [A(local5())] // 3 void local6() { } } } "; var comp = CreateCompilation(text, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics( // (17,12): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type // [A(s1)] // 1 Diagnostic(ErrorCode.ERR_BadAttributeArgument, "s1").WithLocation(17, 12), // (26,12): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type // [A(s1.ToString())] // 2 Diagnostic(ErrorCode.ERR_BadAttributeArgument, "s1.ToString()").WithLocation(26, 12), // (31,12): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type // [A(local5())] // 3 Diagnostic(ErrorCode.ERR_BadAttributeArgument, "local5()").WithLocation(31, 12)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var arg1 = (AttributeArgumentSyntax)tree.FindNodeOrTokenByKind(SyntaxKind.AttributeArgument, occurrence: 1).AsNode(); Assert.Equal("System.String s1", model.GetSymbolInfo(arg1.Expression).Symbol.ToTestDisplayString()); Assert.Equal(SpecialType.System_String, model.GetTypeInfo(arg1.Expression).Type.SpecialType); var arg2 = (AttributeArgumentSyntax)tree.FindNodeOrTokenByKind(SyntaxKind.AttributeArgument, occurrence: 2).AsNode(); Assert.Null(model.GetSymbolInfo(arg2.Expression).Symbol); Assert.Equal(SpecialType.System_String, model.GetTypeInfo(arg2.Expression).Type.SpecialType); var arg3 = (AttributeArgumentSyntax)tree.FindNodeOrTokenByKind(SyntaxKind.AttributeArgument, occurrence: 3).AsNode(); Assert.Equal("System.String s2", model.GetSymbolInfo(arg3.Expression).Symbol.ToTestDisplayString()); Assert.Equal(SpecialType.System_String, model.GetTypeInfo(arg3.Expression).Type.SpecialType); } [Fact] public void LocalFunctionAttribute_OnFunction_DeclarationPattern() { const string text = @" using System; class A : Attribute { internal A(bool b) { } } class C { void M() { #pragma warning disable 8321 // Unreferenced local function [A(42 is int i)] // 1 void local1() { _ = i.ToString(); // 2 } _ = i.ToString(); // 3 } } "; var comp = CreateCompilation(text, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics( // (13,12): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type // [A(42 is int i)] // 1 Diagnostic(ErrorCode.ERR_BadAttributeArgument, "42 is int i").WithLocation(13, 12), // (16,17): error CS0103: The name 'i' does not exist in the current context // _ = i.ToString(); // 2 Diagnostic(ErrorCode.ERR_NameNotInContext, "i").WithArguments("i").WithLocation(16, 17), // (19,13): error CS0103: The name 'i' does not exist in the current context // _ = i.ToString(); // 3 Diagnostic(ErrorCode.ERR_NameNotInContext, "i").WithArguments("i").WithLocation(19, 13)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var arg = (AttributeArgumentSyntax)tree.FindNodeOrTokenByKind(SyntaxKind.AttributeArgument, occurrence: 1).AsNode(); Assert.Null(model.GetSymbolInfo(arg.Expression).Symbol); Assert.Equal(SpecialType.System_Boolean, model.GetTypeInfo(arg.Expression).Type.SpecialType); var decl = (DeclarationPatternSyntax)tree.FindNodeOrTokenByKind(SyntaxKind.DeclarationPattern, occurrence: 1).AsNode(); Assert.Equal("System.Int32 i", model.GetDeclaredSymbol(decl.Designation).ToTestDisplayString()); } [Fact] public void LocalFunctionAttribute_OnFunction_OutVarInCall() { const string text = @" using System; class A : Attribute { internal A(bool b) { } } class C { void M1() { #pragma warning disable 8321 // Unreferenced local function [A(M2(out var i))] // 1 void local1() { _ = i.ToString(); // 2 } _ = i.ToString(); // 3 } static bool M2(out int x) { x = 0; return false; } } "; var comp = CreateCompilation(text, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics( // (13,12): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type // [A(M2(out var i))] // 1 Diagnostic(ErrorCode.ERR_BadAttributeArgument, "M2(out var i)").WithLocation(13, 12), // (16,17): error CS0103: The name 'i' does not exist in the current context // _ = i.ToString(); // 2 Diagnostic(ErrorCode.ERR_NameNotInContext, "i").WithArguments("i").WithLocation(16, 17), // (19,13): error CS0103: The name 'i' does not exist in the current context // _ = i.ToString(); // 3 Diagnostic(ErrorCode.ERR_NameNotInContext, "i").WithArguments("i").WithLocation(19, 13)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var arg = (AttributeArgumentSyntax)tree.FindNodeOrTokenByKind(SyntaxKind.AttributeArgument, occurrence: 1).AsNode(); Assert.Equal("System.Boolean C.M2(out System.Int32 x)", model.GetSymbolInfo(arg.Expression).Symbol.ToTestDisplayString()); Assert.Equal(SpecialType.System_Boolean, model.GetTypeInfo(arg.Expression).Type.SpecialType); var decl = (DeclarationExpressionSyntax)tree.FindNodeOrTokenByKind(SyntaxKind.DeclarationExpression, occurrence: 1).AsNode(); Assert.Equal("System.Int32 i", model.GetDeclaredSymbol(decl.Designation).ToTestDisplayString()); } [Fact] public void LocalFunctionAttribute_OutParam() { const string text = @" using System; class A : Attribute { internal A(out string s) { s = ""a""; } } class C { void M() { #pragma warning disable 8321, 0168 // Unreferenced local string s; [A(out s)] void local1() { } [A(out var s)] void local2() { } } } "; var comp = CreateCompilation(text, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics( // (15,12): error CS1041: Identifier expected; 'out' is a keyword // [A(out s)] Diagnostic(ErrorCode.ERR_IdentifierExpectedKW, "out").WithArguments("", "out").WithLocation(15, 12), // (15,16): error CS1620: Argument 1 must be passed with the 'out' keyword // [A(out s)] Diagnostic(ErrorCode.ERR_BadArgRef, "s").WithArguments("1", "out").WithLocation(15, 16), // (18,10): error CS1729: 'A' does not contain a constructor that takes 2 arguments // [A(out var s)] Diagnostic(ErrorCode.ERR_BadCtorArgCount, "A(out var s)").WithArguments("A", "2").WithLocation(18, 10), // (18,12): error CS1041: Identifier expected; 'out' is a keyword // [A(out var s)] Diagnostic(ErrorCode.ERR_IdentifierExpectedKW, "out").WithArguments("", "out").WithLocation(18, 12), // (18,16): error CS0103: The name 'var' does not exist in the current context // [A(out var s)] Diagnostic(ErrorCode.ERR_NameNotInContext, "var").WithArguments("var").WithLocation(18, 16), // (18,20): error CS1003: Syntax error, ',' expected // [A(out var s)] Diagnostic(ErrorCode.ERR_SyntaxError, "s").WithArguments(",").WithLocation(18, 20)); } [Fact] public void LocalFunctionAttribute_Return() { const string text = @" using System; class A : Attribute { } class C { void M() { [return: A] int local() => 42; } } "; var comp = CreateCompilation(text, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics( // (10,13): warning CS8321: The local function 'local' is declared but never used // int local() => 42; Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "local").WithArguments("local").WithLocation(10, 13)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var localFunction = tree.GetRoot().DescendantNodes() .OfType<LocalFunctionStatementSyntax>() .Single(); var attributeList = localFunction.AttributeLists.Single(); Assert.Equal(SyntaxKind.ReturnKeyword, attributeList.Target.Identifier.Kind()); var attribute = attributeList.Attributes.Single(); Assert.Equal("A", ((SimpleNameSyntax)attribute.Name).Identifier.ValueText); var symbol = (IMethodSymbol)model.GetDeclaredSymbol(localFunction); Assert.NotNull(symbol); var returnAttributes = symbol.GetReturnTypeAttributes(); var attributeData = returnAttributes.Single(); var aAttribute = comp.GetTypeByMetadataName("A"); Assert.Equal(aAttribute, attributeData.AttributeClass.GetSymbol()); Assert.Equal(aAttribute.InstanceConstructors.Single(), attributeData.AttributeConstructor.GetSymbol()); var attributes = symbol.GetAttributes(); Assert.Empty(attributes); } [Fact] public void LocalFunctionAttribute_Parameter() { var source = @" using System; class A : Attribute { } class C { void M() { int local([A] int i) => i; } } "; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics( // (9,13): warning CS8321: The local function 'local' is declared but never used // int local([A] int i) => i; Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "local").WithArguments("local").WithLocation(9, 13)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var localFunction = tree.GetRoot().DescendantNodes().OfType<LocalFunctionStatementSyntax>().Single(); var parameter = localFunction.ParameterList.Parameters.Single(); var paramSymbol = model.GetDeclaredSymbol(parameter); var attrs = paramSymbol.GetAttributes(); var attr = attrs.Single(); Assert.Equal(comp.GetTypeByMetadataName("A"), attr.AttributeClass.GetSymbol()); } [Fact] public void LocalFunctionAttribute_LangVersionError() { const string text = @" using System; class A : Attribute { } class C { void M() { #pragma warning disable 8321 // Unreferenced local function [A] void local1() { } [return: A] void local2() { } void local3([A] int i) { } void local4<[A] T>() { } } } "; var comp = CreateCompilation(text, parseOptions: TestOptions.Regular8); comp.VerifyDiagnostics( // (10,9): error CS8400: Feature 'local function attributes' is not available in C# 8.0. Please use language version 9.0 or greater. // [A] Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "[A]").WithArguments("local function attributes", "9.0").WithLocation(10, 9), // (13,9): error CS8400: Feature 'local function attributes' is not available in C# 8.0. Please use language version 9.0 or greater. // [return: A] Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "[return: A]").WithArguments("local function attributes", "9.0").WithLocation(13, 9), // (16,21): error CS8400: Feature 'local function attributes' is not available in C# 8.0. Please use language version 9.0 or greater. // void local3([A] int i) { } Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "[A]").WithArguments("local function attributes", "9.0").WithLocation(16, 21), // (18,21): error CS8400: Feature 'local function attributes' is not available in C# 8.0. Please use language version 9.0 or greater. // void local4<[A] T>() { } Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion8, "[A]").WithArguments("local function attributes", "9.0").WithLocation(18, 21)); comp = CreateCompilation(text, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics(); } [Fact] public void LocalFunctionAttribute_BadAttributeLocation() { const string text = @" using System; [AttributeUsage(AttributeTargets.Property)] class PropAttribute : Attribute { } [AttributeUsage(AttributeTargets.Method)] class MethodAttribute : Attribute { } [AttributeUsage(AttributeTargets.ReturnValue)] class ReturnAttribute : Attribute { } [AttributeUsage(AttributeTargets.Parameter)] class ParamAttribute : Attribute { } [AttributeUsage(AttributeTargets.GenericParameter)] class TypeParamAttribute : Attribute { } public class C { public void M() { #pragma warning disable 8321 // Unreferenced local function [Prop] // 1 [Return] // 2 [Method] [return: Prop] // 3 [return: Return] [return: Method] // 4 void local< [Param] // 5 [TypeParam] T>( [Param] [TypeParam] // 6 T t) { } } } "; var comp = CreateCompilation(text, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics( // (22,10): error CS0592: Attribute 'Prop' is not valid on this declaration type. It is only valid on 'property, indexer' declarations. // [Prop] // 1 Diagnostic(ErrorCode.ERR_AttributeOnBadSymbolType, "Prop").WithArguments("Prop", "property, indexer").WithLocation(22, 10), // (23,10): error CS0592: Attribute 'Return' is not valid on this declaration type. It is only valid on 'return' declarations. // [Return] // 2 Diagnostic(ErrorCode.ERR_AttributeOnBadSymbolType, "Return").WithArguments("Return", "return").WithLocation(23, 10), // (25,18): error CS0592: Attribute 'Prop' is not valid on this declaration type. It is only valid on 'property, indexer' declarations. // [return: Prop] // 3 Diagnostic(ErrorCode.ERR_AttributeOnBadSymbolType, "Prop").WithArguments("Prop", "property, indexer").WithLocation(25, 18), // (27,18): error CS0592: Attribute 'Method' is not valid on this declaration type. It is only valid on 'method' declarations. // [return: Method] // 4 Diagnostic(ErrorCode.ERR_AttributeOnBadSymbolType, "Method").WithArguments("Method", "method").WithLocation(27, 18), // (29,14): error CS0592: Attribute 'Param' is not valid on this declaration type. It is only valid on 'parameter' declarations. // [Param] // 5 Diagnostic(ErrorCode.ERR_AttributeOnBadSymbolType, "Param").WithArguments("Param", "parameter").WithLocation(29, 14), // (33,14): error CS0592: Attribute 'TypeParam' is not valid on this declaration type. It is only valid on 'type parameter' declarations. // [TypeParam] // 6 Diagnostic(ErrorCode.ERR_AttributeOnBadSymbolType, "TypeParam").WithArguments("TypeParam", "type parameter").WithLocation(33, 14)); var tree = comp.SyntaxTrees.Single(); var localFunction = tree.GetRoot().DescendantNodes().OfType<LocalFunctionStatementSyntax>().Single(); var model = comp.GetSemanticModel(tree); var symbol = (IMethodSymbol)model.GetDeclaredSymbol(localFunction); Assert.NotNull(symbol); var attributes = symbol.GetAttributes(); Assert.Equal(3, attributes.Length); Assert.Equal(comp.GetTypeByMetadataName("PropAttribute"), attributes[0].AttributeClass.GetSymbol()); Assert.Equal(comp.GetTypeByMetadataName("ReturnAttribute"), attributes[1].AttributeClass.GetSymbol()); Assert.Equal(comp.GetTypeByMetadataName("MethodAttribute"), attributes[2].AttributeClass.GetSymbol()); var returnAttributes = symbol.GetReturnTypeAttributes(); Assert.Equal(3, returnAttributes.Length); Assert.Equal(comp.GetTypeByMetadataName("PropAttribute"), returnAttributes[0].AttributeClass.GetSymbol()); Assert.Equal(comp.GetTypeByMetadataName("ReturnAttribute"), returnAttributes[1].AttributeClass.GetSymbol()); Assert.Equal(comp.GetTypeByMetadataName("MethodAttribute"), returnAttributes[2].AttributeClass.GetSymbol()); } [Fact] public void LocalFunctionAttribute_AttributeSemanticModel() { const string text = @" using System; class A : Attribute { } class C { void M() { local1(); local2(); local3(0); local4<object>(); [A] void local1() { } [return: A] void local2() { } void local3([A] int i) { } void local4<[A] T>() { } } } "; var comp = CreateCompilation(text, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var attributeSyntaxes = tree.GetRoot().DescendantNodes().OfType<AttributeSyntax>().ToList(); Assert.Equal(4, attributeSyntaxes.Count); var attributeConstructor = comp.GetTypeByMetadataName("A").InstanceConstructors.Single(); foreach (var attributeSyntax in attributeSyntaxes) { var symbol = model.GetSymbolInfo(attributeSyntax).Symbol.GetSymbol<MethodSymbol>(); Assert.Equal(attributeConstructor, symbol); } } [Fact] public void StatementAttributeSemanticModel() { const string text = @" using System; class A : Attribute { } class C { void M() { #pragma warning disable 219 // The variable '{0}' is assigned but its value is never used [A] int i = 0; } } "; var comp = CreateCompilation(text); comp.VerifyDiagnostics( // (11,9): error CS7014: Attributes are not valid in this context. // [A] int i = 0; Diagnostic(ErrorCode.ERR_AttributesNotAllowed, "[A]").WithLocation(11, 9)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var attrSyntax = tree.GetRoot().DescendantNodes().OfType<AttributeSyntax>().Single(); var attrConstructor = (IMethodSymbol)model.GetSymbolInfo(attrSyntax).Symbol; Assert.Equal(MethodKind.Constructor, attrConstructor.MethodKind); Assert.Equal("A", attrConstructor.ContainingType.Name); } [Fact] public void LocalFunctionNoBody() { const string text = @" class C { void M() { local1(); void local1(); } } "; var comp = CreateCompilation(text, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics( // (8,14): error CS8112: Local function 'local1()' must either have a body or be marked 'static extern'. // void local1(); Diagnostic(ErrorCode.ERR_LocalFunctionMissingBody, "local1").WithArguments("local1()").WithLocation(8, 14)); } [Fact] public void LocalFunctionExtern() { const string text = @" using System.Runtime.InteropServices; class C { void M() { #pragma warning disable 8321 // Unreferenced local function [DllImport(""a"")] extern void local1(); // 1, 2 [DllImport(""a"")] extern void local2() { } // 3, 4 [DllImport(""a"")] extern int local3() => 0; // 5, 6 static void local4(); // 7 static void local5() { } static int local6() => 0; [DllImport(""a"")] static extern void local7(); [DllImport(""a"")] static extern void local8() { } // 8 [DllImport(""a"")] static extern int local9() => 0; // 9 [DllImport(""a"")] extern static void local10(); [DllImport(""a"")] extern static void local11() { } // 10 [DllImport(""a"")] extern static int local12() => 0; // 11 } } "; var comp = CreateCompilation(text, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics( // (10,10): error CS0601: The DllImport attribute must be specified on a method marked 'extern' that is either 'static' or an extension member // [DllImport("a")] extern void local1(); // 1, 2 Diagnostic(ErrorCode.ERR_DllImportOnInvalidMethod, "DllImport").WithLocation(10, 10), // (10,38): error CS8112: Local function 'local1()' must either have a body or be marked 'static extern'. // [DllImport("a")] extern void local1(); // 1, 2 Diagnostic(ErrorCode.ERR_LocalFunctionMissingBody, "local1").WithArguments("local1()").WithLocation(10, 38), // (11,10): error CS0601: The DllImport attribute must be specified on a method marked 'extern' that is either 'static' or an extension member // [DllImport("a")] extern void local2() { } // 3, 4 Diagnostic(ErrorCode.ERR_DllImportOnInvalidMethod, "DllImport").WithLocation(11, 10), // (11,38): error CS0179: 'local2()' cannot be extern and declare a body // [DllImport("a")] extern void local2() { } // 3, 4 Diagnostic(ErrorCode.ERR_ExternHasBody, "local2").WithArguments("local2()").WithLocation(11, 38), // (12,10): error CS0601: The DllImport attribute must be specified on a method marked 'extern' that is either 'static' or an extension member // [DllImport("a")] extern int local3() => 0; // 5, 6 Diagnostic(ErrorCode.ERR_DllImportOnInvalidMethod, "DllImport").WithLocation(12, 10), // (12,37): error CS0179: 'local3()' cannot be extern and declare a body // [DllImport("a")] extern int local3() => 0; // 5, 6 Diagnostic(ErrorCode.ERR_ExternHasBody, "local3").WithArguments("local3()").WithLocation(12, 37), // (14,21): error CS8112: Local function 'local4()' must either have a body or be marked 'static extern'. // static void local4(); // 7 Diagnostic(ErrorCode.ERR_LocalFunctionMissingBody, "local4").WithArguments("local4()").WithLocation(14, 21), // (19,45): error CS0179: 'local8()' cannot be extern and declare a body // [DllImport("a")] static extern void local8() { } // 8 Diagnostic(ErrorCode.ERR_ExternHasBody, "local8").WithArguments("local8()").WithLocation(19, 45), // (20,44): error CS0179: 'local9()' cannot be extern and declare a body // [DllImport("a")] static extern int local9() => 0; // 9 Diagnostic(ErrorCode.ERR_ExternHasBody, "local9").WithArguments("local9()").WithLocation(20, 44), // (23,45): error CS0179: 'local11()' cannot be extern and declare a body // [DllImport("a")] extern static void local11() { } // 10 Diagnostic(ErrorCode.ERR_ExternHasBody, "local11").WithArguments("local11()").WithLocation(23, 45), // (24,44): error CS0179: 'local12()' cannot be extern and declare a body // [DllImport("a")] extern static int local12() => 0; // 11 Diagnostic(ErrorCode.ERR_ExternHasBody, "local12").WithArguments("local12()").WithLocation(24, 44)); } [Fact] public void LocalFunctionExtern_Generic() { var source = @" using System; using System.Runtime.InteropServices; class C { #pragma warning disable 8321 // Unreferenced local function void M() { [DllImport(""a"")] extern static void local1(); [DllImport(""a"")] extern static void local2<T>(); // 1 void local3() { [DllImport(""a"")] extern static void local1(); [DllImport(""a"")] extern static void local2<T2>(); // 2 } void local4<T4>() { [DllImport(""a"")] extern static void local1(); // 3 [DllImport(""a"")] extern static void local2<T2>(); // 4 } Action a = () => { [DllImport(""a"")] extern static void local1(); [DllImport(""a"")] extern static void local2<T>(); // 5 void local3() { [DllImport(""a"")] extern static void local1(); [DllImport(""a"")] extern static void local2<T2>(); // 6 } void local4<T4>() { [DllImport(""a"")] extern static void local1(); // 7 [DllImport(""a"")] extern static void local2<T2>(); // 8 } }; } }"; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics( // (12,10): error CS7042: The DllImport attribute cannot be applied to a method that is generic or contained in a generic method or type. // [DllImport("a")] extern static void local2<T>(); // 1 Diagnostic(ErrorCode.ERR_DllImportOnGenericMethod, "DllImport").WithLocation(12, 10), // (17,14): error CS7042: The DllImport attribute cannot be applied to a method that is generic or contained in a generic method or type. // [DllImport("a")] extern static void local2<T2>(); // 2 Diagnostic(ErrorCode.ERR_DllImportOnGenericMethod, "DllImport").WithLocation(17, 14), // (22,14): error CS7042: The DllImport attribute cannot be applied to a method that is generic or contained in a generic method or type. // [DllImport("a")] extern static void local1(); // 3 Diagnostic(ErrorCode.ERR_DllImportOnGenericMethod, "DllImport").WithLocation(22, 14), // (23,14): error CS7042: The DllImport attribute cannot be applied to a method that is generic or contained in a generic method or type. // [DllImport("a")] extern static void local2<T2>(); // 4 Diagnostic(ErrorCode.ERR_DllImportOnGenericMethod, "DllImport").WithLocation(23, 14), // (29,14): error CS7042: The DllImport attribute cannot be applied to a method that is generic or contained in a generic method or type. // [DllImport("a")] extern static void local2<T>(); // 5 Diagnostic(ErrorCode.ERR_DllImportOnGenericMethod, "DllImport").WithLocation(29, 14), // (34,18): error CS7042: The DllImport attribute cannot be applied to a method that is generic or contained in a generic method or type. // [DllImport("a")] extern static void local2<T2>(); // 6 Diagnostic(ErrorCode.ERR_DllImportOnGenericMethod, "DllImport").WithLocation(34, 18), // (39,18): error CS7042: The DllImport attribute cannot be applied to a method that is generic or contained in a generic method or type. // [DllImport("a")] extern static void local1(); // 7 Diagnostic(ErrorCode.ERR_DllImportOnGenericMethod, "DllImport").WithLocation(39, 18), // (40,18): error CS7042: The DllImport attribute cannot be applied to a method that is generic or contained in a generic method or type. // [DllImport("a")] extern static void local2<T2>(); // 8 Diagnostic(ErrorCode.ERR_DllImportOnGenericMethod, "DllImport").WithLocation(40, 18)); } [Theory] [InlineData("<CT>", "", "")] [InlineData("", "<MT>", "")] [InlineData("", "", "<LT>")] public void LocalFunctionExtern_Generic_GenericMembers(string classTypeParams, string methodTypeParams, string localFunctionTypeParams) { var source = $@" using System; using System.Runtime.InteropServices; class C{classTypeParams} {{ #pragma warning disable 8321 // Unreferenced local function void M{methodTypeParams}() {{ void localOuter{localFunctionTypeParams}() {{ [DllImport(""a"")] extern static void local1(); // 1 [DllImport(""a"")] extern static void local2<T>(); // 2 void local3() {{ [DllImport(""a"")] extern static void local1(); // 3 [DllImport(""a"")] extern static void local2<T2>(); // 4 }} void local4<T4>() {{ [DllImport(""a"")] extern static void local1(); // 5 [DllImport(""a"")] extern static void local2<T2>(); // 6 }} Action a = () => {{ [DllImport(""a"")] extern static void local1(); // 7 [DllImport(""a"")] extern static void local2<T>(); // 8 void local3() {{ [DllImport(""a"")] extern static void local1(); // 9 [DllImport(""a"")] extern static void local2<T2>(); // 10 }} void local4<T4>() {{ [DllImport(""a"")] extern static void local1(); // 11 [DllImport(""a"")] extern static void local2<T2>(); // 12 }} }}; }} }} }}"; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics( // (13,14): error CS7042: The DllImport attribute cannot be applied to a method that is generic or contained in a generic method or type. // [DllImport("a")] extern static void local1(); // 1 Diagnostic(ErrorCode.ERR_DllImportOnGenericMethod, "DllImport").WithLocation(13, 14), // (14,14): error CS7042: The DllImport attribute cannot be applied to a method that is generic or contained in a generic method or type. // [DllImport("a")] extern static void local2<T>(); // 2 Diagnostic(ErrorCode.ERR_DllImportOnGenericMethod, "DllImport").WithLocation(14, 14), // (18,18): error CS7042: The DllImport attribute cannot be applied to a method that is generic or contained in a generic method or type. // [DllImport("a")] extern static void local1(); // 3 Diagnostic(ErrorCode.ERR_DllImportOnGenericMethod, "DllImport").WithLocation(18, 18), // (19,18): error CS7042: The DllImport attribute cannot be applied to a method that is generic or contained in a generic method or type. // [DllImport("a")] extern static void local2<T2>(); // 4 Diagnostic(ErrorCode.ERR_DllImportOnGenericMethod, "DllImport").WithLocation(19, 18), // (24,18): error CS7042: The DllImport attribute cannot be applied to a method that is generic or contained in a generic method or type. // [DllImport("a")] extern static void local1(); // 5 Diagnostic(ErrorCode.ERR_DllImportOnGenericMethod, "DllImport").WithLocation(24, 18), // (25,18): error CS7042: The DllImport attribute cannot be applied to a method that is generic or contained in a generic method or type. // [DllImport("a")] extern static void local2<T2>(); // 6 Diagnostic(ErrorCode.ERR_DllImportOnGenericMethod, "DllImport").WithLocation(25, 18), // (30,18): error CS7042: The DllImport attribute cannot be applied to a method that is generic or contained in a generic method or type. // [DllImport("a")] extern static void local1(); // 7 Diagnostic(ErrorCode.ERR_DllImportOnGenericMethod, "DllImport").WithLocation(30, 18), // (31,18): error CS7042: The DllImport attribute cannot be applied to a method that is generic or contained in a generic method or type. // [DllImport("a")] extern static void local2<T>(); // 8 Diagnostic(ErrorCode.ERR_DllImportOnGenericMethod, "DllImport").WithLocation(31, 18), // (35,22): error CS7042: The DllImport attribute cannot be applied to a method that is generic or contained in a generic method or type. // [DllImport("a")] extern static void local1(); // 9 Diagnostic(ErrorCode.ERR_DllImportOnGenericMethod, "DllImport").WithLocation(35, 22), // (36,22): error CS7042: The DllImport attribute cannot be applied to a method that is generic or contained in a generic method or type. // [DllImport("a")] extern static void local2<T2>(); // 10 Diagnostic(ErrorCode.ERR_DllImportOnGenericMethod, "DllImport").WithLocation(36, 22), // (41,22): error CS7042: The DllImport attribute cannot be applied to a method that is generic or contained in a generic method or type. // [DllImport("a")] extern static void local1(); // 11 Diagnostic(ErrorCode.ERR_DllImportOnGenericMethod, "DllImport").WithLocation(41, 22), // (42,22): error CS7042: The DllImport attribute cannot be applied to a method that is generic or contained in a generic method or type. // [DllImport("a")] extern static void local2<T2>(); // 12 Diagnostic(ErrorCode.ERR_DllImportOnGenericMethod, "DllImport").WithLocation(42, 22)); } [Fact] public void LocalFunctionExtern_NoImplementationWarning_Attribute() { const string text = @" using System.Runtime.InteropServices; class Attr : System.Attribute { } class C { void M() { #pragma warning disable 8321 // Unreferenced local function static extern void local1(); // 1 static extern void local2() { } // 2 [DllImport(""a"")] static extern void local3(); [Attr] static extern void local4(); } } "; var comp = CreateCompilation(text, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics( // (12,28): warning CS0626: Method, operator, or accessor 'local1()' is marked external and has no attributes on it. Consider adding a DllImport attribute to specify the external implementation. // static extern void local1(); // 1 Diagnostic(ErrorCode.WRN_ExternMethodNoImplementation, "local1").WithArguments("local1()").WithLocation(12, 28), // (13,28): error CS0179: 'local2()' cannot be extern and declare a body // static extern void local2() { } // 2 Diagnostic(ErrorCode.ERR_ExternHasBody, "local2").WithArguments("local2()").WithLocation(13, 28)); } [Fact] public void LocalFunctionExtern_Errors() { const string text = @" class C { #pragma warning disable 8321 // Unreferenced local function void M1() { void local1(); // 1 static extern void local1(); // 2, 3 } void M2() { void local1(); // 4 static extern void local1() { } // 5 } } "; var comp = CreateCompilation(text, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics( // (8,14): error CS8112: Local function 'local1()' must either have a body or be marked 'static extern'. // void local1(); // 1 Diagnostic(ErrorCode.ERR_LocalFunctionMissingBody, "local1").WithArguments("local1()").WithLocation(8, 14), // (9,28): error CS0128: A local variable or function named 'local1' is already defined in this scope // static extern void local1(); // 2, 3 Diagnostic(ErrorCode.ERR_LocalDuplicate, "local1").WithArguments("local1").WithLocation(9, 28), // (9,28): warning CS0626: Method, operator, or accessor 'local1()' is marked external and has no attributes on it. Consider adding a DllImport attribute to specify the external implementation. // static extern void local1(); // 2, 3 Diagnostic(ErrorCode.WRN_ExternMethodNoImplementation, "local1").WithArguments("local1()").WithLocation(9, 28), // (14,14): error CS8112: Local function 'local1()' must either have a body or be marked 'static extern'. // void local1(); // 4 Diagnostic(ErrorCode.ERR_LocalFunctionMissingBody, "local1").WithArguments("local1()").WithLocation(14, 14), // (15,28): error CS0128: A local variable or function named 'local1' is already defined in this scope // static extern void local1() { } // 5 Diagnostic(ErrorCode.ERR_LocalDuplicate, "local1").WithArguments("local1").WithLocation(15, 28)); } [Fact] public void ComImport_Class() { const string text = @" using System; using System.Runtime.InteropServices; [ComImport, Guid(""00020813-0000-0000-c000-000000000046"")] class C { void M() // 1 { #pragma warning disable 8321 // Unreferenced local function void local1() { } } } "; var comp = CreateCompilation(text); comp.VerifyDiagnostics( // (8,10): error CS0423: Since 'C' has the ComImport attribute, 'C.M()' must be extern or abstract // void M() // 1 Diagnostic(ErrorCode.ERR_ComImportWithImpl, "M").WithArguments("C.M()", "C").WithLocation(8, 10)); } [Fact] public void UnsafeLocal() { var source = @" class C { void M() { var bytesA = local(); unsafe byte[] local() { var bytes = new byte[sizeof(int)]; fixed (byte* ptr = &bytes[0]) { *(int*)ptr = sizeof(int); } return bytes; } } }"; var comp = CreateCompilation(source); Assert.Empty(comp.GetDeclarationDiagnostics()); comp.VerifyDiagnostics( // (8,23): error CS0227: Unsafe code may only appear if compiling with /unsafe // unsafe byte[] local() Diagnostic(ErrorCode.ERR_IllegalUnsafe, "local").WithLocation(8, 23) ); var compWithUnsafe = CreateCompilation(source, options: TestOptions.UnsafeDebugDll); compWithUnsafe.VerifyDiagnostics(); } [Fact] public void LocalInUnsafeStruct() { var source = @" unsafe struct C { void A() { var bytesA = local(); var bytesB = B(); byte[] local() { var bytes = new byte[sizeof(int)]; fixed (byte* ptr = &bytes[0]) { *(int*)ptr = sizeof(int); } return bytes; } } byte[] B() { var bytes = new byte[sizeof(long)]; fixed (byte* ptr = &bytes[0]) { *(long*)ptr = sizeof(long); } return bytes; } }"; // no need to declare local function `local` or method `B` as unsafe var compWithUnsafe = CreateCompilation(source, options: TestOptions.UnsafeDebugDll); compWithUnsafe.VerifyDiagnostics(); } [Fact] public void LocalInUnsafeBlock() { var source = @" struct C { void A() { unsafe { var bytesA = local(); byte[] local() { var bytes = new byte[sizeof(int)]; fixed (byte* ptr = &bytes[0]) { *(int*)ptr = sizeof(int); } return bytes; } } } }"; // no need to declare local function `local` as unsafe var compWithUnsafe = CreateCompilation(source, options: TestOptions.UnsafeDebugDll); compWithUnsafe.VerifyDiagnostics(); } [Fact] public void ConstraintBinding() { var comp = CreateCompilation(@" class C { void M() { void Local<T, U>() where T : U where U : class { } Local<object, object>(); } }"); comp.VerifyDiagnostics(); } [Fact] public void ConstraintBinding2() { var comp = CreateCompilation(@" class C { void M() { void Local<T, U>(T t) where T : U where U : t { } Local<object, object>(null); } }"); comp.VerifyDiagnostics( // (8,23): error CS0246: The type or namespace name 't' could not be found (are you missing a using directive or an assembly reference?) // where U : t Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "t").WithArguments("t").WithLocation(8, 23), // (11,9): error CS0311: The type 'object' cannot be used as type parameter 'U' in the generic type or method 'Local<T, U>(T)'. There is no implicit reference conversion from 'object' to 't'. // Local<object, object>(null); Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "Local<object, object>").WithArguments("Local<T, U>(T)", "t", "U", "object").WithLocation(11, 9)); } [Fact] [WorkItem(17014, "https://github.com/dotnet/roslyn/pull/17014")] public void RecursiveLocalFuncsAsParameterTypes() { var comp = CreateCompilation(@" class C { void M() { int L(L2 l2) => 0; int L2(L l1) => 0; } }"); comp.VerifyDiagnostics( // (6,15): error CS0246: The type or namespace name 'L2' could not be found (are you missing a using directive or an assembly reference?) // int L(L2 l2) => 0; Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "L2").WithArguments("L2").WithLocation(6, 15), // (7,16): error CS0246: The type or namespace name 'L' could not be found (are you missing a using directive or an assembly reference?) // int L2(L l1) => 0; Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "L").WithArguments("L").WithLocation(7, 16), // (6,13): warning CS8321: The local function 'L' is declared but never used // int L(L2 l2) => 0; Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "L").WithArguments("L").WithLocation(6, 13), // (7,13): warning CS8321: The local function 'L2' is declared but never used // int L2(L l1) => 0; Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "L2").WithArguments("L2").WithLocation(7, 13)); } [Fact] [WorkItem(16451, "https://github.com/dotnet/roslyn/issues/16451")] public void BadGenericConstraint() { var comp = CreateCompilation(@" class C { public void M<T>(T value) where T : class, object { } }"); comp.VerifyDiagnostics( // (4,48): error CS0702: Constraint cannot be special class 'object' // public void M<T>(T value) where T : class, object { } Diagnostic(ErrorCode.ERR_SpecialTypeAsBound, "object").WithArguments("object").WithLocation(4, 48) ); } [Fact] [WorkItem(16451, "https://github.com/dotnet/roslyn/issues/16451")] public void RecursiveDefaultParameter() { var comp = CreateCompilation(@" class C { public static void Main() { int Local(int j = Local()) => 0; Local(); } }"); comp.VerifyDiagnostics( // (6,27): error CS1736: Default parameter value for 'j' must be a compile-time constant // int Local(int j = Local()) => 0; Diagnostic(ErrorCode.ERR_DefaultValueMustBeConstant, "Local()").WithArguments("j").WithLocation(6, 27)); comp.DeclarationDiagnostics.Verify(); } [Fact] [WorkItem(16451, "https://github.com/dotnet/roslyn/issues/16451")] public void RecursiveDefaultParameter2() { var comp = CreateCompilation(@" using System; class C { void M() { int Local(Action a = Local) => 0; Local(); } }"); comp.VerifyDiagnostics( // (7,30): error CS1736: Default parameter value for 'a' must be a compile-time constant // int Local(Action a = Local) => 0; Diagnostic(ErrorCode.ERR_DefaultValueMustBeConstant, "Local").WithArguments("a").WithLocation(7, 30)); comp.DeclarationDiagnostics.Verify(); } [Fact] [WorkItem(16451, "https://github.com/dotnet/roslyn/issues/16451")] public void MutuallyRecursiveDefaultParameters() { var comp = CreateCompilation(@" class C { void M() { int Local1(int p = Local2()) => 0; int Local2(int p = Local1()) => 0; Local1(); Local2(); } }"); comp.VerifyDiagnostics( // (6,28): error CS1736: Default parameter value for 'p' must be a compile-time constant // int Local1(int p = Local2()) => 0; Diagnostic(ErrorCode.ERR_DefaultValueMustBeConstant, "Local2()").WithArguments("p").WithLocation(6, 28), // (7,28): error CS1736: Default parameter value for 'p' must be a compile-time constant // int Local2(int p = Local1()) => 0; Diagnostic(ErrorCode.ERR_DefaultValueMustBeConstant, "Local1()").WithArguments("p").WithLocation(7, 28)); comp.DeclarationDiagnostics.Verify(); } [Fact] public void FetchLocalFunctionSymbolThroughLocal() { var tree = SyntaxFactory.ParseSyntaxTree(@" using System; class C { public void M() { void Local<[A, B, CLSCompliant, D]T>() { var x = new object(); } Local<int>(); } }"); var comp = CreateCompilation(tree); comp.DeclarationDiagnostics.Verify(); comp.VerifyDiagnostics( // (7,21): error CS0246: The type or namespace name 'AAttribute' could not be found (are you missing a using directive or an assembly reference?) // void Local<[A, B, CLSCompliant, D]T>() Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "A").WithArguments("AAttribute").WithLocation(7, 21), // (7,21): error CS0246: The type or namespace name 'A' could not be found (are you missing a using directive or an assembly reference?) // void Local<[A, B, CLSCompliant, D]T>() Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "A").WithArguments("A").WithLocation(7, 21), // (7,24): error CS0246: The type or namespace name 'BAttribute' could not be found (are you missing a using directive or an assembly reference?) // void Local<[A, B, CLSCompliant, D]T>() Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "B").WithArguments("BAttribute").WithLocation(7, 24), // (7,24): error CS0246: The type or namespace name 'B' could not be found (are you missing a using directive or an assembly reference?) // void Local<[A, B, CLSCompliant, D]T>() Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "B").WithArguments("B").WithLocation(7, 24), // (7,41): error CS0246: The type or namespace name 'DAttribute' could not be found (are you missing a using directive or an assembly reference?) // void Local<[A, B, CLSCompliant, D]T>() Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "D").WithArguments("DAttribute").WithLocation(7, 41), // (7,41): error CS0246: The type or namespace name 'D' could not be found (are you missing a using directive or an assembly reference?) // void Local<[A, B, CLSCompliant, D]T>() Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "D").WithArguments("D").WithLocation(7, 41), // (7,27): error CS7036: There is no argument given that corresponds to the required parameter 'isCompliant' of 'CLSCompliantAttribute.CLSCompliantAttribute(bool)' // void Local<[A, B, CLSCompliant, D]T>() Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "CLSCompliant").WithArguments("isCompliant", "System.CLSCompliantAttribute.CLSCompliantAttribute(bool)").WithLocation(7, 27)); var model = comp.GetSemanticModel(tree); var x = tree.GetRoot().DescendantNodes().OfType<VariableDeclaratorSyntax>().Where(v => v.Identifier.ValueText == "x").Single(); var localSymbol = model.GetDeclaredSymbol(x).ContainingSymbol.GetSymbol<LocalFunctionSymbol>(); var typeParam = localSymbol.TypeParameters.Single(); var attrs = typeParam.GetAttributes(); Assert.True(attrs[0].AttributeClass.IsErrorType()); Assert.True(attrs[1].AttributeClass.IsErrorType()); Assert.False(attrs[2].AttributeClass.IsErrorType()); Assert.Equal(comp.GlobalNamespace .GetMember<NamespaceSymbol>("System") .GetMember<NamedTypeSymbol>("CLSCompliantAttribute"), attrs[2].AttributeClass); Assert.True(attrs[3].AttributeClass.IsErrorType()); comp.DeclarationDiagnostics.Verify(); } [Fact] public void TypeParameterAttributesInSemanticModel() { var comp = (Compilation)CreateCompilation(@" using System; class C { public void M() { void Local<[A]T, [CLSCompliant]U>() { } } }", parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics( // (7,21): error CS0246: The type or namespace name 'AAttribute' could not be found (are you missing a using directive or an assembly reference?) // void Local<[A]T, [CLSCompliant]U>() { } Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "A").WithArguments("AAttribute").WithLocation(7, 21), // (7,21): error CS0246: The type or namespace name 'A' could not be found (are you missing a using directive or an assembly reference?) // void Local<[A]T, [CLSCompliant]U>() { } Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "A").WithArguments("A").WithLocation(7, 21), // (7,27): error CS7036: There is no argument given that corresponds to the required parameter 'isCompliant' of 'CLSCompliantAttribute.CLSCompliantAttribute(bool)' // void Local<[A]T, [CLSCompliant]U>() { } Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "CLSCompliant").WithArguments("isCompliant", "System.CLSCompliantAttribute.CLSCompliantAttribute(bool)").WithLocation(7, 27), // (7,14): warning CS8321: The local function 'Local' is declared but never used // void Local<[A]T, [CLSCompliant]U>() { } Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "Local").WithArguments("Local").WithLocation(7, 14)); var tree = comp.SyntaxTrees.First(); var root = tree.GetRoot(); var model = comp.GetSemanticModel(tree); var a = root.DescendantNodes() .OfType<IdentifierNameSyntax>() .Where(id => id.Identifier.ValueText == "A") .Single(); Assert.Null(model.GetDeclaredSymbol(a)); var aSymbolInfo = model.GetSymbolInfo(a); Assert.Equal(0, aSymbolInfo.CandidateSymbols.Length); Assert.Null(aSymbolInfo.Symbol); var aTypeInfo = model.GetTypeInfo(a); Assert.Equal(TypeKind.Error, aTypeInfo.Type.TypeKind); Assert.Null(model.GetAliasInfo(a)); Assert.Empty(model.LookupNamespacesAndTypes(a.SpanStart, name: "A")); var clsCompliant = root.DescendantNodes() .OfType<IdentifierNameSyntax>() .Where(id => id.Identifier.ValueText == "CLSCompliant") .Single(); var clsCompliantSymbol = comp.GlobalNamespace .GetMember<INamespaceSymbol>("System") .GetTypeMember("CLSCompliantAttribute"); Assert.Null(model.GetDeclaredSymbol(clsCompliant)); // This should be null because there is no CLSCompliant ctor with no args var clsCompliantSymbolInfo = model.GetSymbolInfo(clsCompliant); Assert.Null(clsCompliantSymbolInfo.Symbol); Assert.Equal(clsCompliantSymbol.GetMember<IMethodSymbol>(".ctor"), clsCompliantSymbolInfo.CandidateSymbols.Single()); Assert.Equal(CandidateReason.OverloadResolutionFailure, clsCompliantSymbolInfo.CandidateReason); Assert.Equal(clsCompliantSymbol, model.GetTypeInfo(clsCompliant).Type); Assert.Null(model.GetAliasInfo(clsCompliant)); Assert.Equal(clsCompliantSymbol, model.LookupNamespacesAndTypes(clsCompliant.SpanStart, name: "CLSCompliantAttribute").Single()); ((CSharpCompilation)comp).DeclarationDiagnostics.Verify(); } [Fact] public void ParameterAttributesInSemanticModel() { var comp = (Compilation)CreateCompilation(@" using System; class C { public void M() { void Local([A]int x, [CLSCompliant]int y) { } } }", parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics( // (7,21): error CS0246: The type or namespace name 'AAttribute' could not be found (are you missing a using directive or an assembly reference?) // void Local([A]int x, [CLSCompliant]int y) { } Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "A").WithArguments("AAttribute").WithLocation(7, 21), // (7,21): error CS0246: The type or namespace name 'A' could not be found (are you missing a using directive or an assembly reference?) // void Local([A]int x, [CLSCompliant]int y) { } Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "A").WithArguments("A").WithLocation(7, 21), // (7,31): error CS7036: There is no argument given that corresponds to the required parameter 'isCompliant' of 'CLSCompliantAttribute.CLSCompliantAttribute(bool)' // void Local([A]int x, [CLSCompliant]int y) { } Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "CLSCompliant").WithArguments("isCompliant", "System.CLSCompliantAttribute.CLSCompliantAttribute(bool)").WithLocation(7, 31), // (7,14): warning CS8321: The local function 'Local' is declared but never used // void Local([A]int x, [CLSCompliant]int y) { } Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "Local").WithArguments("Local").WithLocation(7, 14)); var tree = comp.SyntaxTrees.First(); var root = tree.GetRoot(); var model = comp.GetSemanticModel(tree); var a = root.DescendantNodes() .OfType<IdentifierNameSyntax>() .Where(id => id.Identifier.ValueText == "A") .Single(); Assert.Null(model.GetDeclaredSymbol(a)); var aSymbolInfo = model.GetSymbolInfo(a); Assert.Equal(0, aSymbolInfo.CandidateSymbols.Length); Assert.Null(aSymbolInfo.Symbol); var aTypeInfo = model.GetTypeInfo(a); Assert.Equal(TypeKind.Error, aTypeInfo.Type.TypeKind); Assert.Null(model.GetAliasInfo(a)); Assert.Empty(model.LookupNamespacesAndTypes(a.SpanStart, name: "A")); var clsCompliant = root.DescendantNodes() .OfType<IdentifierNameSyntax>() .Where(id => id.Identifier.ValueText == "CLSCompliant") .Single(); var clsCompliantSymbol = comp.GlobalNamespace .GetMember<INamespaceSymbol>("System") .GetTypeMember("CLSCompliantAttribute"); Assert.Null(model.GetDeclaredSymbol(clsCompliant)); // This should be null because there is no CLSCompliant ctor with no args var clsCompliantSymbolInfo = model.GetSymbolInfo(clsCompliant); Assert.Null(clsCompliantSymbolInfo.Symbol); Assert.Equal(clsCompliantSymbol.GetMember<IMethodSymbol>(".ctor"), clsCompliantSymbolInfo.CandidateSymbols.Single()); Assert.Equal(CandidateReason.OverloadResolutionFailure, clsCompliantSymbolInfo.CandidateReason); Assert.Equal(clsCompliantSymbol, model.GetTypeInfo(clsCompliant).Type); Assert.Null(model.GetAliasInfo(clsCompliant)); Assert.Equal(clsCompliantSymbol, model.LookupNamespacesAndTypes(clsCompliant.SpanStart, name: "CLSCompliantAttribute").Single()); ((CSharpCompilation)comp).DeclarationDiagnostics.Verify(); } [Fact] public void LocalFunctionAttribute_TypeParameter_Errors() { var tree = SyntaxFactory.ParseSyntaxTree(@" using System; class C { public void M() { void Local<[A, B, CLSCompliant, D]T>() { } Local<int>(); } }", options: TestOptions.Regular9); var comp = CreateCompilation(tree); comp.DeclarationDiagnostics.Verify(); comp.VerifyDiagnostics( // (7,21): error CS0246: The type or namespace name 'AAttribute' could not be found (are you missing a using directive or an assembly reference?) // void Local<[A, B, CLSCompliant, D]T>() { } Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "A").WithArguments("AAttribute").WithLocation(7, 21), // (7,21): error CS0246: The type or namespace name 'A' could not be found (are you missing a using directive or an assembly reference?) // void Local<[A, B, CLSCompliant, D]T>() { } Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "A").WithArguments("A").WithLocation(7, 21), // (7,24): error CS0246: The type or namespace name 'BAttribute' could not be found (are you missing a using directive or an assembly reference?) // void Local<[A, B, CLSCompliant, D]T>() { } Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "B").WithArguments("BAttribute").WithLocation(7, 24), // (7,24): error CS0246: The type or namespace name 'B' could not be found (are you missing a using directive or an assembly reference?) // void Local<[A, B, CLSCompliant, D]T>() { } Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "B").WithArguments("B").WithLocation(7, 24), // (7,41): error CS0246: The type or namespace name 'DAttribute' could not be found (are you missing a using directive or an assembly reference?) // void Local<[A, B, CLSCompliant, D]T>() { } Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "D").WithArguments("DAttribute").WithLocation(7, 41), // (7,41): error CS0246: The type or namespace name 'D' could not be found (are you missing a using directive or an assembly reference?) // void Local<[A, B, CLSCompliant, D]T>() { } Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "D").WithArguments("D").WithLocation(7, 41), // (7,27): error CS7036: There is no argument given that corresponds to the required parameter 'isCompliant' of 'CLSCompliantAttribute.CLSCompliantAttribute(bool)' // void Local<[A, B, CLSCompliant, D]T>() { } Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "CLSCompliant").WithArguments("isCompliant", "System.CLSCompliantAttribute.CLSCompliantAttribute(bool)").WithLocation(7, 27)); var localDecl = tree.FindNodeOrTokenByKind(SyntaxKind.LocalFunctionStatement); var model = comp.GetSemanticModel(tree); var localSymbol = Assert.IsType<LocalFunctionSymbol>(model.GetDeclaredSymbol(localDecl.AsNode()).GetSymbol()); var typeParam = localSymbol.TypeParameters.Single(); var attrs = typeParam.GetAttributes(); Assert.True(attrs[0].AttributeClass.IsErrorType()); Assert.True(attrs[1].AttributeClass.IsErrorType()); Assert.False(attrs[2].AttributeClass.IsErrorType()); Assert.Equal(comp.GlobalNamespace .GetMember<NamespaceSymbol>("System") .GetMember<NamedTypeSymbol>("CLSCompliantAttribute"), attrs[2].AttributeClass); Assert.True(attrs[3].AttributeClass.IsErrorType()); comp.DeclarationDiagnostics.Verify(); } [Fact] public void LocalFunctionAttribute_Parameter_Errors() { var tree = SyntaxFactory.ParseSyntaxTree(@" using System; class C { public void M() { void Local([A, B]int x, [CLSCompliant]string s = """") { } Local(0); } }", options: TestOptions.Regular9); var comp = CreateCompilation(tree); comp.DeclarationDiagnostics.Verify(); comp.VerifyDiagnostics( // (7,21): error CS0246: The type or namespace name 'AAttribute' could not be found (are you missing a using directive or an assembly reference?) // void Local([A, B]int x, [CLSCompliant]string s = "") { } Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "A").WithArguments("AAttribute").WithLocation(7, 21), // (7,21): error CS0246: The type or namespace name 'A' could not be found (are you missing a using directive or an assembly reference?) // void Local([A, B]int x, [CLSCompliant]string s = "") { } Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "A").WithArguments("A").WithLocation(7, 21), // (7,24): error CS0246: The type or namespace name 'BAttribute' could not be found (are you missing a using directive or an assembly reference?) // void Local([A, B]int x, [CLSCompliant]string s = "") { } Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "B").WithArguments("BAttribute").WithLocation(7, 24), // (7,24): error CS0246: The type or namespace name 'B' could not be found (are you missing a using directive or an assembly reference?) // void Local([A, B]int x, [CLSCompliant]string s = "") { } Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "B").WithArguments("B").WithLocation(7, 24), // (7,34): error CS7036: There is no argument given that corresponds to the required parameter 'isCompliant' of 'CLSCompliantAttribute.CLSCompliantAttribute(bool)' // void Local([A, B]int x, [CLSCompliant]string s = "") { } Diagnostic(ErrorCode.ERR_NoCorrespondingArgument, "CLSCompliant").WithArguments("isCompliant", "System.CLSCompliantAttribute.CLSCompliantAttribute(bool)").WithLocation(7, 34)); var localDecl = tree.FindNodeOrTokenByKind(SyntaxKind.LocalFunctionStatement); var model = comp.GetSemanticModel(tree); var localSymbol = Assert.IsType<LocalFunctionSymbol>(model.GetDeclaredSymbol(localDecl.AsNode()).GetSymbol()); var param = localSymbol.Parameters[0]; var attrs = param.GetAttributes(); Assert.True(attrs[0].AttributeClass.IsErrorType()); Assert.True(attrs[1].AttributeClass.IsErrorType()); param = localSymbol.Parameters[1]; attrs = param.GetAttributes(); Assert.Equal(comp.GlobalNamespace .GetMember<NamespaceSymbol>("System") .GetMember<NamedTypeSymbol>("CLSCompliantAttribute"), attrs[0].AttributeClass); comp.DeclarationDiagnostics.Verify(); } [Fact] public void LocalFunctionDisallowedAttributes() { var source = @" using System.Runtime.CompilerServices; namespace System.Runtime.CompilerServices { public class IsReadOnlyAttribute : System.Attribute { } public class IsUnmanagedAttribute : System.Attribute { } public class IsByRefLikeAttribute : System.Attribute { } public class NullableContextAttribute : System.Attribute { public NullableContextAttribute(byte b) { } } } class C { void M() { local1(); [IsReadOnly] // 1 [IsUnmanaged] // 2 [IsByRefLike] // 3 [Extension] // 4 [NullableContext(0)] // 5 void local1() { } } } "; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics( // (18,10): error CS8335: Do not use 'System.Runtime.CompilerServices.IsReadOnlyAttribute'. This is reserved for compiler usage. // [IsReadOnly] // 1 Diagnostic(ErrorCode.ERR_ExplicitReservedAttr, "IsReadOnly").WithArguments("System.Runtime.CompilerServices.IsReadOnlyAttribute").WithLocation(18, 10), // (19,10): error CS8335: Do not use 'System.Runtime.CompilerServices.IsUnmanagedAttribute'. This is reserved for compiler usage. // [IsUnmanaged] // 2 Diagnostic(ErrorCode.ERR_ExplicitReservedAttr, "IsUnmanaged").WithArguments("System.Runtime.CompilerServices.IsUnmanagedAttribute").WithLocation(19, 10), // (20,10): error CS8335: Do not use 'System.Runtime.CompilerServices.IsByRefLikeAttribute'. This is reserved for compiler usage. // [IsByRefLike] // 3 Diagnostic(ErrorCode.ERR_ExplicitReservedAttr, "IsByRefLike").WithArguments("System.Runtime.CompilerServices.IsByRefLikeAttribute").WithLocation(20, 10), // (21,10): error CS1112: Do not use 'System.Runtime.CompilerServices.ExtensionAttribute'. Use the 'this' keyword instead. // [Extension] // 4 Diagnostic(ErrorCode.ERR_ExplicitExtension, "Extension").WithLocation(21, 10), // (22,10): error CS8335: Do not use 'System.Runtime.CompilerServices.NullableContextAttribute'. This is reserved for compiler usage. // [NullableContext(0)] // 5 Diagnostic(ErrorCode.ERR_ExplicitReservedAttr, "NullableContext(0)").WithArguments("System.Runtime.CompilerServices.NullableContextAttribute").WithLocation(22, 10)); } [Fact] public void LocalFunctionDisallowedSecurityAttributes() { var source = @" using System.Security; class C { void M() { local1(); [SecurityCritical] // 1 [SecuritySafeCriticalAttribute] // 2 async void local1() // 3 { } } } "; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics( // (10,10): error CS4030: Security attribute 'SecurityCritical' cannot be applied to an Async method. // [SecurityCritical] // 1 Diagnostic(ErrorCode.ERR_SecurityCriticalOrSecuritySafeCriticalOnAsync, "SecurityCritical").WithArguments("SecurityCritical").WithLocation(10, 10), // (11,10): error CS4030: Security attribute 'SecuritySafeCriticalAttribute' cannot be applied to an Async method. // [SecuritySafeCriticalAttribute] // 2 Diagnostic(ErrorCode.ERR_SecurityCriticalOrSecuritySafeCriticalOnAsync, "SecuritySafeCriticalAttribute").WithArguments("SecuritySafeCriticalAttribute").WithLocation(11, 10) ); } [Fact] public void TypeParameterBindingScope() { var src = @" class C { public void M() { { int T = 0; // Should not have error int Local<T>() => 0; // Should conflict with above Local<int>(); T++; } { int T<T>() => 0; T<int>(); } { int Local<T, T>() => 0; Local<int, int>(); } } public void M2<T>() { { int Local<T>() => 0; Local<int>(); } { int Local1<V>() { int Local2<V>() => 0; return Local2<int>(); } Local1<int>(); } { int T() => 0; T(); } { int Local1<V>() { int V() => 0; return V(); } Local1<int>(); } { int Local1<V>() { int Local2<U>() { // Conflicts with method type parameter int T() => 0; return T(); } return Local2<int>(); } Local1<int>(); } { int Local1<V>() { int Local2<U>() { // Shadows M.2<T> int Local3<T>() => 0; return Local3<int>(); } return Local2<int>(); } Local1<int>(); } } public void V<V>() { } } "; var comp = CreateCompilation(src, parseOptions: TestOptions.Regular7_3); comp.VerifyDiagnostics( // (9,23): error CS0136: A local or parameter named 'T' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter // int Local<T>() => 0; // Should conflict with above Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "T").WithArguments("T").WithLocation(9, 23), // (14,19): error CS0136: A local or parameter named 'T' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter // int T<T>() => 0; Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "T").WithArguments("T").WithLocation(14, 19), // (18,26): error CS0692: Duplicate type parameter 'T' // int Local<T, T>() => 0; Diagnostic(ErrorCode.ERR_DuplicateTypeParameter, "T").WithArguments("T").WithLocation(18, 26), // (25,23): warning CS8387: Type parameter 'T' has the same name as the type parameter from outer method 'C.M2<T>()' // int Local<T>() => 0; Diagnostic(ErrorCode.WRN_TypeParameterSameAsOuterMethodTypeParameter, "T").WithArguments("T", "C.M2<T>()").WithLocation(25, 23), // (31,28): warning CS8387: Type parameter 'V' has the same name as the type parameter from outer method 'Local1<V>()' // int Local2<V>() => 0; Diagnostic(ErrorCode.WRN_TypeParameterSameAsOuterMethodTypeParameter, "V").WithArguments("V", "Local1<V>()").WithLocation(31, 28), // (37,17): error CS0412: 'T': a parameter, local variable, or local function cannot have the same name as a method type parameter // int T() => 0; Diagnostic(ErrorCode.ERR_LocalSameNameAsTypeParam, "T").WithArguments("T").WithLocation(37, 17), // (43,21): error CS0412: 'V': a parameter, local variable, or local function cannot have the same name as a method type parameter // int V() => 0; Diagnostic(ErrorCode.ERR_LocalSameNameAsTypeParam, "V").WithArguments("V").WithLocation(43, 21), // (54,25): error CS0412: 'T': a parameter, local variable, or local function cannot have the same name as a method type parameter // int T() => 0; Diagnostic(ErrorCode.ERR_LocalSameNameAsTypeParam, "T").WithArguments("T").WithLocation(54, 25), // (67,32): warning CS8387: Type parameter 'T' has the same name as the type parameter from outer method 'C.M2<T>()' // int Local3<T>() => 0; Diagnostic(ErrorCode.WRN_TypeParameterSameAsOuterMethodTypeParameter, "T").WithArguments("T", "C.M2<T>()").WithLocation(67, 32)); comp = CreateCompilation(src, parseOptions: TestOptions.Regular8); comp.VerifyDiagnostics( // (18,26): error CS0692: Duplicate type parameter 'T' // int Local<T, T>() => 0; Diagnostic(ErrorCode.ERR_DuplicateTypeParameter, "T").WithArguments("T").WithLocation(18, 26), // (25,23): warning CS8387: Type parameter 'T' has the same name as the type parameter from outer method 'C.M2<T>()' // int Local<T>() => 0; Diagnostic(ErrorCode.WRN_TypeParameterSameAsOuterMethodTypeParameter, "T").WithArguments("T", "C.M2<T>()").WithLocation(25, 23), // (31,28): warning CS8387: Type parameter 'V' has the same name as the type parameter from outer method 'Local1<V>()' // int Local2<V>() => 0; Diagnostic(ErrorCode.WRN_TypeParameterSameAsOuterMethodTypeParameter, "V").WithArguments("V", "Local1<V>()").WithLocation(31, 28), // (37,17): error CS0412: 'T': a parameter, local variable, or local function cannot have the same name as a method type parameter // int T() => 0; Diagnostic(ErrorCode.ERR_LocalSameNameAsTypeParam, "T").WithArguments("T").WithLocation(37, 17), // (43,21): error CS0412: 'V': a parameter, local variable, or local function cannot have the same name as a method type parameter // int V() => 0; Diagnostic(ErrorCode.ERR_LocalSameNameAsTypeParam, "V").WithArguments("V").WithLocation(43, 21), // (67,32): warning CS8387: Type parameter 'T' has the same name as the type parameter from outer method 'C.M2<T>()' // int Local3<T>() => 0; Diagnostic(ErrorCode.WRN_TypeParameterSameAsOuterMethodTypeParameter, "T").WithArguments("T", "C.M2<T>()").WithLocation(67, 32)); } [Fact] public void LocalFuncAndTypeParameterOnType() { var comp = CreateCompilation(@" class C2<T> { public void M() { { int Local1() { int Local2<T>() => 0; return Local2<int>(); } Local1(); } { int Local1() { int Local2() { // Shadows type parameter int T() => 0; // Type parameter resolves in type only context T t = default(T); // Ambiguous context chooses local T.M(); // Call chooses local return T(); } return Local2(); } Local1(); } } }"); comp.VerifyDiagnostics( // (9,28): warning CS0693: Type parameter 'T' has the same name as the type parameter from outer type 'C2<T>' // int Local2<T>() => 0; Diagnostic(ErrorCode.WRN_TypeParameterSameAsOuterTypeParameter, "T").WithArguments("T", "C2<T>").WithLocation(9, 28), // (26,21): error CS0119: 'T()' is a method, which is not valid in the given context // T.M(); Diagnostic(ErrorCode.ERR_BadSKunknown, "T").WithArguments("T()", "method").WithLocation(26, 21), // (23,23): warning CS0219: The variable 't' is assigned but its value is never used // T t = default(T); Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "t").WithArguments("t").WithLocation(23, 23)); } [Fact] public void RefArgsInIteratorLocalFuncs() { var src = @" using System; using System.Collections.Generic; class C { public void M1() { IEnumerable<int> Local(ref int a) { yield break; } int x = 0; Local(ref x); } public void M2() { Action a = () => { IEnumerable<int> Local(ref int x) { yield break; } int y = 0; Local(ref y); return; }; a(); } public Func<int> M3() => (() => { IEnumerable<int> Local(ref int a) { yield break; } int x = 0; Local(ref x); return 0; }); public IEnumerable<int> M4(ref int a) { yield return new Func<int>(() => { IEnumerable<int> Local(ref int b) { yield break; } int x = 0; Local(ref x); return 0; })(); } }"; VerifyDiagnostics(src, // (8,40): error CS1623: Iterators cannot have ref, in or out parameters // IEnumerable<int> Local(ref int a) { yield break; } Diagnostic(ErrorCode.ERR_BadIteratorArgType, "a").WithLocation(8, 40), // (17,44): error CS1623: Iterators cannot have ref, in or out parameters // IEnumerable<int> Local(ref int x) { yield break; } Diagnostic(ErrorCode.ERR_BadIteratorArgType, "x").WithLocation(17, 44), // (27,40): error CS1623: Iterators cannot have ref, in or out parameters // IEnumerable<int> Local(ref int a) { yield break; } Diagnostic(ErrorCode.ERR_BadIteratorArgType, "a").WithLocation(27, 40), // (33,40): error CS1623: Iterators cannot have ref, in or out parameters // public IEnumerable<int> M4(ref int a) Diagnostic(ErrorCode.ERR_BadIteratorArgType, "a").WithLocation(33, 40), // (37,48): error CS1623: Iterators cannot have ref, in or out parameters // IEnumerable<int> Local(ref int b) { yield break; } Diagnostic(ErrorCode.ERR_BadIteratorArgType, "b").WithLocation(37, 48)); } [Fact] public void UnsafeArgsInIteratorLocalFuncs() { var src = @" using System; using System.Collections.Generic; class C { public unsafe void M1() { IEnumerable<int> Local(int* a) { yield break; } int x = 0; Local(&x); } public unsafe void M2() { Action a = () => { IEnumerable<int> Local(int* x) { yield break; } int y = 0; Local(&y); return; }; a(); } public unsafe Func<int> M3() => (() => { IEnumerable<int> Local(int* a) { yield break; } int x = 0; Local(&x); return 0; }); public unsafe IEnumerable<int> M4(int* a) { yield return new Func<int>(() => { IEnumerable<int> Local(int* b) { yield break; } int x = 0; Local(&x); return 0; })(); } }"; var comp = CreateCompilation(src, options: TestOptions.UnsafeDebugDll, parseOptions: TestOptions.Regular12.WithFeature(Feature.RunNullableAnalysis, "never")); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); LocalFunctionStatementSyntax declaration = tree.GetRoot().DescendantNodes().OfType<LocalFunctionStatementSyntax>().First(); var local = model.GetDeclaredSymbol(declaration).GetSymbol<MethodSymbol>(); Assert.True(local.IsIterator); Assert.True(local.GetPublicSymbol().IsIterator); Assert.Equal("System.Int32", local.IteratorElementTypeWithAnnotations.ToTestDisplayString()); model.GetOperation(declaration.Body); Assert.True(local.IsIterator); Assert.True(local.GetPublicSymbol().IsIterator); Assert.Equal("System.Int32", local.IteratorElementTypeWithAnnotations.ToTestDisplayString()); comp.VerifyDiagnostics( // (8,37): error CS1637: Iterators cannot have pointer type parameters // IEnumerable<int> Local(int* a) { yield break; } Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "a").WithLocation(8, 37), // (17,41): error CS1637: Iterators cannot have pointer type parameters // IEnumerable<int> Local(int* x) { yield break; } Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "x").WithLocation(17, 41), // (27,37): error CS1637: Iterators cannot have pointer type parameters // IEnumerable<int> Local(int* a) { yield break; } Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "a").WithLocation(27, 37), // (37,40): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater. // IEnumerable<int> Local(int* b) { yield break; } Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "int*").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(37, 40), // (39,23): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater. // Local(&x); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "&x").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(39, 23), // (39,17): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater. // Local(&x); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "Local(&x)").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(39, 17), // (33,44): error CS1637: Iterators cannot have pointer type parameters // public unsafe IEnumerable<int> M4(int* a) Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "a").WithLocation(33, 44), // (33,36): error CS9202: Feature 'ref and unsafe in async and iterator methods' is not available in C# 12.0. Please use language version 13.0 or greater. // public unsafe IEnumerable<int> M4(int* a) Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion12, "M4").WithArguments("ref and unsafe in async and iterator methods", "13.0").WithLocation(33, 36), // (37,45): error CS1637: Iterators cannot have pointer type parameters // IEnumerable<int> Local(int* b) { yield break; } Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "b").WithLocation(37, 45)); var expectedDiagnostics = new[] { // (8,37): error CS1637: Iterators cannot have pointer type parameters // IEnumerable<int> Local(int* a) { yield break; } Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "a").WithLocation(8, 37), // (17,41): error CS1637: Iterators cannot have pointer type parameters // IEnumerable<int> Local(int* x) { yield break; } Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "x").WithLocation(17, 41), // (27,37): error CS1637: Iterators cannot have pointer type parameters // IEnumerable<int> Local(int* a) { yield break; } Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "a").WithLocation(27, 37), // (33,44): error CS1637: Iterators cannot have pointer type parameters // public unsafe IEnumerable<int> M4(int* a) Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "a").WithLocation(33, 44), // (37,40): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context // IEnumerable<int> Local(int* b) { yield break; } Diagnostic(ErrorCode.ERR_UnsafeNeeded, "int*").WithLocation(37, 40), // (37,45): error CS1637: Iterators cannot have pointer type parameters // IEnumerable<int> Local(int* b) { yield break; } Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "b").WithLocation(37, 45), // (39,17): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context // Local(&x); Diagnostic(ErrorCode.ERR_UnsafeNeeded, "Local(&x)").WithLocation(39, 17), // (39,23): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context // Local(&x); Diagnostic(ErrorCode.ERR_UnsafeNeeded, "&x").WithLocation(39, 23) }; CreateCompilation(src, options: TestOptions.UnsafeDebugDll, parseOptions: TestOptions.Regular13.WithFeature(Feature.RunNullableAnalysis, "never")).VerifyDiagnostics(expectedDiagnostics); var expectedPreviewDiagnostics = new[] { // (8,37): error CS1637: Iterators cannot have pointer type parameters // IEnumerable<int> Local(int* a) { yield break; } Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "a").WithLocation(8, 37), // (17,41): error CS1637: Iterators cannot have pointer type parameters // IEnumerable<int> Local(int* x) { yield break; } Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "x").WithLocation(17, 41), // (27,37): error CS1637: Iterators cannot have pointer type parameters // IEnumerable<int> Local(int* a) { yield break; } Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "a").WithLocation(27, 37), // (33,44): error CS1637: Iterators cannot have pointer type parameters // public unsafe IEnumerable<int> M4(int* a) Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "a").WithLocation(33, 44), // (37,45): error CS1637: Iterators cannot have pointer type parameters // IEnumerable<int> Local(int* b) { yield break; } Diagnostic(ErrorCode.ERR_UnsafeIteratorArgType, "b").WithLocation(37, 45), // (39,17): error CS9363: 'Local(int*)' must be used in an unsafe context because it has pointers in its signature // Local(&x); Diagnostic(ErrorCode.ERR_UnsafeMemberOperationCompat, "Local(&x)").WithArguments("Local(int*)").WithLocation(39, 17) }; CreateCompilation(src, options: TestOptions.UnsafeDebugDll, parseOptions: TestOptions.RegularPreview.WithFeature(Feature.RunNullableAnalysis, "never")).VerifyDiagnostics(expectedPreviewDiagnostics); CreateCompilation(src, options: TestOptions.UnsafeDebugDll, parseOptions: TestOptions.RegularNext.WithFeature(Feature.RunNullableAnalysis, "never")).VerifyDiagnostics(expectedPreviewDiagnostics); } [Fact] [WorkItem(13193, "https://github.com/dotnet/roslyn/issues/13193")] public void LocalFunctionConflictingName() { var comp = CreateCompilation(@" class C { public void M<TLocal>() { void TLocal() { } TLocal(); } public void M(int Local) { void Local() { } Local(); } public void M() { int local = 0; void local() { } local(); } }"); comp.VerifyDiagnostics( // (6,14): error CS0412: 'TLocal': a parameter, local variable, or local function cannot have the same name as a method type parameter // void TLocal() { } Diagnostic(ErrorCode.ERR_LocalSameNameAsTypeParam, "TLocal").WithArguments("TLocal").WithLocation(6, 14), // (11,14): error CS0136: A local or parameter named 'Local' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter // void Local() { } Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "Local").WithArguments("Local").WithLocation(11, 14), // (18,14): error CS0128: A local variable or function named 'local' is already defined in this scope // void local() { } Diagnostic(ErrorCode.ERR_LocalDuplicate, "local").WithArguments("local").WithLocation(18, 14), // (16,13): warning CS0219: The variable 'local' is assigned but its value is never used // int local = 0; Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "local").WithArguments("local").WithLocation(16, 13)); } [Fact] public void ForgotSemicolonLocalFunctionsMistake() { var src = """ class C { public void M1() { // forget closing brace public void BadLocal1() { this.BadLocal2(); } public void BadLocal2() { } public int P => 0; } """; VerifyDiagnostics(src, // (5,6): error CS1513: } expected // { Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(4, 6)); } [Fact] public void VarLocalFunction() { var src = @" class C { void M() { var local() => 0; int x = local(); } }"; VerifyDiagnostics(src, // (6,9): error CS0825: The contextual keyword 'var' may only appear within a local variable declaration or in script code // var local() => 0; Diagnostic(ErrorCode.ERR_TypeVarNotFound, "var").WithLocation(6, 9)); } [Fact] public void VarLocalFunction2() { var comp = CreateCompilation(@" class C { private class @var { } void M() { var local() => new var(); var x = local(); } }", parseOptions: DefaultParseOptions); comp.VerifyDiagnostics(); } [Fact] [CompilerTrait(CompilerFeature.Params)] public void BadParams() { var source = @" using System; class Program { static void Main(string[] args) { void Params(params int x) { Console.WriteLine(x); } Params(2); } } "; VerifyDiagnostics(source, // (8,21): error CS0225: The params parameter must have a valid collection type // void Params(params int x) Diagnostic(ErrorCode.ERR_ParamsMustBeCollection, "params").WithLocation(8, 21) ); } [Fact] public void ParamsArray_Symbol_MultipleParamsArrays() { var source = """ int Method1(params int[] xs, params int[] ys, int[] zs) => xs.Length + ys.Length + zs.Length; int Method2(params int[] xs, int[] ys, params int[] zs) => xs.Length + ys.Length + zs.Length; """; var comp = CreateCompilation(source); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var exprs = tree.GetRoot().DescendantNodes().OfType<LocalFunctionStatementSyntax>().ToImmutableArray(); var methods = exprs.SelectAsArray(e => (IMethodSymbol)model.GetDeclaredSymbol(e)); Assert.Equal(2, methods.Length); // Method1 Assert.Equal(3, methods[0].Parameters.Length); Assert.True(methods[0].Parameters[0].IsParams); Assert.True(methods[0].Parameters[1].IsParams); Assert.False(methods[0].Parameters[2].IsParams); // Method2 Assert.Equal(3, methods[1].Parameters.Length); Assert.True(methods[1].Parameters[0].IsParams); Assert.False(methods[1].Parameters[1].IsParams); Assert.True(methods[1].Parameters[2].IsParams); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/79752")] public void ParamsArray_Attribute() { var source = """ using System; using System.Linq; using System.Reflection; int fun(params int[] xs) => xs.Length; Console.WriteLine(fun(4, 5, 6)); Console.WriteLine(string.Join("\n", typeof(Program) .GetMethod("<<Main>$>g__fun|0_0", BindingFlags.Static | BindingFlags.NonPublic) .GetParameters() .Single() .CustomAttributes .Select(a => a.AttributeType))); """; CompileAndVerify(source, options: TestOptions.DebugExe.WithMetadataImportOptions(MetadataImportOptions.All), symbolValidator: validate, expectedOutput: """ 3 System.ParamArrayAttribute """) .VerifyDiagnostics(); static void validate(ModuleSymbol module) { var lambda = module.GlobalNamespace.GetMember<MethodSymbol>("Program.<<Main>$>g__fun|0_0"); var parameter = lambda.GetParameters().Single(); AssertEx.Equal("params System.Int32[] xs", parameter.ToTestDisplayString()); Assert.True(parameter.IsParams); Assert.True(parameter.IsParamsArray); Assert.False(parameter.IsParamsCollection); Assert.DoesNotContain("ParamArrayAttribute", module.TypeNames); } } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/79752")] public void ParamsArray_Attribute_ExtensionMethod() { var source = """ using System; using System.Linq; using System.Reflection; object.M(); static class E { extension(object) { public static void M() { int fun(params int[] xs) => xs.Length; Console.WriteLine(fun(4, 5, 6)); Console.WriteLine(string.Join("\n", typeof(E) .GetMethod("<M>g__fun|1_0", BindingFlags.Static | BindingFlags.NonPublic) .GetParameters() .Single() .CustomAttributes .Select(a => a.AttributeType))); } } } """; CompileAndVerify(source, options: TestOptions.DebugExe.WithMetadataImportOptions(MetadataImportOptions.All), symbolValidator: validate, expectedOutput: """ 3 System.ParamArrayAttribute """) .VerifyDiagnostics(); static void validate(ModuleSymbol module) { var lambda = module.GlobalNamespace.GetMember<MethodSymbol>("E.<M>g__fun|1_0"); var parameter = lambda.GetParameters().Single(); AssertEx.Equal("params System.Int32[] xs", parameter.ToTestDisplayString()); Assert.True(parameter.IsParams); Assert.True(parameter.IsParamsArray); Assert.False(parameter.IsParamsCollection); Assert.DoesNotContain("ParamArrayAttribute", module.TypeNames); } } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/79752")] public void ParamsArray_Attribute_Missing() { var source = """ int fun(params int[] xs) => xs.Length; fun(4, 5, 6); """; var comp = CreateCompilation(source); comp.MakeTypeMissing(WellKnownType.System_ParamArrayAttribute); comp.VerifyDiagnostics( // (1,9): error CS0656: Missing compiler required member 'System.ParamArrayAttribute..ctor' // int fun(params int[] xs) => xs.Length; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "params int[] xs").WithArguments("System.ParamArrayAttribute", ".ctor").WithLocation(1, 9)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/79752")] public void ParamsArray_Attribute_Missing_ExtensionMethod() { var source = """ static class E { extension(object) { public static void M() { int fun(params int[] xs) => xs.Length; fun(4, 5, 6); } } } """; var comp = CreateCompilation(source); comp.MakeTypeMissing(WellKnownType.System_ParamArrayAttribute); comp.VerifyDiagnostics( // (7,21): error CS0656: Missing compiler required member 'System.ParamArrayAttribute..ctor' // int fun(params int[] xs) => xs.Length; Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "params int[] xs").WithArguments("System.ParamArrayAttribute", ".ctor").WithLocation(7, 21)); } [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/79752")] public void ParamsCollection_Attribute(bool includeAttribute) { var source = """ using System; using System.Collections.Generic; using System.Linq; using System.Reflection; int fun(params IList<int> xs) => xs.Count; Console.WriteLine(fun(4, 5, 6)); Console.WriteLine(string.Join("\n", typeof(Program) .GetMethod("<<Main>$>g__fun|0_0", BindingFlags.Static | BindingFlags.NonPublic) .GetParameters() .Single() .CustomAttributes .Select(a => a.AttributeType))); """; var r = CreateCompilation(includeAttribute ? TestSources.ParamsCollectionAttribute : "").VerifyDiagnostics().ToMetadataReference(); CompileAndVerify(source, [r], options: TestOptions.DebugExe.WithMetadataImportOptions(MetadataImportOptions.All), symbolValidator: validate, expectedOutput: """ 3 System.Runtime.CompilerServices.ParamCollectionAttribute """) .VerifyDiagnostics(); void validate(ModuleSymbol module) { var lambda = module.GlobalNamespace.GetMember<MethodSymbol>("Program.<<Main>$>g__fun|0_0"); var parameter = lambda.GetParameters().Single(); AssertEx.Equal("params System.Collections.Generic.IList<System.Int32> xs", parameter.ToTestDisplayString()); Assert.True(parameter.IsParams); Assert.False(parameter.IsParamsArray); Assert.True(parameter.IsParamsCollection); Assert.Equal(includeAttribute, !module.TypeNames.Contains("ParamCollectionAttribute")); } } [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/79752")] public void ParamsCollection_Attribute_ExtensionMethod(bool includeAttribute) { var source = """ using System; using System.Collections.Generic; using System.Linq; using System.Reflection; object.M(); static class E { extension(object) { public static void M() { int fun(params IList<int> xs) => xs.Count; Console.WriteLine(fun(4, 5, 6)); Console.WriteLine(string.Join("\n", typeof(E) .GetMethod("<M>g__fun|1_0", BindingFlags.Static | BindingFlags.NonPublic) .GetParameters() .Single() .CustomAttributes .Select(a => a.AttributeType))); } } } """; var r = CreateCompilation(includeAttribute ? TestSources.ParamsCollectionAttribute : "").VerifyDiagnostics().ToMetadataReference(); CompileAndVerify(source, [r], options: TestOptions.DebugExe.WithMetadataImportOptions(MetadataImportOptions.All), symbolValidator: validate, expectedOutput: """ 3 System.Runtime.CompilerServices.ParamCollectionAttribute """) .VerifyDiagnostics(); void validate(ModuleSymbol module) { var lambda = module.GlobalNamespace.GetMember<MethodSymbol>("E.<M>g__fun|1_0"); var parameter = lambda.GetParameters().Single(); AssertEx.Equal("params System.Collections.Generic.IList<System.Int32> xs", parameter.ToTestDisplayString()); Assert.True(parameter.IsParams); Assert.False(parameter.IsParamsArray); Assert.True(parameter.IsParamsCollection); Assert.Equal(includeAttribute, !module.TypeNames.Contains("ParamCollectionAttribute")); } } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/79752")] public void ParamsCollection_Attribute_Missing() { var source = """ using System.Collections.Generic; class C { void M() { int func(params IList<int> xs) => xs.Count; func(4, 5, 6); } } """; CreateCompilation(source, options: TestOptions.ReleaseModule).VerifyDiagnostics( // (6,18): error CS0518: Predefined type 'System.Runtime.CompilerServices.ParamCollectionAttribute' is not defined or imported // int func(params IList<int> xs) => xs.Count; Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "params IList<int> xs").WithArguments("System.Runtime.CompilerServices.ParamCollectionAttribute").WithLocation(6, 18)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/79752")] public void ParamsCollection_Attribute_Missing_ExtensionMethod() { var source = """ using System.Collections.Generic; static class E { extension(object) { public static void M() { int func(params IList<int> xs) => xs.Count; func(4, 5, 6); } } } """; CreateCompilation([source, ExtensionMarkerAttributeDefinition], options: TestOptions.ReleaseModule).VerifyDiagnostics( // (8,22): error CS0518: Predefined type 'System.Runtime.CompilerServices.ParamCollectionAttribute' is not defined or imported // int func(params IList<int> xs) => xs.Count; Diagnostic(ErrorCode.ERR_PredefinedTypeNotFound, "params IList<int> xs").WithArguments("System.Runtime.CompilerServices.ParamCollectionAttribute").WithLocation(8, 22)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/79752")] public void ParamsCollection_Attribute_Speculative() { // Compile without a need for the attribute. var source1 = """ class C { void M() { } } """; var comp = CreateCompilation(source1); var tree1 = comp.SyntaxTrees.Single(); var model1 = comp.GetSemanticModel(tree1); // Speculatively bind a lambda that needs the attribute. var source2 = """ class C { void M() { int func(params System.Collections.Generic.IList<int> xs) => xs.Count; } } """; var tree2 = CSharpSyntaxTree.ParseText(source2); var method1 = tree1.GetRoot().DescendantNodes().OfType<MethodDeclarationSyntax>().Single(); var method2 = tree2.GetRoot().DescendantNodes().OfType<MethodDeclarationSyntax>().Single(); Assert.True(model1.TryGetSpeculativeSemanticModelForMethodBody(method1.Body.SpanStart, method2, out var model2)); var func = tree2.GetRoot().DescendantNodes().OfType<LocalFunctionStatementSyntax>().Single(); var symbol = model2.GetDeclaredSymbol(func); Assert.NotNull(symbol); Assert.True(symbol.Parameters.Single().IsParamsCollection); // The original compilation does not synthesize the attribute when emitted. Assert.Equal(TypeKind.Error, comp.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_ParamCollectionAttribute).TypeKind); CompileAndVerify(comp, symbolValidator: static (module) => { Assert.DoesNotContain("ParamCollectionAttribute", module.TypeNames); }) .VerifyDiagnostics(); } [Fact] public void BadRefWithDefault() { var source = @" class Program { static void Main(string[] args) { void RefOut(ref int x = 2) { x++; } int y = 2; RefOut(ref y); } } "; VerifyDiagnostics(source, // (6,21): error CS1741: A ref or out parameter cannot have a default value // void RefOut(ref int x = 2) Diagnostic(ErrorCode.ERR_RefOutDefaultValue, "ref").WithLocation(6, 21) ); } [Fact] public void BadDefaultValueType() { var source = @" using System; class Program { static void Main(string[] args) { void NamedOptional(string x = 2) { Console.WriteLine(x); } NamedOptional(""2""); } } "; VerifyDiagnostics(source, // (8,35): error CS1750: A value of type 'int' cannot be used as a default parameter because there are no standard conversions to type 'string' // void NamedOptional(string x = 2) Diagnostic(ErrorCode.ERR_NoConversionForDefaultParam, "x").WithArguments("int", "string").WithLocation(8, 35) ); } [Fact] public void CallerMemberName() { var comp = CreateCompilationWithMscorlib46(@" using System; using System.Runtime.CompilerServices; class C { static void Main() { void CallerMemberName([CallerMemberName] string s = null) { Console.Write(s); } void LocalFuncName() { CallerMemberName(); } LocalFuncName(); Console.Write(' '); CallerMemberName(); } }", parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics(); } [Fact] public void BadCallerMemberName() { var source = @" using System; using System.Runtime.CompilerServices; class Program { static void Main(string[] args) { void CallerMemberName([CallerMemberName] int s = 2) // 1 { Console.WriteLine(s); } CallerMemberName(); // 2 } } "; CreateCompilationWithMscorlib461AndCSharp(source, parseOptions: TestOptions.Regular9).VerifyDiagnostics( // (9,32): error CS4019: CallerMemberNameAttribute cannot be applied because there are no standard conversions from type 'string' to type 'int' // void CallerMemberName([CallerMemberName] int s = 2) // 1 Diagnostic(ErrorCode.ERR_NoConversionForCallerMemberNameParam, "CallerMemberName").WithArguments("string", "int").WithLocation(9, 32), // (13,9): error CS0029: Cannot implicitly convert type 'string' to 'int' // CallerMemberName(); // 2 Diagnostic(ErrorCode.ERR_NoImplicitConv, "CallerMemberName()").WithArguments("string", "int").WithLocation(13, 9)); } [WorkItem(10708, "https://github.com/dotnet/roslyn/issues/10708")] [CompilerTrait(CompilerFeature.Dynamic, CompilerFeature.Params)] [Fact] public void DynamicArgumentToParams() { var src = @" using System; class C { static void Main() { void L1(int x = 0, params int[] ys) => Console.Write(x); dynamic val = 2; L1(val, val); L1(ys: val, x: val); L1(ys: val); } }"; VerifyDiagnostics(src, // (10,17): error CS8106: Cannot pass argument with dynamic type to params parameter 'ys' of local function 'L1'. // L1(val, val); Diagnostic(ErrorCode.ERR_DynamicLocalFunctionParamsParameter, "val").WithArguments("ys", "L1").WithLocation(10, 17), // (11,16): error CS8106: Cannot pass argument with dynamic type to params parameter 'ys' of local function 'L1'. // L1(ys: val, x: val); Diagnostic(ErrorCode.ERR_DynamicLocalFunctionParamsParameter, "val").WithArguments("ys", "L1").WithLocation(11, 16), // (12,16): error CS8106: Cannot pass argument with dynamic type to params parameter 'ys' of local function 'L1'. // L1(ys: val); Diagnostic(ErrorCode.ERR_DynamicLocalFunctionParamsParameter, "val").WithArguments("ys", "L1").WithLocation(12, 16)); } [Fact] [CompilerTrait(CompilerFeature.Dynamic)] public void DynamicArgOverload() { var src = @" using System; class C { static void Main() { void Overload(int i) => Console.Write(i); void Overload(string s) => Console.Write(s); dynamic val = 2; Overload(val); } }"; VerifyDiagnostics(src, // (8,14): error CS0128: A local variable named 'Overload' is already defined in this scope // void Overload(string s) => Console.Write(s); Diagnostic(ErrorCode.ERR_LocalDuplicate, "Overload").WithArguments("Overload").WithLocation(8, 14), // (8,14): warning CS8321: The local function 'Overload' is declared but never used // void Overload(string s) => Console.Write(s); Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "Overload").WithArguments("Overload").WithLocation(8, 14)); } [Fact] [CompilerTrait(CompilerFeature.Dynamic)] public void DynamicArgWrongArity() { var src = @" using System; class C { static void Main() { void Local(int i) => Console.Write(i); dynamic val = 2; Local(val, val); } }"; VerifyDiagnostics(src, // (10,9): error CS1501: No overload for method 'Local' takes 2 arguments // Local(val, val); Diagnostic(ErrorCode.ERR_BadArgCount, "Local").WithArguments("Local", "2").WithLocation(10, 9)); } [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/71399")] [CompilerTrait(CompilerFeature.Dynamic)] public void DynamicArgWithRefKind_01() { var src = @" class C { static void Main() { dynamic i = 1; local1(i); local1(ref i); local2(i); local3(i); void local1(ref int x){ x++; } void local2(ref object x){ } void local3(ref dynamic x){ x++; } } }"; VerifyDiagnostics(src, // (8,16): error CS1620: Argument 1 must be passed with the 'ref' keyword // local1(i); Diagnostic(ErrorCode.ERR_BadArgRef, "i").WithArguments("1", "ref").WithLocation(8, 16), // (9,20): error CS1503: Argument 1: cannot convert from 'ref dynamic' to 'ref int' // local1(ref i); Diagnostic(ErrorCode.ERR_BadArgType, "i").WithArguments("1", "ref dynamic", "ref int").WithLocation(9, 20), // (11,16): error CS1620: Argument 1 must be passed with the 'ref' keyword // local2(i); Diagnostic(ErrorCode.ERR_BadArgRef, "i").WithArguments("1", "ref").WithLocation(11, 16), // (12,16): error CS1620: Argument 1 must be passed with the 'ref' keyword // local3(i); Diagnostic(ErrorCode.ERR_BadArgRef, "i").WithArguments("1", "ref").WithLocation(12, 16) ); } [Fact] [WorkItem("https://github.com/dotnet/roslyn/issues/71399")] [CompilerTrait(CompilerFeature.Dynamic)] public void DynamicArgWithRefKind_02() { var src = @" class C { static void Main() { dynamic i = 1; local2(ref i); System.Console.Write(i); local3(ref i); System.Console.Write(i); void local2(ref object x){ ref dynamic y = ref x; y++; } void local3(ref dynamic x){ x++; } } }"; var comp = CreateCompilation(src, targetFramework: TargetFramework.StandardAndCSharp, options: TestOptions.ReleaseExe); CompileAndVerify(comp, expectedOutput: "23").VerifyDiagnostics(); } [WorkItem(3923, "https://github.com/dotnet/roslyn/issues/3923")] [Fact] public void ExpressionTreeLocalFunctionUsage_01() { var source = @" using System; using System.Linq.Expressions; class Program { static void Main() { T Id<T>(T x) { return x; } Expression<Func<T>> Local<T>(Expression<Func<T>> f) { return f; } Console.Write(Local(() => Id(2))); Console.Write(Local<Func<int, int>>(() => Id)); Console.Write(Local(() => new Func<int, int>(Id))); Console.Write(Local(() => nameof(Id))); } } "; VerifyDiagnostics(source, // (16,35): error CS8096: An expression tree may not contain a reference to a local function // Console.Write(Local(() => Id(2))); Diagnostic(ErrorCode.ERR_ExpressionTreeContainsLocalFunction, "Id(2)").WithLocation(16, 35), // (17,51): error CS8096: An expression tree may not contain a reference to a local function // Console.Write(Local<Func<int, int>>(() => Id)); Diagnostic(ErrorCode.ERR_ExpressionTreeContainsLocalFunction, "Id").WithLocation(17, 51), // (18,35): error CS8096: An expression tree may not contain a reference to a local function // Console.Write(Local(() => new Func<int, int>(Id))); Diagnostic(ErrorCode.ERR_ExpressionTreeContainsLocalFunction, "Id").WithLocation(18, 54) ); } [Fact] public void ExpressionTreeLocalFunctionUsage_02() { var source = @" using System; using System.Linq.Expressions; class Program { static void Main() { static T Id<T>(T x) { return x; } static Expression<Func<T>> Local<T>(Expression<Func<T>> f) { return f; } Console.Write(Local(() => Id(2))); Console.Write(Local<Func<int, int>>(() => Id)); Console.Write(Local(() => new Func<int, int>(Id))); Console.Write(Local(() => nameof(Id))); } } "; VerifyDiagnostics(source, // (16,35): error CS8096: An expression tree may not contain a reference to a local function // Console.Write(Local(() => Id(2))); Diagnostic(ErrorCode.ERR_ExpressionTreeContainsLocalFunction, "Id(2)").WithLocation(16, 35), // (17,51): error CS8096: An expression tree may not contain a reference to a local function // Console.Write(Local<Func<int, int>>(() => Id)); Diagnostic(ErrorCode.ERR_ExpressionTreeContainsLocalFunction, "Id").WithLocation(17, 51), // (18,35): error CS8096: An expression tree may not contain a reference to a local function // Console.Write(Local(() => new Func<int, int>(Id))); Diagnostic(ErrorCode.ERR_ExpressionTreeContainsLocalFunction, "Id").WithLocation(18, 54) ); } [Fact] public void ExpressionTreeLocalFunctionInside() { var source = @" using System; using System.Linq.Expressions; class Program { static void Main() { Expression<Func<int, int>> f = x => { int Local(int y) => y; return Local(x); }; Console.Write(f); } } "; VerifyDiagnostics(source, // (8,40): error CS0834: A lambda expression with a statement body cannot be converted to an expression tree // Expression<Func<int, int>> f = x => Diagnostic(ErrorCode.ERR_StatementLambdaToExpressionTree, @"x => { int Local(int y) => y; return Local(x); }").WithLocation(8, 40), // (11,20): error CS8096: An expression tree may not contain a local function or a reference to a local function // return Local(x); Diagnostic(ErrorCode.ERR_ExpressionTreeContainsLocalFunction, "Local(x)").WithLocation(11, 20) ); } [Fact] public void BadScoping() { var source = @" using System; class Program { static void Main(string[] args) { if (true) { void Local() { Console.WriteLine(2); } Local(); } Local(); Local2(); void Local2() { Console.WriteLine(2); } } } "; VerifyDiagnostics(source, // (16,9): error CS0103: The name 'Local' does not exist in the current context // Local(); Diagnostic(ErrorCode.ERR_NameNotInContext, "Local").WithArguments("Local").WithLocation(16, 9) ); } [Fact] public void NameConflictDuplicate() { var source = @" class Program { static void Main(string[] args) { void Duplicate() { } void Duplicate() { } Duplicate(); } } "; VerifyDiagnostics(source, // (7,14): error CS0128: A local variable named 'Duplicate' is already defined in this scope // void Duplicate() { } Diagnostic(ErrorCode.ERR_LocalDuplicate, "Duplicate").WithArguments("Duplicate").WithLocation(7, 14), // (7,14): warning CS8321: The local function 'Duplicate' is declared but never used // void Duplicate() { } Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "Duplicate").WithArguments("Duplicate").WithLocation(7, 14) ); } [Fact] public void NameConflictParameter() { var source = @" class Program { static void Main(string[] args) { int x = 2; void Param(int x) { } Param(x); } } "; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular7_3); comp.VerifyDiagnostics( // (7,24): error CS0136: A local or parameter named 'x' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter // void Param(int x) { } Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "x").WithArguments("x").WithLocation(7, 24)); comp = CreateCompilation(source, parseOptions: TestOptions.Regular8); comp.VerifyDiagnostics(); } [Fact] public void NameConflictTypeParameter() { var source = @" class Program { static void Main(string[] args) { int T; void Generic<T>() { } Generic<int>(); } } "; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular7_3); comp.VerifyDiagnostics( // (7,22): error CS0136: A local or parameter named 'T' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter // void Generic<T>() { } Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "T").WithArguments("T").WithLocation(7, 22), // (6,13): warning CS0168: The variable 'T' is declared but never used // int T; Diagnostic(ErrorCode.WRN_UnreferencedVar, "T").WithArguments("T").WithLocation(6, 13)); comp = CreateCompilation(source, parseOptions: TestOptions.Regular8); comp.VerifyDiagnostics( // (6,13): warning CS0168: The variable 'T' is declared but never used // int T; Diagnostic(ErrorCode.WRN_UnreferencedVar, "T").WithArguments("T").WithLocation(6, 13)); } [Fact] public void NameConflictNestedTypeParameter() { var source = @" class Program { static void Main(string[] args) { T Outer<T>() { T Inner<T>() { return default(T); } return Inner<T>(); } System.Console.Write(Outer<int>()); } } "; VerifyDiagnostics(source, // (8,21): warning CS8387: Type parameter 'T' has the same name as the type parameter from outer method 'Outer<T>()' // T Inner<T>() Diagnostic(ErrorCode.WRN_TypeParameterSameAsOuterMethodTypeParameter, "T").WithArguments("T", "Outer<T>()").WithLocation(8, 21) ); } [Fact] public void NameConflictLocalVarFirst() { var source = @" class Program { static void Main(string[] args) { int Conflict; void Conflict() { } } } "; VerifyDiagnostics(source, // (7,14): error CS0128: A local variable named 'Conflict' is already defined in this scope // void Conflict() { } Diagnostic(ErrorCode.ERR_LocalDuplicate, "Conflict").WithArguments("Conflict").WithLocation(7, 14), // (6,13): warning CS0168: The variable 'Conflict' is declared but never used // int Conflict; Diagnostic(ErrorCode.WRN_UnreferencedVar, "Conflict").WithArguments("Conflict").WithLocation(6, 13), // (7,14): warning CS8321: The local function 'Conflict' is declared but never used // void Conflict() { } Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "Conflict").WithArguments("Conflict").WithLocation(7, 14) ); } [Fact] public void NameConflictLocalVarLast() { var source = @" class Program { static void Main(string[] args) { void Conflict() { } int Conflict; } } "; // TODO: This is strange. Probably has to do with the fact that local variables are preferred over functions. VerifyDiagnostics(source, // (6,14): error CS0136: A local or parameter named 'Conflict' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter // void Conflict() { } Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "Conflict").WithArguments("Conflict").WithLocation(6, 14), // (7,13): warning CS0168: The variable 'Conflict' is declared but never used // int Conflict; Diagnostic(ErrorCode.WRN_UnreferencedVar, "Conflict").WithArguments("Conflict").WithLocation(7, 13), // (6,14): warning CS8321: The local function 'Conflict' is declared but never used // void Conflict() { } Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "Conflict").WithArguments("Conflict").WithLocation(6, 14) ); } [Fact] public void BadUnsafeNoKeyword() { var source = @" using System; class Program { static void A() { void Local() { int x = 2; Console.WriteLine(*&x); } Local(); } static void Main(string[] args) { A(); } } "; VerifyDiagnostics(source, // (11,32): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context // Console.WriteLine(*&x); Diagnostic(ErrorCode.ERR_UnsafeNeeded, "&x").WithLocation(11, 32) ); } [Fact] public void BadUnsafeKeywordDoesntApply() { var source = @" using System; class Program { static unsafe void B() { void Local() { int x = 2; Console.WriteLine(*&x); } Local(); } static void Main(string[] args) { B(); } } "; var comp = CreateCompilation(source, options: TestOptions.ReleaseExe.WithAllowUnsafe(true)); comp.VerifyDiagnostics(); } [Fact] public void BadEmptyBody() { var source = @" class Program { static void Main(string[] args) { void Local(int x); Local(2); } }"; VerifyDiagnostics(source, // (6,14): error CS8112: 'Local(int)' is a local function and must therefore always have a body. // void Local(int x); Diagnostic(ErrorCode.ERR_LocalFunctionMissingBody, "Local").WithArguments("Local(int)").WithLocation(6, 14) ); } [Fact] public void BadGotoInto() { var source = @" using System; class Program { static void Main(string[] args) { goto A; void Local() { A: Console.Write(2); } Local(); } }"; VerifyDiagnostics(source, // (8,14): error CS0159: No such label 'A' within the scope of the goto statement // goto A; Diagnostic(ErrorCode.ERR_LabelNotFound, "A").WithArguments("A").WithLocation(8, 14), // (11,9): warning CS0164: This label has not been referenced // A: Console.Write(2); Diagnostic(ErrorCode.WRN_UnreferencedLabel, "A").WithLocation(11, 9) ); } [Fact] public void BadGotoOutOf() { var source = @" class Program { static void Main(string[] args) { void Local() { goto A; } A: Local(); } }"; VerifyDiagnostics(source, // (8,13): error CS0159: No such label 'A' within the scope of the goto statement // goto A; Diagnostic(ErrorCode.ERR_LabelNotFound, "goto").WithArguments("A").WithLocation(8, 13) ); } [Fact] public void BadDefiniteAssignmentCall() { var source = @" using System; class Program { static void A() { goto Label; int x = 2; void Local() { Console.Write(x); } Label: Local(); } static void Main(string[] args) { A(); } }"; VerifyDiagnostics(source, // (9,9): warning CS0162: Unreachable code detected // int x = 2; Diagnostic(ErrorCode.WRN_UnreachableCode, "int").WithLocation(9, 9), // (15,9): error CS0165: Use of unassigned local variable 'x' // Local(); Diagnostic(ErrorCode.ERR_UseDefViolation, "Local()").WithArguments("x").WithLocation(15, 9) ); } [Fact] public void BadDefiniteAssignmentDelegateConversion() { var source = @" using System; class Program { static void A() { goto Label; int x = 2; void Local() { Console.Write(x); } Label: Action goo = Local; } static void Main(string[] args) { A(); } }"; VerifyDiagnostics(source, // (9,9): warning CS0162: Unreachable code detected // int x = 2; Diagnostic(ErrorCode.WRN_UnreachableCode, "int").WithLocation(9, 9), // (15,22): error CS0165: Use of unassigned local variable 'x' // Action goo = Local; Diagnostic(ErrorCode.ERR_UseDefViolation, "Local").WithArguments("x").WithLocation(15, 22) ); } [Fact] public void BadDefiniteAssignmentDelegateConstruction() { var source = @" using System; class Program { static void A() { goto Label; int x = 2; void Local() { Console.Write(x); } Label: var bar = new Action(Local); } static void Main(string[] args) { A(); } }"; VerifyDiagnostics(source, // (9,9): warning CS0162: Unreachable code detected // int x = 2; Diagnostic(ErrorCode.WRN_UnreachableCode, "int").WithLocation(9, 9), // (15,19): error CS0165: Use of unassigned local variable 'x' // var bar = new Action(Local); Diagnostic(ErrorCode.ERR_UseDefViolation, "new Action(Local)").WithArguments("x").WithLocation(15, 19) ); } [Fact] public void BadNotUsed() { var source = @" class Program { static void A() { void Local() { } } static void Main(string[] args) { A(); } }"; VerifyDiagnostics(source, // (6,14): warning CS8321: The local function 'Local' is declared but never used // void Local() Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "Local").WithArguments("Local").WithLocation(6, 14) ); } [Fact] public void BadNotUsedSwitch() { var source = @" class Program { static void A() { switch (0) { case 0: void Local() { } break; } } static void Main(string[] args) { A(); } }"; VerifyDiagnostics(source, // (9,18): warning CS8321: The local function 'Local' is declared but never used // void Local() Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "Local").WithArguments("Local").WithLocation(9, 18) ); } [Fact] public void BadByRefClosure() { var source = @" using System; class Program { static void A(ref int x) { void Local() { Console.WriteLine(x); } Local(); } static void Main() { } }"; VerifyDiagnostics(source, // (10,31): error CS1628: Cannot use ref or out parameter 'x' inside an anonymous method, lambda expression, query expression, or local function // Console.WriteLine(x); Diagnostic(ErrorCode.ERR_AnonDelegateCantUse, "x").WithArguments("x").WithLocation(10, 31) ); } [Fact] public void BadInClosure() { var source = @" using System; class Program { static void A(in int x) { void Local() { Console.WriteLine(x); } Local(); } static void Main() { } }"; VerifyDiagnostics(source, // (10,31): error CS1628: Cannot use ref, out, or in parameter 'x' inside an anonymous method, lambda expression, query expression, or local function // Console.WriteLine(x); Diagnostic(ErrorCode.ERR_AnonDelegateCantUse, "x").WithArguments("x").WithLocation(10, 31) ); } [Fact] public void BadArglistUse() { var source = @" using System; class Program { static void A() { void Local() { Console.WriteLine(__arglist); } Local(); } static void B(__arglist) { void Local() { Console.WriteLine(__arglist); } Local(); } static void C() // C and D produce different errors { void Local(__arglist) { Console.WriteLine(__arglist); } Local(__arglist()); } static void D(__arglist) { void Local(__arglist) { Console.WriteLine(__arglist); } Local(__arglist()); } static void Main() { } } "; VerifyDiagnostics(source, // (10,31): error CS0190: The __arglist construct is valid only within a variable argument method // Console.WriteLine(__arglist); Diagnostic(ErrorCode.ERR_ArgsInvalid, "__arglist").WithLocation(10, 31), // (18,31): error CS4013: Instance of type 'RuntimeArgumentHandle' cannot be used inside a nested function, query expression, iterator block or async method // Console.WriteLine(__arglist); Diagnostic(ErrorCode.ERR_SpecialByRefInLambda, "__arglist").WithArguments("System.RuntimeArgumentHandle").WithLocation(18, 31), // (24,20): error CS1669: __arglist is not valid in this context // void Local(__arglist) Diagnostic(ErrorCode.ERR_IllegalVarArgs, "__arglist").WithLocation(24, 20), // (26,31): error CS0190: The __arglist construct is valid only within a variable argument method // Console.WriteLine(__arglist); Diagnostic(ErrorCode.ERR_ArgsInvalid, "__arglist").WithLocation(26, 31), // (32,20): error CS1669: __arglist is not valid in this context // void Local(__arglist) Diagnostic(ErrorCode.ERR_IllegalVarArgs, "__arglist").WithLocation(32, 20), // (34,31): error CS4013: Instance of type 'RuntimeArgumentHandle' cannot be used inside a nested function, query expression, iterator block or async method // Console.WriteLine(__arglist); Diagnostic(ErrorCode.ERR_SpecialByRefInLambda, "__arglist").WithArguments("System.RuntimeArgumentHandle").WithLocation(34, 31) ); } [Fact] public void BadClosureStaticRefInstance() { var source = @" using System; class Program { int _a = 0; static void A() { void Local() { Console.WriteLine(_a); } Local(); } static void Main() { } } "; VerifyDiagnostics(source, // (11,31): error CS0120: An object reference is required for the non-static field, method, or property 'Program._a' // Console.WriteLine(_a); Diagnostic(ErrorCode.ERR_ObjectRequired, "_a").WithArguments("Program._a").WithLocation(11, 31) ); } [Fact] public void BadRefIterator() { var source = @" using System.Collections.Generic; class Program { static void Main(string[] args) { IEnumerable<int> RefEnumerable(ref int x) { yield return x; } int y = 0; RefEnumerable(ref y); } } "; VerifyDiagnostics(source, // (8,48): error CS1623: Iterators cannot have ref, in or out parameters // IEnumerable<int> RefEnumerable(ref int x) Diagnostic(ErrorCode.ERR_BadIteratorArgType, "x").WithLocation(8, 48) ); } [Fact] public void BadRefAsync() { var source = @" using System; using System.Threading.Tasks; class Program { static void Main(string[] args) { async Task<int> RefAsync(ref int x) { return await Task.FromResult(x); } int y = 2; Console.Write(RefAsync(ref y).Result); } } "; VerifyDiagnostics(source, // (9,42): error CS1988: Async methods cannot have ref, in or out parameters // async Task<int> RefAsync(ref int x) Diagnostic(ErrorCode.ERR_BadAsyncArgType, "x").WithLocation(9, 42) ); } [Fact] public void Extension_01() { var source = @" using System; class Program { static void Main(string[] args) { int Local(this int x) { return x; } Console.WriteLine(Local(2)); } } "; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (8,13): error CS1106: Extension method must be defined in a non-generic static class // int Local(this int x) Diagnostic(ErrorCode.ERR_BadExtensionAgg, "Local").WithLocation(8, 13) ); } [Fact] public void Extension_02() { var source = @"#pragma warning disable 8321 static class E { static void M() { void F1(this string s) { } static void F2(this string s) { } } }"; var comp = CreateCompilation(source); comp.VerifyEmitDiagnostics( // (6,14): error CS1106: Extension method must be defined in a non-generic static class // void F1(this string s) { } Diagnostic(ErrorCode.ERR_BadExtensionAgg, "F1").WithLocation(6, 14), // (7,21): error CS1106: Extension method must be defined in a non-generic static class // static void F2(this string s) { } Diagnostic(ErrorCode.ERR_BadExtensionAgg, "F2").WithLocation(7, 21)); } [Fact] public void BadModifiers() { var source = @" class Program { static void Main(string[] args) { const void LocalConst() { } static void LocalStatic() { } readonly void LocalReadonly() { } volatile void LocalVolatile() { } LocalConst(); LocalStatic(); LocalReadonly(); LocalVolatile(); } } "; var baseExpected = new[] { // (6,9): error CS0106: The modifier 'const' is not valid for this item // const void LocalConst() Diagnostic(ErrorCode.ERR_BadMemberFlag, "const").WithArguments("const").WithLocation(6, 9), // (12,9): error CS0106: The modifier 'readonly' is not valid for this item // readonly void LocalReadonly() Diagnostic(ErrorCode.ERR_BadMemberFlag, "readonly").WithArguments("readonly").WithLocation(12, 9), // (15,9): error CS0106: The modifier 'volatile' is not valid for this item // volatile void LocalVolatile() Diagnostic(ErrorCode.ERR_BadMemberFlag, "volatile").WithArguments("volatile").WithLocation(15, 9) }; var extra = new[] { // (9,9): error CS8652: The feature 'static local functions' is not available in C# 7.3. Please use language version 8.0 or greater. // static void LocalStatic() Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "static").WithArguments("static local functions", "8.0").WithLocation(9, 9), }; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular7_3); comp.VerifyDiagnostics( baseExpected.Concat(extra).ToArray()); comp = CreateCompilation(source, parseOptions: TestOptions.Regular8); comp.VerifyDiagnostics(baseExpected); comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics(baseExpected); } [Fact] public void ArglistIterator() { var source = @" using System; using System.Collections.Generic; class Program { static void Main(string[] args) { IEnumerable<int> Local(__arglist) { yield return 2; } Console.WriteLine(string.Join("","", Local(__arglist()))); } } "; VerifyDiagnostics(source, // (9,26): error CS1636: __arglist is not allowed in the parameter list of iterators // IEnumerable<int> Local(__arglist) Diagnostic(ErrorCode.ERR_VarargsIterator, "Local").WithLocation(9, 26), // (9,32): error CS1669: __arglist is not valid in this context // IEnumerable<int> Local(__arglist) Diagnostic(ErrorCode.ERR_IllegalVarArgs, "__arglist").WithLocation(9, 32)); } [Fact] public void ForwardReference() { var source = @" using System; class Program { static void Main(string[] args) { Console.WriteLine(Local()); int Local() => 2; } } "; CompileAndVerify(source, expectedOutput: "2"); } [Fact] public void ForwardReferenceCapture() { var source = @" using System; class Program { static void Main(string[] args) { int x = 2; Console.WriteLine(Local()); int Local() => x; } } "; CompileAndVerify(source, expectedOutput: "2"); } [Fact] public void ForwardRefInLocalFunc() { var source = @" using System; class Program { static void Main(string[] args) { int x = 2; Console.WriteLine(Local()); int Local() { x = 3; return Local2(); } int Local2() => x; } } "; CompileAndVerify(source, expectedOutput: "3"); } [Fact] public void LocalFuncMutualRecursion() { var source = @" using System; class Program { static void Main(string[] args) { int x = 5; int y = 0; Console.WriteLine(Local1()); int Local1() { x -= 1; return Local2(y++); } int Local2(int z) { if (x == 0) { return z; } else { return Local1(); } } } } "; CompileAndVerify(source, expectedOutput: "4"); } [Fact] public void OtherSwitchBlock() { var source = @" using System; class Program { static void Main(string[] args) { var x = int.Parse(Console.ReadLine()); switch (x) { case 0: void Local() { } break; default: Local(); break; } } } "; VerifyDiagnostics(source); } [Fact] public void NoOperator() { var source = @" class Program { static void Main(string[] args) { Program operator +(Program left, Program right) { return left; } } } "; VerifyDiagnostics(source, // (6,17): error CS1002: ; expected // Program operator +(Program left, Program right) Diagnostic(ErrorCode.ERR_SemicolonExpected, "operator").WithLocation(6, 17), // (6,17): error CS1513: } expected // Program operator +(Program left, Program right) Diagnostic(ErrorCode.ERR_RbraceExpected, "operator").WithLocation(6, 17), // (6,56): error CS1002: ; expected // Program operator +(Program left, Program right) Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(6, 56), // (6,9): error CS0119: 'Program' is a type, which is not valid in the given context // Program operator +(Program left, Program right) Diagnostic(ErrorCode.ERR_BadSKunknown, "Program").WithArguments("Program", "type").WithLocation(6, 9), // (6,28): error CS8185: A declaration is not allowed in this context. // Program operator +(Program left, Program right) Diagnostic(ErrorCode.ERR_DeclarationExpressionNotPermitted, "Program left").WithLocation(6, 28), // (6,42): error CS8185: A declaration is not allowed in this context. // Program operator +(Program left, Program right) Diagnostic(ErrorCode.ERR_DeclarationExpressionNotPermitted, "Program right").WithLocation(6, 42), // (6,27): error CS8179: Predefined type 'System.ValueTuple`2' is not defined or imported // Program operator +(Program left, Program right) Diagnostic(ErrorCode.ERR_PredefinedValueTupleTypeNotFound, "(Program left, Program right)").WithArguments("System.ValueTuple`2").WithLocation(6, 27), // (8,13): error CS0127: Since 'Program.Main(string[])' returns void, a return keyword must not be followed by an object expression // return left; Diagnostic(ErrorCode.ERR_RetNoObjectRequired, "return").WithArguments("Program.Main(string[])").WithLocation(8, 13), // (6,28): error CS0165: Use of unassigned local variable 'left' // Program operator +(Program left, Program right) Diagnostic(ErrorCode.ERR_UseDefViolation, "Program left").WithArguments("left").WithLocation(6, 28), // (6,42): error CS0165: Use of unassigned local variable 'right' // Program operator +(Program left, Program right) Diagnostic(ErrorCode.ERR_UseDefViolation, "Program right").WithArguments("right").WithLocation(6, 42) ); } [Fact] public void NoProperty() { var source = @" class Program { static void Main(string[] args) { int Goo { get { return 2; } } int Bar => 2; } } "; VerifyDiagnostics(source, // (6,16): error CS1002: ; expected // int Goo Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(6, 16), // (8,16): error CS1002: ; expected // get Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(8, 16), // (13,17): error CS1003: Syntax error, ',' expected // int Bar => 2; Diagnostic(ErrorCode.ERR_SyntaxError, "=>").WithArguments(",").WithLocation(13, 17), // (13,20): error CS1002: ; expected // int Bar => 2; Diagnostic(ErrorCode.ERR_SemicolonExpected, "2").WithLocation(13, 20), // (8,13): error CS0103: The name 'get' does not exist in the current context // get Diagnostic(ErrorCode.ERR_NameNotInContext, "get").WithArguments("get").WithLocation(8, 13), // (10,17): error CS0127: Since 'Program.Main(string[])' returns void, a return keyword must not be followed by an object expression // return 2; Diagnostic(ErrorCode.ERR_RetNoObjectRequired, "return").WithArguments("Program.Main(string[])").WithLocation(10, 17), // (13,20): error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement // int Bar => 2; Diagnostic(ErrorCode.ERR_IllegalStatement, "2").WithLocation(13, 20), // (13,9): warning CS0162: Unreachable code detected // int Bar => 2; Diagnostic(ErrorCode.WRN_UnreachableCode, "int").WithLocation(13, 9), // (6,13): warning CS0168: The variable 'Goo' is declared but never used // int Goo Diagnostic(ErrorCode.WRN_UnreferencedVar, "Goo").WithArguments("Goo").WithLocation(6, 13), // (13,13): warning CS0168: The variable 'Bar' is declared but never used // int Bar => 2; Diagnostic(ErrorCode.WRN_UnreferencedVar, "Bar").WithArguments("Bar").WithLocation(13, 13) ); } [Fact] public void NoFeatureSwitch() { var source = @" class Program { static void Main(string[] args) { void Local() { } Local(); } } "; var option = TestOptions.ReleaseExe; CreateCompilation(source, options: option, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp6)).VerifyDiagnostics( // (6,14): error CS8059: Feature 'local functions' is not available in C# 6. Please use language version 7.0 or greater. // void Local() { } Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion6, "Local").WithArguments("local functions", "7.0").WithLocation(6, 14) ); } [Fact, WorkItem(10521, "https://github.com/dotnet/roslyn/issues/10521")] public void LocalFunctionInIf() { var source = @" class Program { static void Main(string[] args) { if () // typing at this point int Add(int x, int y) => x + y; } } "; VerifyDiagnostics(source, // (6,13): error CS1525: Invalid expression term ')' // if () // typing at this point Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(6, 13), // (7,9): error CS1023: Embedded statement cannot be a declaration or labeled statement // int Add(int x, int y) => x + y; Diagnostic(ErrorCode.ERR_BadEmbeddedStmt, "int Add(int x, int y) => x + y;").WithLocation(7, 9), // (7,13): warning CS8321: The local function 'Add' is declared but never used // int Add(int x, int y) => x + y; Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "Add").WithArguments("Add").WithLocation(7, 13) ); } [Fact, WorkItem(10521, "https://github.com/dotnet/roslyn/issues/10521")] public void LabeledLocalFunctionInIf() { var source = @" class Program { static void Main(string[] args) { if () // typing at this point a: int Add(int x, int y) => x + y; } } "; VerifyDiagnostics(source, // (6,13): error CS1525: Invalid expression term ')' // if () // typing at this point Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(6, 13), // (7,1): error CS1023: Embedded statement cannot be a declaration or labeled statement // a: int Add(int x, int y) => x + y; Diagnostic(ErrorCode.ERR_BadEmbeddedStmt, "a: int Add(int x, int y) => x + y;").WithLocation(7, 1), // (7,1): warning CS0164: This label has not been referenced // a: int Add(int x, int y) => x + y; Diagnostic(ErrorCode.WRN_UnreferencedLabel, "a").WithLocation(7, 1), // (7,13): warning CS8321: The local function 'Add' is declared but never used // a: int Add(int x, int y) => x + y; Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "Add").WithArguments("Add").WithLocation(7, 13) ); } [CompilerTrait(CompilerFeature.LocalFunctions, CompilerFeature.Var)] public sealed class VarTests : LocalFunctionsTestBase { [Fact] public void IllegalAsReturn() { var source = @" using System; class Program { static void Main() { var f() => 42; Console.WriteLine(f()); } }"; var comp = CreateCompilationWithMscorlib461(source, parseOptions: DefaultParseOptions); comp.VerifyDiagnostics( // (7,9): error CS0825: The contextual keyword 'var' may only appear within a local variable declaration or in script code // var f() => 42; Diagnostic(ErrorCode.ERR_TypeVarNotFound, "var").WithLocation(7, 9)); } [Fact] public void RealTypeAsReturn() { var source = @" using System; class var { public override string ToString() => ""dog""; } class Program { static void Main() { var f() => new var(); Console.WriteLine(f()); } }"; CompileAndVerify( source, parseOptions: DefaultParseOptions, expectedOutput: "dog"); } [Fact] public void RealTypeParameterAsReturn() { var source = @" using System; class test { public override string ToString() => ""dog""; } class Program { static void Test<var>(var x) { var f() => x; Console.WriteLine(f()); } static void Main() { Test(new test()); } }"; CompileAndVerify( source, parseOptions: DefaultParseOptions, expectedOutput: "dog"); } [Fact] public void IdentifierAndTypeNamedVar() { var source = @" using System; class var { public override string ToString() => ""dog""; } class Program { static void Main() { int var = 42; var f() => new var(); Console.WriteLine($""{f()}-{var}""); } }"; CompileAndVerify( source, parseOptions: DefaultParseOptions, expectedOutput: "dog-42"); } } [CompilerTrait(CompilerFeature.LocalFunctions, CompilerFeature.Async)] public sealed class AsyncTests : LocalFunctionsTestBase { [Fact] public void RealTypeAsReturn() { var source = @" using System; class async { public override string ToString() => ""dog""; } class Program { static void Main() { async f() => new async(); Console.WriteLine(f()); } }"; CompileAndVerify( source, parseOptions: DefaultParseOptions, expectedOutput: "dog"); } [Fact] public void RealTypeParameterAsReturn() { var source = @" using System; class test { public override string ToString() => ""dog""; } class Program { static void Test<async>(async x) { async f() => x; Console.WriteLine(f()); } static void Main() { Test(new test()); } }"; CompileAndVerify( source, parseOptions: DefaultParseOptions, expectedOutput: "dog"); } [Fact] public void ManyMeaningsType() { var source = @" using System; using System.Threading; using System.Threading.Tasks; class async { public override string ToString() => ""async""; } class Program { static void Main() { async Task<async> Test(Task<async> t) { async local = await t; Console.WriteLine(local); return local; } Test(Task.FromResult<async>(new async())).Wait(); } }"; var comp = CreateCompilationWithMscorlib46(source, parseOptions: DefaultParseOptions, options: TestOptions.DebugExe); CompileAndVerify( comp, expectedOutput: "async"); } } [Fact] [WorkItem(12467, "https://github.com/dotnet/roslyn/issues/12467")] public void ParamUnassigned_01() { var src = @" class C { public void M1() { void TakeOutParam1(out int x) { } int y; TakeOutParam1(out y); } void TakeOutParam2(out int x) { } }"; VerifyDiagnostics(src, // (6,14): error CS0177: The out parameter 'x' must be assigned to before control leaves the current method // void TakeOutParam1(out int x) Diagnostic(ErrorCode.ERR_ParamUnassigned, "TakeOutParam1").WithArguments("x").WithLocation(6, 14), // (14,14): error CS0177: The out parameter 'x' must be assigned to before control leaves the current method // void TakeOutParam2(out int x) Diagnostic(ErrorCode.ERR_ParamUnassigned, "TakeOutParam2").WithArguments("x").WithLocation(14, 14) ); } [Fact] [WorkItem(12467, "https://github.com/dotnet/roslyn/issues/12467")] public void ParamUnassigned_02() { var src = @" class C { public void M1() { void TakeOutParam1(out int x) { return; // 1 } int y; TakeOutParam1(out y); } void TakeOutParam2(out int x) { return; // 2 } }"; VerifyDiagnostics(src, // (8,13): error CS0177: The out parameter 'x' must be assigned to before control leaves the current method // return; // 1 Diagnostic(ErrorCode.ERR_ParamUnassigned, "return;").WithArguments("x").WithLocation(8, 13), // (17,13): error CS0177: The out parameter 'x' must be assigned to before control leaves the current method // return; // 2 Diagnostic(ErrorCode.ERR_ParamUnassigned, "return;").WithArguments("x").WithLocation(17, 13) ); } [Fact] [WorkItem(12467, "https://github.com/dotnet/roslyn/issues/12467")] public void ParamUnassigned_03() { var src = @" class C { public void M1() { int TakeOutParam1(out int x) { } int y; TakeOutParam1(out y); } int TakeOutParam2(out int x) { } }"; VerifyDiagnostics(src, // (6,13): error CS0161: 'TakeOutParam1(out int)': not all code paths return a value // int TakeOutParam1(out int x) Diagnostic(ErrorCode.ERR_ReturnExpected, "TakeOutParam1").WithArguments("TakeOutParam1(out int)").WithLocation(6, 13), // (6,13): error CS0177: The out parameter 'x' must be assigned to before control leaves the current method // int TakeOutParam1(out int x) Diagnostic(ErrorCode.ERR_ParamUnassigned, "TakeOutParam1").WithArguments("x").WithLocation(6, 13), // (14,13): error CS0177: The out parameter 'x' must be assigned to before control leaves the current method // int TakeOutParam2(out int x) Diagnostic(ErrorCode.ERR_ParamUnassigned, "TakeOutParam2").WithArguments("x").WithLocation(14, 13), // (14,13): error CS0161: 'C.TakeOutParam2(out int)': not all code paths return a value // int TakeOutParam2(out int x) Diagnostic(ErrorCode.ERR_ReturnExpected, "TakeOutParam2").WithArguments("C.TakeOutParam2(out int)").WithLocation(14, 13) ); } [Fact] [WorkItem(12467, "https://github.com/dotnet/roslyn/issues/12467")] public void ParamUnassigned_04() { var src = @" class C { public void M1() { int TakeOutParam1(out int x) { return 1; } int y; TakeOutParam1(out y); } int TakeOutParam2(out int x) { return 2; } }"; VerifyDiagnostics(src, // (8,13): error CS0177: The out parameter 'x' must be assigned to before control leaves the current method // return 1; Diagnostic(ErrorCode.ERR_ParamUnassigned, "return 1;").WithArguments("x").WithLocation(8, 13), // (17,13): error CS0177: The out parameter 'x' must be assigned to before control leaves the current method // return 2; Diagnostic(ErrorCode.ERR_ParamUnassigned, "return 2;").WithArguments("x").WithLocation(17, 13) ); } [Fact] [WorkItem(49500, "https://github.com/dotnet/roslyn/issues/49500")] public void OutParam_Extern_01() { var src = @" using System.Runtime.InteropServices; class C { void M() { int x; local(out x); x.ToString(); [DllImport(""a"")] static extern void local(out int x); } [DllImport(""a"")] static extern void Method(out int x); }"; VerifyDiagnostics(src); } [Fact] [WorkItem(49500, "https://github.com/dotnet/roslyn/issues/49500")] public void OutParam_Extern_02() { var src = @" using System.Runtime.InteropServices; class C { void M() { local1(out _); local2(out _); local3(out _); [DllImport(""a"")] static extern void local1(out int x) { } // 1 static void local2(out int x) { } // 2 static void local3(out int x); // 3, 4 } [DllImport(""a"")] static extern void Method(out int x); }"; VerifyDiagnostics(src, // (13,28): error CS0179: 'local1(out int)' cannot be extern and declare a body // static extern void local1(out int x) { } // 1 Diagnostic(ErrorCode.ERR_ExternHasBody, "local1").WithArguments("local1(out int)").WithLocation(13, 28), // (15,21): error CS0177: The out parameter 'x' must be assigned to before control leaves the current method // static void local2(out int x) { } // 2 Diagnostic(ErrorCode.ERR_ParamUnassigned, "local2").WithArguments("x").WithLocation(15, 21), // (17,21): error CS8112: Local function 'local3(out int)' must declare a body because it is not marked 'static extern'. // static void local3(out int x); // 3, 4 Diagnostic(ErrorCode.ERR_LocalFunctionMissingBody, "local3").WithArguments("local3(out int)").WithLocation(17, 21), // (17,21): error CS0177: The out parameter 'x' must be assigned to before control leaves the current method // static void local3(out int x); // 3, 4 Diagnostic(ErrorCode.ERR_ParamUnassigned, "local3").WithArguments("x").WithLocation(17, 21)); } [Fact] [WorkItem(13172, "https://github.com/dotnet/roslyn/issues/13172")] public void InheritUnsafeContext() { var source = @" using System; using System.Threading.Tasks; class C { public void M1() { async Task<IntPtr> Local() { await Task.Delay(0); return (IntPtr)(void*)null; } var _ = Local(); } public void M2() { unsafe { async Task<IntPtr> Local() { await Task.Delay(1); return (IntPtr)(void*)null; } var _ = Local(); } } public unsafe void M3() { async Task<IntPtr> Local() { await Task.Delay(2); return (IntPtr)(void*)null; } var _ = Local(); } } unsafe class D { int* p = null; public void M() { async Task<IntPtr> Local() { await Task.Delay(3); return (IntPtr)p; } var _ = Local(); } public unsafe void M2() { unsafe { async Task<IntPtr> Local() { await Task.Delay(4); return (IntPtr)(void*)null; } var _ = Local(); } } }"; var comp = CreateCompilationWithMscorlib46(source, options: TestOptions.UnsafeDebugDll, parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics( // (11,29): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context // return (IntPtr)(void*)null; Diagnostic(ErrorCode.ERR_UnsafeNeeded, "void*").WithLocation(11, 29), // (11,28): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context // return (IntPtr)(void*)null; Diagnostic(ErrorCode.ERR_UnsafeNeeded, "(void*)null").WithLocation(11, 28), // (47,13): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // await Task.Delay(3); Diagnostic(ErrorCode.ERR_FeatureInPreview, "await").WithArguments("updated memory safety rules").WithLocation(47, 13), // (22,17): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // await Task.Delay(1); Diagnostic(ErrorCode.ERR_FeatureInPreview, "await").WithArguments("updated memory safety rules").WithLocation(22, 17), // (59,17): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // await Task.Delay(4); Diagnostic(ErrorCode.ERR_FeatureInPreview, "await").WithArguments("updated memory safety rules").WithLocation(59, 17), // (33,13): error CS8652: The feature 'updated memory safety rules' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // await Task.Delay(2); Diagnostic(ErrorCode.ERR_FeatureInPreview, "await").WithArguments("updated memory safety rules").WithLocation(33, 13)); CreateCompilationWithMscorlib46(source, options: TestOptions.UnsafeDebugDll) .VerifyEmitDiagnostics(); CreateCompilationWithMscorlib46(source, options: TestOptions.UnsafeDebugDll, parseOptions: TestOptions.RegularNext) .VerifyEmitDiagnostics(); } [Fact, WorkItem(16167, "https://github.com/dotnet/roslyn/issues/16167")] public void DeclarationInLocalFunctionParameterDefault() { var text = @" class C { public static void Main(int arg) { void Local1(bool b = M(arg is int z1, z1), int s1 = z1) {} void Local2(bool b = M(M(out int z2), z2), int s2 = z2) {} void Local3(bool b = M(M((int z3, int a2) = (1, 2)), z3), int a3 = z3) {} void Local4(bool b = M(arg is var z4, z4), int s1 = z4) {} void Local5(bool b = M(M(out var z5), z5), int s2 = z5) {} void Local6(bool b = M(M((var z6, int a2) = (1, 2)), z6), int a3 = z6) {} int t = z1 + z2 + z3 + z4 + z5 + z6; } static bool M(out int z) // needed to infer type of z5 { z = 1; return true; } static bool M(params object[] args) => true; } namespace System { public struct ValueTuple<T1, T2> { public T1 Item1; public T2 Item2; public ValueTuple(T1 item1, T2 item2) { Item1 = item1; Item2 = item2; } } } "; // the scope of an expression variable introduced in the default expression // of a local function parameter is that default expression. var compilation = CreateCompilationWithMscorlib461(text); compilation.VerifyDiagnostics( // (6,30): error CS1736: Default parameter value for 'b' must be a compile-time constant // void Local1(bool b = M(arg is int z1, z1), int s1 = z1) {} Diagnostic(ErrorCode.ERR_DefaultValueMustBeConstant, "M(arg is int z1, z1)").WithArguments("b").WithLocation(6, 30), // (6,61): error CS0103: The name 'z1' does not exist in the current context // void Local1(bool b = M(arg is int z1, z1), int s1 = z1) {} Diagnostic(ErrorCode.ERR_NameNotInContext, "z1").WithArguments("z1").WithLocation(6, 61), // (7,30): error CS1736: Default parameter value for 'b' must be a compile-time constant // void Local2(bool b = M(M(out int z2), z2), int s2 = z2) {} Diagnostic(ErrorCode.ERR_DefaultValueMustBeConstant, "M(M(out int z2), z2)").WithArguments("b").WithLocation(7, 30), // (7,61): error CS0103: The name 'z2' does not exist in the current context // void Local2(bool b = M(M(out int z2), z2), int s2 = z2) {} Diagnostic(ErrorCode.ERR_NameNotInContext, "z2").WithArguments("z2").WithLocation(7, 61), // (8,35): error CS8185: A declaration is not allowed in this context. // void Local3(bool b = M(M((int z3, int a2) = (1, 2)), z3), int a3 = z3) {} Diagnostic(ErrorCode.ERR_DeclarationExpressionNotPermitted, "int z3").WithLocation(8, 35), // (8,30): error CS1736: Default parameter value for 'b' must be a compile-time constant // void Local3(bool b = M(M((int z3, int a2) = (1, 2)), z3), int a3 = z3) {} Diagnostic(ErrorCode.ERR_DefaultValueMustBeConstant, "M(M((int z3, int a2) = (1, 2)), z3)").WithArguments("b").WithLocation(8, 30), // (8,76): error CS0103: The name 'z3' does not exist in the current context // void Local3(bool b = M(M((int z3, int a2) = (1, 2)), z3), int a3 = z3) {} Diagnostic(ErrorCode.ERR_NameNotInContext, "z3").WithArguments("z3").WithLocation(8, 76), // (10,30): error CS1736: Default parameter value for 'b' must be a compile-time constant // void Local4(bool b = M(arg is var z4, z4), int s1 = z4) {} Diagnostic(ErrorCode.ERR_DefaultValueMustBeConstant, "M(arg is var z4, z4)").WithArguments("b").WithLocation(10, 30), // (10,61): error CS0103: The name 'z4' does not exist in the current context // void Local4(bool b = M(arg is var z4, z4), int s1 = z4) {} Diagnostic(ErrorCode.ERR_NameNotInContext, "z4").WithArguments("z4").WithLocation(10, 61), // (11,30): error CS1736: Default parameter value for 'b' must be a compile-time constant // void Local5(bool b = M(M(out var z5), z5), int s2 = z5) {} Diagnostic(ErrorCode.ERR_DefaultValueMustBeConstant, "M(M(out var z5), z5)").WithArguments("b").WithLocation(11, 30), // (11,61): error CS0103: The name 'z5' does not exist in the current context // void Local5(bool b = M(M(out var z5), z5), int s2 = z5) {} Diagnostic(ErrorCode.ERR_NameNotInContext, "z5").WithArguments("z5").WithLocation(11, 61), // (12,35): error CS8185: A declaration is not allowed in this context. // void Local6(bool b = M(M((var z6, int a2) = (1, 2)), z6), int a3 = z6) {} Diagnostic(ErrorCode.ERR_DeclarationExpressionNotPermitted, "var z6").WithLocation(12, 35), // (12,30): error CS1736: Default parameter value for 'b' must be a compile-time constant // void Local6(bool b = M(M((var z6, int a2) = (1, 2)), z6), int a3 = z6) {} Diagnostic(ErrorCode.ERR_DefaultValueMustBeConstant, "M(M((var z6, int a2) = (1, 2)), z6)").WithArguments("b").WithLocation(12, 30), // (12,76): error CS0103: The name 'z6' does not exist in the current context // void Local6(bool b = M(M((var z6, int a2) = (1, 2)), z6), int a3 = z6) {} Diagnostic(ErrorCode.ERR_NameNotInContext, "z6").WithArguments("z6").WithLocation(12, 76), // (14,17): error CS0103: The name 'z1' does not exist in the current context // int t = z1 + z2 + z3 + z4 + z5 + z6; Diagnostic(ErrorCode.ERR_NameNotInContext, "z1").WithArguments("z1").WithLocation(14, 17), // (14,22): error CS0103: The name 'z2' does not exist in the current context // int t = z1 + z2 + z3 + z4 + z5 + z6; Diagnostic(ErrorCode.ERR_NameNotInContext, "z2").WithArguments("z2").WithLocation(14, 22), // (14,27): error CS0103: The name 'z3' does not exist in the current context // int t = z1 + z2 + z3 + z4 + z5 + z6; Diagnostic(ErrorCode.ERR_NameNotInContext, "z3").WithArguments("z3").WithLocation(14, 27), // (14,32): error CS0103: The name 'z4' does not exist in the current context // int t = z1 + z2 + z3 + z4 + z5 + z6; Diagnostic(ErrorCode.ERR_NameNotInContext, "z4").WithArguments("z4").WithLocation(14, 32), // (14,37): error CS0103: The name 'z5' does not exist in the current context // int t = z1 + z2 + z3 + z4 + z5 + z6; Diagnostic(ErrorCode.ERR_NameNotInContext, "z5").WithArguments("z5").WithLocation(14, 37), // (14,42): error CS0103: The name 'z6' does not exist in the current context // int t = z1 + z2 + z3 + z4 + z5 + z6; Diagnostic(ErrorCode.ERR_NameNotInContext, "z6").WithArguments("z6").WithLocation(14, 42), // (6,14): warning CS8321: The local function 'Local1' is declared but never used // void Local1(bool b = M(arg is int z1, z1), int s1 = z1) {} Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "Local1").WithArguments("Local1").WithLocation(6, 14), // (7,14): warning CS8321: The local function 'Local2' is declared but never used // void Local2(bool b = M(M(out int z2), z2), int s2 = z2) {} Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "Local2").WithArguments("Local2").WithLocation(7, 14), // (8,14): warning CS8321: The local function 'Local3' is declared but never used // void Local3(bool b = M(M((int z3, int a2) = (1, 2)), z3), int a3 = z3) {} Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "Local3").WithArguments("Local3").WithLocation(8, 14), // (10,14): warning CS8321: The local function 'Local4' is declared but never used // void Local4(bool b = M(arg is var z4, z4), int s1 = z4) {} Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "Local4").WithArguments("Local4").WithLocation(10, 14), // (11,14): warning CS8321: The local function 'Local5' is declared but never used // void Local5(bool b = M(M(out var z5), z5), int s2 = z5) {} Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "Local5").WithArguments("Local5").WithLocation(11, 14), // (12,14): warning CS8321: The local function 'Local6' is declared but never used // void Local6(bool b = M(M((var z6, int a2) = (1, 2)), z6), int a3 = z6) {} Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "Local6").WithArguments("Local6").WithLocation(12, 14) ); var tree = compilation.SyntaxTrees[0]; var model = compilation.GetSemanticModel(tree); var descendents = tree.GetRoot().DescendantNodes(); for (int i = 1; i <= 6; i++) { var name = $"z{i}"; var designation = descendents.OfType<SingleVariableDesignationSyntax>().Where(d => d.Identifier.ValueText == name).Single(); var symbol = (ILocalSymbol)model.GetDeclaredSymbol(designation); Assert.NotNull(symbol); Assert.Equal("System.Int32", symbol.Type.ToTestDisplayString()); var refs = descendents.OfType<IdentifierNameSyntax>().Where(n => n.Identifier.ValueText == name).ToArray(); Assert.Equal(3, refs.Length); Assert.Equal(symbol, model.GetSymbolInfo(refs[0]).Symbol); Assert.Null(model.GetSymbolInfo(refs[1]).Symbol); Assert.Null(model.GetSymbolInfo(refs[2]).Symbol); } } [Fact] [WorkItem(16757, "https://github.com/dotnet/roslyn/issues/16757")] public void LocalFunctionParameterDefaultUsingConst() { var source = @" class C { public static void Main() { const int N = 2; void Local1(int n = N) { System.Console.Write(n); } Local1(); Local1(3); } } "; CompileAndVerify(source, expectedOutput: "23", sourceSymbolValidator: m => { var compilation = m.DeclaringCompilation; compilation.VerifyDiagnostics(); var tree = compilation.SyntaxTrees[0]; var model = compilation.GetSemanticModel(tree); var descendents = tree.GetRoot().DescendantNodes(); var parameter = descendents.OfType<ParameterSyntax>().Single(); Assert.Equal("int n = N", parameter.ToString()); Assert.Equal("[System.Int32 n = 2]", model.GetDeclaredSymbol(parameter).ToTestDisplayString()); var name = "N"; var declarator = descendents.OfType<VariableDeclaratorSyntax>().Where(d => d.Identifier.ValueText == name).Single(); var symbol = (ILocalSymbol)model.GetDeclaredSymbol(declarator); Assert.NotNull(symbol); Assert.Equal("System.Int32 N", symbol.ToTestDisplayString()); var refs = descendents.OfType<IdentifierNameSyntax>().Where(n => n.Identifier.ValueText == name).ToArray(); Assert.Equal(1, refs.Length); Assert.Same(symbol, model.GetSymbolInfo(refs[0]).Symbol); }); } [Fact, WorkItem(16821, "https://github.com/dotnet/roslyn/issues/16821")] public void LocalFunction_ParameterDefaultValue_NameOfLocalFunction() { var source = """ using System; void Local() {} void Local2(string s = nameof(Local)) => Console.WriteLine(s); Local2(); """; CreateCompilation(source).VerifyDiagnostics(); } [Fact] [WorkItem(15536, "https://github.com/dotnet/roslyn/issues/15536")] public void CallFromDifferentSwitchSection_01() { var source = @" class Program { static void Main() { Test(string.Empty); } static void Test(object o) { switch (o) { case string x: Assign(); Print(); break; case int x: void Assign() { x = 5; } void Print() => System.Console.WriteLine(x); break; } } }"; var comp = CreateCompilationWithMscorlib46(source, parseOptions: DefaultParseOptions, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: "5"); } [Fact] [WorkItem(15536, "https://github.com/dotnet/roslyn/issues/15536")] public void CallFromDifferentSwitchSection_02() { var source = @" class Program { static void Main() { Test(string.Empty); } static void Test(object o) { switch (o) { case int x: void Assign() { x = 5; } void Print() => System.Console.WriteLine(x); break; case string x: Assign(); Print(); break; } } }"; var comp = CreateCompilationWithMscorlib46(source, parseOptions: DefaultParseOptions, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: "5"); } [Fact] [WorkItem(15536, "https://github.com/dotnet/roslyn/issues/15536")] public void CallFromDifferentSwitchSection_03() { var source = @" class Program { static void Main() { Test(string.Empty); } static void Test(object o) { switch (o) { case string x: Assign(); System.Action p = Print; p(); break; case int x: void Assign() { x = 5; } void Print() => System.Console.WriteLine(x); break; } } }"; var comp = CreateCompilationWithMscorlib46(source, parseOptions: DefaultParseOptions, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: "5"); } [Fact] [WorkItem(15536, "https://github.com/dotnet/roslyn/issues/15536")] public void CallFromDifferentSwitchSection_04() { var source = @" class Program { static void Main() { Test(string.Empty); } static void Test(object o) { switch (o) { case int x: void Assign() { x = 5; } void Print() => System.Console.WriteLine(x); break; case string x: Assign(); System.Action p = Print; p(); break; } } }"; var comp = CreateCompilationWithMscorlib46(source, parseOptions: DefaultParseOptions, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: "5"); } [Fact] [WorkItem(15536, "https://github.com/dotnet/roslyn/issues/15536")] public void CallFromDifferentSwitchSection_05() { var source = @" class Program { static void Main() { Test(string.Empty); } static void Test(object o) { switch (o) { case string x: Local1(); break; case int x: void Local1() => Local2(x = 5); break; case char x: void Local2(int y) { System.Console.WriteLine(x = 'a'); System.Console.WriteLine(y); } break; } } }"; var comp = CreateCompilationWithMscorlib46(source, parseOptions: DefaultParseOptions, options: TestOptions.DebugExe); CompileAndVerify(comp, expectedOutput: @"a 5"); } [Fact] [WorkItem(16751, "https://github.com/dotnet/roslyn/issues/16751")] public void SemanticModelInAttribute_01() { var source = @" public class X { public static void Main() { const bool b1 = true; void Local1( [Test(p = b1)] [Test(p = b2)] int p1) { } Local1(1); } } class b1 {} class Test : System.Attribute { public bool p {get; set;} } "; var compilation = CreateCompilationWithMscorlib461(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular9); compilation.VerifyDiagnostics( // (10,23): error CS0103: The name 'b2' does not exist in the current context // [Test(p = b2)] Diagnostic(ErrorCode.ERR_NameNotInContext, "b2").WithArguments("b2").WithLocation(10, 23) ); var tree = compilation.SyntaxTrees.Single(); var model = compilation.GetSemanticModel(tree); var b2 = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(id => id.Identifier.ValueText == "b2").Single(); Assert.Null(model.GetSymbolInfo(b2).Symbol); var b1 = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(id => id.Identifier.ValueText == "b1").Single(); var b1Symbol = model.GetSymbolInfo(b1).Symbol; Assert.Equal("System.Boolean b1", b1Symbol.ToTestDisplayString()); Assert.Equal(SymbolKind.Local, b1Symbol.Kind); } [Fact] [WorkItem(19778, "https://github.com/dotnet/roslyn/issues/19778")] public void BindDynamicInvocation() { var source = @"using System; class C { static void M() { dynamic L<T>(Func<dynamic, T> t, object p) => p; L(m => L(d => d, null), null); L(m => L(d => d, m), null); } }"; var comp = CreateCompilationWithMscorlib461(source, references: new[] { SystemCoreRef, CSharpRef }); comp.VerifyEmitDiagnostics( // (8,18): error CS1977: Cannot use a lambda expression as an argument to a dynamically dispatched operation without first casting it to a delegate or expression tree type. // L(m => L(d => d, m), null); Diagnostic(ErrorCode.ERR_BadDynamicMethodArgLambda, "d => d").WithLocation(8, 18), // (8,16): error CS8322: Cannot pass argument with dynamic type to generic local function 'L' with inferred type arguments. // L(m => L(d => d, m), null); Diagnostic(ErrorCode.ERR_DynamicLocalFunctionTypeParameter, "L(d => d, m)").WithArguments("L").WithLocation(8, 16)); } [Fact] [WorkItem(19778, "https://github.com/dotnet/roslyn/issues/19778")] public void BindDynamicInvocation_Async() { var source = @"using System; using System.Threading.Tasks; class C { static void M() { async Task<dynamic> L<T>(Func<dynamic, T> t, object p) => await L(async m => L(async d => await d, m), p); } }"; var comp = CreateCompilationWithMscorlib461(source, references: new[] { SystemCoreRef, CSharpRef }); comp.VerifyEmitDiagnostics( // (8,37): error CS1977: Cannot use a lambda expression as an argument to a dynamically dispatched operation without first casting it to a delegate or expression tree type. // => await L(async m => L(async d => await d, m), p); Diagnostic(ErrorCode.ERR_BadDynamicMethodArgLambda, "async d => await d").WithLocation(8, 37), // (8,35): error CS8322: Cannot pass argument with dynamic type to generic local function 'L' with inferred type arguments. // => await L(async m => L(async d => await d, m), p); Diagnostic(ErrorCode.ERR_DynamicLocalFunctionTypeParameter, "L(async d => await d, m)").WithArguments("L").WithLocation(8, 35) ); } [Fact] [WorkItem(21317, "https://github.com/dotnet/roslyn/issues/21317")] [CompilerTrait(CompilerFeature.Dynamic)] public void DynamicGenericArg() { var src = @" using System.Collections.Generic; class C { static void M() { dynamic val = 2; dynamic dynamicList = new List<int>(); void L1<T>(T x) { } L1(val); void L2<T>(int x, T y) { } L2(1, val); L2(val, 3.0f); void L3<T>(List<T> x) { } L3(dynamicList); void L4<T>(int x, params T[] y) { } L4(1, 2, val); L4(val, 3, 4); void L5<T>(T x, params int[] y) { } L5(val, 1, 2); L5(1, 3, val); } } "; VerifyDiagnostics(src, // (11,9): error CS8322: Cannot pass argument with dynamic type to generic local function 'L1'. Try specifying the type arguments explicitly. // L1(val); Diagnostic(ErrorCode.ERR_DynamicLocalFunctionTypeParameter, "L1(val)").WithArguments("L1").WithLocation(11, 9), // (14,9): error CS8322: Cannot pass argument with dynamic type to generic local function 'L2'. Try specifying the type arguments explicitly. // L2(1, val); Diagnostic(ErrorCode.ERR_DynamicLocalFunctionTypeParameter, "L2(1, val)").WithArguments("L2").WithLocation(14, 9), // (15,9): error CS8322: Cannot pass argument with dynamic type to generic local function 'L2'. Try specifying the type arguments explicitly. // L2(val, 3.0f); Diagnostic(ErrorCode.ERR_DynamicLocalFunctionTypeParameter, "L2(val, 3.0f)").WithArguments("L2").WithLocation(15, 9), // (18,9): error CS8322: Cannot pass argument with dynamic type to generic local function 'L3'. Try specifying the type arguments explicitly. // L3(dynamicList); Diagnostic(ErrorCode.ERR_DynamicLocalFunctionTypeParameter, "L3(dynamicList)").WithArguments("L3").WithLocation(18, 9), // (21,9): error CS8322: Cannot pass argument with dynamic type to generic local function 'L4'. Try specifying the type arguments explicitly. // L4(1, 2, val); Diagnostic(ErrorCode.ERR_DynamicLocalFunctionTypeParameter, "L4(1, 2, val)").WithArguments("L4").WithLocation(21, 9), // (22,9): error CS8322: Cannot pass argument with dynamic type to generic local function 'L4'. Try specifying the type arguments explicitly. // L4(val, 3, 4); Diagnostic(ErrorCode.ERR_DynamicLocalFunctionTypeParameter, "L4(val, 3, 4)").WithArguments("L4").WithLocation(22, 9), // (25,9): error CS8322: Cannot pass argument with dynamic type to generic local function 'L5'. Try specifying the type arguments explicitly. // L5(val, 1, 2); Diagnostic(ErrorCode.ERR_DynamicLocalFunctionTypeParameter, "L5(val, 1, 2)").WithArguments("L5").WithLocation(25, 9), // (26,9): error CS8322: Cannot pass argument with dynamic type to generic local function 'L5'. Try specifying the type arguments explicitly. // L5(1, 3, val); Diagnostic(ErrorCode.ERR_DynamicLocalFunctionTypeParameter, "L5(1, 3, val)").WithArguments("L5").WithLocation(26, 9) ); } [Fact] [WorkItem(23699, "https://github.com/dotnet/roslyn/issues/23699")] public void GetDeclaredSymbolOnTypeParameter() { var src = @" class C<T> { void M<U>() { void LocalFunction<T, U, V>(T p1, U p2, V p3) { } } } "; var comp = CreateCompilation(src); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var localDecl = (LocalFunctionStatementSyntax)tree.FindNodeOrTokenByKind(SyntaxKind.LocalFunctionStatement).AsNode(); var typeParameters = localDecl.TypeParameterList.Parameters; var parameters = localDecl.ParameterList.Parameters; verifyTypeParameterAndParameter(typeParameters[0], parameters[0], "T"); verifyTypeParameterAndParameter(typeParameters[1], parameters[1], "U"); verifyTypeParameterAndParameter(typeParameters[2], parameters[2], "V"); void verifyTypeParameterAndParameter(TypeParameterSyntax typeParameter, ParameterSyntax parameter, string expected) { var symbol = model.GetDeclaredSymbol(typeParameter); Assert.Equal(expected, symbol.ToTestDisplayString()); var parameterSymbol = model.GetDeclaredSymbol(parameter); Assert.Equal(expected, parameterSymbol.Type.ToTestDisplayString()); Assert.Same(symbol, parameterSymbol.Type); } } public sealed class ScriptGlobals { public int SomeGlobal => 42; } [ConditionalFact(typeof(DesktopOnly), Reason = "https://github.com/dotnet/roslyn/issues/28001")] public void CanAccessScriptGlobalsFromInsideMethod() { var source = @" void Method() { LocalFunction(); void LocalFunction() { _ = SomeGlobal; } }"; CreateSubmission(source, new[] { ScriptTestFixtures.HostRef }, hostObjectType: typeof(ScriptGlobals)) .VerifyEmitDiagnostics(); } [ConditionalFact(typeof(DesktopOnly), Reason = "https://github.com/dotnet/roslyn/issues/28001")] public void CanAccessScriptGlobalsFromInsideLambda() { var source = @" var lambda = new System.Action(() => { LocalFunction(); void LocalFunction() { _ = SomeGlobal; } });"; CreateSubmission(source, new[] { ScriptTestFixtures.HostRef }, hostObjectType: typeof(ScriptGlobals)) .VerifyEmitDiagnostics(); } [Fact] public void CanAccessPreviousSubmissionVariablesFromInsideMethod() { var previous = CreateSubmission("int previousSubmissionVariable = 42;") .VerifyEmitDiagnostics(); var source = @" void Method() { LocalFunction(); void LocalFunction() { _ = previousSubmissionVariable; } }"; CreateSubmission(source, previous: previous) .VerifyEmitDiagnostics(); } [Fact] public void CanAccessPreviousSubmissionVariablesFromInsideLambda() { var previous = CreateSubmission("int previousSubmissionVariable = 42;") .VerifyEmitDiagnostics(); var source = @" var lambda = new System.Action(() => { LocalFunction(); void LocalFunction() { _ = previousSubmissionVariable; } });"; CreateSubmission(source, previous: previous) .VerifyEmitDiagnostics(); } [Fact] public void CanAccessPreviousSubmissionMethodsFromInsideMethod() { var previous = CreateSubmission("void PreviousSubmissionMethod() { }") .VerifyEmitDiagnostics(); var source = @" void Method() { LocalFunction(); void LocalFunction() { PreviousSubmissionMethod(); } }"; CreateSubmission(source, previous: previous) .VerifyEmitDiagnostics(); } [Fact] public void CanAccessPreviousSubmissionMethodsFromInsideLambda() { var previous = CreateSubmission("void PreviousSubmissionMethod() { }") .VerifyEmitDiagnostics(); var source = @" var lambda = new System.Action(() => { LocalFunction(); void LocalFunction() { PreviousSubmissionMethod(); } });"; CreateSubmission(source, previous: previous) .VerifyEmitDiagnostics(); } [Fact] public void ShadowNames_01() { var source = @"#pragma warning disable 0219 #pragma warning disable 8321 class Program { static void M() { void F1(object x) { string x = null; } // local void F2(object x, string y, int x) { } // parameter void F3(object x) { void x() { } } // method void F4<@x, @y>(object x) { void y() { } } // type parameter void F5(object M, string Program) { } } }"; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular7_3); verifyDiagnostics(); comp = CreateCompilation(source, parseOptions: TestOptions.Regular8); verifyDiagnostics(); comp = CreateCompilation(source); verifyDiagnostics(); void verifyDiagnostics() { comp.VerifyDiagnostics( // (7,36): error CS0136: A local or parameter named 'x' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter // void F1(object x) { string x = null; } // local Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "x").WithArguments("x").WithLocation(7, 36), // (8,41): error CS0100: The parameter name 'x' is a duplicate // void F2(object x, string y, int x) { } // parameter Diagnostic(ErrorCode.ERR_DuplicateParamName, "x").WithArguments("x").WithLocation(8, 41), // (9,34): error CS0136: A local or parameter named 'x' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter // void F3(object x) { void x() { } } // method Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "x").WithArguments("x").WithLocation(9, 34), // (10,32): error CS0412: 'x': a parameter, local variable, or local function cannot have the same name as a method type parameter // void F4<@x, @y>(object x) { void y() { } } // type parameter Diagnostic(ErrorCode.ERR_LocalSameNameAsTypeParam, "x").WithArguments("x").WithLocation(10, 32), // (10,42): error CS0412: 'y': a parameter, local variable, or local function cannot have the same name as a method type parameter // void F4<@x, @y>(object x) { void y() { } } // type parameter Diagnostic(ErrorCode.ERR_LocalSameNameAsTypeParam, "y").WithArguments("y").WithLocation(10, 42)); } } [Fact] public void ShadowNames_Local_01() { var source = @"#pragma warning disable 0219 #pragma warning disable 8321 using System.Linq; class Program { static void M() { object x = null; void F1() { object x = 0; } // local void F2(string x) { } // parameter void F3() { void x() { } } // method void F4<@x>() { } // type parameter void F5() { _ = from x in new[] { 1, 2, 3 } select x; } // range variable } }"; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular7_3); comp.VerifyDiagnostics( // (9,28): error CS0136: A local or parameter named 'x' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter // void F1() { object x = 0; } // local Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "x").WithArguments("x").WithLocation(9, 28), // (10,24): error CS0136: A local or parameter named 'x' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter // void F2(string x) { } // parameter Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "x").WithArguments("x").WithLocation(10, 24), // (11,26): error CS0136: A local or parameter named 'x' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter // void F3() { void x() { } } // method Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "x").WithArguments("x").WithLocation(11, 26), // (12,17): error CS0136: A local or parameter named 'x' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter // void F4<@x>() { } // type parameter Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "@x").WithArguments("x").WithLocation(12, 17), // (13,30): error CS1931: The range variable 'x' conflicts with a previous declaration of 'x' // void F5() { _ = from x in new[] { 1, 2, 3 } select x; } // range variable Diagnostic(ErrorCode.ERR_QueryRangeVariableOverrides, "x").WithArguments("x").WithLocation(13, 30)); comp = CreateCompilation(source, parseOptions: TestOptions.Regular8); comp.VerifyDiagnostics(); comp = CreateCompilation(source); comp.VerifyDiagnostics(); } [Fact] public void ShadowNames_Local_02() { var source = @"#pragma warning disable 0219 #pragma warning disable 8321 using System.Linq; class Program { static void M() { void F1() { object x = 0; } // local void F2(string x) { } // parameter void F3() { void x() { } } // method void F4<@x>() { } // type parameter void F5() { _ = from x in new[] { 1, 2, 3 } select x; } // range variable object x = null; } }"; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular7_3); comp.VerifyDiagnostics( // (8,28): error CS0136: A local or parameter named 'x' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter // void F1() { object x = 0; } // local Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "x").WithArguments("x").WithLocation(8, 28), // (9,24): error CS0136: A local or parameter named 'x' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter // void F2(string x) { } // parameter Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "x").WithArguments("x").WithLocation(9, 24), // (10,26): error CS0136: A local or parameter named 'x' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter // void F3() { void x() { } } // method Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "x").WithArguments("x").WithLocation(10, 26), // (11,17): error CS0136: A local or parameter named 'x' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter // void F4<@x>() { } // type parameter Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "@x").WithArguments("x").WithLocation(11, 17), // (12,30): error CS1931: The range variable 'x' conflicts with a previous declaration of 'x' // void F5() { _ = from x in new[] { 1, 2, 3 } select x; } // range variable Diagnostic(ErrorCode.ERR_QueryRangeVariableOverrides, "x").WithArguments("x").WithLocation(12, 30)); comp = CreateCompilation(source); comp.VerifyDiagnostics(); } [Fact] public void ShadowNames_Local_03() { var source = @"#pragma warning disable 0219 #pragma warning disable 8321 using System.Linq; class Program { static void M() { static void F1() { object x = 0; } // local static void F2(string x) { } // parameter static void F3() { void x() { } } // method static void F4<@x>() { } // type parameter static void F5() { _ = from x in new[] { 1, 2, 3 } select x; } // range variable object x = null; } }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics(); } [Fact] public void ShadowNames_Parameter() { var source = @"#pragma warning disable 0219 #pragma warning disable 8321 using System.Linq; class Program { static void M(object x) { void F1() { object x = 0; } // local void F2(string x) { } // parameter void F3() { void x() { } } // method void F4<@x>() { } // type parameter void F5() { _ = from x in new[] { 1, 2, 3 } select x; } // range variable } }"; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular7_3); // The conflict between the type parameter in F4<x>() and the parameter // in M(object x) is not reported, for backwards compatibility. comp.VerifyDiagnostics( // (8,28): error CS0136: A local or parameter named 'x' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter // void F1() { object x = 0; } // local Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "x").WithArguments("x").WithLocation(8, 28), // (9,24): error CS0136: A local or parameter named 'x' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter // void F2(string x) { } // parameter Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "x").WithArguments("x").WithLocation(9, 24), // (10,26): error CS0136: A local or parameter named 'x' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter // void F3() { void x() { } } // method Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "x").WithArguments("x").WithLocation(10, 26), // (12,30): error CS1931: The range variable 'x' conflicts with a previous declaration of 'x' // void F5() { _ = from x in new[] { 1, 2, 3 } select x; } // range variable Diagnostic(ErrorCode.ERR_QueryRangeVariableOverrides, "x").WithArguments("x").WithLocation(12, 30)); comp = CreateCompilation(source); comp.VerifyDiagnostics(); } [Fact] public void ShadowNames_TypeParameter() { var source = @"#pragma warning disable 0219 #pragma warning disable 8321 using System.Linq; class Program { static void M<@x>() { void F1() { object x = 0; } // local void F2(string x) { } // parameter void F3() { void x() { } } // method void F4<@x>() { } // type parameter void F5() { _ = from x in new[] { 1, 2, 3 } select x; } // range variable } }"; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular7_3); comp.VerifyDiagnostics( // (8,28): error CS0412: 'x': a parameter, local variable, or local function cannot have the same name as a method type parameter // void F1() { object x = 0; } // local Diagnostic(ErrorCode.ERR_LocalSameNameAsTypeParam, "x").WithArguments("x").WithLocation(8, 28), // (9,24): error CS0412: 'x': a parameter, local variable, or local function cannot have the same name as a method type parameter // void F2(string x) { } // parameter Diagnostic(ErrorCode.ERR_LocalSameNameAsTypeParam, "x").WithArguments("x").WithLocation(9, 24), // (10,26): error CS0412: 'x': a parameter, local variable, or local function cannot have the same name as a method type parameter // void F3() { void x() { } } // method Diagnostic(ErrorCode.ERR_LocalSameNameAsTypeParam, "x").WithArguments("x").WithLocation(10, 26), // (11,17): warning CS8387: Type parameter 'x' has the same name as the type parameter from outer method 'Program.M<x>()' // void F4<@x>() { } // type parameter Diagnostic(ErrorCode.WRN_TypeParameterSameAsOuterMethodTypeParameter, "@x").WithArguments("x", "Program.M<x>()").WithLocation(11, 17), // (12,30): error CS1948: The range variable 'x' cannot have the same name as a method type parameter // void F5() { _ = from x in new[] { 1, 2, 3 } select x; } // range variable Diagnostic(ErrorCode.ERR_QueryRangeVariableSameAsTypeParam, "x").WithArguments("x").WithLocation(12, 30)); comp = CreateCompilation(source); comp.VerifyDiagnostics( // (11,17): warning CS8387: Type parameter 'x' has the same name as the type parameter from outer method 'Program.M<x>()' // void F4<@x>() { } // type parameter Diagnostic(ErrorCode.WRN_TypeParameterSameAsOuterMethodTypeParameter, "@x").WithArguments("x", "Program.M<x>()").WithLocation(11, 17)); } [Fact] public void ShadowNames_LocalFunction_01() { var source = @"#pragma warning disable 0219 #pragma warning disable 8321 using System.Linq; class Program { static void M() { void x() { } void F1() { object x = 0; } // local void F2(string x) { } // parameter void F3() { void x() { } } // method void F4<@x>() { } // type parameter void F5() { _ = from x in new[] { 1, 2, 3 } select x; } // range variable } }"; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular7_3); comp.VerifyDiagnostics( // (9,28): error CS0136: A local or parameter named 'x' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter // void F1() { object x = 0; } // local Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "x").WithArguments("x").WithLocation(9, 28), // (10,24): error CS0136: A local or parameter named 'x' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter // void F2(string x) { } // parameter Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "x").WithArguments("x").WithLocation(10, 24), // (11,26): error CS0136: A local or parameter named 'x' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter // void F3() { void x() { } } // method Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "x").WithArguments("x").WithLocation(11, 26), // (12,17): error CS0136: A local or parameter named 'x' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter // void F4<@x>() { } // type parameter Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "@x").WithArguments("x").WithLocation(12, 17), // (13,30): error CS1931: The range variable 'x' conflicts with a previous declaration of 'x' // void F5() { _ = from x in new[] { 1, 2, 3 } select x; } // range variable Diagnostic(ErrorCode.ERR_QueryRangeVariableOverrides, "x").WithArguments("x").WithLocation(13, 30)); comp = CreateCompilation(source); comp.VerifyDiagnostics(); } [Fact] public void ShadowNames_LocalFunction_02() { var source = @"#pragma warning disable 0219 #pragma warning disable 8321 class Program { static void M1() { void M1() { } } static void M2(object x) { void x() { } } static void M3() { object x = null; void x() { } } static void M4<T>() { void T() { } } }"; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular7_3); verifyDiagnostics(); comp = CreateCompilation(source); verifyDiagnostics(); void verifyDiagnostics() { comp.VerifyDiagnostics( // (11,14): error CS0136: A local or parameter named 'x' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter // void x() { } Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "x").WithArguments("x").WithLocation(11, 14), // (16,14): error CS0128: A local variable or function named 'x' is already defined in this scope // void x() { } Diagnostic(ErrorCode.ERR_LocalDuplicate, "x").WithArguments("x").WithLocation(16, 14), // (20,14): error CS0412: 'T': a parameter, local variable, or local function cannot have the same name as a method type parameter // void T() { } Diagnostic(ErrorCode.ERR_LocalSameNameAsTypeParam, "T").WithArguments("T").WithLocation(20, 14)); } } [Fact] public void ShadowNames_ThisLocalFunction() { var source = @"#pragma warning disable 0219 #pragma warning disable 8321 using System.Linq; class Program { static void M() { void F1() { object F1 = 0; } // local void F2(string F2) { } // parameter void F3() { void F3() { } } // method void F4<F4>() { } // type parameter void F5() { _ = from F5 in new[] { 1, 2, 3 } select F5; } // range variable } }"; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular7_3); comp.VerifyDiagnostics( // (8,28): error CS0136: A local or parameter named 'F1' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter // void F1() { object F1 = 0; } // local Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "F1").WithArguments("F1").WithLocation(8, 28), // (9,24): error CS0136: A local or parameter named 'F2' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter // void F2(string F2) { } // parameter Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "F2").WithArguments("F2").WithLocation(9, 24), // (10,26): error CS0136: A local or parameter named 'F3' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter // void F3() { void F3() { } } // method Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "F3").WithArguments("F3").WithLocation(10, 26), // (11,17): error CS0136: A local or parameter named 'F4' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter // void F4<F4>() { } // type parameter Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "F4").WithArguments("F4").WithLocation(11, 17), // (12,30): error CS1931: The range variable 'F5' conflicts with a previous declaration of 'F5' // void F5() { _ = from F5 in new[] { 1, 2, 3 } select F5; } // range variable Diagnostic(ErrorCode.ERR_QueryRangeVariableOverrides, "F5").WithArguments("F5").WithLocation(12, 30)); comp = CreateCompilation(source); comp.VerifyDiagnostics(); } [Fact] public void ShadowNames_LocalFunctionInsideLocalFunction_01() { var source = @"#pragma warning disable 0219 #pragma warning disable 8321 class Program { static void M<T>(object x) { void F() { void G1(int x) { } void G2() { int T = 0; } void G3<T>() { } } } }"; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular7_3); comp.VerifyDiagnostics( // (9,25): error CS0136: A local or parameter named 'x' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter // void G1(int x) { } Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "x").WithArguments("x").WithLocation(9, 25), // (10,29): error CS0412: 'T': a parameter, local variable, or local function cannot have the same name as a method type parameter // void G2() { int T = 0; } Diagnostic(ErrorCode.ERR_LocalSameNameAsTypeParam, "T").WithArguments("T").WithLocation(10, 29), // (11,21): warning CS8387: Type parameter 'T' has the same name as the type parameter from outer method 'Program.M<T>(object)' // void G3<T>() { } Diagnostic(ErrorCode.WRN_TypeParameterSameAsOuterMethodTypeParameter, "T").WithArguments("T", "Program.M<T>(object)").WithLocation(11, 21)); comp = CreateCompilation(source); comp.VerifyDiagnostics( // (11,21): warning CS8387: Type parameter 'T' has the same name as the type parameter from outer method 'Program.M<T>(object)' // void G3<T>() { } Diagnostic(ErrorCode.WRN_TypeParameterSameAsOuterMethodTypeParameter, "T").WithArguments("T", "Program.M<T>(object)").WithLocation(11, 21)); } [Fact] public void ShadowNames_LocalFunctionInsideLocalFunction_02() { var source = @"#pragma warning disable 0219 #pragma warning disable 8321 class Program { static void M<T>(object x) { static void F1() { void G1(int x) { } } void F2() { static void G2() { int T = 0; } } static void F3() { static void G3<T>() { } } } }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (17,28): warning CS8387: Type parameter 'T' has the same name as the type parameter from outer method 'Program.M<T>(object)' // static void G3<T>() { } Diagnostic(ErrorCode.WRN_TypeParameterSameAsOuterMethodTypeParameter, "T").WithArguments("T", "Program.M<T>(object)").WithLocation(17, 28)); } [Fact] public void ShadowNames_LocalFunctionInsideLambda_01() { var source = @"#pragma warning disable 0219 #pragma warning disable 8321 using System; class Program { static void M() { Action a1 = () => { int x = 0; void F1() { object x = null; } }; Action a2 = () => { int T = 0; void F2<T>() { } }; } }"; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular7_3); comp.VerifyDiagnostics( // (11,32): error CS0136: A local or parameter named 'x' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter // void F1() { object x = null; } Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "x").WithArguments("x").WithLocation(11, 32), // (16,21): error CS0136: A local or parameter named 'T' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter // void F2<T>() { } Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "T").WithArguments("T").WithLocation(16, 21)); comp = CreateCompilation(source); comp.VerifyDiagnostics(); } [Fact] public void ShadowNames_LocalFunctionInsideLambda_02() { var source = @"#pragma warning disable 0219 #pragma warning disable 8321 using System; class Program { static void M() { Action<int> a1 = x => { void F1(object x) { } }; Action<int> a2 = (int T) => { void F2<T>() { } }; } }"; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular7_3); // The conflict between the type parameter in F2<T>() and the parameter // in a2 is not reported, for backwards compatibility. comp.VerifyDiagnostics( // (10,28): error CS0136: A local or parameter named 'x' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter // void F1(object x) { } Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "x").WithArguments("x").WithLocation(10, 28)); comp = CreateCompilation(source); comp.VerifyDiagnostics(); } [Fact] public void ShadowNames_LocalFunctionInsideLambda_03() { var source = @"using System; class Program { static void M() { Action<int> a = x => { void x() { } x(); }; } }"; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular7_3); // The conflict between the local function and the parameter is not reported, // for backwards compatibility. comp.VerifyDiagnostics(); comp = CreateCompilation(source); comp.VerifyDiagnostics(); } [Fact] public void StaticWithThisReference() { var source = @"#pragma warning disable 8321 class C { void M() { static object F1() => this.GetHashCode(); static object F2() => base.GetHashCode(); static void F3() { object G3() => ToString(); } } }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (6,31): error CS8422: A static local function cannot contain a reference to 'this' or 'base'. // static object F1() => this.GetHashCode(); Diagnostic(ErrorCode.ERR_StaticLocalFunctionCannotCaptureThis, "this").WithLocation(6, 31), // (7,31): error CS8422: A static local function cannot contain a reference to 'this' or 'base'. // static object F2() => base.GetHashCode(); Diagnostic(ErrorCode.ERR_StaticLocalFunctionCannotCaptureThis, "base").WithLocation(7, 31), // (10,28): error CS8422: A static local function cannot contain a reference to 'this' or 'base'. // object G3() => ToString(); Diagnostic(ErrorCode.ERR_StaticLocalFunctionCannotCaptureThis, "ToString").WithLocation(10, 28)); } [Fact] public void StaticWithVariableReference() { var source = @"#pragma warning disable 8321 class C { static void M(object x) { object y = null; static object F1() => x; static object F2() => y; static void F3() { object G3() => x; } } }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (7,31): error CS8421: A static local function cannot contain a reference to 'x'. // static object F1() => x; Diagnostic(ErrorCode.ERR_StaticLocalFunctionCannotCaptureVariable, "x").WithArguments("x").WithLocation(7, 31), // (8,31): error CS8421: A static local function cannot contain a reference to 'y'. // static object F2() => y; Diagnostic(ErrorCode.ERR_StaticLocalFunctionCannotCaptureVariable, "y").WithArguments("y").WithLocation(8, 31), // (11,28): error CS8421: A static local function cannot contain a reference to 'x'. // object G3() => x; Diagnostic(ErrorCode.ERR_StaticLocalFunctionCannotCaptureVariable, "x").WithArguments("x").WithLocation(11, 28)); } [Fact] public void StaticWithLocalFunctionVariableReference_01() { var source = @"#pragma warning disable 8321 class C { static void M() { static void F(object x) { object y = null; object G1() => x ?? y; static object G2() => x ?? y; } } }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (10,35): error CS8421: A static local function cannot contain a reference to 'x'. // static object G2() => x ?? y; Diagnostic(ErrorCode.ERR_StaticLocalFunctionCannotCaptureVariable, "x").WithArguments("x").WithLocation(10, 35), // (10,40): error CS8421: A static local function cannot contain a reference to 'y'. // static object G2() => x ?? y; Diagnostic(ErrorCode.ERR_StaticLocalFunctionCannotCaptureVariable, "y").WithArguments("y").WithLocation(10, 40)); } [Fact] public void StaticWithLocalFunctionVariableReference_02() { var source = @"#pragma warning disable 8321 class C { static void M(int x) { static void F1(int y) { int F2() => x + y; } } }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (8,25): error CS8421: A static local function cannot contain a reference to 'x'. // int F2() => x + y; Diagnostic(ErrorCode.ERR_StaticLocalFunctionCannotCaptureVariable, "x").WithArguments("x").WithLocation(8, 25)); } /// <summary> /// Can reference type parameters from enclosing scope. /// </summary> [Fact] public void StaticWithTypeParameterReferences() { var source = @"using static System.Console; class A<T> { internal string F1() { static string L1() => typeof(T).FullName; return L1(); } } class B { internal string F2<T>() { static string L2() => typeof(T).FullName; return L2(); } internal static string F3() { static string L3<T>() { static string L4() => typeof(T).FullName; return L4(); } return L3<byte>(); } } class Program { static void Main() { WriteLine(new A<int>().F1()); WriteLine(new B().F2<string>()); WriteLine(B.F3()); } }"; CompileAndVerify(source, expectedOutput: @"System.Int32 System.String System.Byte"); } [Fact] public void Conditional_ThisReferenceInStatic() { var source = @"#pragma warning disable 0649 #pragma warning disable 8321 using System.Diagnostics; class A { internal object _f; } class B : A { [Conditional(""MyDefine"")] static void F(object o) { } void M() { static void F1() { F(this); } static void F2() { F(base._f); } static void F3() { F(_f); } } }"; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular.WithPreprocessorSymbols("MyDefine")); verifyDiagnostics(); comp = CreateCompilation(source, parseOptions: TestOptions.Regular); verifyDiagnostics(); void verifyDiagnostics() { comp.VerifyDiagnostics( // (16,30): error CS8422: A static local function cannot contain a reference to 'this' or 'base'. // static void F1() { F(this); } Diagnostic(ErrorCode.ERR_StaticLocalFunctionCannotCaptureThis, "this").WithLocation(16, 30), // (17,30): error CS8422: A static local function cannot contain a reference to 'this' or 'base'. // static void F2() { F(base._f); } Diagnostic(ErrorCode.ERR_StaticLocalFunctionCannotCaptureThis, "base").WithLocation(17, 30), // (18,30): error CS8422: A static local function cannot contain a reference to 'this' or 'base'. // static void F3() { F(_f); } Diagnostic(ErrorCode.ERR_StaticLocalFunctionCannotCaptureThis, "_f").WithLocation(18, 30)); } } [Fact] public void LocalFunctionConditional_Errors() { var source = @" using System.Diagnostics; class C { void M() { #pragma warning disable 8321 // Unreferenced local function [Conditional(""DEBUG"")] // 1 int local1() => 42; [Conditional(""DEBUG"")] // 2 void local2(out int i) { i = 42; } } } "; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics( // (10,10): error CS0578: The Conditional attribute is not valid on 'local1()' because its return type is not void // [Conditional("DEBUG")] // 1 Diagnostic(ErrorCode.ERR_ConditionalMustReturnVoid, @"Conditional(""DEBUG"")").WithArguments("local1()").WithLocation(10, 10), // (13,10): error CS0685: Conditional member 'local2(out int)' cannot have an out parameter // [Conditional("DEBUG")] // 2 Diagnostic(ErrorCode.ERR_ConditionalWithOutParam, @"Conditional(""DEBUG"")").WithArguments("local2(out int)").WithLocation(13, 10)); } [Fact] public void LocalFunctionObsolete() { var source = @" using System; class C { void M1() { local1(); // 1 local2(); // 2 [Obsolete] void local1() { } [Obsolete(""hello"", true)] void local2() { } #pragma warning disable 8321 // Unreferenced local function [Obsolete] void local3() { // no diagnostics expected when calling an Obsolete method within an Obsolete method local1(); local2(); } } } "; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics( // (8,9): warning CS0612: 'local1()' is obsolete // local1(); // 1 Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "local1()").WithArguments("local1()").WithLocation(8, 9), // (9,9): error CS0619: 'local2()' is obsolete: 'hello' // local2(); // 2 Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "local2()").WithArguments("local2()", "hello").WithLocation(9, 9)); } [Fact] public void LocalFunction_AttributeMarkedObsolete() { var source = @" using System; [Obsolete] class Attr : Attribute { } class C { void M1() { #pragma warning disable 8321 [Attr] void local1() { } // 1 [return: Attr] void local2() { } // 2 void local3([Attr] int i) { } // 3 void local4<[Attr] T>(T t) { } // 4 } } "; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics( // (12,10): warning CS0612: 'Attr' is obsolete // [Attr] void local1() { } // 1 Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "Attr").WithArguments("Attr").WithLocation(12, 10), // (13,18): warning CS0612: 'Attr' is obsolete // [return: Attr] void local2() { } // 2 Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "Attr").WithArguments("Attr").WithLocation(13, 18), // (14,22): warning CS0612: 'Attr' is obsolete // void local3([Attr] int i) { } // 3 Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "Attr").WithArguments("Attr").WithLocation(14, 22), // (15,22): warning CS0612: 'Attr' is obsolete // void local4<[Attr] T>(T t) { } // 4 Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "Attr").WithArguments("Attr").WithLocation(15, 22)); } [Fact] public void LocalFunction_NotNullIfNotNullAttribute() { var source = @" using System.Diagnostics.CodeAnalysis; #nullable enable class C { void M() { _ = local1(null).ToString(); // 1 _ = local1(""hello"").ToString(); [return: NotNullIfNotNull(""s1"")] string? local1(string? s1) => s1; } } "; var comp = CreateCompilation(new[] { NotNullIfNotNullAttributeDefinition, source }, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics( // (10,13): warning CS8602: Dereference of a possibly null reference. // _ = local1(null).ToString(); // 1 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "local1(null)").WithLocation(10, 13)); } [Fact] public void LocalFunction_MaybeNullWhenAttribute() { var source = @" #nullable enable using System.Diagnostics.CodeAnalysis; class C { void M() { _ = tryGetValue(true, out var s) ? s.ToString() : s.ToString(); // 1 bool tryGetValue(bool b, [MaybeNullWhen(false)] out string s1) { s1 = b ? ""abc"" : null; return b; } } } "; var comp = CreateCompilation(new[] { MaybeNullWhenAttributeDefinition, source }, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics( // (12,15): warning CS8602: Dereference of a possibly null reference. // : s.ToString(); // 1 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s").WithLocation(12, 15)); } [Fact] public void LocalFunction_MaybeNullWhenAttribute_CheckUsage() { var source = @" #nullable enable using System.Diagnostics.CodeAnalysis; class C { void M() { var s = ""abc""; local1(); tryGetValue(""a"", out s); local1(); void local1() { _ = s.ToString(); // 1 } bool tryGetValue(string key, [MaybeNullWhen(false)] out string s1) { s1 = key; return true; } } } "; var comp = CreateCompilation(new[] { MaybeNullWhenAttributeDefinition, source }, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics( // (18,17): warning CS8602: Dereference of a possibly null reference. // _ = s.ToString(); // 1 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s").WithLocation(18, 17)); } [Fact] public void LocalFunction_AllowNullAttribute() { var source = @" #nullable enable using System.Diagnostics.CodeAnalysis; class C { void M<T>([AllowNull] T t1, T t2) { local1(t1); local1(t2); local2(t1); // 1 local2(t2); void local1([AllowNull] T t) { } void local2(T t) { } } } "; var comp = CreateCompilation(new[] { AllowNullAttributeDefinition, source }, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics( // (13,16): warning CS8604: Possible null reference argument for parameter 't' in 'void local2(T t)'. // local2(t1); // 1 Diagnostic(ErrorCode.WRN_NullReferenceArgument, "t1").WithArguments("t", "void local2(T t)").WithLocation(13, 16)); } [Fact] public void LocalFunction_MaybeNullAttribute() { var source = @" #nullable enable using System.Diagnostics.CodeAnalysis; class C { void M<TOuter>() { getDefault<string>().ToString(); // 1 getDefault<string?>().ToString(); // 2 getDefault<int>().ToString(); getDefault<int?>().Value.ToString(); // 3 getDefault<TOuter>().ToString(); // 4 [return: MaybeNull] T getDefault<T>() => default(T); } } "; var comp = CreateCompilation(new[] { MaybeNullAttributeDefinition, source }, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics( // (10,9): warning CS8602: Dereference of a possibly null reference. // getDefault<string>().ToString(); // 1 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "getDefault<string>()").WithLocation(10, 9), // (11,9): warning CS8602: Dereference of a possibly null reference. // getDefault<string?>().ToString(); // 2 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "getDefault<string?>()").WithLocation(11, 9), // (13,9): warning CS8629: Nullable value type may be null. // getDefault<int?>().Value.ToString(); // 3 Diagnostic(ErrorCode.WRN_NullableValueTypeMayBeNull, "getDefault<int?>()").WithLocation(13, 9), // (14,9): warning CS8602: Dereference of a possibly null reference. // getDefault<TOuter>().ToString(); // 4 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "getDefault<TOuter>()").WithLocation(14, 9)); } [Fact] public void LocalFunction_Nullable_CheckUsage_DoesNotUsePostconditions() { var source = @" #nullable enable using System.Diagnostics.CodeAnalysis; class C { void M() { var s0 = ""hello""; local1(out s0); bool local1([MaybeNullWhen(false)] out string s1) { s0.ToString(); s1 = ""world""; return true; } } } "; var comp = CreateCompilation(new[] { MaybeNullWhenAttributeDefinition, source }, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics(); } [Fact] public void LocalFunction_DoesNotReturn() { var source = @" #nullable enable using System.Diagnostics.CodeAnalysis; class C { void M(string? s) { local1(); s.ToString(); [DoesNotReturn] void local1() { throw null!; } } } "; var comp = CreateCompilation(new[] { DoesNotReturnAttributeDefinition, source }, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics(); } [Fact] public void LocalFunction_DoesNotReturnIf() { var source = @" #nullable enable using System.Diagnostics.CodeAnalysis; class C { void M(string? s1, string? s2) { local1(s1 != null); s1.ToString(); local1(false); s2.ToString(); void local1([DoesNotReturnIf(false)] bool b) { throw null!; } } } "; var comp = CreateCompilation(new[] { DoesNotReturnIfAttributeDefinition, source }, parseOptions: TestOptions.Regular9); comp.VerifyDiagnostics(); } [Fact] public void NameOf_ThisReferenceInStatic() { var source = @"#pragma warning disable 8321 class C { void M() { static object F1() => nameof(this.ToString); static object F2() => nameof(base.GetHashCode); static object F3() => nameof(M); } }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics(); } [Fact] public void NameOf_InstanceMemberInStatic() { var source = @"#pragma warning disable 0649 #pragma warning disable 8321 class C { object _f; static void M() { _ = nameof(_f); static object F() => nameof(_f); } }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics(); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var expr = GetNameOfExpressions(tree)[1]; var symbol = model.GetSymbolInfo(expr).Symbol; Assert.Equal("System.Object C._f", symbol.ToTestDisplayString()); } [Fact] public void NameOf_CapturedVariableInStatic() { var source = @"#pragma warning disable 8321 class C { static void M(object x) { static object F() => nameof(x); } }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics(); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var expr = GetNameOfExpressions(tree)[0]; var symbol = model.GetSymbolInfo(expr).Symbol; Assert.Equal("System.Object x", symbol.ToTestDisplayString()); } /// <summary> /// nameof(x) should bind to shadowing symbol. /// </summary> [Fact] public void NameOf_ShadowedVariable() { var source = @"#pragma warning disable 8321 class C { static void M(object x) { object F() { int x = 0; return nameof(x); } } }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics(); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var expr = GetNameOfExpressions(tree)[0]; var symbol = model.GetSymbolInfo(expr).Symbol; Assert.Equal(SymbolKind.Local, symbol.Kind); Assert.Equal("System.Int32 x", symbol.ToTestDisplayString()); } /// <summary> /// nameof(T) should bind to shadowing symbol. /// </summary> [Fact] public void NameOf_ShadowedTypeParameter() { var source = @"#pragma warning disable 8321 class C { static void M<T>() { object F1() { int T = 0; return nameof(T); } object F2<T>() { return nameof(T); } } }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (11,19): warning CS8387: Type parameter 'T' has the same name as the type parameter from outer method 'C.M<T>()' // object F2<T>() Diagnostic(ErrorCode.WRN_TypeParameterSameAsOuterMethodTypeParameter, "T").WithArguments("T", "C.M<T>()").WithLocation(11, 19)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var exprs = GetNameOfExpressions(tree); var symbol = model.GetSymbolInfo(exprs[0]).Symbol; Assert.Equal(SymbolKind.Local, symbol.Kind); Assert.Equal("System.Int32 T", symbol.ToTestDisplayString()); symbol = model.GetSymbolInfo(exprs[1]).Symbol; Assert.Equal(SymbolKind.TypeParameter, symbol.Kind); Assert.Equal("System.Object F2<T>()", symbol.ContainingSymbol.ToTestDisplayString()); } /// <summary> /// typeof(T) should bind to nearest type. /// </summary> [Fact] public void TypeOf_ShadowedTypeParameter() { var source = @"#pragma warning disable 0219 #pragma warning disable 8321 class C { static void M<T>() { object F1() { int T = 0; return typeof(T); } object F2<T>() { return typeof(T); } object F3<U>() { return typeof(U); } } }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (12,19): warning CS8387: Type parameter 'T' has the same name as the type parameter from outer method 'C.M<T>()' // object F2<T>() Diagnostic(ErrorCode.WRN_TypeParameterSameAsOuterMethodTypeParameter, "T").WithArguments("T", "C.M<T>()").WithLocation(12, 19)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var exprs = tree.GetRoot().DescendantNodes().OfType<TypeOfExpressionSyntax>().Select(n => n.Type).ToImmutableArray(); var symbol = model.GetSymbolInfo(exprs[0]).Symbol; Assert.Equal(SymbolKind.TypeParameter, symbol.Kind); Assert.Equal("void C.M<T>()", symbol.ContainingSymbol.ToTestDisplayString()); symbol = model.GetSymbolInfo(exprs[1]).Symbol; Assert.Equal(SymbolKind.TypeParameter, symbol.Kind); Assert.Equal("System.Object F2<T>()", symbol.ContainingSymbol.ToTestDisplayString()); symbol = model.GetSymbolInfo(exprs[2]).Symbol; Assert.Equal(SymbolKind.TypeParameter, symbol.Kind); Assert.Equal("System.Object F3<U>()", symbol.ContainingSymbol.ToTestDisplayString()); } /// <summary> /// sizeof(T) should bind to nearest type. /// </summary> [Fact] public void SizeOf_ShadowedTypeParameter() { var source = @"#pragma warning disable 0219 #pragma warning disable 8321 unsafe class C { static void M<T>() where T : unmanaged { object F1() { int T = 0; return sizeof(T); } object F2<T>() where T : unmanaged { return sizeof(T); } object F3<U>() where U : unmanaged { return sizeof(U); } } }"; var comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseDll); comp.VerifyDiagnostics( // (12,19): warning CS8387: Type parameter 'T' has the same name as the type parameter from outer method 'C.M<T>()' // object F2<T>() Diagnostic(ErrorCode.WRN_TypeParameterSameAsOuterMethodTypeParameter, "T").WithArguments("T", "C.M<T>()").WithLocation(12, 19)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var exprs = tree.GetRoot().DescendantNodes().OfType<SizeOfExpressionSyntax>().Select(n => n.Type).ToImmutableArray(); var symbol = model.GetSymbolInfo(exprs[0]).Symbol; Assert.Equal(SymbolKind.TypeParameter, symbol.Kind); Assert.Equal("void C.M<T>()", symbol.ContainingSymbol.ToTestDisplayString()); symbol = model.GetSymbolInfo(exprs[1]).Symbol; Assert.Equal(SymbolKind.TypeParameter, symbol.Kind); Assert.Equal("System.Object F2<T>()", symbol.ContainingSymbol.ToTestDisplayString()); symbol = model.GetSymbolInfo(exprs[2]).Symbol; Assert.Equal(SymbolKind.TypeParameter, symbol.Kind); Assert.Equal("System.Object F3<U>()", symbol.ContainingSymbol.ToTestDisplayString()); } private static ImmutableArray<ExpressionSyntax> GetNameOfExpressions(SyntaxTree tree) { return tree.GetRoot().DescendantNodes(). OfType<InvocationExpressionSyntax>(). Where(n => n.Expression.ToString() == "nameof"). Select(n => n.ArgumentList.Arguments[0].Expression). ToImmutableArray(); } [Fact] public void ShadowWithSelfReferencingLocal() { var source = @"using System; class Program { static void Main() { int x = 13; void Local() { int x = (x = 0) + 42; Console.WriteLine(x); } Local(); Console.WriteLine(x); } }"; CompileAndVerify(source, expectedOutput: @"42 13"); } [Fact, WorkItem(38129, "https://github.com/dotnet/roslyn/issues/38129")] public void StaticLocalFunctionLocalFunctionReference_01() { var source = @"#pragma warning disable 8321 class C { static void M() { void F1() {} static void F2() {} static void F3() { F1(); F2(); } } }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (11,13): error CS8421: A static local function cannot contain a reference to 'F1'. // F1(); Diagnostic(ErrorCode.ERR_StaticLocalFunctionCannotCaptureVariable, "F1()").WithArguments("F1").WithLocation(11, 13)); } [Fact, WorkItem(39706, "https://github.com/dotnet/roslyn/issues/39706")] public void StaticLocalFunctionLocalFunctionReference_02() { var source = @"#pragma warning disable 8321 class Program { static void Method() { void Local<T>() {} static void StaticLocal() { Local<int>(); } } }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (9,13): error CS8421: A static local function cannot contain a reference to 'Local'. // Local<int>(); Diagnostic(ErrorCode.ERR_StaticLocalFunctionCannotCaptureVariable, "Local<int>()").WithArguments("Local").WithLocation(9, 13)); } [Fact, WorkItem(39706, "https://github.com/dotnet/roslyn/issues/39706")] public void StaticLocalFunctionLocalFunctionReference_03() { var source = @"using System; class Program { static void Method() { int i = 0; void Local<T>() { i = 0; } Action a = () => i++; static void StaticLocal() { Local<int>(); } StaticLocal(); } }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (14,13): error CS8421: A static local function cannot contain a reference to 'Local'. // Local<int>(); Diagnostic(ErrorCode.ERR_StaticLocalFunctionCannotCaptureVariable, "Local<int>()").WithArguments("Local").WithLocation(14, 13)); } [Fact, WorkItem(38240, "https://github.com/dotnet/roslyn/issues/38240")] public void StaticLocalFunctionLocalFunctionDelegateReference_01() { var source = @"#pragma warning disable 8321 using System; class C { static void M() { void F1() {} static void F2() { Action a = F1; _ = new Action(F1); } } }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (11,24): error CS8421: A static local function cannot contain a reference to 'F1'. // Action a = F1; Diagnostic(ErrorCode.ERR_StaticLocalFunctionCannotCaptureVariable, "F1").WithArguments("F1").WithLocation(11, 24), // (12,28): error CS8421: A static local function cannot contain a reference to 'F1'. // _ = new Action(F1); Diagnostic(ErrorCode.ERR_StaticLocalFunctionCannotCaptureVariable, "F1").WithArguments("F1").WithLocation(12, 28)); } [Fact, WorkItem(39706, "https://github.com/dotnet/roslyn/issues/39706")] public void StaticLocalFunctionLocalFunctionDelegateReference_02() { var source = @"#pragma warning disable 8321 using System; class Program { static void Method() { void Local<T>() {} static void StaticLocal() { Action a; a = Local<int>; a = new Action(Local<string>); } } }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (11,17): error CS8421: A static local function cannot contain a reference to 'Local'. // a = Local<int>; Diagnostic(ErrorCode.ERR_StaticLocalFunctionCannotCaptureVariable, "Local<int>").WithArguments("Local").WithLocation(11, 17), // (12,28): error CS8421: A static local function cannot contain a reference to 'Local'. // a = new Action(Local<string>); Diagnostic(ErrorCode.ERR_StaticLocalFunctionCannotCaptureVariable, "Local<string>").WithArguments("Local").WithLocation(12, 28)); } [Fact, WorkItem(39706, "https://github.com/dotnet/roslyn/issues/39706")] public void StaticLocalFunctionLocalFunctionDelegateReference_03() { var source = @"using System; class Program { static void Method() { int i = 0; void Local<T>() { i = 0; } Action a = () => i++; a = StaticLocal(); static Action StaticLocal() { return Local<int>; } } }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (15,20): error CS8421: A static local function cannot contain a reference to 'Local'. // return Local<int>; Diagnostic(ErrorCode.ERR_StaticLocalFunctionCannotCaptureVariable, "Local<int>").WithArguments("Local").WithLocation(15, 20)); } [Fact] public void StaticLocalFunctionGenericStaticLocalFunction() { var source = @"using System; class Program { static void Main() { static void F1<T>() { Console.WriteLine(typeof(T)); } static void F2() { F1<int>(); Action a = F1<string>; a(); } F2(); } }"; CompileAndVerify(source, expectedOutput: @"System.Int32 System.String"); } [Fact, WorkItem(38240, "https://github.com/dotnet/roslyn/issues/38240")] public void StaticLocalFunctionStaticFunctionsDelegateReference() { var source = @"#pragma warning disable 8321 using System; class C { static void M() { static void F1() {} static void F2() { Action m = M; Action f1 = F1; _ = new Action(M); _ = new Action(F1); } } }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics(); } [Fact, WorkItem(38240, "https://github.com/dotnet/roslyn/issues/38240")] public void StaticLocalFunctionThisAndBaseDelegateReference() { var source = @"#pragma warning disable 8321 using System; class B { public virtual void M() {} } class C : B { public override void M() { static void F() { Action a1 = base.M; Action a2 = this.M; Action a3 = M; _ = new Action(base.M); _ = new Action(this.M); _ = new Action(M); } } }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (14,25): error CS8422: A static local function cannot contain a reference to 'this' or 'base'. // Action a1 = base.M; Diagnostic(ErrorCode.ERR_StaticLocalFunctionCannotCaptureThis, "base").WithLocation(14, 25), // (15,25): error CS8422: A static local function cannot contain a reference to 'this' or 'base'. // Action a2 = this.M; Diagnostic(ErrorCode.ERR_StaticLocalFunctionCannotCaptureThis, "this").WithLocation(15, 25), // (16,25): error CS8422: A static local function cannot contain a reference to 'this' or 'base'. // Action a3 = M; Diagnostic(ErrorCode.ERR_StaticLocalFunctionCannotCaptureThis, "M").WithLocation(16, 25), // (17,28): error CS8422: A static local function cannot contain a reference to 'this' or 'base'. // _ = new Action(base.M); Diagnostic(ErrorCode.ERR_StaticLocalFunctionCannotCaptureThis, "base").WithLocation(17, 28), // (18,28): error CS8422: A static local function cannot contain a reference to 'this' or 'base'. // _ = new Action(this.M); Diagnostic(ErrorCode.ERR_StaticLocalFunctionCannotCaptureThis, "this").WithLocation(18, 28), // (19,28): error CS8422: A static local function cannot contain a reference to 'this' or 'base'. // _ = new Action(M); Diagnostic(ErrorCode.ERR_StaticLocalFunctionCannotCaptureThis, "M").WithLocation(19, 28)); } [Fact, WorkItem(38240, "https://github.com/dotnet/roslyn/issues/38240")] public void StaticLocalFunctionDelegateReferenceWithReceiver() { var source = @"#pragma warning disable 649 #pragma warning disable 8321 using System; class C { object f; void M() { object l; static void F1() { _ = new Func<int>(f.GetHashCode); _ = new Func<int>(l.GetHashCode); } } }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (14,31): error CS8422: A static local function cannot contain a reference to 'this' or 'base'. // _ = new Func<int>(f.GetHashCode); Diagnostic(ErrorCode.ERR_StaticLocalFunctionCannotCaptureThis, "f").WithLocation(14, 31), // (15,31): error CS8421: A static local function cannot contain a reference to 'l'. // _ = new Func<int>(l.GetHashCode); Diagnostic(ErrorCode.ERR_StaticLocalFunctionCannotCaptureVariable, "l").WithArguments("l").WithLocation(15, 31)); } [Fact] [WorkItem(38143, "https://github.com/dotnet/roslyn/issues/38143")] public void EmittedAsStatic_01() { var source = @"class Program { static void M() { static void local() { } System.Action action = local; } }"; CompileAndVerify(source, options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All), symbolValidator: m => { var method = (MethodSymbol)m.GlobalNamespace.GetMember("Program.<M>g__local|0_0"); Assert.True(method.IsStatic); }); } [Fact] [WorkItem(38143, "https://github.com/dotnet/roslyn/issues/38143")] public void EmittedAsStatic_02() { var source = @"class Program { static void M<T>() { static void local(T t) { System.Console.Write(t.GetType().FullName); } System.Action<T> action = local; action(default(T)); } static void Main() { M<int>(); } }"; CompileAndVerify(source, options: TestOptions.DebugExe.WithMetadataImportOptions(MetadataImportOptions.All), expectedOutput: "System.Int32", symbolValidator: m => { var method = (MethodSymbol)m.GlobalNamespace.GetMember("Program.<M>g__local|0_0"); Assert.True(method.IsStatic); Assert.True(method.IsGenericMethod); Assert.Equal("void Program.<M>g__local|0_0<T>(T t)", method.ToTestDisplayString()); }); } /// <summary> /// Local function in generic method is emitted as a generic /// method even if no references to type parameters. /// </summary> [Fact] [WorkItem(38143, "https://github.com/dotnet/roslyn/issues/38143")] public void EmittedAsStatic_03() { var source = @"class Program { static void M<T>() where T : new() { static void local(object o) { System.Console.Write(o.GetType().FullName); } local(new T()); } static void Main() { M<int>(); } }"; CompileAndVerify(source, options: TestOptions.DebugExe.WithMetadataImportOptions(MetadataImportOptions.All), expectedOutput: "System.Int32", symbolValidator: m => { var method = (MethodSymbol)m.GlobalNamespace.GetMember("Program.<M>g__local|0_0"); Assert.True(method.IsStatic); Assert.True(method.IsGenericMethod); Assert.Equal("void Program.<M>g__local|0_0<T>(System.Object o)", method.ToTestDisplayString()); }); } /// <summary> /// Emit 'call' rather than 'callvirt' for local functions regardless of whether /// the local function is static. /// </summary> [Fact] public void EmitCallInstruction() { var source = @"using static System.Console; class Program { static void Main() { int i; void L1() => WriteLine(i++); static void L2(int i) => WriteLine(i); i = 1; L1(); L2(i); } }"; var verifier = CompileAndVerify(source, expectedOutput: @"1 2"); verifier.VerifyIL("Program.Main", @"{ // Code size 27 (0x1b) .maxstack 2 .locals init (Program.<>c__DisplayClass0_0 V_0) //CS$<>8__locals0 IL_0000: ldloca.s V_0 IL_0002: ldc.i4.1 IL_0003: stfld ""int Program.<>c__DisplayClass0_0.i"" IL_0008: ldloca.s V_0 IL_000a: call ""void Program.<Main>g__L1|0_0(ref Program.<>c__DisplayClass0_0)"" IL_000f: ldloc.0 IL_0010: ldfld ""int Program.<>c__DisplayClass0_0.i"" IL_0015: call ""void Program.<Main>g__L2|0_1(int)"" IL_001a: ret }"); } /// <summary> /// '_' should bind to '_' symbol in outer scope even in static local function. /// </summary> [Fact] public void UnderscoreInOuterScope() { var source = @"#pragma warning disable 8321 class C1 { object _; void F1() { void A1(object x) => _ = x; static void B1(object y) => _ = y; } } class C2 { static void F2() { object _; void A2(object x) => _ = x; static void B2(object y) => _ = y; } static void F3() { void A3(object x) => _ = x; static void B3(object y) => _ = y; } }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (8,37): error CS8422: A static local function cannot contain a reference to 'this' or 'base'. // static void B1(object y) => _ = y; Diagnostic(ErrorCode.ERR_StaticLocalFunctionCannotCaptureThis, "_").WithLocation(8, 37), // (17,37): error CS8421: A static local function cannot contain a reference to '_'. // static void B2(object y) => _ = y; Diagnostic(ErrorCode.ERR_StaticLocalFunctionCannotCaptureVariable, "_").WithArguments("_").WithLocation(17, 37)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var nodes = tree.GetRoot().DescendantNodes().OfType<AssignmentExpressionSyntax>(); var actualSymbols = nodes.Select(n => model.GetSymbolInfo(n.Left).Symbol).Select(s => $"{s.Kind}: {s.ToTestDisplayString()}").ToArray(); var expectedSymbols = new[] { "Field: System.Object C1._", "Field: System.Object C1._", "Local: System.Object _", "Local: System.Object _", "Discard: System.Object _", "Discard: System.Object _", }; AssertEx.Equal(expectedSymbols, actualSymbols); } /// <summary> /// 'var' should bind to 'var' symbol in outer scope even in static local function. /// </summary> [Fact] public void VarInOuterScope() { var source = @"#pragma warning disable 8321 class C1 { class @var { } static void F1() { void A1(object x) { var y = x; } static void B1(object x) { var y = x; } } } namespace N { using @var = System.String; class C2 { static void F2() { void A2(object x) { var y = x; } static void B3(object x) { var y = x; } } } }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (7,37): error CS0266: Cannot implicitly convert type 'object' to 'C1.var'. An explicit conversion exists (are you missing a cast?) // void A1(object x) { var y = x; } Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "x").WithArguments("object", "C1.var").WithLocation(7, 37), // (8,44): error CS0266: Cannot implicitly convert type 'object' to 'C1.var'. An explicit conversion exists (are you missing a cast?) // static void B1(object x) { var y = x; } Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "x").WithArguments("object", "C1.var").WithLocation(8, 44), // (18,41): error CS0266: Cannot implicitly convert type 'object' to 'string'. An explicit conversion exists (are you missing a cast?) // void A2(object x) { var y = x; } Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "x").WithArguments("object", "string").WithLocation(18, 41), // (19,48): error CS0266: Cannot implicitly convert type 'object' to 'string'. An explicit conversion exists (are you missing a cast?) // static void B3(object x) { var y = x; } Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "x").WithArguments("object", "string").WithLocation(19, 48)); var tree = comp.SyntaxTrees[0]; var model = comp.GetSemanticModel(tree); var nodes = tree.GetRoot().DescendantNodes().OfType<VariableDeclaratorSyntax>(); var actualSymbols = nodes.Select(n => model.GetDeclaredSymbol(n)).ToTestDisplayStrings(); var expectedSymbols = new[] { "C1.var y", "C1.var y", "System.String y", "System.String y", }; AssertEx.Equal(expectedSymbols, actualSymbols); } [Fact] public void AwaitWithinAsyncOuterScope_01() { var source = @" #pragma warning disable 8321 using System.Threading.Tasks; class Program { void F1() { void A1() { await Task.Yield(); } static void B1() { await Task.Yield(); } } void F2() { async void A2() { await Task.Yield(); } async static void B2() { await Task.Yield(); } } async void F3() { void A3() { await Task.Yield(); } static void B3() { await Task.Yield(); } } async void F4() { async void A4() { await Task.Yield(); } async static void B4() { await Task.Yield(); } } }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (8,21): error CS4033: The 'await' operator can only be used within an async method. Consider marking this method with the 'async' modifier and changing its return type to 'Task'. // void A1() { await Task.Yield(); } Diagnostic(ErrorCode.ERR_BadAwaitWithoutVoidAsyncMethod, "await Task.Yield()").WithLocation(8, 21), // (9,28): error CS4033: The 'await' operator can only be used within an async method. Consider marking this method with the 'async' modifier and changing its return type to 'Task'. // static void B1() { await Task.Yield(); } Diagnostic(ErrorCode.ERR_BadAwaitWithoutVoidAsyncMethod, "await Task.Yield()").WithLocation(9, 28), // (18,21): error CS4033: The 'await' operator can only be used within an async method. Consider marking this method with the 'async' modifier and changing its return type to 'Task'. // void A3() { await Task.Yield(); } Diagnostic(ErrorCode.ERR_BadAwaitWithoutVoidAsyncMethod, "await Task.Yield()").WithLocation(18, 21), // (19,28): error CS4033: The 'await' operator can only be used within an async method. Consider marking this method with the 'async' modifier and changing its return type to 'Task'. // static void B3() { await Task.Yield(); } Diagnostic(ErrorCode.ERR_BadAwaitWithoutVoidAsyncMethod, "await Task.Yield()").WithLocation(19, 28)); } /// <summary> /// 'await' should be a contextual keyword in the same way, /// regardless of whether local function is static. /// </summary> [Fact] public void AwaitWithinAsyncOuterScope_02() { var source = @" #pragma warning disable 8321 class Program { void F1() { void A1<await>() { } static void B1<await>() { } } void F2() { async void A2<await>() { } async static void B2<await>() { } } async void F3() { void A3<await>() { } static void B3<await>() { } } async void F4() { async void A4<await>() { } async static void B4<await>() { } } }"; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (7,17): warning CS8981: The type name 'await' only contains lower-cased ascii characters. Such names may become reserved for the language. // void A1<await>() { } Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "await").WithArguments("await").WithLocation(7, 17), // (8,24): warning CS8981: The type name 'await' only contains lower-cased ascii characters. Such names may become reserved for the language. // static void B1<await>() { } Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "await").WithArguments("await").WithLocation(8, 24), // (12,23): error CS4003: 'await' cannot be used as an identifier within an async method or lambda expression // async void A2<await>() { } Diagnostic(ErrorCode.ERR_BadAwaitAsIdentifier, "await").WithLocation(12, 23), // (12,23): warning CS8981: The type name 'await' only contains lower-cased ascii characters. Such names may become reserved for the language. // async void A2<await>() { } Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "await").WithArguments("await").WithLocation(12, 23), // (13,30): error CS4003: 'await' cannot be used as an identifier within an async method or lambda expression // async static void B2<await>() { } Diagnostic(ErrorCode.ERR_BadAwaitAsIdentifier, "await").WithLocation(13, 30), // (13,30): warning CS8981: The type name 'await' only contains lower-cased ascii characters. Such names may become reserved for the language. // async static void B2<await>() { } Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "await").WithArguments("await").WithLocation(13, 30), // (17,17): warning CS8981: The type name 'await' only contains lower-cased ascii characters. Such names may become reserved for the language. // void A3<await>() { } Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "await").WithArguments("await").WithLocation(17, 17), // (18,24): warning CS8981: The type name 'await' only contains lower-cased ascii characters. Such names may become reserved for the language. // static void B3<await>() { } Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "await").WithArguments("await").WithLocation(18, 24), // (22,23): error CS4003: 'await' cannot be used as an identifier within an async method or lambda expression // async void A4<await>() { } Diagnostic(ErrorCode.ERR_BadAwaitAsIdentifier, "await").WithLocation(22, 23), // (22,23): warning CS8981: The type name 'await' only contains lower-cased ascii characters. Such names may become reserved for the language. // async void A4<await>() { } Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "await").WithArguments("await").WithLocation(22, 23), // (23,30): error CS4003: 'await' cannot be used as an identifier within an async method or lambda expression // async static void B4<await>() { } Diagnostic(ErrorCode.ERR_BadAwaitAsIdentifier, "await").WithLocation(23, 30), // (23,30): warning CS8981: The type name 'await' only contains lower-cased ascii characters. Such names may become reserved for the language. // async static void B4<await>() { } Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "await").WithArguments("await").WithLocation(23, 30)); } [Theory, CombinatorialData, WorkItem(59775, "https://github.com/dotnet/roslyn/issues/59775")] public void TypeParameterScope_InMethodAttributeNameOf(bool useCSharp10) { var source = @" class C { void M() { local<object>(); [My(nameof(TParameter))] // 1 void local<TParameter>() { } } [My(nameof(TParameter))] // 2 void M2<TParameter>() { } } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "; var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyTParameter(comp, 0, "void local<TParameter>()"); VerifyTParameter(comp, 1, "void C.M2<TParameter>()"); } [Theory, CombinatorialData, WorkItem(59775, "https://github.com/dotnet/roslyn/issues/59775")] public void TypeParameterScope_InMethodAttributeNameOfNameOf(bool useCSharp10) { var source = @" class C { void M() { local<object>(); [My(nameof(nameof(TParameter)))] // 1 void local<TParameter>() { } } [My(nameof(nameof(TParameter)))] // 2 void M2<TParameter>() { } } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "; var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics( // (8,20): error CS8081: Expression does not have a name. // [My(nameof(nameof(TParameter)))] // 1 Diagnostic(ErrorCode.ERR_ExpressionHasNoName, "nameof(TParameter)").WithLocation(8, 20), // (12,16): error CS8081: Expression does not have a name. // [My(nameof(nameof(TParameter)))] // 2 Diagnostic(ErrorCode.ERR_ExpressionHasNoName, "nameof(TParameter)").WithLocation(12, 16) ); VerifyTParameter(comp, 0, "void local<TParameter>()"); VerifyTParameter(comp, 1, "void C.M2<TParameter>()"); } [Theory, CombinatorialData, WorkItem(59775, "https://github.com/dotnet/roslyn/issues/59775")] public void TypeParameterScope_InMethodAttributeNameOf_TopLevel(bool useCSharp10) { var source = @" local<object>(); [My(nameof(TParameter))] // 1 void local<TParameter>() { } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "; var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyTParameter(comp, 0, "void local<TParameter>()"); } [Theory, CombinatorialData] public void TypeParameterScope_InMethodAttributeNameOf_SpeculatingWithNewAttribute(bool useCSharp10) { var source = @" class C { void M() { local<object>(); //[My(nameof(TParameter))] void local<TParameter>() { } } //[My(nameof(TParameter))] void M2<TParameter>() { } } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "; var parseOptions = useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11; var comp = CreateCompilation(source, parseOptions: parseOptions); comp.VerifyDiagnostics(); var tree = comp.SyntaxTrees.Single(); // Note: offset by one to the left to get away from return type var localFuncPosition = tree.GetText().ToString().IndexOf("void local<TParameter>()", StringComparison.Ordinal) - 1; var methodPosition = tree.GetText().ToString().IndexOf("void M2<TParameter>()", StringComparison.Ordinal) - 1; var parentModel = comp.GetSemanticModel(tree); var attr = parseAttributeSyntax("[My(nameof(TParameter))]", parseOptions); VerifyTParameterSpeculation(parentModel, localFuncPosition, attr, found: false); VerifyTParameterSpeculation(parentModel, methodPosition, attr, found: false); attr = parseAttributeSyntax("[My(TParameter)]", parseOptions); VerifyTParameterSpeculation(parentModel, localFuncPosition, attr, found: false); VerifyTParameterSpeculation(parentModel, methodPosition, attr, found: false); return; // Note: this results in an attribute on a method, but that doesn't bring any extra type parameters static AttributeSyntax parseAttributeSyntax(string source, CSharpParseOptions parseOptions) => SyntaxFactory.ParseCompilationUnit($@"class X {{ {source} void M() {{ }} }}", options: parseOptions).DescendantNodes().OfType<AttributeSyntax>().Single(); } static void VerifyTParameterSpeculation(SemanticModel parentModel, int localFuncPosition, AttributeSyntax attr1, bool found = true) { SemanticModel speculativeModel; var success = parentModel.TryGetSpeculativeSemanticModel(localFuncPosition, attr1, out speculativeModel); Assert.True(success); Assert.NotNull(speculativeModel); var symbolInfo = speculativeModel.GetSymbolInfo(getTParameter(attr1)); if (found) { Assert.Equal(SymbolKind.TypeParameter, symbolInfo.Symbol.Kind); } else { Assert.Null(symbolInfo.Symbol); } return; static IdentifierNameSyntax getTParameter(CSharpSyntaxNode node) { return node.DescendantNodes().OfType<IdentifierNameSyntax>().Where(i => i.Identifier.ValueText == "TParameter").Single(); } } [Theory, CombinatorialData] public void TypeParameterScope_InMethodAttributeNameOf_SpeculatingWithinAttribute(bool useCSharp10) { var source = @" class C { void M() { local<object>(); [My(a)] [My(nameof(b))] void local<TParameter>() { } } [My(c)] [My(nameof(d))] void M2<TParameter>() { } } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "; var parseOptions = useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11; var comp = CreateCompilation(source, parseOptions: parseOptions); comp.VerifyDiagnostics( // (8,13): error CS0103: The name 'a' does not exist in the current context // [My(a)] Diagnostic(ErrorCode.ERR_NameNotInContext, "a").WithArguments("a").WithLocation(8, 13), // (9,20): error CS0103: The name 'b' does not exist in the current context // [My(nameof(b))] Diagnostic(ErrorCode.ERR_NameNotInContext, "b").WithArguments("b").WithLocation(9, 20), // (13,9): error CS0103: The name 'c' does not exist in the current context // [My(c)] Diagnostic(ErrorCode.ERR_NameNotInContext, "c").WithArguments("c").WithLocation(13, 9), // (14,16): error CS0103: The name 'd' does not exist in the current context // [My(nameof(d))] Diagnostic(ErrorCode.ERR_NameNotInContext, "d").WithArguments("d").WithLocation(14, 16) ); var tree = comp.SyntaxTrees.Single(); var parentModel = comp.GetSemanticModel(tree); var aPosition = getIdentifierPosition("a"); var newNameOf = parseNameof("nameof(TParameter)", parseOptions: parseOptions); Assert.Equal("System.String", parentModel.GetSpeculativeTypeInfo(aPosition, newNameOf, SpeculativeBindingOption.BindAsExpression).Type.ToTestDisplayString()); var bPosition = getIdentifierPosition("b"); var newNameOfArgument = parseIdentifier("TParameter", parseOptions: parseOptions); Assert.Equal("TParameter", parentModel.GetSpeculativeTypeInfo(bPosition, newNameOfArgument, SpeculativeBindingOption.BindAsExpression).Type.ToTestDisplayString()); var cPosition = getIdentifierPosition("c"); Assert.Equal("System.String", parentModel.GetSpeculativeTypeInfo(cPosition, newNameOf, SpeculativeBindingOption.BindAsExpression).Type.ToTestDisplayString()); var dPosition = getIdentifierPosition("d"); Assert.Equal("TParameter", parentModel.GetSpeculativeTypeInfo(dPosition, newNameOfArgument, SpeculativeBindingOption.BindAsExpression).Type.ToTestDisplayString()); return; int getIdentifierPosition(string identifier) { return tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(i => i.Identifier.ValueText == identifier).Single().SpanStart; } static ExpressionSyntax parseNameof(string source, CSharpParseOptions parseOptions) => SyntaxFactory.ParseCompilationUnit($@"{source};", options: parseOptions).DescendantNodes().OfType<InvocationExpressionSyntax>().Single(); static ExpressionSyntax parseIdentifier(string source, CSharpParseOptions parseOptions) => SyntaxFactory.ParseCompilationUnit($@"{source};", options: parseOptions).DescendantNodes().OfType<IdentifierNameSyntax>().Single(); } [Fact] public void TypeParameterScope_InMethodAttributeNameOf_SpeculatingWithReplacementAttribute() { var source = @" class C { void M() { local<object>(); [My(a)] void local<TParameter>() { } } [My(b)] void M2<TParameter>() { } } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "; // C# 10 var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics( // (8,13): error CS0103: The name 'a' does not exist in the current context // [My(a)] Diagnostic(ErrorCode.ERR_NameNotInContext, "a").WithArguments("a").WithLocation(8, 13), // (12,9): error CS0103: The name 'b' does not exist in the current context // [My(b)] Diagnostic(ErrorCode.ERR_NameNotInContext, "b").WithArguments("b").WithLocation(12, 9) ); var tree = comp.SyntaxTrees.Single(); var parentModel = comp.GetSemanticModel(tree); var localFuncPosition = tree.GetText().ToString().IndexOf("[My(a)]", StringComparison.Ordinal); var methodPosition = tree.GetText().ToString().IndexOf("[My(b)]", StringComparison.Ordinal); var attr = parseAttributeSyntax("[My(nameof(TParameter))]", TestOptions.Regular10); VerifyTParameterSpeculation(parentModel, localFuncPosition, attr, found: false); VerifyTParameterSpeculation(parentModel, methodPosition, attr, found: false); attr = parseAttributeSyntax("[My(TParameter)]", TestOptions.Regular10); VerifyTParameterSpeculation(parentModel, localFuncPosition, attr, found: false); VerifyTParameterSpeculation(parentModel, methodPosition, attr, found: false); // C# 11 comp = CreateCompilation(source, parseOptions: TestOptions.Regular11); comp.VerifyDiagnostics( // (8,13): error CS0103: The name 'a' does not exist in the current context // [My(a)] Diagnostic(ErrorCode.ERR_NameNotInContext, "a").WithArguments("a").WithLocation(8, 13), // (12,9): error CS0103: The name 'b' does not exist in the current context // [My(b)] Diagnostic(ErrorCode.ERR_NameNotInContext, "b").WithArguments("b").WithLocation(12, 9) ); tree = comp.SyntaxTrees.Single(); parentModel = comp.GetSemanticModel(tree); VerifyTParameterSpeculation(parentModel, localFuncPosition, attr, found: false); VerifyTParameterSpeculation(parentModel, methodPosition, attr, found: false); attr = parseAttributeSyntax("[My(TParameter)]", TestOptions.Regular10); VerifyTParameterSpeculation(parentModel, localFuncPosition, attr, found: false); VerifyTParameterSpeculation(parentModel, methodPosition, attr, found: false); return; static AttributeSyntax parseAttributeSyntax(string source, CSharpParseOptions parseOptions) => SyntaxFactory.ParseCompilationUnit($@"class X {{ {source} void M() {{ }} }}", options: parseOptions).DescendantNodes().OfType<AttributeSyntax>().Single(); } [Theory, CombinatorialData] public void TypeParameterScope_InMethodAttributeNameOf_SpeculatingWithReplacementAttributeInsideExisting(bool useCSharp10) { var source = @" class C { void M() { local<object>(); [My(positionA)] void local<TParameter>() { } } [My(positionB)] void M2<TParameter>() { } } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "; var parseOptions = useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11; var comp = CreateCompilation(source, parseOptions: parseOptions); comp.VerifyDiagnostics( // (8,13): error CS0103: The name 'positionA' does not exist in the current context // [My(positionA)] Diagnostic(ErrorCode.ERR_NameNotInContext, "positionA").WithArguments("positionA").WithLocation(8, 13), // (12,9): error CS0103: The name 'positionB' does not exist in the current context // [My(positionB)] Diagnostic(ErrorCode.ERR_NameNotInContext, "positionB").WithArguments("positionB").WithLocation(12, 9) ); var tree = comp.SyntaxTrees.Single(); var parentModel = comp.GetSemanticModel(tree); var localFuncPosition = tree.GetText().ToString().IndexOf("positionA", StringComparison.Ordinal); var methodPosition = tree.GetText().ToString().IndexOf("positionB", StringComparison.Ordinal); var attr = parseAttributeSyntax("[My(nameof(TParameter))]", parseOptions); VerifyTParameterSpeculation(parentModel, localFuncPosition, attr); VerifyTParameterSpeculation(parentModel, methodPosition, attr); attr = parseAttributeSyntax("[My(TParameter)]", parseOptions); VerifyTParameterSpeculation(parentModel, localFuncPosition, attr, found: false); VerifyTParameterSpeculation(parentModel, methodPosition, attr, found: false); return; static AttributeSyntax parseAttributeSyntax(string source, CSharpParseOptions parseOptions) => SyntaxFactory.ParseCompilationUnit($@"class X {{ {source} void M() {{ }} }}", options: parseOptions).DescendantNodes().OfType<AttributeSyntax>().Single(); } [Theory, CombinatorialData, WorkItem(59775, "https://github.com/dotnet/roslyn/issues/59775")] [WorkItem(60194, "https://github.com/dotnet/roslyn/issues/60194")] public void TypeParameterScope_InMethodAttributeNameOf_CompatBreak(bool useCSharp10) { var source = @" class C { class TParameter { public const string Constant = """"; } void M() { local<object>(); [My(nameof(TParameter.Constant))] // 1 void local<TParameter>() { } } [My(nameof(TParameter.Constant))] // 2 void M2<TParameter>() { } } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "; var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics( // (13,20): error CS0704: Cannot do non-virtual member lookup in 'TParameter' because it is a type parameter // [My(nameof(TParameter.Constant))] // 1 Diagnostic(ErrorCode.ERR_LookupInTypeVariable, "TParameter").WithArguments("TParameter").WithLocation(13, 20), // (17,16): error CS0704: Cannot do non-virtual member lookup in 'TParameter' because it is a type parameter // [My(nameof(TParameter.Constant))] // 2 Diagnostic(ErrorCode.ERR_LookupInTypeVariable, "TParameter").WithArguments("TParameter").WithLocation(17, 16) ); VerifyTParameter(comp, 0, "void local<TParameter>()"); VerifyTParameter(comp, 1, "void C.M2<TParameter>()"); } /// <summary> /// Look for usages of "TParameter" and verify the index-th one. /// </summary> private void VerifyTParameter(CSharpCompilation comp, int index, string expectedContainer, bool findAnyways = false, string lookupFinds = "TParameter", SymbolKind symbolKind = SymbolKind.TypeParameter) { var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var tParameterUsages = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>() .Where(i => i.Identifier.ValueText == "TParameter") .Where(i => i.Ancestors().Any(a => a.Kind() is SyntaxKind.Attribute or SyntaxKind.TypeConstraint or SyntaxKind.DefaultExpression or SyntaxKind.InvocationExpression or SyntaxKind.EqualsValueClause)) .ToArray(); var tParameterUsage = tParameterUsages[index]; var symbol = model.GetSymbolInfo(tParameterUsage).Symbol; if (expectedContainer is null) { Assert.Null(symbol); var typeInfo = model.GetTypeInfo(tParameterUsage); if (findAnyways) { // In certain cases, like `[TParameter]`, we're able to bind the attribute, find the type but reject it. // So GetTypeInfo does return a type. Assert.Equal(SymbolKind.TypeParameter, typeInfo.Type.Kind); } else { Assert.True(typeInfo.Type.IsErrorType()); } Assert.Equal(findAnyways, model.LookupSymbols(tParameterUsage.Position).ToTestDisplayStrings().Contains("TParameter")); } else { Assert.Equal(expectedContainer, symbol.ContainingSymbol.ToTestDisplayString()); Assert.Equal(symbolKind, model.GetTypeInfo(tParameterUsage).Type.Kind); var lookupResults = model.LookupSymbols(tParameterUsage.Position).ToTestDisplayStrings(); Assert.Contains(lookupFinds, lookupResults); if (lookupFinds != "TParameter") { Assert.DoesNotContain("TParameter", lookupResults); } } } [Fact] public void TypeParameterScope_NotInMethodAttribute() { var comp = CreateCompilation(@" class C { void M() { local<object>(); [My(TParameter)] // 1 void local<TParameter>() { } } [My(TParameter)] // 2 void M2<TParameter>() { } } public class MyAttribute : System.Attribute { public MyAttribute(object o) { } } "); comp.VerifyDiagnostics( // (8,13): error CS0103: The name 'TParameter' does not exist in the current context // [My(TParameter)] // 1 Diagnostic(ErrorCode.ERR_NameNotInContext, "TParameter").WithArguments("TParameter").WithLocation(8, 13), // (12,9): error CS0103: The name 'TParameter' does not exist in the current context // [My(TParameter)] // 2 Diagnostic(ErrorCode.ERR_NameNotInContext, "TParameter").WithArguments("TParameter").WithLocation(12, 9) ); VerifyTParameter(comp, 0, null); VerifyTParameter(comp, 1, null); } [Fact] public void TypeParameterScope_NotInMethodAttributeTypeArgument() { var comp = CreateCompilation(@" class C { void M() { local<object>(); [My<TParameter>] // 1 void local<TParameter>() { } } [My<TParameter>] // 2 void M2<TParameter>() { } } public class MyAttribute<T> : System.Attribute { } "); comp.VerifyDiagnostics( // (8,13): error CS0246: The type or namespace name 'TParameter' could not be found (are you missing a using directive or an assembly reference?) // [My<TParameter>] // 1 Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "TParameter").WithArguments("TParameter").WithLocation(8, 13), // (12,9): error CS0246: The type or namespace name 'TParameter' could not be found (are you missing a using directive or an assembly reference?) // [My<TParameter>] // 2 Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "TParameter").WithArguments("TParameter").WithLocation(12, 9) ); VerifyTParameter(comp, 0, null); VerifyTParameter(comp, 1, null); } [Fact] public void TypeParameterScope_NotAsMethodAttributeType() { var comp = CreateCompilation(@" class C { void M() { local<System.Attribute>(); [TParameter] // 1 void local<TParameter>() where TParameter : System.Attribute { } } [TParameter] // 2 void M2<TParameter>() where TParameter : System.Attribute { } } "); comp.VerifyDiagnostics( // (8,10): error CS0246: The type or namespace name 'TParameterAttribute' could not be found (are you missing a using directive or an assembly reference?) // [TParameter] // 1 Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "TParameter").WithArguments("TParameterAttribute").WithLocation(8, 10), // (8,10): error CS0246: The type or namespace name 'TParameter' could not be found (are you missing a using directive or an assembly reference?) // [TParameter] // 1 Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "TParameter").WithArguments("TParameter").WithLocation(8, 10), // (12,6): error CS0246: The type or namespace name 'TParameterAttribute' could not be found (are you missing a using directive or an assembly reference?) // [TParameter] // 2 Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "TParameter").WithArguments("TParameterAttribute").WithLocation(12, 6), // (12,6): error CS0246: The type or namespace name 'TParameter' could not be found (are you missing a using directive or an assembly reference?) // [TParameter] // 2 Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "TParameter").WithArguments("TParameter").WithLocation(12, 6) ); VerifyTParameter(comp, 0, null); VerifyTParameter(comp, 1, null); } [Fact] public void TypeParameterScope_NotInMethodAttributeDefault() { var comp = CreateCompilation(@" class C { void M() { local<object>(); [My(default(TParameter))] void local<TParameter>() where TParameter : class => throw null; } [My(default(TParameter))] void M2<TParameter>() where TParameter : class => throw null; } public class MyAttribute : System.Attribute { public MyAttribute(object o) { } } "); comp.VerifyDiagnostics( // (8,21): error CS0246: The type or namespace name 'TParameter' could not be found (are you missing a using directive or an assembly reference?) // [My(default(TParameter))] Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "TParameter").WithArguments("TParameter").WithLocation(8, 21), // (12,17): error CS0246: The type or namespace name 'TParameter' could not be found (are you missing a using directive or an assembly reference?) // [My(default(TParameter))] Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "TParameter").WithArguments("TParameter").WithLocation(12, 17) ); VerifyTParameter(comp, 0, null); VerifyTParameter(comp, 1, null); } [Fact, WorkItem(60110, "https://github.com/dotnet/roslyn/issues/60110")] public void TypeParameterScope_NotInParameterAttribute() { var comp = CreateCompilation(@" class C { void M() { local<object>(0); void local<TParameter>([My(TParameter)] int i) => throw null; } void M2<TParameter>([My(TParameter)] int i) => throw null; } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "); // TParameter unexpectedly was found in local function case because of IsInMethodBody logic // Tracked by https://github.com/dotnet/roslyn/issues/60110 comp.VerifyDiagnostics( // (8,36): error CS0119: 'TParameter' is a type, which is not valid in the given context // void local<TParameter>([My(TParameter)] int i) => throw null; Diagnostic(ErrorCode.ERR_BadSKunknown, "TParameter").WithArguments("TParameter", "type").WithLocation(8, 36), // (11,29): error CS0103: The name 'TParameter' does not exist in the current context // void M2<TParameter>([My(TParameter)] int i) => throw null; Diagnostic(ErrorCode.ERR_NameNotInContext, "TParameter").WithArguments("TParameter").WithLocation(11, 29) ); //VerifyTParameter(comp, 0, null); VerifyTParameter(comp, 1, null); } [Fact, WorkItem(60110, "https://github.com/dotnet/roslyn/issues/60110")] public void TypeParameterScope_NotInParameterAttribute_NotShadowingConst() { var comp = CreateCompilation(@" class C { const string TParameter = """"; void M() { local<object>(0); void local<TParameter>([My(TParameter)] int i) => throw null; } void M2<TParameter>([My(TParameter)] int i) => throw null; } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "); // TParameter unexpectedly was found in local function case because of IsInMethodBody logic // Tracked by https://github.com/dotnet/roslyn/issues/60110 comp.VerifyDiagnostics( // (10,36): error CS0119: 'TParameter' is a type, which is not valid in the given context // void local<TParameter>([My(TParameter)] int i) => throw null; Diagnostic(ErrorCode.ERR_BadSKunknown, "TParameter").WithArguments("TParameter", "type").WithLocation(10, 36) ); //VerifyTParameter(comp, 0, "C", symbolKind: SymbolKind.NamedType, lookupFinds: "System.String C.TParameter"); VerifyTParameter(comp, 1, "C", symbolKind: SymbolKind.NamedType, lookupFinds: "System.String C.TParameter"); } [Fact, WorkItem(60194, "https://github.com/dotnet/roslyn/issues/60194")] public void TypeParameterScope_InParameterAttributeNameOf() { var comp = CreateCompilation(@" class C { void M() { local<object>(0); void local<TParameter>([My(nameof(TParameter))] int i) => throw null; } void M2<TParameter>([My(nameof(TParameter))] int i) => throw null; } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "); comp.VerifyDiagnostics(); VerifyTParameter(comp, 0, "void local<TParameter>(System.Int32 i)"); VerifyTParameter(comp, 1, "void C.M2<TParameter>(System.Int32 i)"); } [Fact] public void TypeParameterScope_InParameterAttributeTypeOf() { var comp = CreateCompilation(@" class C { void M() { local<object>(0); void local<TParameter>([My(typeof(TParameter))] int i) => throw null; } void M2<TParameter>([My(typeof(TParameter))] int i) => throw null; } public class MyAttribute : System.Attribute { public MyAttribute(System.Type type) { } } "); comp.VerifyDiagnostics( // (8,36): error CS0416: 'TParameter': an attribute argument cannot use type parameters // void local<TParameter>([My(typeof(TParameter))] int i) => throw null; Diagnostic(ErrorCode.ERR_AttrArgWithTypeVars, "typeof(TParameter)").WithArguments("TParameter").WithLocation(8, 36), // (11,29): error CS0416: 'TParameter': an attribute argument cannot use type parameters // void M2<TParameter>([My(typeof(TParameter))] int i) => throw null; Diagnostic(ErrorCode.ERR_AttrArgWithTypeVars, "typeof(TParameter)").WithArguments("TParameter").WithLocation(11, 29) ); VerifyTParameter(comp, 0, "void local<TParameter>(System.Int32 i)"); VerifyTParameter(comp, 1, "void C.M2<TParameter>(System.Int32 i)"); } [Fact] public void TypeParameterScope_InParameterAttributeSizeOf() { var source = @" class C { void M() { local<int>(0); void local<TParameter>([My(sizeof(TParameter))] int i) where TParameter : unmanaged => throw null; } void M2<TParameter>([My(sizeof(TParameter))] int i) where TParameter : unmanaged => throw null; } public class MyAttribute : System.Attribute { public MyAttribute(int i) { } } "; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular14); comp.VerifyDiagnostics( // (8,36): error CS0233: 'TParameter' does not have a predefined size, therefore sizeof can only be used in an unsafe context // void local<TParameter>([My(sizeof(TParameter))] int i) where TParameter : unmanaged => throw null; Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(TParameter)").WithArguments("TParameter").WithLocation(8, 36), // (11,29): error CS0233: 'TParameter' does not have a predefined size, therefore sizeof can only be used in an unsafe context // void M2<TParameter>([My(sizeof(TParameter))] int i) where TParameter : unmanaged => throw null; Diagnostic(ErrorCode.ERR_SizeofUnsafe, "sizeof(TParameter)").WithArguments("TParameter").WithLocation(11, 29) ); VerifyTParameter(comp, 0, "void local<TParameter>(System.Int32 i)"); VerifyTParameter(comp, 1, "void C.M2<TParameter>(System.Int32 i)"); var expectedPreviewDiagnostics = new[] { // (8,36): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type // void local<TParameter>([My(sizeof(TParameter))] int i) where TParameter : unmanaged => throw null; Diagnostic(ErrorCode.ERR_BadAttributeArgument, "sizeof(TParameter)").WithLocation(8, 36), // (11,29): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type // void M2<TParameter>([My(sizeof(TParameter))] int i) where TParameter : unmanaged => throw null; Diagnostic(ErrorCode.ERR_BadAttributeArgument, "sizeof(TParameter)").WithLocation(11, 29), }; CreateCompilation(source).VerifyDiagnostics(expectedPreviewDiagnostics); CreateCompilation(source, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedPreviewDiagnostics); } [Fact] public void TypeParameterScope_InParameterAttributeDefault() { var comp = CreateCompilation(@" class C { void M() { local<object>(0); void local<TParameter>([My(default(TParameter))] int i) where TParameter : class => throw null; } void M2<TParameter>([My(default(TParameter))] int i) where TParameter : class => throw null; } public class MyAttribute : System.Attribute { public MyAttribute(object o) { } } "); comp.VerifyDiagnostics(); VerifyTParameter(comp, 0, "void local<TParameter>(System.Int32 i)"); VerifyTParameter(comp, 1, "void C.M2<TParameter>(System.Int32 i)"); } [Fact] public void TypeParameterScope_AsParameterAttributeType() { var comp = CreateCompilation(@" class C { void M() { local<System.Attribute>(0); void local<TParameter>([TParameter] int i) where TParameter : System.Attribute => throw null; } void M2<TParameter>([TParameter] int i) where TParameter : System.Attribute => throw null; } "); comp.VerifyDiagnostics( // (8,33): error CS0616: 'TParameter' is not an attribute class // void local<TParameter>([TParameter] int i) where TParameter : System.Attribute => throw null; Diagnostic(ErrorCode.ERR_NotAnAttributeClass, "TParameter").WithArguments("TParameter").WithLocation(8, 33), // (11,26): error CS0616: 'TParameter' is not an attribute class // void M2<TParameter>([TParameter] int i) where TParameter : System.Attribute => throw null; Diagnostic(ErrorCode.ERR_NotAnAttributeClass, "TParameter").WithArguments("TParameter").WithLocation(11, 26) ); VerifyTParameter(comp, 0, null, findAnyways: true); VerifyTParameter(comp, 1, null, findAnyways: true); } [Fact] public void TypeParameterScope_InReturnType() { var comp = CreateCompilation(@" class C { void M() { local<object>(); TParameter local<TParameter>() => throw null; } TParameter M2<TParameter>() => throw null; } "); comp.VerifyDiagnostics(); } [Fact] public void TypeParameterScope_InParameterType() { var comp = CreateCompilation(@" class C { void M() { local<object>(null); void local<TParameter>(TParameter p) => throw null; } void M2<TParameter>(TParameter p) => throw null; } "); comp.VerifyDiagnostics(); } [Fact] public void TypeParameterScope_InTypeConstraint() { var comp = CreateCompilation(@" class C { void M() { local<object, object>(); void local<TParameter2, TParameter>() where TParameter2 : TParameter => throw null; } void M2<TParameter2, TParameter>() where TParameter2 : TParameter => throw null; } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "); comp.VerifyDiagnostics(); VerifyTParameter(comp, 0, "void local<TParameter2, TParameter>()"); VerifyTParameter(comp, 1, "void C.M2<TParameter2, TParameter>()"); } [Fact] public void TypeParameterScope_NotInMethodAttributeTypeOf() { var comp = CreateCompilation(@" class C { void M() { local<object>(); [My(typeof(TParameter))] void local<TParameter>() => throw null; } [My(typeof(TParameter))] void M2<TParameter>() => throw null; } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "); comp.VerifyDiagnostics( // (8,20): error CS0246: The type or namespace name 'TParameter' could not be found (are you missing a using directive or an assembly reference?) // [My(typeof(TParameter))] Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "TParameter").WithArguments("TParameter").WithLocation(8, 20), // (12,16): error CS0246: The type or namespace name 'TParameter' could not be found (are you missing a using directive or an assembly reference?) // [My(typeof(TParameter))] Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "TParameter").WithArguments("TParameter").WithLocation(12, 16) ); VerifyTParameter(comp, 0, null); VerifyTParameter(comp, 1, null); } [Fact, WorkItem(60110, "https://github.com/dotnet/roslyn/issues/60110")] public void TypeParameterScope_NotInTypeParameterAttribute() { var comp = CreateCompilation(@" class C { void M() { local<object>(); void local<[My(TParameter)] TParameter>() => throw null; } void M2<[My(TParameter)] TParameter>() => throw null; } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "); // TParameter unexpectedly was found in local function case because of IsInMethodBody logic // Tracked by https://github.com/dotnet/roslyn/issues/60110 comp.VerifyDiagnostics( // (8,24): error CS0119: 'TParameter' is a type, which is not valid in the given context // void local<[My(TParameter)] TParameter>() => throw null; Diagnostic(ErrorCode.ERR_BadSKunknown, "TParameter").WithArguments("TParameter", "type").WithLocation(8, 24), // (11,17): error CS0103: The name 'TParameter' does not exist in the current context // void M2<[My(TParameter)] TParameter>() => throw null; Diagnostic(ErrorCode.ERR_NameNotInContext, "TParameter").WithArguments("TParameter").WithLocation(11, 17) ); //VerifyTParameter(comp, 0, null); VerifyTParameter(comp, 1, null); } [Fact, WorkItem(60194, "https://github.com/dotnet/roslyn/issues/60194")] public void TypeParameterScope_InTypeParameterAttributeNameOf() { var comp = CreateCompilation(@" class C { void M() { local<object>(); void local<[My(nameof(TParameter))] TParameter>() => throw null; } void M2<[My(nameof(TParameter))] TParameter>() => throw null; } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "); comp.VerifyDiagnostics(); VerifyTParameter(comp, 0, "void local<TParameter>()"); VerifyTParameter(comp, 1, "void C.M2<TParameter>()"); } [Fact] public void TypeParameterScope_InTypeParameterAttributeDefault() { var comp = CreateCompilation(@" class C { void M() { local<object>(); void local<[My(default(TParameter))] TParameter>() where TParameter : class => throw null; } void M2<[My(default(TParameter))] TParameter>() where TParameter : class => throw null; } public class MyAttribute : System.Attribute { public MyAttribute(object o) { } } "); comp.VerifyDiagnostics(); VerifyTParameter(comp, 0, "void local<TParameter>()"); VerifyTParameter(comp, 1, "void C.M2<TParameter>()"); } [Fact] public void TypeParameterScope_AsTypeParameterAttributeType() { var comp = CreateCompilation(@" class C { void M() { local<System.Attribute>(); void local<[TParameter] TParameter>() where TParameter : System.Attribute => throw null; } void M2<[TParameter] TParameter>() where TParameter : System.Attribute => throw null; } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "); comp.VerifyDiagnostics( // (8,21): error CS0616: 'TParameter' is not an attribute class // void local<[TParameter] TParameter>() where TParameter : System.Attribute => throw null; Diagnostic(ErrorCode.ERR_NotAnAttributeClass, "TParameter").WithArguments("TParameter").WithLocation(8, 21), // (11,14): error CS0616: 'TParameter' is not an attribute class // void M2<[TParameter] TParameter>() where TParameter : System.Attribute => throw null; Diagnostic(ErrorCode.ERR_NotAnAttributeClass, "TParameter").WithArguments("TParameter").WithLocation(11, 14) ); VerifyTParameter(comp, 0, null, findAnyways: true); VerifyTParameter(comp, 1, null, findAnyways: true); } [Fact] public void TypeParameterScope_InParameterDefaultDefaultValue() { var comp = CreateCompilation(@" class C { void M() { local<System.Attribute>(); void local<TParameter>(TParameter s = default(TParameter)) => throw null; } void M2<TParameter>(TParameter s = default(TParameter)) => throw null; } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "); comp.VerifyDiagnostics(); VerifyTParameter(comp, 0, "void local<TParameter>([TParameter s = default(TParameter)])"); VerifyTParameter(comp, 1, "void C.M2<TParameter>([TParameter s = default(TParameter)])"); } [Fact] public void TypeParameterScope_InParameterDefaultValue() { var comp = CreateCompilation(@" class C { void M() { local<System.Attribute>(); void local<TParameter>(TParameter s = TParameter) => throw null; } void M2<TParameter>(TParameter s = TParameter) => throw null; } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "); // TParameter unexpectedly was found in local function case because of IsInMethodBody logic // Tracked by https://github.com/dotnet/roslyn/issues/60110 comp.VerifyDiagnostics( // (8,47): error CS0119: 'TParameter' is a type, which is not valid in the given context // void local<TParameter>(TParameter s = TParameter) => throw null; Diagnostic(ErrorCode.ERR_BadSKunknown, "TParameter").WithArguments("TParameter", "type").WithLocation(8, 47), // (11,40): error CS0103: The name 'TParameter' does not exist in the current context // void M2<TParameter>(TParameter s = TParameter) => throw null; Diagnostic(ErrorCode.ERR_NameNotInContext, "TParameter").WithArguments("TParameter").WithLocation(11, 40) ); //VerifyTParameter(comp, 0, "void local<TParameter>([TParameter s = default(TParameter)])"); VerifyTParameter(comp, 1, null); } [Fact, WorkItem(60110, "https://github.com/dotnet/roslyn/issues/60110")] public void TypeParameterScope_InParameterDefaultValue_NotShadowingConstant() { var comp = CreateCompilation(@" class C { const string TParameter = """"; void M() { local<System.Attribute>(); void local<TParameter>(string s = TParameter) => throw null; } void M2<TParameter>(string s = TParameter) => throw null; } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "); // TParameter unexpectedly was found in local function case because of IsInMethodBody logic // Tracked by https://github.com/dotnet/roslyn/issues/60110 comp.VerifyDiagnostics( // (10,43): error CS0119: 'TParameter' is a type, which is not valid in the given context // void local<TParameter>(string s = TParameter) => throw null; Diagnostic(ErrorCode.ERR_BadSKunknown, "TParameter").WithArguments("TParameter", "type").WithLocation(10, 43) ); //VerifyTParameter(comp, 0, "C", symbolKind: SymbolKind.NamedType, lookupFinds: "System.String C.TParameter"); VerifyTParameter(comp, 1, "C", symbolKind: SymbolKind.NamedType, lookupFinds: "System.String C.TParameter"); } [Fact, WorkItem(60194, "https://github.com/dotnet/roslyn/issues/60194")] public void TypeParameterScope_InParameterNameOfDefaultValue() { var comp = CreateCompilation(@" class C { void M() { local<System.Attribute>(); void local<TParameter>(string s = nameof(TParameter)) => throw null; } void M2<TParameter>(string s = nameof(TParameter)) => throw null; } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "); comp.VerifyDiagnostics(); VerifyTParameter(comp, 0, @"void local<TParameter>([System.String s = ""TParameter""])"); VerifyTParameter(comp, 1, @"void C.M2<TParameter>([System.String s = ""TParameter""])"); } [Fact] public void TypeParameterScope_InParameterNameOfDefaultValue_NestedLocalFunction() { var comp = CreateCompilation(@" class C { const string TParameter = """"; void M() { local<object>(); void local<TParameter>(string s = TParameter) => throw null; } void M2<TParameter>(string s = TParameter) => throw null; } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "); // TParameter unexpectedly was found in local function case because of IsInMethodBody logic // Tracked by https://github.com/dotnet/roslyn/issues/60110 comp.VerifyDiagnostics( // (10,43): error CS0119: 'TParameter' is a type, which is not valid in the given context // void local<TParameter>(string s = TParameter) => throw null; Diagnostic(ErrorCode.ERR_BadSKunknown, "TParameter").WithArguments("TParameter", "type").WithLocation(10, 43) ); //VerifyTParameter(comp, 0, "C", lookupFinds: "System.String C.TParameter", symbolKind: SymbolKind.NamedType); VerifyTParameter(comp, 1, "C", lookupFinds: "System.String C.TParameter", symbolKind: SymbolKind.NamedType); } [Fact] public void TypeParameterScope_InTypeAttributeNameOf() { var comp = CreateCompilation(@" [My(nameof(TParameter))] class C<TParameter> { } public class MyAttribute : System.Attribute { public MyAttribute(string name) { } } "); comp.VerifyDiagnostics(); VerifyTParameter(comp, 0, "C<TParameter>"); } [Fact] public void TypeParameterScope_InTypeAttributeConstant() { var comp = CreateCompilation(@" [My(TParameter.Constant)] class C<TParameter> where TParameter : I { } interface I { const string Constant = ""hello""; } public class MyAttribute : System.Attribute { public MyAttribute(string name) { } } ", targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (2,5): error CS0704: Cannot do non-virtual member lookup in 'TParameter' because it is a type parameter // [My(TParameter.Constant)] Diagnostic(ErrorCode.ERR_LookupInTypeVariable, "TParameter").WithArguments("TParameter").WithLocation(2, 5) ); VerifyTParameter(comp, 0, "C<TParameter>"); } [Fact] public void TypeParameterScope_InTypeAttributeType() { var comp = CreateCompilation(@" [TParameter] class C<TParameter> where TParameter : MyAttribute { } public class MyAttribute : System.Attribute { } "); comp.VerifyDiagnostics( // (2,2): error CS0616: 'TParameter' is not an attribute class // [TParameter] Diagnostic(ErrorCode.ERR_NotAnAttributeClass, "TParameter").WithArguments("TParameter").WithLocation(2, 2) ); VerifyTParameter(comp, 0, null, findAnyways: true); } [Fact] public void TypeParameterScope_InRecordAttributeNameOf() { var source = @" [My(nameof(TParameter))] record R<TParameter>(); public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics(); VerifyTParameter(comp, 0, "R<TParameter>"); comp = CreateCompilation(source, parseOptions: TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyTParameter(comp, 0, "R<TParameter>"); } [Fact] public void TypeParameterScope_InRecordParameterAttributeNameOf() { var source = @" record R<TParameter>([My(nameof(TParameter))] int I); public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "; var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular10); comp.VerifyDiagnostics(); VerifyTParameter(comp, 0, "R<TParameter>"); comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyTParameter(comp, 0, "R<TParameter>"); } [Fact] public void TypeParameterScope_InRecordAttributeNameOfConstant() { var source = @" [My(nameof(TParameter.Constant))] record R<TParameter>() where TParameter : I; interface I { const string Constant = ""hello""; } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "; var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (2,12): error CS0704: Cannot do non-virtual member lookup in 'TParameter' because it is a type parameter // [My(nameof(TParameter.Constant))] Diagnostic(ErrorCode.ERR_LookupInTypeVariable, "TParameter").WithArguments("TParameter").WithLocation(2, 12) ); VerifyTParameter(comp, 0, "R<TParameter>"); } [Fact] public void TypeParameterScope_InRecordAttributeNameOf_RecordStruct() { var source = @" [My(nameof(TParameter))] record struct R<TParameter>(); public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics(); VerifyTParameter(comp, 0, "R<TParameter>"); } [Fact] public void TypeParameterScope_AsRecordAttributeType() { var source = @" [TParameter] record R<TParameter>() where TParameter : System.Attribute; "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (2,2): error CS0616: 'TParameter' is not an attribute class // [TParameter] Diagnostic(ErrorCode.ERR_NotAnAttributeClass, "TParameter").WithArguments("TParameter").WithLocation(2, 2) ); VerifyTParameter(comp, 0, null, findAnyways: true); } [Fact] public void TypeParameterScope_InRecordAttributeTypeArgument() { var source = @" [My<TParameter>] record R<TParameter>() where TParameter : System.Attribute; public class MyAttribute<T> : System.Attribute { public MyAttribute() { } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (2,2): error CS8968: 'TParameter': an attribute type argument cannot use type parameters // [My<TParameter>] Diagnostic(ErrorCode.ERR_AttrTypeArgCannotBeTypeVar, "My<TParameter>").WithArguments("TParameter").WithLocation(2, 2) ); VerifyTParameter(comp, 0, "R<TParameter>"); } [Fact] public void TypeParameterScope_InRecordAttributeConstant() { var source = @" [My(TParameter.Constant)] record R<TParameter>() where TParameter : I; public class MyAttribute : System.Attribute { public MyAttribute(string name) { } } public interface I { const string Constant = ""hello""; } "; var comp = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp); comp.VerifyDiagnostics( // (2,5): error CS0704: Cannot do non-virtual member lookup in 'TParameter' because it is a type parameter // [My(TParameter.Constant)] Diagnostic(ErrorCode.ERR_LookupInTypeVariable, "TParameter").WithArguments("TParameter").WithLocation(2, 5) ); VerifyTParameter(comp, 0, "R<TParameter>"); } [Theory, CombinatorialData] public void ParameterScope_InMethodAttributeNameOf(bool useCSharp10) { var source = @" class C { void M() { local(0); [My(nameof(parameter))] // 1 void local(int parameter) { } } [My(nameof(parameter))] // 2 void M2(int parameter) { } } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "; var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyParameter(comp, 0, "void local(System.Int32 parameter)"); VerifyParameter(comp, 1, "void C.M2(System.Int32 parameter)"); } /// <summary> /// Look for usages of "parameter" and verify the index-th one. /// </summary> private void VerifyParameter(CSharpCompilation comp, int index, string expectedMethod, string parameterName = "parameter") { var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var parameterUsages = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>() .Where(i => i.Identifier.ValueText == parameterName) .Where(i => i.Ancestors().Any(a => a.IsKind(SyntaxKind.Attribute) || a.IsKind(SyntaxKind.TypeConstraint) || a.IsKind(SyntaxKind.DefaultExpression) || a.IsKind(SyntaxKind.InvocationExpression))) .ToArray(); var parameterUsage = parameterUsages[index]; var symbol = model.GetSymbolInfo(parameterUsage).Symbol; if (expectedMethod is null) { Assert.Null(symbol); Assert.True(model.GetTypeInfo(parameterUsage).Type.IsErrorType()); Assert.DoesNotContain("parameter", model.LookupSymbols(parameterUsage.Position).ToTestDisplayStrings()); } else { Assert.Equal(expectedMethod, symbol.ContainingSymbol.ToTestDisplayString()); Assert.Equal("System.Int32", model.GetTypeInfo(parameterUsage).Type.ToTestDisplayString()); var lookupResults = model.LookupSymbols(parameterUsage.Position).ToTestDisplayStrings(); Assert.Contains($"System.Int32 {parameterName}", lookupResults); } } [Fact] [WorkItem(60801, "https://github.com/dotnet/roslyn/issues/60801")] public void ParameterScope_InMethodAttributeNameOf_GetSymbolInfoOnSpeculativeMethodBodySemanticModel() { var source = @" class C { void M() { [My(nameof(parameter))] void local(int parameter) { } } } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular11); comp.VerifyDiagnostics( // (7,14): warning CS8321: The local function 'local' is declared but never used // void local(int parameter) { } Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "local").WithArguments("local").WithLocation(7, 14) ); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var tree2 = CSharpSyntaxTree.ParseText(source); var method = tree2.GetRoot().DescendantNodes().OfType<MethodDeclarationSyntax>().First(); Assert.True(model.TryGetSpeculativeSemanticModelForMethodBody(method.Body.SpanStart, method, out var speculativeModel)); var invocation = tree2.GetRoot().DescendantNodes().OfType<InvocationExpressionSyntax>().Single(); Assert.Equal("nameof(parameter)", invocation.ToString()); var symbolInfo = speculativeModel.GetSymbolInfo(invocation); Assert.Null(symbolInfo.Symbol); } [Fact] public void ParameterScope_InMethodAttributeNameOf_LookupInEmptyNameof() { var source = @" class C { void M() { [My(nameof())] void local(int parameter) { } } } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "; var comp = CreateCompilation(source, parseOptions: TestOptions.Regular11); comp.VerifyDiagnostics( // (6,13): error CS0103: The name 'nameof' does not exist in the current context // [My(nameof())] Diagnostic(ErrorCode.ERR_NameNotInContext, "nameof").WithArguments("nameof").WithLocation(6, 13), // (7,14): warning CS8321: The local function 'local' is declared but never used // void local(int parameter) { } Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "local").WithArguments("local").WithLocation(7, 14) ); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var nameofExpression = tree.GetRoot().DescendantNodes().OfType<InvocationExpressionSyntax>().Single(); // An invocation may not be considered a 'nameof' operator unless it has one argument Assert.False(model.LookupSymbols(nameofExpression.ArgumentList.CloseParenToken.SpanStart).ToTestDisplayStrings().Contains("parameter")); } [Theory, CombinatorialData] public void ParameterScope_InMethodAttributeNameOf_ConflictingNames(bool useCSharp10) { var source = @" class C { void M() { local<object>(0); [My(nameof(parameter))] void local<@parameter>(int parameter) => throw null; } [My(nameof(parameter))] void M2<@parameter>(int parameter) => throw null; } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "; var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics( // (9,36): error CS0412: 'parameter': a parameter, local variable, or local function cannot have the same name as a method type parameter // void local<@parameter>(int parameter) => throw null; Diagnostic(ErrorCode.ERR_LocalSameNameAsTypeParam, "parameter").WithArguments("parameter").WithLocation(9, 36), // (13,29): error CS0412: 'parameter': a parameter, local variable, or local function cannot have the same name as a method type parameter // void M2<@parameter>(int parameter) => throw null; Diagnostic(ErrorCode.ERR_LocalSameNameAsTypeParam, "parameter").WithArguments("parameter").WithLocation(13, 29) ); VerifyParameter(comp, 0, "void local<parameter>(System.Int32 parameter)"); VerifyParameter(comp, 1, "void C.M2<parameter>(System.Int32 parameter)"); } [Theory, CombinatorialData] public void ParameterScope_InMethodAttributeNameOf_CompatBreak(bool useCSharp10) { var source = @" class C { class @parameter { internal const int Constant = 0; } void M() { local(0); [My(nameof(parameter.Constant))] // 1 void local(int parameter) { } } [My(nameof(parameter.Constant))] // 2 void M2(int parameter) { } } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "; var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics( // (13,30): error CS1061: 'int' does not contain a definition for 'Constant' and no accessible extension method 'Constant' accepting a first argument of type 'int' could be found (are you missing a using directive or an assembly reference?) // [My(nameof(parameter.Constant))] // 1 Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Constant").WithArguments("int", "Constant").WithLocation(13, 30), // (17,26): error CS1061: 'int' does not contain a definition for 'Constant' and no accessible extension method 'Constant' accepting a first argument of type 'int' could be found (are you missing a using directive or an assembly reference?) // [My(nameof(parameter.Constant))] // 2 Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "Constant").WithArguments("int", "Constant").WithLocation(17, 26) ); } [Theory, CombinatorialData] public void ParameterScope_InMethodAttributeNameOf_WithReturnTarget(bool useCSharp10) { var source = @" class C { void M() { local(0); [return: My(nameof(parameter))] // 1 void local(int parameter) { } } [return: My(nameof(parameter))] // 2 void M2(int parameter) { } } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "; var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyParameter(comp, 0, "void local(System.Int32 parameter)"); VerifyParameter(comp, 1, "void C.M2(System.Int32 parameter)"); } [Theory, CombinatorialData] public void ParameterScope_InMethodAttributeNameOf_SpeculatingWithReplacementAttributeInsideExisting(bool useCSharp10) { var source = @" class C { void M() { local(0); [My(positionA)] void local(int parameter) { } } [My(positionB)] void M2(int parameter) { } } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "; var parseOptions = useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11; var comp = CreateCompilation(source, parseOptions: parseOptions); comp.VerifyDiagnostics( // (8,13): error CS0103: The name 'positionA' does not exist in the current context // [My(positionA)] Diagnostic(ErrorCode.ERR_NameNotInContext, "positionA").WithArguments("positionA").WithLocation(8, 13), // (12,9): error CS0103: The name 'positionB' does not exist in the current context // [My(positionB)] Diagnostic(ErrorCode.ERR_NameNotInContext, "positionB").WithArguments("positionB").WithLocation(12, 9) ); var tree = comp.SyntaxTrees.Single(); var parentModel = comp.GetSemanticModel(tree); var localFuncPosition = tree.GetText().ToString().IndexOf("positionA", StringComparison.Ordinal); var methodPosition = tree.GetText().ToString().IndexOf("positionB", StringComparison.Ordinal); var attr = parseAttributeSyntax("[My(nameof(parameter))]", parseOptions); VerifyParameterSpeculation(parentModel, localFuncPosition, attr); VerifyParameterSpeculation(parentModel, methodPosition, attr); attr = parseAttributeSyntax("[My(parameter)]", parseOptions); VerifyParameterSpeculation(parentModel, localFuncPosition, attr, found: false); VerifyParameterSpeculation(parentModel, methodPosition, attr, found: false); return; static AttributeSyntax parseAttributeSyntax(string source, CSharpParseOptions parseOptions) => SyntaxFactory.ParseCompilationUnit($@"class X {{ {source} void M() {{ }} }}", options: parseOptions).DescendantNodes().OfType<AttributeSyntax>().Single(); } static void VerifyParameterSpeculation(SemanticModel parentModel, int localFuncPosition, AttributeSyntax attr1, bool found = true) { SemanticModel speculativeModel; var success = parentModel.TryGetSpeculativeSemanticModel(localFuncPosition, attr1, out speculativeModel); Assert.True(success); Assert.NotNull(speculativeModel); var symbolInfo = speculativeModel.GetSymbolInfo(getParameter(attr1)); if (found) { Assert.Equal(SymbolKind.Parameter, symbolInfo.Symbol.Kind); } else { Assert.Null(symbolInfo.Symbol); } return; static IdentifierNameSyntax getParameter(CSharpSyntaxNode node) { return node.DescendantNodes().OfType<IdentifierNameSyntax>().Where(i => i.Identifier.ValueText == "parameter").Single(); } } [Theory, CombinatorialData] public void ParameterScope_InIndexerAttributeNameOf(bool useCSharp10) { var source = @" class C { [My(nameof(parameter))] int this[int parameter] => 0; } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "; var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyParameter(comp, 0, "System.Int32 C.this[System.Int32 parameter] { get; }"); } [Theory, CombinatorialData] public void ParameterScope_InIndexerAttributeNameOf_SetterOnly(bool useCSharp10) { var source = @" class C { [My(nameof(parameter))] int this[int parameter] { set => throw null; } } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "; var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyParameter(comp, 0, "System.Int32 C.this[System.Int32 parameter] { set; }"); } [Theory, CombinatorialData] public void ParameterScope_InIndexerGetterAttributeNameOf(bool useCSharp10) { var source = @" class C { int this[int parameter] { [My(nameof(parameter))] get => throw null; } } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "; var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyParameter(comp, 0, "System.Int32 C.this[System.Int32 parameter].get"); } [Theory, CombinatorialData] public void ParameterScope_InIndexerSetterAttributeNameOf(bool useCSharp10) { var source = @" class C { int this[int parameter] { [My(nameof(parameter))] set => throw null; } } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "; var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyParameter(comp, 0, "void C.this[System.Int32 parameter].set"); } [Theory, CombinatorialData] public void ParameterScope_InIndexerInitSetterAttributeNameOf(bool useCSharp10) { var source = @" class C { int this[int parameter] { [My(nameof(parameter))] init => throw null; } } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "; var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyParameter(comp, 0, "void modreq(System.Runtime.CompilerServices.IsExternalInit) C.this[System.Int32 parameter].init"); } [Theory, CombinatorialData] public void ParameterScope_InMethodAttributeNameOf_Lambda(bool useCSharp10) { var source = @" class C { void M() { var x = [My(nameof(parameter))] int (int parameter) => 0; } } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "; var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyParameter(comp, 0, "lambda expression"); } [Fact] public void ParameterScope_InMethodAttributeNameOf_AnonymousFunctionWithImplicitParameters() { var source = @" class C { void M() { System.Func<int, int> x = [My(nameof(parameter))] delegate { return 1; } } } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (6,36): error CS0103: The name 'My' does not exist in the current context // System.Func<int, int> x = [My(nameof(parameter))] delegate { return 1; } Diagnostic(ErrorCode.ERR_NameNotInContext, "My").WithArguments("My").WithLocation(6, 36), // (6,46): error CS0103: The name 'parameter' does not exist in the current context // System.Func<int, int> x = [My(nameof(parameter))] delegate { return 1; } Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(6, 46), // (6,59): error CS1002: ; expected // System.Func<int, int> x = [My(nameof(parameter))] delegate { return 1; } Diagnostic(ErrorCode.ERR_SemicolonExpected, "delegate").WithLocation(6, 59), // (6,81): error CS1002: ; expected // System.Func<int, int> x = [My(nameof(parameter))] delegate { return 1; } Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(6, 81)); } [Theory, CombinatorialData] public void ParameterScope_InMethodAttributeNameOf_Delegate(bool useCSharp10) { var source = @" [My(nameof(parameter))] delegate int MyDelegate(int parameter); public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "; var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyParameter(comp, 0, "System.Int32 MyDelegate.Invoke(System.Int32 parameter)"); } [Theory, CombinatorialData] public void ParameterScope_InMethodAttributeNameOf_Delegate_ConflictingName(bool useCSharp10) { var source = @" [My(nameof(TParameter))] delegate int MyDelegate<TParameter>(int TParameter); public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "; var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyParameter(comp, 0, "System.Int32 MyDelegate<TParameter>.Invoke(System.Int32 TParameter)", parameterName: "TParameter"); } [Theory, CombinatorialData] public void ParameterScope_InMethodAttributeNameOf_Constructor(bool useCSharp10) { var source = @" class C { [My(nameof(parameter))] C(int parameter) { } } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "; var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyParameter(comp, 0, "C..ctor(System.Int32 parameter)"); } [Fact] public void ParameterScope_NotInMethodAttribute() { var comp = CreateCompilation(@" class C { void M() { local(0); [My(parameter)] // 1 void local(int parameter) { } } [My(parameter)] // 2 void M2(int parameter) { } } public class MyAttribute : System.Attribute { public MyAttribute(object o) { } } "); comp.VerifyDiagnostics( // (8,13): error CS0103: The name 'parameter' does not exist in the current context // [My(parameter)] // 1 Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(8, 13), // (12,9): error CS0103: The name 'parameter' does not exist in the current context // [My(parameter)] // 2 Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(12, 9) ); VerifyParameter(comp, 0, null); VerifyParameter(comp, 1, null); } [Fact] public void ParameterScope_NotInMethodAttributeTypeArgument() { var comp = CreateCompilation(@" class C { void M() { local(0); [My<parameter>] // 1 void local(int parameter) { } } [My<parameter>] // 2 void M2(int parameter) { } } public class MyAttribute<T> : System.Attribute { } "); comp.VerifyDiagnostics( // (8,13): error CS0246: The type or namespace name 'parameter' could not be found (are you missing a using directive or an assembly reference?) // [My<parameter>] // 1 Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "parameter").WithArguments("parameter").WithLocation(8, 13), // (12,9): error CS0246: The type or namespace name 'parameter' could not be found (are you missing a using directive or an assembly reference?) // [My<parameter>] // 2 Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "parameter").WithArguments("parameter").WithLocation(12, 9) ); VerifyParameter(comp, 0, null); VerifyParameter(comp, 1, null); } [Fact] public void ParameterScope_NotAsMethodAttributeType() { var comp = CreateCompilation(@" class C { void M() { local(null); [parameter] // 1 void local(System.Attribute parameter) { } } [parameter] // 2 void M2(System.Attribute parameter) { } } "); comp.VerifyDiagnostics( // (8,10): error CS0246: The type or namespace name 'parameterAttribute' could not be found (are you missing a using directive or an assembly reference?) // [parameter] // 1 Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "parameter").WithArguments("parameterAttribute").WithLocation(8, 10), // (8,10): error CS0246: The type or namespace name 'parameter' could not be found (are you missing a using directive or an assembly reference?) // [parameter] // 1 Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "parameter").WithArguments("parameter").WithLocation(8, 10), // (12,6): error CS0246: The type or namespace name 'parameterAttribute' could not be found (are you missing a using directive or an assembly reference?) // [parameter] // 2 Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "parameter").WithArguments("parameterAttribute").WithLocation(12, 6), // (12,6): error CS0246: The type or namespace name 'parameter' could not be found (are you missing a using directive or an assembly reference?) // [parameter] // 2 Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "parameter").WithArguments("parameter").WithLocation(12, 6) ); VerifyParameter(comp, 0, null); VerifyParameter(comp, 1, null); } [Fact] public void ParameterScope_NotInParameterAttribute() { var comp = CreateCompilation(@" class C { void M() { local(0); void local([My(parameter)] int parameter) => throw null; } void M2([My(parameter)] int parameter) => throw null; } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "); comp.VerifyDiagnostics( // (8,24): error CS0103: The name 'parameter' does not exist in the current context // void local([My(parameter)] int parameter) => throw null; Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(8, 24), // (11,17): error CS0103: The name 'parameter' does not exist in the current context // void M2([My(parameter)] int parameter) => throw null; Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(11, 17) ); VerifyParameter(comp, 0, null); VerifyParameter(comp, 1, null); } [Theory, CombinatorialData] public void ParameterScope_InParameterAttributeNameOf(bool useCSharp10) { var source = @" class C { void M() { local(0); void local([My(nameof(parameter))] int parameter) => throw null; } void M2([My(nameof(parameter))] int parameter) => throw null; } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "; var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyParameter(comp, 0, "void local(System.Int32 parameter)"); VerifyParameter(comp, 1, "void C.M2(System.Int32 parameter)"); } [Theory, CombinatorialData] public void ParameterScope_InParameterAttributeNameOf_ConflictingNames(bool useCSharp10) { var source = @" class C { void M() { local<object>(0); void local<TParameter>([My(nameof(TParameter))] int TParameter) => throw null; } void M2<TParameter>([My(nameof(TParameter))] int TParameter) => throw null; } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "; var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics( // (8,61): error CS0412: 'TParameter': a parameter, local variable, or local function cannot have the same name as a method type parameter // void local<TParameter>([My(nameof(TParameter))] int TParameter) => throw null; Diagnostic(ErrorCode.ERR_LocalSameNameAsTypeParam, "TParameter").WithArguments("TParameter").WithLocation(8, 61), // (11,54): error CS0412: 'TParameter': a parameter, local variable, or local function cannot have the same name as a method type parameter // void M2<TParameter>([My(nameof(TParameter))] int TParameter) => throw null; Diagnostic(ErrorCode.ERR_LocalSameNameAsTypeParam, "TParameter").WithArguments("TParameter").WithLocation(11, 54) ); VerifyParameter(comp, 0, "void local<TParameter>(System.Int32 TParameter)", parameterName: "TParameter"); VerifyParameter(comp, 1, "void C.M2<TParameter>(System.Int32 TParameter)", parameterName: "TParameter"); } [Theory, CombinatorialData] public void ParameterScope_InParameterAttributeNameOf_SpeculatingWithReplacementAttributeInsideExisting(bool useCSharp10) { var source = @" class C { void M() { local(0); void local([My(positionA)] int parameter) { } } void M2([My(positionB)] int parameter) { } } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "; var parseOptions = useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11; var comp = CreateCompilation(source, parseOptions: parseOptions); comp.VerifyDiagnostics( // (8,24): error CS0103: The name 'positionA' does not exist in the current context // void local([My(positionA)] int parameter) { } Diagnostic(ErrorCode.ERR_NameNotInContext, "positionA").WithArguments("positionA").WithLocation(8, 24), // (11,17): error CS0103: The name 'positionB' does not exist in the current context // void M2([My(positionB)] int parameter) { } Diagnostic(ErrorCode.ERR_NameNotInContext, "positionB").WithArguments("positionB").WithLocation(11, 17) ); var tree = comp.SyntaxTrees.Single(); var parentModel = comp.GetSemanticModel(tree); var localFuncPosition = tree.GetText().ToString().IndexOf("positionA", StringComparison.Ordinal); var methodPosition = tree.GetText().ToString().IndexOf("positionB", StringComparison.Ordinal); var attr = parseAttributeSyntax("[My(nameof(parameter))]", TestOptions.Regular10); VerifyParameterSpeculation(parentModel, localFuncPosition, attr); VerifyParameterSpeculation(parentModel, methodPosition, attr); attr = parseAttributeSyntax("[My(parameter)]", TestOptions.Regular10); VerifyParameterSpeculation(parentModel, localFuncPosition, attr, found: false); VerifyParameterSpeculation(parentModel, methodPosition, attr, found: false); return; static AttributeSyntax parseAttributeSyntax(string source, CSharpParseOptions parseOptions) => SyntaxFactory.ParseCompilationUnit($@"class X {{ {source} void M() {{ }} }}", options: parseOptions).DescendantNodes().OfType<AttributeSyntax>().Single(); } [Theory, CombinatorialData] public void ParameterScope_InParameterAttributeNameOf_Indexer(bool useCSharp10) { var source = @" class C { int this[[My(nameof(parameter))] int parameter] => throw null; } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "; var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyParameter(comp, 0, "System.Int32 C.this[System.Int32 parameter] { get; }"); } [Theory, CombinatorialData] public void ParameterScope_InParameterAttributeNameOf_Indexer_SetterOnly(bool useCSharp10) { var source = @" class C { int this[[My(nameof(parameter))] int parameter] { set => throw null; } } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "; var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyParameter(comp, 0, "System.Int32 C.this[System.Int32 parameter] { set; }"); } [Fact] public void ParameterScope_ValueLocalNotInPropertyOrAccessorAttributeNameOf() { var source = @" class C { [My(nameof(value))] int Property { set => throw null; } int Property2 { [My(nameof(value))] get => throw null; } int Property3 { [My(nameof(value))] set => throw null; } int Property4 { [My(nameof(value))] init => throw null; } } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "; var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }); comp.VerifyDiagnostics( // (4,16): error CS0103: The name 'value' does not exist in the current context // [My(nameof(value))] Diagnostic(ErrorCode.ERR_NameNotInContext, "value").WithArguments("value").WithLocation(4, 16), // (7,32): error CS0103: The name 'value' does not exist in the current context // int Property2 { [My(nameof(value))] get => throw null; } Diagnostic(ErrorCode.ERR_NameNotInContext, "value").WithArguments("value").WithLocation(7, 32), // (9,32): error CS0103: The name 'value' does not exist in the current context // int Property3 { [My(nameof(value))] set => throw null; } Diagnostic(ErrorCode.ERR_NameNotInContext, "value").WithArguments("value").WithLocation(9, 32), // (11,32): error CS0103: The name 'value' does not exist in the current context // int Property4 { [My(nameof(value))] init => throw null; } Diagnostic(ErrorCode.ERR_NameNotInContext, "value").WithArguments("value").WithLocation(11, 32) ); } [Fact, WorkItem(1556927, "https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1556927")] public void ParameterScope_ValueLocalNotInPropertyOrAccessorAttributeNameOf_UnknownAccessor() { var source = @" class C { int Property4 { [My(nameof(value))] unknown => throw null; } } public class MyAttribute : System.Attribute { public MyAttribute(string name) { } } "; var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }); comp.VerifyDiagnostics( // (4,9): error CS0548: 'C.Property4': property or indexer must have at least one accessor // int Property4 { [My(nameof(value))] unknown => throw null; } Diagnostic(ErrorCode.ERR_PropertyWithNoAccessors, "Property4").WithArguments("C.Property4").WithLocation(4, 9), // (4,41): error CS1014: A get or set accessor expected // int Property4 { [My(nameof(value))] unknown => throw null; } Diagnostic(ErrorCode.ERR_GetOrSetExpected, "unknown").WithLocation(4, 41) ); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var node = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>() .Where(i => i.Identifier.ValueText == "value") .Where(i => i.Ancestors().Any(a => a.IsKind(SyntaxKind.Attribute))) .Single(); Assert.Null(model.GetSymbolInfo(node).Symbol); } [Theory, CombinatorialData] public void ParameterScope_InParameterAttributeNameOf_Constructor(bool useCSharp10) { var source = @" class C { C([My(nameof(parameter))] int parameter) => throw null; } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "; var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyParameter(comp, 0, "C..ctor(System.Int32 parameter)"); } [Theory, CombinatorialData] public void ParameterScope_InParameterAttributeNameOf_Delegate(bool useCSharp10) { var source = @" delegate void MyDelegate([My(nameof(parameter))] int parameter); public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "; var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyParameter(comp, 0, "void MyDelegate.Invoke(System.Int32 parameter)"); } [Theory, CombinatorialData] public void ParameterScope_InParameterAttributeNameOf_ConversionOperator(bool useCSharp10) { var source = @" class C { public static implicit operator C([My(nameof(parameter))] int parameter) => throw null; } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "; var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyParameter(comp, 0, "C C.op_Implicit(System.Int32 parameter)"); } [Theory, CombinatorialData] public void ParameterScope_InParameterAttributeNameOf_Operator(bool useCSharp10) { var source = @" class C { public static C operator +([My(nameof(parameter))] int parameter, C other) => throw null; } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "; var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyParameter(comp, 0, "C C.op_Addition(System.Int32 parameter, C other)"); } [Theory, CombinatorialData] public void ParameterScope_InParameterAttributeNameOf_Lambda(bool useCSharp10) { var source = @" class C { void M() { var x = ([My(nameof(parameter))] int parameter) => 0; } } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "; var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyParameter(comp, 0, "lambda expression"); } [Fact] public void ParameterScope_InParameterAttributeNameOf_AnonymousDelegate() { var source = @" class C { void M() { var x = delegate ([My(nameof(parameter))] int parameter) { return 0; }; } } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "; var comp = CreateCompilation(source); comp.VerifyDiagnostics( // (6,27): error CS7014: Attributes are not valid in this context. // var x = delegate ([My(nameof(parameter))] int parameter) { return 0; }; Diagnostic(ErrorCode.ERR_AttributesNotAllowed, "[My(nameof(parameter))]").WithLocation(6, 27) ); VerifyParameter(comp, 0, "lambda expression"); } [Theory, CombinatorialData] public void ParameterScope_InTypeParameterAttributeNameOf(bool useCSharp10) { var source = @" class C { void M() { local<object>(0); void local<[My(nameof(parameter))] T>(int parameter) { } } void M2<[My(nameof(parameter))] T>(int parameter) { } } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "; var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyParameter(comp, 0, "void local<T>(System.Int32 parameter)"); VerifyParameter(comp, 1, "void C.M2<T>(System.Int32 parameter)"); } [Theory, CombinatorialData] public void ParameterScope_InTypeParameterAttributeNameOf_SpeculatingWithReplacementAttributeInsideExisting(bool useCSharp10) { var source = @" class C { void M() { local<object>(0); void local<[My(positionA)] T>(int parameter) { } } void M2<[My(positionB)] T>(int parameter) { } } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "; var parseOptions = useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11; var comp = CreateCompilation(source, parseOptions: parseOptions); comp.VerifyDiagnostics( // (8,24): error CS0103: The name 'positionA' does not exist in the current context // void local([My(positionA)] int parameter) { } Diagnostic(ErrorCode.ERR_NameNotInContext, "positionA").WithArguments("positionA").WithLocation(8, 24), // (11,17): error CS0103: The name 'positionB' does not exist in the current context // void M2([My(positionB)] int parameter) { } Diagnostic(ErrorCode.ERR_NameNotInContext, "positionB").WithArguments("positionB").WithLocation(11, 17) ); var tree = comp.SyntaxTrees.Single(); var parentModel = comp.GetSemanticModel(tree); var localFuncPosition = tree.GetText().ToString().IndexOf("positionA", StringComparison.Ordinal); var methodPosition = tree.GetText().ToString().IndexOf("positionB", StringComparison.Ordinal); var attr = parseAttributeSyntax("[My(nameof(parameter))]", TestOptions.Regular10); VerifyParameterSpeculation(parentModel, localFuncPosition, attr); VerifyParameterSpeculation(parentModel, methodPosition, attr); attr = parseAttributeSyntax("[My(parameter)]", TestOptions.Regular10); VerifyParameterSpeculation(parentModel, localFuncPosition, attr, found: false); VerifyParameterSpeculation(parentModel, methodPosition, attr, found: false); return; static AttributeSyntax parseAttributeSyntax(string source, CSharpParseOptions parseOptions) => SyntaxFactory.ParseCompilationUnit($@"class X {{ {source} void M() {{ }} }}", options: parseOptions).DescendantNodes().OfType<AttributeSyntax>().Single(); } [Theory, CombinatorialData] public void ParameterScope_InTypeParameterAttributeNameOf_Delegate(bool useCSharp10) { var source = @" delegate int MyDelegate<[My(nameof(parameter))] T>(int parameter); public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "; var comp = CreateCompilation(source, parseOptions: useCSharp10 ? TestOptions.Regular10 : TestOptions.Regular11); comp.VerifyDiagnostics(); VerifyParameter(comp, 0, "System.Int32 MyDelegate<T>.Invoke(System.Int32 parameter)"); } [Fact] public void ParameterScope_NotAsParameterAttributeType() { var comp = CreateCompilation(@" class C { void M() { local(null); void local([parameter] System.Attribute parameter) => throw null; } void M2([parameter] System.Attribute parameter) => throw null; } "); comp.VerifyDiagnostics( // (8,21): error CS0246: The type or namespace name 'parameterAttribute' could not be found (are you missing a using directive or an assembly reference?) // void local([parameter] System.Attribute parameter) => throw null; Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "parameter").WithArguments("parameterAttribute").WithLocation(8, 21), // (8,21): error CS0246: The type or namespace name 'parameter' could not be found (are you missing a using directive or an assembly reference?) // void local([parameter] System.Attribute parameter) => throw null; Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "parameter").WithArguments("parameter").WithLocation(8, 21), // (11,14): error CS0246: The type or namespace name 'parameterAttribute' could not be found (are you missing a using directive or an assembly reference?) // void M2([parameter] System.Attribute parameter) => throw null; Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "parameter").WithArguments("parameterAttribute").WithLocation(11, 14), // (11,14): error CS0246: The type or namespace name 'parameter' could not be found (are you missing a using directive or an assembly reference?) // void M2([parameter] System.Attribute parameter) => throw null; Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "parameter").WithArguments("parameter").WithLocation(11, 14) ); VerifyParameter(comp, 0, null); } [Fact] public void ParameterScope_NotInReturnType() { var comp = CreateCompilation(@" class C { void M() { local(0); parameter local(int parameter) => throw null; } parameter M2(int parameter) => throw null; } "); comp.VerifyDiagnostics( // (8,9): error CS0246: The type or namespace name 'parameter' could not be found (are you missing a using directive or an assembly reference?) // parameter local(int parameter) => throw null; Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "parameter").WithArguments("parameter").WithLocation(8, 9), // (11,5): error CS0246: The type or namespace name 'parameter' could not be found (are you missing a using directive or an assembly reference?) // parameter M2(int parameter) => throw null; Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "parameter").WithArguments("parameter").WithLocation(11, 5) ); } [Fact] public void ParameterScope_NotInParameterType() { var comp = CreateCompilation(@" class C { void M() { local(null); void local(parameter parameter) => throw null; } void M2<TParameter>(parameter parameter) => throw null; } "); comp.VerifyDiagnostics( // (8,20): error CS0246: The type or namespace name 'parameter' could not be found (are you missing a using directive or an assembly reference?) // void local(parameter parameter) => throw null; Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "parameter").WithArguments("parameter").WithLocation(8, 20), // (11,25): error CS0246: The type or namespace name 'parameter' could not be found (are you missing a using directive or an assembly reference?) // void M2<TParameter>(parameter parameter) => throw null; Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "parameter").WithArguments("parameter").WithLocation(11, 25) ); } [Fact] public void ParameterScope_NotInTypeConstraint() { var comp = CreateCompilation(@" class C { void M() { local<object>(0); M2<object>(0); void local<TParameter>(int parameter) where TParameter : parameter => throw null; } void M2<TParameter>(int parameter) where TParameter : parameter => throw null; } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "); comp.VerifyDiagnostics( // (6,9): error CS0311: The type 'object' cannot be used as type parameter 'TParameter' in the generic type or method 'local<TParameter>(int)'. There is no implicit reference conversion from 'object' to 'parameter'. // local<object>(0); Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "local<object>").WithArguments("local<TParameter>(int)", "parameter", "TParameter", "object").WithLocation(6, 9), // (7,9): error CS0311: The type 'object' cannot be used as type parameter 'TParameter' in the generic type or method 'C.M2<TParameter>(int)'. There is no implicit reference conversion from 'object' to 'parameter'. // M2<object>(0); Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "M2<object>").WithArguments("C.M2<TParameter>(int)", "parameter", "TParameter", "object").WithLocation(7, 9), // (9,66): error CS0246: The type or namespace name 'parameter' could not be found (are you missing a using directive or an assembly reference?) // void local<TParameter>(int parameter) where TParameter : parameter => throw null; Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "parameter").WithArguments("parameter").WithLocation(9, 66), // (12,59): error CS0246: The type or namespace name 'parameter' could not be found (are you missing a using directive or an assembly reference?) // void M2<TParameter>(int parameter) where TParameter : parameter => throw null; Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "parameter").WithArguments("parameter").WithLocation(12, 59) ); VerifyParameter(comp, 0, null); VerifyParameter(comp, 1, null); } [Fact] public void ParameterScope_NotInParameterDefaultDefaultValue() { var comp = CreateCompilation(@" class C { void M() { local(); void local(string parameter = default(parameter)) => throw null; } void M2(string parameter = default(parameter)) => throw null; } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "); comp.VerifyDiagnostics( // (8,27): error CS1750: A value of type 'parameter' cannot be used as a default parameter because there are no standard conversions to type 'string' // void local(string parameter = default(parameter)) => throw null; Diagnostic(ErrorCode.ERR_NoConversionForDefaultParam, "parameter").WithArguments("parameter", "string").WithLocation(8, 27), // (8,47): error CS0246: The type or namespace name 'parameter' could not be found (are you missing a using directive or an assembly reference?) // void local(string parameter = default(parameter)) => throw null; Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "parameter").WithArguments("parameter").WithLocation(8, 47), // (11,20): error CS1750: A value of type 'parameter' cannot be used as a default parameter because there are no standard conversions to type 'string' // void M2(string parameter = default(parameter)) => throw null; Diagnostic(ErrorCode.ERR_NoConversionForDefaultParam, "parameter").WithArguments("parameter", "string").WithLocation(11, 20), // (11,40): error CS0246: The type or namespace name 'parameter' could not be found (are you missing a using directive or an assembly reference?) // void M2(string parameter = default(parameter)) => throw null; Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "parameter").WithArguments("parameter").WithLocation(11, 40) ); VerifyParameter(comp, 0, null); VerifyParameter(comp, 1, null); } [Fact] public void ParameterScope_NotInParameterNameOfDefaultValue() { var comp = CreateCompilation(@" class C { void M() { local(); void local(string parameter = nameof(parameter)) => throw null; } void M2(string parameter = nameof(parameter)) => throw null; } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "); comp.VerifyDiagnostics( // (8,46): error CS0103: The name 'parameter' does not exist in the current context // void local(string parameter = nameof(parameter)) => throw null; Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(8, 46), // (11,39): error CS0103: The name 'parameter' does not exist in the current context // void M2(string parameter = nameof(parameter)) => throw null; Diagnostic(ErrorCode.ERR_NameNotInContext, "parameter").WithArguments("parameter").WithLocation(11, 39) ); VerifyParameter(comp, 0, null); VerifyParameter(comp, 1, null); } [Fact] public void MethodScope_InParameterAttribute() { var comp = CreateCompilation(@" class C { void M() { local<object>(0); void local<TParameter>([My(local)] int i) => throw null; } void M2<TParameter>([My(M2)] int i) => throw null; } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "); comp.VerifyDiagnostics( // (8,36): error CS1503: Argument 1: cannot convert from 'method group' to 'string' // void local<TParameter>([My(local)] int i) => throw null; Diagnostic(ErrorCode.ERR_BadArgType, "local").WithArguments("1", "method group", "string").WithLocation(8, 36), // (11,29): error CS1503: Argument 1: cannot convert from 'method group' to 'string' // void M2<TParameter>([My(M2)] int i) => throw null; Diagnostic(ErrorCode.ERR_BadArgType, "M2").WithArguments("1", "method group", "string").WithLocation(11, 29) ); } [Fact] public void MethodScope_InParameterAttributeNameOf() { var comp = CreateCompilation(@" class C { void M() { local<object>(0); void local<TParameter>([My(nameof(local))] int i) => throw null; } void M2<TParameter>([My(nameof(M2))] int i) => throw null; } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "); comp.VerifyDiagnostics(); } [Fact] public void MethodScope_InTypeParameterAttribute() { var comp = CreateCompilation(@" class C { void M() { local<object>(0); void local<[My(local)] TParameter>(int i) => throw null; } void M2<[My(M2)] TParameter>(int i) => throw null; } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "); comp.VerifyDiagnostics( // (8,24): error CS1503: Argument 1: cannot convert from 'method group' to 'string' // void local<[My(local)] TParameter>(int i) => throw null; Diagnostic(ErrorCode.ERR_BadArgType, "local").WithArguments("1", "method group", "string").WithLocation(8, 24), // (11,17): error CS1503: Argument 1: cannot convert from 'method group' to 'string' // void M2<[My(M2)] TParameter>(int i) => throw null; Diagnostic(ErrorCode.ERR_BadArgType, "M2").WithArguments("1", "method group", "string").WithLocation(11, 17) ); } [Fact] public void MethodScope_InTypeParameterAttributeNameOf() { var comp = CreateCompilation(@" class C { void M() { local<object>(0); void local<[My(nameof(local))] TParameter>(int i) => throw null; } void M2<[My(nameof(M2))] TParameter>(int i) => throw null; } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "); comp.VerifyDiagnostics(); } [Fact] public void MethodScope_InMethodAttribute() { var comp = CreateCompilation(@" class C { void M() { local<object>(0); [My(local)] void local<TParameter>(int i) => throw null; } [My(M2)] void M2<TParameter>(int i) => throw null; } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "); comp.VerifyDiagnostics( // (8,13): error CS1503: Argument 1: cannot convert from 'method group' to 'string' // [My(local)] Diagnostic(ErrorCode.ERR_BadArgType, "local").WithArguments("1", "method group", "string").WithLocation(8, 13), // (12,9): error CS1503: Argument 1: cannot convert from 'method group' to 'string' // [My(M2)] Diagnostic(ErrorCode.ERR_BadArgType, "M2").WithArguments("1", "method group", "string").WithLocation(12, 9) ); } [Fact] public void MethodScope_InMethodAttributeNameOf() { var comp = CreateCompilation(@" class C { void M() { local<object>(0); [My(nameof(local))] void local<TParameter>(int i) => throw null; } [My(nameof(M2))] void M2<TParameter>(int i) => throw null; } public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } "); comp.VerifyDiagnostics(); } [Fact, WorkItem(1556927, "https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1556927")] public void LambdaOutsideMemberModel() { var text = @" public class MyAttribute : System.Attribute { public MyAttribute(string name1) { } } int P { badAccessorName { M([My(nameof(P))] env => env); "; var comp = CreateCompilation(text); var tree = comp.SyntaxTrees.First(); var model = comp.GetSemanticModel(tree); var node = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>() .Where(i => i.Identifier.ValueText == "P") .Where(i => i.Ancestors().Any(a => a.IsKind(SyntaxKind.Attribute))) .Single(); // int P ... should be pulled into MyAttribute as it's more likely that there's an errant close curly in the // type, versus a property in a compilation unit. var symbol = model.GetSymbolInfo(node).Symbol; Assert.NotNull(symbol); var property = (IPropertySymbol)symbol; Assert.Equal("P", property.Name); Assert.Equal("MyAttribute", property.ContainingType.Name); } [Fact, WorkItem(43697, "https://github.com/dotnet/roslyn/issues/43697")] public void DefiniteAssignment_01() { var text = @" using System; using System.Threading.Tasks; #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call. public class C { public void M() { bool a; M1(); Console.WriteLine(a); async Task M1() { if ("""" == String.Empty) { throw new Exception(); } else { a = true; } } } } "; CreateCompilation(text).VerifyDiagnostics( // (13,27): error CS0165: Use of unassigned local variable 'a' // Console.WriteLine(a); Diagnostic(ErrorCode.ERR_UseDefViolation, "a").WithArguments("a").WithLocation(13, 27) ); } [Fact, WorkItem(43697, "https://github.com/dotnet/roslyn/issues/43697")] public void DefiniteAssignment_02() { var text = @" using System; using System.Threading.Tasks; public class C { public void M() { bool a; M1(); Console.WriteLine(a); Task M1() { if ("""" == String.Empty) { throw new Exception(); } else { a = true; } return null; } } } "; CreateCompilation(text).VerifyDiagnostics(); } [Fact, WorkItem(43697, "https://github.com/dotnet/roslyn/issues/43697")] public void DefiniteAssignment_03() { var text = @" using System; using System.Threading.Tasks; #pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call. public class C { public void M() { bool a; M1(); Console.WriteLine(a); async Task M1() { await Task.Yield(); if ("""" == String.Empty) { throw new Exception(); } else { a = true; } } } } "; CreateCompilation(text).VerifyDiagnostics( // (13,27): error CS0165: Use of unassigned local variable 'a' // Console.WriteLine(a); Diagnostic(ErrorCode.ERR_UseDefViolation, "a").WithArguments("a").WithLocation(13, 27) ); } [Fact, WorkItem(43697, "https://github.com/dotnet/roslyn/issues/43697")] public void DefiniteAssignment_04() { var text = @" using System; using System.Threading.Tasks; public class C { public async Task M() { bool a; await M1(); Console.WriteLine(a); async Task M1() { if ("""" == String.Empty) { throw new Exception(); } else { a = true; } } } } "; CreateCompilation(text).VerifyDiagnostics( // (11,27): error CS0165: Use of unassigned local variable 'a' // Console.WriteLine(a); Diagnostic(ErrorCode.ERR_UseDefViolation, "a").WithArguments("a").WithLocation(11, 27) ); } [Fact, WorkItem(43697, "https://github.com/dotnet/roslyn/issues/43697")] public void DefiniteAssignment_05() { var text = @" using System; using System.Threading.Tasks; public class C { public async Task M() { bool a; await M1(); Console.WriteLine(a); async Task M1() { await Task.Yield(); if ("""" == String.Empty) { throw new Exception(); } else { a = true; } } } } "; CreateCompilation(text).VerifyDiagnostics( // (11,27): error CS0165: Use of unassigned local variable 'a' // Console.WriteLine(a); Diagnostic(ErrorCode.ERR_UseDefViolation, "a").WithArguments("a").WithLocation(11, 27) ); } [Fact] public void TestLocalFunctionDeclaration() { var compilation = CreateCompilation(""" class Test { void M() { int LocalFunc(string s) {} } } """); var tree = compilation.SyntaxTrees[0]; var semanticModel = compilation.GetSemanticModel(tree); var root = tree.GetCompilationUnitRoot(); var localFunction = root.DescendantNodes().OfType<LocalFunctionStatementSyntax>().Single(); IMethodSymbol methodSymbol = semanticModel.GetDeclaredSymbol(localFunction); Assert.Equal("System.Int32 LocalFunc(System.String s)", methodSymbol.ToTestDisplayString()); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73905")] public void IdentifierInNameofInAttributeOnLocalFunctionInAccessor() { var src = """ using System; [AttributeUsage(AttributeTargets.All)] class A : Attribute { public A(string s) { } } class C { event EventHandler E { add { [param: A(nameof(p))] void F(int p) { } } remove { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (15,14): warning CS0657: 'param' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'method, return'. All attributes in this block will be ignored. // [param: A(nameof(p))] void F(int p) { } Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "param").WithArguments("param", "method, return").WithLocation(15, 14), // (15,40): warning CS8321: The local function 'F' is declared but never used // [param: A(nameof(p))] void F(int p) { } Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "F").WithArguments("F").WithLocation(15, 40)); var tree = comp.SyntaxTrees.Single(); var model = comp.GetSemanticModel(tree); var nameof = GetSyntax<InvocationExpressionSyntax>(tree, "nameof(p)"); var p = nameof.ArgumentList.Arguments[0].Expression; Assert.Equal("System.Int32", model.GetTypeInfo(p).Type.ToTestDisplayString()); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73905")] public void IdentifierInNameofInAttributeOnLocalFunctionInMethod() { var src = """ using System; [AttributeUsage(AttributeTargets.All)] class A : Attribute { public A(string s) { } } class C { void M() { [param: A(nameof(p))] void F(int p) { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (13,10): warning CS0657: 'param' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'method, return'. All attributes in this block will be ignored. // [param: A(nameof(p))] void F(int p) { } Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "param").WithArguments("param", "method, return").WithLocation(13, 10), // (13,36): warning CS8321: The local function 'F' is declared but never used // [param: A(nameof(p))] void F(int p) { } Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "F").WithArguments("F").WithLocation(13, 36)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73905")] public void IdentifierInNameofInAttributeOnLocalFunctionInMethodWithParameter() { var src = """ using System; [AttributeUsage(AttributeTargets.All)] class A : Attribute { public A(string s) { } } class C { void M(int p) { [param: A(nameof(p))] void F(int p2) { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (13,10): warning CS0657: 'param' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'method, return'. All attributes in this block will be ignored. // [param: A(nameof(p))] void F(int p2) { } Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "param").WithArguments("param", "method, return").WithLocation(13, 10), // (13,36): warning CS8321: The local function 'F' is declared but never used // [param: A(nameof(p))] void F(int p2) { } Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "F").WithArguments("F").WithLocation(13, 36)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73905")] public void IdentifierInNameofInParamAttributeOnLocalFunctionInPrimaryConstructorType() { var src = """ using System; [AttributeUsage(AttributeTargets.All)] class A : Attribute { public A(string s) { } } class C(int p) { void M() { [param: A(nameof(p))] void F(int p2) { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (9,13): warning CS9113: Parameter 'p' is unread. // class C(int p) Diagnostic(ErrorCode.WRN_UnreadPrimaryConstructorParameter, "p").WithArguments("p").WithLocation(9, 13), // (13,10): warning CS0657: 'param' is not a valid attribute location for this declaration. Valid attribute locations for this declaration are 'method, return'. All attributes in this block will be ignored. // [param: A(nameof(p))] void F(int p2) { } Diagnostic(ErrorCode.WRN_AttributeLocationOnBadDeclaration, "param").WithArguments("param", "method, return").WithLocation(13, 10), // (13,36): warning CS8321: The local function 'F' is declared but never used // [param: A(nameof(p))] void F(int p2) { } Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "F").WithArguments("F").WithLocation(13, 36)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73905")] public void IdentifierInNameofInAttributeOnLocalFunctionInPrimaryConstructorType() { var src = """ using System; [AttributeUsage(AttributeTargets.All)] class A : Attribute { public A(string s) { } } class C(int p) { void M() { [A(nameof(p))] void F() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (9,13): warning CS9113: Parameter 'p' is unread. // class C(int p) Diagnostic(ErrorCode.WRN_UnreadPrimaryConstructorParameter, "p").WithArguments("p").WithLocation(9, 13), // (13,29): warning CS8321: The local function 'F' is declared but never used // [A(nameof(p))] void F() { } Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "F").WithArguments("F").WithLocation(13, 29)); } [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/73905")] public void IdentifierInAttributeOnLocalFunctionInPrimaryConstructorType() { var src = """ using System; [AttributeUsage(AttributeTargets.All)] class A : Attribute { public A(string s) { } } class C(string p) { void M() { [A(p)] void F() { } } } """; var comp = CreateCompilation(src); comp.VerifyEmitDiagnostics( // (9,16): warning CS9113: Parameter 'p' is unread. // class C(string p) Diagnostic(ErrorCode.WRN_UnreadPrimaryConstructorParameter, "p").WithArguments("p").WithLocation(9, 16), // (13,12): error CS9105: Cannot use primary constructor parameter 'string p' in this context. // [A(p)] void F() { } Diagnostic(ErrorCode.ERR_InvalidPrimaryConstructorParameterReference, "p").WithArguments("string p").WithLocation(13, 12), // (13,12): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type // [A(p)] void F() { } Diagnostic(ErrorCode.ERR_BadAttributeArgument, "p").WithLocation(13, 12), // (13,21): warning CS8321: The local function 'F' is declared but never used // [A(p)] void F() { } Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "F").WithArguments("F").WithLocation(13, 21)); } [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/76528")] [InlineData("")] [InlineData("static ")] public void Repro76528(string modifiers) { var source = $$""" #nullable enable using System; using System.Diagnostics.CodeAnalysis; public class C { public static string? _field; public Action Prop1 { get; } = () => { init(); Console.WriteLine(_field.Length); [MemberNotNull(nameof(_field))] {{modifiers}}void init() => _field ??= ""; }; } """; var comp = CreateCompilation([source, MemberNotNullAttributeDefinition]); comp.VerifyEmitDiagnostics(); } [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/76528")] [InlineData("")] [InlineData("static ")] public void Repro76528_FieldInitializer(string modifiers) { var source = $$""" #nullable enable using System; using System.Diagnostics.CodeAnalysis; public class C { public static string? _field; public Action _field2 = () => { init(); Console.WriteLine(_field.Length); [MemberNotNull(nameof(_field))] {{modifiers}}void init() => _field ??= ""; }; } """; var comp = CreateCompilation([source, MemberNotNullAttributeDefinition]); comp.VerifyEmitDiagnostics(); } [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/76528")] [InlineData("")] [InlineData("static ")] public void Repro76528_StaticLambda(string modifiers) { var source = $$""" #nullable enable using System; using System.Diagnostics.CodeAnalysis; public class C { public static string? _field; public Action Prop1 { get; } = static () => { init(); Console.WriteLine(_field.Length); [MemberNotNull(nameof(_field))] {{modifiers}}void init() => _field ??= ""; }; } """; var comp = CreateCompilation([source, MemberNotNullAttributeDefinition]); comp.VerifyEmitDiagnostics(); } [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/76528")] [CombinatorialData] public void Repro76528_FieldInitializer_PrimaryConstructor(bool isStatic) { var source = $$""" #nullable enable using System; using System.Diagnostics.CodeAnalysis; public class C(string p) { public static string? _field; public Action _field2 = () => { init(); Console.WriteLine(_field.Length); [MemberNotNull(nameof(_field))] {{(isStatic ? "static " : "")}}void init() => _field ??= p; }; string M() => p; } """; var comp = CreateCompilation([source, MemberNotNullAttributeDefinition]); comp.VerifyEmitDiagnostics(isStatic ? [ // (16,42): error CS8421: A static local function cannot contain a reference to 'p'. // static void init() => _field ??= p; Diagnostic(ErrorCode.ERR_StaticLocalFunctionCannotCaptureVariable, "p").WithArguments("p").WithLocation(16, 42) ] : []); } [Fact] public void SimpleIteratorLocalFunction() { var source = """ using System.Collections.Generic; using System.Threading.Tasks; class C { void M() { #pragma warning disable 8321 // The local function 'X' is declared but never used IEnumerable<int> I1() { yield return 1; } async IAsyncEnumerable<int> I2() { await Task.Yield(); yield return 1; } } } """; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net60); comp.VerifyDiagnostics(); var syntaxTree = comp.SyntaxTrees.Single(); var semanticModel = comp.GetSemanticModel(syntaxTree); var localFunctionSyntaxes = syntaxTree.GetRoot().DescendantNodes().OfType<LocalFunctionStatementSyntax>().ToArray(); var i1Syntax = localFunctionSyntaxes[0]; IMethodSymbol i1Symbol = semanticModel.GetDeclaredSymbol(i1Syntax); Assert.True(i1Symbol.IsIterator); var i2Syntax = localFunctionSyntaxes[1]; IMethodSymbol i2Symbol = semanticModel.GetDeclaredSymbol(i2Syntax); Assert.True(i2Symbol.IsIterator); } [Fact] public void LocalFunctionJustReturnsEnumerable_NotIterator() { var source = """ using System.Collections.Generic; class C { void M() { #pragma warning disable 8321 // The local function 'X' is declared but never used IEnumerable<int> I1() { return []; } IAsyncEnumerable<int> I2() { return default; } } } """; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net60); comp.VerifyDiagnostics(); var syntaxTree = comp.SyntaxTrees.Single(); var semanticModel = comp.GetSemanticModel(syntaxTree); var localFunctionSyntaxes = syntaxTree.GetRoot().DescendantNodes().OfType<LocalFunctionStatementSyntax>().ToArray(); var i1Syntax = localFunctionSyntaxes[0]; IMethodSymbol i1Symbol = semanticModel.GetDeclaredSymbol(i1Syntax); Assert.False(i1Symbol.IsIterator); var i2Syntax = localFunctionSyntaxes[1]; IMethodSymbol i2Symbol = semanticModel.GetDeclaredSymbol(i2Syntax); Assert.False(i2Symbol.IsIterator); } } }