@@ -400,44 +400,6 @@ class FlowAnalysis<Statement, Expression, Variable, Type> {
400
400
}
401
401
}
402
402
403
- @visibleForTesting
404
- Map <Variable , Type > joinPromoted (
405
- Map <Variable , Type > first,
406
- Map <Variable , Type > second,
407
- ) {
408
- if (identical (first, second)) return first;
409
- if (first.isEmpty || second.isEmpty) return const {};
410
-
411
- var result = < Variable , Type > {};
412
- var alwaysFirst = true ;
413
- var alwaysSecond = true ;
414
- for (var variable in first.keys) {
415
- var firstType = first[variable];
416
- var secondType = second[variable];
417
- if (secondType != null ) {
418
- if (identical (firstType, secondType)) {
419
- result[variable] = firstType;
420
- } else if (typeOperations.isSubtypeOf (firstType, secondType)) {
421
- result[variable] = secondType;
422
- alwaysFirst = false ;
423
- } else if (typeOperations.isSubtypeOf (secondType, firstType)) {
424
- result[variable] = firstType;
425
- alwaysSecond = false ;
426
- } else {
427
- alwaysFirst = false ;
428
- alwaysSecond = false ;
429
- }
430
- } else {
431
- alwaysFirst = false ;
432
- }
433
- }
434
-
435
- if (alwaysFirst) return first;
436
- if (alwaysSecond && result.length == second.length) return second;
437
- if (result.isEmpty) return const {};
438
- return result;
439
- }
440
-
441
403
void logicalAnd_end (Expression andExpression, Expression rightOperand) {
442
404
_conditionalEnd (rightOperand);
443
405
// Tail of the stack: falseLeft, trueLeft, falseRight, trueRight
@@ -643,27 +605,8 @@ class FlowAnalysis<Statement, Expression, Variable, Type> {
643
605
}
644
606
645
607
State <Variable , Type > _join (
646
- State <Variable , Type > first,
647
- State <Variable , Type > second,
648
- ) {
649
- if (first == null ) return second;
650
- if (second == null ) return first;
651
-
652
- if (first.reachable && ! second.reachable) return first;
653
- if (! first.reachable && second.reachable) return second;
654
-
655
- var newReachable = first.reachable || second.reachable;
656
- var newNotAssigned = first.notAssigned.union (second.notAssigned);
657
- var newPromoted = joinPromoted (first.promoted, second.promoted);
658
-
659
- return State ._identicalOrNew (
660
- first,
661
- second,
662
- newReachable,
663
- newNotAssigned,
664
- newPromoted,
665
- );
666
- }
608
+ State <Variable , Type > first, State <Variable , Type > second) =>
609
+ State .join (typeOperations, first, second);
667
610
668
611
/// If assertions are enabled, records that the given variable has been
669
612
/// referenced. The [finish] method will verify that all referenced variables
@@ -1019,6 +962,80 @@ class State<Variable, Type> {
1019
962
return result;
1020
963
}
1021
964
965
+ /// Forms a new state to reflect a control flow path that might have come from
966
+ /// either `this` or the [other] state.
967
+ ///
968
+ /// The control flow path is considered reachable if either of the input
969
+ /// states is reachable. Variables are considered definitely assigned if they
970
+ /// were definitely assigned in both of the input states. Variable promotions
971
+ /// are kept only if they are common to both input states; if a variable is
972
+ /// promoted to one type in one state and a subtype in the other state, the
973
+ /// less specific type promotion is kept.
974
+ static State <Variable , Type > join <Variable , Type >(
975
+ TypeOperations <Variable , Type > typeOperations,
976
+ State <Variable , Type > first,
977
+ State <Variable , Type > second,
978
+ ) {
979
+ if (first == null ) return second;
980
+ if (second == null ) return first;
981
+
982
+ if (first.reachable && ! second.reachable) return first;
983
+ if (! first.reachable && second.reachable) return second;
984
+
985
+ var newReachable = first.reachable || second.reachable;
986
+ var newNotAssigned = first.notAssigned.union (second.notAssigned);
987
+ var newPromoted =
988
+ State .joinPromoted (typeOperations, first.promoted, second.promoted);
989
+
990
+ return State ._identicalOrNew (
991
+ first,
992
+ second,
993
+ newReachable,
994
+ newNotAssigned,
995
+ newPromoted,
996
+ );
997
+ }
998
+
999
+ /// Joins two "promoted" maps. See [join] for details.
1000
+ @visibleForTesting
1001
+ static Map <Variable , Type > joinPromoted <Variable , Type >(
1002
+ TypeOperations <Variable , Type > typeOperations,
1003
+ Map <Variable , Type > first,
1004
+ Map <Variable , Type > second,
1005
+ ) {
1006
+ if (identical (first, second)) return first;
1007
+ if (first.isEmpty || second.isEmpty) return const {};
1008
+
1009
+ var result = < Variable , Type > {};
1010
+ var alwaysFirst = true ;
1011
+ var alwaysSecond = true ;
1012
+ for (var variable in first.keys) {
1013
+ var firstType = first[variable];
1014
+ var secondType = second[variable];
1015
+ if (secondType != null ) {
1016
+ if (identical (firstType, secondType)) {
1017
+ result[variable] = firstType;
1018
+ } else if (typeOperations.isSubtypeOf (firstType, secondType)) {
1019
+ result[variable] = secondType;
1020
+ alwaysFirst = false ;
1021
+ } else if (typeOperations.isSubtypeOf (secondType, firstType)) {
1022
+ result[variable] = firstType;
1023
+ alwaysSecond = false ;
1024
+ } else {
1025
+ alwaysFirst = false ;
1026
+ alwaysSecond = false ;
1027
+ }
1028
+ } else {
1029
+ alwaysFirst = false ;
1030
+ }
1031
+ }
1032
+
1033
+ if (alwaysFirst) return first;
1034
+ if (alwaysSecond && result.length == second.length) return second;
1035
+ if (result.isEmpty) return const {};
1036
+ return result;
1037
+ }
1038
+
1022
1039
/// Creates a new [State] object, unless it is equivalent to either [first] or
1023
1040
/// [second] , in which case one of those objects is re-used.
1024
1041
static State <Variable , Type > _identicalOrNew <Variable , Type >(
0 commit comments