Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir_def/src/macro_expansion_tests/mbe.rs')
| -rw-r--r-- | crates/hir_def/src/macro_expansion_tests/mbe.rs | 339 |
1 files changed, 333 insertions, 6 deletions
diff --git a/crates/hir_def/src/macro_expansion_tests/mbe.rs b/crates/hir_def/src/macro_expansion_tests/mbe.rs index df93298a35..1da0110fe2 100644 --- a/crates/hir_def/src/macro_expansion_tests/mbe.rs +++ b/crates/hir_def/src/macro_expansion_tests/mbe.rs @@ -4,6 +4,7 @@ mod tt_conversion; mod matching; mod meta_syntax; +mod regression; use expect_test::expect; @@ -35,12 +36,12 @@ macro_rules! impl_froms { } } impl From<Leaf> for TokenTree { - fn from(it:Leaf) -> TokenTree { + fn from(it: Leaf) -> TokenTree { TokenTree::Leaf(it) } } impl From<Subtree> for TokenTree { - fn from(it:Subtree) -> TokenTree { + fn from(it: Subtree) -> TokenTree { TokenTree::Subtree(it) } } @@ -433,10 +434,10 @@ macro_rules! structs { } struct Foo { - field:u32 + field: u32 } struct Bar { - field:u32 + field: u32 } @@ -906,8 +907,8 @@ extern crate a; mod b; mod c {} use d; -const E:i32 = 0; -static F:i32 = 0; +const E: i32 = 0; +static F: i32 = 0; impl G {} struct H; enum I { @@ -1119,3 +1120,329 @@ ok!(); "#]], ); } + +#[test] +fn test_underscore() { + check( + r#" +macro_rules! m { ($_:tt) => { ok!(); } } +m! { => } +"#, + expect![[r#" +macro_rules! m { ($_:tt) => { ok!(); } } +ok!(); +"#]], + ); +} + +#[test] +fn test_underscore_not_greedily() { + check( + r#" +// `_` overlaps with `$a:ident` but rustc matches it under the `_` token. +macro_rules! m1 { + ($($a:ident)* _) => { ok!(); } +} +m1![a b c d _]; + +// `_ => ou` overlaps with `$a:expr => $b:ident` but rustc matches it under `_ => $c:expr`. +macro_rules! m2 { + ($($a:expr => $b:ident)* _ => $c:expr) => { ok!(); } +} +m2![a => b c => d _ => ou] +"#, + expect![[r#" +// `_` overlaps with `$a:ident` but rustc matches it under the `_` token. +macro_rules! m1 { + ($($a:ident)* _) => { ok!(); } +} +ok!(); + +// `_ => ou` overlaps with `$a:expr => $b:ident` but rustc matches it under `_ => $c:expr`. +macro_rules! m2 { + ($($a:expr => $b:ident)* _ => $c:expr) => { ok!(); } +} +ok!(); +"#]], + ); +} + +#[test] +fn test_underscore_flavors() { + check( + r#" +macro_rules! m1 { ($a:ty) => { ok!(); } } +m1![_]; + +macro_rules! m2 { ($a:lifetime) => { ok!(); } } +m2!['_]; +"#, + expect![[r#" +macro_rules! m1 { ($a:ty) => { ok!(); } } +ok!(); + +macro_rules! m2 { ($a:lifetime) => { ok!(); } } +ok!(); +"#]], + ); +} + +#[test] +fn test_vertical_bar_with_pat() { + check( + r#" +macro_rules! m { (|$pat:pat| ) => { ok!(); } } +m! { |x| } + "#, + expect![[r#" +macro_rules! m { (|$pat:pat| ) => { ok!(); } } +ok!(); + "#]], + ); +} + +#[test] +fn test_dollar_crate_lhs_is_not_meta() { + check( + r#" +macro_rules! m { + ($crate) => { err!(); }; + () => { ok!(); }; +} +m!{} +"#, + expect![[r#" +macro_rules! m { + ($crate) => { err!(); }; + () => { ok!(); }; +} +ok!(); +"#]], + ); +} + +#[test] +fn test_lifetime() { + check( + r#" +macro_rules! m { + ($lt:lifetime) => { struct Ref<$lt>{ s: &$ lt str } } +} +m! {'a} +"#, + expect![[r#" +macro_rules! m { + ($lt:lifetime) => { struct Ref<$lt>{ s: &$ lt str } } +} +struct Ref<'a> { + s: &'a str +} +"#]], + ); +} + +#[test] +fn test_literal() { + check( + r#" +macro_rules! m { + ($type:ty, $lit:literal) => { const VALUE: $type = $ lit; }; +} +m!(u8, 0); +"#, + expect![[r#" +macro_rules! m { + ($type:ty, $lit:literal) => { const VALUE: $type = $ lit; }; +} +const VALUE: u8 = 0; +"#]], + ); + + check( + r#" +macro_rules! m { + ($type:ty, $lit:literal) => { const VALUE: $ type = $ lit; }; +} +m!(i32, -1); +"#, + expect![[r#" +macro_rules! m { + ($type:ty, $lit:literal) => { const VALUE: $ type = $ lit; }; +} +const VALUE: i32 = -1; +"#]], + ); +} + +#[test] +fn test_boolean_is_ident() { + check( + r#" +macro_rules! m { + ($lit0:literal, $lit1:literal) => { const VALUE: (bool, bool) = ($lit0, $lit1); }; +} +m!(true, false); +"#, + expect![[r#" +macro_rules! m { + ($lit0:literal, $lit1:literal) => { const VALUE: (bool, bool) = ($lit0, $lit1); }; +} +const VALUE: (bool, bool) = (true , false ); +"#]], + ); +} + +#[test] +fn test_vis() { + check( + r#" +macro_rules! m { + ($vis:vis $name:ident) => { $vis fn $name() {} } +} +m!(pub foo); +m!(foo); +"#, + expect![[r#" +macro_rules! m { + ($vis:vis $name:ident) => { $vis fn $name() {} } +} +pub fn foo() {} +fn foo() {} +"#]], + ); +} + +#[test] +fn test_inner_macro_rules() { + check( + r#" +macro_rules! m { + ($a:ident, $b:ident, $c:tt) => { + macro_rules! inner { + ($bi:ident) => { fn $bi() -> u8 { $c } } + } + + inner!($a); + fn $b() -> u8 { $c } + } +} +m!(x, y, 1); +"#, + expect![[r#" +macro_rules! m { + ($a:ident, $b:ident, $c:tt) => { + macro_rules! inner { + ($bi:ident) => { fn $bi() -> u8 { $c } } + } + + inner!($a); + fn $b() -> u8 { $c } + } +} +macro_rules !inner { + ($bi: ident) = > { + fn $bi()-> u8 { + 1 + } + } +} +inner!(x); +fn y() -> u8 { + 1 +} +"#]], + ); +} + +#[test] +fn test_expr_after_path_colons() { + check( + r#" +macro_rules! m { + ($k:expr) => { fn f() { K::$k; } } +} +// +tree +errors +m!(C("0")); +"#, + expect![[r#" +macro_rules! m { + ($k:expr) => { fn f() { K::$k; } } +} +/* parse error: expected identifier */ +/* parse error: expected SEMICOLON */ +fn f() { + K::C("0"); +} +// [email protected] "fn" +// [email protected] "f" +// [email protected] "(" +// [email protected] ")" +// [email protected] "{" +// [email protected] "K" +// [email protected] "::" +// [email protected] "C" +// [email protected] "(" +// [email protected] "\"0\"" +// [email protected] ")" +// [email protected] ";" +// [email protected] "}" + +"#]], + ); +} + +#[test] +fn test_match_is_not_greedy() { + check( + r#" +macro_rules! foo { + ($($i:ident $(,)*),*) => {}; +} +foo!(a,b); +"#, + expect![[r#" +macro_rules! foo { + ($($i:ident $(,)*),*) => {}; +} + +"#]], + ); +} + +#[test] +fn expr_interpolation() { + check( + r#" +macro_rules! m { ($expr:expr) => { map($expr) } } +fn f() { + let _ = m!(x + foo); +} +"#, + expect![[r#" +macro_rules! m { ($expr:expr) => { map($expr) } } +fn f() { + let _ = map(x+foo); +} +"#]], + ) +} |