Skip to content

Commit cf3b4f1

Browse files
committed
hir_ty: Expand macros at type position
1 parent fb2d284 commit cf3b4f1

File tree

17 files changed

+434
-81
lines changed

17 files changed

+434
-81
lines changed

crates/hir/src/semantics.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use std::{cell::RefCell, fmt, iter::successors};
66

77
use base_db::{FileId, FileRange};
88
use hir_def::{
9+
body,
910
resolver::{self, HasResolver, Resolver, TypeNs},
1011
AsMacroCall, FunctionId, TraitId, VariantId,
1112
};
@@ -854,7 +855,8 @@ impl<'a> SemanticsScope<'a> {
854855
/// necessary a heuristic, as it doesn't take hygiene into account.
855856
pub fn speculative_resolve(&self, path: &ast::Path) -> Option<PathResolution> {
856857
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)?;
858860
resolve_hir_path(self.db, &self.resolver, &path)
859861
}
860862
}

crates/hir/src/source_analyzer.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use std::{iter::once, sync::Arc};
99

1010
use hir_def::{
1111
body::{
12+
self,
1213
scope::{ExprScopes, ScopeId},
1314
Body, BodySourceMap,
1415
},
@@ -202,8 +203,8 @@ impl SourceAnalyzer {
202203
db: &dyn HirDatabase,
203204
macro_call: InFile<&ast::MacroCall>,
204205
) -> Option<MacroDef> {
205-
let hygiene = Hygiene::new(db.upcast(), macro_call.file_id);
206-
let path = macro_call.value.path().and_then(|ast| Path::from_src(ast, &hygiene))?;
206+
let ctx = body::LowerCtx::new(db.upcast(), macro_call.file_id);
207+
let path = macro_call.value.path().and_then(|ast| Path::from_src(ast, &ctx))?;
207208
self.resolver.resolve_path_as_macro(db.upcast(), path.mod_path()).map(|it| it.into())
208209
}
209210

@@ -281,7 +282,9 @@ impl SourceAnalyzer {
281282
}
282283

283284
// 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)?;
285288

286289
// Case where path is a qualifier of another path, e.g. foo::bar::Baz where we
287290
// trying to resolve foo::bar.

crates/hir_def/src/body.rs

Lines changed: 60 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ use hir_expand::{
1919
use la_arena::{Arena, ArenaMap};
2020
use profile::Count;
2121
use rustc_hash::FxHashMap;
22-
use syntax::{ast, AstNode, AstPtr};
22+
use syntax::{ast, AstNode, AstPtr, SyntaxNode};
2323

24-
pub(crate) use lower::LowerCtx;
24+
pub use lower::LowerCtx;
2525

2626
use crate::{
2727
attr::{Attrs, RawAttrs},
@@ -98,11 +98,14 @@ impl Expander {
9898
}
9999
}
100100

101-
pub(crate) fn enter_expand<T: ast::AstNode>(
101+
fn enter_expand_intern(
102102
&mut self,
103103
db: &dyn DefDatabase,
104104
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+
> {
106109
if self.recursion_limit + 1 > EXPANSION_RECURSION_LIMIT {
107110
cov_mark::hit!(your_stack_belongs_to_me);
108111
return Ok(ExpandResult::str_err(
@@ -147,6 +150,55 @@ impl Expander {
147150
}
148151
};
149152

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+
150202
let node = match T::cast(raw_node) {
151203
Some(it) => it,
152204
None => {
@@ -157,15 +209,7 @@ impl Expander {
157209

158210
log::debug!("macro expansion {:#?}", node.syntax());
159211

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);
212+
let mark = advance_state(db);
169213

170214
Ok(ExpandResult { value: Some((mark, node)), err })
171215
}
@@ -191,7 +235,8 @@ impl Expander {
191235
}
192236

193237
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)
195240
}
196241

197242
fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<MacroDefId> {
@@ -204,6 +249,7 @@ impl Expander {
204249
}
205250
}
206251

252+
#[derive(Debug)]
207253
pub(crate) struct Mark {
208254
file_id: HirFileId,
209255
ast_id_map: Arc<AstIdMap>,

crates/hir_def/src/body/lower.rs

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
//! Transforms `ast::Expr` into an equivalent `hir_def::expr::Expr`
22
//! representation.
33
4-
use std::mem;
4+
use std::{mem, sync::Arc};
55

66
use either::Either;
77
use hir_expand::{
8+
ast_id_map::{AstIdMap, FileAstId},
89
hygiene::Hygiene,
910
name::{name, AsName, Name},
1011
ExpandError, HirFileId,
@@ -39,20 +40,39 @@ use crate::{
3940

4041
use super::{diagnostics::BodyDiagnostic, ExprSource, PatSource};
4142

42-
pub(crate) struct LowerCtx {
43+
pub struct LowerCtx {
4344
hygiene: Hygiene,
45+
file_id: Option<HirFileId>,
46+
source_ast_id_map: Option<Arc<AstIdMap>>,
4447
}
4548

4649
impl LowerCtx {
47-
pub(crate) fn new(db: &dyn DefDatabase, file_id: HirFileId) -> Self {
48-
LowerCtx { hygiene: Hygiene::new(db.upcast(), file_id) }
50+
pub fn new(db: &dyn DefDatabase, file_id: HirFileId) -> Self {
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
4964
}
50-
pub(crate) fn with_hygiene(hygiene: &Hygiene) -> Self {
51-
LowerCtx { hygiene: hygiene.clone() }
65+
66+
pub(crate) fn file_id(&self) -> HirFileId {
67+
self.file_id.unwrap()
5268
}
5369

5470
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))
5676
}
5777
}
5878

crates/hir_def/src/data.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,10 +123,11 @@ impl TypeAliasData {
123123
let loc = typ.lookup(db);
124124
let item_tree = loc.id.item_tree(db);
125125
let typ = &item_tree[loc.id.value];
126+
let type_ref = typ.type_ref.clone();
126127

127128
Arc::new(TypeAliasData {
128129
name: typ.name.clone(),
129-
type_ref: typ.type_ref.clone(),
130+
type_ref: type_ref,
130131
visibility: item_tree[typ.visibility].clone(),
131132
is_extern: typ.is_extern,
132133
bounds: typ.bounds.to_vec(),
@@ -202,12 +203,13 @@ impl ImplData {
202203
let item_tree = impl_loc.id.item_tree(db);
203204
let impl_def = &item_tree[impl_loc.id.value];
204205
let target_trait = impl_def.target_trait.clone();
205-
let self_ty = impl_def.self_ty.clone();
206206
let is_negative = impl_def.is_negative;
207207
let module_id = impl_loc.container;
208208
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();
210211

212+
let mut expander = Expander::new(db, file_id, module_id);
211213
let items = collect_items(
212214
db,
213215
module_id,

crates/hir_def/src/item_tree/lower.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -189,12 +189,16 @@ impl Ctx {
189189
block_stack.push(self.source_ast_id_map.ast_id(&block));
190190
},
191191
ast::Item(item) => {
192-
// FIXME: This triggers for macro calls in expression/pattern/type position
193-
let mod_items = self.lower_mod_item(&item, true);
194-
let current_block = block_stack.last();
195-
if let (Some(mod_items), Some(block)) = (mod_items, current_block) {
196-
if !mod_items.0.is_empty() {
197-
self.data().inner_items.entry(*block).or_default().extend(mod_items.0.iter().copied());
192+
// FIXME: This triggers for macro calls in expression/pattern
193+
if let Some(SyntaxKind::MACRO_TYPE) = node.parent().map(|p| p.kind()) {
194+
// Ignore macros at type position
195+
} else {
196+
let mod_items = self.lower_mod_item(&item, true);
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+
}
198202
}
199203
}
200204
},

crates/hir_def/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -676,6 +676,7 @@ impl<T: ast::AstNode> AstIdWithPath<T> {
676676
}
677677
}
678678

679+
#[derive(Debug)]
679680
pub struct UnresolvedMacro {
680681
pub path: ModPath,
681682
}

crates/hir_def/src/path.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ pub enum ImportAlias {
4848

4949
impl ModPath {
5050
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())
5253
}
5354

5455
pub fn from_segments(kind: PathKind, segments: impl IntoIterator<Item = Name>) -> ModPath {
@@ -167,8 +168,8 @@ pub enum GenericArg {
167168
impl Path {
168169
/// Converts an `ast::Path` to `Path`. Works with use trees.
169170
/// It correctly handles `$crate` based path from macro call.
170-
pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<Path> {
171-
lower::lower_path(path, hygiene)
171+
pub fn from_src(path: ast::Path, ctx: &LowerCtx) -> Option<Path> {
172+
lower::lower_path(path, ctx)
172173
}
173174

174175
/// Converts a known mod path to `Path`.

crates/hir_def/src/path/lower.rs

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,7 @@ use crate::intern::Interned;
66
use std::sync::Arc;
77

88
use either::Either;
9-
use hir_expand::{
10-
hygiene::Hygiene,
11-
name::{name, AsName},
12-
};
9+
use hir_expand::name::{name, AsName};
1310
use syntax::ast::{self, AstNode, TypeBoundsOwner};
1411

1512
use super::AssociatedTypeBinding;
@@ -23,12 +20,12 @@ pub(super) use lower_use::lower_use_tree;
2320

2421
/// Converts an `ast::Path` to `Path`. Works with use trees.
2522
/// It correctly handles `$crate` based path from macro call.
26-
pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> {
23+
pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx) -> Option<Path> {
2724
let mut kind = PathKind::Plain;
2825
let mut type_anchor = None;
2926
let mut segments = Vec::new();
3027
let mut generic_args = Vec::new();
31-
let ctx = LowerCtx::with_hygiene(hygiene);
28+
let hygiene = ctx.hygiene();
3229
loop {
3330
let segment = path.segment()?;
3431

@@ -43,10 +40,10 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path>
4340
Either::Left(name) => {
4441
let args = segment
4542
.generic_arg_list()
46-
.and_then(|it| lower_generic_args(&ctx, it))
43+
.and_then(|it| lower_generic_args(ctx, it))
4744
.or_else(|| {
4845
lower_generic_args_from_fn_path(
49-
&ctx,
46+
ctx,
5047
segment.param_list(),
5148
segment.ret_type(),
5249
)
@@ -64,7 +61,7 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path>
6461
ast::PathSegmentKind::Type { type_ref, trait_ref } => {
6562
assert!(path.qualifier().is_none()); // this can only occur at the first segment
6663

67-
let self_type = TypeRef::from_ast(&ctx, type_ref?);
64+
let self_type = TypeRef::from_ast(ctx, type_ref?);
6865

6966
match trait_ref {
7067
// <T>::foo
@@ -74,7 +71,7 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path>
7471
}
7572
// <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo
7673
Some(trait_ref) => {
77-
let path = Path::from_src(trait_ref.path()?, hygiene)?;
74+
let path = Path::from_src(trait_ref.path()?, ctx)?;
7875
let mod_path = (*path.mod_path).clone();
7976
let num_segments = path.mod_path.segments.len();
8077
kind = mod_path.kind;

0 commit comments

Comments
 (0)