Skip to content

Commit a7ee05f

Browse files
stereotype441commit-bot@chromium.org
authored andcommitted
Reland "Flow analysis: Track expression variables separately from promotion info."
This is a reland of fd2a6c6 Original change's description: > Flow analysis: Track expression variables separately from promotion info. > > Previously, we used a single class hierarchy, ExpressionInfo, to store > all the information that flow analysis needs to know about a variable, > including: > > 1. What is known about the program state if the expression evaluates > to true/false > > 2. Whether the expression is a `null` literal > > 3. Whether the expression is a reference to a variable. > > However, in order to address > dart-lang/language#1274 (Infer > non-nullability from local boolean variables), we'll need #3 to be > tracked orthogonally from #1, so that when a local boolean is referred > to later, we can track information of type #1 and #3 simultaneously. > > However, it makes sense to keep #1 and #2 in the same data structure, > because future work is planned to represent them in a more uniform > way, as part of addressing > dart-lang/language#1224 (Using `if (foo?.bar > == somethingNotNull)` should promote `foo`). > > Change-Id: I432f6e2e80543bb1d565b49403180c520eef66a5 > Bug: dart-lang/language#1274 > Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/175008 > Reviewed-by: Johnni Winther <[email protected]> > Commit-Queue: Paul Berry <[email protected]> Bug: dart-lang/language#1274 Change-Id: I002adbde782887def50dc80ab6673411b321c341 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/175362 Reviewed-by: Konstantin Shcheglov <[email protected]> Reviewed-by: Johnni Winther <[email protected]> Commit-Queue: Paul Berry <[email protected]>
1 parent c603984 commit a7ee05f

File tree

1 file changed

+67
-59
lines changed

1 file changed

+67
-59
lines changed

pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart

Lines changed: 67 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -2566,8 +2566,12 @@ class _EqualityOpContext<Variable, Type> extends _BranchContext {
25662566
/// The type of the expression on the LHS of `==` or `!=`.
25672567
final Type _leftOperandType;
25682568

2569-
_EqualityOpContext(
2570-
ExpressionInfo<Variable, Type> conditionInfo, this._leftOperandType)
2569+
/// If the LHS of `==` or `!=` is a variable reference, the variable.
2570+
/// Otherwise `null`.
2571+
final Variable _leftOperandVariable;
2572+
2573+
_EqualityOpContext(ExpressionInfo<Variable, Type> conditionInfo,
2574+
this._leftOperandType, this._leftOperandVariable)
25712575
: super(conditionInfo);
25722576

25732577
@override
@@ -2602,6 +2606,14 @@ class _FlowAnalysisImpl<Node, Statement extends Node, Expression, Variable,
26022606
/// corresponding to it. Otherwise `null`.
26032607
ExpressionInfo<Variable, Type> _expressionInfo;
26042608

2609+
/// The most recently visited expression which was a variable reference, or
2610+
/// `null` if no expression has been visited that was a variable reference.
2611+
Expression _expressionWithVariable;
2612+
2613+
/// If [_expressionVariable] is not `null`, the variable corresponding to it.
2614+
/// Otherwise `null`.
2615+
Variable _expressionVariable;
2616+
26052617
int _functionNestingLevel = 0;
26062618

26072619
final AssignedVariables<Node, Variable> _assignedVariables;
@@ -2615,14 +2627,8 @@ class _FlowAnalysisImpl<Node, Statement extends Node, Expression, Variable,
26152627

26162628
@override
26172629
void asExpression_end(Expression subExpression, Type type) {
2618-
ExpressionInfo<Variable, Type> subExpressionInfo =
2619-
_getExpressionInfo(subExpression);
2620-
Variable variable;
2621-
if (subExpressionInfo is _VariableReadInfo<Variable, Type>) {
2622-
variable = subExpressionInfo._variable;
2623-
} else {
2624-
return;
2625-
}
2630+
Variable variable = _getExpressionVariable(subExpression);
2631+
if (variable == null) return;
26262632
_current = _current.tryPromoteForTypeCast(typeOperations, variable, type);
26272633
}
26282634

@@ -2730,8 +2736,10 @@ class _FlowAnalysisImpl<Node, Statement extends Node, Expression, Variable,
27302736
_EqualityOpContext<Variable, Type> context =
27312737
_stack.removeLast() as _EqualityOpContext<Variable, Type>;
27322738
ExpressionInfo<Variable, Type> lhsInfo = context._conditionInfo;
2739+
Variable lhsVariable = context._leftOperandVariable;
27332740
Type leftOperandType = context._leftOperandType;
27342741
ExpressionInfo<Variable, Type> rhsInfo = _getExpressionInfo(rightOperand);
2742+
Variable rhsVariable = _getExpressionVariable(rightOperand);
27352743
TypeClassification leftOperandTypeClassification =
27362744
typeOperations.classifyType(leftOperandType);
27372745
TypeClassification rightOperandTypeClassification =
@@ -2749,18 +2757,16 @@ class _FlowAnalysisImpl<Node, Statement extends Node, Expression, Variable,
27492757
// but weak mode it might produce an "equal" result. We don't want flow
27502758
// analysis behavior to depend on mode, so we conservatively assume that
27512759
// either result is possible.
2752-
} else if (lhsInfo is _NullInfo<Variable, Type> &&
2753-
rhsInfo is _VariableReadInfo<Variable, Type>) {
2760+
} else if (lhsInfo is _NullInfo<Variable, Type> && rhsVariable != null) {
27542761
assert(
27552762
leftOperandTypeClassification == TypeClassification.nullOrEquivalent);
27562763
ExpressionInfo<Variable, Type> equalityInfo =
2757-
_current.tryMarkNonNullable(typeOperations, rhsInfo._variable);
2764+
_current.tryMarkNonNullable(typeOperations, rhsVariable);
27582765
_storeExpressionInfo(wholeExpression,
27592766
notEqual ? equalityInfo : ExpressionInfo.invert(equalityInfo));
2760-
} else if (rhsInfo is _NullInfo<Variable, Type> &&
2761-
lhsInfo is _VariableReadInfo<Variable, Type>) {
2767+
} else if (rhsInfo is _NullInfo<Variable, Type> && lhsVariable != null) {
27622768
ExpressionInfo<Variable, Type> equalityInfo =
2763-
_current.tryMarkNonNullable(typeOperations, lhsInfo._variable);
2769+
_current.tryMarkNonNullable(typeOperations, lhsVariable);
27642770
_storeExpressionInfo(wholeExpression,
27652771
notEqual ? equalityInfo : ExpressionInfo.invert(equalityInfo));
27662772
}
@@ -2769,7 +2775,9 @@ class _FlowAnalysisImpl<Node, Statement extends Node, Expression, Variable,
27692775
@override
27702776
void equalityOp_rightBegin(Expression leftOperand, Type leftOperandType) {
27712777
_stack.add(new _EqualityOpContext<Variable, Type>(
2772-
_getExpressionInfo(leftOperand), leftOperandType));
2778+
_getExpressionInfo(leftOperand),
2779+
leftOperandType,
2780+
_getExpressionVariable(leftOperand)));
27732781
}
27742782

