Skip to content

Commit 0cbcbb0

Browse files
committed
Auto merge of #17715 - Throne3d:fix/glob-may-override-vis-2, r=Veykril
fix: let glob imports override other globs' visibility Follow up to #14930 Fixes #11858 Fixes #14902 Fixes #17704 I haven't reworked the code here at all - I don't feel confident in the codebase to do so - just rebased it onto the current main branch and fixed conflicts. I'm not _entirely_ sure I understand the structure of the `check` function in `crates/hir-def/src/nameres` tests. I think the change to the test expectation from #14930 is correct, marking the `crate::reexport::inner` imports with `i`, and I understand it to mean there's a specific token in the import that we can match it to (in this case, `Trait`, `function` and `makro` of `pub use crate::defs::{Trait, function, makro};` respectively), but I had some trouble understanding the meaning of the different parts of `PerNs` to be sure. Does this make sense? I tested building and using RA locally with `cargo xtask install` and after this change the documentation for `arrow_array::ArrowPrimitiveType` seems to be picked up correctly!
2 parents 2c68c9a + fdb367a commit 0cbcbb0

File tree

3 files changed

+197
-32
lines changed

3 files changed

+197
-32
lines changed

crates/hir-def/src/item_scope.rs

Lines changed: 70 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,18 @@ pub struct ImportId {
6161
pub idx: Idx<ast::UseTree>,
6262
}
6363

