Refactor global inference data to prepare for serialization

Change-Id: If88b948ca80b1a7915d87a49ba4e1d05de669282
Reviewed-on: https://dart-review.googlesource.com/72401
Reviewed-by: Stephen Adams <sra@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
diff --git a/pkg/compiler/lib/src/backend_strategy.dart b/pkg/compiler/lib/src/backend_strategy.dart
index cced759..d7d5d0d 100644
--- a/pkg/compiler/lib/src/backend_strategy.dart
+++ b/pkg/compiler/lib/src/backend_strategy.dart
@@ -58,6 +58,5 @@
 
   /// Creates the [TypesInferrer] used by this strategy.
   TypesInferrer createTypesInferrer(
-      JClosedWorld closedWorld, InferredDataBuilder inferredDataBuilder,
-      {bool disableTypeInference: false});
+      JClosedWorld closedWorld, InferredDataBuilder inferredDataBuilder);
 }
diff --git a/pkg/compiler/lib/src/dump_info.dart b/pkg/compiler/lib/src/dump_info.dart
index b022af7..64423bf 100644
--- a/pkg/compiler/lib/src/dump_info.dart
+++ b/pkg/compiler/lib/src/dump_info.dart
@@ -22,10 +22,7 @@
 import 'js_backend/js_backend.dart' show JavaScriptBackend;
 import 'types/abstract_value_domain.dart';
 import 'types/types.dart'
-    show
-        GlobalTypeInferenceElementResult,
-        GlobalTypeInferenceMemberResult,
-        GlobalTypeInferenceResults;
+    show GlobalTypeInferenceMemberResult, GlobalTypeInferenceResults;
 import 'universe/world_builder.dart' show CodegenWorldBuilder;
 import 'universe/world_impact.dart'
     show ImpactUseCase, WorldImpact, WorldImpactVisitorImpl;
@@ -112,7 +109,7 @@
   GlobalTypeInferenceMemberResult _resultOfMember(MemberEntity e) =>
       _globalInferenceResults.resultOfMember(e);
 
