aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_expand/src/builtin_macro.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_expand/src/builtin_macro.rs')
-rw-r--r--crates/hir_expand/src/builtin_macro.rs90
1 files changed, 37 insertions, 53 deletions
diff --git a/crates/hir_expand/src/builtin_macro.rs b/crates/hir_expand/src/builtin_macro.rs
index 80b60d59f..eb57ea7d6 100644
--- a/crates/hir_expand/src/builtin_macro.rs
+++ b/crates/hir_expand/src/builtin_macro.rs
@@ -6,7 +6,7 @@ use crate::{
6 6
7use base_db::{AnchoredPath, FileId}; 7use base_db::{AnchoredPath, FileId};
8use either::Either; 8use either::Either;
9use mbe::{parse_to_token_tree, ExpandResult}; 9use mbe::{parse_exprs_with_sep, parse_to_token_tree, ExpandResult};
10use parser::FragmentKind; 10use parser::FragmentKind;
11use syntax::ast::{self, AstToken}; 11use syntax::ast::{self, AstToken};
12 12
@@ -182,25 +182,10 @@ fn assert_expand(
182 // ```, 182 // ```,
183 // which is wrong but useful. 183 // which is wrong but useful.
184 184
185 let mut args = Vec::new(); 185 let args = parse_exprs_with_sep(tt, ',');
186 let mut current = Vec::new();
187 for tt in tt.token_trees.iter().cloned() {
188 match tt {
189 tt::TokenTree::Leaf(tt::Leaf::Punct(p)) if p.char == ',' => {
190 args.push(current);
191 current = Vec::new();
192 }
193 _ => {
194 current.push(tt);
195 }
196 }
197 }
198 if !current.is_empty() {
199 args.push(current);
200 }
201 186
202 let arg_tts = args.into_iter().flat_map(|arg| { 187 let arg_tts = args.into_iter().flat_map(|arg| {
203 quote! { &(##arg), } 188 quote! { &(#arg), }
204 }.token_trees).collect::<Vec<_>>(); 189 }.token_trees).collect::<Vec<_>>();
205 190
206 let expanded = quote! { 191 let expanded = quote! {
@@ -238,35 +223,21 @@ fn format_args_expand(
238 // ]) 223 // ])
239 // ```, 224 // ```,
240 // which is still not really correct, but close enough for now 225 // which is still not really correct, but close enough for now
241 let mut args = Vec::new(); 226 let mut args = parse_exprs_with_sep(tt, ',');
242 let mut current = Vec::new(); 227
243 for tt in tt.token_trees.iter().cloned() {
244 match tt {
245 tt::TokenTree::Leaf(tt::Leaf::Punct(p)) if p.char == ',' => {
246 args.push(current);
247 current = Vec::new();
248 }
249 _ => {
250 current.push(tt);
251 }
252 }
253 }
254 if !current.is_empty() {
255 args.push(current);
256 }
257 if args.is_empty() { 228 if args.is_empty() {
258 return ExpandResult::only_err(mbe::ExpandError::NoMatchingRule); 229 return ExpandResult::only_err(mbe::ExpandError::NoMatchingRule);
259 } 230 }
260 for arg in &mut args { 231 for arg in &mut args {
261 // Remove `key =`. 232 // Remove `key =`.
262 if matches!(arg.get(1), Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p))) if p.char == '=' && p.spacing != tt::Spacing::Joint) 233 if matches!(arg.token_trees.get(1), Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p))) if p.char == '=' && p.spacing != tt::Spacing::Joint)
263 { 234 {
264 arg.drain(..2); 235 arg.token_trees.drain(..2);
265 } 236 }
266 } 237 }
267 let _format_string = args.remove(0); 238 let _format_string = args.remove(0);
268 let arg_tts = args.into_iter().flat_map(|arg| { 239 let arg_tts = args.into_iter().flat_map(|arg| {
269 quote! { std::fmt::ArgumentV1::new(&(##arg), std::fmt::Display::fmt), } 240 quote! { std::fmt::ArgumentV1::new(&(#arg), std::fmt::Display::fmt), }
270 }.token_trees).collect::<Vec<_>>(); 241 }.token_trees).collect::<Vec<_>>();
271 let expanded = quote! { 242 let expanded = quote! {
272 std::fmt::Arguments::new_v1(&[], &[##arg_tts]) 243 std::fmt::Arguments::new_v1(&[], &[##arg_tts])
@@ -327,17 +298,14 @@ fn concat_expand(
327 // concat works with string and char literals, so remove any quotes. 298 // concat works with string and char literals, so remove any quotes.
328 // It also works with integer, float and boolean literals, so just use the rest 299 // It also works with integer, float and boolean literals, so just use the rest
329 // as-is. 300 // as-is.
330 301 let component = unquote_str(&it).unwrap_or_else(|| it.text.to_string());
331 text += it 302 text.push_str(&component);
332 .text 303 }
333 .trim_start_matches(|c| match c { 304 // handle boolean literals
334 'r' | '#' | '\'' | '"' => true, 305 tt::TokenTree::Leaf(tt::Leaf::Ident(id))
335 _ => false, 306 if i % 2 == 0 && (id.text == "true" || id.text == "false") =>
336 }) 307 {
337 .trim_end_matches(|c| match c { 308 text.push_str(id.text.as_str());
338 '#' | '\'' | '"' => true,
339 _ => false,
340 });
341 } 309 }
342 tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if i % 2 == 1 && punct.char == ',' => (), 310 tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if i % 2 == 1 && punct.char == ',' => (),
343 _ => { 311 _ => {
@@ -345,7 +313,6 @@ fn concat_expand(
345 } 313 }
346 } 314 }
347 } 315 }
348
349 ExpandResult { value: Some((quote!(#text), FragmentKind::Expr)), err } 316 ExpandResult { value: Some((quote!(#text), FragmentKind::Expr)), err }
350} 317}
351 318
@@ -724,6 +691,25 @@ mod tests {
724 } 691 }
725 692
726 #[test] 693 #[test]
694 fn test_format_args_expand_with_comma_exprs() {
695 let expanded = expand_builtin_macro(
696 r#"
697 #[rustc_builtin_macro]
698 macro_rules! format_args {
699 ($fmt:expr) => ({ /* compiler built-in */ });
700 ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ })
701 }
702 format_args!("{} {:?}", a::<A,B>(), b);
703 "#,
704 );
705
706 assert_eq!(
707 expanded,
708 r#"std::fmt::Arguments::new_v1(&[], &[std::fmt::ArgumentV1::new(&(a::<A,B>()),std::fmt::Display::fmt),std::fmt::ArgumentV1::new(&(b),std::fmt::Display::fmt),])"#
709 );
710 }
711
712 #[test]
727 fn test_include_bytes_expand() { 713 fn test_include_bytes_expand() {
728 let expanded = expand_builtin_macro( 714 let expanded = expand_builtin_macro(
729 r#" 715 r#"
@@ -745,12 +731,10 @@ mod tests {
745 r##" 731 r##"
746 #[rustc_builtin_macro] 732 #[rustc_builtin_macro]
747 macro_rules! concat {} 733 macro_rules! concat {}
748 concat!("foo", 0, r#"bar"#); 734 concat!("foo", "r", 0, r#"bar"#, false);
749 "##, 735 "##,
750 ); 736 );
751 737
752 assert_eq!(expanded, r#""foo0bar""#); 738 assert_eq!(expanded, r#""foor0barfalse""#);
753
754 // FIXME: `true`/`false` literals don't work.
755 } 739 }
756} 740}