Move DDC to analyzer-based checker
diff --git a/lib/src/checker/checker.dart b/lib/src/checker/checker.dart
index 0af5675..10bae9c 100644
--- a/lib/src/checker/checker.dart
+++ b/lib/src/checker/checker.dart
@@ -4,945 +4,4 @@
 
 library dev_compiler.src.checker.checker;
 
-import 'package:analyzer/analyzer.dart';
-import 'package:analyzer/src/generated/ast.dart';
-import 'package:analyzer/src/generated/element.dart';
-import 'package:analyzer/src/generated/scanner.dart' show Token, TokenType;
-
-import '../info.dart';
-import '../utils.dart' show getMemberType;
-import 'rules.dart';
-
-/// Checks for overriding declarations of fields and methods. This is used to
-/// check overrides between classes and superclasses, interfaces, and mixin
-/// applications.
-class _OverrideChecker {
-  bool _failure = false;
-  final TypeRules _rules;
-  final AnalysisErrorListener _reporter;
-
-  _OverrideChecker(this._rules, this._reporter);
-
-  void check(ClassDeclaration node) {
-    if (node.element.type.isObject) return;
-    _checkSuperOverrides(node);
-    _checkMixinApplicationOverrides(node);
-    _checkAllInterfaceOverrides(node);
-  }
-
-  /// Check overrides from mixin applications themselves. For example, in:
-  ///
-  ///      A extends B with E, F
-  ///
-  ///  we check:
-  ///
-  ///      B & E against B (equivalently how E overrides B)
-  ///      B & E & F against B & E (equivalently how F overrides both B and E)
-  void _checkMixinApplicationOverrides(ClassDeclaration node) {
-    var type = node.element.type;
-    var parent = type.superclass;
-    var mixins = type.mixins;
-
-    // Check overrides from applying mixins
-    for (int i = 0; i < mixins.length; i++) {
-      var seen = new Set<String>();
-      var current = mixins[i];
-      var errorLocation = node.withClause.mixinTypes[i];
-      for (int j = i - 1; j >= 0; j--) {
-        _checkIndividualOverridesFromType(
-            current, mixins[j], errorLocation, seen);
-      }
-      _checkIndividualOverridesFromType(current, parent, errorLocation, seen);
-    }
-  }
-
-  /// Check overrides between a class and its superclasses and mixins. For
-  /// example, in:
-  ///
-  ///      A extends B with E, F
-  ///
-  /// we check A against B, B super classes, E, and F.
-  ///
-  /// Internally we avoid reporting errors twice and we visit classes bottom up
-  /// to ensure we report the most immediate invalid override first. For
-  /// example, in the following code we'll report that `Test` has an invalid
-  /// override with respect to `Parent` (as opposed to an invalid override with
-  /// respect to `Grandparent`):
-  ///
-  ///     class Grandparent {
-  ///         m(A a) {}
-  ///     }
-  ///     class Parent extends Grandparent {
-  ///         m(A a) {}
-  ///     }
-  ///     class Test extends Parent {
-  ///         m(B a) {} // invalid override
-  ///     }
-  void _checkSuperOverrides(ClassDeclaration node) {
-    var seen = new Set<String>();
-    var current = node.element.type;
-    var visited = new Set<InterfaceType>();
-    do {
-      visited.add(current);
-      current.mixins.reversed
-          .forEach((m) => _checkIndividualOverridesFromClass(node, m, seen));
-      _checkIndividualOverridesFromClass(node, current.superclass, seen);
-      current = current.superclass;
-    } while (!current.isObject && !visited.contains(current));
-  }
-
-  /// Checks that implementations correctly override all reachable interfaces.
-  /// In particular, we need to check these overrides for the definitions in
-  /// the class itself and each its superclasses. If a superclass is not
-  /// abstract, then we can skip its transitive interfaces. For example, in:
-  ///
-  ///     B extends C implements G
-  ///     A extends B with E, F implements H, I
-  ///
-  /// we check:
-  ///
-  ///     C against G, H, and I
-  ///     B against G, H, and I
-  ///     E against H and I // no check against G because B is a concrete class
-  ///     F against H and I
-  ///     A against H and I
-  void _checkAllInterfaceOverrides(ClassDeclaration node) {
-    var seen = new Set<String>();
-    // Helper function to collect all reachable interfaces.
-    find(InterfaceType interfaceType, Set result) {
-      if (interfaceType == null || interfaceType.isObject) return;
-      if (result.contains(interfaceType)) return;
-      result.add(interfaceType);
-      find(interfaceType.superclass, result);
-      interfaceType.mixins.forEach((i) => find(i, result));
-      interfaceType.interfaces.forEach((i) => find(i, result));
-    }
-
-    // Check all interfaces reachable from the `implements` clause in the
-    // current class against definitions here and in superclasses.
-    var localInterfaces = new Set<InterfaceType>();
-    var type = node.element.type;
-    type.interfaces.forEach((i) => find(i, localInterfaces));
-    _checkInterfacesOverrides(node, localInterfaces, seen,
-        includeParents: true);
-
-    // Check also how we override locally the interfaces from parent classes if
-    // the parent class is abstract. Otherwise, these will be checked as
-    // overrides on the concrete superclass.
-    var superInterfaces = new Set<InterfaceType>();
-    var parent = type.superclass;
-    // TODO(sigmund): we don't seem to be reporting the analyzer error that a
-    // non-abstract class is not implementing an interface. See
-    // https://github.com/dart-lang/dart-dev-compiler/issues/25
-    while (parent != null && parent.element.isAbstract) {
-      parent.interfaces.forEach((i) => find(i, superInterfaces));
-      parent = parent.superclass;
-    }
-    _checkInterfacesOverrides(node, superInterfaces, seen,
-        includeParents: false);
-  }
-
-  /// Checks that [cls] and its super classes (including mixins) correctly
-  /// overrides each interface in [interfaces]. If [includeParents] is false,
-  /// then mixins are still checked, but the base type and it's transitive
-  /// supertypes are not.
-  ///
-  /// [cls] can be either a [ClassDeclaration] or a [InterfaceType]. For
-  /// [ClassDeclaration]s errors are reported on the member that contains the
-  /// invalid override, for [InterfaceType]s we use [errorLocation] instead.
-  void _checkInterfacesOverrides(
-      cls, Iterable<InterfaceType> interfaces, Set<String> seen,
-      {Set<InterfaceType> visited,
-      bool includeParents: true,
-      AstNode errorLocation}) {
-    var node = cls is ClassDeclaration ? cls : null;
-    var type = cls is InterfaceType ? cls : node.element.type;
-
-    if (visited == null) {
-      visited = new Set<InterfaceType>();
-    } else if (visited.contains(type)) {
-      // Malformed type.
-      return;
-    } else {
-      visited.add(type);
-    }
-
-    // Check direct overrides on [type]
-    for (var interfaceType in interfaces) {
-      if (node != null) {
-        _checkIndividualOverridesFromClass(node, interfaceType, seen);
-      } else {
-        _checkIndividualOverridesFromType(
-            type, interfaceType, errorLocation, seen);
-      }
-    }
-
-    // Check overrides from its mixins
-    for (int i = 0; i < type.mixins.length; i++) {
-      var loc =
-          errorLocation != null ? errorLocation : node.withClause.mixinTypes[i];
-      for (var interfaceType in interfaces) {
-        // We copy [seen] so we can report separately if more than one mixin or
-        // the base class have an invalid override.
-        _checkIndividualOverridesFromType(
-            type.mixins[i], interfaceType, loc, new Set.from(seen));
-      }
-    }
-
-    // Check overrides from its superclasses
-    if (includeParents) {
-      var parent = type.superclass;
-      if (parent.isObject) return;
-      var loc = errorLocation != null ? errorLocation : node.extendsClause;
-      // No need to copy [seen] here because we made copies above when reporting
-      // errors on mixins.
-      _checkInterfacesOverrides(parent, interfaces, seen,
-          visited: visited, includeParents: true, errorLocation: loc);
-    }
-  }
-
-  /// Check that individual methods and fields in [subType] correctly override
-  /// the declarations in [baseType].
-  ///
-  /// The [errorLocation] node indicates where errors are reported, see
-  /// [_checkSingleOverride] for more details.
-  ///
-  /// The set [seen] is used to avoid reporting overrides more than once. It
-  /// is used when invoking this function multiple times when checking several
-  /// types in a class hierarchy. Errors are reported only the first time an
-  /// invalid override involving a specific member is encountered.
-  _checkIndividualOverridesFromType(InterfaceType subType,
-      InterfaceType baseType, AstNode errorLocation, Set<String> seen) {
-    void checkHelper(ExecutableElement e) {
-      if (e.isStatic) return;
-      if (seen.contains(e.name)) return;
-      if (_checkSingleOverride(e, baseType, null, errorLocation)) {
-        seen.add(e.name);
-      }
-    }
-    subType.methods.forEach(checkHelper);
-    subType.accessors.forEach(checkHelper);
-  }
-
-  /// Check that individual methods and fields in [subType] correctly override
-  /// the declarations in [baseType].
-  ///
-  /// The [errorLocation] node indicates where errors are reported, see
-  /// [_checkSingleOverride] for more details.
-  _checkIndividualOverridesFromClass(
-      ClassDeclaration node, InterfaceType baseType, Set<String> seen) {
-    for (var member in node.members) {
-      if (member is ConstructorDeclaration) continue;
-      if (member is FieldDeclaration) {
-        if (member.isStatic) continue;
-        for (var variable in member.fields.variables) {
-          var element = variable.element as PropertyInducingElement;
-          var name = element.name;
-          if (seen.contains(name)) continue;
-          var getter = element.getter;
-          var setter = element.setter;
-          bool found = _checkSingleOverride(getter, baseType, variable, member);
-          if (!variable.isFinal &&
-              !variable.isConst &&
-              _checkSingleOverride(setter, baseType, variable, member)) {
-            found = true;
-          }
-          if (found) seen.add(name);
-        }
-      } else {
-        if ((member as MethodDeclaration).isStatic) continue;
-        var method = (member as MethodDeclaration).element;
-        if (seen.contains(method.name)) continue;
-        if (_checkSingleOverride(method, baseType, member, member)) {
-          seen.add(method.name);
-        }
-      }
-    }
-  }
-
-  /// Checks that [element] correctly overrides its corresponding member in
-  /// [type]. Returns `true` if an override was found, that is, if [element] has
-  /// a corresponding member in [type] that it overrides.
-  ///
-  /// The [errorLocation] is a node where the error is reported. For example, a
-  /// bad override of a method in a class with respect to its superclass is
-  /// reported directly at the method declaration. However, invalid overrides
-  /// from base classes to interfaces, mixins to the base they are applied to,
-  /// or mixins to interfaces are reported at the class declaration, since the
-  /// base class or members on their own were not incorrect, only combining them
-  /// with the interface was problematic. For example, these are example error
-  /// locations in these cases:
-  ///
-  ///     error: base class introduces an invalid override. The type of B.foo is
-  ///     not a subtype of E.foo:
-  ///       class A extends B implements E { ... }
-  ///               ^^^^^^^^^
-  ///
-  ///     error: mixin introduces an invalid override. The type of C.foo is not
-  ///     a subtype of E.foo:
-  ///       class A extends B with C implements E { ... }
-  ///                              ^
-  ///
-  /// When checking for overrides from a type and it's super types, [node] is
-  /// the AST node that defines [element]. This is used to determine whether the
-  /// type of the element could be inferred from the types in the super classes.
-  bool _checkSingleOverride(ExecutableElement element, InterfaceType type,
-      AstNode node, AstNode errorLocation) {
-    assert(!element.isStatic);
-
-    FunctionType subType = _rules.elementType(element);
-    // TODO(vsm): Test for generic
-    FunctionType baseType = getMemberType(type, element);
-
-    if (baseType == null) return false;
-    if (!_rules.isAssignable(subType, baseType)) {
-      // See whether non-assignable cases fit one of our common patterns:
-      //
-      // Common pattern 1: Inferable return type (on getters and methods)
-      //   class A {
-      //     int get foo => ...;
-      //     String toString() { ... }
-      //   }
-      //   class B extends A {
-      //     get foo => e; // no type specified.
-      //     toString() { ... } // no return type specified.
-      //   }
-      _recordMessage(new InvalidMethodOverride(
-          errorLocation, element, type, subType, baseType));
-    }
-    return true;
-  }
-
-  void _recordMessage(StaticInfo info) {
-    if (info == null) return;
-    var error = info.toAnalysisError();
-    if (error.errorCode.errorSeverity == ErrorSeverity.ERROR) _failure = true;
-    _reporter.onError(error);
-  }
-}
-
-/// Checks the body of functions and properties.
-class CodeChecker extends RecursiveAstVisitor {
-  final TypeRules rules;
-  final AnalysisErrorListener reporter;
-  final _OverrideChecker _overrideChecker;
-  bool _failure = false;
-  bool get failure => _failure || _overrideChecker._failure;
-
-  void reset() {
-    _failure = false;
-    _overrideChecker._failure = false;
-  }
-
-  CodeChecker(TypeRules rules, AnalysisErrorListener reporter)
-      : rules = rules,
-        reporter = reporter,
-        _overrideChecker = new _OverrideChecker(rules, reporter);
-
-  @override
-  void visitComment(Comment node) {
-    // skip, no need to do typechecking inside comments (they may contain
-    // comment references which would require resolution).
-  }
-
-  @override
-  void visitClassDeclaration(ClassDeclaration node) {
-    _overrideChecker.check(node);
-    super.visitClassDeclaration(node);
-  }
-
-  @override
-  void visitAssignmentExpression(AssignmentExpression node) {
-    var token = node.operator;
-    if (token.type != TokenType.EQ) {
-      _checkCompoundAssignment(node);
-    } else {
-      DartType staticType = _getStaticType(node.leftHandSide);
-      checkAssignment(node.rightHandSide, staticType);
-    }
-    node.visitChildren(this);
-  }
-
-  /// Check constructor declaration to ensure correct super call placement.
-  @override
-  void visitConstructorDeclaration(ConstructorDeclaration node) {
-    node.visitChildren(this);
-
-    final init = node.initializers;
-    for (int i = 0, last = init.length - 1; i < last; i++) {
-      final node = init[i];
-      if (node is SuperConstructorInvocation) {
-        _recordMessage(new InvalidSuperInvocation(node));
-      }
-    }
-  }
-
-  @override
-  void visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
-    var field = node.fieldName;
-    var element = field.staticElement;
-    DartType staticType = rules.elementType(element);
-    checkAssignment(node.expression, staticType);
-    node.visitChildren(this);
-  }
-
-  @override
-  void visitForEachStatement(ForEachStatement node) {
-    // Check that the expression is an Iterable.
-    var expr = node.iterable;
-    var iterableType = node.awaitKeyword != null
-        ? rules.provider.streamType
-        : rules.provider.iterableType;
-    var loopVariable = node.identifier != null
-        ? node.identifier
-        : node.loopVariable?.identifier;
-    if (loopVariable != null) {
-      var iteratorType = loopVariable.staticType;
-      var checkedType = iterableType.substitute4([iteratorType]);
-      checkAssignment(expr, checkedType);
-    }
-    node.visitChildren(this);
-  }
-
-  @override
-  void visitForStatement(ForStatement node) {
-    if (node.condition != null) {
-      checkBoolean(node.condition);
-    }
-    node.visitChildren(this);
-  }
-
-  @override
-  void visitIfStatement(IfStatement node) {
-    checkBoolean(node.condition);
-    node.visitChildren(this);
-  }
-
-  @override
-  void visitDoStatement(DoStatement node) {
-    checkBoolean(node.condition);
-    node.visitChildren(this);
-  }
-
-  @override
-  void visitWhileStatement(WhileStatement node) {
-    checkBoolean(node.condition);
-    node.visitChildren(this);
-  }
-
-  @override
-  void visitSwitchStatement(SwitchStatement node) {
-    // SwitchStatement defines a boolean conversion to check the result of the
-    // case value == the switch value, but in dev_compiler we require a boolean
-    // return type from an overridden == operator (because Object.==), so
-    // checking in SwitchStatement shouldn't be necessary.
-    node.visitChildren(this);
-  }
-
-  @override
-  void visitListLiteral(ListLiteral node) {
-    var type = rules.provider.dynamicType;
-    if (node.typeArguments != null) {
-      var targs = node.typeArguments.arguments;
-      if (targs.length > 0) type = targs[0].type;
-    }
-    var elements = node.elements;
-    for (int i = 0; i < elements.length; i++) {
-      checkArgument(elements[i], type);
-    }
-    super.visitListLiteral(node);
-  }
-
-  @override
-  void visitMapLiteral(MapLiteral node) {
-    var ktype = rules.provider.dynamicType;
-    var vtype = rules.provider.dynamicType;
-    if (node.typeArguments != null) {
-      var targs = node.typeArguments.arguments;
-      if (targs.length > 0) ktype = targs[0].type;
-      if (targs.length > 1) vtype = targs[1].type;
-    }
-    var entries = node.entries;
-    for (int i = 0; i < entries.length; i++) {
-      var entry = entries[i];
-      checkArgument(entry.key, ktype);
-      checkArgument(entry.value, vtype);
-    }
-    super.visitMapLiteral(node);
-  }
-
-  // Check invocations
-  void checkArgumentList(ArgumentList node, FunctionType type) {
-    NodeList<Expression> list = node.arguments;
-    int len = list.length;
-    for (int i = 0; i < len; ++i) {
-      Expression arg = list[i];
-      ParameterElement element = arg.staticParameterElement;
-      if (element == null) {
-        if (type.parameters.length < len) {
-          // We found an argument mismatch, the analyzer will report this too,
-          // so no need to insert an error for this here.
-          continue;
-        }
-        element = type.parameters[i];
-        // TODO(vsm): When can this happen?
-        assert(element != null);
-      }
-      DartType expectedType = rules.elementType(element);
-      if (expectedType == null) expectedType = rules.provider.dynamicType;
-      checkArgument(arg, expectedType);
-    }
-  }
-
-  void checkArgument(Expression arg, DartType expectedType) {
-    // Preserve named argument structure, so their immediate parent is the
-    // method invocation.
-    if (arg is NamedExpression) {
-      arg = (arg as NamedExpression).expression;
-    }
-    checkAssignment(arg, expectedType);
-  }
-
-  void checkFunctionApplication(
-      Expression node, Expression f, ArgumentList list) {
-    if (rules.isDynamicCall(f)) {
-      // If f is Function and this is a method invocation, we should have
-      // gotten an analyzer error, so no need to issue another error.
-      _recordDynamicInvoke(node, f);
-    } else {
-      checkArgumentList(list, rules.getTypeAsCaller(f));
-    }
-  }
-
-  @override
-  visitMethodInvocation(MethodInvocation node) {
-    var target = node.realTarget;
-    if (rules.isDynamicTarget(target) &&
-        !_isObjectMethod(node, node.methodName)) {
-      _recordDynamicInvoke(node, target);
-
-      // Mark the tear-off as being dynamic, too. This lets us distinguish
-      // cases like:
-      //
-      //     dynamic d;
-      //     d.someMethod(...); // the whole method call must be a dynamic send.
-      //
-      // ... from case like:
-      //
-      //     SomeType s;
-      //     s.someDynamicField(...); // static get, followed by dynamic call.
-      //
-      // The first case is handled here, the second case is handled below when
-      // we call [checkFunctionApplication].
-      DynamicInvoke.set(node.methodName, true);
-    } else {
-      checkFunctionApplication(node, node.methodName, node.argumentList);
-    }
-    node.visitChildren(this);
-  }
-
-  @override
-  void visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
-    checkFunctionApplication(node, node.function, node.argumentList);
-    node.visitChildren(this);
-  }
-
-  @override
-  void visitRedirectingConstructorInvocation(
-      RedirectingConstructorInvocation node) {
-    var type = node.staticElement.type;
-    checkArgumentList(node.argumentList, type);
-    node.visitChildren(this);
-  }
-
-  @override
-  void visitSuperConstructorInvocation(SuperConstructorInvocation node) {
-    var element = node.staticElement;
-    if (element == null) {
-      _recordMessage(new MissingTypeError(node));
-    } else {
-      var type = node.staticElement.type;
-      checkArgumentList(node.argumentList, type);
-    }
-    node.visitChildren(this);
-  }
-
-  void _checkReturnOrYield(Expression expression, AstNode node,
-      {bool yieldStar: false}) {
-    var body = node.getAncestor((n) => n is FunctionBody);
-    var type = rules.getExpectedReturnType(body, yieldStar: yieldStar);
-    if (type == null) {
-      // We have a type mismatch: the async/async*/sync* modifier does
-      // not match the return or yield type.  We should have already gotten an
-      // analyzer error in this case.
-      return;
-    }
-    // TODO(vsm): Enforce void or dynamic (to void?) when expression is null.
-    if (expression != null) checkAssignment(expression, type);
-  }
-
-  @override
-  void visitExpressionFunctionBody(ExpressionFunctionBody node) {
-    _checkReturnOrYield(node.expression, node);
-    node.visitChildren(this);
-  }
-
-  @override
-  void visitReturnStatement(ReturnStatement node) {
-    _checkReturnOrYield(node.expression, node);
-    node.visitChildren(this);
-  }
-
-  @override
-  void visitYieldStatement(YieldStatement node) {
-    _checkReturnOrYield(node.expression, node, yieldStar: node.star != null);
-    node.visitChildren(this);
-  }
-
-  @override
-  void visitPropertyAccess(PropertyAccess node) {
-    var target = node.realTarget;
-    if (rules.isDynamicTarget(target) &&
-        !_isObjectProperty(target, node.propertyName)) {
-      _recordDynamicInvoke(node, target);
-    }
-    node.visitChildren(this);
-  }
-
-  @override
-  void visitPrefixedIdentifier(PrefixedIdentifier node) {
-    final target = node.prefix;
-    if (rules.isDynamicTarget(target) &&
-        !_isObjectProperty(target, node.identifier)) {
-      _recordDynamicInvoke(node, target);
-    }
-    node.visitChildren(this);
-  }
-
-  @override
-  void visitDefaultFormalParameter(DefaultFormalParameter node) {
-    // Check that defaults have the proper subtype.
-    var parameter = node.parameter;
-    var parameterType = rules.elementType(parameter.element);
-    assert(parameterType != null);
-    var defaultValue = node.defaultValue;
-    if (defaultValue != null) {
-      checkAssignment(defaultValue, parameterType);
-    }
-
-    node.visitChildren(this);
-  }
-
-  @override
-  void visitFieldFormalParameter(FieldFormalParameter node) {
-    var element = node.element;
-    var typeName = node.type;
-    if (typeName != null) {
-      var type = rules.elementType(element);
-      var fieldElement =
-          node.identifier.staticElement as FieldFormalParameterElement;
-      var fieldType = rules.elementType(fieldElement.field);
-      if (!rules.isSubTypeOf(type, fieldType)) {
-        var staticInfo =
-            new InvalidParameterDeclaration(rules, node, fieldType);
-        _recordMessage(staticInfo);
-      }
-    }
-    node.visitChildren(this);
-  }
-
-  @override
-  void visitInstanceCreationExpression(InstanceCreationExpression node) {
-    var arguments = node.argumentList;
-    var element = node.staticElement;
-    if (element != null) {
-      var type = rules.elementType(node.staticElement);
-      checkArgumentList(arguments, type);
-    } else {
-      _recordMessage(new MissingTypeError(node));
-    }
-    node.visitChildren(this);
-  }
-
-  @override
-  void visitVariableDeclarationList(VariableDeclarationList node) {
-    TypeName type = node.type;
-    if (type == null) {
-      // No checks are needed when the type is var. Although internally the
-      // typing rules may have inferred a more precise type for the variable
-      // based on the initializer.
-    } else {
-      var dartType = getType(type);
-      for (VariableDeclaration variable in node.variables) {
-        var initializer = variable.initializer;
-        if (initializer != null) {
-          checkAssignment(initializer, dartType);
-        }
-      }
-    }
-    node.visitChildren(this);
-  }
-
-  void _checkRuntimeTypeCheck(AstNode node, TypeName typeName) {
-    var type = getType(typeName);
-    if (!rules.isGroundType(type)) {
-      _recordMessage(new NonGroundTypeCheckInfo(node, type));
-    }
-  }
-
-  @override
-  void visitAsExpression(AsExpression node) {
-    // We could do the same check as the IsExpression below, but that is
-    // potentially too conservative.  Instead, at runtime, we must fail hard
-    // if the Dart as and the DDC as would return different values.
-    node.visitChildren(this);
-  }
-
-  @override
-  void visitIsExpression(IsExpression node) {
-    _checkRuntimeTypeCheck(node, node.type);
-    node.visitChildren(this);
-  }
-
-  @override
-  void visitPrefixExpression(PrefixExpression node) {
-    if (node.operator.type == TokenType.BANG) {
-      checkBoolean(node.operand);
-    } else {
-      _checkUnary(node);
-    }
-    node.visitChildren(this);
-  }
-
-  @override
-  void visitPostfixExpression(PostfixExpression node) {
-    _checkUnary(node);
-    node.visitChildren(this);
-  }
-
-  void _checkUnary(/*PrefixExpression|PostfixExpression*/ node) {
-    var op = node.operator;
-    if (op.isUserDefinableOperator ||
-        op.type == TokenType.PLUS_PLUS ||
-        op.type == TokenType.MINUS_MINUS) {
-      if (rules.isDynamicTarget(node.operand)) {
-        _recordDynamicInvoke(node, node.operand);
-      }
-      // For ++ and --, even if it is not dynamic, we still need to check
-      // that the user defined method accepts an `int` as the RHS.
-      // We assume Analyzer has done this already.
-    }
-  }
-
-  @override
-  void visitBinaryExpression(BinaryExpression node) {
-    var op = node.operator;
-    if (op.isUserDefinableOperator) {
-      if (rules.isDynamicTarget(node.leftOperand)) {
-        // Dynamic invocation
-        // TODO(vsm): Move this logic to the resolver?
-        if (op.type != TokenType.EQ_EQ && op.type != TokenType.BANG_EQ) {
-          _recordDynamicInvoke(node, node.leftOperand);
-        }
-      } else {
-        var element = node.staticElement;
-        // Method invocation.
-        if (element is MethodElement) {
-          var type = element.type;
-          // Analyzer should enforce number of parameter types, but check in
-          // case we have erroneous input.
-          if (type.normalParameterTypes.isNotEmpty) {
-            checkArgument(node.rightOperand, type.normalParameterTypes[0]);
-          }
-        } else {
-          // TODO(vsm): Assert that the analyzer found an error here?
-        }
-      }
-    } else {
-      // Non-method operator.
-      switch (op.type) {
-        case TokenType.AMPERSAND_AMPERSAND:
-        case TokenType.BAR_BAR:
-          checkBoolean(node.leftOperand);
-          checkBoolean(node.rightOperand);
-          break;
-        case TokenType.BANG_EQ:
-          break;
-        case TokenType.QUESTION_QUESTION:
-          break;
-        default:
-          assert(false);
-      }
-    }
-    node.visitChildren(this);
-  }
-
-  @override
-  void visitConditionalExpression(ConditionalExpression node) {
-    checkBoolean(node.condition);
-    node.visitChildren(this);
-  }
-
-  @override
-  void visitIndexExpression(IndexExpression node) {
-    var target = node.realTarget;
-    if (rules.isDynamicTarget(target)) {
-      _recordDynamicInvoke(node, target);
-    } else {
-      var element = node.staticElement;
-      if (element is MethodElement) {
-        var type = element.type;
-        // Analyzer should enforce number of parameter types, but check in
-        // case we have erroneous input.
-        if (type.normalParameterTypes.isNotEmpty) {
-          checkArgument(node.index, type.normalParameterTypes[0]);
-        }
-      } else {
-        // TODO(vsm): Assert that the analyzer found an error here?
-      }
-    }
-    node.visitChildren(this);
-  }
-
-  DartType getType(TypeName name) {
-    return (name == null) ? rules.provider.dynamicType : name.type;
-  }
-
-  /// Analyzer checks boolean conversions, but we need to check too, because
-  /// it uses the default assignability rules that allow `dynamic` and `Object`
-  /// to be assigned to bool with no message.
-  void checkBoolean(Expression expr) =>
-      checkAssignment(expr, rules.provider.boolType);
-
-  void checkAssignment(Expression expr, DartType type) {
-    if (expr is ParenthesizedExpression) {
-      checkAssignment(expr.expression, type);
-    } else {
-      _recordMessage(rules.checkAssignment(expr, type));
-    }
-  }
-
-  DartType _specializedBinaryReturnType(
-      TokenType op, DartType t1, DartType t2, DartType normalReturnType) {
-    // This special cases binary return types as per 16.26 and 16.27 of the
-    // Dart language spec.
-    switch (op) {
-      case TokenType.PLUS:
-      case TokenType.MINUS:
-      case TokenType.STAR:
-      case TokenType.TILDE_SLASH:
-      case TokenType.PERCENT:
-      case TokenType.PLUS_EQ:
-      case TokenType.MINUS_EQ:
-      case TokenType.STAR_EQ:
-      case TokenType.TILDE_SLASH_EQ:
-      case TokenType.PERCENT_EQ:
-        if (t1 == rules.provider.intType &&
-            t2 == rules.provider.intType) return t1;
-        if (t1 == rules.provider.doubleType &&
-            t2 == rules.provider.doubleType) return t1;
-        // This particular combo is not spelled out in the spec, but all
-        // implementations and analyzer seem to follow this.
-        if (t1 == rules.provider.doubleType &&
-            t2 == rules.provider.intType) return t1;
-    }
-    return normalReturnType;
-  }
-
-  void _checkCompoundAssignment(AssignmentExpression expr) {
-    var op = expr.operator.type;
-    assert(op.isAssignmentOperator && op != TokenType.EQ);
-    var methodElement = expr.staticElement;
-    if (methodElement == null) {
-      // Dynamic invocation
-      _recordDynamicInvoke(expr, expr.leftHandSide);
-    } else {
-      // Sanity check the operator
-      assert(methodElement.isOperator);
-      var functionType = methodElement.type;
-      var paramTypes = functionType.normalParameterTypes;
-      assert(paramTypes.length == 1);
-      assert(functionType.namedParameterTypes.isEmpty);
-      assert(functionType.optionalParameterTypes.isEmpty);
-
-      // Check the lhs type
-      var staticInfo;
-      var rhsType = _getStaticType(expr.rightHandSide);
-      var lhsType = _getStaticType(expr.leftHandSide);
-      var returnType = _specializedBinaryReturnType(
-          op, lhsType, rhsType, functionType.returnType);
-
-      if (!rules.isSubTypeOf(returnType, lhsType)) {
-        final numType = rules.provider.numType;
-        // Try to fix up the numerical case if possible.
-        if (rules.isSubTypeOf(lhsType, numType) &&
-            rules.isSubTypeOf(lhsType, rhsType)) {
-          // This is also slightly different from spec, but allows us to keep
-          // compound operators in the int += num and num += dynamic cases.
-          staticInfo = DownCast.create(
-              rules, expr.rightHandSide, Coercion.cast(rhsType, lhsType));
-          rhsType = lhsType;
-        } else {
-          // Static type error
-          staticInfo = new StaticTypeError(rules, expr, lhsType);
-        }
-        _recordMessage(staticInfo);
-      }
-
-      // Check the rhs type
-      if (staticInfo is! CoercionInfo) {
-        var paramType = paramTypes.first;
-        staticInfo = rules.checkAssignment(expr.rightHandSide, paramType);
-        _recordMessage(staticInfo);
-      }
-    }
-  }
-
-  bool _isObjectGetter(Expression target, SimpleIdentifier id) {
-    PropertyAccessorElement element =
-        rules.provider.objectType.element.getGetter(id.name);
-    return (element != null && !element.isStatic);
-  }
-
-  bool _isObjectMethod(Expression target, SimpleIdentifier id) {
-    MethodElement element =
-        rules.provider.objectType.element.getMethod(id.name);
-    return (element != null && !element.isStatic);
-  }
-
-  bool _isObjectProperty(Expression target, SimpleIdentifier id) {
-    return _isObjectGetter(target, id) || _isObjectMethod(target, id);
-  }
-
-  DartType _getStaticType(Expression expr) {
-    var type = expr.staticType;
-    if (type == null) {
-      reporter.onError(new MissingTypeError(expr).toAnalysisError());
-    }
-    return type ?? rules.provider.dynamicType;
-  }
-
-  void _recordDynamicInvoke(AstNode node, AstNode target) {
-    reporter.onError(new DynamicInvoke(rules, node).toAnalysisError());
-    // TODO(jmesserly): we may eventually want to record if the whole operation
-    // (node) was dynamic, rather than the target, but this is an easier fit
-    // with what we used to do.
-    DynamicInvoke.set(target, true);
-  }
-
-  void _recordMessage(StaticInfo info) {
-    if (info == null) return;
-    var error = info.toAnalysisError();
-    if (error.errorCode.errorSeverity == ErrorSeverity.ERROR) _failure = true;
-    reporter.onError(error);
-
-    if (info is CoercionInfo) {
-      // TODO(jmesserly): if we're run again on the same AST, we'll produce the
-      // same annotations. This should be harmless. This might go away once
-      // CodeChecker is integrated better with analyzer, as it will know that
-      // checking has already been performed.
-      // assert(CoercionInfo.get(info.node) == null);
-      CoercionInfo.set(info.node, info);
-    }
-  }
-}
+export 'package:analyzer/src/task/strong/checker.dart';
diff --git a/lib/src/checker/resolver.dart b/lib/src/checker/resolver.dart
index f05998e..1e141cf 100644
--- a/lib/src/checker/resolver.dart
+++ b/lib/src/checker/resolver.dart
@@ -19,6 +19,7 @@
 
 import '../../strong_mode.dart' show StrongModeOptions;
 import '../utils.dart';
