[Constraint solver] Look through optional binding for overload sets.

When we’re trying to find the overload set corresponding to a particular
type variable, look through “optional object of” constraints that represent
the use of ? binding or ! forcing. This allows us to find overload sets
when referring to, e.g., @objc optional protocol requirements.
This commit is contained in:
Doug Gregor
2019-03-05 16:54:43 -08:00
parent fd50d945ce
commit b83bb70bac
4 changed files with 93 additions and 20 deletions

View File

@@ -1650,32 +1650,67 @@ bool ConstraintSystem::haveTypeInformationForAllArguments(
}
Constraint *ConstraintSystem::getUnboundBindOverloadDisjunction(
TypeVariableType *tyvar) {
TypeVariableType *tyvar, unsigned *numOptionalUnwraps) {
if (numOptionalUnwraps)
*numOptionalUnwraps = 0;
auto *rep = getRepresentative(tyvar);
assert(!getFixedType(rep));
llvm::SetVector<Constraint *> disjunctions;
getConstraintGraph().gatherConstraints(
rep, disjunctions, ConstraintGraph::GatheringKind::EquivalenceClass,
[this, rep](Constraint *match) {
if (match->getKind() != ConstraintKind::Disjunction ||
match->getNestedConstraints().front()->getKind() !=
ConstraintKind::BindOverload)
return false;
SmallPtrSet<TypeVariableType *, 4> visitedVars;
while (visitedVars.insert(rep).second) {
// Look for a disjunction that binds this type variable to an overload set.
TypeVariableType *optionalObjectTypeVar = nullptr;
llvm::SetVector<Constraint *> disjunctions;
getConstraintGraph().gatherConstraints(
rep, disjunctions, ConstraintGraph::GatheringKind::EquivalenceClass,
[this, rep, &optionalObjectTypeVar](Constraint *match) {
// If we have an "optional object of" constraint where the right-hand
// side is this type variable, we may need to follow that type
// variable to find the disjunction.
if (match->getKind() == ConstraintKind::OptionalObject) {
auto rhsTypeVar = match->getSecondType()->getAs<TypeVariableType>();
if (rhsTypeVar && getRepresentative(rhsTypeVar) == rep) {
optionalObjectTypeVar =
match->getFirstType()->getAs<TypeVariableType>();
}
return false;
}
auto lhsTypeVar =
match->getNestedConstraints().front()->getFirstType()
->getAs<TypeVariableType>();
if (!lhsTypeVar)
return false;
// We only care about disjunctions of overload bindings.
if (match->getKind() != ConstraintKind::Disjunction ||
match->getNestedConstraints().front()->getKind() !=
ConstraintKind::BindOverload)
return false;
return getRepresentative(lhsTypeVar) == rep;
});
auto lhsTypeVar =
match->getNestedConstraints().front()->getFirstType()
->getAs<TypeVariableType>();
if (!lhsTypeVar)
return false;
if (disjunctions.empty())
return getRepresentative(lhsTypeVar) == rep;
});
// If we found a disjunction, return it.
if (!disjunctions.empty())
return disjunctions[0];
// If we found an "optional object of" constraint, follow it.
if (optionalObjectTypeVar && !getFixedType(optionalObjectTypeVar)) {
if (numOptionalUnwraps)
++*numOptionalUnwraps;
tyvar = optionalObjectTypeVar;
rep = getRepresentative(tyvar);
continue;
}
// There is nowhere else to look.
return nullptr;
}
return disjunctions[0];
return nullptr;
}
/// solely resolved by an overload set.