Repository: rust-analyzer/rust-analyzer
Pull request #11165 (2022-01-02 14:45:51)

internal: start enforcing invariants for top-level entry points
bors r+
🤖


Patch:
diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs
index e1a265d817..6ffb4c191b 100644
--- a/crates/parser/src/grammar.rs
+++ b/crates/parser/src/grammar.rs
@@ -109,6 +109,32 @@ 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);
+        }
     }
 }
 
diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs
index c5014be6c3..72d529d6cf 100644
--- a/crates/parser/src/lib.rs
+++ b/crates/parser/src/lib.rs
@@ -110,6 +110,8 @@ pub enum TopEntryPoint {
     Pattern,
     Type,
     Expr,
+    /// Edge case -- macros generally don't expand to attributes, with the
+    /// exception of `cfg_attr` which does!
     MetaItem,
 }
 
@@ -119,9 +121,9 @@ impl TopEntryPoint {
             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_,
             // 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,
         };


Test patch:
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 97c27c453b..4c58ea9ba6 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
@@ -141,7 +141,7 @@ macro_rules! m1 { () => (Some(x) left overs) }
 macro_rules! m2 { () => ($) }
 
 fn main() {
-    let Some(x) = ();
+    let Some(x)left overs = ();
     let /* parse error: expected pattern */
 $ = ();
 }
diff --git a/crates/parser/src/tests/top_entries.rs b/crates/parser/src/tests/top_entries.rs
index fa25ffd0a2..dcf61b6aca 100644
--- a/crates/parser/src/tests/top_entries.rs
+++ b/crates/parser/src/tests/top_entries.rs
@@ -146,6 +146,82 @@ fn macro_pattern() {
               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,
+        "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
+        "#]],
+    );
 }
 
 #[track_caller]