@@ -18,6 +18,7 @@ import 'package:analyzer/src/dart/resolver/resolution_result.dart';
1818import 'package:analyzer/src/dart/resolver/type_property_resolver.dart' ;
1919import 'package:analyzer/src/error/codes.dart' ;
2020import 'package:analyzer/src/error/nullable_dereference_verifier.dart' ;
21+ import 'package:analyzer/src/generated/migration.dart' ;
2122import 'package:analyzer/src/generated/resolver.dart' ;
2223import 'package:analyzer/src/task/strong/checker.dart' ;
2324import 'package:meta/meta.dart' ;
@@ -46,6 +47,10 @@ class AssignmentExpressionResolver {
4647
4748 bool get _isNonNullableByDefault => _typeSystem.isNonNullableByDefault;
4849
50+ MigrationResolutionHooks get _migrationResolutionHooks {
51+ return _resolver.migrationResolutionHooks;
52+ }
53+
4954 NullableDereferenceVerifier get _nullableDereferenceVerifier =>
5055 _resolver.nullableDereferenceVerifier;
5156
@@ -57,10 +62,22 @@ class AssignmentExpressionResolver {
5762 var left = node.leftHandSide;
5863 var right = node.rightHandSide;
5964
65+ // Case `id = e`.
66+ // Consider an assignment of the form `id = e`, where `id` is an identifier.
67+ if (left is SimpleIdentifier ) {
68+ var leftLookup = _resolver.nameScope.lookup2 (left.name);
69+ // When the lexical lookup yields a local variable `v`.
70+ var leftGetter = leftLookup.getter;
71+ if (leftGetter is VariableElement ) {
72+ _resolve_SimpleIdentifier_LocalVariable (node, left, leftGetter, right);
73+ return ;
74+ }
75+ }
76+
6077 left? .accept (_resolver);
6178 left = node.leftHandSide;
6279
63- var leftLocalVariable = _flowAnalysis? .assignmentExpression (node);
80+ _flowAnalysis? .assignmentExpression (node);
6481
6582 TokenType operator = node.operator .type;
6683 if (operator == TokenType .EQ ||
@@ -76,12 +93,7 @@ class AssignmentExpressionResolver {
7693 _resolve1 (node);
7794 _resolve2 (node);
7895
79- _flowAnalysis? .assignmentExpression_afterRight (
80- node,
81- leftLocalVariable,
82- operator == TokenType .QUESTION_QUESTION_EQ
83- ? node.rightHandSide.staticType
84- : node.staticType);
96+ _flowAnalysis? .assignmentExpression_afterRight (node);
8597 }
8698
8799 /// Set the static type of [node] to be the least upper bound of the static
@@ -180,6 +192,32 @@ class AssignmentExpressionResolver {
180192 return type;
181193 }
182194
195+ /// Record that the static type of the given node is the given type.
196+ ///
197+ /// @param expression the node whose type is to be recorded
198+ /// @param type the static type of the node
199+ ///
200+ /// TODO(scheglov) this is duplication
201+ void _recordStaticType (Expression expression, DartType type) {
202+ if (_resolver.migrationResolutionHooks != null ) {
203+ // TODO(scheglov) type cannot be null
204+ type = _migrationResolutionHooks.modifyExpressionType (
205+ expression,
206+ type ?? DynamicTypeImpl .instance,
207+ );
208+ }
209+
210+ // TODO(scheglov) type cannot be null
211+ if (type == null ) {
212+ expression.staticType = DynamicTypeImpl .instance;
213+ } else {
214+ expression.staticType = type;
215+ if (_typeSystem.isBottom (type)) {
216+ _flowAnalysis? .flow? .handleExit ();
217+ }
218+ }
219+ }
220+
183221 void _resolve1 (AssignmentExpressionImpl node) {
184222 Token operator = node.operator ;
185223 TokenType operatorType = operator .type;
@@ -290,6 +328,47 @@ class AssignmentExpressionResolver {
290328 _resolver.nullShortingTermination (node);
291329 }
292330
331+ void _resolve_SimpleIdentifier_LocalVariable (
332+ AssignmentExpressionImpl node,
333+ SimpleIdentifier left,
334+ VariableElement leftElement,
335+ Expression right,
336+ ) {
337+ left.staticElement = leftElement;
338+
339+ var leftType = _resolver.localVariableTypeProvider.getType (left);
340+ // TODO(scheglov) Set the type only when `operator != TokenType.EQ`.
341+ _recordStaticType (left, leftType);
342+
343+ var operator = node.operator .type;
344+ if (operator != TokenType .EQ ) {
345+ _resolver.checkReadOfNotAssignedLocalVariable (left);
346+ }
347+
348+ if (operator == TokenType .EQ ||
349+ operator == TokenType .QUESTION_QUESTION_EQ ) {
350+ InferenceContext .setType (right, leftType);
351+ }
352+
353+ var flow = _flowAnalysis? .flow;
354+ if (flow != null && operator == TokenType .QUESTION_QUESTION_EQ ) {
355+ flow.ifNullExpression_rightBegin (left);
356+ }
357+
358+ right? .accept (_resolver);
359+ right = node.rightHandSide;
360+
361+ _resolve1 (node);
362+ _resolve2 (node);
363+
364+ if (flow != null ) {
365+ flow.write (leftElement, node.staticType);
366+ if (node.operator .type == TokenType .QUESTION_QUESTION_EQ ) {
367+ flow.ifNullExpression_end ();
368+ }
369+ }
370+ }
371+
293372 /// If the given [type] is a type parameter, resolve it to the type that
294373 /// should be used when looking up members. Otherwise, return the original
295374 /// type.
0 commit comments