@@ -60,7 +60,7 @@ class FlowAnalysis<Statement, Expression, Variable, Type> {
60
60
final FunctionBodyAccess <Variable > functionBody;
61
61
62
62
/// The stack of states of variables that are not definitely assigned.
63
- final List <State <Variable , Type >> _stack = [];
63
+ final List <FlowModel <Variable , Type >> _stack = [];
64
64
65
65
/// The mapping from labeled [Statement] s to the index in the [_stack]
66
66
/// where the first related element is located. The number of elements
@@ -71,16 +71,16 @@ class FlowAnalysis<Statement, Expression, Variable, Type> {
71
71
/// List of all variables passed to [add] .
72
72
final List <Variable > _addedVariables = [];
73
73
74
- State <Variable , Type > _current;
74
+ FlowModel <Variable , Type > _current;
75
75
76
76
/// The last boolean condition, for [_conditionTrue] and [_conditionFalse] .
77
77
Expression _condition;
78
78
79
79
/// The state when [_condition] evaluates to `true` .
80
- State <Variable , Type > _conditionTrue;
80
+ FlowModel <Variable , Type > _conditionTrue;
81
81
82
82
/// The state when [_condition] evaluates to `false` .
83
- State <Variable , Type > _conditionFalse;
83
+ FlowModel <Variable , Type > _conditionFalse;
84
84
85
85
/// If assertions are enabled, keeps track of all variables that have been
86
86
/// passed into the API (other than through a call to [add] ). The [finish]
@@ -100,7 +100,7 @@ class FlowAnalysis<Statement, Expression, Variable, Type> {
100
100
TypeOperations <Variable , Type > typeOperations,
101
101
FunctionBodyAccess <Variable > functionBody,
102
102
) {
103
- var emptySet = State <Variable , Type >(false ).notAssigned;
103
+ var emptySet = FlowModel <Variable , Type >(false ).notAssigned;
104
104
return FlowAnalysis ._(
105
105
nodeOperations,
106
106
typeOperations,
@@ -115,7 +115,7 @@ class FlowAnalysis<Statement, Expression, Variable, Type> {
115
115
this .functionBody,
116
116
this ._emptySet,
117
117
) {
118
- _current = State <Variable , Type >(true );
118
+ _current = FlowModel <Variable , Type >(true );
119
119
}
120
120
121
121
/// Return `true` if the current state is reachable.
@@ -357,8 +357,8 @@ class FlowAnalysis<Statement, Expression, Variable, Type> {
357
357
}
358
358
359
359
void ifStatement_end (bool hasElse) {
360
- State <Variable , Type > afterThen;
361
- State <Variable , Type > afterElse;
360
+ FlowModel <Variable , Type > afterThen;
361
+ FlowModel <Variable , Type > afterElse;
362
362
if (hasElse) {
363
363
afterThen = _stack.removeLast ();
364
364
afterElse = _current;
@@ -604,9 +604,9 @@ class FlowAnalysis<Statement, Expression, Variable, Type> {
604
604
}
605
605
}
606
606
607
- State <Variable , Type > _join (
608
- State <Variable , Type > first, State <Variable , Type > second) =>
609
- State .join (typeOperations, first, second);
607
+ FlowModel <Variable , Type > _join (
608
+ FlowModel <Variable , Type > first, FlowModel <Variable , Type > second) =>
609
+ FlowModel .join (typeOperations, first, second);
610
610
611
611
/// If assertions are enabled, records that the given variable has been
612
612
/// referenced. The [finish] method will verify that all referenced variables
@@ -629,27 +629,14 @@ class FlowAnalysis<Statement, Expression, Variable, Type> {
629
629
}
630
630
}
631
631
632
- /// Accessor for function body information.
633
- abstract class FunctionBodyAccess <Variable > {
634
- bool isPotentiallyMutatedInClosure (Variable variable);
635
-
636
- bool isPotentiallyMutatedInScope (Variable variable);
637
- }
638
-
639
- /// Operations on nodes, abstracted from concrete node interfaces.
640
- abstract class NodeOperations <Expression > {
641
- /// If the [node] is a parenthesized expression, recursively unwrap it.
642
- Expression unwrapParenthesized (Expression node);
643
- }
644
-
645
- /// An instance of the [State] class represents the information gathered by flow
646
- /// analysis at a single point in the control flow of the function or method
647
- /// being analyzed.
632
+ /// An instance of the [FlowModel] class represents the information gathered by
633
+ /// flow analysis at a single point in the control flow of the function or
634
+ /// method being analyzed.
648
635
///
649
636
/// Instances of this class are immutable, so the methods below that "update"
650
637
/// the state actually leave `this` unchanged and return a new state object.
651
638
@visibleForTesting
652
- class State <Variable , Type > {
639
+ class FlowModel <Variable , Type > {
653
640
/// Indicates whether this point in the control flow is reachable.
654
641
final bool reachable;
655
642
@@ -675,14 +662,14 @@ class State<Variable, Type> {
675
662
/// Creates a state object with the given [reachable] status. All variables
676
663
/// are assumed to be unpromoted and already assigned, so joining another
677
664
/// state with this one will have no effect on it.
678
- State (bool reachable)
665
+ FlowModel (bool reachable)
679
666
: this ._(
680
667
reachable,
681
668
_VariableSet <Variable >._(const []),
682
669
const {},
683
670
);
684
671
685
- State ._(
672
+ FlowModel ._(
686
673
this .reachable,
687
674
this .notAssigned,
688
675
this .promoted,
@@ -691,14 +678,14 @@ class State<Variable, Type> {
691
678
/// Updates the state to track a newly declared local [variable] . The
692
679
/// optional [assigned] boolean indicates whether the variable is assigned at
693
680
/// the point of declaration.
694
- State <Variable , Type > add (Variable variable, {bool assigned: false }) {
681
+ FlowModel <Variable , Type > add (Variable variable, {bool assigned: false }) {
695
682
var newNotAssigned = assigned ? notAssigned : notAssigned.add (variable);
696
683
697
684
if (identical (newNotAssigned, notAssigned)) {
698
685
return this ;
699
686
}
700
687
701
- return State <Variable , Type >._(
688
+ return FlowModel <Variable , Type >._(
702
689
reachable,
703
690
newNotAssigned,
704
691
promoted,
@@ -710,7 +697,7 @@ class State<Variable, Type> {
710
697
///
711
698
/// TODO(paulberry): should this method mark the variable as definitely
712
699
/// assigned? Does it matter?
713
- State <Variable , Type > markNonNullable (
700
+ FlowModel <Variable , Type > markNonNullable (
714
701
TypeOperations <Variable , Type > typeOperations, Variable variable) {
715
702
var previousType = promoted[variable];
716
703
previousType ?? = typeOperations.variableType (variable);
@@ -719,7 +706,7 @@ class State<Variable, Type> {
719
706
if (! typeOperations.isSameType (type, previousType)) {
720
707
var newPromoted = < Variable , Type > {}..addAll (promoted);
721
708
newPromoted[variable] = type;
722
- return State <Variable , Type >._(
709
+ return FlowModel <Variable , Type >._(
723
710
reachable,
724
711
notAssigned,
725
712
newPromoted,
@@ -738,7 +725,7 @@ class State<Variable, Type> {
738
725
///
739
726
/// TODO(paulberry): if the type is non-nullable, should this method mark the
740
727
/// variable as definitely assigned? Does it matter?
741
- State <Variable , Type > promote (
728
+ FlowModel <Variable , Type > promote (
742
729
TypeOperations <Variable , Type > typeOperations,
743
730
Variable variable,
744
731
Type type,
@@ -750,7 +737,7 @@ class State<Variable, Type> {
750
737
! typeOperations.isSameType (type, previousType)) {
751
738
var newPromoted = < Variable , Type > {}..addAll (promoted);
752
739
newPromoted[variable] = type;
753
- return State <Variable , Type >._(
740
+ return FlowModel <Variable , Type >._(
754
741
reachable,
755
742
notAssigned,
756
743
newPromoted,
@@ -779,12 +766,12 @@ class State<Variable, Type> {
779
766
/// and only remove promotions if it can be shown that they aren't restored
780
767
/// later in the loop body. If we switch to a fixed point analysis, we should
781
768
/// be able to remove this method.
782
- State <Variable , Type > removePromotedAll (Set <Variable > variables) {
769
+ FlowModel <Variable , Type > removePromotedAll (Set <Variable > variables) {
783
770
var newPromoted = _removePromotedAll (promoted, variables);
784
771
785
772
if (identical (newPromoted, promoted)) return this ;
786
773
787
- return State <Variable , Type >._(
774
+ return FlowModel <Variable , Type >._(
788
775
reachable,
789
776
notAssigned,
790
777
newPromoted,
@@ -811,10 +798,10 @@ class State<Variable, Type> {
811
798
/// state from the `try` block). Variables that are assigned in the `finally`
812
799
/// block are considered "unsafe" because the assignment might have cancelled
813
800
/// the effect of any promotion that occurred inside the `try` block.
814
- State <Variable , Type > restrict (
801
+ FlowModel <Variable , Type > restrict (
815
802
TypeOperations <Variable , Type > typeOperations,
816
803
_VariableSet <Variable > emptySet,
817
- State <Variable , Type > other,
804
+ FlowModel <Variable , Type > other,
818
805
Set <Variable > unsafe,
819
806
) {
820
807
var newReachable = reachable && other.reachable;
@@ -883,10 +870,10 @@ class State<Variable, Type> {
883
870
884
871
/// Updates the state to indicate whether the control flow path is
885
872
/// [reachable] .
886
- State <Variable , Type > setReachable (bool reachable) {
873
+ FlowModel <Variable , Type > setReachable (bool reachable) {
887
874
if (this .reachable == reachable) return this ;
888
875
889
- return State <Variable , Type >._(
876
+ return FlowModel <Variable , Type >._(
890
877
reachable,
891
878
notAssigned,
892
879
promoted,
@@ -901,7 +888,7 @@ class State<Variable, Type> {
901
888
/// previous type promotion is removed.
902
889
///
903
890
/// TODO(paulberry): allow for writes that preserve type promotions.
904
- State <Variable , Type > write (TypeOperations <Variable , Type > typeOperations,
891
+ FlowModel <Variable , Type > write (TypeOperations <Variable , Type > typeOperations,
905
892
_VariableSet <Variable > emptySet, Variable variable) {
906
893
var newNotAssigned = typeOperations.isLocalVariable (variable)
907
894
? notAssigned.remove (emptySet, variable)
@@ -914,7 +901,7 @@ class State<Variable, Type> {
914
901
return this ;
915
902
}
916
903
917
- return State <Variable , Type >._(
904
+ return FlowModel <Variable , Type >._(
918
905
reachable,
919
906
newNotAssigned,
920
907
newPromoted,
@@ -971,10 +958,10 @@ class State<Variable, Type> {
971
958
/// are kept only if they are common to both input states; if a variable is
972
959
/// promoted to one type in one state and a subtype in the other state, the
973
960
/// less specific type promotion is kept.
974
- static State <Variable , Type > join <Variable , Type >(
961
+ static FlowModel <Variable , Type > join <Variable , Type >(
975
962
TypeOperations <Variable , Type > typeOperations,
976
- State <Variable , Type > first,
977
- State <Variable , Type > second,
963
+ FlowModel <Variable , Type > first,
964
+ FlowModel <Variable , Type > second,
978
965
) {
979
966
if (first == null ) return second;
980
967
if (second == null ) return first;
@@ -985,9 +972,9 @@ class State<Variable, Type> {
985
972
var newReachable = first.reachable || second.reachable;
986
973
var newNotAssigned = first.notAssigned.union (second.notAssigned);
987
974
var newPromoted =
988
- State .joinPromoted (typeOperations, first.promoted, second.promoted);
975
+ FlowModel .joinPromoted (typeOperations, first.promoted, second.promoted);
989
976
990
- return State ._identicalOrNew (
977
+ return FlowModel ._identicalOrNew (
991
978
first,
992
979
second,
993
980
newReachable,
@@ -1036,11 +1023,11 @@ class State<Variable, Type> {
1036
1023
return result;
1037
1024
}
1038
1025
1039
- /// Creates a new [State ] object, unless it is equivalent to either [first] or
1040
- /// [second] , in which case one of those objects is re-used.
1041
- static State <Variable , Type > _identicalOrNew <Variable , Type >(
1042
- State <Variable , Type > first,
1043
- State <Variable , Type > second,
1026
+ /// Creates a new [FlowModel ] object, unless it is equivalent to either
1027
+ /// [first] or [ second] , in which case one of those objects is re-used.
1028
+ static FlowModel <Variable , Type > _identicalOrNew <Variable , Type >(
1029
+ FlowModel <Variable , Type > first,
1030
+ FlowModel <Variable , Type > second,
1044
1031
bool newReachable,
1045
1032
_VariableSet <Variable > newNotAssigned,
1046
1033
Map <Variable , Type > newPromoted,
@@ -1056,7 +1043,7 @@ class State<Variable, Type> {
1056
1043
return second;
1057
1044
}
1058
1045
1059
- return State <Variable , Type >._(
1046
+ return FlowModel <Variable , Type >._(
1060
1047
newReachable,
1061
1048
newNotAssigned,
1062
1049
newPromoted,
@@ -1079,6 +1066,19 @@ class State<Variable, Type> {
1079
1066
}
1080
1067
}
1081
1068
1069
+ /// Accessor for function body information.
1070
+ abstract class FunctionBodyAccess <Variable > {
1071
+ bool isPotentiallyMutatedInClosure (Variable variable);
1072
+
1073
+ bool isPotentiallyMutatedInScope (Variable variable);
1074
+ }
1075
+
1076
+ /// Operations on nodes, abstracted from concrete node interfaces.
1077
+ abstract class NodeOperations <Expression > {
1078
+ /// If the [node] is a parenthesized expression, recursively unwrap it.
1079
+ Expression unwrapParenthesized (Expression node);
1080
+ }
1081
+
1082
1082
/// Operations on types, abstracted from concrete type interfaces.
1083
1083
abstract class TypeOperations <Variable , Type > {
1084
1084
/// Return `true` if the [variable] is a local variable, not a parameter.
0 commit comments