mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-08-04 18:58:41 +00:00
311 lines
5.7 KiB
Rust
311 lines
5.7 KiB
Rust
//! 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;
|
|
}
|
|
"#]],
|
|
);
|
|
}
|