Index: pkg/compiler/lib/src/constants/expressions.dart |
diff --git a/pkg/compiler/lib/src/constants/expressions.dart b/pkg/compiler/lib/src/constants/expressions.dart |
index f1ad90bfae1106d9e36724eb6c7857f3f068b8a2..0b1d4f1a51cceb0222c5096121759d85b656fddc 100644 |
--- a/pkg/compiler/lib/src/constants/expressions.dart |
+++ b/pkg/compiler/lib/src/constants/expressions.dart |
@@ -73,6 +73,9 @@ abstract class ConstantExpression { |
accept(ConstantExpressionVisitor visitor, [context]); |
+ /// `true` if this is an erroneous constant expression. |
+ bool get isErroneous => false; |
+ |
/// Substitute free variables using arguments. |
ConstantExpression apply(NormalizedArguments arguments) => this; |
@@ -137,6 +140,9 @@ class ErroneousConstantExpression extends ConstantExpression { |
@override |
bool _equals(ErroneousConstantExpression other) => true; |
+ |
+ @override |
+ bool get isErroneous => true; |
} |
// TODO(johnniwinther): Avoid the need for this class. |
@@ -387,10 +393,28 @@ class MapConstantExpression extends ConstantExpression { |
@override |
ConstantValue evaluate(Environment environment, |
ConstantSystem constantSystem) { |
- return constantSystem.createMap(environment.compiler, |
+ /*return constantSystem.createMap(environment.compiler, |
type, |
keys.map((k) => k.evaluate(environment, constantSystem)).toList(), |
- values.map((v) => v.evaluate(environment, constantSystem)).toList()); |
+ values.map((v) => v.evaluate(environment, constantSystem)).toList());*/ |
+ Map<ConstantValue, ConstantValue> map = <ConstantValue, ConstantValue>{}; |
+ |
+ for (int i = 0; i < keys.length; i++) { |
+ ConstantValue key = keys[i].evaluate(environment, constantSystem); |
+ if (!key.isConstant) { |
+ return new NonConstantValue(); |
+ } |
+ ConstantValue value = values[i].evaluate(environment, constantSystem); |
+ if (!value.isConstant) { |
+ return new NonConstantValue(); |
+ } |
+ if (map.containsKey(key)) { |
+ environment.reportWarning(keys[i], MessageKind.EQUAL_MAP_ENTRY_KEY, {}); |
+ } |
+ map[key] = value; |
+ } |
+ return constantSystem.createMap( |
+ environment.compiler, type, map.keys.toList(), map.values.toList()); |
} |
ConstantExpression apply(NormalizedArguments arguments) { |
@@ -438,6 +462,8 @@ class ConstructedConstantExpression extends ConstantExpression { |
this.arguments) { |
assert(type.element == target.enclosingClass); |
assert(!arguments.contains(null)); |
+ assert(invariant(NO_LOCATION_SPANNABLE, target.isConst, |
+ message: "Referenced constructor $target is not constant.")); |
} |
ConstantExpressionKind get kind => ConstantExpressionKind.CONSTRUCTED; |
@@ -447,6 +473,8 @@ class ConstructedConstantExpression extends ConstantExpression { |
} |
Map<FieldElement, ConstantExpression> computeInstanceFields() { |
+ assert(invariant(target, target.constantConstructor != null, |
+ message: "Constant constructor has not been computed for $target.")); |
return target.constantConstructor.computeInstanceFields( |
arguments, callStructure); |
} |
@@ -464,13 +492,32 @@ class ConstructedConstantExpression extends ConstantExpression { |
@override |
ConstantValue evaluate(Environment environment, |
ConstantSystem constantSystem) { |
- Map<FieldElement, ConstantValue> fieldValues = |
- <FieldElement, ConstantValue>{}; |
- computeInstanceFields().forEach( |
- (FieldElement field, ConstantExpression constant) { |
- fieldValues[field] = constant.evaluate(environment, constantSystem); |
+ return environment.evaluateConstructor(target, () { |
+ Map<FieldElement, ConstantExpression> fieldMap = |
+ computeInstanceFields(); |
+ if (fieldMap == null) { |
+ // An erroneous constant constructor was encountered in the super-chain. |
+ return new NonConstantValue(); |
+ } |
+ bool isValidAsConstant = true; |
+ Map<FieldElement, ConstantValue> fieldValues = |
+ <FieldElement, ConstantValue>{}; |
+ fieldMap.forEach((FieldElement field, ConstantExpression constant) { |
+ ConstantValue value = constant.evaluate(environment, constantSystem); |
+ assert(invariant(CURRENT_ELEMENT_SPANNABLE, value != null, |
+ message: "No value computed for ${constant.getText()}.")); |
+ if (value.isConstant) { |
+ fieldValues[field] = value; |
+ } else { |
+ isValidAsConstant = false; |
+ } |
+ }); |
+ if (isValidAsConstant) { |
+ return new ConstructedConstantValue(computeInstanceType(), fieldValues); |
+ } else { |
+ return new NonConstantValue(); |
+ } |
}); |
- return new ConstructedConstantValue(computeInstanceType(), fieldValues); |
} |
@override |
@@ -517,11 +564,15 @@ class ConcatenateConstantExpression extends ConstantExpression { |
@override |
ConstantValue evaluate(Environment environment, |
ConstantSystem constantSystem) { |
+ bool isValidAsConstant = true; |
DartString accumulator; |
for (ConstantExpression expression in expressions) { |
ConstantValue value = expression.evaluate(environment, constantSystem); |
DartString valueString; |
- if (value.isNum || value.isBool) { |
+ if (!value.isConstant) { |
+ isValidAsConstant = false; |
+ continue; |
+ } else if (value.isNum || value.isBool) { |
PrimitiveConstantValue primitive = value; |
valueString = |
new DartString.literal(primitive.primitiveValue.toString()); |
@@ -531,7 +582,13 @@ class ConcatenateConstantExpression extends ConstantExpression { |
} else { |
// TODO(johnniwinther): Specialize message to indicated that the problem |
// is not constness but the types of the const expressions. |
- return new NonConstantValue(); |
+ environment.reportError( |
+ expression, |
+ MessageKind.INVALID_CONSTANT_INTERPOLATION_TYPE, |
+ {'constant': expression, |
+ 'type': value.getType(environment.coreTypes)}); |
+ isValidAsConstant = false; |
+ continue; |
} |
if (accumulator == null) { |
accumulator = valueString; |
@@ -539,7 +596,10 @@ class ConcatenateConstantExpression extends ConstantExpression { |
accumulator = new DartString.concat(accumulator, valueString); |
} |
} |
- return constantSystem.createString(accumulator); |
+ if (isValidAsConstant) { |
+ return constantSystem.createString(accumulator); |
+ } |
+ return new NonConstantValue(); |
} |
@override |
@@ -587,8 +647,7 @@ class SymbolConstantExpression extends ConstantExpression { |
@override |
ConstantValue evaluate(Environment environment, |
ConstantSystem constantSystem) { |
- // TODO(johnniwinther): Implement this. |
- throw new UnsupportedError('SymbolConstantExpression.evaluate'); |
+ return constantSystem.createSymbol(environment.compiler, name); |
} |
@override |
@@ -632,7 +691,10 @@ class TypeConstantExpression extends ConstantExpression { |
class VariableConstantExpression extends ConstantExpression { |
final VariableElement element; |
- VariableConstantExpression(this.element); |
+ VariableConstantExpression(this.element) { |
+ /*assert(invariant(NO_LOCATION_SPANNABLE, element.isConst, |
+ message: "Referenced variable $element is not constant."));*/ |
+ } |
ConstantExpressionKind get kind => ConstantExpressionKind.VARIABLE; |
@@ -643,7 +705,9 @@ class VariableConstantExpression extends ConstantExpression { |
@override |
ConstantValue evaluate(Environment environment, |
ConstantSystem constantSystem) { |
- return element.constant.evaluate(environment, constantSystem); |
+ return environment.evaluateVariable(element, () { |
+ return element.constant.evaluate(environment, constantSystem); |
+ }); |
} |
@override |
@@ -704,9 +768,29 @@ class BinaryConstantExpression extends ConstantExpression { |
@override |
ConstantValue evaluate(Environment environment, |
ConstantSystem constantSystem) { |
- return constantSystem.lookupBinary(operator).fold( |
- left.evaluate(environment, constantSystem), |
- right.evaluate(environment, constantSystem)); |
+ ConstantValue leftValue = left.evaluate(environment, constantSystem); |
+ ConstantValue rightValue = right.evaluate(environment, constantSystem); |
+ if (!leftValue.isConstant || |
+ !rightValue.isConstant) { |
+ return new NonConstantValue(); |
+ } |
+ ConstantExpressionChecker checker = |
+ new ConstantExpressionChecker(environment); |
+ bool isValid = checker.checkBinaryExpression( |
+ this, |
+ checker.createInfo(left, leftValue), |
+ operator, |
+ checker.createInfo(right, rightValue)); |
+ |
+ BinaryOperation operation = constantSystem.lookupBinary(operator); |
+ assert(invariant(NO_LOCATION_SPANNABLE, operation != null, |
+ message: "No binary operation for $operator.")); |
+ ConstantValue value = operation.fold(leftValue, rightValue); |
+ if (value != null) { |
+ return value; |
+ } |
+ assert(!isValid); |
+ return new NonConstantValue(); |
} |
ConstantExpression apply(NormalizedArguments arguments) { |
@@ -730,26 +814,32 @@ class BinaryConstantExpression extends ConstantExpression { |
case BinaryOperatorKind.LTEQ: |
return coreTypes.boolType; |
case BinaryOperatorKind.ADD: |
- if (knownLeftType == coreTypes.stringType) { |
- assert(knownRightType == coreTypes.stringType); |
+ if (knownLeftType == coreTypes.stringType && |
+ knownRightType == coreTypes.stringType) { |
return coreTypes.stringType; |
} else if (knownLeftType == coreTypes.intType && |
knownRightType == coreTypes.intType) { |
return coreTypes.intType; |
+ } else if ((knownLeftType == coreTypes.intType || |
+ knownLeftType == coreTypes.doubleType) && |
+ (knownRightType == coreTypes.intType || |
+ knownRightType == coreTypes.doubleType)) { |
+ return coreTypes.doubleType; |
} |
- assert(knownLeftType == coreTypes.doubleType || |
- knownRightType == coreTypes.doubleType); |
- return coreTypes.doubleType; |
+ return null; |
case BinaryOperatorKind.SUB: |
case BinaryOperatorKind.MUL: |
case BinaryOperatorKind.MOD: |
if (knownLeftType == coreTypes.intType && |
knownRightType == coreTypes.intType) { |
return coreTypes.intType; |
+ } else if ((knownLeftType == coreTypes.intType || |
+ knownLeftType == coreTypes.doubleType) && |
+ (knownRightType == coreTypes.intType || |
+ knownRightType == coreTypes.doubleType)) { |
+ return coreTypes.doubleType; |
} |
- assert(knownLeftType == coreTypes.doubleType || |
- knownRightType == coreTypes.doubleType); |
- return coreTypes.doubleType; |
+ return null; |
case BinaryOperatorKind.DIV: |
return coreTypes.doubleType; |
case BinaryOperatorKind.IDIV: |
@@ -767,7 +857,6 @@ class BinaryConstantExpression extends ConstantExpression { |
} |
} |
- |
int get precedence => PRECEDENCE_MAP[operator.kind]; |
@override |
@@ -823,9 +912,12 @@ class IdenticalConstantExpression extends ConstantExpression { |
@override |
ConstantValue evaluate(Environment environment, |
ConstantSystem constantSystem) { |
- return constantSystem.identity.fold( |
- left.evaluate(environment, constantSystem), |
- right.evaluate(environment, constantSystem)); |
+ ConstantValue leftValue = left.evaluate(environment, constantSystem); |
+ ConstantValue rightValue = right.evaluate(environment, constantSystem); |
+ if (leftValue.isConstant && rightValue.isConstant) { |
+ return constantSystem.identity.fold(leftValue, rightValue); |
+ } |
+ return new NonConstantValue(); |
} |
ConstantExpression apply(NormalizedArguments arguments) { |
@@ -870,8 +962,16 @@ class UnaryConstantExpression extends ConstantExpression { |
@override |
ConstantValue evaluate(Environment environment, |
ConstantSystem constantSystem) { |
- return constantSystem.lookupUnary(operator).fold( |
- expression.evaluate(environment, constantSystem)); |
+ ConstantValue expressionValue = |
+ expression.evaluate(environment, constantSystem); |
+ ConstantExpressionChecker checker = |
+ new ConstantExpressionChecker(environment); |
+ bool isValidAsConstant = checker.checkUnary( |
+ operator, checker.createInfo(expression, expressionValue)); |
+ if (isValidAsConstant) { |
+ return constantSystem.lookupUnary(operator).fold(expressionValue); |
+ } |
+ return new NonConstantValue(); |
} |
ConstantExpression apply(NormalizedArguments arguments) { |
@@ -998,12 +1098,17 @@ class ConditionalConstantExpression extends ConstantExpression { |
trueExp.evaluate(environment, constantSystem); |
ConstantValue falseValue = |
falseExp.evaluate(environment, constantSystem); |
- if (conditionValue.isTrue) { |
+ ConstantExpressionChecker checker = |
+ new ConstantExpressionChecker(environment); |
+ bool isValidAsConstant = checker.checkConditional( |
+ checker.createInfo(condition, conditionValue)); |
+ if (!isValidAsConstant) { |
+ return new NonConstantValue(); |
+ } else if (conditionValue.isTrue) { |
return trueValue; |
- } else if (conditionValue.isFalse) { |
- return falseValue; |
} else { |
- return new NonConstantValue(); |
+ assert(conditionValue.isFalse); |
+ return falseValue; |
} |
} |
@@ -1128,7 +1233,12 @@ class BoolFromEnvironmentConstantExpression |
} else { |
defaultConstantValue = constantSystem.createBool(false); |
} |
- if (!nameConstantValue.isString) { |
+ ConstantExpressionChecker checker = |
+ new ConstantExpressionChecker(environment); |
+ bool isValidAsConstant = checker.checkBoolFromEnvironment( |
+ checker.createInfo(name, nameConstantValue), |
+ checker.createInfo(defaultValue, defaultConstantValue)); |
+ if (!isValidAsConstant) { |
return new NonConstantValue(); |
} |
StringConstantValue nameStringConstantValue = nameConstantValue; |
@@ -1182,7 +1292,12 @@ class IntFromEnvironmentConstantExpression |
} else { |
defaultConstantValue = constantSystem.createNull(); |
} |
- if (!nameConstantValue.isString) { |
+ ConstantExpressionChecker checker = |
+ new ConstantExpressionChecker(environment); |
+ bool isValidAsConstant = checker.checkIntFromEnvironment( |
+ checker.createInfo(name, nameConstantValue), |
+ checker.createInfo(defaultValue, defaultConstantValue)); |
+ if (!isValidAsConstant) { |
return new NonConstantValue(); |
} |
StringConstantValue nameStringConstantValue = nameConstantValue; |
@@ -1238,7 +1353,12 @@ class StringFromEnvironmentConstantExpression |
} else { |
defaultConstantValue = constantSystem.createNull(); |
} |
- if (!nameConstantValue.isString) { |
+ ConstantExpressionChecker checker = |
+ new ConstantExpressionChecker(environment); |
+ bool isValidAsConstant = checker.checkStringFromEnvironment( |
+ checker.createInfo(name, nameConstantValue), |
+ checker.createInfo(defaultValue, defaultConstantValue)); |
+ if (!isValidAsConstant) { |
return new NonConstantValue(); |
} |
StringConstantValue nameStringConstantValue = nameConstantValue; |
@@ -1605,4 +1725,4 @@ class ConstExpPrinter extends ConstantExpressionVisitor { |
} |
String toString() => sb.toString(); |
-} |
+} |