64+
impl PerNsGlobImports {
65+
pub(crate) fn contains_type(&self, module_id: LocalModuleId, name: Name) -> bool {
66+
self.types.contains(&(module_id, name))
67+
}
68+
pub(crate) fn contains_value(&self, module_id: LocalModuleId, name: Name) -> bool {
69+
self.values.contains(&(module_id, name))
70+
}
71+
pub(crate) fn contains_macro(&self, module_id: LocalModuleId, name: Name) -> bool {
72+
self.macros.contains(&(module_id, name))
73+
}
74+
}
75+
6476
#[derive(Debug, Default, PartialEq, Eq)]
6577
pub struct ItemScope {
6678
/// Defs visible in this scope. This includes `declarations`, but also
@@ -510,38 +522,48 @@ impl ItemScope {
510522
entry.insert(fld);
511523
changed = true;
512524
}
513-
Entry::Occupied(mut entry) if !matches!(import, Some(ImportType::Glob(..))) => {
514-
if glob_imports.types.remove(&lookup) {
515-
let import = match import {
516-
Some(ImportType::ExternCrate(extern_crate)) => {
517-
Some(ImportOrExternCrate::ExternCrate(extern_crate))
518-
}
519-
Some(ImportType::Import(import)) => {
520-
Some(ImportOrExternCrate::Import(import))
521-
}
522-
None | Some(ImportType::Glob(_)) => None,
523-
};
524-
let prev = std::mem::replace(&mut fld.2, import);
525-
if let Some(import) = import {
526-
self.use_imports_types.insert(
527-
import,
528-
match prev {
529-
Some(ImportOrExternCrate::Import(import)) => {
530-
ImportOrDef::Import(import)
525+
Entry::Occupied(mut entry) => {
526+
match import {
527+
Some(ImportType::Glob(..)) => {
528+
// Multiple globs may import the same item and they may
529+
// override visibility from previously resolved globs. This is
530+
// currently handled by `DefCollector`, because we need to
531+
// compute the max visibility for items and we need `DefMap`
532+
// for that.
533+
}
534+
_ => {
535+
if glob_imports.types.remove(&lookup) {
536+
let import = match import {
537+
Some(ImportType::ExternCrate(extern_crate)) => {
538+
Some(ImportOrExternCrate::ExternCrate(extern_crate))
531539
}
532-
Some(ImportOrExternCrate::ExternCrate(import)) => {
533-
ImportOrDef::ExternCrate(import)
540+
Some(ImportType::Import(import)) => {
541+
Some(ImportOrExternCrate::Import(import))
534542
}
535-
None => ImportOrDef::Def(fld.0),
536-
},
537-
);
543+
None | Some(ImportType::Glob(_)) => None,
544+
};
545+
let prev = std::mem::replace(&mut fld.2, import);
546+
if let Some(import) = import {
547+
self.use_imports_types.insert(
548+
import,
549+
match prev {
550+
Some(ImportOrExternCrate::Import(import)) => {
551+
ImportOrDef::Import(import)
552+
}
553+
Some(ImportOrExternCrate::ExternCrate(import)) => {
554+
ImportOrDef::ExternCrate(import)
555+
}
556+
None => ImportOrDef::Def(fld.0),
557+
},
558+
);
559+
}
560+
cov_mark::hit!(import_shadowed);
561+
entry.insert(fld);
562+
changed = true;
563+
}
538564
}
539-
cov_mark::hit!(import_shadowed);
540-
entry.insert(fld);
541-
changed = true;
542565
}
543566
}
544-
_ => {}
545567
}
546568
}
547569

@@ -756,6 +778,27 @@ impl ItemScope {
756778
}
757779
}
758780

781+
// These methods are a temporary measure only meant to be used by `DefCollector::push_res_and_update_glob_vis()`.
782+
impl ItemScope {
783+
pub(crate) fn update_visibility_types(&mut self, name: &Name, vis: Visibility) {
784+
let res =
785+
self.types.get_mut(name).expect("tried to update visibility of non-existent type");
786+
res.1 = vis;
787+
}
788+
789+
pub(crate) fn update_visibility_values(&mut self, name: &Name, vis: Visibility) {
790+
let res =
791+
self.values.get_mut(name).expect("tried to update visibility of non-existent value");
792+
res.1 = vis;
793+
}
794+
795+
pub(crate) fn update_visibility_macros(&mut self, name: &Name, vis: Visibility) {
796+
let res =
797+
self.macros.get_mut(name).expect("tried to update visibility of non-existent macro");
798+
res.1 = vis;
799+
}
800+
}
801+
759802
impl PerNs {
760803
pub(crate) fn from_def(
761804
def: ModuleDefId,

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

Lines changed: 82 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1025,7 +1025,7 @@ impl DefCollector<'_> {
10251025

10261026
fn update_recursive(
10271027
&mut self,
1028-
// The module for which `resolutions` have been resolve
1028+
// The module for which `resolutions` have been resolved.
10291029
module_id: LocalModuleId,
10301030
resolutions: &[(Option<Name>, PerNs)],
10311031
// All resolutions are imported with this visibility; the visibilities in
@@ -1043,10 +1043,9 @@ impl DefCollector<'_> {
10431043
for (name, res) in resolutions {
10441044
match name {
10451045
Some(name) => {
1046-
let scope = &mut self.def_map.modules[module_id].scope;
1047-
changed |= scope.push_res_with_import(
1048-
&mut self.from_glob_import,
1049-
(module_id, name.clone()),
1046+
changed |= self.push_res_and_update_glob_vis(
1047+
module_id,
1048+
name,
10501049
res.with_visibility(vis),
10511050
import,
10521051
);
@@ -1112,6 +1111,84 @@ impl DefCollector<'_> {
11121111
}
11131112
}
11141113

1114+
fn push_res_and_update_glob_vis(
1115+
&mut self,
1116+
module_id: LocalModuleId,
1117+
name: &Name,
1118+
mut defs: PerNs,
1119+
def_import_type: Option<ImportType>,
1120+
) -> bool {
1121+
let mut changed = false;
1122+
1123+
if let Some(ImportType::Glob(_)) = def_import_type {
1124+
let prev_defs = self.def_map[module_id].scope.get(name);
1125+
1126+
// Multiple globs may import the same item and they may override visibility from
1127+
// previously resolved globs. Handle overrides here and leave the rest to
1128+
// `ItemScope::push_res_with_import()`.
1129+
if let Some((def, def_vis, _)) = defs.types {
1130+
if let Some((prev_def, prev_vis, _)) = prev_defs.types {
1131+
if def == prev_def
1132+
&& self.from_glob_import.contains_type(module_id, name.clone())
1133+
&& def_vis != prev_vis
1134+
&& def_vis.max(prev_vis, &self.def_map) == Some(def_vis)
1135+
{
1136+
changed = true;
1137+
// This import is being handled here, don't pass it down to
1138+
// `ItemScope::push_res_with_import()`.
1139+
defs.types = None;
1140+
self.def_map.modules[module_id]
1141+
.scope
1142+
.update_visibility_types(name, def_vis);
1143+
}
1144+
}
1145+
}
1146+
1147+
if let Some((def, def_vis, _)) = defs.values {
1148+
if let Some((prev_def, prev_vis, _)) = prev_defs.values {
1149+
if def == prev_def
1150+
&& self.from_glob_import.contains_value(module_id, name.clone())
1151+
&& def_vis != prev_vis
1152+
&& def_vis.max(prev_vis, &self.def_map) == Some(def_vis)
1153+
{
1154+
changed = true;
1155+
// See comment above.
1156+
defs.values = None;
1157+
self.def_map.modules[module_id]
1158+
.scope
1159+
.update_visibility_values(name, def_vis);
1160+
}
1161+
}
1162+
}
1163+
1164+
if let Some((def, def_vis, _)) = defs.macros {
1165+
if let Some((prev_def, prev_vis, _)) = prev_defs.macros {
1166+
if def == prev_def
1167+
&& self.from_glob_import.contains_macro(module_id, name.clone())
1168+
&& def_vis != prev_vis
1169+
&& def_vis.max(prev_vis, &self.def_map) == Some(def_vis)
1170+
{
1171+
changed = true;
1172+
// See comment above.
1173+
defs.macros = None;
1174+
self.def_map.modules[module_id]
1175+
.scope
1176+
.update_visibility_macros(name, def_vis);
1177+
}
1178+
}
1179+
}
1180+
}
1181+
1182+
changed |= self.def_map.modules[module_id].scope.push_res_with_import(
1183+
&mut self.from_glob_import,
1184+
(module_id, name.clone()),
1185+
defs,
1186+
def_import_type,
1187+
);
1188+
1189+
changed
1190+
}
1191+
11151192
fn resolve_macros(&mut self) -> ReachedFixedPoint {
11161193
let mut macros = mem::take(&mut self.unresolved_macros);
11171194
let mut resolved = Vec::new();

crates/hir-def/src/nameres/tests/globs.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,3 +367,48 @@ use event::Event;
367367
"#]],
368368
);
369369
}
370+
371+
#[test]
372+
fn glob_may_override_visibility() {
373+
check(
374+
r#"
375+
mod reexport {
376+
use crate::defs::*;
377+
mod inner {
378+
pub use crate::defs::{Trait, function, makro};
379+
}
380+
pub use inner::*;
381+
}
382+
mod defs {
383+
pub trait Trait {}
384+
pub fn function() {}
385+
pub macro makro($t:item) { $t }
386+
}
387+
use reexport::*;
388+
"#,
389+
expect![[r#"
390+
crate
391+
Trait: t
392+
defs: t
393+
function: v
394+
makro: m
395+
reexport: t
396+
397+
crate::defs
398+
Trait: t
399+
function: v
400+
makro: m
401+
402+
crate::reexport
403+
Trait: t
404+
function: v
405+
inner: t
406+
makro: m
407+
408+
crate::reexport::inner
409+
Trait: ti
410+
function: vi
411+
makro: mi
412+
"#]],
413+
);
414+
}

0 commit comments

Comments
 (0)