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)"; |
+ } |
+} |