Skip to content

Commit 93fabf0

Browse files
authored
Merge pull request swiftlang#72239 from xedin/infersendablefromcaptures-fixes
[Sema] A few minor fixes for `InferSendableFromCaptures` feature
2 parents 495a177 + 3376d03 commit 93fabf0

File tree

3 files changed

+68
-0
lines changed

3 files changed

+68
-0
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10206,6 +10206,9 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
1020610206
// where the base type has a conditional Sendable conformance
1020710207
if (Context.LangOpts.hasFeature(Feature::InferSendableFromCaptures)) {
1020810208
auto shouldCheckSendabilityOfBase = [&]() {
10209+
if (!Context.getProtocol(KnownProtocolKind::Sendable))
10210+
return false;
10211+
1020910212
// Static members are always sendable because they only capture
1021010213
// metatypes which are Sendable.
1021110214
if (baseObjTy->is<AnyMetatypeType>())

lib/Sema/MiscDiagnostics.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5450,6 +5450,11 @@ static void maybeDiagnoseCallToKeyValueObserveMethod(const Expr *E,
54505450
auto isKeyPathLiteral = [&](Expr *argExpr) -> KeyPathExpr * {
54515451
if (auto *DTBE = getAsExpr<DerivedToBaseExpr>(argExpr))
54525452
argExpr = DTBE->getSubExpr();
5453+
// Sendable key path literals are represented as an existential
5454+
// protocol composition with `Sendable` protocol which has to be
5455+
// opened in certain scenarios i.e. to pass it to non-Sendable version.
5456+
if (auto *OEE = getAsExpr<OpenExistentialExpr>(argExpr))
5457+
argExpr = OEE->getExistentialValue();
54535458
return getAsExpr<KeyPathExpr>(argExpr);
54545459
};
54555460

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// RUN: %target-typecheck-verify-swift -enable-upcoming-feature InferSendableFromCaptures
2+
3+
// REQUIRES: objc_interop
4+
// REQUIRES: concurrency
5+
// REQUIRES: asserts
6+
7+
// This is a copy of test/expr/primary/keypath/keypath-observe-objc.swift with additional requirements to test sendable key paths
8+
9+
import Foundation
10+
11+
class Foo: NSObject {
12+
var number1 = 1
13+
dynamic var number2 = 2
14+
@objc var number3 = 3
15+
@objc dynamic var number4 = 4
16+
@objc var number5: Int {
17+
get { return 5 }
18+
set {}
19+
}
20+
}
21+
22+
class Bar: NSObject {
23+
@objc dynamic let foo: Foo
24+
25+
init(foo: Foo) {
26+
self.foo = foo
27+
super.init()
28+
29+
_ = observe(\.foo.number1, options: [.new]) { _, change in
30+
// expected-warning@-1 {{passing reference to non-'@objc dynamic' property 'number1' to KVO method 'observe(_:options:changeHandler:)' may lead to unexpected behavior or runtime trap}}
31+
print("observer1")
32+
}
33+
34+
_ = observe(\.foo.number2, options: [.new]) { _, change in
35+
// expected-warning@-1 {{passing reference to non-'@objc dynamic' property 'number2' to KVO method 'observe(_:options:changeHandler:)' may lead to unexpected behavior or runtime trap}}
36+
print("observer2")
37+
}
38+
39+
_ = observe(\.foo.number3, options: [.new]) { _, change in
40+
// expected-warning@-1 {{passing reference to non-'@objc dynamic' property 'number3' to KVO method 'observe(_:options:changeHandler:)' may lead to unexpected behavior or runtime trap}}
41+
print("observer3")
42+
}
43+
44+
_ = observe(\.foo.number4, options: [.new]) { _, change in // Okay
45+
print("observer4")
46+
}
47+
48+
_ = observe(\.foo.number5, options: [.new]) { _, change in // Okay
49+
print("observer4")
50+
}
51+
}
52+
}
53+
54+
@_semantics("keypath.mustBeValidForKVO")
55+
func quux<T, V, U>(_ object: T, at keyPath: KeyPath<T, V>, _ keyPath2: KeyPath<T, U>) { }
56+
57+
// The presence of a valid keypath should not prevent detection of invalid ones
58+
// later in the argument list, so start with a valid one here.
59+
quux(Foo(), at: \.number4, \.number1)
60+
// expected-warning@-1 {{passing reference to non-'@objc dynamic' property 'number1' to KVO method 'quux(_:at:_:)' may lead to unexpected behavior or runtime trap}}

0 commit comments

Comments
 (0)