Include bounds in type literals

Change-Id: Ieb3e5b09e88c98f8943a6e7ca9031c8a6ab776e1
Reviewed-on: https://dart-review.googlesource.com/63820
Commit-Queue: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Sigmund Cherem <sigmund@google.com>
diff --git a/pkg/compiler/lib/src/common_elements.dart b/pkg/compiler/lib/src/common_elements.dart
index c54b666..8a39e86 100644
--- a/pkg/compiler/lib/src/common_elements.dart
+++ b/pkg/compiler/lib/src/common_elements.dart
@@ -1051,9 +1051,6 @@
   FunctionEntity get getRuntimeTypeArgumentIntercepted =>
       _findHelperFunction('getRuntimeTypeArgumentIntercepted');
 
-  FunctionEntity get runtimeTypeToString =>
-      _findHelperFunction('runtimeTypeToString');
-
   FunctionEntity get assertIsSubtype => _findHelperFunction('assertIsSubtype');
 
   FunctionEntity get checkSubtype => _findHelperFunction('checkSubtype');
diff --git a/pkg/compiler/lib/src/deferred_load.dart b/pkg/compiler/lib/src/deferred_load.dart
index 54daa5c..fa9b677 100644
--- a/pkg/compiler/lib/src/deferred_load.dart
+++ b/pkg/compiler/lib/src/deferred_load.dart
@@ -361,6 +361,9 @@
                 _collectTypeDependencies(type, dependencies);
               }
               break;
+            case TypeUseKind.RTI_VALUE:
+              failedAt(element, "Unexpected type use: $typeUse.");
+              break;
           }
         }, visitDynamicUse: (DynamicUse dynamicUse) {
           // TODO(johnniwinther): Use rti need data to skip unneeded type
diff --git a/pkg/compiler/lib/src/elements/types.dart b/pkg/compiler/lib/src/elements/types.dart
index dc244d9..231c558 100644
--- a/pkg/compiler/lib/src/elements/types.dart
+++ b/pkg/compiler/lib/src/elements/types.dart
@@ -264,8 +264,9 @@
 class TypedefType extends DartType {
   final TypedefEntity element;
   final List<DartType> typeArguments;
+  final FunctionType unaliased;
 
-  TypedefType(this.element, this.typeArguments);
+  TypedefType(this.element, this.typeArguments, this.unaliased);
 
   bool get isTypedef => true;
 
@@ -291,9 +292,11 @@
     }
     List<DartType> newTypeArguments =
         _substTypes(typeArguments, arguments, parameters);
-    if (!identical(typeArguments, newTypeArguments)) {
+    FunctionType newUnaliased = unaliased.subst(arguments, parameters);
+    if (!identical(typeArguments, newTypeArguments) ||
+        !identical(unaliased, newUnaliased)) {
       // Create a new type only if necessary.
-      return new TypedefType(element, newTypeArguments);
+      return new TypedefType(element, newTypeArguments, newUnaliased);
     }
     return this;
   }
diff --git a/pkg/compiler/lib/src/enqueue.dart b/pkg/compiler/lib/src/enqueue.dart
index c89e967..8a0d580 100644
--- a/pkg/compiler/lib/src/enqueue.dart
+++ b/pkg/compiler/lib/src/enqueue.dart
@@ -380,6 +380,9 @@
           _worldBuilder.registerTypeVariableTypeLiteral(type);
         }
         break;
+      case TypeUseKind.RTI_VALUE:
+        failedAt(CURRENT_ELEMENT_SPANNABLE, "Unexpected type use: $typeUse.");
+        break;
     }
   }
 
diff --git a/pkg/compiler/lib/src/js_backend/backend_impact.dart b/pkg/compiler/lib/src/js_backend/backend_impact.dart
index 9adf701..361ac44 100644
--- a/pkg/compiler/lib/src/js_backend/backend_impact.dart
+++ b/pkg/compiler/lib/src/js_backend/backend_impact.dart
@@ -448,7 +448,6 @@
     return _typeVariableExpression ??= new BackendImpact(staticUses: [
       _commonElements.setRuntimeTypeInfo,
       _commonElements.getRuntimeTypeInfo,
-      _commonElements.runtimeTypeToString,
       _commonElements.createRuntimeType
     ], otherImpacts: [
       listValues,
diff --git a/pkg/compiler/lib/src/js_backend/constant_emitter.dart b/pkg/compiler/lib/src/js_backend/constant_emitter.dart
index 0ce6141..f3e8913 100644
--- a/pkg/compiler/lib/src/js_backend/constant_emitter.dart
+++ b/pkg/compiler/lib/src/js_backend/constant_emitter.dart
@@ -16,7 +16,6 @@
 import 'allocator_analysis.dart' show JAllocatorAnalysis;
 import 'constant_system_javascript.dart';
 import 'js_backend.dart';
-import 'namer.dart';
 import 'runtime_types.dart';
 
 typedef jsAst.Expression _ConstantReferenceGenerator(ConstantValue constant);
@@ -42,7 +41,6 @@
   final RuntimeTypesNeed _rtiNeed;
   final RuntimeTypesEncoder _rtiEncoder;
   final JAllocatorAnalysis _allocatorAnalysis;
-  final Namer _namer;
   final CodeEmitterTask _task;
   final _ConstantReferenceGenerator constantReferenceGenerator;
   final _ConstantListGenerator makeConstantList;
@@ -59,7 +57,6 @@
       this._rtiNeed,
       this._rtiEncoder,
       this._allocatorAnalysis,
-      this._namer,
       this._task,
       this.constantReferenceGenerator,
       this.makeConstantList);
@@ -280,19 +277,21 @@
 
   @override
   jsAst.Expression visitType(TypeConstantValue constant, [_]) {
-    DartType type = constant.representedType;
-    jsAst.Name typeName;
-    Entity element;
-    if (type is InterfaceType) {
-      element = type.element;
-    } else if (type is TypedefType) {
-      element = type.element;
-    } else {
-      assert(type is DynamicType);
+    DartType type = constant.representedType.unaliased;
+
+    jsAst.Expression unexpected(TypeVariableType _variable) {
+      TypeVariableType variable = _variable;
+      throw failedAt(
+          NO_LOCATION_SPANNABLE,
+          "Unexpected type variable '${variable}'"
+          " in constant '${constant.toDartText()}'");
     }
-    typeName = _namer.runtimeTypeName(element);
-    return new jsAst.Call(getHelperProperty(_commonElements.createRuntimeType),
-        [js.quoteName(typeName)]);
+
+    jsAst.Expression rti =
+        _rtiEncoder.getTypeRepresentation(_emitter, type, unexpected);
+
+    return new jsAst.Call(
+        getHelperProperty(_commonElements.createRuntimeType), [rti]);
   }
 
   @override
diff --git a/pkg/compiler/lib/src/js_backend/enqueuer.dart b/pkg/compiler/lib/src/js_backend/enqueuer.dart
index 4e72531..7d9d0b3 100644
--- a/pkg/compiler/lib/src/js_backend/enqueuer.dart
+++ b/pkg/compiler/lib/src/js_backend/enqueuer.dart
@@ -210,6 +210,9 @@
           _worldBuilder.registerTypeVariableTypeLiteral(type);
         }
         break;
+      case TypeUseKind.RTI_VALUE:
+        _worldBuilder.registerTypeArgument(type);
+        break;
     }
   }
 
diff --git a/pkg/compiler/lib/src/js_backend/impact_transformer.dart b/pkg/compiler/lib/src/js_backend/impact_transformer.dart
index b7a388a..a4fb279 100644
--- a/pkg/compiler/lib/src/js_backend/impact_transformer.dart
+++ b/pkg/compiler/lib/src/js_backend/impact_transformer.dart
@@ -202,6 +202,9 @@
           }
           hasTypeLiteral = true;
           break;
+        case TypeUseKind.RTI_VALUE:
+          failedAt(CURRENT_ELEMENT_SPANNABLE, "Unexpected type use: $typeUse.");
+          break;
       }
     }
 
diff --git a/pkg/compiler/lib/src/js_backend/runtime_types.dart b/pkg/compiler/lib/src/js_backend/runtime_types.dart
index 0835bf8..00dd8de 100644
--- a/pkg/compiler/lib/src/js_backend/runtime_types.dart
+++ b/pkg/compiler/lib/src/js_backend/runtime_types.dart
@@ -250,6 +250,7 @@
         ..checkedInstance = true
         ..typeArgument = true
         ..checkedTypeArgument = true
+        ..typeLiteral = true
         ..functionType = _computeFunctionType(_elementEnvironment, cls,
             strongMode: options.strongMode);
       classUseMap[cls] = classUse;
@@ -340,10 +341,12 @@
 
       bool isNativeClass = _closedWorld.nativeData.isNativeClass(cls);
       if (classUse.typeArgument ||
+          classUse.typeLiteral ||
           (isNativeClass && classUse.checkedInstance)) {
         Substitution substitution = computeSubstitution(cls, cls);
         // We need [cls] at runtime - even if [cls] is not instantiated. Either
-        // as a type argument or for an is-test if [cls] is native.
+        // as a type argument, for a type literal or for an is-test if [cls] is
+        // native.
         checks.add(new TypeCheck(cls, substitution, needsIs: isNativeClass));
       }
 
