Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix type parameter scoping for local functions #60098

Merged
merged 8 commits into from
Mar 22, 2022
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public override void GenerateAnonymousFunctionConversionError(BindingDiagnosticB
base.GenerateAnonymousFunctionConversionError(diagnostics, targetType);
}

public override Binder ParameterBinder(LambdaSymbol lambdaSymbol, Binder binder)
public override Binder GetWithParametersBinder(LambdaSymbol lambdaSymbol, Binder binder)
{
return new WithQueryLambdaParametersBinder(lambdaSymbol, _rangeVariableMap, binder);
}
Expand Down
8 changes: 4 additions & 4 deletions src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs
Original file line number Diff line number Diff line change
Expand Up @@ -631,7 +631,7 @@ private static TypeWithAnnotations DelegateReturnTypeWithAnnotations(MethodSymbo
parameterRefKinds,
refKind: default,
returnType: default);
var lambdaBodyBinder = new ExecutableCodeBinder(_unboundLambda.Syntax, lambdaSymbol, ParameterBinder(lambdaSymbol, Binder));
var lambdaBodyBinder = new ExecutableCodeBinder(_unboundLambda.Syntax, lambdaSymbol, GetWithParametersBinder(lambdaSymbol, Binder));
var block = BindLambdaBody(lambdaSymbol, lambdaBodyBinder, BindingDiagnosticBag.Discarded);
var returnTypes = ArrayBuilder<(BoundReturnStatement, TypeWithAnnotations)>.GetInstance();
BoundLambda.BlockReturns.GetReturnTypes(returnTypes, block);
Expand Down Expand Up @@ -704,7 +704,7 @@ private BoundLambda ReallyBind(NamedTypeSymbol delegateType, bool inExpressionTr
else
{
lambdaSymbol = CreateLambdaSymbol(Binder.ContainingMemberOrLambda, returnType, cacheKey.ParameterTypes, cacheKey.ParameterRefKinds, refKind);
lambdaBodyBinder = new ExecutableCodeBinder(_unboundLambda.Syntax, lambdaSymbol, ParameterBinder(lambdaSymbol, Binder), inExpressionTree ? BinderFlags.InExpressionTree : BinderFlags.None);
lambdaBodyBinder = new ExecutableCodeBinder(_unboundLambda.Syntax, lambdaSymbol, GetWithParametersBinder(lambdaSymbol, Binder), inExpressionTree ? BinderFlags.InExpressionTree : BinderFlags.None);
block = BindLambdaBody(lambdaSymbol, lambdaBodyBinder, diagnostics);
}

Expand Down Expand Up @@ -890,7 +890,7 @@ private void ValidateUnsafeParameters(BindingDiagnosticBag diagnostics, Immutabl
parameterTypes,
parameterRefKinds,
refKind);
var lambdaBodyBinder = new ExecutableCodeBinder(_unboundLambda.Syntax, lambdaSymbol, ParameterBinder(lambdaSymbol, Binder));
var lambdaBodyBinder = new ExecutableCodeBinder(_unboundLambda.Syntax, lambdaSymbol, GetWithParametersBinder(lambdaSymbol, Binder));
var block = BindLambdaBody(lambdaSymbol, lambdaBodyBinder, diagnostics);
lambdaSymbol.GetDeclarationDiagnostics(diagnostics);
return (lambdaSymbol, block, lambdaBodyBinder, diagnostics);
Expand Down Expand Up @@ -1024,7 +1024,7 @@ public static ReturnInferenceCacheKey Create(NamedTypeSymbol? delegateType, bool
}
}

