Repository: rust-analyzer/rust-analyzer
Pull request #7878 (2021-03-05 13:55:36)

Remove `item_scope` field from `Body`
Closes https://github.com/rust-analyzer/rust-analyzer/issues/7632

Instead of storing an `ItemScope` filled with inner items, we store the list of `BlockId`s for all block expressions that are part of a `Body`. Code can then query the `block_def_map` for those.

bors r+

bors[bot]: Build failed:
  * [Rust (ubuntu-latest)](https://github.com/rust-analyzer/rust-analyzer/runs/2040145934)
matklad: Nice!
jonas-schievink: Oh, cool, this also fixes resolving/highlighting references to inner functions from inside inner functions:

```rust
fn outer() {
    fn inner() {
        inner();
    }
}
```
jonas-schievink: It looks like `glorious_old_parser` now gets 2 *fewer* identifiers detected as `SymbolKind::Function`, which seems wrong. Is there any way to debug that?
matklad: dunno, perhaps some other test fails as well?

otherwise, highilighting the parser and diffing the ruslts might point to a problem.
jonas-schievink: Looks like it's the 2 `.to_string()` calls in this inner function:

```rust
        fn tokens_to_string(tokens: &[TokenType]) -> String {
            let mut i = tokens.iter();
            // This might be a sign we need a connect method on Iterator.
            let b = i.next()
                     .map_or(String::new(), |t| t.to_string());
            i.enumerate().fold(b, |mut b, (i, a)| {
                if tokens.len() > 2 && i == tokens.len() - 2 {
                    b.push_str(", or ");
                } else if tokens.len() == 2 && i == tokens.len() - 2 {
                    b.push_str(" or ");
                } else {
                    b.push_str(", ");
                }
                b.push_str(&a.to_string());
                b
            })
        }
```

These *correctly* don't resolve, because the standard library is missing, so there's no `ToString` trait. But there's a trait in that file that also defines a `to_string` method, so presumably that used to be chosen here? Anyways, this looks like spurious behavior, since we're now handling the inner function more correctly.
lnicola: I guess we can take a look at that test after merging this and file a new issue with some smaller test case.
jonas-schievink: Hmm, no, both calls are actually for an inherent method, and it seems to work fine when adding `glorious_old_parser` as a module in `hir_def` (both on master and this branch). Weird.

Patch:
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 638398e292..c6d424c487 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -1157,7 +1157,7 @@ where
 {
     match id.lookup(db.upcast()).container {
         AssocContainerId::TraitId(_) | AssocContainerId::ImplId(_) => Some(ctor(DEF::from(id))),
-        AssocContainerId::ContainerId(_) => None,
+        AssocContainerId::ModuleId(_) => None,
     }
 }
 
@@ -1185,7 +1185,7 @@ impl AssocItem {
         match container {
             AssocContainerId::TraitId(id) => AssocItemContainer::Trait(id.into()),
             AssocContainerId::ImplId(id) => AssocItemContainer::Impl(id.into()),
-            AssocContainerId::ContainerId(_) => panic!("invalid AssocItem"),
+            AssocContainerId::ModuleId(_) => panic!("invalid AssocItem"),
         }
     }
 
diff --git a/crates/hir_def/src/body.rs b/crates/hir_def/src/body.rs
index b1a3fe1cb8..19c4eb521d 100644
--- a/crates/hir_def/src/body.rs
+++ b/crates/hir_def/src/body.rs
@@ -28,11 +28,10 @@ use crate::{
     db::DefDatabase,
     expr::{Expr, ExprId, Label, LabelId, Pat, PatId},
     item_scope::BuiltinShadowMode,
-    item_scope::ItemScope,
     nameres::DefMap,
     path::{ModPath, Path},
     src::HasSource,
-    AsMacroCall, DefWithBodyId, HasModule, LocalModuleId, Lookup, ModuleId,
+    AsMacroCall, BlockId, DefWithBodyId, HasModule, LocalModuleId, Lookup, ModuleId,
 };
 
 /// A subset of Expander that only deals with cfg attributes. We only need it to
@@ -226,7 +225,8 @@ pub struct Body {
     pub params: Vec<PatId>,
     /// The `ExprId` of the actual body expression.
     pub body_expr: ExprId,
-    pub item_scope: ItemScope,
+    /// Block expressions in this body that may contain inner items.
+    pub block_scopes: Vec<BlockId>,
     _c: Count<Self>,
 }
 
@@ -295,7 +295,7 @@ impl Body {
             }
         };
         let expander = Expander::new(db, file_id, module);
