Skip to content

Document/improve DynGd<_, D> type inference #1026

Closed
@Bromeon

Description

@Bromeon

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_upcasts– 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_binds doesn't yield anything either…).

Current solutions to this problem:

  1. Just explicitly specify given dyn trait (recommended):
let mut obj = obj.into_dyn::<dyn Health>();
let mut obj: DynGd<_, dyn Health> = obj.into_dyn();. 
  1. Enforce lifetime bound on original trait:
trait Health: 'static {}
  1. Explicitly declare lifetime bound in function signature: fn deal_20_damage(h: &mut (dyn Health + 'static)) {…}. (ugh)

Metadata

Metadata

Assignees

No one assigned

    Labels

    c: coreCore componentsdocumentationImprovements or additions to documentationquality-of-lifeNo new functionality, but improves ergonomics/internals

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions