8746: Don't store call-site text offsets in hygiene info r=matklad a=jonas-schievink

This threads a lot more database references around in order to avoid storing a bare `TextOffset` in the hygiene info. This `TextOffset` made hygiene info and `ItemTree`s more volatile than they should be, leading to excessive recomputation of `ItemTree`s.

The incremental test added in https://github.com/rust-analyzer/rust-analyzer/pull/8721 is now passing with these changes.

closes https://github.com/rust-analyzer/rust-analyzer/pull/8721

Co-authored-by: Jonas Schievink <jonasschievink@gmail.com>
Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
bors[bot] 2021-05-06 21:53:05 +00:00 committed by GitHub
commit 6fccb152b4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 180 additions and 81 deletions

View file

@ -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" }

View file

@ -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) {

View file

@ -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 {

View file

@ -283,7 +283,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(&hygiene);
let ctx = body::LowerCtx::with_hygiene(db.upcast(), &hygiene);
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

View file

@ -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<Attr> {
let path = Interned::new(ModPath::from_src(ast.path()?, hygiene)?);
fn from_src(
db: &dyn DefDatabase,
ast: ast::Attr,
hygiene: &Hygiene,
id: AttrId,
) -> Option<Attr> {
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(),

View file

@ -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,8 +192,8 @@ impl Expander {
self.current_file_id
}
fn parse_path(&mut self, path: ast::Path) -> Option<Path> {
let ctx = LowerCtx::with_hygiene(&self.cfg_expander.hygiene);
fn parse_path(&mut self, db: &dyn DefDatabase, path: ast::Path) -> Option<Path> {
let ctx = LowerCtx::with_hygiene(db, &self.cfg_expander.hygiene);
Path::from_src(path, &ctx)
}

View file

@ -40,23 +40,25 @@ use crate::{
use super::{diagnostics::BodyDiagnostic, ExprSource, PatSource};
pub struct LowerCtx {
pub struct LowerCtx<'a> {
pub db: &'a dyn DefDatabase,
hygiene: Hygiene,
file_id: Option<HirFileId>,
source_ast_id_map: Option<Arc<AstIdMap>>,
}
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 {
@ -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")

View file

@ -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

View file

@ -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) => {

View file

@ -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<AstIdMap>,
body_ctx: crate::body::LowerCtx,
body_ctx: crate::body::LowerCtx<'a>,
forced_visibility: Option<RawVisibilityId>,
}
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(&param, &self.hygiene));
self.add_attrs(idx.into(), RawAttrs::new(self.db, &param, &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<FileItemTreeId<MacroCall>> {
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)

View file

@ -654,7 +654,7 @@ impl AsMacroCall for InFile<&ast::MacroCall> {
) -> Result<Result<MacroCallId, ErrorEmitted>, 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)

View file

@ -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| {

View file

@ -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_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);
}
}

View file

@ -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,8 +47,8 @@ pub enum ImportAlias {
}
impl ModPath {
pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> {
let ctx = LowerCtx::with_hygiene(hygiene);
pub fn from_src(db: &dyn DefDatabase, path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> {
let ctx = LowerCtx::with_hygiene(db, hygiene);
lower::lower_path(path, &ctx).map(|it| (*it.mod_path).clone())
}
@ -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<ast::Use>,
hygiene: &Hygiene,
mut cb: impl FnMut(ModPath, &ast::UseTree, /* is_glob */ bool, Option<ImportAlias>),
) {
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);
}
}

View file

@ -36,7 +36,7 @@ pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx) -> Option<Path> {
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(ctx.db.upcast(), name_ref) {
Either::Left(name) => {
let args = segment
.generic_arg_list()
@ -133,7 +133,7 @@ pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx) -> Option<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(path) {
if let Some(crate_id) = hygiene.local_inner_macros(ctx.db.upcast(), path) {
kind = PathKind::DollarCrate(crate_id);
}
}

View file

@ -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<ModPath>,
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<ModPath>, path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> {
fn convert_path(
db: &dyn DefDatabase,
prefix: Option<ModPath>,
path: ast::Path,
hygiene: &Hygiene,
) -> Option<ModPath> {
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<ModPath>, 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(|| {

View file

@ -33,17 +33,19 @@ impl RawVisibility {
db: &dyn DefDatabase,
node: InFile<Option<ast::Visibility>>,
) -> 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<ast::Visibility>,
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<ast::Visibility>,
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,

View file

@ -32,10 +32,14 @@ impl Hygiene {
}
// FIXME: this should just return name
pub fn name_ref_to_name(&self, name_ref: ast::NameRef) -> Either<Name, CrateId> {
pub fn name_ref_to_name(
&self,
db: &dyn AstDatabase,
name_ref: ast::NameRef,
) -> Either<Name, CrateId> {
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<CrateId> {
pub fn local_inner_macros(&self, db: &dyn AstDatabase, path: ast::Path) -> Option<CrateId> {
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<CrateId> {
fn root_crate(&self, db: &dyn AstDatabase, node: &SyntaxNode) -> Option<CrateId> {
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<TextSize>,
file: MacroFile,
/// The `macro_rules!` arguments.
def_start: Option<InFile<TextSize>>,
@ -122,12 +130,24 @@ struct HygieneInfo {
}
impl HygieneInfo {
fn map_ident_up(&self, token: TextRange) -> Option<(InFile<TextRange>, Origin)> {
fn map_ident_up(
&self,
db: &dyn AstDatabase,
token: TextRange,
) -> Option<(InFile<TextRange>, 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<HygieneInfo> {
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 }
}

View file

@ -1000,7 +1000,7 @@ 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) => path.hir_fmt(f)?,