Skip to content

Commit dce956e

Browse files
scheglovCommit Queue
authored andcommitted
Elements. Break cycles in InterfaceElementImpl.
Change-Id: Iaea43db437064f21dee54b4c89938830caf60f39 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/445805 Reviewed-by: Johnni Winther <[email protected]> Reviewed-by: Samuel Rawlins <[email protected]> Commit-Queue: Konstantin Shcheglov <[email protected]>
1 parent 048f059 commit dce956e

File tree

14 files changed

+384
-103
lines changed

14 files changed

+384
-103
lines changed

pkg/analysis_server/test/search/type_hierarchy_test.dart

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,18 @@ class B extends A {
6464
'superclass': 1,
6565
'interfaces': [],
6666
'mixins': [],
67-
'subclasses': [1],
67+
'subclasses': [2],
68+
},
69+
{
70+
'classElement': {
71+
'kind': 'CLASS',
72+
'name': 'Object',
73+
'location': anything,
74+
'flags': 0,
75+
},
76+
'interfaces': [],
77+
'mixins': [],
78+
'subclasses': [],
6879
},
6980
{
7081
'classElement': {
@@ -76,7 +87,7 @@ class B extends A {
7687
'superclass': 0,
7788
'interfaces': [],
7889
'mixins': [],
79-
'subclasses': [],
90+
'subclasses': [0],
8091
},
8192
]);
8293
}

