Description
I specified "part files with imports" (#3800) to generalize over "augmentation libraries" and part files, so that part files can have import (etc.).
@jakemac53 had some suggestions on abilities of part files to shadow names inherited from the parent file, which differ from the current specification. The options currently on the table can be summarized as:
- Part files inherit the imports and import prefixes of their parent file (the "combined import scope").
- Part file's own imports either:
- Shadow inherited names, taking precedence.
- Combine with inherited imports, causing conflict if the same name is imported more than once.
- Part files either:
- Inherit the declaration scope of their parent file, allowing its imports to shadow declarations, and then adds its own declaration scope on top containing all declarations in the file's subtree (those always take precedence over imports, declarations in parents or siblings do not).
- Do not inherit the declaration scope of the parent, but introduce their own which contains all declarations in the library. A library declaration always takes precedence over imports, anywhere. (And conflict with import prefixes of the same name).
The four combinations would have the following top-level scopes:
-
Shadow inherited imports, shadow inherited declarations and only redeclared declarations from subtree:
Parent's inherited frames Parent import scope (unprefixed imports) Parent import prefix scope (prefixed import names) Parent declaration scope (all declarations of entire subtree) Own import scope (unprefixed imports) Own import prefix scope (prefixed import names) Own declaration scope (all declarations of entire subtree) This version can probably combine the prefix scope and the declaration scope, since we don't allow a prefix with the same name as a declaration in the declaration scope.
It's the maximally permissive combination: A part file can import any name and have it accessible as long as there is no
declaration with the same name in the part's own part-subtree. That also means that it's possible to shadow a declaration of
the same library with an import, making it inaccessible in the subtree. It's your library, knock yourself out, or use a prefix
(which also doesn't conflict with anything from a parent or sibling.)
Sibling parts can't introduce conflicting declarations, since the parent file's declaration scope must contain them all. -
Shadow inherited imports, redeclare every declaration in library
Parent's inherited frames Parent import scope (unprefixed imports) Parent import prefix scope (prefixed import names) Own import scope (unprefixed imports) Own import prefix scope (prefixed import names) Own declaration scope (all declarations of library) This variant makes sure that library declarations are ubiquitous. The declaration scope is library wide, and
everybody has to agree on those names. That means that a declaration anywhere in the library prevents
a part file from using that name as a prefix, and shadows any import with that name.
(Solution: Import with another prefix, just like always.)
Imports, on the other hand, are just suggestions. A part file can shadow any import it inherits from its
parent with an import of its own. That allows part files (and parent files) to concentrate on the imports they
need themselves, while still allowing a library author to move any chunk of code into a new part file of
the file it came from. -
Conflicting inherited imports, shadow inherited declarations and only redeclared declarations from subtree:
Parent's inherited frames Parent import scope (unprefixed imports) Parent import prefix scope (prefixed import names) Parent declaration scope (all declarations of entire subtree) Own import scope w/ conflicts (unprefixed imports) Own import prefix scope w/ conflicts (prefixed import names) Own declaration scope (all declarations of entire subtree) Where the "/w conflicts" means that if a name is imported in the part, and the same name is accessible in the parent scope
chain as an import for a different declaration, then the name is conflicted in the part file's scope. (Being conflicted is only an
error if the name is accessed.)
This allows a part file to shadow declarations from siblings (and parents), but not to ignore imports from parents.
This is more about not being obstructed by declarations in sibling libraries, while still considering every import
inherited from the parent file as intentional. -
Conflicting inherited imports, redeclare every declaration in library:
Parent's inherited frames Parent import scope (unprefixed imports) Parent import prefix scope (prefixed import names) Own import scope w/ conflicts (unprefixed imports) Own import prefix scope w/ conflicts (prefixed import names) Own declaration scope (all declarations of library) This also makes the library's declarations ubiquitous, but also makes it an error to conflict with an inherited
import. It's the most restrictive variant, in that part file can conflict with any declaration anywhere, and any
import of its parent chain.
So, which version do we want, or are there more options?
@dart-lang/language-team