-  GlobalTypeInferenceElementResult _resultOfParameter(Local e) =>
+  AbstractValue _resultOfParameter(Local e) =>
       _globalInferenceResults.resultOfParameter(e);
 
   FieldInfo visitField(FieldEntity field, {ClassEntity containingClass}) {
@@ -280,7 +277,7 @@
     List<ParameterInfo> parameters = <ParameterInfo>[];
     List<String> inferredParameterTypes = <String>[];
     codegenWorldBuilder.forEachParameterAsLocal(function, (parameter) {
-      inferredParameterTypes.add('${_resultOfParameter(parameter).type}');
+      inferredParameterTypes.add('${_resultOfParameter(parameter)}');
     });
     int parameterIndex = 0;
     codegenWorldBuilder.forEachParameter(function, (type, name, _) {
diff --git a/pkg/compiler/lib/src/inferrer/inferrer_engine.dart b/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
index 777d861..a25c9fc 100644
--- a/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
+++ b/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
@@ -121,8 +121,6 @@
   // TODO(johnniwinther): Make this private again.
   GlobalTypeInferenceElementData dataOfMember(MemberEntity element);
 
-  GlobalTypeInferenceElementData lookupDataOfMember(MemberEntity element);
-
   bool checkIfExposesThis(ConstructorEntity element);
 
   void recordExposesThis(ConstructorEntity element, bool exposesThis);
@@ -225,6 +223,8 @@
 
   bool returnsMapValueType(Selector selector, AbstractValue mask);
 
+  void close();
+
   void clear();
 
   /// Returns true if global optimizations such as type inferencing can apply to
@@ -280,8 +280,6 @@
   final Map<ir.Node, TypeInformation> concreteTypes =
       new Map<ir.Node, TypeInformation>();
 
-  final Map<ir.Node, TypeInformation> concreteKernelTypes =
-      new Map<ir.Node, TypeInformation>();
   final Set<ConstructorEntity> generativeConstructorsExposingThis =
       new Set<ConstructorEntity>();
 
@@ -329,9 +327,6 @@
   GlobalTypeInferenceElementData dataOfMember(MemberEntity element) =>
       _memberData[element] ??= new KernelGlobalTypeInferenceElementData();
 
-  GlobalTypeInferenceElementData lookupDataOfMember(MemberEntity element) =>
-      _memberData[element];
-
   /**
    * Update [sideEffects] with the side effects of [callee] being
    * called with [selector].
@@ -1167,11 +1162,18 @@
     return info;
   }
 
+  void close() {
+    for (MemberTypeInformation typeInformation
+        in types.memberTypeInformations.values) {
+      typeInformation.computeIsCalledOnce();
+    }
+  }
+
   void clear() {
+    if (retainDataForTesting) return;
+
     void cleanup(TypeInformation info) {
-      if (!retainDataForTesting) {
-        info.cleanup();
-      }
+      info.cleanup();
     }
 
     types.allocatedCalls.forEach(cleanup);
@@ -1195,6 +1197,8 @@
 
     types.allocatedMaps.values.forEach(cleanup);
     types.allocatedLists.values.forEach(cleanup);
+
+    _memberData.clear();
   }
 
   Iterable<MemberEntity> getCallersOfForTesting(MemberEntity element) {
diff --git a/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart b/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
index 72fad8b..4319b27 100644
--- a/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
+++ b/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
@@ -11,11 +11,11 @@
 import '../compiler.dart';
 import '../elements/entities.dart';
 import '../js_backend/inferred_data.dart';
+import '../js_model/elements.dart' show JClosureCallMethod;
 import '../js_model/locals.dart';
 import '../kernel/element_map.dart';
 import '../types/abstract_value_domain.dart';
 import '../types/types.dart';
-import '../universe/selector.dart' show Selector;
 import '../world.dart';
 import 'inferrer_engine.dart';
 import 'type_graph_nodes.dart';
@@ -53,7 +53,6 @@
 
 class TypeGraphInferrer implements TypesInferrer {
   InferrerEngine inferrer;
-  final bool _disableTypeInference;
   final JClosedWorld closedWorld;
 
   final Compiler _compiler;
@@ -63,21 +62,17 @@
   final InferredDataBuilder _inferredDataBuilder;
 
   TypeGraphInferrer(this._compiler, this._elementMap, this._globalLocalsMap,
-      this._closureDataLookup, this.closedWorld, this._inferredDataBuilder,
-      {bool disableTypeInference: false})
-      : this._disableTypeInference = disableTypeInference;
+      this._closureDataLookup, this.closedWorld, this._inferredDataBuilder);
 
   String get name => 'Graph inferrer';
 
   AbstractValueDomain get abstractValueDomain =>
       closedWorld.abstractValueDomain;
 
-  AbstractValue get _dynamicType => abstractValueDomain.dynamicType;
-
-  void analyzeMain(FunctionEntity main) {
+  GlobalTypeInferenceResults analyzeMain(FunctionEntity main) {
     inferrer = createInferrerEngineFor(main);
-    if (_disableTypeInference) return;
     inferrer.runOverAllElements();
+    return buildResults();
   }
 
   InferrerEngine createInferrerEngineFor(FunctionEntity main) {
@@ -96,90 +91,95 @@
         _inferredDataBuilder);
   }
 
-  AbstractValue getReturnTypeOfMember(MemberEntity element) {
-    if (_disableTypeInference) return _dynamicType;
-    // Currently, closure calls return dynamic.
-    if (element is! FunctionEntity) return _dynamicType;
-    return inferrer.types.getInferredTypeOfMember(element).type;
-  }
-
-  AbstractValue getReturnTypeOfParameter(Local element) {
-    if (_disableTypeInference) return _dynamicType;
-    return _dynamicType;
-  }
-
-  AbstractValue getTypeOfMember(MemberEntity element) {
-    if (_disableTypeInference) return _dynamicType;
-    // The inferrer stores the return type for a function, so we have to
-    // be careful to not return it here.
-    if (element is FunctionEntity) return abstractValueDomain.functionType;
-    return inferrer.types.getInferredTypeOfMember(element).type;
-  }
-
-  AbstractValue getTypeOfParameter(Local element) {
-    if (_disableTypeInference) return _dynamicType;
-    // The inferrer stores the return type for a function, so we have to
-    // be careful to not return it here.
-    return inferrer.types.getInferredTypeOfParameter(element).type;
-  }
-
-  AbstractValue getTypeForNewList(ir.Node node) {
-    if (_disableTypeInference) return _dynamicType;
-    return inferrer.types.allocatedLists[node].type;
-  }
-
-  bool isFixedArrayCheckedForGrowable(ir.Node node) {
-    if (_disableTypeInference) return true;
-    ListTypeInformation info = inferrer.types.allocatedLists[node];
-    return info.checksGrowable;
-  }
-
-  AbstractValue getTypeOfSelector(Selector selector, AbstractValue receiver) {
-    if (_disableTypeInference) return _dynamicType;
-    // Bailout for closure calls. We're not tracking types of
-    // closures.
-    if (selector.isClosureCall) return _dynamicType;
-    if (selector.isSetter || selector.isIndexSet) {
-      return _dynamicType;
-    }
-    if (inferrer.returnsListElementType(selector, receiver)) {
-      return abstractValueDomain.getContainerElementType(receiver);
-    }
-    if (inferrer.returnsMapValueType(selector, receiver)) {
-      return abstractValueDomain.getMapValueType(receiver);
-    }
-
-    if (inferrer.closedWorld.includesClosureCall(selector, receiver)) {
-      return abstractValueDomain.dynamicType;
-    } else {
-      Iterable<MemberEntity> elements =
-          inferrer.closedWorld.locateMembers(selector, receiver);
-      List<AbstractValue> types = <AbstractValue>[];
-      for (MemberEntity element in elements) {
-        AbstractValue type =
-            inferrer.typeOfMemberWithSelector(element, selector).type;
-        types.add(type);
-      }
-      return abstractValueDomain.unionOfMany(types);
-    }
-  }
-
   Iterable<MemberEntity> getCallersOfForTesting(MemberEntity element) {
-    if (_disableTypeInference) {
-      throw new UnsupportedError(
-          "Cannot query the type inferrer when type inference is disabled.");
-    }
     return inferrer.getCallersOfForTesting(element);
   }
 
-  bool isMemberCalledOnce(MemberEntity element) {
-    if (_disableTypeInference) return false;
-    MemberTypeInformation info =
-        inferrer.types.getInferredTypeOfMember(element);
-    return info.isCalledOnce();
-  }
+  GlobalTypeInferenceResults buildResults() {
+    inferrer.close();
 
-  void clear() {
+    Map<ir.Node, AbstractValue> allocatedLists = <ir.Node, AbstractValue>{};
+    Set<ir.Node> checkedForGrowableLists = new Set<ir.Node>();
+    inferrer.types.allocatedLists
+        .forEach((ir.Node node, ListTypeInformation typeInformation) {
+      ListTypeInformation info = inferrer.types.allocatedLists[node];
+      if (info.checksGrowable) {
+        checkedForGrowableLists.add(node);
+      }
+      allocatedLists[node] = typeInformation.type;
+    });
+
+    Map<MemberEntity, GlobalTypeInferenceMemberResult> memberResults =
+        <MemberEntity, GlobalTypeInferenceMemberResult>{};
+    Map<Local, AbstractValue> parameterResults = <Local, AbstractValue>{};
+
+    void createMemberResults(
+        MemberEntity member, MemberTypeInformation typeInformation) {
+      GlobalTypeInferenceElementData data = inferrer.dataOfMember(member);
+      bool isJsInterop = closedWorld.nativeData.isJsInteropMember(member);
+
+      AbstractValue returnType;
+      AbstractValue type;
+
+      if (isJsInterop) {
+        returnType = type = abstractValueDomain.dynamicType;
+      } else if (member is FunctionEntity) {
+        returnType = typeInformation.type;
+        type = abstractValueDomain.functionType;
+      } else {
+        returnType = abstractValueDomain.dynamicType;
+        type = typeInformation.type;
+      }
+
+      bool throwsAlways =
+          // Always throws if the return type was inferred to be non-null empty.
+          returnType != null && abstractValueDomain.isEmpty(returnType);
+
+      bool isCalledOnce =
+          typeInformation.isCalledOnce(); //isMemberCalledOnce(member);
+
+      memberResults[member] = new GlobalTypeInferenceMemberResultImpl(
+          data, allocatedLists, returnType, type,
+          throwsAlways: throwsAlways, isCalledOnce: isCalledOnce);
+    }
+
+    Set<FieldEntity> freeVariables = new Set<FieldEntity>();
+    inferrer.types.forEachMemberType(
+        (MemberEntity member, MemberTypeInformation typeInformation) {
+      createMemberResults(member, typeInformation);
+      if (member is JClosureCallMethod) {
+        ClosureRepresentationInfo info =
+            _closureDataLookup.getScopeInfo(member);
+        info.forEachFreeVariable((Local from, FieldEntity to) {
+          freeVariables.add(to);
+        });
+      }
+    });
+    for (FieldEntity field in freeVariables) {
+      if (!memberResults.containsKey(field)) {
+        MemberTypeInformation typeInformation =
+            inferrer.types.getInferredTypeOfMember(field);
+        typeInformation.computeIsCalledOnce();
+        createMemberResults(field, typeInformation);
+      }
+    }
+
+    inferrer.types.forEachParameterType(
+        (Local parameter, ParameterTypeInformation typeInformation) {
+      AbstractValue type = typeInformation.type;
+      parameterResults[parameter] = type;
+    });
+
+    GlobalTypeInferenceResults results = new GlobalTypeInferenceResultsImpl(
+        closedWorld,
+        _inferredDataBuilder.close(closedWorld),
+        memberResults,
+        parameterResults,
+        checkedForGrowableLists,
+        inferrer.returnsListElementTypeSet);
+
     inferrer.clear();
+
+    return results;
   }
 }
diff --git a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
index d89a8a8..4b5d61e 100644
--- a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
+++ b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
@@ -445,6 +445,11 @@
     return count == 1;
   }
 
+  void computeIsCalledOnce() {
+    assert(_isCalledOnce == null, "isCalledOnce has already been computed.");
+    _isCalledOnce = _computeIsCalledOnce();
+  }
+
   bool get isClosurized => closurizedCount > 0;
 
   // Closurized methods never become stable to ensure that the information in
@@ -501,9 +506,6 @@
   }
 
   void cleanup() {
-    // This node is on multiple lists so cleanup() can be called twice.
-    if (_isCalledOnce != null) return;
-    _isCalledOnce = _computeIsCalledOnce();
     _callers = null;
     super.cleanup();
   }
diff --git a/pkg/compiler/lib/src/inferrer/type_system.dart b/pkg/compiler/lib/src/inferrer/type_system.dart
index 75e4ee3..2fb026d 100644
--- a/pkg/compiler/lib/src/inferrer/type_system.dart
+++ b/pkg/compiler/lib/src/inferrer/type_system.dart
@@ -55,16 +55,16 @@
   final List<TypeInformation> _orderedTypeInformations = <TypeInformation>[];
 
   /// [ParameterTypeInformation]s for parameters.
-  final Map<Local, TypeInformation> parameterTypeInformations =
-      new Map<Local, TypeInformation>();
+  final Map<Local, ParameterTypeInformation> parameterTypeInformations =
+      new Map<Local, ParameterTypeInformation>();
 
   /// [MemberTypeInformation]s for members.
-  final Map<MemberEntity, TypeInformation> memberTypeInformations =
-      new Map<MemberEntity, TypeInformation>();
+  final Map<MemberEntity, MemberTypeInformation> memberTypeInformations =
+      new Map<MemberEntity, MemberTypeInformation>();
 
   /// [ListTypeInformation] for allocated lists.
-  final Map<ir.Node, TypeInformation> allocatedLists =
-      new Map<ir.Node, TypeInformation>();
+  final Map<ir.Node, ListTypeInformation> allocatedLists =
+      new Map<ir.Node, ListTypeInformation>();
 
   /// [MapTypeInformation] for allocated Maps.
   final Map<ir.Node, TypeInformation> allocatedMaps =
@@ -398,12 +398,22 @@
     });
   }
 
+  void forEachParameterType(
+      void f(Local parameter, ParameterTypeInformation typeInformation)) {
+    parameterTypeInformations.forEach(f);
+  }
+
   MemberTypeInformation getInferredTypeOfMember(MemberEntity member) {
     assert(!member.isAbstract,
         failedAt(member, "Unexpected abstract member $member."));
     return memberTypeInformations[member] ??= _getInferredTypeOfMember(member);
   }
 
+  void forEachMemberType(
+      void f(MemberEntity member, MemberTypeInformation typeInformation)) {
+    memberTypeInformations.forEach(f);
+  }
+
   MemberTypeInformation _getInferredTypeOfMember(MemberEntity member) {
     MemberTypeInformation typeInformation =
         strategy.createMemberTypeInformation(_abstractValueDomain, member);
diff --git a/pkg/compiler/lib/src/js_backend/inferred_data.dart b/pkg/compiler/lib/src/js_backend/inferred_data.dart
index 1f5de05..9ae9b5f 100644
--- a/pkg/compiler/lib/src/js_backend/inferred_data.dart
+++ b/pkg/compiler/lib/src/js_backend/inferred_data.dart
@@ -243,3 +243,27 @@
     return _functionsThatMightBePassedToApply.contains(element);
   }
 }
+
+class TrivialInferredData implements InferredData {
+  final SideEffects _allSideEffects = new SideEffects();
+
+  @override
+  SideEffects getSideEffectsOfElement(FunctionEntity element) {
+    return _allSideEffects;
+  }
+
+  @override
+  bool getMightBePassedToApply(FunctionEntity element) => true;
+
+  @override
+  bool isCalledInLoop(MemberEntity element) => true;
+
+  @override
+  bool getCannotThrow(FunctionEntity element) => false;
+
+  @override
+  SideEffects getSideEffectsOfSelector(
+      Selector selector, AbstractValue receiver) {
+    return _allSideEffects;
+  }
+}
diff --git a/pkg/compiler/lib/src/js_model/js_strategy.dart b/pkg/compiler/lib/src/js_model/js_strategy.dart
index 095117e..e2889cd 100644
--- a/pkg/compiler/lib/src/js_model/js_strategy.dart
+++ b/pkg/compiler/lib/src/js_model/js_strategy.dart
@@ -221,11 +221,9 @@
 
   @override
   TypesInferrer createTypesInferrer(
-      JClosedWorld closedWorld, InferredDataBuilder inferredDataBuilder,
-      {bool disableTypeInference: false}) {
+      JClosedWorld closedWorld, InferredDataBuilder inferredDataBuilder) {
     return new TypeGraphInferrer(_compiler, _elementMap, _globalLocalsMap,
-        _closureDataLookup, closedWorld, inferredDataBuilder,
-        disableTypeInference: disableTypeInference);
+        _closureDataLookup, closedWorld, inferredDataBuilder);
   }
 }
 
diff --git a/pkg/compiler/lib/src/kernel/kernel_backend_strategy.dart b/pkg/compiler/lib/src/kernel/kernel_backend_strategy.dart
index 7753d69..9b4dae7 100644
--- a/pkg/compiler/lib/src/kernel/kernel_backend_strategy.dart
+++ b/pkg/compiler/lib/src/kernel/kernel_backend_strategy.dart
@@ -121,14 +121,14 @@
 
 class KernelToTypeInferenceMapImpl implements KernelToTypeInferenceMap {
   final GlobalTypeInferenceResults _globalInferenceResults;
-  GlobalTypeInferenceElementResult _targetResults;
+  GlobalTypeInferenceMemberResult _targetResults;
 
   KernelToTypeInferenceMapImpl(
       MemberEntity target, this._globalInferenceResults) {
     _targetResults = _resultOf(target);
   }
 
-  GlobalTypeInferenceElementResult _resultOf(MemberEntity e) =>
+  GlobalTypeInferenceMemberResult _resultOf(MemberEntity e) =>
       _globalInferenceResults
           .resultOfMember(e is ConstructorBodyEntity ? e.constructor : e);
 
diff --git a/pkg/compiler/lib/src/ssa/types.dart b/pkg/compiler/lib/src/ssa/types.dart
index f9b3752..c7dd084 100644
--- a/pkg/compiler/lib/src/ssa/types.dart
+++ b/pkg/compiler/lib/src/ssa/types.dart
@@ -25,7 +25,7 @@
 
   static AbstractValue inferredTypeForParameter(
       Local element, GlobalTypeInferenceResults results) {
-    return results.resultOfParameter(element).type ??
+    return results.resultOfParameter(element) ??
         results.closedWorld.abstractValueDomain.dynamicType;
   }
 
diff --git a/pkg/compiler/lib/src/types/types.dart b/pkg/compiler/lib/src/types/types.dart
index 89c5b8c..83c2bee 100644
--- a/pkg/compiler/lib/src/types/types.dart
+++ b/pkg/compiler/lib/src/types/types.dart
@@ -6,6 +6,7 @@
 
 import 'package:kernel/ast.dart' as ir;
 import '../common.dart' show failedAt;
+import '../common/names.dart';
 import '../common/tasks.dart' show CompilerTask;
 import '../compiler.dart' show Compiler;
 import '../elements/entities.dart';
@@ -26,12 +27,19 @@
 /// guarantees) and the `subclass of Object or null` type mask for the type
 /// based queries (the runtime value could be anything).
 abstract class GlobalTypeInferenceElementResult {
-  /// Whether the method element associated with this result always throws.
-  bool get throwsAlways;
-
   /// The inferred type when this result belongs to a parameter or field
   /// element, null otherwise.
   AbstractValue get type;
+}
+
+abstract class GlobalTypeInferenceMemberResult
+    extends GlobalTypeInferenceElementResult {
+  /// Whether the member associated with this result is only called once in one
+  /// location in the entire program.
+  bool get isCalledOnce;
+
+  /// Whether the method element associated with this result always throws.
+  bool get throwsAlways;
 
   /// The inferred return type when this result belongs to a function element.
   AbstractValue get returnType;
@@ -60,91 +68,6 @@
   AbstractValue typeOfIteratorCurrent(ir.Node node);
 }
 
-abstract class GlobalTypeInferenceMemberResult
-    extends GlobalTypeInferenceElementResult {
-  /// Whether the member associated with this result is only called once in one
-  /// location in the entire program.
-  bool get isCalledOnce;
-}
-
-abstract class GlobalTypeInferenceParameterResult
-    extends GlobalTypeInferenceElementResult {}
-
-abstract class GlobalTypeInferenceElementResultImpl
-    implements GlobalTypeInferenceElementResult {
-  // TODO(sigmund): split - stop using _data after inference is done.
-  final GlobalTypeInferenceElementData _data;
-
-  // TODO(sigmund): store relevant data & drop reference to inference engine.
-  final TypesInferrer _inferrer;
-  final bool _isJsInterop;
-
-  GlobalTypeInferenceElementResultImpl(
-      this._data, this._inferrer, this._isJsInterop);
-
-  bool get throwsAlways {
-    AbstractValue mask = this.returnType;
-    // Always throws if the return type was inferred to be non-null empty.
-    return mask != null && _inferrer.abstractValueDomain.isEmpty(mask);
-  }
-
-  AbstractValue typeOfNewList(ir.Node node) =>
-      _inferrer.getTypeForNewList(node);
-
-  AbstractValue typeOfListLiteral(ir.Node node) =>
-      _inferrer.getTypeForNewList(node);
-
-  AbstractValue typeOfSend(ir.Node node) => _data?.typeOfSend(node);
-  AbstractValue typeOfGetter(ir.Node node) => _data?.typeOfGetter(node);
-  AbstractValue typeOfIterator(ir.Node node) => _data?.typeOfIterator(node);
-  AbstractValue typeOfIteratorMoveNext(ir.Node node) =>
-      _data?.typeOfIteratorMoveNext(node);
-  AbstractValue typeOfIteratorCurrent(ir.Node node) =>
-      _data?.typeOfIteratorCurrent(node);
-}
-
-class GlobalTypeInferenceMemberResultImpl
-    extends GlobalTypeInferenceElementResultImpl
-    implements GlobalTypeInferenceMemberResult {
-  // TODO(sigmund): delete, store data directly here.
-  final MemberEntity _owner;
-
-  GlobalTypeInferenceMemberResultImpl(
-      this._owner,
-      GlobalTypeInferenceElementData data,
-      TypesInferrer inferrer,
-      bool isJsInterop)
-      : super(data, inferrer, isJsInterop);
-
-  bool get isCalledOnce => _inferrer.isMemberCalledOnce(_owner);
-
-  AbstractValue get returnType => _isJsInterop
-      ? _inferrer.abstractValueDomain.dynamicType
-      : _inferrer.getReturnTypeOfMember(_owner);
-
-  AbstractValue get type => _isJsInterop
-      ? _inferrer.abstractValueDomain.dynamicType
-      : _inferrer.getTypeOfMember(_owner);
-}
-
-class GlobalTypeInferenceParameterResultImpl
-    extends GlobalTypeInferenceElementResultImpl
-    implements GlobalTypeInferenceParameterResult {
-  // TODO(sigmund): delete, store data directly here.
-  final Local _owner;
-
-  GlobalTypeInferenceParameterResultImpl(this._owner, TypesInferrer inferrer)
-      : super(null, inferrer, false);
-
-  AbstractValue get returnType => _isJsInterop
-      ? _inferrer.abstractValueDomain.dynamicType
-      : _inferrer.getReturnTypeOfParameter(_owner);
-
-  AbstractValue get type => _isJsInterop
-      ? _inferrer.abstractValueDomain.dynamicType
-      : _inferrer.getTypeOfParameter(_owner);
-}
-
 /// Internal data used during type-inference to store intermediate results about
 /// a single element.
 abstract class GlobalTypeInferenceElementData {
@@ -169,17 +92,7 @@
 
 /// API to interact with the global type-inference engine.
 abstract class TypesInferrer {
-  AbstractValueDomain get abstractValueDomain;
-  void analyzeMain(FunctionEntity element);
-  AbstractValue getReturnTypeOfMember(MemberEntity element);
-  AbstractValue getReturnTypeOfParameter(Local element);
-  AbstractValue getTypeOfMember(MemberEntity element);
-  AbstractValue getTypeOfParameter(Local element);
-  AbstractValue getTypeForNewList(ir.Node node);
-  AbstractValue getTypeOfSelector(Selector selector, AbstractValue receiver);
-  void clear();
-  bool isMemberCalledOnce(MemberEntity element);
-  bool isFixedArrayCheckedForGrowable(ir.Node node);
+  GlobalTypeInferenceResults analyzeMain(FunctionEntity element);
 }
 
 /// Results produced by the global type-inference algorithm.
@@ -195,7 +108,7 @@
 
   GlobalTypeInferenceMemberResult resultOfMember(MemberEntity member);
 
-  GlobalTypeInferenceElementResult resultOfParameter(Local parameter);
+  AbstractValue resultOfParameter(Local parameter);
 
   /// Returns the type of a [selector] when applied to a receiver with the given
   /// type [mask].
@@ -227,17 +140,15 @@
   GlobalTypeInferenceResults runGlobalTypeInference(FunctionEntity mainElement,
       JClosedWorld closedWorld, InferredDataBuilder inferredDataBuilder) {
     return measure(() {
-      typesInferrerInternal ??= compiler.backendStrategy.createTypesInferrer(
-          closedWorld, inferredDataBuilder,
-          disableTypeInference: compiler.disableTypeInference);
-      typesInferrerInternal.analyzeMain(mainElement);
-      typesInferrerInternal.clear();
-
-      GlobalTypeInferenceResultsImpl results =
-          new GlobalTypeInferenceResultsImpl(
-              typesInferrerInternal, closedWorld);
+      GlobalTypeInferenceResults results;
+      if (compiler.disableTypeInference) {
+        results = new TrivialGlobalTypeInferenceResults(closedWorld);
+      } else {
+        typesInferrerInternal ??= compiler.backendStrategy
+            .createTypesInferrer(closedWorld, inferredDataBuilder);
+        results = typesInferrerInternal.analyzeMain(mainElement);
+      }
       closedWorld.noSuchMethodData.categorizeComplexImplementations(results);
-      results.inferredData = inferredDataBuilder.close(closedWorld);
       resultsForTesting = results;
       return results;
     });
@@ -246,35 +157,29 @@
 
 class GlobalTypeInferenceResultsImpl implements GlobalTypeInferenceResults {
   final JClosedWorld closedWorld;
-  InferredData inferredData;
-  final TypeGraphInferrer _inferrer;
-  // TODO(sigmund): store relevant data & drop reference to inference engine.
-  final Map<MemberEntity, GlobalTypeInferenceMemberResult> _memberResults =
-      <MemberEntity, GlobalTypeInferenceMemberResult>{};
-  final Map<Local, GlobalTypeInferenceParameterResult> _parameterResults =
-      <Local, GlobalTypeInferenceParameterResult>{};
+  final InferredData inferredData;
+  final GlobalTypeInferenceMemberResult _deadFieldResult;
+  final GlobalTypeInferenceMemberResult _deadMethodResult;
+  final AbstractValue _trivialParameterResult;
 
-  GlobalTypeInferenceResultsImpl(this._inferrer, this.closedWorld);
+  final Map<MemberEntity, GlobalTypeInferenceMemberResult> memberResults;
+  final Map<Local, AbstractValue> parameterResults;
+  final Set<ir.Node> checkedForGrowableLists;
+  final Set<Selector> returnsListElementTypeSet;
 
-  GlobalTypeInferenceMemberResult _createMemberResult(
-      TypeGraphInferrer inferrer, MemberEntity member,
-      {bool isJsInterop: false}) {
-    return new GlobalTypeInferenceMemberResultImpl(
-        member,
-        // We store data in the context of the enclosing method, even
-        // for closure elements.
-        inferrer.inferrer.lookupDataOfMember(member),
-        inferrer,
-        isJsInterop);
-  }
+  GlobalTypeInferenceResultsImpl(
+      this.closedWorld,
+      this.inferredData,
+      this.memberResults,
+      this.parameterResults,
+      this.checkedForGrowableLists,
+      this.returnsListElementTypeSet)
+      : _deadFieldResult = new DeadFieldGlobalTypeInferenceResult(
+            closedWorld.abstractValueDomain),
+        _deadMethodResult = new DeadMethodGlobalTypeInferenceResult(
+            closedWorld.abstractValueDomain),
+        _trivialParameterResult = closedWorld.abstractValueDomain.dynamicType;
 
-  GlobalTypeInferenceParameterResult _createParameterResult(
-      TypeGraphInferrer inferrer, Local parameter) {
-    return new GlobalTypeInferenceParameterResultImpl(parameter, inferrer);
-  }
-
-  // TODO(sigmund,johnniwinther): compute result objects eagerly and make it an
-  // error to query for results that don't exist.
   @override
   GlobalTypeInferenceMemberResult resultOfMember(MemberEntity member) {
     assert(
@@ -283,25 +188,93 @@
             member,
             "unexpected input: ConstructorBodyElements are created"
             " after global type inference, no data is avaiable for them."));
-
-    bool isJsInterop = closedWorld.nativeData.isJsInteropMember(member);
-    return _memberResults.putIfAbsent(member,
-        () => _createMemberResult(_inferrer, member, isJsInterop: isJsInterop));
+    // TODO(sigmund,johnniwinther): Make it an error to query for results that
+    // don't exist..
+    /*assert(memberResults.containsKey(member) || member is JSignatureMethod,
+        "No inference result for member $member");*/
+    return memberResults[member] ??
+        (member is FunctionEntity ? _deadMethodResult : _deadFieldResult);
   }
 
-  // TODO(sigmund,johnniwinther): compute result objects eagerly and make it an
-  // error to query for results that don't exist.
   @override
-  GlobalTypeInferenceElementResult resultOfParameter(Local parameter) {
-    return _parameterResults.putIfAbsent(
-        parameter, () => _createParameterResult(_inferrer, parameter));
+  AbstractValue resultOfParameter(Local parameter) {
+    // TODO(sigmund,johnniwinther): Make it an error to query for results that
+    // don't exist.
+    /*assert(parameterResults.containsKey(parameter),
+        "No inference result for parameter $parameter");*/
+    return parameterResults[parameter] ?? _trivialParameterResult;
   }
 
   /// Returns the type of a [selector] when applied to a receiver with the given
-  /// type [mask].
+  /// [receiver] type.
   @override
-  AbstractValue typeOfSelector(Selector selector, AbstractValue mask) =>
-      _inferrer.getTypeOfSelector(selector, mask);
+  AbstractValue typeOfSelector(Selector selector, AbstractValue receiver) {
+    // Bailout for closure calls. We're not tracking types of
+    // closures.
+    if (selector.isClosureCall)
+      return closedWorld.abstractValueDomain.dynamicType;
+    if (selector.isSetter || selector.isIndexSet) {
+      return closedWorld.abstractValueDomain.dynamicType;
+    }
+    if (returnsListElementType(selector, receiver)) {
+      return closedWorld.abstractValueDomain.getContainerElementType(receiver);
+    }
+    if (returnsMapValueType(selector, receiver)) {
+      return closedWorld.abstractValueDomain.getMapValueType(receiver);
+    }
+
+    if (closedWorld.includesClosureCall(selector, receiver)) {
+      return closedWorld.abstractValueDomain.dynamicType;
+    } else {
+      Iterable<MemberEntity> elements =
+          closedWorld.locateMembers(selector, receiver);
+      List<AbstractValue> types = <AbstractValue>[];
+      for (MemberEntity element in elements) {
+        AbstractValue type = typeOfMemberWithSelector(element, selector);
+        types.add(type);
+      }
+      return closedWorld.abstractValueDomain.unionOfMany(types);
+    }
+  }
+
+  bool returnsListElementType(Selector selector, AbstractValue mask) {
+    return mask != null &&
+        closedWorld.abstractValueDomain.isContainer(mask) &&
+        returnsListElementTypeSet.contains(selector);
+  }
+
+  bool returnsMapValueType(Selector selector, AbstractValue mask) {
+    return mask != null &&
+        closedWorld.abstractValueDomain.isMap(mask) &&
+        selector.isIndex;
+  }
+
+  AbstractValue typeOfMemberWithSelector(
+      MemberEntity element, Selector selector) {
+    if (element.name == Identifiers.noSuchMethod_ &&
+        selector.name != element.name) {
+      // An invocation can resolve to a [noSuchMethod], in which case
+      // we get the return type of [noSuchMethod].
+      return resultOfMember(element).returnType;
+    } else if (selector.isGetter) {
+      if (element.isFunction) {
+        // [functionType] is null if the inferrer did not run.
+        return closedWorld.abstractValueDomain.functionType;
+      } else if (element.isField) {
+        return resultOfMember(element).type;
+      } else if (element.isGetter) {
+        return resultOfMember(element).returnType;
+      } else {
+        assert(false, failedAt(element, "Unexpected member $element"));
+        return closedWorld.abstractValueDomain.dynamicType;
+      }
+    } else if (element.isGetter || element.isField) {
+      assert(selector.isCall || selector.isSetter);
+      return closedWorld.abstractValueDomain.dynamicType;
+    } else {
+      return resultOfMember(element).returnType;
+    }
+  }
 
   /// Returns whether a fixed-length constructor call goes through a growable
   /// check.
@@ -309,5 +282,187 @@
   // constructor call.
   @override
   bool isFixedArrayCheckedForGrowable(ir.Node ctorCall) =>
-      _inferrer.isFixedArrayCheckedForGrowable(ctorCall);
+      checkedForGrowableLists.contains(ctorCall);
+}
+
+class GlobalTypeInferenceMemberResultImpl
+    implements GlobalTypeInferenceMemberResult {
+  final GlobalTypeInferenceElementData _data;
+  final Map<ir.Node, AbstractValue> _allocatedLists;
+  final AbstractValue returnType;
+  final AbstractValue type;
+  final bool throwsAlways;
+  final bool isCalledOnce;
+
+  GlobalTypeInferenceMemberResultImpl(
+      this._data, this._allocatedLists, this.returnType, this.type,
+      {this.throwsAlways, this.isCalledOnce});
+
+  AbstractValue typeOfSend(ir.Node node) => _data?.typeOfSend(node);
+  AbstractValue typeOfGetter(ir.Node node) => _data?.typeOfGetter(node);
+  AbstractValue typeOfIterator(ir.Node node) => _data?.typeOfIterator(node);
+  AbstractValue typeOfIteratorMoveNext(ir.Node node) =>
+      _data?.typeOfIteratorMoveNext(node);
+  AbstractValue typeOfIteratorCurrent(ir.Node node) =>
+      _data?.typeOfIteratorCurrent(node);
+
+  AbstractValue typeOfNewList(ir.Node node) => _allocatedLists[node];
+
+  AbstractValue typeOfListLiteral(ir.Node node) => _allocatedLists[node];
+}
+
+class TrivialGlobalTypeInferenceResults implements GlobalTypeInferenceResults {
+  final JClosedWorld closedWorld;
+  final TrivialGlobalTypeInferenceMemberResult _trivialMemberResult;
+  final AbstractValue _trivialParameterResult;
+  final InferredData inferredData = new TrivialInferredData();
+
+  TrivialGlobalTypeInferenceResults(this.closedWorld)
+      : _trivialMemberResult = new TrivialGlobalTypeInferenceMemberResult(
+            closedWorld.abstractValueDomain.dynamicType),
+        _trivialParameterResult = closedWorld.abstractValueDomain.dynamicType;
+
+  @override
+  bool isFixedArrayCheckedForGrowable(ir.Node node) => false;
+
+  @override
+  AbstractValue typeOfSelector(Selector selector, AbstractValue mask) {
+    return closedWorld.abstractValueDomain.dynamicType;
+  }
+
+  @override
+  AbstractValue resultOfParameter(Local parameter) {
+    return _trivialParameterResult;
+  }
+
+  @override
+  GlobalTypeInferenceMemberResult resultOfMember(MemberEntity member) {
+    return _trivialMemberResult;
+  }
+}
+
+class TrivialGlobalTypeInferenceMemberResult
+    implements GlobalTypeInferenceMemberResult {
+  final AbstractValue dynamicType;
+
+  TrivialGlobalTypeInferenceMemberResult(this.dynamicType);
+
+  @override
+  AbstractValue get type => dynamicType;
+
+  @override
+  AbstractValue get returnType => dynamicType;
+
+  @override
+  bool get throwsAlways => false;
+
+  @override
+  AbstractValue typeOfIteratorCurrent(ir.Node node) => null;
+
+  @override
+  AbstractValue typeOfIteratorMoveNext(ir.Node node) => null;
+
+  @override
+  AbstractValue typeOfIterator(ir.Node node) => null;
+
+  @override
+  AbstractValue typeOfGetter(ir.Node node) => null;
+
+  @override
+  AbstractValue typeOfSend(ir.Node node) => null;
+
+  @override
+  AbstractValue typeOfListLiteral(ir.Node node) => null;
+
+  @override
+  AbstractValue typeOfNewList(ir.Node node) => null;
+
+  @override
+  bool get isCalledOnce => false;
+}
+
+class DeadFieldGlobalTypeInferenceResult
+    implements GlobalTypeInferenceMemberResult {
+  final AbstractValue dynamicType;
+  final AbstractValue emptyType;
+
+  DeadFieldGlobalTypeInferenceResult(AbstractValueDomain domain)
+      : this.dynamicType = domain.dynamicType,
+        this.emptyType = domain.emptyType;
+
+  @override
+  AbstractValue get type => emptyType;
+
+  @override
+  AbstractValue get returnType => dynamicType;
+
+  @override
+  bool get throwsAlways => false;
+
+  @override
+  AbstractValue typeOfIteratorCurrent(ir.Node node) => null;
+
+  @override
+  AbstractValue typeOfIteratorMoveNext(ir.Node node) => null;
+
+  @override
+  AbstractValue typeOfIterator(ir.Node node) => null;
+
+  @override
+  AbstractValue typeOfGetter(ir.Node node) => null;
+
+  @override
+  AbstractValue typeOfSend(ir.Node node) => null;
+
+  @override
+  AbstractValue typeOfListLiteral(ir.Node node) => null;
+
+  @override
+  AbstractValue typeOfNewList(ir.Node node) => null;
+
+  @override
+  bool get isCalledOnce => false;
+}
+
+class DeadMethodGlobalTypeInferenceResult
+    implements GlobalTypeInferenceMemberResult {
+  final AbstractValue emptyType;
+  final AbstractValue functionType;
+
+  DeadMethodGlobalTypeInferenceResult(AbstractValueDomain domain)
+      : this.functionType = domain.functionType,
+        this.emptyType = domain.emptyType;
+
+  @override
+  AbstractValue get type => functionType;
+
+  @override
+  AbstractValue get returnType => emptyType;
+
+  @override
+  bool get throwsAlways => false;
+
+  @override
+  AbstractValue typeOfIteratorCurrent(ir.Node node) => null;
+
+  @override
+  AbstractValue typeOfIteratorMoveNext(ir.Node node) => null;
+
+  @override
+  AbstractValue typeOfIterator(ir.Node node) => null;
+
+  @override
+  AbstractValue typeOfGetter(ir.Node node) => null;
+
+  @override
+  AbstractValue typeOfSend(ir.Node node) => null;
+
+  @override
+  AbstractValue typeOfListLiteral(ir.Node node) => null;
+
+  @override
+  AbstractValue typeOfNewList(ir.Node node) => null;
+
+  @override
+  bool get isCalledOnce => false;
 }
diff --git a/tests/compiler/dart2js/codegen/expect_annotations_test.dart b/tests/compiler/dart2js/codegen/expect_annotations_test.dart
index d23eb44..93f0714 100644
--- a/tests/compiler/dart2js/codegen/expect_annotations_test.dart
+++ b/tests/compiler/dart2js/codegen/expect_annotations_test.dart
@@ -68,15 +68,15 @@
       'AssumeDynamicClass is unresolved.');
 
   void testTypeMatch(FunctionEntity function, TypeMask expectedParameterType,
-      TypeMask expectedReturnType, TypesInferrer inferrer) {
+      TypeMask expectedReturnType, GlobalTypeInferenceResults results) {
     compiler.codegenWorldBuilder.forEachParameterAsLocal(function,
         (Local parameter) {
-      TypeMask type = inferrer.getTypeOfParameter(parameter);
+      TypeMask type = results.resultOfParameter(parameter);
       Expect.equals(
           expectedParameterType, simplify(type, closedWorld), "$parameter");
     });
     if (expectedReturnType != null) {
-      TypeMask type = inferrer.getReturnTypeOfMember(function);
+      TypeMask type = results.resultOfMember(function).returnType;
       Expect.equals(
           expectedReturnType, simplify(type, closedWorld), "$function");
     }
@@ -107,13 +107,13 @@
         optimizerHints.assumeDynamic(
             closedWorld.elementEnvironment, closedWorld.commonElements, method),
         "Unexpected annotation of @AssumeDynamic on '$method'.");
-    TypesInferrer inferrer = compiler.globalInference.typesInferrerInternal;
+    GlobalTypeInferenceResults results =
+        compiler.globalInference.resultsForTesting;
     if (expectTrustTypeAnnotations && expectedParameterType != null) {
-      testTypeMatch(
-          method, expectedParameterType, expectedReturnType, inferrer);
+      testTypeMatch(method, expectedParameterType, expectedReturnType, results);
     } else if (expectAssumeDynamic) {
       testTypeMatch(
-          method, closedWorld.abstractValueDomain.dynamicType, null, inferrer);
+          method, closedWorld.abstractValueDomain.dynamicType, null, results);
     }
   }
 
