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); } }