about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--crates/hir-def/src/nameres.rs4
-rw-r--r--crates/hir-def/src/visibility.rs28
-rw-r--r--crates/ide-diagnostics/src/handlers/private_field.rs20
3 files changed, 37 insertions, 15 deletions
diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs
index a7ce0360516..59b52c3caa3 100644
--- a/crates/hir-def/src/nameres.rs
+++ b/crates/hir-def/src/nameres.rs
@@ -215,7 +215,7 @@ pub struct ModuleData {
     pub origin: ModuleOrigin,
     /// Declared visibility of this module.
     pub visibility: Visibility,
-
+    /// Always [`None`] for block modules
     pub parent: Option<LocalModuleId>,
     pub children: FxHashMap<Name, LocalModuleId>,
     pub scope: ItemScope,
@@ -429,7 +429,7 @@ impl DefMap {
         Some(self.block?.parent)
     }
 
-    /// Returns the module containing `local_mod`, either the parent `mod`, or the module containing
+    /// Returns the module containing `local_mod`, either the parent `mod`, or the module (or block) containing
     /// the block, if `self` corresponds to a block expression.
     pub fn containing_module(&self, local_mod: LocalModuleId) -> Option<ModuleId> {
         match self[local_mod].parent {
diff --git a/crates/hir-def/src/visibility.rs b/crates/hir-def/src/visibility.rs
index c9fcaae56cf..ab76ed43d3a 100644
--- a/crates/hir-def/src/visibility.rs
+++ b/crates/hir-def/src/visibility.rs
@@ -131,21 +131,23 @@ impl Visibility {
         // visibility as the containing module (even though no items are directly nameable from
         // there, getting this right is important for method resolution).
         // In that case, we adjust the visibility of `to_module` to point to the containing module.
+
         // Additional complication: `to_module` might be in `from_module`'s `DefMap`, which we're
         // currently computing, so we must not call the `def_map` query for it.
-        let arc;
-        let to_module_def_map =
-            if to_module.krate == def_map.krate() && to_module.block == def_map.block_id() {
-                cov_mark::hit!(is_visible_from_same_block_def_map);
-                def_map
-            } else {
-                arc = to_module.def_map(db);
-                &arc
-            };
-        let is_block_root =
-            to_module.block.is_some() && to_module_def_map[to_module.local_id].parent.is_none();
-        if is_block_root {
-            to_module = to_module_def_map.containing_module(to_module.local_id).unwrap();
+        let mut arc;
+        loop {
+            let to_module_def_map =
+                if to_module.krate == def_map.krate() && to_module.block == def_map.block_id() {
+                    cov_mark::hit!(is_visible_from_same_block_def_map);
+                    def_map
+                } else {
+                    arc = to_module.def_map(db);
+                    &arc
+                };
+            match to_module_def_map.parent() {
+                Some(parent) => to_module = parent,
+                None => break,
+            }
         }
 
         // from_module needs to be a descendant of to_module
diff --git a/crates/ide-diagnostics/src/handlers/private_field.rs b/crates/ide-diagnostics/src/handlers/private_field.rs
index e630ae36866..be83ad6aaad 100644
--- a/crates/ide-diagnostics/src/handlers/private_field.rs
+++ b/crates/ide-diagnostics/src/handlers/private_field.rs
@@ -65,4 +65,24 @@ fn main(s: module::Struct) {
 "#,
         );
     }
+
+    #[test]
+    fn block_module_madness() {
+        check_diagnostics(
+            r#"
+fn main() {
+    let strukt = {
+        use crate as ForceParentBlockDefMap;
+        {
+            pub struct Struct {
+                field: (),
+            }
+            Struct { field: () }
+        }
+    };
+    strukt.field;
+}
+"#,
+        );
+    }
 }