diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceTypeParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceTypeParameterSymbol.cs index 8ed6ae131e6c6644d05fb18b13bce15f0426974f..6cdf27683e545d062306aba81b14e4e0b745efab 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceTypeParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceTypeParameterSymbol.cs @@ -179,7 +179,8 @@ internal virtual CustomAttributesBag GetAttributesBag() { lazyAttributesStored = LoadAndValidateAttributes( OneOrMany.Create(this.MergedAttributeDeclarationSyntaxLists), - ref _lazyCustomAttributesBag); + ref _lazyCustomAttributesBag, + binderOpt: (ContainingSymbol as LocalFunctionSymbol)?.SignatureBinder); } else { diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs index f1812e8ed7a7913a55de545a9b2af47133e83f98..4fdb26e1820955944b48bd1e07cd4a68d470795a 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs @@ -30,6 +30,90 @@ internal void VerifyDiagnostics(string source, CSharpCompilationOptions options, [CompilerTrait(CompilerFeature.LocalFunctions)] public class LocalFunctionTests : LocalFunctionsTestBase { + [Fact] + public void LocalFunctionTypeParametersUseCorrectBinder() + { + var text = @" +class C +{ + static void M() + { + void local<[X]T>() {} + } +}"; + var tree = SyntaxFactory.ParseSyntaxTree(text); + var comp = CreateStandardCompilation(tree); + var model = comp.GetSemanticModel(tree, ignoreAccessibility: true); + + var newTree = SyntaxFactory.ParseSyntaxTree(text + " "); + var m = newTree.GetRoot() + .DescendantNodes().OfType().Single(); + + Assert.True(model.TryGetSpeculativeSemanticModelForMethodBody(m.Body.SpanStart, m, out model)); + + var x = newTree.GetRoot().DescendantNodes().OfType().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,20): error CS8205: Attributes are not allowed on local function parameters or type parameters + // void local<[X]T>() {} + Diagnostic(ErrorCode.ERR_AttributesInLocalFuncDecl, "[X]").WithLocation(6, 20), + // (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)); + } + + [Fact] + public void LocalFunctionAttribute() + { + const string text = @" +using System; +class A : Attribute {} + +class C +{ + static void M() + { + void local<[A]T>() {} + } +}"; + var tree = SyntaxFactory.ParseSyntaxTree(text); + var comp = CreateStandardCompilation(tree); + var model = comp.GetSemanticModel(tree); + var a = tree.GetRoot().DescendantNodes() + .OfType().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().Single(); + + Assert.True(model.TryGetSpeculativeSemanticModelForMethodBody(m.Body.SpanStart, m, out model)); + + a = newTree.GetRoot().DescendantNodes().OfType().ElementAt(2); + Assert.Equal("A", a.Identifier.Text); + + // If we aren't using the right binder here, the compiler crashes going through the binder factory + var info = model.GetSymbolInfo(a); + // This behavior is wrong. See https://github.com/dotnet/roslyn/issues/24135 + Assert.Equal(attrType, info.Symbol); + } + [Fact] public void UnsafeLocal() {