Version 2.10.0-33.0.dev

Merge commit '87027c97a12a9926c2af8770a3d2a5cebc1767f3' into 'dev'
diff --git a/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
index e558b4d..dcfb6a0 100644
--- a/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
@@ -18,6 +18,7 @@
 import 'package:analyzer/src/dart/resolver/type_property_resolver.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/error/nullable_dereference_verifier.dart';
+import 'package:analyzer/src/generated/migration.dart';
 import 'package:analyzer/src/generated/resolver.dart';
 import 'package:analyzer/src/task/strong/checker.dart';
 import 'package:meta/meta.dart';
@@ -46,6 +47,10 @@
 
   bool get _isNonNullableByDefault => _typeSystem.isNonNullableByDefault;
 
+  MigrationResolutionHooks get _migrationResolutionHooks {
+    return _resolver.migrationResolutionHooks;
+  }
+
   NullableDereferenceVerifier get _nullableDereferenceVerifier =>
       _resolver.nullableDereferenceVerifier;
 
@@ -57,10 +62,22 @@
     var left = node.leftHandSide;
     var right = node.rightHandSide;
 
+    // Case `id = e`.
+    // Consider an assignment of the form `id = e`, where `id` is an identifier.
+    if (left is SimpleIdentifier) {
+      var leftLookup = _resolver.nameScope.lookup2(left.name);
+      // When the lexical lookup yields a local variable `v`.
+      var leftGetter = leftLookup.getter;
+      if (leftGetter is VariableElement) {
+        _resolve_SimpleIdentifier_LocalVariable(node, left, leftGetter, right);
+        return;
+      }
+    }
+
     left?.accept(_resolver);
     left = node.leftHandSide;
 
-    var leftLocalVariable = _flowAnalysis?.assignmentExpression(node);
+    _flowAnalysis?.assignmentExpression(node);
 
     TokenType operator = node.operator.type;
     if (operator == TokenType.EQ ||
@@ -76,12 +93,7 @@
     _resolve1(node);
     _resolve2(node);
 
-    _flowAnalysis?.assignmentExpression_afterRight(
-        node,
-        leftLocalVariable,
-        operator == TokenType.QUESTION_QUESTION_EQ
-            ? node.rightHandSide.staticType
-            : node.staticType);
+    _flowAnalysis?.assignmentExpression_afterRight(node);
   }
 
   /// Set the static type of [node] to be the least upper bound of the static
@@ -180,6 +192,32 @@
     return type;
   }
 
+  /// Record that the static type of the given node is the given type.
+  ///
+  /// @param expression the node whose type is to be recorded
+  /// @param type the static type of the node
+  ///
+  /// TODO(scheglov) this is duplication
+  void _recordStaticType(Expression expression, DartType type) {
+    if (_resolver.migrationResolutionHooks != null) {
+      // TODO(scheglov) type cannot be null
+      type = _migrationResolutionHooks.modifyExpressionType(
+        expression,
+        type ?? DynamicTypeImpl.instance,
+      );
+    }
+
+    // TODO(scheglov) type cannot be null
+    if (type == null) {
+      expression.staticType = DynamicTypeImpl.instance;
+    } else {
+      expression.staticType = type;
+      if (_typeSystem.isBottom(type)) {
+        _flowAnalysis?.flow?.handleExit();
+      }
+    }
+  }
+
   void _resolve1(AssignmentExpressionImpl node) {
     Token operator = node.operator;
     TokenType operatorType = operator.type;
@@ -290,6 +328,47 @@
     _resolver.nullShortingTermination(node);
   }
 
+  void _resolve_SimpleIdentifier_LocalVariable(
+    AssignmentExpressionImpl node,
+    SimpleIdentifier left,
+    VariableElement leftElement,
+    Expression right,
+  ) {
+    left.staticElement = leftElement;
+
+    var leftType = _resolver.localVariableTypeProvider.getType(left);
+    // TODO(scheglov) Set the type only when `operator != TokenType.EQ`.
+    _recordStaticType(left, leftType);
+
+    var operator = node.operator.type;
+    if (operator != TokenType.EQ) {
+      _resolver.checkReadOfNotAssignedLocalVariable(left);
+    }
+
+    if (operator == TokenType.EQ ||
+        operator == TokenType.QUESTION_QUESTION_EQ) {
+      InferenceContext.setType(right, leftType);
+    }
+
+    var flow = _flowAnalysis?.flow;
+    if (flow != null && operator == TokenType.QUESTION_QUESTION_EQ) {
+      flow.ifNullExpression_rightBegin(left);
+    }
+
+    right?.accept(_resolver);
+    right = node.rightHandSide;
+
+    _resolve1(node);
+    _resolve2(node);
+
+    if (flow != null) {
+      flow.write(leftElement, node.staticType);
+      if (node.operator.type == TokenType.QUESTION_QUESTION_EQ) {
+        flow.ifNullExpression_end();
+      }
+    }
+  }
+
   /// If the given [type] is a type parameter, resolve it to the type that
   /// should be used when looking up members. Otherwise, return the original
   /// type.
