Skip to content

Commit c46b6b8

Browse files
committed
[sending] Implement non-protocol function subtyping rules.
rdar://127675288 (cherry picked from commit 3c166b5)
1 parent 01a728a commit c46b6b8

File tree

2 files changed

+64
-3
lines changed

2 files changed

+64
-3
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3236,6 +3236,12 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
32363236
return getTypeMatchFailure(locator);
32373237
}
32383238

3239+
// () -> sending T can be a subtype of () -> T... but not vis-a-versa.
3240+
if (func1->hasSendingResult() != func2->hasSendingResult() &&
3241+
(!func1->hasSendingResult() || kind < ConstraintKind::Subtype)) {
3242+
return getTypeMatchFailure(locator);
3243+
}
3244+
32393245
if (!matchFunctionIsolations(func1, func2, kind, flags, locator))
32403246
return getTypeMatchFailure(locator);
32413247

@@ -3666,6 +3672,13 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
36663672
return getTypeMatchFailure(argumentLocator);
36673673
}
36683674

3675+
// Do not allow for functions that expect a sending parameter to match
3676+
// with a function that expects a non-sending parameter.
3677+
if (func1Param.getParameterFlags().isSending() &&
3678+
!func2Param.getParameterFlags().isSending()) {
3679+
return getTypeMatchFailure(argumentLocator);
3680+
}
3681+
36693682
// FIXME: We should check value ownership too, but it's not completely
36703683
// trivial because of inout-to-pointer conversions.
36713684

test/Concurrency/transfernonsendable_functionsubtyping.swift

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,57 @@ protocol ProtocolWithMixedReqs {
2222
func nonSendingParamAndSendingResult(_ x: NonSendableKlass) -> sending NonSendableKlass // expected-note 4{{}}
2323
}
2424

25-
/////////////////
26-
// MARK: Tests //
27-
/////////////////
25+
/////////////////////////////////
26+
// MARK: Normal Function Tests //
27+
/////////////////////////////////
28+
29+
func functionWithSendingResult() -> sending NonSendableKlass { fatalError() }
30+
func functionWithoutSendingResult() -> NonSendableKlass { fatalError() }
31+
func functionWithSendingParameter(_ x: sending NonSendableKlass) { fatalError() }
32+
func functionWithoutSendingParameter(_ x: NonSendableKlass) { fatalError() }
33+
34+
func takeFnWithSendingResult(_ fn: () -> sending NonSendableKlass) {}
35+
func takeFnWithoutSendingResult(_ fn: () -> NonSendableKlass) {}
36+
func takeFnWithSendingParam(_ fn: (sending NonSendableKlass) -> ()) {}
37+
func takeFnWithoutSendingParam(_ fn: (NonSendableKlass) -> ()) {}
38+
39+
func testFunctionMatching() {
40+
let _: (NonSendableKlass) -> () = functionWithSendingParameter
41+
// expected-error @-1 {{cannot convert value of type '@Sendable (sending NonSendableKlass) -> ()' to specified type '(NonSendableKlass) -> ()'}}
42+
let _: (sending NonSendableKlass) -> () = functionWithSendingParameter
43+
44+
let _: (NonSendableKlass) -> () = functionWithoutSendingParameter
45+
let _: (sending NonSendableKlass) -> () = functionWithoutSendingParameter
46+
47+
takeFnWithSendingParam(functionWithSendingParameter)
48+
takeFnWithoutSendingParam(functionWithSendingParameter)
49+
// expected-error @-1 {{@Sendable (sending NonSendableKlass) -> ()' to expected argument type '(NonSendableKlass) -> ()}}
50+
takeFnWithSendingParam(functionWithoutSendingParameter)
51+
takeFnWithoutSendingParam(functionWithoutSendingParameter)
52+
}
53+
54+
func testReturnValueMatching() {
55+
let _: () -> NonSendableKlass = functionWithSendingResult
56+
let _: () -> sending NonSendableKlass = functionWithSendingResult
57+
let _: () -> NonSendableKlass = functionWithoutSendingResult
58+
let _: () -> sending NonSendableKlass = functionWithoutSendingResult
59+
// expected-error @-1 {{cannot convert value of type '@Sendable () -> NonSendableKlass' to specified type '() -> sending NonSendableKlass'}}
60+
61+
takeFnWithSendingResult(functionWithSendingResult)
62+
takeFnWithSendingResult(functionWithoutSendingResult)
63+
// expected-error @-1 {{cannot convert value of type '@Sendable () -> NonSendableKlass' to expected argument type '() -> sending NonSendableKlass'}}
64+
let x: () -> NonSendableKlass = { fatalError() }
65+
takeFnWithSendingResult(x)
66+
// expected-error @-1 {{cannot convert value of type '() -> NonSendableKlass' to expected argument type '() -> sending NonSendableKlass'}}
67+
68+
takeFnWithoutSendingResult(functionWithSendingResult)
69+
takeFnWithoutSendingResult(functionWithoutSendingResult)
70+
takeFnWithoutSendingResult(x)
71+
}
72+
73+
//////////////////////////
74+
// MARK: Protocol Tests //
75+
//////////////////////////
2876

2977
struct MatchSuccess : ProtocolWithSendingReqs, ProtocolWithMixedReqs {
3078
func sendingResult() -> sending NonSendableKlass { fatalError() }

0 commit comments

Comments
 (0)