Consuming closure arguments require specific annotation

I am currently exploring some uses cases for ~Copyable types. I think a rather simple example is this:

struct NC: ~Copyable {}

func fn(closure: (consuming NC) -> Void) {
    let nc = NC()
    closure(nc)
}

struct Consumer {
    init(_: consuming NC) {}
}

At call site, I would have assumed that it should look like this:

fn { nc in
    _ = Consumer(nc)
}

However, the compiler tells me: 'nc' is borrowed and cannot be consumed. It is not borrowed, since I specified the closure argument as consuming, right?

A temporary workaround was this:

fn { (nc: consuming NC) in
    _ = Consumer(nc)
}

To me this seems like a bug, however I want to verify that I am not missing anything. Would someone mind to clarify? I could not find anything about this in the pitch and nothing really similar in the forums.

I can reproduce this error, I agree it seems to be a type-checking bug. Inside fn { nc in }, nc is inferred as a borrowing one.

Note that for functions with a ~Copyable argument, it is legal to cast a borrowing function to a consuming function, but not vise versa.

func foo(_ val: consuming NC) {}
let foo1: (borrowing NC) -> Void = foo // No, crashes my compiler

func bar(_ val: borrowing NC) {}
let bar1: (consuming NC) -> Void = bar // OK, compiler managed to create thunks

I just wonder why the compiler prefers to infer borrowing here...

1 Like

Here the bug report for reference: `consuming` closure arguments automatically infers `borrowing` · Issue #78851 · swiftlang/swift · GitHub

1 Like