Skip to content

Different sending behavior between global actor and isolated parameter within a closure #75910

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

Closed
mattmassicotte opened this issue Aug 15, 2024 · 5 comments
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. concurrency Feature: umbrella label for concurrency language features

Comments

@mattmassicotte
Copy link
Contributor

mattmassicotte commented Aug 15, 2024

Description

I'm trying to understand the difference between these two forms. I think they should be equivalent, but the global actor version works and the isolation param version does not.

Reproduction

class Argument {
}

class NonSendable {
    public func noArgument(closure: () -> Void) {
    }
    
    public func isolatedNoArgument(isolation: isolated (any Actor)? = #isolation, value: Argument) {
        noArgument() {
            Task {
                _ = isolation
                
                // ERROR: Sending 'value' risks causing data races
                print(value)
            }
        }
    }
    
    @MainActor
    public func globalActorArgument(value: Argument) {
        noArgument() {
            Task {
                print(value)
            }
        }
    }
}

Expected behavior

I expected both of these versions to compile with no error.

Environment

Apple Swift version 6.0-dev (LLVM 3751470251df3e4, Swift 026ffdd)
Target: arm64-apple-macosx14.0

Additional information

No response

@mattmassicotte mattmassicotte added bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. triage needed This issue needs more specific labels labels Aug 15, 2024
@mattmassicotte
Copy link
Contributor Author

mattmassicotte commented Aug 15, 2024

I think I may have simplied this down even more.

class Argument {
}

class NonSendable {
    public func noArgument(closure: (isolated (any Actor)?) async -> Void) {
    }

    public func isolatedNoArgument(isolation: isolated (any Actor)? = #isolation, value: Argument) {
        // here, self *must* be on isolation
        noArgument() { innerIsolation in
            // closure is non-Sendable
            // so innerIsolation must be isolation

            // ERROR: sending 'value' risks causing data races
            print(value)
        }
    }
}

If I remove the isolated param from closure, this compiles fine.

@hborla
Copy link
Member

hborla commented Aug 22, 2024

I agree that your original examples in the issue description should behave the same. Your example in #75910 (comment) looks different, though, and I'm not convinced the compiler error in that case is a bug.

@hborla hborla added concurrency Feature: umbrella label for concurrency language features and removed triage needed This issue needs more specific labels labels Aug 22, 2024
@mattmassicotte
Copy link
Contributor Author

Ok, at the very least it is quite different. I've opened a seperate bug for that one:

#76038

@gottesmm
Copy link
Contributor

This is fixed in 0ece31e

@mattmassicotte
Copy link
Contributor Author

Confirmed - thank you so much!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. concurrency Feature: umbrella label for concurrency language features
Projects
None yet
Development

No branches or pull requests

3 participants