]> git.lizzy.rs Git - rust.git/commitdiff
Merge #5951 #5975
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>
Fri, 11 Sep 2020 13:47:33 +0000 (13:47 +0000)
committerGitHub <noreply@github.com>
Fri, 11 Sep 2020 13:47:33 +0000 (13:47 +0000)
5951: Rename record_field_pat to record_pat_field r=jonas-schievink a=pksunkara

The token was renamed but not this.

5975: Report better errors in project.json/sysroot r=jonas-schievink a=jonas-schievink

This does a bunch of light refactoring so that the `Sysroot` is loaded later, which makes sure that any errors are reported to the user. I then added a check that reports an error if libcore is missing in the loaded sysroot. Since a sysroot without libcore is very useless, this indicates a configuration error.

Co-authored-by: Pavan Kumar Sunkara <pavan.sss1991@gmail.com>
Co-authored-by: Jonas Schievink <jonas.schievink@ferrous-systems.com>
15 files changed:
crates/assists/src/handlers/remove_dbg.rs
crates/hir/src/semantics.rs
crates/hir/src/source_analyzer.rs
crates/hir_ty/src/infer.rs
crates/hir_ty/src/infer/pat.rs
crates/ide_db/src/defs.rs
crates/parser/src/grammar/patterns.rs
crates/syntax/test_data/parser/inline/ok/0102_record_field_pat_list.rast [deleted file]
crates/syntax/test_data/parser/inline/ok/0102_record_field_pat_list.rs [deleted file]
crates/syntax/test_data/parser/inline/ok/0102_record_pat_field_list.rast [new file with mode: 0644]
crates/syntax/test_data/parser/inline/ok/0102_record_pat_field_list.rs [new file with mode: 0644]
crates/syntax/test_data/parser/inline/ok/0145_record_field_pat.rast [deleted file]
crates/syntax/test_data/parser/inline/ok/0145_record_field_pat.rs [deleted file]
crates/syntax/test_data/parser/inline/ok/0145_record_pat_field.rast [new file with mode: 0644]
crates/syntax/test_data/parser/inline/ok/0145_record_pat_field.rs [new file with mode: 0644]

index 4e252edf02d797c1dc895ec0bc93dbdadbf030d2..0b581dc22a27163427d15f50290c2a585c264e2f 100644 (file)
@@ -1,6 +1,6 @@
 use syntax::{
     ast::{self, AstNode},
-    TextRange, TextSize, T,
+    SyntaxElement, TextRange, TextSize, T,
 };
 
 use crate::{AssistContext, AssistId, AssistKind, Assists};
 // ```
 pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
     let macro_call = ctx.find_node_at_offset::<ast::MacroCall>()?;
+    let new_contents = adjusted_macro_contents(&macro_call)?;
 
-    if !is_valid_macrocall(&macro_call, "dbg")? {
-        return None;
-    }
-
-    let is_leaf = macro_call.syntax().next_sibling().is_none();
-
+    let macro_text_range = macro_call.syntax().text_range();
     let macro_end = if macro_call.semicolon_token().is_some() {
-        macro_call.syntax().text_range().end() - TextSize::of(';')
+        macro_text_range.end() - TextSize::of(';')
     } else {
-        macro_call.syntax().text_range().end()
+        macro_text_range.end()
     };
 
-    // macro_range determines what will be deleted and replaced with macro_content
-    let macro_range = TextRange::new(macro_call.syntax().text_range().start(), macro_end);
-    let paste_instead_of_dbg = {
-        let text = macro_call.token_tree()?.syntax().text();
-
-        // leafiness determines if we should include the parenthesis or not
-        let slice_index: TextRange = if is_leaf {
-            // leaf means - we can extract the contents of the dbg! in text
-            TextRange::new(TextSize::of('('), text.len() - TextSize::of(')'))
-        } else {
-            // not leaf - means we should keep the parens
-            TextRange::up_to(text.len())
-        };
-        text.slice(slice_index).to_string()
-    };
+    acc.add(
+        AssistId("remove_dbg", AssistKind::Refactor),
+        "Remove dbg!()",
+        macro_text_range,
+        |builder| {
+            builder.replace(TextRange::new(macro_text_range.start(), macro_end), new_contents);
+        },
+    )
+}
 
