-
Notifications
You must be signed in to change notification settings - Fork 10.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Sema]Skip Sendable conformance check when sending
are added to parameters or return types of an actor-isolated function
#78601
base: main
Are you sure you want to change the base?
Conversation
4c3c8fe
to
f96c267
Compare
sending
are added to parameters or return types of an actor-isolated function
f96c267
to
5a6d928
Compare
test/Sema/issue-76710.swift
Outdated
class NonSendableKlass1 {} | ||
|
||
protocol P1 { | ||
func bar(_ a: sending NonSendableKlass1) async -> sending NonSendableKlass1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit
func bar(_ a: sending NonSendableKlass1) async -> sending NonSendableKlass1 | |
func bar(_ a: sending NonSendableKlass1) async -> sending NonSendableKlass1 |
lib/Sema/TypeCheckConcurrency.cpp
Outdated
@@ -1166,6 +1166,9 @@ bool swift::diagnoseNonSendableTypesInReference( | |||
if (funcCheckOptions.contains(FunctionCheckKind::Params)) { | |||
// only check params if funcCheckKind specifies so | |||
for (auto param : *function->getParameters()) { | |||
if (param->isSending()) | |||
return true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here you are skipping sendability validation on all other parameters if at least one of them is marked as sending
, which seems incorrect, we should check sendability of all arguments.
Also this function is supposed to return true
if there are any errors being produced, which is not what happens in our case.
It seems like instead of bailing out early from this function we should keep checking other arguments but skip diagnoseNonSendableTypes
check below if the argument is marked as sending
.
Could you also consider adding a test for a case where first argument is marked with sending
but a second argument isn't?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the review.
we should check sendability of all arguments.
I think that's right. Let me check it again.
Also, I overlooked type->hasError()
in diagnoseSingleNonSendableType
. I think that we need to check type->hasError()
as well (not sure point).
static bool diagnoseSingleNonSendableType(
Type type, SendableCheckContext fromContext,
Type inDerivedConformance, SourceLoc loc,
llvm::function_ref<bool(Type, DiagnosticBehavior)> diagnose) {
if (type->hasError())
return false;
Could you also consider adding a test for a case where first argument is marked with sending but a second argument isn't?
Sure, I'll add it.
Thank you!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I fixed it in f633505. Please check it when you have time. Thank you!
@swift-ci please smoke test |
lib/Sema/TypeCheckConcurrency.cpp
Outdated
@@ -1181,6 +1185,10 @@ bool swift::diagnoseNonSendableTypesInReference( | |||
if (funcCheckOptions.contains(FunctionCheckKind::Results)) { | |||
// only check results if funcCheckKind specifies so | |||
Type resultType = func->getResultInterfaceType().subst(subs); | |||
|
|||
if (func->hasSendingResult() && !resultType->hasError()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We probably shouldn't bail out early if the result is markin with sending
, there are a lot of other checks further down in this function that should still pass.
Also the return value can't be true
here, since based on the comment here true
means that an error was emitted, in our case though there is no error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you.
Also the return value can't be true here,
It was my misunderstanding🤦🏻♂️ Let me fix it.
We probably shouldn't bail out early if the result is markin with sending, there are a lot of other checks further down in this function that should still pass.
How about checking diag.ID like the below?
if (diag.ID == diag::non_sendable_result_in_witness.ID &&
func->hasSendingResult() && !resultType->hasError())
return false;
non_sendable_result_in_witness.ID is “non-sendable type %0 cannot be returned from %2 implementation to caller of protocol requirement %1”.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
subscript
declarations can have sending
on parameters/result:
struct S {
subscript(_: sending Int) -> Bool { true }
}
I think it should be possible to unify some of the logic in this function because i.e. getParameters()
and getIndices()
both produce ParameterList *
and for results the logic is pretty much the same except to exactly how the type has been retrieved.
Thank you very much for the advice. I combined the function and subscript checks into one. Sorry, It's my misunderstanding. the below subscirpt is not async.
|
d350737
to
ed63c60
Compare
lib/Sema/TypeCheckConcurrency.cpp
Outdated
// Check the result type of a function. | ||
if (auto func = dyn_cast<FuncDecl>(function)) { | ||
// Check the result type of a function or subscript. | ||
if (auto func = dyn_cast<FuncDecl>(decl)) { | ||
if (funcCheckOptions.contains(FunctionCheckKind::Results)) { | ||
// only check results if funcCheckKind specifies so | ||
Type resultType = func->getResultInterfaceType().subst(subs); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is probably incorrect. It looks that we need to use getElementInterfaceType
in the case of subscript. I'll correct it (and the above if condition as well).
I’m currently looking into several potential issues related to subscripts that use the 1An assertion failure occurs during SIL generation (see https://github.com/swiftlang/swift/blob/main/lib/AST/ASTPrinter.cpp#L3816). It appears that
Steps to reproduce: Run the following: swift -frontend -emit-sil -swift-version 6 protocol P {
subscript(_: sending NonSendable) -> Bool { get }
}
struct S: P {
subscript(_: sending NonSendable) -> Bool { true }
} It seems that https://github.com/swiftlang/swift/blob/main/lib/AST/Decl.cpp#L10701 if (subscriptParam->isSending())
param->setSending();
I fixed it in another PR. 2
It appears ok. 3The For example, given the following code: struct S5 {
subscript(_: Bool) -> sending NonSendable { NonSendable() }
} The output is:
In this case, the
I fixed it in another PR. |
59c071a
to
bd1cd03
Compare
I made a mistake with the branch. I corrected it. |
81c2f43
to
414fbe4
Compare
…eters or return types of an actor-isolated function
414fbe4
to
acfabdd
Compare
I think I can find all of my answers in the comment. So, I’d like to proceed with this PR again. What do I need to modify more to fix the original issue? |
Resolves #76710
Previously, we encountered errors and notes when using a non-Sendable type with
sending
for parameters or return types of an actor-isolated function, as shown below:Based on the issue described, this functionality should work without any errors. To resolve the issue, we need to bypass the Sendable conformance check for non-Sendable types when
sending
keywords is added to function's parameters or return types.--
Even if the conformance check is skipped, invalid scenarios will still be validated at the SIL stage to ensure correctness.
For example:
When running
-emit-sil -swift-version 6
, a potential data race error is still detected.