aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def
diff options
context:
space:
mode:
authorcynecx <[email protected]>2021-04-10 16:49:12 +0100
committercynecx <[email protected]>2021-04-17 15:24:56 +0100
commitcf3b4f1e208247c9d171273dabff9c6b3c98a240 (patch)
tree0cae2703b98ba8640ce6693abe32fb51fe27fdda /crates/hir_def
parentfb2d284f28f70426e39e1b92d95bdbb217a48109 (diff)
hir_ty: Expand macros at type position
Diffstat (limited to 'crates/hir_def')
-rw-r--r--crates/hir_def/src/body.rs74
-rw-r--r--crates/hir_def/src/body/lower.rs34
-rw-r--r--crates/hir_def/src/data.rs8
-rw-r--r--crates/hir_def/src/item_tree/lower.rs16
-rw-r--r--crates/hir_def/src/lib.rs1
-rw-r--r--crates/hir_def/src/path.rs7
-rw-r--r--crates/hir_def/src/path/lower.rs17
-rw-r--r--crates/hir_def/src/type_ref.rs102
8 files changed, 210 insertions, 49 deletions
diff --git a/crates/hir_def/src/body.rs b/crates/hir_def/src/body.rs
index 96b959967..44ae13643 100644
--- a/crates/hir_def/src/body.rs
+++ b/crates/hir_def/src/body.rs
@@ -19,9 +19,9 @@ use hir_expand::{
19use la_arena::{Arena, ArenaMap}; 19use la_arena::{Arena, ArenaMap};
20use profile::Count; 20use profile::Count;
21use rustc_hash::FxHashMap; 21use rustc_hash::FxHashMap;
22use syntax::{ast, AstNode, AstPtr}; 22use syntax::{ast, AstNode, AstPtr, SyntaxNode};
23 23
24pub(crate) use lower::LowerCtx; 24pub use lower::LowerCtx;
25 25
26use crate::{ 26use crate::{
27 attr::{Attrs, RawAttrs}, 27 attr::{Attrs, RawAttrs},
@@ -98,11 +98,14 @@ impl Expander {
98 } 98 }
99 } 99 }
100 100
101 pub(crate) fn enter_expand<T: ast::AstNode>( 101 fn enter_expand_intern(
102 &mut self, 102 &mut self,
103 db: &dyn DefDatabase, 103 db: &dyn DefDatabase,
104 macro_call: ast::MacroCall, 104 macro_call: ast::MacroCall,
105 ) -> Result<ExpandResult<Option<(Mark, T)>>, UnresolvedMacro> { 105 ) -> Result<
106 ExpandResult<Option<(SyntaxNode, impl FnMut(&dyn DefDatabase) -> Mark + '_)>>,
107 UnresolvedMacro,
108 > {
106 if self.recursion_limit + 1 > EXPANSION_RECURSION_LIMIT { 109 if self.recursion_limit + 1 > EXPANSION_RECURSION_LIMIT {
107 cov_mark::hit!(your_stack_belongs_to_me); 110 cov_mark::hit!(your_stack_belongs_to_me);
108 return Ok(ExpandResult::str_err( 111 return Ok(ExpandResult::str_err(
@@ -147,6 +150,55 @@ impl Expander {
147 } 150 }
148 }; 151 };
149 152
153 let this = self;
154
155 let advance_state = move |db: &dyn DefDatabase| {
156 this.recursion_limit += 1;
157 let mark = Mark {
158 file_id: this.current_file_id,
159 ast_id_map: mem::take(&mut this.ast_id_map),
160 bomb: DropBomb::new("expansion mark dropped"),
161 };
162 this.cfg_expander.hygiene = Hygiene::new(db.upcast(), file_id);
163 this.current_file_id = file_id;
164 this.ast_id_map = db.ast_id_map(file_id);
165 mark
166 };
167
168 Ok(ExpandResult { value: Some((raw_node, advance_state)), err })
169 }
170
171 pub(crate) fn enter_expand_raw(
172 &mut self,
173 db: &dyn DefDatabase,
174 macro_call: ast::MacroCall,
175 ) -> Result<ExpandResult<Option<(Mark, SyntaxNode)>>, UnresolvedMacro> {
176 let (raw_node, mut advance_state, err) = match self.enter_expand_intern(db, macro_call)? {
177 ExpandResult { value: Some((raw_node, advance_state)), err } => {
178 (raw_node, advance_state, err)
179 }
180 ExpandResult { value: None, err } => return Ok(ExpandResult { value: None, err }),
181 };
182
183 log::debug!("macro expansion {:#?}", raw_node);
184
185 let mark = advance_state(db);
186
187 Ok(ExpandResult { value: Some((mark, raw_node)), err })
188 }
189
190 pub(crate) fn enter_expand<T: ast::AstNode>(
191 &mut self,
192 db: &dyn DefDatabase,
193 macro_call: ast::MacroCall,
194 ) -> Result<ExpandResult<Option<(Mark, T)>>, UnresolvedMacro> {
195 let (raw_node, mut advance_state, err) = match self.enter_expand_intern(db, macro_call)? {
196 ExpandResult { value: Some((raw_node, advance_state)), err } => {
197 (raw_node, advance_state, err)
198 }
199 ExpandResult { value: None, err } => return Ok(ExpandResult { value: None, err }),
200 };
201
150 let node = match T::cast(raw_node) { 202 let node = match T::cast(raw_node) {
151 Some(it) => it, 203 Some(it) => it,
152 None => { 204 None => {
@@ -157,15 +209,7 @@ impl Expander {
157 209
158 log::debug!("macro expansion {:#?}", node.syntax()); 210 log::debug!("macro expansion {:#?}", node.syntax());
159 211
160 self.recursion_limit += 1; 212 let mark = advance_state(db);
161 let mark = Mark {
162 file_id: self.current_file_id,
163 ast_id_map: mem::take(&mut self.ast_id_map),
164 bomb: DropBomb::new("expansion mark dropped"),
165 };
166 self.cfg_expander.hygiene = Hygiene::new(db.upcast(), file_id);
167 self.current_file_id = file_id;
168 self.ast_id_map = db.ast_id_map(file_id);
169 213
170 Ok(ExpandResult { value: Some((mark, node)), err }) 214 Ok(ExpandResult { value: Some((mark, node)), err })
171 } 215 }
@@ -191,7 +235,8 @@ impl Expander {
191 } 235 }
192 236
193 fn parse_path(&mut self, path: ast::Path) -> Option<Path> { 237 fn parse_path(&mut self, path: ast::Path) -> Option<Path> {
194 Path::from_src(path, &self.cfg_expander.hygiene) 238 let ctx = LowerCtx::with_hygiene(&self.cfg_expander.hygiene);
239 Path::from_src(path, &ctx)
195 } 240 }
196 241
197 fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<MacroDefId> { 242 fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<MacroDefId> {
@@ -204,6 +249,7 @@ impl Expander {
204 } 249 }
205} 250}
206 251
252#[derive(Debug)]
207pub(crate) struct Mark { 253pub(crate) struct Mark {
208 file_id: HirFileId, 254 file_id: HirFileId,
209 ast_id_map: Arc<AstIdMap>, 255 ast_id_map: Arc<AstIdMap>,
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs
index c0b0b7841..c11da30d2 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -1,10 +1,11 @@
1//! Transforms `ast::Expr` into an equivalent `hir_def::expr::Expr` 1//! Transforms `ast::Expr` into an equivalent `hir_def::expr::Expr`
2//! representation. 2//! representation.
3 3
4use std::mem; 4use std::{mem, sync::Arc};
5 5
6use either::Either; 6use either::Either;
7use hir_expand::{ 7use hir_expand::{
8 ast_id_map::{AstIdMap, FileAstId},
8 hygiene::Hygiene, 9 hygiene::Hygiene,
9 name::{name, AsName, Name}, 10 name::{name, AsName, Name},
10 ExpandError, HirFileId, 11 ExpandError, HirFileId,
@@ -39,20 +40,39 @@ use crate::{
39 40
40use super::{diagnostics::BodyDiagnostic, ExprSource, PatSource}; 41use super::{diagnostics::BodyDiagnostic, ExprSource, PatSource};
41 42
42pub(crate) struct LowerCtx { 43pub struct LowerCtx {
43 hygiene: Hygiene, 44 hygiene: Hygiene,
45 file_id: Option<HirFileId>,
46 source_ast_id_map: Option<Arc<AstIdMap>>,
44} 47}
45 48
46impl LowerCtx { 49impl LowerCtx {
47 pub(crate) fn new(db: &dyn DefDatabase, file_id: HirFileId) -> Self { 50 pub fn new(db: &dyn DefDatabase, file_id: HirFileId) -> Self {
48 LowerCtx { hygiene: Hygiene::new(db.upcast(), file_id) } 51 LowerCtx {
52 hygiene: Hygiene::new(db.upcast(), file_id),
53 file_id: Some(file_id),
54 source_ast_id_map: Some(db.ast_id_map(file_id)),
55 }
56 }
57
58 pub fn with_hygiene(hygiene: &Hygiene) -> Self {
59 LowerCtx { hygiene: hygiene.clone(), file_id: None, source_ast_id_map: None }
60 }
61
62 pub(crate) fn hygiene(&self) -> &Hygiene {
63 &self.hygiene
49 } 64 }
50 pub(crate) fn with_hygiene(hygiene: &Hygiene) -> Self { 65
51 LowerCtx { hygiene: hygiene.clone() } 66 pub(crate) fn file_id(&self) -> HirFileId {
67 self.file_id.unwrap()
52 } 68 }
53 69
54 pub(crate) fn lower_path(&self, ast: ast::Path) -> Option<Path> { 70 pub(crate) fn lower_path(&self, ast: ast::Path) -> Option<Path> {
55 Path::from_src(ast, &self.hygiene) 71 Path::from_src(ast, self)
72 }
73
74 pub(crate) fn ast_id<N: AstNode>(&self, item: &N) -> Option<FileAstId<N>> {
75 self.source_ast_id_map.as_ref().map(|ast_id_map| ast_id_map.ast_id(item))
56 } 76 }
57} 77}
58 78
diff --git a/crates/hir_def/src/data.rs b/crates/hir_def/src/data.rs
index 135a6698e..8732b1e3e 100644
--- a/crates/hir_def/src/data.rs
+++ b/crates/hir_def/src/data.rs
@@ -123,10 +123,11 @@ impl TypeAliasData {
123 let loc = typ.lookup(db); 123 let loc = typ.lookup(db);
124 let item_tree = loc.id.item_tree(db); 124 let item_tree = loc.id.item_tree(db);
125 let typ = &item_tree[loc.id.value]; 125 let typ = &item_tree[loc.id.value];
126 let type_ref = typ.type_ref.clone();
126 127
127 Arc::new(TypeAliasData { 128 Arc::new(TypeAliasData {
128 name: typ.name.clone(), 129 name: typ.name.clone(),
129 type_ref: typ.type_ref.clone(), 130 type_ref: type_ref,
130 visibility: item_tree[typ.visibility].clone(), 131 visibility: item_tree[typ.visibility].clone(),
131 is_extern: typ.is_extern, 132 is_extern: typ.is_extern,
132 bounds: typ.bounds.to_vec(), 133 bounds: typ.bounds.to_vec(),
@@ -202,12 +203,13 @@ impl ImplData {
202 let item_tree = impl_loc.id.item_tree(db); 203 let item_tree = impl_loc.id.item_tree(db);
203 let impl_def = &item_tree[impl_loc.id.value]; 204 let impl_def = &item_tree[impl_loc.id.value];
204 let target_trait = impl_def.target_trait.clone(); 205 let target_trait = impl_def.target_trait.clone();
205 let self_ty = impl_def.self_ty.clone();
206 let is_negative = impl_def.is_negative; 206 let is_negative = impl_def.is_negative;
207 let module_id = impl_loc.container; 207 let module_id = impl_loc.container;
208 let container = AssocContainerId::ImplId(id); 208 let container = AssocContainerId::ImplId(id);
209 let mut expander = Expander::new(db, impl_loc.id.file_id(), module_id); 209 let file_id = impl_loc.id.file_id();
210 let self_ty = impl_def.self_ty.clone();
210 211
212 let mut expander = Expander::new(db, file_id, module_id);
211 let items = collect_items( 213 let items = collect_items(
212 db, 214 db,
213 module_id, 215 module_id,
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs
index 45b099cf3..2975786dd 100644
--- a/crates/hir_def/src/item_tree/lower.rs
+++ b/crates/hir_def/src/item_tree/lower.rs
@@ -189,12 +189,16 @@ impl Ctx {
189 block_stack.push(self.source_ast_id_map.ast_id(&block)); 189 block_stack.push(self.source_ast_id_map.ast_id(&block));
190 }, 190 },
191 ast::Item(item) => { 191 ast::Item(item) => {
192 // FIXME: This triggers for macro calls in expression/pattern/type position 192 // FIXME: This triggers for macro calls in expression/pattern
193 let mod_items = self.lower_mod_item(&item, true); 193 if let Some(SyntaxKind::MACRO_TYPE) = node.parent().map(|p| p.kind()) {
194 let current_block = block_stack.last(); 194 // Ignore macros at type position
195 if let (Some(mod_items), Some(block)) = (mod_items, current_block) { 195 } else {
196 if !mod_items.0.is_empty() { 196 let mod_items = self.lower_mod_item(&item, true);
197 self.data().inner_items.entry(*block).or_default().extend(mod_items.0.iter().copied()); 197 let current_block = block_stack.last();
198 if let (Some(mod_items), Some(block)) = (mod_items, current_block) {
199 if !mod_items.0.is_empty() {
200 self.data().inner_items.entry(*block).or_default().extend(mod_items.0.iter().copied());
201 }
198 } 202 }
199 } 203 }
200 }, 204 },
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs
index 000567d99..059724daa 100644
--- a/crates/hir_def/src/lib.rs
+++ b/crates/hir_def/src/lib.rs
@@ -676,6 +676,7 @@ impl<T: ast::AstNode> AstIdWithPath<T> {
676 } 676 }
677} 677}
678 678
679#[derive(Debug)]
679pub struct UnresolvedMacro { 680pub struct UnresolvedMacro {
680 pub path: ModPath, 681 pub path: ModPath,
681} 682}
diff --git a/crates/hir_def/src/path.rs b/crates/hir_def/src/path.rs
index b528ff8ba..509f77850 100644
--- a/crates/hir_def/src/path.rs
+++ b/crates/hir_def/src/path.rs
@@ -48,7 +48,8 @@ pub enum ImportAlias {
48 48
49impl ModPath { 49impl ModPath {
50 pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> { 50 pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> {
51 lower::lower_path(path, hygiene).map(|it| (*it.mod_path).clone()) 51 let ctx = LowerCtx::with_hygiene(hygiene);
52 lower::lower_path(path, &ctx).map(|it| (*it.mod_path).clone())
52 } 53 }
53 54
54 pub fn from_segments(kind: PathKind, segments: impl IntoIterator<Item = Name>) -> ModPath { 55 pub fn from_segments(kind: PathKind, segments: impl IntoIterator<Item = Name>) -> ModPath {
@@ -167,8 +168,8 @@ pub enum GenericArg {
167impl Path { 168impl Path {
168 /// Converts an `ast::Path` to `Path`. Works with use trees. 169 /// Converts an `ast::Path` to `Path`. Works with use trees.
169 /// It correctly handles `$crate` based path from macro call. 170 /// It correctly handles `$crate` based path from macro call.
170 pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<Path> { 171 pub fn from_src(path: ast::Path, ctx: &LowerCtx) -> Option<Path> {
171 lower::lower_path(path, hygiene) 172 lower::lower_path(path, ctx)
172 } 173 }
173 174
174 /// Converts a known mod path to `Path`. 175 /// Converts a known mod path to `Path`.
diff --git a/crates/hir_def/src/path/lower.rs b/crates/hir_def/src/path/lower.rs
index 7b29d9d4f..1df6db525 100644
--- a/crates/hir_def/src/path/lower.rs
+++ b/crates/hir_def/src/path/lower.rs
@@ -6,10 +6,7 @@ use crate::intern::Interned;
6use std::sync::Arc; 6use std::sync::Arc;
7 7
8use either::Either; 8use either::Either;
9use hir_expand::{ 9use hir_expand::name::{name, AsName};
10 hygiene::Hygiene,
11 name::{name, AsName},
12};
13use syntax::ast::{self, AstNode, TypeBoundsOwner}; 10use syntax::ast::{self, AstNode, TypeBoundsOwner};
14 11
15use super::AssociatedTypeBinding; 12use super::AssociatedTypeBinding;
@@ -23,12 +20,12 @@ pub(super) use lower_use::lower_use_tree;
23 20
24/// Converts an `ast::Path` to `Path`. Works with use trees. 21/// Converts an `ast::Path` to `Path`. Works with use trees.
25/// It correctly handles `$crate` based path from macro call. 22/// It correctly handles `$crate` based path from macro call.
26pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> { 23pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx) -> Option<Path> {
27 let mut kind = PathKind::Plain; 24 let mut kind = PathKind::Plain;
28 let mut type_anchor = None; 25 let mut type_anchor = None;
29 let mut segments = Vec::new(); 26 let mut segments = Vec::new();
30 let mut generic_args = Vec::new(); 27 let mut generic_args = Vec::new();
31 let ctx = LowerCtx::with_hygiene(hygiene); 28 let hygiene = ctx.hygiene();
32 loop { 29 loop {
33 let segment = path.segment()?; 30 let segment = path.segment()?;
34 31
@@ -43,10 +40,10 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path>
43 Either::Left(name) => { 40 Either::Left(name) => {
44 let args = segment 41 let args = segment
45 .generic_arg_list() 42 .generic_arg_list()
46 .and_then(|it| lower_generic_args(&ctx, it)) 43 .and_then(|it| lower_generic_args(ctx, it))
47 .or_else(|| { 44 .or_else(|| {
48 lower_generic_args_from_fn_path( 45 lower_generic_args_from_fn_path(
49 &ctx, 46 ctx,
50 segment.param_list(), 47 segment.param_list(),
51 segment.ret_type(), 48 segment.ret_type(),
52 ) 49 )
@@ -64,7 +61,7 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path>
64 ast::PathSegmentKind::Type { type_ref, trait_ref } => { 61 ast::PathSegmentKind::Type { type_ref, trait_ref } => {
65 assert!(path.qualifier().is_none()); // this can only occur at the first segment 62 assert!(path.qualifier().is_none()); // this can only occur at the first segment
66 63
67 let self_type = TypeRef::from_ast(&ctx, type_ref?); 64 let self_type = TypeRef::from_ast(ctx, type_ref?);
68 65
69 match trait_ref { 66 match trait_ref {
70 // <T>::foo 67 // <T>::foo
@@ -74,7 +71,7 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path>
74 } 71 }
75 // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo 72 // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo
76 Some(trait_ref) => { 73 Some(trait_ref) => {
77 let path = Path::from_src(trait_ref.path()?, hygiene)?; 74 let path = Path::from_src(trait_ref.path()?, ctx)?;
78 let mod_path = (*path.mod_path).clone(); 75 let mod_path = (*path.mod_path).clone();
79 let num_segments = path.mod_path.segments.len(); 76 let num_segments = path.mod_path.segments.len();
80 kind = mod_path.kind; 77 kind = mod_path.kind;
diff --git a/crates/hir_def/src/type_ref.rs b/crates/hir_def/src/type_ref.rs
index 4c24aae94..0832371c0 100644
--- a/crates/hir_def/src/type_ref.rs
+++ b/crates/hir_def/src/type_ref.rs
@@ -1,9 +1,16 @@
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.
3use hir_expand::name::Name; 3use std::borrow::Cow;
4use syntax::ast;
5 4
6use crate::{body::LowerCtx, path::Path}; 5use hir_expand::{ast_id_map::FileAstId, name::Name, ExpandResult, InFile};
6use syntax::{algo::SyntaxRewriter, ast, AstNode, SyntaxKind, SyntaxNode};
7
8use crate::{
9 body::{Expander, LowerCtx},
10 db::DefDatabase,
11 path::Path,
12 ModuleId,
13};
7 14
8#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] 15#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
9pub enum Mutability { 16pub enum Mutability {
@@ -68,6 +75,7 @@ impl TraitRef {
68 } 75 }
69 } 76 }
70} 77}
78
71/// Compare ty::Ty 79/// Compare ty::Ty
72#[derive(Clone, PartialEq, Eq, Hash, Debug)] 80#[derive(Clone, PartialEq, Eq, Hash, Debug)]
73pub enum TypeRef { 81pub enum TypeRef {
@@ -84,6 +92,7 @@ pub enum TypeRef {
84 // For 92 // For
85 ImplTrait(Vec<TypeBound>), 93 ImplTrait(Vec<TypeBound>),
86 DynTrait(Vec<TypeBound>), 94 DynTrait(Vec<TypeBound>),
95 Macro(InFile<FileAstId<ast::MacroCall>>),
87 Error, 96 Error,
88} 97}
89 98
@@ -176,8 +185,13 @@ impl TypeRef {
176 ast::Type::DynTraitType(inner) => { 185 ast::Type::DynTraitType(inner) => {
177 TypeRef::DynTrait(type_bounds_from_ast(ctx, inner.type_bound_list())) 186 TypeRef::DynTrait(type_bounds_from_ast(ctx, inner.type_bound_list()))
178 } 187 }
179 // FIXME: Macros in type position are not yet supported. 188 ast::Type::MacroType(mt) => match mt.macro_call() {
180 ast::Type::MacroType(_) => TypeRef::Error, 189 Some(mc) => ctx
190 .ast_id(&mc)
191 .map(|mc| TypeRef::Macro(InFile::new(ctx.file_id(), mc)))
192 .unwrap_or(TypeRef::Error),
193 None => TypeRef::Error,
194 },
181 } 195 }
182 } 196 }
183 197
@@ -193,6 +207,16 @@ impl TypeRef {
193 TypeRef::Tuple(Vec::new()) 207 TypeRef::Tuple(Vec::new())
194 } 208 }
195 209
210 pub fn has_macro_calls(&self) -> bool {
211 let mut has_macro_call = false;
212 self.walk(&mut |ty_ref| {
213 if let TypeRef::Macro(_) = ty_ref {
214 has_macro_call |= true
215 }
216 });
217 has_macro_call
218 }
219
196 pub fn walk(&self, f: &mut impl FnMut(&TypeRef)) { 220 pub fn walk(&self, f: &mut impl FnMut(&TypeRef)) {
197 go(self, f); 221 go(self, f);
198 222
@@ -215,7 +239,7 @@ impl TypeRef {
215 } 239 }
216 } 240 }
217 TypeRef::Path(path) => go_path(path, f), 241 TypeRef::Path(path) => go_path(path, f),
218 TypeRef::Never | TypeRef::Placeholder | TypeRef::Error => {} 242 TypeRef::Never | TypeRef::Placeholder | TypeRef::Macro(_) | TypeRef::Error => {}
219 }; 243 };
220 } 244 }
221 245
@@ -290,3 +314,69 @@ impl TypeBound {
290 } 314 }
291 } 315 }
292} 316}
317
318pub fn expand_type_ref<'a>(
319 db: &dyn DefDatabase,
320 module_id: ModuleId,
321 type_ref: &'a TypeRef,
322) -> Option<Cow<'a, TypeRef>> {
323 let macro_call = match type_ref {
324 TypeRef::Macro(macro_call) => macro_call,
325 _ => return Some(Cow::Borrowed(type_ref)),
326 };
327
328 let file_id = macro_call.file_id;
329 let macro_call = macro_call.to_node(db.upcast());
330
331 let mut expander = Expander::new(db, file_id, module_id);
332 let expanded = expand(db, &mut expander, &macro_call, true)?;
333
334 let node = ast::Type::cast(expanded)?;
335
336 let ctx = LowerCtx::new(db, file_id);
337 return Some(Cow::Owned(TypeRef::from_ast(&ctx, node)));
338
339 fn expand(
340 db: &dyn DefDatabase,
341 expander: &mut Expander,
342 macro_call: &ast::MacroCall,
343 expect_type: bool,
344 ) -> Option<SyntaxNode> {
345 let (mark, mut expanded) = match expander.enter_expand_raw(db, macro_call.clone()) {
346 Ok(ExpandResult { value: Some((mark, expanded)), .. }) => (mark, expanded),
347 _ => return None,
348 };
349
350 if expect_type && !ast::Type::can_cast(expanded.kind()) {
351 expander.exit(db, mark);
352 return None;
353 }
354
355 if ast::MacroType::can_cast(expanded.kind()) {
356 expanded = expanded.first_child()?; // MACRO_CALL
357 }
358
359 let mut rewriter = SyntaxRewriter::default();
360
361 let children = expanded.descendants().filter_map(ast::MacroCall::cast);
362 for child in children {
363 if let Some(new_node) = expand(db, expander, &child, false) {
364 if expanded == *child.syntax() {
365 expanded = new_node;
366 } else {
367 let parent = child.syntax().parent();
368 let old_node = match &parent {
369 Some(node) if node.kind() == SyntaxKind::MACRO_TYPE => node,
370 _ => child.syntax(),
371 };
372 rewriter.replace(old_node, &new_node)
373 }
374 }
375 }
376
377 expander.exit(db, mark);
378
379 let res = rewriter.rewrite(&expanded);
380 Some(res)
381 }
382}