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