-    let target = macro_call.syntax().text_range();
-    acc.add(AssistId("remove_dbg", AssistKind::Refactor), "Remove dbg!()", target, |builder| {
-        builder.replace(macro_range, paste_instead_of_dbg);
-    })
+fn adjusted_macro_contents(macro_call: &ast::MacroCall) -> Option<String> {
+    let contents = get_valid_macrocall_contents(&macro_call, "dbg")?;
+    let is_leaf = macro_call.syntax().next_sibling().is_none();
+    let macro_text_with_brackets = macro_call.token_tree()?.syntax().text();
+    let slice_index = if is_leaf || !needs_parentheses_around_macro_contents(contents) {
+        TextRange::new(TextSize::of('('), macro_text_with_brackets.len() - TextSize::of(')'))
+    } else {
+        // leave parenthesis around macro contents to preserve the semantics
+        TextRange::up_to(macro_text_with_brackets.len())
+    };
+    Some(macro_text_with_brackets.slice(slice_index).to_string())
 }
 
 /// Verifies that the given macro_call actually matches the given name
-/// and contains proper ending tokens
-fn is_valid_macrocall(macro_call: &ast::MacroCall, macro_name: &str) -> Option<bool> {
+/// and contains proper ending tokens, then returns the contents between the ending tokens
+fn get_valid_macrocall_contents(
+    macro_call: &ast::MacroCall,
+    macro_name: &str,
+) -> Option<Vec<SyntaxElement>> {
     let path = macro_call.path()?;
     let name_ref = path.segment()?.name_ref()?;
 
     // Make sure it is actually a dbg-macro call, dbg followed by !
     let excl = path.syntax().next_sibling_or_token()?;
-
     if name_ref.text() != macro_name || excl.kind() != T![!] {
         return None;
     }
 
-    let node = macro_call.token_tree()?.syntax().clone();
-    let first_child = node.first_child_or_token()?;
-    let last_child = node.last_child_or_token()?;
+    let mut children_with_tokens = macro_call.token_tree()?.syntax().children_with_tokens();
+    let first_child = children_with_tokens.next()?;
+    let mut contents_between_brackets = children_with_tokens.collect::<Vec<_>>();
+    let last_child = contents_between_brackets.pop()?;
+
+    if contents_between_brackets.is_empty() {
+        None
+    } else {
+        match (first_child.kind(), last_child.kind()) {
+            (T!['('], T![')']) | (T!['['], T![']']) | (T!['{'], T!['}']) => {
+                Some(contents_between_brackets)
+            }
+            _ => None,
+        }
+    }
+}
+
+fn needs_parentheses_around_macro_contents(macro_contents: Vec<SyntaxElement>) -> bool {
+    if macro_contents.len() < 2 {
+        return false;
+    }
+
+    let mut macro_contents_kind_not_in_brackets = Vec::with_capacity(macro_contents.len());
 
-    match (first_child.kind(), last_child.kind()) {
-        (T!['('], T![')']) | (T!['['], T![']']) | (T!['{'], T!['}']) => Some(true),
-        _ => Some(false),
+    let mut first_bracket_in_macro = None;
+    let mut unpaired_brackets_in_contents = Vec::new();
+    for element in macro_contents {
+        match element.kind() {
+            T!['('] | T!['['] | T!['{'] => {
+                if let None = first_bracket_in_macro {
+                    first_bracket_in_macro = Some(element.clone())
+                }
+                unpaired_brackets_in_contents.push(element);
+            }
+            T![')'] => {
+                if !matches!(unpaired_brackets_in_contents.pop(), Some(correct_bracket) if correct_bracket.kind() == T!['('])
+                {
+                    return true;
+                }
+            }
+            T![']'] => {
+                if !matches!(unpaired_brackets_in_contents.pop(), Some(correct_bracket) if correct_bracket.kind() == T!['['])
+                {
+                    return true;
+                }
+            }
+            T!['}'] => {
+                if !matches!(unpaired_brackets_in_contents.pop(), Some(correct_bracket) if correct_bracket.kind() == T!['{'])
+                {
+                    return true;
+                }
+            }
+            other_kind => {
+                if unpaired_brackets_in_contents.is_empty() {
+                    macro_contents_kind_not_in_brackets.push(other_kind);
+                }
+            }
+        }
     }
+
+    !unpaired_brackets_in_contents.is_empty()
+        || matches!(first_bracket_in_macro, Some(bracket) if bracket.kind() != T!['('])
+        || macro_contents_kind_not_in_brackets
+            .into_iter()
+            .any(|macro_contents_kind| macro_contents_kind.is_punct())
 }
 
 #[cfg(test)]
@@ -156,6 +212,29 @@ fn test_remove_dbg_keep_semicolon() {
         );
     }
 
+    #[test]
+    fn remove_dbg_from_non_leaf_simple_expression() {
+        check_assist(
+            remove_dbg,
+            "
+fn main() {
+    let mut a = 1;
+    while dbg!<|>(a) < 10000 {
+        a += 1;
+    }
+}
+",
+            "
+fn main() {
+    let mut a = 1;
+    while a < 10000 {
+        a += 1;
+    }
+}
+",
+        );
+    }
+
     #[test]
     fn test_remove_dbg_keep_expression() {
         check_assist(
@@ -163,6 +242,8 @@ fn test_remove_dbg_keep_expression() {
             r#"let res = <|>dbg!(a + b).foo();"#,
             r#"let res = (a + b).foo();"#,
         );
+
+        check_assist(remove_dbg, r#"let res = <|>dbg!(2 + 2) * 5"#, r#"let res = (2 + 2) * 5"#);
     }
 
     #[test]
index 1594d4f0ff9937fb00054a2b5769869eb6b7373d..0516a05b4154f3c863cef5695332e1f02a6c7741 100644 (file)
@@ -207,8 +207,8 @@ pub fn resolve_record_field(
         self.imp.resolve_record_field(field)
     }
 
-    pub fn resolve_record_field_pat(&self, field: &ast::RecordPatField) -> Option<Field> {
-        self.imp.resolve_record_field_pat(field)
+    pub fn resolve_record_pat_field(&self, field: &ast::RecordPatField) -> Option<Field> {
+        self.imp.resolve_record_pat_field(field)
     }
 
     pub fn resolve_macro_call(&self, macro_call: &ast::MacroCall) -> Option<MacroDef> {
@@ -433,8 +433,8 @@ fn resolve_record_field(&self, field: &ast::RecordExprField) -> Option<(Field, O
         self.analyze(field.syntax()).resolve_record_field(self.db, field)
     }
 
-    fn resolve_record_field_pat(&self, field: &ast::RecordPatField) -> Option<Field> {
-        self.analyze(field.syntax()).resolve_record_field_pat(self.db, field)
+    fn resolve_record_pat_field(&self, field: &ast::RecordPatField) -> Option<Field> {
+        self.analyze(field.syntax()).resolve_record_pat_field(self.db, field)
     }
 
     fn resolve_macro_call(&self, macro_call: &ast::MacroCall) -> Option<MacroDef> {
index 1d13c4f1d3b7d276b883e0f9edb6e52a59ec9c1a..1aef0f33f5f84fa6e6d23ddd42c30ad197a2c9d7 100644 (file)
@@ -179,13 +179,13 @@ pub(crate) fn resolve_record_field(
         Some((struct_field.into(), local))
     }
 
-    pub(crate) fn resolve_record_field_pat(
+    pub(crate) fn resolve_record_pat_field(
         &self,
         _db: &dyn HirDatabase,
         field: &ast::RecordPatField,
     ) -> Option<Field> {
         let pat_id = self.pat_id(&field.pat()?)?;
-        let struct_field = self.infer.as_ref()?.record_field_pat_resolution(pat_id)?;
+        let struct_field = self.infer.as_ref()?.record_pat_field_resolution(pat_id)?;
         Some(struct_field.into())
     }
 
index 03b00b101c2314788f795ad6f7ae4edd3b64d40a..2b53b8297314941f5b917917ff7939d908b83bfc 100644 (file)
@@ -125,7 +125,7 @@ pub struct InferenceResult {
     field_resolutions: FxHashMap<ExprId, FieldId>,
     /// For each field in record literal, records the field it resolves to.
     record_field_resolutions: FxHashMap<ExprId, FieldId>,
-    record_field_pat_resolutions: FxHashMap<PatId, FieldId>,
+    record_pat_field_resolutions: FxHashMap<PatId, FieldId>,
     /// For each struct literal, records the variant it resolves to.
     variant_resolutions: FxHashMap<ExprOrPatId, VariantId>,
     /// For each associated item record what it resolves to
@@ -146,8 +146,8 @@ pub fn field_resolution(&self, expr: ExprId) -> Option<FieldId> {
     pub fn record_field_resolution(&self, expr: ExprId) -> Option<FieldId> {
         self.record_field_resolutions.get(&expr).copied()
     }
-    pub fn record_field_pat_resolution(&self, pat: PatId) -> Option<FieldId> {
-        self.record_field_pat_resolutions.get(&pat).copied()
+    pub fn record_pat_field_resolution(&self, pat: PatId) -> Option<FieldId> {
+        self.record_pat_field_resolutions.get(&pat).copied()
     }
     pub fn variant_resolution_for_expr(&self, id: ExprId) -> Option<VariantId> {
         self.variant_resolutions.get(&id.into()).copied()
index 4dd4f9802d6ecf93bf48027fe64baccf9820080b..dde38bc397b6eb184e342760001496badb8e3e58 100644 (file)
@@ -70,7 +70,7 @@ fn infer_record_pat(
             let matching_field = var_data.as_ref().and_then(|it| it.field(&subpat.name));
             if let Some(local_id) = matching_field {
                 let field_def = FieldId { parent: def.unwrap(), local_id };
-                self.result.record_field_pat_resolutions.insert(subpat.pat, field_def);
+                self.result.record_pat_field_resolutions.insert(subpat.pat, field_def);
             }
 
             let expected_ty =
index 0d0affc273575eca6758b78ed22ecd8feecce7c9..f8c7aa491ea56ef205d0adc306aadcb9f059ceca 100644 (file)
@@ -157,9 +157,9 @@ pub fn classify_name(sema: &Semantics<RootDatabase>, name: &ast::Name) -> Option
             ast::IdentPat(it) => {
                 let local = sema.to_def(&it)?;
 
-                if let Some(record_field_pat) = it.syntax().parent().and_then(ast::RecordPatField::cast) {
-                    if record_field_pat.name_ref().is_none() {
-                        if let Some(field) = sema.resolve_record_field_pat(&record_field_pat) {
+                if let Some(record_pat_field) = it.syntax().parent().and_then(ast::RecordPatField::cast) {
+                    if record_pat_field.name_ref().is_none() {
+                        if let Some(field) = sema.resolve_record_pat_field(&record_pat_field) {
                             let field = Definition::Field(field);
                             return Some(NameClass::FieldShorthand { local, field });
                         }
@@ -275,8 +275,8 @@ pub fn classify_name_ref(
         }
     }
 
-    if let Some(record_field_pat) = ast::RecordPatField::cast(parent.clone()) {
-        if let Some(field) = sema.resolve_record_field_pat(&record_field_pat) {
+    if let Some(record_pat_field) = ast::RecordPatField::cast(parent.clone()) {
+        if let Some(field) = sema.resolve_record_pat_field(&record_pat_field) {
             let field = Definition::Field(field);
             return Some(NameRefClass::Definition(field));
         }
index 796f206e1284fac80d5cab9000d667078014b968..7e7f73deeac9db2111aa8a208a058cc4ba1511bf 100644 (file)
@@ -188,7 +188,7 @@ fn tuple_pat_fields(p: &mut Parser) {
     p.expect(T![')']);
 }
 
-// test record_field_pat_list
+// test record_pat_field_list
 // fn foo() {
 //     let S {} = ();
 //     let S { f, ref mut g } = ();
@@ -208,7 +208,7 @@ fn record_pat_field_list(p: &mut Parser) {
             c => {
                 let m = p.start();
                 match c {
-                    // test record_field_pat
+                    // test record_pat_field
                     // fn foo() {
                     //     let S { 0: 1 } = ();
                     //     let S { x: 1 } = ();
diff --git a/crates/syntax/test_data/parser/inline/ok/0102_record_field_pat_list.rast b/crates/syntax/test_data/parser/inline/ok/0102_record_field_pat_list.rast
deleted file mode 100644 (file)
index 866e60e..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-SOURCE_FILE@0..119
-  FN@0..118
-    FN_KW@0..2 "fn"
-    WHITESPACE@2..3 " "
-    NAME@3..6
-      IDENT@3..6 "foo"
-    PARAM_LIST@6..8
-      L_PAREN@6..7 "("
-      R_PAREN@7..8 ")"
-    WHITESPACE@8..9 " "
-    BLOCK_EXPR@9..118
-      L_CURLY@9..10 "{"
-      WHITESPACE@10..15 "\n    "
-      LET_STMT@15..29
-        LET_KW@15..18 "let"
-        WHITESPACE@18..19 " "
-        RECORD_PAT@19..23
-          PATH@19..20
-            PATH_SEGMENT@19..20
-              NAME_REF@19..20
-                IDENT@19..20 "S"
-          WHITESPACE@20..21 " "
-          RECORD_PAT_FIELD_LIST@21..23
-            L_CURLY@21..22 "{"
-            R_CURLY@22..23 "}"
-        WHITESPACE@23..24 " "
-        EQ@24..25 "="
-        WHITESPACE@25..26 " "
-        TUPLE_EXPR@26..28
-          L_PAREN@26..27 "("
-          R_PAREN@27..28 ")"
-        SEMICOLON@28..29 ";"
-      WHITESPACE@29..34 "\n    "
-      LET_STMT@34..62
-        LET_KW@34..37 "let"
-        WHITESPACE@37..38 " "
-        RECORD_PAT@38..56
-          PATH@38..39
-            PATH_SEGMENT@38..39
-              NAME_REF@38..39
-                IDENT@38..39 "S"
-          WHITESPACE@39..40 " "
-          RECORD_PAT_FIELD_LIST@40..56
-            L_CURLY@40..41 "{"
-            WHITESPACE@41..42 " "
-            RECORD_PAT_FIELD@42..43
-              IDENT_PAT@42..43
-                NAME@42..43
-                  IDENT@42..43 "f"
-            COMMA@43..44 ","
-            WHITESPACE@44..45 " "
-            RECORD_PAT_FIELD@45..54
-              IDENT_PAT@45..54
-                REF_KW@45..48 "ref"
-                WHITESPACE@48..49 " "
-                MUT_KW@49..52 "mut"
-                WHITESPACE@52..53 " "
-                NAME@53..54
-                  IDENT@53..54 "g"
-            WHITESPACE@54..55 " "
-            R_CURLY@55..56 "}"
-        WHITESPACE@56..57 " "
-        EQ@57..58 "="
-        WHITESPACE@58..59 " "
-        TUPLE_EXPR@59..61
-          L_PAREN@59..60 "("
-          R_PAREN@60..61 ")"
-        SEMICOLON@61..62 ";"
-      WHITESPACE@62..67 "\n    "
-      LET_STMT@67..90
-        LET_KW@67..70 "let"
-        WHITESPACE@70..71 " "
-        RECORD_PAT@71..84
-          PATH@71..72
-            PATH_SEGMENT@71..72
-              NAME_REF@71..72
-                IDENT@71..72 "S"
-          WHITESPACE@72..73 " "
-          RECORD_PAT_FIELD_LIST@73..84
-            L_CURLY@73..74 "{"
-            WHITESPACE@74..75 " "
-            RECORD_PAT_FIELD@75..79
-              NAME_REF@75..76
-                IDENT@75..76 "h"
-              COLON@76..77 ":"
-              WHITESPACE@77..78 " "
-              WILDCARD_PAT@78..79
-                UNDERSCORE@78..79 "_"
-            COMMA@79..80 ","
-            WHITESPACE@80..81 " "
-            DOT2@81..83 ".."
-            R_CURLY@83..84 "}"
-        WHITESPACE@84..85 " "
-        EQ@85..86 "="
-        WHITESPACE@86..87 " "
-        TUPLE_EXPR@87..89
-          L_PAREN@87..88 "("
-          R_PAREN@88..89 ")"
-        SEMICOLON@89..90 ";"
-      WHITESPACE@90..95 "\n    "
-      LET_STMT@95..116
-        LET_KW@95..98 "let"
-        WHITESPACE@98..99 " "
-        RECORD_PAT@99..110
-          PATH@99..100
-            PATH_SEGMENT@99..100
-              NAME_REF@99..100
-                IDENT@99..100 "S"
-          WHITESPACE@100..101 " "
-          RECORD_PAT_FIELD_LIST@101..110
-            L_CURLY@101..102 "{"
-            WHITESPACE@102..103 " "
-            RECORD_PAT_FIELD@103..107
-              NAME_REF@103..104
-                IDENT@103..104 "h"
-              COLON@104..105 ":"
-              WHITESPACE@105..106 " "
-              WILDCARD_PAT@106..107
-                UNDERSCORE@106..107 "_"
-            COMMA@107..108 ","
-            WHITESPACE@108..109 " "
-            R_CURLY@109..110 "}"
-        WHITESPACE@110..111 " "
-        EQ@111..112 "="
-        WHITESPACE@112..113 " "
-        TUPLE_EXPR@113..115
-          L_PAREN@113..114 "("
-          R_PAREN@114..115 ")"
-        SEMICOLON@115..116 ";"
-      WHITESPACE@116..117 "\n"
-      R_CURLY@117..118 "}"
-  WHITESPACE@118..119 "\n"
diff --git a/crates/syntax/test_data/parser/inline/ok/0102_record_field_pat_list.rs b/crates/syntax/test_data/parser/inline/ok/0102_record_field_pat_list.rs
deleted file mode 100644 (file)
index da3412f..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-fn foo() {
-    let S {} = ();
-    let S { f, ref mut g } = ();
-    let S { h: _, ..} = ();
-    let S { h: _, } = ();
-}
diff --git a/crates/syntax/test_data/parser/inline/ok/0102_record_pat_field_list.rast b/crates/syntax/test_data/parser/inline/ok/0102_record_pat_field_list.rast
new file mode 100644 (file)
index 0000000..866e60e
--- /dev/null
@@ -0,0 +1,132 @@
+SOURCE_FILE@0..119
+  FN@0..118
+    FN_KW@0..2 "fn"
+    WHITESPACE@2..3 " "
+    NAME@3..6
+      IDENT@3..6 "foo"
+    PARAM_LIST@6..8
+      L_PAREN@6..7 "("
+      R_PAREN@7..8 ")"
+    WHITESPACE@8..9 " "
+    BLOCK_EXPR@9..118
+      L_CURLY@9..10 "{"
+      WHITESPACE@10..15 "\n    "
+      LET_STMT@15..29
+        LET_KW@15..18 "let"
+        WHITESPACE@18..19 " "
+        RECORD_PAT@19..23
+          PATH@19..20
+            PATH_SEGMENT@19..20
+              NAME_REF@19..20
+                IDENT@19..20 "S"
+          WHITESPACE@20..21 " "
+          RECORD_PAT_FIELD_LIST@21..23
+            L_CURLY@21..22 "{"
+            R_CURLY@22..23 "}"
+        WHITESPACE@23..24 " "
+        EQ@24..25 "="
+        WHITESPACE@25..26 " "
+        TUPLE_EXPR@26..28
+          L_PAREN@26..27 "("
+          R_PAREN@27..28 ")"
+        SEMICOLON@28..29 ";"
+      WHITESPACE@29..34 "\n    "
+      LET_STMT@34..62
+        LET_KW@34..37 "let"
+        WHITESPACE@37..38 " "
+        RECORD_PAT@38..56
+          PATH@38..39
+            PATH_SEGMENT@38..39
+              NAME_REF@38..39
+                IDENT@38..39 "S"
+          WHITESPACE@39..40 " "
+          RECORD_PAT_FIELD_LIST@40..56
+            L_CURLY@40..41 "{"
+            WHITESPACE@41..42 " "
+            RECORD_PAT_FIELD@42..43
+              IDENT_PAT@42..43
+                NAME@42..43
+                  IDENT@42..43 "f"
+            COMMA@43..44 ","
+            WHITESPACE@44..45 " "
+            RECORD_PAT_FIELD@45..54
+              IDENT_PAT@45..54
+                REF_KW@45..48 "ref"
+                WHITESPACE@48..49 " "
+                MUT_KW@49..52 "mut"
+                WHITESPACE@52..53 " "
+                NAME@53..54
+                  IDENT@53..54 "g"
+            WHITESPACE@54..55 " "
+            R_CURLY@55..56 "}"
+        WHITESPACE@56..57 " "
+        EQ@57..58 "="
+        WHITESPACE@58..59 " "
+        TUPLE_EXPR@59..61
+          L_PAREN@59..60 "("
+          R_PAREN@60..61 ")"
+        SEMICOLON@61..62 ";"
+      WHITESPACE@62..67 "\n    "
+      LET_STMT@67..90
+        LET_KW@67..70 "let"
+        WHITESPACE@70..71 " "
+        RECORD_PAT@71..84
+          PATH@71..72
+            PATH_SEGMENT@71..72
+              NAME_REF@71..72
+                IDENT@71..72 "S"
+          WHITESPACE@72..73 " "
+          RECORD_PAT_FIELD_LIST@73..84
+            L_CURLY@73..74 "{"
+            WHITESPACE@74..75 " "
+            RECORD_PAT_FIELD@75..79
+              NAME_REF@75..76
+                IDENT@75..76 "h"
+              COLON@76..77 ":"
+              WHITESPACE@77..78 " "
+              WILDCARD_PAT@78..79
+                UNDERSCORE@78..79 "_"
+            COMMA@79..80 ","
+            WHITESPACE@80..81 " "
+            DOT2@81..83 ".."
+            R_CURLY@83..84 "}"
+        WHITESPACE@84..85 " "
+        EQ@85..86 "="
+        WHITESPACE@86..87 " "
+        TUPLE_EXPR@87..89
+          L_PAREN@87..88 "("
+          R_PAREN@88..89 ")"
+        SEMICOLON@89..90 ";"
+      WHITESPACE@90..95 "\n    "
+      LET_STMT@95..116
+        LET_KW@95..98 "let"
+        WHITESPACE@98..99 " "
+        RECORD_PAT@99..110
+          PATH@99..100
+            PATH_SEGMENT@99..100
+              NAME_REF@99..100
+                IDENT@99..100 "S"
+          WHITESPACE@100..101 " "
+          RECORD_PAT_FIELD_LIST@101..110
+            L_CURLY@101..102 "{"
+            WHITESPACE@102..103 " "
+            RECORD_PAT_FIELD@103..107
+              NAME_REF@103..104
+                IDENT@103..104 "h"
+              COLON@104..105 ":"
+              WHITESPACE@105..106 " "
+              WILDCARD_PAT@106..107
+                UNDERSCORE@106..107 "_"
+            COMMA@107..108 ","
+            WHITESPACE@108..109 " "
+            R_CURLY@109..110 "}"
+        WHITESPACE@110..111 " "
+        EQ@111..112 "="
+        WHITESPACE@112..113 " "
+        TUPLE_EXPR@113..115
+          L_PAREN@113..114 "("
+          R_PAREN@114..115 ")"
+        SEMICOLON@115..116 ";"
+      WHITESPACE@116..117 "\n"
+      R_CURLY@117..118 "}"
+  WHITESPACE@118..119 "\n"
diff --git a/crates/syntax/test_data/parser/inline/ok/0102_record_pat_field_list.rs b/crates/syntax/test_data/parser/inline/ok/0102_record_pat_field_list.rs
new file mode 100644 (file)
index 0000000..da3412f
--- /dev/null
@@ -0,0 +1,6 @@
+fn foo() {
+    let S {} = ();
+    let S { f, ref mut g } = ();
+    let S { h: _, ..} = ();
+    let S { h: _, } = ();
+}
diff --git a/crates/syntax/test_data/parser/inline/ok/0145_record_field_pat.rast b/crates/syntax/test_data/parser/inline/ok/0145_record_field_pat.rast
deleted file mode 100644 (file)
index 925409b..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-SOURCE_FILE@0..63
-  FN@0..62
-    FN_KW@0..2 "fn"
-    WHITESPACE@2..3 " "
-    NAME@3..6
-      IDENT@3..6 "foo"
-    PARAM_LIST@6..8
-      L_PAREN@6..7 "("
-      R_PAREN@7..8 ")"
-    WHITESPACE@8..9 " "
-    BLOCK_EXPR@9..62
-      L_CURLY@9..10 "{"
-      WHITESPACE@10..15 "\n    "
-      LET_STMT@15..35
-        LET_KW@15..18 "let"
-        WHITESPACE@18..19 " "
-        RECORD_PAT@19..29
-          PATH@19..20
-            PATH_SEGMENT@19..20
-              NAME_REF@19..20
-                IDENT@19..20 "S"
-          WHITESPACE@20..21 " "
-          RECORD_PAT_FIELD_LIST@21..29
-            L_CURLY@21..22 "{"
-            WHITESPACE@22..23 " "
-            RECORD_PAT_FIELD@23..27
-              NAME_REF@23..24
-                INT_NUMBER@23..24 "0"
-              COLON@24..25 ":"
-              WHITESPACE@25..26 " "
-              LITERAL_PAT@26..27
-                LITERAL@26..27
-                  INT_NUMBER@26..27 "1"
-            WHITESPACE@27..28 " "
-            R_CURLY@28..29 "}"
-        WHITESPACE@29..30 " "
-        EQ@30..31 "="
-        WHITESPACE@31..32 " "
-        TUPLE_EXPR@32..34
-          L_PAREN@32..33 "("
-          R_PAREN@33..34 ")"
-        SEMICOLON@34..35 ";"
-      WHITESPACE@35..40 "\n    "
-      LET_STMT@40..60
-        LET_KW@40..43 "let"
-        WHITESPACE@43..44 " "
-        RECORD_PAT@44..54
-          PATH@44..45
-            PATH_SEGMENT@44..45
-              NAME_REF@44..45
-                IDENT@44..45 "S"
-          WHITESPACE@45..46 " "
-          RECORD_PAT_FIELD_LIST@46..54
-            L_CURLY@46..47 "{"
-            WHITESPACE@47..48 " "
-            RECORD_PAT_FIELD@48..52
-              NAME_REF@48..49
-                IDENT@48..49 "x"
-              COLON@49..50 ":"
-              WHITESPACE@50..51 " "
-              LITERAL_PAT@51..52
-                LITERAL@51..52
-                  INT_NUMBER@51..52 "1"
-            WHITESPACE@52..53 " "
-            R_CURLY@53..54 "}"
-        WHITESPACE@54..55 " "
-        EQ@55..56 "="
-        WHITESPACE@56..57 " "
-        TUPLE_EXPR@57..59
-          L_PAREN@57..58 "("
-          R_PAREN@58..59 ")"
-        SEMICOLON@59..60 ";"
-      WHITESPACE@60..61 "\n"
-      R_CURLY@61..62 "}"
-  WHITESPACE@62..63 "\n"
diff --git a/crates/syntax/test_data/parser/inline/ok/0145_record_field_pat.rs b/crates/syntax/test_data/parser/inline/ok/0145_record_field_pat.rs
deleted file mode 100644 (file)
index 26b1d5f..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-fn foo() {
-    let S { 0: 1 } = ();
-    let S { x: 1 } = ();
-}
diff --git a/crates/syntax/test_data/parser/inline/ok/0145_record_pat_field.rast b/crates/syntax/test_data/parser/inline/ok/0145_record_pat_field.rast
new file mode 100644 (file)
index 0000000..925409b
--- /dev/null
@@ -0,0 +1,75 @@
+SOURCE_FILE@0..63
+  FN@0..62
+    FN_KW@0..2 "fn"
+    WHITESPACE@2..3 " "
+    NAME@3..6
+      IDENT@3..6 "foo"
+    PARAM_LIST@6..8
+      L_PAREN@6..7 "("
+      R_PAREN@7..8 ")"
+    WHITESPACE@8..9 " "
+    BLOCK_EXPR@9..62
+      L_CURLY@9..10 "{"
+      WHITESPACE@10..15 "\n    "
+      LET_STMT@15..35
+        LET_KW@15..18 "let"
+        WHITESPACE@18..19 " "
+        RECORD_PAT@19..29
+          PATH@19..20
+            PATH_SEGMENT@19..20
+              NAME_REF@19..20
+                IDENT@19..20 "S"
+          WHITESPACE@20..21 " "
+          RECORD_PAT_FIELD_LIST@21..29
+            L_CURLY@21..22 "{"
+            WHITESPACE@22..23 " "
+            RECORD_PAT_FIELD@23..27
+              NAME_REF@23..24
+                INT_NUMBER@23..24 "0"
+              COLON@24..25 ":"
+              WHITESPACE@25..26 " "
+              LITERAL_PAT@26..27
+                LITERAL@26..27
+                  INT_NUMBER@26..27 "1"
+            WHITESPACE@27..28 " "
+            R_CURLY@28..29 "}"
+        WHITESPACE@29..30 " "
+        EQ@30..31 "="
+        WHITESPACE@31..32 " "
+        TUPLE_EXPR@32..34
+          L_PAREN@32..33 "("
+          R_PAREN@33..34 ")"
+        SEMICOLON@34..35 ";"
+      WHITESPACE@35..40 "\n    "
+      LET_STMT@40..60
+        LET_KW@40..43 "let"
+        WHITESPACE@43..44 " "
+        RECORD_PAT@44..54
+          PATH@44..45
+            PATH_SEGMENT@44..45
+              NAME_REF@44..45
+                IDENT@44..45 "S"
+          WHITESPACE@45..46 " "
+          RECORD_PAT_FIELD_LIST@46..54
+            L_CURLY@46..47 "{"
+            WHITESPACE@47..48 " "
+            RECORD_PAT_FIELD@48..52
+              NAME_REF@48..49
+                IDENT@48..49 "x"
+              COLON@49..50 ":"
+              WHITESPACE@50..51 " "
+              LITERAL_PAT@51..52
+                LITERAL@51..52
+                  INT_NUMBER@51..52 "1"
+            WHITESPACE@52..53 " "
+            R_CURLY@53..54 "}"
+        WHITESPACE@54..55 " "
+        EQ@55..56 "="
+        WHITESPACE@56..57 " "
+        TUPLE_EXPR@57..59
+          L_PAREN@57..58 "("
+          R_PAREN@58..59 ")"
+        SEMICOLON@59..60 ";"
+      WHITESPACE@60..61 "\n"
+      R_CURLY@61..62 "}"
+  WHITESPACE@62..63 "\n"
diff --git a/crates/syntax/test_data/parser/inline/ok/0145_record_pat_field.rs b/crates/syntax/test_data/parser/inline/ok/0145_record_pat_field.rs
new file mode 100644 (file)
index 0000000..26b1d5f
--- /dev/null
@@ -0,0 +1,4 @@
+fn foo() {
+    let S { 0: 1 } = ();
+    let S { x: 1 } = ();
+}