From 8576ad641f0d85a5cdd767883a99880eaeb16be2 Mon Sep 17 00:00:00 2001 From: Youssef1313 Date: Sat, 5 Mar 2022 20:33:06 +0200 Subject: [PATCH 1/3] Fix type parameter scoping for local functions --- .../Symbols/Source/LocalFunctionSymbol.cs | 13 ++++---- .../Semantic/Semantics/LocalFunctionTests.cs | 33 +++++++++++++++++++ 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs index 34d250feb9f6a..02234e1478a3d 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs @@ -15,6 +15,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols internal sealed class LocalFunctionSymbol : SourceMethodSymbolWithAttributes { private readonly Binder _binder; + private readonly Binder? _withTypeParamsBinder; private readonly Symbol _containingSymbol; private readonly DeclarationModifiers _declarationModifiers; private readonly ImmutableArray _typeParameters; @@ -60,7 +61,7 @@ public LocalFunctionSymbol( if (syntax.TypeParameterList != null) { - binder = new WithMethodTypeParametersBinder(this, binder); + _withTypeParamsBinder = new WithMethodTypeParametersBinder(this, binder); _typeParameters = MakeTypeParameters(_declarationDiagnostics); } else @@ -105,7 +106,7 @@ public LocalFunctionSymbol( /// internal Binder ScopeBinder { get; } - internal override Binder ParameterBinder => _binder; + internal override Binder ParameterBinder => _withTypeParamsBinder ?? _binder; internal LocalFunctionStatementSyntax Syntax => (LocalFunctionStatementSyntax)syntaxReferenceOpt.GetSyntax(); @@ -180,7 +181,7 @@ private void ComputeParameters() var diagnostics = BindingDiagnosticBag.GetInstance(_declarationDiagnostics); var parameters = ParameterHelpers.MakeParameters( - _binder, + _withTypeParamsBinder ?? _binder, this, this.Syntax.ParameterList, arglistToken: out arglistToken, @@ -239,7 +240,7 @@ internal void ComputeReturnType() var diagnostics = BindingDiagnosticBag.GetInstance(_declarationDiagnostics); TypeSyntax returnTypeSyntax = Syntax.ReturnType; - TypeWithAnnotations returnType = _binder.BindType(returnTypeSyntax.SkipRef(), diagnostics); + TypeWithAnnotations returnType = (_withTypeParamsBinder ?? _binder).BindType(returnTypeSyntax.SkipRef(), diagnostics); var compilation = DeclaringCompilation; @@ -476,7 +477,7 @@ public override ImmutableArray> GetTypeParam var syntax = Syntax; var diagnostics = BindingDiagnosticBag.GetInstance(_declarationDiagnostics); var constraints = this.MakeTypeParameterConstraintTypes( - _binder, + _withTypeParamsBinder ?? _binder, TypeParameters, syntax.TypeParameterList, syntax.ConstraintClauses, @@ -501,7 +502,7 @@ public override ImmutableArray GetTypeParameterCons { var syntax = Syntax; var constraints = this.MakeTypeParameterConstraintKinds( - _binder, + _withTypeParamsBinder ?? _binder, TypeParameters, syntax.TypeParameterList, syntax.ConstraintClauses); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs index 1367310b17dfa..4e06c4fa8cadc 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs @@ -7117,5 +7117,38 @@ async static void B4() { } // async static void B4() { } Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "await").WithArguments("await").WithLocation(23, 30)); } + + [Fact] + public void TypeParameterScope() + { + var comp = CreateCompilation(@" +class C +{ + void M() + { + local(); + + [My(nameof(TParameter))] // works, but why? + void local() { } + } + + [My(nameof(TParameter))] // error CS0103: The name 'TParameter' does not exist in the current context + void M2() { } +} + +public class MyAttribute : System.Attribute +{ + public MyAttribute(string name1) { } +} +"); + comp.VerifyDiagnostics( + // (8,20): error CS0103: The name 'TParameter' does not exist in the current context + // [My(nameof(TParameter))] // works, but why? + Diagnostic(ErrorCode.ERR_NameNotInContext, "TParameter").WithArguments("TParameter").WithLocation(8, 20), + // (12,16): error CS0103: The name 'TParameter' does not exist in the current context + // [My(nameof(TParameter))] // error CS0103: The name 'TParameter' does not exist in the current context + Diagnostic(ErrorCode.ERR_NameNotInContext, "TParameter").WithArguments("TParameter").WithLocation(12, 16) + ); + } } } From bb9ed8e5e203bf91b07306a97c62e77ceb49841b Mon Sep 17 00:00:00 2001 From: Youssef1313 Date: Sat, 5 Mar 2022 23:39:15 +0200 Subject: [PATCH 2/3] Fix LookupPosition test --- .../CSharp/Portable/Compilation/MemberSemanticModel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs index 8d106bcd64aa9..bdab55a464d56 100644 --- a/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/MemberSemanticModel.cs @@ -358,7 +358,7 @@ private static Binder GetEnclosingBinderInternalWithinRoot(SyntaxNode node, int LocalFunctionSymbol function = GetDeclaredLocalFunction(binder, ownerOfTypeParametersInScope.Identifier); if ((object)function != null) { - binder = function.SignatureBinder; + binder = function.ParameterBinder; } } From 218dcafd22d8180c4e5595cf67870c959f251a40 Mon Sep 17 00:00:00 2001 From: Youssef1313 Date: Sat, 5 Mar 2022 23:43:58 +0200 Subject: [PATCH 3/3] Use ParameterBinder --- .../CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs index 02234e1478a3d..929820627dc9c 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs @@ -181,7 +181,7 @@ private void ComputeParameters() var diagnostics = BindingDiagnosticBag.GetInstance(_declarationDiagnostics); var parameters = ParameterHelpers.MakeParameters( - _withTypeParamsBinder ?? _binder, + ParameterBinder, this, this.Syntax.ParameterList, arglistToken: out arglistToken, @@ -240,7 +240,7 @@ internal void ComputeReturnType() var diagnostics = BindingDiagnosticBag.GetInstance(_declarationDiagnostics); TypeSyntax returnTypeSyntax = Syntax.ReturnType; - TypeWithAnnotations returnType = (_withTypeParamsBinder ?? _binder).BindType(returnTypeSyntax.SkipRef(), diagnostics); + TypeWithAnnotations returnType = ParameterBinder.BindType(returnTypeSyntax.SkipRef(), diagnostics); var compilation = DeclaringCompilation; @@ -477,7 +477,7 @@ public override ImmutableArray> GetTypeParam var syntax = Syntax; var diagnostics = BindingDiagnosticBag.GetInstance(_declarationDiagnostics); var constraints = this.MakeTypeParameterConstraintTypes( - _withTypeParamsBinder ?? _binder, + ParameterBinder, TypeParameters, syntax.TypeParameterList, syntax.ConstraintClauses, @@ -502,7 +502,7 @@ public override ImmutableArray GetTypeParameterCons { var syntax = Syntax; var constraints = this.MakeTypeParameterConstraintKinds( - _withTypeParamsBinder ?? _binder, + ParameterBinder, TypeParameters, syntax.TypeParameterList, syntax.ConstraintClauses);