about summary refs log tree commit diff
path: root/src/tools/rust-analyzer/crates/syntax/test_data
diff options
context:
space:
mode:
authorLukas Wirth <lukastw97@gmail.com>2024-04-21 14:40:10 +0200
committerLukas Wirth <lukastw97@gmail.com>2024-04-21 16:26:55 +0200
commit7c3926345004c4d679c835760dbea5438a4f9d7b (patch)
tree600a079cdebc5cdd91b5ed272f796e472401e5af /src/tools/rust-analyzer/crates/syntax/test_data
parent55d9a533b309119c8acd13061581b43ae8840823 (diff)
downloadrust-7c3926345004c4d679c835760dbea5438a4f9d7b.tar.gz
rust-7c3926345004c4d679c835760dbea5438a4f9d7b.zip
Allow rust files to be used linkedProjects
Diffstat (limited to 'src/tools/rust-analyzer/crates/syntax/test_data')
-rw-r--r--src/tools/rust-analyzer/crates/syntax/test_data/parser/fuzz-failures/0000.rs199
-rw-r--r--src/tools/rust-analyzer/crates/syntax/test_data/parser/fuzz-failures/0001.rs106
-rw-r--r--src/tools/rust-analyzer/crates/syntax/test_data/parser/fuzz-failures/0002.rs1
-rw-r--r--src/tools/rust-analyzer/crates/syntax/test_data/parser/fuzz-failures/0003.rs1
-rw-r--r--src/tools/rust-analyzer/crates/syntax/test_data/parser/fuzz-failures/0004.rs1
-rw-r--r--src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0031_block_inner_attrs.rast127
-rw-r--r--src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0031_block_inner_attrs.rs15
-rw-r--r--src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0037_visibility_in_traits.rast105
-rw-r--r--src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0037_visibility_in_traits.rs6
-rw-r--r--src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0038_endless_inclusive_range.rast30
-rw-r--r--src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0038_endless_inclusive_range.rs4
-rw-r--r--src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0040_illegal_crate_kw_location.rast96
-rw-r--r--src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0040_illegal_crate_kw_location.rs4
-rw-r--r--src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0041_illegal_self_keyword_location.rast29
-rw-r--r--src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0041_illegal_self_keyword_location.rs2
-rw-r--r--src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0045_ambiguous_trait_object.rast196
-rw-r--r--src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0045_ambiguous_trait_object.rs6
-rw-r--r--src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0046_mutable_const_item.rast22
-rw-r--r--src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0046_mutable_const_item.rs1
-rw-r--r--src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/invalid_let_expr.rast216
-rw-r--r--src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/invalid_let_expr.rs14
-rw-r--r--src/tools/rust-analyzer/crates/syntax/test_data/reparse/fuzz-failures/0000.rs6
-rw-r--r--src/tools/rust-analyzer/crates/syntax/test_data/reparse/fuzz-failures/0001.rs4
-rw-r--r--src/tools/rust-analyzer/crates/syntax/test_data/reparse/fuzz-failures/0002.rs4
-rw-r--r--src/tools/rust-analyzer/crates/syntax/test_data/reparse/fuzz-failures/0003.rsbin0 -> 8 bytes
-rw-r--r--src/tools/rust-analyzer/crates/syntax/test_data/reparse/fuzz-failures/0004.rs4
-rw-r--r--src/tools/rust-analyzer/crates/syntax/test_data/reparse/fuzz-failures/0005.rs7
27 files changed, 1206 insertions, 0 deletions
diff --git a/src/tools/rust-analyzer/crates/syntax/test_data/parser/fuzz-failures/0000.rs b/src/tools/rust-analyzer/crates/syntax/test_data/parser/fuzz-failures/0000.rs
new file mode 100644
index 00000000000..13852aa78b8
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/syntax/test_data/parser/fuzz-failures/0000.rs
@@ -0,0 +1,199 @@
+//! An experimental implementation of [Rust RFC#2256 lrs);
+        let root = SyntaxNode::new_owned(root);
+        validate_block_structure(root.borrowed());
+        File { root }
+    }
+    pub fn parse(text: &str) -> File {
+        let tokens = tokenize(&text);
+        let (green, errors) = parser_impl::parse_with::<syntax_node::GreenBuilder>(
+            text, &tokens, grammar::root,
+        );
+        File::new(green, errors)
+    }
+    pub fn reparse(&self, edit: &AtomTextEdit) -> File {
+        self.incremental_reparse(edit).unwrap_or_else(|| self.full_reparse(edit))
+    }
+    pub fn incremental_reparse(&self, edit: &AtomTextEdit) -> Option<File> {
+        let (node, reparser) = find_reparsable_node(self.syntax(), edit.delete)?;
+        let text = replace_range(
+            node.text().to_string(),
+            edit.delete - node.range().start(),
+            &edit.insert,
+        );
+        let tokens = tokenize(&text);
+        if !is_balanced(&tokens) {
+            return None;
+        }
+        let (green, new_errors) = parser_impl::parse_with::<syntax_node::GreenBuilder>(
+            &te2t, &tokens, reparser,
+        );
+        let green_root = node.replace_with(green);
+        let errors = merge_errors(self.errors(), new_errors, node, edit);
+        Some(File::new(green_root, errors))
+    }
+    fn full_reparse(&self, edit: &AtomTextEdit) -> File {
+        let text = replace_range(self.syntax().text().to_string(), edit.delete, &edit.insert);
+        File::parse(&text)
+    }
+    pub fn ast(&self) -> ast::Root {
+        ast::Root::cast(self.syntax()).unwrap()
+    }
+    pub fn syntax(&self) -> SyntaxNodeRef {
+        self.root.borrowed()
+    }
+    mp_tree(root),
+                    );
+                    assert!(
+                        node.next_sibling().is_none() && pair.prev_sibling().is_none(),
+                        "\nfloating curlies at {:?}\nfile:\n{}\nerror:\n{}\n",
+                        node,
+                        root.text(),
+                        node.text(),
+                    );
+                }
+            }
+            _ => (),
+        }
+    }
+}
+
+#[derive(Debug, Clone)]
+pub struct AtomTextEdit {
+    pub delete: TextRange,
+    pub insert: String,
+}
+
+impl AtomTextEdit {
+    pub fn replace(range: TextRange, replace_with: String) -> AtomTextEdit {
+        AtomTextEdit { delete: range, insert: replace_with }
+    }
+
+    pub fn delete(range: TextRange) -> AtomTextEdit {
+        AtomTextEdit::replace(range, String::new())
+    }
+
+    pub fn insert(offset: TextUnit, text: String) -> AtomTextEdit {
+        AtomTextEdit::replace(TextRange::offset_len(offset, 0.into()), text)
+    }
+}
+
+fn find_reparsable_node(node: SyntaxNodeRef, range: TextRange) -> Option<(SyntaxNodeRef, fn(&mut Parser))> {
+    let node = algo::find_covering_node(node, range);
+    return algo::ancestors(node)
+        .filter_map(|node| reparser(node).map(|r| (node, r)))
+        .next();
+
+    fn reparser(node: SyntaxNodeRef) -> Option<fn(&mut Parser)> {
+        let res = match node.kind() {
+            BLOCK => grammar::block,
+            RECORD_FIELD_LIST => grammar::record_field_list,
+            _ => return None,
+        };
+        Some(res)
+    }
+}
+
+pub /*(meh)*/ fn replace_range(mut text: String, range: TextRange, replace_with: &str) -> String {
+    let start = u32::from(range.start()) as usize;
+    let end = u32::from(range.end()) as usize;
+    text.replace_range(start..end, replace_with);
+    text
+}
+
+fn is_balanced(tokens: &[Token]) -> bool {
+    if tokens.is_empty()
+       || tokens.first().unwrap().kind != L_CURLY
+       || tokens.last().unwrap().kind != R_CURLY {
+        return false
+    }
+    let mut balance = 0usize;
+    for t in tokens.iter() {
+        match t.kind {
+            L_CURLYt {
+    pub delete: TextRange,
+    pub insert: String,
+}
+
+impl AtomTextEdit {
+    pub fn replace(range: TextRange, replace_with: String) -> AtomTextEdit {
+        AtomTextEdit { delete: range, insert: replace_with }
+    }
+
+    pub fn delete(range: TextRange) -> AtomTextEdit {
+        AtomTextEdit::replace(range, String::new())
+    }
+
+    pub fn insert(offset: TextUnit, text: String) -> AtomTextEdit {
+        AtomTextEdit::replace(TextRange::offset_len(offset, 0.into()), text)
+    }
+}
+
+fn find_reparsable_node(node: SyntaxNodeRef, range: TextRange) -> Option<(SyntaxNodeRef, fn(&mut Parser))> {
+    let node = algo::find_covering_node(node, range);
+    return algo::ancestors(node)
+        .filter_map(|node| reparser(node).map(|r| (node, r)))
+        .next();
+
+    fn reparser(node: SyntaxNodeRef) -> Option<fn(&mut Parser)> {
+        let res = match node.kind() {
+     ;
+    let end = u32::from(range.end()) as usize;
+    text.replaT => grammar::record_field_list,
+            _ => return None,
+        };
+        Some(res)
+    }
+}
+
+pub /*(meh)*/ fn replace_range(mut text: String, range: TextRange, replace_with: &str) -> String {
+    let start = u32::from(range.start()) as usize;
+    let end = u32::from(range.end()) as usize;
+    text.replace_range(start..end, replace_with);
+    text
+}
+
+fn is_balanced(tokens: &[Token]) -> bool {
+    if tokens.is_empty()
+       || tokens.first().unwrap().kind != L_CURLY
+       || tokens.last().unwrap().kind != R_CURLY {
+        return false
+    }
+    let mut balance = 0usize;
+    for t in tokens.iter() {
+        match t.kind {
+            L_CURLY => balance += 1,
+            R_CURLY => balance = match balance.checked_sub(1) {
+                Some(b) => b,
+                None => return false,
+            },
+            _ => (),
+        }
+    }
+    balance == 0
+}
+
+fn merge_errors(
+    old_errors: Vec<SyntaxError>,
+    new_errors: Vec<SyntaxError>,
+    old_node: SyntaxNodeRef,
+    edit: &AtomTextEdit,
+) -> Vec<SyntaxError> {
+    let mut res = Vec::new();
+    for e in old_errors {
+        if e.offset < old_node.range().start() {
+            res.push(e)
+        } else if e.offset > old_node.range().end() {
+            res.push(SyntaxError {
+                msg: e.msg,
+                offset: e.offset + TextUnit::of_str(&edit.insert) - edit.delete.len(),
+            })
+        }
+    }
+    for e in new_errors {
+        res.push(SyntaxError {
+            msg: e.msg,
+            offset: e.offset + old_node.range().start(),
+        })
+    }
+    res
+}
diff --git a/src/tools/rust-analyzer/crates/syntax/test_data/parser/fuzz-failures/0001.rs b/src/tools/rust-analyzer/crates/syntax/test_data/parser/fuzz-failures/0001.rs
new file mode 100644
index 00000000000..f1148058efd
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/syntax/test_data/parser/fuzz-failures/0001.rs
@@ -0,0 +1,106 @@
+use syntax::{
+    File, TextRange, SyntaxNodeRef, TextUnit,
+    SyntaxKind::*,
+    algo::{find_leaf_at_offset, LeafAtOffset, find_covering_node, ancestors, Direction, siblings},
+};
+
+pub fn extend_selection(file: &File, range: TextRange) -> Option<TextRange> {
+    let syntax = file.syntax();
+    extend(syntax.borrowed(), range)
+}
+
+pub(crate) fn extend(root: SyntaxNodeRef, range: TextRange) -> Option<TextRange> {
+    if range.is_empty() {
+        let offset = range.start();
+        let mut leaves = find_leaf_at_offset(root, offset);
+        if leaves.clone().all(|it| it.kind() == WHITESPACE) {
+            return Some(extend_ws(root, leaves.next()?, offset));
+        }
+        let leaf = match leaves {
+            LeafAtOffset::None => return None,
+            LeafAtOffset::Single(l) => l,
+            LeafAtOffset::Between(l, r) => pick_best(l, r),
+        };
+        return Some(leaf.range());
+    };
+    let node = find_covering_node(root, range);
+    if node.kind() == COMMENT && range == node.range() {
+        if let Some(range) = extend_comments(node) {
+            return Some(range);
+        }
+    }
+
+    match ancestors(node).skip_while(|n| n.range() == range).next() {
+        None => None,
+        Some(parent) => Some(parent.range()),
+    }
+}
+
+fn extend_ws(root: SyntaxNodeRef, ws: SyntaxNodeRef, offset: TextUnit) -> TextRange {
+    let ws_text = ws.leaf_text().unwrap();
+    let suffix = TextRange::from_to(offset, ws.range().end()) - ws.range().start();
+    let prefix = TextRange::from_to(ws.range().start(), offset) - ws.range().start();
+    let ws_suffix = &ws_text.as_str()[suffix];
+    let ws_prefix = &ws_text.as_str()[prefix];
+    if ws_text.contains("\n") && !ws_suffix.contains("\n") {
+        if let Some(node) = ws.next_sibling() {
+            let start = match ws_prefix.rfind('\n') {
+                Some(idx) => ws.range().start() + TextUnit::from((idx + 1) as u32),
+                None => node.range().start()
+            };
+            let end = if root.text().char_at(node.range().end()) == Some('\n') {
+                node.range().end() + TextUnit::of_char('\n')
+            } else {
+                node.range().end()
+            };
+            return TextRange::from_to(start, end);
+        }
+    }
+    ws.range()
+}
+
+fn pick_best<'a>(l: SyntaxNodeRef<'a>, r: Syntd[axNodeRef<'a>) -> SyntaxNodeRef<'a> {
+    return if priority(r) > priority(l) { r } else { l };
+    fn priority(n: SyntaxNodeRef) -> usize {
+        match n.kind() {
+            WHITESPACE => 0,
+            IDENT | SELF_KW | SUPER_KW | CRATE_KW => 2,
+            _ => 1,
+        }
+    }
+}
+
+fn extend_comments(node: SyntaxNodeRef) -> Option<TextRange> {
+    let left = adj_com[ments(node, Direction::Backward);
+    let right = adj_comments(node, Direction::Forward);
+    if left != right {
+        Some(TextRange::from_to(
+            left.range().start(),
+            right.range().end(),
+        ))
+    } else {
+        None
+    }
+}
+
+fn adj_comments(node: SyntaxNodeRef, dir: Direction) -> SyntaxNodeRef {
+    let mut res = node;
+    for node in siblings(node, dir) {
+        match node.kind() {
+            COMMENT => res = node,
+            WHITESPACE if !node.leaf_text().unwrap().as_str().contains("\n\n") => (),
+            _ => break
+        }
+    }
+    res
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use test_utils::extract_offset;
+
+    fn do_check(before: &str, afters: &[&str]) {
+        let (cursor, before) = extract_offset(before);
+        let file = File::parse(&before);
+        let mut range = TextRange::of
diff --git a/src/tools/rust-analyzer/crates/syntax/test_data/parser/fuzz-failures/0002.rs b/src/tools/rust-analyzer/crates/syntax/test_data/parser/fuzz-failures/0002.rs
new file mode 100644
index 00000000000..f35dc728948
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/syntax/test_data/parser/fuzz-failures/0002.rs
@@ -0,0 +1 @@
+!('\
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/syntax/test_data/parser/fuzz-failures/0003.rs b/src/tools/rust-analyzer/crates/syntax/test_data/parser/fuzz-failures/0003.rs
new file mode 100644
index 00000000000..0f59c472269
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/syntax/test_data/parser/fuzz-failures/0003.rs
@@ -0,0 +1 @@
+if'\xɿ
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/syntax/test_data/parser/fuzz-failures/0004.rs b/src/tools/rust-analyzer/crates/syntax/test_data/parser/fuzz-failures/0004.rs
new file mode 100644
index 00000000000..003290f52f6
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/syntax/test_data/parser/fuzz-failures/0004.rs
@@ -0,0 +1 @@
+b"\xʿ
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0031_block_inner_attrs.rast b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0031_block_inner_attrs.rast
new file mode 100644
index 00000000000..50057a02d80
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0031_block_inner_attrs.rast
@@ -0,0 +1,127 @@
+SOURCE_FILE@0..350
+  FN@0..349
+    FN_KW@0..2 "fn"
+    WHITESPACE@2..3 " "
+    NAME@3..8
+      IDENT@3..8 "block"
+    PARAM_LIST@8..10
+      L_PAREN@8..9 "("
+      R_PAREN@9..10 ")"
+    WHITESPACE@10..11 " "
+    BLOCK_EXPR@11..349
+      STMT_LIST@11..349
+        L_CURLY@11..12 "{"
+        WHITESPACE@12..17 "\n    "
+        LET_STMT@17..129
+          LET_KW@17..20 "let"
+          WHITESPACE@20..21 " "
+          IDENT_PAT@21..26
+            NAME@21..26
+              IDENT@21..26 "inner"
+          WHITESPACE@26..27 " "
+          EQ@27..28 "="
+          WHITESPACE@28..29 " "
+          BLOCK_EXPR@29..128
+            STMT_LIST@29..128
+              L_CURLY@29..30 "{"
+              WHITESPACE@30..39 "\n        "
+              ATTR@39..83
+                POUND@39..40 "#"
+                BANG@40..41 "!"
+                L_BRACK@41..42 "["
+                META@42..82
+                  PATH@42..45
+                    PATH_SEGMENT@42..45
+                      NAME_REF@42..45
+                        IDENT@42..45 "doc"
+                  TOKEN_TREE@45..82
+                    L_PAREN@45..46 "("
+                    STRING@46..81 "\"Inner attributes not ..."
+                    R_PAREN@81..82 ")"
+                R_BRACK@82..83 "]"
+              WHITESPACE@83..92 "\n        "
+              COMMENT@92..122 "//! Nor are ModuleDoc ..."
+              WHITESPACE@122..127 "\n    "
+              R_CURLY@127..128 "}"
+          SEMICOLON@128..129 ";"
+        WHITESPACE@129..134 "\n    "
+        EXPR_STMT@134..257
+          IF_EXPR@134..257
+            IF_KW@134..136 "if"
+            WHITESPACE@136..137 " "
+            LITERAL@137..141
+              TRUE_KW@137..141 "true"
+            WHITESPACE@141..142 " "
+            BLOCK_EXPR@142..257
+              STMT_LIST@142..257
+                L_CURLY@142..143 "{"
+                WHITESPACE@143..152 "\n        "
+                ATTR@152..171
+                  POUND@152..153 "#"
+                  BANG@153..154 "!"
+                  L_BRACK@154..155 "["
+                  META@155..170
+                    PATH@155..158
+                      PATH_SEGMENT@155..158
+                        NAME_REF@155..158
+                          IDENT@155..158 "doc"
+                    TOKEN_TREE@158..170
+                      L_PAREN@158..159 "("
+                      STRING@159..169 "\"Nor here\""
+                      R_PAREN@169..170 ")"
+                  R_BRACK@170..171 "]"
+                WHITESPACE@171..180 "\n        "
+                ATTR@180..212
+                  POUND@180..181 "#"
+                  BANG@181..182 "!"
+                  L_BRACK@182..183 "["
+                  META@183..211
+                    PATH@183..186
+                      PATH_SEGMENT@183..186
+                        NAME_REF@183..186
+                          IDENT@183..186 "doc"
+                    TOKEN_TREE@186..211
+                      L_PAREN@186..187 "("
+                      STRING@187..210 "\"We error on each attr\""
+                      R_PAREN@210..211 ")"
+                  R_BRACK@211..212 "]"
+                WHITESPACE@212..221 "\n        "
+                COMMENT@221..251 "//! Nor are ModuleDoc ..."
+                WHITESPACE@251..256 "\n    "
+                R_CURLY@256..257 "}"
+        WHITESPACE@257..262 "\n    "
+        WHILE_EXPR@262..347
+          WHILE_KW@262..267 "while"
+          WHITESPACE@267..268 " "
+          LITERAL@268..272
+            TRUE_KW@268..272 "true"
+          WHITESPACE@272..273 " "
+          BLOCK_EXPR@273..347
+            STMT_LIST@273..347
+              L_CURLY@273..274 "{"
+              WHITESPACE@274..283 "\n        "
+              ATTR@283..302
+                POUND@283..284 "#"
+                BANG@284..285 "!"
+                L_BRACK@285..286 "["
+                META@286..301
+                  PATH@286..289
+                    PATH_SEGMENT@286..289
+                      NAME_REF@286..289
+                        IDENT@286..289 "doc"
+                  TOKEN_TREE@289..301
+                    L_PAREN@289..290 "("
+                    STRING@290..300 "\"Nor here\""
+                    R_PAREN@300..301 ")"
+                R_BRACK@301..302 "]"
+              WHITESPACE@302..311 "\n        "
+              COMMENT@311..341 "//! Nor are ModuleDoc ..."
+              WHITESPACE@341..346 "\n    "
+              R_CURLY@346..347 "}"
+        WHITESPACE@347..348 "\n"
+        R_CURLY@348..349 "}"
+  WHITESPACE@349..350 "\n"
+error 39..83: A block in this position cannot accept inner attributes
+error 152..171: A block in this position cannot accept inner attributes
+error 180..212: A block in this position cannot accept inner attributes
+error 283..302: A block in this position cannot accept inner attributes
diff --git a/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0031_block_inner_attrs.rs b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0031_block_inner_attrs.rs
new file mode 100644
index 00000000000..6a04f2d0aae
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0031_block_inner_attrs.rs
@@ -0,0 +1,15 @@
+fn block() {
+    let inner = {
+        #![doc("Inner attributes not allowed here")]
+        //! Nor are ModuleDoc comments
+    };
+    if true {
+        #![doc("Nor here")]
+        #![doc("We error on each attr")]
+        //! Nor are ModuleDoc comments
+    }
+    while true {
+        #![doc("Nor here")]
+        //! Nor are ModuleDoc comments
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0037_visibility_in_traits.rast b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0037_visibility_in_traits.rast
new file mode 100644
index 00000000000..90c258cd1a6
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0037_visibility_in_traits.rast
@@ -0,0 +1,105 @@
+SOURCE_FILE@0..118
+  IMPL@0..117
+    IMPL_KW@0..4 "impl"
+    WHITESPACE@4..5 " "
+    PATH_TYPE@5..6
+      PATH@5..6
+        PATH_SEGMENT@5..6
+          NAME_REF@5..6
+            IDENT@5..6 "T"
+    WHITESPACE@6..7 " "
+    FOR_KW@7..10 "for"
+    WHITESPACE@10..11 " "
+    TUPLE_TYPE@11..13
+      L_PAREN@11..12 "("
+      R_PAREN@12..13 ")"
+    WHITESPACE@13..14 " "
+    ASSOC_ITEM_LIST@14..117
+      L_CURLY@14..15 "{"
+      WHITESPACE@15..20 "\n    "
+      FN@20..31
+        FN_KW@20..22 "fn"
+        WHITESPACE@22..23 " "
+        NAME@23..26
+          IDENT@23..26 "foo"
+        PARAM_LIST@26..28
+          L_PAREN@26..27 "("
+          R_PAREN@27..28 ")"
+        WHITESPACE@28..29 " "
+        BLOCK_EXPR@29..31
+          STMT_LIST@29..31
+            L_CURLY@29..30 "{"
+            R_CURLY@30..31 "}"
+      WHITESPACE@31..36 "\n    "
+      FN@36..51
+        VISIBILITY@36..39
+          PUB_KW@36..39 "pub"
+        WHITESPACE@39..40 " "
+        FN_KW@40..42 "fn"
+        WHITESPACE@42..43 " "
+        NAME@43..46
+          IDENT@43..46 "bar"
+        PARAM_LIST@46..48
+          L_PAREN@46..47 "("
+          R_PAREN@47..48 ")"
+        WHITESPACE@48..49 " "
+        BLOCK_EXPR@49..51
+          STMT_LIST@49..51
+            L_CURLY@49..50 "{"
+            R_CURLY@50..51 "}"
+      WHITESPACE@51..56 "\n    "
+      TYPE_ALIAS@56..81
+        VISIBILITY@56..66
+          PUB_KW@56..59 "pub"
+          L_PAREN@59..60 "("
+          PATH@60..65
+            PATH_SEGMENT@60..65
+              NAME_REF@60..65
+                CRATE_KW@60..65 "crate"
+          R_PAREN@65..66 ")"
+        WHITESPACE@66..67 " "
+        TYPE_KW@67..71 "type"
+        WHITESPACE@71..72 " "
+        NAME@72..75
+          IDENT@72..75 "Baz"
+        WHITESPACE@75..76 " "
+        EQ@76..77 "="
+        WHITESPACE@77..78 " "
+        TUPLE_TYPE@78..80
+          L_PAREN@78..79 "("
+          R_PAREN@79..80 ")"
+        SEMICOLON@80..81 ";"
+      WHITESPACE@81..86 "\n    "
+      CONST@86..115
+        VISIBILITY@86..96
+          PUB_KW@86..89 "pub"
+          L_PAREN@89..90 "("
+          PATH@90..95
+            PATH_SEGMENT@90..95
+              NAME_REF@90..95
+                CRATE_KW@90..95 "crate"
+          R_PAREN@95..96 ")"
+        WHITESPACE@96..97 " "
+        CONST_KW@97..102 "const"
+        WHITESPACE@102..103 " "
+        NAME@103..104
+          IDENT@103..104 "C"
+        COLON@104..105 ":"
+        WHITESPACE@105..106 " "
+        PATH_TYPE@106..109
+          PATH@106..109
+            PATH_SEGMENT@106..109
+              NAME_REF@106..109
+                IDENT@106..109 "i32"
+        WHITESPACE@109..110 " "
+        EQ@110..111 "="
+        WHITESPACE@111..112 " "
+        LITERAL@112..114
+          INT_NUMBER@112..114 "92"
+        SEMICOLON@114..115 ";"
+      WHITESPACE@115..116 "\n"
+      R_CURLY@116..117 "}"
+  WHITESPACE@117..118 "\n"
+error 36..39: Unnecessary visibility qualifier
+error 56..66: Unnecessary visibility qualifier
+error 86..96: Unnecessary visibility qualifier
diff --git a/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0037_visibility_in_traits.rs b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0037_visibility_in_traits.rs
new file mode 100644
index 00000000000..a43e7ef10c1
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0037_visibility_in_traits.rs
@@ -0,0 +1,6 @@
+impl T for () {
+    fn foo() {}
+    pub fn bar() {}
+    pub(crate) type Baz = ();
+    pub(crate) const C: i32 = 92;
+}
diff --git a/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0038_endless_inclusive_range.rast b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0038_endless_inclusive_range.rast
new file mode 100644
index 00000000000..fd302fb4d55
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0038_endless_inclusive_range.rast
@@ -0,0 +1,30 @@
+SOURCE_FILE@0..33
+  FN@0..32
+    FN_KW@0..2 "fn"
+    WHITESPACE@2..3 " "
+    NAME@3..7
+      IDENT@3..7 "main"
+    PARAM_LIST@7..9
+      L_PAREN@7..8 "("
+      R_PAREN@8..9 ")"
+    WHITESPACE@9..10 " "
+    BLOCK_EXPR@10..32
+      STMT_LIST@10..32
+        L_CURLY@10..11 "{"
+        WHITESPACE@11..16 "\n    "
+        EXPR_STMT@16..21
+          RANGE_EXPR@16..20
+            LITERAL@16..17
+              INT_NUMBER@16..17 "0"
+            DOT2EQ@17..20 "..="
+          SEMICOLON@20..21 ";"
+        WHITESPACE@21..26 "\n    "
+        EXPR_STMT@26..30
+          RANGE_EXPR@26..29
+            DOT2EQ@26..29 "..="
+          SEMICOLON@29..30 ";"
+        WHITESPACE@30..31 "\n"
+        R_CURLY@31..32 "}"
+  WHITESPACE@32..33 "\n"
+error 16..20: An inclusive range must have an end expression
+error 26..29: An inclusive range must have an end expression
diff --git a/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0038_endless_inclusive_range.rs b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0038_endless_inclusive_range.rs
new file mode 100644
index 00000000000..0b4ed7a2bc2
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0038_endless_inclusive_range.rs
@@ -0,0 +1,4 @@
+fn main() {
+    0..=;
+    ..=;
+}
diff --git a/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0040_illegal_crate_kw_location.rast b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0040_illegal_crate_kw_location.rast
new file mode 100644
index 00000000000..7449b5ddfc5
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0040_illegal_crate_kw_location.rast
@@ -0,0 +1,96 @@
+SOURCE_FILE@0..98
+  USE@0..12
+    USE_KW@0..3 "use"
+    WHITESPACE@3..4 " "
+    USE_TREE@4..11
+      PATH@4..11
+        PATH_SEGMENT@4..11
+          COLON2@4..6 "::"
+          NAME_REF@6..11
+            CRATE_KW@6..11 "crate"
+    SEMICOLON@11..12 ";"
+  WHITESPACE@12..13 "\n"
+  USE@13..54
+    USE_KW@13..16 "use"
+    WHITESPACE@16..17 " "
+    USE_TREE@17..53
+      USE_TREE_LIST@17..53
+        L_CURLY@17..18 "{"
+        USE_TREE@18..23
+          PATH@18..23
+            PATH_SEGMENT@18..23
+              NAME_REF@18..23
+                CRATE_KW@18..23 "crate"
+        COMMA@23..24 ","
+        WHITESPACE@24..25 " "
+        USE_TREE@25..52
+          PATH@25..28
+            PATH_SEGMENT@25..28
+              NAME_REF@25..28
+                IDENT@25..28 "foo"
+          COLON2@28..30 "::"
+          USE_TREE_LIST@30..52
+            L_CURLY@30..31 "{"
+            USE_TREE@31..51
+              PATH@31..51
+                PATH@31..46
+                  PATH@31..41
+                    PATH@31..36
+                      PATH_SEGMENT@31..36
+                        NAME_REF@31..36
+                          CRATE_KW@31..36 "crate"
+                    COLON2@36..38 "::"
+                    PATH_SEGMENT@38..41
+                      NAME_REF@38..41
+                        IDENT@38..41 "foo"
+                  COLON2@41..43 "::"
+                  PATH_SEGMENT@43..46
+                    NAME_REF@43..46
+                      IDENT@43..46 "bar"
+                COLON2@46..48 "::"
+                PATH_SEGMENT@48..51
+                  NAME_REF@48..51
+                    IDENT@48..51 "baz"
+            R_CURLY@51..52 "}"
+        R_CURLY@52..53 "}"
+    SEMICOLON@53..54 ";"
+  WHITESPACE@54..55 "\n"
+  USE@55..72
+    USE_KW@55..58 "use"
+    WHITESPACE@58..59 " "
+    USE_TREE@59..71
+      PATH@59..71
+        PATH@59..64
+          PATH_SEGMENT@59..64
+            NAME_REF@59..64
+              IDENT@59..64 "hello"
+        COLON2@64..66 "::"
+        PATH_SEGMENT@66..71
+          NAME_REF@66..71
+            CRATE_KW@66..71 "crate"
+    SEMICOLON@71..72 ";"
+  WHITESPACE@72..73 "\n"
+  USE@73..97
+    USE_KW@73..76 "use"
+    WHITESPACE@76..77 " "
+    USE_TREE@77..96
+      PATH@77..96
+        PATH@77..89
+          PATH@77..82
+            PATH_SEGMENT@77..82
+              NAME_REF@77..82
+                IDENT@77..82 "hello"
+          COLON2@82..84 "::"
+          PATH_SEGMENT@84..89
+            NAME_REF@84..89
+              CRATE_KW@84..89 "crate"
+        COLON2@89..91 "::"
+        PATH_SEGMENT@91..96
+          NAME_REF@91..96
+            IDENT@91..96 "there"
+    SEMICOLON@96..97 ";"
+  WHITESPACE@97..98 "\n"
+error 6..11: The `crate` keyword is only allowed as the first segment of a path
+error 31..36: The `crate` keyword is only allowed as the first segment of a path
+error 66..71: The `crate` keyword is only allowed as the first segment of a path
+error 84..89: The `crate` keyword is only allowed as the first segment of a path
diff --git a/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0040_illegal_crate_kw_location.rs b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0040_illegal_crate_kw_location.rs
new file mode 100644
index 00000000000..508def2c7ef
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0040_illegal_crate_kw_location.rs
@@ -0,0 +1,4 @@
+use ::crate;
+use {crate, foo::{crate::foo::bar::baz}};
+use hello::crate;
+use hello::crate::there;
diff --git a/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0041_illegal_self_keyword_location.rast b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0041_illegal_self_keyword_location.rast
new file mode 100644
index 00000000000..01f60109144
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0041_illegal_self_keyword_location.rast
@@ -0,0 +1,29 @@
+SOURCE_FILE@0..25
+  USE@0..11
+    USE_KW@0..3 "use"
+    WHITESPACE@3..4 " "
+    USE_TREE@4..10
+      PATH@4..10
+        PATH_SEGMENT@4..10
+          COLON2@4..6 "::"
+          NAME_REF@6..10
+            SELF_KW@6..10 "self"
+    SEMICOLON@10..11 ";"
+  WHITESPACE@11..12 "\n"
+  USE@12..24
+    USE_KW@12..15 "use"
+    WHITESPACE@15..16 " "
+    USE_TREE@16..23
+      PATH@16..23
+        PATH@16..17
+          PATH_SEGMENT@16..17
+            NAME_REF@16..17
+              IDENT@16..17 "a"
+        COLON2@17..19 "::"
+        PATH_SEGMENT@19..23
+          NAME_REF@19..23
+            SELF_KW@19..23 "self"
+    SEMICOLON@23..24 ";"
+  WHITESPACE@24..25 "\n"
+error 6..10: The `self` keyword is only allowed as the first segment of a path
+error 19..23: The `self` keyword is only allowed as the first segment of a path
diff --git a/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0041_illegal_self_keyword_location.rs b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0041_illegal_self_keyword_location.rs
new file mode 100644
index 00000000000..b9e1d7d8be2
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0041_illegal_self_keyword_location.rs
@@ -0,0 +1,2 @@
+use ::self;
+use a::self;
diff --git a/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0045_ambiguous_trait_object.rast b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0045_ambiguous_trait_object.rast
new file mode 100644
index 00000000000..d94daacdc1d
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0045_ambiguous_trait_object.rast
@@ -0,0 +1,196 @@
+SOURCE_FILE@0..187
+  TYPE_ALIAS@0..35
+    TYPE_KW@0..4 "type"
+    WHITESPACE@4..5 " "
+    NAME@5..8
+      IDENT@5..8 "Foo"
+    GENERIC_PARAM_LIST@8..12
+      L_ANGLE@8..9 "<"
+      LIFETIME_PARAM@9..11
+        LIFETIME@9..11
+          LIFETIME_IDENT@9..11 "'a"
+      R_ANGLE@11..12 ">"
+    WHITESPACE@12..13 " "
+    EQ@13..14 "="
+    WHITESPACE@14..15 " "
+    REF_TYPE@15..34
+      AMP@15..16 "&"
+      LIFETIME@16..18
+        LIFETIME_IDENT@16..18 "'a"
+      WHITESPACE@18..19 " "
+      DYN_TRAIT_TYPE@19..34
+        DYN_KW@19..22 "dyn"
+        WHITESPACE@22..23 " "
+        TYPE_BOUND_LIST@23..34
+          TYPE_BOUND@23..27
+            PATH_TYPE@23..27
+              PATH@23..27
+                PATH_SEGMENT@23..27
+                  NAME_REF@23..27
+                    IDENT@23..27 "Send"
+          WHITESPACE@27..28 " "
+          PLUS@28..29 "+"
+          WHITESPACE@29..30 " "
+          TYPE_BOUND@30..34
+            PATH_TYPE@30..34
+              PATH@30..34
+                PATH_SEGMENT@30..34
+                  NAME_REF@30..34
+                    IDENT@30..34 "Sync"
+    SEMICOLON@34..35 ";"
+  WHITESPACE@35..36 "\n"
+  TYPE_ALIAS@36..70
+    TYPE_KW@36..40 "type"
+    WHITESPACE@40..41 " "
+    NAME@41..44
+      IDENT@41..44 "Foo"
+    WHITESPACE@44..45 " "
+    EQ@45..46 "="
+    WHITESPACE@46..47 " "
+    PTR_TYPE@47..69
+      STAR@47..48 "*"
+      CONST_KW@48..53 "const"
+      WHITESPACE@53..54 " "
+      DYN_TRAIT_TYPE@54..69
+        DYN_KW@54..57 "dyn"
+        WHITESPACE@57..58 " "
+        TYPE_BOUND_LIST@58..69
+          TYPE_BOUND@58..62
+            PATH_TYPE@58..62
+              PATH@58..62
+                PATH_SEGMENT@58..62
+                  NAME_REF@58..62
+                    IDENT@58..62 "Send"
+          WHITESPACE@62..63 " "
+          PLUS@63..64 "+"
+          WHITESPACE@64..65 " "
+          TYPE_BOUND@65..69
+            PATH_TYPE@65..69
+              PATH@65..69
+                PATH_SEGMENT@65..69
+                  NAME_REF@65..69
+                    IDENT@65..69 "Sync"
+    SEMICOLON@69..70 ";"
+  WHITESPACE@70..71 "\n"
+  TYPE_ALIAS@71..109
+    TYPE_KW@71..75 "type"
+    WHITESPACE@75..76 " "
+    NAME@76..79
+      IDENT@76..79 "Foo"
+    WHITESPACE@79..80 " "
+    EQ@80..81 "="
+    WHITESPACE@81..82 " "
+    FN_PTR_TYPE@82..108
+      FN_KW@82..84 "fn"
+      PARAM_LIST@84..86
+        L_PAREN@84..85 "("
+        R_PAREN@85..86 ")"
+      WHITESPACE@86..87 " "
+      RET_TYPE@87..108
+        THIN_ARROW@87..89 "->"
+        WHITESPACE@89..90 " "
+        DYN_TRAIT_TYPE@90..108
+          DYN_KW@90..93 "dyn"
+          WHITESPACE@93..94 " "
+          TYPE_BOUND_LIST@94..108
+            TYPE_BOUND@94..98
+              PATH_TYPE@94..98
+                PATH@94..98
+                  PATH_SEGMENT@94..98
+                    NAME_REF@94..98
+                      IDENT@94..98 "Send"
+            WHITESPACE@98..99 " "
+            PLUS@99..100 "+"
+            WHITESPACE@100..101 " "
+            TYPE_BOUND@101..108
+              LIFETIME@101..108
+                LIFETIME_IDENT@101..108 "'static"
+    SEMICOLON@108..109 ";"
+  WHITESPACE@109..110 "\n"
+  FN@110..186
+    FN_KW@110..112 "fn"
+    WHITESPACE@112..113 " "
+    NAME@113..117
+      IDENT@113..117 "main"
+    PARAM_LIST@117..119
+      L_PAREN@117..118 "("
+      R_PAREN@118..119 ")"
+    WHITESPACE@119..120 " "
+    BLOCK_EXPR@120..186
+      STMT_LIST@120..186
+        L_CURLY@120..121 "{"
+        WHITESPACE@121..126 "\n    "
+        LET_STMT@126..184
+          LET_KW@126..129 "let"
+          WHITESPACE@129..130 " "
+          IDENT_PAT@130..131
+            NAME@130..131
+              IDENT@130..131 "b"
+          WHITESPACE@131..132 " "
+          EQ@132..133 "="
+          WHITESPACE@133..134 " "
+          CAST_EXPR@134..183
+            PAREN_EXPR@134..138
+              L_PAREN@134..135 "("
+              REF_EXPR@135..137
+                AMP@135..136 "&"
+                PATH_EXPR@136..137
+                  PATH@136..137
+                    PATH_SEGMENT@136..137
+                      NAME_REF@136..137
+                        IDENT@136..137 "a"
+              R_PAREN@137..138 ")"
+            WHITESPACE@138..139 " "
+            AS_KW@139..141 "as"
+            WHITESPACE@141..142 " "
+            REF_TYPE@142..183
+              AMP@142..143 "&"
+              DYN_TRAIT_TYPE@143..183
+                DYN_KW@143..146 "dyn"
+                WHITESPACE@146..147 " "
+                TYPE_BOUND_LIST@147..183
+                  TYPE_BOUND@147..175
+                    PATH_TYPE@147..175
+                      PATH@147..175
+                        PATH_SEGMENT@147..175
+                          NAME_REF@147..150
+                            IDENT@147..150 "Add"
+                          GENERIC_ARG_LIST@150..175
+                            L_ANGLE@150..151 "<"
+                            TYPE_ARG@151..156
+                              PATH_TYPE@151..156
+                                PATH@151..156
+                                  PATH_SEGMENT@151..156
+                                    NAME_REF@151..156
+                                      IDENT@151..156 "Other"
+                            COMMA@156..157 ","
+                            WHITESPACE@157..158 " "
+                            ASSOC_TYPE_ARG@158..174
+                              NAME_REF@158..164
+                                IDENT@158..164 "Output"
+                              WHITESPACE@164..165 " "
+                              EQ@165..166 "="
+                              WHITESPACE@166..167 " "
+                              PATH_TYPE@167..174
+                                PATH@167..174
+                                  PATH_SEGMENT@167..174
+                                    NAME_REF@167..174
+                                      IDENT@167..174 "Addable"
+                            R_ANGLE@174..175 ">"
+                  WHITESPACE@175..176 " "
+                  PLUS@176..177 "+"
+                  WHITESPACE@177..178 " "
+                  TYPE_BOUND@178..183
+                    PATH_TYPE@178..183
+                      PATH@178..183
+                        PATH_SEGMENT@178..183
+                          NAME_REF@178..183
+                            IDENT@178..183 "Other"
+          SEMICOLON@183..184 ";"
+        WHITESPACE@184..185 "\n"
+        R_CURLY@185..186 "}"
+  WHITESPACE@186..187 "\n"
+error 19..34: ambiguous `+` in a type
+error 54..69: ambiguous `+` in a type
+error 90..108: ambiguous `+` in a type
+error 143..183: ambiguous `+` in a type
diff --git a/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0045_ambiguous_trait_object.rs b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0045_ambiguous_trait_object.rs
new file mode 100644
index 00000000000..0a5958f25f7
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0045_ambiguous_trait_object.rs
@@ -0,0 +1,6 @@
+type Foo<'a> = &'a dyn Send + Sync;
+type Foo = *const dyn Send + Sync;
+type Foo = fn() -> dyn Send + 'static;
+fn main() {
+    let b = (&a) as &dyn Add<Other, Output = Addable> + Other;
+}
diff --git a/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0046_mutable_const_item.rast b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0046_mutable_const_item.rast
new file mode 100644
index 00000000000..c7eb312c92c
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0046_mutable_const_item.rast
@@ -0,0 +1,22 @@
+SOURCE_FILE@0..24
+  CONST@0..23
+    CONST_KW@0..5 "const"
+    WHITESPACE@5..6 " "
+    MUT_KW@6..9 "mut"
+    WHITESPACE@9..10 " "
+    NAME@10..13
+      IDENT@10..13 "FOO"
+    COLON@13..14 ":"
+    WHITESPACE@14..15 " "
+    TUPLE_TYPE@15..17
+      L_PAREN@15..16 "("
+      R_PAREN@16..17 ")"
+    WHITESPACE@17..18 " "
+    EQ@18..19 "="
+    WHITESPACE@19..20 " "
+    TUPLE_EXPR@20..22
+      L_PAREN@20..21 "("
+      R_PAREN@21..22 ")"
+    SEMICOLON@22..23 ";"
+  WHITESPACE@23..24 "\n"
+error 6..9: const globals cannot be mutable
diff --git a/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0046_mutable_const_item.rs b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0046_mutable_const_item.rs
new file mode 100644
index 00000000000..ccab6bccfaa
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/0046_mutable_const_item.rs
@@ -0,0 +1 @@
+const mut FOO: () = ();
diff --git a/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/invalid_let_expr.rast b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/invalid_let_expr.rast
new file mode 100644
index 00000000000..9e1e4886401
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/invalid_let_expr.rast
@@ -0,0 +1,216 @@
+SOURCE_FILE@0..282
+  FN@0..281
+    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..281
+      STMT_LIST@9..281
+        L_CURLY@9..10 "{"
+        WHITESPACE@10..15 "\n    "
+        CONST@15..42
+          CONST_KW@15..20 "const"
+          WHITESPACE@20..21 " "
+          UNDERSCORE@21..22 "_"
+          COLON@22..23 ":"
+          WHITESPACE@23..24 " "
+          TUPLE_TYPE@24..26
+            L_PAREN@24..25 "("
+            R_PAREN@25..26 ")"
+          WHITESPACE@26..27 " "
+          EQ@27..28 "="
+          WHITESPACE@28..29 " "
+          LET_EXPR@29..41
+            LET_KW@29..32 "let"
+            WHITESPACE@32..33 " "
+            WILDCARD_PAT@33..34
+              UNDERSCORE@33..34 "_"
+            WHITESPACE@34..35 " "
+            EQ@35..36 "="
+            WHITESPACE@36..37 " "
+            PATH_EXPR@37..41
+              PATH@37..41
+                PATH_SEGMENT@37..41
+                  NAME_REF@37..41
+                    IDENT@37..41 "None"
+          SEMICOLON@41..42 ";"
+        WHITESPACE@42..48 "\n\n    "
+        LET_STMT@48..83
+          LET_KW@48..51 "let"
+          WHITESPACE@51..52 " "
+          WILDCARD_PAT@52..53
+            UNDERSCORE@52..53 "_"
+          WHITESPACE@53..54 " "
+          EQ@54..55 "="
+          WHITESPACE@55..56 " "
+          IF_EXPR@56..82
+            IF_KW@56..58 "if"
+            WHITESPACE@58..59 " "
+            LITERAL@59..63
+              TRUE_KW@59..63 "true"
+            WHITESPACE@63..64 " "
+            BLOCK_EXPR@64..82
+              STMT_LIST@64..82
+                L_CURLY@64..65 "{"
+                WHITESPACE@65..66 " "
+                PAREN_EXPR@66..80
+                  L_PAREN@66..67 "("
+                  LET_EXPR@67..79
+                    LET_KW@67..70 "let"
+                    WHITESPACE@70..71 " "
+                    WILDCARD_PAT@71..72
+                      UNDERSCORE@71..72 "_"
+                    WHITESPACE@72..73 " "
+                    EQ@73..74 "="
+                    WHITESPACE@74..75 " "
+                    PATH_EXPR@75..79
+                      PATH@75..79
+                        PATH_SEGMENT@75..79
+                          NAME_REF@75..79
+                            IDENT@75..79 "None"
+                  R_PAREN@79..80 ")"
+                WHITESPACE@80..81 " "
+                R_CURLY@81..82 "}"
+          SEMICOLON@82..83 ";"
+        WHITESPACE@83..89 "\n\n    "
+        IF_EXPR@89..279
+          IF_KW@89..91 "if"
+          WHITESPACE@91..92 " "
+          BIN_EXPR@92..114
+            LITERAL@92..96
+              TRUE_KW@92..96 "true"
+            WHITESPACE@96..97 " "
+            AMP2@97..99 "&&"
+            WHITESPACE@99..100 " "
+            PAREN_EXPR@100..114
+              L_PAREN@100..101 "("
+              LET_EXPR@101..113
+                LET_KW@101..104 "let"
+                WHITESPACE@104..105 " "
+                WILDCARD_PAT@105..106
+                  UNDERSCORE@105..106 "_"
+                WHITESPACE@106..107 " "
+                EQ@107..108 "="
+                WHITESPACE@108..109 " "
+                PATH_EXPR@109..113
+                  PATH@109..113
+                    PATH_SEGMENT@109..113
+                      NAME_REF@109..113
+                        IDENT@109..113 "None"
+              R_PAREN@113..114 ")"
+          WHITESPACE@114..115 " "
+          BLOCK_EXPR@115..279
+            STMT_LIST@115..279
+              L_CURLY@115..116 "{"
+              WHITESPACE@116..125 "\n        "
+              EXPR_STMT@125..140
+                PAREN_EXPR@125..139
+                  L_PAREN@125..126 "("
+                  LET_EXPR@126..138
+                    LET_KW@126..129 "let"
+                    WHITESPACE@129..130 " "
+                    WILDCARD_PAT@130..131
+                      UNDERSCORE@130..131 "_"
+                    WHITESPACE@131..132 " "
+                    EQ@132..133 "="
+                    WHITESPACE@133..134 " "
+                    PATH_EXPR@134..138
+                      PATH@134..138
+                        PATH_SEGMENT@134..138
+                          NAME_REF@134..138
+                            IDENT@134..138 "None"
+                  R_PAREN@138..139 ")"
+                SEMICOLON@139..140 ";"
+              WHITESPACE@140..149 "\n        "
+              WHILE_EXPR@149..273
+                WHILE_KW@149..154 "while"
+                WHITESPACE@154..155 " "
+                LET_EXPR@155..167
+                  LET_KW@155..158 "let"
+                  WHITESPACE@158..159 " "
+                  WILDCARD_PAT@159..160
+                    UNDERSCORE@159..160 "_"
+                  WHITESPACE@160..161 " "
+                  EQ@161..162 "="
+                  WHITESPACE@162..163 " "
+                  PATH_EXPR@163..167
+                    PATH@163..167
+                      PATH_SEGMENT@163..167
+                        NAME_REF@163..167
+                          IDENT@163..167 "None"
+                WHITESPACE@167..168 " "
+                BLOCK_EXPR@168..273
+                  STMT_LIST@168..273
+                    L_CURLY@168..169 "{"
+                    WHITESPACE@169..182 "\n            "
+                    MATCH_EXPR@182..263
+                      MATCH_KW@182..187 "match"
+                      WHITESPACE@187..188 " "
+                      PATH_EXPR@188..192
+                        PATH@188..192
+                          PATH_SEGMENT@188..192
+                            NAME_REF@188..192
+                              IDENT@188..192 "None"
+                      WHITESPACE@192..193 " "
+                      MATCH_ARM_LIST@193..263
+                        L_CURLY@193..194 "{"
+                        WHITESPACE@194..211 "\n                "
+                        MATCH_ARM@211..249
+                          WILDCARD_PAT@211..212
+                            UNDERSCORE@211..212 "_"
+                          WHITESPACE@212..213 " "
+                          MATCH_GUARD@213..228
+                            IF_KW@213..215 "if"
+                            WHITESPACE@215..216 " "
+                            LET_EXPR@216..228
+                              LET_KW@216..219 "let"
+                              WHITESPACE@219..220 " "
+                              WILDCARD_PAT@220..221
+                                UNDERSCORE@220..221 "_"
+                              WHITESPACE@221..222 " "
+                              EQ@222..223 "="
+                              WHITESPACE@223..224 " "
+                              PATH_EXPR@224..228
+                                PATH@224..228
+                                  PATH_SEGMENT@224..228
+                                    NAME_REF@224..228
+                                      IDENT@224..228 "None"
+                          WHITESPACE@228..229 " "
+                          FAT_ARROW@229..231 "=>"
+                          WHITESPACE@231..232 " "
+                          BLOCK_EXPR@232..249
+                            STMT_LIST@232..249
+                              L_CURLY@232..233 "{"
+                              WHITESPACE@233..234 " "
+                              LET_STMT@234..247
+                                LET_KW@234..237 "let"
+                                WHITESPACE@237..238 " "
+                                WILDCARD_PAT@238..239
+                                  UNDERSCORE@238..239 "_"
+                                WHITESPACE@239..240 " "
+                                EQ@240..241 "="
+                                WHITESPACE@241..242 " "
+                                PATH_EXPR@242..246
+                                  PATH@242..246
+                                    PATH_SEGMENT@242..246
+                                      NAME_REF@242..246
+                                        IDENT@242..246 "None"
+                                SEMICOLON@246..247 ";"
+                              WHITESPACE@247..248 " "
+                              R_CURLY@248..249 "}"
+                        WHITESPACE@249..262 "\n            "
+                        R_CURLY@262..263 "}"
+                    WHITESPACE@263..272 "\n        "
+                    R_CURLY@272..273 "}"
+              WHITESPACE@273..278 "\n    "
+              R_CURLY@278..279 "}"
+        WHITESPACE@279..280 "\n"
+        R_CURLY@280..281 "}"
+  WHITESPACE@281..282 "\n"
+error 29..41: `let` expressions are not supported here
+error 67..79: `let` expressions are not supported here
+error 126..138: `let` expressions are not supported here
diff --git a/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/invalid_let_expr.rs b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/invalid_let_expr.rs
new file mode 100644
index 00000000000..1515ae5334d
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/syntax/test_data/parser/validation/invalid_let_expr.rs
@@ -0,0 +1,14 @@
+fn foo() {
+    const _: () = let _ = None;
+
+    let _ = if true { (let _ = None) };
+
+    if true && (let _ = None) {
+        (let _ = None);
+        while let _ = None {
+            match None {
+                _ if let _ = None => { let _ = None; }
+            }
+        }
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/syntax/test_data/reparse/fuzz-failures/0000.rs b/src/tools/rust-analyzer/crates/syntax/test_data/reparse/fuzz-failures/0000.rs
new file mode 100644
index 00000000000..388eb74eda1
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/syntax/test_data/reparse/fuzz-failures/0000.rs
@@ -0,0 +1,6 @@
+0
+1
+
+
+
+0
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/syntax/test_data/reparse/fuzz-failures/0001.rs b/src/tools/rust-analyzer/crates/syntax/test_data/reparse/fuzz-failures/0001.rs
new file mode 100644
index 00000000000..d2d42c6f941
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/syntax/test_data/reparse/fuzz-failures/0001.rs
@@ -0,0 +1,4 @@
+0
+1
+
+bb"
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/syntax/test_data/reparse/fuzz-failures/0002.rs b/src/tools/rust-analyzer/crates/syntax/test_data/reparse/fuzz-failures/0002.rs
new file mode 100644
index 00000000000..3fbee154810
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/syntax/test_data/reparse/fuzz-failures/0002.rs
@@ -0,0 +1,4 @@
+1
+1
+
+""!
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/syntax/test_data/reparse/fuzz-failures/0003.rs b/src/tools/rust-analyzer/crates/syntax/test_data/reparse/fuzz-failures/0003.rs
new file mode 100644
index 00000000000..d2757cd08df
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/syntax/test_data/reparse/fuzz-failures/0003.rs
Binary files differdiff --git a/src/tools/rust-analyzer/crates/syntax/test_data/reparse/fuzz-failures/0004.rs b/src/tools/rust-analyzer/crates/syntax/test_data/reparse/fuzz-failures/0004.rs
new file mode 100644
index 00000000000..481617a701d
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/syntax/test_data/reparse/fuzz-failures/0004.rs
@@ -0,0 +1,4 @@
+0
+0
+}
+{;
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/syntax/test_data/reparse/fuzz-failures/0005.rs b/src/tools/rust-analyzer/crates/syntax/test_data/reparse/fuzz-failures/0005.rs
new file mode 100644
index 00000000000..074d761c7b5
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/syntax/test_data/reparse/fuzz-failures/0005.rs
@@ -0,0 +1,7 @@
+05
+1
+
+
+
+b'
+		
\ No newline at end of file