Unnamed repository; edit this file 'description' to name the repository.
Auto merge of #14594 - Veykril:Simplify, r=Veykril
internal: Move Expander and LowerCtx into separate modules
bors 2023-04-18
parent b92b7c0 · parent bca8029 · commit 9b835f3
-rw-r--r--crates/hir-def/src/attr.rs86
-rw-r--r--crates/hir-def/src/body.rs347
-rw-r--r--crates/hir-def/src/body/lower.rs32
-rw-r--r--crates/hir-def/src/data.rs33
-rw-r--r--crates/hir-def/src/data/adt.rs3
-rw-r--r--crates/hir-def/src/db.rs6
-rw-r--r--crates/hir-def/src/expander.rs211
-rw-r--r--crates/hir-def/src/generics.rs42
-rw-r--r--crates/hir-def/src/hir/type_ref.rs2
-rw-r--r--crates/hir-def/src/import_map.rs2
-rw-r--r--crates/hir-def/src/item_tree/lower.rs4
-rw-r--r--crates/hir-def/src/lib.rs26
-rw-r--r--crates/hir-def/src/lower.rs46
-rw-r--r--crates/hir-def/src/nameres/collector.rs6
-rw-r--r--crates/hir-def/src/nameres/tests/incremental.rs2
-rw-r--r--crates/hir-def/src/path.rs2
-rw-r--r--crates/hir-def/src/path/lower.rs6
-rw-r--r--crates/hir-ty/src/display.rs6
-rw-r--r--crates/hir-ty/src/interner.rs2
-rw-r--r--crates/hir-ty/src/lower.rs6
-rw-r--r--crates/hir/src/semantics.rs8
-rw-r--r--crates/hir/src/source_analyzer.rs6
-rw-r--r--crates/ide-db/src/line_index.rs3
-rw-r--r--crates/ide-db/src/symbol_index.rs1
-rw-r--r--crates/limit/src/lib.rs1
25 files changed, 487 insertions, 402 deletions
diff --git a/crates/hir-def/src/attr.rs b/crates/hir-def/src/attr.rs
index a00337ae9c..1ebbe160b0 100644
--- a/crates/hir-def/src/attr.rs
+++ b/crates/hir-def/src/attr.rs
@@ -28,8 +28,8 @@ use crate::{
lang_item::LangItem,
nameres::{ModuleOrigin, ModuleSource},
src::{HasChildSource, HasSource},
- AdtId, AttrDefId, EnumId, GenericParamId, LocalEnumVariantId, LocalFieldId, Lookup, MacroId,
- VariantId,
+ AdtId, AssocItemLoc, AttrDefId, EnumId, GenericParamId, ItemLoc, LocalEnumVariantId,
+ LocalFieldId, Lookup, MacroId, VariantId,
};
/// Holds documentation
@@ -421,23 +421,24 @@ impl AttrsWithOwner {
AttrDefId::EnumVariantId(it) => {
return db.variants_attrs(it.parent)[it.local_id].clone();
}
+ // FIXME: DRY this up
AttrDefId::AdtId(it) => match it {
- AdtId::StructId(it) => attrs_from_item_tree(it.lookup(db).id, db),
- AdtId::EnumId(it) => attrs_from_item_tree(it.lookup(db).id, db),
- AdtId::UnionId(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_loc(db, it),
+ AdtId::UnionId(it) => attrs_from_item_tree_loc(db, it),
},
- AttrDefId::TraitId(it) => attrs_from_item_tree(it.lookup(db).id, db),
- AttrDefId::TraitAliasId(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_loc(db, it),
AttrDefId::MacroId(it) => match it {
- MacroId::Macro2Id(it) => attrs_from_item_tree(it.lookup(db).id, db),
- MacroId::MacroRulesId(it) => attrs_from_item_tree(it.lookup(db).id, db),
- MacroId::ProcMacroId(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(db, it.lookup(db).id),
+ 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::ConstId(it) => attrs_from_item_tree(it.lookup(db).id, db),
- AttrDefId::StaticId(it) => attrs_from_item_tree(it.lookup(db).id, db),
- AttrDefId::FunctionId(it) => attrs_from_item_tree(it.lookup(db).id, db),
- AttrDefId::TypeAliasId(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_assoc(db, it),
+ AttrDefId::StaticId(it) => attrs_from_item_tree_assoc(db, it),
+ AttrDefId::FunctionId(it) => attrs_from_item_tree_assoc(db, it),
+ AttrDefId::TypeAliasId(it) => attrs_from_item_tree_assoc(db, it),
AttrDefId::GenericParamId(it) => match it {
GenericParamId::ConstParamId(it) => {
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]))
}
},
- 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));
@@ -506,28 +507,28 @@ impl AttrsWithOwner {
InFile::new(file_id, owner)
}
AttrDefId::AdtId(adt) => match adt {
- AdtId::StructId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new),
- AdtId::UnionId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new),
- AdtId::EnumId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new),
+ AdtId::StructId(id) => any_has_attrs(db, id),
+ AdtId::UnionId(id) => any_has_attrs(db, id),
+ 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) => {
let map = db.variants_attrs_source_map(id.parent);
let file_id = id.parent.lookup(db).id.file_id();
let root = db.parse_or_expand(file_id);
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::ConstId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new),
- AttrDefId::TraitId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new),
- AttrDefId::TraitAliasId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new),
- AttrDefId::TypeAliasId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new),
+ AttrDefId::StaticId(id) => any_has_attrs(db, id),
+ AttrDefId::ConstId(id) => any_has_attrs(db, id),
+ AttrDefId::TraitId(id) => any_has_attrs(db, id),
+ AttrDefId::TraitAliasId(id) => any_has_attrs(db, id),
+ AttrDefId::TypeAliasId(id) => any_has_attrs(db, id),
AttrDefId::MacroId(id) => match id {
- MacroId::Macro2Id(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new),
- MacroId::MacroRulesId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new),
- MacroId::ProcMacroId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new),
+ MacroId::Macro2Id(id) => any_has_attrs(db, id),
+ MacroId::MacroRulesId(id) => any_has_attrs(db, id),
+ 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 {
GenericParamId::ConstParamId(id) => id
.parent()
@@ -542,7 +543,7 @@ impl AttrsWithOwner {
.child_source(db)
.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))
@@ -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 mod_item = N::id_to_mod_item(id.value);
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(
db: &dyn DefDatabase,
def: EnumId,
diff --git a/crates/hir-def/src/body.rs b/crates/hir-def/src/body.rs
index cf2227b379..0c0e8ac820 100644
--- a/crates/hir-def/src/body.rs
+++ b/crates/hir-def/src/body.rs
@@ -10,284 +10,25 @@ use std::{ops::Index, sync::Arc};
use base_db::CrateId;
use cfg::{CfgExpr, CfgOptions};
-use drop_bomb::DropBomb;
use either::Either;
-use hir_expand::{
- ast_id_map::AstIdMap, attrs::RawAttrs, hygiene::Hygiene, name::Name, AstId, ExpandError,
- ExpandResult, HirFileId, InFile, MacroCallId,
-};
+use hir_expand::{name::Name, HirFileId, InFile};
use la_arena::{Arena, ArenaMap};
-use limit::Limit;
-use once_cell::unsync::OnceCell;
use profile::Count;
use rustc_hash::FxHashMap;
-use syntax::{ast, AstPtr, Parse, SyntaxNode, SyntaxNodePtr};
+use syntax::{ast, AstPtr, SyntaxNodePtr};
use crate::{
- attr::Attrs,
db::DefDatabase,
+ expander::Expander,
hir::{
dummy_expr_id, Binding, BindingId, Expr, ExprId, Label, LabelId, Pat, PatId, RecordFieldPat,
},
- item_scope::BuiltinShadowMode,
- macro_id_to_def_id,
nameres::DefMap,
path::{ModPath, Path},
src::{HasChildSource, HasSource},
- AsMacroCall, BlockId, DefWithBodyId, HasModule, LocalModuleId, Lookup, MacroId, ModuleId,
- UnresolvedMacro,
+ BlockId, DefWithBodyId, HasModule, Lookup,
};
-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, &macro_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.).
#[derive(Debug, Eq, PartialEq)]
pub struct Body {
@@ -376,47 +117,49 @@ impl Body {
let _p = profile::span("body_with_source_map_query");
let mut params = None;
- let (file_id, module, body, is_async_fn) = match def {
- DefWithBodyId::FunctionId(f) => {
- let data = db.function_data(f);
- let f = f.lookup(db);
- let src = f.source(db);
- params = src.value.param_list().map(|param_list| {
- let item_tree = f.id.item_tree(db);
- let func = &item_tree[f.id.value];
- let krate = f.container.module(db).krate;
- let crate_graph = db.crate_graph();
+ let (file_id, module, body, is_async_fn) = {
+ match def {
+ DefWithBodyId::FunctionId(f) => {
+ let data = db.function_data(f);
+ let f = f.lookup(db);
+ let src = f.source(db);
+ params = src.value.param_list().map(|param_list| {
+ let item_tree = f.id.item_tree(db);
+ let func = &item_tree[f.id.value];
+ 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,
- func.params.clone().map(move |param| {
- item_tree
- .attrs(db, krate, param.into())
- .is_cfg_enabled(&crate_graph[krate].cfg_options)
- }),
+ src.file_id,
+ f.module(db),
+ src.value.body().map(ast::Expr::from),
+ data.has_async_kw(),
)
- });
- (
- src.file_id,
- f.module(db),
- src.value.body().map(ast::Expr::from),
- data.has_async_kw(),
- )
- }
- DefWithBodyId::ConstId(c) => {
- let c = c.lookup(db);
- let src = c.source(db);
- (src.file_id, c.module(db), src.value.body(), false)
- }
- DefWithBodyId::StaticId(s) => {
- let s = s.lookup(db);
- let src = s.source(db);
- (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)
+ }
+ DefWithBodyId::ConstId(c) => {
+ let c = c.lookup(db);
+ let src = c.source(db);
+ (src.file_id, c.module(db), src.value.body(), false)
+ }
+ DefWithBodyId::StaticId(s) => {
+ let s = s.lookup(db);
+ let src = s.source(db);
+ (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);
diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs
index db619b97db..27dfe766d3 100644
--- a/crates/hir-def/src/body/lower.rs
+++ b/crates/hir-def/src/body/lower.rs
@@ -24,9 +24,10 @@ use syntax::{
};
use crate::{
- body::{Body, BodyDiagnostic, BodySourceMap, Expander, ExprPtr, LabelPtr, LowerCtx, PatPtr},
+ body::{Body, BodyDiagnostic, BodySourceMap, ExprPtr, LabelPtr, PatPtr},
data::adt::StructKind,
db::DefDatabase,
+ expander::Expander,
hir::{
dummy_expr_id, Array, Binding, BindingAnnotation, BindingId, CaptureBy, ClosureKind, Expr,
ExprId, Label, LabelId, Literal, MatchArm, Movability, Pat, PatId, RecordFieldPat,
@@ -34,6 +35,8 @@ use crate::{
},
item_scope::BuiltinShadowMode,
lang_item::LangItem,
+ lower::LowerCtx,
+ nameres::DefMap,
path::{GenericArgs, Path},
type_ref::{Mutability, Rawness, TypeRef},
AdtId, BlockId, BlockLoc, ModuleDefId, UnresolvedMacro,
@@ -50,6 +53,7 @@ pub(super) fn lower(
ExprCollector {
db,
krate,
+ def_map: db.crate_def_map(krate),
source_map: BodySourceMap::default(),
ast_id_map: db.ast_id_map(expander.current_file_id),
body: Body {
@@ -75,6 +79,7 @@ pub(super) fn lower(
struct ExprCollector<'a> {
db: &'a dyn DefDatabase,
expander: Expander,
+ def_map: Arc<DefMap>,
ast_id_map: Arc<AstIdMap>,
krate: CrateId,
body: Body,
@@ -777,7 +782,13 @@ impl ExprCollector<'_> {
let outer_file = self.expander.current_file_id;
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 {
Ok(res) => res,
@@ -944,10 +955,7 @@ impl ExprCollector<'_> {
let block_id = if block_has_items {
let file_local_id = self.ast_id_map.ast_id(&block);
let ast_id = AstId::new(self.expander.current_file_id, file_local_id);
- Some(self.db.intern_block(BlockLoc {
- ast_id,
- module: self.expander.def_map.module_id(self.expander.module),
- }))
+ Some(self.db.intern_block(BlockLoc { ast_id, module: self.expander.module }))
} else {
None
};
@@ -956,11 +964,11 @@ impl ExprCollector<'_> {
match block_id.map(|block_id| (self.db.block_def_map(block_id), block_id)) {
Some((def_map, 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 mut statements = Vec::new();
@@ -982,7 +990,7 @@ impl ExprCollector<'_> {
let expr_id = self
.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;
expr_id
}
@@ -1028,9 +1036,9 @@ impl ExprCollector<'_> {
let (binding, pattern) = if is_simple_ident_pat {
// This could also be a single-segment path pattern. To
// 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.expander.module,
+ self.expander.module.local_id,
&name.clone().into(),
BuiltinShadowMode::Other,
);
diff --git a/crates/hir-def/src/data.rs b/crates/hir-def/src/data.rs
index 3fdd09b004..73d4eebb85 100644
--- a/crates/hir-def/src/data.rs
+++ b/crates/hir-def/src/data.rs
@@ -11,8 +11,8 @@ use syntax::{ast, Parse};
use crate::{
attr::Attrs,
- body::{Expander, Mark},
db::DefDatabase,
+ expander::{Expander, Mark},
item_tree::{self, AssocItem, FnFlags, ItemTree, ItemTreeId, ModItem, Param, TreeId},
nameres::{
attr_resolution::ResolvedAttr,
@@ -44,16 +44,16 @@ impl FunctionData {
pub(crate) fn fn_data_query(db: &dyn DefDatabase, func: FunctionId) -> Arc<FunctionData> {
let loc = func.lookup(db);
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 func = &item_tree[loc.id.value];
let visibility = if let ItemContainerId::TraitId(trait_id) = loc.container {
- db.trait_data(trait_id).visibility.clone()
+ trait_vis(db, trait_id)
} else {
item_tree[func.visibility].clone()
};
+ let crate_graph = db.crate_graph();
+ let cfg_options = &crate_graph[krate].cfg_options;
let enabled_params = func
.params
.clone()
@@ -188,7 +188,7 @@ impl TypeAliasData {
let item_tree = loc.id.item_tree(db);
let typ = &item_tree[loc.id.value];
let visibility = if let ItemContainerId::TraitId(trait_id) = loc.container {
- db.trait_data(trait_id).visibility.clone()
+ trait_vis(db, trait_id)
} else {
item_tree[typ.visibility].clone()
};
@@ -471,7 +471,7 @@ impl ConstData {
let item_tree = loc.id.item_tree(db);
let konst = &item_tree[loc.id.value];
let visibility = if let ItemContainerId::TraitId(trait_id) = loc.container {
- db.trait_data(trait_id).visibility.clone()
+ trait_vis(db, trait_id)
} else {
item_tree[konst.visibility].clone()
};
@@ -647,8 +647,20 @@ impl<'a> AssocItemCollector<'a> {
let _cx = stdx::panic_context::enter(format!(
"collect_items MacroCall: {macro_call}"
));
+ let module = self.expander.module.local_id;
+
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 {
ast_id: InFile::new(file_id, call.ast_id),
@@ -692,3 +704,10 @@ impl<'a> AssocItemCollector<'a> {
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()
+}
diff --git a/crates/hir-def/src/data/adt.rs b/crates/hir-def/src/data/adt.rs
index fd1d54233d..31f9131799 100644
--- a/crates/hir-def/src/data/adt.rs
+++ b/crates/hir-def/src/data/adt.rs
@@ -17,11 +17,12 @@ use rustc_abi::{Align, Integer, IntegerType, ReprFlags, ReprOptions};
use syntax::ast::{self, HasName, HasVisibility};
use crate::{
- body::{CfgExpander, LowerCtx},
builtin_type::{BuiltinInt, BuiltinUint},
db::DefDatabase,
+ expander::CfgExpander,
item_tree::{AttrOwner, Field, FieldAstId, Fields, ItemTree, ModItem, RawVisibilityId},
lang_item::LangItem,
+ lower::LowerCtx,
nameres::diagnostics::DefDiagnostic,
src::HasChildSource,
src::HasSource,
diff --git a/crates/hir-def/src/db.rs b/crates/hir-def/src/db.rs
index 678b0fcb7e..cc87b03eef 100644
--- a/crates/hir-def/src/db.rs
+++ b/crates/hir-def/src/db.rs
@@ -217,6 +217,8 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba
#[salsa::transparent]
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;
}
@@ -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 {
let file = db.crate_graph()[crate_id].root_file_id;
let item_tree = db.file_item_tree(file.into());
diff --git a/crates/hir-def/src/expander.rs b/crates/hir-def/src/expander.rs
new file mode 100644
index 0000000000..34ed1e72f2
--- /dev/null
+++ b/crates/hir-def/src/expander.rs
@@ -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, &macro_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,
+}
diff --git a/crates/hir-def/src/generics.rs b/crates/hir-def/src/generics.rs
index c1e20d657b..c766857758 100644
--- a/crates/hir-def/src/generics.rs
+++ b/crates/hir-def/src/generics.rs
@@ -3,6 +3,8 @@
//! generic parameters. See also the `Generics` type and the `generics_of` query
//! in rustc.
+use std::sync::Arc;
+
use base_db::FileId;
use either::Either;
use hir_expand::{
@@ -16,10 +18,12 @@ use stdx::impl_from;
use syntax::ast::{self, HasGenericParams, HasName, HasTypeBounds};
use crate::{
- body::{Expander, LowerCtx},
child_by_source::ChildBySource,
db::DefDatabase,
dyn_map::{keys, DynMap},
+ expander::Expander,
+ lower::LowerCtx,
+ nameres::DefMap,
src::{HasChildSource, HasSource},
type_ref::{LifetimeRef, TypeBound, TypeRef},
AdtId, ConstParamId, GenericDefId, HasModule, LifetimeParamId, LocalLifetimeParamId,
@@ -151,7 +155,6 @@ impl GenericParams {
def: GenericDefId,
) -> Interned<GenericParams> {
let _p = profile::span("generic_params_query");
-
macro_rules! id_to_generics {
($id:ident) => {{
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
// 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 {
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(
&mut self,
db: &dyn DefDatabase,
- expander: &mut Expander,
+ exp: &mut Lazy<(Arc<DefMap>, Expander), impl FnOnce() -> (Arc<DefMap>, Expander)>,
type_ref: &TypeRef,
) {
type_ref.walk(&mut |type_ref| {
@@ -347,14 +352,27 @@ impl GenericParams {
}
if let TypeRef::Macro(mc) = type_ref {
let macro_call = mc.to_node(db.upcast());
- match expander.enter_expand::<ast::Type>(db, macro_call) {
- Ok(ExpandResult { value: Some((mark, expanded)), .. }) => {
- let ctx = expander.ctx(db);
- let type_ref = TypeRef::from_ast(&ctx, expanded.tree());
- self.fill_implicit_impl_trait_args(db, expander, &type_ref);
- expander.exit(db, mark);
- }
- _ => {}
+ let (def_map, expander) = &mut **exp;
+
+ let module = expander.module.local_id;
+ let resolver = |path| {
+ def_map
+ .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);
}
}
});
diff --git a/crates/hir-def/src/hir/type_ref.rs b/crates/hir-def/src/hir/type_ref.rs
index 0e2c0d864d..06e6be66ba 100644
--- a/crates/hir-def/src/hir/type_ref.rs
+++ b/crates/hir-def/src/hir/type_ref.rs
@@ -11,9 +11,9 @@ use intern::Interned;
use syntax::ast::{self, HasName};
use crate::{
- body::LowerCtx,
builtin_type::{BuiltinInt, BuiltinType, BuiltinUint},
hir::Literal,
+ lower::LowerCtx,
path::Path,
};
diff --git a/crates/hir-def/src/import_map.rs b/crates/hir-def/src/import_map.rs
index 07a68d1598..0480e6a51d 100644
--- a/crates/hir-def/src/import_map.rs
+++ b/crates/hir-def/src/import_map.rs
@@ -476,7 +476,7 @@ mod tests {
use base_db::{fixture::WithFixture, SourceDatabase, Upcast};
use expect_test::{expect, Expect};
- use crate::{test_db::TestDB, ItemContainerId, Lookup};
+ use crate::{db::DefDatabase, test_db::TestDB, ItemContainerId, Lookup};
use super::*;
diff --git a/crates/hir-def/src/item_tree/lower.rs b/crates/hir-def/src/item_tree/lower.rs
index c67c8bb440..457a519872 100644
--- a/crates/hir-def/src/item_tree/lower.rs
+++ b/crates/hir-def/src/item_tree/lower.rs
@@ -20,7 +20,7 @@ pub(super) struct Ctx<'a> {
db: &'a dyn DefDatabase,
tree: ItemTree,
source_ast_id_map: Arc<AstIdMap>,
- body_ctx: crate::body::LowerCtx<'a>,
+ body_ctx: crate::lower::LowerCtx<'a>,
}
impl<'a> Ctx<'a> {
@@ -29,7 +29,7 @@ impl<'a> Ctx<'a> {
db,
tree: ItemTree::default(),
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),
}
}
diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs
index 34d704942a..b7f0e229ee 100644
--- a/crates/hir-def/src/lib.rs
+++ b/crates/hir-def/src/lib.rs
@@ -22,6 +22,9 @@ pub mod builtin_type;
pub mod per_ns;
pub mod item_scope;
+pub mod lower;
+pub mod expander;
+
pub mod dyn_map;
pub mod item_tree;
@@ -65,6 +68,7 @@ use hir_expand::{
builtin_attr_macro::BuiltinAttrExpander,
builtin_derive_macro::BuiltinDeriveExpander,
builtin_fn_macro::{BuiltinFnLikeExpander, EagerExpander},
+ db::ExpandDatabase,
eager::expand_eager_macro,
hygiene::Hygiene,
proc_macro::ProcMacroExpander,
@@ -791,7 +795,7 @@ impl AttrDefId {
pub trait AsMacroCall {
fn as_call_id(
&self,
- db: &dyn db::DefDatabase,
+ db: &dyn ExpandDatabase,
krate: CrateId,
resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
) -> Option<MacroCallId> {
@@ -800,7 +804,7 @@ pub trait AsMacroCall {
fn as_call_id_with_errors(
&self,
- db: &dyn db::DefDatabase,
+ db: &dyn ExpandDatabase,
krate: CrateId,
resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
) -> Result<ExpandResult<Option<MacroCallId>>, UnresolvedMacro>;
@@ -809,15 +813,14 @@ pub trait AsMacroCall {
impl AsMacroCall for InFile<&ast::MacroCall> {
fn as_call_id_with_errors(
&self,
- db: &dyn db::DefDatabase,
+ db: &dyn ExpandDatabase,
krate: CrateId,
resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
) -> Result<ExpandResult<Option<MacroCallId>>, UnresolvedMacro> {
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 h = Hygiene::new(db.upcast(), self.file_id);
- let path =
- self.value.path().and_then(|path| path::ModPath::from_src(db.upcast(), path, &h));
+ let h = Hygiene::new(db, self.file_id);
+ let path = self.value.path().and_then(|path| path::ModPath::from_src(db, path, &h));
let Some(path) = path else {
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(
- db: &dyn db::DefDatabase,
+ db: &dyn ExpandDatabase,
call: &AstIdWithPath<ast::MacroCall>,
expand_to: ExpandTo,
krate: CrateId,
@@ -857,7 +860,7 @@ fn macro_call_as_call_id(
}
fn macro_call_as_call_id_(
- db: &dyn db::DefDatabase,
+ db: &dyn ExpandDatabase,
call: &AstIdWithPath<ast::MacroCall>,
expand_to: ExpandTo,
krate: CrateId,
@@ -867,13 +870,12 @@ fn macro_call_as_call_id_(
resolver(call.path.clone()).ok_or_else(|| UnresolvedMacro { path: call.path.clone() })?;
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()));
-
- expand_eager_macro(db.upcast(), krate, macro_call, def, &resolver)?
+ 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)?
} else {
ExpandResult {
value: Some(def.as_lazy_macro(
- db.upcast(),
+ db,
krate,
MacroCallKind::FnLike { ast_id: call.ast_id, expand_to },
)),
diff --git a/crates/hir-def/src/lower.rs b/crates/hir-def/src/lower.rs
new file mode 100644
index 0000000000..1991d547f5
--- /dev/null
+++ b/crates/hir-def/src/lower.rs
@@ -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)))
+ }
+}
diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs
index 461b498fa0..756a8f5049 100644
--- a/crates/hir-def/src/nameres/collector.rs
+++ b/crates/hir-def/src/nameres/collector.rs
@@ -1111,7 +1111,7 @@ impl DefCollector<'_> {
match &directive.kind {
MacroDirectiveKind::FnLike { ast_id, expand_to } => {
let call_id = macro_call_as_call_id(
- self.db,
+ self.db.upcast(),
ast_id,
*expand_to,
self.def_map.krate,
@@ -1402,7 +1402,7 @@ impl DefCollector<'_> {
MacroDirectiveKind::FnLike { ast_id, expand_to } => {
// 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(
- self.db,
+ self.db.upcast(),
ast_id,
*expand_to,
self.def_map.krate,
@@ -2117,7 +2117,7 @@ impl ModCollector<'_, '_> {
// Case 1: try to resolve in legacy scope and expand macro_rules
if let Ok(res) = macro_call_as_call_id(
- self.def_collector.db,
+ self.def_collector.db.upcast(),
&ast_id,
mac.expand_to,
self.def_collector.def_map.krate,
diff --git a/crates/hir-def/src/nameres/tests/incremental.rs b/crates/hir-def/src/nameres/tests/incremental.rs
index d2e3575d5e..34fa15f9e1 100644
--- a/crates/hir-def/src/nameres/tests/incremental.rs
+++ b/crates/hir-def/src/nameres/tests/incremental.rs
@@ -2,7 +2,7 @@ use std::sync::Arc;
use base_db::SourceDatabaseExt;
-use crate::{AdtId, ModuleDefId};
+use crate::{db::DefDatabase, AdtId, ModuleDefId};
use super::*;
diff --git a/crates/hir-def/src/path.rs b/crates/hir-def/src/path.rs
index 8cd287f7f3..b9b8082549 100644
--- a/crates/hir-def/src/path.rs
+++ b/crates/hir-def/src/path.rs
@@ -7,8 +7,8 @@ use std::{
};
use crate::{
- body::LowerCtx,
lang_item::LangItemTarget,
+ lower::LowerCtx,
type_ref::{ConstRefOrPath, LifetimeRef, TypeBound, TypeRef},
};
use hir_expand::name::Name;
diff --git a/crates/hir-def/src/path/lower.rs b/crates/hir-def/src/path/lower.rs
index c35f915b00..721f9b7680 100644
--- a/crates/hir-def/src/path/lower.rs
+++ b/crates/hir-def/src/path/lower.rs
@@ -2,17 +2,15 @@
use std::iter;
-use crate::type_ref::ConstRefOrPath;
+use crate::{lower::LowerCtx, type_ref::ConstRefOrPath};
use either::Either;
use hir_expand::name::{name, AsName};
use intern::Interned;
use syntax::ast::{self, AstNode, HasTypeBounds};
-use super::AssociatedTypeBinding;
use crate::{
- body::LowerCtx,
- path::{GenericArg, GenericArgs, ModPath, Path, PathKind},
+ path::{AssociatedTypeBinding, GenericArg, GenericArgs, ModPath, Path, PathKind},
type_ref::{LifetimeRef, TypeBound, TypeRef},
};
diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs
index 0eef25102e..d445abae92 100644
--- a/crates/hir-ty/src/display.rs
+++ b/crates/hir-ty/src/display.rs
@@ -7,7 +7,6 @@ use std::fmt::{self, Debug};
use base_db::CrateId;
use chalk_ir::{BoundVar, TyKind};
use hir_def::{
- body,
data::adt::VariantData,
db::DefDatabase,
find_path,
@@ -1552,7 +1551,10 @@ impl HirDisplay for TypeRef {
}
TypeRef::Macro(macro_call) => {
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() {
Some(path) => match Path::from_src(path, &ctx) {
Some(path) => path.hir_fmt(f)?,
diff --git a/crates/hir-ty/src/interner.rs b/crates/hir-ty/src/interner.rs
index 874f808cda..19bb7f169f 100644
--- a/crates/hir-ty/src/interner.rs
+++ b/crates/hir-ty/src/interner.rs
@@ -43,7 +43,7 @@ impl_internable!(
);
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 InternedConst = Interned<InternedWrapper<chalk_ir::ConstData<Self>>>;
type InternedConcreteConst = ConstScalar;
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index 33dc5e2d69..7da747b949 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -18,9 +18,9 @@ use chalk_ir::{
use either::Either;
use hir_def::{
- body::Expander,
builtin_type::BuiltinType,
data::adt::StructKind,
+ expander::Expander,
generics::{
TypeOrConstParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget,
},
@@ -378,7 +378,9 @@ impl<'a> TyLoweringContext<'a> {
};
let ty = {
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)), .. }) => {
let ctx = expander.ctx(self.db.upcast());
// FIXME: Report syntax errors in expansion here
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index b32efe1cb5..a9f7813150 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -7,8 +7,8 @@ use std::{cell::RefCell, fmt, iter, mem, ops};
use base_db::{FileId, FileRange};
use either::Either;
use hir_def::{
- body,
hir::Expr,
+ lower::LowerCtx,
macro_id_to_def_id,
resolver::{self, HasResolver, Resolver, TypeNs},
type_ref::Mutability,
@@ -1065,7 +1065,7 @@ impl<'db> SemanticsImpl<'db> {
fn resolve_type(&self, ty: &ast::Type) -> Option<Type> {
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)
.lower_ty(&crate::TypeRef::from_ast(&ctx, ty.clone()));
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> {
let analyze = self.analyze(path.syntax())?;
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)?;
match analyze.resolver.resolve_path_in_type_ns_fully(self.db.upcast(), &hir_path)? {
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
/// necessary a heuristic, as it doesn't take hygiene into account.
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)?;
resolve_hir_path(self.db, &self.resolver, &path)
}
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index d0bf1c23ac..a6a51e4907 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -13,12 +13,12 @@ use std::{
use either::Either;
use hir_def::{
body::{
- self,
scope::{ExprScopes, ScopeId},
Body, BodySourceMap,
},
hir::{ExprId, Pat, PatId},
lang_item::LangItem,
+ lower::LowerCtx,
macro_id_to_def_id,
path::{ModPath, Path, PathKind},
resolver::{resolver_for_scope, Resolver, TypeNs, ValueNs},
@@ -463,7 +463,7 @@ impl SourceAnalyzer {
db: &dyn HirDatabase,
macro_call: InFile<&ast::MacroCall>,
) -> 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))?;
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.
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)?;
// Case where path is a qualifier of a use tree, e.g. foo::bar::{Baz, Qux} where we are
diff --git a/crates/ide-db/src/line_index.rs b/crates/ide-db/src/line_index.rs
index 16814a1e63..9fb58ebe8a 100644
--- a/crates/ide-db/src/line_index.rs
+++ b/crates/ide-db/src/line_index.rs
@@ -109,6 +109,9 @@ impl LineIndex {
line_wide_chars.insert(line, wide_chars);
}
+ newlines.shrink_to_fit();
+ line_wide_chars.shrink_to_fit();
+
LineIndex { newlines, line_wide_chars }
}
diff --git a/crates/ide-db/src/symbol_index.rs b/crates/ide-db/src/symbol_index.rs
index a91ffd1ec4..dcdcd17dc6 100644
--- a/crates/ide-db/src/symbol_index.rs
+++ b/crates/ide-db/src/symbol_index.rs
@@ -93,6 +93,7 @@ impl Query {
pub trait SymbolsDatabase: HirDatabase + SourceDatabaseExt + Upcast<dyn HirDatabase> {
/// The symbol index for a given module. These modules should only be in source roots that
/// are inside local_roots.
+ // FIXME: We should probably LRU this
fn module_symbols(&self, module: Module) -> Arc<SymbolIndex>;
/// The symbol index for a given source root within library_roots.
diff --git a/crates/limit/src/lib.rs b/crates/limit/src/lib.rs
index 6b2534aa46..7fb4b513a7 100644
--- a/crates/limit/src/lib.rs
+++ b/crates/limit/src/lib.rs
@@ -6,6 +6,7 @@
use std::sync::atomic::AtomicUsize;
/// Represents a struct used to enforce a numerical limit.
+#[derive(Debug)]
pub struct Limit {
upper_bound: usize,
#[cfg(feature = "tracking")]