public virtual Binder ParameterBinder(LambdaSymbol lambdaSymbol, Binder binder)
public virtual Binder GetWithParametersBinder(LambdaSymbol lambdaSymbol, Binder binder)
{
return new WithLambdaParametersBinder(lambdaSymbol, binder);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,8 +250,7 @@ private static Binder GetEnclosingBinderInternalWithinRoot(SyntaxNode node, int
{
Debug.Assert(ownerOfTypeParametersInScope == null);
var localFunction = (LocalFunctionStatementSyntax)stmt;
if (localFunction.TypeParameterList != null &&
!LookupPosition.IsBetweenTokens(position, localFunction.Identifier, localFunction.TypeParameterList.LessThanToken)) // Scope does not include method name.
if (LookupPosition.IsInLocalFunctionTypeParameterScope(position, localFunction))
{
ownerOfTypeParametersInScope = localFunction;
}
Expand Down Expand Up @@ -358,7 +357,7 @@ private static Binder GetEnclosingBinderInternalWithinRoot(SyntaxNode node, int
LocalFunctionSymbol function = GetDeclaredLocalFunction(binder, ownerOfTypeParametersInScope.Identifier);
if ((object)function != null)
{
binder = function.SignatureBinder;
binder = function.WithTypeParametersBinder;
}
}

Expand Down
18 changes: 9 additions & 9 deletions src/Compilers/CSharp/Portable/Symbols/ConstraintsHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ internal static class ConstraintsHelper

internal static ImmutableArray<ImmutableArray<TypeWithAnnotations>> MakeTypeParameterConstraintTypes(
this MethodSymbol containingSymbol,
Binder binder,
Binder withTypeParametersBinder,
ImmutableArray<TypeParameterSymbol> typeParameters,
TypeParameterListSyntax typeParameterList,
SyntaxList<TypeParameterConstraintClauseSyntax> constraintClauses,
Expand All @@ -327,11 +327,11 @@ internal static class ConstraintsHelper

// Wrap binder from factory in a generic constraints specific binder
// to avoid checking constraints when binding type names.
Debug.Assert(!binder.Flags.Includes(BinderFlags.GenericConstraintsClause));
binder = binder.WithAdditionalFlags(BinderFlags.GenericConstraintsClause | BinderFlags.SuppressConstraintChecks);
Debug.Assert(!withTypeParametersBinder.Flags.Includes(BinderFlags.GenericConstraintsClause));
withTypeParametersBinder = withTypeParametersBinder.WithAdditionalFlags(BinderFlags.GenericConstraintsClause | BinderFlags.SuppressConstraintChecks);

ImmutableArray<TypeParameterConstraintClause> clauses;
clauses = binder.BindTypeParameterConstraintClauses(containingSymbol, typeParameters, typeParameterList, constraintClauses,
clauses = withTypeParametersBinder.BindTypeParameterConstraintClauses(containingSymbol, typeParameters, typeParameterList, constraintClauses,
diagnostics, performOnlyCycleSafeValidation: false);

if (clauses.All(clause => clause.ConstraintTypes.IsEmpty))
Expand All @@ -344,7 +344,7 @@ internal static class ConstraintsHelper

internal static ImmutableArray<TypeParameterConstraintKind> MakeTypeParameterConstraintKinds(
this MethodSymbol containingSymbol,
Binder binder,
Binder withTypeParametersBinder,
ImmutableArray<TypeParameterSymbol> typeParameters,
TypeParameterListSyntax typeParameterList,
SyntaxList<TypeParameterConstraintClauseSyntax> constraintClauses)
Expand All @@ -358,18 +358,18 @@ internal static class ConstraintsHelper

if (constraintClauses.Count == 0)
{
clauses = binder.GetDefaultTypeParameterConstraintClauses(typeParameterList);
clauses = withTypeParametersBinder.GetDefaultTypeParameterConstraintClauses(typeParameterList);
}
else
{
// Wrap binder from factory in a generic constraints specific binder
// Also, suppress type argument binding in constraint types, this helps to avoid cycles while we figure out constraint kinds.
// to avoid checking constraints when binding type names.
Debug.Assert(!binder.Flags.Includes(BinderFlags.GenericConstraintsClause));
binder = binder.WithAdditionalFlags(BinderFlags.GenericConstraintsClause | BinderFlags.SuppressConstraintChecks | BinderFlags.SuppressTypeArgumentBinding);
Debug.Assert(!withTypeParametersBinder.Flags.Includes(BinderFlags.GenericConstraintsClause));
withTypeParametersBinder = withTypeParametersBinder.WithAdditionalFlags(BinderFlags.GenericConstraintsClause | BinderFlags.SuppressConstraintChecks | BinderFlags.SuppressTypeArgumentBinding);

// We will recompute this diagnostics more accurately later, when binding without BinderFlags.SuppressTypeArgumentBinding
clauses = binder.BindTypeParameterConstraintClauses(containingSymbol, typeParameters, typeParameterList, constraintClauses,
clauses = withTypeParametersBinder.BindTypeParameterConstraintClauses(containingSymbol, typeParameters, typeParameterList, constraintClauses,
BindingDiagnosticBag.Discarded, performOnlyCycleSafeValidation: true);

clauses = AdjustConstraintKindsBasedOnConstraintTypes(containingSymbol, typeParameters, clauses);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -265,9 +265,9 @@ public override bool IsExtensionMethod
get { return false; }
}

internal override Binder SignatureBinder => _binder;
internal override Binder OuterBinder => _binder;

internal override Binder ParameterBinder => new WithLambdaParametersBinder(this, _binder);
internal override Binder WithTypeParametersBinder => _binder;

internal override OneOrMany<SyntaxList<AttributeListSyntax>> GetAttributeDeclarations()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ internal sealed class LocalFunctionSymbol : SourceMethodSymbolWithAttributes

if (syntax.TypeParameterList != null)
{
binder = new WithMethodTypeParametersBinder(this, binder);
_typeParameters = MakeTypeParameters(_declarationDiagnostics);
}
else
Expand Down Expand Up @@ -105,7 +104,10 @@ internal sealed class LocalFunctionSymbol : SourceMethodSymbolWithAttributes
/// </summary>
internal Binder ScopeBinder { get; }

internal override Binder ParameterBinder => _binder;
internal override Binder OuterBinder => _binder;

internal override Binder WithTypeParametersBinder
=> _typeParameters.IsEmpty ? _binder : new WithMethodTypeParametersBinder(this, _binder);
RikkiGibson marked this conversation as resolved.
Show resolved Hide resolved

internal LocalFunctionStatementSyntax Syntax => (LocalFunctionStatementSyntax)syntaxReferenceOpt.GetSyntax();

Expand Down Expand Up @@ -180,7 +182,7 @@ private void ComputeParameters()
var diagnostics = BindingDiagnosticBag.GetInstance(_declarationDiagnostics);

var parameters = ParameterHelpers.MakeParameters(
_binder,
WithTypeParametersBinder,
this,
this.Syntax.ParameterList,
arglistToken: out arglistToken,
Expand Down Expand Up @@ -239,7 +241,7 @@ internal void ComputeReturnType()

var diagnostics = BindingDiagnosticBag.GetInstance(_declarationDiagnostics);
TypeSyntax returnTypeSyntax = Syntax.ReturnType;
TypeWithAnnotations returnType = _binder.BindType(returnTypeSyntax.SkipRef(), diagnostics);
TypeWithAnnotations returnType = WithTypeParametersBinder.BindType(returnTypeSyntax.SkipRef(), diagnostics);

var compilation = DeclaringCompilation;

Expand Down Expand Up @@ -334,8 +336,6 @@ internal override TypeWithAnnotations IteratorElementTypeWithAnnotations

public SyntaxToken NameToken => Syntax.Identifier;

internal override Binder SignatureBinder => _binder;

public override ImmutableArray<MethodSymbol> ExplicitInterfaceImplementations => ImmutableArray<MethodSymbol>.Empty;

public override ImmutableArray<Location> Locations => ImmutableArray.Create(Syntax.Identifier.GetLocation());
Expand Down Expand Up @@ -476,7 +476,7 @@ public override ImmutableArray<ImmutableArray<TypeWithAnnotations>> GetTypeParam
var syntax = Syntax;
var diagnostics = BindingDiagnosticBag.GetInstance(_declarationDiagnostics);
var constraints = this.MakeTypeParameterConstraintTypes(
_binder,
WithTypeParametersBinder,
TypeParameters,
syntax.TypeParameterList,
syntax.ConstraintClauses,
Expand All @@ -501,7 +501,7 @@ public override ImmutableArray<TypeParameterConstraintKind> GetTypeParameterCons
{
var syntax = Syntax;
var constraints = this.MakeTypeParameterConstraintKinds(
_binder,
WithTypeParametersBinder,
TypeParameters,
syntax.TypeParameterList,
syntax.ConstraintClauses);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols
internal static class ParameterHelpers
{
public static ImmutableArray<ParameterSymbol> MakeParameters(
Binder binder,
Binder withTypeParametersBinder,
Symbol owner,
BaseParameterListSyntax syntax,
out SyntaxToken arglistToken,
Expand All @@ -27,7 +27,7 @@ internal static class ParameterHelpers
bool addRefReadOnlyModifier)
{
return MakeParameters<ParameterSyntax, ParameterSymbol, Symbol>(
binder,
withTypeParametersBinder,
owner,
syntax.Parameters,
out arglistToken,
Expand Down Expand Up @@ -106,7 +106,7 @@ internal static class ParameterHelpers
}

private static ImmutableArray<TParameterSymbol> MakeParameters<TParameterSyntax, TParameterSymbol, TOwningSymbol>(
Binder binder,
Binder withTypeParametersBinder,
TOwningSymbol owner,
SeparatedSyntaxList<TParameterSyntax> parametersList,
out SyntaxToken arglistToken,
Expand Down Expand Up @@ -179,7 +179,7 @@ internal static class ParameterHelpers
}

Debug.Assert(parameterSyntax.Type != null);
var parameterType = binder.BindType(parameterSyntax.Type, diagnostics, suppressUseSiteDiagnostics: suppressUseSiteDiagnostics);
var parameterType = withTypeParametersBinder.BindType(parameterSyntax.Type, diagnostics, suppressUseSiteDiagnostics: suppressUseSiteDiagnostics);

if (!allowRefOrOut && (refKind == RefKind.Ref || refKind == RefKind.Out))
{
Expand All @@ -197,7 +197,7 @@ internal static class ParameterHelpers
}
}

TParameterSymbol parameter = parameterCreationFunc(binder, owner, parameterType, parameterSyntax, refKind, parameterIndex, paramsKeyword, thisKeyword, addRefReadOnlyModifier, diagnostics);
TParameterSymbol parameter = parameterCreationFunc(withTypeParametersBinder, owner, parameterType, parameterSyntax, refKind, parameterIndex, paramsKeyword, thisKeyword, addRefReadOnlyModifier, diagnostics);

ReportParameterErrors(owner, parameterSyntax, parameter, thisKeyword, paramsKeyword, firstDefault, diagnostics);

Expand All @@ -224,10 +224,10 @@ internal static class ParameterHelpers
default(ImmutableArray<TypeParameterSymbol>);

Debug.Assert(methodOwner?.MethodKind != MethodKind.LambdaMethod);
bool allowShadowingNames = binder.Compilation.IsFeatureEnabled(MessageID.IDS_FeatureNameShadowingInNestedFunctions) &&
bool allowShadowingNames = withTypeParametersBinder.Compilation.IsFeatureEnabled(MessageID.IDS_FeatureNameShadowingInNestedFunctions) &&
methodOwner?.MethodKind == MethodKind.LocalFunction;

binder.ValidateParameterNameConflicts(typeParameters, parameters.Cast<TParameterSymbol, ParameterSymbol>(), allowShadowingNames, diagnostics);
withTypeParametersBinder.ValidateParameterNameConflicts(typeParameters, parameters.Cast<TParameterSymbol, ParameterSymbol>(), allowShadowingNames, diagnostics);
}

return parameters;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ private enum ParameterSyntaxKind : byte
_lazyDefaultSyntaxValue = ConstantValue.Unset;
}

private Binder ParameterBinderOpt => (ContainingSymbol as SourceMethodSymbolWithAttributes)?.ParameterBinder;
private Binder WithTypeParametersBinderOpt => (ContainingSymbol as SourceMethodSymbolWithAttributes)?.WithTypeParametersBinder;

internal sealed override SyntaxReference SyntaxReference => _syntaxRef;

Expand Down Expand Up @@ -246,9 +246,9 @@ private ConstantValue DefaultSyntaxValue
}
}

private Binder GetBinder(SyntaxNode syntax)
private Binder GetDefaultParameterValueBinder(SyntaxNode syntax)
{
var binder = ParameterBinderOpt;
var binder = WithTypeParametersBinderOpt;

// If binder is null, then get it from the compilation. Otherwise use the provided binder.
// Don't always get it from the compilation because we might be in a speculative context (local function parameter),
Expand Down Expand Up @@ -289,7 +289,7 @@ private void NullableAnalyzeParameterDefaultValueFromAttributes()
return;
}

var binder = GetBinder(parameterSyntax);
var binder = GetDefaultParameterValueBinder(parameterSyntax);

// Nullable warnings *within* the attribute argument (such as a W-warning for `(string)null`)
// are reported when we nullable-analyze attribute arguments separately from here.
Expand Down Expand Up @@ -329,7 +329,7 @@ private ConstantValue MakeDefaultExpression(BindingDiagnosticBag diagnostics, ou
return ConstantValue.NotAvailable;
}

binder = GetBinder(defaultSyntax);
binder = GetDefaultParameterValueBinder(defaultSyntax);
Binder binderForDefault = binder.CreateBinderForParameterDefaultValue(this, defaultSyntax);
Debug.Assert(binderForDefault.InParameterDefaultValue);
Debug.Assert(binderForDefault.ContainingMemberOrLambda == ContainingSymbol);
Expand Down Expand Up @@ -551,7 +551,7 @@ internal sealed override CustomAttributesBag<CSharpAttributeData> GetAttributesB
else
{
var attributeSyntax = this.GetAttributeDeclarations();
bagCreatedOnThisThread = LoadAndValidateAttributes(attributeSyntax, ref _lazyCustomAttributesBag, binderOpt: ParameterBinderOpt);
bagCreatedOnThisThread = LoadAndValidateAttributes(attributeSyntax, ref _lazyCustomAttributesBag, binderOpt: WithTypeParametersBinderOpt);
}

if (bagCreatedOnThisThread)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,9 @@ protected SourceMethodSymbolWithAttributes(SyntaxReference syntaxReferenceOpt)
}
}

internal virtual Binder? SignatureBinder => null;
internal virtual Binder? OuterBinder => null;

internal virtual Binder? ParameterBinder => null;
internal virtual Binder? WithTypeParametersBinder => null;

#nullable disable

Expand Down Expand Up @@ -283,7 +283,7 @@ private CustomAttributesBag<CSharpAttributeData> GetAttributesBag(ref CustomAttr
declarations,
ref lazyCustomAttributesBag,
symbolPart,
binderOpt: SignatureBinder);
binderOpt: OuterBinder);
}

if (bagCreatedOnThisThread)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ internal virtual CustomAttributesBag<CSharpAttributeData> GetAttributesBag()
lazyAttributesStored = LoadAndValidateAttributes(
OneOrMany.Create(this.MergedAttributeDeclarationSyntaxLists),
ref _lazyCustomAttributesBag,
binderOpt: (ContainingSymbol as LocalFunctionSymbol)?.SignatureBinder);
binderOpt: (ContainingSymbol as LocalFunctionSymbol)?.WithTypeParametersBinder);
}
else
{
Expand Down
Loading