pkg/analyzer/lib/src/dart/analysis/driver.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ testFineAfterLibraryAnalyzerHook;
109109
// TODO(scheglov): Clean up the list of implicitly analyzed files.
110110
class AnalysisDriver {
111111
/// The version of data format, should be incremented on every format change.
112-
static const int DATA_VERSION = 522;
112+
static const int DATA_VERSION = 523;
113113

114114
/// The number of exception contexts allowed to write. Once this field is
115115
/// zero, we stop writing any new exception contexts in this process.

pkg/analyzer/lib/src/dart/element/element.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4600,6 +4600,10 @@ abstract class InterfaceElementImpl extends InstanceElementImpl
46004600

46014601
InterfaceTypeImpl? _thisType;
46024602

4603+
/// If not `null`, this element was part of a supertypes cycle. The cycle
4604+
/// is broken by clearing supertypes for all cycle elements.
4605+
List<InterfaceElementImpl>? interfaceCycle;
4606+
46034607
/// The cached result of [allSupertypes].
46044608
List<InterfaceTypeImpl>? _allSupertypes;
46054609

pkg/analyzer/lib/src/error/inheritance_override.dart

Lines changed: 48 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -560,82 +560,71 @@ class _ClassVerifier {
560560
/// [CompileTimeErrorCode.recursiveInterfaceInheritanceImplements],
561561
/// [CompileTimeErrorCode.recursiveInterfaceInheritanceOn],
562562
/// [CompileTimeErrorCode.recursiveInterfaceInheritanceWith].
563-
bool _checkForRecursiveInterfaceInheritance(
564-
InterfaceElementImpl element, [
565-
List<InterfaceElement>? path,
566-
]) {
567-
path ??= <InterfaceElement>[];
568-
569-
// Detect error condition.
570-
int size = path.length;
571-
// If this is not the base case (size > 0), and the enclosing class is the
572-
// given class element then report an error.
573-
if (size > 0 && classElement == element) {
574-
String className = classElement.displayName;
575-
if (size > 1) {
576-
// Construct a string showing the cyclic implements path:
577-
// "A, B, C, D, A"
578-
String separator = ", ";
579-
StringBuffer buffer = StringBuffer();
580-
for (int i = 0; i < size; i++) {
581-
buffer.write(path[i].displayName);
582-
buffer.write(separator);
583-
}
584-
buffer.write(element.displayName);
585-
reporter.atElement2(
586-
classElement,
587-
CompileTimeErrorCode.recursiveInterfaceInheritance,
588-
arguments: [className, buffer.toString()],
589-
);
590-
return true;
591-
} else {
592-
// RECURSIVE_INTERFACE_INHERITANCE_BASE_CASE_EXTENDS or
593-
// RECURSIVE_INTERFACE_INHERITANCE_BASE_CASE_IMPLEMENTS or
594-
// RECURSIVE_INTERFACE_INHERITANCE_ON or
595-
// RECURSIVE_INTERFACE_INHERITANCE_BASE_CASE_WITH
563+
bool _checkForRecursiveInterfaceInheritance(InterfaceElementImpl element) {
564+
var cycle = element.interfaceCycle;
565+
if (cycle == null) {
566+
return false;
567+
}
568+
569+
if (superclass case var superclass?) {
570+
if (superclass.element == element) {
596571
reporter.atElement2(
597-
classElement,
598-
_getRecursiveErrorCode(element),
599-
arguments: [className],
572+
element,
573+
CompileTimeErrorCode.recursiveInterfaceInheritanceExtends,
574+
arguments: [element.displayName],
600575
);
601576
return true;
602577
}
603578
}
604579

605-
if (path.indexOf(element) > 0) {
606-
return false;
607-
}
608-
path.add(element);
609-
610-
// n-case
611-
var supertype = element.supertype;
612-
if (supertype != null &&
613-
_checkForRecursiveInterfaceInheritance(supertype.element, path)) {
614-
return true;
615-
}
616-
617-
for (var type in element.mixins) {
618-
if (_checkForRecursiveInterfaceInheritance(type.element, path)) {
619-
return true;
580+
if (onClause case var onClause?) {
581+
for (var typeAnnotation in onClause.superclassConstraints) {
582+
if (typeAnnotation.element == element) {
583+
reporter.atElement2(
584+
element,
585+
CompileTimeErrorCode.recursiveInterfaceInheritanceOn,
586+
arguments: [element.displayName],
587+
);
588+
return true;
589+
}
620590
}
621591
}
622592

623-
if (element is MixinElementImpl) {
624-
for (var type in element.superclassConstraints) {
625-
if (_checkForRecursiveInterfaceInheritance(type.element, path)) {
593+
if (withClause case var withClause?) {
594+
for (var typeAnnotation in withClause.mixinTypes) {
595+
if (typeAnnotation.element == element) {
596+
reporter.atElement2(
597+
element,
598+
CompileTimeErrorCode.recursiveInterfaceInheritanceWith,
599+
arguments: [element.displayName],
600+
);
626601
return true;
627602
}
628603
}
629604
}
630605

631-
for (var type in element.interfaces) {
632-
if (_checkForRecursiveInterfaceInheritance(type.element, path)) {
633-
return true;
606+
if (implementsClause case var implementsClause?) {
607+
for (var typeAnnotation in implementsClause.interfaces) {
608+
if (typeAnnotation.element == element) {
609+
reporter.atElement2(
610+
element,
611+
CompileTimeErrorCode.recursiveInterfaceInheritanceImplements,
612+
arguments: [element.displayName],
613+
);
614+
return true;
615+
}
634616
}
635617
}
636618

637-
path.removeAt(path.length - 1);
638-
return false;
619+
reporter.atElement2(
620+
classElement,
621+
CompileTimeErrorCode.recursiveInterfaceInheritance,
622+
arguments: [
623+
element.displayName,
624+
cycle.map((e) => e.displayName).join(', '),
625+
],
626+
);
627+
return true;
639628
}
640629

641630
void _checkIllegalConcreteEnumMemberDeclaration(Token name) {
@@ -742,30 +731,6 @@ class _ClassVerifier {
742731
return true;
743732
}
744733

745-
/// Return the error code that should be used when the given class [element]
746-
/// references itself directly.
747-
DiagnosticCode _getRecursiveErrorCode(InterfaceElement element) {
748-
if (element.supertype?.element == classElement) {
749-
return CompileTimeErrorCode.recursiveInterfaceInheritanceExtends;
750-
}
751-
752-
if (element is MixinElement) {
753-
for (var type in element.superclassConstraints) {
754-
if (type.element == classElement) {
755-
return CompileTimeErrorCode.recursiveInterfaceInheritanceOn;
756-
}
757-
}
758-
}
759-
760-
for (var type in element.mixins) {
761-
if (type.element == classElement) {
762-
return CompileTimeErrorCode.recursiveInterfaceInheritanceWith;
763-
}
764-
}
765-
766-
return CompileTimeErrorCode.recursiveInterfaceInheritanceImplements;
767-
}
768-
769734
/// If [name] is not implemented in the extended concrete class, the
770735
/// issue should be fixed there, and then [classElement] will not have it too.
771736
bool _isNotImplementedInConcreteSuperClass(Name name) {

pkg/analyzer/lib/src/summary2/bundle_reader.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,7 @@ class LibraryReader {
293293
element.supertype = reader._readOptionalInterfaceType();
294294
element.mixins = reader._readInterfaceTypeList();
295295
element.interfaces = reader._readInterfaceTypeList();
296+
element.interfaceCycle = reader.readOptionalElementList();
296297
}),
297298
);
298299

@@ -493,6 +494,7 @@ class LibraryReader {
493494
element.supertype = reader._readOptionalInterfaceType();
494495
element.mixins = reader._readInterfaceTypeList();
495496
element.interfaces = reader._readInterfaceTypeList();
497+
element.interfaceCycle = reader.readOptionalElementList();
496498
}),
497499
);
498500

@@ -632,6 +634,7 @@ class LibraryReader {
632634
reader._addTypeParameters2(element.typeParameters);
633635
element.typeErasure = reader.readRequiredType();
634636
element.interfaces = reader._readInterfaceTypeList();
637+
element.interfaceCycle = reader.readOptionalElementList();
635638
}),
636639
);
637640

@@ -967,6 +970,7 @@ class LibraryReader {
967970
reader._addTypeParameters2(element.typeParameters);
968971
element.superclassConstraints = reader._readInterfaceTypeList();
969972
element.interfaces = reader._readInterfaceTypeList();
973+
element.interfaceCycle = reader.readOptionalElementList();
970974
}),
971975
);
972976

@@ -1537,6 +1541,10 @@ class ResolutionReader {
15371541
return _readNodeList();
15381542
}
15391543

1544+
List<T>? readOptionalElementList<T extends Element>() {
1545+
return _reader.readOptionalObject(readElementList);
1546+
}
1547+
15401548
ExpressionImpl? readOptionalExpression() {
15411549
if (_reader.readBool()) {
15421550
return _readRequiredNode() as ExpressionImpl;

pkg/analyzer/lib/src/summary2/bundle_writer.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ class BundleWriter {
160160
_resolutionSink.writeType(element.supertype);
161161
_resolutionSink._writeTypeList(element.mixins);
162162
_resolutionSink._writeTypeList(element.interfaces);
163+
_resolutionSink.writeOptionalElementList(element.interfaceCycle);
163164
});
164165
});
165166
});
@@ -275,6 +276,7 @@ class BundleWriter {
275276
_resolutionSink.writeType(element.supertype);
276277
_resolutionSink._writeTypeList(element.mixins);
277278
_resolutionSink._writeTypeList(element.interfaces);
279+
_resolutionSink.writeOptionalElementList(element.interfaceCycle);
278280
});
279281
});
280282
});
@@ -369,6 +371,7 @@ class BundleWriter {
369371
_resolutionSink.withTypeParameters(element.typeParameters, () {
370372
_resolutionSink.writeType(element.typeErasure);
371373
_resolutionSink._writeTypeList(element.interfaces);
374+
_resolutionSink.writeOptionalElementList(element.interfaceCycle);
372375
});
373376
});
374377
});
@@ -572,6 +575,7 @@ class BundleWriter {
572575
_resolutionSink.withTypeParameters(element.typeParameters, () {
573576
_resolutionSink._writeTypeList(element.superclassConstraints);
574577
_resolutionSink._writeTypeList(element.interfaces);
578+
_resolutionSink.writeOptionalElementList(element.interfaceCycle);
575579
});
576580
});
577581
});
@@ -913,6 +917,10 @@ class ResolutionSink extends _SummaryDataWriter {
913917
}
914918
}
915919

920+
void writeOptionalElementList(List<Element>? elements) {
921+
writeOptionalObject(elements, (it) => _writeElementList(it));
922+
}
923+
916924
void writeOptionalTypeList(List<DartType>? types) {
917925
if (types != null) {
918926
writeBool(true);

0 commit comments

Comments
 (0)