Chromium Code Reviews| Index: pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart |
| diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart |
| index 5252b0f04a9c175cd6def2a89af33c1f407aa0b4..1a3d1bbf5dd5bdcb319974ff64a1ddf8fa742a44 100644 |
| --- a/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart |
| +++ b/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart |
| @@ -140,8 +140,7 @@ abstract class IrBuilderVisitor extends ast.Visitor<ir.Primitive> |
| BaseImplementationOfDynamicsMixin<ir.Primitive, dynamic>, |
| BaseImplementationOfConstantsMixin<ir.Primitive, dynamic>, |
| BaseImplementationOfSuperIncDecsMixin<ir.Primitive, dynamic>, |
| - BaseImplementationOfNewMixin<ir.Primitive, dynamic>, |
| - ErrorBulkMixin<ir.Primitive, dynamic> |
| + BaseImplementationOfNewMixin<ir.Primitive, dynamic> |
| implements SemanticSendVisitor<ir.Primitive, dynamic> { |
| final TreeElements elements; |
| final Compiler compiler; |
| @@ -178,11 +177,6 @@ abstract class IrBuilderVisitor extends ast.Visitor<ir.Primitive> |
| this.compiler, |
| this.sourceInformationBuilder); |
| - @override |
| - bulkHandleNode(ast.Node node, String message, _) { |
| - giveup(node, message.replaceFirst('#', '$node')); |
| - } |
| - |
| String bailoutMessage = null; |
| @override |
| @@ -223,6 +217,28 @@ abstract class IrBuilderVisitor extends ast.Visitor<ir.Primitive> |
| CallStructure callStructure, |
| List<ir.Primitive> arguments); |
| + /// Creates a [TypedSelector] variant of [newSelector] using the type of |
| + /// [oldSelector], if available. |
| + /// |
| + /// This is needed to preserve inferred receiver types when creating new |
| + /// selectors. |
| + Selector useSelectorType(Selector newSelector, Selector oldSelector) { |
| + // TODO(asgerf,johnniwinther): This works but it is brittle. |
| + // We should decouple selectors from inferred receiver type masks. |
| + // TODO(asgerf): Use this whenever we create a selector for a dynamic call. |
| + if (oldSelector is TypedSelector) { |
| + return new TypedSelector(oldSelector.mask, newSelector, compiler.world); |
| + } else { |
| + return newSelector; |
| + } |
| + } |
| + |
| + /// Like [useSelectorType], except the original typed selector is obtained |
| + /// from the [node]. |
| + Selector useSelectorTypeOfNode(Selector newSelector, ast.Send node) { |
| + return useSelectorType(newSelector, elements.getSelector(node)); |
| + } |
| + |
| ir.RootNode _makeFunctionBody(FunctionElement element, |
| ast.FunctionExpression node) { |
| FunctionSignature signature = element.functionSignature; |
| @@ -614,12 +630,6 @@ abstract class IrBuilderVisitor extends ast.Visitor<ir.Primitive> |
| return translateConstant(node); |
| } |
| - ir.Primitive visitIdentifier(ast.Identifier node) { |
| - // "this" is the only identifier that should be met by the visitor. |
| - assert(node.isThis()); |
| - return irBuilder.buildThis(); |
| - } |
| - |
| ir.Primitive visitParenthesizedExpression( |
| ast.ParenthesizedExpression node) { |
| assert(irBuilder.isOpen); |
| @@ -795,23 +805,20 @@ abstract class IrBuilderVisitor extends ast.Visitor<ir.Primitive> |
| } |
| @override |
| - ir.Primitive visitUnresolvedGet( |
| - ast.Send node, |
| - Element element, |
| - _) { |
| - return giveup(node, 'visitUnresolvedGet'); |
| - } |
| - |
| - @override |
| ir.Primitive visitUnresolvedSuperGet( |
| ast.Send node, |
| - Element element, |
| - _) { |
| - return giveup(node, 'visitUnresolvedSuperGet'); |
| + Element element, _) { |
| + return buildInstanceNoSuchMethod(elements.getSelector(node), []); |
| } |
| @override |
| ir.Primitive visitThisGet(ast.Identifier node, _) { |
| + if (irBuilder.state.thisParameter == null) { |
| + // TODO(asgerf,johnniwinther): Should be in a visitInvalidThis method. |
| + // 'this' in static context. Just translate to null. |
| + assert(compiler.compilationFailed); |
| + return irBuilder.buildNullConstant(); |
| + } |
| return irBuilder.buildThis(); |
| } |
| @@ -933,16 +940,6 @@ abstract class IrBuilderVisitor extends ast.Visitor<ir.Primitive> |
| } |
| @override |
| - ir.Primitive visitUnresolvedSuperBinary( |
| - ast.Send node, |
| - Element element, |
| - op.BinaryOperator operator, |
| - ast.Node argument, |
| - _) { |
| - return giveup(node, 'visitUnresolvedSuperBinary'); |
| - } |
| - |
| - @override |
| ir.Primitive visitSuperIndex( |
| ast.Send node, |
| FunctionElement function, |
| @@ -952,15 +949,6 @@ abstract class IrBuilderVisitor extends ast.Visitor<ir.Primitive> |
| } |
| @override |
| - ir.Primitive visitUnresolvedSuperIndex( |
| - ast.Send node, |
| - Element element, |
| - ast.Node index, |
| - _) { |
| - return giveup(node, 'visitUnresolvedSuperIndex'); |
| - } |
| - |
| - @override |
| ir.Primitive visitEquals( |
| ast.Send node, |
| ast.Node left, |
| @@ -1028,15 +1016,6 @@ abstract class IrBuilderVisitor extends ast.Visitor<ir.Primitive> |
| function, CallStructure.NO_ARGS, const []); |
| } |
| - @override |
| - ir.Primitive visitUnresolvedSuperUnary( |
| - ast.Send node, |
| - op.UnaryOperator operator, |
| - Element element, |
| - _) { |
| - return giveup(node, 'visitUnresolvedSuperUnary'); |
| - } |
| - |
| // TODO(johnniwinther): Handle this in the [IrBuilder] to ensure the correct |
| // semantic correlation between arguments and invocation. |
| List<ir.Primitive> translateDynamicArguments(ast.NodeList nodeList, |
| @@ -1140,9 +1119,10 @@ abstract class IrBuilderVisitor extends ast.Visitor<ir.Primitive> |
| ast.Send node, |
| MethodElement function, |
| ast.NodeList arguments, |
| - CallStructure callStructure, |
| - _) { |
| - return giveup(node, 'handleStaticFunctionIncompatibleInvoke'); |
| + CallStructure callStructure, _) { |
|
Kevin Millikin (Google)
2015/05/08 08:30:06
I liked the old indentation better. I can't extra
asgerf
2015/05/08 09:38:57
It's a judgement call. Irrelevant details can turn
|
| + return buildStaticNoSuchMethod( |
| + elements.getSelector(node), |
| + arguments.nodes.mapToList(visit)); |
| } |
| @override |
| @@ -1203,19 +1183,10 @@ abstract class IrBuilderVisitor extends ast.Visitor<ir.Primitive> |
| ast.Send node, |
| MethodElement method, |
| ast.NodeList arguments, |
| - CallStructure callStructure, |
| - _) { |
| - return giveup(node, 'visitSuperMethodIncompatibleInvoke'); |
| - } |
| - |
| - @override |
| - ir.Primitive visitUnresolvedInvoke( |
| - ast.Send node, |
| - Element element, |
| - ast.NodeList arguments, |
| - Selector selector, |
| - _) { |
| - return giveup(node, 'visitUnresolvedInvoke'); |
| + CallStructure callStructure, _) { |
| + return buildInstanceNoSuchMethod( |
| + elements.getSelector(node), |
| + translateDynamicArguments(arguments, callStructure)); |
| } |
| @override |
| @@ -1223,9 +1194,10 @@ abstract class IrBuilderVisitor extends ast.Visitor<ir.Primitive> |
| ast.Send node, |
| Element element, |
| ast.NodeList arguments, |
| - Selector selector, |
| - _) { |
| - return giveup(node, 'visitUnresolvedSuperInvoke'); |
| + Selector selector, _) { |
| + return buildInstanceNoSuchMethod( |
| + elements.getSelector(node), |
| + translateDynamicArguments(arguments, selector.callStructure)); |
| } |
| @override |
| @@ -1867,130 +1839,857 @@ abstract class IrBuilderVisitor extends ast.Visitor<ir.Primitive> |
| return irBuilder.buildNonTailThrow(visit(node.expression)); |
| } |
| - ir.RootNode nullIfGiveup(ir.RootNode action()) { |
| - try { |
| - return action(); |
| - } catch(e) { |
| - if (e == ABORT_IRNODE_BUILDER) { |
| - return null; |
| - } |
| - rethrow; |
| + ir.Primitive buildStaticNoSuchMethod( |
| + Selector selector, |
| + List<ir.Primitive> arguments); |
| + |
| + ir.Primitive buildInstanceNoSuchMethod( |
| + Selector selector, |
| + List<ir.Primitive> arguments); |
| + |
| + ir.Primitive buildRuntimeError(String message); |
| + |
| + ir.Primitive buildAbstractClassInstantiationError(ClassElement element); |
| + |
| + @override |
| + ir.Primitive errorInvalidAssert( |
| + ast.Send node, |
| + ast.NodeList arguments, _) { |
| + if (compiler.enableUserAssertions) { |
| + return giveup(node, 'Assert'); |
| + } else { |
| + return irBuilder.buildNullConstant(); |
| } |
| } |
| - void internalError(ast.Node node, String message) { |
| - giveup(node, message); |
| + @override |
| + ir.Primitive errorUnresolvedCompound( |
| + ast.Send node, |
| + Element element, |
| + op.AssignmentOperator operator, |
| + ast.Node rhs, _) { |
| + // TODO(asgerf): What is unresolved? The getter and/or the setter? |
| + // If it was th setter, we must evaluate right-hand side. |
|
floitsch
2015/05/08 03:03:40
was th*e* setter, we must evaluate *the* right-han
asgerf
2015/05/08 08:17:58
Done.
|
| + return buildStaticNoSuchMethod(elements.getSelector(node), []); |
| } |
| @override |
| - visitNode(ast.Node node) { |
| - internalError(node, "Unhandled node"); |
| + ir.Primitive visitUnresolvedClassConstructorInvoke( |
| + ast.NewExpression node, |
| + Element element, |
| + DartType type, |
| + ast.NodeList arguments, |
| + Selector selector, _) { |
| + // If the class is missing it's a runtime error. |
| + return buildRuntimeError("Unresolved class: '${element.name}'"); |
| } |
| - dynamic giveup(ast.Node node, [String reason]) { |
| - bailoutMessage = '($node): $reason'; |
| - throw ABORT_IRNODE_BUILDER; |
| + @override |
| + ir.Primitive visitUnresolvedConstructorInvoke( |
| + ast.NewExpression node, |
| + Element constructor, |
| + DartType type, |
| + ast.NodeList arguments, |
| + Selector selector, _) { |
| + // If the class is there but the constructor is missing, it's an NSM error. |
| + return buildStaticNoSuchMethod(selector, |
| + translateDynamicArguments(arguments, selector.callStructure)); |
| } |
| -} |
| -final String ABORT_IRNODE_BUILDER = "IrNode builder aborted"; |
| + @override |
| + ir.Primitive errorNonConstantConstructorInvoke( |
| + ast.NewExpression node, |
| + Element element, |
| + InterfaceType type, |
| + ast.NodeList arguments, |
| + CallStructure callStructure, _) { |
| + assert(compiler.compilationFailed); |
| + return irBuilder.buildNullConstant(); |
| + } |
| -/// Classifies local variables and local functions as captured, if they |
| -/// are accessed from within a nested function. |
| -/// |
| -/// This class is specific to the [DartIrBuilder], in that it gives up if it |
| -/// sees a feature that is currently unsupport by that builder. In particular, |
| -/// loop variables captured in a for-loop initializer, condition, or update |
| -/// expression are unsupported. |
| -class DartCapturedVariables extends ast.Visitor { |
| - final TreeElements elements; |
| - DartCapturedVariables(this.elements); |
| + @override |
| + ir.Primitive visitUnresolvedGet( |
| + ast.Send node, |
| + Element element, _) { |
| + return buildStaticNoSuchMethod(elements.getSelector(node), []); |
| + } |
| - FunctionElement currentFunction; |
| - bool insideInitializer = false; |
| - Set<Local> capturedVariables = new Set<Local>(); |
| + @override |
| + ir.Primitive visitUnresolvedInvoke( |
| + ast.Send node, |
| + Element element, |
| + ast.NodeList arguments, |
| + Selector selector, _) { |
| + return buildStaticNoSuchMethod(elements.getSelector(node), |
| + arguments.nodes.mapToList(visit)); |
| + } |
| - Map<ast.TryStatement, TryStatementInfo> tryStatements = |
| - <ast.TryStatement, TryStatementInfo>{}; |
| + @override |
| + ir.Primitive errorUnresolvedPostfix( |
| + ast.Send node, |
| + Element element, |
| + op.IncDecOperator operator, _) { |
| + // TODO(asgerf): Which ones are missing? The getter and/or the setter? |
| + return buildStaticNoSuchMethod(elements.getSelector(node), []); |
| + } |
| - List<TryStatementInfo> tryNestingStack = <TryStatementInfo>[]; |
| - bool get inTryStatement => tryNestingStack.isNotEmpty; |
| + @override |
| + ir.Primitive errorUnresolvedPrefix( |
| + ast.Send node, |
| + Element element, |
| + op.IncDecOperator operator, _) { |
| + // TODO(asgerf): Which ones are missing? The getter and/or the setter? |
| + return buildStaticNoSuchMethod(elements.getSelector(node), []); |
| + } |
| + |
| + @override |
| + ir.Primitive visitUnresolvedRedirectingFactoryConstructorInvoke( |
| + ast.NewExpression node, |
| + ConstructorElement constructor, |
| + InterfaceType type, |
| + ast.NodeList arguments, |
| + CallStructure callStructure, _) { |
| + String nameString = Elements.reconstructConstructorName(constructor); |
| + Name name = new Name(nameString, constructor.library); |
| + return buildStaticNoSuchMethod( |
| + new Selector(SelectorKind.CALL, name, callStructure), |
| + translateDynamicArguments(arguments, callStructure)); |
| + } |
| - String bailoutMessage = null; |
| + @override |
| + ir.Primitive errorUnresolvedSet( |
| + ast.Send node, |
| + Element element, |
| + ast.Node rhs, _) { |
| + return buildStaticNoSuchMethod(elements.getSelector(node), [visit(rhs)]); |
|
Kevin Millikin (Google)
2015/05/08 08:30:06
I'd rather name the value of visit(rhs). I'm alle
asgerf
2015/05/08 09:38:57
The real problem is the repetitive code. If we wer
|
| + } |
| - giveup(ast.Node node, [String reason]) { |
| - bailoutMessage = '($node): $reason'; |
| - throw ABORT_IRNODE_BUILDER; |
| + @override |
| + ir.Primitive errorUnresolvedSuperCompoundIndexSet( |
| + ast.SendSet node, |
| + Element element, |
| + ast.Node index, |
| + op.AssignmentOperator operator, |
| + ast.Node rhs, _) { |
| + // Assume the index getter is missing. |
| + Selector selector = useSelectorTypeOfNode(new Selector.index(), node); |
| + return buildInstanceNoSuchMethod(selector, [visit(index)]); |
| } |
| - void markAsCaptured(Local local) { |
| - capturedVariables.add(local); |
| + @override |
| + ir.Primitive visitUnresolvedSuperIndex( |
| + ast.Send node, |
| + Element function, |
| + ast.Node index, _) { |
| + // Assume the index getter is missing. |
| + Selector selector = useSelectorTypeOfNode(new Selector.index(), node); |
| + return buildInstanceNoSuchMethod(selector, [visit(index)]); |
| } |
| - analyze(ast.Node node) { |
| - visit(node); |
| - // Variables that are captured by a closure are boxed for their entire |
| - // lifetime, so they never need to be boxed on entry to a try block. |
| - // They are not filtered out before this because we cannot identify all |
| - // of them in the same pass (they may be captured by a closure after the |
| - // try statement). |
| - for (TryStatementInfo info in tryStatements.values) { |
| - info.boxedOnEntry.removeAll(capturedVariables); |
| - } |
| + @override |
| + ir.Primitive errorUnresolvedSuperIndexPostfix( |
| + ast.Send node, |
| + Element function, |
| + ast.Node index, |
| + op.IncDecOperator operator, _) { |
| + // Assume the index getter is missing. |
| + Selector selector = useSelectorTypeOfNode(new Selector.index(), node); |
| + return buildInstanceNoSuchMethod(selector, [visit(index)]); |
| } |
| - visit(ast.Node node) => node.accept(this); |
| + @override |
| + ir.Primitive errorUnresolvedSuperIndexPrefix( |
| + ast.Send node, |
| + Element function, |
| + ast.Node index, |
| + op.IncDecOperator operator, _) { |
| + // Assume the index getter is missing. |
| + Selector selector = useSelectorTypeOfNode(new Selector.index(), node); |
| + return buildInstanceNoSuchMethod(selector, [visit(index)]); |
| + } |
| - visitNode(ast.Node node) { |
| - node.visitChildren(this); |
| + @override |
| + ir.Primitive errorUnresolvedSuperIndexSet( |
| + ast.SendSet node, |
| + Element element, |
| + ast.Node index, |
| + ast.Node rhs, _) { |
| + Selector selector = useSelectorTypeOfNode(new Selector.index(), node); |
| + return buildInstanceNoSuchMethod( |
| + selector, |
| + [visit(index), visit(rhs)]); |
| } |
| - visitFor(ast.For node) { |
| - if (node.initializer != null) visit(node.initializer); |
| - if (node.condition != null) visit(node.condition); |
| - if (node.update != null) visit(node.update); |
| + @override |
| + ir.Primitive visitUnresolvedSuperBinary( |
| + ast.Send node, |
| + Element element, |
| + op.BinaryOperator operator, |
| + ast.Node argument, _) { |
| + return buildInstanceNoSuchMethod( |
| + elements.getSelector(node), |
| + [visit(argument)]); |
| + } |
| - // Give up if a variable was captured outside of the loop body. |
| - if (node.initializer is ast.VariableDefinitions) { |
| - ast.VariableDefinitions definitions = node.initializer; |
| - for (ast.Node node in definitions.definitions.nodes) { |
| - LocalElement loopVariable = elements[node]; |
| - if (capturedVariables.contains(loopVariable)) { |
| - return giveup(node, 'For-loop variable captured in loop header'); |
| - } |
| - } |
| - } |
| + @override |
| + ir.Primitive visitUnresolvedSuperUnary( |
| + ast.Send node, |
| + op.UnaryOperator operator, |
| + Element element, _) { |
| + return buildInstanceNoSuchMethod(elements.getSelector(node), []); |
| + } |
| - if (node.body != null) visit(node.body); |
| + @override |
| + ir.Primitive errorUndefinedBinaryExpression( |
| + ast.Send node, |
| + ast.Node left, |
| + ast.Operator operator, |
| + ast.Node right, _) { |
| + assert(compiler.compilationFailed); |
| + return irBuilder.buildNullConstant(); |
| } |
| - void handleSend(ast.Send node) { |
| - Element element = elements[node]; |
| - if (Elements.isLocal(element) && |
| - !element.isConst && |
| - element.enclosingElement != currentFunction) { |
| - LocalElement local = element; |
| - markAsCaptured(local); |
| - } |
| + @override |
| + ir.Primitive errorUndefinedUnaryExpression( |
| + ast.Send node, |
| + ast.Operator operator, |
| + ast.Node expression, _) { |
| + assert(compiler.compilationFailed); |
| + return irBuilder.buildNullConstant(); |
| } |
| - visitSend(ast.Send node) { |
| - handleSend(node); |
| - node.visitChildren(this); |
| + @override |
| + ir.Primitive errorTopLevelFunctionSet( |
| + ast.Send node, |
| + MethodElement function, |
| + ast.Node rhs, _) { |
| + return buildStaticNoSuchMethod( |
| + new Selector.setter(function.name, function.library), |
| + [visit(rhs)]); |
| } |
| - visitSendSet(ast.SendSet node) { |
| - handleSend(node); |
| - Element element = elements[node]; |
| - if (Elements.isLocal(element)) { |
| - LocalElement local = element; |
| - if (insideInitializer) { |
| - assert(local.isParameter); |
| - // Initializers in an initializer-list can communicate via parameters. |
| - // If a parameter is stored in an initializer list we box it. |
| - // TODO(sigurdm): Fix this. |
| - // Though these variables do not outlive the activation of the |
| - // function, they still need to be boxed. As a simplification, we |
| + @override |
| + ir.Primitive errorTopLevelSetterGet( |
| + ast.Send node, |
| + FunctionElement setter, _) { |
| + return buildStaticNoSuchMethod( |
| + new Selector.getter(setter.name, setter.library), []); |
| + } |
| + |
| + @override |
| + ir.Primitive errorTopLevelGetterSet( |
| + ast.SendSet node, |
| + FunctionElement getter, |
| + ast.Node rhs, _) { |
| + return buildStaticNoSuchMethod( |
| + new Selector.setter(getter.name, getter.library), |
| + [visit(rhs)]); |
| + } |
| + |
| + @override |
| + ir.Primitive errorTopLevelSetterInvoke( |
| + ast.Send node, |
| + FunctionElement setter, |
| + ast.NodeList arguments, |
| + CallStructure callStructure, _) { |
| + return buildStaticNoSuchMethod( |
| + new Selector.getter(setter.name, setter.library), []); |
| + } |
| + |
| + @override |
| + ir.Primitive errorClassTypeLiteralSet( |
| + ast.SendSet node, |
| + TypeConstantExpression constant, |
| + ast.Node rhs, _) { |
| + InterfaceType type = constant.type; |
| + ClassElement element = type.element; |
| + return buildStaticNoSuchMethod( |
| + new Selector.setter(element.name, element.library), [visit(rhs)]); |
| + } |
| + |
| + @override |
| + ir.Primitive errorTypedefTypeLiteralSet( |
| + ast.SendSet node, |
| + TypeConstantExpression constant, |
| + ast.Node rhs, _) { |
| + TypedefType type = constant.type; |
| + TypedefElement element = type.element; |
| + return buildStaticNoSuchMethod( |
| + new Selector.setter(element.name, element.library), [visit(rhs)]); |
| + } |
| + |
| + @override |
| + ir.Primitive errorTypeVariableTypeLiteralSet( |
| + ast.SendSet node, |
| + TypeVariableElement element, |
| + ast.Node rhs, _) { |
| + return buildStaticNoSuchMethod( |
| + new Selector.setter(element.name, element.library), [visit(rhs)]); |
| + } |
| + |
| + @override |
| + ir.Primitive errorDynamicTypeLiteralSet( |
| + ast.SendSet node, |
| + ConstantExpression constant, |
| + ast.Node rhs, _) { |
| + return buildStaticNoSuchMethod( |
| + new Selector.setter('dynamic', null), [visit(rhs)]); |
| + } |
| + |
| + @override |
| + ir.Primitive visitAbstractClassConstructorInvoke( |
| + ast.NewExpression node, |
| + ConstructorElement element, |
| + InterfaceType type, |
| + ast.NodeList arguments, |
| + CallStructure callStructure, _) { |
| + return buildAbstractClassInstantiationError(element.enclosingClass); |
| + } |
| + |
| + @override |
| + ir.Primitive errorClassTypeLiteralCompound( |
| + ast.Send node, |
| + ConstantExpression constant, |
| + op.AssignmentOperator operator, |
| + ast.Node rhs, _) { |
| + return translateCompound( |
| + getValue: () => irBuilder.buildConstant(constant), |
| + operator: operator, |
| + rhs: rhs, |
| + setValue: (value) {}); // The binary operator will throw before this. |
| + } |
| + |
| + @override |
| + ir.Primitive errorClassTypeLiteralPostfix( |
| + ast.Send node, |
| + ConstantExpression constant, |
| + op.IncDecOperator operator, _) { |
| + String text = constant.getText(); |
|
floitsch
2015/05/08 03:03:40
unused
asgerf
2015/05/08 08:17:59
Thanks.
|
| + return translatePrefixPostfix( |
| + getValue: () => irBuilder.buildConstant(constant), |
| + operator: operator, |
| + setValue: (value) {}, // The binary operator will throw before this. |
| + isPrefix: false); |
| + } |
| + |
| + @override |
| + ir.Primitive errorClassTypeLiteralPrefix( |
| + ast.Send node, |
| + ConstantExpression constant, |
| + op.IncDecOperator operator, _) { |
| + String text = constant.getText(); |
|
floitsch
2015/05/08 03:03:40
unused.
asgerf
2015/05/08 08:17:59
Done.
|
| + return translatePrefixPostfix( |
| + getValue: () => irBuilder.buildConstant(constant), |
| + operator: operator, |
| + setValue: (value) {}, // The binary operator will throw before this. |
| + isPrefix: true); |
| + } |
| + |
| + @override |
| + ir.Primitive errorDynamicTypeLiteralCompound( |
| + ast.Send node, |
| + ConstantExpression constant, |
| + op.AssignmentOperator operator, |
| + ast.Node rhs, _) { |
| + return translateCompound( |
| + getValue: () => irBuilder.buildConstant(constant), |
| + operator: operator, |
| + rhs: rhs, |
| + setValue: (value) {}); // The binary operator will throw before this. |
| + } |
| + |
| + @override |
| + ir.Primitive errorDynamicTypeLiteralPostfix( |
| + ast.Send node, |
| + ConstantExpression constant, |
| + op.IncDecOperator operator, _) { |
| + return translatePrefixPostfix( |
| + getValue: () => irBuilder.buildConstant(constant), |
| + operator: operator, |
| + setValue: (value) {}, // The binary operator will throw before this. |
| + isPrefix: false); |
| + } |
| + |
| + @override |
| + ir.Primitive errorDynamicTypeLiteralPrefix( |
| + ast.Send node, |
| + ConstantExpression constant, |
| + op.IncDecOperator operator, _) { |
| + return translatePrefixPostfix( |
| + getValue: () => irBuilder.buildConstant(constant), |
| + operator: operator, |
| + setValue: (value) {}, // The binary operator will throw before this. |
| + isPrefix: true); |
| + } |
| + |
| + @override |
| + ir.Primitive errorFinalLocalVariableCompound( |
| + ast.Send node, |
| + LocalVariableElement variable, |
| + op.AssignmentOperator operator, |
| + ast.Node rhs, _) { |
| + Selector selector = new Selector.setter(variable.name, null); |
| + return translateCompound( |
| + getValue: () => irBuilder.buildLocalVariableGet(variable), |
| + operator: operator, |
| + rhs: rhs, |
| + setValue: (value) => buildStaticNoSuchMethod(selector, [value])); |
| + } |
| + |
| + @override |
| + ir.Primitive errorFinalLocalVariableSet( |
| + ast.SendSet node, |
| + LocalVariableElement variable, |
| + ast.Node rhs, _) { |
| + Selector selector = new Selector.setter(variable.name, null); |
| + return buildStaticNoSuchMethod(selector, [visit(rhs)]); |
| + } |
| + |
| + @override |
| + ir.Primitive errorFinalParameterCompound( |
| + ast.Send node, |
| + ParameterElement parameter, |
| + op.AssignmentOperator operator, |
| + ast.Node rhs, _) { |
| + Selector selector = new Selector.setter(parameter.name, null); |
| + return translateCompound( |
| + getValue: () => irBuilder.buildLocalVariableGet(parameter), |
| + operator: operator, |
| + rhs: rhs, |
| + setValue: (value) => buildStaticNoSuchMethod(selector, [value])); |
| + } |
| + |
| + @override |
| + ir.Primitive errorFinalParameterSet( |
| + ast.SendSet node, |
| + ParameterElement parameter, |
| + ast.Node rhs, _) { |
| + Selector selector = new Selector.setter(parameter.name, null); |
| + return buildStaticNoSuchMethod(selector, [visit(rhs)]); |
| + } |
| + |
| + @override |
| + ir.Primitive errorFinalStaticFieldCompound( |
| + ast.Send node, |
| + FieldElement field, |
| + op.AssignmentOperator operator, |
| + ast.Node rhs, _) { |
| + return translateCompound( |
| + getValue: () => irBuilder.buildStaticFieldGet(field), |
| + operator: operator, |
| + rhs: rhs, |
| + setValue: (value) => buildStaticNoSuchMethod( |
| + new Selector.setter(field.name, field.library), [value])); |
| + } |
| + |
| + @override |
| + ir.Primitive errorFinalStaticFieldSet( |
| + ast.SendSet node, |
| + FieldElement field, |
| + ast.Node rhs, _) { |
| + // TODO(asgerf): Include class name somehow? |
| + return buildStaticNoSuchMethod( |
| + new Selector.setter(field.name, field.library), |
| + [visit(rhs)]); |
| + } |
| + |
| + @override |
| + ir.Primitive errorFinalSuperFieldCompound( |
| + ast.Send node, |
| + FieldElement field, |
| + op.AssignmentOperator operator, |
| + ast.Node rhs, _) { |
| + Selector selector = useSelectorTypeOfNode( |
| + new Selector.setter(field.name, field.library), |
| + node); |
| + return translateCompound( |
| + getValue: () => irBuilder.buildSuperFieldGet(field), |
| + operator: operator, |
| + rhs: rhs, |
| + setValue: (value) => buildInstanceNoSuchMethod(selector, [value])); |
| + } |
| + |
| + @override |
| + ir.Primitive errorFinalSuperFieldSet( |
| + ast.SendSet node, |
| + FieldElement field, |
| + ast.Node rhs, _) { |
| + Selector selector = useSelectorTypeOfNode( |
| + new Selector.setter(field.name, field.library), |
| + node); |
| + return buildInstanceNoSuchMethod(selector, [visit(rhs)]); |
| + } |
| + |
| + @override |
| + ir.Primitive errorFinalTopLevelFieldCompound( |
| + ast.Send node, |
| + FieldElement field, |
| + op.AssignmentOperator operator, |
| + ast.Node rhs, _) { |
| + return translateCompound( |
| + getValue: () => irBuilder.buildStaticFieldGet(field), |
| + operator: operator, |
| + rhs: rhs, |
| + setValue: (value) => buildStaticNoSuchMethod( |
| + new Selector.setter(field.name, field.library), [value])); |
| + } |
| + |
| + @override |
| + ir.Primitive errorFinalTopLevelFieldSet( |
| + ast.SendSet node, |
| + FieldElement field, |
| + ast.Node rhs, _) { |
| + return buildStaticNoSuchMethod( |
| + new Selector.setter(field.name, field.library), |
| + [visit(rhs)]); |
| + } |
| + |
| + @override |
| + ir.Primitive errorLocalFunctionCompound( |
| + ast.Send node, |
| + LocalFunctionElement function, |
| + op.AssignmentOperator operator, |
| + ast.Node rhs, _) { |
| + return translateCompound( |
| + getValue: () => irBuilder.buildLocalFunctionGet(function), |
| + operator: operator, |
| + rhs: rhs, |
| + setValue: (value) {}); // Binary operator will throw before this. |
| + } |
| + |
| + @override |
| + ir.Primitive errorLocalFunctionPostfix( |
| + ast.Send node, |
| + LocalFunctionElement function, |
| + op.IncDecOperator operator, |
| + _) { |
| + return translatePrefixPostfix( |
| + getValue: () => irBuilder.buildLocalFunctionGet(function), |
| + operator: operator, |
| + setValue: (value) {}, // Binary operator will throw before this. |
| + isPrefix: false); |
| + } |
| + |
| + @override |
| + ir.Primitive errorLocalFunctionPrefix( |
| + ast.Send node, |
| + LocalFunctionElement function, |
| + op.IncDecOperator operator, |
| + _) { |
| + return translatePrefixPostfix( |
| + getValue: () => irBuilder.buildLocalFunctionGet(function), |
| + operator: operator, |
| + setValue: (value) {}, // Binary operator will throw before this. |
| + isPrefix: true); |
| + } |
| + |
| + @override |
| + ir.Primitive errorLocalFunctionSet( |
| + ast.SendSet node, |
| + LocalFunctionElement function, |
| + ast.Node rhs, _) { |
| + return buildStaticNoSuchMethod( |
| + new Selector.setter(function.name, null), |
| + [visit(rhs)]); |
| + } |
| + |
| + @override |
| + ir.Primitive errorStaticFunctionSet( |
| + ast.Send node, |
| + MethodElement function, |
| + ast.Node rhs, |
| + _) { |
| + return buildStaticNoSuchMethod( |
| + new Selector.setter(function.name, function.library), |
| + [visit(rhs)]); |
| + } |
| + |
| + @override |
| + ir.Primitive errorStaticGetterSet( |
| + ast.SendSet node, |
| + FunctionElement getter, |
| + ast.Node rhs, |
| + _) { |
| + return buildStaticNoSuchMethod( |
| + new Selector.setter(getter.name, getter.library), |
| + [visit(rhs)]); |
| + } |
| + |
| + @override |
| + ir.Primitive errorStaticSetterGet( |
| + ast.Send node, |
| + FunctionElement setter, |
| + _) { |
| + return buildStaticNoSuchMethod( |
| + new Selector.getter(setter.name, setter.library), |
| + []); |
| + } |
| + |
| + @override |
| + ir.Primitive errorStaticSetterInvoke( |
| + ast.Send node, |
| + FunctionElement setter, |
| + ast.NodeList arguments, |
| + CallStructure callStructure, _) { |
| + // Translate as a method call. |
| + List<ir.Primitive> args = arguments.nodes.mapToList(visit); |
| + Name name = new Name(setter.name, setter.library); |
| + return buildStaticNoSuchMethod( |
| + new Selector(SelectorKind.CALL, name, callStructure), |
| + args); |
| + } |
| + |
| + @override |
| + ir.Primitive errorSuperGetterSet( |
| + ast.SendSet node, |
| + FunctionElement getter, |
| + ast.Node rhs, |
| + _) { |
| + Selector selector = useSelectorTypeOfNode( |
| + new Selector.setter(getter.name, getter.library), |
| + node); |
| + return buildInstanceNoSuchMethod(selector, [visit(rhs)]); |
| + } |
| + |
| + @override |
| + ir.Primitive errorSuperMethodSet( |
| + ast.Send node, |
| + MethodElement method, |
| + ast.Node rhs, |
| + _) { |
| + Selector selector = useSelectorTypeOfNode( |
| + new Selector.setter(method.name, method.library), |
| + node); |
| + return buildInstanceNoSuchMethod(selector, [visit(rhs)]); |
| + } |
| + |
| + @override |
| + ir.Primitive errorSuperSetterGet( |
| + ast.Send node, |
| + FunctionElement setter, _) { |
| + Selector selector = useSelectorTypeOfNode( |
| + new Selector.setter(setter.name, setter.library), |
| + node); |
| + return buildInstanceNoSuchMethod(selector, []); |
| + } |
| + |
| + @override |
| + ir.Primitive errorSuperSetterInvoke( |
| + ast.Send node, |
| + FunctionElement setter, |
| + ast.NodeList arguments, |
| + CallStructure callStructure, _) { |
| + List<ir.Primitive> args = |
| + translateDynamicArguments(arguments, callStructure); |
| + Name name = new Name(setter.name, setter.library); |
| + Selector selector = useSelectorTypeOfNode( |
| + new Selector(SelectorKind.CALL, name, callStructure), |
| + node); |
| + return buildInstanceNoSuchMethod(selector, args); |
| + } |
| + |
| + @override |
| + ir.Primitive errorTypeVariableTypeLiteralCompound( |
| + ast.Send node, |
| + TypeVariableElement element, |
| + op.AssignmentOperator operator, |
| + ast.Node rhs, _) { |
| + ir.Primitive receiver = irBuilder.buildThis(); |
| + return translateCompound( |
| + getValue: () => buildReifyTypeVariable(receiver, element.type), |
| + operator: operator, |
| + rhs: rhs, |
| + setValue: (value) {}); // The binary operator will throw before this. |
| + } |
| + |
| + @override |
| + ir.Primitive errorTypeVariableTypeLiteralPostfix( |
| + ast.Send node, |
| + TypeVariableElement element, |
| + op.IncDecOperator operator, _) { |
| + ir.Primitive receiver = irBuilder.buildThis(); |
| + String message = 'Cannot assign to type variable ${element.name}'; |
|
floitsch
2015/05/08 03:03:40
unused.
asgerf
2015/05/08 08:17:59
Done.
|
| + return translatePrefixPostfix( |
| + getValue: () => buildReifyTypeVariable(receiver, element.type), |
| + operator: operator, |
| + setValue: (value) {}, // The binary operator will throw before this. |
| + isPrefix: false); |
| + } |
| + |
| + @override |
| + ir.Primitive errorTypeVariableTypeLiteralPrefix( |
| + ast.Send node, |
| + TypeVariableElement element, |
| + op.IncDecOperator operator, _) { |
| + ir.Primitive receiver = irBuilder.buildThis(); |
| + return translatePrefixPostfix( |
| + getValue: () => buildReifyTypeVariable(receiver, element.type), |
| + operator: operator, |
| + setValue: (value) {}, // The binary operator will throw before this. |
| + isPrefix: true); |
| + } |
| + |
| + @override |
| + ir.Primitive errorTypedefTypeLiteralCompound( |
| + ast.Send node, |
| + ConstantExpression constant, |
| + op.AssignmentOperator operator, |
| + ast.Node rhs, _) { |
| + return translateCompound( |
| + getValue: () => irBuilder.buildConstant(constant), |
| + operator: operator, |
| + rhs: rhs, |
| + setValue: (value) {}); // The binary operator will throw before this. |
| + } |
| + |
| + @override |
| + ir.Primitive errorTypedefTypeLiteralPostfix( |
| + ast.Send node, |
| + ConstantExpression constant, |
| + op.IncDecOperator operator, _) { |
| + return translatePrefixPostfix( |
| + getValue: () => irBuilder.buildConstant(constant), |
| + operator: operator, |
| + setValue: (value) {}, // The binary operator will throw before this. |
| + isPrefix: false); |
| + } |
| + |
| + @override |
| + ir.Primitive errorTypedefTypeLiteralPrefix( |
| + ast.Send node, |
| + TypeConstantExpression constant, |
| + op.IncDecOperator operator, _) { |
| + return translatePrefixPostfix( |
| + getValue: () => irBuilder.buildConstant(constant), |
| + operator: operator, |
| + setValue: (value) {}, // The binary operator will throw before this. |
| + isPrefix: true); |
| + } |
| + |
| + ir.RootNode nullIfGiveup(ir.RootNode action()) { |
| + try { |
| + return action(); |
| + } catch(e) { |
| + if (e == ABORT_IRNODE_BUILDER) { |
| + return null; |
| + } |
| + rethrow; |
| + } |
| + } |
| + |
| + void internalError(ast.Node node, String message) { |
| + giveup(node, message); |
| + } |
| + |
| + @override |
| + visitNode(ast.Node node) { |
| + internalError(node, "Unhandled node"); |
| + } |
| + |
| + dynamic giveup(ast.Node node, [String reason]) { |
| + bailoutMessage = '($node): $reason'; |
| + throw ABORT_IRNODE_BUILDER; |
| + } |
| +} |
| + |
| +final String ABORT_IRNODE_BUILDER = "IrNode builder aborted"; |
| + |
| +/// Classifies local variables and local functions as captured, if they |
| +/// are accessed from within a nested function. |
| +/// |
| +/// This class is specific to the [DartIrBuilder], in that it gives up if it |
| +/// sees a feature that is currently unsupport by that builder. In particular, |
| +/// loop variables captured in a for-loop initializer, condition, or update |
| +/// expression are unsupported. |
| +class DartCapturedVariables extends ast.Visitor { |
| + final TreeElements elements; |
| + DartCapturedVariables(this.elements); |
| + |
| + FunctionElement currentFunction; |
| + bool insideInitializer = false; |
| + Set<Local> capturedVariables = new Set<Local>(); |
| + |
| + Map<ast.TryStatement, TryStatementInfo> tryStatements = |
| + <ast.TryStatement, TryStatementInfo>{}; |
| + |
| + List<TryStatementInfo> tryNestingStack = <TryStatementInfo>[]; |
| + bool get inTryStatement => tryNestingStack.isNotEmpty; |
| + |
| + String bailoutMessage = null; |
| + |
| + giveup(ast.Node node, [String reason]) { |
| + bailoutMessage = '($node): $reason'; |
| + throw ABORT_IRNODE_BUILDER; |
| + } |
| + |
| + void markAsCaptured(Local local) { |
| + capturedVariables.add(local); |
| + } |
| + |
| + analyze(ast.Node node) { |
| + visit(node); |
| + // Variables that are captured by a closure are boxed for their entire |
| + // lifetime, so they never need to be boxed on entry to a try block. |
| + // They are not filtered out before this because we cannot identify all |
| + // of them in the same pass (they may be captured by a closure after the |
| + // try statement). |
| + for (TryStatementInfo info in tryStatements.values) { |
| + info.boxedOnEntry.removeAll(capturedVariables); |
| + } |
| + } |
| + |
| + visit(ast.Node node) => node.accept(this); |
| + |
| + visitNode(ast.Node node) { |
| + node.visitChildren(this); |
| + } |
| + |
| + visitFor(ast.For node) { |
| + if (node.initializer != null) visit(node.initializer); |
| + if (node.condition != null) visit(node.condition); |
| + if (node.update != null) visit(node.update); |
| + |
| + // Give up if a variable was captured outside of the loop body. |
| + if (node.initializer is ast.VariableDefinitions) { |
| + ast.VariableDefinitions definitions = node.initializer; |
| + for (ast.Node node in definitions.definitions.nodes) { |
| + LocalElement loopVariable = elements[node]; |
| + if (capturedVariables.contains(loopVariable)) { |
| + return giveup(node, 'For-loop variable captured in loop header'); |
| + } |
| + } |
| + } |
| + |
| + if (node.body != null) visit(node.body); |
| + } |
| + |
| + void handleSend(ast.Send node) { |
| + Element element = elements[node]; |
| + if (Elements.isLocal(element) && |
| + !element.isConst && |
| + element.enclosingElement != currentFunction) { |
| + LocalElement local = element; |
| + markAsCaptured(local); |
| + } |
| + } |
| + |
| + visitSend(ast.Send node) { |
| + handleSend(node); |
| + node.visitChildren(this); |
| + } |
| + |
| + visitSendSet(ast.SendSet node) { |
| + handleSend(node); |
| + Element element = elements[node]; |
| + if (Elements.isLocal(element)) { |
| + LocalElement local = element; |
| + if (insideInitializer) { |
| + assert(local.isParameter); |
| + // Initializers in an initializer-list can communicate via parameters. |
| + // If a parameter is stored in an initializer list we box it. |
| + // TODO(sigurdm): Fix this. |
| + // Though these variables do not outlive the activation of the |
| + // function, they still need to be boxed. As a simplification, we |
| // treat them as if they are captured by a closure (i.e., they do |
| // outlive the activation of the function). |
| markAsCaptured(local); |
| @@ -2213,6 +2912,28 @@ class DartIrBuilderVisitor extends IrBuilderVisitor { |
| type, |
| arguments); |
| } |
| + |
| + @override |
| + ir.Primitive buildStaticNoSuchMethod(Selector selector, |
| + List<ir.Primitive> arguments) { |
| + return giveup(null, 'Static noSuchMethod'); |
| + } |
| + |
| + @override |
| + ir.Primitive buildInstanceNoSuchMethod(Selector selector, |
| + List<ir.Primitive> arguments) { |
| + return giveup(null, 'Instance noSuchMethod'); |
| + } |
| + |
| + @override |
| + ir.Primitive buildRuntimeError(String message) { |
| + return giveup(null, 'Build runtime error: $message'); |
| + } |
| + |
| + @override |
| + ir.Primitive buildAbstractClassInstantiationError(ClassElement element) { |
| + return giveup(null, 'Abstract class instantiation: ${element.name}'); |
| + } |
| } |
| /// The [IrBuilder]s view on the information about the program that has been |
| @@ -2235,6 +2956,8 @@ class JsIrBuilderVisitor extends IrBuilderVisitor { |
| /// Promote the type of [irBuilder] to [JsIrBuilder]. |
| JsIrBuilder get irBuilder => super.irBuilder; |
| + JavaScriptBackend get backend => compiler.backend; |
| + |
| /// Result of closure conversion for the current body of code. |
| /// |
| /// Will be initialized upon entering the body of a function. |
| @@ -2845,6 +3568,45 @@ class JsIrBuilderVisitor extends IrBuilderVisitor { |
| constructor.computeEffectiveTargetType(type), |
| arguments); |
| } |
| + |
| + @override |
| + ir.Primitive buildStaticNoSuchMethod(Selector selector, |
| + List<ir.Primitive> arguments) { |
| + Element thrower = backend.getThrowNoSuchMethod(); |
| + ir.Primitive receiver = irBuilder.buildStringConstant(''); |
| + ir.Primitive name = irBuilder.buildStringConstant(selector.name); |
| + ir.Primitive argumentList = irBuilder.buildListLiteral(null, arguments); |
| + ir.Primitive expectedArgumentNames = irBuilder.buildNullConstant(); |
| + return irBuilder.buildStaticFunctionInvocation( |
| + thrower, |
| + new CallStructure.unnamed(4), |
| + [receiver, name, argumentList, expectedArgumentNames]); |
| + } |
| + |
| + @override |
| + ir.Primitive buildInstanceNoSuchMethod(Selector selector, |
| + List<ir.Primitive> arguments) { |
| + return irBuilder.buildDynamicInvocation( |
| + irBuilder.buildThis(), |
| + useSelectorType(compiler.noSuchMethodSelector, selector), |
| + [irBuilder.buildInvocationMirror(selector, arguments)]); |
| + } |
| + |
| + @override |
| + ir.Primitive buildRuntimeError(String message) { |
| + return irBuilder.buildStaticFunctionInvocation( |
| + backend.getThrowRuntimeError(), |
| + new CallStructure.unnamed(1), |
| + [irBuilder.buildStringConstant(message)]); |
| + } |
| + |
| + @override |
| + ir.Primitive buildAbstractClassInstantiationError(ClassElement element) { |
| + return irBuilder.buildStaticFunctionInvocation( |
| + backend.getThrowAbstractClassInstantiationError(), |
| + new CallStructure.unnamed(1), |
| + [irBuilder.buildStringConstant(element.name)]); |
| + } |
| } |
| /// Perform simple post-processing on the initial CPS-translated root term. |