-        let (body, source_map) = Body::new(db, def, expander, params, body);
+        let (body, source_map) = Body::new(db, expander, params, body);
         (Arc::new(body), Arc::new(source_map))
     }
 
@@ -305,12 +305,11 @@ impl Body {
 
     fn new(
         db: &dyn DefDatabase,
-        def: DefWithBodyId,
         expander: Expander,
         params: Option<ast::ParamList>,
         body: Option<ast::Expr>,
     ) -> (Body, BodySourceMap) {
-        lower::lower(db, def, expander, params, body)
+        lower::lower(db, expander, params, body)
     }
 }
 
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs
index d4abe819d3..4d79ab72cd 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -1,13 +1,13 @@
 //! Transforms `ast::Expr` into an equivalent `hir_def::expr::Expr`
 //! representation.
 
-use std::{any::type_name, mem, sync::Arc};
+use std::{mem, sync::Arc};
 
 use either::Either;
 use hir_expand::{
     hygiene::Hygiene,
     name::{name, AsName, Name},
-    ExpandError, HirFileId, MacroDefId, MacroDefKind,
+    ExpandError, HirFileId,
 };
 use la_arena::Arena;
 use profile::Count;
@@ -32,11 +32,10 @@ use crate::{
         Statement,
     },
     item_scope::BuiltinShadowMode,
-    item_tree::{ItemTree, ItemTreeId, ItemTreeNode},
+    item_tree::ItemTree,
     path::{GenericArgs, Path},
     type_ref::{Mutability, Rawness, TypeRef},
-    AdtId, BlockLoc, ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern,
-    ModuleDefId, StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc,
+    AdtId, BlockLoc, ModuleDefId,
 };
 
 use super::{diagnostics::BodyDiagnostic, ExprSource, PatSource};
