Skip to content

Commit 32424d0

Browse files
committed
Auto merge of rust-lang#14176 - lowr:fix/assoc-func-vis-in-local-impl, r=Veykril
Fix associated item visibility in block-local impls Fixes rust-lang#14046 When we're resolving visibility of block-local items... > `self` normally refers to the containing non-block module, and `super` to its parent (etc.). However, visibilities must only refer to a module in the DefMap they're written in, so we restrict them when that happens. ([link]) ...unless we're resolving visibility of associated items in block-local impls, because that impl is semantically "hoisted" to the nearest (non-block) module. With this PR, we skip the adjustment for such items. Since visibility representation of those items is modified, this PR also adjusts visibility rendering in `HirDisplay`. [link]: https://github.com/rust-lang/rust-analyzer/blob/a6603fc21d50b3386a488c96225b2d1fd492e533/crates/hir-def/src/nameres/path_resolution.rs#L101-L103
2 parents ef9d5db + d416623 commit 32424d0

File tree

10 files changed

+282
-30
lines changed

10 files changed

+282
-30
lines changed

crates/hir-def/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ impl ModuleId {
128128
}
129129
}
130130

131-
/// An ID of a module, **local** to a specific crate
131+
/// An ID of a module, **local** to a `DefMap`.
132132
pub type LocalModuleId = Idx<nameres::ModuleData>;
133133

134134
#[derive(Debug)]

crates/hir-def/src/nameres.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ impl DefMap {
342342
}
343343

344344
pub(crate) fn block_id(&self) -> Option<BlockId> {
345-
self.block.as_ref().map(|block| block.block)
345+
self.block.map(|block| block.block)
346346
}
347347

