Choosing a best fit when getting multiple exact bounds for a type variable
This commit is contained in:
+4
-4
@@ -156,10 +156,10 @@ public class TypeBoundsImpl implements TypeBounds {
|
||||
}
|
||||
|
||||
Set<JetType> exactBounds = filterBounds(bounds, BoundKind.EXACT_BOUND, values);
|
||||
if (exactBounds.size() == 1) {
|
||||
JetType exactBound = exactBounds.iterator().next();
|
||||
if (tryPossibleAnswer(exactBound)) {
|
||||
return Collections.singleton(exactBound);
|
||||
JetType bestFit = TypesPackage.singleBestRepresentative(exactBounds);
|
||||
if (bestFit != null) {
|
||||
if (tryPossibleAnswer(bestFit)) {
|
||||
return Collections.singleton(bestFit);
|
||||
}
|
||||
}
|
||||
values.addAll(exactBounds);
|
||||
|
||||
@@ -103,7 +103,9 @@ public class CommonSupertypes {
|
||||
private static JetType commonSuperTypeForInflexible(@NotNull Collection<JetType> types, int recursionDepth, int maxDepth) {
|
||||
assert !types.isEmpty();
|
||||
Collection<JetType> typeSet = new HashSet<JetType>(types);
|
||||
if (typeSet.size() == 1) return typeSet.iterator().next();
|
||||
|
||||
JetType bestFit = TypesPackage.singleBestRepresentative(typeSet);
|
||||
if (bestFit != null) return bestFit;
|
||||
|
||||
// If any of the types is nullable, the result must be nullable
|
||||
// This also removed Nothing and Nothing? because they are subtypes of everything else
|
||||
@@ -232,8 +234,9 @@ public class CommonSupertypes {
|
||||
@NotNull Set<TypeProjection> typeProjections,
|
||||
int recursionDepth, int maxDepth
|
||||
) {
|
||||
if (typeProjections.size() == 1) {
|
||||
return typeProjections.iterator().next();
|
||||
TypeProjection singleBestProjection = TypesPackage.singleBestRepresentative(typeProjections);
|
||||
if (singleBestProjection != null) {
|
||||
return singleBestProjection;
|
||||
}
|
||||
|
||||
if (recursionDepth >= maxDepth) {
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.jetbrains.jet.lang.types
|
||||
|
||||
import org.jetbrains.jet.lang.types.checker.JetTypeChecker
|
||||
import org.jetbrains.jet.lang.types.Approximation.DataFlowExtras
|
||||
import org.jetbrains.kotlin.util.printAndReturn
|
||||
|
||||
public trait Flexibility : TypeCapability {
|
||||
// lowerBound is a subtype of upperBound
|
||||
@@ -29,6 +30,38 @@ public trait Flexibility : TypeCapability {
|
||||
public fun JetType.isFlexible(): Boolean = this.getCapability(javaClass<Flexibility>()) != null
|
||||
public fun JetType.flexibility(): Flexibility = this.getCapability(javaClass<Flexibility>())!!
|
||||
|
||||
// This function is intended primarily for sets: since JetType.equals() represents _syntactical_ equality of types,
|
||||
// whereas JetTypeChecker.DEFAULT.equalsTypes() represents semantical equality
|
||||
// A set of types (e.g. exact bounds etc) may contain, for example, X, X? and X!
|
||||
// These are not equal syntactically (by JetType.equals()), but X! is _compatible_ with others as exact bounds,
|
||||
// moreover, X! is a better fit.
|
||||
//
|
||||
// So, we are looking for a type among this set such that it is equal to all others semantically
|
||||
// (by JetTypeChecker.DEFAULT.equalsTypes()), and fits at least as well as they do.
|
||||
fun Collection<JetType>.singleBestRepresentative(): JetType? {
|
||||
if (this.size() == 1) return this.first()
|
||||
|
||||
return this.firstOrNull {
|
||||
candidate ->
|
||||
this.all {
|
||||
other ->
|
||||
candidate == other || JetTypeChecker.DEFAULT.equalTypes(candidate, other)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Collection<TypeProjection>.singleBestRepresentative(): TypeProjection? {
|
||||
if (this.size() == 1) return this.first()
|
||||
|
||||
val projectionKinds = this.map { it.getProjectionKind() }.toSet()
|
||||
if (projectionKinds.size() != 1) return null
|
||||
|
||||
val bestType = this.map { it.getType() }.singleBestRepresentative()
|
||||
if (bestType == null) return null
|
||||
|
||||
return TypeProjectionImpl(projectionKinds.single(), bestType)
|
||||
}
|
||||
|
||||
public fun JetType.lowerIfFlexible(): JetType = if (this.isFlexible()) this.flexibility().getLowerBound() else this
|
||||
public fun JetType.upperIfFlexible(): JetType = if (this.isFlexible()) this.flexibility().getUpperBound() else this
|
||||
|
||||
|
||||
Reference in New Issue
Block a user