aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def
diff options
context:
space:
mode:
authorJonas Schievink <[email protected]>2020-07-21 16:52:43 +0100
committerJonas Schievink <[email protected]>2020-07-21 16:55:17 +0100
commitc07eaf868dab86d061ae80c098798a767b910e91 (patch)
tree1793a7f85fd45a0774e019aaa9fe16410ab6eda9 /crates/ra_hir_def
parent65b89b5471879a80fb6003c9fa0f8f93e2eb38e6 (diff)
Support `Trait as _` imports
Diffstat (limited to 'crates/ra_hir_def')
-rw-r--r--crates/ra_hir_def/src/item_scope.rs29
-rw-r--r--crates/ra_hir_def/src/nameres.rs2
-rw-r--r--crates/ra_hir_def/src/nameres/collector.rs67
-rw-r--r--crates/ra_hir_def/src/nameres/tests.rs131
-rw-r--r--crates/ra_hir_def/src/visibility.rs41
5 files changed, 244 insertions, 26 deletions
diff --git a/crates/ra_hir_def/src/item_scope.rs b/crates/ra_hir_def/src/item_scope.rs
index beeb98559..8fee4b15e 100644
--- a/crates/ra_hir_def/src/item_scope.rs
+++ b/crates/ra_hir_def/src/item_scope.rs
@@ -36,6 +36,8 @@ pub struct ItemScope {
36 36
37 defs: Vec<ModuleDefId>, 37 defs: Vec<ModuleDefId>,
38 impls: Vec<ImplId>, 38 impls: Vec<ImplId>,
39 /// Traits imported via `use Trait as _;`.
40 unnamed_trait_imports: FxHashMap<TraitId, Visibility>,
39 /// Macros visible in current module in legacy textual scope 41 /// Macros visible in current module in legacy textual scope
40 /// 42 ///
41 /// For macros invoked by an unqualified identifier like `bar!()`, `legacy_macros` will be searched in first. 43 /// For macros invoked by an unqualified identifier like `bar!()`, `legacy_macros` will be searched in first.
@@ -126,10 +128,13 @@ impl ItemScope {
126 } 128 }
127 129
128 pub(crate) fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a { 130 pub(crate) fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a {
129 self.types.values().filter_map(|(def, _)| match def { 131 self.types
130 ModuleDefId::TraitId(t) => Some(*t), 132 .values()
131 _ => None, 133 .filter_map(|(def, _)| match def {
132 }) 134 ModuleDefId::TraitId(t) => Some(*t),
135 _ => None,
136 })
137 .chain(self.unnamed_trait_imports.keys().copied())
133 } 138 }
134 139
135 pub(crate) fn define_def(&mut self, def: ModuleDefId) { 140 pub(crate) fn define_def(&mut self, def: ModuleDefId) {
@@ -148,6 +153,14 @@ impl ItemScope {
148 self.legacy_macros.insert(name, mac); 153 self.legacy_macros.insert(name, mac);
149 } 154 }
150 155
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
151 pub(crate) fn push_res(&mut self, name: Name, def: PerNs) -> bool { 164 pub(crate) fn push_res(&mut self, name: Name, def: PerNs) -> bool {
152 let mut changed = false; 165 let mut changed = false;
153 166
@@ -241,8 +254,12 @@ impl ItemScope {
241 changed 254 changed
242 } 255 }
243 256
244 pub(crate) fn resolutions<'a>(&'a self) -> impl Iterator<Item = (Name, PerNs)> + 'a { 257 pub(crate) fn resolutions<'a>(&'a self) -> impl Iterator<Item = (Option<Name>, PerNs)> + 'a {
245 self.entries().map(|(name, res)| (name.clone(), res)) 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 )
246 } 263 }
247 264
248 pub(crate) fn collect_legacy_macros(&self) -> FxHashMap<Name, MacroDefId> { 265 pub(crate) fn collect_legacy_macros(&self) -> FxHashMap<Name, MacroDefId> {
diff --git a/crates/ra_hir_def/src/nameres.rs b/crates/ra_hir_def/src/nameres.rs
index 5a9de3d3e..3d9b55a73 100644
--- a/crates/ra_hir_def/src/nameres.rs
+++ b/crates/ra_hir_def/src/nameres.rs
@@ -239,7 +239,7 @@ impl CrateDefMap {
239 entries.sort_by_key(|(name, _)| name.clone()); 239 entries.sort_by_key(|(name, _)| name.clone());
240 240
241 for (name, def) in entries { 241 for (name, def) in entries {
242 format_to!(buf, "{}:", name); 242 format_to!(buf, "{}:", name.map_or("_".to_string(), |name| name.to_string()));
243 243
244 if def.types.is_some() { 244 if def.types.is_some() {
245 buf.push_str(" t"); 245 buf.push_str(" t");
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs
index d85a86c0a..8913111f1 100644
--- a/crates/ra_hir_def/src/nameres/collector.rs
+++ b/crates/ra_hir_def/src/nameres/collector.rs
@@ -310,7 +310,7 @@ impl DefCollector<'_> {
310 if export { 310 if export {
311 self.update( 311 self.update(
312 self.def_map.root, 312 self.def_map.root,
313 &[(name, PerNs::macros(macro_, Visibility::Public))], 313 &[(Some(name), PerNs::macros(macro_, Visibility::Public))],
314 Visibility::Public, 314 Visibility::Public,
315 ImportType::Named, 315 ImportType::Named,
316 ); 316 );
@@ -336,7 +336,7 @@ impl DefCollector<'_> {
336 fn define_proc_macro(&mut self, name: Name, macro_: MacroDefId) { 336 fn define_proc_macro(&mut self, name: Name, macro_: MacroDefId) {
337 self.update( 337 self.update(
338 self.def_map.root, 338 self.def_map.root,
339 &[(name, PerNs::macros(macro_, Visibility::Public))], 339 &[(Some(name), PerNs::macros(macro_, Visibility::Public))],
340 Visibility::Public, 340 Visibility::Public,
341 ImportType::Named, 341 ImportType::Named,
342 ); 342 );
@@ -534,7 +534,7 @@ impl DefCollector<'_> {
534 let name = variant_data.name.clone(); 534 let name = variant_data.name.clone();
535 let variant = EnumVariantId { parent: e, local_id }; 535 let variant = EnumVariantId { parent: e, local_id };
536 let res = PerNs::both(variant.into(), variant.into(), vis); 536 let res = PerNs::both(variant.into(), variant.into(), vis);
537 (name, res) 537 (Some(name), res)
538 }) 538 })
539 .collect::<Vec<_>>(); 539 .collect::<Vec<_>>();
540 self.update(module_id, &resolutions, vis, ImportType::Glob); 540 self.update(module_id, &resolutions, vis, ImportType::Glob);
@@ -550,15 +550,15 @@ impl DefCollector<'_> {
550 match import.path.segments.last() { 550 match import.path.segments.last() {
551 Some(last_segment) => { 551 Some(last_segment) => {
552 let name = match &import.alias { 552 let name = match &import.alias {
553 Some(ImportAlias::Alias(name)) => name.clone(), 553 Some(ImportAlias::Alias(name)) => Some(name.clone()),
554 Some(ImportAlias::Underscore) => last_segment.clone(), // FIXME rust-analyzer#2736 554 Some(ImportAlias::Underscore) => None,
555 None => last_segment.clone(), 555 None => Some(last_segment.clone()),
556 }; 556 };
557 log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def); 557 log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
558 558
559 // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658 559 // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
560 if import.is_extern_crate && module_id == self.def_map.root { 560 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()) {
562 self.def_map.extern_prelude.insert(name.clone(), def); 562 self.def_map.extern_prelude.insert(name.clone(), def);
563 } 563 }
564 } 564 }
@@ -573,7 +573,7 @@ impl DefCollector<'_> {
573 fn update( 573 fn update(
574 &mut self, 574 &mut self,
575 module_id: LocalModuleId, 575 module_id: LocalModuleId,
576 resolutions: &[(Name, PerNs)], 576 resolutions: &[(Option<Name>, PerNs)],
577 vis: Visibility, 577 vis: Visibility,
578 import_type: ImportType, 578 import_type: ImportType,
579 ) { 579 ) {
@@ -584,7 +584,7 @@ impl DefCollector<'_> {
584 fn update_recursive( 584 fn update_recursive(
585 &mut self, 585 &mut self,
586 module_id: LocalModuleId, 586 module_id: LocalModuleId,
587 resolutions: &[(Name, PerNs)], 587 resolutions: &[(Option<Name>, PerNs)],
588 // All resolutions are imported with this visibility; the visibilies in 588 // All resolutions are imported with this visibility; the visibilies in
589 // the `PerNs` values are ignored and overwritten 589 // the `PerNs` values are ignored and overwritten
590 vis: Visibility, 590 vis: Visibility,
@@ -595,15 +595,46 @@ impl DefCollector<'_> {
595 // prevent stack overflows (but this shouldn't be possible) 595 // prevent stack overflows (but this shouldn't be possible)
596 panic!("infinite recursion in glob imports!"); 596 panic!("infinite recursion in glob imports!");
597 } 597 }
598 let scope = &mut self.def_map.modules[module_id].scope;
599 let mut changed = false; 598 let mut changed = false;
599
600 for (name, res) in resolutions { 600 for (name, res) in resolutions {
601 changed |= scope.push_res_with_import( 601 match name {
602 &mut self.from_glob_import, 602 Some(name) => {
603 (module_id, name.clone()), 603 let scope = &mut self.def_map.modules[module_id].scope;
604 res.with_visibility(vis), 604 changed |= scope.push_res_with_import(
605 import_type, 605 &mut self.from_glob_import,
606 ); 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 max_vis != old_vis
629 }
630 };
631
632 if should_update {
633 changed = true;
634 self.def_map.modules[module_id].scope.push_unnamed_trait(tr, vis);
635 }
636 }
637 }
607 } 638 }
608 639
609 if !changed { 640 if !changed {
@@ -950,7 +981,7 @@ impl ModCollector<'_, '_> {
950 .unwrap_or(Visibility::Public); 981 .unwrap_or(Visibility::Public);
951 self.def_collector.update( 982 self.def_collector.update(
952 self.module_id, 983 self.module_id,
953 &[(name.clone(), PerNs::from_def(id, vis, has_constructor))], 984 &[(Some(name.clone()), PerNs::from_def(id, vis, has_constructor))],
954 vis, 985 vis,
955 ImportType::Named, 986 ImportType::Named,
956 ) 987 )
@@ -1057,7 +1088,7 @@ impl ModCollector<'_, '_> {
1057 self.def_collector.def_map.modules[self.module_id].scope.define_def(def); 1088 self.def_collector.def_map.modules[self.module_id].scope.define_def(def);
1058 self.def_collector.update( 1089 self.def_collector.update(
1059 self.module_id, 1090 self.module_id,
1060 &[(name, PerNs::from_def(def, vis, false))], 1091 &[(Some(name), PerNs::from_def(def, vis, false))],
1061 vis, 1092 vis,
1062 ImportType::Named, 1093 ImportType::Named,
1063 ); 1094 );
diff --git a/crates/ra_hir_def/src/nameres/tests.rs b/crates/ra_hir_def/src/nameres/tests.rs
index 205d3528b..502b1fb69 100644
--- a/crates/ra_hir_def/src/nameres/tests.rs
+++ b/crates/ra_hir_def/src/nameres/tests.rs
@@ -558,3 +558,134 @@ mod b {
558 "#]], 558 "#]],
559 ); 559 );
560} 560}
561
562#[test]
563fn underscore_import() {
564 check(
565 r#"
566//- /main.rs
567use tr::Tr as _;
568use tr::Tr2 as _;
569
570mod 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]
589fn underscore_reexport() {
590 check(
591 r#"
592//- /main.rs
593mod tr {
594 pub trait PubTr {}
595 pub trait PrivTr {}
596}
597mod reex {
598 use crate::tr::PrivTr as _;
599 pub use crate::tr::PubTr as _;
600}
601use 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]
621fn underscore_pub_crate_reexport() {
622 check(
623 r#"
624//- /main.rs crate:main deps:lib
625use lib::*;
626
627//- /lib.rs crate:lib
628use tr::Tr as _;
629pub use tr::Tr as _;
630
631mod tr {
632 pub trait Tr {
633 fn method(&self) {}
634 }
635}
636 "#,
637 expect![[r#"
638 crate
639 _: t
640 "#]],
641 );
642}
643
644#[test]
645fn underscore_nontrait() {
646 check(
647 r#"
648//- /main.rs
649mod m {
650 pub struct Struct;
651 pub enum Enum {}
652 pub const CONST: () = ();
653}
654use crate::m::{Struct as _, Enum as _, CONST as _};
655 "#,
656 expect![[r#"
657 crate
658 m: t
659
660 crate::m
661 CONST: v
662 Enum: t
663 Struct: t v
664 "#]],
665 );
666}
667
668#[test]
669fn underscore_name_conflict() {
670 check(
671 r#"
672//- /main.rs
673struct Tr;
674
675use tr::Tr as _;
676
677mod tr {
678 pub trait Tr {}
679}
680 "#,
681 expect![[r#"
682 crate
683 _: t
684 Tr: t v
685 tr: t
686
687 crate::tr
688 Tr: t
689 "#]],
690 );
691}
diff --git a/crates/ra_hir_def/src/visibility.rs b/crates/ra_hir_def/src/visibility.rs
index 8136cb50c..1abffb4c3 100644
--- a/crates/ra_hir_def/src/visibility.rs
+++ b/crates/ra_hir_def/src/visibility.rs
@@ -5,6 +5,7 @@ use ra_syntax::ast;
5 5
6use crate::{ 6use crate::{
7 db::DefDatabase, 7 db::DefDatabase,
8 nameres::CrateDefMap,
8 path::{ModPath, PathKind}, 9 path::{ModPath, PathKind},
9 ModuleId, 10 ModuleId,
10}; 11};
@@ -115,7 +116,7 @@ impl Visibility {
115 116
116 pub(crate) fn is_visible_from_def_map( 117 pub(crate) fn is_visible_from_def_map(
117 self, 118 self,
118 def_map: &crate::nameres::CrateDefMap, 119 def_map: &CrateDefMap,
119 from_module: crate::LocalModuleId, 120 from_module: crate::LocalModuleId,
120 ) -> bool { 121 ) -> bool {
121 let to_module = match self { 122 let to_module = match self {
@@ -129,4 +130,42 @@ impl Visibility {
129 }); 130 });
130 ancestors.any(|m| m == to_module.local_id) 131 ancestors.any(|m| m == to_module.local_id)
131 } 132 }
133
134 /// Returns the most permissive visibility of `self` and `other`.
135 ///
136 /// If there is no subset relation between `self` and `other`, returns `None` (ie. they're only
137 /// visible in unrelated modules).
138 pub(crate) fn max(self, other: Visibility, def_map: &CrateDefMap) -> Option<Visibility> {
139 match (self, other) {
140 (Visibility::Module(_), Visibility::Public)
141 | (Visibility::Public, Visibility::Module(_))
142 | (Visibility::Public, Visibility::Public) => Some(Visibility::Public),
143 (Visibility::Module(mod_a), Visibility::Module(mod_b)) => {
144 if mod_a.krate != mod_b.krate {
145 return None;
146 }
147
148 let mut a_ancestors = std::iter::successors(Some(mod_a.local_id), |m| {
149 let parent_id = def_map[*m].parent?;
150 Some(parent_id)
151 });
152 let mut b_ancestors = std::iter::successors(Some(mod_b.local_id), |m| {
153 let parent_id = def_map[*m].parent?;
154 Some(parent_id)
155 });
156
157 if a_ancestors.any(|m| m == mod_b.local_id) {
158 // B is above A
159 return Some(Visibility::Module(mod_b));
160 }
161
162 if b_ancestors.any(|m| m == mod_a.local_id) {
163 // A is above B
164 return Some(Visibility::Module(mod_a));
165 }
166
167 None
168 }
169 }
170 }
132} 171}