Skip to content

Commit 00e4c92

Browse files
kallentuCommit Queue
authored and
Commit Queue
committed
[flow] Part 3 Issue 3658 Avoid writing promotion information for postfix inc/dec expressions.
Postfix increment and decrement expressions should not be saving any promotion information. An example of where saving the promotion information after the write is unsafe is: ``` class A { A operator +(int i) { return new B(); } } class B extends A {} main() { A x = A(); if ((x++) is B) { // x should not be B } } ``` This change is only for the analyzer because the CFE does something different (converts the postfix increment/decrement into a let expression). Bug: dart-lang/language#3658 Change-Id: Ic22f69bf79da66965908ade80bdf70399f0bcaa3 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/391494 Reviewed-by: Paul Berry <[email protected]> Commit-Queue: Kallen Tu <[email protected]>
1 parent 507d40f commit 00e4c92

File tree

3 files changed

+69
-4
lines changed

3 files changed

+69
-4
lines changed

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

+24-2
Original file line numberDiff line numberDiff line change
@@ -822,6 +822,10 @@ abstract class FlowAnalysis<Node extends Object, Statement extends Node,
822822
/// state that was saved by [pushSubpattern].
823823
void popSubpattern();
824824

825+
/// Call this method when writing to the [variable] with type [writtenType] in
826+
/// a postfix increment or decrement operation.
827+
void postIncDec(Node node, Variable variable, Type writtenType);
828+
825829
/// Retrieves the type that a property named [propertyName] is promoted to, if
826830
/// the property is currently promoted. Otherwise returns `null`.
827831
///
@@ -1818,6 +1822,12 @@ class FlowAnalysisDebug<Node extends Object, Statement extends Node,
18181822
_wrap('popSubpattern()', () => _wrapped.popSubpattern());
18191823
}
18201824

1825+
@override
1826+
void postIncDec(Node node, Variable variable, Type writtenType) {
1827+
_wrap(
1828+
'postIncDec()', () => _wrapped.postIncDec(node, variable, writtenType));
1829+
}
1830+
18211831
@override
18221832
Type? promotedPropertyType(PropertyTarget<Expression> target,
18231833
String propertyName, Object? propertyMember, Type unpromotedType) {
@@ -5296,6 +5306,11 @@ class _FlowAnalysisImpl<Node extends Object, Statement extends Node,
52965306
assert(context is _PatternContext<Type>);
52975307
}
52985308

5309+
@override
5310+
void postIncDec(Node node, Variable variable, Type writtenType) {
5311+
_write(node, variable, writtenType, null, isPostfixIncDec: true);
5312+
}
5313+
52995314
@override
53005315
Type? promotedPropertyType(PropertyTarget<Expression> target,
53015316
String propertyName, Object? propertyMember, Type unpromotedType) {
@@ -6274,8 +6289,12 @@ class _FlowAnalysisImpl<Node extends Object, Statement extends Node,
62746289

62756290
/// Common logic for handling writes to variables, whether they occur as part
62766291
/// of an ordinary assignment or a pattern assignment.
6292+
///
6293+
/// If [isPostfixIncDec] is `true`, the [node] is a postfix expression and we
6294+
/// won't store information about [variable].
62776295
void _write(Node node, Variable variable, Type writtenType,
6278-
ExpressionInfo<Type>? expressionInfo) {
6296+
ExpressionInfo<Type>? expressionInfo,
6297+
{bool isPostfixIncDec = false}) {
62796298
Type unpromotedType = operations.variableType(variable);
62806299
int variableKey = promotionKeyStore.keyForVariable(variable);
62816300
SsaNode<Type> newSsaNode = new SsaNode<Type>(
@@ -6292,7 +6311,7 @@ class _FlowAnalysisImpl<Node extends Object, Statement extends Node,
62926311
unpromotedType: unpromotedType);
62936312

62946313
// Update the type of the variable for looking up the write expression.
6295-
if (inferenceUpdate4Enabled && node is Expression) {
6314+
if (inferenceUpdate4Enabled && node is Expression && !isPostfixIncDec) {
62966315
_Reference<Type> reference = _variableReference(
62976316
variableKey,
62986317
unpromotedType,
@@ -6891,6 +6910,9 @@ class _LegacyTypePromotion<Node extends Object, Statement extends Node,
68916910
@override
68926911
void popSubpattern() {}
68936912

6913+
@override
6914+
void postIncDec(Node node, Variable variable, Type writtenType) {}
6915+
68946916
@override
68956917
Type? promotedPropertyType(PropertyTarget<Expression> target,
68966918
String propertyName, Object? propertyMember, Type unpromotedType) =>

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

+12-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// BSD-style license that can be found in the LICENSE file.
44

55
import 'package:_fe_analyzer_shared/src/types/shared_type.dart';
6+
import 'package:analyzer/dart/analysis/features.dart';
67
import 'package:analyzer/dart/ast/token.dart';
78
import 'package:analyzer/dart/element/element.dart';
89
import 'package:analyzer/dart/element/type.dart';
@@ -176,8 +177,17 @@ class PostfixExpressionResolver {
176177
if (operand is SimpleIdentifier) {
177178
var element = operand.staticElement;
178179
if (element is PromotableElement) {
179-
_resolver.flowAnalysis.flow
180-
?.write(node, element, SharedTypeView(operatorReturnType), null);
180+
if (_resolver.definingLibrary.featureSet
181+
.isEnabled(Feature.inference_update_4)) {
182+
_resolver.flowAnalysis.flow?.postIncDec(
183+
node,
184+
element,
185+
SharedTypeView(operatorReturnType),
186+
);
187+
} else {
188+
_resolver.flowAnalysis.flow?.write(
189+
node, element, SharedTypeView(operatorReturnType), null);
190+
}
181191
}
182192
}
183193
node.recordStaticType(receiverType, resolver: _resolver);

pkg/analyzer/test/src/dart/resolution/postfix_expression_test.dart

+33
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5+
import 'package:analyzer/dart/analysis/features.dart';
56
import 'package:analyzer/dart/ast/ast.dart';
67
import 'package:analyzer/src/dart/error/syntactic_errors.dart';
78
import 'package:analyzer/src/error/codes.dart';
@@ -11,10 +12,42 @@ import 'context_collection_resolution.dart';
1112

1213
main() {
1314
defineReflectiveSuite(() {
15+
defineReflectiveTests(InferenceUpdate4Test);
1416
defineReflectiveTests(PostfixExpressionResolutionTest);
1517
});
1618
}
1719

20+
@reflectiveTest
21+
class InferenceUpdate4Test extends PubPackageResolutionTest {
22+
@override
23+
List<String> get experiments {
24+
return [
25+
...super.experiments,
26+
Feature.inference_update_4.enableString,
27+
];
28+
}
29+
30+
test_isExpression_notPromoted() async {
31+
await assertNoErrorsInCode('''
32+
f() {
33+
num x = 2;
34+
if ((x++) is int) {
35+
x;
36+
}
37+
}
38+
''');
39+
var nonPromotedIdentifier = findNode.simple('x;');
40+
assertResolvedNodeText(nonPromotedIdentifier, r'''
41+
SimpleIdentifier
42+
token: x
43+
staticElement: x@12
44+
element: x@12
45+
staticType: num
46+
''');
47+
assertType(nonPromotedIdentifier, 'num');
48+
}
49+
}
50+
1851
@reflectiveTest
1952
class PostfixExpressionResolutionTest extends PubPackageResolutionTest {
2053
test_dec_simpleIdentifier_parameter_int() async {

0 commit comments

Comments
 (0)