mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[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:
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user