Skip to content

Commit 8aa7930

Browse files
committed
[patterns] Refine records proposal around record type syntax.
- Make the grammar closer to function type parameter lists. - Don't allow record types in inheritance clauses, but do allow them as the return type of function types. - Remove ambiguous shorthand syntax for named-field only records. - Clarify that there is no record type literal syntax. Fix #2302. Fix #2304.
1 parent 8715e74 commit 8aa7930

File tree

1 file changed

+65
-34
lines changed

1 file changed

+65
-34
lines changed

working/0546-patterns/records-feature-specification.md

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

55
Status: In progress
66

7-
Version 1.4 (see [CHANGELOG](#CHANGELOG) at end)
7+
Version 1.5 (see [CHANGELOG](#CHANGELOG) at end)
88

99
## Motivation
1010

@@ -121,26 +121,61 @@ compile-time error if a record has any of:
121121

122122
### Record type annotations
123123

124-
In the type system, each record has a corresponding record type. The grammar for
125-
record type annotations is:
124+
In the type system, each record has a corresponding record type. A record type
125+
looks similar to a function type's parameter list. The type is surrounded by
126+
parentheses and may contain comma-separated positional fields:
126127

128+
```dart
129+
(int, String name, bool) triple;
130+
```
131+
132+
Each field is a type annotation and an optional name which isn't meaningful but
133+
is useful for documentation purposes.
134+
135+
Named fields go inside a brace-delimited section of type and name pairs:
136+
137+
```dart
138+
({int n, String s}) pair;
139+
```
140+
141+
A record type may have both positional and named fields:
142+
143+
```dart
144+
(bool, num, {int n, String s}) quad;
127145
```
128-
// Existing rule:
129-
typeNotVoidNotFunction ::= recordType
130-
| // Existing typeNotVoidNotFunction productions...
131146

132-
recordType ::= '(' recordTypeFields ','? ')'
133-
| '(' ( recordTypeFields ',' )?
134-
recordTypeNamedFields ')'
135-
| recordTypeNamedFields
147+
The grammar is:
148+
149+
```
150+
// Existing rules:
151+
type ::= functionType '?'? // Existing production.
152+
| recordType // New production.
153+
| typeNotFunction // Existing production.
136154
137-
recordTypeFields ::= type ( ',' type )*
155+
typeNotFunction ::= 'void' // Existing production.
156+
| recordType // New production.
157+
| typeNotVoidNotFunction // Existing production.
158+
159+
// New rules:
160+
recordType ::= '(' recordTypeFields ',' recordTypeNamedFields ')'
161+
| '(' recordTypeFields ','? ')'
162+
| '(' recordTypeNamedFields ')'
163+
164+
recordTypeFields ::= recordTypeField ( ',' recordTypeField )*
165+
recordTypeField ::= metadata type identifier?
138166
139167
recordTypeNamedFields ::= '{' recordTypeNamedField
140168
( ',' recordTypeNamedField )* ','? '}'
141169
recordTypeNamedField ::= type identifier
170+
recordTypeNamedField ::= metadata typedIdentifier
142171
```
143172

173+
*The grammar is exactly the same as `parameterTypeList` in function types but
174+
without `()`, `required`, and optional positional parameters since those don't
175+
apply to record types. A record type can't appear in an `extends`, `implements`,
176+
`with`, or mixin `on` clause, which is enforced by being a production in `type`
177+
and not `typeNotVoid`.*
178+
144179
It is a compile-time error if a record type has any of:
145180

146181
* The same field name more than once.
@@ -154,34 +189,17 @@ It is a compile-time error if a record type has any of:
154189

155190
* A field name that starts with an underscore.
156191

157-
The syntax is similar to a function type's parameter list. You have zero or more
158-
positional fields where each field is a type annotation:
192+
### No record type literals
159193

160-
```dart
161-
(int, String, bool) triple;
162-
```
163-
164-
Then a brace-delimited section for named fields. Each named field is a type and
165-
name pair:
194+
There is no record type literal syntax that can be used as an expression, since
195+
it would be ambiguous with other existing syntax:
166196

167197
```dart
168-
({int n, String s}) pair;
198+
var t = (int, String);
169199
```
170200

171-
A record type can have both positional and named fields:
172-
173-
```dart
174-
(bool, num, {int n, String s}) quad;
175-
```
176-
177-
If there are only named fields, you are allowed to omit the surrounding
178-
parentheses:
179-
180-
```dart
181-
{int n, String s} pair;
182-
```
183-
184-
Like record expressions, a record type must have at least one field.
201+
This is a record expression containing two type literals, `int` and `String`,
202+
not a type literal for a record type.
185203

186204
## Static semantics
187205

@@ -360,6 +378,19 @@ covariant in their field types.
360378

361379
## CHANGELOG
362380

381+
### 1.5
382+
383+
- Make the grammar for record types closer to function type parameter lists.
384+
Allow metadata before fields and optional names for positional fields.
385+
386+
- Weave `recordType` into the grammar better. Don't allow it in inheritance
387+
clauses, but do allow it as the return type of function types.
388+
389+
- Remove shorthand syntax that elides parentheses when there are no positional
390+
fields since that's ambiguous inside a function type (#2302).
391+
392+
- Clarify that there is no record type literal syntax (#2304).
393+
363394
### 1.4
364395

365396
- Remove the reflective static members on `Record`. Like other reflective

0 commit comments

Comments
 (0)