-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[CodeComplete] Mark results as not recommended if global actor context doesn't match #37711
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
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
// REQUIRES: concurrency | ||
// RUN: %target-swift-ide-test -batch-code-completion -source-filename %s -filecheck %raw-FileCheck -completion-output-dir %t -enable-experimental-concurrency | ||
|
||
class MyNonSendable {} | ||
struct MySendable {} | ||
|
||
@globalActor | ||
actor MyGlobalActor { | ||
static var shared = MyGlobalActor() | ||
} | ||
|
||
@globalActor | ||
actor MyOtherGlobalActor { | ||
static var shared = MyOtherGlobalActor() | ||
} | ||
|
||
@MyGlobalActor func globalFuncOnGlobalActor() {} | ||
|
||
func takeClosure<T>(_: () async -> T) {} | ||
|
||
var otherInstanceOfMyClass = MyClass() | ||
|
||
class MyClass { | ||
@MyGlobalActor func funcOnGlobalActor() -> Int { return 0 } | ||
@MyOtherGlobalActor func funcOnOtherGlobalActor() -> Int { return 0 } | ||
func funcSync() -> Int { return 0 } | ||
|
||
@MyGlobalActor func nonSenableFuncOnGlobalActor(arg: MyNonSendable) -> Int { return 0 } | ||
@MyOtherGlobalActor func nonSenableFuncOnOtherGlobalActor(arg: MyNonSendable) -> Int { return 0 } | ||
|
||
@MyGlobalActor var varOnGlobalActor: Int = 0 | ||
@MyOtherGlobalActor var varOnOtherGlobalActor: Int = 0 | ||
var varSync: Int = 0 | ||
|
||
@MyGlobalActor subscript(onGlobalActor onGlobalActor: Int) -> Int { get { 1 } set { } } | ||
@MyOtherGlobalActor subscript(onOtherGlobalActor onOtherGlobalActor: Int) -> Int { get { 1 } set { } } | ||
subscript(sync sync: Int) -> Int { get { 1 } set { } } | ||
} | ||
|
||
extension MyClass { | ||
@MyGlobalActor func testOnGlobalActor() { | ||
let _ = #^IN_FUNC_ON_GLOBAL_ACTOR^# | ||
// IN_FUNC_ON_GLOBAL_ACTOR: Begin completions | ||
// IN_FUNC_ON_GLOBAL_ACTOR-DAG: Decl[InstanceMethod]/CurrNominal: funcOnGlobalActor()[#Int#]; name=funcOnGlobalActor() | ||
// IN_FUNC_ON_GLOBAL_ACTOR-DAG: Decl[InstanceMethod]/CurrNominal/NotRecommended: funcOnOtherGlobalActor()[' async'][#Int#]; name=funcOnOtherGlobalActor() async | ||
// IN_FUNC_ON_GLOBAL_ACTOR-DAG: Decl[InstanceMethod]/CurrNominal: funcSync()[#Int#]; name=funcSync() | ||
// IN_FUNC_ON_GLOBAL_ACTOR-DAG: Decl[InstanceMethod]/CurrNominal: nonSenableFuncOnGlobalActor({#arg: MyNonSendable#})[#Int#]; name=nonSenableFuncOnGlobalActor(arg: MyNonSendable) | ||
// IN_FUNC_ON_GLOBAL_ACTOR-DAG: Decl[InstanceMethod]/CurrNominal/NotRecommended: nonSenableFuncOnOtherGlobalActor({#arg: MyNonSendable#})[' async'][#Int#]; name=nonSenableFuncOnOtherGlobalActor(arg: MyNonSendable) async | ||
// IN_FUNC_ON_GLOBAL_ACTOR-DAG: Decl[InstanceVar]/CurrNominal: varOnGlobalActor[#Int#]; name=varOnGlobalActor | ||
// IN_FUNC_ON_GLOBAL_ACTOR-DAG: Decl[InstanceVar]/CurrNominal/NotRecommended: varOnOtherGlobalActor[#Int#][' async']; name=varOnOtherGlobalActor async | ||
// IN_FUNC_ON_GLOBAL_ACTOR-DAG: Decl[InstanceVar]/CurrNominal: varSync[#Int#]; name=varSync | ||
// IN_FUNC_ON_GLOBAL_ACTOR: End completions | ||
|
||
let _ = self.#^IN_FUNC_ON_GLOBAL_ACTOR_SELF_DOT^# | ||
// IN_FUNC_ON_GLOBAL_ACTOR_SELF_DOT: Begin completions | ||
// IN_FUNC_ON_GLOBAL_ACTOR_SELF_DOT-DAG: Decl[InstanceMethod]/CurrNominal: funcOnGlobalActor()[#Int#]; name=funcOnGlobalActor() | ||
// IN_FUNC_ON_GLOBAL_ACTOR_SELF_DOT-DAG: Decl[InstanceMethod]/CurrNominal/NotRecommended: funcOnOtherGlobalActor()[' async'][#Int#]; name=funcOnOtherGlobalActor() async | ||
// IN_FUNC_ON_GLOBAL_ACTOR_SELF_DOT-DAG: Decl[InstanceMethod]/CurrNominal: funcSync()[#Int#]; name=funcSync() | ||
// IN_FUNC_ON_GLOBAL_ACTOR_SELF_DOT-DAG: Decl[InstanceMethod]/CurrNominal: nonSenableFuncOnGlobalActor({#arg: MyNonSendable#})[#Int#]; name=nonSenableFuncOnGlobalActor(arg: MyNonSendable) | ||
// IN_FUNC_ON_GLOBAL_ACTOR_SELF_DOT-DAG: Decl[InstanceMethod]/CurrNominal/NotRecommended: nonSenableFuncOnOtherGlobalActor({#arg: MyNonSendable#})[' async'][#Int#]; name=nonSenableFuncOnOtherGlobalActor(arg: MyNonSendable) async | ||
// IN_FUNC_ON_GLOBAL_ACTOR_SELF_DOT-DAG: Decl[InstanceVar]/CurrNominal: varOnGlobalActor[#Int#]; name=varOnGlobalActor | ||
// IN_FUNC_ON_GLOBAL_ACTOR_SELF_DOT-DAG: Decl[InstanceVar]/CurrNominal/NotRecommended: varOnOtherGlobalActor[#Int#][' async']; name=varOnOtherGlobalActor async | ||
// IN_FUNC_ON_GLOBAL_ACTOR_SELF_DOT-DAG: Decl[InstanceVar]/CurrNominal: varSync[#Int#]; name=varSync | ||
// IN_FUNC_ON_GLOBAL_ACTOR_SELF_DOT: End completions | ||
|
||
let _ = self#^IN_FUNC_ON_GLOBAL_ACTOR_NODOT^# | ||
// IN_FUNC_ON_GLOBAL_ACTOR_NODOT: Begin completions | ||
// IN_FUNC_ON_GLOBAL_ACTOR_NODOT-DAG: Decl[InstanceMethod]/CurrNominal: .funcOnGlobalActor()[#Int#]; name=funcOnGlobalActor() | ||
// IN_FUNC_ON_GLOBAL_ACTOR_NODOT-DAG: Decl[InstanceMethod]/CurrNominal/NotRecommended: .funcOnOtherGlobalActor()[' async'][#Int#]; name=funcOnOtherGlobalActor() async | ||
// IN_FUNC_ON_GLOBAL_ACTOR_NODOT-DAG: Decl[InstanceMethod]/CurrNominal: .funcSync()[#Int#]; name=funcSync() | ||
// IN_FUNC_ON_GLOBAL_ACTOR_NODOT-DAG: Decl[InstanceMethod]/CurrNominal: .nonSenableFuncOnGlobalActor({#arg: MyNonSendable#})[#Int#]; name=nonSenableFuncOnGlobalActor(arg: MyNonSendable) | ||
// IN_FUNC_ON_GLOBAL_ACTOR_NODOT-DAG: Decl[InstanceMethod]/CurrNominal/NotRecommended: .nonSenableFuncOnOtherGlobalActor({#arg: MyNonSendable#})[' async'][#Int#]; name=nonSenableFuncOnOtherGlobalActor(arg: MyNonSendable) async | ||
// IN_FUNC_ON_GLOBAL_ACTOR_NODOT-DAG: Decl[InstanceVar]/CurrNominal: .varOnGlobalActor[#Int#]; name=varOnGlobalActor | ||
// IN_FUNC_ON_GLOBAL_ACTOR_NODOT-DAG: Decl[InstanceVar]/CurrNominal/NotRecommended: .varOnOtherGlobalActor[#Int#][' async']; name=varOnOtherGlobalActor async | ||
// IN_FUNC_ON_GLOBAL_ACTOR_NODOT-DAG: Decl[InstanceVar]/CurrNominal: .varSync[#Int#]; name=varSync | ||
// IN_FUNC_ON_GLOBAL_ACTOR_NODOT-DAG: Decl[Subscript]/CurrNominal: [{#onGlobalActor: Int#}][#Int#]; name=[onGlobalActor: Int] | ||
// IN_FUNC_ON_GLOBAL_ACTOR_NODOT-DAG: Decl[Subscript]/CurrNominal/NotRecommended: [{#onOtherGlobalActor: Int#}][' async'][#Int#]; name=[onOtherGlobalActor: Int] async | ||
// IN_FUNC_ON_GLOBAL_ACTOR_NODOT-DAG: Decl[Subscript]/CurrNominal: [{#sync: Int#}][#Int#]; name=[sync: Int] | ||
// IN_FUNC_ON_GLOBAL_ACTOR_NODOT: End completions | ||
|
||
let _ = otherInstanceOfMyClass.#^IN_FUNC_ON_GLOBAL_ACTOR_OTHER_DOT?check=IN_FUNC_ON_GLOBAL_ACTOR_SELF_DOT^# | ||
let _ = otherInstanceOfMyClass#^IN_FUNC_ON_GLOBAL_ACTOR_OTHER_NODOT?check=IN_FUNC_ON_GLOBAL_ACTOR_NODOT^# | ||
} | ||
|
||
func testInSyncFunc() { | ||
let _ = #^IN_SYNC_FUNC^# | ||
// IN_SYNC_FUNC: Begin completions | ||
// IN_SYNC_FUNC_DOT-DAG: Decl[InstanceMethod]/CurrNominal/NotRecommended: funcOnGlobalActor()[' async'][#Int#]; name=funcOnGlobalActor() | ||
// IN_SYNC_FUNC_DOT-DAG: Decl[InstanceMethod]/CurrNominal/NotRecommended: funcOnOtherGlobalActor()[' async'][#Int#]; name=funcOnOtherGlobalActor() async | ||
// IN_SYNC_FUNC_DOT-DAG: Decl[InstanceMethod]/CurrNominal: funcSync()[#Int#]; name=funcSync() | ||
// IN_SYNC_FUNC_DOT-DAG: Decl[InstanceMethod]/CurrNominal/NotRecommended: nonSenableFuncOnGlobalActor({#arg: MyNonSendable#})[' async'][#Int#]; name=nonSenableFuncOnGlobalActor(arg: MyNonSendable) | ||
// IN_SYNC_FUNC_DOT-DAG: Decl[InstanceMethod]/CurrNominal/NotRecommended: nonSenableFuncOnOtherGlobalActor({#arg: MyNonSendable#})[' async'][#Int#]; name=nonSenableFuncOnOtherGlobalActor(arg: MyNonSendable) async | ||
// IN_SYNC_FUNC_DOT-DAG: Decl[InstanceVar]/CurrNominal/NotRecommended: varOnGlobalActor[#Int#][' async']; name=varOnGlobalActor | ||
// IN_SYNC_FUNC_DOT-DAG: Decl[InstanceVar]/CurrNominal/NotRecommended: varOnOtherGlobalActor[#Int#][' async']; name=varOnOtherGlobalActor async | ||
// IN_SYNC_FUNC_DOT-DAG: Decl[InstanceVar]/CurrNominal: varSync[#Int#]; name=varSync | ||
// IN_SYNC_FUNC: End completions | ||
|
||
let _ = self.#^IN_SYNC_FUNC_SELF_DOT^# | ||
// IN_SYNC_FUNC_SELF_DOT: Begin completions | ||
// IN_SYNC_FUNC_SELF_DOT-DAG: Decl[InstanceMethod]/CurrNominal/NotRecommended: funcOnGlobalActor()[' async'][#Int#]; name=funcOnGlobalActor() | ||
// IN_SYNC_FUNC_SELF_DOT-DAG: Decl[InstanceMethod]/CurrNominal/NotRecommended: funcOnOtherGlobalActor()[' async'][#Int#]; name=funcOnOtherGlobalActor() async | ||
// IN_SYNC_FUNC_SELF_DOT-DAG: Decl[InstanceMethod]/CurrNominal: funcSync()[#Int#]; name=funcSync() | ||
// IN_SYNC_FUNC_SELF_DOT-DAG: Decl[InstanceMethod]/CurrNominal/NotRecommended: nonSenableFuncOnGlobalActor({#arg: MyNonSendable#})[' async'][#Int#]; name=nonSenableFuncOnGlobalActor(arg: MyNonSendable) | ||
// IN_SYNC_FUNC_SELF_DOT-DAG: Decl[InstanceMethod]/CurrNominal/NotRecommended: nonSenableFuncOnOtherGlobalActor({#arg: MyNonSendable#})[' async'][#Int#]; name=nonSenableFuncOnOtherGlobalActor(arg: MyNonSendable) async | ||
// IN_SYNC_FUNC_SELF_DOT-DAG: Decl[InstanceVar]/CurrNominal/NotRecommended: varOnGlobalActor[#Int#][' async']; name=varOnGlobalActor | ||
// IN_SYNC_FUNC_SELF_DOT-DAG: Decl[InstanceVar]/CurrNominal/NotRecommended: varOnOtherGlobalActor[#Int#][' async']; name=varOnOtherGlobalActor async | ||
// IN_SYNC_FUNC_SELF_DOT-DAG: Decl[InstanceVar]/CurrNominal: varSync[#Int#]; name=varSync | ||
// IN_SYNC_FUNC_SELF_DOT: End completions | ||
|
||
let _ = self#^IN_SYNC_FUNC_NODOT^# | ||
// IN_SYNC_FUNC_NODOT: Begin completions | ||
// IN_SYNC_FUNC_NODOT-DAG: Decl[InstanceMethod]/CurrNominal/NotRecommended: .funcOnGlobalActor()[' async'][#Int#]; name=funcOnGlobalActor() | ||
// IN_SYNC_FUNC_NODOT-DAG: Decl[InstanceMethod]/CurrNominal/NotRecommended: .funcOnOtherGlobalActor()[' async'][#Int#]; name=funcOnOtherGlobalActor() async | ||
// IN_SYNC_FUNC_NODOT-DAG: Decl[InstanceMethod]/CurrNominal: .funcSync()[#Int#]; name=funcSync() | ||
// IN_SYNC_FUNC_NODOT-DAG: Decl[InstanceMethod]/CurrNominal/NotRecommended: .nonSenableFuncOnGlobalActor({#arg: MyNonSendable#})[' async'][#Int#]; name=nonSenableFuncOnGlobalActor(arg: MyNonSendable) | ||
// IN_SYNC_FUNC_NODOT-DAG: Decl[InstanceMethod]/CurrNominal/NotRecommended: .nonSenableFuncOnOtherGlobalActor({#arg: MyNonSendable#})[' async'][#Int#]; name=nonSenableFuncOnOtherGlobalActor(arg: MyNonSendable) async | ||
// IN_SYNC_FUNC_NODOT-DAG: Decl[InstanceVar]/CurrNominal/NotRecommended: .varOnGlobalActor[#Int#][' async']; name=varOnGlobalActor | ||
// IN_SYNC_FUNC_NODOT-DAG: Decl[InstanceVar]/CurrNominal/NotRecommended: .varOnOtherGlobalActor[#Int#][' async']; name=varOnOtherGlobalActor async | ||
// IN_SYNC_FUNC_NODOT-DAG: Decl[InstanceVar]/CurrNominal: .varSync[#Int#]; name=varSync | ||
// IN_SYNC_FUNC_NODOT-DAG: Decl[Subscript]/CurrNominal/NotRecommended: [{#onGlobalActor: Int#}][' async'][#Int#]; name=[onGlobalActor: Int] | ||
// IN_SYNC_FUNC_NODOT-DAG: Decl[Subscript]/CurrNominal/NotRecommended: [{#onOtherGlobalActor: Int#}][' async'][#Int#]; name=[onOtherGlobalActor: Int] async | ||
// IN_SYNC_FUNC_NODOT-DAG: Decl[Subscript]/CurrNominal: [{#sync: Int#}][#Int#]; name=[sync: Int] | ||
// IN_SYNC_FUNC_NODOT: End completions | ||
|
||
let _ = otherInstanceOfMyClass.#^IN_SYNC_FUNC_OTHER_DOT?check=IN_SYNC_FUNC_SELF_DOT^# | ||
let _ = otherInstanceOfMyClass#^IN_SYNC_FUNC_OTHER_NODOT?check=IN_SYNC_FUNC_NODOT^# | ||
} | ||
|
||
func testInGlobalActorClosure() { | ||
_ = { @MyGlobalActor () -> Void in | ||
let _ = otherInstanceOfMyClass.#^IN_CLOSURE_ON_GLOBAL_ACTOR_OTHER_DOT?check=IN_FUNC_ON_GLOBAL_ACTOR_SELF_DOT^# | ||
} | ||
} | ||
|
||
func testInGlobalActorClosureWithoutExplicitAttribute() { | ||
let callback: @MyGlobalActor () -> Void | ||
callback = { | ||
let _ = otherInstanceOfMyClass.#^IN_CLOSURE_ON_GLOBAL_ACTOR_WITHOUT_EXPLICIT_LABEL_OTHER_DOT?check=IN_FUNC_ON_GLOBAL_ACTOR_SELF_DOT^# | ||
} | ||
} | ||
|
||
@MyGlobalActor func testInClosureInGlobalActorFunc() { | ||
_ = { () -> Void in | ||
let _ = otherInstanceOfMyClass.#^IN_CLOSURE_IN_FUNC_ON_GLOBAL_ACTOR_OTHER_DOT?check=IN_FUNC_ON_GLOBAL_ACTOR_SELF_DOT^# | ||
} | ||
} | ||
|
||
func testInClosureNestedInClosureOnGlobalActorFunc() { | ||
_ = { @MyGlobalActor () -> Void in | ||
_ = { () -> Void in | ||
let _ = otherInstanceOfMyClass.#^IN_CLOSURE_NESTED_IN_CLOSURE_ON_GLOBAL_ACTOR_OTHER_DOT?check=IN_FUNC_ON_GLOBAL_ACTOR_SELF_DOT^# | ||
} | ||
} | ||
} | ||
|
||
func testInLocalFunc() { | ||
@MyGlobalActor func localFunc() { | ||
let _ = otherInstanceOfMyClass.#^IN_LOCAL_FUNC_ON_GLOBAL_ACTOR_OTHER_DOT?check=IN_FUNC_ON_GLOBAL_ACTOR_SELF_DOT^# | ||
} | ||
} | ||
|
||
@MyGlobalActor func testInNestedSingleExpressionClosure() { | ||
takeClosure { | ||
takeClosure { | ||
otherInstanceOfMyClass.#^IN_NESTED_SINGLE_EXPRESSION_CLOSURE_ON_GLBOAL_ACTOR_OTHER_DOT?check=IN_FUNC_ON_GLOBAL_ACTOR_SELF_DOT^# | ||
} | ||
} | ||
} | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you add a nested single expression closure test? e.g. @MyGlobalActor func globalFuncOnMyGlobalActor() {}
@MyOtherGlobalActor func globalFuncOnMyOtherGlobalActor() {}
func foo<T>(_: () async -> T) {}
@MyGlobalActor func test() {
foo {
foo {
<HERE>
}
}
} |
||
actor ActorTests { | ||
func testInActor() { | ||
let _ = otherInstanceOfMyClass.#^IN_ACTOR_OTHER_DOT?check=IN_SYNC_FUNC_SELF_DOT^# | ||
let _ = otherInstanceOfMyClass#^IN_ACTOR_OTHER_NODOT?check=IN_SYNC_FUNC_NODOT^# | ||
} | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Hmm, it feels a bit dicey setting the actor isolation for a closure in more than one place. Should we request'ify
determineClosureActorIsolation
?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 agree that it’s not really pretty. But the problem is that the
ActorIsolationChecker
currently implicitly assumes that it’s walking the tree top to bottom.IMHO the proper solution would be to completely requesting
ActorIsolationChecker
so that it works bottom to top, requesting the actor isolation of an outer type as needed. But I felt that was too big of a change for Swift 5.5 and that’s why I stuck with the current, more local, approach.