@@ -48,6 +48,7 @@ import '../fasta_codes.dart'
4848 templateConstEvalInvalidType,
4949 templateConstEvalInvalidBinaryOperandType,
5050 templateConstEvalInvalidMethodInvocation,
51+ templateConstEvalInvalidPropertyGet,
5152 templateConstEvalInvalidStaticInvocation,
5253 templateConstEvalInvalidStringInterpolationOperand,
5354 templateConstEvalInvalidSymbolName,
@@ -478,17 +479,27 @@ class ConstantEvaluator extends RecursiveVisitor<Constant> {
478479 errorReporter.report (locatedMessage, contextMessages);
479480 return new UnevaluatedConstant (new InvalidExpression (e.message.message));
480481 } on _AbortDueToInvalidExpression catch (e) {
481- errorReporter.reportInvalidExpression (e.node);
482- return new UnevaluatedConstant (e.node);
482+ // TODO(askesc): Copy position from erroneous node.
483+ // Currently not possible, as it might be in a different file.
484+ // Can be done if we add an explicit URI to InvalidExpression.
485+ InvalidExpression invalid = new InvalidExpression (e.message);
486+ if (invalid.fileOffset == TreeNode .noOffset) {
487+ invalid.fileOffset = node.fileOffset;
488+ }
489+ errorReporter.reportInvalidExpression (invalid);
490+ return new UnevaluatedConstant (invalid);
483491 }
484492 }
485493
494+ /// Report an error that has been detected during constant evaluation.
486495 Null report (TreeNode node, Message message, {List <LocatedMessage > context}) {
487496 throw new _AbortDueToError (node, message, context: context);
488497 }
489498
490- Null reportInvalidExpression (InvalidExpression node) {
491- throw new _AbortDueToInvalidExpression (node);
499+ /// Report a construct that should not occur inside a potentially constant
500+ /// expression. It is assumed that an error has already been reported.
501+ Null reportInvalid (TreeNode node, String message) {
502+ throw new _AbortDueToInvalidExpression (node, message);
492503 }
493504
494505 /// Produce an unevaluated constant node for an expression.
@@ -575,7 +586,8 @@ class ConstantEvaluator extends RecursiveVisitor<Constant> {
575586 defaultTreeNode (Node node) {
576587 // Only a subset of the expression language is valid for constant
577588 // evaluation.
578- throw 'Constant evaluation has no support for ${node .runtimeType } yet!' ;
589+ return reportInvalid (
590+ node, 'Constant evaluation has no support for ${node .runtimeType }!' );
579591 }
580592
581593 visitNullLiteral (NullLiteral node) => nullConstant;
@@ -707,15 +719,18 @@ class ConstantEvaluator extends RecursiveVisitor<Constant> {
707719 final Constructor constructor = node.target;
708720 final Class klass = constructor.enclosingClass;
709721 if (! constructor.isConst) {
710- throw 'The front-end should ensure we do not encounter a '
711- 'constructor invocation of a non-const constructor.' ;
722+ return reportInvalid (node, 'Non-const constructor invocation.' );
712723 }
713724 if (constructor.function.body != null &&
714725 constructor.function.body is ! EmptyStatement ) {
715- throw 'Constructor "$node " has non-trivial body "${constructor .function .body .runtimeType }".' ;
726+ return reportInvalid (
727+ node,
728+ 'Constructor "$node " has non-trivial body '
729+ '"${constructor .function .body .runtimeType }".' );
716730 }
717731 if (klass.isAbstract) {
718- throw 'Constructor "$node " belongs to abstract class "${klass }".' ;
732+ return reportInvalid (
733+ node, 'Constructor "$node " belongs to abstract class "${klass }".' );
719734 }
720735
721736 final positionals = evaluatePositionalArguments (node.arguments);
@@ -993,16 +1008,18 @@ class ConstantEvaluator extends RecursiveVisitor<Constant> {
9931008 }
9941009 }
9951010 } else {
996- throw new Exception (
997- 'No support for handling initializer of type "${init .runtimeType }".' );
1011+ return reportInvalid (
1012+ constructor,
1013+ 'No support for handling initializer of type '
1014+ '"${init .runtimeType }".' );
9981015 }
9991016 }
10001017 });
10011018 });
10021019 }
10031020
10041021 visitInvalidExpression (InvalidExpression node) {
1005- return reportInvalidExpression (node);
1022+ return reportInvalid (node, node.message );
10061023 }
10071024
10081025 visitMethodInvocation (MethodInvocation node) {
@@ -1260,12 +1277,16 @@ class ConstantEvaluator extends RecursiveVisitor<Constant> {
12601277 visitPropertyGet (PropertyGet node) {
12611278 if (node.receiver is ThisExpression ) {
12621279 // Access "this" during instance creation.
1280+ if (instanceBuilder == null ) {
1281+ return reportInvalid (node, 'Instance field access outside constructor' );
1282+ }
12631283 for (final Field field in instanceBuilder.fields.keys) {
12641284 if (field.name == node.name) {
12651285 return instanceBuilder.fields[field];
12661286 }
12671287 }
1268- throw 'Could not evaluate field get ${node .name } on incomplete instance' ;
1288+ return reportInvalid (node,
1289+ 'Could not evaluate field get ${node .name } on incomplete instance' );
12691290 }
12701291
12711292 final Constant receiver = _evaluateSubexpression (node.receiver);
@@ -1283,7 +1304,10 @@ class ConstantEvaluator extends RecursiveVisitor<Constant> {
12831304 } else if (receiver is NullConstant ) {
12841305 return report (node, messageConstEvalNullValue);
12851306 }
1286- throw 'Could not evaluate property get on $receiver .' ;
1307+ return report (
1308+ node,
1309+ templateConstEvalInvalidPropertyGet.withArguments (
1310+ node.name.name, receiver));
12871311 }
12881312
12891313 visitLet (Let node) {
@@ -1310,8 +1334,7 @@ class ConstantEvaluator extends RecursiveVisitor<Constant> {
13101334 if (variable.isConst) {
13111335 return _evaluateSubexpression (variable.initializer);
13121336 }
1313- throw new Exception ('The front-end should ensure we do not encounter a '
1314- 'variable get of a non-const variable.' );
1337+ return reportInvalid (node, 'Variable get of a non-const variable.' );
13151338 }
13161339
13171340 visitStaticGet (StaticGet node) {
@@ -1340,8 +1363,8 @@ class ConstantEvaluator extends RecursiveVisitor<Constant> {
13401363 templateConstEvalInvalidStaticInvocation
13411364 .withArguments (target.name.name));
13421365 } else {
1343- throw new Exception (
1344- 'No support for ${target .runtimeType } in a static-get.' );
1366+ reportInvalid (
1367+ node, 'No support for ${target .runtimeType } in a static-get.' );
13451368 }
13461369 });
13471370 }
@@ -1530,14 +1553,15 @@ class ConstantEvaluator extends RecursiveVisitor<Constant> {
15301553 return canonicalize (
15311554 new PartialInstantiationConstant (constant, typeArguments));
15321555 }
1533- throw new Exception (
1556+ return reportInvalid (
1557+ node,
15341558 'The number of type arguments supplied in the partial instantiation '
15351559 'does not match the number of type arguments of the $constant .' );
15361560 }
15371561 // The inner expression in an instantiation can never be null, since
15381562 // instantiations are only inferred on direct references to declarations.
1539- throw new Exception (
1540- 'Only tear-off constants can be partially instantiated.' );
1563+ return reportInvalid (
1564+ node, 'Only tear-off constants can be partially instantiated.' );
15411565 }
15421566
15431567 @override
@@ -1701,7 +1725,7 @@ class ConstantEvaluator extends RecursiveVisitor<Constant> {
17011725 return a > b ? trueConstant : falseConstant;
17021726 }
17031727
1704- throw new Exception ( "Unexpected binary numeric operation '$op '." );
1728+ return reportInvalid (node, "Unexpected binary numeric operation '$op '." );
17051729 }
17061730
17071731 Library libraryOf (TreeNode node) {
@@ -1793,9 +1817,10 @@ class _AbortDueToError {
17931817}
17941818
17951819class _AbortDueToInvalidExpression {
1796- final InvalidExpression node;
1820+ final TreeNode node;
1821+ final String message;
17971822
1798- _AbortDueToInvalidExpression (this .node);
1823+ _AbortDueToInvalidExpression (this .node, this .message );
17991824}
18001825
18011826abstract class ErrorReporter {
0 commit comments