An annoying thing in Rust is that closures only borrow and capture the first part of a stable name, rather than all of it.
This often results in unexpected spurious borrow check errors when a closure attempts to mutably borrow and capture “self” (or some other big structure variable) when you of course expected to only borrow a relevant field, requiring to manually desugar the closure capture in the proper way.
It also means that moving code inside an once closure that is executed immediately can result in code that unexpectedly does not compile due to this issue.
I think this should be fixed, and as far as I can tell this should be a compatible change.
The size of closure types would change, and broken unsafe code modifying data that is borrowed elsewhere would cause breakage, but I don’t think these would be problems in practice, and are not guaranteed anyway.
To be clear, what would happen is that:
take_closure(|| a.b.c.foo())
would be desugared to:
let capture = &a.b.c; take_closure(move || capture.foo());
as opposed to the current and annoying:
let capture = &a; take_closure(move || capture.b.c.foo());
Obviously the “stable name” must stop whenever an automatic deref or anything else that results in Rust code executing would be required, as moving that out of a closure would be an incompatible change due to possible side effects.
if the user wants to override this behavior, they can just introduce a variable in the closure:
take_closure(|| {let a = &a; a.b.c.foo()})
Note that a direct implementation of this will result in increased memory usage for stored closures due to a higher number of capture variables. Thus, it’s important to, as an optimization, capture the shortest part of the stable name that would not cause borrow check issues.