// Copyright (c) 2013, 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 file.

library simple_types_inferrer;

import '../closure.dart' show ClosureRepresentationInfo;
import '../common.dart';
import '../common/names.dart' show Identifiers, Selectors;
import '../compiler.dart' show Compiler;
import '../constants/constant_system.dart';
import '../constants/expressions.dart';
import '../constants/values.dart' show ConstantValue, IntConstantValue;
import '../elements/elements.dart';
import '../elements/entities.dart';
import '../elements/jumps.dart';
import '../elements/names.dart';
import '../elements/operators.dart' as op;
import '../elements/resolution_types.dart'
    show ResolutionDartType, ResolutionInterfaceType;
import '../js_backend/backend.dart' show JavaScriptBackend;
import '../native/native.dart' as native;
import '../resolution/semantic_visitor.dart';
import '../resolution/tree_elements.dart' show TreeElements;
import '../tree/tree.dart' as ast;
import '../types/constants.dart' show computeTypeMask;
import '../types/types.dart' show TypeMask, GlobalTypeInferenceElementData;
import '../universe/call_structure.dart' show CallStructure;
import '../universe/selector.dart' show Selector;
import '../universe/side_effects.dart' show SideEffects;
import '../util/util.dart' show Link, Setlet;
import '../world.dart' show ClosedWorld;
import 'inferrer_engine.dart';
import 'locals_handler.dart';
import 'type_graph_nodes.dart';
import 'type_system.dart';

