Skip to content

Commit dba534a

Browse files
bors[bot]Jonas Schievink
andauthored
Merge #5475
5475: Support `Trait as _` imports r=matklad a=jonas-schievink Fixes #2736 Co-authored-by: Jonas Schievink <[email protected]>
2 parents 2dd8ba2 + dce9987 commit dba534a

File tree

6 files changed

+270
-26
lines changed

6 files changed

+270
-26
lines changed

crates/ra_hir_def/src/item_scope.rs

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ pub struct ItemScope {
3636

3737
defs: Vec<ModuleDefId>,
3838
impls: Vec<ImplId>,
39+
/// Traits imported via `use Trait as _;`.
40+
unnamed_trait_imports: FxHashMap<TraitId, Visibility>,
3941
/// Macros visible in current module in legacy textual scope
4042
///
4143
/// For macros invoked by an unqualified identifier like `bar!()`, `legacy_macros` will be searched in first.
@@ -126,10 +128,13 @@ impl ItemScope {
126128
}
127129

128130
pub(crate) fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a {
129-
self.types.values().filter_map(|(def, _)| match def {
130-
ModuleDefId::TraitId(t) => Some(*t),
131-
_ => None,
132-
})
131+
self.types
132+
.values()
133+
.filter_map(|(def, _)| match def {
134+
ModuleDefId::TraitId(t) => Some(*t),
135+
_ => None,
136+
})
137+
.chain(self.unnamed_trait_imports.keys().copied())
133138
}
134139

135140
pub(crate) fn define_def(&mut self, def: ModuleDefId) {
@@ -148,6 +153,14 @@ impl ItemScope {
148153
self.legacy_macros.insert(name, mac);
149154
}
150155

156+
pub(crate) fn unnamed_trait_vis(&self, tr: TraitId) -> Option<Visibility> {
157+
self.unnamed_trait_imports.get(&tr).copied()
158+
}
159+
160+
pub(crate) fn push_unnamed_trait(&mut self, tr: TraitId, vis: Visibility) {
161+
self.unnamed_trait_imports.insert(tr, vis);
162+
}
163+
151164
pub(crate) fn push_res(&mut self, name: Name, def: PerNs) -> bool {
152165
let mut changed = false;
153166

@@ -241,8 +254,12 @@ impl ItemScope {
241254
changed
242255
}
243256

244-
pub(crate) fn resolutions<'a>(&'a self) -> impl Iterator<Item = (Name, PerNs)> + 'a {
245-
self.entries().map(|(name, res)| (name.clone(), res))
257+
pub(crate) fn resolutions<'a>(&'a self) -> impl Iterator<Item = (Option<Name>, PerNs)> + 'a {
258+
self.entries().map(|(name, res)| (Some(name.clone()), res)).chain(
259+
self.unnamed_trait_imports
260+
.iter()
261+
.map(|(tr, vis)| (None, PerNs::types(ModuleDefId::TraitId(*tr), *vis))),
262+
)
246263
}
247264

