Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 84dd5e0

Browse files
committedSep 6, 2023
Emit builtin#format_args in builtin format_args expander
1 parent 5fdd1e3 commit 84dd5e0

File tree

15 files changed

+144
-336
lines changed

15 files changed

+144
-336
lines changed
 

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

Lines changed: 23 additions & 16 deletions
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‎

Lines changed: 3 additions & 3 deletions
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‎

Lines changed: 4 additions & 8 deletions
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‎

Lines changed: 7 additions & 146 deletions
Original file line numberDiff line numberDiff line change
@@ -97,11 +97,11 @@ register_builtin! {
9797
(unreachable, Unreachable) => unreachable_expand,
9898
(log_syntax, LogSyntax) => log_syntax_expand,
9999
(trace_macros, TraceMacros) => trace_macros_expand,
100-
101-
EAGER:
102100
(format_args, FormatArgs) => format_args_expand,
103101
(const_format_args, ConstFormatArgs) => format_args_expand,
104102
(format_args_nl, FormatArgsNl) => format_args_nl_expand,
103+
104+
EAGER:
105105
(compile_error, CompileError) => compile_error_expand,
106106
(concat, Concat) => concat_expand,
107107
(concat_idents, ConcatIdents) => concat_idents_expand,
@@ -249,158 +249,19 @@ fn format_args_expand_general(
249249
tt: &tt::Subtree,
250250
end_string: &str,
251251
) -> 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 ,)
252+
let pound = quote! {@PUNCT '#'};
253+
let mut tt = tt.clone();
254+
tt.delimiter.kind = tt::DelimiterKind::Parenthesis;
255+
return ExpandResult::ok(quote! {
256+
builtin #pound format_args #tt
389257
});
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 }
395258
}
396259

