Store resolution for 'throw' in constant.

R=brianwilkerson@google.com, paulberry@google.com

Change-Id: Iebd1122ff887b75e94daa2153c43d59e77c3359d
Reviewed-on: https://dart-review.googlesource.com/64762
Reviewed-by: Paul Berry <paulberry@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index 68083db..5bc0f10 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -208,6 +208,7 @@
   CompileTimeErrorCode.NON_GENERATIVE_CONSTRUCTOR,
   CompileTimeErrorCode.NON_SYNC_ABSTRACT_METHOD,
   CompileTimeErrorCode.NON_SYNC_FACTORY_METHOD,
+  CompileTimeErrorCode.NOT_CONSTANT_EXPRESSION,
   CompileTimeErrorCode.NOT_ENOUGH_REQUIRED_ARGUMENTS,
   CompileTimeErrorCode.NO_ANNOTATION_CONSTRUCTOR_ARGUMENTS,
   CompileTimeErrorCode.NO_DEFAULT_SUPER_CONSTRUCTOR_EXPLICIT,
diff --git a/pkg/analyzer/lib/src/error/codes.dart b/pkg/analyzer/lib/src/error/codes.dart
index 49a4b15..832b4fa 100644
--- a/pkg/analyzer/lib/src/error/codes.dart
+++ b/pkg/analyzer/lib/src/error/codes.dart
@@ -2071,6 +2071,9 @@
               "Try calling a different constructor in the superclass, or "
               "making the called constructor not be a factory constructor.");
 
