Noncopyable types and implicit conversions

Yeah, that transformation does work for simple cases, but in general it won't work if the original value is borrowed as two different types, since it can't exist as both as the same time:

extension Foo { borrowing func getAnswer() -> Bool { ... } }
func query(_ foo: borrowing Foo?, _ generate: () -> Bool) -> Bool { ... } 

var foo = Foo()
query(foo) {
  return foo.getAnswer()
}

This example makes it less obvious, but foo is borrowed as a Foo? in the argument, and as a Foo as captured in the closure. It's suppose to valid to have multiple read accesses at the same time. For Copyable types, this is implemented by copying foo to do the cast.

A general borrowed-cast mechanism, or borrowed types, would be needed to fix this. I think we one day could implement a borrow x as Foo cast expression that yields a ~Escapable result whose lifetime depends on x.

Like borrowing switches, it'd be nice if the casts were borrowing like that by default, if the original type of the cast is noncopyable. It would only be consuming if you wrote consume x as Foo. So for the more immediate timeframe, it seems like it makes sense to say that you need to write consume explicitly until then.

I'm working on a PR that so far takes care of implicit optional casts; seems to work ok. My hope is to get at least a warning into Swift 6.

2 Likes