From f1afc933530a87bd0cc7b25726c9a7fff3f3e007 Mon Sep 17 00:00:00 2001
From: Florian Diebold <flodiebold@gmail.com>
Date: Sat, 9 Feb 2019 19:07:35 +0100
Subject: [PATCH] Fix handling of literal patterns

Wrap them in a LiteralPat node so they can be distinguished from literal
expressions.
---
 crates/ra_hir/src/expr.rs                     |  1 +
 .../snapshots/tests__infer_std_crash_3.snap   | 13 ++++++
 crates/ra_hir/src/ty/tests.rs                 | 15 +++++++
 crates/ra_syntax/src/ast/generated.rs         | 37 ++++++++++++++++-
 crates/ra_syntax/src/grammar.ron              |  3 ++
 crates/ra_syntax/src/grammar/patterns.rs      | 41 ++++++++++++-------
 .../ra_syntax/src/syntax_kinds/generated.rs   |  2 +
 .../parser/inline/ok/0055_literal_pattern.txt | 22 ++++++----
 .../data/parser/inline/ok/0058_range_pat.txt  | 30 ++++++++------
 .../tests/data/parser/ok/0035_weird_exprs.txt | 10 +++--
 10 files changed, 133 insertions(+), 41 deletions(-)
 create mode 100644 crates/ra_hir/src/ty/snapshots/tests__infer_std_crash_3.snap

diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs
index 4e61d87ff04..bf423d3d882 100644
--- a/crates/ra_hir/src/expr.rs
+++ b/crates/ra_hir/src/expr.rs
@@ -850,6 +850,7 @@ impl ExprCollector {
             }
 
             // TODO: implement
+            ast::PatKind::LiteralPat(_) => Pat::Missing,
             ast::PatKind::SlicePat(_) | ast::PatKind::RangePat(_) => Pat::Missing,
         };
         let syntax_ptr = SyntaxNodePtr::new(pat.syntax());
diff --git a/crates/ra_hir/src/ty/snapshots/tests__infer_std_crash_3.snap b/crates/ra_hir/src/ty/snapshots/tests__infer_std_crash_3.snap
new file mode 100644
index 00000000000..d15b77e171e
--- /dev/null
+++ b/crates/ra_hir/src/ty/snapshots/tests__infer_std_crash_3.snap
@@ -0,0 +1,13 @@
+---
+created: "2019-02-09T18:02:37.377591660Z"
+creator: insta@0.6.1
+source: crates/ra_hir/src/ty/tests.rs
+expression: "&result"
+---
+[18; 102) '{     ...   } }': ()
+[24; 100) 'match ...     }': ()
+[42; 88) 'SizeSk...tail }': [unknown]
+[76; 80) 'true': [unknown]
+[82; 86) 'tail': [unknown]
+[92; 94) '{}': ()
+
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 3139eba0b47..e0b5a64717c 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -663,6 +663,21 @@ fn test_line_buffer() {
     );
 }
 