@@ -492,7 +495,7 @@
 
     for (ClassEntity cls in classUseMap.keys) {
       ClassUse classUse = classUseMap[cls] ?? emptyUse;
-      if (classUse.instance || classUse.typeArgument) {
+      if (classUse.instance || classUse.typeArgument || classUse.typeLiteral) {
         // Add checks only for classes that are live either as instantiated
         // classes or type arguments passed at runtime.
         computeChecks(cls);
@@ -1935,54 +1938,69 @@
     Set<FunctionType> checkedFunctionTypes = new Set<FunctionType>();
 
     TypeVisitor liveTypeVisitor =
-        new TypeVisitor(onClass: (ClassEntity cls, {bool inTypeArgument}) {
+        new TypeVisitor(onClass: (ClassEntity cls, {TypeVisitorState state}) {
       ClassUse classUse = classUseMap.putIfAbsent(cls, () => new ClassUse());
-      if (inTypeArgument) {
-        classUse.typeArgument = true;
+      switch (state) {
+        case TypeVisitorState.typeArgument:
+          classUse.typeArgument = true;
+          break;
+        case TypeVisitorState.typeLiteral:
+          classUse.typeLiteral = true;
+          break;
+        case TypeVisitorState.direct:
+          break;
       }
     });
 
     TypeVisitor testedTypeVisitor =
-        new TypeVisitor(onClass: (ClassEntity cls, {bool inTypeArgument}) {
+        new TypeVisitor(onClass: (ClassEntity cls, {TypeVisitorState state}) {
       ClassUse classUse = classUseMap.putIfAbsent(cls, () => new ClassUse());
-      if (inTypeArgument) {
-        classUse.typeArgument = true;
-        classUse.checkedTypeArgument = true;
-      } else {
-        classUse.checkedInstance = true;
+      switch (state) {
+        case TypeVisitorState.typeArgument:
+          classUse.typeArgument = true;
+          classUse.checkedTypeArgument = true;
+          break;
+        case TypeVisitorState.typeLiteral:
+          break;
+        case TypeVisitorState.direct:
+          classUse.checkedInstance = true;
+          break;
       }
     });
 
     codegenWorldBuilder.instantiatedTypes.forEach((InterfaceType type) {
-      liveTypeVisitor.visitType(type, false);
+      liveTypeVisitor.visitType(type, TypeVisitorState.direct);
       ClassUse classUse =
           classUseMap.putIfAbsent(type.element, () => new ClassUse());
       classUse.instance = true;
       FunctionType callType = _types.getCallType(type);
       if (callType != null) {
-        testedTypeVisitor.visitType(callType, false);
+        testedTypeVisitor.visitType(callType, TypeVisitorState.direct);
       }
     });
 
     for (FunctionEntity element
         in codegenWorldBuilder.staticFunctionsNeedingGetter) {
       FunctionType functionType = _elementEnvironment.getFunctionType(element);
-      testedTypeVisitor.visitType(functionType, false);
+      testedTypeVisitor.visitType(functionType, TypeVisitorState.direct);
     }
 
     for (FunctionEntity element in codegenWorldBuilder.closurizedMembers) {
       FunctionType functionType = _elementEnvironment.getFunctionType(element);
-      testedTypeVisitor.visitType(functionType, false);
+      testedTypeVisitor.visitType(functionType, TypeVisitorState.direct);
     }
 
     void processMethodTypeArguments(_, Set<DartType> typeArguments) {
       for (DartType typeArgument in typeArguments) {
-        liveTypeVisitor.visit(typeArgument, true);
+        liveTypeVisitor.visit(typeArgument, TypeVisitorState.typeArgument);
       }
     }
 
     codegenWorldBuilder.forEachStaticTypeArgument(processMethodTypeArguments);
     codegenWorldBuilder.forEachDynamicTypeArgument(processMethodTypeArguments);
+    codegenWorldBuilder.constTypeLiterals.forEach((DartType type) {
+      liveTypeVisitor.visitType(type, TypeVisitorState.typeLiteral);
+    });
 
     bool isFunctionChecked = false;
 
@@ -1993,7 +2011,7 @@
         isFunctionChecked =
             isFunctionChecked || t.element == _commonElements.functionClass;
       }
-      testedTypeVisitor.visitType(t, false);
+      testedTypeVisitor.visitType(t, TypeVisitorState.direct);
     }
 
     explicitIsChecks.forEach(processCheckedType);
@@ -2057,7 +2075,7 @@
             DartType bound =
                 _elementEnvironment.getTypeVariableBound(typeVariable.element);
             processCheckedType(bound);
-            liveTypeVisitor.visit(bound, true);
+            liveTypeVisitor.visit(bound, TypeVisitorState.typeArgument);
           }
         }
       }
@@ -2334,6 +2352,7 @@
   final NativeBasicData _nativeData;
   // If true, compile using strong mode.
   final bool _strongMode;
+
   OnVariableCallback onVariable;
   ShouldEncodeTypedefCallback shouldEncodeTypedef;
   Map<TypeVariableType, jsAst.Expression> typedefBindings;
@@ -2413,7 +2432,7 @@
   jsAst.Expression visitInterfaceType(InterfaceType type, Emitter emitter) {
     jsAst.Expression name = getJavaScriptClassName(type.element, emitter);
     jsAst.Expression result;
-    if (type.treatAsRaw) {
+    if ((!_strongMode && type.treatAsRaw) || type.typeArguments.isEmpty) {
       result = name;
     } else {
       // Visit all type arguments. This is done even for jsinterop classes to
@@ -2770,64 +2789,73 @@
       'TypeCheck(cls=$cls,needsIs=$needsIs,substitution=$substitution)';
 }
 
-class TypeVisitor extends DartTypeVisitor<void, bool> {
+enum TypeVisitorState { direct, typeArgument, typeLiteral }
+
+class TypeVisitor extends DartTypeVisitor<void, TypeVisitorState> {
   Set<FunctionTypeVariable> _visitedFunctionTypeVariables =
       new Set<FunctionTypeVariable>();
 
-  final void Function(ClassEntity entity, {bool inTypeArgument}) onClass;
-  final void Function(TypeVariableEntity entity, {bool inTypeArgument})
+  final void Function(ClassEntity entity, {TypeVisitorState state}) onClass;
+  final void Function(TypeVariableEntity entity, {TypeVisitorState state})
       onTypeVariable;
-  final void Function(FunctionType type, {bool inTypeArgument}) onFunctionType;
+  final void Function(FunctionType type, {TypeVisitorState state})
+      onFunctionType;
 
   TypeVisitor({this.onClass, this.onTypeVariable, this.onFunctionType});
 
-  visitType(DartType type, bool inTypeArgument) =>
-      type.accept(this, inTypeArgument);
+  visitType(DartType type, TypeVisitorState state) => type.accept(this, state);
 
-  visitTypes(List<DartType> types, bool inTypeArgument) {
+  visitTypes(List<DartType> types, TypeVisitorState state) {
     for (DartType type in types) {
-      visitType(type, inTypeArgument);
+      visitType(type, state);
     }
   }
 
   @override
-  void visitTypeVariableType(TypeVariableType type, bool inTypeArgument) {
+  void visitTypeVariableType(TypeVariableType type, TypeVisitorState state) {
     if (onTypeVariable != null) {
-      onTypeVariable(type.element, inTypeArgument: inTypeArgument);
+      onTypeVariable(type.element, state: state);
     }
   }
 
   @override
-  visitInterfaceType(InterfaceType type, bool inTypeArgument) {
+  visitInterfaceType(InterfaceType type, TypeVisitorState state) {
     if (onClass != null) {
-      onClass(type.element, inTypeArgument: inTypeArgument);
+      onClass(type.element, state: state);
     }
-    visitTypes(type.typeArguments, true);
+    visitTypes(
+        type.typeArguments,
+        state == TypeVisitorState.typeLiteral
+            ? state
+            : TypeVisitorState.typeArgument);
   }
 
   @override
-  visitFunctionType(FunctionType type, bool inTypeArgument) {
+  visitFunctionType(FunctionType type, TypeVisitorState state) {
     if (onFunctionType != null) {
-      onFunctionType(type, inTypeArgument: inTypeArgument);
+      onFunctionType(type, state: state);
     }
     // Visit all nested types as type arguments; these types are not runtime
     // instances but runtime type representations.
-    visitType(type.returnType, true);
-    visitTypes(type.parameterTypes, true);
-    visitTypes(type.optionalParameterTypes, true);
-    visitTypes(type.namedParameterTypes, true);
+    state = state == TypeVisitorState.typeLiteral
+        ? state
+        : TypeVisitorState.typeArgument;
+    visitType(type.returnType, state);
+    visitTypes(type.parameterTypes, state);
+    visitTypes(type.optionalParameterTypes, state);
+    visitTypes(type.namedParameterTypes, state);
     _visitedFunctionTypeVariables.removeAll(type.typeVariables);
   }
 
   @override
-  visitTypedefType(TypedefType type, bool inTypeArgument) {
-    visitType(type.unaliased, inTypeArgument);
+  visitTypedefType(TypedefType type, TypeVisitorState state) {
+    visitType(type.unaliased, state);
   }
 
   @override
-  visitFunctionTypeVariable(FunctionTypeVariable type, bool inTypeArgument) {
+  visitFunctionTypeVariable(FunctionTypeVariable type, TypeVisitorState state) {
     if (_visitedFunctionTypeVariables.add(type)) {
-      visitType(type.bound, inTypeArgument);
+      visitType(type.bound, state);
     }
   }
 }
@@ -2914,6 +2942,17 @@
   ///
   bool checkedTypeArgument = false;
 
+  /// Whether the class is used in a constant type literal.
+  ///
+  /// For instance `A`, `B` and `C` in:
+  ///
+  ///     class A {}
+  ///     class B<T> {}
+  ///     class C {}
+  ///     main() => A == B<C>;
+  ///
+  bool typeLiteral = false;
+
   /// The function type of the class, if any.
   ///
   /// This is only set if the function type is needed at runtime. For instance,
@@ -2942,6 +2981,9 @@
     if (checkedTypeArgument) {
       properties.add('checkedTypeArgument');
     }
+    if (typeLiteral) {
+      properties.add('rtiValue');
+    }
     if (functionType != null) {
       properties.add('functionType');
     }
diff --git a/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart b/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart
index b8f4d31..d9910c9 100644
--- a/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart
@@ -167,7 +167,6 @@
         _closedWorld.rtiNeed,
         compiler.backend.rtiEncoder,
         _closedWorld.allocatorAnalysis,
-        namer,
         task,
         this.constantReference,
         constantListGenerator);
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
index 46bce90..2f22884 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
@@ -84,7 +84,6 @@
         _closedWorld.rtiNeed,
         compiler.backend.rtiEncoder,
         _closedWorld.allocatorAnalysis,
-        namer,
         task,
         this.generateConstantReference,
         constantListGenerator);
diff --git a/pkg/compiler/lib/src/js_model/elements.dart b/pkg/compiler/lib/src/js_model/elements.dart
index 79be26a..17de922 100644
--- a/pkg/compiler/lib/src/js_model/elements.dart
+++ b/pkg/compiler/lib/src/js_model/elements.dart
@@ -276,7 +276,9 @@
   @override
   DartType visitTypedefType(TypedefType type, EntityConverter converter) {
     return new TypedefType(
-        converter(type.element), visitList(type.typeArguments, converter));
+        converter(type.element),
+        visitList(type.typeArguments, converter),
+        visit(type.unaliased, converter));
   }
 
   @override
diff --git a/pkg/compiler/lib/src/js_model/js_strategy.dart b/pkg/compiler/lib/src/js_model/js_strategy.dart
index 9179c63..a613ed6 100644
--- a/pkg/compiler/lib/src/js_model/js_strategy.dart
+++ b/pkg/compiler/lib/src/js_model/js_strategy.dart
@@ -827,7 +827,8 @@
   DartType visitTypedefType(TypedefType type, _) {
     var element = toBackendEntity(type.element);
     var args = _visitList(type.typeArguments);
-    return new TypedefType(element, args);
+    var unaliased = convert(type.unaliased);
+    return new TypedefType(element, args, unaliased);
   }
 
   List<DartType> _visitList(List<DartType> list) =>
diff --git a/pkg/compiler/lib/src/kernel/element_map_impl.dart b/pkg/compiler/lib/src/kernel/element_map_impl.dart
index 0623dec..cdbfe78 100644
--- a/pkg/compiler/lib/src/kernel/element_map_impl.dart
+++ b/pkg/compiler/lib/src/kernel/element_map_impl.dart
@@ -983,7 +983,8 @@
     TypedefType typedefType = new TypedefType(
         typedef,
         new List<DartType>.filled(
-            node.typeParameters.length, const DynamicType()));
+            node.typeParameters.length, const DynamicType()),
+        getDartType(node.type));
     return _typedefs.register(
         typedef, new TypedefData(node, typedef, typedefType));
   }
@@ -1820,6 +1821,11 @@
             elementMap.getTypeVariable(node.parameter));
       }
     }
+    if (node.parameter.parent is ir.Typedef) {
+      // Typedefs are only used in type literals so we never need their type
+      // variables.
+      return const DynamicType();
+    }
     return new TypeVariableType(elementMap.getTypeVariable(node.parameter));
   }
 
@@ -2319,7 +2325,8 @@
               new TypedefType(
                   newTypedef,
                   new List<DartType>.filled(
-                      data.node.typeParameters.length, const DynamicType()))));
+                      data.node.typeParameters.length, const DynamicType()),
+                  getDartType(data.node.type))));
       assert(newTypedef.typedefIndex == oldTypedef.typedefIndex);
     }
     for (int memberIndex = 0;
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index 82c06b1..78867a0 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -2853,14 +2853,8 @@
         dartType, sourceElement,
         sourceInformation: sourceInformation);
     _pushStaticInvocation(
-        _commonElements.runtimeTypeToString,
-        <HInstruction>[value],
-        abstractValueDomain.stringType,
-        const <DartType>[],
-        sourceInformation: sourceInformation);
-    _pushStaticInvocation(
         _commonElements.createRuntimeType,
-        <HInstruction>[pop()],
+        <HInstruction>[value],
         _typeInferenceMap.getReturnTypeOf(_commonElements.createRuntimeType),
         const <DartType>[],
         sourceInformation: sourceInformation);
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index d72a6b5..947432d 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -2208,6 +2208,11 @@
     generateConstant(node.constant, node.sourceInformation);
 
     _registry.registerConstantUse(new ConstantUse.literal(node.constant));
