Description
This is a cross post from the users forum where I was redirected to here:
While working on a project I hit a brick wall when designing a more complicated way to reborrow an object so that a different interface is exposed. This is the definition of the types used (stripped down):
trait WorkspaceLog {
fn get(&self) -> usize;
}
struct TheLog<'a>(&'a FSWorkspaceController<'a>);
impl<'a> WorkspaceLog for TheLog<'a> {
fn get(&self) -> usize {
((self.0).0).0
}
}
trait WorkspaceController<'a> {
type Log: WorkspaceLog+'a;
fn get_log(&'a self) -> Self::Log;
fn set_log(&mut self, x: usize);
}
struct FilesystemOverlay(usize);
struct FSWorkspaceController<'a>(&'a mut FilesystemOverlay);
impl<'a, 'b> WorkspaceController<'b> for FSWorkspaceController<'a> {
type Log = TheLog<'b>;
fn get_log(&'b self) -> Self::Log {
TheLog(&*self)
}
fn set_log(&mut self, x: usize) {
(self.0).0 = x;
}
}
trait AsWorkspaceController<'a, 'b> {
type Controller: WorkspaceController<'b>+'a;
fn get_controller(&'a mut self) -> Self::Controller;
}
impl<'a, 'b> AsWorkspaceController<'a, 'b> for FilesystemOverlay {
type Controller = FSWorkspaceController<'a>;
fn get_controller(&'a mut self) -> FSWorkspaceController<'a> {
FSWorkspaceController(self)
}
}
Now, if I directly use the type FilesystemOverlay everything is just fine:
fn init1(control_dir: &mut FilesystemOverlay) -> usize {
let controller = control_dir.get_controller();
let log = controller.get_log();
log.get()
}
However, if I try to generalize control_dir, I get a problem:
fn init2<O>(control_dir: &mut O) -> usize
where for<'a, 'b> O: AsWorkspaceController<'a, 'b> {
let controller = control_dir.get_controller();
let log = controller.get_log();
log.get()
}
Although this compiles, there is a warning which might eventually be turned into an error:
warning[E0597]: `controller` does not live long enough
--> src/main.rs:59:15
|
59 | let log = controller.get_log();
| ^^^^^^^^^^ borrowed value does not live long enough
60 | log.get()
61 | }
| -
| |
| `controller` dropped here while still borrowed
| borrow might be used here, when `controller` is dropped and runs the destructor for type `<O as AsWorkspaceController<'_, '_>>::Controller`
|
= warning: This error has been downgraded to a warning for backwards compatibility with previous releases.
It represents potential unsoundness in your code.
This warning will become a hard error in the future.
It is unclear to me why the compiler thinks that controller is still borrowed and the warning doesn't carry any information which object controller is borrowed to. In addition I wonder why the compiler thinks it's unsound: As log
was constructed after controller
and may be dropped before since the lifetime of log
is late-bound, and the compiler is free to choose a shorter lifetime.
This is the full code on the playground.