diff --git a/tests/compiler/dart2js/codegen/trust_type_annotations_test.dart b/tests/compiler/dart2js/codegen/trust_type_annotations_test.dart
index 900a628..f7feed2 100644
--- a/tests/compiler/dart2js/codegen/trust_type_annotations_test.dart
+++ b/tests/compiler/dart2js/codegen/trust_type_annotations_test.dart
@@ -55,8 +55,8 @@
     var result = await runCompiler(
         memorySourceFiles: {'main.dart': TEST}, options: options);
     var compiler = result.compiler;
-    var typesInferrer = compiler.globalInference.typesInferrerInternal;
-    var closedWorld = typesInferrer.closedWorld;
+    var results = compiler.globalInference.resultsForTesting;
+    var closedWorld = results.closedWorld;
     var elementEnvironment = closedWorld.elementEnvironment;
 
     ClassEntity classA =
@@ -64,14 +64,14 @@
 
     checkReturn(String name, TypeMask type) {
       MemberEntity element = elementEnvironment.lookupClassMember(classA, name);
-      var mask = typesInferrer.getReturnTypeOfMember(element);
+      var mask = results.resultOfMember(element).returnType;
       Expect.isTrue(type.containsMask(mask, closedWorld));
     }
 
     checkType(String name, type) {
       MemberEntity element = elementEnvironment.lookupClassMember(classA, name);
-      Expect.isTrue(type.containsMask(
-          typesInferrer.getTypeOfMember(element), closedWorld));
+      Expect.isTrue(
+          type.containsMask(results.resultOfMember(element).type, closedWorld));
     }
 
     var intMask =
