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

Unified Diff: frog/leg/compile_time_constants.dart

Issue 9753001: super and this in compile-time constants. (Closed) Base URL: /home/flo/programming/dart2/../dart/dart@master
Patch Set: Address comments Created 8 years, 9 months 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 | « no previous file | frog/leg/compiler.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: frog/leg/compile_time_constants.dart
diff --git a/frog/leg/compile_time_constants.dart b/frog/leg/compile_time_constants.dart
index 70a81db2cb2440ec417e1fd254fc24b1ac9f5b54..c481947dbd3fa7ca2d593d8a0d751e88d3948005 100644
--- a/frog/leg/compile_time_constants.dart
+++ b/frog/leg/compile_time_constants.dart
@@ -532,7 +532,7 @@ class ConstantHandler extends CompilerTask {
return measure(() {
assert(node !== null);
CompileTimeConstantEvaluator evaluator =
- new CompileTimeConstantEvaluator(this, definitions, compiler);
+ new CompileTimeConstantEvaluator(definitions, compiler);
return evaluator.evaluate(node);
});
}
@@ -666,21 +666,10 @@ class ConstantHandler extends CompilerTask {
}
class CompileTimeConstantEvaluator extends AbstractVisitor {
- final ConstantHandler constantHandler;
final TreeElements elements;
final Compiler compiler;
- final Map<Element, Constant> definitions = null;
- CompileTimeConstantEvaluator(this.constantHandler,
- this.elements,
- this.compiler);
-
- CompileTimeConstantEvaluator.insideConstructor(this.constantHandler,
- this.elements,
- this.compiler,
- this.definitions);
-
- bool insideConstructor() => definitions !== null;
+ CompileTimeConstantEvaluator(this.elements, this.compiler);
Constant evaluate(Node node) {
return node.accept(this);
@@ -713,7 +702,7 @@ class CompileTimeConstantEvaluator extends AbstractVisitor {
// TODO(floitsch): get type from somewhere.
Type type = null;
Constant constant = new ListConstant(type, arguments);
- constantHandler.registerCompileTimeConstant(constant);
+ compiler.constantHandler.registerCompileTimeConstant(constant);
return constant;
}
@@ -747,7 +736,7 @@ class CompileTimeConstantEvaluator extends AbstractVisitor {
// TODO(floitsch): this should be a List<String> type.
Type keysType = null;
ListConstant keysList = new ListConstant(keysType, keys);
- constantHandler.registerCompileTimeConstant(keysList);
+ compiler.constantHandler.registerCompileTimeConstant(keysList);
ClassElement classElement =
compiler.jsHelperLibrary.find(MapConstant.DART_CLASS);
classElement.ensureResolved(compiler);
@@ -755,7 +744,7 @@ class CompileTimeConstantEvaluator extends AbstractVisitor {
Type type = new SimpleType(classElement.name, classElement);
compiler.registerInstantiatedClass(classElement);
Constant constant = new MapConstant(type, keysList, values);
- constantHandler.registerCompileTimeConstant(constant);
+ compiler.constantHandler.registerCompileTimeConstant(constant);
return constant;
}
@@ -802,7 +791,7 @@ class CompileTimeConstantEvaluator extends AbstractVisitor {
!element.modifiers.isFinal()) {
error(send);
}
- return constantHandler.compileVariable(element);
+ return compiler.compileVariable(element);
} else if (send.isPrefix) {
assert(send.isOperator);
Constant receiverConstant = evaluate(send.receiver);
@@ -824,13 +813,6 @@ class CompileTimeConstantEvaluator extends AbstractVisitor {
}
if (folded === null) error(send);
return folded;
- } else if (Elements.isLocal(element)) {
- if (!insideConstructor()) error(send);
- Constant constant = definitions[element];
- if (constant === null) {
- compiler.internalError("Local variable without value", node: send);
- }
- return constant;
} else if (send.isOperator && !send.isPostfix) {
assert(send.argumentCount() == 1);
Constant left = evaluate(send.receiver);
@@ -931,126 +913,44 @@ class CompileTimeConstantEvaluator extends AbstractVisitor {
error(node);
}
- Constant visitNewExpression(NewExpression node) {
- Element currentElement = compiler.currentElement;
-
- void assignArgumentsToParameters(
- FunctionParameters parameters,
- Map<Element, Constant> constructorDefinitions,
- Map<Element, Constant> fieldValues) {
- Send send = node.send;
- if (send.arguments.isEmpty() && parameters.parameterCount == 0) return;
- List<Constant> arguments = <Constant>[];
- Selector selector = elements.getSelector(send);
-
- Function compileArgument = evaluate;
- Function compileConstant = constantHandler.compileVariable;
- bool succeeded = selector.addSendArgumentsToList(
- send, arguments, parameters, compileArgument, compileConstant);
- if (!succeeded) error(node);
-
- int index = 0;
- parameters.forEachParameter((Element parameter) {
- Constant argument = arguments[index++];
- constructorDefinitions[parameter] = argument;
- if (parameter.kind == ElementKind.FIELD_PARAMETER) {
- FieldParameterElement fieldParameterElement = parameter;
- fieldValues[fieldParameterElement.fieldElement] = argument;
- }
- });
- }
-
- void compileInitializers(Link<Node> initializers,
- CompileTimeConstantEvaluator evaluator,
- TreeElements constructorElements,
- Map<Element, Constant> constructorDefinitions,
- Map<Element, Constant> fieldValues) {
- for (Link<Node> link = initializers; !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;
- assert(Initializers.isSuperConstructorCall(call) ||
- Initializers.isConstructorRedirect(call));
- compiler.unimplemented("ConstantHandler with this or super",
- node: call);
- } else {
- // A field initializer.
- SendSet init = link.head;
- Link<Node> arguments = init.arguments;
- assert(!arguments.isEmpty() && arguments.tail.isEmpty());
- Constant fieldValue = evaluator.evaluate(arguments.head);
- fieldValues[constructorElements[init]] = fieldValue;
- }
- }
- }
-
- List<Constant> buildJsNewArguments(ClassElement classElement,
- Map<Element, Constant> fieldValues) {
- List<Constant> jsNewArguments = <Constant>[];
- for (Element member in classElement.members) {
- if (member.isInstanceMember() && member.kind == ElementKind.FIELD) {
- Constant fieldValue = fieldValues[member];
- if (fieldValue === null) {
- // Use the default value.
- fieldValue = constantHandler.compileVariable(member);
- }
- jsNewArguments.add(fieldValue);
- }
- }
- if (classElement.superclass != compiler.coreLibrary.find(Types.OBJECT)) {
- compiler.withCurrentElement(currentElement, () {
- compiler.unimplemented("ConstantHandler with super", node: node);
- });
- }
- return jsNewArguments;
- }
+ /** Returns the list of constants that are passed to the static function. */
+ List<Constant> evaluateArgumentsToConstructor(Send send,
+ FunctionElement target) {
+ FunctionParameters parameters = target.computeParameters(compiler);
+ List<Constant> arguments = <Constant>[];
+ Selector selector = elements.getSelector(send);
+
+ Function compileArgument = evaluate;
+ Function compileConstant = compiler.compileVariable;
+ bool succeeded = selector.addSendArgumentsToList(
+ send, arguments, parameters, compileArgument, compileConstant);
+ if (!succeeded) error(send);
+ return arguments;
+ }
+ Constant visitNewExpression(NewExpression node) {
if (!node.isConst()) error(node);
FunctionElement constructor = elements[node.send];
- TreeElements constructorElements =
- compiler.resolver.resolveMethodElement(constructor);
- if (constructor != constructor.defaultImplementation) {
+ ClassElement classElement = constructor.enclosingElement;
+ if (classElement.isInterface()) {
+ compiler.resolver.resolveMethodElement(constructor);
constructor = constructor.defaultImplementation;
- constructorElements =
- compiler.resolver.resolveMethodElement(constructor);
+ classElement = constructor.enclosingElement;
}
- List<Constant> jsNewArguments;
- ClassElement classElement = constructor.enclosingElement;
- compiler.withCurrentElement(constructor, () {
- FunctionExpression functionNode = constructor.parseNode(compiler);
- NodeList initializerList = functionNode.initializers;
- FunctionParameters parameters = constructor.computeParameters(compiler);
-
- Map<Element, Constant> fieldValues = new Map<Element, Constant>();
- Map<Element, Constant> constructorDefinitions =
- new Map<Element, Constant>();
-
- assignArgumentsToParameters(parameters, constructorDefinitions,
- fieldValues);
- CompileTimeConstantEvaluator initializerEvaluator =
- new CompileTimeConstantEvaluator.insideConstructor(
- constantHandler, constructorElements, compiler,
- constructorDefinitions);
- if (initializerList !== null) {
- Link<Node> initializers = functionNode.initializers.nodes;
- compileInitializers(initializers,
- initializerEvaluator,
- constructorElements,
- constructorDefinitions,
- fieldValues);
- }
- jsNewArguments = buildJsNewArguments(classElement, fieldValues);
- });
-
+ List<Constant> arguments =
+ evaluateArgumentsToConstructor(node.send, constructor);
+ ConstructorEvaluator evaluator =
+ new ConstructorEvaluator(constructor, compiler);
+ evaluator.evaluateConstructorFieldValues(arguments);
+ List<Constant>jsNewArguments = evaluator.buildJsNewArguments(classElement);
compiler.registerInstantiatedClass(classElement);
// TODO(floitsch): take generic types into account.
Type type = classElement.computeType(compiler);
Constant constant = new ConstructedConstant(type, jsNewArguments);
- constantHandler.registerCompileTimeConstant(constant);
+ compiler.constantHandler.registerCompileTimeConstant(constant);
return constant;
}
@@ -1065,3 +965,140 @@ class CompileTimeConstantEvaluator extends AbstractVisitor {
compiler.reportError(node, new CompileTimeConstantError(kind, const []));
}
}
+
+class ConstructorEvaluator extends CompileTimeConstantEvaluator {
+ FunctionElement constructor;
+ final Map<Element, Constant> definitions;
+ final Map<Element, Constant> fieldValues;
+
+ ConstructorEvaluator(FunctionElement constructor, Compiler compiler)
+ : this.constructor = constructor,
+ this.definitions = new Map<Element, Constant>(),
+ this.fieldValues = new Map<Element, Constant>(),
+ super(compiler.resolver.resolveMethodElement(constructor),
+ compiler);
+
+ Constant visitSend(Send send) {
+ Element element = elements[send];
+ if (Elements.isLocal(element)) {
+ Constant constant = definitions[element];
+ if (constant === null) {
+ compiler.internalError("Local variable without value", node: send);
+ }
+ return constant;
+ }
+ return super.visitSend(send);
+ }
+
+ /**
+ * 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<Constant> arguments) {
+ // Assign arguments to parameters.
+ FunctionParameters parameters = constructor.computeParameters(compiler);
+ int index = 0;
+ parameters.forEachParameter((Element parameter) {
+ Constant argument = arguments[index++];
+ definitions[parameter] = argument;
+ if (parameter.kind == ElementKind.FIELD_PARAMETER) {
+ FieldParameterElement fieldParameterElement = parameter;
+ fieldValues[fieldParameterElement.fieldElement] = argument;
+ }
+ });
+ }
+
+ void evaluateSuperOrRedirectSend(FunctionElement targetConstructor,
+ List<Constant> targetArguments) {
+ ConstructorEvaluator evaluator =
+ new ConstructorEvaluator(targetConstructor, compiler);
+ evaluator.evaluateConstructorFieldValues(targetArguments);
+ // Copy over the fieldValues from the super/redirect-constructor.
+ evaluator.fieldValues.forEach((key, value) => fieldValues[key] = value);
+ }
+
+ /**
+ * Runs through the initializers of the given [constructor] and updates
+ * the [fieldValues] map.
+ */
+ void evaluateConstructorInitializers() {
+ FunctionExpression functionNode = constructor.parseNode(compiler);
+ 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 targetConstructor = elements[call];
+ List<Constant> targetArguments =
+ evaluateArgumentsToConstructor(call, targetConstructor);
+ evaluateSuperOrRedirectSend(targetConstructor, targetArguments);
+ foundSuperOrRedirect = true;
+ } else {
+ // A field initializer.
+ SendSet init = link.head;
+ Link<Node> initArguments = init.arguments;
+ assert(!initArguments.isEmpty() && initArguments.tail.isEmpty());
+ Constant fieldValue = evaluate(initArguments.head);
+ fieldValues[elements[init]] = fieldValue;
+ }
+ }
+ }
+
+ if (!foundSuperOrRedirect) {
+ // No super initializer found. Try to find the default constructor if
+ // the class is not Object.
+ ClassElement enclosingClass = constructor.enclosingElement;
+ ClassElement superClass = enclosingClass.superclass;
+ if (enclosingClass != compiler.objectClass) {
+ assert(superClass !== null);
+ assert(superClass.isResolved);
+ FunctionElement targetConstructor =
+ superClass.lookupConstructor(superClass.name);
+ if (targetConstructor === null) {
+ compiler.internalError("no default constructor available");
+ }
+ evaluateSuperOrRedirectSend(targetConstructor, const <Constant>[]);
+ }
+ }
+ }
+
+ /**
+ * 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<Constant> arguments) {
+ compiler.withCurrentElement(constructor, () {
+ assignArgumentsToParameters(arguments);
+ evaluateConstructorInitializers();
+ });
+ }
+
+ List<Constant> buildJsNewArguments(ClassElement classElement) {
+ List<Constant> jsNewArguments = <Constant>[];
+ // TODO(floitsch): share this code with the emitter, so that we don't
+ // need to care about the order of fields here.
+ while (classElement != compiler.objectClass) {
+ for (Element member in classElement.members) {
+ if (member.isInstanceMember() && member.kind == ElementKind.FIELD) {
+ Constant fieldValue = fieldValues[member];
+ if (fieldValue === null) {
+ // Use the default value.
+ fieldValue = compiler.compileVariable(member);
+ }
+ jsNewArguments.add(fieldValue);
+ }
+ }
+ classElement = classElement.superclass;
+ }
+ return jsNewArguments;
+ }
+}
« no previous file with comments | « no previous file | frog/leg/compiler.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698