Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions lib/Sema/CSDiagnostics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<KeyPathExpr>(getRawAnchor()) &&
getLocator()->isFirstElement<LocatorPathElt::KeyPathType>() &&
getOwnerType()->is<FunctionType>()) {
return getASTContext().getKeyPathDecl();
}

return getAffectedDeclFromType(getOwnerType());
}

Expand Down
23 changes: 22 additions & 1 deletion lib/Sema/CSSimplify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<BoundGenericType>();
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);
Expand Down
19 changes: 16 additions & 3 deletions test/Sema/keypaths_noncopyable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@ public func testKeypath<V: ~Copyable>(m: consuming M<V>) {
// expected-error@-1 {{key path cannot refer to noncopyable type 'M<V>'}}

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'}}
}

Expand All @@ -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'}}
}