non-lexical lifetimes
plan exists to address
nested method calls
vec.push(vec.len()
plan exists
closures always borrow locals, even if you only use a sub-path
fn foo(&mut self) {
let inc = || self.bar += 1;
read(self.baz); // ERROR
}
SOLUTION: upvar inference can probably transform that closure so it borrows &mut self.bar
instead of &mut self
&mut self
or &self
methods that only use, or only mutate, a small subset of the state
fn foo(&mut self) {
let p = self.lookup(22); // I know this only uses `self.map`
self.set.insert(p.clone()); // ERROR: self already borrowed
}
OR
fn foo(&mut self) {
let p = self.lookup();
self.process(p);
}
fn lookup(&self) -> &Data {
// uses self.map only
}
fn process(&mut self, p: &Data) {
// this does not use `self.map`
}
This is much harder. I can imagine some special cases that use interprocedural analysis to figure things out, but other than that we're going to require some fancy annotations. Once you start thinking about trait methods, public APIs, it gets even more fun. Lots of related work here, but feels like a big step up in complexity.
relinquishing borrows
fn foo(&mut self) -> &u32 { ... }
after calling x.foo()
, it'd be nice for caller to have a shared borrow on x
T: 'a
annotations on structs
struct Foo<'a, T: 'a> { ... }
Solve with a combination of inference and elision. Draft RFC in the works. That particular struct would be:
struct Foo<', T> { ... }
but more generally you'd never have to type T: 'a
or 'a: 'b
in a struct.
lots and lots of region declarations
fn foo<'a, 'tcx: 'a, 'gcx: 'tcx, ...> { ... }
Personally, I'd like to permit generic modules:
mod tcx<'tcx, 'gcx: 'tcx> { // now all code in here can just refer to 'tcx and 'gcx
fn foo<'a> { ... }
}
Obviously this requires some sketching out. :P
frustrating interactions around invariance and mutability
This often leads to an explosion in lifetime parameters and weird error messages. Hard to fix given &mut
.