Make the internal TypeSystem implement the public TypeSystem
Change-Id: I38731f0bc560134c7ad0b0a339ea4e0528e5f6ab
Reviewed-on: https://dart-review.googlesource.com/c/87602
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/analyzer/lib/src/generated/type_system.dart b/pkg/analyzer/lib/src/generated/type_system.dart
index 5d0de22..2a2bebe 100644
--- a/pkg/analyzer/lib/src/generated/type_system.dart
+++ b/pkg/analyzer/lib/src/generated/type_system.dart
@@ -9,6 +9,7 @@
import 'package:analyzer/dart/ast/token.dart' show Keyword, TokenType;
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/dart/element/type_system.dart' as public;
import 'package:analyzer/error/listener.dart' show ErrorReporter;
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/member.dart' show TypeParameterMember;
@@ -1674,7 +1675,8 @@
* way for a possible future where we may wish to make the type system
* pluggable.
*/
-abstract class TypeSystem {
+// TODO(brianwilkerson) Rename this class to TypeSystemImpl.
+abstract class TypeSystem implements public.TypeSystem {
/**
* Whether the type system is strong or not.
*/
@@ -1686,6 +1688,40 @@
*/
TypeProvider get typeProvider;
+ @override
+ DartType flatten(DartType type) {
+ if (type is InterfaceType) {
+ // Implement the cases:
+ // - "If T = FutureOr<S> then flatten(T) = S."
+ // - "If T = Future<S> then flatten(T) = S."
+ if (type.isDartAsyncFutureOr || type.isDartAsyncFuture) {
+ return type.typeArguments.isNotEmpty
+ ? type.typeArguments[0]
+ : DynamicTypeImpl.instance;
+ }
+ // Implement the case: "Otherwise if T <: Future then let S be a type
+ // such that T << Future<S> and for all R, if T << Future<R> then S << R.
+ // Then flatten(T) = S."
+ //
+ // In other words, given the set of all types R such that T << Future<R>,
+ // let S be the most specific of those types, if any such S exists.
+ //
+ // Since we only care about the most specific type, it is sufficient to
+ // look at the types appearing as a parameter to Future in the type
+ // hierarchy of T. We don't need to consider the supertypes of those
+ // types, since they are by definition less specific.
+ List<DartType> candidateTypes =
+ _searchTypeHierarchyForFutureTypeParameters(type);
+ DartType flattenResult =
+ InterfaceTypeImpl.findMostSpecificType(candidateTypes, this);
+ if (flattenResult != null) {
+ return flattenResult;
+ }
+ }
+ // Implement the case: "In any other circumstance, flatten(T) = T."
+ return type;
+ }
+
List<InterfaceType> gatherMixinSupertypeConstraintsForInference(
ClassElement mixinElement) {
List<InterfaceType> candidates;
@@ -1823,6 +1859,11 @@
*/
bool isSubtypeOf(DartType leftType, DartType rightType);
+ @override
+ DartType leastUpperBound(DartType leftType, DartType rightType) {
+ return getLeastUpperBound(leftType, rightType);
+ }
+
/// Attempts to find the appropriate substitution for [typeParameters] that can
/// be applied to [src] to make it equal to [dest]. If no such substitution can
/// be found, `null` is returned.
@@ -1937,6 +1978,11 @@
return currentType;
}
+ @override
+ DartType resolveToBound(DartType type) {
+ return instantiateToBounds(type);
+ }
+
/**
* Tries to promote from the first type from the second type, and returns the
* promoted type if it succeeds, otherwise null.
@@ -2064,6 +2110,32 @@
DartType _interfaceLeastUpperBound(InterfaceType type1, InterfaceType type2);
/**
+ * Starting from the given [type], search its class hierarchy for types of the
+ * form Future<R>, and return a list of the resulting R's.
+ */
+ List<DartType> _searchTypeHierarchyForFutureTypeParameters(DartType type) {
+ List<DartType> result = <DartType>[];
+ HashSet<ClassElement> visitedClasses = new HashSet<ClassElement>();
+ void recurse(InterfaceTypeImpl type) {
+ if (type.isDartAsyncFuture && type.typeArguments.isNotEmpty) {
+ result.add(type.typeArguments[0]);
+ }
+ if (visitedClasses.add(type.element)) {
+ if (type.superclass != null) {
+ recurse(type.superclass);
+ }
+ for (InterfaceType interface in type.interfaces) {
+ recurse(interface);
+ }
+ visitedClasses.remove(type.element);
+ }
+ }
+
+ recurse(type);
+ return result;
+ }
+
+ /**
* Given two [DartType]s [type1] and [type2] at least one of which is a
* [TypeParameterType], return their least upper bound in a type system
* specific manner.