aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def/src/item_tree
diff options
context:
space:
mode:
authorJonas Schievink <[email protected]>2021-05-26 00:01:58 +0100
committerJonas Schievink <[email protected]>2021-05-26 00:01:58 +0100
commitb52df9187730abbcd9cbb132f7d184c74b9a3b7f (patch)
tree06cf9ab8dcd938db5390b7da40f7e9a6db262d0d /crates/hir_def/src/item_tree
parent5587d0a3e3599063a8993e9a44a7628abbabae8b (diff)
Stop expanding UseTrees during ItemTree lowering
Diffstat (limited to 'crates/hir_def/src/item_tree')
-rw-r--r--crates/hir_def/src/item_tree/lower.rs100
-rw-r--r--crates/hir_def/src/item_tree/pretty.rs43
-rw-r--r--crates/hir_def/src/item_tree/tests.rs17
3 files changed, 118 insertions, 42 deletions
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs
index b4389371f..a59a3dc37 100644
--- a/crates/hir_def/src/item_tree/lower.rs
+++ b/crates/hir_def/src/item_tree/lower.rs
@@ -35,7 +35,6 @@ pub(super) struct Ctx<'a> {
35 db: &'a dyn DefDatabase, 35 db: &'a dyn DefDatabase,
36 tree: ItemTree, 36 tree: ItemTree,
37 hygiene: Hygiene, 37 hygiene: Hygiene,
38 file: HirFileId,
39 source_ast_id_map: Arc<AstIdMap>, 38 source_ast_id_map: Arc<AstIdMap>,
40 body_ctx: crate::body::LowerCtx<'a>, 39 body_ctx: crate::body::LowerCtx<'a>,
41 forced_visibility: Option<RawVisibilityId>, 40 forced_visibility: Option<RawVisibilityId>,
@@ -47,7 +46,6 @@ impl<'a> Ctx<'a> {
47 db, 46 db,
48 tree: ItemTree::default(), 47 tree: ItemTree::default(),
49 hygiene, 48 hygiene,
50 file,
51 source_ast_id_map: db.ast_id_map(file), 49 source_ast_id_map: db.ast_id_map(file),
52 body_ctx: crate::body::LowerCtx::new(db, file), 50 body_ctx: crate::body::LowerCtx::new(db, file),
53 forced_visibility: None, 51 forced_visibility: None,
@@ -561,30 +559,13 @@ impl<'a> Ctx<'a> {
561 Some(id(self.data().impls.alloc(res))) 559 Some(id(self.data().impls.alloc(res)))
562 } 560 }
563 561
564 fn lower_use(&mut self, use_item: &ast::Use) -> Vec<FileItemTreeId<Import>> { 562 fn lower_use(&mut self, use_item: &ast::Use) -> Option<FileItemTreeId<Import>> {
565 let visibility = self.lower_visibility(use_item); 563 let visibility = self.lower_visibility(use_item);
566 let ast_id = self.source_ast_id_map.ast_id(use_item); 564 let ast_id = self.source_ast_id_map.ast_id(use_item);
565 let (use_tree, _) = lower_use_tree(self.db, &self.hygiene, use_item.use_tree()?)?;
567 566
568 // Every use item can expand to many `Import`s. 567 let res = Import { visibility, ast_id, use_tree };
569 let mut imports = Vec::new(); 568 Some(id(self.data().imports.alloc(res)))
570 let tree = self.tree.data_mut();
571 ModPath::expand_use_item(
572 self.db,
573 InFile::new(self.file, use_item.clone()),
574 &self.hygiene,
575 |path, _use_tree, is_glob, alias| {
576 imports.push(id(tree.imports.alloc(Import {
577 path: Interned::new(path),
578 alias,
579 visibility,
580 is_glob,
581 ast_id,
582 index: imports.len(),
583 })));
584 },
585 );
586
587 imports
588 } 569 }
589 570
590 fn lower_extern_crate( 571 fn lower_extern_crate(
@@ -884,3 +865,76 @@ fn lower_abi(abi: ast::Abi) -> Interned<str> {
884 } 865 }
885 } 866 }
886} 867}
868
869struct UseTreeLowering<'a> {
870 db: &'a dyn DefDatabase,
871 hygiene: &'a Hygiene,
872 mapping: Arena<ast::UseTree>,
873}
874
875impl UseTreeLowering<'_> {
876 fn lower_use_tree(&mut self, tree: ast::UseTree) -> Option<UseTree> {
877 if let Some(use_tree_list) = tree.use_tree_list() {
878 let prefix = match tree.path() {
879 // E.g. use something::{{{inner}}};
880 None => None,
881 // E.g. `use something::{inner}` (prefix is `None`, path is `something`)
882 // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`)
883 Some(path) => {
884 match ModPath::from_src(self.db, path, &self.hygiene) {
885 Some(it) => Some(it),
886 None => return None, // FIXME: report errors somewhere
887 }
888 }
889 };
890
891 let list =
892 use_tree_list.use_trees().filter_map(|tree| self.lower_use_tree(tree)).collect();
893
894 Some(self.use_tree(UseTreeKind::Prefixed { prefix, list }, tree))
895 } else {
896 let is_glob = tree.star_token().is_some();
897 let path = match tree.path() {
898 Some(path) => Some(ModPath::from_src(self.db, path, &self.hygiene)?),
899 None => None,
900 };
901 let alias = tree.rename().map(|a| {
902 a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias)
903 });
904 if alias.is_some() && is_glob {
905 return None;
906 }
907
908 match (path, alias, is_glob) {
909 (path, None, true) => {
910 if path.is_none() {
911 cov_mark::hit!(glob_enum_group);
912 }
913 Some(self.use_tree(UseTreeKind::Glob { path }, tree))
914 }
915 // Globs can't be renamed
916 (_, Some(_), true) | (None, None, false) => None,
917 // `bla::{ as Name}` is invalid
918 (None, Some(_), false) => None,
919 (Some(path), alias, false) => {
920 Some(self.use_tree(UseTreeKind::Single { path, alias }, tree))
921 }
922 }
923 }
924 }
925
926 fn use_tree(&mut self, kind: UseTreeKind, ast: ast::UseTree) -> UseTree {
927 let index = self.mapping.alloc(ast);
928 UseTree { index, kind }
929 }
930}
931
932pub(super) fn lower_use_tree(
933 db: &dyn DefDatabase,
934 hygiene: &Hygiene,
935 tree: ast::UseTree,
936) -> Option<(UseTree, Arena<ast::UseTree>)> {
937 let mut lowering = UseTreeLowering { db, hygiene, mapping: Arena::new() };
938 let tree = lowering.lower_use_tree(tree)?;
939 Some((tree, lowering.mapping))
940}
diff --git a/crates/hir_def/src/item_tree/pretty.rs b/crates/hir_def/src/item_tree/pretty.rs
index 9394a5de6..53631ab19 100644
--- a/crates/hir_def/src/item_tree/pretty.rs
+++ b/crates/hir_def/src/item_tree/pretty.rs
@@ -163,21 +163,46 @@ impl<'a> Printer<'a> {
163 } 163 }
164 } 164 }
165 165
166 fn print_use_tree(&mut self, use_tree: &UseTree) {
167 match &use_tree.kind {
168 UseTreeKind::Single { path, alias } => {
169 w!(self, "{}", path);
170 if let Some(alias) = alias {
171 w!(self, " as {}", alias);
172 }
173 }
174 UseTreeKind::Glob { path } => {
175 if let Some(path) = path {
176 w!(self, "{}::", path);
177 }
178 w!(self, "*");
179 }
180 UseTreeKind::Prefixed { prefix, list } => {
181 if let Some(prefix) = prefix {
182 w!(self, "{}::", prefix);
183 }
184 w!(self, "{{");
185 for (i, tree) in list.iter().enumerate() {
186 if i != 0 {
187 w!(self, ", ");
188 }
189 self.print_use_tree(tree);
190 }
191 w!(self, "}}");
192 }
193 }
194 }
195
166 fn print_mod_item(&mut self, item: ModItem) { 196 fn print_mod_item(&mut self, item: ModItem) {
167 self.print_attrs_of(item); 197 self.print_attrs_of(item);
168 198
169 match item { 199 match item {
170 ModItem::Import(it) => { 200 ModItem::Import(it) => {
171 let Import { visibility, path, is_glob, alias, ast_id: _, index } = &self.tree[it]; 201 let Import { visibility, use_tree, ast_id: _ } = &self.tree[it];
172 self.print_visibility(*visibility); 202 self.print_visibility(*visibility);
173 w!(self, "use {}", path); 203 w!(self, "use ");
174 if *is_glob { 204 self.print_use_tree(use_tree);
175 w!(self, "::*"); 205 wln!(self, ";");
176 }
177 if let Some(alias) = alias {
178 w!(self, " as {}", alias);
179 }
180 wln!(self, "; // {}", index);
181 } 206 }
182 ModItem::ExternCrate(it) => { 207 ModItem::ExternCrate(it) => {
183 let ExternCrate { name, alias, visibility, ast_id: _ } = &self.tree[it]; 208 let ExternCrate { name, alias, visibility, ast_id: _ } = &self.tree[it];
diff --git a/crates/hir_def/src/item_tree/tests.rs b/crates/hir_def/src/item_tree/tests.rs
index 6407871b5..20773aa69 100644
--- a/crates/hir_def/src/item_tree/tests.rs
+++ b/crates/hir_def/src/item_tree/tests.rs
@@ -26,6 +26,8 @@ use globs::*;
26 26
27/// docs on import 27/// docs on import
28use crate::{A, B}; 28use crate::{A, B};
29
30use a::{c, d::{e}};
29 "#, 31 "#,
30 expect![[r##" 32 expect![[r##"
31 #![doc = " file comment"] // AttrId { is_doc_comment: true, ast_index: 0 } 33 #![doc = " file comment"] // AttrId { is_doc_comment: true, ast_index: 0 }
@@ -36,19 +38,14 @@ use crate::{A, B};
36 38
37 pub(super) extern crate bli; 39 pub(super) extern crate bli;
38 40
39 pub use crate::path::nested; // 0 41 pub use crate::path::{nested, items as renamed, Trait as _};
40
41 pub use crate::path::items as renamed; // 1
42 42
43 pub use crate::path::Trait as _; // 2 43 pub(self) use globs::*;
44
45 pub(self) use globs::*; // 0
46 44
47 #[doc = " docs on import"] // AttrId { is_doc_comment: true, ast_index: 0 } 45 #[doc = " docs on import"] // AttrId { is_doc_comment: true, ast_index: 0 }
48 pub(self) use crate::A; // 0 46 pub(self) use crate::{A, B};
49 47
50 #[doc = " docs on import"] // AttrId { is_doc_comment: true, ast_index: 0 } 48 pub(self) use a::{c, d::{e}};
51 pub(self) use crate::B; // 1
52 "##]], 49 "##]],
53 ); 50 );
54} 51}
@@ -218,7 +215,7 @@ mod outline;
218 #[doc = " outer"] // AttrId { is_doc_comment: true, ast_index: 0 } 215 #[doc = " outer"] // AttrId { is_doc_comment: true, ast_index: 0 }
219 #[doc = " inner"] // AttrId { is_doc_comment: true, ast_index: 1 } 216 #[doc = " inner"] // AttrId { is_doc_comment: true, ast_index: 1 }
220 pub(self) mod inline { 217 pub(self) mod inline {
221 pub(self) use super::*; // 0 218 pub(self) use super::*;
222 219
223 // flags = 0x2 220 // flags = 0x2
224 pub(self) fn fn_in_module() -> (); 221 pub(self) fn fn_in_module() -> ();