about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-01-18 09:52:37 +0000
committerbors <bors@rust-lang.org>2024-01-18 09:52:37 +0000
commit1ab8c7fd270649e90de9d46e8068ec78738d6676 (patch)
tree0a2b1c6e8e4cd38518a688dccd9646510dd0ff99
parent2dfa9b86d04733f83084ae3587843eb053495a64 (diff)
parent1c61326ca04b284a964dd581749a563cbbd71273 (diff)
downloadrust-1ab8c7fd270649e90de9d46e8068ec78738d6676.tar.gz
rust-1ab8c7fd270649e90de9d46e8068ec78738d6676.zip
Auto merge of #16349 - Young-Flash:use_error_recovery, r=Veykril
fix: add error recovery for use_tree_list parsing

This PR adds error recovery for USE_TREE_LIST parsing, avoid the wrong USE_TREE_LIST making the rest parsing incorrectly.

before

![before](https://github.com/rust-lang/rust-analyzer/assets/71162630/c6643690-f25c-4ad9-93d9-e661ba5b1dc3)

after

![after](https://github.com/rust-lang/rust-analyzer/assets/71162630/30a58c40-2711-48d2-b2e5-fb208fc8636c)

close https://github.com/rust-lang/rust-analyzer/issues/16227
-rw-r--r--crates/ide-completion/src/tests/use_tree.rs27
-rw-r--r--crates/parser/src/grammar/items/use_item.rs28
-rw-r--r--crates/parser/test_data/parser/err/0036_partial_use.rast45
-rw-r--r--crates/parser/test_data/parser/inline/err/0026_use_tree_list_err_recovery.rast46
-rw-r--r--crates/parser/test_data/parser/inline/err/0026_use_tree_list_err_recovery.rs4
5 files changed, 112 insertions, 38 deletions
diff --git a/crates/ide-completion/src/tests/use_tree.rs b/crates/ide-completion/src/tests/use_tree.rs
index 167bdec546d..f8b76571ca0 100644
--- a/crates/ide-completion/src/tests/use_tree.rs
+++ b/crates/ide-completion/src/tests/use_tree.rs
@@ -9,6 +9,33 @@ fn check(ra_fixture: &str, expect: Expect) {
 }
 
 #[test]
+fn use_tree_completion() {
+    check(
+        r#"
+struct implThing;
+
+use crate::{impl$0};
+"#,
+        expect![[r#"
+            st implThing implThing
+            kw self
+        "#]],
+    );
+
+    check(
+        r#"
+struct implThing;
+
+use crate::{impl$0;
+"#,
+        expect![[r#"
+            st implThing implThing
+            kw self
+        "#]],
+    );
+}
+
+#[test]
 fn use_tree_start() {
     cov_mark::check!(unqualified_path_selected_only);
     check(
diff --git a/crates/parser/src/grammar/items/use_item.rs b/crates/parser/src/grammar/items/use_item.rs
index 69880b7946b..f689c06b31c 100644
--- a/crates/parser/src/grammar/items/use_item.rs
+++ b/crates/parser/src/grammar/items/use_item.rs
@@ -11,7 +11,7 @@ pub(super) fn use_(p: &mut Parser<'_>, m: Marker) {
 
 // test use_tree
 // use outer::tree::{inner::tree};
-fn use_tree(p: &mut Parser<'_>, top_level: bool) {
+fn use_tree(p: &mut Parser<'_>, top_level: bool) -> bool {
     let m = p.start();
     match p.current() {
         // test use_tree_star
@@ -70,24 +70,32 @@ fn use_tree(p: &mut Parser<'_>, top_level: bool) {
                 // main balanced `{}`
                 p.err_and_bump(msg);
             }
-            return;
+            return false;
         }
     }
     m.complete(p, USE_TREE);
+    true
 }
 
+pub(super) const USE_TREE_LIST_RECOVERY_SET: TokenSet =
+    TokenSet::new(&[T![;], T![,], T![.], T![ident]]).union(ITEM_RECOVERY_SET);
+
+pub(super) const USE_TREE_LIST_FIRST_SET: TokenSet = TokenSet::new(&[T!['{'], T![ident]]);
+
 // test use_tree_list
 // use {a, b, c};
 pub(crate) fn use_tree_list(p: &mut Parser<'_>) {
     assert!(p.at(T!['{']));
     let m = p.start();
-    p.bump(T!['{']);
-    while !p.at(EOF) && !p.at(T!['}']) {
-        use_tree(p, false);
-        if !p.at(T!['}']) {
-            p.expect(T![,]);
-        }
-    }
-    p.expect(T!['}']);
+
+    // test_err use_tree_list_err_recovery
+    // use {a;
+    // use b;
+    // struct T;
+    // fn test() {}
+    delimited(p, T!['{'], T!['}'], T![,], USE_TREE_LIST_FIRST_SET, |p: &mut Parser<'_>| {
+        use_tree(p, false) || p.at_ts(USE_TREE_LIST_RECOVERY_SET)
+    });
+
     m.complete(p, USE_TREE_LIST);
 }
diff --git a/crates/parser/test_data/parser/err/0036_partial_use.rast b/crates/parser/test_data/parser/err/0036_partial_use.rast
index 13e76e68307..e27c9417939 100644
--- a/crates/parser/test_data/parser/err/0036_partial_use.rast
+++ b/crates/parser/test_data/parser/err/0036_partial_use.rast
@@ -20,32 +20,21 @@ SOURCE_FILE
             PATH_SEGMENT
               NAME_REF
                 IDENT "Error"
-        ERROR
-          SEMICOLON ";"
-        WHITESPACE "\n"
-        ERROR
-          USE_KW "use"
-        WHITESPACE " "
-        USE_TREE
-          PATH
-            PATH
-              PATH_SEGMENT
-                NAME_REF
-                  IDENT "std"
-            COLON2 "::"
-            PATH_SEGMENT
-              NAME_REF
-                IDENT "io"
-        ERROR
-          SEMICOLON ";"
+    SEMICOLON ";"
+  WHITESPACE "\n"
+  USE
+    USE_KW "use"
+    WHITESPACE " "
+    USE_TREE
+      PATH
+        PATH
+          PATH_SEGMENT
+            NAME_REF
+              IDENT "std"
+        COLON2 "::"
+        PATH_SEGMENT
+          NAME_REF
+            IDENT "io"
+    SEMICOLON ";"
   WHITESPACE "\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 SEMICOLON
+error 22: expected R_CURLY
diff --git a/crates/parser/test_data/parser/inline/err/0026_use_tree_list_err_recovery.rast b/crates/parser/test_data/parser/inline/err/0026_use_tree_list_err_recovery.rast
new file mode 100644
index 00000000000..cb90b093ba0
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/err/0026_use_tree_list_err_recovery.rast
@@ -0,0 +1,46 @@
+SOURCE_FILE
+  USE
+    USE_KW "use"
+    WHITESPACE " "
+    USE_TREE
+      USE_TREE_LIST
+        L_CURLY "{"
+        USE_TREE
+          PATH
+            PATH_SEGMENT
+              NAME_REF
+                IDENT "a"
+    SEMICOLON ";"
+  WHITESPACE "\n"
+  USE
+    USE_KW "use"
+    WHITESPACE " "
+    USE_TREE
+      PATH
+        PATH_SEGMENT
+          NAME_REF
+            IDENT "b"
+    SEMICOLON ";"
+  WHITESPACE "\n"
+  STRUCT
+    STRUCT_KW "struct"
+    WHITESPACE " "
+    NAME
+      IDENT "T"
+    SEMICOLON ";"
+  WHITESPACE "\n"
+  FN
+    FN_KW "fn"
+    WHITESPACE " "
+    NAME
+      IDENT "test"
+    PARAM_LIST
+      L_PAREN "("
+      R_PAREN ")"
+    WHITESPACE " "
+    BLOCK_EXPR
+      STMT_LIST
+        L_CURLY "{"
+        R_CURLY "}"
+  WHITESPACE "\n"
+error 6: expected R_CURLY
diff --git a/crates/parser/test_data/parser/inline/err/0026_use_tree_list_err_recovery.rs b/crates/parser/test_data/parser/inline/err/0026_use_tree_list_err_recovery.rs
new file mode 100644
index 00000000000..f16959c25f2
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/err/0026_use_tree_list_err_recovery.rs
@@ -0,0 +1,4 @@
+use {a;
+use b;
+struct T;
+fn test() {}