diff --git a/tests/compiler/dart2js/codegen/type_inference8_test.dart b/tests/compiler/dart2js/codegen/type_inference8_test.dart
index 1b14a0b..b3d232e 100644
--- a/tests/compiler/dart2js/codegen/type_inference8_test.dart
+++ b/tests/compiler/dart2js/codegen/type_inference8_test.dart
@@ -37,13 +37,13 @@
       memorySourceFiles: {'main.dart': TEST1},
       options: [Flags.disableInlining]);
   var compiler = result.compiler;
-  var typesInferrer = compiler.globalInference.typesInferrerInternal;
-  var closedWorld = typesInferrer.closedWorld;
+  var results = compiler.globalInference.resultsForTesting;
+  var closedWorld = results.closedWorld;
   var elementEnvironment = closedWorld.elementEnvironment;
   var commonMasks = closedWorld.abstractValueDomain;
   var element = elementEnvironment.lookupLibraryMember(
       elementEnvironment.mainLibrary, 'foo');
-  var mask = typesInferrer.getReturnTypeOfMember(element);
+  var mask = results.resultOfMember(element).returnType;
   var falseType =
       new ValueTypeMask(commonMasks.boolType, new FalseConstantValue());
   // 'foo' should always return false
@@ -52,7 +52,7 @@
   dynamic bar = elementEnvironment.lookupLibraryMember(
       elementEnvironment.mainLibrary, 'bar');
   compiler.codegenWorldBuilder.forEachParameterAsLocal(bar, (barArg) {
-    var barArgMask = typesInferrer.getTypeOfParameter(barArg);
+    var barArgMask = results.resultOfParameter(barArg);
     Expect.equals(falseType, barArgMask);
   });
   var barCode = compiler.backend.getGeneratedCode(bar);
