diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart index a3188cf0258b..d4467029df50 100644 --- a/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart +++ b/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_test.dart @@ -2154,6 +2154,27 @@ main() { ]); }); + test('postIncDec() does not store expressionInfo in the write', () { + // num x; + // if (x++ is int) { + // x is not promoted. + // } + + var x = Var('x'); + h.run([ + declare(x, type: 'num'), + if_( + x + .postIncDec() + .is_('int') + .getExpressionInfo((info) => expect(info, isNull)), + [ + checkNotPromoted(x), + ]), + checkNotPromoted(x), + ]); + }); + test('switchExpression throw in scrutinee makes all cases unreachable', () { h.run([ switchExpr(throw_(expr('C')), [ diff --git a/pkg/_fe_analyzer_shared/test/mini_ast.dart b/pkg/_fe_analyzer_shared/test/mini_ast.dart index df5058925ac2..d911205ffed1 100644 --- a/pkg/_fe_analyzer_shared/test/mini_ast.dart +++ b/pkg/_fe_analyzer_shared/test/mini_ast.dart @@ -2529,6 +2529,9 @@ abstract class LValue extends Expression { location: location); } + void _visitPostIncDec( + Harness h, Expression postIncDecExpression, Type writtenType); + void _visitWrite(Harness h, Expression assignmentExpression, Type writtenType, Expression? rhs); } @@ -3851,6 +3854,31 @@ mixin PossiblyGuardedPattern on Node implements ProtoSwitchHead { } } +/// Representation of a postfix increment or decrement operation. +class PostIncDec extends Expression { + final LValue lhs; + + PostIncDec(this.lhs, {required super.location}); + + @override + void preVisit(PreVisitor visitor) { + lhs.preVisit(visitor, disposition: _LValueDisposition.readWrite); + } + + @override + String toString() => '$lhs++'; + + @override + ExpressionTypeAnalysisResult visit( + Harness h, SharedTypeSchemaView schema) { + Type type = h.typeAnalyzer + .analyzeExpression(lhs, h.operations.unknownType) + .unwrapTypeView(); + lhs._visitPostIncDec(h, this, type); + return new SimpleTypeAnalysisResult(type: SharedTypeView(type)); + } +} + /// Data structure holding information needed during the "pre-visit" phase of /// type analysis. class PreVisitor { @@ -3916,6 +3944,12 @@ class Property extends PromotableLValue { ?.unwrapTypeView(); } + @override + void _visitPostIncDec( + Harness h, Expression postIncDecExpression, Type writtenType) { + // No flow analysis impact + } + @override void _visitWrite(Harness h, Expression assignmentExpression, Type writtenType, Expression? rhs) { @@ -4673,6 +4707,12 @@ class ThisOrSuperProperty extends PromotableLValue { ?.unwrapTypeView(); } + @override + void _visitPostIncDec( + Harness h, Expression postIncDecExpression, Type writtenType) { + // No flow analysis impact + } + @override void _visitWrite(Harness h, Expression assignmentExpression, Type writtenType, Expression? rhs) { @@ -4856,6 +4896,16 @@ class Var extends Node @override void preVisit(PreVisitor visitor) {} + /// Creates an expression representing a postfix increment or decrement + /// operation applied to this variable. + Expression postIncDec() { + var location = computeLocation(); + return new PostIncDec( + new VariableReference._(this, null, location: location), + location: location, + ); + } + /// Creates an expression representing a read of this variable, which as a /// side effect will call the given callback with the returned promoted type. Expression readAndCheckPromotedType(void Function(Type?) callback) => @@ -4978,6 +5028,16 @@ class VariableReference extends LValue { return result; } + @override + void _visitPostIncDec( + Harness h, Expression postIncDecExpression, Type writtenType) { + h.flow.postIncDec( + postIncDecExpression, + variable, + SharedTypeView(writtenType), + ); + } + @override void _visitWrite(Harness h, Expression assignmentExpression, Type writtenType, Expression? rhs) {