+import 'rules.dart';
 
 final _log = new logger.Logger('dev_compiler.src.resolver');
 
diff --git a/lib/src/checker/rules.dart b/lib/src/checker/rules.dart
index f4d35bc..eebfcac 100644
--- a/lib/src/checker/rules.dart
+++ b/lib/src/checker/rules.dart
@@ -4,731 +4,4 @@
 
 library dev_compiler.src.checker.rules;
 
-import 'package:analyzer/src/generated/ast.dart';
-import 'package:analyzer/src/generated/element.dart';
-import 'package:analyzer/src/generated/resolver.dart';
-
-import '../../strong_mode.dart' show StrongModeOptions;
-import '../info.dart';
-import '../utils.dart' as utils;
-
-class TypeRules {
-  final TypeProvider provider;
-
-  /// Map of fields / properties / methods on Object.
-  final Map<String, DartType> objectMembers;
-
-  final StrongModeOptions options;
-  DownwardsInference inferrer;
-
-  TypeRules(TypeProvider provider, {this.options})
-      : provider = provider,
-        objectMembers = utils.getObjectMemberMap(provider) {
-    inferrer = new DownwardsInference(this);
-  }
-
-  /// Given a type t, if t is an interface type with a call method
-  /// defined, return the function type for the call method, otherwise
-  /// return null.
-  FunctionType getCallMethodType(DartType t) {
-    if (t is InterfaceType) {
-      ClassElement element = t.element;
-      InheritanceManager manager = new InheritanceManager(element.library);
-      FunctionType callType = manager.lookupMemberType(t, "call");
-      return callType;
-    }
-    return null;
-  }
-
-  /// Given an expression, return its type assuming it is
-  /// in the caller position of a call (that is, accounting
-  /// for the possibility of a call method).  Returns null
-  /// if expression is not statically callable.
-  FunctionType getTypeAsCaller(Expression applicand) {
-    var t = getStaticType(applicand);
-    if (t is InterfaceType) {
-      return getCallMethodType(t);
-    }
-    if (t is FunctionType) return t;
-    return null;
-  }
-
-  /// Gets the expected return type of the given function [body], either from
-  /// a normal return/yield, or from a yield*.
-  DartType getExpectedReturnType(FunctionBody body, {bool yieldStar: false}) {
-    FunctionType functionType;
-    var parent = body.parent;
-    if (parent is Declaration) {
-      functionType = elementType(parent.element);
-    } else {
-      assert(parent is FunctionExpression);
-      functionType = getStaticType(parent);
-    }
-
-    var type = functionType.returnType;
-
-    InterfaceType expectedType = null;
-    if (body.isAsynchronous) {
-      if (body.isGenerator) {
-        // Stream<T> -> T
-        expectedType = provider.streamType;
-      } else {
-        // Future<T> -> T
-        // TODO(vsm): Revisit with issue #228.
-        expectedType = provider.futureType;
-      }
-    } else {
-      if (body.isGenerator) {
-        // Iterable<T> -> T
-        expectedType = provider.iterableType;
-      } else {
-        // T -> T
-        return type;
-      }
-    }
-    if (yieldStar) {
-      if (type.isDynamic) {
-        // Ensure it's at least a Stream / Iterable.
-        return expectedType.substitute4([provider.dynamicType]);
-      } else {
-        // Analyzer will provide a separate error if expected type
-        // is not compatible with type.
-        return type;
-      }
-    }
-    if (type.isDynamic) {
-      return type;
-    } else if (type is InterfaceType && type.element == expectedType.element) {
-      return type.typeArguments[0];
-    } else {
-      // Malformed type - fallback on analyzer error.
-      return null;
-    }
-  }
-
-  DartType getStaticType(Expression expr) {
-    return expr.staticType ?? provider.dynamicType;
-  }
-
-  bool _isBottom(DartType t, {bool dynamicIsBottom: false}) {
-    if (t.isDynamic && dynamicIsBottom) return true;
-    // TODO(vsm): We need direct support for non-nullability in DartType.
-    // This should check on "true/nonnullable" Bottom
-    if (t.isBottom) return true;
-    return false;
-  }
-
-  bool _isTop(DartType t, {bool dynamicIsBottom: false}) {
-    if (t.isDynamic && !dynamicIsBottom) return true;
-    if (t.isObject) return true;
-    return false;
-  }
-
-  bool _anyParameterType(FunctionType ft, bool predicate(DartType t)) {
-    return ft.normalParameterTypes.any(predicate) ||
-        ft.optionalParameterTypes.any(predicate) ||
-        ft.namedParameterTypes.values.any(predicate);
-  }
-
-  // TODO(leafp): Revisit this.
-  bool isGroundType(DartType t) {
-    if (t is TypeParameterType) return false;
-    if (_isTop(t)) return true;
-
-    if (t is FunctionType) {
-      if (!_isTop(t.returnType) ||
-          _anyParameterType(t, (pt) => !_isBottom(pt, dynamicIsBottom: true))) {
-        return false;
-      } else {
-        return true;
-      }
-    }
-
-    if (t is InterfaceType) {
-      var typeArguments = t.typeArguments;
-      for (var typeArgument in typeArguments) {
-        if (!_isTop(typeArgument)) return false;
-      }
-      return true;
-    }
-
-    // We should not see any other type aside from malformed code.
-    return false;
-  }
-
-  /// Check that f1 is a subtype of f2. [ignoreReturn] is used in the DDC
-  /// checker to determine whether f1 would be a subtype of f2 if the return
-  /// type of f1 is set to match f2's return type.
-  // [fuzzyArrows] indicates whether or not the f1 and f2 should be
-  // treated as fuzzy arrow types (and hence dynamic parameters to f2 treated as
-  // bottom).
-  bool isFunctionSubTypeOf(FunctionType f1, FunctionType f2,
-      {bool fuzzyArrows: true, bool ignoreReturn: false}) {
-    final r1s = f1.normalParameterTypes;
-    final o1s = f1.optionalParameterTypes;
-    final n1s = f1.namedParameterTypes;
-    final r2s = f2.normalParameterTypes;
-    final o2s = f2.optionalParameterTypes;
-    final n2s = f2.namedParameterTypes;
-    final ret1 = ignoreReturn ? f2.returnType : f1.returnType;
-    final ret2 = f2.returnType;
-
-    // A -> B <: C -> D if C <: A and
-    // either D is void or B <: D
-    if (!ret2.isVoid && !isSubTypeOf(ret1, ret2)) return false;
-
-    // Reject if one has named and the other has optional
-    if (n1s.length > 0 && o2s.length > 0) return false;
-    if (n2s.length > 0 && o1s.length > 0) return false;
-
-    // f2 has named parameters
-    if (n2s.length > 0) {
-      // Check that every named parameter in f2 has a match in f1
-      for (String k2 in n2s.keys) {
-        if (!n1s.containsKey(k2)) return false;
-        if (!isSubTypeOf(n2s[k2], n1s[k2],
-            dynamicIsBottom: fuzzyArrows)) return false;
-      }
-    }
-    // If we get here, we either have no named parameters,
-    // or else the named parameters match and we have no optional
-    // parameters
-
-    // If f1 has more required parameters, reject
-    if (r1s.length > r2s.length) return false;
-
-    // If f2 has more required + optional parameters, reject
-    if (r2s.length + o2s.length > r1s.length + o1s.length) return false;
-
-    // The parameter lists must look like the following at this point
-    // where rrr is a region of required, and ooo is a region of optionals.
-    // f1: rrr ooo ooo ooo
-    // f2: rrr rrr ooo
-    int rr = r1s.length; // required in both
-    int or = r2s.length - r1s.length; // optional in f1, required in f2
-    int oo = o2s.length; // optional in both
-
-    for (int i = 0; i < rr; ++i) {
-      if (!isSubTypeOf(r2s[i], r1s[i],
-          dynamicIsBottom: fuzzyArrows)) return false;
-    }
-    for (int i = 0, j = rr; i < or; ++i, ++j) {
-      if (!isSubTypeOf(r2s[j], o1s[i],
-          dynamicIsBottom: fuzzyArrows)) return false;
-    }
-    for (int i = or, j = 0; i < oo; ++i, ++j) {
-      if (!isSubTypeOf(o2s[j], o1s[i],
-          dynamicIsBottom: fuzzyArrows)) return false;
-    }
-    return true;
-  }
-
-  bool _isInterfaceSubTypeOf(InterfaceType i1, InterfaceType i2) {
-    if (i1 == i2) return true;
-
-    if (i1.element == i2.element) {
-      List<DartType> tArgs1 = i1.typeArguments;
-      List<DartType> tArgs2 = i2.typeArguments;
-
-      // TODO(leafp): Verify that this is always true
-      // Do raw types get filled in?
-      assert(tArgs1.length == tArgs2.length);
-
-      for (int i = 0; i < tArgs1.length; i++) {
-        DartType t1 = tArgs1[i];
-        DartType t2 = tArgs2[i];
-        if (!isSubTypeOf(t1, t2)) return false;
-      }
-      return true;
-    }
-
-    if (i2.isDartCoreFunction) {
-      if (i1.element.getMethod("call") != null) return true;
-    }
-
-    if (i1 == provider.objectType) return false;
-
-    if (_isInterfaceSubTypeOf(i1.superclass, i2)) return true;
-
-    for (final parent in i1.interfaces) {
-      if (_isInterfaceSubTypeOf(parent, i2)) return true;
-    }
-
-    for (final parent in i1.mixins) {
-      if (_isInterfaceSubTypeOf(parent, i2)) return true;
-    }
-
-    return false;
-  }
-
-  bool isSubTypeOf(DartType t1, DartType t2, {bool dynamicIsBottom: false}) {
-    if (t1 == t2) return true;
-
-    // Trivially true.
-    if (_isTop(t2, dynamicIsBottom: dynamicIsBottom) ||
-        _isBottom(t1, dynamicIsBottom: dynamicIsBottom)) {
-      return true;
-    }
-
-    // Trivially false.
-    if (_isTop(t1, dynamicIsBottom: dynamicIsBottom) ||
-        _isBottom(t2, dynamicIsBottom: dynamicIsBottom)) {
-      return false;
-    }
-
-    // The null type is a subtype of any nullable type, which is all Dart types.
-    // TODO(vsm): Note, t1.isBottom still allows for null confusingly.
-    // _isBottom(t1) does not necessarily imply t1.isBottom if there are
-    // nonnullable types in the system.
-    if (t1.isBottom) {
-      return true;
-    }
-
-    // S <: T where S is a type variable
-    //  T is not dynamic or object (handled above)
-    //  S != T (handled above)
-    //  So only true if bound of S is S' and
-    //  S' <: T
-    if (t1 is TypeParameterType) {
-      DartType bound = t1.element.bound;
-      if (bound == null) return false;
-      return isSubTypeOf(bound, t2);
-    }
-
-    if (t2 is TypeParameterType) {
-      return false;
-    }
-
-    if (t2.isDartCoreFunction) {
-      if (t1 is FunctionType) return true;
-      if (t1.element is ClassElement) {
-        if ((t1.element as ClassElement).getMethod("call") != null) return true;
-      }
-    }
-
-    // "Traditional" name-based subtype check.
-    if (t1 is InterfaceType && t2 is InterfaceType) {
-      return _isInterfaceSubTypeOf(t1, t2);
-    }
-
-    if (t1 is! FunctionType && t2 is! FunctionType) return false;
-
-    if (t1 is InterfaceType && t2 is FunctionType) {
-      var callType = getCallMethodType(t1);
-      if (callType == null) return false;
-      return isFunctionSubTypeOf(callType, t2);
-    }
-
-    if (t1 is FunctionType && t2 is InterfaceType) {
-      return false;
-    }
-
-    // Functions
-    // Note: it appears under the hood all Dart functions map to a class /
-    // hidden type that:
-    //  (a) subtypes Object (an internal _FunctionImpl in the VM)
-    //  (b) implements Function
-    //  (c) provides standard Object members (hashCode, toString)
-    //  (d) contains private members (corresponding to _FunctionImpl?)
-    //  (e) provides a call method to handle the actual function invocation
-    //
-    // The standard Dart subtyping rules are structural in nature.  I.e.,
-    // bivariant on arguments and return type.
-    //
-    // The below tries for a more traditional subtyping rule:
-    // - covariant on return type
-    // - contravariant on parameters
-    // - 'sensible' (?) rules on optional and/or named params
-    // but doesn't properly mix with class subtyping.  I suspect Java 8 lambdas
-    // essentially map to dynamic (and rely on invokedynamic) due to similar
-    // issues.
-    return isFunctionSubTypeOf(t1 as FunctionType, t2 as FunctionType);
-  }
-
-  bool isAssignable(DartType t1, DartType t2) {
-    return isSubTypeOf(t1, t2);
-  }
-
-  // Produce a coercion which coerces something of type fromT
-  // to something of type toT.
-  // If wrap is true and both are function types, a closure
-  // wrapper coercion is produced using _wrapTo (see above)
-  // Returns the error coercion if the types cannot be coerced
-  // according to our current criteria.
-  Coercion _coerceTo(DartType fromT, DartType toT) {
-    // We can use anything as void
-    if (toT.isVoid) return Coercion.identity(toT);
-
-    // fromT <: toT, no coercion needed
-    if (isSubTypeOf(fromT, toT)) return Coercion.identity(toT);
-
-    // For now, reject conversions between function types and
-    // call method objects.  We could choose to allow casts here.
-    // Wrapping a function type to assign it to a call method
-    // object will never succeed.  Wrapping the other way could
-    // be allowed.
-    if ((fromT is FunctionType && getCallMethodType(toT) != null) ||
-        (toT is FunctionType && getCallMethodType(fromT) != null)) {
-      return Coercion.error();
-    }
-
-    // Downcast if toT <: fromT
-    if (isSubTypeOf(toT, fromT)) return Coercion.cast(fromT, toT);
-
-    // Downcast if toT <===> fromT
-    // The intention here is to allow casts that are sideways in the restricted
-    // type system, but allowed in the regular dart type system, since these
-    // are likely to succeed.  The canonical example is List<dynamic> and
-    // Iterable<T> for some concrete T (e.g. Object).  These are unrelated
-    // in the restricted system, but List<dynamic> <: Iterable<T> in dart.
-    if (fromT.isAssignableTo(toT)) {
-      return Coercion.cast(fromT, toT);
-    }
-    return Coercion.error();
-  }
-
-  StaticInfo checkAssignment(Expression expr, DartType toT) {
-    final fromT = getStaticType(expr);
-    final Coercion c = _coerceTo(fromT, toT);
-    if (c is Identity) return null;
-    if (c is CoercionError) return new StaticTypeError(this, expr, toT);
-    var reason = null;
-
-    var errors = <String>[];
-    var ok = inferrer.inferExpression(expr, toT, errors);
-    if (ok) return InferredType.create(this, expr, toT);
-    reason = (errors.isNotEmpty) ? errors.first : null;
-
-    if (c is Cast) return DownCast.create(this, expr, c, reason: reason);
-    assert(false);
-    return null;
-  }
-
-  DartType elementType(Element e) {
-    if (e == null) {
-      // Malformed code - just return dynamic.
-      return provider.dynamicType;
-    }
-    return (e as dynamic).type;
-  }
-
-  /// Returns `true` if the target expression is dynamic.
-  // TODO(jmesserly): remove this in favor of utils? Or a static method here?
-  bool isDynamicTarget(Expression target) => utils.isDynamicTarget(target);
-
-  /// Returns `true` if the expression is a dynamic function call or method
-  /// invocation.
-  bool isDynamicCall(Expression call) {
-    var ft = getTypeAsCaller(call);
-    // TODO(leafp): This will currently return true if t is Function
-    // This is probably the most correct thing to do for now, since
-    // this code is also used by the back end.  Maybe revisit at some
-    // point?
-    if (ft == null) return true;
-    // Dynamic as the parameter type is treated as bottom.  A function with
-    // a dynamic parameter type requires a dynamic call in general.
-    // However, as an optimization, if we have an original definition, we know
-    // dynamic is reified as Object - in this case a regular call is fine.
-    if (call is SimpleIdentifier) {
-      var element = call.staticElement;
-      if (element is FunctionElement || element is MethodElement) {
-        // An original declaration.
-        return false;
-      }
-    }
-
-    return _anyParameterType(ft, (pt) => pt.isDynamic);
-  }
-}
-
-class DownwardsInference {
-  final TypeRules rules;
-
-  DownwardsInference(this.rules);
-
-  /// Called for each list literal which gets inferred
-  void annotateListLiteral(ListLiteral e, List<DartType> targs) {}
-
-  /// Called for each map literal which gets inferred
-  void annotateMapLiteral(MapLiteral e, List<DartType> targs) {}
-
-  /// Called for each new/const which gets inferred
-  void annotateInstanceCreationExpression(
-      InstanceCreationExpression e, List<DartType> targs) {}
-
-  /// Called for cast from dynamic required for inference to succeed
-  void annotateCastFromDynamic(Expression e, DartType t) {}
-
-  /// Called for each function expression return type inferred
-  void annotateFunctionExpression(FunctionExpression e, DartType returnType) {}
-
-  /// Downward inference
-  bool inferExpression(Expression e, DartType t, List<String> errors) {
-    // Don't cast top level expressions, only sub-expressions
-    return _inferExpression(e, t, errors, cast: false);
-  }
-
-  /// Downward inference
-  bool _inferExpression(Expression e, DartType t, List<String> errors,
-      {cast: true}) {
-    if (e is ConditionalExpression) {
-      return _inferConditionalExpression(e, t, errors);
-    }
-    if (e is ParenthesizedExpression) {
-      return _inferParenthesizedExpression(e, t, errors);
-    }
-    if (rules.isSubTypeOf(rules.getStaticType(e), t)) return true;
-    if (cast && rules.getStaticType(e).isDynamic) {
-      annotateCastFromDynamic(e, t);
-      return true;
-    }
-    if (e is FunctionExpression) return _inferFunctionExpression(e, t, errors);
-    if (e is ListLiteral) return _inferListLiteral(e, t, errors);
-    if (e is MapLiteral) return _inferMapLiteral(e, t, errors);
-    if (e is NamedExpression) return _inferNamedExpression(e, t, errors);
-    if (e is InstanceCreationExpression) {
-      return _inferInstanceCreationExpression(e, t, errors);
-    }
-    errors.add("$e cannot be typed as $t");
-    return false;
-  }
-
-  /// If t1 = I<dynamic, ..., dynamic>, then look for a supertype
-  /// of t1 of the form K<S0, ..., Sm> where t2 = K<S0', ..., Sm'>
-  /// If the supertype exists, use the constraints S0 <: S0', ... Sm <: Sm'
-  /// to derive a concrete instantation for I of the form <T0, ..., Tn>,
-  /// such that I<T0, .., Tn> <: t2
-  List<DartType> _matchTypes(InterfaceType t1, InterfaceType t2) {
-    if (t1 == t2) return t2.typeArguments;
-    var tArgs1 = t1.typeArguments;
-    var tArgs2 = t2.typeArguments;
-    // If t1 isn't a raw type, bail out
-    if (tArgs1 != null && tArgs1.any((t) => !t.isDynamic)) return null;
-
-    // This is our inferred type argument list.  We start at all dynamic,
-    // and fill in with inferred types when we reach a match.
-    var actuals =
-        new List<DartType>.filled(tArgs1.length, rules.provider.dynamicType);
-
-    // When we find the supertype of t1 with the same
-    // classname as t2 (see below), we have the following:
-    // If t1 is an instantiation of a class T1<X0, ..., Xn>
-    // and t2 is an instantiation of a class T2<Y0, ...., Ym>
-    // of the form t2 = T2<S0, ..., Sm>
-    // then we want to choose instantiations for the Xi
-    // T0, ..., Tn such that T1<T0, ..., Tn> <: t2 .
-    // To find this, we simply instantate T1 with
-    // X0, ..., Xn, and then find its superclass
-    // T2<T0', ..., Tn'>.  We then solve the constraint
-    // set T0' <: S0, ..., Tn' <: Sn for the Xi.
-    // Currently, we only handle constraints where
-    // the Ti' is one of the Xi'.  If there are multiple
-    // constraints on some Xi, we choose the lower of the
-    // two (if it exists).
-    bool permute(List<DartType> permutedArgs) {
-      if (permutedArgs == null) return false;
-      var ps = t1.typeParameters;
-      var ts = ps.map((p) => p.type).toList();
-      for (int i = 0; i < permutedArgs.length; i++) {
-        var tVar = permutedArgs[i];
-        var tActual = tArgs2[i];
-        var index = ts.indexOf(tVar);
-        if (index >= 0 && rules.isSubTypeOf(tActual, actuals[index])) {
-          actuals[index] = tActual;
-        }
-      }
-      return actuals.any((x) => !x.isDynamic);
-    }
-
-    // Look for the first supertype of t1 with the same class name as t2.
-    bool match(InterfaceType t1) {
-      if (t1.element == t2.element) {
-        return permute(t1.typeArguments);
-      }
-
-      if (t1 == rules.provider.objectType) return false;
-
-      if (match(t1.superclass)) return true;
-
-      for (final parent in t1.interfaces) {
-        if (match(parent)) return true;
-      }
-
-      for (final parent in t1.mixins) {
-        if (match(parent)) return true;
-      }
-      return false;
-    }
-
-    // We have that t1 = T1<dynamic, ..., dynamic>.
-    // To match t1 against t2, we use the uninstantiated version
-    // of t1, essentially treating it as an instantiation with
-    // fresh variables, and solve for the variables.
-    // t1.element.type will be of the form T1<X0, ..., Xn>
-    if (!match(t1.element.type)) return null;
-    var newT1 = t1.element.type.substitute4(actuals);
-    // If we found a solution, return it.
-    if (rules.isSubTypeOf(newT1, t2)) return actuals;
-    return null;
-  }
-
-  /// These assume that e is not already a subtype of t
-
-  bool _inferConditionalExpression(
-      ConditionalExpression e, DartType t, errors) {
-    return _inferExpression(e.thenExpression, t, errors) &&
-        _inferExpression(e.elseExpression, t, errors);
-  }
-
-  bool _inferParenthesizedExpression(
-      ParenthesizedExpression e, DartType t, errors) {
-    return _inferExpression(e.expression, t, errors);
-  }
-
-  bool _inferInstanceCreationExpression(
-      InstanceCreationExpression e, DartType t, errors) {
-    var arguments = e.argumentList.arguments;
-    var rawType = rules.getStaticType(e);
-    // rawType is the instantiated type of the instance
-    if (rawType is! InterfaceType) return false;
-    var type = (rawType as InterfaceType);
-    if (type.typeParameters == null ||
-        type.typeParameters.length == 0) return false;
-    if (e.constructorName.type == null) return false;
-    // classTypeName is the type name of the class being instantiated
-    var classTypeName = e.constructorName.type;
-    // Check that we were not passed any type arguments
-    if (classTypeName.typeArguments != null) return false;
-    // Infer type arguments
-    if (t is! InterfaceType) return false;
-    var targs = _matchTypes(type, t);
-    if (targs == null) return false;
-    if (e.staticElement == null) return false;
-    var constructorElement = e.staticElement;
-    // From the constructor element get:
-    //  the instantiated type of the constructor, then
-    //     the uninstantiated element for the constructor, then
-    //        the uninstantiated type for the constructor
-    var rawConstructorElement =
-        constructorElement.type.element as ConstructorElement;
-    var baseType = rawConstructorElement.type;
-    if (baseType == null) return false;
-    // From the interface type (instantiated), get:
-    //  the uninstantiated element, then
-    //    the uninstantiated type, then
-    //      the type arguments (aka the type parameters)
-    var tparams = type.element.type.typeArguments;
-    // Take the uninstantiated constructor type, and replace the type
-    // parameters with the inferred arguments.
-    var fType = baseType.substitute2(targs, tparams);
-    {
-      var rTypes = fType.normalParameterTypes;
-      var oTypes = fType.optionalParameterTypes;
-      var pTypes = new List.from(rTypes)..addAll(oTypes);
-      var pArgs = arguments.where((x) => x is! NamedExpression);
-      var pi = 0;
-      for (var arg in pArgs) {
-        if (pi >= pTypes.length) return false;
-        var argType = pTypes[pi];
-        if (!_inferExpression(arg, argType, errors)) return false;
-        pi++;
-      }
-      var nTypes = fType.namedParameterTypes;
-      for (var arg0 in arguments) {
-        if (arg0 is! NamedExpression) continue;
-        var arg = arg0 as NamedExpression;
-        SimpleIdentifier nameNode = arg.name.label;
-        String name = nameNode.name;
-        var argType = nTypes[name];
-        if (argType == null) return false;
-        if (!_inferExpression(arg, argType, errors)) return false;
-      }
-    }
-    annotateInstanceCreationExpression(e, targs);
-    return true;
-  }
-
-  bool _inferNamedExpression(NamedExpression e, DartType t, errors) {
-    return _inferExpression(e.expression, t, errors);
-  }
-
-  bool _inferFunctionExpression(FunctionExpression e, DartType t, errors) {
-    if (t is! FunctionType) return false;
-    var fType = t as FunctionType;
-    var eType = e.staticType as FunctionType;
-    if (eType is! FunctionType) return false;
-
-    // We have a function literal, so we can treat the arrow type
-    // as non-fuzzy.  Since we're not improving on parameter types
-    // currently, if this check fails then we cannot succeed, so
-    // bail out.  Otherwise, we never need to check the parameter types
-    // again.
-    if (!rules.isFunctionSubTypeOf(eType, fType,
-        fuzzyArrows: false, ignoreReturn: true)) return false;
-
-    // This only entered inference because of fuzzy typing.
-    // The function type is already specific enough, we can just
-    // succeed and treat it as a successful inference
-    if (rules.isSubTypeOf(eType.returnType, fType.returnType)) return true;
-
-    // Fuzzy typing again, handle the void case (not caught by the previous)
-    if (fType.returnType.isVoid) return true;
-
-    if (e.body is! ExpressionFunctionBody) return false;
-    var body = (e.body as ExpressionFunctionBody).expression;
-    if (!_inferExpression(body, fType.returnType, errors)) return false;
-
-    // TODO(leafp): Try narrowing the argument types if possible
-    // to get better code in the function body.  This requires checking
-    // that the body is well-typed at the more specific type.
-
-    // At this point, we know that the parameter types are in the appropriate subtype
-    // relation, and we have checked that we can type the body at the appropriate return
-    // type, so we can are done.
-    annotateFunctionExpression(e, fType.returnType);
-    return true;
-  }
-
-  bool _inferListLiteral(ListLiteral e, DartType t, errors) {
-    var dyn = rules.provider.dynamicType;
-    var listT = rules.provider.listType.substitute4([dyn]);
-    // List <: t (using dart rules) must be true
-    if (!listT.isSubtypeOf(t)) return false;
-    // The list literal must have no type arguments
-    if (e.typeArguments != null) return false;
-    if (t is! InterfaceType) return false;
-    var targs = _matchTypes(listT, t);
-    if (targs == null) return false;
-    assert(targs.length == 1);
-    var etype = targs[0];
-    assert(!etype.isDynamic);
-    var elements = e.elements;
-    var b = elements.every((e) => _inferExpression(e, etype, errors));
-    if (b) annotateListLiteral(e, targs);
-    return b;
-  }
-
-  bool _inferMapLiteral(MapLiteral e, DartType t, errors) {
-    var dyn = rules.provider.dynamicType;
-    var mapT = rules.provider.mapType.substitute4([dyn, dyn]);
-    // Map <: t (using dart rules) must be true
-    if (!mapT.isSubtypeOf(t)) return false;
-    // The map literal must have no type arguments
-    if (e.typeArguments != null) return false;
-    if (t is! InterfaceType) return false;
-    var targs = _matchTypes(mapT, t);
-    if (targs == null) return false;
-    assert(targs.length == 2);
-    var kType = targs[0];
-    var vType = targs[1];
-    assert(!(kType.isDynamic && vType.isDynamic));
-    var entries = e.entries;
-    bool inferEntry(MapLiteralEntry entry) {
-      return _inferExpression(entry.key, kType, errors) &&
-          _inferExpression(entry.value, vType, errors);
-    }
-    var b = entries.every(inferEntry);
-    if (b) annotateMapLiteral(e, targs);
-    return b;
-  }
-}
+export 'package:analyzer/src/task/strong/rules.dart';
diff --git a/lib/src/codegen/code_generator.dart b/lib/src/codegen/code_generator.dart
index eb4135d..12cc751 100644
--- a/lib/src/codegen/code_generator.dart
+++ b/lib/src/codegen/code_generator.dart
@@ -23,7 +23,7 @@
 
   CodeGenerator(AbstractCompiler compiler)
       : compiler = compiler,
