From b52df9187730abbcd9cbb132f7d184c74b9a3b7f Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Wed, 26 May 2021 01:01:58 +0200 Subject: Stop expanding UseTrees during ItemTree lowering --- crates/hir_def/src/item_tree.rs | 130 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 119 insertions(+), 11 deletions(-) (limited to 'crates/hir_def/src/item_tree.rs') diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs index 11767d100..508736885 100644 --- a/crates/hir_def/src/item_tree.rs +++ b/crates/hir_def/src/item_tree.rs @@ -523,21 +523,38 @@ impl Index> for ItemTree { } } -/// A desugared `use` import. #[derive(Debug, Clone, Eq, PartialEq)] pub struct Import { - pub path: Interned, - pub alias: Option, pub visibility: RawVisibilityId, - pub is_glob: bool, - /// AST ID of the `use` item this import was derived from. Note that many `Import`s can map to - /// the same `use` item. pub ast_id: FileAstId, - /// Index of this `Import` when the containing `Use` is visited via `ModPath::expand_use_item`. - /// - /// This can be used to get the `UseTree` this `Import` corresponds to and allows emitting - /// precise diagnostics. - pub index: usize, + pub use_tree: UseTree, +} + +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct UseTree { + pub index: Idx, + kind: UseTreeKind, +} + +#[derive(Debug, Clone, Eq, PartialEq)] +pub enum UseTreeKind { + /// ```ignore + /// use path::to::Item; + /// use path::to::Item as Renamed; + /// use path::to::Trait as _; + /// ``` + Single { path: ModPath, alias: Option }, + + /// ```ignore + /// use *; // (invalid, but can occur in nested tree) + /// use path::*; + /// ``` + Glob { path: Option }, + + /// ```ignore + /// use prefix::{self, Item, ...}; + /// ``` + Prefixed { prefix: Option, list: Vec }, } #[derive(Debug, Clone, Eq, PartialEq)] @@ -711,6 +728,97 @@ pub struct MacroDef { pub ast_id: FileAstId, } +impl Import { + /// Maps a `UseTree` contained in this import back to its AST node. + pub fn use_tree_to_ast( + &self, + db: &dyn DefDatabase, + file_id: HirFileId, + index: Idx, + ) -> ast::UseTree { + // Re-lower the AST item and get the source map. + // Note: The AST unwraps are fine, since if they fail we should have never obtained `index`. + let ast = InFile::new(file_id, self.ast_id).to_node(db.upcast()); + let ast_use_tree = ast.use_tree().expect("missing `use_tree`"); + let hygiene = Hygiene::new(db.upcast(), file_id); + let (_, source_map) = + lower::lower_use_tree(db, &hygiene, ast_use_tree).expect("failed to lower use tree"); + source_map[index].clone() + } +} + +impl UseTree { + /// Expands the `UseTree` into individually imported `ModPath`s. + pub fn expand( + &self, + mut cb: impl FnMut(Idx, ModPath, /* is_glob */ bool, Option), + ) { + self.expand_impl(None, &mut cb) + } + + fn expand_impl( + &self, + prefix: Option, + cb: &mut dyn FnMut( + Idx, + ModPath, + /* is_glob */ bool, + Option, + ), + ) { + fn concat_mod_paths(prefix: Option, path: &ModPath) -> Option { + match (prefix, &path.kind) { + (None, _) => Some(path.clone()), + (Some(mut prefix), PathKind::Plain) => { + for segment in path.segments() { + prefix.push_segment(segment.clone()); + } + Some(prefix) + } + (Some(prefix), PathKind::Super(0)) => { + // `some::path::self` == `some::path` + if path.segments().is_empty() { + Some(prefix) + } else { + None + } + } + (Some(_), _) => None, + } + } + + match &self.kind { + UseTreeKind::Single { path, alias } => { + if let Some(path) = concat_mod_paths(prefix, path) { + cb(self.index, path, false, alias.clone()); + } + } + UseTreeKind::Glob { path: Some(path) } => { + if let Some(path) = concat_mod_paths(prefix, path) { + cb(self.index, path, true, None); + } + } + UseTreeKind::Glob { path: None } => { + if let Some(prefix) = prefix { + cb(self.index, prefix, true, None); + } + } + UseTreeKind::Prefixed { prefix: additional_prefix, list } => { + let prefix = match additional_prefix { + Some(path) => match concat_mod_paths(prefix, path) { + Some(path) => Some(path), + None => return, + }, + None => prefix, + }; + for tree in list { + tree.expand_impl(prefix.clone(), cb); + } + } + } + } +} + macro_rules! impl_froms { ($e:ident { $($v:ident ($t:ty)),* $(,)? }) => { $( -- cgit v1.2.3 From fe910c7bc4aac8a33fc1933d64aa260d42a3c4f1 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Wed, 26 May 2021 01:26:16 +0200 Subject: Reduce memory usage a bit --- crates/hir_def/src/item_tree.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'crates/hir_def/src/item_tree.rs') diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs index 508736885..c960f66d6 100644 --- a/crates/hir_def/src/item_tree.rs +++ b/crates/hir_def/src/item_tree.rs @@ -543,18 +543,18 @@ pub enum UseTreeKind { /// use path::to::Item as Renamed; /// use path::to::Trait as _; /// ``` - Single { path: ModPath, alias: Option }, + Single { path: Interned, alias: Option }, /// ```ignore /// use *; // (invalid, but can occur in nested tree) /// use path::*; /// ``` - Glob { path: Option }, + Glob { path: Option> }, /// ```ignore /// use prefix::{self, Item, ...}; /// ``` - Prefixed { prefix: Option, list: Vec }, + Prefixed { prefix: Option>, list: Box<[UseTree]> }, } #[derive(Debug, Clone, Eq, PartialEq)] @@ -811,7 +811,7 @@ impl UseTree { }, None => prefix, }; - for tree in list { + for tree in &**list { tree.expand_impl(prefix.clone(), cb); } } -- cgit v1.2.3 From 196cb65ead398f81340de431400103224d7de660 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Thu, 27 May 2021 13:55:31 +0200 Subject: Drop `ignore` from doctests --- crates/hir_def/src/item_tree.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'crates/hir_def/src/item_tree.rs') diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs index c960f66d6..f84c4cf2b 100644 --- a/crates/hir_def/src/item_tree.rs +++ b/crates/hir_def/src/item_tree.rs @@ -538,20 +538,20 @@ pub struct UseTree { #[derive(Debug, Clone, Eq, PartialEq)] pub enum UseTreeKind { - /// ```ignore + /// ``` /// use path::to::Item; /// use path::to::Item as Renamed; /// use path::to::Trait as _; /// ``` Single { path: Interned, alias: Option }, - /// ```ignore + /// ``` /// use *; // (invalid, but can occur in nested tree) /// use path::*; /// ``` Glob { path: Option> }, - /// ```ignore + /// ``` /// use prefix::{self, Item, ...}; /// ``` Prefixed { prefix: Option>, list: Box<[UseTree]> }, -- cgit v1.2.3