Skip to content

Commit 9b62c84

Browse files
committed
[CSOptimizer] Adjust scoreCandidateMatch to indicate when match cannot be decided
It is not always possible to match candidate types against corresponding parameter types for certain overloads i.e. when parameter is an associated type. `scoreCandidateMatch` needs to be able to indicate that to the caller to allow it to move to the next parameter (if any) without failing the overload choice when the match cannot be established.
1 parent 6caf1cc commit 9b62c84

File tree

1 file changed

+29
-12
lines changed

1 file changed

+29
-12
lines changed

lib/Sema/CSOptimizer.cpp

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -450,10 +450,16 @@ static Constraint *determineBestChoicesInContext(
450450
// - Array-to-pointer conversion
451451
// - Value to existential conversion
452452
// - Exact match on top-level types
453-
std::function<double(GenericSignature, Type, Type, MatchOptions)>
454-
scoreCandidateMatch = [&](GenericSignature genericSig,
455-
Type candidateType, Type paramType,
456-
MatchOptions options) -> double {
453+
//
454+
// In situations when it's not possible to determine whether a candidate
455+
// type matches a parameter type (i.e. when partially resolved generic
456+
// types are matched) this function is going to produce \c std::nullopt
457+
// instead of `0` that indicates "not a match".
458+
std::function<std::optional<double>(GenericSignature, Type, Type,
459+
MatchOptions)>
460+
scoreCandidateMatch =
461+
[&](GenericSignature genericSig, Type candidateType, Type paramType,
462+
MatchOptions options) -> std::optional<double> {
457463
auto areEqual = [&options](Type a, Type b) {
458464
// Double<->CGFloat implicit conversion support for literals
459465
// only since in this case the conversion might not result in
@@ -527,10 +533,12 @@ static Constraint *determineBestChoicesInContext(
527533

528534
// Check protocol requirement(s) if this parameter is a
529535
// generic parameter type.
530-
if (genericSig && paramType->is<GenericTypeParamType>()) {
531-
// If candidate is not fully resolved, check conformances only
532-
// and lower the score.
533-
if (candidateType->hasTypeVariable()) {
536+
if (genericSig && paramType->isTypeParameter()) {
537+
// If candidate is not fully resolved or is matched against a
538+
// dependent member type (i.e. `Self.T`), let's check conformances
539+
// only and lower the score.
540+
if (candidateType->hasTypeVariable() ||
541+
paramType->is<DependentMemberType>()) {
534542
auto protocolRequirements =
535543
genericSig->getRequiredProtocols(paramType);
536544
if (llvm::all_of(protocolRequirements, [&](ProtocolDecl *protocol) {
@@ -547,6 +555,10 @@ static Constraint *determineBestChoicesInContext(
547555
return 0;
548556
}
549557

558+
// Cannot match anything but generic type parameters here.
559+
if (!paramType->is<GenericTypeParamType>())
560+
return std::nullopt;
561+
550562
// If the candidate type is fully resolved, let's check all of
551563
// the requirements that are associated with the corresponding
552564
// parameter, if all of them are satisfied this candidate is
@@ -718,10 +730,15 @@ static Constraint *determineBestChoicesInContext(
718730
if (favorExactMatchesOnly)
719731
options |= MatchFlag::ExactOnly;
720732

721-
auto score = scoreCandidateMatch(genericSig, candidateType,
722-
paramType, options);
723-
if (score > 0) {
724-
bestCandidateScore = std::max(bestCandidateScore, score);
733+
auto candidateScore = scoreCandidateMatch(
734+
genericSig, candidateType, paramType, options);
735+
736+
if (!candidateScore)
737+
continue;
738+
739+
if (candidateScore > 0) {
740+
bestCandidateScore =
741+
std::max(bestCandidateScore, candidateScore.value());
725742
continue;
726743
}
727744

0 commit comments

Comments
 (0)