diff --git a/lib/Sema/CSBindings.cpp b/lib/Sema/CSBindings.cpp index 7ac46bae1de65..48afd84090013 100644 --- a/lib/Sema/CSBindings.cpp +++ b/lib/Sema/CSBindings.cpp @@ -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 enumerateDirectSupertypes(Type type) { SmallVector result; - if (type->mayHaveSuperclass()) { + if (type->is() || type->is()) { + 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() || type->is()) - result.push_back(type->getWithoutSpecifierType()); - // FIXME: lots of other cases to consider! return result; } diff --git a/test/Constraints/rdar45490737.swift b/test/Constraints/rdar45490737.swift new file mode 100644 index 0000000000000..63775ec8e073b --- /dev/null +++ b/test/Constraints/rdar45490737.swift @@ -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(_ 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) +}