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
14 changes: 13 additions & 1 deletion lib/Sema/CSBindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -721,6 +721,7 @@ bool BindingSet::finalize(bool transitive) {
if (isValid && !capability)
return false;

bool isContextualTypeReadOnly = false;
// If the key path is sufficiently resolved we can add inferred binding
// to the set.
SmallSetVector<PotentialBinding, 4> updatedBindings;
Expand All @@ -740,19 +741,30 @@ bool BindingSet::finalize(bool transitive) {
}

updatedBindings.insert(binding.withType(fnType));
isContextualTypeReadOnly = true;
} else if (!(bindingTy->isWritableKeyPath() ||
bindingTy->isReferenceWritableKeyPath())) {
isContextualTypeReadOnly = true;
}
}

// Note that even though key path literal maybe be invalid it's
// still the best course of action to use contextual function type
// bindings because they allow to propagate type information from
// the key path into the context, so key path bindings are addded
// the key path into the context, so key path bindings are added
// only if there is absolutely no other choice.
if (updatedBindings.empty()) {
auto rootTy = CS.getKeyPathRootType(keyPath);

// A valid key path literal.
if (capability) {
// Capability inference always results in a maximum mutability
// but if context is read-only it can be downgraded to avoid
// conversions.
if (isContextualTypeReadOnly)
capability =
std::make_pair(KeyPathMutability::ReadOnly, capability->second);

// Note that the binding is formed using root & value
// type variables produced during constraint generation
// because at this point root is already known (otherwise
Expand Down
19 changes: 15 additions & 4 deletions test/Concurrency/sendable_keypaths.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ do {

let _: KeyPath<K, Bool> = \.[NonSendable()] // ok
let _: KeyPath<K, Bool> & Sendable = \.[NonSendable()] // expected-warning {{type 'KeyPath<K, Bool>' does not conform to the 'Sendable' protocol}}
let _: KeyPath<K, Int> & Sendable = \.[42, NonSendable(data: [-1, 0, 1])] // expected-warning {{type 'ReferenceWritableKeyPath<K, Int>' does not conform to the 'Sendable' protocol}}
let _: KeyPath<K, Int> & Sendable = \.[42, NonSendable(data: [-1, 0, 1])] // expected-warning {{type 'KeyPath<K, Int>' does not conform to the 'Sendable' protocol}}
let _: KeyPath<K, Int> & Sendable = \.[42, -1] // Ok

test(nonSendableKP) // expected-warning {{type 'KeyPath<K, Bool>' does not conform to the 'Sendable' protocol}}
Expand Down Expand Up @@ -106,22 +106,22 @@ do {
// expected-warning@-1 {{converting non-Sendable function value to '@Sendable (V) -> Int' may introduce data races}}

let _: KeyPath<V, Int> & Sendable = \.[42, CondSendable(NonSendable(data: [1, 2, 3]))]
// expected-warning@-1 {{type 'ReferenceWritableKeyPath<V, Int>' does not conform to the 'Sendable' protocol}}
// expected-warning@-1 {{type 'KeyPath<V, Int>' does not conform to the 'Sendable' protocol}}
let _: KeyPath<V, Int> & Sendable = \.[42, CondSendable(42)] // Ok

struct Root {
let v: V
}

testSendableKP(v: v, \.[42, CondSendable(NonSendable(data: [1, 2, 3]))])
// expected-warning@-1 {{type 'ReferenceWritableKeyPath<V, Int>' does not conform to the 'Sendable' protocol}}
// expected-warning@-1 {{type 'KeyPath<V, Int>' does not conform to the 'Sendable' protocol}}
testSendableFn(v: v, \.[42, CondSendable(NonSendable(data: [1, 2, 3]))])
// expected-warning@-1 {{converting non-Sendable function value to '@Sendable (V) -> Int' may introduce data races}}
testSendableKP(v: v, \.[42, CondSendable(42)]) // Ok

let nonSendable = NonSendable()
testSendableKP(v: v, \.[42, CondSendable(nonSendable)])
// expected-warning@-1 {{type 'ReferenceWritableKeyPath<V, Int>' does not conform to the 'Sendable' protocol}}
// expected-warning@-1 {{type 'KeyPath<V, Int>' does not conform to the 'Sendable' protocol}}

testSendableFn(v: v, \.[42, CondSendable(nonSendable)])
// expected-warning@-1 {{converting non-Sendable function value to '@Sendable (V) -> Int' may introduce data races}}
Expand Down Expand Up @@ -277,3 +277,14 @@ do {
// expected-warning@-1 {{type 'KeyPath<Foo, Int>' does not conform to the 'Sendable' protocol; this is an error in the Swift 6 language mode}}
}
}

public final class TestSetterRef {
public internal(set) var v: Int = 0 // expected-note {{setter for property 'v' is not '@usableFromInline' or public}}

public func test1(_ kp: KeyPath<TestSetterRef, Int> = \.v) {} // Ok
public func test2(_ kp: KeyPath<TestSetterRef, Int> = \TestSetterRef.v) {} // Ok
public func test3(_ kp: KeyPath<TestSetterRef, Int> & Sendable = \.v) {} // Ok

public func test_err(_ kp: WritableKeyPath<TestSetterRef, Int> = \.v) {}
// expected-warning@-1 {{setter for property 'v' is internal and should not be referenced from a default argument value}}
}
4 changes: 2 additions & 2 deletions test/SILGen/keypaths.swift
Original file line number Diff line number Diff line change
Expand Up @@ -738,11 +738,11 @@ class M {
// CHECK-LABEL: // test_metatype_keypaths()
// CHECK-LABEL: sil hidden [ossa] @{{.*}} : $@convention(thin) () -> () {
func test_metatype_keypaths() {
// CHECK: keypath $ReferenceWritableKeyPath<M.Type, Int>, (root $M.Type; settable_property $Int, id @$s8keypaths1MC10chanceRainSivgZ : $@convention(method) (@thick M.Type) -> Int, getter @$s8keypaths1MC10chanceRainSivpZACmTK : $@convention(keypath_accessor_getter) (@in_guaranteed @thick M.Type) -> @out Int, setter @$s8keypaths1MC10chanceRainSivpZACmTk : $@convention(keypath_accessor_setter) (@in_guaranteed Int, @in_guaranteed @thick M.Type) -> ())
// CHECK: keypath $KeyPath<M.Type, Int>, (root $M.Type; settable_property $Int, id @$s8keypaths1MC10chanceRainSivgZ : $@convention(method) (@thick M.Type) -> Int, getter @$s8keypaths1MC10chanceRainSivpZACmTK : $@convention(keypath_accessor_getter) (@in_guaranteed @thick M.Type) -> @out Int, setter @$s8keypaths1MC10chanceRainSivpZACmTk : $@convention(keypath_accessor_setter) (@in_guaranteed Int, @in_guaranteed @thick M.Type) -> ())
let _: KeyPath<M.Type, Int> = \M.Type.chanceRain
// CHECK: keypath $KeyPath<M.Type, Bool>, (root $M.Type; gettable_property $Bool, id @$s8keypaths1MC7isSunnySbvgZ : $@convention(method) (@thick M.Type) -> Bool, getter @$s8keypaths1MC7isSunnySbvpZACmTK : $@convention(keypath_accessor_getter) (@in_guaranteed @thick M.Type) -> @out Bool)
let _: KeyPath<M.Type, Bool> = \M.Type.isSunny
// CHECK: keypath $ReferenceWritableKeyPath<M.Type, Bool>, (root $M.Type; settable_property $Bool, id @$s8keypaths1MC8isCloudySbvgZ : $@convention(method) (@thick M.Type) -> Bool, getter @$s8keypaths1MC8isCloudySbvpZACmTK : $@convention(keypath_accessor_getter) (@in_guaranteed @thick M.Type) -> @out Bool, setter @$s8keypaths1MC8isCloudySbvpZACmTk : $@convention(keypath_accessor_setter) (@in_guaranteed Bool, @in_guaranteed @thick M.Type) -> ())
// CHECK: keypath $KeyPath<M.Type, Bool>, (root $M.Type; settable_property $Bool, id @$s8keypaths1MC8isCloudySbvgZ : $@convention(method) (@thick M.Type) -> Bool, getter @$s8keypaths1MC8isCloudySbvpZACmTK : $@convention(keypath_accessor_getter) (@in_guaranteed @thick M.Type) -> @out Bool, setter @$s8keypaths1MC8isCloudySbvpZACmTk : $@convention(keypath_accessor_setter) (@in_guaranteed Bool, @in_guaranteed @thick M.Type) -> ())
let _: KeyPath<M.Type, Bool> = \M.Type.isCloudy
// CHECK: keypath $KeyPath<M.Type, String>, (root $M.Type; gettable_property $String, id @$s8keypaths1MCySSSicigZ : $@convention(method) (Int, @thick M.Type) -> @owned String, getter @$s8keypaths1MCySSSicipZACmTK : $@convention(keypath_accessor_getter) (@in_guaranteed @thick M.Type, @in_guaranteed Int) -> @out String, indices [%$0 : $Int : $Int], indices_equals @$sSiTH : $@convention(keypath_accessor_equals) (@in_guaranteed Int, @in_guaranteed Int) -> Bool, indices_hash @$sSiTh : $@convention(keypath_accessor_hash) (@in_guaranteed Int) -> Int) (%{{.*}})
let _: KeyPath<M.Type, String> = \M.Type.[2]
Expand Down