rust-analyzer: Auto-completion doesn't find suggestions with trait-heavy code (e.g. gtk-rs)

For example when taking the example directly from https://gtk-rs.org and typing window.set in the connect_activate() closure, only the functions that are already used in scope (set_title(), set_default_size()) are suggested.

However gtk::ApplicationWindow impls glib::IsA<gtk::Widget> (and various others), via which it is covered by the impl<T: IsA<gtk::Widget>> gtk::WidgetExt for T { ... } blanket impl, which provides lots of other set_... functions.

Maybe the indirection via the IsA trait and the blanket impl is the problem here?

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 1
  • Comments: 15 (7 by maintainers)

Commits related to this issue

Most upvoted comments

After #4220 , is_writable() is visible for Message now.

And I just checked, for the case of gtk::ApplicationWindow :

gtk-screen-shot

So I think this issue could be closed ?

Still leaves $crate:: etc around but I assume that’s expected.

Thanks for the information! Yes, it is expected. RA should translate it to def-site crate name in lowering. However, it seem like there is some bugs around path resolution for $crate in associate type, here is a minimal reproducible example :

struct MessageRef;
struct Message1(MessageRef);
struct Message2(MessageRef);

macro_rules! foo {
    () => {
        impl ::std::ops::Deref for Message1 {
            type Target = $crate::MessageRef;
            fn deref(&self) ->  &Self::Target {
                &self.0
            }
        }

        impl ::std::ops::Deref for Message2 {
            type Target = crate::MessageRef;
            fn deref(&self) ->  &Self::Target {
                &self.0
            }
        }
    }
}

foo!();

fn main() {        
    let msg1 = Message1(MessageRef);
    let msg2 = Message2(MessageRef);
    
    let _a = &*msg1;     // _a is &{unknown}
    let _a = &*msg2;     // _a is &MessageRef
}

Sure, but that macro is a bit more complicated 😄

  1. glib_wrapper! is defined here . These and the cases below are the ones used for actual objects with IsA. They map to glib_object_wrapper!
  2. That one comes from here and is rather complicated, involving some recursion. In there you will find the IsA impls. There will be one for each parent type and interface that is implemented by a type (e.g. gtk::Button inherits among other things from gtk::Widget and glib::Object so there would be IsA<gtk::Widget> and IsA<glib::Object> impls).
  3. An example usage inside glib can be found here
  4. The IsA trait is defined here and has various super traits that also all come from the same file
  5. The most important usage of it is in blanket trait impls like here. That one actually uses T: ObjectType instead of T: IsA<Object> for reasons I can’t remember, but usually that would be T: IsA<Object>. See for example here for gtk::Button. That’s how methods of parent types are automatically available on sub types, i.e. how one part of OOP inheritance is modeled here.

If you have more questions please just ask 😃