Skip to content

Commit 5c19c9f

Browse files
stereotype441commit-bot@chromium.org
authored andcommitted
Flow analysis: store ExpressionInfo in SSA nodes.
This CL modifies flow analysis API so that when a variable is written or initialized, if the written expression has non-trivial flow analysis information, it is captured in the SsaNode associated with the variable. The stored information is not yet used; in a follow-up CL, I will add the ability to retrieve it on a read and use it for promotions. Bug: dart-lang/language#1274 Change-Id: I1e2590205d4a0c59f4400a119f3d6b380a11414c Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/176460 Reviewed-by: Konstantin Shcheglov <[email protected]> Reviewed-by: Johnni Winther <[email protected]>
1 parent c64842e commit 5c19c9f

File tree

11 files changed

+489
-151
lines changed

11 files changed

+489
-151
lines changed

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

Lines changed: 155 additions & 53 deletions
Large diffs are not rendered by default.

pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_mini_ast.dart

Lines changed: 78 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -68,13 +68,15 @@ Statement continue_(BranchTargetPlaceholder branchTargetPlaceholder) =>
6868
new _Continue(branchTargetPlaceholder);
6969

7070
Statement declare(Var variable,
71-
{required bool initialized, bool isFinal = false}) =>
72-
new _Declare(
73-
variable, initialized ? expr(variable.type.type) : null, isFinal);
71+
{required bool initialized,
72+
bool isFinal = false,
73+
bool isLate = false}) =>
74+
new _Declare(variable, initialized ? expr(variable.type.type) : null,
75+
isFinal, isLate);
7476

7577
Statement declareInitialized(Var variable, Expression initializer,
76-
{bool isFinal = false}) =>
77-
new _Declare(variable, initializer, isFinal);
78+
{bool isFinal = false, bool isLate = false}) =>
79+
new _Declare(variable, initializer, isFinal, isLate);
7880

