Elements. Track not yet inferred classes in a set in InstanceMemberInferrer instead of a field in InterfaceElementImpl.
Change-Id: I3cf6962813d1e62e7b0caaa5e0a2cd9601e26781
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/448243
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index dc5f033..8ed4b8b4 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -4629,10 +4629,6 @@
List<InterfaceTypeImpl>? Function(InterfaceElementImpl)?
mixinInferenceCallback;
- /// A flag indicating whether the types associated with the instance members
- /// of this class have been inferred.
- bool hasBeenInferred = false;
-
/// Whether the class or its superclass declares a non-final instance field.
bool hasNonFinalField = false;
diff --git a/pkg/analyzer/lib/src/summary2/instance_member_inferrer.dart b/pkg/analyzer/lib/src/summary2/instance_member_inferrer.dart
index f9f2bf4..343fece 100644
--- a/pkg/analyzer/lib/src/summary2/instance_member_inferrer.dart
+++ b/pkg/analyzer/lib/src/summary2/instance_member_inferrer.dart
@@ -18,7 +18,7 @@
/// https://github.com/dart-lang/language/blob/main/resources/type-system/inference.md
class InstanceMemberInferrer {
final InheritanceManager3 inheritance;
- final Set<InterfaceElementImpl> elementsBeingInferred = {};
+ final Set<InterfaceElementImpl> interfacesToInfer = {};
late InterfaceElementImpl currentInterfaceElement;
@@ -29,11 +29,11 @@
return currentInterfaceElement.library.typeSystem;
}
- void inferLibrary(LibraryElementImpl library) {
- _inferClasses(library.classes);
- _inferClasses(library.enums);
- _inferExtensionTypes(library.extensionTypes);
- _inferClasses(library.mixins);
+ void perform(List<InterfaceElementImpl> elements) {
+ interfacesToInfer.addAll(elements);
+ for (var element in elements) {
+ _inferClass(element);
+ }
}
/// Return `true` if the elements corresponding to the [elements] have the
@@ -317,67 +317,43 @@
/// Infer type information for all of the instance members in the given
/// [element].
void _inferClass(InterfaceElementImpl element) {
- if (element.hasBeenInferred) {
+ if (!interfacesToInfer.remove(element)) {
return;
}
_setInducedModifier(element);
- if (!elementsBeingInferred.add(element)) {
- // We have found a circularity in the class hierarchy. For now we just
- // stop trying to infer any type information for any classes that
- // inherit from any class in the cycle. We could potentially limit the
- // algorithm to only not inferring types in the classes in the cycle,
- // but it isn't clear that the results would be significantly better.
- throw _CycleException();
+ //
+ // Ensure that all of instance members in the supertypes have had types
+ // inferred for them.
+ //
+ _inferType(element.supertype);
+ element.mixins.forEach(_inferType);
+ element.interfaces.forEach(_inferType);
+
+ //
+ // Then infer the types for the members.
+ //
+ currentInterfaceElement = element;
+ for (var field in element.fields) {
+ _inferAccessorOrField(field: field);
+ }
+ for (var getter in element.getters) {
+ _inferAccessorOrField(getter: getter);
+ }
+ for (var setter in element.setters) {
+ _inferAccessorOrField(setter: setter);
+ }
+ for (var method in element.methods) {
+ _inferExecutable(method);
}
- try {
- //
- // Ensure that all of instance members in the supertypes have had types
- // inferred for them.
- //
- _inferType(element.supertype);
- element.mixins.forEach(_inferType);
- element.interfaces.forEach(_inferType);
- //
- // Then infer the types for the members.
- //
- // TODO(scheglov): get other members from the container
- currentInterfaceElement = element;
- for (var field in element.fields) {
- _inferAccessorOrField(field: field);
- }
- for (var getter in element.getters) {
- _inferAccessorOrField(getter: getter);
- }
- for (var setter in element.setters) {
- _inferAccessorOrField(setter: setter);
- }
- for (var method in element.methods) {
- _inferExecutable(method);
- }
- //
- // Infer initializing formal parameter types. This must happen after
- // field types are inferred.
- //
- for (var constructor in element.constructors) {
- _inferConstructor(constructor);
- }
- element.hasBeenInferred = true;
- } finally {
- elementsBeingInferred.remove(element);
- }
- }
-
- void _inferClasses(List<InterfaceElementImpl> elements) {
- for (var element in elements) {
- try {
- _inferClass(element);
- } on _CycleException {
- // This is a short circuit return to prevent types that inherit from
- // types containing a circular reference from being inferred.
- }
+ //
+ // Infer initializing formal parameter types. This must happen after
+ // field types are inferred.
+ //
+ for (var constructor in element.constructors) {
+ _inferConstructor(constructor);
}
}
@@ -494,14 +470,6 @@
_resetOperatorEqualParameterTypeToDynamic(element, overriddenElements);
}
- void _inferExtensionTypes(List<ExtensionTypeElementImpl> extensionTypes) {
- for (var extensionType in extensionTypes) {
- for (var constructor in extensionType.constructors) {
- _inferConstructor(constructor);
- }
- }
- }
-
void _inferMixinApplicationConstructor(
ClassElementImpl classElement,
ConstructorElementImpl constructor,
@@ -757,9 +725,6 @@
}
}
-/// A class of exception that is not used anywhere else.
-class _CycleException implements Exception {}
-
extension on InterfaceElementImpl {
bool get isBase {
switch (this) {
diff --git a/pkg/analyzer/lib/src/summary2/top_level_inference.dart b/pkg/analyzer/lib/src/summary2/top_level_inference.dart
index 0ea15f0..7417d75 100644
--- a/pkg/analyzer/lib/src/summary2/top_level_inference.dart
+++ b/pkg/analyzer/lib/src/summary2/top_level_inference.dart
@@ -98,10 +98,12 @@
}
void _performOverrideInference() {
+ var interfacesToInfer = linker.builders.values.expand((builder) {
+ return builder.element.children.whereType<InterfaceElementImpl>();
+ }).toList();
+
var inferrer = InstanceMemberInferrer(linker.inheritance);
- for (var builder in linker.builders.values) {
- inferrer.inferLibrary(builder.element);
- }
+ inferrer.perform(interfacesToInfer);
}
}