aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/hir/src/semantics.rs4
-rw-r--r--crates/hir/src/source_analyzer.rs9
-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
-rw-r--r--crates/hir_expand/src/db.rs1
-rw-r--r--crates/hir_expand/src/eager.rs1
-rw-r--r--crates/hir_ty/src/display.rs2
-rw-r--r--crates/hir_ty/src/lower.rs12
-rw-r--r--crates/hir_ty/src/tests/macros.rs169
-rw-r--r--crates/parser/src/grammar/types.rs10
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0117_macro_call_type.rast48
17 files changed, 434 insertions, 81 deletions
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 7955bf0b5..29c0821cf 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -6,6 +6,7 @@ use std::{cell::RefCell, fmt, iter::successors};
6 6
7use base_db::{FileId, FileRange}; 7use base_db::{FileId, FileRange};
8use hir_def::{ 8use hir_def::{
9 body,
9 resolver::{self, HasResolver, Resolver, TypeNs}, 10 resolver::{self, HasResolver, Resolver, TypeNs},
10 AsMacroCall, FunctionId, TraitId, VariantId, 11 AsMacroCall, FunctionId, TraitId, VariantId,
11}; 12};
@@ -854,7 +855,8 @@ impl<'a> SemanticsScope<'a> {
854 /// necessary a heuristic, as it doesn't take hygiene into account. 855 /// necessary a heuristic, as it doesn't take hygiene into account.
855 pub fn speculative_resolve(&self, path: &ast::Path) -> Option<PathResolution> { 856 pub fn speculative_resolve(&self, path: &ast::Path) -> Option<PathResolution> {
856 let hygiene = Hygiene::new(self.db.upcast(), self.file_id); 857 let hygiene = Hygiene::new(self.db.upcast(), self.file_id);
857 let path = Path::from_src(path.clone(), &hygiene)?; 858 let ctx = body::LowerCtx::with_hygiene(&hygiene);
859 let path = Path::from_src(path.clone(), &ctx)?;
858 resolve_hir_path(self.db, &self.resolver, &path) 860 resolve_hir_path(self.db, &self.resolver, &path)
859 } 861 }
860} 862}
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index 847d2537d..0895bd6f1 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -9,6 +9,7 @@ use std::{iter::once, sync::Arc};
9 9
10use hir_def::{ 10use hir_def::{
11 body::{ 11 body::{
12 self,
12 scope::{ExprScopes, ScopeId}, 13 scope::{ExprScopes, ScopeId},
13 Body, BodySourceMap, 14 Body, BodySourceMap,
14 }, 15 },
@@ -202,8 +203,8 @@ impl SourceAnalyzer {
202 db: &dyn HirDatabase, 203 db: &dyn HirDatabase,
203 macro_call: InFile<&ast::MacroCall>, 204 macro_call: InFile<&ast::MacroCall>,
204 ) -> Option<MacroDef> { 205 ) -> Option<MacroDef> {
205 let hygiene = Hygiene::new(db.upcast(), macro_call.file_id); 206 let ctx = body::LowerCtx::new(db.upcast(), macro_call.file_id);
206 let path = macro_call.value.path().and_then(|ast| Path::from_src(ast, &hygiene))?; 207 let path = macro_call.value.path().and_then(|ast| Path::from_src(ast, &ctx))?;
207 self.resolver.resolve_path_as_macro(db.upcast(), path.mod_path()).map(|it| it.into()) 208 self.resolver.resolve_path_as_macro(db.upcast(), path.mod_path()).map(|it| it.into())
208 } 209 }
209 210
@@ -281,7 +282,9 @@ impl SourceAnalyzer {
281 } 282 }
282 283
283 // This must be a normal source file rather than macro file. 284 // This must be a normal source file rather than macro file.
284 let hir_path = Path::from_src(path.clone(), &Hygiene::new(db.upcast(), self.file_id))?; 285 let hygiene = Hygiene::new(db.upcast(), self.file_id);
286 let ctx = body::LowerCtx::with_hygiene(&hygiene);
287 let hir_path = Path::from_src(path.clone(), &ctx)?;
285 288
286 // Case where path is a qualifier of another path, e.g. foo::bar::Baz where we 289 // Case where path is a qualifier of another path, e.g. foo::bar::Baz where we
287 // trying to resolve foo::bar. 290 // trying to resolve foo::bar.
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}
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs
index ca705ee9d..1e4b0cc19 100644
--- a/crates/hir_expand/src/db.rs
+++ b/crates/hir_expand/src/db.rs
@@ -440,6 +440,7 @@ fn to_fragment_kind(db: &dyn AstDatabase, id: MacroCallId) -> FragmentKind {
440 MACRO_ITEMS | SOURCE_FILE => FragmentKind::Items, 440 MACRO_ITEMS | SOURCE_FILE => FragmentKind::Items,
441 MACRO_STMTS => FragmentKind::Statements, 441 MACRO_STMTS => FragmentKind::Statements,
442 MACRO_PAT => FragmentKind::Pattern, 442 MACRO_PAT => FragmentKind::Pattern,
443 MACRO_TYPE => FragmentKind::Type,
443 ITEM_LIST => FragmentKind::Items, 444 ITEM_LIST => FragmentKind::Items,
444 LET_STMT => { 445 LET_STMT => {
445 // FIXME: Handle LHS Pattern 446 // FIXME: Handle LHS Pattern
diff --git a/crates/hir_expand/src/eager.rs b/crates/hir_expand/src/eager.rs
index ef126e4ad..a5ac32d3c 100644
--- a/crates/hir_expand/src/eager.rs
+++ b/crates/hir_expand/src/eager.rs
@@ -31,6 +31,7 @@ use parser::FragmentKind;
31use std::sync::Arc; 31use std::sync::Arc;
32use syntax::{algo::SyntaxRewriter, SyntaxNode}; 32use syntax::{algo::SyntaxRewriter, SyntaxNode};
33 33
34#[derive(Debug)]
34pub struct ErrorEmitted { 35pub struct ErrorEmitted {
35 _private: (), 36 _private: (),
36} 37}
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs
index e7c9dabc2..63bcb0640 100644
--- a/crates/hir_ty/src/display.rs
+++ b/crates/hir_ty/src/display.rs
@@ -997,7 +997,7 @@ impl HirDisplay for TypeRef {
997 write!(f, "dyn ")?; 997 write!(f, "dyn ")?;
998 f.write_joined(bounds, " + ")?; 998 f.write_joined(bounds, " + ")?;
999 } 999 }
1000 TypeRef::Error => write!(f, "{{error}}")?, 1000 TypeRef::Error | TypeRef::Macro(_) => write!(f, "{{error}}")?,
1001 } 1001 }
1002 Ok(()) 1002 Ok(())
1003 } 1003 }
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index a035686bc..95ca5bdb0 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -15,7 +15,7 @@ use hir_def::{
15 generics::{TypeParamProvenance, WherePredicate, WherePredicateTypeTarget}, 15 generics::{TypeParamProvenance, WherePredicate, WherePredicateTypeTarget},
16 path::{GenericArg, Path, PathSegment, PathSegments}, 16 path::{GenericArg, Path, PathSegment, PathSegments},
17 resolver::{HasResolver, Resolver, TypeNs}, 17 resolver::{HasResolver, Resolver, TypeNs},
18 type_ref::{TraitRef as HirTraitRef, TypeBound, TypeRef}, 18 type_ref::{expand_type_ref, TraitRef as HirTraitRef, TypeBound, TypeRef},
19 AdtId, AssocContainerId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId, 19 AdtId, AssocContainerId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId,
20 GenericDefId, HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId, 20 GenericDefId, HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId,
21 TypeAliasId, TypeParamId, UnionId, VariantId, 21 TypeAliasId, TypeParamId, UnionId, VariantId,
@@ -287,6 +287,16 @@ impl<'a> TyLoweringContext<'a> {
287 } 287 }
288 } 288 }
289 } 289 }
290 mt @ TypeRef::Macro(_) => {
291 if let Some(module_id) = self.resolver.module() {
292 match expand_type_ref(self.db.upcast(), module_id, mt) {
293 Some(type_ref) => self.lower_ty(type_ref.as_ref()),
294 None => TyKind::Error.intern(&Interner),
295 }
296 } else {
297 TyKind::Error.intern(&Interner)
298 }
299 }
290 TypeRef::Error => TyKind::Error.intern(&Interner), 300 TypeRef::Error => TyKind::Error.intern(&Interner),
291 }; 301 };
292 (ty, res) 302 (ty, res)
diff --git a/crates/hir_ty/src/tests/macros.rs b/crates/hir_ty/src/tests/macros.rs
index b8e373ed8..cbe05a5c1 100644
--- a/crates/hir_ty/src/tests/macros.rs
+++ b/crates/hir_ty/src/tests/macros.rs
@@ -1074,3 +1074,172 @@ fn macro_in_arm() {
1074 "#]], 1074 "#]],
1075 ); 1075 );
1076} 1076}
1077
1078#[test]
1079fn macro_in_type_alias_position() {
1080 check_infer(
1081 r#"
1082 macro_rules! U32 {
1083 () => { u32 };
1084 }
1085
1086 trait Foo {
1087 type Ty;
1088 }
1089
1090 impl<T> Foo for T {
1091 type Ty = U32!();
1092 }
1093
1094 type TayTo = U32!();
1095
1096 fn testy() {
1097 let a: <() as Foo>::Ty;
1098 let b: TayTo;
1099 }
1100 "#,
1101 expect![[r#"
1102 147..196 '{ ...yTo; }': ()
1103 157..158 'a': u32
1104 185..186 'b': u32
1105 "#]],
1106 );
1107}
1108
1109#[test]
1110fn nested_macro_in_type_alias_position() {
1111 check_infer(
1112 r#"
1113 macro_rules! U32Inner2 {
1114 () => { u32 };
1115 }
1116
1117 macro_rules! U32Inner1 {
1118 () => { U32Inner2!() };
1119 }
1120
1121 macro_rules! U32 {
1122 () => { U32Inner1!() };
1123 }
1124
1125 trait Foo {
1126 type Ty;
1127 }
1128
1129 impl<T> Foo for T {
1130 type Ty = U32!();
1131 }
1132
1133 type TayTo = U32!();
1134
1135 fn testy() {
1136 let a: <() as Foo>::Ty;
1137 let b: TayTo;
1138 }
1139 "#,
1140 expect![[r#"
1141 259..308 '{ ...yTo; }': ()
1142 269..270 'a': u32
1143 297..298 'b': u32
1144 "#]],
1145 );
1146}
1147
1148#[test]
1149fn macros_in_type_alias_position_generics() {
1150 check_infer(
1151 r#"
1152 struct Foo<A, B>(A, B);
1153
1154 macro_rules! U32 {
1155 () => { u32 };
1156 }
1157
1158 macro_rules! Bar {
1159 () => { Foo<U32!(), U32!()> };
1160 }
1161
1162 trait Moo {
1163 type Ty;
1164 }
1165
1166 impl<T> Moo for T {
1167 type Ty = Bar!();
1168 }
1169
1170 type TayTo = Bar!();
1171
1172 fn main() {
1173 let a: <() as Moo>::Ty;
1174 let b: TayTo;
1175 }
1176 "#,
1177 expect![[r#"
1178 228..277 '{ ...yTo; }': ()
1179 238..239 'a': Foo<u32, u32>
1180 266..267 'b': Foo<u32, u32>
1181 "#]],
1182 );
1183}
1184
1185#[test]
1186fn macros_in_type_position() {
1187 check_infer(
1188 r#"
1189 struct Foo<A, B>(A, B);
1190
1191 macro_rules! U32 {
1192 () => { u32 };
1193 }
1194
1195 macro_rules! Bar {
1196 () => { Foo<U32!(), U32!()> };
1197 }
1198
1199 fn main() {
1200 let a: Bar!();
1201 }
1202 "#,
1203 expect![[r#"
1204 133..155 '{ ...!(); }': ()
1205 143..144 'a': Foo<u32, u32>
1206 "#]],
1207 );
1208}
1209
1210#[test]
1211fn macros_in_type_generics() {
1212 check_infer(
1213 r#"
1214 struct Foo<A, B>(A, B);
1215
1216 macro_rules! U32 {
1217 () => { u32 };
1218 }
1219
1220 macro_rules! Bar {
1221 () => { Foo<U32!(), U32!()> };
1222 }
1223
1224 trait Moo {
1225 type Ty;
1226 }
1227
1228 impl<T> Moo for T {
1229 type Ty = Foo<Bar!(), Bar!()>;
1230 }
1231
1232 type TayTo = Foo<Bar!(), U32!()>;
1233
1234 fn main() {
1235 let a: <() as Moo>::Ty;
1236 let b: TayTo;
1237 }
1238 "#,
1239 expect![[r#"
1240 254..303 '{ ...yTo; }': ()
1241 264..265 'a': Foo<Foo<u32, u32>, Foo<u32, u32>>
1242 292..293 'b': Foo<Foo<u32, u32>, u32>
1243 "#]],
1244 );
1245}
diff --git a/crates/parser/src/grammar/types.rs b/crates/parser/src/grammar/types.rs
index 94cbf7d85..6ae3e734f 100644
--- a/crates/parser/src/grammar/types.rs
+++ b/crates/parser/src/grammar/types.rs
@@ -283,17 +283,21 @@ pub(super) fn path_type(p: &mut Parser) {
283// type B = crate::foo!(); 283// type B = crate::foo!();
284fn path_or_macro_type_(p: &mut Parser, allow_bounds: bool) { 284fn path_or_macro_type_(p: &mut Parser, allow_bounds: bool) {
285 assert!(paths::is_path_start(p)); 285 assert!(paths::is_path_start(p));
286 let r = p.start();
286 let m = p.start(); 287 let m = p.start();
288
287 paths::type_path(p); 289 paths::type_path(p);
288 290
289 let kind = if p.at(T![!]) && !p.at(T![!=]) { 291 let kind = if p.at(T![!]) && !p.at(T![!=]) {
290 items::macro_call_after_excl(p); 292 items::macro_call_after_excl(p);
291 MACRO_CALL 293 m.complete(p, MACRO_CALL);
294 MACRO_TYPE
292 } else { 295 } else {
296 m.abandon(p);
293 PATH_TYPE 297 PATH_TYPE
294 }; 298 };
295 299
296 let path = m.complete(p, kind); 300 let path = r.complete(p, kind);
297 301
298 if allow_bounds { 302 if allow_bounds {
299 opt_type_bounds_as_dyn_trait_type(p, path); 303 opt_type_bounds_as_dyn_trait_type(p, path);
@@ -319,7 +323,7 @@ pub(super) fn path_type_(p: &mut Parser, allow_bounds: bool) {
319fn opt_type_bounds_as_dyn_trait_type(p: &mut Parser, type_marker: CompletedMarker) { 323fn opt_type_bounds_as_dyn_trait_type(p: &mut Parser, type_marker: CompletedMarker) {
320 assert!(matches!( 324 assert!(matches!(
321 type_marker.kind(), 325 type_marker.kind(),
322 SyntaxKind::PATH_TYPE | SyntaxKind::FOR_TYPE | SyntaxKind::MACRO_CALL 326 SyntaxKind::PATH_TYPE | SyntaxKind::FOR_TYPE | SyntaxKind::MACRO_TYPE
323 )); 327 ));
324 if !p.at(T![+]) { 328 if !p.at(T![+]) {
325 return; 329 return;
diff --git a/crates/syntax/test_data/parser/inline/ok/0117_macro_call_type.rast b/crates/syntax/test_data/parser/inline/ok/0117_macro_call_type.rast
index 3016a6574..1ff3f7656 100644
--- a/crates/syntax/test_data/parser/inline/ok/0117_macro_call_type.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0117_macro_call_type.rast
@@ -7,15 +7,16 @@ [email protected]
7 [email protected] " " 7 [email protected] " "
8 [email protected] "=" 8 [email protected] "="
9 [email protected] " " 9 [email protected] " "
10 [email protected] 10 [email protected]
11 [email protected] 11 [email protected]
12 [email protected] 12 [email protected]
13 [email protected] 13 [email protected]
14 [email protected] "foo" 14 [email protected]
15 [email protected] "!" 15 [email protected] "foo"
16 [email protected] 16 [email protected] "!"
17 [email protected] "(" 17 [email protected]
18 [email protected] ")" 18 [email protected] "("
19 [email protected] ")"
19 [email protected] ";" 20 [email protected] ";"
20 [email protected] "\n" 21 [email protected] "\n"
21 [email protected] 22 [email protected]
@@ -26,19 +27,20 @@ [email protected]
26 [email protected] " " 27 [email protected] " "
27 [email protected] "=" 28 [email protected] "="
28 [email protected] " " 29 [email protected] " "
29 [email protected] 30 [email protected]
30 [email protected] 31 [email protected]
31 [email protected] 32 [email protected]
32 [email protected] 33 [email protected]
33 [email protected] 34 [email protected]
34 [email protected] "crate" 35 [email protected]
35 [email protected] "::" 36 [email protected] "crate"
36 [email protected] 37 [email protected] "::"
37 [email protected] 38 [email protected]
38 [email protected] "foo" 39 [email protected]
39 [email protected] "!" 40 [email protected] "foo"
40 [email protected] 41 [email protected] "!"
41 [email protected] "(" 42 [email protected]
42 [email protected] ")" 43 [email protected] "("
44 [email protected] ")"
43 [email protected] ";" 45 [email protected] ";"
44 [email protected] "\n" 46 [email protected] "\n"