Sort classes topologically when checking for cycles
Change-Id: I4d2fd8a1d3f2d369e69ed93665ce43ca4747b02d
Reviewed-on: https://dart-review.googlesource.com/c/86204
Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
diff --git a/pkg/front_end/lib/src/fasta/dill/dill_target.dart b/pkg/front_end/lib/src/fasta/dill/dill_target.dart
index bae16f6..63348b0 100644
--- a/pkg/front_end/lib/src/fasta/dill/dill_target.dart
+++ b/pkg/front_end/lib/src/fasta/dill/dill_target.dart
@@ -58,8 +58,5 @@
}
@override
- void addDirectSupertype(ClassBuilder cls, Set<ClassBuilder> set) {}
-
- @override
void breakCycle(ClassBuilder cls) {}
}
diff --git a/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart b/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
index 8381a1e..9f88c43 100644
--- a/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
+++ b/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
@@ -1754,27 +1754,24 @@
}
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-const Template<Message Function(String name, String string)>
- templateCyclicClassHierarchy =
- const Template<Message Function(String name, String string)>(
- messageTemplate: r"""'#name' is a supertype of itself via '#string'.""",
+const Template<Message Function(String name)> templateCyclicClassHierarchy =
+ const Template<Message Function(String name)>(
+ messageTemplate: r"""'#name' is a supertype of itself.""",
withArguments: _withArgumentsCyclicClassHierarchy);
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-const Code<Message Function(String name, String string)>
- codeCyclicClassHierarchy =
- const Code<Message Function(String name, String string)>(
+const Code<Message Function(String name)> codeCyclicClassHierarchy =
+ const Code<Message Function(String name)>(
"CyclicClassHierarchy", templateCyclicClassHierarchy,
analyzerCodes: <String>["RECURSIVE_INTERFACE_INHERITANCE"]);
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-Message _withArgumentsCyclicClassHierarchy(String name, String string) {
+Message _withArgumentsCyclicClassHierarchy(String name) {
if (name.isEmpty) throw 'No name provided';
name = demangleMixinApplicationName(name);
- if (string.isEmpty) throw 'No string provided';
return new Message(codeCyclicClassHierarchy,
- message: """'${name}' is a supertype of itself via '${string}'.""",
- arguments: {'name': name, 'string': string});
+ message: """'${name}' is a supertype of itself.""",
+ arguments: {'name': name});
}
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -2044,28 +2041,6 @@
}
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-const Template<Message Function(String name)>
- templateDirectCyclicClassHierarchy =
- const Template<Message Function(String name)>(
- messageTemplate: r"""'#name' can't use itself as a supertype.""",
- withArguments: _withArgumentsDirectCyclicClassHierarchy);
-
-// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-const Code<Message Function(String name)> codeDirectCyclicClassHierarchy =
- const Code<Message Function(String name)>(
- "DirectCyclicClassHierarchy", templateDirectCyclicClassHierarchy,
- analyzerCodes: <String>["RECURSIVE_INTERFACE_INHERITANCE"]);
-
-// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-Message _withArgumentsDirectCyclicClassHierarchy(String name) {
- if (name.isEmpty) throw 'No name provided';
- name = demangleMixinApplicationName(name);
- return new Message(codeDirectCyclicClassHierarchy,
- message: """'${name}' can't use itself as a supertype.""",
- arguments: {'name': name});
-}
-
-// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Null> codeDirectiveAfterDeclaration =
messageDirectiveAfterDeclaration;
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
index 3fc17fc..b31d999 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
@@ -197,37 +197,6 @@
return new KernelLibraryBuilder(uri, fileUri, loader, origin);
}
- void forEachDirectSupertype(ClassBuilder cls, void f(NamedTypeBuilder type)) {
- TypeBuilder supertype = cls.supertype;
- if (supertype is NamedTypeBuilder) {
- f(supertype);
- } else if (supertype != null) {
- unhandled("${supertype.runtimeType}", "forEachDirectSupertype",
- cls.charOffset, cls.fileUri);
- }
- if (cls.interfaces != null) {
- for (NamedTypeBuilder t in cls.interfaces) {
- f(t);
- }
- }
- if (cls.library.loader == loader &&
- // TODO(ahe): Implement DillClassBuilder.mixedInType and remove the
- // above check.
- cls.mixedInType != null) {
- f(cls.mixedInType);
- }
- }
-
- void addDirectSupertype(ClassBuilder cls, Set<ClassBuilder> set) {
- if (cls == null) return;
- forEachDirectSupertype(cls, (NamedTypeBuilder type) {
- Declaration declaration = type.declaration;
- if (declaration is ClassBuilder) {
- set.add(declaration);
- }
- });
- }
-
/// Returns classes defined in libraries in [loader].
List<SourceClassBuilder> collectMyClasses() {
List<SourceClassBuilder> result = <SourceClassBuilder>[];
@@ -270,8 +239,8 @@
bottomType.bind(loader.coreLibrary["Null"]);
loader.resolveTypes();
loader.computeDefaultTypes(dynamicType, bottomType, objectClassBuilder);
- List<SourceClassBuilder> myClasses = collectMyClasses();
- loader.checkSemantics(myClasses, objectClassBuilder);
+ List<SourceClassBuilder> myClasses =
+ loader.checkSemantics(objectClassBuilder);
loader.finishTypeVariables(objectClassBuilder, dynamicType);
loader.buildComponent();
installDefaultSupertypes();
@@ -412,7 +381,7 @@
void installSyntheticConstructors(List<SourceClassBuilder> builders) {
Class objectClass = this.objectClass;
for (SourceClassBuilder builder in builders) {
- if (builder.target != objectClass) {
+ if (builder.target != objectClass && !builder.isPatch) {
if (builder.isPatch || builder.isMixinDeclaration) continue;
if (builder.isMixinApplication) {
installForwardingConstructors(builder);
diff --git a/pkg/front_end/lib/src/fasta/source/source_class_builder.dart b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
index 0c507c5..0691889 100644
--- a/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
@@ -24,12 +24,14 @@
import '../kernel/kernel_builder.dart'
show
+ ClassBuilder,
ConstructorReferenceBuilder,
Declaration,
KernelClassBuilder,
KernelFieldBuilder,
KernelFunctionBuilder,
KernelLibraryBuilder,
+ KernelNamedTypeBuilder,
KernelTypeBuilder,
KernelTypeVariableBuilder,
LibraryBuilder,
@@ -69,7 +71,8 @@
return cls;
}
-class SourceClassBuilder extends KernelClassBuilder {
+class SourceClassBuilder extends KernelClassBuilder
+ implements Comparable<SourceClassBuilder> {
@override
final Class actualCls;
@@ -247,7 +250,9 @@
declaration.prepareTopLevelInference();
}
});
- cls.setupApiMembers(library.loader.interfaceResolver);
+ if (!isPatch) {
+ cls.setupApiMembers(library.loader.interfaceResolver);
+ }
}
@override
@@ -274,4 +279,33 @@
});
return count;
}
+
+ List<Declaration> computeDirectSupertypes(ClassBuilder objectClass) {
+ final List<Declaration> result = <Declaration>[];
+ final KernelNamedTypeBuilder supertype = this.supertype;
+ if (supertype != null) {
+ result.add(supertype.declaration);
+ } else if (objectClass != this) {
+ result.add(objectClass);
+ }
+ final List<KernelTypeBuilder> interfaces = this.interfaces;
+ if (interfaces != null) {
+ for (int i = 0; i < interfaces.length; i++) {
+ KernelNamedTypeBuilder interface = interfaces[i];
+ result.add(interface.declaration);
+ }
+ }
+ final KernelNamedTypeBuilder mixedInType = this.mixedInType;
+ if (mixedInType != null) {
+ result.add(mixedInType.declaration);
+ }
+ return result;
+ }
+
+ @override
+ int compareTo(SourceClassBuilder other) {
+ int result = "$fileUri".compareTo("${other.fileUri}");
+ if (result != 0) return result;
+ return charOffset.compareTo(other.charOffset);
+ }
}
diff --git a/pkg/front_end/lib/src/fasta/source/source_loader.dart b/pkg/front_end/lib/src/fasta/source/source_loader.dart
index 5edde47..35aade6 100644
--- a/pkg/front_end/lib/src/fasta/source/source_loader.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_loader.dart
@@ -66,7 +66,6 @@
templateIllegalMixinDueToConstructorsCause,
templateInternalProblemUriMissingScheme,
templateSourceOutlineSummary,
- templateDirectCyclicClassHierarchy,
templateUntranslatableUri;
import '../fasta_codes.dart' as fasta_codes;
@@ -95,7 +94,7 @@
import '../parser.dart' show Parser, lengthForToken, offsetForToken;
-import '../problems.dart' show internalProblem, unexpected, unhandled;
+import '../problems.dart' show internalProblem, unhandled;
import '../scanner.dart' show ErrorToken, ScannerResult, Token, scan;
@@ -142,8 +141,6 @@
Instrumentation instrumentation;
- List<ClassBuilder> orderedClasses;
-
SourceLoader(this.fileSystem, this.includeComments, KernelTarget target)
: super(target);
@@ -504,57 +501,6 @@
ticker.logMs("Finished $count patch methods");
}
- /// Returns all the supertypes (including interfaces) of [cls]
- /// transitively. Includes [cls].
- Set<ClassBuilder> allSupertypes(ClassBuilder cls) {
- int length = 0;
- Set<ClassBuilder> result = new Set<ClassBuilder>()..add(cls);
- while (length != result.length) {
- length = result.length;
- result.addAll(directSupertypes(result));
- }
- return result;
- }
-
- /// Returns the direct supertypes (including interface) of [classes]. A class
- /// from [classes] is only included if it is a supertype of one of the other
- /// classes in [classes].
- Set<ClassBuilder> directSupertypes(Iterable<ClassBuilder> classes) {
- Set<ClassBuilder> result = new Set<ClassBuilder>();
- for (ClassBuilder cls in classes) {
- target.addDirectSupertype(cls, result);
- }
- return result;
- }
-
- /// Computes a set of classes that may have cycles. The set is empty if there
- /// are no cycles. If the set isn't empty, it will include supertypes of
- /// classes with cycles, as well as the classes with cycles.
- ///
- /// It is assumed that [classes] is a transitive closure with respect to
- /// supertypes.
- Iterable<ClassBuilder> cyclicCandidates(Iterable<ClassBuilder> classes) {
- // The candidates are found by a fixed-point computation.
- //
- // On each iteration, the classes that have no supertypes in the input set
- // will be removed.
- //
- // If there are no cycles, eventually, the set will converge on Object, and
- // the next iteration will make the set empty (as Object has no
- // supertypes).
- //
- // On the other hand, if there is a cycle, the cycle will remain in the
- // set, and so will its supertypes, and eventually the input and output set
- // will have the same length.
- Iterable<ClassBuilder> input = const [];
- Iterable<ClassBuilder> output = classes;
- while (input.length != output.length) {
- input = output;
- output = directSupertypes(input);
- }
- return output;
- }
-
/// Check that [objectClass] has no supertypes. Recover by removing any
/// found.
void checkObjectClassHierarchy(ClassBuilder objectClass) {
@@ -578,111 +524,141 @@
}
}
- void checkSemantics(
- List<SourceClassBuilder> classes, ClassBuilder objectClass) {
- checkObjectClassHierarchy(objectClass);
- Iterable<ClassBuilder> candidates = cyclicCandidates(classes);
- if (candidates.isNotEmpty) {
- Map<ClassBuilder, Set<ClassBuilder>> realCycles =
- <ClassBuilder, Set<ClassBuilder>>{};
- for (ClassBuilder cls in candidates) {
- Set<ClassBuilder> cycles = cyclicCandidates(allSupertypes(cls));
- if (cycles.isNotEmpty) {
- realCycles[cls] = cycles;
- }
- }
- Map<LocatedMessage, ClassBuilder> messages =
- <LocatedMessage, ClassBuilder>{};
- realCycles.forEach((ClassBuilder cls, Set<ClassBuilder> cycles) {
- target.breakCycle(cls);
- List<ClassBuilder> involved = <ClassBuilder>[];
- for (ClassBuilder cls in cycles) {
- if (realCycles.containsKey(cls)) {
- involved.add(cls);
+ /// Returns a list of all class builders declared in this loader. As the
+ /// classes are sorted, any cycles in the hiearchy are reported as
+ /// errors. Recover by breaking the cycles. This means that the rest of the
+ /// pipeline (including backends) can assume that there are no hierarchy
+ /// cycles.
+ List<SourceClassBuilder> handleHierarchyCycles(ClassBuilder objectClass) {
+ // Compute the initial work list of all classes declared in this loader.
+ List<SourceClassBuilder> workList = <SourceClassBuilder>[];
+ for (LibraryBuilder library in builders.values) {
+ if (library.loader == this) {
+ Iterator<Declaration> members = library.iterator;
+ while (members.moveNext()) {
+ Declaration member = members.current;
+ if (member is SourceClassBuilder) {
+ workList.add(member);
}
}
- // Sort the class names alphabetically to ensure the order is stable.
- // TODO(ahe): It's possible that a better UX would be to sort the
- // classes based on walking the class hierarchy in breadth-first order.
- String involvedString = (involved
- .where((c) => c != cls)
- .map((c) => c.fullNameForErrors)
- .toList()
- ..sort())
- .join("', '");
- LocatedMessage message = involvedString.isEmpty
- ? templateDirectCyclicClassHierarchy
- .withArguments(cls.fullNameForErrors)
- .withLocation(cls.fileUri, cls.charOffset, noLength)
- : templateCyclicClassHierarchy
- .withArguments(cls.fullNameForErrors, involvedString)
- .withLocation(cls.fileUri, cls.charOffset, noLength);
- messages[message] = cls;
- });
-
- // Report all classes involved in a cycle, sorted to ensure stability as
- // [cyclicCandidates] is sensitive to if the platform (or other modules)
- // are included in [classes].
- for (LocatedMessage message in messages.keys.toList()..sort()) {
- messages[message].addProblem(
- message.messageObject, message.charOffset, message.length);
}
}
- ticker.logMs("Found cycles");
+
Set<ClassBuilder> blackListedClasses = new Set<ClassBuilder>();
for (int i = 0; i < blacklistedCoreClasses.length; i++) {
blackListedClasses.add(coreLibrary[blacklistedCoreClasses[i]]);
}
- for (ClassBuilder cls in classes) {
- if (cls.library.loader != this) continue;
- Set<ClassBuilder> directSupertypes = new Set<ClassBuilder>();
- target.addDirectSupertype(cls, directSupertypes);
- for (ClassBuilder supertype in directSupertypes) {
- if (supertype is EnumBuilder) {
- cls.addProblem(templateExtendingEnum.withArguments(supertype.name),
- cls.charOffset, noLength);
- } else if (!cls.library.mayImplementRestrictedTypes &&
- blackListedClasses.contains(supertype)) {
- cls.addProblem(
- templateExtendingRestricted.withArguments(supertype.name),
- cls.charOffset,
- noLength);
+
+ // Sort the classes topologically.
+ Set<SourceClassBuilder> topologicallySortedClasses =
+ new Set<SourceClassBuilder>();
+ List<SourceClassBuilder> previousWorkList;
+ do {
+ previousWorkList = workList;
+ workList = <SourceClassBuilder>[];
+ for (int i = 0; i < previousWorkList.length; i++) {
+ SourceClassBuilder cls = previousWorkList[i];
+ List<Declaration> directSupertypes =
+ cls.computeDirectSupertypes(objectClass);
+ bool allSupertypesProcessed = true;
+ for (int i = 0; i < directSupertypes.length; i++) {
+ Declaration supertype = directSupertypes[i];
+ if (supertype is SourceClassBuilder &&
+ supertype.library.loader == this &&
+ !topologicallySortedClasses.contains(supertype)) {
+ allSupertypesProcessed = false;
+ break;
+ }
+ }
+ if (allSupertypesProcessed) {
+ topologicallySortedClasses.add(cls);
+ checkClassSupertypes(cls, directSupertypes, blackListedClasses);
+ } else {
+ workList.add(cls);
}
}
- TypeBuilder mixedInType = cls.mixedInType;
- if (mixedInType != null) {
- bool isClassBuilder = false;
- if (mixedInType is NamedTypeBuilder) {
- var builder = mixedInType.declaration;
- if (builder is ClassBuilder) {
- isClassBuilder = true;
- for (Declaration constructory
- in builder.constructors.local.values) {
- if (constructory.isConstructor && !constructory.isSynthetic) {
- cls.addProblem(
- templateIllegalMixinDueToConstructors
- .withArguments(builder.fullNameForErrors),
- cls.charOffset,
- noLength,
- context: [
- templateIllegalMixinDueToConstructorsCause
- .withArguments(builder.fullNameForErrors)
- .withLocation(constructory.fileUri,
- constructory.charOffset, noLength)
- ]);
- }
+ } while (previousWorkList.length != workList.length);
+ List<SourceClassBuilder> classes = topologicallySortedClasses.toList();
+ List<SourceClassBuilder> classesWithCycles = previousWorkList;
+
+ // Once the work list doesn't change in size, it's either empty, or
+ // contains all classes with cycles.
+
+ // Sort the classes to ensure consistent output.
+ classesWithCycles.sort();
+ for (int i = 0; i < classesWithCycles.length; i++) {
+ SourceClassBuilder cls = classesWithCycles[i];
+ target.breakCycle(cls);
+ classes.add(cls);
+ cls.addProblem(
+ templateCyclicClassHierarchy.withArguments(cls.fullNameForErrors),
+ cls.charOffset,
+ noLength);
+ }
+
+ ticker.logMs("Checked class hierarchy");
+ return classes;
+ }
+
+ void checkClassSupertypes(
+ SourceClassBuilder cls,
+ List<Declaration> directSupertypes,
+ Set<ClassBuilder> blackListedClasses) {
+ // Check that the direct supertypes aren't black-listed or enums.
+ for (int i = 0; i < directSupertypes.length; i++) {
+ Declaration supertype = directSupertypes[i];
+ if (supertype is EnumBuilder) {
+ cls.addProblem(templateExtendingEnum.withArguments(supertype.name),
+ cls.charOffset, noLength);
+ } else if (!cls.library.mayImplementRestrictedTypes &&
+ blackListedClasses.contains(supertype)) {
+ cls.addProblem(
+ templateExtendingRestricted
+ .withArguments(supertype.fullNameForErrors),
+ cls.charOffset,
+ noLength);
+ }
+ }
+
+ // Check that the mixed-in type can be used as a mixin.
+ final TypeBuilder mixedInType = cls.mixedInType;
+ if (mixedInType != null) {
+ bool isClassBuilder = false;
+ if (mixedInType is NamedTypeBuilder) {
+ var builder = mixedInType.declaration;
+ if (builder is ClassBuilder) {
+ isClassBuilder = true;
+ for (Declaration constructory in builder.constructors.local.values) {
+ if (constructory.isConstructor && !constructory.isSynthetic) {
+ cls.addProblem(
+ templateIllegalMixinDueToConstructors
+ .withArguments(builder.fullNameForErrors),
+ cls.charOffset,
+ noLength,
+ context: [
+ templateIllegalMixinDueToConstructorsCause
+ .withArguments(builder.fullNameForErrors)
+ .withLocation(constructory.fileUri,
+ constructory.charOffset, noLength)
+ ]);
}
}
}
- if (!isClassBuilder) {
- cls.addProblem(
- templateIllegalMixin.withArguments(mixedInType.fullNameForErrors),
- cls.charOffset,
- noLength);
- }
+ }
+ if (!isClassBuilder) {
+ // TODO(ahe): Either we need to check this for superclass and
+ // interfaces, or this shouldn't be necessary (or handled elsewhere).
+ cls.addProblem(
+ templateIllegalMixin.withArguments(mixedInType.fullNameForErrors),
+ cls.charOffset,
+ noLength);
}
}
- ticker.logMs("Checked restricted supertypes");
+ }
+
+ List<SourceClassBuilder> checkSemantics(ClassBuilder objectClass) {
+ checkObjectClassHierarchy(objectClass);
+ List<SourceClassBuilder> classes = handleHierarchyCycles(objectClass);
// Check imports and exports for duplicate names.
// This is rather silly, e.g. it makes importing 'foo' and exporting another
@@ -757,6 +733,7 @@
}
});
ticker.logMs("Checked imports and exports for duplicate names");
+ return classes;
}
void buildComponent() {
@@ -847,7 +824,7 @@
void checkSupertypes(List<SourceClassBuilder> sourceClasses) {
for (SourceClassBuilder builder in sourceClasses) {
- if (builder.library.loader == this) {
+ if (builder.library.loader == this && !builder.isPatch) {
builder.checkSupertypes(coreTypes);
}
}
@@ -871,7 +848,7 @@
void checkOverrides(List<SourceClassBuilder> sourceClasses) {
assert(hierarchy != null);
for (SourceClassBuilder builder in sourceClasses) {
- if (builder.library.loader == this) {
+ if (builder.library.loader == this && !builder.isPatch) {
builder.checkOverrides(
hierarchy, typeInferenceEngine?.typeSchemaEnvironment);
}
@@ -883,7 +860,7 @@
if (target.legacyMode) return;
assert(hierarchy != null);
for (SourceClassBuilder builder in sourceClasses) {
- if (builder.library.loader == this) {
+ if (builder.library.loader == this && !builder.isPatch) {
builder.checkAbstractMembers(
coreTypes, hierarchy, typeInferenceEngine.typeSchemaEnvironment);
}
@@ -894,7 +871,7 @@
void checkRedirectingFactories(List<SourceClassBuilder> sourceClasses) {
if (target.legacyMode) return;
for (SourceClassBuilder builder in sourceClasses) {
- if (builder.library.loader == this) {
+ if (builder.library.loader == this && !builder.isPatch) {
builder.checkRedirectingFactories(
typeInferenceEngine.typeSchemaEnvironment);
}
@@ -907,7 +884,7 @@
List<Class> changedClasses = new List<Class>();
for (SourceClassBuilder builder in sourceClasses) {
- if (builder.library.loader == this) {
+ if (builder.library.loader == this && !builder.isPatch) {
if (builder.addNoSuchMethodForwarders(target, hierarchy)) {
changedClasses.add(builder.target);
}
@@ -919,7 +896,7 @@
void checkMixins(List<SourceClassBuilder> sourceClasses) {
for (SourceClassBuilder builder in sourceClasses) {
- if (builder.library.loader == this) {
+ if (builder.library.loader == this && !builder.isPatch) {
if (builder.isMixinDeclaration) {
builder.checkMixinDeclaration();
}
@@ -962,27 +939,8 @@
}
}
}
- {
- // Note: we need to create a list before iterating, since calling
- // builder.prepareTopLevelInference causes further class hierarchy
- // queries to be made which would otherwise result in a concurrent
- // modification exception.
- List<Class> classes = new List<Class>(sourceClasses.length);
- for (int i = 0; i < sourceClasses.length; i++) {
- classes[i] = sourceClasses[i].target;
- }
- orderedClasses = null;
- List<ClassBuilder> result = new List<ClassBuilder>(sourceClasses.length);
- int i = 0;
- for (Class cls
- in new List<Class>.from(hierarchy.getOrderedClasses(classes))) {
- result[i++] = ShadowClass.getClassInferenceInfo(cls).builder
- ..prepareTopLevelInference();
- }
- if (i != result.length) {
- unexpected("${result.length}", "$i", -1, null);
- }
- orderedClasses = result;
+ for (int i = 0; i < sourceClasses.length; i++) {
+ sourceClasses[i].prepareTopLevelInference();
}
typeInferenceEngine.isTypeInferencePrepared = true;
ticker.logMs("Prepared top level inference");
@@ -992,7 +950,8 @@
/// their types.
typeInferenceEngine.finishTopLevelFields();
List<Class> changedClasses = new List<Class>();
- for (var builder in orderedClasses) {
+ for (var builder in sourceClasses) {
+ if (builder.isPatch) continue;
ShadowClass class_ = builder.target;
int memberCount = class_.fields.length +
class_.constructors.length +
@@ -1012,7 +971,6 @@
}
}
- orderedClasses = null;
typeInferenceEngine.finishTopLevelInitializingFormals();
if (instrumentation != null) {
builders.forEach((Uri uri, LibraryBuilder library) {
diff --git a/pkg/front_end/lib/src/fasta/target_implementation.dart b/pkg/front_end/lib/src/fasta/target_implementation.dart
index 08581aa..350a79a 100644
--- a/pkg/front_end/lib/src/fasta/target_implementation.dart
+++ b/pkg/front_end/lib/src/fasta/target_implementation.dart
@@ -46,9 +46,6 @@
LibraryBuilder createLibraryBuilder(
Uri uri, Uri fileUri, covariant LibraryBuilder origin);
- /// Add the classes extended or implemented directly by [cls] to [set].
- void addDirectSupertype(ClassBuilder cls, Set<ClassBuilder> set);
-
/// The class [cls] is involved in a cyclic definition. This method should
/// ensure that the cycle is broken, for example, by removing superclass and
/// implemented interfaces.
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index 3876a46..cebe774 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -1792,7 +1792,7 @@
main.dart: "import 'lib1.dart'; import 'lib2.dart'; A a;"
CyclicClassHierarchy:
- template: "'#name' is a supertype of itself via '#string'."
+ template: "'#name' is a supertype of itself."
analyzerCode: RECURSIVE_INTERFACE_INHERITANCE
script:
- |
@@ -1801,11 +1801,6 @@
- |
class A implements B {}
class B implements A {}
-
-DirectCyclicClassHierarchy:
- template: "'#name' can't use itself as a supertype."
- analyzerCode: RECURSIVE_INTERFACE_INHERITANCE
- script:
- "class C = Object with C;"
- "class C extends C {}"
- "class C implements C {}"
diff --git a/pkg/front_end/testcases/cycles.dart.legacy.expect b/pkg/front_end/testcases/cycles.dart.legacy.expect
index d2e8cdf..4ee0331 100644
--- a/pkg/front_end/testcases/cycles.dart.legacy.expect
+++ b/pkg/front_end/testcases/cycles.dart.legacy.expect
@@ -1,28 +1,28 @@
// Formatted problems:
//
-// pkg/front_end/testcases/cycles.dart:5:7: Error: 'A' is a supertype of itself via 'B', 'C'.
+// pkg/front_end/testcases/cycles.dart:5:7: Error: 'A' is a supertype of itself.
// class A implements C {}
// ^
//
-// pkg/front_end/testcases/cycles.dart:7:7: Error: 'B' is a supertype of itself via 'A', 'C'.
+// pkg/front_end/testcases/cycles.dart:7:7: Error: 'B' is a supertype of itself.
// class B extends A {}
// ^
//
-// pkg/front_end/testcases/cycles.dart:9:7: Error: 'C' is a supertype of itself via 'A', 'B'.
+// pkg/front_end/testcases/cycles.dart:9:7: Error: 'C' is a supertype of itself.
// class C extends B implements D {}
// ^
// Unhandled errors:
//
-// pkg/front_end/testcases/cycles.dart:5:7: Error: 'A' is a supertype of itself via 'B', 'C'.
+// pkg/front_end/testcases/cycles.dart:5:7: Error: 'A' is a supertype of itself.
// class A implements C {}
// ^
//
-// pkg/front_end/testcases/cycles.dart:7:7: Error: 'B' is a supertype of itself via 'A', 'C'.
+// pkg/front_end/testcases/cycles.dart:7:7: Error: 'B' is a supertype of itself.
// class B extends A {}
// ^
//
-// pkg/front_end/testcases/cycles.dart:9:7: Error: 'C' is a supertype of itself via 'A', 'B'.
+// pkg/front_end/testcases/cycles.dart:9:7: Error: 'C' is a supertype of itself.
// class C extends B implements D {}
// ^
diff --git a/pkg/front_end/testcases/cycles.dart.legacy.transformed.expect b/pkg/front_end/testcases/cycles.dart.legacy.transformed.expect
index 435c417..08a24b3 100644
--- a/pkg/front_end/testcases/cycles.dart.legacy.transformed.expect
+++ b/pkg/front_end/testcases/cycles.dart.legacy.transformed.expect
@@ -1,14 +1,14 @@
// Unhandled errors:
//
-// pkg/front_end/testcases/cycles.dart:5:7: Error: 'A' is a supertype of itself via 'B', 'C'.
+// pkg/front_end/testcases/cycles.dart:5:7: Error: 'A' is a supertype of itself.
// class A implements C {}
// ^
//
-// pkg/front_end/testcases/cycles.dart:7:7: Error: 'B' is a supertype of itself via 'A', 'C'.
+// pkg/front_end/testcases/cycles.dart:7:7: Error: 'B' is a supertype of itself.
// class B extends A {}
// ^
//
-// pkg/front_end/testcases/cycles.dart:9:7: Error: 'C' is a supertype of itself via 'A', 'B'.
+// pkg/front_end/testcases/cycles.dart:9:7: Error: 'C' is a supertype of itself.
// class C extends B implements D {}
// ^
diff --git a/pkg/front_end/testcases/cycles.dart.outline.expect b/pkg/front_end/testcases/cycles.dart.outline.expect
index 3aaceb9..b1b0614 100644
--- a/pkg/front_end/testcases/cycles.dart.outline.expect
+++ b/pkg/front_end/testcases/cycles.dart.outline.expect
@@ -1,14 +1,14 @@
// Formatted problems:
//
-// pkg/front_end/testcases/cycles.dart:5:7: Error: 'A' is a supertype of itself via 'B', 'C'.
+// pkg/front_end/testcases/cycles.dart:5:7: Error: 'A' is a supertype of itself.
// class A implements C {}
// ^
//
-// pkg/front_end/testcases/cycles.dart:7:7: Error: 'B' is a supertype of itself via 'A', 'C'.
+// pkg/front_end/testcases/cycles.dart:7:7: Error: 'B' is a supertype of itself.
// class B extends A {}
// ^
//
-// pkg/front_end/testcases/cycles.dart:9:7: Error: 'C' is a supertype of itself via 'A', 'B'.
+// pkg/front_end/testcases/cycles.dart:9:7: Error: 'C' is a supertype of itself.
// class C extends B implements D {}
// ^
diff --git a/pkg/front_end/testcases/cycles.dart.strong.expect b/pkg/front_end/testcases/cycles.dart.strong.expect
index d2e8cdf..4ee0331 100644
--- a/pkg/front_end/testcases/cycles.dart.strong.expect
+++ b/pkg/front_end/testcases/cycles.dart.strong.expect
@@ -1,28 +1,28 @@
// Formatted problems:
//
-// pkg/front_end/testcases/cycles.dart:5:7: Error: 'A' is a supertype of itself via 'B', 'C'.
+// pkg/front_end/testcases/cycles.dart:5:7: Error: 'A' is a supertype of itself.
// class A implements C {}
// ^
//
-// pkg/front_end/testcases/cycles.dart:7:7: Error: 'B' is a supertype of itself via 'A', 'C'.
+// pkg/front_end/testcases/cycles.dart:7:7: Error: 'B' is a supertype of itself.
// class B extends A {}
// ^
//
-// pkg/front_end/testcases/cycles.dart:9:7: Error: 'C' is a supertype of itself via 'A', 'B'.
+// pkg/front_end/testcases/cycles.dart:9:7: Error: 'C' is a supertype of itself.
// class C extends B implements D {}
// ^
// Unhandled errors:
//
-// pkg/front_end/testcases/cycles.dart:5:7: Error: 'A' is a supertype of itself via 'B', 'C'.
+// pkg/front_end/testcases/cycles.dart:5:7: Error: 'A' is a supertype of itself.
// class A implements C {}
// ^
//
-// pkg/front_end/testcases/cycles.dart:7:7: Error: 'B' is a supertype of itself via 'A', 'C'.
+// pkg/front_end/testcases/cycles.dart:7:7: Error: 'B' is a supertype of itself.
// class B extends A {}
// ^
//
-// pkg/front_end/testcases/cycles.dart:9:7: Error: 'C' is a supertype of itself via 'A', 'B'.
+// pkg/front_end/testcases/cycles.dart:9:7: Error: 'C' is a supertype of itself.
// class C extends B implements D {}
// ^
diff --git a/pkg/front_end/testcases/cycles.dart.strong.transformed.expect b/pkg/front_end/testcases/cycles.dart.strong.transformed.expect
index 435c417..08a24b3 100644
--- a/pkg/front_end/testcases/cycles.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/cycles.dart.strong.transformed.expect
@@ -1,14 +1,14 @@
// Unhandled errors:
//
-// pkg/front_end/testcases/cycles.dart:5:7: Error: 'A' is a supertype of itself via 'B', 'C'.
+// pkg/front_end/testcases/cycles.dart:5:7: Error: 'A' is a supertype of itself.
// class A implements C {}
// ^
//
-// pkg/front_end/testcases/cycles.dart:7:7: Error: 'B' is a supertype of itself via 'A', 'C'.
+// pkg/front_end/testcases/cycles.dart:7:7: Error: 'B' is a supertype of itself.
// class B extends A {}
// ^
//
-// pkg/front_end/testcases/cycles.dart:9:7: Error: 'C' is a supertype of itself via 'A', 'B'.
+// pkg/front_end/testcases/cycles.dart:9:7: Error: 'C' is a supertype of itself.
// class C extends B implements D {}
// ^
diff --git a/pkg/front_end/testcases/incremental_bulk_compiler_smoke.status b/pkg/front_end/testcases/incremental_bulk_compiler_smoke.status
index 4240855..959cc51 100644
--- a/pkg/front_end/testcases/incremental_bulk_compiler_smoke.status
+++ b/pkg/front_end/testcases/incremental_bulk_compiler_smoke.status
@@ -1,9 +1,8 @@
# 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.md file.
+
language_2/deferred_super_dependency_test: Crash # missing "#errors"
language_2/missing_part_of_tag_test: Crash # missing empty library that shouldn't have been there in the first place
-language_2/regress_27957_test: Crash # isSynthetic becomes false on C1 SuperInitializer.
language_2/script1_negative_test: Crash # missing "#errors", missing empty library that shouldn't have been there in the first place
language_2/script2_negative_test: Crash # missing "#errors", missing empty library that shouldn't have been there in the first place
-
diff --git a/pkg/front_end/testcases/inference/circular_method_inference.dart.legacy.expect b/pkg/front_end/testcases/inference/circular_method_inference.dart.legacy.expect
index d03e49e..658bd51 100644
--- a/pkg/front_end/testcases/inference/circular_method_inference.dart.legacy.expect
+++ b/pkg/front_end/testcases/inference/circular_method_inference.dart.legacy.expect
@@ -1,20 +1,20 @@
// Formatted problems:
//
-// pkg/front_end/testcases/inference/circular_method_inference.dart:12:16: Error: 'A' is a supertype of itself via 'B'.
+// pkg/front_end/testcases/inference/circular_method_inference.dart:12:16: Error: 'A' is a supertype of itself.
// abstract class A extends B {
// ^
//
-// pkg/front_end/testcases/inference/circular_method_inference.dart:16:16: Error: 'B' is a supertype of itself via 'A'.
+// pkg/front_end/testcases/inference/circular_method_inference.dart:16:16: Error: 'B' is a supertype of itself.
// abstract class B extends A {
// ^
// Unhandled errors:
//
-// pkg/front_end/testcases/inference/circular_method_inference.dart:12:16: Error: 'A' is a supertype of itself via 'B'.
+// pkg/front_end/testcases/inference/circular_method_inference.dart:12:16: Error: 'A' is a supertype of itself.
// abstract class A extends B {
// ^
//
-// pkg/front_end/testcases/inference/circular_method_inference.dart:16:16: Error: 'B' is a supertype of itself via 'A'.
+// pkg/front_end/testcases/inference/circular_method_inference.dart:16:16: Error: 'B' is a supertype of itself.
// abstract class B extends A {
// ^
diff --git a/pkg/front_end/testcases/inference/circular_method_inference.dart.legacy.transformed.expect b/pkg/front_end/testcases/inference/circular_method_inference.dart.legacy.transformed.expect
index 8f3be84..fa9873c 100644
--- a/pkg/front_end/testcases/inference/circular_method_inference.dart.legacy.transformed.expect
+++ b/pkg/front_end/testcases/inference/circular_method_inference.dart.legacy.transformed.expect
@@ -1,10 +1,10 @@
// Unhandled errors:
//
-// pkg/front_end/testcases/inference/circular_method_inference.dart:12:16: Error: 'A' is a supertype of itself via 'B'.
+// pkg/front_end/testcases/inference/circular_method_inference.dart:12:16: Error: 'A' is a supertype of itself.
// abstract class A extends B {
// ^
//
-// pkg/front_end/testcases/inference/circular_method_inference.dart:16:16: Error: 'B' is a supertype of itself via 'A'.
+// pkg/front_end/testcases/inference/circular_method_inference.dart:16:16: Error: 'B' is a supertype of itself.
// abstract class B extends A {
// ^
diff --git a/pkg/front_end/testcases/inference/circular_method_inference.dart.outline.expect b/pkg/front_end/testcases/inference/circular_method_inference.dart.outline.expect
index 1cb6512..bd72e73 100644
--- a/pkg/front_end/testcases/inference/circular_method_inference.dart.outline.expect
+++ b/pkg/front_end/testcases/inference/circular_method_inference.dart.outline.expect
@@ -1,10 +1,10 @@
// Formatted problems:
//
-// pkg/front_end/testcases/inference/circular_method_inference.dart:12:16: Error: 'A' is a supertype of itself via 'B'.
+// pkg/front_end/testcases/inference/circular_method_inference.dart:12:16: Error: 'A' is a supertype of itself.
// abstract class A extends B {
// ^
//
-// pkg/front_end/testcases/inference/circular_method_inference.dart:16:16: Error: 'B' is a supertype of itself via 'A'.
+// pkg/front_end/testcases/inference/circular_method_inference.dart:16:16: Error: 'B' is a supertype of itself.
// abstract class B extends A {
// ^
diff --git a/pkg/front_end/testcases/inference/circular_method_inference.dart.strong.expect b/pkg/front_end/testcases/inference/circular_method_inference.dart.strong.expect
index d03e49e..658bd51 100644
--- a/pkg/front_end/testcases/inference/circular_method_inference.dart.strong.expect
+++ b/pkg/front_end/testcases/inference/circular_method_inference.dart.strong.expect
@@ -1,20 +1,20 @@
// Formatted problems:
//
-// pkg/front_end/testcases/inference/circular_method_inference.dart:12:16: Error: 'A' is a supertype of itself via 'B'.
+// pkg/front_end/testcases/inference/circular_method_inference.dart:12:16: Error: 'A' is a supertype of itself.
// abstract class A extends B {
// ^
//
-// pkg/front_end/testcases/inference/circular_method_inference.dart:16:16: Error: 'B' is a supertype of itself via 'A'.
+// pkg/front_end/testcases/inference/circular_method_inference.dart:16:16: Error: 'B' is a supertype of itself.
// abstract class B extends A {
// ^
// Unhandled errors:
//
-// pkg/front_end/testcases/inference/circular_method_inference.dart:12:16: Error: 'A' is a supertype of itself via 'B'.
+// pkg/front_end/testcases/inference/circular_method_inference.dart:12:16: Error: 'A' is a supertype of itself.
// abstract class A extends B {
// ^
//
-// pkg/front_end/testcases/inference/circular_method_inference.dart:16:16: Error: 'B' is a supertype of itself via 'A'.
+// pkg/front_end/testcases/inference/circular_method_inference.dart:16:16: Error: 'B' is a supertype of itself.
// abstract class B extends A {
// ^
diff --git a/pkg/front_end/testcases/inference/circular_method_inference.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/circular_method_inference.dart.strong.transformed.expect
index 8f3be84..fa9873c 100644
--- a/pkg/front_end/testcases/inference/circular_method_inference.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/circular_method_inference.dart.strong.transformed.expect
@@ -1,10 +1,10 @@
// Unhandled errors:
//
-// pkg/front_end/testcases/inference/circular_method_inference.dart:12:16: Error: 'A' is a supertype of itself via 'B'.
+// pkg/front_end/testcases/inference/circular_method_inference.dart:12:16: Error: 'A' is a supertype of itself.
// abstract class A extends B {
// ^
//
-// pkg/front_end/testcases/inference/circular_method_inference.dart:16:16: Error: 'B' is a supertype of itself via 'A'.
+// pkg/front_end/testcases/inference/circular_method_inference.dart:16:16: Error: 'B' is a supertype of itself.
// abstract class B extends A {
// ^
diff --git a/pkg/front_end/testcases/metadata_named_mixin_application.dart.outline.expect b/pkg/front_end/testcases/metadata_named_mixin_application.dart.outline.expect
index 1da773d..cec02ba 100644
--- a/pkg/front_end/testcases/metadata_named_mixin_application.dart.outline.expect
+++ b/pkg/front_end/testcases/metadata_named_mixin_application.dart.outline.expect
@@ -4,6 +4,7 @@
class C = self::D with self::E {
synthetic constructor •() → self::C
+ : super self::D::•()
;
}
class D extends core::Object {
diff --git a/pkg/front_end/testcases/qualified.dart.outline.expect b/pkg/front_end/testcases/qualified.dart.outline.expect
index 42db141..fb0b74d 100644
--- a/pkg/front_end/testcases/qualified.dart.outline.expect
+++ b/pkg/front_end/testcases/qualified.dart.outline.expect
@@ -32,6 +32,7 @@
}
abstract class _WithMixin&Supertype&Mixin = lib::Supertype with lib::Mixin {
synthetic constructor •() → self::_WithMixin&Supertype&Mixin
+ : super lib::Supertype::•()
;
}
class WithMixin extends self::_WithMixin&Supertype&Mixin {