Skip to content

Commit 3d89f16

Browse files
authored
Update specification for enhanced parts with extension resolution (#4120)
* Update feature specification for enhanced parts with extension resolution. Adds rules for resolving implicit extension applications in the new, more complicated, scope.
1 parent 57da765 commit 3d89f16

File tree

1 file changed

+92
-31
lines changed

1 file changed

+92
-31
lines changed

working/augmentation-libraries/parts_with_imports.md

Lines changed: 92 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
# Part files with imports
22

33
4-
Version: 1.0 (See [Changelog](#Changelog) at end)
4+
Version: 1.1 (See [Changelog](#Changelog) at end)
55

6-
This is a stand-along definition of _improved part files_, where the title of
6+
This is a stand-alone definition of _enhanced part files_, where the title of
77
this document/feature is highlighting only the most prominent part of the
88
feature. This document is extracted and distilled from the [Augmentations][]
99
specification. The original specification introduced special files for
@@ -197,7 +197,7 @@ as a `<partDirective>`, or if its leading `<partHeader>`'s `<uri>` string,
197197
resolved as a URI reference against the URI *U*, does not denote the library of
198198
*P*. _That is, if a Dart file has a part directive, its target must be a part
199199
file whose “part of” directive points back to the first Dart file. Nothing new,
200-
except that now the parent file may not be a library file.)_
200+
except that now the parent file may not be a library file._
201201

202202
### Resolution and scopes (part and import directives)
203203

@@ -269,7 +269,7 @@ defined as:
269269

270270
That is: The combined import scope of a Dart file is a chain of the combined
271271
import scopes of the file and its parent files, each step adding two scopes:
272-
The (unnamed, top-level) import scope of the unprefixed imports and the prefix
272+
The (unnamed) import scope of the unprefixed imports and the prefix
273273
scope with prefixed imports, each shadowing names further up in the chain.
274274

275275
The *top-level scope* of a Dart file is a library *declaration scope*
@@ -279,14 +279,16 @@ the combined import scope of that Dart file. _Each Dart file has its own copy
279279
of the library declaration scope, all containing the same declarations, because
280280
the declaration scopes of different files have different parent scopes._
281281

282-
**It’s a compile-time error ** if any file declares an import prefix with the
282+
**It’s a compile-time error** if any file declares an import prefix with the
283283
same base name as a top-level declaration of the library.
284284

285285
_We have split the prefixes out of the top-level scope, but we maintain that
286-
they must not have the same names anyway. Any prefix that has the same name as
287-
a top-level declaration of the library is impossible to reference, because the
288-
library declaration scope always precedes the prefix scope in any scope chain
289-
lookup. This does mean that adding a top-level declaration in one part file may
286+
they must not have the same names anyway. Not because it's a problem for the
287+
compiler or language, but because it's probably a sign of a user error.
288+
Any prefix that has the same name as a top-level declaration of the library
289+
is impossible to reference, because the library declaration scope
290+
always precedes the prefix scope in any scope chain lookup.
291+
This does mean that adding a top-level declaration in one part file may
290292
conflict with a prefix name in another part file in a completely different
291293
branch of the library file tree. That is not a conflict with the “other file’s
292294
imports cannot break your code” principle, rather the error is in the file
@@ -296,14 +298,56 @@ library, so the library author should fix the conflict by renaming the prefix.
296298
That such a name conflict is a compile-time error, makes it much easier to
297299
detect if it happens._
298300

301+
#### Resolving implicitly applied extensions
302+
303+
The only change to implicit extension application in this feature
304+
is in the definition of whether an extension is *available*.
305+
Whether an extension is *applicable*, its *specificity* if applicable,
306+
and how that is used to to choose between multiple available and applicable
307+
extensions is unchanged.
308+
309+
An extension declaration being *available* has been defined as being
310+
declared or *imported* by the current library.
311+
Being imported by a library means that the library has at least one
312+
import directive which *imports the extensions*, which again means that it
313+
imports a library which has the extension declaration in its export scope,
314+
and the import directive does not have a `show` or `hide` combinator
315+
which hides the name of the extension declaration.
316+
317+
With this feature, imports are not global to the entire library,
318+
and neither is extension availability.
319+
320+
Extension availability is defined *per file*, and an extension
321+
is available *in a Dart file* if any of:
322+
* The extension is declared by the library of the Dart file.
323+
* The extension is available *by import* in the Dart file.
324+
325+
where an extension is available by import in a Dart file if any of:
326+
* That file contains an import directive which *imports the extension*
327+
* That file is a part file and the extension is (recursively) available
328+
by import in its parent file.
329+
330+
(One way to visualize the availability is to associate declared
331+
or imported extensions with scopes. If a file has an import directive
332+
which imports an extension, the extension is associated with the
333+
import scope of that file, or with the prefix import scope
334+
if the import is prefixed. A declaration in the library itself
335+
is associated with the top-level scope of each file.
336+
Then an extension is available in a file if it is associated with
337+
any scope in the top-level scope chain of that file.)
338+
339+
There is no attempt to *prioritize* available extensions based on
340+
where they are imported. Every extension imported or declared in the
341+
file's top-level scope chain is equally available.
342+
299343
### Export directives
300344

301345
Any Dart file can contain an `export` directive. It makes no difference which
302-
file an `export` is in, its declarations (filtered by any `hide` or `show`
303-
modifiers) are added to the library’s single export scope, along with those of
304-
any other `export`s in the library and the non-private declarations of the
305-
library itself. Conflicts are handled as usual (as an error if it’s not the
306-
*same* declaration).
346+
file an `export` is in, its exported declarations (filtered by any `hide` or
347+
`show` combinators) are added to the library’s single export scope,
348+
along with those of any other `export` directives in the library and
349+
the all non-private declarations of the library itself. Conflicts are handled
350+
as usual (as an error if it’s not the *same* declaration).
307351

308352
Allowing a part file to have its own export is mainly for consistency.
309353
Most libraries will likely keep all `export` directives in the library file.
@@ -332,20 +376,21 @@ URI denoting that part file.
332376
* _It’s a compile-time error if a Dart file has two `part` directives with
333377
the same URI, so each included part file is included exactly once._
334378
* _It’s a compile-time error if a `part` directive denotes a file which is
335-
not a part file._
379+
not a Dart part file._
336380

337381
The *parent file* of a part file is the file denoted by the URI of the
338382
`part of` declaration of the part file. A library file has no parent file.
339383

340384
* _It’s a compile-time error if a part file is included by any Dart file
341385
other than the part file’s parent file._
342386
* The *includes* and *is the parent file of* properties are equivalent for
343-
the files of a Dart program. A Dart file includes a part file if, and only
344-
if, the Dart file is the parent file of the part file, otherwise there is a
345-
compile-time error. (There are no restrictions on the parent file of a part
346-
file which is not part of a library of a Dart program. Dart semantics is
347-
only assigned to entire libraries and programs, not individual part files.
348-
We’ll refer to the relation as both one file being included by another, and
387+
the files of a valid Dart program. A Dart file includes a part file if,
388+
and only if, the Dart file is the parent file of the part file, otherwise
389+
there is a compile-time error.
390+
_(There are no restrictions on the parent file of a part file which is not
391+
part of a library of a Dart program. Dart semantics is only assigned to
392+
entire libraries and programs, not individual part files.)_
393+
We’ll refer to this relation as both one file being included by another, and
349394
the former file being the parent (file) of the latter file.
350395

351396
Two or more part files are called *sibling part files* (or just
@@ -359,17 +404,17 @@ the Dart file, or if the file is a *sub-part* of a file included by the
359404
*included by* relation. We’ll refer to it by saying either that one Dart
360405
file is an ancestor file of another part file, or that a part file is a
361406
sub-part of another Dart file.
362-
* <a name="part_cycle"></a>_It’s a compile-time error if a part file is a sub-part
363-
of itself._
364-
That is, if the *includes* relation has a cycle. This is not a *necessary*
407+
* <a name="part_cycle"></a>_It’s a compile-time error if a part file is
408+
a sub-part of itself._
409+
That is, if the *includes* relation has a cycle. _This is not a *necessary*
365410
error from the language's perspective, since no library can contain such a
366411
part file without introducing another error; at the first `part` directive
367412
reachable from a library file which includes a file from the cycle,
368-
the including file is not the parent of that file.
369-
The rule is included as a help to tools that try to analyzer Dart code
413+
the including file is not the parent of that file._
414+
_The rule is included as a help to tools that try to analyzer Dart code
370415
starting at individual files, they can then assume that either a part file
371416
has an ancestor which is a library file, or there is a compile-time error.
372-
Or an infinite number of part files.)
417+
Or an infinite number of part files._
373418

374419
The *sub-tree* of a Dart file is the set of files containing the file itself
375420
and all its sub-parts. The *root* of a sub-tree is the Dart file that all other
@@ -399,9 +444,9 @@ least containing sub-tree for any set of nodes._
399444
included parts or some in the file itself, and then no included part file
400445
contains all the files, so there is no lesser containing file.)_
401446

402-
The *files of a library* is the entire sub-tree of the defining library file.
403-
It contains the library file.
404-
The sub-tree of a part file of a library contains no library file.
447+
The *files of a library* is the entire sub-tree of the defining library file,
448+
and the only subtree which contains the library file.
449+
The sub-tree of a part file of a library contains only part files.
405450

406451
In short:
407452

@@ -610,13 +655,29 @@ will already be compatible.
610655

611656
[string_part_of_lint]: https://dart.dev/tools/linter-rules/use_string_in_part_of_directives "use_string_in_part_of_directives lint"
612657

658+
### Development
659+
660+
The experiment name for this feature is `enhanced-parts`.
661+
662+
The macro feature requires both this feature and the augmentations feature.
663+
Tools can choose to enable these features automatically when the macros feature
664+
is enabled, or they can enable it selectively only for code generated by macros.
665+
666+
The augmentations feature does not require enhanced parts, it can work
667+
within the existing part requirements.
668+
613669
## Changelog
614670

671+
### 1.1
672+
673+
* Specifies resolution of implicit extension declarations.
674+
* Names the feature "Enhanced parts".
675+
* Fixes some typos.
676+
615677
### 1.0
616678

617679
* Initial version. The corresponding version of [Augmentations], which refers
618680
to part files with imports, is version 1.21.
619-
620681
* Combines augmentation libraries, libraries and part files into just
621682
libraries and part files, where the part files can have import, export and
622683
further part directives. Those part directives can use configurable imports.

0 commit comments

Comments
 (0)