Skip to content

Commit

Permalink
Add lambda parameters in scope in nameof using proper binder (#61382)
Browse files Browse the repository at this point in the history
  • Loading branch information
jcouv authored May 19, 2022
1 parent dc2c23d commit d7d1d04
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 4 deletions.
10 changes: 8 additions & 2 deletions src/Compilers/CSharp/Portable/Binder/LocalBinderFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ public override void VisitInvocationExpression(InvocationExpressionSyntax node)
var oldEnclosing = _enclosing;

WithTypeParametersBinder? withTypeParametersBinder;
WithParametersBinder? withParametersBinder;
Binder? withParametersBinder;
// The LangVer check will be removed before shipping .NET 7.
// Tracked by https://github.com/dotnet/roslyn/issues/60640
if (((_enclosing.Flags & BinderFlags.InContextualAttributeBinder) != 0) && _enclosing.Compilation.IsFeatureEnabled(MessageID.IDS_FeatureExtendedNameofScope))
Expand Down Expand Up @@ -249,8 +249,14 @@ static Symbol getAttributeTarget(Binder current)

// We're bringing parameters in scope inside `nameof` in attributes on methods, their type parameters and parameters.
// This also applies to local functions, lambdas, indexers and delegates.
static WithParametersBinder? getExtraWithParametersBinder(Binder enclosing, Symbol target)
static Binder? getExtraWithParametersBinder(Binder enclosing, Symbol target)
{
if (target is LambdaSymbol lambda)
{
// lambda parameters have some special rules around parameters named `_`
return new WithLambdaParametersBinder(lambda, enclosing);
}

var parameters = target switch
{
SourcePropertyAccessorSymbol { MethodKind: MethodKind.PropertySet } setter => getSetterParameters(setter),
Expand Down
4 changes: 2 additions & 2 deletions src/Compilers/CSharp/Portable/Binder/NameofBinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ internal sealed class NameofBinder : Binder
{
private readonly SyntaxNode _nameofArgument;
private readonly WithTypeParametersBinder? _withTypeParametersBinder;
private readonly WithParametersBinder? _withParametersBinder;
private readonly Binder? _withParametersBinder;
private ThreeState _lazyIsNameofOperator;

internal NameofBinder(SyntaxNode nameofArgument, Binder next, WithTypeParametersBinder? withTypeParametersBinder, WithParametersBinder? withParametersBinder)
internal NameofBinder(SyntaxNode nameofArgument, Binder next, WithTypeParametersBinder? withTypeParametersBinder, Binder? withParametersBinder)
: base(next)
{
_nameofArgument = nameofArgument;
Expand Down
58 changes: 58 additions & 0 deletions src/Compilers/CSharp/Test/Semantic/Semantics/LambdaTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6674,5 +6674,63 @@ void M()
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "parameter").WithArguments("parameter").WithLocation(9, 13)
);
}

[Fact, WorkItem(61143, "https://github.com/dotnet/roslyn/issues/61143")]
public void ParameterScope_LambdaDiscardParameter()
{
var comp = CreateCompilation(@"
class AAttribute : System.Attribute
{
public AAttribute(string s) { }
}
class C
{
void M(int _)
{
System.Func<string, string, int> a = [A(nameof(_))] (_, _) => 0;
}
}
");
comp.VerifyDiagnostics();

var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var discard = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>()
.Where(i => i.Identifier.ValueText == "_")
.Where(i => i.Ancestors().Any(a => a.IsKind(SyntaxKind.InvocationExpression)))
.Single();

Assert.Equal("System.Int32 _", model.GetSymbolInfo(discard).Symbol.ToTestDisplayString());
}

[Fact, WorkItem(61143, "https://github.com/dotnet/roslyn/issues/61143")]
public void ParameterScope_LambdaUnderscoreParameter()
{
var comp = CreateCompilation(@"
class AAttribute : System.Attribute
{
public AAttribute(string s) { }
}
class C
{
void M(int _)
{
System.Func<string, string, int> a = [A(nameof(_))] (_, x) => 0;
}
}
");
comp.VerifyDiagnostics();

var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);
var underscore = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>()
.Where(i => i.Identifier.ValueText == "_")
.Where(i => i.Ancestors().Any(a => a.IsKind(SyntaxKind.InvocationExpression)))
.Single();

Assert.Equal("System.String _", model.GetSymbolInfo(underscore).Symbol.ToTestDisplayString());
}
}
}

0 comments on commit d7d1d04

Please sign in to comment.