[ConstraintSystem] Allow getPotentialBindings to find supertypes of optionals.

Improve enumerateDirectSupertypes so that for T? it will return U? if
U is a supertype of T. This is another form of direct supertype.

This is making up for a deficiency in the completeness of our Type
join implementation, which should be able to directly compute a join
of disparate types that share some common supertype, but sometimes
fails to in cases involving protocol compositions.

Fixes rdar://problem/45490737
This commit is contained in:
Mark Lacey
2018-10-23 21:36:54 -07:00
parent edfb86f09a
commit 85237aa071
2 changed files with 52 additions and 7 deletions

View File

@@ -757,6 +757,29 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) {
return result;
}
// Given a possibly-Optional type, return the direct superclass of the
// (underlying) type wrapped in the same number of optional levels as
// type.
static Type getOptionalSuperclass(Type type) {
int optionalLevels = 0;
while (auto underlying = type->getOptionalObjectType()) {
++optionalLevels;
type = underlying;
}
if (!type->mayHaveSuperclass())
return Type();
auto superclass = type->getSuperclass();
if (!superclass)
return Type();
while (optionalLevels--)
superclass = OptionalType::get(superclass);
return superclass;
}
/// \brief Enumerates all of the 'direct' supertypes of the given type.
///
/// The direct supertype S of a type T is a supertype of T (e.g., T < S)
@@ -764,19 +787,19 @@ ConstraintSystem::getPotentialBindings(TypeVariableType *typeVar) {
static SmallVector<Type, 4> enumerateDirectSupertypes(Type type) {
SmallVector<Type, 4> result;
if (type->mayHaveSuperclass()) {
if (type->is<InOutType>() || type->is<LValueType>()) {
type = type->getWithoutSpecifierType();
result.push_back(type);
}
if (auto superclass = getOptionalSuperclass(type)) {
// FIXME: Can also weaken to the set of protocol constraints, but only
// if there are any protocols that the type conforms to but the superclass
// does not.
// If there is a superclass, it is a direct supertype.
if (auto superclass = type->getSuperclass())
result.push_back(superclass);
result.push_back(superclass);
}
if (type->is<InOutType>() || type->is<LValueType>())
result.push_back(type->getWithoutSpecifierType());
// FIXME: lots of other cases to consider!
return result;
}

View File

@@ -0,0 +1,22 @@
// RUN: %target-typecheck-verify-swift
protocol X {}
class B : Equatable {
static func == (lhs: B, rhs: B) -> Bool { fatalError() }
}
class C : B {}
extension C : X {}
func f<T: Equatable>(_ lhs: T, _ rhs: T) {}
extension Optional where Wrapped : Equatable {
static func f(_ lhs: Wrapped?, _ rhs: Wrapped?) {}
}
// Ensure that we can call both a function that has generic parameters
// as well as one that has the generic parameters wrapped in
// Optionals.
func test(x: (X & B)?, y: C?) {
f(x, y)
Optional.f(x, y)
}