-
Notifications
You must be signed in to change notification settings - Fork 227
Update declaring constructors to allow the new constructor syntax #4543
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
Conversation
|
Testing the libraries in A couple of errors arise because the test specifically tests the treatment of built-in identifiers and reserved words, so that's to be expected. The remaining errors are all concerned with the use of We could try out the radical approach (making |
c1abdba to
19471aa
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great!
accepted/future-releases/primary-constructors/feature-specification.md
Outdated
Show resolved
Hide resolved
|
|
||
| A factory constructor declaration of the form `factory C(...` where `C` | ||
| is the name of the enclosing class, mixin class, enum, or extension type is | ||
| treated as if `C` had been omitted. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be more direct to say that it the grammar factory C(... is not allowed to parse as a new-style constructor when C is the name of the surrounding thing.
Then there is no grammar ambiguity, and the syntax only parses as an old-style factory constructor. (And if we ever remove the old-style grammar, we won't still accept factory C(), because we forget to remove this special-case. Better to not have it to begin with.)
| | 'CONST'? <factoryConstructorHead> <formalParameterList> '=' | ||
| <constructorDesignation>; // New form. | ||
| <constantConstructorSignature> ::= // Modified rule. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also declared on line 617.
| <redirectingFactoryConstructorSignature> ::= // Modified rule. | ||
| 'const'? 'factory' <constructorName> <formalParameterList> '=' | ||
| <constructorDesignation> // Old form. | ||
| | 'CONST'? <factoryConstructorHead> <formalParameterList> '=' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'CONST' -> 'const'
Same, could then be:
'const'? <factoryDesignator> <formalParameterList> '='... which is just <factoryConstructorSignature> '=', right?
| *Another special exception is introduced with factory constructors in order | ||
| to avoid breaking existing code:* | ||
|
|
||
| A factory constructor declaration of the form `factory C(...` where `C` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or const factory C(....
It needs to be said. 😞
| treated as if `C` had been omitted. | ||
|
|
||
| *Without this special rule, such a declaration would declare a constructor | ||
| named `C.C`. With this rule it declares a constructor named `C`, which |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Without this special rule, the grammar would be ambiguous.
And because the rule for the old form is first, it would parse as the old form.
Which means this sentence isn't needed, the grammar would parse it that way anyway.
... until we introduce static extension constructors which can only use the new syntax,
and if that's restricted at the grammar level, the syntax would then start meaning C.C. So let's not do the restriction at the grammar level, allow both to be parsed, then say it's an error to use the old style syntax.
| <declaringConstructorSignature> ::= // New rule. | ||
| 'this' ('.' <identifierOrNew>)? <declaringParameterList>?; | ||
| 'this' <identifier>? <declaringParameterList>?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should be 'this' (<identifier>? <declaringParameterList>)?;.
You can't have an identifier without a parameter list.
The const, name-identifier and parameter list either all go in the class header or all in an in-body declaration.
| <factoryConstructorSignature> ::= // Modified rule. | ||
| 'const'? 'factory' <constructorName> <formalParameterList> // Old form. | ||
| | 'const'? <factoryConstructorHead> <formalParameterList>; // New form. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Would it make sense to make this:
<factoryConstructorSignature> ::=
'const'? <factoryDesignator> <formalParameterList>
<factoryDesignator> ::=
'factory' <constructorName>
| <factoryConstructorHead>(Strawman production name!)
It seems that the rest of the productions are the same, and mean the same thing,
so we can abstract only the part that actually is different.)
| <constantConstructorSignature> ::= // Modified rule. | ||
| : 'const' <constructorName> <formalParameterList> // Old form. | ||
| | 'const' <constructorHead> <formalParameterList> // New form. | ||
| | <declaringConstantConstructorSignature>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we didn't use <declaringFormalParameterList> for <declaringConstrntConstructorSignature>, but just said that it is an error to have a declaring parameter anywhere else, this could also be:
<constantConstructorSignature> ::=
'const' <constructorDesignator> <formalParameterList>;
<constructorDesignator> ::=
<constructorName> // old form
| <constructorHead> // new form
| <declaringConstructorHead> // also new
;
<declaringConstructorHead> ::=
'this' <identifier>?;which also avoids repeating things that mean the same thing between different productions.
|
|
||
| This ambiguity is resolved as follows: When a Dart parser expects to parse | ||
| a `<memberDeclaration>`, and the first token is `factory`, it proceeds to | ||
| parse the following input as a factory constructor. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Could add commentary like "This is similar to how a statement starting with switch or { are parsed as a switch statement or block, and never as an expression statement.".)
| *It introduces a breaking change in the grammar, which implies that | ||
| developers must explicitly enable it. In particular, `factory() {}` in a | ||
| class body used to be a method declaration. With this feature it will be | ||
| a factory constructor declaration.* |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The feature also disallows var x, final x and final T x as parameters in all non-declaring constructors (Line 122/130.), which is much more far-reaching and potentially breaking.
See #4485 for background information.
This PR changes the feature specification of declaring constructors such that its grammar rules support the new style of constructor declarations (like
new();andconst factory name() = D;).It handles the ambiguity among
factory();being a method or a factory constructor declaration whose name is the name of the enclosing class/mixin-class/enum/extension-type declaration by makingfactorya reserved word.