@@ -85,19 +85,19 @@
       memorySourceFiles: {'main.dart': TEST2},
       options: [Flags.disableInlining]);
   var compiler = result.compiler;
-  var typesInferrer = compiler.globalInference.typesInferrerInternal;
-  var commonMasks = typesInferrer.closedWorld.abstractValueDomain;
-  var closedWorld = typesInferrer.closedWorld;
+  var results = compiler.globalInference.resultsForTesting;
+  var closedWorld = results.closedWorld;
+  var commonMasks = closedWorld.abstractValueDomain;
   var elementEnvironment = closedWorld.elementEnvironment;
   var element = elementEnvironment.lookupLibraryMember(
       elementEnvironment.mainLibrary, 'foo');
-  var mask = typesInferrer.getReturnTypeOfMember(element);
+  var mask = results.resultOfMember(element).returnType;
   // Can't infer value for foo's return type, it could be either true or false
   Expect.identical(commonMasks.boolType, mask);
   dynamic bar = elementEnvironment.lookupLibraryMember(
       elementEnvironment.mainLibrary, 'bar');
   compiler.codegenWorldBuilder.forEachParameterAsLocal(bar, (barArg) {
-    var barArgMask = typesInferrer.getTypeOfParameter(barArg);
+    var barArgMask = results.resultOfParameter(barArg);
     // The argument to bar should have the same type as the return type of foo
     Expect.identical(commonMasks.boolType, barArgMask);
   });
