Fix analyzer/FE integration of some obscure invalid assignment cases.

This CL fixes handling of the following erroneous assignments:
- Assignment to postfix increment (e.g. "x++ = y;")
- Assignment to prefix increment (e.g. "++x = y;")
- Prefix increment of postfix increment (e.g. "++x++;")

Change-Id: I651c7cbcc4b3d43f7008f9d583e2057db9bc6e6e
Reviewed-on: https://dart-review.googlesource.com/71260
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
diff --git a/pkg/analyzer/test/src/dart/analysis/driver_resolution_test.dart b/pkg/analyzer/test/src/dart/analysis/driver_resolution_test.dart
index d872324..454fd79 100644
--- a/pkg/analyzer/test/src/dart/analysis/driver_resolution_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/driver_resolution_test.dart
@@ -956,6 +956,38 @@
     assertElement(zRef, findElement.parameter('z'));
   }
 
+  test_assign_to_postfix_increment() async {
+    addTestFile('''
+void f(num x, int y) {
+  x++ = y;
+}
+''');
+    await resolveTestFile();
+
+    var xRef = findNode.simple('x++');
+    assertType(xRef, 'num');
+    assertElement(xRef, findElement.parameter('x'));
+    var yRef = findNode.simple('y;');
+    assertType(yRef, 'int');
+    assertElement(yRef, findElement.parameter('y'));
+  }
+
+  test_assign_to_prefix_increment() async {
+    addTestFile('''
+void f(num x, int y) {
+  ++x = y;
+}
+''');
+    await resolveTestFile();
+
+    var xRef = findNode.simple('x =');
+    assertType(xRef, 'num');
+    assertElement(xRef, findElement.parameter('x'));
+    var yRef = findNode.simple('y;');
+    assertType(yRef, 'int');
+    assertElement(yRef, findElement.parameter('y'));
+  }
+
   test_assign_with_synthetic_lhs() async {
     addTestFile('''
 void f(int x) {
@@ -7277,6 +7309,19 @@
     assertElement(xRef, findElement.parameter('x'));
   }
 
+  test_prefix_increment_of_postfix_increment() async {
+    addTestFile('''
+void f(int x) {
+  ++x++;
+}
+''');
+    await resolveTestFile();
+
+    var xRef = findNode.simple('x++');
+    assertType(xRef, 'int');
+    assertElement(xRef, findElement.parameter('x'));
+  }
+
   test_prefix_increment_of_prefix_increment() async {
     addTestFile('''
 void f(int x) {
diff --git a/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart b/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
index 0dfb764..477d2eb 100644
--- a/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
@@ -120,7 +120,8 @@
   ///
   /// The returned expression evaluates to the assigned value, unless
   /// [voidContext] is true, in which case it may evaluate to anything.
-  Expression buildAssignment(Expression value, {bool voidContext});
+  Expression buildAssignment(Expression value,
+      {bool voidContext, int offset: -1});
 
   /// Returns a [Expression] representing a null-aware assignment (`??=`) with
   /// the generator on the LHS and [value] on the RHS.
@@ -780,7 +781,8 @@
   }
 
   @override
-  Expression buildAssignment(Expression value, {bool voidContext: false}) {
+  Expression buildAssignment(Expression value,
+      {bool voidContext: false, int offset: -1}) {
     return new SyntheticExpressionJudgment(buildError(
         forest.arguments(<Expression>[value], token, token),
         isSetter: true));
@@ -938,8 +940,18 @@
   }
 
   @override
-  Expression buildAssignment(Expression value, {bool voidContext: false}) {
-    return makeInvalidWrite(value);
+  Expression buildAssignment(Expression value,
+      {bool voidContext: false, int offset: -1}) {
+    var lhs = buildSimpleRead();
+    // The lhs expression needs to have a parent so that type inference can be
+    // applied to it, but it doesn't matter what the parent is because the
+    // lhs expression won't appear in the tree.  So just give it a quick and
+    // dirty parent.
+    new VariableDeclaration.forValue(lhs);
+
+    return new IllegalAssignmentJudgment(value,
+        assignmentOffset: offset, desugared: makeInvalidWrite(value))
+      ..write = lhs;
   }
 
   @override
@@ -962,7 +974,18 @@
   @override
   Expression buildPrefixIncrement(Name binaryOperator,
       {int offset: -1, bool voidContext: false, Procedure interfaceTarget}) {
-    return makeInvalidWrite(null);
+    var innerExpression = buildSimpleRead();
+    // The inner expression needs to have a parent so that type inference can be
+    // applied to it, but it doesn't matter what the parent is because the
+    // inner expression won't appear in the tree.  So just give it a quick and
+    // dirty parent.
+    new VariableDeclaration.forValue(innerExpression);
+
+    return new IllegalAssignmentJudgment(
+        forest.literalInt(1, null, isSynthetic: true),
+        assignmentOffset: offset,
+        desugared: makeInvalidWrite(null))
+      ..write = innerExpression;
   }
 
   @override
@@ -1038,7 +1061,8 @@
 
   Expression makeAssignmentExpression(bool voidContext) {
     if (identical("=", assignmentOperator)) {
-      return generator.buildAssignment(value, voidContext: voidContext);
+      return generator.buildAssignment(value,
+          voidContext: voidContext, offset: token.offset);
     } else if (identical("+=", assignmentOperator)) {
       return generator.buildCompoundAssignment(plusName, value,
           offset: offsetForToken(token), voidContext: voidContext);
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_expression_generator.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_expression_generator.dart
index fe7cb08..9927ce07 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_expression_generator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_expression_generator.dart
@@ -142,7 +142,8 @@
   }
 
   @override
-  Expression buildAssignment(Expression value, {bool voidContext: false}) {
+  Expression buildAssignment(Expression value,
+      {bool voidContext: false, int offset: -1}) {
     var complexAssignment = startComplexAssignment(value);
     return _finish(_makeSimpleWrite(value, voidContext, complexAssignment),
         complexAssignment);
@@ -1531,7 +1532,8 @@
       : super(helper, token);
 
   @override
-  Expression buildAssignment(Expression value, {bool voidContext: false}) {
+  Expression buildAssignment(Expression value,
+      {bool voidContext: false, int offset: -1}) {
     return _buildUnresolvedVariableAssignment(false, value);
   }
 
@@ -1596,7 +1598,8 @@
         super(helper, token);
 
   @override
-  Expression buildAssignment(Expression value, {bool voidContext}) {
+  Expression buildAssignment(Expression value,
+      {bool voidContext, int offset: -1}) {
     return new PropertySet(receiver, name, value)
       ..fileOffset = offsetForToken(token);
   }
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_expression_generator_impl.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_expression_generator_impl.dart
index cbff91f..c9cfbf9 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_expression_generator_impl.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_expression_generator_impl.dart
@@ -135,7 +135,8 @@
     }
   }
 
-  Expression buildAssignment(Expression value, {bool voidContext: false}) {
+  Expression buildAssignment(Expression value,
+      {bool voidContext: false, int offset: -1}) {
     return buildAssignmentError();
   }
 
@@ -260,7 +261,8 @@
     return unsupported("buildSimpleRead", offsetForToken(token), uri);
   }
 
-  Expression buildAssignment(Expression value, {bool voidContext: false}) {
+  Expression buildAssignment(Expression value,
+      {bool voidContext: false, int offset: -1}) {
     return unsupported("buildAssignment", offsetForToken(token), uri);
   }
 
@@ -331,7 +333,8 @@
     return unsupported("buildSimpleRead", offsetForToken(token), uri);
   }
 
-  Expression buildAssignment(Expression value, {bool voidContext: false}) {
+  Expression buildAssignment(Expression value,
+      {bool voidContext: false, int offset: -1}) {
     return unsupported("buildAssignment", offsetForToken(token), uri);
   }