swiftlang / swift

The Swift Programming Language
https://swift.org
Apache License 2.0
67.54k stars 10.35k forks source link

Compiler performs implicit copies on a `borrowing` parameter passed-through to a local closure #75854

Open karwa opened 2 months ago

karwa commented 2 months ago

Description

According to SE-377:

We propose new borrowing and consuming parameter modifiers to allow developers to explicitly choose the ownership convention that a function uses to receive immutable parameters. Applying one of these modifiers to a parameter causes that parameter binding to no longer be implicitly copyable, and potential copies need to be marked with the new copy x operator.

In the reproduction test case, the compiler performs a copy of a parameter marked as borrowing without the developer having to use the copy operator.

(there is a related bug, which I will file separately, about this crashing the compiler if Foo<T> is ~Copyable)

Reproduction

struct Foo<T> {}

func huh<T>(_ source: borrowing Foo<T>) {
  let process: (borrowing Foo<T>) -> () -> Void = {
    s in { _ = consume s }  // This should not be valid!
  }
  process(source)()
}

Expected behavior

Expect the compiler to reject the reproduction test case. It is not possible to consume a borrow!

Environment

Swift version 6.0-dev (LLVM 73a346c9caf32cc, Swift 3e21fc6610cc917) Target: x86_64-unknown-linux-gnu

Additional information

No response

tbkka commented 2 months ago

CC: @kavon

kavon commented 2 months ago

Seems this can be reduced further to:

struct Foo<T> {}
func consumeFoo<T>(_ x: consuming Foo<T>) {}

func huh<T>(_ source: borrowing Foo<T>) {
  let process: (borrowing Foo<T>) -> Void = { 
    s in
    // (_ s: borrowing Foo<T>) in  // <- only caught with explicit annotation
    _ = consume s
  }
  process(source)
}

I thought this was recently fixed in https://github.com/swiftlang/swift/pull/75731 but it turns out that's not the case, and there's still some issues around the inference of borrowing and whether that triggers the right checking.