44
55import 'package:meta/meta.dart' ;
66
7- /// Set this boolean to `true` to permanently enable the feature of allowing
8- /// local boolean variables to influence promotion (see
9- /// https://github.com/dart-lang/language/issues/1274). While this boolean is
10- /// `false` , the feature remains experimental and can be activated via an
11- /// optional boolean parameter to the [FlowAnalysis] constructor.
12- ///
13- /// Changing this value to `true` will cause some dead code warnings to appear
14- /// for code that only exists to support the old behavior.
15- const bool allowLocalBooleanVarsToPromoteByDefault = true ;
16-
177/// [AssignedVariables] is a helper class capable of computing the set of
188/// variables that are potentially written to, and potentially captured by
199/// closures, at various locations inside the code being analyzed. This class
@@ -242,6 +232,11 @@ class AssignedVariables<Node extends Object, Variable extends Object> {
242232 '{${_info .keys .map ((k ) => '$k (${k .hashCode })' ).join (',' )}}' ));
243233 }
244234
235+ /// Indicates whether information is stored for the given [node] .
236+ bool _hasInfoForNode (Node node) {
237+ return _info[node] != null ;
238+ }
239+
245240 void _printOn (StringBuffer sb) {
246241 sb.write ('_info=$_info ,' );
247242 sb.write ('_stack=$_stack ,' );
@@ -402,10 +397,8 @@ class ExpressionInfo<Variable extends Object, Type extends Object> {
402397abstract class FlowAnalysis <Node extends Object , Statement extends Node ,
403398 Expression extends Object , Variable extends Object , Type extends Object > {
404399 factory FlowAnalysis (TypeOperations <Variable , Type > typeOperations,
405- AssignedVariables <Node , Variable > assignedVariables,
406- {bool allowLocalBooleanVarsToPromote = false }) {
407- return new _FlowAnalysisImpl (typeOperations, assignedVariables,
408- allowLocalBooleanVarsToPromote: allowLocalBooleanVarsToPromote);
400+ AssignedVariables <Node , Variable > assignedVariables) {
401+ return new _FlowAnalysisImpl (typeOperations, assignedVariables);
409402 }
410403
411404 factory FlowAnalysis .legacy (TypeOperations <Variable , Type > typeOperations,
@@ -935,6 +928,8 @@ abstract class FlowAnalysis<Node extends Object, Statement extends Node,
935928 /// promotion, to retrieve information about why [target] was not promoted.
936929 /// This call must be made right after visiting [target] .
937930 ///
931+ /// If [target] is `null` it is assumed to be an implicit reference to `this` .
932+ ///
938933 /// The returned value is a map whose keys are types that the user might have
939934 /// been expecting the target to be promoted to, and whose values are reasons
940935 /// why the corresponding promotion did not occur. The caller is expected to
@@ -943,7 +938,7 @@ abstract class FlowAnalysis<Node extends Object, Statement extends Node,
943938 /// occurs due to the target having a nullable type, the caller should report
944939 /// a non-promotion reason associated with non-promotion to a non-nullable
945940 /// type).
946- Map <Type , NonPromotionReason > whyNotPromoted (Expression target);
941+ Map <Type , NonPromotionReason > whyNotPromoted (Expression ? target);
947942
948943 /// Register write of the given [variable] in the current state.
949944 /// [writtenType] should be the type of the value that was written.
@@ -974,12 +969,10 @@ class FlowAnalysisDebug<Node extends Object, Statement extends Node,
974969 bool _exceptionOccurred = false ;
975970
976971 factory FlowAnalysisDebug (TypeOperations <Variable , Type > typeOperations,
977- AssignedVariables <Node , Variable > assignedVariables,
978- {bool allowLocalBooleanVarsToPromote = false }) {
972+ AssignedVariables <Node , Variable > assignedVariables) {
979973 print ('FlowAnalysisDebug()' );
980- return new FlowAnalysisDebug ._(new _FlowAnalysisImpl (
981- typeOperations, assignedVariables,
982- allowLocalBooleanVarsToPromote: allowLocalBooleanVarsToPromote));
974+ return new FlowAnalysisDebug ._(
975+ new _FlowAnalysisImpl (typeOperations, assignedVariables));
983976 }
984977
985978 factory FlowAnalysisDebug .legacy (
@@ -1460,7 +1453,7 @@ class FlowAnalysisDebug<Node extends Object, Statement extends Node,
14601453 }
14611454
14621455 @override
1463- Map <Type , NonPromotionReason > whyNotPromoted (Expression target) {
1456+ Map <Type , NonPromotionReason > whyNotPromoted (Expression ? target) {
14641457 return _wrap (
14651458 'whyNotPromoted($target )' , () => _wrapped.whyNotPromoted (target),
14661459 isQuery: true );
@@ -1879,79 +1872,6 @@ class FlowModel<Variable extends Object, Type extends Object> {
18791872 return _identicalOrNew (this , base , newReachable, newVariableInfo);
18801873 }
18811874
1882- /// Updates the state to reflect a control path that is known to have
1883- /// previously passed through some [other] state.
1884- ///
1885- /// Approximately, this method forms the union of the definite assignments and
1886- /// promotions in `this` state and the [other] state. More precisely:
1887- ///
1888- /// The control flow path is considered reachable if both this state and the
1889- /// other state are reachable. Variables are considered definitely assigned
1890- /// if they were definitely assigned in either this state or the other state.
1891- /// Variable type promotions are taken from this state, unless the promotion
1892- /// in the other state is more specific, and the variable is "safe". A
1893- /// variable is considered safe if there is no chance that it was assigned
1894- /// more recently than the "other" state.
1895- ///
1896- /// This is used after a `try/finally` statement to combine the promotions and
1897- /// definite assignments that occurred in the `try` and `finally` blocks
1898- /// (where `this` is the state from the `finally` block and `other` is the
1899- /// state from the `try` block). Variables that are assigned in the `finally`
1900- /// block are considered "unsafe" because the assignment might have cancelled
1901- /// the effect of any promotion that occurred inside the `try` block.
1902- FlowModel <Variable , Type > restrict (
1903- TypeOperations <Variable , Type > typeOperations,
1904- FlowModel <Variable , Type > other,
1905- Set <Variable > unsafe) {
1906- if (allowLocalBooleanVarsToPromoteByDefault) {
1907- // TODO(paulberry): when we hardcode
1908- // allowLocalBooleanVarsToPromoteByDefault to `true`, we should remove
1909- // this method entirely.
1910- throw new StateError ('This method should not be called anymore' );
1911- }
1912- Reachability newReachable =
1913- Reachability .restrict (reachable, other.reachable);
1914-
1915- Map <Variable ?, VariableModel <Variable , Type >> newVariableInfo =
1916- < Variable ? , VariableModel <Variable , Type >> {};
1917- bool variableInfoMatchesThis = true ;
1918- bool variableInfoMatchesOther = true ;
1919- for (MapEntry <Variable ?, VariableModel <Variable , Type >> entry
1920- in variableInfo.entries) {
1921- Variable ? variable = entry.key;
1922- VariableModel <Variable , Type > thisModel = entry.value;
1923- VariableModel <Variable , Type >? otherModel = other.variableInfo[variable];
1924- if (otherModel == null ) {
1925- variableInfoMatchesThis = false ;
1926- continue ;
1927- }
1928- VariableModel <Variable , Type > restricted = thisModel.restrict (
1929- typeOperations, otherModel, unsafe.contains (variable));
1930- newVariableInfo[variable] = restricted;
1931- if (! identical (restricted, thisModel)) variableInfoMatchesThis = false ;
1932- if (! identical (restricted, otherModel)) variableInfoMatchesOther = false ;
1933- }
1934- if (variableInfoMatchesOther) {
1935- for (Variable ? variable in other.variableInfo.keys) {
1936- if (! variableInfo.containsKey (variable)) {
1937- variableInfoMatchesOther = false ;
1938- break ;
1939- }
1940- }
1941- }
1942- assert (variableInfoMatchesThis ==
1943- _variableInfosEqual (newVariableInfo, variableInfo));
1944- assert (variableInfoMatchesOther ==
1945- _variableInfosEqual (newVariableInfo, other.variableInfo));
1946- if (variableInfoMatchesThis) {
1947- newVariableInfo = variableInfo;
1948- } else if (variableInfoMatchesOther) {
1949- newVariableInfo = other.variableInfo;
1950- }
1951-
1952- return _identicalOrNew (this , other, newReachable, newVariableInfo);
1953- }
1954-
19551875 /// Updates the state to indicate that the control flow path is unreachable.
19561876 FlowModel <Variable , Type > setUnreachable () {
19571877 if (! reachable.locallyReachable) return this ;
@@ -2797,59 +2717,6 @@ class VariableModel<Variable extends Object, Type extends Object> {
27972717 ssaNode: writeCaptured ? null : new SsaNode <Variable , Type >(null ));
27982718 }
27992719
2800- /// Returns an updated model reflect a control path that is known to have
2801- /// previously passed through some [other] state. See [FlowModel.restrict]
2802- /// for details.
2803- VariableModel <Variable , Type > restrict (
2804- TypeOperations <Variable , Type > typeOperations,
2805- VariableModel <Variable , Type > otherModel,
2806- bool unsafe) {
2807- if (allowLocalBooleanVarsToPromoteByDefault) {
2808- // TODO(paulberry): when we hardcode
2809- // allowLocalBooleanVarsToPromoteByDefault to `true`, we should remove
2810- // this method entirely.
2811- throw new StateError ('This method should not be called anymore' );
2812- }
2813- List <Type >? thisPromotedTypes = promotedTypes;
2814- List <Type >? otherPromotedTypes = otherModel.promotedTypes;
2815- bool newAssigned = assigned || otherModel.assigned;
2816- // The variable can only be unassigned in this state if it was also
2817- // unassigned in the other state or if the other state didn't complete
2818- // normally. For the latter case the resulting state is unreachable but to
2819- // avoid creating a variable model that is both assigned and unassigned we
2820- // take the intersection below.
2821- //
2822- // This situation can occur in try-finally like:
2823- //
2824- // method() {
2825- // var local;
2826- // try {
2827- // local = 0;
2828- // return; // assigned
2829- // } finally {
2830- // local; // unassigned
2831- // }
2832- // local; // unreachable state
2833- // }
2834- //
2835- bool newUnassigned = unassigned && otherModel.unassigned;
2836- bool newWriteCaptured = writeCaptured || otherModel.writeCaptured;
2837- List <Type >? newPromotedTypes;
2838- if (newWriteCaptured) {
2839- // Write-captured variables can't be promoted
2840- newPromotedTypes = null ;
2841- } else if (unsafe) {
2842- // There was an assignment to the variable in the "this" path, so none of
2843- // the promotions from the "other" path can be used.
2844- newPromotedTypes = thisPromotedTypes;
2845- } else {
2846- newPromotedTypes = rebasePromotedTypes (
2847- typeOperations, thisPromotedTypes, otherPromotedTypes);
2848- }
2849- return _identicalOrNew (this , otherModel, newPromotedTypes, tested,
2850- newAssigned, newUnassigned, newWriteCaptured ? null : ssaNode);
2851- }
2852-
28532720 /// Updates `this` with a new set of properties.
28542721 VariableModel <Variable , Type > setProperties (
28552722 Map <String , VariableModel <Variable , Type >> newProperties) =>
@@ -3524,18 +3391,7 @@ class _FlowAnalysisImpl<Node extends Object, Statement extends Node,
35243391
35253392 final AssignedVariables <Node , Variable > _assignedVariables;
35263393
3527- /// Set this boolean to `true` to temporarily enable the feature of allowing
3528- /// local boolean variables to influence promotion, for this flow analysis
3529- /// session (see https://github.com/dart-lang/language/issues/1274). Once the
3530- /// top level const [allowLocalBooleanVarsToPromoteByDefault] is changed to
3531- /// `true` , this field will always be `true` , so it can be safely removed.
3532- final bool allowLocalBooleanVarsToPromote;
3533-
3534- _FlowAnalysisImpl (this .typeOperations, this ._assignedVariables,
3535- {bool allowLocalBooleanVarsToPromote = false })
3536- : allowLocalBooleanVarsToPromote =
3537- allowLocalBooleanVarsToPromoteByDefault ||
3538- allowLocalBooleanVarsToPromote;
3394+ _FlowAnalysisImpl (this .typeOperations, this ._assignedVariables);
35393395
35403396 @override
35413397 bool get isReachable => _current.reachable.overallReachable;
@@ -4186,17 +4042,13 @@ class _FlowAnalysisImpl<Node extends Object, Statement extends Node,
41864042
41874043 @override
41884044 void tryFinallyStatement_end (Node finallyBlock) {
4189- AssignedVariablesNodeInfo <Variable > info =
4190- _assignedVariables._getInfoForNode (finallyBlock);
4045+ // We used to need info for `finally` blocks but we don't anymore.
4046+ assert (! _assignedVariables._hasInfoForNode (finallyBlock),
4047+ 'No assigned variables info should have been stored for $finallyBlock ' );
41914048 _TryFinallyContext <Variable , Type > context =
41924049 _stack.removeLast () as _TryFinallyContext <Variable , Type >;
4193- if (allowLocalBooleanVarsToPromote) {
4194- _current = context._afterBodyAndCatches
4195- .attachFinally (typeOperations, context._beforeFinally, _current);
4196- } else {
4197- _current = _current.restrict (
4198- typeOperations, context._afterBodyAndCatches, info._written);
4199- }
4050+ _current = context._afterBodyAndCatches
4051+ .attachFinally (typeOperations, context._beforeFinally, _current);
42004052 }
42014053
42024054 @override
@@ -4218,13 +4070,11 @@ class _FlowAnalysisImpl<Node extends Object, Statement extends Node,
42184070 _storeExpressionReference (expression, variableReference);
42194071 VariableModel <Variable , Type > variableModel =
42204072 variableReference.getInfo (_current.variableInfo);
4221- if (allowLocalBooleanVarsToPromote) {
4222- ExpressionInfo <Variable , Type >? expressionInfo = variableModel
4223- .ssaNode? .expressionInfo
4224- ? .rebaseForward (typeOperations, _current);
4225- if (expressionInfo != null ) {
4226- _storeExpressionInfo (expression, expressionInfo);
4227- }
4073+ ExpressionInfo <Variable , Type >? expressionInfo = variableModel
4074+ .ssaNode? .expressionInfo
4075+ ? .rebaseForward (typeOperations, _current);
4076+ if (expressionInfo != null ) {
4077+ _storeExpressionInfo (expression, expressionInfo);
42284078 }
42294079 return variableModel.promotedTypes? .last;
42304080 }
@@ -4257,13 +4107,16 @@ class _FlowAnalysisImpl<Node extends Object, Statement extends Node,
42574107 }
42584108
42594109 @override
4260- Map <Type , NonPromotionReason > whyNotPromoted (Expression target) {
4261- if (identical (target, _expressionWithReference)) {
4262- Reference <Variable , Type >? reference = _expressionReference;
4263- if (reference != null ) {
4264- return reference.getNonPromotionReasons (
4265- _current.variableInfo, typeOperations);
4266- }
4110+ Map <Type , NonPromotionReason > whyNotPromoted (Expression ? target) {
4111+ Reference <Variable , Type >? reference;
4112+ if (target == null ) {
4113+ reference = new _ThisReference <Variable , Type >();
4114+ } else if (identical (target, _expressionWithReference)) {
4115+ reference = _expressionReference;
4116+ }
4117+ if (reference != null ) {
4118+ return reference.getNonPromotionReasons (
4119+ _current.variableInfo, typeOperations);
42674120 }
42684121 return {};
42694122 }
@@ -4850,7 +4703,7 @@ class _LegacyTypePromotion<Node extends Object, Statement extends Node,
48504703 void whileStatement_end () {}
48514704
48524705 @override
4853- Map <Type , NonPromotionReason > whyNotPromoted (Expression target) {
4706+ Map <Type , NonPromotionReason > whyNotPromoted (Expression ? target) {
48544707 return {};
48554708 }
48564709
0 commit comments