+    if (node.constant.isType) {
+      TypeConstantValue typeConstant = node.constant;
+      _registry.registerTypeUse(
+          new TypeUse.constTypeLiteral(typeConstant.representedType));
+    }
   }
 
   visitNot(HNot node) {
diff --git a/pkg/compiler/lib/src/universe/codegen_world_builder.dart b/pkg/compiler/lib/src/universe/codegen_world_builder.dart
index fecaed8..8c448bd 100644
--- a/pkg/compiler/lib/src/universe/codegen_world_builder.dart
+++ b/pkg/compiler/lib/src/universe/codegen_world_builder.dart
@@ -77,6 +77,9 @@
   /// an ordering that is less sensitive to perturbations in the source code.
   List<ConstantValue> getConstantsForEmission(
       [Comparator<ConstantValue> preSortCompare]);
+
+  /// Returns the types that are live as constant type literals.
+  Iterable<DartType> get constTypeLiterals;
 }
 
 class CodegenWorldBuilderImpl extends WorldBuilderBase
@@ -162,6 +165,8 @@
   final KernelToWorldBuilder _elementMap;
   final GlobalLocalsMap _globalLocalsMap;
 
+  final Set<DartType> _liveTypeArguments = new Set<DartType>();
+
   CodegenWorldBuilderImpl(
       this._elementMap,
       this._globalLocalsMap,
@@ -688,4 +693,10 @@
       f(member);
     });
   }
+
+  void registerTypeArgument(DartType type) {
+    _liveTypeArguments.add(type);
+  }
+
+  Iterable<DartType> get constTypeLiterals => _liveTypeArguments;
 }
diff --git a/pkg/compiler/lib/src/universe/use.dart b/pkg/compiler/lib/src/universe/use.dart
index 0db511d..5cfeed7 100644
--- a/pkg/compiler/lib/src/universe/use.dart
+++ b/pkg/compiler/lib/src/universe/use.dart
@@ -582,6 +582,7 @@
   NATIVE_INSTANTIATION,
   IMPLICIT_CAST,
   PARAMETER_CHECK,
+  RTI_VALUE,
 }
 
 /// Use of a [DartType].
@@ -629,6 +630,9 @@
       case TypeUseKind.PARAMETER_CHECK:
         sb.write('param:');
         break;
+      case TypeUseKind.RTI_VALUE:
+        sb.write('typeArg:');
+        break;
     }
     sb.write(type);
     return sb.toString();
@@ -692,6 +696,11 @@
     return new TypeUse.internal(type, TypeUseKind.NATIVE_INSTANTIATION);
   }
 
+  /// [type] used as a direct RTI value.
+  factory TypeUse.constTypeLiteral(DartType type) {
+    return new TypeUse.internal(type, TypeUseKind.RTI_VALUE);
+  }
+
   bool operator ==(other) {
     if (identical(this, other)) return true;
     if (other is! TypeUse) return false;
diff --git a/sdk/lib/_internal/js_runtime/lib/js_helper.dart b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
index 9e2f105..6e5d05d 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_helper.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
@@ -348,8 +348,7 @@
     int start = _arguments.length - _typeArgumentCount;
     var list = <Type>[];
     for (int index = 0; index < _typeArgumentCount; index++) {
-      list.add(
-          createRuntimeType(runtimeTypeToString(_arguments[start + index])));
+      list.add(createRuntimeType(_arguments[start + index]));
     }
     return list;
   }
@@ -3027,7 +3026,8 @@
 
   toString() {
     var receiver = _receiver == null ? _self : _receiver;
-    return "Closure '$_name' of ${Primitives.objectToHumanReadableString(receiver)}";
+    return "Closure '$_name' of "
+        "${Primitives.objectToHumanReadableString(receiver)}";
   }
 
   @NoInline()
