aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_def')
-rw-r--r--crates/hir_def/src/body.rs72
-rw-r--r--crates/hir_def/src/type_ref.rs78
2 files changed, 30 insertions, 120 deletions
diff --git a/crates/hir_def/src/body.rs b/crates/hir_def/src/body.rs
index 44ae13643..8a9b936ea 100644
--- a/crates/hir_def/src/body.rs
+++ b/crates/hir_def/src/body.rs
@@ -19,7 +19,7 @@ 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, SyntaxNode}; 22use syntax::{ast, AstNode, AstPtr};
23 23
24pub use lower::LowerCtx; 24pub use lower::LowerCtx;
25 25
@@ -98,14 +98,11 @@ impl Expander {
98 } 98 }
99 } 99 }
100 100
101 fn enter_expand_intern( 101 pub(crate) fn enter_expand<T: ast::AstNode>(
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< 105 ) -> Result<ExpandResult<Option<(Mark, T)>>, UnresolvedMacro> {
106 ExpandResult<Option<(SyntaxNode, impl FnMut(&dyn DefDatabase) -> Mark + '_)>>,
107 UnresolvedMacro,
108 > {
109 if self.recursion_limit + 1 > EXPANSION_RECURSION_LIMIT { 106 if self.recursion_limit + 1 > EXPANSION_RECURSION_LIMIT {
110 cov_mark::hit!(your_stack_belongs_to_me); 107 cov_mark::hit!(your_stack_belongs_to_me);
111 return Ok(ExpandResult::str_err( 108 return Ok(ExpandResult::str_err(
@@ -150,55 +147,6 @@ impl Expander {
150 } 147 }
151 }; 148 };
152 149
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
202 let node = match T::cast(raw_node) { 150 let node = match T::cast(raw_node) {
203 Some(it) => it, 151 Some(it) => it,
204 None => { 152 None => {
@@ -209,7 +157,15 @@ impl Expander {
209 157
210 log::debug!("macro expansion {:#?}", node.syntax()); 158 log::debug!("macro expansion {:#?}", node.syntax());
211 159
212 let mark = advance_state(db); 160 self.recursion_limit += 1;
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);
213 169
214 Ok(ExpandResult { value: Some((mark, node)), err }) 170 Ok(ExpandResult { value: Some((mark, node)), err })
215 } 171 }
@@ -234,6 +190,10 @@ impl Expander {
234 &self.cfg_expander.cfg_options 190 &self.cfg_expander.cfg_options
235 } 191 }
236 192
193 pub(crate) fn current_file_id(&self) -> HirFileId {
194 self.current_file_id
195 }
196
237 fn parse_path(&mut self, path: ast::Path) -> Option<Path> { 197 fn parse_path(&mut self, path: ast::Path) -> Option<Path> {
238 let ctx = LowerCtx::with_hygiene(&self.cfg_expander.hygiene); 198 let ctx = LowerCtx::with_hygiene(&self.cfg_expander.hygiene);
239 Path::from_src(path, &ctx) 199 Path::from_src(path, &ctx)
diff --git a/crates/hir_def/src/type_ref.rs b/crates/hir_def/src/type_ref.rs
index 0832371c0..cf8a584ab 100644
--- a/crates/hir_def/src/type_ref.rs
+++ b/crates/hir_def/src/type_ref.rs
@@ -1,9 +1,8 @@
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 std::borrow::Cow;
4 3
5use hir_expand::{ast_id_map::FileAstId, name::Name, ExpandResult, InFile}; 4use hir_expand::{ast_id_map::FileAstId, name::Name, ExpandResult, InFile};
6use syntax::{algo::SyntaxRewriter, ast, AstNode, SyntaxKind, SyntaxNode}; 5use syntax::ast;
7 6
8use crate::{ 7use crate::{
9 body::{Expander, LowerCtx}, 8 body::{Expander, LowerCtx},
@@ -207,16 +206,6 @@ impl TypeRef {
207 TypeRef::Tuple(Vec::new()) 206 TypeRef::Tuple(Vec::new())
208 } 207 }
209 208
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
220 pub fn walk(&self, f: &mut impl FnMut(&TypeRef)) { 209 pub fn walk(&self, f: &mut impl FnMut(&TypeRef)) {
221 go(self, f); 210 go(self, f);
222 211
@@ -315,68 +304,29 @@ impl TypeBound {
315 } 304 }
316} 305}
317 306
318pub fn expand_type_ref<'a>( 307pub fn expand_macro_type(
319 db: &dyn DefDatabase, 308 db: &dyn DefDatabase,
320 module_id: ModuleId, 309 module_id: ModuleId,
321 type_ref: &'a TypeRef, 310 macro_type: &TypeRef,
322) -> Option<Cow<'a, TypeRef>> { 311) -> Option<TypeRef> {
323 let macro_call = match type_ref { 312 let macro_call = match macro_type {
324 TypeRef::Macro(macro_call) => macro_call, 313 TypeRef::Macro(macro_call) => macro_call,
325 _ => return Some(Cow::Borrowed(type_ref)), 314 _ => panic!("expected TypeRef::Macro"),
326 }; 315 };
327 316
328 let file_id = macro_call.file_id; 317 let file_id = macro_call.file_id;
329 let macro_call = macro_call.to_node(db.upcast()); 318 let macro_call = macro_call.to_node(db.upcast());
330 319
331 let mut expander = Expander::new(db, file_id, module_id); 320 let mut expander = Expander::new(db, file_id, module_id);
332 let expanded = expand(db, &mut expander, &macro_call, true)?; 321 let (file_id, expanded) = match expander.enter_expand::<ast::Type>(db, macro_call.clone()) {
333 322 Ok(ExpandResult { value: Some((mark, expanded)), .. }) => {
334 let node = ast::Type::cast(expanded)?; 323 let file_id = expander.current_file_id();
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); 324 expander.exit(db, mark);
352 return None; 325 (file_id, expanded)
353 }
354
355 if ast::MacroType::can_cast(expanded.kind()) {
356 expanded = expanded.first_child()?; // MACRO_CALL
357 } 326 }
327 _ => return None,
328 };
358 329
359 let mut rewriter = SyntaxRewriter::default(); 330 let ctx = LowerCtx::new(db, file_id);
360 331 return Some(TypeRef::from_ast(&ctx, expanded));
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} 332}