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

Bind base arguments fo records #44876

Merged
merged 3 commits into from
Jun 5, 2020
Merged

Conversation

AlekseyTs
Copy link
Contributor

@AlekseyTs AlekseyTs commented Jun 5, 2020

@AlekseyTs
Copy link
Contributor Author

AlekseyTs commented Jun 5, 2020

@agocke, @RikkiGibson, @cston, @jcouv, @dotnet/roslyn-compiler Please review #Closed

1 similar comment
@AlekseyTs
Copy link
Contributor Author

AlekseyTs commented Jun 5, 2020

@agocke, @RikkiGibson, @cston, @jcouv, @dotnet/roslyn-compiler Please review #Closed

@RikkiGibson
Copy link
Contributor

RikkiGibson commented Jun 5, 2020

Taking a look #Resolved

public Base() {}
}

record C(int X, int Y) : Base(X, Y)
Copy link
Member

@gafter gafter Jun 5, 2020

Choose a reason for hiding this comment

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

Base [](start = 25, length = 4)

Please test (for semantic errors) an argument list in the base with a class and struct declaration (rather than a record declaration). #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Please test (for semantic errors) an argument list in the base with a class and struct declaration (rather than a record declaration).

There are existing tests for parsing errors in these scenarios. However, I added some tests here as well.


In reply to: 436046885 [](ancestors = 436046885)


if (node.BaseWithArguments is SimpleBaseTypeSyntax baseWithArguments)
{
VisitNodeToBind(baseWithArguments);
Copy link
Member

@gafter gafter Jun 5, 2020

Choose a reason for hiding this comment

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

VisitNodeToBind [](start = 16, length = 15)

The scope rules implemented here are not supported by the specification at https://github.com/dotnet/csharplang/blob/master/proposals/records.md #WontFix

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The scope rules implemented here are not supported by the specification at https://github.com/dotnet/csharplang/blob/master/proposals/records.md

It is a well-known fact that the spec is behind. Please see https://github.com/dotnet/csharplang/blob/master/meetings/2020/LDM-2020-06-01.md


In reply to: 436049242 [](ancestors = 436049242)

Copy link
Member

Choose a reason for hiding this comment

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

Please update the specification so this code can be checked against that.


In reply to: 436051230 [](ancestors = 436051230,436049242)

Copy link
Contributor

@RikkiGibson RikkiGibson left a comment

Choose a reason for hiding this comment

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

LGTM with some minor comments/questions.

@@ -53,8 +53,7 @@ public int Position
// until later when it is known if they can be optimized or not.
// As a result the last emitted method tokens are synthetic ctor and then synthetic cctor (if not optimized)
// Since it is not too hard, we will try keeping the same order just to be easy on metadata diffing tools and such.
public static readonly LexicalSortKey SynthesizedRecordCopyCtor = new LexicalSortKey() { _treeOrdinal = int.MaxValue, _position = int.MaxValue - 3 };
public static readonly LexicalSortKey SynthesizedRecordCtor = new LexicalSortKey() { _treeOrdinal = int.MaxValue, _position = int.MaxValue - 2 };
public static readonly LexicalSortKey SynthesizedRecordCopyCtor = new LexicalSortKey() { _treeOrdinal = int.MaxValue, _position = int.MaxValue - 2 };
Copy link
Contributor

@RikkiGibson RikkiGibson Jun 5, 2020

Choose a reason for hiding this comment

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

should the above SortKey positions be adjusted? #Resolved

Copy link
Member

@cston cston Jun 5, 2020

Choose a reason for hiding this comment

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

I've replaced this code in #44882. #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

should the above SortKey positions be adjusted?

I am not following. Could you elaborate please?


In reply to: 436055537 [](ancestors = 436055537)

Copy link
Contributor

@RikkiGibson RikkiGibson Jun 5, 2020

Choose a reason for hiding this comment

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

For instance SynthesizedRecordObjEquals still has _position = int.MaxValue - 4 while there is no symbol with position int.MaxValue - 3. I doubt this negatively affects anything so perhaps we can just leave it as is, especially if changing it may introduce more conflicts with other PRs. #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've replaced this code in #44882.

Reverted to avoid a conflict


In reply to: 436071673 [](ancestors = 436071673)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For instance SynthesizedRecordObjEquals still has _position = int.MaxValue - 4 while there is no symbol with position int.MaxValue - 3. I doubt this negatively affects anything so perhaps we can just leave it as is, especially if changing it may introduce more conflicts with other PRs.

I reverted the change in favor of in #44882.


In reply to: 436077962 [](ancestors = 436077962)


var comp = CreateCompilation(src);
comp.VerifyEmitDiagnostics(
// (13,16): error CS8861: Unexpected argument list.
Copy link
Contributor

@RikkiGibson RikkiGibson Jun 5, 2020

Choose a reason for hiding this comment

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

Ideally this diagnostic would say something like "only a record with positional parameters may have a constructor initializer." We can follow up in #44826 #WontFix

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ideally this diagnostic would say something like "only a record with positional parameters may have a constructor initializer." We can follow up in #44826

This is preexisting condition.


In reply to: 436066301 [](ancestors = 436066301)

// record C(dynamic X) : Base(X)
Diagnostic(ErrorCode.ERR_NoDynamicPhantomOnBaseCtor, "(X)").WithLocation(11, 27)
);
}
Copy link
Contributor

