From 7f8b26639d7ba159b530cc6ce694343a4b13bc7a Mon Sep 17 00:00:00 2001 From: Konstantin Shcheglov Date: Mon, 16 Oct 2023 21:56:30 +0000 Subject: [PATCH] Use InterfaceType directly in InterfaceLeastUpperBoundHelper. Change-Id: I359ad5d3fae4f4237cb2d58b5d1a6d92dc034cfd Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/330700 Reviewed-by: Brian Wilkerson Commit-Queue: Konstantin Shcheglov --- .../src/dart/element/least_upper_bound.dart | 186 ++---------------- .../least_upper_bound_helper_test.dart | 168 ++++++++-------- 2 files changed, 105 insertions(+), 249 deletions(-) diff --git a/pkg/analyzer/lib/src/dart/element/least_upper_bound.dart b/pkg/analyzer/lib/src/dart/element/least_upper_bound.dart index dde8cf1fc388..95e8477532b8 100644 --- a/pkg/analyzer/lib/src/dart/element/least_upper_bound.dart +++ b/pkg/analyzer/lib/src/dart/element/least_upper_bound.dart @@ -10,150 +10,12 @@ import 'package:analyzer/dart/element/type.dart'; import 'package:analyzer/src/dart/element/element.dart'; import 'package:analyzer/src/dart/element/extensions.dart'; import 'package:analyzer/src/dart/element/type.dart'; -import 'package:analyzer/src/dart/element/type_algebra.dart'; import 'package:analyzer/src/dart/element/type_schema.dart'; import 'package:analyzer/src/dart/element/type_system.dart'; import 'package:analyzer/src/dart/resolver/variance.dart'; import 'package:analyzer/src/generated/utilities_dart.dart'; import 'package:meta/meta.dart'; -/// The instantiation of a [ClassElement] with type arguments. -/// -/// It is not a [DartType] itself, because it does not have nullability. -/// But it should be used where nullability does not make sense - to specify -/// superclasses, mixins, and implemented interfaces. -class InstantiatedClass { - final InterfaceElement element; - final List arguments; - - final Substitution _substitution; - - InstantiatedClass(this.element, this.arguments) - : _substitution = Substitution.fromPairs( - element.typeParameters, - arguments, - ); - - /// Return the [InstantiatedClass] that corresponds to the [type] - with the - /// same element and type arguments, ignoring its nullability suffix. - factory InstantiatedClass.of(InterfaceType type) { - return InstantiatedClass(type.element, type.typeArguments); - } - - @override - int get hashCode { - var hash = 0x3fffffff & element.hashCode; - for (var i = 0; i < arguments.length; i++) { - hash = 0x3fffffff & (hash * 31 + (hash ^ arguments[i].hashCode)); - } - return hash; - } - - /// Return the interfaces that are directly implemented by this class. - List get interfaces { - var interfaces = element.interfaces; - return _toInstantiatedClasses(interfaces); - } - - /// Return `true` if this type represents the type 'Function' defined in the - /// dart:core library. - bool get isDartCoreFunction { - return element.name == 'Function' && element.library.isDartCore; - } - - /// Return the mixin that are directly implemented by this class. - List get mixins { - var mixins = element.mixins; - return _toInstantiatedClasses(mixins); - } - - /// Return the superclass of this type, or `null` if this type represents - /// the class 'Object'. - InstantiatedClass? get superclass { - final element = this.element; - - var supertype = element.supertype; - if (supertype == null) return null; - - supertype = _substitution.substituteType(supertype) as InterfaceType; - return InstantiatedClass.of(supertype); - } - - /// Return a list containing all of the superclass constraints defined for - /// this class. The list will be empty if this class does not represent a - /// mixin declaration. If this class _does_ represent a mixin declaration but - /// the declaration does not have an `on` clause, then the list will contain - /// the type for the class `Object`. - List get superclassConstraints { - final element = this.element; - if (element is MixinElement) { - var constraints = element.superclassConstraints; - return _toInstantiatedClasses(constraints); - } else { - return []; - } - } - - @visibleForTesting - InterfaceType get withNullabilitySuffixNone { - return withNullability(NullabilitySuffix.none); - } - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - - if (other is InstantiatedClass) { - if (element != other.element) return false; - if (arguments.length != other.arguments.length) return false; - for (var i = 0; i < arguments.length; i++) { - if (arguments[i] != other.arguments[i]) return false; - } - return true; - } - return false; - } - - InstantiatedClass mapArguments(DartType Function(DartType) f) { - var mappedArguments = arguments.map(f).toList(); - return InstantiatedClass(element, mappedArguments); - } - - @override - String toString() { - var buffer = StringBuffer(); - buffer.write(element.name); - if (arguments.isNotEmpty) { - buffer.write('<'); - buffer.write(arguments.join(', ')); - buffer.write('>'); - } - return buffer.toString(); - } - - InterfaceTypeImpl withNullability(NullabilitySuffix nullability) { - return InterfaceTypeImpl( - element: element, - typeArguments: arguments, - nullabilitySuffix: nullability, - ); - } - - List _toInstantiatedClasses( - List interfaces, - ) { - var result = []; - for (var i = 0; i < interfaces.length; i++) { - var interface = interfaces[i]; - var substituted = - _substitution.substituteType(interface) as InterfaceType; - result.add(InstantiatedClass.of(substituted)); - } - - return result; - } -} - class InterfaceLeastUpperBoundHelper { final TypeSystemImpl typeSystem; @@ -218,10 +80,8 @@ class InterfaceLeastUpperBoundHelper { if (!typeSystem.isSubtypeOf(args1[i], args2[i]) || !typeSystem.isSubtypeOf(args2[i], args1[i])) { // No bound will be valid, find bound at the interface level. - return _computeLeastUpperBound( - InstantiatedClass.of(type1), - InstantiatedClass.of(type2), - ).withNullability(nullability); + return _computeLeastUpperBound(type1, type2) + .withNullability(nullability); } // TODO (kallentu) : Fix asymmetric bounds behavior for invariant type // parameters. @@ -239,24 +99,22 @@ class InterfaceLeastUpperBoundHelper { ); } - var result = _computeLeastUpperBound( - InstantiatedClass.of(type1), - InstantiatedClass.of(type2), - ); + var result = _computeLeastUpperBound(type1, type2); return result.withNullability(nullability); } /// Return all of the superinterfaces of the given [type]. @visibleForTesting - Set computeSuperinterfaceSet(InstantiatedClass type) { - var result = {}; + Set computeSuperinterfaceSet(InterfaceType type) { + var result = {}; _addSuperinterfaces(result, type); if (typeSystem.isNonNullableByDefault) { return result; } else { - return result.map((e) { - return e.mapArguments(typeSystem.toLegacyTypeIfOptOut); - }).toSet(); + return result + .map(typeSystem.toLegacyTypeIfOptOut) + .cast() + .toSet(); } } @@ -265,9 +123,9 @@ class InterfaceLeastUpperBoundHelper { /// /// In the event that the algorithm fails (which might occur due to a bug in /// the analyzer), `null` is returned. - InstantiatedClass _computeLeastUpperBound( - InstantiatedClass i, - InstantiatedClass j, + InterfaceTypeImpl _computeLeastUpperBound( + InterfaceTypeImpl i, + InterfaceTypeImpl j, ) { // compute set of supertypes var si = computeSuperinterfaceSet(i); @@ -278,7 +136,7 @@ class InterfaceLeastUpperBoundHelper { sj.add(j); // compute intersection, reference as set 's' - var s = _intersection(si, sj); + var s = si.intersection(sj).toList(); return _computeTypeAtMaxUniqueDepth(s); } @@ -291,8 +149,7 @@ class InterfaceLeastUpperBoundHelper { } /// Add all of the superinterfaces of the given [type] to the given [set]. - static void _addSuperinterfaces( - Set set, InstantiatedClass type) { + static void _addSuperinterfaces(Set set, InterfaceType type) { for (var interface in type.interfaces) { if (!interface.isDartCoreFunction) { if (set.add(interface)) { @@ -409,8 +266,8 @@ class InterfaceLeastUpperBoundHelper { /// Return the type from the [types] list that has the longest inheritance /// path to Object of unique length. - static InstantiatedClass _computeTypeAtMaxUniqueDepth( - List types, + static InterfaceTypeImpl _computeTypeAtMaxUniqueDepth( + List types, ) { // for each element in Set s, compute the largest inheritance path to Object List depths = List.filled(types.length, 0); @@ -440,17 +297,6 @@ class InterfaceLeastUpperBoundHelper { // maximum depth. throw StateError('Empty path: $types'); } - - /// Return the intersection of the [first] and [second] sets of types, where - /// intersection is based on the equality of the types themselves. - static List _intersection( - Set first, - Set second, - ) { - var result = first.toSet(); - result.retainAll(second); - return result.toList(); - } } class LeastUpperBoundHelper { diff --git a/pkg/analyzer/test/src/dart/element/least_upper_bound_helper_test.dart b/pkg/analyzer/test/src/dart/element/least_upper_bound_helper_test.dart index a8016428beb2..50376a46ef8a 100644 --- a/pkg/analyzer/test/src/dart/element/least_upper_bound_helper_test.dart +++ b/pkg/analyzer/test/src/dart/element/least_upper_bound_helper_test.dart @@ -359,16 +359,16 @@ class SuperinterfaceSetTest extends AbstractTypeSystemTest { // D // - var instObject = InstantiatedClass.of(typeProvider.objectType); + var instObject = typeProvider.objectType; - ClassElementImpl classA = class_(name: 'A'); - var instA = InstantiatedClass(classA, const []); + final classA = class_(name: 'A'); + var instA = interfaceTypeNone(classA); var BT = typeParameter('T'); var classB = class_( name: 'B', typeParameters: [BT], - interfaces: [instA.withNullabilitySuffixNone], + interfaces: [instA], ); var CT = typeParameter('T'); @@ -376,10 +376,9 @@ class SuperinterfaceSetTest extends AbstractTypeSystemTest { name: 'C', typeParameters: [CT], interfaces: [ - InstantiatedClass( - classB, - [typeParameterTypeStar(CT)], - ).withNullabilitySuffixNone, + interfaceTypeNone(classB, typeArguments: [ + typeParameterTypeStar(CT), + ]), ], ); @@ -394,7 +393,9 @@ class SuperinterfaceSetTest extends AbstractTypeSystemTest { // B expect( _superInterfaces( - InstantiatedClass(classB, [interfaceTypeStar(classD)]), + interfaceTypeNone(classB, typeArguments: [ + interfaceTypeStar(classD), + ]), ), unorderedEquals([instObject, instA]), ); @@ -402,12 +403,16 @@ class SuperinterfaceSetTest extends AbstractTypeSystemTest { // C expect( _superInterfaces( - InstantiatedClass(classC, [interfaceTypeStar(classD)]), + interfaceTypeNone(classC, typeArguments: [ + interfaceTypeStar(classD), + ]), ), unorderedEquals([ instObject, instA, - InstantiatedClass(classB, [interfaceTypeStar(classD)]), + interfaceTypeNone(classB, typeArguments: [ + interfaceTypeStar(classD), + ]), ]), ); } @@ -423,25 +428,24 @@ class SuperinterfaceSetTest extends AbstractTypeSystemTest { // D // - var instObject = InstantiatedClass.of(typeProvider.objectType); + var instObject = typeProvider.objectType; - ClassElementImpl classA = class_(name: 'A'); - var instA = InstantiatedClass(classA, const []); + final classA = class_(name: 'A'); + var instA = interfaceTypeNone(classA); var classB = class_( name: 'B', typeParameters: [typeParameter('T')], - superType: instA.withNullabilitySuffixNone, + superType: instA, ); var typeParametersC = ElementFactory.typeParameters(['T']); var classC = class_( name: 'B', typeParameters: typeParametersC, - superType: InstantiatedClass( - classB, - [typeParameterTypeStar(typeParametersC[0])], - ).withNullabilitySuffixNone, + superType: interfaceTypeNone(classB, typeArguments: [ + typeParameterTypeStar(typeParametersC[0]), + ]), ); var classD = class_(name: 'D'); @@ -455,7 +459,9 @@ class SuperinterfaceSetTest extends AbstractTypeSystemTest { // B expect( _superInterfaces( - InstantiatedClass(classB, [interfaceTypeStar(classD)]), + interfaceTypeNone(classB, typeArguments: [ + interfaceTypeStar(classD), + ]), ), unorderedEquals([instObject, instA]), ); @@ -463,39 +469,43 @@ class SuperinterfaceSetTest extends AbstractTypeSystemTest { // C expect( _superInterfaces( - InstantiatedClass(classC, [interfaceTypeStar(classD)]), + interfaceTypeNone(classC, typeArguments: [ + interfaceTypeStar(classD), + ]), ), unorderedEquals([ instObject, instA, - InstantiatedClass(classB, [interfaceTypeStar(classD)]), + interfaceTypeNone(classB, typeArguments: [ + interfaceTypeStar(classD), + ]), ]), ); } void test_mixin_constraints() { - var instObject = InstantiatedClass.of(typeProvider.objectType); + var instObject = typeProvider.objectType; var classA = class_(name: 'A'); - var instA = InstantiatedClass(classA, const []); + var instA = interfaceTypeNone(classA); var classB = class_( name: 'B', - interfaces: [instA.withNullabilitySuffixNone], + interfaces: [instA], ); - var instB = InstantiatedClass(classB, const []); + var instB = interfaceTypeNone(classB); var classC = class_(name: 'C'); - var instC = InstantiatedClass(classC, const []); + var instC = interfaceTypeNone(classC); var mixinM = mixin_( name: 'M', constraints: [ - instB.withNullabilitySuffixNone, - instC.withNullabilitySuffixNone, + instB, + instC, ], ); - var instM = InstantiatedClass(mixinM, const []); + var instM = interfaceTypeNone(mixinM); expect( _superInterfaces(instM), @@ -504,10 +514,10 @@ class SuperinterfaceSetTest extends AbstractTypeSystemTest { } void test_mixin_constraints_object() { - var instObject = InstantiatedClass.of(typeProvider.objectType); + var instObject = typeProvider.objectType; var mixinM = mixin_(name: 'M'); - var instM = InstantiatedClass(mixinM, const []); + var instM = interfaceTypeNone(mixinM); expect( _superInterfaces(instM), @@ -516,28 +526,28 @@ class SuperinterfaceSetTest extends AbstractTypeSystemTest { } void test_mixin_interfaces() { - var instObject = InstantiatedClass.of(typeProvider.objectType); + var instObject = typeProvider.objectType; var classA = class_(name: 'A'); - var instA = InstantiatedClass(classA, const []); + var instA = interfaceTypeNone(classA); var classB = class_( name: 'B', - interfaces: [instA.withNullabilitySuffixNone], + interfaces: [instA], ); - var instB = InstantiatedClass(classB, const []); + var instB = interfaceTypeNone(classB); var classC = class_(name: 'C'); - var instC = InstantiatedClass(classC, const []); + var instC = interfaceTypeNone(classC); var mixinM = mixin_( name: 'M', interfaces: [ - instB.withNullabilitySuffixNone, - instC.withNullabilitySuffixNone, + instB, + instC, ], ); - var instM = InstantiatedClass(mixinM, const []); + var instM = interfaceTypeNone(mixinM); expect( _superInterfaces(instM), @@ -546,37 +556,37 @@ class SuperinterfaceSetTest extends AbstractTypeSystemTest { } void test_multipleInterfacePaths() { - var instObject = InstantiatedClass.of(typeProvider.objectType); + var instObject = typeProvider.objectType; var classA = class_(name: 'A'); - var instA = InstantiatedClass(classA, const []); + var instA = interfaceTypeNone(classA); var classB = class_( name: 'B', - interfaces: [instA.withNullabilitySuffixNone], + interfaces: [instA], ); - var instB = InstantiatedClass(classB, const []); + var instB = interfaceTypeNone(classB); var classC = class_( name: 'C', - interfaces: [instA.withNullabilitySuffixNone], + interfaces: [instA], ); - var instC = InstantiatedClass(classC, const []); + var instC = interfaceTypeNone(classC); var classD = class_( name: 'D', - interfaces: [instC.withNullabilitySuffixNone], + interfaces: [instC], ); - var instD = InstantiatedClass(classD, const []); + var instD = interfaceTypeNone(classD); var classE = class_( name: 'E', interfaces: [ - instB.withNullabilitySuffixNone, - instD.withNullabilitySuffixNone, + instB, + instD, ], ); - var instE = InstantiatedClass(classE, const []); + var instE = interfaceTypeNone(classE); // D expect( @@ -592,37 +602,37 @@ class SuperinterfaceSetTest extends AbstractTypeSystemTest { } void test_multipleSuperclassPaths() { - var instObject = InstantiatedClass.of(typeProvider.objectType); + var instObject = typeProvider.objectType; var classA = class_(name: 'A'); - var instA = InstantiatedClass(classA, const []); + var instA = interfaceTypeNone(classA); var classB = class_( name: 'B', - superType: instA.withNullabilitySuffixNone, + superType: instA, ); - var instB = InstantiatedClass(classB, const []); + var instB = interfaceTypeNone(classB); var classC = class_( name: 'C', - superType: instA.withNullabilitySuffixNone, + superType: instA, ); - var instC = InstantiatedClass(classC, const []); + var instC = interfaceTypeNone(classC); var classD = class_( name: 'D', - superType: instC.withNullabilitySuffixNone, + superType: instC, ); - var instD = InstantiatedClass(classD, const []); + var instD = interfaceTypeNone(classD); var classE = class_( name: 'E', - superType: instB.withNullabilitySuffixNone, + superType: instB, interfaces: [ - instD.withNullabilitySuffixNone, + instD, ], ); - var instE = InstantiatedClass(classE, const []); + var instE = interfaceTypeNone(classE); // D expect( @@ -639,15 +649,15 @@ class SuperinterfaceSetTest extends AbstractTypeSystemTest { void test_recursion() { var classA = class_(name: 'A'); - var instA = InstantiatedClass(classA, const []); + var instA = interfaceTypeNone(classA); var classB = class_( name: 'B', - superType: instA.withNullabilitySuffixNone, + superType: instA, ); - var instB = InstantiatedClass(classB, const []); + var instB = interfaceTypeNone(classB); - classA.supertype = instB.withNullabilitySuffixNone; + classA.supertype = instB; expect( _superInterfaces(instB), @@ -661,22 +671,22 @@ class SuperinterfaceSetTest extends AbstractTypeSystemTest { } void test_singleInterfacePath() { - var instObject = InstantiatedClass.of(typeProvider.objectType); + var instObject = typeProvider.objectType; var classA = class_(name: 'A'); - var instA = InstantiatedClass(classA, const []); + var instA = interfaceTypeNone(classA); var classB = class_( name: 'B', - interfaces: [instA.withNullabilitySuffixNone], + interfaces: [instA], ); - var instB = InstantiatedClass(classB, const []); + var instB = interfaceTypeNone(classB); var classC = class_( name: 'C', - interfaces: [instB.withNullabilitySuffixNone], + interfaces: [instB], ); - var instC = InstantiatedClass(classC, const []); + var instC = interfaceTypeNone(classC); // A expect( @@ -705,22 +715,22 @@ class SuperinterfaceSetTest extends AbstractTypeSystemTest { // | // C // - var instObject = InstantiatedClass.of(typeProvider.objectType); + var instObject = typeProvider.objectType; var classA = class_(name: 'A'); - var instA = InstantiatedClass(classA, const []); + var instA = interfaceTypeNone(classA); var classB = class_( name: 'B', - superType: instA.withNullabilitySuffixNone, + superType: instA, ); - var instB = InstantiatedClass(classB, const []); + var instB = interfaceTypeNone(classB); var classC = class_( name: 'C', - superType: instB.withNullabilitySuffixNone, + superType: instB, ); - var instC = InstantiatedClass(classC, const []); + var instC = interfaceTypeNone(classC); // A expect( @@ -741,7 +751,7 @@ class SuperinterfaceSetTest extends AbstractTypeSystemTest { ); } - Set _superInterfaces(InstantiatedClass type) { + Set _superInterfaces(InterfaceType type) { var helper = InterfaceLeastUpperBoundHelper(typeSystem); return helper.computeSuperinterfaceSet(type); }