Description
TLDR: we need to find ways to improve or deal with error messages arising from failed type inference of D
in DynGd<T, D>
.
Originally posted by @Yarwin in #1022 (comment)
It is worth noting that type inference doesn't work – and results in very confusing errors – in most cases (sic!) if there are multiple possible DynGd<_, D>
trait implementations.
In this example foreign::NodeHealth is implementor of two dyn_gd traits: Health
and InstanceProvider
. Trying to compile following code:
fn dyn_gd_creation_deref() {
let obj = foreign::NodeHealth::new_alloc();
let original_id = obj.instance_id();
let mut obj = obj.into_dyn();
let dyn_id = obj.instance_id();
assert_eq!(dyn_id, original_id);
deal_20_damage(&mut *obj.dyn_bind_mut());
assert_eq!(obj.dyn_bind().get_hitpoints(), 80);
obj.free();
}
fn deal_20_damage(h: &mut Health) {
h.deal_damage(20);
}
trait Health {
(…)
}
Results in bunch of very confusing errors:
Checking itest v0.0.0 (/home/irwin/apps/godot/opensource-contr/missing_docs/gdext/itest/rust)
error[E0597]: `obj` does not live long enough
--> itest/rust/src/object_tests/dyn_gd_test.rs:68:26
|
63 | let mut obj = obj.into_dyn();
| ------- binding `obj` declared here
...
68 | deal_20_damage(&mut *obj.dyn_bind_mut());
| ^^^---------------
| |
| borrowed value does not live long enough
| argument requires that `obj` is borrowed for `'static`
...
72 | }
| - `obj` dropped here while still borrowed
error[E0716]: temporary value dropped while borrowed
--> itest/rust/src/object_tests/dyn_gd_test.rs:68:26
|
68 | deal_20_damage(&mut *obj.dyn_bind_mut());
| ---------------------^^^^^^^^^^^^^^^^^^-- temporary value is freed at the end of this statement
| | |
| | creates a temporary value which is freed while still in use
| argument requires that borrow lasts for `'static`
error[E0502]: cannot borrow `obj` as immutable because it is also borrowed as mutable
--> itest/rust/src/object_tests/dyn_gd_test.rs:69:16
|
68 | deal_20_damage(&mut *obj.dyn_bind_mut());
| ------------------
| |
| mutable borrow occurs here
| argument requires that `obj` is borrowed for `'static`
69 | assert_eq!(obj.dyn_bind().get_hitpoints(), 80);
| ^^^ immutable borrow occurs here
error[E0505]: cannot move out of `obj` because it is borrowed
--> itest/rust/src/object_tests/dyn_gd_test.rs:71:5
|
63 | let mut obj = obj.into_dyn();
| ------- binding `obj` declared here
...
68 | deal_20_damage(&mut *obj.dyn_bind_mut());
| ------------------
| |
| borrow of `obj` occurs here
| argument requires that `obj` is borrowed for `'static`
...
71 | obj.free();
| ^^^ move out of `obj` occurs here
It might be that &mut (dyn Health + 'static)
- a return type declared in NodeHealth
's AsDyn
implementation for dyn_upcast
s– is different from &mut Health
and compiler tries to enforce/satisfy this lifetime bound by making a reference static?
This issue should be mentioned and documented in the book. The errors are unhelpful and confusing. It is next to impossible to know what is going on without knowledge about an inner implementation (which might require some digging – AsDyn
is hidden behind macro invocation for example, checking descriptions of dyn_bind
s doesn't yield anything either…).
Current solutions to this problem:
- Just explicitly specify given dyn trait (recommended):
let mut obj = obj.into_dyn::<dyn Health>();
let mut obj: DynGd<_, dyn Health> = obj.into_dyn();.
- Enforce lifetime bound on original trait:
trait Health: 'static {
…
}
- Explicitly declare lifetime bound in function signature:
fn deal_20_damage(h: &mut (dyn Health + 'static)) {…}
. (ugh)