Move Expander and LowerCtx into separate modules

This commit is contained in:
Lukas Wirth 2023-04-17 17:31:39 +02:00
parent fd4bbcabe8
commit bca8029a6e
25 changed files with 487 additions and 402 deletions

View file

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

View file

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

View file

@ -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,
);

View file

@ -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()
}

View file

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

View file

@ -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());

View 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, &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,
}

View file

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

View file

@ -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,
};

View file

@ -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::*;

View file

@ -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),
}
}

View file

@ -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 },
)),

View 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)))
}
}

View file

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

View file

@ -2,7 +2,7 @@ use std::sync::Arc;
use base_db::SourceDatabaseExt;
use crate::{AdtId, ModuleDefId};
use crate::{db::DefDatabase, AdtId, ModuleDefId};
use super::*;

View file

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

View file

@ -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},
};

View file

@ -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)?,

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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")]