348348
pub(crate) fn prelude(&self) -> Option<ModuleId> {
@@ -354,7 +354,7 @@ impl DefMap {
354354
}
355355

356356
pub fn module_id(&self, local_id: LocalModuleId) -> ModuleId {
357-
let block = self.block.as_ref().map(|b| b.block);
357+
let block = self.block.map(|b| b.block);
358358
ModuleId { krate: self.krate, local_id, block }
359359
}
360360

@@ -432,9 +432,9 @@ impl DefMap {
432432
/// Returns the module containing `local_mod`, either the parent `mod`, or the module containing
433433
/// the block, if `self` corresponds to a block expression.
434434
pub fn containing_module(&self, local_mod: LocalModuleId) -> Option<ModuleId> {
435-
match &self[local_mod].parent {
436-
Some(parent) => Some(self.module_id(*parent)),
437-
None => self.block.as_ref().map(|block| block.parent),
435+
match self[local_mod].parent {
436+
Some(parent) => Some(self.module_id(parent)),
437+
None => self.block.map(|block| block.parent),
438438
}
439439
}
440440

@@ -444,11 +444,11 @@ impl DefMap {
444444
let mut buf = String::new();
445445
let mut arc;
446446
let mut current_map = self;
447-
while let Some(block) = &current_map.block {
447+
while let Some(block) = current_map.block {
448448
go(&mut buf, current_map, "block scope", current_map.root);
449449
buf.push('\n');
450450
arc = block.parent.def_map(db);
451-
current_map = &*arc;
451+
current_map = &arc;
452452
}
453453
go(&mut buf, current_map, "crate", current_map.root);
454454
return buf;
@@ -472,10 +472,10 @@ impl DefMap {
472472
let mut buf = String::new();
473473
let mut arc;
474474
let mut current_map = self;
475-
while let Some(block) = &current_map.block {
475+
while let Some(block) = current_map.block {
476476
format_to!(buf, "{:?} in {:?}\n", block.block, block.parent);
477477
arc = block.parent.def_map(db);
478-
current_map = &*arc;
478+
current_map = &arc;
479479
}
480480

481481
format_to!(buf, "crate scope\n");

crates/hir-def/src/nameres/collector.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -666,8 +666,10 @@ impl DefCollector<'_> {
666666
macro_: Macro2Id,
667667
vis: &RawVisibility,
668668
) {
669-
let vis =
670-
self.def_map.resolve_visibility(self.db, module_id, vis).unwrap_or(Visibility::Public);
669+
let vis = self
670+
.def_map
671+
.resolve_visibility(self.db, module_id, vis, false)
672+
.unwrap_or(Visibility::Public);
671673
self.def_map.modules[module_id].scope.declare(macro_.into());
672674
self.update(
673675
module_id,
@@ -831,7 +833,7 @@ impl DefCollector<'_> {
831833
let mut def = directive.status.namespaces();
832834
let vis = self
833835
.def_map
834-
.resolve_visibility(self.db, module_id, &directive.import.visibility)
836+
.resolve_visibility(self.db, module_id, &directive.import.visibility, false)
835837
.unwrap_or(Visibility::Public);
836838

837839
match import.kind {
@@ -1547,7 +1549,7 @@ impl ModCollector<'_, '_> {
15471549
};
15481550
let resolve_vis = |def_map: &DefMap, visibility| {
15491551
def_map
1550-
.resolve_visibility(db, self.module_id, visibility)
1552+
.resolve_visibility(db, self.module_id, visibility, false)
15511553
.unwrap_or(Visibility::Public)
15521554
};
15531555

@@ -1823,7 +1825,7 @@ impl ModCollector<'_, '_> {
18231825
) -> LocalModuleId {
18241826
let def_map = &mut self.def_collector.def_map;
18251827
let vis = def_map
1826-
.resolve_visibility(self.def_collector.db, self.module_id, visibility)
1828+
.resolve_visibility(self.def_collector.db, self.module_id, visibility, false)
18271829
.unwrap_or(Visibility::Public);
18281830
let modules = &mut def_map.modules;
18291831
let origin = match definition {

crates/hir-def/src/nameres/path_resolution.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ impl DefMap {
7878
// pub(path)
7979
// ^^^^ this
8080
visibility: &RawVisibility,
81+
within_impl: bool,
8182
) -> Option<Visibility> {
8283
let mut vis = match visibility {
8384
RawVisibility::Module(path) => {
@@ -102,7 +103,8 @@ impl DefMap {
102103
// `super` to its parent (etc.). However, visibilities must only refer to a module in the
103104
// DefMap they're written in, so we restrict them when that happens.
104105
if let Visibility::Module(m) = vis {
105-
if self.block_id() != m.block {
106+
// ...unless we're resolving visibility for an associated item in an impl.
107+
if self.block_id() != m.block && !within_impl {
106108
cov_mark::hit!(adjust_vis_in_block_def_map);
107109
vis = Visibility::Module(self.module_id(self.root()));
108110
tracing::debug!("visibility {:?} points outside DefMap, adjusting to {:?}", m, vis);

crates/hir-def/src/resolver.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,10 +214,12 @@ impl Resolver {
214214
db: &dyn DefDatabase,
215215
visibility: &RawVisibility,
216216
) -> Option<Visibility> {
217+
let within_impl =
218+
self.scopes().find(|scope| matches!(scope, Scope::ImplDefScope(_))).is_some();
217219
match visibility {
218220
RawVisibility::Module(_) => {
219221
let (item_map, module) = self.item_scope();
220-
item_map.resolve_visibility(db, module, visibility)
222+
item_map.resolve_visibility(db, module, visibility, within_impl)
221223
}
222224
RawVisibility::Public => Some(Visibility::Public),
223225
}

crates/hir-def/src/visibility.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::{
1111
nameres::DefMap,
1212
path::{ModPath, PathKind},
1313
resolver::HasResolver,
14-
ConstId, FunctionId, HasModule, LocalFieldId, ModuleId, VariantId,
14+
ConstId, FunctionId, HasModule, LocalFieldId, LocalModuleId, ModuleId, VariantId,
1515
};
1616

1717
/// Visibility of an item, not yet resolved.
@@ -120,7 +120,7 @@ impl Visibility {
120120
self,
121121
db: &dyn DefDatabase,
122122
def_map: &DefMap,
123-
mut from_module: crate::LocalModuleId,
123+
mut from_module: LocalModuleId,
124124
) -> bool {
125125
let mut to_module = match self {
126126
Visibility::Module(m) => m,
@@ -142,7 +142,8 @@ impl Visibility {
142142
arc = to_module.def_map(db);
143143
&arc
144144
};
145-
let is_block_root = matches!(to_module.block, Some(_) if to_module_def_map[to_module.local_id].parent.is_none());
145+
let is_block_root =
146+
to_module.block.is_some() && to_module_def_map[to_module.local_id].parent.is_none();
146147
if is_block_root {
147148
to_module = to_module_def_map.containing_module(to_module.local_id).unwrap();
148149
}

crates/hir/src/display.rs

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,23 @@ use hir_ty::{
1717
};
1818

1919
use crate::{
20-
Adt, Const, ConstParam, Enum, Field, Function, GenericParam, HasCrate, HasVisibility,
21-
LifetimeParam, Macro, Module, Static, Struct, Trait, TyBuilder, Type, TypeAlias,
22-
TypeOrConstParam, TypeParam, Union, Variant,
20+
Adt, AsAssocItem, AssocItemContainer, Const, ConstParam, Enum, Field, Function, GenericParam,
21+
HasCrate, HasVisibility, LifetimeParam, Macro, Module, Static, Struct, Trait, TyBuilder, Type,
22+
TypeAlias, TypeOrConstParam, TypeParam, Union, Variant,
2323
};
2424

2525
impl HirDisplay for Function {
2626
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
27-
let data = f.db.function_data(self.id);
28-
write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
27+
let db = f.db;
28+
let data = db.function_data(self.id);
29+
let container = self.as_assoc_item(db).map(|it| it.container(db));
30+
let mut module = self.module(db);
31+
if let Some(AssocItemContainer::Impl(_)) = container {
32+
// Block-local impls are "hoisted" to the nearest (non-block) module.
33+
module = module.nearest_non_block_module(db);
34+
}
35+
let module_id = module.id;
36+
write_visibility(module_id, self.visibility(db), f)?;
2937
if data.has_default_kw() {
3038
f.write_str("default ")?;
3139
}
@@ -35,7 +43,7 @@ impl HirDisplay for Function {
3543
if data.has_async_kw() {
3644
f.write_str("async ")?;
3745
}
38-
if self.is_unsafe_to_call(f.db) {
46+
if self.is_unsafe_to_call(db) {
3947
f.write_str("unsafe ")?;
4048
}
4149
if let Some(abi) = &data.abi {
@@ -50,7 +58,7 @@ impl HirDisplay for Function {
5058

5159
let write_self_param = |ty: &TypeRef, f: &mut HirFormatter<'_>| match ty {
5260
TypeRef::Path(p) if p.is_self_type() => f.write_str("self"),
53-
TypeRef::Reference(inner, lifetime, mut_) if matches!(&**inner,TypeRef::Path(p) if p.is_self_type()) =>
61+
TypeRef::Reference(inner, lifetime, mut_) if matches!(&**inner, TypeRef::Path(p) if p.is_self_type()) =>
5462
{
5563
f.write_char('&')?;
5664
if let Some(lifetime) = lifetime {
@@ -442,8 +450,15 @@ fn write_where_clause(def: GenericDefId, f: &mut HirFormatter<'_>) -> Result<(),
442450

443451
impl HirDisplay for Const {
444452
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
445-
write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
446-
let data = f.db.const_data(self.id);
453+
let db = f.db;
454+
let container = self.as_assoc_item(db).map(|it| it.container(db));
455+
let mut module = self.module(db);
456+
if let Some(AssocItemContainer::Impl(_)) = container {
457+
// Block-local impls are "hoisted" to the nearest (non-block) module.
458+
module = module.nearest_non_block_module(db);
459+
}
460+
write_visibility(module.id, self.visibility(db), f)?;
461+
let data = db.const_data(self.id);
447462
f.write_str("const ")?;
448463
match &data.name {
449464
Some(name) => write!(f, "{name}: ")?,

crates/hir/src/lib.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ use hir_def::{
4646
item_tree::ItemTreeNode,
4747
lang_item::{LangItem, LangItemTarget},
4848
layout::{Layout, LayoutError, ReprOptions},
49-
nameres::{self, diagnostics::DefDiagnostic},
49+
nameres::{self, diagnostics::DefDiagnostic, ModuleOrigin},
5050
per_ns::PerNs,
5151
resolver::{HasResolver, Resolver},
5252
src::HasSource as _,
@@ -488,6 +488,20 @@ impl Module {
488488
Some(Module { id: def_map.module_id(parent_id) })
489489
}
490490

491+
/// Finds nearest non-block ancestor `Module` (`self` included).
492+
fn nearest_non_block_module(self, db: &dyn HirDatabase) -> Module {
493+
let mut id = self.id;
494+
loop {
495+
let def_map = id.def_map(db.upcast());
496+
let origin = def_map[id.local_id].origin;
497+
if matches!(origin, ModuleOrigin::BlockExpr { .. }) {
498+
id = id.containing_module(db.upcast()).expect("block without parent module")
499+
} else {
500+
return Module { id };
501+
}
502+
}
503+
}
504+
491505
pub fn path_to_root(self, db: &dyn HirDatabase) -> Vec<Module> {
492506
let mut res = vec![self];
493507
let mut curr = self;

crates/ide-diagnostics/src/handlers/private_assoc_item.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,44 @@ mod module {
115115
fn main(s: module::Struct) {
116116
s.method();
117117
}
118+
"#,
119+
);
120+
}
121+
122+
#[test]
123+
fn can_see_through_top_level_anonymous_const() {
124+
// regression test for #14046.
125+
check_diagnostics(
126+
r#"
127+
struct S;
128+
mod m {
129+
const _: () = {
130+
impl crate::S {
131+
pub(crate) fn method(self) {}
132+
pub(crate) const A: usize = 42;
133+
}
134+
};
135+
mod inner {
136+
const _: () = {
137+
impl crate::S {
138+
pub(crate) fn method2(self) {}
139+
pub(crate) const B: usize = 42;
140+
pub(super) fn private(self) {}
141+
pub(super) const PRIVATE: usize = 42;
142+
}
143+
};
144+
}
145+
}
146+
fn main() {
147+
S.method();
148+
S::A;
149+
S.method2();
150+
S::B;
151+
S.private();
152+
//^^^^^^^^^^^ error: function `private` is private
153+
S::PRIVATE;
154+
//^^^^^^^^^^ error: const `PRIVATE` is private
155+
}
118156
"#,
119157
);
120158
}

0 commit comments

Comments
 (0)