aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-04-19 14:01:30 +0100
committerGitHub <[email protected]>2021-04-19 14:01:30 +0100
commite4f7f1e1bd2ca3c1816abf87779ad8893b7bf990 (patch)
treee843f284eca0c2a8d371c7af7c6532bace0d504d /crates
parent3f1a220f32220cd4a664ca1adac5eb36e9eb33b2 (diff)
parentf0507ab7c697ba4bcd59dd2f673dfff5072e3e1a (diff)
Merge #8462
8462: Expand macros at type position r=jonas-schievink a=cynecx Co-authored-by: cynecx <[email protected]>
Diffstat (limited to 'crates')
-rw-r--r--crates/hir/src/semantics.rs7
-rw-r--r--crates/hir/src/source_analyzer.rs9
-rw-r--r--crates/hir_def/src/body.rs26
-rw-r--r--crates/hir_def/src/body/lower.rs34
-rw-r--r--crates/hir_def/src/item_tree.rs5
-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.rs18
-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.rs15
-rw-r--r--crates/hir_ty/src/lower.rs69
-rw-r--r--crates/hir_ty/src/tests/macros.rs199
-rw-r--r--crates/parser/src/grammar/types.rs10
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0117_macro_call_type.rast48
16 files changed, 391 insertions, 76 deletions
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 7955bf0b5..62500602a 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -6,10 +6,11 @@ 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};
12use hir_expand::{hygiene::Hygiene, name::AsName, ExpansionInfo}; 13use hir_expand::{name::AsName, ExpansionInfo};
13use hir_ty::associated_type_shorthand_candidates; 14use hir_ty::associated_type_shorthand_candidates;
14use itertools::Itertools; 15use itertools::Itertools;
15use rustc_hash::{FxHashMap, FxHashSet}; 16use rustc_hash::{FxHashMap, FxHashSet};
@@ -853,8 +854,8 @@ impl<'a> SemanticsScope<'a> {
853 /// Resolve a path as-if it was written at the given scope. This is 854 /// Resolve a path as-if it was written at the given scope. This is
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 ctx = body::LowerCtx::new(self.db.upcast(), self.file_id);
857 let path = Path::from_src(path.clone(), &hygiene)?; 858 let path = Path::from_src(path.clone(), &ctx)?;
858 resolve_hir_path(self.db, &self.resolver, &path) 859 resolve_hir_path(self.db, &self.resolver, &path)
859 } 860 }
860} 861}
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..131f424cc 100644
--- a/crates/hir_def/src/body.rs
+++ b/crates/hir_def/src/body.rs
@@ -21,7 +21,7 @@ use profile::Count;
21use rustc_hash::FxHashMap; 21use rustc_hash::FxHashMap;
22use syntax::{ast, AstNode, AstPtr}; 22use syntax::{ast, AstNode, AstPtr};
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},
@@ -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,8 +188,13 @@ impl Expander {
190 &self.cfg_expander.cfg_options 188 &self.cfg_expander.cfg_options
191 } 189 }
192 190
191 pub fn current_file_id(&self) -> HirFileId {
192 self.current_file_id
193 }
194
193 fn parse_path(&mut self, path: ast::Path) -> Option<Path> { 195 fn parse_path(&mut self, path: ast::Path) -> Option<Path> {
194 Path::from_src(path, &self.cfg_expander.hygiene) 196 let ctx = LowerCtx::with_hygiene(&self.cfg_expander.hygiene);
197 Path::from_src(path, &ctx)
195 } 198 }
196 199
197 fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<MacroDefId> { 200 fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<MacroDefId> {
@@ -204,7 +207,8 @@ impl Expander {
204 } 207 }
205} 208}
206 209
207pub(crate) struct Mark { 210#[derive(Debug)]
211pub struct Mark {
208 file_id: HirFileId, 212 file_id: HirFileId,
209 ast_id_map: Arc<AstIdMap>, 213 ast_id_map: Arc<AstIdMap>,
210 bomb: DropBomb, 214 bomb: DropBomb,
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/item_tree.rs b/crates/hir_def/src/item_tree.rs
index 94e08f835..16a94a058 100644
--- a/crates/hir_def/src/item_tree.rs
+++ b/crates/hir_def/src/item_tree.rs
@@ -104,6 +104,11 @@ impl ItemTree {
104 // items and expanded during block DefMap computation 104 // items and expanded during block DefMap computation
105 return Default::default(); 105 return Default::default();
106 }, 106 },
107 ast::Type(ty) => {
108 // Types can contain inner items. We return an empty item tree in this case, but
109 // still need to collect inner items.
110 ctx.lower_inner_items(ty.syntax())
111 },
107 ast::Expr(e) => { 112 ast::Expr(e) => {
108 // Macros can expand to expressions. We return an empty item tree in this case, but 113 // Macros can expand to expressions. We return an empty item tree in this case, but
109 // still need to collect inner items. 114 // still need to collect inner items.
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs
index 5ac1670b5..25694f037 100644
--- a/crates/hir_def/src/lib.rs
+++ b/crates/hir_def/src/lib.rs
@@ -688,6 +688,7 @@ impl<T: ast::AstNode> AstIdWithPath<T> {
688 } 688 }
689} 689}
690 690
691#[derive(Debug)]
691pub struct UnresolvedMacro { 692pub struct UnresolvedMacro {
692 pub path: ModPath, 693 pub path: ModPath,
693} 694}
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..ea29da5da 100644
--- a/crates/hir_def/src/type_ref.rs
+++ b/crates/hir_def/src/type_ref.rs
@@ -1,6 +1,7 @@
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; 3
4use hir_expand::{name::Name, AstId, InFile};
4use syntax::ast; 5use syntax::ast;
5 6
6use crate::{body::LowerCtx, path::Path}; 7use crate::{body::LowerCtx, path::Path};
@@ -68,6 +69,7 @@ impl TraitRef {
68 } 69 }
69 } 70 }
70} 71}
72
71/// Compare ty::Ty 73/// Compare ty::Ty
72#[derive(Clone, PartialEq, Eq, Hash, Debug)] 74#[derive(Clone, PartialEq, Eq, Hash, Debug)]
73pub enum TypeRef { 75pub enum TypeRef {
@@ -84,6 +86,7 @@ pub enum TypeRef {
84 // For 86 // For
85 ImplTrait(Vec<TypeBound>), 87 ImplTrait(Vec<TypeBound>),
86 DynTrait(Vec<TypeBound>), 88 DynTrait(Vec<TypeBound>),
89 Macro(AstId<ast::MacroCall>),
87 Error, 90 Error,
88} 91}
89 92
@@ -116,7 +119,7 @@ pub enum TypeBound {
116 119
117impl TypeRef { 120impl TypeRef {
118 /// Converts an `ast::TypeRef` to a `hir::TypeRef`. 121 /// Converts an `ast::TypeRef` to a `hir::TypeRef`.
119 pub(crate) fn from_ast(ctx: &LowerCtx, node: ast::Type) -> Self { 122 pub fn from_ast(ctx: &LowerCtx, node: ast::Type) -> Self {
120 match node { 123 match node {
121 ast::Type::ParenType(inner) => TypeRef::from_ast_opt(&ctx, inner.ty()), 124 ast::Type::ParenType(inner) => TypeRef::from_ast_opt(&ctx, inner.ty()),
122 ast::Type::TupleType(inner) => { 125 ast::Type::TupleType(inner) => {
@@ -176,8 +179,13 @@ impl TypeRef {
176 ast::Type::DynTraitType(inner) => { 179 ast::Type::DynTraitType(inner) => {
177 TypeRef::DynTrait(type_bounds_from_ast(ctx, inner.type_bound_list())) 180 TypeRef::DynTrait(type_bounds_from_ast(ctx, inner.type_bound_list()))
178 } 181 }
179 // FIXME: Macros in type position are not yet supported. 182 ast::Type::MacroType(mt) => match mt.macro_call() {
180 ast::Type::MacroType(_) => TypeRef::Error, 183 Some(mc) => ctx
184 .ast_id(&mc)
185 .map(|mc| TypeRef::Macro(InFile::new(ctx.file_id(), mc)))
186 .unwrap_or(TypeRef::Error),
187 None => TypeRef::Error,
188 },
181 } 189 }
182 } 190 }
183 191
@@ -215,7 +223,7 @@ impl TypeRef {
215 } 223 }
216 } 224 }
217 TypeRef::Path(path) => go_path(path, f), 225 TypeRef::Path(path) => go_path(path, f),
218 TypeRef::Never | TypeRef::Placeholder | TypeRef::Error => {} 226 TypeRef::Never | TypeRef::Placeholder | TypeRef::Macro(_) | TypeRef::Error => {}
219 }; 227 };
220 } 228 }
221 229
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..4fb7d9cf2 100644
--- a/crates/hir_ty/src/display.rs
+++ b/crates/hir_ty/src/display.rs
@@ -9,6 +9,7 @@ use std::{
9 9
10use chalk_ir::BoundVar; 10use chalk_ir::BoundVar;
11use hir_def::{ 11use hir_def::{
12 body,
12 db::DefDatabase, 13 db::DefDatabase,
13 find_path, 14 find_path,
14 generics::TypeParamProvenance, 15 generics::TypeParamProvenance,
@@ -18,7 +19,7 @@ use hir_def::{
18 visibility::Visibility, 19 visibility::Visibility,
19 AssocContainerId, Lookup, ModuleId, TraitId, 20 AssocContainerId, Lookup, ModuleId, TraitId,
20}; 21};
21use hir_expand::name::Name; 22use hir_expand::{hygiene::Hygiene, name::Name};
22 23
23use crate::{ 24use crate::{
24 const_from_placeholder_idx, db::HirDatabase, from_assoc_type_id, from_foreign_def_id, 25 const_from_placeholder_idx, db::HirDatabase, from_assoc_type_id, from_foreign_def_id,
@@ -997,6 +998,18 @@ impl HirDisplay for TypeRef {
997 write!(f, "dyn ")?; 998 write!(f, "dyn ")?;
998 f.write_joined(bounds, " + ")?; 999 f.write_joined(bounds, " + ")?;
999 } 1000 }
1001 TypeRef::Macro(macro_call) => {
1002 let macro_call = macro_call.to_node(f.db.upcast());
1003 let ctx = body::LowerCtx::with_hygiene(&Hygiene::new_unhygienic());
1004 match macro_call.path() {
1005 Some(path) => match Path::from_src(path, &ctx) {
1006 Some(path) => path.hir_fmt(f)?,
1007 None => write!(f, "{{macro}}")?,
1008 },
1009 None => write!(f, "{{macro}}")?,
1010 }
1011 write!(f, "!(..)")?;
1012 }
1000 TypeRef::Error => write!(f, "{{error}}")?, 1013 TypeRef::Error => write!(f, "{{error}}")?,
1001 } 1014 }
1002 Ok(()) 1015 Ok(())
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index a035686bc..7fd46becd 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -5,12 +5,14 @@
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},
@@ -20,10 +22,11 @@ use hir_def::{
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,6 +295,53 @@ impl<'a> TyLoweringContext<'a> {
287 } 295 }
288 } 296 }
289 } 297 }
298 TypeRef::Macro(macro_call) => {
299 let (expander, recursion_start) = {
300 let mut expander = self.expander.borrow_mut();
301 if expander.is_some() {
302 (Some(expander), false)
303 } else {
304 if let Some(module_id) = self.resolver.module() {
305 *expander = Some(Expander::new(
306 self.db.upcast(),
307 macro_call.file_id,
308 module_id,
309 ));
310 (Some(expander), true)
311 } else {
312 (None, false)
313 }
314 }
315 };
316 let ty = if let Some(mut expander) = expander {
317 let expander_mut = expander.as_mut().unwrap();
318 let macro_call = macro_call.to_node(self.db.upcast());
319 match expander_mut.enter_expand::<ast::Type>(self.db.upcast(), macro_call) {
320 Ok(ExpandResult { value: Some((mark, expanded)), .. }) => {
321 let ctx =
322 LowerCtx::new(self.db.upcast(), expander_mut.current_file_id());
323 let type_ref = TypeRef::from_ast(&ctx, expanded);
324
325 drop(expander);
326 let ty = self.lower_ty(&type_ref);
327
328 self.expander
329 .borrow_mut()
330 .as_mut()
331 .unwrap()
332 .exit(self.db.upcast(), mark);
333 Some(ty)
334 }
335 _ => None,
336 }
337 } else {
338 None
339 };
340 if recursion_start {
341 *self.expander.borrow_mut() = None;
342 }
343 ty.unwrap_or_else(|| TyKind::Error.intern(&Interner))
344 }
290 TypeRef::Error => TyKind::Error.intern(&Interner), 345 TypeRef::Error => TyKind::Error.intern(&Interner),
291 }; 346 };
292 (ty, res) 347 (ty, res)
diff --git a/crates/hir_ty/src/tests/macros.rs b/crates/hir_ty/src/tests/macros.rs
index b8e373ed8..6588aa46c 100644
--- a/crates/hir_ty/src/tests/macros.rs
+++ b/crates/hir_ty/src/tests/macros.rs
@@ -1074,3 +1074,202 @@ 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}
1246
1247#[test]
1248fn infinitely_recursive_macro_type() {
1249 check_infer(
1250 r#"
1251 struct Bar<T, X>(T, X);
1252
1253 macro_rules! Foo {
1254 () => { Foo!() }
1255 }
1256
1257 macro_rules! U32 {
1258 () => { u32 }
1259 }
1260
1261 type A = Foo!();
1262 type B = Bar<Foo!(), U32!()>;
1263
1264 fn main() {
1265 let a: A;
1266 let b: B;
1267 }
1268 "#,
1269 expect![[r#"
1270 166..197 '{ ...: B; }': ()
1271 176..177 'a': {unknown}
1272 190..191 'b': Bar<{unknown}, u32>
1273 "#]],
1274 );
1275}
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"