Skip to content

Commit 63fd643

Browse files
committed
Various fixes
1 parent bdb7ae5 commit 63fd643

File tree

5 files changed

+75
-25
lines changed

5 files changed

+75
-25
lines changed

crates/hir_expand/src/db.rs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ pub trait AstDatabase: SourceDatabase {
111111
fn macro_arg(
112112
&self,
113113
id: MacroCallId,
114-
) -> Option<Arc<(tt::Subtree, mbe::TokenMap, fixup::SyntaxFixupMap)>>;
114+
) -> Option<Arc<(tt::Subtree, mbe::TokenMap, fixup::SyntaxFixupUndoInfo)>>;
115115
/// Extracts syntax node, corresponding to a macro call. That's a firewall
116116
/// query, only typing in the macro call itself changes the returned
117117
/// subtree.
@@ -151,8 +151,10 @@ pub fn expand_speculative(
151151
let censor = censor_for_macro_input(&loc, &speculative_args);
152152
let mut fixups = fixup::fixup_syntax(&speculative_args);
153153
fixups.replace.extend(censor.into_iter().map(|node| (node, Vec::new())));
154-
let (mut tt, spec_args_tmap) = mbe::syntax_node_to_token_tree_with_modifications(
154+
let (mut tt, spec_args_tmap, _) = mbe::syntax_node_to_token_tree_with_modifications(
155155
&speculative_args,
156+
fixups.token_map,
157+
fixups.next_id,
156158
fixups.replace,
157159
fixups.append,
158160
);
@@ -202,14 +204,15 @@ pub fn expand_speculative(
202204

203205
// Do the actual expansion, we need to directly expand the proc macro due to the attribute args
204206
// Otherwise the expand query will fetch the non speculative attribute args and pass those instead.
205-
let speculative_expansion = if let MacroDefKind::ProcMacro(expander, ..) = loc.def.kind {
207+
let mut speculative_expansion = if let MacroDefKind::ProcMacro(expander, ..) = loc.def.kind {
206208
tt.delimiter = None;
207209
expander.expand(db, loc.krate, &tt, attr_arg.as_ref())
208210
} else {
209211
macro_def.expand(db, actual_macro_call, &tt)
210212
};
211213

212214
let expand_to = macro_expand_to(db, actual_macro_call);
215+
fixup::reverse_fixups(&mut speculative_expansion.value, &spec_args_tmap, &fixups.undo_info);
213216
let (node, rev_tmap) = token_tree_to_syntax_node(&speculative_expansion.value, expand_to);
214217

215218
let range = rev_tmap.first_range_by_token(token_id, token_to_map.kind())?;
@@ -300,23 +303,28 @@ fn parse_macro_expansion(
300303
fn macro_arg(
301304
db: &dyn AstDatabase,
302305
id: MacroCallId,
303-
) -> Option<Arc<(tt::Subtree, mbe::TokenMap, fixup::SyntaxFixupMap)>> {
306+
) -> Option<Arc<(tt::Subtree, mbe::TokenMap, fixup::SyntaxFixupUndoInfo)>> {
304307
let arg = db.macro_arg_text(id)?;
305308
let loc = db.lookup_intern_macro_call(id);
306309

307310
let node = SyntaxNode::new_root(arg);
308311
let censor = censor_for_macro_input(&loc, &node);
309312
let mut fixups = fixup::fixup_syntax(&node);
310313
fixups.replace.extend(censor.into_iter().map(|node| (node, Vec::new())));
311-
let (mut tt, tmap) =
312-
mbe::syntax_node_to_token_tree_with_modifications(&node, fixups.replace, fixups.append);
314+
let (mut tt, tmap, _) = mbe::syntax_node_to_token_tree_with_modifications(
315+
&node,
316+
fixups.token_map,
317+
fixups.next_id,
318+
fixups.replace,
319+
fixups.append,
320+
);
313321

314322
if loc.def.is_proc_macro() {
315323
// proc macros expect their inputs without parentheses, MBEs expect it with them included
316324
tt.delimiter = None;
317325
}
318326

319-
Some(Arc::new((tt, tmap, fixups.map)))
327+
Some(Arc::new((tt, tmap, fixups.undo_info)))
320328
}
321329

322330
fn censor_for_macro_input(loc: &MacroCallLoc, node: &SyntaxNode) -> FxHashSet<SyntaxNode> {

crates/hir_expand/src/fixup.rs

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
//! To make attribute macros work reliably when typing, we need to take care to
2+
//! fix up syntax errors in the code we're passing to them.
3+
use std::mem;
4+
15
use mbe::{SyntheticToken, SyntheticTokenId, TokenMap};
26
use rustc_hash::FxHashMap;
37
use syntax::{
@@ -6,16 +10,22 @@ use syntax::{
610
};
711
use tt::Subtree;
812

13+
/// The result of calculating fixes for a syntax node -- a bunch of changes
14+
/// (appending to and replacing nodes), the information that is needed to
15+
/// reverse those changes afterwards, and a token map.
916
#[derive(Debug)]
1017
pub struct SyntaxFixups {
1118
pub append: FxHashMap<SyntaxNode, Vec<SyntheticToken>>,
1219
pub replace: FxHashMap<SyntaxNode, Vec<SyntheticToken>>,
13-
pub map: SyntaxFixupMap,
20+
pub undo_info: SyntaxFixupUndoInfo,
21+
pub token_map: TokenMap,
22+
pub next_id: u32,
1423
}
1524

25+
/// This is the information needed to reverse the fixups.
1626
#[derive(Debug, PartialEq, Eq)]
17-
pub struct SyntaxFixupMap {
18-
original: Vec<(Subtree, TokenMap)>,
27+
pub struct SyntaxFixupUndoInfo {
28+
original: Vec<Subtree>,
1929
}
2030

2131
const EMPTY_ID: SyntheticTokenId = SyntheticTokenId(!0);
@@ -25,15 +35,26 @@ pub fn fixup_syntax(node: &SyntaxNode) -> SyntaxFixups {
2535
let mut replace = FxHashMap::default();
2636
let mut preorder = node.preorder();
2737
let mut original = Vec::new();
38+
let mut token_map = TokenMap::default();
39+
let mut next_id = 0;
2840
while let Some(event) = preorder.next() {
2941
let node = match event {
3042
syntax::WalkEvent::Enter(node) => node,
3143
syntax::WalkEvent::Leave(_) => continue,
3244
};
45+
3346
if can_handle_error(&node) && has_error_to_handle(&node) {
3447
// the node contains an error node, we have to completely replace it by something valid
35-
let original_tree = mbe::syntax_node_to_token_tree(&node);
36-
// TODO handle token ids / token map
48+
let (original_tree, new_tmap, new_next_id) =
49+
mbe::syntax_node_to_token_tree_with_modifications(
50+
&node,
51+
mem::take(&mut token_map),
52+
next_id,
53+
Default::default(),
54+
Default::default(),
55+
);
56+
token_map = new_tmap;
57+
next_id = new_next_id;
3758
let idx = original.len() as u32;
3859
original.push(original_tree);
3960
let replacement = SyntheticToken {
@@ -46,6 +67,8 @@ pub fn fixup_syntax(node: &SyntaxNode) -> SyntaxFixups {
4667
preorder.skip_subtree();
4768
continue;
4869
}
70+
71+
// In some other situations, we can fix things by just appending some tokens.
4972
let end_range = TextRange::empty(node.text_range().end());
5073
match_ast! {
5174
match node {
@@ -78,7 +101,13 @@ pub fn fixup_syntax(node: &SyntaxNode) -> SyntaxFixups {
78101
}
79102
}
80103
}
81-
SyntaxFixups { append, replace, map: SyntaxFixupMap { original } }
104+
SyntaxFixups {
105+
append,
106+
replace,
107+
token_map,
108+
next_id,
109+
undo_info: SyntaxFixupUndoInfo { original },
110+
}
82111
}
83112

84113
fn has_error(node: &SyntaxNode) -> bool {
@@ -93,7 +122,7 @@ fn has_error_to_handle(node: &SyntaxNode) -> bool {
93122
has_error(node) || node.children().any(|c| !can_handle_error(&c) && has_error_to_handle(&c))
94123
}
95124

96-
pub fn reverse_fixups(tt: &mut Subtree, token_map: &TokenMap, fixup_map: &SyntaxFixupMap) {
125+
pub fn reverse_fixups(tt: &mut Subtree, token_map: &TokenMap, undo_info: &SyntaxFixupUndoInfo) {
97126
tt.token_trees.retain(|tt| match tt {
98127
tt::TokenTree::Leaf(leaf) => {
99128
token_map.synthetic_token_id(leaf.id()).is_none()
@@ -102,10 +131,10 @@ pub fn reverse_fixups(tt: &mut Subtree, token_map: &TokenMap, fixup_map: &Syntax
102131
_ => true,
103132
});
104133
tt.token_trees.iter_mut().for_each(|tt| match tt {
105-
tt::TokenTree::Subtree(tt) => reverse_fixups(tt, token_map, fixup_map),
134+
tt::TokenTree::Subtree(tt) => reverse_fixups(tt, token_map, undo_info),
106135
tt::TokenTree::Leaf(leaf) => {
107136
if let Some(id) = token_map.synthetic_token_id(leaf.id()) {
108-
let (original, _original_tmap) = &fixup_map.original[id.0 as usize];
137+
let original = &undo_info.original[id.0 as usize];
109138
*tt = tt::TokenTree::Subtree(original.clone());
110139
}
111140
}
@@ -123,8 +152,10 @@ mod tests {
123152
let parsed = syntax::SourceFile::parse(ra_fixture);
124153
eprintln!("parse: {:#?}", parsed.syntax_node());
125154
let fixups = super::fixup_syntax(&parsed.syntax_node());
126-
let (mut tt, tmap) = mbe::syntax_node_to_token_tree_with_modifications(
155+
let (mut tt, tmap, _) = mbe::syntax_node_to_token_tree_with_modifications(
127156
&parsed.syntax_node(),
157+
fixups.token_map,
158+
fixups.next_id,
128159
fixups.replace,
129160
fixups.append,
130161
);
@@ -144,7 +175,7 @@ mod tests {
144175
parse.syntax_node()
145176
);
146177

147-
reverse_fixups(&mut tt, &tmap, &fixups.map);
178+
reverse_fixups(&mut tt, &tmap, &fixups.undo_info);
148179

149180
// the fixed-up + reversed version should be equivalent to the original input
150181
// (but token IDs don't matter)

crates/hir_expand/src/hygiene.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ struct HygieneInfo {
128128
attr_input_or_mac_def_start: Option<InFile<TextSize>>,
129129

130130
macro_def: Arc<TokenExpander>,
131-
macro_arg: Arc<(tt::Subtree, mbe::TokenMap, fixup::SyntaxFixupMap)>,
131+
macro_arg: Arc<(tt::Subtree, mbe::TokenMap, fixup::SyntaxFixupUndoInfo)>,
132132
macro_arg_shift: mbe::Shift,
133133
exp_map: Arc<mbe::TokenMap>,
134134
}

crates/hir_expand/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,7 @@ pub struct ExpansionInfo {
427427
attr_input_or_mac_def: Option<InFile<ast::TokenTree>>,
428428

429429
macro_def: Arc<TokenExpander>,
430-
macro_arg: Arc<(tt::Subtree, mbe::TokenMap, fixup::SyntaxFixupMap)>,
430+
macro_arg: Arc<(tt::Subtree, mbe::TokenMap, fixup::SyntaxFixupUndoInfo)>,
431431
/// A shift built from `macro_arg`'s subtree, relevant for attributes as the item is the macro arg
432432
/// and as such we need to shift tokens if they are part of an attributes input instead of their item.
433433
macro_arg_shift: mbe::Shift,

crates/mbe/src/syntax_bridge.rs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,32 @@ use crate::{to_parser_input::to_parser_input, tt_iter::TtIter, TokenMap};
1515
/// Convert the syntax node to a `TokenTree` (what macro
1616
/// will consume).
1717
pub fn syntax_node_to_token_tree(node: &SyntaxNode) -> (tt::Subtree, TokenMap) {
18-
syntax_node_to_token_tree_with_modifications(node, Default::default(), Default::default())
18+
let (subtree, token_map, _) = syntax_node_to_token_tree_with_modifications(
19+
node,
20+
Default::default(),
21+
0,
22+
Default::default(),
23+
Default::default(),
24+
);
25+
(subtree, token_map)
1926
}
2027

2128
/// Convert the syntax node to a `TokenTree` (what macro will consume)
2229
/// with the censored range excluded.
2330
pub fn syntax_node_to_token_tree_with_modifications(
2431
node: &SyntaxNode,
32+
existing_token_map: TokenMap,
33+
next_id: u32,
2534
replace: FxHashMap<SyntaxNode, Vec<SyntheticToken>>,
2635
append: FxHashMap<SyntaxNode, Vec<SyntheticToken>>,
27-
) -> (tt::Subtree, TokenMap) {
36+
) -> (tt::Subtree, TokenMap, u32) {
2837
let global_offset = node.text_range().start();
29-
let mut c = Convertor::new(node, global_offset, replace, append);
38+
let mut c = Convertor::new(node, global_offset, existing_token_map, next_id, replace, append);
3039
let subtree = convert_tokens(&mut c);
3140
c.id_alloc.map.shrink_to_fit();
3241
always!(c.replace.is_empty(), "replace: {:?}", c.replace);
3342
always!(c.append.is_empty(), "append: {:?}", c.append);
34-
(subtree, c.id_alloc.map)
43+
(subtree, c.id_alloc.map, c.id_alloc.next_id)
3544
}
3645

3746
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
@@ -510,14 +519,16 @@ impl Convertor {
510519
fn new(
511520
node: &SyntaxNode,
512521
global_offset: TextSize,
522+
existing_token_map: TokenMap,
523+
next_id: u32,
513524
mut replace: FxHashMap<SyntaxNode, Vec<SyntheticToken>>,
514525
mut append: FxHashMap<SyntaxNode, Vec<SyntheticToken>>,
515526
) -> Convertor {
516527
let range = node.text_range();
517528
let mut preorder = node.preorder_with_tokens();
518529
let (first, synthetic) = Self::next_token(&mut preorder, &mut replace, &mut append);
519530
Convertor {
520-
id_alloc: { TokenIdAlloc { map: TokenMap::default(), global_offset, next_id: 0 } },
531+
id_alloc: { TokenIdAlloc { map: existing_token_map, global_offset, next_id } },
521532
current: first,
522533
current_synthetic: synthetic,
523534
preorder,

0 commit comments

Comments
 (0)