| // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE.md file. |
| |
| import 'package:kernel/ast.dart' as ir; |
| import 'package:kernel/frontend/accessors.dart' |
| show |
| Accessor, |
| IndexAccessor, |
| NullAwarePropertyAccessor, |
| PropertyAccessor, |
| ReadOnlyAccessor, |
| StaticAccessor, |
| SuperIndexAccessor, |
| SuperPropertyAccessor, |
| ThisPropertyAccessor, |
| VariableAccessor, |
| buildIsNull, |
| makeBinary, |
| makeLet, |
| makeOrReuseVariable; |
| import 'package:kernel/transformations/flags.dart'; |
| |
| import '../common.dart'; |
| import '../common/names.dart'; |
| import '../constants/expressions.dart' |
| show |
| BoolFromEnvironmentConstantExpression, |
| ConstantExpression, |
| ConstructedConstantExpression, |
| IntFromEnvironmentConstantExpression, |
| StringFromEnvironmentConstantExpression, |
| TypeConstantExpression; |
| import '../dart_types.dart' show DartType, InterfaceType; |
| import '../diagnostics/spannable.dart' show Spannable; |
| import '../elements/elements.dart' |
| show |
| AstElement, |
| AsyncMarker, |
| ClassElement, |
| ConstructorElement, |
| Element, |
| FieldElement, |
| FunctionElement, |
| FunctionSignature, |
| GetterElement, |
| InitializingFormalElement, |
| JumpTarget, |
| LocalElement, |
| LocalFunctionElement, |
| LocalVariableElement, |
| MethodElement, |
| Name, |
| ParameterElement, |
| PrefixElement, |
| TypeVariableElement; |
| import '../resolution/operators.dart' |
| show AssignmentOperator, BinaryOperator, IncDecOperator, UnaryOperator; |
| import '../resolution/semantic_visitor.dart' |
| show |
| BaseImplementationOfCompoundsMixin, |
| BaseImplementationOfLocalsMixin, |
| BaseImplementationOfSetIfNullsMixin, |
| BaseImplementationOfStaticsMixin, |
| CompoundGetter, |
| CompoundKind, |
| CompoundRhs, |
| CompoundSetter, |
| SemanticDeclarationResolvedMixin, |
| SemanticDeclarationVisitor, |
| SemanticSendResolvedMixin, |
| SemanticSendVisitor, |
| SemanticVisitor; |
| import '../resolution/send_resolver.dart' show DeclarationResolverMixin; |
| import '../resolution/send_structure.dart' |
| show |
| InitializerStructure, |
| InitializersStructure, |
| ParameterStructure, |
| VariableStructure; |
| import '../resolution/tree_elements.dart' show TreeElements; |
| import '../tree/tree.dart' |
| show |
| Assert, |
| AsyncForIn, |
| Await, |
| Block, |
| BreakStatement, |
| Cascade, |
| CascadeReceiver, |
| CaseMatch, |
| CatchBlock, |
| Conditional, |
| ConditionalUri, |
| ContinueStatement, |
| DoWhile, |
| DottedName, |
| EmptyStatement, |
| Enum, |
| Expression, |
| ExpressionStatement, |
| For, |
| ForIn, |
| FunctionDeclaration, |
| FunctionExpression, |
| Identifier, |
| If, |
| Label, |
| LabeledStatement, |
| LiteralBool, |
| LiteralDouble, |
| LiteralInt, |
| LiteralList, |
| LiteralMap, |
| LiteralMapEntry, |
| LiteralNull, |
| LiteralString, |
| LiteralSymbol, |
| Metadata, |
| NamedArgument, |
| NewExpression, |
| Node, |
| NodeList, |
| Operator, |
| ParenthesizedExpression, |
| RedirectingFactoryBody, |
| Rethrow, |
| Return, |
| Send, |
| SendSet, |
| Statement, |
| StringInterpolation, |
| StringInterpolationPart, |
| StringJuxtaposition, |
| SwitchCase, |
| SwitchStatement, |
| SyncForIn, |
| Throw, |
| TryStatement, |
| TypeAnnotation, |
| TypeVariable, |
| VariableDefinitions, |
| While, |
| Yield; |
| import '../universe/call_structure.dart' show CallStructure; |
| import '../universe/selector.dart' show Selector; |
| import '../util/util.dart' show Link; |
| import 'error.dart' show KernelError; |
| import 'kernel.dart' show ConstructorTarget, Kernel; |
| import 'unavailable.dart' show UnavailableVisitor; |
| import 'unresolved.dart' show UnresolvedVisitor; |
| |
| /// Translates dart2js AST nodes [Node] into Kernel IR [ir.TreeNode]. |
| /// |
| /// Most methods in this class have a prefix that follows these conventions: |
| /// |
| /// * `visit` for overridden visitor methods. |
| /// * `handle` for methods that implement common behavior for several `visit` |
| /// methods. These methods are called by `visit` methods implemented by |
| /// various mixins below. |
| /// * `build` helper method that builds a new Kernel IR tree. |
| /// * `get` helper method that use a cache to build exactly one Kernel IR |
| /// tree for a given element. |
| /// |
| /// We reserve the prefixes `visit` and `handle` for superclasses of this |
| /// class. So those methods should always have an @override annotation. Use |
| /// `build` instead of `handle` when adding a new helper method to this class. |
| class KernelVisitor extends Object |
| with |
| SemanticSendResolvedMixin, |
| BaseImplementationOfStaticsMixin, |
| BaseImplementationOfLocalsMixin, |
| BaseImplementationOfCompoundsMixin, |
| BaseImplementationOfSetIfNullsMixin, |
| SemanticDeclarationResolvedMixin, |
| DeclarationResolverMixin, |
| UnavailableVisitor, |
| UnresolvedVisitor, |
| KernelError |
| implements |
| SemanticVisitor, |
| SemanticSendVisitor, |
| SemanticDeclarationVisitor { |
| TreeElements elements; |
| AstElement currentElement; |
| final Kernel kernel; |
| int transformerFlags = 0; |
| |
| final Map<JumpTarget, ir.LabeledStatement> continueTargets = |
| <JumpTarget, ir.LabeledStatement>{}; |
| |
| final Map<JumpTarget, ir.SwitchCase> continueSwitchTargets = |
| <JumpTarget, ir.SwitchCase>{}; |
| |
| final Map<JumpTarget, ir.LabeledStatement> breakTargets = |
| <JumpTarget, ir.LabeledStatement>{}; |
| |
| final Map<LocalElement, ir.VariableDeclaration> locals = |
| <LocalElement, ir.VariableDeclaration>{}; |
| |
| final Map<CascadeReceiver, ir.VariableGet> cascadeReceivers = |
| <CascadeReceiver, ir.VariableGet>{}; |
| |
| ir.Node associateElement(ir.Node node, Element element) { |
| kernel.nodeToElement[node] = element; |
| return node; |
| } |
| |
| ir.Node associateNode(ir.Node node, Node ast) { |
| kernel.nodeToAst[node] = ast; |
| return node; |
| } |
| |
| bool isVoidContext = false; |
| |
| KernelVisitor(this.currentElement, this.elements, this.kernel); |
| |
| KernelVisitor get sendVisitor => this; |
| |
| KernelVisitor get declVisitor => this; |
| |
| ir.TreeNode visitForValue(Expression node) { |
| bool wasVoidContext = isVoidContext; |
| isVoidContext = false; |
| try { |
| return node?.accept(this); |
| } finally { |
| isVoidContext = wasVoidContext; |
| } |
| } |
| |
| ir.TreeNode visitForEffect(Expression node) { |
| bool wasVoidContext = isVoidContext; |
| isVoidContext = true; |
| try { |
| return node?.accept(this); |
| } finally { |
| isVoidContext = wasVoidContext; |
| } |
| } |
| |
| ir.TreeNode visitWithCurrentContext(Expression node) => node?.accept(this); |
| |
| withCurrentElement(AstElement element, f()) { |
| assert(element.library == kernel.compiler.currentElement.library); |
| Element previousElement = currentElement; |
| currentElement = element; |
| try { |
| return f(); |
| } finally { |
| currentElement = previousElement; |
| } |
| } |
| |
| ir.DartType computeType(TypeAnnotation node) { |
| if (node == null) return const ir.DynamicType(); |
| return kernel.typeToIr(elements.getType(node)); |
| } |
| |
| // This works around a bug in dart2js. |
| // TODO(ahe): Fix the bug in dart2js and remove this function. |
| ir.DartType typeToIrHack(DartType type) { |
| if (currentElement.isSynthesized && |
| currentElement.enclosingClass.isMixinApplication && |
| !kernel.hasHierarchyProblem(currentElement.enclosingClass)) { |
| // Dart2js doesn't compute the correct functionSignature for synthetic |
| // constructors in mixin applications. So we compute the correct type: |
| // First, find the first superclass that isn't a mixin. |
| ClassElement superclass = currentElement.enclosingClass.superclass; |
| while (superclass.isMixinApplication) { |
| superclass = superclass.superclass; |
| } |
| // Then translate the "this type" of the mixin application to its |
| // supertype with the correct type arguments. |
| // |
| // Consider this example: |
| // |
| // class Super<S> {} |
| // class Sub<T> extends Object with Super<T> {} |
| // |
| // Here the problem is that dart2js has created a constructor that refers |
| // to S (not T) in Sub (for example, the return type of the constructor |
| // is Super<S> and it should be Sub<T>, but we settle for Super<T> for |
| // now). So we need to translate Sub<T> to an instance of Super, which is |
| // Super<T> (not Super<S>). |
| InterfaceType supertype = |
| currentElement.enclosingClass.asInstanceOf(superclass); |
| // Once we have [supertype], we know how to substitute S with T: the type |
| // arguments of [supertype] corresponds to T, and the type variables of |
| // its element correspond to S. |
| type = |
| type.subst(supertype.typeArguments, supertype.element.typeVariables); |
| } |
| return kernel.typeToIr(type); |
| } |
| |
| // TODO(ahe): Hack. Fix dart2js instead. |
| ir.Name nameToIrName(Name name) { |
| assert(!name.isPrivate || |
| name.library.implementation == currentElement.library.implementation); |
| return kernel.irName(name.text, currentElement); |
| } |
| |
| List<ir.DartType> computeTypesFromTypes(NodeList nodes, {int expected}) { |
| if (expected == null) { |
| throw "[expected] is null"; |
| } |
| List<ir.DartType> types = new List<ir.DartType>(expected); |
| Iterator<Node> iterator = nodes?.iterator; |
| for (int i = 0; i < expected; i++) { |
| TypeAnnotation type = null; |
| if (iterator != null && iterator.moveNext()) { |
| type = iterator.current; |
| } |
| types[i] = computeType(type); |
| } |
| if (iterator != null && iterator.moveNext()) { |
| // Should already have been reported by resolution. |
| // TODO(ahe): Delete this debug message. |
| kernel.debugMessage(iterator.current, "Extra type arguments."); |
| } |
| return types; |
| } |
| |
| ir.DartType computeTypeFromTypes(NodeList node) { |
| return computeTypesFromTypes(node, expected: 1).single; |
| } |
| |
| ir.MethodInvocation buildInvokeSelector( |
| ir.Expression receiver, Selector selector, ir.Arguments arguments) { |
| return new ir.MethodInvocation( |
| receiver, nameToIrName(selector.memberName), arguments); |
| } |
| |
| ir.MethodInvocation buildCall( |
| ir.Expression receiver, CallStructure callStructure, NodeList arguments) { |
| return buildInvokeSelector( |
| receiver, callStructure.callSelector, buildArguments(arguments)); |
| } |
| |
| @override |
| ir.Expression visitIdentifier(Identifier node) { |
| // TODO(ahe): Shouldn't have to override this method, but |
| // [SemanticSendResolvedMixin.visitIdentifier] may return `null` on errors. |
| if (node.isThis()) { |
| return sendVisitor.visitThisGet(node, null); |
| } else { |
| return new ir.InvalidExpression(); |
| } |
| } |
| |
| @override |
| ir.InvalidExpression handleUnresolved(Node node) { |
| return new ir.InvalidExpression(); |
| } |
| |
| @override |
| ir.Expression handleError(Node node) => new ir.InvalidExpression(); |
| |
| @override |
| void apply(Node node, _) { |
| throw new UnsupportedError("apply"); |
| } |
| |
| @override |
| void previsitDeferredAccess(Send node, PrefixElement prefix, _) {} |
| |
| @override |
| internalError(Spannable spannable, String message) { |
| kernel.internalError(spannable, message); |
| } |
| |
| @override |
| applyParameters(NodeList parameters, _) { |
| throw new UnsupportedError("applyParameters"); |
| } |
| |
| @override |
| applyInitializers(FunctionExpression constructor, _) { |
| throw new UnsupportedError("applyInitializers"); |
| } |
| |
| @override |
| ir.AssertStatement visitAssert(Assert node) { |
| return new ir.AssertStatement( |
| visitForValue(node.condition), visitForValue(node.message)); |
| } |
| |
| ir.LabeledStatement getBreakTarget(JumpTarget target) { |
| return breakTargets.putIfAbsent( |
| target, () => new ir.LabeledStatement(null)); |
| } |
| |
| ir.LabeledStatement getContinueTarget(JumpTarget target) { |
| return continueTargets.putIfAbsent( |
| target, () => new ir.LabeledStatement(null)); |
| } |
| |
| ir.SwitchCase getContinueSwitchTarget(JumpTarget target) { |
| return continueSwitchTargets[target]; |
| } |
| |
| ir.Statement buildBreakTarget( |
| ir.Statement statement, Node node, JumpTarget jumpTarget) { |
| assert(node.isValidBreakTarget()); |
| assert(jumpTarget == elements.getTargetDefinition(node)); |
| if (jumpTarget != null && jumpTarget.isBreakTarget) { |
| ir.LabeledStatement breakTarget = getBreakTarget(jumpTarget); |
| breakTarget.body = statement; |
| statement.parent = breakTarget; |
| return breakTarget; |
| } else { |
| return statement; |
| } |
| } |
| |
| ir.Statement buildContinueTarget( |
| ir.Statement statement, Node node, JumpTarget jumpTarget) { |
| assert(node.isValidContinueTarget()); |
| assert(jumpTarget == elements.getTargetDefinition(node)); |
| if (jumpTarget != null && jumpTarget.isContinueTarget) { |
| ir.LabeledStatement continueTarget = getContinueTarget(jumpTarget); |
| continueTarget.body = statement; |
| statement.parent = continueTarget; |
| return continueTarget; |
| } else { |
| return statement; |
| } |
| } |
| |
| ir.Statement buildForInCommon( |
| ForIn node, ir.VariableDeclaration variable, ir.Statement body, |
| {bool isAsync}) { |
| ir.Expression iterable = visitForValue(node.expression); |
| JumpTarget jumpTarget = elements.getTargetDefinition(node); |
| body = buildContinueTarget(body, node, jumpTarget); |
| return buildBreakTarget( |
| associateNode( |
| new ir.ForInStatement(variable, iterable, body, isAsync: isAsync), |
| node), |
| node, |
| jumpTarget); |
| } |
| |
| /// Builds a for-in statement for this case: |
| /// |
| /// for (constOrVarOrType loopVariable in expression) body |
| ir.Statement buildForInWithDeclaration( |
| ForIn node, VariableDefinitions declaration, |
| {bool isAsync}) { |
| if (declaration.definitions.slowLength() != 1) { |
| // It's not legal to declare more than one variable in a for-in loop. |
| return new ir.InvalidStatement(); |
| } |
| ir.VariableDeclaration variable = declaration.accept(this); |
| return buildForInCommon(node, variable, buildStatementInBlock(node.body), |
| isAsync: isAsync); |
| } |
| |
| Accessor buildStaticAccessor(Element getter, [Element setter]) { |
| if (setter == null && |
| getter != null && |
| getter.isField && |
| !getter.isFinal && |
| !getter.isConst) { |
| setter = getter; |
| } |
| return new StaticAccessor( |
| (getter == null) ? null : kernel.elementToIr(getter), |
| (setter == null) ? null : kernel.elementToIr(setter)); |
| } |
| |
| Accessor computeAccessor(ForIn node, Element element) { |
| if (element == null) { |
| Send send = node.declaredIdentifier.asSend(); |
| if (send == null) { |
| return buildStaticAccessor(null); |
| } |
| // This should be the situation where `node.declaredIdentifier` is |
| // unresolved, but in an instance method context. If it is some different |
| // situation, the assignment to [ir.PropertyGet] should act as an |
| // assertion. |
| ir.PropertyGet expression = visitForValue(send); |
| return PropertyAccessor.make( |
| expression.receiver, expression.name, null, null); |
| } else if (kernel.isSyntheticError(element)) { |
| return buildStaticAccessor(null); |
| } else if (element.isGetter) { |
| if (element.isInstanceMember) { |
| return new ThisPropertyAccessor( |
| kernel.irName(element.name, element), null, null); |
| } else { |
| GetterElement getter = element; |
| Element setter = getter.setter; |
| return buildStaticAccessor(getter, setter); |
| } |
| } else if (element.isLocal) { |
| return new VariableAccessor(getLocal(element)); |
| } else if (element.isField) { |
| return buildStaticAccessor(element); |
| } else { |
| return buildStaticAccessor(null); |
| } |
| } |
| |
| /// Builds a for-in statement for this case: |
| /// |
| /// for (element in expression) body |
| /// |
| /// This is normalized to: |
| /// |
| /// for (final #t in expression) { |
| /// element = #t; |
| /// body; |
| /// } |
| ir.Statement buildForInWithoutDeclaration(ForIn node, Element element, |
| {bool isAsync}) { |
| Accessor accessor = computeAccessor(node, elements.getForInVariable(node)); |
| // Since we've created [variable], we know it's only assigned to in the |
| // loop header and can be final. |
| ir.VariableDeclaration variable = |
| new ir.VariableDeclaration.forValue(null, isFinal: true); |
| ir.Statement assigment = new ir.ExpressionStatement(accessor |
| .buildAssignment(new ir.VariableGet(variable), voidContext: true)); |
| ir.Block body = buildStatementInBlock(node.body, forceBlock: true); |
| List<ir.Statement> statements = <ir.Statement>[assigment] |
| ..addAll(body.statements); |
| return buildForInCommon(node, variable, new ir.Block(statements), |
| isAsync: isAsync); |
| } |
| |
| ir.Statement buildForIn(ForIn node, {bool isAsync}) { |
| VariableDefinitions declaration = |
| node.declaredIdentifier.asVariableDefinitions(); |
| if (declaration != null) { |
| return buildForInWithDeclaration(node, declaration, isAsync: isAsync); |
| } else { |
| Element element = elements.getForInVariable(node); |
| return buildForInWithoutDeclaration(node, element, isAsync: isAsync); |
| } |
| } |
| |
| @override |
| ir.Statement visitAsyncForIn(AsyncForIn node) { |
| return buildForIn(node, isAsync: true); |
| } |
| |
| @override |
| ir.AwaitExpression visitAwait(Await node) { |
| return new ir.AwaitExpression(visitForValue(node.expression)); |
| } |
| |
| @override |
| ir.Statement visitBlock(Block node) { |
| return buildBreakTarget( |
| buildStatementInBlock(node), node, elements.getTargetDefinition(node)); |
| } |
| |
| bool buildStatement(Statement statement, List<ir.Statement> statements) { |
| ir.Node irNode = statement.accept(this); |
| bool hasVariableDeclaration = false; |
| if (irNode is VariableDeclarations) { |
| statements.addAll(irNode.variables); |
| hasVariableDeclaration = true; |
| } else { |
| statements.add(irNode); |
| if (irNode is ir.VariableDeclaration) { |
| hasVariableDeclaration = true; |
| } |
| } |
| return hasVariableDeclaration; |
| } |
| |
| ir.Statement buildStatementInBlock(Statement node, {bool forceBlock: false}) { |
| if (node == null) return null; |
| List<ir.Statement> statements = <ir.Statement>[]; |
| if (node is Block) { |
| for (Node statement in node.statements.nodes) { |
| buildStatement(statement, statements); |
| } |
| } else { |
| if (buildStatement(node, statements)) forceBlock = true; |
| if (!forceBlock && statements.length == 1) { |
| return statements.single; |
| } |
| // One VariableDefinitions statement node (dart2js AST) may generate |
| // multiple statements in Kernel IR so we sometimes fall through here. |
| } |
| return new ir.Block(statements); |
| } |
| |
| @override |
| ir.Statement visitBreakStatement(BreakStatement node) { |
| JumpTarget target = elements.getTargetOf(node); |
| if (target == null || !target.statement.isValidBreakTarget()) { |
| // This is a break in an invalid position. |
| return new ir.InvalidStatement(); |
| } |
| // A break can break to itself in the degenerate case `label: break |
| // label'`. |
| return buildBreakTarget(new ir.BreakStatement(getBreakTarget(target)), node, |
| elements.getTargetDefinition(node)); |
| } |
| |
| CascadeReceiver computeCascadeReceiver(Cascade cascade) { |
| CascadeReceiver receiver; |
| Expression send = cascade.expression.asSend(); |
| while (send != null && (receiver = send.asCascadeReceiver()) == null) { |
| Expression possibleReceiver = send.asSend()?.receiver; |
| if (possibleReceiver != null) { |
| send = possibleReceiver; |
| } else { |
| // Can happen in this case: `a..add(foo)('WHAT')`. |
| send = send.asSend()?.selector; |
| } |
| } |
| if (receiver == null) { |
| internalError(cascade, "Can't find cascade receiver"); |
| } |
| return receiver; |
| } |
| |
| @override |
| ir.Let visitCascade(Cascade node) { |
| // Given this cascade expression `receiver..cascade1()..cascade2()`, the |
| // parser has produced a tree like this: |
| // Cascade(Send( |
| // CascadeReceiver(Cascade(Send( |
| // CascadeRecevier(receiver), 'cascade1', []))), |
| // 'cascade2', [])) |
| // If viewed as a tree, `CascadeReceiver(receiver)` is the left-most leaf |
| // node. Below, we create this: |
| // cascades = [ |
| // Cascade(Send(CascadeReceiver(...), 'cascade2', [])), |
| // Cascade(Send(CascadeReceiver(...), 'cascade1', []))] |
| // Notice that the cascades are in reverse order, which we use to build a |
| // `let` expression bottom up. |
| // First iteration of the loop produces: |
| // let dummy = rcv.cascade2() in |
| // rcv |
| // Second iteration: |
| // let dummy = rcv.cascade1() in |
| // let dummy = rcv.cascade2() in |
| // rcv |
| // Finally we return: |
| // let rcv = receiver in |
| // let dummy = rcv.cascade1() in |
| // let dummy = rcv.cascade2() in |
| // rcv |
| int startLength; |
| assert((startLength = cascadeReceivers.length) >= 0); |
| |
| Cascade cascade = node; |
| List<Cascade> cascades = <Cascade>[]; |
| CascadeReceiver receiver; |
| ir.VariableDeclaration receiverVariable = makeOrReuseVariable(null); |
| |
| do { |
| cascades.add(cascade); |
| receiver = computeCascadeReceiver(cascade); |
| cascadeReceivers[receiver] = new ir.VariableGet(receiverVariable); |
| cascade = receiver.expression.asCascade(); |
| } while (cascade != null); |
| // At this point, all nested [Cascades] targeting the same receiver have |
| // been collected in [cascades] in reverse order. [receiver] is the |
| // left-most receiver. [receiverVariable] will hold the value of evaluating |
| // [receiver]. Each [CascadeReceiver] has a getter for [receiverVariable] |
| // in [cascadeReceivers]. |
| |
| receiverVariable.initializer = visitForValue(receiver.expression); |
| receiverVariable.initializer.parent = receiverVariable; |
| |
| ir.Expression result = new ir.VariableGet(receiverVariable); // rcv. |
| for (Cascade cascade in cascades) { |
| // When evaluating `cascade.expression`, we stop the recursion at |
| // [visitCascadeReceiver] and instead returns an [ir.VariableGet]. |
| // TODO(ahe): Use visitForEffect here? |
| ir.Expression value = visitForValue(cascade.expression); |
| result = new ir.Let(makeOrReuseVariable(value), result); |
| } |
| |
| assert(startLength == cascadeReceivers.length); |
| return new ir.Let(receiverVariable, result); |
| } |
| |
| @override |
| ir.VariableGet visitCascadeReceiver(CascadeReceiver node) { |
| return cascadeReceivers.remove(node); |
| } |
| |
| @override |
| visitCaseMatch(CaseMatch node) { |
| // Shouldn't be called. Handled by [visitSwitchCase]. |
| return internalError(node, "CaseMatch"); |
| } |
| |
| @override |
| ir.Catch visitCatchBlock(CatchBlock node) { |
| ir.VariableDeclaration exception = |
| (node.exception == null) ? null : getLocal(elements[node.exception]); |
| ir.VariableDeclaration trace = |
| (node.trace == null) ? null : getLocal(elements[node.trace]); |
| ir.DartType guard = computeType(node.type); |
| return new ir.Catch(exception, buildStatementInBlock(node.block), |
| guard: guard, stackTrace: trace); |
| } |
| |
| @override |
| ir.ConditionalExpression visitConditional(Conditional node) { |
| return new ir.ConditionalExpression( |
| visitForValue(node.condition), |
| visitWithCurrentContext(node.thenExpression), |
| visitWithCurrentContext(node.elseExpression)); |
| } |
| |
| @override |
| ir.Statement visitContinueStatement(ContinueStatement node) { |
| JumpTarget target = elements.getTargetOf(node); |
| if (target == null || !target.statement.isValidContinueTarget()) { |
| // This is a continue in an invalid position. |
| return new ir.InvalidStatement(); |
| } |
| ir.SwitchCase switchCase = getContinueSwitchTarget(target); |
| return (switchCase == null) |
| ? new ir.BreakStatement(getContinueTarget(target)) |
| : new ir.ContinueSwitchStatement(switchCase); |
| } |
| |
| @override |
| ir.Statement visitDoWhile(DoWhile node) { |
| JumpTarget jumpTarget = elements.getTargetDefinition(node); |
| ir.Statement body = |
| buildContinueTarget(buildStatementInBlock(node.body), node, jumpTarget); |
| ir.Expression condition = visitForValue(node.condition); |
| return buildBreakTarget( |
| new ir.DoStatement(body, condition), node, jumpTarget); |
| } |
| |
| @override |
| ir.EmptyStatement visitEmptyStatement(EmptyStatement node) { |
| return new ir.EmptyStatement(); |
| } |
| |
| @override |
| visitEnum(Enum node) { |
| // Not called normally. In dart2js, enums are represented as class |
| // elements, so `classToIr` handles enums. All the synthetic members of an |
| // enum class have already been installed by dart2js and we don't have to |
| // do anything special. |
| return internalError(node, "Enum"); |
| } |
| |
| @override |
| ir.ExpressionStatement visitExpressionStatement(ExpressionStatement node) { |
| return new ir.ExpressionStatement(visitForEffect(node.expression)); |
| } |
| |
| @override |
| ir.Statement visitFor(For node) { |
| VariableDefinitions initializers = |
| node.initializer?.asVariableDefinitions(); |
| ir.Expression initializer; |
| List<ir.VariableDeclaration> variables; |
| if (initializers != null) { |
| ir.Block block = buildStatementInBlock(initializers, forceBlock: true); |
| variables = new List<ir.VariableDeclaration>.from(block.statements); |
| } else { |
| if (node.initializer != null) { |
| initializer = visitForValue(node.initializer); |
| } |
| variables = const <ir.VariableDeclaration>[]; |
| } |
| ir.Expression condition = visitForValue(node.condition); |
| List<ir.Expression> updates = <ir.Expression>[]; |
| for (Expression update in node.update) { |
| updates.add(visitForEffect(update)); |
| } |
| |
| JumpTarget jumpTarget = elements.getTargetDefinition(node); |
| ir.Statement body = |
| buildContinueTarget(buildStatementInBlock(node.body), node, jumpTarget); |
| ir.ForStatement forStatement = associateNode( |
| new ir.ForStatement(variables, condition, updates, body), node); |
| ir.Statement result = buildBreakTarget(forStatement, node, jumpTarget); |
| if (initializer != null) { |
| result = new ir.Block( |
| <ir.Statement>[new ir.ExpressionStatement(initializer), result]); |
| } |
| return result; |
| } |
| |
| @override |
| ir.FunctionDeclaration visitFunctionDeclaration(FunctionDeclaration node) { |
| return node.function.accept(this); |
| } |
| |
| @override |
| ir.Statement visitIf(If node) { |
| return buildBreakTarget( |
| new ir.IfStatement( |
| visitForValue(node.condition), |
| buildStatementInBlock(node.thenPart), |
| buildStatementInBlock(node.elsePart)), |
| node, |
| elements.getTargetDefinition(node)); |
| } |
| |
| @override |
| visitLabel(Label node) { |
| // Shouldn't be called. Handled by visitLabeledStatement and |
| // visitSwitchCase. |
| return internalError(node, "Label"); |
| } |
| |
| @override |
| ir.Statement visitLabeledStatement(LabeledStatement node) { |
| Statement statement = node.statement; |
| ir.Statement result = (statement is Block) |
| // If [statement] is a Block, we need to ensure that we don't bypass |
| // its visit method (so it can build break targets correctly). |
| ? statement.accept(this) |
| : buildStatementInBlock(statement); |
| |
| // A [LabeledStatement] isn't the actual jump target, instead, [statement] |
| // is the target. This allows uniform handling of break and continue in |
| // loops. The following code simply assert that [result] has been generated |
| // correctly with respect to jump targets. |
| JumpTarget jumpTarget = elements.getTargetDefinition(node.statement); |
| if (jumpTarget != null) { |
| if (jumpTarget.isBreakTarget) { |
| ir.LabeledStatement target = breakTargets[jumpTarget]; |
| if (target != null && target != result && target.parent == null) { |
| internalError(node, "no parent"); |
| } |
| } |
| if (jumpTarget.isContinueTarget) { |
| ir.LabeledStatement target = continueTargets[jumpTarget]; |
| if (target != null && target != result && target.parent == null) { |
| internalError(node, "no parent"); |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| @override |
| ir.BoolLiteral visitLiteralBool(LiteralBool node) { |
| return new ir.BoolLiteral(node.value); |
| } |
| |
| @override |
| ir.DoubleLiteral visitLiteralDouble(LiteralDouble node) { |
| return new ir.DoubleLiteral(node.value); |
| } |
| |
| @override |
| ir.IntLiteral visitLiteralInt(LiteralInt node) { |
| return new ir.IntLiteral(node.value); |
| } |
| |
| @override |
| ir.ListLiteral visitLiteralList(LiteralList node) { |
| // TODO(ahe): Type arguments. |
| List<ir.Expression> elements = <ir.Expression>[]; |
| for (Expression element in node.elements.nodes) { |
| elements.add(visitForValue(element)); |
| } |
| return associateNode( |
| new ir.ListLiteral(elements, |
| typeArgument: computeTypeFromTypes(node.typeArguments), |
| // TODO(ahe): Should constness be validated? |
| isConst: node.isConst), |
| node); |
| } |
| |
| @override |
| ir.MapLiteral visitLiteralMap(LiteralMap node) { |
| // TODO(ahe): Type arguments. |
| List<ir.MapEntry> entries = <ir.MapEntry>[]; |
| for (LiteralMapEntry entry in node.entries.nodes) { |
| entries.add(new ir.MapEntry( |
| visitForValue(entry.key), visitForValue(entry.value))); |
| } |
| List<ir.DartType> typeArguments = |
| computeTypesFromTypes(node.typeArguments, expected: 2); |
| return associateNode( |
| new ir.MapLiteral(entries, |
| keyType: typeArguments.first, |
| valueType: typeArguments.last, |
| // TODO(ahe): Should Constness be validated? |
| isConst: node.isConst), |
| node); |
| } |
| |
| @override |
| visitLiteralMapEntry(LiteralMapEntry node) { |
| // Shouldn't be called. Handled by [visitLiteralMap]. |
| return internalError(node, "LiteralMapEntry"); |
| } |
| |
| @override |
| ir.NullLiteral visitLiteralNull(LiteralNull node) { |
| return new ir.NullLiteral(); |
| } |
| |
| @override |
| ir.Expression visitLiteralString(LiteralString node) { |
| if (node.dartString == null) return new ir.InvalidExpression(); |
| return new ir.StringLiteral(node.dartString.slowToString()); |
| } |
| |
| @override |
| ir.SymbolLiteral visitLiteralSymbol(LiteralSymbol node) { |
| var result = new ir.SymbolLiteral(node.slowNameString); |
| return associateNode(result, node); |
| } |
| |
| @override |
| visitMetadata(Metadata node) { |
| // Shouldn't be called. Metadata should already have been analyzed and |
| // converted to a constant expression in the resolver. |
| return internalError(node, "Metadata not handled as constant."); |
| } |
| |
| @override |
| ir.NamedExpression visitNamedArgument(NamedArgument node) { |
| return new ir.NamedExpression( |
| node.name.source, visitForValue(node.expression)); |
| } |
| |
| @override |
| visitOperator(Operator node) { |
| // This is a special subclass of [Identifier], and we should never see that |
| // in the semantic visitor. |
| return internalError(node, "Operator"); |
| } |
| |
| @override |
| ir.Expression visitParenthesizedExpression(ParenthesizedExpression node) { |
| return visitWithCurrentContext(node.expression); |
| } |
| |
| @override |
| ir.InvalidStatement visitRedirectingFactoryBody(RedirectingFactoryBody node) { |
| // Not implemented yet, only serves to recover from parser errors as |
| // dart2js is lenient in parsing something that looks like a redirecting |
| // factory method. |
| return new ir.InvalidStatement(); |
| } |
| |
| @override |
| ir.ExpressionStatement visitRethrow(Rethrow node) { |
| return new ir.ExpressionStatement(new ir.Rethrow()); |
| } |
| |
| @override |
| ir.ReturnStatement visitReturn(Return node) { |
| return new ir.ReturnStatement(visitForValue(node.expression)); |
| } |
| |
| @override |
| ir.StringConcatenation visitStringInterpolation(StringInterpolation node) { |
| List<ir.Expression> expressions = <ir.Expression>[]; |
| expressions.add(visitForValue(node.string)); |
| for (StringInterpolationPart part in node.parts) { |
| expressions.add(visitForValue(part.expression)); |
| expressions.add(visitForValue(part.string)); |
| } |
| return new ir.StringConcatenation(expressions); |
| } |
| |
| @override |
| ir.StringConcatenation visitStringJuxtaposition(StringJuxtaposition node) { |
| return new ir.StringConcatenation( |
| <ir.Expression>[visitForValue(node.first), visitForValue(node.second)]); |
| } |
| |
| @override |
| ir.SwitchCase visitSwitchCase(SwitchCase node) { |
| List<ir.Expression> expressions = <ir.Expression>[]; |
| for (var labelOrCase in node.labelsAndCases.nodes) { |
| CaseMatch match = labelOrCase.asCaseMatch(); |
| if (match != null) { |
| expressions.add(visitForValue(match.expression)); |
| } else { |
| // Assert that labelOrCase is one of two known types: [CaseMatch] or |
| // [Label]. We ignore cases, as any users have been resolved to use the |
| // case directly. |
| assert(labelOrCase.asLabel() != null); |
| } |
| } |
| // We ignore the node's statements here, they're generated below in |
| // [visitSwitchStatement] once we've set up all the jump targets. |
| return new ir.SwitchCase(expressions, null, isDefault: node.isDefaultCase); |
| } |
| |
| /// Returns true if [node] would let execution reach the next node (aka |
| /// fall-through in switch cases). |
| bool fallsThrough(ir.Statement node) { |
| return !(node is ir.BreakStatement || |
| node is ir.ReturnStatement || |
| node is ir.ContinueSwitchStatement || |
| (node is ir.ExpressionStatement && node.expression is ir.Throw)); |
| } |
| |
| @override |
| ir.Statement visitSwitchStatement(SwitchStatement node) { |
| ir.Expression expression = visitForValue(node.expression); |
| List<ir.SwitchCase> cases = <ir.SwitchCase>[]; |
| for (SwitchCase caseNode in node.cases.nodes) { |
| cases.add(caseNode.accept(this)); |
| JumpTarget jumpTarget = elements.getTargetDefinition(caseNode); |
| if (jumpTarget != null) { |
| assert(jumpTarget.isContinueTarget); |
| assert(!continueSwitchTargets.containsKey(jumpTarget)); |
| continueSwitchTargets[jumpTarget] = cases.last; |
| } |
| } |
| |
| Iterator<ir.SwitchCase> casesIterator = cases.iterator; |
| for (Link<Node> link = node.cases.nodes; |
| link.isNotEmpty; |
| link = link.tail) { |
| SwitchCase caseNode = link.head; |
| bool isLastCase = link.tail.isEmpty; |
| if (!casesIterator.moveNext()) { |
| internalError(caseNode, "case node mismatch"); |
| } |
| ir.SwitchCase irCase = casesIterator.current; |
| List<ir.Statement> statements = <ir.Statement>[]; |
| bool hasVariableDeclaration = false; |
| for (Statement statement in caseNode.statements.nodes) { |
| if (buildStatement(statement, statements)) { |
| hasVariableDeclaration = true; |
| } |
| } |
| if (statements.isEmpty || fallsThrough(statements.last)) { |
| if (isLastCase) { |
| statements.add(new ir.BreakStatement( |
| getBreakTarget(elements.getTargetDefinition(node)))); |
| } else { |
| statements.add(new ir.ExpressionStatement(new ir.Throw( |
| new ir.ConstructorInvocation( |
| kernel.getFallThroughErrorConstructor(), |
| new ir.Arguments.empty())))); |
| } |
| } |
| ir.Statement body = new ir.Block(statements); |
| irCase.body = body; |
| body.parent = irCase; |
| } |
| assert(!casesIterator.moveNext()); |
| |
| return buildBreakTarget(new ir.SwitchStatement(expression, cases), node, |
| elements.getTargetDefinition(node)); |
| } |
| |
| @override |
| ir.Statement visitSyncForIn(SyncForIn node) { |
| return buildForIn(node, isAsync: false); |
| } |
| |
| @override |
| ir.Throw visitThrow(Throw node) { |
| return new ir.Throw(visitForValue(node?.expression)); |
| } |
| |
| @override |
| ir.Statement visitTryStatement(TryStatement node) { |
| ir.Statement result = buildStatementInBlock(node.tryBlock); |
| if (node.catchBlocks != null && !node.catchBlocks.isEmpty) { |
| List<ir.Catch> catchBlocks = <ir.Catch>[]; |
| for (CatchBlock block in node.catchBlocks.nodes) { |
| catchBlocks.add(block.accept(this)); |
| } |
| result = new ir.TryCatch(result, catchBlocks); |
| } |
| if (node.finallyBlock != null) { |
| result = |
| new ir.TryFinally(result, buildStatementInBlock(node.finallyBlock)); |
| } |
| return buildBreakTarget(result, node, elements.getTargetDefinition(node)); |
| } |
| |
| @override |
| visitTypeAnnotation(TypeAnnotation node) { |
| // Shouldn't be called, as the resolver have already resolved types and |
| // created [DartType] objects. |
| return internalError(node, "TypeAnnotation"); |
| } |
| |
| @override |
| visitTypeVariable(TypeVariable node) { |
| // Shouldn't be called, as the resolver have already resolved types and |
| // created [DartType] objects. |
| return internalError(node, "TypeVariable"); |
| } |
| |
| @override |
| ir.Statement visitWhile(While node) { |
| ir.Expression condition = visitForValue(node.condition); |
| JumpTarget jumpTarget = elements.getTargetDefinition(node); |
| ir.Statement body = |
| buildContinueTarget(buildStatementInBlock(node.body), node, jumpTarget); |
| return buildBreakTarget( |
| associateNode(new ir.WhileStatement(condition, body), node), |
| node, |
| jumpTarget); |
| } |
| |
| @override |
| ir.YieldStatement visitYield(Yield node) { |
| return new ir.YieldStatement(visitForValue(node.expression), |
| isYieldStar: node.hasStar); |
| } |
| |
| @override |
| ir.InvalidExpression visitAbstractClassConstructorInvoke( |
| NewExpression node, |
| ConstructorElement element, |
| InterfaceType type, |
| NodeList arguments, |
| CallStructure callStructure, |
| _) { |
| return new ir.InvalidExpression(); |
| } |
| |
| IrFunction buildIrFunction( |
| ir.ProcedureKind kind, FunctionElement function, Node body) { |
| return new IrFunction.procedure(kind, buildFunctionNode(function, body)); |
| } |
| |
| @override |
| IrFunction visitAbstractGetterDeclaration( |
| FunctionExpression node, MethodElement getter, _) { |
| return buildIrFunction(ir.ProcedureKind.Getter, getter, null); |
| } |
| |
| @override |
| IrFunction visitAbstractSetterDeclaration( |
| FunctionExpression node, MethodElement setter, NodeList parameters, _) { |
| return buildIrFunction(ir.ProcedureKind.Setter, setter, null); |
| } |
| |
| @override |
| ir.AsExpression visitAs(Send node, Node expression, DartType type, _) { |
| return new ir.AsExpression( |
| visitForValue(expression), kernel.typeToIr(type)); |
| } |
| |
| @override |
| ir.MethodInvocation visitBinary( |
| Send node, Node left, BinaryOperator operator, Node right, _) { |
| return associateNode( |
| buildBinaryOperator(left, operator.selectorName, right), node); |
| } |
| |
| ir.Expression buildConstructorInvoke(NewExpression node, {bool isConst}) { |
| ConstructorElement constructor = elements[node.send]; |
| ConstructorTarget target; |
| if (isConst) { |
| target = |
| kernel.computeEffectiveTarget(constructor, elements.getType(node)); |
| } else { |
| target = new ConstructorTarget(constructor, elements.getType(node)); |
| } |
| NodeList arguments = node.send.argumentsNode; |
| if (kernel.isSyntheticError(target.element)) { |
| return new ir.MethodInvocation(new ir.InvalidExpression(), |
| kernel.irName("call", currentElement), buildArguments(arguments)); |
| } |
| ir.InvocationExpression invoke = target.element.isGenerativeConstructor |
| ? buildGenerativeConstructorInvoke(target.element, arguments, |
| isConst: isConst) |
| : buildStaticInvoke(target.element, arguments, isConst: isConst); |
| if (target.type.isInterfaceType) { |
| InterfaceType type = target.type; |
| if (type.isGeneric) { |
| invoke.arguments.types.addAll(kernel.typesToIr(type.typeArguments)); |
| } |
| } |
| return invoke; |
| } |
| |
| @override |
| ir.InvocationExpression visitBoolFromEnvironmentConstructorInvoke( |
| NewExpression node, BoolFromEnvironmentConstantExpression constant, _) { |
| return buildConstructorInvoke(node, isConst: true); |
| } |
| |
| ir.TypeLiteral buildTypeLiteral(TypeConstantExpression constant) { |
| return new ir.TypeLiteral(kernel.typeLiteralToIr(constant)); |
| } |
| |
| @override |
| ir.TypeLiteral visitClassTypeLiteralGet( |
| Send node, ConstantExpression constant, _) { |
| return buildTypeLiteral(constant); |
| } |
| |
| @override |
| ir.MethodInvocation visitClassTypeLiteralInvoke( |
| Send node, |
| ConstantExpression constant, |
| NodeList arguments, |
| CallStructure callStructure, |
| _) { |
| return buildCall(buildTypeLiteral(constant), callStructure, arguments); |
| } |
| |
| ir.Expression buildTypeLiteralSet(TypeConstantExpression constant, Node rhs) { |
| return new ReadOnlyAccessor(buildTypeLiteral(constant)) |
| .buildAssignment(visitForValue(rhs), voidContext: isVoidContext); |
| } |
| |
| @override |
| ir.Expression visitClassTypeLiteralSet( |
| SendSet node, ConstantExpression constant, Node rhs, _) { |
| return buildTypeLiteralSet(constant, rhs); |
| } |
| |
| @override |
| ir.FunctionExpression visitClosureDeclaration(FunctionExpression node, |
| LocalFunctionElement closure, NodeList parameters, Node body, _) { |
| return withCurrentElement(closure, () { |
| ir.FunctionExpression function = |
| new ir.FunctionExpression(buildFunctionNode(closure, body)); |
| kernel.localFunctions[closure] = function; |
| return function; |
| }); |
| } |
| |
| @override |
| ir.Expression visitCompoundIndexSet(SendSet node, Node receiver, Node index, |
| AssignmentOperator operator, Node rhs, _) { |
| return buildIndexAccessor(receiver, index).buildCompoundAssignment( |
| kernel.irName(operator.selectorName, currentElement), |
| visitForValue(rhs), |
| voidContext: isVoidContext); |
| } |
| |
| @override |
| ir.InvocationExpression visitConstConstructorInvoke( |
| NewExpression node, ConstructedConstantExpression constant, _) { |
| return buildConstructorInvoke(node, isConst: true); |
| } |
| |
| @override |
| visitConstantGet(Send node, ConstantExpression constant, _) { |
| // TODO(ahe): This method is never called. Is it a bug in semantic visitor? |
| return internalError(node, "ConstantGet"); |
| } |
| |
| @override |
| visitConstantInvoke(Send node, ConstantExpression constant, |
| NodeList arguments, CallStructure callStructure, _) { |
| // TODO(ahe): This method is never called. Is it a bug in semantic visitor? |
| return internalError(node, "ConstantInvoke"); |
| } |
| |
| @override |
| ir.InvalidExpression visitConstructorIncompatibleInvoke( |
| NewExpression node, |
| ConstructorElement constructor, |
| InterfaceType type, |
| NodeList arguments, |
| CallStructure callStructure, |
| _) { |
| return new ir.InvalidExpression(); |
| } |
| |
| @override |
| ir.PropertyGet visitDynamicPropertyGet( |
| Send node, Node receiver, Name name, _) { |
| return associateNode( |
| new ir.PropertyGet(visitForValue(receiver), nameToIrName(name)), node); |
| } |
| |
| @override |
| ir.MethodInvocation visitDynamicPropertyInvoke( |
| Send node, Node receiver, NodeList arguments, Selector selector, _) { |
| return associateNode( |
| buildInvokeSelector( |
| visitForValue(receiver), selector, buildArguments(arguments)), |
| node); |
| } |
| |
| @override |
| ir.Expression handleDynamicCompounds( |
| Send node, Node receiver, Name name, CompoundRhs rhs, _) { |
| ir.Expression receiverNode = |
| receiver == null ? new ir.ThisExpression() : visitForValue(receiver); |
| ir.Expression compound = buildCompound( |
| PropertyAccessor.make(receiverNode, nameToIrName(name), null, null), |
| rhs); |
| if (compound is ir.VariableSet) { |
| associateNode(compound.value, node); |
| } else { |
| associateNode(compound, node); |
| } |
| return compound; |
| } |
| |
| @override |
| ir.PropertySet visitDynamicPropertySet( |
| SendSet node, Node receiver, Name name, Node rhs, _) { |
| ir.Expression value = visitForValue(rhs); |
| return new ir.PropertySet( |
| visitForValue(receiver), nameToIrName(name), value); |
| } |
| |
| @override |
| ir.Expression handleDynamicSetIfNulls( |
| Send node, Node receiver, Name name, Node rhs, _) { |
| ir.Name irName = nameToIrName(name); |
| Accessor accessor = (receiver == null) |
| ? new ThisPropertyAccessor(irName, null, null) |
| : PropertyAccessor.make(visitForValue(receiver), irName, null, null); |
| return accessor.buildNullAwareAssignment(visitForValue(rhs), |
| voidContext: isVoidContext); |
| } |
| |
| @override |
| ir.TypeLiteral visitDynamicTypeLiteralGet( |
| Send node, ConstantExpression constant, _) { |
| return buildTypeLiteral(constant); |
| } |
| |
| @override |
| ir.MethodInvocation visitDynamicTypeLiteralInvoke( |
| Send node, |
| ConstantExpression constant, |
| NodeList arguments, |
| CallStructure callStructure, |
| _) { |
| return buildCall(buildTypeLiteral(constant), callStructure, arguments); |
| } |
| |
| @override |
| ir.Expression visitDynamicTypeLiteralSet( |
| SendSet node, ConstantExpression constant, Node rhs, _) { |
| return buildTypeLiteralSet(constant, rhs); |
| } |
| |
| ir.MethodInvocation buildBinaryOperator( |
| Node left, String operator, Node right) { |
| ir.Name name = kernel.irName(operator, currentElement); |
| return makeBinary(visitForValue(left), name, null, visitForValue(right)); |
| } |
| |
| @override |
| ir.MethodInvocation visitEquals(Send node, Node left, Node right, _) { |
| return associateNode(buildBinaryOperator(left, '==', right), node); |
| } |
| |
| @override |
| ir.MethodInvocation visitExpressionInvoke(Send node, Node expression, |
| NodeList arguments, CallStructure callStructure, _) { |
| return associateNode( |
| buildCall(visitForValue(expression), callStructure, arguments), node); |
| } |
| |
| @override |
| IrFunction visitFactoryConstructorDeclaration(FunctionExpression node, |
| ConstructorElement constructor, NodeList parameters, Node body, _) { |
| return buildIrFunction(ir.ProcedureKind.Factory, constructor, body); |
| } |
| |
| @override |
| ir.InvocationExpression visitFactoryConstructorInvoke( |
| NewExpression node, |
| ConstructorElement constructor, |
| InterfaceType type, |
| NodeList arguments, |
| CallStructure callStructure, |
| _) { |
| return buildConstructorInvoke(node, isConst: false); |
| } |
| |
| @override |
| ir.Initializer visitFieldInitializer( |
| SendSet node, FieldElement field, Node expression, _) { |
| if (kernel.isSyntheticError(field)) { |
| return new ir.InvalidInitializer(); |
| } else { |
| return new ir.FieldInitializer( |
| kernel.fieldToIr(field), visitForValue(expression)); |
| } |
| } |
| |
| ir.Expression buildStaticFieldSet(FieldElement field, Node rhs) { |
| return buildStaticAccessor(field) |
| .buildAssignment(visitForValue(rhs), voidContext: isVoidContext); |
| } |
| |
| @override |
| ir.Expression handleFinalStaticFieldSet( |
| SendSet node, FieldElement field, Node rhs, _) { |
| return buildStaticFieldSet(field, rhs); |
| } |
| |
| @override |
| ir.Expression visitFinalSuperFieldSet( |
| SendSet node, FieldElement field, Node rhs, _) { |
| return buildSuperPropertyAccessor(field) |
| .buildAssignment(visitForValue(rhs), voidContext: isVoidContext); |
| } |
| |
| IrFunction buildGenerativeConstructor( |
| ConstructorElement constructor, NodeList parameters, Node body) { |
| List<ir.Initializer> constructorInitializers = <ir.Initializer>[]; |
| if (kernel.hasHierarchyProblem(constructor.enclosingClass)) { |
| constructorInitializers.add(new ir.InvalidInitializer()); |
| } else if (constructor.isSynthesized) { |
| List<ir.Expression> arguments = const <ir.Expression>[]; |
| List<ir.NamedExpression> named = const <ir.NamedExpression>[]; |
| FunctionSignature signature = constructor.functionSignature; |
| if (signature.parameterCount != 0) { |
| // Mixin application implicit super call. |
| arguments = <ir.Expression>[]; |
| named = <ir.NamedExpression>[]; |
| signature.orderedForEachParameter((ParameterElement parameter) { |
| ir.VariableGet argument = buildLocalGet(parameter); |
| if (parameter.isNamed) { |
| named.add(new ir.NamedExpression(parameter.name, argument)); |
| } else { |
| arguments.add(argument); |
| } |
| }); |
| } |
| if (kernel.isSyntheticError(constructor.definingConstructor)) { |
| constructorInitializers.add(new ir.InvalidInitializer()); |
| } else { |
| constructorInitializers.add(new ir.SuperInitializer( |
| kernel.functionToIr(constructor.definingConstructor), |
| new ir.Arguments(arguments, named: named, types: null))); |
| } |
| } else { |
| if (parameters != null) { |
| // TODO(ahe): the following is a (modified) copy of |
| // [SemanticDeclarationResolvedMixin.visitParameters]. |
| List<ParameterStructure> structures = |
| computeParameterStructures(parameters); |
| for (ParameterStructure structure in structures) { |
| if (structure.parameter.isInitializingFormal) { |
| constructorInitializers.add(structure.dispatch(declVisitor, null)); |
| } |
| } |
| } |
| // TODO(ahe): the following is a (modified) copy of |
| // [SemanticDeclarationResolvedMixin.visitInitializers]. |
| InitializersStructure initializers = |
| computeInitializersStructure(constructor.node); |
| for (InitializerStructure structure in initializers.initializers) { |
| constructorInitializers.add(structure.dispatch(declVisitor, null)); |
| } |
| } |
| return new IrFunction.constructor( |
| buildFunctionNode(constructor, body), constructorInitializers); |
| } |
| |
| @override |
| IrFunction visitGenerativeConstructorDeclaration( |
| FunctionExpression node, |
| ConstructorElement constructor, |
| NodeList parameters, |
| NodeList initializers, |
| Node body, |
| _) { |
| return buildGenerativeConstructor(constructor, parameters, body); |
| } |
| |
| ir.ConstructorInvocation buildGenerativeConstructorInvoke( |
| ConstructorElement constructor, NodeList arguments, |
| {bool isConst}) { |
| if (const bool.fromEnvironment("require_kernel_arguments")) { |
| // Check that all constructors from kernel/ast.dart (that are invoked |
| // from this package) provide all arguments (including optional |
| // arguments). |
| // TODO(ahe): Remove this when the implementation has matured. |
| if (("package:kernel/ast.dart" == |
| "${constructor.library.canonicalUri}") && |
| "${currentElement.library.canonicalUri}" |
| .startsWith("package:rasta/")) { |
| if (constructor.functionSignature.parameterCount != |
| arguments.slowLength()) { |
| kernel.debugMessage(arguments, "Missing arguments"); |
| kernel.debugMessage(constructor, "When calling the constructor"); |
| } |
| } |
| } |
| ir.Arguments argumentsNode = buildArguments(arguments); |
| ir.Constructor target = kernel.functionToIr(constructor); |
| return new ir.ConstructorInvocation(target, argumentsNode, |
| isConst: isConst); |
| } |
| |
| @override |
| ir.InvocationExpression visitGenerativeConstructorInvoke( |
| NewExpression node, |
| ConstructorElement constructor, |
| InterfaceType type, |
| NodeList arguments, |
| CallStructure callStructure, |
| _) { |
| return buildConstructorInvoke(node, isConst: false); |
| } |
| |
| Accessor buildNullAwarePropertyAccessor(Node receiver, Name name) { |
| return new NullAwarePropertyAccessor( |
| visitForValue(receiver), nameToIrName(name), null, null); |
| } |
| |
| @override |
| ir.Expression visitIfNotNullDynamicPropertyGet( |
| Send node, Node receiver, Name name, _) { |
| return buildNullAwarePropertyAccessor(receiver, name).buildSimpleRead(); |
| } |
| |
| @override |
| ir.Let visitIfNotNullDynamicPropertyInvoke( |
| Send node, Node receiverNode, NodeList arguments, Selector selector, _) { |
| ir.VariableDeclaration receiver = |
| makeOrReuseVariable(visitForValue(receiverNode)); |
| return makeLet( |
| receiver, |
| new ir.ConditionalExpression( |
| buildIsNull(new ir.VariableGet(receiver)), |
| new ir.NullLiteral(), |
| buildInvokeSelector(new ir.VariableGet(receiver), selector, |
| buildArguments(arguments)))); |
| } |
| |
| @override |
| ir.Expression visitIfNotNullDynamicPropertySet( |
| SendSet node, Node receiver, Name name, Node rhs, _) { |
| return buildNullAwarePropertyAccessor(receiver, name) |
| .buildAssignment(visitForValue(rhs), voidContext: isVoidContext); |
| } |
| |
| @override |
| ir.Expression visitIfNotNullDynamicPropertySetIfNull( |
| Send node, Node receiver, Name name, Node rhs, _) { |
| return buildNullAwarePropertyAccessor(receiver, name) |
| .buildNullAwareAssignment(visitForValue(rhs), |
| voidContext: isVoidContext); |
| } |
| |
| ir.LogicalExpression buildLogicalExpression( |
| Node left, Operator operator, Node right) { |
| return new ir.LogicalExpression( |
| visitForValue(left), operator.source, visitForValue(right)); |
| } |
| |
| @override |
| ir.LogicalExpression visitIfNull(Send node, Node left, Node right, _) { |
| return buildLogicalExpression(left, node.selector, right); |
| } |
| |
| @override |
| ir.Initializer visitImplicitSuperConstructorInvoke(FunctionExpression node, |
| ConstructorElement superConstructor, InterfaceType type, _) { |
| if (superConstructor == null) { |
| // TODO(ahe): Semantic visitor shouldn't call this. |
| return new ir.InvalidInitializer(); |
| } |
| return new ir.SuperInitializer( |
| kernel.functionToIr(superConstructor), new ir.Arguments.empty()); |
| } |
| |
| Accessor buildIndexAccessor(Node receiver, Node index) { |
| return IndexAccessor.make( |
| visitForValue(receiver), visitForValue(index), null, null); |
| } |
| |
| @override |
| ir.Expression visitIndex(Send node, Node receiver, Node index, _) { |
| return associateNode( |
| buildIndexAccessor(receiver, index).buildSimpleRead(), node); |
| } |
| |
| ir.Expression buildIndexPostfix(Accessor accessor, IncDecOperator operator) { |
| ir.Name name = kernel.irName(operator.selectorName, currentElement); |
| return accessor.buildPostfixIncrement(name, voidContext: isVoidContext); |
| } |
| |
| @override |
| ir.Expression visitIndexPostfix( |
| Send node, Node receiver, Node index, IncDecOperator operator, _) { |
| return buildIndexPostfix(buildIndexAccessor(receiver, index), operator); |
| } |
| |
| ir.Expression buildIndexPrefix(Accessor accessor, IncDecOperator operator) { |
| ir.Name name = kernel.irName(operator.selectorName, currentElement); |
| return accessor.buildPrefixIncrement(name, voidContext: isVoidContext); |
| } |
| |
| @override |
| ir.Expression visitIndexPrefix( |
| Send node, Node receiver, Node index, IncDecOperator operator, _) { |
| return buildIndexPrefix(buildIndexAccessor(receiver, index), operator); |
| } |
| |
| @override |
| ir.Expression visitIndexSet( |
| SendSet node, Node receiver, Node index, Node rhs, _) { |
| return associateNode( |
| buildIndexAccessor(receiver, index) |
| .buildAssignment(visitForValue(rhs), voidContext: isVoidContext), |
| node); |
| } |
| |
| ir.Initializer buildInitializingFormal(InitializingFormalElement parameter) { |
| FieldElement field = parameter.fieldElement; |
| if (kernel.isSyntheticError(field)) { |
| return new ir.InvalidInitializer(); |
| } else { |
| return new ir.FieldInitializer( |
| kernel.fieldToIr(field), buildLocalGet(parameter)); |
| } |
| } |
| |
| @override |
| ir.Initializer visitInitializingFormalDeclaration(VariableDefinitions node, |
| Node definition, InitializingFormalElement parameter, int index, _) { |
| return buildInitializingFormal(parameter); |
| } |
| |
| @override |
| visitInstanceFieldDeclaration(VariableDefinitions node, Node definition, |
| FieldElement field, Node initializer, _) { |
| // Shouldn't be called, handled by fieldToIr. |
| return internalError(node, "InstanceFieldDeclaration"); |
| } |
| |
| @override |
| IrFunction visitInstanceGetterDeclaration( |
| FunctionExpression node, MethodElement getter, Node body, _) { |
| return buildIrFunction(ir.ProcedureKind.Getter, getter, body); |
| } |
| |
| @override |
| IrFunction visitInstanceSetterDeclaration(FunctionExpression node, |
| MethodElement setter, NodeList parameters, Node body, _) { |
| return buildIrFunction(ir.ProcedureKind.Setter, setter, body); |
| } |
| |
| @override |
| ir.InvocationExpression visitIntFromEnvironmentConstructorInvoke( |
| NewExpression node, IntFromEnvironmentConstantExpression constant, _) { |
| return buildConstructorInvoke(node, isConst: true); |
| } |
| |
| ir.IsExpression buildIs(Node expression, DartType type) { |
| return new ir.IsExpression( |
| visitForValue(expression), kernel.typeToIr(type)); |
| } |
| |
| @override |
| ir.IsExpression visitIs(Send node, Node expression, DartType type, _) { |
| return buildIs(expression, type); |
| } |
| |
| @override |
| ir.Not visitIsNot(Send node, Node expression, DartType type, _) { |
| return new ir.Not(buildIs(expression, type)); |
| } |
| |
| ir.VariableDeclaration buildLocalVariableDeclaration( |
| LocalVariableElement variable, Node initializer) { |
| ir.Expression initializerNode = visitForValue(initializer); |
| ir.VariableDeclaration local = getLocal(variable); |
| if (initializer != null) { |
| local.initializer = initializerNode; |
| initializerNode.parent = local; |
| } |
| return local; |
| } |
| |
| @override |
| ir.VariableDeclaration visitLocalConstantDeclaration( |
| VariableDefinitions node, |
| Node definition, |
| LocalVariableElement variable, |
| ConstantExpression constant, |
| _) { |
| // TODO(ahe): Use [constant]? |
| return buildLocalVariableDeclaration(variable, variable.initializer) |
| ..isConst = true; |
| } |
| |
| @override |
| ir.FunctionDeclaration visitLocalFunctionDeclaration(FunctionExpression node, |
| LocalFunctionElement localFunction, NodeList parameters, Node body, _) { |
| return withCurrentElement(localFunction, () { |
| ir.VariableDeclaration local = getLocal(localFunction)..isFinal = true; |
| ir.FunctionDeclaration function = new ir.FunctionDeclaration( |
| local, buildFunctionNode(localFunction, body)); |
| // Closures can escape their context and we must therefore store them |
| // globally to include them in the world computation. |
| kernel.localFunctions[localFunction] = function; |
| return function; |
| }); |
| } |
| |
| @override |
| ir.VariableDeclaration visitLocalVariableDeclaration(VariableDefinitions node, |
| Node definition, LocalVariableElement variable, Node initializer, _) { |
| return buildLocalVariableDeclaration(variable, initializer); |
| } |
| |
| ir.VariableGet buildLocalGet(LocalElement local) { |
| return new ir.VariableGet(getLocal(local)); |
| } |
| |
| @override |
| ir.VariableGet handleLocalGet(Send node, LocalElement element, _) { |
| return buildLocalGet(element); |
| } |
| |
| ir.Expression buildCompound(Accessor accessor, CompoundRhs rhs) { |
| ir.Name name = kernel.irName(rhs.operator.selectorName, currentElement); |
| switch (rhs.kind) { |
| case CompoundKind.POSTFIX: |
| return accessor.buildPostfixIncrement(name, voidContext: isVoidContext); |
| |
| case CompoundKind.PREFIX: |
| return accessor.buildPrefixIncrement(name, voidContext: isVoidContext); |
| |
| case CompoundKind.ASSIGNMENT: |
| return accessor.buildCompoundAssignment(name, visitForValue(rhs.rhs), |
| voidContext: isVoidContext); |
| } |
| } |
| |
| @override |
| ir.Expression handleLocalCompounds( |
| SendSet node, LocalElement local, CompoundRhs rhs, _, |
| {bool isSetterValid}) { |
| ir.Expression compound = |
| buildCompound(new VariableAccessor(getLocal(local)), rhs); |
| if (compound is ir.VariableSet) { |
| associateNode(compound.value, node); |
| } else { |
| associateNode(compound, node); |
| } |
| return compound; |
| } |
| |
| @override |
| ir.VariableSet handleLocalSet( |
| SendSet node, LocalElement element, Node rhs, _) { |
| return new ir.VariableSet(getLocal(element), visitForValue(rhs)); |
| } |
| |
| @override |
| ir.VariableSet handleImmutableLocalSet( |
| SendSet node, LocalElement element, Node rhs, _) { |
| // TODO(ahe): Build invalid? |
| return handleLocalSet(node, element, rhs, _); |
| } |
| |
| @override |
| ir.LogicalExpression visitLogicalAnd(Send node, Node left, Node right, _) { |
| return buildLogicalExpression(left, node.selector, right); |
| } |
| |
| @override |
| ir.LogicalExpression visitLogicalOr(Send node, Node left, Node right, _) { |
| return buildLogicalExpression(left, node.selector, right); |
| } |
| |
| @override |
| ir.Initializer visitNamedInitializingFormalDeclaration( |
| VariableDefinitions node, |
| Node definition, |
| InitializingFormalElement parameter, |
| ConstantExpression defaultValue, |
| _) { |
| return buildInitializingFormal(parameter); |
| } |
| |
| @override |
| visitNamedParameterDeclaration(VariableDefinitions node, Node definition, |
| ParameterElement parameter, ConstantExpression defaultValue, _) { |
| // Shouldn't be called, we handle parameters via [FunctionSignture]. |
| return internalError(node, "NamedParameterDeclaration"); |
| } |
| |
| @override |
| ir.Not visitNot(Send node, Node expression, _) { |
| return new ir.Not(visitForValue(expression)); |
| } |
| |
| @override |
| ir.Not visitNotEquals(Send node, Node left, Node right, _) { |
| return associateNode( |
| new ir.Not(associateNode(buildBinaryOperator(left, '==', right), node)), |
| node); |
| } |
| |
| @override |
| ir.Initializer visitOptionalInitializingFormalDeclaration( |
| VariableDefinitions node, |
| Node definition, |
| InitializingFormalElement parameter, |
| ConstantExpression defaultValue, |
| int index, |
| _) { |
| return buildInitializingFormal(parameter); |
| } |
| |
| @override |
| visitOptionalParameterDeclaration( |
| VariableDefinitions node, |
| Node definition, |
| ParameterElement parameter, |
| ConstantExpression defaultValue, |
| int index, |
| _) { |
| // Shouldn't be called, we handle parameters via [FunctionSignture]. |
| return internalError(node, "OptionalParameterDeclaration"); |
| } |
| |
| @override |
| visitParameterDeclaration(VariableDefinitions node, Node definition, |
| ParameterElement parameter, int index, _) { |
| // Shouldn't be called, we handle parameters via [FunctionSignture]. |
| return internalError(node, "ParameterDeclaration"); |
| } |
| |
| @override |
| ir.MethodInvocation handleLocalInvoke(Send node, LocalElement element, |
| NodeList arguments, CallStructure callStructure, _) { |
| return associateNode( |
| buildCall(buildLocalGet(element), callStructure, arguments), node); |
| } |
| |
| @override |
| ir.Expression handleLocalSetIfNulls( |
| SendSet node, LocalElement local, Node rhs, _, |
| {bool isSetterValid}) { |
| return new VariableAccessor(getLocal(local)).buildNullAwareAssignment( |
| visitForValue(rhs), |
| voidContext: isVoidContext); |
| } |
| |
| @override |
| IrFunction visitRedirectingFactoryConstructorDeclaration( |
| FunctionExpression node, |
| ConstructorElement constructor, |
| NodeList parameters, |
| DartType redirectionType, // TODO(ahe): Should be InterfaceType. |
| ConstructorElement redirectionTarget, |
| _) { |
| if (!constructor.isFactoryConstructor) { |
| // TODO(ahe): This seems like a bug in semantic visitor and how it |
| // recovers from a bad constructor. |
| return new IrFunction.constructor(buildFunctionNode(constructor, null), |
| <ir.Initializer>[new ir.InvalidInitializer()]); |
| } |
| ir.Statement body = null; |
| if (kernel.isSyntheticError(redirectionTarget)) { |
| body = new ir.InvalidStatement(); |
| } else { |
| // TODO(ahe): This should be implemented, but doesn't matter much unless |
| // we support reflection. At the call-site, we bypass this factory and |
| // call its effective target directly. So this factory is only necessary |
| // for reflection. |
| body = new ir.InvalidStatement(); |
| } |
| IrFunction function = |
| buildIrFunction(ir.ProcedureKind.Factory, constructor, null); |
| function.node.body = body..parent = function.node; |
| return function; |
| } |
| |
| @override |
| ir.InvocationExpression visitRedirectingFactoryConstructorInvoke( |
| NewExpression node, |
| ConstructorElement constructor, |
| InterfaceType type, |
| ConstructorElement effectiveTarget, |
| InterfaceType effectiveTargetType, |
| NodeList arguments, |
| CallStructure callStructure, |
| _) { |
| return buildConstructorInvoke(node, isConst: false); |
| } |
| |
| @override |
| IrFunction visitRedirectingGenerativeConstructorDeclaration( |
| FunctionExpression node, |
| ConstructorElement constructor, |
| NodeList parameters, |
| NodeList initializers, |
| _) { |
| return buildGenerativeConstructor(constructor, parameters, null); |
| } |
| |
| @override |
| ir.InvocationExpression visitRedirectingGenerativeConstructorInvoke( |
| NewExpression node, |
| ConstructorElement constructor, |
| InterfaceType type, |
| NodeList arguments, |
| CallStructure callStructure, |
| _) { |
| return buildConstructorInvoke(node, isConst: false); |
| } |
| |
| @override |
| visitStaticConstantDeclaration(VariableDefinitions node, Node definition, |
| FieldElement field, ConstantExpression constant, _) { |
| // Shouldn't be called, handled by fieldToIr. |
| return internalError(node, "StaticConstantDeclaration"); |
| } |
| |
| @override |
| visitStaticFieldDeclaration(VariableDefinitions node, Node definition, |
| FieldElement field, Node initializer, _) { |
| // Shouldn't be called, handled by fieldToIr. |
| return internalError(node, "StaticFieldDeclaration"); |
| } |
| |
| ir.Expression buildStaticGet(Element element) { |
| return buildStaticAccessor(element).buildSimpleRead(); |
| } |
| |
| @override |
| ir.Expression handleStaticFieldGet(Send node, FieldElement field, _) { |
| return buildStaticGet(field); |
| } |
| |
| @override |
| ir.MethodInvocation handleStaticFieldInvoke(Send node, FieldElement field, |
| NodeList arguments, CallStructure callStructure, _) { |
| return associateNode( |
| buildCall(buildStaticGet(field), callStructure, arguments), node); |
| } |
| |
| @override |
| ir.Expression handleStaticFieldSet( |
| SendSet node, FieldElement field, Node rhs, _) { |
| return buildStaticFieldSet(field, rhs); |
| } |
| |
| @override |
| ir.Expression handleStaticSetIfNulls( |
| SendSet node, |
| Element getter, |
| CompoundGetter getterKind, |
| Element setter, |
| CompoundSetter setterKind, |
| Node rhs, |
| _) { |
| if (setterKind == CompoundSetter.INVALID) { |
| setter = null; |
| } |
| return buildStaticAccessor(getter, setter).buildNullAwareAssignment( |
| visitForValue(rhs), |
| voidContext: isVoidContext); |
| } |
| |
| ir.VariableDeclaration getLocal(LocalElement local) { |
| return locals.putIfAbsent(local, () { |
| // Currently, initializing formals are not final. |
| bool isFinal = local.isFinal && !local.isInitializingFormal; |
| return associateElement( |
| new ir.VariableDeclaration(local.name, |
| initializer: null, |
| type: typeToIrHack(local.type), |
| isFinal: isFinal, |
| isConst: local.isConst), |
| local); |
| }); |
| } |
| |
| ir.FunctionNode buildFunctionNode(FunctionElement function, Node bodyNode) { |
| List<ir.TypeParameter> typeParameters = |
| kernel.typeParametersNotImplemented(); |
| List<ir.VariableDeclaration> positionalParameters = |
| <ir.VariableDeclaration>[]; |
| List<ir.VariableDeclaration> namedParameters = <ir.VariableDeclaration>[]; |
| int requiredParameterCount = 0; |
| ir.DartType returnType = const ir.DynamicType(); |
| if (function.hasFunctionSignature) { |
| FunctionSignature signature = function.functionSignature; |
| requiredParameterCount = signature.requiredParameterCount; |
| signature.forEachParameter((ParameterElement parameter) { |
| ir.VariableDeclaration variable = getLocal(parameter); |
| if (parameter.isNamed) { |
| namedParameters.add(variable); |
| } else { |
| positionalParameters.add(variable); |
| } |
| }); |
| signature.forEachParameter((ParameterElement parameter) { |
| if (!parameter.isOptional) return; |
| ir.Expression initializer = visitForValue(parameter.initializer); |
| ir.VariableDeclaration variable = getLocal(parameter); |
| if (initializer != null) { |
| variable.initializer = initializer; |
| initializer.parent = variable; |
| } |
| }); |
| if (function.isGenerativeConstructor) { |
| returnType = const ir.VoidType(); |
| } else { |
| returnType = typeToIrHack(signature.type.returnType); |
| } |
| if (function.isFactoryConstructor) { |
| InterfaceType type = function.enclosingClass.thisType; |
| if (type.isGeneric) { |
| typeParameters = new List<ir.TypeParameter>(); |
| for (DartType parameter in type.typeArguments) { |
| typeParameters.add(kernel.typeVariableToIr(parameter.element)); |
| } |
| } |
| } |
| } |
| ir.AsyncMarker asyncMarker = ir.AsyncMarker.Sync; |
| if (!kernel.isSyntheticError(function)) { |
| switch (function.asyncMarker) { |
| case AsyncMarker.SYNC: |
| asyncMarker = ir.AsyncMarker.Sync; |
| break; |
| |
| case AsyncMarker.SYNC_STAR: |
| asyncMarker = ir.AsyncMarker.SyncStar; |
| break; |
| |
| case AsyncMarker.ASYNC: |
| asyncMarker = ir.AsyncMarker.Async; |
| break; |
| |
| case AsyncMarker.ASYNC_STAR: |
| asyncMarker = ir.AsyncMarker.AsyncStar; |
| break; |
| |
| default: |
| internalError( |
| function, "Unknown async maker: ${function.asyncMarker}"); |
| break; |
| } |
| } |
| ir.Statement body; |
| if (function.isExternal) { |
| // [body] must be `null`. |
| } else if (function.isConstructor) { |
| // TODO(johnniwinther): Clean this up pending kernel issue #28. |
| ConstructorElement constructor = function; |
| if (bodyNode == null || bodyNode.asEmptyStatement() != null) { |
| body = new ir.EmptyStatement(); |
| } else { |
| body = buildStatementInBlock(bodyNode); |
| } |
| } else if (bodyNode != null) { |
| Return returnStatement = bodyNode.asReturn(); |
| if ((function.isSetter || function.name == Names.INDEX_SET_NAME.text) && |
| returnStatement != null) { |
| // Avoid encoding the implicit return of setters with arrow body: |
| // set setter(value) => this.value = value; |
| // operator []=(index, value) => this[index] = value; |
| body = new ir.ExpressionStatement( |
| visitForEffect(returnStatement.expression)); |
| } else { |
| body = buildStatementInBlock(bodyNode); |
| } |
| } |
| return associateElement( |
| new ir.FunctionNode(body, |
| asyncMarker: asyncMarker, |
| returnType: returnType, |
| typeParameters: typeParameters, |
| positionalParameters: positionalParameters, |
| namedParameters: namedParameters, |
| requiredParameterCount: requiredParameterCount), |
| function); |
| } |
| |
| @override |
| IrFunction visitStaticFunctionDeclaration(FunctionExpression node, |
| MethodElement function, NodeList parameters, Node body, _) { |
| return buildIrFunction(ir.ProcedureKind.Method, function, body); |
| } |
| |
| ir.ProcedureKind computeInstanceMethodKind(MethodElement method) { |
| assert(method.isFunction); |
| return method.isOperator |
| ? ir.ProcedureKind.Operator |
| : ir.ProcedureKind.Method; |
| } |
| |
| @override |
| IrFunction visitInstanceMethodDeclaration(FunctionExpression node, |
| MethodElement method, NodeList parameters, Node body, _) { |
| return buildIrFunction( |
| computeInstanceMethodKind(currentElement), currentElement, body); |
| } |
| |
| @override |
| IrFunction visitAbstractMethodDeclaration( |
| FunctionExpression node, MethodElement method, NodeList parameters, _) { |
| return buildIrFunction( |
| computeInstanceMethodKind(currentElement), currentElement, null); |
| } |
| |
| @override |
| ir.Expression handleStaticFunctionGet(Send node, MethodElement function, _) { |
| return buildStaticGet(function); |
| } |
| |
| @override |
| ir.StaticInvocation handleStaticFunctionIncompatibleInvoke( |
| Send node, |
| MethodElement function, |
| NodeList arguments, |
| CallStructure callStructure, |
| _) { |
| return buildStaticInvoke(function, arguments, isConst: false); |
| } |
| |
| ir.StaticInvocation buildStaticInvoke( |
| FunctionElement function, NodeList arguments, |
| {bool isConst}) { |
| ir.Arguments argumentsNode = buildArguments(arguments); |
| return new ir.StaticInvocation(kernel.functionToIr(function), argumentsNode, |
| isConst: isConst); |
| } |
| |
| @override |
| ir.StaticInvocation handleStaticFunctionInvoke( |
| Send node, |
| MethodElement function, |
| NodeList arguments, |
| CallStructure callStructure, |
| _) { |
| return buildStaticInvoke(function, arguments, isConst: false); |
| } |
| |
| @override |
| ir.Expression handleStaticFunctionSet( |
| Send node, MethodElement function, Node rhs, _) { |
| return buildStaticAccessor(function) |
| .buildAssignment(visitForValue(rhs), voidContext: isVoidContext); |
| } |
| |
| @override |
| IrFunction visitStaticGetterDeclaration( |
| FunctionExpression node, MethodElement getter, Node body, _) { |
| return buildIrFunction(ir.ProcedureKind.Getter, getter, body); |
| } |
| |
| @override |
| ir.Expression handleStaticGetterGet(Send node, FunctionElement getter, _) { |
| if (getter.isDeferredLoaderGetter) { |
| // TODO(ahe): Support deferred load. |
| return new ir.InvalidExpression(); |
| } |
| return buildStaticGet(getter); |
| } |
| |
| @override |
| ir.Expression handleStaticGetterInvoke(Send node, FunctionElement getter, |
| NodeList arguments, CallStructure callStructure, _) { |
| if (getter.isDeferredLoaderGetter) { |
| // TODO(ahe): Support deferred load. |
| return new ir.InvalidExpression(); |
| } |
| return buildCall(buildStaticGet(getter), callStructure, arguments); |
| } |
| |
| @override |
| ir.Expression handleStaticGetterSet( |
| SendSet node, FunctionElement getter, Node rhs, _) { |
| return buildStaticAccessor(getter) |
| .buildAssignment(visitForValue(rhs), voidContext: isVoidContext); |
| } |
| |
| @override |
| IrFunction visitStaticSetterDeclaration(FunctionExpression node, |
| MethodElement setter, NodeList parameters, Node body, _) { |
| return buildIrFunction(ir.ProcedureKind.Setter, setter, body); |
| } |
| |
| @override |
| ir.Expression handleStaticSetterGet(Send node, FunctionElement setter, _) { |
| return buildStaticAccessor(null, setter).buildSimpleRead(); |
| } |
| |
| @override |
| ir.MethodInvocation handleStaticSetterInvoke( |
| Send node, |
| FunctionElement setter, |
| NodeList arguments, |
| CallStructure callStructure, |
| _) { |
| return buildCall(buildStaticAccessor(null, setter).buildSimpleRead(), |
| callStructure, arguments); |
| } |
| |
| @override |
| ir.Expression handleStaticSetterSet( |
| SendSet node, FunctionElement setter, Node rhs, _) { |
| return buildStaticAccessor(null, setter) |
| .buildAssignment(visitForValue(rhs), voidContext: isVoidContext); |
| } |
| |
| @override |
| ir.InvocationExpression visitStringFromEnvironmentConstructorInvoke( |
| NewExpression node, StringFromEnvironmentConstantExpression constant, _) { |
| return buildConstructorInvoke(node, isConst: true); |
| } |
| |
| @override |
| ir.SuperMethodInvocation visitSuperBinary(Send node, FunctionElement function, |
| BinaryOperator operator, Node argument, _) { |
| transformerFlags |= TransformerFlag.superCalls; |
| return new ir.SuperMethodInvocation( |
| kernel.irName(operator.selectorName, currentElement), |
| new ir.Arguments(<ir.Expression>[visitForValue(argument)]), |
| kernel.functionToIr(function)); |
| } |
| |
| @override |
| ir.Expression visitSuperCompoundIndexSet( |
| SendSet node, |
| MethodElement getter, |
| MethodElement setter, |
| Node index, |
| AssignmentOperator operator, |
| Node rhs, |
| _) { |
| return buildSuperIndexAccessor(index, getter, setter) |
| .buildCompoundAssignment( |
| kernel.irName(operator.selectorName, currentElement), |
| visitForValue(rhs), |
| voidContext: isVoidContext); |
| } |
| |
| @override |
| ir.Initializer visitSuperConstructorInvoke( |
| Send node, |
| ConstructorElement superConstructor, |
| InterfaceType type, |
| NodeList arguments, |
| CallStructure callStructure, |
| _) { |
| if (kernel.isSyntheticError(superConstructor)) { |
| // TODO(ahe): Semantic visitor shouldn't call in this case. |
| return new ir.InvalidInitializer(); |
| } |
| return new ir.SuperInitializer( |
| kernel.functionToIr(superConstructor), buildArguments(arguments)); |
| } |
| |
| ir.SuperMethodInvocation buildSuperEquals( |
| FunctionElement function, Node argument) { |
| transformerFlags |= TransformerFlag.superCalls; |
| return new ir.SuperMethodInvocation( |
| kernel.irName(function.name, function), |
| new ir.Arguments(<ir.Expression>[visitForValue(argument)], |
| types: null, named: null), |
| kernel.functionToIr(function)); |
| } |
| |
| @override |
| ir.SuperMethodInvocation visitSuperEquals( |
| Send node, FunctionElement function, Node argument, _) { |
| return buildSuperEquals(function, argument); |
| } |
| |
| @override |
| ir.Expression handleSuperCompounds( |
| SendSet node, |
| Element getter, |
| CompoundGetter getterKind, |
| Element setter, |
| CompoundSetter setterKind, |
| CompoundRhs rhs, |
| _) { |
| if (setterKind == CompoundSetter.INVALID) { |
| setter = null; |
| } |
| return buildCompound(buildSuperPropertyAccessor(getter, setter), rhs); |
| } |
| |
| @override |
| ir.Expression handleStaticCompounds( |
| SendSet node, |
| Element getter, |
| CompoundGetter getterKind, |
| Element setter, |
| CompoundSetter setterKind, |
| CompoundRhs rhs, |
| _) { |
| if (setterKind == CompoundSetter.INVALID) { |
| setter = null; |
| } |
| return buildCompound(buildStaticAccessor(getter, setter), rhs); |
| } |
| |
| @override |
| ir.Expression handleTypeLiteralConstantCompounds( |
| SendSet node, ConstantExpression constant, CompoundRhs rhs, _) { |
| return buildCompound(new ReadOnlyAccessor(buildTypeLiteral(constant)), rhs); |
| } |
| |
| ir.TypeLiteral buildTypeVariable(TypeVariableElement element) { |
| return new ir.TypeLiteral(kernel.typeToIr(element.type)); |
| } |
| |
| @override |
| ir.Expression handleTypeVariableTypeLiteralCompounds( |
| SendSet node, TypeVariableElement element, CompoundRhs rhs, _) { |
| return buildCompound(new ReadOnlyAccessor(buildTypeVariable(element)), rhs); |
| } |
| |
| @override |
| ir.SuperPropertyGet visitSuperFieldGet(Send node, FieldElement field, _) { |
| return buildSuperPropertyAccessor(field).buildSimpleRead(); |
| } |
| |
| @override |
| ir.MethodInvocation visitSuperFieldInvoke(Send node, FieldElement field, |
| NodeList arguments, CallStructure callStructure, _) { |
| return buildCall(buildSuperPropertyAccessor(field).buildSimpleRead(), |
| callStructure, arguments); |
| } |
| |
| @override |
| ir.Expression visitSuperFieldSet( |
| SendSet node, FieldElement field, Node rhs, _) { |
| return buildSuperPropertyAccessor(field) |
| .buildAssignment(visitForValue(rhs), voidContext: isVoidContext); |
| } |
| |
| Accessor buildSuperPropertyAccessor(Element getter, [Element setter]) { |
| transformerFlags |= TransformerFlag.superCalls; |
| if (setter == null && |
| getter.isField && |
| !getter.isFinal && |
| !getter.isConst) { |
| setter = getter; |
| } |
| Element element = getter ?? setter; |
| return new SuperPropertyAccessor( |
| kernel.irName(element.name, element), |
| (getter == null) ? null : kernel.elementToIr(getter), |
| (setter == null) ? null : kernel.elementToIr(setter)); |
| } |
| |
| Accessor buildSuperIndexAccessor(Expression index, Element getter, |
| [Element setter]) { |
| if (setter == null && |
| getter.isField && |
| !getter.isFinal && |
| !getter.isConst) { |
| setter = getter; |
| } |
| return new SuperIndexAccessor( |
| visitForValue(index), |
| (getter == null) ? null : kernel.elementToIr(getter), |
| (setter == null) ? null : kernel.elementToIr(setter)); |
| } |
| |
| @override |
| ir.SuperPropertyGet visitSuperGetterGet( |
| Send node, FunctionElement getter, _) { |
| return buildSuperPropertyAccessor(getter).buildSimpleRead(); |
| } |
| |
| @override |
| ir.MethodInvocation visitSuperGetterInvoke(Send node, FunctionElement getter, |
| NodeList arguments, CallStructure callStructure, _) { |
| return buildCall(buildSuperPropertyAccessor(getter).buildSimpleRead(), |
| callStructure, arguments); |
| } |
| |
| @override |
| ir.Expression visitSuperGetterSet( |
| SendSet node, FunctionElement getter, Node rhs, _) { |
| return buildSuperPropertyAccessor(getter) |
| .buildAssignment(visitForValue(rhs), voidContext: isVoidContext); |
| } |
| |
| @override |
| ir.Expression handleSuperSetIfNulls( |
| SendSet node, |
| Element getter, |
| CompoundGetter getterKind, |
| Element setter, |
| CompoundSetter setterKind, |
| Node rhs, |
| _) { |
| if (setterKind == CompoundSetter.INVALID) { |
| setter = null; |
| } |
| return buildSuperPropertyAccessor(getter, setter).buildNullAwareAssignment( |
| visitForValue(rhs), |
| voidContext: isVoidContext); |
| } |
| |
| @override |
| ir.SuperMethodInvocation visitSuperIndex( |
| Send node, FunctionElement function, Node index, _) { |
| return buildSuperIndexAccessor(index, function).buildSimpleRead(); |
| } |
| |
| @override |
| ir.Expression visitSuperIndexPostfix(Send node, MethodElement indexFunction, |
| MethodElement indexSetFunction, Node index, IncDecOperator operator, _) { |
| Accessor accessor = |
| buildSuperIndexAccessor(index, indexFunction, indexSetFunction); |
| return buildIndexPostfix(accessor, operator); |
| } |
| |
| @override |
| ir.Expression visitSuperIndexPrefix(Send node, MethodElement indexFunction, |
| MethodElement indexSetFunction, Node index, IncDecOperator operator, _) { |
| Accessor accessor = |
| buildSuperIndexAccessor(index, indexFunction, indexSetFunction); |
| return buildIndexPrefix(accessor, operator); |
| } |
| |
| @override |
| ir.Expression visitSuperIndexSet( |
| SendSet node, FunctionElement function, Node index, Node rhs, _) { |
| return buildSuperIndexAccessor(index, null, function) |
| .buildAssignment(visitForValue(rhs), voidContext: isVoidContext); |
| } |
| |
| @override |
| ir.Expression visitSuperMethodGet(Send node, MethodElement method, _) { |
| return buildSuperPropertyAccessor(method).buildSimpleRead(); |
| } |
| |
| ir.SuperMethodInvocation buildSuperMethodInvoke( |
| MethodElement method, NodeList arguments) { |
| transformerFlags |= TransformerFlag.superCalls; |
| return new ir.SuperMethodInvocation(kernel.irName(method.name, method), |
| buildArguments(arguments), kernel.functionToIr(method)); |
| } |
| |
| @override |
| ir.SuperMethodInvocation visitSuperMethodIncompatibleInvoke( |
| Send node, |
| MethodElement method, |
| NodeList arguments, |
| CallStructure callStructure, |
| _) { |
| return buildSuperMethodInvoke(method, arguments); |
| } |
| |
| @override |
| ir.SuperMethodInvocation visitSuperMethodInvoke( |
| Send node, |
| MethodElement method, |
| NodeList arguments, |
| CallStructure callStructure, |
| _) { |
| return associateNode(buildSuperMethodInvoke(method, arguments), node); |
| } |
| |
| @override |
| ir.Expression visitSuperMethodSet( |
| Send node, MethodElement method, Node rhs, _) { |
| return buildSuperPropertyAccessor(method) |
| .buildAssignment(visitForValue(rhs), voidContext: isVoidContext); |
| } |
| |
| @override |
| ir.Not visitSuperNotEquals( |
| Send node, FunctionElement function, Node argument, _) { |
| return new ir.Not(buildSuperEquals(function, argument)); |
| } |
| |
| @override |
| ir.Expression visitSuperSetterGet(Send node, FunctionElement setter, _) { |
| return buildSuperPropertyAccessor(null, setter).buildSimpleRead(); |
| } |
| |
| @override |
| ir.MethodInvocation visitSuperSetterInvoke(Send node, FunctionElement setter, |
| NodeList arguments, CallStructure callStructure, _) { |
| return buildCall(buildSuperPropertyAccessor(null, setter).buildSimpleRead(), |
| callStructure, arguments); |
| } |
| |
| @override |
| ir.Expression visitSuperSetterSet( |
| SendSet node, FunctionElement setter, Node rhs, _) { |
| return buildSuperPropertyAccessor(null, setter) |
| .buildAssignment(visitForValue(rhs), voidContext: isVoidContext); |
| } |
| |
| @override |
| ir.SuperMethodInvocation visitSuperUnary( |
| Send node, UnaryOperator operator, FunctionElement function, _) { |
| transformerFlags |= TransformerFlag.superCalls; |
| return new ir.SuperMethodInvocation(kernel.irName(function.name, function), |
| new ir.Arguments.empty(), kernel.functionToIr(function)); |
| } |
| |
| @override |
| ir.Initializer visitThisConstructorInvoke( |
| Send node, |
| ConstructorElement thisConstructor, |
| NodeList arguments, |
| CallStructure callStructure, |
| _) { |
| if (kernel.isSyntheticError(thisConstructor)) { |
| return new ir.InvalidInitializer(); |
| } else { |
| return new ir.RedirectingInitializer( |
| kernel.functionToIr(thisConstructor), buildArguments(arguments)); |
| } |
| } |
| |
| @override |
| ir.ThisExpression visitThisGet(Identifier node, _) { |
| return new ir.ThisExpression(); |
| } |
| |
| @override |
| ir.MethodInvocation visitThisInvoke( |
| Send node, NodeList arguments, CallStructure callStructure, _) { |
| return buildCall(new ir.ThisExpression(), callStructure, arguments); |
| } |
| |
| Accessor buildThisPropertyAccessor(Name name) { |
| return new ThisPropertyAccessor(nameToIrName(name), null, null); |
| } |
| |
| @override |
| ir.Expression visitThisPropertyGet(Send node, Name name, _) { |
| return associateNode( |
| buildThisPropertyAccessor(name).buildSimpleRead(), node); |
| } |
| |
| @override |
| ir.MethodInvocation visitThisPropertyInvoke( |
| Send node, NodeList arguments, Selector selector, _) { |
| return associateNode( |
| buildInvokeSelector( |
| new ir.ThisExpression(), selector, buildArguments(arguments)), |
| node); |
| } |
| |
| @override |
| ir.Expression visitThisPropertySet(SendSet node, Name name, Node rhs, _) { |
| return buildThisPropertyAccessor(name) |
| .buildAssignment(visitForValue(rhs), voidContext: isVoidContext); |
| } |
| |
| @override |
| ir.Expression visitTopLevelConstantDeclaration(VariableDefinitions node, |
| Node definition, FieldElement field, ConstantExpression constant, _) { |
| // Shouldn't be called, handled by fieldToIr. |
| return internalError(node, "TopLevelFieldDeclaration"); |
| } |
| |
| @override |
| ir.Expression visitTopLevelFieldDeclaration(VariableDefinitions node, |
| Node definition, FieldElement field, Node initializer, _) { |
| // Shouldn't be called, handled by fieldToIr. |
| return internalError(node, "TopLevelFieldDeclaration"); |
| } |
| |
| @override |
| IrFunction visitTopLevelFunctionDeclaration(FunctionExpression node, |
| MethodElement function, NodeList parameters, Node body, _) { |
| return buildIrFunction(ir.ProcedureKind.Method, function, body); |
| } |
| |
| ir.Arguments buildArguments(NodeList arguments) { |
| List<ir.Expression> positional = <ir.Expression>[]; |
| List<ir.NamedExpression> named = <ir.NamedExpression>[]; |
| for (Expression expression in arguments.nodes) { |
| ir.TreeNode argument = visitForValue(expression); |
| if (argument is ir.NamedExpression) { |
| named.add(argument); |
| } else { |
| positional.add(argument); |
| } |
| } |
| return new ir.Arguments(positional, named: named, types: null); |
| } |
| |
| @override |
| IrFunction visitTopLevelGetterDeclaration( |
| FunctionExpression node, MethodElement getter, Node body, _) { |
| return buildIrFunction(ir.ProcedureKind.Getter, getter, body); |
| } |
| |
| @override |
| IrFunction visitTopLevelSetterDeclaration(FunctionExpression node, |
| MethodElement setter, NodeList parameters, Node body, _) { |
| return buildIrFunction(ir.ProcedureKind.Setter, setter, body); |
| } |
| |
| @override |
| ir.TypeLiteral visitTypeVariableTypeLiteralGet( |
| Send node, TypeVariableElement element, _) { |
| return buildTypeVariable(element); |
| } |
| |
| @override |
| ir.MethodInvocation visitTypeVariableTypeLiteralInvoke( |
| Send node, |
| TypeVariableElement element, |
| NodeList arguments, |
| CallStructure callStructure, |
| _) { |
| return buildCall(buildTypeVariable(element), callStructure, arguments); |
| } |
| |
| @override |
| ir.Expression visitTypeVariableTypeLiteralSet( |
| SendSet node, TypeVariableElement element, Node rhs, _) { |
| return new ReadOnlyAccessor(buildTypeVariable(element)) |
| .buildAssignment(visitForValue(rhs), voidContext: isVoidContext); |
| } |
| |
| @override |
| ir.Expression visitTypeVariableTypeLiteralSetIfNull( |
| Send node, TypeVariableElement element, Node rhs, _) { |
| return new ReadOnlyAccessor(buildTypeVariable(element)) |
| .buildNullAwareAssignment(visitForValue(rhs), |
| voidContext: isVoidContext); |
| } |
| |
| @override |
| ir.TypeLiteral visitTypedefTypeLiteralGet( |
| Send node, ConstantExpression constant, _) { |
| return buildTypeLiteral(constant); |
| } |
| |
| @override |
| ir.MethodInvocation visitTypedefTypeLiteralInvoke( |
| Send node, |
| ConstantExpression constant, |
| NodeList arguments, |
| CallStructure callStructure, |
| _) { |
| return buildCall(buildTypeLiteral(constant), callStructure, arguments); |
| } |
| |
| @override |
| ir.Expression visitTypedefTypeLiteralSet( |
| SendSet node, ConstantExpression constant, Node rhs, _) { |
| return buildTypeLiteralSet(constant, rhs); |
| } |
| |
| @override |
| ir.Expression handleTypeLiteralConstantSetIfNulls( |
| SendSet node, ConstantExpression constant, Node rhs, _) { |
| // Degenerate case: ignores [rhs] as a type literal is never null. |
| return buildTypeLiteral(constant); |
| } |
| |
| @override |
| ir.MethodInvocation visitUnary( |
| Send node, UnaryOperator operator, Node expression, _) { |
| return associateNode( |
| new ir.MethodInvocation( |
| visitForValue(expression), |
| kernel.irName(operator.selectorName, currentElement), |
| new ir.Arguments.empty()), |
| node); |
| } |
| |
| @override |
| visitConditionalUri(ConditionalUri node) { |
| // Shouldn't be called, handled by library loader. |
| return internalError(node, "ConditionalUri"); |
| } |
| |
| @override |
| visitDottedName(DottedName node) { |
| // Shouldn't be called, handled by library loader. |
| return internalError(node, "DottedName"); |
| } |
| |
| @override |
| visitForIn(ForIn node) { |
| // Shouldn't be called, handled by [visitAsyncForIn] or [visitSyncForIn]. |
| return internalError(node, "ForIn"); |
| } |
| |
| @override |
| ir.Expression visitIndexSetIfNull( |
| SendSet node, Node receiver, Node index, Node rhs, _) { |
| return buildIndexAccessor(receiver, index).buildNullAwareAssignment( |
| visitForValue(rhs), |
| voidContext: isVoidContext); |
| } |
| |
| @override |
| ir.Expression visitSuperIndexSetIfNull(SendSet node, MethodElement getter, |
| MethodElement setter, Node index, Node rhs, _) { |
| return buildSuperIndexAccessor(index, getter, setter) |
| .buildNullAwareAssignment(visitForValue(rhs), |
| voidContext: isVoidContext); |
| } |
| |
| @override |
| ir.Node visitVariableDefinitions(VariableDefinitions definitions) { |
| // TODO(ahe): This method is copied from [SemanticDeclarationResolvedMixin] |
| // and modified. Perhaps we can find a way to avoid code duplication. |
| List<ir.VariableDeclaration> variables = <ir.VariableDeclaration>[]; |
| computeVariableStructures(definitions, |
| (Node node, VariableStructure structure) { |
| if (structure == null) { |
| return internalError(node, 'No structure for $node'); |
| } else { |
| ir.VariableDeclaration variable = |
| structure.dispatch(declVisitor, node, null); |
| variables.add(variable); |
| return variable; |
| } |
| }); |
| if (variables.length == 1) return variables.single; |
| return new VariableDeclarations(variables); |
| } |
| |
| IrFunction buildFunction() { |
| return kernel.compiler.reporter.withCurrentElement(currentElement, () { |
| if (kernel.isSyntheticError(currentElement)) { |
| kernel.internalError(currentElement, |
| "Can't build synthetic function element: $currentElement"); |
| } else if (currentElement.isMalformed) { |
| ir.FunctionNode node = buildFunctionNode(currentElement, null); |
| if (currentElement.isGenerativeConstructor) { |
| return new IrFunction.constructor( |
| node, <ir.Initializer>[new ir.InvalidInitializer()]); |
| } else { |
| node.body = new ir.InvalidStatement()..parent = node; |
| return new IrFunction.procedure(ir.ProcedureKind.Method, node); |
| } |
| } else if (currentElement.isSynthesized) { |
| if (currentElement.isGenerativeConstructor) { |
| return buildGenerativeConstructor(currentElement, null, null); |
| } else { |
| return internalError(currentElement, "Unhandled synthetic function."); |
| } |
| } else { |
| Node node = currentElement.node; |
| if (node.isErroneous) { |
| return internalError(currentElement, "Unexpected syntax error."); |
| } else { |
| return node.accept(this); |
| } |
| } |
| }); |
| } |
| |
| ir.Expression buildInitializer() { |
| return kernel.compiler.reporter.withCurrentElement(currentElement, () { |
| FieldElement field = currentElement; |
| return field.isMalformed |
| ? new ir.InvalidExpression() |
| : visitForValue(field.initializer); |
| }); |
| } |
| } |
| |
| class VariableDeclarations implements ir.Node { |
| final List<ir.VariableDeclaration> variables; |
| |
| VariableDeclarations(this.variables); |
| |
| accept(ir.Visitor v) => throw "unsupported"; |
| |
| visitChildren(ir.Visitor v) => throw "unsupported"; |
| |
| String toString() => "VariableDeclarations($variables)"; |
| } |
| |
| class IrFunction implements ir.Node { |
| final ir.ProcedureKind kind; |
| final bool isConstructor; |
| final ir.FunctionNode node; |
| final List<ir.Initializer> initializers; |
| |
| IrFunction(this.kind, this.isConstructor, this.node, this.initializers); |
| |
| IrFunction.procedure(ir.ProcedureKind kind, ir.FunctionNode node) |
| : this(kind, false, node, null); |
| |
| IrFunction.constructor( |
| ir.FunctionNode node, List<ir.Initializer> initializers) |
| : this(null, true, node, initializers); |
| |
| accept(ir.Visitor v) => throw "unsupported"; |
| |
| visitChildren(ir.Visitor v) => throw "unsupported"; |
| |
| String toString() { |
| return "IrFunction($kind, $isConstructor, $node, $initializers)"; |
| } |
| } |