Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-def/src/macro_expansion_tests/mbe/metavar_expr.rs')
| -rw-r--r-- | crates/hir-def/src/macro_expansion_tests/mbe/metavar_expr.rs | 311 |
1 files changed, 311 insertions, 0 deletions
diff --git a/crates/hir-def/src/macro_expansion_tests/mbe/metavar_expr.rs b/crates/hir-def/src/macro_expansion_tests/mbe/metavar_expr.rs new file mode 100644 index 0000000000..967b5ad36b --- /dev/null +++ b/crates/hir-def/src/macro_expansion_tests/mbe/metavar_expr.rs @@ -0,0 +1,311 @@ +//! Tests for RFC 3086 metavariable expressions. + +use expect_test::expect; + +use crate::macro_expansion_tests::check; + +#[test] +fn test_dollar_dollar() { + check( + r#" +macro_rules! register_struct { ($Struct:ident) => { + macro_rules! register_methods { ($$($method:ident),*) => { + macro_rules! implement_methods { ($$$$($$val:expr),*) => { + struct $Struct; + impl $Struct { $$(fn $method() -> &'static [u32] { &[$$$$($$$$val),*] })*} + }} + }} +}} + +register_struct!(Foo); +register_methods!(alpha, beta); +implement_methods!(1, 2, 3); +"#, + expect![[r#" +macro_rules! register_struct { ($Struct:ident) => { + macro_rules! register_methods { ($$($method:ident),*) => { + macro_rules! implement_methods { ($$$$($$val:expr),*) => { + struct $Struct; + impl $Struct { $$(fn $method() -> &'static [u32] { &[$$$$($$$$val),*] })*} + }} + }} +}} + +macro_rules !register_methods { + ($($method: ident), *) = > { + macro_rules!implement_methods { + ($$($val: expr), *) = > { + struct Foo; + impl Foo { + $(fn $method()-> &'static[u32] { + &[$$($$val), *] + } + )* + } + } + } + } +} +macro_rules !implement_methods { + ($($val: expr), *) = > { + struct Foo; + impl Foo { + fn alpha()-> &'static[u32] { + &[$($val), *] + } + fn beta()-> &'static[u32] { + &[$($val), *] + } + } + } +} +struct Foo; +impl Foo { + fn alpha() -> &'static[u32] { + &[1, 2, 3] + } + fn beta() -> &'static[u32] { + &[1, 2, 3] + } +} +"#]], + ) +} + +#[test] +fn test_metavar_exprs() { + check( + r#" +macro_rules! m { + ( $( $t:tt )* ) => ( $( ${ignore(t)} -${index()} )-* ); +} +const _: i32 = m!(a b c); + "#, + expect![[r#" +macro_rules! m { + ( $( $t:tt )* ) => ( $( ${ignore(t)} -${index()} )-* ); +} +const _: i32 = -0--1--2; + "#]], + ); +} + +#[test] +fn count_basic() { + check( + r#" +macro_rules! m { + ($($t:ident),*) => { + ${count(t)} + } +} + +fn test() { + m!(); + m!(a); + m!(a, a); +} +"#, + expect![[r#" +macro_rules! m { + ($($t:ident),*) => { + ${count(t)} + } +} + +fn test() { + 0; + 1; + 2; +} +"#]], + ); +} + +#[test] +fn count_with_depth() { + check( + r#" +macro_rules! foo { + ($( $( $($t:ident)* ),* );*) => { + $( + { + let depth_none = ${count(t)}; + let depth_zero = ${count(t, 0)}; + let depth_one = ${count(t, 1)}; + } + )* + } +} + +fn bar() { + foo!( + a a a, a, a a; + a a a + ) +} +"#, + expect![[r#" +macro_rules! foo { + ($( $( $($t:ident)* ),* );*) => { + $( + { + let depth_none = ${count(t)}; + let depth_zero = ${count(t, 0)}; + let depth_one = ${count(t, 1)}; + } + )* + } +} + +fn bar() { + { + let depth_none = 6; + let depth_zero = 3; + let depth_one = 6; + } { + let depth_none = 3; + let depth_zero = 1; + let depth_one = 3; + } +} +"#]], + ); +} + +#[test] +fn count_depth_out_of_bounds() { + check( + r#" +macro_rules! foo { + ($($t:ident)*) => { ${count(t, 1)} }; + ($( $( $l:literal )* );*) => { $(${count(l, 1)};)* } +} +macro_rules! bar { + ($($t:ident)*) => { ${count(t, 1024)} }; + ($( $( $l:literal )* );*) => { $(${count(l, 8192)};)* } +} + +fn test() { + foo!(a b); + foo!(1 2; 3); + bar!(a b); + bar!(1 2; 3); +} +"#, + expect![[r#" +macro_rules! foo { + ($($t:ident)*) => { ${count(t, 1)} }; + ($( $( $l:literal )* );*) => { $(${count(l, 1)};)* } +} +macro_rules! bar { + ($($t:ident)*) => { ${count(t, 1024)} }; + ($( $( $l:literal )* );*) => { $(${count(l, 8192)};)* } +} + +fn test() { + /* error: ${count} out of bounds */; + /* error: ${count} out of bounds */; + /* error: ${count} out of bounds */; + /* error: ${count} out of bounds */; +} +"#]], + ); +} + +#[test] +fn misplaced_count() { + check( + r#" +macro_rules! foo { + ($($t:ident)*) => { $(${count(t)})* }; + ($l:literal) => { ${count(l)} } +} + +fn test() { + foo!(a b c); + foo!(1); +} +"#, + expect![[r#" +macro_rules! foo { + ($($t:ident)*) => { $(${count(t)})* }; + ($l:literal) => { ${count(l)} } +} + +fn test() { + /* error: ${count} misplaced */; + /* error: ${count} misplaced */; +} +"#]], + ); +} + +#[test] +fn malformed_count() { + check( + r#" +macro_rules! too_many_args { + ($($t:ident)*) => { ${count(t, 1, leftover)} } +} +macro_rules! depth_suffixed { + ($($t:ident)*) => { ${count(t, 0usize)} } +} +macro_rules! depth_too_large { + ($($t:ident)*) => { ${count(t, 18446744073709551616)} } +} + +fn test() { + too_many_args!(); + depth_suffixed!(); + depth_too_large!(); +} +"#, + expect![[r#" +macro_rules! too_many_args { + ($($t:ident)*) => { ${count(t, 1, leftover)} } +} +macro_rules! depth_suffixed { + ($($t:ident)*) => { ${count(t, 0usize)} } +} +macro_rules! depth_too_large { + ($($t:ident)*) => { ${count(t, 18446744073709551616)} } +} + +fn test() { + /* error: invalid macro definition: invalid metavariable expression */; + /* error: invalid macro definition: invalid metavariable expression */; + /* error: invalid macro definition: invalid metavariable expression */; +} +"#]], + ); +} + +#[test] +fn count_interaction_with_empty_binding() { + // FIXME: Should this error? rustc currently accepts it. + check( + r#" +macro_rules! m { + ($($t:ident),*) => { + ${count(t, 100)} + } +} + +fn test() { + m!(); +} +"#, + expect![[r#" +macro_rules! m { + ($($t:ident),*) => { + ${count(t, 100)} + } +} + +fn test() { + 0; +} +"#]], + ); +} |