gtk-rs-core icon indicating copy to clipboard operation
gtk-rs-core copied to clipboard

`Dowgrade/Upgrade` not ususable in traits

Open gdesmott opened this issue 11 months ago • 2 comments

trait Mytrait: Downgrade {
    fn mushroom(&self) {
        let weak = self.downgrade();
        let this = weak.upgrade().unwrap();
        this.snake();
    }

    fn snake(&self) {}
}

fails with:

error[E0599]: no method named `snake` found for associated type `<<Self as Downgrade>::Weak as Upgrade>::Strong` in the current scope
   --> glib/src/clone.rs:116:14
    |
116 |         this.snake();
    |              ^^^^^ method not found in `<<Self as Downgrade>::Weak as Upgrade>::Strong`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
note: `Mytrait` defines an item `snake`, perhaps you need to implement it
   --> glib/src/clone.rs:112:1
    |
112 | trait Mytrait: Downgrade {
    | ^^^^^^^^^^^^^^^^^^^^^^^^

I tried adding a bound tying back Upgrade::Strong with the trait but that doesn't work either:

trait Mytrait: Downgrade
where
    <<Self as Downgrade>::Weak as Upgrade>::Strong: Mytrait,
{
    fn mushroom(&self) {
        let weak = self.downgrade();
        let this = weak.upgrade().unwrap();
        this.snake();
    }

    fn snake(&self) {}
}
error[E0277]: the trait bound `<<<<Self as Downgrade>::Weak as Upgrade>::Strong as Downgrade>::Weak as Upgrade>::Strong: Mytrait` is not satisfied
   --> glib/src/clone.rs:114:53
    |
114 |     <<Self as Downgrade>::Weak as Upgrade>::Strong: Mytrait,
    |                                                     ^^^^^^^ the trait `Mytrait` is not implemented for `<<<<Self as Downgrade>::Weak as Upgrade>::Strong as Downgrade>::Weak as Upgrade>::Strong`
    |
note: required by a bound in `Mytrait`
   --> glib/src/clone.rs:114:53
    |
112 | trait Mytrait: Downgrade
    |       ------- required by a bound in this trait
113 | where
114 |     <<Self as Downgrade>::Weak as Upgrade>::Strong: Mytrait,
    |                                                     ^^^^^^^ required by this bound in `Mytrait`
    = note: `Mytrait` is a "sealed trait", because to implement it you also need to implement `clone::Mytrait`, which is not accessible; this is usually done to force you to use one of the provided types that already implement it
help: consider further restricting the associated type
    |
114 |     <<Self as Downgrade>::Weak as Upgrade>::Strong: Mytrait, <<<<Self as Downgrade>::Weak as Upgrade>::Strong as Downgrade>::Weak as Upgrade>::Strong: Mytrait
    |                                                            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Is there a way to make this work easily?

gdesmott avatar Mar 05 '24 10:03 gdesmott

Here is a standalone version of the problem for easier testing:

trait Downgrade
where
    Self: Sized,
{
    type Weak: Upgrade;

    fn downgrade(&self) -> Self::Weak;
}

trait Upgrade
where
    Self: Sized,
{
    type Strong;

    fn upgrade(&self) -> Option<Self::Strong>;
}

trait Mytrait: Downgrade {
    fn mushroom(&self) {
        let weak = self.downgrade();
        let this = weak.upgrade().unwrap();
        this.snake();
    }

    fn snake(&self) {}
}

fn main() {}

gdesmott avatar Mar 05 '24 10:03 gdesmott

~~Library-level, the signature for Downgrade could be changed to have type Weak: Upgrade<Strong = Self>; instead of just type Weak: Upgrade;. (Are there are any cases where Self::Weak::Strong isn't Self?)~~ (see below)

As for user-level workarounds, you can add a where Self::Weak: Upgrade<Strong = Self> to your trait, e.g.

trait Mytrait: Downgrade where Self::Weak: Upgrade<Strong = Self> {
    fn mushroom(&self) {
        let weak = self.downgrade();
        let this: Self = weak.upgrade().unwrap();
        this.snake();
    }

    fn snake(&self) {}
}

Ah, no the library-level change won't work (as-is at least), since &T where T: Downgrade implements Downgrade, and you obviously can't get a &T back out of that.

errors when applying the naive change to `glib`
error[E0271]: type mismatch resolving `<<T as Downgrade>::Weak as Upgrade>::Strong == &T`
  --> glib/src/clone.rs:57:17
   |
56 | impl<T: Downgrade> Downgrade for &T {
   |      - found this type parameter
57 |     type Weak = T::Weak;
   |                 ^^^^^^^ expected `&T`, found type parameter `T`
   |
   = note:   expected reference `&_`
           found type parameter `_`
note: required by a bound in `Downgrade::Weak`
  --> glib/src/clone.rs:18:24
   |
18 |     type Weak: Upgrade<Strong = Self>;
   |                        ^^^^^^^^^^^^^ required by this bound in `Downgrade::Weak`

error[E0271]: type mismatch resolving `<<T as Downgrade>::Weak as Upgrade>::Strong == BorrowedObject<'a, T>`
    --> glib/src/object.rs:4426:17
     |
4423 | impl<'a, T: crate::clone::Downgrade + ObjectType> crate::clone::Downgrade
     |          - found this type parameter
...
4426 |     type Weak = <T as crate::clone::Downgrade>::Weak;
     |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `BorrowedObject<'_, T>`, found type parameter `T`
     |
     = note:      expected struct `BorrowedObject<'a, T>`
             found type parameter `T`
note: required by a bound in `Downgrade::Weak`
    --> glib/src/clone.rs:18:24
     |
18   |     type Weak: Upgrade<Strong = Self>;
     |                        ^^^^^^^^^^^^^ required by this bound in `Downgrade::Weak`

error[E0271]: type mismatch resolving `<ObjectImplWeakRef<BoxedAnyObject> as Upgrade>::Strong == BoxedAnyObject`
   --> glib/src/boxed_any_object.rs:37:5
    |
37  |     #[glib::object_subclass]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^ type mismatch resolving `<ObjectImplWeakRef<BoxedAnyObject> as Upgrade>::Strong == BoxedAnyObject`
    |
note: expected this to be `imp::BoxedAnyObject`
   --> glib/src/subclass/object_impl_ref.rs:157:19
    |
157 |     type Strong = ObjectImplRef<T>;
    |                   ^^^^^^^^^^^^^^^^
    = note: expected struct `imp::BoxedAnyObject`
               found struct `ObjectImplRef<imp::BoxedAnyObject>`
note: required by a bound in `Downgrade::Weak`
   --> glib/src/clone.rs:18:24
    |
18  |     type Weak: Upgrade<Strong = Self>;
    |                        ^^^^^^^^^^^^^ required by this bound in `Downgrade::Weak`
    = note: this error originates in the attribute macro `glib::object_subclass` (in Nightly builds, run with -Z macro-backtrace for more info)

For more information about this error, try `rustc --explain E0271`.
error: could not compile `glib` (lib) due to 3 previous errors
warning: build failed, waiting for other jobs to finish...
error: could not compile `glib` (lib) due to 3 previous errors

zachs18 avatar Mar 11 '24 03:03 zachs18