-        rules = compiler.rules,
+        rules = new TypeRules(compiler.context.typeProvider),
         context = compiler.context,
         options = compiler.options.codegenOptions;
 
diff --git a/lib/src/codegen/js_codegen.dart b/lib/src/codegen/js_codegen.dart
index 99a2408..872a7a5 100644
--- a/lib/src/codegen/js_codegen.dart
+++ b/lib/src/codegen/js_codegen.dart
@@ -105,11 +105,10 @@
 
   Map<String, DartType> _objectMembers;
 
-  JSCodegenVisitor(AbstractCompiler compiler, this.currentLibrary,
+  JSCodegenVisitor(AbstractCompiler compiler, this.rules, this.currentLibrary,
       this._extensionTypes, this._fieldsNeedingStorage)
       : compiler = compiler,
         options = compiler.options.codegenOptions,
-        rules = compiler.rules,
         _types = compiler.context.typeProvider {
     _loader = new ModuleItemLoadOrder(_emitModuleItem);
 
@@ -125,7 +124,7 @@
 
   JS.Program emitLibrary(LibraryUnit library) {
     // Modify the AST to make coercions explicit.
-    new CoercionReifier(library, compiler).reify();
+    new CoercionReifier(library, rules).reify();
 
     // Build the public namespace for this library. This allows us to do
     // constant time lookups (contrast with `Element.getChild(name)`).
@@ -3280,7 +3279,7 @@
     var library = unit.library.element.library;
     var fields = findFieldsNeedingStorage(unit);
     var codegen =
-        new JSCodegenVisitor(compiler, library, _extensionTypes, fields);
+        new JSCodegenVisitor(compiler, rules, library, _extensionTypes, fields);
     var module = codegen.emitLibrary(unit);
     var out = compiler.getOutputPath(library.source.uri);
     return writeJsLibrary(module, out,
diff --git a/lib/src/codegen/reify_coercions.dart b/lib/src/codegen/reify_coercions.dart
index 8a2c542..3bf1d91 100644
--- a/lib/src/codegen/reify_coercions.dart
+++ b/lib/src/codegen/reify_coercions.dart
@@ -9,7 +9,6 @@
 import 'package:analyzer/src/generated/element.dart';
 import 'package:logging/logging.dart' as logger;
 
-import '../compiler.dart' show AbstractCompiler;
 import '../checker/rules.dart';
 import '../info.dart';
 
@@ -100,11 +99,11 @@
   CoercionReifier._(
       this._cm, this._tm, this._vm, this._library, this._inferrer);
 
-  factory CoercionReifier(LibraryUnit library, AbstractCompiler compiler) {
+  factory CoercionReifier(LibraryUnit library, TypeRules rules) {
     var vm = new VariableManager();
     var tm = new TypeManager(library.library.element.enclosingElement, vm);
     var cm = new CoercionManager(vm, tm);
-    var inferrer = new _Inference(compiler.rules, tm);
+    var inferrer = new _Inference(rules, tm);
     return new CoercionReifier._(cm, tm, vm, library, inferrer);
   }
 
diff --git a/lib/src/compiler.dart b/lib/src/compiler.dart
index 8194518..d4f61a4 100644
--- a/lib/src/compiler.dart
+++ b/lib/src/compiler.dart
@@ -25,8 +25,6 @@
 import 'package:path/path.dart' as path;
 
 import 'analysis_context.dart';
-import 'checker/checker.dart';
-import 'checker/rules.dart';
 import 'codegen/html_codegen.dart' as html_codegen;
 import 'codegen/js_codegen.dart';
 import 'info.dart'
@@ -100,7 +98,7 @@
     _dartCore = context.typeProvider.objectType.element.library;
   }
 
-  ErrorCollector get reporter => checker.reporter;
+  ErrorCollector get reporter => super.reporter;
 
   /// Compiles every file in [options.inputs].
   /// Returns true on successful compile.
@@ -211,10 +209,7 @@
     for (var element in unitElements) {
       var unit = context.resolveCompilationUnit(element.source, library);
       units.add(unit);
-      failureInLib = logErrors(element.source) || failureInLib;
-      checker.reset();
-      checker.visitCompilationUnit(unit);
-      if (checker.failure) failureInLib = true;
+      failureInLib = computeErrors(element.source) || failureInLib;
     }
     if (failureInLib) _compilationRecord[library] = false;
 
@@ -345,19 +340,11 @@
 abstract class AbstractCompiler {
   final CompilerOptions options;
   final AnalysisContext context;
-  final CodeChecker checker;
+  final AnalysisErrorListener reporter;
 
-  AbstractCompiler(AnalysisContext context, CompilerOptions options,
-      [AnalysisErrorListener reporter])
-      : context = context,
-        options = options,
-        checker = new CodeChecker(
-            new TypeRules(context.typeProvider, options: options.strongOptions),
-            reporter ?? AnalysisErrorListener.NULL_LISTENER);
+  AbstractCompiler(this.context, this.options, [this.reporter]);
 
   String get outputDir => options.codegenOptions.outputDir;
-  TypeRules get rules => checker.rules;
-  AnalysisErrorListener get reporter => checker.reporter;
 
   Uri stringToUri(String uriString) {
     var uri = uriString.startsWith('dart:') || uriString.startsWith('package:')
@@ -440,23 +427,33 @@
 
   /// Log any errors encountered when resolving [source] and return whether any
   /// errors were found.
-  bool logErrors(Source source) {
-    List<AnalysisError> errors = context.computeErrors(source);
+  bool computeErrors(Source source) {
+    AnalysisContext errorContext = context;
+    // TODO(jmesserly): should this be a fix somewhere in analyzer?
+    // otherwise we fail to find the parts.
+    if (source.uri.scheme == 'dart') {
+      errorContext = context.sourceFactory.dartSdk.context;
+    }
+    List<AnalysisError> errors = errorContext.computeErrors(source);
     bool failure = false;
-    if (errors.isNotEmpty) {
-      for (var error in errors) {
-        // Always skip TODOs.
-        if (error.errorCode.type == ErrorType.TODO) continue;
+    for (var error in errors) {
+      // Always skip TODOs.
+      if (error.errorCode.type == ErrorType.TODO) continue;
 
-        // Skip hints for now. In the future these could be turned on via flags.
-        if (error.errorCode.errorSeverity.ordinal <
-            ErrorSeverity.WARNING.ordinal) {
-          continue;
+      // TODO(jmesserly): for now, treat DDC errors as having a different
+      // error level from Analayzer ones.
+      if (error.errorCode.name.startsWith('dev_compiler')) {
+        reporter.onError(error);
+        if (error.errorCode.errorSeverity == ErrorSeverity.ERROR) {
+          failure = true;
         }
-
+      } else if (error.errorCode.errorSeverity.ordinal >=
+          ErrorSeverity.WARNING.ordinal) {
         // All analyzer warnings or errors are errors for DDC.
         failure = true;
         reporter.onError(error);
+      } else {
+        // Skip hints for now.
       }
     }
     return failure;
diff --git a/lib/src/info.dart b/lib/src/info.dart
index c48fb36..75e74a3 100644
--- a/lib/src/info.dart
+++ b/lib/src/info.dart
@@ -8,20 +8,19 @@
 
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/element.dart';
-import 'package:analyzer/src/generated/error.dart';
 import 'package:analyzer/src/generated/parser.dart';
 
-import 'checker/rules.dart';
 import 'utils.dart' as utils;
+import 'package:analyzer/src/task/strong/info.dart';
+export 'package:analyzer/src/task/strong/info.dart';
 
 /// Represents a summary of the results collected by running the program
 /// checker.
 class CheckerResults {
   final List<LibraryInfo> libraries;
-  final TypeRules rules;
   final bool failure;
 
-  CheckerResults(this.libraries, this.rules, this.failure);
+  CheckerResults(this.libraries, this.failure);
 }
 
 /// Computed information about each library.
@@ -102,474 +101,3 @@
     return clone;
   }
 }
-
-// The abstract type of coercions mapping one type to another.
-// This class also exposes static builder functions which
-// check for errors and reduce redundant coercions to the identity.
-abstract class Coercion {
-  final DartType fromType;
-  final DartType toType;
-  Coercion(this.fromType, this.toType);
-  static Coercion cast(DartType fromT, DartType toT) => new Cast(fromT, toT);
-  static Coercion identity(DartType type) => new Identity(type);
-  static Coercion error() => new CoercionError();
-}
-
-// Coercion which casts one type to another
-class Cast extends Coercion {
-  Cast(DartType fromType, DartType toType) : super(fromType, toType);
-}
-
-// The identity coercion
-class Identity extends Coercion {
-  Identity(DartType fromType) : super(fromType, fromType);
-}
-
-// The error coercion.  This coercion signals that a coercion
-// could not be generated.  The code generator should not see
-// these.
-class CoercionError extends Coercion {
-  CoercionError() : super(null, null);
-}
-
-// TODO(jmesserly): this could use some refactoring. These are essentially
-// like ErrorCodes in analyzer, but we're including some details in our message.
-// Analyzer instead has template strings, and replaces '{0}' with the first
-// argument.
-abstract class StaticInfo {
-  /// AST Node this info is attached to.
-  AstNode get node;
-
-  // TODO(jmesserly): review the usage of error codes. We probably want our own,
-  // as well as some DDC specific [ErrorType]s.
-  ErrorCode toErrorCode();
-
-  // TODO(jmesserly): what convention to use here?
-  String get name => 'dev_compiler.$runtimeType';
-
-  List<Object> get arguments => [node];
-
-  AnalysisError toAnalysisError() {
-    int begin = node is AnnotatedNode
-        ? (node as AnnotatedNode).firstTokenAfterCommentAndMetadata.offset
-        : node.offset;
-    int length = node.end - begin;
-    var source = (node.root as CompilationUnit).element.source;
-    return new AnalysisError(source, begin, length, toErrorCode(), arguments);
-  }
-}
-
-/// Implicitly injected expression conversion.
-abstract class CoercionInfo extends StaticInfo {
-  final TypeRules rules;
-
-  final Expression node;
-
-  DartType get convertedType;
-
-  CoercionInfo(this.rules, this.node);
-
-  DartType get baseType => rules.getStaticType(node);
-  DartType get staticType => convertedType;
-
-  String get message;
-  toErrorCode() => new HintCode(name, message);
-
-  static const String _propertyName = 'dev_compiler.src.info.CoercionInfo';
-
-  /// Gets the coercion info associated with this node.
-  static CoercionInfo get(AstNode node) => node.getProperty(_propertyName);
-
-  /// Sets the coercion info associated with this node.
-  static CoercionInfo set(AstNode node, CoercionInfo info) {
-    node.setProperty(_propertyName, info);
-    return info;
-  }
-}
-
-// Base class for all casts from base type to sub type.
-abstract class DownCast extends CoercionInfo {
-  Cast _cast;
-
-  DownCast._internal(TypeRules rules, Expression expression, this._cast)
-      : super(rules, expression) {
-    assert(_cast.toType != baseType &&
-        _cast.fromType == baseType &&
-        (baseType.isDynamic ||
-            // Call methods make the following non-redundant
-            _cast.toType.isSubtypeOf(baseType) ||
-            baseType.isAssignableTo(_cast.toType)));
-  }
-
-  Cast get cast => _cast;
-
-  DartType get convertedType => _cast.toType;
-
-  @override List<Object> get arguments => [node, baseType, convertedType];
-  @override String get message => '{0} ({1}) will need runtime check '
-      'to cast to type {2}';
-
-  // Factory to create correct DownCast variant.
-  static StaticInfo create(TypeRules rules, Expression expression, Cast cast,
-      {String reason}) {
-    final fromT = cast.fromType;
-    final toT = cast.toType;
-
-    // toT <:_R fromT => to <: fromT
-    // NB: classes with call methods are subtypes of function
-    // types, but the function type is not assignable to the class
-    assert(toT.isSubtypeOf(fromT) || fromT.isAssignableTo(toT));
-
-    // Handle null call specially.
-    if (expression is NullLiteral) {
-      // TODO(vsm): Create a NullCast for this once we revisit nonnullability.
-      return new DownCastImplicit(rules, expression, cast);
-    }
-
-    // Inference "casts":
-    if (expression is Literal) {
-      // fromT should be an exact type - this will almost certainly fail at
-      // runtime.
-      return new StaticTypeError(rules, expression, toT, reason: reason);
-    }
-    if (expression is FunctionExpression) {
-      // fromT should be an exact type - this will almost certainly fail at
-      // runtime.
-      return new UninferredClosure(rules, expression, cast);
-    }
-    if (expression is InstanceCreationExpression) {
-      // fromT should be an exact type - this will almost certainly fail at
-      // runtime.
-      return new StaticTypeError(rules, expression, toT, reason: reason);
-    }
-
-    // Composite cast: these are more likely to fail.
-    if (!rules.isGroundType(toT)) {
-      // This cast is (probably) due to our different treatment of dynamic.
-      // It may be more likely to fail at runtime.
-      return new DownCastComposite(rules, expression, cast);
-    }
-
-    // Dynamic cast
-    if (fromT.isDynamic) {
-      return new DynamicCast(rules, expression, cast);
-    }
-
-    // Assignment cast
-    var parent = expression.parent;
-    if (parent is VariableDeclaration && (parent.initializer == expression)) {
-      return new AssignmentCast(rules, expression, cast);
-    }
-
-    // Other casts
-    return new DownCastImplicit(rules, expression, cast);
-  }
-}
-
-//
-// Standard down casts.  These casts are implicitly injected by the compiler.
-//
-
-// A down cast from dynamic to T.
-class DynamicCast extends DownCast {
-  DynamicCast(TypeRules rules, Expression expression, Cast cast)
-      : super._internal(rules, expression, cast);
-
-  toErrorCode() => new HintCode(name, message);
-}
-
-// A down cast due to a variable declaration to a ground type.  E.g.,
-//   T x = expr;
-// where T is ground.  We exclude non-ground types as these behave differently
-// compared to standard Dart.
-class AssignmentCast extends DownCast {
-  AssignmentCast(TypeRules rules, Expression expression, Cast cast)
-      : super._internal(rules, expression, cast);
-
-  toErrorCode() => new HintCode(name, message);
-}
-
-//
-// Temporary "casts" of allocation sites - literals, constructor invocations,
-// and closures.  These should be handled by contextual inference.  In most
-// cases, inference will be sufficient, though in some it may unmask an actual
-// error: e.g.,
-//   List<int> l = [1, 2, 3]; // Inference succeeds
-//   List<String> l = [1, 2, 3]; // Inference reveals static type error
-// We're marking all as warnings for now.
-//
-// TODO(vsm,leafp): Remove this.
-class UninferredClosure extends DownCast {
-  UninferredClosure(TypeRules rules, FunctionExpression expression, Cast cast)
-      : super._internal(rules, expression, cast);
-
-  toErrorCode() => new StaticTypeWarningCode(name, message);
-}
-
-//
-// Implicit down casts.  These are only injected by the compiler by flag.
-//
-
-// A down cast to a non-ground type.  These behave differently from standard
-// Dart and may be more likely to fail at runtime.
-class DownCastComposite extends DownCast {
-  DownCastComposite(TypeRules rules, Expression expression, Cast cast)
-      : super._internal(rules, expression, cast);
-
-  toErrorCode() => new StaticTypeWarningCode(name, message);
-}
-
-// A down cast to a non-ground type.  These behave differently from standard
-// Dart and may be more likely to fail at runtime.
-class DownCastImplicit extends DownCast {
-  DownCastImplicit(TypeRules rules, Expression expression, Cast cast)
-      : super._internal(rules, expression, cast);
-
-  toErrorCode() => new HintCode(name, message);
-}
-
-// An inferred type for the wrapped expression, which may need to be
-// reified into the term
-abstract class InferredTypeBase extends CoercionInfo {
-  final DartType _type;
-
-  InferredTypeBase._internal(TypeRules rules, Expression expression, this._type)
-      : super(rules, expression);
-
-  DartType get type => _type;
-  DartType get convertedType => type;
-  @override String get message => '{0} has inferred type {1}';
-  @override List get arguments => [node, type];
-
-  toErrorCode() => new HintCode(name, message);
-}
-
-// Standard / unspecialized inferred type
-class InferredType extends InferredTypeBase {
-  InferredType(TypeRules rules, Expression expression, DartType type)
-      : super._internal(rules, expression, type);
-
-  // Factory to create correct InferredType variant.
-  static InferredTypeBase create(
-      TypeRules rules, Expression expression, DartType type) {
-    // Specialized inference:
-    if (expression is Literal) {
-      return new InferredTypeLiteral(rules, expression, type);
-    }
-    if (expression is InstanceCreationExpression) {
-      return new InferredTypeAllocation(rules, expression, type);
-    }
-    if (expression is FunctionExpression) {
-      return new InferredTypeClosure(rules, expression, type);
-    }
-    return new InferredType(rules, expression, type);
-  }
-}
-
-// An infered type for a literal expression.
-class InferredTypeLiteral extends InferredTypeBase {
-  InferredTypeLiteral(TypeRules rules, Expression expression, DartType type)
-      : super._internal(rules, expression, type);
-}
-
-// An inferred type for a non-literal allocation site.
-class InferredTypeAllocation extends InferredTypeBase {
-  InferredTypeAllocation(TypeRules rules, Expression expression, DartType type)
-      : super._internal(rules, expression, type);
-}
-
-// An inferred type for a closure expression
-class InferredTypeClosure extends InferredTypeBase {
-  InferredTypeClosure(TypeRules rules, Expression expression, DartType type)
-      : super._internal(rules, expression, type);
-}
-
-class DynamicInvoke extends CoercionInfo {
-  DynamicInvoke(TypeRules rules, Expression expression)
-      : super(rules, expression);
-
-  DartType get convertedType => rules.provider.dynamicType;
-  String get message => '{0} requires dynamic invoke';
-  toErrorCode() => new HintCode(name, message);
-
-  static const String _propertyName = 'dev_compiler.src.info.DynamicInvoke';
-
-  /// Whether this [node] is the target of a dynamic operation.
-  static bool get(AstNode node) {
-    var value = node.getProperty(_propertyName);
-    return value != null ? value : false;
-  }
-
-  /// Sets whether this node is the target of a dynamic operation.
-  static bool set(AstNode node, bool value) {
-    // Free the storage for things that aren't dynamic.
-    if (value == false) value = null;
-    node.setProperty(_propertyName, value);
-    return value;
-  }
-}
-
-abstract class StaticError extends StaticInfo {
-  final AstNode node;
-
-  StaticError(this.node);
-
-  String get message;
-
-  toErrorCode() => new CompileTimeErrorCode(name, message);
-}
-
-class StaticTypeError extends StaticError {
-  final DartType baseType;
-  final DartType expectedType;
-  String reason = null;
-
-  StaticTypeError(TypeRules rules, Expression expression, this.expectedType,
-      {this.reason})
-      : baseType = rules.getStaticType(expression),
-        super(expression);
-
-  @override List<Object> get arguments => [node, baseType, expectedType];
-  @override String get message =>
-      'Type check failed: {0} ({1}) is not of type {2}' +
-          ((reason == null) ? '' : ' because $reason');
-}
-
-class InvalidVariableDeclaration extends StaticError {
-  final DartType expectedType;
-
-  InvalidVariableDeclaration(
-      TypeRules rules, AstNode declaration, this.expectedType)
-      : super(declaration);
-
-  @override List<Object> get arguments => [expectedType];
-  @override String get message => 'Type check failed: null is not of type {0}';
-}
-
-class InvalidParameterDeclaration extends StaticError {
-  final DartType expectedType;
-
-  InvalidParameterDeclaration(
-      TypeRules rules, FormalParameter declaration, this.expectedType)
-      : super(declaration);
-
-  @override List<Object> get arguments => [node, expectedType];
-  @override String get message => 'Type check failed: {0} is not of type {1}';
-}
-
-class NonGroundTypeCheckInfo extends StaticInfo {
-  final DartType type;
-  final AstNode node;
-
-  NonGroundTypeCheckInfo(this.node, this.type) {
-    assert(node is IsExpression || node is AsExpression);
-  }
-
-  @override List<Object> get arguments => [type];
-  String get message =>
-      "Runtime check on non-ground type {0} may throw StrongModeError";
-
-  toErrorCode() => new HintCode(name, message);
-}
-
-// Invalid override of an instance member of a class.
-abstract class InvalidOverride extends StaticError {
-  /// Member declaration with the invalid override.
-  final ExecutableElement element;
-
-  /// Type (class or interface) that provides the base declaration.
-  final InterfaceType base;
-
-  /// Actual type of the overridden member.
-  final DartType subType;
-
-  /// Actual type of the base member.
-  final DartType baseType;
-
-  /// Whether the error comes from combining a base class and an interface
-  final bool fromBaseClass;
-
-  /// Whether the error comes from a mixin (either overriding a base class or an
-  /// interface declaration).
-  final bool fromMixin;
-
-  InvalidOverride(
-      AstNode node, this.element, this.base, this.subType, this.baseType)
-      : fromBaseClass = node is ExtendsClause,
-        fromMixin = node.parent is WithClause,
-        super(node);
-
-  ClassElement get parent => element.enclosingElement;
-
-  @override List<Object> get arguments =>
-      [parent.name, element.name, subType, base, baseType];
-
-  String _messageHelper(String errorName) {
-    var lcErrorName = errorName.toLowerCase();
-    var intro = fromBaseClass
-        ? 'Base class introduces an $lcErrorName'
-        : (fromMixin ? 'Mixin introduces an $lcErrorName' : errorName);
-    return '$intro. The type of {0}.{1} ({2}) is not a '
-        'subtype of {3}.{1} ({4}).';
-  }
-}
-
-// Invalid override due to incompatible type.  I.e., the overridden signature
-// is not compatible with the original.
-class InvalidMethodOverride extends InvalidOverride {
-  InvalidMethodOverride(AstNode node, ExecutableElement element,
-      InterfaceType base, FunctionType subType, FunctionType baseType)
-      : super(node, element, base, subType, baseType);
-
-  String get message => _messageHelper('Invalid override');
-}
-
-/// Used to mark unexpected situations in our compiler were we couldn't compute
-/// the type of an expression.
-// TODO(sigmund): This is normally a result of another error that is caught by
-// the analyzer, so this should likely be removed in the future.
-class MissingTypeError extends StaticInfo {
-  final AstNode node;
-  toErrorCode() => new StaticTypeWarningCode(name, message);
-
-  MissingTypeError(this.node);
-
-  @override List<Object> get arguments => [node, node.runtimeType];
-  String get message => "type analysis didn't compute the type of: {0} {1}";
-}
-
-/// Dart constructors have one weird quirk, illustrated with this example:
-///
-///     class Base {
-///       var x;
-///       Base() : x = print('Base.1') {
-///         print('Base.2');
-///       }
-///     }
-///
-///     class Derived extends Base {
-///       var y, z;
-///       Derived()
-///           : y = print('Derived.1'),
-///             super(),
-///             z = print('Derived.2') {
-///         print('Derived.3');
-///       }
-///     }
-///
-/// The order will be Derived.1, Base.1, Derived.2, Base.2, Derived.3; this
-/// ordering preserves the invariant that code can't observe uninitialized
-/// state, however it results in super constructor body not being run
-/// immediately after super initializers. Normally this isn't observable, but it
-/// could be if initializers have side effects.
-///
-/// Better to have `super` at the end, as required by the Dart style guide:
-/// <http://goo.gl/q1T4BB>
-///
-/// For now this is the only pattern we support.
-class InvalidSuperInvocation extends StaticError {
-  InvalidSuperInvocation(SuperConstructorInvocation node) : super(node);
-
-  @override String get message => "super call must be last in an initializer "
-      "list (see http://goo.gl/q1T4BB): {0}";
-}
diff --git a/lib/src/server/server.dart b/lib/src/server/server.dart
index 9a6320f..079b231 100644
--- a/lib/src/server/server.dart
+++ b/lib/src/server/server.dart
@@ -84,7 +84,7 @@
     var time = (clock.elapsedMilliseconds / 1000).toStringAsFixed(2);
     _log.fine('Compiled ${_libraries.length} libraries in ${time} s\n');
     return new CheckerResults(
-        _libraries, rules, _failure || options.codegenOptions.forceCompile);
+        _libraries, _failure || options.codegenOptions.forceCompile);
   }
 
   bool _buildSource(SourceNode node) {
@@ -154,9 +154,7 @@
     for (var unit in libraryUnit.libraryThenParts) {
       var unitSource = unit.element.source;
       // TODO(sigmund): integrate analyzer errors with static-info (issue #6).
-      failureInLib = logErrors(unitSource) || failureInLib;
-      checker.visitCompilationUnit(unit);
-      if (checker.failure) failureInLib = true;
+      failureInLib = computeErrors(unitSource) || failureInLib;
     }
     if (failureInLib) {
       _failure = true;
@@ -310,4 +308,4 @@
 }
 
 final _log = new Logger('dev_compiler.src.server');
-final _earlyErrorResult = new CheckerResults(const [], null, true);
+final _earlyErrorResult = new CheckerResults(const [], true);
diff --git a/lib/src/utils.dart b/lib/src/utils.dart
index b561c59..b38f531 100644
--- a/lib/src/utils.dart
+++ b/lib/src/utils.dart
@@ -380,30 +380,6 @@
 // TODO(vsm): Move this onto the appropriate class.  Ideally, we'd attach
 // it to TypeProvider.
 
-final _objectMap = new Expando('providerToObjectMap');
-Map<String, DartType> getObjectMemberMap(TypeProvider typeProvider) {
-  var map = _objectMap[typeProvider] as Map<String, DartType>;
-  if (map == null) {
-    map = <String, DartType>{};
-    _objectMap[typeProvider] = map;
-    var objectType = typeProvider.objectType;
-    var element = objectType.element;
-    // Only record methods (including getters) with no parameters.  As parameters are contravariant wrt
-    // type, using Object's version may be too strict.
-    // Add instance methods.
-    element.methods.where((method) => !method.isStatic).forEach((method) {
-      map[method.name] = method.type;
-    });
-    // Add getters.
-    element.accessors
-        .where((member) => !member.isStatic && member.isGetter)
-        .forEach((member) {
-      map[member.name] = member.type.returnType;
-    });
-  }
-  return map;
-}
-
 /// Searches all supertype, in order of most derived members, to see if any
 /// [match] a condition. If so, returns the first match, otherwise returns null.
 InterfaceType findSupertype(InterfaceType type, bool match(InterfaceType t)) {
diff --git a/lib/strong_mode.dart b/lib/strong_mode.dart
index 99cef5c..45d17ab 100644
--- a/lib/strong_mode.dart
+++ b/lib/strong_mode.dart
@@ -31,6 +31,7 @@
 
 /// A type checker for Dart code that operates under stronger rules, and has
 /// the ability to do local type inference in some situations.
+// TODO(jmesserly): remove this class.
 class StrongChecker {
   final AnalysisContext _context;
   final CodeChecker _checker;
@@ -41,25 +42,28 @@
   factory StrongChecker(AnalysisContext context, StrongModeOptions options) {
     // TODO(vsm): Remove this once analyzer_cli is completely switched to the
     // task model.
-    if (!AnalysisEngine
-        .instance.useTaskModel) enableDevCompilerInference(context, options);
-    var rules = new TypeRules(context.typeProvider, options: options);
-    var reporter = new _ErrorCollector(options.hints);
-    var checker = new CodeChecker(rules, reporter);
-    return new StrongChecker._(context, checker, reporter);
+    if (!AnalysisEngine.instance.useTaskModel) {
+      enableDevCompilerInference(context, options);
+      var rules = new TypeRules(context.typeProvider);
+      var reporter = new _ErrorCollector(options.hints);
+      var checker = new CodeChecker(rules, reporter);
+      return new StrongChecker._(context, checker, reporter);
+    }
+    return new StrongChecker._(context, null, null);
   }
 
   /// Computes and returns DDC errors for the [source].
   AnalysisErrorInfo computeErrors(Source source) {
     var errors = new List<AnalysisError>();
-    _reporter.errors = errors;
+    if (_checker != null) {
+      _reporter.errors = errors;
 
-    for (Source librarySource in _context.getLibrariesContaining(source)) {
-      var resolved = _context.resolveCompilationUnit2(source, librarySource);
-      _checker.visitCompilationUnit(resolved);
+      for (Source librarySource in _context.getLibrariesContaining(source)) {
+        var resolved = _context.resolveCompilationUnit2(source, librarySource);
+        _checker.visitCompilationUnit(resolved);
+      }
+      _reporter.errors = null;
     }
-    _reporter.errors = null;
-
     return new AnalysisErrorInfoImpl(errors, _context.getLineInfo(source));
   }
 }
diff --git a/pubspec.yaml b/pubspec.yaml
index 7c9dd37..0f56a4c 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -41,3 +41,6 @@
   # Similar to dartdevc, but runs the (single) entry point with iojs (requires
   # a very recent iojs next-nightly version).
   dartdevrun: devrun
+
+dependency_overrides:
+  analyzer: { path: ../dart/sdk/pkg/analyzer }
diff --git a/test/all_tests.dart b/test/all_tests.dart
index bd97444..b7c60ca 100644
--- a/test/all_tests.dart
+++ b/test/all_tests.dart
@@ -7,8 +7,6 @@
 
 import 'package:test/test.dart';
 
-import 'checker/checker_test.dart' as checker_test;
-import 'checker/inferred_type_test.dart' as inferred_type_test;
 import 'checker/self_host_test.dart' as self_host;
 import 'closure/closure_annotation_test.dart' as closure_annotation_test;
 import 'closure/closure_type_test.dart' as closure_type_test;
@@ -19,8 +17,6 @@
 
 void main() {
   group('end-to-end', e2e.main);
-  group('inferred types', inferred_type_test.main);
-  group('checker', checker_test.main);
   group('report', report_test.main);
   group('dependency_graph', dependency_graph_test.main);
   group('codegen', () => codegen_test.main([]));
diff --git a/test/testing.dart b/test/testing.dart
index 6874ed3..faa90be 100644
--- a/test/testing.dart
+++ b/test/testing.dart
@@ -28,17 +28,21 @@
 import 'package:dev_compiler/src/utils.dart';
 
 /// Shared analysis context used for compilation.
-final realSdkContext = createAnalysisContextWithSources(
-    new StrongModeOptions(),
-    new SourceResolverOptions(
-        dartSdkPath: getSdkDir().path,
-        customUrlMappings: {
-          'package:expect/expect.dart': _testCodegenPath('expect.dart'),
-          'package:async_helper/async_helper.dart':
-              _testCodegenPath('async_helper.dart'),
-          'package:unittest/unittest.dart': _testCodegenPath('unittest.dart'),
-          'package:dom/dom.dart': _testCodegenPath('sunflower', 'dom.dart')
-        }))..analysisOptions.cacheSize = 512;
+final AnalysisContext realSdkContext = () {
+  var context = createAnalysisContextWithSources(
+      new StrongModeOptions(),
+      new SourceResolverOptions(
+          dartSdkPath: getSdkDir().path,
+          customUrlMappings: {
+            'package:expect/expect.dart': _testCodegenPath('expect.dart'),
+            'package:async_helper/async_helper.dart':
+                _testCodegenPath('async_helper.dart'),
+            'package:unittest/unittest.dart': _testCodegenPath('unittest.dart'),
+            'package:dom/dom.dart': _testCodegenPath('sunflower', 'dom.dart')
+          }));
+  (context.analysisOptions as AnalysisOptionsImpl).cacheSize = 512;
+  return context;
+}();
 
 String _testCodegenPath(String p1, [String p2]) =>
     path.join(testDirectory, 'codegen', p1, p2);