@@ -3062,8 +3062,8 @@
   @NoSideEffects()
   static String computeFieldNamed(String fieldName) {
     var template = new BoundClosure('self', 'target', 'receiver', 'name');
-    var names = JSArray
-        .markFixedList(JS('', 'Object.getOwnPropertyNames(#)', template));
+    var names = JSArray.markFixedList(
+        JS('', 'Object.getOwnPropertyNames(#)', template));
     for (int i = 0; i < names.length; i++) {
       var name = names[i];
       if (JS('bool', '#[#] === #', template, name, fieldName)) {
@@ -3556,8 +3556,8 @@
 
   /// Normal type error caused by a failed subtype test.
   TypeErrorImplementation(Object value, String type)
-      : message = "TypeError: ${Error.safeToString(value)}: "
-            "type '${_typeDescription(value)}' is not a subtype of type '$type'";
+      : message = "TypeError: ${Error.safeToString(value)}: type "
+            "'${_typeDescription(value)}' is not a subtype of type '$type'";
 
   TypeErrorImplementation.fromMessage(String this.message);
 
@@ -3571,8 +3571,8 @@
 
   /// Normal cast error caused by a failed type cast.
   CastErrorImplementation(Object value, Object type)
-      : message = "CastError: ${Error.safeToString(value)}: "
-            "type '${_typeDescription(value)}' is not a subtype of type '$type'";
+      : message = "CastError: ${Error.safeToString(value)}: type "
+            "'${_typeDescription(value)}' is not a subtype of type '$type'";
 
   String toString() => message;
 }
diff --git a/sdk/lib/_internal/js_runtime/lib/js_rti.dart b/sdk/lib/_internal/js_runtime/lib/js_rti.dart
index 74a6352..f724172 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_rti.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_rti.dart
@@ -42,26 +42,28 @@
 
 part of _js_helper;
 
-Type createRuntimeType(String name) {
-  // Use a 'JS' cast to String.  Since this is registered as used by the
-  // backend, type inference assumes the worst (name is dynamic).
-  return new TypeImpl(JS('String', '#', name));
+/// Called from generated code.
+Type createRuntimeType(rti) {
+  return new TypeImpl(rti);
 }
 
 class TypeImpl implements Type {
-  final String _typeName;
+  final dynamic _rti;
+  String __typeName;
   String _unmangledName;
+  int _hashCode;
 
-  TypeImpl(this._typeName);
+  TypeImpl(this._rti);
+
+  String get _typeName => __typeName ??= runtimeTypeToString(_rti);
 
   String toString() {
-    if (_unmangledName != null) return _unmangledName;
-    String unmangledName = unmangleAllIdentifiersIfPreservedAnyways(_typeName);
-    return _unmangledName = unmangledName;
+    return _unmangledName ??=
+        unmangleAllIdentifiersIfPreservedAnyways(_typeName);
   }
 
   // TODO(ahe): This is a poor hashCode as it collides with its name.
-  int get hashCode => _typeName.hashCode;
+  int get hashCode => _hashCode ??= _typeName.hashCode;
 
   bool operator ==(other) {
     return (other is TypeImpl) && _typeName == other._typeName;
@@ -171,10 +173,10 @@
  * of type 4, the JavaScript array, where the first element represents the class
  * and the remaining elements represent the type arguments.
  */
-String _getRuntimeTypeAsStringV1(var rti, {String onTypeVariable(int i)}) {
+String _getRuntimeTypeAsStringV1(var rti) {
   assert(isJsArray(rti));
   String className = rawRtiToJsConstructorName(getIndex(rti, 0));
-  return '$className${joinArgumentsV1(rti, 1, onTypeVariable: onTypeVariable)}';
+  return '$className${joinArgumentsV1(rti, 1)}';
 }
 
 String _getRuntimeTypeAsStringV2(var rti, List<String> genericContext) {
@@ -186,29 +188,27 @@
 /// Returns a human-readable representation of the type representation [rti].
 ///
 /// Called from generated code.
-///
-/// [onTypeVariable] is used only from dart:mirrors.
 @NoInline()
-String runtimeTypeToString(var rti, {String onTypeVariable(int i)}) {
+String runtimeTypeToString(var rti) {
   return JS_GET_FLAG('STRONG_MODE')
       ? runtimeTypeToStringV2(rti, null)
-      : runtimeTypeToStringV1(rti, onTypeVariable: onTypeVariable);
+      : runtimeTypeToStringV1(rti);
 }
 
-String runtimeTypeToStringV1(var rti, {String onTypeVariable(int i)}) {
+String runtimeTypeToStringV1(var rti) {
   if (rti == null) {
     return 'dynamic';
   }
   if (isJsArray(rti)) {
     // A list representing a type with arguments.
-    return _getRuntimeTypeAsStringV1(rti, onTypeVariable: onTypeVariable);
+    return _getRuntimeTypeAsStringV1(rti);
   }
   if (isJsFunction(rti)) {
     // A reference to the constructor.
     return rawRtiToJsConstructorName(rti);
   }
   if (rti is int) {
-    return '${onTypeVariable == null ? rti : onTypeVariable(rti)}';
+    return '${rti}';
   }
   String functionPropertyName = JS_GET_NAME(JsGetName.FUNCTION_TYPE_TAG);
   if (JS('bool', 'typeof #[#] != "undefined"', rti, functionPropertyName)) {
@@ -218,9 +218,9 @@
     String typedefPropertyName = JS_GET_NAME(JsGetName.TYPEDEF_TAG);
     var typedefInfo = JS('', '#[#]', rti, typedefPropertyName);
     if (typedefInfo != null) {
-      return runtimeTypeToStringV1(typedefInfo, onTypeVariable: onTypeVariable);
+      return runtimeTypeToStringV1(typedefInfo);
     }
-    return _functionRtiToStringV1(rti, onTypeVariable);
+    return _functionRtiToStringV1(rti);
   }
   // We should not get here.
   return 'unknown-reified-type';
@@ -263,7 +263,7 @@
   return 'unknown-reified-type';
 }
 
-String _functionRtiToStringV1(var rti, String onTypeVariable(int i)) {
+String _functionRtiToStringV1(var rti) {
   String returnTypeText;
   String voidTag = JS_GET_NAME(JsGetName.FUNCTION_TYPE_VOID_RETURN_TAG);
   if (JS('bool', '!!#[#]', rti, voidTag)) {
@@ -271,8 +271,7 @@
   } else {
     String returnTypeTag = JS_GET_NAME(JsGetName.FUNCTION_TYPE_RETURN_TYPE_TAG);
     var returnRti = JS('', '#[#]', rti, returnTypeTag);
-    returnTypeText =
-        runtimeTypeToStringV1(returnRti, onTypeVariable: onTypeVariable);
+    returnTypeText = runtimeTypeToStringV1(returnRti);
   }
 
   String argumentsText = '';
@@ -285,8 +284,7 @@
     List arguments = JS('JSFixedArray', '#[#]', rti, requiredParamsTag);
     for (var argument in arguments) {
       argumentsText += sep;
-      argumentsText +=
-          runtimeTypeToStringV1(argument, onTypeVariable: onTypeVariable);
+      argumentsText += runtimeTypeToStringV1(argument);
       sep = ', ';
     }
   }
@@ -300,8 +298,7 @@
     sep = '';
     for (var argument in optionalArguments) {
       argumentsText += sep;
-      argumentsText +=
-          runtimeTypeToStringV1(argument, onTypeVariable: onTypeVariable);
+      argumentsText += runtimeTypeToStringV1(argument);
       sep = ', ';
     }
     argumentsText += ']';
@@ -316,9 +313,8 @@
     sep = '';
     for (String name in extractKeys(namedArguments)) {
       argumentsText += sep;
-      argumentsText += runtimeTypeToStringV1(
-          JS('', '#[#]', namedArguments, name),
-          onTypeVariable: onTypeVariable);
+      argumentsText +=
+          runtimeTypeToStringV1(JS('', '#[#]', namedArguments, name));
       argumentsText += ' $name';
       sep = ', ';
     }
@@ -454,8 +450,7 @@
       : joinArgumentsV1(types, startIndex);
 }
 
-String joinArgumentsV1(var types, int startIndex,
-    {String onTypeVariable(int i)}) {
+String joinArgumentsV1(var types, int startIndex) {
   if (types == null) return '';
   assert(isJsArray(types));
   bool firstArgument = true;
@@ -471,8 +466,7 @@
     if (argument != null) {
       allDynamic = false;
     }
-    buffer
-        .write(runtimeTypeToStringV1(argument, onTypeVariable: onTypeVariable));
+    buffer.write(runtimeTypeToStringV1(argument));
   }
   return allDynamic ? '' : '<$buffer>';
 }
@@ -480,22 +474,19 @@
 String joinArgumentsV2(var types, int startIndex, List<String> genericContext) {
   if (types == null) return '';
   assert(isJsArray(types));
-  bool firstArgument = true;
+  var separator = '';
   bool allDynamic = true;
   StringBuffer buffer = new StringBuffer('');
   for (int index = startIndex; index < getLength(types); index++) {
-    if (firstArgument) {
-      firstArgument = false;
-    } else {
-      buffer.write(', ');
-    }
+    buffer.write(separator);
+    separator = ', ';
     var argument = getIndex(types, index);
     if (argument != null) {
       allDynamic = false;
     }
     buffer.write(runtimeTypeToStringV2(argument, genericContext));
   }
-  return allDynamic ? '' : '<$buffer>';
+  return (!JS_GET_FLAG('STRONG_MODE') && allDynamic) ? '' : '<$buffer>';
 }
 
 /**
@@ -519,9 +510,32 @@
   return "$className${joinArguments(rti, 0)}";
 }
 
+/// Returns the full type of [o] in the runtime type representation.
+getRti(o) {
+  if (o is Closure) {
+    // This excludes classes that implement Function via a `call` method, but
+    // includes classes generated to represent closures in closure conversion.
+    var functionRti = extractFunctionTypeObjectFrom(o);
+    if (functionRti != null) return functionRti;
+  }
+  var interceptor = getInterceptor(o);
+  var type = getRawRuntimeType(interceptor);
+  if (o == null) return type;
+  if (JS('bool', 'typeof # != "object"', o)) return type;
+  var rti = getRuntimeTypeInfo(o);
+  if (rti != null) {
+    // If the type has type variables (that is, `rti != null`), make a copy of
+    // the type arguments and insert [o] in the first position to create a
+    // compound type representation.
+    rti = JS('JSExtendableArray', '#.slice()', rti); // Make a copy.
+    JS('', '#.splice(0, 0, #)', rti, type); // Insert type at position 0.
+    type = rti;
+  }
+  return type;
+}
+
 Type getRuntimeType(var object) {
-  String type = getRuntimeTypeString(object);
-  return new TypeImpl(type);
+  return new TypeImpl(getRti(object));
 }
 
 /**
diff --git a/tests/co19/co19-dart2js.status b/tests/co19/co19-dart2js.status
index 4c34ac7..deb4a7f 100644
--- a/tests/co19/co19-dart2js.status
+++ b/tests/co19/co19-dart2js.status
@@ -616,7 +616,6 @@
 LayoutTests/fast/dom/Range/range-expand_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/Range/range-insertNode-separate-endContainer_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/Range/range-insertNode-splittext_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/dom/SelectorAPI/dumpNodeList-2_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/StyleSheet/css-medialist-item_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/StyleSheet/detached-parent-rule-without-wrapper_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/StyleSheet/detached-stylesheet-without-wrapper_t01: RuntimeError # Please triage this failure
@@ -662,7 +661,6 @@
 LayoutTests/fast/dom/set-innerHTML_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/shadow/distribution-crash_t01: RuntimeError
 LayoutTests/fast/dom/shadow/distribution-update-recalcs-style_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/dom/shadow/event-path_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/shadow/insertion-point-list-menu-crash_t01: RuntimeError
 LayoutTests/fast/dom/shadow/insertion-point-shadow-crash_t01: RuntimeError
 LayoutTests/fast/dom/shadow/insertion-point-video-crash_t01: RuntimeError
@@ -1744,7 +1742,6 @@
 LayoutTests/fast/dom/Range/range-detached-exceptions_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/Range/range-insertNode-separate-endContainer_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/Range/range-insertNode-splittext_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/dom/SelectorAPI/dumpNodeList-2_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/StyleSheet/css-medialist-item_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/StyleSheet/detached-stylesheet-without-wrapper_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/Window/getMatchedCSSRules-with-pseudo-elements-complex_t01: Pass, RuntimeError # Issue 29634
@@ -1771,7 +1768,6 @@
 LayoutTests/fast/dom/partial-layout-overlay-scrollbars_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/set-innerHTML_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/shadow/content-pseudo-element-css-text_t01: Pass, RuntimeError # Issue 29634
-LayoutTests/fast/dom/shadow/event-path_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/shadow/host-context-pseudo-class-css-text_t01: Pass, RuntimeError # Issue 29634
 LayoutTests/fast/dom/shadow/host-pseudo-class-css-text_t01: Pass, RuntimeError # Issue 29634
 LayoutTests/fast/dom/shadow/pseudoclass-update-checked-option_t01: RuntimeError # Please triage this failure
@@ -2713,7 +2709,6 @@
 LayoutTests/fast/dom/Range/range-insertNode-separate-endContainer_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/Range/range-insertNode-splittext_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/SelectorAPI/caseTagX_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/dom/SelectorAPI/dumpNodeList-2_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/StyleSheet/css-insert-import-rule-to-shadow-stylesheets_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/StyleSheet/css-medialist-item_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/StyleSheet/detached-parent-rule-without-wrapper_t01: RuntimeError # Please triage this failure
@@ -2810,7 +2805,6 @@
 LayoutTests/fast/dom/shadow/elementfrompoint_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/shadow/elements-in-frameless-document_t01: RuntimeError # Issue 28983
 LayoutTests/fast/dom/shadow/event-path-not-in-document_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/dom/shadow/event-path_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/shadow/form-in-shadow_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/shadow/get-distributed-nodes-orphan_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/shadow/get-element-by-id-in-shadow-mutation_t01: RuntimeError # Please triage this failure
@@ -4311,7 +4305,6 @@
 LayoutTests/fast/dom/Selection/getRangeAt_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/SelectorAPI/caseID_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/SelectorAPI/caseTagX_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/dom/SelectorAPI/dumpNodeList-2_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/StyleSheet/css-insert-import-rule-to-shadow-stylesheets_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/StyleSheet/css-medialist-item_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/StyleSheet/detached-parent-rule-without-wrapper_t01: RuntimeError # Please triage this failure
@@ -4440,7 +4433,6 @@
 LayoutTests/fast/dom/shadow/distribution-update-recalcs-style_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/shadow/elementfrompoint_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/shadow/elements-in-frameless-document_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/dom/shadow/event-path_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/shadow/get-distributed-nodes-orphan_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/shadow/get-element-by-id-in-shadow-mutation_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/shadow/getComputedStyle-composed-parent-dirty_t01: RuntimeError # Please triage this failure
@@ -5885,7 +5877,6 @@
 LayoutTests/fast/dom/Range/range-isPointInRange_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/Range/range-on-detached-node_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/Range/surroundContents-for-detached-node_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/dom/SelectorAPI/dumpNodeList-2_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/StyleSheet/css-insert-import-rule-to-shadow-stylesheets_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/StyleSheet/css-medialist-item_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/StyleSheet/detached-shadow-style_t01: RuntimeError # Please triage this failure
@@ -5961,7 +5952,6 @@
 LayoutTests/fast/dom/shadow/elementfrompoint_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/shadow/elements-in-frameless-document_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/shadow/event-path-not-in-document_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/dom/shadow/event-path_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/shadow/form-in-shadow_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/shadow/get-distributed-nodes-orphan_t01: RuntimeError # Please triage this failure
 LayoutTests/fast/dom/shadow/get-element-by-id-in-shadow-mutation_t01: RuntimeError # Please triage this failure
diff --git a/tests/compiler/dart2js/inference/data/non_null.dart b/tests/compiler/dart2js/inference/data/non_null.dart
new file mode 100644
index 0000000..da87bbe
--- /dev/null
+++ b/tests/compiler/dart2js/inference/data/non_null.dart
@@ -0,0 +1,52 @@
+// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/*element: main:[null]*/
+main() {
+  nonNullStaticField();
+  nonNullInstanceField1();
+  nonNullInstanceField2();
+  nonNullLocal();
+}
+
+/*element: staticField:[null|exact=JSUInt31]*/
+var staticField;
+
+/*element: nonNullStaticField:[exact=JSUInt31]*/
+nonNullStaticField() => staticField ??= 42;
+
+/*element: Class1.:[exact=Class1]*/
+class Class1 {
+  /*element: Class1.field:[null|exact=JSUInt31]*/
+  var field;
+}
+
+/*element: nonNullInstanceField1:[exact=JSUInt31]*/
+nonNullInstanceField1() {
+  return new Class1(). /*[exact=Class1]*/ /*update: [exact=Class1]*/ field ??=
+      42;
+}
+
+/*element: Class2.:[exact=Class2]*/
+class Class2 {
+  /*element: Class2.field:[null|exact=JSUInt31]*/
+  var field;
+
+  /*element: Class2.method:[exact=JSUInt31]*/
+  method() {
+    return /*[exact=Class2]*/ /*update: [exact=Class2]*/ field ??= 42;
+  }
+}
+
+/*element: nonNullInstanceField2:[exact=JSUInt31]*/
+nonNullInstanceField2() {
+  return new Class2(). /*invoke: [exact=Class2]*/ method();
+}
+
+// TODO(johnniwinther): We should infer that the returned value cannot be null.
+/*element: nonNullLocal:[null|exact=JSUInt31]*/
+nonNullLocal() {
+  var local = null;
+  return local ??= 42;
+}
diff --git a/tests/compiler/dart2js/inference/data/type_literal.dart b/tests/compiler/dart2js/inference/data/type_literal.dart
new file mode 100644
index 0000000..b0d8246
--- /dev/null
+++ b/tests/compiler/dart2js/inference/data/type_literal.dart
@@ -0,0 +1,25 @@
+// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/*element: main:[null]*/
+main() {
+  typeLiteral();
+  typeLiteralToString();
+  typeLiteralSubstring();
+}
+
+/*element: typeLiteral:[exact=TypeImpl]*/
+typeLiteral() => Object;
+
+/*kernel.element: typeLiteralToString:[null|subclass=Object]*/
+/*strong.element: typeLiteralToString:[exact=JSString]*/
+typeLiteralToString() => (Object). /*invoke: [exact=TypeImpl]*/ toString();
+
+/*element: typeLiteralSubstring:[exact=JSString]*/
+typeLiteralSubstring() {
+  String name = (List). /*invoke: [exact=TypeImpl]*/ toString();
+  name = name. /*strong.invoke: [exact=JSString]*/ substring(
+      0, name. /*strong.invoke: [exact=JSString]*/ indexOf('<'));
+  return name;
+}
diff --git a/tests/compiler/dart2js/rti/data/indirect_type_literal.dart b/tests/compiler/dart2js/rti/data/indirect_type_literal.dart
new file mode 100644
index 0000000..bd9a39f
--- /dev/null
+++ b/tests/compiler/dart2js/rti/data/indirect_type_literal.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+class A<T> {}
+
+class B<T extends num> {}
+
+/*class: Indirect:exp,needsArgs*/
+class Indirect<T> {
+  Type get type => T;
+}
+
+void main() {
+  Expect.equals(A, new Indirect<A>().type);
+  Expect.equals(A, new Indirect<A<dynamic>>().type);
+  Expect.notEquals(A, new Indirect<A<num>>().type);
+  Expect.equals(B, new Indirect<B>().type);
+  Expect.equals(B, new Indirect<B<num>>().type);
+  Expect.notEquals(B, new Indirect<B<int>>().type);
+}
diff --git a/tests/compiler/dart2js/rti/emission/closure_function.dart b/tests/compiler/dart2js/rti/emission/closure_function.dart
index 9b11f64..1874f1a 100644
--- a/tests/compiler/dart2js/rti/emission/closure_function.dart
+++ b/tests/compiler/dart2js/rti/emission/closure_function.dart
@@ -10,6 +10,8 @@
 main() {
   test(
       /*kernel.checks=[],functionType,instance*/
-      /*strong.checks=[],instance*/ () {});
+      /*strong.checks=[],instance*/
+      /*omit.checks=[],instance*/
+      () {});
   test(null);
 }
diff --git a/tests/compiler/dart2js/rti/emission/closure_function_type.dart b/tests/compiler/dart2js/rti/emission/closure_function_type.dart
index 22ffd4f..b37395b 100644
--- a/tests/compiler/dart2js/rti/emission/closure_function_type.dart
+++ b/tests/compiler/dart2js/rti/emission/closure_function_type.dart
@@ -9,5 +9,9 @@
 
 main() {
   test(/*checks=[],functionType,instance*/ () {});
-  test(/*checks=[],functionType,instance*/ (a) {});
+  test(
+      /*kernel.checks=[],functionType,instance*/
+      /*strong.checks=[],instance*/
+      /*omit.checks=[],instance*/
+      (a) {});
 }
diff --git a/tests/compiler/dart2js/rti/emission/closure_signature_unneeded.dart b/tests/compiler/dart2js/rti/emission/closure_signature_unneeded.dart
index 6ffe4e3..52b2ec9 100644
--- a/tests/compiler/dart2js/rti/emission/closure_signature_unneeded.dart
+++ b/tests/compiler/dart2js/rti/emission/closure_signature_unneeded.dart
@@ -13,6 +13,7 @@
     return
         /*kernel.checks=[$signature],instance*/
         /*strong.checks=[],instance*/
+        /*omit.checks=[],instance*/
         (T t, String s) {};
   }
 }
diff --git a/tests/compiler/dart2js/rti/emission/dynamic_type_literal.dart b/tests/compiler/dart2js/rti/emission/dynamic_type_literal.dart
new file mode 100644
index 0000000..8f7ce92
--- /dev/null
+++ b/tests/compiler/dart2js/rti/emission/dynamic_type_literal.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/*class: global#Type:checks=[],instance,typeLiteral*/
+
+import "package:expect/expect.dart";
+
+void main() {
+  Expect.isTrue(dynamic is Type);
+  Expect.isFalse(dynamic == Type);
+}
diff --git a/tests/compiler/dart2js/rti/emission/function_type_argument_strong.dart b/tests/compiler/dart2js/rti/emission/function_type_argument_strong.dart
index faa845a..cac5f11 100644
--- a/tests/compiler/dart2js/rti/emission/function_type_argument_strong.dart
+++ b/tests/compiler/dart2js/rti/emission/function_type_argument_strong.dart
@@ -5,12 +5,14 @@
 import 'package:expect/expect.dart';
 import 'package:meta/dart2js.dart';
 
-/*class: C:checkedInstance,checks=[],instance,typeArgument*/
+/*strong.class: C:checkedInstance,checks=[],instance,typeArgument*/
+/*omit.class: C:checks=[],instance,typeArgument*/
 class C {
   call(int i) {}
 }
 
-/*class: D:checkedInstance,checks=[],instance,typeArgument*/
+/*strong.class: D:checkedInstance,checks=[],instance,typeArgument*/
+/*omit.class: D:checks=[],instance,typeArgument*/
 class D {
   call(double i) {}
 }
diff --git a/tests/compiler/dart2js/rti/emission/generic_methods_dynamic_02_strong.dart b/tests/compiler/dart2js/rti/emission/generic_methods_dynamic_02_strong.dart
index ccc9db9..e091714 100644
--- a/tests/compiler/dart2js/rti/emission/generic_methods_dynamic_02_strong.dart
+++ b/tests/compiler/dart2js/rti/emission/generic_methods_dynamic_02_strong.dart
@@ -6,10 +6,12 @@
 
 library generic_methods_dynamic_test;
 
-/*class: A:checkedInstance,checks=[],typeArgument*/
+/*strong.class: A:checkedInstance,checks=[],typeArgument*/
+/*omit.class: A:*/
 class A {}
 
-/*class: B:checks=[],instance*/
+/*strong.class: B:checks=[],instance*/
+/*omit.class: B:*/
 class B {}
 
 /*class: C:*/
diff --git a/tests/compiler/dart2js/rti/emission/jsinterop_generic_factory_args.dart b/tests/compiler/dart2js/rti/emission/jsinterop_generic_factory_args.dart
index de9bc8b..963c073 100644
--- a/tests/compiler/dart2js/rti/emission/jsinterop_generic_factory_args.dart
+++ b/tests/compiler/dart2js/rti/emission/jsinterop_generic_factory_args.dart
@@ -14,6 +14,7 @@
 
 /*kernel.class: A:checkedTypeArgument,checks=[],typeArgument*/
 /*strong.class: A:checkedInstance,checkedTypeArgument,checks=[],typeArgument*/
+/*omit.class: A:checkedTypeArgument,checks=[],typeArgument*/
 @JS()
 @anonymous
 class A<T> {
diff --git a/tests/compiler/dart2js/rti/emission/list.dart b/tests/compiler/dart2js/rti/emission/list.dart
index 997bd49..0c8d312 100644
--- a/tests/compiler/dart2js/rti/emission/list.dart
+++ b/tests/compiler/dart2js/rti/emission/list.dart
@@ -6,15 +6,18 @@
 
 /*kernel.class: global#JSArray:checkedInstance,checks=[$isIterable],instance*/
 /*strong.class: global#JSArray:checkedInstance,checks=[$isIterable,$isList],instance*/
+/*omit.class: global#JSArray:checkedInstance,checks=[$isIterable],instance*/
 
 /*class: global#Iterable:checkedInstance*/
 
 /*kernel.class: A:checkedTypeArgument,checks=[],typeArgument*/
 /*strong.class: A:checkedInstance,checkedTypeArgument,checks=[],typeArgument*/
+/*omit.class: A:checkedTypeArgument,checks=[],typeArgument*/
 class A {}
 
 /*kernel.class: B:checks=[],typeArgument*/
 /*strong.class: B:checkedInstance,checks=[],typeArgument*/
+/*omit.class: B:checks=[],typeArgument*/
 class B {}
 
 @noInline
diff --git a/tests/compiler/dart2js/rti/emission/local_function_list_literal_strong.dart b/tests/compiler/dart2js/rti/emission/local_function_list_literal_strong.dart
index f3ac8a5..e4ded08 100644
--- a/tests/compiler/dart2js/rti/emission/local_function_list_literal_strong.dart
+++ b/tests/compiler/dart2js/rti/emission/local_function_list_literal_strong.dart
@@ -4,7 +4,8 @@
 
 import 'package:expect/expect.dart';
 
-/*class: global#JSArray:checkedInstance,checks=[$isIterable,$isList],instance*/
+/*strong.class: global#JSArray:checkedInstance,checks=[$isIterable,$isList],instance*/
+/*omit.class: global#JSArray:checkedInstance,checks=[$isList],instance*/
 
 @NoInline()
 method<T>() {
diff --git a/tests/compiler/dart2js/rti/emission/runtime_type_instantiate_to_string1_strong.dart b/tests/compiler/dart2js/rti/emission/runtime_type_instantiate_to_string1_strong.dart
index da4456d..3123b79 100644
--- a/tests/compiler/dart2js/rti/emission/runtime_type_instantiate_to_string1_strong.dart
+++ b/tests/compiler/dart2js/rti/emission/runtime_type_instantiate_to_string1_strong.dart
@@ -3,7 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 
 main() {
-  /*checks=[],functionType,instance*/
+  /*strong.checks=[],functionType,instance*/
+  /*omit.checks=[],instance*/
   T id<T>(T t) => t;
   int Function(int) x = id;
   print("${x.runtimeType}");
diff --git a/tests/compiler/dart2js/rti/emission/static_argument_strong.dart b/tests/compiler/dart2js/rti/emission/static_argument_strong.dart
index 7bdc190..4df0ab4 100644
--- a/tests/compiler/dart2js/rti/emission/static_argument_strong.dart
+++ b/tests/compiler/dart2js/rti/emission/static_argument_strong.dart
@@ -4,18 +4,22 @@
 
 import 'package:meta/dart2js.dart';
 
-/*class: I1:checkedInstance*/
+/*strong.class: I1:checkedInstance*/
+/*omit.class: I1:*/
 class I1 {}
 
-/*class: I2:checkedInstance,checkedTypeArgument,checks=[],typeArgument*/
+/*strong.class: I2:checkedInstance,checkedTypeArgument,checks=[],typeArgument*/
+/*omit.class: I2:checkedTypeArgument,checks=[],typeArgument*/
 class I2 {}
 
 // TODO(32954): Exclude $isI1 because foo is only called directly.
-/*class: A:checks=[$isI1,$isI2],instance*/
+/*strong.class: A:checks=[$isI1,$isI2],instance*/
+/*omit.class: A:checks=[$isI2],instance*/
 class A implements I1, I2 {}
 
 // TODO(32954): Exclude $isI1 because foo is only called directly.
-/*class: B:checks=[$isI1,$isI2],instance*/
+/*strong.class: B:checks=[$isI1,$isI2],instance*/
+/*omit.class: B:checks=[$isI2],instance*/
 class B implements I1, I2 {}
 
 @noInline
diff --git a/tests/compiler/dart2js/rti/emission/type_literal.dart b/tests/compiler/dart2js/rti/emission/type_literal.dart
new file mode 100644
index 0000000..e46e083
--- /dev/null
+++ b/tests/compiler/dart2js/rti/emission/type_literal.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+
+/*class: Class1:checks=[],typeLiteral*/
+class Class1 {}
+
+/*class: Class2:checks=[],typeLiteral*/
+class Class2<X> {}
+
+void main() {
+  String name1 = '${Class1}';
+  String name2 = '${Class2}';
+  Expect.equals('Class1', name1);
+  Expect.equals('Class2<dynamic>', name2);
+}
diff --git a/tests/compiler/dart2js/rti/rti_emission_test.dart b/tests/compiler/dart2js/rti/rti_emission_test.dart
index a5aa305..36fefb6 100644
--- a/tests/compiler/dart2js/rti/rti_emission_test.dart
+++ b/tests/compiler/dart2js/rti/rti_emission_test.dart
@@ -27,6 +27,7 @@
       dataDir,
       const RtiEmissionDataComputer(),
       args: args,
+      testOmit: true,
       skipForStrong: [
         // Dart 1 semantics:
         'call.dart',
@@ -50,6 +51,7 @@
   static const String checkedInstance = 'checkedInstance';
   static const String typeArgument = 'typeArgument';
   static const String checkedTypeArgument = 'checkedTypeArgument';
+  static const String typeLiteral = 'typeLiteral';
   static const String functionType = 'functionType';
 }
 
@@ -87,6 +89,9 @@
       if (classUse.checkedTypeArgument) {
         features.add(Tags.checkedTypeArgument);
       }
+      if (classUse.typeLiteral) {
+        features.add(Tags.typeLiteral);
+      }
     }
     return features.getText();
   }
diff --git a/tests/compiler/dart2js/rti/type_representation_test.dart b/tests/compiler/dart2js/rti/type_representation_test.dart
index a4a6f9e..147cd0d 100644
--- a/tests/compiler/dart2js/rti/type_representation_test.dart
+++ b/tests/compiler/dart2js/rti/type_representation_test.dart
@@ -187,9 +187,11 @@
   // List<E>
   expect(elementEnvironment.getThisType(List_), '[$List_rep, $List_E_rep]');
   // List
-  expect(elementEnvironment.getRawType(List_), '$List_rep');
+  expect(elementEnvironment.getRawType(List_),
+      strongMode ? '[$List_rep,,]' : '$List_rep');
   // List<dynamic>
-  expect(instantiate(List_, [dynamic_]), '$List_rep');
+  expect(instantiate(List_, [dynamic_]),
+      strongMode ? '[$List_rep,,]' : '$List_rep');
   // List<int>
   expect(instantiate(List_, [int_]), '[$List_rep, $int_rep]');
   // List<Typedef1>
@@ -263,9 +265,11 @@
   expect(elementEnvironment.getThisType(Map_),
       '[$Map_rep, $Map_K_rep, $Map_V_rep]');
   // Map
-  expect(elementEnvironment.getRawType(Map_), '$Map_rep');
+  expect(elementEnvironment.getRawType(Map_),
+      strongMode ? '[$Map_rep,,,]' : '$Map_rep');
   // Map<dynamic,dynamic>
-  expect(instantiate(Map_, [dynamic_, dynamic_]), '$Map_rep');
+  expect(instantiate(Map_, [dynamic_, dynamic_]),
+      strongMode ? '[$Map_rep,,,]' : '$Map_rep');
   // Map<int,String>
   expect(
       instantiate(Map_, [int_, String_]), '[$Map_rep, $int_rep, $String_rep]');
diff --git a/tests/compiler/dart2js_extra/28749_test.dart b/tests/compiler/dart2js_extra/28749_test.dart
index ca4d3bf..1795ea6 100644
--- a/tests/compiler/dart2js_extra/28749_test.dart
+++ b/tests/compiler/dart2js_extra/28749_test.dart
@@ -37,7 +37,7 @@
 
 void main() {
   var name = '${Wrap}';
-  if (name.length < 4) return; // minified.
+  if ('$Object' != 'Object') return; // minified
 
   Expect.equals(
     'Wrap<(int) => ((int) => void) => (int) => void>',
diff --git a/tests/compiler/dart2js_extra/bounded_type_literal_test.dart b/tests/compiler/dart2js_extra/bounded_type_literal_test.dart
new file mode 100644
index 0000000..ad0fbe8
--- /dev/null
+++ b/tests/compiler/dart2js_extra/bounded_type_literal_test.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// dart2jsOptions=--strong
+
+import 'package:expect/expect.dart';
+
+class Foo<T extends num> {}
+
+main() {
+  var a = new Foo();
+  var b = Foo;
+  Expect.equals(a.runtimeType, b);
+
+  var runtimeTypeToString = "${a.runtimeType}";
+  var typeLiteralToString = "${b}";
+  Expect.equals(runtimeTypeToString, typeLiteralToString);
+
+  if ('$Object' == 'Object') {
+    // `true` if non-minified.
+    Expect.equals("Foo<num>", runtimeTypeToString);
+    Expect.equals("Foo<num>", typeLiteralToString);
+  }
+  print(runtimeTypeToString);
+  print(typeLiteralToString);
+}
diff --git a/tests/compiler/dart2js_extra/dart2js_extra.status b/tests/compiler/dart2js_extra/dart2js_extra.status
index 43feede..f56e2f2 100644
--- a/tests/compiler/dart2js_extra/dart2js_extra.status
+++ b/tests/compiler/dart2js_extra/dart2js_extra.status
@@ -101,6 +101,7 @@
 mirrors_used_warning_test/minif: Fail, OK # Tests warning that minified code will be broken.
 runtime_type_test: Fail, OK # Tests extected output of Type.toString().
 to_string_test: Fail # Issue 7179.
+type_literal_test: Fail, OK # Tests expected output of Type.toString().
 typevariable_typedef_test: Fail, OK # Tests expected output of Type.toString().
 
 [ $compiler == dart2js && !$strong ]
diff --git a/tests/compiler/dart2js_extra/dynamic_type_literal_test.dart b/tests/compiler/dart2js_extra/dynamic_type_literal_test.dart
new file mode 100644
index 0000000..3231717
--- /dev/null
+++ b/tests/compiler/dart2js_extra/dynamic_type_literal_test.dart
@@ -0,0 +1,14 @@
+// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// dart2jsOptions=--strong --omit-implicit-checks
+
+// Test generation of 'dynamic' type literals.
+
+import "package:expect/expect.dart";
+
+void main() {
+  Expect.isTrue(dynamic is Type);
+  Expect.isFalse(dynamic == Type);
+}
diff --git a/tests/compiler/dart2js_extra/generic_type_error_message_test.dart b/tests/compiler/dart2js_extra/generic_type_error_message_test.dart
new file mode 100644
index 0000000..8becaf9
--- /dev/null
+++ b/tests/compiler/dart2js_extra/generic_type_error_message_test.dart
@@ -0,0 +1,35 @@
+// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// dart2jsOptions=--strong
+
+import 'package:expect/expect.dart';
+
+class Foo<T extends num> {}
+
+class Bar<T extends num> {}
+
+main() {
+  test(new Foo(), Foo, expectTypeArguments: false);
+  test(new Bar() as Bar<num>, Bar, expectTypeArguments: true);
+}
+
+void test(dynamic object, Type type, {bool expectTypeArguments}) {
+  bool caught = false;
+  try {
+    print(type);
+    object as List<String>;
+  } catch (e) {
+    String expected = '$type';
+    if (!expectTypeArguments) {
+      expected = expected.substring(0, expected.indexOf('<'));
+    }
+    expected = "'$expected'";
+    Expect.isTrue(e.toString().contains(expected),
+        'Expected "$expected" in the message: $e');
+    caught = true;
+    print(e);
+  }
+  Expect.isTrue(caught);
+}
diff --git a/tests/compiler/dart2js_extra/indirect_type_literal_test.dart b/tests/compiler/dart2js_extra/indirect_type_literal_test.dart
new file mode 100644
index 0000000..8929796
--- /dev/null
+++ b/tests/compiler/dart2js_extra/indirect_type_literal_test.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// dart2jsOptions=--strong
+
+import "package:expect/expect.dart";
+
+class A<T> {}
+
+class B<T extends num> {}
+
+class Indirect<T> {
+  Type get type => T;
+}
+
+void main() {
+  Expect.equals(A, new Indirect<A>().type);
+  Expect.equals(A, new Indirect<A<dynamic>>().type);
+  Expect.notEquals(A, new Indirect<A<num>>().type);
+  Expect.equals(B, new Indirect<B>().type);
+  Expect.equals(B, new Indirect<B<num>>().type);
+  Expect.notEquals(B, new Indirect<B<int>>().type);
+}
diff --git a/tests/compiler/dart2js_extra/lax_runtime_type_instantiate_to_string_test.dart b/tests/compiler/dart2js_extra/lax_runtime_type_instantiate_to_string_test.dart
index d8b456c..26ba4e8 100644
--- a/tests/compiler/dart2js_extra/lax_runtime_type_instantiate_to_string_test.dart
+++ b/tests/compiler/dart2js_extra/lax_runtime_type_instantiate_to_string_test.dart
@@ -14,7 +14,7 @@
     // `true` if non-minified.
     // The signature of `id` is not otherwise needed so the instantiation
     // wrapper doesn't have a function type.
-    Expect.equals("Instantiation1", toString);
+    Expect.equals("Instantiation1<dynamic>", toString);
   }
   print(toString);
 }
diff --git a/tests/compiler/dart2js_extra/runtime_type_test.dart b/tests/compiler/dart2js_extra/runtime_type_test.dart
index c307ef4..f127dbe 100644
--- a/tests/compiler/dart2js_extra/runtime_type_test.dart
+++ b/tests/compiler/dart2js_extra/runtime_type_test.dart
@@ -2,6 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// dart2jsOptions=--strong
+
 // Test that Type.toString returns nice strings for native classes with
 // reserved names and for raw types.
 
@@ -14,17 +16,18 @@
 class Class$With$Dollar {}
 
 void main() {
-  Expect.equals('C', new C().runtimeType.toString());
+  Expect.equals('C<dynamic>', new C().runtimeType.toString());
   Expect.equals('C<int>', new C<int>().runtimeType.toString());
   Expect.equals('C<double>', new C<double>().runtimeType.toString());
   Expect.equals('C<num>', new C<num>().runtimeType.toString());
   Expect.equals('C<bool>', new C<bool>().runtimeType.toString());
-  Expect.equals('D', new D().runtimeType.toString());
+  Expect.equals('D<dynamic, dynamic, dynamic>', new D().runtimeType.toString());
   Expect.equals('D<dynamic, int, dynamic>',
       new D<dynamic, int, dynamic>().runtimeType.toString());
   D d = new D<dynamic, D, D<dynamic, dynamic, int>>();
   Expect.equals(
-      'D<dynamic, D, D<dynamic, dynamic, int>>', d.runtimeType.toString());
+      'D<dynamic, D<dynamic, dynamic, dynamic>, D<dynamic, dynamic, int>>',
+      d.runtimeType.toString());
   Expect.equals(r'C<Class$With$Dollar>',
       new C<Class$With$Dollar>().runtimeType.toString());
 }
diff --git a/tests/compiler/dart2js_extra/runtime_type_to_string1_test.dart b/tests/compiler/dart2js_extra/runtime_type_to_string1_test.dart
index 8c6cbb4..80fa25c 100644
--- a/tests/compiler/dart2js_extra/runtime_type_to_string1_test.dart
+++ b/tests/compiler/dart2js_extra/runtime_type_to_string1_test.dart
@@ -11,6 +11,11 @@
 }
 
 main() {
-  Expect.equals((Class).toString(), new Class().runtimeType.toString());
-  Expect.equals((Class).toString(), new Class<int>().runtimeType.toString());
+  // Since the type argument of `Class` is only needed for
+  // `.runtimeType.toString()`, it is not reified, and the toString is therefore
+  // only 'Class'.
+  String className = (Class).toString();
+  className = className.substring(0, className.indexOf('<'));
+  Expect.equals(className, new Class().runtimeType.toString());
+  Expect.equals(className, new Class<int>().runtimeType.toString());
 }
diff --git a/tests/compiler/dart2js_extra/type_error_message_test.dart b/tests/compiler/dart2js_extra/type_error_message_test.dart
index d097577..6f34931 100644
--- a/tests/compiler/dart2js_extra/type_error_message_test.dart
+++ b/tests/compiler/dart2js_extra/type_error_message_test.dart
@@ -25,12 +25,16 @@
       C<String, String> x = (new C<C<int, String>, String>()) as dynamic;
     } catch (e) {
       String nameOfC = (C).toString();
+      if (nameOfC.contains('<')) {
+        nameOfC = nameOfC.substring(0, nameOfC.indexOf('<'));
+      }
       String nameOfInt = (int).toString();
       String nameOfString = (String).toString();
       String expected =
-          '$nameOfC<$nameOfC<$nameOfInt, $nameOfString>, $nameOfString>';
+          "'$nameOfC<$nameOfC<$nameOfInt, $nameOfString>, $nameOfString>'";
       Expect.isTrue(e.toString().contains(expected),
-          'Expected "$expected" in the message');
+          'Expected "$expected" in the message: $e');
+      print(e);
       caught = true;
     }
     Expect.isTrue(caught);
diff --git a/tests/compiler/dart2js_extra/type_literal_test.dart b/tests/compiler/dart2js_extra/type_literal_test.dart
new file mode 100644
index 0000000..4426847
--- /dev/null
+++ b/tests/compiler/dart2js_extra/type_literal_test.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// dart2jsOptions=--strong
+
+import 'package:expect/expect.dart';
+
+class Class1 {}
+
+class Class2<X> {}
+
+void main() {
+  String name1 = '${Class1}';
+  String name2 = '${Class2}';
+  Expect.equals('Class1', name1);
+  Expect.equals('Class2<dynamic>', name2);
+}
diff --git a/tests/language_2/cyclic_type2_test.dart b/tests/language_2/cyclic_type2_test.dart
index c90cf23..0b62f2f 100644
--- a/tests/language_2/cyclic_type2_test.dart
+++ b/tests/language_2/cyclic_type2_test.dart
@@ -19,9 +19,13 @@
 
 main() {
   var d = new Derived1<Derived1, Derived2>();
-  Expect.equals("Derived1<Derived1, Derived2>", d.u.toString());
   Expect.equals(
-      "Derived1<Derived2<Derived2, Derived1>, Derived2>", d.v.toString());
+      "Derived1<Derived1<dynamic, dynamic>, Derived2<dynamic, dynamic>>",
+      d.u.toString());
+  Expect.equals(
+      "Derived1<Derived2<Derived2<dynamic, dynamic>, "
+      "Derived1<dynamic, dynamic>>, Derived2<dynamic, dynamic>>",
+      d.v.toString());
   Expect.isTrue(d is Derived1<Derived1, Derived2>);
   Expect.isFalse(d is Derived1<Derived1, Derived1>);
   Expect.isTrue(d is Base<Derived1<Derived1, Derived2>,
diff --git a/tests/language_2/language_2_dart2js.status b/tests/language_2/language_2_dart2js.status
index 5fa91ed..493bbfb 100644
--- a/tests/language_2/language_2_dart2js.status
+++ b/tests/language_2/language_2_dart2js.status
@@ -552,10 +552,7 @@
 partial_tearoff_instantiation_test/06: Pass # for the wrong reason.
 partial_tearoff_instantiation_test/07: Pass # for the wrong reason.
 partial_tearoff_instantiation_test/08: Pass # for the wrong reason.
-type_alias_equality_test/01: RuntimeError # Issue 32784
 type_alias_equality_test/02: RuntimeError # Issue 32784
-type_alias_equality_test/03: RuntimeError # Issue 32784
-type_alias_equality_test/04: RuntimeError # Issue 32784
 
 [ $compiler == dart2js && $fasta && $host_checked && $strong ]
 abstract_override_adds_optional_args_concrete_subclass_test: MissingCompileTimeError
@@ -939,6 +936,7 @@
 [ $compiler == dart2js && $minified ]
 cyclic_type2_test: RuntimeError # Issue 31054
 cyclic_type_test/0*: RuntimeError # Issue 31054
+f_bounded_quantification4_test: RuntimeError # Issue 31054
 f_bounded_quantification5_test: RuntimeError # Issue 31054
 generic_closure_test/01: RuntimeError # Uses runtimeType.toString()
 mixin_mixin2_test: RuntimeError # Issue 31054
@@ -989,10 +987,6 @@
 covariance_type_parameter_test/02: RuntimeError
 covariant_subtyping_test: Crash
 ct_const_test: RuntimeError
-cyclic_type_test/00: RuntimeError
-cyclic_type_test/02: RuntimeError
-cyclic_type_test/03: RuntimeError
-cyclic_type_test/04: RuntimeError
 deferred_inheritance_constraints_test/extends: MissingCompileTimeError
 deferred_inheritance_constraints_test/implements: MissingCompileTimeError
 deferred_inheritance_constraints_test/mixin: MissingCompileTimeError
@@ -1012,7 +1006,6 @@
 external_test/20: MissingRuntimeError
 external_test/21: CompileTimeError
 external_test/24: CompileTimeError
-f_bounded_quantification4_test: RuntimeError
 field_initialization_order_test/01: MissingCompileTimeError
 field_initialization_order_test/none: RuntimeError
 flatten_test/05: MissingRuntimeError
@@ -1102,7 +1095,6 @@
 mixin_illegal_superclass_test/28: MissingCompileTimeError
 mixin_illegal_superclass_test/29: MissingCompileTimeError
 mixin_illegal_superclass_test/30: MissingCompileTimeError
-mixin_mixin6_test: RuntimeError
 mixin_of_mixin_test/none: CompileTimeError
 mixin_super_2_test/none: CompileTimeError
 mixin_super_constructor_named_test/01: MissingCompileTimeError