From 7de4b964a9ac25b95ec303f675b36d8c04859e34 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 2 Jan 2022 16:48:10 +0300 Subject: [PATCH 1/2] add test for macro items --- crates/parser/src/tests/top_entries.rs | 37 ++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/crates/parser/src/tests/top_entries.rs b/crates/parser/src/tests/top_entries.rs index 0b77c0a5b96..2d867a4df3c 100644 --- a/crates/parser/src/tests/top_entries.rs +++ b/crates/parser/src/tests/top_entries.rs @@ -92,6 +92,43 @@ fn macro_stmt() { ); } +#[test] +fn macro_items() { + check( + TopEntryPoint::MacroItems, + "#!/usr/bin/rust", + expect![[r##" + MACRO_ITEMS + ERROR + SHEBANG "#!/usr/bin/rust" + error 0: expected an item + "##]], + ); + check( + TopEntryPoint::MacroItems, + "struct S; foo!{}", + expect![[r#" + MACRO_ITEMS + STRUCT + STRUCT_KW "struct" + WHITESPACE " " + NAME + IDENT "S" + SEMICOLON ";" + WHITESPACE " " + MACRO_CALL + PATH + PATH_SEGMENT + NAME_REF + IDENT "foo" + BANG "!" + TOKEN_TREE + L_CURLY "{" + R_CURLY "}" + "#]], + ); +} + #[track_caller] fn check(entry: TopEntryPoint, input: &str, expect: expect_test::Expect) { let (parsed, _errors) = super::parse(entry, input); From 7989d567e2c642e3a9444c9092d83789c1fb82a4 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 2 Jan 2022 17:18:21 +0300 Subject: [PATCH 2/2] internal: more macro tests --- .../hir_def/src/macro_expansion_tests/mbe.rs | 20 -------- .../mbe/tt_conversion.rs | 50 ++++++++++++++++++- crates/mbe/src/syntax_bridge.rs | 1 + crates/parser/src/tests.rs | 8 ++- crates/parser/src/tests/top_entries.rs | 19 +++++++ 5 files changed, 76 insertions(+), 22 deletions(-) diff --git a/crates/hir_def/src/macro_expansion_tests/mbe.rs b/crates/hir_def/src/macro_expansion_tests/mbe.rs index 466c85fc5b0..2cd70a84c53 100644 --- a/crates/hir_def/src/macro_expansion_tests/mbe.rs +++ b/crates/hir_def/src/macro_expansion_tests/mbe.rs @@ -85,26 +85,6 @@ impl From for TokenTree { ); } -#[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 wrong_nesting_level() { check( diff --git a/crates/hir_def/src/macro_expansion_tests/mbe/tt_conversion.rs b/crates/hir_def/src/macro_expansion_tests/mbe/tt_conversion.rs index 291f99330f1..97c27c453b0 100644 --- a/crates/hir_def/src/macro_expansion_tests/mbe/tt_conversion.rs +++ b/crates/hir_def/src/macro_expansion_tests/mbe/tt_conversion.rs @@ -2,7 +2,9 @@ //! Rather, token trees are an explicit bridge between the parser and //! (procedural or declarative) macros. //! -//! This module tests tt <-> syntax tree conversion specifically +//! This module tests tt <-> syntax tree conversion specifically. In particular, +//! it, among other things, check that we convert `tt` to the right kind of +//! syntax node depending on the macro call-site. use expect_test::expect; use crate::macro_expansion_tests::check; @@ -100,3 +102,49 @@ macro_rules! m2 { ($x:ident) => {} } "#]], ) } + +#[test] +fn expansion_does_not_parse_as_expression() { + cov_mark::check!(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 broken_pat() { + check( + r#" +macro_rules! m1 { () => (Some(x) left overs) } +macro_rules! m2 { () => ($) } + +fn main() { + let m1!() = (); + let m2!/*+errors*/() = (); +} +"#, + expect![[r#" +macro_rules! m1 { () => (Some(x) left overs) } +macro_rules! m2 { () => ($) } + +fn main() { + let Some(x) = (); + let /* parse error: expected pattern */ +$ = (); +} +"#]], + ) +} diff --git a/crates/mbe/src/syntax_bridge.rs b/crates/mbe/src/syntax_bridge.rs index 8021e63f7f0..1141365e82c 100644 --- a/crates/mbe/src/syntax_bridge.rs +++ b/crates/mbe/src/syntax_bridge.rs @@ -67,6 +67,7 @@ pub fn token_tree_to_syntax_node( } } if tree_sink.roots.len() != 1 { + cov_mark::hit!(expansion_does_not_parse_as_expression); return Err(ExpandError::ConversionError); } //FIXME: would be cool to report errors diff --git a/crates/parser/src/tests.rs b/crates/parser/src/tests.rs index 52388dacc61..c0437bc3b8a 100644 --- a/crates/parser/src/tests.rs +++ b/crates/parser/src/tests.rs @@ -114,7 +114,13 @@ fn parse(entry: TopEntryPoint, text: &str) -> (String, bool) { errors.push(format!("error {}: {}\n", pos, msg)) } }); - assert_eq!(len, text.len()); + assert_eq!( + len, + text.len(), + "didn't parse all text.\nParsed:\n{}\n\nAll:\n{}\n", + &text[..len], + text + ); for (token, msg) in lexed.errors() { let pos = lexed.text_start(token); diff --git a/crates/parser/src/tests/top_entries.rs b/crates/parser/src/tests/top_entries.rs index 2d867a4df3c..fa25ffd0a26 100644 --- a/crates/parser/src/tests/top_entries.rs +++ b/crates/parser/src/tests/top_entries.rs @@ -129,6 +129,25 @@ fn macro_items() { ); } +#[test] +fn macro_pattern() { + check( + TopEntryPoint::Pattern, + "Some(_)", + expect![[r#" + TUPLE_STRUCT_PAT + PATH + PATH_SEGMENT + NAME_REF + IDENT "Some" + L_PAREN "(" + WILDCARD_PAT + UNDERSCORE "_" + R_PAREN ")" + "#]], + ); +} + #[track_caller] fn check(entry: TopEntryPoint, input: &str, expect: expect_test::Expect) { let (parsed, _errors) = super::parse(entry, input);