diff --git a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
index f6fe441..96dff00 100644
--- a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
@@ -77,30 +77,16 @@
     flow.asExpression_end(expression, typeAnnotation.type);
   }
 
-  VariableElement assignmentExpression(AssignmentExpression node) {
+  void assignmentExpression(AssignmentExpression node) {
     if (flow == null) return null;
 
     if (node.operator.type == TokenType.QUESTION_QUESTION_EQ) {
       flow.ifNullExpression_rightBegin(node.leftHandSide);
     }
-
-    var left = node.leftHandSide;
-
-    if (left is SimpleIdentifier) {
-      var element = left.staticElement;
-      if (element is VariableElement) {
-        return element;
-      }
-    }
-
-    return null;
   }
 
-  void assignmentExpression_afterRight(AssignmentExpression node,
-      VariableElement localElement, DartType writtenType) {
-    if (localElement != null) {
-      flow.write(localElement, writtenType);
-    }
+  void assignmentExpression_afterRight(AssignmentExpression node) {
+    if (flow == null) return null;
 
     if (node.operator.type == TokenType.QUESTION_QUESTION_EQ) {
       flow.ifNullExpression_end();
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 8bba9a1..add5879 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -153,6 +153,8 @@
 
   final MigratableAstInfoProvider _migratableAstInfoProvider;
 
+  final MigrationResolutionHooks migrationResolutionHooks;
+
   /// Helper for checking expression that should have the `bool` type.
   BoolExpressionVerifier boolExpressionVerifier;
 
@@ -290,6 +292,7 @@
       this._migratableAstInfoProvider,
       MigrationResolutionHooks migrationResolutionHooks)
       : _featureSet = featureSet,
+        migrationResolutionHooks = migrationResolutionHooks,
         super(definingLibrary, source, typeProvider, errorListener,
             nameScope: nameScope) {
     _promoteManager = TypePromotionManager(typeSystem);
@@ -429,6 +432,26 @@
     }
   }
 
+  void checkReadOfNotAssignedLocalVariable(SimpleIdentifier node) {
+    if (_flowAnalysis != null) {
+      if (_flowAnalysis.isPotentiallyNonNullableLocalReadBeforeWrite(node)) {
+        errorReporter.reportErrorForNode(
+          CompileTimeErrorCode
+              .NOT_ASSIGNED_POTENTIALLY_NON_NULLABLE_LOCAL_VARIABLE,
+          node,
+          [node.name],
+        );
+      }
+      if (_flowAnalysis.isReadOfDefinitelyUnassignedLateLocal(node)) {
+        errorReporter.reportErrorForNode(
+          CompileTimeErrorCode.DEFINITELY_UNASSIGNED_LATE_LOCAL_VARIABLE,
+          node,
+          [node.name],
+        );
+      }
+    }
+  }
+
   void checkUnreachableNode(AstNode node) {
     nullSafetyDeadCodeVerifier.visitNode(node);
   }
@@ -1533,23 +1556,7 @@
       return;
     }
 
-    if (_flowAnalysis != null) {
-      if (_flowAnalysis.isPotentiallyNonNullableLocalReadBeforeWrite(node)) {
-        errorReporter.reportErrorForNode(
-          CompileTimeErrorCode
-              .NOT_ASSIGNED_POTENTIALLY_NON_NULLABLE_LOCAL_VARIABLE,
-          node,
-          [node.name],
-        );
-      }
-      if (_flowAnalysis.isReadOfDefinitelyUnassignedLateLocal(node)) {
-        errorReporter.reportErrorForNode(
-          CompileTimeErrorCode.DEFINITELY_UNASSIGNED_LATE_LOCAL_VARIABLE,
-          node,
-          [node.name],
-        );
-      }
-    }
+    checkReadOfNotAssignedLocalVariable(node);
 
     super.visitSimpleIdentifier(node);
   }
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index 4c605a3..2ccef51 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -102,14 +102,20 @@
   ///
   /// @param expression the node whose type is to be recorded
   /// @param type the static type of the node
+  ///
+  /// TODO(scheglov) this is duplication
   void recordStaticType(Expression expression, DartType type) {
     if (_migrationResolutionHooks != null) {
+      // TODO(scheglov) type cannot be null
       type = _migrationResolutionHooks.modifyExpressionType(
-          expression, type ?? _dynamicType);
+        expression,
+        type ?? DynamicTypeImpl.instance,
+      );
     }
 
