Skip to content

Commit cbca2be

Browse files
committed
Small tweaks to augmentation libraries:
- Allow type parameter names to be different in type augmentations. - Specify augmentation merge order more precisely. - Disallow parts in augmentations.
1 parent 85e7b86 commit cbca2be

File tree

1 file changed

+103
-30
lines changed

1 file changed

+103
-30
lines changed

working/augmentation-libraries/feature-specification.md

Lines changed: 103 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Augmentation Libraries
22

3-
Author: [email protected], Version: 1.5 (see [Changelog](#Changelog) at end)
3+
Author: [email protected], Version: 1.6 (see [Changelog](#Changelog) at end)
44

55
Augmentation libraries allow splitting a Dart library into files. Unlike part
66
files, each augmentation has its [own imports][part imports] and top-level
@@ -130,10 +130,14 @@ However, augmentations do *not* share an import scope with the main library or
130130
each other. The libraries one augmentation imports are visible only to that
131131
file.
132132

133-
It is a compile-time error if a top-level declaration in an augmentation has the
134-
same name as a declaration in the main library or another of its augmentations
135-
(unless it is an *augmenting* declaration, described below). This is the same
136-
error conceptually as having a name collision in one file.
133+
It is a compile-time error if:
134+
135+
* A top-level declaration in an augmentation has the same name as a
136+
declaration in the main library or another of its augmentations (unless it
137+
is an *augmenting* declaration, described below). *This is the same error
138+
conceptually as having a name collision in one file.*
139+
140+
* An augmentation library contains any `part` directives.
137141

138142
### Applying an augmentation library
139143

@@ -161,32 +165,81 @@ Since the main library and its augmentation both point to each other, these
161165
rules imply that a given augmentation file can only be used to augment a single
162166
library.
163167

168+
### Merge order
169+
164170
A library may apply multiple augmentations to itself. Also, augmentation files
165171
may themselves contain `import augment` directives. The entire tree of
166-
augmentations is recursively applied to the main library. In most cases, the
167-
order that augmentations are applied doesn't matter, but it is visible in a
168-
couple of corners where the merge process involves "appending". For those cases,
169-
merge order is defined as a depth-first pre-order traversal of the `import
170-
augment` directives in the main library and its augmentations. So, in:
172+
augmentations is recursively applied to the main library. The merge order is
173+
defined as a depth-first pre-order traversal of the `import augment` directives
174+
starting at the main library.
175+
176+
For example:
171177

172178
```
173179
// main.dart
174180
import augment 'a.dart';
175181
import augment 'c.dart';
176182
183+
class C {}
184+
185+
void trace() {
186+
print('main');
187+
}
188+
177189
// a.dart
178190
library augment 'main.dart';
179191
180192
import augment 'b.dart';
181193
194+
augment class C {}
195+
196+
augment void trace() {
197+
augment super.trace();
198+
print('a');
199+
}
200+
182201
// b.dart
183202
library augment 'a.dart';
184203
204+
class D {}
205+
206+
augment void trace() {
207+
augment super.trace();
208+
print('b');
209+
}
210+
185211
// c.dart
186212
library augment 'main.dart';
213+
214+
augment class D {}
215+
216+
augment void trace() {
217+
augment super.trace();
218+
print('c');
219+
}
187220
```
188221

189-
The merge order is `a.dart`, `b.dart`, then `c.dart`.
222+
The merge order is `main.dart`, `a.dart`, `b.dart`, then `c.dart`. The
223+
declarations in those libraries—new declarations or augmentations—
224+
are processed in that order.
225+
226+
This order is user-visible in two ways:
227+
228+
* A non-augmenting declaration must appear first before it can be augmented.
229+
For example, `C` in `main.dart` is augmented by `C` in `a.dart`. Likewise,
230+
`D` in `b.dart` is augmented by `D` in `c.dart`. Note that the latter is
231+
allowed even though `b.dart` does not itself import `c.dart`.
232+
233+
* When the same declaration is augmented multiple times, merge order
234+
determines the order that those wrappers are applied. When the `trace()`
235+
function is called, it prints:
236+
237+
```
238+
main
239+
a
240+
b
241+
c
242+
```
190243
191244
**TODO: Should it be a compile-time error if the main library and augmentation
192245
are in different packages?**
@@ -215,6 +268,15 @@ The same declaration can be augmented multiple times by separate augmentation
215268
libraries. When that happens, the merge order defined previously determines
216269
which order the wrapping is applied.
217270
271+
It is a compile-time error if:
272+
273+
* An augmenting declaration has no corresponding original declaration to
274+
apply to.
275+
276+
* An augmenting declaration appears in a library before the library where the
277+
original declaration occurs, according to merge order. *An augmentation
278+
library can both declare a new declaration and augment it in the same file.*
279+
218280
### Augmenting types
219281
220282
A class, mixin, enum, or extension declaration can be marked with an `augment`
@@ -230,8 +292,8 @@ This means that instead of creating a new type declaration, the augmentation
230292
modifies a corresponding declaration in the main library or one of its other
231293
augmentations.
232294

233-
A class augmentation may specify `implements` and `with` clauses. When those
234-
appear, the specified superinterfaces and mixins are appended to the main
295+
A class or enum augmentation may specify `implements` and `with` clauses. When
296+
those appear, the specified superinterfaces and mixins are appended to the main
235297
class's superinterface and mixin lists, respectively.
236298

237299
**TODO: Is appending the right order for mixins?**
@@ -260,14 +322,15 @@ It is a compile-time error if:
260322
* The augmenting type is marked `abstract`. The main library determines
261323
whether the class is abstract or not.
262324

263-
* The type parameters of the type augmentation do not exactly match the
264-
original type's type parameters. This means there must be the same number of
265-
type parameters with the same names and same bounds.
325+
* The type parameters of the type augmentation do not match the original
326+
type's type parameters. This means there must be the same number of type
327+
parameters with the same bounds.
266328

267329
*Since repeating the type parameters is, by definition, redundant, this
268330
doesn't accomplish anything semantically. But it ensures that anyone reading
269331
the augmenting type can see the declarations of any type parameters that it
270-
uses in its body.*
332+
uses in its body and avoids potential confusion with other top-level
333+
variables that might be in scope in the augmentation library.*
271334

272335
### Augmenting functions
273336

@@ -656,22 +719,28 @@ process a theoretical Dart implementation could take.
656719

657720
To apply an augmentation to the main library:
658721

722+
1. Merge the augmentation's declarations into the main library's top-level
723+
namespace using the following procedure.
724+
659725
1. For each `import augment` directive in the augmentation library, in
660726
syntactic order:
661727

662728
1. Apply the imported augmentation to the main library using this
663729
procedure, recursively.
664730

665-
1. For each declaration in the augmentation:
731+
To merge a set of declarations `D` into a namespace:
666732

667-
1. Merge the declaration into the main library's top-level namespace using
668-
the following procedure.
733+
1. For each non-augmenting declaration in `D`:
669734

670-
To merge a declaration into a namespace:
735+
1. If a declaration with that name already exists in the namespace, error.
736+
(Exception: setters do not collide with getters and final variables.)
737+
738+
1. Else, add the declaration to the namespace.
671739

672-
1. If the declaration is marked `augment`:
740+
1. For each augmenting declaration in `D`:
673741

674742
1. If the namespace does not have a declaration with that name, error.
743+
*A non-augmenting declaration must occur before it can be augmented.*
675744

676745
1. If the corresponding declaration in the namespace is not the same kind,
677746
error. "Kind" means class, mixin, function, etc. Getters, setters, and
@@ -706,20 +775,13 @@ To merge a declaration into a namespace:
706775
**TODO: What is the syntax for calling a prefix operator's original
707776
code?**
708777

709-
1. Else, if the declaration is a variable:
778+
1. Else, the declaration is a variable:
710779

711780
1. Replace a matching variable, getter, and/or setter in the namespace
712781
with the declaration. Inside the augmenting variable's initializer
713782
expression, an `augment super` expression invokes the original
714783
variable initializer.
715784

716-
1. Else, it is a new declaration in the augmentation library:
717-
718-
1. If a declaration with that name already exists in the namespace, error.
719-
(Exception: setters do not collide with getters and final variables.)
720-
721-
1. Else, add the declaration to the namespace.
722-
723785
## Deprecating part files
724786

725787
Part files have been [discouraged for many years][discourage]. They are still
@@ -735,6 +797,17 @@ language and our tools.
735797

736798
## Changelog
737799

800+
### 1.6
801+
802+
* Allow class augmentations to use different names for type parameters. This
803+
isn't particular valuable, but is consistent with functions augmentations
804+
which are allowed to change the names of positional parameters.
805+
806+
* Specify that a non-augmenting declaration must occur before any
807+
augmentations of it, in merge order.
808+
809+
* Specify that augmentations can't have parts (#2057).
810+
738811
### 1.5
739812

740813
* Augmentation libraries share the same top-level declaration and private

0 commit comments

Comments
 (0)