summaryrefslogtreecommitdiffstats
path: root/src/tools/rust-analyzer/crates/parser
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/rust-analyzer/crates/parser')
-rw-r--r--src/tools/rust-analyzer/crates/parser/Cargo.toml19
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/event.rs133
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar.rs342
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/attributes.rs53
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs625
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs643
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs131
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs242
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/items.rs465
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/items/adt.rs168
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/items/consts.rs37
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/items/traits.rs140
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/items/use_item.rs93
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/params.rs209
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs132
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs440
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/types.rs352
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/input.rs88
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/lexed_str.rs300
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/lib.rs181
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/output.rs77
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/parser.rs340
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/shortcuts.rs215
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/syntax_kind.rs29
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs390
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/tests.rs166
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/tests/prefix_entries.rs107
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/tests/sourcegen_inline_tests.rs123
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/tests/top_entries.rs312
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/token_set.rs42
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/empty_exponent.rast48
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/empty_exponent.rs22
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/empty_exponent.txt48
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/empty_int.rast26
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/empty_int.rs17
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/empty_int.txt26
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/lifetime_starts_with_a_number.rast4
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/lifetime_starts_with_a_number.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/lifetime_starts_with_a_number.txt4
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_block_comment_at_eof.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_block_comment_at_eof.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_block_comment_at_eof.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_block_comment_with_content.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_block_comment_with_content.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_block_comment_with_content.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_at_eof.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_at_eof.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_at_eof.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_at_eof.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_at_eof.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_at_eof.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_ascii_escape.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_ascii_escape.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_ascii_escape.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_ferris.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_ferris.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_ferris.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash_double_quote.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash_double_quote.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash_double_quote.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash_n.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash_n.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash_n.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_space.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_space.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_space.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_unicode_escape.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_unicode_escape.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_unicode_escape.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_ascii_escape.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_ascii_escape.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_ascii_escape.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_ferris.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_ferris.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_ferris.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash_n.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash_n.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash_n.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash_single_quote.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash_single_quote.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash_single_quote.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_space.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_space.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_space.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_unicode_escape.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_unicode_escape.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_unicode_escape.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_at_eof.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_at_eof.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_at_eof.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_ascii_escape.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_ascii_escape.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_ascii_escape.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_ferris.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_ferris.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_ferris.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash_n.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash_n.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash_n.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash_single_quote.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash_single_quote.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash_single_quote.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_space.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_space.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_space.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_unicode_escape.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_unicode_escape.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_unicode_escape.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_nested_block_comment_entirely.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_nested_block_comment_entirely.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_nested_block_comment_entirely.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_nested_block_comment_partially.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_nested_block_comment_partially.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_nested_block_comment_partially.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_at_eof.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_at_eof.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_at_eof.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ascii_escape.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ascii_escape.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ascii_escape.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ferris.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ferris.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ferris.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash_n.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash_n.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash_n.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_space.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_space.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_space.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_unicode_escape.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_unicode_escape.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_unicode_escape.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_at_eof.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_at_eof.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_at_eof.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ascii_escape.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ascii_escape.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ascii_escape.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ferris.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ferris.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ferris.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash_n.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash_n.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash_n.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_space.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_space.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_space.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_unicode_escape.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_unicode_escape.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_unicode_escape.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_at_eof.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_at_eof.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_at_eof.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_ascii_escape.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_ascii_escape.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_ascii_escape.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_ferris.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_ferris.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_ferris.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash_double_quote.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash_double_quote.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash_double_quote.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash_n.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash_n.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash_n.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_space.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_space.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_space.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_unicode_escape.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_unicode_escape.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_unicode_escape.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_at_eof.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_at_eof.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_at_eof.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_with_ascii.rast9
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_with_ascii.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_with_ascii.txt9
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_string_at_eof.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_string_at_eof.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_string_at_eof.txt1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_string_with_ascii.rast9
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_string_with_ascii.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_string_with_ascii.txt9
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/block_comment.rast6
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/block_comment.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/block_comment.txt6
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/byte_strings.rast22
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/byte_strings.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/byte_strings.txt22
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/chars.rast16
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/chars.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/chars.txt16
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/hello.rast3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/hello.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/hello.txt3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/ident.rast14
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/ident.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/ident.txt14
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/keywords.rast64
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/keywords.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/keywords.txt64
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/lifetimes.rast8
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/lifetimes.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/lifetimes.txt8
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/numbers.rast57
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/numbers.rs9
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/numbers.txt57
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/raw_ident.rast2
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/raw_ident.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/raw_ident.txt2
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/raw_strings.rast2
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/raw_strings.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/raw_strings.txt2
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/single_line_comments.rast22
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/single_line_comments.rs12
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/single_line_comments.txt22
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/strings.rast8
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/strings.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/strings.txt8
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/symbols.rast77
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/symbols.rs6
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/symbols.txt77
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/whitespace.rast12
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/whitespace.rs4
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/whitespace.txt12
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0000_struct_field_missing_comma.rast34
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0000_struct_field_missing_comma.rs4
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0001_item_recovery_in_file.rast18
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0001_item_recovery_in_file.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0002_duplicate_shebang.rast45
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0002_duplicate_shebang.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0003_C++_semicolon.rast39
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0003_C++_semicolon.rs4
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0004_use_path_bad_segment.rast15
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0004_use_path_bad_segment.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0005_attribute_recover.rast62
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0005_attribute_recover.rs8
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0006_named_field_recovery.rast74
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0006_named_field_recovery.rs7
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0007_stray_curly_in_file.rast33
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0007_stray_curly_in_file.rs9
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0008_item_block_recovery.rast80
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0008_item_block_recovery.rs13
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0009_broken_struct_type_parameter.rast56
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0009_broken_struct_type_parameter.rs5
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0010_unsafe_lambda_block.rast45
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0010_unsafe_lambda_block.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0011_extern_struct.rast13
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0011_extern_struct.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0012_broken_lambda.rast387
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0013_invalid_type.rast89
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0013_invalid_type.rs7
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0014_where_no_bounds.rast32
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0014_where_no_bounds.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0015_curly_in_params.rast24
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0015_curly_in_params.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0016_missing_semi.rast44
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0016_missing_semi.rs6
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0017_incomplete_binexpr.rast47
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0017_incomplete_binexpr.rs4
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0018_incomplete_fn.rast134
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0018_incomplete_fn.rs8
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0019_let_recover.rast107
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0019_let_recover.rs12
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0020_fn_recover.rast21
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0020_fn_recover.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0021_incomplete_param.rast34
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0021_incomplete_param.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0022_bad_exprs.rast171
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0022_bad_exprs.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0023_mismatched_paren.rast45
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0023_mismatched_paren.rs5
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0024_many_type_parens.rast327
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0024_many_type_parens.rs7
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0025_nope.rast209
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0025_nope.rs32
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0026_imp_recovery.rast49
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0026_imp_recovery.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0027_incomplere_where_for.rast29
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0027_incomplere_where_for.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0029_field_completion.rast36
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0029_field_completion.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0032_match_arms_inner_attrs.rast205
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0032_match_arms_inner_attrs.rs20
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0033_match_arms_outer_attrs.rast68
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0033_match_arms_outer_attrs.rs7
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0034_bad_box_pattern.rast96
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0034_bad_box_pattern.rs6
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0035_use_recover.rast55
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0035_use_recover.rs5
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0036_partial_use.rast51
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0036_partial_use.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0039_lambda_recovery.rast83
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0039_lambda_recovery.rs5
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0042_weird_blocks.rast75
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0042_weird_blocks.rs6
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0043_unexpected_for_type.rast256
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0043_unexpected_for_type.rs9
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0044_item_modifiers.rast48
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0044_item_modifiers.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0047_repated_extern_modifier.rast15
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0047_repated_extern_modifier.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0048_double_fish.rast123
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0048_double_fish.rs7
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0001_array_type_missing_semi.rast27
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0001_array_type_missing_semi.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0002_misplaced_label_err.rast28
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0002_misplaced_label_err.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0003_pointer_type_no_mutability.rast17
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0003_pointer_type_no_mutability.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0004_impl_type.rast79
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0004_impl_type.rs4
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0005_fn_pointer_type_missing_fn.rast23
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0005_fn_pointer_type_missing_fn.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0006_unsafe_block_in_mod.rast37
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0006_unsafe_block_in_mod.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0007_async_without_semicolon.rast32
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0007_async_without_semicolon.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0008_pub_expr.rast26
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0008_pub_expr.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0013_anonymous_static.rast21
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0013_anonymous_static.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0014_record_literal_before_ellipsis_recovery.rast49
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0014_record_literal_before_ellipsis_recovery.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0014_struct_field_recover.rast31
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0014_struct_field_recover.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0015_empty_segment.rast14
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0015_empty_segment.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0015_missing_fn_param_type.rast53
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0015_missing_fn_param_type.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0002_use_tree_list.rast29
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0002_use_tree_list.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0003_where_pred_for.rast63
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0003_where_pred_for.rs4
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0004_value_parameters_no_patterns.rast60
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0004_value_parameters_no_patterns.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0005_function_type_params.rast38
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0005_function_type_params.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0006_self_param.rast128
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0006_self_param.rs7
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0007_type_param_bounds.rast53
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0007_type_param_bounds.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0008_path_part.rast98
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0008_path_part.rs6
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0009_loop_expr.rast26
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0009_loop_expr.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0010_extern_block.rast21
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0010_extern_block.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0011_field_expr.rast60
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0011_field_expr.rs5
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0012_type_item_where_clause.rast33
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0012_type_item_where_clause.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0013_pointer_type_mut.rast35
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0013_pointer_type_mut.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0014_never_type.rast13
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0014_never_type.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0015_continue_expr.rast38
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0015_continue_expr.rs6
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0017_array_type.rast21
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0017_array_type.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0018_arb_self_types.rast76
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0018_arb_self_types.rs4
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0019_unary_expr.rast45
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0019_unary_expr.rs5
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0021_assoc_item_list.rast81
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0021_assoc_item_list.rs6
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0022_crate_visibility.rast49
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0022_crate_visibility.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0023_placeholder_type.rast13
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0023_placeholder_type.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0024_slice_pat.rast42
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0024_slice_pat.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0025_slice_type.rast17
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0025_slice_type.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0026_tuple_pat_fields.rast105
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0026_tuple_pat_fields.rs6
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0027_ref_pat.rast50
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0027_ref_pat.rs4
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0028_impl_trait_type.rast45
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0028_impl_trait_type.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0029_cast_expr.rast90
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0029_cast_expr.rs6
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0030_let_expr.rast90
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0030_let_expr.rs4
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0031_while_expr.rast87
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0031_while_expr.rs5
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0032_fn_pointer_type.rast98
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0032_fn_pointer_type.rs4
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0033_reference_type;.rast51
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0033_reference_type;.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0034_break_expr.rast57
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0034_break_expr.rs8
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0037_qual_paths.rast79
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0037_qual_paths.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0038_full_range_expr.rast29
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0038_full_range_expr.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0040_crate_keyword_vis.rast63
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0040_crate_keyword_vis.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0041_trait_item.rast31
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0041_trait_item.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0042_call_expr.rast148
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0042_call_expr.rs6
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0044_block_items.rast30
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0044_block_items.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0045_param_list_opt_patterns.rast48
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0045_param_list_opt_patterns.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0046_singleton_tuple_type.rast20
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0046_singleton_tuple_type.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0048_path_type_with_bounds.rast85
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0048_path_type_with_bounds.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0050_fn_decl.rast22
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0050_fn_decl.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0051_unit_type.rast14
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0051_unit_type.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0052_path_type.rast72
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0052_path_type.rs4
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0053_path_expr.rast97
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0053_path_expr.rs6
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0054_record_field_attrs.rast33
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0054_record_field_attrs.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0055_literal_pattern.rast77
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0055_literal_pattern.rs8
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0056_where_clause.rast117
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0056_where_clause.rs7
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0058_range_pat.rast251
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0058_range_pat.rs18
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0059_match_arms_commas.rast60
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0059_match_arms_commas.rs7
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0060_extern_crate.rast10
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0060_extern_crate.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0061_record_lit.rast125
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0061_record_lit.rs6
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0062_mod_contents.rast65
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0062_mod_contents.rs5
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0063_impl_item_neg.rast23
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0063_impl_item_neg.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0064_if_expr.rast126
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0064_if_expr.rs7
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0065_dyn_trait_type.rast45
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0065_dyn_trait_type.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0066_match_arm.rast152
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0066_match_arm.rs9
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0067_crate_path.rast16
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0067_crate_path.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0070_stmt_bin_expr_ambiguity.rast53
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0070_stmt_bin_expr_ambiguity.rs4
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0071_match_expr.rast96
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0071_match_expr.rs6
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0072_return_expr.rast29
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0072_return_expr.rs4
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0073_type_item_type_params.rast20
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0073_type_item_type_params.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0074_stmt_postfix_expr_ambiguity.rast63
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0074_stmt_postfix_expr_ambiguity.rs7
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0075_block.rast90
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0075_block.rs4
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0076_function_where_clause.rast40
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0076_function_where_clause.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0077_try_expr.rast26
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0077_try_expr.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0078_type_alias.rast16
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0078_type_alias.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0079_impl_item.rast14
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0079_impl_item.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0080_postfix_range.rast96
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0080_postfix_range.rs5
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0081_for_type.rast117
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0081_for_type.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0082_ref_expr.rast139
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0082_ref_expr.rs10
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0083_struct_items.rast87
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0084_paren_type.rast19
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0084_paren_type.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0085_expr_literals.rast136
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0085_expr_literals.rs12
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0086_function_ret_type.rast36
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0086_function_ret_type.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0088_break_ambiguity.rast67
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0088_break_ambiguity.rs6
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0090_type_param_default.rast22
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0090_type_param_default.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0092_fn_pointer_type_with_ret.rast23
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0092_fn_pointer_type_with_ret.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0093_index_expr.rast34
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0093_index_expr.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0095_placeholder_pat.rast29
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0095_placeholder_pat.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0096_no_semi_after_block.rast125
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0096_no_semi_after_block.rs13
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0099_param_list.rast103
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0099_param_list.rs4
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0100_for_expr.rast36
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0100_for_expr.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0102_record_pat_field_list.rast175
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0102_record_pat_field_list.rs7
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0103_array_expr.rast55
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0103_array_expr.rs6
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0104_path_fn_trait_args.rast41
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0104_path_fn_trait_args.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0106_lambda_expr.rast246
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0106_lambda_expr.rs15
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0107_method_call_expr.rast63
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0107_method_call_expr.rs4
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0108_tuple_expr.rast39
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0108_tuple_expr.rs5
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0109_label.rast70
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0109_label.rs5
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0111_tuple_pat.rast90
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0111_tuple_pat.rs6
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0112_bind_pat.rast128
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0112_bind_pat.rs8
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0113_nocontentexpr.rast57
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0113_nocontentexpr.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0114_tuple_struct_where.rast42
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0114_tuple_struct_where.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0115_tuple_field_attrs.rast28
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0115_tuple_field_attrs.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0117_macro_call_type.rast46
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0117_macro_call_type.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0118_match_guard.rast77
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0118_match_guard.rs6
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0120_match_arms_inner_attribute.rast84
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0120_match_arms_inner_attribute.rs8
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0121_match_arms_outer_attributes.rast151
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0121_match_arms_outer_attributes.rs12
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0123_param_list_vararg.rast62
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0123_param_list_vararg.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0125_crate_keyword_path.rast33
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0125_crate_keyword_path.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0125_record_literal_field_with_attr.rast49
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0125_record_literal_field_with_attr.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0126_attr_on_expr_stmt.rast105
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0126_attr_on_expr_stmt.rs6
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0129_marco_pat.rast37
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0129_marco_pat.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0130_let_stmt.rast36
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0130_let_stmt.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0130_try_block_expr.rast32
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0130_try_block_expr.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0131_existential_type.rast31
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0131_existential_type.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0132_box_expr.rast90
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0132_box_expr.rs5
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0134_nocontentexpr_after_item.rast64
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0134_nocontentexpr_after_item.rs8
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0137_await_expr.rast70
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0137_await_expr.rs5
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0138_associated_type_bounds.rast111
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0138_associated_type_bounds.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0138_expression_after_block.rast66
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0138_expression_after_block.rs4
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0138_self_param_outer_attr.rast28
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0138_self_param_outer_attr.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0139_param_outer_arg.rast36
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0139_param_outer_arg.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0142_for_range_from.rast42
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0142_for_range_from.rs5
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0143_box_pat.rast111
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0143_box_pat.rs5
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0144_dot_dot_pat.rast456
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0144_dot_dot_pat.rs25
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0145_record_pat_field.rast123
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0145_record_pat_field.rs5
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0146_as_precedence.rast43
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0146_as_precedence.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0147_const_param.rast23
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0147_const_param.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0147_macro_def.rast19
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0147_macro_def.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0150_array_attrs.rast48
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0150_array_attrs.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0150_impl_type_params.rast38
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0150_impl_type_params.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0151_fn.rast15
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0151_fn.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0151_trait_alias.rast33
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0151_trait_alias.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0152_arg_with_attr.rast38
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0152_arg_with_attr.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0153_pub_parens_typepath.rast56
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0153_pub_parens_typepath.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0154_fn_pointer_param_ident_path.rast58
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0154_fn_pointer_param_ident_path.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rast43
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0154_tuple_attrs.rast51
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0154_tuple_attrs.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0155_closure_params.rast70
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0155_closure_params.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0156_const_block_pat.rast79
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0156_const_block_pat.rs4
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0156_fn_def_param.rast48
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0156_fn_def_param.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0156_or_pattern.rast112
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0156_or_pattern.rs8
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0157_fn_pointer_unnamed_arg.rast26
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0157_fn_pointer_unnamed_arg.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0157_variant_discriminant.rast30
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0157_variant_discriminant.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0158_binop_resets_statementness.rast38
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0158_binop_resets_statementness.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0158_lambda_ret_block.rast45
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0158_lambda_ret_block.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0158_macro_rules_non_brace.rast57
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0158_macro_rules_non_brace.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0159_try_macro_fallback.rast36
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0159_try_macro_fallback.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0159_yield_expr.rast29
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0159_yield_expr.rs4
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0160_crate_visibility_in.rast42
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0160_crate_visibility_in.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0160_try_macro_rules.rast24
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0160_try_macro_rules.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0161_impl_item_const.rast24
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0161_impl_item_const.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0161_labeled_block.rast28
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0161_labeled_block.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0162_default_async_unsafe_fn.rast43
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0162_default_async_unsafe_fn.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0163_default_async_fn.rast41
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0163_default_async_fn.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0163_default_unsafe_item.rast45
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0163_default_unsafe_item.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0164_default_item.rast24
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0164_default_item.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0164_type_path_in_pattern.rast39
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0164_type_path_in_pattern.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0166_half_open_range_pat.rast32
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0166_half_open_range_pat.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0168_extern_crate_rename.rast16
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0168_extern_crate_rename.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0168_extern_crate_self.rast10
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0168_extern_crate_self.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0169_mod_item.rast8
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0169_mod_item.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0170_mod_item_curly.rast12
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0170_mod_item_curly.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0170_tuple_struct.rast25
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0170_tuple_struct.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0171_struct_item.rast11
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0171_struct_item.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0172_const_item.rast20
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0172_const_item.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0172_record_field_list.rast35
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0172_record_field_list.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0173_anonymous_const.rast19
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0173_anonymous_const.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0173_macro_def_curly.rast27
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0173_macro_def_curly.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0173_union_item.rast35
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0173_union_item.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0174_trait_item_generic_params.rast35
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0174_trait_item_generic_params.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0174_unit_struct.rast8
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0174_unit_struct.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0174_use_tree_star.rast24
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0174_use_tree_star.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0175_trait_item_bounds.rast29
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0175_trait_item_bounds.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0176_trait_item_where_clause.rast30
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0176_trait_item_where_clause.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0176_use_tree_alias.rast32
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0176_use_tree_alias.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_assoc_item_list_inner_attrs.rast26
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_assoc_item_list_inner_attrs.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_trait_alias_where_clause.rast96
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_trait_alias_where_clause.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_use_tree.rast30
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_use_tree.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_use_tree_path.rast72
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_use_tree_path.rs6
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0178_use_tree_path_use_tree.rast20
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0178_use_tree_path_use_tree.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0179_use_tree_abs_star.rast26
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0179_use_tree_abs_star.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0180_use_tree_path_star.rast13
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0180_use_tree_path_star.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0181_generic_param_attribute.rast46
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0181_generic_param_attribute.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0181_use_item.rast16
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0181_use_item.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0182_lifetime_param.rast25
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0182_lifetime_param.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0183_const_arg_block.rast32
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0183_const_arg_block.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0183_type_param.rast30
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0183_type_param.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0184_const_arg.rast22
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0184_const_arg.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0184_generic_param_list.rast30
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0184_generic_param_list.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0185_assoc_type_bound.rast37
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0185_assoc_type_bound.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0186_lifetime_arg.rast22
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0186_lifetime_arg.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0187_assoc_type_eq.rast41
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0187_assoc_type_eq.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0188_const_param_default_path.rast36
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0188_const_param_default_path.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0189_const_arg_literal.rast27
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0189_const_arg_literal.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0190_generic_arg.rast25
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0190_generic_arg.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0191_const_arg_negative_number.rast24
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0191_const_arg_negative_number.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0192_const_arg_bool_literal.rast22
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0192_const_arg_bool_literal.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0193_let_stmt_init.rast29
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0193_let_stmt_init.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0194_let_else.rast51
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0194_let_else.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0194_let_stmt_ascription.rast31
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0194_let_stmt_ascription.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0194_macro_inside_generic_arg.rast36
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0194_macro_inside_generic_arg.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0196_pub_tuple_field.rast30
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0196_pub_tuple_field.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0197_destructuring_assignment_struct_rest_pattern.rast44
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0197_destructuring_assignment_struct_rest_pattern.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0198_destructuring_assignment_wildcard_pat.rast50
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0198_destructuring_assignment_wildcard_pat.rs4
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0199_const_param_default_expression.rast34
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0199_const_param_default_expression.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0199_effect_blocks.rast95
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0199_effect_blocks.rs4
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0199_type_item_where_clause_deprecated.rast33
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0199_type_item_where_clause_deprecated.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0200_assoc_const_eq.rast105
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0200_assoc_const_eq.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0200_const_param_default_literal.rast30
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0200_const_param_default_literal.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0201_question_for_type_trait_bound.rast47
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0201_question_for_type_trait_bound.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0000_empty.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0000_empty.rs0
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0001_struct_item.rast39
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0001_struct_item.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0002_struct_item_field.rast22
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0002_struct_item_field.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0004_file_shebang.rast2
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0004_file_shebang.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0005_fn_item.rast16
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0005_fn_item.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0006_inner_attributes.rast194
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0006_inner_attributes.rs10
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0007_extern_crate.rast40
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0007_extern_crate.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0008_mod_item.rast77
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0008_mod_item.rs12
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0009_use_item.rast21
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0009_use_item.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0010_use_path_segments.rast42
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0010_use_path_segments.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0011_outer_attribute.rast61
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0011_outer_attribute.rs6
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0012_visibility.rast133
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0012_visibility.rs6
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0013_use_path_self_super.rast36
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0013_use_path_self_super.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0014_use_tree.rast95
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0014_use_tree.rs7
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0015_use_tree.rast65
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0015_use_tree.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0016_struct_flavors.rast93
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0016_struct_flavors.rs10
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0017_attr_trailing_comma.rast30
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0017_attr_trailing_comma.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0018_struct_type_params.rast274
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0018_struct_type_params.rs17
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0019_enums.rast155
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0019_enums.rs25
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0020_type_param_bounds.rast283
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0020_type_param_bounds.rs10
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0022_empty_extern_block.rast21
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0022_empty_extern_block.rs5
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0023_static_items.rast41
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0023_static_items.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0024_const_item.rast1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0024_const_item.rs0
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0025_extern_fn_in_block.rast33
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0025_extern_fn_in_block.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0026_const_fn_in_block.rast32
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0026_const_fn_in_block.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0027_unsafe_fn_in_block.rast43
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0027_unsafe_fn_in_block.rs4
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0028_operator_binding_power.rast186
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0028_operator_binding_power.rs14
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0029_range_forms.rast152
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0029_range_forms.rs11
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0030_string_suffixes.rast64
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0030_string_suffixes.rs6
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0030_traits.rast61
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0030_traits.rs7
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0031_extern.rast973
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0031_extern.rs29
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0032_where_for.rast93
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0032_where_for.rs4
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0033_label_break.rast223
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0033_label_break.rs28
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0034_crate_path_in_call.rast43
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0034_crate_path_in_call.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0035_weird_exprs.rast2339
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0035_weird_exprs.rs154
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0036_fully_qualified.rast93
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0036_fully_qualified.rs8
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0037_mod.rast16
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0037_mod.rs5
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0038_where_pred_type.rast43
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0038_where_pred_type.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0039_raw_fn_item.rast16
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0039_raw_fn_item.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0040_raw_struct_item_field.rast22
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0040_raw_struct_item_field.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0041_raw_keywords.rast50
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0041_raw_keywords.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0042_ufcs_call_list.rast127
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0042_ufcs_call_list.rs15
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0043_complex_assignment.rast110
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0043_complex_assignment.rs8
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0044_let_attrs.rast77
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0044_let_attrs.rs5
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0045_block_attrs.rast230
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0045_block_attrs.rs24
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0046_extern_inner_attributes.rast29
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0046_extern_inner_attributes.rs4
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0047_minus_in_inner_pattern.rast323
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0047_minus_in_inner_pattern.rs27
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0048_compound_assignment.rast201
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0048_compound_assignment.rs17
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0049_async_block.rast36
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0049_async_block.rs5
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0050_async_block_as_argument.rast92
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0050_async_block_as_argument.rs5
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0051_parameter_attrs.rast548
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0051_parameter_attrs.rs21
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0052_for_range_block.rast81
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0052_for_range_block.rs5
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0053_outer_attribute_on_macro_rules.rast37
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0053_outer_attribute_on_macro_rules.rs5
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0054_qual_path_in_type_arg.rast126
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0054_qual_path_in_type_arg.rs5
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0055_dot_dot_dot.rast50
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0055_dot_dot_dot.rs5
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0056_neq_in_type.rast65
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0056_neq_in_type.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0057_loop_in_call.rast59
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0057_loop_in_call.rs5
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0058_unary_expr_precedence.rast97
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0058_unary_expr_precedence.rs7
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0059_loops_in_parens.rast100
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0059_loops_in_parens.rs5
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0060_as_range.rast56
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0060_as_range.rs4
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0061_match_full_range.rast27
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0061_match_full_range.rs4
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0062_macro_2.0.rast177
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0062_macro_2.0.rs15
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0063_trait_fn_patterns.rast198
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0063_trait_fn_patterns.rs7
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0063_variadic_fun.rast134
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0063_variadic_fun.rs5
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0064_impl_fn_params.rast166
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0064_impl_fn_params.rs6
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0065_comment_newline.rast17
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0065_comment_newline.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0065_plus_after_fn_trait_bound.rast61
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0065_plus_after_fn_trait_bound.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0066_default_modifier.rast222
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0066_default_modifier.rs16
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0067_where_for_pred.rast413
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0067_where_for_pred.rs30
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0068_item_modifiers.rast238
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0068_item_modifiers.rs18
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0069_multi_trait_object.rast204
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0069_multi_trait_object.rs6
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0070_expr_attr_placement.rast59
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0070_expr_attr_placement.rs3
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0071_stmt_attr_placement.rast72
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0071_stmt_attr_placement.rs4
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0072_destructuring_assignment.rast352
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0072_destructuring_assignment.rs14
899 files changed, 35189 insertions, 0 deletions
diff --git a/src/tools/rust-analyzer/crates/parser/Cargo.toml b/src/tools/rust-analyzer/crates/parser/Cargo.toml
new file mode 100644
index 000000000..a286a6bcd
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/Cargo.toml
@@ -0,0 +1,19 @@
+[package]
+name = "parser"
+version = "0.0.0"
+description = "TBD"
+license = "MIT OR Apache-2.0"
+edition = "2021"
+rust-version = "1.57"
+
+[lib]
+doctest = false
+
+[dependencies]
+drop_bomb = "0.1.5"
+rustc_lexer = { version = "725.0.0", package = "rustc-ap-rustc_lexer" }
+limit = { path = "../limit", version = "0.0.0" }
+
+[dev-dependencies]
+expect-test = "1.4.0"
+sourcegen = { path = "../sourcegen" }
diff --git a/src/tools/rust-analyzer/crates/parser/src/event.rs b/src/tools/rust-analyzer/crates/parser/src/event.rs
new file mode 100644
index 000000000..b0e70e794
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/src/event.rs
@@ -0,0 +1,133 @@
+//! This module provides a way to construct a `File`.
+//! It is intended to be completely decoupled from the
+//! parser, so as to allow to evolve the tree representation
+//! and the parser algorithm independently.
+//!
+//! The `TreeSink` trait is the bridge between the parser and the
+//! tree builder: the parser produces a stream of events like
+//! `start node`, `finish node`, and `FileBuilder` converts
+//! this stream to a real tree.
+use std::mem;
+
+use crate::{
+ output::Output,
+ SyntaxKind::{self, *},
+};
+
+/// `Parser` produces a flat list of `Event`s.
+/// They are converted to a tree-structure in
+/// a separate pass, via `TreeBuilder`.
+#[derive(Debug)]
+pub(crate) enum Event {
+ /// This event signifies the start of the node.
+ /// It should be either abandoned (in which case the
+ /// `kind` is `TOMBSTONE`, and the event is ignored),
+ /// or completed via a `Finish` event.
+ ///
+ /// All tokens between a `Start` and a `Finish` would
+ /// become the children of the respective node.
+ ///
+ /// For left-recursive syntactic constructs, the parser produces
+ /// a child node before it sees a parent. `forward_parent`
+ /// saves the position of current event's parent.
+ ///
+ /// Consider this path
+ ///
+ /// foo::bar
+ ///
+ /// The events for it would look like this:
+ ///
+ /// ```text
+ /// START(PATH) IDENT('foo') FINISH START(PATH) T![::] IDENT('bar') FINISH
+ /// | /\
+ /// | |
+ /// +------forward-parent------+
+ /// ```
+ ///
+ /// And the tree would look like this
+ ///
+ /// ```text
+ /// +--PATH---------+
+ /// | | |
+ /// | | |
+ /// | '::' 'bar'
+ /// |
+ /// PATH
+ /// |
+ /// 'foo'
+ /// ```
+ ///
+ /// See also `CompletedMarker::precede`.
+ Start {
+ kind: SyntaxKind,
+ forward_parent: Option<u32>,
+ },
+
+ /// Complete the previous `Start` event
+ Finish,
+
+ /// Produce a single leaf-element.
+ /// `n_raw_tokens` is used to glue complex contextual tokens.
+ /// For example, lexer tokenizes `>>` as `>`, `>`, and
+ /// `n_raw_tokens = 2` is used to produced a single `>>`.
+ Token {
+ kind: SyntaxKind,
+ n_raw_tokens: u8,
+ },
+
+ Error {
+ msg: String,
+ },
+}
+
+impl Event {
+ pub(crate) fn tombstone() -> Self {
+ Event::Start { kind: TOMBSTONE, forward_parent: None }
+ }
+}
+
+/// Generate the syntax tree with the control of events.
+pub(super) fn process(mut events: Vec<Event>) -> Output {
+ let mut res = Output::default();
+ let mut forward_parents = Vec::new();
+
+ for i in 0..events.len() {
+ match mem::replace(&mut events[i], Event::tombstone()) {
+ Event::Start { kind, forward_parent } => {
+ // For events[A, B, C], B is A's forward_parent, C is B's forward_parent,
+ // in the normal control flow, the parent-child relation: `A -> B -> C`,
+ // while with the magic forward_parent, it writes: `C <- B <- A`.
+
+ // append `A` into parents.
+ forward_parents.push(kind);
+ let mut idx = i;
+ let mut fp = forward_parent;
+ while let Some(fwd) = fp {
+ idx += fwd as usize;
+ // append `A`'s forward_parent `B`
+ fp = match mem::replace(&mut events[idx], Event::tombstone()) {
+ Event::Start { kind, forward_parent } => {
+ forward_parents.push(kind);
+ forward_parent
+ }
+ _ => unreachable!(),
+ };
+ // append `B`'s forward_parent `C` in the next stage.
+ }
+
+ for kind in forward_parents.drain(..).rev() {
+ if kind != TOMBSTONE {
+ res.enter_node(kind);
+ }
+ }
+ }
+ Event::Finish => res.leave_node(),
+ Event::Token { kind, n_raw_tokens } => {
+ res.token(kind, n_raw_tokens);
+ }
+ Event::Error { msg } => res.error(msg),
+ }
+ }
+
+ res
+}
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar.rs b/src/tools/rust-analyzer/crates/parser/src/grammar.rs
new file mode 100644
index 000000000..b74683296
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar.rs
@@ -0,0 +1,342 @@
+//! This is the actual "grammar" of the Rust language.
+//!
+//! Each function in this module and its children corresponds
+//! to a production of the formal grammar. Submodules roughly
+//! correspond to different *areas* of the grammar. By convention,
+//! each submodule starts with `use super::*` import and exports
+//! "public" productions via `pub(super)`.
+//!
+//! See docs for [`Parser`](super::parser::Parser) to learn about API,
+//! available to the grammar, and see docs for [`Event`](super::event::Event)
+//! to learn how this actually manages to produce parse trees.
+//!
+//! Code in this module also contains inline tests, which start with
+//! `// test name-of-the-test` comment and look like this:
+//!
+//! ```
+//! // test function_with_zero_parameters
+//! // fn foo() {}
+//! ```
+//!
+//! After adding a new inline-test, run `cargo test -p xtask` to
+//! extract it as a standalone text-fixture into
+//! `crates/syntax/test_data/parser/`, and run `cargo test` once to
+//! create the "gold" value.
+//!
+//! Coding convention: rules like `where_clause` always produce either a
+//! node or an error, rules like `opt_where_clause` may produce nothing.
+//! Non-opt rules typically start with `assert!(p.at(FIRST_TOKEN))`, the
+//! caller is responsible for branching on the first token.
+
+mod attributes;
+mod expressions;
+mod items;
+mod params;
+mod paths;
+mod patterns;
+mod generic_args;
+mod generic_params;
+mod types;
+
+use crate::{
+ parser::{CompletedMarker, Marker, Parser},
+ SyntaxKind::{self, *},
+ TokenSet, T,
+};
+
+pub(crate) mod entry {
+ use super::*;
+
+ pub(crate) mod prefix {
+ use super::*;
+
+ pub(crate) fn vis(p: &mut Parser<'_>) {
+ let _ = opt_visibility(p, false);
+ }
+
+ pub(crate) fn block(p: &mut Parser<'_>) {
+ expressions::block_expr(p);
+ }
+
+ pub(crate) fn stmt(p: &mut Parser<'_>) {
+ expressions::stmt(p, expressions::Semicolon::Forbidden);
+ }
+
+ pub(crate) fn pat(p: &mut Parser<'_>) {
+ patterns::pattern_single(p);
+ }
+
+ pub(crate) fn ty(p: &mut Parser<'_>) {
+ types::type_(p);
+ }
+ pub(crate) fn expr(p: &mut Parser<'_>) {
+ let _ = expressions::expr(p);
+ }
+ pub(crate) fn path(p: &mut Parser<'_>) {
+ let _ = paths::type_path(p);
+ }
+ pub(crate) fn item(p: &mut Parser<'_>) {
+ items::item_or_macro(p, true);
+ }
+ // Parse a meta item , which excluded [], e.g : #[ MetaItem ]
+ pub(crate) fn meta_item(p: &mut Parser<'_>) {
+ attributes::meta(p);
+ }
+ }
+
+ pub(crate) mod top {
+ use super::*;
+
+ pub(crate) fn source_file(p: &mut Parser<'_>) {
+ let m = p.start();
+ p.eat(SHEBANG);
+ items::mod_contents(p, false);
+ m.complete(p, SOURCE_FILE);
+ }
+
+ pub(crate) fn macro_stmts(p: &mut Parser<'_>) {
+ let m = p.start();
+
+ while !p.at(EOF) {
+ expressions::stmt(p, expressions::Semicolon::Optional);
+ }
+
+ m.complete(p, MACRO_STMTS);
+ }
+
+ pub(crate) fn macro_items(p: &mut Parser<'_>) {
+ let m = p.start();
+ items::mod_contents(p, false);
+ m.complete(p, MACRO_ITEMS);
+ }
+
+ pub(crate) fn pattern(p: &mut Parser<'_>) {
+ let m = p.start();
+ patterns::pattern_top(p);
+ if p.at(EOF) {
+ m.abandon(p);
+ return;
+ }
+ while !p.at(EOF) {
+ p.bump_any();
+ }
+ m.complete(p, ERROR);
+ }
+
+ pub(crate) fn type_(p: &mut Parser<'_>) {
+ let m = p.start();
+ types::type_(p);
+ if p.at(EOF) {
+ m.abandon(p);
+ return;
+ }
+ while !p.at(EOF) {
+ p.bump_any();
+ }
+ m.complete(p, ERROR);
+ }
+
+ pub(crate) fn expr(p: &mut Parser<'_>) {
+ let m = p.start();
+ expressions::expr(p);
+ if p.at(EOF) {
+ m.abandon(p);
+ return;
+ }
+ while !p.at(EOF) {
+ p.bump_any();
+ }
+ m.complete(p, ERROR);
+ }
+
+ pub(crate) fn meta_item(p: &mut Parser<'_>) {
+ let m = p.start();
+ attributes::meta(p);
+ if p.at(EOF) {
+ m.abandon(p);
+ return;
+ }
+ while !p.at(EOF) {
+ p.bump_any();
+ }
+ m.complete(p, ERROR);
+ }
+ }
+}
+
+pub(crate) fn reparser(
+ node: SyntaxKind,
+ first_child: Option<SyntaxKind>,
+ parent: Option<SyntaxKind>,
+) -> Option<fn(&mut Parser<'_>)> {
+ let res = match node {
+ BLOCK_EXPR => expressions::block_expr,
+ RECORD_FIELD_LIST => items::record_field_list,
+ RECORD_EXPR_FIELD_LIST => items::record_expr_field_list,
+ VARIANT_LIST => items::variant_list,
+ MATCH_ARM_LIST => items::match_arm_list,
+ USE_TREE_LIST => items::use_tree_list,
+ EXTERN_ITEM_LIST => items::extern_item_list,
+ TOKEN_TREE if first_child? == T!['{'] => items::token_tree,
+ ASSOC_ITEM_LIST => match parent? {
+ IMPL | TRAIT => items::assoc_item_list,
+ _ => return None,
+ },
+ ITEM_LIST => items::item_list,
+ _ => return None,
+ };
+ Some(res)
+}
+
+#[derive(Clone, Copy, PartialEq, Eq)]
+enum BlockLike {
+ Block,
+ NotBlock,
+}
+
+impl BlockLike {
+ fn is_block(self) -> bool {
+ self == BlockLike::Block
+ }
+}
+
+fn opt_visibility(p: &mut Parser<'_>, in_tuple_field: bool) -> bool {
+ match p.current() {
+ T![pub] => {
+ let m = p.start();
+ p.bump(T![pub]);
+ if p.at(T!['(']) {
+ match p.nth(1) {
+ // test crate_visibility
+ // pub(crate) struct S;
+ // pub(self) struct S;
+ // pub(super) struct S;
+
+ // test pub_parens_typepath
+ // struct B(pub (super::A));
+ // struct B(pub (crate::A,));
+ T![crate] | T![self] | T![super] | T![ident] if p.nth(2) != T![:] => {
+ // If we are in a tuple struct, then the parens following `pub`
+ // might be an tuple field, not part of the visibility. So in that
+ // case we don't want to consume an identifier.
+
+ // test pub_tuple_field
+ // struct MyStruct(pub (u32, u32));
+ if !(in_tuple_field && matches!(p.nth(1), T![ident])) {
+ p.bump(T!['(']);
+ paths::use_path(p);
+ p.expect(T![')']);
+ }
+ }
+ // test crate_visibility_in
+ // pub(in super::A) struct S;
+ // pub(in crate) struct S;
+ T![in] => {
+ p.bump(T!['(']);
+ p.bump(T![in]);
+ paths::use_path(p);
+ p.expect(T![')']);
+ }
+ _ => (),
+ }
+ }
+ m.complete(p, VISIBILITY);
+ true
+ }
+ // test crate_keyword_vis
+ // crate fn main() { }
+ // struct S { crate field: u32 }
+ // struct T(crate u32);
+ T![crate] => {
+ if p.nth_at(1, T![::]) {
+ // test crate_keyword_path
+ // fn foo() { crate::foo(); }
+ return false;
+ }
+ let m = p.start();
+ p.bump(T![crate]);
+ m.complete(p, VISIBILITY);
+ true
+ }
+ _ => false,
+ }
+}
+
+fn opt_rename(p: &mut Parser<'_>) {
+ if p.at(T![as]) {
+ let m = p.start();
+ p.bump(T![as]);
+ if !p.eat(T![_]) {
+ name(p);
+ }
+ m.complete(p, RENAME);
+ }
+}
+
+fn abi(p: &mut Parser<'_>) {
+ assert!(p.at(T![extern]));
+ let abi = p.start();
+ p.bump(T![extern]);
+ p.eat(STRING);
+ abi.complete(p, ABI);
+}
+
+fn opt_ret_type(p: &mut Parser<'_>) -> bool {
+ if p.at(T![->]) {
+ let m = p.start();
+ p.bump(T![->]);
+ types::type_no_bounds(p);
+ m.complete(p, RET_TYPE);
+ true
+ } else {
+ false
+ }
+}
+
+fn name_r(p: &mut Parser<'_>, recovery: TokenSet) {
+ if p.at(IDENT) {
+ let m = p.start();
+ p.bump(IDENT);
+ m.complete(p, NAME);
+ } else {
+ p.err_recover("expected a name", recovery);
+ }
+}
+
+fn name(p: &mut Parser<'_>) {
+ name_r(p, TokenSet::EMPTY);
+}
+
+fn name_ref(p: &mut Parser<'_>) {
+ if p.at(IDENT) {
+ let m = p.start();
+ p.bump(IDENT);
+ m.complete(p, NAME_REF);
+ } else {
+ p.err_and_bump("expected identifier");
+ }
+}
+
+fn name_ref_or_index(p: &mut Parser<'_>) {
+ assert!(p.at(IDENT) || p.at(INT_NUMBER));
+ let m = p.start();
+ p.bump_any();
+ m.complete(p, NAME_REF);
+}
+
+fn lifetime(p: &mut Parser<'_>) {
+ assert!(p.at(LIFETIME_IDENT));
+ let m = p.start();
+ p.bump(LIFETIME_IDENT);
+ m.complete(p, LIFETIME);
+}
+
+fn error_block(p: &mut Parser<'_>, message: &str) {
+ assert!(p.at(T!['{']));
+ let m = p.start();
+ p.error(message);
+ p.bump(T!['{']);
+ expressions::expr_block_contents(p);
+ p.eat(T!['}']);
+ m.complete(p, ERROR);
+}
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/attributes.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/attributes.rs
new file mode 100644
index 000000000..0cf6a16f8
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/attributes.rs
@@ -0,0 +1,53 @@
+use super::*;
+
+pub(super) fn inner_attrs(p: &mut Parser<'_>) {
+ while p.at(T![#]) && p.nth(1) == T![!] {
+ attr(p, true);
+ }
+}
+
+pub(super) fn outer_attrs(p: &mut Parser<'_>) {
+ while p.at(T![#]) {
+ attr(p, false);
+ }
+}
+
+fn attr(p: &mut Parser<'_>, inner: bool) {
+ assert!(p.at(T![#]));
+
+ let attr = p.start();
+ p.bump(T![#]);
+
+ if inner {
+ p.bump(T![!]);
+ }
+
+ if p.eat(T!['[']) {
+ meta(p);
+
+ if !p.eat(T![']']) {
+ p.error("expected `]`");
+ }
+ } else {
+ p.error("expected `[`");
+ }
+ attr.complete(p, ATTR);
+}
+
+pub(super) fn meta(p: &mut Parser<'_>) {
+ let meta = p.start();
+ paths::use_path(p);
+
+ match p.current() {
+ T![=] => {
+ p.bump(T![=]);
+ if !expressions::expr(p) {
+ p.error("expected expression");
+ }
+ }
+ T!['('] | T!['['] | T!['{'] => items::token_tree(p),
+ _ => {}
+ }
+
+ meta.complete(p, META);
+}
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs
new file mode 100644
index 000000000..e7402104e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs
@@ -0,0 +1,625 @@
+mod atom;
+
+use super::*;
+
+pub(crate) use self::atom::{block_expr, match_arm_list};
+pub(super) use self::atom::{literal, LITERAL_FIRST};
+
+#[derive(PartialEq, Eq)]
+pub(super) enum Semicolon {
+ Required,
+ Optional,
+ Forbidden,
+}
+
+const EXPR_FIRST: TokenSet = LHS_FIRST;
+
+pub(super) fn expr(p: &mut Parser<'_>) -> bool {
+ let r = Restrictions { forbid_structs: false, prefer_stmt: false };
+ expr_bp(p, None, r, 1).is_some()
+}
+
+pub(super) fn expr_stmt(
+ p: &mut Parser<'_>,
+ m: Option<Marker>,
+) -> Option<(CompletedMarker, BlockLike)> {
+ let r = Restrictions { forbid_structs: false, prefer_stmt: true };
+ expr_bp(p, m, r, 1)
+}
+
+fn expr_no_struct(p: &mut Parser<'_>) {
+ let r = Restrictions { forbid_structs: true, prefer_stmt: false };
+ expr_bp(p, None, r, 1);
+}
+
+/// Parses the expression in `let pattern = expression`.
+/// It needs to be parsed with lower precedence than `&&`, so that
+/// `if let true = true && false` is parsed as `if (let true = true) && (true)`
+/// and not `if let true = (true && true)`.
+fn expr_let(p: &mut Parser<'_>) {
+ let r = Restrictions { forbid_structs: true, prefer_stmt: false };
+ expr_bp(p, None, r, 5);
+}
+
+pub(super) fn stmt(p: &mut Parser<'_>, semicolon: Semicolon) {
+ if p.eat(T![;]) {
+ return;
+ }
+
+ let m = p.start();
+ // test attr_on_expr_stmt
+ // fn foo() {
+ // #[A] foo();
+ // #[B] bar!{}
+ // #[C] #[D] {}
+ // #[D] return ();
+ // }
+ attributes::outer_attrs(p);
+
+ if p.at(T![let]) {
+ let_stmt(p, m, semicolon);
+ return;
+ }
+
+ // test block_items
+ // fn a() { fn b() {} }
+ let m = match items::opt_item(p, m) {
+ Ok(()) => return,
+ Err(m) => m,
+ };
+
+ if let Some((cm, blocklike)) = expr_stmt(p, Some(m)) {
+ if !(p.at(T!['}']) || (semicolon != Semicolon::Required && p.at(EOF))) {
+ // test no_semi_after_block
+ // fn foo() {
+ // if true {}
+ // loop {}
+ // match () {}
+ // while true {}
+ // for _ in () {}
+ // {}
+ // {}
+ // macro_rules! test {
+ // () => {}
+ // }
+ // test!{}
+ // }
+ let m = cm.precede(p);
+ match semicolon {
+ Semicolon::Required => {
+ if blocklike.is_block() {
+ p.eat(T![;]);
+ } else {
+ p.expect(T![;]);
+ }
+ }
+ Semicolon::Optional => {
+ p.eat(T![;]);
+ }
+ Semicolon::Forbidden => (),
+ }
+ m.complete(p, EXPR_STMT);
+ }
+ }
+
+ // test let_stmt
+ // fn f() { let x: i32 = 92; }
+ fn let_stmt(p: &mut Parser<'_>, m: Marker, with_semi: Semicolon) {
+ p.bump(T![let]);
+ patterns::pattern(p);
+ if p.at(T![:]) {
+ // test let_stmt_ascription
+ // fn f() { let x: i32; }
+ types::ascription(p);
+ }
+ if p.eat(T![=]) {
+ // test let_stmt_init
+ // fn f() { let x = 92; }
+ expressions::expr(p);
+ }
+
+ if p.at(T![else]) {
+ // test let_else
+ // fn f() { let Some(x) = opt else { return }; }
+
+ let m = p.start();
+ p.bump(T![else]);
+ block_expr(p);
+ m.complete(p, LET_ELSE);
+ }
+
+ match with_semi {
+ Semicolon::Forbidden => (),
+ Semicolon::Optional => {
+ p.eat(T![;]);
+ }
+ Semicolon::Required => {
+ p.expect(T![;]);
+ }
+ }
+ m.complete(p, LET_STMT);
+ }
+}
+
+pub(super) fn expr_block_contents(p: &mut Parser<'_>) {
+ attributes::inner_attrs(p);
+
+ while !p.at(EOF) && !p.at(T!['}']) {
+ // test nocontentexpr
+ // fn foo(){
+ // ;;;some_expr();;;;{;;;};;;;Ok(())
+ // }
+
+ // test nocontentexpr_after_item
+ // fn simple_function() {
+ // enum LocalEnum {
+ // One,
+ // Two,
+ // };
+ // fn f() {};
+ // struct S {};
+ // }
+ stmt(p, Semicolon::Required);
+ }
+}
+
+#[derive(Clone, Copy)]
+struct Restrictions {
+ forbid_structs: bool,
+ prefer_stmt: bool,
+}
+
+/// Binding powers of operators for a Pratt parser.
+///
+/// See <https://matklad.github.io/2020/04/13/simple-but-powerful-pratt-parsing.html>
+#[rustfmt::skip]
+fn current_op(p: &Parser<'_>) -> (u8, SyntaxKind) {
+ const NOT_AN_OP: (u8, SyntaxKind) = (0, T![@]);
+ match p.current() {
+ T![|] if p.at(T![||]) => (3, T![||]),
+ T![|] if p.at(T![|=]) => (1, T![|=]),
+ T![|] => (6, T![|]),
+ T![>] if p.at(T![>>=]) => (1, T![>>=]),
+ T![>] if p.at(T![>>]) => (9, T![>>]),
+ T![>] if p.at(T![>=]) => (5, T![>=]),
+ T![>] => (5, T![>]),
+ T![=] if p.at(T![=>]) => NOT_AN_OP,
+ T![=] if p.at(T![==]) => (5, T![==]),
+ T![=] => (1, T![=]),
+ T![<] if p.at(T![<=]) => (5, T![<=]),
+ T![<] if p.at(T![<<=]) => (1, T![<<=]),
+ T![<] if p.at(T![<<]) => (9, T![<<]),
+ T![<] => (5, T![<]),
+ T![+] if p.at(T![+=]) => (1, T![+=]),
+ T![+] => (10, T![+]),
+ T![^] if p.at(T![^=]) => (1, T![^=]),
+ T![^] => (7, T![^]),
+ T![%] if p.at(T![%=]) => (1, T![%=]),
+ T![%] => (11, T![%]),
+ T![&] if p.at(T![&=]) => (1, T![&=]),
+ // If you update this, remember to update `expr_let()` too.
+ T![&] if p.at(T![&&]) => (4, T![&&]),
+ T![&] => (8, T![&]),
+ T![/] if p.at(T![/=]) => (1, T![/=]),
+ T![/] => (11, T![/]),
+ T![*] if p.at(T![*=]) => (1, T![*=]),
+ T![*] => (11, T![*]),
+ T![.] if p.at(T![..=]) => (2, T![..=]),
+ T![.] if p.at(T![..]) => (2, T![..]),
+ T![!] if p.at(T![!=]) => (5, T![!=]),
+ T![-] if p.at(T![-=]) => (1, T![-=]),
+ T![-] => (10, T![-]),
+ T![as] => (12, T![as]),
+
+ _ => NOT_AN_OP
+ }
+}
+
+// Parses expression with binding power of at least bp.
+fn expr_bp(
+ p: &mut Parser<'_>,
+ m: Option<Marker>,
+ mut r: Restrictions,
+ bp: u8,
+) -> Option<(CompletedMarker, BlockLike)> {
+ let m = m.unwrap_or_else(|| {
+ let m = p.start();
+ attributes::outer_attrs(p);
+ m
+ });
+ let mut lhs = match lhs(p, r) {
+ Some((lhs, blocklike)) => {
+ let lhs = lhs.extend_to(p, m);
+ if r.prefer_stmt && blocklike.is_block() {
+ // test stmt_bin_expr_ambiguity
+ // fn f() {
+ // let _ = {1} & 2;
+ // {1} &2;
+ // }
+ return Some((lhs, BlockLike::Block));
+ }
+ lhs
+ }
+ None => {
+ m.abandon(p);
+ return None;
+ }
+ };
+
+ loop {
+ let is_range = p.at(T![..]) || p.at(T![..=]);
+ let (op_bp, op) = current_op(p);
+ if op_bp < bp {
+ break;
+ }
+ // test as_precedence
+ // fn f() { let _ = &1 as *const i32; }
+ if p.at(T![as]) {
+ lhs = cast_expr(p, lhs);
+ continue;
+ }
+ let m = lhs.precede(p);
+ p.bump(op);
+
+ // test binop_resets_statementness
+ // fn f() { v = {1}&2; }
+ r = Restrictions { prefer_stmt: false, ..r };
+
+ if is_range {
+ // test postfix_range
+ // fn foo() {
+ // let x = 1..;
+ // match 1.. { _ => () };
+ // match a.b()..S { _ => () };
+ // }
+ let has_trailing_expression =
+ p.at_ts(EXPR_FIRST) && !(r.forbid_structs && p.at(T!['{']));
+ if !has_trailing_expression {
+ // no RHS
+ lhs = m.complete(p, RANGE_EXPR);
+ break;
+ }
+ }
+
+ expr_bp(p, None, Restrictions { prefer_stmt: false, ..r }, op_bp + 1);
+ lhs = m.complete(p, if is_range { RANGE_EXPR } else { BIN_EXPR });
+ }
+ Some((lhs, BlockLike::NotBlock))
+}
+
+const LHS_FIRST: TokenSet =
+ atom::ATOM_EXPR_FIRST.union(TokenSet::new(&[T![&], T![*], T![!], T![.], T![-]]));
+
+fn lhs(p: &mut Parser<'_>, r: Restrictions) -> Option<(CompletedMarker, BlockLike)> {
+ let m;
+ let kind = match p.current() {
+ // test ref_expr
+ // fn foo() {
+ // // reference operator
+ // let _ = &1;
+ // let _ = &mut &f();
+ // let _ = &raw;
+ // let _ = &raw.0;
+ // // raw reference operator
+ // let _ = &raw mut foo;
+ // let _ = &raw const foo;
+ // }
+ T![&] => {
+ m = p.start();
+ p.bump(T![&]);
+ if p.at_contextual_kw(T![raw]) && (p.nth_at(1, T![mut]) || p.nth_at(1, T![const])) {
+ p.bump_remap(T![raw]);
+ p.bump_any();
+ } else {
+ p.eat(T![mut]);
+ }
+ REF_EXPR
+ }
+ // test unary_expr
+ // fn foo() {
+ // **&1;
+ // !!true;
+ // --1;
+ // }
+ T![*] | T![!] | T![-] => {
+ m = p.start();
+ p.bump_any();
+ PREFIX_EXPR
+ }
+ _ => {
+ // test full_range_expr
+ // fn foo() { xs[..]; }
+ for op in [T![..=], T![..]] {
+ if p.at(op) {
+ m = p.start();
+ p.bump(op);
+ if p.at_ts(EXPR_FIRST) && !(r.forbid_structs && p.at(T!['{'])) {
+ expr_bp(p, None, r, 2);
+ }
+ let cm = m.complete(p, RANGE_EXPR);
+ return Some((cm, BlockLike::NotBlock));
+ }
+ }
+
+ // test expression_after_block
+ // fn foo() {
+ // let mut p = F{x: 5};
+ // {p}.x = 10;
+ // }
+ let (lhs, blocklike) = atom::atom_expr(p, r)?;
+ let (cm, block_like) =
+ postfix_expr(p, lhs, blocklike, !(r.prefer_stmt && blocklike.is_block()));
+ return Some((cm, block_like));
+ }
+ };
+ // parse the interior of the unary expression
+ expr_bp(p, None, r, 255);
+ let cm = m.complete(p, kind);
+ Some((cm, BlockLike::NotBlock))
+}
+
+fn postfix_expr(
+ p: &mut Parser<'_>,
+ mut lhs: CompletedMarker,
+ // Calls are disallowed if the type is a block and we prefer statements because the call cannot be disambiguated from a tuple
+ // E.g. `while true {break}();` is parsed as
+ // `while true {break}; ();`
+ mut block_like: BlockLike,
+ mut allow_calls: bool,
+) -> (CompletedMarker, BlockLike) {
+ loop {
+ lhs = match p.current() {
+ // test stmt_postfix_expr_ambiguity
+ // fn foo() {
+ // match () {
+ // _ => {}
+ // () => {}
+ // [] => {}
+ // }
+ // }
+ T!['('] if allow_calls => call_expr(p, lhs),
+ T!['['] if allow_calls => index_expr(p, lhs),
+ T![.] => match postfix_dot_expr(p, lhs) {
+ Ok(it) => it,
+ Err(it) => {
+ lhs = it;
+ break;
+ }
+ },
+ T![?] => try_expr(p, lhs),
+ _ => break,
+ };
+ allow_calls = true;
+ block_like = BlockLike::NotBlock;
+ }
+ return (lhs, block_like);
+
+ fn postfix_dot_expr(
+ p: &mut Parser<'_>,
+ lhs: CompletedMarker,
+ ) -> Result<CompletedMarker, CompletedMarker> {
+ assert!(p.at(T![.]));
+ if p.nth(1) == IDENT && (p.nth(2) == T!['('] || p.nth_at(2, T![::])) {
+ return Ok(method_call_expr(p, lhs));
+ }
+
+ // test await_expr
+ // fn foo() {
+ // x.await;
+ // x.0.await;
+ // x.0().await?.hello();
+ // }
+ if p.nth(1) == T![await] {
+ let m = lhs.precede(p);
+ p.bump(T![.]);
+ p.bump(T![await]);
+ return Ok(m.complete(p, AWAIT_EXPR));
+ }
+
+ if p.at(T![..=]) || p.at(T![..]) {
+ return Err(lhs);
+ }
+
+ Ok(field_expr(p, lhs))
+ }
+}
+
+// test call_expr
+// fn foo() {
+// let _ = f();
+// let _ = f()(1)(1, 2,);
+// let _ = f(<Foo>::func());
+// f(<Foo as Trait>::func());
+// }
+fn call_expr(p: &mut Parser<'_>, lhs: CompletedMarker) -> CompletedMarker {
+ assert!(p.at(T!['(']));
+ let m = lhs.precede(p);
+ arg_list(p);
+ m.complete(p, CALL_EXPR)
+}
+
+// test index_expr
+// fn foo() {
+// x[1][2];
+// }
+fn index_expr(p: &mut Parser<'_>, lhs: CompletedMarker) -> CompletedMarker {
+ assert!(p.at(T!['[']));
+ let m = lhs.precede(p);
+ p.bump(T!['[']);
+ expr(p);
+ p.expect(T![']']);
+ m.complete(p, INDEX_EXPR)
+}
+
+// test method_call_expr
+// fn foo() {
+// x.foo();
+// y.bar::<T>(1, 2,);
+// }
+fn method_call_expr(p: &mut Parser<'_>, lhs: CompletedMarker) -> CompletedMarker {
+ assert!(p.at(T![.]) && p.nth(1) == IDENT && (p.nth(2) == T!['('] || p.nth_at(2, T![::])));
+ let m = lhs.precede(p);
+ p.bump_any();
+ name_ref(p);
+ generic_args::opt_generic_arg_list(p, true);
+ if p.at(T!['(']) {
+ arg_list(p);
+ }
+ m.complete(p, METHOD_CALL_EXPR)
+}
+
+// test field_expr
+// fn foo() {
+// x.foo;
+// x.0.bar;
+// x.0();
+// }
+fn field_expr(p: &mut Parser<'_>, lhs: CompletedMarker) -> CompletedMarker {
+ assert!(p.at(T![.]));
+ let m = lhs.precede(p);
+ p.bump(T![.]);
+ if p.at(IDENT) || p.at(INT_NUMBER) {
+ name_ref_or_index(p);
+ } else if p.at(FLOAT_NUMBER) {
+ // FIXME: How to recover and instead parse INT + T![.]?
+ p.bump_any();
+ } else {
+ p.error("expected field name or number");
+ }
+ m.complete(p, FIELD_EXPR)
+}
+
+// test try_expr
+// fn foo() {
+// x?;
+// }
+fn try_expr(p: &mut Parser<'_>, lhs: CompletedMarker) -> CompletedMarker {
+ assert!(p.at(T![?]));
+ let m = lhs.precede(p);
+ p.bump(T![?]);
+ m.complete(p, TRY_EXPR)
+}
+
+// test cast_expr
+// fn foo() {
+// 82 as i32;
+// 81 as i8 + 1;
+// 79 as i16 - 1;
+// 0x36 as u8 <= 0x37;
+// }
+fn cast_expr(p: &mut Parser<'_>, lhs: CompletedMarker) -> CompletedMarker {
+ assert!(p.at(T![as]));
+ let m = lhs.precede(p);
+ p.bump(T![as]);
+ // Use type_no_bounds(), because cast expressions are not
+ // allowed to have bounds.
+ types::type_no_bounds(p);
+ m.complete(p, CAST_EXPR)
+}
+
+fn arg_list(p: &mut Parser<'_>) {
+ assert!(p.at(T!['(']));
+ let m = p.start();
+ p.bump(T!['(']);
+ while !p.at(T![')']) && !p.at(EOF) {
+ // test arg_with_attr
+ // fn main() {
+ // foo(#[attr] 92)
+ // }
+ if !expr(p) {
+ break;
+ }
+ if !p.at(T![')']) && !p.expect(T![,]) {
+ break;
+ }
+ }
+ p.eat(T![')']);
+ m.complete(p, ARG_LIST);
+}
+
+// test path_expr
+// fn foo() {
+// let _ = a;
+// let _ = a::b;
+// let _ = ::a::<b>;
+// let _ = format!();
+// }
+fn path_expr(p: &mut Parser<'_>, r: Restrictions) -> (CompletedMarker, BlockLike) {
+ assert!(paths::is_path_start(p));
+ let m = p.start();
+ paths::expr_path(p);
+ match p.current() {
+ T!['{'] if !r.forbid_structs => {
+ record_expr_field_list(p);
+ (m.complete(p, RECORD_EXPR), BlockLike::NotBlock)
+ }
+ T![!] if !p.at(T![!=]) => {
+ let block_like = items::macro_call_after_excl(p);
+ (m.complete(p, MACRO_CALL).precede(p).complete(p, MACRO_EXPR), block_like)
+ }
+ _ => (m.complete(p, PATH_EXPR), BlockLike::NotBlock),
+ }
+}
+
+// test record_lit
+// fn foo() {
+// S {};
+// S { x, y: 32, };
+// S { x, y: 32, ..Default::default() };
+// TupleStruct { 0: 1 };
+// }
+pub(crate) fn record_expr_field_list(p: &mut Parser<'_>) {
+ assert!(p.at(T!['{']));
+ let m = p.start();
+ p.bump(T!['{']);
+ while !p.at(EOF) && !p.at(T!['}']) {
+ let m = p.start();
+ // test record_literal_field_with_attr
+ // fn main() {
+ // S { #[cfg(test)] field: 1 }
+ // }
+ attributes::outer_attrs(p);
+
+ match p.current() {
+ IDENT | INT_NUMBER => {
+ // test_err record_literal_before_ellipsis_recovery
+ // fn main() {
+ // S { field ..S::default() }
+ // }
+ if p.nth_at(1, T![:]) || p.nth_at(1, T![..]) {
+ name_ref_or_index(p);
+ p.expect(T![:]);
+ }
+ expr(p);
+ m.complete(p, RECORD_EXPR_FIELD);
+ }
+ T![.] if p.at(T![..]) => {
+ m.abandon(p);
+ p.bump(T![..]);
+
+ // test destructuring_assignment_struct_rest_pattern
+ // fn foo() {
+ // S { .. } = S {};
+ // }
+
+ // We permit `.. }` on the left-hand side of a destructuring assignment.
+ if !p.at(T!['}']) {
+ expr(p);
+ }
+ }
+ T!['{'] => {
+ error_block(p, "expected a field");
+ m.abandon(p);
+ }
+ _ => {
+ p.err_and_bump("expected identifier");
+ m.abandon(p);
+ }
+ }
+ if !p.at(T!['}']) {
+ p.expect(T![,]);
+ }
+ }
+ p.expect(T!['}']);
+ m.complete(p, RECORD_EXPR_FIELD_LIST);
+}
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs
new file mode 100644
index 000000000..99f42a266
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs
@@ -0,0 +1,643 @@
+use super::*;
+
+// test expr_literals
+// fn foo() {
+// let _ = true;
+// let _ = false;
+// let _ = 1;
+// let _ = 2.0;
+// let _ = b'a';
+// let _ = 'b';
+// let _ = "c";
+// let _ = r"d";
+// let _ = b"e";
+// let _ = br"f";
+// }
+pub(crate) const LITERAL_FIRST: TokenSet = TokenSet::new(&[
+ T![true],
+ T![false],
+ INT_NUMBER,
+ FLOAT_NUMBER,
+ BYTE,
+ CHAR,
+ STRING,
+ BYTE_STRING,
+]);
+
+pub(crate) fn literal(p: &mut Parser<'_>) -> Option<CompletedMarker> {
+ if !p.at_ts(LITERAL_FIRST) {
+ return None;
+ }
+ let m = p.start();
+ p.bump_any();
+ Some(m.complete(p, LITERAL))
+}
+
+// E.g. for after the break in `if break {}`, this should not match
+pub(super) const ATOM_EXPR_FIRST: TokenSet =
+ LITERAL_FIRST.union(paths::PATH_FIRST).union(TokenSet::new(&[
+ T!['('],
+ T!['{'],
+ T!['['],
+ T![|],
+ T![move],
+ T![box],
+ T![if],
+ T![while],
+ T![match],
+ T![unsafe],
+ T![return],
+ T![yield],
+ T![break],
+ T![continue],
+ T![async],
+ T![try],
+ T![const],
+ T![loop],
+ T![for],
+ LIFETIME_IDENT,
+ ]));
+
+const EXPR_RECOVERY_SET: TokenSet = TokenSet::new(&[T![let]]);
+
+pub(super) fn atom_expr(
+ p: &mut Parser<'_>,
+ r: Restrictions,
+) -> Option<(CompletedMarker, BlockLike)> {
+ if let Some(m) = literal(p) {
+ return Some((m, BlockLike::NotBlock));
+ }
+ if paths::is_path_start(p) {
+ return Some(path_expr(p, r));
+ }
+ let la = p.nth(1);
+ let done = match p.current() {
+ T!['('] => tuple_expr(p),
+ T!['['] => array_expr(p),
+ T![if] => if_expr(p),
+ T![let] => let_expr(p),
+ T![_] => {
+ // test destructuring_assignment_wildcard_pat
+ // fn foo() {
+ // _ = 1;
+ // Some(_) = None;
+ // }
+ let m = p.start();
+ p.bump(T![_]);
+ m.complete(p, UNDERSCORE_EXPR)
+ }
+ T![loop] => loop_expr(p, None),
+ T![box] => box_expr(p, None),
+ T![while] => while_expr(p, None),
+ T![try] => try_block_expr(p, None),
+ T![match] => match_expr(p),
+ T![return] => return_expr(p),
+ T![yield] => yield_expr(p),
+ T![continue] => continue_expr(p),
+ T![break] => break_expr(p, r),
+
+ LIFETIME_IDENT if la == T![:] => {
+ let m = p.start();
+ label(p);
+ match p.current() {
+ T![loop] => loop_expr(p, Some(m)),
+ T![for] => for_expr(p, Some(m)),
+ T![while] => while_expr(p, Some(m)),
+ // test labeled_block
+ // fn f() { 'label: {}; }
+ T!['{'] => {
+ stmt_list(p);
+ m.complete(p, BLOCK_EXPR)
+ }
+ _ => {
+ // test_err misplaced_label_err
+ // fn main() {
+ // 'loop: impl
+ // }
+ p.error("expected a loop");
+ m.complete(p, ERROR);
+ return None;
+ }
+ }
+ }
+ // test effect_blocks
+ // fn f() { unsafe { } }
+ // fn f() { const { } }
+ // fn f() { async { } }
+ // fn f() { async move { } }
+ T![const] | T![unsafe] | T![async] if la == T!['{'] => {
+ let m = p.start();
+ p.bump_any();
+ stmt_list(p);
+ m.complete(p, BLOCK_EXPR)
+ }
+ T![async] if la == T![move] && p.nth(2) == T!['{'] => {
+ let m = p.start();
+ p.bump(T![async]);
+ p.eat(T![move]);
+ stmt_list(p);
+ m.complete(p, BLOCK_EXPR)
+ }
+ T!['{'] => {
+ // test for_range_from
+ // fn foo() {
+ // for x in 0 .. {
+ // break;
+ // }
+ // }
+ let m = p.start();
+ stmt_list(p);
+ m.complete(p, BLOCK_EXPR)
+ }
+
+ T![static] | T![async] | T![move] | T![|] => closure_expr(p),
+ T![for] if la == T![<] => closure_expr(p),
+ T![for] => for_expr(p, None),
+
+ _ => {
+ p.err_recover("expected expression", EXPR_RECOVERY_SET);
+ return None;
+ }
+ };
+ let blocklike = match done.kind() {
+ IF_EXPR | WHILE_EXPR | FOR_EXPR | LOOP_EXPR | MATCH_EXPR | BLOCK_EXPR => BlockLike::Block,
+ _ => BlockLike::NotBlock,
+ };
+ Some((done, blocklike))
+}
+
+// test tuple_expr
+// fn foo() {
+// ();
+// (1);
+// (1,);
+// }
+fn tuple_expr(p: &mut Parser<'_>) -> CompletedMarker {
+ assert!(p.at(T!['(']));
+ let m = p.start();
+ p.expect(T!['(']);
+
+ let mut saw_comma = false;
+ let mut saw_expr = false;
+ while !p.at(EOF) && !p.at(T![')']) {
+ saw_expr = true;
+
+ // test tuple_attrs
+ // const A: (i64, i64) = (1, #[cfg(test)] 2);
+ if !expr(p) {
+ break;
+ }
+
+ if !p.at(T![')']) {
+ saw_comma = true;
+ p.expect(T![,]);
+ }
+ }
+ p.expect(T![')']);
+ m.complete(p, if saw_expr && !saw_comma { PAREN_EXPR } else { TUPLE_EXPR })
+}
+
+// test array_expr
+// fn foo() {
+// [];
+// [1];
+// [1, 2,];
+// [1; 2];
+// }
+fn array_expr(p: &mut Parser<'_>) -> CompletedMarker {
+ assert!(p.at(T!['[']));
+ let m = p.start();
+
+ let mut n_exprs = 0u32;
+ let mut has_semi = false;
+
+ p.bump(T!['[']);
+ while !p.at(EOF) && !p.at(T![']']) {
+ n_exprs += 1;
+
+ // test array_attrs
+ // const A: &[i64] = &[1, #[cfg(test)] 2];
+ if !expr(p) {
+ break;
+ }
+
+ if n_exprs == 1 && p.eat(T![;]) {
+ has_semi = true;
+ continue;
+ }
+
+ if has_semi || !p.at(T![']']) && !p.expect(T![,]) {
+ break;
+ }
+ }
+ p.expect(T![']']);
+
+ m.complete(p, ARRAY_EXPR)
+}
+
+// test lambda_expr
+// fn foo() {
+// || ();
+// || -> i32 { 92 };
+// |x| x;
+// move |x: i32,| x;
+// async || {};
+// move || {};
+// async move || {};
+// static || {};
+// static move || {};
+// static async || {};
+// static async move || {};
+// for<'a> || {};
+// for<'a> move || {};
+// }
+fn closure_expr(p: &mut Parser<'_>) -> CompletedMarker {
+ assert!(match p.current() {
+ T![static] | T![async] | T![move] | T![|] => true,
+ T![for] => p.nth(1) == T![<],
+ _ => false,
+ });
+
+ let m = p.start();
+
+ if p.at(T![for]) {
+ types::for_binder(p);
+ }
+
+ p.eat(T![static]);
+ p.eat(T![async]);
+ p.eat(T![move]);
+
+ if !p.at(T![|]) {
+ p.error("expected `|`");
+ return m.complete(p, CLOSURE_EXPR);
+ }
+ params::param_list_closure(p);
+ if opt_ret_type(p) {
+ // test lambda_ret_block
+ // fn main() { || -> i32 { 92 }(); }
+ block_expr(p);
+ } else if p.at_ts(EXPR_FIRST) {
+ expr(p);
+ } else {
+ p.error("expected expression");
+ }
+ m.complete(p, CLOSURE_EXPR)
+}
+
+// test if_expr
+// fn foo() {
+// if true {};
+// if true {} else {};
+// if true {} else if false {} else {};
+// if S {};
+// if { true } { } else { };
+// }
+fn if_expr(p: &mut Parser<'_>) -> CompletedMarker {
+ assert!(p.at(T![if]));
+ let m = p.start();
+ p.bump(T![if]);
+ expr_no_struct(p);
+ block_expr(p);
+ if p.at(T![else]) {
+ p.bump(T![else]);
+ if p.at(T![if]) {
+ if_expr(p);
+ } else {
+ block_expr(p);
+ }
+ }
+ m.complete(p, IF_EXPR)
+}
+
+// test label
+// fn foo() {
+// 'a: loop {}
+// 'b: while true {}
+// 'c: for x in () {}
+// }
+fn label(p: &mut Parser<'_>) {
+ assert!(p.at(LIFETIME_IDENT) && p.nth(1) == T![:]);
+ let m = p.start();
+ lifetime(p);
+ p.bump_any();
+ m.complete(p, LABEL);
+}
+
+// test loop_expr
+// fn foo() {
+// loop {};
+// }
+fn loop_expr(p: &mut Parser<'_>, m: Option<Marker>) -> CompletedMarker {
+ assert!(p.at(T![loop]));
+ let m = m.unwrap_or_else(|| p.start());
+ p.bump(T![loop]);
+ block_expr(p);
+ m.complete(p, LOOP_EXPR)
+}
+
+// test while_expr
+// fn foo() {
+// while true {};
+// while let Some(x) = it.next() {};
+// while { true } {};
+// }
+fn while_expr(p: &mut Parser<'_>, m: Option<Marker>) -> CompletedMarker {
+ assert!(p.at(T![while]));
+ let m = m.unwrap_or_else(|| p.start());
+ p.bump(T![while]);
+ expr_no_struct(p);
+ block_expr(p);
+ m.complete(p, WHILE_EXPR)
+}
+
+// test for_expr
+// fn foo() {
+// for x in [] {};
+// }
+fn for_expr(p: &mut Parser<'_>, m: Option<Marker>) -> CompletedMarker {
+ assert!(p.at(T![for]));
+ let m = m.unwrap_or_else(|| p.start());
+ p.bump(T![for]);
+ patterns::pattern(p);
+ p.expect(T![in]);
+ expr_no_struct(p);
+ block_expr(p);
+ m.complete(p, FOR_EXPR)
+}
+
+// test let_expr
+// fn foo() {
+// if let Some(_) = None && true {}
+// while 1 == 5 && (let None = None) {}
+// }
+fn let_expr(p: &mut Parser<'_>) -> CompletedMarker {
+ let m = p.start();
+ p.bump(T![let]);
+ patterns::pattern_top(p);
+ p.expect(T![=]);
+ expr_let(p);
+ m.complete(p, LET_EXPR)
+}
+
+// test match_expr
+// fn foo() {
+// match () { };
+// match S {};
+// match { } { _ => () };
+// match { S {} } {};
+// }
+fn match_expr(p: &mut Parser<'_>) -> CompletedMarker {
+ assert!(p.at(T![match]));
+ let m = p.start();
+ p.bump(T![match]);
+ expr_no_struct(p);
+ if p.at(T!['{']) {
+ match_arm_list(p);
+ } else {
+ p.error("expected `{`");
+ }
+ m.complete(p, MATCH_EXPR)
+}
+
+pub(crate) fn match_arm_list(p: &mut Parser<'_>) {
+ assert!(p.at(T!['{']));
+ let m = p.start();
+ p.eat(T!['{']);
+
+ // test match_arms_inner_attribute
+ // fn foo() {
+ // match () {
+ // #![doc("Inner attribute")]
+ // #![doc("Can be")]
+ // #![doc("Stacked")]
+ // _ => (),
+ // }
+ // }
+ attributes::inner_attrs(p);
+
+ while !p.at(EOF) && !p.at(T!['}']) {
+ if p.at(T!['{']) {
+ error_block(p, "expected match arm");
+ continue;
+ }
+ match_arm(p);
+ }
+ p.expect(T!['}']);
+ m.complete(p, MATCH_ARM_LIST);
+}
+
+// test match_arm
+// fn foo() {
+// match () {
+// _ => (),
+// _ if Test > Test{field: 0} => (),
+// X | Y if Z => (),
+// | X | Y if Z => (),
+// | X => (),
+// };
+// }
+fn match_arm(p: &mut Parser<'_>) {
+ let m = p.start();
+ // test match_arms_outer_attributes
+ // fn foo() {
+ // match () {
+ // #[cfg(feature = "some")]
+ // _ => (),
+ // #[cfg(feature = "other")]
+ // _ => (),
+ // #[cfg(feature = "many")]
+ // #[cfg(feature = "attributes")]
+ // #[cfg(feature = "before")]
+ // _ => (),
+ // }
+ // }
+ attributes::outer_attrs(p);
+
+ patterns::pattern_top_r(p, TokenSet::EMPTY);
+ if p.at(T![if]) {
+ match_guard(p);
+ }
+ p.expect(T![=>]);
+ let blocklike = match expr_stmt(p, None) {
+ Some((_, blocklike)) => blocklike,
+ None => BlockLike::NotBlock,
+ };
+
+ // test match_arms_commas
+ // fn foo() {
+ // match () {
+ // _ => (),
+ // _ => {}
+ // _ => ()
+ // }
+ // }
+ if !p.eat(T![,]) && !blocklike.is_block() && !p.at(T!['}']) {
+ p.error("expected `,`");
+ }
+ m.complete(p, MATCH_ARM);
+}
+
+// test match_guard
+// fn foo() {
+// match () {
+// _ if foo => (),
+// _ if let foo = bar => (),
+// }
+// }
+fn match_guard(p: &mut Parser<'_>) -> CompletedMarker {
+ assert!(p.at(T![if]));
+ let m = p.start();
+ p.bump(T![if]);
+ expr(p);
+ m.complete(p, MATCH_GUARD)
+}
+
+// test block
+// fn a() {}
+// fn b() { let _ = 1; }
+// fn c() { 1; 2; }
+// fn d() { 1; 2 }
+pub(crate) fn block_expr(p: &mut Parser<'_>) {
+ if !p.at(T!['{']) {
+ p.error("expected a block");
+ return;
+ }
+ let m = p.start();
+ stmt_list(p);
+ m.complete(p, BLOCK_EXPR);
+}
+
+fn stmt_list(p: &mut Parser<'_>) -> CompletedMarker {
+ assert!(p.at(T!['{']));
+ let m = p.start();
+ p.bump(T!['{']);
+ expr_block_contents(p);
+ p.expect(T!['}']);
+ m.complete(p, STMT_LIST)
+}
+
+// test return_expr
+// fn foo() {
+// return;
+// return 92;
+// }
+fn return_expr(p: &mut Parser<'_>) -> CompletedMarker {
+ assert!(p.at(T![return]));
+ let m = p.start();
+ p.bump(T![return]);
+ if p.at_ts(EXPR_FIRST) {
+ expr(p);
+ }
+ m.complete(p, RETURN_EXPR)
+}
+// test yield_expr
+// fn foo() {
+// yield;
+// yield 1;
+// }
+fn yield_expr(p: &mut Parser<'_>) -> CompletedMarker {
+ assert!(p.at(T![yield]));
+ let m = p.start();
+ p.bump(T![yield]);
+ if p.at_ts(EXPR_FIRST) {
+ expr(p);
+ }
+ m.complete(p, YIELD_EXPR)
+}
+
+// test continue_expr
+// fn foo() {
+// loop {
+// continue;
+// continue 'l;
+// }
+// }
+fn continue_expr(p: &mut Parser<'_>) -> CompletedMarker {
+ assert!(p.at(T![continue]));
+ let m = p.start();
+ p.bump(T![continue]);
+ if p.at(LIFETIME_IDENT) {
+ lifetime(p);
+ }
+ m.complete(p, CONTINUE_EXPR)
+}
+
+// test break_expr
+// fn foo() {
+// loop {
+// break;
+// break 'l;
+// break 92;
+// break 'l 92;
+// }
+// }
+fn break_expr(p: &mut Parser<'_>, r: Restrictions) -> CompletedMarker {
+ assert!(p.at(T![break]));
+ let m = p.start();
+ p.bump(T![break]);
+ if p.at(LIFETIME_IDENT) {
+ lifetime(p);
+ }
+ // test break_ambiguity
+ // fn foo(){
+ // if break {}
+ // while break {}
+ // for i in break {}
+ // match break {}
+ // }
+ if p.at_ts(EXPR_FIRST) && !(r.forbid_structs && p.at(T!['{'])) {
+ expr(p);
+ }
+ m.complete(p, BREAK_EXPR)
+}
+
+// test try_block_expr
+// fn foo() {
+// let _ = try {};
+// }
+fn try_block_expr(p: &mut Parser<'_>, m: Option<Marker>) -> CompletedMarker {
+ assert!(p.at(T![try]));
+ let m = m.unwrap_or_else(|| p.start());
+ // Special-case `try!` as macro.
+ // This is a hack until we do proper edition support
+ if p.nth_at(1, T![!]) {
+ // test try_macro_fallback
+ // fn foo() { try!(Ok(())); }
+ let macro_call = p.start();
+ let path = p.start();
+ let path_segment = p.start();
+ let name_ref = p.start();
+ p.bump_remap(IDENT);
+ name_ref.complete(p, NAME_REF);
+ path_segment.complete(p, PATH_SEGMENT);
+ path.complete(p, PATH);
+ let _block_like = items::macro_call_after_excl(p);
+ macro_call.complete(p, MACRO_CALL);
+ return m.complete(p, MACRO_EXPR);
+ }
+
+ p.bump(T![try]);
+ if p.at(T!['{']) {
+ stmt_list(p);
+ } else {
+ p.error("expected a block");
+ }
+ m.complete(p, BLOCK_EXPR)
+}
+
+// test box_expr
+// fn foo() {
+// let x = box 1i32;
+// let y = (box 1i32, box 2i32);
+// let z = Foo(box 1i32, box 2i32);
+// }
+fn box_expr(p: &mut Parser<'_>, m: Option<Marker>) -> CompletedMarker {
+ assert!(p.at(T![box]));
+ let m = m.unwrap_or_else(|| p.start());
+ p.bump(T![box]);
+ if p.at_ts(EXPR_FIRST) {
+ expr(p);
+ }
+ m.complete(p, BOX_EXPR)
+}
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs
new file mode 100644
index 000000000..c438943a0
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs
@@ -0,0 +1,131 @@
+use super::*;
+
+pub(super) fn opt_generic_arg_list(p: &mut Parser<'_>, colon_colon_required: bool) {
+ let m;
+ if p.at(T![::]) && p.nth(2) == T![<] {
+ m = p.start();
+ p.bump(T![::]);
+ p.bump(T![<]);
+ } else if !colon_colon_required && p.at(T![<]) && p.nth(1) != T![=] {
+ m = p.start();
+ p.bump(T![<]);
+ } else {
+ return;
+ }
+
+ while !p.at(EOF) && !p.at(T![>]) {
+ generic_arg(p);
+ if !p.at(T![>]) && !p.expect(T![,]) {
+ break;
+ }
+ }
+ p.expect(T![>]);
+ m.complete(p, GENERIC_ARG_LIST);
+}
+
+// test generic_arg
+// type T = S<i32>;
+fn generic_arg(p: &mut Parser<'_>) {
+ match p.current() {
+ LIFETIME_IDENT => lifetime_arg(p),
+ T!['{'] | T![true] | T![false] | T![-] => const_arg(p),
+ k if k.is_literal() => const_arg(p),
+ // test associated_type_bounds
+ // fn print_all<T: Iterator<Item, Item::Item, Item::<true>, Item: Display, Item<'a> = Item>>(printables: T) {}
+
+ // test macro_inside_generic_arg
+ // type A = Foo<syn::Token![_]>;
+ IDENT if [T![<], T![=], T![:]].contains(&p.nth(1)) && !p.nth_at(1, T![::]) => {
+ let m = p.start();
+ name_ref(p);
+ opt_generic_arg_list(p, false);
+ match p.current() {
+ T![=] => {
+ p.bump_any();
+ if types::TYPE_FIRST.contains(p.current()) {
+ // test assoc_type_eq
+ // type T = StreamingIterator<Item<'a> = &'a T>;
+ types::type_(p);
+ } else {
+ // test assoc_const_eq
+ // fn foo<F: Foo<N=3>>() {}
+ // const TEST: usize = 3;
+ // fn bar<F: Foo<N={TEST}>>() {}
+ const_arg(p);
+ }
+ m.complete(p, ASSOC_TYPE_ARG);
+ }
+ // test assoc_type_bound
+ // type T = StreamingIterator<Item<'a>: Clone>;
+ T![:] if !p.at(T![::]) => {
+ generic_params::bounds(p);
+ m.complete(p, ASSOC_TYPE_ARG);
+ }
+ _ => {
+ let m = m.complete(p, PATH_SEGMENT).precede(p).complete(p, PATH);
+ let m = paths::type_path_for_qualifier(p, m);
+ m.precede(p).complete(p, PATH_TYPE).precede(p).complete(p, TYPE_ARG);
+ }
+ }
+ }
+ _ => type_arg(p),
+ }
+}
+
+// test lifetime_arg
+// type T = S<'static>;
+fn lifetime_arg(p: &mut Parser<'_>) {
+ let m = p.start();
+ lifetime(p);
+ m.complete(p, LIFETIME_ARG);
+}
+
+pub(super) fn const_arg_expr(p: &mut Parser<'_>) {
+ // The tests in here are really for `const_arg`, which wraps the content
+ // CONST_ARG.
+ match p.current() {
+ // test const_arg_block
+ // type T = S<{90 + 2}>;
+ T!['{'] => {
+ expressions::block_expr(p);
+ }
+ // test const_arg_literal
+ // type T = S<"hello", 0xdeadbeef>;
+ k if k.is_literal() => {
+ expressions::literal(p);
+ }
+ // test const_arg_bool_literal
+ // type T = S<true>;
+ T![true] | T![false] => {
+ expressions::literal(p);
+ }
+ // test const_arg_negative_number
+ // type T = S<-92>;
+ T![-] => {
+ let lm = p.start();
+ p.bump(T![-]);
+ expressions::literal(p);
+ lm.complete(p, PREFIX_EXPR);
+ }
+ _ => {
+ // This shouldn't be hit by `const_arg`
+ let lm = p.start();
+ paths::use_path(p);
+ lm.complete(p, PATH_EXPR);
+ }
+ }
+}
+
+// test const_arg
+// type T = S<92>;
+pub(super) fn const_arg(p: &mut Parser<'_>) {
+ let m = p.start();
+ const_arg_expr(p);
+ m.complete(p, CONST_ARG);
+}
+
+fn type_arg(p: &mut Parser<'_>) {
+ let m = p.start();
+ types::type_(p);
+ m.complete(p, TYPE_ARG);
+}
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs
new file mode 100644
index 000000000..6db28ef13
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs
@@ -0,0 +1,242 @@
+use super::*;
+
+pub(super) fn opt_generic_param_list(p: &mut Parser<'_>) {
+ if p.at(T![<]) {
+ generic_param_list(p);
+ }
+}
+
+// test generic_param_list
+// fn f<T: Clone>() {}
+fn generic_param_list(p: &mut Parser<'_>) {
+ assert!(p.at(T![<]));
+ let m = p.start();
+ p.bump(T![<]);
+
+ while !p.at(EOF) && !p.at(T![>]) {
+ generic_param(p);
+ if !p.at(T![>]) && !p.expect(T![,]) {
+ break;
+ }
+ }
+ p.expect(T![>]);
+ m.complete(p, GENERIC_PARAM_LIST);
+}
+
+fn generic_param(p: &mut Parser<'_>) {
+ let m = p.start();
+ // test generic_param_attribute
+ // fn foo<#[lt_attr] 'a, #[t_attr] T>() {}
+ attributes::outer_attrs(p);
+ match p.current() {
+ LIFETIME_IDENT => lifetime_param(p, m),
+ IDENT => type_param(p, m),
+ T![const] => const_param(p, m),
+ _ => {
+ m.abandon(p);
+ p.err_and_bump("expected type parameter");
+ }
+ }
+}
+
+// test lifetime_param
+// fn f<'a: 'b>() {}
+fn lifetime_param(p: &mut Parser<'_>, m: Marker) {
+ assert!(p.at(LIFETIME_IDENT));
+ lifetime(p);
+ if p.at(T![:]) {
+ lifetime_bounds(p);
+ }
+ m.complete(p, LIFETIME_PARAM);
+}
+
+// test type_param
+// fn f<T: Clone>() {}
+fn type_param(p: &mut Parser<'_>, m: Marker) {
+ assert!(p.at(IDENT));
+ name(p);
+ if p.at(T![:]) {
+ bounds(p);
+ }
+ if p.at(T![=]) {
+ // test type_param_default
+ // struct S<T = i32>;
+ p.bump(T![=]);
+ types::type_(p);
+ }
+ m.complete(p, TYPE_PARAM);
+}
+
+// test const_param
+// struct S<const N: u32>;
+fn const_param(p: &mut Parser<'_>, m: Marker) {
+ p.bump(T![const]);
+ name(p);
+ if p.at(T![:]) {
+ types::ascription(p);
+ } else {
+ p.error("missing type for const parameter");
+ }
+
+ if p.at(T![=]) {
+ // test const_param_default_literal
+ // struct A<const N: i32 = -1>;
+ p.bump(T![=]);
+
+ // test const_param_default_expression
+ // struct A<const N: i32 = { 1 }>;
+
+ // test const_param_default_path
+ // struct A<const N: i32 = i32::MAX>;
+ generic_args::const_arg_expr(p);
+ }
+
+ m.complete(p, CONST_PARAM);
+}
+
+fn lifetime_bounds(p: &mut Parser<'_>) {
+ assert!(p.at(T![:]));
+ p.bump(T![:]);
+ while p.at(LIFETIME_IDENT) {
+ lifetime(p);
+ if !p.eat(T![+]) {
+ break;
+ }
+ }
+}
+
+// test type_param_bounds
+// struct S<T: 'a + ?Sized + (Copy) + ~const Drop>;
+pub(super) fn bounds(p: &mut Parser<'_>) {
+ assert!(p.at(T![:]));
+ p.bump(T![:]);
+ bounds_without_colon(p);
+}
+
+pub(super) fn bounds_without_colon(p: &mut Parser<'_>) {
+ let m = p.start();
+ bounds_without_colon_m(p, m);
+}
+
+pub(super) fn bounds_without_colon_m(p: &mut Parser<'_>, marker: Marker) -> CompletedMarker {
+ while type_bound(p) {
+ if !p.eat(T![+]) {
+ break;
+ }
+ }
+ marker.complete(p, TYPE_BOUND_LIST)
+}
+
+fn type_bound(p: &mut Parser<'_>) -> bool {
+ let m = p.start();
+ let has_paren = p.eat(T!['(']);
+ match p.current() {
+ LIFETIME_IDENT => lifetime(p),
+ T![for] => types::for_type(p, false),
+ T![?] if p.nth_at(1, T![for]) => {
+ // test question_for_type_trait_bound
+ // fn f<T>() where T: ?for<> Sized {}
+ p.bump_any();
+ types::for_type(p, false)
+ }
+ current => {
+ match current {
+ T![?] => p.bump_any(),
+ T![~] => {
+ p.bump_any();
+ p.expect(T![const]);
+ }
+ _ => (),
+ }
+ if paths::is_use_path_start(p) {
+ types::path_type_(p, false);
+ } else {
+ m.abandon(p);
+ return false;
+ }
+ }
+ }
+ if has_paren {
+ p.expect(T![')']);
+ }
+ m.complete(p, TYPE_BOUND);
+
+ true
+}
+
+// test where_clause
+// fn foo()
+// where
+// 'a: 'b + 'c,
+// T: Clone + Copy + 'static,
+// Iterator::Item: 'a,
+// <T as Iterator>::Item: 'a
+// {}
+pub(super) fn opt_where_clause(p: &mut Parser<'_>) {
+ if !p.at(T![where]) {
+ return;
+ }
+ let m = p.start();
+ p.bump(T![where]);
+
+ while is_where_predicate(p) {
+ where_predicate(p);
+
+ let comma = p.eat(T![,]);
+
+ match p.current() {
+ T!['{'] | T![;] | T![=] => break,
+ _ => (),
+ }
+
+ if !comma {
+ p.error("expected comma");
+ }
+ }
+
+ m.complete(p, WHERE_CLAUSE);
+
+ fn is_where_predicate(p: &mut Parser<'_>) -> bool {
+ match p.current() {
+ LIFETIME_IDENT => true,
+ T![impl] => false,
+ token => types::TYPE_FIRST.contains(token),
+ }
+ }
+}
+
+fn where_predicate(p: &mut Parser<'_>) {
+ let m = p.start();
+ match p.current() {
+ LIFETIME_IDENT => {
+ lifetime(p);
+ if p.at(T![:]) {
+ bounds(p);
+ } else {
+ p.error("expected colon");
+ }
+ }
+ T![impl] => {
+ p.error("expected lifetime or type");
+ }
+ _ => {
+ if p.at(T![for]) {
+ // test where_pred_for
+ // fn for_trait<F>()
+ // where
+ // for<'a> F: Fn(&'a str)
+ // { }
+ types::for_binder(p);
+ }
+
+ types::type_(p);
+
+ if p.at(T![:]) {
+ bounds(p);
+ } else {
+ p.error("expected colon");
+ }
+ }
+ }
+ m.complete(p, WHERE_PRED);
+}
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs
new file mode 100644
index 000000000..5e0951bf8
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs
@@ -0,0 +1,465 @@
+mod consts;
+mod adt;
+mod traits;
+mod use_item;
+
+pub(crate) use self::{
+ adt::{record_field_list, variant_list},
+ expressions::{match_arm_list, record_expr_field_list},
+ traits::assoc_item_list,
+ use_item::use_tree_list,
+};
+use super::*;
+
+// test mod_contents
+// fn foo() {}
+// macro_rules! foo {}
+// foo::bar!();
+// super::baz! {}
+// struct S;
+pub(super) fn mod_contents(p: &mut Parser<'_>, stop_on_r_curly: bool) {
+ attributes::inner_attrs(p);
+ while !p.at(EOF) && !(p.at(T!['}']) && stop_on_r_curly) {
+ item_or_macro(p, stop_on_r_curly);
+ }
+}
+
+pub(super) const ITEM_RECOVERY_SET: TokenSet = TokenSet::new(&[
+ T![fn],
+ T![struct],
+ T![enum],
+ T![impl],
+ T![trait],
+ T![const],
+ T![static],
+ T![let],
+ T![mod],
+ T![pub],
+ T![crate],
+ T![use],
+ T![macro],
+ T![;],
+]);
+
+pub(super) fn item_or_macro(p: &mut Parser<'_>, stop_on_r_curly: bool) {
+ let m = p.start();
+ attributes::outer_attrs(p);
+
+ let m = match opt_item(p, m) {
+ Ok(()) => {
+ if p.at(T![;]) {
+ p.err_and_bump(
+ "expected item, found `;`\n\
+ consider removing this semicolon",
+ );
+ }
+ return;
+ }
+ Err(m) => m,
+ };
+
+ if paths::is_use_path_start(p) {
+ match macro_call(p) {
+ BlockLike::Block => (),
+ BlockLike::NotBlock => {
+ p.expect(T![;]);
+ }
+ }
+ m.complete(p, MACRO_CALL);
+ return;
+ }
+
+ m.abandon(p);
+ match p.current() {
+ T!['{'] => error_block(p, "expected an item"),
+ T!['}'] if !stop_on_r_curly => {
+ let e = p.start();
+ p.error("unmatched `}`");
+ p.bump(T!['}']);
+ e.complete(p, ERROR);
+ }
+ EOF | T!['}'] => p.error("expected an item"),
+ _ => p.err_and_bump("expected an item"),
+ }
+}
+
+/// Try to parse an item, completing `m` in case of success.
+pub(super) fn opt_item(p: &mut Parser<'_>, m: Marker) -> Result<(), Marker> {
+ // test_err pub_expr
+ // fn foo() { pub 92; }
+ let has_visibility = opt_visibility(p, false);
+
+ let m = match opt_item_without_modifiers(p, m) {
+ Ok(()) => return Ok(()),
+ Err(m) => m,
+ };
+
+ let mut has_mods = false;
+ let mut has_extern = false;
+
+ // modifiers
+ if p.at(T![const]) && p.nth(1) != T!['{'] {
+ p.eat(T![const]);
+ has_mods = true;
+ }
+
+ // test_err async_without_semicolon
+ // fn foo() { let _ = async {} }
+ if p.at(T![async]) && !matches!(p.nth(1), T!['{'] | T![move] | T![|]) {
+ p.eat(T![async]);
+ has_mods = true;
+ }
+
+ // test_err unsafe_block_in_mod
+ // fn foo(){} unsafe { } fn bar(){}
+ if p.at(T![unsafe]) && p.nth(1) != T!['{'] {
+ p.eat(T![unsafe]);
+ has_mods = true;
+ }
+
+ if p.at(T![extern]) {
+ has_extern = true;
+ has_mods = true;
+ abi(p);
+ }
+ if p.at_contextual_kw(T![auto]) && p.nth(1) == T![trait] {
+ p.bump_remap(T![auto]);
+ has_mods = true;
+ }
+
+ // test default_item
+ // default impl T for Foo {}
+ if p.at_contextual_kw(T![default]) {
+ match p.nth(1) {
+ T![fn] | T![type] | T![const] | T![impl] => {
+ p.bump_remap(T![default]);
+ has_mods = true;
+ }
+ // test default_unsafe_item
+ // default unsafe impl T for Foo {
+ // default unsafe fn foo() {}
+ // }
+ T![unsafe] if matches!(p.nth(2), T![impl] | T![fn]) => {
+ p.bump_remap(T![default]);
+ p.bump(T![unsafe]);
+ has_mods = true;
+ }
+ // test default_async_fn
+ // impl T for Foo {
+ // default async fn foo() {}
+ // }
+ T![async] => {
+ let mut maybe_fn = p.nth(2);
+ let is_unsafe = if matches!(maybe_fn, T![unsafe]) {
+ // test default_async_unsafe_fn
+ // impl T for Foo {
+ // default async unsafe fn foo() {}
+ // }
+ maybe_fn = p.nth(3);
+ true
+ } else {
+ false
+ };
+
+ if matches!(maybe_fn, T![fn]) {
+ p.bump_remap(T![default]);
+ p.bump(T![async]);
+ if is_unsafe {
+ p.bump(T![unsafe]);
+ }
+ has_mods = true;
+ }
+ }
+ _ => (),
+ }
+ }
+
+ // test existential_type
+ // existential type Foo: Fn() -> usize;
+ if p.at_contextual_kw(T![existential]) && p.nth(1) == T![type] {
+ p.bump_remap(T![existential]);
+ has_mods = true;
+ }
+
+ // items
+ match p.current() {
+ T![fn] => fn_(p, m),
+
+ T![const] if p.nth(1) != T!['{'] => consts::konst(p, m),
+
+ T![trait] => traits::trait_(p, m),
+ T![impl] => traits::impl_(p, m),
+
+ T![type] => type_alias(p, m),
+
+ // test extern_block
+ // unsafe extern "C" {}
+ // extern {}
+ T!['{'] if has_extern => {
+ extern_item_list(p);
+ m.complete(p, EXTERN_BLOCK);
+ }
+
+ _ if has_visibility || has_mods => {
+ if has_mods {
+ p.error("expected existential, fn, trait or impl");
+ } else {
+ p.error("expected an item");
+ }
+ m.complete(p, ERROR);
+ }
+
+ _ => return Err(m),
+ }
+ Ok(())
+}
+
+fn opt_item_without_modifiers(p: &mut Parser<'_>, m: Marker) -> Result<(), Marker> {
+ let la = p.nth(1);
+ match p.current() {
+ T![extern] if la == T![crate] => extern_crate(p, m),
+ T![use] => use_item::use_(p, m),
+ T![mod] => mod_item(p, m),
+
+ T![type] => type_alias(p, m),
+ T![struct] => adt::strukt(p, m),
+ T![enum] => adt::enum_(p, m),
+ IDENT if p.at_contextual_kw(T![union]) && p.nth(1) == IDENT => adt::union(p, m),
+
+ T![macro] => macro_def(p, m),
+ IDENT if p.at_contextual_kw(T![macro_rules]) && p.nth(1) == BANG => macro_rules(p, m),
+
+ T![const] if (la == IDENT || la == T![_] || la == T![mut]) => consts::konst(p, m),
+ T![static] if (la == IDENT || la == T![_] || la == T![mut]) => consts::static_(p, m),
+
+ _ => return Err(m),
+ };
+ Ok(())
+}
+
+// test extern_crate
+// extern crate foo;
+fn extern_crate(p: &mut Parser<'_>, m: Marker) {
+ p.bump(T![extern]);
+ p.bump(T![crate]);
+
+ if p.at(T![self]) {
+ // test extern_crate_self
+ // extern crate self;
+ let m = p.start();
+ p.bump(T![self]);
+ m.complete(p, NAME_REF);
+ } else {
+ name_ref(p);
+ }
+
+ // test extern_crate_rename
+ // extern crate foo as bar;
+ opt_rename(p);
+ p.expect(T![;]);
+ m.complete(p, EXTERN_CRATE);
+}
+
+// test mod_item
+// mod a;
+pub(crate) fn mod_item(p: &mut Parser<'_>, m: Marker) {
+ p.bump(T![mod]);
+ name(p);
+ if p.at(T!['{']) {
+ // test mod_item_curly
+ // mod b { }
+ item_list(p);
+ } else if !p.eat(T![;]) {
+ p.error("expected `;` or `{`");
+ }
+ m.complete(p, MODULE);
+}
+
+// test type_alias
+// type Foo = Bar;
+fn type_alias(p: &mut Parser<'_>, m: Marker) {
+ p.bump(T![type]);
+
+ name(p);
+
+ // test type_item_type_params
+ // type Result<T> = ();
+ generic_params::opt_generic_param_list(p);
+
+ if p.at(T![:]) {
+ generic_params::bounds(p);
+ }
+
+ // test type_item_where_clause_deprecated
+ // type Foo where Foo: Copy = ();
+ generic_params::opt_where_clause(p);
+ if p.eat(T![=]) {
+ types::type_(p);
+ }
+
+ // test type_item_where_clause
+ // type Foo = () where Foo: Copy;
+ generic_params::opt_where_clause(p);
+
+ p.expect(T![;]);
+ m.complete(p, TYPE_ALIAS);
+}
+
+pub(crate) fn item_list(p: &mut Parser<'_>) {
+ assert!(p.at(T!['{']));
+ let m = p.start();
+ p.bump(T!['{']);
+ mod_contents(p, true);
+ p.expect(T!['}']);
+ m.complete(p, ITEM_LIST);
+}
+
+pub(crate) fn extern_item_list(p: &mut Parser<'_>) {
+ assert!(p.at(T!['{']));
+ let m = p.start();
+ p.bump(T!['{']);
+ mod_contents(p, true);
+ p.expect(T!['}']);
+ m.complete(p, EXTERN_ITEM_LIST);
+}
+
+fn macro_rules(p: &mut Parser<'_>, m: Marker) {
+ assert!(p.at_contextual_kw(T![macro_rules]));
+ p.bump_remap(T![macro_rules]);
+ p.expect(T![!]);
+
+ if p.at(IDENT) {
+ name(p);
+ }
+ // Special-case `macro_rules! try`.
+ // This is a hack until we do proper edition support
+
+ // test try_macro_rules
+ // macro_rules! try { () => {} }
+ if p.at(T![try]) {
+ let m = p.start();
+ p.bump_remap(IDENT);
+ m.complete(p, NAME);
+ }
+
+ match p.current() {
+ // test macro_rules_non_brace
+ // macro_rules! m ( ($i:ident) => {} );
+ // macro_rules! m [ ($i:ident) => {} ];
+ T!['['] | T!['('] => {
+ token_tree(p);
+ p.expect(T![;]);
+ }
+ T!['{'] => token_tree(p),
+ _ => p.error("expected `{`, `[`, `(`"),
+ }
+ m.complete(p, MACRO_RULES);
+}
+
+// test macro_def
+// macro m($i:ident) {}
+fn macro_def(p: &mut Parser<'_>, m: Marker) {
+ p.expect(T![macro]);
+ name_r(p, ITEM_RECOVERY_SET);
+ if p.at(T!['{']) {
+ // test macro_def_curly
+ // macro m { ($i:ident) => {} }
+ token_tree(p);
+ } else if p.at(T!['(']) {
+ let m = p.start();
+ token_tree(p);
+ match p.current() {
+ T!['{'] | T!['['] | T!['('] => token_tree(p),
+ _ => p.error("expected `{`, `[`, `(`"),
+ }
+ m.complete(p, TOKEN_TREE);
+ } else {
+ p.error("unmatched `(`");
+ }
+
+ m.complete(p, MACRO_DEF);
+}
+
+// test fn
+// fn foo() {}
+fn fn_(p: &mut Parser<'_>, m: Marker) {
+ p.bump(T![fn]);
+
+ name_r(p, ITEM_RECOVERY_SET);
+ // test function_type_params
+ // fn foo<T: Clone + Copy>(){}
+ generic_params::opt_generic_param_list(p);
+
+ if p.at(T!['(']) {
+ params::param_list_fn_def(p);
+ } else {
+ p.error("expected function arguments");
+ }
+ // test function_ret_type
+ // fn foo() {}
+ // fn bar() -> () {}
+ opt_ret_type(p);
+
+ // test function_where_clause
+ // fn foo<T>() where T: Copy {}
+ generic_params::opt_where_clause(p);
+
+ if p.at(T![;]) {
+ // test fn_decl
+ // trait T { fn foo(); }
+ p.bump(T![;]);
+ } else {
+ expressions::block_expr(p);
+ }
+ m.complete(p, FN);
+}
+
+fn macro_call(p: &mut Parser<'_>) -> BlockLike {
+ assert!(paths::is_use_path_start(p));
+ paths::use_path(p);
+ macro_call_after_excl(p)
+}
+
+pub(super) fn macro_call_after_excl(p: &mut Parser<'_>) -> BlockLike {
+ p.expect(T![!]);
+
+ match p.current() {
+ T!['{'] => {
+ token_tree(p);
+ BlockLike::Block
+ }
+ T!['('] | T!['['] => {
+ token_tree(p);
+ BlockLike::NotBlock
+ }
+ _ => {
+ p.error("expected `{`, `[`, `(`");
+ BlockLike::NotBlock
+ }
+ }
+}
+
+pub(crate) fn token_tree(p: &mut Parser<'_>) {
+ let closing_paren_kind = match p.current() {
+ T!['{'] => T!['}'],
+ T!['('] => T![')'],
+ T!['['] => T![']'],
+ _ => unreachable!(),
+ };
+ let m = p.start();
+ p.bump_any();
+ while !p.at(EOF) && !p.at(closing_paren_kind) {
+ match p.current() {
+ T!['{'] | T!['('] | T!['['] => token_tree(p),
+ T!['}'] => {
+ p.error("unmatched `}`");
+ m.complete(p, TOKEN_TREE);
+ return;
+ }
+ T![')'] | T![']'] => p.err_and_bump("unmatched brace"),
+ _ => p.bump_any(),
+ }
+ }
+ p.expect(closing_paren_kind);
+ m.complete(p, TOKEN_TREE);
+}
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/items/adt.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/items/adt.rs
new file mode 100644
index 000000000..e7d30516b
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/items/adt.rs
@@ -0,0 +1,168 @@
+use super::*;
+
+// test struct_item
+// struct S {}
+pub(super) fn strukt(p: &mut Parser<'_>, m: Marker) {
+ p.bump(T![struct]);
+ struct_or_union(p, m, true);
+}
+
+// test union_item
+// struct U { i: i32, f: f32 }
+pub(super) fn union(p: &mut Parser<'_>, m: Marker) {
+ assert!(p.at_contextual_kw(T![union]));
+ p.bump_remap(T![union]);
+ struct_or_union(p, m, false);
+}
+
+fn struct_or_union(p: &mut Parser<'_>, m: Marker, is_struct: bool) {
+ name_r(p, ITEM_RECOVERY_SET);
+ generic_params::opt_generic_param_list(p);
+ match p.current() {
+ T![where] => {
+ generic_params::opt_where_clause(p);
+ match p.current() {
+ T![;] => p.bump(T![;]),
+ T!['{'] => record_field_list(p),
+ _ => {
+ //FIXME: special case `(` error message
+ p.error("expected `;` or `{`");
+ }
+ }
+ }
+ T!['{'] => record_field_list(p),
+ // test unit_struct
+ // struct S;
+ T![;] if is_struct => {
+ p.bump(T![;]);
+ }
+ // test tuple_struct
+ // struct S(String, usize);
+ T!['('] if is_struct => {
+ tuple_field_list(p);
+ // test tuple_struct_where
+ // struct S<T>(T) where T: Clone;
+ generic_params::opt_where_clause(p);
+ p.expect(T![;]);
+ }
+ _ => p.error(if is_struct { "expected `;`, `{`, or `(`" } else { "expected `{`" }),
+ }
+ m.complete(p, if is_struct { STRUCT } else { UNION });
+}
+
+pub(super) fn enum_(p: &mut Parser<'_>, m: Marker) {
+ p.bump(T![enum]);
+ name_r(p, ITEM_RECOVERY_SET);
+ generic_params::opt_generic_param_list(p);
+ generic_params::opt_where_clause(p);
+ if p.at(T!['{']) {
+ variant_list(p);
+ } else {
+ p.error("expected `{`");
+ }
+ m.complete(p, ENUM);
+}
+
+pub(crate) fn variant_list(p: &mut Parser<'_>) {
+ assert!(p.at(T!['{']));
+ let m = p.start();
+ p.bump(T!['{']);
+ while !p.at(EOF) && !p.at(T!['}']) {
+ if p.at(T!['{']) {
+ error_block(p, "expected enum variant");
+ continue;
+ }
+ variant(p);
+ if !p.at(T!['}']) {
+ p.expect(T![,]);
+ }
+ }
+ p.expect(T!['}']);
+ m.complete(p, VARIANT_LIST);
+
+ fn variant(p: &mut Parser<'_>) {
+ let m = p.start();
+ attributes::outer_attrs(p);
+ if p.at(IDENT) {
+ name(p);
+ match p.current() {
+ T!['{'] => record_field_list(p),
+ T!['('] => tuple_field_list(p),
+ _ => (),
+ }
+
+ // test variant_discriminant
+ // enum E { X(i32) = 10 }
+ if p.eat(T![=]) {
+ expressions::expr(p);
+ }
+ m.complete(p, VARIANT);
+ } else {
+ m.abandon(p);
+ p.err_and_bump("expected enum variant");
+ }
+ }
+}
+
+// test record_field_list
+// struct S { a: i32, b: f32 }
+pub(crate) fn record_field_list(p: &mut Parser<'_>) {
+ assert!(p.at(T!['{']));
+ let m = p.start();
+ p.bump(T!['{']);
+ while !p.at(T!['}']) && !p.at(EOF) {
+ if p.at(T!['{']) {
+ error_block(p, "expected field");
+ continue;
+ }
+ record_field(p);
+ if !p.at(T!['}']) {
+ p.expect(T![,]);
+ }
+ }
+ p.expect(T!['}']);
+ m.complete(p, RECORD_FIELD_LIST);
+
+ fn record_field(p: &mut Parser<'_>) {
+ let m = p.start();
+ // test record_field_attrs
+ // struct S { #[attr] f: f32 }
+ attributes::outer_attrs(p);
+ opt_visibility(p, false);
+ if p.at(IDENT) {
+ name(p);
+ p.expect(T![:]);
+ types::type_(p);
+ m.complete(p, RECORD_FIELD);
+ } else {
+ m.abandon(p);
+ p.err_and_bump("expected field declaration");
+ }
+ }
+}
+
+fn tuple_field_list(p: &mut Parser<'_>) {
+ assert!(p.at(T!['(']));
+ let m = p.start();
+ p.bump(T!['(']);
+ while !p.at(T![')']) && !p.at(EOF) {
+ let m = p.start();
+ // test tuple_field_attrs
+ // struct S (#[attr] f32);
+ attributes::outer_attrs(p);
+ opt_visibility(p, true);
+ if !p.at_ts(types::TYPE_FIRST) {
+ p.error("expected a type");
+ m.complete(p, ERROR);
+ break;
+ }
+ types::type_(p);
+ m.complete(p, TUPLE_FIELD);
+
+ if !p.at(T![')']) {
+ p.expect(T![,]);
+ }
+ }
+ p.expect(T![')']);
+ m.complete(p, TUPLE_FIELD_LIST);
+}
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/items/consts.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/items/consts.rs
new file mode 100644
index 000000000..9549ec9b4
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/items/consts.rs
@@ -0,0 +1,37 @@
+use super::*;
+
+// test const_item
+// const C: u32 = 92;
+pub(super) fn konst(p: &mut Parser<'_>, m: Marker) {
+ p.bump(T![const]);
+ const_or_static(p, m, true);
+}
+
+pub(super) fn static_(p: &mut Parser<'_>, m: Marker) {
+ p.bump(T![static]);
+ const_or_static(p, m, false);
+}
+
+fn const_or_static(p: &mut Parser<'_>, m: Marker, is_const: bool) {
+ p.eat(T![mut]);
+
+ if is_const && p.eat(T![_]) {
+ // test anonymous_const
+ // const _: u32 = 0;
+ } else {
+ // test_err anonymous_static
+ // static _: i32 = 5;
+ name(p);
+ }
+
+ if p.at(T![:]) {
+ types::ascription(p);
+ } else {
+ p.error("missing type for `const` or `static`");
+ }
+ if p.eat(T![=]) {
+ expressions::expr(p);
+ }
+ p.expect(T![;]);
+ m.complete(p, if is_const { CONST } else { STATIC });
+}
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/items/traits.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/items/traits.rs
new file mode 100644
index 000000000..c982e2d56
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/items/traits.rs
@@ -0,0 +1,140 @@
+use super::*;
+
+// test trait_item
+// trait T { fn new() -> Self; }
+pub(super) fn trait_(p: &mut Parser<'_>, m: Marker) {
+ p.bump(T![trait]);
+ name_r(p, ITEM_RECOVERY_SET);
+
+ // test trait_item_generic_params
+ // trait X<U: Debug + Display> {}
+ generic_params::opt_generic_param_list(p);
+
+ if p.eat(T![=]) {
+ // test trait_alias
+ // trait Z<U> = T<U>;
+ generic_params::bounds_without_colon(p);
+
+ // test trait_alias_where_clause
+ // trait Z<U> = T<U> where U: Copy;
+ // trait Z<U> = where Self: T<U>;
+ generic_params::opt_where_clause(p);
+ p.expect(T![;]);
+ m.complete(p, TRAIT);
+ return;
+ }
+
+ if p.at(T![:]) {
+ // test trait_item_bounds
+ // trait T: Hash + Clone {}
+ generic_params::bounds(p);
+ }
+
+ // test trait_item_where_clause
+ // trait T where Self: Copy {}
+ generic_params::opt_where_clause(p);
+
+ if p.at(T!['{']) {
+ assoc_item_list(p);
+ } else {
+ p.error("expected `{`");
+ }
+ m.complete(p, TRAIT);
+}
+
+// test impl_item
+// impl S {}
+pub(super) fn impl_(p: &mut Parser<'_>, m: Marker) {
+ p.bump(T![impl]);
+ if p.at(T![<]) && not_a_qualified_path(p) {
+ generic_params::opt_generic_param_list(p);
+ }
+
+ // test impl_item_const
+ // impl const Send for S {}
+ p.eat(T![const]);
+
+ // FIXME: never type
+ // impl ! {}
+
+ // test impl_item_neg
+ // impl !Send for S {}
+ p.eat(T![!]);
+ impl_type(p);
+ if p.eat(T![for]) {
+ impl_type(p);
+ }
+ generic_params::opt_where_clause(p);
+ if p.at(T!['{']) {
+ assoc_item_list(p);
+ } else {
+ p.error("expected `{`");
+ }
+ m.complete(p, IMPL);
+}
+
+// test assoc_item_list
+// impl F {
+// type A = i32;
+// const B: i32 = 92;
+// fn foo() {}
+// fn bar(&self) {}
+// }
+pub(crate) fn assoc_item_list(p: &mut Parser<'_>) {
+ assert!(p.at(T!['{']));
+
+ let m = p.start();
+ p.bump(T!['{']);
+ // test assoc_item_list_inner_attrs
+ // impl S { #![attr] }
+ attributes::inner_attrs(p);
+
+ while !p.at(EOF) && !p.at(T!['}']) {
+ if p.at(T!['{']) {
+ error_block(p, "expected an item");
+ continue;
+ }
+ item_or_macro(p, true);
+ }
+ p.expect(T!['}']);
+ m.complete(p, ASSOC_ITEM_LIST);
+}
+
+// test impl_type_params
+// impl<const N: u32> Bar<N> {}
+fn not_a_qualified_path(p: &Parser<'_>) -> bool {
+ // There's an ambiguity between generic parameters and qualified paths in impls.
+ // If we see `<` it may start both, so we have to inspect some following tokens.
+ // The following combinations can only start generics,
+ // but not qualified paths (with one exception):
+ // `<` `>` - empty generic parameters
+ // `<` `#` - generic parameters with attributes
+ // `<` `const` - const generic parameters
+ // `<` (LIFETIME_IDENT|IDENT) `>` - single generic parameter
+ // `<` (LIFETIME_IDENT|IDENT) `,` - first generic parameter in a list
+ // `<` (LIFETIME_IDENT|IDENT) `:` - generic parameter with bounds
+ // `<` (LIFETIME_IDENT|IDENT) `=` - generic parameter with a default
+ // The only truly ambiguous case is
+ // `<` IDENT `>` `::` IDENT ...
+ // we disambiguate it in favor of generics (`impl<T> ::absolute::Path<T> { ... }`)
+ // because this is what almost always expected in practice, qualified paths in impls
+ // (`impl <Type>::AssocTy { ... }`) aren't even allowed by type checker at the moment.
+ if p.nth(1) == T![#] || p.nth(1) == T![>] || p.nth(1) == T![const] {
+ return true;
+ }
+ (p.nth(1) == LIFETIME_IDENT || p.nth(1) == IDENT)
+ && (p.nth(2) == T![>] || p.nth(2) == T![,] || p.nth(2) == T![:] || p.nth(2) == T![=])
+}
+
+// test_err impl_type
+// impl Type {}
+// impl Trait1 for T {}
+// impl impl NotType {}
+// impl Trait2 for impl NotType {}
+pub(crate) fn impl_type(p: &mut Parser<'_>) {
+ if p.at(T![impl]) {
+ p.error("expected trait or type");
+ return;
+ }
+ types::type_(p);
+}
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/items/use_item.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/items/use_item.rs
new file mode 100644
index 000000000..69880b794
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/items/use_item.rs
@@ -0,0 +1,93 @@
+use super::*;
+
+// test use_item
+// use std::collections;
+pub(super) fn use_(p: &mut Parser<'_>, m: Marker) {
+ p.bump(T![use]);
+ use_tree(p, true);
+ p.expect(T![;]);
+ m.complete(p, USE);
+}
+
+// test use_tree
+// use outer::tree::{inner::tree};
+fn use_tree(p: &mut Parser<'_>, top_level: bool) {
+ let m = p.start();
+ match p.current() {
+ // test use_tree_star
+ // use *;
+ // use std::{*};
+ T![*] => p.bump(T![*]),
+ // test use_tree_abs_star
+ // use ::*;
+ // use std::{::*};
+ T![:] if p.at(T![::]) && p.nth(2) == T![*] => {
+ p.bump(T![::]);
+ p.bump(T![*]);
+ }
+ T!['{'] => use_tree_list(p),
+ T![:] if p.at(T![::]) && p.nth(2) == T!['{'] => {
+ p.bump(T![::]);
+ use_tree_list(p);
+ }
+
+ // test use_tree_path
+ // use ::std;
+ // use std::collections;
+ //
+ // use self::m;
+ // use super::m;
+ // use crate::m;
+ _ if paths::is_use_path_start(p) => {
+ paths::use_path(p);
+ match p.current() {
+ // test use_tree_alias
+ // use std as stdlib;
+ // use Trait as _;
+ T![as] => opt_rename(p),
+ T![:] if p.at(T![::]) => {
+ p.bump(T![::]);
+ match p.current() {
+ // test use_tree_path_star
+ // use std::*;
+ T![*] => p.bump(T![*]),
+ // test use_tree_path_use_tree
+ // use std::{collections};
+ T!['{'] => use_tree_list(p),
+ _ => p.error("expected `{` or `*`"),
+ }
+ }
+ _ => (),
+ }
+ }
+ _ => {
+ m.abandon(p);
+ 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;
+ }
+ }
+ m.complete(p, USE_TREE);
+}
+
+// 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!['}']);
+ m.complete(p, USE_TREE_LIST);
+}
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/params.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/params.rs
new file mode 100644
index 000000000..20e8e95f0
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/params.rs
@@ -0,0 +1,209 @@
+use super::*;
+
+// test param_list
+// fn a() {}
+// fn b(x: i32) {}
+// fn c(x: i32, ) {}
+// fn d(x: i32, y: ()) {}
+pub(super) fn param_list_fn_def(p: &mut Parser<'_>) {
+ list_(p, Flavor::FnDef);
+}
+
+// test param_list_opt_patterns
+// fn foo<F: FnMut(&mut Foo<'a>)>(){}
+pub(super) fn param_list_fn_trait(p: &mut Parser<'_>) {
+ list_(p, Flavor::FnTrait);
+}
+
+pub(super) fn param_list_fn_ptr(p: &mut Parser<'_>) {
+ list_(p, Flavor::FnPointer);
+}
+
+pub(super) fn param_list_closure(p: &mut Parser<'_>) {
+ list_(p, Flavor::Closure);
+}
+
+#[derive(Debug, Clone, Copy)]
+enum Flavor {
+ FnDef, // Includes trait fn params; omitted param idents are not supported
+ FnTrait, // Params for `Fn(...)`/`FnMut(...)`/`FnOnce(...)` annotations
+ FnPointer,
+ Closure,
+}
+
+fn list_(p: &mut Parser<'_>, flavor: Flavor) {
+ use Flavor::*;
+
+ let (bra, ket) = match flavor {
+ Closure => (T![|], T![|]),
+ FnDef | FnTrait | FnPointer => (T!['('], T![')']),
+ };
+
+ let list_marker = p.start();
+ p.bump(bra);
+
+ let mut param_marker = None;
+ if let FnDef = flavor {
+ // test self_param_outer_attr
+ // fn f(#[must_use] self) {}
+ let m = p.start();
+ attributes::outer_attrs(p);
+ match opt_self_param(p, m) {
+ Ok(()) => {}
+ Err(m) => param_marker = Some(m),
+ }
+ }
+
+ while !p.at(EOF) && !p.at(ket) {
+ // test param_outer_arg
+ // fn f(#[attr1] pat: Type) {}
+ let m = match param_marker.take() {
+ Some(m) => m,
+ None => {
+ let m = p.start();
+ attributes::outer_attrs(p);
+ m
+ }
+ };
+
+ if !p.at_ts(PARAM_FIRST) {
+ p.error("expected value parameter");
+ m.abandon(p);
+ break;
+ }
+ param(p, m, flavor);
+ if !p.at(ket) {
+ p.expect(T![,]);
+ }
+ }
+
+ if let Some(m) = param_marker {
+ m.abandon(p);
+ }
+
+ p.expect(ket);
+ list_marker.complete(p, PARAM_LIST);
+}
+
+const PARAM_FIRST: TokenSet = patterns::PATTERN_FIRST.union(types::TYPE_FIRST);
+
+fn param(p: &mut Parser<'_>, m: Marker, flavor: Flavor) {
+ match flavor {
+ // test param_list_vararg
+ // extern "C" { fn printf(format: *const i8, ..., _: u8) -> i32; }
+ Flavor::FnDef | Flavor::FnPointer if p.eat(T![...]) => {}
+
+ // test fn_def_param
+ // fn foo(..., (x, y): (i32, i32)) {}
+ Flavor::FnDef => {
+ patterns::pattern(p);
+ if !variadic_param(p) {
+ if p.at(T![:]) {
+ types::ascription(p);
+ } else {
+ // test_err missing_fn_param_type
+ // fn f(x y: i32, z, t: i32) {}
+ p.error("missing type for function parameter");
+ }
+ }
+ }
+ // test value_parameters_no_patterns
+ // type F = Box<Fn(i32, &i32, &i32, ())>;
+ Flavor::FnTrait => {
+ types::type_(p);
+ }
+ // test fn_pointer_param_ident_path
+ // type Foo = fn(Bar::Baz);
+ // type Qux = fn(baz: Bar::Baz);
+
+ // test fn_pointer_unnamed_arg
+ // type Foo = fn(_: bar);
+ Flavor::FnPointer => {
+ if (p.at(IDENT) || p.at(UNDERSCORE)) && p.nth(1) == T![:] && !p.nth_at(1, T![::]) {
+ patterns::pattern_single(p);
+ if !variadic_param(p) {
+ if p.at(T![:]) {
+ types::ascription(p);
+ } else {
+ p.error("missing type for function parameter");
+ }
+ }
+ } else {
+ types::type_(p);
+ }
+ }
+ // test closure_params
+ // fn main() {
+ // let foo = |bar, baz: Baz, qux: Qux::Quux| ();
+ // }
+ Flavor::Closure => {
+ patterns::pattern_single(p);
+ if p.at(T![:]) && !p.at(T![::]) {
+ types::ascription(p);
+ }
+ }
+ }
+ m.complete(p, PARAM);
+}
+
+fn variadic_param(p: &mut Parser<'_>) -> bool {
+ if p.at(T![:]) && p.nth_at(1, T![...]) {
+ p.bump(T![:]);
+ p.bump(T![...]);
+ true
+ } else {
+ false
+ }
+}
+
+// test self_param
+// impl S {
+// fn a(self) {}
+// fn b(&self,) {}
+// fn c(&'a self,) {}
+// fn d(&'a mut self, x: i32) {}
+// fn e(mut self) {}
+// }
+fn opt_self_param(p: &mut Parser<'_>, m: Marker) -> Result<(), Marker> {
+ if p.at(T![self]) || p.at(T![mut]) && p.nth(1) == T![self] {
+ p.eat(T![mut]);
+ self_as_name(p);
+ // test arb_self_types
+ // impl S {
+ // fn a(self: &Self) {}
+ // fn b(mut self: Box<Self>) {}
+ // }
+ if p.at(T![:]) {
+ types::ascription(p);
+ }
+ } else {
+ let la1 = p.nth(1);
+ let la2 = p.nth(2);
+ let la3 = p.nth(3);
+ if !matches!(
+ (p.current(), la1, la2, la3),
+ (T![&], T![self], _, _)
+ | (T![&], T![mut] | LIFETIME_IDENT, T![self], _)
+ | (T![&], LIFETIME_IDENT, T![mut], T![self])
+ ) {
+ return Err(m);
+ }
+ p.bump(T![&]);
+ if p.at(LIFETIME_IDENT) {
+ lifetime(p);
+ }
+ p.eat(T![mut]);
+ self_as_name(p);
+ }
+ m.complete(p, SELF_PARAM);
+ if !p.at(T![')']) {
+ p.expect(T![,]);
+ }
+ Ok(())
+}
+
+fn self_as_name(p: &mut Parser<'_>) {
+ let m = p.start();
+ p.bump(T![self]);
+ m.complete(p, NAME);
+}
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs
new file mode 100644
index 000000000..8de5d33a1
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs
@@ -0,0 +1,132 @@
+use super::*;
+
+pub(super) const PATH_FIRST: TokenSet =
+ TokenSet::new(&[IDENT, T![self], T![super], T![crate], T![Self], T![:], T![<]]);
+
+pub(super) fn is_path_start(p: &Parser<'_>) -> bool {
+ is_use_path_start(p) || p.at(T![<]) || p.at(T![Self])
+}
+
+pub(super) fn is_use_path_start(p: &Parser<'_>) -> bool {
+ match p.current() {
+ IDENT | T![self] | T![super] | T![crate] => true,
+ T![:] if p.at(T![::]) => true,
+ _ => false,
+ }
+}
+
+pub(super) fn use_path(p: &mut Parser<'_>) {
+ path(p, Mode::Use);
+}
+
+pub(crate) fn type_path(p: &mut Parser<'_>) {
+ path(p, Mode::Type);
+}
+
+pub(super) fn expr_path(p: &mut Parser<'_>) {
+ path(p, Mode::Expr);
+}
+
+pub(crate) fn type_path_for_qualifier(
+ p: &mut Parser<'_>,
+ qual: CompletedMarker,
+) -> CompletedMarker {
+ path_for_qualifier(p, Mode::Type, qual)
+}
+
+#[derive(Clone, Copy, Eq, PartialEq)]
+enum Mode {
+ Use,
+ Type,
+ Expr,
+}
+
+fn path(p: &mut Parser<'_>, mode: Mode) {
+ let path = p.start();
+ path_segment(p, mode, true);
+ let qual = path.complete(p, PATH);
+ path_for_qualifier(p, mode, qual);
+}
+
+fn path_for_qualifier(
+ p: &mut Parser<'_>,
+ mode: Mode,
+ mut qual: CompletedMarker,
+) -> CompletedMarker {
+ loop {
+ let use_tree = mode == Mode::Use && matches!(p.nth(2), T![*] | T!['{']);
+ if p.at(T![::]) && !use_tree {
+ let path = qual.precede(p);
+ p.bump(T![::]);
+ path_segment(p, mode, false);
+ let path = path.complete(p, PATH);
+ qual = path;
+ } else {
+ return qual;
+ }
+ }
+}
+
+fn path_segment(p: &mut Parser<'_>, mode: Mode, first: bool) {
+ let m = p.start();
+ // test qual_paths
+ // type X = <A as B>::Output;
+ // fn foo() { <usize as Default>::default(); }
+ if first && p.eat(T![<]) {
+ types::type_(p);
+ if p.eat(T![as]) {
+ if is_use_path_start(p) {
+ types::path_type(p);
+ } else {
+ p.error("expected a trait");
+ }
+ }
+ p.expect(T![>]);
+ } else {
+ let mut empty = true;
+ if first {
+ p.eat(T![::]);
+ empty = false;
+ }
+ match p.current() {
+ IDENT => {
+ name_ref(p);
+ opt_path_type_args(p, mode);
+ }
+ // test crate_path
+ // use crate::foo;
+ T![self] | T![super] | T![crate] | T![Self] => {
+ let m = p.start();
+ p.bump_any();
+ m.complete(p, NAME_REF);
+ }
+ _ => {
+ p.err_recover("expected identifier", items::ITEM_RECOVERY_SET);
+ if empty {
+ // test_err empty_segment
+ // use crate::;
+ m.abandon(p);
+ return;
+ }
+ }
+ };
+ }
+ m.complete(p, PATH_SEGMENT);
+}
+
+fn opt_path_type_args(p: &mut Parser<'_>, mode: Mode) {
+ match mode {
+ Mode::Use => {}
+ Mode::Type => {
+ // test path_fn_trait_args
+ // type F = Box<Fn(i32) -> ()>;
+ if p.at(T!['(']) {
+ params::param_list_fn_trait(p);
+ opt_ret_type(p);
+ } else {
+ generic_args::opt_generic_arg_list(p, false);
+ }
+ }
+ Mode::Expr => generic_args::opt_generic_arg_list(p, true),
+ }
+}
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs
new file mode 100644
index 000000000..4cbf10306
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs
@@ -0,0 +1,440 @@
+use super::*;
+
+pub(super) const PATTERN_FIRST: TokenSet =
+ expressions::LITERAL_FIRST.union(paths::PATH_FIRST).union(TokenSet::new(&[
+ T![box],
+ T![ref],
+ T![mut],
+ T!['('],
+ T!['['],
+ T![&],
+ T![_],
+ T![-],
+ T![.],
+ ]));
+
+pub(crate) fn pattern(p: &mut Parser<'_>) {
+ pattern_r(p, PAT_RECOVERY_SET);
+}
+
+/// Parses a pattern list separated by pipes `|`.
+pub(super) fn pattern_top(p: &mut Parser<'_>) {
+ pattern_top_r(p, PAT_RECOVERY_SET);
+}
+
+pub(crate) fn pattern_single(p: &mut Parser<'_>) {
+ pattern_single_r(p, PAT_RECOVERY_SET);
+}
+
+/// Parses a pattern list separated by pipes `|`
+/// using the given `recovery_set`.
+pub(super) fn pattern_top_r(p: &mut Parser<'_>, recovery_set: TokenSet) {
+ p.eat(T![|]);
+ pattern_r(p, recovery_set);
+}
+
+/// Parses a pattern list separated by pipes `|`, with no leading `|`,using the
+/// given `recovery_set`.
+
+// test or_pattern
+// fn main() {
+// match () {
+// (_ | _) => (),
+// &(_ | _) => (),
+// (_ | _,) => (),
+// [_ | _,] => (),
+// }
+// }
+fn pattern_r(p: &mut Parser<'_>, recovery_set: TokenSet) {
+ let m = p.start();
+ pattern_single_r(p, recovery_set);
+
+ if !p.at(T![|]) {
+ m.abandon(p);
+ return;
+ }
+ while p.eat(T![|]) {
+ pattern_single_r(p, recovery_set);
+ }
+ m.complete(p, OR_PAT);
+}
+
+fn pattern_single_r(p: &mut Parser<'_>, recovery_set: TokenSet) {
+ if let Some(lhs) = atom_pat(p, recovery_set) {
+ // test range_pat
+ // fn main() {
+ // match 92 {
+ // 0 ... 100 => (),
+ // 101 ..= 200 => (),
+ // 200 .. 301 => (),
+ // 302 .. => (),
+ // }
+ //
+ // match Some(10 as u8) {
+ // Some(0) | None => (),
+ // Some(1..) => ()
+ // }
+ //
+ // match (10 as u8, 5 as u8) {
+ // (0, _) => (),
+ // (1.., _) => ()
+ // }
+ // }
+
+ // FIXME: support half_open_range_patterns (`..=2`),
+ // exclusive_range_pattern (`..5`) with missing lhs
+ for range_op in [T![...], T![..=], T![..]] {
+ if p.at(range_op) {
+ let m = lhs.precede(p);
+ p.bump(range_op);
+
+ // `0 .. =>` or `let 0 .. =` or `Some(0 .. )`
+ // ^ ^ ^
+ if p.at(T![=]) | p.at(T![')']) | p.at(T![,]) {
+ // test half_open_range_pat
+ // fn f() { let 0 .. = 1u32; }
+ } else {
+ atom_pat(p, recovery_set);
+ }
+ m.complete(p, RANGE_PAT);
+ return;
+ }
+ }
+ }
+}
+
+const PAT_RECOVERY_SET: TokenSet =
+ TokenSet::new(&[T![let], T![if], T![while], T![loop], T![match], T![')'], T![,], T![=]]);
+
+fn atom_pat(p: &mut Parser<'_>, recovery_set: TokenSet) -> Option<CompletedMarker> {
+ let m = match p.current() {
+ T![box] => box_pat(p),
+ T![ref] | T![mut] => ident_pat(p, true),
+ T![const] => const_block_pat(p),
+ IDENT => match p.nth(1) {
+ // Checks the token after an IDENT to see if a pattern is a path (Struct { .. }) or macro
+ // (T![x]).
+ T!['('] | T!['{'] | T![!] => path_or_macro_pat(p),
+ T![:] if p.nth_at(1, T![::]) => path_or_macro_pat(p),
+ _ => ident_pat(p, true),
+ },
+
+ // test type_path_in_pattern
+ // fn main() { let <_>::Foo = (); }
+ _ if paths::is_path_start(p) => path_or_macro_pat(p),
+ _ if is_literal_pat_start(p) => literal_pat(p),
+
+ T![.] if p.at(T![..]) => rest_pat(p),
+ T![_] => wildcard_pat(p),
+ T![&] => ref_pat(p),
+ T!['('] => tuple_pat(p),
+ T!['['] => slice_pat(p),
+
+ _ => {
+ p.err_recover("expected pattern", recovery_set);
+ return None;
+ }
+ };
+
+ Some(m)
+}
+
+fn is_literal_pat_start(p: &Parser<'_>) -> bool {
+ p.at(T![-]) && (p.nth(1) == INT_NUMBER || p.nth(1) == FLOAT_NUMBER)
+ || p.at_ts(expressions::LITERAL_FIRST)
+}
+
+// test literal_pattern
+// fn main() {
+// match () {
+// -1 => (),
+// 92 => (),
+// 'c' => (),
+// "hello" => (),
+// }
+// }
+fn literal_pat(p: &mut Parser<'_>) -> CompletedMarker {
+ assert!(is_literal_pat_start(p));
+ let m = p.start();
+ if p.at(T![-]) {
+ p.bump(T![-]);
+ }
+ expressions::literal(p);
+ m.complete(p, LITERAL_PAT)
+}
+
+// test path_part
+// fn foo() {
+// let foo::Bar = ();
+// let ::Bar = ();
+// let Bar { .. } = ();
+// let Bar(..) = ();
+// }
+fn path_or_macro_pat(p: &mut Parser<'_>) -> CompletedMarker {
+ assert!(paths::is_path_start(p));
+ let m = p.start();
+ paths::expr_path(p);
+ let kind = match p.current() {
+ T!['('] => {
+ tuple_pat_fields(p);
+ TUPLE_STRUCT_PAT
+ }
+ T!['{'] => {
+ record_pat_field_list(p);
+ RECORD_PAT
+ }
+ // test marco_pat
+ // fn main() {
+ // let m!(x) = 0;
+ // }
+ T![!] => {
+ items::macro_call_after_excl(p);
+ return m.complete(p, MACRO_CALL).precede(p).complete(p, MACRO_PAT);
+ }
+ _ => PATH_PAT,
+ };
+ m.complete(p, kind)
+}
+
+// test tuple_pat_fields
+// fn foo() {
+// let S() = ();
+// let S(_) = ();
+// let S(_,) = ();
+// let S(_, .. , x) = ();
+// }
+fn tuple_pat_fields(p: &mut Parser<'_>) {
+ assert!(p.at(T!['(']));
+ p.bump(T!['(']);
+ pat_list(p, T![')']);
+ p.expect(T![')']);
+}
+
+// test record_pat_field
+// fn foo() {
+// let S { 0: 1 } = ();
+// let S { x: 1 } = ();
+// let S { #[cfg(any())] x: 1 } = ();
+// }
+fn record_pat_field(p: &mut Parser<'_>) {
+ match p.current() {
+ IDENT | INT_NUMBER if p.nth(1) == T![:] => {
+ name_ref_or_index(p);
+ p.bump(T![:]);
+ pattern(p);
+ }
+ T![box] => {
+ // FIXME: not all box patterns should be allowed
+ box_pat(p);
+ }
+ T![ref] | T![mut] | IDENT => {
+ ident_pat(p, false);
+ }
+ _ => {
+ p.err_and_bump("expected identifier");
+ }
+ }
+}
+
+// test record_pat_field_list
+// fn foo() {
+// let S {} = ();
+// let S { f, ref mut g } = ();
+// let S { h: _, ..} = ();
+// let S { h: _, } = ();
+// let S { #[cfg(any())] .. } = ();
+// }
+fn record_pat_field_list(p: &mut Parser<'_>) {
+ assert!(p.at(T!['{']));
+ let m = p.start();
+ p.bump(T!['{']);
+ while !p.at(EOF) && !p.at(T!['}']) {
+ let m = p.start();
+ attributes::outer_attrs(p);
+
+ match p.current() {
+ // A trailing `..` is *not* treated as a REST_PAT.
+ T![.] if p.at(T![..]) => {
+ p.bump(T![..]);
+ m.complete(p, REST_PAT);
+ }
+ T!['{'] => {
+ error_block(p, "expected ident");
+ m.abandon(p);
+ }
+ _ => {
+ record_pat_field(p);
+ m.complete(p, RECORD_PAT_FIELD);
+ }
+ }
+ if !p.at(T!['}']) {
+ p.expect(T![,]);
+ }
+ }
+ p.expect(T!['}']);
+ m.complete(p, RECORD_PAT_FIELD_LIST);
+}
+
+// test placeholder_pat
+// fn main() { let _ = (); }
+fn wildcard_pat(p: &mut Parser<'_>) -> CompletedMarker {
+ assert!(p.at(T![_]));
+ let m = p.start();
+ p.bump(T![_]);
+ m.complete(p, WILDCARD_PAT)
+}
+
+// test dot_dot_pat
+// fn main() {
+// let .. = ();
+// //
+// // Tuples
+// //
+// let (a, ..) = ();
+// let (a, ..,) = ();
+// let Tuple(a, ..) = ();
+// let Tuple(a, ..,) = ();
+// let (.., ..) = ();
+// let Tuple(.., ..) = ();
+// let (.., a, ..) = ();
+// let Tuple(.., a, ..) = ();
+// //
+// // Slices
+// //
+// let [..] = ();
+// let [head, ..] = ();
+// let [head, tail @ ..] = ();
+// let [head, .., cons] = ();
+// let [head, mid @ .., cons] = ();
+// let [head, .., .., cons] = ();
+// let [head, .., mid, tail @ ..] = ();
+// let [head, .., mid, .., cons] = ();
+// }
+fn rest_pat(p: &mut Parser<'_>) -> CompletedMarker {
+ assert!(p.at(T![..]));
+ let m = p.start();
+ p.bump(T![..]);
+ m.complete(p, REST_PAT)
+}
+
+// test ref_pat
+// fn main() {
+// let &a = ();
+// let &mut b = ();
+// }
+fn ref_pat(p: &mut Parser<'_>) -> CompletedMarker {
+ assert!(p.at(T![&]));
+ let m = p.start();
+ p.bump(T![&]);
+ p.eat(T![mut]);
+ pattern_single(p);
+ m.complete(p, REF_PAT)
+}
+
+// test tuple_pat
+// fn main() {
+// let (a, b, ..) = ();
+// let (a,) = ();
+// let (..) = ();
+// let () = ();
+// }
+fn tuple_pat(p: &mut Parser<'_>) -> CompletedMarker {
+ assert!(p.at(T!['(']));
+ let m = p.start();
+ p.bump(T!['(']);
+ let mut has_comma = false;
+ let mut has_pat = false;
+ let mut has_rest = false;
+ while !p.at(EOF) && !p.at(T![')']) {
+ has_pat = true;
+ if !p.at_ts(PATTERN_FIRST) {
+ p.error("expected a pattern");
+ break;
+ }
+ has_rest |= p.at(T![..]);
+
+ pattern(p);
+ if !p.at(T![')']) {
+ has_comma = true;
+ p.expect(T![,]);
+ }
+ }
+ p.expect(T![')']);
+
+ m.complete(p, if !has_comma && !has_rest && has_pat { PAREN_PAT } else { TUPLE_PAT })
+}
+
+// test slice_pat
+// fn main() {
+// let [a, b, ..] = [];
+// }
+fn slice_pat(p: &mut Parser<'_>) -> CompletedMarker {
+ assert!(p.at(T!['[']));
+ let m = p.start();
+ p.bump(T!['[']);
+ pat_list(p, T![']']);
+ p.expect(T![']']);
+ m.complete(p, SLICE_PAT)
+}
+
+fn pat_list(p: &mut Parser<'_>, ket: SyntaxKind) {
+ while !p.at(EOF) && !p.at(ket) {
+ if !p.at_ts(PATTERN_FIRST) {
+ p.error("expected a pattern");
+ break;
+ }
+
+ pattern(p);
+ if !p.at(ket) {
+ p.expect(T![,]);
+ }
+ }
+}
+
+// test bind_pat
+// fn main() {
+// let a = ();
+// let mut b = ();
+// let ref c = ();
+// let ref mut d = ();
+// let e @ _ = ();
+// let ref mut f @ g @ _ = ();
+// }
+fn ident_pat(p: &mut Parser<'_>, with_at: bool) -> CompletedMarker {
+ assert!(matches!(p.current(), T![ref] | T![mut] | IDENT));
+ let m = p.start();
+ p.eat(T![ref]);
+ p.eat(T![mut]);
+ name_r(p, PAT_RECOVERY_SET);
+ if with_at && p.eat(T![@]) {
+ pattern_single(p);
+ }
+ m.complete(p, IDENT_PAT)
+}
+
+// test box_pat
+// fn main() {
+// let box i = ();
+// let box Outer { box i, j: box Inner(box &x) } = ();
+// let box ref mut i = ();
+// }
+fn box_pat(p: &mut Parser<'_>) -> CompletedMarker {
+ assert!(p.at(T![box]));
+ let m = p.start();
+ p.bump(T![box]);
+ pattern_single(p);
+ m.complete(p, BOX_PAT)
+}
+
+// test const_block_pat
+// fn main() {
+// let const { 15 } = ();
+// let const { foo(); bar() } = ();
+// }
+fn const_block_pat(p: &mut Parser<'_>) -> CompletedMarker {
+ assert!(p.at(T![const]));
+ let m = p.start();
+ p.bump(T![const]);
+ expressions::block_expr(p);
+ m.complete(p, CONST_BLOCK_PAT)
+}
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs
new file mode 100644
index 000000000..5c6e18fee
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs
@@ -0,0 +1,352 @@
+use super::*;
+
+pub(super) const TYPE_FIRST: TokenSet = paths::PATH_FIRST.union(TokenSet::new(&[
+ T!['('],
+ T!['['],
+ T![<],
+ T![!],
+ T![*],
+ T![&],
+ T![_],
+ T![fn],
+ T![unsafe],
+ T![extern],
+ T![for],
+ T![impl],
+ T![dyn],
+ T![Self],
+]));
+
+const TYPE_RECOVERY_SET: TokenSet = TokenSet::new(&[
+ T![')'],
+ T![,],
+ // test_err struct_field_recover
+ // struct S { f pub g: () }
+ T![pub],
+]);
+
+pub(crate) fn type_(p: &mut Parser<'_>) {
+ type_with_bounds_cond(p, true);
+}
+
+pub(super) fn type_no_bounds(p: &mut Parser<'_>) {
+ type_with_bounds_cond(p, false);
+}
+
+fn type_with_bounds_cond(p: &mut Parser<'_>, allow_bounds: bool) {
+ match p.current() {
+ T!['('] => paren_or_tuple_type(p),
+ T![!] => never_type(p),
+ T![*] => ptr_type(p),
+ T!['['] => array_or_slice_type(p),
+ T![&] => ref_type(p),
+ T![_] => infer_type(p),
+ T![fn] | T![unsafe] | T![extern] => fn_ptr_type(p),
+ T![for] => for_type(p, allow_bounds),
+ T![impl] => impl_trait_type(p),
+ T![dyn] => dyn_trait_type(p),
+ // Some path types are not allowed to have bounds (no plus)
+ T![<] => path_type_(p, allow_bounds),
+ _ if paths::is_path_start(p) => path_or_macro_type_(p, allow_bounds),
+ _ => {
+ p.err_recover("expected type", TYPE_RECOVERY_SET);
+ }
+ }
+}
+
+pub(super) fn ascription(p: &mut Parser<'_>) {
+ assert!(p.at(T![:]));
+ p.bump(T![:]);
+ if p.at(T![=]) {
+ // recover from `let x: = expr;`, `const X: = expr;` and similars
+ // hopefully no type starts with `=`
+ p.error("missing type");
+ return;
+ }
+ type_(p);
+}
+
+fn paren_or_tuple_type(p: &mut Parser<'_>) {
+ assert!(p.at(T!['(']));
+ let m = p.start();
+ p.bump(T!['(']);
+ let mut n_types: u32 = 0;
+ let mut trailing_comma: bool = false;
+ while !p.at(EOF) && !p.at(T![')']) {
+ n_types += 1;
+ type_(p);
+ if p.eat(T![,]) {
+ trailing_comma = true;
+ } else {
+ trailing_comma = false;
+ break;
+ }
+ }
+ p.expect(T![')']);
+
+ let kind = if n_types == 1 && !trailing_comma {
+ // test paren_type
+ // type T = (i32);
+ PAREN_TYPE
+ } else {
+ // test unit_type
+ // type T = ();
+
+ // test singleton_tuple_type
+ // type T = (i32,);
+ TUPLE_TYPE
+ };
+ m.complete(p, kind);
+}
+
+// test never_type
+// type Never = !;
+fn never_type(p: &mut Parser<'_>) {
+ assert!(p.at(T![!]));
+ let m = p.start();
+ p.bump(T![!]);
+ m.complete(p, NEVER_TYPE);
+}
+
+fn ptr_type(p: &mut Parser<'_>) {
+ assert!(p.at(T![*]));
+ let m = p.start();
+ p.bump(T![*]);
+
+ match p.current() {
+ // test pointer_type_mut
+ // type M = *mut ();
+ // type C = *mut ();
+ T![mut] | T![const] => p.bump_any(),
+ _ => {
+ // test_err pointer_type_no_mutability
+ // type T = *();
+ p.error(
+ "expected mut or const in raw pointer type \
+ (use `*mut T` or `*const T` as appropriate)",
+ );
+ }
+ };
+
+ type_no_bounds(p);
+ m.complete(p, PTR_TYPE);
+}
+
+fn array_or_slice_type(p: &mut Parser<'_>) {
+ assert!(p.at(T!['[']));
+ let m = p.start();
+ p.bump(T!['[']);
+
+ type_(p);
+ let kind = match p.current() {
+ // test slice_type
+ // type T = [()];
+ T![']'] => {
+ p.bump(T![']']);
+ SLICE_TYPE
+ }
+
+ // test array_type
+ // type T = [(); 92];
+ T![;] => {
+ p.bump(T![;]);
+ expressions::expr(p);
+ p.expect(T![']']);
+ ARRAY_TYPE
+ }
+ // test_err array_type_missing_semi
+ // type T = [() 92];
+ _ => {
+ p.error("expected `;` or `]`");
+ SLICE_TYPE
+ }
+ };
+ m.complete(p, kind);
+}
+
+// test reference_type;
+// type A = &();
+// type B = &'static ();
+// type C = &mut ();
+fn ref_type(p: &mut Parser<'_>) {
+ assert!(p.at(T![&]));
+ let m = p.start();
+ p.bump(T![&]);
+ if p.at(LIFETIME_IDENT) {
+ lifetime(p);
+ }
+ p.eat(T![mut]);
+ type_no_bounds(p);
+ m.complete(p, REF_TYPE);
+}
+
+// test placeholder_type
+// type Placeholder = _;
+fn infer_type(p: &mut Parser<'_>) {
+ assert!(p.at(T![_]));
+ let m = p.start();
+ p.bump(T![_]);
+ m.complete(p, INFER_TYPE);
+}
+
+// test fn_pointer_type
+// type A = fn();
+// type B = unsafe fn();
+// type C = unsafe extern "C" fn();
+// type D = extern "C" fn ( u8 , ... ) -> u8;
+fn fn_ptr_type(p: &mut Parser<'_>) {
+ let m = p.start();
+ p.eat(T![unsafe]);
+ if p.at(T![extern]) {
+ abi(p);
+ }
+ // test_err fn_pointer_type_missing_fn
+ // type F = unsafe ();
+ if !p.eat(T![fn]) {
+ m.abandon(p);
+ p.error("expected `fn`");
+ return;
+ }
+ if p.at(T!['(']) {
+ params::param_list_fn_ptr(p);
+ } else {
+ p.error("expected parameters");
+ }
+ // test fn_pointer_type_with_ret
+ // type F = fn() -> ();
+ opt_ret_type(p);
+ m.complete(p, FN_PTR_TYPE);
+}
+
+pub(super) fn for_binder(p: &mut Parser<'_>) {
+ assert!(p.at(T![for]));
+ p.bump(T![for]);
+ if p.at(T![<]) {
+ generic_params::opt_generic_param_list(p);
+ } else {
+ p.error("expected `<`");
+ }
+}
+
+// test for_type
+// type A = for<'a> fn() -> ();
+// type B = for<'a> unsafe extern "C" fn(&'a ()) -> ();
+// type Obj = for<'a> PartialEq<&'a i32>;
+pub(super) fn for_type(p: &mut Parser<'_>, allow_bounds: bool) {
+ assert!(p.at(T![for]));
+ let m = p.start();
+ for_binder(p);
+ match p.current() {
+ T![fn] | T![unsafe] | T![extern] => {}
+ // OK: legacy trait object format
+ _ if paths::is_use_path_start(p) => {}
+ _ => {
+ p.error("expected a function pointer or path");
+ }
+ }
+ type_no_bounds(p);
+ let completed = m.complete(p, FOR_TYPE);
+
+ // test no_dyn_trait_leading_for
+ // type A = for<'a> Test<'a> + Send;
+ if allow_bounds {
+ opt_type_bounds_as_dyn_trait_type(p, completed);
+ }
+}
+
+// test impl_trait_type
+// type A = impl Iterator<Item=Foo<'a>> + 'a;
+fn impl_trait_type(p: &mut Parser<'_>) {
+ assert!(p.at(T![impl]));
+ let m = p.start();
+ p.bump(T![impl]);
+ generic_params::bounds_without_colon(p);
+ m.complete(p, IMPL_TRAIT_TYPE);
+}
+
+// test dyn_trait_type
+// type A = dyn Iterator<Item=Foo<'a>> + 'a;
+fn dyn_trait_type(p: &mut Parser<'_>) {
+ assert!(p.at(T![dyn]));
+ let m = p.start();
+ p.bump(T![dyn]);
+ generic_params::bounds_without_colon(p);
+ m.complete(p, DYN_TRAIT_TYPE);
+}
+
+// test path_type
+// type A = Foo;
+// type B = ::Foo;
+// type C = self::Foo;
+// type D = super::Foo;
+pub(super) fn path_type(p: &mut Parser<'_>) {
+ path_type_(p, true);
+}
+
+// test macro_call_type
+// type A = foo!();
+// type B = crate::foo!();
+fn path_or_macro_type_(p: &mut Parser<'_>, allow_bounds: bool) {
+ assert!(paths::is_path_start(p));
+ let r = p.start();
+ let m = p.start();
+
+ paths::type_path(p);
+
+ let kind = if p.at(T![!]) && !p.at(T![!=]) {
+ items::macro_call_after_excl(p);
+ m.complete(p, MACRO_CALL);
+ MACRO_TYPE
+ } else {
+ m.abandon(p);
+ PATH_TYPE
+ };
+
+ let path = r.complete(p, kind);
+
+ if allow_bounds {
+ opt_type_bounds_as_dyn_trait_type(p, path);
+ }
+}
+
+pub(super) fn path_type_(p: &mut Parser<'_>, allow_bounds: bool) {
+ assert!(paths::is_path_start(p));
+ let m = p.start();
+ paths::type_path(p);
+
+ // test path_type_with_bounds
+ // fn foo() -> Box<T + 'f> {}
+ // fn foo() -> Box<dyn T + 'f> {}
+ let path = m.complete(p, PATH_TYPE);
+ if allow_bounds {
+ opt_type_bounds_as_dyn_trait_type(p, path);
+ }
+}
+
+/// This turns a parsed PATH_TYPE or FOR_TYPE optionally into a DYN_TRAIT_TYPE
+/// with a TYPE_BOUND_LIST
+fn opt_type_bounds_as_dyn_trait_type(p: &mut Parser<'_>, type_marker: CompletedMarker) {
+ assert!(matches!(
+ type_marker.kind(),
+ SyntaxKind::PATH_TYPE | SyntaxKind::FOR_TYPE | SyntaxKind::MACRO_TYPE
+ ));
+ if !p.at(T![+]) {
+ return;
+ }
+
+ // First create a TYPE_BOUND from the completed PATH_TYPE
+ let m = type_marker.precede(p).complete(p, TYPE_BOUND);
+
+ // Next setup a marker for the TYPE_BOUND_LIST
+ let m = m.precede(p);
+
+ // This gets consumed here so it gets properly set
+ // in the TYPE_BOUND_LIST
+ p.eat(T![+]);
+
+ // Parse rest of the bounds into the TYPE_BOUND_LIST
+ let m = generic_params::bounds_without_colon_m(p, m);
+
+ // Finally precede everything with DYN_TRAIT_TYPE
+ m.precede(p).complete(p, DYN_TRAIT_TYPE);
+}
diff --git a/src/tools/rust-analyzer/crates/parser/src/input.rs b/src/tools/rust-analyzer/crates/parser/src/input.rs
new file mode 100644
index 000000000..9504bd4d9
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/src/input.rs
@@ -0,0 +1,88 @@
+//! See [`Input`].
+
+use crate::SyntaxKind;
+
+#[allow(non_camel_case_types)]
+type bits = u64;
+
+/// Input for the parser -- a sequence of tokens.
+///
+/// As of now, parser doesn't have access to the *text* of the tokens, and makes
+/// decisions based solely on their classification. Unlike `LexerToken`, the
+/// `Tokens` doesn't include whitespace and comments. Main input to the parser.
+///
+/// Struct of arrays internally, but this shouldn't really matter.
+#[derive(Default)]
+pub struct Input {
+ kind: Vec<SyntaxKind>,
+ joint: Vec<bits>,
+ contextual_kind: Vec<SyntaxKind>,
+}
+
+/// `pub` impl used by callers to create `Tokens`.
+impl Input {
+ #[inline]
+ pub fn push(&mut self, kind: SyntaxKind) {
+ self.push_impl(kind, SyntaxKind::EOF)
+ }
+ #[inline]
+ pub fn push_ident(&mut self, contextual_kind: SyntaxKind) {
+ self.push_impl(SyntaxKind::IDENT, contextual_kind)
+ }
+ /// Sets jointness for the last token we've pushed.
+ ///
+ /// This is a separate API rather than an argument to the `push` to make it
+ /// convenient both for textual and mbe tokens. With text, you know whether
+ /// the *previous* token was joint, with mbe, you know whether the *current*
+ /// one is joint. This API allows for styles of usage:
+ ///
+ /// ```
+ /// // In text:
+ /// tokens.was_joint(prev_joint);
+ /// tokens.push(curr);
+ ///
+ /// // In MBE:
+ /// token.push(curr);
+ /// tokens.push(curr_joint)
+ /// ```
+ #[inline]
+ pub fn was_joint(&mut self) {
+ let n = self.len() - 1;
+ let (idx, b_idx) = self.bit_index(n);
+ self.joint[idx] |= 1 << b_idx;
+ }
+ #[inline]
+ fn push_impl(&mut self, kind: SyntaxKind, contextual_kind: SyntaxKind) {
+ let idx = self.len();
+ if idx % (bits::BITS as usize) == 0 {
+ self.joint.push(0);
+ }
+ self.kind.push(kind);
+ self.contextual_kind.push(contextual_kind);
+ }
+}
+
+/// pub(crate) impl used by the parser to consume `Tokens`.
+impl Input {
+ pub(crate) fn kind(&self, idx: usize) -> SyntaxKind {
+ self.kind.get(idx).copied().unwrap_or(SyntaxKind::EOF)
+ }
+ pub(crate) fn contextual_kind(&self, idx: usize) -> SyntaxKind {
+ self.contextual_kind.get(idx).copied().unwrap_or(SyntaxKind::EOF)
+ }
+ pub(crate) fn is_joint(&self, n: usize) -> bool {
+ let (idx, b_idx) = self.bit_index(n);
+ self.joint[idx] & 1 << b_idx != 0
+ }
+}
+
+impl Input {
+ fn bit_index(&self, n: usize) -> (usize, usize) {
+ let idx = n / (bits::BITS as usize);
+ let b_idx = n % (bits::BITS as usize);
+ (idx, b_idx)
+ }
+ fn len(&self) -> usize {
+ self.kind.len()
+ }
+}
diff --git a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs
new file mode 100644
index 000000000..f4b9988ea
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs
@@ -0,0 +1,300 @@
+//! Lexing `&str` into a sequence of Rust tokens.
+//!
+//! Note that strictly speaking the parser in this crate is not required to work
+//! on tokens which originated from text. Macros, eg, can synthesize tokens out
+//! of thin air. So, ideally, lexer should be an orthogonal crate. It is however
+//! convenient to include a text-based lexer here!
+//!
+//! Note that these tokens, unlike the tokens we feed into the parser, do
+//! include info about comments and whitespace.
+
+use std::ops;
+
+use crate::{
+ SyntaxKind::{self, *},
+ T,
+};
+
+pub struct LexedStr<'a> {
+ text: &'a str,
+ kind: Vec<SyntaxKind>,
+ start: Vec<u32>,
+ error: Vec<LexError>,
+}
+
+struct LexError {
+ msg: String,
+ token: u32,
+}
+
+impl<'a> LexedStr<'a> {
+ pub fn new(text: &'a str) -> LexedStr<'a> {
+ let mut conv = Converter::new(text);
+ if let Some(shebang_len) = rustc_lexer::strip_shebang(text) {
+ conv.res.push(SHEBANG, conv.offset);
+ conv.offset = shebang_len;
+ };
+
+ for token in rustc_lexer::tokenize(&text[conv.offset..]) {
+ let token_text = &text[conv.offset..][..token.len];
+
+ conv.extend_token(&token.kind, token_text);
+ }
+
+ conv.finalize_with_eof()
+ }
+
+ pub fn single_token(text: &'a str) -> Option<(SyntaxKind, Option<String>)> {
+ if text.is_empty() {
+ return None;
+ }
+
+ let token = rustc_lexer::first_token(text);
+ if token.len != text.len() {
+ return None;
+ }
+
+ let mut conv = Converter::new(text);
+ conv.extend_token(&token.kind, text);
+ match &*conv.res.kind {
+ [kind] => Some((*kind, conv.res.error.pop().map(|it| it.msg.clone()))),
+ _ => None,
+ }
+ }
+
+ pub fn as_str(&self) -> &str {
+ self.text
+ }
+
+ pub fn len(&self) -> usize {
+ self.kind.len() - 1
+ }
+
+ pub fn is_empty(&self) -> bool {
+ self.len() == 0
+ }
+
+ pub fn kind(&self, i: usize) -> SyntaxKind {
+ assert!(i < self.len());
+ self.kind[i]
+ }
+
+ pub fn text(&self, i: usize) -> &str {
+ self.range_text(i..i + 1)
+ }
+ pub fn range_text(&self, r: ops::Range<usize>) -> &str {
+ assert!(r.start < r.end && r.end <= self.len());
+ let lo = self.start[r.start] as usize;
+ let hi = self.start[r.end] as usize;
+ &self.text[lo..hi]
+ }
+
+ // Naming is hard.
+ pub fn text_range(&self, i: usize) -> ops::Range<usize> {
+ assert!(i < self.len());
+ let lo = self.start[i] as usize;
+ let hi = self.start[i + 1] as usize;
+ lo..hi
+ }
+ pub fn text_start(&self, i: usize) -> usize {
+ assert!(i <= self.len());
+ self.start[i] as usize
+ }
+ pub fn text_len(&self, i: usize) -> usize {
+ assert!(i < self.len());
+ let r = self.text_range(i);
+ r.end - r.start
+ }
+
+ pub fn error(&self, i: usize) -> Option<&str> {
+ assert!(i < self.len());
+ let err = self.error.binary_search_by_key(&(i as u32), |i| i.token).ok()?;
+ Some(self.error[err].msg.as_str())
+ }
+
+ pub fn errors(&self) -> impl Iterator<Item = (usize, &str)> + '_ {
+ self.error.iter().map(|it| (it.token as usize, it.msg.as_str()))
+ }
+
+ fn push(&mut self, kind: SyntaxKind, offset: usize) {
+ self.kind.push(kind);
+ self.start.push(offset as u32);
+ }
+}
+
+struct Converter<'a> {
+ res: LexedStr<'a>,
+ offset: usize,
+}
+
+impl<'a> Converter<'a> {
+ fn new(text: &'a str) -> Self {
+ Self {
+ res: LexedStr { text, kind: Vec::new(), start: Vec::new(), error: Vec::new() },
+ offset: 0,
+ }
+ }
+
+ fn finalize_with_eof(mut self) -> LexedStr<'a> {
+ self.res.push(EOF, self.offset);
+ self.res
+ }
+
+ fn push(&mut self, kind: SyntaxKind, len: usize, err: Option<&str>) {
+ self.res.push(kind, self.offset);
+ self.offset += len;
+
+ if let Some(err) = err {
+ let token = self.res.len() as u32;
+ let msg = err.to_string();
+ self.res.error.push(LexError { msg, token });
+ }
+ }
+
+ fn extend_token(&mut self, kind: &rustc_lexer::TokenKind, token_text: &str) {
+ // A note on an intended tradeoff:
+ // We drop some useful information here (see patterns with double dots `..`)
+ // Storing that info in `SyntaxKind` is not possible due to its layout requirements of
+ // being `u16` that come from `rowan::SyntaxKind`.
+ let mut err = "";
+
+ let syntax_kind = {
+ match kind {
+ rustc_lexer::TokenKind::LineComment { doc_style: _ } => COMMENT,
+ rustc_lexer::TokenKind::BlockComment { doc_style: _, terminated } => {
+ if !terminated {
+ err = "Missing trailing `*/` symbols to terminate the block comment";
+ }
+ COMMENT
+ }
+
+ rustc_lexer::TokenKind::Whitespace => WHITESPACE,
+
+ rustc_lexer::TokenKind::Ident if token_text == "_" => UNDERSCORE,
+ rustc_lexer::TokenKind::Ident => {
+ SyntaxKind::from_keyword(token_text).unwrap_or(IDENT)
+ }
+
+ rustc_lexer::TokenKind::RawIdent => IDENT,
+ rustc_lexer::TokenKind::Literal { kind, .. } => {
+ self.extend_literal(token_text.len(), kind);
+ return;
+ }
+
+ rustc_lexer::TokenKind::Lifetime { starts_with_number } => {
+ if *starts_with_number {
+ err = "Lifetime name cannot start with a number";
+ }
+ LIFETIME_IDENT
+ }
+
+ rustc_lexer::TokenKind::Semi => T![;],
+ rustc_lexer::TokenKind::Comma => T![,],
+ rustc_lexer::TokenKind::Dot => T![.],
+ rustc_lexer::TokenKind::OpenParen => T!['('],
+ rustc_lexer::TokenKind::CloseParen => T![')'],
+ rustc_lexer::TokenKind::OpenBrace => T!['{'],
+ rustc_lexer::TokenKind::CloseBrace => T!['}'],
+ rustc_lexer::TokenKind::OpenBracket => T!['['],
+ rustc_lexer::TokenKind::CloseBracket => T![']'],
+ rustc_lexer::TokenKind::At => T![@],
+ rustc_lexer::TokenKind::Pound => T![#],
+ rustc_lexer::TokenKind::Tilde => T![~],
+ rustc_lexer::TokenKind::Question => T![?],
+ rustc_lexer::TokenKind::Colon => T![:],
+ rustc_lexer::TokenKind::Dollar => T![$],
+ rustc_lexer::TokenKind::Eq => T![=],
+ rustc_lexer::TokenKind::Bang => T![!],
+ rustc_lexer::TokenKind::Lt => T![<],
+ rustc_lexer::TokenKind::Gt => T![>],
+ rustc_lexer::TokenKind::Minus => T![-],
+ rustc_lexer::TokenKind::And => T![&],
+ rustc_lexer::TokenKind::Or => T![|],
+ rustc_lexer::TokenKind::Plus => T![+],
+ rustc_lexer::TokenKind::Star => T![*],
+ rustc_lexer::TokenKind::Slash => T![/],
+ rustc_lexer::TokenKind::Caret => T![^],
+ rustc_lexer::TokenKind::Percent => T![%],
+ rustc_lexer::TokenKind::Unknown => ERROR,
+ }
+ };
+
+ let err = if err.is_empty() { None } else { Some(err) };
+ self.push(syntax_kind, token_text.len(), err);
+ }
+
+ fn extend_literal(&mut self, len: usize, kind: &rustc_lexer::LiteralKind) {
+ let mut err = "";
+
+ let syntax_kind = match *kind {
+ rustc_lexer::LiteralKind::Int { empty_int, base: _ } => {
+ if empty_int {
+ err = "Missing digits after the integer base prefix";
+ }
+ INT_NUMBER
+ }
+ rustc_lexer::LiteralKind::Float { empty_exponent, base: _ } => {
+ if empty_exponent {
+ err = "Missing digits after the exponent symbol";
+ }
+ FLOAT_NUMBER
+ }
+ rustc_lexer::LiteralKind::Char { terminated } => {
+ if !terminated {
+ err = "Missing trailing `'` symbol to terminate the character literal";
+ }
+ CHAR
+ }
+ rustc_lexer::LiteralKind::Byte { terminated } => {
+ if !terminated {
+ err = "Missing trailing `'` symbol to terminate the byte literal";
+ }
+ BYTE
+ }
+ rustc_lexer::LiteralKind::Str { terminated } => {
+ if !terminated {
+ err = "Missing trailing `\"` symbol to terminate the string literal";
+ }
+ STRING
+ }
+ rustc_lexer::LiteralKind::ByteStr { terminated } => {
+ if !terminated {
+ err = "Missing trailing `\"` symbol to terminate the byte string literal";
+ }
+ BYTE_STRING
+ }
+ rustc_lexer::LiteralKind::RawStr { err: raw_str_err, .. } => {
+ if let Some(raw_str_err) = raw_str_err {
+ err = match raw_str_err {
+ rustc_lexer::RawStrError::InvalidStarter { .. } => "Missing `\"` symbol after `#` symbols to begin the raw string literal",
+ rustc_lexer::RawStrError::NoTerminator { expected, found, .. } => if expected == found {
+ "Missing trailing `\"` to terminate the raw string literal"
+ } else {
+ "Missing trailing `\"` with `#` symbols to terminate the raw string literal"
+ },
+ rustc_lexer::RawStrError::TooManyDelimiters { .. } => "Too many `#` symbols: raw strings may be delimited by up to 65535 `#` symbols",
+ };
+ };
+ STRING
+ }
+ rustc_lexer::LiteralKind::RawByteStr { err: raw_str_err, .. } => {
+ if let Some(raw_str_err) = raw_str_err {
+ err = match raw_str_err {
+ rustc_lexer::RawStrError::InvalidStarter { .. } => "Missing `\"` symbol after `#` symbols to begin the raw byte string literal",
+ rustc_lexer::RawStrError::NoTerminator { expected, found, .. } => if expected == found {
+ "Missing trailing `\"` to terminate the raw byte string literal"
+ } else {
+ "Missing trailing `\"` with `#` symbols to terminate the raw byte string literal"
+ },
+ rustc_lexer::RawStrError::TooManyDelimiters { .. } => "Too many `#` symbols: raw byte strings may be delimited by up to 65535 `#` symbols",
+ };
+ };
+
+ BYTE_STRING
+ }
+ };
+
+ let err = if err.is_empty() { None } else { Some(err) };
+ self.push(syntax_kind, len, err);
+ }
+}
diff --git a/src/tools/rust-analyzer/crates/parser/src/lib.rs b/src/tools/rust-analyzer/crates/parser/src/lib.rs
new file mode 100644
index 000000000..87be47927
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/src/lib.rs
@@ -0,0 +1,181 @@
+//! The Rust parser.
+//!
+//! NOTE: The crate is undergoing refactors, don't believe everything the docs
+//! say :-)
+//!
+//! The parser doesn't know about concrete representation of tokens and syntax
+//! trees. Abstract [`TokenSource`] and [`TreeSink`] traits are used instead. As
+//! a consequence, this crate does not contain a lexer.
+//!
+//! The [`Parser`] struct from the [`parser`] module is a cursor into the
+//! sequence of tokens. Parsing routines use [`Parser`] to inspect current
+//! state and advance the parsing.
+//!
+//! The actual parsing happens in the [`grammar`] module.
+//!
+//! Tests for this crate live in the `syntax` crate.
+//!
+//! [`Parser`]: crate::parser::Parser
+
+#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
+#![allow(rustdoc::private_intra_doc_links)]
+
+mod lexed_str;
+mod token_set;
+mod syntax_kind;
+mod event;
+mod parser;
+mod grammar;
+mod input;
+mod output;
+mod shortcuts;
+
+#[cfg(test)]
+mod tests;
+
+pub(crate) use token_set::TokenSet;
+
+pub use crate::{
+ input::Input,
+ lexed_str::LexedStr,
+ output::{Output, Step},
+ shortcuts::StrStep,
+ syntax_kind::SyntaxKind,
+};
+
+/// Parse the whole of the input as a given syntactic construct.
+///
+/// This covers two main use-cases:
+///
+/// * Parsing a Rust file.
+/// * Parsing a result of macro expansion.
+///
+/// That is, for something like
+///
+/// ```
+/// quick_check! {
+/// fn prop() {}
+/// }
+/// ```
+///
+/// the input to the macro will be parsed with [`PrefixEntryPoint::Item`], and
+/// the result will be [`TopEntryPoint::MacroItems`].
+///
+/// [`TopEntryPoint::parse`] makes a guarantee that
+/// * all input is consumed
+/// * the result is a valid tree (there's one root node)
+#[derive(Debug)]
+pub enum TopEntryPoint {
+ SourceFile,
+ MacroStmts,
+ MacroItems,
+ Pattern,
+ Type,
+ Expr,
+ /// Edge case -- macros generally don't expand to attributes, with the
+ /// exception of `cfg_attr` which does!
+ MetaItem,
+}
+
+impl TopEntryPoint {
+ pub fn parse(&self, input: &Input) -> Output {
+ let entry_point: fn(&'_ mut parser::Parser<'_>) = match self {
+ TopEntryPoint::SourceFile => grammar::entry::top::source_file,
+ TopEntryPoint::MacroStmts => grammar::entry::top::macro_stmts,
+ TopEntryPoint::MacroItems => grammar::entry::top::macro_items,
+ TopEntryPoint::Pattern => grammar::entry::top::pattern,
+ TopEntryPoint::Type => grammar::entry::top::type_,
+ TopEntryPoint::Expr => grammar::entry::top::expr,
+ TopEntryPoint::MetaItem => grammar::entry::top::meta_item,
+ };
+ let mut p = parser::Parser::new(input);
+ entry_point(&mut p);
+ let events = p.finish();
+ let res = event::process(events);
+
+ if cfg!(debug_assertions) {
+ let mut depth = 0;
+ let mut first = true;
+ for step in res.iter() {
+ assert!(depth > 0 || first);
+ first = false;
+ match step {
+ Step::Enter { .. } => depth += 1,
+ Step::Exit => depth -= 1,
+ Step::Token { .. } | Step::Error { .. } => (),
+ }
+ }
+ assert!(!first, "no tree at all");
+ }
+
+ res
+ }
+}
+
+/// Parse a prefix of the input as a given syntactic construct.
+///
+/// This is used by macro-by-example parser to implement things like `$i:item`
+/// and the naming of variants follows the naming of macro fragments.
+///
+/// Note that this is generally non-optional -- the result is intentionally not
+/// `Option<Output>`. The way MBE work, by the time we *try* to parse `$e:expr`
+/// we already commit to expression. In other words, this API by design can't be
+/// used to implement "rollback and try another alternative" logic.
+#[derive(Debug)]
+pub enum PrefixEntryPoint {
+ Vis,
+ Block,
+ Stmt,
+ Pat,
+ Ty,
+ Expr,
+ Path,
+ Item,
+ MetaItem,
+}
+
+impl PrefixEntryPoint {
+ pub fn parse(&self, input: &Input) -> Output {
+ let entry_point: fn(&'_ mut parser::Parser<'_>) = match self {
+ PrefixEntryPoint::Vis => grammar::entry::prefix::vis,
+ PrefixEntryPoint::Block => grammar::entry::prefix::block,
+ PrefixEntryPoint::Stmt => grammar::entry::prefix::stmt,
+ PrefixEntryPoint::Pat => grammar::entry::prefix::pat,
+ PrefixEntryPoint::Ty => grammar::entry::prefix::ty,
+ PrefixEntryPoint::Expr => grammar::entry::prefix::expr,
+ PrefixEntryPoint::Path => grammar::entry::prefix::path,
+ PrefixEntryPoint::Item => grammar::entry::prefix::item,
+ PrefixEntryPoint::MetaItem => grammar::entry::prefix::meta_item,
+ };
+ let mut p = parser::Parser::new(input);
+ entry_point(&mut p);
+ let events = p.finish();
+ event::process(events)
+ }
+}
+
+/// A parsing function for a specific braced-block.
+pub struct Reparser(fn(&mut parser::Parser<'_>));
+
+impl Reparser {
+ /// If the node is a braced block, return the corresponding `Reparser`.
+ pub fn for_node(
+ node: SyntaxKind,
+ first_child: Option<SyntaxKind>,
+ parent: Option<SyntaxKind>,
+ ) -> Option<Reparser> {
+ grammar::reparser(node, first_child, parent).map(Reparser)
+ }
+
+ /// Re-parse given tokens using this `Reparser`.
+ ///
+ /// Tokens must start with `{`, end with `}` and form a valid brace
+ /// sequence.
+ pub fn parse(self, tokens: &Input) -> Output {
+ let Reparser(r) = self;
+ let mut p = parser::Parser::new(tokens);
+ r(&mut p);
+ let events = p.finish();
+ event::process(events)
+ }
+}
diff --git a/src/tools/rust-analyzer/crates/parser/src/output.rs b/src/tools/rust-analyzer/crates/parser/src/output.rs
new file mode 100644
index 000000000..e9ec9822d
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/src/output.rs
@@ -0,0 +1,77 @@
+//! See [`Output`]
+
+use crate::SyntaxKind;
+
+/// Output of the parser -- a DFS traversal of a concrete syntax tree.
+///
+/// Use the [`Output::iter`] method to iterate over traversal steps and consume
+/// a syntax tree.
+///
+/// In a sense, this is just a sequence of [`SyntaxKind`]-colored parenthesis
+/// interspersed into the original [`crate::Input`]. The output is fundamentally
+/// coordinated with the input and `n_input_tokens` refers to the number of
+/// times [`crate::Input::push`] was called.
+#[derive(Default)]
+pub struct Output {
+ /// 32-bit encoding of events. If LSB is zero, then that's an index into the
+ /// error vector. Otherwise, it's one of the thee other variants, with data encoded as
+ ///
+ /// |16 bit kind|8 bit n_input_tokens|4 bit tag|4 bit leftover|
+ ///
+ event: Vec<u32>,
+ error: Vec<String>,
+}
+
+#[derive(Debug)]
+pub enum Step<'a> {
+ Token { kind: SyntaxKind, n_input_tokens: u8 },
+ Enter { kind: SyntaxKind },
+ Exit,
+ Error { msg: &'a str },
+}
+
+impl Output {
+ pub fn iter(&self) -> impl Iterator<Item = Step<'_>> {
+ self.event.iter().map(|&event| {
+ if event & 0b1 == 0 {
+ return Step::Error { msg: self.error[(event as usize) >> 1].as_str() };
+ }
+ let tag = ((event & 0x0000_00F0) >> 4) as u8;
+ match tag {
+ 0 => {
+ let kind: SyntaxKind = (((event & 0xFFFF_0000) >> 16) as u16).into();
+ let n_input_tokens = ((event & 0x0000_FF00) >> 8) as u8;
+ Step::Token { kind, n_input_tokens }
+ }
+ 1 => {
+ let kind: SyntaxKind = (((event & 0xFFFF_0000) >> 16) as u16).into();
+ Step::Enter { kind }
+ }
+ 2 => Step::Exit,
+ _ => unreachable!(),
+ }
+ })
+ }
+
+ pub(crate) fn token(&mut self, kind: SyntaxKind, n_tokens: u8) {
+ let e = ((kind as u16 as u32) << 16) | ((n_tokens as u32) << 8) | (0 << 4) | 1;
+ self.event.push(e)
+ }
+
+ pub(crate) fn enter_node(&mut self, kind: SyntaxKind) {
+ let e = ((kind as u16 as u32) << 16) | (1 << 4) | 1;
+ self.event.push(e)
+ }
+
+ pub(crate) fn leave_node(&mut self) {
+ let e = 2 << 4 | 1;
+ self.event.push(e)
+ }
+
+ pub(crate) fn error(&mut self, error: String) {
+ let idx = self.error.len();
+ self.error.push(error);
+ let e = (idx as u32) << 1;
+ self.event.push(e);
+ }
+}
diff --git a/src/tools/rust-analyzer/crates/parser/src/parser.rs b/src/tools/rust-analyzer/crates/parser/src/parser.rs
new file mode 100644
index 000000000..48d8350e0
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/src/parser.rs
@@ -0,0 +1,340 @@
+//! See [`Parser`].
+
+use std::cell::Cell;
+
+use drop_bomb::DropBomb;
+use limit::Limit;
+
+use crate::{
+ event::Event,
+ input::Input,
+ SyntaxKind::{self, EOF, ERROR, TOMBSTONE},
+ TokenSet, T,
+};
+
+/// `Parser` struct provides the low-level API for
+/// navigating through the stream of tokens and
+/// constructing the parse tree. The actual parsing
+/// happens in the [`grammar`](super::grammar) module.
+///
+/// However, the result of this `Parser` is not a real
+/// tree, but rather a flat stream of events of the form
+/// "start expression, consume number literal,
+/// finish expression". See `Event` docs for more.
+pub(crate) struct Parser<'t> {
+ inp: &'t Input,
+ pos: usize,
+ events: Vec<Event>,
+ steps: Cell<u32>,
+}
+
+static PARSER_STEP_LIMIT: Limit = Limit::new(15_000_000);
+
+impl<'t> Parser<'t> {
+ pub(super) fn new(inp: &'t Input) -> Parser<'t> {
+ Parser { inp, pos: 0, events: Vec::new(), steps: Cell::new(0) }
+ }
+
+ pub(crate) fn finish(self) -> Vec<Event> {
+ self.events
+ }
+
+ /// Returns the kind of the current token.
+ /// If parser has already reached the end of input,
+ /// the special `EOF` kind is returned.
+ pub(crate) fn current(&self) -> SyntaxKind {
+ self.nth(0)
+ }
+
+ /// Lookahead operation: returns the kind of the next nth
+ /// token.
+ pub(crate) fn nth(&self, n: usize) -> SyntaxKind {
+ assert!(n <= 3);
+
+ let steps = self.steps.get();
+ assert!(PARSER_STEP_LIMIT.check(steps as usize).is_ok(), "the parser seems stuck");
+ self.steps.set(steps + 1);
+
+ self.inp.kind(self.pos + n)
+ }
+
+ /// Checks if the current token is `kind`.
+ pub(crate) fn at(&self, kind: SyntaxKind) -> bool {
+ self.nth_at(0, kind)
+ }
+
+ pub(crate) fn nth_at(&self, n: usize, kind: SyntaxKind) -> bool {
+ match kind {
+ T![-=] => self.at_composite2(n, T![-], T![=]),
+ T![->] => self.at_composite2(n, T![-], T![>]),
+ T![::] => self.at_composite2(n, T![:], T![:]),
+ T![!=] => self.at_composite2(n, T![!], T![=]),
+ T![..] => self.at_composite2(n, T![.], T![.]),
+ T![*=] => self.at_composite2(n, T![*], T![=]),
+ T![/=] => self.at_composite2(n, T![/], T![=]),
+ T![&&] => self.at_composite2(n, T![&], T![&]),
+ T![&=] => self.at_composite2(n, T![&], T![=]),
+ T![%=] => self.at_composite2(n, T![%], T![=]),
+ T![^=] => self.at_composite2(n, T![^], T![=]),
+ T![+=] => self.at_composite2(n, T![+], T![=]),
+ T![<<] => self.at_composite2(n, T![<], T![<]),
+ T![<=] => self.at_composite2(n, T![<], T![=]),
+ T![==] => self.at_composite2(n, T![=], T![=]),
+ T![=>] => self.at_composite2(n, T![=], T![>]),
+ T![>=] => self.at_composite2(n, T![>], T![=]),
+ T![>>] => self.at_composite2(n, T![>], T![>]),
+ T![|=] => self.at_composite2(n, T![|], T![=]),
+ T![||] => self.at_composite2(n, T![|], T![|]),
+
+ T![...] => self.at_composite3(n, T![.], T![.], T![.]),
+ T![..=] => self.at_composite3(n, T![.], T![.], T![=]),
+ T![<<=] => self.at_composite3(n, T![<], T![<], T![=]),
+ T![>>=] => self.at_composite3(n, T![>], T![>], T![=]),
+
+ _ => self.inp.kind(self.pos + n) == kind,
+ }
+ }
+
+ /// Consume the next token if `kind` matches.
+ pub(crate) fn eat(&mut self, kind: SyntaxKind) -> bool {
+ if !self.at(kind) {
+ return false;
+ }
+ let n_raw_tokens = match kind {
+ T![-=]
+ | T![->]
+ | T![::]
+ | T![!=]
+ | T![..]
+ | T![*=]
+ | T![/=]
+ | T![&&]
+ | T![&=]
+ | T![%=]
+ | T![^=]
+ | T![+=]
+ | T![<<]
+ | T![<=]
+ | T![==]
+ | T![=>]
+ | T![>=]
+ | T![>>]
+ | T![|=]
+ | T![||] => 2,
+
+ T![...] | T![..=] | T![<<=] | T![>>=] => 3,
+ _ => 1,
+ };
+ self.do_bump(kind, n_raw_tokens);
+ true
+ }
+
+ fn at_composite2(&self, n: usize, k1: SyntaxKind, k2: SyntaxKind) -> bool {
+ self.inp.kind(self.pos + n) == k1
+ && self.inp.kind(self.pos + n + 1) == k2
+ && self.inp.is_joint(self.pos + n)
+ }
+
+ fn at_composite3(&self, n: usize, k1: SyntaxKind, k2: SyntaxKind, k3: SyntaxKind) -> bool {
+ self.inp.kind(self.pos + n) == k1
+ && self.inp.kind(self.pos + n + 1) == k2
+ && self.inp.kind(self.pos + n + 2) == k3
+ && self.inp.is_joint(self.pos + n)
+ && self.inp.is_joint(self.pos + n + 1)
+ }
+
+ /// Checks if the current token is in `kinds`.
+ pub(crate) fn at_ts(&self, kinds: TokenSet) -> bool {
+ kinds.contains(self.current())
+ }
+
+ /// Checks if the current token is contextual keyword with text `t`.
+ pub(crate) fn at_contextual_kw(&self, kw: SyntaxKind) -> bool {
+ self.inp.contextual_kind(self.pos) == kw
+ }
+
+ /// Starts a new node in the syntax tree. All nodes and tokens
+ /// consumed between the `start` and the corresponding `Marker::complete`
+ /// belong to the same node.
+ pub(crate) fn start(&mut self) -> Marker {
+ let pos = self.events.len() as u32;
+ self.push_event(Event::tombstone());
+ Marker::new(pos)
+ }
+
+ /// Consume the next token if `kind` matches.
+ pub(crate) fn bump(&mut self, kind: SyntaxKind) {
+ assert!(self.eat(kind));
+ }
+
+ /// Advances the parser by one token
+ pub(crate) fn bump_any(&mut self) {
+ let kind = self.nth(0);
+ if kind == EOF {
+ return;
+ }
+ self.do_bump(kind, 1);
+ }
+
+ /// Advances the parser by one token, remapping its kind.
+ /// This is useful to create contextual keywords from
+ /// identifiers. For example, the lexer creates a `union`
+ /// *identifier* token, but the parser remaps it to the
+ /// `union` keyword, and keyword is what ends up in the
+ /// final tree.
+ pub(crate) fn bump_remap(&mut self, kind: SyntaxKind) {
+ if self.nth(0) == EOF {
+ // FIXME: panic!?
+ return;
+ }
+ self.do_bump(kind, 1);
+ }
+
+ /// Emit error with the `message`
+ /// FIXME: this should be much more fancy and support
+ /// structured errors with spans and notes, like rustc
+ /// does.
+ pub(crate) fn error<T: Into<String>>(&mut self, message: T) {
+ let msg = message.into();
+ self.push_event(Event::Error { msg });
+ }
+
+ /// Consume the next token if it is `kind` or emit an error
+ /// otherwise.
+ pub(crate) fn expect(&mut self, kind: SyntaxKind) -> bool {
+ if self.eat(kind) {
+ return true;
+ }
+ self.error(format!("expected {:?}", kind));
+ false
+ }
+
+ /// Create an error node and consume the next token.
+ pub(crate) fn err_and_bump(&mut self, message: &str) {
+ self.err_recover(message, TokenSet::EMPTY);
+ }
+
+ /// Create an error node and consume the next token.
+ pub(crate) fn err_recover(&mut self, message: &str, recovery: TokenSet) {
+ match self.current() {
+ T!['{'] | T!['}'] => {
+ self.error(message);
+ return;
+ }
+ _ => (),
+ }
+
+ if self.at_ts(recovery) {
+ self.error(message);
+ return;
+ }
+
+ let m = self.start();
+ self.error(message);
+ self.bump_any();
+ m.complete(self, ERROR);
+ }
+
+ fn do_bump(&mut self, kind: SyntaxKind, n_raw_tokens: u8) {
+ self.pos += n_raw_tokens as usize;
+ self.push_event(Event::Token { kind, n_raw_tokens });
+ }
+
+ fn push_event(&mut self, event: Event) {
+ self.events.push(event);
+ }
+}
+
+/// See [`Parser::start`].
+pub(crate) struct Marker {
+ pos: u32,
+ bomb: DropBomb,
+}
+
+impl Marker {
+ fn new(pos: u32) -> Marker {
+ Marker { pos, bomb: DropBomb::new("Marker must be either completed or abandoned") }
+ }
+
+ /// Finishes the syntax tree node and assigns `kind` to it,
+ /// and mark the create a `CompletedMarker` for possible future
+ /// operation like `.precede()` to deal with forward_parent.
+ pub(crate) fn complete(mut self, p: &mut Parser<'_>, kind: SyntaxKind) -> CompletedMarker {
+ self.bomb.defuse();
+ let idx = self.pos as usize;
+ match &mut p.events[idx] {
+ Event::Start { kind: slot, .. } => {
+ *slot = kind;
+ }
+ _ => unreachable!(),
+ }
+ p.push_event(Event::Finish);
+ CompletedMarker::new(self.pos, kind)
+ }
+
+ /// Abandons the syntax tree node. All its children
+ /// are attached to its parent instead.
+ pub(crate) fn abandon(mut self, p: &mut Parser<'_>) {
+ self.bomb.defuse();
+ let idx = self.pos as usize;
+ if idx == p.events.len() - 1 {
+ match p.events.pop() {
+ Some(Event::Start { kind: TOMBSTONE, forward_parent: None }) => (),
+ _ => unreachable!(),
+ }
+ }
+ }
+}
+
+pub(crate) struct CompletedMarker {
+ pos: u32,
+ kind: SyntaxKind,
+}
+
+impl CompletedMarker {
+ fn new(pos: u32, kind: SyntaxKind) -> Self {
+ CompletedMarker { pos, kind }
+ }
+
+ /// This method allows to create a new node which starts
+ /// *before* the current one. That is, parser could start
+ /// node `A`, then complete it, and then after parsing the
+ /// whole `A`, decide that it should have started some node
+ /// `B` before starting `A`. `precede` allows to do exactly
+ /// that. See also docs about
+ /// [`Event::Start::forward_parent`](crate::event::Event::Start::forward_parent).
+ ///
+ /// Given completed events `[START, FINISH]` and its corresponding
+ /// `CompletedMarker(pos: 0, _)`.
+ /// Append a new `START` events as `[START, FINISH, NEWSTART]`,
+ /// then mark `NEWSTART` as `START`'s parent with saving its relative
+ /// distance to `NEWSTART` into forward_parent(=2 in this case);
+ pub(crate) fn precede(self, p: &mut Parser<'_>) -> Marker {
+ let new_pos = p.start();
+ let idx = self.pos as usize;
+ match &mut p.events[idx] {
+ Event::Start { forward_parent, .. } => {
+ *forward_parent = Some(new_pos.pos - self.pos);
+ }
+ _ => unreachable!(),
+ }
+ new_pos
+ }
+
+ /// Extends this completed marker *to the left* up to `m`.
+ pub(crate) fn extend_to(self, p: &mut Parser<'_>, mut m: Marker) -> CompletedMarker {
+ m.bomb.defuse();
+ let idx = m.pos as usize;
+ match &mut p.events[idx] {
+ Event::Start { forward_parent, .. } => {
+ *forward_parent = Some(self.pos - m.pos);
+ }
+ _ => unreachable!(),
+ }
+ self
+ }
+
+ pub(crate) fn kind(&self) -> SyntaxKind {
+ self.kind
+ }
+}
diff --git a/src/tools/rust-analyzer/crates/parser/src/shortcuts.rs b/src/tools/rust-analyzer/crates/parser/src/shortcuts.rs
new file mode 100644
index 000000000..4b805fadd
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/src/shortcuts.rs
@@ -0,0 +1,215 @@
+//! Shortcuts that span lexer/parser abstraction.
+//!
+//! The way Rust works, parser doesn't necessary parse text, and you might
+//! tokenize text without parsing it further. So, it makes sense to keep
+//! abstract token parsing, and string tokenization as completely separate
+//! layers.
+//!
+//! However, often you do pares text into syntax trees and the glue code for
+//! that needs to live somewhere. Rather than putting it to lexer or parser, we
+//! use a separate shortcuts module for that.
+
+use std::mem;
+
+use crate::{
+ LexedStr, Step,
+ SyntaxKind::{self, *},
+};
+
+#[derive(Debug)]
+pub enum StrStep<'a> {
+ Token { kind: SyntaxKind, text: &'a str },
+ Enter { kind: SyntaxKind },
+ Exit,
+ Error { msg: &'a str, pos: usize },
+}
+
+impl<'a> LexedStr<'a> {
+ pub fn to_input(&self) -> crate::Input {
+ let mut res = crate::Input::default();
+ let mut was_joint = false;
+ for i in 0..self.len() {
+ let kind = self.kind(i);
+ if kind.is_trivia() {
+ was_joint = false
+ } else {
+ if kind == SyntaxKind::IDENT {
+ let token_text = self.text(i);
+ let contextual_kw = SyntaxKind::from_contextual_keyword(token_text)
+ .unwrap_or(SyntaxKind::IDENT);
+ res.push_ident(contextual_kw);
+ } else {
+ if was_joint {
+ res.was_joint();
+ }
+ res.push(kind);
+ }
+ was_joint = true;
+ }
+ }
+ res
+ }
+
+ /// NB: only valid to call with Output from Reparser/TopLevelEntry.
+ pub fn intersperse_trivia(
+ &self,
+ output: &crate::Output,
+ sink: &mut dyn FnMut(StrStep<'_>),
+ ) -> bool {
+ let mut builder = Builder { lexed: self, pos: 0, state: State::PendingEnter, sink };
+
+ for event in output.iter() {
+ match event {
+ Step::Token { kind, n_input_tokens: n_raw_tokens } => {
+ builder.token(kind, n_raw_tokens)
+ }
+ Step::Enter { kind } => builder.enter(kind),
+ Step::Exit => builder.exit(),
+ Step::Error { msg } => {
+ let text_pos = builder.lexed.text_start(builder.pos);
+ (builder.sink)(StrStep::Error { msg, pos: text_pos });
+ }
+ }
+ }
+
+ match mem::replace(&mut builder.state, State::Normal) {
+ State::PendingExit => {
+ builder.eat_trivias();
+ (builder.sink)(StrStep::Exit);
+ }
+ State::PendingEnter | State::Normal => unreachable!(),
+ }
+
+ let is_eof = builder.pos == builder.lexed.len();
+ is_eof
+ }
+}
+
+struct Builder<'a, 'b> {
+ lexed: &'a LexedStr<'a>,
+ pos: usize,
+ state: State,
+ sink: &'b mut dyn FnMut(StrStep<'_>),
+}
+
+enum State {
+ PendingEnter,
+ Normal,
+ PendingExit,
+}
+
+impl Builder<'_, '_> {
+ fn token(&mut self, kind: SyntaxKind, n_tokens: u8) {
+ match mem::replace(&mut self.state, State::Normal) {
+ State::PendingEnter => unreachable!(),
+ State::PendingExit => (self.sink)(StrStep::Exit),
+ State::Normal => (),
+ }
+ self.eat_trivias();
+ self.do_token(kind, n_tokens as usize);
+ }
+
+ fn enter(&mut self, kind: SyntaxKind) {
+ match mem::replace(&mut self.state, State::Normal) {
+ State::PendingEnter => {
+ (self.sink)(StrStep::Enter { kind });
+ // No need to attach trivias to previous node: there is no
+ // previous node.
+ return;
+ }
+ State::PendingExit => (self.sink)(StrStep::Exit),
+ State::Normal => (),
+ }
+
+ let n_trivias =
+ (self.pos..self.lexed.len()).take_while(|&it| self.lexed.kind(it).is_trivia()).count();
+ let leading_trivias = self.pos..self.pos + n_trivias;
+ let n_attached_trivias = n_attached_trivias(
+ kind,
+ leading_trivias.rev().map(|it| (self.lexed.kind(it), self.lexed.text(it))),
+ );
+ self.eat_n_trivias(n_trivias - n_attached_trivias);
+ (self.sink)(StrStep::Enter { kind });
+ self.eat_n_trivias(n_attached_trivias);
+ }
+
+ fn exit(&mut self) {
+ match mem::replace(&mut self.state, State::PendingExit) {
+ State::PendingEnter => unreachable!(),
+ State::PendingExit => (self.sink)(StrStep::Exit),
+ State::Normal => (),
+ }
+ }
+
+ fn eat_trivias(&mut self) {
+ while self.pos < self.lexed.len() {
+ let kind = self.lexed.kind(self.pos);
+ if !kind.is_trivia() {
+ break;
+ }
+ self.do_token(kind, 1);
+ }
+ }
+
+ fn eat_n_trivias(&mut self, n: usize) {
+ for _ in 0..n {
+ let kind = self.lexed.kind(self.pos);
+ assert!(kind.is_trivia());
+ self.do_token(kind, 1);
+ }
+ }
+
+ fn do_token(&mut self, kind: SyntaxKind, n_tokens: usize) {
+ let text = &self.lexed.range_text(self.pos..self.pos + n_tokens);
+ self.pos += n_tokens;
+ (self.sink)(StrStep::Token { kind, text });
+ }
+}
+
+fn n_attached_trivias<'a>(
+ kind: SyntaxKind,
+ trivias: impl Iterator<Item = (SyntaxKind, &'a str)>,
+) -> usize {
+ match kind {
+ CONST | ENUM | FN | IMPL | MACRO_CALL | MACRO_DEF | MACRO_RULES | MODULE | RECORD_FIELD
+ | STATIC | STRUCT | TRAIT | TUPLE_FIELD | TYPE_ALIAS | UNION | USE | VARIANT => {
+ let mut res = 0;
+ let mut trivias = trivias.enumerate().peekable();
+
+ while let Some((i, (kind, text))) = trivias.next() {
+ match kind {
+ WHITESPACE if text.contains("\n\n") => {
+ // we check whether the next token is a doc-comment
+ // and skip the whitespace in this case
+ if let Some((COMMENT, peek_text)) = trivias.peek().map(|(_, pair)| pair) {
+ if is_outer(peek_text) {
+ continue;
+ }
+ }
+ break;
+ }
+ COMMENT => {
+ if is_inner(text) {
+ break;
+ }
+ res = i + 1;
+ }
+ _ => (),
+ }
+ }
+ res
+ }
+ _ => 0,
+ }
+}
+
+fn is_outer(text: &str) -> bool {
+ if text.starts_with("////") || text.starts_with("/***") {
+ return false;
+ }
+ text.starts_with("///") || text.starts_with("/**")
+}
+
+fn is_inner(text: &str) -> bool {
+ text.starts_with("//!") || text.starts_with("/*!")
+}
diff --git a/src/tools/rust-analyzer/crates/parser/src/syntax_kind.rs b/src/tools/rust-analyzer/crates/parser/src/syntax_kind.rs
new file mode 100644
index 000000000..0483adc77
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/src/syntax_kind.rs
@@ -0,0 +1,29 @@
+//! Defines [`SyntaxKind`] -- a fieldless enum of all possible syntactic
+//! constructs of the Rust language.
+
+mod generated;
+
+#[allow(unreachable_pub)]
+pub use self::generated::{SyntaxKind, T};
+
+impl From<u16> for SyntaxKind {
+ #[inline]
+ fn from(d: u16) -> SyntaxKind {
+ assert!(d <= (SyntaxKind::__LAST as u16));
+ unsafe { std::mem::transmute::<u16, SyntaxKind>(d) }
+ }
+}
+
+impl From<SyntaxKind> for u16 {
+ #[inline]
+ fn from(k: SyntaxKind) -> u16 {
+ k as u16
+ }
+}
+
+impl SyntaxKind {
+ #[inline]
+ pub fn is_trivia(self) -> bool {
+ matches!(self, SyntaxKind::WHITESPACE | SyntaxKind::COMMENT)
+ }
+}
diff --git a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs
new file mode 100644
index 000000000..628fa745e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs
@@ -0,0 +1,390 @@
+//! Generated by `sourcegen_ast`, do not edit by hand.
+
+#![allow(bad_style, missing_docs, unreachable_pub)]
+#[doc = r" The kind of syntax node, e.g. `IDENT`, `USE_KW`, or `STRUCT`."]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+#[repr(u16)]
+pub enum SyntaxKind {
+ #[doc(hidden)]
+ TOMBSTONE,
+ #[doc(hidden)]
+ EOF,
+ SEMICOLON,
+ COMMA,
+ L_PAREN,
+ R_PAREN,
+ L_CURLY,
+ R_CURLY,
+ L_BRACK,
+ R_BRACK,
+ L_ANGLE,
+ R_ANGLE,
+ AT,
+ POUND,
+ TILDE,
+ QUESTION,
+ DOLLAR,
+ AMP,
+ PIPE,
+ PLUS,
+ STAR,
+ SLASH,
+ CARET,
+ PERCENT,
+ UNDERSCORE,
+ DOT,
+ DOT2,
+ DOT3,
+ DOT2EQ,
+ COLON,
+ COLON2,
+ EQ,
+ EQ2,
+ FAT_ARROW,
+ BANG,
+ NEQ,
+ MINUS,
+ THIN_ARROW,
+ LTEQ,
+ GTEQ,
+ PLUSEQ,
+ MINUSEQ,
+ PIPEEQ,
+ AMPEQ,
+ CARETEQ,
+ SLASHEQ,
+ STAREQ,
+ PERCENTEQ,
+ AMP2,
+ PIPE2,
+ SHL,
+ SHR,
+ SHLEQ,
+ SHREQ,
+ AS_KW,
+ ASYNC_KW,
+ AWAIT_KW,
+ BOX_KW,
+ BREAK_KW,
+ CONST_KW,
+ CONTINUE_KW,
+ CRATE_KW,
+ DYN_KW,
+ ELSE_KW,
+ ENUM_KW,
+ EXTERN_KW,
+ FALSE_KW,
+ FN_KW,
+ FOR_KW,
+ IF_KW,
+ IMPL_KW,
+ IN_KW,
+ LET_KW,
+ LOOP_KW,
+ MACRO_KW,
+ MATCH_KW,
+ MOD_KW,
+ MOVE_KW,
+ MUT_KW,
+ PUB_KW,
+ REF_KW,
+ RETURN_KW,
+ SELF_KW,
+ SELF_TYPE_KW,
+ STATIC_KW,
+ STRUCT_KW,
+ SUPER_KW,
+ TRAIT_KW,
+ TRUE_KW,
+ TRY_KW,
+ TYPE_KW,
+ UNSAFE_KW,
+ USE_KW,
+ WHERE_KW,
+ WHILE_KW,
+ YIELD_KW,
+ AUTO_KW,
+ DEFAULT_KW,
+ EXISTENTIAL_KW,
+ UNION_KW,
+ RAW_KW,
+ MACRO_RULES_KW,
+ INT_NUMBER,
+ FLOAT_NUMBER,
+ CHAR,
+ BYTE,
+ STRING,
+ BYTE_STRING,
+ ERROR,
+ IDENT,
+ WHITESPACE,
+ LIFETIME_IDENT,
+ COMMENT,
+ SHEBANG,
+ SOURCE_FILE,
+ STRUCT,
+ UNION,
+ ENUM,
+ FN,
+ RET_TYPE,
+ EXTERN_CRATE,
+ MODULE,
+ USE,
+ STATIC,
+ CONST,
+ TRAIT,
+ IMPL,
+ TYPE_ALIAS,
+ MACRO_CALL,
+ MACRO_RULES,
+ MACRO_ARM,
+ TOKEN_TREE,
+ MACRO_DEF,
+ PAREN_TYPE,
+ TUPLE_TYPE,
+ MACRO_TYPE,
+ NEVER_TYPE,
+ PATH_TYPE,
+ PTR_TYPE,
+ ARRAY_TYPE,
+ SLICE_TYPE,
+ REF_TYPE,
+ INFER_TYPE,
+ FN_PTR_TYPE,
+ FOR_TYPE,
+ IMPL_TRAIT_TYPE,
+ DYN_TRAIT_TYPE,
+ OR_PAT,
+ PAREN_PAT,
+ REF_PAT,
+ BOX_PAT,
+ IDENT_PAT,
+ WILDCARD_PAT,
+ REST_PAT,
+ PATH_PAT,
+ RECORD_PAT,
+ RECORD_PAT_FIELD_LIST,
+ RECORD_PAT_FIELD,
+ TUPLE_STRUCT_PAT,
+ TUPLE_PAT,
+ SLICE_PAT,
+ RANGE_PAT,
+ LITERAL_PAT,
+ MACRO_PAT,
+ CONST_BLOCK_PAT,
+ TUPLE_EXPR,
+ ARRAY_EXPR,
+ PAREN_EXPR,
+ PATH_EXPR,
+ CLOSURE_EXPR,
+ IF_EXPR,
+ WHILE_EXPR,
+ LOOP_EXPR,
+ FOR_EXPR,
+ CONTINUE_EXPR,
+ BREAK_EXPR,
+ LABEL,
+ BLOCK_EXPR,
+ STMT_LIST,
+ RETURN_EXPR,
+ YIELD_EXPR,
+ LET_EXPR,
+ UNDERSCORE_EXPR,
+ MACRO_EXPR,
+ MATCH_EXPR,
+ MATCH_ARM_LIST,
+ MATCH_ARM,
+ MATCH_GUARD,
+ RECORD_EXPR,
+ RECORD_EXPR_FIELD_LIST,
+ RECORD_EXPR_FIELD,
+ BOX_EXPR,
+ CALL_EXPR,
+ INDEX_EXPR,
+ METHOD_CALL_EXPR,
+ FIELD_EXPR,
+ AWAIT_EXPR,
+ TRY_EXPR,
+ CAST_EXPR,
+ REF_EXPR,
+ PREFIX_EXPR,
+ RANGE_EXPR,
+ BIN_EXPR,
+ EXTERN_BLOCK,
+ EXTERN_ITEM_LIST,
+ VARIANT,
+ RECORD_FIELD_LIST,
+ RECORD_FIELD,
+ TUPLE_FIELD_LIST,
+ TUPLE_FIELD,
+ VARIANT_LIST,
+ ITEM_LIST,
+ ASSOC_ITEM_LIST,
+ ATTR,
+ META,
+ USE_TREE,
+ USE_TREE_LIST,
+ PATH,
+ PATH_SEGMENT,
+ LITERAL,
+ RENAME,
+ VISIBILITY,
+ WHERE_CLAUSE,
+ WHERE_PRED,
+ ABI,
+ NAME,
+ NAME_REF,
+ LET_STMT,
+ LET_ELSE,
+ EXPR_STMT,
+ GENERIC_PARAM_LIST,
+ GENERIC_PARAM,
+ LIFETIME_PARAM,
+ TYPE_PARAM,
+ CONST_PARAM,
+ GENERIC_ARG_LIST,
+ LIFETIME,
+ LIFETIME_ARG,
+ TYPE_ARG,
+ ASSOC_TYPE_ARG,
+ CONST_ARG,
+ PARAM_LIST,
+ PARAM,
+ SELF_PARAM,
+ ARG_LIST,
+ TYPE_BOUND,
+ TYPE_BOUND_LIST,
+ MACRO_ITEMS,
+ MACRO_STMTS,
+ #[doc(hidden)]
+ __LAST,
+}
+use self::SyntaxKind::*;
+impl SyntaxKind {
+ pub fn is_keyword(self) -> bool {
+ match self {
+ AS_KW | ASYNC_KW | AWAIT_KW | BOX_KW | BREAK_KW | CONST_KW | CONTINUE_KW | CRATE_KW
+ | DYN_KW | ELSE_KW | ENUM_KW | EXTERN_KW | FALSE_KW | FN_KW | FOR_KW | IF_KW
+ | IMPL_KW | IN_KW | LET_KW | LOOP_KW | MACRO_KW | MATCH_KW | MOD_KW | MOVE_KW
+ | MUT_KW | PUB_KW | REF_KW | RETURN_KW | SELF_KW | SELF_TYPE_KW | STATIC_KW
+ | STRUCT_KW | SUPER_KW | TRAIT_KW | TRUE_KW | TRY_KW | TYPE_KW | UNSAFE_KW | USE_KW
+ | WHERE_KW | WHILE_KW | YIELD_KW | AUTO_KW | DEFAULT_KW | EXISTENTIAL_KW | UNION_KW
+ | RAW_KW | MACRO_RULES_KW => true,
+ _ => false,
+ }
+ }
+ pub fn is_punct(self) -> bool {
+ match self {
+ SEMICOLON | COMMA | L_PAREN | R_PAREN | L_CURLY | R_CURLY | L_BRACK | R_BRACK
+ | L_ANGLE | R_ANGLE | AT | POUND | TILDE | QUESTION | DOLLAR | AMP | PIPE | PLUS
+ | STAR | SLASH | CARET | PERCENT | UNDERSCORE | DOT | DOT2 | DOT3 | DOT2EQ | COLON
+ | COLON2 | EQ | EQ2 | FAT_ARROW | BANG | NEQ | MINUS | THIN_ARROW | LTEQ | GTEQ
+ | PLUSEQ | MINUSEQ | PIPEEQ | AMPEQ | CARETEQ | SLASHEQ | STAREQ | PERCENTEQ | AMP2
+ | PIPE2 | SHL | SHR | SHLEQ | SHREQ => true,
+ _ => false,
+ }
+ }
+ pub fn is_literal(self) -> bool {
+ match self {
+ INT_NUMBER | FLOAT_NUMBER | CHAR | BYTE | STRING | BYTE_STRING => true,
+ _ => false,
+ }
+ }
+ pub fn from_keyword(ident: &str) -> Option<SyntaxKind> {
+ let kw = match ident {
+ "as" => AS_KW,
+ "async" => ASYNC_KW,
+ "await" => AWAIT_KW,
+ "box" => BOX_KW,
+ "break" => BREAK_KW,
+ "const" => CONST_KW,
+ "continue" => CONTINUE_KW,
+ "crate" => CRATE_KW,
+ "dyn" => DYN_KW,
+ "else" => ELSE_KW,
+ "enum" => ENUM_KW,
+ "extern" => EXTERN_KW,
+ "false" => FALSE_KW,
+ "fn" => FN_KW,
+ "for" => FOR_KW,
+ "if" => IF_KW,
+ "impl" => IMPL_KW,
+ "in" => IN_KW,
+ "let" => LET_KW,
+ "loop" => LOOP_KW,
+ "macro" => MACRO_KW,
+ "match" => MATCH_KW,
+ "mod" => MOD_KW,
+ "move" => MOVE_KW,
+ "mut" => MUT_KW,
+ "pub" => PUB_KW,
+ "ref" => REF_KW,
+ "return" => RETURN_KW,
+ "self" => SELF_KW,
+ "Self" => SELF_TYPE_KW,
+ "static" => STATIC_KW,
+ "struct" => STRUCT_KW,
+ "super" => SUPER_KW,
+ "trait" => TRAIT_KW,
+ "true" => TRUE_KW,
+ "try" => TRY_KW,
+ "type" => TYPE_KW,
+ "unsafe" => UNSAFE_KW,
+ "use" => USE_KW,
+ "where" => WHERE_KW,
+ "while" => WHILE_KW,
+ "yield" => YIELD_KW,
+ _ => return None,
+ };
+ Some(kw)
+ }
+ pub fn from_contextual_keyword(ident: &str) -> Option<SyntaxKind> {
+ let kw = match ident {
+ "auto" => AUTO_KW,
+ "default" => DEFAULT_KW,
+ "existential" => EXISTENTIAL_KW,
+ "union" => UNION_KW,
+ "raw" => RAW_KW,
+ "macro_rules" => MACRO_RULES_KW,
+ _ => return None,
+ };
+ Some(kw)
+ }
+ pub fn from_char(c: char) -> Option<SyntaxKind> {
+ let tok = match c {
+ ';' => SEMICOLON,
+ ',' => COMMA,
+ '(' => L_PAREN,
+ ')' => R_PAREN,
+ '{' => L_CURLY,
+ '}' => R_CURLY,
+ '[' => L_BRACK,
+ ']' => R_BRACK,
+ '<' => L_ANGLE,
+ '>' => R_ANGLE,
+ '@' => AT,
+ '#' => POUND,
+ '~' => TILDE,
+ '?' => QUESTION,
+ '$' => DOLLAR,
+ '&' => AMP,
+ '|' => PIPE,
+ '+' => PLUS,
+ '*' => STAR,
+ '/' => SLASH,
+ '^' => CARET,
+ '%' => PERCENT,
+ '_' => UNDERSCORE,
+ '.' => DOT,
+ ':' => COLON,
+ '=' => EQ,
+ '!' => BANG,
+ '-' => MINUS,
+ _ => return None,
+ };
+ Some(tok)
+ }
+}
+#[macro_export]
+macro_rules ! T { [;] => { $ crate :: SyntaxKind :: SEMICOLON } ; [,] => { $ crate :: SyntaxKind :: COMMA } ; ['('] => { $ crate :: SyntaxKind :: L_PAREN } ; [')'] => { $ crate :: SyntaxKind :: R_PAREN } ; ['{'] => { $ crate :: SyntaxKind :: L_CURLY } ; ['}'] => { $ crate :: SyntaxKind :: R_CURLY } ; ['['] => { $ crate :: SyntaxKind :: L_BRACK } ; [']'] => { $ crate :: SyntaxKind :: R_BRACK } ; [<] => { $ crate :: SyntaxKind :: L_ANGLE } ; [>] => { $ crate :: SyntaxKind :: R_ANGLE } ; [@] => { $ crate :: SyntaxKind :: AT } ; [#] => { $ crate :: SyntaxKind :: POUND } ; [~] => { $ crate :: SyntaxKind :: TILDE } ; [?] => { $ crate :: SyntaxKind :: QUESTION } ; [$] => { $ crate :: SyntaxKind :: DOLLAR } ; [&] => { $ crate :: SyntaxKind :: AMP } ; [|] => { $ crate :: SyntaxKind :: PIPE } ; [+] => { $ crate :: SyntaxKind :: PLUS } ; [*] => { $ crate :: SyntaxKind :: STAR } ; [/] => { $ crate :: SyntaxKind :: SLASH } ; [^] => { $ crate :: SyntaxKind :: CARET } ; [%] => { $ crate :: SyntaxKind :: PERCENT } ; [_] => { $ crate :: SyntaxKind :: UNDERSCORE } ; [.] => { $ crate :: SyntaxKind :: DOT } ; [..] => { $ crate :: SyntaxKind :: DOT2 } ; [...] => { $ crate :: SyntaxKind :: DOT3 } ; [..=] => { $ crate :: SyntaxKind :: DOT2EQ } ; [:] => { $ crate :: SyntaxKind :: COLON } ; [::] => { $ crate :: SyntaxKind :: COLON2 } ; [=] => { $ crate :: SyntaxKind :: EQ } ; [==] => { $ crate :: SyntaxKind :: EQ2 } ; [=>] => { $ crate :: SyntaxKind :: FAT_ARROW } ; [!] => { $ crate :: SyntaxKind :: BANG } ; [!=] => { $ crate :: SyntaxKind :: NEQ } ; [-] => { $ crate :: SyntaxKind :: MINUS } ; [->] => { $ crate :: SyntaxKind :: THIN_ARROW } ; [<=] => { $ crate :: SyntaxKind :: LTEQ } ; [>=] => { $ crate :: SyntaxKind :: GTEQ } ; [+=] => { $ crate :: SyntaxKind :: PLUSEQ } ; [-=] => { $ crate :: SyntaxKind :: MINUSEQ } ; [|=] => { $ crate :: SyntaxKind :: PIPEEQ } ; [&=] => { $ crate :: SyntaxKind :: AMPEQ } ; [^=] => { $ crate :: SyntaxKind :: CARETEQ } ; [/=] => { $ crate :: SyntaxKind :: SLASHEQ } ; [*=] => { $ crate :: SyntaxKind :: STAREQ } ; [%=] => { $ crate :: SyntaxKind :: PERCENTEQ } ; [&&] => { $ crate :: SyntaxKind :: AMP2 } ; [||] => { $ crate :: SyntaxKind :: PIPE2 } ; [<<] => { $ crate :: SyntaxKind :: SHL } ; [>>] => { $ crate :: SyntaxKind :: SHR } ; [<<=] => { $ crate :: SyntaxKind :: SHLEQ } ; [>>=] => { $ crate :: SyntaxKind :: SHREQ } ; [as] => { $ crate :: SyntaxKind :: AS_KW } ; [async] => { $ crate :: SyntaxKind :: ASYNC_KW } ; [await] => { $ crate :: SyntaxKind :: AWAIT_KW } ; [box] => { $ crate :: SyntaxKind :: BOX_KW } ; [break] => { $ crate :: SyntaxKind :: BREAK_KW } ; [const] => { $ crate :: SyntaxKind :: CONST_KW } ; [continue] => { $ crate :: SyntaxKind :: CONTINUE_KW } ; [crate] => { $ crate :: SyntaxKind :: CRATE_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [else] => { $ crate :: SyntaxKind :: ELSE_KW } ; [enum] => { $ crate :: SyntaxKind :: ENUM_KW } ; [extern] => { $ crate :: SyntaxKind :: EXTERN_KW } ; [false] => { $ crate :: SyntaxKind :: FALSE_KW } ; [fn] => { $ crate :: SyntaxKind :: FN_KW } ; [for] => { $ crate :: SyntaxKind :: FOR_KW } ; [if] => { $ crate :: SyntaxKind :: IF_KW } ; [impl] => { $ crate :: SyntaxKind :: IMPL_KW } ; [in] => { $ crate :: SyntaxKind :: IN_KW } ; [let] => { $ crate :: SyntaxKind :: LET_KW } ; [loop] => { $ crate :: SyntaxKind :: LOOP_KW } ; [macro] => { $ crate :: SyntaxKind :: MACRO_KW } ; [match] => { $ crate :: SyntaxKind :: MATCH_KW } ; [mod] => { $ crate :: SyntaxKind :: MOD_KW } ; [move] => { $ crate :: SyntaxKind :: MOVE_KW } ; [mut] => { $ crate :: SyntaxKind :: MUT_KW } ; [pub] => { $ crate :: SyntaxKind :: PUB_KW } ; [ref] => { $ crate :: SyntaxKind :: REF_KW } ; [return] => { $ crate :: SyntaxKind :: RETURN_KW } ; [self] => { $ crate :: SyntaxKind :: SELF_KW } ; [Self] => { $ crate :: SyntaxKind :: SELF_TYPE_KW } ; [static] => { $ crate :: SyntaxKind :: STATIC_KW } ; [struct] => { $ crate :: SyntaxKind :: STRUCT_KW } ; [super] => { $ crate :: SyntaxKind :: SUPER_KW } ; [trait] => { $ crate :: SyntaxKind :: TRAIT_KW } ; [true] => { $ crate :: SyntaxKind :: TRUE_KW } ; [try] => { $ crate :: SyntaxKind :: TRY_KW } ; [type] => { $ crate :: SyntaxKind :: TYPE_KW } ; [unsafe] => { $ crate :: SyntaxKind :: UNSAFE_KW } ; [use] => { $ crate :: SyntaxKind :: USE_KW } ; [where] => { $ crate :: SyntaxKind :: WHERE_KW } ; [while] => { $ crate :: SyntaxKind :: WHILE_KW } ; [yield] => { $ crate :: SyntaxKind :: YIELD_KW } ; [auto] => { $ crate :: SyntaxKind :: AUTO_KW } ; [default] => { $ crate :: SyntaxKind :: DEFAULT_KW } ; [existential] => { $ crate :: SyntaxKind :: EXISTENTIAL_KW } ; [union] => { $ crate :: SyntaxKind :: UNION_KW } ; [raw] => { $ crate :: SyntaxKind :: RAW_KW } ; [macro_rules] => { $ crate :: SyntaxKind :: MACRO_RULES_KW } ; [lifetime_ident] => { $ crate :: SyntaxKind :: LIFETIME_IDENT } ; [ident] => { $ crate :: SyntaxKind :: IDENT } ; [shebang] => { $ crate :: SyntaxKind :: SHEBANG } ; }
+pub use T;
diff --git a/src/tools/rust-analyzer/crates/parser/src/tests.rs b/src/tools/rust-analyzer/crates/parser/src/tests.rs
new file mode 100644
index 000000000..735c0b3e4
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/src/tests.rs
@@ -0,0 +1,166 @@
+mod sourcegen_inline_tests;
+mod top_entries;
+mod prefix_entries;
+
+use std::{
+ fmt::Write,
+ fs,
+ path::{Path, PathBuf},
+};
+
+use expect_test::expect_file;
+
+use crate::{LexedStr, TopEntryPoint};
+
+#[test]
+fn lex_ok() {
+ for case in TestCase::list("lexer/ok") {
+ let actual = lex(&case.text);
+ expect_file![case.rast].assert_eq(&actual)
+ }
+}
+
+#[test]
+fn lex_err() {
+ for case in TestCase::list("lexer/err") {
+ let actual = lex(&case.text);
+ expect_file![case.rast].assert_eq(&actual)
+ }
+}
+
+fn lex(text: &str) -> String {
+ let lexed = LexedStr::new(text);
+
+ let mut res = String::new();
+ for i in 0..lexed.len() {
+ let kind = lexed.kind(i);
+ let text = lexed.text(i);
+ let error = lexed.error(i);
+
+ let error = error.map(|err| format!(" error: {}", err)).unwrap_or_default();
+ writeln!(res, "{:?} {:?}{}", kind, text, error).unwrap();
+ }
+ res
+}
+
+#[test]
+fn parse_ok() {
+ for case in TestCase::list("parser/ok") {
+ let (actual, errors) = parse(TopEntryPoint::SourceFile, &case.text);
+ assert!(!errors, "errors in an OK file {}:\n{}", case.rs.display(), actual);
+ expect_file![case.rast].assert_eq(&actual);
+ }
+}
+
+#[test]
+fn parse_inline_ok() {
+ for case in TestCase::list("parser/inline/ok") {
+ let (actual, errors) = parse(TopEntryPoint::SourceFile, &case.text);
+ assert!(!errors, "errors in an OK file {}:\n{}", case.rs.display(), actual);
+ expect_file![case.rast].assert_eq(&actual);
+ }
+}
+
+#[test]
+fn parse_err() {
+ for case in TestCase::list("parser/err") {
+ let (actual, errors) = parse(TopEntryPoint::SourceFile, &case.text);
+ assert!(errors, "no errors in an ERR file {}:\n{}", case.rs.display(), actual);
+ expect_file![case.rast].assert_eq(&actual)
+ }
+}
+
+#[test]
+fn parse_inline_err() {
+ for case in TestCase::list("parser/inline/err") {
+ let (actual, errors) = parse(TopEntryPoint::SourceFile, &case.text);
+ assert!(errors, "no errors in an ERR file {}:\n{}", case.rs.display(), actual);
+ expect_file![case.rast].assert_eq(&actual)
+ }
+}
+
+fn parse(entry: TopEntryPoint, text: &str) -> (String, bool) {
+ let lexed = LexedStr::new(text);
+ let input = lexed.to_input();
+ let output = entry.parse(&input);
+
+ let mut buf = String::new();
+ let mut errors = Vec::new();
+ let mut indent = String::new();
+ let mut depth = 0;
+ let mut len = 0;
+ lexed.intersperse_trivia(&output, &mut |step| match step {
+ crate::StrStep::Token { kind, text } => {
+ assert!(depth > 0);
+ len += text.len();
+ write!(buf, "{}", indent).unwrap();
+ write!(buf, "{:?} {:?}\n", kind, text).unwrap();
+ }
+ crate::StrStep::Enter { kind } => {
+ assert!(depth > 0 || len == 0);
+ depth += 1;
+ write!(buf, "{}", indent).unwrap();
+ write!(buf, "{:?}\n", kind).unwrap();
+ indent.push_str(" ");
+ }
+ crate::StrStep::Exit => {
+ assert!(depth > 0);
+ depth -= 1;
+ indent.pop();
+ indent.pop();
+ }
+ crate::StrStep::Error { msg, pos } => {
+ assert!(depth > 0);
+ errors.push(format!("error {}: {}\n", pos, msg))
+ }
+ });
+ assert_eq!(
+ len,
+ text.len(),
+ "didn't parse all text.\nParsed:\n{}\n\nAll:\n{}\n",
+ &text[..len],
+ text
+ );
+
+ for (token, msg) in lexed.errors() {
+ let pos = lexed.text_start(token);
+ errors.push(format!("error {}: {}\n", pos, msg));
+ }
+
+ let has_errors = !errors.is_empty();
+ for e in errors {
+ buf.push_str(&e);
+ }
+ (buf, has_errors)
+}
+
+#[derive(PartialEq, Eq, PartialOrd, Ord)]
+struct TestCase {
+ rs: PathBuf,
+ rast: PathBuf,
+ text: String,
+}
+
+impl TestCase {
+ fn list(path: &'static str) -> Vec<TestCase> {
+ let crate_root_dir = Path::new(env!("CARGO_MANIFEST_DIR"));
+ let test_data_dir = crate_root_dir.join("test_data");
+ let dir = test_data_dir.join(path);
+
+ let mut res = Vec::new();
+ let read_dir = fs::read_dir(&dir)
+ .unwrap_or_else(|err| panic!("can't `read_dir` {}: {}", dir.display(), err));
+ for file in read_dir {
+ let file = file.unwrap();
+ let path = file.path();
+ if path.extension().unwrap_or_default() == "rs" {
+ let rs = path;
+ let rast = rs.with_extension("rast");
+ let text = fs::read_to_string(&rs).unwrap();
+ res.push(TestCase { rs, rast, text });
+ }
+ }
+ res.sort();
+ res
+ }
+}
diff --git a/src/tools/rust-analyzer/crates/parser/src/tests/prefix_entries.rs b/src/tools/rust-analyzer/crates/parser/src/tests/prefix_entries.rs
new file mode 100644
index 000000000..e626b4f27
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/src/tests/prefix_entries.rs
@@ -0,0 +1,107 @@
+use crate::{LexedStr, PrefixEntryPoint, Step};
+
+#[test]
+fn vis() {
+ check(PrefixEntryPoint::Vis, "pub(crate) fn foo() {}", "pub(crate)");
+ check(PrefixEntryPoint::Vis, "fn foo() {}", "");
+ check(PrefixEntryPoint::Vis, "pub(fn foo() {}", "pub");
+ check(PrefixEntryPoint::Vis, "pub(crate fn foo() {}", "pub(crate");
+ check(PrefixEntryPoint::Vis, "crate fn foo() {}", "crate");
+}
+
+#[test]
+fn block() {
+ check(PrefixEntryPoint::Block, "{}, 92", "{}");
+ check(PrefixEntryPoint::Block, "{, 92)", "{, 92)");
+ check(PrefixEntryPoint::Block, "()", "");
+}
+
+#[test]
+fn stmt() {
+ check(PrefixEntryPoint::Stmt, "92; fn", "92");
+ check(PrefixEntryPoint::Stmt, "let _ = 92; 1", "let _ = 92");
+ check(PrefixEntryPoint::Stmt, "pub fn f() {} = 92", "pub fn f() {}");
+ check(PrefixEntryPoint::Stmt, "struct S;;", "struct S;");
+ check(PrefixEntryPoint::Stmt, "fn f() {};", "fn f() {}");
+ check(PrefixEntryPoint::Stmt, ";;;", ";");
+ check(PrefixEntryPoint::Stmt, "+", "+");
+ check(PrefixEntryPoint::Stmt, "@", "@");
+ check(PrefixEntryPoint::Stmt, "loop {} - 1", "loop {}");
+}
+
+#[test]
+fn pat() {
+ check(PrefixEntryPoint::Pat, "x y", "x");
+ check(PrefixEntryPoint::Pat, "fn f() {}", "fn");
+ // FIXME: This one is wrong, we should consume only one pattern.
+ check(PrefixEntryPoint::Pat, ".. ..", ".. ..");
+}
+
+#[test]
+fn ty() {
+ check(PrefixEntryPoint::Ty, "fn() foo", "fn()");
+ check(PrefixEntryPoint::Ty, "Clone + Copy + fn", "Clone + Copy +");
+ check(PrefixEntryPoint::Ty, "struct f", "struct");
+}
+
+#[test]
+fn expr() {
+ check(PrefixEntryPoint::Expr, "92 92", "92");
+ check(PrefixEntryPoint::Expr, "+1", "+");
+ check(PrefixEntryPoint::Expr, "-1", "-1");
+ check(PrefixEntryPoint::Expr, "fn foo() {}", "fn");
+ check(PrefixEntryPoint::Expr, "#[attr] ()", "#[attr] ()");
+}
+
+#[test]
+fn path() {
+ check(PrefixEntryPoint::Path, "foo::bar baz", "foo::bar");
+ check(PrefixEntryPoint::Path, "foo::<> baz", "foo::<>");
+ check(PrefixEntryPoint::Path, "foo<> baz", "foo<>");
+ check(PrefixEntryPoint::Path, "Fn() -> i32?", "Fn() -> i32");
+ // FIXME: This shouldn't be accepted as path actually.
+ check(PrefixEntryPoint::Path, "<_>::foo", "<_>::foo");
+}
+
+#[test]
+fn item() {
+ // FIXME: This shouldn't consume the semicolon.
+ check(PrefixEntryPoint::Item, "fn foo() {};", "fn foo() {};");
+ check(PrefixEntryPoint::Item, "#[attr] pub struct S {} 92", "#[attr] pub struct S {}");
+ check(PrefixEntryPoint::Item, "item!{}?", "item!{}");
+ check(PrefixEntryPoint::Item, "????", "?");
+}
+
+#[test]
+fn meta_item() {
+ check(PrefixEntryPoint::MetaItem, "attr, ", "attr");
+ check(PrefixEntryPoint::MetaItem, "attr(some token {stream});", "attr(some token {stream})");
+ check(PrefixEntryPoint::MetaItem, "path::attr = 2 * 2!", "path::attr = 2 * 2");
+}
+
+#[track_caller]
+fn check(entry: PrefixEntryPoint, input: &str, prefix: &str) {
+ let lexed = LexedStr::new(input);
+ let input = lexed.to_input();
+
+ let mut n_tokens = 0;
+ for step in entry.parse(&input).iter() {
+ match step {
+ Step::Token { n_input_tokens, .. } => n_tokens += n_input_tokens as usize,
+ Step::Enter { .. } | Step::Exit | Step::Error { .. } => (),
+ }
+ }
+
+ let mut i = 0;
+ loop {
+ if n_tokens == 0 {
+ break;
+ }
+ if !lexed.kind(i).is_trivia() {
+ n_tokens -= 1;
+ }
+ i += 1;
+ }
+ let buf = &lexed.as_str()[..lexed.text_start(i)];
+ assert_eq!(buf, prefix);
+}
diff --git a/src/tools/rust-analyzer/crates/parser/src/tests/sourcegen_inline_tests.rs b/src/tools/rust-analyzer/crates/parser/src/tests/sourcegen_inline_tests.rs
new file mode 100644
index 000000000..7b2b703de
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/src/tests/sourcegen_inline_tests.rs
@@ -0,0 +1,123 @@
+//! This module greps parser's code for specially formatted comments and turns
+//! them into tests.
+
+use std::{
+ collections::HashMap,
+ fs, iter,
+ path::{Path, PathBuf},
+};
+
+#[test]
+fn sourcegen_parser_tests() {
+ let grammar_dir = sourcegen::project_root().join(Path::new("crates/parser/src/grammar"));
+ let tests = tests_from_dir(&grammar_dir);
+
+ install_tests(&tests.ok, "crates/parser/test_data/parser/inline/ok");
+ install_tests(&tests.err, "crates/parser/test_data/parser/inline/err");
+
+ fn install_tests(tests: &HashMap<String, Test>, into: &str) {
+ let tests_dir = sourcegen::project_root().join(into);
+ if !tests_dir.is_dir() {
+ fs::create_dir_all(&tests_dir).unwrap();
+ }
+ // ok is never actually read, but it needs to be specified to create a Test in existing_tests
+ let existing = existing_tests(&tests_dir, true);
+ for t in existing.keys().filter(|&t| !tests.contains_key(t)) {
+ panic!("Test is deleted: {}", t);
+ }
+
+ let mut new_idx = existing.len() + 1;
+ for (name, test) in tests {
+ let path = match existing.get(name) {
+ Some((path, _test)) => path.clone(),
+ None => {
+ let file_name = format!("{:04}_{}.rs", new_idx, name);
+ new_idx += 1;
+ tests_dir.join(file_name)
+ }
+ };
+ sourcegen::ensure_file_contents(&path, &test.text);
+ }
+ }
+}
+
+#[derive(Debug)]
+struct Test {
+ name: String,
+ text: String,
+ ok: bool,
+}
+
+#[derive(Default, Debug)]
+struct Tests {
+ ok: HashMap<String, Test>,
+ err: HashMap<String, Test>,
+}
+
+fn collect_tests(s: &str) -> Vec<Test> {
+ let mut res = Vec::new();
+ for comment_block in sourcegen::CommentBlock::extract_untagged(s) {
+ let first_line = &comment_block.contents[0];
+ let (name, ok) = if let Some(name) = first_line.strip_prefix("test ") {
+ (name.to_string(), true)
+ } else if let Some(name) = first_line.strip_prefix("test_err ") {
+ (name.to_string(), false)
+ } else {
+ continue;
+ };
+ let text: String = comment_block.contents[1..]
+ .iter()
+ .cloned()
+ .chain(iter::once(String::new()))
+ .collect::<Vec<_>>()
+ .join("\n");
+ assert!(!text.trim().is_empty() && text.ends_with('\n'));
+ res.push(Test { name, text, ok })
+ }
+ res
+}
+
+fn tests_from_dir(dir: &Path) -> Tests {
+ let mut res = Tests::default();
+ for entry in sourcegen::list_rust_files(dir) {
+ process_file(&mut res, entry.as_path());
+ }
+ let grammar_rs = dir.parent().unwrap().join("grammar.rs");
+ process_file(&mut res, &grammar_rs);
+ return res;
+
+ fn process_file(res: &mut Tests, path: &Path) {
+ let text = fs::read_to_string(path).unwrap();
+
+ for test in collect_tests(&text) {
+ if test.ok {
+ if let Some(old_test) = res.ok.insert(test.name.clone(), test) {
+ panic!("Duplicate test: {}", old_test.name);
+ }
+ } else if let Some(old_test) = res.err.insert(test.name.clone(), test) {
+ panic!("Duplicate test: {}", old_test.name);
+ }
+ }
+ }
+}
+
+fn existing_tests(dir: &Path, ok: bool) -> HashMap<String, (PathBuf, Test)> {
+ let mut res = HashMap::default();
+ for file in fs::read_dir(dir).unwrap() {
+ let file = file.unwrap();
+ let path = file.path();
+ if path.extension().unwrap_or_default() != "rs" {
+ continue;
+ }
+ let name = {
+ let file_name = path.file_name().unwrap().to_str().unwrap();
+ file_name[5..file_name.len() - 3].to_string()
+ };
+ let text = fs::read_to_string(&path).unwrap();
+ let test = Test { name: name.clone(), text, ok };
+ if let Some(old) = res.insert(name, (path, test)) {
+ println!("Duplicate test: {:?}", old);
+ }
+ }
+ res
+}
diff --git a/src/tools/rust-analyzer/crates/parser/src/tests/top_entries.rs b/src/tools/rust-analyzer/crates/parser/src/tests/top_entries.rs
new file mode 100644
index 000000000..eb640dc7f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/src/tests/top_entries.rs
@@ -0,0 +1,312 @@
+use expect_test::expect;
+
+use crate::TopEntryPoint;
+
+#[test]
+fn source_file() {
+ check(
+ TopEntryPoint::SourceFile,
+ "",
+ expect![[r#"
+ SOURCE_FILE
+ "#]],
+ );
+
+ check(
+ TopEntryPoint::SourceFile,
+ "struct S;",
+ expect![[r#"
+ SOURCE_FILE
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S"
+ SEMICOLON ";"
+ "#]],
+ );
+
+ check(
+ TopEntryPoint::SourceFile,
+ "@error@",
+ expect![[r#"
+ SOURCE_FILE
+ ERROR
+ AT "@"
+ MACRO_CALL
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "error"
+ ERROR
+ AT "@"
+ error 0: expected an item
+ error 6: expected BANG
+ error 6: expected `{`, `[`, `(`
+ error 6: expected SEMICOLON
+ error 6: expected an item
+ "#]],
+ );
+}
+
+#[test]
+fn macro_stmt() {
+ check(
+ TopEntryPoint::MacroStmts,
+ "",
+ expect![[r#"
+ MACRO_STMTS
+ "#]],
+ );
+ check(
+ TopEntryPoint::MacroStmts,
+ "#!/usr/bin/rust",
+ expect![[r##"
+ MACRO_STMTS
+ ERROR
+ SHEBANG "#!/usr/bin/rust"
+ error 0: expected expression
+ "##]],
+ );
+ check(
+ TopEntryPoint::MacroStmts,
+ "let x = 1 2 struct S;",
+ expect![[r#"
+ MACRO_STMTS
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "x"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "1"
+ WHITESPACE " "
+ EXPR_STMT
+ LITERAL
+ INT_NUMBER "2"
+ WHITESPACE " "
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S"
+ SEMICOLON ";"
+ "#]],
+ );
+}
+
+#[test]
+fn macro_items() {
+ check(
+ TopEntryPoint::MacroItems,
+ "",
+ expect![[r#"
+ MACRO_ITEMS
+ "#]],
+ );
+ check(
+ TopEntryPoint::MacroItems,
+ "#!/usr/bin/rust",
+ expect![[r##"
+ MACRO_ITEMS
+ ERROR
+ SHEBANG "#!/usr/bin/rust"
+ error 0: expected an item
+ "##]],
+ );
+ check(
+ TopEntryPoint::MacroItems,
+ "struct S; foo!{}",
+ expect![[r#"
+ MACRO_ITEMS
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S"
+ SEMICOLON ";"
+ WHITESPACE " "
+ MACRO_CALL
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "foo"
+ BANG "!"
+ TOKEN_TREE
+ L_CURLY "{"
+ R_CURLY "}"
+ "#]],
+ );
+}
+
+#[test]
+fn macro_pattern() {
+ check(
+ TopEntryPoint::Pattern,
+ "",
+ expect![[r#"
+ ERROR
+ error 0: expected pattern
+ "#]],
+ );
+ check(
+ TopEntryPoint::Pattern,
+ "Some(_)",
+ expect![[r#"
+ TUPLE_STRUCT_PAT
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Some"
+ L_PAREN "("
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ R_PAREN ")"
+ "#]],
+ );
+
+ check(
+ TopEntryPoint::Pattern,
+ "None leftover tokens",
+ expect![[r#"
+ ERROR
+ IDENT_PAT
+ NAME
+ IDENT "None"
+ WHITESPACE " "
+ IDENT "leftover"
+ WHITESPACE " "
+ IDENT "tokens"
+ "#]],
+ );
+
+ check(
+ TopEntryPoint::Pattern,
+ "@err",
+ expect![[r#"
+ ERROR
+ ERROR
+ AT "@"
+ IDENT "err"
+ error 0: expected pattern
+ "#]],
+ );
+}
+
+#[test]
+fn type_() {
+ check(
+ TopEntryPoint::Type,
+ "",
+ expect![[r#"
+ ERROR
+ error 0: expected type
+ "#]],
+ );
+
+ check(
+ TopEntryPoint::Type,
+ "Option<!>",
+ expect![[r#"
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Option"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ TYPE_ARG
+ NEVER_TYPE
+ BANG "!"
+ R_ANGLE ">"
+ "#]],
+ );
+ check(
+ TopEntryPoint::Type,
+ "() () ()",
+ expect![[r#"
+ ERROR
+ TUPLE_TYPE
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ L_PAREN "("
+ R_PAREN ")"
+ "#]],
+ );
+ check(
+ TopEntryPoint::Type,
+ "$$$",
+ expect![[r#"
+ ERROR
+ ERROR
+ DOLLAR "$"
+ DOLLAR "$"
+ DOLLAR "$"
+ error 0: expected type
+ "#]],
+ );
+}
+
+#[test]
+fn expr() {
+ check(
+ TopEntryPoint::Expr,
+ "",
+ expect![[r#"
+ ERROR
+ error 0: expected expression
+ "#]],
+ );
+ check(
+ TopEntryPoint::Expr,
+ "2 + 2 == 5",
+ expect![[r#"
+ BIN_EXPR
+ BIN_EXPR
+ LITERAL
+ INT_NUMBER "2"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "2"
+ WHITESPACE " "
+ EQ2 "=="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "5"
+ "#]],
+ );
+ check(
+ TopEntryPoint::Expr,
+ "let _ = 0;",
+ expect![[r#"
+ ERROR
+ LET_EXPR
+ LET_KW "let"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "0"
+ SEMICOLON ";"
+ "#]],
+ );
+}
+
+#[track_caller]
+fn check(entry: TopEntryPoint, input: &str, expect: expect_test::Expect) {
+ let (parsed, _errors) = super::parse(entry, input);
+ expect.assert_eq(&parsed)
+}
diff --git a/src/tools/rust-analyzer/crates/parser/src/token_set.rs b/src/tools/rust-analyzer/crates/parser/src/token_set.rs
new file mode 100644
index 000000000..cd4894c1e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/src/token_set.rs
@@ -0,0 +1,42 @@
+//! A bit-set of `SyntaxKind`s.
+
+use crate::SyntaxKind;
+
+/// A bit-set of `SyntaxKind`s
+#[derive(Clone, Copy)]
+pub(crate) struct TokenSet(u128);
+
+impl TokenSet {
+ pub(crate) const EMPTY: TokenSet = TokenSet(0);
+
+ pub(crate) const fn new(kinds: &[SyntaxKind]) -> TokenSet {
+ let mut res = 0u128;
+ let mut i = 0;
+ while i < kinds.len() {
+ res |= mask(kinds[i]);
+ i += 1;
+ }
+ TokenSet(res)
+ }
+
+ pub(crate) const fn union(self, other: TokenSet) -> TokenSet {
+ TokenSet(self.0 | other.0)
+ }
+
+ pub(crate) const fn contains(&self, kind: SyntaxKind) -> bool {
+ self.0 & mask(kind) != 0
+ }
+}
+
+const fn mask(kind: SyntaxKind) -> u128 {
+ 1u128 << (kind as usize)
+}
+
+#[test]
+fn token_set_works_for_tokens() {
+ use crate::SyntaxKind::*;
+ let ts = TokenSet::new(&[EOF, SHEBANG]);
+ assert!(ts.contains(EOF));
+ assert!(ts.contains(SHEBANG));
+ assert!(!ts.contains(PLUS));
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/empty_exponent.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/empty_exponent.rast
new file mode 100644
index 000000000..af03d73ce
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/empty_exponent.rast
@@ -0,0 +1,48 @@
+FLOAT_NUMBER "0e" error: Missing digits after the exponent symbol
+WHITESPACE "\n"
+FLOAT_NUMBER "0E" error: Missing digits after the exponent symbol
+WHITESPACE "\n\n"
+FLOAT_NUMBER "42e+" error: Missing digits after the exponent symbol
+WHITESPACE "\n"
+FLOAT_NUMBER "42e-" error: Missing digits after the exponent symbol
+WHITESPACE "\n"
+FLOAT_NUMBER "42E+" error: Missing digits after the exponent symbol
+WHITESPACE "\n"
+FLOAT_NUMBER "42E-" error: Missing digits after the exponent symbol
+WHITESPACE "\n\n"
+INT_NUMBER "42"
+DOT "."
+IDENT "e"
+PLUS "+"
+WHITESPACE "\n"
+INT_NUMBER "42"
+DOT "."
+IDENT "e"
+MINUS "-"
+WHITESPACE "\n"
+INT_NUMBER "42"
+DOT "."
+IDENT "E"
+PLUS "+"
+WHITESPACE "\n"
+INT_NUMBER "42"
+DOT "."
+IDENT "E"
+MINUS "-"
+WHITESPACE "\n\n"
+FLOAT_NUMBER "42.2e+" error: Missing digits after the exponent symbol
+WHITESPACE "\n"
+FLOAT_NUMBER "42.2e-" error: Missing digits after the exponent symbol
+WHITESPACE "\n"
+FLOAT_NUMBER "42.2E+" error: Missing digits after the exponent symbol
+WHITESPACE "\n"
+FLOAT_NUMBER "42.2E-" error: Missing digits after the exponent symbol
+WHITESPACE "\n\n"
+FLOAT_NUMBER "42.2e+f32" error: Missing digits after the exponent symbol
+WHITESPACE "\n"
+FLOAT_NUMBER "42.2e-f32" error: Missing digits after the exponent symbol
+WHITESPACE "\n"
+FLOAT_NUMBER "42.2E+f32" error: Missing digits after the exponent symbol
+WHITESPACE "\n"
+FLOAT_NUMBER "42.2E-f32" error: Missing digits after the exponent symbol
+WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/empty_exponent.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/empty_exponent.rs
new file mode 100644
index 000000000..286584c88
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/empty_exponent.rs
@@ -0,0 +1,22 @@
+0e
+0E
+
+42e+
+42e-
+42E+
+42E-
+
+42.e+
+42.e-
+42.E+
+42.E-
+
+42.2e+
+42.2e-
+42.2E+
+42.2E-
+
+42.2e+f32
+42.2e-f32
+42.2E+f32
+42.2E-f32
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/empty_exponent.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/empty_exponent.txt
new file mode 100644
index 000000000..af03d73ce
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/empty_exponent.txt
@@ -0,0 +1,48 @@
+FLOAT_NUMBER "0e" error: Missing digits after the exponent symbol
+WHITESPACE "\n"
+FLOAT_NUMBER "0E" error: Missing digits after the exponent symbol
+WHITESPACE "\n\n"
+FLOAT_NUMBER "42e+" error: Missing digits after the exponent symbol
+WHITESPACE "\n"
+FLOAT_NUMBER "42e-" error: Missing digits after the exponent symbol
+WHITESPACE "\n"
+FLOAT_NUMBER "42E+" error: Missing digits after the exponent symbol
+WHITESPACE "\n"
+FLOAT_NUMBER "42E-" error: Missing digits after the exponent symbol
+WHITESPACE "\n\n"
+INT_NUMBER "42"
+DOT "."
+IDENT "e"
+PLUS "+"
+WHITESPACE "\n"
+INT_NUMBER "42"
+DOT "."
+IDENT "e"
+MINUS "-"
+WHITESPACE "\n"
+INT_NUMBER "42"
+DOT "."
+IDENT "E"
+PLUS "+"
+WHITESPACE "\n"
+INT_NUMBER "42"
+DOT "."
+IDENT "E"
+MINUS "-"
+WHITESPACE "\n\n"
+FLOAT_NUMBER "42.2e+" error: Missing digits after the exponent symbol
+WHITESPACE "\n"
+FLOAT_NUMBER "42.2e-" error: Missing digits after the exponent symbol
+WHITESPACE "\n"
+FLOAT_NUMBER "42.2E+" error: Missing digits after the exponent symbol
+WHITESPACE "\n"
+FLOAT_NUMBER "42.2E-" error: Missing digits after the exponent symbol
+WHITESPACE "\n\n"
+FLOAT_NUMBER "42.2e+f32" error: Missing digits after the exponent symbol
+WHITESPACE "\n"
+FLOAT_NUMBER "42.2e-f32" error: Missing digits after the exponent symbol
+WHITESPACE "\n"
+FLOAT_NUMBER "42.2E+f32" error: Missing digits after the exponent symbol
+WHITESPACE "\n"
+FLOAT_NUMBER "42.2E-f32" error: Missing digits after the exponent symbol
+WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/empty_int.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/empty_int.rast
new file mode 100644
index 000000000..7f7194f45
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/empty_int.rast
@@ -0,0 +1,26 @@
+INT_NUMBER "0b" error: Missing digits after the integer base prefix
+WHITESPACE "\n"
+INT_NUMBER "0o" error: Missing digits after the integer base prefix
+WHITESPACE "\n"
+INT_NUMBER "0x" error: Missing digits after the integer base prefix
+WHITESPACE "\n\n"
+INT_NUMBER "0b_" error: Missing digits after the integer base prefix
+WHITESPACE "\n"
+INT_NUMBER "0o_" error: Missing digits after the integer base prefix
+WHITESPACE "\n"
+INT_NUMBER "0x_" error: Missing digits after the integer base prefix
+WHITESPACE "\n\n"
+INT_NUMBER "0bnoDigit" error: Missing digits after the integer base prefix
+WHITESPACE "\n"
+INT_NUMBER "0onoDigit" error: Missing digits after the integer base prefix
+WHITESPACE "\n"
+INT_NUMBER "0xnoDigit" error: Missing digits after the integer base prefix
+WHITESPACE "\n\n"
+INT_NUMBER "0xG" error: Missing digits after the integer base prefix
+WHITESPACE "\n"
+INT_NUMBER "0xg" error: Missing digits after the integer base prefix
+WHITESPACE "\n\n"
+INT_NUMBER "0x_g" error: Missing digits after the integer base prefix
+WHITESPACE "\n"
+INT_NUMBER "0x_G" error: Missing digits after the integer base prefix
+WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/empty_int.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/empty_int.rs
new file mode 100644
index 000000000..aa2a9fdca
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/empty_int.rs
@@ -0,0 +1,17 @@
+0b
+0o
+0x
+
+0b_
+0o_
+0x_
+
+0bnoDigit
+0onoDigit
+0xnoDigit
+
+0xG
+0xg
+
+0x_g
+0x_G
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/empty_int.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/empty_int.txt
new file mode 100644
index 000000000..7f7194f45
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/empty_int.txt
@@ -0,0 +1,26 @@
+INT_NUMBER "0b" error: Missing digits after the integer base prefix
+WHITESPACE "\n"
+INT_NUMBER "0o" error: Missing digits after the integer base prefix
+WHITESPACE "\n"
+INT_NUMBER "0x" error: Missing digits after the integer base prefix
+WHITESPACE "\n\n"
+INT_NUMBER "0b_" error: Missing digits after the integer base prefix
+WHITESPACE "\n"
+INT_NUMBER "0o_" error: Missing digits after the integer base prefix
+WHITESPACE "\n"
+INT_NUMBER "0x_" error: Missing digits after the integer base prefix
+WHITESPACE "\n\n"
+INT_NUMBER "0bnoDigit" error: Missing digits after the integer base prefix
+WHITESPACE "\n"
+INT_NUMBER "0onoDigit" error: Missing digits after the integer base prefix
+WHITESPACE "\n"
+INT_NUMBER "0xnoDigit" error: Missing digits after the integer base prefix
+WHITESPACE "\n\n"
+INT_NUMBER "0xG" error: Missing digits after the integer base prefix
+WHITESPACE "\n"
+INT_NUMBER "0xg" error: Missing digits after the integer base prefix
+WHITESPACE "\n\n"
+INT_NUMBER "0x_g" error: Missing digits after the integer base prefix
+WHITESPACE "\n"
+INT_NUMBER "0x_G" error: Missing digits after the integer base prefix
+WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/lifetime_starts_with_a_number.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/lifetime_starts_with_a_number.rast
new file mode 100644
index 000000000..e919bf2a4
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/lifetime_starts_with_a_number.rast
@@ -0,0 +1,4 @@
+LIFETIME_IDENT "'1" error: Lifetime name cannot start with a number
+WHITESPACE "\n"
+LIFETIME_IDENT "'1lifetime" error: Lifetime name cannot start with a number
+WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/lifetime_starts_with_a_number.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/lifetime_starts_with_a_number.rs
new file mode 100644
index 000000000..a7698a404
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/lifetime_starts_with_a_number.rs
@@ -0,0 +1,2 @@
+'1
+'1lifetime
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/lifetime_starts_with_a_number.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/lifetime_starts_with_a_number.txt
new file mode 100644
index 000000000..e919bf2a4
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/lifetime_starts_with_a_number.txt
@@ -0,0 +1,4 @@
+LIFETIME_IDENT "'1" error: Lifetime name cannot start with a number
+WHITESPACE "\n"
+LIFETIME_IDENT "'1lifetime" error: Lifetime name cannot start with a number
+WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_block_comment_at_eof.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_block_comment_at_eof.rast
new file mode 100644
index 000000000..7d2c32976
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_block_comment_at_eof.rast
@@ -0,0 +1 @@
+COMMENT "/*" error: Missing trailing `*/` symbols to terminate the block comment
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_block_comment_at_eof.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_block_comment_at_eof.rs
new file mode 100644
index 000000000..22e83649f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_block_comment_at_eof.rs
@@ -0,0 +1 @@
+/* \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_block_comment_at_eof.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_block_comment_at_eof.txt
new file mode 100644
index 000000000..7d2c32976
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_block_comment_at_eof.txt
@@ -0,0 +1 @@
+COMMENT "/*" error: Missing trailing `*/` symbols to terminate the block comment
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_block_comment_with_content.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_block_comment_with_content.rast
new file mode 100644
index 000000000..227a20660
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_block_comment_with_content.rast
@@ -0,0 +1 @@
+COMMENT "/* comment\n" error: Missing trailing `*/` symbols to terminate the block comment
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_block_comment_with_content.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_block_comment_with_content.rs
new file mode 100644
index 000000000..c45c2844d
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_block_comment_with_content.rs
@@ -0,0 +1 @@
+/* comment
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_block_comment_with_content.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_block_comment_with_content.txt
new file mode 100644
index 000000000..227a20660
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_block_comment_with_content.txt
@@ -0,0 +1 @@
+COMMENT "/* comment\n" error: Missing trailing `*/` symbols to terminate the block comment
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_at_eof.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_at_eof.rast
new file mode 100644
index 000000000..36944dbb2
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_at_eof.rast
@@ -0,0 +1 @@
+BYTE "b'" error: Missing trailing `'` symbol to terminate the byte literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_at_eof.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_at_eof.rs
new file mode 100644
index 000000000..795dc7e25
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_at_eof.rs
@@ -0,0 +1 @@
+b' \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_at_eof.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_at_eof.txt
new file mode 100644
index 000000000..36944dbb2
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_at_eof.txt
@@ -0,0 +1 @@
+BYTE "b'" error: Missing trailing `'` symbol to terminate the byte literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_at_eof.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_at_eof.rast
new file mode 100644
index 000000000..534a3cadc
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_at_eof.rast
@@ -0,0 +1 @@
+BYTE_STRING "b\"" error: Missing trailing `"` symbol to terminate the byte string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_at_eof.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_at_eof.rs
new file mode 100644
index 000000000..36f4f4321
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_at_eof.rs
@@ -0,0 +1 @@
+b" \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_at_eof.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_at_eof.txt
new file mode 100644
index 000000000..534a3cadc
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_at_eof.txt
@@ -0,0 +1 @@
+BYTE_STRING "b\"" error: Missing trailing `"` symbol to terminate the byte string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_ascii_escape.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_ascii_escape.rast
new file mode 100644
index 000000000..03f61de9a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_ascii_escape.rast
@@ -0,0 +1 @@
+BYTE_STRING "b\"\\x7f" error: Missing trailing `"` symbol to terminate the byte string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_ascii_escape.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_ascii_escape.rs
new file mode 100644
index 000000000..836c112c1
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_ascii_escape.rs
@@ -0,0 +1 @@
+b"\x7f \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_ascii_escape.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_ascii_escape.txt
new file mode 100644
index 000000000..03f61de9a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_ascii_escape.txt
@@ -0,0 +1 @@
+BYTE_STRING "b\"\\x7f" error: Missing trailing `"` symbol to terminate the byte string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_ferris.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_ferris.rast
new file mode 100644
index 000000000..e11d49d1e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_ferris.rast
@@ -0,0 +1 @@
+BYTE_STRING "b\"🦀" error: Missing trailing `"` symbol to terminate the byte string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_ferris.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_ferris.rs
new file mode 100644
index 000000000..3c23a0372
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_ferris.rs
@@ -0,0 +1 @@
+b"🦀 \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_ferris.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_ferris.txt
new file mode 100644
index 000000000..e11d49d1e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_ferris.txt
@@ -0,0 +1 @@
+BYTE_STRING "b\"🦀" error: Missing trailing `"` symbol to terminate the byte string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash.rast
new file mode 100644
index 000000000..4e374b120
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash.rast
@@ -0,0 +1 @@
+BYTE_STRING "b\"\\" error: Missing trailing `"` symbol to terminate the byte string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash.rs
new file mode 100644
index 000000000..cce661538
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash.rs
@@ -0,0 +1 @@
+b"\ \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash.txt
new file mode 100644
index 000000000..4e374b120
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash.txt
@@ -0,0 +1 @@
+BYTE_STRING "b\"\\" error: Missing trailing `"` symbol to terminate the byte string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash_double_quote.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash_double_quote.rast
new file mode 100644
index 000000000..ee1997586
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash_double_quote.rast
@@ -0,0 +1 @@
+BYTE_STRING "b\"\\\"" error: Missing trailing `"` symbol to terminate the byte string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash_double_quote.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash_double_quote.rs
new file mode 100644
index 000000000..f2ff58ba9
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash_double_quote.rs
@@ -0,0 +1 @@
+b"\" \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash_double_quote.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash_double_quote.txt
new file mode 100644
index 000000000..ee1997586
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash_double_quote.txt
@@ -0,0 +1 @@
+BYTE_STRING "b\"\\\"" error: Missing trailing `"` symbol to terminate the byte string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash_n.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash_n.rast
new file mode 100644
index 000000000..b109d8629
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash_n.rast
@@ -0,0 +1 @@
+BYTE_STRING "b\"\\n" error: Missing trailing `"` symbol to terminate the byte string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash_n.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash_n.rs
new file mode 100644
index 000000000..5e680aabb
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash_n.rs
@@ -0,0 +1 @@
+b"\n \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash_n.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash_n.txt
new file mode 100644
index 000000000..b109d8629
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_slash_n.txt
@@ -0,0 +1 @@
+BYTE_STRING "b\"\\n" error: Missing trailing `"` symbol to terminate the byte string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_space.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_space.rast
new file mode 100644
index 000000000..eaca94fa4
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_space.rast
@@ -0,0 +1 @@
+BYTE_STRING "b\" " error: Missing trailing `"` symbol to terminate the byte string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_space.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_space.rs
new file mode 100644
index 000000000..d6898541e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_space.rs
@@ -0,0 +1 @@
+b" \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_space.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_space.txt
new file mode 100644
index 000000000..eaca94fa4
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_space.txt
@@ -0,0 +1 @@
+BYTE_STRING "b\" " error: Missing trailing `"` symbol to terminate the byte string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_unicode_escape.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_unicode_escape.rast
new file mode 100644
index 000000000..3b79f48bc
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_unicode_escape.rast
@@ -0,0 +1 @@
+BYTE_STRING "b\"\\u{20AA}" error: Missing trailing `"` symbol to terminate the byte string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_unicode_escape.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_unicode_escape.rs
new file mode 100644
index 000000000..1c6df1d00
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_unicode_escape.rs
@@ -0,0 +1 @@
+b"\u{20AA} \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_unicode_escape.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_unicode_escape.txt
new file mode 100644
index 000000000..3b79f48bc
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_string_with_unicode_escape.txt
@@ -0,0 +1 @@
+BYTE_STRING "b\"\\u{20AA}" error: Missing trailing `"` symbol to terminate the byte string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_ascii_escape.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_ascii_escape.rast
new file mode 100644
index 000000000..5525376f4
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_ascii_escape.rast
@@ -0,0 +1 @@
+BYTE "b'\\x7f" error: Missing trailing `'` symbol to terminate the byte literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_ascii_escape.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_ascii_escape.rs
new file mode 100644
index 000000000..d146a8090
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_ascii_escape.rs
@@ -0,0 +1 @@
+b'\x7f \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_ascii_escape.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_ascii_escape.txt
new file mode 100644
index 000000000..5525376f4
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_ascii_escape.txt
@@ -0,0 +1 @@
+BYTE "b'\\x7f" error: Missing trailing `'` symbol to terminate the byte literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_ferris.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_ferris.rast
new file mode 100644
index 000000000..e7a8be4f6
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_ferris.rast
@@ -0,0 +1 @@
+BYTE "b'🦀" error: Missing trailing `'` symbol to terminate the byte literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_ferris.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_ferris.rs
new file mode 100644
index 000000000..c9230dc24
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_ferris.rs
@@ -0,0 +1 @@
+b'🦀 \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_ferris.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_ferris.txt
new file mode 100644
index 000000000..e7a8be4f6
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_ferris.txt
@@ -0,0 +1 @@
+BYTE "b'🦀" error: Missing trailing `'` symbol to terminate the byte literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash.rast
new file mode 100644
index 000000000..d9937135a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash.rast
@@ -0,0 +1 @@
+BYTE "b'\\" error: Missing trailing `'` symbol to terminate the byte literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash.rs
new file mode 100644
index 000000000..abffa5037
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash.rs
@@ -0,0 +1 @@
+b'\ \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash.txt
new file mode 100644
index 000000000..d9937135a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash.txt
@@ -0,0 +1 @@
+BYTE "b'\\" error: Missing trailing `'` symbol to terminate the byte literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash_n.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash_n.rast
new file mode 100644
index 000000000..c408cdb2b
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash_n.rast
@@ -0,0 +1 @@
+BYTE "b'\\n" error: Missing trailing `'` symbol to terminate the byte literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash_n.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash_n.rs
new file mode 100644
index 000000000..4f46836a9
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash_n.rs
@@ -0,0 +1 @@
+b'\n \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash_n.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash_n.txt
new file mode 100644
index 000000000..c408cdb2b
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash_n.txt
@@ -0,0 +1 @@
+BYTE "b'\\n" error: Missing trailing `'` symbol to terminate the byte literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash_single_quote.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash_single_quote.rast
new file mode 100644
index 000000000..b331f9560
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash_single_quote.rast
@@ -0,0 +1 @@
+BYTE "b'\\'" error: Missing trailing `'` symbol to terminate the byte literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash_single_quote.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash_single_quote.rs
new file mode 100644
index 000000000..645b641ee
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash_single_quote.rs
@@ -0,0 +1 @@
+b'\' \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash_single_quote.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash_single_quote.txt
new file mode 100644
index 000000000..b331f9560
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_slash_single_quote.txt
@@ -0,0 +1 @@
+BYTE "b'\\'" error: Missing trailing `'` symbol to terminate the byte literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_space.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_space.rast
new file mode 100644
index 000000000..80c0e1c00
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_space.rast
@@ -0,0 +1 @@
+BYTE "b' " error: Missing trailing `'` symbol to terminate the byte literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_space.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_space.rs
new file mode 100644
index 000000000..93b7f9c87
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_space.rs
@@ -0,0 +1 @@
+b' \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_space.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_space.txt
new file mode 100644
index 000000000..80c0e1c00
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_space.txt
@@ -0,0 +1 @@
+BYTE "b' " error: Missing trailing `'` symbol to terminate the byte literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_unicode_escape.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_unicode_escape.rast
new file mode 100644
index 000000000..e1c3dc141
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_unicode_escape.rast
@@ -0,0 +1 @@
+BYTE "b'\\u{20AA}" error: Missing trailing `'` symbol to terminate the byte literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_unicode_escape.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_unicode_escape.rs
new file mode 100644
index 000000000..a3dec7c25
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_unicode_escape.rs
@@ -0,0 +1 @@
+b'\u{20AA} \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_unicode_escape.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_unicode_escape.txt
new file mode 100644
index 000000000..e1c3dc141
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_byte_with_unicode_escape.txt
@@ -0,0 +1 @@
+BYTE "b'\\u{20AA}" error: Missing trailing `'` symbol to terminate the byte literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_at_eof.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_at_eof.rast
new file mode 100644
index 000000000..218c7a2d7
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_at_eof.rast
@@ -0,0 +1 @@
+CHAR "'" error: Missing trailing `'` symbol to terminate the character literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_at_eof.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_at_eof.rs
new file mode 100644
index 000000000..ad2823b48
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_at_eof.rs
@@ -0,0 +1 @@
+' \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_at_eof.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_at_eof.txt
new file mode 100644
index 000000000..218c7a2d7
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_at_eof.txt
@@ -0,0 +1 @@
+CHAR "'" error: Missing trailing `'` symbol to terminate the character literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_ascii_escape.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_ascii_escape.rast
new file mode 100644
index 000000000..a0d8e1b83
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_ascii_escape.rast
@@ -0,0 +1 @@
+CHAR "'\\x7f" error: Missing trailing `'` symbol to terminate the character literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_ascii_escape.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_ascii_escape.rs
new file mode 100644
index 000000000..cf74b4dad
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_ascii_escape.rs
@@ -0,0 +1 @@
+'\x7f \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_ascii_escape.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_ascii_escape.txt
new file mode 100644
index 000000000..a0d8e1b83
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_ascii_escape.txt
@@ -0,0 +1 @@
+CHAR "'\\x7f" error: Missing trailing `'` symbol to terminate the character literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_ferris.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_ferris.rast
new file mode 100644
index 000000000..56f19cce0
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_ferris.rast
@@ -0,0 +1 @@
+CHAR "'🦀" error: Missing trailing `'` symbol to terminate the character literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_ferris.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_ferris.rs
new file mode 100644
index 000000000..e264a4152
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_ferris.rs
@@ -0,0 +1 @@
+'🦀 \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_ferris.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_ferris.txt
new file mode 100644
index 000000000..56f19cce0
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_ferris.txt
@@ -0,0 +1 @@
+CHAR "'🦀" error: Missing trailing `'` symbol to terminate the character literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash.rast
new file mode 100644
index 000000000..cfa0e0752
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash.rast
@@ -0,0 +1 @@
+CHAR "'\\" error: Missing trailing `'` symbol to terminate the character literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash.rs
new file mode 100644
index 000000000..6ba258b10
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash.rs
@@ -0,0 +1 @@
+'\ \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash.txt
new file mode 100644
index 000000000..cfa0e0752
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash.txt
@@ -0,0 +1 @@
+CHAR "'\\" error: Missing trailing `'` symbol to terminate the character literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash_n.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash_n.rast
new file mode 100644
index 000000000..6a42a4e22
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash_n.rast
@@ -0,0 +1 @@
+CHAR "'\\n" error: Missing trailing `'` symbol to terminate the character literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash_n.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash_n.rs
new file mode 100644
index 000000000..78bef7e3e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash_n.rs
@@ -0,0 +1 @@
+'\n \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash_n.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash_n.txt
new file mode 100644
index 000000000..6a42a4e22
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash_n.txt
@@ -0,0 +1 @@
+CHAR "'\\n" error: Missing trailing `'` symbol to terminate the character literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash_single_quote.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash_single_quote.rast
new file mode 100644
index 000000000..1275f6aa8
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash_single_quote.rast
@@ -0,0 +1 @@
+CHAR "'\\'" error: Missing trailing `'` symbol to terminate the character literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash_single_quote.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash_single_quote.rs
new file mode 100644
index 000000000..a0e722065
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash_single_quote.rs
@@ -0,0 +1 @@
+'\' \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash_single_quote.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash_single_quote.txt
new file mode 100644
index 000000000..1275f6aa8
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_slash_single_quote.txt
@@ -0,0 +1 @@
+CHAR "'\\'" error: Missing trailing `'` symbol to terminate the character literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_space.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_space.rast
new file mode 100644
index 000000000..746c425c4
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_space.rast
@@ -0,0 +1 @@
+CHAR "' " error: Missing trailing `'` symbol to terminate the character literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_space.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_space.rs
new file mode 100644
index 000000000..309ecfe47
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_space.rs
@@ -0,0 +1 @@
+' \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_space.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_space.txt
new file mode 100644
index 000000000..746c425c4
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_space.txt
@@ -0,0 +1 @@
+CHAR "' " error: Missing trailing `'` symbol to terminate the character literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_unicode_escape.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_unicode_escape.rast
new file mode 100644
index 000000000..9abd59098
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_unicode_escape.rast
@@ -0,0 +1 @@
+CHAR "'\\u{20AA}" error: Missing trailing `'` symbol to terminate the character literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_unicode_escape.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_unicode_escape.rs
new file mode 100644
index 000000000..50be91f68
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_unicode_escape.rs
@@ -0,0 +1 @@
+'\u{20AA} \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_unicode_escape.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_unicode_escape.txt
new file mode 100644
index 000000000..9abd59098
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_char_with_unicode_escape.txt
@@ -0,0 +1 @@
+CHAR "'\\u{20AA}" error: Missing trailing `'` symbol to terminate the character literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_nested_block_comment_entirely.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_nested_block_comment_entirely.rast
new file mode 100644
index 000000000..15ce8905a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_nested_block_comment_entirely.rast
@@ -0,0 +1 @@
+COMMENT "/* /* /*\n" error: Missing trailing `*/` symbols to terminate the block comment
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_nested_block_comment_entirely.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_nested_block_comment_entirely.rs
new file mode 100644
index 000000000..3fcfc9660
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_nested_block_comment_entirely.rs
@@ -0,0 +1 @@
+/* /* /*
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_nested_block_comment_entirely.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_nested_block_comment_entirely.txt
new file mode 100644
index 000000000..15ce8905a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_nested_block_comment_entirely.txt
@@ -0,0 +1 @@
+COMMENT "/* /* /*\n" error: Missing trailing `*/` symbols to terminate the block comment
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_nested_block_comment_partially.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_nested_block_comment_partially.rast
new file mode 100644
index 000000000..e9b74ee7f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_nested_block_comment_partially.rast
@@ -0,0 +1 @@
+COMMENT "/** /*! /* comment */ */\n" error: Missing trailing `*/` symbols to terminate the block comment
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_nested_block_comment_partially.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_nested_block_comment_partially.rs
new file mode 100644
index 000000000..26c898f01
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_nested_block_comment_partially.rs
@@ -0,0 +1 @@
+/** /*! /* comment */ */
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_nested_block_comment_partially.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_nested_block_comment_partially.txt
new file mode 100644
index 000000000..e9b74ee7f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_nested_block_comment_partially.txt
@@ -0,0 +1 @@
+COMMENT "/** /*! /* comment */ */\n" error: Missing trailing `*/` symbols to terminate the block comment
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_at_eof.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_at_eof.rast
new file mode 100644
index 000000000..6ec1780c3
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_at_eof.rast
@@ -0,0 +1 @@
+BYTE_STRING "br##\"" error: Missing trailing `"` with `#` symbols to terminate the raw byte string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_at_eof.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_at_eof.rs
new file mode 100644
index 000000000..ae5bae622
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_at_eof.rs
@@ -0,0 +1 @@
+br##" \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_at_eof.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_at_eof.txt
new file mode 100644
index 000000000..6ec1780c3
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_at_eof.txt
@@ -0,0 +1 @@
+BYTE_STRING "br##\"" error: Missing trailing `"` with `#` symbols to terminate the raw byte string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ascii_escape.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ascii_escape.rast
new file mode 100644
index 000000000..d65f1bb2f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ascii_escape.rast
@@ -0,0 +1 @@
+BYTE_STRING "br##\"\\x7f" error: Missing trailing `"` with `#` symbols to terminate the raw byte string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ascii_escape.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ascii_escape.rs
new file mode 100644
index 000000000..d50270afe
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ascii_escape.rs
@@ -0,0 +1 @@
+br##"\x7f \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ascii_escape.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ascii_escape.txt
new file mode 100644
index 000000000..d65f1bb2f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ascii_escape.txt
@@ -0,0 +1 @@
+BYTE_STRING "br##\"\\x7f" error: Missing trailing `"` with `#` symbols to terminate the raw byte string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ferris.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ferris.rast
new file mode 100644
index 000000000..0f9e0a165
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ferris.rast
@@ -0,0 +1 @@
+BYTE_STRING "br##\"🦀" error: Missing trailing `"` with `#` symbols to terminate the raw byte string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ferris.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ferris.rs
new file mode 100644
index 000000000..9ef01207a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ferris.rs
@@ -0,0 +1 @@
+br##"🦀 \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ferris.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ferris.txt
new file mode 100644
index 000000000..0f9e0a165
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_ferris.txt
@@ -0,0 +1 @@
+BYTE_STRING "br##\"🦀" error: Missing trailing `"` with `#` symbols to terminate the raw byte string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash.rast
new file mode 100644
index 000000000..202dcd2d4
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash.rast
@@ -0,0 +1 @@
+BYTE_STRING "br##\"\\" error: Missing trailing `"` with `#` symbols to terminate the raw byte string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash.rs
new file mode 100644
index 000000000..0b3c015d7
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash.rs
@@ -0,0 +1 @@
+br##"\ \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash.txt
new file mode 100644
index 000000000..202dcd2d4
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash.txt
@@ -0,0 +1 @@
+BYTE_STRING "br##\"\\" error: Missing trailing `"` with `#` symbols to terminate the raw byte string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash_n.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash_n.rast
new file mode 100644
index 000000000..d45485b52
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash_n.rast
@@ -0,0 +1 @@
+BYTE_STRING "br##\"\\n" error: Missing trailing `"` with `#` symbols to terminate the raw byte string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash_n.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash_n.rs
new file mode 100644
index 000000000..0d8b0e7ab
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash_n.rs
@@ -0,0 +1 @@
+br##"\n \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash_n.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash_n.txt
new file mode 100644
index 000000000..d45485b52
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_slash_n.txt
@@ -0,0 +1 @@
+BYTE_STRING "br##\"\\n" error: Missing trailing `"` with `#` symbols to terminate the raw byte string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_space.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_space.rast
new file mode 100644
index 000000000..1bfabbc3a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_space.rast
@@ -0,0 +1 @@
+BYTE_STRING "br##\" " error: Missing trailing `"` with `#` symbols to terminate the raw byte string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_space.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_space.rs
new file mode 100644
index 000000000..14c602fd2
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_space.rs
@@ -0,0 +1 @@
+br##" \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_space.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_space.txt
new file mode 100644
index 000000000..1bfabbc3a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_space.txt
@@ -0,0 +1 @@
+BYTE_STRING "br##\" " error: Missing trailing `"` with `#` symbols to terminate the raw byte string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_unicode_escape.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_unicode_escape.rast
new file mode 100644
index 000000000..104ab8aae
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_unicode_escape.rast
@@ -0,0 +1 @@
+BYTE_STRING "br##\"\\u{20AA}" error: Missing trailing `"` with `#` symbols to terminate the raw byte string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_unicode_escape.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_unicode_escape.rs
new file mode 100644
index 000000000..90e299a1a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_unicode_escape.rs
@@ -0,0 +1 @@
+br##"\u{20AA} \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_unicode_escape.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_unicode_escape.txt
new file mode 100644
index 000000000..104ab8aae
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_byte_string_with_unicode_escape.txt
@@ -0,0 +1 @@
+BYTE_STRING "br##\"\\u{20AA}" error: Missing trailing `"` with `#` symbols to terminate the raw byte string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_at_eof.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_at_eof.rast
new file mode 100644
index 000000000..71b20fd19
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_at_eof.rast
@@ -0,0 +1 @@
+STRING "r##\"" error: Missing trailing `"` with `#` symbols to terminate the raw string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_at_eof.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_at_eof.rs
new file mode 100644
index 000000000..557c59b62
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_at_eof.rs
@@ -0,0 +1 @@
+r##" \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_at_eof.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_at_eof.txt
new file mode 100644
index 000000000..71b20fd19
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_at_eof.txt
@@ -0,0 +1 @@
+STRING "r##\"" error: Missing trailing `"` with `#` symbols to terminate the raw string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ascii_escape.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ascii_escape.rast
new file mode 100644
index 000000000..dc106dd24
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ascii_escape.rast
@@ -0,0 +1 @@
+STRING "r##\"\\x7f" error: Missing trailing `"` with `#` symbols to terminate the raw string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ascii_escape.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ascii_escape.rs
new file mode 100644
index 000000000..5bec883dc
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ascii_escape.rs
@@ -0,0 +1 @@
+r##"\x7f \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ascii_escape.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ascii_escape.txt
new file mode 100644
index 000000000..dc106dd24
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ascii_escape.txt
@@ -0,0 +1 @@
+STRING "r##\"\\x7f" error: Missing trailing `"` with `#` symbols to terminate the raw string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ferris.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ferris.rast
new file mode 100644
index 000000000..30ee029f6
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ferris.rast
@@ -0,0 +1 @@
+STRING "r##\"🦀" error: Missing trailing `"` with `#` symbols to terminate the raw string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ferris.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ferris.rs
new file mode 100644
index 000000000..bd046e4bb
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ferris.rs
@@ -0,0 +1 @@
+r##"🦀 \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ferris.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ferris.txt
new file mode 100644
index 000000000..30ee029f6
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_ferris.txt
@@ -0,0 +1 @@
+STRING "r##\"🦀" error: Missing trailing `"` with `#` symbols to terminate the raw string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash.rast
new file mode 100644
index 000000000..8a6f6cc43
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash.rast
@@ -0,0 +1 @@
+STRING "r##\"\\" error: Missing trailing `"` with `#` symbols to terminate the raw string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash.rs
new file mode 100644
index 000000000..9242077b8
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash.rs
@@ -0,0 +1 @@
+r##"\ \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash.txt
new file mode 100644
index 000000000..8a6f6cc43
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash.txt
@@ -0,0 +1 @@
+STRING "r##\"\\" error: Missing trailing `"` with `#` symbols to terminate the raw string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash_n.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash_n.rast
new file mode 100644
index 000000000..f46eff251
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash_n.rast
@@ -0,0 +1 @@
+STRING "r##\"\\n" error: Missing trailing `"` with `#` symbols to terminate the raw string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash_n.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash_n.rs
new file mode 100644
index 000000000..db1c16f2b
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash_n.rs
@@ -0,0 +1 @@
+r##"\n \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash_n.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash_n.txt
new file mode 100644
index 000000000..f46eff251
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_slash_n.txt
@@ -0,0 +1 @@
+STRING "r##\"\\n" error: Missing trailing `"` with `#` symbols to terminate the raw string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_space.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_space.rast
new file mode 100644
index 000000000..49b6afea4
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_space.rast
@@ -0,0 +1 @@
+STRING "r##\" " error: Missing trailing `"` with `#` symbols to terminate the raw string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_space.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_space.rs
new file mode 100644
index 000000000..f104bae4f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_space.rs
@@ -0,0 +1 @@
+r##" \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_space.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_space.txt
new file mode 100644
index 000000000..49b6afea4
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_space.txt
@@ -0,0 +1 @@
+STRING "r##\" " error: Missing trailing `"` with `#` symbols to terminate the raw string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_unicode_escape.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_unicode_escape.rast
new file mode 100644
index 000000000..d10d6d8e8
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_unicode_escape.rast
@@ -0,0 +1 @@
+STRING "r##\"\\u{20AA}" error: Missing trailing `"` with `#` symbols to terminate the raw string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_unicode_escape.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_unicode_escape.rs
new file mode 100644
index 000000000..bf05c3913
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_unicode_escape.rs
@@ -0,0 +1 @@
+r##"\u{20AA} \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_unicode_escape.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_unicode_escape.txt
new file mode 100644
index 000000000..d10d6d8e8
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_raw_string_with_unicode_escape.txt
@@ -0,0 +1 @@
+STRING "r##\"\\u{20AA}" error: Missing trailing `"` with `#` symbols to terminate the raw string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_at_eof.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_at_eof.rast
new file mode 100644
index 000000000..3b89ce0ca
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_at_eof.rast
@@ -0,0 +1 @@
+STRING "\"" error: Missing trailing `"` symbol to terminate the string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_at_eof.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_at_eof.rs
new file mode 100644
index 000000000..9d68933c4
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_at_eof.rs
@@ -0,0 +1 @@
+" \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_at_eof.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_at_eof.txt
new file mode 100644
index 000000000..3b89ce0ca
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_at_eof.txt
@@ -0,0 +1 @@
+STRING "\"" error: Missing trailing `"` symbol to terminate the string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_ascii_escape.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_ascii_escape.rast
new file mode 100644
index 000000000..6694cf17a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_ascii_escape.rast
@@ -0,0 +1 @@
+STRING "\"\\x7f" error: Missing trailing `"` symbol to terminate the string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_ascii_escape.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_ascii_escape.rs
new file mode 100644
index 000000000..56186a344
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_ascii_escape.rs
@@ -0,0 +1 @@
+"\x7f \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_ascii_escape.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_ascii_escape.txt
new file mode 100644
index 000000000..6694cf17a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_ascii_escape.txt
@@ -0,0 +1 @@
+STRING "\"\\x7f" error: Missing trailing `"` symbol to terminate the string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_ferris.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_ferris.rast
new file mode 100644
index 000000000..5f4501c18
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_ferris.rast
@@ -0,0 +1 @@
+STRING "\"🦀" error: Missing trailing `"` symbol to terminate the string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_ferris.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_ferris.rs
new file mode 100644
index 000000000..d439b8d2a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_ferris.rs
@@ -0,0 +1 @@
+"🦀 \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_ferris.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_ferris.txt
new file mode 100644
index 000000000..5f4501c18
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_ferris.txt
@@ -0,0 +1 @@
+STRING "\"🦀" error: Missing trailing `"` symbol to terminate the string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash.rast
new file mode 100644
index 000000000..a8ac565ac
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash.rast
@@ -0,0 +1 @@
+STRING "\"\\" error: Missing trailing `"` symbol to terminate the string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash.rs
new file mode 100644
index 000000000..00a258400
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash.rs
@@ -0,0 +1 @@
+"\ \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash.txt
new file mode 100644
index 000000000..a8ac565ac
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash.txt
@@ -0,0 +1 @@
+STRING "\"\\" error: Missing trailing `"` symbol to terminate the string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash_double_quote.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash_double_quote.rast
new file mode 100644
index 000000000..919183b91
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash_double_quote.rast
@@ -0,0 +1 @@
+STRING "\"\\\"" error: Missing trailing `"` symbol to terminate the string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash_double_quote.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash_double_quote.rs
new file mode 100644
index 000000000..403c2d6dd
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash_double_quote.rs
@@ -0,0 +1 @@
+"\" \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash_double_quote.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash_double_quote.txt
new file mode 100644
index 000000000..919183b91
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash_double_quote.txt
@@ -0,0 +1 @@
+STRING "\"\\\"" error: Missing trailing `"` symbol to terminate the string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash_n.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash_n.rast
new file mode 100644
index 000000000..39e288af9
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash_n.rast
@@ -0,0 +1 @@
+STRING "\"\\n" error: Missing trailing `"` symbol to terminate the string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash_n.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash_n.rs
new file mode 100644
index 000000000..a0c29b8cf
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash_n.rs
@@ -0,0 +1 @@
+"\n \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash_n.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash_n.txt
new file mode 100644
index 000000000..39e288af9
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_slash_n.txt
@@ -0,0 +1 @@
+STRING "\"\\n" error: Missing trailing `"` symbol to terminate the string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_space.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_space.rast
new file mode 100644
index 000000000..dcff94d7e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_space.rast
@@ -0,0 +1 @@
+STRING "\" " error: Missing trailing `"` symbol to terminate the string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_space.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_space.rs
new file mode 100644
index 000000000..72cdc841f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_space.rs
@@ -0,0 +1 @@
+" \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_space.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_space.txt
new file mode 100644
index 000000000..dcff94d7e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_space.txt
@@ -0,0 +1 @@
+STRING "\" " error: Missing trailing `"` symbol to terminate the string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_unicode_escape.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_unicode_escape.rast
new file mode 100644
index 000000000..ac232b530
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_unicode_escape.rast
@@ -0,0 +1 @@
+STRING "\"\\u{20AA}" error: Missing trailing `"` symbol to terminate the string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_unicode_escape.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_unicode_escape.rs
new file mode 100644
index 000000000..ed24095c3
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_unicode_escape.rs
@@ -0,0 +1 @@
+"\u{20AA} \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_unicode_escape.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_unicode_escape.txt
new file mode 100644
index 000000000..ac232b530
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unclosed_string_with_unicode_escape.txt
@@ -0,0 +1 @@
+STRING "\"\\u{20AA}" error: Missing trailing `"` symbol to terminate the string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_at_eof.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_at_eof.rast
new file mode 100644
index 000000000..cf942c92f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_at_eof.rast
@@ -0,0 +1 @@
+BYTE_STRING "br##" error: Missing `"` symbol after `#` symbols to begin the raw byte string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_at_eof.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_at_eof.rs
new file mode 100644
index 000000000..7e8cadf4f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_at_eof.rs
@@ -0,0 +1 @@
+br## \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_at_eof.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_at_eof.txt
new file mode 100644
index 000000000..cf942c92f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_at_eof.txt
@@ -0,0 +1 @@
+BYTE_STRING "br##" error: Missing `"` symbol after `#` symbols to begin the raw byte string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_with_ascii.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_with_ascii.rast
new file mode 100644
index 000000000..042769c27
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_with_ascii.rast
@@ -0,0 +1,9 @@
+BYTE_STRING "br## " error: Missing `"` symbol after `#` symbols to begin the raw byte string literal
+IDENT "I"
+WHITESPACE " "
+IDENT "lack"
+WHITESPACE " "
+IDENT "a"
+WHITESPACE " "
+IDENT "quote"
+BANG "!"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_with_ascii.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_with_ascii.rs
new file mode 100644
index 000000000..d9b55455a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_with_ascii.rs
@@ -0,0 +1 @@
+br## I lack a quote! \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_with_ascii.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_with_ascii.txt
new file mode 100644
index 000000000..042769c27
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_byte_string_with_ascii.txt
@@ -0,0 +1,9 @@
+BYTE_STRING "br## " error: Missing `"` symbol after `#` symbols to begin the raw byte string literal
+IDENT "I"
+WHITESPACE " "
+IDENT "lack"
+WHITESPACE " "
+IDENT "a"
+WHITESPACE " "
+IDENT "quote"
+BANG "!"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_string_at_eof.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_string_at_eof.rast
new file mode 100644
index 000000000..2f7c7529a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_string_at_eof.rast
@@ -0,0 +1 @@
+STRING "r##" error: Missing `"` symbol after `#` symbols to begin the raw string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_string_at_eof.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_string_at_eof.rs
new file mode 100644
index 000000000..eddf8d080
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_string_at_eof.rs
@@ -0,0 +1 @@
+r## \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_string_at_eof.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_string_at_eof.txt
new file mode 100644
index 000000000..2f7c7529a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_string_at_eof.txt
@@ -0,0 +1 @@
+STRING "r##" error: Missing `"` symbol after `#` symbols to begin the raw string literal
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_string_with_ascii.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_string_with_ascii.rast
new file mode 100644
index 000000000..4a06b0abe
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_string_with_ascii.rast
@@ -0,0 +1,9 @@
+STRING "r## " error: Missing `"` symbol after `#` symbols to begin the raw string literal
+IDENT "I"
+WHITESPACE " "
+IDENT "lack"
+WHITESPACE " "
+IDENT "a"
+WHITESPACE " "
+IDENT "quote"
+BANG "!"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_string_with_ascii.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_string_with_ascii.rs
new file mode 100644
index 000000000..534668a9b
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_string_with_ascii.rs
@@ -0,0 +1 @@
+r## I lack a quote! \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_string_with_ascii.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_string_with_ascii.txt
new file mode 100644
index 000000000..4a06b0abe
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/err/unstarted_raw_string_with_ascii.txt
@@ -0,0 +1,9 @@
+STRING "r## " error: Missing `"` symbol after `#` symbols to begin the raw string literal
+IDENT "I"
+WHITESPACE " "
+IDENT "lack"
+WHITESPACE " "
+IDENT "a"
+WHITESPACE " "
+IDENT "quote"
+BANG "!"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/block_comment.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/block_comment.rast
new file mode 100644
index 000000000..18bb5cad8
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/block_comment.rast
@@ -0,0 +1,6 @@
+COMMENT "/* */"
+WHITESPACE "\n"
+COMMENT "/**/"
+WHITESPACE "\n"
+COMMENT "/* /* */ */"
+WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/block_comment.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/block_comment.rs
new file mode 100644
index 000000000..b880a59d9
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/block_comment.rs
@@ -0,0 +1,3 @@
+/* */
+/**/
+/* /* */ */
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/block_comment.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/block_comment.txt
new file mode 100644
index 000000000..18bb5cad8
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/block_comment.txt
@@ -0,0 +1,6 @@
+COMMENT "/* */"
+WHITESPACE "\n"
+COMMENT "/**/"
+WHITESPACE "\n"
+COMMENT "/* /* */ */"
+WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/byte_strings.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/byte_strings.rast
new file mode 100644
index 000000000..c848ac368
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/byte_strings.rast
@@ -0,0 +1,22 @@
+BYTE "b''"
+WHITESPACE " "
+BYTE "b'x'"
+WHITESPACE " "
+BYTE_STRING "b\"foo\""
+WHITESPACE " "
+BYTE_STRING "br\"\""
+WHITESPACE "\n"
+BYTE "b''suf"
+WHITESPACE " "
+BYTE_STRING "b\"\"ix"
+WHITESPACE " "
+BYTE_STRING "br\"\"br"
+WHITESPACE "\n"
+BYTE "b'\\n'"
+WHITESPACE " "
+BYTE "b'\\\\'"
+WHITESPACE " "
+BYTE "b'\\''"
+WHITESPACE " "
+BYTE "b'hello'"
+WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/byte_strings.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/byte_strings.rs
new file mode 100644
index 000000000..b54930f5e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/byte_strings.rs
@@ -0,0 +1,3 @@
+b'' b'x' b"foo" br""
+b''suf b""ix br""br
+b'\n' b'\\' b'\'' b'hello'
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/byte_strings.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/byte_strings.txt
new file mode 100644
index 000000000..c848ac368
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/byte_strings.txt
@@ -0,0 +1,22 @@
+BYTE "b''"
+WHITESPACE " "
+BYTE "b'x'"
+WHITESPACE " "
+BYTE_STRING "b\"foo\""
+WHITESPACE " "
+BYTE_STRING "br\"\""
+WHITESPACE "\n"
+BYTE "b''suf"
+WHITESPACE " "
+BYTE_STRING "b\"\"ix"
+WHITESPACE " "
+BYTE_STRING "br\"\"br"
+WHITESPACE "\n"
+BYTE "b'\\n'"
+WHITESPACE " "
+BYTE "b'\\\\'"
+WHITESPACE " "
+BYTE "b'\\''"
+WHITESPACE " "
+BYTE "b'hello'"
+WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/chars.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/chars.rast
new file mode 100644
index 000000000..66e58cc29
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/chars.rast
@@ -0,0 +1,16 @@
+CHAR "'x'"
+WHITESPACE " "
+CHAR "' '"
+WHITESPACE " "
+CHAR "'0'"
+WHITESPACE " "
+CHAR "'hello'"
+WHITESPACE " "
+CHAR "'\\x7f'"
+WHITESPACE " "
+CHAR "'\\n'"
+WHITESPACE " "
+CHAR "'\\\\'"
+WHITESPACE " "
+CHAR "'\\''"
+WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/chars.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/chars.rs
new file mode 100644
index 000000000..454ee0a5f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/chars.rs
@@ -0,0 +1 @@
+'x' ' ' '0' 'hello' '\x7f' '\n' '\\' '\''
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/chars.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/chars.txt
new file mode 100644
index 000000000..66e58cc29
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/chars.txt
@@ -0,0 +1,16 @@
+CHAR "'x'"
+WHITESPACE " "
+CHAR "' '"
+WHITESPACE " "
+CHAR "'0'"
+WHITESPACE " "
+CHAR "'hello'"
+WHITESPACE " "
+CHAR "'\\x7f'"
+WHITESPACE " "
+CHAR "'\\n'"
+WHITESPACE " "
+CHAR "'\\\\'"
+WHITESPACE " "
+CHAR "'\\''"
+WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/hello.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/hello.rast
new file mode 100644
index 000000000..7f5ce9de1
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/hello.rast
@@ -0,0 +1,3 @@
+IDENT "hello"
+WHITESPACE " "
+IDENT "world"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/hello.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/hello.rs
new file mode 100644
index 000000000..95d09f2b1
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/hello.rs
@@ -0,0 +1 @@
+hello world \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/hello.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/hello.txt
new file mode 100644
index 000000000..7f5ce9de1
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/hello.txt
@@ -0,0 +1,3 @@
+IDENT "hello"
+WHITESPACE " "
+IDENT "world"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/ident.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/ident.rast
new file mode 100644
index 000000000..5689644c0
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/ident.rast
@@ -0,0 +1,14 @@
+IDENT "foo"
+WHITESPACE " "
+IDENT "foo_"
+WHITESPACE " "
+IDENT "_foo"
+WHITESPACE " "
+UNDERSCORE "_"
+WHITESPACE " "
+IDENT "__"
+WHITESPACE " "
+IDENT "x"
+WHITESPACE " "
+IDENT "привет"
+WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/ident.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/ident.rs
new file mode 100644
index 000000000..c05c9c009
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/ident.rs
@@ -0,0 +1 @@
+foo foo_ _foo _ __ x привет
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/ident.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/ident.txt
new file mode 100644
index 000000000..5689644c0
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/ident.txt
@@ -0,0 +1,14 @@
+IDENT "foo"
+WHITESPACE " "
+IDENT "foo_"
+WHITESPACE " "
+IDENT "_foo"
+WHITESPACE " "
+UNDERSCORE "_"
+WHITESPACE " "
+IDENT "__"
+WHITESPACE " "
+IDENT "x"
+WHITESPACE " "
+IDENT "привет"
+WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/keywords.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/keywords.rast
new file mode 100644
index 000000000..e19b1399a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/keywords.rast
@@ -0,0 +1,64 @@
+ASYNC_KW "async"
+WHITESPACE " "
+FN_KW "fn"
+WHITESPACE " "
+USE_KW "use"
+WHITESPACE " "
+STRUCT_KW "struct"
+WHITESPACE " "
+TRAIT_KW "trait"
+WHITESPACE " "
+ENUM_KW "enum"
+WHITESPACE " "
+IMPL_KW "impl"
+WHITESPACE " "
+TRUE_KW "true"
+WHITESPACE " "
+FALSE_KW "false"
+WHITESPACE " "
+AS_KW "as"
+WHITESPACE " "
+EXTERN_KW "extern"
+WHITESPACE " "
+CRATE_KW "crate"
+WHITESPACE "\n"
+MOD_KW "mod"
+WHITESPACE " "
+PUB_KW "pub"
+WHITESPACE " "
+SELF_KW "self"
+WHITESPACE " "
+SUPER_KW "super"
+WHITESPACE " "
+IN_KW "in"
+WHITESPACE " "
+WHERE_KW "where"
+WHITESPACE " "
+FOR_KW "for"
+WHITESPACE " "
+LOOP_KW "loop"
+WHITESPACE " "
+WHILE_KW "while"
+WHITESPACE " "
+IF_KW "if"
+WHITESPACE " "
+MATCH_KW "match"
+WHITESPACE " "
+CONST_KW "const"
+WHITESPACE "\n"
+STATIC_KW "static"
+WHITESPACE " "
+MUT_KW "mut"
+WHITESPACE " "
+TYPE_KW "type"
+WHITESPACE " "
+REF_KW "ref"
+WHITESPACE " "
+LET_KW "let"
+WHITESPACE " "
+ELSE_KW "else"
+WHITESPACE " "
+MOVE_KW "move"
+WHITESPACE " "
+RETURN_KW "return"
+WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/keywords.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/keywords.rs
new file mode 100644
index 000000000..1e91bff4e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/keywords.rs
@@ -0,0 +1,3 @@
+async fn use struct trait enum impl true false as extern crate
+mod pub self super in where for loop while if match const
+static mut type ref let else move return
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/keywords.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/keywords.txt
new file mode 100644
index 000000000..e19b1399a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/keywords.txt
@@ -0,0 +1,64 @@
+ASYNC_KW "async"
+WHITESPACE " "
+FN_KW "fn"
+WHITESPACE " "
+USE_KW "use"
+WHITESPACE " "
+STRUCT_KW "struct"
+WHITESPACE " "
+TRAIT_KW "trait"
+WHITESPACE " "
+ENUM_KW "enum"
+WHITESPACE " "
+IMPL_KW "impl"
+WHITESPACE " "
+TRUE_KW "true"
+WHITESPACE " "
+FALSE_KW "false"
+WHITESPACE " "
+AS_KW "as"
+WHITESPACE " "
+EXTERN_KW "extern"
+WHITESPACE " "
+CRATE_KW "crate"
+WHITESPACE "\n"
+MOD_KW "mod"
+WHITESPACE " "
+PUB_KW "pub"
+WHITESPACE " "
+SELF_KW "self"
+WHITESPACE " "
+SUPER_KW "super"
+WHITESPACE " "
+IN_KW "in"
+WHITESPACE " "
+WHERE_KW "where"
+WHITESPACE " "
+FOR_KW "for"
+WHITESPACE " "
+LOOP_KW "loop"
+WHITESPACE " "
+WHILE_KW "while"
+WHITESPACE " "
+IF_KW "if"
+WHITESPACE " "
+MATCH_KW "match"
+WHITESPACE " "
+CONST_KW "const"
+WHITESPACE "\n"
+STATIC_KW "static"
+WHITESPACE " "
+MUT_KW "mut"
+WHITESPACE " "
+TYPE_KW "type"
+WHITESPACE " "
+REF_KW "ref"
+WHITESPACE " "
+LET_KW "let"
+WHITESPACE " "
+ELSE_KW "else"
+WHITESPACE " "
+MOVE_KW "move"
+WHITESPACE " "
+RETURN_KW "return"
+WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/lifetimes.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/lifetimes.rast
new file mode 100644
index 000000000..eeb1e9541
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/lifetimes.rast
@@ -0,0 +1,8 @@
+LIFETIME_IDENT "'a"
+WHITESPACE " "
+LIFETIME_IDENT "'foo"
+WHITESPACE " "
+LIFETIME_IDENT "'foo_bar_baz"
+WHITESPACE " "
+LIFETIME_IDENT "'_"
+WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/lifetimes.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/lifetimes.rs
new file mode 100644
index 000000000..b764f1dce
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/lifetimes.rs
@@ -0,0 +1 @@
+'a 'foo 'foo_bar_baz '_
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/lifetimes.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/lifetimes.txt
new file mode 100644
index 000000000..eeb1e9541
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/lifetimes.txt
@@ -0,0 +1,8 @@
+LIFETIME_IDENT "'a"
+WHITESPACE " "
+LIFETIME_IDENT "'foo"
+WHITESPACE " "
+LIFETIME_IDENT "'foo_bar_baz"
+WHITESPACE " "
+LIFETIME_IDENT "'_"
+WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/numbers.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/numbers.rast
new file mode 100644
index 000000000..8d13c3f61
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/numbers.rast
@@ -0,0 +1,57 @@
+INT_NUMBER "0"
+WHITESPACE " "
+INT_NUMBER "00"
+WHITESPACE " "
+INT_NUMBER "0_"
+WHITESPACE " "
+FLOAT_NUMBER "0."
+WHITESPACE " "
+INT_NUMBER "0z"
+WHITESPACE "\n"
+INT_NUMBER "01790"
+WHITESPACE " "
+INT_NUMBER "0b1790"
+WHITESPACE " "
+INT_NUMBER "0o1790"
+WHITESPACE " "
+INT_NUMBER "0x1790aAbBcCdDeEfF"
+WHITESPACE " "
+INT_NUMBER "001279"
+WHITESPACE " "
+INT_NUMBER "0_1279"
+WHITESPACE " "
+FLOAT_NUMBER "0.1279"
+WHITESPACE " "
+FLOAT_NUMBER "0e1279"
+WHITESPACE " "
+FLOAT_NUMBER "0E1279"
+WHITESPACE "\n"
+INT_NUMBER "0"
+DOT "."
+DOT "."
+INT_NUMBER "2"
+WHITESPACE "\n"
+INT_NUMBER "0"
+DOT "."
+IDENT "foo"
+L_PAREN "("
+R_PAREN ")"
+WHITESPACE "\n"
+FLOAT_NUMBER "0e+1"
+WHITESPACE "\n"
+INT_NUMBER "0"
+DOT "."
+IDENT "e"
+PLUS "+"
+INT_NUMBER "1"
+WHITESPACE "\n"
+FLOAT_NUMBER "0.0E-2"
+WHITESPACE "\n"
+FLOAT_NUMBER "0___0.10000____0000e+111__"
+WHITESPACE "\n"
+INT_NUMBER "1i64"
+WHITESPACE " "
+FLOAT_NUMBER "92.0f32"
+WHITESPACE " "
+INT_NUMBER "11__s"
+WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/numbers.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/numbers.rs
new file mode 100644
index 000000000..bc761c235
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/numbers.rs
@@ -0,0 +1,9 @@
+0 00 0_ 0. 0z
+01790 0b1790 0o1790 0x1790aAbBcCdDeEfF 001279 0_1279 0.1279 0e1279 0E1279
+0..2
+0.foo()
+0e+1
+0.e+1
+0.0E-2
+0___0.10000____0000e+111__
+1i64 92.0f32 11__s
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/numbers.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/numbers.txt
new file mode 100644
index 000000000..8d13c3f61
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/numbers.txt
@@ -0,0 +1,57 @@
+INT_NUMBER "0"
+WHITESPACE " "
+INT_NUMBER "00"
+WHITESPACE " "
+INT_NUMBER "0_"
+WHITESPACE " "
+FLOAT_NUMBER "0."
+WHITESPACE " "
+INT_NUMBER "0z"
+WHITESPACE "\n"
+INT_NUMBER "01790"
+WHITESPACE " "
+INT_NUMBER "0b1790"
+WHITESPACE " "
+INT_NUMBER "0o1790"
+WHITESPACE " "
+INT_NUMBER "0x1790aAbBcCdDeEfF"
+WHITESPACE " "
+INT_NUMBER "001279"
+WHITESPACE " "
+INT_NUMBER "0_1279"
+WHITESPACE " "
+FLOAT_NUMBER "0.1279"
+WHITESPACE " "
+FLOAT_NUMBER "0e1279"
+WHITESPACE " "
+FLOAT_NUMBER "0E1279"
+WHITESPACE "\n"
+INT_NUMBER "0"
+DOT "."
+DOT "."
+INT_NUMBER "2"
+WHITESPACE "\n"
+INT_NUMBER "0"
+DOT "."
+IDENT "foo"
+L_PAREN "("
+R_PAREN ")"
+WHITESPACE "\n"
+FLOAT_NUMBER "0e+1"
+WHITESPACE "\n"
+INT_NUMBER "0"
+DOT "."
+IDENT "e"
+PLUS "+"
+INT_NUMBER "1"
+WHITESPACE "\n"
+FLOAT_NUMBER "0.0E-2"
+WHITESPACE "\n"
+FLOAT_NUMBER "0___0.10000____0000e+111__"
+WHITESPACE "\n"
+INT_NUMBER "1i64"
+WHITESPACE " "
+FLOAT_NUMBER "92.0f32"
+WHITESPACE " "
+INT_NUMBER "11__s"
+WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/raw_ident.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/raw_ident.rast
new file mode 100644
index 000000000..fddad9982
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/raw_ident.rast
@@ -0,0 +1,2 @@
+IDENT "r#raw_ident"
+WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/raw_ident.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/raw_ident.rs
new file mode 100644
index 000000000..b40a1b6a2
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/raw_ident.rs
@@ -0,0 +1 @@
+r#raw_ident
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/raw_ident.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/raw_ident.txt
new file mode 100644
index 000000000..fddad9982
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/raw_ident.txt
@@ -0,0 +1,2 @@
+IDENT "r#raw_ident"
+WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/raw_strings.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/raw_strings.rast
new file mode 100644
index 000000000..13cf733b7
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/raw_strings.rast
@@ -0,0 +1,2 @@
+STRING "r###\"this is a r##\"raw\"## string\"###"
+WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/raw_strings.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/raw_strings.rs
new file mode 100644
index 000000000..e5ed0b693
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/raw_strings.rs
@@ -0,0 +1 @@
+r###"this is a r##"raw"## string"###
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/raw_strings.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/raw_strings.txt
new file mode 100644
index 000000000..13cf733b7
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/raw_strings.txt
@@ -0,0 +1,2 @@
+STRING "r###\"this is a r##\"raw\"## string\"###"
+WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/single_line_comments.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/single_line_comments.rast
new file mode 100644
index 000000000..a7681e9f5
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/single_line_comments.rast
@@ -0,0 +1,22 @@
+SHEBANG "#!/usr/bin/env bash"
+WHITESPACE "\n"
+COMMENT "// hello"
+WHITESPACE "\n"
+COMMENT "//! World"
+WHITESPACE "\n"
+COMMENT "//!! Inner line doc"
+WHITESPACE "\n"
+COMMENT "/// Outer line doc"
+WHITESPACE "\n"
+COMMENT "//// Just a comment"
+WHITESPACE "\n\n"
+COMMENT "//"
+WHITESPACE "\n"
+COMMENT "//!"
+WHITESPACE "\n"
+COMMENT "//!!"
+WHITESPACE "\n"
+COMMENT "///"
+WHITESPACE "\n"
+COMMENT "////"
+WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/single_line_comments.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/single_line_comments.rs
new file mode 100644
index 000000000..4b6653f9c
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/single_line_comments.rs
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+// hello
+//! World
+//!! Inner line doc
+/// Outer line doc
+//// Just a comment
+
+//
+//!
+//!!
+///
+////
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/single_line_comments.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/single_line_comments.txt
new file mode 100644
index 000000000..a7681e9f5
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/single_line_comments.txt
@@ -0,0 +1,22 @@
+SHEBANG "#!/usr/bin/env bash"
+WHITESPACE "\n"
+COMMENT "// hello"
+WHITESPACE "\n"
+COMMENT "//! World"
+WHITESPACE "\n"
+COMMENT "//!! Inner line doc"
+WHITESPACE "\n"
+COMMENT "/// Outer line doc"
+WHITESPACE "\n"
+COMMENT "//// Just a comment"
+WHITESPACE "\n\n"
+COMMENT "//"
+WHITESPACE "\n"
+COMMENT "//!"
+WHITESPACE "\n"
+COMMENT "//!!"
+WHITESPACE "\n"
+COMMENT "///"
+WHITESPACE "\n"
+COMMENT "////"
+WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/strings.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/strings.rast
new file mode 100644
index 000000000..ec222591b
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/strings.rast
@@ -0,0 +1,8 @@
+STRING "\"hello\""
+WHITESPACE " "
+STRING "r\"world\""
+WHITESPACE " "
+STRING "\"\\n\\\"\\\\no escape\""
+WHITESPACE " "
+STRING "\"multi\nline\""
+WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/strings.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/strings.rs
new file mode 100644
index 000000000..4ddb5bffc
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/strings.rs
@@ -0,0 +1,2 @@
+"hello" r"world" "\n\"\\no escape" "multi
+line"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/strings.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/strings.txt
new file mode 100644
index 000000000..ec222591b
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/strings.txt
@@ -0,0 +1,8 @@
+STRING "\"hello\""
+WHITESPACE " "
+STRING "r\"world\""
+WHITESPACE " "
+STRING "\"\\n\\\"\\\\no escape\""
+WHITESPACE " "
+STRING "\"multi\nline\""
+WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/symbols.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/symbols.rast
new file mode 100644
index 000000000..533ccff9a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/symbols.rast
@@ -0,0 +1,77 @@
+SEMICOLON ";"
+WHITESPACE " "
+COMMA ","
+WHITESPACE " "
+L_PAREN "("
+WHITESPACE " "
+R_PAREN ")"
+WHITESPACE " "
+L_CURLY "{"
+WHITESPACE " "
+R_CURLY "}"
+WHITESPACE " "
+L_BRACK "["
+WHITESPACE " "
+R_BRACK "]"
+WHITESPACE " "
+L_ANGLE "<"
+WHITESPACE " "
+R_ANGLE ">"
+WHITESPACE " "
+AT "@"
+WHITESPACE " "
+POUND "#"
+WHITESPACE " "
+TILDE "~"
+WHITESPACE " "
+QUESTION "?"
+WHITESPACE " "
+DOLLAR "$"
+WHITESPACE " "
+AMP "&"
+WHITESPACE " "
+PIPE "|"
+WHITESPACE " "
+PLUS "+"
+WHITESPACE " "
+STAR "*"
+WHITESPACE " "
+SLASH "/"
+WHITESPACE " "
+CARET "^"
+WHITESPACE " "
+PERCENT "%"
+WHITESPACE "\n"
+DOT "."
+WHITESPACE " "
+DOT "."
+DOT "."
+WHITESPACE " "
+DOT "."
+DOT "."
+DOT "."
+WHITESPACE " "
+DOT "."
+DOT "."
+EQ "="
+WHITESPACE "\n"
+COLON ":"
+WHITESPACE " "
+COLON ":"
+COLON ":"
+WHITESPACE "\n"
+EQ "="
+WHITESPACE " "
+EQ "="
+R_ANGLE ">"
+WHITESPACE "\n"
+BANG "!"
+WHITESPACE " "
+BANG "!"
+EQ "="
+WHITESPACE "\n"
+MINUS "-"
+WHITESPACE " "
+MINUS "-"
+R_ANGLE ">"
+WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/symbols.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/symbols.rs
new file mode 100644
index 000000000..487569b5a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/symbols.rs
@@ -0,0 +1,6 @@
+; , ( ) { } [ ] < > @ # ~ ? $ & | + * / ^ %
+. .. ... ..=
+: ::
+= =>
+! !=
+- ->
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/symbols.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/symbols.txt
new file mode 100644
index 000000000..533ccff9a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/symbols.txt
@@ -0,0 +1,77 @@
+SEMICOLON ";"
+WHITESPACE " "
+COMMA ","
+WHITESPACE " "
+L_PAREN "("
+WHITESPACE " "
+R_PAREN ")"
+WHITESPACE " "
+L_CURLY "{"
+WHITESPACE " "
+R_CURLY "}"
+WHITESPACE " "
+L_BRACK "["
+WHITESPACE " "
+R_BRACK "]"
+WHITESPACE " "
+L_ANGLE "<"
+WHITESPACE " "
+R_ANGLE ">"
+WHITESPACE " "
+AT "@"
+WHITESPACE " "
+POUND "#"
+WHITESPACE " "
+TILDE "~"
+WHITESPACE " "
+QUESTION "?"
+WHITESPACE " "
+DOLLAR "$"
+WHITESPACE " "
+AMP "&"
+WHITESPACE " "
+PIPE "|"
+WHITESPACE " "
+PLUS "+"
+WHITESPACE " "
+STAR "*"
+WHITESPACE " "
+SLASH "/"
+WHITESPACE " "
+CARET "^"
+WHITESPACE " "
+PERCENT "%"
+WHITESPACE "\n"
+DOT "."
+WHITESPACE " "
+DOT "."
+DOT "."
+WHITESPACE " "
+DOT "."
+DOT "."
+DOT "."
+WHITESPACE " "
+DOT "."
+DOT "."
+EQ "="
+WHITESPACE "\n"
+COLON ":"
+WHITESPACE " "
+COLON ":"
+COLON ":"
+WHITESPACE "\n"
+EQ "="
+WHITESPACE " "
+EQ "="
+R_ANGLE ">"
+WHITESPACE "\n"
+BANG "!"
+WHITESPACE " "
+BANG "!"
+EQ "="
+WHITESPACE "\n"
+MINUS "-"
+WHITESPACE " "
+MINUS "-"
+R_ANGLE ">"
+WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/whitespace.rast b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/whitespace.rast
new file mode 100644
index 000000000..8ccb79e4e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/whitespace.rast
@@ -0,0 +1,12 @@
+IDENT "a"
+WHITESPACE " "
+IDENT "b"
+WHITESPACE " "
+IDENT "c"
+WHITESPACE "\n"
+IDENT "d"
+WHITESPACE "\n\n"
+IDENT "e"
+WHITESPACE "\t"
+IDENT "f"
+WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/whitespace.rs b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/whitespace.rs
new file mode 100644
index 000000000..08fce1418
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/whitespace.rs
@@ -0,0 +1,4 @@
+a b c
+d
+
+e f
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/whitespace.txt b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/whitespace.txt
new file mode 100644
index 000000000..8ccb79e4e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/lexer/ok/whitespace.txt
@@ -0,0 +1,12 @@
+IDENT "a"
+WHITESPACE " "
+IDENT "b"
+WHITESPACE " "
+IDENT "c"
+WHITESPACE "\n"
+IDENT "d"
+WHITESPACE "\n\n"
+IDENT "e"
+WHITESPACE "\t"
+IDENT "f"
+WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0000_struct_field_missing_comma.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0000_struct_field_missing_comma.rast
new file mode 100644
index 000000000..b30328c82
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0000_struct_field_missing_comma.rast
@@ -0,0 +1,34 @@
+SOURCE_FILE
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ RECORD_FIELD
+ NAME
+ IDENT "a"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u32"
+ WHITESPACE "\n "
+ RECORD_FIELD
+ NAME
+ IDENT "b"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u32"
+ WHITESPACE "\n"
+ R_CURLY "}"
+error 21: expected COMMA
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0000_struct_field_missing_comma.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0000_struct_field_missing_comma.rs
new file mode 100644
index 000000000..fe5030d89
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0000_struct_field_missing_comma.rs
@@ -0,0 +1,4 @@
+struct S {
+ a: u32
+ b: u32
+} \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0001_item_recovery_in_file.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0001_item_recovery_in_file.rast
new file mode 100644
index 000000000..959b87ebb
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0001_item_recovery_in_file.rast
@@ -0,0 +1,18 @@
+SOURCE_FILE
+ ERROR
+ IF_KW "if"
+ WHITESPACE " "
+ ERROR
+ MATCH_KW "match"
+ WHITESPACE "\n\n"
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_FIELD_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+error 0: expected an item
+error 3: expected an item
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0001_item_recovery_in_file.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0001_item_recovery_in_file.rs
new file mode 100644
index 000000000..98f23de1f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0001_item_recovery_in_file.rs
@@ -0,0 +1,3 @@
+if match
+
+struct S {} \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0002_duplicate_shebang.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0002_duplicate_shebang.rast
new file mode 100644
index 000000000..ec6c31510
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0002_duplicate_shebang.rast
@@ -0,0 +1,45 @@
+SOURCE_FILE
+ SHEBANG "#!/use/bin/env rusti"
+ WHITESPACE "\n"
+ ATTR
+ POUND "#"
+ BANG "!"
+ ERROR
+ SLASH "/"
+ USE
+ USE_KW "use"
+ ERROR
+ SLASH "/"
+ MACRO_CALL
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "bin"
+ ERROR
+ SLASH "/"
+ MACRO_CALL
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "env"
+ WHITESPACE " "
+ MACRO_CALL
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "rusti"
+ WHITESPACE "\n"
+error 23: expected `[`
+error 23: expected an item
+error 27: expected one of `*`, `::`, `{`, `self`, `super` or an identifier
+error 28: expected SEMICOLON
+error 31: expected BANG
+error 31: expected `{`, `[`, `(`
+error 31: expected SEMICOLON
+error 31: expected an item
+error 35: expected BANG
+error 35: expected `{`, `[`, `(`
+error 35: expected SEMICOLON
+error 41: expected BANG
+error 41: expected `{`, `[`, `(`
+error 41: expected SEMICOLON
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0002_duplicate_shebang.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0002_duplicate_shebang.rs
new file mode 100644
index 000000000..48a3a3980
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0002_duplicate_shebang.rs
@@ -0,0 +1,2 @@
+#!/use/bin/env rusti
+#!/use/bin/env rusti
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0003_C++_semicolon.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0003_C++_semicolon.rast
new file mode 100644
index 000000000..00131bea5
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0003_C++_semicolon.rast
@@ -0,0 +1,39 @@
+SOURCE_FILE
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ RECORD_FIELD
+ NAME
+ IDENT "a"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ COMMA ","
+ WHITESPACE "\n "
+ RECORD_FIELD
+ NAME
+ IDENT "b"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "String"
+ COMMA ","
+ WHITESPACE "\n"
+ R_CURLY "}"
+ ERROR
+ SEMICOLON ";"
+error 39: expected item, found `;`
+consider removing this semicolon
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0003_C++_semicolon.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0003_C++_semicolon.rs
new file mode 100644
index 000000000..009312270
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0003_C++_semicolon.rs
@@ -0,0 +1,4 @@
+struct S {
+ a: i32,
+ b: String,
+}; \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0004_use_path_bad_segment.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0004_use_path_bad_segment.rast
new file mode 100644
index 000000000..44e192a5f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0004_use_path_bad_segment.rast
@@ -0,0 +1,15 @@
+SOURCE_FILE
+ USE
+ USE_KW "use"
+ WHITESPACE " "
+ USE_TREE
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "foo"
+ COLON2 "::"
+ ERROR
+ INT_NUMBER "92"
+ SEMICOLON ";"
+error 9: expected identifier
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0004_use_path_bad_segment.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0004_use_path_bad_segment.rs
new file mode 100644
index 000000000..060e65d06
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0004_use_path_bad_segment.rs
@@ -0,0 +1 @@
+use foo::92; \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0005_attribute_recover.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0005_attribute_recover.rast
new file mode 100644
index 000000000..6ff072e20
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0005_attribute_recover.rast
@@ -0,0 +1,62 @@
+SOURCE_FILE
+ FN
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "foo"
+ TOKEN_TREE
+ L_PAREN "("
+ IDENT "foo"
+ COMMA ","
+ WHITESPACE " "
+ PLUS "+"
+ COMMA ","
+ WHITESPACE " "
+ INT_NUMBER "92"
+ R_PAREN ")"
+ R_BRACK "]"
+ WHITESPACE "\n"
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n\n\n"
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "foo"
+ TOKEN_TREE
+ L_PAREN "("
+ WHITESPACE "\n"
+ FN_KW "fn"
+ WHITESPACE " "
+ IDENT "foo"
+ TOKEN_TREE
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ TOKEN_TREE
+ L_CURLY "{"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
+error 53: expected R_PAREN
+error 53: expected `]`
+error 53: expected an item
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0005_attribute_recover.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0005_attribute_recover.rs
new file mode 100644
index 000000000..de7f81628
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0005_attribute_recover.rs
@@ -0,0 +1,8 @@
+#[foo(foo, +, 92)]
+fn foo() {
+}
+
+
+#[foo(
+fn foo() {
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0006_named_field_recovery.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0006_named_field_recovery.rast
new file mode 100644
index 000000000..7a4aa93b2
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0006_named_field_recovery.rast
@@ -0,0 +1,74 @@
+SOURCE_FILE
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ RECORD_FIELD
+ NAME
+ IDENT "f"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u32"
+ COMMA ","
+ WHITESPACE "\n "
+ VISIBILITY
+ PUB_KW "pub"
+ WHITESPACE " "
+ ERROR
+ INT_NUMBER "92"
+ WHITESPACE "\n "
+ ERROR
+ PLUS "+"
+ WHITESPACE " "
+ ERROR
+ MINUS "-"
+ WHITESPACE " "
+ ERROR
+ STAR "*"
+ WHITESPACE "\n "
+ RECORD_FIELD
+ VISIBILITY
+ PUB_KW "pub"
+ WHITESPACE " "
+ NAME
+ IDENT "x"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u32"
+ COMMA ","
+ WHITESPACE "\n "
+ RECORD_FIELD
+ NAME
+ IDENT "z"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "f64"
+ COMMA ","
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
+error 31: expected field declaration
+error 33: expected COMMA
+error 38: expected field declaration
+error 39: expected COMMA
+error 40: expected field declaration
+error 41: expected COMMA
+error 42: expected field declaration
+error 43: expected COMMA
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0006_named_field_recovery.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0006_named_field_recovery.rs
new file mode 100644
index 000000000..8069c111b
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0006_named_field_recovery.rs
@@ -0,0 +1,7 @@
+struct S {
+ f: u32,
+ pub 92
+ + - *
+ pub x: u32,
+ z: f64,
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0007_stray_curly_in_file.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0007_stray_curly_in_file.rast
new file mode 100644
index 000000000..5d87ff866
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0007_stray_curly_in_file.rast
@@ -0,0 +1,33 @@
+SOURCE_FILE
+ ERROR
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S"
+ SEMICOLON ";"
+ WHITESPACE "\n\n"
+ ERROR
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ ERROR
+ R_CURLY "}"
+ WHITESPACE "\n"
+error 0: unmatched `}`
+error 14: unmatched `}`
+error 29: unmatched `}`
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0007_stray_curly_in_file.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0007_stray_curly_in_file.rs
new file mode 100644
index 000000000..dc869fb78
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0007_stray_curly_in_file.rs
@@ -0,0 +1,9 @@
+}
+
+struct S;
+
+}
+
+fn foo(){}
+
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0008_item_block_recovery.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0008_item_block_recovery.rast
new file mode 100644
index 000000000..60b2fe987
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0008_item_block_recovery.rast
@@ -0,0 +1,80 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ MACRO_CALL
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "bar"
+ TOKEN_TREE
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ ERROR
+ L_CURLY "{"
+ WHITESPACE "\n "
+ IF_EXPR
+ IF_KW "if"
+ WHITESPACE " "
+ LITERAL
+ TRUE_KW "true"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ LITERAL
+ INT_NUMBER "1"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE " "
+ ELSE_KW "else"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ BIN_EXPR
+ LITERAL
+ INT_NUMBER "2"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "3"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "baz"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
+error 17: expected BANG
+error 19: expected SEMICOLON
+error 20: expected an item
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0008_item_block_recovery.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0008_item_block_recovery.rs
new file mode 100644
index 000000000..9fcac19b5
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0008_item_block_recovery.rs
@@ -0,0 +1,13 @@
+fn foo() {
+}
+
+bar() {
+ if true {
+ 1
+ } else {
+ 2 + 3
+ }
+}
+
+fn baz() {
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0009_broken_struct_type_parameter.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0009_broken_struct_type_parameter.rast
new file mode 100644
index 000000000..a01543217
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0009_broken_struct_type_parameter.rast
@@ -0,0 +1,56 @@
+SOURCE_FILE
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ ERROR
+ INT_NUMBER "90"
+ WHITESPACE " "
+ ERROR
+ PLUS "+"
+ WHITESPACE " "
+ ERROR
+ INT_NUMBER "2"
+ ERROR
+ R_ANGLE ">"
+ WHITESPACE " "
+ ERROR
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "f"
+ ERROR
+ COLON ":"
+ WHITESPACE " "
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u32"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "T"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+error 9: expected type parameter
+error 11: expected COMMA
+error 11: expected R_ANGLE
+error 11: expected `;`, `{`, or `(`
+error 12: expected an item
+error 14: expected an item
+error 15: expected an item
+error 17: expected an item
+error 24: expected SEMICOLON
+error 24: expected expression
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0009_broken_struct_type_parameter.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0009_broken_struct_type_parameter.rs
new file mode 100644
index 000000000..0dd30d0bd
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0009_broken_struct_type_parameter.rs
@@ -0,0 +1,5 @@
+struct S<90 + 2> {
+ f: u32
+}
+
+struct T;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0010_unsafe_lambda_block.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0010_unsafe_lambda_block.rast
new file mode 100644
index 000000000..9427ee5c0
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0010_unsafe_lambda_block.rast
@@ -0,0 +1,45 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CLOSURE_EXPR
+ PARAM_LIST
+ PIPE "|"
+ PIPE "|"
+ WHITESPACE " "
+ RET_TYPE
+ THIN_ARROW "->"
+ WHITESPACE " "
+ TUPLE_TYPE
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ EXPR_STMT
+ BLOCK_EXPR
+ UNSAFE_KW "unsafe"
+ WHITESPACE " "
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
+error 24: expected a block
+error 24: expected SEMICOLON
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0010_unsafe_lambda_block.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0010_unsafe_lambda_block.rs
new file mode 100644
index 000000000..985775282
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0010_unsafe_lambda_block.rs
@@ -0,0 +1,3 @@
+fn main() {
+ || -> () unsafe { () };
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0011_extern_struct.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0011_extern_struct.rast
new file mode 100644
index 000000000..bd5ec4b7c
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0011_extern_struct.rast
@@ -0,0 +1,13 @@
+SOURCE_FILE
+ ERROR
+ ABI
+ EXTERN_KW "extern"
+ WHITESPACE " "
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "Foo"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+error 6: expected existential, fn, trait or impl
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0011_extern_struct.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0011_extern_struct.rs
new file mode 100644
index 000000000..c1bd0a2d1
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0011_extern_struct.rs
@@ -0,0 +1 @@
+extern struct Foo;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0012_broken_lambda.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0012_broken_lambda.rast
new file mode 100644
index 000000000..f31c27633
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0012_broken_lambda.rast
@@ -0,0 +1,387 @@
+SOURCE_FILE@0..389
+ FN@0..389
+ VISIBILITY@0..10
+ PUB_KW@0..3
+ L_PAREN@3..4
+ SUPER_KW@4..9
+ R_PAREN@9..10
+ WHITESPACE@10..11
+ FN_KW@11..13
+ WHITESPACE@13..14
+ NAME@14..21
+ IDENT@14..21 "process"
+ GENERIC_PARAM_LIST@21..38
+ L_ANGLE@21..22
+ LIFETIME_PARAM@22..24
+ LIFETIME@22..24 "'a"
+ COMMA@24..25
+ WHITESPACE@25..26
+ TYPE_PARAM@26..37
+ NAME@26..27
+ IDENT@26..27 "S"
+ COLON@27..28
+ WHITESPACE@28..29
+ PATH@29..37
+ PATH_SEGMENT@29..37
+ NAME_REF@29..33
+ IDENT@29..33 "Sink"
+ GENERIC_ARG_LIST@33..37
+ L_ANGLE@33..34
+ LIFETIME_ARG@34..36
+ LIFETIME@34..36 "'a"
+ R_ANGLE@36..37
+ R_ANGLE@37..38
+ PARAM_LIST@38..93
+ L_PAREN@38..39
+ PARAM@39..54
+ IDENT_PAT@39..46
+ NAME@39..46
+ IDENT@39..46 "builder"
+ COLON@46..47
+ WHITESPACE@47..48
+ REF_TYPE@48..54
+ AMP@48..49
+ MUT_KW@49..52
+ WHITESPACE@52..53
+ PATH_TYPE@53..54
+ PATH@53..54
+ PATH_SEGMENT@53..54
+ NAME_REF@53..54
+ IDENT@53..54 "S"
+ COMMA@54..55
+ WHITESPACE@55..56
+ PARAM@56..72
+ IDENT_PAT@56..62
+ NAME@56..62
+ IDENT@56..62 "tokens"
+ COLON@62..63
+ WHITESPACE@63..64
+ REF_TYPE@64..72
+ AMP@64..65
+ SLICE_TYPE@65..72
+ L_BRACK@65..66
+ PATH_TYPE@66..71
+ PATH@66..71
+ PATH_SEGMENT@66..71
+ NAME_REF@66..71
+ IDENT@66..71 "Token"
+ R_BRACK@71..72
+ COMMA@72..73
+ WHITESPACE@73..74
+ PARAM@74..92
+ IDENT_PAT@74..80
+ NAME@74..80
+ IDENT@74..80 "events"
+ COLON@80..81
+ WHITESPACE@81..82
+ PATH_TYPE@82..92
+ PATH@82..92
+ PATH_SEGMENT@82..92
+ NAME_REF@82..85
+ IDENT@82..85 "Vec"
+ GENERIC_ARG_LIST@85..92
+ L_ANGLE@85..86
+ TYPE_ARG@86..91
+ PATH_TYPE@86..91
+ PATH@86..91
+ PATH_SEGMENT@86..91
+ NAME_REF@86..91
+ IDENT@86..91 "Event"
+ R_ANGLE@91..92
+ R_PAREN@92..93
+ WHITESPACE@93..94
+ BLOCK_EXPR@94..389
+ L_CURLY@94..95
+ WHITESPACE@95..100
+ LET_STMT@100..125
+ LET_KW@100..103
+ WHITESPACE@103..104
+ IDENT_PAT@104..120
+ MUT_KW@104..107
+ WHITESPACE@107..108
+ NAME@108..120
+ IDENT@108..120 "next_tok_idx"
+ WHITESPACE@120..121
+ EQ@121..122
+ WHITESPACE@122..123
+ LITERAL@123..124
+ INT_NUMBER@123..124 "0"
+ SEMICOLON@124..125
+ WHITESPACE@125..130
+ LET_STMT@130..389
+ LET_KW@130..133
+ WHITESPACE@133..134
+ IDENT_PAT@134..140
+ NAME@134..140
+ IDENT@134..140 "eat_ws"
+ WHITESPACE@140..141
+ EQ@141..142
+ WHITESPACE@142..143
+ CLOSURE_EXPR@143..389
+ PARAM_LIST@143..388
+ PIPE@143..144
+ PARAM@144..159
+ IDENT_PAT@144..147
+ NAME@144..147
+ IDENT@144..147 "idx"
+ COLON@147..148
+ WHITESPACE@148..149
+ REF_TYPE@149..159
+ AMP@149..150
+ MUT_KW@150..153
+ WHITESPACE@153..154
+ PATH_TYPE@154..159
+ PATH@154..159
+ PATH_SEGMENT@154..159
+ NAME_REF@154..159
+ IDENT@154..159 "usize"
+ COMMA@159..160
+ WHITESPACE@160..161
+ PARAM@161..167
+ REF_PAT@161..167
+ AMP@161..162
+ MUT_KW@162..165
+ WHITESPACE@165..166
+ err: `expected pattern`
+ ERROR@166..167
+ PIPE@166..167
+ err: `expected COMMA`
+ WHITESPACE@167..168
+ err: `expected pattern`
+ PARAM@168..169
+ ERROR@168..169
+ L_CURLY@168..169
+ err: `expected COMMA`
+ WHITESPACE@169..178
+ err: `expected pattern`
+ PARAM@178..183
+ ERROR@178..183
+ WHILE_KW@178..183
+ err: `expected COMMA`
+ WHITESPACE@183..184
+ err: `expected pattern`
+ PARAM@184..187
+ ERROR@184..187
+ LET_KW@184..187
+ err: `expected COMMA`
+ WHITESPACE@187..188
+ PARAM@188..199
+ TUPLE_STRUCT_PAT@188..199
+ PATH@188..192
+ PATH_SEGMENT@188..192
+ NAME_REF@188..192
+ IDENT@188..192 "Some"
+ L_PAREN@192..193
+ IDENT_PAT@193..198
+ NAME@193..198
+ IDENT@193..198 "token"
+ R_PAREN@198..199
+ err: `expected COMMA`
+ WHITESPACE@199..200
+ err: `expected pattern`
+ PARAM@200..201
+ ERROR@200..201
+ EQ@200..201
+ err: `expected COMMA`
+ WHITESPACE@201..202
+ PARAM@202..208
+ IDENT_PAT@202..208
+ NAME@202..208
+ IDENT@202..208 "tokens"
+ err: `expected COMMA`
+ err: `expected pattern`
+ PARAM@208..209
+ ERROR@208..209
+ DOT@208..209
+ err: `expected COMMA`
+ PARAM@209..218
+ TUPLE_STRUCT_PAT@209..218
+ PATH@209..212
+ PATH_SEGMENT@209..212
+ NAME_REF@209..212
+ IDENT@209..212 "get"
+ L_PAREN@212..213
+ err: `expected pattern`
+ ERROR@213..214
+ STAR@213..214
+ err: `expected COMMA`
+ IDENT_PAT@214..217
+ NAME@214..217
+ IDENT@214..217 "idx"
+ R_PAREN@217..218
+ err: `expected COMMA`
+ WHITESPACE@218..219
+ err: `expected pattern`
+ PARAM@219..220
+ ERROR@219..220
+ L_CURLY@219..220
+ err: `expected COMMA`
+ WHITESPACE@220..233
+ err: `expected pattern`
+ PARAM@233..235
+ ERROR@233..235
+ IF_KW@233..235
+ err: `expected COMMA`
+ WHITESPACE@235..236
+ err: `expected pattern`
+ PARAM@236..237
+ ERROR@236..237
+ BANG@236..237
+ err: `expected COMMA`
+ PARAM@237..242
+ IDENT_PAT@237..242
+ NAME@237..242
+ IDENT@237..242 "token"
+ err: `expected COMMA`
+ err: `expected pattern`
+ PARAM@242..243
+ ERROR@242..243
+ DOT@242..243
+ err: `expected COMMA`
+ PARAM@243..247
+ IDENT_PAT@243..247
+ NAME@243..247
+ IDENT@243..247 "kind"
+ err: `expected COMMA`
+ err: `expected pattern`
+ PARAM@247..248
+ ERROR@247..248
+ DOT@247..248
+ err: `expected COMMA`
+ PARAM@248..259
+ TUPLE_STRUCT_PAT@248..259
+ PATH@248..257
+ PATH_SEGMENT@248..257
+ NAME_REF@248..257
+ IDENT@248..257 "is_trivia"
+ L_PAREN@257..258
+ R_PAREN@258..259
+ err: `expected COMMA`
+ WHITESPACE@259..260
+ err: `expected pattern`
+ PARAM@260..261
+ ERROR@260..261
+ L_CURLY@260..261
+ err: `expected COMMA`
+ WHITESPACE@261..278
+ PARAM@278..283
+ IDENT_PAT@278..283
+ NAME@278..283
+ IDENT@278..283 "break"
+ err: `expected COMMA`
+ err: `expected pattern`
+ PARAM@283..284
+ ERROR@283..284
+ SEMICOLON@283..284
+ err: `expected COMMA`
+ WHITESPACE@284..297
+ err: `expected pattern`
+ PARAM@297..298
+ ERROR@297..298
+ R_CURLY@297..298
+ err: `expected COMMA`
+ WHITESPACE@298..311
+ PARAM@311..318
+ IDENT_PAT@311..318
+ NAME@311..318
+ IDENT@311..318 "builder"
+ err: `expected COMMA`
+ err: `expected pattern`
+ PARAM@318..319
+ ERROR@318..319
+ DOT@318..319
+ err: `expected COMMA`
+ PARAM@319..346
+ TUPLE_STRUCT_PAT@319..346
+ PATH@319..323
+ PATH_SEGMENT@319..323
+ NAME_REF@319..323
+ IDENT@319..323 "leaf"
+ L_PAREN@323..324
+ IDENT_PAT@324..329
+ NAME@324..329
+ IDENT@324..329 "token"
+ err: `expected COMMA`
+ err: `expected pattern`
+ ERROR@329..330
+ DOT@329..330
+ err: `expected COMMA`
+ IDENT_PAT@330..334
+ NAME@330..334
+ IDENT@330..334 "kind"
+ COMMA@334..335
+ WHITESPACE@335..336
+ IDENT_PAT@336..341
+ NAME@336..341
+ IDENT@336..341 "token"
+ err: `expected COMMA`
+ err: `expected pattern`
+ ERROR@341..342
+ DOT@341..342
+ err: `expected COMMA`
+ IDENT_PAT@342..345
+ NAME@342..345
+ IDENT@342..345 "len"
+ R_PAREN@345..346
+ err: `expected COMMA`
+ err: `expected pattern`
+ PARAM@346..347
+ ERROR@346..347
+ SEMICOLON@346..347
+ err: `expected COMMA`
+ WHITESPACE@347..360
+ err: `expected pattern`
+ PARAM@360..361
+ ERROR@360..361
+ STAR@360..361
+ err: `expected COMMA`
+ PARAM@361..364
+ IDENT_PAT@361..364
+ NAME@361..364
+ IDENT@361..364 "idx"
+ err: `expected COMMA`
+ WHITESPACE@364..365
+ err: `expected pattern`
+ PARAM@365..366
+ ERROR@365..366
+ PLUS@365..366
+ err: `expected COMMA`
+ err: `expected pattern`
+ PARAM@366..367
+ ERROR@366..367
+ EQ@366..367
+ err: `expected COMMA`
+ WHITESPACE@367..368
+ PARAM@368..369
+ LITERAL@368..369
+ INT_NUMBER@368..369 "1"
+ err: `expected COMMA`
+ WHITESPACE@369..378
+ err: `expected pattern`
+ PARAM@378..379
+ ERROR@378..379
+ R_CURLY@378..379
+ err: `expected COMMA`
+ WHITESPACE@379..384
+ err: `expected pattern`
+ PARAM@384..385
+ ERROR@384..385
+ R_CURLY@384..385
+ err: `expected COMMA`
+ err: `expected pattern`
+ PARAM@385..386
+ ERROR@385..386
+ SEMICOLON@385..386
+ err: `expected COMMA`
+ WHITESPACE@386..387
+ err: `expected pattern`
+ PARAM@387..388
+ ERROR@387..388
+ R_CURLY@387..388
+ err: `expected COMMA`
+ err: `expected PIPE`
+ WHITESPACE@388..389
+ err: `expected expression`
+ err: `expected SEMI`
+ err: `expected R_CURLY`
+ ERROR@389..389
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0013_invalid_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0013_invalid_type.rast
new file mode 100644
index 000000000..eec84a0c6
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0013_invalid_type.rast
@@ -0,0 +1,89 @@
+SOURCE_FILE
+ STRUCT
+ VISIBILITY
+ PUB_KW "pub"
+ WHITESPACE " "
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "Cache"
+ TUPLE_FIELD_LIST
+ L_PAREN "("
+ WHITESPACE "\n "
+ TUPLE_FIELD
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "RefCell"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ TYPE_ARG
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "HashMap"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ WHITESPACE "\n "
+ TYPE_ARG
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "TypeId"
+ COMMA ","
+ WHITESPACE "\n "
+ TYPE_ARG
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Box"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ TYPE_ARG
+ ERROR
+ AT "@"
+ WHITESPACE " "
+ TUPLE_FIELD
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Any"
+ ERROR
+ ERROR
+ R_ANGLE ">"
+ ERROR
+ COMMA ","
+ WHITESPACE "\n "
+ ERROR
+ R_ANGLE ">"
+ ERROR
+ R_ANGLE ">"
+ WHITESPACE "\n"
+ ERROR
+ R_PAREN ")"
+ ERROR
+ SEMICOLON ";"
+ WHITESPACE "\n\n"
+error 67: expected type
+error 68: expected COMMA
+error 68: expected R_ANGLE
+error 68: expected COMMA
+error 68: expected R_ANGLE
+error 68: expected COMMA
+error 68: expected R_ANGLE
+error 68: expected COMMA
+error 72: expected COMMA
+error 72: expected a type
+error 72: expected R_PAREN
+error 72: expected SEMICOLON
+error 72: expected an item
+error 73: expected an item
+error 79: expected an item
+error 80: expected an item
+error 82: expected an item
+error 83: expected an item
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0013_invalid_type.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0013_invalid_type.rs
new file mode 100644
index 000000000..20dde3bc3
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0013_invalid_type.rs
@@ -0,0 +1,7 @@
+pub struct Cache(
+ RefCell<HashMap<
+ TypeId,
+ Box<@ Any>,
+ >>
+);
+
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0014_where_no_bounds.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0014_where_no_bounds.rast
new file mode 100644
index 000000000..fd2f9ada3
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0014_where_no_bounds.rast
@@ -0,0 +1,32 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "T"
+ R_ANGLE ">"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ WHERE_CLAUSE
+ WHERE_KW "where"
+ WHITESPACE " "
+ WHERE_PRED
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "T"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+error 19: expected colon
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0014_where_no_bounds.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0014_where_no_bounds.rs
new file mode 100644
index 000000000..75c1d2f98
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0014_where_no_bounds.rs
@@ -0,0 +1 @@
+fn foo<T>() where T {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0015_curly_in_params.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0015_curly_in_params.rast
new file mode 100644
index 000000000..8e169320d
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0015_curly_in_params.rast
@@ -0,0 +1,24 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ ERROR
+ R_CURLY "}"
+ ERROR
+ R_PAREN ")"
+ WHITESPACE " "
+ ERROR
+ L_CURLY "{"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
+error 7: expected value parameter
+error 7: expected R_PAREN
+error 7: expected a block
+error 7: unmatched `}`
+error 8: expected an item
+error 10: expected an item
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0015_curly_in_params.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0015_curly_in_params.rs
new file mode 100644
index 000000000..156e70251
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0015_curly_in_params.rs
@@ -0,0 +1,2 @@
+fn foo(}) {
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0016_missing_semi.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0016_missing_semi.rast
new file mode 100644
index 000000000..c48c35bf8
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0016_missing_semi.rast
@@ -0,0 +1,44 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "foo"
+ ARG_LIST
+ L_PAREN "("
+ WHITESPACE "\n "
+ LITERAL
+ INT_NUMBER "1"
+ COMMA ","
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "2"
+ WHITESPACE "\n "
+ R_PAREN ")"
+ WHITESPACE "\n "
+ EXPR_STMT
+ RETURN_EXPR
+ RETURN_KW "return"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "92"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
+error 38: expected SEMICOLON
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0016_missing_semi.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0016_missing_semi.rs
new file mode 100644
index 000000000..9ae857686
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0016_missing_semi.rs
@@ -0,0 +1,6 @@
+fn foo() {
+ foo(
+ 1, 2
+ )
+ return 92;
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0017_incomplete_binexpr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0017_incomplete_binexpr.rast
new file mode 100644
index 000000000..807356462
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0017_incomplete_binexpr.rast
@@ -0,0 +1,47 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "foo"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "bar"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "92"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ BIN_EXPR
+ LITERAL
+ INT_NUMBER "1"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
+error 44: expected expression
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0017_incomplete_binexpr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0017_incomplete_binexpr.rs
new file mode 100644
index 000000000..17bd49777
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0017_incomplete_binexpr.rs
@@ -0,0 +1,4 @@
+fn foo(foo: i32) {
+ let bar = 92;
+ 1 +
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0018_incomplete_fn.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0018_incomplete_fn.rast
new file mode 100644
index 000000000..6524d8e8f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0018_incomplete_fn.rast
@@ -0,0 +1,134 @@
+SOURCE_FILE
+ IMPL
+ IMPL_KW "impl"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "FnScopes"
+ WHITESPACE " "
+ ASSOC_ITEM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "new_scope"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ REF_PAT
+ AMP "&"
+ R_PAREN ")"
+ WHITESPACE " "
+ RET_TYPE
+ THIN_ARROW "->"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "ScopeId"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "res"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ METHOD_CALL_EXPR
+ FIELD_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ SELF_KW "self"
+ DOT "."
+ NAME_REF
+ IDENT "scopes"
+ DOT "."
+ NAME_REF
+ IDENT "len"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ METHOD_CALL_EXPR
+ FIELD_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ SELF_KW "self"
+ DOT "."
+ NAME_REF
+ IDENT "scopes"
+ DOT "."
+ NAME_REF
+ IDENT "push"
+ ARG_LIST
+ L_PAREN "("
+ RECORD_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "ScopeData"
+ WHITESPACE " "
+ RECORD_EXPR_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ RECORD_EXPR_FIELD
+ NAME_REF
+ IDENT "parent"
+ COLON ":"
+ WHITESPACE " "
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "None"
+ COMMA ","
+ WHITESPACE " "
+ RECORD_EXPR_FIELD
+ NAME_REF
+ IDENT "entries"
+ COLON ":"
+ WHITESPACE " "
+ MACRO_EXPR
+ MACRO_CALL
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "vec"
+ BANG "!"
+ TOKEN_TREE
+ L_BRACK "["
+ R_BRACK "]"
+ WHITESPACE " "
+ R_CURLY "}"
+ R_PAREN ")"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n\n "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "set_parent"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
+error 34: expected pattern
+error 34: missing type for function parameter
+error 180: expected function arguments
+error 180: expected a block
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0018_incomplete_fn.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0018_incomplete_fn.rs
new file mode 100644
index 000000000..fe604006c
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0018_incomplete_fn.rs
@@ -0,0 +1,8 @@
+impl FnScopes {
+ fn new_scope(&) -> ScopeId {
+ let res = self.scopes.len();
+ self.scopes.push(ScopeData { parent: None, entries: vec![] })
+ }
+
+ fn set_parent
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0019_let_recover.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0019_let_recover.rast
new file mode 100644
index 000000000..7d62e0cc1
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0019_let_recover.rast
@@ -0,0 +1,107 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "foo"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "11"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "bar"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "1"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "baz"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "92"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE "\n "
+ EXPR_STMT
+ IF_EXPR
+ IF_KW "if"
+ WHITESPACE " "
+ LITERAL
+ TRUE_KW "true"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE "\n "
+ EXPR_STMT
+ WHILE_EXPR
+ WHILE_KW "while"
+ WHITESPACE " "
+ LITERAL
+ TRUE_KW "true"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE "\n "
+ LOOP_EXPR
+ LOOP_KW "loop"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
+error 27: expected SEMICOLON
+error 52: expected pattern
+error 52: expected SEMICOLON
+error 78: expected pattern
+error 78: expected SEMICOLON
+error 101: expected pattern
+error 101: expected SEMICOLON
+error 127: expected pattern
+error 127: expected SEMICOLON
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0019_let_recover.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0019_let_recover.rs
new file mode 100644
index 000000000..5108d5a49
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0019_let_recover.rs
@@ -0,0 +1,12 @@
+fn foo() {
+ let foo = 11
+ let bar = 1;
+ let
+ let baz = 92;
+ let
+ if true {}
+ let
+ while true {}
+ let
+ loop {}
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0020_fn_recover.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0020_fn_recover.rast
new file mode 100644
index 000000000..56d124cb9
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0020_fn_recover.rast
@@ -0,0 +1,21 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE "\n\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+error 2: expected a name
+error 2: expected function arguments
+error 2: expected a block
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0020_fn_recover.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0020_fn_recover.rs
new file mode 100644
index 000000000..3393b668b
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0020_fn_recover.rs
@@ -0,0 +1,3 @@
+fn
+
+fn foo() {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0021_incomplete_param.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0021_incomplete_param.rast
new file mode 100644
index 000000000..762840aa2
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0021_incomplete_param.rast
@@ -0,0 +1,34 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "x"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ COMMA ","
+ WHITESPACE " "
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "y"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
+error 16: missing type for function parameter
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0021_incomplete_param.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0021_incomplete_param.rs
new file mode 100644
index 000000000..7a6c264f6
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0021_incomplete_param.rs
@@ -0,0 +1,2 @@
+fn foo(x: i32, y) {
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0022_bad_exprs.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0022_bad_exprs.rast
new file mode 100644
index 000000000..900394bd9
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0022_bad_exprs.rast
@@ -0,0 +1,171 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "a"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ EXPR_STMT
+ ARRAY_EXPR
+ L_BRACK "["
+ LITERAL
+ INT_NUMBER "1"
+ COMMA ","
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "2"
+ COMMA ","
+ WHITESPACE " "
+ ERROR
+ AT "@"
+ ERROR
+ COMMA ","
+ WHITESPACE " "
+ STRUCT
+ STRUCT_KW "struct"
+ ERROR
+ COMMA ","
+ WHITESPACE " "
+ LET_STMT
+ LET_KW "let"
+ ERROR
+ R_BRACK "]"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "b"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ EXPR_STMT
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "foo"
+ ARG_LIST
+ L_PAREN "("
+ LITERAL
+ INT_NUMBER "1"
+ COMMA ","
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "2"
+ COMMA ","
+ WHITESPACE " "
+ ERROR
+ AT "@"
+ ERROR
+ COMMA ","
+ WHITESPACE " "
+ IMPL
+ IMPL_KW "impl"
+ ERROR
+ COMMA ","
+ WHITESPACE " "
+ LET_STMT
+ LET_KW "let"
+ ERROR
+ R_PAREN ")"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "c"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ EXPR_STMT
+ METHOD_CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "foo"
+ DOT "."
+ NAME_REF
+ IDENT "bar"
+ ARG_LIST
+ L_PAREN "("
+ LITERAL
+ INT_NUMBER "1"
+ COMMA ","
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "2"
+ COMMA ","
+ WHITESPACE " "
+ ERROR
+ AT "@"
+ ERROR
+ COMMA ","
+ WHITESPACE " "
+ ERROR
+ R_BRACK "]"
+ ERROR
+ COMMA ","
+ WHITESPACE " "
+ TRAIT
+ TRAIT_KW "trait"
+ ERROR
+ COMMA ","
+ WHITESPACE " "
+ LET_STMT
+ LET_KW "let"
+ ERROR
+ R_PAREN ")"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
+error 16: expected expression
+error 17: expected R_BRACK
+error 17: expected SEMICOLON
+error 17: expected expression
+error 25: expected a name
+error 26: expected `;`, `{`, or `(`
+error 30: expected pattern
+error 31: expected SEMICOLON
+error 53: expected expression
+error 54: expected SEMICOLON
+error 54: expected expression
+error 60: expected type
+error 60: expected `{`
+error 60: expected expression
+error 65: expected pattern
+error 65: expected SEMICOLON
+error 65: expected expression
+error 92: expected expression
+error 93: expected SEMICOLON
+error 93: expected expression
+error 95: expected expression
+error 96: expected expression
+error 103: expected a name
+error 104: expected `{`
+error 108: expected pattern
+error 108: expected SEMICOLON
+error 108: expected expression
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0022_bad_exprs.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0022_bad_exprs.rs
new file mode 100644
index 000000000..cd2d493a1
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0022_bad_exprs.rs
@@ -0,0 +1,3 @@
+fn a() { [1, 2, @, struct, let] }
+fn b() { foo(1, 2, @, impl, let) }
+fn c() { foo.bar(1, 2, @, ], trait, let) }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0023_mismatched_paren.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0023_mismatched_paren.rast
new file mode 100644
index 000000000..4064a7a1f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0023_mismatched_paren.rast
@@ -0,0 +1,45 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ MACRO_EXPR
+ MACRO_CALL
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "foo"
+ BANG "!"
+ WHITESPACE " "
+ TOKEN_TREE
+ L_PAREN "("
+ WHITESPACE "\n "
+ IDENT "bar"
+ COMMA ","
+ WHITESPACE " "
+ STRING "\"baz\""
+ COMMA ","
+ WHITESPACE " "
+ INT_NUMBER "1"
+ COMMA ","
+ WHITESPACE " "
+ FLOAT_NUMBER "2.0"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE " "
+ COMMENT "//~ ERROR incorrect close delimiter"
+ WHITESPACE "\n"
+ ERROR
+ R_CURLY "}"
+ WHITESPACE "\n"
+error 49: unmatched `}`
+error 92: unmatched `}`
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0023_mismatched_paren.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0023_mismatched_paren.rs
new file mode 100644
index 000000000..0206d563e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0023_mismatched_paren.rs
@@ -0,0 +1,5 @@
+fn main() {
+ foo! (
+ bar, "baz", 1, 2.0
+ } //~ ERROR incorrect close delimiter
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0024_many_type_parens.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0024_many_type_parens.rast
new file mode 100644
index 000000000..d374f8661
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0024_many_type_parens.rast
@@ -0,0 +1,327 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "f"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "T"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ L_PAREN "("
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Copy"
+ R_PAREN ")"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ TYPE_BOUND
+ L_PAREN "("
+ QUESTION "?"
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Sized"
+ R_PAREN ")"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ TYPE_BOUND
+ L_PAREN "("
+ FOR_TYPE
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Trait"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ LIFETIME_ARG
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ R_PAREN ")"
+ R_ANGLE ">"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ COLON ":"
+ WHITESPACE " "
+ DYN_TRAIT_TYPE
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Box"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ TYPE_ARG
+ PAREN_TYPE
+ L_PAREN "("
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Copy"
+ R_PAREN ")"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ TYPE_BOUND
+ L_PAREN "("
+ QUESTION "?"
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Sized"
+ R_PAREN ")"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ TYPE_BOUND
+ L_PAREN "("
+ FOR_TYPE
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Trait"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ LIFETIME_ARG
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ R_PAREN ")"
+ ERROR
+ R_ANGLE ">"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Box"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ TYPE_ARG
+ PAREN_TYPE
+ L_PAREN "("
+ ERROR
+ QUESTION "?"
+ EXPR_STMT
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Sized"
+ ERROR
+ R_PAREN ")"
+ WHITESPACE " "
+ ERROR
+ PLUS "+"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ CLOSURE_EXPR
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ WHITESPACE " "
+ BIN_EXPR
+ BIN_EXPR
+ BIN_EXPR
+ BIN_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Trait"
+ L_ANGLE "<"
+ ERROR
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ ERROR
+ R_PAREN ")"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ PAREN_EXPR
+ L_PAREN "("
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Copy"
+ R_PAREN ")"
+ R_ANGLE ">"
+ ERROR
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_EXPR
+ LET_KW "let"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ ERROR
+ COLON ":"
+ WHITESPACE " "
+ BIN_EXPR
+ BIN_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Box"
+ L_ANGLE "<"
+ TUPLE_EXPR
+ L_PAREN "("
+ CLOSURE_EXPR
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ WHITESPACE " "
+ BIN_EXPR
+ BIN_EXPR
+ BIN_EXPR
+ BIN_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Trait"
+ L_ANGLE "<"
+ ERROR
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ ERROR
+ R_PAREN ")"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ PAREN_EXPR
+ L_PAREN "("
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Copy"
+ R_PAREN ")"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ PAREN_EXPR
+ L_PAREN "("
+ ERROR
+ QUESTION "?"
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Sized"
+ R_PAREN ")"
+ R_ANGLE ">"
+ ERROR
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
+error 88: expected COMMA
+error 88: expected R_ANGLE
+error 121: expected SEMICOLON
+error 121: expected expression
+error 140: expected type
+error 141: expected R_PAREN
+error 141: expected COMMA
+error 141: expected R_ANGLE
+error 141: expected SEMICOLON
+error 146: expected SEMICOLON
+error 146: expected expression
+error 148: expected expression
+error 158: expected `|`
+error 158: expected COMMA
+error 165: expected expression
+error 168: expected expression
+error 179: expected expression
+error 180: expected COMMA
+error 190: expected EQ
+error 190: expected expression
+error 191: expected COMMA
+error 204: expected `|`
+error 204: expected COMMA
+error 211: expected expression
+error 214: expected expression
+error 228: expected expression
+error 229: expected R_PAREN
+error 229: expected COMMA
+error 236: expected expression
+error 237: expected COMMA
+error 237: expected expression
+error 237: expected R_PAREN
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0024_many_type_parens.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0024_many_type_parens.rs
new file mode 100644
index 000000000..6c2e95c02
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0024_many_type_parens.rs
@@ -0,0 +1,7 @@
+fn f<T: (Copy) + (?Sized) + (for<'a> Trait<'a>)>() {}
+
+fn main() {
+ let _: Box<(Copy) + (?Sized) + (for<'a> Trait<'a>)>;
+ let _: Box<(?Sized) + (for<'a> Trait<'a>) + (Copy)>;
+ let _: Box<(for<'a> Trait<'a>) + (Copy) + (?Sized)>;
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0025_nope.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0025_nope.rast
new file mode 100644
index 000000000..6b49724ec
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0025_nope.rast
@@ -0,0 +1,209 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ ENUM
+ ENUM_KW "enum"
+ WHITESPACE " "
+ NAME
+ IDENT "Test"
+ WHITESPACE " "
+ VARIANT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ VARIANT
+ NAME
+ IDENT "Var1"
+ COMMA ","
+ WHITESPACE "\n "
+ VARIANT
+ NAME
+ IDENT "Var2"
+ TUPLE_FIELD_LIST
+ L_PAREN "("
+ TUPLE_FIELD
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "String"
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n "
+ VARIANT
+ NAME
+ IDENT "Var3"
+ WHITESPACE " "
+ RECORD_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ RECORD_FIELD
+ NAME
+ IDENT "abc"
+ COLON ":"
+ WHITESPACE " "
+ ERROR
+ L_CURLY "{"
+ R_CURLY "}"
+ ERROR
+ COMMA ","
+ WHITESPACE " "
+ COMMENT "//~ ERROR: expected type, found `{`"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ COMMA ","
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n\n "
+ COMMENT "// recover..."
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "a"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "1"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ ENUM
+ ENUM_KW "enum"
+ WHITESPACE " "
+ NAME
+ IDENT "Test2"
+ WHITESPACE " "
+ VARIANT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ VARIANT
+ NAME
+ IDENT "Fine"
+ COMMA ","
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n\n "
+ ENUM
+ ENUM_KW "enum"
+ WHITESPACE " "
+ NAME
+ IDENT "Test3"
+ WHITESPACE " "
+ VARIANT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ VARIANT
+ NAME
+ IDENT "StillFine"
+ WHITESPACE " "
+ RECORD_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ RECORD_FIELD
+ NAME
+ IDENT "def"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ COMMA ","
+ WHITESPACE "\n "
+ R_CURLY "}"
+ COMMA ","
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n\n "
+ EXPR_STMT
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ ENUM
+ COMMENT "// fail again"
+ WHITESPACE "\n "
+ ENUM_KW "enum"
+ WHITESPACE " "
+ NAME
+ IDENT "Test4"
+ WHITESPACE " "
+ VARIANT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ VARIANT
+ NAME
+ IDENT "Nope"
+ TUPLE_FIELD_LIST
+ L_PAREN "("
+ TUPLE_FIELD
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ WHITESPACE " "
+ ERROR
+ ERROR
+ L_CURLY "{"
+ R_CURLY "}"
+ ERROR
+ R_PAREN ")"
+ WHITESPACE " "
+ COMMENT "//~ ERROR: found `{`"
+ WHITESPACE "\n "
+ COMMENT "//~^ ERROR: found `{`"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n "
+ COMMENT "// still recover later"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ ERROR
+ SEMICOLON ";"
+ WHITESPACE " "
+ COMMENT "//~ ERROR: expected pattern"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "0"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
+error 95: expected type
+error 95: expected COMMA
+error 96: expected field
+error 98: expected field declaration
+error 371: expected COMMA
+error 372: expected a type
+error 372: expected R_PAREN
+error 372: expected COMMA
+error 372: expected enum variant
+error 374: expected enum variant
+error 494: expected pattern
+error 495: expected SEMICOLON
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0025_nope.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0025_nope.rs
new file mode 100644
index 000000000..c78abe80a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0025_nope.rs
@@ -0,0 +1,32 @@
+fn main() {
+ enum Test {
+ Var1,
+ Var2(String),
+ Var3 {
+ abc: {}, //~ ERROR: expected type, found `{`
+ },
+ }
+
+ // recover...
+ let a = 1;
+ enum Test2 {
+ Fine,
+ }
+
+ enum Test3 {
+ StillFine {
+ def: i32,
+ },
+ }
+
+ {
+ // fail again
+ enum Test4 {
+ Nope(i32 {}) //~ ERROR: found `{`
+ //~^ ERROR: found `{`
+ }
+ }
+ // still recover later
+ let; //~ ERROR: expected pattern
+ let _ = 0;
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0026_imp_recovery.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0026_imp_recovery.rast
new file mode 100644
index 000000000..1068418e0
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0026_imp_recovery.rast
@@ -0,0 +1,49 @@
+SOURCE_FILE
+ IMPL
+ IMPL_KW "impl"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "T"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Clone"
+ R_ANGLE ">"
+ WHITESPACE "\n"
+ IMPL
+ IMPL_KW "impl"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "T"
+ R_ANGLE ">"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "OnceCell"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ TYPE_ARG
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "T"
+ R_ANGLE ">"
+ WHITESPACE " "
+ ASSOC_ITEM_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+error 14: expected trait or type
+error 14: expected `{`
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0026_imp_recovery.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0026_imp_recovery.rs
new file mode 100644
index 000000000..829ca1c4b
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0026_imp_recovery.rs
@@ -0,0 +1,2 @@
+impl<T: Clone>
+impl<T> OnceCell<T> {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0027_incomplere_where_for.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0027_incomplere_where_for.rast
new file mode 100644
index 000000000..674c8d536
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0027_incomplere_where_for.rast
@@ -0,0 +1,29 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE "\n "
+ WHERE_CLAUSE
+ WHERE_KW "where"
+ WHITESPACE " "
+ WHERE_PRED
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ WHITESPACE "\n"
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+error 26: expected type
+error 26: expected colon
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0027_incomplere_where_for.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0027_incomplere_where_for.rs
new file mode 100644
index 000000000..2792c2084
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0027_incomplere_where_for.rs
@@ -0,0 +1,3 @@
+fn foo()
+ where for<'a>
+{}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0029_field_completion.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0029_field_completion.rast
new file mode 100644
index 000000000..fb037112f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0029_field_completion.rast
@@ -0,0 +1,36 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "a"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "A"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ FIELD_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "a"
+ DOT "."
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
+error 21: expected field name or number
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0029_field_completion.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0029_field_completion.rs
new file mode 100644
index 000000000..a7cdc17bb
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0029_field_completion.rs
@@ -0,0 +1,3 @@
+fn foo(a: A) {
+ a.
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0032_match_arms_inner_attrs.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0032_match_arms_inner_attrs.rast
new file mode 100644
index 000000000..327bf94a4
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0032_match_arms_inner_attrs.rast
@@ -0,0 +1,205 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ MATCH_EXPR
+ MATCH_KW "match"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ MATCH_ARM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ MATCH_ARM
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n "
+ MATCH_ARM
+ ATTR
+ POUND "#"
+ ERROR
+ BANG "!"
+ ARRAY_EXPR
+ L_BRACK "["
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "doc"
+ ARG_LIST
+ L_PAREN "("
+ LITERAL
+ STRING "\"Not allowed here\""
+ R_PAREN ")"
+ R_BRACK "]"
+ WHITESPACE "\n "
+ MATCH_ARM
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n\n "
+ EXPR_STMT
+ MATCH_EXPR
+ MATCH_KW "match"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ MATCH_ARM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ MATCH_ARM
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n "
+ MATCH_ARM
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n "
+ MATCH_ARM
+ ATTR
+ POUND "#"
+ ERROR
+ BANG "!"
+ ARRAY_EXPR
+ L_BRACK "["
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "doc"
+ ARG_LIST
+ L_PAREN "("
+ LITERAL
+ STRING "\"Nor here\""
+ R_PAREN ")"
+ R_BRACK "]"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n\n "
+ MATCH_EXPR
+ MATCH_KW "match"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ MATCH_ARM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ MATCH_ARM
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "cfg"
+ TOKEN_TREE
+ L_PAREN "("
+ IDENT "test"
+ R_PAREN ")"
+ R_BRACK "]"
+ WHITESPACE "\n "
+ ATTR
+ POUND "#"
+ ERROR
+ BANG "!"
+ ARRAY_EXPR
+ L_BRACK "["
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "doc"
+ ARG_LIST
+ L_PAREN "("
+ LITERAL
+ STRING "\"Nor here\""
+ R_PAREN ")"
+ R_BRACK "]"
+ WHITESPACE "\n "
+ MATCH_ARM
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n "
+ MATCH_ARM
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
+error 52: expected `[`
+error 52: expected pattern
+error 53: expected FAT_ARROW
+error 78: expected `,`
+error 161: expected `[`
+error 161: expected pattern
+error 162: expected FAT_ARROW
+error 232: expected `[`
+error 232: expected pattern
+error 233: expected FAT_ARROW
+error 250: expected `,`
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0032_match_arms_inner_attrs.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0032_match_arms_inner_attrs.rs
new file mode 100644
index 000000000..06aa47770
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0032_match_arms_inner_attrs.rs
@@ -0,0 +1,20 @@
+fn foo() {
+ match () {
+ _ => (),
+ #![doc("Not allowed here")]
+ _ => (),
+ }
+
+ match () {
+ _ => (),
+ _ => (),
+ #![doc("Nor here")]
+ }
+
+ match () {
+ #[cfg(test)]
+ #![doc("Nor here")]
+ _ => (),
+ _ => (),
+ }
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0033_match_arms_outer_attrs.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0033_match_arms_outer_attrs.rast
new file mode 100644
index 000000000..b5bc3d84d
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0033_match_arms_outer_attrs.rast
@@ -0,0 +1,68 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ MATCH_EXPR
+ MATCH_KW "match"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ MATCH_ARM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ MATCH_ARM
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n "
+ MATCH_ARM
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n "
+ MATCH_ARM
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "cfg"
+ TOKEN_TREE
+ L_PAREN "("
+ IDENT "test"
+ R_PAREN ")"
+ R_BRACK "]"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
+error 80: expected pattern
+error 80: expected FAT_ARROW
+error 80: expected expression
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0033_match_arms_outer_attrs.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0033_match_arms_outer_attrs.rs
new file mode 100644
index 000000000..4635222da
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0033_match_arms_outer_attrs.rs
@@ -0,0 +1,7 @@
+fn foo() {
+ match () {
+ _ => (),
+ _ => (),
+ #[cfg(test)]
+ }
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0034_bad_box_pattern.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0034_bad_box_pattern.rast
new file mode 100644
index 000000000..7a2ae9103
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0034_bad_box_pattern.rast
@@ -0,0 +1,96 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ REF_KW "ref"
+ WHITESPACE " "
+ ERROR
+ BOX_KW "box"
+ WHITESPACE " "
+ EXPR_STMT
+ BIN_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ MUT_KW "mut"
+ WHITESPACE " "
+ ERROR
+ BOX_KW "box"
+ WHITESPACE " "
+ EXPR_STMT
+ BIN_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ REF_KW "ref"
+ WHITESPACE " "
+ MUT_KW "mut"
+ WHITESPACE " "
+ ERROR
+ BOX_KW "box"
+ WHITESPACE " "
+ EXPR_STMT
+ BIN_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+error 24: expected a name
+error 27: expected SEMICOLON
+error 48: expected a name
+error 51: expected SEMICOLON
+error 76: expected a name
+error 79: expected SEMICOLON
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0034_bad_box_pattern.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0034_bad_box_pattern.rs
new file mode 100644
index 000000000..d3fa2e468
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0034_bad_box_pattern.rs
@@ -0,0 +1,6 @@
+fn main() {
+ let ref box i = ();
+ let mut box i = ();
+ let ref mut box i = ();
+}
+
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0035_use_recover.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0035_use_recover.rast
new file mode 100644
index 000000000..f9287d42e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0035_use_recover.rast
@@ -0,0 +1,55 @@
+SOURCE_FILE
+ USE
+ USE_KW "use"
+ WHITESPACE " "
+ USE_TREE
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "foo"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "bar"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ USE
+ USE_KW "use"
+ WHITESPACE "\n"
+ USE
+ USE_KW "use"
+ WHITESPACE " "
+ USE_TREE
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ CRATE_KW "crate"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "baz"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ USE
+ USE_KW "use"
+ WHITESPACE "\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "f"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+error 17: expected one of `*`, `::`, `{`, `self`, `super` or an identifier
+error 17: expected SEMICOLON
+error 37: expected one of `*`, `::`, `{`, `self`, `super` or an identifier
+error 37: expected SEMICOLON
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0035_use_recover.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0035_use_recover.rs
new file mode 100644
index 000000000..4a2668126
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0035_use_recover.rs
@@ -0,0 +1,5 @@
+use foo::bar;
+use
+use crate::baz;
+use
+fn f() {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0036_partial_use.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0036_partial_use.rast
new file mode 100644
index 000000000..13e76e683
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0036_partial_use.rast
@@ -0,0 +1,51 @@
+SOURCE_FILE
+ USE
+ USE_KW "use"
+ WHITESPACE " "
+ USE_TREE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "std"
+ COLON2 "::"
+ USE_TREE_LIST
+ L_CURLY "{"
+ USE_TREE
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "error"
+ COLON2 "::"
+ 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 ";"
+ 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
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0036_partial_use.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0036_partial_use.rs
new file mode 100644
index 000000000..d521a5bb2
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0036_partial_use.rs
@@ -0,0 +1,2 @@
+use std::{error::Error;
+use std::io;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0039_lambda_recovery.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0039_lambda_recovery.rast
new file mode 100644
index 000000000..8ca160601
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0039_lambda_recovery.rast
@@ -0,0 +1,83 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ RET_TYPE
+ THIN_ARROW "->"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ METHOD_CALL_EXPR
+ METHOD_CALL_EXPR
+ METHOD_CALL_EXPR
+ ARRAY_EXPR
+ L_BRACK "["
+ LITERAL
+ INT_NUMBER "1"
+ COMMA ","
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "2"
+ COMMA ","
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "3"
+ R_BRACK "]"
+ DOT "."
+ NAME_REF
+ IDENT "iter"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE "\n "
+ DOT "."
+ NAME_REF
+ IDENT "map"
+ ARG_LIST
+ L_PAREN "("
+ CLOSURE_EXPR
+ PARAM_LIST
+ PIPE "|"
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "it"
+ PIPE "|"
+ R_PAREN ")"
+ WHITESPACE "\n "
+ DOT "."
+ NAME_REF
+ IDENT "max"
+ GENERIC_ARG_LIST
+ COLON2 "::"
+ L_ANGLE "<"
+ TYPE_ARG
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ R_ANGLE ">"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
+error 56: expected expression
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0039_lambda_recovery.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0039_lambda_recovery.rs
new file mode 100644
index 000000000..a2f74bd87
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0039_lambda_recovery.rs
@@ -0,0 +1,5 @@
+fn foo() -> i32 {
+ [1, 2, 3].iter()
+ .map(|it|)
+ .max::<i32>();
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0042_weird_blocks.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0042_weird_blocks.rast
new file mode 100644
index 000000000..9cea337ce
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0042_weird_blocks.rast
@@ -0,0 +1,75 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ ERROR
+ UNSAFE_KW "unsafe"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "92"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ ERROR
+ ASYNC_KW "async"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "92"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ EXPR_STMT
+ BLOCK_EXPR
+ TRY_KW "try"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "92"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ ERROR
+ LABEL
+ LIFETIME
+ LIFETIME_IDENT "'label"
+ COLON ":"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "92"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
+error 24: expected existential, fn, trait or impl
+error 41: expected existential, fn, trait or impl
+error 56: expected a block
+error 75: expected a loop
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0042_weird_blocks.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0042_weird_blocks.rs
new file mode 100644
index 000000000..8fa324c1a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0042_weird_blocks.rs
@@ -0,0 +1,6 @@
+fn main() {
+ { unsafe 92 }
+ { async 92 }
+ { try 92 }
+ { 'label: 92 }
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0043_unexpected_for_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0043_unexpected_for_type.rast
new file mode 100644
index 000000000..cb4fb1642
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0043_unexpected_for_type.rast
@@ -0,0 +1,256 @@
+SOURCE_FILE
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "ForRef"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ FOR_TYPE
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ WHITESPACE " "
+ REF_TYPE
+ AMP "&"
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u32"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "ForTup"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ FOR_TYPE
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ WHITESPACE " "
+ TUPLE_TYPE
+ L_PAREN "("
+ REF_TYPE
+ AMP "&"
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u32"
+ COMMA ","
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "ForSlice"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ FOR_TYPE
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ WHITESPACE " "
+ SLICE_TYPE
+ L_BRACK "["
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u32"
+ R_BRACK "]"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "ForForFn"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ FOR_TYPE
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ WHITESPACE " "
+ FOR_TYPE
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'b"
+ R_ANGLE ">"
+ WHITESPACE " "
+ FN_PTR_TYPE
+ FN_KW "fn"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ REF_TYPE
+ AMP "&"
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ COMMA ","
+ WHITESPACE " "
+ PARAM
+ REF_TYPE
+ AMP "&"
+ LIFETIME
+ LIFETIME_IDENT "'b"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "for_for_for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "T"
+ R_ANGLE ">"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE "\n"
+ WHERE_CLAUSE
+ WHERE_KW "where"
+ WHITESPACE "\n "
+ WHERE_PRED
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ WHITESPACE " "
+ FOR_TYPE
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'b"
+ R_ANGLE ">"
+ WHITESPACE " "
+ FOR_TYPE
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'c"
+ R_ANGLE ">"
+ WHITESPACE " "
+ FN_PTR_TYPE
+ FN_KW "fn"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ REF_TYPE
+ AMP "&"
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "T"
+ COMMA ","
+ WHITESPACE " "
+ PARAM
+ REF_TYPE
+ AMP "&"
+ LIFETIME
+ LIFETIME_IDENT "'b"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "T"
+ COMMA ","
+ WHITESPACE " "
+ PARAM
+ REF_TYPE
+ AMP "&"
+ LIFETIME
+ LIFETIME_IDENT "'c"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "T"
+ R_PAREN ")"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Copy"
+ COMMA ","
+ WHITESPACE "\n"
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
+error 21: expected a function pointer or path
+error 52: expected a function pointer or path
+error 88: expected a function pointer or path
+error 119: expected a function pointer or path
+error 195: expected a function pointer or path
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0043_unexpected_for_type.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0043_unexpected_for_type.rs
new file mode 100644
index 000000000..0e9f8ccb4
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0043_unexpected_for_type.rs
@@ -0,0 +1,9 @@
+type ForRef = for<'a> &'a u32;
+type ForTup = for<'a> (&'a u32,);
+type ForSlice = for<'a> [u32];
+type ForForFn = for<'a> for<'b> fn(&'a i32, &'b i32);
+fn for_for_for<T>()
+where
+ for<'a> for<'b> for<'c> fn(&'a T, &'b T, &'c T): Copy,
+{
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0044_item_modifiers.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0044_item_modifiers.rast
new file mode 100644
index 000000000..96e471a69
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0044_item_modifiers.rast
@@ -0,0 +1,48 @@
+SOURCE_FILE
+ ERROR
+ UNSAFE_KW "unsafe"
+ WHITESPACE " "
+ FN
+ ASYNC_KW "async"
+ WHITESPACE " "
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ CONST
+ UNSAFE_KW "unsafe"
+ WHITESPACE " "
+ CONST_KW "const"
+ WHITESPACE " "
+ ERROR
+ FN_KW "fn"
+ WHITESPACE " "
+ MACRO_CALL
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "bar"
+ TOKEN_TREE
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ ERROR
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+error 6: expected existential, fn, trait or impl
+error 38: expected a name
+error 40: missing type for `const` or `static`
+error 40: expected SEMICOLON
+error 44: expected BANG
+error 46: expected SEMICOLON
+error 47: expected an item
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0044_item_modifiers.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0044_item_modifiers.rs
new file mode 100644
index 000000000..731e58013
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0044_item_modifiers.rs
@@ -0,0 +1,2 @@
+unsafe async fn foo() {}
+unsafe const fn bar() {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0047_repated_extern_modifier.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0047_repated_extern_modifier.rast
new file mode 100644
index 000000000..4b2a74036
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0047_repated_extern_modifier.rast
@@ -0,0 +1,15 @@
+SOURCE_FILE
+ ERROR
+ ABI
+ EXTERN_KW "extern"
+ WHITESPACE " "
+ STRING "\"C\""
+ WHITESPACE " "
+ ERROR
+ ABI
+ EXTERN_KW "extern"
+ WHITESPACE " "
+ STRING "\"C\""
+ WHITESPACE "\n"
+error 10: expected existential, fn, trait or impl
+error 21: expected existential, fn, trait or impl
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0047_repated_extern_modifier.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0047_repated_extern_modifier.rs
new file mode 100644
index 000000000..db32b98df
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0047_repated_extern_modifier.rs
@@ -0,0 +1 @@
+extern "C" extern "C"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0048_double_fish.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0048_double_fish.rast
new file mode 100644
index 000000000..3a05bfee1
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0048_double_fish.rast
@@ -0,0 +1,123 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "f"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ GENERIC_ARG_LIST
+ COLON2 "::"
+ L_ANGLE "<"
+ TYPE_ARG
+ PATH_TYPE
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Item"
+ GENERIC_ARG_LIST
+ COLON2 "::"
+ L_ANGLE "<"
+ TYPE_ARG
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "lol"
+ R_ANGLE ">"
+ COLON2 "::"
+ ERROR
+ L_ANGLE "<"
+ BIN_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "nope"
+ SHR ">>"
+ ERROR
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "g"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Item"
+ GENERIC_ARG_LIST
+ COLON2 "::"
+ L_ANGLE "<"
+ TYPE_ARG
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "lol"
+ R_ANGLE ">"
+ COLON2 "::"
+ ERROR
+ L_ANGLE "<"
+ EXPR_STMT
+ BIN_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "nope"
+ R_ANGLE ">"
+ WHITESPACE " "
+ ERROR
+ EQ "="
+ WHITESPACE " "
+ EXPR_STMT
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
+error 30: expected identifier
+error 31: expected COMMA
+error 31: expected R_ANGLE
+error 31: expected SEMICOLON
+error 37: expected expression
+error 75: expected identifier
+error 76: expected SEMICOLON
+error 82: expected expression
+error 83: expected SEMICOLON
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0048_double_fish.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0048_double_fish.rs
new file mode 100644
index 000000000..31c12bfff
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0048_double_fish.rs
@@ -0,0 +1,7 @@
+fn f() {
+ S::<Item::<lol>::<nope>>;
+}
+
+fn g() {
+ let _: Item::<lol>::<nope> = ();
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0001_array_type_missing_semi.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0001_array_type_missing_semi.rast
new file mode 100644
index 000000000..ed739a7e3
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0001_array_type_missing_semi.rast
@@ -0,0 +1,27 @@
+SOURCE_FILE
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "T"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ SLICE_TYPE
+ L_BRACK "["
+ TUPLE_TYPE
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ ERROR
+ INT_NUMBER "92"
+ ERROR
+ R_BRACK "]"
+ ERROR
+ SEMICOLON ";"
+ WHITESPACE "\n"
+error 12: expected `;` or `]`
+error 12: expected SEMICOLON
+error 13: expected an item
+error 15: expected an item
+error 16: expected an item
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0001_array_type_missing_semi.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0001_array_type_missing_semi.rs
new file mode 100644
index 000000000..a94851443
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0001_array_type_missing_semi.rs
@@ -0,0 +1 @@
+type T = [() 92];
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0002_misplaced_label_err.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0002_misplaced_label_err.rast
new file mode 100644
index 000000000..56cea4b15
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0002_misplaced_label_err.rast
@@ -0,0 +1,28 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ ERROR
+ LABEL
+ LIFETIME
+ LIFETIME_IDENT "'loop"
+ COLON ":"
+ WHITESPACE " "
+ IMPL
+ IMPL_KW "impl"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
+error 22: expected a loop
+error 27: expected type
+error 27: expected `{`
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0002_misplaced_label_err.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0002_misplaced_label_err.rs
new file mode 100644
index 000000000..a2164c510
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0002_misplaced_label_err.rs
@@ -0,0 +1,3 @@
+fn main() {
+ 'loop: impl
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0003_pointer_type_no_mutability.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0003_pointer_type_no_mutability.rast
new file mode 100644
index 000000000..354c4135a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0003_pointer_type_no_mutability.rast
@@ -0,0 +1,17 @@
+SOURCE_FILE
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "T"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ PTR_TYPE
+ STAR "*"
+ TUPLE_TYPE
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+error 10: expected mut or const in raw pointer type (use `*mut T` or `*const T` as appropriate)
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0003_pointer_type_no_mutability.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0003_pointer_type_no_mutability.rs
new file mode 100644
index 000000000..fae705131
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0003_pointer_type_no_mutability.rs
@@ -0,0 +1 @@
+type T = *();
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0004_impl_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0004_impl_type.rast
new file mode 100644
index 000000000..dbeb878a2
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0004_impl_type.rast
@@ -0,0 +1,79 @@
+SOURCE_FILE
+ IMPL
+ IMPL_KW "impl"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Type"
+ WHITESPACE " "
+ ASSOC_ITEM_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ IMPL
+ IMPL_KW "impl"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Trait1"
+ WHITESPACE " "
+ FOR_KW "for"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "T"
+ WHITESPACE " "
+ ASSOC_ITEM_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ IMPL
+ IMPL_KW "impl"
+ WHITESPACE " "
+ IMPL
+ IMPL_KW "impl"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "NotType"
+ WHITESPACE " "
+ ASSOC_ITEM_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ IMPL
+ IMPL_KW "impl"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Trait2"
+ WHITESPACE " "
+ FOR_KW "for"
+ WHITESPACE " "
+ IMPL
+ IMPL_KW "impl"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "NotType"
+ WHITESPACE " "
+ ASSOC_ITEM_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+error 38: expected trait or type
+error 38: expected `{`
+error 70: expected trait or type
+error 70: expected `{`
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0004_impl_type.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0004_impl_type.rs
new file mode 100644
index 000000000..b8c7b65e3
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0004_impl_type.rs
@@ -0,0 +1,4 @@
+impl Type {}
+impl Trait1 for T {}
+impl impl NotType {}
+impl Trait2 for impl NotType {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0005_fn_pointer_type_missing_fn.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0005_fn_pointer_type_missing_fn.rast
new file mode 100644
index 000000000..eb0595293
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0005_fn_pointer_type_missing_fn.rast
@@ -0,0 +1,23 @@
+SOURCE_FILE
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "F"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ UNSAFE_KW "unsafe"
+ WHITESPACE " "
+ ERROR
+ L_PAREN "("
+ ERROR
+ R_PAREN ")"
+ ERROR
+ SEMICOLON ";"
+ WHITESPACE "\n"
+error 15: expected `fn`
+error 15: expected SEMICOLON
+error 16: expected an item
+error 17: expected an item
+error 18: expected an item
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0005_fn_pointer_type_missing_fn.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0005_fn_pointer_type_missing_fn.rs
new file mode 100644
index 000000000..f014914ff
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0005_fn_pointer_type_missing_fn.rs
@@ -0,0 +1 @@
+type F = unsafe ();
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0006_unsafe_block_in_mod.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0006_unsafe_block_in_mod.rast
new file mode 100644
index 000000000..77c2b56ad
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0006_unsafe_block_in_mod.rast
@@ -0,0 +1,37 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE " "
+ ERROR
+ UNSAFE_KW "unsafe"
+ WHITESPACE " "
+ ERROR
+ L_CURLY "{"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE " "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "bar"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+error 11: expected an item
+error 18: expected an item
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0006_unsafe_block_in_mod.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0006_unsafe_block_in_mod.rs
new file mode 100644
index 000000000..26141e904
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0006_unsafe_block_in_mod.rs
@@ -0,0 +1 @@
+fn foo(){} unsafe { } fn bar(){}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0007_async_without_semicolon.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0007_async_without_semicolon.rast
new file mode 100644
index 000000000..bf20d5fa4
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0007_async_without_semicolon.rast
@@ -0,0 +1,32 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ BLOCK_EXPR
+ ASYNC_KW "async"
+ WHITESPACE " "
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
+error 27: expected SEMICOLON
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0007_async_without_semicolon.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0007_async_without_semicolon.rs
new file mode 100644
index 000000000..9a423248c
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0007_async_without_semicolon.rs
@@ -0,0 +1 @@
+fn foo() { let _ = async {} }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0008_pub_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0008_pub_expr.rast
new file mode 100644
index 000000000..0ae9f64e7
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0008_pub_expr.rast
@@ -0,0 +1,26 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ ERROR
+ VISIBILITY
+ PUB_KW "pub"
+ WHITESPACE " "
+ EXPR_STMT
+ LITERAL
+ INT_NUMBER "92"
+ SEMICOLON ";"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
+error 14: expected an item
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0008_pub_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0008_pub_expr.rs
new file mode 100644
index 000000000..2976f6862
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0008_pub_expr.rs
@@ -0,0 +1 @@
+fn foo() { pub 92; }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0013_anonymous_static.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0013_anonymous_static.rast
new file mode 100644
index 000000000..823db94f5
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0013_anonymous_static.rast
@@ -0,0 +1,21 @@
+SOURCE_FILE
+ STATIC
+ STATIC_KW "static"
+ WHITESPACE " "
+ ERROR
+ UNDERSCORE "_"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "5"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+error 7: expected a name
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0013_anonymous_static.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0013_anonymous_static.rs
new file mode 100644
index 000000000..df8cecb43
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0013_anonymous_static.rs
@@ -0,0 +1 @@
+static _: i32 = 5;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0014_record_literal_before_ellipsis_recovery.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0014_record_literal_before_ellipsis_recovery.rast
new file mode 100644
index 000000000..f51196004
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0014_record_literal_before_ellipsis_recovery.rast
@@ -0,0 +1,49 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ RECORD_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_EXPR_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ RECORD_EXPR_FIELD
+ NAME_REF
+ IDENT "field"
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2 ".."
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "default"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
+error 25: expected COLON
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0014_record_literal_before_ellipsis_recovery.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0014_record_literal_before_ellipsis_recovery.rs
new file mode 100644
index 000000000..a4e5b2f69
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0014_record_literal_before_ellipsis_recovery.rs
@@ -0,0 +1,3 @@
+fn main() {
+ S { field ..S::default() }
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0014_struct_field_recover.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0014_struct_field_recover.rast
new file mode 100644
index 000000000..458d7f4e2
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0014_struct_field_recover.rast
@@ -0,0 +1,31 @@
+SOURCE_FILE
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ RECORD_FIELD
+ NAME
+ IDENT "f"
+ WHITESPACE " "
+ RECORD_FIELD
+ VISIBILITY
+ PUB_KW "pub"
+ WHITESPACE " "
+ NAME
+ IDENT "g"
+ COLON ":"
+ WHITESPACE " "
+ TUPLE_TYPE
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
+error 12: expected COLON
+error 12: expected type
+error 12: expected COMMA
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0014_struct_field_recover.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0014_struct_field_recover.rs
new file mode 100644
index 000000000..da32227ad
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0014_struct_field_recover.rs
@@ -0,0 +1 @@
+struct S { f pub g: () }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0015_empty_segment.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0015_empty_segment.rast
new file mode 100644
index 000000000..b03f5ad9f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0015_empty_segment.rast
@@ -0,0 +1,14 @@
+SOURCE_FILE
+ USE
+ USE_KW "use"
+ WHITESPACE " "
+ USE_TREE
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ CRATE_KW "crate"
+ COLON2 "::"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+error 11: expected identifier
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0015_empty_segment.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0015_empty_segment.rs
new file mode 100644
index 000000000..7510664e1
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0015_empty_segment.rs
@@ -0,0 +1 @@
+use crate::;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0015_missing_fn_param_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0015_missing_fn_param_type.rast
new file mode 100644
index 000000000..e72df374d
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0015_missing_fn_param_type.rast
@@ -0,0 +1,53 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "f"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "x"
+ WHITESPACE " "
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "y"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ COMMA ","
+ WHITESPACE " "
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "z"
+ COMMA ","
+ WHITESPACE " "
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "t"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+error 6: missing type for function parameter
+error 6: expected COMMA
+error 16: missing type for function parameter
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0015_missing_fn_param_type.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0015_missing_fn_param_type.rs
new file mode 100644
index 000000000..4a95b9084
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0015_missing_fn_param_type.rs
@@ -0,0 +1 @@
+fn f(x y: i32, z, t: i32) {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0002_use_tree_list.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0002_use_tree_list.rast
new file mode 100644
index 000000000..f3b1129f2
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0002_use_tree_list.rast
@@ -0,0 +1,29 @@
+SOURCE_FILE
+ USE
+ USE_KW "use"
+ WHITESPACE " "
+ USE_TREE
+ USE_TREE_LIST
+ L_CURLY "{"
+ USE_TREE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "a"
+ COMMA ","
+ WHITESPACE " "
+ USE_TREE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "b"
+ COMMA ","
+ WHITESPACE " "
+ USE_TREE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "c"
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0002_use_tree_list.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0002_use_tree_list.rs
new file mode 100644
index 000000000..6fa175f54
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0002_use_tree_list.rs
@@ -0,0 +1 @@
+use {a, b, c};
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0003_where_pred_for.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0003_where_pred_for.rast
new file mode 100644
index 000000000..8407e99f6
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0003_where_pred_for.rast
@@ -0,0 +1,63 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "for_trait"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "F"
+ R_ANGLE ">"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE "\n"
+ WHERE_CLAUSE
+ WHERE_KW "where"
+ WHITESPACE "\n "
+ WHERE_PRED
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "F"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Fn"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ REF_TYPE
+ AMP "&"
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "str"
+ R_PAREN ")"
+ WHITESPACE "\n"
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0003_where_pred_for.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0003_where_pred_for.rs
new file mode 100644
index 000000000..423bc105b
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0003_where_pred_for.rs
@@ -0,0 +1,4 @@
+fn for_trait<F>()
+where
+ for<'a> F: Fn(&'a str)
+{ }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0004_value_parameters_no_patterns.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0004_value_parameters_no_patterns.rast
new file mode 100644
index 000000000..902b06484
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0004_value_parameters_no_patterns.rast
@@ -0,0 +1,60 @@
+SOURCE_FILE
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "F"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Box"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ TYPE_ARG
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Fn"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ COMMA ","
+ WHITESPACE " "
+ PARAM
+ REF_TYPE
+ AMP "&"
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ COMMA ","
+ WHITESPACE " "
+ PARAM
+ REF_TYPE
+ AMP "&"
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ COMMA ","
+ WHITESPACE " "
+ PARAM
+ TUPLE_TYPE
+ L_PAREN "("
+ R_PAREN ")"
+ R_PAREN ")"
+ R_ANGLE ">"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0004_value_parameters_no_patterns.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0004_value_parameters_no_patterns.rs
new file mode 100644
index 000000000..93636e926
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0004_value_parameters_no_patterns.rs
@@ -0,0 +1 @@
+type F = Box<Fn(i32, &i32, &i32, ())>;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0005_function_type_params.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0005_function_type_params.rast
new file mode 100644
index 000000000..3858e3eed
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0005_function_type_params.rast
@@ -0,0 +1,38 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "T"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Clone"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Copy"
+ R_ANGLE ">"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0005_function_type_params.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0005_function_type_params.rs
new file mode 100644
index 000000000..9df40ed39
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0005_function_type_params.rs
@@ -0,0 +1 @@
+fn foo<T: Clone + Copy>(){}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0006_self_param.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0006_self_param.rast
new file mode 100644
index 000000000..67e282363
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0006_self_param.rast
@@ -0,0 +1,128 @@
+SOURCE_FILE
+ IMPL
+ IMPL_KW "impl"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ WHITESPACE " "
+ ASSOC_ITEM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "a"
+ PARAM_LIST
+ L_PAREN "("
+ SELF_PARAM
+ NAME
+ SELF_KW "self"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "b"
+ PARAM_LIST
+ L_PAREN "("
+ SELF_PARAM
+ AMP "&"
+ NAME
+ SELF_KW "self"
+ COMMA ","
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "c"
+ PARAM_LIST
+ L_PAREN "("
+ SELF_PARAM
+ AMP "&"
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ WHITESPACE " "
+ NAME
+ SELF_KW "self"
+ COMMA ","
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "d"
+ PARAM_LIST
+ L_PAREN "("
+ SELF_PARAM
+ AMP "&"
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ WHITESPACE " "
+ MUT_KW "mut"
+ WHITESPACE " "
+ NAME
+ SELF_KW "self"
+ COMMA ","
+ WHITESPACE " "
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "x"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "e"
+ PARAM_LIST
+ L_PAREN "("
+ SELF_PARAM
+ MUT_KW "mut"
+ WHITESPACE " "
+ NAME
+ SELF_KW "self"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0006_self_param.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0006_self_param.rs
new file mode 100644
index 000000000..80c0a43f5
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0006_self_param.rs
@@ -0,0 +1,7 @@
+impl S {
+ fn a(self) {}
+ fn b(&self,) {}
+ fn c(&'a self,) {}
+ fn d(&'a mut self, x: i32) {}
+ fn e(mut self) {}
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0007_type_param_bounds.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0007_type_param_bounds.rast
new file mode 100644
index 000000000..dee860c24
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0007_type_param_bounds.rast
@@ -0,0 +1,53 @@
+SOURCE_FILE
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "T"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ TYPE_BOUND
+ QUESTION "?"
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Sized"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ TYPE_BOUND
+ L_PAREN "("
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Copy"
+ R_PAREN ")"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ TYPE_BOUND
+ TILDE "~"
+ CONST_KW "const"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Drop"
+ R_ANGLE ">"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0007_type_param_bounds.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0007_type_param_bounds.rs
new file mode 100644
index 000000000..5da3083b9
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0007_type_param_bounds.rs
@@ -0,0 +1 @@
+struct S<T: 'a + ?Sized + (Copy) + ~const Drop>;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0008_path_part.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0008_path_part.rast
new file mode 100644
index 000000000..4ccda19a8
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0008_path_part.rast
@@ -0,0 +1,98 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ PATH_PAT
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "foo"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Bar"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ PATH_PAT
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "Bar"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ RECORD_PAT
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Bar"
+ WHITESPACE " "
+ RECORD_PAT_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ REST_PAT
+ DOT2 ".."
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ TUPLE_STRUCT_PAT
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Bar"
+ L_PAREN "("
+ REST_PAT
+ DOT2 ".."
+ R_PAREN ")"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0008_path_part.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0008_path_part.rs
new file mode 100644
index 000000000..f6e32c7c1
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0008_path_part.rs
@@ -0,0 +1,6 @@
+fn foo() {
+ let foo::Bar = ();
+ let ::Bar = ();
+ let Bar { .. } = ();
+ let Bar(..) = ();
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0009_loop_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0009_loop_expr.rast
new file mode 100644
index 000000000..ab3b49b0d
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0009_loop_expr.rast
@@ -0,0 +1,26 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ LOOP_EXPR
+ LOOP_KW "loop"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0009_loop_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0009_loop_expr.rs
new file mode 100644
index 000000000..9f078fa48
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0009_loop_expr.rs
@@ -0,0 +1,3 @@
+fn foo() {
+ loop {};
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0010_extern_block.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0010_extern_block.rast
new file mode 100644
index 000000000..7a3cd6a0d
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0010_extern_block.rast
@@ -0,0 +1,21 @@
+SOURCE_FILE
+ EXTERN_BLOCK
+ UNSAFE_KW "unsafe"
+ WHITESPACE " "
+ ABI
+ EXTERN_KW "extern"
+ WHITESPACE " "
+ STRING "\"C\""
+ WHITESPACE " "
+ EXTERN_ITEM_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ EXTERN_BLOCK
+ ABI
+ EXTERN_KW "extern"
+ WHITESPACE " "
+ EXTERN_ITEM_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0010_extern_block.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0010_extern_block.rs
new file mode 100644
index 000000000..bee5ac845
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0010_extern_block.rs
@@ -0,0 +1,2 @@
+unsafe extern "C" {}
+extern {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0011_field_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0011_field_expr.rast
new file mode 100644
index 000000000..8498724b9
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0011_field_expr.rast
@@ -0,0 +1,60 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ FIELD_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "x"
+ DOT "."
+ NAME_REF
+ IDENT "foo"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ FIELD_EXPR
+ FIELD_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "x"
+ DOT "."
+ NAME_REF
+ INT_NUMBER "0"
+ DOT "."
+ NAME_REF
+ IDENT "bar"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CALL_EXPR
+ FIELD_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "x"
+ DOT "."
+ NAME_REF
+ INT_NUMBER "0"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0011_field_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0011_field_expr.rs
new file mode 100644
index 000000000..b8da2ddc3
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0011_field_expr.rs
@@ -0,0 +1,5 @@
+fn foo() {
+ x.foo;
+ x.0.bar;
+ x.0();
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0012_type_item_where_clause.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0012_type_item_where_clause.rast
new file mode 100644
index 000000000..31c87d1b3
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0012_type_item_where_clause.rast
@@ -0,0 +1,33 @@
+SOURCE_FILE
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "Foo"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_TYPE
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ WHERE_CLAUSE
+ WHERE_KW "where"
+ WHITESPACE " "
+ WHERE_PRED
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Foo"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Copy"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0012_type_item_where_clause.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0012_type_item_where_clause.rs
new file mode 100644
index 000000000..2d30e8521
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0012_type_item_where_clause.rs
@@ -0,0 +1 @@
+type Foo = () where Foo: Copy;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0013_pointer_type_mut.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0013_pointer_type_mut.rast
new file mode 100644
index 000000000..bfe7ed5b4
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0013_pointer_type_mut.rast
@@ -0,0 +1,35 @@
+SOURCE_FILE
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "M"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ PTR_TYPE
+ STAR "*"
+ MUT_KW "mut"
+ WHITESPACE " "
+ TUPLE_TYPE
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "C"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ PTR_TYPE
+ STAR "*"
+ MUT_KW "mut"
+ WHITESPACE " "
+ TUPLE_TYPE
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0013_pointer_type_mut.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0013_pointer_type_mut.rs
new file mode 100644
index 000000000..04b2bb9ba
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0013_pointer_type_mut.rs
@@ -0,0 +1,2 @@
+type M = *mut ();
+type C = *mut ();
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0014_never_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0014_never_type.rast
new file mode 100644
index 000000000..53dbf3999
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0014_never_type.rast
@@ -0,0 +1,13 @@
+SOURCE_FILE
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "Never"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ NEVER_TYPE
+ BANG "!"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0014_never_type.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0014_never_type.rs
new file mode 100644
index 000000000..de399fcf4
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0014_never_type.rs
@@ -0,0 +1 @@
+type Never = !;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0015_continue_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0015_continue_expr.rast
new file mode 100644
index 000000000..5d80a57a2
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0015_continue_expr.rast
@@ -0,0 +1,38 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ LOOP_EXPR
+ LOOP_KW "loop"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CONTINUE_EXPR
+ CONTINUE_KW "continue"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CONTINUE_EXPR
+ CONTINUE_KW "continue"
+ WHITESPACE " "
+ LIFETIME
+ LIFETIME_IDENT "'l"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0015_continue_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0015_continue_expr.rs
new file mode 100644
index 000000000..474cc3f0e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0015_continue_expr.rs
@@ -0,0 +1,6 @@
+fn foo() {
+ loop {
+ continue;
+ continue 'l;
+ }
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0017_array_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0017_array_type.rast
new file mode 100644
index 000000000..2a5c644d4
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0017_array_type.rast
@@ -0,0 +1,21 @@
+SOURCE_FILE
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "T"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ ARRAY_TYPE
+ L_BRACK "["
+ TUPLE_TYPE
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "92"
+ R_BRACK "]"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0017_array_type.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0017_array_type.rs
new file mode 100644
index 000000000..27eb22f22
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0017_array_type.rs
@@ -0,0 +1 @@
+type T = [(); 92];
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0018_arb_self_types.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0018_arb_self_types.rast
new file mode 100644
index 000000000..a0b562629
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0018_arb_self_types.rast
@@ -0,0 +1,76 @@
+SOURCE_FILE
+ IMPL
+ IMPL_KW "impl"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ WHITESPACE " "
+ ASSOC_ITEM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "a"
+ PARAM_LIST
+ L_PAREN "("
+ SELF_PARAM
+ NAME
+ SELF_KW "self"
+ COLON ":"
+ WHITESPACE " "
+ REF_TYPE
+ AMP "&"
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ SELF_TYPE_KW "Self"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "b"
+ PARAM_LIST
+ L_PAREN "("
+ SELF_PARAM
+ MUT_KW "mut"
+ WHITESPACE " "
+ NAME
+ SELF_KW "self"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Box"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ TYPE_ARG
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ SELF_TYPE_KW "Self"
+ R_ANGLE ">"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0018_arb_self_types.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0018_arb_self_types.rs
new file mode 100644
index 000000000..6a170d5ac
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0018_arb_self_types.rs
@@ -0,0 +1,4 @@
+impl S {
+ fn a(self: &Self) {}
+ fn b(mut self: Box<Self>) {}
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0019_unary_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0019_unary_expr.rast
new file mode 100644
index 000000000..525b26745
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0019_unary_expr.rast
@@ -0,0 +1,45 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ PREFIX_EXPR
+ STAR "*"
+ PREFIX_EXPR
+ STAR "*"
+ REF_EXPR
+ AMP "&"
+ LITERAL
+ INT_NUMBER "1"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ PREFIX_EXPR
+ BANG "!"
+ PREFIX_EXPR
+ BANG "!"
+ LITERAL
+ TRUE_KW "true"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ PREFIX_EXPR
+ MINUS "-"
+ PREFIX_EXPR
+ MINUS "-"
+ LITERAL
+ INT_NUMBER "1"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0019_unary_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0019_unary_expr.rs
new file mode 100644
index 000000000..f1c3f7118
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0019_unary_expr.rs
@@ -0,0 +1,5 @@
+fn foo() {
+ **&1;
+ !!true;
+ --1;
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0021_assoc_item_list.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0021_assoc_item_list.rast
new file mode 100644
index 000000000..def7373c9
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0021_assoc_item_list.rast
@@ -0,0 +1,81 @@
+SOURCE_FILE
+ IMPL
+ IMPL_KW "impl"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "F"
+ WHITESPACE " "
+ ASSOC_ITEM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "A"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ CONST
+ CONST_KW "const"
+ WHITESPACE " "
+ NAME
+ IDENT "B"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "92"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "bar"
+ PARAM_LIST
+ L_PAREN "("
+ SELF_PARAM
+ AMP "&"
+ NAME
+ SELF_KW "self"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0021_assoc_item_list.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0021_assoc_item_list.rs
new file mode 100644
index 000000000..f10851487
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0021_assoc_item_list.rs
@@ -0,0 +1,6 @@
+impl F {
+ type A = i32;
+ const B: i32 = 92;
+ fn foo() {}
+ fn bar(&self) {}
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0022_crate_visibility.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0022_crate_visibility.rast
new file mode 100644
index 000000000..8738292a9
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0022_crate_visibility.rast
@@ -0,0 +1,49 @@
+SOURCE_FILE
+ STRUCT
+ VISIBILITY
+ PUB_KW "pub"
+ L_PAREN "("
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ CRATE_KW "crate"
+ R_PAREN ")"
+ WHITESPACE " "
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ STRUCT
+ VISIBILITY
+ PUB_KW "pub"
+ L_PAREN "("
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ SELF_KW "self"
+ R_PAREN ")"
+ WHITESPACE " "
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ STRUCT
+ VISIBILITY
+ PUB_KW "pub"
+ L_PAREN "("
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ SUPER_KW "super"
+ R_PAREN ")"
+ WHITESPACE " "
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0022_crate_visibility.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0022_crate_visibility.rs
new file mode 100644
index 000000000..a790a485f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0022_crate_visibility.rs
@@ -0,0 +1,3 @@
+pub(crate) struct S;
+pub(self) struct S;
+pub(super) struct S;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0023_placeholder_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0023_placeholder_type.rast
new file mode 100644
index 000000000..d9db1c34b
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0023_placeholder_type.rast
@@ -0,0 +1,13 @@
+SOURCE_FILE
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "Placeholder"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ INFER_TYPE
+ UNDERSCORE "_"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0023_placeholder_type.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0023_placeholder_type.rs
new file mode 100644
index 000000000..7952dbd57
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0023_placeholder_type.rs
@@ -0,0 +1 @@
+type Placeholder = _;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0024_slice_pat.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0024_slice_pat.rast
new file mode 100644
index 000000000..235a9d7f4
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0024_slice_pat.rast
@@ -0,0 +1,42 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ SLICE_PAT
+ L_BRACK "["
+ IDENT_PAT
+ NAME
+ IDENT "a"
+ COMMA ","
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "b"
+ COMMA ","
+ WHITESPACE " "
+ REST_PAT
+ DOT2 ".."
+ R_BRACK "]"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ ARRAY_EXPR
+ L_BRACK "["
+ R_BRACK "]"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0024_slice_pat.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0024_slice_pat.rs
new file mode 100644
index 000000000..7955973b9
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0024_slice_pat.rs
@@ -0,0 +1,3 @@
+fn main() {
+ let [a, b, ..] = [];
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0025_slice_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0025_slice_type.rast
new file mode 100644
index 000000000..0bcb31524
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0025_slice_type.rast
@@ -0,0 +1,17 @@
+SOURCE_FILE
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "T"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ SLICE_TYPE
+ L_BRACK "["
+ TUPLE_TYPE
+ L_PAREN "("
+ R_PAREN ")"
+ R_BRACK "]"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0025_slice_type.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0025_slice_type.rs
new file mode 100644
index 000000000..4da1af827
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0025_slice_type.rs
@@ -0,0 +1 @@
+type T = [()];
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0026_tuple_pat_fields.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0026_tuple_pat_fields.rast
new file mode 100644
index 000000000..3cdaf32b5
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0026_tuple_pat_fields.rast
@@ -0,0 +1,105 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ TUPLE_STRUCT_PAT
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ TUPLE_STRUCT_PAT
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ L_PAREN "("
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ R_PAREN ")"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ TUPLE_STRUCT_PAT
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ L_PAREN "("
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ COMMA ","
+ R_PAREN ")"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ TUPLE_STRUCT_PAT
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ L_PAREN "("
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ COMMA ","
+ WHITESPACE " "
+ REST_PAT
+ DOT2 ".."
+ WHITESPACE " "
+ COMMA ","
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "x"
+ R_PAREN ")"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0026_tuple_pat_fields.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0026_tuple_pat_fields.rs
new file mode 100644
index 000000000..0dfe63629
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0026_tuple_pat_fields.rs
@@ -0,0 +1,6 @@
+fn foo() {
+ let S() = ();
+ let S(_) = ();
+ let S(_,) = ();
+ let S(_, .. , x) = ();
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0027_ref_pat.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0027_ref_pat.rast
new file mode 100644
index 000000000..4516fd011
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0027_ref_pat.rast
@@ -0,0 +1,50 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ REF_PAT
+ AMP "&"
+ IDENT_PAT
+ NAME
+ IDENT "a"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ REF_PAT
+ AMP "&"
+ MUT_KW "mut"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "b"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0027_ref_pat.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0027_ref_pat.rs
new file mode 100644
index 000000000..de41f5cae
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0027_ref_pat.rs
@@ -0,0 +1,4 @@
+fn main() {
+ let &a = ();
+ let &mut b = ();
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0028_impl_trait_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0028_impl_trait_type.rast
new file mode 100644
index 000000000..c7478da94
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0028_impl_trait_type.rast
@@ -0,0 +1,45 @@
+SOURCE_FILE
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "A"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ IMPL_TRAIT_TYPE
+ IMPL_KW "impl"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Iterator"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ ASSOC_TYPE_ARG
+ NAME_REF
+ IDENT "Item"
+ EQ "="
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Foo"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ LIFETIME_ARG
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ R_ANGLE ">"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ TYPE_BOUND
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0028_impl_trait_type.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0028_impl_trait_type.rs
new file mode 100644
index 000000000..54c5a7c46
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0028_impl_trait_type.rs
@@ -0,0 +1 @@
+type A = impl Iterator<Item=Foo<'a>> + 'a;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0029_cast_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0029_cast_expr.rast
new file mode 100644
index 000000000..d53dde538
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0029_cast_expr.rast
@@ -0,0 +1,90 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CAST_EXPR
+ LITERAL
+ INT_NUMBER "82"
+ WHITESPACE " "
+ AS_KW "as"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BIN_EXPR
+ CAST_EXPR
+ LITERAL
+ INT_NUMBER "81"
+ WHITESPACE " "
+ AS_KW "as"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i8"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "1"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BIN_EXPR
+ CAST_EXPR
+ LITERAL
+ INT_NUMBER "79"
+ WHITESPACE " "
+ AS_KW "as"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i16"
+ WHITESPACE " "
+ MINUS "-"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "1"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BIN_EXPR
+ CAST_EXPR
+ LITERAL
+ INT_NUMBER "0x36"
+ WHITESPACE " "
+ AS_KW "as"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u8"
+ WHITESPACE " "
+ LTEQ "<="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "0x37"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0029_cast_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0029_cast_expr.rs
new file mode 100644
index 000000000..bfe8e4b36
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0029_cast_expr.rs
@@ -0,0 +1,6 @@
+fn foo() {
+ 82 as i32;
+ 81 as i8 + 1;
+ 79 as i16 - 1;
+ 0x36 as u8 <= 0x37;
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0030_let_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0030_let_expr.rast
new file mode 100644
index 000000000..dcffcb1ce
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0030_let_expr.rast
@@ -0,0 +1,90 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ IF_EXPR
+ IF_KW "if"
+ WHITESPACE " "
+ BIN_EXPR
+ LET_EXPR
+ LET_KW "let"
+ WHITESPACE " "
+ TUPLE_STRUCT_PAT
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Some"
+ L_PAREN "("
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ R_PAREN ")"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "None"
+ WHITESPACE " "
+ AMP2 "&&"
+ WHITESPACE " "
+ LITERAL
+ TRUE_KW "true"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n "
+ WHILE_EXPR
+ WHILE_KW "while"
+ WHITESPACE " "
+ BIN_EXPR
+ BIN_EXPR
+ LITERAL
+ INT_NUMBER "1"
+ WHITESPACE " "
+ EQ2 "=="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "5"
+ WHITESPACE " "
+ AMP2 "&&"
+ WHITESPACE " "
+ PAREN_EXPR
+ L_PAREN "("
+ LET_EXPR
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "None"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "None"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0030_let_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0030_let_expr.rs
new file mode 100644
index 000000000..0131d5e33
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0030_let_expr.rs
@@ -0,0 +1,4 @@
+fn foo() {
+ if let Some(_) = None && true {}
+ while 1 == 5 && (let None = None) {}
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0031_while_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0031_while_expr.rast
new file mode 100644
index 000000000..16c522414
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0031_while_expr.rast
@@ -0,0 +1,87 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ WHILE_EXPR
+ WHILE_KW "while"
+ WHITESPACE " "
+ LITERAL
+ TRUE_KW "true"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ WHILE_EXPR
+ WHILE_KW "while"
+ WHITESPACE " "
+ LET_EXPR
+ LET_KW "let"
+ WHITESPACE " "
+ TUPLE_STRUCT_PAT
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Some"
+ L_PAREN "("
+ IDENT_PAT
+ NAME
+ IDENT "x"
+ R_PAREN ")"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ METHOD_CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "it"
+ DOT "."
+ NAME_REF
+ IDENT "next"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ WHILE_EXPR
+ WHILE_KW "while"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ LITERAL
+ TRUE_KW "true"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0031_while_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0031_while_expr.rs
new file mode 100644
index 000000000..2f8188160
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0031_while_expr.rs
@@ -0,0 +1,5 @@
+fn foo() {
+ while true {};
+ while let Some(x) = it.next() {};
+ while { true } {};
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0032_fn_pointer_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0032_fn_pointer_type.rast
new file mode 100644
index 000000000..608b0be16
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0032_fn_pointer_type.rast
@@ -0,0 +1,98 @@
+SOURCE_FILE
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "A"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ FN_PTR_TYPE
+ FN_KW "fn"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "B"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ FN_PTR_TYPE
+ UNSAFE_KW "unsafe"
+ WHITESPACE " "
+ FN_KW "fn"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "C"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ FN_PTR_TYPE
+ UNSAFE_KW "unsafe"
+ WHITESPACE " "
+ ABI
+ EXTERN_KW "extern"
+ WHITESPACE " "
+ STRING "\"C\""
+ WHITESPACE " "
+ FN_KW "fn"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "D"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ FN_PTR_TYPE
+ ABI
+ EXTERN_KW "extern"
+ WHITESPACE " "
+ STRING "\"C\""
+ WHITESPACE " "
+ FN_KW "fn"
+ WHITESPACE " "
+ PARAM_LIST
+ L_PAREN "("
+ WHITESPACE " "
+ PARAM
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u8"
+ WHITESPACE " "
+ COMMA ","
+ WHITESPACE " "
+ PARAM
+ DOT3 "..."
+ WHITESPACE " "
+ R_PAREN ")"
+ WHITESPACE " "
+ RET_TYPE
+ THIN_ARROW "->"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u8"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0032_fn_pointer_type.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0032_fn_pointer_type.rs
new file mode 100644
index 000000000..9493da83d
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0032_fn_pointer_type.rs
@@ -0,0 +1,4 @@
+type A = fn();
+type B = unsafe fn();
+type C = unsafe extern "C" fn();
+type D = extern "C" fn ( u8 , ... ) -> u8;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0033_reference_type;.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0033_reference_type;.rast
new file mode 100644
index 000000000..b5c9d7a8d
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0033_reference_type;.rast
@@ -0,0 +1,51 @@
+SOURCE_FILE
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "A"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ REF_TYPE
+ AMP "&"
+ TUPLE_TYPE
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "B"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ REF_TYPE
+ AMP "&"
+ LIFETIME
+ LIFETIME_IDENT "'static"
+ WHITESPACE " "
+ TUPLE_TYPE
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "C"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ REF_TYPE
+ AMP "&"
+ MUT_KW "mut"
+ WHITESPACE " "
+ TUPLE_TYPE
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0033_reference_type;.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0033_reference_type;.rs
new file mode 100644
index 000000000..3ac0badab
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0033_reference_type;.rs
@@ -0,0 +1,3 @@
+type A = &();
+type B = &'static ();
+type C = &mut ();
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0034_break_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0034_break_expr.rast
new file mode 100644
index 000000000..06c053d0f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0034_break_expr.rast
@@ -0,0 +1,57 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ LOOP_EXPR
+ LOOP_KW "loop"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BREAK_EXPR
+ BREAK_KW "break"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BREAK_EXPR
+ BREAK_KW "break"
+ WHITESPACE " "
+ LIFETIME
+ LIFETIME_IDENT "'l"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BREAK_EXPR
+ BREAK_KW "break"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "92"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BREAK_EXPR
+ BREAK_KW "break"
+ WHITESPACE " "
+ LIFETIME
+ LIFETIME_IDENT "'l"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "92"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0034_break_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0034_break_expr.rs
new file mode 100644
index 000000000..1b4094636
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0034_break_expr.rs
@@ -0,0 +1,8 @@
+fn foo() {
+ loop {
+ break;
+ break 'l;
+ break 92;
+ break 'l 92;
+ }
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0037_qual_paths.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0037_qual_paths.rast
new file mode 100644
index 000000000..8c66cfe59
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0037_qual_paths.rast
@@ -0,0 +1,79 @@
+SOURCE_FILE
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "X"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH
+ PATH_SEGMENT
+ L_ANGLE "<"
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "A"
+ WHITESPACE " "
+ AS_KW "as"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "B"
+ R_ANGLE ">"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Output"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ EXPR_STMT
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH
+ PATH_SEGMENT
+ L_ANGLE "<"
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "usize"
+ WHITESPACE " "
+ AS_KW "as"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Default"
+ R_ANGLE ">"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "default"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0037_qual_paths.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0037_qual_paths.rs
new file mode 100644
index 000000000..d140692e2
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0037_qual_paths.rs
@@ -0,0 +1,2 @@
+type X = <A as B>::Output;
+fn foo() { <usize as Default>::default(); }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0038_full_range_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0038_full_range_expr.rast
new file mode 100644
index 000000000..9ffc07630
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0038_full_range_expr.rast
@@ -0,0 +1,29 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ EXPR_STMT
+ INDEX_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "xs"
+ L_BRACK "["
+ RANGE_EXPR
+ DOT2 ".."
+ R_BRACK "]"
+ SEMICOLON ";"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0038_full_range_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0038_full_range_expr.rs
new file mode 100644
index 000000000..ae21ad94c
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0038_full_range_expr.rs
@@ -0,0 +1 @@
+fn foo() { xs[..]; }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0040_crate_keyword_vis.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0040_crate_keyword_vis.rast
new file mode 100644
index 000000000..07b0210e4
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0040_crate_keyword_vis.rast
@@ -0,0 +1,63 @@
+SOURCE_FILE
+ FN
+ VISIBILITY
+ CRATE_KW "crate"
+ WHITESPACE " "
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ RECORD_FIELD
+ VISIBILITY
+ CRATE_KW "crate"
+ WHITESPACE " "
+ NAME
+ IDENT "field"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u32"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "T"
+ TUPLE_FIELD_LIST
+ L_PAREN "("
+ TUPLE_FIELD
+ VISIBILITY
+ CRATE_KW "crate"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u32"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0040_crate_keyword_vis.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0040_crate_keyword_vis.rs
new file mode 100644
index 000000000..e2b5f2161
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0040_crate_keyword_vis.rs
@@ -0,0 +1,3 @@
+crate fn main() { }
+struct S { crate field: u32 }
+struct T(crate u32);
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0041_trait_item.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0041_trait_item.rast
new file mode 100644
index 000000000..dd7f76eb9
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0041_trait_item.rast
@@ -0,0 +1,31 @@
+SOURCE_FILE
+ TRAIT
+ TRAIT_KW "trait"
+ WHITESPACE " "
+ NAME
+ IDENT "T"
+ WHITESPACE " "
+ ASSOC_ITEM_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "new"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ RET_TYPE
+ THIN_ARROW "->"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ SELF_TYPE_KW "Self"
+ SEMICOLON ";"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0041_trait_item.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0041_trait_item.rs
new file mode 100644
index 000000000..dcd9a7114
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0041_trait_item.rs
@@ -0,0 +1 @@
+trait T { fn new() -> Self; }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0042_call_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0042_call_expr.rast
new file mode 100644
index 000000000..19cc8d5ac
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0042_call_expr.rast
@@ -0,0 +1,148 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "f"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ CALL_EXPR
+ CALL_EXPR
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "f"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ ARG_LIST
+ L_PAREN "("
+ LITERAL
+ INT_NUMBER "1"
+ R_PAREN ")"
+ ARG_LIST
+ L_PAREN "("
+ LITERAL
+ INT_NUMBER "1"
+ COMMA ","
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "2"
+ COMMA ","
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "f"
+ ARG_LIST
+ L_PAREN "("
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH
+ PATH_SEGMENT
+ L_ANGLE "<"
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Foo"
+ R_ANGLE ">"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "func"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "f"
+ ARG_LIST
+ L_PAREN "("
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH
+ PATH_SEGMENT
+ L_ANGLE "<"
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Foo"
+ WHITESPACE " "
+ AS_KW "as"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Trait"
+ R_ANGLE ">"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "func"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0042_call_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0042_call_expr.rs
new file mode 100644
index 000000000..ffbf46d6d
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0042_call_expr.rs
@@ -0,0 +1,6 @@
+fn foo() {
+ let _ = f();
+ let _ = f()(1)(1, 2,);
+ let _ = f(<Foo>::func());
+ f(<Foo as Trait>::func());
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0044_block_items.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0044_block_items.rast
new file mode 100644
index 000000000..2e4b515ca
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0044_block_items.rast
@@ -0,0 +1,30 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "a"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "b"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0044_block_items.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0044_block_items.rs
new file mode 100644
index 000000000..d9868718c
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0044_block_items.rs
@@ -0,0 +1 @@
+fn a() { fn b() {} }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0045_param_list_opt_patterns.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0045_param_list_opt_patterns.rast
new file mode 100644
index 000000000..e9d93a0d0
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0045_param_list_opt_patterns.rast
@@ -0,0 +1,48 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "F"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "FnMut"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ REF_TYPE
+ AMP "&"
+ MUT_KW "mut"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Foo"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ LIFETIME_ARG
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ R_PAREN ")"
+ R_ANGLE ">"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0045_param_list_opt_patterns.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0045_param_list_opt_patterns.rs
new file mode 100644
index 000000000..9b93442c0
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0045_param_list_opt_patterns.rs
@@ -0,0 +1 @@
+fn foo<F: FnMut(&mut Foo<'a>)>(){}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0046_singleton_tuple_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0046_singleton_tuple_type.rast
new file mode 100644
index 000000000..0129955d1
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0046_singleton_tuple_type.rast
@@ -0,0 +1,20 @@
+SOURCE_FILE
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "T"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_TYPE
+ L_PAREN "("
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ COMMA ","
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0046_singleton_tuple_type.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0046_singleton_tuple_type.rs
new file mode 100644
index 000000000..cb66bad24
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0046_singleton_tuple_type.rs
@@ -0,0 +1 @@
+type T = (i32,);
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0048_path_type_with_bounds.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0048_path_type_with_bounds.rast
new file mode 100644
index 000000000..a059e124a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0048_path_type_with_bounds.rast
@@ -0,0 +1,85 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ RET_TYPE
+ THIN_ARROW "->"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Box"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ TYPE_ARG
+ DYN_TRAIT_TYPE
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "T"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ TYPE_BOUND
+ LIFETIME
+ LIFETIME_IDENT "'f"
+ R_ANGLE ">"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ RET_TYPE
+ THIN_ARROW "->"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Box"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ TYPE_ARG
+ DYN_TRAIT_TYPE
+ DYN_KW "dyn"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "T"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ TYPE_BOUND
+ LIFETIME
+ LIFETIME_IDENT "'f"
+ R_ANGLE ">"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0048_path_type_with_bounds.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0048_path_type_with_bounds.rs
new file mode 100644
index 000000000..4bb0f63b7
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0048_path_type_with_bounds.rs
@@ -0,0 +1,2 @@
+fn foo() -> Box<T + 'f> {}
+fn foo() -> Box<dyn T + 'f> {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0050_fn_decl.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0050_fn_decl.rast
new file mode 100644
index 000000000..f7fac807f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0050_fn_decl.rast
@@ -0,0 +1,22 @@
+SOURCE_FILE
+ TRAIT
+ TRAIT_KW "trait"
+ WHITESPACE " "
+ NAME
+ IDENT "T"
+ WHITESPACE " "
+ ASSOC_ITEM_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0050_fn_decl.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0050_fn_decl.rs
new file mode 100644
index 000000000..c9f74f7f5
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0050_fn_decl.rs
@@ -0,0 +1 @@
+trait T { fn foo(); }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0051_unit_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0051_unit_type.rast
new file mode 100644
index 000000000..b3df31535
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0051_unit_type.rast
@@ -0,0 +1,14 @@
+SOURCE_FILE
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "T"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_TYPE
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0051_unit_type.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0051_unit_type.rs
new file mode 100644
index 000000000..c039cf7d3
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0051_unit_type.rs
@@ -0,0 +1 @@
+type T = ();
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0052_path_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0052_path_type.rast
new file mode 100644
index 000000000..d498d3721
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0052_path_type.rast
@@ -0,0 +1,72 @@
+SOURCE_FILE
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "A"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Foo"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "B"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "Foo"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "C"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ SELF_KW "self"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Foo"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "D"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ SUPER_KW "super"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Foo"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0052_path_type.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0052_path_type.rs
new file mode 100644
index 000000000..bf94f32e1
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0052_path_type.rs
@@ -0,0 +1,4 @@
+type A = Foo;
+type B = ::Foo;
+type C = self::Foo;
+type D = super::Foo;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0053_path_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0053_path_expr.rast
new file mode 100644
index 000000000..48e123ab1
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0053_path_expr.rast
@@ -0,0 +1,97 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "a"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ PATH_EXPR
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "a"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "b"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "a"
+ GENERIC_ARG_LIST
+ COLON2 "::"
+ L_ANGLE "<"
+ TYPE_ARG
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "b"
+ R_ANGLE ">"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ MACRO_EXPR
+ MACRO_CALL
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "format"
+ BANG "!"
+ TOKEN_TREE
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0053_path_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0053_path_expr.rs
new file mode 100644
index 000000000..333ebabef
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0053_path_expr.rs
@@ -0,0 +1,6 @@
+fn foo() {
+ let _ = a;
+ let _ = a::b;
+ let _ = ::a::<b>;
+ let _ = format!();
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0054_record_field_attrs.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0054_record_field_attrs.rast
new file mode 100644
index 000000000..639ee0eb7
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0054_record_field_attrs.rast
@@ -0,0 +1,33 @@
+SOURCE_FILE
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ RECORD_FIELD
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "attr"
+ R_BRACK "]"
+ WHITESPACE " "
+ NAME
+ IDENT "f"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "f32"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0054_record_field_attrs.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0054_record_field_attrs.rs
new file mode 100644
index 000000000..d7f0b4382
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0054_record_field_attrs.rs
@@ -0,0 +1 @@
+struct S { #[attr] f: f32 }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0055_literal_pattern.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0055_literal_pattern.rast
new file mode 100644
index 000000000..c83ea7ade
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0055_literal_pattern.rast
@@ -0,0 +1,77 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ MATCH_EXPR
+ MATCH_KW "match"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ MATCH_ARM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ MATCH_ARM
+ LITERAL_PAT
+ MINUS "-"
+ LITERAL
+ INT_NUMBER "1"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n "
+ MATCH_ARM
+ LITERAL_PAT
+ LITERAL
+ INT_NUMBER "92"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n "
+ MATCH_ARM
+ LITERAL_PAT
+ LITERAL
+ CHAR "'c'"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n "
+ MATCH_ARM
+ LITERAL_PAT
+ LITERAL
+ STRING "\"hello\""
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0055_literal_pattern.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0055_literal_pattern.rs
new file mode 100644
index 000000000..6dfd67b4c
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0055_literal_pattern.rs
@@ -0,0 +1,8 @@
+fn main() {
+ match () {
+ -1 => (),
+ 92 => (),
+ 'c' => (),
+ "hello" => (),
+ }
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0056_where_clause.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0056_where_clause.rast
new file mode 100644
index 000000000..a3cbe457e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0056_where_clause.rast
@@ -0,0 +1,117 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE "\n"
+ WHERE_CLAUSE
+ WHERE_KW "where"
+ WHITESPACE "\n "
+ WHERE_PRED
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ LIFETIME
+ LIFETIME_IDENT "'b"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ TYPE_BOUND
+ LIFETIME
+ LIFETIME_IDENT "'c"
+ COMMA ","
+ WHITESPACE "\n "
+ WHERE_PRED
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "T"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Clone"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Copy"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ TYPE_BOUND
+ LIFETIME
+ LIFETIME_IDENT "'static"
+ COMMA ","
+ WHITESPACE "\n "
+ WHERE_PRED
+ PATH_TYPE
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Iterator"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Item"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ COMMA ","
+ WHITESPACE "\n "
+ WHERE_PRED
+ PATH_TYPE
+ PATH
+ PATH
+ PATH_SEGMENT
+ L_ANGLE "<"
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "T"
+ WHITESPACE " "
+ AS_KW "as"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Iterator"
+ R_ANGLE ">"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Item"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ WHITESPACE "\n"
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0056_where_clause.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0056_where_clause.rs
new file mode 100644
index 000000000..19d7e571b
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0056_where_clause.rs
@@ -0,0 +1,7 @@
+fn foo()
+where
+ 'a: 'b + 'c,
+ T: Clone + Copy + 'static,
+ Iterator::Item: 'a,
+ <T as Iterator>::Item: 'a
+{}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0058_range_pat.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0058_range_pat.rast
new file mode 100644
index 000000000..44c967e8d
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0058_range_pat.rast
@@ -0,0 +1,251 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ MATCH_EXPR
+ MATCH_KW "match"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "92"
+ WHITESPACE " "
+ MATCH_ARM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ MATCH_ARM
+ RANGE_PAT
+ LITERAL_PAT
+ LITERAL
+ INT_NUMBER "0"
+ WHITESPACE " "
+ DOT3 "..."
+ WHITESPACE " "
+ LITERAL_PAT
+ LITERAL
+ INT_NUMBER "100"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n "
+ MATCH_ARM
+ RANGE_PAT
+ LITERAL_PAT
+ LITERAL
+ INT_NUMBER "101"
+ WHITESPACE " "
+ DOT2EQ "..="
+ WHITESPACE " "
+ LITERAL_PAT
+ LITERAL
+ INT_NUMBER "200"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n "
+ MATCH_ARM
+ RANGE_PAT
+ LITERAL_PAT
+ LITERAL
+ INT_NUMBER "200"
+ WHITESPACE " "
+ DOT2 ".."
+ WHITESPACE " "
+ LITERAL_PAT
+ LITERAL
+ INT_NUMBER "301"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n "
+ MATCH_ARM
+ RANGE_PAT
+ LITERAL_PAT
+ LITERAL
+ INT_NUMBER "302"
+ WHITESPACE " "
+ DOT2 ".."
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n\n "
+ EXPR_STMT
+ MATCH_EXPR
+ MATCH_KW "match"
+ WHITESPACE " "
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Some"
+ ARG_LIST
+ L_PAREN "("
+ CAST_EXPR
+ LITERAL
+ INT_NUMBER "10"
+ WHITESPACE " "
+ AS_KW "as"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u8"
+ R_PAREN ")"
+ WHITESPACE " "
+ MATCH_ARM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ MATCH_ARM
+ OR_PAT
+ TUPLE_STRUCT_PAT
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Some"
+ L_PAREN "("
+ LITERAL_PAT
+ LITERAL
+ INT_NUMBER "0"
+ R_PAREN ")"
+ WHITESPACE " "
+ PIPE "|"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "None"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n "
+ MATCH_ARM
+ TUPLE_STRUCT_PAT
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Some"
+ L_PAREN "("
+ RANGE_PAT
+ LITERAL_PAT
+ LITERAL
+ INT_NUMBER "1"
+ DOT2 ".."
+ R_PAREN ")"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n\n "
+ MATCH_EXPR
+ MATCH_KW "match"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ CAST_EXPR
+ LITERAL
+ INT_NUMBER "10"
+ WHITESPACE " "
+ AS_KW "as"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u8"
+ COMMA ","
+ WHITESPACE " "
+ CAST_EXPR
+ LITERAL
+ INT_NUMBER "5"
+ WHITESPACE " "
+ AS_KW "as"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u8"
+ R_PAREN ")"
+ WHITESPACE " "
+ MATCH_ARM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ MATCH_ARM
+ TUPLE_PAT
+ L_PAREN "("
+ LITERAL_PAT
+ LITERAL
+ INT_NUMBER "0"
+ COMMA ","
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ R_PAREN ")"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n "
+ MATCH_ARM
+ TUPLE_PAT
+ L_PAREN "("
+ RANGE_PAT
+ LITERAL_PAT
+ LITERAL
+ INT_NUMBER "1"
+ DOT2 ".."
+ COMMA ","
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ R_PAREN ")"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0058_range_pat.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0058_range_pat.rs
new file mode 100644
index 000000000..6c586a895
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0058_range_pat.rs
@@ -0,0 +1,18 @@
+fn main() {
+ match 92 {
+ 0 ... 100 => (),
+ 101 ..= 200 => (),
+ 200 .. 301 => (),
+ 302 .. => (),
+ }
+
+ match Some(10 as u8) {
+ Some(0) | None => (),
+ Some(1..) => ()
+ }
+
+ match (10 as u8, 5 as u8) {
+ (0, _) => (),
+ (1.., _) => ()
+ }
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0059_match_arms_commas.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0059_match_arms_commas.rast
new file mode 100644
index 000000000..94897c2d2
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0059_match_arms_commas.rast
@@ -0,0 +1,60 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ MATCH_EXPR
+ MATCH_KW "match"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ MATCH_ARM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ MATCH_ARM
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n "
+ MATCH_ARM
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n "
+ MATCH_ARM
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0059_match_arms_commas.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0059_match_arms_commas.rs
new file mode 100644
index 000000000..1f25d577a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0059_match_arms_commas.rs
@@ -0,0 +1,7 @@
+fn foo() {
+ match () {
+ _ => (),
+ _ => {}
+ _ => ()
+ }
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0060_extern_crate.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0060_extern_crate.rast
new file mode 100644
index 000000000..0a660957d
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0060_extern_crate.rast
@@ -0,0 +1,10 @@
+SOURCE_FILE
+ EXTERN_CRATE
+ EXTERN_KW "extern"
+ WHITESPACE " "
+ CRATE_KW "crate"
+ WHITESPACE " "
+ NAME_REF
+ IDENT "foo"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0060_extern_crate.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0060_extern_crate.rs
new file mode 100644
index 000000000..49af74e1b
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0060_extern_crate.rs
@@ -0,0 +1 @@
+extern crate foo;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0061_record_lit.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0061_record_lit.rast
new file mode 100644
index 000000000..9997d0ae3
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0061_record_lit.rast
@@ -0,0 +1,125 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ RECORD_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_EXPR_FIELD_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ RECORD_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_EXPR_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ RECORD_EXPR_FIELD
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "x"
+ COMMA ","
+ WHITESPACE " "
+ RECORD_EXPR_FIELD
+ NAME_REF
+ IDENT "y"
+ COLON ":"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "32"
+ COMMA ","
+ WHITESPACE " "
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ RECORD_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_EXPR_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ RECORD_EXPR_FIELD
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "x"
+ COMMA ","
+ WHITESPACE " "
+ RECORD_EXPR_FIELD
+ NAME_REF
+ IDENT "y"
+ COLON ":"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "32"
+ COMMA ","
+ WHITESPACE " "
+ DOT2 ".."
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Default"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "default"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ RECORD_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "TupleStruct"
+ WHITESPACE " "
+ RECORD_EXPR_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ RECORD_EXPR_FIELD
+ NAME_REF
+ INT_NUMBER "0"
+ COLON ":"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "1"
+ WHITESPACE " "
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0061_record_lit.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0061_record_lit.rs
new file mode 100644
index 000000000..6285e5549
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0061_record_lit.rs
@@ -0,0 +1,6 @@
+fn foo() {
+ S {};
+ S { x, y: 32, };
+ S { x, y: 32, ..Default::default() };
+ TupleStruct { 0: 1 };
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0062_mod_contents.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0062_mod_contents.rast
new file mode 100644
index 000000000..5f60e03d4
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0062_mod_contents.rast
@@ -0,0 +1,65 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ MACRO_RULES
+ MACRO_RULES_KW "macro_rules"
+ BANG "!"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ WHITESPACE " "
+ TOKEN_TREE
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ MACRO_CALL
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "foo"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "bar"
+ BANG "!"
+ TOKEN_TREE
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ MACRO_CALL
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ SUPER_KW "super"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "baz"
+ BANG "!"
+ WHITESPACE " "
+ TOKEN_TREE
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0062_mod_contents.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0062_mod_contents.rs
new file mode 100644
index 000000000..24a15c5c5
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0062_mod_contents.rs
@@ -0,0 +1,5 @@
+fn foo() {}
+macro_rules! foo {}
+foo::bar!();
+super::baz! {}
+struct S;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0063_impl_item_neg.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0063_impl_item_neg.rast
new file mode 100644
index 000000000..805052fbc
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0063_impl_item_neg.rast
@@ -0,0 +1,23 @@
+SOURCE_FILE
+ IMPL
+ IMPL_KW "impl"
+ WHITESPACE " "
+ BANG "!"
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Send"
+ WHITESPACE " "
+ FOR_KW "for"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ WHITESPACE " "
+ ASSOC_ITEM_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0063_impl_item_neg.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0063_impl_item_neg.rs
new file mode 100644
index 000000000..a7bd4b048
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0063_impl_item_neg.rs
@@ -0,0 +1 @@
+impl !Send for S {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0064_if_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0064_if_expr.rast
new file mode 100644
index 000000000..e2e964e44
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0064_if_expr.rast
@@ -0,0 +1,126 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ IF_EXPR
+ IF_KW "if"
+ WHITESPACE " "
+ LITERAL
+ TRUE_KW "true"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ IF_EXPR
+ IF_KW "if"
+ WHITESPACE " "
+ LITERAL
+ TRUE_KW "true"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE " "
+ ELSE_KW "else"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ IF_EXPR
+ IF_KW "if"
+ WHITESPACE " "
+ LITERAL
+ TRUE_KW "true"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE " "
+ ELSE_KW "else"
+ WHITESPACE " "
+ IF_EXPR
+ IF_KW "if"
+ WHITESPACE " "
+ LITERAL
+ FALSE_KW "false"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE " "
+ ELSE_KW "else"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ IF_EXPR
+ IF_KW "if"
+ WHITESPACE " "
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ IF_EXPR
+ IF_KW "if"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ LITERAL
+ TRUE_KW "true"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE " "
+ ELSE_KW "else"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0064_if_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0064_if_expr.rs
new file mode 100644
index 000000000..40f227ba3
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0064_if_expr.rs
@@ -0,0 +1,7 @@
+fn foo() {
+ if true {};
+ if true {} else {};
+ if true {} else if false {} else {};
+ if S {};
+ if { true } { } else { };
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0065_dyn_trait_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0065_dyn_trait_type.rast
new file mode 100644
index 000000000..e37d43aac
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0065_dyn_trait_type.rast
@@ -0,0 +1,45 @@
+SOURCE_FILE
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "A"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ DYN_TRAIT_TYPE
+ DYN_KW "dyn"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Iterator"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ ASSOC_TYPE_ARG
+ NAME_REF
+ IDENT "Item"
+ EQ "="
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Foo"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ LIFETIME_ARG
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ R_ANGLE ">"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ TYPE_BOUND
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0065_dyn_trait_type.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0065_dyn_trait_type.rs
new file mode 100644
index 000000000..c3ecabb99
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0065_dyn_trait_type.rs
@@ -0,0 +1 @@
+type A = dyn Iterator<Item=Foo<'a>> + 'a;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0066_match_arm.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0066_match_arm.rast
new file mode 100644
index 000000000..8189cf0a8
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0066_match_arm.rast
@@ -0,0 +1,152 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ MATCH_EXPR
+ MATCH_KW "match"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ MATCH_ARM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ MATCH_ARM
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n "
+ MATCH_ARM
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ MATCH_GUARD
+ IF_KW "if"
+ WHITESPACE " "
+ BIN_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Test"
+ WHITESPACE " "
+ R_ANGLE ">"
+ WHITESPACE " "
+ RECORD_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Test"
+ RECORD_EXPR_FIELD_LIST
+ L_CURLY "{"
+ RECORD_EXPR_FIELD
+ NAME_REF
+ IDENT "field"
+ COLON ":"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "0"
+ R_CURLY "}"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n "
+ MATCH_ARM
+ OR_PAT
+ IDENT_PAT
+ NAME
+ IDENT "X"
+ WHITESPACE " "
+ PIPE "|"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "Y"
+ WHITESPACE " "
+ MATCH_GUARD
+ IF_KW "if"
+ WHITESPACE " "
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Z"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n "
+ MATCH_ARM
+ PIPE "|"
+ WHITESPACE " "
+ OR_PAT
+ IDENT_PAT
+ NAME
+ IDENT "X"
+ WHITESPACE " "
+ PIPE "|"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "Y"
+ WHITESPACE " "
+ MATCH_GUARD
+ IF_KW "if"
+ WHITESPACE " "
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Z"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n "
+ MATCH_ARM
+ PIPE "|"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "X"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n "
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0066_match_arm.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0066_match_arm.rs
new file mode 100644
index 000000000..9e009e24f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0066_match_arm.rs
@@ -0,0 +1,9 @@
+fn foo() {
+ match () {
+ _ => (),
+ _ if Test > Test{field: 0} => (),
+ X | Y if Z => (),
+ | X | Y if Z => (),
+ | X => (),
+ };
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0067_crate_path.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0067_crate_path.rast
new file mode 100644
index 000000000..f71367ae1
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0067_crate_path.rast
@@ -0,0 +1,16 @@
+SOURCE_FILE
+ USE
+ USE_KW "use"
+ WHITESPACE " "
+ USE_TREE
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ CRATE_KW "crate"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "foo"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0067_crate_path.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0067_crate_path.rs
new file mode 100644
index 000000000..1bbb5930b
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0067_crate_path.rs
@@ -0,0 +1 @@
+use crate::foo;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0070_stmt_bin_expr_ambiguity.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0070_stmt_bin_expr_ambiguity.rast
new file mode 100644
index 000000000..e387e14d1
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0070_stmt_bin_expr_ambiguity.rast
@@ -0,0 +1,53 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "f"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ BIN_EXPR
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ LITERAL
+ INT_NUMBER "1"
+ R_CURLY "}"
+ WHITESPACE " "
+ AMP "&"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "2"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ LITERAL
+ INT_NUMBER "1"
+ R_CURLY "}"
+ WHITESPACE " "
+ EXPR_STMT
+ REF_EXPR
+ AMP "&"
+ LITERAL
+ INT_NUMBER "2"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0070_stmt_bin_expr_ambiguity.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0070_stmt_bin_expr_ambiguity.rs
new file mode 100644
index 000000000..7e8bd87bf
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0070_stmt_bin_expr_ambiguity.rs
@@ -0,0 +1,4 @@
+fn f() {
+ let _ = {1} & 2;
+ {1} &2;
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0071_match_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0071_match_expr.rast
new file mode 100644
index 000000000..0d6cd390e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0071_match_expr.rast
@@ -0,0 +1,96 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ MATCH_EXPR
+ MATCH_KW "match"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ MATCH_ARM_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ MATCH_EXPR
+ MATCH_KW "match"
+ WHITESPACE " "
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ WHITESPACE " "
+ MATCH_ARM_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ MATCH_EXPR
+ MATCH_KW "match"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE " "
+ MATCH_ARM_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ MATCH_ARM
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ MATCH_EXPR
+ MATCH_KW "match"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ RECORD_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_EXPR_FIELD_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE " "
+ MATCH_ARM_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0071_match_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0071_match_expr.rs
new file mode 100644
index 000000000..c4021dc10
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0071_match_expr.rs
@@ -0,0 +1,6 @@
+fn foo() {
+ match () { };
+ match S {};
+ match { } { _ => () };
+ match { S {} } {};
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0072_return_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0072_return_expr.rast
new file mode 100644
index 000000000..62cff1220
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0072_return_expr.rast
@@ -0,0 +1,29 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ RETURN_EXPR
+ RETURN_KW "return"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ RETURN_EXPR
+ RETURN_KW "return"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "92"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0072_return_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0072_return_expr.rs
new file mode 100644
index 000000000..5733666b6
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0072_return_expr.rs
@@ -0,0 +1,4 @@
+fn foo() {
+ return;
+ return 92;
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0073_type_item_type_params.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0073_type_item_type_params.rast
new file mode 100644
index 000000000..60ac3b3c4
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0073_type_item_type_params.rast
@@ -0,0 +1,20 @@
+SOURCE_FILE
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "Result"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "T"
+ R_ANGLE ">"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_TYPE
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0073_type_item_type_params.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0073_type_item_type_params.rs
new file mode 100644
index 000000000..defd110c4
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0073_type_item_type_params.rs
@@ -0,0 +1 @@
+type Result<T> = ();
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0074_stmt_postfix_expr_ambiguity.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0074_stmt_postfix_expr_ambiguity.rast
new file mode 100644
index 000000000..950421feb
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0074_stmt_postfix_expr_ambiguity.rast
@@ -0,0 +1,63 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ MATCH_EXPR
+ MATCH_KW "match"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ MATCH_ARM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ MATCH_ARM
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n "
+ MATCH_ARM
+ TUPLE_PAT
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n "
+ MATCH_ARM
+ SLICE_PAT
+ L_BRACK "["
+ R_BRACK "]"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0074_stmt_postfix_expr_ambiguity.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0074_stmt_postfix_expr_ambiguity.rs
new file mode 100644
index 000000000..2edd578f9
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0074_stmt_postfix_expr_ambiguity.rs
@@ -0,0 +1,7 @@
+fn foo() {
+ match () {
+ _ => {}
+ () => {}
+ [] => {}
+ }
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0075_block.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0075_block.rast
new file mode 100644
index 000000000..a23364d15
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0075_block.rast
@@ -0,0 +1,90 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "a"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "b"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "1"
+ SEMICOLON ";"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "c"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ EXPR_STMT
+ LITERAL
+ INT_NUMBER "1"
+ SEMICOLON ";"
+ WHITESPACE " "
+ EXPR_STMT
+ LITERAL
+ INT_NUMBER "2"
+ SEMICOLON ";"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "d"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ EXPR_STMT
+ LITERAL
+ INT_NUMBER "1"
+ SEMICOLON ";"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "2"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0075_block.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0075_block.rs
new file mode 100644
index 000000000..81f44c533
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0075_block.rs
@@ -0,0 +1,4 @@
+fn a() {}
+fn b() { let _ = 1; }
+fn c() { 1; 2; }
+fn d() { 1; 2 }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0076_function_where_clause.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0076_function_where_clause.rast
new file mode 100644
index 000000000..a000d7e59
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0076_function_where_clause.rast
@@ -0,0 +1,40 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "T"
+ R_ANGLE ">"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ WHERE_CLAUSE
+ WHERE_KW "where"
+ WHITESPACE " "
+ WHERE_PRED
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "T"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Copy"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0076_function_where_clause.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0076_function_where_clause.rs
new file mode 100644
index 000000000..f0920b2a8
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0076_function_where_clause.rs
@@ -0,0 +1 @@
+fn foo<T>() where T: Copy {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0077_try_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0077_try_expr.rast
new file mode 100644
index 000000000..c3aa8c15d
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0077_try_expr.rast
@@ -0,0 +1,26 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ TRY_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "x"
+ QUESTION "?"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0077_try_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0077_try_expr.rs
new file mode 100644
index 000000000..8b74f7bc8
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0077_try_expr.rs
@@ -0,0 +1,3 @@
+fn foo() {
+ x?;
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0078_type_alias.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0078_type_alias.rast
new file mode 100644
index 000000000..c5da79974
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0078_type_alias.rast
@@ -0,0 +1,16 @@
+SOURCE_FILE
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "Foo"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Bar"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0078_type_alias.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0078_type_alias.rs
new file mode 100644
index 000000000..04c0344fa
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0078_type_alias.rs
@@ -0,0 +1 @@
+type Foo = Bar;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0079_impl_item.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0079_impl_item.rast
new file mode 100644
index 000000000..879676309
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0079_impl_item.rast
@@ -0,0 +1,14 @@
+SOURCE_FILE
+ IMPL
+ IMPL_KW "impl"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ WHITESPACE " "
+ ASSOC_ITEM_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0079_impl_item.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0079_impl_item.rs
new file mode 100644
index 000000000..647799d7c
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0079_impl_item.rs
@@ -0,0 +1 @@
+impl S {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0080_postfix_range.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0080_postfix_range.rast
new file mode 100644
index 000000000..3a59cf7b8
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0080_postfix_range.rast
@@ -0,0 +1,96 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "x"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ RANGE_EXPR
+ LITERAL
+ INT_NUMBER "1"
+ DOT2 ".."
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ MATCH_EXPR
+ MATCH_KW "match"
+ WHITESPACE " "
+ RANGE_EXPR
+ LITERAL
+ INT_NUMBER "1"
+ DOT2 ".."
+ WHITESPACE " "
+ MATCH_ARM_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ MATCH_ARM
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ MATCH_EXPR
+ MATCH_KW "match"
+ WHITESPACE " "
+ RANGE_EXPR
+ METHOD_CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "a"
+ DOT "."
+ NAME_REF
+ IDENT "b"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ DOT2 ".."
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ WHITESPACE " "
+ MATCH_ARM_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ MATCH_ARM
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0080_postfix_range.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0080_postfix_range.rs
new file mode 100644
index 000000000..e7b7cfc6b
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0080_postfix_range.rs
@@ -0,0 +1,5 @@
+fn foo() {
+ let x = 1..;
+ match 1.. { _ => () };
+ match a.b()..S { _ => () };
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0081_for_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0081_for_type.rast
new file mode 100644
index 000000000..7600457a9
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0081_for_type.rast
@@ -0,0 +1,117 @@
+SOURCE_FILE
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "A"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ FOR_TYPE
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ WHITESPACE " "
+ FN_PTR_TYPE
+ FN_KW "fn"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ RET_TYPE
+ THIN_ARROW "->"
+ WHITESPACE " "
+ TUPLE_TYPE
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "B"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ FOR_TYPE
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ WHITESPACE " "
+ FN_PTR_TYPE
+ UNSAFE_KW "unsafe"
+ WHITESPACE " "
+ ABI
+ EXTERN_KW "extern"
+ WHITESPACE " "
+ STRING "\"C\""
+ WHITESPACE " "
+ FN_KW "fn"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ REF_TYPE
+ AMP "&"
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ WHITESPACE " "
+ TUPLE_TYPE
+ L_PAREN "("
+ R_PAREN ")"
+ R_PAREN ")"
+ WHITESPACE " "
+ RET_TYPE
+ THIN_ARROW "->"
+ WHITESPACE " "
+ TUPLE_TYPE
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "Obj"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ FOR_TYPE
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "PartialEq"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ TYPE_ARG
+ REF_TYPE
+ AMP "&"
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ R_ANGLE ">"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0081_for_type.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0081_for_type.rs
new file mode 100644
index 000000000..8ac7b9e10
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0081_for_type.rs
@@ -0,0 +1,3 @@
+type A = for<'a> fn() -> ();
+type B = for<'a> unsafe extern "C" fn(&'a ()) -> ();
+type Obj = for<'a> PartialEq<&'a i32>;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0082_ref_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0082_ref_expr.rast
new file mode 100644
index 000000000..108b0802c
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0082_ref_expr.rast
@@ -0,0 +1,139 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ COMMENT "// reference operator"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ REF_EXPR
+ AMP "&"
+ LITERAL
+ INT_NUMBER "1"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ REF_EXPR
+ AMP "&"
+ MUT_KW "mut"
+ WHITESPACE " "
+ REF_EXPR
+ AMP "&"
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "f"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ REF_EXPR
+ AMP "&"
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "raw"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ REF_EXPR
+ AMP "&"
+ FIELD_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "raw"
+ DOT "."
+ NAME_REF
+ INT_NUMBER "0"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ COMMENT "// raw reference operator"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ REF_EXPR
+ AMP "&"
+ RAW_KW "raw"
+ WHITESPACE " "
+ MUT_KW "mut"
+ WHITESPACE " "
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "foo"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ REF_EXPR
+ AMP "&"
+ RAW_KW "raw"
+ WHITESPACE " "
+ CONST_KW "const"
+ WHITESPACE " "
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "foo"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0082_ref_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0082_ref_expr.rs
new file mode 100644
index 000000000..c5262f446
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0082_ref_expr.rs
@@ -0,0 +1,10 @@
+fn foo() {
+ // reference operator
+ let _ = &1;
+ let _ = &mut &f();
+ let _ = &raw;
+ let _ = &raw.0;
+ // raw reference operator
+ let _ = &raw mut foo;
+ let _ = &raw const foo;
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0083_struct_items.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0083_struct_items.rast
new file mode 100644
index 000000000..cdbc40fe0
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0083_struct_items.rast
@@ -0,0 +1,87 @@
+SOURCE_FILE@0..106
+ STRUCT@0..11
+ STRUCT_KW@0..6 "struct"
+ WHITESPACE@6..7 " "
+ NAME@7..10
+ IDENT@7..10 "Foo"
+ SEMICOLON@10..11 ";"
+ WHITESPACE@11..12 "\n"
+ STRUCT@12..25
+ STRUCT_KW@12..18 "struct"
+ WHITESPACE@18..19 " "
+ NAME@19..22
+ IDENT@19..22 "Foo"
+ WHITESPACE@22..23 " "
+ RECORD_FIELD_LIST@23..25
+ L_CURLY@23..24 "{"
+ R_CURLY@24..25 "}"
+ WHITESPACE@25..26 "\n"
+ STRUCT@26..39
+ STRUCT_KW@26..32 "struct"
+ WHITESPACE@32..33 " "
+ NAME@33..36
+ IDENT@33..36 "Foo"
+ TUPLE_FIELD_LIST@36..38
+ L_PAREN@36..37 "("
+ R_PAREN@37..38 ")"
+ SEMICOLON@38..39 ";"
+ WHITESPACE@39..40 "\n"
+ STRUCT@40..66
+ STRUCT_KW@40..46 "struct"
+ WHITESPACE@46..47 " "
+ NAME@47..50
+ IDENT@47..50 "Foo"
+ TUPLE_FIELD_LIST@50..65
+ L_PAREN@50..51 "("
+ TUPLE_FIELD@51..57
+ PATH_TYPE@51..57
+ PATH@51..57
+ PATH_SEGMENT@51..57
+ NAME_REF@51..57
+ IDENT@51..57 "String"
+ COMMA@57..58 ","
+ WHITESPACE@58..59 " "
+ TUPLE_FIELD@59..64
+ PATH_TYPE@59..64
+ PATH@59..64
+ PATH_SEGMENT@59..64
+ NAME_REF@59..64
+ IDENT@59..64 "usize"
+ R_PAREN@64..65 ")"
+ SEMICOLON@65..66 ";"
+ WHITESPACE@66..67 "\n"
+ STRUCT@67..105
+ STRUCT_KW@67..73 "struct"
+ WHITESPACE@73..74 " "
+ NAME@74..77
+ IDENT@74..77 "Foo"
+ WHITESPACE@77..78 " "
+ RECORD_FIELD_LIST@78..105
+ L_CURLY@78..79 "{"
+ WHITESPACE@79..84 "\n "
+ RECORD_FIELD@84..90
+ NAME@84..85
+ IDENT@84..85 "a"
+ COLON@85..86 ":"
+ WHITESPACE@86..87 " "
+ PATH_TYPE@87..90
+ PATH@87..90
+ PATH_SEGMENT@87..90
+ NAME_REF@87..90
+ IDENT@87..90 "i32"
+ COMMA@90..91 ","
+ WHITESPACE@91..96 "\n "
+ RECORD_FIELD@96..102
+ NAME@96..97
+ IDENT@96..97 "b"
+ COLON@97..98 ":"
+ WHITESPACE@98..99 " "
+ PATH_TYPE@99..102
+ PATH@99..102
+ PATH_SEGMENT@99..102
+ NAME_REF@99..102
+ IDENT@99..102 "f32"
+ COMMA@102..103 ","
+ WHITESPACE@103..104 "\n"
+ R_CURLY@104..105 "}"
+ WHITESPACE@105..106 "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0084_paren_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0084_paren_type.rast
new file mode 100644
index 000000000..29995bb75
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0084_paren_type.rast
@@ -0,0 +1,19 @@
+SOURCE_FILE
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "T"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ PAREN_TYPE
+ L_PAREN "("
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0084_paren_type.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0084_paren_type.rs
new file mode 100644
index 000000000..6e1b25101
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0084_paren_type.rs
@@ -0,0 +1 @@
+type T = (i32);
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0085_expr_literals.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0085_expr_literals.rast
new file mode 100644
index 000000000..403c265ea
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0085_expr_literals.rast
@@ -0,0 +1,136 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ TRUE_KW "true"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ FALSE_KW "false"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "1"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ FLOAT_NUMBER "2.0"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ BYTE "b'a'"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ CHAR "'b'"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ STRING "\"c\""
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ STRING "r\"d\""
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ BYTE_STRING "b\"e\""
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ BYTE_STRING "br\"f\""
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0085_expr_literals.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0085_expr_literals.rs
new file mode 100644
index 000000000..2e11a5a6e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0085_expr_literals.rs
@@ -0,0 +1,12 @@
+fn foo() {
+ let _ = true;
+ let _ = false;
+ let _ = 1;
+ let _ = 2.0;
+ let _ = b'a';
+ let _ = 'b';
+ let _ = "c";
+ let _ = r"d";
+ let _ = b"e";
+ let _ = br"f";
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0086_function_ret_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0086_function_ret_type.rast
new file mode 100644
index 000000000..6687c843f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0086_function_ret_type.rast
@@ -0,0 +1,36 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "bar"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ RET_TYPE
+ THIN_ARROW "->"
+ WHITESPACE " "
+ TUPLE_TYPE
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0086_function_ret_type.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0086_function_ret_type.rs
new file mode 100644
index 000000000..d22d8cada
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0086_function_ret_type.rs
@@ -0,0 +1,2 @@
+fn foo() {}
+fn bar() -> () {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0088_break_ambiguity.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0088_break_ambiguity.rast
new file mode 100644
index 000000000..cbf5e84e8
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0088_break_ambiguity.rast
@@ -0,0 +1,67 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ IF_EXPR
+ IF_KW "if"
+ WHITESPACE " "
+ BREAK_EXPR
+ BREAK_KW "break"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n "
+ EXPR_STMT
+ WHILE_EXPR
+ WHILE_KW "while"
+ WHITESPACE " "
+ BREAK_EXPR
+ BREAK_KW "break"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n "
+ EXPR_STMT
+ FOR_EXPR
+ FOR_KW "for"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "i"
+ WHITESPACE " "
+ IN_KW "in"
+ WHITESPACE " "
+ BREAK_EXPR
+ BREAK_KW "break"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n "
+ MATCH_EXPR
+ MATCH_KW "match"
+ WHITESPACE " "
+ BREAK_EXPR
+ BREAK_KW "break"
+ WHITESPACE " "
+ MATCH_ARM_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0088_break_ambiguity.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0088_break_ambiguity.rs
new file mode 100644
index 000000000..560eb05b9
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0088_break_ambiguity.rs
@@ -0,0 +1,6 @@
+fn foo(){
+ if break {}
+ while break {}
+ for i in break {}
+ match break {}
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0090_type_param_default.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0090_type_param_default.rast
new file mode 100644
index 000000000..cf7236f62
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0090_type_param_default.rast
@@ -0,0 +1,22 @@
+SOURCE_FILE
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "T"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ R_ANGLE ">"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0090_type_param_default.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0090_type_param_default.rs
new file mode 100644
index 000000000..540eacb02
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0090_type_param_default.rs
@@ -0,0 +1 @@
+struct S<T = i32>;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0092_fn_pointer_type_with_ret.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0092_fn_pointer_type_with_ret.rast
new file mode 100644
index 000000000..372c867ae
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0092_fn_pointer_type_with_ret.rast
@@ -0,0 +1,23 @@
+SOURCE_FILE
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "F"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ FN_PTR_TYPE
+ FN_KW "fn"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ RET_TYPE
+ THIN_ARROW "->"
+ WHITESPACE " "
+ TUPLE_TYPE
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0092_fn_pointer_type_with_ret.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0092_fn_pointer_type_with_ret.rs
new file mode 100644
index 000000000..e3ba5e87f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0092_fn_pointer_type_with_ret.rs
@@ -0,0 +1 @@
+type F = fn() -> ();
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0093_index_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0093_index_expr.rast
new file mode 100644
index 000000000..6969259fc
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0093_index_expr.rast
@@ -0,0 +1,34 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ INDEX_EXPR
+ INDEX_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "x"
+ L_BRACK "["
+ LITERAL
+ INT_NUMBER "1"
+ R_BRACK "]"
+ L_BRACK "["
+ LITERAL
+ INT_NUMBER "2"
+ R_BRACK "]"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0093_index_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0093_index_expr.rs
new file mode 100644
index 000000000..b9ba78a6c
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0093_index_expr.rs
@@ -0,0 +1,3 @@
+fn foo() {
+ x[1][2];
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0095_placeholder_pat.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0095_placeholder_pat.rast
new file mode 100644
index 000000000..d39c3df2b
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0095_placeholder_pat.rast
@@ -0,0 +1,29 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0095_placeholder_pat.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0095_placeholder_pat.rs
new file mode 100644
index 000000000..4d719c433
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0095_placeholder_pat.rs
@@ -0,0 +1 @@
+fn main() { let _ = (); }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0096_no_semi_after_block.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0096_no_semi_after_block.rast
new file mode 100644
index 000000000..f89cc15e7
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0096_no_semi_after_block.rast
@@ -0,0 +1,125 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ IF_EXPR
+ IF_KW "if"
+ WHITESPACE " "
+ LITERAL
+ TRUE_KW "true"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n "
+ EXPR_STMT
+ LOOP_EXPR
+ LOOP_KW "loop"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n "
+ EXPR_STMT
+ MATCH_EXPR
+ MATCH_KW "match"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ MATCH_ARM_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n "
+ EXPR_STMT
+ WHILE_EXPR
+ WHILE_KW "while"
+ WHITESPACE " "
+ LITERAL
+ TRUE_KW "true"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n "
+ EXPR_STMT
+ FOR_EXPR
+ FOR_KW "for"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ IN_KW "in"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n "
+ MACRO_RULES
+ MACRO_RULES_KW "macro_rules"
+ BANG "!"
+ WHITESPACE " "
+ NAME
+ IDENT "test"
+ WHITESPACE " "
+ TOKEN_TREE
+ L_CURLY "{"
+ WHITESPACE "\n "
+ TOKEN_TREE
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ EQ "="
+ R_ANGLE ">"
+ WHITESPACE " "
+ TOKEN_TREE
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n "
+ MACRO_EXPR
+ MACRO_CALL
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "test"
+ BANG "!"
+ TOKEN_TREE
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0096_no_semi_after_block.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0096_no_semi_after_block.rs
new file mode 100644
index 000000000..4919665cb
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0096_no_semi_after_block.rs
@@ -0,0 +1,13 @@
+fn foo() {
+ if true {}
+ loop {}
+ match () {}
+ while true {}
+ for _ in () {}
+ {}
+ {}
+ macro_rules! test {
+ () => {}
+ }
+ test!{}
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0099_param_list.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0099_param_list.rast
new file mode 100644
index 000000000..d240a52f6
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0099_param_list.rast
@@ -0,0 +1,103 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "a"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "b"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "x"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "c"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "x"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ COMMA ","
+ WHITESPACE " "
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "d"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "x"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ COMMA ","
+ WHITESPACE " "
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "y"
+ COLON ":"
+ WHITESPACE " "
+ TUPLE_TYPE
+ L_PAREN "("
+ R_PAREN ")"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0099_param_list.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0099_param_list.rs
new file mode 100644
index 000000000..9d55bedbb
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0099_param_list.rs
@@ -0,0 +1,4 @@
+fn a() {}
+fn b(x: i32) {}
+fn c(x: i32, ) {}
+fn d(x: i32, y: ()) {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0100_for_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0100_for_expr.rast
new file mode 100644
index 000000000..6bc3c0fb0
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0100_for_expr.rast
@@ -0,0 +1,36 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ FOR_EXPR
+ FOR_KW "for"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "x"
+ WHITESPACE " "
+ IN_KW "in"
+ WHITESPACE " "
+ ARRAY_EXPR
+ L_BRACK "["
+ R_BRACK "]"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0100_for_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0100_for_expr.rs
new file mode 100644
index 000000000..972197d2a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0100_for_expr.rs
@@ -0,0 +1,3 @@
+fn foo() {
+ for x in [] {};
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0102_record_pat_field_list.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0102_record_pat_field_list.rast
new file mode 100644
index 000000000..f69ae1d64
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0102_record_pat_field_list.rast
@@ -0,0 +1,175 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ RECORD_PAT
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_PAT_FIELD_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ RECORD_PAT
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_PAT_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ RECORD_PAT_FIELD
+ IDENT_PAT
+ NAME
+ IDENT "f"
+ COMMA ","
+ WHITESPACE " "
+ RECORD_PAT_FIELD
+ IDENT_PAT
+ REF_KW "ref"
+ WHITESPACE " "
+ MUT_KW "mut"
+ WHITESPACE " "
+ NAME
+ IDENT "g"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ RECORD_PAT
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_PAT_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ RECORD_PAT_FIELD
+ NAME_REF
+ IDENT "h"
+ COLON ":"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ COMMA ","
+ WHITESPACE " "
+ REST_PAT
+ DOT2 ".."
+ R_CURLY "}"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ RECORD_PAT
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_PAT_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ RECORD_PAT_FIELD
+ NAME_REF
+ IDENT "h"
+ COLON ":"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ COMMA ","
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ RECORD_PAT
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_PAT_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ REST_PAT
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "cfg"
+ TOKEN_TREE
+ L_PAREN "("
+ IDENT "any"
+ TOKEN_TREE
+ L_PAREN "("
+ R_PAREN ")"
+ R_PAREN ")"
+ R_BRACK "]"
+ WHITESPACE " "
+ DOT2 ".."
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0102_record_pat_field_list.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0102_record_pat_field_list.rs
new file mode 100644
index 000000000..0bfaae7c4
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0102_record_pat_field_list.rs
@@ -0,0 +1,7 @@
+fn foo() {
+ let S {} = ();
+ let S { f, ref mut g } = ();
+ let S { h: _, ..} = ();
+ let S { h: _, } = ();
+ let S { #[cfg(any())] .. } = ();
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0103_array_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0103_array_expr.rast
new file mode 100644
index 000000000..60395948c
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0103_array_expr.rast
@@ -0,0 +1,55 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ ARRAY_EXPR
+ L_BRACK "["
+ R_BRACK "]"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ ARRAY_EXPR
+ L_BRACK "["
+ LITERAL
+ INT_NUMBER "1"
+ R_BRACK "]"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ ARRAY_EXPR
+ L_BRACK "["
+ LITERAL
+ INT_NUMBER "1"
+ COMMA ","
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "2"
+ COMMA ","
+ R_BRACK "]"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ ARRAY_EXPR
+ L_BRACK "["
+ LITERAL
+ INT_NUMBER "1"
+ SEMICOLON ";"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "2"
+ R_BRACK "]"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0103_array_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0103_array_expr.rs
new file mode 100644
index 000000000..4dc1999d1
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0103_array_expr.rs
@@ -0,0 +1,6 @@
+fn foo() {
+ [];
+ [1];
+ [1, 2,];
+ [1; 2];
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0104_path_fn_trait_args.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0104_path_fn_trait_args.rast
new file mode 100644
index 000000000..fd83daf84
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0104_path_fn_trait_args.rast
@@ -0,0 +1,41 @@
+SOURCE_FILE
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "F"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Box"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ TYPE_ARG
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Fn"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ R_PAREN ")"
+ WHITESPACE " "
+ RET_TYPE
+ THIN_ARROW "->"
+ WHITESPACE " "
+ TUPLE_TYPE
+ L_PAREN "("
+ R_PAREN ")"
+ R_ANGLE ">"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0104_path_fn_trait_args.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0104_path_fn_trait_args.rs
new file mode 100644
index 000000000..17ed20e5b
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0104_path_fn_trait_args.rs
@@ -0,0 +1 @@
+type F = Box<Fn(i32) -> ()>;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0106_lambda_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0106_lambda_expr.rast
new file mode 100644
index 000000000..c25ad8430
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0106_lambda_expr.rast
@@ -0,0 +1,246 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CLOSURE_EXPR
+ PARAM_LIST
+ PIPE "|"
+ PIPE "|"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CLOSURE_EXPR
+ PARAM_LIST
+ PIPE "|"
+ PIPE "|"
+ WHITESPACE " "
+ RET_TYPE
+ THIN_ARROW "->"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "92"
+ WHITESPACE " "
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CLOSURE_EXPR
+ PARAM_LIST
+ PIPE "|"
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "x"
+ PIPE "|"
+ WHITESPACE " "
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "x"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CLOSURE_EXPR
+ MOVE_KW "move"
+ WHITESPACE " "
+ PARAM_LIST
+ PIPE "|"
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "x"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ COMMA ","
+ PIPE "|"
+ WHITESPACE " "
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "x"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CLOSURE_EXPR
+ ASYNC_KW "async"
+ WHITESPACE " "
+ PARAM_LIST
+ PIPE "|"
+ PIPE "|"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CLOSURE_EXPR
+ MOVE_KW "move"
+ WHITESPACE " "
+ PARAM_LIST
+ PIPE "|"
+ PIPE "|"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CLOSURE_EXPR
+ ASYNC_KW "async"
+ WHITESPACE " "
+ MOVE_KW "move"
+ WHITESPACE " "
+ PARAM_LIST
+ PIPE "|"
+ PIPE "|"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CLOSURE_EXPR
+ STATIC_KW "static"
+ WHITESPACE " "
+ PARAM_LIST
+ PIPE "|"
+ PIPE "|"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CLOSURE_EXPR
+ STATIC_KW "static"
+ WHITESPACE " "
+ MOVE_KW "move"
+ WHITESPACE " "
+ PARAM_LIST
+ PIPE "|"
+ PIPE "|"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CLOSURE_EXPR
+ STATIC_KW "static"
+ WHITESPACE " "
+ ASYNC_KW "async"
+ WHITESPACE " "
+ PARAM_LIST
+ PIPE "|"
+ PIPE "|"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CLOSURE_EXPR
+ STATIC_KW "static"
+ WHITESPACE " "
+ ASYNC_KW "async"
+ WHITESPACE " "
+ MOVE_KW "move"
+ WHITESPACE " "
+ PARAM_LIST
+ PIPE "|"
+ PIPE "|"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CLOSURE_EXPR
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ WHITESPACE " "
+ PARAM_LIST
+ PIPE "|"
+ PIPE "|"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CLOSURE_EXPR
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ WHITESPACE " "
+ MOVE_KW "move"
+ WHITESPACE " "
+ PARAM_LIST
+ PIPE "|"
+ PIPE "|"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0106_lambda_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0106_lambda_expr.rs
new file mode 100644
index 000000000..75516d258
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0106_lambda_expr.rs
@@ -0,0 +1,15 @@
+fn foo() {
+ || ();
+ || -> i32 { 92 };
+ |x| x;
+ move |x: i32,| x;
+ async || {};
+ move || {};
+ async move || {};
+ static || {};
+ static move || {};
+ static async || {};
+ static async move || {};
+ for<'a> || {};
+ for<'a> move || {};
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0107_method_call_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0107_method_call_expr.rast
new file mode 100644
index 000000000..dcbcfe123
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0107_method_call_expr.rast
@@ -0,0 +1,63 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ METHOD_CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "x"
+ DOT "."
+ NAME_REF
+ IDENT "foo"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ METHOD_CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "y"
+ DOT "."
+ NAME_REF
+ IDENT "bar"
+ GENERIC_ARG_LIST
+ COLON2 "::"
+ L_ANGLE "<"
+ TYPE_ARG
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "T"
+ R_ANGLE ">"
+ ARG_LIST
+ L_PAREN "("
+ LITERAL
+ INT_NUMBER "1"
+ COMMA ","
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "2"
+ COMMA ","
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0107_method_call_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0107_method_call_expr.rs
new file mode 100644
index 000000000..1a3aa35ae
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0107_method_call_expr.rs
@@ -0,0 +1,4 @@
+fn foo() {
+ x.foo();
+ y.bar::<T>(1, 2,);
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0108_tuple_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0108_tuple_expr.rast
new file mode 100644
index 000000000..ac5a71703
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0108_tuple_expr.rast
@@ -0,0 +1,39 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ PAREN_EXPR
+ L_PAREN "("
+ LITERAL
+ INT_NUMBER "1"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ TUPLE_EXPR
+ L_PAREN "("
+ LITERAL
+ INT_NUMBER "1"
+ COMMA ","
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0108_tuple_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0108_tuple_expr.rs
new file mode 100644
index 000000000..e4f774280
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0108_tuple_expr.rs
@@ -0,0 +1,5 @@
+fn foo() {
+ ();
+ (1);
+ (1,);
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0109_label.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0109_label.rast
new file mode 100644
index 000000000..48d0bde84
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0109_label.rast
@@ -0,0 +1,70 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ LOOP_EXPR
+ LABEL
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ COLON ":"
+ WHITESPACE " "
+ LOOP_KW "loop"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n "
+ EXPR_STMT
+ WHILE_EXPR
+ LABEL
+ LIFETIME
+ LIFETIME_IDENT "'b"
+ COLON ":"
+ WHITESPACE " "
+ WHILE_KW "while"
+ WHITESPACE " "
+ LITERAL
+ TRUE_KW "true"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n "
+ FOR_EXPR
+ LABEL
+ LIFETIME
+ LIFETIME_IDENT "'c"
+ COLON ":"
+ WHITESPACE " "
+ FOR_KW "for"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "x"
+ WHITESPACE " "
+ IN_KW "in"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0109_label.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0109_label.rs
new file mode 100644
index 000000000..48e83f263
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0109_label.rs
@@ -0,0 +1,5 @@
+fn foo() {
+ 'a: loop {}
+ 'b: while true {}
+ 'c: for x in () {}
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0111_tuple_pat.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0111_tuple_pat.rast
new file mode 100644
index 000000000..cebe98c43
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0111_tuple_pat.rast
@@ -0,0 +1,90 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ TUPLE_PAT
+ L_PAREN "("
+ IDENT_PAT
+ NAME
+ IDENT "a"
+ COMMA ","
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "b"
+ COMMA ","
+ WHITESPACE " "
+ REST_PAT
+ DOT2 ".."
+ R_PAREN ")"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ TUPLE_PAT
+ L_PAREN "("
+ IDENT_PAT
+ NAME
+ IDENT "a"
+ COMMA ","
+ R_PAREN ")"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ TUPLE_PAT
+ L_PAREN "("
+ REST_PAT
+ DOT2 ".."
+ R_PAREN ")"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ TUPLE_PAT
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0111_tuple_pat.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0111_tuple_pat.rs
new file mode 100644
index 000000000..ba719879d
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0111_tuple_pat.rs
@@ -0,0 +1,6 @@
+fn main() {
+ let (a, b, ..) = ();
+ let (a,) = ();
+ let (..) = ();
+ let () = ();
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0112_bind_pat.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0112_bind_pat.rast
new file mode 100644
index 000000000..eb1c32474
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0112_bind_pat.rast
@@ -0,0 +1,128 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "a"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ MUT_KW "mut"
+ WHITESPACE " "
+ NAME
+ IDENT "b"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ REF_KW "ref"
+ WHITESPACE " "
+ NAME
+ IDENT "c"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ REF_KW "ref"
+ WHITESPACE " "
+ MUT_KW "mut"
+ WHITESPACE " "
+ NAME
+ IDENT "d"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "e"
+ WHITESPACE " "
+ AT "@"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ REF_KW "ref"
+ WHITESPACE " "
+ MUT_KW "mut"
+ WHITESPACE " "
+ NAME
+ IDENT "f"
+ WHITESPACE " "
+ AT "@"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "g"
+ WHITESPACE " "
+ AT "@"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0112_bind_pat.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0112_bind_pat.rs
new file mode 100644
index 000000000..820a9e72c
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0112_bind_pat.rs
@@ -0,0 +1,8 @@
+fn main() {
+ let a = ();
+ let mut b = ();
+ let ref c = ();
+ let ref mut d = ();
+ let e @ _ = ();
+ let ref mut f @ g @ _ = ();
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0113_nocontentexpr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0113_nocontentexpr.rast
new file mode 100644
index 000000000..8bd90a7f6
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0113_nocontentexpr.rast
@@ -0,0 +1,57 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ SEMICOLON ";"
+ SEMICOLON ";"
+ SEMICOLON ";"
+ EXPR_STMT
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "some_expr"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ SEMICOLON ";"
+ SEMICOLON ";"
+ SEMICOLON ";"
+ EXPR_STMT
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ SEMICOLON ";"
+ SEMICOLON ";"
+ SEMICOLON ";"
+ R_CURLY "}"
+ SEMICOLON ";"
+ SEMICOLON ";"
+ SEMICOLON ";"
+ SEMICOLON ";"
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Ok"
+ ARG_LIST
+ L_PAREN "("
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ R_PAREN ")"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0113_nocontentexpr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0113_nocontentexpr.rs
new file mode 100644
index 000000000..bbf09e367
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0113_nocontentexpr.rs
@@ -0,0 +1,3 @@
+fn foo(){
+ ;;;some_expr();;;;{;;;};;;;Ok(())
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0114_tuple_struct_where.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0114_tuple_struct_where.rast
new file mode 100644
index 000000000..aab774165
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0114_tuple_struct_where.rast
@@ -0,0 +1,42 @@
+SOURCE_FILE
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "T"
+ R_ANGLE ">"
+ TUPLE_FIELD_LIST
+ L_PAREN "("
+ TUPLE_FIELD
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "T"
+ R_PAREN ")"
+ WHITESPACE " "
+ WHERE_CLAUSE
+ WHERE_KW "where"
+ WHITESPACE " "
+ WHERE_PRED
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "T"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Clone"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0114_tuple_struct_where.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0114_tuple_struct_where.rs
new file mode 100644
index 000000000..a602e0018
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0114_tuple_struct_where.rs
@@ -0,0 +1 @@
+struct S<T>(T) where T: Clone;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0115_tuple_field_attrs.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0115_tuple_field_attrs.rast
new file mode 100644
index 000000000..1699602f4
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0115_tuple_field_attrs.rast
@@ -0,0 +1,28 @@
+SOURCE_FILE
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S"
+ WHITESPACE " "
+ TUPLE_FIELD_LIST
+ L_PAREN "("
+ TUPLE_FIELD
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "attr"
+ R_BRACK "]"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "f32"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0115_tuple_field_attrs.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0115_tuple_field_attrs.rs
new file mode 100644
index 000000000..648ffe565
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0115_tuple_field_attrs.rs
@@ -0,0 +1 @@
+struct S (#[attr] f32);
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0117_macro_call_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0117_macro_call_type.rast
new file mode 100644
index 000000000..8165cb7d9
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0117_macro_call_type.rast
@@ -0,0 +1,46 @@
+SOURCE_FILE
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "A"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ MACRO_TYPE
+ MACRO_CALL
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "foo"
+ BANG "!"
+ TOKEN_TREE
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "B"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ MACRO_TYPE
+ MACRO_CALL
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ CRATE_KW "crate"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "foo"
+ BANG "!"
+ TOKEN_TREE
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0117_macro_call_type.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0117_macro_call_type.rs
new file mode 100644
index 000000000..edb470c89
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0117_macro_call_type.rs
@@ -0,0 +1,2 @@
+type A = foo!();
+type B = crate::foo!();
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0118_match_guard.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0118_match_guard.rast
new file mode 100644
index 000000000..96318b521
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0118_match_guard.rast
@@ -0,0 +1,77 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ MATCH_EXPR
+ MATCH_KW "match"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ MATCH_ARM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ MATCH_ARM
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ MATCH_GUARD
+ IF_KW "if"
+ WHITESPACE " "
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "foo"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n "
+ MATCH_ARM
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ MATCH_GUARD
+ IF_KW "if"
+ WHITESPACE " "
+ LET_EXPR
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "foo"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "bar"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0118_match_guard.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0118_match_guard.rs
new file mode 100644
index 000000000..cfe05ce4e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0118_match_guard.rs
@@ -0,0 +1,6 @@
+fn foo() {
+ match () {
+ _ if foo => (),
+ _ if let foo = bar => (),
+ }
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0120_match_arms_inner_attribute.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0120_match_arms_inner_attribute.rast
new file mode 100644
index 000000000..6fd9f4246
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0120_match_arms_inner_attribute.rast
@@ -0,0 +1,84 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ MATCH_EXPR
+ MATCH_KW "match"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ MATCH_ARM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ ATTR
+ POUND "#"
+ BANG "!"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "doc"
+ TOKEN_TREE
+ L_PAREN "("
+ STRING "\"Inner attribute\""
+ R_PAREN ")"
+ R_BRACK "]"
+ WHITESPACE "\n "
+ ATTR
+ POUND "#"
+ BANG "!"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "doc"
+ TOKEN_TREE
+ L_PAREN "("
+ STRING "\"Can be\""
+ R_PAREN ")"
+ R_BRACK "]"
+ WHITESPACE "\n "
+ ATTR
+ POUND "#"
+ BANG "!"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "doc"
+ TOKEN_TREE
+ L_PAREN "("
+ STRING "\"Stacked\""
+ R_PAREN ")"
+ R_BRACK "]"
+ WHITESPACE "\n "
+ MATCH_ARM
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0120_match_arms_inner_attribute.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0120_match_arms_inner_attribute.rs
new file mode 100644
index 000000000..54a67c9d7
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0120_match_arms_inner_attribute.rs
@@ -0,0 +1,8 @@
+fn foo() {
+ match () {
+ #![doc("Inner attribute")]
+ #![doc("Can be")]
+ #![doc("Stacked")]
+ _ => (),
+ }
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0121_match_arms_outer_attributes.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0121_match_arms_outer_attributes.rast
new file mode 100644
index 000000000..0f7580c1a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0121_match_arms_outer_attributes.rast
@@ -0,0 +1,151 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ MATCH_EXPR
+ MATCH_KW "match"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ MATCH_ARM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ MATCH_ARM
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "cfg"
+ TOKEN_TREE
+ L_PAREN "("
+ IDENT "feature"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ STRING "\"some\""
+ R_PAREN ")"
+ R_BRACK "]"
+ WHITESPACE "\n "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n "
+ MATCH_ARM
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "cfg"
+ TOKEN_TREE
+ L_PAREN "("
+ IDENT "feature"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ STRING "\"other\""
+ R_PAREN ")"
+ R_BRACK "]"
+ WHITESPACE "\n "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n "
+ MATCH_ARM
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "cfg"
+ TOKEN_TREE
+ L_PAREN "("
+ IDENT "feature"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ STRING "\"many\""
+ R_PAREN ")"
+ R_BRACK "]"
+ WHITESPACE "\n "
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "cfg"
+ TOKEN_TREE
+ L_PAREN "("
+ IDENT "feature"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ STRING "\"attributes\""
+ R_PAREN ")"
+ R_BRACK "]"
+ WHITESPACE "\n "
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "cfg"
+ TOKEN_TREE
+ L_PAREN "("
+ IDENT "feature"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ STRING "\"before\""
+ R_PAREN ")"
+ R_BRACK "]"
+ WHITESPACE "\n "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0121_match_arms_outer_attributes.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0121_match_arms_outer_attributes.rs
new file mode 100644
index 000000000..676db42d1
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0121_match_arms_outer_attributes.rs
@@ -0,0 +1,12 @@
+fn foo() {
+ match () {
+ #[cfg(feature = "some")]
+ _ => (),
+ #[cfg(feature = "other")]
+ _ => (),
+ #[cfg(feature = "many")]
+ #[cfg(feature = "attributes")]
+ #[cfg(feature = "before")]
+ _ => (),
+ }
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0123_param_list_vararg.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0123_param_list_vararg.rast
new file mode 100644
index 000000000..338d53995
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0123_param_list_vararg.rast
@@ -0,0 +1,62 @@
+SOURCE_FILE
+ EXTERN_BLOCK
+ ABI
+ EXTERN_KW "extern"
+ WHITESPACE " "
+ STRING "\"C\""
+ WHITESPACE " "
+ EXTERN_ITEM_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "printf"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "format"
+ COLON ":"
+ WHITESPACE " "
+ PTR_TYPE
+ STAR "*"
+ CONST_KW "const"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i8"
+ COMMA ","
+ WHITESPACE " "
+ PARAM
+ DOT3 "..."
+ COMMA ","
+ WHITESPACE " "
+ PARAM
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u8"
+ R_PAREN ")"
+ WHITESPACE " "
+ RET_TYPE
+ THIN_ARROW "->"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ SEMICOLON ";"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0123_param_list_vararg.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0123_param_list_vararg.rs
new file mode 100644
index 000000000..533096cd5
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0123_param_list_vararg.rs
@@ -0,0 +1 @@
+extern "C" { fn printf(format: *const i8, ..., _: u8) -> i32; }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0125_crate_keyword_path.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0125_crate_keyword_path.rast
new file mode 100644
index 000000000..8d9b61630
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0125_crate_keyword_path.rast
@@ -0,0 +1,33 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ EXPR_STMT
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ CRATE_KW "crate"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "foo"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0125_crate_keyword_path.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0125_crate_keyword_path.rs
new file mode 100644
index 000000000..0f454d121
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0125_crate_keyword_path.rs
@@ -0,0 +1 @@
+fn foo() { crate::foo(); }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0125_record_literal_field_with_attr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0125_record_literal_field_with_attr.rast
new file mode 100644
index 000000000..a1df70841
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0125_record_literal_field_with_attr.rast
@@ -0,0 +1,49 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ RECORD_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_EXPR_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ RECORD_EXPR_FIELD
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "cfg"
+ TOKEN_TREE
+ L_PAREN "("
+ IDENT "test"
+ R_PAREN ")"
+ R_BRACK "]"
+ WHITESPACE " "
+ NAME_REF
+ IDENT "field"
+ COLON ":"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "1"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0125_record_literal_field_with_attr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0125_record_literal_field_with_attr.rs
new file mode 100644
index 000000000..a6c7760c7
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0125_record_literal_field_with_attr.rs
@@ -0,0 +1,3 @@
+fn main() {
+ S { #[cfg(test)] field: 1 }
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0126_attr_on_expr_stmt.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0126_attr_on_expr_stmt.rast
new file mode 100644
index 000000000..81b7f2b3c
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0126_attr_on_expr_stmt.rast
@@ -0,0 +1,105 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CALL_EXPR
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "A"
+ R_BRACK "]"
+ WHITESPACE " "
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "foo"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ MACRO_EXPR
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "B"
+ R_BRACK "]"
+ WHITESPACE " "
+ MACRO_CALL
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "bar"
+ BANG "!"
+ TOKEN_TREE
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BLOCK_EXPR
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "C"
+ R_BRACK "]"
+ WHITESPACE " "
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "D"
+ R_BRACK "]"
+ WHITESPACE " "
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n "
+ EXPR_STMT
+ RETURN_EXPR
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "D"
+ R_BRACK "]"
+ WHITESPACE " "
+ RETURN_KW "return"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0126_attr_on_expr_stmt.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0126_attr_on_expr_stmt.rs
new file mode 100644
index 000000000..b28c078f9
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0126_attr_on_expr_stmt.rs
@@ -0,0 +1,6 @@
+fn foo() {
+ #[A] foo();
+ #[B] bar!{}
+ #[C] #[D] {}
+ #[D] return ();
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0129_marco_pat.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0129_marco_pat.rast
new file mode 100644
index 000000000..cedaa9045
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0129_marco_pat.rast
@@ -0,0 +1,37 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ MACRO_PAT
+ MACRO_CALL
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "m"
+ BANG "!"
+ TOKEN_TREE
+ L_PAREN "("
+ IDENT "x"
+ R_PAREN ")"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "0"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0129_marco_pat.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0129_marco_pat.rs
new file mode 100644
index 000000000..811181d9b
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0129_marco_pat.rs
@@ -0,0 +1,3 @@
+fn main() {
+ let m!(x) = 0;
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0130_let_stmt.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0130_let_stmt.rast
new file mode 100644
index 000000000..de9d0fc19
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0130_let_stmt.rast
@@ -0,0 +1,36 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "f"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "x"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "92"
+ SEMICOLON ";"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0130_let_stmt.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0130_let_stmt.rs
new file mode 100644
index 000000000..8003999fd
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0130_let_stmt.rs
@@ -0,0 +1 @@
+fn f() { let x: i32 = 92; }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0130_try_block_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0130_try_block_expr.rast
new file mode 100644
index 000000000..aec8fbf47
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0130_try_block_expr.rast
@@ -0,0 +1,32 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ BLOCK_EXPR
+ TRY_KW "try"
+ WHITESPACE " "
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0130_try_block_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0130_try_block_expr.rs
new file mode 100644
index 000000000..0f1b41eb6
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0130_try_block_expr.rs
@@ -0,0 +1,3 @@
+fn foo() {
+ let _ = try {};
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0131_existential_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0131_existential_type.rast
new file mode 100644
index 000000000..b73780261
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0131_existential_type.rast
@@ -0,0 +1,31 @@
+SOURCE_FILE
+ TYPE_ALIAS
+ EXISTENTIAL_KW "existential"
+ WHITESPACE " "
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "Foo"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Fn"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ RET_TYPE
+ THIN_ARROW "->"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "usize"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0131_existential_type.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0131_existential_type.rs
new file mode 100644
index 000000000..23baf7145
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0131_existential_type.rs
@@ -0,0 +1 @@
+existential type Foo: Fn() -> usize;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0132_box_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0132_box_expr.rast
new file mode 100644
index 000000000..b21f37cd8
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0132_box_expr.rast
@@ -0,0 +1,90 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "x"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ BOX_EXPR
+ BOX_KW "box"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "1i32"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "y"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ BOX_EXPR
+ BOX_KW "box"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "1i32"
+ COMMA ","
+ WHITESPACE " "
+ BOX_EXPR
+ BOX_KW "box"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "2i32"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "z"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Foo"
+ ARG_LIST
+ L_PAREN "("
+ BOX_EXPR
+ BOX_KW "box"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "1i32"
+ COMMA ","
+ WHITESPACE " "
+ BOX_EXPR
+ BOX_KW "box"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "2i32"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0132_box_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0132_box_expr.rs
new file mode 100644
index 000000000..fc9923b71
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0132_box_expr.rs
@@ -0,0 +1,5 @@
+fn foo() {
+ let x = box 1i32;
+ let y = (box 1i32, box 2i32);
+ let z = Foo(box 1i32, box 2i32);
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0134_nocontentexpr_after_item.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0134_nocontentexpr_after_item.rast
new file mode 100644
index 000000000..f5ee12fe9
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0134_nocontentexpr_after_item.rast
@@ -0,0 +1,64 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "simple_function"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ ENUM
+ ENUM_KW "enum"
+ WHITESPACE " "
+ NAME
+ IDENT "LocalEnum"
+ WHITESPACE " "
+ VARIANT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ VARIANT
+ NAME
+ IDENT "One"
+ COMMA ","
+ WHITESPACE "\n "
+ VARIANT
+ NAME
+ IDENT "Two"
+ COMMA ","
+ WHITESPACE "\n "
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "f"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_FIELD_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0134_nocontentexpr_after_item.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0134_nocontentexpr_after_item.rs
new file mode 100644
index 000000000..eadc7fffb
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0134_nocontentexpr_after_item.rs
@@ -0,0 +1,8 @@
+fn simple_function() {
+ enum LocalEnum {
+ One,
+ Two,
+ };
+ fn f() {};
+ struct S {};
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0137_await_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0137_await_expr.rast
new file mode 100644
index 000000000..9d37ada0d
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0137_await_expr.rast
@@ -0,0 +1,70 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ AWAIT_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "x"
+ DOT "."
+ AWAIT_KW "await"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ AWAIT_EXPR
+ FIELD_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "x"
+ DOT "."
+ NAME_REF
+ INT_NUMBER "0"
+ DOT "."
+ AWAIT_KW "await"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ METHOD_CALL_EXPR
+ TRY_EXPR
+ AWAIT_EXPR
+ CALL_EXPR
+ FIELD_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "x"
+ DOT "."
+ NAME_REF
+ INT_NUMBER "0"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ DOT "."
+ AWAIT_KW "await"
+ QUESTION "?"
+ DOT "."
+ NAME_REF
+ IDENT "hello"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0137_await_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0137_await_expr.rs
new file mode 100644
index 000000000..d2ba89ca6
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0137_await_expr.rs
@@ -0,0 +1,5 @@
+fn foo() {
+ x.await;
+ x.0.await;
+ x.0().await?.hello();
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0138_associated_type_bounds.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0138_associated_type_bounds.rast
new file mode 100644
index 000000000..8cbc98c51
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0138_associated_type_bounds.rast
@@ -0,0 +1,111 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "print_all"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "T"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Iterator"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ TYPE_ARG
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Item"
+ COMMA ","
+ WHITESPACE " "
+ TYPE_ARG
+ PATH_TYPE
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Item"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Item"
+ COMMA ","
+ WHITESPACE " "
+ TYPE_ARG
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Item"
+ GENERIC_ARG_LIST
+ COLON2 "::"
+ L_ANGLE "<"
+ CONST_ARG
+ LITERAL
+ TRUE_KW "true"
+ R_ANGLE ">"
+ COMMA ","
+ WHITESPACE " "
+ ASSOC_TYPE_ARG
+ NAME_REF
+ IDENT "Item"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Display"
+ COMMA ","
+ WHITESPACE " "
+ ASSOC_TYPE_ARG
+ NAME_REF
+ IDENT "Item"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ LIFETIME_ARG
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Item"
+ R_ANGLE ">"
+ R_ANGLE ">"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "printables"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "T"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0138_associated_type_bounds.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0138_associated_type_bounds.rs
new file mode 100644
index 000000000..0f7a2d160
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0138_associated_type_bounds.rs
@@ -0,0 +1 @@
+fn print_all<T: Iterator<Item, Item::Item, Item::<true>, Item: Display, Item<'a> = Item>>(printables: T) {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0138_expression_after_block.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0138_expression_after_block.rast
new file mode 100644
index 000000000..553ac356d
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0138_expression_after_block.rast
@@ -0,0 +1,66 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ MUT_KW "mut"
+ WHITESPACE " "
+ NAME
+ IDENT "p"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ RECORD_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "F"
+ RECORD_EXPR_FIELD_LIST
+ L_CURLY "{"
+ RECORD_EXPR_FIELD
+ NAME_REF
+ IDENT "x"
+ COLON ":"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "5"
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BIN_EXPR
+ FIELD_EXPR
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "p"
+ R_CURLY "}"
+ DOT "."
+ NAME_REF
+ IDENT "x"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "10"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0138_expression_after_block.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0138_expression_after_block.rs
new file mode 100644
index 000000000..76007e3ee
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0138_expression_after_block.rs
@@ -0,0 +1,4 @@
+fn foo() {
+ let mut p = F{x: 5};
+ {p}.x = 10;
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0138_self_param_outer_attr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0138_self_param_outer_attr.rast
new file mode 100644
index 000000000..db583f7d5
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0138_self_param_outer_attr.rast
@@ -0,0 +1,28 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "f"
+ PARAM_LIST
+ L_PAREN "("
+ SELF_PARAM
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "must_use"
+ R_BRACK "]"
+ WHITESPACE " "
+ NAME
+ SELF_KW "self"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0138_self_param_outer_attr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0138_self_param_outer_attr.rs
new file mode 100644
index 000000000..35155057a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0138_self_param_outer_attr.rs
@@ -0,0 +1 @@
+fn f(#[must_use] self) {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0139_param_outer_arg.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0139_param_outer_arg.rast
new file mode 100644
index 000000000..c63ea020a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0139_param_outer_arg.rast
@@ -0,0 +1,36 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "f"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "attr1"
+ R_BRACK "]"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "pat"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Type"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0139_param_outer_arg.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0139_param_outer_arg.rs
new file mode 100644
index 000000000..c238be791
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0139_param_outer_arg.rs
@@ -0,0 +1 @@
+fn f(#[attr1] pat: Type) {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0142_for_range_from.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0142_for_range_from.rast
new file mode 100644
index 000000000..90cf3101c
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0142_for_range_from.rast
@@ -0,0 +1,42 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ FOR_EXPR
+ FOR_KW "for"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "x"
+ WHITESPACE " "
+ IN_KW "in"
+ WHITESPACE " "
+ RANGE_EXPR
+ LITERAL
+ INT_NUMBER "0"
+ WHITESPACE " "
+ DOT2 ".."
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BREAK_EXPR
+ BREAK_KW "break"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0142_for_range_from.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0142_for_range_from.rs
new file mode 100644
index 000000000..af0d40a7a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0142_for_range_from.rs
@@ -0,0 +1,5 @@
+fn foo() {
+ for x in 0 .. {
+ break;
+ }
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0143_box_pat.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0143_box_pat.rast
new file mode 100644
index 000000000..df22decde
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0143_box_pat.rast
@@ -0,0 +1,111 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ BOX_PAT
+ BOX_KW "box"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "i"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ BOX_PAT
+ BOX_KW "box"
+ WHITESPACE " "
+ RECORD_PAT
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Outer"
+ WHITESPACE " "
+ RECORD_PAT_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ RECORD_PAT_FIELD
+ BOX_PAT
+ BOX_KW "box"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "i"
+ COMMA ","
+ WHITESPACE " "
+ RECORD_PAT_FIELD
+ NAME_REF
+ IDENT "j"
+ COLON ":"
+ WHITESPACE " "
+ BOX_PAT
+ BOX_KW "box"
+ WHITESPACE " "
+ TUPLE_STRUCT_PAT
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Inner"
+ L_PAREN "("
+ BOX_PAT
+ BOX_KW "box"
+ WHITESPACE " "
+ REF_PAT
+ AMP "&"
+ IDENT_PAT
+ NAME
+ IDENT "x"
+ R_PAREN ")"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ BOX_PAT
+ BOX_KW "box"
+ WHITESPACE " "
+ IDENT_PAT
+ REF_KW "ref"
+ WHITESPACE " "
+ MUT_KW "mut"
+ WHITESPACE " "
+ NAME
+ IDENT "i"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0143_box_pat.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0143_box_pat.rs
new file mode 100644
index 000000000..9d458aa1e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0143_box_pat.rs
@@ -0,0 +1,5 @@
+fn main() {
+ let box i = ();
+ let box Outer { box i, j: box Inner(box &x) } = ();
+ let box ref mut i = ();
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0144_dot_dot_pat.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0144_dot_dot_pat.rast
new file mode 100644
index 000000000..4d4011e6b
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0144_dot_dot_pat.rast
@@ -0,0 +1,456 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ REST_PAT
+ DOT2 ".."
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ COMMENT "//"
+ WHITESPACE "\n "
+ COMMENT "// Tuples"
+ WHITESPACE "\n "
+ COMMENT "//"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ TUPLE_PAT
+ L_PAREN "("
+ IDENT_PAT
+ NAME
+ IDENT "a"
+ COMMA ","
+ WHITESPACE " "
+ REST_PAT
+ DOT2 ".."
+ R_PAREN ")"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ TUPLE_PAT
+ L_PAREN "("
+ IDENT_PAT
+ NAME
+ IDENT "a"
+ COMMA ","
+ WHITESPACE " "
+ REST_PAT
+ DOT2 ".."
+ COMMA ","
+ R_PAREN ")"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ TUPLE_STRUCT_PAT
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Tuple"
+ L_PAREN "("
+ IDENT_PAT
+ NAME
+ IDENT "a"
+ COMMA ","
+ WHITESPACE " "
+ REST_PAT
+ DOT2 ".."
+ R_PAREN ")"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ TUPLE_STRUCT_PAT
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Tuple"
+ L_PAREN "("
+ IDENT_PAT
+ NAME
+ IDENT "a"
+ COMMA ","
+ WHITESPACE " "
+ REST_PAT
+ DOT2 ".."
+ COMMA ","
+ R_PAREN ")"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ TUPLE_PAT
+ L_PAREN "("
+ REST_PAT
+ DOT2 ".."
+ COMMA ","
+ WHITESPACE " "
+ REST_PAT
+ DOT2 ".."
+ R_PAREN ")"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ TUPLE_STRUCT_PAT
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Tuple"
+ L_PAREN "("
+ REST_PAT
+ DOT2 ".."
+ COMMA ","
+ WHITESPACE " "
+ REST_PAT
+ DOT2 ".."
+ R_PAREN ")"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ TUPLE_PAT
+ L_PAREN "("
+ REST_PAT
+ DOT2 ".."
+ COMMA ","
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "a"
+ COMMA ","
+ WHITESPACE " "
+ REST_PAT
+ DOT2 ".."
+ R_PAREN ")"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ TUPLE_STRUCT_PAT
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Tuple"
+ L_PAREN "("
+ REST_PAT
+ DOT2 ".."
+ COMMA ","
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "a"
+ COMMA ","
+ WHITESPACE " "
+ REST_PAT
+ DOT2 ".."
+ R_PAREN ")"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ COMMENT "//"
+ WHITESPACE "\n "
+ COMMENT "// Slices"
+ WHITESPACE "\n "
+ COMMENT "//"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ SLICE_PAT
+ L_BRACK "["
+ REST_PAT
+ DOT2 ".."
+ R_BRACK "]"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ SLICE_PAT
+ L_BRACK "["
+ IDENT_PAT
+ NAME
+ IDENT "head"
+ COMMA ","
+ WHITESPACE " "
+ REST_PAT
+ DOT2 ".."
+ R_BRACK "]"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ SLICE_PAT
+ L_BRACK "["
+ IDENT_PAT
+ NAME
+ IDENT "head"
+ COMMA ","
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "tail"
+ WHITESPACE " "
+ AT "@"
+ WHITESPACE " "
+ REST_PAT
+ DOT2 ".."
+ R_BRACK "]"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ SLICE_PAT
+ L_BRACK "["
+ IDENT_PAT
+ NAME
+ IDENT "head"
+ COMMA ","
+ WHITESPACE " "
+ REST_PAT
+ DOT2 ".."
+ COMMA ","
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "cons"
+ R_BRACK "]"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ SLICE_PAT
+ L_BRACK "["
+ IDENT_PAT
+ NAME
+ IDENT "head"
+ COMMA ","
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "mid"
+ WHITESPACE " "
+ AT "@"
+ WHITESPACE " "
+ REST_PAT
+ DOT2 ".."
+ COMMA ","
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "cons"
+ R_BRACK "]"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ SLICE_PAT
+ L_BRACK "["
+ IDENT_PAT
+ NAME
+ IDENT "head"
+ COMMA ","
+ WHITESPACE " "
+ REST_PAT
+ DOT2 ".."
+ COMMA ","
+ WHITESPACE " "
+ REST_PAT
+ DOT2 ".."
+ COMMA ","
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "cons"
+ R_BRACK "]"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ SLICE_PAT
+ L_BRACK "["
+ IDENT_PAT
+ NAME
+ IDENT "head"
+ COMMA ","
+ WHITESPACE " "
+ REST_PAT
+ DOT2 ".."
+ COMMA ","
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "mid"
+ COMMA ","
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "tail"
+ WHITESPACE " "
+ AT "@"
+ WHITESPACE " "
+ REST_PAT
+ DOT2 ".."
+ R_BRACK "]"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ SLICE_PAT
+ L_BRACK "["
+ IDENT_PAT
+ NAME
+ IDENT "head"
+ COMMA ","
+ WHITESPACE " "
+ REST_PAT
+ DOT2 ".."
+ COMMA ","
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "mid"
+ COMMA ","
+ WHITESPACE " "
+ REST_PAT
+ DOT2 ".."
+ COMMA ","
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "cons"
+ R_BRACK "]"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0144_dot_dot_pat.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0144_dot_dot_pat.rs
new file mode 100644
index 000000000..3262f27e1
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0144_dot_dot_pat.rs
@@ -0,0 +1,25 @@
+fn main() {
+ let .. = ();
+ //
+ // Tuples
+ //
+ let (a, ..) = ();
+ let (a, ..,) = ();
+ let Tuple(a, ..) = ();
+ let Tuple(a, ..,) = ();
+ let (.., ..) = ();
+ let Tuple(.., ..) = ();
+ let (.., a, ..) = ();
+ let Tuple(.., a, ..) = ();
+ //
+ // Slices
+ //
+ let [..] = ();
+ let [head, ..] = ();
+ let [head, tail @ ..] = ();
+ let [head, .., cons] = ();
+ let [head, mid @ .., cons] = ();
+ let [head, .., .., cons] = ();
+ let [head, .., mid, tail @ ..] = ();
+ let [head, .., mid, .., cons] = ();
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0145_record_pat_field.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0145_record_pat_field.rast
new file mode 100644
index 000000000..f3d2fde46
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0145_record_pat_field.rast
@@ -0,0 +1,123 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ RECORD_PAT
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_PAT_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ RECORD_PAT_FIELD
+ NAME_REF
+ INT_NUMBER "0"
+ COLON ":"
+ WHITESPACE " "
+ LITERAL_PAT
+ LITERAL
+ INT_NUMBER "1"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ RECORD_PAT
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_PAT_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ RECORD_PAT_FIELD
+ NAME_REF
+ IDENT "x"
+ COLON ":"
+ WHITESPACE " "
+ LITERAL_PAT
+ LITERAL
+ INT_NUMBER "1"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ RECORD_PAT
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_PAT_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ RECORD_PAT_FIELD
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "cfg"
+ TOKEN_TREE
+ L_PAREN "("
+ IDENT "any"
+ TOKEN_TREE
+ L_PAREN "("
+ R_PAREN ")"
+ R_PAREN ")"
+ R_BRACK "]"
+ WHITESPACE " "
+ NAME_REF
+ IDENT "x"
+ COLON ":"
+ WHITESPACE " "
+ LITERAL_PAT
+ LITERAL
+ INT_NUMBER "1"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0145_record_pat_field.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0145_record_pat_field.rs
new file mode 100644
index 000000000..53cfdc22d
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0145_record_pat_field.rs
@@ -0,0 +1,5 @@
+fn foo() {
+ let S { 0: 1 } = ();
+ let S { x: 1 } = ();
+ let S { #[cfg(any())] x: 1 } = ();
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0146_as_precedence.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0146_as_precedence.rast
new file mode 100644
index 000000000..4079d2a99
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0146_as_precedence.rast
@@ -0,0 +1,43 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "f"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ CAST_EXPR
+ REF_EXPR
+ AMP "&"
+ LITERAL
+ INT_NUMBER "1"
+ WHITESPACE " "
+ AS_KW "as"
+ WHITESPACE " "
+ PTR_TYPE
+ STAR "*"
+ CONST_KW "const"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ SEMICOLON ";"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0146_as_precedence.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0146_as_precedence.rs
new file mode 100644
index 000000000..70559c5ef
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0146_as_precedence.rs
@@ -0,0 +1 @@
+fn f() { let _ = &1 as *const i32; }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0147_const_param.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0147_const_param.rast
new file mode 100644
index 000000000..24595a1a1
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0147_const_param.rast
@@ -0,0 +1,23 @@
+SOURCE_FILE
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ CONST_PARAM
+ CONST_KW "const"
+ WHITESPACE " "
+ NAME
+ IDENT "N"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u32"
+ R_ANGLE ">"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0147_const_param.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0147_const_param.rs
new file mode 100644
index 000000000..8cdb3b703
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0147_const_param.rs
@@ -0,0 +1 @@
+struct S<const N: u32>;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0147_macro_def.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0147_macro_def.rast
new file mode 100644
index 000000000..01de13a90
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0147_macro_def.rast
@@ -0,0 +1,19 @@
+SOURCE_FILE
+ MACRO_DEF
+ MACRO_KW "macro"
+ WHITESPACE " "
+ NAME
+ IDENT "m"
+ TOKEN_TREE
+ TOKEN_TREE
+ L_PAREN "("
+ DOLLAR "$"
+ IDENT "i"
+ COLON ":"
+ IDENT "ident"
+ R_PAREN ")"
+ WHITESPACE " "
+ TOKEN_TREE
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0147_macro_def.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0147_macro_def.rs
new file mode 100644
index 000000000..a014ae546
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0147_macro_def.rs
@@ -0,0 +1 @@
+macro m($i:ident) {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0150_array_attrs.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0150_array_attrs.rast
new file mode 100644
index 000000000..6eb8af331
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0150_array_attrs.rast
@@ -0,0 +1,48 @@
+SOURCE_FILE
+ CONST
+ CONST_KW "const"
+ WHITESPACE " "
+ NAME
+ IDENT "A"
+ COLON ":"
+ WHITESPACE " "
+ REF_TYPE
+ AMP "&"
+ SLICE_TYPE
+ L_BRACK "["
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i64"
+ R_BRACK "]"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ REF_EXPR
+ AMP "&"
+ ARRAY_EXPR
+ L_BRACK "["
+ LITERAL
+ INT_NUMBER "1"
+ COMMA ","
+ WHITESPACE " "
+ LITERAL
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "cfg"
+ TOKEN_TREE
+ L_PAREN "("
+ IDENT "test"
+ R_PAREN ")"
+ R_BRACK "]"
+ WHITESPACE " "
+ INT_NUMBER "2"
+ R_BRACK "]"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0150_array_attrs.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0150_array_attrs.rs
new file mode 100644
index 000000000..2ac310924
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0150_array_attrs.rs
@@ -0,0 +1 @@
+const A: &[i64] = &[1, #[cfg(test)] 2];
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0150_impl_type_params.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0150_impl_type_params.rast
new file mode 100644
index 000000000..24977a22a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0150_impl_type_params.rast
@@ -0,0 +1,38 @@
+SOURCE_FILE
+ IMPL
+ IMPL_KW "impl"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ CONST_PARAM
+ CONST_KW "const"
+ WHITESPACE " "
+ NAME
+ IDENT "N"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u32"
+ R_ANGLE ">"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Bar"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ TYPE_ARG
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "N"
+ R_ANGLE ">"
+ WHITESPACE " "
+ ASSOC_ITEM_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0150_impl_type_params.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0150_impl_type_params.rs
new file mode 100644
index 000000000..cb0a105c2
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0150_impl_type_params.rs
@@ -0,0 +1 @@
+impl<const N: u32> Bar<N> {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0151_fn.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0151_fn.rast
new file mode 100644
index 000000000..a88b3393f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0151_fn.rast
@@ -0,0 +1,15 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0151_fn.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0151_fn.rs
new file mode 100644
index 000000000..8f3b7ef11
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0151_fn.rs
@@ -0,0 +1 @@
+fn foo() {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0151_trait_alias.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0151_trait_alias.rast
new file mode 100644
index 000000000..2ef66484a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0151_trait_alias.rast
@@ -0,0 +1,33 @@
+SOURCE_FILE
+ TRAIT
+ TRAIT_KW "trait"
+ WHITESPACE " "
+ NAME
+ IDENT "Z"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "U"
+ R_ANGLE ">"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "T"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ TYPE_ARG
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "U"
+ R_ANGLE ">"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0151_trait_alias.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0151_trait_alias.rs
new file mode 100644
index 000000000..71d76789f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0151_trait_alias.rs
@@ -0,0 +1 @@
+trait Z<U> = T<U>;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0152_arg_with_attr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0152_arg_with_attr.rast
new file mode 100644
index 000000000..ae1074c36
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0152_arg_with_attr.rast
@@ -0,0 +1,38 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "foo"
+ ARG_LIST
+ L_PAREN "("
+ LITERAL
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "attr"
+ R_BRACK "]"
+ WHITESPACE " "
+ INT_NUMBER "92"
+ R_PAREN ")"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0152_arg_with_attr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0152_arg_with_attr.rs
new file mode 100644
index 000000000..5daf1d7b0
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0152_arg_with_attr.rs
@@ -0,0 +1,3 @@
+fn main() {
+ foo(#[attr] 92)
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0153_pub_parens_typepath.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0153_pub_parens_typepath.rast
new file mode 100644
index 000000000..2dede8359
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0153_pub_parens_typepath.rast
@@ -0,0 +1,56 @@
+SOURCE_FILE
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "B"
+ TUPLE_FIELD_LIST
+ L_PAREN "("
+ TUPLE_FIELD
+ VISIBILITY
+ PUB_KW "pub"
+ WHITESPACE " "
+ PAREN_TYPE
+ L_PAREN "("
+ PATH_TYPE
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ SUPER_KW "super"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "A"
+ R_PAREN ")"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "B"
+ TUPLE_FIELD_LIST
+ L_PAREN "("
+ TUPLE_FIELD
+ VISIBILITY
+ PUB_KW "pub"
+ WHITESPACE " "
+ TUPLE_TYPE
+ L_PAREN "("
+ PATH_TYPE
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ CRATE_KW "crate"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "A"
+ COMMA ","
+ R_PAREN ")"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0153_pub_parens_typepath.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0153_pub_parens_typepath.rs
new file mode 100644
index 000000000..d4c163822
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0153_pub_parens_typepath.rs
@@ -0,0 +1,2 @@
+struct B(pub (super::A));
+struct B(pub (crate::A,));
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0154_fn_pointer_param_ident_path.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0154_fn_pointer_param_ident_path.rast
new file mode 100644
index 000000000..ee8465e6c
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0154_fn_pointer_param_ident_path.rast
@@ -0,0 +1,58 @@
+SOURCE_FILE
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "Foo"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ FN_PTR_TYPE
+ FN_KW "fn"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ PATH_TYPE
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Bar"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Baz"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "Qux"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ FN_PTR_TYPE
+ FN_KW "fn"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "baz"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Bar"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Baz"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0154_fn_pointer_param_ident_path.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0154_fn_pointer_param_ident_path.rs
new file mode 100644
index 000000000..80a1701fd
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0154_fn_pointer_param_ident_path.rs
@@ -0,0 +1,2 @@
+type Foo = fn(Bar::Baz);
+type Qux = fn(baz: Bar::Baz);
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rast
new file mode 100644
index 000000000..30a2842e5
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rast
@@ -0,0 +1,43 @@
+SOURCE_FILE
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "A"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ DYN_TRAIT_TYPE
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ FOR_TYPE
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Test"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ LIFETIME_ARG
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Send"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rs
new file mode 100644
index 000000000..47a71fd19
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0154_no_dyn_trait_leading_for.rs
@@ -0,0 +1 @@
+type A = for<'a> Test<'a> + Send;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0154_tuple_attrs.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0154_tuple_attrs.rast
new file mode 100644
index 000000000..39857b23c
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0154_tuple_attrs.rast
@@ -0,0 +1,51 @@
+SOURCE_FILE
+ CONST
+ CONST_KW "const"
+ WHITESPACE " "
+ NAME
+ IDENT "A"
+ COLON ":"
+ WHITESPACE " "
+ TUPLE_TYPE
+ L_PAREN "("
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i64"
+ COMMA ","
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i64"
+ R_PAREN ")"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ LITERAL
+ INT_NUMBER "1"
+ COMMA ","
+ WHITESPACE " "
+ LITERAL
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "cfg"
+ TOKEN_TREE
+ L_PAREN "("
+ IDENT "test"
+ R_PAREN ")"
+ R_BRACK "]"
+ WHITESPACE " "
+ INT_NUMBER "2"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0154_tuple_attrs.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0154_tuple_attrs.rs
new file mode 100644
index 000000000..f84b7ab31
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0154_tuple_attrs.rs
@@ -0,0 +1 @@
+const A: (i64, i64) = (1, #[cfg(test)] 2);
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0155_closure_params.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0155_closure_params.rast
new file mode 100644
index 000000000..318eb89de
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0155_closure_params.rast
@@ -0,0 +1,70 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "foo"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ CLOSURE_EXPR
+ PARAM_LIST
+ PIPE "|"
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "bar"
+ COMMA ","
+ WHITESPACE " "
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "baz"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Baz"
+ COMMA ","
+ WHITESPACE " "
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "qux"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Qux"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Quux"
+ PIPE "|"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0155_closure_params.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0155_closure_params.rs
new file mode 100644
index 000000000..6ca8dd2d6
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0155_closure_params.rs
@@ -0,0 +1,3 @@
+fn main() {
+ let foo = |bar, baz: Baz, qux: Qux::Quux| ();
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0156_const_block_pat.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0156_const_block_pat.rast
new file mode 100644
index 000000000..59de2b9f1
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0156_const_block_pat.rast
@@ -0,0 +1,79 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ CONST_BLOCK_PAT
+ CONST_KW "const"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "15"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ CONST_BLOCK_PAT
+ CONST_KW "const"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ EXPR_STMT
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "foo"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE " "
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "bar"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0156_const_block_pat.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0156_const_block_pat.rs
new file mode 100644
index 000000000..dce9defac
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0156_const_block_pat.rs
@@ -0,0 +1,4 @@
+fn main() {
+ let const { 15 } = ();
+ let const { foo(); bar() } = ();
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0156_fn_def_param.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0156_fn_def_param.rast
new file mode 100644
index 000000000..ce425a1af
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0156_fn_def_param.rast
@@ -0,0 +1,48 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ DOT3 "..."
+ COMMA ","
+ WHITESPACE " "
+ PARAM
+ TUPLE_PAT
+ L_PAREN "("
+ IDENT_PAT
+ NAME
+ IDENT "x"
+ COMMA ","
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "y"
+ R_PAREN ")"
+ COLON ":"
+ WHITESPACE " "
+ TUPLE_TYPE
+ L_PAREN "("
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ COMMA ","
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ R_PAREN ")"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0156_fn_def_param.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0156_fn_def_param.rs
new file mode 100644
index 000000000..7b4c62658
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0156_fn_def_param.rs
@@ -0,0 +1 @@
+fn foo(..., (x, y): (i32, i32)) {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0156_or_pattern.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0156_or_pattern.rast
new file mode 100644
index 000000000..6a2046d9e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0156_or_pattern.rast
@@ -0,0 +1,112 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ MATCH_EXPR
+ MATCH_KW "match"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ MATCH_ARM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ MATCH_ARM
+ PAREN_PAT
+ L_PAREN "("
+ OR_PAT
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ PIPE "|"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ R_PAREN ")"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n "
+ MATCH_ARM
+ REF_PAT
+ AMP "&"
+ PAREN_PAT
+ L_PAREN "("
+ OR_PAT
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ PIPE "|"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ R_PAREN ")"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n "
+ MATCH_ARM
+ TUPLE_PAT
+ L_PAREN "("
+ OR_PAT
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ PIPE "|"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ COMMA ","
+ R_PAREN ")"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n "
+ MATCH_ARM
+ SLICE_PAT
+ L_BRACK "["
+ OR_PAT
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ PIPE "|"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ COMMA ","
+ R_BRACK "]"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0156_or_pattern.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0156_or_pattern.rs
new file mode 100644
index 000000000..a26316605
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0156_or_pattern.rs
@@ -0,0 +1,8 @@
+fn main() {
+ match () {
+ (_ | _) => (),
+ &(_ | _) => (),
+ (_ | _,) => (),
+ [_ | _,] => (),
+ }
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0157_fn_pointer_unnamed_arg.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0157_fn_pointer_unnamed_arg.rast
new file mode 100644
index 000000000..8a525c6e0
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0157_fn_pointer_unnamed_arg.rast
@@ -0,0 +1,26 @@
+SOURCE_FILE
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "Foo"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ FN_PTR_TYPE
+ FN_KW "fn"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "bar"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0157_fn_pointer_unnamed_arg.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0157_fn_pointer_unnamed_arg.rs
new file mode 100644
index 000000000..1ebbe5b03
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0157_fn_pointer_unnamed_arg.rs
@@ -0,0 +1 @@
+type Foo = fn(_: bar);
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0157_variant_discriminant.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0157_variant_discriminant.rast
new file mode 100644
index 000000000..9f0c5a761
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0157_variant_discriminant.rast
@@ -0,0 +1,30 @@
+SOURCE_FILE
+ ENUM
+ ENUM_KW "enum"
+ WHITESPACE " "
+ NAME
+ IDENT "E"
+ WHITESPACE " "
+ VARIANT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ VARIANT
+ NAME
+ IDENT "X"
+ TUPLE_FIELD_LIST
+ L_PAREN "("
+ TUPLE_FIELD
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ R_PAREN ")"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "10"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0157_variant_discriminant.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0157_variant_discriminant.rs
new file mode 100644
index 000000000..c8c5c0f17
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0157_variant_discriminant.rs
@@ -0,0 +1 @@
+enum E { X(i32) = 10 }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0158_binop_resets_statementness.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0158_binop_resets_statementness.rast
new file mode 100644
index 000000000..f667c1972
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0158_binop_resets_statementness.rast
@@ -0,0 +1,38 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "f"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ EXPR_STMT
+ BIN_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "v"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ BIN_EXPR
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ LITERAL
+ INT_NUMBER "1"
+ R_CURLY "}"
+ AMP "&"
+ LITERAL
+ INT_NUMBER "2"
+ SEMICOLON ";"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0158_binop_resets_statementness.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0158_binop_resets_statementness.rs
new file mode 100644
index 000000000..e325e4667
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0158_binop_resets_statementness.rs
@@ -0,0 +1 @@
+fn f() { v = {1}&2; }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0158_lambda_ret_block.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0158_lambda_ret_block.rast
new file mode 100644
index 000000000..93238bd8f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0158_lambda_ret_block.rast
@@ -0,0 +1,45 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ EXPR_STMT
+ CALL_EXPR
+ CLOSURE_EXPR
+ PARAM_LIST
+ PIPE "|"
+ PIPE "|"
+ WHITESPACE " "
+ RET_TYPE
+ THIN_ARROW "->"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "92"
+ WHITESPACE " "
+ R_CURLY "}"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0158_lambda_ret_block.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0158_lambda_ret_block.rs
new file mode 100644
index 000000000..061118d3a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0158_lambda_ret_block.rs
@@ -0,0 +1 @@
+fn main() { || -> i32 { 92 }(); }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0158_macro_rules_non_brace.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0158_macro_rules_non_brace.rast
new file mode 100644
index 000000000..45cd4d2aa
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0158_macro_rules_non_brace.rast
@@ -0,0 +1,57 @@
+SOURCE_FILE
+ MACRO_RULES
+ MACRO_RULES_KW "macro_rules"
+ BANG "!"
+ WHITESPACE " "
+ NAME
+ IDENT "m"
+ WHITESPACE " "
+ TOKEN_TREE
+ L_PAREN "("
+ WHITESPACE " "
+ TOKEN_TREE
+ L_PAREN "("
+ DOLLAR "$"
+ IDENT "i"
+ COLON ":"
+ IDENT "ident"
+ R_PAREN ")"
+ WHITESPACE " "
+ EQ "="
+ R_ANGLE ">"
+ WHITESPACE " "
+ TOKEN_TREE
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE " "
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ MACRO_RULES
+ MACRO_RULES_KW "macro_rules"
+ BANG "!"
+ WHITESPACE " "
+ NAME
+ IDENT "m"
+ WHITESPACE " "
+ TOKEN_TREE
+ L_BRACK "["
+ WHITESPACE " "
+ TOKEN_TREE
+ L_PAREN "("
+ DOLLAR "$"
+ IDENT "i"
+ COLON ":"
+ IDENT "ident"
+ R_PAREN ")"
+ WHITESPACE " "
+ EQ "="
+ R_ANGLE ">"
+ WHITESPACE " "
+ TOKEN_TREE
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE " "
+ R_BRACK "]"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0158_macro_rules_non_brace.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0158_macro_rules_non_brace.rs
new file mode 100644
index 000000000..6033a28cd
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0158_macro_rules_non_brace.rs
@@ -0,0 +1,2 @@
+macro_rules! m ( ($i:ident) => {} );
+macro_rules! m [ ($i:ident) => {} ];
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0159_try_macro_fallback.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0159_try_macro_fallback.rast
new file mode 100644
index 000000000..0adb678fa
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0159_try_macro_fallback.rast
@@ -0,0 +1,36 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ EXPR_STMT
+ MACRO_EXPR
+ MACRO_CALL
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "try"
+ BANG "!"
+ TOKEN_TREE
+ L_PAREN "("
+ IDENT "Ok"
+ TOKEN_TREE
+ L_PAREN "("
+ TOKEN_TREE
+ L_PAREN "("
+ R_PAREN ")"
+ R_PAREN ")"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0159_try_macro_fallback.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0159_try_macro_fallback.rs
new file mode 100644
index 000000000..61a6b46a0
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0159_try_macro_fallback.rs
@@ -0,0 +1 @@
+fn foo() { try!(Ok(())); }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0159_yield_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0159_yield_expr.rast
new file mode 100644
index 000000000..31aa58de2
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0159_yield_expr.rast
@@ -0,0 +1,29 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ YIELD_EXPR
+ YIELD_KW "yield"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ YIELD_EXPR
+ YIELD_KW "yield"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "1"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0159_yield_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0159_yield_expr.rs
new file mode 100644
index 000000000..596e221f7
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0159_yield_expr.rs
@@ -0,0 +1,4 @@
+fn foo() {
+ yield;
+ yield 1;
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0160_crate_visibility_in.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0160_crate_visibility_in.rast
new file mode 100644
index 000000000..ac45c5695
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0160_crate_visibility_in.rast
@@ -0,0 +1,42 @@
+SOURCE_FILE
+ STRUCT
+ VISIBILITY
+ PUB_KW "pub"
+ L_PAREN "("
+ IN_KW "in"
+ WHITESPACE " "
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ SUPER_KW "super"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "A"
+ R_PAREN ")"
+ WHITESPACE " "
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ STRUCT
+ VISIBILITY
+ PUB_KW "pub"
+ L_PAREN "("
+ IN_KW "in"
+ WHITESPACE " "
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ CRATE_KW "crate"
+ R_PAREN ")"
+ WHITESPACE " "
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0160_crate_visibility_in.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0160_crate_visibility_in.rs
new file mode 100644
index 000000000..2856dbd84
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0160_crate_visibility_in.rs
@@ -0,0 +1,2 @@
+pub(in super::A) struct S;
+pub(in crate) struct S;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0160_try_macro_rules.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0160_try_macro_rules.rast
new file mode 100644
index 000000000..e6916ae97
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0160_try_macro_rules.rast
@@ -0,0 +1,24 @@
+SOURCE_FILE
+ MACRO_RULES
+ MACRO_RULES_KW "macro_rules"
+ BANG "!"
+ WHITESPACE " "
+ NAME
+ IDENT "try"
+ WHITESPACE " "
+ TOKEN_TREE
+ L_CURLY "{"
+ WHITESPACE " "
+ TOKEN_TREE
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ EQ "="
+ R_ANGLE ">"
+ WHITESPACE " "
+ TOKEN_TREE
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0160_try_macro_rules.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0160_try_macro_rules.rs
new file mode 100644
index 000000000..2e2ab6e60
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0160_try_macro_rules.rs
@@ -0,0 +1 @@
+macro_rules! try { () => {} }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0161_impl_item_const.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0161_impl_item_const.rast
new file mode 100644
index 000000000..f7c7aaabc
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0161_impl_item_const.rast
@@ -0,0 +1,24 @@
+SOURCE_FILE
+ IMPL
+ IMPL_KW "impl"
+ WHITESPACE " "
+ CONST_KW "const"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Send"
+ WHITESPACE " "
+ FOR_KW "for"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ WHITESPACE " "
+ ASSOC_ITEM_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0161_impl_item_const.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0161_impl_item_const.rs
new file mode 100644
index 000000000..3252d6f36
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0161_impl_item_const.rs
@@ -0,0 +1 @@
+impl const Send for S {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0161_labeled_block.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0161_labeled_block.rast
new file mode 100644
index 000000000..181251d4f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0161_labeled_block.rast
@@ -0,0 +1,28 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "f"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ EXPR_STMT
+ BLOCK_EXPR
+ LABEL
+ LIFETIME
+ LIFETIME_IDENT "'label"
+ COLON ":"
+ WHITESPACE " "
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0161_labeled_block.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0161_labeled_block.rs
new file mode 100644
index 000000000..18b4ff4b1
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0161_labeled_block.rs
@@ -0,0 +1 @@
+fn f() { 'label: {}; }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0162_default_async_unsafe_fn.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0162_default_async_unsafe_fn.rast
new file mode 100644
index 000000000..7c2f7b34c
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0162_default_async_unsafe_fn.rast
@@ -0,0 +1,43 @@
+SOURCE_FILE
+ IMPL
+ IMPL_KW "impl"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "T"
+ WHITESPACE " "
+ FOR_KW "for"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Foo"
+ WHITESPACE " "
+ ASSOC_ITEM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ FN
+ DEFAULT_KW "default"
+ WHITESPACE " "
+ ASYNC_KW "async"
+ WHITESPACE " "
+ UNSAFE_KW "unsafe"
+ WHITESPACE " "
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0162_default_async_unsafe_fn.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0162_default_async_unsafe_fn.rs
new file mode 100644
index 000000000..05c20a68f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0162_default_async_unsafe_fn.rs
@@ -0,0 +1,3 @@
+impl T for Foo {
+ default async unsafe fn foo() {}
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0163_default_async_fn.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0163_default_async_fn.rast
new file mode 100644
index 000000000..06b37e239
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0163_default_async_fn.rast
@@ -0,0 +1,41 @@
+SOURCE_FILE
+ IMPL
+ IMPL_KW "impl"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "T"
+ WHITESPACE " "
+ FOR_KW "for"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Foo"
+ WHITESPACE " "
+ ASSOC_ITEM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ FN
+ DEFAULT_KW "default"
+ WHITESPACE " "
+ ASYNC_KW "async"
+ WHITESPACE " "
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0163_default_async_fn.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0163_default_async_fn.rs
new file mode 100644
index 000000000..78c3b4d85
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0163_default_async_fn.rs
@@ -0,0 +1,3 @@
+impl T for Foo {
+ default async fn foo() {}
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0163_default_unsafe_item.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0163_default_unsafe_item.rast
new file mode 100644
index 000000000..b180d0b72
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0163_default_unsafe_item.rast
@@ -0,0 +1,45 @@
+SOURCE_FILE
+ IMPL
+ DEFAULT_KW "default"
+ WHITESPACE " "
+ UNSAFE_KW "unsafe"
+ WHITESPACE " "
+ IMPL_KW "impl"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "T"
+ WHITESPACE " "
+ FOR_KW "for"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Foo"
+ WHITESPACE " "
+ ASSOC_ITEM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ FN
+ DEFAULT_KW "default"
+ WHITESPACE " "
+ UNSAFE_KW "unsafe"
+ WHITESPACE " "
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0163_default_unsafe_item.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0163_default_unsafe_item.rs
new file mode 100644
index 000000000..96340f84a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0163_default_unsafe_item.rs
@@ -0,0 +1,3 @@
+default unsafe impl T for Foo {
+ default unsafe fn foo() {}
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0164_default_item.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0164_default_item.rast
new file mode 100644
index 000000000..7a8e8cf1d
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0164_default_item.rast
@@ -0,0 +1,24 @@
+SOURCE_FILE
+ IMPL
+ DEFAULT_KW "default"
+ WHITESPACE " "
+ IMPL_KW "impl"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "T"
+ WHITESPACE " "
+ FOR_KW "for"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Foo"
+ WHITESPACE " "
+ ASSOC_ITEM_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0164_default_item.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0164_default_item.rs
new file mode 100644
index 000000000..a6836cbd5
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0164_default_item.rs
@@ -0,0 +1 @@
+default impl T for Foo {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0164_type_path_in_pattern.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0164_type_path_in_pattern.rast
new file mode 100644
index 000000000..297f7575c
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0164_type_path_in_pattern.rast
@@ -0,0 +1,39 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ PATH_PAT
+ PATH
+ PATH
+ PATH_SEGMENT
+ L_ANGLE "<"
+ INFER_TYPE
+ UNDERSCORE "_"
+ R_ANGLE ">"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Foo"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0164_type_path_in_pattern.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0164_type_path_in_pattern.rs
new file mode 100644
index 000000000..ebe26834d
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0164_type_path_in_pattern.rs
@@ -0,0 +1 @@
+fn main() { let <_>::Foo = (); }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0166_half_open_range_pat.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0166_half_open_range_pat.rast
new file mode 100644
index 000000000..3d3587a70
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0166_half_open_range_pat.rast
@@ -0,0 +1,32 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "f"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ RANGE_PAT
+ LITERAL_PAT
+ LITERAL
+ INT_NUMBER "0"
+ WHITESPACE " "
+ DOT2 ".."
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "1u32"
+ SEMICOLON ";"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0166_half_open_range_pat.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0166_half_open_range_pat.rs
new file mode 100644
index 000000000..1360eda05
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0166_half_open_range_pat.rs
@@ -0,0 +1 @@
+fn f() { let 0 .. = 1u32; }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0168_extern_crate_rename.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0168_extern_crate_rename.rast
new file mode 100644
index 000000000..5a5aca96f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0168_extern_crate_rename.rast
@@ -0,0 +1,16 @@
+SOURCE_FILE
+ EXTERN_CRATE
+ EXTERN_KW "extern"
+ WHITESPACE " "
+ CRATE_KW "crate"
+ WHITESPACE " "
+ NAME_REF
+ IDENT "foo"
+ WHITESPACE " "
+ RENAME
+ AS_KW "as"
+ WHITESPACE " "
+ NAME
+ IDENT "bar"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0168_extern_crate_rename.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0168_extern_crate_rename.rs
new file mode 100644
index 000000000..fc76e17dd
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0168_extern_crate_rename.rs
@@ -0,0 +1 @@
+extern crate foo as bar;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0168_extern_crate_self.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0168_extern_crate_self.rast
new file mode 100644
index 000000000..edea4245f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0168_extern_crate_self.rast
@@ -0,0 +1,10 @@
+SOURCE_FILE
+ EXTERN_CRATE
+ EXTERN_KW "extern"
+ WHITESPACE " "
+ CRATE_KW "crate"
+ WHITESPACE " "
+ NAME_REF
+ SELF_KW "self"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0168_extern_crate_self.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0168_extern_crate_self.rs
new file mode 100644
index 000000000..c969ed109
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0168_extern_crate_self.rs
@@ -0,0 +1 @@
+extern crate self;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0169_mod_item.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0169_mod_item.rast
new file mode 100644
index 000000000..4d505916c
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0169_mod_item.rast
@@ -0,0 +1,8 @@
+SOURCE_FILE
+ MODULE
+ MOD_KW "mod"
+ WHITESPACE " "
+ NAME
+ IDENT "a"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0169_mod_item.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0169_mod_item.rs
new file mode 100644
index 000000000..f21af614d
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0169_mod_item.rs
@@ -0,0 +1 @@
+mod a;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0170_mod_item_curly.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0170_mod_item_curly.rast
new file mode 100644
index 000000000..d5e3f3493
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0170_mod_item_curly.rast
@@ -0,0 +1,12 @@
+SOURCE_FILE
+ MODULE
+ MOD_KW "mod"
+ WHITESPACE " "
+ NAME
+ IDENT "b"
+ WHITESPACE " "
+ ITEM_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0170_mod_item_curly.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0170_mod_item_curly.rs
new file mode 100644
index 000000000..16b1b43e8
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0170_mod_item_curly.rs
@@ -0,0 +1 @@
+mod b { }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0170_tuple_struct.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0170_tuple_struct.rast
new file mode 100644
index 000000000..6e5f6c2d2
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0170_tuple_struct.rast
@@ -0,0 +1,25 @@
+SOURCE_FILE
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S"
+ TUPLE_FIELD_LIST
+ L_PAREN "("
+ TUPLE_FIELD
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "String"
+ COMMA ","
+ WHITESPACE " "
+ TUPLE_FIELD
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "usize"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0170_tuple_struct.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0170_tuple_struct.rs
new file mode 100644
index 000000000..b4e05717e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0170_tuple_struct.rs
@@ -0,0 +1 @@
+struct S(String, usize);
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0171_struct_item.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0171_struct_item.rast
new file mode 100644
index 000000000..78f968207
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0171_struct_item.rast
@@ -0,0 +1,11 @@
+SOURCE_FILE
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_FIELD_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0171_struct_item.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0171_struct_item.rs
new file mode 100644
index 000000000..5f1a34f49
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0171_struct_item.rs
@@ -0,0 +1 @@
+struct S {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0172_const_item.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0172_const_item.rast
new file mode 100644
index 000000000..909983c9a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0172_const_item.rast
@@ -0,0 +1,20 @@
+SOURCE_FILE
+ CONST
+ CONST_KW "const"
+ WHITESPACE " "
+ NAME
+ IDENT "C"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u32"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "92"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0172_const_item.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0172_const_item.rs
new file mode 100644
index 000000000..6d5f5be65
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0172_const_item.rs
@@ -0,0 +1 @@
+const C: u32 = 92;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0172_record_field_list.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0172_record_field_list.rast
new file mode 100644
index 000000000..065d7e7e8
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0172_record_field_list.rast
@@ -0,0 +1,35 @@
+SOURCE_FILE
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ RECORD_FIELD
+ NAME
+ IDENT "a"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ COMMA ","
+ WHITESPACE " "
+ RECORD_FIELD
+ NAME
+ IDENT "b"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "f32"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0172_record_field_list.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0172_record_field_list.rs
new file mode 100644
index 000000000..a3bd7787d
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0172_record_field_list.rs
@@ -0,0 +1 @@
+struct S { a: i32, b: f32 }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0173_anonymous_const.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0173_anonymous_const.rast
new file mode 100644
index 000000000..d81b4ff26
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0173_anonymous_const.rast
@@ -0,0 +1,19 @@
+SOURCE_FILE
+ CONST
+ CONST_KW "const"
+ WHITESPACE " "
+ UNDERSCORE "_"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u32"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "0"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0173_anonymous_const.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0173_anonymous_const.rs
new file mode 100644
index 000000000..c1d5cdfc6
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0173_anonymous_const.rs
@@ -0,0 +1 @@
+const _: u32 = 0;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0173_macro_def_curly.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0173_macro_def_curly.rast
new file mode 100644
index 000000000..5cf305d26
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0173_macro_def_curly.rast
@@ -0,0 +1,27 @@
+SOURCE_FILE
+ MACRO_DEF
+ MACRO_KW "macro"
+ WHITESPACE " "
+ NAME
+ IDENT "m"
+ WHITESPACE " "
+ TOKEN_TREE
+ L_CURLY "{"
+ WHITESPACE " "
+ TOKEN_TREE
+ L_PAREN "("
+ DOLLAR "$"
+ IDENT "i"
+ COLON ":"
+ IDENT "ident"
+ R_PAREN ")"
+ WHITESPACE " "
+ EQ "="
+ R_ANGLE ">"
+ WHITESPACE " "
+ TOKEN_TREE
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0173_macro_def_curly.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0173_macro_def_curly.rs
new file mode 100644
index 000000000..5ed0c777d
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0173_macro_def_curly.rs
@@ -0,0 +1 @@
+macro m { ($i:ident) => {} }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0173_union_item.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0173_union_item.rast
new file mode 100644
index 000000000..af608fc4a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0173_union_item.rast
@@ -0,0 +1,35 @@
+SOURCE_FILE
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "U"
+ WHITESPACE " "
+ RECORD_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ RECORD_FIELD
+ NAME
+ IDENT "i"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ COMMA ","
+ WHITESPACE " "
+ RECORD_FIELD
+ NAME
+ IDENT "f"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "f32"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0173_union_item.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0173_union_item.rs
new file mode 100644
index 000000000..5edf50de3
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0173_union_item.rs
@@ -0,0 +1 @@
+struct U { i: i32, f: f32 }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0174_trait_item_generic_params.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0174_trait_item_generic_params.rast
new file mode 100644
index 000000000..01f212e71
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0174_trait_item_generic_params.rast
@@ -0,0 +1,35 @@
+SOURCE_FILE
+ TRAIT
+ TRAIT_KW "trait"
+ WHITESPACE " "
+ NAME
+ IDENT "X"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "U"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Debug"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Display"
+ R_ANGLE ">"
+ WHITESPACE " "
+ ASSOC_ITEM_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0174_trait_item_generic_params.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0174_trait_item_generic_params.rs
new file mode 100644
index 000000000..4a51926a6
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0174_trait_item_generic_params.rs
@@ -0,0 +1 @@
+trait X<U: Debug + Display> {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0174_unit_struct.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0174_unit_struct.rast
new file mode 100644
index 000000000..438dea6f4
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0174_unit_struct.rast
@@ -0,0 +1,8 @@
+SOURCE_FILE
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0174_unit_struct.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0174_unit_struct.rs
new file mode 100644
index 000000000..28377c276
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0174_unit_struct.rs
@@ -0,0 +1 @@
+struct S;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0174_use_tree_star.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0174_use_tree_star.rast
new file mode 100644
index 000000000..8662423f5
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0174_use_tree_star.rast
@@ -0,0 +1,24 @@
+SOURCE_FILE
+ USE
+ USE_KW "use"
+ WHITESPACE " "
+ USE_TREE
+ STAR "*"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ USE
+ USE_KW "use"
+ WHITESPACE " "
+ USE_TREE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "std"
+ COLON2 "::"
+ USE_TREE_LIST
+ L_CURLY "{"
+ USE_TREE
+ STAR "*"
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0174_use_tree_star.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0174_use_tree_star.rs
new file mode 100644
index 000000000..b8c613440
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0174_use_tree_star.rs
@@ -0,0 +1,2 @@
+use *;
+use std::{*};
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0175_trait_item_bounds.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0175_trait_item_bounds.rast
new file mode 100644
index 000000000..bab831456
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0175_trait_item_bounds.rast
@@ -0,0 +1,29 @@
+SOURCE_FILE
+ TRAIT
+ TRAIT_KW "trait"
+ WHITESPACE " "
+ NAME
+ IDENT "T"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Hash"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Clone"
+ WHITESPACE " "
+ ASSOC_ITEM_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0175_trait_item_bounds.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0175_trait_item_bounds.rs
new file mode 100644
index 000000000..e6ad2b56a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0175_trait_item_bounds.rs
@@ -0,0 +1 @@
+trait T: Hash + Clone {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0176_trait_item_where_clause.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0176_trait_item_where_clause.rast
new file mode 100644
index 000000000..46cd8ee66
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0176_trait_item_where_clause.rast
@@ -0,0 +1,30 @@
+SOURCE_FILE
+ TRAIT
+ TRAIT_KW "trait"
+ WHITESPACE " "
+ NAME
+ IDENT "T"
+ WHITESPACE " "
+ WHERE_CLAUSE
+ WHERE_KW "where"
+ WHITESPACE " "
+ WHERE_PRED
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ SELF_TYPE_KW "Self"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Copy"
+ WHITESPACE " "
+ ASSOC_ITEM_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0176_trait_item_where_clause.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0176_trait_item_where_clause.rs
new file mode 100644
index 000000000..52a6a806f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0176_trait_item_where_clause.rs
@@ -0,0 +1 @@
+trait T where Self: Copy {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0176_use_tree_alias.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0176_use_tree_alias.rast
new file mode 100644
index 000000000..ef0dd6ba1
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0176_use_tree_alias.rast
@@ -0,0 +1,32 @@
+SOURCE_FILE
+ USE
+ USE_KW "use"
+ WHITESPACE " "
+ USE_TREE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "std"
+ WHITESPACE " "
+ RENAME
+ AS_KW "as"
+ WHITESPACE " "
+ NAME
+ IDENT "stdlib"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ USE
+ USE_KW "use"
+ WHITESPACE " "
+ USE_TREE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Trait"
+ WHITESPACE " "
+ RENAME
+ AS_KW "as"
+ WHITESPACE " "
+ UNDERSCORE "_"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0176_use_tree_alias.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0176_use_tree_alias.rs
new file mode 100644
index 000000000..19a6906a2
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0176_use_tree_alias.rs
@@ -0,0 +1,2 @@
+use std as stdlib;
+use Trait as _;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_assoc_item_list_inner_attrs.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_assoc_item_list_inner_attrs.rast
new file mode 100644
index 000000000..9cb3c8a5c
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_assoc_item_list_inner_attrs.rast
@@ -0,0 +1,26 @@
+SOURCE_FILE
+ IMPL
+ IMPL_KW "impl"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ WHITESPACE " "
+ ASSOC_ITEM_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ ATTR
+ POUND "#"
+ BANG "!"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "attr"
+ R_BRACK "]"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_assoc_item_list_inner_attrs.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_assoc_item_list_inner_attrs.rs
new file mode 100644
index 000000000..915e2c932
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_assoc_item_list_inner_attrs.rs
@@ -0,0 +1 @@
+impl S { #![attr] }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_trait_alias_where_clause.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_trait_alias_where_clause.rast
new file mode 100644
index 000000000..4443d9d14
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_trait_alias_where_clause.rast
@@ -0,0 +1,96 @@
+SOURCE_FILE
+ TRAIT
+ TRAIT_KW "trait"
+ WHITESPACE " "
+ NAME
+ IDENT "Z"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "U"
+ R_ANGLE ">"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "T"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ TYPE_ARG
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "U"
+ R_ANGLE ">"
+ WHITESPACE " "
+ WHERE_CLAUSE
+ WHERE_KW "where"
+ WHITESPACE " "
+ WHERE_PRED
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "U"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Copy"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ TRAIT
+ TRAIT_KW "trait"
+ WHITESPACE " "
+ NAME
+ IDENT "Z"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "U"
+ R_ANGLE ">"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ WHERE_CLAUSE
+ WHERE_KW "where"
+ WHITESPACE " "
+ WHERE_PRED
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ SELF_TYPE_KW "Self"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "T"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ TYPE_ARG
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "U"
+ R_ANGLE ">"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_trait_alias_where_clause.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_trait_alias_where_clause.rs
new file mode 100644
index 000000000..a90d54b01
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_trait_alias_where_clause.rs
@@ -0,0 +1,2 @@
+trait Z<U> = T<U> where U: Copy;
+trait Z<U> = where Self: T<U>;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_use_tree.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_use_tree.rast
new file mode 100644
index 000000000..98231cdc2
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_use_tree.rast
@@ -0,0 +1,30 @@
+SOURCE_FILE
+ USE
+ USE_KW "use"
+ WHITESPACE " "
+ USE_TREE
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "outer"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "tree"
+ COLON2 "::"
+ USE_TREE_LIST
+ L_CURLY "{"
+ USE_TREE
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "inner"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "tree"
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_use_tree.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_use_tree.rs
new file mode 100644
index 000000000..3cc394348
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_use_tree.rs
@@ -0,0 +1 @@
+use outer::tree::{inner::tree};
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_use_tree_path.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_use_tree_path.rast
new file mode 100644
index 000000000..ede22dbaf
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_use_tree_path.rast
@@ -0,0 +1,72 @@
+SOURCE_FILE
+ USE
+ USE_KW "use"
+ WHITESPACE " "
+ USE_TREE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "std"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ USE
+ USE_KW "use"
+ WHITESPACE " "
+ USE_TREE
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "std"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "collections"
+ SEMICOLON ";"
+ WHITESPACE "\n\n"
+ USE
+ USE_KW "use"
+ WHITESPACE " "
+ USE_TREE
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ SELF_KW "self"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "m"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ USE
+ USE_KW "use"
+ WHITESPACE " "
+ USE_TREE
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ SUPER_KW "super"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "m"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ USE
+ USE_KW "use"
+ WHITESPACE " "
+ USE_TREE
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ CRATE_KW "crate"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "m"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_use_tree_path.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_use_tree_path.rs
new file mode 100644
index 000000000..5b22f8852
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0177_use_tree_path.rs
@@ -0,0 +1,6 @@
+use ::std;
+use std::collections;
+
+use self::m;
+use super::m;
+use crate::m;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0178_use_tree_path_use_tree.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0178_use_tree_path_use_tree.rast
new file mode 100644
index 000000000..ed3cafae1
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0178_use_tree_path_use_tree.rast
@@ -0,0 +1,20 @@
+SOURCE_FILE
+ USE
+ USE_KW "use"
+ WHITESPACE " "
+ USE_TREE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "std"
+ COLON2 "::"
+ USE_TREE_LIST
+ L_CURLY "{"
+ USE_TREE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "collections"
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0178_use_tree_path_use_tree.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0178_use_tree_path_use_tree.rs
new file mode 100644
index 000000000..c3086f51a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0178_use_tree_path_use_tree.rs
@@ -0,0 +1 @@
+use std::{collections};
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0179_use_tree_abs_star.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0179_use_tree_abs_star.rast
new file mode 100644
index 000000000..b4dc1f25d
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0179_use_tree_abs_star.rast
@@ -0,0 +1,26 @@
+SOURCE_FILE
+ USE
+ USE_KW "use"
+ WHITESPACE " "
+ USE_TREE
+ COLON2 "::"
+ STAR "*"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ USE
+ USE_KW "use"
+ WHITESPACE " "
+ USE_TREE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "std"
+ COLON2 "::"
+ USE_TREE_LIST
+ L_CURLY "{"
+ USE_TREE
+ COLON2 "::"
+ STAR "*"
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0179_use_tree_abs_star.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0179_use_tree_abs_star.rs
new file mode 100644
index 000000000..caae0ba02
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0179_use_tree_abs_star.rs
@@ -0,0 +1,2 @@
+use ::*;
+use std::{::*};
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0180_use_tree_path_star.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0180_use_tree_path_star.rast
new file mode 100644
index 000000000..d255adb5a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0180_use_tree_path_star.rast
@@ -0,0 +1,13 @@
+SOURCE_FILE
+ USE
+ USE_KW "use"
+ WHITESPACE " "
+ USE_TREE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "std"
+ COLON2 "::"
+ STAR "*"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0180_use_tree_path_star.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0180_use_tree_path_star.rs
new file mode 100644
index 000000000..dd601cffe
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0180_use_tree_path_star.rs
@@ -0,0 +1 @@
+use std::*;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0181_generic_param_attribute.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0181_generic_param_attribute.rast
new file mode 100644
index 000000000..28a216e87
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0181_generic_param_attribute.rast
@@ -0,0 +1,46 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "lt_attr"
+ R_BRACK "]"
+ WHITESPACE " "
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ COMMA ","
+ WHITESPACE " "
+ TYPE_PARAM
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "t_attr"
+ R_BRACK "]"
+ WHITESPACE " "
+ NAME
+ IDENT "T"
+ R_ANGLE ">"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0181_generic_param_attribute.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0181_generic_param_attribute.rs
new file mode 100644
index 000000000..0509f81da
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0181_generic_param_attribute.rs
@@ -0,0 +1 @@
+fn foo<#[lt_attr] 'a, #[t_attr] T>() {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0181_use_item.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0181_use_item.rast
new file mode 100644
index 000000000..25761ed8c
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0181_use_item.rast
@@ -0,0 +1,16 @@
+SOURCE_FILE
+ USE
+ USE_KW "use"
+ WHITESPACE " "
+ USE_TREE
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "std"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "collections"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0181_use_item.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0181_use_item.rs
new file mode 100644
index 000000000..48ac87b14
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0181_use_item.rs
@@ -0,0 +1 @@
+use std::collections;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0182_lifetime_param.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0182_lifetime_param.rast
new file mode 100644
index 000000000..c595031f3
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0182_lifetime_param.rast
@@ -0,0 +1,25 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "f"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ COLON ":"
+ WHITESPACE " "
+ LIFETIME
+ LIFETIME_IDENT "'b"
+ R_ANGLE ">"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0182_lifetime_param.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0182_lifetime_param.rs
new file mode 100644
index 000000000..2bb38ece8
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0182_lifetime_param.rs
@@ -0,0 +1 @@
+fn f<'a: 'b>() {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0183_const_arg_block.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0183_const_arg_block.rast
new file mode 100644
index 000000000..ea8866da2
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0183_const_arg_block.rast
@@ -0,0 +1,32 @@
+SOURCE_FILE
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "T"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ CONST_ARG
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ BIN_EXPR
+ LITERAL
+ INT_NUMBER "90"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "2"
+ R_CURLY "}"
+ R_ANGLE ">"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0183_const_arg_block.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0183_const_arg_block.rs
new file mode 100644
index 000000000..1c279db28
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0183_const_arg_block.rs
@@ -0,0 +1 @@
+type T = S<{90 + 2}>;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0183_type_param.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0183_type_param.rast
new file mode 100644
index 000000000..becb77e04
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0183_type_param.rast
@@ -0,0 +1,30 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "f"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "T"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Clone"
+ R_ANGLE ">"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0183_type_param.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0183_type_param.rs
new file mode 100644
index 000000000..b250bc6bf
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0183_type_param.rs
@@ -0,0 +1 @@
+fn f<T: Clone>() {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0184_const_arg.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0184_const_arg.rast
new file mode 100644
index 000000000..1e0300717
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0184_const_arg.rast
@@ -0,0 +1,22 @@
+SOURCE_FILE
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "T"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ CONST_ARG
+ LITERAL
+ INT_NUMBER "92"
+ R_ANGLE ">"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0184_const_arg.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0184_const_arg.rs
new file mode 100644
index 000000000..8b5e5dbe1
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0184_const_arg.rs
@@ -0,0 +1 @@
+type T = S<92>;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0184_generic_param_list.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0184_generic_param_list.rast
new file mode 100644
index 000000000..becb77e04
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0184_generic_param_list.rast
@@ -0,0 +1,30 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "f"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "T"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Clone"
+ R_ANGLE ">"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0184_generic_param_list.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0184_generic_param_list.rs
new file mode 100644
index 000000000..b250bc6bf
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0184_generic_param_list.rs
@@ -0,0 +1 @@
+fn f<T: Clone>() {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0185_assoc_type_bound.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0185_assoc_type_bound.rast
new file mode 100644
index 000000000..f2e4e0106
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0185_assoc_type_bound.rast
@@ -0,0 +1,37 @@
+SOURCE_FILE
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "T"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "StreamingIterator"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ ASSOC_TYPE_ARG
+ NAME_REF
+ IDENT "Item"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ LIFETIME_ARG
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Clone"
+ R_ANGLE ">"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0185_assoc_type_bound.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0185_assoc_type_bound.rs
new file mode 100644
index 000000000..daae97e4f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0185_assoc_type_bound.rs
@@ -0,0 +1 @@
+type T = StreamingIterator<Item<'a>: Clone>;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0186_lifetime_arg.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0186_lifetime_arg.rast
new file mode 100644
index 000000000..dbd7ff306
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0186_lifetime_arg.rast
@@ -0,0 +1,22 @@
+SOURCE_FILE
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "T"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ LIFETIME_ARG
+ LIFETIME
+ LIFETIME_IDENT "'static"
+ R_ANGLE ">"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0186_lifetime_arg.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0186_lifetime_arg.rs
new file mode 100644
index 000000000..41715aa27
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0186_lifetime_arg.rs
@@ -0,0 +1 @@
+type T = S<'static>;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0187_assoc_type_eq.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0187_assoc_type_eq.rast
new file mode 100644
index 000000000..970431840
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0187_assoc_type_eq.rast
@@ -0,0 +1,41 @@
+SOURCE_FILE
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "T"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "StreamingIterator"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ ASSOC_TYPE_ARG
+ NAME_REF
+ IDENT "Item"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ LIFETIME_ARG
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ REF_TYPE
+ AMP "&"
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "T"
+ R_ANGLE ">"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0187_assoc_type_eq.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0187_assoc_type_eq.rs
new file mode 100644
index 000000000..359141747
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0187_assoc_type_eq.rs
@@ -0,0 +1 @@
+type T = StreamingIterator<Item<'a> = &'a T>;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0188_const_param_default_path.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0188_const_param_default_path.rast
new file mode 100644
index 000000000..11002bf98
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0188_const_param_default_path.rast
@@ -0,0 +1,36 @@
+SOURCE_FILE
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "A"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ CONST_PARAM
+ CONST_KW "const"
+ WHITESPACE " "
+ NAME
+ IDENT "N"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ PATH_EXPR
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "MAX"
+ R_ANGLE ">"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0188_const_param_default_path.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0188_const_param_default_path.rs
new file mode 100644
index 000000000..f3da43ca0
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0188_const_param_default_path.rs
@@ -0,0 +1 @@
+struct A<const N: i32 = i32::MAX>;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0189_const_arg_literal.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0189_const_arg_literal.rast
new file mode 100644
index 000000000..03d414e33
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0189_const_arg_literal.rast
@@ -0,0 +1,27 @@
+SOURCE_FILE
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "T"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ CONST_ARG
+ LITERAL
+ STRING "\"hello\""
+ COMMA ","
+ WHITESPACE " "
+ CONST_ARG
+ LITERAL
+ INT_NUMBER "0xdeadbeef"
+ R_ANGLE ">"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0189_const_arg_literal.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0189_const_arg_literal.rs
new file mode 100644
index 000000000..7eacada73
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0189_const_arg_literal.rs
@@ -0,0 +1 @@
+type T = S<"hello", 0xdeadbeef>;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0190_generic_arg.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0190_generic_arg.rast
new file mode 100644
index 000000000..5a01f154b
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0190_generic_arg.rast
@@ -0,0 +1,25 @@
+SOURCE_FILE
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "T"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ TYPE_ARG
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ R_ANGLE ">"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0190_generic_arg.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0190_generic_arg.rs
new file mode 100644
index 000000000..f2ccc558b
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0190_generic_arg.rs
@@ -0,0 +1 @@
+type T = S<i32>;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0191_const_arg_negative_number.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0191_const_arg_negative_number.rast
new file mode 100644
index 000000000..e504badbd
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0191_const_arg_negative_number.rast
@@ -0,0 +1,24 @@
+SOURCE_FILE
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "T"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ CONST_ARG
+ PREFIX_EXPR
+ MINUS "-"
+ LITERAL
+ INT_NUMBER "92"
+ R_ANGLE ">"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0191_const_arg_negative_number.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0191_const_arg_negative_number.rs
new file mode 100644
index 000000000..d0a87bdc0
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0191_const_arg_negative_number.rs
@@ -0,0 +1 @@
+type T = S<-92>;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0192_const_arg_bool_literal.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0192_const_arg_bool_literal.rast
new file mode 100644
index 000000000..aea23e463
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0192_const_arg_bool_literal.rast
@@ -0,0 +1,22 @@
+SOURCE_FILE
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "T"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ CONST_ARG
+ LITERAL
+ TRUE_KW "true"
+ R_ANGLE ">"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0192_const_arg_bool_literal.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0192_const_arg_bool_literal.rs
new file mode 100644
index 000000000..4b92e2d48
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0192_const_arg_bool_literal.rs
@@ -0,0 +1 @@
+type T = S<true>;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0193_let_stmt_init.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0193_let_stmt_init.rast
new file mode 100644
index 000000000..1b6399158
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0193_let_stmt_init.rast
@@ -0,0 +1,29 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "f"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "x"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "92"
+ SEMICOLON ";"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0193_let_stmt_init.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0193_let_stmt_init.rs
new file mode 100644
index 000000000..232c0db41
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0193_let_stmt_init.rs
@@ -0,0 +1 @@
+fn f() { let x = 92; }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0194_let_else.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0194_let_else.rast
new file mode 100644
index 000000000..ce7f1a35e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0194_let_else.rast
@@ -0,0 +1,51 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "f"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ TUPLE_STRUCT_PAT
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Some"
+ L_PAREN "("
+ IDENT_PAT
+ NAME
+ IDENT "x"
+ R_PAREN ")"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "opt"
+ WHITESPACE " "
+ LET_ELSE
+ ELSE_KW "else"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ RETURN_EXPR
+ RETURN_KW "return"
+ WHITESPACE " "
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0194_let_else.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0194_let_else.rs
new file mode 100644
index 000000000..8303de06f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0194_let_else.rs
@@ -0,0 +1 @@
+fn f() { let Some(x) = opt else { return }; }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0194_let_stmt_ascription.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0194_let_stmt_ascription.rast
new file mode 100644
index 000000000..ac8e1d93c
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0194_let_stmt_ascription.rast
@@ -0,0 +1,31 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "f"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "x"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ SEMICOLON ";"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0194_let_stmt_ascription.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0194_let_stmt_ascription.rs
new file mode 100644
index 000000000..a94161dff
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0194_let_stmt_ascription.rs
@@ -0,0 +1 @@
+fn f() { let x: i32; }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0194_macro_inside_generic_arg.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0194_macro_inside_generic_arg.rast
new file mode 100644
index 000000000..88f8a7345
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0194_macro_inside_generic_arg.rast
@@ -0,0 +1,36 @@
+SOURCE_FILE
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "A"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Foo"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ TYPE_ARG
+ MACRO_TYPE
+ MACRO_CALL
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "syn"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Token"
+ BANG "!"
+ TOKEN_TREE
+ L_BRACK "["
+ UNDERSCORE "_"
+ R_BRACK "]"
+ R_ANGLE ">"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0194_macro_inside_generic_arg.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0194_macro_inside_generic_arg.rs
new file mode 100644
index 000000000..8d43a53d9
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0194_macro_inside_generic_arg.rs
@@ -0,0 +1 @@
+type A = Foo<syn::Token![_]>;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0196_pub_tuple_field.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0196_pub_tuple_field.rast
new file mode 100644
index 000000000..a23ddf69f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0196_pub_tuple_field.rast
@@ -0,0 +1,30 @@
+SOURCE_FILE
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "MyStruct"
+ TUPLE_FIELD_LIST
+ L_PAREN "("
+ TUPLE_FIELD
+ VISIBILITY
+ PUB_KW "pub"
+ WHITESPACE " "
+ TUPLE_TYPE
+ L_PAREN "("
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u32"
+ COMMA ","
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u32"
+ R_PAREN ")"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0196_pub_tuple_field.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0196_pub_tuple_field.rs
new file mode 100644
index 000000000..00d8feba9
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0196_pub_tuple_field.rs
@@ -0,0 +1 @@
+struct MyStruct(pub (u32, u32));
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0197_destructuring_assignment_struct_rest_pattern.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0197_destructuring_assignment_struct_rest_pattern.rast
new file mode 100644
index 000000000..fb8aa5acc
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0197_destructuring_assignment_struct_rest_pattern.rast
@@ -0,0 +1,44 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BIN_EXPR
+ RECORD_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_EXPR_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ DOT2 ".."
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ RECORD_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_EXPR_FIELD_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0197_destructuring_assignment_struct_rest_pattern.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0197_destructuring_assignment_struct_rest_pattern.rs
new file mode 100644
index 000000000..22a5b5f3e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0197_destructuring_assignment_struct_rest_pattern.rs
@@ -0,0 +1,3 @@
+fn foo() {
+ S { .. } = S {};
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0198_destructuring_assignment_wildcard_pat.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0198_destructuring_assignment_wildcard_pat.rast
new file mode 100644
index 000000000..5f53d3451
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0198_destructuring_assignment_wildcard_pat.rast
@@ -0,0 +1,50 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BIN_EXPR
+ UNDERSCORE_EXPR
+ UNDERSCORE "_"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "1"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BIN_EXPR
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Some"
+ ARG_LIST
+ L_PAREN "("
+ UNDERSCORE_EXPR
+ UNDERSCORE "_"
+ R_PAREN ")"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "None"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0198_destructuring_assignment_wildcard_pat.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0198_destructuring_assignment_wildcard_pat.rs
new file mode 100644
index 000000000..91acfb3a0
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0198_destructuring_assignment_wildcard_pat.rs
@@ -0,0 +1,4 @@
+fn foo() {
+ _ = 1;
+ Some(_) = None;
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0199_const_param_default_expression.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0199_const_param_default_expression.rast
new file mode 100644
index 000000000..0607ff54f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0199_const_param_default_expression.rast
@@ -0,0 +1,34 @@
+SOURCE_FILE
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "A"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ CONST_PARAM
+ CONST_KW "const"
+ WHITESPACE " "
+ NAME
+ IDENT "N"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "1"
+ WHITESPACE " "
+ R_CURLY "}"
+ R_ANGLE ">"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0199_const_param_default_expression.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0199_const_param_default_expression.rs
new file mode 100644
index 000000000..551bde0b0
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0199_const_param_default_expression.rs
@@ -0,0 +1 @@
+struct A<const N: i32 = { 1 }>;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0199_effect_blocks.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0199_effect_blocks.rast
new file mode 100644
index 000000000..f14080c90
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0199_effect_blocks.rast
@@ -0,0 +1,95 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "f"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ BLOCK_EXPR
+ UNSAFE_KW "unsafe"
+ WHITESPACE " "
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "f"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ BLOCK_EXPR
+ CONST_KW "const"
+ WHITESPACE " "
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "f"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ BLOCK_EXPR
+ ASYNC_KW "async"
+ WHITESPACE " "
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "f"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ BLOCK_EXPR
+ ASYNC_KW "async"
+ WHITESPACE " "
+ MOVE_KW "move"
+ WHITESPACE " "
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0199_effect_blocks.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0199_effect_blocks.rs
new file mode 100644
index 000000000..c57d24b2f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0199_effect_blocks.rs
@@ -0,0 +1,4 @@
+fn f() { unsafe { } }
+fn f() { const { } }
+fn f() { async { } }
+fn f() { async move { } }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0199_type_item_where_clause_deprecated.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0199_type_item_where_clause_deprecated.rast
new file mode 100644
index 000000000..7210b7389
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0199_type_item_where_clause_deprecated.rast
@@ -0,0 +1,33 @@
+SOURCE_FILE
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "Foo"
+ WHITESPACE " "
+ WHERE_CLAUSE
+ WHERE_KW "where"
+ WHITESPACE " "
+ WHERE_PRED
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Foo"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Copy"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_TYPE
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0199_type_item_where_clause_deprecated.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0199_type_item_where_clause_deprecated.rs
new file mode 100644
index 000000000..a602d07f0
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0199_type_item_where_clause_deprecated.rs
@@ -0,0 +1 @@
+type Foo where Foo: Copy = ();
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0200_assoc_const_eq.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0200_assoc_const_eq.rast
new file mode 100644
index 000000000..fa2733e7f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0200_assoc_const_eq.rast
@@ -0,0 +1,105 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "F"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Foo"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ ASSOC_TYPE_ARG
+ NAME_REF
+ IDENT "N"
+ EQ "="
+ CONST_ARG
+ LITERAL
+ INT_NUMBER "3"
+ R_ANGLE ">"
+ R_ANGLE ">"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ CONST
+ CONST_KW "const"
+ WHITESPACE " "
+ NAME
+ IDENT "TEST"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "usize"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "3"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "bar"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "F"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Foo"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ ASSOC_TYPE_ARG
+ NAME_REF
+ IDENT "N"
+ EQ "="
+ CONST_ARG
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "TEST"
+ R_CURLY "}"
+ R_ANGLE ">"
+ R_ANGLE ">"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0200_assoc_const_eq.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0200_assoc_const_eq.rs
new file mode 100644
index 000000000..b43c4e36a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0200_assoc_const_eq.rs
@@ -0,0 +1,3 @@
+fn foo<F: Foo<N=3>>() {}
+const TEST: usize = 3;
+fn bar<F: Foo<N={TEST}>>() {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0200_const_param_default_literal.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0200_const_param_default_literal.rast
new file mode 100644
index 000000000..8e5231365
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0200_const_param_default_literal.rast
@@ -0,0 +1,30 @@
+SOURCE_FILE
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "A"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ CONST_PARAM
+ CONST_KW "const"
+ WHITESPACE " "
+ NAME
+ IDENT "N"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ PREFIX_EXPR
+ MINUS "-"
+ LITERAL
+ INT_NUMBER "1"
+ R_ANGLE ">"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0200_const_param_default_literal.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0200_const_param_default_literal.rs
new file mode 100644
index 000000000..879ecffa7
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0200_const_param_default_literal.rs
@@ -0,0 +1 @@
+struct A<const N: i32 = -1>;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0201_question_for_type_trait_bound.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0201_question_for_type_trait_bound.rast
new file mode 100644
index 000000000..56e2d1095
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0201_question_for_type_trait_bound.rast
@@ -0,0 +1,47 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "f"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "T"
+ R_ANGLE ">"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ WHERE_CLAUSE
+ WHERE_KW "where"
+ WHITESPACE " "
+ WHERE_PRED
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "T"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ QUESTION "?"
+ FOR_TYPE
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ R_ANGLE ">"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Sized"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0201_question_for_type_trait_bound.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0201_question_for_type_trait_bound.rs
new file mode 100644
index 000000000..f80dd90d4
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0201_question_for_type_trait_bound.rs
@@ -0,0 +1 @@
+fn f<T>() where T: ?for<> Sized {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0000_empty.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0000_empty.rast
new file mode 100644
index 000000000..40b9ef804
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0000_empty.rast
@@ -0,0 +1 @@
+SOURCE_FILE
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0000_empty.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0000_empty.rs
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0000_empty.rs
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0001_struct_item.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0001_struct_item.rast
new file mode 100644
index 000000000..0e9639f23
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0001_struct_item.rast
@@ -0,0 +1,39 @@
+SOURCE_FILE
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "T"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Copy"
+ R_ANGLE ">"
+ WHITESPACE " "
+ RECORD_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ RECORD_FIELD
+ NAME
+ IDENT "f"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "T"
+ COMMA ","
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0001_struct_item.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0001_struct_item.rs
new file mode 100644
index 000000000..512aeb3e7
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0001_struct_item.rs
@@ -0,0 +1,3 @@
+struct S<T: Copy> {
+ f: T,
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0002_struct_item_field.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0002_struct_item_field.rast
new file mode 100644
index 000000000..dd52e5850
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0002_struct_item_field.rast
@@ -0,0 +1,22 @@
+SOURCE_FILE
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ RECORD_FIELD
+ NAME
+ IDENT "foo"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u32"
+ WHITESPACE "\n"
+ R_CURLY "}"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0002_struct_item_field.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0002_struct_item_field.rs
new file mode 100644
index 000000000..cc3866d25
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0002_struct_item_field.rs
@@ -0,0 +1,3 @@
+struct S {
+ foo: u32
+} \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0004_file_shebang.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0004_file_shebang.rast
new file mode 100644
index 000000000..698957189
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0004_file_shebang.rast
@@ -0,0 +1,2 @@
+SOURCE_FILE
+ SHEBANG "#!/use/bin/env rusti"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0004_file_shebang.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0004_file_shebang.rs
new file mode 100644
index 000000000..53dc9e617
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0004_file_shebang.rs
@@ -0,0 +1 @@
+#!/use/bin/env rusti \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0005_fn_item.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0005_fn_item.rast
new file mode 100644
index 000000000..756d20e4d
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0005_fn_item.rast
@@ -0,0 +1,16 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0005_fn_item.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0005_fn_item.rs
new file mode 100644
index 000000000..03210551c
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0005_fn_item.rs
@@ -0,0 +1,2 @@
+fn foo() {
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0006_inner_attributes.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0006_inner_attributes.rast
new file mode 100644
index 000000000..cb63ba80e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0006_inner_attributes.rast
@@ -0,0 +1,194 @@
+SOURCE_FILE
+ ATTR
+ POUND "#"
+ BANG "!"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "attr"
+ R_BRACK "]"
+ WHITESPACE "\n"
+ ATTR
+ POUND "#"
+ BANG "!"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "attr"
+ TOKEN_TREE
+ L_PAREN "("
+ TRUE_KW "true"
+ R_PAREN ")"
+ R_BRACK "]"
+ WHITESPACE "\n"
+ ATTR
+ POUND "#"
+ BANG "!"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "attr"
+ TOKEN_TREE
+ L_PAREN "("
+ IDENT "ident"
+ R_PAREN ")"
+ R_BRACK "]"
+ WHITESPACE "\n"
+ ATTR
+ POUND "#"
+ BANG "!"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "attr"
+ TOKEN_TREE
+ L_PAREN "("
+ IDENT "ident"
+ COMMA ","
+ WHITESPACE " "
+ INT_NUMBER "100"
+ COMMA ","
+ WHITESPACE " "
+ TRUE_KW "true"
+ COMMA ","
+ WHITESPACE " "
+ STRING "\"true\""
+ COMMA ","
+ WHITESPACE " "
+ IDENT "ident"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ INT_NUMBER "100"
+ COMMA ","
+ WHITESPACE " "
+ IDENT "ident"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ STRING "\"hello\""
+ COMMA ","
+ WHITESPACE " "
+ IDENT "ident"
+ TOKEN_TREE
+ L_PAREN "("
+ INT_NUMBER "100"
+ R_PAREN ")"
+ R_PAREN ")"
+ R_BRACK "]"
+ WHITESPACE "\n"
+ ATTR
+ POUND "#"
+ BANG "!"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "attr"
+ TOKEN_TREE
+ L_PAREN "("
+ INT_NUMBER "100"
+ R_PAREN ")"
+ R_BRACK "]"
+ WHITESPACE "\n"
+ ATTR
+ POUND "#"
+ BANG "!"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "attr"
+ TOKEN_TREE
+ L_PAREN "("
+ IDENT "enabled"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TRUE_KW "true"
+ R_PAREN ")"
+ R_BRACK "]"
+ WHITESPACE "\n"
+ ATTR
+ POUND "#"
+ BANG "!"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "enabled"
+ TOKEN_TREE
+ L_PAREN "("
+ TRUE_KW "true"
+ R_PAREN ")"
+ R_BRACK "]"
+ WHITESPACE "\n"
+ ATTR
+ POUND "#"
+ BANG "!"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "attr"
+ TOKEN_TREE
+ L_PAREN "("
+ STRING "\"hello\""
+ R_PAREN ")"
+ R_BRACK "]"
+ WHITESPACE "\n"
+ ATTR
+ POUND "#"
+ BANG "!"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "repr"
+ TOKEN_TREE
+ L_PAREN "("
+ IDENT "C"
+ COMMA ","
+ WHITESPACE " "
+ IDENT "align"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ INT_NUMBER "4"
+ R_PAREN ")"
+ R_BRACK "]"
+ WHITESPACE "\n"
+ ATTR
+ POUND "#"
+ BANG "!"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "repr"
+ TOKEN_TREE
+ L_PAREN "("
+ IDENT "C"
+ COMMA ","
+ WHITESPACE " "
+ IDENT "align"
+ TOKEN_TREE
+ L_PAREN "("
+ INT_NUMBER "4"
+ R_PAREN ")"
+ R_PAREN ")"
+ R_BRACK "]"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0006_inner_attributes.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0006_inner_attributes.rs
new file mode 100644
index 000000000..e81f8b1e8
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0006_inner_attributes.rs
@@ -0,0 +1,10 @@
+#![attr]
+#![attr(true)]
+#![attr(ident)]
+#![attr(ident, 100, true, "true", ident = 100, ident = "hello", ident(100))]
+#![attr(100)]
+#![attr(enabled = true)]
+#![enabled(true)]
+#![attr("hello")]
+#![repr(C, align = 4)]
+#![repr(C, align(4))] \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0007_extern_crate.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0007_extern_crate.rast
new file mode 100644
index 000000000..8b9259fd6
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0007_extern_crate.rast
@@ -0,0 +1,40 @@
+SOURCE_FILE
+ EXTERN_CRATE
+ EXTERN_KW "extern"
+ WHITESPACE " "
+ CRATE_KW "crate"
+ WHITESPACE " "
+ NAME_REF
+ IDENT "foo"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ EXTERN_CRATE
+ EXTERN_KW "extern"
+ WHITESPACE " "
+ CRATE_KW "crate"
+ WHITESPACE " "
+ NAME_REF
+ IDENT "foo"
+ WHITESPACE " "
+ RENAME
+ AS_KW "as"
+ WHITESPACE " "
+ NAME
+ IDENT "bar"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ EXTERN_CRATE
+ EXTERN_KW "extern"
+ WHITESPACE " "
+ CRATE_KW "crate"
+ WHITESPACE " "
+ NAME_REF
+ SELF_KW "self"
+ WHITESPACE " "
+ RENAME
+ AS_KW "as"
+ WHITESPACE " "
+ NAME
+ IDENT "baz"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0007_extern_crate.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0007_extern_crate.rs
new file mode 100644
index 000000000..ab81a608c
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0007_extern_crate.rs
@@ -0,0 +1,3 @@
+extern crate foo;
+extern crate foo as bar;
+extern crate self as baz;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0008_mod_item.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0008_mod_item.rast
new file mode 100644
index 000000000..adee67181
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0008_mod_item.rast
@@ -0,0 +1,77 @@
+SOURCE_FILE
+ MODULE
+ MOD_KW "mod"
+ WHITESPACE " "
+ NAME
+ IDENT "c"
+ WHITESPACE " "
+ ITEM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n "
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_FIELD_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ MODULE
+ MOD_KW "mod"
+ WHITESPACE " "
+ NAME
+ IDENT "d"
+ WHITESPACE " "
+ ITEM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ ATTR
+ POUND "#"
+ BANG "!"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "attr"
+ R_BRACK "]"
+ WHITESPACE "\n "
+ MODULE
+ MOD_KW "mod"
+ WHITESPACE " "
+ NAME
+ IDENT "e"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ MODULE
+ MOD_KW "mod"
+ WHITESPACE " "
+ NAME
+ IDENT "f"
+ WHITESPACE " "
+ ITEM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0008_mod_item.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0008_mod_item.rs
new file mode 100644
index 000000000..4ff0d9795
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0008_mod_item.rs
@@ -0,0 +1,12 @@
+mod c {
+ fn foo() {
+ }
+ struct S {}
+}
+
+mod d {
+ #![attr]
+ mod e;
+ mod f {
+ }
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0009_use_item.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0009_use_item.rast
new file mode 100644
index 000000000..04a44ef7e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0009_use_item.rast
@@ -0,0 +1,21 @@
+SOURCE_FILE
+ USE
+ USE_KW "use"
+ WHITESPACE " "
+ USE_TREE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "foo"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ USE
+ USE_KW "use"
+ WHITESPACE " "
+ USE_TREE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "bar"
+ SEMICOLON ";"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0009_use_item.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0009_use_item.rs
new file mode 100644
index 000000000..05a6aff83
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0009_use_item.rs
@@ -0,0 +1,2 @@
+use foo;
+use ::bar; \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0010_use_path_segments.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0010_use_path_segments.rast
new file mode 100644
index 000000000..ddadec817
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0010_use_path_segments.rast
@@ -0,0 +1,42 @@
+SOURCE_FILE
+ USE
+ USE_KW "use"
+ WHITESPACE " "
+ USE_TREE
+ PATH
+ PATH
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "foo"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "bar"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "baz"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ USE
+ USE_KW "use"
+ WHITESPACE " "
+ USE_TREE
+ PATH
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "foo"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "bar"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "baz"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0010_use_path_segments.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0010_use_path_segments.rs
new file mode 100644
index 000000000..1e71b7a6c
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0010_use_path_segments.rs
@@ -0,0 +1,2 @@
+use ::foo::bar::baz;
+use foo::bar::baz;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0011_outer_attribute.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0011_outer_attribute.rast
new file mode 100644
index 000000000..dbb9bc54d
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0011_outer_attribute.rast
@@ -0,0 +1,61 @@
+SOURCE_FILE
+ FN
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "cfg"
+ TOKEN_TREE
+ L_PAREN "("
+ IDENT "test"
+ R_PAREN ")"
+ R_BRACK "]"
+ WHITESPACE "\n"
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Ignore"
+ R_BRACK "]"
+ WHITESPACE "\n"
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ MODULE
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "path"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ STRING "\"a.rs\""
+ R_BRACK "]"
+ WHITESPACE "\n"
+ MOD_KW "mod"
+ WHITESPACE " "
+ NAME
+ IDENT "b"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0011_outer_attribute.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0011_outer_attribute.rs
new file mode 100644
index 000000000..6f04cb171
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0011_outer_attribute.rs
@@ -0,0 +1,6 @@
+#[cfg(test)]
+#[Ignore]
+fn foo() {}
+
+#[path = "a.rs"]
+mod b;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0012_visibility.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0012_visibility.rast
new file mode 100644
index 000000000..a95bc2301
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0012_visibility.rast
@@ -0,0 +1,133 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "a"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ FN
+ VISIBILITY
+ PUB_KW "pub"
+ WHITESPACE " "
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "b"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ MACRO_DEF
+ VISIBILITY
+ PUB_KW "pub"
+ WHITESPACE " "
+ MACRO_KW "macro"
+ WHITESPACE " "
+ NAME
+ IDENT "m"
+ TOKEN_TREE
+ TOKEN_TREE
+ L_PAREN "("
+ DOLLAR "$"
+ COLON ":"
+ IDENT "ident"
+ R_PAREN ")"
+ WHITESPACE " "
+ TOKEN_TREE
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ FN
+ VISIBILITY
+ PUB_KW "pub"
+ L_PAREN "("
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ CRATE_KW "crate"
+ R_PAREN ")"
+ WHITESPACE " "
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "c"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ FN
+ VISIBILITY
+ PUB_KW "pub"
+ L_PAREN "("
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ SUPER_KW "super"
+ R_PAREN ")"
+ WHITESPACE " "
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "d"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ FN
+ VISIBILITY
+ PUB_KW "pub"
+ L_PAREN "("
+ IN_KW "in"
+ WHITESPACE " "
+ PATH
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "foo"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "bar"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "baz"
+ R_PAREN ")"
+ WHITESPACE " "
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "e"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0012_visibility.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0012_visibility.rs
new file mode 100644
index 000000000..129d486fa
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0012_visibility.rs
@@ -0,0 +1,6 @@
+fn a() {}
+pub fn b() {}
+pub macro m($:ident) {}
+pub(crate) fn c() {}
+pub(super) fn d() {}
+pub(in foo::bar::baz) fn e() {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0013_use_path_self_super.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0013_use_path_self_super.rast
new file mode 100644
index 000000000..8a0149cac
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0013_use_path_self_super.rast
@@ -0,0 +1,36 @@
+SOURCE_FILE
+ USE
+ USE_KW "use"
+ WHITESPACE " "
+ USE_TREE
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ SELF_KW "self"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "foo"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ USE
+ USE_KW "use"
+ WHITESPACE " "
+ USE_TREE
+ PATH
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ SUPER_KW "super"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ SUPER_KW "super"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "bar"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0013_use_path_self_super.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0013_use_path_self_super.rs
new file mode 100644
index 000000000..9d9eb9917
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0013_use_path_self_super.rs
@@ -0,0 +1,2 @@
+use self::foo;
+use super::super::bar;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0014_use_tree.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0014_use_tree.rast
new file mode 100644
index 000000000..b37edc365
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0014_use_tree.rast
@@ -0,0 +1,95 @@
+SOURCE_FILE
+ USE
+ USE_KW "use"
+ WHITESPACE " "
+ USE_TREE
+ STAR "*"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ USE
+ USE_KW "use"
+ WHITESPACE " "
+ USE_TREE
+ COLON2 "::"
+ STAR "*"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ USE
+ USE_KW "use"
+ WHITESPACE " "
+ USE_TREE
+ COLON2 "::"
+ USE_TREE_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ USE
+ USE_KW "use"
+ WHITESPACE " "
+ USE_TREE
+ USE_TREE_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ USE
+ USE_KW "use"
+ WHITESPACE " "
+ USE_TREE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "foo"
+ COLON2 "::"
+ STAR "*"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ USE
+ USE_KW "use"
+ WHITESPACE " "
+ USE_TREE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "foo"
+ COLON2 "::"
+ USE_TREE_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ USE
+ USE_KW "use"
+ WHITESPACE " "
+ USE_TREE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "foo"
+ COLON2 "::"
+ USE_TREE_LIST
+ L_CURLY "{"
+ USE_TREE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "a"
+ COMMA ","
+ WHITESPACE " "
+ USE_TREE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "b"
+ COMMA ","
+ WHITESPACE " "
+ USE_TREE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "c"
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0014_use_tree.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0014_use_tree.rs
new file mode 100644
index 000000000..5e4aa3a33
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0014_use_tree.rs
@@ -0,0 +1,7 @@
+use *;
+use ::*;
+use ::{};
+use {};
+use foo::*;
+use foo::{};
+use ::foo::{a, b, c};
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0015_use_tree.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0015_use_tree.rast
new file mode 100644
index 000000000..ddf8aad6f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0015_use_tree.rast
@@ -0,0 +1,65 @@
+SOURCE_FILE
+ USE
+ USE_KW "use"
+ WHITESPACE " "
+ USE_TREE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "foo"
+ WHITESPACE " "
+ RENAME
+ AS_KW "as"
+ WHITESPACE " "
+ NAME
+ IDENT "bar"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ USE
+ USE_KW "use"
+ WHITESPACE " "
+ USE_TREE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "foo"
+ COLON2 "::"
+ USE_TREE_LIST
+ L_CURLY "{"
+ USE_TREE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "a"
+ WHITESPACE " "
+ RENAME
+ AS_KW "as"
+ WHITESPACE " "
+ NAME
+ IDENT "b"
+ COMMA ","
+ WHITESPACE " "
+ USE_TREE
+ STAR "*"
+ COMMA ","
+ WHITESPACE " "
+ USE_TREE
+ COLON2 "::"
+ STAR "*"
+ COMMA ","
+ WHITESPACE " "
+ USE_TREE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "foo"
+ WHITESPACE " "
+ RENAME
+ AS_KW "as"
+ WHITESPACE " "
+ NAME
+ IDENT "x"
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0015_use_tree.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0015_use_tree.rs
new file mode 100644
index 000000000..46a0783a2
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0015_use_tree.rs
@@ -0,0 +1,2 @@
+use foo as bar;
+use foo::{a as b, *, ::*, ::foo as x};
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0016_struct_flavors.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0016_struct_flavors.rast
new file mode 100644
index 000000000..eb2724e2f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0016_struct_flavors.rast
@@ -0,0 +1,93 @@
+SOURCE_FILE
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "A"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "B"
+ WHITESPACE " "
+ RECORD_FIELD_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "C"
+ TUPLE_FIELD_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n\n"
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "D"
+ WHITESPACE " "
+ RECORD_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ RECORD_FIELD
+ NAME
+ IDENT "a"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u32"
+ COMMA ","
+ WHITESPACE "\n "
+ RECORD_FIELD
+ VISIBILITY
+ PUB_KW "pub"
+ WHITESPACE " "
+ NAME
+ IDENT "b"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u32"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "E"
+ TUPLE_FIELD_LIST
+ L_PAREN "("
+ TUPLE_FIELD
+ VISIBILITY
+ PUB_KW "pub"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "x"
+ COMMA ","
+ WHITESPACE " "
+ TUPLE_FIELD
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "y"
+ COMMA ","
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0016_struct_flavors.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0016_struct_flavors.rs
new file mode 100644
index 000000000..69638350c
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0016_struct_flavors.rs
@@ -0,0 +1,10 @@
+struct A;
+struct B {}
+struct C();
+
+struct D {
+ a: u32,
+ pub b: u32
+}
+
+struct E(pub x, y,);
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0017_attr_trailing_comma.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0017_attr_trailing_comma.rast
new file mode 100644
index 000000000..7c914e254
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0017_attr_trailing_comma.rast
@@ -0,0 +1,30 @@
+SOURCE_FILE
+ FN
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "foo"
+ TOKEN_TREE
+ L_PAREN "("
+ IDENT "a"
+ COMMA ","
+ R_PAREN ")"
+ R_BRACK "]"
+ WHITESPACE "\n"
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0017_attr_trailing_comma.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0017_attr_trailing_comma.rs
new file mode 100644
index 000000000..fe0a7bb97
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0017_attr_trailing_comma.rs
@@ -0,0 +1,2 @@
+#[foo(a,)]
+fn foo() {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0018_struct_type_params.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0018_struct_type_params.rast
new file mode 100644
index 000000000..11ebc7efb
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0018_struct_type_params.rast
@@ -0,0 +1,274 @@
+SOURCE_FILE
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S1"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "T"
+ R_ANGLE ">"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S2"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "T"
+ R_ANGLE ">"
+ TUPLE_FIELD_LIST
+ L_PAREN "("
+ TUPLE_FIELD
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u32"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S3"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "T"
+ R_ANGLE ">"
+ WHITESPACE " "
+ RECORD_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ RECORD_FIELD
+ NAME
+ IDENT "u"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u32"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S4"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ R_ANGLE ">"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S5"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S6"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ COLON ":"
+ R_ANGLE ">"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S7"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ COLON ":"
+ WHITESPACE " "
+ LIFETIME
+ LIFETIME_IDENT "'b"
+ R_ANGLE ">"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S8"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ COLON ":"
+ WHITESPACE " "
+ LIFETIME
+ LIFETIME_IDENT "'b"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ R_ANGLE ">"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S9"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ COLON ":"
+ WHITESPACE " "
+ LIFETIME
+ LIFETIME_IDENT "'b"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ LIFETIME
+ LIFETIME_IDENT "'c"
+ R_ANGLE ">"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S10"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ COMMA ","
+ R_ANGLE ">"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S11"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ COMMA ","
+ WHITESPACE " "
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'b"
+ R_ANGLE ">"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S12"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ COLON ":"
+ WHITESPACE " "
+ LIFETIME
+ LIFETIME_IDENT "'b"
+ PLUS "+"
+ COMMA ","
+ WHITESPACE " "
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'b"
+ COLON ":"
+ WHITESPACE " "
+ LIFETIME
+ LIFETIME_IDENT "'c"
+ COMMA ","
+ R_ANGLE ">"
+ SEMICOLON ";"
+ WHITESPACE "\n\n"
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S13"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "T"
+ R_ANGLE ">"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S14"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "T"
+ COMMA ","
+ WHITESPACE " "
+ TYPE_PARAM
+ NAME
+ IDENT "U"
+ R_ANGLE ">"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S15"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ COMMA ","
+ WHITESPACE " "
+ TYPE_PARAM
+ NAME
+ IDENT "T"
+ COMMA ","
+ WHITESPACE " "
+ TYPE_PARAM
+ NAME
+ IDENT "U"
+ R_ANGLE ">"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0018_struct_type_params.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0018_struct_type_params.rs
new file mode 100644
index 000000000..88c544923
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0018_struct_type_params.rs
@@ -0,0 +1,17 @@
+struct S1<T>;
+struct S2<T>(u32);
+struct S3<T> { u: u32 }
+
+struct S4<>;
+struct S5<'a>;
+struct S6<'a:>;
+struct S7<'a: 'b>;
+struct S8<'a: 'b + >;
+struct S9<'a: 'b + 'c>;
+struct S10<'a,>;
+struct S11<'a, 'b>;
+struct S12<'a: 'b+, 'b: 'c,>;
+
+struct S13<T>;
+struct S14<T, U>;
+struct S15<'a, T, U>;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0019_enums.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0019_enums.rast
new file mode 100644
index 000000000..dd47e3aa4
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0019_enums.rast
@@ -0,0 +1,155 @@
+SOURCE_FILE
+ ENUM
+ ENUM_KW "enum"
+ WHITESPACE " "
+ NAME
+ IDENT "E1"
+ WHITESPACE " "
+ VARIANT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ ENUM
+ ENUM_KW "enum"
+ WHITESPACE " "
+ NAME
+ IDENT "E2"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "T"
+ R_ANGLE ">"
+ WHITESPACE " "
+ VARIANT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ ENUM
+ ENUM_KW "enum"
+ WHITESPACE " "
+ NAME
+ IDENT "E3"
+ WHITESPACE " "
+ VARIANT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ VARIANT
+ NAME
+ IDENT "X"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ ENUM
+ ENUM_KW "enum"
+ WHITESPACE " "
+ NAME
+ IDENT "E4"
+ WHITESPACE " "
+ VARIANT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ VARIANT
+ NAME
+ IDENT "X"
+ COMMA ","
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ ENUM
+ ENUM_KW "enum"
+ WHITESPACE " "
+ NAME
+ IDENT "E5"
+ WHITESPACE " "
+ VARIANT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ VARIANT
+ NAME
+ IDENT "A"
+ COMMA ","
+ WHITESPACE "\n "
+ VARIANT
+ NAME
+ IDENT "B"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "92"
+ COMMA ","
+ WHITESPACE "\n "
+ VARIANT
+ NAME
+ IDENT "C"
+ WHITESPACE " "
+ RECORD_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ RECORD_FIELD
+ NAME
+ IDENT "a"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u32"
+ COMMA ","
+ WHITESPACE "\n "
+ RECORD_FIELD
+ VISIBILITY
+ PUB_KW "pub"
+ WHITESPACE " "
+ NAME
+ IDENT "b"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "f64"
+ COMMA ","
+ WHITESPACE "\n "
+ R_CURLY "}"
+ COMMA ","
+ WHITESPACE "\n "
+ VARIANT
+ NAME
+ IDENT "F"
+ WHITESPACE " "
+ RECORD_FIELD_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ COMMA ","
+ WHITESPACE "\n "
+ VARIANT
+ NAME
+ IDENT "D"
+ TUPLE_FIELD_LIST
+ L_PAREN "("
+ TUPLE_FIELD
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u32"
+ COMMA ","
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n "
+ VARIANT
+ NAME
+ IDENT "E"
+ TUPLE_FIELD_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0019_enums.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0019_enums.rs
new file mode 100644
index 000000000..7a1afa0e6
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0019_enums.rs
@@ -0,0 +1,25 @@
+enum E1 {
+}
+
+enum E2<T> {
+}
+
+enum E3 {
+ X
+}
+
+enum E4 {
+ X,
+}
+
+enum E5 {
+ A,
+ B = 92,
+ C {
+ a: u32,
+ pub b: f64,
+ },
+ F {},
+ D(u32,),
+ E(),
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0020_type_param_bounds.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0020_type_param_bounds.rast
new file mode 100644
index 000000000..043a966ff
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0020_type_param_bounds.rast
@@ -0,0 +1,283 @@
+SOURCE_FILE
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "A"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "T"
+ R_ANGLE ">"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "B"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "T"
+ COLON ":"
+ TYPE_BOUND_LIST
+ R_ANGLE ">"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "C"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "T"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "D"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "T"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ R_ANGLE ">"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "E"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "T"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ TYPE_BOUND
+ LIFETIME
+ LIFETIME_IDENT "'d"
+ WHITESPACE " "
+ R_ANGLE ">"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "F"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "T"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ TYPE_BOUND
+ LIFETIME
+ LIFETIME_IDENT "'d"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Clone"
+ R_ANGLE ">"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "G"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "T"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Clone"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Copy"
+ R_ANGLE ">"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "H"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "T"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "Foo"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ SELF_KW "self"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Bar"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ TYPE_BOUND
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "I"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "T"
+ COLON ":"
+ TYPE_BOUND_LIST
+ COMMA ","
+ WHITESPACE " "
+ TYPE_PARAM
+ NAME
+ IDENT "U"
+ COLON ":"
+ TYPE_BOUND_LIST
+ COMMA ","
+ R_ANGLE ">"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "K"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ COLON ":"
+ WHITESPACE " "
+ LIFETIME
+ LIFETIME_IDENT "'d"
+ COMMA ","
+ WHITESPACE " "
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'d"
+ COLON ":"
+ WHITESPACE " "
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ LIFETIME
+ LIFETIME_IDENT "'b"
+ COMMA ","
+ WHITESPACE " "
+ TYPE_PARAM
+ NAME
+ IDENT "T"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ TYPE_BOUND
+ LIFETIME
+ LIFETIME_IDENT "'d"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Clone"
+ R_ANGLE ">"
+ SEMICOLON ";"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0020_type_param_bounds.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0020_type_param_bounds.rs
new file mode 100644
index 000000000..712898978
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0020_type_param_bounds.rs
@@ -0,0 +1,10 @@
+struct A<T>;
+struct B<T:>;
+struct C<T: 'a>;
+struct D<T: 'a + >;
+struct E<T: 'a + 'd >;
+struct F<T: 'a + 'd + Clone>;
+struct G<T: Clone + Copy>;
+struct H<T: ::Foo + self::Bar + 'a>;
+struct I<T:, U:,>;
+struct K<'a: 'd, 'd: 'a + 'b, T: 'a + 'd + Clone>; \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0022_empty_extern_block.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0022_empty_extern_block.rast
new file mode 100644
index 000000000..ef2fb66dd
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0022_empty_extern_block.rast
@@ -0,0 +1,21 @@
+SOURCE_FILE
+ EXTERN_BLOCK
+ ABI
+ EXTERN_KW "extern"
+ WHITESPACE " "
+ EXTERN_ITEM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ EXTERN_BLOCK
+ ABI
+ EXTERN_KW "extern"
+ WHITESPACE " "
+ STRING "\"C\""
+ WHITESPACE " "
+ EXTERN_ITEM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0022_empty_extern_block.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0022_empty_extern_block.rs
new file mode 100644
index 000000000..f5fe0e6ef
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0022_empty_extern_block.rs
@@ -0,0 +1,5 @@
+extern {
+}
+
+extern "C" {
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0023_static_items.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0023_static_items.rast
new file mode 100644
index 000000000..b164e828e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0023_static_items.rast
@@ -0,0 +1,41 @@
+SOURCE_FILE
+ STATIC
+ STATIC_KW "static"
+ WHITESPACE " "
+ NAME
+ IDENT "FOO"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u32"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "1"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ STATIC
+ STATIC_KW "static"
+ WHITESPACE " "
+ MUT_KW "mut"
+ WHITESPACE " "
+ NAME
+ IDENT "BAR"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "92"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0023_static_items.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0023_static_items.rs
new file mode 100644
index 000000000..5fb92ce33
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0023_static_items.rs
@@ -0,0 +1,2 @@
+static FOO: u32 = 1;
+static mut BAR: i32 = 92;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0024_const_item.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0024_const_item.rast
new file mode 100644
index 000000000..40b9ef804
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0024_const_item.rast
@@ -0,0 +1 @@
+SOURCE_FILE
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0024_const_item.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0024_const_item.rs
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0024_const_item.rs
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0025_extern_fn_in_block.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0025_extern_fn_in_block.rast
new file mode 100644
index 000000000..9c5f5ac64
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0025_extern_fn_in_block.rast
@@ -0,0 +1,33 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ FN
+ ABI
+ EXTERN_KW "extern"
+ WHITESPACE " "
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "f"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0025_extern_fn_in_block.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0025_extern_fn_in_block.rs
new file mode 100644
index 000000000..289809809
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0025_extern_fn_in_block.rs
@@ -0,0 +1,3 @@
+fn main() {
+ extern fn f() {}
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0026_const_fn_in_block.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0026_const_fn_in_block.rast
new file mode 100644
index 000000000..ca9a3df86
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0026_const_fn_in_block.rast
@@ -0,0 +1,32 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ FN
+ CONST_KW "const"
+ WHITESPACE " "
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "f"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0026_const_fn_in_block.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0026_const_fn_in_block.rs
new file mode 100644
index 000000000..7641a3d28
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0026_const_fn_in_block.rs
@@ -0,0 +1,3 @@
+fn main() {
+ const fn f() {}
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0027_unsafe_fn_in_block.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0027_unsafe_fn_in_block.rast
new file mode 100644
index 000000000..88ebd1095
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0027_unsafe_fn_in_block.rast
@@ -0,0 +1,43 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ FN
+ UNSAFE_KW "unsafe"
+ WHITESPACE " "
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "f"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n "
+ BLOCK_EXPR
+ UNSAFE_KW "unsafe"
+ WHITESPACE " "
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "92"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0027_unsafe_fn_in_block.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0027_unsafe_fn_in_block.rs
new file mode 100644
index 000000000..f3c5ff938
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0027_unsafe_fn_in_block.rs
@@ -0,0 +1,4 @@
+fn main() {
+ unsafe fn f() {}
+ unsafe { 92 }
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0028_operator_binding_power.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0028_operator_binding_power.rast
new file mode 100644
index 000000000..ae08c0756
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0028_operator_binding_power.rast
@@ -0,0 +1,186 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "binding_power"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "x"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ BIN_EXPR
+ BIN_EXPR
+ LITERAL
+ INT_NUMBER "1"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ BIN_EXPR
+ BIN_EXPR
+ LITERAL
+ INT_NUMBER "2"
+ WHITESPACE " "
+ STAR "*"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "3"
+ WHITESPACE " "
+ PERCENT "%"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "4"
+ WHITESPACE " "
+ MINUS "-"
+ WHITESPACE " "
+ BIN_EXPR
+ LITERAL
+ INT_NUMBER "5"
+ WHITESPACE " "
+ SLASH "/"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "6"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BIN_EXPR
+ LITERAL
+ INT_NUMBER "1"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ BIN_EXPR
+ LITERAL
+ INT_NUMBER "2"
+ WHITESPACE " "
+ STAR "*"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "3"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BIN_EXPR
+ LITERAL
+ INT_NUMBER "1"
+ WHITESPACE " "
+ SHL "<<"
+ WHITESPACE " "
+ BIN_EXPR
+ LITERAL
+ INT_NUMBER "2"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "3"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BIN_EXPR
+ LITERAL
+ INT_NUMBER "1"
+ WHITESPACE " "
+ AMP "&"
+ WHITESPACE " "
+ BIN_EXPR
+ LITERAL
+ INT_NUMBER "2"
+ WHITESPACE " "
+ SHR ">>"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "3"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BIN_EXPR
+ LITERAL
+ INT_NUMBER "1"
+ WHITESPACE " "
+ CARET "^"
+ WHITESPACE " "
+ BIN_EXPR
+ LITERAL
+ INT_NUMBER "2"
+ WHITESPACE " "
+ AMP "&"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "3"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BIN_EXPR
+ LITERAL
+ INT_NUMBER "1"
+ WHITESPACE " "
+ PIPE "|"
+ WHITESPACE " "
+ BIN_EXPR
+ LITERAL
+ INT_NUMBER "2"
+ WHITESPACE " "
+ CARET "^"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "3"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BIN_EXPR
+ LITERAL
+ INT_NUMBER "1"
+ WHITESPACE " "
+ EQ2 "=="
+ WHITESPACE " "
+ BIN_EXPR
+ LITERAL
+ INT_NUMBER "2"
+ WHITESPACE " "
+ PIPE "|"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "3"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BIN_EXPR
+ LITERAL
+ INT_NUMBER "1"
+ WHITESPACE " "
+ AMP2 "&&"
+ WHITESPACE " "
+ BIN_EXPR
+ LITERAL
+ INT_NUMBER "2"
+ WHITESPACE " "
+ EQ2 "=="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "3"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ COMMENT "//1 || 2 && 2;"
+ WHITESPACE "\n "
+ COMMENT "//1 .. 2 || 3;"
+ WHITESPACE "\n "
+ COMMENT "//1 = 2 .. 3;"
+ WHITESPACE "\n "
+ COMMENT "//---&*1 - --2 * 9;"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0028_operator_binding_power.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0028_operator_binding_power.rs
new file mode 100644
index 000000000..cc9598470
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0028_operator_binding_power.rs
@@ -0,0 +1,14 @@
+fn binding_power() {
+ let x = 1 + 2 * 3 % 4 - 5 / 6;
+ 1 + 2 * 3;
+ 1 << 2 + 3;
+ 1 & 2 >> 3;
+ 1 ^ 2 & 3;
+ 1 | 2 ^ 3;
+ 1 == 2 | 3;
+ 1 && 2 == 3;
+ //1 || 2 && 2;
+ //1 .. 2 || 3;
+ //1 = 2 .. 3;
+ //---&*1 - --2 * 9;
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0029_range_forms.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0029_range_forms.rast
new file mode 100644
index 000000000..5acc54e71
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0029_range_forms.rast
@@ -0,0 +1,152 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ RANGE_EXPR
+ DOT2 ".."
+ BIN_EXPR
+ LITERAL
+ INT_NUMBER "1"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "1"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BIN_EXPR
+ RANGE_EXPR
+ DOT2 ".."
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "z"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "2"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BIN_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "x"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ RANGE_EXPR
+ LITERAL
+ FALSE_KW "false"
+ DOT2 ".."
+ BIN_EXPR
+ LITERAL
+ INT_NUMBER "1"
+ WHITESPACE " "
+ EQ2 "=="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "1"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "x"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ RANGE_EXPR
+ LITERAL
+ INT_NUMBER "1"
+ DOT2 ".."
+ SEMICOLON ";"
+ WHITESPACE "\n \n "
+ EXPR_STMT
+ RANGE_EXPR
+ DOT2EQ "..="
+ BIN_EXPR
+ LITERAL
+ INT_NUMBER "1"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "1"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BIN_EXPR
+ RANGE_EXPR
+ DOT2EQ "..="
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "z"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "2"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BIN_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "x"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ RANGE_EXPR
+ LITERAL
+ FALSE_KW "false"
+ DOT2EQ "..="
+ BIN_EXPR
+ LITERAL
+ INT_NUMBER "1"
+ WHITESPACE " "
+ EQ2 "=="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "1"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "x"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ RANGE_EXPR
+ LITERAL
+ INT_NUMBER "1"
+ DOT2 ".."
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0029_range_forms.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0029_range_forms.rs
new file mode 100644
index 000000000..f9ff444d4
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0029_range_forms.rs
@@ -0,0 +1,11 @@
+fn foo() {
+ ..1 + 1;
+ ..z = 2;
+ x = false..1 == 1;
+ let x = 1..;
+
+ ..=1 + 1;
+ ..=z = 2;
+ x = false..=1 == 1;
+ let x = 1..;
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0030_string_suffixes.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0030_string_suffixes.rast
new file mode 100644
index 000000000..44211c7c4
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0030_string_suffixes.rast
@@ -0,0 +1,64 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ CHAR "'c'u32"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ STRING "\"string\"invalid"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ BYTE "b'b'_suff"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ BYTE_STRING "b\"bs\"invalid"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0030_string_suffixes.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0030_string_suffixes.rs
new file mode 100644
index 000000000..261aad1fb
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0030_string_suffixes.rs
@@ -0,0 +1,6 @@
+fn main() {
+ let _ = 'c'u32;
+ let _ = "string"invalid;
+ let _ = b'b'_suff;
+ let _ = b"bs"invalid;
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0030_traits.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0030_traits.rast
new file mode 100644
index 000000000..44423581e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0030_traits.rast
@@ -0,0 +1,61 @@
+SOURCE_FILE
+ TRAIT
+ TRAIT_KW "trait"
+ WHITESPACE " "
+ NAME
+ IDENT "Runnable"
+ WHITESPACE " "
+ ASSOC_ITEM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "handler"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ TRAIT
+ TRAIT_KW "trait"
+ WHITESPACE " "
+ NAME
+ IDENT "TraitWithExpr"
+ WHITESPACE " "
+ ASSOC_ITEM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "fn_with_expr"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "x"
+ COLON ":"
+ WHITESPACE " "
+ ARRAY_TYPE
+ L_BRACK "["
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ SEMICOLON ";"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "1"
+ R_BRACK "]"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0030_traits.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0030_traits.rs
new file mode 100644
index 000000000..ac30843ef
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0030_traits.rs
@@ -0,0 +1,7 @@
+trait Runnable {
+ fn handler();
+}
+
+trait TraitWithExpr {
+ fn fn_with_expr(x: [i32; 1]);
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0031_extern.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0031_extern.rast
new file mode 100644
index 000000000..70b527808
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0031_extern.rast
@@ -0,0 +1,973 @@
+SOURCE_FILE
+ EXTERN_BLOCK
+ ABI
+ EXTERN_KW "extern"
+ WHITESPACE " "
+ EXTERN_ITEM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ FN
+ VISIBILITY
+ PUB_KW "pub"
+ WHITESPACE " "
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "socket"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "domain"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "c_int"
+ COMMA ","
+ WHITESPACE " "
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "ty"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "c_int"
+ COMMA ","
+ WHITESPACE " "
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "protocol"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "c_int"
+ R_PAREN ")"
+ WHITESPACE " "
+ RET_TYPE
+ THIN_ARROW "->"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "c_int"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ FN
+ VISIBILITY
+ PUB_KW "pub"
+ WHITESPACE " "
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "bind"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "fd"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "c_int"
+ COMMA ","
+ WHITESPACE " "
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "addr"
+ COLON ":"
+ WHITESPACE " "
+ PTR_TYPE
+ STAR "*"
+ CONST_KW "const"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "sockaddr"
+ COMMA ","
+ WHITESPACE " "
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "len"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "socklen_t"
+ R_PAREN ")"
+ WHITESPACE " "
+ RET_TYPE
+ THIN_ARROW "->"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "c_int"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ FN
+ VISIBILITY
+ PUB_KW "pub"
+ WHITESPACE " "
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "connect"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "socket"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "c_int"
+ COMMA ","
+ WHITESPACE " "
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "address"
+ COLON ":"
+ WHITESPACE " "
+ PTR_TYPE
+ STAR "*"
+ CONST_KW "const"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "sockaddr"
+ COMMA ","
+ WHITESPACE "\n "
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "len"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "socklen_t"
+ R_PAREN ")"
+ WHITESPACE " "
+ RET_TYPE
+ THIN_ARROW "->"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "c_int"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ FN
+ VISIBILITY
+ PUB_KW "pub"
+ WHITESPACE " "
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "listen"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "socket"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "c_int"
+ COMMA ","
+ WHITESPACE " "
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "backlog"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "c_int"
+ R_PAREN ")"
+ WHITESPACE " "
+ RET_TYPE
+ THIN_ARROW "->"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "c_int"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ FN
+ VISIBILITY
+ PUB_KW "pub"
+ WHITESPACE " "
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "getsockname"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "socket"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "c_int"
+ COMMA ","
+ WHITESPACE " "
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "address"
+ COLON ":"
+ WHITESPACE " "
+ PTR_TYPE
+ STAR "*"
+ MUT_KW "mut"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "sockaddr"
+ COMMA ","
+ WHITESPACE "\n "
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "address_len"
+ COLON ":"
+ WHITESPACE " "
+ PTR_TYPE
+ STAR "*"
+ MUT_KW "mut"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "socklen_t"
+ R_PAREN ")"
+ WHITESPACE " "
+ RET_TYPE
+ THIN_ARROW "->"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "c_int"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ FN
+ VISIBILITY
+ PUB_KW "pub"
+ WHITESPACE " "
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "getsockopt"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "sockfd"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "c_int"
+ COMMA ","
+ WHITESPACE "\n "
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "level"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "c_int"
+ COMMA ","
+ WHITESPACE "\n "
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "optname"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "c_int"
+ COMMA ","
+ WHITESPACE "\n "
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "optval"
+ COLON ":"
+ WHITESPACE " "
+ PTR_TYPE
+ STAR "*"
+ MUT_KW "mut"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "c_void"
+ COMMA ","
+ WHITESPACE "\n "
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "optlen"
+ COLON ":"
+ WHITESPACE " "
+ PTR_TYPE
+ STAR "*"
+ MUT_KW "mut"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "socklen_t"
+ R_PAREN ")"
+ WHITESPACE " "
+ RET_TYPE
+ THIN_ARROW "->"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "c_int"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ FN
+ VISIBILITY
+ PUB_KW "pub"
+ WHITESPACE " "
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "setsockopt"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "socket"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "c_int"
+ COMMA ","
+ WHITESPACE " "
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "level"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "c_int"
+ COMMA ","
+ WHITESPACE " "
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "name"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "c_int"
+ COMMA ","
+ WHITESPACE "\n "
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "value"
+ COLON ":"
+ WHITESPACE " "
+ PTR_TYPE
+ STAR "*"
+ CONST_KW "const"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "c_void"
+ COMMA ","
+ WHITESPACE "\n "
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "option_len"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "socklen_t"
+ R_PAREN ")"
+ WHITESPACE " "
+ RET_TYPE
+ THIN_ARROW "->"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "c_int"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ FN
+ VISIBILITY
+ PUB_KW "pub"
+ WHITESPACE " "
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "getpeername"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "socket"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "c_int"
+ COMMA ","
+ WHITESPACE " "
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "address"
+ COLON ":"
+ WHITESPACE " "
+ PTR_TYPE
+ STAR "*"
+ MUT_KW "mut"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "sockaddr"
+ COMMA ","
+ WHITESPACE "\n "
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "address_len"
+ COLON ":"
+ WHITESPACE " "
+ PTR_TYPE
+ STAR "*"
+ MUT_KW "mut"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "socklen_t"
+ R_PAREN ")"
+ WHITESPACE " "
+ RET_TYPE
+ THIN_ARROW "->"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "c_int"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ FN
+ VISIBILITY
+ PUB_KW "pub"
+ WHITESPACE " "
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "sendto"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "socket"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "c_int"
+ COMMA ","
+ WHITESPACE " "
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "buf"
+ COLON ":"
+ WHITESPACE " "
+ PTR_TYPE
+ STAR "*"
+ CONST_KW "const"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "c_void"
+ COMMA ","
+ WHITESPACE " "
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "len"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "size_t"
+ COMMA ","
+ WHITESPACE "\n "
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "flags"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "c_int"
+ COMMA ","
+ WHITESPACE " "
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "addr"
+ COLON ":"
+ WHITESPACE " "
+ PTR_TYPE
+ STAR "*"
+ CONST_KW "const"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "sockaddr"
+ COMMA ","
+ WHITESPACE "\n "
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "addrlen"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "socklen_t"
+ R_PAREN ")"
+ WHITESPACE " "
+ RET_TYPE
+ THIN_ARROW "->"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "ssize_t"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ FN
+ VISIBILITY
+ PUB_KW "pub"
+ WHITESPACE " "
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "send"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "socket"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "c_int"
+ COMMA ","
+ WHITESPACE " "
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "buf"
+ COLON ":"
+ WHITESPACE " "
+ PTR_TYPE
+ STAR "*"
+ CONST_KW "const"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "c_void"
+ COMMA ","
+ WHITESPACE " "
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "len"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "size_t"
+ COMMA ","
+ WHITESPACE "\n "
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "flags"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "c_int"
+ R_PAREN ")"
+ WHITESPACE " "
+ RET_TYPE
+ THIN_ARROW "->"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "ssize_t"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ FN
+ VISIBILITY
+ PUB_KW "pub"
+ WHITESPACE " "
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "recvfrom"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "socket"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "c_int"
+ COMMA ","
+ WHITESPACE " "
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "buf"
+ COLON ":"
+ WHITESPACE " "
+ PTR_TYPE
+ STAR "*"
+ MUT_KW "mut"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "c_void"
+ COMMA ","
+ WHITESPACE " "
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "len"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "size_t"
+ COMMA ","
+ WHITESPACE "\n "
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "flags"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "c_int"
+ COMMA ","
+ WHITESPACE " "
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "addr"
+ COLON ":"
+ WHITESPACE " "
+ PTR_TYPE
+ STAR "*"
+ MUT_KW "mut"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "sockaddr"
+ COMMA ","
+ WHITESPACE "\n "
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "addrlen"
+ COLON ":"
+ WHITESPACE " "
+ PTR_TYPE
+ STAR "*"
+ MUT_KW "mut"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "socklen_t"
+ R_PAREN ")"
+ WHITESPACE " "
+ RET_TYPE
+ THIN_ARROW "->"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "ssize_t"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ FN
+ VISIBILITY
+ PUB_KW "pub"
+ WHITESPACE " "
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "recv"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "socket"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "c_int"
+ COMMA ","
+ WHITESPACE " "
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "buf"
+ COLON ":"
+ WHITESPACE " "
+ PTR_TYPE
+ STAR "*"
+ MUT_KW "mut"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "c_void"
+ COMMA ","
+ WHITESPACE " "
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "len"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "size_t"
+ COMMA ","
+ WHITESPACE "\n "
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "flags"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "c_int"
+ R_PAREN ")"
+ WHITESPACE " "
+ RET_TYPE
+ THIN_ARROW "->"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "ssize_t"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0031_extern.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0031_extern.rs
new file mode 100644
index 000000000..b33ac273c
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0031_extern.rs
@@ -0,0 +1,29 @@
+extern {
+ pub fn socket(domain: ::c_int, ty: ::c_int, protocol: ::c_int) -> ::c_int;
+ pub fn bind(fd: ::c_int, addr: *const sockaddr, len: socklen_t) -> ::c_int;
+ pub fn connect(socket: ::c_int, address: *const sockaddr,
+ len: socklen_t) -> ::c_int;
+ pub fn listen(socket: ::c_int, backlog: ::c_int) -> ::c_int;
+ pub fn getsockname(socket: ::c_int, address: *mut sockaddr,
+ address_len: *mut socklen_t) -> ::c_int;
+ pub fn getsockopt(sockfd: ::c_int,
+ level: ::c_int,
+ optname: ::c_int,
+ optval: *mut ::c_void,
+ optlen: *mut ::socklen_t) -> ::c_int;
+ pub fn setsockopt(socket: ::c_int, level: ::c_int, name: ::c_int,
+ value: *const ::c_void,
+ option_len: socklen_t) -> ::c_int;
+ pub fn getpeername(socket: ::c_int, address: *mut sockaddr,
+ address_len: *mut socklen_t) -> ::c_int;
+ pub fn sendto(socket: ::c_int, buf: *const ::c_void, len: ::size_t,
+ flags: ::c_int, addr: *const sockaddr,
+ addrlen: socklen_t) -> ::ssize_t;
+ pub fn send(socket: ::c_int, buf: *const ::c_void, len: ::size_t,
+ flags: ::c_int) -> ::ssize_t;
+ pub fn recvfrom(socket: ::c_int, buf: *mut ::c_void, len: ::size_t,
+ flags: ::c_int, addr: *mut ::sockaddr,
+ addrlen: *mut ::socklen_t) -> ::ssize_t;
+ pub fn recv(socket: ::c_int, buf: *mut ::c_void, len: ::size_t,
+ flags: ::c_int) -> ::ssize_t;
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0032_where_for.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0032_where_for.rast
new file mode 100644
index 000000000..86f6af97c
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0032_where_for.rast
@@ -0,0 +1,93 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "test_serialization"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "SER"
+ R_ANGLE ">"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE "\n"
+ WHERE_CLAUSE
+ WHERE_KW "where"
+ WHITESPACE "\n "
+ WHERE_PRED
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "SER"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Serialize"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ TYPE_BOUND
+ FOR_TYPE
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'de"
+ R_ANGLE ">"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Deserialize"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ LIFETIME_ARG
+ LIFETIME
+ LIFETIME_IDENT "'de"
+ R_ANGLE ">"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "PartialEq"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "std"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "fmt"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Debug"
+ COMMA ","
+ WHITESPACE "\n"
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0032_where_for.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0032_where_for.rs
new file mode 100644
index 000000000..588170fbe
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0032_where_for.rs
@@ -0,0 +1,4 @@
+fn test_serialization<SER>()
+where
+ SER: Serialize + for<'de> Deserialize<'de> + PartialEq + std::fmt::Debug,
+{}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0033_label_break.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0033_label_break.rast
new file mode 100644
index 000000000..df1acd6b8
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0033_label_break.rast
@@ -0,0 +1,223 @@
+SOURCE_FILE
+ FN
+ COMMENT "// format with label break value."
+ WHITESPACE "\n"
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BLOCK_EXPR
+ LABEL
+ LIFETIME
+ LIFETIME_IDENT "'empty_block"
+ COLON ":"
+ WHITESPACE " "
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n\n "
+ EXPR_STMT
+ BLOCK_EXPR
+ LABEL
+ LIFETIME
+ LIFETIME_IDENT "'block"
+ COLON ":"
+ WHITESPACE " "
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "do_thing"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ IF_EXPR
+ IF_KW "if"
+ WHITESPACE " "
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "condition_not_met"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BREAK_EXPR
+ BREAK_KW "break"
+ WHITESPACE " "
+ LIFETIME
+ LIFETIME_IDENT "'block"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "do_next_thing"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ IF_EXPR
+ IF_KW "if"
+ WHITESPACE " "
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "condition_not_met"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BREAK_EXPR
+ BREAK_KW "break"
+ WHITESPACE " "
+ LIFETIME
+ LIFETIME_IDENT "'block"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "do_last_thing"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "result"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ BLOCK_EXPR
+ LABEL
+ LIFETIME
+ LIFETIME_IDENT "'block"
+ COLON ":"
+ WHITESPACE " "
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ IF_EXPR
+ IF_KW "if"
+ WHITESPACE " "
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "foo"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ COMMENT "// comment"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BREAK_EXPR
+ BREAK_KW "break"
+ WHITESPACE " "
+ LIFETIME
+ LIFETIME_IDENT "'block"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "1"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n "
+ EXPR_STMT
+ IF_EXPR
+ IF_KW "if"
+ WHITESPACE " "
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "bar"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ COMMENT "/* comment */"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BREAK_EXPR
+ BREAK_KW "break"
+ WHITESPACE " "
+ LIFETIME
+ LIFETIME_IDENT "'block"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "2"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n "
+ LITERAL
+ INT_NUMBER "3"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0033_label_break.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0033_label_break.rs
new file mode 100644
index 000000000..728d78137
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0033_label_break.rs
@@ -0,0 +1,28 @@
+// format with label break value.
+fn main() {
+ 'empty_block: {}
+
+ 'block: {
+ do_thing();
+ if condition_not_met() {
+ break 'block;
+ }
+ do_next_thing();
+ if condition_not_met() {
+ break 'block;
+ }
+ do_last_thing();
+ }
+
+ let result = 'block: {
+ if foo() {
+ // comment
+ break 'block 1;
+ }
+ if bar() {
+ /* comment */
+ break 'block 2;
+ }
+ 3
+ };
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0034_crate_path_in_call.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0034_crate_path_in_call.rast
new file mode 100644
index 000000000..2b3b86ebf
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0034_crate_path_in_call.rast
@@ -0,0 +1,43 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "make_query"
+ ARG_LIST
+ L_PAREN "("
+ PATH_EXPR
+ PATH
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ CRATE_KW "crate"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "module_map"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "module_tree"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0034_crate_path_in_call.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0034_crate_path_in_call.rs
new file mode 100644
index 000000000..f1ed30220
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0034_crate_path_in_call.rs
@@ -0,0 +1,3 @@
+fn main() {
+ make_query(crate::module_map::module_tree);
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0035_weird_exprs.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0035_weird_exprs.rast
new file mode 100644
index 000000000..318d492ab
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0035_weird_exprs.rast
@@ -0,0 +1,2339 @@
+SOURCE_FILE
+ COMMENT "//! Adapted from a `rustc` test, which can be found at "
+ WHITESPACE "\n"
+ COMMENT "//! https://github.com/rust-lang/rust/blob/6d34ec18c7d7e574553f6347ecf08e1e1c45c13d/src/test/run-pass/weird-exprs.rs."
+ WHITESPACE "\n"
+ COMMENT "//! "
+ WHITESPACE "\n"
+ COMMENT "//! Reported to rust-analyzer in https://github.com/rust-lang/rust-analyzer/issues/290"
+ WHITESPACE "\n\n"
+ ATTR
+ POUND "#"
+ BANG "!"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "allow"
+ TOKEN_TREE
+ L_PAREN "("
+ IDENT "non_camel_case_types"
+ R_PAREN ")"
+ R_BRACK "]"
+ WHITESPACE "\n"
+ ATTR
+ POUND "#"
+ BANG "!"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "allow"
+ TOKEN_TREE
+ L_PAREN "("
+ IDENT "dead_code"
+ R_PAREN ")"
+ R_BRACK "]"
+ WHITESPACE "\n"
+ ATTR
+ POUND "#"
+ BANG "!"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "allow"
+ TOKEN_TREE
+ L_PAREN "("
+ IDENT "unreachable_code"
+ R_PAREN ")"
+ R_BRACK "]"
+ WHITESPACE "\n"
+ ATTR
+ POUND "#"
+ BANG "!"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "allow"
+ TOKEN_TREE
+ L_PAREN "("
+ IDENT "unused_parens"
+ R_PAREN ")"
+ R_BRACK "]"
+ WHITESPACE "\n\n"
+ ATTR
+ POUND "#"
+ BANG "!"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "recursion_limit"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ STRING "\"128\""
+ R_BRACK "]"
+ WHITESPACE "\n\n"
+ USE
+ USE_KW "use"
+ WHITESPACE " "
+ USE_TREE
+ PATH
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "std"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "cell"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Cell"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ USE
+ USE_KW "use"
+ WHITESPACE " "
+ USE_TREE
+ PATH
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "std"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "mem"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "swap"
+ SEMICOLON ";"
+ WHITESPACE "\n\n"
+ COMMENT "// Just a grab bag of stuff that you wouldn't want to actually write."
+ WHITESPACE "\n\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "strange"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ RET_TYPE
+ THIN_ARROW "->"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "bool"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "_x"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "bool"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ RETURN_EXPR
+ RETURN_KW "return"
+ WHITESPACE " "
+ LITERAL
+ TRUE_KW "true"
+ SEMICOLON ";"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "funny"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "f"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "_x"
+ COLON ":"
+ WHITESPACE " "
+ TUPLE_TYPE
+ L_PAREN "("
+ R_PAREN ")"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "f"
+ ARG_LIST
+ L_PAREN "("
+ RETURN_EXPR
+ RETURN_KW "return"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "what"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "the"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "x"
+ COLON ":"
+ WHITESPACE " "
+ REF_TYPE
+ AMP "&"
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Cell"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ TYPE_ARG
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "bool"
+ R_ANGLE ">"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ RETURN_EXPR
+ RETURN_KW "return"
+ WHITESPACE " "
+ WHILE_EXPR
+ WHILE_KW "while"
+ WHITESPACE " "
+ PREFIX_EXPR
+ BANG "!"
+ METHOD_CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "x"
+ DOT "."
+ NAME_REF
+ IDENT "get"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ EXPR_STMT
+ METHOD_CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "x"
+ DOT "."
+ NAME_REF
+ IDENT "set"
+ ARG_LIST
+ L_PAREN "("
+ LITERAL
+ TRUE_KW "true"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE " "
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "i"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ REF_EXPR
+ AMP "&"
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Cell"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "new"
+ ARG_LIST
+ L_PAREN "("
+ LITERAL
+ FALSE_KW "false"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "dont"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ CLOSURE_EXPR
+ PARAM_LIST
+ PIPE "|"
+ PIPE "|"
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "the"
+ ARG_LIST
+ L_PAREN "("
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i"
+ R_PAREN ")"
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "dont"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ MACRO_EXPR
+ MACRO_CALL
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "assert"
+ BANG "!"
+ TOKEN_TREE
+ L_PAREN "("
+ TOKEN_TREE
+ L_PAREN "("
+ IDENT "i"
+ DOT "."
+ IDENT "get"
+ TOKEN_TREE
+ L_PAREN "("
+ R_PAREN ")"
+ R_PAREN ")"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "zombiejesus"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ LOOP_EXPR
+ LOOP_KW "loop"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ WHILE_EXPR
+ WHILE_KW "while"
+ WHITESPACE " "
+ PAREN_EXPR
+ L_PAREN "("
+ RETURN_EXPR
+ RETURN_KW "return"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ IF_EXPR
+ IF_KW "if"
+ WHITESPACE " "
+ PAREN_EXPR
+ L_PAREN "("
+ RETURN_EXPR
+ RETURN_KW "return"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ MATCH_EXPR
+ MATCH_KW "match"
+ WHITESPACE " "
+ PAREN_EXPR
+ L_PAREN "("
+ RETURN_EXPR
+ RETURN_KW "return"
+ R_PAREN ")"
+ WHITESPACE " "
+ MATCH_ARM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ MATCH_ARM
+ LITERAL_PAT
+ LITERAL
+ INT_NUMBER "1"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ IF_EXPR
+ IF_KW "if"
+ WHITESPACE " "
+ PAREN_EXPR
+ L_PAREN "("
+ RETURN_EXPR
+ RETURN_KW "return"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ RETURN_EXPR
+ RETURN_KW "return"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE " "
+ ELSE_KW "else"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ RETURN_EXPR
+ RETURN_KW "return"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n "
+ MATCH_ARM
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ RETURN_EXPR
+ RETURN_KW "return"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE " "
+ ELSE_KW "else"
+ WHITESPACE " "
+ IF_EXPR
+ IF_KW "if"
+ WHITESPACE " "
+ PAREN_EXPR
+ L_PAREN "("
+ RETURN_EXPR
+ RETURN_KW "return"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ RETURN_EXPR
+ RETURN_KW "return"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n "
+ IF_EXPR
+ IF_KW "if"
+ WHITESPACE " "
+ PAREN_EXPR
+ L_PAREN "("
+ RETURN_EXPR
+ RETURN_KW "return"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ EXPR_STMT
+ BREAK_EXPR
+ BREAK_KW "break"
+ SEMICOLON ";"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "notsure"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ MUT_KW "mut"
+ WHITESPACE " "
+ NAME
+ IDENT "_x"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "isize"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ MUT_KW "mut"
+ WHITESPACE " "
+ NAME
+ IDENT "_y"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ BIN_EXPR
+ PAREN_EXPR
+ L_PAREN "("
+ BIN_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "_x"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "0"
+ R_PAREN ")"
+ WHITESPACE " "
+ EQ2 "=="
+ WHITESPACE " "
+ PAREN_EXPR
+ L_PAREN "("
+ BIN_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "_x"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "0"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ MUT_KW "mut"
+ WHITESPACE " "
+ NAME
+ IDENT "_z"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ BIN_EXPR
+ PAREN_EXPR
+ L_PAREN "("
+ BIN_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "_x"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "0"
+ R_PAREN ")"
+ WHITESPACE " "
+ L_ANGLE "<"
+ WHITESPACE " "
+ PAREN_EXPR
+ L_PAREN "("
+ BIN_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "_x"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "0"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "_a"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ BIN_EXPR
+ PAREN_EXPR
+ L_PAREN "("
+ BIN_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "_x"
+ WHITESPACE " "
+ PLUSEQ "+="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "0"
+ R_PAREN ")"
+ WHITESPACE " "
+ EQ2 "=="
+ WHITESPACE " "
+ PAREN_EXPR
+ L_PAREN "("
+ BIN_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "_x"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "0"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "_b"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ BIN_EXPR
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "swap"
+ ARG_LIST
+ L_PAREN "("
+ REF_EXPR
+ AMP "&"
+ MUT_KW "mut"
+ WHITESPACE " "
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "_y"
+ COMMA ","
+ WHITESPACE " "
+ REF_EXPR
+ AMP "&"
+ MUT_KW "mut"
+ WHITESPACE " "
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "_z"
+ R_PAREN ")"
+ WHITESPACE " "
+ EQ2 "=="
+ WHITESPACE " "
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "swap"
+ ARG_LIST
+ L_PAREN "("
+ REF_EXPR
+ AMP "&"
+ MUT_KW "mut"
+ WHITESPACE " "
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "_y"
+ COMMA ","
+ WHITESPACE " "
+ REF_EXPR
+ AMP "&"
+ MUT_KW "mut"
+ WHITESPACE " "
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "_z"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "canttouchthis"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ RET_TYPE
+ THIN_ARROW "->"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "usize"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "p"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ RET_TYPE
+ THIN_ARROW "->"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "bool"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ LITERAL
+ TRUE_KW "true"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "_a"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ PAREN_EXPR
+ L_PAREN "("
+ BIN_EXPR
+ MACRO_EXPR
+ MACRO_CALL
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "assert"
+ BANG "!"
+ TOKEN_TREE
+ L_PAREN "("
+ TOKEN_TREE
+ L_PAREN "("
+ TRUE_KW "true"
+ R_PAREN ")"
+ R_PAREN ")"
+ WHITESPACE " "
+ EQ2 "=="
+ WHITESPACE " "
+ PAREN_EXPR
+ L_PAREN "("
+ MACRO_EXPR
+ MACRO_CALL
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "assert"
+ BANG "!"
+ TOKEN_TREE
+ L_PAREN "("
+ IDENT "p"
+ TOKEN_TREE
+ L_PAREN "("
+ R_PAREN ")"
+ R_PAREN ")"
+ R_PAREN ")"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "_c"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ PAREN_EXPR
+ L_PAREN "("
+ BIN_EXPR
+ MACRO_EXPR
+ MACRO_CALL
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "assert"
+ BANG "!"
+ TOKEN_TREE
+ L_PAREN "("
+ TOKEN_TREE
+ L_PAREN "("
+ IDENT "p"
+ TOKEN_TREE
+ L_PAREN "("
+ R_PAREN ")"
+ R_PAREN ")"
+ R_PAREN ")"
+ WHITESPACE " "
+ EQ2 "=="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "_b"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "bool"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ PAREN_EXPR
+ L_PAREN "("
+ BIN_EXPR
+ MACRO_EXPR
+ MACRO_CALL
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "println"
+ BANG "!"
+ TOKEN_TREE
+ L_PAREN "("
+ STRING "\"{}\""
+ COMMA ","
+ WHITESPACE " "
+ INT_NUMBER "0"
+ R_PAREN ")"
+ WHITESPACE " "
+ EQ2 "=="
+ WHITESPACE " "
+ PAREN_EXPR
+ L_PAREN "("
+ RETURN_EXPR
+ RETURN_KW "return"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "0"
+ R_PAREN ")"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "angrydome"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ LOOP_EXPR
+ LOOP_KW "loop"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ IF_EXPR
+ IF_KW "if"
+ WHITESPACE " "
+ BREAK_EXPR
+ BREAK_KW "break"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ MUT_KW "mut"
+ WHITESPACE " "
+ NAME
+ IDENT "i"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "0"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LOOP_EXPR
+ LOOP_KW "loop"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ EXPR_STMT
+ BIN_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i"
+ WHITESPACE " "
+ PLUSEQ "+="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "1"
+ SEMICOLON ";"
+ WHITESPACE " "
+ EXPR_STMT
+ IF_EXPR
+ IF_KW "if"
+ WHITESPACE " "
+ BIN_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i"
+ WHITESPACE " "
+ EQ2 "=="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "1"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ MATCH_EXPR
+ MATCH_KW "match"
+ WHITESPACE " "
+ PAREN_EXPR
+ L_PAREN "("
+ CONTINUE_EXPR
+ CONTINUE_KW "continue"
+ R_PAREN ")"
+ WHITESPACE " "
+ MATCH_ARM_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ MATCH_ARM
+ LITERAL_PAT
+ LITERAL
+ INT_NUMBER "1"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ R_CURLY "}"
+ COMMA ","
+ WHITESPACE " "
+ MATCH_ARM
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ MACRO_EXPR
+ MACRO_CALL
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "panic"
+ BANG "!"
+ TOKEN_TREE
+ L_PAREN "("
+ STRING "\"wat\""
+ R_PAREN ")"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BREAK_EXPR
+ BREAK_KW "break"
+ SEMICOLON ";"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "evil_lincoln"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "_evil"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ MACRO_EXPR
+ MACRO_CALL
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "println"
+ BANG "!"
+ TOKEN_TREE
+ L_PAREN "("
+ STRING "\"lincoln\""
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "dots"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ MACRO_EXPR
+ MACRO_CALL
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "assert_eq"
+ BANG "!"
+ TOKEN_TREE
+ L_PAREN "("
+ IDENT "String"
+ COLON ":"
+ COLON ":"
+ IDENT "from"
+ TOKEN_TREE
+ L_PAREN "("
+ STRING "\"..................................................\""
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n "
+ IDENT "format"
+ BANG "!"
+ TOKEN_TREE
+ L_PAREN "("
+ STRING "\"{:?}\""
+ COMMA ","
+ WHITESPACE " "
+ DOT "."
+ DOT "."
+ WHITESPACE " "
+ DOT "."
+ DOT "."
+ WHITESPACE " "
+ DOT "."
+ DOT "."
+ WHITESPACE " "
+ DOT "."
+ DOT "."
+ WHITESPACE " "
+ DOT "."
+ DOT "."
+ WHITESPACE " "
+ DOT "."
+ DOT "."
+ WHITESPACE " "
+ DOT "."
+ DOT "."
+ WHITESPACE " "
+ DOT "."
+ DOT "."
+ WHITESPACE " "
+ DOT "."
+ DOT "."
+ WHITESPACE " "
+ DOT "."
+ DOT "."
+ WHITESPACE " "
+ DOT "."
+ DOT "."
+ WHITESPACE " "
+ DOT "."
+ DOT "."
+ WHITESPACE " "
+ DOT "."
+ DOT "."
+ WHITESPACE "\n "
+ DOT "."
+ DOT "."
+ WHITESPACE " "
+ DOT "."
+ DOT "."
+ WHITESPACE " "
+ DOT "."
+ DOT "."
+ WHITESPACE " "
+ DOT "."
+ DOT "."
+ WHITESPACE " "
+ DOT "."
+ DOT "."
+ WHITESPACE " "
+ DOT "."
+ DOT "."
+ WHITESPACE " "
+ DOT "."
+ DOT "."
+ WHITESPACE " "
+ DOT "."
+ DOT "."
+ WHITESPACE " "
+ DOT "."
+ DOT "."
+ WHITESPACE " "
+ DOT "."
+ DOT "."
+ WHITESPACE " "
+ DOT "."
+ DOT "."
+ WHITESPACE " "
+ DOT "."
+ DOT "."
+ R_PAREN ")"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "u8"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "u8"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u8"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ IF_EXPR
+ IF_KW "if"
+ WHITESPACE " "
+ BIN_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u8"
+ WHITESPACE " "
+ NEQ "!="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "0u8"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ MACRO_EXPR
+ MACRO_CALL
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "assert_eq"
+ BANG "!"
+ TOKEN_TREE
+ L_PAREN "("
+ INT_NUMBER "8u8"
+ COMMA ","
+ WHITESPACE " "
+ TOKEN_TREE
+ L_CURLY "{"
+ WHITESPACE "\n "
+ IDENT "macro_rules"
+ BANG "!"
+ WHITESPACE " "
+ IDENT "u8"
+ WHITESPACE " "
+ TOKEN_TREE
+ L_CURLY "{"
+ WHITESPACE "\n "
+ TOKEN_TREE
+ L_PAREN "("
+ IDENT "u8"
+ R_PAREN ")"
+ WHITESPACE " "
+ EQ "="
+ R_ANGLE ">"
+ WHITESPACE " "
+ TOKEN_TREE
+ L_CURLY "{"
+ WHITESPACE "\n "
+ MOD_KW "mod"
+ WHITESPACE " "
+ IDENT "u8"
+ WHITESPACE " "
+ TOKEN_TREE
+ L_CURLY "{"
+ WHITESPACE "\n "
+ PUB_KW "pub"
+ WHITESPACE " "
+ FN_KW "fn"
+ WHITESPACE " "
+ IDENT "u8"
+ L_ANGLE "<"
+ LIFETIME_IDENT "'u8"
+ COLON ":"
+ WHITESPACE " "
+ LIFETIME_IDENT "'u8"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ LIFETIME_IDENT "'u8"
+ R_ANGLE ">"
+ TOKEN_TREE
+ L_PAREN "("
+ IDENT "u8"
+ COLON ":"
+ WHITESPACE " "
+ AMP "&"
+ LIFETIME_IDENT "'u8"
+ WHITESPACE " "
+ IDENT "u8"
+ R_PAREN ")"
+ WHITESPACE " "
+ MINUS "-"
+ R_ANGLE ">"
+ WHITESPACE " "
+ AMP "&"
+ LIFETIME_IDENT "'u8"
+ WHITESPACE " "
+ IDENT "u8"
+ WHITESPACE " "
+ TOKEN_TREE
+ L_CURLY "{"
+ WHITESPACE "\n "
+ STRING "\"u8\""
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ IDENT "u8"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n\n "
+ IDENT "u8"
+ BANG "!"
+ TOKEN_TREE
+ L_PAREN "("
+ IDENT "u8"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_KW "let"
+ WHITESPACE " "
+ AMP "&"
+ IDENT "u8"
+ COLON ":"
+ WHITESPACE " "
+ AMP "&"
+ IDENT "u8"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ IDENT "u8"
+ COLON ":"
+ COLON ":"
+ IDENT "u8"
+ TOKEN_TREE
+ L_PAREN "("
+ AMP "&"
+ INT_NUMBER "8u8"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ CRATE_KW "crate"
+ COLON ":"
+ COLON ":"
+ IDENT "u8"
+ TOKEN_TREE
+ L_PAREN "("
+ INT_NUMBER "0u8"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ IDENT "u8"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "fishy"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ MACRO_EXPR
+ MACRO_CALL
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "assert_eq"
+ BANG "!"
+ TOKEN_TREE
+ L_PAREN "("
+ IDENT "String"
+ COLON ":"
+ COLON ":"
+ IDENT "from"
+ TOKEN_TREE
+ L_PAREN "("
+ STRING "\"><>\""
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n "
+ IDENT "String"
+ COLON ":"
+ COLON ":"
+ L_ANGLE "<"
+ R_ANGLE ">"
+ COLON ":"
+ COLON ":"
+ IDENT "from"
+ COLON ":"
+ COLON ":"
+ L_ANGLE "<"
+ R_ANGLE ">"
+ TOKEN_TREE
+ L_PAREN "("
+ STRING "\"><>\""
+ R_PAREN ")"
+ DOT "."
+ IDENT "chars"
+ COLON ":"
+ COLON ":"
+ L_ANGLE "<"
+ R_ANGLE ">"
+ TOKEN_TREE
+ L_PAREN "("
+ R_PAREN ")"
+ DOT "."
+ IDENT "rev"
+ COLON ":"
+ COLON ":"
+ L_ANGLE "<"
+ R_ANGLE ">"
+ TOKEN_TREE
+ L_PAREN "("
+ R_PAREN ")"
+ DOT "."
+ IDENT "collect"
+ COLON ":"
+ COLON ":"
+ L_ANGLE "<"
+ IDENT "String"
+ R_ANGLE ">"
+ TOKEN_TREE
+ L_PAREN "("
+ R_PAREN ")"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "union"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ UNION
+ UNION_KW "union"
+ WHITESPACE " "
+ NAME
+ IDENT "union"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'union"
+ R_ANGLE ">"
+ WHITESPACE " "
+ RECORD_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ RECORD_FIELD
+ NAME
+ IDENT "union"
+ COLON ":"
+ WHITESPACE " "
+ REF_TYPE
+ AMP "&"
+ LIFETIME
+ LIFETIME_IDENT "'union"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "union"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ LIFETIME_ARG
+ LIFETIME
+ LIFETIME_IDENT "'union"
+ R_ANGLE ">"
+ COMMA ","
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "special_characters"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "val"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ PREFIX_EXPR
+ BANG "!"
+ PAREN_EXPR
+ L_PAREN "("
+ BIN_EXPR
+ CALL_EXPR
+ PAREN_EXPR
+ L_PAREN "("
+ CLOSURE_EXPR
+ PARAM_LIST
+ PIPE "|"
+ PARAM
+ TUPLE_PAT
+ L_PAREN "("
+ REST_PAT
+ DOT2 ".."
+ R_PAREN ")"
+ COLON ":"
+ TUPLE_TYPE
+ L_PAREN "("
+ INFER_TYPE
+ UNDERSCORE "_"
+ COMMA ","
+ INFER_TYPE
+ UNDERSCORE "_"
+ R_PAREN ")"
+ COMMA ","
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "__"
+ AT "@"
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ PIPE "|"
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "__"
+ R_PAREN ")"
+ ARG_LIST
+ L_PAREN "("
+ TUPLE_EXPR
+ L_PAREN "("
+ REF_EXPR
+ AMP "&"
+ PREFIX_EXPR
+ STAR "*"
+ LITERAL
+ STRING "\"\\\\\""
+ COMMA ","
+ LITERAL
+ CHAR "'🤔'"
+ R_PAREN ")"
+ COMMENT "/**/"
+ COMMA ","
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ R_PAREN ")"
+ EQ2 "=="
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ EXPR_STMT
+ REF_EXPR
+ AMP "&"
+ INDEX_EXPR
+ ARRAY_EXPR
+ L_BRACK "["
+ RANGE_EXPR
+ DOT2EQ "..="
+ RANGE_EXPR
+ DOT2 ".."
+ R_BRACK "]"
+ L_BRACK "["
+ RANGE_EXPR
+ DOT2 ".."
+ R_BRACK "]"
+ SEMICOLON ";"
+ R_CURLY "}"
+ R_PAREN ")"
+ COMMENT "//"
+ WHITESPACE "\n "
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ MACRO_EXPR
+ MACRO_CALL
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "assert"
+ BANG "!"
+ TOKEN_TREE
+ L_PAREN "("
+ BANG "!"
+ IDENT "val"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "punch_card"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ RET_TYPE
+ THIN_ARROW "->"
+ WHITESPACE " "
+ IMPL_TRAIT_TYPE
+ IMPL_KW "impl"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "std"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "fmt"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Debug"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ RANGE_EXPR
+ DOT2EQ "..="
+ RANGE_EXPR
+ DOT2EQ "..="
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2EQ "..="
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE "\n "
+ RANGE_EXPR
+ DOT2EQ "..="
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2EQ "..="
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2EQ "..="
+ RANGE_EXPR
+ DOT2EQ "..="
+ RANGE_EXPR
+ DOT2EQ "..="
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE "\n "
+ RANGE_EXPR
+ DOT2EQ "..="
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2EQ "..="
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2EQ "..="
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2EQ "..="
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2EQ "..="
+ RANGE_EXPR
+ DOT2EQ "..="
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2EQ "..="
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE "\n "
+ RANGE_EXPR
+ DOT2EQ "..="
+ RANGE_EXPR
+ DOT2EQ "..="
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2EQ "..="
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2EQ "..="
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2EQ "..="
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2EQ "..="
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE "\n "
+ RANGE_EXPR
+ DOT2EQ "..="
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2EQ "..="
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2EQ "..="
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2EQ "..="
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2EQ "..="
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2EQ "..="
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE "\n "
+ RANGE_EXPR
+ DOT2EQ "..="
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2EQ "..="
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2EQ "..="
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2EQ "..="
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2EQ "..="
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2EQ "..="
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE "\n "
+ RANGE_EXPR
+ DOT2EQ "..="
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2EQ "..="
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2EQ "..="
+ RANGE_EXPR
+ DOT2EQ "..="
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2EQ "..="
+ RANGE_EXPR
+ DOT2EQ "..="
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2EQ "..="
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "ktulhu"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ SEMICOLON ";"
+ SEMICOLON ";"
+ SEMICOLON ";"
+ EXPR_STMT
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ SEMICOLON ";"
+ SEMICOLON ";"
+ SEMICOLON ";"
+ SEMICOLON ";"
+ SEMICOLON ";"
+ SEMICOLON ";"
+ SEMICOLON ";"
+ SEMICOLON ";"
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ FN
+ VISIBILITY
+ PUB_KW "pub"
+ WHITESPACE " "
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "strange"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "funny"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "what"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "zombiejesus"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "notsure"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "canttouchthis"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "angrydome"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "evil_lincoln"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "dots"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u8"
+ ARG_LIST
+ L_PAREN "("
+ LITERAL
+ INT_NUMBER "8u8"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "fishy"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "union"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "special_characters"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "punch_card"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "ktulhu"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0035_weird_exprs.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0035_weird_exprs.rs
new file mode 100644
index 000000000..fb7d706b0
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0035_weird_exprs.rs
@@ -0,0 +1,154 @@
+//! Adapted from a `rustc` test, which can be found at
+//! https://github.com/rust-lang/rust/blob/6d34ec18c7d7e574553f6347ecf08e1e1c45c13d/src/test/run-pass/weird-exprs.rs.
+//!
+//! Reported to rust-analyzer in https://github.com/rust-lang/rust-analyzer/issues/290
+
+#![allow(non_camel_case_types)]
+#![allow(dead_code)]
+#![allow(unreachable_code)]
+#![allow(unused_parens)]
+
+#![recursion_limit = "128"]
+
+use std::cell::Cell;
+use std::mem::swap;
+
+// Just a grab bag of stuff that you wouldn't want to actually write.
+
+fn strange() -> bool { let _x: bool = return true; }
+
+fn funny() {
+ fn f(_x: ()) { }
+ f(return);
+}
+
+fn what() {
+ fn the(x: &Cell<bool>) {
+ return while !x.get() { x.set(true); };
+ }
+ let i = &Cell::new(false);
+ let dont = {||the(i)};
+ dont();
+ assert!((i.get()));
+}
+
+fn zombiejesus() {
+ loop {
+ while (return) {
+ if (return) {
+ match (return) {
+ 1 => {
+ if (return) {
+ return
+ } else {
+ return
+ }
+ }
+ _ => { return }
+ };
+ } else if (return) {
+ return;
+ }
+ }
+ if (return) { break; }
+ }
+}
+
+fn notsure() {
+ let mut _x: isize;
+ let mut _y = (_x = 0) == (_x = 0);
+ let mut _z = (_x = 0) < (_x = 0);
+ let _a = (_x += 0) == (_x = 0);
+ let _b = swap(&mut _y, &mut _z) == swap(&mut _y, &mut _z);
+}
+
+fn canttouchthis() -> usize {
+ fn p() -> bool { true }
+ let _a = (assert!((true)) == (assert!(p())));
+ let _c = (assert!((p())) == ());
+ let _b: bool = (println!("{}", 0) == (return 0));
+}
+
+fn angrydome() {
+ loop { if break { } }
+ let mut i = 0;
+ loop { i += 1; if i == 1 { match (continue) { 1 => { }, _ => panic!("wat") } }
+ break; }
+}
+
+fn evil_lincoln() { let _evil = println!("lincoln"); }
+
+fn dots() {
+ assert_eq!(String::from(".................................................."),
+ format!("{:?}", .. .. .. .. .. .. .. .. .. .. .. .. ..
+ .. .. .. .. .. .. .. .. .. .. .. ..));
+}
+
+fn u8(u8: u8) {
+ if u8 != 0u8 {
+ assert_eq!(8u8, {
+ macro_rules! u8 {
+ (u8) => {
+ mod u8 {
+ pub fn u8<'u8: 'u8 + 'u8>(u8: &'u8 u8) -> &'u8 u8 {
+ "u8";
+ u8
+ }
+ }
+ };
+ }
+
+ u8!(u8);
+ let &u8: &u8 = u8::u8(&8u8);
+ crate::u8(0u8);
+ u8
+ });
+ }
+}
+
+fn fishy() {
+ assert_eq!(String::from("><>"),
+ String::<>::from::<>("><>").chars::<>().rev::<>().collect::<String>());
+}
+
+fn union() {
+ union union<'union> { union: &'union union<'union>, }
+}
+
+fn special_characters() {
+ let val = !((|(..):(_,_),__@_|__)((&*"\\",'🤔')/**/,{})=={&[..=..][..];})//
+ ;
+ assert!(!val);
+}
+
+fn punch_card() -> impl std::fmt::Debug {
+ ..=..=.. .. .. .. .. .. .. .. .. .. .. ..=.. ..
+ ..=.. ..=.. .. .. .. .. .. .. .. .. ..=..=..=..
+ ..=.. ..=.. ..=.. ..=.. .. ..=..=.. .. ..=.. ..
+ ..=..=.. .. ..=.. ..=.. ..=.. .. .. .. ..=.. ..
+ ..=.. ..=.. ..=.. ..=.. .. ..=.. .. .. ..=.. ..
+ ..=.. ..=.. ..=.. ..=.. .. .. ..=.. .. ..=.. ..
+ ..=.. ..=.. .. ..=..=.. ..=..=.. .. .. ..=.. ..
+}
+
+fn ktulhu() {
+ ;;;();;;;;;;;;()
+}
+
+pub fn main() {
+ strange();
+ funny();
+ what();
+ zombiejesus();
+ notsure();
+ canttouchthis();
+ angrydome();
+ evil_lincoln();
+ dots();
+ u8(8u8);
+ fishy();
+ union();
+ special_characters();
+ punch_card();
+ ktulhu();
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0036_fully_qualified.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0036_fully_qualified.rast
new file mode 100644
index 000000000..9382020e2
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0036_fully_qualified.rast
@@ -0,0 +1,93 @@
+SOURCE_FILE
+ COMMENT "// https://github.com/rust-lang/rust-analyzer/issues/311"
+ WHITESPACE "\n\n"
+ FN
+ VISIBILITY
+ PUB_KW "pub"
+ WHITESPACE " "
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "S"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Iterator"
+ R_ANGLE ">"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ RET_TYPE
+ THIN_ARROW "->"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "String"
+ WHITESPACE "\n"
+ WHERE_CLAUSE
+ WHERE_KW "where"
+ WHITESPACE "\n "
+ WHERE_PRED
+ PATH_TYPE
+ PATH
+ PATH
+ PATH_SEGMENT
+ L_ANGLE "<"
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ WHITESPACE " "
+ AS_KW "as"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Iterator"
+ R_ANGLE ">"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Item"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Eq"
+ COMMA ","
+ WHITESPACE "\n"
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ METHOD_CALL_EXPR
+ LITERAL
+ STRING "\"\""
+ DOT "."
+ NAME_REF
+ IDENT "to_owned"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0036_fully_qualified.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0036_fully_qualified.rs
new file mode 100644
index 000000000..f8a085dc7
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0036_fully_qualified.rs
@@ -0,0 +1,8 @@
+// https://github.com/rust-lang/rust-analyzer/issues/311
+
+pub fn foo<S: Iterator>() -> String
+where
+ <S as Iterator>::Item: Eq,
+{
+ "".to_owned()
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0037_mod.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0037_mod.rast
new file mode 100644
index 000000000..b4a3fc629
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0037_mod.rast
@@ -0,0 +1,16 @@
+SOURCE_FILE
+ COMMENT "// https://github.com/rust-lang/rust-analyzer/issues/357"
+ WHITESPACE "\n\n"
+ COMMENT "//! docs"
+ WHITESPACE "\n"
+ MODULE
+ COMMENT "// non-docs"
+ WHITESPACE "\n"
+ MOD_KW "mod"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ WHITESPACE " "
+ ITEM_LIST
+ L_CURLY "{"
+ R_CURLY "}"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0037_mod.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0037_mod.rs
new file mode 100644
index 000000000..05f6cf05c
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0037_mod.rs
@@ -0,0 +1,5 @@
+// https://github.com/rust-lang/rust-analyzer/issues/357
+
+//! docs
+// non-docs
+mod foo {} \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0038_where_pred_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0038_where_pred_type.rast
new file mode 100644
index 000000000..e89763042
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0038_where_pred_type.rast
@@ -0,0 +1,43 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "test"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ WHERE_CLAUSE
+ WHERE_KW "where"
+ WHITESPACE " "
+ WHERE_PRED
+ TUPLE_TYPE
+ L_PAREN "("
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u64"
+ COMMA ","
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u64"
+ R_PAREN ")"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Foo"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0038_where_pred_type.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0038_where_pred_type.rs
new file mode 100644
index 000000000..8bfc341a5
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0038_where_pred_type.rs
@@ -0,0 +1 @@
+fn test() where (u64, u64): Foo {} \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0039_raw_fn_item.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0039_raw_fn_item.rast
new file mode 100644
index 000000000..2eeed781c
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0039_raw_fn_item.rast
@@ -0,0 +1,16 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "r#foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0039_raw_fn_item.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0039_raw_fn_item.rs
new file mode 100644
index 000000000..8380d1e79
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0039_raw_fn_item.rs
@@ -0,0 +1,2 @@
+fn r#foo() {
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0040_raw_struct_item_field.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0040_raw_struct_item_field.rast
new file mode 100644
index 000000000..ceb918420
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0040_raw_struct_item_field.rast
@@ -0,0 +1,22 @@
+SOURCE_FILE
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ RECORD_FIELD
+ NAME
+ IDENT "r#foo"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u32"
+ WHITESPACE "\n"
+ R_CURLY "}"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0040_raw_struct_item_field.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0040_raw_struct_item_field.rs
new file mode 100644
index 000000000..098a60a72
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0040_raw_struct_item_field.rs
@@ -0,0 +1,3 @@
+struct S {
+ r#foo: u32
+} \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0041_raw_keywords.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0041_raw_keywords.rast
new file mode 100644
index 000000000..dacf0ce74
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0041_raw_keywords.rast
@@ -0,0 +1,50 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "r#struct"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "92"
+ SEMICOLON ";"
+ WHITESPACE " "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "r#trait"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ BIN_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "r#struct"
+ WHITESPACE " "
+ STAR "*"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "2"
+ SEMICOLON ";"
+ WHITESPACE " "
+ R_CURLY "}"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0041_raw_keywords.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0041_raw_keywords.rs
new file mode 100644
index 000000000..d59a6d347
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0041_raw_keywords.rs
@@ -0,0 +1 @@
+fn foo() { let r#struct = 92; let r#trait = r#struct * 2; } \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0042_ufcs_call_list.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0042_ufcs_call_list.rast
new file mode 100644
index 000000000..a536b0e88
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0042_ufcs_call_list.rast
@@ -0,0 +1,127 @@
+SOURCE_FILE
+ COMMENT "// https://github.com/rust-lang/rust-analyzer/issues/596"
+ WHITESPACE "\n\n"
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "Foo"
+ SEMICOLON ";"
+ WHITESPACE "\n\n"
+ IMPL
+ IMPL_KW "impl"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Foo"
+ WHITESPACE " "
+ ASSOC_ITEM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "bar"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ RET_TYPE
+ THIN_ARROW "->"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "bool"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ MACRO_EXPR
+ MACRO_CALL
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "unimplemented"
+ BANG "!"
+ TOKEN_TREE
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "baz"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "bool"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "baz"
+ ARG_LIST
+ L_PAREN "("
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH
+ PATH_SEGMENT
+ L_ANGLE "<"
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Foo"
+ R_ANGLE ">"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "bar"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ R_PAREN ")"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0042_ufcs_call_list.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0042_ufcs_call_list.rs
new file mode 100644
index 000000000..09b18982e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0042_ufcs_call_list.rs
@@ -0,0 +1,15 @@
+// https://github.com/rust-lang/rust-analyzer/issues/596
+
+struct Foo;
+
+impl Foo {
+ fn bar() -> bool {
+ unimplemented!()
+ }
+}
+
+fn baz(_: bool) {}
+
+fn main() {
+ baz(<Foo>::bar())
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0043_complex_assignment.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0043_complex_assignment.rast
new file mode 100644
index 000000000..3b02c3f96
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0043_complex_assignment.rast
@@ -0,0 +1,110 @@
+SOURCE_FILE
+ COMMENT "// https://github.com/rust-lang/rust-analyzer/issues/674"
+ WHITESPACE "\n\n"
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "Repr"
+ WHITESPACE " "
+ RECORD_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ RECORD_FIELD
+ NAME
+ IDENT "raw"
+ COLON ":"
+ WHITESPACE " "
+ ARRAY_TYPE
+ L_BRACK "["
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u8"
+ SEMICOLON ";"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "1"
+ R_BRACK "]"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "abc"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BIN_EXPR
+ INDEX_EXPR
+ FIELD_EXPR
+ RECORD_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Repr"
+ WHITESPACE " "
+ RECORD_EXPR_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ RECORD_EXPR_FIELD
+ NAME_REF
+ IDENT "raw"
+ COLON ":"
+ WHITESPACE " "
+ ARRAY_EXPR
+ L_BRACK "["
+ LITERAL
+ INT_NUMBER "0"
+ R_BRACK "]"
+ WHITESPACE " "
+ R_CURLY "}"
+ DOT "."
+ NAME_REF
+ IDENT "raw"
+ L_BRACK "["
+ LITERAL
+ INT_NUMBER "0"
+ R_BRACK "]"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "0"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CALL_EXPR
+ RECORD_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Repr"
+ RECORD_EXPR_FIELD_LIST
+ L_CURLY "{"
+ RECORD_EXPR_FIELD
+ NAME_REF
+ IDENT "raw"
+ COLON ":"
+ ARRAY_EXPR
+ L_BRACK "["
+ LITERAL
+ INT_NUMBER "0"
+ R_BRACK "]"
+ R_CURLY "}"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0043_complex_assignment.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0043_complex_assignment.rs
new file mode 100644
index 000000000..961dc8c7d
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0043_complex_assignment.rs
@@ -0,0 +1,8 @@
+// https://github.com/rust-lang/rust-analyzer/issues/674
+
+struct Repr { raw: [u8; 1] }
+
+fn abc() {
+ Repr { raw: [0] }.raw[0] = 0;
+ Repr{raw:[0]}();
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0044_let_attrs.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0044_let_attrs.rast
new file mode 100644
index 000000000..f3c20337e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0044_let_attrs.rast
@@ -0,0 +1,77 @@
+SOURCE_FILE
+ FN
+ COMMENT "// https://github.com/rust-lang/rust-analyzer/issues/677"
+ WHITESPACE "\n"
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ LET_STMT
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "cfg"
+ TOKEN_TREE
+ L_PAREN "("
+ IDENT "feature"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ STRING "\"backtrace\""
+ R_PAREN ")"
+ R_BRACK "]"
+ WHITESPACE "\n "
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "exit_code"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "panic"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "catch_unwind"
+ ARG_LIST
+ L_PAREN "("
+ CLOSURE_EXPR
+ MOVE_KW "move"
+ WHITESPACE " "
+ PARAM_LIST
+ PIPE "|"
+ PIPE "|"
+ WHITESPACE " "
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "main"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0044_let_attrs.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0044_let_attrs.rs
new file mode 100644
index 000000000..7d1524879
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0044_let_attrs.rs
@@ -0,0 +1,5 @@
+// https://github.com/rust-lang/rust-analyzer/issues/677
+fn main() {
+ #[cfg(feature = "backtrace")]
+ let exit_code = panic::catch_unwind(move || main());
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0045_block_attrs.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0045_block_attrs.rast
new file mode 100644
index 000000000..bef138071
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0045_block_attrs.rast
@@ -0,0 +1,230 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "inner"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ ATTR
+ POUND "#"
+ BANG "!"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "doc"
+ TOKEN_TREE
+ L_PAREN "("
+ STRING "\"Inner attributes allowed here\""
+ R_PAREN ")"
+ R_BRACK "]"
+ WHITESPACE "\n "
+ COMMENT "//! As are ModuleDoc style comments"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ ATTR
+ POUND "#"
+ BANG "!"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "doc"
+ TOKEN_TREE
+ L_PAREN "("
+ STRING "\"Inner attributes are allowed in blocks used as statements\""
+ R_PAREN ")"
+ R_BRACK "]"
+ WHITESPACE "\n "
+ ATTR
+ POUND "#"
+ BANG "!"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "doc"
+ TOKEN_TREE
+ L_PAREN "("
+ STRING "\"Being validated is not affected by duplcates\""
+ R_PAREN ")"
+ R_BRACK "]"
+ WHITESPACE "\n "
+ COMMENT "//! As are ModuleDoc style comments"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ ATTR
+ POUND "#"
+ BANG "!"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "doc"
+ TOKEN_TREE
+ L_PAREN "("
+ STRING "\"Inner attributes are allowed in blocks when they are the last statement of another block\""
+ R_PAREN ")"
+ R_BRACK "]"
+ WHITESPACE "\n "
+ COMMENT "//! As are ModuleDoc style comments"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "outer"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ BLOCK_EXPR
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "doc"
+ TOKEN_TREE
+ L_PAREN "("
+ STRING "\"Outer attributes are always allowed\""
+ R_PAREN ")"
+ R_BRACK "]"
+ WHITESPACE " "
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ IMPL
+ COMMENT "// https://github.com/rust-lang/rust-analyzer/issues/689"
+ WHITESPACE "\n"
+ IMPL_KW "impl"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Whatever"
+ WHITESPACE " "
+ ASSOC_ITEM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "salsa_event"
+ PARAM_LIST
+ L_PAREN "("
+ SELF_PARAM
+ AMP "&"
+ NAME
+ SELF_KW "self"
+ COMMA ","
+ WHITESPACE " "
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "event_fn"
+ COLON ":"
+ WHITESPACE " "
+ IMPL_TRAIT_TYPE
+ IMPL_KW "impl"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Fn"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ RET_TYPE
+ THIN_ARROW "->"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Event"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ TYPE_ARG
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ SELF_TYPE_KW "Self"
+ R_ANGLE ">"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ ATTR
+ POUND "#"
+ BANG "!"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "allow"
+ TOKEN_TREE
+ L_PAREN "("
+ IDENT "unused_variables"
+ R_PAREN ")"
+ R_BRACK "]"
+ WHITESPACE " "
+ COMMENT "// this is `inner_attr` of the block"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0045_block_attrs.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0045_block_attrs.rs
new file mode 100644
index 000000000..f16c4566e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0045_block_attrs.rs
@@ -0,0 +1,24 @@
+fn inner() {
+ #![doc("Inner attributes allowed here")]
+ //! As are ModuleDoc style comments
+ {
+ #![doc("Inner attributes are allowed in blocks used as statements")]
+ #![doc("Being validated is not affected by duplcates")]
+ //! As are ModuleDoc style comments
+ };
+ {
+ #![doc("Inner attributes are allowed in blocks when they are the last statement of another block")]
+ //! As are ModuleDoc style comments
+ }
+}
+
+fn outer() {
+ let _ = #[doc("Outer attributes are always allowed")] {};
+}
+
+// https://github.com/rust-lang/rust-analyzer/issues/689
+impl Whatever {
+ fn salsa_event(&self, event_fn: impl Fn() -> Event<Self>) {
+ #![allow(unused_variables)] // this is `inner_attr` of the block
+ }
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0046_extern_inner_attributes.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0046_extern_inner_attributes.rast
new file mode 100644
index 000000000..4eb51cfdf
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0046_extern_inner_attributes.rast
@@ -0,0 +1,29 @@
+SOURCE_FILE
+ EXTERN_BLOCK
+ ABI
+ EXTERN_KW "extern"
+ WHITESPACE " "
+ STRING "\"C\""
+ WHITESPACE " "
+ EXTERN_ITEM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ COMMENT "//! This is a doc comment"
+ WHITESPACE "\n "
+ ATTR
+ POUND "#"
+ BANG "!"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "doc"
+ TOKEN_TREE
+ L_PAREN "("
+ STRING "\"This is also a doc comment\""
+ R_PAREN ")"
+ R_BRACK "]"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0046_extern_inner_attributes.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0046_extern_inner_attributes.rs
new file mode 100644
index 000000000..fe67e2df4
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0046_extern_inner_attributes.rs
@@ -0,0 +1,4 @@
+extern "C" {
+ //! This is a doc comment
+ #![doc("This is also a doc comment")]
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0047_minus_in_inner_pattern.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0047_minus_in_inner_pattern.rast
new file mode 100644
index 000000000..c7eb3687d
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0047_minus_in_inner_pattern.rast
@@ -0,0 +1,323 @@
+SOURCE_FILE
+ COMMENT "// https://github.com/rust-lang/rust-analyzer/issues/972"
+ WHITESPACE "\n\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ MATCH_EXPR
+ MATCH_KW "match"
+ WHITESPACE " "
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Some"
+ ARG_LIST
+ L_PAREN "("
+ PREFIX_EXPR
+ MINUS "-"
+ LITERAL
+ INT_NUMBER "1"
+ R_PAREN ")"
+ WHITESPACE " "
+ MATCH_ARM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ MATCH_ARM
+ TUPLE_STRUCT_PAT
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Some"
+ L_PAREN "("
+ LITERAL_PAT
+ MINUS "-"
+ LITERAL
+ INT_NUMBER "1"
+ R_PAREN ")"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n "
+ MATCH_ARM
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n\n "
+ EXPR_STMT
+ MATCH_EXPR
+ MATCH_KW "match"
+ WHITESPACE " "
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Some"
+ ARG_LIST
+ L_PAREN "("
+ TUPLE_EXPR
+ L_PAREN "("
+ PREFIX_EXPR
+ MINUS "-"
+ LITERAL
+ INT_NUMBER "1"
+ COMMA ","
+ WHITESPACE " "
+ PREFIX_EXPR
+ MINUS "-"
+ LITERAL
+ INT_NUMBER "1"
+ R_PAREN ")"
+ R_PAREN ")"
+ WHITESPACE " "
+ MATCH_ARM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ MATCH_ARM
+ TUPLE_STRUCT_PAT
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Some"
+ L_PAREN "("
+ TUPLE_PAT
+ L_PAREN "("
+ LITERAL_PAT
+ MINUS "-"
+ LITERAL
+ INT_NUMBER "1"
+ COMMA ","
+ WHITESPACE " "
+ LITERAL_PAT
+ MINUS "-"
+ LITERAL
+ INT_NUMBER "1"
+ R_PAREN ")"
+ R_PAREN ")"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n "
+ MATCH_ARM
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n\n "
+ EXPR_STMT
+ MATCH_EXPR
+ MATCH_KW "match"
+ WHITESPACE " "
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "A"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "B"
+ ARG_LIST
+ L_PAREN "("
+ PREFIX_EXPR
+ MINUS "-"
+ LITERAL
+ INT_NUMBER "1"
+ COMMA ","
+ WHITESPACE " "
+ PREFIX_EXPR
+ MINUS "-"
+ LITERAL
+ INT_NUMBER "1"
+ R_PAREN ")"
+ WHITESPACE " "
+ MATCH_ARM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ MATCH_ARM
+ TUPLE_STRUCT_PAT
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "A"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "B"
+ L_PAREN "("
+ LITERAL_PAT
+ MINUS "-"
+ LITERAL
+ INT_NUMBER "1"
+ COMMA ","
+ WHITESPACE " "
+ LITERAL_PAT
+ MINUS "-"
+ LITERAL
+ INT_NUMBER "1"
+ R_PAREN ")"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n "
+ MATCH_ARM
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ FAT_ARROW "=>"
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n\n "
+ IF_EXPR
+ IF_KW "if"
+ WHITESPACE " "
+ LET_EXPR
+ LET_KW "let"
+ WHITESPACE " "
+ TUPLE_STRUCT_PAT
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Some"
+ L_PAREN "("
+ LITERAL_PAT
+ MINUS "-"
+ LITERAL
+ INT_NUMBER "1"
+ R_PAREN ")"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Some"
+ ARG_LIST
+ L_PAREN "("
+ PREFIX_EXPR
+ MINUS "-"
+ LITERAL
+ INT_NUMBER "1"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ ENUM
+ ENUM_KW "enum"
+ WHITESPACE " "
+ NAME
+ IDENT "A"
+ WHITESPACE " "
+ VARIANT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ VARIANT
+ NAME
+ IDENT "B"
+ TUPLE_FIELD_LIST
+ L_PAREN "("
+ TUPLE_FIELD
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i8"
+ COMMA ","
+ WHITESPACE " "
+ TUPLE_FIELD
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i8"
+ R_PAREN ")"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ RANGE_PAT
+ LITERAL_PAT
+ MINUS "-"
+ LITERAL
+ INT_NUMBER "128"
+ DOT2EQ "..="
+ LITERAL_PAT
+ LITERAL
+ INT_NUMBER "127"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i8"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0047_minus_in_inner_pattern.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0047_minus_in_inner_pattern.rs
new file mode 100644
index 000000000..13dc46afa
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0047_minus_in_inner_pattern.rs
@@ -0,0 +1,27 @@
+// https://github.com/rust-lang/rust-analyzer/issues/972
+
+fn main() {
+ match Some(-1) {
+ Some(-1) => (),
+ _ => (),
+ }
+
+ match Some((-1, -1)) {
+ Some((-1, -1)) => (),
+ _ => (),
+ }
+
+ match A::B(-1, -1) {
+ A::B(-1, -1) => (),
+ _ => (),
+ }
+
+ if let Some(-1) = Some(-1) {
+ }
+}
+
+enum A {
+ B(i8, i8)
+}
+
+fn foo(-128..=127: i8) {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0048_compound_assignment.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0048_compound_assignment.rast
new file mode 100644
index 000000000..e0f163b1a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0048_compound_assignment.rast
@@ -0,0 +1,201 @@
+SOURCE_FILE
+ COMMENT "// https://github.com/rust-lang/rust-analyzer/pull/983"
+ WHITESPACE "\n\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "compound_assignment"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ MUT_KW "mut"
+ WHITESPACE " "
+ NAME
+ IDENT "a"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "0"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BIN_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "a"
+ WHITESPACE " "
+ PLUSEQ "+="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "1"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BIN_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "a"
+ WHITESPACE " "
+ MINUSEQ "-="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "2"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BIN_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "a"
+ WHITESPACE " "
+ STAREQ "*="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "3"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BIN_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "a"
+ WHITESPACE " "
+ PERCENTEQ "%="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "4"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BIN_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "a"
+ WHITESPACE " "
+ SLASHEQ "/="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "5"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BIN_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "a"
+ WHITESPACE " "
+ PIPEEQ "|="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "6"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BIN_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "a"
+ WHITESPACE " "
+ AMPEQ "&="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "7"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BIN_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "a"
+ WHITESPACE " "
+ CARETEQ "^="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "8"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BIN_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "a"
+ WHITESPACE " "
+ LTEQ "<="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "9"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BIN_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "a"
+ WHITESPACE " "
+ GTEQ ">="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "10"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BIN_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "a"
+ WHITESPACE " "
+ SHREQ ">>="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "11"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BIN_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "a"
+ WHITESPACE " "
+ SHLEQ "<<="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "12"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0048_compound_assignment.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0048_compound_assignment.rs
new file mode 100644
index 000000000..1a6a9bdf5
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0048_compound_assignment.rs
@@ -0,0 +1,17 @@
+// https://github.com/rust-lang/rust-analyzer/pull/983
+
+fn compound_assignment() {
+ let mut a = 0;
+ a += 1;
+ a -= 2;
+ a *= 3;
+ a %= 4;
+ a /= 5;
+ a |= 6;
+ a &= 7;
+ a ^= 8;
+ a <= 9;
+ a >= 10;
+ a >>= 11;
+ a <<= 12;
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0049_async_block.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0049_async_block.rast
new file mode 100644
index 000000000..f376821e2
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0049_async_block.rast
@@ -0,0 +1,36 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BLOCK_EXPR
+ ASYNC_KW "async"
+ WHITESPACE " "
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BLOCK_EXPR
+ ASYNC_KW "async"
+ WHITESPACE " "
+ MOVE_KW "move"
+ WHITESPACE " "
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0049_async_block.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0049_async_block.rs
new file mode 100644
index 000000000..4781b3225
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0049_async_block.rs
@@ -0,0 +1,5 @@
+fn foo() {
+ async {};
+ async move {};
+}
+
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0050_async_block_as_argument.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0050_async_block_as_argument.rast
new file mode 100644
index 000000000..53ddf35cc
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0050_async_block_as_argument.rast
@@ -0,0 +1,92 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "x"
+ COLON ":"
+ WHITESPACE " "
+ IMPL_TRAIT_TYPE
+ IMPL_KW "impl"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "std"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "future"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Future"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ ASSOC_TYPE_ARG
+ NAME_REF
+ IDENT "Output"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ R_ANGLE ">"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "foo"
+ ARG_LIST
+ L_PAREN "("
+ BLOCK_EXPR
+ ASYNC_KW "async"
+ WHITESPACE " "
+ MOVE_KW "move"
+ WHITESPACE " "
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "12"
+ WHITESPACE " "
+ R_CURLY "}"
+ R_PAREN ")"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0050_async_block_as_argument.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0050_async_block_as_argument.rs
new file mode 100644
index 000000000..ec4612cff
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0050_async_block_as_argument.rs
@@ -0,0 +1,5 @@
+fn foo(x: impl std::future::Future<Output = i32>) {}
+
+fn main() {
+ foo(async move { 12 })
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0051_parameter_attrs.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0051_parameter_attrs.rast
new file mode 100644
index 000000000..f8b11e778
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0051_parameter_attrs.rast
@@ -0,0 +1,548 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "g1"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "attr1"
+ R_BRACK "]"
+ WHITESPACE " "
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "attr2"
+ R_BRACK "]"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "pat"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Type"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "g2"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "attr1"
+ R_BRACK "]"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "x"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u8"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ EXTERN_BLOCK
+ ABI
+ EXTERN_KW "extern"
+ WHITESPACE " "
+ STRING "\"C\""
+ WHITESPACE " "
+ EXTERN_ITEM_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "printf"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "format"
+ COLON ":"
+ WHITESPACE " "
+ PTR_TYPE
+ STAR "*"
+ CONST_KW "const"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i8"
+ COMMA ","
+ WHITESPACE " "
+ PARAM
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "attr"
+ R_BRACK "]"
+ WHITESPACE " "
+ DOT3 "..."
+ R_PAREN ")"
+ WHITESPACE " "
+ RET_TYPE
+ THIN_ARROW "->"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ SEMICOLON ";"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "F"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "FnMut"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "attr"
+ R_BRACK "]"
+ WHITESPACE " "
+ REF_TYPE
+ AMP "&"
+ MUT_KW "mut"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Foo"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ LIFETIME_ARG
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ R_PAREN ")"
+ R_ANGLE ">"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ TRAIT
+ TRAIT_KW "trait"
+ WHITESPACE " "
+ NAME
+ IDENT "Foo"
+ WHITESPACE " "
+ ASSOC_ITEM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "bar"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "attr"
+ R_BRACK "]"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u64"
+ COMMA ","
+ WHITESPACE " "
+ PARAM
+ ATTR
+ POUND "#"
+ WHITESPACE " "
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "attr"
+ R_BRACK "]"
+ WHITESPACE " "
+ IDENT_PAT
+ MUT_KW "mut"
+ WHITESPACE " "
+ NAME
+ IDENT "x"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ IMPL
+ IMPL_KW "impl"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ WHITESPACE " "
+ ASSOC_ITEM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "f"
+ PARAM_LIST
+ L_PAREN "("
+ SELF_PARAM
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "must_use"
+ R_BRACK "]"
+ WHITESPACE " "
+ NAME
+ SELF_KW "self"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "g1"
+ PARAM_LIST
+ L_PAREN "("
+ SELF_PARAM
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "attr"
+ R_BRACK "]"
+ WHITESPACE " "
+ NAME
+ SELF_KW "self"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "g2"
+ PARAM_LIST
+ L_PAREN "("
+ SELF_PARAM
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "attr"
+ R_BRACK "]"
+ WHITESPACE " "
+ AMP "&"
+ NAME
+ SELF_KW "self"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "g3"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ PARAM_LIST
+ L_PAREN "("
+ SELF_PARAM
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "attr"
+ R_BRACK "]"
+ WHITESPACE " "
+ AMP "&"
+ MUT_KW "mut"
+ WHITESPACE " "
+ NAME
+ SELF_KW "self"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "g4"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ PARAM_LIST
+ L_PAREN "("
+ SELF_PARAM
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "attr"
+ R_BRACK "]"
+ WHITESPACE " "
+ AMP "&"
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ WHITESPACE " "
+ NAME
+ SELF_KW "self"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "g5"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ PARAM_LIST
+ L_PAREN "("
+ SELF_PARAM
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "attr"
+ R_BRACK "]"
+ WHITESPACE " "
+ AMP "&"
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ WHITESPACE " "
+ MUT_KW "mut"
+ WHITESPACE " "
+ NAME
+ SELF_KW "self"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "c"
+ PARAM_LIST
+ L_PAREN "("
+ SELF_PARAM
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "attr"
+ R_BRACK "]"
+ WHITESPACE " "
+ NAME
+ SELF_KW "self"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ SELF_TYPE_KW "Self"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "d"
+ PARAM_LIST
+ L_PAREN "("
+ SELF_PARAM
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "attr"
+ R_BRACK "]"
+ WHITESPACE " "
+ NAME
+ SELF_KW "self"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Rc"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ TYPE_ARG
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ SELF_TYPE_KW "Self"
+ R_ANGLE ">"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0051_parameter_attrs.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0051_parameter_attrs.rs
new file mode 100644
index 000000000..de350d858
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0051_parameter_attrs.rs
@@ -0,0 +1,21 @@
+fn g1(#[attr1] #[attr2] pat: Type) {}
+fn g2(#[attr1] x: u8) {}
+
+extern "C" { fn printf(format: *const i8, #[attr] ...) -> i32; }
+
+fn foo<F: FnMut(#[attr] &mut Foo<'a>)>(){}
+
+trait Foo {
+ fn bar(#[attr] _: u64, # [attr] mut x: i32);
+}
+
+impl S {
+ fn f(#[must_use] self) {}
+ fn g1(#[attr] self) {}
+ fn g2(#[attr] &self) {}
+ fn g3<'a>(#[attr] &mut self) {}
+ fn g4<'a>(#[attr] &'a self) {}
+ fn g5<'a>(#[attr] &'a mut self) {}
+ fn c(#[attr] self: Self) {}
+ fn d(#[attr] self: Rc<Self>) {}
+} \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0052_for_range_block.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0052_for_range_block.rast
new file mode 100644
index 000000000..0c9dd432f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0052_for_range_block.rast
@@ -0,0 +1,81 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ FOR_EXPR
+ FOR_KW "for"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "_x"
+ WHITESPACE " "
+ IN_KW "in"
+ WHITESPACE " "
+ RANGE_EXPR
+ LITERAL
+ INT_NUMBER "0"
+ WHITESPACE " "
+ DOT2 ".."
+ WHITESPACE " "
+ METHOD_CALL_EXPR
+ PAREN_EXPR
+ L_PAREN "("
+ RANGE_EXPR
+ LITERAL
+ INT_NUMBER "0"
+ WHITESPACE " "
+ DOT2 ".."
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ BIN_EXPR
+ LITERAL
+ INT_NUMBER "1"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "2"
+ R_CURLY "}"
+ R_PAREN ")"
+ DOT "."
+ NAME_REF
+ IDENT "sum"
+ GENERIC_ARG_LIST
+ COLON2 "::"
+ L_ANGLE "<"
+ TYPE_ARG
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u32"
+ R_ANGLE ">"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BREAK_EXPR
+ BREAK_KW "break"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0052_for_range_block.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0052_for_range_block.rs
new file mode 100644
index 000000000..b51b19630
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0052_for_range_block.rs
@@ -0,0 +1,5 @@
+fn foo() {
+ for _x in 0 .. (0 .. {1 + 2}).sum::<u32>() {
+ break;
+ }
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0053_outer_attribute_on_macro_rules.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0053_outer_attribute_on_macro_rules.rast
new file mode 100644
index 000000000..b94d43beb
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0053_outer_attribute_on_macro_rules.rast
@@ -0,0 +1,37 @@
+SOURCE_FILE
+ MACRO_RULES
+ COMMENT "/// Some docs"
+ WHITESPACE "\n"
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "macro_export"
+ R_BRACK "]"
+ WHITESPACE "\n"
+ MACRO_RULES_KW "macro_rules"
+ BANG "!"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ WHITESPACE " "
+ TOKEN_TREE
+ L_CURLY "{"
+ WHITESPACE "\n "
+ TOKEN_TREE
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ EQ "="
+ R_ANGLE ">"
+ WHITESPACE " "
+ TOKEN_TREE
+ L_CURLY "{"
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0053_outer_attribute_on_macro_rules.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0053_outer_attribute_on_macro_rules.rs
new file mode 100644
index 000000000..b59c23c56
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0053_outer_attribute_on_macro_rules.rs
@@ -0,0 +1,5 @@
+/// Some docs
+#[macro_export]
+macro_rules! foo {
+ () => {};
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0054_qual_path_in_type_arg.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0054_qual_path_in_type_arg.rast
new file mode 100644
index 000000000..4e1e31f37
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0054_qual_path_in_type_arg.rast
@@ -0,0 +1,126 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "a"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ RET_TYPE
+ THIN_ARROW "->"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Foo"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ TYPE_ARG
+ PATH_TYPE
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "bar"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Baz"
+ R_ANGLE ">"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "b"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ COLON ":"
+ WHITESPACE " "
+ IMPL_TRAIT_TYPE
+ IMPL_KW "impl"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "FnMut"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ PATH_TYPE
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "x"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Y"
+ R_PAREN ")"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "c"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ COLON ":"
+ WHITESPACE " "
+ IMPL_TRAIT_TYPE
+ IMPL_KW "impl"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "FnMut"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ REF_TYPE
+ AMP "&"
+ PATH_TYPE
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "x"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Y"
+ R_PAREN ")"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0054_qual_path_in_type_arg.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0054_qual_path_in_type_arg.rs
new file mode 100644
index 000000000..0d3f5722a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0054_qual_path_in_type_arg.rs
@@ -0,0 +1,5 @@
+fn a() -> Foo<bar::Baz> {}
+
+fn b(_: impl FnMut(x::Y)) {}
+
+fn c(_: impl FnMut(&x::Y)) {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0055_dot_dot_dot.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0055_dot_dot_dot.rast
new file mode 100644
index 000000000..684f499df
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0055_dot_dot_dot.rast
@@ -0,0 +1,50 @@
+SOURCE_FILE
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "X"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_TYPE
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ TUPLE_PAT
+ L_PAREN "("
+ R_PAREN ")"
+ COLON ":"
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ COLON2 "::"
+ NAME_REF
+ IDENT "X"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0055_dot_dot_dot.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0055_dot_dot_dot.rs
new file mode 100644
index 000000000..cd204f65e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0055_dot_dot_dot.rs
@@ -0,0 +1,5 @@
+type X = ();
+
+fn main() {
+ let ():::X = ();
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0056_neq_in_type.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0056_neq_in_type.rast
new file mode 100644
index 000000000..55ce31275
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0056_neq_in_type.rast
@@ -0,0 +1,65 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ IF_EXPR
+ IF_KW "if"
+ WHITESPACE " "
+ BIN_EXPR
+ CAST_EXPR
+ METHOD_CALL_EXPR
+ LITERAL
+ FLOAT_NUMBER "1.0f32"
+ DOT "."
+ NAME_REF
+ IDENT "floor"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ AS_KW "as"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i64"
+ WHITESPACE " "
+ NEQ "!="
+ WHITESPACE " "
+ CAST_EXPR
+ METHOD_CALL_EXPR
+ LITERAL
+ FLOAT_NUMBER "1.0f32"
+ DOT "."
+ NAME_REF
+ IDENT "floor"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ AS_KW "as"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i64"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0056_neq_in_type.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0056_neq_in_type.rs
new file mode 100644
index 000000000..6210683ce
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0056_neq_in_type.rs
@@ -0,0 +1,3 @@
+fn main() {
+ if 1.0f32.floor() as i64 != 1.0f32.floor() as i64 {}
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0057_loop_in_call.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0057_loop_in_call.rast
new file mode 100644
index 000000000..67837e475
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0057_loop_in_call.rast
@@ -0,0 +1,59 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "x"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "foo"
+ ARG_LIST
+ L_PAREN "("
+ LOOP_EXPR
+ LOOP_KW "loop"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0057_loop_in_call.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0057_loop_in_call.rs
new file mode 100644
index 000000000..31c12522f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0057_loop_in_call.rs
@@ -0,0 +1,5 @@
+fn foo(x: i32) {}
+
+fn main() {
+ foo(loop {});
+} \ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0058_unary_expr_precedence.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0058_unary_expr_precedence.rast
new file mode 100644
index 000000000..683d5070a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0058_unary_expr_precedence.rast
@@ -0,0 +1,97 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BIN_EXPR
+ BIN_EXPR
+ LITERAL
+ INT_NUMBER "1"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ PREFIX_EXPR
+ STAR "*"
+ REF_EXPR
+ AMP "&"
+ LITERAL
+ INT_NUMBER "2"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "3"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CAST_EXPR
+ PREFIX_EXPR
+ STAR "*"
+ REF_EXPR
+ AMP "&"
+ LITERAL
+ INT_NUMBER "1"
+ WHITESPACE " "
+ AS_KW "as"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u64"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ PREFIX_EXPR
+ STAR "*"
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "x"
+ ARG_LIST
+ L_PAREN "("
+ LITERAL
+ INT_NUMBER "1"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ REF_EXPR
+ AMP "&"
+ INDEX_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "x"
+ L_BRACK "["
+ LITERAL
+ INT_NUMBER "1"
+ R_BRACK "]"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ RANGE_EXPR
+ PREFIX_EXPR
+ MINUS "-"
+ LITERAL
+ INT_NUMBER "1"
+ DOT2 ".."
+ LITERAL
+ INT_NUMBER "2"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0058_unary_expr_precedence.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0058_unary_expr_precedence.rs
new file mode 100644
index 000000000..100fccc64
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0058_unary_expr_precedence.rs
@@ -0,0 +1,7 @@
+fn foo() {
+ 1 + *&2 + 3;
+ *&1 as u64;
+ *x(1);
+ &x[1];
+ -1..2;
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0059_loops_in_parens.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0059_loops_in_parens.rast
new file mode 100644
index 000000000..79bc7f971
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0059_loops_in_parens.rast
@@ -0,0 +1,100 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Some"
+ ARG_LIST
+ L_PAREN "("
+ FOR_EXPR
+ FOR_KW "for"
+ WHITESPACE " "
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ WHITESPACE " "
+ IN_KW "in"
+ WHITESPACE " "
+ METHOD_CALL_EXPR
+ ARRAY_EXPR
+ L_BRACK "["
+ LITERAL
+ INT_NUMBER "1"
+ R_BRACK "]"
+ DOT "."
+ NAME_REF
+ IDENT "into_iter"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Some"
+ ARG_LIST
+ L_PAREN "("
+ LOOP_EXPR
+ LOOP_KW "loop"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ EXPR_STMT
+ BREAK_EXPR
+ BREAK_KW "break"
+ SEMICOLON ";"
+ WHITESPACE " "
+ R_CURLY "}"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Some"
+ ARG_LIST
+ L_PAREN "("
+ WHILE_EXPR
+ WHILE_KW "while"
+ WHITESPACE " "
+ LITERAL
+ TRUE_KW "true"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0059_loops_in_parens.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0059_loops_in_parens.rs
new file mode 100644
index 000000000..6e8b718aa
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0059_loops_in_parens.rs
@@ -0,0 +1,5 @@
+fn main() {
+ Some(for _ in [1].into_iter() {});
+ Some(loop { break; });
+ Some(while true {});
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0060_as_range.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0060_as_range.rast
new file mode 100644
index 000000000..81fc02b6f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0060_as_range.rast
@@ -0,0 +1,56 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ RANGE_EXPR
+ CAST_EXPR
+ LITERAL
+ INT_NUMBER "0"
+ WHITESPACE " "
+ AS_KW "as"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "usize"
+ WHITESPACE " "
+ DOT2 ".."
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ RANGE_EXPR
+ BIN_EXPR
+ LITERAL
+ INT_NUMBER "1"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ CAST_EXPR
+ LITERAL
+ INT_NUMBER "2"
+ WHITESPACE " "
+ AS_KW "as"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "usize"
+ WHITESPACE " "
+ DOT2 ".."
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0060_as_range.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0060_as_range.rs
new file mode 100644
index 000000000..f063ffadb
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0060_as_range.rs
@@ -0,0 +1,4 @@
+fn main() {
+ 0 as usize ..;
+ 1 + 2 as usize ..;
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0061_match_full_range.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0061_match_full_range.rast
new file mode 100644
index 000000000..2f56e9041
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0061_match_full_range.rast
@@ -0,0 +1,27 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ MATCH_EXPR
+ MATCH_KW "match"
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2 ".."
+ WHITESPACE " "
+ MATCH_ARM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0061_match_full_range.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0061_match_full_range.rs
new file mode 100644
index 000000000..2c4ed11e1
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0061_match_full_range.rs
@@ -0,0 +1,4 @@
+fn main() {
+ match .. {
+ }
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0062_macro_2.0.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0062_macro_2.0.rast
new file mode 100644
index 000000000..3915ed750
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0062_macro_2.0.rast
@@ -0,0 +1,177 @@
+SOURCE_FILE
+ MACRO_DEF
+ MACRO_KW "macro"
+ WHITESPACE " "
+ NAME
+ IDENT "parse_use_trees"
+ TOKEN_TREE
+ TOKEN_TREE
+ L_PAREN "("
+ DOLLAR "$"
+ TOKEN_TREE
+ L_PAREN "("
+ DOLLAR "$"
+ IDENT "s"
+ COLON ":"
+ IDENT "expr"
+ R_PAREN ")"
+ COMMA ","
+ STAR "*"
+ WHITESPACE " "
+ DOLLAR "$"
+ TOKEN_TREE
+ L_PAREN "("
+ COMMA ","
+ R_PAREN ")"
+ STAR "*"
+ R_PAREN ")"
+ WHITESPACE " "
+ TOKEN_TREE
+ L_CURLY "{"
+ WHITESPACE "\n "
+ IDENT "vec"
+ BANG "!"
+ TOKEN_TREE
+ L_BRACK "["
+ WHITESPACE "\n "
+ DOLLAR "$"
+ TOKEN_TREE
+ L_PAREN "("
+ IDENT "parse_use_tree"
+ TOKEN_TREE
+ L_PAREN "("
+ DOLLAR "$"
+ IDENT "s"
+ R_PAREN ")"
+ COMMA ","
+ R_PAREN ")"
+ STAR "*"
+ WHITESPACE "\n "
+ R_BRACK "]"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ FN
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "test"
+ R_BRACK "]"
+ WHITESPACE "\n"
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "test_use_tree_merge"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ MACRO_DEF
+ MACRO_KW "macro"
+ WHITESPACE " "
+ NAME
+ IDENT "test_merge"
+ TOKEN_TREE
+ TOKEN_TREE
+ L_PAREN "("
+ TOKEN_TREE
+ L_BRACK "["
+ DOLLAR "$"
+ TOKEN_TREE
+ L_PAREN "("
+ DOLLAR "$"
+ IDENT "input"
+ COLON ":"
+ IDENT "expr"
+ R_PAREN ")"
+ COMMA ","
+ STAR "*"
+ WHITESPACE " "
+ DOLLAR "$"
+ TOKEN_TREE
+ L_PAREN "("
+ COMMA ","
+ R_PAREN ")"
+ STAR "*"
+ R_BRACK "]"
+ COMMA ","
+ WHITESPACE " "
+ TOKEN_TREE
+ L_BRACK "["
+ DOLLAR "$"
+ TOKEN_TREE
+ L_PAREN "("
+ DOLLAR "$"
+ IDENT "output"
+ COLON ":"
+ IDENT "expr"
+ R_PAREN ")"
+ COMMA ","
+ STAR "*"
+ WHITESPACE " "
+ DOLLAR "$"
+ TOKEN_TREE
+ L_PAREN "("
+ COMMA ","
+ R_PAREN ")"
+ STAR "*"
+ R_BRACK "]"
+ R_PAREN ")"
+ WHITESPACE " "
+ TOKEN_TREE
+ L_CURLY "{"
+ WHITESPACE "\n "
+ IDENT "assert_eq"
+ BANG "!"
+ TOKEN_TREE
+ L_PAREN "("
+ WHITESPACE "\n "
+ IDENT "merge_use_trees"
+ TOKEN_TREE
+ L_PAREN "("
+ IDENT "parse_use_trees"
+ BANG "!"
+ TOKEN_TREE
+ L_PAREN "("
+ DOLLAR "$"
+ TOKEN_TREE
+ L_PAREN "("
+ DOLLAR "$"
+ IDENT "input"
+ COMMA ","
+ R_PAREN ")"
+ STAR "*"
+ R_PAREN ")"
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n "
+ IDENT "parse_use_trees"
+ BANG "!"
+ TOKEN_TREE
+ L_PAREN "("
+ DOLLAR "$"
+ TOKEN_TREE
+ L_PAREN "("
+ DOLLAR "$"
+ IDENT "output"
+ COMMA ","
+ R_PAREN ")"
+ STAR "*"
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n "
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0062_macro_2.0.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0062_macro_2.0.rs
new file mode 100644
index 000000000..781047ba1
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0062_macro_2.0.rs
@@ -0,0 +1,15 @@
+macro parse_use_trees($($s:expr),* $(,)*) {
+ vec![
+ $(parse_use_tree($s),)*
+ ]
+}
+
+#[test]
+fn test_use_tree_merge() {
+ macro test_merge([$($input:expr),* $(,)*], [$($output:expr),* $(,)*]) {
+ assert_eq!(
+ merge_use_trees(parse_use_trees!($($input,)*)),
+ parse_use_trees!($($output,)*),
+ );
+ }
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0063_trait_fn_patterns.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0063_trait_fn_patterns.rast
new file mode 100644
index 000000000..a86b21d27
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0063_trait_fn_patterns.rast
@@ -0,0 +1,198 @@
+SOURCE_FILE
+ TRAIT
+ TRAIT_KW "trait"
+ WHITESPACE " "
+ NAME
+ IDENT "T"
+ WHITESPACE " "
+ ASSOC_ITEM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "f1"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ TUPLE_PAT
+ L_PAREN "("
+ IDENT_PAT
+ NAME
+ IDENT "a"
+ COMMA ","
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "b"
+ R_PAREN ")"
+ COLON ":"
+ WHITESPACE " "
+ TUPLE_TYPE
+ L_PAREN "("
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "usize"
+ COMMA ","
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "usize"
+ R_PAREN ")"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "f2"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ RECORD_PAT
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_PAT_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ RECORD_PAT_FIELD
+ IDENT_PAT
+ NAME
+ IDENT "a"
+ COMMA ","
+ WHITESPACE " "
+ RECORD_PAT_FIELD
+ IDENT_PAT
+ NAME
+ IDENT "b"
+ WHITESPACE " "
+ R_CURLY "}"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "f3"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ TUPLE_STRUCT_PAT
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "NewType"
+ L_PAREN "("
+ IDENT_PAT
+ NAME
+ IDENT "a"
+ R_PAREN ")"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "NewType"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "f4"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ REF_PAT
+ AMP "&"
+ REF_PAT
+ AMP "&"
+ IDENT_PAT
+ NAME
+ IDENT "a"
+ COLON ":"
+ WHITESPACE " "
+ REF_TYPE
+ AMP "&"
+ REF_TYPE
+ AMP "&"
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "usize"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "bar"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u64"
+ COMMA ","
+ WHITESPACE " "
+ PARAM
+ IDENT_PAT
+ MUT_KW "mut"
+ WHITESPACE " "
+ NAME
+ IDENT "x"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0063_trait_fn_patterns.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0063_trait_fn_patterns.rs
new file mode 100644
index 000000000..3b666af8e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0063_trait_fn_patterns.rs
@@ -0,0 +1,7 @@
+trait T {
+ fn f1((a, b): (usize, usize)) {}
+ fn f2(S { a, b }: S) {}
+ fn f3(NewType(a): NewType) {}
+ fn f4(&&a: &&usize) {}
+ fn bar(_: u64, mut x: i32);
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0063_variadic_fun.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0063_variadic_fun.rast
new file mode 100644
index 000000000..e36399123
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0063_variadic_fun.rast
@@ -0,0 +1,134 @@
+SOURCE_FILE
+ EXTERN_BLOCK
+ ABI
+ EXTERN_KW "extern"
+ WHITESPACE " "
+ STRING "\"C\""
+ WHITESPACE " "
+ EXTERN_ITEM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "a"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ COLON ":"
+ WHITESPACE " "
+ PTR_TYPE
+ STAR "*"
+ MUT_KW "mut"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u8"
+ COMMA ","
+ WHITESPACE " "
+ PARAM
+ DOT3 "..."
+ COMMA ","
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "b"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ COLON ":"
+ WHITESPACE " "
+ PTR_TYPE
+ STAR "*"
+ MUT_KW "mut"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u8"
+ COMMA ","
+ WHITESPACE " "
+ PARAM
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ COLON ":"
+ WHITESPACE " "
+ DOT3 "..."
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "c"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ WILDCARD_PAT
+ UNDERSCORE "_"
+ COLON ":"
+ WHITESPACE " "
+ PTR_TYPE
+ STAR "*"
+ MUT_KW "mut"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u8"
+ COMMA ","
+ WHITESPACE " "
+ PARAM
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "cfg"
+ TOKEN_TREE
+ L_PAREN "("
+ IDENT "never"
+ R_PAREN ")"
+ R_BRACK "]"
+ WHITESPACE " "
+ SLICE_PAT
+ L_BRACK "["
+ IDENT_PAT
+ NAME
+ IDENT "w"
+ COMMA ","
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "t"
+ COMMA ","
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "f"
+ R_BRACK "]"
+ COLON ":"
+ WHITESPACE " "
+ DOT3 "..."
+ COMMA ","
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0063_variadic_fun.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0063_variadic_fun.rs
new file mode 100644
index 000000000..a16afbaf3
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0063_variadic_fun.rs
@@ -0,0 +1,5 @@
+extern "C" {
+ fn a(_: *mut u8, ...,);
+ fn b(_: *mut u8, _: ...);
+ fn c(_: *mut u8, #[cfg(never)] [w, t, f]: ...,);
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0064_impl_fn_params.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0064_impl_fn_params.rast
new file mode 100644
index 000000000..18cecc810
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0064_impl_fn_params.rast
@@ -0,0 +1,166 @@
+SOURCE_FILE
+ IMPL
+ IMPL_KW "impl"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "U"
+ WHITESPACE " "
+ ASSOC_ITEM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "f1"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ TUPLE_PAT
+ L_PAREN "("
+ IDENT_PAT
+ NAME
+ IDENT "a"
+ COMMA ","
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "b"
+ R_PAREN ")"
+ COLON ":"
+ WHITESPACE " "
+ TUPLE_TYPE
+ L_PAREN "("
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "usize"
+ COMMA ","
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "usize"
+ R_PAREN ")"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "f2"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ RECORD_PAT
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_PAT_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ RECORD_PAT_FIELD
+ IDENT_PAT
+ NAME
+ IDENT "a"
+ COMMA ","
+ WHITESPACE " "
+ RECORD_PAT_FIELD
+ IDENT_PAT
+ NAME
+ IDENT "b"
+ WHITESPACE " "
+ R_CURLY "}"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "f3"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ TUPLE_STRUCT_PAT
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "NewType"
+ L_PAREN "("
+ IDENT_PAT
+ NAME
+ IDENT "a"
+ R_PAREN ")"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "NewType"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n "
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "f4"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ REF_PAT
+ AMP "&"
+ REF_PAT
+ AMP "&"
+ IDENT_PAT
+ NAME
+ IDENT "a"
+ COLON ":"
+ WHITESPACE " "
+ REF_TYPE
+ AMP "&"
+ REF_TYPE
+ AMP "&"
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "usize"
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0064_impl_fn_params.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0064_impl_fn_params.rs
new file mode 100644
index 000000000..b49e872d7
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0064_impl_fn_params.rs
@@ -0,0 +1,6 @@
+impl U {
+ fn f1((a, b): (usize, usize)) {}
+ fn f2(S { a, b }: S) {}
+ fn f3(NewType(a): NewType) {}
+ fn f4(&&a: &&usize) {}
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0065_comment_newline.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0065_comment_newline.rast
new file mode 100644
index 000000000..3ffcb48f5
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0065_comment_newline.rast
@@ -0,0 +1,17 @@
+SOURCE_FILE
+ FN
+ COMMENT "/// Example"
+ WHITESPACE "\n\n"
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "test"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0065_comment_newline.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0065_comment_newline.rs
new file mode 100644
index 000000000..1fafe216b
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0065_comment_newline.rs
@@ -0,0 +1,3 @@
+/// Example
+
+fn test() {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0065_plus_after_fn_trait_bound.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0065_plus_after_fn_trait_bound.rast
new file mode 100644
index 000000000..ba7b6042a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0065_plus_after_fn_trait_bound.rast
@@ -0,0 +1,61 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "f"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "T"
+ R_ANGLE ">"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ WHERE_CLAUSE
+ WHERE_KW "where"
+ WHITESPACE " "
+ WHERE_PRED
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "T"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Fn"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ RET_TYPE
+ THIN_ARROW "->"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u8"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Send"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0065_plus_after_fn_trait_bound.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0065_plus_after_fn_trait_bound.rs
new file mode 100644
index 000000000..29f3655e0
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0065_plus_after_fn_trait_bound.rs
@@ -0,0 +1 @@
+fn f<T>() where T: Fn() -> u8 + Send {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0066_default_modifier.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0066_default_modifier.rast
new file mode 100644
index 000000000..a4303098a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0066_default_modifier.rast
@@ -0,0 +1,222 @@
+SOURCE_FILE
+ TRAIT
+ TRAIT_KW "trait"
+ WHITESPACE " "
+ NAME
+ IDENT "T"
+ WHITESPACE " "
+ ASSOC_ITEM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ TYPE_ALIAS
+ DEFAULT_KW "default"
+ WHITESPACE " "
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "T"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Bar"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ CONST
+ DEFAULT_KW "default"
+ WHITESPACE " "
+ CONST_KW "const"
+ WHITESPACE " "
+ NAME
+ IDENT "f"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u8"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "0"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ FN
+ DEFAULT_KW "default"
+ WHITESPACE " "
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n "
+ FN
+ DEFAULT_KW "default"
+ WHITESPACE " "
+ UNSAFE_KW "unsafe"
+ WHITESPACE " "
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "bar"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ IMPL
+ IMPL_KW "impl"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "T"
+ WHITESPACE " "
+ FOR_KW "for"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Foo"
+ WHITESPACE " "
+ ASSOC_ITEM_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ TYPE_ALIAS
+ DEFAULT_KW "default"
+ WHITESPACE " "
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "T"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Bar"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ CONST
+ DEFAULT_KW "default"
+ WHITESPACE " "
+ CONST_KW "const"
+ WHITESPACE " "
+ NAME
+ IDENT "f"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "u8"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "0"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ FN
+ DEFAULT_KW "default"
+ WHITESPACE " "
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n "
+ FN
+ DEFAULT_KW "default"
+ WHITESPACE " "
+ UNSAFE_KW "unsafe"
+ WHITESPACE " "
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "bar"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ IMPL
+ DEFAULT_KW "default"
+ WHITESPACE " "
+ IMPL_KW "impl"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "T"
+ WHITESPACE " "
+ FOR_KW "for"
+ WHITESPACE " "
+ TUPLE_TYPE
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ ASSOC_ITEM_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ IMPL
+ DEFAULT_KW "default"
+ WHITESPACE " "
+ UNSAFE_KW "unsafe"
+ WHITESPACE " "
+ IMPL_KW "impl"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "T"
+ WHITESPACE " "
+ FOR_KW "for"
+ WHITESPACE " "
+ TUPLE_TYPE
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ ASSOC_ITEM_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0066_default_modifier.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0066_default_modifier.rs
new file mode 100644
index 000000000..e443e3495
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0066_default_modifier.rs
@@ -0,0 +1,16 @@
+trait T {
+ default type T = Bar;
+ default const f: u8 = 0;
+ default fn foo() {}
+ default unsafe fn bar() {}
+}
+
+impl T for Foo {
+ default type T = Bar;
+ default const f: u8 = 0;
+ default fn foo() {}
+ default unsafe fn bar() {}
+}
+
+default impl T for () {}
+default unsafe impl T for () {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0067_where_for_pred.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0067_where_for_pred.rast
new file mode 100644
index 000000000..136fce93d
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0067_where_for_pred.rast
@@ -0,0 +1,413 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "for_trait"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "F"
+ R_ANGLE ">"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE "\n"
+ WHERE_CLAUSE
+ WHERE_KW "where"
+ WHITESPACE "\n "
+ WHERE_PRED
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "F"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Fn"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ REF_TYPE
+ AMP "&"
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "str"
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n"
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "for_ref"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "F"
+ R_ANGLE ">"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE "\n"
+ WHERE_CLAUSE
+ WHERE_KW "where"
+ WHITESPACE "\n "
+ WHERE_PRED
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ WHITESPACE " "
+ REF_TYPE
+ AMP "&"
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "F"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Debug"
+ COMMA ","
+ WHITESPACE "\n"
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "for_parens"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "F"
+ R_ANGLE ">"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE "\n"
+ WHERE_CLAUSE
+ WHERE_KW "where"
+ WHITESPACE "\n "
+ WHERE_PRED
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ WHITESPACE " "
+ PAREN_TYPE
+ L_PAREN "("
+ REF_TYPE
+ AMP "&"
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "F"
+ R_PAREN ")"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Fn"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ REF_TYPE
+ AMP "&"
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "str"
+ R_PAREN ")"
+ COMMA ","
+ WHITESPACE "\n"
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "for_slice"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "F"
+ R_ANGLE ">"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE "\n"
+ WHERE_CLAUSE
+ WHERE_KW "where"
+ WHITESPACE "\n "
+ WHERE_PRED
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ WHITESPACE " "
+ SLICE_TYPE
+ L_BRACK "["
+ REF_TYPE
+ AMP "&"
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "F"
+ R_BRACK "]"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Eq"
+ COMMA ","
+ WHITESPACE "\n"
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "for_qpath"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "T"
+ R_ANGLE ">"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ IDENT_PAT
+ NAME
+ IDENT "_t"
+ COLON ":"
+ WHITESPACE " "
+ REF_TYPE
+ AMP "&"
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "T"
+ R_PAREN ")"
+ WHITESPACE "\n"
+ WHERE_CLAUSE
+ WHERE_KW "where"
+ WHITESPACE "\n "
+ WHERE_PRED
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH
+ PATH_SEGMENT
+ L_ANGLE "<"
+ REF_TYPE
+ AMP "&"
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "T"
+ WHITESPACE " "
+ AS_KW "as"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Baz"
+ R_ANGLE ">"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Foo"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Iterator"
+ COMMA ","
+ WHITESPACE "\n"
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "for_for_fn"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "T"
+ R_ANGLE ">"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE "\n"
+ WHERE_CLAUSE
+ WHERE_KW "where"
+ WHITESPACE "\n "
+ WHERE_PRED
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ WHITESPACE " "
+ FOR_TYPE
+ FOR_KW "for"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'b"
+ R_ANGLE ">"
+ WHITESPACE " "
+ FN_PTR_TYPE
+ FN_KW "fn"
+ PARAM_LIST
+ L_PAREN "("
+ PARAM
+ REF_TYPE
+ AMP "&"
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "T"
+ COMMA ","
+ WHITESPACE " "
+ PARAM
+ REF_TYPE
+ AMP "&"
+ LIFETIME
+ LIFETIME_IDENT "'b"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "T"
+ R_PAREN ")"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Copy"
+ COMMA ","
+ WHITESPACE "\n"
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0067_where_for_pred.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0067_where_for_pred.rs
new file mode 100644
index 000000000..9058c4619
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0067_where_for_pred.rs
@@ -0,0 +1,30 @@
+fn for_trait<F>()
+where
+ for<'a> F: Fn(&'a str),
+{
+}
+fn for_ref<F>()
+where
+ for<'a> &'a F: Debug,
+{
+}
+fn for_parens<F>()
+where
+ for<'a> (&'a F): Fn(&'a str),
+{
+}
+fn for_slice<F>()
+where
+ for<'a> [&'a F]: Eq,
+{
+}
+fn for_qpath<T>(_t: &T)
+where
+ for<'a> <&'a T as Baz>::Foo: Iterator,
+{
+}
+fn for_for_fn<T>()
+where
+ for<'a> for<'b> fn(&'a T, &'b T): Copy,
+{
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0068_item_modifiers.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0068_item_modifiers.rast
new file mode 100644
index 000000000..41fc5691a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0068_item_modifiers.rast
@@ -0,0 +1,238 @@
+SOURCE_FILE
+ FN
+ ASYNC_KW "async"
+ WHITESPACE " "
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ FN
+ ABI
+ EXTERN_KW "extern"
+ WHITESPACE " "
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ FN
+ CONST_KW "const"
+ WHITESPACE " "
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ FN
+ CONST_KW "const"
+ WHITESPACE " "
+ UNSAFE_KW "unsafe"
+ WHITESPACE " "
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ FN
+ UNSAFE_KW "unsafe"
+ WHITESPACE " "
+ ABI
+ EXTERN_KW "extern"
+ WHITESPACE " "
+ STRING "\"C\""
+ WHITESPACE " "
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ FN
+ UNSAFE_KW "unsafe"
+ WHITESPACE " "
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ FN
+ ASYNC_KW "async"
+ WHITESPACE " "
+ UNSAFE_KW "unsafe"
+ WHITESPACE " "
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ FN
+ CONST_KW "const"
+ WHITESPACE " "
+ UNSAFE_KW "unsafe"
+ WHITESPACE " "
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "bar"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ TRAIT
+ UNSAFE_KW "unsafe"
+ WHITESPACE " "
+ TRAIT_KW "trait"
+ WHITESPACE " "
+ NAME
+ IDENT "T"
+ WHITESPACE " "
+ ASSOC_ITEM_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ TRAIT
+ AUTO_KW "auto"
+ WHITESPACE " "
+ TRAIT_KW "trait"
+ WHITESPACE " "
+ NAME
+ IDENT "T"
+ WHITESPACE " "
+ ASSOC_ITEM_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ TRAIT
+ UNSAFE_KW "unsafe"
+ WHITESPACE " "
+ AUTO_KW "auto"
+ WHITESPACE " "
+ TRAIT_KW "trait"
+ WHITESPACE " "
+ NAME
+ IDENT "T"
+ WHITESPACE " "
+ ASSOC_ITEM_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ IMPL
+ UNSAFE_KW "unsafe"
+ WHITESPACE " "
+ IMPL_KW "impl"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Foo"
+ WHITESPACE " "
+ ASSOC_ITEM_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ IMPL
+ DEFAULT_KW "default"
+ WHITESPACE " "
+ IMPL_KW "impl"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Foo"
+ WHITESPACE " "
+ ASSOC_ITEM_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
+ IMPL
+ UNSAFE_KW "unsafe"
+ WHITESPACE " "
+ DEFAULT_KW "default"
+ WHITESPACE " "
+ IMPL_KW "impl"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Foo"
+ WHITESPACE " "
+ ASSOC_ITEM_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n\n"
+ EXTERN_BLOCK
+ UNSAFE_KW "unsafe"
+ WHITESPACE " "
+ ABI
+ EXTERN_KW "extern"
+ WHITESPACE " "
+ STRING "\"C++\""
+ WHITESPACE " "
+ EXTERN_ITEM_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0068_item_modifiers.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0068_item_modifiers.rs
new file mode 100644
index 000000000..6d27a082c
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0068_item_modifiers.rs
@@ -0,0 +1,18 @@
+async fn foo() {}
+extern fn foo() {}
+const fn foo() {}
+const unsafe fn foo() {}
+unsafe extern "C" fn foo() {}
+unsafe fn foo() {}
+async unsafe fn foo() {}
+const unsafe fn bar() {}
+
+unsafe trait T {}
+auto trait T {}
+unsafe auto trait T {}
+
+unsafe impl Foo {}
+default impl Foo {}
+unsafe default impl Foo {}
+
+unsafe extern "C++" {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0069_multi_trait_object.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0069_multi_trait_object.rast
new file mode 100644
index 000000000..9e8f4e197
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0069_multi_trait_object.rast
@@ -0,0 +1,204 @@
+SOURCE_FILE
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "Foo"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ LIFETIME_PARAM
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ R_ANGLE ">"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ REF_TYPE
+ AMP "&"
+ LIFETIME
+ LIFETIME_IDENT "'a"
+ WHITESPACE " "
+ PAREN_TYPE
+ L_PAREN "("
+ DYN_TRAIT_TYPE
+ DYN_KW "dyn"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Send"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Sync"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "Foo"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ PTR_TYPE
+ STAR "*"
+ CONST_KW "const"
+ WHITESPACE " "
+ PAREN_TYPE
+ L_PAREN "("
+ DYN_TRAIT_TYPE
+ DYN_KW "dyn"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Send"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Sync"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "Foo"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ FN_PTR_TYPE
+ FN_KW "fn"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ RET_TYPE
+ THIN_ARROW "->"
+ WHITESPACE " "
+ PAREN_TYPE
+ L_PAREN "("
+ DYN_TRAIT_TYPE
+ DYN_KW "dyn"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Send"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ TYPE_BOUND
+ LIFETIME
+ LIFETIME_IDENT "'static"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "main"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "b"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ CAST_EXPR
+ PAREN_EXPR
+ L_PAREN "("
+ REF_EXPR
+ AMP "&"
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "a"
+ R_PAREN ")"
+ WHITESPACE " "
+ AS_KW "as"
+ WHITESPACE " "
+ REF_TYPE
+ AMP "&"
+ PAREN_TYPE
+ L_PAREN "("
+ DYN_TRAIT_TYPE
+ DYN_KW "dyn"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Add"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ TYPE_ARG
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Other"
+ COMMA ","
+ WHITESPACE " "
+ ASSOC_TYPE_ARG
+ NAME_REF
+ IDENT "Output"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Addable"
+ R_ANGLE ">"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Other"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0069_multi_trait_object.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0069_multi_trait_object.rs
new file mode 100644
index 000000000..97eb79c48
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0069_multi_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/parser/test_data/parser/ok/0070_expr_attr_placement.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0070_expr_attr_placement.rast
new file mode 100644
index 000000000..3d00b27ab
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0070_expr_attr_placement.rast
@@ -0,0 +1,59 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "f"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ PAREN_EXPR
+ L_PAREN "("
+ BIN_EXPR
+ TRY_EXPR
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "a"
+ R_BRACK "]"
+ WHITESPACE " "
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "lhs"
+ QUESTION "?"
+ WHITESPACE " "
+ PLUS "+"
+ WHITESPACE " "
+ AWAIT_EXPR
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "b"
+ R_BRACK "]"
+ WHITESPACE " "
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "rhs"
+ DOT "."
+ AWAIT_KW "await"
+ R_PAREN ")"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0070_expr_attr_placement.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0070_expr_attr_placement.rs
new file mode 100644
index 000000000..d8b7a3832
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0070_expr_attr_placement.rs
@@ -0,0 +1,3 @@
+fn f() {
+ (#[a] lhs? + #[b] rhs.await)
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0071_stmt_attr_placement.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0071_stmt_attr_placement.rast
new file mode 100644
index 000000000..1cafc775c
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0071_stmt_attr_placement.rast
@@ -0,0 +1,72 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BLOCK_EXPR
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "A"
+ R_BRACK "]"
+ WHITESPACE " "
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ TRY_EXPR
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "B"
+ R_BRACK "]"
+ WHITESPACE " "
+ MACRO_EXPR
+ MACRO_CALL
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "bar"
+ BANG "!"
+ TOKEN_TREE
+ L_PAREN "("
+ R_PAREN ")"
+ QUESTION "?"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n "
+ REF_EXPR
+ ATTR
+ POUND "#"
+ L_BRACK "["
+ META
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "C"
+ R_BRACK "]"
+ WHITESPACE " "
+ AMP "&"
+ TUPLE_EXPR
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0071_stmt_attr_placement.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0071_stmt_attr_placement.rs
new file mode 100644
index 000000000..b4d5204bc
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0071_stmt_attr_placement.rs
@@ -0,0 +1,4 @@
+fn foo() {
+ #[A] { #[B] bar!()? }
+ #[C] &()
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0072_destructuring_assignment.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0072_destructuring_assignment.rast
new file mode 100644
index 000000000..e8b836dfb
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0072_destructuring_assignment.rast
@@ -0,0 +1,352 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ TUPLE_PAT
+ L_PAREN "("
+ IDENT_PAT
+ MUT_KW "mut"
+ WHITESPACE " "
+ NAME
+ IDENT "a"
+ COMMA ","
+ WHITESPACE " "
+ IDENT_PAT
+ MUT_KW "mut"
+ WHITESPACE " "
+ NAME
+ IDENT "b"
+ R_PAREN ")"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ LITERAL
+ INT_NUMBER "0"
+ COMMA ","
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "1"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BIN_EXPR
+ TUPLE_EXPR
+ L_PAREN "("
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "b"
+ COMMA ","
+ WHITESPACE " "
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "a"
+ COMMA ","
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2 ".."
+ R_PAREN ")"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "a"
+ COMMA ","
+ WHITESPACE " "
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "b"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BIN_EXPR
+ PAREN_EXPR
+ L_PAREN "("
+ UNDERSCORE_EXPR
+ UNDERSCORE "_"
+ R_PAREN ")"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2 ".."
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ RECORD_FIELD
+ NAME
+ IDENT "a"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BIN_EXPR
+ RECORD_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_EXPR_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ DOT2 ".."
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ RECORD_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_EXPR_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ DOT2 ".."
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "default"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BIN_EXPR
+ BIN_EXPR
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Some"
+ ARG_LIST
+ L_PAREN "("
+ RANGE_EXPR
+ DOT2 ".."
+ R_PAREN ")"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ METHOD_CALL_EXPR
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Some"
+ ARG_LIST
+ L_PAREN "("
+ LITERAL
+ INT_NUMBER "0"
+ R_PAREN ")"
+ DOT "."
+ WHITESPACE "\n "
+ NAME_REF
+ IDENT "Ok"
+ ARG_LIST
+ L_PAREN "("
+ UNDERSCORE_EXPR
+ UNDERSCORE "_"
+ R_PAREN ")"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "0"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ TUPLE_PAT
+ L_PAREN "("
+ IDENT_PAT
+ NAME
+ IDENT "a"
+ COMMA ","
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "b"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BIN_EXPR
+ ARRAY_EXPR
+ L_BRACK "["
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "a"
+ COMMA ","
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2 ".."
+ COMMA ","
+ WHITESPACE " "
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "b"
+ R_BRACK "]"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ ARRAY_EXPR
+ L_BRACK "["
+ LITERAL
+ INT_NUMBER "1"
+ COMMA ","
+ WHITESPACE " "
+ RANGE_EXPR
+ DOT2 ".."
+ COMMA ","
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "2"
+ R_BRACK "]"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BIN_EXPR
+ TUPLE_EXPR
+ L_PAREN "("
+ UNDERSCORE_EXPR
+ UNDERSCORE "_"
+ COMMA ","
+ WHITESPACE " "
+ UNDERSCORE_EXPR
+ UNDERSCORE "_"
+ R_PAREN ")"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "a"
+ COMMA ","
+ WHITESPACE " "
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "b"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BIN_EXPR
+ PAREN_EXPR
+ L_PAREN "("
+ UNDERSCORE_EXPR
+ UNDERSCORE "_"
+ R_PAREN ")"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "a"
+ COMMA ","
+ WHITESPACE " "
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "b"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ BIN_EXPR
+ UNDERSCORE_EXPR
+ UNDERSCORE "_"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ TUPLE_EXPR
+ L_PAREN "("
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "a"
+ COMMA ","
+ WHITESPACE " "
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "b"
+ R_PAREN ")"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0072_destructuring_assignment.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0072_destructuring_assignment.rs
new file mode 100644
index 000000000..9d3e86603
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0072_destructuring_assignment.rs
@@ -0,0 +1,14 @@
+fn foo() {
+ let (mut a, mut b) = (0, 1);
+ (b, a, ..) = (a, b);
+ (_) = ..;
+ struct S { a: i32 }
+ S { .. } = S { ..S::default() };
+ Some(..) = Some(0).
+ Ok(_) = 0;
+ let (a, b);
+ [a, .., b] = [1, .., 2];
+ (_, _) = (a, b);
+ (_) = (a, b);
+ _ = (a, b);
+}