Skip to content

Commit 2ca55dc

Browse files
authored
Allow variables to be augmenting and augmented. (#4395)
Allow variables to be augmenting and augmented. Also allow the abstract variable syntax at the top level and for static fields. Fix #4387.
1 parent 545cdc3 commit 2ca55dc

File tree

1 file changed

+91
-82
lines changed

1 file changed

+91
-82
lines changed

working/augmentation-libraries/feature-specification.md

Lines changed: 91 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,25 @@ from changing the constructor to a factory.
106106

107107
## Syntax
108108

109-
There are a handful of grammar changes mostly around allowing `augment` before
110-
the various declarations that can be augmented allowing declarations to be less
111-
"complete" than they were required to be before this proposal since an
112-
augmentation can fill them in. For example, non-instance functions without
113-
bodies and enums without values.
109+
The syntax changes are simple but fairly extensive and touch several parts of
110+
the grammar so are broken out into separate sections.
111+
112+
### Top-level augmentations and incomplete top-level members
113+
114+
We allow an `augment` modifier before most top-level declarations.
115+
116+
Also, we allow incomplete declarations at the top level. This reuses the same
117+
syntax used inside a class to declare abstract variables, methods, getters,
118+
setters, and operators. For callable members, that means the body is `;`. For
119+
variable declarations, that means using `abstract`. *Example:*
120+
121+
```dart
122+
abstract int x; // Incomplete top-level variable.
123+
int get y; // Incomplete top-level getter.
124+
set z(int value); // Incomplete top-level setter.
125+
```
126+
127+
The new top-level grammar is:
114128

115129
```
116130
topLevelDeclaration ::= classDeclaration
@@ -123,13 +137,21 @@ topLevelDeclaration ::= classDeclaration
123137
| 'augment'? 'external' getterSignature ';'
124138
| 'augment'? 'external' setterSignature ';'
125139
| 'augment'? 'external' finalVarOrType identifierList ';'
126-
| 'augment'? functionSignature (functionBody | ';')
140+
| 'augment'? 'abstract' finalVarOrType identifierList ';'
127141
| 'augment'? getterSignature (functionBody | ';')
128142
| 'augment'? setterSignature (functionBody | ';')
143+
| 'augment'? functionSignature (functionBody | ';')
129144
| 'augment'? ('final' | 'const') type? initializedIdentifierList ';'
130145
| 'augment'? 'late' 'final' type? initializedIdentifierList ';'
131146
| 'augment'? 'late'? varOrType initializedIdentifierList ';'
147+
```
132148

149+
### Class-like declarations
150+
151+
We allow `augment` before class, extension type, and mixin declarations. *(Enums
152+
and extensions are discussed in subsequent sections.)*
153+
154+
```
133155
classDeclaration ::=
134156
'augment'? (classModifiers | mixinClassModifiers)
135157
'class' typeWithParameters superclass? interfaces?
@@ -164,8 +186,8 @@ declaration ::=
164186
| 'augment'? 'external'? 'static'? getterSignature ';'
165187
| 'augment'? 'external'? 'static'? setterSignature ';'
166188
| 'augment'? 'external'? 'static'? functionSignature ';'
167-
| 'external' ('static'? finalVarOrType | 'covariant' varOrType) identifierList ';'
168189
| 'augment'? 'external'? operatorSignature ';'
190+
| 'external' ('static'? finalVarOrType | 'covariant' varOrType) identifierList ';'
169191
| 'augment'? 'abstract' (finalVarOrType | 'covariant' varOrType) identifierList ';'
170192
| 'static' 'const' type? initializedIdentifierList ';'
171193
| 'static' 'final' type? initializedIdentifierList ';'
@@ -180,14 +202,26 @@ declaration ::=
180202
| 'augment'? constructorSignature (redirection | initializers)? ';'
181203
```
182204

183-
*Note that the grammar for putting `augment` before an extension type
184-
declaration doesn't allow also specifying a representation field. This is by
185-
design. An extension type augmentation always inherits the representation field
186-
of the introductory declaration and can't specify it.*
205+
As with top-level declarations, we also reuse the abstract member syntax with a
206+
`static` modifier to allow declaring incomplete static fields, methods, getters,
207+
setters, and operators. *Example:*
208+
209+
```dart
210+
class C {
211+
static abstract int x; // Incomplete static variable (getter and setter).
212+
static int get y; // Incomplete static getter.
213+
static set z(int value); // Incomplete static setter.
214+
}
215+
```
216+
217+
Note that the grammar for putting `augment` before an extension type declaration
218+
doesn't allow also specifying a representation field. This is by design. An
219+
extension type augmentation always inherits the representation field of the
220+
introductory declaration and can't specify it.
187221

188-
*Likewise, the grammar for an augmenting `mixin` declaration does not allow
222+
Likewise, the grammar for an augmenting `mixin` declaration does not allow
189223
specifying an `on` clause. Only the introductory declaration permits that. We
190-
could relax this restriction if compelling use cases arise.*
224+
could relax this restriction if compelling use cases arise.
191225

192226
### Enums
193227

@@ -605,6 +639,16 @@ subsections.
605639

606640
It's a **compile-time** error if:
607641

642+
* An augmentation declaration is applied to a declaration of a different kind.
643+
For example, augmenting a `class` with a `mixin`, an `enum` with a function,
644+
a method with a getter, a constructor with a static method, etc.
645+
646+
The exception is that a variable declaration (introductory or augmenting) is
647+
treated as a getter declaration (and a setter declaration if non-final) for
648+
purposes of augmentation. These implicit declarations can augment and be
649+
augmented by other explicit getter and setter declarations. (See "Augmenting
650+
variables, getters, and setters" for more details.)
651+
608652
* A library contains two top-level declarations with the same name, and one of
609653
the declarations is a class-like declaration and the other is not of the
610654
same kind, meaning that either one is a class, mixin, enum, extension or
@@ -732,91 +776,55 @@ It's a **compile-time** error if:
732776
* The augmenting function specifies any default values. *Default values are
733777
defined solely by the introductory function.*
734778

735-
* A function is not complete after all augmentations are applied, unless it
736-
is in a context where it can be abstract. *Every function declaration
737-
eventually needs to have a body filled in unless it's an instance method
738-
that can be abstract. In that case, if no declaration provides a body, it
739-
is considered abstract.*
779+
* A function is not complete after all augmentations are applied, unless it's
780+
an instance member and the surrounding class is abstract. *Every function
781+
declaration eventually needs to have a body filled in unless it's an
782+
instance method that can be abstract. In that case, if no declaration
783+
provides a body, it is considered abstract.*
740784

741-
### Augmenting variables
785+
### Augmenting variables, getters, and setters
742786

743-
A class-like augmentation can add *new* variables (that is instance or static
744-
fields) to the type being augmented:
787+
For purposes of augmentation, a variable declaration is treated as implicitly
788+
defining a getter whose return type is the type of the variable. If the variable
789+
is not `final`, or is `late` without an initializer, then the variable
790+
declaration also implicitly defines a setter with a parameter named `_` whose
791+
type is the type of the variable.
745792

746-
```dart
747-
class C {}
793+
If the variable is `abstract`, then the getter and setter are incomplete,
794+
otherwise they are complete. *For non-abstract variables, the compiler
795+
synthesizes a getter that accesses the backing storage and a setter that updates
796+
it, so these members have bodies.*
748797

749-
augment class C {
750-
int x = 3;
798+
A getter can be augmented by another getter, and likewise a setter can be
799+
augmented by a setter. This is true whether the getter or setter is explicitly
800+
declared or implicitly declared using a variable declaration.
751801

752-
static int y = 4;
753-
}
754-
```
755-
756-
Variable declarations themselves can't be augmented (by variables, getters, or
757-
setters, even if the getter or setter is incomplete), with the exception of
758-
abstract instance variable declarations.
759-
760-
*A variable declaration implicitly has code for the synthesized getter and
761-
setter that access and modify the underlying backing storage. Since we don't
762-
allow augmentations to replace code, that implies that augmentations can't
763-
change variables. So we don't allow them to be augmented.*
764-
765-
#### Abstract instance variables
766-
767-
Dart supports `abstract` field declarations. They are syntactic sugar for
768-
declaring an abstract getter and, if not `final`, an abstract setter. They don't
769-
actually declare a variable with any backing storage.
770-
771-
Because abstract variables are effectively abstract getter and setter
772-
declarations, they can be augmented and used in augmentations just like function
773-
declarations:
774-
775-
*Examples:*
776-
777-
```dart
778-
class C {
779-
// Augment an abstract variable with a getter:
780-
abstract final int a;
781-
augment int get a => 1; // OK.
802+
*Since non-abstract variables are complete, that implies that it is an error to
803+
augment a non-abstract variable declaration with a complete getter, setter, or
804+
variable declaration. Likewise, it is an error to augment a complete getter or
805+
setter with a non-abstract variable declaration.*
782806

783-
// Augment an abstract variable with a getter and setter:
784-
abstract int b;
785-
augment int get b => 1; // OK.
786-
augment set b(int value) {} // OK.
787-
788-
// Augment a getter with an abstract variable:
789-
int get c;
790-
791-
@someMetadata
792-
augment abstract final int c; // (Not very useful, but valid.)
793-
}
794-
```
807+
It's a **compile-time error** if:
795808

796-
For purposes of [signature matching][], the implicit setter induced by a
797-
non-final abstract variable has a positional parameter named `_`. *This means
798-
you can augment an abstract variable with a setter that uses whatever positional
799-
parameter name you want:*
809+
* The signature of the augmenting getter or setter does not [match][signature
810+
matching] the signature of the augmented getter or setter.
800811

801-
```dart
802-
class C {
803-
abstract int x;
804-
}
812+
* A `const` variable declaration is augmented or augmenting.
805813

806-
augment class C {
807-
augment set x(int anyNameIWant) { // OK.
808-
// ...
809-
}
810-
}
811-
```
814+
* A getter or setter (including one implicitly induced by a variable
815+
declaration) is not complete after all augmentations are applied, unless
816+
it's an instance member and the surrounding class is abstract. *Every getter
817+
or setter declaration eventually needs to have a body filled in unless it's
818+
an instance member that can be abstract. In that case, if no declaration
819+
provides a body, it is considered abstract.*
812820

813821
### Augmenting enums
814822

815823
An augmentation of an enum type can add new members to the enum, including new
816824
enum values. Enum values are appended in augmentation application order.
817825

818826
Enum values themselves can't be augmented since they are essentially constant
819-
variables and variables can't be augmented.
827+
variables and constant variables can't be augmented.
820828

821829
It's a **compile-time error** if:
822830

@@ -1121,6 +1129,7 @@ and assume the third point is always true.
11211129

11221130
* Remove `augment` from typedef grammar since typedefs can no longer be
11231131
augmented (#4388).
1132+
* Allow augmenting variable declarations (#4387).
11241133

11251134
### 1.35
11261135

0 commit comments

Comments
 (0)