@@ -701,12 +701,31 @@ abstract class NodeOperations<Expression> {
701
701
Expression unwrapParenthesized (Expression node);
702
702
}
703
703
704
+ /// An instance of the [State] class represents the information gathered by flow
705
+ /// analysis at a single point in the control flow of the function or method
706
+ /// being analyzed.
707
+ ///
708
+ /// Instances of this class are immuatable, so the methods below that "update"
709
+ /// the state actually leave `this` unchanged and return a new state object.
704
710
@visibleForTesting
705
711
class State <Variable , Type > {
712
+ /// Indicates whether this point in the control flow is reachable.
706
713
final bool reachable;
714
+
715
+ /// The set of variables that are not yet definitely assigned at this point in
716
+ /// the control flow.
707
717
final _VariableSet <Variable > notAssigned;
718
+
719
+ /// For each variable whose type is promoted at this point in the control
720
+ /// flow, the promoted type. Variables whose type is not promoted are not
721
+ /// present in the map. Variables that have gone out of scope are not
722
+ /// guaranteed to be present in the map even if they were promoted at the time
723
+ /// they went out of scope.
708
724
final Map <Variable , Type > promoted;
709
725
726
+ /// Creates a state object with the given [reachable] status. All variables
727
+ /// are assumed to be unpromoted and already assigned, so joining another
728
+ /// state with this one will have no effect on it.
710
729
State (bool reachable)
711
730
: this ._(
712
731
reachable,
@@ -720,7 +739,9 @@ class State<Variable, Type> {
720
739
this .promoted,
721
740
);
722
741
723
- /// Add a new [variable] to track definite assignment.
742
+ /// Updates the state to track a newly declared local [variable] . The
743
+ /// optional [assigned] boolean indicates whether the variable is assigned at
744
+ /// the point of declaration.
724
745
State <Variable , Type > add (Variable variable, {bool assigned: false }) {
725
746
var newNotAssigned = assigned ? notAssigned : notAssigned.add (variable);
726
747
@@ -735,6 +756,7 @@ class State<Variable, Type> {
735
756
);
736
757
}
737
758
759
+ /// Updates the state to indicate that the control flow path is unreachable.
738
760
State <Variable , Type > exit () {
739
761
return State <Variable , Type >._(
740
762
false ,
@@ -743,6 +765,11 @@ class State<Variable, Type> {
743
765
);
744
766
}
745
767
768
+ /// Updates the state to indicate that the given [variable] has been
769
+ /// determined to contain a non-null value.
770
+ ///
771
+ /// TODO(paulberry): should this method mark the variable as definitely
772
+ /// assigned? Does it matter?
746
773
State <Variable , Type > markNonNullable (
747
774
TypeOperations <Variable , Type > typeOperations, Variable variable) {
748
775
var previousType = promoted[variable];
@@ -762,6 +789,14 @@ class State<Variable, Type> {
762
789
return this ;
763
790
}
764
791
792
+ /// Updates the state to indicate that the given [variable] has been
793
+ /// determined to satisfy the given [type] .
794
+ ///
795
+ /// Note that the state is only changed if [type] is a subtype of the
796
+ /// variable's previous (possibly promoted) type.
797
+ ///
798
+ /// TODO(paulberry): if the type is non-nullable, should this method mark the
799
+ /// variable as definitely assigned? Does it matter?
765
800
State <Variable , Type > promote (
766
801
TypeOperations <Variable , Type > typeOperations,
767
802
Variable variable,
@@ -784,6 +819,8 @@ class State<Variable, Type> {
784
819
return this ;
785
820
}
786
821
822
+ /// Updates the state to indicate that the given [variables] are no longer
823
+ /// promoted; they are presumed to have their declared types.
787
824
State <Variable , Type > removePromotedAll (Set <Variable > variables) {
788
825
var newPromoted = _removePromotedAll (promoted, variables);
789
826
@@ -796,6 +833,16 @@ class State<Variable, Type> {
796
833
);
797
834
}
798
835
836
+ /// Updates the state to reflect a control path that is known to have
837
+ /// previously passed through some [other] state.
838
+ ///
839
+ /// The control flow path is considered reachable if both this state and the
840
+ /// other state are reachable. Variables are considered definitely assigned
841
+ /// if they were definitely assigned in either this state or the other state.
842
+ /// Variable type promotions are taken from this state, unless the promotion
843
+ /// in the other state is more specific, and the variable is "safe". A
844
+ /// variable is considered safe if there is no chance that it was assigned
845
+ /// more recently than the "other" state.
799
846
State <Variable , Type > restrict (
800
847
TypeOperations <Variable , Type > typeOperations,
801
848
_VariableSet <Variable > emptySet,
@@ -866,6 +913,8 @@ class State<Variable, Type> {
866
913
);
867
914
}
868
915
916
+ /// Updates the state to indicate whether the control flow path is
917
+ /// [reachable] .
869
918
State <Variable , Type > setReachable (bool reachable) {
870
919
if (this .reachable == reachable) return this ;
871
920
@@ -879,6 +928,11 @@ class State<Variable, Type> {
879
928
@override
880
929
String toString () => '($reachable , $notAssigned , $promoted )' ;
881
930
931
+ /// Updates the state to indicate that an assignment was made to the given
932
+ /// [variable] . The variable is marked as definitely assigned, and any
933
+ /// previous type promotion is removed.
934
+ ///
935
+ /// TODO(paulberry): allow for writes that preserve type promotions.
882
936
State <Variable , Type > write (TypeOperations <Variable , Type > typeOperations,
883
937
_VariableSet <Variable > emptySet, Variable variable) {
884
938
var newNotAssigned = typeOperations.isLocalVariable (variable)
@@ -899,6 +953,8 @@ class State<Variable, Type> {
899
953
);
900
954
}
901
955
956
+ /// Removes a [variable] from a "promoted" [map] , treating the map as
957
+ /// immutable.
902
958
Map <Variable , Type > _removePromoted (
903
959
Map <Variable , Type > map, Variable variable) {
904
960
if (map.isEmpty) return const {};
@@ -914,6 +970,8 @@ class State<Variable, Type> {
914
970
return result;
915
971
}
916
972
973
+ /// Removes a set of [variable] s from a "promoted" [map] , treating the map as
974
+ /// immutable.
917
975
Map <Variable , Type > _removePromotedAll (
918
976
Map <Variable , Type > map,
919
977
Set <Variable > variables,
@@ -936,6 +994,8 @@ class State<Variable, Type> {
936
994
return result;
937
995
}
938
996
997
+ /// Creates a new [State] object, unless it is equivalent to either [first] or
998
+ /// [second] , in which case one of those objects is re-used.
939
999
static State <Variable , Type > _identicalOrNew <Variable , Type >(
940
1000
State <Variable , Type > first,
941
1001
State <Variable , Type > second,
@@ -961,6 +1021,7 @@ class State<Variable, Type> {
961
1021
);
962
1022
}
963
1023
1024
+ /// Determines whether the given "promoted" maps are equivalent.
964
1025
static bool _promotionsEqual <Variable , Type >(
965
1026
TypeOperations <Variable , Type > typeOperations,
966
1027
Map <Variable , Type > p1,
0 commit comments