@RikkiGibson RikkiGibson Jun 5, 2020

Choose a reason for hiding this comment

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

Do we have a test which demonstrates whether a partial record is allowed to reiterate its base class without arguments, e.g.:

record A(int X) { }

partial record B(int X, int Y) : A(X) { }
partial record B : A { }

#Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do we have a test which demonstrates whether a partial record is allowed to reiterate its base class without arguments, e.g.:

I do not know. I think this is outside of scope of this PR, feel free to add a note to the Test Plan.


In reply to: 436069358 [](ancestors = 436069358)

@jcouv jcouv mentioned this pull request Jun 5, 2020
@RikkiGibson
Copy link
Contributor

RikkiGibson commented Jun 5, 2020

Aleksey has suggested that if the PR receives a second sign-off that we can squash merge the PR even if he is offline at the time. #Resolved

@jcouv
Copy link
Member

jcouv commented Jun 5, 2020

Looking now #Resolved

@jcouv jcouv self-assigned this Jun 5, 2020
@@ -390,6 +393,16 @@ public override void VisitConstructorDeclaration(ConstructorDeclarationSyntax no
}
}

public override void VisitRecordDeclaration(RecordDeclarationSyntax node)
{
Debug.Assert(((RecordDeclarationSyntax)node).ParameterList is object);
Copy link
Member

@jcouv jcouv Jun 5, 2020

Choose a reason for hiding this comment

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

RecordDeclarationSyntax [](start = 27, length = 23)

nit: redundant cast #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

nit: redundant cast

Removed in #44906


In reply to: 436172247 [](ancestors = 436172247)

@@ -3864,7 +3864,7 @@ private static bool IsNegativeConstantForArraySize(BoundExpression expression)
NamedTypeSymbol initializerType = containingType;

bool isBaseConstructorInitializer = initializerArgumentListOpt == null ||
initializerArgumentListOpt.Parent.Kind() == SyntaxKind.BaseConstructorInitializer;
initializerArgumentListOpt.Parent.Kind() != SyntaxKind.ThisConstructorInitializer;
Copy link
Member

@jcouv jcouv Jun 5, 2020

Choose a reason for hiding this comment

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

nit: wouldn't it be clearer to keep the check as "parent is BaseConstructorInitializer OR parent is SimpleBaseTypeSyntax"? #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

nit: wouldn't it be clearer to keep the check as "parent is BaseConstructorInitializer OR parent is SimpleBaseTypeSyntax"?

I think it is clearer this way, i.e. either we are dealing with "this" initializer syntax, or it is a base initializer swmantically.


In reply to: 436174617 [](ancestors = 436174617)

Copy link
Member

@jcouv jcouv left a comment

Choose a reason for hiding this comment

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

LGTM Thanks (iteration 3)

@jcouv jcouv self-requested a review June 5, 2020 21:53
@jcouv
Copy link
Member

jcouv commented Jun 5, 2020

@AlekseyTs I'm testing on top of this PR, and encountered an unexpected error:
image

Can you add a test like this? #Resolved

Copy link
Member

@agocke agocke left a comment

Choose a reason for hiding this comment

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

LGTM. Test suggestion that can be added later.

public Base() {}
}

