Skip to content

Commit 6ed2fd2

Browse files
committed
hir_ty: keep body::Expander in TyLoweringContext
1 parent 3d39e77 commit 6ed2fd2

File tree

4 files changed

+94
-59
lines changed

4 files changed

+94
-59
lines changed

crates/hir_def/src/body.rs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,15 @@ use crate::{
3737

3838
/// A subset of Expander that only deals with cfg attributes. We only need it to
3939
/// avoid cyclic queries in crate def map during enum processing.
40+
#[derive(Debug)]
4041
pub(crate) struct CfgExpander {
4142
cfg_options: CfgOptions,
4243
hygiene: Hygiene,
4344
krate: CrateId,
4445
}
4546

46-
pub(crate) struct Expander {
47+
#[derive(Debug)]
48+
pub struct Expander {
4749
cfg_expander: CfgExpander,
4850
def_map: Arc<DefMap>,
4951
current_file_id: HirFileId,
@@ -80,11 +82,7 @@ impl CfgExpander {
8082
}
8183

8284
impl Expander {
83-
pub(crate) fn new(
84-
db: &dyn DefDatabase,
85-
current_file_id: HirFileId,
86-
module: ModuleId,
87-
) -> Expander {
85+
pub fn new(db: &dyn DefDatabase, current_file_id: HirFileId, module: ModuleId) -> Expander {
8886
let cfg_expander = CfgExpander::new(db, current_file_id, module.krate);
8987
let def_map = module.def_map(db);
9088
let ast_id_map = db.ast_id_map(current_file_id);
@@ -98,7 +96,7 @@ impl Expander {
9896
}
9997
}
10098

101-
pub(crate) fn enter_expand<T: ast::AstNode>(
99+
pub fn enter_expand<T: ast::AstNode>(
102100
&mut self,
103101
db: &dyn DefDatabase,
104102
macro_call: ast::MacroCall,
@@ -170,7 +168,7 @@ impl Expander {
170168
Ok(ExpandResult { value: Some((mark, node)), err })
171169
}
172170

173-
pub(crate) fn exit(&mut self, db: &dyn DefDatabase, mut mark: Mark) {
171+
pub fn exit(&mut self, db: &dyn DefDatabase, mut mark: Mark) {
174172
self.cfg_expander.hygiene = Hygiene::new(db.upcast(), mark.file_id);
175173
self.current_file_id = mark.file_id;
176174
self.ast_id_map = mem::take(&mut mark.ast_id_map);
@@ -190,7 +188,7 @@ impl Expander {
190188
&self.cfg_expander.cfg_options
191189
}
192190

193-
pub(crate) fn current_file_id(&self) -> HirFileId {
191+
pub fn current_file_id(&self) -> HirFileId {
194192
self.current_file_id
195193
}
196194

@@ -210,7 +208,7 @@ impl Expander {
210208
}
211209

212210
#[derive(Debug)]
213-
pub(crate) struct Mark {
211+
pub struct Mark {
214212
file_id: HirFileId,
215213
ast_id_map: Arc<AstIdMap>,
216214
bomb: DropBomb,

crates/hir_def/src/type_ref.rs

Lines changed: 3 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,10 @@
11
//! HIR for references to types. Paths in these are not yet resolved. They can
22
//! be directly created from an ast::TypeRef, without further queries.
33
4-
use hir_expand::{name::Name, AstId, ExpandResult, InFile};
4+
use hir_expand::{name::Name, AstId, InFile};
55
use syntax::ast;
66

7-
use crate::{
8-
body::{Expander, LowerCtx},
9-
db::DefDatabase,
10-
path::Path,
11-
ModuleId,
12-
};
7+
use crate::{body::LowerCtx, path::Path};
138

149
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
1510
pub enum Mutability {
@@ -124,7 +119,7 @@ pub enum TypeBound {
124119

125120
impl TypeRef {
126121
/// Converts an `ast::TypeRef` to a `hir::TypeRef`.
127-
pub(crate) fn from_ast(ctx: &LowerCtx, node: ast::Type) -> Self {
122+
pub fn from_ast(ctx: &LowerCtx, node: ast::Type) -> Self {
128123
match node {
129124
ast::Type::ParenType(inner) => TypeRef::from_ast_opt(&ctx, inner.ty()),
130125
ast::Type::TupleType(inner) => {
@@ -303,30 +298,3 @@ impl TypeBound {
303298
}
304299
}
305300
}
306-
307-
pub fn expand_macro_type(
308-
db: &dyn DefDatabase,
309-
module_id: ModuleId,
310-
macro_type: &TypeRef,
311-
) -> Option<TypeRef> {
312-
let macro_call = match macro_type {
313-
TypeRef::Macro(macro_call) => macro_call,
314-
_ => panic!("expected TypeRef::Macro"),
315-
};
316-
317-
let file_id = macro_call.file_id;
318-
let macro_call = macro_call.to_node(db.upcast());
319-
320-
let mut expander = Expander::new(db, file_id, module_id);
321-
let (file_id, expanded) = match expander.enter_expand::<ast::Type>(db, macro_call.clone()) {
322-
Ok(ExpandResult { value: Some((mark, expanded)), .. }) => {
323-
let file_id = expander.current_file_id();
324-
expander.exit(db, mark);
325-
(file_id, expanded)
326-
}
327-
_ => return None,
328-
};
329-
330-
let ctx = LowerCtx::new(db, file_id);
331-
return Some(TypeRef::from_ast(&ctx, expanded));
332-
}

crates/hir_ty/src/lower.rs

Lines changed: 57 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,28 @@
55
//! - Building the type for an item: This happens through the `type_for_def` query.
66
//!
77
//! This usually involves resolving names, collecting generic arguments etc.
8+
use std::cell::{Cell, RefCell};
89
use std::{iter, sync::Arc};
910

1011
use base_db::CrateId;
1112
use chalk_ir::{cast::Cast, fold::Shift, interner::HasInterner, Mutability, Safety};
1213
use hir_def::{
1314
adt::StructKind,
15+
body::{Expander, LowerCtx},
1416
builtin_type::BuiltinType,
1517
generics::{TypeParamProvenance, WherePredicate, WherePredicateTypeTarget},
1618
path::{GenericArg, Path, PathSegment, PathSegments},
1719
resolver::{HasResolver, Resolver, TypeNs},
18-
type_ref::{expand_macro_type, TraitRef as HirTraitRef, TypeBound, TypeRef},
20+
type_ref::{TraitRef as HirTraitRef, TypeBound, TypeRef},
1921
AdtId, AssocContainerId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId,
2022
GenericDefId, HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId,
2123
TypeAliasId, TypeParamId, UnionId, VariantId,
2224
};
23-
use hir_expand::name::Name;
25+
use hir_expand::{name::Name, ExpandResult};
2426
use la_arena::ArenaMap;
2527
use smallvec::SmallVec;
2628
use stdx::impl_from;
29+
use syntax::ast;
2730

2831
use crate::{
2932
db::HirDatabase,
@@ -50,7 +53,7 @@ pub struct TyLoweringContext<'a> {
5053
/// possible currently, so this should be fine for now.
5154
pub type_param_mode: TypeParamLoweringMode,
5255
pub impl_trait_mode: ImplTraitLoweringMode,
53-
impl_trait_counter: std::cell::Cell<u16>,
56+
impl_trait_counter: Cell<u16>,
5457
/// When turning `impl Trait` into opaque types, we have to collect the
5558
/// bounds at the same time to get the IDs correct (without becoming too
5659
/// complicated). I don't like using interior mutability (as for the
@@ -59,16 +62,17 @@ pub struct TyLoweringContext<'a> {
5962
/// we're grouping the mutable data (the counter and this field) together
6063
/// with the immutable context (the references to the DB and resolver).
6164
/// Splitting this up would be a possible fix.
62-
opaque_type_data: std::cell::RefCell<Vec<ReturnTypeImplTrait>>,
65+
opaque_type_data: RefCell<Vec<ReturnTypeImplTrait>>,
66+
expander: RefCell<Option<Expander>>,
6367
}
6468

6569
impl<'a> TyLoweringContext<'a> {
6670
pub fn new(db: &'a dyn HirDatabase, resolver: &'a Resolver) -> Self {
67-
let impl_trait_counter = std::cell::Cell::new(0);
71+
let impl_trait_counter = Cell::new(0);
6872
let impl_trait_mode = ImplTraitLoweringMode::Disallowed;
6973
let type_param_mode = TypeParamLoweringMode::Placeholder;
7074
let in_binders = DebruijnIndex::INNERMOST;
71-
let opaque_type_data = std::cell::RefCell::new(Vec::new());
75+
let opaque_type_data = RefCell::new(Vec::new());
7276
Self {
7377
db,
7478
resolver,
@@ -77,6 +81,7 @@ impl<'a> TyLoweringContext<'a> {
7781
impl_trait_counter,
7882
type_param_mode,
7983
opaque_type_data,
84+
expander: RefCell::new(None),
8085
}
8186
}
8287

@@ -86,15 +91,18 @@ impl<'a> TyLoweringContext<'a> {
8691
f: impl FnOnce(&TyLoweringContext) -> T,
8792
) -> T {
8893
let opaque_ty_data_vec = self.opaque_type_data.replace(Vec::new());
94+
let expander = self.expander.replace(None);
8995
let new_ctx = Self {
9096
in_binders: debruijn,
91-
impl_trait_counter: std::cell::Cell::new(self.impl_trait_counter.get()),
92-
opaque_type_data: std::cell::RefCell::new(opaque_ty_data_vec),
97+
impl_trait_counter: Cell::new(self.impl_trait_counter.get()),
98+
opaque_type_data: RefCell::new(opaque_ty_data_vec),
99+
expander: RefCell::new(expander),
93100
..*self
94101
};
95102
let result = f(&new_ctx);
96103
self.impl_trait_counter.set(new_ctx.impl_trait_counter.get());
97104
self.opaque_type_data.replace(new_ctx.opaque_type_data.into_inner());
105+
self.expander.replace(new_ctx.expander.into_inner());
98106
result
99107
}
100108

@@ -287,15 +295,50 @@ impl<'a> TyLoweringContext<'a> {
287295
}
288296
}
289297
}
290-
mt @ TypeRef::Macro(_) => {
291-
if let Some(module_id) = self.resolver.module() {
292-
match expand_macro_type(self.db.upcast(), module_id, mt) {
293-
Some(type_ref) => self.lower_ty(&type_ref),
294-
None => TyKind::Error.intern(&Interner),
298+
TypeRef::Macro(macro_call) => {
299+
let (expander, recursion_start) = match self.expander.borrow_mut() {
300+
expander if expander.is_some() => (Some(expander), false),
301+
mut expander => {
302+
if let Some(module_id) = self.resolver.module() {
303+
*expander = Some(Expander::new(
304+
self.db.upcast(),
305+
macro_call.file_id,
306+
module_id,
307+
));
308+
(Some(expander), true)
309+
} else {
310+
(None, false)
311+
}
312+
}
313+
};
314+
let ty = if let Some(mut expander) = expander {
315+
let expander_mut = expander.as_mut().unwrap();
316+
let macro_call = macro_call.to_node(self.db.upcast());
317+
match expander_mut.enter_expand::<ast::Type>(self.db.upcast(), macro_call) {
318+
Ok(ExpandResult { value: Some((mark, expanded)), .. }) => {
319+
let ctx =
320+
LowerCtx::new(self.db.upcast(), expander_mut.current_file_id());
321+
let type_ref = TypeRef::from_ast(&ctx, expanded);
322+
323+
drop(expander);
324+
let ty = self.lower_ty(&type_ref);
325+
326+
self.expander
327+
.borrow_mut()
328+
.as_mut()
329+
.unwrap()
330+
.exit(self.db.upcast(), mark);
331+
Some(ty)
332+
}
333+
_ => None,
295334
}
296335
} else {
297-
TyKind::Error.intern(&Interner)
336+
None
337+
};
338+
if recursion_start {
339+
*self.expander.borrow_mut() = None;
298340
}
341+
ty.unwrap_or_else(|| TyKind::Error.intern(&Interner))
299342
}
300343
TypeRef::Error => TyKind::Error.intern(&Interner),
301344
};

crates/hir_ty/src/tests/macros.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1243,3 +1243,29 @@ fn macros_in_type_generics() {
12431243
"#]],
12441244
);
12451245
}
1246+
1247+
#[test]
1248+
fn infinitely_recursive_macro_type() {
1249+
check_infer(
1250+
r#"
1251+
struct Bar<T>(T);
1252+
1253+
macro_rules! Foo {
1254+
() => { Foo!() }
1255+
}
1256+
1257+
type A = Foo!();
1258+
type B = Bar<Foo!()>;
1259+
1260+
fn main() {
1261+
let a: A;
1262+
let b: B;
1263+
}
1264+
"#,
1265+
expect![[r#"
1266+
112..143 '{ ...: B; }': ()
1267+
122..123 'a': {unknown}
1268+
136..137 'b': Bar<{unknown}>
1269+
"#]],
1270+
);
1271+
}

0 commit comments

Comments
 (0)