Don't store call-site text offsets in hygiene info

This commit is contained in:
Jonas Schievink 2021-05-06 19:59:54 +02:00
parent b37b709459
commit 976a3226fe
19 changed files with 145 additions and 93 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" } # chalk-recursive = { path = "../chalk/chalk-recursive" }
# ungrammar = { path = "../ungrammar" } # ungrammar = { path = "../ungrammar" }
# salsa = { path = "../salsa" }

View file

@ -112,7 +112,7 @@ fn resolve_doc_path(
AttrDefId::MacroDefId(_) => return None, AttrDefId::MacroDefId(_) => return None,
}; };
let path = ast::Path::parse(link).ok()?; 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); let resolved = resolver.resolve_module_path_in_items(db.upcast(), &modpath);
if resolved == PerNs::none() { if resolved == PerNs::none() {
if let Some(trait_id) = resolver.resolve_module_path_in_trait_items(db.upcast(), &modpath) { if let Some(trait_id) = resolver.resolve_module_path_in_trait_items(db.upcast(), &modpath) {

View file

@ -1666,7 +1666,7 @@ impl Impl {
.value .value
.attrs() .attrs()
.filter_map(|it| { .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" { if path.as_ident()?.to_string() == "derive" {
Some(it) Some(it)
} else { } else {

View file

@ -855,7 +855,7 @@ impl<'a> SemanticsScope<'a> {
/// necessary a heuristic, as it doesn't take hygiene into account. /// necessary a heuristic, as it doesn't take hygiene into account.
pub fn speculative_resolve(&self, path: &ast::Path) -> Option<PathResolution> { pub fn speculative_resolve(&self, path: &ast::Path) -> Option<PathResolution> {
let ctx = body::LowerCtx::new(self.db.upcast(), self.file_id); 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) resolve_hir_path(self.db, &self.resolver, &path)
} }
} }

View file

@ -204,7 +204,8 @@ impl SourceAnalyzer {
macro_call: InFile<&ast::MacroCall>, macro_call: InFile<&ast::MacroCall>,
) -> Option<MacroDef> { ) -> Option<MacroDef> {
let ctx = body::LowerCtx::new(db.upcast(), macro_call.file_id); 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()) 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. // This must be a normal source file rather than macro file.
let hygiene = Hygiene::new(db.upcast(), self.file_id); 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)?; 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 // Case where path is a qualifier of another path, e.g. foo::bar::Baz where we
// trying to resolve foo::bar. // trying to resolve foo::bar.

View file

@ -95,13 +95,17 @@ impl ops::Deref for AttrsWithOwner {
impl RawAttrs { impl RawAttrs {
pub(crate) const EMPTY: Self = Self { entries: None }; 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) let entries = collect_attrs(owner)
.enumerate() .enumerate()
.flat_map(|(i, attr)| { .flat_map(|(i, attr)| {
let index = AttrId(i as u32); let index = AttrId(i as u32);
match attr { 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 { Either::Right(comment) => comment.doc_comment().map(|doc| Attr {
id: index, id: index,
input: Some(AttrInput::Literal(SmolStr::new(doc))), 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 { fn from_attrs_owner(db: &dyn DefDatabase, owner: InFile<&dyn ast::AttrsOwner>) -> Self {
let hygiene = Hygiene::new(db.upcast(), owner.file_id); 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 { pub(crate) fn merge(&self, other: Self) -> Self {
@ -170,7 +174,7 @@ impl RawAttrs {
let attr = ast::Attr::parse(&format!("#[{}]", tree)).ok()?; let attr = ast::Attr::parse(&format!("#[{}]", tree)).ok()?;
// FIXME hygiene // FIXME hygiene
let hygiene = Hygiene::new_unhygienic(); 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; let cfg_options = &crate_graph[krate].cfg_options;
@ -627,8 +631,13 @@ pub enum AttrInput {
} }
impl Attr { impl Attr {
fn from_src(ast: ast::Attr, hygiene: &Hygiene, id: AttrId) -> Option<Attr> { fn from_src(
let path = Interned::new(ModPath::from_src(ast.path()?, hygiene)?); 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 input = if let Some(ast::Expr::Literal(lit)) = ast.expr() {
let value = match lit.kind() { let value = match lit.kind() {
ast::LiteralKind::String(string) => string.value()?.into(), 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 { 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 { 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 self.current_file_id
} }
fn parse_path(&mut self, path: ast::Path) -> Option<Path> { fn parse_path(&mut self, db: &dyn DefDatabase, path: ast::Path) -> Option<Path> {
let ctx = LowerCtx::with_hygiene(&self.cfg_expander.hygiene); let ctx = LowerCtx::with_hygiene(db, &self.cfg_expander.hygiene);
Path::from_src(path, &ctx) Path::from_src(db, path, &ctx)
} }
fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<MacroDefId> { fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<MacroDefId> {

View file

@ -40,23 +40,25 @@ use crate::{
use super::{diagnostics::BodyDiagnostic, ExprSource, PatSource}; use super::{diagnostics::BodyDiagnostic, ExprSource, PatSource};
pub struct LowerCtx { pub struct LowerCtx<'a> {
db: &'a dyn DefDatabase,
hygiene: Hygiene, hygiene: Hygiene,
file_id: Option<HirFileId>, file_id: Option<HirFileId>,
source_ast_id_map: Option<Arc<AstIdMap>>, source_ast_id_map: Option<Arc<AstIdMap>>,
} }
impl LowerCtx { impl<'a> LowerCtx<'a> {
pub fn new(db: &dyn DefDatabase, file_id: HirFileId) -> Self { pub fn new(db: &'a dyn DefDatabase, file_id: HirFileId) -> Self {
LowerCtx { LowerCtx {
db,
hygiene: Hygiene::new(db.upcast(), file_id), hygiene: Hygiene::new(db.upcast(), file_id),
file_id: Some(file_id), file_id: Some(file_id),
source_ast_id_map: Some(db.ast_id_map(file_id)), source_ast_id_map: Some(db.ast_id_map(file_id)),
} }
} }
pub fn with_hygiene(hygiene: &Hygiene) -> Self { pub fn with_hygiene(db: &'a dyn DefDatabase, hygiene: &Hygiene) -> Self {
LowerCtx { hygiene: hygiene.clone(), file_id: None, source_ast_id_map: None } LowerCtx { db, hygiene: hygiene.clone(), file_id: None, source_ast_id_map: None }
} }
pub(crate) fn hygiene(&self) -> &Hygiene { pub(crate) fn hygiene(&self) -> &Hygiene {
@ -68,7 +70,7 @@ impl LowerCtx {
} }
pub(crate) fn lower_path(&self, ast: ast::Path) -> Option<Path> { pub(crate) fn lower_path(&self, ast: ast::Path) -> Option<Path> {
Path::from_src(ast, self) Path::from_src(self.db, ast, self)
} }
pub(crate) fn ast_id<N: AstNode>(&self, item: &N) -> Option<FileAstId<N>> { pub(crate) fn ast_id<N: AstNode>(&self, item: &N) -> Option<FileAstId<N>> {
@ -145,7 +147,7 @@ impl ExprCollector<'_> {
(self.body, self.source_map) (self.body, self.source_map)
} }
fn ctx(&self) -> LowerCtx { fn ctx(&self) -> LowerCtx<'_> {
LowerCtx::new(self.db, self.expander.current_file_id) LowerCtx::new(self.db, self.expander.current_file_id)
} }
@ -376,7 +378,7 @@ impl ExprCollector<'_> {
ast::Expr::PathExpr(e) => { ast::Expr::PathExpr(e) => {
let path = e let path = e
.path() .path()
.and_then(|path| self.expander.parse_path(path)) .and_then(|path| self.expander.parse_path(self.db, path))
.map(Expr::Path) .map(Expr::Path)
.unwrap_or(Expr::Missing); .unwrap_or(Expr::Missing);
self.alloc_expr(path, syntax_ptr) self.alloc_expr(path, syntax_ptr)
@ -408,7 +410,8 @@ impl ExprCollector<'_> {
self.alloc_expr(Expr::Yield { expr }, syntax_ptr) self.alloc_expr(Expr::Yield { expr }, syntax_ptr)
} }
ast::Expr::RecordExpr(e) => { 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 record_lit = if let Some(nfl) = e.record_expr_field_list() {
let fields = nfl let fields = nfl
.fields() .fields()
@ -791,7 +794,8 @@ impl ExprCollector<'_> {
} }
} }
ast::Pat::TupleStructPat(p) => { 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()); let (args, ellipsis) = self.collect_tuple_pat(p.fields());
Pat::TupleStruct { path, args, ellipsis } Pat::TupleStruct { path, args, ellipsis }
} }
@ -801,7 +805,8 @@ impl ExprCollector<'_> {
Pat::Ref { pat, mutability } Pat::Ref { pat, mutability }
} }
ast::Pat::PathPat(p) => { 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) path.map(Pat::Path).unwrap_or(Pat::Missing)
} }
ast::Pat::OrPat(p) => { ast::Pat::OrPat(p) => {
@ -815,7 +820,8 @@ impl ExprCollector<'_> {
} }
ast::Pat::WildcardPat(_) => Pat::Wild, ast::Pat::WildcardPat(_) => Pat::Wild,
ast::Pat::RecordPat(p) => { 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 let args: Vec<_> = p
.record_pat_field_list() .record_pat_field_list()
.expect("every struct should have a 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 parsed_path_file = syntax::SourceFile::parse(&format!("use {};", path));
let ast_path = let ast_path =
parsed_path_file.syntax_node().descendants().find_map(syntax::ast::Path::cast).unwrap(); 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 def_map = module.def_map(&db);
let resolved = def_map let resolved = def_map

View file

@ -88,7 +88,7 @@ impl ItemTree {
let mut item_tree = match_ast! { let mut item_tree = match_ast! {
match syntax { match syntax {
ast::SourceFile(file) => { ast::SourceFile(file) => {
top_attrs = Some(RawAttrs::new(&file, &hygiene)); top_attrs = Some(RawAttrs::new(db, &file, &hygiene));
ctx.lower_module_items(&file) ctx.lower_module_items(&file)
}, },
ast::MacroItems(items) => { 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, tree: ItemTree,
hygiene: Hygiene, hygiene: Hygiene,
file: HirFileId, file: HirFileId,
source_ast_id_map: Arc<AstIdMap>, source_ast_id_map: Arc<AstIdMap>,
body_ctx: crate::body::LowerCtx, body_ctx: crate::body::LowerCtx<'a>,
forced_visibility: Option<RawVisibilityId>, forced_visibility: Option<RawVisibilityId>,
} }
impl Ctx { impl<'a> Ctx<'a> {
pub(super) fn new(db: &dyn DefDatabase, hygiene: Hygiene, file: HirFileId) -> Self { pub(super) fn new(db: &'a dyn DefDatabase, hygiene: Hygiene, file: HirFileId) -> Self {
Self { Self {
db,
tree: ItemTree::default(), tree: ItemTree::default(),
hygiene, hygiene,
file, file,
@ -126,7 +128,7 @@ impl Ctx {
| ast::Item::MacroDef(_) => {} | ast::Item::MacroDef(_) => {}
}; };
let attrs = RawAttrs::new(item, &self.hygiene); let attrs = RawAttrs::new(self.db, item, &self.hygiene);
let items = match item { let items = match item {
ast::Item::Struct(ast) => self.lower_struct(ast).map(Into::into), ast::Item::Struct(ast) => self.lower_struct(ast).map(Into::into),
ast::Item::Union(ast) => self.lower_union(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() { for field in fields.fields() {
if let Some(data) = self.lower_record_field(&field) { if let Some(data) = self.lower_record_field(&field) {
let idx = self.data().fields.alloc(data); 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(); let end = self.next_field_idx();
@ -276,7 +278,7 @@ impl Ctx {
for (i, field) in fields.fields().enumerate() { for (i, field) in fields.fields().enumerate() {
let data = self.lower_tuple_field(i, &field); let data = self.lower_tuple_field(i, &field);
let idx = self.data().fields.alloc(data); 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(); let end = self.next_field_idx();
IdRange::new(start..end) IdRange::new(start..end)
@ -321,7 +323,7 @@ impl Ctx {
for variant in variants.variants() { for variant in variants.variants() {
if let Some(data) = self.lower_variant(&variant) { if let Some(data) = self.lower_variant(&variant) {
let idx = self.data().variants.alloc(data); 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(); let end = self.next_variant_idx();
@ -364,7 +366,7 @@ impl Ctx {
}; };
let ty = Interned::new(self_type); let ty = Interned::new(self_type);
let idx = self.data().params.alloc(Param::Normal(ty)); 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; has_self_param = true;
} }
for param in param_list.params() { for param in param_list.params() {
@ -376,7 +378,7 @@ impl Ctx {
self.data().params.alloc(Param::Normal(ty)) 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(); let end_param = self.next_param_idx();
@ -522,10 +524,11 @@ impl Ctx {
let is_unsafe = trait_def.unsafe_token().is_some(); let is_unsafe = trait_def.unsafe_token().is_some();
let bounds = self.lower_type_bounds(trait_def); let bounds = self.lower_type_bounds(trait_def);
let items = trait_def.assoc_item_list().map(|list| { let items = trait_def.assoc_item_list().map(|list| {
let db = self.db;
self.with_inherited_visibility(visibility, |this| { self.with_inherited_visibility(visibility, |this| {
list.assoc_items() list.assoc_items()
.filter_map(|item| { .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.collect_inner_items(item.syntax());
this.lower_assoc_item(&item).map(|item| { this.lower_assoc_item(&item).map(|item| {
this.add_attrs(ModItem::from(item).into(), attrs); this.add_attrs(ModItem::from(item).into(), attrs);
@ -567,7 +570,7 @@ impl Ctx {
.filter_map(|item| { .filter_map(|item| {
self.collect_inner_items(item.syntax()); self.collect_inner_items(item.syntax());
let assoc = self.lower_assoc_item(&item)?; 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); self.add_attrs(ModItem::from(assoc).into(), attrs);
Some(assoc) Some(assoc)
}) })
@ -585,6 +588,7 @@ impl Ctx {
let mut imports = Vec::new(); let mut imports = Vec::new();
let tree = self.tree.data_mut(); let tree = self.tree.data_mut();
ModPath::expand_use_item( ModPath::expand_use_item(
self.db,
InFile::new(self.file, use_item.clone()), InFile::new(self.file, use_item.clone()),
&self.hygiene, &self.hygiene,
|path, _use_tree, is_glob, alias| { |path, _use_tree, is_glob, alias| {
@ -618,7 +622,7 @@ impl Ctx {
} }
fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option<FileItemTreeId<MacroCall>> { 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 ast_id = self.source_ast_id_map.ast_id(m);
let res = MacroCall { path, ast_id }; let res = MacroCall { path, ast_id };
Some(id(self.data().macro_calls.alloc(res))) Some(id(self.data().macro_calls.alloc(res)))
@ -647,7 +651,7 @@ impl Ctx {
list.extern_items() list.extern_items()
.filter_map(|item| { .filter_map(|item| {
self.collect_inner_items(item.syntax()); 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 { let id: ModItem = match item {
ast::ExternItem::Fn(ast) => { ast::ExternItem::Fn(ast) => {
let func_id = self.lower_function(&ast)?; let func_id = self.lower_function(&ast)?;
@ -755,7 +759,7 @@ impl Ctx {
fn lower_visibility(&mut self, item: &impl ast::VisibilityOwner) -> RawVisibilityId { fn lower_visibility(&mut self, item: &impl ast::VisibilityOwner) -> RawVisibilityId {
let vis = match self.forced_visibility { let vis = match self.forced_visibility {
Some(vis) => return vis, 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) self.data().vis.alloc(vis)

View file

@ -654,7 +654,7 @@ impl AsMacroCall for InFile<&ast::MacroCall> {
) -> Result<Result<MacroCallId, ErrorEmitted>, UnresolvedMacro> { ) -> 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 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 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 let path = match error_sink
.option(path, || mbe::ExpandError::Other("malformed macro invocation".into())) .option(path, || mbe::ExpandError::Other("malformed macro invocation".into()))
@ -712,7 +712,7 @@ fn macro_call_as_call_id(
krate, krate,
macro_call, macro_call,
def, def,
&|path: ast::Path| resolver(path::ModPath::from_src(path, &hygiene)?), &|path: ast::Path| resolver(path::ModPath::from_src(db, path, &hygiene)?),
error_sink, error_sink,
) )
.map(MacroCallId::from) .map(MacroCallId::from)

View file

@ -599,6 +599,7 @@ mod diagnostics {
let mut cur = 0; let mut cur = 0;
let mut tree = None; let mut tree = None;
ModPath::expand_use_item( ModPath::expand_use_item(
db,
InFile::new(ast.file_id, use_item), InFile::new(ast.file_id, use_item),
&hygiene, &hygiene,
|_mod_path, use_tree, _is_glob, _alias| { |_mod_path, use_tree, _is_glob, _alias| {

View file

@ -7,7 +7,7 @@ use std::{
sync::Arc, 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 base_db::CrateId;
use hir_expand::{ use hir_expand::{
hygiene::Hygiene, hygiene::Hygiene,
@ -47,9 +47,9 @@ pub enum ImportAlias {
} }
impl ModPath { impl ModPath {
pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> { pub fn from_src(db: &dyn DefDatabase, path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> {
let ctx = LowerCtx::with_hygiene(hygiene); let ctx = LowerCtx::with_hygiene(db, hygiene);
lower::lower_path(path, &ctx).map(|it| (*it.mod_path).clone()) lower::lower_path(db, path, &ctx).map(|it| (*it.mod_path).clone())
} }
pub fn from_segments(kind: PathKind, segments: impl IntoIterator<Item = Name>) -> ModPath { pub fn from_segments(kind: PathKind, segments: impl IntoIterator<Item = Name>) -> ModPath {
@ -64,12 +64,13 @@ impl ModPath {
/// Calls `cb` with all paths, represented by this use item. /// Calls `cb` with all paths, represented by this use item.
pub(crate) fn expand_use_item( pub(crate) fn expand_use_item(
db: &dyn DefDatabase,
item_src: InFile<ast::Use>, item_src: InFile<ast::Use>,
hygiene: &Hygiene, hygiene: &Hygiene,
mut cb: impl FnMut(ModPath, &ast::UseTree, /* is_glob */ bool, Option<ImportAlias>), mut cb: impl FnMut(ModPath, &ast::UseTree, /* is_glob */ bool, Option<ImportAlias>),
) { ) {
if let Some(tree) = item_src.value.use_tree() { 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 { impl Path {
/// Converts an `ast::Path` to `Path`. Works with use trees. /// Converts an `ast::Path` to `Path`. Works with use trees.
/// It correctly handles `$crate` based path from macro call. /// It correctly handles `$crate` based path from macro call.
pub fn from_src(path: ast::Path, ctx: &LowerCtx) -> Option<Path> { pub fn from_src(db: &dyn DefDatabase, path: ast::Path, ctx: &LowerCtx) -> Option<Path> {
lower::lower_path(path, ctx) lower::lower_path(db, path, ctx)
} }
/// Converts a known mod path to `Path`. /// Converts a known mod path to `Path`.

View file

@ -2,7 +2,7 @@
mod lower_use; mod lower_use;
use crate::intern::Interned; use crate::{db::DefDatabase, intern::Interned};
use std::sync::Arc; use std::sync::Arc;
use either::Either; 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. /// Converts an `ast::Path` to `Path`. Works with use trees.
/// It correctly handles `$crate` based path from macro call. /// It correctly handles `$crate` based path from macro call.
pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx) -> Option<Path> { pub(super) fn lower_path(
db: &dyn DefDatabase,
mut path: ast::Path,
ctx: &LowerCtx,
) -> Option<Path> {
let mut kind = PathKind::Plain; let mut kind = PathKind::Plain;
let mut type_anchor = None; let mut type_anchor = None;
let mut segments = Vec::new(); let mut segments = Vec::new();
@ -36,7 +40,7 @@ pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx) -> Option<Path> {
match segment.kind()? { match segment.kind()? {
ast::PathSegmentKind::Name(name_ref) => { ast::PathSegmentKind::Name(name_ref) => {
// FIXME: this should just return name // 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) => { Either::Left(name) => {
let args = segment let args = segment
.generic_arg_list() .generic_arg_list()
@ -71,7 +75,7 @@ pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx) -> Option<Path> {
} }
// <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo
Some(trait_ref) => { 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 mod_path = (*path.mod_path).clone();
let num_segments = path.mod_path.segments.len(); let num_segments = path.mod_path.segments.len();
kind = mod_path.kind; kind = mod_path.kind;
@ -133,7 +137,7 @@ pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx) -> Option<Path> {
// We follow what it did anyway :) // We follow what it did anyway :)
if segments.len() == 1 && kind == PathKind::Plain { if segments.len() == 1 && kind == PathKind::Plain {
if let Some(_macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) { 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); kind = PathKind::DollarCrate(crate_id);
} }
} }

View file

@ -7,9 +7,13 @@ use either::Either;
use hir_expand::{hygiene::Hygiene, name::AsName}; use hir_expand::{hygiene::Hygiene, name::AsName};
use syntax::ast::{self, NameOwner}; 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( pub(crate) fn lower_use_tree(
db: &dyn DefDatabase,
prefix: Option<ModPath>, prefix: Option<ModPath>,
tree: ast::UseTree, tree: ast::UseTree,
hygiene: &Hygiene, hygiene: &Hygiene,
@ -21,13 +25,13 @@ pub(crate) fn lower_use_tree(
None => prefix, None => prefix,
// E.g. `use something::{inner}` (prefix is `None`, path is `something`) // E.g. `use something::{inner}` (prefix is `None`, path is `something`)
// or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`) // 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), Some(it) => Some(it),
None => return, // FIXME: report errors somewhere None => return, // FIXME: report errors somewhere
}, },
}; };
for child_tree in use_tree_list.use_trees() { 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 { } else {
let alias = tree.rename().map(|a| { 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) cb(path, &tree, is_glob, alias)
} }
// FIXME: report errors somewhere // 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() { let prefix = if let Some(qual) = path.qualifier() {
Some(convert_path(prefix, qual, hygiene)?) Some(convert_path(db, prefix, qual, hygiene)?)
} else { } else {
prefix prefix
}; };
@ -71,7 +80,7 @@ fn convert_path(prefix: Option<ModPath>, path: ast::Path, hygiene: &Hygiene) ->
let segment = path.segment()?; let segment = path.segment()?;
let res = match segment.kind()? { let res = match segment.kind()? {
ast::PathSegmentKind::Name(name_ref) => { 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) => { Either::Left(name) => {
// no type args in use // no type args in use
let mut res = prefix.unwrap_or_else(|| { let mut res = prefix.unwrap_or_else(|| {

View file

@ -33,17 +33,19 @@ impl RawVisibility {
db: &dyn DefDatabase, db: &dyn DefDatabase,
node: InFile<Option<ast::Visibility>>, node: InFile<Option<ast::Visibility>>,
) -> RawVisibility { ) -> 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( pub(crate) fn from_ast_with_hygiene(
db: &dyn DefDatabase,
node: Option<ast::Visibility>, node: Option<ast::Visibility>,
hygiene: &Hygiene, hygiene: &Hygiene,
) -> RawVisibility { ) -> 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( pub(crate) fn from_ast_with_hygiene_and_default(
db: &dyn DefDatabase,
node: Option<ast::Visibility>, node: Option<ast::Visibility>,
default: RawVisibility, default: RawVisibility,
hygiene: &Hygiene, hygiene: &Hygiene,
@ -54,7 +56,7 @@ impl RawVisibility {
}; };
match node.kind() { match node.kind() {
ast::VisibilityKind::In(path) => { ast::VisibilityKind::In(path) => {
let path = ModPath::from_src(path, hygiene); let path = ModPath::from_src(db, path, hygiene);
let path = match path { let path = match path {
None => return RawVisibility::private(), None => return RawVisibility::private(),
Some(path) => path, Some(path) => path,

View file

@ -32,10 +32,14 @@ impl Hygiene {
} }
// FIXME: this should just return name // 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 let Some(frames) = &self.frames {
if name_ref.text() == "$crate" { 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); return Either::Right(krate);
} }
} }
@ -44,15 +48,19 @@ impl Hygiene {
Either::Left(name_ref.as_name()) 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 mut token = path.syntax().first_token()?.text_range();
let frames = self.frames.as_ref()?; let frames = self.frames.as_ref()?;
let mut current = frames.0.clone(); let mut current = frames.0.clone();
loop { 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 { 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(); current = current.call_site.as_ref()?.clone();
token = mapped.value; token = mapped.value;
@ -82,13 +90,13 @@ impl HygieneFrames {
HygieneFrames(Arc::new(HygieneFrame::new(db, file_id))) 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 token = node.first_token()?.text_range();
let mut result = self.0.krate; let mut result = self.0.krate;
let mut current = self.0.clone(); let mut current = self.0.clone();
while let Some((mapped, origin)) = 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; result = current.krate;
@ -112,7 +120,7 @@ impl HygieneFrames {
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
struct HygieneInfo { struct HygieneInfo {
arg_start: InFile<TextSize>, file: MacroFile,
/// The `macro_rules!` arguments. /// The `macro_rules!` arguments.
def_start: Option<InFile<TextSize>>, def_start: Option<InFile<TextSize>>,
@ -122,12 +130,24 @@ struct HygieneInfo {
} }
impl 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 = self.exp_map.token_by_range(token)?;
let (token_id, origin) = self.macro_def.map_id_up(token_id); let (token_id, origin) = self.macro_def.map_id_up(token_id);
let (token_map, tt) = match origin { 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) { mbe::Origin::Def => match (&*self.macro_def, self.def_start) {
(TokenExpander::MacroDef { def_site_token_map, .. }, Some(tt)) (TokenExpander::MacroDef { def_site_token_map, .. }, Some(tt))
| (TokenExpander::MacroRules { 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, macro_file: MacroFile,
loc: &MacroCallLoc, loc: &MacroCallLoc,
) -> Option<HygieneInfo> { ) -> Option<HygieneInfo> {
let arg_tt = loc.kind.arg(db)?;
let def_offset = loc.def.ast_id().left().and_then(|id| { let def_offset = loc.def.ast_id().left().and_then(|id| {
let def_tt = match id.to_node(db) { let def_tt = match id.to_node(db) {
ast::Macro::MacroRules(mac) => mac.token_tree()?.syntax().text_range().start(), 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 (_, exp_map) = db.parse_macro_expansion(macro_file).value?;
let macro_arg = db.macro_arg(macro_file.macro_call_id)?; let macro_arg = db.macro_arg(macro_file.macro_call_id)?;
Some(HygieneInfo { Some(HygieneInfo { file: macro_file, def_start: def_offset, macro_arg, macro_def, exp_map })
arg_start: InFile::new(loc.kind.file_id(), arg_tt.text_range().start()),
def_start: def_offset,
macro_arg,
macro_def,
exp_map,
})
} }
impl HygieneFrame { impl HygieneFrame {
@ -178,7 +190,8 @@ impl HygieneFrame {
MacroCallId::EagerMacro(_id) => (None, None, false), MacroCallId::EagerMacro(_id) => (None, None, false),
MacroCallId::LazyMacro(id) => { MacroCallId::LazyMacro(id) => {
let loc = db.lookup_intern_macro(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 { match loc.def.kind {
MacroDefKind::Declarative(_) => { MacroDefKind::Declarative(_) => {
(info, Some(loc.def.krate), loc.def.local_inner) (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 => { None => {
return HygieneFrame { return HygieneFrame {
expansion: None, expansion: None,
@ -206,7 +219,7 @@ impl HygieneFrame {
}; };
let def_site = info.def_start.map(|it| db.hygiene_frame(it.file_id)); 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 } HygieneFrame { expansion: Some(info), local_inner, krate, call_site, def_site }
} }

View file

@ -1000,9 +1000,9 @@ impl HirDisplay for TypeRef {
} }
TypeRef::Macro(macro_call) => { TypeRef::Macro(macro_call) => {
let macro_call = macro_call.to_node(f.db.upcast()); 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() { 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)?, Some(path) => path.hir_fmt(f)?,
None => write!(f, "{{macro}}")?, None => write!(f, "{{macro}}")?,
}, },