gtk-rs / gtk-rs-core

Rust bindings for GNOME libraries
https://gtk-rs.org/gtk-rs-core
MIT License
280 stars 112 forks source link

`Dowgrade/Upgrade` not ususable in traits #1322

Open gdesmott opened 7 months ago

gdesmott commented 7 months ago
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 commented 7 months ago

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() {}
zachs18 commented 6 months ago

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` ```rs error[E0271]: type mismatch resolving `<::Weak as Upgrade>::Strong == &T` --> glib/src/clone.rs:57:17 | 56 | impl 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; | ^^^^^^^^^^^^^ required by this bound in `Downgrade::Weak` error[E0271]: type mismatch resolving `<::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 = ::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; | ^^^^^^^^^^^^^ required by this bound in `Downgrade::Weak` error[E0271]: type mismatch resolving ` as Upgrade>::Strong == BoxedAnyObject` --> glib/src/boxed_any_object.rs:37:5 | 37 | #[glib::object_subclass] | ^^^^^^^^^^^^^^^^^^^^^^^^ type mismatch resolving ` as Upgrade>::Strong == BoxedAnyObject` | note: expected this to be `imp::BoxedAnyObject` --> glib/src/subclass/object_impl_ref.rs:157:19 | 157 | type Strong = ObjectImplRef; | ^^^^^^^^^^^^^^^^ = note: expected struct `imp::BoxedAnyObject` found struct `ObjectImplRef` note: required by a bound in `Downgrade::Weak` --> glib/src/clone.rs:18:24 | 18 | type Weak: Upgrade; | ^^^^^^^^^^^^^ 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 ```