diff --git a/lib/Sema/CSBindings.cpp b/lib/Sema/CSBindings.cpp index a82b389991788..d9f4d7e8fc3e3 100644 --- a/lib/Sema/CSBindings.cpp +++ b/lib/Sema/CSBindings.cpp @@ -743,6 +743,24 @@ ConstraintSystem::getPotentialBindingForRelationalConstraint( return None; } + // If subtyping is allowed and this is a result 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 of the chain but it can't be done early - type variable + // representing chain's result type has a different l-valueness comparing + // to generic parameter of the optional. + if (kind == AllowedBindingKind::Subtypes) { + auto *locator = typeVar->getImpl().getLocator(); + if (locator && + locator->isLastElement()) { + auto objectType = type->getOptionalObjectType(); + if (objectType && objectType->isTypeVariableOrMember()) { + result.PotentiallyIncomplete = true; + } + } + } + if (type->is() && !typeVar->getImpl().canBindToInOut()) type = LValueType::get(type->getInOutObjectType()); if (type->is() && !typeVar->getImpl().canBindToLValue()) diff --git a/test/expr/delayed-ident/member_chains.swift b/test/expr/delayed-ident/member_chains.swift index 2691574dbd321..a2684adf0d310 100644 --- a/test/expr/delayed-ident/member_chains.swift +++ b/test/expr/delayed-ident/member_chains.swift @@ -344,3 +344,30 @@ extension CurriedGeneric where T == Int { let _: CurriedGeneric = .createInt(CurriedGeneric())() let _: CurriedGeneric = .create(CurriedGeneric())(Int.self) + +// rdar://problem/68094328 - failed to compile unresolved member with implicit optional promotion +func rdar68094328() { + struct S { + init(string: String) {} + + var value: S { + get { S(string: "") } + } + + func baz(str: String) -> S { + S(string: str) + } + } + + class C { + func bar(_: S) {} + } + + func foo(_: (C) -> (T) -> Void, _: T?) {} + + func test(str: String) { + foo(C.bar, .init(string: str)) // Ok + foo(C.bar, .init(string: str).value) // Ok + foo(C.bar, .init(string: str).baz(str: "")) // Ok + } +}