Why this fires¶
using resource = acquire() { ... } closes a resource at the end of its lexical
block. A method merely named close does not establish the cleanup contract.
struct Resource { id: int }
impl core::cleanup::Cleanup for Resource {
fn close(self) { print(self.id) }
}
let answer = using resource = Resource { id: 7 } { resource.id + 1 }The scope owns disposal after the existing borrowing Cleanup::close(self)
call. For a linear resource, an earlier transfer to a sink parameter or a
returned tail value disarms this cleanup through the ordinary linear defer
rules. An authored borrowing resource.close() keeps its ordinary meaning.
Acquisition evaluates once. A failed acquisition does not install cleanup.
The binding belongs to the body, and its tail returns an ordinary value.
Cleanup also runs on lexical return, ?, break, and continue exits.
An erased any value and a user-defined trait named Cleanup are not proofs
of the canonical protocol. Give the acquisition a concrete resource type
and implement core::cleanup::Cleanup.
For a generic T: core::cleanup::Cleanup, acquisition must come from an owned
factory result or a sink binding. A borrowed generic value might be linear
at a call site, so disposing it would invalidate its caller's ownership. Generic
owned resources follow the same transfer and duplicate-use rules as concrete
linear resources.
A generic call result also requires ownership of any generic inputs: pass
those inputs through declared sink parameters. A call that only borrows a
generic input cannot turn that input into a scope-owned resource. Factory
calls without generic inputs remain valid, including factories imported from
another module.