aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def/src/item_tree/lower.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_def/src/item_tree/lower.rs')
-rw-r--r--crates/hir_def/src/item_tree/lower.rs100
1 files changed, 77 insertions, 23 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}