+#[test]
+fn infer_std_crash_3() {
+    // taken from rustc
+    check_inference(
+        "infer_std_crash_3",
+        r#"
+pub fn compute() {
+    match _ {
+        SizeSkeleton::Pointer { non_zero: true, tail } => {}
+    }
+}
+"#,
+    );
+}
+
 fn infer(content: &str) -> String {
     let (db, _, file_id) = MockDatabase::with_single_file(content);
     let source_file = db.parse(file_id);
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs
index 60314d24527..256277609f6 100644
--- a/crates/ra_syntax/src/ast/generated.rs
+++ b/crates/ra_syntax/src/ast/generated.rs
@@ -1821,6 +1821,38 @@ impl LiteralExpr {
 
 impl LiteralExpr {}
 
+// LiteralPat
+#[derive(Debug, PartialEq, Eq, Hash)]
+#[repr(transparent)]
+pub struct LiteralPat {
+    pub(crate) syntax: SyntaxNode,
+}
+unsafe impl TransparentNewType for LiteralPat {
+    type Repr = rowan::SyntaxNode<RaTypes>;
+}
+
+impl AstNode for LiteralPat {
+    fn cast(syntax: &SyntaxNode) -> Option<&Self> {
+        match syntax.kind() {
+            LITERAL_PAT => Some(LiteralPat::from_repr(syntax.into_repr())),
+            _ => None,
+        }
+    }
+    fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+
+impl ToOwned for LiteralPat {
+    type Owned = TreeArc<LiteralPat>;
+    fn to_owned(&self) -> TreeArc<LiteralPat> { TreeArc::cast(self.syntax.to_owned()) }
+}
+
+
+impl LiteralPat {
+    pub fn literal(&self) -> Option<&Literal> {
+        super::child_opt(self)
+    }
+}
+
 // LoopExpr
 #[derive(Debug, PartialEq, Eq, Hash)]
 #[repr(transparent)]
@@ -2594,6 +2626,7 @@ pub enum PatKind<'a> {
     TuplePat(&'a TuplePat),
     SlicePat(&'a SlicePat),
     RangePat(&'a RangePat),
+    LiteralPat(&'a LiteralPat),
 }
 
 impl AstNode for Pat {
@@ -2607,7 +2640,8 @@ impl AstNode for Pat {
             | TUPLE_STRUCT_PAT
             | TUPLE_PAT
             | SLICE_PAT
-            | RANGE_PAT => Some(Pat::from_repr(syntax.into_repr())),
+            | RANGE_PAT
+            | LITERAL_PAT => Some(Pat::from_repr(syntax.into_repr())),
             _ => None,
         }
     }
@@ -2631,6 +2665,7 @@ impl Pat {
             TUPLE_PAT => PatKind::TuplePat(TuplePat::cast(&self.syntax).unwrap()),
             SLICE_PAT => PatKind::SlicePat(SlicePat::cast(&self.syntax).unwrap()),
             RANGE_PAT => PatKind::RangePat(RangePat::cast(&self.syntax).unwrap()),
+            LITERAL_PAT => PatKind::LiteralPat(LiteralPat::cast(&self.syntax).unwrap()),
             _ => unreachable!(),
         }
     }
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron
index 046db588550..d428bc5955d 100644
--- a/crates/ra_syntax/src/grammar.ron
+++ b/crates/ra_syntax/src/grammar.ron
@@ -161,6 +161,7 @@ Grammar(
         "TUPLE_PAT",
         "SLICE_PAT",
         "RANGE_PAT",
+        "LITERAL_PAT",
 
         // atoms
         "TUPLE_EXPR",
@@ -524,6 +525,7 @@ Grammar(
         "TuplePat": ( collections: [["args", "Pat"]] ),
         "SlicePat": (),
         "RangePat": (),
+        "LiteralPat": (options: ["Literal"]),
 
         "Pat": (
             enum: [
@@ -536,6 +538,7 @@ Grammar(
                 "TuplePat",
                 "SlicePat",
                 "RangePat",
+                "LiteralPat",
             ],
         ),
 
diff --git a/crates/ra_syntax/src/grammar/patterns.rs b/crates/ra_syntax/src/grammar/patterns.rs
index f3f400ae0cc..9d7da639d5e 100644
--- a/crates/ra_syntax/src/grammar/patterns.rs
+++ b/crates/ra_syntax/src/grammar/patterns.rs
@@ -43,21 +43,8 @@ fn atom_pat(p: &mut Parser, recovery_set: TokenSet) -> Option<CompletedMarker> {
         return Some(path_pat(p));
     }
 
-    // test literal_pattern
-    // fn main() {
-    //     match () {
-    //         -1 => (),
-    //         92 => (),
-    //         'c' => (),
-    //         "hello" => (),
-    //     }
-    // }
-    if p.at(MINUS) && (p.nth(1) == INT_NUMBER || p.nth(1) == FLOAT_NUMBER) {
-        p.bump();
-    }
-
-    if let Some(m) = expressions::literal(p) {
-        return Some(m);
+    if is_literal_pat_start(p) {
+        return Some(literal_pat(p));
     }
 
     let m = match la0 {
@@ -73,6 +60,30 @@ fn atom_pat(p: &mut Parser, recovery_set: TokenSet) -> Option<CompletedMarker> {
     Some(m)
 }
 
+fn is_literal_pat_start(p: &mut Parser) -> bool {
+    p.at(MINUS) && (p.nth(1) == INT_NUMBER || p.nth(1) == FLOAT_NUMBER)
+        || p.at_ts(expressions::LITERAL_FIRST)
+}
+
+// test literal_pattern
+// fn main() {
+//     match () {
+//         -1 => (),
+//         92 => (),
+//         'c' => (),
+//         "hello" => (),
+//     }
+// }
+fn literal_pat(p: &mut Parser) -> CompletedMarker {
+    assert!(is_literal_pat_start(p));
+    let m = p.start();
+    if p.at(MINUS) {
+        p.bump();
+    }
+    expressions::literal(p);
+    m.complete(p, LITERAL_PAT)
+}
+
 // test path_part
 // fn foo() {
 //     let foo::Bar = ();
diff --git a/crates/ra_syntax/src/syntax_kinds/generated.rs b/crates/ra_syntax/src/syntax_kinds/generated.rs
index fea51345846..266b95bbb19 100644
--- a/crates/ra_syntax/src/syntax_kinds/generated.rs
+++ b/crates/ra_syntax/src/syntax_kinds/generated.rs
@@ -157,6 +157,7 @@ pub enum SyntaxKind {
     TUPLE_PAT,
     SLICE_PAT,
     RANGE_PAT,
+    LITERAL_PAT,
     TUPLE_EXPR,
     ARRAY_EXPR,
     PAREN_EXPR,
@@ -493,6 +494,7 @@ impl SyntaxKind {
             TUPLE_PAT => &SyntaxInfo { name: "TUPLE_PAT" },
             SLICE_PAT => &SyntaxInfo { name: "SLICE_PAT" },
             RANGE_PAT => &SyntaxInfo { name: "RANGE_PAT" },
+            LITERAL_PAT => &SyntaxInfo { name: "LITERAL_PAT" },
             TUPLE_EXPR => &SyntaxInfo { name: "TUPLE_EXPR" },
             ARRAY_EXPR => &SyntaxInfo { name: "ARRAY_EXPR" },
             PAREN_EXPR => &SyntaxInfo { name: "PAREN_EXPR" },
diff --git a/crates/ra_syntax/tests/data/parser/inline/ok/0055_literal_pattern.txt b/crates/ra_syntax/tests/data/parser/inline/ok/0055_literal_pattern.txt
index 71d62eaba78..51c5ab7f28c 100644
--- a/crates/ra_syntax/tests/data/parser/inline/ok/0055_literal_pattern.txt
+++ b/crates/ra_syntax/tests/data/parser/inline/ok/0055_literal_pattern.txt
@@ -22,9 +22,10 @@ SOURCE_FILE@[0; 113)
           L_CURLY@[25; 26)
           WHITESPACE@[26; 35)
           MATCH_ARM@[35; 43)
-            MINUS@[35; 36)
-            LITERAL@[36; 37)
-              INT_NUMBER@[36; 37) "1"
+            LITERAL_PAT@[35; 37)
+              MINUS@[35; 36)
+              LITERAL@[36; 37)
+                INT_NUMBER@[36; 37) "1"
             WHITESPACE@[37; 38)
             FAT_ARROW@[38; 40)
             WHITESPACE@[40; 41)
@@ -34,8 +35,9 @@ SOURCE_FILE@[0; 113)
           COMMA@[43; 44)
           WHITESPACE@[44; 53)
           MATCH_ARM@[53; 61)
-            LITERAL@[53; 55)
-              INT_NUMBER@[53; 55) "92"
+            LITERAL_PAT@[53; 55)
+              LITERAL@[53; 55)
+                INT_NUMBER@[53; 55) "92"
             WHITESPACE@[55; 56)
             FAT_ARROW@[56; 58)
             WHITESPACE@[58; 59)
@@ -45,8 +47,9 @@ SOURCE_FILE@[0; 113)
           COMMA@[61; 62)
           WHITESPACE@[62; 71)
           MATCH_ARM@[71; 80)
-            LITERAL@[71; 74)
-              CHAR@[71; 74)
+            LITERAL_PAT@[71; 74)
+              LITERAL@[71; 74)
+                CHAR@[71; 74)
             WHITESPACE@[74; 75)
             FAT_ARROW@[75; 77)
             WHITESPACE@[77; 78)
@@ -56,8 +59,9 @@ SOURCE_FILE@[0; 113)
           COMMA@[80; 81)
           WHITESPACE@[81; 90)
           MATCH_ARM@[90; 103)
-            LITERAL@[90; 97)
-              STRING@[90; 97)
+            LITERAL_PAT@[90; 97)
+              LITERAL@[90; 97)
+                STRING@[90; 97)
             WHITESPACE@[97; 98)
             FAT_ARROW@[98; 100)
             WHITESPACE@[100; 101)
diff --git a/crates/ra_syntax/tests/data/parser/inline/ok/0058_range_pat.txt b/crates/ra_syntax/tests/data/parser/inline/ok/0058_range_pat.txt
index d47f38903a2..de54c49e6fa 100644
--- a/crates/ra_syntax/tests/data/parser/inline/ok/0058_range_pat.txt
+++ b/crates/ra_syntax/tests/data/parser/inline/ok/0058_range_pat.txt
@@ -22,13 +22,15 @@ SOURCE_FILE@[0; 112)
           WHITESPACE@[26; 35)
           MATCH_ARM@[35; 50)
             RANGE_PAT@[35; 44)
-              LITERAL@[35; 36)
-                INT_NUMBER@[35; 36) "0"
+              LITERAL_PAT@[35; 36)
+                LITERAL@[35; 36)
+                  INT_NUMBER@[35; 36) "0"
               WHITESPACE@[36; 37)
               DOTDOTDOT@[37; 40)
               WHITESPACE@[40; 41)
-              LITERAL@[41; 44)
-                INT_NUMBER@[41; 44) "100"
+              LITERAL_PAT@[41; 44)
+                LITERAL@[41; 44)
+                  INT_NUMBER@[41; 44) "100"
             WHITESPACE@[44; 45)
             FAT_ARROW@[45; 47)
             WHITESPACE@[47; 48)
@@ -39,13 +41,15 @@ SOURCE_FILE@[0; 112)
           WHITESPACE@[51; 60)
           MATCH_ARM@[60; 77)
             RANGE_PAT@[60; 71)
-              LITERAL@[60; 63)
-                INT_NUMBER@[60; 63) "101"
+              LITERAL_PAT@[60; 63)
+                LITERAL@[60; 63)
+                  INT_NUMBER@[60; 63) "101"
               WHITESPACE@[63; 64)
               DOTDOTEQ@[64; 67)
               WHITESPACE@[67; 68)
-              LITERAL@[68; 71)
-                INT_NUMBER@[68; 71) "200"
+              LITERAL_PAT@[68; 71)
+                LITERAL@[68; 71)
+                  INT_NUMBER@[68; 71) "200"
             WHITESPACE@[71; 72)
             FAT_ARROW@[72; 74)
             WHITESPACE@[74; 75)
@@ -56,13 +60,15 @@ SOURCE_FILE@[0; 112)
           WHITESPACE@[78; 87)
           MATCH_ARM@[87; 102)
             RANGE_PAT@[87; 97)
-              LITERAL@[87; 90)
-                INT_NUMBER@[87; 90) "200"
+              LITERAL_PAT@[87; 90)
+                LITERAL@[87; 90)
+                  INT_NUMBER@[87; 90) "200"
               WHITESPACE@[90; 91)
               DOTDOT@[91; 93)
               WHITESPACE@[93; 94)
-              LITERAL@[94; 97)
-                INT_NUMBER@[94; 97) "301"
+              LITERAL_PAT@[94; 97)
+                LITERAL@[94; 97)
+                  INT_NUMBER@[94; 97) "301"
             FAT_ARROW@[97; 99)
             WHITESPACE@[99; 100)
             TUPLE_EXPR@[100; 102)
diff --git a/crates/ra_syntax/tests/data/parser/ok/0035_weird_exprs.txt b/crates/ra_syntax/tests/data/parser/ok/0035_weird_exprs.txt
index 20932a8378a..f3987c3b79d 100644
--- a/crates/ra_syntax/tests/data/parser/ok/0035_weird_exprs.txt
+++ b/crates/ra_syntax/tests/data/parser/ok/0035_weird_exprs.txt
@@ -456,8 +456,9 @@ SOURCE_FILE@[0; 3813)
                           L_CURLY@[930; 931)
                           WHITESPACE@[931; 952)
                           MATCH_ARM@[952; 1147)
-                            LITERAL@[952; 953)
-                              INT_NUMBER@[952; 953) "1"
+                            LITERAL_PAT@[952; 953)
+                              LITERAL@[952; 953)
+                                INT_NUMBER@[952; 953) "1"
                             WHITESPACE@[953; 954)
                             FAT_ARROW@[954; 956)
                             WHITESPACE@[956; 957)
@@ -1080,8 +1081,9 @@ SOURCE_FILE@[0; 3813)
                     L_CURLY@[1853; 1854)
                     WHITESPACE@[1854; 1855)
                     MATCH_ARM@[1855; 1863)
-                      LITERAL@[1855; 1856)
-                        INT_NUMBER@[1855; 1856) "1"
+                      LITERAL_PAT@[1855; 1856)
+                        LITERAL@[1855; 1856)
+                          INT_NUMBER@[1855; 1856) "1"
                       WHITESPACE@[1856; 1857)
                       FAT_ARROW@[1857; 1859)
                       WHITESPACE@[1859; 1860)