Skip to content

Commit c0e4026

Browse files
committed
Emit builtin#format_args in builtin format_args expander
1 parent 5fdd1e3 commit c0e4026

File tree

15 files changed

+146
-341
lines changed

15 files changed

+146
-341
lines changed

crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs

+23-16
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ macro_rules! format_args {
240240
}
241241
242242
fn main() {
243-
::core::fmt::Arguments::new_v1(&["", " ", ], &[::core::fmt::ArgumentV1::new(&(arg1(a, b, c)), ::core::fmt::Display::fmt), ::core::fmt::ArgumentV1::new(&(arg2), ::core::fmt::Debug::fmt), ]);
243+
builtin #format_args ("{} {:?}", arg1(a, b, c), arg2);
244244
}
245245
"##]],
246246
);
@@ -258,10 +258,10 @@ macro_rules! format_args {
258258
259259
fn main() {
260260
format_args!(x = 2);
261-
format_args!(x =);
262-
format_args!(x =, x = 2);
263-
format_args!("{}", x =);
264-
format_args!(=, "{}", x =);
261+
format_args!/*+errors*/(x =);
262+
format_args!/*+errors*/(x =, x = 2);
263+
format_args!/*+errors*/("{}", x =);
264+
format_args!/*+errors*/(=, "{}", x =);
265265
format_args!(x = 2, "{}", 5);
266266
}
267267
"#,
@@ -273,12 +273,19 @@ macro_rules! format_args {
273273
}
274274
275275
fn main() {
276-
/* error: no rule matches input tokens */;
277-
/* error: expected expression */;
278-
/* error: expected expression, expected COMMA */;
279-
/* error: expected expression */::core::fmt::Arguments::new_v1(&["", ], &[::core::fmt::ArgumentV1::new(&(), ::core::fmt::Display::fmt), ]);
280-
/* error: expected expression, expected R_PAREN */;
281-
::core::fmt::Arguments::new_v1(&["", ], &[::core::fmt::ArgumentV1::new(&(5), ::core::fmt::Display::fmt), ]);
276+
builtin #format_args (x = 2);
277+
/* parse error: expected expression */
278+
builtin #format_args (x = );
279+
/* parse error: expected expression */
280+
/* parse error: expected R_PAREN */
281+
/* parse error: expected expression, item or let statement */
282+
builtin #format_args (x = , x = 2);
283+
/* parse error: expected expression */
284+
builtin #format_args ("{}", x = );
285+
/* parse error: expected expression */
286+
/* parse error: expected expression */
287+
builtin #format_args ( = , "{}", x = );
288+
builtin #format_args (x = 2, "{}", 5);
282289
}
283290
"##]],
284291
);
@@ -306,7 +313,7 @@ macro_rules! format_args {
306313
}
307314
308315
fn main() {
309-
::core::fmt::Arguments::new_v1(&["", " ", ], &[::core::fmt::ArgumentV1::new(&(a::<A, B>()), ::core::fmt::Display::fmt), ::core::fmt::ArgumentV1::new(&(b), ::core::fmt::Debug::fmt), ]);
316+
builtin #format_args ("{} {:?}", a::<A, B>(), b);
310317
}
311318
"##]],
312319
);
@@ -339,7 +346,7 @@ macro_rules! format_args {
339346
}
340347
341348
fn main() {
342-
::core::fmt::Arguments::new_v1(&[r#""#, r#",mismatch,""#, r#"",""#, r#"""#, ], &[::core::fmt::ArgumentV1::new(&(location_csv_pat(db, &analysis, vfs, &sm, pat_id)), ::core::fmt::Display::fmt), ::core::fmt::ArgumentV1::new(&(mismatch.expected.display(db)), ::core::fmt::Display::fmt), ::core::fmt::ArgumentV1::new(&(mismatch.actual.display(db)), ::core::fmt::Display::fmt), ]);
349+
builtin #format_args (r#"{},mismatch,"{}","{}""#, location_csv_pat(db, &analysis, vfs, &sm, pat_id), mismatch.expected.display(db), mismatch.actual.display(db));
343350
}
344351
"##]],
345352
);
@@ -373,7 +380,7 @@ macro_rules! format_args {
373380
}
374381
375382
fn main() {
376-
::core::fmt::Arguments::new_v1(&["xxx", "y", "zzz", ], &[::core::fmt::ArgumentV1::new(&(2), ::core::fmt::Display::fmt), ::core::fmt::ArgumentV1::new(&(b), ::core::fmt::Debug::fmt), ]);
383+
builtin #format_args (concat!("xxx{}y", "{:?}zzz"), 2, b);
377384
}
378385
"##]],
379386
);
@@ -403,8 +410,8 @@ macro_rules! format_args {
403410
404411
fn main() {
405412
let _ =
406-
/* error: expected field name or number *//* parse error: expected field name or number */
407-
::core::fmt::Arguments::new_v1(&["", " ", ], &[::core::fmt::ArgumentV1::new(&(a.), ::core::fmt::Display::fmt), ::core::fmt::ArgumentV1::new(&(), ::core::fmt::Debug::fmt), ]);
413+
/* parse error: expected field name or number */
414+
builtin #format_args ("{} {:?}", a.);
408415
}
409416
"##]],
410417
);

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ fn main(foo: ()) {
117117
macro_rules! format_args {}
118118
119119
fn main(foo: ()) {
120-
/* error: unresolved macro identity */::core::fmt::Arguments::new_v1(&["", " ", " ", ], &[::core::fmt::ArgumentV1::new(&(::core::fmt::Arguments::new_v1(&["", ], &[::core::fmt::ArgumentV1::new(&(0), ::core::fmt::Display::fmt), ])), ::core::fmt::Display::fmt), ::core::fmt::ArgumentV1::new(&(foo), ::core::fmt::Display::fmt), ::core::fmt::ArgumentV1::new(&(identity!(10)), ::core::fmt::Display::fmt), ])
120+
builtin #format_args ("{} {} {}", format_args!("{}", 0), foo, identity!(10), "bar")
121121
}
122122
"##]],
123123
);
@@ -150,8 +150,8 @@ macro_rules! identity {
150150
}
151151
152152
fn main(foo: ()) {
153-
// format_args/*+tokenids*/!("{} {} {}"#1,#3 format_args!("{}", 0#10),#12 foo#13,#14 identity!(10#18),#21 "bar"#22)
154-
::core#4294967295::fmt#4294967295::Arguments#4294967295::new_v1#4294967295(&#4294967295[#4294967295""#4294967295,#4294967295 " "#4294967295,#4294967295 " "#4294967295,#4294967295 ]#4294967295,#4294967295 &#4294967295[::core#4294967295::fmt#4294967295::ArgumentV1#4294967295::new#4294967295(&#4294967295(::core#4294967295::fmt#4294967295::Arguments#4294967295::new_v1#4294967295(&#4294967295[#4294967295""#4294967295,#4294967295 ]#4294967295,#4294967295 &#4294967295[::core#4294967295::fmt#4294967295::ArgumentV1#4294967295::new#4294967295(&#4294967295(#42949672950#10)#4294967295,#4294967295 ::core#4294967295::fmt#4294967295::Display#4294967295::fmt#4294967295)#4294967295,#4294967295 ]#4294967295)#4294967295)#4294967295,#4294967295 ::core#4294967295::fmt#4294967295::Display#4294967295::fmt#4294967295)#4294967295,#4294967295 ::core#4294967295::fmt#4294967295::ArgumentV1#4294967295::new#4294967295(&#4294967295(#4294967295foo#13)#4294967295,#4294967295 ::core#4294967295::fmt#4294967295::Display#4294967295::fmt#4294967295)#4294967295,#4294967295 ::core#4294967295::fmt#4294967295::ArgumentV1#4294967295::new#4294967295(&#4294967295(#429496729510#18)#4294967295,#4294967295 ::core#4294967295::fmt#4294967295::Display#4294967295::fmt#4294967295)#4294967295,#4294967295 ]#4294967295)#4294967295
153+
// format_args/*+tokenids*/!("{} {} {}"#1,#2 format_args#3!#4("{}"#6,#7 0#8),#9 foo#10,#11 identity#12!#13(10#15),#16 "bar"#17)
154+
builtin#4294967295 ##4294967295format_args#4294967295 (#0"{} {} {}"#1,#2 format_args#3!#4(#5"{}"#6,#7 0#8)#5,#9 foo#10,#11 identity#12!#13(#1410#15)#14,#16 "bar"#17)#0
155155
}
156156
157157
"##]],

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

