aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/hir_def/src/body.rs18
-rw-r--r--crates/hir_def/src/type_ref.rs38
-rw-r--r--crates/hir_ty/src/lower.rs71
-rw-r--r--crates/hir_ty/src/tests/macros.rs26
4 files changed, 94 insertions, 59 deletions
diff --git a/crates/hir_def/src/body.rs b/crates/hir_def/src/body.rs
index 8a9b936ea..131f424cc 100644
--- a/crates/hir_def/src/body.rs
+++ b/crates/hir_def/src/body.rs
@@ -37,13 +37,15 @@ use crate::{
37 37
38/// A subset of Expander that only deals with cfg attributes. We only need it to 38/// A subset of Expander that only deals with cfg attributes. We only need it to
39/// avoid cyclic queries in crate def map during enum processing. 39/// avoid cyclic queries in crate def map during enum processing.
40#[derive(Debug)]
40pub(crate) struct CfgExpander { 41pub(crate) struct CfgExpander {
41 cfg_options: CfgOptions, 42 cfg_options: CfgOptions,
42 hygiene: Hygiene, 43 hygiene: Hygiene,
43 krate: CrateId, 44 krate: CrateId,
44} 45}
45 46
46pub(crate) struct Expander { 47#[derive(Debug)]
48pub struct Expander {
47 cfg_expander: CfgExpander, 49 cfg_expander: CfgExpander,
48 def_map: Arc<DefMap>, 50 def_map: Arc<DefMap>,
49 current_file_id: HirFileId, 51 current_file_id: HirFileId,
@@ -80,11 +82,7 @@ impl CfgExpander {
80} 82}
81 83
82impl Expander { 84impl Expander {
83 pub(crate) fn new( 85 pub fn new(db: &dyn DefDatabase, current_file_id: HirFileId, module: ModuleId) -> Expander {
84 db: &dyn DefDatabase,
85 current_file_id: HirFileId,
86 module: ModuleId,
87 ) -> Expander {
88 let cfg_expander = CfgExpander::new(db, current_file_id, module.krate); 86 let cfg_expander = CfgExpander::new(db, current_file_id, module.krate);
89 let def_map = module.def_map(db); 87 let def_map = module.def_map(db);
90 let ast_id_map = db.ast_id_map(current_file_id); 88 let ast_id_map = db.ast_id_map(current_file_id);
@@ -98,7 +96,7 @@ impl Expander {
98 } 96 }
99 } 97 }
100 98
101 pub(crate) fn enter_expand<T: ast::AstNode>( 99 pub fn enter_expand<T: ast::AstNode>(
102 &mut self, 100 &mut self,
103 db: &dyn DefDatabase, 101 db: &dyn DefDatabase,
104 macro_call: ast::MacroCall, 102 macro_call: ast::MacroCall,
@@ -170,7 +168,7 @@ impl Expander {
170 Ok(ExpandResult { value: Some((mark, node)), err }) 168 Ok(ExpandResult { value: Some((mark, node)), err })
171 } 169 }
172 170
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) {
174 self.cfg_expander.hygiene = Hygiene::new(db.upcast(), mark.file_id); 172 self.cfg_expander.hygiene = Hygiene::new(db.upcast(), mark.file_id);
175 self.current_file_id = mark.file_id; 173 self.current_file_id = mark.file_id;
176 self.ast_id_map = mem::take(&mut mark.ast_id_map); 174 self.ast_id_map = mem::take(&mut mark.ast_id_map);
@@ -190,7 +188,7 @@ impl Expander {
190 &self.cfg_expander.cfg_options 188 &self.cfg_expander.cfg_options
191 } 189 }
192 190
193 pub(crate) fn current_file_id(&self) -> HirFileId { 191 pub fn current_file_id(&self) -> HirFileId {
194 self.current_file_id 192 self.current_file_id
195 } 193 }
196 194
@@ -210,7 +208,7 @@ impl Expander {
210} 208}
211 209
212#[derive(Debug)] 210#[derive(Debug)]
213pub(crate) struct Mark { 211pub struct Mark {
214 file_id: HirFileId, 212 file_id: HirFileId,
215 ast_id_map: Arc<AstIdMap>, 213 ast_id_map: Arc<AstIdMap>,
216 bomb: DropBomb, 214 bomb: DropBomb,
diff --git a/crates/hir_def/src/type_ref.rs b/crates/hir_def/src/type_ref.rs
index e18712d24..ea29da5da 100644
--- a/crates/hir_def/src/type_ref.rs
+++ b/crates/hir_def/src/type_ref.rs
@@ -1,15 +1,10 @@
1//! HIR for references to types. Paths in these are not yet resolved. They can 1//! HIR for references to types. Paths in these are not yet resolved. They can
2//! be directly created from an ast::TypeRef, without further queries. 2//! be directly created from an ast::TypeRef, without further queries.
3 3
4use hir_expand::{name::Name, AstId, ExpandResult, InFile}; 4use hir_expand::{name::Name, AstId, InFile};
5use syntax::ast; 5use syntax::ast;
6 6
7use crate::{ 7use crate::{body::LowerCtx, path::Path};
8 body::{Expander, LowerCtx},
9 db::DefDatabase,
10 path::Path,
11 ModuleId,
12};
13 8
14#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] 9#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
15pub enum Mutability { 10pub enum Mutability {
@@ -124,7 +119,7 @@ pub enum TypeBound {
124 119
125impl TypeRef { 120impl TypeRef {
126 /// Converts an `ast::TypeRef` to a `hir::TypeRef`. 121 /// 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 {
128 match node { 123 match node {
129 ast::Type::ParenType(inner) => TypeRef::from_ast_opt(&ctx, inner.ty()), 124 ast::Type::ParenType(inner) => TypeRef::from_ast_opt(&ctx, inner.ty()),
130 ast::Type::TupleType(inner) => { 125 ast::Type::TupleType(inner) => {
@@ -303,30 +298,3 @@ impl TypeBound {
303 } 298 }
304 } 299 }
305} 300}
306
307pub 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}
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index e01b7aa91..a883334af 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -5,25 +5,28 @@
5//! - Building the type for an item: This happens through the `type_for_def` query. 5//! - Building the type for an item: This happens through the `type_for_def` query.
6//! 6//!
7//! This usually involves resolving names, collecting generic arguments etc. 7//! This usually involves resolving names, collecting generic arguments etc.
8use std::cell::{Cell, RefCell};
8use std::{iter, sync::Arc}; 9use std::{iter, sync::Arc};
9 10
10use base_db::CrateId; 11use base_db::CrateId;
11use chalk_ir::{cast::Cast, fold::Shift, interner::HasInterner, Mutability, Safety}; 12use chalk_ir::{cast::Cast, fold::Shift, interner::HasInterner, Mutability, Safety};
12use hir_def::{ 13use hir_def::{
13 adt::StructKind, 14 adt::StructKind,
15 body::{Expander, LowerCtx},
14 builtin_type::BuiltinType, 16 builtin_type::BuiltinType,
15 generics::{TypeParamProvenance, WherePredicate, WherePredicateTypeTarget}, 17 generics::{TypeParamProvenance, WherePredicate, WherePredicateTypeTarget},
16 path::{GenericArg, Path, PathSegment, PathSegments}, 18 path::{GenericArg, Path, PathSegment, PathSegments},
17 resolver::{HasResolver, Resolver, TypeNs}, 19 resolver::{HasResolver, Resolver, TypeNs},
18 type_ref::{expand_macro_type, TraitRef as HirTraitRef, TypeBound, TypeRef}, 20 type_ref::{TraitRef as HirTraitRef, TypeBound, TypeRef},
19 AdtId, AssocContainerId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId, 21 AdtId, AssocContainerId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId,
20 GenericDefId, HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId, 22 GenericDefId, HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId,
21 TypeAliasId, TypeParamId, UnionId, VariantId, 23 TypeAliasId, TypeParamId, UnionId, VariantId,
22}; 24};
23use hir_expand::name::Name; 25use hir_expand::{name::Name, ExpandResult};
24use la_arena::ArenaMap; 26use la_arena::ArenaMap;
25use smallvec::SmallVec; 27use smallvec::SmallVec;
26use stdx::impl_from; 28use stdx::impl_from;
29use syntax::ast;
27 30
28use crate::{ 31use crate::{
29 db::HirDatabase, 32 db::HirDatabase,
@@ -50,7 +53,7 @@ pub struct TyLoweringContext<'a> {
50 /// possible currently, so this should be fine for now. 53 /// possible currently, so this should be fine for now.
51 pub type_param_mode: TypeParamLoweringMode, 54 pub type_param_mode: TypeParamLoweringMode,
52 pub impl_trait_mode: ImplTraitLoweringMode, 55 pub impl_trait_mode: ImplTraitLoweringMode,
53 impl_trait_counter: std::cell::Cell<u16>, 56 impl_trait_counter: Cell<u16>,
54 /// When turning `impl Trait` into opaque types, we have to collect the 57 /// When turning `impl Trait` into opaque types, we have to collect the
55 /// bounds at the same time to get the IDs correct (without becoming too 58 /// bounds at the same time to get the IDs correct (without becoming too
56 /// complicated). I don't like using interior mutability (as for the 59 /// complicated). I don't like using interior mutability (as for the
@@ -59,16 +62,17 @@ pub struct TyLoweringContext<'a> {
59 /// we're grouping the mutable data (the counter and this field) together 62 /// we're grouping the mutable data (the counter and this field) together
60 /// with the immutable context (the references to the DB and resolver). 63 /// with the immutable context (the references to the DB and resolver).
61 /// Splitting this up would be a possible fix. 64 /// 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>>,
63} 67}
64 68
65impl<'a> TyLoweringContext<'a> { 69impl<'a> TyLoweringContext<'a> {
66 pub fn new(db: &'a dyn HirDatabase, resolver: &'a Resolver) -> Self { 70 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);
68 let impl_trait_mode = ImplTraitLoweringMode::Disallowed; 72 let impl_trait_mode = ImplTraitLoweringMode::Disallowed;
69 let type_param_mode = TypeParamLoweringMode::Placeholder; 73 let type_param_mode = TypeParamLoweringMode::Placeholder;
70 let in_binders = DebruijnIndex::INNERMOST; 74 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());
72 Self { 76 Self {
73 db, 77 db,
74 resolver, 78 resolver,
@@ -77,6 +81,7 @@ impl<'a> TyLoweringContext<'a> {
77 impl_trait_counter, 81 impl_trait_counter,
78 type_param_mode, 82 type_param_mode,
79 opaque_type_data, 83 opaque_type_data,
84 expander: RefCell::new(None),
80 } 85 }
81 } 86 }
82 87
@@ -86,15 +91,18 @@ impl<'a> TyLoweringContext<'a> {
86 f: impl FnOnce(&TyLoweringContext) -> T, 91 f: impl FnOnce(&TyLoweringContext) -> T,
87 ) -> T { 92 ) -> T {
88 let opaque_ty_data_vec = self.opaque_type_data.replace(Vec::new()); 93 let opaque_ty_data_vec = self.opaque_type_data.replace(Vec::new());
94 let expander = self.expander.replace(None);
89 let new_ctx = Self { 95 let new_ctx = Self {
90 in_binders: debruijn, 96 in_binders: debruijn,
91 impl_trait_counter: std::cell::Cell::new(self.impl_trait_counter.get()), 97 impl_trait_counter: Cell::new(self.impl_trait_counter.get()),
92 opaque_type_data: std::cell::RefCell::new(opaque_ty_data_vec), 98 opaque_type_data: RefCell::new(opaque_ty_data_vec),
99 expander: RefCell::new(expander),
93 ..*self 100 ..*self
94 }; 101 };
95 let result = f(&new_ctx); 102 let result = f(&new_ctx);
96 self.impl_trait_counter.set(new_ctx.impl_trait_counter.get()); 103 self.impl_trait_counter.set(new_ctx.impl_trait_counter.get());
97 self.opaque_type_data.replace(new_ctx.opaque_type_data.into_inner()); 104 self.opaque_type_data.replace(new_ctx.opaque_type_data.into_inner());
105 self.expander.replace(new_ctx.expander.into_inner());
98 result 106 result
99 } 107 }
100 108
@@ -287,15 +295,50 @@ impl<'a> TyLoweringContext<'a> {
287 } 295 }
288 } 296 }
289 } 297 }
290 mt @ TypeRef::Macro(_) => { 298 TypeRef::Macro(macro_call) => {
291 if let Some(module_id) = self.resolver.module() { 299 let (expander, recursion_start) = match self.expander.borrow_mut() {
292 match expand_macro_type(self.db.upcast(), module_id, mt) { 300 expander if expander.is_some() => (Some(expander), false),
293 Some(type_ref) => self.lower_ty(&type_ref), 301 mut expander => {
294 None => TyKind::Error.intern(&Interner), 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,
295 } 334 }
296 } else { 335 } else {
297 TyKind::Error.intern(&Interner) 336 None
337 };
338 if recursion_start {
339 *self.expander.borrow_mut() = None;
298 } 340 }
341 ty.unwrap_or_else(|| TyKind::Error.intern(&Interner))
299 } 342 }
300 TypeRef::Error => TyKind::Error.intern(&Interner), 343 TypeRef::Error => TyKind::Error.intern(&Interner),
301 }; 344 };
diff --git a/crates/hir_ty/src/tests/macros.rs b/crates/hir_ty/src/tests/macros.rs
index cbe05a5c1..8de1e229f 100644
--- a/crates/hir_ty/src/tests/macros.rs
+++ b/crates/hir_ty/src/tests/macros.rs
@@ -1243,3 +1243,29 @@ fn macros_in_type_generics() {
1243 "#]], 1243 "#]],
1244 ); 1244 );
1245} 1245}
1246
1247#[test]
1248fn 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}