[ConstraintSystem] Increase score only if members found on Optional and its unwrapped type

Unresolved member lookup is allowed to perform implicit optional
unwrap of a base type to find members. Previously if there were
any members directly on `Optional`, lookup would stop there. But
since SR-13815 it became possible for solver to attempt members
found on unwrapped type even if there are viable ones on
`Optional` as well.

New score kind has been introduced to guard against possible ambiguities
with new scheme - `SK_UnresolvedMemberViaOptional`. It's used very
time member found via base type unwrap is attempted. Unfortunately,
doing so can lead to behavior changes in existing code because it's
possible that base was wrapped into optional implicitly based on
context e.g. unresolved member passed in as an argument to a parameter
of optional type.

To fix situations like that, `SK_UnresolvedMemberViaOptional` should
only be increased if there is a mix of members to attempt - both directly
on `Optional` and on unwrapped type, in all other cases score should stay
the same because there could be no ambiguity.

Resolves: rdar://73027153
This commit is contained in:
Pavel Yaskevich
2021-01-12 14:02:33 -08:00
parent d710cfc3a5
commit f6637276fd
4 changed files with 62 additions and 13 deletions

View File

@@ -6672,8 +6672,9 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
// Local function that turns a ValueDecl into a properly configured
// OverloadChoice.
auto getOverloadChoice = [&](ValueDecl *cand, bool isBridged,
bool isUnwrappedOptional) -> OverloadChoice {
auto getOverloadChoice =
[&](ValueDecl *cand, bool isBridged, bool isUnwrappedOptional,
bool isFallbackUnwrap = false) -> OverloadChoice {
// If we're looking into an existential type, check whether this
// result was found via dynamic lookup.
if (instanceTy->isAnyObject()) {
@@ -6694,8 +6695,9 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
auto ovlBaseTy = MetatypeType::get(baseTy->castTo<MetatypeType>()
->getInstanceType()
->getOptionalObjectType());
return OverloadChoice::getDeclViaUnwrappedOptional(ovlBaseTy, cand,
functionRefKind);
return OverloadChoice::getDeclViaUnwrappedOptional(
ovlBaseTy, cand,
/*isFallback=*/isFallbackUnwrap, functionRefKind);
}
// While looking for subscript choices it's possible to find
@@ -6719,7 +6721,7 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
return OverloadChoice(baseTy, cand, functionRefKind);
};
// Add all results from this lookup.
for (auto result : lookup)
addChoice(getOverloadChoice(result.getValueDecl(),
@@ -6802,11 +6804,16 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
}
if (objectType->mayHaveMembers()) {
// If there are viable members directly on `Optional`, let's
// prioritize them and mark any results found on wrapped type
// as a fallback results.
bool isFallback = !result.ViableCandidates.empty();
LookupResult &optionalLookup = lookupMember(objectType, memberName);
for (auto result : optionalLookup)
addChoice(getOverloadChoice(result.getValueDecl(),
/*bridged*/false,
/*isUnwrappedOptional=*/true));
/*bridged*/ false,
/*isUnwrappedOptional=*/true,
/*isUnwrapFallback=*/isFallback));
}
}
}