partial record C(int X, int Y) : Base(X, Y)
Copy link
Member

@agocke agocke Jun 5, 2020

Choose a reason for hiding this comment

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

I assume the following is legal:

record Base(int X);
partial record C(int X) : Base(X);
partial record C { }

Could you write a test that shows it succeeds/emits correctly? #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I assume the following is legal:

Yes, this works, adding test in the next PR


In reply to: 436186239 [](ancestors = 436186239)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

adding test in the next PR

Added in #44906


In reply to: 436197211 [](ancestors = 436197211,436186239)

@jcouv
Copy link
Member

jcouv commented Jun 5, 2020

Confirmed the problem with a unittest:

        [Fact]
        public void TODO()
        {
            var src = @"

public record Human(int age) { }
public record Person(string First, string Last) : Human(0) { }
";

            var comp = CreateCompilation(src);
            comp.VerifyDiagnostics(
                // (4,15): error CS1729: 'Human' does not contain a constructor that takes 0 arguments
                // public record Person(string First, string Last) : Human(0) 
                Diagnostic(ErrorCode.ERR_BadCtorArgCount, "Person").WithArguments("Human", "0").WithLocation(4, 15)
                );
        }
``` #Resolved

@AlekseyTs
Copy link
Contributor Author

I'm testing on top of this PR, and encountered an unexpected error:

The error is coming from generation of the copy constructor, it is not related to arguments


In reply to: 639844282 [](ancestors = 639844282)

@AlekseyTs
Copy link
Contributor Author

See

    .method public hidebysig specialname rtspecialname 
        instance void .ctor (
            class Person ''
        ) cil managed 
    {
        // Method begins at RVA 0x214d
        // Code size 32 (0x20)
        .maxstack 8

        IL_0000: ldarg.0
        IL_0001: call instance void Human::.ctor()
        IL_0006: nop
        IL_0007: ldarg.0
        IL_0008: ldarg.1
        IL_0009: ldfld string Person::'<First>k__BackingField'
        IL_000e: stfld string Person::'<First>k__BackingField'
        IL_0013: ldarg.0
        IL_0014: ldarg.1
        IL_0015: ldfld string Person::'<Last>k__BackingField'
        IL_001a: stfld string Person::'<Last>k__BackingField'
        IL_001f: ret
    } // end of method Person::.ctor

in https://sharplab.io/#v2:EYLgZgpghgLgrgJwgZwLRIMYHsEBNkA0MIAlgDYG4gDUAPpjrgAQAScAtlAHYAUJXMJiQCUAWABQAbwlNZTAAIBmVh249hTEExgALEsh6oAjMMkBfCRfESGeJgAUICZFl7yjABiYAxEs5gECp5MADJQyDAaWmycvB7CANwSElxQ7CgADlAYEEEAdABKcAIk6XkAwljsGeROAMpOAG4kOcgS0uJyCsrI0GQQzPIATEwAksgAogAeME6pZKNcJDAych1dVlZAA


In reply to: 639867910 [](ancestors = 639867910,639844282)

@AlekseyTs
Copy link
Contributor Author

Confirmed the problem with a unittest:

Responded above, doesn't look related to the primary constructor


In reply to: 639859945 [](ancestors = 639859945)

Copy link
Member

@jcouv jcouv left a comment

Choose a reason for hiding this comment

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

LGTM Thanks (iteration 3)
From discussion with Aleksey, I'll file an issue with copy constructor (it should probably leverage copy constructor from the base, instead of no-args constructor).

@AlekseyTs AlekseyTs merged commit 062cfa5 into dotnet:features/records Jun 5, 2020
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.

6 participants