Skip to content

Commit 4e9220e

Browse files
stereotype441commit-bot@chromium.org
authored andcommitted
Flow analysis: change the way parenthesized expressions are handled.
Instead of forcing the client to provide a way to de-parenthesize an expression, the client informs flow analysis when a parenthesized expression is encountered. This reduces the runtime overhead to zero for non-parenthesized expressions, and it saves the front end from having to worry about support for parenthesized expressions (since its internal representation doesn't care about parentheses). Change-Id: I0bb6e91c87acaa05591e1b075da18700b11e4aae Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/121080 Reviewed-by: Mike Fairhurst <mfairhurst@google.com>
1 parent 5fad012 commit 4e9220e

File tree

7 files changed

+77
-43
lines changed

7 files changed

+77
-43
lines changed

pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,24 +11,12 @@ import 'package:analyzer/src/dart/element/type.dart';
1111
import 'package:analyzer/src/generated/variable_type_provider.dart';
1212
import 'package:front_end/src/fasta/flow_analysis/flow_analysis.dart';
1313

14-
class AnalyzerNodeOperations implements NodeOperations<Expression> {
15-
const AnalyzerNodeOperations();
16-
17-
@override
18-
Expression unwrapParenthesized(Expression node) {
19-
return node.unParenthesized;
20-
}
21-
}
22-
2314
/// The helper for performing flow analysis during resolution.
2415
///
2516
/// It contains related precomputed data, result, and non-trivial pieces of
2617
/// code that are independent from visiting AST during resolution, so can
2718
/// be extracted.
2819
class FlowAnalysisHelper {
29-
/// The reused instance for creating new [FlowAnalysis] instances.
30-
final NodeOperations<Expression> _nodeOperations;
31-
3220
/// The reused instance for creating new [FlowAnalysis] instances.
3321
final TypeSystemTypeOperations _typeOperations;
3422

@@ -42,13 +30,11 @@ class FlowAnalysisHelper {
4230
FlowAnalysis<Statement, Expression, PromotableElement, DartType> flow;
4331

4432
factory FlowAnalysisHelper(TypeSystem typeSystem, bool retainDataForTesting) {
45-
return FlowAnalysisHelper._(
46-
const AnalyzerNodeOperations(),
47-
TypeSystemTypeOperations(typeSystem),
33+
return FlowAnalysisHelper._(TypeSystemTypeOperations(typeSystem),
4834
retainDataForTesting ? FlowAnalysisResult() : null);
4935
}
5036

51-
FlowAnalysisHelper._(this._nodeOperations, this._typeOperations, this.result);
37+
FlowAnalysisHelper._(this._typeOperations, this.result);
5238

5339
LocalVariableTypeProvider get localVariableTypeProvider {
5440
return _LocalVariableTypeProvider(this);
@@ -186,7 +172,6 @@ class FlowAnalysisHelper {
186172
assert(flow == null);
187173
assignedVariables = computeAssignedVariables(node, parameters);
188174
flow = FlowAnalysis<Statement, Expression, PromotableElement, DartType>(
189-
_nodeOperations,
190175
_typeOperations,
191176
assignedVariables.writtenAnywhere,
192177
assignedVariables.capturedAnywhere);

pkg/analyzer/lib/src/generated/resolver.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4345,6 +4345,7 @@ class ResolverVisitor extends ScopedVisitor {
43454345
void visitParenthesizedExpression(ParenthesizedExpression node) {
43464346
InferenceContext.setTypeFromNode(node.expression, node);
43474347
super.visitParenthesizedExpression(node);
4348+
_flowAnalysis?.flow?.parenthesizedExpression(node, node.expression);
43484349
}
43494350

43504351
@override

pkg/front_end/lib/src/fasta/flow_analysis/flow_analysis.dart

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -168,9 +168,6 @@ class FlowAnalysis<Statement, Expression, Variable, Type> {
168168

169169
final List<Variable> _variablesCapturedAnywhere;
170170

171-
/// The [NodeOperations], used to manipulate expressions.
172-
final NodeOperations<Expression> nodeOperations;
173-
174171
/// The [TypeOperations], used to access types, and check subtyping.
175172
final TypeOperations<Variable, Type> typeOperations;
176173

@@ -198,16 +195,15 @@ class FlowAnalysis<Statement, Expression, Variable, Type> {
198195
int _functionNestingLevel = 0;
199196

200197
factory FlowAnalysis(
201-
NodeOperations<Expression> nodeOperations,
202198
TypeOperations<Variable, Type> typeOperations,
203199
Iterable<Variable> variablesWrittenAnywhere,
204200
Iterable<Variable> variablesCapturedAnywhere) {
205-
return new FlowAnalysis._(nodeOperations, typeOperations,
206-
variablesWrittenAnywhere.toList(), variablesCapturedAnywhere.toList());
201+
return new FlowAnalysis._(typeOperations, variablesWrittenAnywhere.toList(),
202+
variablesCapturedAnywhere.toList());
207203
}
208204

209-
FlowAnalysis._(this.nodeOperations, this.typeOperations,
210-
this._variablesWrittenAnywhere, this._variablesCapturedAnywhere) {
205+
FlowAnalysis._(this.typeOperations, this._variablesWrittenAnywhere,
206+
this._variablesCapturedAnywhere) {
211207
_current = new FlowModel<Variable, Type>(true);
212208
}
213209

@@ -552,6 +548,17 @@ class FlowAnalysis<Statement, Expression, Variable, Type> {
552548
_storeExpressionInfo(expression, new _NullInfo(_current));
553549
}
554550

551+
/// Call this method just after visiting a parenthesized expression.
552+
///
553+
/// This is only necessary if the implementation uses a different [Expression]
554+
/// object to represent a parenthesized expression and its contents.
555+
void parenthesizedExpression(
556+
Expression outerExpression, Expression innerExpression) {
557+
if (identical(_expressionWithInfo, innerExpression)) {
558+
_expressionWithInfo = outerExpression;
559+
}
560+
}
561+
555562
/// Retrieves the type that the [variable] is promoted to, if the [variable]
556563
/// is currently promoted. Otherwise returns `null`.
557564
///
@@ -722,7 +729,6 @@ class FlowAnalysis<Statement, Expression, Variable, Type> {
722729
/// [_ExpressionInfo] associated with the [expression], then `null` is
723730
/// returned.
724731
_ExpressionInfo<Variable, Type> _getExpressionInfo(Expression expression) {
725-
expression = nodeOperations.unwrapParenthesized(expression);
726732
if (identical(expression, _expressionWithInfo)) {
727733
return _expressionInfo;
728734
} else {
@@ -1087,12 +1093,6 @@ class FlowModel<Variable, Type> {
10871093
}
10881094
}
10891095

1090-
/// Operations on nodes, abstracted from concrete node interfaces.
1091-
abstract class NodeOperations<Expression> {
1092-
/// If the [node] is a parenthesized expression, recursively unwrap it.
1093-
Expression unwrapParenthesized(Expression node);
1094-
}
1095-
10961096
/// Operations on types, abstracted from concrete type interfaces.
10971097
abstract class TypeOperations<Variable, Type> {
10981098
/// Returns `true` if [type1] and [type2] are the same type.

pkg/front_end/test/fasta/flow_analysis/flow_analysis_test.dart

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -768,6 +768,18 @@ main() {
768768
});
769769
});
770770

771+
test('parenthesizedExpression preserves promotion behaviors', () {
772+
var h = _Harness();
773+
var x = h.addVar('x', 'int?');
774+
h.run((flow) {
775+
h.if_(
776+
h.parenthesized(h.notEqual(h.parenthesized(h.variableRead(x)),
777+
h.parenthesized(h.nullLiteral))), () {
778+
expect(flow.promotedType(x).type, 'int');
779+
});
780+
});
781+
});
782+
771783
test('promotedType handles not-yet-seen variables', () {
772784
// Note: this is needed for error recovery in the analyzer.
773785
var h = _Harness();
@@ -1785,8 +1797,7 @@ typedef _Expression LazyExpression();
17851797

17861798
class _Expression {}
17871799

1788-
class _Harness
1789-
implements NodeOperations<_Expression>, TypeOperations<_Var, _Type> {
1800+
class _Harness implements TypeOperations<_Var, _Type> {
17901801
FlowAnalysis<_Statement, _Expression, _Var, _Type> _flow;
17911802

17921803
final List<_Var> _variablesWrittenAnywhere = [];
@@ -1797,6 +1808,12 @@ class _Harness
17971808
/// flow analysis semantics.
17981809
LazyExpression get expr => () => _Expression();
17991810

1811+
LazyExpression get nullLiteral => () {
1812+
var expr = _Expression();
1813+
_flow.nullLiteral(expr);
1814+
return expr;
1815+
};
1816+
18001817
_Var addVar(String name, String type,
18011818
{bool hasWrites: false, bool isCaptured: false}) {
18021819
assert(_flow == null);
@@ -1837,7 +1854,7 @@ class _Harness
18371854

18381855
FlowAnalysis<_Statement, _Expression, _Var, _Type> createFlow() =>
18391856
FlowAnalysis<_Statement, _Expression, _Var, _Type>(
1840-
this, this, _variablesWrittenAnywhere, _variablesCapturedAnywhere);
1857+
this, _variablesWrittenAnywhere, _variablesCapturedAnywhere);
18411858

18421859
void declare(_Var v, {@required bool initialized}) {
18431860
if (initialized) {
@@ -1860,6 +1877,17 @@ class _Harness
18601877
};
18611878
}
18621879

1880+
/// Creates a [LazyExpression] representing an equality check between two
1881+
/// other expressions.
1882+
LazyExpression notEqual(LazyExpression lhs, LazyExpression rhs) {
1883+
return () {
1884+
var expr = _Expression();
1885+
_flow.equalityOp_rightBegin(lhs());
1886+
_flow.equalityOp_end(expr, rhs(), notEqual: true);
1887+
return expr;
1888+
};
1889+
}
1890+
18631891
/// Invokes flow analysis of a nested function.
18641892
void function(Iterable<_Var> writeCaptured, void body()) {
18651893
_flow.functionExpression_begin(writeCaptured);
@@ -1954,6 +1982,15 @@ class _Harness
19541982
};
19551983
}
19561984

1985+
/// Creates a [LazyExpression] representing a parenthesized subexpression.
1986+
LazyExpression parenthesized(LazyExpression inner) {
1987+
return () {
1988+
var expr = _Expression();
1989+
_flow.parenthesizedExpression(expr, inner());
1990+
return expr;
1991+
};
1992+
}
1993+
19571994
/// Causes [variable] to be promoted to [type].
19581995
void promote(_Var variable, String type) {
19591996
if_(isNotType(variable, type), _flow.handleExit);
@@ -1976,10 +2013,12 @@ class _Harness
19762013
_flow.finish();
19772014
}
19782015

1979-
@override
1980-
_Expression unwrapParenthesized(_Expression node) {
1981-
// TODO(paulberry): test cases where this matters
1982-
return node;
2016+
LazyExpression variableRead(_Var variable) {
2017+
return () {
2018+
var expr = _Expression();
2019+
_flow.variableRead(expr, variable);
2020+
return expr;
2021+
};
19832022
}
19842023

19852024
@override

pkg/nnbd_migration/lib/src/edge_builder.dart

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -966,7 +966,9 @@ class EdgeBuilder extends GeneralizingAstVisitor<DecoratedType>
966966

967967
@override
968968
DecoratedType visitParenthesizedExpression(ParenthesizedExpression node) {
969-
return node.expression.accept(this);
969+
var result = node.expression.accept(this);
970+
_flowAnalysis.parenthesizedExpression(node, node.expression);
971+
return result;
970972
}
971973

972974
@override
@@ -1454,7 +1456,6 @@ class EdgeBuilder extends GeneralizingAstVisitor<DecoratedType>
14541456
FlowAnalysisHelper.computeAssignedVariables(node, parameters);
14551457
_flowAnalysis =
14561458
FlowAnalysis<Statement, Expression, PromotableElement, DecoratedType>(
1457-
const AnalyzerNodeOperations(),
14581459
DecoratedTypeOperations(_typeSystem, _variables, _graph),
14591460
_assignedVariables.writtenAnywhere,
14601461
_assignedVariables.capturedAnywhere);

pkg/nnbd_migration/lib/src/fix_builder.dart

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,6 @@ abstract class FixBuilder extends GeneralizingAstVisitor<DartType> {
111111
FlowAnalysisHelper.computeAssignedVariables(node, parameters);
112112
_flowAnalysis =
113113
FlowAnalysis<Statement, Expression, PromotableElement, DartType>(
114-
const AnalyzerNodeOperations(),
115114
TypeSystemTypeOperations(_typeSystem),
116115
_assignedVariables.writtenAnywhere,
117116
_assignedVariables.capturedAnywhere);
@@ -252,7 +251,9 @@ abstract class FixBuilder extends GeneralizingAstVisitor<DartType> {
252251

253252
@override
254253
DartType visitParenthesizedExpression(ParenthesizedExpression node) {
255-
return node.expression.accept(this);
254+
var result = node.expression.accept(this);
255+
_flowAnalysis.parenthesizedExpression(node, node.expression);
256+
return result;
256257
}
257258

258259
@override

pkg/nnbd_migration/test/fix_builder_test.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,13 @@ f() => (1);
543543
visitSubexpression(findNode.integerLiteral('1'), 'int');
544544
}
545545

546+
test_parenthesizedExpression_flow() async {
547+
await analyze('''
548+
_f(bool/*?*/ x) => ((x) != (null)) && x;
549+
''');
550+
visitSubexpression(findNode.binary('&&'), 'bool');
551+
}
552+
546553
test_simpleIdentifier_className() async {
547554
await analyze('''
548555
_f() => int;

0 commit comments

Comments
 (0)