Skip to content

Don't lose local function optional parameter information#53402

Merged
RikkiGibson merged 7 commits intodotnet:mainfrom
Youssef1313:local-func-opt
Jun 7, 2021
Merged

Don't lose local function optional parameter information#53402
RikkiGibson merged 7 commits intodotnet:mainfrom
Youssef1313:local-func-opt

Conversation

@Youssef1313
Copy link
Member

@Youssef1313 Youssef1313 commented May 13, 2021

Fixes #51518
Fixes #53478

@Youssef1313 Youssef1313 requested a review from a team as a code owner May 13, 2021 20:31
@ghost ghost added the Area-Compilers label May 13, 2021
@Youssef1313 Youssef1313 changed the title Don't loose local function optional parameter information Don't lose local function optional parameter information May 13, 2021
Comment on lines +288 to +290
internal override bool IsMetadataOptional => _baseParameterForAttributes?.IsMetadataOptional == true;

internal override ConstantValue? ExplicitDefaultConstantValue => _baseParameterForAttributes?.ExplicitDefaultConstantValue;
Copy link
Member Author

Choose a reason for hiding this comment

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

I'm not sure if there are other properties I should override, and what they'll affect.

Copy link
Member

Choose a reason for hiding this comment

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

I looked over the ParameterSymbol members and all that comes to mind is IsIDispatchConstant and IsIUnknownConstant.

I think that synthesized parameter symbols with non-null _baseParameterForAttributes are only produced for lowering/emit, so we don't expect to actually check the IsIDispatchConstant or IsIUnknownConstant members from the _baseParameterForAttributes.

I am not certain whether it makes more sense to:

  1. Do nothing to override or verify IsIDispatchConstant or IsIUnknownConstant on SynthesizedComplexParameterSymbol (i.e. don't change the implementation in this PR)
  2. Change IsIDispatchConstant and IsIUnknownConstant on SynthesizedParameterSymbolBase to throw ExceptionUtilities.Unreachable, since we don't expect to check those members on such parameters, because we don't expect to bind a default argument based on such a parameter, for example. (I'm not certain about this--if it results in new CI failures then we'll have learned something about the usage 😄)
  3. Override IsIDispatchConstant and IsIUnknownConstant on SynthesizedComplexParameterSymbol to delegate to the _baseParameterForAttributes.

I'm leaning slightly toward (2).

Copy link
Member Author

Choose a reason for hiding this comment

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

@RikkiGibson Thanks. I took the second approach as you suggested.

Is there anything needed for nullable analysis here?

e.g, override FlowAnalysisAnnotation and things related to nullable analysis?

Copy link
Member

Choose a reason for hiding this comment

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

I had a few more overrides and assertions in mind but I felt like enumerating them was equal work to adding the implementations, so I went ahead and pushed a commit to your PR.


internal override MarshalPseudoCustomAttributeData? MarshallingInformation => _baseParameterForAttributes?.MarshallingInformation;

internal override bool IsMetadataOptional => _baseParameterForAttributes?.IsMetadataOptional == true;
Copy link
Member

Choose a reason for hiding this comment

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

We should verify if this causes a behavior change in any other scenarios, and if so, do we want that behavior change. For example, could this cause parameter default value info to be emitted for some other kind of declaration that we don't want it emitted for.

Copy link
Member Author

Choose a reason for hiding this comment

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

@RikkiGibson Based on @jaredpar comment on the issue, a breaking change is okay here.

One possible code that's going to have a behavioral change:

using System;
public static class Program
{
    public static void Main()
    {
        void TestLocalAction(int a = 2)
        {
        }

        MapAction((Action<int>)TestMethodAction);
        MapAction((Action<int>)TestLocalAction);
    }

    public static void TestMethodAction(int a = 2)
    {
    }

    public static void MapAction(Delegate action)
    {
        Console.WriteLine(action.Method.GetParameters()[0].HasDefaultValue);
    }
}

I couldn't come up with a more "realistic" scenario.

Copy link
Member

@RikkiGibson RikkiGibson May 13, 2021

Choose a reason for hiding this comment

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

I agree that it is good to "break" this scenario, I just want to make sure that we've enumerated the other places in the compiler where a SynthesizedParameterSymbol can be created with a non-null _baseParameterForAttributes, in case this might impact other kinds of symbols.

I'll try and sit down later this afternoon and make sure of it myself. I think local functions might be the only scenario where we set a non-null value for this field, although lambdas might do it too now (cc @cston), and we probably would want the same kind of behavior for lambdas as we want for local functions here.

edit: actually, I think optional parameters are disallowed in lambdas both before and after the lambda improvements changes we're doing in C# 10, so it might be moot to try and test that scenario.

Copy link
Member Author

Choose a reason for hiding this comment

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

I think the only place for _baseParameterForAttributes to be non-null is SynthesizedClosureMethod (either a lambda or a local function).

Copy link
Contributor

Choose a reason for hiding this comment

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

I think the only place for _baseParameterForAttributes to be non-null is SynthesizedClosureMethod (either a lambda or a local function).

It feels like we might want to add negative tests for other scenarios consuming SynthesizedParameterSymbol.Create.

Copy link
Member Author

Choose a reason for hiding this comment

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

@AlekseyTs Any concrete/specific test cases you have in mind? For example, top-level entry point and record copy ctor are using SynthesizedParameterSymbol.Create. How a test for them would look like? they're never synthesized with optional parameters.

@RikkiGibson RikkiGibson self-assigned this May 13, 2021
@RikkiGibson RikkiGibson added the Community The pull request was submitted by a contributor who is not a Microsoft employee. label May 13, 2021
@Youssef1313
Copy link
Member Author

D:\workspace_work\1\s\src\Tools\Source\CompilerGeneratorTools\Source\CSharpSyntaxGenerator\CSharpSyntaxGenerator.csproj : error NU3037: Package 'System.Numerics.Vectors 4.4.0' from source 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public/nuget/v3/index.json': The repository primary signature validity period has expired. [D:\workspace_work\1\s\src\NuGet\Microsoft.Net.Compilers.Toolset\Microsoft.Net.Compilers.Toolset.Package.csproj]

@Youssef1313 Youssef1313 reopened this May 21, 2021
@RikkiGibson
Copy link
Member

@AlekseyTs Did you have any further comments on this PR?

@Youssef1313
Copy link
Member Author

@AlekseyTs Can you please take a look? Thanks!

@RikkiGibson
Copy link
Member

Sorry, I synced with Aleksey offline about this PR and he said he had no further comments. Then I forgot to finish driving this PR 😅

@Youssef1313
Copy link
Member Author

Sorry, I synced with Aleksey offline about this PR and he said he had no further comments. Then I forgot to finish driving this PR 😅

No problem!

@RikkiGibson RikkiGibson merged commit adb08ed into dotnet:main Jun 7, 2021
@ghost ghost added this to the Next milestone Jun 7, 2021
@RikkiGibson
Copy link
Member

Thanks for the contribution @Youssef1313!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area-Compilers Community The pull request was submitted by a contributor who is not a Microsoft employee.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Local methods and delegates aren't populating ParameterInfo.DefaultValue Optional ParameterInfo is lost at runtime for local functions

4 participants