diff --git a/lib/Sema/CSDiagnostics.cpp b/lib/Sema/CSDiagnostics.cpp index b9132ae6a128c..e545f13a7476e 100644 --- a/lib/Sema/CSDiagnostics.cpp +++ b/lib/Sema/CSDiagnostics.cpp @@ -411,6 +411,14 @@ ValueDecl *RequirementFailure::getDeclRef() const { } } + // If this is a key path to function conversion, the requirements come + // from a key path type implicitly formed by the solver. + if (isExpr(getRawAnchor()) && + getLocator()->isFirstElement() && + getOwnerType()->is()) { + return getASTContext().getKeyPathDecl(); + } + return getAffectedDeclFromType(getOwnerType()); } diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 00fce0f20f5f2..ad8c12c221404 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -12982,8 +12982,29 @@ ConstraintSystem::simplifyKeyPathConstraint( auto paramFnTy = FunctionType::get(paramParam, fnTy->getResult(), fnTy->getExtInfo()); + // Form a key path type as well to make sure that root and value + // types satisfy all of its requirements. + // Note that `KeyPath` types used to have no requirements but now + // they do require `Root` and `Value` to be `Copyable` and `Escapable`. + { + auto keyPathTy = + openUnboundGenericType( + getASTContext().getKeyPathDecl(), + /*parent=*/Type(), + locator.withPathElement(LocatorPathElt::KeyPathType()), + /*isTypeResolution=*/false) + ->castTo(); + addConstraint(ConstraintKind::Bind, keyPathTy->getGenericArgs()[0], + rootTy, + locator.withPathElement(LocatorPathElt::KeyPathRoot())); + addConstraint(ConstraintKind::Bind, keyPathTy->getGenericArgs()[1], + valueTy, + locator.withPathElement(LocatorPathElt::KeyPathValue())); + } + return !matchTypes(kpFnTy, paramFnTy, ConstraintKind::Conversion, - subflags, locator).isFailure(); + subflags, locator) + .isFailure(); } assert(contextualRootTy && contextualValueTy); diff --git a/test/Sema/keypaths_noncopyable.swift b/test/Sema/keypaths_noncopyable.swift index 104bf1dbc23e2..82c802e562a6c 100644 --- a/test/Sema/keypaths_noncopyable.swift +++ b/test/Sema/keypaths_noncopyable.swift @@ -53,9 +53,9 @@ public func testKeypath(m: consuming M) { // expected-error@-1 {{key path cannot refer to noncopyable type 'M'}} let b = Box(NC()) - _ = b.with(\.data) - _ = b.with(\.next) - _ = b.with(\.next?.wrapped) // expected-error {{key path cannot refer to noncopyable type 'NC'}} + _ = b.with(\.data) // expected-error {{key path cannot refer to noncopyable type 'NC'}} + _ = b.with(\.next) // expected-error {{key path cannot refer to noncopyable type 'NC'}} + _ = b.with(\.next?.wrapped) // expected-error 2 {{key path cannot refer to noncopyable type 'NC'}} _ = b.with(\.next!.wrapped.data) // expected-error {{key path cannot refer to noncopyable type 'NC'}} } @@ -68,3 +68,16 @@ func testAsFunc(_ someA: A) -> Int { let fn: (A) -> Int = \A.b.c.d // expected-error {{key path cannot refer to noncopyable type 'B'}} return fn(someA) } + +// https://github.com/swiftlang/swift/issues/84150 +func testKeyPathToFunctionConversion() { + struct HasID: ~Copyable { + let id: Int + } + + func map(_ operation: (consuming HasID) -> Int) {} + + map(\.id) // expected-error {{key path cannot refer to noncopyable type 'HasID'}} + + let _: (consuming HasID) -> Int = \.id // expected-error {{key path cannot refer to noncopyable type 'HasID'}} +}