mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 01:45:06 +00:00
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>
This commit is contained in:
parent
77889c10e3
commit
6ec321f2b7
|
@ -57,9 +57,6 @@ class DillTarget extends TargetImplementation {
|
|||
return new DillLibraryBuilder(uri, loader);
|
||||
}
|
||||
|
||||
@override
|
||||
void addDirectSupertype(ClassBuilder cls, Set<ClassBuilder> set) {}
|
||||
|
||||
@override
|
||||
void breakCycle(ClassBuilder cls) {}
|
||||
}
|
||||
|
|
|
@ -1754,27 +1754,24 @@ Message _withArgumentsCycleInTypeVariables(String name, String string) {
|
|||
}
|
||||
|
||||
// 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.
|
||||
|
@ -2043,28 +2040,6 @@ Message _withArgumentsDirectCycleInTypeVariables(String name) {
|
|||
arguments: {'name': name});
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
|
|
@ -197,37 +197,6 @@ class KernelTarget extends TargetImplementation {
|
|||
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 @@ class KernelTarget extends TargetImplementation {
|
|||
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 @@ class KernelTarget extends TargetImplementation {
|
|||
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);
|
||||
|
|
|
@ -24,12 +24,14 @@ import '../fasta_codes.dart'
|
|||
|
||||
import '../kernel/kernel_builder.dart'
|
||||
show
|
||||
ClassBuilder,
|
||||
ConstructorReferenceBuilder,
|
||||
Declaration,
|
||||
KernelClassBuilder,
|
||||
KernelFieldBuilder,
|
||||
KernelFunctionBuilder,
|
||||
KernelLibraryBuilder,
|
||||
KernelNamedTypeBuilder,
|
||||
KernelTypeBuilder,
|
||||
KernelTypeVariableBuilder,
|
||||
LibraryBuilder,
|
||||
|
@ -69,7 +71,8 @@ ShadowClass initializeClass(
|
|||
return cls;
|
||||
}
|
||||
|
||||
class SourceClassBuilder extends KernelClassBuilder {
|
||||
class SourceClassBuilder extends KernelClassBuilder
|
||||
implements Comparable<SourceClassBuilder> {
|
||||
@override
|
||||
final Class actualCls;
|
||||
|
||||
|
@ -247,7 +250,9 @@ class SourceClassBuilder extends KernelClassBuilder {
|
|||
declaration.prepareTopLevelInference();
|
||||
}
|
||||
});
|
||||
cls.setupApiMembers(library.loader.interfaceResolver);
|
||||
if (!isPatch) {
|
||||
cls.setupApiMembers(library.loader.interfaceResolver);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -274,4 +279,33 @@ class SourceClassBuilder extends KernelClassBuilder {
|
|||
});
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,7 +66,6 @@ import '../fasta_codes.dart'
|
|||
templateIllegalMixinDueToConstructorsCause,
|
||||
templateInternalProblemUriMissingScheme,
|
||||
templateSourceOutlineSummary,
|
||||
templateDirectCyclicClassHierarchy,
|
||||
templateUntranslatableUri;
|
||||
|
||||
import '../fasta_codes.dart' as fasta_codes;
|
||||
|
@ -95,7 +94,7 @@ import '../parser/class_member_parser.dart' show ClassMemberParser;
|
|||
|
||||
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 @@ class SourceLoader<L> extends Loader<L> {
|
|||
|
||||
Instrumentation instrumentation;
|
||||
|
||||
List<ClassBuilder> orderedClasses;
|
||||
|
||||
SourceLoader(this.fileSystem, this.includeComments, KernelTarget target)
|
||||
: super(target);
|
||||
|
||||
|
@ -504,57 +501,6 @@ class SourceLoader<L> extends Loader<L> {
|
|||
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 @@ class SourceLoader<L> extends Loader<L> {
|
|||
}
|
||||
}
|
||||
|
||||
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 @@ class SourceLoader<L> extends Loader<L> {
|
|||
}
|
||||
});
|
||||
ticker.logMs("Checked imports and exports for duplicate names");
|
||||
return classes;
|
||||
}
|
||||
|
||||
void buildComponent() {
|
||||
|
@ -847,7 +824,7 @@ class SourceLoader<L> extends Loader<L> {
|
|||
|
||||
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 @@ class SourceLoader<L> extends Loader<L> {
|
|||
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 @@ class SourceLoader<L> extends Loader<L> {
|
|||
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 @@ class SourceLoader<L> extends Loader<L> {
|
|||
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 @@ class SourceLoader<L> extends Loader<L> {
|
|||
|
||||
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 @@ class SourceLoader<L> extends Loader<L> {
|
|||
|
||||
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 @@ class SourceLoader<L> extends Loader<L> {
|
|||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
// 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 @@ class SourceLoader<L> extends Loader<L> {
|
|||
/// 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 @@ class SourceLoader<L> extends Loader<L> {
|
|||
}
|
||||
}
|
||||
|
||||
orderedClasses = null;
|
||||
typeInferenceEngine.finishTopLevelInitializingFormals();
|
||||
if (instrumentation != null) {
|
||||
builders.forEach((Uri uri, LibraryBuilder library) {
|
||||
|
|
|
@ -46,9 +46,6 @@ abstract class TargetImplementation extends Target {
|
|||
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.
|
||||
|
|
|
@ -1792,7 +1792,7 @@ DuplicatedImportInType:
|
|||
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 @@ CyclicClassHierarchy:
|
|||
- |
|
||||
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 {}"
|
||||
|
|
|
@ -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 {}
|
||||
// ^
|
||||
|
||||
|
|
|
@ -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 {}
|
||||
// ^
|
||||
|
||||
|
|
|
@ -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 {}
|
||||
// ^
|
||||
|
||||
|
|
|
@ -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 {}
|
||||
// ^
|
||||
|
||||
|
|
|
@ -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 {}
|
||||
// ^
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 {
|
||||
// ^
|
||||
|
||||
|
|
|
@ -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 {
|
||||
// ^
|
||||
|
||||
|
|
|
@ -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 {
|
||||
// ^
|
||||
|
||||
|
|
|
@ -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 {
|
||||
// ^
|
||||
|
||||
|
|
|
@ -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 {
|
||||
// ^
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import "dart:core" as core;
|
|||
|
||||
class C = self::D with self::E {
|
||||
synthetic constructor •() → self::C
|
||||
: super self::D::•()
|
||||
;
|
||||
}
|
||||
class D extends core::Object {
|
||||
|
|
|
@ -32,6 +32,7 @@ class Bad extends core::Object {
|
|||
}
|
||||
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 {
|
||||
|
|
Loading…
Reference in a new issue