+4-8
Original file line numberDiff line numberDiff line change
@@ -929,8 +929,8 @@ fn main() {
929929
macro_rules! format_args {}
930930
931931
fn main() {
932-
/* error: expected field name or number *//* parse error: expected field name or number */
933-
::core::fmt::Arguments::new_v1(&["", ], &[::core::fmt::ArgumentV1::new(&(line.1.), ::core::fmt::Display::fmt), ]);
932+
/* parse error: expected field name or number */
933+
builtin #format_args ("{}", line.1.);
934934
}
935935
936936
"##]],
@@ -956,19 +956,15 @@ fn main() {
956956
macro_rules! format_args {}
957957
958958
fn main() {
959-
/* error: expected COMMA, expected R_BRACK, expected COMMA, expected COMMA, expected expression, expected R_PAREN *//* parse error: expected COMMA */
959+
/* parse error: expected COMMA */
960960
/* parse error: expected R_BRACK */
961961
/* parse error: expected COMMA */
962962
/* parse error: expected COMMA */
963963
/* parse error: expected expression */
964964
/* parse error: expected R_PAREN */
965-
/* parse error: expected R_PAREN */
966-
/* parse error: expected expression, item or let statement */
967-
/* parse error: expected expression, item or let statement */
968-
/* parse error: expected expression, item or let statement */
969965
/* parse error: expected expression, item or let statement */
970966
/* parse error: expected expression, item or let statement */
971-
::core::fmt::Arguments::new_v1(&["", ], &[::core::fmt::ArgumentV1::new(&(&[0 2]), ::core::fmt::Display::fmt), ]);
967+
builtin #format_args ("{}", &[0 2]);
972968
}
973969
974970
"##]],

crates/hir-expand/src/builtin_fn_macro.rs

+9-151
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
11
//! Builtin macro
22
3-
use std::mem;
4-
5-
use ::tt::Ident;
63
use base_db::{AnchoredPath, Edition, FileId};
74
use cfg::CfgExpr;
85
use either::Either;
96
use mbe::{parse_exprs_with_sep, parse_to_token_tree, TokenMap};
10-
use rustc_hash::FxHashMap;
117
use syntax::{
128
ast::{self, AstToken},
139
SmolStr,
@@ -97,11 +93,11 @@ register_builtin! {
9793
(unreachable, Unreachable) => unreachable_expand,
9894
(log_syntax, LogSyntax) => log_syntax_expand,
9995
(trace_macros, TraceMacros) => trace_macros_expand,
100-
101-
EAGER:
10296
(format_args, FormatArgs) => format_args_expand,
10397
(const_format_args, ConstFormatArgs) => format_args_expand,
10498
(format_args_nl, FormatArgsNl) => format_args_nl_expand,
99+
100+
EAGER:
105101
(compile_error, CompileError) => compile_error_expand,
106102
(concat, Concat) => concat_expand,
107103
(concat_idents, ConcatIdents) => concat_idents_expand,
@@ -247,160 +243,22 @@ fn format_args_expand_general(
247243
_db: &dyn ExpandDatabase,
248244
_id: MacroCallId,
249245
tt: &tt::Subtree,
250-
end_string: &str,
246+
// FIXME: Make use of this so that mir interpretation works properly
247+
_end_string: &str,
251248
) -> ExpandResult<tt::Subtree> {
252-
let args = parse_exprs_with_sep(tt, ',');
253-
254-
let expand_error =
255-
ExpandResult::new(tt::Subtree::empty(), mbe::ExpandError::NoMatchingRule.into());
256-
257-
let mut key_args = FxHashMap::default();
258-
let mut args = args.into_iter().filter_map(|mut arg| {
259-
// Remove `key =`.
260-
if matches!(arg.token_trees.get(1), Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p))) if p.char == '=')
261-
{
262-
// but not with `==`
263-
if !matches!(arg.token_trees.get(2), Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p))) if p.char == '=')
264-
{
265-
let key = arg.token_trees.drain(..2).next().unwrap();
266-
key_args.insert(key.to_string(), arg);
267-
return None;
268-
}
269-
}
270-
Some(arg)
271-
}).collect::<Vec<_>>().into_iter();
272-
// ^^^^^^^ we need this collect, to enforce the side effect of the filter_map closure (building the `key_args`)
273-
let Some(format_subtree) = args.next() else {
274-
return expand_error;
275-
};
276-
let format_string = (|| {
277-
let token_tree = format_subtree.token_trees.get(0)?;
278-
match token_tree {
279-
tt::TokenTree::Leaf(l) => match l {
280-
tt::Leaf::Literal(l) => {
281-
if let Some(mut text) = l.text.strip_prefix('r') {
282-
let mut raw_sharps = String::new();
283-
while let Some(t) = text.strip_prefix('#') {
284-
text = t;
285-
raw_sharps.push('#');
286-
}
287-
text =
288-
text.strip_suffix(&raw_sharps)?.strip_prefix('"')?.strip_suffix('"')?;
289-
Some((text, l.span, Some(raw_sharps)))
290-
} else {
291-
let text = l.text.strip_prefix('"')?.strip_suffix('"')?;
292-
let span = l.span;
293-
Some((text, span, None))
294-
}
295-
}
296-
_ => None,
297-
},
298-
tt::TokenTree::Subtree(_) => None,
299-
}
300-
})();
301-
let Some((format_string, _format_string_span, raw_sharps)) = format_string else {
302-
return expand_error;
303-
};
304-
let mut format_iter = format_string.chars().peekable();
305-
let mut parts = vec![];
306-
let mut last_part = String::new();
307-
let mut arg_tts = vec![];
308-
let mut err = None;
309-
while let Some(c) = format_iter.next() {
310-
// Parsing the format string. See https://doc.rust-lang.org/std/fmt/index.html#syntax for the grammar and more info
311-
match c {
312-
'{' => {
313-
if format_iter.peek() == Some(&'{') {
314-
format_iter.next();
315-
last_part.push('{');
316-
continue;
317-
}
318-
let mut argument = String::new();
319-
while ![Some(&'}'), Some(&':')].contains(&format_iter.peek()) {
320-
argument.push(match format_iter.next() {
321-
Some(c) => c,
322-
None => return expand_error,
323-
});
324-
}
325-
let format_spec = match format_iter.next().unwrap() {
326-
'}' => "".to_owned(),
327-
':' => {
328-
let mut s = String::new();
329-
while let Some(c) = format_iter.next() {
330-
if c == '}' {
331-
break;
332-
}
333-
s.push(c);
334-
}
335-
s
336-
}
337-
_ => unreachable!(),
338-
};
339-
parts.push(mem::take(&mut last_part));
340-
let arg_tree = if argument.is_empty() {
341-
match args.next() {
342-
Some(it) => it,
343-
None => {
344-
err = Some(mbe::ExpandError::NoMatchingRule.into());
345-
tt::Subtree::empty()
346-
}
347-
}
348-
} else if let Some(tree) = key_args.get(&argument) {
349-
tree.clone()
350-
} else {
351-
// FIXME: we should pick the related substring of the `_format_string_span` as the span. You
352-
// can use `.char_indices()` instead of `.char()` for `format_iter` to find the substring interval.
353-
let ident = Ident::new(argument, tt::TokenId::unspecified());
354-
quote!(#ident)
355-
};
356-
let formatter = match &*format_spec {
357-
"?" => quote!(::core::fmt::Debug::fmt),
358-
"" => quote!(::core::fmt::Display::fmt),
359-
_ => {
360-
// FIXME: implement the rest and return expand error here
361-
quote!(::core::fmt::Display::fmt)
362-
}
363-
};
364-
arg_tts.push(quote! { ::core::fmt::ArgumentV1::new(&(#arg_tree), #formatter), });
365-
}
366-
'}' => {
367-
if format_iter.peek() == Some(&'}') {
368-
format_iter.next();
369-
last_part.push('}');
370-
} else {
371-
return expand_error;
372-
}
373-
}
374-
_ => last_part.push(c),
375-
}
376-
}
377-
last_part += end_string;
378-
if !last_part.is_empty() {
379-
parts.push(last_part);
380-
}
381-
let part_tts = parts.into_iter().map(|it| {
382-
let text = if let Some(raw) = &raw_sharps {
383-
format!("r{raw}\"{}\"{raw}", it).into()
384-
} else {
385-
format!("\"{}\"", it).into()
386-
};
387-
let l = tt::Literal { span: tt::TokenId::unspecified(), text };
388-
quote!(#l ,)
249+
let pound = quote! {@PUNCT '#'};
250+
let mut tt = tt.clone();
251+
tt.delimiter.kind = tt::DelimiterKind::Parenthesis;
252+
return ExpandResult::ok(quote! {
253+
builtin #pound format_args #tt
389254
});
390-
let arg_tts = arg_tts.into_iter().flat_map(|arg| arg.token_trees);
391-
let expanded = quote! {
392-
::core::fmt::Arguments::new_v1(&[##part_tts], &[##arg_tts])
393-
};
394-
ExpandResult { value: expanded, err }
395255
}
396256

397257
fn asm_expand(
398258
_db: &dyn ExpandDatabase,
399259
_id: MacroCallId,
400260
tt: &tt::Subtree,
401261
) -> ExpandResult<tt::Subtree> {
402-
// FIXME: parse asm here
403-
404262
// We expand all assembly snippets to `format_args!` invocations to get format syntax
405263
// highlighting for them.
406264

0 commit comments

Comments
 (0)