[dart2js] Correctly output class types when they are shadowed.
Change-Id: Ie0889a6312aa9f885059873dd8cb2debde64f2cf
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/158724
Commit-Queue: Joshua Litt <joshualitt@google.com>
Reviewed-by: Sigmund Cherem <sigmund@google.com>
diff --git a/pkg/compiler/lib/src/js_emitter/program_builder/collector.dart b/pkg/compiler/lib/src/js_emitter/program_builder/collector.dart
index b1aaa3b..1ab31fc 100644
--- a/pkg/compiler/lib/src/js_emitter/program_builder/collector.dart
+++ b/pkg/compiler/lib/src/js_emitter/program_builder/collector.dart
@@ -24,9 +24,9 @@
final Sorter _sorter;
final Set<ClassEntity> neededClasses = {};
+ final Set<ClassEntity> neededClassTypes = {};
final Set<ClassEntity> classesOnlyNeededForRti = {};
- // This field is set in [computeNeededDeclarations].
- Set<ClassEntity> classesOnlyNeededForConstructor;
+ final Set<ClassEntity> classesOnlyNeededForConstructor = {};
final Map<OutputUnit, List<ClassEntity>> outputClassLists = {};
final Map<OutputUnit, List<ClassEntity>> outputClassTypeLists = {};
final Map<OutputUnit, List<ConstantValue>> outputConstantLists = {};
@@ -150,6 +150,18 @@
Set<ClassEntity> backendTypeHelpers =
getBackendTypeHelpers(_commonElements).toSet();
+ /// A class type is 'shadowed' if the class is needed for direct
+ /// instantiation in one OutputUnit while its type is needed in another
+ /// OutputUnit.
+ bool isClassTypeShadowed(ClassEntity cls) {
+ return !backendTypeHelpers.contains(cls) &&
+ _rtiNeededClasses.contains(cls) &&
+ !classesOnlyNeededForRti.contains(cls) &&
+ _options.deferClassTypes &&
+ _outputUnitData.outputUnitForClass(cls) !=
+ _outputUnitData.outputUnitForClassType(cls);
+ }
+
// Compute needed classes.
Set<ClassEntity> instantiatedClasses =
// TODO(johnniwinther): This should be accessed from a codegen closed
@@ -177,10 +189,11 @@
neededClasses.addAll(mixinClasses);
// 3. Add classes only needed for their constructors.
- classesOnlyNeededForConstructor = _codegenWorld.constructorReferences
- .where((cls) => !neededClasses.contains(cls))
- .toSet();
- neededClasses.addAll(classesOnlyNeededForConstructor);
+ for (var cls in _codegenWorld.constructorReferences) {
+ if (neededClasses.add(cls)) {
+ classesOnlyNeededForConstructor.add(cls);
+ }
+ }
// 4. Find all classes needed for rti.
// It is important that this is the penultimate step, at this point,
@@ -193,21 +206,16 @@
if (backendTypeHelpers.contains(cls)) continue;
while (cls != null && !neededClasses.contains(cls)) {
if (!classesOnlyNeededForRti.add(cls)) break;
+ // TODO(joshualitt) delete classesOnlyNeededForRti when the
+ // no-defer-class_types flag is removed.
+ neededClassTypes.add(cls);
cls = _elementEnvironment.getSuperClass(cls);
}
}
- neededClasses.addAll(classesOnlyNeededForRti);
-
- // 5. Finally, sort the classes.
- List<ClassEntity> sortedClasses = _sorter.sortClasses(neededClasses);
-
- for (ClassEntity cls in sortedClasses) {
- if (classesOnlyNeededForRti.contains(cls)) {
- _outputListsForClassType
- .putIfAbsent(_outputUnitData.outputUnitForClassType(cls), () => [])
- .add(cls);
- } else if (_nativeData.isNativeOrExtendsNative(cls) &&
+ // 5. Sort classes and add them to their respective OutputUnits.
+ for (ClassEntity cls in _sorter.sortClasses(neededClasses)) {
+ if (_nativeData.isNativeOrExtendsNative(cls) &&
!classesOnlyNeededForConstructor.contains(cls)) {
// For now, native classes and related classes cannot be deferred.
nativeClassesAndSubclasses.add(cls);
@@ -221,6 +229,21 @@
.add(cls);
}
}
+
+ // 6. Collect any class types 'shadowed' by direct instantiation.
+ for (ClassEntity cls in _rtiNeededClasses) {
+ if (isClassTypeShadowed(cls)) {
+ neededClassTypes.add(cls);
+ }
+ }
+
+ // 7. Sort classes needed for type checking and then add them to their
+ // respective OutputUnits.
+ for (ClassEntity cls in _sorter.sortClasses(neededClassTypes)) {
+ _outputListsForClassType
+ .putIfAbsent(_outputUnitData.outputUnitForClassType(cls), () => [])
+ .add(cls);
+ }
}
void computeNeededStatics() {
@@ -292,9 +315,12 @@
outputLibraryLists.putIfAbsent(unit, () => {}).add(library);
});
neededClasses.forEach((ClassEntity element) {
- OutputUnit unit = classesOnlyNeededForRti.contains(element)
- ? _outputUnitData.outputUnitForClassType(element)
- : _outputUnitData.outputUnitForClass(element);
+ OutputUnit unit = _outputUnitData.outputUnitForClass(element);
+ LibraryEntity library = element.library;
+ outputLibraryLists.putIfAbsent(unit, () => {}).add(library);
+ });
+ neededClassTypes.forEach((ClassEntity element) {
+ OutputUnit unit = _outputUnitData.outputUnitForClassType(element);
LibraryEntity library = element.library;
outputLibraryLists.putIfAbsent(unit, () => {}).add(library);
});