From d57b993adec18a4629b0a1669f2ee714984d8536 Mon Sep 17 00:00:00 2001
From: Aleksey Kladov <aleksey.kladov@gmail.com>
Date: Fri, 20 Sep 2019 16:53:05 +0300
Subject: fix infinite loop in the parser

closes #1866
---
 crates/ra_parser/src/grammar/items/use_item.rs     | 18 +++++---
 .../test_data/parser/err/0036_partial_use.rs       |  2 +
 .../test_data/parser/err/0036_partial_use.txt      | 51 ++++++++++++++++++++++
 3 files changed, 64 insertions(+), 7 deletions(-)
 create mode 100644 crates/ra_syntax/test_data/parser/err/0036_partial_use.rs
 create mode 100644 crates/ra_syntax/test_data/parser/err/0036_partial_use.txt

diff --git a/crates/ra_parser/src/grammar/items/use_item.rs b/crates/ra_parser/src/grammar/items/use_item.rs
index 2af2ad315..63ac37e9e 100644
--- a/crates/ra_parser/src/grammar/items/use_item.rs
+++ b/crates/ra_parser/src/grammar/items/use_item.rs
@@ -3,7 +3,7 @@ use super::*;
 pub(super) fn use_item(p: &mut Parser, m: Marker) {
     assert!(p.at(T![use]));
     p.bump(T![use]);
-    use_tree(p);
+    use_tree(p, true);
     p.expect(T![;]);
     m.complete(p, USE_ITEM);
 }
@@ -12,7 +12,7 @@ pub(super) fn use_item(p: &mut Parser, m: Marker) {
 /// Note that this is called both by `use_item` and `use_tree_list`,
 /// so handles both `some::path::{inner::path}` and `inner::path` in
 /// `use some::path::{inner::path};`
-fn use_tree(p: &mut Parser) {
+fn use_tree(p: &mut Parser, top_level: bool) {
     let m = p.start();
     match p.current() {
         // Finish the use_tree for cases of e.g.
@@ -101,10 +101,14 @@ fn use_tree(p: &mut Parser) {
         }
         _ => {
             m.abandon(p);
-            p.err_recover(
-                "expected one of `*`, `::`, `{`, `self`, `super` or an identifier",
-                ITEM_RECOVERY_SET,
-            );
+            let msg = "expected one of `*`, `::`, `{`, `self`, `super` or an identifier";
+            if top_level {
+                p.err_recover(msg, ITEM_RECOVERY_SET);
+            } else {
+                // if we are parsing a nested tree, we have to eat a token to
+                // main balanced `{}`
+                p.err_and_bump(msg);
+            }
             return;
         }
     }
@@ -116,7 +120,7 @@ pub(crate) fn use_tree_list(p: &mut Parser) {
     let m = p.start();
     p.bump(T!['{']);
     while !p.at(EOF) && !p.at(T!['}']) {
-        use_tree(p);
+        use_tree(p, false);
         if !p.at(T!['}']) {
             p.expect(T![,]);
         }
diff --git a/crates/ra_syntax/test_data/parser/err/0036_partial_use.rs b/crates/ra_syntax/test_data/parser/err/0036_partial_use.rs
new file mode 100644
index 000000000..d521a5bb2
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/err/0036_partial_use.rs
@@ -0,0 +1,2 @@
+use std::{error::Error;
+use std::io;
diff --git a/crates/ra_syntax/test_data/parser/err/0036_partial_use.txt b/crates/ra_syntax/test_data/parser/err/0036_partial_use.txt
new file mode 100644
index 000000000..181f408c8
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/err/0036_partial_use.txt
@@ -0,0 +1,51 @@
+SOURCE_FILE@[0; 37)
+  USE_ITEM@[0; 36)
+    USE_KW@[0; 3) "use"
+    WHITESPACE@[3; 4) " "
+    USE_TREE@[4; 36)
+      PATH@[4; 7)
+        PATH_SEGMENT@[4; 7)
+          NAME_REF@[4; 7)
+            IDENT@[4; 7) "std"
+      COLONCOLON@[7; 9) "::"
+      USE_TREE_LIST@[9; 36)
+        L_CURLY@[9; 10) "{"
+        USE_TREE@[10; 22)
+          PATH@[10; 22)
+            PATH@[10; 15)
+              PATH_SEGMENT@[10; 15)
+                NAME_REF@[10; 15)
+                  IDENT@[10; 15) "error"
+            COLONCOLON@[15; 17) "::"
+            PATH_SEGMENT@[17; 22)
+              NAME_REF@[17; 22)
+                IDENT@[17; 22) "Error"
+        ERROR@[22; 23)
+          SEMI@[22; 23) ";"
+        WHITESPACE@[23; 24) "\n"
+        ERROR@[24; 27)
+          USE_KW@[24; 27) "use"
+        WHITESPACE@[27; 28) " "
+        USE_TREE@[28; 35)
+          PATH@[28; 35)
+            PATH@[28; 31)
+              PATH_SEGMENT@[28; 31)
+                NAME_REF@[28; 31)
+                  IDENT@[28; 31) "std"
+            COLONCOLON@[31; 33) "::"
+            PATH_SEGMENT@[33; 35)
+              NAME_REF@[33; 35)
+                IDENT@[33; 35) "io"
+        ERROR@[35; 36)
+          SEMI@[35; 36) ";"
+  WHITESPACE@[36; 37) "\n"
+error 22: expected COMMA
+error 22: expected one of `*`, `::`, `{`, `self`, `super` or an identifier
+error 23: expected COMMA
+error 24: expected one of `*`, `::`, `{`, `self`, `super` or an identifier
+error 27: expected COMMA
+error 35: expected COMMA
+error 35: expected one of `*`, `::`, `{`, `self`, `super` or an identifier
+error 36: expected COMMA
+error 36: expected R_CURLY
+error 36: expected SEMI
-- 
cgit v1.2.3