Skip to content

Commit

Permalink
Implement LUB for interface types with nullability.
Browse files Browse the repository at this point in the history
Using InstantiatedClass is a necessary step for fixing DartType.==
dart-lang/sdk#37587

Change-Id: Ia959d841778b3894f50f47b7490b59b9d7ab6ba6
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/110348
Reviewed-by: Paul Berry <[email protected]>
Reviewed-by: Brian Wilkerson <[email protected]>
  • Loading branch information
scheglov committed Jul 25, 2019
1 parent 8fb6f68 commit b9ab8ef
Show file tree
Hide file tree
Showing 8 changed files with 1,090 additions and 547 deletions.
173 changes: 0 additions & 173 deletions pkg/analyzer/lib/src/dart/element/type.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2415,80 +2415,6 @@ class InterfaceTypeImpl extends TypeImpl implements InterfaceType {
return result;
}

/**
* Compute the least upper bound of types [i] and [j], both of which are
* known to be interface types.
*
* In the event that the algorithm fails (which might occur due to a bug in
* the analyzer), `null` is returned.
*/
static InterfaceType computeLeastUpperBound(InterfaceType i, InterfaceType j,
{@deprecated bool strong = true}) {
// compute set of supertypes
Set<InterfaceType> si = computeSuperinterfaceSet(i);
Set<InterfaceType> sj = computeSuperinterfaceSet(j);
// union si with i and sj with j
si.add(i);
sj.add(j);
// compute intersection, reference as set 's'
List<InterfaceType> s = _intersection(si, sj);
return computeTypeAtMaxUniqueDepth(s);
}

/**
* Return the length of the longest inheritance path from the given [type] to
* Object.
*
* See [computeLeastUpperBound].
*/
static int computeLongestInheritancePathToObject(InterfaceType type) =>
_computeLongestInheritancePathToObject(
type, 0, new HashSet<ClassElement>());

/**
* Returns the set of all superinterfaces of the given [type].
*
* See [computeLeastUpperBound].
*/
static Set<InterfaceType> computeSuperinterfaceSet(InterfaceType type,
{@deprecated bool strong = true}) =>
_computeSuperinterfaceSet(type, new HashSet<InterfaceType>(), true);

/**
* Return the type from the [types] list that has the longest inheritance path
* to Object of unique length.
*/
static InterfaceType computeTypeAtMaxUniqueDepth(List<InterfaceType> types) {
// for each element in Set s, compute the largest inheritance path to Object
List<int> depths = new List<int>.filled(types.length, 0);
int maxDepth = 0;
for (int n = 0; n < types.length; n++) {
depths[n] = computeLongestInheritancePathToObject(types[n]);
if (depths[n] > maxDepth) {
maxDepth = depths[n];
}
}
// ensure that the currently computed maxDepth is unique,
// otherwise, decrement and test for uniqueness again
for (; maxDepth >= 0; maxDepth--) {
int indexOfLeastUpperBound = -1;
int numberOfTypesAtMaxDepth = 0;
for (int m = 0; m < depths.length; m++) {
if (depths[m] == maxDepth) {
numberOfTypesAtMaxDepth++;
indexOfLeastUpperBound = m;
}
}
if (numberOfTypesAtMaxDepth == 1) {
return types[indexOfLeastUpperBound];
}
}
// Should be impossible--there should always be exactly one type with the
// maximum depth.
assert(false);
return null;
}

