[dart2js] Omit empty objects from new RTI type rules.

Change-Id: I3efbb9d1283606023babbe4940e040b5c5e24d60
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/111265
Commit-Queue: Mayank Patke <fishythefish@google.com>
Reviewed-by: Stephen Adams <sra@google.com>
diff --git a/pkg/compiler/lib/src/js_backend/runtime_types_new.dart b/pkg/compiler/lib/src/js_backend/runtime_types_new.dart
index ca1a425..cd8f4be 100644
--- a/pkg/compiler/lib/src/js_backend/runtime_types_new.dart
+++ b/pkg/compiler/lib/src/js_backend/runtime_types_new.dart
@@ -416,6 +416,23 @@
   }
 }
 
+class _RulesetEntry {
+  final InterfaceType _targetType;
+  List<InterfaceType> _supertypes;
+
+  _RulesetEntry(this._targetType, this._supertypes);
+}
+
+class Ruleset {
+  List<_RulesetEntry> _entries;
+
+  Ruleset(this._entries);
+  Ruleset.empty() : this([]);
+
+  void add(InterfaceType targetType, Iterable<InterfaceType> supertypes) =>
+      _entries.add(_RulesetEntry(targetType, supertypes));
+}
+
 class RulesetEncoder {
   final DartTypes _dartTypes;
   final ModularEmitter _emitter;
@@ -436,34 +453,40 @@
 
   bool _isObject(InterfaceType type) => identical(type.element, _objectClass);
 
+  void _preprocessEntry(_RulesetEntry entry) =>
+      entry._supertypes.removeWhere(_isObject);
+
+  void _preprocessRuleset(Ruleset ruleset) {
+    ruleset._entries.forEach(_preprocessEntry);
+    ruleset._entries.removeWhere((_RulesetEntry entry) =>
+        _isObject(entry._targetType) || entry._supertypes.isEmpty);
+  }
+
   // TODO(fishythefish): Common substring elimination.
 
   /// Produces a string readable by `JSON.parse()`.
-  jsAst.StringConcatenation encodeRuleset(
-          Map<InterfaceType, Iterable<InterfaceType>> ruleset) =>
+  jsAst.StringConcatenation encodeRuleset(Ruleset ruleset) {
+    _preprocessRuleset(ruleset);
+    return _encodeRuleset(ruleset);
+  }
+
+  jsAst.StringConcatenation _encodeRuleset(Ruleset ruleset) =>
       js.concatenateStrings([
         _quote,
         _leftBrace,
-        ...js.joinLiterals(
-            ruleset.entries
-                .where((entry) => !_isObject(entry.key))
-                .map((entry) => _encodeRule(entry.key, entry.value)),
-            _comma),
+        ...js.joinLiterals(ruleset._entries.map(_encodeEntry), _comma),
         _rightBrace,
         _quote,
       ]);
 
-  jsAst.StringConcatenation _encodeRule(
-          InterfaceType targetType, Iterable<InterfaceType> supertypes) =>
+  jsAst.StringConcatenation _encodeEntry(_RulesetEntry entry) =>
       js.concatenateStrings([
-        js.quoteName(_emitter.typeAccessNewRti(targetType.element)),
+        js.quoteName(_emitter.typeAccessNewRti(entry._targetType.element)),
         _colon,
         _leftBrace,
         ...js.joinLiterals(
-            supertypes
-                .where((InterfaceType supertype) => !_isObject(supertype))
-                .map((InterfaceType supertype) =>
-                    _encodeSupertype(targetType, supertype)),
+            entry._supertypes.map((InterfaceType supertype) =>
+                _encodeSupertype(entry._targetType, supertype)),
             _comma),
         _rightBrace,
       ]);
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
index 62fd32b..5bdffb4 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
@@ -1942,15 +1942,17 @@
   js.Statement emitTypeRules(Fragment fragment) {
     if (!_options.experimentNewRti) return js.EmptyStatement();
 
-    Map<InterfaceType, Iterable<InterfaceType>> ruleset = {};
+    Ruleset ruleset = Ruleset.empty();
     Iterable<Class> classes =
         fragment.libraries.expand((Library library) => library.classes);
     classes.forEach((Class cls) {
       if (cls.classChecksNewRti == null) return;
       InterfaceType targetType = _elementEnvironment.getThisType(cls.element);
-      Iterable<InterfaceType> supertypes = cls.classChecksNewRti.checks.map(
-          (TypeCheck check) => _dartTypes.asInstanceOf(targetType, check.cls));
-      ruleset[targetType] = supertypes;
+      List<InterfaceType> supertypes = cls.classChecksNewRti.checks
+          .map((TypeCheck check) =>
+              _dartTypes.asInstanceOf(targetType, check.cls))
+          .toList();
+      ruleset.add(targetType, supertypes);
     });
 
     FunctionEntity method = _closedWorld.commonElements.rtiAddRulesMethod;
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 f2daeff..ef075cd 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
@@ -52,7 +52,7 @@
 import '../../js_backend/runtime_types.dart';
 import '../../js_backend/runtime_types_codegen.dart';
 import '../../js_backend/runtime_types_new.dart'
-    show RecipeEncoder, RecipeEncoderImpl, RulesetEncoder;
+    show RecipeEncoder, RecipeEncoderImpl, Ruleset, RulesetEncoder;
 import '../../options.dart';
 import '../../universe/codegen_world_builder.dart' show CodegenWorld;
 import '../../world.dart';