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

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 7fdfbbe43a1d29006a9f103e5b20e8b30f79f90e..eae8d2fa9a9ebf009b11a51d770492697680f1fd 100644
--- a/frog/leg/compile_time_constants.dart
+++ b/frog/leg/compile_time_constants.dart
@@ -538,7 +538,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);
});
}
@@ -672,21 +672,13 @@ 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(this.elements, this.compiler);
- CompileTimeConstantEvaluator.insideConstructor(this.constantHandler,
- this.elements,
- this.compiler,
- this.definitions);
-
- bool insideConstructor() => definitions !== null;
+ bool get insideConstructor() => false;
+ Map<Element, Constant> get definitions() => null;
ngeoffray 2012/03/27 11:30:33 Please consider removing these getters, and overri
floitsch 2012/03/28 00:10:58 I was afraid that a local could be a Prefix too. B
Constant evaluate(Node node) {
return node.accept(this);
@@ -721,7 +713,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;
}
@@ -755,7 +747,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);
@@ -763,7 +755,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;
}
@@ -810,7 +802,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);
@@ -833,7 +825,7 @@ class CompileTimeConstantEvaluator extends AbstractVisitor {
if (folded === null) error(send);
return folded;
} else if (Elements.isLocal(element)) {
- if (!insideConstructor()) error(send);
+ if (!insideConstructor) error(send);
Constant constant = definitions[element];
if (constant === null) {
compiler.internalError("Local variable without value", node: send);
@@ -933,126 +925,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> evaluateStaticSendArguments(Send send,
ngeoffray 2012/03/27 11:30:33 Since this is only used by the ConstructorEvaluato
floitsch 2012/03/28 00:10:58 It is actually used by the normal evaluator too (i
+ 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);
- });
-
+ Send send = node.send;
+ List<Constant> arguments = evaluateStaticSendArguments(send, constructor);
ngeoffray 2012/03/27 11:30:33 evaluateStaticSendArguments -> evaluateArgumentsTo
floitsch 2012/03/28 00:10:58 Done.
+ ConstructorEvaluator evaluator =
+ new ConstructorEvaluator(constructor, compiler);
+ evaluator.evaluateConstructorFieldValues(arguments);
ngeoffray 2012/03/27 11:30:33 Instead of passing arguments, I would pass the nod
floitsch 2012/03/28 00:10:58 Can't do that, because there is no Send for implic
+ 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;
}
@@ -1067,3 +977,130 @@ 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);
+
+ bool get insideConstructor() => true;
+
+ /**
+ * 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 =
+ evaluateStaticSendArguments(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