Skip to content

Commit ee8b87e

Browse files
committed
[CSBindings] Allow base type of an unresolved member to be inferred from protocol requirements
To be able to infer base type in situations like: ```swift func foo<T: P>(_: T) {} foo(.bar) ``` Type variable used for a base type of the chain has to be allowed to infer types from contextual protocol requirements e.g. `T: P` in our example.
1 parent b05678f commit ee8b87e

File tree

1 file changed

+33
-0
lines changed

1 file changed

+33
-0
lines changed

lib/Sema/CSBindings.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,31 @@ void PotentialBindings::finalize(
408408
&inferredBindings) {
409409
inferTransitiveProtocolRequirements(inferredBindings);
410410
inferTransitiveBindings(inferredBindings);
411+
412+
if (auto *locator = TypeVar->getImpl().getLocator()) {
413+
if (locator->isLastElement<LocatorPathElt::MemberRefBase>()) {
414+
// If this is a base of an unresolved member chain, as a last
415+
// resort effort let's infer base to be a protocol type based
416+
// on contextual conformance requirements.
417+
//
418+
// This allows us to find solutions in cases like this:
419+
//
420+
// \code
421+
// func foo<T: P>(_: T) {}
422+
// foo(.bar) <- `.bar` should be a static member of `P`.
423+
// \endcode
424+
if (Bindings.empty() && TransitiveProtocols.hasValue()) {
425+
for (auto *constraint : *TransitiveProtocols) {
426+
auto protocolTy = constraint->getSecondType();
427+
addPotentialBinding(
428+
{protocolTy, AllowedBindingKind::Exact, constraint});
429+
}
430+
431+
PotentiallyIncomplete = true;
432+
FullyBound = true;
433+
}
434+
}
435+
}
411436
}
412437

413438
PotentialBindings::BindingScore
@@ -451,6 +476,14 @@ Optional<PotentialBindings> ConstraintSystem::determineBestBindings() {
451476
auto isViableForRanking = [this](const PotentialBindings &bindings) -> bool {
452477
auto *typeVar = bindings.TypeVar;
453478

479+
// Type variable representing a base of unresolved member chain should
480+
// always be considered viable for ranking since it's allow to infer
481+
// types from transitive protocol requirements.
482+
if (auto *locator = typeVar->getImpl().getLocator()) {
483+
if (locator->isLastElement<LocatorPathElt::MemberRefBase>())
484+
return true;
485+
}
486+
454487
// If type variable is marked as a potential hole there is always going
455488
// to be at least one binding available for it.
456489
if (shouldAttemptFixes() && typeVar->getImpl().canBindToHole())

0 commit comments

Comments
 (0)