Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(956)

Unified Diff: pkg/compiler/lib/src/compile_time_constants.dart

Issue 693183006: Revert "Move dart2js from sdk/lib/_internal/compiler to pkg/compiler" (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/compiler/lib/src/common.dart ('k') | pkg/compiler/lib/src/compiler.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/compiler/lib/src/compile_time_constants.dart
diff --git a/pkg/compiler/lib/src/compile_time_constants.dart b/pkg/compiler/lib/src/compile_time_constants.dart
deleted file mode 100644
index 7b0494365797ef2bd23e32e0e1b8c4fad197657e..0000000000000000000000000000000000000000
--- a/pkg/compiler/lib/src/compile_time_constants.dart
+++ /dev/null
@@ -1,1101 +0,0 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-part of dart2js;
-
-/// A [ConstantEnvironment] provides access for constants compiled for variable
-/// initializers.
-abstract class ConstantEnvironment {
- /// Returns the constant for the initializer of [element].
- ConstantExpression getConstantForVariable(VariableElement element);
-}
-
-/// A class that can compile and provide constants for variables, nodes and
-/// metadata.
-abstract class ConstantCompiler extends ConstantEnvironment {
- /// Compiles the compile-time constant for the initializer of [element], or
- /// reports an error if the initializer is not a compile-time constant.
- ///
- /// Depending on implementation, the constant compiler might also compute
- /// the compile-time constant for the backend interpretation of constants.
- ///
- /// The returned constant is always of the frontend interpretation.
- ConstantExpression compileConstant(VariableElement element);
-
- /// Computes the compile-time constant for the variable initializer,
- /// if possible.
- void compileVariable(VariableElement element);
-
- /// Compiles the compile-time constant for [node], or reports an error if
- /// [node] is not a compile-time constant.
- ///
- /// Depending on implementation, the constant compiler might also compute
- /// the compile-time constant for the backend interpretation of constants.
- ///
- /// The returned constant is always of the frontend interpretation.
- ConstantExpression compileNode(Node node, TreeElements elements);
-
- /// Compiles the compile-time constant for the value [metadata], or reports an
- /// error if the value is not a compile-time constant.
- ///
- /// Depending on implementation, the constant compiler might also compute
- /// the compile-time constant for the backend interpretation of constants.
- ///
- /// The returned constant is always of the frontend interpretation.
- ConstantExpression compileMetadata(MetadataAnnotation metadata,
- Node node,
- TreeElements elements);
-}
-
-/// A [BackendConstantEnvironment] provides access to constants needed for
-/// backend implementation.
-abstract class BackendConstantEnvironment extends ConstantEnvironment {
- /// Returns the compile-time constant associated with [node].
- ///
- /// Depending on implementation, the constant might be stored in [elements].
- ConstantExpression getConstantForNode(Node node, TreeElements elements);
-
- /// Returns the compile-time constant value of [metadata].
- ConstantExpression getConstantForMetadata(MetadataAnnotation metadata);
-}
-
-/// Interface for the task that compiles the constant environments for the
-/// frontend and backend interpretation of compile-time constants.
-abstract class ConstantCompilerTask extends CompilerTask
- implements ConstantCompiler {
- ConstantCompilerTask(Compiler compiler) : super(compiler);
-}
-
-/**
- * The [ConstantCompilerBase] is provides base implementation for compilation of
- * compile-time constants for both the Dart and JavaScript interpretation of
- * constants. It keeps track of compile-time constants for initializations of
- * global and static fields, and default values of optional parameters.
- */
-abstract class ConstantCompilerBase implements ConstantCompiler {
- final Compiler compiler;
- final ConstantSystem constantSystem;
-
- /**
- * Contains the initial values of fields and default values of parameters.
- *
- * Must contain all static and global initializations of const fields.
- *
- * May contain eagerly compiled initial values for statics and instance
- * fields (if those are compile-time constants).
- *
- * May contain default parameter values of optional arguments.
- *
- * Invariant: The keys in this map are declarations.
- */
- final Map<VariableElement, ConstantExpression> initialVariableValues =
- new Map<VariableElement, ConstantExpression>();
-
- /** The set of variable elements that are in the process of being computed. */
- final Set<VariableElement> pendingVariables = new Set<VariableElement>();
-
- ConstantCompilerBase(this.compiler, this.constantSystem);
-
- ConstantExpression getConstantForVariable(VariableElement element) {
- return initialVariableValues[element.declaration];
- }
-
- ConstantExpression compileConstant(VariableElement element) {
- return compileVariable(element, isConst: true);
- }
-
- ConstantExpression compileVariable(VariableElement element,
- {bool isConst: false}) {
-
- if (initialVariableValues.containsKey(element.declaration)) {
- ConstantExpression result = initialVariableValues[element.declaration];
- return result;
- }
- AstElement currentElement = element.analyzableElement;
- return compiler.withCurrentElement(currentElement, () {
- compiler.analyzeElement(currentElement.declaration);
- ConstantExpression constant = compileVariableWithDefinitions(
- element, currentElement.resolvedAst.elements, isConst: isConst);
- return constant;
- });
- }
-
- /**
- * Returns the a compile-time constant if the variable could be compiled
- * eagerly. If the variable needs to be initialized lazily returns `null`.
- * If the variable is `const` but cannot be compiled eagerly reports an
- * error.
- */
- ConstantExpression compileVariableWithDefinitions(VariableElement element,
- TreeElements definitions,
- {bool isConst: false}) {
- Node node = element.node;
- if (pendingVariables.contains(element)) {
- if (isConst) {
- compiler.reportFatalError(
- node, MessageKind.CYCLIC_COMPILE_TIME_CONSTANTS);
- }
- return null;
- }
- pendingVariables.add(element);
-
- Expression initializer = element.initializer;
- ConstantExpression value;
- if (initializer == null) {
- // No initial value.
- value = new PrimitiveConstantExpression(new NullConstantValue());
- } else {
- value = compileNodeWithDefinitions(
- initializer, definitions, isConst: isConst);
- if (compiler.enableTypeAssertions &&
- value != null &&
- element.isField) {
- DartType elementType = element.type;
- if (elementType.isMalformed && !value.value.isNull) {
- if (isConst) {
- ErroneousElement element = elementType.element;
- compiler.reportFatalError(
- node, element.messageKind, element.messageArguments);
- } else {
- // We need to throw an exception at runtime.
- value = null;
- }
- } else {
- DartType constantType = value.value.computeType(compiler);
- if (!constantSystem.isSubtype(compiler,
- constantType, elementType)) {
- if (isConst) {
- compiler.reportFatalError(
- node, MessageKind.NOT_ASSIGNABLE,
- {'fromType': constantType, 'toType': elementType});
- } else {
- // If the field cannot be lazily initialized, we will throw
- // the exception at runtime.
- value = null;
- }
- }
- }
- }
- }
- if (value != null) {
- initialVariableValues[element.declaration] = value;
- } else {
- assert(invariant(element, !isConst,
- message: "Variable $element does not compile to a constant."));
- }
- pendingVariables.remove(element);
- return value;
- }
-
- ConstantExpression compileNodeWithDefinitions(Node node,
- TreeElements definitions,
- {bool isConst: true}) {
- assert(node != null);
- CompileTimeConstantEvaluator evaluator = new CompileTimeConstantEvaluator(
- this, definitions, compiler, isConst: isConst);
- AstConstant constant = evaluator.evaluate(node);
- return constant != null ? constant.expression : null;
- }
-
- ConstantExpression compileNode(Node node, TreeElements elements) {
- return compileNodeWithDefinitions(node, elements);
- }
-
- ConstantExpression compileMetadata(MetadataAnnotation metadata,
- Node node,
- TreeElements elements) {
- return compileNodeWithDefinitions(node, elements);
- }
-
- void forgetElement(Element element) {
- initialVariableValues.remove(element);
- if (element is ScopeContainerElement) {
- element.forEachLocalMember(initialVariableValues.remove);
- }
- if (element is FunctionElement && element.hasFunctionSignature) {
- element.functionSignature.forEachParameter(this.forgetElement);
- }
- }
-}
-
-/// [ConstantCompiler] that uses the Dart semantics for the compile-time
-/// constant evaluation.
-class DartConstantCompiler extends ConstantCompilerBase {
- DartConstantCompiler(Compiler compiler)
- : super(compiler, const DartConstantSystem());
-
- ConstantExpression getConstantForNode(Node node, TreeElements definitions) {
- return definitions.getConstant(node);
- }
-
- ConstantExpression getConstantForMetadata(MetadataAnnotation metadata) {
- return metadata.constant;
- }
-
- ConstantExpression compileNodeWithDefinitions(Node node,
- TreeElements definitions,
- {bool isConst: true}) {
- ConstantExpression constant = definitions.getConstant(node);
- if (constant != null) {
- return constant;
- }
- constant =
- super.compileNodeWithDefinitions(node, definitions, isConst: isConst);
- if (constant != null) {
- definitions.setConstant(node, constant);
- }
- return constant;
- }
-}
-
-// TODO(johnniwinther): Decouple the creation of [ConstExp] and [Constant] from
-// front-end AST in order to reuse the evaluation for the shared front-end.
-class CompileTimeConstantEvaluator extends Visitor<AstConstant> {
- bool isEvaluatingConstant;
- final ConstantCompilerBase handler;
- final TreeElements elements;
- final Compiler compiler;
-
- Element get context => elements.analyzedElement;
-
- CompileTimeConstantEvaluator(this.handler,
- this.elements,
- this.compiler,
- {bool isConst: false})
- : this.isEvaluatingConstant = isConst;
-
- ConstantSystem get constantSystem => handler.constantSystem;
-
- AstConstant evaluate(Node node) {
- return node.accept(this);
- }
-
- AstConstant evaluateConstant(Node node) {
- bool oldIsEvaluatingConstant = isEvaluatingConstant;
- isEvaluatingConstant = true;
- AstConstant result = node.accept(this);
- isEvaluatingConstant = oldIsEvaluatingConstant;
- assert(result != null);
- return result;
- }
-
- AstConstant visitNode(Node node) {
- return signalNotCompileTimeConstant(node);
- }
-
- AstConstant visitLiteralBool(LiteralBool node) {
- return new AstConstant(
- context, node, new PrimitiveConstantExpression(
- constantSystem.createBool(node.value)));
- }
-
- AstConstant visitLiteralDouble(LiteralDouble node) {
- return new AstConstant(
- context, node, new PrimitiveConstantExpression(
- constantSystem.createDouble(node.value)));
- }
-
- AstConstant visitLiteralInt(LiteralInt node) {
- return new AstConstant(
- context, node, new PrimitiveConstantExpression(
- constantSystem.createInt(node.value)));
- }
-
- AstConstant visitLiteralList(LiteralList node) {
- if (!node.isConst) {
- return signalNotCompileTimeConstant(node);
- }
- List<ConstantExpression> argumentExpressions = <ConstantExpression>[];
- List<ConstantValue> argumentValues = <ConstantValue>[];
- for (Link<Node> link = node.elements.nodes;
- !link.isEmpty;
- link = link.tail) {
- AstConstant argument = evaluateConstant(link.head);
- if (argument == null) {
- return null;
- }
- argumentExpressions.add(argument.expression);
- argumentValues.add(argument.value);
- }
- DartType type = elements.getType(node);
- return new AstConstant(
- context, node, new ListConstantExpression(
- new ListConstantValue(type, argumentValues),
- type,
- argumentExpressions));
- }
-
- AstConstant visitLiteralMap(LiteralMap node) {
- if (!node.isConst) {
- return signalNotCompileTimeConstant(node);
- }
- List<ConstantExpression> keyExpressions = <ConstantExpression>[];
- List<ConstantValue> keyValues = <ConstantValue>[];
- Map<ConstantValue, ConstantExpression> map =
- new Map<ConstantValue, ConstantExpression>();
- for (Link<Node> link = node.entries.nodes;
- !link.isEmpty;
- link = link.tail) {
- LiteralMapEntry entry = link.head;
- AstConstant key = evaluateConstant(entry.key);
- if (key == null) {
- return null;
- }
- if (!map.containsKey(key.value)) {
- keyExpressions.add(key.expression);
- keyValues.add(key.value);
- } else {
- compiler.reportWarning(entry.key, MessageKind.EQUAL_MAP_ENTRY_KEY);
- }
- AstConstant value = evaluateConstant(entry.value);
- if (value == null) {
- return null;
- }
- map[key.value] = value.expression;
- }
- List<ConstantExpression> valueExpressions = map.values.toList();
- InterfaceType type = elements.getType(node);
- return new AstConstant(
- context, node, new MapConstantExpression(
- constantSystem.createMap(compiler, type, keyValues,
- valueExpressions.map((e) => e.value).toList()),
- type,
- keyExpressions,
- valueExpressions));
- }
-
- AstConstant visitLiteralNull(LiteralNull node) {
- return new AstConstant(
- context, node, new PrimitiveConstantExpression(
- constantSystem.createNull()));
- }
-
- AstConstant visitLiteralString(LiteralString node) {
- return new AstConstant(
- context, node, new PrimitiveConstantExpression(
- constantSystem.createString(node.dartString)));
- }
-
- AstConstant visitStringJuxtaposition(StringJuxtaposition node) {
- AstConstant left = evaluate(node.first);
- AstConstant right = evaluate(node.second);
- if (left == null || right == null) return null;
- StringConstantValue leftValue = left.value;
- StringConstantValue rightValue = right.value;
- return new AstConstant(
- context, node, new ConcatenateConstantExpression(
- constantSystem.createString(
- new DartString.concat(
- leftValue.primitiveValue, rightValue.primitiveValue)),
- [left.expression, right.expression]));
- }
-
- AstConstant visitStringInterpolation(StringInterpolation node) {
- List<ConstantExpression> subexpressions = <ConstantExpression>[];
- AstConstant initialString = evaluate(node.string);
- if (initialString == null) {
- return null;
- }
- subexpressions.add(initialString.expression);
- StringConstantValue initialStringValue = initialString.value;
- DartString accumulator = initialStringValue.primitiveValue;
- for (StringInterpolationPart part in node.parts) {
- AstConstant subexpression = evaluate(part.expression);
- if (subexpression == null) {
- return null;
- }
- subexpressions.add(subexpression.expression);
- ConstantValue expression = subexpression.value;
- DartString expressionString;
- if (expression.isNum || expression.isBool) {
- PrimitiveConstantValue primitive = expression;
- expressionString =
- new DartString.literal(primitive.primitiveValue.toString());
- } else if (expression.isString) {
- PrimitiveConstantValue primitive = expression;
- expressionString = primitive.primitiveValue;
- } else {
- // TODO(johnniwinther): Specialize message to indicated that the problem
- // is not constness but the types of the const expressions.
- return signalNotCompileTimeConstant(part.expression);
- }
- accumulator = new DartString.concat(accumulator, expressionString);
- AstConstant partString = evaluate(part.string);
- if (partString == null) return null;
- subexpressions.add(partString.expression);
- StringConstantValue partStringValue = partString.value;
- accumulator =
- new DartString.concat(accumulator, partStringValue.primitiveValue);
- };
- return new AstConstant(
- context, node, new ConcatenateConstantExpression(
- constantSystem.createString(accumulator),
- subexpressions));
- }
-
- AstConstant visitLiteralSymbol(LiteralSymbol node) {
- InterfaceType type = compiler.symbolClass.rawType;
- String text = node.slowNameString;
- List<AstConstant> arguments =
- <AstConstant>[new AstConstant(context, node,
- new PrimitiveConstantExpression(constantSystem.createString(
- new DartString.literal(text))))];
- AstConstant constant = makeConstructedConstant(
- compiler, handler, context, node, type, compiler.symbolConstructor,
- new Selector.callConstructor('', null, 1),
- arguments, arguments);
- return new AstConstant(
- context, node, new SymbolConstantExpression(constant.value, text));
- }
-
- AstConstant makeTypeConstant(Node node, DartType elementType) {
- DartType constantType =
- compiler.backend.typeImplementation.computeType(compiler);
- return new AstConstant(
- context, node, new TypeConstantExpression(
- new TypeConstantValue(elementType, constantType),
- elementType));
- }
-
- /// Returns true if the prefix of the send resolves to a deferred import
- /// prefix.
- bool isDeferredUse(Send send) {
- if (send == null) return false;
- return compiler.deferredLoadTask
- .deferredPrefixElement(send, elements) != null;
- }
-
- AstConstant visitIdentifier(Identifier node) {
- Element element = elements[node];
- if (Elements.isClass(element) || Elements.isTypedef(element)) {
- TypeDeclarationElement typeDeclarationElement = element;
- DartType type = typeDeclarationElement.rawType;
- return makeTypeConstant(node, type);
- }
- return signalNotCompileTimeConstant(node);
- }
-
- // TODO(floitsch): provide better error-messages.
- AstConstant visitSend(Send send) {
- Element element = elements[send];
- if (send.isPropertyAccess) {
- if (isDeferredUse(send)) {
- return signalNotCompileTimeConstant(send,
- message: MessageKind.DEFERRED_COMPILE_TIME_CONSTANT);
- }
- if (Elements.isStaticOrTopLevelFunction(element)) {
- return new AstConstant(
- context, send, new FunctionConstantExpression(
- new FunctionConstantValue(element),
- element));
- } else if (Elements.isStaticOrTopLevelField(element)) {
- ConstantExpression result;
- if (element.isConst) {
- result = handler.compileConstant(element);
- } else if (element.isFinal && !isEvaluatingConstant) {
- result = handler.compileVariable(element);
- }
- if (result != null) {
- return new AstConstant(
- context, send,
- new VariableConstantExpression(result.value, element));
- }
- } else if (Elements.isClass(element) || Elements.isTypedef(element)) {
- assert(elements.isTypeLiteral(send));
- return makeTypeConstant(send, elements.getTypeLiteralType(send));
- } else if (send.receiver != null) {
- // Fall through to error handling.
- } else if (!Elements.isUnresolved(element)
- && element.isVariable
- && element.isConst) {
- ConstantExpression result = handler.compileConstant(element);
- if (result != null) {
- return new AstConstant(
- context, send,
- new VariableConstantExpression(result.value, element));
- }
- }
- return signalNotCompileTimeConstant(send);
- } else if (send.isCall) {
- if (identical(element, compiler.identicalFunction)
- && send.argumentCount() == 2) {
- AstConstant left = evaluate(send.argumentsNode.nodes.head);
- AstConstant right = evaluate(send.argumentsNode.nodes.tail.head);
- if (left == null || right == null) {
- return null;
- }
- ConstantValue result =
- constantSystem.identity.fold(left.value, right.value);
- if (result != null) {
- return new AstConstant(
- context, send, new BinaryConstantExpression(result,
- left.expression, 'identical', right.expression));
- }
- }
- return signalNotCompileTimeConstant(send);
- } else if (send.isPrefix) {
- assert(send.isOperator);
- AstConstant receiverConstant = evaluate(send.receiver);
- if (receiverConstant == null) {
- return null;
- }
- Operator op = send.selector;
- UnaryOperation operation = constantSystem.lookupUnary(op.source);
- if (operation == null) {
- compiler.internalError(op, "Unexpected operator.");
- }
- ConstantValue folded = operation.fold(receiverConstant.value);
- if (folded == null) {
- return signalNotCompileTimeConstant(send);
- }
- return new AstConstant(
- context, send, new UnaryConstantExpression(folded,
- op.source, receiverConstant.expression));
- } else if (send.isOperator && !send.isPostfix) {
- assert(send.argumentCount() == 1);
- AstConstant left = evaluate(send.receiver);
- AstConstant right = evaluate(send.argumentsNode.nodes.head);
- if (left == null || right == null) {
- return null;
- }
- ConstantValue leftValue = left.value;
- ConstantValue rightValue = right.value;
- Operator op = send.selector.asOperator();
- ConstantValue folded = null;
- switch (op.source) {
- case "==":
- if (leftValue.isPrimitive && rightValue.isPrimitive) {
- folded = constantSystem.equal.fold(leftValue, rightValue);
- }
- break;
- case "!=":
- if (leftValue.isPrimitive && rightValue.isPrimitive) {
- BoolConstantValue areEquals =
- constantSystem.equal.fold(leftValue, rightValue);
- if (areEquals == null) {
- folded = null;
- } else {
- folded = areEquals.negate();
- }
- }
- break;
- default:
- BinaryOperation operation = constantSystem.lookupBinary(op.source);
- if (operation != null) {
- folded = operation.fold(leftValue, rightValue);
- }
- }
- if (folded == null) {
- return signalNotCompileTimeConstant(send);
- }
- return new AstConstant(
- context, send, new BinaryConstantExpression(folded,
- left.expression, op.source, right.expression));
- }
- return signalNotCompileTimeConstant(send);
- }
-
- AstConstant visitConditional(Conditional node) {
- AstConstant condition = evaluate(node.condition);
- if (condition == null) {
- return null;
- } else if (!condition.value.isBool) {
- DartType conditionType = condition.value.computeType(compiler);
- if (isEvaluatingConstant) {
- compiler.reportFatalError(
- node.condition, MessageKind.NOT_ASSIGNABLE,
- {'fromType': conditionType, 'toType': compiler.boolClass.rawType});
- }
- return null;
- }
- AstConstant thenExpression = evaluate(node.thenExpression);
- AstConstant elseExpression = evaluate(node.elseExpression);
- if (thenExpression == null || elseExpression == null) {
- return null;
- }
- BoolConstantValue boolCondition = condition.value;
- return new AstConstant(
- context, node, new ConditionalConstantExpression(
- boolCondition.primitiveValue
- ? thenExpression.value
- : elseExpression.value,
- condition.expression,
- thenExpression.expression,
- elseExpression.expression));
- }
-
- AstConstant visitSendSet(SendSet node) {
- return signalNotCompileTimeConstant(node);
- }
-
- /**
- * Returns the normalized list of constant arguments that are passed to the
- * constructor including both the concrete arguments and default values for
- * omitted optional arguments.
- *
- * Invariant: [target] must be an implementation element.
- */
- List<AstConstant> evaluateArgumentsToConstructor(
- Node node,
- Selector selector,
- Link<Node> arguments,
- FunctionElement target,
- {AstConstant compileArgument(Node node)}) {
- assert(invariant(node, target.isImplementation));
- List<AstConstant> compiledArguments = <AstConstant>[];
-
- AstConstant compileDefaultValue(VariableElement element) {
- ConstantExpression constant = handler.compileConstant(element);
- return new AstConstant.fromDefaultValue(element, constant);
- }
- target.computeSignature(compiler);
- bool succeeded = selector.addArgumentsToList(arguments,
- compiledArguments,
- target,
- compileArgument,
- compileDefaultValue,
- compiler.world);
- if (!succeeded) {
- String name = Elements.constructorNameForDiagnostics(
- target.enclosingClass.name, target.name);
- compiler.reportFatalError(
- node,
- MessageKind.INVALID_CONSTRUCTOR_ARGUMENTS,
- {'constructorName': name});
- }
- return compiledArguments;
- }
-
- AstConstant visitNewExpression(NewExpression node) {
- if (!node.isConst) {
- return signalNotCompileTimeConstant(node);
- }
-
- Send send = node.send;
- FunctionElement constructor = elements[send];
- if (Elements.isUnresolved(constructor)) {
- return signalNotCompileTimeConstant(node);
- }
-
- // Deferred types can not be used in const instance creation expressions.
- // Check if the constructor comes from a deferred library.
- if (isDeferredUse(node.send.selector.asSend())) {
- return signalNotCompileTimeConstant(node,
- message: MessageKind.DEFERRED_COMPILE_TIME_CONSTANT_CONSTRUCTION);
- }
-
- // TODO(ahe): This is nasty: we must eagerly analyze the
- // constructor to ensure the redirectionTarget has been computed
- // correctly. Find a way to avoid this.
- compiler.analyzeElement(constructor.declaration);
-
- InterfaceType type = elements.getType(node);
- Selector selector = elements.getSelector(send);
-
- Map<Node, AstConstant> concreteArgumentMap =
- <Node, AstConstant>{};
- for (Link<Node> link = send.arguments; !link.isEmpty; link = link.tail) {
- Node argument = link.head;
- NamedArgument namedArgument = argument.asNamedArgument();
- if (namedArgument != null) {
- argument = namedArgument.expression;
- }
- concreteArgumentMap[argument] = evaluateConstant(argument);
- }
-
- List<AstConstant> normalizedArguments =
- evaluateArgumentsToConstructor(
- node, selector, send.arguments, constructor.implementation,
- compileArgument: (node) => concreteArgumentMap[node]);
- List<AstConstant> concreteArguments =
- concreteArgumentMap.values.toList();
-
- if (constructor == compiler.intEnvironment ||
- constructor == compiler.boolEnvironment ||
- constructor == compiler.stringEnvironment) {
-
- AstConstant createEvaluatedConstant(ConstantValue value) {
- return new AstConstant(
- context, node, new ConstructedConstantExpresssion(
- value,
- type,
- constructor,
- elements.getSelector(send),
- concreteArguments.map((e) => e.expression).toList()));
- }
-
- var firstArgument = normalizedArguments[0].value;
- ConstantValue defaultValue = normalizedArguments[1].value;
-
- if (firstArgument.isNull) {
- compiler.reportFatalError(
- send.arguments.head, MessageKind.NULL_NOT_ALLOWED);
- return null;
- }
-
- if (!firstArgument.isString) {
- DartType type = defaultValue.computeType(compiler);
- compiler.reportFatalError(
- send.arguments.head, MessageKind.NOT_ASSIGNABLE,
- {'fromType': type, 'toType': compiler.stringClass.rawType});
- return null;
- }
-
- if (constructor == compiler.intEnvironment &&
- !(defaultValue.isNull || defaultValue.isInt)) {
- DartType type = defaultValue.computeType(compiler);
- compiler.reportFatalError(
- send.arguments.tail.head, MessageKind.NOT_ASSIGNABLE,
- {'fromType': type, 'toType': compiler.intClass.rawType});
- return null;
- }
-
- if (constructor == compiler.boolEnvironment &&
- !(defaultValue.isNull || defaultValue.isBool)) {
- DartType type = defaultValue.computeType(compiler);
- compiler.reportFatalError(
- send.arguments.tail.head, MessageKind.NOT_ASSIGNABLE,
- {'fromType': type, 'toType': compiler.boolClass.rawType});
- return null;
- }
-
- if (constructor == compiler.stringEnvironment &&
- !(defaultValue.isNull || defaultValue.isString)) {
- DartType type = defaultValue.computeType(compiler);
- compiler.reportFatalError(
- send.arguments.tail.head, MessageKind.NOT_ASSIGNABLE,
- {'fromType': type, 'toType': compiler.stringClass.rawType});
- return null;
- }
-
- String value =
- compiler.fromEnvironment(firstArgument.primitiveValue.slowToString());
-
- if (value == null) {
- return createEvaluatedConstant(defaultValue);
- } else if (constructor == compiler.intEnvironment) {
- int number = int.parse(value, onError: (_) => null);
- return createEvaluatedConstant(
- (number == null)
- ? defaultValue
- : constantSystem.createInt(number));
- } else if (constructor == compiler.boolEnvironment) {
- if (value == 'true') {
- return createEvaluatedConstant(constantSystem.createBool(true));
- } else if (value == 'false') {
- return createEvaluatedConstant(constantSystem.createBool(false));
- } else {
- return createEvaluatedConstant(defaultValue);
- }
- } else {
- assert(constructor == compiler.stringEnvironment);
- return createEvaluatedConstant(
- constantSystem.createString(new DartString.literal(value)));
- }
- } else {
- return makeConstructedConstant(
- compiler, handler, context,
- node, type, constructor, selector,
- concreteArguments, normalizedArguments);
- }
- }
-
- static AstConstant makeConstructedConstant(
- Compiler compiler,
- ConstantCompilerBase handler,
- Element context,
- Node node,
- InterfaceType type,
- ConstructorElement constructor,
- Selector selector,
- List<AstConstant> concreteArguments,
- List<AstConstant> normalizedArguments) {
- assert(invariant(node, selector.applies(constructor, compiler.world),
- message: "Selector $selector does not apply to constructor "
- "$constructor."));
-
- // The redirection chain of this element may not have been resolved through
- // a post-process action, so we have to make sure it is done here.
- compiler.resolver.resolveRedirectionChain(constructor, node);
- InterfaceType constructedType =
- constructor.computeEffectiveTargetType(type);
- ConstructorElement target = constructor.effectiveTarget;
- ClassElement classElement = target.enclosingClass;
- // The constructor must be an implementation to ensure that field
- // initializers are handled correctly.
- target = target.implementation;
- assert(invariant(node, target.isImplementation));
-
- ConstructorEvaluator evaluator = new ConstructorEvaluator(
- constructedType, target, handler, compiler);
- evaluator.evaluateConstructorFieldValues(normalizedArguments);
- List<AstConstant> fieldConstants =
- evaluator.buildFieldConstants(classElement);
-
- return new AstConstant(
- context, node, new ConstructedConstantExpresssion(
- new ConstructedConstantValue(
- constructedType,
- fieldConstants.map((e) => e.value).toList()),
- type,
- constructor,
- selector,
- concreteArguments.map((e) => e.expression).toList()));
- }
-
- AstConstant visitParenthesizedExpression(ParenthesizedExpression node) {
- return node.expression.accept(this);
- }
-
- error(Node node, MessageKind message) {
- // TODO(floitsch): get the list of constants that are currently compiled
- // and present some kind of stack-trace.
- compiler.reportFatalError(node, message);
- }
-
- AstConstant signalNotCompileTimeConstant(Node node,
- {MessageKind message: MessageKind.NOT_A_COMPILE_TIME_CONSTANT}) {
- if (isEvaluatingConstant) {
- error(node, message);
- }
- // Else we don't need to do anything. The final handler is only
- // optimistically trying to compile constants. So it is normal that we
- // sometimes see non-compile time constants.
- // Simply return [:null:] which is used to propagate a failing
- // compile-time compilation.
- return null;
- }
-}
-
-class ConstructorEvaluator extends CompileTimeConstantEvaluator {
- final InterfaceType constructedType;
- final ConstructorElement constructor;
- final Map<Element, AstConstant> definitions;
- final Map<Element, AstConstant> fieldValues;
-
- /**
- * Documentation wanted -- johnniwinther
- *
- * Invariant: [constructor] must be an implementation element.
- */
- ConstructorEvaluator(InterfaceType this.constructedType,
- FunctionElement constructor,
- ConstantCompiler handler,
- Compiler compiler)
- : this.constructor = constructor,
- this.definitions = new Map<Element, AstConstant>(),
- this.fieldValues = new Map<Element, AstConstant>(),
- super(handler,
- compiler.resolver.resolveMethodElement(constructor.declaration),
- compiler,
- isConst: true) {
- assert(invariant(constructor, constructor.isImplementation));
- }
-
- AstConstant visitSend(Send send) {
- Element element = elements[send];
- if (Elements.isLocal(element)) {
- AstConstant constant = definitions[element];
- if (constant == null) {
- compiler.internalError(send, "Local variable without value.");
- }
- return constant;
- }
- return super.visitSend(send);
- }
-
- void potentiallyCheckType(Node node,
- TypedElement element,
- AstConstant constant) {
- if (compiler.enableTypeAssertions) {
- DartType elementType = element.type.substByContext(constructedType);
- DartType constantType = constant.value.computeType(compiler);
- if (!constantSystem.isSubtype(compiler, constantType, elementType)) {
- compiler.withCurrentElement(constant.element, () {
- compiler.reportFatalError(
- constant.node, MessageKind.NOT_ASSIGNABLE,
- {'fromType': constantType, 'toType': elementType});
- });
- }
- }
- }
-
- void updateFieldValue(Node node,
- TypedElement element,
- AstConstant constant) {
- potentiallyCheckType(node, element, constant);
- fieldValues[element] = constant;
- }
-
- /**
- * Given the arguments (a list of constants) assigns them to the parameters,
- * updating the definitions map. If the constructor has field-initializer
- * parameters (like [:this.x:]), also updates the [fieldValues] map.
- */
- void assignArgumentsToParameters(List<AstConstant> arguments) {
- // Assign arguments to parameters.
- FunctionSignature signature = constructor.functionSignature;
- int index = 0;
- signature.orderedForEachParameter((ParameterElement parameter) {
- AstConstant argument = arguments[index++];
- Node node = parameter.node;
- if (parameter.isInitializingFormal) {
- InitializingFormalElement initializingFormal = parameter;
- updateFieldValue(node, initializingFormal.fieldElement, argument);
- } else {
- potentiallyCheckType(node, parameter, argument);
- definitions[parameter] = argument;
- }
- });
- }
-
- void evaluateSuperOrRedirectSend(List<AstConstant> compiledArguments,
- FunctionElement targetConstructor) {
- ConstructorEvaluator evaluator = new ConstructorEvaluator(
- constructedType.asInstanceOf(targetConstructor.enclosingClass),
- targetConstructor, handler, compiler);
- evaluator.evaluateConstructorFieldValues(compiledArguments);
- // Copy over the fieldValues from the super/redirect-constructor.
- // No need to go through [updateFieldValue] because the
- // assignments have already been checked in checked mode.
- evaluator.fieldValues.forEach((key, value) => fieldValues[key] = value);
- }
-
- /**
- * Runs through the initializers of the given [constructor] and updates
- * the [fieldValues] map.
- */
- void evaluateConstructorInitializers() {
- if (constructor.isSynthesized) {
- List<AstConstant> compiledArguments = <AstConstant>[];
-
- Function compileArgument = (element) => definitions[element];
- Function compileConstant = handler.compileConstant;
- FunctionElement target = constructor.definingConstructor.implementation;
- Selector.addForwardingElementArgumentsToList(constructor,
- compiledArguments,
- target,
- compileArgument,
- compileConstant,
- compiler.world);
- evaluateSuperOrRedirectSend(compiledArguments, target);
- return;
- }
- FunctionExpression functionNode = constructor.node;
- NodeList initializerList = functionNode.initializers;
-
- bool foundSuperOrRedirect = false;
-
- if (initializerList != null) {
- for (Link<Node> link = initializerList.nodes;
- !link.isEmpty;
- link = link.tail) {
- assert(link.head is Send);
- if (link.head is !SendSet) {
- // A super initializer or constructor redirection.
- Send call = link.head;
- FunctionElement target = elements[call];
- List<AstConstant> compiledArguments =
- evaluateArgumentsToConstructor(
- call, elements.getSelector(call), call.arguments, target,
- compileArgument: evaluateConstant);
- evaluateSuperOrRedirectSend(compiledArguments, target);
- foundSuperOrRedirect = true;
- } else {
- // A field initializer.
- SendSet init = link.head;
- Link<Node> initArguments = init.arguments;
- assert(!initArguments.isEmpty && initArguments.tail.isEmpty);
- AstConstant fieldValue = evaluate(initArguments.head);
- updateFieldValue(init, elements[init], fieldValue);
- }
- }
- }
-
- if (!foundSuperOrRedirect) {
- // No super initializer found. Try to find the default constructor if
- // the class is not Object.
- ClassElement enclosingClass = constructor.enclosingClass;
- ClassElement superClass = enclosingClass.superclass;
- if (enclosingClass != compiler.objectClass) {
- assert(superClass != null);
- assert(superClass.resolutionState == STATE_DONE);
-
- Selector selector =
- new Selector.callDefaultConstructor(enclosingClass.library);
-
- FunctionElement targetConstructor =
- superClass.lookupConstructor(selector);
- if (targetConstructor == null) {
- compiler.internalError(functionNode,
- "No default constructor available.");
- }
- List<AstConstant> compiledArguments =
- evaluateArgumentsToConstructor(
- functionNode, selector, const Link<Node>(), targetConstructor);
- evaluateSuperOrRedirectSend(compiledArguments, targetConstructor);
- }
- }
- }
-
- /**
- * Simulates the execution of the [constructor] with the given
- * [arguments] to obtain the field values that need to be passed to the
- * native JavaScript constructor.
- */
- void evaluateConstructorFieldValues(List<AstConstant> arguments) {
- compiler.withCurrentElement(constructor, () {
- assignArgumentsToParameters(arguments);
- evaluateConstructorInitializers();
- });
- }
-
- /// Builds a normalized list of the constant values for each field in the
- /// inheritance chain of [classElement].
- List<AstConstant> buildFieldConstants(ClassElement classElement) {
- List<AstConstant> fieldConstants = <AstConstant>[];
- classElement.implementation.forEachInstanceField(
- (ClassElement enclosing, FieldElement field) {
- AstConstant fieldValue = fieldValues[field];
- if (fieldValue == null) {
- // Use the default value.
- fieldValue = new AstConstant.fromDefaultValue(
- field, handler.compileConstant(field));
- }
- fieldConstants.add(fieldValue);
- },
- includeSuperAndInjectedMembers: true);
- return fieldConstants;
- }
-}
-
-/// A constant created from the front-end AST.
-///
-/// [element] and [node] point to the source location of the constant.
-/// [expression] holds the symbolic constant expression and [value] its constant
-/// value.
-///
-/// This class differs from [ConstantExpression] in that it is coupled to the
-/// front-end AST whereas [ConstantExpression] is only coupled to the element
-/// model.
-class AstConstant {
- final Element element;
- final Node node;
- final ConstantExpression expression;
-
- AstConstant(this.element, this.node, this.expression);
-
- factory AstConstant.fromDefaultValue(
- VariableElement element,
- ConstantExpression constant) {
- return new AstConstant(
- element,
- element.initializer != null ? element.initializer : element.node,
- constant);
- }
-
- ConstantValue get value => expression.value;
-
- String toString() => expression.toString();
-}
« no previous file with comments | « pkg/compiler/lib/src/common.dart ('k') | pkg/compiler/lib/src/compiler.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698