Skip to content

Commit 9bfa236

Browse files
committed
[sending] Implement non-protocol function subtyping rules.
rdar://127675288
1 parent b09073e commit 9bfa236

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
@@ -3235,6 +3235,12 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
32353235
return getTypeMatchFailure(locator);
32363236
}
32373237

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

@@ -3665,6 +3671,13 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
36653671
return getTypeMatchFailure(argumentLocator);
36663672
}
36673673

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

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)