diff options
author | cynecx <[email protected]> | 2021-04-10 16:49:12 +0100 |
---|---|---|
committer | cynecx <[email protected]> | 2021-04-17 15:24:56 +0100 |
commit | cf3b4f1e208247c9d171273dabff9c6b3c98a240 (patch) | |
tree | 0cae2703b98ba8640ce6693abe32fb51fe27fdda /crates/hir_def/src/type_ref.rs | |
parent | fb2d284f28f70426e39e1b92d95bdbb217a48109 (diff) |
hir_ty: Expand macros at type position
Diffstat (limited to 'crates/hir_def/src/type_ref.rs')
-rw-r--r-- | crates/hir_def/src/type_ref.rs | 102 |
1 files changed, 96 insertions, 6 deletions
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. |
3 | use hir_expand::name::Name; | 3 | use std::borrow::Cow; |
4 | use syntax::ast; | ||
5 | 4 | ||
6 | use crate::{body::LowerCtx, path::Path}; | 5 | use hir_expand::{ast_id_map::FileAstId, name::Name, ExpandResult, InFile}; |
6 | use syntax::{algo::SyntaxRewriter, ast, AstNode, SyntaxKind, SyntaxNode}; | ||
7 | |||
8 | use 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)] |
9 | pub enum Mutability { | 16 | pub 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)] |
73 | pub enum TypeRef { | 81 | pub 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 | |||
318 | pub 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, ¯o_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 | } | ||