Chromium Code Reviews| Index: frog/leg/compile_time_constants.dart |
| diff --git a/frog/leg/compile_time_constants.dart b/frog/leg/compile_time_constants.dart |
| index c4d932b2cc919f28d4130e860bb5a8a758a00fc7..1324913b6375e504d54d95280081c3a16663859f 100644 |
| --- a/frog/leg/compile_time_constants.dart |
| +++ b/frog/leg/compile_time_constants.dart |
| @@ -683,8 +683,8 @@ class CompileTimeConstantEvaluator extends AbstractVisitor { |
| CompileTimeConstantEvaluator.insideConstructor(this.constantHandler, |
| this.elements, |
| - this.compiler, |
| - this.definitions); |
| + this.compiler) |
| + : definitions = new Map<Element, Constant>(); |
| bool insideConstructor() => definitions !== null; |
| @@ -933,117 +933,169 @@ class CompileTimeConstantEvaluator extends AbstractVisitor { |
| error(node); |
| } |
| - Constant visitNewExpression(NewExpression node) { |
| - 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; |
| - } |
| - }); |
| + List<Constant> evaluateConstructorArguments(Send send, |
| + FunctionElement constructor) { |
| + FunctionParameters parameters = constructor.computeParameters(compiler); |
| + if (send.arguments.isEmpty() && parameters.parameterCount == 0) { |
| + return const <Constant>[]; |
| + } |
| + List<Constant> arguments = <Constant>[]; |
| + Selector selector = elements.getSelector(send); |
| + |
| + Function compileArgument = (x) => evaluate(x); |
| + Function compileConstant = (x) => compiler.compileVariable(x); |
|
ahe
2012/03/23 10:56:15
What is up with this? Is there a VM bug? I have no
|
| + bool succeeded = selector.addSendArgumentsToList( |
| + send, arguments, parameters, compileArgument, compileConstant); |
| + if (!succeeded) error(send); |
| + return arguments; |
| + } |
| + |
| + void assignConstructorArgumentsToParameters( |
| + FunctionElement constructor, List<Constant> arguments, |
| + Map<Element, Constant> fieldValues) { |
| + // 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 evaluateConstructorInitializers( |
| + FunctionElement constructor, |
| + Set<FunctionElement> executedConstructors, |
| + Map<Element, Constant> fieldValues) { |
| + |
| + void evaluateSuperOrRedirectSend(FunctionElement targetConstructor, |
| + List<Constant> targetArguments) { |
| + compiler.withCurrentElement(targetConstructor, () { |
| + evaluateConstructorFieldValues( |
| + targetConstructor, targetArguments, executedConstructors, |
| + fieldValues); |
| + }); |
| } |
| - 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) { |
| + 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; |
| - assert(Initializers.isSuperConstructorCall(call) || |
| - Initializers.isConstructorRedirect(call)); |
| - compiler.unimplemented("ConstantHandler with this or super", |
| - node: call); |
| + FunctionElement targetConstructor = elements[call]; |
| + List<Constant> targetArguments = |
| + evaluateConstructorArguments(call, targetConstructor); |
| + evaluateSuperOrRedirectSend(targetConstructor, targetArguments); |
| + foundSuperOrRedirect = true; |
| } 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; |
| + 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>[]); |
| } |
| } |
| + } |
| + |
| + void evaluateConstructorFieldValues(FunctionElement constructor, |
| + List<Constant> arguments, |
| + Set<FunctionElement> executedConstructors, |
| + Map<Element, Constant> fieldValues) { |
| + compiler.withCurrentElement(constructor, () { |
| + if (executedConstructors.contains(constructor)) { |
| + MessageKind kind = MessageKind.REDIRECTING_CONSTRUCTOR_CYCLE; |
| + compiler.reportError(constructor.parseNode(compiler), |
| + new CompileTimeConstantError(kind, const [])); |
| + } |
| + executedConstructors.add(constructor); |
| + TreeElements constructorElements = |
| + compiler.resolver.resolveMethodElement(constructor); |
| + CompileTimeConstantEvaluator evaluator = |
| + new CompileTimeConstantEvaluator.insideConstructor( |
| + constantHandler, constructorElements, compiler); |
| + |
| + evaluator.assignConstructorArgumentsToParameters( |
| + constructor, arguments, fieldValues); |
| + evaluator.evaluateConstructorInitializers( |
| + constructor, executedConstructors, fieldValues); |
| + }); |
| + } |
| + |
| + Constant visitNewExpression(NewExpression node) { |
| 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); |
| + // 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 = constantHandler.compileVariable(member); |
| + } |
| + jsNewArguments.add(fieldValue); |
| } |
| - jsNewArguments.add(fieldValue); |
| } |
| - } |
| - if (classElement.superclass != compiler.coreLibrary.find(Types.OBJECT)) { |
| - compiler.unimplemented("ConstantHandler with super", node: node); |
| - } |
| + classElement = classElement.superclass; |
| + } |
| return jsNewArguments; |
| } |
| 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); |
| - |
| + // We use a set to avoid cyclic redirection constructors. |
| + Set<FunctionElement> executedConstructors = new Set<FunctionElement>(); |
| 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); |
| - } |
| + List<Constant> arguments = |
| + evaluateConstructorArguments(node.send, constructor); |
| + evaluateConstructorFieldValues( |
| + constructor, arguments, executedConstructors, fieldValues); |
| jsNewArguments = buildJsNewArguments(classElement, fieldValues); |
| }); |
| - |
| compiler.registerInstantiatedClass(classElement); |
| // TODO(floitsch): take generic types into account. |
| Type type = classElement.computeType(compiler); |