/// [ElementGraphBuilder] can be thought of as a type-inference graph
/// builder for a single element.
///
/// Calling [run] will start the work of visiting the body of the code to
/// construct a set of infernece-nodes that abstractly represent what the code
/// is doing.
///
/// This visitor is parameterized by an [InferenceEngine], which internally
/// decides how to represent inference nodes.
class ElementGraphBuilder extends ast.Visitor<TypeInformation>
    with
        SemanticSendResolvedMixin<TypeInformation, dynamic>,
        CompoundBulkMixin<TypeInformation, dynamic>,
        SetIfNullBulkMixin<TypeInformation, dynamic>,
        PrefixBulkMixin<TypeInformation, dynamic>,
        PostfixBulkMixin<TypeInformation, dynamic>,
        ErrorBulkMixin<TypeInformation, dynamic>,
        NewBulkMixin<TypeInformation, dynamic>,
        SetBulkMixin<TypeInformation, dynamic>
    implements SemanticSendVisitor<TypeInformation, dynamic> {
  final Compiler compiler;
  final MemberElement analyzedElement;
  final ResolvedAst resolvedAst;
  final TypeSystem<ast.Node> types;
  final Map<JumpTarget, List<LocalsHandler>> breaksFor =
      new Map<JumpTarget, List<LocalsHandler>>();
  final Map<JumpTarget, List<LocalsHandler>> continuesFor =
      new Map<JumpTarget, List<LocalsHandler>>();
  LocalsHandler<ast.Node> locals;
  final List<TypeInformation> cascadeReceiverStack =
      new List<TypeInformation>();

  TypeInformation returnType;
  bool visitingInitializers = false;
  bool isConstructorRedirect = false;
  bool seenSuperConstructorCall = false;
  SideEffects sideEffects = new SideEffects.empty();
  final MemberElement outermostElement;
  final InferrerEngine inferrer;
  final Setlet<Entity> capturedVariables = new Setlet<Entity>();
  final GlobalTypeInferenceElementData memberData;

  ElementGraphBuilder.internal(
      MemberElement analyzedElement,
      this.resolvedAst,
      this.outermostElement,
      InferrerEngine inferrer,
      this.compiler,
      this.locals)
      : this.analyzedElement = analyzedElement,
        this.inferrer = inferrer,
        this.types = inferrer.types,
        this.memberData = inferrer.dataOfMember(analyzedElement.memberContext) {
    assert(analyzedElement.isDeclaration);
    assert(outermostElement != null);
    assert(outermostElement.isDeclaration);
    if (locals != null) return;
    ast.Node node;
    if (resolvedAst.kind == ResolvedAstKind.PARSED) {
      node = resolvedAst.node;
    }
    FieldInitializationScope<ast.Node> fieldScope =
        analyzedElement.isGenerativeConstructor
            ? new FieldInitializationScope<ast.Node>(types)
            : null;
    locals = new LocalsHandler<ast.Node>(
        inferrer, types, compiler.options, node, fieldScope);
  }

  ElementGraphBuilder(
      MemberElement element, Compiler compiler, InferrerEngine inferrer,
      [LocalsHandler handler])
      : this.internal(element, element.resolvedAst,
            element.memberContext.declaration, inferrer, compiler, handler);

  TreeElements get elements => resolvedAst.elements;

  bool accumulateIsChecks = false;
  bool conditionIsSimple = false;
  List<ast.Send> isChecks;
  int loopLevel = 0;

  bool get inLoop => loopLevel > 0;
  bool get isThisExposed {
    return analyzedElement.isGenerativeConstructor
        ? locals.fieldScope.isThisExposed
        : true;
  }

  void set isThisExposed(value) {
    if (analyzedElement.isGenerativeConstructor) {
      locals.fieldScope.isThisExposed = value;
    }
  }

  void initializationIsIndefinite() {
    if (analyzedElement.isGenerativeConstructor) {
      locals.fieldScope.isIndefinite = true;
    }
  }

  DiagnosticReporter get reporter => compiler.reporter;

  ClosedWorld get closedWorld => inferrer.closedWorld;

  @override
  SemanticSendVisitor<TypeInformation, dynamic> get sendVisitor => this;

  @override
  TypeInformation apply(ast.Node node, _) => visit(node);

  TypeInformation visitAssert(ast.Assert node) {
    // Avoid pollution from assert statement unless enabled.
    if (!compiler.options.enableUserAssertions) {
      return null;
    }
    List<ast.Send> tests = <ast.Send>[];
    bool simpleCondition = handleCondition(node.condition, tests);
    LocalsHandler saved = locals;
    locals = new LocalsHandler.from(locals, node);
    updateIsChecks(tests, usePositive: true);

    LocalsHandler thenLocals = locals;
    locals = new LocalsHandler.from(saved, node);
    if (simpleCondition) updateIsChecks(tests, usePositive: false);
    visit(node.message);
    locals.seenReturnOrThrow = true;
    saved.mergeDiamondFlow(thenLocals, locals);
    locals = saved;
    return null;
  }

  @override
  TypeInformation bulkHandleSet(ast.SendSet node, _) {
    return handleSendSet(node);
  }

  @override
  TypeInformation bulkHandleCompound(ast.SendSet node, _) {
    return handleSendSet(node);
  }

  @override
  TypeInformation bulkHandleSetIfNull(ast.SendSet node, _) {
    return handleSendSet(node);
  }

  @override
  TypeInformation bulkHandlePrefix(ast.SendSet node, _) {
    return handleSendSet(node);
  }

  @override
  TypeInformation bulkHandlePostfix(ast.SendSet node, _) {
    return handleSendSet(node);
  }

  @override
  TypeInformation bulkHandleError(ast.Node node, ErroneousElement error, _) {
    return types.dynamicType;
  }

  TypeInformation visitNode(ast.Node node) {
    return node.visitChildren(this);
  }

  TypeInformation visit(ast.Node node) {
    return node == null ? null : node.accept(this);
  }

  TypeInformation visitLiteralString(ast.LiteralString node) {
    return types.stringLiteralType(node.dartString.slowToString());
  }

  TypeInformation visitStringJuxtaposition(ast.StringJuxtaposition node) {
    node.visitChildren(this);
    return types.stringType;
  }

  TypeInformation visitLiteralBool(ast.LiteralBool node) {
    return types.boolLiteralType(node.value);
  }

  TypeInformation visitLiteralDouble(ast.LiteralDouble node) {
    ConstantSystem constantSystem = closedWorld.constantSystem;
    // The JavaScript backend may turn this literal into an integer at
    // runtime.
    return types.getConcreteTypeFor(
        computeTypeMask(closedWorld, constantSystem.createDouble(node.value)));
  }

  TypeInformation visitLiteralInt(ast.LiteralInt node) {
    ConstantSystem constantSystem = closedWorld.constantSystem;
    // The JavaScript backend may turn this literal into a double at
    // runtime.
    return types.getConcreteTypeFor(
        computeTypeMask(closedWorld, constantSystem.createInt(node.value)));
  }

  TypeInformation visitLiteralNull(ast.LiteralNull node) {
    return types.nullType;
  }

  TypeInformation visitLiteralSymbol(ast.LiteralSymbol node) {
    // TODO(kasperl): We should be able to tell that the type of a literal
    // symbol is always a non-null exact symbol implementation -- not just
    // any non-null subtype of the symbol interface.
    return types
        .nonNullSubtype(closedWorld.commonElements.symbolImplementationClass);
  }

  @override
  void previsitDeferredAccess(ast.Send node, PrefixElement prefix, _) {
    // Deferred access does not affect inference.
  }

  TypeInformation handleTypeLiteralGet() {
    return types.typeType;
  }

  @override
  TypeInformation bulkHandleNode(ast.Node node, String message, _) {
    return internalError(node, message.replaceAll('#', '$node'));
  }

  @override
  TypeInformation visitConstantGet(
      ast.Send node, ConstantExpression constant, _) {
    return bulkHandleNode(node, "Constant read `#` unhandled.", _);
  }

  @override
  TypeInformation visitConstantInvoke(
      ast.Send node,
      ConstantExpression constant,
      ast.NodeList arguments,
      CallStructure callStructure,
      _) {
    return bulkHandleNode(node, "Constant invoke `#` unhandled.", _);
  }

  TypeInformation visitClassTypeLiteralGet(
      ast.Send node, ConstantExpression constant, _) {
    return handleTypeLiteralGet();
  }

  TypeInformation visitClassTypeLiteralInvoke(
      ast.Send node,
      ConstantExpression constant,
      ast.NodeList arguments,
      CallStructure callStructure,
      _) {
    return handleTypeLiteralInvoke(arguments);
  }

  TypeInformation visitTypedefTypeLiteralGet(
      ast.Send node, ConstantExpression constant, _) {
    return handleTypeLiteralGet();
  }

  TypeInformation visitTypedefTypeLiteralInvoke(
      ast.Send node,
      ConstantExpression constant,
      ast.NodeList arguments,
      CallStructure callStructure,
      _) {
    return handleTypeLiteralInvoke(arguments);
  }

  TypeInformation visitTypeVariableTypeLiteralGet(
      ast.Send node, TypeVariableElement element, _) {
    return handleTypeLiteralGet();
  }

  TypeInformation visitTypeVariableTypeLiteralInvoke(
      ast.Send node,
      TypeVariableElement element,
      ast.NodeList arguments,
      CallStructure callStructure,
      _) {
    return handleTypeLiteralInvoke(arguments);
  }

  TypeInformation visitDynamicTypeLiteralGet(
      ast.Send node, ConstantExpression constant, _) {
    return handleTypeLiteralGet();
  }

  TypeInformation visitDynamicTypeLiteralInvoke(
      ast.Send node,
      ConstantExpression constant,
      ast.NodeList arguments,
      CallStructure callStructure,
      _) {
    return handleTypeLiteralInvoke(arguments);
  }

  TypeInformation _thisType;
  TypeInformation get thisType {
    if (_thisType != null) return _thisType;
    ClassElement cls = outermostElement.enclosingClass;
    if (closedWorld.isUsedAsMixin(cls)) {
      return _thisType = types.nonNullSubtype(cls);
    } else {
      return _thisType = types.nonNullSubclass(cls);
    }
  }

  @override
  TypeInformation visitThisGet(ast.Identifier node, _) {
    return thisType;
  }

  TypeInformation visitIdentifier(ast.Identifier node) {
    if (node.isThis()) {
      return thisType;
    } else if (node.isSuper()) {
      return internalError(node, 'Unexpected expression $node.');
    } else {
      Element element = elements[node];
      if (Elements.isLocal(element)) {
        LocalElement local = element;
        return locals.use(local);
      }
      return null;
    }
  }

  void potentiallyAddIsCheck(ast.Send node) {
    if (!accumulateIsChecks) return;
    if (!Elements.isLocal(elements[node.receiver])) return;
    isChecks.add(node);
  }

  void potentiallyAddNullCheck(ast.Send node, ast.Node receiver) {
    if (!accumulateIsChecks) return;
    if (!Elements.isLocal(elements[receiver])) return;
    isChecks.add(node);
  }

  void updateIsChecks(List<ast.Node> tests, {bool usePositive}) {
    if (tests == null) return;
    for (ast.Send node in tests) {
      if (node.isTypeTest) {
        if (node.isIsNotCheck) {
          if (usePositive) continue;
        } else {
          if (!usePositive) continue;
        }
        ResolutionDartType type =
            elements.getType(node.typeAnnotationFromIsCheckOrCast);
        Element element = elements[node.receiver];
        if (Elements.isLocal(element)) {
          LocalElement local = element;
          locals.narrow(local, type, node);
        }
      } else {
        Element receiverElement = elements[node.receiver];
        Element argumentElement = elements[node.arguments.first];
        String operator = node.selector.asOperator().source;
        if ((operator == '==' && usePositive) ||
            (operator == '!=' && !usePositive)) {
          // Type the elements as null.
          if (Elements.isLocal(receiverElement)) {
            LocalElement local = receiverElement;
            locals.update(local, types.nullType, node, local.type);
          }
          if (Elements.isLocal(argumentElement)) {
            LocalElement local = argumentElement;
            locals.update(local, types.nullType, node, local.type);
          }
        } else {
          // Narrow the elements to a non-null type.
          ResolutionInterfaceType objectType =
              closedWorld.commonElements.objectType;
          if (Elements.isLocal(receiverElement)) {
            LocalElement local = receiverElement;
            locals.narrow(local, objectType, node);
          }
          if (Elements.isLocal(argumentElement)) {
            LocalElement local = argumentElement;
            locals.narrow(local, objectType, node);
          }
        }
      }
    }
  }

  @override
  TypeInformation visitIndex(
      ast.Send node, ast.Node receiver, ast.Node index, _) {
    return handleDynamicInvoke(node);
  }

  @override
  TypeInformation visitDynamicPropertyInvoke(ast.Send node, ast.Node receiver,
      ast.NodeList arguments, Selector selector, _) {
    return handleDynamicInvoke(node);
  }

  @override
  TypeInformation visitIfNotNullDynamicPropertyInvoke(ast.Send node,
      ast.Node receiver, ast.NodeList arguments, Selector selector, _) {
    return handleDynamicInvoke(node);
  }

  @override
  TypeInformation visitThisPropertyInvoke(
      ast.Send node, ast.NodeList arguments, Selector selector, _) {
    return handleDynamicInvoke(node);
  }

  @override
  TypeInformation visitIfNull(ast.Send node, ast.Node left, ast.Node right, _) {
    TypeInformation firstType = visit(left);
    TypeInformation secondType = visit(right);
    return types.allocateDiamondPhi(types.narrowNotNull(firstType), secondType);
  }

  @override
  TypeInformation visitLogicalAnd(
      ast.Send node, ast.Node left, ast.Node right, _) {
    conditionIsSimple = false;
    bool oldAccumulateIsChecks = accumulateIsChecks;
    List<ast.Send> oldIsChecks = isChecks;
    if (!accumulateIsChecks) {
      accumulateIsChecks = true;
      isChecks = <ast.Send>[];
    }
    visit(left);
    LocalsHandler saved = locals;
    locals = new LocalsHandler.from(locals, node);
    updateIsChecks(isChecks, usePositive: true);
    LocalsHandler narrowed;
    if (oldAccumulateIsChecks) {
      narrowed = new LocalsHandler.topLevelCopyOf(locals);
    } else {
      accumulateIsChecks = false;
      isChecks = oldIsChecks;
    }
    visit(right);
    if (oldAccumulateIsChecks) {
      bool invalidatedInRightHandSide(ast.Send test) {
        Element receiver = elements[test.receiver];
        if (receiver is LocalElement) {
          return narrowed.locals[receiver] != locals.locals[receiver];
        }
        return false;
      }

      isChecks.removeWhere(invalidatedInRightHandSide);
    }
    saved.mergeDiamondFlow(locals, null);
    locals = saved;
    return types.boolType;
  }

  @override
  TypeInformation visitLogicalOr(
      ast.Send node, ast.Node left, ast.Node right, _) {
    conditionIsSimple = false;
    List<ast.Send> tests = <ast.Send>[];
    bool isSimple = handleCondition(left, tests);
    LocalsHandler saved = locals;
    locals = new LocalsHandler.from(locals, node);
    if (isSimple) updateIsChecks(tests, usePositive: false);
    bool oldAccumulateIsChecks = accumulateIsChecks;
    accumulateIsChecks = false;
    visit(right);
    accumulateIsChecks = oldAccumulateIsChecks;
    saved.mergeDiamondFlow(locals, null);
    locals = saved;
    return types.boolType;
  }

  @override
  TypeInformation visitNot(ast.Send node, ast.Node expression, _) {
    bool oldAccumulateIsChecks = accumulateIsChecks;
    accumulateIsChecks = false;
    visit(expression);
    accumulateIsChecks = oldAccumulateIsChecks;
    return types.boolType;
  }

  @override
  TypeInformation visitIs(
      ast.Send node, ast.Node expression, ResolutionDartType type, _) {
    potentiallyAddIsCheck(node);
    visit(expression);
    return types.boolType;
  }

  @override
  TypeInformation visitIsNot(
      ast.Send node, ast.Node expression, ResolutionDartType type, _) {
    potentiallyAddIsCheck(node);
    visit(expression);
    return types.boolType;
  }

  @override
  TypeInformation visitAs(
      ast.Send node, ast.Node expression, ResolutionDartType type, _) {
    TypeInformation receiverType = visit(expression);
    return types.narrowType(receiverType, type);
  }

  @override
  TypeInformation visitUnary(
      ast.Send node, op.UnaryOperator operator, ast.Node expression, _) {
    return handleDynamicInvoke(node);
  }

  @override
  TypeInformation visitNotEquals(
      ast.Send node, ast.Node left, ast.Node right, _) {
    handleDynamicInvoke(node);
    return types.boolType;
  }

  @override
  TypeInformation visitEquals(ast.Send node, ast.Node left, ast.Node right, _) {
    return handleDynamicInvoke(node);
  }

  @override
  TypeInformation visitBinary(ast.Send node, ast.Node left,
      op.BinaryOperator operator, ast.Node right, _) {
    return handleDynamicInvoke(node);
  }

  // Because some nodes just visit their children, we may end up
  // visiting a type annotation, that may contain a send in case of a
  // prefixed type. Therefore we explicitly visit the type annotation
  // to avoid confusing the [ResolvedVisitor].
  visitTypeAnnotation(ast.TypeAnnotation node) {}

  TypeInformation visitConditional(ast.Conditional node) {
    List<ast.Send> tests = <ast.Send>[];
    bool simpleCondition = handleCondition(node.condition, tests);
    LocalsHandler saved = locals;
    locals = new LocalsHandler.from(locals, node);
    updateIsChecks(tests, usePositive: true);
    TypeInformation firstType = visit(node.thenExpression);
    LocalsHandler thenLocals = locals;
    locals = new LocalsHandler.from(saved, node);
    if (simpleCondition) updateIsChecks(tests, usePositive: false);
    TypeInformation secondType = visit(node.elseExpression);
    saved.mergeDiamondFlow(thenLocals, locals);
    locals = saved;
    TypeInformation type = types.allocateDiamondPhi(firstType, secondType);
    return type;
  }

  TypeInformation visitVariableDefinitions(ast.VariableDefinitions node) {
    for (Link<ast.Node> link = node.definitions.nodes;
        !link.isEmpty;
        link = link.tail) {
      ast.Node definition = link.head;
      if (definition is ast.Identifier) {
        LocalElement local = elements[definition];
        locals.update(local, types.nullType, node, local.type);
      } else {
        assert(definition.asSendSet() != null);
        handleSendSet(definition);
      }
    }
    return null;
  }

  bool handleCondition(ast.Node node, List<ast.Send> tests) {
    bool oldConditionIsSimple = conditionIsSimple;
    bool oldAccumulateIsChecks = accumulateIsChecks;
    List<ast.Send> oldIsChecks = isChecks;
    accumulateIsChecks = true;
    conditionIsSimple = true;
    isChecks = tests;
    visit(node);
    bool simpleCondition = conditionIsSimple;
    accumulateIsChecks = oldAccumulateIsChecks;
    isChecks = oldIsChecks;
    conditionIsSimple = oldConditionIsSimple;
    return simpleCondition;
  }

  TypeInformation visitIf(ast.If node) {
    List<ast.Send> tests = <ast.Send>[];
    bool simpleCondition = handleCondition(node.condition, tests);
    LocalsHandler saved = locals;
    locals = new LocalsHandler.from(locals, node);
    updateIsChecks(tests, usePositive: true);
    visit(node.thenPart);
    LocalsHandler thenLocals = locals;
    locals = new LocalsHandler.from(saved, node);
    if (simpleCondition) updateIsChecks(tests, usePositive: false);
    visit(node.elsePart);
    saved.mergeDiamondFlow(thenLocals, locals);
    locals = saved;
    return null;
  }

  void setupBreaksAndContinues(JumpTarget element) {
    if (element == null) return;
    if (element.isContinueTarget) continuesFor[element] = <LocalsHandler>[];
    if (element.isBreakTarget) breaksFor[element] = <LocalsHandler>[];
  }

  void clearBreaksAndContinues(JumpTarget element) {
    continuesFor.remove(element);
    breaksFor.remove(element);
  }

  List<LocalsHandler> getBreaks(JumpTarget element) {
    List<LocalsHandler> list = <LocalsHandler>[locals];
    if (element == null) return list;
    if (!element.isBreakTarget) return list;
    return list..addAll(breaksFor[element]);
  }

  List<LocalsHandler> getLoopBackEdges(JumpTarget element) {
    List<LocalsHandler> list = <LocalsHandler>[locals];
    if (element == null) return list;
    if (!element.isContinueTarget) return list;
    return list..addAll(continuesFor[element]);
  }

  TypeInformation handleLoop(ast.Node node, void logic()) {
    loopLevel++;
    bool changed = false;
    JumpTarget target = elements.getTargetDefinition(node);
    LocalsHandler saved = locals;
    saved.startLoop(node);
    do {
      // Setup (and clear in case of multiple iterations of the loop)
      // the lists of breaks and continues seen in the loop.
      setupBreaksAndContinues(target);
      locals = new LocalsHandler.from(saved, node);
      logic();
      changed = saved.mergeAll(getLoopBackEdges(target));
    } while (changed);
    loopLevel--;
    saved.endLoop(node);
    bool keepOwnLocals = node.asDoWhile() == null;
    saved.mergeAfterBreaks(getBreaks(target), keepOwnLocals: keepOwnLocals);
    locals = saved;
    clearBreaksAndContinues(target);
    return null;
  }

  TypeInformation visitWhile(ast.While node) {
    return handleLoop(node, () {
      List<ast.Send> tests = <ast.Send>[];
      handleCondition(node.condition, tests);
      updateIsChecks(tests, usePositive: true);
      visit(node.body);
    });
  }

  TypeInformation visitDoWhile(ast.DoWhile node) {
    return handleLoop(node, () {
      visit(node.body);
      List<ast.Send> tests = <ast.Send>[];
      handleCondition(node.condition, tests);
      // TODO(29309): This condition appears to stengthen both the back-edge and
      // exit-edge. For now, avoid strengthening on the condition until the
      // proper fix is found.
      //
      //     updateIsChecks(tests, usePositive: true);
    });
  }

  TypeInformation visitFor(ast.For node) {
    visit(node.initializer);
    return handleLoop(node, () {
      List<ast.Send> tests = <ast.Send>[];
      handleCondition(node.condition, tests);
      updateIsChecks(tests, usePositive: true);
      visit(node.body);
      visit(node.update);
    });
  }

  TypeInformation visitTryStatement(ast.TryStatement node) {
    LocalsHandler saved = locals;
    locals = new LocalsHandler.from(locals, node, useOtherTryBlock: false);
    initializationIsIndefinite();
    visit(node.tryBlock);
    saved.mergeDiamondFlow(locals, null);
    locals = saved;
    for (ast.Node catchBlock in node.catchBlocks) {
      saved = locals;
      locals = new LocalsHandler.from(locals, catchBlock);
      visit(catchBlock);
      saved.mergeDiamondFlow(locals, null);
      locals = saved;
    }
    visit(node.finallyBlock);
    return null;
  }

  TypeInformation visitThrow(ast.Throw node) {
    node.visitChildren(this);
    locals.seenReturnOrThrow = true;
    return types.nonNullEmpty();
  }

  TypeInformation visitCatchBlock(ast.CatchBlock node) {
    ast.Node exception = node.exception;
    if (exception != null) {
      ResolutionDartType type = elements.getType(node.type);
      TypeInformation mask;
      if (type == null || type.treatAsDynamic || type.isTypeVariable) {
        mask = types.dynamicType;
      } else {
        ResolutionInterfaceType interfaceType = type;
        mask = types.nonNullSubtype(interfaceType.element);
      }
      LocalElement local = elements[exception];
      locals.update(local, mask, node, local.type);
    }
    ast.Node trace = node.trace;
    if (trace != null) {
      LocalElement local = elements[trace];
      locals.update(local, types.dynamicType, node, local.type);
    }
    visit(node.block);
    return null;
  }

  TypeInformation visitParenthesizedExpression(
      ast.ParenthesizedExpression node) {
    return visit(node.expression);
  }

  TypeInformation visitBlock(ast.Block node) {
    if (node.statements != null) {
      for (ast.Node statement in node.statements) {
        visit(statement);
        if (locals.aborts) break;
      }
    }
    return null;
  }

  TypeInformation visitLabeledStatement(ast.LabeledStatement node) {
    ast.Statement body = node.statement;
    if (body is ast.Loop ||
        body is ast.SwitchStatement ||
        Elements.isUnusedLabel(node, elements)) {
      // Loops and switches handle their own labels.
      visit(body);
    } else {
      JumpTarget targetElement = elements.getTargetDefinition(body);
      setupBreaksAndContinues(targetElement);
      visit(body);
      locals.mergeAfterBreaks(getBreaks(targetElement));
      clearBreaksAndContinues(targetElement);
    }
    return null;
  }

  TypeInformation visitBreakStatement(ast.BreakStatement node) {
    JumpTarget target = elements.getTargetOf(node);
    locals.seenBreakOrContinue = true;
    // Do a deep-copy of the locals, because the code following the
    // break will change them.
    breaksFor[target].add(new LocalsHandler.deepCopyOf(locals));
    return null;
  }

  TypeInformation visitContinueStatement(ast.ContinueStatement node) {
    JumpTarget target = elements.getTargetOf(node);
    locals.seenBreakOrContinue = true;
    // Do a deep-copy of the locals, because the code following the
    // continue will change them.
    continuesFor[target].add(new LocalsHandler.deepCopyOf(locals));
    return null;
  }

  internalError(Spannable node, String reason) {
    reporter.internalError(node, reason);
  }

  TypeInformation visitSwitchStatement(ast.SwitchStatement node) {
    visit(node.parenthesizedExpression);

    setupBreaksAndContinues(elements.getTargetDefinition(node));
    if (Elements.switchStatementHasContinue(node, elements)) {
      void forEachLabeledCase(void action(JumpTarget target)) {
        for (ast.SwitchCase switchCase in node.cases) {
          for (ast.Node labelOrCase in switchCase.labelsAndCases) {
            if (labelOrCase.asLabel() == null) continue;
            LabelDefinition labelElement =
                elements.getLabelDefinition(labelOrCase);
            if (labelElement != null) {
              action(labelElement.target);
            }
          }
        }
      }

      forEachLabeledCase((JumpTarget target) {
        setupBreaksAndContinues(target);
      });

      // If the switch statement has a continue, we conservatively
      // visit all cases and update [locals] until we have reached a
      // fixed point.
      bool changed;
      locals.startLoop(node);
      do {
        changed = false;
        for (ast.Node switchCase in node.cases) {
          LocalsHandler saved = locals;
          locals = new LocalsHandler.from(locals, switchCase);
          visit(switchCase);
          changed = saved.mergeAll([locals]) || changed;
          locals = saved;
        }
      } while (changed);
      locals.endLoop(node);

      forEachLabeledCase((JumpTarget target) {
        clearBreaksAndContinues(target);
      });
    } else {
      LocalsHandler saved = locals;
      List<LocalsHandler> localsToMerge = <LocalsHandler>[];
      bool hasDefaultCase = false;

      for (ast.SwitchCase switchCase in node.cases) {
        if (switchCase.isDefaultCase) {
          hasDefaultCase = true;
        }
        locals = new LocalsHandler.from(saved, switchCase);
        visit(switchCase);
        localsToMerge.add(locals);
      }
      saved.mergeAfterBreaks(localsToMerge, keepOwnLocals: !hasDefaultCase);
      locals = saved;
    }
    clearBreaksAndContinues(elements.getTargetDefinition(node));
    return null;
  }

  TypeInformation visitCascadeReceiver(ast.CascadeReceiver node) {
    var type = visit(node.expression);
    cascadeReceiverStack.add(type);
    return type;
  }

  TypeInformation visitCascade(ast.Cascade node) {
    // Ignore the result of the cascade send and return the type of the cascade
    // receiver.
    visit(node.expression);
    return cascadeReceiverStack.removeLast();
  }

  void analyzeSuperConstructorCall(
      ConstructorElement target, ArgumentsTypes arguments) {
    assert(target.isDeclaration);
    ResolvedAst resolvedAst = target.resolvedAst;
    ast.Node body;
    if (resolvedAst.kind == ResolvedAstKind.PARSED) {
      body = resolvedAst.node;
    }
    inferrer.analyze(target, body, arguments);
    isThisExposed = isThisExposed || inferrer.checkIfExposesThis(target);
  }

  TypeInformation run() {
    var node;
    if (resolvedAst.kind == ResolvedAstKind.PARSED) {
      node = resolvedAst.node;
    }
    ast.Expression initializer;
    if (analyzedElement.isField) {
      initializer = resolvedAst.body;
      if (initializer == null) {
        // Eagerly bailout, because computing the closure data only
        // works for functions and field assignments.
        return types.nullType;
      }
    }
    // Update the locals that are boxed in [locals]. These locals will
    // be handled specially, in that we are computing their LUB at
    // each update, and reading them yields the type that was found in a
    // previous analysis of [outermostElement].
    ClosureRepresentationInfo closureData = compiler
        .backendStrategy.closureDataLookup
        .getClosureInfoForMember(analyzedElement);
    closureData.forEachCapturedVariable((variable, field) {
      locals.setCaptured(variable, field);
    });
    closureData.forEachBoxedVariable((variable, field) {
      locals.setCapturedAndBoxed(variable, field);
    });
    if (analyzedElement.isField) {
      return visit(initializer);
    }

    MethodElement function = analyzedElement.implementation;
    FunctionSignature signature = function.functionSignature;
    signature.forEachOptionalParameter((FormalElement _element) {
      ParameterElement parameter = _element;
      ast.Expression defaultValue = parameter.initializer;
      // TODO(25566): The default value of a parameter of a redirecting factory
      // constructor comes from the corresponding parameter of the target.

      // If this is a default value from a different context (because
      // the current function is synthetic, e.g., a constructor from
      // a mixin application), we have to start a new inferrer visitor
      // with the correct context.
      // TODO(johnniwinther): Remove once function signatures are fixed.
      ElementGraphBuilder visitor = this;
      if (inferrer.hasAlreadyComputedTypeOfParameterDefault(parameter)) return;

      FunctionElement declaration = parameter.functionDeclaration.declaration;
      MethodElement declarationMethod = declaration is LocalFunctionElement
          ? declaration.callMethod
          : declaration;
      bool needNewContext = declarationMethod != analyzedElement;
      if (needNewContext) {
        assert(
            declarationMethod is ConstructorElement,
            failedAt(
                parameter,
                "Unexpected function declaration "
                "${declarationMethod}, expected ${analyzedElement}."));
        visitor =
            new ElementGraphBuilder(declarationMethod, compiler, inferrer);
      }
      TypeInformation type =
          (defaultValue == null) ? types.nullType : visitor.visit(defaultValue);
      inferrer.setDefaultTypeOfParameter(parameter, type,
          isInstanceMember: function.isInstanceMember);
    });

    if (closedWorld.nativeData.isNativeMember(analyzedElement)) {
      // Native methods do not have a body, and we currently just say
      // they return dynamic.
      return types.dynamicType;
    }

    if (analyzedElement.isGenerativeConstructor) {
      ConstructorElement analyzedConstructor = analyzedElement;
      isThisExposed = false;
      signature.forEachParameter((FormalElement _element) {
        ParameterElement element = _element;
        TypeInformation parameterType = inferrer.typeOfParameter(element);
        if (element.isInitializingFormal) {
          InitializingFormalElement initializingFormal = element;
          if (initializingFormal.fieldElement.isFinal) {
            inferrer.recordTypeOfField(
                initializingFormal.fieldElement, parameterType);
          } else {
            locals.updateField(initializingFormal.fieldElement, parameterType);
            inferrer.recordTypeOfField(
                initializingFormal.fieldElement, parameterType);
          }
        }
        locals.update(element, parameterType, node, element.type);
      });
      ClassElement cls = analyzedConstructor.enclosingClass;
      Spannable spannable = node;
      if (analyzedConstructor.isSynthesized) {
        spannable = analyzedConstructor;
        synthesizeForwardingCall(
            spannable, analyzedConstructor.definingConstructor);
      } else {
        visitingInitializers = true;
        if (node.initializers != null) {
          for (ast.Node initializer in node.initializers) {
            ast.SendSet fieldInitializer = initializer.asSendSet();
            if (fieldInitializer != null) {
              handleSendSet(fieldInitializer);
            } else {
              Element element = elements[initializer];
              handleConstructorSend(initializer, element);
            }
          }
        }
        visitingInitializers = false;
        // For a generative constructor like: `Foo();`, we synthesize
        // a call to the default super constructor (the one that takes
        // no argument). Resolution ensures that such a constructor
        // exists.
        if (!isConstructorRedirect &&
            !seenSuperConstructorCall &&
            !cls.isObject) {
          ConstructorElement target = cls.superclass.lookupDefaultConstructor();
          ArgumentsTypes arguments = new ArgumentsTypes([], {});
          analyzeSuperConstructorCall(target, arguments);
          inferrer.registerCalledMember(node, null, null, outermostElement,
              target, arguments, sideEffects, inLoop);
        }
        visit(node.body);
        inferrer.recordExposesThis(analyzedConstructor, isThisExposed);
      }
      if (!isConstructorRedirect) {
        // Iterate over all instance fields, and give a null type to
        // fields that we haven't initialized for sure.
        cls.forEachInstanceField((_, FieldElement field) {
          if (field.isFinal) return;
          TypeInformation type = locals.fieldScope.readField(field);
          ResolvedAst resolvedAst = field.resolvedAst;
          if (type == null &&
              (resolvedAst.body == null ||
                  resolvedAst.body is ast.LiteralNull)) {
            inferrer.recordTypeOfField(field, types.nullType);
          }
        });
      }
      if (analyzedElement.isGenerativeConstructor && cls.isAbstract) {
        if (closedWorld.isInstantiated(cls)) {
          returnType = types.nonNullSubclass(cls);
        } else {
          // TODO(johnniwinther): Avoid analyzing [analyzedElement] in this
          // case; it's never called.
          returnType = types.nonNullEmpty();
        }
      } else {
        returnType = types.nonNullExact(cls);
      }
    } else {
      signature.forEachParameter((FormalElement _element) {
        ParameterElement element = _element;
        locals.update(
            element, inferrer.typeOfParameter(element), node, element.type);
      });
      visit(node.body);
      switch (function.asyncMarker) {
        case AsyncMarker.SYNC:
          if (returnType == null) {
            // No return in the body.
            returnType = locals.seenReturnOrThrow
                ? types.nonNullEmpty() // Body always throws.
                : types.nullType;
          } else if (!locals.seenReturnOrThrow) {
            // We haven't seen returns on all branches. So the method may
            // also return null.
            recordReturnType(types.nullType);
          }
          break;

        case AsyncMarker.SYNC_STAR:
          // TODO(asgerf): Maybe make a ContainerTypeMask for these? The type
          //               contained is the method body's return type.
          recordReturnType(types.syncStarIterableType);
          break;

        case AsyncMarker.ASYNC:
          recordReturnType(types.asyncFutureType);
          break;

        case AsyncMarker.ASYNC_STAR:
          recordReturnType(types.asyncStarStreamType);
          break;
      }
    }

    MethodElement declaration = analyzedElement.declaration;
    inferrer.closedWorldRefiner.registerSideEffects(declaration, sideEffects);
    assert(breaksFor.isEmpty);
    assert(continuesFor.isEmpty);
    return returnType;
  }

  TypeInformation visitFunctionExpression(ast.FunctionExpression node) {
    // We loose track of [this] in closures (see issue 20840). To be on
    // the safe side, we mark [this] as exposed here. We could do better by
    // analyzing the closure.
    // TODO(herhut): Analyze whether closure exposes this.
    isThisExposed = true;
    LocalFunctionElement element = elements.getFunctionDefinition(node);
    // We don't put the closure in the work queue of the
    // inferrer, because it will share information with its enclosing
    // method, like for example the types of local variables.
    LocalsHandler closureLocals =
        new LocalsHandler.from(locals, node, useOtherTryBlock: false);
    ElementGraphBuilder visitor = new ElementGraphBuilder(
        element.callMethod, compiler, inferrer, closureLocals);
    visitor.run();
    inferrer.recordReturnType(element.callMethod, visitor.returnType);

    // Record the types of captured non-boxed variables. Types of
    // these variables may already be there, because of an analysis of
    // a previous closure.
    ClosureRepresentationInfo nestedClosureData =
        compiler.backendStrategy.closureDataLookup.getClosureInfo(node);
    nestedClosureData.forEachCapturedVariable((variable, field) {
      if (!nestedClosureData.isVariableBoxed(variable)) {
        if (variable == nestedClosureData.thisLocal) {
          inferrer.recordTypeOfField(field, thisType);
        }
        // The type is null for type parameters.
        if (locals.locals[variable] == null) return;
        inferrer.recordTypeOfField(field, locals.locals[variable]);
      }
      capturedVariables.add(variable);
    });

    return inferrer.concreteTypes.putIfAbsent(node, () {
      return types.allocateClosure(element.callMethod);
    });
  }

  TypeInformation visitFunctionDeclaration(ast.FunctionDeclaration node) {
    LocalFunctionElement element =
        elements.getFunctionDefinition(node.function);
    TypeInformation type =
        inferrer.concreteTypes.putIfAbsent(node.function, () {
      return types.allocateClosure(element.callMethod);
    });
    locals.update(element, type, node, element.type);
    visit(node.function);
    return type;
  }

  TypeInformation visitStringInterpolation(ast.StringInterpolation node) {
    // Interpolation could have any effects since it could call any toString()
    // method.
    // TODO(sra): This could be modelled by a call to toString() but with a
    // guaranteed String return type.  Interpolation of known types would get
    // specialized effects.  This would not currently be effective since the JS
    // code in the toString methods for intercepted primitive types is assumed
    // to have all effects.  Effect annotations on JS code would be needed to
    // get the benefit.
    sideEffects.setAllSideEffects();
    node.visitChildren(this);
    return types.stringType;
  }

  TypeInformation visitLiteralList(ast.LiteralList node) {
    // We only set the type once. We don't need to re-visit the children
    // when re-analyzing the node.
    return inferrer.concreteTypes.putIfAbsent(node, () {
      TypeInformation elementType;
      int length = 0;
      for (ast.Node element in node.elements.nodes) {
        TypeInformation type = visit(element);
        elementType = elementType == null
            ? types.allocatePhi(null, null, type, isTry: false)
            : types.addPhiInput(null, elementType, type);
        length++;
      }
      elementType = elementType == null
          ? types.nonNullEmpty()
          : types.simplifyPhi(null, null, elementType);
      TypeInformation containerType =
          node.isConst ? types.constListType : types.growableListType;
      return types.allocateList(
          containerType, node, outermostElement, elementType, length);
    });
  }

  TypeInformation visitLiteralMap(ast.LiteralMap node) {
    return inferrer.concreteTypes.putIfAbsent(node, () {
      ast.NodeList entries = node.entries;
      List keyTypes = [];
      List valueTypes = [];

      for (ast.LiteralMapEntry entry in entries) {
        keyTypes.add(visit(entry.key));
        valueTypes.add(visit(entry.value));
      }

      TypeInformation type = node.isConst ? types.constMapType : types.mapType;
      return types.allocateMap(
          type, node, outermostElement, keyTypes, valueTypes);
    });
  }

  bool isThisOrSuper(ast.Node node) => node.isThis() || node.isSuper();

  bool isInClassOrSubclass(Element element) {
    ClassElement cls = outermostElement.enclosingClass;
    ClassElement enclosing = element.enclosingClass;
    return closedWorld.isSubclassOf(enclosing, cls);
  }

  void checkIfExposesThis(Selector selector, TypeMask mask) {
    if (isThisExposed) return;
    inferrer.forEachElementMatching(selector, mask, (MemberEntity element) {
      if (element.isField) {
        FieldElement field = element;
        ResolvedAst elementResolvedAst = field.resolvedAst;
        if (!selector.isSetter &&
            isInClassOrSubclass(field) &&
            !field.isFinal &&
            locals.fieldScope.readField(field) == null &&
            elementResolvedAst.body == null) {
          // If the field is being used before this constructor
          // actually had a chance to initialize it, say it can be
          // null.
          inferrer.recordTypeOfField(field, types.nullType);
        }
        // Accessing a field does not expose [:this:].
        return true;
      }
      // TODO(ngeoffray): We could do better here if we knew what we
      // are calling does not expose this.
      isThisExposed = true;
      return false;
    });
  }

  bool get inInstanceContext {
    return (outermostElement.isInstanceMember && !outermostElement.isField) ||
        outermostElement.isGenerativeConstructor;
  }

  bool treatAsInstanceMember(Element element) {
    return (Elements.isUnresolved(element) && inInstanceContext) ||
        (element != null && element.isInstanceMember);
  }

  TypeInformation handleSendSet(ast.SendSet node) {
    Element element = elements[node];
    if (!Elements.isUnresolved(element) && element.impliesType) {
      node.visitChildren(this);
      return types.dynamicType;
    }

    Selector getterSelector = elements.getGetterSelectorInComplexSendSet(node);
    TypeMask getterMask = memberData.typeOfGetter(node);
    TypeMask operatorMask = memberData.typeOfOperator(node);
    Selector setterSelector = elements.getSelector(node);
    TypeMask setterMask = memberData.typeOfSend(node);

    String op = node.assignmentOperator.source;
    bool isIncrementOrDecrement = op == '++' || op == '--';

    TypeInformation receiverType;
    bool isCallOnThis = false;
    if (node.receiver == null) {
      if (treatAsInstanceMember(element)) {
        receiverType = thisType;
        isCallOnThis = true;
      }
    } else {
      if (node.receiver != null) {
        Element receiver = elements[node.receiver];
        if (receiver is! PrefixElement && receiver is! ClassElement) {
          // TODO(johnniwinther): Avoid blindly recursing on the receiver.
          receiverType = visit(node.receiver);
        }
      }
      isCallOnThis = isThisOrSuper(node.receiver);
    }

    TypeInformation rhsType;

    if (isIncrementOrDecrement) {
      rhsType = types.uint31Type;
      if (node.isIndex) visit(node.arguments.head);
    } else if (node.isIndex) {
      visit(node.arguments.head);
      rhsType = visit(node.arguments.tail.head);
    } else {
      rhsType = visit(node.arguments.head);
    }

    if (!visitingInitializers && !isThisExposed) {
      for (ast.Node node in node.arguments) {
        if (isThisOrSuper(node)) {
          isThisExposed = true;
          break;
        }
      }
      if (!isThisExposed && isCallOnThis) {
        checkIfExposesThis(
            setterSelector, types.newTypedSelector(receiverType, setterMask));
        if (getterSelector != null) {
          checkIfExposesThis(
              getterSelector, types.newTypedSelector(receiverType, getterMask));
        }
      }
    }

    if (node.isIndex) {
      return internalError(node, "Unexpected index operation");
    } else if (op == '=') {
      return handlePlainAssignment(node, element, setterSelector, setterMask,
          receiverType, rhsType, node.arguments.head);
    } else {
      // [foo ??= bar], [: foo++ :] or [: foo += 1 :].
      TypeInformation getterType;
      TypeInformation newType;

      if (Elements.isMalformed(element)) return types.dynamicType;

      if (Elements.isStaticOrTopLevelField(element)) {
        Element getterElement = elements[node.selector];
        getterType = handleStaticSend(
            node, getterSelector, getterMask, getterElement, null);
      } else if (Elements.isUnresolved(element) ||
          element.isSetter ||
          element.isField) {
        getterType = handleDynamicSend(CallType.complex, node, getterSelector,
            getterMask, receiverType, null);
      } else if (element.isLocal) {
        LocalElement local = element;
        getterType = locals.use(local);
      } else {
        // Bogus SendSet, for example [: myMethod += 42 :].
        getterType = types.dynamicType;
      }

      if (op == '??=') {
        newType = types.allocateDiamondPhi(getterType, rhsType);
      } else {
        Selector operatorSelector =
            elements.getOperatorSelectorInComplexSendSet(node);
        newType = handleDynamicSend(CallType.complex, node, operatorSelector,
            operatorMask, getterType, new ArgumentsTypes([rhsType], null));
      }

      if (Elements.isStaticOrTopLevelField(element)) {
        handleStaticSend(node, setterSelector, setterMask, element,
            new ArgumentsTypes([newType], null));
      } else if (Elements.isUnresolved(element) ||
          element.isSetter ||
          element.isField) {
        handleDynamicSend(CallType.complex, node, setterSelector, setterMask,
            receiverType, new ArgumentsTypes([newType], null));
      } else if (element.isLocal) {
        LocalElement local = element;
        locals.update(local, newType, node, local.type,
            isSetIfNull: node.isIfNullAssignment);
      }

      return node.isPostfix ? getterType : newType;
    }
  }

  /// Handle compound index set, like `foo[0] += 42` or `foo[0]++`.
  TypeInformation handleCompoundIndexSet(
      ast.SendSet node,
      TypeInformation receiverType,
      TypeInformation indexType,
      TypeInformation rhsType) {
    Selector getterSelector = elements.getGetterSelectorInComplexSendSet(node);

    TypeMask getterMask = memberData.typeOfGetter(node);
    Selector operatorSelector =
        elements.getOperatorSelectorInComplexSendSet(node);
    TypeMask operatorMask = memberData.typeOfOperator(node);
    Selector setterSelector = elements.getSelector(node);
    TypeMask setterMask = memberData.typeOfSend(node);

    TypeInformation getterType = handleDynamicSend(
        CallType.complex,
        node,
        getterSelector,
        getterMask,
        receiverType,
        new ArgumentsTypes([indexType], null));

    TypeInformation returnType;
    if (node.isIfNullAssignment) {
      returnType = types.allocateDiamondPhi(getterType, rhsType);
    } else {
      returnType = handleDynamicSend(CallType.complex, node, operatorSelector,
          operatorMask, getterType, new ArgumentsTypes([rhsType], null));
    }
    handleDynamicSend(CallType.complex, node, setterSelector, setterMask,
        receiverType, new ArgumentsTypes([indexType, returnType], null));

    if (node.isPostfix) {
      return getterType;
    } else {
      return returnType;
    }
  }

  /// Handle compound prefix/postfix operations, like `a[0]++`.
  TypeInformation handleCompoundPrefixPostfix(
      ast.Send node, TypeInformation receiverType, TypeInformation indexType) {
    return handleCompoundIndexSet(
        node, receiverType, indexType, types.uint31Type);
  }

  @override
  TypeInformation visitIndexPostfix(ast.Send node, ast.Node receiver,
      ast.Node index, op.IncDecOperator operator, _) {
    TypeInformation receiverType = visit(receiver);
    TypeInformation indexType = visit(index);
    return handleCompoundPrefixPostfix(node, receiverType, indexType);
  }

  @override
  TypeInformation visitIndexPrefix(ast.Send node, ast.Node receiver,
      ast.Node index, op.IncDecOperator operator, _) {
    TypeInformation receiverType = visit(receiver);
    TypeInformation indexType = visit(index);
    return handleCompoundPrefixPostfix(node, receiverType, indexType);
  }

  @override
  TypeInformation visitCompoundIndexSet(ast.SendSet node, ast.Node receiver,
      ast.Node index, op.AssignmentOperator operator, ast.Node rhs, _) {
    TypeInformation receiverType = visit(receiver);
    TypeInformation indexType = visit(index);
    TypeInformation rhsType = visit(rhs);
    return handleCompoundIndexSet(node, receiverType, indexType, rhsType);
  }

  @override
  TypeInformation visitIndexSetIfNull(
      ast.SendSet node, ast.Node receiver, ast.Node index, ast.Node rhs, _) {
    TypeInformation receiverType = visit(receiver);
    TypeInformation indexType = visit(index);
    TypeInformation rhsType = visit(rhs);
    return handleCompoundIndexSet(node, receiverType, indexType, rhsType);
  }

  @override
  TypeInformation visitSuperIndexPrefix(ast.Send node, MethodElement getter,
      MethodElement setter, ast.Node index, op.IncDecOperator operator, _) {
    TypeInformation indexType = visit(index);
    return handleSuperIndexPrefixPostfix(node, getter, setter, indexType);
  }

  @override
  TypeInformation visitSuperIndexPostfix(ast.Send node, MethodElement getter,
      MethodElement setter, ast.Node index, op.IncDecOperator operator, _) {
    TypeInformation indexType = visit(index);
    return handleSuperIndexPrefixPostfix(node, getter, setter, indexType);
  }

  /// Handle compound prefix/postfix operations, like `super[0]++`.
  TypeInformation handleSuperIndexPrefixPostfix(ast.Send node, Element getter,
      Element setter, TypeInformation indexType) {
    return _handleSuperCompoundIndexSet(
        node, getter, setter, indexType, types.uint31Type);
  }

  /// Handle compound super index set, like `super[42] =+ 2`.
  TypeInformation handleSuperCompoundIndexSet(ast.SendSet node, Element getter,
      Element setter, ast.Node index, ast.Node rhs) {
    TypeInformation indexType = visit(index);
    TypeInformation rhsType = visit(rhs);
    return _handleSuperCompoundIndexSet(
        node, getter, setter, indexType, rhsType);
  }

  TypeInformation _handleSuperCompoundIndexSet(ast.SendSet node, Element getter,
      Element setter, TypeInformation indexType, TypeInformation rhsType) {
    Selector getterSelector = elements.getGetterSelectorInComplexSendSet(node);

    TypeMask getterMask = memberData.typeOfGetter(node);
    Selector setterSelector = elements.getSelector(node);
    TypeMask setterMask = memberData.typeOfSend(node);

    TypeInformation getterType = handleSuperSend(node, getterSelector,
        getterMask, getter, new ArgumentsTypes([indexType], null));

    TypeInformation returnType;
    if (node.isIfNullAssignment) {
      returnType = types.allocateDiamondPhi(getterType, rhsType);
    } else {
      Selector operatorSelector =
          elements.getOperatorSelectorInComplexSendSet(node);
      TypeMask operatorMask = memberData.typeOfOperator(node);
      returnType = handleDynamicSend(CallType.complex, node, operatorSelector,
          operatorMask, getterType, new ArgumentsTypes([rhsType], null));
    }
    handleSuperSend(node, setterSelector, setterMask, setter,
        new ArgumentsTypes([indexType, returnType], null));

    return node.isPostfix ? getterType : returnType;
  }

  TypeInformation handleSuperSend(ast.Node node, Selector selector,
      TypeMask mask, Element element, ArgumentsTypes arguments) {
    if (element.isMalformed) {
      return handleSuperNoSuchMethod(node, selector, mask, arguments);
    } else {
      return handleStaticSend(node, selector, mask, element, arguments);
    }
  }

  @override
  TypeInformation visitSuperCompoundIndexSet(
      ast.SendSet node,
      MethodElement getter,
      MethodElement setter,
      ast.Node index,
      op.AssignmentOperator operator,
      ast.Node rhs,
      _) {
    return handleSuperCompoundIndexSet(node, getter, setter, index, rhs);
  }

  @override
  TypeInformation visitSuperIndexSetIfNull(
      ast.SendSet node,
      MethodElement getter,
      MethodElement setter,
      ast.Node index,
      ast.Node rhs,
      _) {
    return handleSuperCompoundIndexSet(node, getter, setter, index, rhs);
  }

  @override
  TypeInformation visitUnresolvedSuperCompoundIndexSet(
      ast.SendSet node,
      Element element,
      ast.Node index,
      op.AssignmentOperator operator,
      ast.Node rhs,
      _) {
    return handleSuperCompoundIndexSet(node, element, element, index, rhs);
  }

  @override
  TypeInformation visitUnresolvedSuperIndexSetIfNull(
      ast.Send node, Element element, ast.Node index, ast.Node rhs, _) {
    return handleSuperCompoundIndexSet(node, element, element, index, rhs);
  }

  @override
  TypeInformation visitUnresolvedSuperGetterCompoundIndexSet(
      ast.SendSet node,
      Element element,
      MethodElement setter,
      ast.Node index,
      op.AssignmentOperator operator,
      ast.Node rhs,
      _) {
    return handleSuperCompoundIndexSet(node, element, setter, index, rhs);
  }

  @override
  TypeInformation visitUnresolvedSuperGetterIndexSetIfNull(ast.SendSet node,
      Element element, MethodElement setter, ast.Node index, ast.Node rhs, _) {
    return handleSuperCompoundIndexSet(node, element, setter, index, rhs);
  }

  @override
  TypeInformation visitUnresolvedSuperSetterCompoundIndexSet(
      ast.SendSet node,
      MethodElement getter,
      Element element,
      ast.Node index,
      op.AssignmentOperator operator,
      ast.Node rhs,
      _) {
    return handleSuperCompoundIndexSet(node, getter, element, index, rhs);
  }

  @override
  TypeInformation visitUnresolvedSuperSetterIndexSetIfNull(ast.SendSet node,
      MethodElement getter, Element element, ast.Node index, ast.Node rhs, _) {
    return handleSuperCompoundIndexSet(node, getter, element, index, rhs);
  }

  @override
  TypeInformation visitUnresolvedSuperIndexPrefix(ast.Send node,
      Element element, ast.Node index, op.IncDecOperator operator, _) {
    TypeInformation indexType = visit(index);
    return handleSuperIndexPrefixPostfix(node, element, element, indexType);
  }

  @override
  TypeInformation visitUnresolvedSuperGetterIndexPrefix(
      ast.SendSet node,
      Element element,
      MethodElement setter,
      ast.Node index,
      op.IncDecOperator operator,
      _) {
    TypeInformation indexType = visit(index);
    return handleSuperIndexPrefixPostfix(node, element, setter, indexType);
  }

  @override
  TypeInformation visitUnresolvedSuperSetterIndexPrefix(
      ast.SendSet node,
      MethodElement getter,
      Element element,
      ast.Node index,
      op.IncDecOperator operator,
      _) {
    TypeInformation indexType = visit(index);
    return handleSuperIndexPrefixPostfix(node, getter, element, indexType);
  }

  @override
  TypeInformation visitUnresolvedSuperIndexPostfix(ast.Send node,
      Element element, ast.Node index, op.IncDecOperator operator, _) {
    TypeInformation indexType = visit(index);
    return handleSuperIndexPrefixPostfix(node, element, element, indexType);
  }

  @override
  TypeInformation visitUnresolvedSuperGetterIndexPostfix(
      ast.SendSet node,
      Element element,
      MethodElement setter,
      ast.Node index,
      op.IncDecOperator operator,
      _) {
    TypeInformation indexType = visit(index);
    return handleSuperIndexPrefixPostfix(node, element, setter, indexType);
  }

  @override
  TypeInformation visitUnresolvedSuperSetterIndexPostfix(
      ast.SendSet node,
      MethodElement getter,
      Element element,
      ast.Node index,
      op.IncDecOperator operator,
      _) {
    TypeInformation indexType = visit(index);
    return handleSuperIndexPrefixPostfix(node, getter, element, indexType);
  }

  @override
  TypeInformation visitSuperFieldCompound(ast.Send node, FieldElement field,
      op.AssignmentOperator operator, ast.Node rhs, _) {
    return handleSuperCompound(node, field, field, rhs);
  }

  @override
  TypeInformation visitSuperFieldSetterCompound(
      ast.Send node,
      FieldElement field,
      SetterElement setter,
      op.AssignmentOperator operator,
      ast.Node rhs,
      _) {
    return handleSuperCompound(node, field, setter, rhs);
  }

  @override
  TypeInformation visitSuperGetterFieldCompound(
      ast.Send node,
      GetterElement getter,
      FieldElement field,
      op.AssignmentOperator operator,
      ast.Node rhs,
      _) {
    return handleSuperCompound(node, getter, field, rhs);
  }

  @override
  TypeInformation visitSuperGetterSetterCompound(
      ast.Send node,
      GetterElement getter,
      SetterElement setter,
      op.AssignmentOperator operator,
      ast.Node rhs,
      _) {
    return handleSuperCompound(node, getter, setter, rhs);
  }

  @override
  TypeInformation visitSuperMethodSetterCompound(
      ast.Send node,
      FunctionElement method,
      SetterElement setter,
      op.AssignmentOperator operator,
      ast.Node rhs,
      _) {
    return handleSuperCompound(node, method, setter, rhs);
  }

  @override
  TypeInformation visitUnresolvedSuperCompound(ast.Send node, Element element,
      op.AssignmentOperator operator, ast.Node rhs, _) {
    return handleSuperCompound(node, element, element, rhs);
  }

  @override
  TypeInformation visitUnresolvedSuperGetterCompound(
      ast.SendSet node,
      Element getter,
      SetterElement setter,
      op.AssignmentOperator operator,
      ast.Node rhs,
      _) {
    return handleSuperCompound(node, getter, setter, rhs);
  }

  @override
  TypeInformation visitUnresolvedSuperSetterCompound(
      ast.Send node,
      GetterElement getter,
      Element setter,
      op.AssignmentOperator operator,
      ast.Node rhs,
      _) {
    return handleSuperCompound(node, getter, setter, rhs);
  }

  @override
  TypeInformation visitSuperFieldFieldSetIfNull(ast.Send node,
      FieldElement readField, FieldElement writtenField, ast.Node rhs, _) {
    return handleSuperCompound(node, readField, writtenField, rhs);
  }

  @override
  TypeInformation visitSuperFieldSetIfNull(
      ast.Send node, FieldElement field, ast.Node rhs, _) {
    return handleSuperCompound(node, field, field, rhs);
  }

  @override
  TypeInformation visitSuperFieldSetterSetIfNull(ast.Send node,
      FieldElement field, SetterElement setter, ast.Node rhs, _) {
    return handleSuperCompound(node, field, setter, rhs);
  }

  @override
  TypeInformation visitSuperGetterFieldSetIfNull(ast.Send node,
      GetterElement getter, FieldElement field, ast.Node rhs, _) {
    return handleSuperCompound(node, getter, field, rhs);
  }

  @override
  TypeInformation visitSuperGetterSetterSetIfNull(ast.Send node,
      GetterElement getter, SetterElement setter, ast.Node rhs, _) {
    return handleSuperCompound(node, getter, setter, rhs);
  }

  @override
  TypeInformation visitSuperMethodSetIfNull(
      ast.Send node, FunctionElement method, ast.Node rhs, _) {
    return handleSuperCompound(node, method, null, rhs);
  }

  @override
  TypeInformation visitSuperMethodSetterSetIfNull(ast.Send node,
      FunctionElement method, SetterElement setter, ast.Node rhs, _) {
    return handleSuperCompound(node, method, setter, rhs);
  }

  TypeInformation handleSuperCompound(
      ast.SendSet node, Element getter, Element setter, ast.Node rhs) {
    TypeInformation rhsType = visit(rhs);
    return _handleSuperCompound(node, getter, setter, rhsType);
  }

  @override
  TypeInformation visitSuperFieldFieldPostfix(
      ast.SendSet node,
      FieldElement readField,
      FieldElement writtenField,
      op.IncDecOperator operator,
      _) {
    return handleSuperPrefixPostfix(node, readField, writtenField);
  }

  @override
  TypeInformation visitSuperFieldFieldPrefix(
      ast.SendSet node,
      FieldElement readField,
      FieldElement writtenField,
      op.IncDecOperator operator,
      _) {
    return handleSuperPrefixPostfix(node, readField, writtenField);
  }

  @override
  TypeInformation visitSuperFieldPostfix(
      ast.SendSet node, FieldElement field, op.IncDecOperator operator, _) {
    return handleSuperPrefixPostfix(node, field, field);
  }

  @override
  TypeInformation visitSuperFieldPrefix(
      ast.SendSet node, FieldElement field, op.IncDecOperator operator, _) {
    return handleSuperPrefixPostfix(node, field, field);
  }

  @override
  TypeInformation visitSuperFieldSetterPostfix(ast.SendSet node,
      FieldElement field, SetterElement setter, op.IncDecOperator operator, _) {
    return handleSuperPrefixPostfix(node, field, setter);
  }

  @override
  TypeInformation visitSuperFieldSetterPrefix(ast.SendSet node,
      FieldElement field, SetterElement setter, op.IncDecOperator operator, _) {
    return handleSuperPrefixPostfix(node, field, setter);
  }

  @override
  TypeInformation visitSuperGetterFieldPostfix(ast.SendSet node,
      GetterElement getter, FieldElement field, op.IncDecOperator operator, _) {
    return handleSuperPrefixPostfix(node, getter, field);
  }

  @override
  TypeInformation visitSuperGetterFieldPrefix(ast.SendSet node,
      GetterElement getter, FieldElement field, op.IncDecOperator operator, _) {
    return handleSuperPrefixPostfix(node, getter, field);
  }

  @override
  TypeInformation visitSuperGetterSetterPostfix(
      ast.SendSet node,
      GetterElement getter,
      SetterElement setter,
      op.IncDecOperator operator,
      _) {
    return handleSuperPrefixPostfix(node, getter, setter);
  }

  @override
  TypeInformation visitSuperGetterSetterPrefix(
      ast.SendSet node,
      GetterElement getter,
      SetterElement setter,
      op.IncDecOperator operator,
      _) {
    return handleSuperPrefixPostfix(node, getter, setter);
  }

  @override
  TypeInformation visitSuperMethodSetterPostfix(
      ast.SendSet node,
      FunctionElement method,
      SetterElement setter,
      op.IncDecOperator operator,
      _) {
    return handleSuperPrefixPostfix(node, method, setter);
  }

  @override
  TypeInformation visitSuperMethodSetterPrefix(
      ast.SendSet node,
      FunctionElement method,
      SetterElement setter,
      op.IncDecOperator operator,
      _) {
    return handleSuperPrefixPostfix(node, method, setter);
  }

  @override
  TypeInformation visitUnresolvedSuperPrefix(
      ast.SendSet node, Element element, op.IncDecOperator operator, _) {
    return handleSuperPrefixPostfix(node, element, element);
  }

  @override
  TypeInformation visitUnresolvedSuperPostfix(
      ast.SendSet node, Element element, op.IncDecOperator operator, _) {
    return handleSuperPrefixPostfix(node, element, element);
  }

  @override
  TypeInformation visitUnresolvedSuperGetterPrefix(ast.SendSet node,
      Element getter, SetterElement setter, op.IncDecOperator operator, _) {
    return handleSuperPrefixPostfix(node, getter, setter);
  }

  @override
  TypeInformation visitUnresolvedSuperGetterPostfix(ast.SendSet node,
      Element getter, SetterElement setter, op.IncDecOperator operator, _) {
    return handleSuperPrefixPostfix(node, getter, setter);
  }

  @override
  TypeInformation visitUnresolvedSuperSetterPrefix(ast.SendSet node,
      GetterElement getter, Element setter, op.IncDecOperator operator, _) {
    return handleSuperPrefixPostfix(node, getter, setter);
  }

  @override
  TypeInformation visitUnresolvedSuperSetterPostfix(ast.SendSet node,
      GetterElement getter, Element setter, op.IncDecOperator operator, _) {
    return handleSuperPrefixPostfix(node, getter, setter);
  }

  TypeInformation handleSuperPrefixPostfix(
      ast.SendSet node, Element getter, Element setter) {
    return _handleSuperCompound(node, getter, setter, types.uint31Type);
  }

  TypeInformation _handleSuperCompound(ast.SendSet node, Element getter,
      Element setter, TypeInformation rhsType) {
    Selector getterSelector = elements.getGetterSelectorInComplexSendSet(node);
    TypeMask getterMask = memberData.typeOfGetter(node);
    Selector setterSelector = elements.getSelector(node);
    TypeMask setterMask = memberData.typeOfSend(node);

    TypeInformation getterType =
        handleSuperSend(node, getterSelector, getterMask, getter, null);

    TypeInformation returnType;
    if (node.isIfNullAssignment) {
      returnType = types.allocateDiamondPhi(getterType, rhsType);
    } else {
      Selector operatorSelector =
          elements.getOperatorSelectorInComplexSendSet(node);
      TypeMask operatorMask = memberData.typeOfOperator(node);
      returnType = handleDynamicSend(CallType.complex, node, operatorSelector,
          operatorMask, getterType, new ArgumentsTypes([rhsType], null));
    }
    handleSuperSend(node, setterSelector, setterMask, setter,
        new ArgumentsTypes([returnType], null));

    return node.isPostfix ? getterType : returnType;
  }

  /// Handle index set, like `foo[0] = 42`.
  TypeInformation handleIndexSet(ast.SendSet node, TypeInformation receiverType,
      TypeInformation indexType, TypeInformation rhsType) {
    Selector setterSelector = elements.getSelector(node);
    TypeMask setterMask = memberData.typeOfSend(node);
    handleDynamicSend(CallType.complex, node, setterSelector, setterMask,
        receiverType, new ArgumentsTypes([indexType, rhsType], null));
    return rhsType;
  }

  @override
  TypeInformation visitIndexSet(
      ast.SendSet node, ast.Node receiver, ast.Node index, ast.Node rhs, _) {
    TypeInformation receiverType = visit(receiver);
    TypeInformation indexType = visit(index);
    TypeInformation rhsType = visit(rhs);
    return handleIndexSet(node, receiverType, indexType, rhsType);
  }

  /// Handle super index set, like `super[42] = true`.
  TypeInformation handleSuperIndexSet(
      ast.SendSet node, Element element, ast.Node index, ast.Node rhs) {
    TypeInformation indexType = visit(index);
    TypeInformation rhsType = visit(rhs);
    Selector setterSelector = elements.getSelector(node);
    TypeMask setterMask = memberData.typeOfSend(node);
    handleStaticSend(node, setterSelector, setterMask, element,
        new ArgumentsTypes([indexType, rhsType], null));
    return rhsType;
  }

  @override
  TypeInformation visitSuperIndexSet(ast.SendSet node, FunctionElement function,
      ast.Node index, ast.Node rhs, _) {
    return handleSuperIndexSet(node, function, index, rhs);
  }

  @override
  TypeInformation visitUnresolvedSuperIndexSet(ast.SendSet node,
      ErroneousElement element, ast.Node index, ast.Node rhs, _) {
    return handleSuperIndexSet(node, element, index, rhs);
  }

  TypeInformation handlePlainAssignment(
      ast.Node node,
      Element element,
      Selector setterSelector,
      TypeMask setterMask,
      TypeInformation receiverType,
      TypeInformation rhsType,
      ast.Node rhs) {
    ArgumentsTypes arguments = new ArgumentsTypes([rhsType], null);
    if (Elements.isMalformed(element)) {
      // Code will always throw.
    } else if (Elements.isStaticOrTopLevelField(element)) {
      handleStaticSend(node, setterSelector, setterMask, element, arguments);
    } else if (Elements.isUnresolved(element) || element.isSetter) {
      if (analyzedElement.isGenerativeConstructor &&
          (node.asSendSet() != null) &&
          (node.asSendSet().receiver != null) &&
          node.asSendSet().receiver.isThis()) {
        Iterable<MemberEntity> targets = closedWorld.locateMembers(
            setterSelector, types.newTypedSelector(thisType, setterMask));
        // We just recognized a field initialization of the form:
        // `this.foo = 42`. If there is only one target, we can update
        // its type.
        if (targets.length == 1) {
          MemberElement single = targets.first;
          if (single.isField) {
            FieldElement field = single;
            locals.updateField(field, rhsType);
          }
        }
      }
      handleDynamicSend(CallType.access, node, setterSelector, setterMask,
          receiverType, arguments);
    } else if (element.isField) {
      FieldElement field = element;
      if (field.isFinal) {
        inferrer.recordTypeOfField(field, rhsType);
      } else {
        if (analyzedElement.isGenerativeConstructor) {
          locals.updateField(field, rhsType);
        }
        if (visitingInitializers) {
          inferrer.recordTypeOfField(field, rhsType);
        } else {
          handleDynamicSend(CallType.complex, node, setterSelector, setterMask,
              receiverType, arguments);
        }
      }
    } else if (element.isLocal) {
      LocalElement local = element;
      ast.SendSet sendSet = node.asSendSet();
      bool isSetIfNull = sendSet != null && sendSet.isIfNullAssignment;
      locals.update(local, rhsType, node, local.type, isSetIfNull: isSetIfNull);
    }
    return rhsType;
  }

  /// Handle a super access or invocation that results in a `noSuchMethod` call.
  TypeInformation handleErroneousSuperSend(ast.Send node) {
    ArgumentsTypes arguments =
        node.isPropertyAccess ? null : analyzeArguments(node.arguments);
    Selector selector = elements.getSelector(node);
    TypeMask mask = memberData.typeOfSend(node);
    // TODO(herhut): We could do better here if we knew what we
    // are calling does not expose this.
    // TODO(johnniwinther): Do we still need this when calling directly?
    isThisExposed = true;
    return handleSuperNoSuchMethod(node, selector, mask, arguments);
  }

  TypeInformation handleSuperNoSuchMethod(ast.Send node, Selector selector,
      TypeMask mask, ArgumentsTypes arguments) {
    // Ensure we create a node, to make explicit the call to the
    // `noSuchMethod` handler.
    ClassElement cls = outermostElement.enclosingClass;
    MethodElement element = cls.lookupSuperMember(Identifiers.noSuchMethod_);
    if (!Selectors.noSuchMethod_.signatureApplies(element)) {
      ClassElement objectClass = closedWorld.commonElements.objectClass;
      element = objectClass.lookupMember(Identifiers.noSuchMethod_);
    }
    return handleStaticSend(node, selector, mask, element, arguments);
  }

  /// Handle a .call invocation on the values retrieved from the super
  /// [element]. For instance `super.foo(bar)` where `foo` is a field or getter.
  TypeInformation handleSuperClosureCall(
      ast.Send node, MemberElement element, ast.NodeList arguments) {
    ArgumentsTypes argumentTypes = analyzeArguments(arguments.nodes);
    Selector selector = elements.getSelector(node);
    TypeMask mask = memberData.typeOfSend(node);
    // TODO(herhut): We could do better here if we knew what we
    // are calling does not expose this.
    isThisExposed = true;
    return inferrer.registerCalledClosure(
        node,
        selector,
        mask,
        inferrer.typeOfMember(element),
        outermostElement,
        argumentTypes,
        sideEffects,
        inLoop);
  }

  /// Handle an invocation of super [method].
  TypeInformation handleSuperMethodInvoke(
      ast.Send node, MethodElement method, ArgumentsTypes arguments) {
    // TODO(herhut): We could do better here if we knew what we
    // are calling does not expose this.
    isThisExposed = true;
    Selector selector = elements.getSelector(node);
    TypeMask mask = memberData.typeOfSend(node);
    return handleStaticSend(node, selector, mask, method, arguments);
  }

  /// Handle access to a super field or getter [element].
  TypeInformation handleSuperGet(ast.Send node, Element element) {
    // TODO(herhut): We could do better here if we knew what we
    // are calling does not expose this.
    isThisExposed = true;
    Selector selector = elements.getSelector(node);
    TypeMask mask = memberData.typeOfSend(node);
    return handleStaticSend(node, selector, mask, element, null);
  }

  /// Handle update to a super field or setter [element].
  TypeInformation handleSuperSet(ast.Send node, Element element, ast.Node rhs) {
    TypeInformation rhsType = visit(rhs);
    // TODO(herhut): We could do better here if we knew what we
    // are calling does not expose this.
    isThisExposed = true;
    Selector selector = elements.getSelector(node);
    TypeMask mask = memberData.typeOfSend(node);
    handleStaticSend(
        node, selector, mask, element, new ArgumentsTypes([rhsType], null));
    return rhsType;
  }

  @override
  TypeInformation visitSuperFieldSet(
      ast.Send node, FieldElement method, ast.Node rhs, _) {
    return handleSuperSet(node, method, rhs);
  }

  @override
  TypeInformation visitSuperSetterSet(
      ast.SendSet node, SetterElement field, ast.Node rhs, _) {
    return handleSuperSet(node, field, rhs);
  }

  @override
  TypeInformation visitUnresolvedSuperIndex(
      ast.Send node, Element element, ast.Node index, _) {
    return handleErroneousSuperSend(node);
  }

  @override
  TypeInformation visitUnresolvedSuperUnary(
      ast.Send node, op.UnaryOperator operator, Element element, _) {
    return handleErroneousSuperSend(node);
  }

  @override
  TypeInformation visitUnresolvedSuperBinary(ast.Send node, Element element,
      op.BinaryOperator operator, ast.Node argument, _) {
    return handleErroneousSuperSend(node);
  }

  @override
  TypeInformation visitUnresolvedSuperGet(ast.Send node, Element element, _) {
    return handleErroneousSuperSend(node);
  }

  @override
  TypeInformation visitSuperSetterGet(ast.Send node, MethodElement setter, _) {
    return handleErroneousSuperSend(node);
  }

  @override
  TypeInformation visitSuperGetterSet(
      ast.Send node, GetterElement getter, ast.Node rhs, _) {
    return handleErroneousSuperSend(node);
  }

  @override
  TypeInformation visitSuperMethodSet(
      ast.SendSet node, MethodElement method, ast.Node rhs, _) {
    return handleErroneousSuperSend(node);
  }

  @override
  TypeInformation visitFinalSuperFieldSet(
      ast.Send node, FieldElement method, ast.Node rhs, _) {
    return handleErroneousSuperSend(node);
  }

  @override
  TypeInformation visitUnresolvedSuperSet(
      ast.Send node, Element element, ast.Node rhs, _) {
    return handleErroneousSuperSend(node);
  }

  @override
  TypeInformation visitUnresolvedSuperInvoke(
      ast.Send node, Element element, ast.Node argument, Selector selector, _) {
    return handleErroneousSuperSend(node);
  }

  @override
  TypeInformation visitSuperFieldGet(ast.Send node, FieldElement field, _) {
    return handleSuperGet(node, field);
  }

  @override
  TypeInformation visitSuperGetterGet(ast.Send node, MethodElement method, _) {
    return handleSuperGet(node, method);
  }

  @override
  TypeInformation visitSuperMethodGet(ast.Send node, MethodElement method, _) {
    return handleSuperGet(node, method);
  }

  @override
  TypeInformation visitSuperFieldInvoke(ast.Send node, FieldElement field,
      ast.NodeList arguments, CallStructure callStructure, _) {
    return handleSuperClosureCall(node, field, arguments);
  }

  @override
  TypeInformation visitSuperGetterInvoke(ast.Send node, GetterElement getter,
      ast.NodeList arguments, CallStructure callStructure, _) {
    return handleSuperClosureCall(node, getter, arguments);
  }

  @override
  TypeInformation visitSuperMethodInvoke(ast.Send node, MethodElement method,
      ast.NodeList arguments, CallStructure callStructure, _) {
    return handleSuperMethodInvoke(
        node, method, analyzeArguments(arguments.nodes));
  }

  @override
  TypeInformation visitSuperSetterInvoke(ast.Send node, SetterElement setter,
      ast.NodeList arguments, CallStructure callStructure, _) {
    return handleErroneousSuperSend(node);
  }

  @override
  TypeInformation visitSuperIndex(
      ast.Send node, MethodElement method, ast.Node index, _) {
    return handleSuperMethodInvoke(
        node, method, analyzeArguments(node.arguments));
  }

  @override
  TypeInformation visitSuperEquals(
      ast.Send node, MethodElement method, ast.Node argument, _) {
    // TODO(johnniwinther): Special case ==.
    return handleSuperMethodInvoke(
        node, method, analyzeArguments(node.arguments));
  }

  @override
  TypeInformation visitSuperNotEquals(
      ast.Send node, MethodElement method, ast.Node argument, _) {
    // TODO(johnniwinther): Special case !=.
    return handleSuperMethodInvoke(
        node, method, analyzeArguments(node.arguments));
  }

  @override
  TypeInformation visitSuperBinary(ast.Send node, MethodElement method,
      op.BinaryOperator operator, ast.Node argument, _) {
    return handleSuperMethodInvoke(
        node, method, analyzeArguments(node.arguments));
  }

  @override
  TypeInformation visitSuperUnary(
      ast.Send node, op.UnaryOperator operator, MethodElement method, _) {
    return handleSuperMethodInvoke(
        node, method, analyzeArguments(node.arguments));
  }

  @override
  TypeInformation visitSuperMethodIncompatibleInvoke(
      ast.Send node,
      MethodElement method,
      ast.NodeList arguments,
      CallStructure callStructure,
      _) {
    return handleErroneousSuperSend(node);
  }

  // Try to find the length given to a fixed array constructor call.
  int findLength(ast.Send node) {
    ast.Node firstArgument = node.arguments.head;
    Element element = elements[firstArgument];
    ast.LiteralInt length = firstArgument.asLiteralInt();
    if (length != null) {
      return length.value;
    } else if (element != null &&
        element.isField &&
        Elements.isStaticOrTopLevelField(element)) {
      FieldElement fieldElement = element;
      if (closedWorld.fieldNeverChanges(fieldElement)) {
        ConstantValue value =
            compiler.backend.constants.getConstantValue(fieldElement.constant);
        if (value != null && value.isInt) {
          IntConstantValue intValue = value;
          return intValue.primitiveValue;
        }
      }
    }
    return null;
  }

  TypeInformation visitAwait(ast.Await node) {
    TypeInformation futureType = node.expression.accept(this);
    return inferrer.registerAwait(node, futureType);
  }

  TypeInformation visitYield(ast.Yield node) {
    TypeInformation operandType = node.expression.accept(this);
    return inferrer.registerYield(node, operandType);
  }

  TypeInformation handleTypeLiteralInvoke(ast.NodeList arguments) {
    // This is reached when users forget to put a `new` in front of a type
    // literal. The emitter will generate an actual call (even though it is
    // likely invalid), and for that it needs to have the arguments processed
    // as well.
    analyzeArguments(arguments.nodes);
    return types.dynamicType;
  }

  /// Handle constructor invocation of [constructor].
  TypeInformation handleConstructorSend(
      ast.Send node, ConstructorElement constructor) {
    ConstructorElement target = constructor.implementation;
    ArgumentsTypes arguments = analyzeArguments(node.arguments);
    if (visitingInitializers) {
      if (ast.Initializers.isConstructorRedirect(node)) {
        isConstructorRedirect = true;
      } else if (ast.Initializers.isSuperConstructorCall(node)) {
        seenSuperConstructorCall = true;
        analyzeSuperConstructorCall(constructor, arguments);
      }
    }
    // If we are looking at a new expression on a forwarding factory, we have to
    // forward the call to the effective target of the factory.
    // TODO(herhut): Remove the loop once effectiveTarget forwards to patches.
    while (target.isFactoryConstructor) {
      if (!target.isRedirectingFactory) break;
      target = target.effectiveTarget.implementation;
    }
    if (closedWorld.commonElements.isForeign(target)) {
      return handleForeignSend(node, target);
    }
    Selector selector = elements.getSelector(node);
    CallStructure callStructure = selector.callStructure;
    TypeMask mask = memberData.typeOfSend(node);
    // In erroneous code the number of arguments in the selector might not
    // match the function element.
    // TODO(polux): return nonNullEmpty and check it doesn't break anything
    if (target.isMalformed ||
        !callStructure.signatureApplies(target.parameterStructure)) {
      return types.dynamicType;
    }

    TypeInformation returnType =
        handleStaticSend(node, selector, mask, target.declaration, arguments);
    if (Elements.isGrowableListConstructorCall(
        constructor, node, closedWorld.commonElements)) {
      return inferrer.concreteTypes.putIfAbsent(
          node,
          () => types.allocateList(types.growableListType, node,
              outermostElement, types.nonNullEmpty(), 0));
    } else if (Elements.isFixedListConstructorCall(
            constructor, node, closedWorld.commonElements) ||
        Elements.isFilledListConstructorCall(
            constructor, node, closedWorld.commonElements)) {
      int length = findLength(node);
      TypeInformation elementType = Elements.isFixedListConstructorCall(
              constructor, node, closedWorld.commonElements)
          ? types.nullType
          : arguments.positional[1];

      return inferrer.concreteTypes.putIfAbsent(
          node,
          () => types.allocateList(types.fixedListType, node, outermostElement,
              elementType, length));
    } else if (Elements.isConstructorOfTypedArraySubclass(
        constructor, closedWorld)) {
      int length = findLength(node);
      MemberElement member = target.enclosingClass.lookupMember('[]');
      TypeInformation elementType = inferrer.returnTypeOfMember(member);
      return inferrer.concreteTypes.putIfAbsent(
          node,
          () => types.allocateList(types.nonNullExact(target.enclosingClass),
              node, outermostElement, elementType, length));
    } else {
      return returnType;
    }
  }

  @override
  TypeInformation bulkHandleNew(ast.NewExpression node, _) {
    Element element = elements[node.send];
    return handleConstructorSend(node.send, element);
  }

  @override
  TypeInformation errorNonConstantConstructorInvoke(
      ast.NewExpression node,
      Element element,
      ResolutionDartType type,
      ast.NodeList arguments,
      CallStructure callStructure,
      _) {
    return bulkHandleNew(node, _);
  }

  /// Handle invocation of a top level or static field or getter [element].
  TypeInformation handleStaticFieldOrGetterInvoke(
      ast.Send node, MemberElement element) {
    ArgumentsTypes arguments = analyzeArguments(node.arguments);
    Selector selector = elements.getSelector(node);
    TypeMask mask = memberData.typeOfSend(node);
    handleStaticSend(node, selector, mask, element, arguments);
    return inferrer.registerCalledClosure(
        node,
        selector,
        mask,
        inferrer.typeOfMember(element),
        outermostElement,
        arguments,
        sideEffects,
        inLoop);
  }

  /// Handle invocation of a top level or static [function].
  TypeInformation handleStaticFunctionInvoke(
      ast.Send node, MethodElement function) {
    if (closedWorld.commonElements.isForeign(function)) {
      return handleForeignSend(node, function);
    }
    ArgumentsTypes arguments = analyzeArguments(node.arguments);
    Selector selector = elements.getSelector(node);
    TypeMask mask = memberData.typeOfSend(node);
    return handleStaticSend(node, selector, mask, function, arguments);
  }

  /// Handle an static invocation of an unresolved target or with incompatible
  /// arguments to a resolved target.
  TypeInformation handleInvalidStaticInvoke(ast.Send node) {
    analyzeArguments(node.arguments);
    return types.dynamicType;
  }

  @override
  TypeInformation visitStaticFieldInvoke(ast.Send node, FieldElement field,
      ast.NodeList arguments, CallStructure callStructure, _) {
    return handleStaticFieldOrGetterInvoke(node, field);
  }

  @override
  TypeInformation visitStaticFunctionInvoke(
      ast.Send node,
      MethodElement function,
      ast.NodeList arguments,
      CallStructure callStructure,
      _) {
    return handleStaticFunctionInvoke(node, function);
  }

  @override
  TypeInformation visitStaticFunctionIncompatibleInvoke(
      ast.Send node,
      MethodElement function,
      ast.NodeList arguments,
      CallStructure callStructure,
      _) {
    return handleInvalidStaticInvoke(node);
  }

  @override
  TypeInformation visitStaticGetterInvoke(ast.Send node, GetterElement getter,
      ast.NodeList arguments, CallStructure callStructure, _) {
    return handleStaticFieldOrGetterInvoke(node, getter);
  }

  @override
  TypeInformation visitTopLevelFieldInvoke(ast.Send node, FieldElement field,
      ast.NodeList arguments, CallStructure callStructure, _) {
    return handleStaticFieldOrGetterInvoke(node, field);
  }

  @override
  TypeInformation visitTopLevelFunctionInvoke(
      ast.Send node,
      MethodElement function,
      ast.NodeList arguments,
      CallStructure callStructure,
      _) {
    return handleStaticFunctionInvoke(node, function);
  }

  @override
  TypeInformation visitTopLevelFunctionIncompatibleInvoke(
      ast.Send node,
      MethodElement function,
      ast.NodeList arguments,
      CallStructure callStructure,
      _) {
    return handleInvalidStaticInvoke(node);
  }

  @override
  TypeInformation visitTopLevelGetterInvoke(ast.Send node, GetterElement getter,
      ast.NodeList arguments, CallStructure callStructure, _) {
    return handleStaticFieldOrGetterInvoke(node, getter);
  }

  @override
  TypeInformation visitStaticSetterInvoke(ast.Send node, MethodElement setter,
      ast.NodeList arguments, CallStructure callStructure, _) {
    return handleInvalidStaticInvoke(node);
  }

  @override
  TypeInformation visitTopLevelSetterInvoke(ast.Send node, MethodElement setter,
      ast.NodeList arguments, CallStructure callStructure, _) {
    return handleInvalidStaticInvoke(node);
  }

  @override
  TypeInformation visitUnresolvedInvoke(ast.Send node, Element element,
      ast.NodeList arguments, Selector selector, _) {
    return handleInvalidStaticInvoke(node);
  }

  TypeInformation handleForeignSend(ast.Send node, Element element) {
    ArgumentsTypes arguments = analyzeArguments(node.arguments);
    Selector selector = elements.getSelector(node);
    TypeMask mask = memberData.typeOfSend(node);
    String name = element.name;
    handleStaticSend(node, selector, mask, element, arguments);
    if (name == JavaScriptBackend.JS ||
        name == JavaScriptBackend.JS_EMBEDDED_GLOBAL ||
        name == JavaScriptBackend.JS_BUILTIN) {
      native.NativeBehavior nativeBehavior = elements.getNativeData(node);
      sideEffects.add(nativeBehavior.sideEffects);
      return inferrer.typeOfNativeBehavior(nativeBehavior);
    } else if (name == 'JS_OPERATOR_AS_PREFIX' || name == 'JS_STRING_CONCAT') {
      return types.stringType;
    } else {
      sideEffects.setAllSideEffects();
      return types.dynamicType;
    }
  }

  ArgumentsTypes analyzeArguments(Link<ast.Node> arguments) {
    List positional = [];
    Map<String, TypeInformation> named;
    for (var argument in arguments) {
      ast.NamedArgument namedArgument = argument.asNamedArgument();
      if (namedArgument != null) {
        argument = namedArgument.expression;
        if (named == null) named = new Map<String, TypeInformation>();
        named[namedArgument.name.source] = argument.accept(this);
      } else {
        positional.add(argument.accept(this));
      }
      // TODO(ngeoffray): We could do better here if we knew what we
      // are calling does not expose this.
      isThisExposed = isThisExposed || argument.isThis();
    }
    return new ArgumentsTypes(positional, named);
  }

  /// Read a local variable, function or parameter.
  TypeInformation handleLocalGet(ast.Send node, LocalElement local) {
    assert(locals.use(local) != null);
    return locals.use(local);
  }

  /// Read a static or top level field.
  TypeInformation handleStaticFieldGet(ast.Send node, FieldElement field) {
    Selector selector = elements.getSelector(node);
    TypeMask mask = memberData.typeOfSend(node);
    return handleStaticSend(node, selector, mask, field, null);
  }

  /// Invoke a static or top level getter.
  TypeInformation handleStaticGetterGet(ast.Send node, GetterElement getter) {
    Selector selector = elements.getSelector(node);
    TypeMask mask = memberData.typeOfSend(node);
    return handleStaticSend(node, selector, mask, getter, null);
  }

  /// Closurize a static or top level function.
  TypeInformation handleStaticFunctionGet(
      ast.Send node, MethodElement function) {
    Selector selector = elements.getSelector(node);
    TypeMask mask = memberData.typeOfSend(node);
    return handleStaticSend(node, selector, mask, function, null);
  }

  @override
  TypeInformation visitDynamicPropertyGet(
      ast.Send node, ast.Node receiver, Name name, _) {
    return handleDynamicGet(node);
  }

  @override
  TypeInformation visitIfNotNullDynamicPropertyGet(
      ast.Send node, ast.Node receiver, Name name, _) {
    return handleDynamicGet(node);
  }

  @override
  TypeInformation visitLocalVariableGet(
      ast.Send node, LocalVariableElement variable, _) {
    return handleLocalGet(node, variable);
  }

  @override
  TypeInformation visitParameterGet(
      ast.Send node, ParameterElement parameter, _) {
    return handleLocalGet(node, parameter);
  }

  @override
  TypeInformation visitLocalFunctionGet(
      ast.Send node, LocalFunctionElement function, _) {
    return handleLocalGet(node, function);
  }

  @override
  TypeInformation visitStaticFieldGet(ast.Send node, FieldElement field, _) {
    return handleStaticFieldGet(node, field);
  }

  @override
  TypeInformation visitStaticFunctionGet(
      ast.Send node, MethodElement function, _) {
    return handleStaticFunctionGet(node, function);
  }

  @override
  TypeInformation visitStaticGetterGet(ast.Send node, GetterElement getter, _) {
    return handleStaticGetterGet(node, getter);
  }

  @override
  TypeInformation visitThisPropertyGet(ast.Send node, Name name, _) {
    return handleDynamicGet(node);
  }

  @override
  TypeInformation visitTopLevelFieldGet(ast.Send node, FieldElement field, _) {
    return handleStaticFieldGet(node, field);
  }

  @override
  TypeInformation visitTopLevelFunctionGet(
      ast.Send node, MethodElement function, _) {
    return handleStaticFunctionGet(node, function);
  }

  @override
  TypeInformation visitTopLevelGetterGet(
      ast.Send node, GetterElement getter, _) {
    return handleStaticGetterGet(node, getter);
  }

  @override
  TypeInformation visitStaticSetterGet(ast.Send node, MethodElement setter, _) {
    return types.dynamicType;
  }

  @override
  TypeInformation visitTopLevelSetterGet(
      ast.Send node, MethodElement setter, _) {
    return types.dynamicType;
  }

  @override
  TypeInformation visitUnresolvedGet(ast.Send node, Element element, _) {
    return types.dynamicType;
  }

  /// Handle .call invocation on [closure].
  TypeInformation handleCallInvoke(ast.Send node, TypeInformation closure) {
    ArgumentsTypes arguments = analyzeArguments(node.arguments);
    Selector selector = elements.getSelector(node);
    TypeMask mask = memberData.typeOfSend(node);
    return inferrer.registerCalledClosure(node, selector, mask, closure,
        outermostElement, arguments, sideEffects, inLoop);
  }

  @override
  TypeInformation visitExpressionInvoke(ast.Send node, ast.Node expression,
      ast.NodeList arguments, CallStructure callStructure, _) {
    return handleCallInvoke(node, expression.accept(this));
  }

  @override
  TypeInformation visitThisInvoke(
      ast.Send node, ast.NodeList arguments, CallStructure callStructure, _) {
    return handleCallInvoke(node, thisType);
  }

  @override
  TypeInformation visitParameterInvoke(
      ast.Send node,
      ParameterElement parameter,
      ast.NodeList arguments,
      CallStructure callStructure,
      _) {
    return handleCallInvoke(node, locals.use(parameter));
  }

  @override
  TypeInformation visitLocalVariableInvoke(
      ast.Send node,
      LocalVariableElement variable,
      ast.NodeList arguments,
      CallStructure callStructure,
      _) {
    return handleCallInvoke(node, locals.use(variable));
  }

  @override
  TypeInformation visitLocalFunctionInvoke(
      ast.Send node,
      LocalFunctionElement function,
      ast.NodeList arguments,
      CallStructure callStructure,
      _) {
    ArgumentsTypes argumentTypes = analyzeArguments(node.arguments);
    Selector selector = elements.getSelector(node);
    TypeMask mask = memberData.typeOfSend(node);
    // This only works for function statements. We need a
    // more sophisticated type system with function types to support
    // more.
    return inferrer.registerCalledMember(node, selector, mask, outermostElement,
        function.callMethod, argumentTypes, sideEffects, inLoop);
  }

  @override
  TypeInformation visitLocalFunctionIncompatibleInvoke(
      ast.Send node,
      LocalFunctionElement function,
      ast.NodeList arguments,
      CallStructure callStructure,
      _) {
    analyzeArguments(node.arguments);
    return types.dynamicType;
  }

  TypeInformation handleStaticSend(ast.Node node, Selector selector,
      TypeMask mask, MemberElement element, ArgumentsTypes arguments) {
    assert(element.isDeclaration);
    assert(!element.isFactoryConstructor ||
        !(element as ConstructorElement).isRedirectingFactory);
    // Erroneous elements may be unresolved, for example missing getters.
    if (Elements.isUnresolved(element)) return types.dynamicType;
    // TODO(herhut): should we follow redirecting constructors here? We would
    // need to pay attention if the constructor is pointing to an erroneous
    // element.
    return inferrer.registerCalledMember(node, selector, mask, outermostElement,
        element, arguments, sideEffects, inLoop);
  }

  TypeInformation handleDynamicSend(
      CallType callType,
      ast.Node node,
      Selector selector,
      TypeMask mask,
      TypeInformation receiverType,
      ArgumentsTypes arguments) {
    assert(receiverType != null);
    if (types.selectorNeedsUpdate(receiverType, mask)) {
      mask = receiverType == types.dynamicType
          ? null
          : types.newTypedSelector(receiverType, mask);
      inferrer.updateSelectorInMember(
          outermostElement, callType, node, selector, mask);
    }

    // If the receiver of the call is a local, we may know more about
    // its type by refining it with the potential targets of the
    // calls.
    ast.Send send = node.asSend();
    bool isConditional = false;
    if (send != null) {
      isConditional = send.isConditional;
      ast.Node receiver = send.receiver;
      if (receiver != null) {
        Element element = elements[receiver];
        if (Elements.isLocal(element) && !capturedVariables.contains(element)) {
          TypeInformation refinedType = types.refineReceiver(
              selector, mask, receiverType, send.isConditional);
          LocalElement local = element;
          locals.update(local, refinedType, node, local.type);
        }
      }
    }

    return inferrer.registerCalledSelector(callType, node, selector, mask,
        receiverType, outermostElement, arguments, sideEffects,
        inLoop: inLoop, isConditional: isConditional);
  }

  TypeInformation handleDynamicInvoke(ast.Send node) {
    return _handleDynamicSend(node);
  }

  TypeInformation handleDynamicGet(ast.Send node) {
    return _handleDynamicSend(node);
  }

  TypeInformation _handleDynamicSend(ast.Send node) {
    Element element = elements[node];
    TypeInformation receiverType;
    bool isCallOnThis = false;
    if (node.receiver == null) {
      if (treatAsInstanceMember(element)) {
        isCallOnThis = true;
        receiverType = thisType;
      }
    } else {
      ast.Node receiver = node.receiver;
      isCallOnThis = isThisOrSuper(receiver);
      receiverType = visit(receiver);
    }

    Selector selector = elements.getSelector(node);
    TypeMask mask = memberData.typeOfSend(node);
    if (!isThisExposed && isCallOnThis) {
      checkIfExposesThis(selector, types.newTypedSelector(receiverType, mask));
    }

    ArgumentsTypes arguments =
        node.isPropertyAccess ? null : analyzeArguments(node.arguments);
    if (selector.name == '==' || selector.name == '!=') {
      if (types.isNull(receiverType)) {
        potentiallyAddNullCheck(node, node.arguments.head);
        return types.boolType;
      } else if (types.isNull(arguments.positional[0])) {
        potentiallyAddNullCheck(node, node.receiver);
        return types.boolType;
      }
    }
    return handleDynamicSend(
        CallType.access, node, selector, mask, receiverType, arguments);
  }

  void recordReturnType(TypeInformation type) {
    MethodElement analyzedMethod = analyzedElement;
    returnType =
        inferrer.addReturnTypeForMethod(analyzedMethod, returnType, type);
  }

  TypeInformation synthesizeForwardingCall(
      Spannable node, ConstructorElement element) {
    assert(element.isDeclaration);
    MethodElement function = analyzedElement.implementation;
    FunctionSignature signature = function.functionSignature;
    FunctionSignature calleeSignature = element.functionSignature;
    if (!calleeSignature.isCompatibleWith(signature)) {
      return types.nonNullEmpty();
    }

    List<TypeInformation> unnamed = <TypeInformation>[];
    signature.forEachRequiredParameter((FormalElement _element) {
      ParameterElement element = _element;
      assert(locals.use(element) != null);
      unnamed.add(locals.use(element));
    });

    Map<String, TypeInformation> named;
    if (signature.optionalParametersAreNamed) {
      named = new Map<String, TypeInformation>();
      signature.forEachOptionalParameter((FormalElement _element) {
        ParameterElement element = _element;
        named[element.name] = locals.use(element);
      });
    } else {
      signature.forEachOptionalParameter((FormalElement _element) {
        ParameterElement element = _element;
        unnamed.add(locals.use(element));
      });
    }

    ArgumentsTypes arguments = new ArgumentsTypes(unnamed, named);
    return inferrer.registerCalledMember(node, null, null, outermostElement,
        element, arguments, sideEffects, inLoop);
  }

  TypeInformation visitRedirectingFactoryBody(ast.RedirectingFactoryBody node) {
    ConstructorElement element = elements.getRedirectingTargetConstructor(node);
    if (Elements.isMalformed(element)) {
      recordReturnType(types.dynamicType);
    } else {
      // We don't create a selector for redirecting factories, and
      // the send is just a property access. Therefore we must
      // manually create the [ArgumentsTypes] of the call, and
      // manually register [analyzedElement] as a caller of [element].
      TypeInformation mask =
          synthesizeForwardingCall(node.constructorReference, element);
      recordReturnType(mask);
    }
    locals.seenReturnOrThrow = true;
    return null;
  }

  TypeInformation visitReturn(ast.Return node) {
    ast.Node expression = node.expression;
    recordReturnType(
        expression == null ? types.nullType : expression.accept(this));
    locals.seenReturnOrThrow = true;
    initializationIsIndefinite();
    return null;
  }

  TypeInformation handleForInLoop(
      ast.ForIn node,
      TypeInformation iteratorType,
      Selector currentSelector,
      TypeMask currentMask,
      Selector moveNextSelector,
      TypeMask moveNextMask) {
    handleDynamicSend(CallType.forIn, node, moveNextSelector, moveNextMask,
        iteratorType, new ArgumentsTypes.empty());
    TypeInformation currentType = handleDynamicSend(CallType.forIn, node,
        currentSelector, currentMask, iteratorType, new ArgumentsTypes.empty());

    if (node.expression.isThis()) {
      // Any reasonable implementation of an iterator would expose
      // this, so we play it safe and assume it will.
      isThisExposed = true;
    }

    ast.Node identifier = node.declaredIdentifier;
    Element element = elements.getForInVariable(node);
    Selector selector = elements.getSelector(identifier);
    TypeMask mask = memberData.typeOfSend(identifier.asSend());

    TypeInformation receiverType;
    if (element != null && element.isInstanceMember) {
      receiverType = thisType;
    } else {
      receiverType = types.dynamicType;
    }

    handlePlainAssignment(identifier, element, selector, mask, receiverType,
        currentType, node.expression);
    return handleLoop(node, () {
      visit(node.body);
    });
  }

  TypeInformation visitAsyncForIn(ast.AsyncForIn node) {
    TypeInformation expressionType = visit(node.expression);

    Selector currentSelector = Selectors.current;
    TypeMask currentMask = memberData.typeOfIteratorCurrent(node);
    Selector moveNextSelector = Selectors.moveNext;
    TypeMask moveNextMask = memberData.typeOfIteratorMoveNext(node);

    ConstructorElement ctor =
        closedWorld.commonElements.streamIteratorConstructor;

    /// Synthesize a call to the [StreamIterator] constructor.
    TypeInformation iteratorType = handleStaticSend(
        node, null, null, ctor, new ArgumentsTypes([expressionType], null));

    return handleForInLoop(node, iteratorType, currentSelector, currentMask,
        moveNextSelector, moveNextMask);
  }

  TypeInformation visitSyncForIn(ast.SyncForIn node) {
    TypeInformation expressionType = visit(node.expression);
    Selector iteratorSelector = Selectors.iterator;
    TypeMask iteratorMask = memberData.typeOfIterator(node);
    Selector currentSelector = Selectors.current;
    TypeMask currentMask = memberData.typeOfIteratorCurrent(node);
    Selector moveNextSelector = Selectors.moveNext;
    TypeMask moveNextMask = memberData.typeOfIteratorMoveNext(node);

    TypeInformation iteratorType = handleDynamicSend(
        CallType.forIn,
        node,
        iteratorSelector,
        iteratorMask,
        expressionType,
        new ArgumentsTypes.empty());

    return handleForInLoop(node, iteratorType, currentSelector, currentMask,
        moveNextSelector, moveNextMask);
  }
}