27752783
@override
@@ -2844,6 +2852,9 @@ class _FlowAnalysisImpl<Node, Statement extends Node, Expression, Variable,
28442852
if (identical(_expressionWithInfo, oldExpression)) {
28452853
_expressionWithInfo = newExpression;
28462854
}
2855+
if (identical(_expressionWithVariable, oldExpression)) {
2856+
_expressionWithVariable = newExpression;
2857+
}
28472858
}
28482859

28492860
@override
@@ -2901,12 +2912,12 @@ class _FlowAnalysisImpl<Node, Statement extends Node, Expression, Variable,
29012912
@override
29022913
void ifNullExpression_rightBegin(
29032914
Expression leftHandSide, Type leftHandSideType) {
2904-
ExpressionInfo<Variable, Type> lhsInfo = _getExpressionInfo(leftHandSide);
2915+
Variable lhsVariable = _getExpressionVariable(leftHandSide);
29052916
FlowModel<Variable, Type> promoted;
29062917
_current = _current.split();
2907-
if (lhsInfo is _VariableReadInfo<Variable, Type>) {
2918+
if (lhsVariable != null) {
29082919
ExpressionInfo<Variable, Type> promotionInfo =
2909-
_current.tryMarkNonNullable(typeOperations, lhsInfo._variable);
2920+
_current.tryMarkNonNullable(typeOperations, lhsVariable);
29102921
_current = promotionInfo.ifFalse;
29112922
promoted = promotionInfo.ifTrue;
29122923
} else {
@@ -2959,12 +2970,10 @@ class _FlowAnalysisImpl<Node, Statement extends Node, Expression, Variable,
29592970
@override
29602971
void isExpression_end(Expression isExpression, Expression subExpression,
29612972
bool isNot, Type type) {
2962-
ExpressionInfo<Variable, Type> subExpressionInfo =
2963-
_getExpressionInfo(subExpression);
2964-
if (subExpressionInfo is _VariableReadInfo<Variable, Type>) {
2965-
ExpressionInfo<Variable, Type> expressionInfo =
2966-
_current.tryPromoteForTypeCheck(
2967-
typeOperations, subExpressionInfo._variable, type);
2973+
Variable subExpressionVariable = _getExpressionVariable(subExpression);
2974+
if (subExpressionVariable != null) {
2975+
ExpressionInfo<Variable, Type> expressionInfo = _current
2976+
.tryPromoteForTypeCheck(typeOperations, subExpressionVariable, type);
29682977
_storeExpressionInfo(isExpression,
29692978
isNot ? ExpressionInfo.invert(expressionInfo) : expressionInfo);
29702979
}
@@ -3054,11 +3063,10 @@ class _FlowAnalysisImpl<Node, Statement extends Node, Expression, Variable,
30543063

30553064
@override
30563065
void nonNullAssert_end(Expression operand) {
3057-
ExpressionInfo<Variable, Type> operandInfo = _getExpressionInfo(operand);
3058-
if (operandInfo is _VariableReadInfo<Variable, Type>) {
3059-
_current = _current
3060-
.tryMarkNonNullable(typeOperations, operandInfo._variable)
3061-
.ifTrue;
3066+
Variable operandVariable = _getExpressionVariable(operand);
3067+
if (operandVariable != null) {
3068+
_current =
3069+
_current.tryMarkNonNullable(typeOperations, operandVariable).ifTrue;
30623070
}
30633071
}
30643072

@@ -3075,11 +3083,10 @@ class _FlowAnalysisImpl<Node, Statement extends Node, Expression, Variable,
30753083
_current = _current.split();
30763084
_stack.add(new _NullAwareAccessContext<Variable, Type>(_current));
30773085
if (target != null) {
3078-
ExpressionInfo<Variable, Type> targetInfo = _getExpressionInfo(target);
3079-
if (targetInfo is _VariableReadInfo<Variable, Type>) {
3080-
_current = _current
3081-
.tryMarkNonNullable(typeOperations, targetInfo._variable)
3082-
.ifTrue;
3086+
Variable targetVariable = _getExpressionVariable(target);
3087+
if (targetVariable != null) {
3088+
_current =
3089+
_current.tryMarkNonNullable(typeOperations, targetVariable).ifTrue;
30833090
}
30843091
}
30853092
}
@@ -3226,7 +3233,7 @@ class _FlowAnalysisImpl<Node, Statement extends Node, Expression, Variable,
32263233

32273234
@override
32283235
Type variableRead(Expression expression, Variable variable) {
3229-
_storeExpressionInfo(expression, new _VariableReadInfo(_current, variable));
3236+
_storeExpressionVariable(expression, variable);
32303237
return _current.infoFor(variable).promotedTypes?.last;
32313238
}
32323239

@@ -3273,6 +3280,8 @@ class _FlowAnalysisImpl<Node, Statement extends Node, Expression, Variable,
32733280
print(' current: $_current');
32743281
print(' expressionWithInfo: $_expressionWithInfo');
32753282
print(' expressionInfo: $_expressionInfo');
3283+
print(' expressionWithVariable: $_expressionWithVariable');
3284+
print(' expressionVariable: $_expressionVariable');
32763285
print(' stack:');
32773286
for (_FlowContext stackEntry in _stack.reversed) {
32783287
print(' $stackEntry');
@@ -3301,6 +3310,19 @@ class _FlowAnalysisImpl<Node, Statement extends Node, Expression, Variable,
33013310
}
33023311
}
33033312

3313+
/// Gets the [Variable] associated with the [expression] (which should be the
3314+
/// last expression that was traversed). If there is no [Variable] associated
3315+
/// with the [expression], then `null` is returned.
3316+
Variable _getExpressionVariable(Expression expression) {
3317+
if (identical(expression, _expressionWithVariable)) {
3318+
Variable expressionVariable = _expressionVariable;
3319+
_expressionVariable = null;
3320+
return expressionVariable;
3321+
} else {
3322+
return null;
3323+
}
3324+
}
3325+
33043326
FlowModel<Variable, Type> _join(
33053327
FlowModel<Variable, Type> first, FlowModel<Variable, Type> second) =>
33063328
FlowModel.join(typeOperations, first, second, _current._emptyVariableMap);
@@ -3319,6 +3341,14 @@ class _FlowAnalysisImpl<Node, Statement extends Node, Expression, Variable,
33193341
_expressionInfo = expressionInfo;
33203342
_current = expressionInfo.after;
33213343
}
3344+
3345+
/// Associates [expression], which should be the most recently visited
3346+
/// expression, with the given [Variable] object.
3347+
void _storeExpressionVariable(
3348+
Expression expression, Variable expressionVariable) {
3349+
_expressionWithVariable = expression;
3350+
_expressionVariable = expressionVariable;
3351+
}
33223352
}
33233353

33243354
/// Base class for objects representing constructs in the Dart programming
@@ -3437,28 +3467,6 @@ class _TryContext<Variable, Type> extends _SimpleContext<Variable, Type> {
34373467
'afterBodyAndCatches: $_afterBodyAndCatches)';
34383468
}
34393469

3440-
/// [ExpressionInfo] representing an expression that reads the value of a
3441-
/// variable.
3442-
class _VariableReadInfo<Variable, Type>
3443-
implements ExpressionInfo<Variable, Type> {
3444-
@override
3445-
final FlowModel<Variable, Type> after;
3446-
3447-
/// The variable that is being read.
3448-
final Variable _variable;
3449-
3450-
_VariableReadInfo(this.after, this._variable);
3451-
3452-
@override
3453-
FlowModel<Variable, Type> get ifFalse => after;
3454-
3455-
@override
3456-
FlowModel<Variable, Type> get ifTrue => after;
3457-
3458-
@override
3459-
String toString() => '_VariableReadInfo(after: $after, variable: $_variable)';
3460-
}
3461-
34623470
/// [_FlowContext] representing a `while` loop (or a C-style `for` loop, which
34633471
/// is functionally similar).
34643472
class _WhileContext<Variable, Type>

0 commit comments

Comments
 (0)