/**
* If there is a single type which is at least as specific as all of the
* types in [types], return it. Otherwise return `null`.
Expand Down Expand Up @@ -2565,105 +2491,6 @@ class InterfaceTypeImpl extends TypeImpl implements InterfaceType {
return context.typeSystem.getLeastUpperBound(first, second);
}

/**
* Return the length of the longest inheritance path from a subtype of the
* given [type] to Object, where the given [depth] is the length of the
* longest path from the subtype to this type. The set of [visitedTypes] is
* used to prevent infinite recursion in the case of a cyclic type structure.
*
* See [computeLongestInheritancePathToObject], and [computeLeastUpperBound].
*/
static int _computeLongestInheritancePathToObject(
InterfaceType type, int depth, HashSet<ClassElement> visitedTypes) {
ClassElement classElement = type.element;
// Object case
if (type.isObject || visitedTypes.contains(classElement)) {
return depth;
}
int longestPath = 1;
try {
visitedTypes.add(classElement);
int pathLength;

// loop through each of the superinterfaces recursively calling this
// method and keeping track of the longest path to return
for (InterfaceType interface in classElement.superclassConstraints) {
pathLength = _computeLongestInheritancePathToObject(
interface, depth + 1, visitedTypes);
if (pathLength > longestPath) {
longestPath = pathLength;
}
}

// loop through each of the superinterfaces recursively calling this
// method and keeping track of the longest path to return
for (InterfaceType interface in classElement.interfaces) {
pathLength = _computeLongestInheritancePathToObject(
interface, depth + 1, visitedTypes);
if (pathLength > longestPath) {
longestPath = pathLength;
}
}

// finally, perform this same check on the super type
// TODO(brianwilkerson) Does this also need to add in the number of mixin
// classes?
InterfaceType supertype = classElement.supertype;
if (supertype != null) {
pathLength = _computeLongestInheritancePathToObject(
supertype, depth + 1, visitedTypes);
if (pathLength > longestPath) {
longestPath = pathLength;
}
}
} finally {
visitedTypes.remove(classElement);
}
return longestPath;
}

/**
* Add all of the superinterfaces of the given [type] to the given [set].
* Return the [set] as a convenience.
*
* If [strong] mode is enabled (Dart 2), then the `Function` interface is
* ignored and not treated as a superinterface.
*
* See [computeSuperinterfaceSet], and [computeLeastUpperBound].
*/
static Set<InterfaceType> _computeSuperinterfaceSet(
InterfaceType type, HashSet<InterfaceType> set, bool _) {
Element element = type.element;
if (element != null) {
List<InterfaceType> superinterfaces = type.interfaces;
for (InterfaceType superinterface in superinterfaces) {
if (!superinterface.isDartCoreFunction) {
if (set.add(superinterface)) {
_computeSuperinterfaceSet(superinterface, set, true);
}
}
}
InterfaceType supertype = type.superclass;
if (supertype != null && !supertype.isDartCoreFunction) {
if (set.add(supertype)) {
_computeSuperinterfaceSet(supertype, set, true);
}
}
}
return set;
}

/**
* Return the intersection of the [first] and [second] sets of types, where
* intersection is based on the equality of the types themselves.
*/
static List<InterfaceType> _intersection(
Set<InterfaceType> first, Set<InterfaceType> second) {
Set<InterfaceType> result = new HashSet<InterfaceType>.from(first);
result.retainAll(second);
return new List.from(result);
}

/**
* Return the "least upper bound" of the given types under the assumption that
* the types have the same element and differ only in terms of the type
Expand Down
21 changes: 21 additions & 0 deletions pkg/analyzer/lib/src/generated/testing/element_factory.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/testing/ast_test_factory.dart';
import 'package:analyzer/src/generated/utilities_dart.dart';
import 'package:meta/meta.dart';
import 'package:path/path.dart';

/**
Expand Down Expand Up @@ -54,6 +55,26 @@ class ElementFactory {
[List<String> parameterNames]) =>
classElement(typeName, objectType, parameterNames);

static ClassElementImpl classElement3({
@required String name,
List<TypeParameterElement> typeParameters,
List<String> typeParameterNames = const [],
InterfaceType supertype,
List<InterfaceType> mixins = const [],
List<InterfaceType> interfaces = const [],
}) {
typeParameters ??= ElementFactory.typeParameters(typeParameterNames);
supertype ??= objectType;

var element = ClassElementImpl(name, 0);
element.typeParameters = typeParameters;
element.supertype = supertype;
element.mixins = mixins;
element.interfaces = interfaces;
element.constructors = const <ConstructorElement>[];
return element;
}

static classTypeAlias(String typeName, InterfaceType superclassType,
[List<String> parameterNames]) {
ClassElementImpl element =
Expand Down
Loading

0 comments on commit b9ab8ef

Please sign in to comment.