Chromium Code Reviews| Index: pkg/compiler/lib/src/cps_ir/cps_ir_builder_visitor.dart |
| diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_builder_visitor.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_builder_visitor.dart |
| index e800a5c94fe28ee1d877dc305e3b87795dfaa1cc..cffa732445e5a42174feff6c628aa1deddc96805 100644 |
| --- a/pkg/compiler/lib/src/cps_ir/cps_ir_builder_visitor.dart |
| +++ b/pkg/compiler/lib/src/cps_ir/cps_ir_builder_visitor.dart |
| @@ -66,7 +66,9 @@ class IrBuilderTask extends CompilerTask { |
| assert(invariant(element, !element.isNative)); |
| // TODO(kmillikin,sigurdm): Support constructors. |
| - if (element is ConstructorElement) return false; |
| + if (element is ConstructorElement && !element.isGenerativeConstructor) { |
| + return false; |
| + } |
| } else if (element is! FieldElement) { |
| compiler.internalError(element, "Unexpected elementtype $element"); |
| @@ -187,9 +189,91 @@ class IrBuilderVisitor extends ResolvedVisitor<ir.Primitive> |
| defaults.add(getConstantForVariable(element)); |
| }); |
| - visit(node.body); |
| + List<ir.Initializer> initializers; |
| + if (element.isGenerativeConstructor) { |
| + initializers = buildConstructorInitializers(node, element); |
| + visit(node.body); |
| + return irBuilder.makeConstructorDefinition(defaults, initializers); |
| + } else { |
| + visit(node.body); |
| + return irBuilder.makeFunctionDefinition(defaults); |
| + } |
| + } |
| + |
| + List<ir.Initializer> buildConstructorInitializers( |
| + ast.FunctionExpression function, ConstructorElement element) { |
| + List<ir.Initializer> result = new List<ir.Initializer>(); |
|
Kevin Millikin (Google)
2014/12/11 09:28:25
<ir.Initializer>[];
sigurdm
2014/12/17 10:20:56
Done.
|
| + FunctionSignature signature = element.functionSignature; |
| + |
| + void tryAddInitializingFormal(ParameterElement parameterElement) { |
| + if (parameterElement.isInitializingFormal) { |
| + InitializingFormalElement initializingFormal = parameterElement; |
| + withBuilder(new IrBuilder.delimited(irBuilder), () { |
| + ir.Primitive value = irBuilder.buildLocalGet(parameterElement); |
| + result.add(irBuilder.makeFieldInitializer( |
| + initializingFormal.fieldElement, |
| + irBuilder.makeRunnableBody(value))); |
| + }); |
| + } |
| + } |
| + |
| + // TODO(sigurdm): Preserve initializing formals as initializing formals. |
| + signature.orderedForEachParameter(tryAddInitializingFormal); |
| + |
| + if (function.initializers == null) return result; |
| + bool explicitSuperInitializer = false; |
| + for(ast.Node initializer in function.initializers) { |
| + if (initializer is ast.SendSet) { |
| + // Field initializer. |
| + FieldElement field = elements[initializer]; |
| + withBuilder(new IrBuilder.delimited(irBuilder), () { |
| + ir.Primitive value = visit(initializer.arguments.head); |
| + ir.RunnableBody body = irBuilder.makeRunnableBody(value); |
| + result.add(irBuilder.makeFieldInitializer(field, body)); |
| + }); |
| + } else if (initializer is ast.Send) { |
| + // Super or this initializer. |
| + if (ast.Initializers.isConstructorRedirect(initializer)) { |
| + giveup(initializer, "constructor redirect (this) initializer"); |
| + } |
| + ConstructorElement constructor = elements[initializer].implementation; |
| + Selector selector = elements.getSelector(initializer); |
| + List<ir.RunnableBody> arguments = |
| + initializer.arguments.mapToList((ast.Node argument) { |
| + return withBuilder(new IrBuilder.delimited(irBuilder), () { |
| + ir.Primitive value = visit(argument); |
| + return irBuilder.makeRunnableBody(value); |
| + }); |
| + }); |
| + result.add(irBuilder.makeSuperInitializer(constructor, |
| + selector, |
| + arguments)); |
| + explicitSuperInitializer = true; |
| + } else { |
| + compiler.internalError(initializer, |
| + "Unexpected initializer type $initializer"); |
| + } |
| - return irBuilder.makeFunctionDefinition(defaults); |
| + } |
| + if (!explicitSuperInitializer) { |
| + // No super initializer found. Try to find the default constructor if |
| + // the class is not Object. |
| + ClassElement enclosingClass = element.enclosingClass; |
| + if (!enclosingClass.isObject) { |
| + ClassElement superClass = enclosingClass.superclass; |
| + Selector selector = |
| + new Selector.callDefaultConstructor(enclosingClass.library); |
|
Kevin Millikin (Google)
2014/12/11 09:28:25
Too much indentation here.
sigurdm
2014/12/17 10:20:56
Done.
|
| + FunctionElement target = superClass.lookupConstructor(selector); |
| + if (target == null) { |
| + compiler.internalError(superClass, |
| + "No default constructor available."); |
| + } |
| + result.add(irBuilder.makeSuperInitializer(target, |
| + selector, |
| + <ir.RunnableBody>[])); |
| + } |
| + } |
| + return result; |
| } |
| ir.FunctionDefinition buildFunction(FunctionElement element) { |
| @@ -897,6 +981,7 @@ class DetectClosureVariables extends ast.Visitor { |
| DetectClosureVariables(this.elements); |
| FunctionElement currentFunction; |
| + bool insideInitializer = false; |
| Set<Local> usedFromClosure = new Set<Local>(); |
| Set<FunctionElement> recursiveFunctions = new Set<FunctionElement>(); |
| @@ -923,9 +1008,28 @@ class DetectClosureVariables extends ast.Visitor { |
| node.visitChildren(this); |
| } |
| + visitSendSet(ast.SendSet node) { |
| + visitSend(node); |
| + Element element = elements[node]; |
| + // Initializers in an initializer-list can communicate via parameters. |
| + // If a parameter is stored in an initializer list we box it. |
| + if (insideInitializer && |
| + Elements.isLocal(element) && |
| + element.isParameter) { |
| + LocalElement local = element; |
| + markAsClosureVariable(local); |
|
Kevin Millikin (Google)
2014/12/11 09:28:25
For now this is OK, but I think later we will want
sigurdm
2014/12/17 10:20:56
Acknowledged.
|
| + } |
| + node.visitChildren(this); |
|
Kevin Millikin (Google)
2014/12/11 09:28:25
This function visits all the children twice (once
sigurdm
2014/12/17 10:20:56
Made a helper that both visitSend and visitSendSet
|
| + } |
| + |
| visitFunctionExpression(ast.FunctionExpression node) { |
| FunctionElement oldFunction = currentFunction; |
| currentFunction = elements[node]; |
| + if (node.initializers != null) { |
| + insideInitializer = true; |
| + visit(node.initializers); |
| + insideInitializer = false; |
| + } |
| visit(node.body); |
| currentFunction = oldFunction; |
| } |