diff options
Diffstat (limited to 'crates/hir_def/src/item_tree/lower.rs')
-rw-r--r-- | crates/hir_def/src/item_tree/lower.rs | 100 |
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 | |||
869 | struct UseTreeLowering<'a> { | ||
870 | db: &'a dyn DefDatabase, | ||
871 | hygiene: &'a Hygiene, | ||
872 | mapping: Arena<ast::UseTree>, | ||
873 | } | ||
874 | |||
875 | impl 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 | |||
932 | pub(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 | } | ||