Skip to content

Commit 6a99fde

Browse files
committed
[CSBindings] Delay binding chain result if type is an optional of a type variable
If subtyping is allowed for a result type of an implicit member chain, let's delay binding it to an optional until its object type resolved too or it has been determined that there is no possibility to resolve it. Otherwise we might end up missing solutions since it's allowed to implicitly unwrap base type but it can't be done early - type variable representing chain's result type has a different l-valueness comparing to generic parameter of an optional. This used to work before due to a hack in constraint generator where unresolved member with arguments would return base type (which doesn't allow l-value) instead of a result type. Resolves: rdar://problem/68094328
1 parent 0990fa9 commit 6a99fde

File tree

2 files changed

+45
-0
lines changed

2 files changed

+45
-0
lines changed

lib/Sema/CSBindings.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -743,6 +743,24 @@ ConstraintSystem::getPotentialBindingForRelationalConstraint(
743743
return None;
744744
}
745745

746+
// If subtyping is allowed and this is a result of an implicit member chain,
747+
// let's delay binding it to an optional until its object type resolved too or
748+
// it has been determined that there is no possibility to resolve it. Otherwise
749+
// we might end up missing solutions since it's allowed to implicitly unwrap
750+
// base type of the chain but it can't be done early - type variable
751+
// representing chain's result type has a different l-valueness comparing
752+
// to generic parameter of the optional.
753+
if (kind == AllowedBindingKind::Subtypes) {
754+
auto *locator = typeVar->getImpl().getLocator();
755+
if (locator &&
756+
locator->isLastElement<LocatorPathElt::UnresolvedMemberChainResult>()) {
757+
auto objectType = type->getOptionalObjectType();
758+
if (objectType && objectType->isTypeVariableOrMember()) {
759+
result.PotentiallyIncomplete = true;
760+
}
761+
}
762+
}
763+
746764
if (type->is<InOutType>() && !typeVar->getImpl().canBindToInOut())
747765
type = LValueType::get(type->getInOutObjectType());
748766
if (type->is<LValueType>() && !typeVar->getImpl().canBindToLValue())

test/expr/delayed-ident/member_chains.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,3 +344,30 @@ extension CurriedGeneric where T == Int {
344344

345345
let _: CurriedGeneric = .createInt(CurriedGeneric())()
346346
let _: CurriedGeneric = .create(CurriedGeneric())(Int.self)
347+
348+
// rdar://problem/68094328 - failed to compile unresolved member with implicit optional promotion
349+
func rdar68094328() {
350+
struct S {
351+
init(string: String) {}
352+
353+
var value: S {
354+
get { S(string: "") }
355+
}
356+
357+
func baz(str: String) -> S {
358+
S(string: str)
359+
}
360+
}
361+
362+
class C {
363+
func bar(_: S) {}
364+
}
365+
366+
func foo<T>(_: (C) -> (T) -> Void, _: T?) {}
367+
368+
func test(str: String) {
369+
foo(C.bar, .init(string: str)) // Ok
370+
foo(C.bar, .init(string: str).value) // Ok
371+
foo(C.bar, .init(string: str).baz(str: "")) // Ok
372+
}
373+
}

0 commit comments

Comments
 (0)