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)."