diff options
Diffstat (limited to 'crates/ra_hir_expand')
-rw-r--r-- | crates/ra_hir_expand/src/builtin_macro.rs | 47 |
1 files changed, 43 insertions, 4 deletions
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( | |||
207 | fn format_args_expand( | 207 | fn format_args_expand( |
208 | _db: &dyn AstDatabase, | 208 | _db: &dyn AstDatabase, |
209 | _id: MacroCallId, | 209 | _id: MacroCallId, |
210 | _tt: &tt::Subtree, | 210 | tt: &tt::Subtree, |
211 | ) -> Result<tt::Subtree, mbe::ExpandError> { | 211 | ) -> Result<tt::Subtree, mbe::ExpandError> { |
212 | // FIXME this is just a stub to make format macros type-check without mismatches | 212 | // We expand `format_args!("", arg1, arg2)` to |
213 | // We should make this at least insert the arguments, so that go to def etc. work within format macros | 213 | // `std::fmt::Arguments::new_v1(&[], &[&arg1, &arg2])`, |
214 | // which is still not really correct, but close enough for now | ||
215 | let mut args = Vec::new(); | ||
216 | let mut current = Vec::new(); | ||
217 | for tt in tt.token_trees.iter().cloned() { | ||
218 | match tt { | ||
219 | tt::TokenTree::Leaf(tt::Leaf::Punct(p)) if p.char == ',' => { | ||
220 | args.push(tt::Subtree { delimiter: tt::Delimiter::None, token_trees: current }); | ||
221 | current = Vec::new(); | ||
222 | } | ||
223 | _ => { | ||
224 | current.push(tt); | ||
225 | } | ||
226 | } | ||
227 | } | ||
228 | if !current.is_empty() { | ||
229 | args.push(tt::Subtree { delimiter: tt::Delimiter::None, token_trees: current }); | ||
230 | } | ||
231 | if args.is_empty() { | ||
232 | return Err(mbe::ExpandError::NoMatchingRule); | ||
233 | } | ||
234 | let _format_string = args.remove(0); | ||
235 | let arg_tts = args.into_iter().flat_map(|arg| (quote! { & #arg , }).token_trees); | ||
214 | let expanded = quote! { | 236 | let expanded = quote! { |
215 | std::fmt::Arguments::new_v1(&[], &[]) | 237 | std::fmt::Arguments::new_v1(&[], &[##arg_tts]) |
216 | }; | 238 | }; |
217 | Ok(expanded) | 239 | Ok(expanded) |
218 | } | 240 | } |
@@ -324,4 +346,21 @@ mod tests { | |||
324 | 346 | ||
325 | assert_eq!(expanded, r#"loop{"error!"}"#); | 347 | assert_eq!(expanded, r#"loop{"error!"}"#); |
326 | } | 348 | } |
349 | |||
350 | #[test] | ||
351 | fn test_format_args_expand() { | ||
352 | let expanded = expand_builtin_macro( | ||
353 | r#" | ||
354 | #[rustc_builtin_macro] | ||
355 | macro_rules! format_args { | ||
356 | ($fmt:expr) => ({ /* compiler built-in */ }); | ||
357 | ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ }) | ||
358 | } | ||
359 | format_args!("{} {:?}", arg1(a, b, c), arg2); | ||
360 | "#, | ||
361 | BuiltinFnLikeExpander::FormatArgs, | ||
362 | ); | ||
363 | |||
364 | assert_eq!(expanded, r#"std::fmt::Arguments::new_v1(&[] ,&[&arg1(a,b,c),&arg2,])"#); | ||
365 | } | ||
327 | } | 366 | } |