future proof structure

This commit is contained in:
Aleksey Kladov 2021-10-09 14:48:38 +03:00
parent 5ecda802f1
commit 8e9003447c
3 changed files with 143 additions and 135 deletions
crates
hir_def/src
macro_expansion_tests.rs
macro_expansion_tests
mbe/src

@ -9,10 +9,12 @@
//! write unit-tests (in fact, we used to do that), but that makes tests brittle
//! and harder to understand.
mod mbe;
use std::{iter, ops::Range};
use base_db::{fixture::WithFixture, SourceDatabase};
use expect_test::{expect, Expect};
use expect_test::Expect;
use hir_expand::{db::AstDatabase, InFile, MacroFile};
use stdx::format_to;
use syntax::{
@ -113,137 +115,3 @@ fn pretty_print_macro_expansion(expn: SyntaxNode) -> String {
}
res
}
#[test]
fn wrong_nesting_level() {
check(
r#"
macro_rules! m {
($($i:ident);*) => ($i)
}
m!{a}
"#,
expect![[r#"
macro_rules! m {
($($i:ident);*) => ($i)
}
/* error: expected simple binding, found nested binding `i` */
"#]],
);
}
#[test]
fn expansion_does_not_parse_as_expression() {
check(
r#"
macro_rules! stmts {
() => { let _ = 0; }
}
fn f() { let _ = stmts!(); }
"#,
expect![[r#"
macro_rules! stmts {
() => { let _ = 0; }
}
fn f() { let _ = /* error: could not convert tokens */; }
"#]],
)
}
#[test]
fn round_trips_compound_tokens() {
check(
r#"
macro_rules! m {
() => { type qual: ::T = qual::T; }
}
m!();
"#,
expect![[r#"
macro_rules! m {
() => { type qual: ::T = qual::T; }
}
type qual: ::T = qual::T;
"#]],
)
}
#[test]
fn round_trips_literals() {
check(
r#"
macro_rules! m {
() => {
let _ = 'c';
let _ = 1000;
let _ = 12E+99_f64;
let _ = "rust1";
let _ = -92;
}
}
fn f() {
m!()
}
"#,
expect![[r#"
macro_rules! m {
() => {
let _ = 'c';
let _ = 1000;
let _ = 12E+99_f64;
let _ = "rust1";
let _ = -92;
}
}
fn f() {
let_ = 'c';
let_ = 1000;
let_ = 12E+99_f64;
let_ = "rust1";
let_ = -92;
}
"#]],
);
}
#[test]
fn broken_parenthesis_sequence() {
check(
r#"
macro_rules! m1 { ($x:ident) => { ($x } }
macro_rules! m2 { ($x:ident) => {} }
m1!();
m2!(x
"#,
expect![[r#"
macro_rules! m1 { ($x:ident) => { ($x } }
macro_rules! m2 { ($x:ident) => {} }
/* error: Failed to find macro definition */
/* error: Failed to lower macro args to token tree */
"#]],
)
}
#[test]
fn unary_minus_is_a_literal() {
check(
r#"
macro_rules! m { ($x:literal) => (literal!()); ($x:tt) => (not_a_literal!()); }
m!(92);
m!(-92);
m!(-9.2);
m!(--92);
"#,
expect![[r#"
macro_rules! m { ($x:literal) => (literal!()); ($x:tt) => (not_a_literal!()); }
literal!()
literal!()
literal!()
/* error: leftover tokens */not_a_literal!()
"#]],
)
}

@ -0,0 +1,137 @@
use expect_test::expect;
use crate::macro_expansion_tests::check;
#[test]
fn wrong_nesting_level() {
check(
r#"
macro_rules! m {
($($i:ident);*) => ($i)
}
m!{a}
"#,
expect![[r#"
macro_rules! m {
($($i:ident);*) => ($i)
}
/* error: expected simple binding, found nested binding `i` */
"#]],
);
}
#[test]
fn expansion_does_not_parse_as_expression() {
check(
r#"
macro_rules! stmts {
() => { let _ = 0; }
}
fn f() { let _ = stmts!(); }
"#,
expect![[r#"
macro_rules! stmts {
() => { let _ = 0; }
}
fn f() { let _ = /* error: could not convert tokens */; }
"#]],
)
}
#[test]
fn round_trips_compound_tokens() {
check(
r#"
macro_rules! m {
() => { type qual: ::T = qual::T; }
}
m!();
"#,
expect![[r#"
macro_rules! m {
() => { type qual: ::T = qual::T; }
}
type qual: ::T = qual::T;
"#]],
)
}
#[test]
fn round_trips_literals() {
check(
r#"
macro_rules! m {
() => {
let _ = 'c';
let _ = 1000;
let _ = 12E+99_f64;
let _ = "rust1";
let _ = -92;
}
}
fn f() {
m!()
}
"#,
expect![[r#"
macro_rules! m {
() => {
let _ = 'c';
let _ = 1000;
let _ = 12E+99_f64;
let _ = "rust1";
let _ = -92;
}
}
fn f() {
let_ = 'c';
let_ = 1000;
let_ = 12E+99_f64;
let_ = "rust1";
let_ = -92;
}
"#]],
);
}
#[test]
fn broken_parenthesis_sequence() {
check(
r#"
macro_rules! m1 { ($x:ident) => { ($x } }
macro_rules! m2 { ($x:ident) => {} }
m1!();
m2!(x
"#,
expect![[r#"
macro_rules! m1 { ($x:ident) => { ($x } }
macro_rules! m2 { ($x:ident) => {} }
/* error: Failed to find macro definition */
/* error: Failed to lower macro args to token tree */
"#]],
)
}
#[test]
fn unary_minus_is_a_literal() {
check(
r#"
macro_rules! m { ($x:literal) => (literal!()); ($x:tt) => (not_a_literal!()); }
m!(92);
m!(-92);
m!(-9.2);
m!(--92);
"#,
expect![[r#"
macro_rules! m { ($x:literal) => (literal!()); ($x:tt) => (not_a_literal!()); }
literal!()
literal!()
literal!()
/* error: leftover tokens */not_a_literal!()
"#]],
)
}

@ -2,6 +2,9 @@
//! `macro_rules` macros. It uses `TokenTree` (from `tt` package) as the
//! interface, although it contains some code to bridge `SyntaxNode`s and
//! `TokenTree`s as well!
//!
//! The tes for this functionality live in another crate:
//! `hir_def::macro_expansion_tests::mbe`.
mod parser;
mod expander;