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

Make local function parameters bind lazily #16736

Closed
wants to merge 2 commits into from

Conversation

agocke
Copy link
Member

@agocke agocke commented Jan 25, 2017

Customer scenario

Mentioning a local function in the default value of one of its parameters will cause the compiler to crash. The following program is the simplest repro for this scenario:

class C
{
    public void M()
    {
        int Local(int x = Local()) => 0;
    }
}

Bugs this fixes:

Fixes #16451

Workarounds, if any

Don't mention the local function in its parameters' default values.

Risk

This change preserves the existing code paths for binding of default parameters for almost all circumstances and simply attempts to delay the code path for local functions to occur later.

Performance impact

Low. Same code path, just done lazily.

Is this a regression from a previous update?

No.

Root cause analysis:

Insufficient testing across new language features and lack of adversarial testing. Unit tests have been added for this and scenarios like this.

How was the bug found?

Testing local function default parameters with other language features.

@agocke
Copy link
Member Author

agocke commented Jan 25, 2017

@dotnet/roslyn-compiler For review

@@ -194,23 +193,28 @@ internal override bool IsCallerMemberName
}
}

private ConstantValue DefaultSyntaxValue
private ConstantValue GetDefaultSyntaxValue(DiagnosticBag diagnosticsOpt = null)
Copy link
Contributor

@AlekseyTs AlekseyTs Jan 25, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

private ConstantValue GetDefaultSyntaxValue(DiagnosticBag diagnosticsOpt = null) [](start = 8, length = 80)

Please open an issue to get rid of this pattern post RTM #Closed

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think this is encompassed by #16652?

That would remove the flakiness with adding to declaration diagnostics.

Copy link
Contributor

@AlekseyTs AlekseyTs Jan 25, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Somewhat, I think we should explicitly track API changes what we would like to revert. We can keep the list in that issue. #Closed

{
get { return null; }
}
protected virtual Binder ParameterBinder { get; }
Copy link
Contributor

@AlekseyTs AlekseyTs Jan 25, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

protected virtual Binder ParameterBinder { get; } [](start = 8, length = 49)

It feels like this property can be calculated from the containing LocalFunctionSymbol. #Closed

{
get { return null; }
}
protected virtual Binder ParameterBinder { get; }
Copy link
Contributor

@AlekseyTs AlekseyTs Jan 25, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

protected [](start = 8, length = 9)

private? #Closed

protected ConstantValue _lazyDefaultSyntaxValue;
private ConstantValue _lazyDefaultSyntaxValue;

private Binder _parameterBinder
Copy link
Contributor

@AlekseyTs AlekseyTs Jan 25, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_parameterBinder [](start = 23, length = 16)

_parameterBinder [](start = 23, length = 16)

Does this follow naming convention for properties? #Closed

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider naming LocalFunctionParameterBinder so it's clear when the binder is expected.

((MethodSymbol)ContainingSymbol).MethodKind == MethodKind.LocalFunction;
return isLocalFunction
? ((LocalFunctionSymbol)ContainingSymbol).ParameterBinder
: null;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While we typically prefer Kind checks, would it be simpler to use as instead here?

return (ContainingSymbol as LocalFunctionSymbol)?.ParameterBinder;

// int Local2(int p = Local1()) => 0;
Diagnostic(ErrorCode.ERR_DefaultValueMustBeConstant, "Local1()").WithArguments("p").WithLocation(7, 28));
comp.DeclarationDiagnostics.Verify();
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is nameof interesting? string Local(string s = nameof(Local)) => s;

@cston
Copy link
Member

cston commented Jan 26, 2017

LGTM

Local function parameters seemed to be designed to bind their
parameters' default values eagerly, as opposed to methods which bind
their default values lazily. This creates the possibility of infinite
binder recursion if the default value mentions the local function
itself (which has yet to be fully bound).

Fixes dotnet#16451
Copy link
Contributor

@AlekseyTs AlekseyTs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@agocke
Copy link
Member Author

agocke commented Jan 26, 2017

@MattGertz For escrow approval

@MattGertz
Copy link
Contributor

Rejected for RTW per raised bar in Shiproom. Please target 2.1 for this fix.

@AlekseyTs
Copy link
Contributor

@agocke We probably shouldn't merge this into 2.1 as is without addressing the issue around GetDefaultSyntaxValue (#16736 (review)).

@agocke
Copy link
Member Author

agocke commented Jan 26, 2017

@AlekseyTs Agreed

@agocke agocke closed this Jan 26, 2017
@agocke agocke deleted the localfunc-default-params branch September 12, 2018 22:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Compiler crash with recursive local function parameter default value
5 participants