@@ -4,7 +4,7 @@ Author: Bob Nystrom
4
4
5
5
Status: In-progress
6
6
7
- Version 0.1
7
+ Version 0.2 (see [ CHANGELOG ] ( #CHANGELOG ) at end)
8
8
9
9
Experiment flag: null-aware-elements
10
10
@@ -301,21 +301,25 @@ More formally, here is the proposal:
301
301
302
302
## Syntax
303
303
304
- We redefine two rules in the grammar, ` expressionElement ` and ` mapElement ` in
305
- terms of a new ` nullAwareExpression ` rule:
304
+ We add two new rules in the grammar and add two new clauses to ` element ` :
306
305
307
306
```
308
- expressionElement ::= nullAwareExpression
307
+ element ::=
308
+ | nullAwareExpressionElement
309
+ | nullAwareMapElement
310
+ | // Existing productions...
309
311
310
- mapElement ::= nullAwareExpression ':' nullAwareExpression
312
+ nullAwareExpressionElement ::= '?' expression
311
313
312
- nullAwareExpression ::= '?'? expression
314
+ nullAwareMapElement ::=
315
+ | '?' expression ':' '?'? expression // Null-aware key or both.
316
+ | expression ':' '?' expression // Null-aware value.
313
317
```
314
318
315
- * Note that the inner production of ` nullAwareExpression ` is ` expression ` and not
319
+ * Note that the productions after ` ? ` in these new rules are ` expression ` and not
316
320
` element ` . As with spread elements, null-aware elements can't nest and contain
317
- other elements. These immediately exit the element grammar and bottom out in an
318
- expression. There's no ` ????foo ` or `?if (c) nullableThing else
321
+ other elements. These new elements immediately exit the element grammar and
322
+ bottom out in an expression. There's no ` ????foo ` or `?if (c) nullableThing else
319
323
otherNullableThing`.*
320
324
321
325
* The ` ? ` character is already overloaded in Dart for nullable types, conditional
@@ -328,12 +332,43 @@ ambiguous.*
328
332
329
333
## Static semantics
330
334
331
- Here and below, we use "null-aware ` expressionElement ` " to mean an
332
- ` expressionElement ` beginning with ` ? ` . A "null-aware ` mapElement ` is a
333
- ` mapElement ` whose key and/or value parts begin with ` ? ` . A "key null-aware
334
- ` mapElement ` is a ` mapElement ` that begins with ` ? ` * (and whose value part may
335
- or may not be null-aware)* . A "value null-aware ` mapElement ` is a ` mapElement `
336
- with a ` ? ` after the ` : ` * (and whose key part may or may not be null-aware)* .
335
+ Here and below, we say a ` nullAwareMapElement ` "has a null-aware key" if the
336
+ ` nullAwareMapElement ` begins with ` ? ` and "has a null-aware value" if there is a
337
+ ` ? ` after the ` : ` .
338
+
339
+ ### Leaf elements
340
+
341
+ The existing specification uses * leaf elements* as part of disambiguating map
342
+ and set literals. We extend the rules by saying the leaf elements of ` element `
343
+ are:
344
+
345
+ * Else, if element is an ` nullAwareExpressionElement ` or ` nullAwareMapEntry ` ,
346
+ then the * leaf element* is ` element ` itself.
347
+
348
+ * In other words, just like their non-null-aware forms, null-aware expressions
349
+ and map entries are leaf elements.*
350
+
351
+ When disambiguating map and set literals, we replace the existing "If * leaf
352
+ elements* is not empty" step with:
353
+
354
+ 1 . Else, if * leaf elements* is not empty, then:
355
+
356
+ * If * leaf elements* has at least one ` expressionElement ` or
357
+ ` nullAwareExpressionElement ` and no ` mapEntry ` or ` nullAwareMapEntry `
358
+ elements, then * e* is a set literal with unknown static type. The static
359
+ type will be filled in by type inference, defined below.
360
+
361
+ * If * leaf elements* has at least one ` mapEntry ` or ` nullAwareMapEntry `
362
+ and no ` expressionElement ` or ` nullAwareExpressionElement ` elements,
363
+ then * e* is a map literal with unknown static type. The static type will
364
+ be filled in by type inference, defined below.
365
+
366
+ * If leaf elements has at least one ` mapEntry ` or ` nullAwareMapEntry ` and
367
+ at least one ` expressionElement ` or ` nullAwareExpressionElement ` , report
368
+ a compile-time error.
369
+
370
+ * In other words, for map/set disambiguation, null-aware elements behave exactly
371
+ like their non-null-aware siblings.*
337
372
338
373
### Type inference
339
374
@@ -346,15 +381,13 @@ flow in and out of the element.
346
381
When type inference is flowing through a brace-delimited collection literal, it
347
382
is applied to each element. The [ existing type inference behavior] [ type
348
383
inference] is mostly unchanged by this proposal. We add two new clauses to
349
- handle null-aware elements. * The existing clauses for ` expressionElement ` and
350
- ` mapElement ` are interpreted to only apply to * non* -null-aware elements.* The
351
- new clauses are:
384
+ handle null-aware elements:
352
385
353
386
[ type inference ] : https://github.com/dart-lang/language/blob/main/accepted/2.3/unified-collections/feature-specification.md#type-inference
354
387
355
388
To infer the type of ` element ` in context ` P ` :
356
389
357
- * If ` element ` is a null-aware ` expressionElement ` with expression ` e1 ` :
390
+ * If ` element ` is a ` nullAwareExpressionElement ` with expression ` e1 ` :
358
391
359
392
* If ` P ` is ` _ ` (the unknown context):
360
393
@@ -370,32 +403,32 @@ To infer the type of `element` in context `P`:
370
403
* The inferred set element type is ** NonNull** (` U ` ). * The value added to
371
404
the set will never be ` null ` .*
372
405
373
- * If ` element ` is a null-aware ` mapElement ` with entry ` ek: ev ` :
406
+ * If ` element ` is a ` nullAwareMapElement ` with entry ` ek: ev ` :
374
407
375
408
* If ` P ` is ` _ ` then the inferred key and value types of ` element ` are:
376
409
377
410
* Let ` Uk ` be the inferred type of ` ek ` in context ` _ ` .
378
411
379
- * If ` element ` is a key null-aware element then the inferred key
380
- element type is ** NonNull** (` Uk ` ). * The entry added to the map will
381
- never have a ` null ` key.*
412
+ * If ` element ` has a null-aware key then the inferred key element type
413
+ is ** NonNull** (` Uk ` ). * The entry added to the map will never have a
414
+ ` null ` key.*
382
415
383
416
* Else the inferred key element type is ` Uk ` . * The whole element is
384
417
null-aware, but the key part is not, so it is inferred as normal.*
385
418
386
419
* Let ` Uv ` be the inferred type of ` ev ` in context ` _ ` .
387
420
388
- * If ` element ` is a value null-aware element then the inferred value
389
- element type is ** NonNull** (` Uv ` ). * The entry added to the map will
390
- never have a ` null ` value.*
421
+ * If ` element ` has a null-aware value then the inferred value element
422
+ type is ** NonNull** (` Uv ` ). * The entry added to the map will never
423
+ have a ` null ` value.*
391
424
392
425
* Else the inferred value element type is ` Uv ` . * The whole element is
393
426
null-aware, but the value part is not, so it is inferred as normal.*
394
427
395
428
* If ` P ` is ` Map<Pk, Pv> ` then the inferred key and value types of
396
429
` element ` are:
397
430
398
- * If ` element ` is a key null-aware element then:
431
+ * If ` element ` has a null-aware key then:
399
432
400
433
* Let ` Uk ` be the inferred type of ` ek ` in context ` Pk? ` . * The key
401
434
expression has a nullable context type because it may safely
@@ -409,7 +442,7 @@ To infer the type of `element` in context `P`:
409
442
context ` Pk ` . * The whole element is null-aware, but the key part is
410
443
not, so it is inferred as normal.*
411
444
412
- * If ` element ` is a value null-aware element then:
445
+ * If ` element ` has a null-aware value then:
413
446
414
447
* Let ` Uv ` be the inferred type of ` ev ` in context ` Pv? ` . * The
415
448
value expression has a nullable context type because it may
@@ -435,7 +468,7 @@ Likewise, with list literals, we add a clause to handle a null-aware expression.
435
468
436
469
To infer the type of ` element ` in context ` P ` :
437
470
438
- * If ` element ` is null-aware ` expressionElement ` with expression ` e1 ` :
471
+ * If ` element ` is a ` nullAwareExpressionElement ` with expression ` e1 ` :
439
472
440
473
* If ` P ` is ` _ ` :
441
474
@@ -453,7 +486,7 @@ To infer the type of `element` in context `P`:
453
486
454
487
### Constants
455
488
456
- A null-aware ` expressionElement ` or ` mapElement ` is constant if its inner
489
+ A ` nullAwareExpressionElement ` or ` nullAwareMapElement ` is constant if its inner
457
490
expression or map entry is constant.
458
491
459
492
## Runtime semantics
@@ -466,24 +499,24 @@ add two new cases to that procedure:
466
499
467
500
[ unified-dynamic-element ] : https://github.com/dart-lang/language/blob/main/accepted/2.3/unified-collections/feature-specification.md#to-evaluate-a-collection-element
468
501
469
- * If ` element ` is a null-aware ` expressionElement ` with expression ` e ` :
502
+ * If ` element ` is a ` nullAwareExpressionElement ` with expression ` e ` :
470
503
471
504
* Evaluate ` e ` to ` v ` .
472
505
473
506
* If ` v ` is not ` null ` then append it to * result* . * Else the ` null ` is
474
507
discarded.*
475
508
476
- * Else, if ` element ` is a null-aware ` mapElement ` with entry ` k: v ` :
509
+ * Else, if ` element ` is a ` nullAwareMapElement ` with entry ` k: v ` :
477
510
478
511
* Evaluate ` k ` to a value ` kv ` .
479
512
480
- * If ` element ` is a key null-aware element and ` kv ` is ` null ` , then stop.
481
- Else continue...
513
+ * If ` element ` has a null-aware key and ` kv ` is ` null ` , then stop. Else
514
+ continue...
482
515
483
516
* Evaluate ` v ` to a value ` vv ` .
484
517
485
- * If ` element ` is a value null-aware element and ` vv ` is ` null ` , then
486
- stop. Else continue...
518
+ * If ` element ` has a null-aware value and ` vv ` is ` null ` , then stop. Else
519
+ continue...
487
520
488
521
* Append an entry ` kv: vv ` to * result* .
489
522
@@ -539,3 +572,16 @@ use instead:
539
572
If any of these patterns can be reliably detected through static analysis, then
540
573
quick fixes could be added to automatically convert these to use null-aware
541
574
elements instead.
575
+
576
+ ## Changelog
577
+
578
+ ### 0.2
579
+
580
+ - Use separate grammar rules for null-aware elements instead of allowing
581
+ optional ` ? ` inside ` expressionElement ` and ` mapEntryElement ` . This only
582
+ affects the wording of the specification but not the behavior of the
583
+ feature.
584
+
585
+ ### 0.1
586
+
587
+ - Initial draft.
0 commit comments