diff --git a/tests/compiler/dart2js/inference/data/js_interop.dart b/tests/compiler/dart2js/inference/data/js_interop.dart
index ecb615c..34767e1 100644
--- a/tests/compiler/dart2js/inference/data/js_interop.dart
+++ b/tests/compiler/dart2js/inference/data/js_interop.dart
@@ -10,6 +10,7 @@
 /*element: main:[null]*/
 main() {
   anonymousClass();
+  jsInteropClass();
 }
 
 @JS()
@@ -22,3 +23,28 @@
 
 /*strong.element: anonymousClass:[null|subclass=JavaScriptObject]*/
 anonymousClass() => new Class1(a: 1, b: '');
+
+@JS()
+class JsInteropClass {
+  /*element: JsInteropClass.:[null|subclass=Object]*/
+  external JsInteropClass();
+
+  /*element: JsInteropClass.getter:[null|subclass=Object]*/
+  external int get getter;
+
+  external void set setter(int /*[subclass=JSInt]*/ value);
+
+  /*element: JsInteropClass.method:[null|subclass=Object]*/
+  external int method(int /*[exact=JSUInt31]*/ a);
+}
+
+/*element: jsInteropClass:[subclass=JSInt]*/
+jsInteropClass() {
+  JsInteropClass cls = new JsInteropClass();
+  return cls. /*update: [null|subclass=JavaScriptObject]*/ setter =
+      cls. /*[null|subclass=JavaScriptObject]*/ getter
+          /*invoke: [null|subclass=JSInt]*/ +
+          cls. /*invoke: [subclass=JavaScriptObject]*/ method(0)
+          /*invoke: [subclass=JSInt]*/ +
+          10;
+}
diff --git a/tests/compiler/dart2js/inference/inference_test_helper.dart b/tests/compiler/dart2js/inference/inference_test_helper.dart
index b26366c..293e0d5 100644
--- a/tests/compiler/dart2js/inference/inference_test_helper.dart
+++ b/tests/compiler/dart2js/inference/inference_test_helper.dart
@@ -73,7 +73,7 @@
 /// IR visitor for computing inference data for a member.
 class TypeMaskIrComputer extends IrDataExtractor {
   final GlobalTypeInferenceResults results;
-  GlobalTypeInferenceElementResult result;
+  GlobalTypeInferenceMemberResult result;
   final KernelToElementMapForBuilding _elementMap;
   final KernelToLocalsMap _localsMap;
   final ClosureDataLookup _closureDataLookup;
@@ -106,9 +106,7 @@
   }
 
   String getParameterValue(Local parameter) {
-    GlobalTypeInferenceParameterResult elementResult =
-        results.resultOfParameter(parameter);
-    return getTypeMaskValue(elementResult.type);
+    return getTypeMaskValue(results.resultOfParameter(parameter));
   }
 
   String getTypeMaskValue(TypeMask typeMask) {
diff --git a/tests/compiler/dart2js/inference/list_tracer_test.dart b/tests/compiler/dart2js/inference/list_tracer_test.dart
index d474b9d..e475be6 100644
--- a/tests/compiler/dart2js/inference/list_tracer_test.dart
+++ b/tests/compiler/dart2js/inference/list_tracer_test.dart
@@ -210,13 +210,13 @@
   var result = await runCompiler(memorySourceFiles: {'main.dart': source});
   Expect.isTrue(result.isSuccess);
   var compiler = result.compiler;
-  var typesInferrer = compiler.globalInference.typesInferrerInternal;
-  var closedWorld = typesInferrer.closedWorld;
+  var results = compiler.globalInference.resultsForTesting;
+  var closedWorld = results.closedWorld;
   var commonMasks = closedWorld.abstractValueDomain;
 
   checkType(String name, type) {
     var element = findMember(closedWorld, name);
-    ContainerTypeMask mask = typesInferrer.getTypeOfMember(element);
+    ContainerTypeMask mask = results.resultOfMember(element).type;
     if (nullify) type = type.nullable();
     Expect.equals(type, simplify(mask.elementType, closedWorld), name);
   }
diff --git a/tests/compiler/dart2js/inference/load_deferred_library_test.dart b/tests/compiler/dart2js/inference/load_deferred_library_test.dart
index a6d709c..c9e89ff 100644
--- a/tests/compiler/dart2js/inference/load_deferred_library_test.dart
+++ b/tests/compiler/dart2js/inference/load_deferred_library_test.dart
@@ -56,10 +56,9 @@
   MemberDefinition definition =
       backendStrategy.elementMap.getMemberDefinition(loadDeferredLibrary);
   ir.Procedure procedure = definition.node;
-  typeMask = compiler.globalInference.resultsForTesting
-      .resultOfParameter(localsMap
-          .getLocalVariable(procedure.function.positionalParameters.first))
-      .type;
+  typeMask = compiler.globalInference.resultsForTesting.resultOfParameter(
+      localsMap
+          .getLocalVariable(procedure.function.positionalParameters.first));
 
   if (trust) {
     Expect.equals(
diff --git a/tests/compiler/dart2js/inference/map_tracer_test.dart b/tests/compiler/dart2js/inference/map_tracer_test.dart
index 44426e8..aa7e497 100644
--- a/tests/compiler/dart2js/inference/map_tracer_test.dart
+++ b/tests/compiler/dart2js/inference/map_tracer_test.dart
@@ -5,7 +5,6 @@
 import 'package:async_helper/async_helper.dart';
 import 'package:compiler/src/compiler.dart';
 import 'package:compiler/src/elements/entities.dart';
-import 'package:compiler/src/inferrer/type_graph_inferrer.dart';
 import 'package:compiler/src/inferrer/typemasks/masks.dart';
 import 'package:compiler/src/types/abstract_value_domain.dart';
 import 'package:compiler/src/world.dart';
@@ -230,27 +229,27 @@
   Expect.isTrue(result.isSuccess);
   Compiler compiler = result.compiler;
   TypeMask keyType, valueType;
-  TypeGraphInferrer typesInferrer =
-      compiler.globalInference.typesInferrerInternal;
-  JClosedWorld closedWorld = typesInferrer.closedWorld;
+  GlobalTypeInferenceResults results =
+      compiler.globalInference.resultsForTesting;
+  JClosedWorld closedWorld = results.closedWorld;
   AbstractValueDomain commonMasks = closedWorld.abstractValueDomain;
   TypeMask emptyType = new TypeMask.nonNullEmpty();
   MemberEntity aKey = findMember(closedWorld, 'aKey');
-  TypeMask aKeyType = typesInferrer.getTypeOfMember(aKey);
+  TypeMask aKeyType = results.resultOfMember(aKey).type;
   if (keyElementName != null) {
     MemberEntity keyElement = findMember(closedWorld, keyElementName);
-    keyType = typesInferrer.getTypeOfMember(keyElement);
+    keyType = results.resultOfMember(keyElement).type;
   }
   if (valueElementName != null) {
     MemberEntity valueElement = findMember(closedWorld, valueElementName);
-    valueType = typesInferrer.getTypeOfMember(valueElement);
+    valueType = results.resultOfMember(valueElement).type;
   }
   if (keyType == null) keyType = emptyType;
   if (valueType == null) valueType = emptyType;
 
   checkType(String name, keyType, valueType) {
     MemberEntity element = findMember(closedWorld, name);
-    MapTypeMask mask = typesInferrer.getTypeOfMember(element);
+    MapTypeMask mask = results.resultOfMember(element).type;
     Expect.equals(keyType, simplify(mask.keyType, closedWorld), name);
     Expect.equals(valueType, simplify(mask.valueType, closedWorld), name);
   }