+    // TODO(scheglov) type cannot be null
     if (type == null) {
-      expression.staticType = _dynamicType;
+      expression.staticType = DynamicTypeImpl.instance;
     } else {
       expression.staticType = type;
       if (_typeSystem.isBottom(type)) {
diff --git a/pkg/analyzer/test/src/dart/resolution/assignment_test.dart b/pkg/analyzer/test/src/dart/resolution/assignment_test.dart
index 2761663..7ce888a 100644
--- a/pkg/analyzer/test/src/dart/resolution/assignment_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/assignment_test.dart
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/dart/error/syntactic_errors.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -50,34 +50,6 @@
     assertType(right, 'int');
   }
 
-  test_compound_local() async {
-    await resolveTestCode(r'''
-main() {
-  num v = 0;
-  v += 3;
-}
-''');
-    var assignment = findNode.assignment('v += 3');
-    assertElement(
-      assignment,
-      elementMatcher(
-        numElement.getMethod('+'),
-        isLegacy: isNullSafetySdkAndLegacyLibrary,
-      ),
-    );
-    assertType(assignment, 'num'); // num + int = num
-
-    assertSimpleIdentifier(
-      assignment.leftHandSide,
-      readElement: findElement.localVar('v'),
-      writeElement: findElement.localVar('v'),
-      type: 'num',
-    );
-
-    Expression right = assignment.rightHandSide;
-    assertType(right, 'int');
-  }
-
   test_compound_prefixedIdentifier() async {
     await resolveTestCode(r'''
 main() {
@@ -147,80 +119,6 @@
     assertType(right, 'int');
   }
 
-  test_compound_refineType_int_double() async {
-    await assertErrorsInCode(r'''
-main(int i) {
-  i += 1.2;
-  i -= 1.2;
-  i *= 1.2;
-  i %= 1.2;
-}
-''', [
-      error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 21, 3),
-      error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 33, 3),
-      error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 45, 3),
-      error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 57, 3),
-    ]);
-    assertType(findNode.assignment('+='), 'double');
-    assertType(findNode.assignment('-='), 'double');
-    assertType(findNode.assignment('*='), 'double');
-    assertType(findNode.assignment('%='), 'double');
-  }
-
-  test_compound_refineType_int_int() async {
-    await assertNoErrorsInCode(r'''
-main(int i) {
-  i += 1;
-  i -= 1;
-  i *= 1;
-  i ~/= 1;
-  i %= 1;
-}
-''');
-    assertType(findNode.assignment('+='), 'int');
-    assertType(findNode.assignment('-='), 'int');
-    assertType(findNode.assignment('*='), 'int');
-    assertType(findNode.assignment('~/='), 'int');
-    assertType(findNode.assignment('%='), 'int');
-  }
-
-  test_compoundIfNull_differentTypes() async {
-    await assertErrorsInCode(r'''
-main(double a, int b) {
-  a ??= b;
-}
-''', [
-      error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 32, 1),
-    ]);
-    assertType(findNode.assignment('??='), 'num');
-  }
-
-  test_compoundIfNull_sameTypes() async {
-    await assertNoErrorsInCode(r'''
-main(int a) {
-  a ??= 0;
-}
-''');
-    assertType(findNode.assignment('??='), 'int');
-  }
-
-  test_in_const_context() async {
-    await resolveTestCode('''
-void f(num x, int y) {
-  const [x = y];
-}
-''');
-    expect(result.errors, isNotEmpty);
-
-    var xRef = findNode.simple('x =');
-    assertElement(xRef, findElement.parameter('x'));
-    assertType(xRef, 'num');
-
-    var yRef = findNode.simple('y]');
-    assertElement(yRef, findElement.parameter('y'));
-    assertType(yRef, 'int');
-  }
-
   test_indexExpression_cascade() async {
     await resolveTestCode(r'''
 main() {
@@ -270,25 +168,6 @@
     assertType(assignment, 'double');
   }
 
-  test_nullAware_local() async {
-    await resolveTestCode(r'''
-main() {
-  String v;
-  v ??= 'test';
-}
-''');
-    var assignment = findNode.assignment('v ??=');
-    assertElementNull(assignment);
-    assertType(assignment, 'String');
-
-    SimpleIdentifier left = assignment.leftHandSide;
-    assertElement(left, findElement.localVar('v'));
-    assertType(left, 'String');
-
-    Expression right = assignment.rightHandSide;
-    assertType(right, 'String');
-  }
-
   test_propertyAccess_forwardingStub() async {
     await resolveTestCode(r'''
 class A {
@@ -347,49 +226,6 @@
     assertType(right, 'int');
   }
 
-  test_simple_instanceField_unqualified() async {
-    await resolveTestCode(r'''
-class C {
-  num f = 0;
-  foo() {
-    f = 2;
-  }
-}
-''');
-    var assignment = findNode.assignment('f = 2;');
-    assertElementNull(assignment);
-    assertType(assignment, 'int');
-
-    SimpleIdentifier left = assignment.leftHandSide;
-    assertElement(left, findElement.setter('f'));
-    assertType(left, 'num');
-
-    Expression right = assignment.rightHandSide;
-    assertType(right, 'int');
-  }
-
-  test_simple_local() async {
-    await resolveTestCode(r'''
-main() {
-  num v = 0;
-  v = 2;
-}
-''');
-    var assignment = findNode.assignment('v = 2;');
-    assertElementNull(assignment);
-    assertType(assignment, 'int');
-
-    assertSimpleIdentifier(
-      assignment.leftHandSide,
-      readElement: null,
-      writeElement: findElement.localVar('v'),
-      type: 'num',
-    );
-
-    Expression right = assignment.rightHandSide;
-    assertType(right, 'int');
-  }
-
   test_simple_prefixedIdentifier() async {
     await resolveTestCode(r'''
 main() {
@@ -543,68 +379,628 @@
     assertType(right, 'int');
   }
 
-  test_simple_staticField_unqualified() async {
-    await resolveTestCode(r'''
-class C {
-  static num f = 0;
-  foo() {
-    f = 2;
-  }
-}
-''');
-    var assignment = findNode.assignment('f = 2');
-    assertElementNull(assignment);
-    assertType(assignment, 'int');
-
-    assertSimpleIdentifier(
-      assignment.leftHandSide,
-      readElement: null,
-      writeElement: findElement.setter('f'),
-      type: 'num',
-    );
-
-    var right = assignment.rightHandSide;
-    assertType(right, 'int');
-  }
-
-  test_simple_topLevelVariable() async {
-    await resolveTestCode(r'''
-main() {
-  v = 2;
-}
-num v = 0;
-''');
-    var assignment = findNode.assignment('v = 2');
-    assertElementNull(assignment);
-    assertType(assignment, 'int');
-
-    assertSimpleIdentifier(
-      assignment.leftHandSide,
-      readElement: null,
-      writeElement: findElement.topSet('v'),
-      type: 'num',
-    );
-
-    var right = assignment.rightHandSide;
-    assertType(right, 'int');
-  }
-
-  test_to_class() async {
-    await resolveTestCode('''
+  test_simpleIdentifier_class_simple() async {
+    await assertErrorsInCode('''
 class C {}
-void f(int x) {
-  C = x;
+
+void f() {
+  C = 0;
+}
+''', [
+      error(CompileTimeErrorCode.ASSIGNMENT_TO_TYPE, 25, 1),
+      error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 29, 1),
+    ]);
+
+    var assignment = findNode.assignment('C = 0');
+    assertAssignment(
+      assignment,
+      operatorElement: null,
+      type: 'int',
+    );
+
+    assertSimpleIdentifier(
+      assignment.leftHandSide,
+      readElement: null,
+      writeElement: findElement.class_('C'),
+      type: null,
+    );
+
+    assertType(assignment.rightHandSide, 'int');
+  }
+
+  test_simpleIdentifier_fieldInstance_simple() async {
+    await assertNoErrorsInCode(r'''
+class C {
+  num x = 0;
+
+  void f() {
+    x = 2;
+  }
 }
 ''');
-    expect(result.errors, isNotEmpty);
 
-    var cRef = findNode.simple('C =');
-    assertElement(cRef, findElement.class_('C'));
-    assertType(cRef, 'Type');
+    var assignment = findNode.assignment('x = 2');
+    assertAssignment(
+      assignment,
+      operatorElement: null,
+      type: 'int',
+    );
 
-    var xRef = findNode.simple('x;');
-    assertElement(xRef, findElement.parameter('x'));
-    assertType(xRef, 'int');
+    assertSimpleIdentifier(
+      assignment.leftHandSide,
+      readElement: null,
+      writeElement: findElement.setter('x'),
+      type: null,
+    );
+
+    assertType(assignment.rightHandSide, 'int');
+  }
+
+  test_simpleIdentifier_fieldStatic_simple() async {
+    await assertNoErrorsInCode(r'''
+class C {
+  static num x = 0;
+
+  void f() {
+    x = 2;
+  }
+}
+''');
+
+    var assignment = findNode.assignment('x = 2');
+    assertAssignment(
+      assignment,
+      operatorElement: null,
+      type: 'int',
+    );
+
+    assertSimpleIdentifier(
+      assignment.leftHandSide,
+      readElement: null,
+      writeElement: findElement.setter('x'),
+      type: null,
+    );
+
+    assertType(assignment.rightHandSide, 'int');
+  }
+
+  test_simpleIdentifier_getterInstance_simple() async {
+    await assertErrorsInCode('''
+class C {
+  num get x => 0;
+
+  void f() {
+    x = 2;
+  }
+}
+''', [
+      error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_NO_SETTER, 46, 1),
+    ]);
+
+    var assignment = findNode.assignment('x = 2');
+    assertAssignment(
+      assignment,
+      operatorElement: null,
+      type: 'int',
+    );
+
+    assertSimpleIdentifier(
+      assignment.leftHandSide,
+      readElement: null,
+      writeElement: findElement.getter('x'),
+      type: null,
+    );
+
+    assertType(assignment.rightHandSide, 'int');
+  }
+
+  test_simpleIdentifier_getterStatic_simple() async {
+    await assertErrorsInCode('''
+class C {
+  static num get x => 0;
+
+  void f() {
+    x = 2;
+  }
+}
+''', [
+      error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_NO_SETTER, 53, 1),
+    ]);
+
+    var assignment = findNode.assignment('x = 2');
+    assertAssignment(
+      assignment,
+      operatorElement: null,
+      type: 'int',
+    );
+
+    assertSimpleIdentifier(
+      assignment.leftHandSide,
+      readElement: null,
+      writeElement: findElement.getter('x'),
+      type: null,
+    );
+
+    assertType(assignment.rightHandSide, 'int');
+  }
+
+  test_simpleIdentifier_getterTopLevel_simple() async {
+    await assertErrorsInCode('''
+int get x => 0;
+
+void f() {
+  x = 2;
+}
+''', [
+      error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_LOCAL, 30, 1),
+    ]);
+
+    var assignment = findNode.assignment('x = 2');
+    assertAssignment(
+      assignment,
+      operatorElement: null,
+      type: 'int',
+    );
+
+    assertSimpleIdentifier(
+      assignment.leftHandSide,
+      readElement: null,
+      writeElement: findElement.topGet('x'),
+      type: null,
+    );
+
+    assertType(assignment.rightHandSide, 'int');
+  }
+
+  test_simpleIdentifier_importPrefix_simple() async {
+    await assertErrorsInCode('''
+import 'dart:math' as x;
+
+main() {
+  x = 2;
+}
+''', [
+      error(CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT, 37, 1),
+    ]);
+
+    var assignment = findNode.assignment('x = 2');
+    assertAssignment(
+      assignment,
+      operatorElement: null,
+      type: 'int',
+    );
+
+    assertSimpleIdentifier(
+      assignment.leftHandSide,
+      readElement: null,
+      writeElement: findElement.prefix('x'),
+      type: null,
+    );
+
+    assertType(assignment.rightHandSide, 'int');
+  }
+
+  test_simpleIdentifier_localVariable_compound() async {
+    await assertNoErrorsInCode(r'''
+void f() {
+  // ignore:unused_local_variable
+  num x = 0;
+  x += 3;
+}
+''');
+
+    var assignment = findNode.assignment('x += 3');
+    assertAssignment(
+      assignment,
+      operatorElement: elementMatcher(
+        numElement.getMethod('+'),
+        isLegacy: isNullSafetySdkAndLegacyLibrary,
+      ),
+      type: 'num', // num + int = num
+    );
+
+    assertSimpleIdentifier(
+      assignment.leftHandSide,
+      readElement: findElement.localVar('x'),
+      writeElement: findElement.localVar('x'),
+      type: 'num',
+    );
+
+    assertType(assignment.rightHandSide, 'int');
+  }
+
+  test_simpleIdentifier_localVariable_simple() async {
+    await assertNoErrorsInCode(r'''
+void f() {
+  // ignore:unused_local_variable
+  num x = 0;
+  x = 2;
+}
+''');
+
+    var assignment = findNode.assignment('x = 2');
+    assertAssignment(
+      assignment,
+      operatorElement: null,
+      type: 'int',
+    );
+
+    assertSimpleIdentifier(
+      assignment.leftHandSide,
+      readElement: null,
+      writeElement: findElement.localVar('x'),
+      type: 'num',
+    );
+
+    assertType(assignment.rightHandSide, 'int');
+  }
+
+  test_simpleIdentifier_localVariableConst_simple() async {
+    await assertErrorsInCode('''
+void f() {
+  // ignore:unused_local_variable
+  const num x = 1;
+  x = 2;
+}
+''', [
+      error(CompileTimeErrorCode.ASSIGNMENT_TO_CONST, 66, 1),
+    ]);
+
+    var assignment = findNode.assignment('x = 2');
+    assertAssignment(
+      assignment,
+      operatorElement: null,
+      type: 'int',
+    );
+
+    assertSimpleIdentifier(
+      assignment.leftHandSide,
+      readElement: null,
+      writeElement: findElement.localVar('x'),
+      type: null,
+    );
+
+    assertType(assignment.rightHandSide, 'int');
+  }
+
+  test_simpleIdentifier_localVariableFinal_simple() async {
+    await assertErrorsInCode('''
+void f() {
+  // ignore:unused_local_variable
+  final num x = 1;
+  x = 2;
+}
+''', [
+      error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_LOCAL, 66, 1),
+    ]);
+
+    var assignment = findNode.assignment('x = 2');
+    assertAssignment(
+      assignment,
+      operatorElement: null,
+      type: 'int',
+    );
+
+    assertSimpleIdentifier(
+      assignment.leftHandSide,
+      readElement: null,
+      writeElement: findElement.localVar('x'),
+      type: null,
+    );
+
+    assertType(assignment.rightHandSide, 'int');
+  }
+
+  test_simpleIdentifier_parameter_compound_ifNull() async {
+    await assertNoErrorsInCode(r'''
+void f(num x) {
+  x ??= 0;
+}
+''');
+
+    var assignment = findNode.assignment('x ??=');
+    assertAssignment(
+      assignment,
+      operatorElement: null,
+      type: 'num',
+    );
+
+    assertSimpleIdentifier(
+      assignment.leftHandSide,
+      readElement: findElement.parameter('x'),
+      writeElement: findElement.parameter('x'),
+      type: 'num',
+    );
+
+    assertType(assignment.rightHandSide, 'int');
+  }
+
+  test_simpleIdentifier_parameter_compound_ifNull_notAssignableType() async {
+    await assertErrorsInCode(r'''
+void f(double a, int b) {
+  a ??= b;
+}
+''', [
+      error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 34, 1),
+    ]);
+
+    var assignment = findNode.assignment('a ??=');
+    assertAssignment(
+      assignment,
+      operatorElement: null,
+      type: 'num',
+    );
+
+    assertSimpleIdentifier(
+      assignment.leftHandSide,
+      readElement: findElement.parameter('a'),
+      writeElement: findElement.parameter('a'),
+      type: 'double',
+    );
+
+    assertSimpleIdentifier(
+      assignment.rightHandSide,
+      readElement: findElement.parameter('b'),
+      writeElement: null,
+      type: 'int',
+    );
+  }
+
+  test_simpleIdentifier_parameter_compound_refineType_int_double() async {
+    await assertErrorsInCode(r'''
+void f(int x) {
+  x += 1.2;
+  x -= 1.2;
+  x *= 1.2;
+  x %= 1.2;
+}
+''', [
+      error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 23, 3),
+      error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 35, 3),
+      error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 47, 3),
+      error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 59, 3),
+    ]);
+    assertType(findNode.assignment('+='), 'double');
+    assertType(findNode.assignment('-='), 'double');
+    assertType(findNode.assignment('*='), 'double');
+    assertType(findNode.assignment('%='), 'double');
+  }
+
+  test_simpleIdentifier_parameter_compound_refineType_int_int() async {
+    await assertNoErrorsInCode(r'''
+main(int x) {
+  x += 1;
+  x -= 1;
+  x *= 1;
+  x ~/= 1;
+  x %= 1;
+}
+''');
+    assertType(findNode.assignment('+='), 'int');
+    assertType(findNode.assignment('-='), 'int');
+    assertType(findNode.assignment('*='), 'int');
+    assertType(findNode.assignment('~/='), 'int');
+    assertType(findNode.assignment('%='), 'int');
+  }
+
+  test_simpleIdentifier_parameter_simple() async {
+    await assertNoErrorsInCode(r'''
+void f(num x) {
+  x = 2;
+}
+''');
+
+    var assignment = findNode.assignment('x = 2');
+    assertAssignment(
+      assignment,
+      operatorElement: null,
+      type: 'int',
+    );
+
+    assertSimpleIdentifier(
+      assignment.leftHandSide,
+      readElement: null,
+      writeElement: findElement.parameter('x'),
+      type: null,
+    );
+
+    assertType(assignment.rightHandSide, 'int');
+  }
+
+  test_simpleIdentifier_parameter_simple_notAssignableType() async {
+    await assertErrorsInCode(r'''
+void f(int x) {
+  x = true;
+}
+''', [
+      error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 22, 4),
+    ]);
+
+    var assignment = findNode.assignment('x = true');
+    assertAssignment(
+      assignment,
+      operatorElement: null,
+      type: 'bool',
+    );
+
+    assertSimpleIdentifier(
+      assignment.leftHandSide,
+      readElement: null,
+      writeElement: findElement.parameter('x'),
+      type: null,
+    );
+
+    assertType(assignment.rightHandSide, 'bool');
+  }
+
+  test_simpleIdentifier_parameterFinal_simple() async {
+    await assertErrorsInCode('''
+void f(final int x) {
+  x = 2;
+}
+''', [
+      error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_LOCAL, 24, 1),
+    ]);
+
+    var assignment = findNode.assignment('x = 2');
+    assertAssignment(
+      assignment,
+      operatorElement: null,
+      type: 'int',
+    );
+
+    assertSimpleIdentifier(
+      assignment.leftHandSide,
+      readElement: null,
+      writeElement: findElement.parameter('x'),
+      type: null,
+    );
+
+    assertType(assignment.rightHandSide, 'int');
+  }
+
+  test_simpleIdentifier_synthetic_simple() async {
+    await assertErrorsInCode('''
+void f(int y) {
+  = y;
+}
+''', [
+      error(ParserErrorCode.MISSING_IDENTIFIER, 18, 1),
+    ]);
+
+    var assignment = findNode.assignment('= y');
+    assertAssignment(
+      assignment,
+      operatorElement: null,
+      type: 'int',
+    );
+
+    assertSimpleIdentifier(
+      assignment.leftHandSide,
+      readElement: null,
+      writeElement: null,
+      type: 'dynamic',
+    );
+
+    assertSimpleIdentifier(
+      assignment.rightHandSide,
+      readElement: findElement.parameter('y'),
+      writeElement: null,
+      type: 'int',
+    );
+  }
+
+  test_simpleIdentifier_topLevelVariable_simple() async {
+    await assertNoErrorsInCode(r'''
+num x = 0;
+
+void f() {
+  x = 2;
+}
+''');
+
+    var assignment = findNode.assignment('x = 2');
+    assertAssignment(
+      assignment,
+      operatorElement: null,
+      type: 'int',
+    );
+
+    assertSimpleIdentifier(
+      assignment.leftHandSide,
+      readElement: null,
+      writeElement: findElement.topSet('x'),
+      type: null,
+    );
+
+    assertType(assignment.rightHandSide, 'int');
+  }
+
+  test_simpleIdentifier_topLevelVariable_simple_notAssignableType() async {
+    await assertErrorsInCode(r'''
+int x = 0;
+
+void f() {
+  x = true;
+}
+''', [
+      error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 29, 4),
+    ]);
+
+    var assignment = findNode.assignment('x = true');
+    assertAssignment(
+      assignment,
+      operatorElement: null,
+      type: 'bool',
+    );
+
+    assertSimpleIdentifier(
+      assignment.leftHandSide,
+      readElement: null,
+      writeElement: findElement.topSet('x'),
+      type: null,
+    );
+
+    assertType(assignment.rightHandSide, 'bool');
+  }
+
+  test_simpleIdentifier_topLevelVariableFinal_simple() async {
+    await assertErrorsInCode(r'''
+final num x = 0;
+
+void f() {
+  x = 2;
+}
+''', [
+      error(CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_LOCAL, 31, 1),
+    ]);
+
+    var assignment = findNode.assignment('x = 2');
+    assertAssignment(
+      assignment,
+      operatorElement: null,
+      type: 'int',
+    );
+
+    assertSimpleIdentifier(
+      assignment.leftHandSide,
+      readElement: null,
+      writeElement: findElement.topGet('x'),
+      type: null,
+    );
+
+    assertType(assignment.rightHandSide, 'int');
+  }
+
+  test_simpleIdentifier_unresolved_simple() async {
+    await assertErrorsInCode(r'''
+void f(int a) {
+  x = a;
+}
+''', [
+      error(CompileTimeErrorCode.UNDEFINED_IDENTIFIER, 18, 1),
+    ]);
+
+    var assignment = findNode.assignment('x = a');
+    assertAssignment(
+      assignment,
+      operatorElement: null,
+      type: 'int',
+    );
+
+    assertSimpleIdentifier(
+      assignment.leftHandSide,
+      readElement: null,
+      writeElement: null,
+      type: null,
+    );
+
+    assertSimpleIdentifier(
+      assignment.rightHandSide,
+      readElement: findElement.parameter('a'),
+      writeElement: null,
+      type: 'int',
+    );
   }
 
   test_to_class_ambiguous() async {
@@ -624,33 +1020,6 @@
     assertType(xRef, 'int');
   }
 
-  test_to_final_parameter() async {
-    await resolveTestCode('''
-f(final int x) {
-  x += 2;
-}
-''');
-    expect(result.errors, isNotEmpty);
-
-    var xRef = findNode.simple('x +=');
-    assertElement(xRef, findElement.parameter('x'));
-    assertType(xRef, 'int');
-  }
-
-  test_to_final_variable_local() async {
-    await resolveTestCode('''
-main() {
-  final x = 1;
-  x += 2;
-}
-''');
-    expect(result.errors, isNotEmpty);
-
-    var xRef = findNode.simple('x +=');
-    assertElement(xRef, findElement.localVar('x'));
-    assertType(xRef, 'int');
-  }
-
   test_to_getter_instance_direct() async {
     await resolveTestCode('''
 class C {
@@ -667,22 +1036,6 @@
     assertType(xRef, 'int');
   }
 
-  test_to_getter_instance_via_implicit_this() async {
-    await resolveTestCode('''
-class C {
-  int get x => 0;
-  f() {
-    x += 2;
-  }
-}
-''');
-    expect(result.errors, isNotEmpty);
-
-    var xRef = findNode.simple('x +=');
-    assertElement(xRef, findElement.getter('x'));
-    assertType(xRef, 'int');
-  }
-
   test_to_getter_static_direct() async {
     await resolveTestCode('''
 class C {
@@ -699,36 +1052,6 @@
     assertType(xRef, 'int');
   }
 
-  test_to_getter_static_via_scope() async {
-    await resolveTestCode('''
-class C {
-  static int get x => 0;
-  f() {
-    x += 2;
-  }
-}
-''');
-    expect(result.errors, isNotEmpty);
-
-    var xRef = findNode.simple('x +=');
-    assertElement(xRef, findElement.getter('x'));
-    assertType(xRef, 'int');
-  }
-
-  test_to_getter_top_level() async {
-    await resolveTestCode('''
-int get x => 0;
-main() {
-  x += 2;
-}
-''');
-    expect(result.errors, isNotEmpty);
-
-    var xRef = findNode.simple('x +=');
-    assertElement(xRef, findElement.topGet('x'));
-    assertType(xRef, 'int');
-  }
-
   test_to_non_lvalue() async {
     await resolveTestCode('''
 void f(int x, double y, String z) {
@@ -801,23 +1124,6 @@
     assertType(yRef, 'int');
   }
 
-  test_to_prefix() async {
-    newFile('/test/lib/a.dart', content: '''
-var x = 0;
-''');
-    await resolveTestCode('''
-import 'a.dart' as p;
-main() {
-  p += 2;
-}
-''');
-    expect(result.errors, isNotEmpty);
-
-    var pRef = findNode.simple('p +=');
-    assertElement(pRef, findElement.prefix('p'));
-    assertTypeDynamic(pRef);
-  }
-
   test_to_prefix_increment() async {
     await resolveTestCode('''
 void f(num x, int y) {
@@ -869,60 +1175,6 @@
     assertType(yRef, 'int');
   }
 
-  test_types_local() async {
-    await resolveTestCode(r'''
-int a;
-bool b;
-main() {
-  a = b;
-}
-''');
-    expect(result.errors, isNotEmpty);
-
-    var assignment = findNode.assignment('a = b');
-    assertElementNull(assignment);
-    assertType(assignment, 'bool');
-
-    assertIdentifierTopSetRef(assignment.leftHandSide, 'a');
-    assertIdentifierTopGetRef(assignment.rightHandSide, 'b');
-  }
-
-  test_types_top() async {
-    await resolveTestCode(r'''
-int a = 0;
-bool b = a;
-''');
-    expect(result.errors, isNotEmpty);
-
-    var bDeclaration = findNode.variableDeclaration('b =');
-    TopLevelVariableElement bElement = bDeclaration.declaredElement;
-    assertElement(bDeclaration.name, findElement.topVar('b'));
-    assertTypeNull(bDeclaration.name);
-    assertType(bElement.type, 'bool');
-
-    SimpleIdentifier aRef = bDeclaration.initializer;
-    assertElement(aRef, findElement.topGet('a'));
-    assertType(aRef, 'int');
-  }
-
-  test_types_top_const() async {
-    await resolveTestCode(r'''
-const int a = 0;
-const bool b = a;
-''');
-    expect(result.errors, isNotEmpty);
-
-    var bDeclaration = findNode.variableDeclaration('b =');
-    TopLevelVariableElement bElement = bDeclaration.declaredElement;
-    assertElement(bDeclaration.name, bElement);
-    assertTypeNull(bDeclaration.name);
-    assertType(bElement.type, 'bool');
-
-    SimpleIdentifier aRef = bDeclaration.initializer;
-    assertElement(aRef, findElement.topGet('a'));
-    assertType(aRef, 'int');
-  }
-
   test_unresolved_left_identifier_compound() async {
     await resolveTestCode(r'''
 int b;
@@ -943,26 +1195,6 @@
     assertType(assignment.rightHandSide, 'int');
   }
 
-  test_unresolved_left_identifier_simple() async {
-    await resolveTestCode(r'''
-int b;
-main() {
-  a = b;
-}
-''');
-    expect(result.errors, isNotEmpty);
-
-    var assignment = findNode.assignment('a = b');
-    assertElementNull(assignment);
-    assertType(assignment, 'int');
-
-    assertElementNull(assignment.leftHandSide);
-    assertTypeDynamic(assignment.leftHandSide);
-
-    assertElement(assignment.rightHandSide, findElement.topGet('b'));
-    assertType(assignment.rightHandSide, 'int');
-  }
-
   test_unresolved_left_indexed1_simple() async {
     await resolveTestCode(r'''
 int c;
@@ -1238,32 +1470,4 @@
     assertElement(assignment.rightHandSide, findElement.topGet('d'));
     assertType(assignment.rightHandSide, 'int');
   }
-
-  test_with_synthetic_lhs() async {
-    await resolveTestCode('''
-void f(int x) {
-  = x;
-}
-''');
-    expect(result.errors, isNotEmpty);
-
-    var xRef = findNode.simple('x;');
-    assertElement(xRef, findElement.parameter('x'));
-    assertType(xRef, 'int');
-  }
-
-  test_with_synthetic_lhs_in_method() async {
-    await resolveTestCode('''
-class C {
-  void f(int x) {
-    = x;
-  }
-}
-''');
-    expect(result.errors, isNotEmpty);
-
-    var xRef = findNode.simple('x;');
-    assertElement(xRef, findElement.parameter('x'));
-    assertType(xRef, 'int');
-  }
 }
diff --git a/tools/VERSION b/tools/VERSION
index 27730e4..ce12337 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 10
 PATCH 0
-PRERELEASE 32
+PRERELEASE 33
 PRERELEASE_PATCH 0
\ No newline at end of file