diff --git a/crates/ra_hir_def/src/item_tree/lower.rs b/crates/ra_hir_def/src/item_tree/lower.rs index 6e31266a2c..f10ad25f70 100644 --- a/crates/ra_hir_def/src/item_tree/lower.rs +++ b/crates/ra_hir_def/src/item_tree/lower.rs @@ -82,7 +82,13 @@ impl Ctx { | ast::ModuleItem::TypeAliasDef(_) | ast::ModuleItem::ConstDef(_) | ast::ModuleItem::StaticDef(_) - | ast::ModuleItem::MacroCall(_) => self.collect_inner_items(item.syntax()), + | ast::ModuleItem::MacroCall(_) => { + // Skip this if we're already collecting inner items. We'll descend into all nodes + // already. + if !inner { + self.collect_inner_items(item.syntax()); + } + } // These are handled in their respective `lower_X` method (since we can't just blindly // walk them). @@ -403,7 +409,8 @@ impl Ctx { fn lower_trait(&mut self, trait_def: &ast::TraitDef) -> Option> { let name = trait_def.name()?.as_name(); let visibility = self.lower_visibility(trait_def); - let generic_params = self.lower_generic_params(GenericsOwner::Trait(trait_def), trait_def); + let generic_params = + self.lower_generic_params_and_inner_items(GenericsOwner::Trait(trait_def), trait_def); let auto = trait_def.auto_token().is_some(); let items = trait_def.item_list().map(|list| { self.with_inherited_visibility(visibility, |this| { @@ -432,7 +439,8 @@ impl Ctx { } fn lower_impl(&mut self, impl_def: &ast::ImplDef) -> Option> { - let generic_params = self.lower_generic_params(GenericsOwner::Impl, impl_def); + let generic_params = + self.lower_generic_params_and_inner_items(GenericsOwner::Impl, impl_def); let target_trait = impl_def.target_trait().map(|tr| self.lower_type_ref(&tr)); let target_type = self.lower_type_ref(&impl_def.target_type()?); let is_negative = impl_def.excl_token().is_some(); @@ -548,6 +556,23 @@ impl Ctx { }) } + /// Lowers generics defined on `node` and collects inner items defined within. + fn lower_generic_params_and_inner_items( + &mut self, + owner: GenericsOwner<'_>, + node: &impl ast::TypeParamsOwner, + ) -> GenericParamsId { + // Generics are part of item headers and may contain inner items we need to collect. + if let Some(params) = node.type_param_list() { + self.collect_inner_items(params.syntax()); + } + if let Some(clause) = node.where_clause() { + self.collect_inner_items(clause.syntax()); + } + + self.lower_generic_params(owner, node) + } + fn lower_generic_params( &mut self, owner: GenericsOwner<'_>, @@ -617,7 +642,7 @@ impl Ctx { TypeRef::from_ast(&self.body_ctx, type_ref.clone()) } fn lower_type_ref_opt(&self, type_ref: Option) -> TypeRef { - TypeRef::from_ast_opt(&self.body_ctx, type_ref) + type_ref.map(|ty| self.lower_type_ref(&ty)).unwrap_or(TypeRef::Error) } /// Forces the visibility `vis` to be used for all items lowered during execution of `f`. diff --git a/crates/ra_hir_def/src/item_tree/tests.rs b/crates/ra_hir_def/src/item_tree/tests.rs index cd4c8a1996..dc035d809e 100644 --- a/crates/ra_hir_def/src/item_tree/tests.rs +++ b/crates/ra_hir_def/src/item_tree/tests.rs @@ -374,11 +374,17 @@ fn cursed_inner_items() { impl En { fn assoc() { - trait InnerTrait {} - struct InnerStruct {} - impl InnerTrait for InnerStruct {} + trait InnerTrait {} + struct InnerStruct {} + impl InnerTrait for InnerStruct {} } } + + trait Tr { + type AssocTy = [u8; { fn f() {} }]; + + const AssocConst: [u8; { fn f() {} }]; + } ", ); }