Skip to content

Commit 8753ca5

Browse files
committed
fix: Update metavariable expression implementation
1 parent 002e611 commit 8753ca5

File tree

7 files changed

+83
-65
lines changed

7 files changed

+83
-65
lines changed

crates/hir-def/src/macro_expansion_tests/mbe/meta_syntax.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ macro_rules! m {
1818
($($false:ident)*) => ($false);
1919
(double_dollar) => ($$);
2020
($) => (m!($););
21-
($($t:tt)*) => ($( ${ignore(t)} ${index()} )-*);
21+
($($t:tt)*) => ($( ${ignore($t)} ${index()} )-*);
2222
}
2323
m!($);
2424
"#,
@@ -33,7 +33,7 @@ macro_rules! m {
3333
($($false:ident)*) => ($false);
3434
(double_dollar) => ($$);
3535
($) => (m!($););
36-
($($t:tt)*) => ($( ${ignore(t)} ${index()} )-*);
36+
($($t:tt)*) => ($( ${ignore($t)} ${index()} )-*);
3737
}
3838
m!($);
3939
"#]],

crates/hir-def/src/macro_expansion_tests/mbe/metavar_expr.rs

+40-38
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,13 @@ fn test_metavar_exprs() {
7777
check(
7878
r#"
7979
macro_rules! m {
80-
( $( $t:tt )* ) => ( $( ${ignore(t)} -${index()} )-* );
80+
( $( $t:tt )* ) => ( $( ${ignore($t)} -${index()} )-* );
8181
}
8282
const _: i32 = m!(a b c);
8383
"#,
8484
expect![[r#"
8585
macro_rules! m {
86-
( $( $t:tt )* ) => ( $( ${ignore(t)} -${index()} )-* );
86+
( $( $t:tt )* ) => ( $( ${ignore($t)} -${index()} )-* );
8787
}
8888
const _: i32 = -0--1--2;
8989
"#]],
@@ -96,7 +96,7 @@ fn count_basic() {
9696
r#"
9797
macro_rules! m {
9898
($($t:ident),*) => {
99-
${count(t)}
99+
${count($t)}
100100
}
101101
}
102102
@@ -109,7 +109,7 @@ fn test() {
109109
expect![[r#"
110110
macro_rules! m {
111111
($($t:ident),*) => {
112-
${count(t)}
112+
${count($t)}
113113
}
114114
}
115115
@@ -130,9 +130,9 @@ macro_rules! foo {
130130
($( $( $($t:ident)* ),* );*) => {
131131
$(
132132
{
133-
let depth_none = ${count(t)};
134-
let depth_zero = ${count(t, 0)};
135-
let depth_one = ${count(t, 1)};
133+
let depth_none = ${count($t)};
134+
let depth_zero = ${count($t, 0)};
135+
let depth_one = ${count($t, 1)};
136136
}
137137
)*
138138
}
@@ -150,21 +150,21 @@ macro_rules! foo {
150150
($( $( $($t:ident)* ),* );*) => {
151151
$(
152152
{
153-
let depth_none = ${count(t)};
154-
let depth_zero = ${count(t, 0)};
155-
let depth_one = ${count(t, 1)};
153+
let depth_none = ${count($t)};
154+
let depth_zero = ${count($t, 0)};
155+
let depth_one = ${count($t, 1)};
156156
}
157157
)*
158158
}
159159
}
160160
161161
fn bar() {
162162
{
163-
let depth_none = 6;
163+
let depth_none = 3;
164164
let depth_zero = 3;
165165
let depth_one = 6;
166166
} {
167-
let depth_none = 3;
167+
let depth_none = 1;
168168
let depth_zero = 1;
169169
let depth_one = 3;
170170
}
@@ -178,12 +178,12 @@ fn count_depth_out_of_bounds() {
178178
check(
179179
r#"
180180
macro_rules! foo {
181-
($($t:ident)*) => { ${count(t, 1)} };
182-
($( $( $l:literal )* );*) => { $(${count(l, 1)};)* }
181+
($($t:ident)*) => { ${count($t, 1)} };
182+
($( $( $l:literal )* );*) => { $(${count($l, 1)};)* }
183183
}
184184
macro_rules! bar {
185-
($($t:ident)*) => { ${count(t, 1024)} };
186-
($( $( $l:literal )* );*) => { $(${count(l, 8192)};)* }
185+
($($t:ident)*) => { ${count($t, 1024)} };
186+
($( $( $l:literal )* );*) => { $(${count($l, 8192)};)* }
187187
}
188188
189189
fn test() {
@@ -195,19 +195,21 @@ fn test() {
195195
"#,
196196
expect![[r#"
197197
macro_rules! foo {
198-
($($t:ident)*) => { ${count(t, 1)} };
199-
($( $( $l:literal )* );*) => { $(${count(l, 1)};)* }
198+
($($t:ident)*) => { ${count($t, 1)} };
199+
($( $( $l:literal )* );*) => { $(${count($l, 1)};)* }
200200
}
201201
macro_rules! bar {
202-
($($t:ident)*) => { ${count(t, 1024)} };
203-
($( $( $l:literal )* );*) => { $(${count(l, 8192)};)* }
202+
($($t:ident)*) => { ${count($t, 1024)} };
203+
($( $( $l:literal )* );*) => { $(${count($l, 8192)};)* }
204204
}
205205
206206
fn test() {
207-
/* error: ${count} out of bounds */;
208-
/* error: ${count} out of bounds */;
209-
/* error: ${count} out of bounds */;
210-
/* error: ${count} out of bounds */;
207+
2;
208+
2;
209+
1;;
210+
2;
211+
2;
212+
1;;
211213
}
212214
"#]],
213215
);
@@ -218,8 +220,8 @@ fn misplaced_count() {
218220
check(
219221
r#"
220222
macro_rules! foo {
221-
($($t:ident)*) => { $(${count(t)})* };
222-
($l:literal) => { ${count(l)} }
223+
($($t:ident)*) => { $(${count($t)})* };
224+
($l:literal) => { ${count($l)} }
223225
}
224226
225227
fn test() {
@@ -229,13 +231,13 @@ fn test() {
229231
"#,
230232
expect![[r#"
231233
macro_rules! foo {
232-
($($t:ident)*) => { $(${count(t)})* };
233-
($l:literal) => { ${count(l)} }
234+
($($t:ident)*) => { $(${count($t)})* };
235+
($l:literal) => { ${count($l)} }
234236
}
235237
236238
fn test() {
237-
/* error: ${count} misplaced */;
238-
/* error: ${count} misplaced */;
239+
1 1 1;
240+
1;
239241
}
240242
"#]],
241243
);
@@ -246,13 +248,13 @@ fn malformed_count() {
246248
check(
247249
r#"
248250
macro_rules! too_many_args {
249-
($($t:ident)*) => { ${count(t, 1, leftover)} }
251+
($($t:ident)*) => { ${count($t, 1, leftover)} }
250252
}
251253
macro_rules! depth_suffixed {
252-
($($t:ident)*) => { ${count(t, 0usize)} }
254+
($($t:ident)*) => { ${count($t, 0usize)} }
253255
}
254256
macro_rules! depth_too_large {
255-
($($t:ident)*) => { ${count(t, 18446744073709551616)} }
257+
($($t:ident)*) => { ${count($t, 18446744073709551616)} }
256258
}
257259
258260
fn test() {
@@ -263,13 +265,13 @@ fn test() {
263265
"#,
264266
expect![[r#"
265267
macro_rules! too_many_args {
266-
($($t:ident)*) => { ${count(t, 1, leftover)} }
268+
($($t:ident)*) => { ${count($t, 1, leftover)} }
267269
}
268270
macro_rules! depth_suffixed {
269-
($($t:ident)*) => { ${count(t, 0usize)} }
271+
($($t:ident)*) => { ${count($t, 0usize)} }
270272
}
271273
macro_rules! depth_too_large {
272-
($($t:ident)*) => { ${count(t, 18446744073709551616)} }
274+
($($t:ident)*) => { ${count($t, 18446744073709551616)} }
273275
}
274276
275277
fn test() {
@@ -288,7 +290,7 @@ fn count_interaction_with_empty_binding() {
288290
r#"
289291
macro_rules! m {
290292
($($t:ident),*) => {
291-
${count(t, 100)}
293+
${count($t, 100)}
292294
}
293295
}
294296
@@ -299,7 +301,7 @@ fn test() {
299301
expect![[r#"
300302
macro_rules! m {
301303
($($t:ident),*) => {
302-
${count(t, 100)}
304+
${count($t, 100)}
303305
}
304306
}
305307

crates/mbe/src/benchmark.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ fn invocation_fixtures(
199199
});
200200
parent.token_trees.push(subtree.into());
201201
}
202-
Op::Ignore { .. } | Op::Index { .. } | Op::Count { .. } => {}
202+
Op::Ignore { .. } | Op::Index { .. } | Op::Count { .. } | Op::Length { .. } => {}
203203
};
204204

205205
// Simple linear congruential generator for deterministic result

crates/mbe/src/expander/matcher.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -588,7 +588,9 @@ fn match_loop_inner<'t, S: Span>(
588588
item.is_error = true;
589589
error_items.push(item);
590590
}
591-
OpDelimited::Op(Op::Ignore { .. } | Op::Index { .. } | Op::Count { .. }) => {
591+
OpDelimited::Op(
592+
Op::Ignore { .. } | Op::Index { .. } | Op::Count { .. } | Op::Length { .. },
593+
) => {
592594
stdx::never!("metavariable expression in lhs found");
593595
}
594596
OpDelimited::Open => {
@@ -851,7 +853,7 @@ fn collect_vars<S: Span>(collector_fun: &mut impl FnMut(SmolStr), pattern: &Meta
851853
Op::Subtree { tokens, .. } => collect_vars(collector_fun, tokens),
852854
Op::Repeat { tokens, .. } => collect_vars(collector_fun, tokens),
853855
Op::Literal(_) | Op::Ident(_) | Op::Punct(_) => {}
854-
Op::Ignore { .. } | Op::Index { .. } | Op::Count { .. } => {
856+
Op::Ignore { .. } | Op::Index { .. } | Op::Count { .. } | Op::Length { .. } => {
855857
stdx::never!("metavariable expression in lhs found");
856858
}
857859
}

crates/mbe/src/expander/transcriber.rs

+23-18
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,21 @@ fn expand_subtree<S: Span>(
232232
.into(),
233233
);
234234
}
235+
Op::Length { depth } => {
236+
let length = ctx.nesting.get(ctx.nesting.len() - 1 - depth).map_or(0, |_nest| {
237+
// FIXME: to be implemented
238+
0
239+
});
240+
arena.push(
241+
tt::Leaf::Literal(tt::Literal {
242+
text: length.to_string().into(),
243+
// FIXME
244+
#[allow(deprecated)]
245+
span: S::DUMMY,
246+
})
247+
.into(),
248+
);
249+
}
235250
Op::Count { name, depth } => {
236251
let mut binding = match ctx.bindings.get(name.as_str()) {
237252
Ok(b) => b,
@@ -518,28 +533,18 @@ fn fix_up_and_push_path_tt<S: Span>(buf: &mut Vec<tt::TokenTree<S>>, subtree: tt
518533
fn count<S>(
519534
ctx: &ExpandCtx<'_, S>,
520535
binding: &Binding<S>,
521-
our_depth: usize,
522-
count_depth: Option<usize>,
536+
depth_curr: usize,
537+
depth_max: usize,
523538
) -> Result<usize, CountError> {
524539
match binding {
525-
Binding::Nested(bs) => match count_depth {
526-
None => bs.iter().map(|b| count(ctx, b, our_depth + 1, None)).sum(),
527-
Some(0) => Ok(bs.len()),
528-
Some(d) => bs.iter().map(|b| count(ctx, b, our_depth + 1, Some(d - 1))).sum(),
529-
},
530-
Binding::Empty => Ok(0),
531-
Binding::Fragment(_) | Binding::Missing(_) => {
532-
if our_depth == 0 {
533-
// `${count(t)}` is placed inside the innermost repetition. This includes cases
534-
// where `t` is not a repeated fragment.
535-
Err(CountError::Misplaced)
536-
} else if count_depth.is_none() {
537-
Ok(1)
540+
Binding::Nested(bs) => {
541+
if depth_curr == depth_max {
542+
Ok(bs.len())
538543
} else {
539-
// We've reached at the innermost repeated fragment, but the user wants us to go
540-
// further!
541-
Err(CountError::OutOfBounds)
544+
bs.iter().map(|b| count(ctx, b, depth_curr + 1, depth_max)).sum()
542545
}
543546
}
547+
Binding::Empty => Ok(0),
548+
Binding::Fragment(_) | Binding::Missing(_) => Ok(1),
544549
}
545550
}

crates/mbe/src/parser.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ pub(crate) enum Op<S> {
5454
Var { name: SmolStr, kind: Option<MetaVarKind>, id: S },
5555
Ignore { name: SmolStr, id: S },
5656
Index { depth: usize },
57-
Count { name: SmolStr, depth: Option<usize> },
57+
Length { depth: usize },
58+
Count { name: SmolStr, depth: usize },
5859
Repeat { tokens: MetaTemplate<S>, kind: RepeatKind, separator: Option<Separator<S>> },
5960
Subtree { tokens: MetaTemplate<S>, delimiter: tt::Delimiter<S> },
6061
Literal(tt::Literal<S>),
@@ -299,15 +300,16 @@ fn parse_metavar_expr<S: Span>(src: &mut TtIter<'_, S>) -> Result<Op<S>, ()> {
299300

300301
let op = match &*func.text {
301302
"ignore" => {
303+
args.expect_dollar()?;
302304
let ident = args.expect_ident()?;
303305
Op::Ignore { name: ident.text.clone(), id: ident.span }
304306
}
305307
"index" => Op::Index { depth: parse_depth(&mut args)? },
308+
"length" => Op::Length { depth: parse_depth(&mut args)? },
306309
"count" => {
310+
args.expect_dollar()?;
307311
let ident = args.expect_ident()?;
308-
// `${count(t)}` and `${count(t,)}` have different meanings. Not sure if this is a bug
309-
// but that's how it's implemented in rustc as of this writing. See rust-lang/rust#111904.
310-
let depth = if try_eat_comma(&mut args) { Some(parse_depth(&mut args)?) } else { None };
312+
let depth = if try_eat_comma(&mut args) { parse_depth(&mut args)? } else { 0 };
311313
Op::Count { name: ident.text.clone(), depth }
312314
}
313315
_ => return Err(()),

crates/mbe/src/tt_iter.rs

+7
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,13 @@ impl<'a, S: Span> TtIter<'a, S> {
5151
}
5252
}
5353

54+
pub(crate) fn expect_dollar(&mut self) -> Result<(), ()> {
55+
match self.expect_leaf()? {
56+
tt::Leaf::Punct(tt::Punct { char: '$', .. }) => Ok(()),
57+
_ => Err(()),
58+
}
59+
}
60+
5461
pub(crate) fn expect_ident(&mut self) -> Result<&'a tt::Ident<S>, ()> {
5562
match self.expect_leaf()? {
5663
tt::Leaf::Ident(it) if it.text != "_" => Ok(it),

0 commit comments

Comments
 (0)