Skip to content

Commit 352c2ca

Browse files
committed
[records] Disambiguate metadata annotation arguments and record types.
Fix #2469.
1 parent d3b469b commit 352c2ca

File tree

1 file changed

+79
-1
lines changed

1 file changed

+79
-1
lines changed

accepted/future-releases/records/records-feature-specification.md

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Author: Bob Nystrom
44

55
Status: Accepted
66

7-
Version 1.12 (see [CHANGELOG](#CHANGELOG) at end)
7+
Version 1.13 (see [CHANGELOG](#CHANGELOG) at end)
88

99
## Motivation
1010

@@ -257,6 +257,80 @@ avoid this ambiguity ([#2469][]).**
257257

258258
[#2469]: https://github.com/dart-lang/language/issues/2469
259259

260+
### Ambiguity with metadata annotations
261+
262+
A metadata annotation may or may not have an argument list following it. A
263+
variable declaration may omit a preceding type annotation. Likewise, a function
264+
declaration may omit a preceding return type. This combination of syntax where
265+
an optional trailing element is followed by syntax with an optional preceding
266+
element can lead to ambiguity. In particular:
267+
268+
```dart
269+
@metadata (a, b) function() {}
270+
```
271+
272+
This could be a metadata annotation `@metadata(a, b)` associated with a function
273+
declaration with no return type. Or it could be a metadata annotation
274+
`@metadata` associated with a function whose return type is the record type `(a,
275+
b)`.
276+
277+
In practice, idiomatically written code is clear thanks to whitespace:
278+
279+
```dart
280+
@metadata(a, b) function() {}
281+
282+
@metadata (a, b) function() {}
283+
```
284+
285+
The former applies `(a, b)` to the metadata annotation and the latter is a
286+
return type. We disambiguate in the same way, by making whitespace after a
287+
metadata annotation name significant. Change the grammar to:
288+
289+
```
290+
metadatum ::= identifier // Existing rule.
291+
| qualifiedName // Existing rule.
292+
| constructorDesignation ~WHITESPACE arguments // Changed.
293+
```
294+
295+
The `~WHITESPACE` lexical rule matches when there are no whitespace characters
296+
(according to the existing `WHITESPACE` lexical rule) between the
297+
`constructorDesignation` and `arguments`. Comments do not count as whitespace,
298+
nor do whitespace characters in comments. The newline at the end of a line
299+
comment *does* count as whitespace.
300+
301+
```dart
302+
// These are argument lists to the annotation:
303+
@metadata(x,) a;
304+
@metadata/* a comment */(x,) a;
305+
@metadata/* a
306+
multi
307+
line
308+
comment */(x,) a;
309+
310+
// These are record variable types:
311+
@metadata (x,) a;
312+
313+
@metadata
314+
(x,) a;
315+
316+
@metadata // Comment.
317+
(x,) a;
318+
319+
@metadata/* Comment with newline after. */
320+
(x,) a;
321+
```
322+
323+
Note that the no whitespace rule is applied unconditionally, even when the
324+
metadata annotation appears in a context where no ambiguity with record types
325+
is possible.
326+
327+
**Breaking change:** Existing metadata annotations with whitespace before their
328+
argument lists will no longer parse correctly. In a corpus of 18,672,247 lines
329+
of code containing 409,825 metadata annotations, 46,245 had argument lists and
330+
none of those had whitespace before the argument list. Note that this analysis
331+
only captures code that has been committed. Code being written may be less well
332+
formatted, but we expect problems from this to be rare.
333+
260334
## Static semantics
261335

262336
We define **shape** to mean the number of positional fields (the record's
@@ -587,6 +661,10 @@ covariant in their field types.
587661

588662
## CHANGELOG
589663

664+
### 1.13
665+
666+
- Disambiguate record types following metadata annotations (#2469).
667+
590668
### 1.12
591669

592670
- Include record types in `typeNotVoid`. This allows them to appear in `is` and

0 commit comments

Comments
 (0)