From 976a3226fe0f145dfefd473e9fecd63d58aca50e Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Thu, 6 May 2021 19:59:54 +0200 Subject: Don't store call-site text offsets in hygiene info --- Cargo.toml | 2 ++ crates/hir/src/attrs.rs | 2 +- crates/hir/src/lib.rs | 2 +- crates/hir/src/semantics.rs | 2 +- crates/hir/src/source_analyzer.rs | 7 ++-- crates/hir_def/src/attr.rs | 21 +++++++---- crates/hir_def/src/body.rs | 8 ++--- crates/hir_def/src/body/lower.rs | 30 +++++++++------- crates/hir_def/src/find_path.rs | 2 +- crates/hir_def/src/item_tree.rs | 2 +- crates/hir_def/src/item_tree/lower.rs | 34 ++++++++++-------- crates/hir_def/src/lib.rs | 4 +-- crates/hir_def/src/nameres.rs | 1 + crates/hir_def/src/path.rs | 15 ++++---- crates/hir_def/src/path/lower.rs | 14 +++++--- crates/hir_def/src/path/lower/lower_use.rs | 23 ++++++++---- crates/hir_def/src/visibility.rs | 8 +++-- crates/hir_expand/src/hygiene.rs | 57 ++++++++++++++++++------------ crates/hir_ty/src/display.rs | 4 +-- 19 files changed, 145 insertions(+), 93 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 46c64d35c..d34251fc0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,3 +27,5 @@ debug = 0 # Set this to 1 or 2 to get more useful backtraces in debugger. # chalk-recursive = { path = "../chalk/chalk-recursive" } # ungrammar = { path = "../ungrammar" } + +# salsa = { path = "../salsa" } diff --git a/crates/hir/src/attrs.rs b/crates/hir/src/attrs.rs index 4a11622fc..e8fa3c56e 100644 --- a/crates/hir/src/attrs.rs +++ b/crates/hir/src/attrs.rs @@ -112,7 +112,7 @@ fn resolve_doc_path( AttrDefId::MacroDefId(_) => return None, }; let path = ast::Path::parse(link).ok()?; - let modpath = ModPath::from_src(path, &Hygiene::new_unhygienic()).unwrap(); + let modpath = ModPath::from_src(db.upcast(), path, &Hygiene::new_unhygienic()).unwrap(); let resolved = resolver.resolve_module_path_in_items(db.upcast(), &modpath); if resolved == PerNs::none() { if let Some(trait_id) = resolver.resolve_module_path_in_trait_items(db.upcast(), &modpath) { diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 6fcc58f61..f876339de 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -1666,7 +1666,7 @@ impl Impl { .value .attrs() .filter_map(|it| { - let path = ModPath::from_src(it.path()?, &hygenic)?; + let path = ModPath::from_src(db.upcast(), it.path()?, &hygenic)?; if path.as_ident()?.to_string() == "derive" { Some(it) } else { diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index 62500602a..d53d81c07 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -855,7 +855,7 @@ impl<'a> SemanticsScope<'a> { /// necessary a heuristic, as it doesn't take hygiene into account. pub fn speculative_resolve(&self, path: &ast::Path) -> Option { let ctx = body::LowerCtx::new(self.db.upcast(), self.file_id); - let path = Path::from_src(path.clone(), &ctx)?; + let path = Path::from_src(self.db.upcast(), path.clone(), &ctx)?; resolve_hir_path(self.db, &self.resolver, &path) } } diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index 0895bd6f1..186421cbd 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -204,7 +204,8 @@ impl SourceAnalyzer { macro_call: InFile<&ast::MacroCall>, ) -> Option { let ctx = body::LowerCtx::new(db.upcast(), macro_call.file_id); - let path = macro_call.value.path().and_then(|ast| Path::from_src(ast, &ctx))?; + let path = + macro_call.value.path().and_then(|ast| Path::from_src(db.upcast(), ast, &ctx))?; self.resolver.resolve_path_as_macro(db.upcast(), path.mod_path()).map(|it| it.into()) } @@ -283,8 +284,8 @@ impl SourceAnalyzer { // This must be a normal source file rather than macro file. let hygiene = Hygiene::new(db.upcast(), self.file_id); - let ctx = body::LowerCtx::with_hygiene(&hygiene); - let hir_path = Path::from_src(path.clone(), &ctx)?; + let ctx = body::LowerCtx::with_hygiene(db.upcast(), &hygiene); + let hir_path = Path::from_src(db.upcast(), path.clone(), &ctx)?; // Case where path is a qualifier of another path, e.g. foo::bar::Baz where we // trying to resolve foo::bar. diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs index 0171d8a92..a2479016e 100644 --- a/crates/hir_def/src/attr.rs +++ b/crates/hir_def/src/attr.rs @@ -95,13 +95,17 @@ impl ops::Deref for AttrsWithOwner { impl RawAttrs { pub(crate) const EMPTY: Self = Self { entries: None }; - pub(crate) fn new(owner: &dyn ast::AttrsOwner, hygiene: &Hygiene) -> Self { + pub(crate) fn new( + db: &dyn DefDatabase, + owner: &dyn ast::AttrsOwner, + hygiene: &Hygiene, + ) -> Self { let entries = collect_attrs(owner) .enumerate() .flat_map(|(i, attr)| { let index = AttrId(i as u32); match attr { - Either::Left(attr) => Attr::from_src(attr, hygiene, index), + Either::Left(attr) => Attr::from_src(db, attr, hygiene, index), Either::Right(comment) => comment.doc_comment().map(|doc| Attr { id: index, input: Some(AttrInput::Literal(SmolStr::new(doc))), @@ -116,7 +120,7 @@ impl RawAttrs { fn from_attrs_owner(db: &dyn DefDatabase, owner: InFile<&dyn ast::AttrsOwner>) -> Self { let hygiene = Hygiene::new(db.upcast(), owner.file_id); - Self::new(owner.value, &hygiene) + Self::new(db, owner.value, &hygiene) } pub(crate) fn merge(&self, other: Self) -> Self { @@ -170,7 +174,7 @@ impl RawAttrs { let attr = ast::Attr::parse(&format!("#[{}]", tree)).ok()?; // FIXME hygiene let hygiene = Hygiene::new_unhygienic(); - Attr::from_src(attr, &hygiene, index) + Attr::from_src(db, attr, &hygiene, index) }); let cfg_options = &crate_graph[krate].cfg_options; @@ -627,8 +631,13 @@ pub enum AttrInput { } impl Attr { - fn from_src(ast: ast::Attr, hygiene: &Hygiene, id: AttrId) -> Option { - let path = Interned::new(ModPath::from_src(ast.path()?, hygiene)?); + fn from_src( + db: &dyn DefDatabase, + ast: ast::Attr, + hygiene: &Hygiene, + id: AttrId, + ) -> Option { + let path = Interned::new(ModPath::from_src(db, ast.path()?, hygiene)?); let input = if let Some(ast::Expr::Literal(lit)) = ast.expr() { let value = match lit.kind() { ast::LiteralKind::String(string) => string.value()?.into(), diff --git a/crates/hir_def/src/body.rs b/crates/hir_def/src/body.rs index 131f424cc..9510a8575 100644 --- a/crates/hir_def/src/body.rs +++ b/crates/hir_def/src/body.rs @@ -72,7 +72,7 @@ impl CfgExpander { } pub(crate) fn parse_attrs(&self, db: &dyn DefDatabase, owner: &dyn ast::AttrsOwner) -> Attrs { - RawAttrs::new(owner, &self.hygiene).filter(db, self.krate) + RawAttrs::new(db, owner, &self.hygiene).filter(db, self.krate) } pub(crate) fn is_cfg_enabled(&self, db: &dyn DefDatabase, owner: &dyn ast::AttrsOwner) -> bool { @@ -192,9 +192,9 @@ impl Expander { self.current_file_id } - fn parse_path(&mut self, path: ast::Path) -> Option { - let ctx = LowerCtx::with_hygiene(&self.cfg_expander.hygiene); - Path::from_src(path, &ctx) + fn parse_path(&mut self, db: &dyn DefDatabase, path: ast::Path) -> Option { + let ctx = LowerCtx::with_hygiene(db, &self.cfg_expander.hygiene); + Path::from_src(db, path, &ctx) } fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option { diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs index c11da30d2..e4fa7f9c9 100644 --- a/crates/hir_def/src/body/lower.rs +++ b/crates/hir_def/src/body/lower.rs @@ -40,23 +40,25 @@ use crate::{ use super::{diagnostics::BodyDiagnostic, ExprSource, PatSource}; -pub struct LowerCtx { +pub struct LowerCtx<'a> { + db: &'a dyn DefDatabase, hygiene: Hygiene, file_id: Option, source_ast_id_map: Option>, } -impl LowerCtx { - pub fn new(db: &dyn DefDatabase, file_id: HirFileId) -> Self { +impl<'a> LowerCtx<'a> { + pub fn new(db: &'a dyn DefDatabase, file_id: HirFileId) -> Self { LowerCtx { + db, hygiene: Hygiene::new(db.upcast(), file_id), file_id: Some(file_id), source_ast_id_map: Some(db.ast_id_map(file_id)), } } - pub fn with_hygiene(hygiene: &Hygiene) -> Self { - LowerCtx { hygiene: hygiene.clone(), file_id: None, source_ast_id_map: None } + pub fn with_hygiene(db: &'a dyn DefDatabase, hygiene: &Hygiene) -> Self { + LowerCtx { db, hygiene: hygiene.clone(), file_id: None, source_ast_id_map: None } } pub(crate) fn hygiene(&self) -> &Hygiene { @@ -68,7 +70,7 @@ impl LowerCtx { } pub(crate) fn lower_path(&self, ast: ast::Path) -> Option { - Path::from_src(ast, self) + Path::from_src(self.db, ast, self) } pub(crate) fn ast_id(&self, item: &N) -> Option> { @@ -145,7 +147,7 @@ impl ExprCollector<'_> { (self.body, self.source_map) } - fn ctx(&self) -> LowerCtx { + fn ctx(&self) -> LowerCtx<'_> { LowerCtx::new(self.db, self.expander.current_file_id) } @@ -376,7 +378,7 @@ impl ExprCollector<'_> { ast::Expr::PathExpr(e) => { let path = e .path() - .and_then(|path| self.expander.parse_path(path)) + .and_then(|path| self.expander.parse_path(self.db, path)) .map(Expr::Path) .unwrap_or(Expr::Missing); self.alloc_expr(path, syntax_ptr) @@ -408,7 +410,8 @@ impl ExprCollector<'_> { self.alloc_expr(Expr::Yield { expr }, syntax_ptr) } ast::Expr::RecordExpr(e) => { - let path = e.path().and_then(|path| self.expander.parse_path(path)).map(Box::new); + let path = + e.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new); let record_lit = if let Some(nfl) = e.record_expr_field_list() { let fields = nfl .fields() @@ -791,7 +794,8 @@ impl ExprCollector<'_> { } } ast::Pat::TupleStructPat(p) => { - let path = p.path().and_then(|path| self.expander.parse_path(path)).map(Box::new); + let path = + p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new); let (args, ellipsis) = self.collect_tuple_pat(p.fields()); Pat::TupleStruct { path, args, ellipsis } } @@ -801,7 +805,8 @@ impl ExprCollector<'_> { Pat::Ref { pat, mutability } } ast::Pat::PathPat(p) => { - let path = p.path().and_then(|path| self.expander.parse_path(path)).map(Box::new); + let path = + p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new); path.map(Pat::Path).unwrap_or(Pat::Missing) } ast::Pat::OrPat(p) => { @@ -815,7 +820,8 @@ impl ExprCollector<'_> { } ast::Pat::WildcardPat(_) => Pat::Wild, ast::Pat::RecordPat(p) => { - let path = p.path().and_then(|path| self.expander.parse_path(path)).map(Box::new); + let path = + p.path().and_then(|path| self.expander.parse_path(self.db, path)).map(Box::new); let args: Vec<_> = p .record_pat_field_list() .expect("every struct should have a field list") diff --git a/crates/hir_def/src/find_path.rs b/crates/hir_def/src/find_path.rs index c06a37294..858e88038 100644 --- a/crates/hir_def/src/find_path.rs +++ b/crates/hir_def/src/find_path.rs @@ -386,7 +386,7 @@ mod tests { let parsed_path_file = syntax::SourceFile::parse(&format!("use {};", path)); let ast_path = parsed_path_file.syntax_node().descendants().find_map(syntax::ast::Path::cast).unwrap(); - let mod_path = ModPath::from_src(ast_path, &Hygiene::new_unhygienic()).unwrap(); + let mod_path = ModPath::from_src(&db, ast_path, &Hygiene::new_unhygienic()).unwrap(); let def_map = module.def_map(&db); let resolved = def_map diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs index eaeca01bd..8d13c7e04 100644 --- a/crates/hir_def/src/item_tree.rs +++ b/crates/hir_def/src/item_tree.rs @@ -88,7 +88,7 @@ impl ItemTree { let mut item_tree = match_ast! { match syntax { ast::SourceFile(file) => { - top_attrs = Some(RawAttrs::new(&file, &hygiene)); + top_attrs = Some(RawAttrs::new(db, &file, &hygiene)); ctx.lower_module_items(&file) }, ast::MacroItems(items) => { diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs index 45b099cf3..5743b3386 100644 --- a/crates/hir_def/src/item_tree/lower.rs +++ b/crates/hir_def/src/item_tree/lower.rs @@ -31,18 +31,20 @@ where } } -pub(super) struct Ctx { +pub(super) struct Ctx<'a> { + db: &'a dyn DefDatabase, tree: ItemTree, hygiene: Hygiene, file: HirFileId, source_ast_id_map: Arc, - body_ctx: crate::body::LowerCtx, + body_ctx: crate::body::LowerCtx<'a>, forced_visibility: Option, } -impl Ctx { - pub(super) fn new(db: &dyn DefDatabase, hygiene: Hygiene, file: HirFileId) -> Self { +impl<'a> Ctx<'a> { + pub(super) fn new(db: &'a dyn DefDatabase, hygiene: Hygiene, file: HirFileId) -> Self { Self { + db, tree: ItemTree::default(), hygiene, file, @@ -126,7 +128,7 @@ impl Ctx { | ast::Item::MacroDef(_) => {} }; - let attrs = RawAttrs::new(item, &self.hygiene); + let attrs = RawAttrs::new(self.db, item, &self.hygiene); let items = match item { ast::Item::Struct(ast) => self.lower_struct(ast).map(Into::into), ast::Item::Union(ast) => self.lower_union(ast).map(Into::into), @@ -256,7 +258,7 @@ impl Ctx { for field in fields.fields() { if let Some(data) = self.lower_record_field(&field) { let idx = self.data().fields.alloc(data); - self.add_attrs(idx.into(), RawAttrs::new(&field, &self.hygiene)); + self.add_attrs(idx.into(), RawAttrs::new(self.db, &field, &self.hygiene)); } } let end = self.next_field_idx(); @@ -276,7 +278,7 @@ impl Ctx { for (i, field) in fields.fields().enumerate() { let data = self.lower_tuple_field(i, &field); let idx = self.data().fields.alloc(data); - self.add_attrs(idx.into(), RawAttrs::new(&field, &self.hygiene)); + self.add_attrs(idx.into(), RawAttrs::new(self.db, &field, &self.hygiene)); } let end = self.next_field_idx(); IdRange::new(start..end) @@ -321,7 +323,7 @@ impl Ctx { for variant in variants.variants() { if let Some(data) = self.lower_variant(&variant) { let idx = self.data().variants.alloc(data); - self.add_attrs(idx.into(), RawAttrs::new(&variant, &self.hygiene)); + self.add_attrs(idx.into(), RawAttrs::new(self.db, &variant, &self.hygiene)); } } let end = self.next_variant_idx(); @@ -364,7 +366,7 @@ impl Ctx { }; let ty = Interned::new(self_type); let idx = self.data().params.alloc(Param::Normal(ty)); - self.add_attrs(idx.into(), RawAttrs::new(&self_param, &self.hygiene)); + self.add_attrs(idx.into(), RawAttrs::new(self.db, &self_param, &self.hygiene)); has_self_param = true; } for param in param_list.params() { @@ -376,7 +378,7 @@ impl Ctx { self.data().params.alloc(Param::Normal(ty)) } }; - self.add_attrs(idx.into(), RawAttrs::new(¶m, &self.hygiene)); + self.add_attrs(idx.into(), RawAttrs::new(self.db, ¶m, &self.hygiene)); } } let end_param = self.next_param_idx(); @@ -522,10 +524,11 @@ impl Ctx { let is_unsafe = trait_def.unsafe_token().is_some(); let bounds = self.lower_type_bounds(trait_def); let items = trait_def.assoc_item_list().map(|list| { + let db = self.db; self.with_inherited_visibility(visibility, |this| { list.assoc_items() .filter_map(|item| { - let attrs = RawAttrs::new(&item, &this.hygiene); + let attrs = RawAttrs::new(db, &item, &this.hygiene); this.collect_inner_items(item.syntax()); this.lower_assoc_item(&item).map(|item| { this.add_attrs(ModItem::from(item).into(), attrs); @@ -567,7 +570,7 @@ impl Ctx { .filter_map(|item| { self.collect_inner_items(item.syntax()); let assoc = self.lower_assoc_item(&item)?; - let attrs = RawAttrs::new(&item, &self.hygiene); + let attrs = RawAttrs::new(self.db, &item, &self.hygiene); self.add_attrs(ModItem::from(assoc).into(), attrs); Some(assoc) }) @@ -585,6 +588,7 @@ impl Ctx { let mut imports = Vec::new(); let tree = self.tree.data_mut(); ModPath::expand_use_item( + self.db, InFile::new(self.file, use_item.clone()), &self.hygiene, |path, _use_tree, is_glob, alias| { @@ -618,7 +622,7 @@ impl Ctx { } fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option> { - let path = Interned::new(ModPath::from_src(m.path()?, &self.hygiene)?); + let path = Interned::new(ModPath::from_src(self.db, m.path()?, &self.hygiene)?); let ast_id = self.source_ast_id_map.ast_id(m); let res = MacroCall { path, ast_id }; Some(id(self.data().macro_calls.alloc(res))) @@ -647,7 +651,7 @@ impl Ctx { list.extern_items() .filter_map(|item| { self.collect_inner_items(item.syntax()); - let attrs = RawAttrs::new(&item, &self.hygiene); + let attrs = RawAttrs::new(self.db, &item, &self.hygiene); let id: ModItem = match item { ast::ExternItem::Fn(ast) => { let func_id = self.lower_function(&ast)?; @@ -755,7 +759,7 @@ impl Ctx { fn lower_visibility(&mut self, item: &impl ast::VisibilityOwner) -> RawVisibilityId { let vis = match self.forced_visibility { Some(vis) => return vis, - None => RawVisibility::from_ast_with_hygiene(item.visibility(), &self.hygiene), + None => RawVisibility::from_ast_with_hygiene(self.db, item.visibility(), &self.hygiene), }; self.data().vis.alloc(vis) diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs index 25694f037..da46f16f7 100644 --- a/crates/hir_def/src/lib.rs +++ b/crates/hir_def/src/lib.rs @@ -654,7 +654,7 @@ impl AsMacroCall for InFile<&ast::MacroCall> { ) -> Result, UnresolvedMacro> { let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value)); let h = Hygiene::new(db.upcast(), self.file_id); - let path = self.value.path().and_then(|path| path::ModPath::from_src(path, &h)); + let path = self.value.path().and_then(|path| path::ModPath::from_src(db, path, &h)); let path = match error_sink .option(path, || mbe::ExpandError::Other("malformed macro invocation".into())) @@ -712,7 +712,7 @@ fn macro_call_as_call_id( krate, macro_call, def, - &|path: ast::Path| resolver(path::ModPath::from_src(path, &hygiene)?), + &|path: ast::Path| resolver(path::ModPath::from_src(db, path, &hygiene)?), error_sink, ) .map(MacroCallId::from) diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs index ba027c44a..1bc72ec1f 100644 --- a/crates/hir_def/src/nameres.rs +++ b/crates/hir_def/src/nameres.rs @@ -599,6 +599,7 @@ mod diagnostics { let mut cur = 0; let mut tree = None; ModPath::expand_use_item( + db, InFile::new(ast.file_id, use_item), &hygiene, |_mod_path, use_tree, _is_glob, _alias| { diff --git a/crates/hir_def/src/path.rs b/crates/hir_def/src/path.rs index 509f77850..64bff318e 100644 --- a/crates/hir_def/src/path.rs +++ b/crates/hir_def/src/path.rs @@ -7,7 +7,7 @@ use std::{ sync::Arc, }; -use crate::{body::LowerCtx, intern::Interned, type_ref::LifetimeRef}; +use crate::{body::LowerCtx, db::DefDatabase, intern::Interned, type_ref::LifetimeRef}; use base_db::CrateId; use hir_expand::{ hygiene::Hygiene, @@ -47,9 +47,9 @@ pub enum ImportAlias { } impl ModPath { - pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option { - let ctx = LowerCtx::with_hygiene(hygiene); - lower::lower_path(path, &ctx).map(|it| (*it.mod_path).clone()) + pub fn from_src(db: &dyn DefDatabase, path: ast::Path, hygiene: &Hygiene) -> Option { + let ctx = LowerCtx::with_hygiene(db, hygiene); + lower::lower_path(db, path, &ctx).map(|it| (*it.mod_path).clone()) } pub fn from_segments(kind: PathKind, segments: impl IntoIterator) -> ModPath { @@ -64,12 +64,13 @@ impl ModPath { /// Calls `cb` with all paths, represented by this use item. pub(crate) fn expand_use_item( + db: &dyn DefDatabase, item_src: InFile, hygiene: &Hygiene, mut cb: impl FnMut(ModPath, &ast::UseTree, /* is_glob */ bool, Option), ) { if let Some(tree) = item_src.value.use_tree() { - lower::lower_use_tree(None, tree, hygiene, &mut cb); + lower::lower_use_tree(db, None, tree, hygiene, &mut cb); } } @@ -168,8 +169,8 @@ pub enum GenericArg { impl Path { /// Converts an `ast::Path` to `Path`. Works with use trees. /// It correctly handles `$crate` based path from macro call. - pub fn from_src(path: ast::Path, ctx: &LowerCtx) -> Option { - lower::lower_path(path, ctx) + pub fn from_src(db: &dyn DefDatabase, path: ast::Path, ctx: &LowerCtx) -> Option { + lower::lower_path(db, path, ctx) } /// Converts a known mod path to `Path`. diff --git a/crates/hir_def/src/path/lower.rs b/crates/hir_def/src/path/lower.rs index 1df6db525..3b3a3738f 100644 --- a/crates/hir_def/src/path/lower.rs +++ b/crates/hir_def/src/path/lower.rs @@ -2,7 +2,7 @@ mod lower_use; -use crate::intern::Interned; +use crate::{db::DefDatabase, intern::Interned}; use std::sync::Arc; use either::Either; @@ -20,7 +20,11 @@ pub(super) use lower_use::lower_use_tree; /// Converts an `ast::Path` to `Path`. Works with use trees. /// It correctly handles `$crate` based path from macro call. -pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx) -> Option { +pub(super) fn lower_path( + db: &dyn DefDatabase, + mut path: ast::Path, + ctx: &LowerCtx, +) -> Option { let mut kind = PathKind::Plain; let mut type_anchor = None; let mut segments = Vec::new(); @@ -36,7 +40,7 @@ pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx) -> Option { match segment.kind()? { ast::PathSegmentKind::Name(name_ref) => { // FIXME: this should just return name - match hygiene.name_ref_to_name(name_ref) { + match hygiene.name_ref_to_name(db.upcast(), name_ref) { Either::Left(name) => { let args = segment .generic_arg_list() @@ -71,7 +75,7 @@ pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx) -> Option { } // >::Foo desugars to Trait::Foo Some(trait_ref) => { - let path = Path::from_src(trait_ref.path()?, ctx)?; + let path = Path::from_src(db, trait_ref.path()?, ctx)?; let mod_path = (*path.mod_path).clone(); let num_segments = path.mod_path.segments.len(); kind = mod_path.kind; @@ -133,7 +137,7 @@ pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx) -> Option { // We follow what it did anyway :) if segments.len() == 1 && kind == PathKind::Plain { if let Some(_macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) { - if let Some(crate_id) = hygiene.local_inner_macros(path) { + if let Some(crate_id) = hygiene.local_inner_macros(db.upcast(), path) { kind = PathKind::DollarCrate(crate_id); } } diff --git a/crates/hir_def/src/path/lower/lower_use.rs b/crates/hir_def/src/path/lower/lower_use.rs index e2965b033..ee80e3df3 100644 --- a/crates/hir_def/src/path/lower/lower_use.rs +++ b/crates/hir_def/src/path/lower/lower_use.rs @@ -7,9 +7,13 @@ use either::Either; use hir_expand::{hygiene::Hygiene, name::AsName}; use syntax::ast::{self, NameOwner}; -use crate::path::{ImportAlias, ModPath, PathKind}; +use crate::{ + db::DefDatabase, + path::{ImportAlias, ModPath, PathKind}, +}; pub(crate) fn lower_use_tree( + db: &dyn DefDatabase, prefix: Option, tree: ast::UseTree, hygiene: &Hygiene, @@ -21,13 +25,13 @@ pub(crate) fn lower_use_tree( None => prefix, // E.g. `use something::{inner}` (prefix is `None`, path is `something`) // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`) - Some(path) => match convert_path(prefix, path, hygiene) { + Some(path) => match convert_path(db, prefix, path, hygiene) { Some(it) => Some(it), None => return, // FIXME: report errors somewhere }, }; for child_tree in use_tree_list.use_trees() { - lower_use_tree(prefix.clone(), child_tree, hygiene, cb); + lower_use_tree(db, prefix.clone(), child_tree, hygiene, cb); } } else { let alias = tree.rename().map(|a| { @@ -47,7 +51,7 @@ pub(crate) fn lower_use_tree( } } } - if let Some(path) = convert_path(prefix, ast_path, hygiene) { + if let Some(path) = convert_path(db, prefix, ast_path, hygiene) { cb(path, &tree, is_glob, alias) } // FIXME: report errors somewhere @@ -61,9 +65,14 @@ pub(crate) fn lower_use_tree( } } -fn convert_path(prefix: Option, path: ast::Path, hygiene: &Hygiene) -> Option { +fn convert_path( + db: &dyn DefDatabase, + prefix: Option, + path: ast::Path, + hygiene: &Hygiene, +) -> Option { let prefix = if let Some(qual) = path.qualifier() { - Some(convert_path(prefix, qual, hygiene)?) + Some(convert_path(db, prefix, qual, hygiene)?) } else { prefix }; @@ -71,7 +80,7 @@ fn convert_path(prefix: Option, path: ast::Path, hygiene: &Hygiene) -> let segment = path.segment()?; let res = match segment.kind()? { ast::PathSegmentKind::Name(name_ref) => { - match hygiene.name_ref_to_name(name_ref) { + match hygiene.name_ref_to_name(db.upcast(), name_ref) { Either::Left(name) => { // no type args in use let mut res = prefix.unwrap_or_else(|| { diff --git a/crates/hir_def/src/visibility.rs b/crates/hir_def/src/visibility.rs index d4b7c9970..83500f54e 100644 --- a/crates/hir_def/src/visibility.rs +++ b/crates/hir_def/src/visibility.rs @@ -33,17 +33,19 @@ impl RawVisibility { db: &dyn DefDatabase, node: InFile>, ) -> RawVisibility { - Self::from_ast_with_hygiene(node.value, &Hygiene::new(db.upcast(), node.file_id)) + Self::from_ast_with_hygiene(db, node.value, &Hygiene::new(db.upcast(), node.file_id)) } pub(crate) fn from_ast_with_hygiene( + db: &dyn DefDatabase, node: Option, hygiene: &Hygiene, ) -> RawVisibility { - Self::from_ast_with_hygiene_and_default(node, RawVisibility::private(), hygiene) + Self::from_ast_with_hygiene_and_default(db, node, RawVisibility::private(), hygiene) } pub(crate) fn from_ast_with_hygiene_and_default( + db: &dyn DefDatabase, node: Option, default: RawVisibility, hygiene: &Hygiene, @@ -54,7 +56,7 @@ impl RawVisibility { }; match node.kind() { ast::VisibilityKind::In(path) => { - let path = ModPath::from_src(path, hygiene); + let path = ModPath::from_src(db, path, hygiene); let path = match path { None => return RawVisibility::private(), Some(path) => path, diff --git a/crates/hir_expand/src/hygiene.rs b/crates/hir_expand/src/hygiene.rs index ed61ebca3..aca69e35a 100644 --- a/crates/hir_expand/src/hygiene.rs +++ b/crates/hir_expand/src/hygiene.rs @@ -32,10 +32,14 @@ impl Hygiene { } // FIXME: this should just return name - pub fn name_ref_to_name(&self, name_ref: ast::NameRef) -> Either { + pub fn name_ref_to_name( + &self, + db: &dyn AstDatabase, + name_ref: ast::NameRef, + ) -> Either { if let Some(frames) = &self.frames { if name_ref.text() == "$crate" { - if let Some(krate) = frames.root_crate(name_ref.syntax()) { + if let Some(krate) = frames.root_crate(db, name_ref.syntax()) { return Either::Right(krate); } } @@ -44,15 +48,19 @@ impl Hygiene { Either::Left(name_ref.as_name()) } - pub fn local_inner_macros(&self, path: ast::Path) -> Option { + pub fn local_inner_macros(&self, db: &dyn AstDatabase, path: ast::Path) -> Option { let mut token = path.syntax().first_token()?.text_range(); let frames = self.frames.as_ref()?; let mut current = frames.0.clone(); loop { - let (mapped, origin) = current.expansion.as_ref()?.map_ident_up(token)?; + let (mapped, origin) = current.expansion.as_ref()?.map_ident_up(db, token)?; if origin == Origin::Def { - return if current.local_inner { frames.root_crate(path.syntax()) } else { None }; + return if current.local_inner { + frames.root_crate(db, path.syntax()) + } else { + None + }; } current = current.call_site.as_ref()?.clone(); token = mapped.value; @@ -82,13 +90,13 @@ impl HygieneFrames { HygieneFrames(Arc::new(HygieneFrame::new(db, file_id))) } - fn root_crate(&self, node: &SyntaxNode) -> Option { + fn root_crate(&self, db: &dyn AstDatabase, node: &SyntaxNode) -> Option { let mut token = node.first_token()?.text_range(); let mut result = self.0.krate; let mut current = self.0.clone(); while let Some((mapped, origin)) = - current.expansion.as_ref().and_then(|it| it.map_ident_up(token)) + current.expansion.as_ref().and_then(|it| it.map_ident_up(db, token)) { result = current.krate; @@ -112,7 +120,7 @@ impl HygieneFrames { #[derive(Debug, Clone, PartialEq, Eq)] struct HygieneInfo { - arg_start: InFile, + file: MacroFile, /// The `macro_rules!` arguments. def_start: Option>, @@ -122,12 +130,24 @@ struct HygieneInfo { } impl HygieneInfo { - fn map_ident_up(&self, token: TextRange) -> Option<(InFile, Origin)> { + fn map_ident_up( + &self, + db: &dyn AstDatabase, + token: TextRange, + ) -> Option<(InFile, Origin)> { let token_id = self.exp_map.token_by_range(token)?; let (token_id, origin) = self.macro_def.map_id_up(token_id); let (token_map, tt) = match origin { - mbe::Origin::Call => (&self.macro_arg.1, self.arg_start), + mbe::Origin::Call => { + let call_id = match self.file.macro_call_id { + MacroCallId::LazyMacro(lazy) => lazy, + MacroCallId::EagerMacro(_) => unreachable!(), + }; + let loc: MacroCallLoc = db.lookup_intern_macro(call_id); + let arg_start = loc.kind.arg(db)?.text_range().start(); + (&self.macro_arg.1, InFile::new(loc.kind.file_id(), arg_start)) + } mbe::Origin::Def => match (&*self.macro_def, self.def_start) { (TokenExpander::MacroDef { def_site_token_map, .. }, Some(tt)) | (TokenExpander::MacroRules { def_site_token_map, .. }, Some(tt)) => { @@ -147,8 +167,6 @@ fn make_hygiene_info( macro_file: MacroFile, loc: &MacroCallLoc, ) -> Option { - let arg_tt = loc.kind.arg(db)?; - let def_offset = loc.def.ast_id().left().and_then(|id| { let def_tt = match id.to_node(db) { ast::Macro::MacroRules(mac) => mac.token_tree()?.syntax().text_range().start(), @@ -161,13 +179,7 @@ fn make_hygiene_info( let (_, exp_map) = db.parse_macro_expansion(macro_file).value?; let macro_arg = db.macro_arg(macro_file.macro_call_id)?; - Some(HygieneInfo { - arg_start: InFile::new(loc.kind.file_id(), arg_tt.text_range().start()), - def_start: def_offset, - macro_arg, - macro_def, - exp_map, - }) + Some(HygieneInfo { file: macro_file, def_start: def_offset, macro_arg, macro_def, exp_map }) } impl HygieneFrame { @@ -178,7 +190,8 @@ impl HygieneFrame { MacroCallId::EagerMacro(_id) => (None, None, false), MacroCallId::LazyMacro(id) => { let loc = db.lookup_intern_macro(id); - let info = make_hygiene_info(db, macro_file, &loc); + let info = make_hygiene_info(db, macro_file, &loc) + .map(|info| (loc.kind.file_id(), info)); match loc.def.kind { MacroDefKind::Declarative(_) => { (info, Some(loc.def.krate), loc.def.local_inner) @@ -192,7 +205,7 @@ impl HygieneFrame { }, }; - let info = match info { + let (calling_file, info) = match info { None => { return HygieneFrame { expansion: None, @@ -206,7 +219,7 @@ impl HygieneFrame { }; let def_site = info.def_start.map(|it| db.hygiene_frame(it.file_id)); - let call_site = Some(db.hygiene_frame(info.arg_start.file_id)); + let call_site = Some(db.hygiene_frame(calling_file)); HygieneFrame { expansion: Some(info), local_inner, krate, call_site, def_site } } diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs index 4fb7d9cf2..f452edc61 100644 --- a/crates/hir_ty/src/display.rs +++ b/crates/hir_ty/src/display.rs @@ -1000,9 +1000,9 @@ impl HirDisplay for TypeRef { } TypeRef::Macro(macro_call) => { let macro_call = macro_call.to_node(f.db.upcast()); - let ctx = body::LowerCtx::with_hygiene(&Hygiene::new_unhygienic()); + let ctx = body::LowerCtx::with_hygiene(f.db.upcast(), &Hygiene::new_unhygienic()); match macro_call.path() { - Some(path) => match Path::from_src(path, &ctx) { + Some(path) => match Path::from_src(f.db.upcast(), path, &ctx) { Some(path) => path.hir_fmt(f)?, None => write!(f, "{{macro}}")?, }, -- cgit v1.2.3 From 548e5a5c29bb0b453ef170e65d45a6673d8443f1 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 4 May 2021 15:31:23 +0300 Subject: internal: add failing incremental test --- crates/hir_def/src/nameres/tests/incremental.rs | 52 +++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/crates/hir_def/src/nameres/tests/incremental.rs b/crates/hir_def/src/nameres/tests/incremental.rs index 509e1bbbc..747407ec7 100644 --- a/crates/hir_def/src/nameres/tests/incremental.rs +++ b/crates/hir_def/src/nameres/tests/incremental.rs @@ -105,3 +105,55 @@ fn typing_inside_a_macro_should_not_invalidate_def_map() { assert!(!format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) } } + +#[test] +fn typing_inside_a_function_doe_should_not_invalidate_expansions() { + let (mut db, pos) = TestDB::with_position( + r#" +//- /lib.rs +macro_rules! m { + ($ident:ident) => { + fn $ident() { }; + } +} +mod foo; + +//- /foo/mod.rs +pub mod bar; + +//- /foo/bar.rs +m!(X); +fn quux() { 1$0 } +m!(Y); +m!(Z); +"#, + ); + let krate = db.test_crate(); + { + let events = db.log_executed(|| { + let crate_def_map = db.crate_def_map(krate); + let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); + assert_eq!(module_data.scope.resolutions().count(), 4); + }); + let n_recalculated_item_trees = events.iter().filter(|it| it.contains("item_tree")).count(); + assert_eq!(n_recalculated_item_trees, 6); + } + + let new_text = r#" +m!(X); +fn quux() { 92 } +m!(Y); +m!(Z); +"#; + db.set_file_text(pos.file_id, Arc::new(new_text.to_string())); + + { + let events = db.log_executed(|| { + let crate_def_map = db.crate_def_map(krate); + let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); + assert_eq!(module_data.scope.resolutions().count(), 4); + }); + let n_recalculated_item_trees = events.iter().filter(|it| it.contains("item_tree")).count(); + assert_eq!(n_recalculated_item_trees, 1); + } +} -- cgit v1.2.3 From c4f9cb9b53314b584f6451908ce40bbd65453116 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 4 May 2021 17:12:35 +0300 Subject: Update crates/hir_def/src/nameres/tests/incremental.rs Co-authored-by: Jonas Schievink --- crates/hir_def/src/nameres/tests/incremental.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/hir_def/src/nameres/tests/incremental.rs b/crates/hir_def/src/nameres/tests/incremental.rs index 747407ec7..227ecd162 100644 --- a/crates/hir_def/src/nameres/tests/incremental.rs +++ b/crates/hir_def/src/nameres/tests/incremental.rs @@ -107,7 +107,7 @@ fn typing_inside_a_macro_should_not_invalidate_def_map() { } #[test] -fn typing_inside_a_function_doe_should_not_invalidate_expansions() { +fn typing_inside_a_function_should_not_invalidate_expansions() { let (mut db, pos) = TestDB::with_position( r#" //- /lib.rs -- cgit v1.2.3 From 20ae41c1a12963e938cb3bd4c7c84007412d6fa6 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Thu, 6 May 2021 23:23:50 +0200 Subject: Reuse database in LowerCtx --- crates/hir/src/semantics.rs | 2 +- crates/hir/src/source_analyzer.rs | 5 ++--- crates/hir_def/src/body.rs | 2 +- crates/hir_def/src/body/lower.rs | 4 ++-- crates/hir_def/src/path.rs | 6 +++--- crates/hir_def/src/path/lower.rs | 14 +++++--------- crates/hir_ty/src/display.rs | 2 +- 7 files changed, 15 insertions(+), 20 deletions(-) diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index d53d81c07..62500602a 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -855,7 +855,7 @@ impl<'a> SemanticsScope<'a> { /// necessary a heuristic, as it doesn't take hygiene into account. pub fn speculative_resolve(&self, path: &ast::Path) -> Option { let ctx = body::LowerCtx::new(self.db.upcast(), self.file_id); - let path = Path::from_src(self.db.upcast(), path.clone(), &ctx)?; + let path = Path::from_src(path.clone(), &ctx)?; resolve_hir_path(self.db, &self.resolver, &path) } } diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index 186421cbd..b5c65808e 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -204,8 +204,7 @@ impl SourceAnalyzer { macro_call: InFile<&ast::MacroCall>, ) -> Option { let ctx = body::LowerCtx::new(db.upcast(), macro_call.file_id); - let path = - macro_call.value.path().and_then(|ast| Path::from_src(db.upcast(), ast, &ctx))?; + let path = macro_call.value.path().and_then(|ast| Path::from_src(ast, &ctx))?; self.resolver.resolve_path_as_macro(db.upcast(), path.mod_path()).map(|it| it.into()) } @@ -285,7 +284,7 @@ impl SourceAnalyzer { // This must be a normal source file rather than macro file. let hygiene = Hygiene::new(db.upcast(), self.file_id); let ctx = body::LowerCtx::with_hygiene(db.upcast(), &hygiene); - let hir_path = Path::from_src(db.upcast(), path.clone(), &ctx)?; + let hir_path = Path::from_src(path.clone(), &ctx)?; // Case where path is a qualifier of another path, e.g. foo::bar::Baz where we // trying to resolve foo::bar. diff --git a/crates/hir_def/src/body.rs b/crates/hir_def/src/body.rs index 9510a8575..8360426f1 100644 --- a/crates/hir_def/src/body.rs +++ b/crates/hir_def/src/body.rs @@ -194,7 +194,7 @@ impl Expander { fn parse_path(&mut self, db: &dyn DefDatabase, path: ast::Path) -> Option { let ctx = LowerCtx::with_hygiene(db, &self.cfg_expander.hygiene); - Path::from_src(db, path, &ctx) + Path::from_src(path, &ctx) } fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option { diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs index e4fa7f9c9..75dc19c11 100644 --- a/crates/hir_def/src/body/lower.rs +++ b/crates/hir_def/src/body/lower.rs @@ -41,7 +41,7 @@ use crate::{ use super::{diagnostics::BodyDiagnostic, ExprSource, PatSource}; pub struct LowerCtx<'a> { - db: &'a dyn DefDatabase, + pub db: &'a dyn DefDatabase, hygiene: Hygiene, file_id: Option, source_ast_id_map: Option>, @@ -70,7 +70,7 @@ impl<'a> LowerCtx<'a> { } pub(crate) fn lower_path(&self, ast: ast::Path) -> Option { - Path::from_src(self.db, ast, self) + Path::from_src(ast, self) } pub(crate) fn ast_id(&self, item: &N) -> Option> { diff --git a/crates/hir_def/src/path.rs b/crates/hir_def/src/path.rs index 64bff318e..a43441b1c 100644 --- a/crates/hir_def/src/path.rs +++ b/crates/hir_def/src/path.rs @@ -49,7 +49,7 @@ pub enum ImportAlias { impl ModPath { pub fn from_src(db: &dyn DefDatabase, path: ast::Path, hygiene: &Hygiene) -> Option { let ctx = LowerCtx::with_hygiene(db, hygiene); - lower::lower_path(db, path, &ctx).map(|it| (*it.mod_path).clone()) + lower::lower_path(path, &ctx).map(|it| (*it.mod_path).clone()) } pub fn from_segments(kind: PathKind, segments: impl IntoIterator) -> ModPath { @@ -169,8 +169,8 @@ pub enum GenericArg { impl Path { /// Converts an `ast::Path` to `Path`. Works with use trees. /// It correctly handles `$crate` based path from macro call. - pub fn from_src(db: &dyn DefDatabase, path: ast::Path, ctx: &LowerCtx) -> Option { - lower::lower_path(db, path, ctx) + pub fn from_src(path: ast::Path, ctx: &LowerCtx) -> Option { + lower::lower_path(path, ctx) } /// Converts a known mod path to `Path`. diff --git a/crates/hir_def/src/path/lower.rs b/crates/hir_def/src/path/lower.rs index 3b3a3738f..a873325b2 100644 --- a/crates/hir_def/src/path/lower.rs +++ b/crates/hir_def/src/path/lower.rs @@ -2,7 +2,7 @@ mod lower_use; -use crate::{db::DefDatabase, intern::Interned}; +use crate::intern::Interned; use std::sync::Arc; use either::Either; @@ -20,11 +20,7 @@ pub(super) use lower_use::lower_use_tree; /// Converts an `ast::Path` to `Path`. Works with use trees. /// It correctly handles `$crate` based path from macro call. -pub(super) fn lower_path( - db: &dyn DefDatabase, - mut path: ast::Path, - ctx: &LowerCtx, -) -> Option { +pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx) -> Option { let mut kind = PathKind::Plain; let mut type_anchor = None; let mut segments = Vec::new(); @@ -40,7 +36,7 @@ pub(super) fn lower_path( match segment.kind()? { ast::PathSegmentKind::Name(name_ref) => { // FIXME: this should just return name - match hygiene.name_ref_to_name(db.upcast(), name_ref) { + match hygiene.name_ref_to_name(ctx.db.upcast(), name_ref) { Either::Left(name) => { let args = segment .generic_arg_list() @@ -75,7 +71,7 @@ pub(super) fn lower_path( } // >::Foo desugars to Trait::Foo Some(trait_ref) => { - let path = Path::from_src(db, trait_ref.path()?, ctx)?; + let path = Path::from_src(trait_ref.path()?, ctx)?; let mod_path = (*path.mod_path).clone(); let num_segments = path.mod_path.segments.len(); kind = mod_path.kind; @@ -137,7 +133,7 @@ pub(super) fn lower_path( // We follow what it did anyway :) if segments.len() == 1 && kind == PathKind::Plain { if let Some(_macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) { - if let Some(crate_id) = hygiene.local_inner_macros(db.upcast(), path) { + if let Some(crate_id) = hygiene.local_inner_macros(ctx.db.upcast(), path) { kind = PathKind::DollarCrate(crate_id); } } diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs index f452edc61..1f6edf7a2 100644 --- a/crates/hir_ty/src/display.rs +++ b/crates/hir_ty/src/display.rs @@ -1002,7 +1002,7 @@ impl HirDisplay for TypeRef { let macro_call = macro_call.to_node(f.db.upcast()); let ctx = body::LowerCtx::with_hygiene(f.db.upcast(), &Hygiene::new_unhygienic()); match macro_call.path() { - Some(path) => match Path::from_src(f.db.upcast(), path, &ctx) { + Some(path) => match Path::from_src(path, &ctx) { Some(path) => path.hir_fmt(f)?, None => write!(f, "{{macro}}")?, }, -- cgit v1.2.3