7981
Statement do_(List<Statement> body, Expression condition) =>
8082
_Do(body, condition);
@@ -211,6 +213,9 @@ abstract class Expression implements _Visitable<Type> {
211213
/// If `this` is an expression `x`, creates the expression `x!`.
212214
Expression get nonNullAssert => new _NonNullAssert(this);
213215

216+
/// If `this` is an expression `x`, creates the expression `!x`.
217+
Expression get not => new _Not(this);
218+
214219
/// If `this` is an expression `x`, creates the expression `(x)`.
215220
Expression get parenthesized => new _ParenthesizedExpression(this);
216221

@@ -231,6 +236,15 @@ abstract class Expression implements _Visitable<Type> {
231236
/// If `this` is an expression `x`, creates the expression `x == other`.
232237
Expression eq(Expression other) => new _Equal(this, other, false);
233238

239+
/// Creates an [Expression] that, when analyzed, will behave the same as
240+
/// `this`, but after visiting it, will cause [callback] to be passed the
241+
/// [ExpressionInfo] associated with it. If the expression has no flow
242+
/// analysis information associated with it, `null` will be passed to
243+
/// [callback].
244+
Expression getExpressionInfo(
245+
void Function(ExpressionInfo<Var, Type>?) callback) =>
246+
new _GetExpressionInfo(this, callback);
247+
234248
/// If `this` is an expression `x`, creates the expression `x ?? other`.
235249
Expression ifNull(Expression other) => new _IfNull(this, other);
236250

@@ -520,7 +534,8 @@ class SsaNodeHarness {
520534

521535
/// Gets the SSA node associated with [variable] at the current point in
522536
/// control flow, or `null` if the variable has been write captured.
523-
SsaNode? operator [](Var variable) => _flow.ssaNodeForTesting(variable);
537+
SsaNode<Var, Type>? operator [](Var variable) =>
538+
_flow.ssaNodeForTesting(variable);
524539
}
525540

526541
/// Representation of a statement in the pseudo-Dart language used for flow
@@ -591,7 +606,7 @@ class Var {
591606
String toString() => '$type $name';
592607

593608
/// Creates an expression representing a write to this variable.
594-
Expression write(Expression value) => new _Write(this, value);
609+
Expression write(Expression? value) => new _Write(this, value);
595610
}
596611

597612
class _As extends Expression {
@@ -848,14 +863,17 @@ class _Declare extends Statement {
848863
final Var variable;
849864
final Expression? initializer;
850865
final bool isFinal;
866+
final bool isLate;
851867

852-
_Declare(this.variable, this.initializer, this.isFinal) : super._();
868+
_Declare(this.variable, this.initializer, this.isFinal, this.isLate)
869+
: super._();
853870

854871
@override
855872
String toString() {
873+
var latePart = isLate ? 'late ' : '';
856874
var finalPart = isFinal ? 'final ' : '';
857875
var initializerPart = initializer != null ? ' = $initializer' : '';
858-
return '$finalPart$variable${initializerPart};';
876+
return '$latePart$finalPart$variable${initializerPart};';
859877
}
860878

861879
@override
@@ -870,8 +888,10 @@ class _Declare extends Statement {
870888
if (initializer == null) {
871889
flow.declare(variable, false);
872890
} else {
873-
initializer._visit(h, flow);
891+
var initializerType = initializer._visit(h, flow);
874892
flow.declare(variable, true);
893+
flow.initialize(variable, initializerType, initializer,
894+
isFinal: isFinal, isLate: isLate);
875895
}
876896
}
877897
}
@@ -1053,6 +1073,28 @@ class _ForEach extends Statement {
10531073
}
10541074
}
10551075

1076+
class _GetExpressionInfo extends Expression {
1077+
final Expression target;
1078+
1079+
final void Function(ExpressionInfo<Var, Type>?) callback;
1080+
1081+
_GetExpressionInfo(this.target, this.callback);
1082+
1083+
@override
1084+
void _preVisit(AssignedVariables<Node, Var> assignedVariables) {
1085+
target._preVisit(assignedVariables);
1086+
}
1087+
1088+
@override
1089+
Type _visit(
1090+
Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
1091+
var type = target._visit(h, flow);
1092+
flow.forwardExpression(this, target);
1093+
callback(flow.expressionInfoForTesting(this));
1094+
return type;
1095+
}
1096+
}
1097+
10561098
class _GetSsaNodes extends Statement {
10571099
final void Function(SsaNodeHarness) callback;
10581100

@@ -1246,6 +1288,27 @@ class _NonNullAssert extends Expression {
12461288
}
12471289
}
12481290

1291+
class _Not extends Expression {
1292+
final Expression operand;
1293+
1294+
_Not(this.operand);
1295+
1296+
@override
1297+
String toString() => '!$operand';
1298+
1299+
@override
1300+
void _preVisit(AssignedVariables<Node, Var> assignedVariables) {
1301+
operand._preVisit(assignedVariables);
1302+
}
1303+
1304+
@override
1305+
Type _visit(
1306+
Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
1307+
flow.logicalNot_end(this, operand.._visit(h, flow));
1308+
return Type('bool');
1309+
}
1310+
}
1311+
12491312
class _NullAwareAccess extends Expression {
12501313
final Expression lhs;
12511314
final Expression rhs;
@@ -1540,7 +1603,7 @@ class _WrappedExpression extends Expression {
15401603

15411604
class _Write extends Expression {
15421605
final Var variable;
1543-
final Expression rhs;
1606+
final Expression? rhs;
15441607

15451608
_Write(this.variable, this.rhs);
15461609

@@ -1550,14 +1613,15 @@ class _Write extends Expression {
15501613
@override
15511614
void _preVisit(AssignedVariables<Node, Var> assignedVariables) {
15521615
assignedVariables.write(variable);
1553-
rhs._preVisit(assignedVariables);
1616+
rhs?._preVisit(assignedVariables);
15541617
}
15551618

15561619
@override
15571620
Type _visit(
15581621
Harness h, FlowAnalysis<Node, Statement, Expression, Var, Type> flow) {
1559-
var type = rhs._visit(h, flow);
1560-
flow.write(variable, type);
1622+
var rhs = this.rhs;
1623+
var type = rhs == null ? variable.type : rhs._visit(h, flow);
1624+
flow.write(variable, type, rhs);
15611625
return type;
15621626
}
15631627
}

0 commit comments

Comments
 (0)