mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-14 14:13:58 +00:00
Move Expander and LowerCtx into separate modules
This commit is contained in:
parent
fd4bbcabe8
commit
bca8029a6e
25 changed files with 487 additions and 402 deletions
|
@ -28,8 +28,8 @@ use crate::{
|
||||||
lang_item::LangItem,
|
lang_item::LangItem,
|
||||||
nameres::{ModuleOrigin, ModuleSource},
|
nameres::{ModuleOrigin, ModuleSource},
|
||||||
src::{HasChildSource, HasSource},
|
src::{HasChildSource, HasSource},
|
||||||
AdtId, AttrDefId, EnumId, GenericParamId, LocalEnumVariantId, LocalFieldId, Lookup, MacroId,
|
AdtId, AssocItemLoc, AttrDefId, EnumId, GenericParamId, ItemLoc, LocalEnumVariantId,
|
||||||
VariantId,
|
LocalFieldId, Lookup, MacroId, VariantId,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Holds documentation
|
/// Holds documentation
|
||||||
|
@ -421,23 +421,24 @@ impl AttrsWithOwner {
|
||||||
AttrDefId::EnumVariantId(it) => {
|
AttrDefId::EnumVariantId(it) => {
|
||||||
return db.variants_attrs(it.parent)[it.local_id].clone();
|
return db.variants_attrs(it.parent)[it.local_id].clone();
|
||||||
}
|
}
|
||||||
|
// FIXME: DRY this up
|
||||||
AttrDefId::AdtId(it) => match it {
|
AttrDefId::AdtId(it) => match it {
|
||||||
AdtId::StructId(it) => attrs_from_item_tree(it.lookup(db).id, db),
|
AdtId::StructId(it) => attrs_from_item_tree_loc(db, it),
|
||||||
AdtId::EnumId(it) => attrs_from_item_tree(it.lookup(db).id, db),
|
AdtId::EnumId(it) => attrs_from_item_tree_loc(db, it),
|
||||||
AdtId::UnionId(it) => attrs_from_item_tree(it.lookup(db).id, db),
|
AdtId::UnionId(it) => attrs_from_item_tree_loc(db, it),
|
||||||
},
|
},
|
||||||
AttrDefId::TraitId(it) => attrs_from_item_tree(it.lookup(db).id, db),
|
AttrDefId::TraitId(it) => attrs_from_item_tree_loc(db, it),
|
||||||
AttrDefId::TraitAliasId(it) => attrs_from_item_tree(it.lookup(db).id, db),
|
AttrDefId::TraitAliasId(it) => attrs_from_item_tree_loc(db, it),
|
||||||
AttrDefId::MacroId(it) => match it {
|
AttrDefId::MacroId(it) => match it {
|
||||||
MacroId::Macro2Id(it) => attrs_from_item_tree(it.lookup(db).id, db),
|
MacroId::Macro2Id(it) => attrs_from_item_tree(db, it.lookup(db).id),
|
||||||
MacroId::MacroRulesId(it) => attrs_from_item_tree(it.lookup(db).id, db),
|
MacroId::MacroRulesId(it) => attrs_from_item_tree(db, it.lookup(db).id),
|
||||||
MacroId::ProcMacroId(it) => attrs_from_item_tree(it.lookup(db).id, db),
|
MacroId::ProcMacroId(it) => attrs_from_item_tree(db, it.lookup(db).id),
|
||||||
},
|
},
|
||||||
AttrDefId::ImplId(it) => attrs_from_item_tree(it.lookup(db).id, db),
|
AttrDefId::ImplId(it) => attrs_from_item_tree_loc(db, it),
|
||||||
AttrDefId::ConstId(it) => attrs_from_item_tree(it.lookup(db).id, db),
|
AttrDefId::ConstId(it) => attrs_from_item_tree_assoc(db, it),
|
||||||
AttrDefId::StaticId(it) => attrs_from_item_tree(it.lookup(db).id, db),
|
AttrDefId::StaticId(it) => attrs_from_item_tree_assoc(db, it),
|
||||||
AttrDefId::FunctionId(it) => attrs_from_item_tree(it.lookup(db).id, db),
|
AttrDefId::FunctionId(it) => attrs_from_item_tree_assoc(db, it),
|
||||||
AttrDefId::TypeAliasId(it) => attrs_from_item_tree(it.lookup(db).id, db),
|
AttrDefId::TypeAliasId(it) => attrs_from_item_tree_assoc(db, it),
|
||||||
AttrDefId::GenericParamId(it) => match it {
|
AttrDefId::GenericParamId(it) => match it {
|
||||||
GenericParamId::ConstParamId(it) => {
|
GenericParamId::ConstParamId(it) => {
|
||||||
let src = it.parent().child_source(db);
|
let src = it.parent().child_source(db);
|
||||||
|
@ -458,7 +459,7 @@ impl AttrsWithOwner {
|
||||||
RawAttrs::from_attrs_owner(db.upcast(), src.with_value(&src.value[it.local_id]))
|
RawAttrs::from_attrs_owner(db.upcast(), src.with_value(&src.value[it.local_id]))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
AttrDefId::ExternBlockId(it) => attrs_from_item_tree(it.lookup(db).id, db),
|
AttrDefId::ExternBlockId(it) => attrs_from_item_tree_loc(db, it),
|
||||||
};
|
};
|
||||||
|
|
||||||
let attrs = raw_attrs.filter(db.upcast(), def.krate(db));
|
let attrs = raw_attrs.filter(db.upcast(), def.krate(db));
|
||||||
|
@ -506,28 +507,28 @@ impl AttrsWithOwner {
|
||||||
InFile::new(file_id, owner)
|
InFile::new(file_id, owner)
|
||||||
}
|
}
|
||||||
AttrDefId::AdtId(adt) => match adt {
|
AttrDefId::AdtId(adt) => match adt {
|
||||||
AdtId::StructId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new),
|
AdtId::StructId(id) => any_has_attrs(db, id),
|
||||||
AdtId::UnionId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new),
|
AdtId::UnionId(id) => any_has_attrs(db, id),
|
||||||
AdtId::EnumId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new),
|
AdtId::EnumId(id) => any_has_attrs(db, id),
|
||||||
},
|
},
|
||||||
AttrDefId::FunctionId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new),
|
AttrDefId::FunctionId(id) => any_has_attrs(db, id),
|
||||||
AttrDefId::EnumVariantId(id) => {
|
AttrDefId::EnumVariantId(id) => {
|
||||||
let map = db.variants_attrs_source_map(id.parent);
|
let map = db.variants_attrs_source_map(id.parent);
|
||||||
let file_id = id.parent.lookup(db).id.file_id();
|
let file_id = id.parent.lookup(db).id.file_id();
|
||||||
let root = db.parse_or_expand(file_id);
|
let root = db.parse_or_expand(file_id);
|
||||||
InFile::new(file_id, ast::AnyHasAttrs::new(map[id.local_id].to_node(&root)))
|
InFile::new(file_id, ast::AnyHasAttrs::new(map[id.local_id].to_node(&root)))
|
||||||
}
|
}
|
||||||
AttrDefId::StaticId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new),
|
AttrDefId::StaticId(id) => any_has_attrs(db, id),
|
||||||
AttrDefId::ConstId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new),
|
AttrDefId::ConstId(id) => any_has_attrs(db, id),
|
||||||
AttrDefId::TraitId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new),
|
AttrDefId::TraitId(id) => any_has_attrs(db, id),
|
||||||
AttrDefId::TraitAliasId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new),
|
AttrDefId::TraitAliasId(id) => any_has_attrs(db, id),
|
||||||
AttrDefId::TypeAliasId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new),
|
AttrDefId::TypeAliasId(id) => any_has_attrs(db, id),
|
||||||
AttrDefId::MacroId(id) => match id {
|
AttrDefId::MacroId(id) => match id {
|
||||||
MacroId::Macro2Id(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new),
|
MacroId::Macro2Id(id) => any_has_attrs(db, id),
|
||||||
MacroId::MacroRulesId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new),
|
MacroId::MacroRulesId(id) => any_has_attrs(db, id),
|
||||||
MacroId::ProcMacroId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new),
|
MacroId::ProcMacroId(id) => any_has_attrs(db, id),
|
||||||
},
|
},
|
||||||
AttrDefId::ImplId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new),
|
AttrDefId::ImplId(id) => any_has_attrs(db, id),
|
||||||
AttrDefId::GenericParamId(id) => match id {
|
AttrDefId::GenericParamId(id) => match id {
|
||||||
GenericParamId::ConstParamId(id) => id
|
GenericParamId::ConstParamId(id) => id
|
||||||
.parent()
|
.parent()
|
||||||
|
@ -542,7 +543,7 @@ impl AttrsWithOwner {
|
||||||
.child_source(db)
|
.child_source(db)
|
||||||
.map(|source| ast::AnyHasAttrs::new(source[id.local_id].clone())),
|
.map(|source| ast::AnyHasAttrs::new(source[id.local_id].clone())),
|
||||||
},
|
},
|
||||||
AttrDefId::ExternBlockId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new),
|
AttrDefId::ExternBlockId(id) => any_has_attrs(db, id),
|
||||||
};
|
};
|
||||||
|
|
||||||
AttrSourceMap::new(owner.as_ref().map(|node| node as &dyn HasAttrs))
|
AttrSourceMap::new(owner.as_ref().map(|node| node as &dyn HasAttrs))
|
||||||
|
@ -769,12 +770,35 @@ impl<'attr> AttrQuery<'attr> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn attrs_from_item_tree<N: ItemTreeNode>(id: ItemTreeId<N>, db: &dyn DefDatabase) -> RawAttrs {
|
fn any_has_attrs(
|
||||||
|
db: &dyn DefDatabase,
|
||||||
|
id: impl Lookup<Data = impl HasSource<Value = impl ast::HasAttrs>>,
|
||||||
|
) -> InFile<ast::AnyHasAttrs> {
|
||||||
|
id.lookup(db).source(db).map(ast::AnyHasAttrs::new)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn attrs_from_item_tree<N: ItemTreeNode>(db: &dyn DefDatabase, id: ItemTreeId<N>) -> RawAttrs {
|
||||||
let tree = id.item_tree(db);
|
let tree = id.item_tree(db);
|
||||||
let mod_item = N::id_to_mod_item(id.value);
|
let mod_item = N::id_to_mod_item(id.value);
|
||||||
tree.raw_attrs(mod_item.into()).clone()
|
tree.raw_attrs(mod_item.into()).clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn attrs_from_item_tree_loc<N: ItemTreeNode>(
|
||||||
|
db: &dyn DefDatabase,
|
||||||
|
lookup: impl Lookup<Data = ItemLoc<N>>,
|
||||||
|
) -> RawAttrs {
|
||||||
|
let id = lookup.lookup(db).id;
|
||||||
|
attrs_from_item_tree(db, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn attrs_from_item_tree_assoc<N: ItemTreeNode>(
|
||||||
|
db: &dyn DefDatabase,
|
||||||
|
lookup: impl Lookup<Data = AssocItemLoc<N>>,
|
||||||
|
) -> RawAttrs {
|
||||||
|
let id = lookup.lookup(db).id;
|
||||||
|
attrs_from_item_tree(db, id)
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn variants_attrs_source_map(
|
pub(crate) fn variants_attrs_source_map(
|
||||||
db: &dyn DefDatabase,
|
db: &dyn DefDatabase,
|
||||||
def: EnumId,
|
def: EnumId,
|
||||||
|
|
|
@ -10,284 +10,25 @@ use std::{ops::Index, sync::Arc};
|
||||||
|
|
||||||
use base_db::CrateId;
|
use base_db::CrateId;
|
||||||
use cfg::{CfgExpr, CfgOptions};
|
use cfg::{CfgExpr, CfgOptions};
|
||||||
use drop_bomb::DropBomb;
|
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use hir_expand::{
|
use hir_expand::{name::Name, HirFileId, InFile};
|
||||||
ast_id_map::AstIdMap, attrs::RawAttrs, hygiene::Hygiene, name::Name, AstId, ExpandError,
|
|
||||||
ExpandResult, HirFileId, InFile, MacroCallId,
|
|
||||||
};
|
|
||||||
use la_arena::{Arena, ArenaMap};
|
use la_arena::{Arena, ArenaMap};
|
||||||
use limit::Limit;
|
|
||||||
use once_cell::unsync::OnceCell;
|
|
||||||
use profile::Count;
|
use profile::Count;
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
use syntax::{ast, AstPtr, Parse, SyntaxNode, SyntaxNodePtr};
|
use syntax::{ast, AstPtr, SyntaxNodePtr};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
attr::Attrs,
|
|
||||||
db::DefDatabase,
|
db::DefDatabase,
|
||||||
|
expander::Expander,
|
||||||
hir::{
|
hir::{
|
||||||
dummy_expr_id, Binding, BindingId, Expr, ExprId, Label, LabelId, Pat, PatId, RecordFieldPat,
|
dummy_expr_id, Binding, BindingId, Expr, ExprId, Label, LabelId, Pat, PatId, RecordFieldPat,
|
||||||
},
|
},
|
||||||
item_scope::BuiltinShadowMode,
|
|
||||||
macro_id_to_def_id,
|
|
||||||
nameres::DefMap,
|
nameres::DefMap,
|
||||||
path::{ModPath, Path},
|
path::{ModPath, Path},
|
||||||
src::{HasChildSource, HasSource},
|
src::{HasChildSource, HasSource},
|
||||||
AsMacroCall, BlockId, DefWithBodyId, HasModule, LocalModuleId, Lookup, MacroId, ModuleId,
|
BlockId, DefWithBodyId, HasModule, Lookup,
|
||||||
UnresolvedMacro,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct LowerCtx<'a> {
|
|
||||||
pub db: &'a dyn DefDatabase,
|
|
||||||
hygiene: Hygiene,
|
|
||||||
ast_id_map: Option<(HirFileId, OnceCell<Arc<AstIdMap>>)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> LowerCtx<'a> {
|
|
||||||
pub fn new(db: &'a dyn DefDatabase, hygiene: &Hygiene, file_id: HirFileId) -> Self {
|
|
||||||
LowerCtx { db, hygiene: hygiene.clone(), ast_id_map: Some((file_id, OnceCell::new())) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_file_id(db: &'a dyn DefDatabase, file_id: HirFileId) -> Self {
|
|
||||||
LowerCtx {
|
|
||||||
db,
|
|
||||||
hygiene: Hygiene::new(db.upcast(), file_id),
|
|
||||||
ast_id_map: Some((file_id, OnceCell::new())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_hygiene(db: &'a dyn DefDatabase, hygiene: &Hygiene) -> Self {
|
|
||||||
LowerCtx { db, hygiene: hygiene.clone(), ast_id_map: None }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn hygiene(&self) -> &Hygiene {
|
|
||||||
&self.hygiene
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn lower_path(&self, ast: ast::Path) -> Option<Path> {
|
|
||||||
Path::from_src(ast, self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn ast_id<N: syntax::AstNode>(&self, item: &N) -> Option<AstId<N>> {
|
|
||||||
let &(file_id, ref ast_id_map) = self.ast_id_map.as_ref()?;
|
|
||||||
let ast_id_map = ast_id_map.get_or_init(|| self.db.ast_id_map(file_id));
|
|
||||||
Some(InFile::new(file_id, ast_id_map.ast_id(item)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A subset of Expander that only deals with cfg attributes. We only need it to
|
|
||||||
/// avoid cyclic queries in crate def map during enum processing.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub(crate) struct CfgExpander {
|
|
||||||
cfg_options: CfgOptions,
|
|
||||||
hygiene: Hygiene,
|
|
||||||
krate: CrateId,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Expander {
|
|
||||||
cfg_expander: CfgExpander,
|
|
||||||
def_map: Arc<DefMap>,
|
|
||||||
current_file_id: HirFileId,
|
|
||||||
module: LocalModuleId,
|
|
||||||
/// `recursion_depth == usize::MAX` indicates that the recursion limit has been reached.
|
|
||||||
recursion_depth: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CfgExpander {
|
|
||||||
pub(crate) fn new(
|
|
||||||
db: &dyn DefDatabase,
|
|
||||||
current_file_id: HirFileId,
|
|
||||||
krate: CrateId,
|
|
||||||
) -> CfgExpander {
|
|
||||||
let hygiene = Hygiene::new(db.upcast(), current_file_id);
|
|
||||||
let cfg_options = db.crate_graph()[krate].cfg_options.clone();
|
|
||||||
CfgExpander { cfg_options, hygiene, krate }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn parse_attrs(&self, db: &dyn DefDatabase, owner: &dyn ast::HasAttrs) -> Attrs {
|
|
||||||
Attrs::filter(db, self.krate, RawAttrs::new(db.upcast(), owner, &self.hygiene))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn is_cfg_enabled(&self, db: &dyn DefDatabase, owner: &dyn ast::HasAttrs) -> bool {
|
|
||||||
let attrs = self.parse_attrs(db, owner);
|
|
||||||
attrs.is_cfg_enabled(&self.cfg_options)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn hygiene(&self) -> &Hygiene {
|
|
||||||
&self.hygiene
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Expander {
|
|
||||||
pub fn new(db: &dyn DefDatabase, current_file_id: HirFileId, module: ModuleId) -> Expander {
|
|
||||||
let cfg_expander = CfgExpander::new(db, current_file_id, module.krate);
|
|
||||||
let def_map = module.def_map(db);
|
|
||||||
Expander {
|
|
||||||
cfg_expander,
|
|
||||||
def_map,
|
|
||||||
current_file_id,
|
|
||||||
module: module.local_id,
|
|
||||||
recursion_depth: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn enter_expand<T: ast::AstNode>(
|
|
||||||
&mut self,
|
|
||||||
db: &dyn DefDatabase,
|
|
||||||
macro_call: ast::MacroCall,
|
|
||||||
) -> Result<ExpandResult<Option<(Mark, Parse<T>)>>, UnresolvedMacro> {
|
|
||||||
// FIXME: within_limit should support this, instead of us having to extract the error
|
|
||||||
let mut unresolved_macro_err = None;
|
|
||||||
|
|
||||||
let result = self.within_limit(db, |this| {
|
|
||||||
let macro_call = InFile::new(this.current_file_id, ¯o_call);
|
|
||||||
|
|
||||||
let resolver =
|
|
||||||
|path| this.resolve_path_as_macro(db, &path).map(|it| macro_id_to_def_id(db, it));
|
|
||||||
|
|
||||||
match macro_call.as_call_id_with_errors(db, this.def_map.krate(), resolver) {
|
|
||||||
Ok(call_id) => call_id,
|
|
||||||
Err(resolve_err) => {
|
|
||||||
unresolved_macro_err = Some(resolve_err);
|
|
||||||
ExpandResult { value: None, err: None }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if let Some(err) = unresolved_macro_err {
|
|
||||||
Err(err)
|
|
||||||
} else {
|
|
||||||
Ok(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn enter_expand_id<T: ast::AstNode>(
|
|
||||||
&mut self,
|
|
||||||
db: &dyn DefDatabase,
|
|
||||||
call_id: MacroCallId,
|
|
||||||
) -> ExpandResult<Option<(Mark, Parse<T>)>> {
|
|
||||||
self.within_limit(db, |_this| ExpandResult::ok(Some(call_id)))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn enter_expand_inner(
|
|
||||||
db: &dyn DefDatabase,
|
|
||||||
call_id: MacroCallId,
|
|
||||||
error: Option<ExpandError>,
|
|
||||||
) -> ExpandResult<Option<InFile<Parse<SyntaxNode>>>> {
|
|
||||||
let file_id = call_id.as_file();
|
|
||||||
let ExpandResult { value, err } = db.parse_or_expand_with_err(file_id);
|
|
||||||
|
|
||||||
ExpandResult { value: Some(InFile::new(file_id, value)), err: error.or(err) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn exit(&mut self, db: &dyn DefDatabase, mut mark: Mark) {
|
|
||||||
self.cfg_expander.hygiene = Hygiene::new(db.upcast(), mark.file_id);
|
|
||||||
self.current_file_id = mark.file_id;
|
|
||||||
if self.recursion_depth == usize::MAX {
|
|
||||||
// Recursion limit has been reached somewhere in the macro expansion tree. Reset the
|
|
||||||
// depth only when we get out of the tree.
|
|
||||||
if !self.current_file_id.is_macro() {
|
|
||||||
self.recursion_depth = 0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
self.recursion_depth -= 1;
|
|
||||||
}
|
|
||||||
mark.bomb.defuse();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn ctx<'a>(&self, db: &'a dyn DefDatabase) -> LowerCtx<'a> {
|
|
||||||
LowerCtx::new(db, &self.cfg_expander.hygiene, self.current_file_id)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn to_source<T>(&self, value: T) -> InFile<T> {
|
|
||||||
InFile { file_id: self.current_file_id, value }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn parse_attrs(&self, db: &dyn DefDatabase, owner: &dyn ast::HasAttrs) -> Attrs {
|
|
||||||
self.cfg_expander.parse_attrs(db, owner)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn cfg_options(&self) -> &CfgOptions {
|
|
||||||
&self.cfg_expander.cfg_options
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn current_file_id(&self) -> HirFileId {
|
|
||||||
self.current_file_id
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<MacroId> {
|
|
||||||
self.def_map.resolve_path(db, self.module, path, BuiltinShadowMode::Other).0.take_macros()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn recursion_limit(&self, db: &dyn DefDatabase) -> Limit {
|
|
||||||
let limit = db.crate_limits(self.cfg_expander.krate).recursion_limit as _;
|
|
||||||
|
|
||||||
#[cfg(not(test))]
|
|
||||||
return Limit::new(limit);
|
|
||||||
|
|
||||||
// Without this, `body::tests::your_stack_belongs_to_me` stack-overflows in debug
|
|
||||||
#[cfg(test)]
|
|
||||||
return Limit::new(std::cmp::min(32, limit));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn within_limit<F, T: ast::AstNode>(
|
|
||||||
&mut self,
|
|
||||||
db: &dyn DefDatabase,
|
|
||||||
op: F,
|
|
||||||
) -> ExpandResult<Option<(Mark, Parse<T>)>>
|
|
||||||
where
|
|
||||||
F: FnOnce(&mut Self) -> ExpandResult<Option<MacroCallId>>,
|
|
||||||
{
|
|
||||||
if self.recursion_depth == usize::MAX {
|
|
||||||
// Recursion limit has been reached somewhere in the macro expansion tree. We should
|
|
||||||
// stop expanding other macro calls in this tree, or else this may result in
|
|
||||||
// exponential number of macro expansions, leading to a hang.
|
|
||||||
//
|
|
||||||
// The overflow error should have been reported when it occurred (see the next branch),
|
|
||||||
// so don't return overflow error here to avoid diagnostics duplication.
|
|
||||||
cov_mark::hit!(overflow_but_not_me);
|
|
||||||
return ExpandResult::only_err(ExpandError::RecursionOverflowPoisoned);
|
|
||||||
} else if self.recursion_limit(db).check(self.recursion_depth + 1).is_err() {
|
|
||||||
self.recursion_depth = usize::MAX;
|
|
||||||
cov_mark::hit!(your_stack_belongs_to_me);
|
|
||||||
return ExpandResult::only_err(ExpandError::Other(
|
|
||||||
"reached recursion limit during macro expansion".into(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
let ExpandResult { value, err } = op(self);
|
|
||||||
let Some(call_id) = value else {
|
|
||||||
return ExpandResult { value: None, err };
|
|
||||||
};
|
|
||||||
|
|
||||||
Self::enter_expand_inner(db, call_id, err).map(|value| {
|
|
||||||
value.and_then(|InFile { file_id, value }| {
|
|
||||||
let parse = value.cast::<T>()?;
|
|
||||||
|
|
||||||
self.recursion_depth += 1;
|
|
||||||
self.cfg_expander.hygiene = Hygiene::new(db.upcast(), file_id);
|
|
||||||
let old_file_id = std::mem::replace(&mut self.current_file_id, file_id);
|
|
||||||
let mark =
|
|
||||||
Mark { file_id: old_file_id, bomb: DropBomb::new("expansion mark dropped") };
|
|
||||||
Some((mark, parse))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Mark {
|
|
||||||
file_id: HirFileId,
|
|
||||||
bomb: DropBomb,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The body of an item (function, const etc.).
|
/// The body of an item (function, const etc.).
|
||||||
#[derive(Debug, Eq, PartialEq)]
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
pub struct Body {
|
pub struct Body {
|
||||||
|
@ -376,47 +117,49 @@ impl Body {
|
||||||
let _p = profile::span("body_with_source_map_query");
|
let _p = profile::span("body_with_source_map_query");
|
||||||
let mut params = None;
|
let mut params = None;
|
||||||
|
|
||||||
let (file_id, module, body, is_async_fn) = match def {
|
let (file_id, module, body, is_async_fn) = {
|
||||||
DefWithBodyId::FunctionId(f) => {
|
match def {
|
||||||
let data = db.function_data(f);
|
DefWithBodyId::FunctionId(f) => {
|
||||||
let f = f.lookup(db);
|
let data = db.function_data(f);
|
||||||
let src = f.source(db);
|
let f = f.lookup(db);
|
||||||
params = src.value.param_list().map(|param_list| {
|
let src = f.source(db);
|
||||||
let item_tree = f.id.item_tree(db);
|
params = src.value.param_list().map(|param_list| {
|
||||||
let func = &item_tree[f.id.value];
|
let item_tree = f.id.item_tree(db);
|
||||||
let krate = f.container.module(db).krate;
|
let func = &item_tree[f.id.value];
|
||||||
let crate_graph = db.crate_graph();
|
let krate = f.container.module(db).krate;
|
||||||
|
let crate_graph = db.crate_graph();
|
||||||
|
(
|
||||||
|
param_list,
|
||||||
|
func.params.clone().map(move |param| {
|
||||||
|
item_tree
|
||||||
|
.attrs(db, krate, param.into())
|
||||||
|
.is_cfg_enabled(&crate_graph[krate].cfg_options)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
});
|
||||||
(
|
(
|
||||||
param_list,
|
src.file_id,
|
||||||
func.params.clone().map(move |param| {
|
f.module(db),
|
||||||
item_tree
|
src.value.body().map(ast::Expr::from),
|
||||||
.attrs(db, krate, param.into())
|
data.has_async_kw(),
|
||||||
.is_cfg_enabled(&crate_graph[krate].cfg_options)
|
|
||||||
}),
|
|
||||||
)
|
)
|
||||||
});
|
}
|
||||||
(
|
DefWithBodyId::ConstId(c) => {
|
||||||
src.file_id,
|
let c = c.lookup(db);
|
||||||
f.module(db),
|
let src = c.source(db);
|
||||||
src.value.body().map(ast::Expr::from),
|
(src.file_id, c.module(db), src.value.body(), false)
|
||||||
data.has_async_kw(),
|
}
|
||||||
)
|
DefWithBodyId::StaticId(s) => {
|
||||||
}
|
let s = s.lookup(db);
|
||||||
DefWithBodyId::ConstId(c) => {
|
let src = s.source(db);
|
||||||
let c = c.lookup(db);
|
(src.file_id, s.module(db), src.value.body(), false)
|
||||||
let src = c.source(db);
|
}
|
||||||
(src.file_id, c.module(db), src.value.body(), false)
|
DefWithBodyId::VariantId(v) => {
|
||||||
}
|
let e = v.parent.lookup(db);
|
||||||
DefWithBodyId::StaticId(s) => {
|
let src = v.parent.child_source(db);
|
||||||
let s = s.lookup(db);
|
let variant = &src.value[v.local_id];
|
||||||
let src = s.source(db);
|
(src.file_id, e.container, variant.expr(), false)
|
||||||
(src.file_id, s.module(db), src.value.body(), false)
|
}
|
||||||
}
|
|
||||||
DefWithBodyId::VariantId(v) => {
|
|
||||||
let e = v.parent.lookup(db);
|
|
||||||
let src = v.parent.child_source(db);
|
|
||||||
let variant = &src.value[v.local_id];
|
|
||||||
(src.file_id, e.container, variant.expr(), false)
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let expander = Expander::new(db, file_id, module);
|
let expander = Expander::new(db, file_id, module);
|
||||||
|
|
|
@ -24,9 +24,10 @@ use syntax::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
body::{Body, BodyDiagnostic, BodySourceMap, Expander, ExprPtr, LabelPtr, LowerCtx, PatPtr},
|
body::{Body, BodyDiagnostic, BodySourceMap, ExprPtr, LabelPtr, PatPtr},
|
||||||
data::adt::StructKind,
|
data::adt::StructKind,
|
||||||
db::DefDatabase,
|
db::DefDatabase,
|
||||||
|
expander::Expander,
|
||||||
hir::{
|
hir::{
|
||||||
dummy_expr_id, Array, Binding, BindingAnnotation, BindingId, CaptureBy, ClosureKind, Expr,
|
dummy_expr_id, Array, Binding, BindingAnnotation, BindingId, CaptureBy, ClosureKind, Expr,
|
||||||
ExprId, Label, LabelId, Literal, MatchArm, Movability, Pat, PatId, RecordFieldPat,
|
ExprId, Label, LabelId, Literal, MatchArm, Movability, Pat, PatId, RecordFieldPat,
|
||||||
|
@ -34,6 +35,8 @@ use crate::{
|
||||||
},
|
},
|
||||||
item_scope::BuiltinShadowMode,
|
item_scope::BuiltinShadowMode,
|
||||||
lang_item::LangItem,
|
lang_item::LangItem,
|
||||||
|
lower::LowerCtx,
|
||||||
|
nameres::DefMap,
|
||||||
path::{GenericArgs, Path},
|
path::{GenericArgs, Path},
|
||||||
type_ref::{Mutability, Rawness, TypeRef},
|
type_ref::{Mutability, Rawness, TypeRef},
|
||||||
AdtId, BlockId, BlockLoc, ModuleDefId, UnresolvedMacro,
|
AdtId, BlockId, BlockLoc, ModuleDefId, UnresolvedMacro,
|
||||||
|
@ -50,6 +53,7 @@ pub(super) fn lower(
|
||||||
ExprCollector {
|
ExprCollector {
|
||||||
db,
|
db,
|
||||||
krate,
|
krate,
|
||||||
|
def_map: db.crate_def_map(krate),
|
||||||
source_map: BodySourceMap::default(),
|
source_map: BodySourceMap::default(),
|
||||||
ast_id_map: db.ast_id_map(expander.current_file_id),
|
ast_id_map: db.ast_id_map(expander.current_file_id),
|
||||||
body: Body {
|
body: Body {
|
||||||
|
@ -75,6 +79,7 @@ pub(super) fn lower(
|
||||||
struct ExprCollector<'a> {
|
struct ExprCollector<'a> {
|
||||||
db: &'a dyn DefDatabase,
|
db: &'a dyn DefDatabase,
|
||||||
expander: Expander,
|
expander: Expander,
|
||||||
|
def_map: Arc<DefMap>,
|
||||||
ast_id_map: Arc<AstIdMap>,
|
ast_id_map: Arc<AstIdMap>,
|
||||||
krate: CrateId,
|
krate: CrateId,
|
||||||
body: Body,
|
body: Body,
|
||||||
|
@ -777,7 +782,13 @@ impl ExprCollector<'_> {
|
||||||
let outer_file = self.expander.current_file_id;
|
let outer_file = self.expander.current_file_id;
|
||||||
|
|
||||||
let macro_call_ptr = self.expander.to_source(AstPtr::new(&mcall));
|
let macro_call_ptr = self.expander.to_source(AstPtr::new(&mcall));
|
||||||
let res = self.expander.enter_expand(self.db, mcall);
|
let module = self.expander.module.local_id;
|
||||||
|
let res = self.expander.enter_expand(self.db, mcall, |path| {
|
||||||
|
self.def_map
|
||||||
|
.resolve_path(self.db, module, &path, crate::item_scope::BuiltinShadowMode::Other)
|
||||||
|
.0
|
||||||
|
.take_macros()
|
||||||
|
});
|
||||||
|
|
||||||
let res = match res {
|
let res = match res {
|
||||||
Ok(res) => res,
|
Ok(res) => res,
|
||||||
|
@ -944,10 +955,7 @@ impl ExprCollector<'_> {
|
||||||
let block_id = if block_has_items {
|
let block_id = if block_has_items {
|
||||||
let file_local_id = self.ast_id_map.ast_id(&block);
|
let file_local_id = self.ast_id_map.ast_id(&block);
|
||||||
let ast_id = AstId::new(self.expander.current_file_id, file_local_id);
|
let ast_id = AstId::new(self.expander.current_file_id, file_local_id);
|
||||||
Some(self.db.intern_block(BlockLoc {
|
Some(self.db.intern_block(BlockLoc { ast_id, module: self.expander.module }))
|
||||||
ast_id,
|
|
||||||
module: self.expander.def_map.module_id(self.expander.module),
|
|
||||||
}))
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
@ -956,11 +964,11 @@ impl ExprCollector<'_> {
|
||||||
match block_id.map(|block_id| (self.db.block_def_map(block_id), block_id)) {
|
match block_id.map(|block_id| (self.db.block_def_map(block_id), block_id)) {
|
||||||
Some((def_map, block_id)) => {
|
Some((def_map, block_id)) => {
|
||||||
self.body.block_scopes.push(block_id);
|
self.body.block_scopes.push(block_id);
|
||||||
(def_map.root(), def_map)
|
(def_map.module_id(def_map.root()), def_map)
|
||||||
}
|
}
|
||||||
None => (self.expander.module, self.expander.def_map.clone()),
|
None => (self.expander.module, self.def_map.clone()),
|
||||||
};
|
};
|
||||||
let prev_def_map = mem::replace(&mut self.expander.def_map, def_map);
|
let prev_def_map = mem::replace(&mut self.def_map, def_map);
|
||||||
let prev_local_module = mem::replace(&mut self.expander.module, module);
|
let prev_local_module = mem::replace(&mut self.expander.module, module);
|
||||||
|
|
||||||
let mut statements = Vec::new();
|
let mut statements = Vec::new();
|
||||||
|
@ -982,7 +990,7 @@ impl ExprCollector<'_> {
|
||||||
let expr_id = self
|
let expr_id = self
|
||||||
.alloc_expr(mk_block(block_id, statements.into_boxed_slice(), tail), syntax_node_ptr);
|
.alloc_expr(mk_block(block_id, statements.into_boxed_slice(), tail), syntax_node_ptr);
|
||||||
|
|
||||||
self.expander.def_map = prev_def_map;
|
self.def_map = prev_def_map;
|
||||||
self.expander.module = prev_local_module;
|
self.expander.module = prev_local_module;
|
||||||
expr_id
|
expr_id
|
||||||
}
|
}
|
||||||
|
@ -1028,9 +1036,9 @@ impl ExprCollector<'_> {
|
||||||
let (binding, pattern) = if is_simple_ident_pat {
|
let (binding, pattern) = if is_simple_ident_pat {
|
||||||
// This could also be a single-segment path pattern. To
|
// This could also be a single-segment path pattern. To
|
||||||
// decide that, we need to try resolving the name.
|
// decide that, we need to try resolving the name.
|
||||||
let (resolved, _) = self.expander.def_map.resolve_path(
|
let (resolved, _) = self.def_map.resolve_path(
|
||||||
self.db,
|
self.db,
|
||||||
self.expander.module,
|
self.expander.module.local_id,
|
||||||
&name.clone().into(),
|
&name.clone().into(),
|
||||||
BuiltinShadowMode::Other,
|
BuiltinShadowMode::Other,
|
||||||
);
|
);
|
||||||
|
|
|
@ -11,8 +11,8 @@ use syntax::{ast, Parse};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
attr::Attrs,
|
attr::Attrs,
|
||||||
body::{Expander, Mark},
|
|
||||||
db::DefDatabase,
|
db::DefDatabase,
|
||||||
|
expander::{Expander, Mark},
|
||||||
item_tree::{self, AssocItem, FnFlags, ItemTree, ItemTreeId, ModItem, Param, TreeId},
|
item_tree::{self, AssocItem, FnFlags, ItemTree, ItemTreeId, ModItem, Param, TreeId},
|
||||||
nameres::{
|
nameres::{
|
||||||
attr_resolution::ResolvedAttr,
|
attr_resolution::ResolvedAttr,
|
||||||
|
@ -44,16 +44,16 @@ impl FunctionData {
|
||||||
pub(crate) fn fn_data_query(db: &dyn DefDatabase, func: FunctionId) -> Arc<FunctionData> {
|
pub(crate) fn fn_data_query(db: &dyn DefDatabase, func: FunctionId) -> Arc<FunctionData> {
|
||||||
let loc = func.lookup(db);
|
let loc = func.lookup(db);
|
||||||
let krate = loc.container.module(db).krate;
|
let krate = loc.container.module(db).krate;
|
||||||
let crate_graph = db.crate_graph();
|
|
||||||
let cfg_options = &crate_graph[krate].cfg_options;
|
|
||||||
let item_tree = loc.id.item_tree(db);
|
let item_tree = loc.id.item_tree(db);
|
||||||
let func = &item_tree[loc.id.value];
|
let func = &item_tree[loc.id.value];
|
||||||
let visibility = if let ItemContainerId::TraitId(trait_id) = loc.container {
|
let visibility = if let ItemContainerId::TraitId(trait_id) = loc.container {
|
||||||
db.trait_data(trait_id).visibility.clone()
|
trait_vis(db, trait_id)
|
||||||
} else {
|
} else {
|
||||||
item_tree[func.visibility].clone()
|
item_tree[func.visibility].clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let crate_graph = db.crate_graph();
|
||||||
|
let cfg_options = &crate_graph[krate].cfg_options;
|
||||||
let enabled_params = func
|
let enabled_params = func
|
||||||
.params
|
.params
|
||||||
.clone()
|
.clone()
|
||||||
|
@ -188,7 +188,7 @@ impl TypeAliasData {
|
||||||
let item_tree = loc.id.item_tree(db);
|
let item_tree = loc.id.item_tree(db);
|
||||||
let typ = &item_tree[loc.id.value];
|
let typ = &item_tree[loc.id.value];
|
||||||
let visibility = if let ItemContainerId::TraitId(trait_id) = loc.container {
|
let visibility = if let ItemContainerId::TraitId(trait_id) = loc.container {
|
||||||
db.trait_data(trait_id).visibility.clone()
|
trait_vis(db, trait_id)
|
||||||
} else {
|
} else {
|
||||||
item_tree[typ.visibility].clone()
|
item_tree[typ.visibility].clone()
|
||||||
};
|
};
|
||||||
|
@ -471,7 +471,7 @@ impl ConstData {
|
||||||
let item_tree = loc.id.item_tree(db);
|
let item_tree = loc.id.item_tree(db);
|
||||||
let konst = &item_tree[loc.id.value];
|
let konst = &item_tree[loc.id.value];
|
||||||
let visibility = if let ItemContainerId::TraitId(trait_id) = loc.container {
|
let visibility = if let ItemContainerId::TraitId(trait_id) = loc.container {
|
||||||
db.trait_data(trait_id).visibility.clone()
|
trait_vis(db, trait_id)
|
||||||
} else {
|
} else {
|
||||||
item_tree[konst.visibility].clone()
|
item_tree[konst.visibility].clone()
|
||||||
};
|
};
|
||||||
|
@ -647,8 +647,20 @@ impl<'a> AssocItemCollector<'a> {
|
||||||
let _cx = stdx::panic_context::enter(format!(
|
let _cx = stdx::panic_context::enter(format!(
|
||||||
"collect_items MacroCall: {macro_call}"
|
"collect_items MacroCall: {macro_call}"
|
||||||
));
|
));
|
||||||
|
let module = self.expander.module.local_id;
|
||||||
|
|
||||||
if let Ok(res) =
|
if let Ok(res) =
|
||||||
self.expander.enter_expand::<ast::MacroItems>(self.db, macro_call)
|
self.expander.enter_expand::<ast::MacroItems>(self.db, macro_call, |path| {
|
||||||
|
self.def_map
|
||||||
|
.resolve_path(
|
||||||
|
self.db,
|
||||||
|
module,
|
||||||
|
&path,
|
||||||
|
crate::item_scope::BuiltinShadowMode::Other,
|
||||||
|
)
|
||||||
|
.0
|
||||||
|
.take_macros()
|
||||||
|
})
|
||||||
{
|
{
|
||||||
self.collect_macro_items(res, &|| hir_expand::MacroCallKind::FnLike {
|
self.collect_macro_items(res, &|| hir_expand::MacroCallKind::FnLike {
|
||||||
ast_id: InFile::new(file_id, call.ast_id),
|
ast_id: InFile::new(file_id, call.ast_id),
|
||||||
|
@ -692,3 +704,10 @@ impl<'a> AssocItemCollector<'a> {
|
||||||
self.expander.exit(self.db, mark);
|
self.expander.exit(self.db, mark);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn trait_vis(db: &dyn DefDatabase, trait_id: TraitId) -> RawVisibility {
|
||||||
|
let ItemLoc { id: tree_id, .. } = trait_id.lookup(db);
|
||||||
|
let item_tree = tree_id.item_tree(db);
|
||||||
|
let tr_def = &item_tree[tree_id.value];
|
||||||
|
item_tree[tr_def.visibility].clone()
|
||||||
|
}
|
||||||
|
|
|
@ -17,11 +17,12 @@ use rustc_abi::{Align, Integer, IntegerType, ReprFlags, ReprOptions};
|
||||||
use syntax::ast::{self, HasName, HasVisibility};
|
use syntax::ast::{self, HasName, HasVisibility};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
body::{CfgExpander, LowerCtx},
|
|
||||||
builtin_type::{BuiltinInt, BuiltinUint},
|
builtin_type::{BuiltinInt, BuiltinUint},
|
||||||
db::DefDatabase,
|
db::DefDatabase,
|
||||||
|
expander::CfgExpander,
|
||||||
item_tree::{AttrOwner, Field, FieldAstId, Fields, ItemTree, ModItem, RawVisibilityId},
|
item_tree::{AttrOwner, Field, FieldAstId, Fields, ItemTree, ModItem, RawVisibilityId},
|
||||||
lang_item::LangItem,
|
lang_item::LangItem,
|
||||||
|
lower::LowerCtx,
|
||||||
nameres::diagnostics::DefDiagnostic,
|
nameres::diagnostics::DefDiagnostic,
|
||||||
src::HasChildSource,
|
src::HasChildSource,
|
||||||
src::HasSource,
|
src::HasSource,
|
||||||
|
|
|
@ -217,6 +217,8 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba
|
||||||
|
|
||||||
#[salsa::transparent]
|
#[salsa::transparent]
|
||||||
fn crate_limits(&self, crate_id: CrateId) -> CrateLimits;
|
fn crate_limits(&self, crate_id: CrateId) -> CrateLimits;
|
||||||
|
#[salsa::transparent]
|
||||||
|
fn recursion_limit(&self, crate_id: CrateId) -> u32;
|
||||||
|
|
||||||
fn crate_supports_no_std(&self, crate_id: CrateId) -> bool;
|
fn crate_supports_no_std(&self, crate_id: CrateId) -> bool;
|
||||||
}
|
}
|
||||||
|
@ -240,6 +242,10 @@ fn crate_limits(db: &dyn DefDatabase, crate_id: CrateId) -> CrateLimits {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn recursion_limit(db: &dyn DefDatabase, crate_id: CrateId) -> u32 {
|
||||||
|
db.crate_limits(crate_id).recursion_limit
|
||||||
|
}
|
||||||
|
|
||||||
fn crate_supports_no_std(db: &dyn DefDatabase, crate_id: CrateId) -> bool {
|
fn crate_supports_no_std(db: &dyn DefDatabase, crate_id: CrateId) -> bool {
|
||||||
let file = db.crate_graph()[crate_id].root_file_id;
|
let file = db.crate_graph()[crate_id].root_file_id;
|
||||||
let item_tree = db.file_item_tree(file.into());
|
let item_tree = db.file_item_tree(file.into());
|
||||||
|
|
211
crates/hir-def/src/expander.rs
Normal file
211
crates/hir-def/src/expander.rs
Normal file
|
@ -0,0 +1,211 @@
|
||||||
|
//! Macro expansion utilities.
|
||||||
|
|
||||||
|
use base_db::CrateId;
|
||||||
|
use cfg::CfgOptions;
|
||||||
|
use drop_bomb::DropBomb;
|
||||||
|
use hir_expand::{
|
||||||
|
attrs::RawAttrs, hygiene::Hygiene, mod_path::ModPath, ExpandError, ExpandResult, HirFileId,
|
||||||
|
InFile, MacroCallId, UnresolvedMacro,
|
||||||
|
};
|
||||||
|
use limit::Limit;
|
||||||
|
use syntax::{ast, Parse, SyntaxNode};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
attr::Attrs, db::DefDatabase, lower::LowerCtx, macro_id_to_def_id, path::Path, AsMacroCall,
|
||||||
|
MacroId, ModuleId,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A subset of Expander that only deals with cfg attributes. We only need it to
|
||||||
|
/// avoid cyclic queries in crate def map during enum processing.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) struct CfgExpander {
|
||||||
|
cfg_options: CfgOptions,
|
||||||
|
hygiene: Hygiene,
|
||||||
|
krate: CrateId,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Expander {
|
||||||
|
cfg_expander: CfgExpander,
|
||||||
|
pub(crate) current_file_id: HirFileId,
|
||||||
|
pub(crate) module: ModuleId,
|
||||||
|
/// `recursion_depth == usize::MAX` indicates that the recursion limit has been reached.
|
||||||
|
recursion_depth: u32,
|
||||||
|
recursion_limit: Limit,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CfgExpander {
|
||||||
|
pub(crate) fn new(
|
||||||
|
db: &dyn DefDatabase,
|
||||||
|
current_file_id: HirFileId,
|
||||||
|
krate: CrateId,
|
||||||
|
) -> CfgExpander {
|
||||||
|
let hygiene = Hygiene::new(db.upcast(), current_file_id);
|
||||||
|
let cfg_options = db.crate_graph()[krate].cfg_options.clone();
|
||||||
|
CfgExpander { cfg_options, hygiene, krate }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn parse_attrs(&self, db: &dyn DefDatabase, owner: &dyn ast::HasAttrs) -> Attrs {
|
||||||
|
Attrs::filter(db, self.krate, RawAttrs::new(db.upcast(), owner, &self.hygiene))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn is_cfg_enabled(&self, db: &dyn DefDatabase, owner: &dyn ast::HasAttrs) -> bool {
|
||||||
|
let attrs = self.parse_attrs(db, owner);
|
||||||
|
attrs.is_cfg_enabled(&self.cfg_options)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn hygiene(&self) -> &Hygiene {
|
||||||
|
&self.hygiene
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Expander {
|
||||||
|
pub fn new(db: &dyn DefDatabase, current_file_id: HirFileId, module: ModuleId) -> Expander {
|
||||||
|
let cfg_expander = CfgExpander::new(db, current_file_id, module.krate);
|
||||||
|
let recursion_limit = db.recursion_limit(module.krate);
|
||||||
|
#[cfg(not(test))]
|
||||||
|
let recursion_limit = Limit::new(recursion_limit as usize);
|
||||||
|
// Without this, `body::tests::your_stack_belongs_to_me` stack-overflows in debug
|
||||||
|
#[cfg(test)]
|
||||||
|
let recursion_limit = Limit::new(std::cmp::min(32, recursion_limit as usize));
|
||||||
|
Expander { cfg_expander, current_file_id, module, recursion_depth: 0, recursion_limit }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enter_expand<T: ast::AstNode>(
|
||||||
|
&mut self,
|
||||||
|
db: &dyn DefDatabase,
|
||||||
|
macro_call: ast::MacroCall,
|
||||||
|
resolver: impl Fn(ModPath) -> Option<MacroId>,
|
||||||
|
) -> Result<ExpandResult<Option<(Mark, Parse<T>)>>, UnresolvedMacro> {
|
||||||
|
// FIXME: within_limit should support this, instead of us having to extract the error
|
||||||
|
let mut unresolved_macro_err = None;
|
||||||
|
|
||||||
|
let result = self.within_limit(db, |this| {
|
||||||
|
let macro_call = InFile::new(this.current_file_id, ¯o_call);
|
||||||
|
match macro_call.as_call_id_with_errors(db.upcast(), this.module.krate(), |path| {
|
||||||
|
resolver(path).map(|it| macro_id_to_def_id(db, it))
|
||||||
|
}) {
|
||||||
|
Ok(call_id) => call_id,
|
||||||
|
Err(resolve_err) => {
|
||||||
|
unresolved_macro_err = Some(resolve_err);
|
||||||
|
ExpandResult { value: None, err: None }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Some(err) = unresolved_macro_err {
|
||||||
|
Err(err)
|
||||||
|
} else {
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enter_expand_id<T: ast::AstNode>(
|
||||||
|
&mut self,
|
||||||
|
db: &dyn DefDatabase,
|
||||||
|
call_id: MacroCallId,
|
||||||
|
) -> ExpandResult<Option<(Mark, Parse<T>)>> {
|
||||||
|
self.within_limit(db, |_this| ExpandResult::ok(Some(call_id)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enter_expand_inner(
|
||||||
|
db: &dyn DefDatabase,
|
||||||
|
call_id: MacroCallId,
|
||||||
|
error: Option<ExpandError>,
|
||||||
|
) -> ExpandResult<Option<InFile<Parse<SyntaxNode>>>> {
|
||||||
|
let file_id = call_id.as_file();
|
||||||
|
let ExpandResult { value, err } = db.parse_or_expand_with_err(file_id);
|
||||||
|
|
||||||
|
ExpandResult { value: Some(InFile::new(file_id, value)), err: error.or(err) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn exit(&mut self, db: &dyn DefDatabase, mut mark: Mark) {
|
||||||
|
self.cfg_expander.hygiene = Hygiene::new(db.upcast(), mark.file_id);
|
||||||
|
self.current_file_id = mark.file_id;
|
||||||
|
if self.recursion_depth == u32::MAX {
|
||||||
|
// Recursion limit has been reached somewhere in the macro expansion tree. Reset the
|
||||||
|
// depth only when we get out of the tree.
|
||||||
|
if !self.current_file_id.is_macro() {
|
||||||
|
self.recursion_depth = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.recursion_depth -= 1;
|
||||||
|
}
|
||||||
|
mark.bomb.defuse();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ctx<'a>(&self, db: &'a dyn DefDatabase) -> LowerCtx<'a> {
|
||||||
|
LowerCtx::new(db, &self.cfg_expander.hygiene, self.current_file_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn to_source<T>(&self, value: T) -> InFile<T> {
|
||||||
|
InFile { file_id: self.current_file_id, value }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn parse_attrs(&self, db: &dyn DefDatabase, owner: &dyn ast::HasAttrs) -> Attrs {
|
||||||
|
self.cfg_expander.parse_attrs(db, owner)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn cfg_options(&self) -> &CfgOptions {
|
||||||
|
&self.cfg_expander.cfg_options
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn current_file_id(&self) -> HirFileId {
|
||||||
|
self.current_file_id
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn within_limit<F, T: ast::AstNode>(
|
||||||
|
&mut self,
|
||||||
|
db: &dyn DefDatabase,
|
||||||
|
op: F,
|
||||||
|
) -> ExpandResult<Option<(Mark, Parse<T>)>>
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut Self) -> ExpandResult<Option<MacroCallId>>,
|
||||||
|
{
|
||||||
|
if self.recursion_depth == u32::MAX {
|
||||||
|
// Recursion limit has been reached somewhere in the macro expansion tree. We should
|
||||||
|
// stop expanding other macro calls in this tree, or else this may result in
|
||||||
|
// exponential number of macro expansions, leading to a hang.
|
||||||
|
//
|
||||||
|
// The overflow error should have been reported when it occurred (see the next branch),
|
||||||
|
// so don't return overflow error here to avoid diagnostics duplication.
|
||||||
|
cov_mark::hit!(overflow_but_not_me);
|
||||||
|
return ExpandResult::only_err(ExpandError::RecursionOverflowPoisoned);
|
||||||
|
} else if self.recursion_limit.check(self.recursion_depth as usize + 1).is_err() {
|
||||||
|
self.recursion_depth = u32::MAX;
|
||||||
|
cov_mark::hit!(your_stack_belongs_to_me);
|
||||||
|
return ExpandResult::only_err(ExpandError::Other(
|
||||||
|
"reached recursion limit during macro expansion".into(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let ExpandResult { value, err } = op(self);
|
||||||
|
let Some(call_id) = value else {
|
||||||
|
return ExpandResult { value: None, err };
|
||||||
|
};
|
||||||
|
|
||||||
|
Self::enter_expand_inner(db, call_id, err).map(|value| {
|
||||||
|
value.and_then(|InFile { file_id, value }| {
|
||||||
|
let parse = value.cast::<T>()?;
|
||||||
|
|
||||||
|
self.recursion_depth += 1;
|
||||||
|
self.cfg_expander.hygiene = Hygiene::new(db.upcast(), file_id);
|
||||||
|
let old_file_id = std::mem::replace(&mut self.current_file_id, file_id);
|
||||||
|
let mark =
|
||||||
|
Mark { file_id: old_file_id, bomb: DropBomb::new("expansion mark dropped") };
|
||||||
|
Some((mark, parse))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Mark {
|
||||||
|
file_id: HirFileId,
|
||||||
|
bomb: DropBomb,
|
||||||
|
}
|
|
@ -3,6 +3,8 @@
|
||||||
//! generic parameters. See also the `Generics` type and the `generics_of` query
|
//! generic parameters. See also the `Generics` type and the `generics_of` query
|
||||||
//! in rustc.
|
//! in rustc.
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use base_db::FileId;
|
use base_db::FileId;
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use hir_expand::{
|
use hir_expand::{
|
||||||
|
@ -16,10 +18,12 @@ use stdx::impl_from;
|
||||||
use syntax::ast::{self, HasGenericParams, HasName, HasTypeBounds};
|
use syntax::ast::{self, HasGenericParams, HasName, HasTypeBounds};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
body::{Expander, LowerCtx},
|
|
||||||
child_by_source::ChildBySource,
|
child_by_source::ChildBySource,
|
||||||
db::DefDatabase,
|
db::DefDatabase,
|
||||||
dyn_map::{keys, DynMap},
|
dyn_map::{keys, DynMap},
|
||||||
|
expander::Expander,
|
||||||
|
lower::LowerCtx,
|
||||||
|
nameres::DefMap,
|
||||||
src::{HasChildSource, HasSource},
|
src::{HasChildSource, HasSource},
|
||||||
type_ref::{LifetimeRef, TypeBound, TypeRef},
|
type_ref::{LifetimeRef, TypeBound, TypeRef},
|
||||||
AdtId, ConstParamId, GenericDefId, HasModule, LifetimeParamId, LocalLifetimeParamId,
|
AdtId, ConstParamId, GenericDefId, HasModule, LifetimeParamId, LocalLifetimeParamId,
|
||||||
|
@ -151,7 +155,6 @@ impl GenericParams {
|
||||||
def: GenericDefId,
|
def: GenericDefId,
|
||||||
) -> Interned<GenericParams> {
|
) -> Interned<GenericParams> {
|
||||||
let _p = profile::span("generic_params_query");
|
let _p = profile::span("generic_params_query");
|
||||||
|
|
||||||
macro_rules! id_to_generics {
|
macro_rules! id_to_generics {
|
||||||
($id:ident) => {{
|
($id:ident) => {{
|
||||||
let id = $id.lookup(db).id;
|
let id = $id.lookup(db).id;
|
||||||
|
@ -174,7 +177,9 @@ impl GenericParams {
|
||||||
|
|
||||||
// Don't create an `Expander` nor call `loc.source(db)` if not needed since this
|
// Don't create an `Expander` nor call `loc.source(db)` if not needed since this
|
||||||
// causes a reparse after the `ItemTree` has been created.
|
// causes a reparse after the `ItemTree` has been created.
|
||||||
let mut expander = Lazy::new(|| Expander::new(db, loc.source(db).file_id, module));
|
let mut expander = Lazy::new(|| {
|
||||||
|
(module.def_map(db), Expander::new(db, loc.source(db).file_id, module))
|
||||||
|
});
|
||||||
for param in &func_data.params {
|
for param in &func_data.params {
|
||||||
generic_params.fill_implicit_impl_trait_args(db, &mut expander, param);
|
generic_params.fill_implicit_impl_trait_args(db, &mut expander, param);
|
||||||
}
|
}
|
||||||
|
@ -327,7 +332,7 @@ impl GenericParams {
|
||||||
pub(crate) fn fill_implicit_impl_trait_args(
|
pub(crate) fn fill_implicit_impl_trait_args(
|
||||||
&mut self,
|
&mut self,
|
||||||
db: &dyn DefDatabase,
|
db: &dyn DefDatabase,
|
||||||
expander: &mut Expander,
|
exp: &mut Lazy<(Arc<DefMap>, Expander), impl FnOnce() -> (Arc<DefMap>, Expander)>,
|
||||||
type_ref: &TypeRef,
|
type_ref: &TypeRef,
|
||||||
) {
|
) {
|
||||||
type_ref.walk(&mut |type_ref| {
|
type_ref.walk(&mut |type_ref| {
|
||||||
|
@ -347,14 +352,27 @@ impl GenericParams {
|
||||||
}
|
}
|
||||||
if let TypeRef::Macro(mc) = type_ref {
|
if let TypeRef::Macro(mc) = type_ref {
|
||||||
let macro_call = mc.to_node(db.upcast());
|
let macro_call = mc.to_node(db.upcast());
|
||||||
match expander.enter_expand::<ast::Type>(db, macro_call) {
|
let (def_map, expander) = &mut **exp;
|
||||||
Ok(ExpandResult { value: Some((mark, expanded)), .. }) => {
|
|
||||||
let ctx = expander.ctx(db);
|
let module = expander.module.local_id;
|
||||||
let type_ref = TypeRef::from_ast(&ctx, expanded.tree());
|
let resolver = |path| {
|
||||||
self.fill_implicit_impl_trait_args(db, expander, &type_ref);
|
def_map
|
||||||
expander.exit(db, mark);
|
.resolve_path(
|
||||||
}
|
db,
|
||||||
_ => {}
|
module,
|
||||||
|
&path,
|
||||||
|
crate::item_scope::BuiltinShadowMode::Other,
|
||||||
|
)
|
||||||
|
.0
|
||||||
|
.take_macros()
|
||||||
|
};
|
||||||
|
if let Ok(ExpandResult { value: Some((mark, expanded)), .. }) =
|
||||||
|
expander.enter_expand(db, macro_call, resolver)
|
||||||
|
{
|
||||||
|
let ctx = expander.ctx(db);
|
||||||
|
let type_ref = TypeRef::from_ast(&ctx, expanded.tree());
|
||||||
|
self.fill_implicit_impl_trait_args(db, &mut *exp, &type_ref);
|
||||||
|
exp.1.exit(db, mark);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -11,9 +11,9 @@ use intern::Interned;
|
||||||
use syntax::ast::{self, HasName};
|
use syntax::ast::{self, HasName};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
body::LowerCtx,
|
|
||||||
builtin_type::{BuiltinInt, BuiltinType, BuiltinUint},
|
builtin_type::{BuiltinInt, BuiltinType, BuiltinUint},
|
||||||
hir::Literal,
|
hir::Literal,
|
||||||
|
lower::LowerCtx,
|
||||||
path::Path,
|
path::Path,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -476,7 +476,7 @@ mod tests {
|
||||||
use base_db::{fixture::WithFixture, SourceDatabase, Upcast};
|
use base_db::{fixture::WithFixture, SourceDatabase, Upcast};
|
||||||
use expect_test::{expect, Expect};
|
use expect_test::{expect, Expect};
|
||||||
|
|
||||||
use crate::{test_db::TestDB, ItemContainerId, Lookup};
|
use crate::{db::DefDatabase, test_db::TestDB, ItemContainerId, Lookup};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ pub(super) struct Ctx<'a> {
|
||||||
db: &'a dyn DefDatabase,
|
db: &'a dyn DefDatabase,
|
||||||
tree: ItemTree,
|
tree: ItemTree,
|
||||||
source_ast_id_map: Arc<AstIdMap>,
|
source_ast_id_map: Arc<AstIdMap>,
|
||||||
body_ctx: crate::body::LowerCtx<'a>,
|
body_ctx: crate::lower::LowerCtx<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Ctx<'a> {
|
impl<'a> Ctx<'a> {
|
||||||
|
@ -29,7 +29,7 @@ impl<'a> Ctx<'a> {
|
||||||
db,
|
db,
|
||||||
tree: ItemTree::default(),
|
tree: ItemTree::default(),
|
||||||
source_ast_id_map: db.ast_id_map(file),
|
source_ast_id_map: db.ast_id_map(file),
|
||||||
body_ctx: crate::body::LowerCtx::with_file_id(db, file),
|
body_ctx: crate::lower::LowerCtx::with_file_id(db, file),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,9 @@ pub mod builtin_type;
|
||||||
pub mod per_ns;
|
pub mod per_ns;
|
||||||
pub mod item_scope;
|
pub mod item_scope;
|
||||||
|
|
||||||
|
pub mod lower;
|
||||||
|
pub mod expander;
|
||||||
|
|
||||||
pub mod dyn_map;
|
pub mod dyn_map;
|
||||||
|
|
||||||
pub mod item_tree;
|
pub mod item_tree;
|
||||||
|
@ -65,6 +68,7 @@ use hir_expand::{
|
||||||
builtin_attr_macro::BuiltinAttrExpander,
|
builtin_attr_macro::BuiltinAttrExpander,
|
||||||
builtin_derive_macro::BuiltinDeriveExpander,
|
builtin_derive_macro::BuiltinDeriveExpander,
|
||||||
builtin_fn_macro::{BuiltinFnLikeExpander, EagerExpander},
|
builtin_fn_macro::{BuiltinFnLikeExpander, EagerExpander},
|
||||||
|
db::ExpandDatabase,
|
||||||
eager::expand_eager_macro,
|
eager::expand_eager_macro,
|
||||||
hygiene::Hygiene,
|
hygiene::Hygiene,
|
||||||
proc_macro::ProcMacroExpander,
|
proc_macro::ProcMacroExpander,
|
||||||
|
@ -791,7 +795,7 @@ impl AttrDefId {
|
||||||
pub trait AsMacroCall {
|
pub trait AsMacroCall {
|
||||||
fn as_call_id(
|
fn as_call_id(
|
||||||
&self,
|
&self,
|
||||||
db: &dyn db::DefDatabase,
|
db: &dyn ExpandDatabase,
|
||||||
krate: CrateId,
|
krate: CrateId,
|
||||||
resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
|
resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
|
||||||
) -> Option<MacroCallId> {
|
) -> Option<MacroCallId> {
|
||||||
|
@ -800,7 +804,7 @@ pub trait AsMacroCall {
|
||||||
|
|
||||||
fn as_call_id_with_errors(
|
fn as_call_id_with_errors(
|
||||||
&self,
|
&self,
|
||||||
db: &dyn db::DefDatabase,
|
db: &dyn ExpandDatabase,
|
||||||
krate: CrateId,
|
krate: CrateId,
|
||||||
resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
|
resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
|
||||||
) -> Result<ExpandResult<Option<MacroCallId>>, UnresolvedMacro>;
|
) -> Result<ExpandResult<Option<MacroCallId>>, UnresolvedMacro>;
|
||||||
|
@ -809,15 +813,14 @@ pub trait AsMacroCall {
|
||||||
impl AsMacroCall for InFile<&ast::MacroCall> {
|
impl AsMacroCall for InFile<&ast::MacroCall> {
|
||||||
fn as_call_id_with_errors(
|
fn as_call_id_with_errors(
|
||||||
&self,
|
&self,
|
||||||
db: &dyn db::DefDatabase,
|
db: &dyn ExpandDatabase,
|
||||||
krate: CrateId,
|
krate: CrateId,
|
||||||
resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
|
resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
|
||||||
) -> Result<ExpandResult<Option<MacroCallId>>, UnresolvedMacro> {
|
) -> Result<ExpandResult<Option<MacroCallId>>, UnresolvedMacro> {
|
||||||
let expands_to = hir_expand::ExpandTo::from_call_site(self.value);
|
let expands_to = hir_expand::ExpandTo::from_call_site(self.value);
|
||||||
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, self.file_id);
|
||||||
let path =
|
let path = self.value.path().and_then(|path| path::ModPath::from_src(db, path, &h));
|
||||||
self.value.path().and_then(|path| path::ModPath::from_src(db.upcast(), path, &h));
|
|
||||||
|
|
||||||
let Some(path) = path else {
|
let Some(path) = path else {
|
||||||
return Ok(ExpandResult::only_err(ExpandError::Other("malformed macro invocation".into())));
|
return Ok(ExpandResult::only_err(ExpandError::Other("malformed macro invocation".into())));
|
||||||
|
@ -847,7 +850,7 @@ impl<T: ast::AstNode> AstIdWithPath<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn macro_call_as_call_id(
|
fn macro_call_as_call_id(
|
||||||
db: &dyn db::DefDatabase,
|
db: &dyn ExpandDatabase,
|
||||||
call: &AstIdWithPath<ast::MacroCall>,
|
call: &AstIdWithPath<ast::MacroCall>,
|
||||||
expand_to: ExpandTo,
|
expand_to: ExpandTo,
|
||||||
krate: CrateId,
|
krate: CrateId,
|
||||||
|
@ -857,7 +860,7 @@ fn macro_call_as_call_id(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn macro_call_as_call_id_(
|
fn macro_call_as_call_id_(
|
||||||
db: &dyn db::DefDatabase,
|
db: &dyn ExpandDatabase,
|
||||||
call: &AstIdWithPath<ast::MacroCall>,
|
call: &AstIdWithPath<ast::MacroCall>,
|
||||||
expand_to: ExpandTo,
|
expand_to: ExpandTo,
|
||||||
krate: CrateId,
|
krate: CrateId,
|
||||||
|
@ -867,13 +870,12 @@ fn macro_call_as_call_id_(
|
||||||
resolver(call.path.clone()).ok_or_else(|| UnresolvedMacro { path: call.path.clone() })?;
|
resolver(call.path.clone()).ok_or_else(|| UnresolvedMacro { path: call.path.clone() })?;
|
||||||
|
|
||||||
let res = if let MacroDefKind::BuiltInEager(..) = def.kind {
|
let res = if let MacroDefKind::BuiltInEager(..) = def.kind {
|
||||||
let macro_call = InFile::new(call.ast_id.file_id, call.ast_id.to_node(db.upcast()));
|
let macro_call = InFile::new(call.ast_id.file_id, call.ast_id.to_node(db));
|
||||||
|
expand_eager_macro(db, krate, macro_call, def, &resolver)?
|
||||||
expand_eager_macro(db.upcast(), krate, macro_call, def, &resolver)?
|
|
||||||
} else {
|
} else {
|
||||||
ExpandResult {
|
ExpandResult {
|
||||||
value: Some(def.as_lazy_macro(
|
value: Some(def.as_lazy_macro(
|
||||||
db.upcast(),
|
db,
|
||||||
krate,
|
krate,
|
||||||
MacroCallKind::FnLike { ast_id: call.ast_id, expand_to },
|
MacroCallKind::FnLike { ast_id: call.ast_id, expand_to },
|
||||||
)),
|
)),
|
||||||
|
|
46
crates/hir-def/src/lower.rs
Normal file
46
crates/hir-def/src/lower.rs
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
//! Context for lowering paths.
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, AstId, HirFileId, InFile};
|
||||||
|
use once_cell::unsync::OnceCell;
|
||||||
|
use syntax::ast;
|
||||||
|
|
||||||
|
use crate::{db::DefDatabase, path::Path};
|
||||||
|
|
||||||
|
pub struct LowerCtx<'a> {
|
||||||
|
pub db: &'a dyn DefDatabase,
|
||||||
|
hygiene: Hygiene,
|
||||||
|
ast_id_map: Option<(HirFileId, OnceCell<Arc<AstIdMap>>)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> LowerCtx<'a> {
|
||||||
|
pub fn new(db: &'a dyn DefDatabase, hygiene: &Hygiene, file_id: HirFileId) -> Self {
|
||||||
|
LowerCtx { db, hygiene: hygiene.clone(), ast_id_map: Some((file_id, OnceCell::new())) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_file_id(db: &'a dyn DefDatabase, file_id: HirFileId) -> Self {
|
||||||
|
LowerCtx {
|
||||||
|
db,
|
||||||
|
hygiene: Hygiene::new(db.upcast(), file_id),
|
||||||
|
ast_id_map: Some((file_id, OnceCell::new())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_hygiene(db: &'a dyn DefDatabase, hygiene: &Hygiene) -> Self {
|
||||||
|
LowerCtx { db, hygiene: hygiene.clone(), ast_id_map: None }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn hygiene(&self) -> &Hygiene {
|
||||||
|
&self.hygiene
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn lower_path(&self, ast: ast::Path) -> Option<Path> {
|
||||||
|
Path::from_src(ast, self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn ast_id<N: syntax::AstNode>(&self, item: &N) -> Option<AstId<N>> {
|
||||||
|
let &(file_id, ref ast_id_map) = self.ast_id_map.as_ref()?;
|
||||||
|
let ast_id_map = ast_id_map.get_or_init(|| self.db.ast_id_map(file_id));
|
||||||
|
Some(InFile::new(file_id, ast_id_map.ast_id(item)))
|
||||||
|
}
|
||||||
|
}
|
|
@ -1111,7 +1111,7 @@ impl DefCollector<'_> {
|
||||||
match &directive.kind {
|
match &directive.kind {
|
||||||
MacroDirectiveKind::FnLike { ast_id, expand_to } => {
|
MacroDirectiveKind::FnLike { ast_id, expand_to } => {
|
||||||
let call_id = macro_call_as_call_id(
|
let call_id = macro_call_as_call_id(
|
||||||
self.db,
|
self.db.upcast(),
|
||||||
ast_id,
|
ast_id,
|
||||||
*expand_to,
|
*expand_to,
|
||||||
self.def_map.krate,
|
self.def_map.krate,
|
||||||
|
@ -1402,7 +1402,7 @@ impl DefCollector<'_> {
|
||||||
MacroDirectiveKind::FnLike { ast_id, expand_to } => {
|
MacroDirectiveKind::FnLike { ast_id, expand_to } => {
|
||||||
// FIXME: we shouldn't need to re-resolve the macro here just to get the unresolved error!
|
// FIXME: we shouldn't need to re-resolve the macro here just to get the unresolved error!
|
||||||
let macro_call_as_call_id = macro_call_as_call_id(
|
let macro_call_as_call_id = macro_call_as_call_id(
|
||||||
self.db,
|
self.db.upcast(),
|
||||||
ast_id,
|
ast_id,
|
||||||
*expand_to,
|
*expand_to,
|
||||||
self.def_map.krate,
|
self.def_map.krate,
|
||||||
|
@ -2117,7 +2117,7 @@ impl ModCollector<'_, '_> {
|
||||||
|
|
||||||
// Case 1: try to resolve in legacy scope and expand macro_rules
|
// Case 1: try to resolve in legacy scope and expand macro_rules
|
||||||
if let Ok(res) = macro_call_as_call_id(
|
if let Ok(res) = macro_call_as_call_id(
|
||||||
self.def_collector.db,
|
self.def_collector.db.upcast(),
|
||||||
&ast_id,
|
&ast_id,
|
||||||
mac.expand_to,
|
mac.expand_to,
|
||||||
self.def_collector.def_map.krate,
|
self.def_collector.def_map.krate,
|
||||||
|
|
|
@ -2,7 +2,7 @@ use std::sync::Arc;
|
||||||
|
|
||||||
use base_db::SourceDatabaseExt;
|
use base_db::SourceDatabaseExt;
|
||||||
|
|
||||||
use crate::{AdtId, ModuleDefId};
|
use crate::{db::DefDatabase, AdtId, ModuleDefId};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,8 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
body::LowerCtx,
|
|
||||||
lang_item::LangItemTarget,
|
lang_item::LangItemTarget,
|
||||||
|
lower::LowerCtx,
|
||||||
type_ref::{ConstRefOrPath, LifetimeRef, TypeBound, TypeRef},
|
type_ref::{ConstRefOrPath, LifetimeRef, TypeBound, TypeRef},
|
||||||
};
|
};
|
||||||
use hir_expand::name::Name;
|
use hir_expand::name::Name;
|
||||||
|
|
|
@ -2,17 +2,15 @@
|
||||||
|
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
use crate::type_ref::ConstRefOrPath;
|
use crate::{lower::LowerCtx, type_ref::ConstRefOrPath};
|
||||||
|
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use hir_expand::name::{name, AsName};
|
use hir_expand::name::{name, AsName};
|
||||||
use intern::Interned;
|
use intern::Interned;
|
||||||
use syntax::ast::{self, AstNode, HasTypeBounds};
|
use syntax::ast::{self, AstNode, HasTypeBounds};
|
||||||
|
|
||||||
use super::AssociatedTypeBinding;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
body::LowerCtx,
|
path::{AssociatedTypeBinding, GenericArg, GenericArgs, ModPath, Path, PathKind},
|
||||||
path::{GenericArg, GenericArgs, ModPath, Path, PathKind},
|
|
||||||
type_ref::{LifetimeRef, TypeBound, TypeRef},
|
type_ref::{LifetimeRef, TypeBound, TypeRef},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@ use std::fmt::{self, Debug};
|
||||||
use base_db::CrateId;
|
use base_db::CrateId;
|
||||||
use chalk_ir::{BoundVar, TyKind};
|
use chalk_ir::{BoundVar, TyKind};
|
||||||
use hir_def::{
|
use hir_def::{
|
||||||
body,
|
|
||||||
data::adt::VariantData,
|
data::adt::VariantData,
|
||||||
db::DefDatabase,
|
db::DefDatabase,
|
||||||
find_path,
|
find_path,
|
||||||
|
@ -1552,7 +1551,10 @@ 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(f.db.upcast(), &Hygiene::new_unhygienic());
|
let ctx = hir_def::lower::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(path, &ctx) {
|
||||||
Some(path) => path.hir_fmt(f)?,
|
Some(path) => path.hir_fmt(f)?,
|
||||||
|
|
|
@ -43,7 +43,7 @@ impl_internable!(
|
||||||
);
|
);
|
||||||
|
|
||||||
impl chalk_ir::interner::Interner for Interner {
|
impl chalk_ir::interner::Interner for Interner {
|
||||||
type InternedType = Interned<InternedWrapper<chalk_ir::TyData<Interner>>>;
|
type InternedType = Interned<InternedWrapper<chalk_ir::TyData<Self>>>;
|
||||||
type InternedLifetime = Interned<InternedWrapper<chalk_ir::LifetimeData<Self>>>;
|
type InternedLifetime = Interned<InternedWrapper<chalk_ir::LifetimeData<Self>>>;
|
||||||
type InternedConst = Interned<InternedWrapper<chalk_ir::ConstData<Self>>>;
|
type InternedConst = Interned<InternedWrapper<chalk_ir::ConstData<Self>>>;
|
||||||
type InternedConcreteConst = ConstScalar;
|
type InternedConcreteConst = ConstScalar;
|
||||||
|
|
|
@ -18,9 +18,9 @@ use chalk_ir::{
|
||||||
|
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use hir_def::{
|
use hir_def::{
|
||||||
body::Expander,
|
|
||||||
builtin_type::BuiltinType,
|
builtin_type::BuiltinType,
|
||||||
data::adt::StructKind,
|
data::adt::StructKind,
|
||||||
|
expander::Expander,
|
||||||
generics::{
|
generics::{
|
||||||
TypeOrConstParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget,
|
TypeOrConstParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget,
|
||||||
},
|
},
|
||||||
|
@ -378,7 +378,9 @@ impl<'a> TyLoweringContext<'a> {
|
||||||
};
|
};
|
||||||
let ty = {
|
let ty = {
|
||||||
let macro_call = macro_call.to_node(self.db.upcast());
|
let macro_call = macro_call.to_node(self.db.upcast());
|
||||||
match expander.enter_expand::<ast::Type>(self.db.upcast(), macro_call) {
|
match expander.enter_expand::<ast::Type>(self.db.upcast(), macro_call, |path| {
|
||||||
|
self.resolver.resolve_path_as_macro(self.db.upcast(), &path)
|
||||||
|
}) {
|
||||||
Ok(ExpandResult { value: Some((mark, expanded)), .. }) => {
|
Ok(ExpandResult { value: Some((mark, expanded)), .. }) => {
|
||||||
let ctx = expander.ctx(self.db.upcast());
|
let ctx = expander.ctx(self.db.upcast());
|
||||||
// FIXME: Report syntax errors in expansion here
|
// FIXME: Report syntax errors in expansion here
|
||||||
|
|
|
@ -7,8 +7,8 @@ use std::{cell::RefCell, fmt, iter, mem, ops};
|
||||||
use base_db::{FileId, FileRange};
|
use base_db::{FileId, FileRange};
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use hir_def::{
|
use hir_def::{
|
||||||
body,
|
|
||||||
hir::Expr,
|
hir::Expr,
|
||||||
|
lower::LowerCtx,
|
||||||
macro_id_to_def_id,
|
macro_id_to_def_id,
|
||||||
resolver::{self, HasResolver, Resolver, TypeNs},
|
resolver::{self, HasResolver, Resolver, TypeNs},
|
||||||
type_ref::Mutability,
|
type_ref::Mutability,
|
||||||
|
@ -1065,7 +1065,7 @@ impl<'db> SemanticsImpl<'db> {
|
||||||
|
|
||||||
fn resolve_type(&self, ty: &ast::Type) -> Option<Type> {
|
fn resolve_type(&self, ty: &ast::Type) -> Option<Type> {
|
||||||
let analyze = self.analyze(ty.syntax())?;
|
let analyze = self.analyze(ty.syntax())?;
|
||||||
let ctx = body::LowerCtx::with_file_id(self.db.upcast(), analyze.file_id);
|
let ctx = LowerCtx::with_file_id(self.db.upcast(), analyze.file_id);
|
||||||
let ty = hir_ty::TyLoweringContext::new(self.db, &analyze.resolver)
|
let ty = hir_ty::TyLoweringContext::new(self.db, &analyze.resolver)
|
||||||
.lower_ty(&crate::TypeRef::from_ast(&ctx, ty.clone()));
|
.lower_ty(&crate::TypeRef::from_ast(&ctx, ty.clone()));
|
||||||
Some(Type::new_with_resolver(self.db, &analyze.resolver, ty))
|
Some(Type::new_with_resolver(self.db, &analyze.resolver, ty))
|
||||||
|
@ -1074,7 +1074,7 @@ impl<'db> SemanticsImpl<'db> {
|
||||||
fn resolve_trait(&self, path: &ast::Path) -> Option<Trait> {
|
fn resolve_trait(&self, path: &ast::Path) -> Option<Trait> {
|
||||||
let analyze = self.analyze(path.syntax())?;
|
let analyze = self.analyze(path.syntax())?;
|
||||||
let hygiene = hir_expand::hygiene::Hygiene::new(self.db.upcast(), analyze.file_id);
|
let hygiene = hir_expand::hygiene::Hygiene::new(self.db.upcast(), analyze.file_id);
|
||||||
let ctx = body::LowerCtx::with_hygiene(self.db.upcast(), &hygiene);
|
let ctx = LowerCtx::with_hygiene(self.db.upcast(), &hygiene);
|
||||||
let hir_path = Path::from_src(path.clone(), &ctx)?;
|
let hir_path = Path::from_src(path.clone(), &ctx)?;
|
||||||
match analyze.resolver.resolve_path_in_type_ns_fully(self.db.upcast(), &hir_path)? {
|
match analyze.resolver.resolve_path_in_type_ns_fully(self.db.upcast(), &hir_path)? {
|
||||||
TypeNs::TraitId(id) => Some(Trait { id }),
|
TypeNs::TraitId(id) => Some(Trait { id }),
|
||||||
|
@ -1672,7 +1672,7 @@ impl<'a> SemanticsScope<'a> {
|
||||||
/// Resolve a path as-if it was written at the given scope. This is
|
/// Resolve a path as-if it was written at the given scope. This is
|
||||||
/// 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::with_file_id(self.db.upcast(), self.file_id);
|
let ctx = LowerCtx::with_file_id(self.db.upcast(), self.file_id);
|
||||||
let path = Path::from_src(path.clone(), &ctx)?;
|
let path = Path::from_src(path.clone(), &ctx)?;
|
||||||
resolve_hir_path(self.db, &self.resolver, &path)
|
resolve_hir_path(self.db, &self.resolver, &path)
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,12 +13,12 @@ use std::{
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use hir_def::{
|
use hir_def::{
|
||||||
body::{
|
body::{
|
||||||
self,
|
|
||||||
scope::{ExprScopes, ScopeId},
|
scope::{ExprScopes, ScopeId},
|
||||||
Body, BodySourceMap,
|
Body, BodySourceMap,
|
||||||
},
|
},
|
||||||
hir::{ExprId, Pat, PatId},
|
hir::{ExprId, Pat, PatId},
|
||||||
lang_item::LangItem,
|
lang_item::LangItem,
|
||||||
|
lower::LowerCtx,
|
||||||
macro_id_to_def_id,
|
macro_id_to_def_id,
|
||||||
path::{ModPath, Path, PathKind},
|
path::{ModPath, Path, PathKind},
|
||||||
resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs},
|
resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs},
|
||||||
|
@ -463,7 +463,7 @@ impl SourceAnalyzer {
|
||||||
db: &dyn HirDatabase,
|
db: &dyn HirDatabase,
|
||||||
macro_call: InFile<&ast::MacroCall>,
|
macro_call: InFile<&ast::MacroCall>,
|
||||||
) -> Option<Macro> {
|
) -> Option<Macro> {
|
||||||
let ctx = body::LowerCtx::with_file_id(db.upcast(), macro_call.file_id);
|
let ctx = LowerCtx::with_file_id(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(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())
|
||||||
}
|
}
|
||||||
|
@ -575,7 +575,7 @@ 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(db.upcast(), &hygiene);
|
let ctx = LowerCtx::with_hygiene(db.upcast(), &hygiene);
|
||||||
let hir_path = Path::from_src(path.clone(), &ctx)?;
|
let hir_path = Path::from_src(path.clone(), &ctx)?;
|
||||||
|
|
||||||
// Case where path is a qualifier of a use tree, e.g. foo::bar::{Baz, Qux} where we are
|
// Case where path is a qualifier of a use tree, e.g. foo::bar::{Baz, Qux} where we are
|
||||||
|
|
|
@ -109,6 +109,9 @@ impl LineIndex {
|
||||||
line_wide_chars.insert(line, wide_chars);
|
line_wide_chars.insert(line, wide_chars);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
newlines.shrink_to_fit();
|
||||||
|
line_wide_chars.shrink_to_fit();
|
||||||
|
|
||||||
LineIndex { newlines, line_wide_chars }
|
LineIndex { newlines, line_wide_chars }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -93,6 +93,7 @@ impl Query {
|
||||||
pub trait SymbolsDatabase: HirDatabase + SourceDatabaseExt + Upcast<dyn HirDatabase> {
|
pub trait SymbolsDatabase: HirDatabase + SourceDatabaseExt + Upcast<dyn HirDatabase> {
|
||||||
/// The symbol index for a given module. These modules should only be in source roots that
|
/// The symbol index for a given module. These modules should only be in source roots that
|
||||||
/// are inside local_roots.
|
/// are inside local_roots.
|
||||||
|
// FIXME: We should probably LRU this
|
||||||
fn module_symbols(&self, module: Module) -> Arc<SymbolIndex>;
|
fn module_symbols(&self, module: Module) -> Arc<SymbolIndex>;
|
||||||
|
|
||||||
/// The symbol index for a given source root within library_roots.
|
/// The symbol index for a given source root within library_roots.
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
use std::sync::atomic::AtomicUsize;
|
use std::sync::atomic::AtomicUsize;
|
||||||
|
|
||||||
/// Represents a struct used to enforce a numerical limit.
|
/// Represents a struct used to enforce a numerical limit.
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Limit {
|
pub struct Limit {
|
||||||
upper_bound: usize,
|
upper_bound: usize,
|
||||||
#[cfg(feature = "tracking")]
|
#[cfg(feature = "tracking")]
|
||||||
|
|
Loading…
Reference in a new issue