about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--crates/hir_def/src/macro_expansion_tests/mbe/tt_conversion.rs6
-rw-r--r--crates/ide/src/hover/tests.rs2
-rw-r--r--crates/mbe/src/syntax_bridge.rs5
-rw-r--r--crates/parser/src/grammar.rs13
-rw-r--r--crates/parser/src/lib.rs28
5 files changed, 42 insertions, 12 deletions
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 4c58ea9ba64..5f4b7d6d0bc 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
@@ -105,21 +105,21 @@ 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!(); }
+fn f() { let _ = stmts!/*+errors*/(); }
 "#,
         expect![[r#"
 macro_rules! stmts {
     () => { let _ = 0; }
 }
 
-fn f() { let _ = /* error: could not convert tokens */; }
+fn f() { let _ = /* parse error: expected expression */
+let _ = 0;; }
 "#]],
     )
 }
diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs
index 82fc385040e..2bfda1aff2e 100644
--- a/crates/ide/src/hover/tests.rs
+++ b/crates/ide/src/hover/tests.rs
@@ -1148,7 +1148,7 @@ fn foo() { let a = id!([0u32, bar($0)] ); }
 fn test_hover_through_literal_string_in_macro() {
     check(
         r#"
-macro_rules! arr { ($($tt:tt)*) => { [$($tt)*)] } }
+macro_rules! arr { ($($tt:tt)*) => { [$($tt)*] } }
 fn foo() {
     let mastered_for_itunes = "";
     let _ = arr!("Tr$0acks", &mastered_for_itunes);
diff --git a/crates/mbe/src/syntax_bridge.rs b/crates/mbe/src/syntax_bridge.rs
index 1141365e82c..7d7807206f4 100644
--- a/crates/mbe/src/syntax_bridge.rs
+++ b/crates/mbe/src/syntax_bridge.rs
@@ -1,7 +1,7 @@
 //! Conversions between [`SyntaxNode`] and [`tt::TokenTree`].
 
 use rustc_hash::{FxHashMap, FxHashSet};
-use stdx::non_empty_vec::NonEmptyVec;
+use stdx::{never, non_empty_vec::NonEmptyVec};
 use syntax::{
     ast::{self, make::tokens::doc_comment},
     AstToken, Parse, PreorderWithTokens, SmolStr, SyntaxElement, SyntaxKind,
@@ -66,8 +66,7 @@ pub fn token_tree_to_syntax_node(
             parser::Step::Error { msg } => tree_sink.error(msg.to_string()),
         }
     }
-    if tree_sink.roots.len() != 1 {
-        cov_mark::hit!(expansion_does_not_parse_as_expression);
+    if never!(tree_sink.roots.len() != 1) {
         return Err(ExpandError::ConversionError);
     }
     //FIXME: would be cool to report errors
diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs
index c6c111c9a87..0240a6f14f6 100644
--- a/crates/parser/src/grammar.rs
+++ b/crates/parser/src/grammar.rs
@@ -148,6 +148,19 @@ pub(crate) mod entry {
             }
             m.complete(p, ERROR);
         }
+
+        pub(crate) fn meta_item(p: &mut Parser) {
+            let m = p.start();
+            attributes::meta(p);
+            if p.at(EOF) {
+                m.abandon(p);
+                return;
+            }
+            while !p.at(EOF) {
+                p.bump_any();
+            }
+            m.complete(p, ERROR);
+        }
     }
 }
 
diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs
index 491a657a34d..9723a17c64a 100644
--- a/crates/parser/src/lib.rs
+++ b/crates/parser/src/lib.rs
@@ -99,9 +99,11 @@ impl PrefixEntryPoint {
 /// ```
 ///
 /// the input to the macro will be parsed with [`PrefixEntryPoint::Item`], and
-/// the result will be [`TopEntryPoint::Items`].
+/// the result will be [`TopEntryPoint::MacroItems`].
 ///
-/// This *should* (but currently doesn't) guarantee that all input is consumed.
+/// [`TopEntryPoint::parse`] makes a guarantee that
+///   * all input is consumed
+///   * the result is a valid tree (there's one root node)
 #[derive(Debug)]
 pub enum TopEntryPoint {
     SourceFile,
@@ -124,13 +126,29 @@ impl TopEntryPoint {
             TopEntryPoint::Pattern => grammar::entry::top::pattern,
             TopEntryPoint::Type => grammar::entry::top::type_,
             TopEntryPoint::Expr => grammar::entry::top::expr,
-            // FIXME
-            TopEntryPoint::MetaItem => grammar::entry::prefix::meta_item,
+            TopEntryPoint::MetaItem => grammar::entry::top::meta_item,
         };
         let mut p = parser::Parser::new(input);
         entry_point(&mut p);
         let events = p.finish();
-        event::process(events)
+        let res = event::process(events);
+
+        if cfg!(debug_assertions) {
+            let mut depth = 0;
+            let mut first = true;
+            for step in res.iter() {
+                assert!(depth > 0 || first);
+                first = false;
+                match step {
+                    Step::Enter { .. } => depth += 1,
+                    Step::Exit => depth -= 1,
+                    Step::Token { .. } | Step::Error { .. } => (),
+                }
+            }
+            assert!(!first, "no tree at all");
+        }
+
+        res
     }
 }