@@ -60,7 +59,6 @@ impl LowerCtx {
 
 pub(super) fn lower(
     db: &dyn DefDatabase,
-    def: DefWithBodyId,
     expander: Expander,
     params: Option<ast::ParamList>,
     body: Option<ast::Expr>,
@@ -68,7 +66,6 @@ pub(super) fn lower(
     let item_tree = db.item_tree(expander.current_file_id);
     ExprCollector {
         db,
-        def,
         source_map: BodySourceMap::default(),
         body: Body {
             exprs: Arena::default(),
@@ -76,7 +73,7 @@ pub(super) fn lower(
             labels: Arena::default(),
             params: Vec::new(),
             body_expr: dummy_expr_id(),
-            item_scope: Default::default(),
+            block_scopes: Vec::new(),
             _c: Count::new(),
         },
         item_trees: {
@@ -91,7 +88,6 @@ pub(super) fn lower(
 
 struct ExprCollector<'a> {
     db: &'a dyn DefDatabase,
-    def: DefWithBodyId,
     expander: Expander,
     body: Body,
     source_map: BodySourceMap,
@@ -605,32 +601,6 @@ impl ExprCollector<'_> {
         }
     }
 
-    fn find_inner_item<N: ItemTreeNode>(&self, ast: &N::Source) -> Option<ItemTreeId<N>> {
-        let id = self.expander.ast_id(ast);
-        let tree = &self.item_trees[&id.file_id];
-
-        // FIXME: This probably breaks with `use` items, since they produce multiple item tree nodes
-
-        // Root file (non-macro).
-        let item_tree_id = tree
-            .all_inner_items()
-            .chain(tree.top_level_items().iter().copied())
-            .filter_map(|mod_item| mod_item.downcast::<N>())
-            .find(|tree_id| tree[*tree_id].ast_id().upcast() == id.value.upcast())
-            .or_else(|| {
-                log::debug!(
-                    "couldn't find inner {} item for {:?} (AST: `{}` - {:?})",
-                    type_name::<N>(),
-                    id,
-                    ast.syntax(),
-                    ast.syntax(),
-                );
-                None
-            })?;
-
-        Some(ItemTreeId::new(id.file_id, item_tree_id))
-    }
-
     fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId {
         if let Some(expr) = expr {
             self.collect_expr(expr)
@@ -662,7 +632,6 @@ impl ExprCollector<'_> {
                             match expansion {
                                 Some(expansion) => {
                                     let statements: ast::MacroStmts = expansion;
-                                    this.collect_stmts_items(statements.statements());
 
                                     statements.statements().for_each(|stmt| {
                                         if let Some(mut r) = this.collect_stmt(stmt) {
@@ -700,6 +669,8 @@ impl ExprCollector<'_> {
         let block_loc =
             BlockLoc { ast_id, module: self.expander.def_map.module_id(self.expander.module) };
         let block_id = self.db.intern_block(block_loc);
+        self.body.block_scopes.push(block_id);
+
         let opt_def_map = self.db.block_def_map(block_id);
         let has_def_map = opt_def_map.is_some();
         let def_map = opt_def_map.unwrap_or_else(|| self.expander.def_map.clone());
@@ -707,7 +678,6 @@ impl ExprCollector<'_> {
         let prev_def_map = mem::replace(&mut self.expander.def_map, def_map);
         let prev_local_module = mem::replace(&mut self.expander.module, module);
 
-        self.collect_stmts_items(block.statements());
         let statements =
             block.statements().filter_map(|s| self.collect_stmt(s)).flatten().collect();
         let tail = block.tail_expr().map(|e| self.collect_expr(e));
@@ -722,108 +692,6 @@ impl ExprCollector<'_> {
         expr_id
     }
 
-    fn collect_stmts_items(&mut self, stmts: ast::AstChildren<ast::Stmt>) {
-        let container = ContainerId::DefWithBodyId(self.def);
-
-        let items = stmts
-            .filter_map(|stmt| match stmt {
-                ast::Stmt::Item(it) => Some(it),
-                ast::Stmt::LetStmt(_) | ast::Stmt::ExprStmt(_) => None,
-            })
-            .filter_map(|item| {
-                let (def, name): (ModuleDefId, Option<ast::Name>) = match item {
-                    ast::Item::Fn(def) => {
-                        let id = self.find_inner_item(&def)?;
-                        (
-                            FunctionLoc { container: container.into(), id }.intern(self.db).into(),
-                            def.name(),
-                        )
-                    }
-                    ast::Item::TypeAlias(def) => {
-                        let id = self.find_inner_item(&def)?;
-                        (
-                            TypeAliasLoc { container: container.into(), id }.intern(self.db).into(),
-                            def.name(),
-                        )
-                    }
-                    ast::Item::Const(def) => {
-                        let id = self.find_inner_item(&def)?;
-                        (
-                            ConstLoc { container: container.into(), id }.intern(self.db).into(),
-                            def.name(),
-                        )
-                    }
-                    ast::Item::Static(def) => {
-                        let id = self.find_inner_item(&def)?;
-                        (StaticLoc { container, id }.intern(self.db).into(), def.name())
-                    }
-                    ast::Item::Struct(def) => {
-                        let id = self.find_inner_item(&def)?;
-                        (StructLoc { container, id }.intern(self.db).into(), def.name())
-                    }
-                    ast::Item::Enum(def) => {
-                        let id = self.find_inner_item(&def)?;
-                        (EnumLoc { container, id }.intern(self.db).into(), def.name())
-                    }
-                    ast::Item::Union(def) => {
-                        let id = self.find_inner_item(&def)?;
-                        (UnionLoc { container, id }.intern(self.db).into(), def.name())
-                    }
-                    ast::Item::Trait(def) => {
-                        let id = self.find_inner_item(&def)?;
-                        (TraitLoc { container, id }.intern(self.db).into(), def.name())
-                    }
-                    ast::Item::ExternBlock(_) => return None, // FIXME: collect from extern blocks
-                    ast::Item::Impl(_)
-                    | ast::Item::Use(_)
-                    | ast::Item::ExternCrate(_)
-                    | ast::Item::Module(_)
-                    | ast::Item::MacroCall(_) => return None,
-                    ast::Item::MacroRules(def) => {
-                        return Some(Either::Right(ast::Macro::from(def)));
-                    }
-                    ast::Item::MacroDef(def) => {
-                        return Some(Either::Right(ast::Macro::from(def)));
-                    }
-                };
-
-                Some(Either::Left((def, name)))
-            })
-            .collect::<Vec<_>>();
-
-        for either in items {
-            match either {
-                Either::Left((def, name)) => {
-                    self.body.item_scope.define_def(def);
-                    if let Some(name) = name {
-                        let vis = crate::visibility::Visibility::Public; // FIXME determine correctly
-                        let has_constructor = match def {
-                            ModuleDefId::AdtId(AdtId::StructId(s)) => {
-                                self.db.struct_data(s).variant_data.kind() != StructKind::Record
-                            }
-                            _ => true,
-                        };
-                        self.body.item_scope.push_res(
-                            name.as_name(),
-                            crate::per_ns::PerNs::from_def(def, vis, has_constructor),
-                        );
-                    }
-                }
-                Either::Right(e) => {
-                    let mac = MacroDefId {
-                        krate: self.expander.def_map.krate(),
-                        ast_id: Some(self.expander.ast_id(&e)),
-                        kind: MacroDefKind::Declarative,
-                        local_inner: false,
-                    };
-                    if let Some(name) = e.name() {
-                        self.body.item_scope.define_legacy_macro(name.as_name(), mac);
-                    }
-                }
-            }
-        }
-    }
-
     fn collect_block_opt(&mut self, expr: Option<ast::BlockExpr>) -> ExprId {
         if let Some(block) = expr {
             self.collect_block(block)
diff --git a/crates/hir_def/src/child_by_source.rs b/crates/hir_def/src/child_by_source.rs
index 75c2d756bf..2a331dcaf9 100644
--- a/crates/hir_def/src/child_by_source.rs
+++ b/crates/hir_def/src/child_by_source.rs
@@ -17,13 +17,16 @@ use crate::{
 };
 
 pub trait ChildBySource {
-    fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap;
-}
-
-impl ChildBySource for TraitId {
     fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap {
         let mut res = DynMap::default();
+        self.child_by_source_to(db, &mut res);
+        res
+    }
+    fn child_by_source_to(&self, db: &dyn DefDatabase, map: &mut DynMap);
+}
 
+impl ChildBySource for TraitId {
+    fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap) {
         let data = db.trait_data(*self);
         for (_name, item) in data.items.iter() {
             match *item {
@@ -41,15 +44,11 @@ impl ChildBySource for TraitId {
                 }
             }
         }
-
-        res
     }
 }
 
 impl ChildBySource for ImplId {
-    fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap {
-        let mut res = DynMap::default();
-
+    fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap) {
         let data = db.impl_data(*self);
         for &item in data.items.iter() {
             match item {
@@ -67,25 +66,21 @@ impl ChildBySource for ImplId {
                 }
             }
         }
-
-        res
     }
 }
 
 impl ChildBySource for ModuleId {
-    fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap {
+    fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap) {
         let def_map = self.def_map(db);
         let module_data = &def_map[self.local_id];
-        module_data.scope.child_by_source(db)
+        module_data.scope.child_by_source_to(db, res);
     }
 }
 
 impl ChildBySource for ItemScope {
-    fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap {
-        let mut res = DynMap::default();
-        self.declarations().for_each(|item| add_module_def(db, &mut res, item));
-        self.impls().for_each(|imp| add_impl(db, &mut res, imp));
-        return res;
+    fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap) {
+        self.declarations().for_each(|item| add_module_def(db, res, item));
+        self.impls().for_each(|imp| add_impl(db, res, imp));
 
         fn add_module_def(db: &dyn DefDatabase, map: &mut DynMap, item: ModuleDefId) {
             match item {
@@ -134,9 +129,7 @@ impl ChildBySource for ItemScope {
 }
 
 impl ChildBySource for VariantId {
-    fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap {
-        let mut res = DynMap::default();
-
+    fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap) {
         let arena_map = self.child_source(db);
         let arena_map = arena_map.as_ref();
         for (local_id, source) in arena_map.value.iter() {
@@ -150,28 +143,27 @@ impl ChildBySource for VariantId {
                 }
             }
         }
-        res
     }
 }
 
 impl ChildBySource for EnumId {
-    fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap {
-        let mut res = DynMap::default();
-
+    fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap) {
         let arena_map = self.child_source(db);
         let arena_map = arena_map.as_ref();
         for (local_id, source) in arena_map.value.iter() {
             let id = EnumVariantId { parent: *self, local_id };
             res[keys::VARIANT].insert(arena_map.with_value(source.clone()), id)
         }
-
-        res
     }
 }
 
 impl ChildBySource for DefWithBodyId {
-    fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap {
+    fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap) {
         let body = db.body(*self);
-        body.item_scope.child_by_source(db)
+        for def_map in body.block_scopes.iter().filter_map(|block| db.block_def_map(*block)) {
+            // All block expressions are merged into the same map, because they logically all add
+            // inner items to the containing `DefWithBodyId`.
+            def_map[def_map.root()].scope.child_by_source_to(db, res);
+        }
     }
 }
diff --git a/crates/hir_def/src/generics.rs b/crates/hir_def/src/generics.rs
index 3ace3be1fa..a056ab797e 100644
--- a/crates/hir_def/src/generics.rs
+++ b/crates/hir_def/src/generics.rs
@@ -421,8 +421,7 @@ impl HasChildSource<LocalConstParamId> for GenericDefId {
 }
 
 impl ChildBySource for GenericDefId {
-    fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap {
-        let mut res = DynMap::default();
+    fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap) {
         let (_, sm) = GenericParams::new(db, *self);
 
         let sm = sm.as_ref();
@@ -440,6 +439,5 @@ impl ChildBySource for GenericDefId {
             let id = ConstParamId { parent: *self, local_id };
             res[keys::CONST_PARAM].insert(sm.with_value(src.clone()), id);
         }
-        res
     }
 }
diff --git a/crates/hir_def/src/item_scope.rs b/crates/hir_def/src/item_scope.rs
index 9199338139..aafd73b606 100644
--- a/crates/hir_def/src/item_scope.rs
+++ b/crates/hir_def/src/item_scope.rs
@@ -168,37 +168,6 @@ impl ItemScope {
         self.unnamed_trait_imports.insert(tr, vis);
     }
 
-    pub(crate) fn push_res(&mut self, name: Name, def: PerNs) -> bool {
-        let mut changed = false;
-
-        if let Some(types) = def.types {
-            self.types.entry(name.clone()).or_insert_with(|| {
-                changed = true;
-                types
-            });
-        }
-        if let Some(values) = def.values {
-            self.values.entry(name.clone()).or_insert_with(|| {
-                changed = true;
-                values
-            });
-        }
-        if let Some(macros) = def.macros {
-            self.macros.entry(name.clone()).or_insert_with(|| {
-                changed = true;
-                macros
-            });
-        }
-
-        if def.is_none() {
-            if self.unresolved.insert(name) {
-                changed = true;
-            }
-        }
-
-        changed
-    }
-
     pub(crate) fn push_res_with_import(
         &mut self,
         glob_imports: &mut PerNsGlobImports,
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs
index 4498d94bb2..ab3b17f6cd 100644
--- a/crates/hir_def/src/lib.rs
+++ b/crates/hir_def/src/lib.rs
@@ -286,11 +286,11 @@ pub enum ContainerId {
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub enum AssocContainerId {
-    ContainerId(ContainerId),
+    ModuleId(ModuleId),
     ImplId(ImplId),
     TraitId(TraitId),
 }
-impl_from!(ContainerId for AssocContainerId);
+impl_from!(ModuleId for AssocContainerId);
 
 /// A Data Type
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
@@ -459,7 +459,7 @@ impl HasModule for ContainerId {
 impl HasModule for AssocContainerId {
     fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
         match *self {
-            AssocContainerId::ContainerId(it) => it.module(db),
+            AssocContainerId::ModuleId(it) => it,
             AssocContainerId::ImplId(it) => it.lookup(db).container.module(db),
             AssocContainerId::TraitId(it) => it.lookup(db).container.module(db),
         }
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index 3bb69d935f..5bf2ba721b 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -1121,7 +1121,7 @@ impl ModCollector<'_, '_> {
 
                     def = Some(DefData {
                         id: FunctionLoc {
-                            container: container.into(),
+                            container: module.into(),
                             id: ItemTreeId::new(self.file_id, id),
                         }
                         .intern(self.def_collector.db)
@@ -1188,7 +1188,7 @@ impl ModCollector<'_, '_> {
                     if let Some(name) = &it.name {
                         def = Some(DefData {
                             id: ConstLoc {
-                                container: container.into(),
+                                container: module.into(),
                                 id: ItemTreeId::new(self.file_id, id),
                             }
                             .intern(self.def_collector.db)
@@ -1228,7 +1228,7 @@ impl ModCollector<'_, '_> {
 
                     def = Some(DefData {
                         id: TypeAliasLoc {
-                            container: container.into(),
+                            container: module.into(),
                             id: ItemTreeId::new(self.file_id, id),
                         }
                         .intern(self.def_collector.db)
diff --git a/crates/hir_def/src/resolver.rs b/crates/hir_def/src/resolver.rs
index 77ff21739d..6f036c8c42 100644
--- a/crates/hir_def/src/resolver.rs
+++ b/crates/hir_def/src/resolver.rs
@@ -342,6 +342,16 @@ impl Resolver {
                     traits.extend(prelude_def_map[prelude.local_id].scope.traits());
                 }
                 traits.extend(m.def_map[m.module_id].scope.traits());
+
+                // Add all traits that are in scope because of the containing DefMaps
+                m.def_map.with_ancestor_maps(db, m.module_id, &mut |def_map, module| {
+                    if let Some(prelude) = def_map.prelude() {
+                        let prelude_def_map = prelude.def_map(db);
+                        traits.extend(prelude_def_map[prelude.local_id].scope.traits());
+                    }
+                    traits.extend(def_map[module].scope.traits());
+                    None::<()>
+                });
             }
         }
         traits
@@ -690,7 +700,7 @@ impl HasResolver for ContainerId {
 impl HasResolver for AssocContainerId {
     fn resolver(self, db: &dyn DefDatabase) -> Resolver {
         match self {
-            AssocContainerId::ContainerId(it) => it.resolver(db),
+            AssocContainerId::ModuleId(it) => it.resolver(db),
             AssocContainerId::TraitId(it) => it.resolver(db),
             AssocContainerId::ImplId(it) => it.resolver(db),
         }
diff --git a/crates/hir_ty/src/diagnostics/decl_check.rs b/crates/hir_ty/src/diagnostics/decl_check.rs
index e230f97656..3605ca5816 100644
--- a/crates/hir_ty/src/diagnostics/decl_check.rs
+++ b/crates/hir_ty/src/diagnostics/decl_check.rs
@@ -99,9 +99,14 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
         let body = self.db.body(func.into());
 
         // Recursively validate inner scope items, such as static variables and constants.
-        for (item_id, _) in body.item_scope.values() {
-            let mut validator = DeclValidator::new(self.db, self.krate, self.sink);
-            validator.validate_item(item_id);
+        let db = self.db;
+        for block_def_map in body.block_scopes.iter().filter_map(|block| db.block_def_map(*block)) {
+            for (_, module) in block_def_map.modules() {
+                for (def_id, _) in module.scope.values() {
+                    let mut validator = DeclValidator::new(self.db, self.krate, self.sink);
+                    validator.validate_item(def_id);
+                }
+            }
         }
 
         // Check whether non-snake case identifiers are allowed for this function.
diff --git a/crates/hir_ty/src/infer/path.rs b/crates/hir_ty/src/infer/path.rs
index 5d541104e2..ae3554bac8 100644
--- a/crates/hir_ty/src/infer/path.rs
+++ b/crates/hir_ty/src/infer/path.rs
@@ -260,7 +260,7 @@ impl<'a> InferenceContext<'a> {
                         }));
                         Some(trait_substs)
                     }
-                    AssocContainerId::ContainerId(_) => None,
+                    AssocContainerId::ModuleId(_) => None,
                 };
 
                 self.write_assoc_resolution(id, item);
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs
index 24db33c491..2483672674 100644
--- a/crates/hir_ty/src/method_resolution.rs
+++ b/crates/hir_ty/src/method_resolution.rs
@@ -715,7 +715,7 @@ fn transform_receiver_ty(
                 .fill_with_unknown()
                 .build()
         }
-        AssocContainerId::ContainerId(_) => unreachable!(),
+        AssocContainerId::ModuleId(_) => unreachable!(),
     };
     let sig = db.callable_item_signature(function_id.into());
     Some(sig.value.params()[0].clone().subst_bound_vars(&substs))
diff --git a/crates/hir_ty/src/utils.rs b/crates/hir_ty/src/utils.rs
index 65b79df0d5..7351e4e54a 100644
--- a/crates/hir_ty/src/utils.rs
+++ b/crates/hir_ty/src/utils.rs
@@ -259,6 +259,6 @@ fn parent_generic_def(db: &dyn DefDatabase, def: GenericDefId) -> Option<Generic
     match container {
         AssocContainerId::ImplId(it) => Some(it.into()),
         AssocContainerId::TraitId(it) => Some(it.into()),
-        AssocContainerId::ContainerId(_) => None,
+        AssocContainerId::ModuleId(_) => None,
     }
 }


Test patch:
diff --git a/crates/hir_ty/src/tests.rs b/crates/hir_ty/src/tests.rs
index 7386a4e7ba..fc770ea600 100644
--- a/crates/hir_ty/src/tests.rs
+++ b/crates/hir_ty/src/tests.rs
@@ -13,7 +13,7 @@ use std::{env, sync::Arc};
 use base_db::{fixture::WithFixture, FileRange, SourceDatabase, SourceDatabaseExt};
 use expect_test::Expect;
 use hir_def::{
-    body::{BodySourceMap, SyntheticSyntax},
+    body::{Body, BodySourceMap, SyntheticSyntax},
     child_by_source::ChildBySource,
     db::DefDatabase,
     item_scope::ItemScope,
@@ -234,13 +234,13 @@ fn visit_module(
                     let def = it.into();
                     cb(def);
                     let body = db.body(def);
-                    visit_scope(db, crate_def_map, &body.item_scope, cb);
+                    visit_body(db, &body, cb);
                 }
                 AssocItemId::ConstId(it) => {
                     let def = it.into();
                     cb(def);
                     let body = db.body(def);
-                    visit_scope(db, crate_def_map, &body.item_scope, cb);
+                    visit_body(db, &body, cb);
                 }
                 AssocItemId::TypeAliasId(_) => (),
             }
@@ -259,19 +259,19 @@ fn visit_module(
                     let def = it.into();
                     cb(def);
                     let body = db.body(def);
-                    visit_scope(db, crate_def_map, &body.item_scope, cb);
+                    visit_body(db, &body, cb);
                 }
                 ModuleDefId::ConstId(it) => {
                     let def = it.into();
                     cb(def);
                     let body = db.body(def);
-                    visit_scope(db, crate_def_map, &body.item_scope, cb);
+                    visit_body(db, &body, cb);
                 }
                 ModuleDefId::StaticId(it) => {
                     let def = it.into();
                     cb(def);
                     let body = db.body(def);
-                    visit_scope(db, crate_def_map, &body.item_scope, cb);
+                    visit_body(db, &body, cb);
                 }
                 ModuleDefId::TraitId(it) => {
                     let trait_data = db.trait_data(it);
@@ -288,6 +288,14 @@ fn visit_module(
             }
         }
     }
+
+    fn visit_body(db: &TestDB, body: &Body, cb: &mut dyn FnMut(DefWithBodyId)) {
+        for def_map in body.block_scopes.iter().filter_map(|block| db.block_def_map(*block)) {
+            for (mod_id, _) in def_map.modules() {
+                visit_module(db, &def_map, mod_id, cb);
+            }
+        }
+    }
 }
 
 fn ellipsize(mut text: String, max_len: usize) -> String {
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs
index 5280920825..e185b1c0a1 100644
--- a/crates/hir_ty/src/tests/traits.rs
+++ b/crates/hir_ty/src/tests/traits.rs
@@ -3173,6 +3173,39 @@ fn f() {
     );
 }
 
+#[test]
+fn trait_in_scope_with_inner_item() {
+    check_infer(
+        r#"
+mod m {
+    pub trait Tr {
+        fn method(&self) -> u8 { 0 }
+    }
+
+    impl Tr for () {}
+}
+
+use m::Tr;
+
+fn f() {
+    fn inner() {
+        ().method();
+      //^^^^^^^^^^^ u8
+    }
+}
+        "#,
+        expect![[r#"
+            46..50 'self': &Self
+            58..63 '{ 0 }': u8
+            60..61 '0': u8
+            115..185 '{     ...   } }': ()
+            132..183 '{     ...     }': ()
+            142..144 '()': ()
+            142..153 '().method()': u8
+        "#]],
+    );
+}
+
 #[test]
 fn inner_use_in_block() {
     check_types(