Skip to content

Commit 5226bc7

Browse files
authored
With "Unquoted Imports" disallow unquoted part of library names. (#4262)
With "Unquoted Imports" disallow unquoted part of library names. Fix #4038.
1 parent 81a8f06 commit 5226bc7

File tree

1 file changed

+105
-83
lines changed

1 file changed

+105
-83
lines changed

accepted/future-releases/unquoted-imports/feature-specification.md

Lines changed: 105 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Author: Bob Nystrom
44

55
Status: Accepted
66

7-
Version 0.4 (see [CHANGELOG](#CHANGELOG) at end)
7+
Version 0.5 (see [CHANGELOG](#CHANGELOG) at end)
88

99
Experiment flag: unquoted-imports
1010

@@ -341,20 +341,80 @@ after the directives outside of the path. These are all valid:
341341

342342
```dart
343343
import /* Weird but OK. */ some/path;
344-
export some/path; // Hi there.
345-
part some/path // Before the semicolon? Really?
344+
import some/path; // Hi there.
345+
export some/path // Before the semicolon? Really?
346346
;
347347
```
348348

349349
The syntax that results from the above few sections is simple to tokenize and
350350
parse while looking like a single opaque "unquoted string" to users and tools.
351351

352+
### Part of directives
353+
354+
In Dart today, `part of` directives can already contain unquoted dotted
355+
identifiers, like:
356+
357+
```dart
358+
// some_lib.dart
359+
library some.lib;
360+
361+
part 'some_part.dart';
362+
363+
// some_part.dart
364+
part of some.lib;
365+
```
366+
367+
This is a legacy syntax from when library names were more widely used in Dart.
368+
Library names in `part of` directives have been deprecated for many years
369+
because the syntax doesn't work well with many tools. How is a given tool
370+
supposed to know where to find the library that happens to contain a `library`
371+
directive with that name? The quoted URI syntax was added later specifically to
372+
address that point and users are encouraged by documentation and lints to use
373+
the quoted syntax.
374+
375+
Looking at a corpus of 122,420 files:
376+
377+
```
378+
-- Directive (443733 total) --
379+
352744 ( 79.495%): import =========================================
380+
55471 ( 12.501%): export =======
381+
17823 ( 4.017%): part ===
382+
17695 ( 3.988%): part of ===
383+
```
384+
385+
So `part of` directives are fairly rare to begin with. Of them, most use the
386+
recommended URI syntax and would not be affected by this change:
387+
388+
```
389+
-- Part of (17695 total) --
390+
13229 ( 74.761%): uri ===================================
391+
4466 ( 25.239%): library name ============
392+
```
393+
394+
If we reinterpreted that existing syntax to refer to another package instead of
395+
a library within the current package, user breakage is likely and would be very
396+
confusing.
397+
398+
To avoid potential user confusion and breakage, the new syntax in this proposal
399+
isn't allowed in `part or` or `part` directives. We disallow it in `part of`
400+
to avoid confusion with the legacy syntax, and we disallow it in `part` to be
401+
symmetric with `part of`.
402+
403+
Further, we make a **language-versioned breaking change** and remove support for
404+
unquoted library identifiers in `part of` directives completely. That way, a
405+
user never sees syntax in a `part of` file that *looks* like a package path but
406+
means something else.
407+
408+
*Since part files should realistically always be part of the same package that
409+
contains the library that owns them, the new unquoted syntax is of limited use
410+
for part files anyway. Quoted relative URIs are shorter and more idiomatic.*
411+
352412
## Syntax
353413

354414
The normative stuff starts now. Here is the proposal:
355415

356-
We add a new rule and hang it off the existing `uri` rule already used by import
357-
and export directives:
416+
We replace the existing `uri` rule with the following rule along with a couple
417+
of helper rules:
358418

359419
```
360420
uri ::= stringLiteral | packagePath
@@ -371,22 +431,33 @@ between any of the `segmentComponent`, `/`, or `.` tokens in a `packagePath`.
371431
*In other words, there can be nothing except the terminals themselves from the
372432
first `segmentComponent` in the `packagePath` to the last.*
373433

374-
*An import, export, or part directive can continue to use a `stringLiteral` for
375-
the quoted form (which is what they will do for relative references). But they
376-
can also use a `packagePath`, which is a slash-separated series of segments,
377-
each of which is a series of dot-separated components.*
434+
*An import or export directive can continue to use a `stringLiteral` for the
435+
quoted form (which is what they will do for relative references). But they can
436+
also use a `packagePath`, which is a slash-separated series of segments, each of
437+
which is a series of dot-separated components.*
438+
439+
### Disallowing unquoted part and part-of directives.
378440

379-
### Part directive lookahead
441+
We change the `partDirective` and `partHeader` rules to:
380442

381-
*There are two directives for working with part files, `part` and `part of`.
382-
This means that when the parser sees `part of`, it doesn't immediately know if
383-
it is looking at a `part` directive followed by an unquoted identifier like
384-
`part of;` or `part of.some/other.thing;` versus a `part of` directive like
385-
`part of thing;` or `part of 'uri.dart';` It must lookahead past the `of`
386-
identifier to see if the next token is `;`, `.`, `/`, or another identifier.*
443+
```
444+
partDirective ::= metadata 'part' stringLiteral ';'
445+
partHeader ::= metadata 'part' 'of' stringLiteral ';'
446+
```
447+
448+
*As part of [augmentations][], we are also planning to [expand the power of part
449+
files][enhanced parts]. That includes supporting configurable part directives
450+
(but not configurable part-of. When/if that happens, this grammar will need to
451+
be tweaked to something like:*
452+
453+
```
454+
partDirective ::= metadata 'part' configurableQuotedUri ';'
455+
configurableQuotedUri ::= stringLiteral configurationQuotedUri*
456+
configurationQuotedUri ::= 'if' '(' uriTest ')' stringLiteral
457+
```
387458

388-
*This may add some complexity to parsing, but should be minor. Dart's grammar
389-
has other places that require much more (sometimes unbounded) lookahead.*
459+
[augmentations]: https://github.com/dart-lang/language/blob/main/working/augmentation-libraries/feature-specification.md
460+
[enhanced parts]: https://github.com/dart-lang/language/blob/main/working/augmentation-libraries/parts_with_imports.md
390461

391462
## Static semantics
392463

@@ -461,8 +532,7 @@ There are no runtime semantics for this feature.
461532

462533
## Compatibility
463534

464-
This feature is fully backwards compatible for `import`, `export`, and `part`
465-
directives.
535+
This feature is fully backwards compatible for `import` and `export` directives.
466536

467537
For all directives, we still allow quoted "dart:" and "package:" imports. Users
468538
may be compelled to use the existing syntax in uncommon corner cases where the
@@ -474,73 +544,21 @@ migrated to the new style and the old quoted forms will be essentially vestigial
474544
syntax (similar to names after `library` directives). A future version of Dart
475545
may make a breaking change and remove support for the old syntax.
476546

477-
### Part-of directives
478-
479-
The `part of` directive allows a library name after `of` instead of a string
480-
literal. With this proposal, that syntax is now ambiguous. Is it interpreted
481-
as a library name, or as an unquoted URI that should be converted to a URI?
482-
In other words, given:
483-
484-
```dart
485-
part of foo.bar;
486-
```
487-
488-
Is the file saying it's a part of the library containing `library foo.bar;` or
489-
that it's part of the library found at URI `package:foo.bar/bar.dart`?
490-
491-
Library names in `part of` directives have been deprecated for many years
492-
because the syntax doesn't work well with many tools. How is a given tool
493-
supposed to know where to find the library that happens to contain a `library`
494-
directive with that name? The quoted URI syntax was added later specifically to
495-
address that point and users are encouraged by documentation and lints to use
496-
the quoted syntax.
497-
498-
Looking at a corpus of 122,420 files:
499-
500-
```
501-
-- Directive (443733 total) --
502-
352744 ( 79.495%): import =========================================
503-
55471 ( 12.501%): export =======
504-
17823 ( 4.017%): part ===
505-
17695 ( 3.988%): part of ===
506-
```
507-
508-
So `part of` directives are fairly rare to begin with. Of them, most use the
509-
recommended URI syntax and would not be affected by this change:
510-
511-
```
512-
-- Part of (17695 total) --
513-
13229 ( 74.761%): uri ===================================
514-
4466 ( 25.239%): library name ============
515-
```
516-
517-
In total, only about 1% of directives are `part of` with a library name:
518-
519-
```
520-
-- URI (443733 total) --
521-
352744 ( 79.495%): import ===========================
522-
55471 ( 12.501%): export =====
523-
17823 ( 4.017%): part ==
524-
13229 ( 2.981%): part of with uri =
525-
4466 ( 1.006%): part of with library name =
526-
```
527-
528-
Given that, I propose that we make a **breaking change** and remove support for
529-
the long-deprecated library name syntax from `part of` directives. An unquoted
530-
series of identifiers after `part of` then gets unambiguously interpreted as
531-
this proposal's semantics. In other words, `part of foo.bar;` is part of the
532-
library at `package:foo/bar.dart`, not part of the library with name `foo.bar`.
533-
534-
Users affected by the breakage can and should update their `part of` directive
535-
to point to the URI of the library that the file is a part of, using either the
536-
quoted or unquoted syntax.
547+
This proposal makes a **breaking change** to disallow unquoted library names in
548+
`part of` directives.
537549

538550
### Language versioning
539551

540552
To avoid breaking existing `part of` directives, this change is language
541-
versioned. Only libraries whose language version is at or above the version that
542-
this proposal ships in can use this new unquoted syntax in `part of` or any
543-
other directive.
553+
versioned.
554+
555+
Only libraries whose language version is at or above the version that this
556+
proposal ships in can use this new unquoted syntax in `import` and `export`
557+
directives.
558+
559+
In language versions before the version this feature ships in, code may
560+
continue to use the old unquoted library name syntax in `part of` directives
561+
but users are encouraged to migrate away from that syntax.
544562

545563
## Tooling
546564

@@ -570,6 +588,10 @@ new unquoted style whenever an existing directive could use it.
570588

571589
## Changelog
572590

591+
### 0.5
592+
593+
- Require `part` and `part of` directives to use quoted paths (#4038).
594+
573595
### 0.4
574596

575597
- Allow reserved words and built-in identifiers as path components (#3984).

0 commit comments

Comments
 (0)