Skip to content

Commit c8ff69d

Browse files
authored
Update declaring constructors to allow the new constructor syntax (#4543)
Update the declaring constructors feature specification to allow the new constructor syntax (`new();` rather than `ClassName();`, etc). This gives rise to an ambiguity in the grammar (`factory() => e;` can be a method named `factory` and no return type, but it can also be a factory constructor whose name is the class name; it's resolved to make it a factory constructor).
1 parent 39d55bd commit c8ff69d

File tree

1 file changed

+85
-33
lines changed

1 file changed

+85
-33
lines changed

accepted/future-releases/primary-constructors/feature-specification.md

Lines changed: 85 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Author: Erik Ernst
44

55
Status: Accepted
66

7-
Version: 1.10
7+
Version: 1.11
88

99
Experiment flag: declaring-constructors
1010

@@ -575,64 +575,81 @@ constructors as well.
575575
```ebnf
576576
<classDeclaration> ::= // First alternative modified.
577577
(<classModifiers> | <mixinClassModifiers>)
578-
'class' <classNamePart> <superclass>? <interfaces>? <classBody>
578+
'class' <classNameMaybePrimary> <superclass>? <interfaces>? <classBody>
579579
| ...;
580580
581-
<primaryConstructorNoConst> ::= // New rule.
582-
<typeIdentifier> <typeParameters>?
583-
('.' <identifierOrNew>)? <declaringParameterList>
581+
<primaryConstructor> ::= // New rule.
582+
'const'? <typeWithParameters> ('.' <identifierOrNew>)?
583+
<declaringParameterList>;
584584
585-
<classNamePart> ::= // New rule.
586-
'const'? <primaryConstructorNoConst>
585+
<classNameMaybePrimary> ::= // New rule.
586+
<primaryConstructor>
587587
| <typeWithParameters>;
588588
589589
<typeWithParameters> ::= <typeIdentifier> <typeParameters>?
590590
591591
<classBody> ::= // New rule.
592-
'{' (<metadata> <classMemberDeclaration>)* '}'
592+
'{' (<metadata> <memberDeclaration>)* '}'
593593
| ';';
594594
595595
<extensionTypeDeclaration> ::= // Modified rule.
596-
'extension' 'type' <classNamePart> <interfaces>?
596+
'extension' 'type' <classNameMaybePrimary> <interfaces>?
597597
<extensionTypeBody>;
598598
599-
<extensionTypeMemberDeclaration> ::= <classMemberDeclaration>;
600-
601599
<extensionTypeBody> ::=
602-
'{' (<metadata> <extensionTypeMemberDeclaration>)* '}'
600+
'{' (<metadata> <memberDeclaration>)* '}'
603601
| ';';
604602
605603
<enumType> ::= // Modified rule.
606-
'enum' <classNamePart> <mixins>? <interfaces>? '{'
607-
<enumEntry> (',' <enumEntry>)* (',')?
608-
(';' (<metadata> <classMemberDeclaration>)*)?
604+
'enum' <classNameMaybePrimary> <mixins>? <interfaces>? '{'
605+
<enumEntry> (',' <enumEntry>)* ','?
606+
(';' (<metadata> <memberDeclaration>)*)?
609607
'}';
610608
611609
<constructorSignature> ::= // Modified rule.
612-
<constructorName> <formalParameterList>
610+
<constructorName> <formalParameterList> // Old form.
611+
| <constructorHead> <formalParameterList> // New form.
613612
| <declaringConstructorSignature>;
614613
615614
<declaringConstructorSignature> ::= // New rule.
616-
'this' ('.' <identifierOrNew>)? <declaringParameterList>?;
615+
'this' <identifier>? <declaringParameterList>?;
617616
618617
<constantConstructorSignature> ::= // Modified rule.
619-
'const' <constructorName> <formalParameterList>
618+
'const' <constructorName> <formalParameterList> // Old form.
619+
| 'const' <constructorHead> <formalParameterList> // New form.
620620
| <declaringConstantConstructorSignature>;
621621
622622
<constructorName> ::= // Modified rule.
623-
<typeIdentifierOrNew> ('.' identifierOrNew)?;
624-
625-
<typeIdentifierOrNew> ::= // New rule.
626-
<typeIdentifier>
627-
| 'new';
623+
<typeIdentifier> ('.' identifierOrNew)?;
628624
629625
<declaringConstantConstructorSignature> ::= // New rule.
630-
'const' 'this' ('.' <identifierOrNew>)? <declaringParameterList>;
626+
'const' 'this' <identifier>? <declaringParameterList>;
627+
628+
<constructorHead> ::= // New rule.
629+
'new' <identifier>?;
630+
631+
<factoryConstructorHead> ::= // New rule.
632+
'factory' <identifier>?;
631633
632634
<identifierOrNew> ::=
633635
<identifier>
634636
| 'new'
635637
638+
<factoryConstructorSignature> ::= // Modified rule.
639+
'const'? 'factory' <constructorName> <formalParameterList> // Old form.
640+
| 'const'? <factoryConstructorHead> <formalParameterList>; // New form.
641+
642+
<redirectingFactoryConstructorSignature> ::= // Modified rule.
643+
'const'? 'factory' <constructorName> <formalParameterList> '='
644+
<constructorDesignation> // Old form.
645+
| 'CONST'? <factoryConstructorHead> <formalParameterList> '='
646+
<constructorDesignation>; // New form.
647+
648+
<constantConstructorSignature> ::= // Modified rule.
649+
: 'const' <constructorName> <formalParameterList> // Old form.
650+
| 'const' <constructorHead> <formalParameterList> // New form.
651+
| <declaringConstantConstructorSignature>;
652+
636653
<simpleFormalParameter> ::= // Modified rule.
637654
'covariant'? <type>? <identifier>;
638655
@@ -688,28 +705,47 @@ constructors as well.
688705
A _declaring constructor_ declaration is a declaration that contains a
689706
`<declaringConstructorSignature>` with a `<declaringParameterList>`, or a
690707
declaration that contains a `<declaringConstantConstructorSignature>`, or
691-
it is a `<primaryConstructorNoConst>` in the header of a class, enum, or
692-
extension type declaration, together with a declaration in the body that
693-
contains a `<declaringConstructorSignature>` *(which does not contain a
708+
it is a `<primaryConstructor>` in the header of a class, enum, or extension
709+
type declaration, together with a declaration in the body that contains a
710+
`<declaringConstructorSignature>` *(which does not contain a
694711
`<declaringParameterList>`, because that's an error)*.
695712

696713
A class or extension type declaration whose class body is `;` is treated as
697714
a declaration whose body is `{}`.
698715

716+
The grammar is ambiguous with regard to the keyword `factory`. *For
717+
example, `factory() => C();` could be a method named `factory` with an
718+
implicitly inferred return type, or it could be a factory constructor.*
719+
720+
This ambiguity is resolved as follows: When a Dart parser expects to parse
721+
a `<memberDeclaration>`, and the first token is `factory`, it proceeds to
722+
parse the following input as a factory constructor.
723+
724+
*Another special exception is introduced with factory constructors in order
725+
to avoid breaking existing code:*
726+
727+
A factory constructor declaration of the form `factory C(...` where `C`
728+
is the name of the enclosing class, mixin class, enum, or extension type is
729+
treated as if `C` had been omitted.
730+
731+
*Without this special rule, such a declaration would declare a constructor
732+
named `C.C`. With this rule it declares a constructor named `C`, which
733+
is the same as today.*
734+
699735
Let _D_ be a class, extension type, or enum declaration.
700736

701-
A compile-time error occurs if _D_ includes a `<classNamePart>` that
702-
contains a `<primaryConstructorNoConst>`, and the body of _D_ contains a
737+
A compile-time error occurs if _D_ includes a `<classNameMaybePrimary>`
738+
that contains a `<primaryConstructor>`, and the body of _D_ contains a
703739
`<declaringConstructorSignature>` that contains a
704740
`<declaringParameterList>`.
705741

706742
*It is an error to have a declaring parameter list both in the header and
707743
in the body.*
708744

709-
A compile-time error occurs if _D_ includes a `<classNamePart>` that
710-
does not contain a `<primaryConstructorNoConst>`, and the body of _D_
711-
contains a `<declaringConstructorSignature>` that does not
712-
contain a `<declaringParameterList>`.
745+
A compile-time error occurs if _D_ includes a `<classNameMaybePrimary>`
746+
that does not contain a `<primaryConstructor>`, and the body of _D_
747+
contains a `<declaringConstructorSignature>` that does not contain a
748+
`<declaringParameterList>`.
713749

714750
*It is an error to have a declaring constructor in the class body, but
715751
no declaring parameter list, neither in the header nor in the body.*
@@ -1004,6 +1040,15 @@ then _k2_ has an initializer list with the same elements in the same order.
10041040

10051041
Finally, _k2_ is added to _D2_, and _D_ is replaced by _D2_.
10061042

1043+
### Language versioning
1044+
1045+
This feature is language versioned.
1046+
1047+
*It introduces a breaking change in the grammar, which implies that
1048+
developers must explicitly enable it. In particular, `factory() {}` in a
1049+
class body used to be a method declaration. With this feature it will be
1050+
a factory constructor declaration.*
1051+
10071052
### Discussion
10081053

10091054
This proposal includes support for adding the declaring header parameters to
@@ -1036,6 +1081,13 @@ of declaration, and the constructor might be non-const).
10361081

10371082
### Changelog
10381083

1084+
1.11 - October 30, 2025
1085+
1086+
* Introduce the new syntax for the beginning of a constructor declaration
1087+
(`new();` rather than `ClassName();`). Specify how to handle the
1088+
ambiguity involving the keyword `factory`. Clarify that this feature is
1089+
language versioned.
1090+
10391091
1.10 - October 3, 2025
10401092

10411093
* Rename the feature to 'declaring constructors'. Fix several small errors.

0 commit comments

Comments
 (0)