Stream: t-compiler/rust-analyzer

Topic: Weird type error w/ DefDatabase & HirDatabase- help?


Jade (Apr 08 2021 at 09:14, on Zulip):

I have a DeclValidator that I want to use its DB reference to do queries with, which should be ok I think, since it's a HirDatabase, and trait HirDatabase : DefDatabase, but for some reason (lifetimes and variance shenanigans, probably), rustc is not taking it. Can someone help?

In particular I have a m which is a ModuleId, which I am calling .containing_module(db) on. db is a db: &'a dyn HirDatabase,. I have the full function below if that's helpful.

error[E0308]: mismatched types
  --> crates/hir_ty/src/diagnostics/decl_check.rs:99:63
   |
99 |                 AttrDefId::ModuleId(m) => m.containing_module(self.db).map(|v| v.into()),
   |                                                               ^^^^^^^ expected trait `DefDatabase`, found trait `HirDatabase`
   |
   = note: expected reference `&dyn DefDatabase`
              found reference `&'a (dyn HirDatabase + 'a)`

The entire function from crates/hir_ty/src/diagnostics/decl_check.rs

    /// Checks whether not following the convention is allowed for this item.
    ///
    /// Currently this method doesn't check parent attributes.
    fn allowed(&self, id: AttrDefId, allow_name: &str) -> bool {
        let is_allowed = |def_id| {
            self.db
                .attrs(def_id)
                .by_key("allow")
                .tt_values()
                .any(|tt| tt.to_string().contains(allow_name))
        };

        is_allowed(id)
            || match id {
                AttrDefId::ModuleId(m) => m.containing_module(self.db).map(|v| v.into()),
                AttrDefId::FieldId(_) => todo!(),
                AttrDefId::AdtId(_) => todo!(),
                AttrDefId::FunctionId(_) => todo!(),
                AttrDefId::EnumVariantId(_) => todo!(),
                AttrDefId::StaticId(_) => todo!(),
                AttrDefId::ConstId(_) => todo!(),
                AttrDefId::TraitId(_) => todo!(),
                AttrDefId::TypeAliasId(_) => todo!(),
                AttrDefId::MacroDefId(_) => todo!(),
                AttrDefId::ImplId(_) => todo!(),
                AttrDefId::GenericParamId(_) => todo!(),
            }
            .map(|mid| self.allowed(mid, allow_name))
            .unwrap_or(false)
    }
Lukas Wirth (Apr 08 2021 at 09:16, on Zulip):

you want to upcast the database m.containing_module(self.db.upcast()).map(|v| v.into()) should work

Jade (Apr 08 2021 at 09:19, on Zulip):

Thanks! Is there anywhere I can read into why that trait is required (for learning reasons)? For some reason putting the &* in the function call itself doesn't do it, so there seems to be some kind of special thing going on here?

Lukas Wirth (Apr 08 2021 at 09:23, on Zulip):

Rust doesn't allow going from one trait object to the traits "super trait object" because vtables arent defined in such a way (yet?) to my knowledge, so this upcast trait is a trick to get that behavior.
I think this is the relevant rfc issue https://github.com/rust-lang/rfcs/issues/2765#issuecomment-257878042

Last update: Jul 28 2021 at 04:00UTC