248265
pub(crate) fn collect_legacy_macros(&self) -> FxHashMap<Name, MacroDefId> {

crates/ra_hir_def/src/nameres.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ impl CrateDefMap {
239239
entries.sort_by_key(|(name, _)| name.clone());
240240

241241
for (name, def) in entries {
242-
format_to!(buf, "{}:", name);
242+
format_to!(buf, "{}:", name.map_or("_".to_string(), |name| name.to_string()));
243243

244244
if def.types.is_some() {
245245
buf.push_str(" t");

crates/ra_hir_def/src/nameres/collector.rs

Lines changed: 54 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ impl DefCollector<'_> {
310310
if export {
311311
self.update(
312312
self.def_map.root,
313-
&[(name, PerNs::macros(macro_, Visibility::Public))],
313+
&[(Some(name), PerNs::macros(macro_, Visibility::Public))],
314314
Visibility::Public,
315315
ImportType::Named,
316316
);
@@ -336,7 +336,7 @@ impl DefCollector<'_> {
336336
fn define_proc_macro(&mut self, name: Name, macro_: MacroDefId) {
337337
self.update(
338338
self.def_map.root,
339-
&[(name, PerNs::macros(macro_, Visibility::Public))],
339+
&[(Some(name), PerNs::macros(macro_, Visibility::Public))],
340340
Visibility::Public,
341341
ImportType::Named,
342342
);
@@ -534,7 +534,7 @@ impl DefCollector<'_> {
534534
let name = variant_data.name.clone();
535535
let variant = EnumVariantId { parent: e, local_id };
536536
let res = PerNs::both(variant.into(), variant.into(), vis);
537-
(name, res)
537+
(Some(name), res)
538538
})
539539
.collect::<Vec<_>>();
540540
self.update(module_id, &resolutions, vis, ImportType::Glob);
@@ -550,15 +550,15 @@ impl DefCollector<'_> {
550550
match import.path.segments.last() {
551551
Some(last_segment) => {
552552
let name = match &import.alias {
553-
Some(ImportAlias::Alias(name)) => name.clone(),
554-
Some(ImportAlias::Underscore) => last_segment.clone(), // FIXME rust-analyzer#2736
555-
None => last_segment.clone(),
553+
Some(ImportAlias::Alias(name)) => Some(name.clone()),
554+
Some(ImportAlias::Underscore) => None,
555+
None => Some(last_segment.clone()),
556556
};
557557
log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
558558

559559
// extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
560560
if import.is_extern_crate && module_id == self.def_map.root {
561-
if let Some(def) = def.take_types() {
561+
if let (Some(def), Some(name)) = (def.take_types(), name.as_ref()) {
562562
self.def_map.extern_prelude.insert(name.clone(), def);
563563
}
564564
}
@@ -573,7 +573,7 @@ impl DefCollector<'_> {
573573
fn update(
574574
&mut self,
575575
module_id: LocalModuleId,
576-
resolutions: &[(Name, PerNs)],
576+
resolutions: &[(Option<Name>, PerNs)],
577577
vis: Visibility,
578578
import_type: ImportType,
579579
) {
@@ -584,7 +584,7 @@ impl DefCollector<'_> {
584584
fn update_recursive(
585585
&mut self,
586586
module_id: LocalModuleId,
587-
resolutions: &[(Name, PerNs)],
587+
resolutions: &[(Option<Name>, PerNs)],
588588
// All resolutions are imported with this visibility; the visibilies in
589589
// the `PerNs` values are ignored and overwritten
590590
vis: Visibility,
@@ -595,15 +595,51 @@ impl DefCollector<'_> {
595595
// prevent stack overflows (but this shouldn't be possible)
596596
panic!("infinite recursion in glob imports!");
597597
}
598-
let scope = &mut self.def_map.modules[module_id].scope;
599598
let mut changed = false;
599+
600600
for (name, res) in resolutions {
601-
changed |= scope.push_res_with_import(
602-
&mut self.from_glob_import,
603-
(module_id, name.clone()),
604-
res.with_visibility(vis),
605-
import_type,
606-
);
601+
match name {
602+
Some(name) => {
603+
let scope = &mut self.def_map.modules[module_id].scope;
604+
changed |= scope.push_res_with_import(
605+
&mut self.from_glob_import,
606+
(module_id, name.clone()),
607+
res.with_visibility(vis),
608+
import_type,
609+
);
610+
}
611+
None => {
612+
let tr = match res.take_types() {
613+
Some(ModuleDefId::TraitId(tr)) => tr,
614+
Some(other) => {
615+
log::debug!("non-trait `_` import of {:?}", other);
616+
continue;
617+
}
618+
None => continue,
619+
};
620+
let old_vis = self.def_map.modules[module_id].scope.unnamed_trait_vis(tr);
621+
let should_update = match old_vis {
622+
None => true,
623+
Some(old_vis) => {
624+
let max_vis = old_vis.max(vis, &self.def_map).unwrap_or_else(|| {
625+
panic!("`Tr as _` imports with unrelated visibilities {:?} and {:?} (trait {:?})", old_vis, vis, tr);
626+
});
627+
628+
if max_vis == old_vis {
629+
false
630+
} else {
631+
mark::hit!(upgrade_underscore_visibility);
632+
true
633+
}
634+
}
635+
};
636+
637+
if should_update {
638+
changed = true;
639+
self.def_map.modules[module_id].scope.push_unnamed_trait(tr, vis);
640+
}
641+
}
642+
}
607643
}
608644

609645
if !changed {
@@ -950,7 +986,7 @@ impl ModCollector<'_, '_> {
950986
.unwrap_or(Visibility::Public);
951987
self.def_collector.update(
952988
self.module_id,
953-
&[(name.clone(), PerNs::from_def(id, vis, has_constructor))],
989+
&[(Some(name.clone()), PerNs::from_def(id, vis, has_constructor))],
954990
vis,
955991
ImportType::Named,
956992
)
@@ -1057,7 +1093,7 @@ impl ModCollector<'_, '_> {
10571093
self.def_collector.def_map.modules[self.module_id].scope.define_def(def);
10581094
self.def_collector.update(
10591095
self.module_id,
1060-
&[(name, PerNs::from_def(def, vis, false))],
1096+
&[(Some(name), PerNs::from_def(def, vis, false))],
10611097
vis,
10621098
ImportType::Named,
10631099
);

crates/ra_hir_def/src/nameres/tests.rs

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -558,3 +558,133 @@ mod b {
558558
"#]],
559559
);
560560
}
561+
562+
#[test]
563+
fn underscore_import() {
564+
check(
565+
r#"
566+
//- /main.rs
567+
use tr::Tr as _;
568+
use tr::Tr2 as _;
569+
570+
mod tr {
571+
pub trait Tr {}
572+
pub trait Tr2 {}
573+
}
574+
"#,
575+
expect![[r#"
576+
crate
577+
_: t
578+
_: t
579+
tr: t
580+
581+
crate::tr
582+
Tr: t
583+
Tr2: t
584+
"#]],
585+
);
586+
}
587+
588+
#[test]
589+
fn underscore_reexport() {
590+
check(
591+
r#"
592+
//- /main.rs
593+
mod tr {
594+
pub trait PubTr {}
595+
pub trait PrivTr {}
596+
}
597+
mod reex {
598+
use crate::tr::PrivTr as _;
599+
pub use crate::tr::PubTr as _;
600+
}
601+
use crate::reex::*;
602+
"#,
603+
expect![[r#"
604+
crate
605+
_: t
606+
reex: t
607+
tr: t
608+
609+
crate::tr
610+
PrivTr: t
611+
PubTr: t
612+
613+
crate::reex
614+
_: t
615+
_: t
616+
"#]],
617+
);
618+
}
619+
620+
#[test]
621+
fn underscore_pub_crate_reexport() {
622+
mark::check!(upgrade_underscore_visibility);
623+
check(
624+
r#"
625+
//- /main.rs crate:main deps:lib
626+
use lib::*;
627+
628+
//- /lib.rs crate:lib
629+
use tr::Tr as _;
630+
pub use tr::Tr as _;
631+
632+
mod tr {
633+
pub trait Tr {}
634+
}
635+
"#,
636+
expect![[r#"
637+
crate
638+
_: t
639+
"#]],
640+
);
641+
}
642+
643+
#[test]
644+
fn underscore_nontrait() {
645+
check(
646+
r#"
647+
//- /main.rs
648+
mod m {
649+
pub struct Struct;
650+
pub enum Enum {}
651+
pub const CONST: () = ();
652+
}
653+
use crate::m::{Struct as _, Enum as _, CONST as _};
654+
"#,
655+
expect![[r#"
656+
crate
657+
m: t
658+
659+
crate::m
660+
CONST: v
661+
Enum: t
662+
Struct: t v
663+
"#]],
664+
);
665+
}
666+
667+
#[test]
668+
fn underscore_name_conflict() {
669+
check(
670+
r#"
671+
//- /main.rs
672+
struct Tr;
673+
674+
use tr::Tr as _;
675+
676+
mod tr {
677+
pub trait Tr {}
678+
}
679+
"#,
680+
expect![[r#"
681+
crate
682+
_: t
683+
Tr: t v
684+
tr: t
685+
686+
crate::tr
687+
Tr: t
688+
"#]],
689+
);
690+
}

0 commit comments

Comments
 (0)