Handle unresolved identifiers with an accessor.

R=karlklose@google.com

Review-Url: https://codereview.chromium.org/2790743004 .
diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
index b4f385e..8d93df5 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -145,18 +145,7 @@
 
   @override
   Expression toValue(Object node) {
-    if (node is UnresolvedIdentifier) {
-      if (isDartLibrary &&
-          node.name.name == "main" &&
-          library.uri.path == "_builtin" &&
-          member?.name == "_getMainClosure") {
-        // TODO(ahe): https://github.com/dart-lang/sdk/issues/28989
-        return new NullLiteral()..fileOffset = node.fileOffset;
-      }
-      return throwNoSuchMethodError(
-          node.name.name, new Arguments.empty(), node.fileOffset,
-          isGetter: true);
-    } else if (node is FastaAccessor) {
+    if (node is FastaAccessor) {
       return node.buildSimpleRead();
     } else if (node is TypeVariableBuilder) {
       TypeParameterType type = node.buildTypesWithBuiltArguments(library, null);
@@ -531,9 +520,6 @@
         addCompileTimeError(charOffset, "Not a constant expression.");
       }
       return receiver.doInvocation(charOffset, arguments);
-    } else if (receiver is UnresolvedIdentifier) {
-      return throwNoSuchMethodError(
-          receiver.name.name, arguments, receiver.fileOffset);
     } else {
       return buildMethodInvocation(
           toValue(receiver), callName, arguments, charOffset);
@@ -761,11 +747,14 @@
           addCompileTimeError(charOffset, "Not a constant expression.");
         }
         return new ThisPropertyAccessor(this, charOffset, n, null, null);
+      } else if (isDartLibrary &&
+          name == "main" &&
+          library.uri.path == "_builtin" &&
+          member?.name == "_getMainClosure") {
+        // TODO(ahe): https://github.com/dart-lang/sdk/issues/28989
+        return new NullLiteral()..fileOffset = charOffset;
       } else {
-        if (constantExpressionRequired) {
-          addCompileTimeError(charOffset, "Not a constant expression.");
-        }
-        return new UnresolvedIdentifier(n)..fileOffset = charOffset;
+        return new UnresolvedAccessor(this, n, charOffset);
       }
     } else if (builder.isTypeDeclaration) {
       if (constantExpressionRequired && builder.isTypeVariable) {
@@ -1305,9 +1294,6 @@
     if (name is FastaAccessor) {
       warning("'${beginToken.lexeme}' isn't a type.", beginToken.charOffset);
       push(const DynamicType());
-    } else if (name is UnresolvedIdentifier) {
-      warning("'${name.name}' isn't a type.", beginToken.charOffset);
-      push(const DynamicType());
     } else if (name is TypeVariableBuilder) {
       if (constantExpressionRequired) {
         addCompileTimeError(
@@ -2458,15 +2444,6 @@
 }
 
 // TODO(ahe): Shouldn't need to be an expression.
-class UnresolvedIdentifier extends InvalidExpression {
-  final Name name;
-
-  UnresolvedIdentifier(this.name);
-
-  String toString() => "unresolved-identifier($name)";
-}
-
-// TODO(ahe): Shouldn't need to be an expression.
 class Identifier extends InvalidExpression {
   final String name;
 
@@ -2917,8 +2894,6 @@
 String getNodeName(Object node) {
   if (node is Identifier) {
     return node.name;
-  } else if (node is UnresolvedIdentifier) {
-    return node.name.name;
   } else if (node is TypeDeclarationBuilder) {
     return node.name;
   } else if (node is PrefixBuilder) {
diff --git a/pkg/front_end/lib/src/fasta/kernel/fasta_accessors.dart b/pkg/front_end/lib/src/fasta/kernel/fasta_accessors.dart
index 6bfae59..c6e7e93 100644
--- a/pkg/front_end/lib/src/fasta/kernel/fasta_accessors.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/fasta_accessors.dart
@@ -88,7 +88,7 @@
         isSetter: true);
   }
 
-  /* Expression | FastaAccessor */ doInvocation(
+  /* Expression | FastaAccessor | Initializer */ doInvocation(
       int offset, Arguments arguments);
 
   /* Expression | FastaAccessor */ buildPropertyAccess(
@@ -106,8 +106,8 @@
   /* Expression | FastaAccessor */ buildThrowNoSuchMethodError(
       Arguments arguments,
       {bool isSuper: false,
-      isGetter: false,
-      isSetter: false,
+      bool isGetter: false,
+      bool isSetter: false,
       String name,
       int offset}) {
     return helper.throwNoSuchMethodError(
@@ -118,7 +118,7 @@
   bool get isThisPropertyAccessor => false;
 }
 
-abstract class CompileTimeErrorAccessor implements FastaAccessor {
+abstract class ErrorAccessor implements FastaAccessor {
   @override
   Expression get builtBinary => internalError("Unsupported operation.");
 
@@ -135,23 +135,35 @@
     internalError("Unsupported operation.");
   }
 
-  Expression buildError();
+  /// Pass [arguments] that must be evaluated before throwing an error.  At
+  /// most one of [isGetter] and [isSetter] should be true and they're passed
+  /// to [BuilderHelper.buildThrowNoSuchMethodError] if it is used.
+  Expression buildError(Arguments arguments,
+      {bool isGetter: false, bool isSetter: false, int offset});
 
   Name get name => internalError("Unsupported operation.");
 
+  @override
   String get plainNameForRead => name.name;
 
   withReceiver(Object receiver, {bool isNullAware}) => this;
 
+  @override
   Initializer buildFieldInitializer(
       Map<String, FieldInitializer> initializers) {
-    return new LocalInitializer(new VariableDeclaration.forValue(buildError()));
+    return new LocalInitializer(new VariableDeclaration.forValue(
+        buildError(new Arguments.empty(), isSetter: true)));
   }
 
-  doInvocation(int offset, Arguments arguments) => this;
+  @override
+  doInvocation(int offset, Arguments arguments) {
+    return buildError(arguments, offset: offset);
+  }
 
+  @override
   buildPropertyAccess(IncompleteSend send, bool isNullAware) => this;
 
+  @override
   buildThrowNoSuchMethodError(Arguments arguments,
       {bool isSuper: false,
       isGetter: false,
@@ -161,41 +173,55 @@
     return this;
   }
 
+  @override
   Expression buildAssignment(Expression value, {bool voidContext: false}) {
-    return buildError();
+    return buildError(new Arguments(<Expression>[value]), isSetter: true);
   }
 
+  @override
   Expression buildCompoundAssignment(Name binaryOperator, Expression value,
       {int offset: TreeNode.noOffset,
       bool voidContext: false,
       Procedure interfaceTarget}) {
-    return buildError();
+    return buildError(new Arguments(<Expression>[value]), isGetter: true);
   }
 
+  @override
   Expression buildPrefixIncrement(Name binaryOperator,
       {int offset: TreeNode.noOffset,
       bool voidContext: false,
       Procedure interfaceTarget}) {
-    return buildError();
+    return buildError(new Arguments(<Expression>[new IntLiteral(1)]),
+        isGetter: true);
   }
 
+  @override
   Expression buildPostfixIncrement(Name binaryOperator,
       {int offset: TreeNode.noOffset,
       bool voidContext: false,
       Procedure interfaceTarget}) {
-    return buildError();
+    return buildError(new Arguments(<Expression>[new IntLiteral(1)]),
+        isGetter: true);
   }
 
+  @override
   Expression buildNullAwareAssignment(Expression value, DartType type,
       {bool voidContext: false}) {
-    return buildError();
+    return buildError(new Arguments(<Expression>[value]), isSetter: true);
   }
 
-  Expression buildSimpleRead() => buildError();
+  @override
+  Expression buildSimpleRead() =>
+      buildError(new Arguments.empty(), isGetter: true);
 
-  Expression makeInvalidRead() => buildError();
+  @override
+  Expression makeInvalidRead() =>
+      buildError(new Arguments.empty(), isGetter: true);
 
-  Expression makeInvalidWrite(Expression value) => buildError();
+  @override
+  Expression makeInvalidWrite(Expression value) {
+    return buildError(new Arguments(<Expression>[value]), isSetter: true);
+  }
 }
 
 class ThisAccessor extends FastaAccessor {
@@ -361,15 +387,20 @@
   withReceiver(Object receiver, {bool isNullAware});
 }
 
-class IncompleteError extends IncompleteSend with CompileTimeErrorAccessor {
+class IncompleteError extends IncompleteSend with ErrorAccessor {
   final Object error;
 
   IncompleteError(BuilderHelper helper, int offset, this.error)
       : super(helper, offset, null);
 
-  Expression buildError() {
-    return helper.buildCompileTimeError(error, offset);
+  @override
+  Expression buildError(Arguments arguments,
+      {bool isGetter: false, bool isSetter: false, int offset}) {
+    return helper.buildCompileTimeError(error, offset ?? this.offset);
   }
+
+  @override
+  doInvocation(int offset, Arguments arguments) => this;
 }
 
 class SendAccessor extends IncompleteSend {
@@ -408,7 +439,7 @@
     Expression result;
     if (receiver is KernelClassBuilder) {
       Builder builder = receiver.findStaticBuilder(name.name, offset, uri);
-      if (builder == null) {
+      if (builder == null || builder is AccessErrorBuilder) {
         return buildThrowNoSuchMethodError(arguments);
       }
       if (builder.hasProblem) {
@@ -802,6 +833,31 @@
   }
 }
 
+class UnresolvedAccessor extends FastaAccessor with ErrorAccessor {
+  @override
+  final int offset;
+
+  @override
+  final BuilderHelper helper;
+
+  @override
+  final Name name;
+
+  UnresolvedAccessor(this.helper, this.name, this.offset);
+
+  Expression doInvocation(int charOffset, Arguments arguments) {
+    return buildError(arguments, offset: charOffset);
+  }
+
+  @override
+  Expression buildError(Arguments arguments,
+      {bool isGetter: false, bool isSetter: false, int offset}) {
+    return helper.throwNoSuchMethodError(
+        plainNameForRead, arguments, offset ?? this.offset,
+        isGetter: isGetter, isSetter: isSetter);
+  }
+}
+
 bool isFieldOrGetter(Member member) {
   return member is Field || (member is Procedure && member.isGetter);
 }
diff --git a/tests/co19/co19-kernel.status b/tests/co19/co19-kernel.status
index 3859231..786598e 100644
--- a/tests/co19/co19-kernel.status
+++ b/tests/co19/co19-kernel.status
@@ -86,15 +86,6 @@
 Language/Enums/restrictions_t08: MissingCompileTimeError
 Language/Expressions/Assignment/expression_assignment_failed_t03: CompileTimeError
 Language/Expressions/Assignment/expression_assignment_t07: CompileTimeError
-Language/Expressions/Assignment/no_such_method_t01: CompileTimeError
-Language/Expressions/Assignment/no_such_method_t02: CompileTimeError
-Language/Expressions/Assignment/no_such_method_t03: CompileTimeError
-Language/Expressions/Assignment/no_such_method_t04: CompileTimeError
-Language/Expressions/Assignment/no_such_method_t05: CompileTimeError
-Language/Expressions/Assignment/no_such_method_t06: CompileTimeError
-Language/Expressions/Assignment/no_such_method_t07: CompileTimeError
-Language/Expressions/Assignment/no_such_method_t08: CompileTimeError
-Language/Expressions/Assignment/no_such_method_t09: CompileTimeError
 Language/Expressions/Assignment/static_type_t06: CompileTimeError
 Language/Expressions/Assignment/super_assignment_failed_t01: RuntimeError
 Language/Expressions/Assignment/super_assignment_failed_t02: RuntimeError
@@ -293,7 +284,6 @@
 Language/Mixins/declaring_constructor_t08: MissingCompileTimeError
 Language/Mixins/declaring_constructor_t09: MissingCompileTimeError
 Language/Mixins/declaring_constructor_t10: MissingCompileTimeError
-Language/Overview/Privacy/private_and_public_t04: CompileTimeError
 Language/Overview/Privacy/private_and_public_t06: RuntimeError
 Language/Overview/Privacy/private_and_public_t09: RuntimeError
 Language/Overview/Privacy/private_and_public_t10: RuntimeError
@@ -324,23 +314,18 @@
 Language/Statements/Continue/label_t10: MissingCompileTimeError
 Language/Statements/Continue/label_t11: MissingCompileTimeError
 Language/Statements/Do/execution_t04: Crash
-Language/Statements/For/syntax_t07: CompileTimeError
 Language/Statements/For/syntax_t12: MissingCompileTimeError
 Language/Statements/For/syntax_t13: MissingCompileTimeError
 Language/Statements/For/syntax_t19: MissingCompileTimeError
 Language/Statements/For/syntax_t20: MissingCompileTimeError
 Language/Statements/If/execution_t03: Crash
-Language/Statements/Labels/scope_t01: CompileTimeError
+Language/Statements/Labels/scope_t01: RuntimeError
 Language/Statements/Labels/scope_t05: MissingCompileTimeError
-Language/Statements/Labels/scope_t07: CompileTimeError
+Language/Statements/Labels/scope_t07: RuntimeError
 Language/Statements/Labels/syntax_t03: Pass # OK
 Language/Statements/Local_Function_Declaration/reference_before_declaration_t01: MissingCompileTimeError
 Language/Statements/Local_Function_Declaration/reference_before_declaration_t03: MissingCompileTimeError
-Language/Statements/Local_Variable_Declaration/syntax_t05: CompileTimeError
-Language/Statements/Local_Variable_Declaration/syntax_t06: CompileTimeError
 Language/Statements/Local_Variable_Declaration/syntax_t11: MissingCompileTimeError
-Language/Statements/Local_Variable_Declaration/syntax_t18: CompileTimeError
-Language/Statements/Local_Variable_Declaration/syntax_t19: CompileTimeError
 Language/Statements/Local_Variable_Declaration/syntax_t20: MissingCompileTimeError
 Language/Statements/Rethrow/on_catch_clause_t01: Crash
 Language/Statements/Rethrow/on_catch_clause_t02: Crash
diff --git a/tests/language/language_kernel.status b/tests/language/language_kernel.status
index a40c7b4..cadd82a 100644
--- a/tests/language/language_kernel.status
+++ b/tests/language/language_kernel.status
@@ -9,7 +9,6 @@
 built_in_identifier_test/01: CompileTimeError
 call_nonexistent_static_test/01: CompileTimeError
 call_nonexistent_static_test/04: CompileTimeError
-call_nonexistent_static_test/06: CompileTimeError
 cha_deopt1_test: RuntimeError  # Deferred Loading Issue 28335
 cha_deopt2_test: RuntimeError  # Deferred Loading Issue 28335
 cha_deopt3_test: RuntimeError  # Deferred Loading Issue 28335
@@ -94,7 +93,6 @@
 covariant_test/46: MissingCompileTimeError
 covariant_test/46b: MissingCompileTimeError
 covariant_test/59: MissingCompileTimeError
-crash_6725_test/01: CompileTimeError
 cyclic_constructor_test/01: MissingCompileTimeError
 cyclic_type_test/00: RuntimeError
 cyclic_type_test/01: RuntimeError