From eae425b10fd7803ae67d2d39e9aca902daa353ba Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 6 Dec 2019 19:30:01 +0100 Subject: Implement format_args more properly --- crates/ra_hir_expand/src/builtin_macro.rs | 47 ++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 4 deletions(-) (limited to 'crates/ra_hir_expand') diff --git a/crates/ra_hir_expand/src/builtin_macro.rs b/crates/ra_hir_expand/src/builtin_macro.rs index e0709704a..99303188b 100644 --- a/crates/ra_hir_expand/src/builtin_macro.rs +++ b/crates/ra_hir_expand/src/builtin_macro.rs @@ -207,12 +207,34 @@ fn compile_error_expand( fn format_args_expand( _db: &dyn AstDatabase, _id: MacroCallId, - _tt: &tt::Subtree, + tt: &tt::Subtree, ) -> Result { - // FIXME this is just a stub to make format macros type-check without mismatches - // We should make this at least insert the arguments, so that go to def etc. work within format macros + // We expand `format_args!("", arg1, arg2)` to + // `std::fmt::Arguments::new_v1(&[], &[&arg1, &arg2])`, + // which is still not really correct, but close enough for now + let mut args = Vec::new(); + let mut current = Vec::new(); + for tt in tt.token_trees.iter().cloned() { + match tt { + tt::TokenTree::Leaf(tt::Leaf::Punct(p)) if p.char == ',' => { + args.push(tt::Subtree { delimiter: tt::Delimiter::None, token_trees: current }); + current = Vec::new(); + } + _ => { + current.push(tt); + } + } + } + if !current.is_empty() { + args.push(tt::Subtree { delimiter: tt::Delimiter::None, token_trees: current }); + } + if args.is_empty() { + return Err(mbe::ExpandError::NoMatchingRule); + } + let _format_string = args.remove(0); + let arg_tts = args.into_iter().flat_map(|arg| (quote! { & #arg , }).token_trees); let expanded = quote! { - std::fmt::Arguments::new_v1(&[], &[]) + std::fmt::Arguments::new_v1(&[], &[##arg_tts]) }; Ok(expanded) } @@ -324,4 +346,21 @@ mod tests { assert_eq!(expanded, r#"loop{"error!"}"#); } + + #[test] + fn test_format_args_expand() { + let expanded = expand_builtin_macro( + r#" + #[rustc_builtin_macro] + macro_rules! format_args { + ($fmt:expr) => ({ /* compiler built-in */ }); + ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ }) + } + format_args!("{} {:?}", arg1(a, b, c), arg2); +"#, + BuiltinFnLikeExpander::FormatArgs, + ); + + assert_eq!(expanded, r#"std::fmt::Arguments::new_v1(&[] ,&[&arg1(a,b,c),&arg2,])"#); + } } -- cgit v1.2.3