397260
fn asm_expand(
398261
_db: &dyn ExpandDatabase,
399262
_id: MacroCallId,
400263
tt: &tt::Subtree,
401264
) -> ExpandResult<tt::Subtree> {
402-
// FIXME: parse asm here
403-
404265
// We expand all assembly snippets to `format_args!` invocations to get format syntax
405266
// highlighting for them.
406267

‎crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs‎

Lines changed: 28 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -15,26 +15,13 @@ use syntax::{ast, AstNode, AstToken, NodeOrToken, SyntaxKind::COMMA, TextRange};
1515
// Move an expression out of a format string.
1616
//
1717
// ```
18-
// macro_rules! format_args {
19-
// ($lit:literal $(tt:tt)*) => { 0 },
20-
// }
21-
// macro_rules! print {
22-
// ($($arg:tt)*) => (std::io::_print(format_args!($($arg)*)));
23-
// }
24-
//
18+
// # //- minicore: fmt
2519
// fn main() {
2620
// print!("{var} {x + 1}$0");
2721
// }
2822
// ```
2923
// ->
3024
// ```
31-
// macro_rules! format_args {
32-
// ($lit:literal $(tt:tt)*) => { 0 },
33-
// }
34-
// macro_rules! print {
35-
// ($($arg:tt)*) => (std::io::_print(format_args!($($arg)*)));
36-
// }
37-
//
3825
// fn main() {
3926
// print!("{var} {}"$0, x + 1);
4027
// }
@@ -47,17 +34,23 @@ pub(crate) fn extract_expressions_from_format_string(
4734
let fmt_string = ctx.find_token_at_offset::<ast::String>()?;
4835
let tt = fmt_string.syntax().parent().and_then(ast::TokenTree::cast)?;
4936

37+
dbg!();
5038
let expanded_t = ast::String::cast(
5139
ctx.sema.descend_into_macros_with_kind_preference(fmt_string.syntax().clone(), 0.into()),
5240
)?;
41+
dbg!();
5342
if !is_format_string(&expanded_t) {
43+
dbg!();
5444
return None;
5545
}
5646

47+
dbg!();
5748
let (new_fmt, extracted_args) = parse_format_exprs(fmt_string.text()).ok()?;
49+
dbg!();
5850
if extracted_args.is_empty() {
5951
return None;
6052
}
53+
dbg!();
6154

6255
acc.add(
6356
AssistId(
@@ -158,165 +151,131 @@ mod tests {
158151
use super::*;
159152
use crate::tests::check_assist;
160153

161-
const MACRO_DECL: &'static str = r#"
162-
macro_rules! format_args {
163-
($lit:literal $(tt:tt)*) => { 0 },
164-
}
165-
macro_rules! print {
166-
($($arg:tt)*) => (std::io::_print(format_args!($($arg)*)));
167-
}
168-
"#;
169-
170-
fn add_macro_decl(s: &'static str) -> String {
171-
MACRO_DECL.to_string() + s
172-
}
173-
174154
#[test]
175155
fn multiple_middle_arg() {
176156
check_assist(
177157
extract_expressions_from_format_string,
178-
&add_macro_decl(
179-
r#"
158+
r#"
159+
//- minicore: fmt
180160
fn main() {
181161
print!("{} {x + 1:b} {}$0", y + 2, 2);
182162
}
183163
"#,
184-
),
185-
&add_macro_decl(
186-
r#"
164+
r#"
187165
fn main() {
188166
print!("{} {:b} {}"$0, y + 2, x + 1, 2);
189167
}
190168
"#,
191-
),
192169
);
193170
}
194171

195172
#[test]
196173
fn single_arg() {
197174
check_assist(
198175
extract_expressions_from_format_string,
199-
&add_macro_decl(
200-
r#"
176+
r#"
177+
//- minicore: fmt
201178
fn main() {
202179
print!("{obj.value:b}$0",);
203180
}
204181
"#,
205-
),
206-
&add_macro_decl(
207-
r#"
182+
r#"
208183
fn main() {
209184
print!("{:b}"$0, obj.value);
210185
}
211186
"#,
212-
),
213187
);
214188
}
215189

216190
#[test]
217191
fn multiple_middle_placeholders_arg() {
218192
check_assist(
219193
extract_expressions_from_format_string,
220-
&add_macro_decl(
221-
r#"
194+
r#"
195+
//- minicore: fmt
222196
fn main() {
223197
print!("{} {x + 1:b} {} {}$0", y + 2, 2);
224198
}
225199
"#,
226-
),
227-
&add_macro_decl(
228-
r#"
200+
r#"
229201
fn main() {
230202
print!("{} {:b} {} {}"$0, y + 2, x + 1, 2, $1);
231203
}
232204
"#,
233-
),
234205
);
235206
}
236207

237208
#[test]
238209
fn multiple_trailing_args() {
239210
check_assist(
240211
extract_expressions_from_format_string,
241-
&add_macro_decl(
242-
r#"
212+
r#"
213+
//- minicore: fmt
243214
fn main() {
244215
print!("{:b} {x + 1:b} {Struct(1, 2)}$0", 1);
245216
}
246217
"#,
247-
),
248-
&add_macro_decl(
249-
r#"
218+
r#"
250219
fn main() {
251220
print!("{:b} {:b} {}"$0, 1, x + 1, Struct(1, 2));
252221
}
253222
"#,
254-
),
255223
);
256224
}
257225

258226
#[test]
259227
fn improper_commas() {
260228
check_assist(
261229
extract_expressions_from_format_string,
262-
&add_macro_decl(
263-
r#"
230+
r#"
231+
//- minicore: fmt
264232
fn main() {
265233
print!("{} {x + 1:b} {Struct(1, 2)}$0", 1,);
266234
}
267235
"#,
268-
),
269-
&add_macro_decl(
270-
r#"
236+
r#"
271237
fn main() {
272238
print!("{} {:b} {}"$0, 1, x + 1, Struct(1, 2));
273239
}
274240
"#,
275-
),
276241
);
277242
}
278243

279244
#[test]
280245
fn nested_tt() {
281246
check_assist(
282247
extract_expressions_from_format_string,
283-
&add_macro_decl(
284-
r#"
248+
r#"
249+
//- minicore: fmt
285250
fn main() {
286251
print!("My name is {} {x$0 + x}", stringify!(Paperino))
287252
}
288253
"#,
289-
),
290-
&add_macro_decl(
291-
r#"
254+
r#"
292255
fn main() {
293256
print!("My name is {} {}"$0, stringify!(Paperino), x + x)
294257
}
295258
"#,
296-
),
297259
);
298260
}
299261

300262
#[test]
301263
fn extract_only_expressions() {
302264
check_assist(
303265
extract_expressions_from_format_string,
304-
&add_macro_decl(
305-
r#"
266+
r#"
267+
//- minicore: fmt
306268
fn main() {
307269
let var = 1 + 1;
308270
print!("foobar {var} {var:?} {x$0 + x}")
309271
}
310272
"#,
311-
),
312-
&add_macro_decl(
313-
r#"
273+
r#"
314274
fn main() {
315275
let var = 1 + 1;
316276
print!("foobar {var} {var:?} {}"$0, x + x)
317277
}
318278
"#,
319-
),
320279
);
321280
}
322281
}

‎crates/ide-assists/src/tests/generated.rs‎

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -694,25 +694,12 @@ fn doctest_extract_expressions_from_format_string() {
694694
check_doc_test(
695695
"extract_expressions_from_format_string",
696696
r#####"
697-
macro_rules! format_args {
698-
($lit:literal $(tt:tt)*) => { 0 },
699-
}
700-
macro_rules! print {
701-
($($arg:tt)*) => (std::io::_print(format_args!($($arg)*)));
702-
}
703-
697+
//- minicore: fmt
704698
fn main() {
705699
print!("{var} {x + 1}$0");
706700
}
707701
"#####,
708702
r#####"
709-
macro_rules! format_args {
710-
($lit:literal $(tt:tt)*) => { 0 },
711-
}
712-
macro_rules! print {
713-
($($arg:tt)*) => (std::io::_print(format_args!($($arg)*)));
714-
}
715-
716703
fn main() {
717704
print!("{var} {}"$0, x + 1);
718705
}

‎crates/ide-completion/src/completions/format_string.rs‎

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,7 @@ mod tests {
5151
fn works_when_wrapped() {
5252
check(
5353
r#"
54-
macro_rules! format_args {
55-
($lit:literal $(tt:tt)*) => { 0 },
56-
}
54+
//- minicore: fmt
5755
macro_rules! print {
5856
($($arg:tt)*) => (std::io::_print(format_args!($($arg)*)));
5957
}
@@ -70,9 +68,7 @@ fn main() {
7068
fn no_completion_without_brace() {
7169
check(
7270
r#"
73-
macro_rules! format_args {
74-
($lit:literal $(tt:tt)*) => { 0 },
75-
}
71+
//- minicore: fmt
7672
fn main() {
7773
let foobar = 1;
7874
format_args!("f$0");
@@ -87,18 +83,13 @@ fn main() {
8783
check_edit(
8884
"foobar",
8985
r#"
90-
macro_rules! format_args {
91-
($lit:literal $(tt:tt)*) => { 0 },
92-
}
86+
//- minicore: fmt
9387
fn main() {
9488
let foobar = 1;
9589
format_args!("{f$0");
9690
}
9791
"#,
9892
r#"
99-
macro_rules! format_args {
100-
($lit:literal $(tt:tt)*) => { 0 },
101-
}
10293
fn main() {
10394
let foobar = 1;
10495
format_args!("{foobar");
@@ -108,18 +99,13 @@ fn main() {
10899
check_edit(
109100
"foobar",
110101
r#"
111-
macro_rules! format_args {
112-
($lit:literal $(tt:tt)*) => { 0 },
113-
}
102+
//- minicore: fmt
114103
fn main() {
115104
let foobar = 1;
116105
format_args!("{$0");
117106
}
118107
"#,
119108
r#"
120-
macro_rules! format_args {
121-
($lit:literal $(tt:tt)*) => { 0 },
122-
}
123109
fn main() {
124110
let foobar = 1;
125111
format_args!("{foobar");

‎crates/ide-db/src/syntax_helpers/format_string.rs‎

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
//! Tools to work with format string literals for the `format_args!` family of macros.
2-
use crate::syntax_helpers::node_ext::macro_call_for_string_token;
32
use syntax::{
43
ast::{self, IsString},
5-
TextRange, TextSize,
4+
AstNode, AstToken, TextRange, TextSize,
65
};
76

7+
// FIXME: This can probably be re-implemented via the HIR?
88
pub fn is_format_string(string: &ast::String) -> bool {
99
// Check if `string` is a format string argument of a macro invocation.
1010
// `string` is a string literal, mapped down into the innermost macro expansion.
@@ -15,19 +15,9 @@ pub fn is_format_string(string: &ast::String) -> bool {
1515
// This setup lets us correctly highlight the components of `concat!("{}", "bla")` format
1616
// strings. It still fails for `concat!("{", "}")`, but that is rare.
1717
(|| {
18-
let name = macro_call_for_string_token(string)?.path()?.segment()?.name_ref()?;
19-
20-
if !matches!(
21-
name.text().as_str(),
22-
"format_args" | "format_args_nl" | "const_format_args" | "panic_2015" | "panic_2021"
23-
) {
24-
return None;
25-
}
26-
27-
// NB: we match against `panic_2015`/`panic_2021` here because they have a special-cased arm for
28-
// `"{}"`, which otherwise wouldn't get highlighted.
29-
30-
Some(())
18+
let lit = string.syntax().parent().and_then(ast::Literal::cast)?;
19+
let fa = lit.syntax().parent().and_then(ast::FormatArgsExpr::cast)?;
20+
(fa.template()? == ast::Expr::Literal(lit)).then_some(|| ())
3121
})()
3222
.is_some()
3323
}

‎crates/ide/src/hover/tests.rs‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6574,3 +6574,23 @@ fn test() {
65746574
"#]],
65756575
);
65766576
}
6577+
6578+
#[test]
6579+
fn format_args_arg() {
6580+
check(
6581+
r#"
6582+
//- minicore: fmt
6583+
fn test() {
6584+
let foo = 0;
6585+
format_args!("{}", foo$0);
6586+
}
6587+
"#,
6588+
expect![[r#"
6589+
*foo*
6590+
6591+
```rust
6592+
let foo: i32 // size = 4, align = 4
6593+
```
6594+
"#]],
6595+
);
6596+
}

‎crates/ide/src/inlay_hints/chaining.rs‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -474,7 +474,7 @@ fn main() {
474474
file_id: FileId(
475475
1,
476476
),
477-
range: 9289..9297,
477+
range: 10739..10747,
478478
},
479479
),
480480
tooltip: "",
@@ -487,7 +487,7 @@ fn main() {
487487
file_id: FileId(
488488
1,
489489
),
490-
range: 9321..9325,
490+
range: 10771..10775,
491491
},
492492
),
493493
tooltip: "",
@@ -511,7 +511,7 @@ fn main() {
511511
file_id: FileId(
512512
1,
513513
),
514-
range: 9289..9297,
514+
range: 10739..10747,
515515
},
516516
),
517517
tooltip: "",
@@ -524,7 +524,7 @@ fn main() {
524524
file_id: FileId(
525525
1,
526526
),
527-
range: 9321..9325,
527+
range: 10771..10775,
528528
},
529529
),
530530
tooltip: "",
@@ -548,7 +548,7 @@ fn main() {
548548
file_id: FileId(
549549
1,
550550
),
551-
range: 9289..9297,
551+
range: 10739..10747,
552552
},
553553
),
554554
tooltip: "",
@@ -561,7 +561,7 @@ fn main() {
561561
file_id: FileId(
562562
1,
563563
),
564-
range: 9321..9325,
564+
range: 10771..10775,
565565
},
566566
),
567567
tooltip: "",

‎crates/ide/src/syntax_highlighting/format.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ pub(super) fn highlight_format_string(
1717
return;
1818
}
1919

20+
// FIXME: Replace this with the HIR info we have now.
2021
lex_format_specifiers(string, &mut |piece_range, kind| {
2122
if let Some(highlight) = highlight_format_specifier(kind) {
2223
stack.add(HlRange {

‎crates/ide/src/syntax_highlighting/highlight.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -617,6 +617,7 @@ fn highlight_name_by_syntax(name: ast::Name) -> Highlight {
617617
CONST => SymbolKind::Const,
618618
STATIC => SymbolKind::Static,
619619
IDENT_PAT => SymbolKind::Local,
620+
FORMAT_ARGS_ARG => SymbolKind::Local,
620621
_ => return default.into(),
621622
};
622623

‎crates/ide/src/syntax_highlighting/test_data/highlight_strings.html‎

Lines changed: 23 additions & 29 deletions
Large diffs are not rendered by default.

‎crates/ide/src/syntax_highlighting/tests.rs‎

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -401,19 +401,14 @@ fn test_string_highlighting() {
401401
// thus, we have to copy the macro definition from `std`
402402
check_highlighting(
403403
r#"
404+
//- minicore: fmt
404405
macro_rules! println {
405406
($($arg:tt)*) => ({
406-
$crate::io::_print($crate::format_args_nl!($($arg)*));
407+
$crate::io::_print(format_args_nl!($($arg)*));
407408
})
408409
}
409410
#[rustc_builtin_macro]
410411
#[macro_export]
411-
macro_rules! format_args {}
412-
#[rustc_builtin_macro]
413-
#[macro_export]
414-
macro_rules! const_format_args {}
415-
#[rustc_builtin_macro]
416-
#[macro_export]
417412
macro_rules! format_args_nl {}
418413
419414
mod panic {
@@ -433,7 +428,7 @@ mod panic {
433428
$crate::panicking::panic_display(&$arg)
434429
),
435430
($fmt:expr, $($arg:tt)+) => (
436-
$crate::panicking::panic_fmt($crate::const_format_args!($fmt, $($arg)+))
431+
$crate::panicking::panic_fmt(const_format_args!($fmt, $($arg)+))
437432
),
438433
}
439434
}
@@ -450,7 +445,7 @@ macro_rules! concat {}
450445
451446
macro_rules! toho {
452447
() => ($crate::panic!("not yet implemented"));
453-
($($arg:tt)+) => ($crate::panic!("not yet implemented: {}", $crate::format_args!($($arg)+)));
448+
($($arg:tt)+) => ($crate::panic!("not yet implemented: {}", format_args!($($arg)+)));
454449
}
455450
456451
fn main() {

‎crates/test-utils/src/minicore.rs‎

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1352,8 +1352,6 @@ mod macros {
13521352
/* compiler built-in */
13531353
};
13541354
}
1355-
1356-
pub(crate) use panic;
13571355
// endregion:panic
13581356

13591357
// region:fmt
@@ -1364,7 +1362,20 @@ mod macros {
13641362
($fmt:expr, $($args:tt)*) => {{ /* compiler built-in */ }};
13651363
}
13661364

1367-
pub(crate) use const_format_args;
1365+
#[macro_export]
1366+
#[rustc_builtin_macro]
1367+
macro_rules! format_args {
1368+
($fmt:expr) => {{ /* compiler built-in */ }};
1369+
($fmt:expr, $($args:tt)*) => {{ /* compiler built-in */ }};
1370+
}
1371+
1372+
#[macro_export]
1373+
macro_rules! print {
1374+
($($arg:tt)*) => {{
1375+
$crate::io::_print($crate::format_args!($($arg)*));
1376+
}};
1377+
}
1378+
13681379
// endregion:fmt
13691380

13701381
// region:derive

0 commit comments

Comments
 (0)
Please sign in to comment.