@@ -193,13 +193,6 @@ The following functions associate flow models to nodes:
193
193
- ` false(E) ` , where ` E ` is an expression, represents the * flow model* just after
194
194
execution of ` E ` , assuming that ` E ` completes normally and evaluates to ` false ` .
195
195
196
- - ` null(E) ` , where ` E ` is an expression, represents the * flow model* just after
197
- execution of ` E ` , assuming that ` E ` completes normally and evaluates to ` null ` .
198
-
199
- - ` notNull(E) ` , where ` E ` is an expression, represents the * flow model* just
200
- after execution of ` E ` , assuming that ` E ` completes normally and does not
201
- evaluate to ` null ` .
202
-
203
196
- ` break(S) ` , where ` S ` is a ` do ` , ` for ` , ` switch ` , or ` while ` statement,
204
197
represents the join of the flow models reaching each ` break ` statement
205
198
targetting ` S ` .
@@ -225,8 +218,8 @@ The following functions associate flow models to nodes:
225
218
expression in the recurrent part of ` S ` , where the "recurrent" part of ` s ` is
226
219
defined as in ` assignedIn ` , above.
227
220
228
- Note that ` true ` , ` false ` , ` null ` , and ` notNull ` are defined for all expressions
229
- regardless of their static types.
221
+ Note that ` true ` and ` false ` are defined for all expressions regardless of their
222
+ static types.
230
223
231
224
We also make use of the following auxiliary functions:
232
225
@@ -429,14 +422,25 @@ Definitions:
429
422
` demoted ` is ` Q::previous `
430
423
- otherwise ` demoted ` is ` previous `
431
424
425
+ - ` stripParens(E1) ` , where ` E1 ` is an expression, is the result of stripping
426
+ outer parentheses from the expression ` E1 ` . It is defined to be the
427
+ expression ` E3 ` , where:
428
+ - If ` E1 ` is a parenthesized expression of the form ` (E2) ` , then ` E3 ` =
429
+ ` stripParens(E2) ` .
430
+ - Otherwise, ` E3 ` = ` E1 ` .
431
+
432
+ - ` equivalentToNull(T) ` , where ` T ` is a type, indicates whether ` T ` is
433
+ equivalent to the ` Null ` type. It is defined to be true if ` T <: Null ` and
434
+ ` Null <: T ` ; otherwise false.
435
+
432
436
- ` promote(E, T, M) ` where ` E ` is an expression, ` T ` is a type which it may be
433
- promoted to, and ` M1 = FlowModel(r, VI)` is the flow model in which to
434
- promote, is defined to be ` M3 ` , where:
435
- - If ` E ` is not a promotion target, then ` M3 ` = ` M1 `
436
- - If ` E ` is a promotion target ` x ` , then
437
+ promoted to, and ` M = FlowModel(r, VI)` is the flow model in which to promote,
438
+ is defined to be ` M3 ` , where:
439
+ - If ` stripParens(E) ` is not a promotion target, then ` M3 ` = ` M `
440
+ - If ` stripParens(E) ` is a promotion target ` x ` , then
437
441
- Let `VM = VariableModel(declared, promoted, tested, assigned, unassigned,
438
442
captured)` be the variable model for ` x` in ` VI`
439
- - If ` x ` is not promotable via type test to ` T ` given ` VM ` , then ` M3 ` = ` M1 `
443
+ - If ` x ` is not promotable via type test to ` T ` given ` VM ` , then ` M3 ` = ` M `
440
444
- Else
441
445
- Let ` S ` be the current type of ` x ` in ` VM `
442
446
- If ` T <: S ` then let ` T1 ` = ` T `
@@ -482,43 +486,24 @@ constructor, or field declaration to be analyzed.
482
486
### Expressions
483
487
484
488
Analysis of an expression ` N ` assumes that ` before(N) ` has been computed, and
485
- uses it to derive ` after(N) ` , ` null(N) ` , ` notNull(N) ` , ` true(N) ` , and
486
- ` false(N) ` .
487
-
488
- If ` N ` is an expression, and the following rules specify the values to be
489
- assigned to ` true(N) ` and ` false(N) ` , but do not specify values for ` null(N) ` ,
490
- ` notNull(N) ` , or ` after(N) ` , then they are by default assigned as follows:
491
- - ` null(N) = unreachable(after(N)) ` .
492
- - ` notNull(N) = join(true(N), false(N)) ` .
493
- - ` after(N) = notNull(N) ` .
489
+ uses it to derive ` after(N) ` , ` true(N) ` , and ` false(N) ` .
494
490
495
491
If ` N ` is an expression, and the following rules specify the values to be
496
- assigned to ` null(N) ` and ` notNull(N) ` , but do not specify values for ` true(N) ` ,
497
- ` false(N) ` , or ` after(N) ` , then they are by default assigned as follows:
498
- - ` true(N) = notNull(N) ` .
499
- - ` false(N) = notNull(N) ` .
500
- - ` after(N) = join(null(N), notNull(N)) ` .
492
+ assigned to ` true(N) ` and ` false(N) ` , but do not specify the value for
493
+ ` after(N) ` , then it is by default assigned as follows:
494
+ - ` after(N) = join(true(N), false(N)) ` .
501
495
502
496
If ` N ` is an expression, and the following rules specify the value to be
503
- assigned to ` after(N) ` , but do not specify values for ` true(N) ` , ` false(N) ` ,
504
- ` null(N) ` , or ` notNull(N) ` , then they are all assigned the same value as
505
- ` after(N) ` .
497
+ assigned to ` after(N) ` , but do not specify values for ` true(N) ` and ` false(N) ` ,
498
+ then they are all assigned the same value as ` after(N) ` .
506
499
507
500
508
501
- ** Variable or getter** : If ` N ` is an expression of the form ` x `
509
502
where the type of ` x ` is ` T ` then:
510
503
- If ` T <: Never ` then:
511
- - Let ` null(N) = unreachable(before(N)) ` .
512
- - Let ` notNull(N) = unreachable(before(N)) ` .
513
- - Otherwise if ` T <: Null ` then:
514
- - Let ` null(N) = before(N) ` .
515
- - Let ` notNull(N) = unreachable(before(N)) ` .
516
- - Otherwise if ` T ` is non-nullable then:
517
- - Let ` null(N) = unreachable(before(N)) ` .
518
- - Let ` notNull(N) = before(N) ` .
504
+ - Let ` after(N) = unreachable(before(N)) ` .
519
505
- Otherwise:
520
- - Let ` null(N) = promote(x, Null, before(N)) `
521
- - Let ` notNull(N) = promoteToNonNull(x, before(N)) `
506
+ - Let ` after(N) = before(N) ` .
522
507
523
508
- ** True literal** : If ` N ` is the literal ` true ` , then:
524
509
- Let ` true(N) = before(N) ` .
@@ -528,13 +513,10 @@ assigned to `after(N)`, but do not specify values for `true(N)`, `false(N)`,
528
513
- Let ` true(N) = unreachable(before(N)) ` .
529
514
- Let ` false(N) = before(N) ` .
530
515
531
- - ** null literal** : If ` N ` is the literal ` null ` , then:
532
- - Let ` null(N) = before(N) ` .
533
- - Let ` notNull(N) = unreachable(before(N)) ` .
516
+ - TODO(paulberry): list, map, and set literals.
534
517
535
518
- ** other literal** : If ` N ` is some other literal than the above, then:
536
- - Let ` null(N) = unreachable(before(N)) ` .
537
- - Let ` notNull(N) = before(N) ` .
519
+ - Let ` after(N) = before(N) ` .
538
520
539
521
- ** throw** : If ` N ` is a throw expression of the form ` throw E1 ` , then:
540
522
- Let ` before(E1) = before(N) ` .
@@ -546,21 +528,35 @@ assigned to `after(N)`, but do not specify values for `true(N)`, `false(N)`,
546
528
- Let ` after(N) = assign(x, E1, after(E1)) ` .
547
529
- Let ` true(N) = assign(x, E1, true(E1)) ` .
548
530
- Let ` false(N) = assign(x, E1, false(E1)) ` .
549
- - Let ` null(N) = assign(x, E1, null(E1)) ` .
550
- - Let ` notNull(N) = assign(x, E1, notNull(E1)) ` .
551
-
552
- TODO(leafp): Per
553
- discussion
554
- [ here] ( https://github.com/dart-lang/language/pull/763/files#r364003138 ) , this is
555
- wrong. This needs reconsideration.
556
- - ** operator==** If ` N ` is an expression of the form ` E1 == E2 ` then:
557
- - Let ` before(E1) = before(N) `
558
- - Let ` before(E2) = after(E1) `
559
- - Let `true(N) = join(join(null(E1), null(E2)),
560
- join(notNull(E1), notNull(E2)))`
561
- - Let `false(N) = join(join(null(E1), notNull(E2)),
562
- join(notNull(E1), null(E2)),
563
- join(notNull(E1), notNull(E2)))`
531
+
532
+ - ** operator==** If ` N ` is an expression of the form ` E1 == E2 ` , where the
533
+ static type of ` E1 ` is ` T1 ` and the static type of ` E2 ` is ` T2 ` , then:
534
+ - Let ` before(E1) = before(N) ` .
535
+ - Let ` before(E2) = after(E1) ` .
536
+ - If ` equivalentToNull(T1) ` and ` equivalentToNull(T2) ` , then:
537
+ - Let ` true(N) = after(E2) ` .
538
+ - Let ` false(N) = unreachable(after(E2)) ` .
539
+ - Otherwise, if ` equivalentToNull(T1) ` and ` T2 ` is non-nullable, or
540
+ ` equivalentToNull(T2) ` and ` T1 ` is non-nullable, then:
541
+ - Let ` true(N) = unreachable(after(E2)) ` .
542
+ - Let ` false(N) = after(E2) ` .
543
+ - Otherwise, if ` stripParens(E1) ` is a ` null ` literal, then:
544
+ - Let ` true(N) = after(E2) ` .
545
+ - Let ` false(N) = promoteToNonNull(E2, after(E2)) ` .
546
+ - Otherwise, if ` stripParens(E2) ` is a ` null ` literal, then:
547
+ - Let ` true(N) = after(E1) ` .
548
+ - Let ` false(N) = promoteToNonNull(E1, after(E2)) ` .
549
+ - Otherwise:
550
+ - Let ` after(N) = after(E2) ` .
551
+
552
+ Note that it is tempting to generalize the two ` null ` literal cases to apply
553
+ to any expression whose type is ` Null ` , but this would be unsound in cases
554
+ where ` E2 ` assigns to ` x ` . (Consider, for example, `(int? x) => x == (x =
555
+ null) ? true : x.isEven` , which tries to call ` null.isEven` in the event of a
556
+ non-null input).
557
+
558
+ - ** operator!=** If ` N ` is an expression of the form ` E1 != E2 ` , it is treated
559
+ as equivalent to the expression ` !(E1 == E2) ` .
564
560
565
561
- ** instance check** If ` N ` is an expression of the form ` E1 is S ` where the
566
562
static type of ` E1 ` is ` T ` then:
@@ -582,11 +578,18 @@ wrong. This needs reconsideration.
582
578
583
579
TODO: This isn't really right, ` E1 ` isn't really an expression here.
584
580
585
- - ** Non local-variable conditional assignment** : If ` N ` is an expression of the form
586
- ` E1 ??= E2 ` where ` E1 ` is not a local variable, then:
587
- - Let ` before(E1) = before(N) `
588
- - Let ` before(E2) = split(null(E1)) ` .
589
- - Let ` after(N) = merge(after(E2), split(notNull(E1))) `
581
+ - ** Conditional assignment to a non local-variable** : If ` N ` is an expression of
582
+ the form ` E1 ??= E2 ` where ` E1 ` is not a local variable, and the type of ` E1 `
583
+ is ` T1 ` , then:
584
+ - Let ` before(E1) = before(N) ` .
585
+ - If ` T1 ` is strictly non-nullable, then:
586
+ - Let ` before(E2) = unreachable(after(E1)) ` .
587
+ - Let ` after(N) = after(E1) ` .
588
+ - Otherwise:
589
+ - Let ` before(E2) = split(after(E1)) ` .
590
+ - Let ` after(N) = merge(after(E2), split(after(E1))) ` .
591
+
592
+ TODO(paulberry): this doesn't seem to match what's currently implemented.
590
593
591
594
- ** Conditional expression** : If ` N ` is a conditional expression of the form `E1
592
595
? E2 : E3`, then:
@@ -596,14 +599,18 @@ TODO: This isn't really right, `E1` isn't really an expression here.
596
599
- Let ` after(N) = merge(after(E2), after(E3)) ` .
597
600
- Let ` true(N) = merge(true(E2), true(E3)) ` .
598
601
- Let ` false(N) = merge(false(E2), false(E3)) ` .
599
- - Let ` null(N) = merge(null(E2), null(E3)) ` .
600
- - Let ` notNull(N) = merge(notNull(E2), notNull(E3)) ` .
601
602
602
- - ** If-null** : If ` N ` is an if-null expression of the form ` E1 ?? E2 ` , then:
603
+ - ** If-null** : If ` N ` is an if-null expression of the form ` E1 ?? E2 ` , where the
604
+ type of ` E1 ` is ` T1 ` , then:
603
605
- Let ` before(E1) = before(N) ` .
604
- - Let ` before(E2) = split(null(E1)) ` .
605
- - Let ` null(N) = unsplit(null(E2)) ` .
606
- - Let ` notNull(N) = merge(split(notNull(E1)), notNull(E2)) ` .
606
+ - If ` T1 ` is strictly non-nullable, then:
607
+ - Let ` before(E2) = unreachable(after(E1)) ` .
608
+ - Let ` after(N) = after(E1) ` .
609
+ - Otherwise:
610
+ - Let ` before(E2) = split(after(E1)) ` .
611
+ - Let ` after(N) = merge(after(E2), split(after(E1))) ` .
612
+
613
+ TODO(paulberry): this doesn't seem to match what's currently implemented.
607
614
608
615
- ** Shortcut and** : If ` N ` is a shortcut "and" expression of the form ` E1 && E2 ` ,
609
616
then:
@@ -623,27 +630,23 @@ TODO: This isn't really right, `E1` isn't really an expression here.
623
630
` ?? ` are handled as calls to the appropriate ` operator ` method.
624
631
625
632
- ** Null check operator** : If ` N ` is an expression of the form ` E! ` , then:
626
- - Let ` before(E) = before(N) `
627
- - Let ` null(N) = unreachable(null(E)) `
628
- - Let ` nonNull(N) = nonNull(E) `
633
+ - Let ` before(E) = before(N) ` .
634
+ - Let ` after(E) = promoteToNonNull(E, after(E)) ` .
629
635
630
636
- ** Method invocation** : If ` N ` is an expression of the form ` E1.m1(E2) ` , then:
631
637
- Let ` before(E1) = before(N) `
632
- - Let ` before(E2) = after(E2 ) `
638
+ - Let ` before(E2) = after(E1 ) `
633
639
- Let ` T ` be the static return type of the invocation
634
640
- If ` T <: Never ` then:
635
- - Let ` null(N) = unreachable(before(N)) ` .
636
- - Let ` notNull(N) = unreachable(before(N)) ` .
637
- - Otherwise if ` T <: Null ` then:
638
- - Let ` null(N) = before(N) ` .
639
- - Let ` notNull(N) = unreachable(before(N)) ` .
640
- - Otherwise if ` T ` is non-nullable then:
641
- - Let ` null(N) = before(N) ` .
642
- - Let ` notNull(N) = unreachable(before(N)) ` .
641
+ - Let ` after(N) = unreachable(after(E2)) ` .
642
+ - Otherwise, if ` m1 ` is a method declared on ` Object ` (e.g. ` toString ` ), then:
643
+ - Let ` after(N) = after(E2) ` .
643
644
- Otherwise:
644
- - Let ` null(N) = promote(x, Null, before(N)) `
645
- - Let ` notNull(N) = promoteToNonNull(x, before(N)) `
645
+ - Let ` after(N) = promoteToNonNull(E1, after(E2)) `
646
646
647
+ TODO(paulberry): is the ` promoteToNonNull ` part of method invocations
648
+ implemented?
649
+ TODO(paulberry): handle ` E1.m1(E2, E3, ...) ` .
647
650
648
651
TODO: Add missing expressions, handle cascades and left-hand sides accurately
649
652
0 commit comments