+  static const CompileTimeErrorCode NOT_CONSTANT_EXPRESSION =
+      const CompileTimeErrorCode.fromFasta('NOT_CONSTANT_EXPRESSION');
+
   /**
    * 7.9 Superclasses: It is a compile-time error to specify an extends clause
    * for class Object.
diff --git a/pkg/analyzer/lib/src/kernel/resynthesize.dart b/pkg/analyzer/lib/src/kernel/resynthesize.dart
index 6407ca4..b2c96be 100644
--- a/pkg/analyzer/lib/src/kernel/resynthesize.dart
+++ b/pkg/analyzer/lib/src/kernel/resynthesize.dart
@@ -585,6 +585,9 @@
     // Invalid initializers and  annotations are represented as Let.
     if (expr is kernel.Let) {
       var body = expr.body;
+      if (_isStaticError(body)) {
+        throw const _CompilationErrorFound();
+      }
       if (body is kernel.Let) {
         var initializer = body.variable.initializer;
         if (initializer is kernel.Let && _isStaticError(initializer.body)) {
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 be5c9e8..912e315 100644
--- a/pkg/analyzer/test/src/dart/analysis/driver_resolution_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/driver_resolution_test.dart
@@ -27,6 +27,8 @@
   });
 }
 
+final isBottomType = new TypeMatcher<BottomTypeImpl>();
+
 final isDynamicType = new TypeMatcher<DynamicTypeImpl>();
 
 final isUndefinedType = new TypeMatcher<UndefinedTypeImpl>();
@@ -3199,6 +3201,32 @@
     assertType(aRef, 'int');
   }
 
+  test_invalid_const_throw_local() async {
+    addTestFile(r'''
+main() {
+  const c = throw 42;
+}
+''');
+    await resolveTestFile();
+    expect(result.errors, isNotEmpty);
+
+    var throwExpression = findNode.throw_('throw 42;');
+    expect(throwExpression.staticType, isBottomType);
+    assertType(throwExpression.expression, 'int');
+  }
+
+  test_invalid_const_throw_topLevel() async {
+    addTestFile(r'''
+const c = throw 42;
+''');
+    await resolveTestFile();
+    expect(result.errors, isNotEmpty);
+
+    var throwExpression = findNode.throw_('throw 42;');
+    expect(throwExpression.staticType, isBottomType);
+    assertType(throwExpression.expression, 'int');
+  }
+
   test_invalid_instanceCreation_abstract() async {
     addTestFile(r'''
 abstract class C<T> {
@@ -8355,6 +8383,10 @@
     return _node(search).getAncestor((n) => n is SimpleFormalParameter);
   }
 
+  ThrowExpression throw_(String search) {
+    return _node(search).getAncestor((n) => n is ThrowExpression);
+  }
+
   VariableDeclaration variableDeclaration(String search) {
     return _node(search).getAncestor((n) => n is VariableDeclaration);
   }
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index d8994bb..57a5a7d 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -4247,6 +4247,23 @@
 ''');
   }
 
+  test_const_topLevel_throw() async {
+    shouldCompareLibraryElements = false;
+    var library = await checkLibrary(r'''
+const c = throw 42;
+''');
+    if (isSharedFrontEnd) {
+      checkElementText(library, r'''
+const dynamic c = #invalidConst;
+''');
+    } else {
+      // This is a bug.
+      checkElementText(library, r'''
+const dynamic c;
+''');
+    }
+  }
+
   test_const_topLevel_typedList() async {
     var library = await checkLibrary(r'''
 const vNull = const <Null>[];
diff --git a/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart b/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
index 29ce10a..4051879 100644
--- a/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
+++ b/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
@@ -4923,6 +4923,25 @@
     const MessageCode("NotAnLvalue", message: r"""Can't assign to this.""");
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<Message Function(String string)> templateNotConstantExpression =
+    const Template<Message Function(String string)>(
+        messageTemplate: r"""#string is not a constant expression.""",
+        withArguments: _withArgumentsNotConstantExpression);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(String string)> codeNotConstantExpression =
+    const Code<Message Function(String string)>(
+        "NotConstantExpression", templateNotConstantExpression,
+        analyzerCode: "NOT_CONSTANT_EXPRESSION", dart2jsCode: "*fatal*");
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsNotConstantExpression(String string) {
+  return new Message(codeNotConstantExpression,
+      message: """${string} is not a constant expression.""",
+      arguments: {'string': string});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Null> codeOnlyTry = messageOnlyTry;
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
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 544f13b..d344f86 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -2325,14 +2325,17 @@
   void handleThrowExpression(Token throwToken, Token endToken) {
     debugEvent("ThrowExpression");
     Expression expression = popForValue();
+
+    Expression error;
     if (constantContext != ConstantContext.none) {
-      push(deprecated_buildCompileTimeError(
-          "Not a constant expression.", throwToken.charOffset));
-      // TODO(brianwilkerson): For analyzer, we need to produce the error above
-      // but then we need to produce the AST as in the `else` clause below.
-    } else {
-      push(forest.throwExpression(throwToken, expression));
+      error = buildCompileTimeError(
+          fasta.templateNotConstantExpression.withArguments('Throw'),
+          throwToken.offset,
+          throwToken.length);
     }
+
+    push(new ThrowJudgment(throwToken, expression, desugaredError: error)
+      ..fileOffset = offsetForToken(throwToken));
   }
 
   @override
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_ast_api.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_ast_api.dart
index a41e9b9..8db8d94 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_ast_api.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_ast_api.dart
@@ -115,6 +115,7 @@
         SwitchCaseJudgment,
         SwitchStatementJudgment,
         SyntheticExpressionJudgment,
+        ThrowJudgment,
         UnresolvedTargetInvocationJudgment,
         UnresolvedVariableGetJudgment,
         UnresolvedVariableAssignmentJudgment,
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
index 090f0d5..a929653 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
@@ -2976,12 +2976,14 @@
 
 class ThrowJudgment extends Throw implements ExpressionJudgment {
   final Token throwKeyword;
+  final kernel.Expression desugaredError;
 
   DartType inferredType;
 
   ExpressionJudgment get judgment => expression;
 
-  ThrowJudgment(this.throwKeyword, Expression expression) : super(expression);
+  ThrowJudgment(this.throwKeyword, Expression expression, {this.desugaredError})
+      : super(expression);
 
   @override
   Expression infer<Expression, Statement, Initializer, Type>(
@@ -2992,6 +2994,10 @@
     inferredType = const BottomType();
     inferrer.listener
         .throw_(this, fileOffset, throwKeyword, null, inferredType);
+    if (desugaredError != null) {
+      parent.replaceChild(this, desugaredError);
+      parent = null;
+    }
     return null;
   }
 }
diff --git a/pkg/front_end/messages.status b/pkg/front_end/messages.status
index 5f2efe1..64ec59f 100644
--- a/pkg/front_end/messages.status
+++ b/pkg/front_end/messages.status
@@ -255,6 +255,7 @@
 NotAType/example: Fail
 NotAnLvalue/analyzerCode: Fail
 NotAnLvalue/example: Fail
+NotConstantExpression/example: Fail
 OperatorMinusParameterMismatch/example: Fail
 OperatorParameterMismatch0/analyzerCode: Fail
 OperatorParameterMismatch0/example: Fail
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index 0704688..b57020e 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -135,6 +135,11 @@
   template: "The variable '#string' is not a constant, only constant expressions are allowed."
   analyzerCode: NON_CONSTANT_VALUE_IN_INITIALIZER
 
+NotConstantExpression:
+  template: "#string is not a constant expression."
+  analyzerCode: NOT_CONSTANT_EXPRESSION
+  dart2jsCode: "*fatal*"
+
 NonAsciiIdentifier:
   template: "The non-ASCII character '#character' (#unicode) can't be used in identifiers, only in strings and comments."
   tip: "Try using an US-ASCII letter, a digit, '_' (an underscore), or '$' (a dollar sign)."