Repository: rust-analyzer/rust-analyzer
Pull request #11166 (2022-01-02 15:37:22)

minor: Simplify
bors r+

bors[bot]: Build failed:
  * [Rust (ubuntu-latest)](https://github.com/rust-analyzer/rust-analyzer/runs/4684900256?check_suite_focus=true)

Patch:
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs
index c88b5639f0..3369e3e5fe 100644
--- a/crates/hir_expand/src/db.rs
+++ b/crates/hir_expand/src/db.rs
@@ -215,8 +215,6 @@ fn parse_or_expand(db: &dyn AstDatabase, file_id: HirFileId) -> Option<SyntaxNod
     match file_id.0 {
         HirFileIdRepr::FileId(file_id) => Some(db.parse(file_id).tree().syntax().clone()),
         HirFileIdRepr::MacroFile(macro_file) => {
-            // FIXME: Note how we convert from `Parse` to `SyntaxNode` here,
-            // forgetting about parse errors.
             db.parse_macro_expansion(macro_file).value.map(|(it, _)| it.syntax_node())
         }
     }
diff --git a/crates/mbe/src/expander/matcher.rs b/crates/mbe/src/expander/matcher.rs
index bcda2381a4..910724411d 100644
--- a/crates/mbe/src/expander/matcher.rs
+++ b/crates/mbe/src/expander/matcher.rs
@@ -571,18 +571,18 @@ fn match_loop(pattern: &MetaTemplate, src: &tt::Subtree) -> Match {
 
         if !error_items.is_empty() {
             error_recover_item = error_items.pop().map(|it| it.bindings);
-        } else if !eof_items.is_empty() {
-            error_recover_item = Some(eof_items[0].bindings.clone());
+        } else if let [state, ..] = &*eof_items {
+            error_recover_item = Some(state.bindings.clone());
         }
 
         // We need to do some post processing after the `match_loop_inner`.
         // If we reached the EOF, check that there is EXACTLY ONE possible matcher. Otherwise,
         // either the parse is ambiguous (which should never happen) or there is a syntax error.
         if src.peek_n(0).is_none() && stack.is_empty() {
-            if eof_items.len() == 1 {
+            if let [state] = &*eof_items {
                 // remove all errors, because it is the correct answer !
                 res = Match::default();
-                res.bindings = bindings_builder.build(&eof_items[0].bindings);
+                res.bindings = bindings_builder.build(&state.bindings);
             } else {
                 // Error recovery
                 if let Some(item) = error_recover_item {
@@ -598,10 +598,10 @@ fn match_loop(pattern: &MetaTemplate, src: &tt::Subtree) -> Match {
         //
         // Another possibility is that we need to call out to parse some rust nonterminal
         // (black-box) parser. However, if there is not EXACTLY ONE of these, something is wrong.
-        if (bb_items.is_empty() && next_items.is_empty())
-            || (!bb_items.is_empty() && !next_items.is_empty())
-            || bb_items.len() > 1
-        {
+        let has_leftover_tokens = (bb_items.is_empty() && next_items.is_empty())
+            || !(bb_items.is_empty() || next_items.is_empty())
+            || bb_items.len() > 1;
+        if has_leftover_tokens {
             res.unmatched_tts += src.len();
             while let Some(it) = stack.pop() {
                 src = it;
@@ -624,7 +624,11 @@ fn match_loop(pattern: &MetaTemplate, src: &tt::Subtree) -> Match {
                     stack.push(src.clone());
                     src = TtIter::new(subtree);
                 }
-                None if !stack.is_empty() => src = stack.pop().unwrap(),
+                None => {
+                    if let Some(iter) = stack.pop() {
+                        src = iter;
+                    }
+                }
                 _ => (),
             }
         }
@@ -662,29 +666,23 @@ fn match_loop(pattern: &MetaTemplate, src: &tt::Subtree) -> Match {
 fn match_leaf(lhs: &tt::Leaf, src: &mut TtIter) -> Result<(), ExpandError> {
     let rhs = match src.expect_leaf() {
         Ok(l) => l,
-        Err(()) => {
-            return Err(err!("expected leaf: `{}`", lhs));
-        }
+        Err(()) => return Err(err!("expected leaf: `{}`", lhs)),
     };
     match (lhs, rhs) {
         (
             tt::Leaf::Punct(tt::Punct { char: lhs, .. }),
             tt::Leaf::Punct(tt::Punct { char: rhs, .. }),
-        ) if lhs == rhs => (),
+        ) if lhs == rhs => Ok(()),
         (
             tt::Leaf::Ident(tt::Ident { text: lhs, .. }),
             tt::Leaf::Ident(tt::Ident { text: rhs, .. }),
-        ) if lhs == rhs => (),
+        ) if lhs == rhs => Ok(()),
         (
             tt::Leaf::Literal(tt::Literal { text: lhs, .. }),
             tt::Leaf::Literal(tt::Literal { text: rhs, .. }),
-        ) if lhs == rhs => (),
-        _ => {
-            return Err(ExpandError::UnexpectedToken);
-        }
+        ) if lhs == rhs => Ok(()),
+        _ => Err(ExpandError::UnexpectedToken),
     }
-
-    Ok(())
 }
 
 fn match_meta_var(kind: &str, input: &mut TtIter) -> ExpandResult<Option<Fragment>> {
diff --git a/crates/mbe/src/expander/transcriber.rs b/crates/mbe/src/expander/transcriber.rs
index 98b37dd122..b5ae5b91bb 100644
--- a/crates/mbe/src/expander/transcriber.rs
+++ b/crates/mbe/src/expander/transcriber.rs
@@ -4,11 +4,10 @@
 use syntax::SmolStr;
 use tt::{Delimiter, Subtree};
 
-use super::ExpandResult;
 use crate::{
     expander::{Binding, Bindings, Fragment},
     parser::{Op, RepeatKind, Separator},
-    ExpandError, MetaTemplate,
+    ExpandError, ExpandResult, MetaTemplate,
 };
 
 impl Bindings {
@@ -17,36 +16,36 @@ impl Bindings {
     }
 
     fn get(&self, name: &str, nesting: &mut [NestingState]) -> Result<&Fragment, ExpandError> {
-        let mut b: &Binding = self.inner.get(name).ok_or_else(|| {
-            ExpandError::BindingError(format!("could not find binding `{}`", name))
-        })?;
+        macro_rules! binding_err {
+            ($($arg:tt)*) => { ExpandError::BindingError(format!($($arg)*)) };
+        }
+
+        let mut b: &Binding = self
+            .inner
+            .get(name)
+            .ok_or_else(|| binding_err!("could not find binding `{}`", name))?;
         for nesting_state in nesting.iter_mut() {
             nesting_state.hit = true;
             b = match b {
                 Binding::Fragment(_) => break,
                 Binding::Nested(bs) => bs.get(nesting_state.idx).ok_or_else(|| {
                     nesting_state.at_end = true;
-                    ExpandError::BindingError(format!("could not find nested binding `{}`", name))
+                    binding_err!("could not find nested binding `{}`", name)
                 })?,
                 Binding::Empty => {
                     nesting_state.at_end = true;
-                    return Err(ExpandError::BindingError(format!(
-                        "could not find empty binding `{}`",
-                        name
-                    )));
+                    return Err(binding_err!("could not find empty binding `{}`", name));
                 }
             };
         }
         match b {
             Binding::Fragment(it) => Ok(it),
-            Binding::Nested(_) => Err(ExpandError::BindingError(format!(
-                "expected simple binding, found nested binding `{}`",
-                name
-            ))),
-            Binding::Empty => Err(ExpandError::BindingError(format!(
-                "expected simple binding, found empty binding `{}`",
-                name
-            ))),
+            Binding::Nested(_) => {
+                Err(binding_err!("expected simple binding, found nested binding `{}`", name))
+            }
+            Binding::Empty => {
+                Err(binding_err!("expected simple binding, found empty binding `{}`", name))
+            }
         }
     }
 }
@@ -109,7 +108,7 @@ fn expand_subtree(
         }
     }
     // drain the elements added in this instance of expand_subtree
-    let tts = arena.drain(start_elements..arena.len()).collect();
+    let tts = arena.drain(start_elements..).collect();
     ExpandResult { value: tt::Subtree { delimiter, token_trees: tts }, err }
 }
 
@@ -193,23 +192,22 @@ fn expand_repeat(
         push_subtree(&mut buf, t);
 
         if let Some(sep) = separator {
-            match sep {
+            has_seps = match sep {
                 Separator::Ident(ident) => {
-                    has_seps = 1;
                     buf.push(tt::Leaf::from(ident.clone()).into());
+                    1
                 }
                 Separator::Literal(lit) => {
-                    has_seps = 1;
                     buf.push(tt::Leaf::from(lit.clone()).into());
+                    1
                 }
-
                 Separator::Puncts(puncts) => {
-                    has_seps = puncts.len();
-                    for punct in puncts {
-                        buf.push(tt::Leaf::from(*punct).into());
+                    for &punct in puncts {
+                        buf.push(tt::Leaf::from(punct).into());
                     }
+                    puncts.len()
                 }
-            }
+            };
         }
 
         if RepeatKind::ZeroOrOne == kind {
diff --git a/crates/mbe/src/parser.rs b/crates/mbe/src/parser.rs
index 7543054494..ef29380557 100644
--- a/crates/mbe/src/parser.rs
+++ b/crates/mbe/src/parser.rs
@@ -41,7 +41,7 @@ impl MetaTemplate {
         let mut res = Vec::new();
         while let Some(first) = src.next() {
             let op = next_op(first, &mut src, mode)?;
-            res.push(op)
+            res.push(op);
         }
 
         Ok(MetaTemplate(res))
@@ -110,12 +110,6 @@ macro_rules! err {
     };
 }
 
-macro_rules! bail {
-    ($($tt:tt)*) => {
-        return Err(err!($($tt)*))
-    };
-}
-
 fn next_op<'a>(first: &tt::TokenTree, src: &mut TtIter<'a>, mode: Mode) -> Result<Op, ParseError> {
     let res = match first {
         tt::TokenTree::Leaf(leaf @ tt::Leaf::Punct(tt::Punct { char: '$', .. })) => {
@@ -131,26 +125,24 @@ fn next_op<'a>(first: &tt::TokenTree, src: &mut TtIter<'a>, mode: Mode) -> Resul
                     Op::Repeat { tokens, separator, kind }
                 }
                 tt::TokenTree::Leaf(leaf) => match leaf {
-                    tt::Leaf::Punct(_) => return Err(ParseError::Expected("ident".to_string())),
                     tt::Leaf::Ident(ident) if ident.text == "crate" => {
                         // We simply produce identifier `$crate` here. And it will be resolved when lowering ast to Path.
                         Op::Leaf(tt::Leaf::from(tt::Ident { text: "$crate".into(), id: ident.id }))
                     }
                     tt::Leaf::Ident(ident) => {
-                        let name = ident.text.clone();
                         let kind = eat_fragment_kind(src, mode)?;
+                        let name = ident.text.clone();
                         let id = ident.id;
                         Op::Var { name, kind, id }
                     }
-                    tt::Leaf::Literal(lit) => {
-                        if is_boolean_literal(lit) {
-                            let name = lit.text.clone();
-                            let kind = eat_fragment_kind(src, mode)?;
-                            let id = lit.id;
-                            Op::Var { name, kind, id }
-                        } else {
-                            bail!("bad var 2");
-                        }
+                    tt::Leaf::Literal(lit) if is_boolean_literal(lit) => {
+                        let kind = eat_fragment_kind(src, mode)?;
+                        let name = lit.text.clone();
+                        let id = lit.id;
+                        Op::Var { name, kind, id }
+                    }
+                    tt::Leaf::Punct(_) | tt::Leaf::Literal(_) => {
+                        return Err(ParseError::Expected("ident".to_string()))
                     }
                 },
             }
@@ -166,8 +158,8 @@ fn next_op<'a>(first: &tt::TokenTree, src: &mut TtIter<'a>, mode: Mode) -> Resul
 
 fn eat_fragment_kind(src: &mut TtIter<'_>, mode: Mode) -> Result<Option<SmolStr>, ParseError> {
     if let Mode::Pattern = mode {
-        src.expect_char(':').map_err(|()| err!("bad fragment specifier 1"))?;
-        let ident = src.expect_ident().map_err(|()| err!("bad fragment specifier 1"))?;
+        src.expect_char(':').map_err(|()| err!("missing fragment specifier"))?;
+        let ident = src.expect_ident().map_err(|()| err!("missing fragment specifier"))?;
         return Ok(Some(ident.text.clone()));
     };
     Ok(None)
@@ -199,21 +191,15 @@ fn parse_repeat(src: &mut TtIter) -> Result<(Option<Separator>, RepeatKind), Par
                     '*' => RepeatKind::ZeroOrMore,
                     '+' => RepeatKind::OneOrMore,
                     '?' => RepeatKind::ZeroOrOne,
-                    _ => {
-                        match &mut separator {
-                            Separator::Puncts(puncts) => {
-                                if puncts.len() == 3 {
-                                    return Err(ParseError::InvalidRepeat);
-                                }
-                                puncts.push(*punct)
-                            }
-                            _ => return Err(ParseError::InvalidRepeat),
+                    _ => match &mut separator {
+                        Separator::Puncts(puncts) if puncts.len() != 3 => {
+                            puncts.push(*punct);
+                            continue;
                         }
-                        continue;
-                    }
+                        _ => return Err(ParseError::InvalidRepeat),
+                    },
                 };
-                let separator = if has_sep { Some(separator) } else { None };
-                return Ok((separator, repeat_kind));
+                return Ok((has_sep.then(|| separator), repeat_kind));
             }
         }
     }
diff --git a/crates/mbe/src/syntax_bridge.rs b/crates/mbe/src/syntax_bridge.rs
index 5d70558241..8021e63f7f 100644
--- a/crates/mbe/src/syntax_bridge.rs
+++ b/crates/mbe/src/syntax_bridge.rs
@@ -66,6 +66,10 @@ pub fn token_tree_to_syntax_node(
             parser::Step::Error { msg } => tree_sink.error(msg.to_string()),
         }
     }
+    if tree_sink.roots.len() != 1 {
+        return Err(ExpandError::ConversionError);
+    }
+    //FIXME: would be cool to report errors
     let (parse, range_map) = tree_sink.finish();
     Ok((parse, range_map))
 }
@@ -280,7 +284,7 @@ fn convert_tokens<C: TokenConvertor>(conv: &mut C) -> tt::Subtree {
         parent.subtree.token_trees.extend(entry.subtree.token_trees);
     }
 
-    let subtree = stack.into_last().subtree;
+    let subtree = stack.into_first().subtree;
     if let [tt::TokenTree::Subtree(first)] = &*subtree.token_trees {
         first.clone()
     } else {
@@ -610,6 +614,10 @@ struct TtTreeSink<'a> {
     text_pos: TextSize,
     inner: SyntaxTreeBuilder,
     token_map: TokenMap,
+
+    // Number of roots
+    // Use for detect ill-form tree which is not single root
+    roots: smallvec::SmallVec<[usize; 1]>,
 }
 
 impl<'a> TtTreeSink<'a> {
@@ -620,6 +628,7 @@ impl<'a> TtTreeSink<'a> {
             open_delims: FxHashMap::default(),
             text_pos: 0.into(),
             inner: SyntaxTreeBuilder::default(),
+            roots: smallvec::SmallVec::new(),
             token_map: TokenMap::default(),
         }
     }
@@ -724,10 +733,16 @@ impl<'a> TtTreeSink<'a> {
 
     fn start_node(&mut self, kind: SyntaxKind) {
         self.inner.start_node(kind);
+
+        match self.roots.last_mut() {
+            None | Some(0) => self.roots.push(1),
+            Some(n) => *n += 1,
+        };
     }
 
     fn finish_node(&mut self) {
         self.inner.finish_node();
+        *self.roots.last_mut().unwrap() -= 1;
     }
 
     fn error(&mut self, error: String) {
diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs
index 0240a6f14f..e1a265d817 100644
--- a/crates/parser/src/grammar.rs
+++ b/crates/parser/src/grammar.rs
@@ -109,58 +109,6 @@ pub(crate) mod entry {
             items::mod_contents(p, false);
             m.complete(p, MACRO_ITEMS);
         }
-
-        pub(crate) fn pattern(p: &mut Parser) {
-            let m = p.start();
-            patterns::pattern_single(p);
-            if p.at(EOF) {
-                m.abandon(p);
-                return;
-            }
-            while !p.at(EOF) {
-                p.bump_any();
-            }
-            m.complete(p, ERROR);
-        }
-
-        pub(crate) fn type_(p: &mut Parser) {
-            let m = p.start();
-            types::type_(p);
-            if p.at(EOF) {
-                m.abandon(p);
-                return;
-            }
-            while !p.at(EOF) {
-                p.bump_any();
-            }
-            m.complete(p, ERROR);
-        }
-
-        pub(crate) fn expr(p: &mut Parser) {
-            let m = p.start();
-            expressions::expr(p);
-            if p.at(EOF) {
-                m.abandon(p);
-                return;
-            }
-            while !p.at(EOF) {
-                p.bump_any();
-            }
-            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 cff4ca4ba2..c5014be6c3 100644
--- a/crates/parser/src/lib.rs
+++ b/crates/parser/src/lib.rs
@@ -41,75 +41,6 @@ pub use crate::{
     syntax_kind::SyntaxKind,
 };
 
-/// Parse the whole of the input as a given syntactic construct.
-///
-/// This covers two main use-cases:
-///
-///   * Parsing a Rust file.
-///   * Parsing a result of macro expansion.
-///
-/// That is, for something like
-///
-/// ```
-/// quick_check! {
-///    fn prop() {}
-/// }
-/// ```
-///
-/// the input to the macro will be parsed with [`PrefixEntryPoint::Item`], and
-/// the result will be [`TopEntryPoint::MacroItems`].
-///
-/// [`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,
-    MacroStmts,
-    MacroItems,
-    Pattern,
-    Type,
-    Expr,
-    /// Edge case -- macros generally don't expand to attributes, with the
-    /// exception of `cfg_attr` which does!
-    MetaItem,
-}
-
-impl TopEntryPoint {
-    pub fn parse(&self, input: &Input) -> Output {
-        let entry_point: fn(&'_ mut parser::Parser) = match self {
-            TopEntryPoint::SourceFile => grammar::entry::top::source_file,
-            TopEntryPoint::MacroStmts => grammar::entry::top::macro_stmts,
-            TopEntryPoint::MacroItems => grammar::entry::top::macro_items,
-            TopEntryPoint::Pattern => grammar::entry::top::pattern,
-            TopEntryPoint::Type => grammar::entry::top::type_,
-            TopEntryPoint::Expr => grammar::entry::top::expr,
-            TopEntryPoint::MetaItem => grammar::entry::top::meta_item,
-        };
-        let mut p = parser::Parser::new(input);
-        entry_point(&mut p);
-        let events = p.finish();
-        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
-    }
-}
-
 /// Parse a prefix of the input as a given syntactic construct.
 ///
 /// This is used by macro-by-example parser to implement things like `$i:item`
@@ -152,6 +83,55 @@ impl PrefixEntryPoint {
     }
 }
 
+/// Parse the whole of the input as a given syntactic construct.
+///
+/// This covers two main use-cases:
+///
+///   * Parsing a Rust file.
+///   * Parsing a result of macro expansion.
+///
+/// That is, for something like
+///
+/// ```
+/// quick_check! {
+///    fn prop() {}
+/// }
+/// ```
+///
+/// the input to the macro will be parsed with [`PrefixEntryPoint::Item`], and
+/// the result will be [`TopEntryPoint::Items`].
+///
+/// This *should* (but currently doesn't) guarantee that all input is consumed.
+#[derive(Debug)]
+pub enum TopEntryPoint {
+    SourceFile,
+    MacroStmts,
+    MacroItems,
+    Pattern,
+    Type,
+    Expr,
+    MetaItem,
+}
+
+impl TopEntryPoint {
+    pub fn parse(&self, input: &Input) -> Output {
+        let entry_point: fn(&'_ mut parser::Parser) = match self {
+            TopEntryPoint::SourceFile => grammar::entry::top::source_file,
+            TopEntryPoint::MacroStmts => grammar::entry::top::macro_stmts,
+            TopEntryPoint::MacroItems => grammar::entry::top::macro_items,
+            // FIXME
+            TopEntryPoint::Pattern => grammar::entry::prefix::pat,
+            TopEntryPoint::Type => grammar::entry::prefix::ty,
+            TopEntryPoint::Expr => grammar::entry::prefix::expr,
+            TopEntryPoint::MetaItem => grammar::entry::prefix::meta_item,
+        };
+        let mut p = parser::Parser::new(input);
+        entry_point(&mut p);
+        let events = p.finish();
+        event::process(events)
+    }
+}
+
 /// A parsing function for a specific braced-block.
 pub struct Reparser(fn(&mut parser::Parser));
 
diff --git a/crates/stdx/src/non_empty_vec.rs b/crates/stdx/src/non_empty_vec.rs
index 342194c783..199ee18b94 100644
--- a/crates/stdx/src/non_empty_vec.rs
+++ b/crates/stdx/src/non_empty_vec.rs
@@ -1,39 +1,45 @@
-//! See [`NonEmptyVec`].
+//! A [`Vec`] that is guaranteed to at least contain one element.
 
-/// A [`Vec`] that is guaranteed to at least contain one element.
-pub struct NonEmptyVec<T> {
-    first: T,
-    rest: Vec<T>,
-}
+pub struct NonEmptyVec<T>(Vec<T>);
 
 impl<T> NonEmptyVec<T> {
     #[inline]
-    pub fn new(first: T) -> Self {
-        NonEmptyVec { first, rest: Vec::new() }
+    pub fn new(initial: T) -> Self {
+        NonEmptyVec(vec![initial])
     }
 
     #[inline]
     pub fn last_mut(&mut self) -> &mut T {
-        self.rest.last_mut().unwrap_or(&mut self.first)
+        match self.0.last_mut() {
+            Some(it) => it,
+            None => unreachable!(),
+        }
     }
 
     #[inline]
     pub fn pop(&mut self) -> Option<T> {
-        self.rest.pop()
+        if self.0.len() <= 1 {
+            None
+        } else {
+            self.0.pop()
+        }
     }
 
     #[inline]
     pub fn push(&mut self, value: T) {
-        self.rest.push(value)
+        self.0.push(value)
     }
 
     #[inline]
     pub fn len(&self) -> usize {
-        1 + self.rest.len()
+        self.0.len()
     }
 
     #[inline]
-    pub fn into_last(mut self) -> T {
-        self.rest.pop().unwrap_or(self.first)
+    pub fn into_first(mut self) -> T {
+        match self.0.pop() {
+            Some(it) => it,
+            None => unreachable!(),
+        }
     }
 }


Test patch:
diff --git a/crates/hir_def/src/macro_expansion_tests/mbe.rs b/crates/hir_def/src/macro_expansion_tests/mbe.rs
index 2cd70a84c5..466c85fc5b 100644
--- a/crates/hir_def/src/macro_expansion_tests/mbe.rs
+++ b/crates/hir_def/src/macro_expansion_tests/mbe.rs
@@ -85,6 +85,26 @@ impl From<Subtree> 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/meta_syntax.rs b/crates/hir_def/src/macro_expansion_tests/mbe/meta_syntax.rs
index dd5effa368..2de10ddbdf 100644
--- a/crates/hir_def/src/macro_expansion_tests/mbe/meta_syntax.rs
+++ b/crates/hir_def/src/macro_expansion_tests/mbe/meta_syntax.rs
@@ -69,11 +69,11 @@ macro_rules! e3 { ($(i:ident)_) => () }
 /* error: invalid macro definition: invalid repeat */
 
 macro_rules! f1 { ($i) => ($i) }
-/* error: invalid macro definition: bad fragment specifier 1 */
+/* error: invalid macro definition: missing fragment specifier */
 macro_rules! f2 { ($i:) => ($i) }
-/* error: invalid macro definition: bad fragment specifier 1 */
+/* error: invalid macro definition: missing fragment specifier */
 macro_rules! f3 { ($i:_) => () }
-/* error: invalid macro definition: bad fragment specifier 1 */
+/* error: invalid macro definition: missing fragment specifier */
 "#]],
     )
 }
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 5f4b7d6d0b..291f99330f 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,9 +2,7 @@
 //! Rather, token trees are an explicit bridge between the parser and
 //! (procedural or declarative) macros.
 //!
-//! 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.
+//! This module tests tt <-> syntax tree conversion specifically
 use expect_test::expect;
 
 use crate::macro_expansion_tests::check;
@@ -102,49 +100,3 @@ macro_rules! m2 { ($x:ident) => {} }
 "#]],
     )
 }
-
-#[test]
-fn expansion_does_not_parse_as_expression() {
-    check(
-        r#"
-macro_rules! stmts {
-    () => { let _ = 0; }
-}
-
-fn f() { let _ = stmts!/*+errors*/(); }
-"#,
-        expect![[r#"
-macro_rules! stmts {
-    () => { let _ = 0; }
-}
-
-fn f() { let _ = /* parse error: expected expression */
-let _ = 0;; }
-"#]],
-    )
-}
-
-#[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)left overs = ();
-    let /* parse error: expected pattern */
-$ = ();
-}
-"#]],
-    )
-}
diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs
index 2bfda1aff2..82fc385040 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/parser/src/tests.rs b/crates/parser/src/tests.rs
index cb25abdfea..fb4885e98d 100644
--- a/crates/parser/src/tests.rs
+++ b/crates/parser/src/tests.rs
@@ -1,6 +1,5 @@
 mod sourcegen_inline_tests;
-mod top_entries;
-mod prefix_entries;
+mod entries;
 
 use std::{
     fmt::Write,
@@ -10,7 +9,7 @@ use std::{
 
 use expect_test::expect_file;
 
-use crate::{LexedStr, TopEntryPoint};
+use crate::LexedStr;
 
 #[test]
 fn lex_ok() {
@@ -46,7 +45,7 @@ fn lex(text: &str) -> String {
 #[test]
 fn parse_ok() {
     for case in TestCase::list("parser/ok") {
-        let (actual, errors) = parse(TopEntryPoint::SourceFile, &case.text);
+        let (actual, errors) = parse(&case.text);
         assert!(!errors, "errors in an OK file {}:\n{}", case.rs.display(), actual);
         expect_file![case.txt].assert_eq(&actual);
     }
@@ -55,7 +54,7 @@ fn parse_ok() {
 #[test]
 fn parse_inline_ok() {
     for case in TestCase::list("parser/inline/ok") {
-        let (actual, errors) = parse(TopEntryPoint::SourceFile, &case.text);
+        let (actual, errors) = parse(&case.text);
         assert!(!errors, "errors in an OK file {}:\n{}", case.rs.display(), actual);
         expect_file![case.txt].assert_eq(&actual);
     }
@@ -64,7 +63,7 @@ fn parse_inline_ok() {
 #[test]
 fn parse_err() {
     for case in TestCase::list("parser/err") {
-        let (actual, errors) = parse(TopEntryPoint::SourceFile, &case.text);
+        let (actual, errors) = parse(&case.text);
         assert!(errors, "no errors in an ERR file {}:\n{}", case.rs.display(), actual);
         expect_file![case.txt].assert_eq(&actual)
     }
@@ -73,54 +72,36 @@ fn parse_err() {
 #[test]
 fn parse_inline_err() {
     for case in TestCase::list("parser/inline/err") {
-        let (actual, errors) = parse(TopEntryPoint::SourceFile, &case.text);
+        let (actual, errors) = parse(&case.text);
         assert!(errors, "no errors in an ERR file {}:\n{}", case.rs.display(), actual);
         expect_file![case.txt].assert_eq(&actual)
     }
 }
 
-fn parse(entry: TopEntryPoint, text: &str) -> (String, bool) {
+fn parse(text: &str) -> (String, bool) {
     let lexed = LexedStr::new(text);
     let input = lexed.to_input();
-    let output = entry.parse(&input);
+    let output = crate::TopEntryPoint::SourceFile.parse(&input);
 
     let mut buf = String::new();
     let mut errors = Vec::new();
     let mut indent = String::new();
-    let mut depth = 0;
-    let mut len = 0;
     lexed.intersperse_trivia(&output, &mut |step| match step {
         crate::StrStep::Token { kind, text } => {
-            assert!(depth > 0);
-            len += text.len();
             write!(buf, "{}", indent).unwrap();
             write!(buf, "{:?} {:?}\n", kind, text).unwrap();
         }
         crate::StrStep::Enter { kind } => {
-            assert!(depth > 0 || len == 0);
-            depth += 1;
             write!(buf, "{}", indent).unwrap();
             write!(buf, "{:?}\n", kind).unwrap();
             indent.push_str("  ");
         }
         crate::StrStep::Exit => {
-            assert!(depth > 0);
-            depth -= 1;
             indent.pop();
             indent.pop();
         }
-        crate::StrStep::Error { msg, pos } => {
-            assert!(depth > 0);
-            errors.push(format!("error {}: {}\n", pos, msg))
-        }
+        crate::StrStep::Error { msg, pos } => errors.push(format!("error {}: {}\n", pos, msg)),
     });
-    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/entries.rs b/crates/parser/src/tests/entries.rs
new file mode 100644
index 0000000000..d52c6fbb16
--- /dev/null
+++ b/crates/parser/src/tests/entries.rs
@@ -0,0 +1,110 @@
+use crate::{LexedStr, PrefixEntryPoint, Step};
+
+#[test]
+fn vis() {
+    check_prefix(PrefixEntryPoint::Vis, "pub(crate) fn foo() {}", "pub(crate)");
+    check_prefix(PrefixEntryPoint::Vis, "fn foo() {}", "");
+    check_prefix(PrefixEntryPoint::Vis, "pub(fn foo() {}", "pub");
+    check_prefix(PrefixEntryPoint::Vis, "pub(crate fn foo() {}", "pub(crate");
+    check_prefix(PrefixEntryPoint::Vis, "crate fn foo() {}", "crate");
+}
+
+#[test]
+fn block() {
+    check_prefix(PrefixEntryPoint::Block, "{}, 92", "{}");
+    check_prefix(PrefixEntryPoint::Block, "{, 92)", "{, 92)");
+    check_prefix(PrefixEntryPoint::Block, "()", "");
+}
+
+#[test]
+fn stmt() {
+    check_prefix(PrefixEntryPoint::Stmt, "92; fn", "92");
+    check_prefix(PrefixEntryPoint::Stmt, "let _ = 92; 1", "let _ = 92");
+    check_prefix(PrefixEntryPoint::Stmt, "pub fn f() {} = 92", "pub fn f() {}");
+    check_prefix(PrefixEntryPoint::Stmt, "struct S;;", "struct S;");
+    check_prefix(PrefixEntryPoint::Stmt, "fn f() {};", "fn f() {}");
+    check_prefix(PrefixEntryPoint::Stmt, ";;;", ";");
+    check_prefix(PrefixEntryPoint::Stmt, "+", "+");
+    check_prefix(PrefixEntryPoint::Stmt, "@", "@");
+    check_prefix(PrefixEntryPoint::Stmt, "loop {} - 1", "loop {}");
+}
+
+#[test]
+fn pat() {
+    check_prefix(PrefixEntryPoint::Pat, "x y", "x");
+    check_prefix(PrefixEntryPoint::Pat, "fn f() {}", "fn");
+    // FIXME: This one is wrong, we should consume only one pattern.
+    check_prefix(PrefixEntryPoint::Pat, ".. ..", ".. ..");
+}
+
+#[test]
+fn ty() {
+    check_prefix(PrefixEntryPoint::Ty, "fn() foo", "fn()");
+    check_prefix(PrefixEntryPoint::Ty, "Clone + Copy + fn", "Clone + Copy +");
+    check_prefix(PrefixEntryPoint::Ty, "struct f", "struct");
+}
+
+#[test]
+fn expr() {
+    check_prefix(PrefixEntryPoint::Expr, "92 92", "92");
+    check_prefix(PrefixEntryPoint::Expr, "+1", "+");
+    check_prefix(PrefixEntryPoint::Expr, "-1", "-1");
+    check_prefix(PrefixEntryPoint::Expr, "fn foo() {}", "fn");
+    check_prefix(PrefixEntryPoint::Expr, "#[attr] ()", "#[attr] ()");
+}
+
+#[test]
+fn path() {
+    check_prefix(PrefixEntryPoint::Path, "foo::bar baz", "foo::bar");
+    check_prefix(PrefixEntryPoint::Path, "foo::<> baz", "foo::<>");
+    check_prefix(PrefixEntryPoint::Path, "foo<> baz", "foo<>");
+    check_prefix(PrefixEntryPoint::Path, "Fn() -> i32?", "Fn() -> i32");
+    // FIXME: This shouldn't be accepted as path actually.
+    check_prefix(PrefixEntryPoint::Path, "<_>::foo", "<_>::foo");
+}
+
+#[test]
+fn item() {
+    // FIXME: This shouldn't consume the semicolon.
+    check_prefix(PrefixEntryPoint::Item, "fn foo() {};", "fn foo() {};");
+    check_prefix(PrefixEntryPoint::Item, "#[attr] pub struct S {} 92", "#[attr] pub struct S {}");
+    check_prefix(PrefixEntryPoint::Item, "item!{}?", "item!{}");
+    check_prefix(PrefixEntryPoint::Item, "????", "?");
+}
+
+#[test]
+fn meta_item() {
+    check_prefix(PrefixEntryPoint::MetaItem, "attr, ", "attr");
+    check_prefix(
+        PrefixEntryPoint::MetaItem,
+        "attr(some token {stream});",
+        "attr(some token {stream})",
+    );
+    check_prefix(PrefixEntryPoint::MetaItem, "path::attr = 2 * 2!", "path::attr = 2 * 2");
+}
+
+fn check_prefix(entry: PrefixEntryPoint, input: &str, prefix: &str) {
+    let lexed = LexedStr::new(input);
+    let input = lexed.to_input();
+
+    let mut n_tokens = 0;
+    for step in entry.parse(&input).iter() {
+        match step {
+            Step::Token { n_input_tokens, .. } => n_tokens += n_input_tokens as usize,
+            Step::Enter { .. } | Step::Exit | Step::Error { .. } => (),
+        }
+    }
+
+    let mut i = 0;
+    loop {
+        if n_tokens == 0 {
+            break;
+        }
+        if !lexed.kind(i).is_trivia() {
+            n_tokens -= 1;
+        }
+        i += 1;
+    }
+    let buf = &lexed.as_str()[..lexed.text_start(i)];
+    assert_eq!(buf, prefix);
+}
diff --git a/crates/parser/src/tests/prefix_entries.rs b/crates/parser/src/tests/prefix_entries.rs
deleted file mode 100644
index e626b4f27e..0000000000
--- a/crates/parser/src/tests/prefix_entries.rs
+++ /dev/null
@@ -1,107 +0,0 @@
-use crate::{LexedStr, PrefixEntryPoint, Step};
-
-#[test]
-fn vis() {
-    check(PrefixEntryPoint::Vis, "pub(crate) fn foo() {}", "pub(crate)");
-    check(PrefixEntryPoint::Vis, "fn foo() {}", "");
-    check(PrefixEntryPoint::Vis, "pub(fn foo() {}", "pub");
-    check(PrefixEntryPoint::Vis, "pub(crate fn foo() {}", "pub(crate");
-    check(PrefixEntryPoint::Vis, "crate fn foo() {}", "crate");
-}
-
-#[test]
-fn block() {
-    check(PrefixEntryPoint::Block, "{}, 92", "{}");
-    check(PrefixEntryPoint::Block, "{, 92)", "{, 92)");
-    check(PrefixEntryPoint::Block, "()", "");
-}
-
-#[test]
-fn stmt() {
-    check(PrefixEntryPoint::Stmt, "92; fn", "92");
-    check(PrefixEntryPoint::Stmt, "let _ = 92; 1", "let _ = 92");
-    check(PrefixEntryPoint::Stmt, "pub fn f() {} = 92", "pub fn f() {}");
-    check(PrefixEntryPoint::Stmt, "struct S;;", "struct S;");
-    check(PrefixEntryPoint::Stmt, "fn f() {};", "fn f() {}");
-    check(PrefixEntryPoint::Stmt, ";;;", ";");
-    check(PrefixEntryPoint::Stmt, "+", "+");
-    check(PrefixEntryPoint::Stmt, "@", "@");
-    check(PrefixEntryPoint::Stmt, "loop {} - 1", "loop {}");
-}
-
-#[test]
-fn pat() {
-    check(PrefixEntryPoint::Pat, "x y", "x");
-    check(PrefixEntryPoint::Pat, "fn f() {}", "fn");
-    // FIXME: This one is wrong, we should consume only one pattern.
-    check(PrefixEntryPoint::Pat, ".. ..", ".. ..");
-}
-
-#[test]
-fn ty() {
-    check(PrefixEntryPoint::Ty, "fn() foo", "fn()");
-    check(PrefixEntryPoint::Ty, "Clone + Copy + fn", "Clone + Copy +");
-    check(PrefixEntryPoint::Ty, "struct f", "struct");
-}
-
-#[test]
-fn expr() {
-    check(PrefixEntryPoint::Expr, "92 92", "92");
-    check(PrefixEntryPoint::Expr, "+1", "+");
-    check(PrefixEntryPoint::Expr, "-1", "-1");
-    check(PrefixEntryPoint::Expr, "fn foo() {}", "fn");
-    check(PrefixEntryPoint::Expr, "#[attr] ()", "#[attr] ()");
-}
-
-#[test]
-fn path() {
-    check(PrefixEntryPoint::Path, "foo::bar baz", "foo::bar");
-    check(PrefixEntryPoint::Path, "foo::<> baz", "foo::<>");
-    check(PrefixEntryPoint::Path, "foo<> baz", "foo<>");
-    check(PrefixEntryPoint::Path, "Fn() -> i32?", "Fn() -> i32");
-    // FIXME: This shouldn't be accepted as path actually.
-    check(PrefixEntryPoint::Path, "<_>::foo", "<_>::foo");
-}
-
-#[test]
-fn item() {
-    // FIXME: This shouldn't consume the semicolon.
-    check(PrefixEntryPoint::Item, "fn foo() {};", "fn foo() {};");
-    check(PrefixEntryPoint::Item, "#[attr] pub struct S {} 92", "#[attr] pub struct S {}");
-    check(PrefixEntryPoint::Item, "item!{}?", "item!{}");
-    check(PrefixEntryPoint::Item, "????", "?");
-}
-
-#[test]
-fn meta_item() {
-    check(PrefixEntryPoint::MetaItem, "attr, ", "attr");
-    check(PrefixEntryPoint::MetaItem, "attr(some token {stream});", "attr(some token {stream})");
-    check(PrefixEntryPoint::MetaItem, "path::attr = 2 * 2!", "path::attr = 2 * 2");
-}
-
-#[track_caller]
-fn check(entry: PrefixEntryPoint, input: &str, prefix: &str) {
-    let lexed = LexedStr::new(input);
-    let input = lexed.to_input();
-
-    let mut n_tokens = 0;
-    for step in entry.parse(&input).iter() {
-        match step {
-            Step::Token { n_input_tokens, .. } => n_tokens += n_input_tokens as usize,
-            Step::Enter { .. } | Step::Exit | Step::Error { .. } => (),
-        }
-    }
-
-    let mut i = 0;
-    loop {
-        if n_tokens == 0 {
-            break;
-        }
-        if !lexed.kind(i).is_trivia() {
-            n_tokens -= 1;
-        }
-        i += 1;
-    }
-    let buf = &lexed.as_str()[..lexed.text_start(i)];
-    assert_eq!(buf, prefix);
-}
diff --git a/crates/parser/src/tests/top_entries.rs b/crates/parser/src/tests/top_entries.rs
deleted file mode 100644
index 24e41b46f8..0000000000
--- a/crates/parser/src/tests/top_entries.rs
+++ /dev/null
@@ -1,310 +0,0 @@
-use expect_test::expect;
-
-use crate::TopEntryPoint;
-
-#[test]
-fn source_file() {
-    check(
-        TopEntryPoint::SourceFile,
-        "",
-        expect![[r#"
-        SOURCE_FILE
-    "#]],
-    );
-
-    check(
-        TopEntryPoint::SourceFile,
-        "struct S;",
-        expect![[r#"
-        SOURCE_FILE
-          STRUCT
-            STRUCT_KW "struct"
-            WHITESPACE " "
-            NAME
-              IDENT "S"
-            SEMICOLON ";"
-    "#]],
-    );
-
-    check(
-        TopEntryPoint::SourceFile,
-        "@error@",
-        expect![[r#"
-        SOURCE_FILE
-          ERROR
-            AT "@"
-          MACRO_CALL
-            PATH
-              PATH_SEGMENT
-                NAME_REF
-                  IDENT "error"
-          ERROR
-            AT "@"
-        error 0: expected an item
-        error 6: expected BANG
-        error 6: expected `{`, `[`, `(`
-        error 6: expected SEMICOLON
-        error 6: expected an item
-    "#]],
-    );
-}
-
-#[test]
-fn macro_stmt() {
-    check(
-        TopEntryPoint::MacroStmts,
-        "",
-        expect![[r#"
-            MACRO_STMTS
-        "#]],
-    );
-    check(
-        TopEntryPoint::MacroStmts,
-        "#!/usr/bin/rust",
-        expect![[r##"
-            MACRO_STMTS
-              ERROR
-                SHEBANG "#!/usr/bin/rust"
-            error 0: expected expression
-        "##]],
-    );
-    check(
-        TopEntryPoint::MacroStmts,
-        "let x = 1 2 struct S;",
-        expect![[r#"
-            MACRO_STMTS
-              LET_STMT
-                LET_KW "let"
-                WHITESPACE " "
-                IDENT_PAT
-                  NAME
-                    IDENT "x"
-                WHITESPACE " "
-                EQ "="
-                WHITESPACE " "
-                LITERAL
-                  INT_NUMBER "1"
-              WHITESPACE " "
-              EXPR_STMT
-                LITERAL
-                  INT_NUMBER "2"
-              WHITESPACE " "
-              STRUCT
-                STRUCT_KW "struct"
-                WHITESPACE " "
-                NAME
-                  IDENT "S"
-                SEMICOLON ";"
-        "#]],
-    );
-}
-
-#[test]
-fn macro_items() {
-    check(
-        TopEntryPoint::MacroItems,
-        "",
-        expect![[r#"
-            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 "}"
-        "#]],
-    );
-}
-
-#[test]
-fn macro_pattern() {
-    check(
-        TopEntryPoint::Pattern,
-        "",
-        expect![[r#"
-            ERROR
-            error 0: expected pattern
-        "#]],
-    );
-    check(
-        TopEntryPoint::Pattern,
-        "Some(_)",
-        expect![[r#"
-            TUPLE_STRUCT_PAT
-              PATH
-                PATH_SEGMENT
-                  NAME_REF
-                    IDENT "Some"
-              L_PAREN "("
-              WILDCARD_PAT
-                UNDERSCORE "_"
-              R_PAREN ")"
-        "#]],
-    );
-
-    check(
-        TopEntryPoint::Pattern,
-        "None leftover tokens",
-        expect![[r#"
-            ERROR
-              IDENT_PAT
-                NAME
-                  IDENT "None"
-              WHITESPACE " "
-              IDENT "leftover"
-              WHITESPACE " "
-              IDENT "tokens"
-        "#]],
-    );
-
-    check(
-        TopEntryPoint::Pattern,
-        "@err",
-        expect![[r#"
-            ERROR
-              ERROR
-                AT "@"
-              IDENT "err"
-            error 0: expected pattern
-        "#]],
-    );
-}
-
-#[test]
-fn type_() {
-    check(
-        TopEntryPoint::Type,
-        "",
-        expect![[r#"
-            ERROR
-            error 0: expected type
-        "#]],
-    );
-
-    check(
-        TopEntryPoint::Type,
-        "Option<!>",
-        expect![[r#"
-            PATH_TYPE
-              PATH
-                PATH_SEGMENT
-                  NAME_REF
-                    IDENT "Option"
-                  GENERIC_ARG_LIST
-                    L_ANGLE "<"
-                    TYPE_ARG
-                      NEVER_TYPE
-                        BANG "!"
-                    R_ANGLE ">"
-        "#]],
-    );
-    check(
-        TopEntryPoint::Type,
-        "() () ()",
-        expect![[r#"
-            ERROR
-              TUPLE_TYPE
-                L_PAREN "("
-                R_PAREN ")"
-              WHITESPACE " "
-              L_PAREN "("
-              R_PAREN ")"
-              WHITESPACE " "
-              L_PAREN "("
-              R_PAREN ")"
-        "#]],
-    );
-    check(
-        TopEntryPoint::Type,
-        "$$$",
-        expect![[r#"
-            ERROR
-              ERROR
-                DOLLAR "$"
-              DOLLAR "$"
-              DOLLAR "$"
-            error 0: expected type
-        "#]],
-    );
-}
-
-#[test]
-fn expr() {
-    check(
-        TopEntryPoint::Expr,
-        "",
-        expect![[r#"
-            ERROR
-            error 0: expected expression
-        "#]],
-    );
-    check(
-        TopEntryPoint::Expr,
-        "2 + 2 == 5",
-        expect![[r#"
-        BIN_EXPR
-          BIN_EXPR
-            LITERAL
-              INT_NUMBER "2"
-            WHITESPACE " "
-            PLUS "+"
-            WHITESPACE " "
-            LITERAL
-              INT_NUMBER "2"
-          WHITESPACE " "
-          EQ2 "=="
-          WHITESPACE " "
-          LITERAL
-            INT_NUMBER "5"
-    "#]],
-    );
-    check(
-        TopEntryPoint::Expr,
-        "let _ = 0;",
-        expect![[r#"
-        ERROR
-          LET_KW "let"
-          WHITESPACE " "
-          UNDERSCORE "_"
-          WHITESPACE " "
-          EQ "="
-          WHITESPACE " "
-          INT_NUMBER "0"
-          SEMICOLON ";"
-        error 0: expected expression
-    "#]],
-    );
-}
-
-#[track_caller]
-fn check(entry: TopEntryPoint, input: &str, expect: expect_test::Expect) {
-    let (parsed, _errors) = super::parse(entry, input);
-    expect.assert_eq(&parsed)
-}