[CFE] Preserve file URIs of expressions in unevaluated constants.

This fixes missing positions on error messages from dart2js arising
from errors in constants in connection with environment constants.

Change-Id: Icc0666b82d0f28add053fbc231d680c6fdeeeff1
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/114603
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Aske Simon Christensen <askesc@google.com>
This commit is contained in:
Aske Simon Christensen 2019-09-06 12:22:09 +00:00 committed by commit-bot@chromium.org
parent 0242f0c724
commit dc204ec879
3 changed files with 41 additions and 11 deletions

View file

@ -592,8 +592,12 @@ class ConstantEvaluator extends RecursiveVisitor<Constant> {
lazyDepth = 0;
try {
Constant result = _evaluateSubexpression(node);
if (errorOnUnevaluatedConstant && result is UnevaluatedConstant) {
return report(node, messageConstEvalUnevaluated);
if (result is UnevaluatedConstant) {
if (errorOnUnevaluatedConstant) {
return report(node, messageConstEvalUnevaluated);
}
return new UnevaluatedConstant(
removeRedundantFileUriExpressions(result.expression));
}
return result;
} on _AbortDueToError catch (e) {
@ -623,13 +627,8 @@ class ConstantEvaluator extends RecursiveVisitor<Constant> {
}
return new UnevaluatedConstant(new InvalidExpression(e.message.message));
} on _AbortDueToInvalidExpression catch (e) {
// TODO(askesc): Copy position from erroneous node.
// Currently not possible, as it might be in a different file.
// Can be done if we add an explicit URI to InvalidExpression.
InvalidExpression invalid = new InvalidExpression(e.message);
if (invalid.fileOffset == TreeNode.noOffset) {
invalid.fileOffset = node.fileOffset;
}
InvalidExpression invalid = new InvalidExpression(e.message)
..fileOffset = node.fileOffset;
errorReporter.reportInvalidExpression(invalid);
return new UnevaluatedConstant(invalid);
}
@ -649,8 +648,13 @@ class ConstantEvaluator extends RecursiveVisitor<Constant> {
/// Produce an unevaluated constant node for an expression.
Constant unevaluated(Expression original, Expression replacement) {
replacement.fileOffset = original.fileOffset;
// TODO(askesc,johnniwinther): Preserve fileUri on [replacement].
return new UnevaluatedConstant(replacement);
return new UnevaluatedConstant(
new FileUriExpression(replacement, getFileUri(original))
..fileOffset = original.fileOffset);
}
Expression removeRedundantFileUriExpressions(Expression node) {
return node.accept(new RedundantFileUriExpressionRemover()) as Expression;
}
/// Extract an expression from a (possibly unevaluated) constant to become
@ -774,6 +778,11 @@ class ConstantEvaluator extends RecursiveVisitor<Constant> {
node, 'Constant evaluation has no support for ${node.runtimeType}!');
}
@override
Constant visitFileUriExpression(FileUriExpression node) {
return _evaluateSubexpression(node.expression);
}
@override
Constant visitNullLiteral(NullLiteral node) => nullConstant;
@ -2312,6 +2321,23 @@ class EvaluationEnvironment {
}
}
class RedundantFileUriExpressionRemover extends Transformer {
Uri currentFileUri = null;
TreeNode visitFileUriExpression(FileUriExpression node) {
if (node.fileUri == currentFileUri) {
return node.expression.accept(this);
} else {
Uri oldFileUri = currentFileUri;
currentFileUri = node.fileUri;
node.expression = node.expression.accept(this) as Expression
..parent = node;
currentFileUri = oldFileUri;
return node;
}
}
}
// Used as control-flow to abort the current evaluation.
class _AbortDueToError {
final TreeNode node;

View file

@ -666,6 +666,7 @@ relaxes
remapped
remedy
removal
remover
reparse
replacer
replaces

View file

@ -2442,6 +2442,9 @@ abstract class Expression extends TreeNode {
/// An expression containing compile-time errors.
///
/// Should throw a runtime error when evaluated.
///
/// The [fileOffset] of an [InvalidExpression] indicates the location in the
/// tree where the expression occurs, rather than the location of the error.
class InvalidExpression extends Expression {
String message;