| // 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), | 
 |         null); | 
 |   } | 
 |  | 
 |   @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 = | 
 |         kernel.computeEffectiveTarget(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, _) { | 
 |     // TODO(sra): Find binary operator. | 
 |     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, | 
 |         node); | 
 |     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), null, | 
 |         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, 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)), | 
 |             null)); | 
 |   } | 
 |  | 
 |   @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), null, | 
 |             voidContext: isVoidContext); | 
 |   } | 
 |  | 
 |   ir.LogicalExpression buildLogicalExpression( | 
 |       Node left, Operator operator, Node right) { | 
 |     return new ir.LogicalExpression( | 
 |         visitForValue(left), operator.source, visitForValue(right)); | 
 |   } | 
 |  | 
 |   @override | 
 |   ir.Expression visitIfNull(Send node, Node left, Node right, _) { | 
 |     var leftValue = new ir.VariableDeclaration.forValue(visitForValue(left)); | 
 |     return new ir.Let( | 
 |         leftValue, | 
 |         new ir.ConditionalExpression(buildIsNull(new ir.VariableGet(leftValue)), | 
 |             visitForValue(right), new ir.VariableGet(leftValue), null)); | 
 |   } | 
 |  | 
 |   @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, SendSet node) { | 
 |     ir.Name name = kernel.irName(rhs.operator.selectorName, currentElement); | 
 |     ir.Expression result; | 
 |     switch (rhs.kind) { | 
 |       case CompoundKind.POSTFIX: | 
 |         result = | 
 |             accessor.buildPostfixIncrement(name, voidContext: isVoidContext); | 
 |         break; | 
 |  | 
 |       case CompoundKind.PREFIX: | 
 |         result = | 
 |             accessor.buildPrefixIncrement(name, voidContext: isVoidContext); | 
 |         break; | 
 |  | 
 |       case CompoundKind.ASSIGNMENT: | 
 |         result = accessor.buildCompoundAssignment(name, visitForValue(rhs.rhs), | 
 |             voidContext: isVoidContext); | 
 |         break; | 
 |     } | 
 |     assert(accessor.builtBinary != null); | 
 |     kernel.nodeToAstOperator[accessor.builtBinary] = node; | 
 |     if (accessor.builtGetter != null) { | 
 |       kernel.nodeToAst[accessor.builtGetter] = node; | 
 |     } | 
 |     return result; | 
 |   } | 
 |  | 
 |   @override | 
 |   ir.Expression handleLocalCompounds( | 
 |       SendSet node, LocalElement local, CompoundRhs rhs, _, | 
 |       {bool isSetterValid}) { | 
 |     ir.Expression compound = | 
 |         buildCompound(new VariableAccessor(getLocal(local)), rhs, node); | 
 |     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), null, | 
 |         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 associateNode(buildStaticGet(field), node); | 
 |   } | 
 |  | 
 |   @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), null, | 
 |         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 associateNode( | 
 |         buildStaticInvoke(function, arguments, isConst: false), node); | 
 |   } | 
 |  | 
 |   @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, | 
 |       _) { | 
 |     // TODO(sra): Find binary operator. | 
 |     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, node); | 
 |   } | 
 |  | 
 |   @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, node); | 
 |   } | 
 |  | 
 |   @override | 
 |   ir.Expression handleTypeLiteralConstantCompounds( | 
 |       SendSet node, ConstantExpression constant, CompoundRhs rhs, _) { | 
 |     return buildCompound( | 
 |         new ReadOnlyAccessor(buildTypeLiteral(constant)), rhs, node); | 
 |   } | 
 |  | 
 |   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, node); | 
 |   } | 
 |  | 
 |   @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), null, | 
 |         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), null, | 
 |             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), null, | 
 |         voidContext: isVoidContext); | 
 |   } | 
 |  | 
 |   @override | 
 |   ir.Expression visitSuperIndexSetIfNull(SendSet node, MethodElement getter, | 
 |       MethodElement setter, Node index, Node rhs, _) { | 
 |     return buildSuperIndexAccessor(index, getter, setter) | 
 |         .buildNullAwareAssignment(visitForValue(rhs), null, | 
 |             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() | 
 |           : associateNode(visitForValue(field.initializer), 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)"; | 
 |   } | 
 | } |