| Index: pkg/compiler/lib/src/kernel/kernel_visitor.dart
|
| diff --git a/pkg/compiler/lib/src/kernel/kernel_visitor.dart b/pkg/compiler/lib/src/kernel/kernel_visitor.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..6f783651bb857926190a33de5d0bcd004d999046
|
| --- /dev/null
|
| +++ b/pkg/compiler/lib/src/kernel/kernel_visitor.dart
|
| @@ -0,0 +1,2703 @@
|
| +// 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 '../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 'fall_through_visitor.dart' show fallsThrough;
|
| +import 'kernel.dart' show ConstructorTarget, Kernel;
|
| +import 'unavailable.dart' show UnavailableVisitor;
|
| +import 'unresolved.dart' show RastaUnresolved;
|
| +
|
| +/// 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,
|
| + RastaUnresolved,
|
| + KernelError
|
| + implements
|
| + SemanticVisitor,
|
| + SemanticSendVisitor,
|
| + SemanticDeclarationVisitor {
|
| + TreeElements elements;
|
| + AstElement currentElement;
|
| + final Kernel kernel;
|
| +
|
| + 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>{};
|
| +
|
| + 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(
|
| + new ir.ForInStatement(variable, iterable, body, isAsync: isAsync),
|
| + 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);
|
| + } else if (kernel.isSyntheticError(element)) {
|
| + return buildStaticAccessor(null);
|
| + } else if (element.isGetter) {
|
| + if (element.isInstanceMember) {
|
| + return new ThisPropertyAccessor(kernel.irName(element.name, element));
|
| + } else {
|
| + GetterElement getter = element;
|
| + Element setter = getter.setter;
|
| + return buildStaticAccessor(getter, setter);
|
| + }
|
| + } else if (element.isLocal) {
|
| + return new VariableAccessor(getLocal(element));
|
| + } else if (element.isField) {
|
| + return buildStaticAccessor(element);
|
| + } else {
|
| + return buildStaticAccessor(null);
|
| + }
|
| + }
|
| +
|
| + /// Builds a for-in statement for this case:
|
| + ///
|
| + /// for (element in expression) body
|
| + ///
|
| + /// This is normalized to:
|
| + ///
|
| + /// for (final #t in expression) {
|
| + /// element = #t;
|
| + /// body;
|
| + /// }
|
| + ir.Statement buildForInWithoutDeclaration(ForIn node, Element element,
|
| + {bool isAsync}) {
|
| + Accessor accessor = computeAccessor(node, elements.getForInVariable(node));
|
| + // Since we've created [variable], we know it's only assigned to in the
|
| + // loop header and can be final.
|
| + ir.VariableDeclaration variable =
|
| + new ir.VariableDeclaration.forValue(null, isFinal: true);
|
| + ir.Statement assigment = new ir.ExpressionStatement(accessor
|
| + .buildAssignment(new ir.VariableGet(variable), voidContext: true));
|
| + ir.Block body = buildStatementInBlock(node.body, forceBlock: true);
|
| + List<ir.Statement> statements = <ir.Statement>[assigment]
|
| + ..addAll(body.statements);
|
| + return buildForInCommon(node, variable, new ir.Block(statements),
|
| + isAsync: isAsync);
|
| + }
|
| +
|
| + ir.Statement buildForIn(ForIn node, {bool isAsync}) {
|
| + VariableDefinitions declaration =
|
| + node.declaredIdentifier.asVariableDefinitions();
|
| + if (declaration != null) {
|
| + return buildForInWithDeclaration(node, declaration, isAsync: isAsync);
|
| + } else {
|
| + Element element = elements.getForInVariable(node);
|
| + return buildForInWithoutDeclaration(node, element, isAsync: isAsync);
|
| + }
|
| + }
|
| +
|
| + @override
|
| + ir.Statement visitAsyncForIn(AsyncForIn node) {
|
| + return buildForIn(node, isAsync: true);
|
| + }
|
| +
|
| + @override
|
| + ir.AwaitExpression visitAwait(Await node) {
|
| + return new ir.AwaitExpression(visitForValue(node.expression));
|
| + }
|
| +
|
| + @override
|
| + ir.Statement visitBlock(Block node) {
|
| + return buildBreakTarget(
|
| + buildStatementInBlock(node), node, elements.getTargetDefinition(node));
|
| + }
|
| +
|
| + bool buildStatement(Statement statement, List<ir.Statement> statements) {
|
| + ir.Node irNode = statement.accept(this);
|
| + bool hasVariableDeclaration = false;
|
| + if (irNode is VariableDeclarations) {
|
| + statements.addAll(irNode.variables);
|
| + hasVariableDeclaration = true;
|
| + } else {
|
| + statements.add(irNode);
|
| + if (irNode is ir.VariableDeclaration) {
|
| + hasVariableDeclaration = true;
|
| + }
|
| + }
|
| + return hasVariableDeclaration;
|
| + }
|
| +
|
| + ir.Statement buildStatementInBlock(Statement node, {bool forceBlock: false}) {
|
| + if (node == null) return null;
|
| + List<ir.Statement> statements = <ir.Statement>[];
|
| + if (node is Block) {
|
| + for (Node statement in node.statements.nodes) {
|
| + buildStatement(statement, statements);
|
| + }
|
| + } else {
|
| + if (buildStatement(node, statements)) forceBlock = true;
|
| + if (!forceBlock && statements.length == 1) {
|
| + return statements.single;
|
| + }
|
| + // One VariableDefinitions statement node (dart2js AST) may generate
|
| + // multiple statements in Kernel IR so we sometimes fall through here.
|
| + }
|
| + return new ir.Block(statements);
|
| + }
|
| +
|
| + @override
|
| + ir.Statement visitBreakStatement(BreakStatement node) {
|
| + JumpTarget target = elements.getTargetOf(node);
|
| + if (target == null || !target.statement.isValidBreakTarget()) {
|
| + // This is a break in an invalid position.
|
| + return new ir.InvalidStatement();
|
| + }
|
| + // A break can break to itself in the degenerate case `label: break
|
| + // label'`.
|
| + return buildBreakTarget(new ir.BreakStatement(getBreakTarget(target)), node,
|
| + elements.getTargetDefinition(node));
|
| + }
|
| +
|
| + CascadeReceiver computeCascadeReceiver(Cascade cascade) {
|
| + CascadeReceiver receiver;
|
| + Expression send = cascade.expression.asSend();
|
| + while (send != null && (receiver = send.asCascadeReceiver()) == null) {
|
| + Expression possibleReceiver = send.asSend()?.receiver;
|
| + if (possibleReceiver != null) {
|
| + send = possibleReceiver;
|
| + } else {
|
| + // Can happen in this case: `a..add(foo)('WHAT')`.
|
| + send = send.asSend()?.selector;
|
| + }
|
| + }
|
| + if (receiver == null) {
|
| + internalError(cascade, "Can't find cascade receiver");
|
| + }
|
| + return receiver;
|
| + }
|
| +
|
| + @override
|
| + ir.Let visitCascade(Cascade node) {
|
| + // Given this cascade expression `receiver..cascade1()..cascade2()`, the
|
| + // parser has produced a tree like this:
|
| + // Cascade(Send(
|
| + // CascadeReceiver(Cascade(Send(
|
| + // CascadeRecevier(receiver), 'cascade1', []))),
|
| + // 'cascade2', []))
|
| + // If viewed as a tree, `CascadeReceiver(receiver)` is the left-most leaf
|
| + // node. Below, we create this:
|
| + // cascades = [
|
| + // Cascade(Send(CascadeReceiver(...), 'cascade2', [])),
|
| + // Cascade(Send(CascadeReceiver(...), 'cascade1', []))]
|
| + // Notice that the cascades are in reverse order, which we use to build a
|
| + // `let` expression bottom up.
|
| + // First iteration of the loop produces:
|
| + // let dummy = rcv.cascade2() in
|
| + // rcv
|
| + // Second iteration:
|
| + // let dummy = rcv.cascade1() in
|
| + // let dummy = rcv.cascade2() in
|
| + // rcv
|
| + // Finally we return:
|
| + // let rcv = receiver in
|
| + // let dummy = rcv.cascade1() in
|
| + // let dummy = rcv.cascade2() in
|
| + // rcv
|
| + int startLength;
|
| + assert((startLength = cascadeReceivers.length) >= 0);
|
| +
|
| + Cascade cascade = node;
|
| + List<Cascade> cascades = <Cascade>[];
|
| + CascadeReceiver receiver;
|
| + ir.VariableDeclaration receiverVariable = makeOrReuseVariable(null);
|
| +
|
| + do {
|
| + cascades.add(cascade);
|
| + receiver = computeCascadeReceiver(cascade);
|
| + cascadeReceivers[receiver] = new ir.VariableGet(receiverVariable);
|
| + cascade = receiver.expression.asCascade();
|
| + } while (cascade != null);
|
| + // At this point, all nested [Cascades] targeting the same receiver have
|
| + // been collected in [cascades] in reverse order. [receiver] is the
|
| + // left-most receiver. [receiverVariable] will hold the value of evaluating
|
| + // [receiver]. Each [CascadeReceiver] has a getter for [receiverVariable]
|
| + // in [cascadeReceivers].
|
| +
|
| + receiverVariable.initializer = visitForValue(receiver.expression);
|
| + receiverVariable.initializer.parent = receiverVariable;
|
| +
|
| + ir.Expression result = new ir.VariableGet(receiverVariable); // rcv.
|
| + for (Cascade cascade in cascades) {
|
| + // When evaluating `cascade.expression`, we stop the recursion at
|
| + // [visitCascadeReceiver] and instead returns an [ir.VariableGet].
|
| + // TODO(ahe): Use visitForEffect here?
|
| + ir.Expression value = visitForValue(cascade.expression);
|
| + result = new ir.Let(makeOrReuseVariable(value), result);
|
| + }
|
| +
|
| + assert(startLength == cascadeReceivers.length);
|
| + return new ir.Let(receiverVariable, result);
|
| + }
|
| +
|
| + @override
|
| + ir.VariableGet visitCascadeReceiver(CascadeReceiver node) {
|
| + return cascadeReceivers.remove(node);
|
| + }
|
| +
|
| + @override
|
| + visitCaseMatch(CaseMatch node) {
|
| + // Shouldn't be called. Handled by [visitSwitchCase].
|
| + return internalError(node, "CaseMatch");
|
| + }
|
| +
|
| + @override
|
| + ir.Catch visitCatchBlock(CatchBlock node) {
|
| + ir.VariableDeclaration exception =
|
| + (node.exception == null) ? null : getLocal(elements[node.exception]);
|
| + ir.VariableDeclaration trace =
|
| + (node.trace == null) ? null : getLocal(elements[node.trace]);
|
| + ir.DartType guard = computeType(node.type);
|
| + return new ir.Catch(exception, buildStatementInBlock(node.block),
|
| + guard: guard, stackTrace: trace);
|
| + }
|
| +
|
| + @override
|
| + ir.ConditionalExpression visitConditional(Conditional node) {
|
| + return new ir.ConditionalExpression(
|
| + visitForValue(node.condition),
|
| + visitWithCurrentContext(node.thenExpression),
|
| + visitWithCurrentContext(node.elseExpression));
|
| + }
|
| +
|
| + @override
|
| + ir.Statement visitContinueStatement(ContinueStatement node) {
|
| + JumpTarget target = elements.getTargetOf(node);
|
| + if (target == null || !target.statement.isValidContinueTarget()) {
|
| + // This is a continue in an invalid position.
|
| + return new ir.InvalidStatement();
|
| + }
|
| + ir.SwitchCase switchCase = getContinueSwitchTarget(target);
|
| + return (switchCase == null)
|
| + ? new ir.BreakStatement(getContinueTarget(target))
|
| + : new ir.ContinueSwitchStatement(switchCase);
|
| + }
|
| +
|
| + @override
|
| + ir.Statement visitDoWhile(DoWhile node) {
|
| + JumpTarget jumpTarget = elements.getTargetDefinition(node);
|
| + ir.Statement body =
|
| + buildContinueTarget(buildStatementInBlock(node.body), node, jumpTarget);
|
| + ir.Expression condition = visitForValue(node.condition);
|
| + return buildBreakTarget(
|
| + new ir.DoStatement(body, condition), node, jumpTarget);
|
| + }
|
| +
|
| + @override
|
| + ir.EmptyStatement visitEmptyStatement(EmptyStatement node) {
|
| + return new ir.EmptyStatement();
|
| + }
|
| +
|
| + @override
|
| + visitEnum(Enum node) {
|
| + // Not called normally. In dart2js, enums are represented as class
|
| + // elements, so `classToIr` handles enums. All the synthetic members of an
|
| + // enum class have already been installed by dart2js and we don't have to
|
| + // do anything special.
|
| + return internalError(node, "Enum");
|
| + }
|
| +
|
| + @override
|
| + ir.ExpressionStatement visitExpressionStatement(ExpressionStatement node) {
|
| + return new ir.ExpressionStatement(visitForEffect(node.expression));
|
| + }
|
| +
|
| + @override
|
| + ir.Statement visitFor(For node) {
|
| + VariableDefinitions initializers =
|
| + node.initializer?.asVariableDefinitions();
|
| + ir.Expression initializer;
|
| + List<ir.VariableDeclaration> variables;
|
| + if (initializers != null) {
|
| + ir.Block block = buildStatementInBlock(initializers, forceBlock: true);
|
| + variables = new List<ir.VariableDeclaration>.from(block.statements);
|
| + } else {
|
| + if (node.initializer != null) {
|
| + initializer = visitForValue(node.initializer);
|
| + }
|
| + variables = const <ir.VariableDeclaration>[];
|
| + }
|
| + ir.Expression condition = visitForValue(node.condition);
|
| + List<ir.Expression> updates = <ir.Expression>[];
|
| + for (Expression update in node.update) {
|
| + updates.add(visitForEffect(update));
|
| + }
|
| +
|
| + JumpTarget jumpTarget = elements.getTargetDefinition(node);
|
| + ir.Statement body =
|
| + buildContinueTarget(buildStatementInBlock(node.body), node, jumpTarget);
|
| + ir.ForStatement forStatement =
|
| + new ir.ForStatement(variables, condition, updates, body);
|
| + 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 new ir.ListLiteral(elements,
|
| + typeArgument: computeTypeFromTypes(node.typeArguments),
|
| + // TODO(ahe): Should constness be validated?
|
| + isConst: node.isConst);
|
| + }
|
| +
|
| + @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 new ir.MapLiteral(entries,
|
| + keyType: typeArguments.first,
|
| + valueType: typeArguments.last,
|
| + // TODO(ahe): Should Constness be validated?
|
| + isConst: node.isConst);
|
| + }
|
| +
|
| + @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) {
|
| + return new ir.SymbolLiteral(node.slowNameString);
|
| + }
|
| +
|
| + @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);
|
| + }
|
| +
|
| + @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 (!isLastCase &&
|
| + (statements.isEmpty || fallsThrough(statements.last))) {
|
| + statements.add(new ir.ExpressionStatement(new ir.Throw(
|
| + new ir.StaticInvocation(kernel.getFallThroughErrorBuilder(),
|
| + new ir.Arguments.empty()))));
|
| + }
|
| + ir.Statement body;
|
| + if (!hasVariableDeclaration && statements.length == 1) {
|
| + body = statements.single;
|
| + } else {
|
| + 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(
|
| + new ir.WhileStatement(condition, body), 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 buildBinaryOperator(left, operator.selectorName, right);
|
| + }
|
| +
|
| + 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, () {
|
| + return new ir.FunctionExpression(buildFunctionNode(closure, body));
|
| + });
|
| + }
|
| +
|
| + @override
|
| + ir.Expression visitCompoundIndexSet(SendSet node, Node receiver, Node index,
|
| + AssignmentOperator operator, Node rhs, _) {
|
| + return buildIndexAccessor(receiver, index).buildCompoundAssignment(
|
| + kernel.irName(operator.selectorName, currentElement),
|
| + visitForValue(rhs),
|
| + voidContext: isVoidContext);
|
| + }
|
| +
|
| + @override
|
| + ir.InvocationExpression visitConstConstructorInvoke(
|
| + NewExpression node, ConstructedConstantExpression constant, _) {
|
| + return buildConstructorInvoke(node, isConst: true);
|
| + }
|
| +
|
| + @override
|
| + visitConstantGet(Send node, ConstantExpression constant, _) {
|
| + // TODO(ahe): This method is never called. Is it a bug in semantic visitor?
|
| + return internalError(node, "ConstantGet");
|
| + }
|
| +
|
| + @override
|
| + visitConstantInvoke(Send node, ConstantExpression constant,
|
| + NodeList arguments, CallStructure callStructure, _) {
|
| + // TODO(ahe): This method is never called. Is it a bug in semantic visitor?
|
| + return internalError(node, "ConstantInvoke");
|
| + }
|
| +
|
| + @override
|
| + ir.InvalidExpression visitConstructorIncompatibleInvoke(
|
| + NewExpression node,
|
| + ConstructorElement constructor,
|
| + InterfaceType type,
|
| + NodeList arguments,
|
| + CallStructure callStructure,
|
| + _) {
|
| + return new ir.InvalidExpression();
|
| + }
|
| +
|
| + @override
|
| + ir.PropertyGet visitDynamicPropertyGet(
|
| + Send node, Node receiver, Name name, _) {
|
| + return new ir.PropertyGet(visitForValue(receiver), nameToIrName(name));
|
| + }
|
| +
|
| + @override
|
| + ir.MethodInvocation visitDynamicPropertyInvoke(
|
| + Send node, Node receiver, NodeList arguments, Selector selector, _) {
|
| + return buildInvokeSelector(
|
| + visitForValue(receiver), selector, buildArguments(arguments));
|
| + }
|
| +
|
| + @override
|
| + ir.Expression handleDynamicCompounds(
|
| + Send node, Node receiver, Name name, CompoundRhs rhs, _) {
|
| + ir.Expression receiverNode =
|
| + receiver == null ? new ir.ThisExpression() : visitForValue(receiver);
|
| + return buildCompound(
|
| + PropertyAccessor.make(receiverNode, nameToIrName(name)), rhs);
|
| + }
|
| +
|
| + @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)
|
| + : PropertyAccessor.make(visitForValue(receiver), irName);
|
| + return accessor.buildNullAwareAssignment(visitForValue(rhs),
|
| + voidContext: isVoidContext);
|
| + }
|
| +
|
| + @override
|
| + ir.TypeLiteral visitDynamicTypeLiteralGet(
|
| + Send node, ConstantExpression constant, _) {
|
| + return buildTypeLiteral(constant);
|
| + }
|
| +
|
| + @override
|
| + ir.MethodInvocation visitDynamicTypeLiteralInvoke(
|
| + Send node,
|
| + ConstantExpression constant,
|
| + NodeList arguments,
|
| + CallStructure callStructure,
|
| + _) {
|
| + return buildCall(buildTypeLiteral(constant), callStructure, arguments);
|
| + }
|
| +
|
| + @override
|
| + ir.Expression visitDynamicTypeLiteralSet(
|
| + SendSet node, ConstantExpression constant, Node rhs, _) {
|
| + return buildTypeLiteralSet(constant, rhs);
|
| + }
|
| +
|
| + ir.MethodInvocation buildBinaryOperator(
|
| + Node left, String operator, Node right) {
|
| + ir.Name name = kernel.irName(operator, currentElement);
|
| + return makeBinary(visitForValue(left), name, visitForValue(right));
|
| + }
|
| +
|
| + @override
|
| + ir.MethodInvocation visitEquals(Send node, Node left, Node right, _) {
|
| + return buildBinaryOperator(left, '==', right);
|
| + }
|
| +
|
| + @override
|
| + ir.MethodInvocation visitExpressionInvoke(Send node, Node expression,
|
| + NodeList arguments, CallStructure callStructure, _) {
|
| + return buildCall(visitForValue(expression), callStructure, arguments);
|
| + }
|
| +
|
| + @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);
|
| + }
|
| +
|
| + void addFieldsWithInitializers(
|
| + ConstructorElement constructor, List<ir.Initializer> initializers) {
|
| + constructor.enclosingClass.forEachInstanceField((_, FieldElement element) {
|
| + // Convert the element into the corresponding IR field before asking
|
| + // if the initializer exists. This is necessary to ensure that the
|
| + // element has been analyzed before looking at its initializer.
|
| + ir.Field field = kernel.fieldToIr(element);
|
| + if (element.initializer != null) {
|
| + KernelVisitor visitor =
|
| + new KernelVisitor(element, element.treeElements, kernel);
|
| + ir.Expression value = visitor.buildInitializer();
|
| + initializers.add(new ir.FieldInitializer(field, value));
|
| + }
|
| + });
|
| + }
|
| +
|
| + 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 {
|
| + addFieldsWithInitializers(constructor, constructorInitializers);
|
| + constructorInitializers.add(new ir.SuperInitializer(
|
| + kernel.functionToIr(constructor.definingConstructor),
|
| + new ir.Arguments(arguments, named: named, types: null)));
|
| + }
|
| + } else {
|
| + addFieldsWithInitializers(constructor, constructorInitializers);
|
| + 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));
|
| + }
|
| +
|
| + @override
|
| + ir.Expression visitIfNotNullDynamicPropertyGet(
|
| + Send node, Node receiver, Name name, _) {
|
| + return buildNullAwarePropertyAccessor(receiver, name).buildSimpleRead();
|
| + }
|
| +
|
| + @override
|
| + ir.Let visitIfNotNullDynamicPropertyInvoke(
|
| + Send node, Node receiverNode, NodeList arguments, Selector selector, _) {
|
| + ir.VariableDeclaration receiver =
|
| + makeOrReuseVariable(visitForValue(receiverNode));
|
| + return makeLet(
|
| + receiver,
|
| + new ir.ConditionalExpression(
|
| + buildIsNull(new ir.VariableGet(receiver)),
|
| + new ir.NullLiteral(),
|
| + buildInvokeSelector(new ir.VariableGet(receiver), selector,
|
| + buildArguments(arguments))));
|
| + }
|
| +
|
| + @override
|
| + ir.Expression visitIfNotNullDynamicPropertySet(
|
| + SendSet node, Node receiver, Name name, Node rhs, _) {
|
| + return buildNullAwarePropertyAccessor(receiver, name)
|
| + .buildAssignment(visitForValue(rhs), voidContext: isVoidContext);
|
| + }
|
| +
|
| + @override
|
| + ir.Expression visitIfNotNullDynamicPropertySetIfNull(
|
| + Send node, Node receiver, Name name, Node rhs, _) {
|
| + return buildNullAwarePropertyAccessor(receiver, name)
|
| + .buildNullAwareAssignment(visitForValue(rhs),
|
| + voidContext: isVoidContext);
|
| + }
|
| +
|
| + ir.LogicalExpression buildLogicalExpression(
|
| + Node left, Operator operator, Node right) {
|
| + return new ir.LogicalExpression(
|
| + visitForValue(left), operator.source, visitForValue(right));
|
| + }
|
| +
|
| + @override
|
| + ir.LogicalExpression visitIfNull(Send node, Node left, Node right, _) {
|
| + return buildLogicalExpression(left, node.selector, right);
|
| + }
|
| +
|
| + @override
|
| + ir.Initializer visitImplicitSuperConstructorInvoke(FunctionExpression node,
|
| + ConstructorElement superConstructor, InterfaceType type, _) {
|
| + if (superConstructor == null) {
|
| + // TODO(ahe): Semantic visitor shouldn't call this.
|
| + return new ir.InvalidInitializer();
|
| + }
|
| + return new ir.SuperInitializer(
|
| + kernel.functionToIr(superConstructor), new ir.Arguments.empty());
|
| + }
|
| +
|
| + Accessor buildIndexAccessor(Node receiver, Node index) {
|
| + return IndexAccessor.make(visitForValue(receiver), visitForValue(index));
|
| + }
|
| +
|
| + @override
|
| + ir.Expression visitIndex(Send node, Node receiver, Node index, _) {
|
| + return buildIndexAccessor(receiver, index).buildSimpleRead();
|
| + }
|
| +
|
| + 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 buildIndexAccessor(receiver, index)
|
| + .buildAssignment(visitForValue(rhs), voidContext: isVoidContext);
|
| + }
|
| +
|
| + 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;
|
| + return new ir.FunctionDeclaration(
|
| + local, buildFunctionNode(localFunction, body));
|
| + });
|
| + }
|
| +
|
| + @override
|
| + ir.VariableDeclaration visitLocalVariableDeclaration(VariableDefinitions node,
|
| + Node definition, LocalVariableElement variable, Node initializer, _) {
|
| + return buildLocalVariableDeclaration(variable, initializer);
|
| + }
|
| +
|
| + ir.VariableGet buildLocalGet(LocalElement local) {
|
| + return new ir.VariableGet(getLocal(local));
|
| + }
|
| +
|
| + @override
|
| + ir.VariableGet handleLocalGet(Send node, LocalElement element, _) {
|
| + return buildLocalGet(element);
|
| + }
|
| +
|
| + ir.Expression buildCompound(Accessor accessor, CompoundRhs rhs) {
|
| + ir.Name name = kernel.irName(rhs.operator.selectorName, currentElement);
|
| + switch (rhs.kind) {
|
| + case CompoundKind.POSTFIX:
|
| + return accessor.buildPostfixIncrement(name, voidContext: isVoidContext);
|
| +
|
| + case CompoundKind.PREFIX:
|
| + return accessor.buildPrefixIncrement(name, voidContext: isVoidContext);
|
| +
|
| + case CompoundKind.ASSIGNMENT:
|
| + return accessor.buildCompoundAssignment(name, visitForValue(rhs.rhs),
|
| + voidContext: isVoidContext);
|
| + }
|
| + }
|
| +
|
| + @override
|
| + ir.Expression handleLocalCompounds(
|
| + SendSet node, LocalElement local, CompoundRhs rhs, _,
|
| + {bool isSetterValid}) {
|
| + return buildCompound(new VariableAccessor(getLocal(local)), rhs);
|
| + }
|
| +
|
| + @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 new ir.Not(buildBinaryOperator(left, '==', right));
|
| + }
|
| +
|
| + @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 buildCall(buildLocalGet(element), callStructure, arguments);
|
| + }
|
| +
|
| + @override
|
| + ir.Expression handleLocalSetIfNulls(
|
| + SendSet node, LocalElement local, Node rhs, _,
|
| + {bool isSetterValid}) {
|
| + return new VariableAccessor(getLocal(local)).buildNullAwareAssignment(
|
| + visitForValue(rhs),
|
| + voidContext: isVoidContext);
|
| + }
|
| +
|
| + @override
|
| + IrFunction visitRedirectingFactoryConstructorDeclaration(
|
| + FunctionExpression node,
|
| + ConstructorElement constructor,
|
| + NodeList parameters,
|
| + DartType redirectionType, // TODO(ahe): Should be InterfaceType.
|
| + ConstructorElement redirectionTarget,
|
| + _) {
|
| + if (!constructor.isFactoryConstructor) {
|
| + // TODO(ahe): This seems like a bug in semantic visitor and how it
|
| + // recovers from a bad constructor.
|
| + return new IrFunction.constructor(buildFunctionNode(constructor, null),
|
| + <ir.Initializer>[new ir.InvalidInitializer()]);
|
| + }
|
| + ir.Statement body = null;
|
| + if (kernel.isSyntheticError(redirectionTarget)) {
|
| + body = new ir.InvalidStatement();
|
| + } else {
|
| + // TODO(ahe): This should be implemented, but doesn't matter much unless
|
| + // we support reflection. At the call-site, we bypass this factory and
|
| + // call its effective target directly. So this factory is only necessary
|
| + // for reflection.
|
| + body = new ir.InvalidStatement();
|
| + }
|
| + IrFunction function =
|
| + buildIrFunction(ir.ProcedureKind.Factory, constructor, null);
|
| + function.node.body = body..parent = function.node;
|
| + return function;
|
| + }
|
| +
|
| + @override
|
| + ir.InvocationExpression visitRedirectingFactoryConstructorInvoke(
|
| + NewExpression node,
|
| + ConstructorElement constructor,
|
| + InterfaceType type,
|
| + ConstructorElement effectiveTarget,
|
| + InterfaceType effectiveTargetType,
|
| + NodeList arguments,
|
| + CallStructure callStructure,
|
| + _) {
|
| + return buildConstructorInvoke(node, isConst: false);
|
| + }
|
| +
|
| + @override
|
| + IrFunction visitRedirectingGenerativeConstructorDeclaration(
|
| + FunctionExpression node,
|
| + ConstructorElement constructor,
|
| + NodeList parameters,
|
| + NodeList initializers,
|
| + _) {
|
| + return buildGenerativeConstructor(constructor, parameters, null);
|
| + }
|
| +
|
| + @override
|
| + ir.InvocationExpression visitRedirectingGenerativeConstructorInvoke(
|
| + NewExpression node,
|
| + ConstructorElement constructor,
|
| + InterfaceType type,
|
| + NodeList arguments,
|
| + CallStructure callStructure,
|
| + _) {
|
| + return buildConstructorInvoke(node, isConst: false);
|
| + }
|
| +
|
| + @override
|
| + visitStaticConstantDeclaration(VariableDefinitions node, Node definition,
|
| + FieldElement field, ConstantExpression constant, _) {
|
| + // Shouldn't be called, handled by fieldToIr.
|
| + return internalError(node, "StaticConstantDeclaration");
|
| + }
|
| +
|
| + @override
|
| + visitStaticFieldDeclaration(VariableDefinitions node, Node definition,
|
| + FieldElement field, Node initializer, _) {
|
| + // Shouldn't be called, handled by fieldToIr.
|
| + return internalError(node, "StaticFieldDeclaration");
|
| + }
|
| +
|
| + ir.Expression buildStaticGet(Element element) {
|
| + return buildStaticAccessor(element).buildSimpleRead();
|
| + }
|
| +
|
| + @override
|
| + ir.Expression handleStaticFieldGet(Send node, FieldElement field, _) {
|
| + return buildStaticGet(field);
|
| + }
|
| +
|
| + @override
|
| + ir.MethodInvocation handleStaticFieldInvoke(Send node, FieldElement field,
|
| + NodeList arguments, CallStructure callStructure, _) {
|
| + return buildCall(buildStaticGet(field), callStructure, arguments);
|
| + }
|
| +
|
| + @override
|
| + ir.Expression handleStaticFieldSet(
|
| + SendSet node, FieldElement field, Node rhs, _) {
|
| + return buildStaticFieldSet(field, rhs);
|
| + }
|
| +
|
| + @override
|
| + ir.Expression handleStaticSetIfNulls(
|
| + SendSet node,
|
| + Element getter,
|
| + CompoundGetter getterKind,
|
| + Element setter,
|
| + CompoundSetter setterKind,
|
| + Node rhs,
|
| + _) {
|
| + if (setterKind == CompoundSetter.INVALID) {
|
| + setter = null;
|
| + }
|
| + return buildStaticAccessor(getter, setter).buildNullAwareAssignment(
|
| + visitForValue(rhs),
|
| + voidContext: isVoidContext);
|
| + }
|
| +
|
| + ir.VariableDeclaration getLocal(LocalElement local) {
|
| + return locals.putIfAbsent(local, () {
|
| + return new ir.VariableDeclaration(local.name,
|
| + initializer: null,
|
| + type: typeToIrHack(local.type),
|
| + isFinal: local.isFinal,
|
| + isConst: local.isConst);
|
| + });
|
| + }
|
| +
|
| + 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;
|
| + }
|
| + });
|
| + 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 =
|
| + (bodyNode == null) ? null : buildStatementInBlock(bodyNode);
|
| + return new ir.FunctionNode(body,
|
| + asyncMarker: asyncMarker,
|
| + returnType: returnType,
|
| + typeParameters: typeParameters,
|
| + positionalParameters: positionalParameters,
|
| + namedParameters: namedParameters,
|
| + requiredParameterCount: requiredParameterCount);
|
| + }
|
| +
|
| + @override
|
| + IrFunction visitStaticFunctionDeclaration(FunctionExpression node,
|
| + MethodElement function, NodeList parameters, Node body, _) {
|
| + return buildIrFunction(ir.ProcedureKind.Method, function, body);
|
| + }
|
| +
|
| + ir.ProcedureKind computeInstanceMethodKind(MethodElement method) {
|
| + assert(method.isFunction);
|
| + return method.isOperator
|
| + ? ir.ProcedureKind.Operator
|
| + : ir.ProcedureKind.Method;
|
| + }
|
| +
|
| + @override
|
| + IrFunction visitInstanceMethodDeclaration(FunctionExpression node,
|
| + MethodElement method, NodeList parameters, Node body, _) {
|
| + return buildIrFunction(
|
| + computeInstanceMethodKind(currentElement), currentElement, body);
|
| + }
|
| +
|
| + @override
|
| + IrFunction visitAbstractMethodDeclaration(
|
| + FunctionExpression node, MethodElement method, NodeList parameters, _) {
|
| + return buildIrFunction(
|
| + computeInstanceMethodKind(currentElement), currentElement, null);
|
| + }
|
| +
|
| + @override
|
| + ir.Expression handleStaticFunctionGet(Send node, MethodElement function, _) {
|
| + return buildStaticGet(function);
|
| + }
|
| +
|
| + @override
|
| + ir.StaticInvocation handleStaticFunctionIncompatibleInvoke(
|
| + Send node,
|
| + MethodElement function,
|
| + NodeList arguments,
|
| + CallStructure callStructure,
|
| + _) {
|
| + return buildStaticInvoke(function, arguments, isConst: false);
|
| + }
|
| +
|
| + ir.StaticInvocation buildStaticInvoke(
|
| + FunctionElement function, NodeList arguments,
|
| + {bool isConst}) {
|
| + ir.Arguments argumentsNode = buildArguments(arguments);
|
| + return new ir.StaticInvocation(kernel.functionToIr(function), argumentsNode,
|
| + isConst: isConst);
|
| + }
|
| +
|
| + @override
|
| + ir.StaticInvocation handleStaticFunctionInvoke(
|
| + Send node,
|
| + MethodElement function,
|
| + NodeList arguments,
|
| + CallStructure callStructure,
|
| + _) {
|
| + return buildStaticInvoke(function, arguments, isConst: false);
|
| + }
|
| +
|
| + @override
|
| + ir.Expression handleStaticFunctionSet(
|
| + Send node, MethodElement function, Node rhs, _) {
|
| + return buildStaticAccessor(function)
|
| + .buildAssignment(visitForValue(rhs), voidContext: isVoidContext);
|
| + }
|
| +
|
| + @override
|
| + IrFunction visitStaticGetterDeclaration(
|
| + FunctionExpression node, MethodElement getter, Node body, _) {
|
| + return buildIrFunction(ir.ProcedureKind.Getter, getter, body);
|
| + }
|
| +
|
| + @override
|
| + ir.Expression handleStaticGetterGet(Send node, FunctionElement getter, _) {
|
| + if (getter.isDeferredLoaderGetter) {
|
| + // TODO(ahe): Support deferred load.
|
| + return new ir.InvalidExpression();
|
| + }
|
| + return buildStaticGet(getter);
|
| + }
|
| +
|
| + @override
|
| + ir.Expression handleStaticGetterInvoke(Send node, FunctionElement getter,
|
| + NodeList arguments, CallStructure callStructure, _) {
|
| + if (getter.isDeferredLoaderGetter) {
|
| + // TODO(ahe): Support deferred load.
|
| + return new ir.InvalidExpression();
|
| + }
|
| + return buildCall(buildStaticGet(getter), callStructure, arguments);
|
| + }
|
| +
|
| + @override
|
| + ir.Expression handleStaticGetterSet(
|
| + SendSet node, FunctionElement getter, Node rhs, _) {
|
| + return buildStaticAccessor(getter)
|
| + .buildAssignment(visitForValue(rhs), voidContext: isVoidContext);
|
| + }
|
| +
|
| + @override
|
| + IrFunction visitStaticSetterDeclaration(FunctionExpression node,
|
| + MethodElement setter, NodeList parameters, Node body, _) {
|
| + return buildIrFunction(ir.ProcedureKind.Setter, setter, body);
|
| + }
|
| +
|
| + @override
|
| + ir.Expression handleStaticSetterGet(Send node, FunctionElement setter, _) {
|
| + return buildStaticAccessor(null, setter).buildSimpleRead();
|
| + }
|
| +
|
| + @override
|
| + ir.MethodInvocation handleStaticSetterInvoke(
|
| + Send node,
|
| + FunctionElement setter,
|
| + NodeList arguments,
|
| + CallStructure callStructure,
|
| + _) {
|
| + return buildCall(buildStaticAccessor(null, setter).buildSimpleRead(),
|
| + callStructure, arguments);
|
| + }
|
| +
|
| + @override
|
| + ir.Expression handleStaticSetterSet(
|
| + SendSet node, FunctionElement setter, Node rhs, _) {
|
| + return buildStaticAccessor(null, setter)
|
| + .buildAssignment(visitForValue(rhs), voidContext: isVoidContext);
|
| + }
|
| +
|
| + @override
|
| + ir.InvocationExpression visitStringFromEnvironmentConstructorInvoke(
|
| + NewExpression node, StringFromEnvironmentConstantExpression constant, _) {
|
| + return buildConstructorInvoke(node, isConst: true);
|
| + }
|
| +
|
| + @override
|
| + ir.SuperMethodInvocation visitSuperBinary(Send node, FunctionElement function,
|
| + BinaryOperator operator, Node argument, _) {
|
| + return new ir.SuperMethodInvocation(kernel.functionToIr(function),
|
| + new ir.Arguments(<ir.Expression>[visitForValue(argument)]));
|
| + }
|
| +
|
| + @override
|
| + ir.Expression visitSuperCompoundIndexSet(
|
| + SendSet node,
|
| + MethodElement getter,
|
| + MethodElement setter,
|
| + Node index,
|
| + AssignmentOperator operator,
|
| + Node rhs,
|
| + _) {
|
| + return buildSuperIndexAccessor(index, getter, setter)
|
| + .buildCompoundAssignment(
|
| + kernel.irName(operator.selectorName, currentElement),
|
| + visitForValue(rhs),
|
| + voidContext: isVoidContext);
|
| + }
|
| +
|
| + @override
|
| + ir.Initializer visitSuperConstructorInvoke(
|
| + Send node,
|
| + ConstructorElement superConstructor,
|
| + InterfaceType type,
|
| + NodeList arguments,
|
| + CallStructure callStructure,
|
| + _) {
|
| + if (kernel.isSyntheticError(superConstructor)) {
|
| + // TODO(ahe): Semantic visitor shouldn't call in this case.
|
| + return new ir.InvalidInitializer();
|
| + }
|
| + return new ir.SuperInitializer(
|
| + kernel.functionToIr(superConstructor), buildArguments(arguments));
|
| + }
|
| +
|
| + ir.SuperMethodInvocation buildSuperEquals(
|
| + FunctionElement function, Node argument) {
|
| + return new ir.SuperMethodInvocation(
|
| + kernel.functionToIr(function),
|
| + new ir.Arguments(<ir.Expression>[visitForValue(argument)],
|
| + types: null, named: null));
|
| + }
|
| +
|
| + @override
|
| + ir.SuperMethodInvocation visitSuperEquals(
|
| + Send node, FunctionElement function, Node argument, _) {
|
| + return buildSuperEquals(function, argument);
|
| + }
|
| +
|
| + @override
|
| + ir.Expression handleSuperCompounds(
|
| + SendSet node,
|
| + Element getter,
|
| + CompoundGetter getterKind,
|
| + Element setter,
|
| + CompoundSetter setterKind,
|
| + CompoundRhs rhs,
|
| + _) {
|
| + if (setterKind == CompoundSetter.INVALID) {
|
| + setter = null;
|
| + }
|
| + return buildCompound(buildSuperPropertyAccessor(getter, setter), rhs);
|
| + }
|
| +
|
| + @override
|
| + ir.Expression handleStaticCompounds(
|
| + SendSet node,
|
| + Element getter,
|
| + CompoundGetter getterKind,
|
| + Element setter,
|
| + CompoundSetter setterKind,
|
| + CompoundRhs rhs,
|
| + _) {
|
| + if (setterKind == CompoundSetter.INVALID) {
|
| + setter = null;
|
| + }
|
| + return buildCompound(buildStaticAccessor(getter, setter), rhs);
|
| + }
|
| +
|
| + @override
|
| + ir.Expression handleTypeLiteralConstantCompounds(
|
| + SendSet node, ConstantExpression constant, CompoundRhs rhs, _) {
|
| + return buildCompound(new ReadOnlyAccessor(buildTypeLiteral(constant)), rhs);
|
| + }
|
| +
|
| + ir.TypeLiteral buildTypeVariable(TypeVariableElement element) {
|
| + return new ir.TypeLiteral(kernel.typeToIr(element.type));
|
| + }
|
| +
|
| + @override
|
| + ir.Expression handleTypeVariableTypeLiteralCompounds(
|
| + SendSet node, TypeVariableElement element, CompoundRhs rhs, _) {
|
| + return buildCompound(new ReadOnlyAccessor(buildTypeVariable(element)), rhs);
|
| + }
|
| +
|
| + @override
|
| + ir.SuperPropertyGet visitSuperFieldGet(Send node, FieldElement field, _) {
|
| + return buildSuperPropertyAccessor(field).buildSimpleRead();
|
| + }
|
| +
|
| + @override
|
| + ir.MethodInvocation visitSuperFieldInvoke(Send node, FieldElement field,
|
| + NodeList arguments, CallStructure callStructure, _) {
|
| + return buildCall(buildSuperPropertyAccessor(field).buildSimpleRead(),
|
| + callStructure, arguments);
|
| + }
|
| +
|
| + @override
|
| + ir.Expression visitSuperFieldSet(
|
| + SendSet node, FieldElement field, Node rhs, _) {
|
| + return buildSuperPropertyAccessor(field)
|
| + .buildAssignment(visitForValue(rhs), voidContext: isVoidContext);
|
| + }
|
| +
|
| + Accessor buildSuperPropertyAccessor(Element getter, [Element setter]) {
|
| + if (setter == null &&
|
| + getter.isField &&
|
| + !getter.isFinal &&
|
| + !getter.isConst) {
|
| + setter = getter;
|
| + }
|
| + return new SuperPropertyAccessor(
|
| + (getter == null) ? null : kernel.elementToIr(getter),
|
| + (setter == null) ? null : kernel.elementToIr(setter));
|
| + }
|
| +
|
| + Accessor buildSuperIndexAccessor(Expression index, Element getter,
|
| + [Element setter]) {
|
| + if (setter == null &&
|
| + getter.isField &&
|
| + !getter.isFinal &&
|
| + !getter.isConst) {
|
| + setter = getter;
|
| + }
|
| + return new SuperIndexAccessor(
|
| + visitForValue(index),
|
| + (getter == null) ? null : kernel.elementToIr(getter),
|
| + (setter == null) ? null : kernel.elementToIr(setter));
|
| + }
|
| +
|
| + @override
|
| + ir.SuperPropertyGet visitSuperGetterGet(
|
| + Send node, FunctionElement getter, _) {
|
| + return buildSuperPropertyAccessor(getter).buildSimpleRead();
|
| + }
|
| +
|
| + @override
|
| + ir.MethodInvocation visitSuperGetterInvoke(Send node, FunctionElement getter,
|
| + NodeList arguments, CallStructure callStructure, _) {
|
| + return buildCall(buildSuperPropertyAccessor(getter).buildSimpleRead(),
|
| + callStructure, arguments);
|
| + }
|
| +
|
| + @override
|
| + ir.Expression visitSuperGetterSet(
|
| + SendSet node, FunctionElement getter, Node rhs, _) {
|
| + return buildSuperPropertyAccessor(getter)
|
| + .buildAssignment(visitForValue(rhs), voidContext: isVoidContext);
|
| + }
|
| +
|
| + @override
|
| + ir.Expression handleSuperSetIfNulls(
|
| + SendSet node,
|
| + Element getter,
|
| + CompoundGetter getterKind,
|
| + Element setter,
|
| + CompoundSetter setterKind,
|
| + Node rhs,
|
| + _) {
|
| + if (setterKind == CompoundSetter.INVALID) {
|
| + setter = null;
|
| + }
|
| + return buildSuperPropertyAccessor(getter, setter).buildNullAwareAssignment(
|
| + visitForValue(rhs),
|
| + voidContext: isVoidContext);
|
| + }
|
| +
|
| + @override
|
| + ir.SuperMethodInvocation visitSuperIndex(
|
| + Send node, FunctionElement function, Node index, _) {
|
| + return buildSuperIndexAccessor(index, function).buildSimpleRead();
|
| + }
|
| +
|
| + @override
|
| + ir.Expression visitSuperIndexPostfix(Send node, MethodElement indexFunction,
|
| + MethodElement indexSetFunction, Node index, IncDecOperator operator, _) {
|
| + Accessor accessor =
|
| + buildSuperIndexAccessor(index, indexFunction, indexSetFunction);
|
| + return buildIndexPostfix(accessor, operator);
|
| + }
|
| +
|
| + @override
|
| + ir.Expression visitSuperIndexPrefix(Send node, MethodElement indexFunction,
|
| + MethodElement indexSetFunction, Node index, IncDecOperator operator, _) {
|
| + Accessor accessor =
|
| + buildSuperIndexAccessor(index, indexFunction, indexSetFunction);
|
| + return buildIndexPrefix(accessor, operator);
|
| + }
|
| +
|
| + @override
|
| + ir.Expression visitSuperIndexSet(
|
| + SendSet node, FunctionElement function, Node index, Node rhs, _) {
|
| + return buildSuperIndexAccessor(index, null, function)
|
| + .buildAssignment(visitForValue(rhs), voidContext: isVoidContext);
|
| + }
|
| +
|
| + @override
|
| + ir.Expression visitSuperMethodGet(Send node, MethodElement method, _) {
|
| + return buildSuperPropertyAccessor(method).buildSimpleRead();
|
| + }
|
| +
|
| + ir.SuperMethodInvocation buildSuperMethodInvoke(
|
| + MethodElement method, NodeList arguments) {
|
| + return new ir.SuperMethodInvocation(
|
| + kernel.functionToIr(method), buildArguments(arguments));
|
| + }
|
| +
|
| + @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 buildSuperMethodInvoke(method, arguments);
|
| + }
|
| +
|
| + @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, _) {
|
| + return new ir.SuperMethodInvocation(
|
| + kernel.functionToIr(function), new ir.Arguments.empty());
|
| + }
|
| +
|
| + @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));
|
| + }
|
| +
|
| + @override
|
| + ir.Expression visitThisPropertyGet(Send node, Name name, _) {
|
| + return buildThisPropertyAccessor(name).buildSimpleRead();
|
| + }
|
| +
|
| + @override
|
| + ir.MethodInvocation visitThisPropertyInvoke(
|
| + Send node, NodeList arguments, Selector selector, _) {
|
| + return buildInvokeSelector(
|
| + new ir.ThisExpression(), selector, buildArguments(arguments));
|
| + }
|
| +
|
| + @override
|
| + ir.Expression visitThisPropertySet(SendSet node, Name name, Node rhs, _) {
|
| + return buildThisPropertyAccessor(name)
|
| + .buildAssignment(visitForValue(rhs), voidContext: isVoidContext);
|
| + }
|
| +
|
| + @override
|
| + ir.Expression visitTopLevelConstantDeclaration(VariableDefinitions node,
|
| + Node definition, FieldElement field, ConstantExpression constant, _) {
|
| + // Shouldn't be called, handled by fieldToIr.
|
| + return internalError(node, "TopLevelFieldDeclaration");
|
| + }
|
| +
|
| + @override
|
| + ir.Expression visitTopLevelFieldDeclaration(VariableDefinitions node,
|
| + Node definition, FieldElement field, Node initializer, _) {
|
| + // Shouldn't be called, handled by fieldToIr.
|
| + return internalError(node, "TopLevelFieldDeclaration");
|
| + }
|
| +
|
| + @override
|
| + IrFunction visitTopLevelFunctionDeclaration(FunctionExpression node,
|
| + MethodElement function, NodeList parameters, Node body, _) {
|
| + return buildIrFunction(ir.ProcedureKind.Method, function, body);
|
| + }
|
| +
|
| + ir.Arguments buildArguments(NodeList arguments) {
|
| + List<ir.Expression> positional = <ir.Expression>[];
|
| + List<ir.NamedExpression> named = <ir.NamedExpression>[];
|
| + for (Expression expression in arguments.nodes) {
|
| + ir.TreeNode argument = visitForValue(expression);
|
| + if (argument is ir.NamedExpression) {
|
| + named.add(argument);
|
| + } else {
|
| + positional.add(argument);
|
| + }
|
| + }
|
| + return new ir.Arguments(positional, named: named, types: null);
|
| + }
|
| +
|
| + @override
|
| + IrFunction visitTopLevelGetterDeclaration(
|
| + FunctionExpression node, MethodElement getter, Node body, _) {
|
| + return buildIrFunction(ir.ProcedureKind.Getter, getter, body);
|
| + }
|
| +
|
| + @override
|
| + IrFunction visitTopLevelSetterDeclaration(FunctionExpression node,
|
| + MethodElement setter, NodeList parameters, Node body, _) {
|
| + return buildIrFunction(ir.ProcedureKind.Setter, setter, body);
|
| + }
|
| +
|
| + @override
|
| + ir.TypeLiteral visitTypeVariableTypeLiteralGet(
|
| + Send node, TypeVariableElement element, _) {
|
| + return buildTypeVariable(element);
|
| + }
|
| +
|
| + @override
|
| + ir.MethodInvocation visitTypeVariableTypeLiteralInvoke(
|
| + Send node,
|
| + TypeVariableElement element,
|
| + NodeList arguments,
|
| + CallStructure callStructure,
|
| + _) {
|
| + return buildCall(buildTypeVariable(element), callStructure, arguments);
|
| + }
|
| +
|
| + @override
|
| + ir.Expression visitTypeVariableTypeLiteralSet(
|
| + SendSet node, TypeVariableElement element, Node rhs, _) {
|
| + return new ReadOnlyAccessor(buildTypeVariable(element))
|
| + .buildAssignment(visitForValue(rhs), voidContext: isVoidContext);
|
| + }
|
| +
|
| + @override
|
| + ir.Expression visitTypeVariableTypeLiteralSetIfNull(
|
| + Send node, TypeVariableElement element, Node rhs, _) {
|
| + return new ReadOnlyAccessor(buildTypeVariable(element))
|
| + .buildNullAwareAssignment(visitForValue(rhs),
|
| + voidContext: isVoidContext);
|
| + }
|
| +
|
| + @override
|
| + ir.TypeLiteral visitTypedefTypeLiteralGet(
|
| + Send node, ConstantExpression constant, _) {
|
| + return buildTypeLiteral(constant);
|
| + }
|
| +
|
| + @override
|
| + ir.MethodInvocation visitTypedefTypeLiteralInvoke(
|
| + Send node,
|
| + ConstantExpression constant,
|
| + NodeList arguments,
|
| + CallStructure callStructure,
|
| + _) {
|
| + return buildCall(buildTypeLiteral(constant), callStructure, arguments);
|
| + }
|
| +
|
| + @override
|
| + ir.Expression visitTypedefTypeLiteralSet(
|
| + SendSet node, ConstantExpression constant, Node rhs, _) {
|
| + return buildTypeLiteralSet(constant, rhs);
|
| + }
|
| +
|
| + @override
|
| + ir.Expression handleTypeLiteralConstantSetIfNulls(
|
| + SendSet node, ConstantExpression constant, Node rhs, _) {
|
| + // Degenerate case: ignores [rhs] as a type literal is never null.
|
| + return buildTypeLiteral(constant);
|
| + }
|
| +
|
| + @override
|
| + ir.MethodInvocation visitUnary(
|
| + Send node, UnaryOperator operator, Node expression, _) {
|
| + return new ir.MethodInvocation(
|
| + visitForValue(expression),
|
| + kernel.irName(operator.selectorName, currentElement),
|
| + new ir.Arguments.empty());
|
| + }
|
| +
|
| + @override
|
| + visitConditionalUri(ConditionalUri node) {
|
| + // Shouldn't be called, handled by library loader.
|
| + return internalError(node, "ConditionalUri");
|
| + }
|
| +
|
| + @override
|
| + visitDottedName(DottedName node) {
|
| + // Shouldn't be called, handled by library loader.
|
| + return internalError(node, "DottedName");
|
| + }
|
| +
|
| + @override
|
| + visitForIn(ForIn node) {
|
| + // Shouldn't be called, handled by [visitAsyncForIn] or [visitSyncForIn].
|
| + return internalError(node, "ForIn");
|
| + }
|
| +
|
| + @override
|
| + ir.Expression visitIndexSetIfNull(
|
| + SendSet node, Node receiver, Node index, Node rhs, _) {
|
| + return buildIndexAccessor(receiver, index).buildNullAwareAssignment(
|
| + visitForValue(rhs),
|
| + voidContext: isVoidContext);
|
| + }
|
| +
|
| + @override
|
| + ir.Expression visitSuperIndexSetIfNull(SendSet node, MethodElement getter,
|
| + MethodElement setter, Node index, Node rhs, _) {
|
| + return buildSuperIndexAccessor(index, getter, setter)
|
| + .buildNullAwareAssignment(visitForValue(rhs),
|
| + voidContext: isVoidContext);
|
| + }
|
| +
|
| + @override
|
| + ir.Node visitVariableDefinitions(VariableDefinitions definitions) {
|
| + // TODO(ahe): This method is copied from [SemanticDeclarationResolvedMixin]
|
| + // and modified. Perhaps we can find a way to avoid code duplication.
|
| + List<ir.VariableDeclaration> variables = <ir.VariableDeclaration>[];
|
| + computeVariableStructures(definitions,
|
| + (Node node, VariableStructure structure) {
|
| + if (structure == null) {
|
| + return internalError(node, 'No structure for $node');
|
| + } else {
|
| + ir.VariableDeclaration variable =
|
| + structure.dispatch(declVisitor, node, null);
|
| + variables.add(variable);
|
| + return variable;
|
| + }
|
| + });
|
| + if (variables.length == 1) return variables.single;
|
| + return new VariableDeclarations(variables);
|
| + }
|
| +
|
| + IrFunction buildFunction() {
|
| + return kernel.compiler.reporter.withCurrentElement(currentElement, () {
|
| + if (kernel.isSyntheticError(currentElement)) {
|
| + kernel.internalError(currentElement,
|
| + "Can't build synthetic function element: $currentElement");
|
| + } else if (currentElement.isMalformed) {
|
| + ir.FunctionNode node = buildFunctionNode(currentElement, null);
|
| + if (currentElement.isGenerativeConstructor) {
|
| + return new IrFunction.constructor(
|
| + node, <ir.Initializer>[new ir.InvalidInitializer()]);
|
| + } else {
|
| + node.body = new ir.InvalidStatement()..parent = node;
|
| + return new IrFunction.procedure(ir.ProcedureKind.Method, node);
|
| + }
|
| + } else if (currentElement.isSynthesized) {
|
| + if (currentElement.isGenerativeConstructor) {
|
| + return buildGenerativeConstructor(currentElement, null, null);
|
| + } else {
|
| + return internalError(currentElement, "Unhandled synthetic function.");
|
| + }
|
| + } else {
|
| + Node node = currentElement.node;
|
| + if (node.isErroneous) {
|
| + return internalError(currentElement, "Unexpected syntax error.");
|
| + } else {
|
| + return node.accept(this);
|
| + }
|
| + }
|
| + });
|
| + }
|
| +
|
| + ir.Expression buildInitializer() {
|
| + return kernel.compiler.reporter.withCurrentElement(currentElement, () {
|
| + FieldElement field = currentElement;
|
| + return field.isMalformed
|
| + ? new ir.InvalidExpression()
|
| + : visitForValue(field.initializer);
|
| + });
|
| + }
|
| +}
|
| +
|
| +class VariableDeclarations implements ir.Node {
|
| + final List<ir.VariableDeclaration> variables;
|
| +
|
| + VariableDeclarations(this.variables);
|
| +
|
| + accept(ir.Visitor v) => throw "unsupported";
|
| +
|
| + visitChildren(ir.Visitor v) => throw "unsupported";
|
| +
|
| + String toString() => "VariableDeclarations($variables)";
|
| +}
|
| +
|
| +class IrFunction implements ir.Node {
|
| + final ir.ProcedureKind kind;
|
| + final bool isConstructor;
|
| + final ir.FunctionNode node;
|
| + final List<ir.Initializer> initializers;
|
| +
|
| + IrFunction(this.kind, this.isConstructor, this.node, this.initializers);
|
| +
|
| + IrFunction.procedure(ir.ProcedureKind kind, ir.FunctionNode node)
|
| + : this(kind, false, node, null);
|
| +
|
| + IrFunction.constructor(
|
| + ir.FunctionNode node, List<ir.Initializer> initializers)
|
| + : this(null, true, node, initializers);
|
| +
|
| + accept(ir.Visitor v) => throw "unsupported";
|
| +
|
| + visitChildren(ir.Visitor v) => throw "unsupported";
|
| +
|
| + String toString() {
|
| + return "IrFunction($kind, $isConstructor, $node, $initializers)";
|
| + }
|
| +}
|
|
|