aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_syntax')
-rw-r--r--crates/ra_syntax/Cargo.toml2
-rw-r--r--crates/ra_syntax/src/algo.rs2
-rw-r--r--crates/ra_syntax/src/ast/expr_extensions.rs15
-rw-r--r--crates/ra_syntax/src/ast/generated.rs2
-rw-r--r--crates/ra_syntax/src/ast/make.rs61
-rw-r--r--crates/ra_syntax/src/lib.rs4
-rw-r--r--crates/ra_syntax/src/parsing.rs18
-rw-r--r--crates/ra_syntax/src/parsing/lexer.rs324
-rw-r--r--crates/ra_syntax/src/parsing/reparsing.rs55
-rw-r--r--crates/ra_syntax/src/parsing/text_tree_sink.rs4
-rw-r--r--crates/ra_syntax/src/syntax_error.rs60
-rw-r--r--crates/ra_syntax/src/syntax_node.rs9
-rw-r--r--crates/ra_syntax/src/tests.rs79
-rw-r--r--crates/ra_syntax/src/validation.rs6
-rw-r--r--crates/ra_syntax/test_data/lexer/0010_comments.rs3
-rw-r--r--crates/ra_syntax/test_data/lexer/0010_comments.txt6
-rw-r--r--crates/ra_syntax/test_data/lexer/0014_unclosed_char.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/0014_unclosed_char.txt1
-rw-r--r--crates/ra_syntax/test_data/lexer/0015_unclosed_string.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/0015_unclosed_string.txt1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0001_unclosed_char_at_eof.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0001_unclosed_char_at_eof.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0002_unclosed_char_with_ferris.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0002_unclosed_char_with_ferris.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0003_unclosed_char_with_ascii_escape.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0003_unclosed_char_with_ascii_escape.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0004_unclosed_char_with_unicode_escape.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0004_unclosed_char_with_unicode_escape.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0005_unclosed_char_with_space.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0005_unclosed_char_with_space.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0006_unclosed_char_with_slash.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0006_unclosed_char_with_slash.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0007_unclosed_char_with_slash_n.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0007_unclosed_char_with_slash_n.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0008_unclosed_char_with_slash_single_quote.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0008_unclosed_char_with_slash_single_quote.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0009_unclosed_byte_at_eof.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0009_unclosed_byte_at_eof.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0010_unclosed_byte_with_ferris.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0010_unclosed_byte_with_ferris.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0011_unclosed_byte_with_ascii_escape.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0011_unclosed_byte_with_ascii_escape.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0012_unclosed_byte_with_unicode_escape.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0012_unclosed_byte_with_unicode_escape.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0013_unclosed_byte_with_space.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0013_unclosed_byte_with_space.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0014_unclosed_byte_with_slash.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0014_unclosed_byte_with_slash.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0015_unclosed_byte_with_slash_n.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0015_unclosed_byte_with_slash_n.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0016_unclosed_byte_with_slash_single_quote.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0016_unclosed_byte_with_slash_single_quote.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0017_unclosed_string_at_eof.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0017_unclosed_string_at_eof.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0018_unclosed_string_with_ferris.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0018_unclosed_string_with_ferris.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0019_unclosed_string_with_ascii_escape.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0019_unclosed_string_with_ascii_escape.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0020_unclosed_string_with_unicode_escape.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0020_unclosed_string_with_unicode_escape.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0021_unclosed_string_with_space.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0021_unclosed_string_with_space.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0022_unclosed_string_with_slash.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0022_unclosed_string_with_slash.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0023_unclosed_string_with_slash_n.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0023_unclosed_string_with_slash_n.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0024_unclosed_string_with_slash_double_quote.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0024_unclosed_string_with_slash_double_quote.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0025_unclosed_byte_string_at_eof.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0025_unclosed_byte_string_at_eof.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0026_unclosed_byte_string_with_ferris.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0026_unclosed_byte_string_with_ferris.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0027_unclosed_byte_string_with_ascii_escape.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0027_unclosed_byte_string_with_ascii_escape.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0028_unclosed_byte_string_with_unicode_escape.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0028_unclosed_byte_string_with_unicode_escape.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0029_unclosed_byte_string_with_space.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0029_unclosed_byte_string_with_space.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0030_unclosed_byte_string_with_slash.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0030_unclosed_byte_string_with_slash.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0031_unclosed_byte_string_with_slash_n.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0031_unclosed_byte_string_with_slash_n.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0032_unclosed_byte_string_with_slash_double_quote.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0032_unclosed_byte_string_with_slash_double_quote.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0033_unclosed_raw_string_at_eof.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0033_unclosed_raw_string_at_eof.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0034_unclosed_raw_string_with_ferris.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0034_unclosed_raw_string_with_ferris.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0035_unclosed_raw_string_with_ascii_escape.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0035_unclosed_raw_string_with_ascii_escape.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0036_unclosed_raw_string_with_unicode_escape.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0036_unclosed_raw_string_with_unicode_escape.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0037_unclosed_raw_string_with_space.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0037_unclosed_raw_string_with_space.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0038_unclosed_raw_string_with_slash.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0038_unclosed_raw_string_with_slash.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0039_unclosed_raw_string_with_slash_n.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0039_unclosed_raw_string_with_slash_n.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0040_unclosed_raw_byte_string_at_eof.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0040_unclosed_raw_byte_string_at_eof.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0041_unclosed_raw_byte_string_with_ferris.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0041_unclosed_raw_byte_string_with_ferris.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0042_unclosed_raw_byte_string_with_ascii_escape.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0042_unclosed_raw_byte_string_with_ascii_escape.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0043_unclosed_raw_byte_string_with_unicode_escape.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0043_unclosed_raw_byte_string_with_unicode_escape.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0044_unclosed_raw_byte_string_with_space.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0044_unclosed_raw_byte_string_with_space.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0045_unclosed_raw_byte_string_with_slash.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0045_unclosed_raw_byte_string_with_slash.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0046_unclosed_raw_byte_string_with_slash_n.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0046_unclosed_raw_byte_string_with_slash_n.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0047_unstarted_raw_string_at_eof.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0047_unstarted_raw_string_at_eof.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0048_unstarted_raw_byte_string_at_eof.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0048_unstarted_raw_byte_string_at_eof.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0049_unstarted_raw_string_with_ascii.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0049_unstarted_raw_string_with_ascii.txt10
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0050_unstarted_raw_byte_string_with_ascii.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0050_unstarted_raw_byte_string_with_ascii.txt10
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0051_unclosed_block_comment_at_eof.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0051_unclosed_block_comment_at_eof.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0052_unclosed_block_comment_with_content.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0052_unclosed_block_comment_with_content.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0053_unclosed_nested_block_comment_entirely.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0053_unclosed_nested_block_comment_entirely.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0054_unclosed_nested_block_comment_partially.rs1
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0054_unclosed_nested_block_comment_partially.txt2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0055_empty_int.rs17
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0055_empty_int.txt39
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0056_empty_exponent.rs22
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0056_empty_exponent.txt62
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0057_lifetime_strarts_with_a_number.rs2
-rw-r--r--crates/ra_syntax/test_data/lexer/err/0057_lifetime_strarts_with_a_number.txt6
-rw-r--r--crates/ra_syntax/test_data/lexer/ok/0001_hello.rs (renamed from crates/ra_syntax/test_data/lexer/0001_hello.rs)0
-rw-r--r--crates/ra_syntax/test_data/lexer/ok/0001_hello.txt (renamed from crates/ra_syntax/test_data/lexer/0001_hello.txt)0
-rw-r--r--crates/ra_syntax/test_data/lexer/ok/0002_whitespace.rs (renamed from crates/ra_syntax/test_data/lexer/0002_whitespace.rs)0
-rw-r--r--crates/ra_syntax/test_data/lexer/ok/0002_whitespace.txt (renamed from crates/ra_syntax/test_data/lexer/0002_whitespace.txt)0
-rw-r--r--crates/ra_syntax/test_data/lexer/ok/0003_ident.rs (renamed from crates/ra_syntax/test_data/lexer/0003_ident.rs)0
-rw-r--r--crates/ra_syntax/test_data/lexer/ok/0003_ident.txt (renamed from crates/ra_syntax/test_data/lexer/0003_ident.txt)0
-rw-r--r--crates/ra_syntax/test_data/lexer/ok/0004_numbers.rs (renamed from crates/ra_syntax/test_data/lexer/0004_numbers.rs)4
-rw-r--r--crates/ra_syntax/test_data/lexer/ok/0004_numbers.txt (renamed from crates/ra_syntax/test_data/lexer/0004_numbers.txt)11
-rw-r--r--crates/ra_syntax/test_data/lexer/ok/0005_symbols.rs (renamed from crates/ra_syntax/test_data/lexer/0005_symbols.rs)0
-rw-r--r--crates/ra_syntax/test_data/lexer/ok/0005_symbols.txt (renamed from crates/ra_syntax/test_data/lexer/0005_symbols.txt)0
-rw-r--r--crates/ra_syntax/test_data/lexer/ok/0006_chars.rs (renamed from crates/ra_syntax/test_data/lexer/0006_chars.rs)0
-rw-r--r--crates/ra_syntax/test_data/lexer/ok/0006_chars.txt (renamed from crates/ra_syntax/test_data/lexer/0006_chars.txt)0
-rw-r--r--crates/ra_syntax/test_data/lexer/ok/0007_lifetimes.rs (renamed from crates/ra_syntax/test_data/lexer/0007_lifetimes.rs)0
-rw-r--r--crates/ra_syntax/test_data/lexer/ok/0007_lifetimes.txt (renamed from crates/ra_syntax/test_data/lexer/0007_lifetimes.txt)0
-rw-r--r--crates/ra_syntax/test_data/lexer/ok/0008_byte_strings.rs (renamed from crates/ra_syntax/test_data/lexer/0008_byte_strings.rs)0
-rw-r--r--crates/ra_syntax/test_data/lexer/ok/0008_byte_strings.txt (renamed from crates/ra_syntax/test_data/lexer/0008_byte_strings.txt)0
-rw-r--r--crates/ra_syntax/test_data/lexer/ok/0009_strings.rs (renamed from crates/ra_syntax/test_data/lexer/0009_strings.rs)0
-rw-r--r--crates/ra_syntax/test_data/lexer/ok/0009_strings.txt (renamed from crates/ra_syntax/test_data/lexer/0009_strings.txt)0
-rw-r--r--crates/ra_syntax/test_data/lexer/ok/0010_single_line_comments.rs12
-rw-r--r--crates/ra_syntax/test_data/lexer/ok/0010_single_line_comments.txt22
-rw-r--r--crates/ra_syntax/test_data/lexer/ok/0011_keywords.rs (renamed from crates/ra_syntax/test_data/lexer/0011_keywords.rs)0
-rw-r--r--crates/ra_syntax/test_data/lexer/ok/0011_keywords.txt (renamed from crates/ra_syntax/test_data/lexer/0011_keywords.txt)0
-rw-r--r--crates/ra_syntax/test_data/lexer/ok/0012_block_comment.rs (renamed from crates/ra_syntax/test_data/lexer/00012_block_comment.rs)1
-rw-r--r--crates/ra_syntax/test_data/lexer/ok/0012_block_comment.txt (renamed from crates/ra_syntax/test_data/lexer/00012_block_comment.txt)1
-rw-r--r--crates/ra_syntax/test_data/lexer/ok/0013_raw_strings.rs (renamed from crates/ra_syntax/test_data/lexer/0013_raw_strings.rs)0
-rw-r--r--crates/ra_syntax/test_data/lexer/ok/0013_raw_strings.txt (renamed from crates/ra_syntax/test_data/lexer/0013_raw_strings.txt)0
-rw-r--r--crates/ra_syntax/test_data/lexer/ok/0014_raw_ident.rs (renamed from crates/ra_syntax/test_data/lexer/0016_raw_ident.rs)0
-rw-r--r--crates/ra_syntax/test_data/lexer/ok/0014_raw_ident.txt (renamed from crates/ra_syntax/test_data/lexer/0016_raw_ident.txt)0
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0010_wrong_order_fns.rs2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0010_wrong_order_fns.txt12
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0004_value_parameters_no_patterns.rs2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0004_value_parameters_no_patterns.txt115
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0104_path_fn_trait_args.rs2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0104_path_fn_trait_args.txt61
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0128_combined_fns.rs2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0128_combined_fns.txt6
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0152_fn_patterns.rs6
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0152_fn_patterns.txt164
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0153_trait_fn_patterns.rs6
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0153_trait_fn_patterns.txt161
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0154_fn_pointer_param_ident_path.rs2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0154_fn_pointer_param_ident_path.txt58
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0155_closure_params.rs3
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0155_closure_params.txt70
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0030_traits.rs4
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0030_traits.txt154
180 files changed, 1471 insertions, 390 deletions
diff --git a/crates/ra_syntax/Cargo.toml b/crates/ra_syntax/Cargo.toml
index c5a3d1999..83db943fe 100644
--- a/crates/ra_syntax/Cargo.toml
+++ b/crates/ra_syntax/Cargo.toml
@@ -4,7 +4,7 @@ name = "ra_syntax"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6license = "MIT OR Apache-2.0" 6license = "MIT OR Apache-2.0"
7description = "Comment and whitespace preserving parser for the Rust langauge" 7description = "Comment and whitespace preserving parser for the Rust language"
8repository = "https://github.com/rust-analyzer/rust-analyzer" 8repository = "https://github.com/rust-analyzer/rust-analyzer"
9 9
10[lib] 10[lib]
diff --git a/crates/ra_syntax/src/algo.rs b/crates/ra_syntax/src/algo.rs
index 30a479f01..acf677e7d 100644
--- a/crates/ra_syntax/src/algo.rs
+++ b/crates/ra_syntax/src/algo.rs
@@ -81,7 +81,7 @@ impl TreeDiff {
81/// Specifically, returns a map whose keys are descendants of `from` and values 81/// Specifically, returns a map whose keys are descendants of `from` and values
82/// are descendants of `to`, such that `replace_descendants(from, map) == to`. 82/// are descendants of `to`, such that `replace_descendants(from, map) == to`.
83/// 83///
84/// A trivial solution is a singletom map `{ from: to }`, but this function 84/// A trivial solution is a singleton map `{ from: to }`, but this function
85/// tries to find a more fine-grained diff. 85/// tries to find a more fine-grained diff.
86pub fn diff(from: &SyntaxNode, to: &SyntaxNode) -> TreeDiff { 86pub fn diff(from: &SyntaxNode, to: &SyntaxNode) -> TreeDiff {
87 let mut buf = FxHashMap::default(); 87 let mut buf = FxHashMap::default();
diff --git a/crates/ra_syntax/src/ast/expr_extensions.rs b/crates/ra_syntax/src/ast/expr_extensions.rs
index 539759450..2e50a095c 100644
--- a/crates/ra_syntax/src/ast/expr_extensions.rs
+++ b/crates/ra_syntax/src/ast/expr_extensions.rs
@@ -7,6 +7,21 @@ use crate::{
7 SyntaxToken, T, 7 SyntaxToken, T,
8}; 8};
9 9
10impl ast::Expr {
11 pub fn is_block_like(&self) -> bool {
12 match self {
13 ast::Expr::IfExpr(_)
14 | ast::Expr::LoopExpr(_)
15 | ast::Expr::ForExpr(_)
16 | ast::Expr::WhileExpr(_)
17 | ast::Expr::BlockExpr(_)
18 | ast::Expr::MatchExpr(_)
19 | ast::Expr::TryBlockExpr(_) => true,
20 _ => false,
21 }
22 }
23}
24
10#[derive(Debug, Clone, PartialEq, Eq)] 25#[derive(Debug, Clone, PartialEq, Eq)]
11pub enum ElseBranch { 26pub enum ElseBranch {
12 Block(ast::BlockExpr), 27 Block(ast::BlockExpr),
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs
index 33d5578e7..435135f92 100644
--- a/crates/ra_syntax/src/ast/generated.rs
+++ b/crates/ra_syntax/src/ast/generated.rs
@@ -1,4 +1,4 @@
1//! Generated file, do not edit by hand, see `crate/ra_tools/src/codegen` 1//! Generated file, do not edit by hand, see `xtask/src/codegen`
2 2
3use crate::{ 3use crate::{
4 ast::{self, AstChildren, AstNode}, 4 ast::{self, AstChildren, AstNode},
diff --git a/crates/ra_syntax/src/ast/make.rs b/crates/ra_syntax/src/ast/make.rs
index 36e648180..862eb1172 100644
--- a/crates/ra_syntax/src/ast/make.rs
+++ b/crates/ra_syntax/src/ast/make.rs
@@ -2,7 +2,7 @@
2//! of smaller pieces. 2//! of smaller pieces.
3use itertools::Itertools; 3use itertools::Itertools;
4 4
5use crate::{ast, AstNode, SourceFile, SyntaxKind, SyntaxToken}; 5use crate::{ast, AstNode, SourceFile, SyntaxKind, SyntaxNode, SyntaxToken};
6 6
7pub fn name(text: &str) -> ast::Name { 7pub fn name(text: &str) -> ast::Name {
8 ast_from_text(&format!("mod {};", text)) 8 ast_from_text(&format!("mod {};", text))
@@ -33,6 +33,21 @@ pub fn record_field(name: ast::NameRef, expr: Option<ast::Expr>) -> ast::RecordF
33 } 33 }
34} 34}
35 35
36pub fn block_expr(
37 stmts: impl IntoIterator<Item = ast::Stmt>,
38 tail_expr: Option<ast::Expr>,
39) -> ast::BlockExpr {
40 let mut text = "{\n".to_string();
41 for stmt in stmts.into_iter() {
42 text += &format!(" {}\n", stmt.syntax());
43 }
44 if let Some(tail_expr) = tail_expr {
45 text += &format!(" {}\n", tail_expr.syntax())
46 }
47 text += "}";
48 ast_from_text(&format!("fn f() {}", text))
49}
50
36pub fn block_from_expr(e: ast::Expr) -> ast::Block { 51pub fn block_from_expr(e: ast::Expr) -> ast::Block {
37 return from_text(&format!("{{ {} }}", e.syntax())); 52 return from_text(&format!("{{ {} }}", e.syntax()));
38 53
@@ -62,6 +77,13 @@ pub fn expr_return() -> ast::Expr {
62pub fn expr_match(expr: ast::Expr, match_arm_list: ast::MatchArmList) -> ast::Expr { 77pub fn expr_match(expr: ast::Expr, match_arm_list: ast::MatchArmList) -> ast::Expr {
63 expr_from_text(&format!("match {} {}", expr.syntax(), match_arm_list.syntax())) 78 expr_from_text(&format!("match {} {}", expr.syntax(), match_arm_list.syntax()))
64} 79}
80pub fn expr_if(condition: ast::Expr, then_branch: ast::BlockExpr) -> ast::Expr {
81 expr_from_text(&format!("if {} {}", condition.syntax(), then_branch.syntax()))
82}
83pub fn expr_prefix(op: SyntaxKind, expr: ast::Expr) -> ast::Expr {
84 let token = token(op);
85 expr_from_text(&format!("{}{}", token, expr.syntax()))
86}
65fn expr_from_text(text: &str) -> ast::Expr { 87fn expr_from_text(text: &str) -> ast::Expr {
66 ast_from_text(&format!("const C: () = {};", text)) 88 ast_from_text(&format!("const C: () = {};", text))
67} 89}
@@ -122,11 +144,18 @@ pub fn match_arm(pats: impl IntoIterator<Item = ast::Pat>, expr: ast::Expr) -> a
122} 144}
123 145
124pub fn match_arm_list(arms: impl IntoIterator<Item = ast::MatchArm>) -> ast::MatchArmList { 146pub fn match_arm_list(arms: impl IntoIterator<Item = ast::MatchArm>) -> ast::MatchArmList {
125 let arms_str = arms.into_iter().map(|arm| format!("\n {}", arm.syntax())).join(","); 147 let arms_str = arms
126 return from_text(&format!("{},\n", arms_str)); 148 .into_iter()
149 .map(|arm| {
150 let needs_comma = arm.expr().map_or(true, |it| !it.is_block_like());
151 let comma = if needs_comma { "," } else { "" };
152 format!(" {}{}\n", arm.syntax(), comma)
153 })
154 .collect::<String>();
155 return from_text(&format!("{}", arms_str));
127 156
128 fn from_text(text: &str) -> ast::MatchArmList { 157 fn from_text(text: &str) -> ast::MatchArmList {
129 ast_from_text(&format!("fn f() {{ match () {{{}}} }}", text)) 158 ast_from_text(&format!("fn f() {{ match () {{\n{}}} }}", text))
130 } 159 }
131} 160}
132 161
@@ -151,14 +180,6 @@ pub fn where_clause(preds: impl IntoIterator<Item = ast::WherePred>) -> ast::Whe
151 } 180 }
152} 181}
153 182
154pub fn if_expression(condition: &ast::Expr, statement: &str) -> ast::IfExpr {
155 ast_from_text(&format!(
156 "fn f() {{ if !{} {{\n {}\n}}\n}}",
157 condition.syntax().text(),
158 statement
159 ))
160}
161
162pub fn let_stmt(pattern: ast::Pat, initializer: Option<ast::Expr>) -> ast::LetStmt { 183pub fn let_stmt(pattern: ast::Pat, initializer: Option<ast::Expr>) -> ast::LetStmt {
163 let text = match initializer { 184 let text = match initializer {
164 Some(it) => format!("let {} = {};", pattern.syntax(), it.syntax()), 185 Some(it) => format!("let {} = {};", pattern.syntax(), it.syntax()),
@@ -166,6 +187,9 @@ pub fn let_stmt(pattern: ast::Pat, initializer: Option<ast::Expr>) -> ast::LetSt
166 }; 187 };
167 ast_from_text(&format!("fn f() {{ {} }}", text)) 188 ast_from_text(&format!("fn f() {{ {} }}", text))
168} 189}
190pub fn expr_stmt(expr: ast::Expr) -> ast::ExprStmt {
191 ast_from_text(&format!("fn f() {{ {}; }}", expr.syntax()))
192}
169 193
170pub fn token(kind: SyntaxKind) -> SyntaxToken { 194pub fn token(kind: SyntaxKind) -> SyntaxToken {
171 tokens::SOURCE_FILE 195 tokens::SOURCE_FILE
@@ -179,7 +203,16 @@ pub fn token(kind: SyntaxKind) -> SyntaxToken {
179 203
180fn ast_from_text<N: AstNode>(text: &str) -> N { 204fn ast_from_text<N: AstNode>(text: &str) -> N {
181 let parse = SourceFile::parse(text); 205 let parse = SourceFile::parse(text);
182 parse.tree().syntax().descendants().find_map(N::cast).unwrap() 206 let node = parse.tree().syntax().descendants().find_map(N::cast).unwrap();
207 let node = node.syntax().clone();
208 let node = unroot(node);
209 let node = N::cast(node).unwrap();
210 assert_eq!(node.syntax().text_range().start(), 0.into());
211 node
212}
213
214fn unroot(n: SyntaxNode) -> SyntaxNode {
215 SyntaxNode::new_root(n.green().clone())
183} 216}
184 217
185pub mod tokens { 218pub mod tokens {
@@ -187,7 +220,7 @@ pub mod tokens {
187 use once_cell::sync::Lazy; 220 use once_cell::sync::Lazy;
188 221
189 pub(super) static SOURCE_FILE: Lazy<Parse<SourceFile>> = 222 pub(super) static SOURCE_FILE: Lazy<Parse<SourceFile>> =
190 Lazy::new(|| SourceFile::parse("const C: <()>::Item = (1 != 1, 2 == 2)\n;")); 223 Lazy::new(|| SourceFile::parse("const C: <()>::Item = (1 != 1, 2 == 2, !true)\n;"));
191 224
192 pub fn comma() -> SyntaxToken { 225 pub fn comma() -> SyntaxToken {
193 SOURCE_FILE 226 SOURCE_FILE
diff --git a/crates/ra_syntax/src/lib.rs b/crates/ra_syntax/src/lib.rs
index 9931fec84..f8f4b64c1 100644
--- a/crates/ra_syntax/src/lib.rs
+++ b/crates/ra_syntax/src/lib.rs
@@ -41,7 +41,9 @@ use crate::syntax_node::GreenNode;
41pub use crate::{ 41pub use crate::{
42 algo::InsertPosition, 42 algo::InsertPosition,
43 ast::{AstNode, AstToken}, 43 ast::{AstNode, AstToken},
44 parsing::{classify_literal, tokenize, Token}, 44 parsing::{
45 lex_single_syntax_kind, lex_single_valid_syntax_kind, tokenize, Token, TokenizeError,
46 },
45 ptr::{AstPtr, SyntaxNodePtr}, 47 ptr::{AstPtr, SyntaxNodePtr},
46 syntax_error::{Location, SyntaxError, SyntaxErrorKind}, 48 syntax_error::{Location, SyntaxError, SyntaxErrorKind},
47 syntax_node::{ 49 syntax_node::{
diff --git a/crates/ra_syntax/src/parsing.rs b/crates/ra_syntax/src/parsing.rs
index 0387f0378..e5eb80850 100644
--- a/crates/ra_syntax/src/parsing.rs
+++ b/crates/ra_syntax/src/parsing.rs
@@ -7,15 +7,23 @@ mod text_tree_sink;
7mod reparsing; 7mod reparsing;
8 8
9use crate::{syntax_node::GreenNode, SyntaxError}; 9use crate::{syntax_node::GreenNode, SyntaxError};
10use text_token_source::TextTokenSource;
11use text_tree_sink::TextTreeSink;
10 12
11pub use self::lexer::{classify_literal, tokenize, Token}; 13pub use lexer::*;
12 14
13pub(crate) use self::reparsing::incremental_reparse; 15pub(crate) use self::reparsing::incremental_reparse;
14 16
15pub(crate) fn parse_text(text: &str) -> (GreenNode, Vec<SyntaxError>) { 17pub(crate) fn parse_text(text: &str) -> (GreenNode, Vec<SyntaxError>) {
16 let tokens = tokenize(&text); 18 let (tokens, lexer_errors) = tokenize(&text);
17 let mut token_source = text_token_source::TextTokenSource::new(text, &tokens); 19
18 let mut tree_sink = text_tree_sink::TextTreeSink::new(text, &tokens); 20 let mut token_source = TextTokenSource::new(text, &tokens);
21 let mut tree_sink = TextTreeSink::new(text, &tokens);
22
19 ra_parser::parse(&mut token_source, &mut tree_sink); 23 ra_parser::parse(&mut token_source, &mut tree_sink);
20 tree_sink.finish() 24
25 let (tree, mut parser_errors) = tree_sink.finish();
26 parser_errors.extend(lexer_errors);
27
28 (tree, parser_errors)
21} 29}
diff --git a/crates/ra_syntax/src/parsing/lexer.rs b/crates/ra_syntax/src/parsing/lexer.rs
index 6d839208d..f889e6a1d 100644
--- a/crates/ra_syntax/src/parsing/lexer.rs
+++ b/crates/ra_syntax/src/parsing/lexer.rs
@@ -1,8 +1,10 @@
1//! FIXME: write short doc here 1//! Lexer analyzes raw input string and produces lexemes (tokens).
2//! It is just a bridge to `rustc_lexer`.
2 3
3use crate::{ 4use crate::{
5 SyntaxError, SyntaxErrorKind,
4 SyntaxKind::{self, *}, 6 SyntaxKind::{self, *},
5 TextUnit, 7 TextRange, TextUnit,
6}; 8};
7 9
8/// A token of Rust source. 10/// A token of Rust source.
@@ -14,91 +16,261 @@ pub struct Token {
14 pub len: TextUnit, 16 pub len: TextUnit,
15} 17}
16 18
17fn match_literal_kind(kind: rustc_lexer::LiteralKind) -> SyntaxKind { 19/// Break a string up into its component tokens.
18 match kind { 20/// Beware that it checks for shebang first and its length contributes to resulting
19 rustc_lexer::LiteralKind::Int { .. } => INT_NUMBER, 21/// tokens offsets.
20 rustc_lexer::LiteralKind::Float { .. } => FLOAT_NUMBER, 22pub fn tokenize(text: &str) -> (Vec<Token>, Vec<SyntaxError>) {
21 rustc_lexer::LiteralKind::Char { .. } => CHAR, 23 // non-empty string is a precondtion of `rustc_lexer::strip_shebang()`.
22 rustc_lexer::LiteralKind::Byte { .. } => BYTE, 24 if text.is_empty() {
23 rustc_lexer::LiteralKind::Str { .. } => STRING, 25 return Default::default();
24 rustc_lexer::LiteralKind::ByteStr { .. } => BYTE_STRING, 26 }
25 rustc_lexer::LiteralKind::RawStr { .. } => RAW_STRING, 27
26 rustc_lexer::LiteralKind::RawByteStr { .. } => RAW_BYTE_STRING, 28 let mut tokens = Vec::new();
29 let mut errors = Vec::new();
30
31 let mut offset: usize = rustc_lexer::strip_shebang(text)
32 .map(|shebang_len| {
33 tokens.push(Token { kind: SHEBANG, len: TextUnit::from_usize(shebang_len) });
34 shebang_len
35 })
36 .unwrap_or(0);
37
38 let text_without_shebang = &text[offset..];
39
40 for rustc_token in rustc_lexer::tokenize(text_without_shebang) {
41 let token_len = TextUnit::from_usize(rustc_token.len);
42 let token_range = TextRange::offset_len(TextUnit::from_usize(offset), token_len);
43
44 let (syntax_kind, error) =
45 rustc_token_kind_to_syntax_kind(&rustc_token.kind, &text[token_range]);
46
47 tokens.push(Token { kind: syntax_kind, len: token_len });
48
49 if let Some(error) = error {
50 errors.push(SyntaxError::new(SyntaxErrorKind::TokenizeError(error), token_range));
51 }
52
53 offset += rustc_token.len;
27 } 54 }
55
56 (tokens, errors)
57}
58
59/// Returns `SyntaxKind` and `Option<SyntaxError>` of the first token
60/// encountered at the beginning of the string.
61///
62/// Returns `None` if the string contains zero *or two or more* tokens.
63/// The token is malformed if the returned error is not `None`.
64///
65/// Beware that unescape errors are not checked at tokenization time.
66pub fn lex_single_syntax_kind(text: &str) -> Option<(SyntaxKind, Option<SyntaxError>)> {
67 lex_first_token(text)
68 .filter(|(token, _)| token.len.to_usize() == text.len())
69 .map(|(token, error)| (token.kind, error))
70}
71
72/// The same as `lex_single_syntax_kind()` but returns only `SyntaxKind` and
73/// returns `None` if any tokenization error occured.
74///
75/// Beware that unescape errors are not checked at tokenization time.
76pub fn lex_single_valid_syntax_kind(text: &str) -> Option<SyntaxKind> {
77 lex_first_token(text)
78 .filter(|(token, error)| !error.is_some() && token.len.to_usize() == text.len())
79 .map(|(token, _error)| token.kind)
28} 80}
29 81
30/// Break a string up into its component tokens 82/// Returns `SyntaxKind` and `Option<SyntaxError>` of the first token
31pub fn tokenize(text: &str) -> Vec<Token> { 83/// encountered at the beginning of the string.
84///
85/// Returns `None` if the string contains zero tokens or if the token was parsed
86/// with an error.
87/// The token is malformed if the returned error is not `None`.
88///
89/// Beware that unescape errors are not checked at tokenization time.
90fn lex_first_token(text: &str) -> Option<(Token, Option<SyntaxError>)> {
91 // non-empty string is a precondtion of `rustc_lexer::first_token()`.
32 if text.is_empty() { 92 if text.is_empty() {
33 return vec![]; 93 return None;
34 }
35 let mut text = text;
36 let mut acc = Vec::new();
37 if let Some(len) = rustc_lexer::strip_shebang(text) {
38 acc.push(Token { kind: SHEBANG, len: TextUnit::from_usize(len) });
39 text = &text[len..];
40 } 94 }
41 while !text.is_empty() { 95
42 let rustc_token = rustc_lexer::first_token(text); 96 let rustc_token = rustc_lexer::first_token(text);
43 let kind = match rustc_token.kind { 97 let (syntax_kind, error) = rustc_token_kind_to_syntax_kind(&rustc_token.kind, text);
44 rustc_lexer::TokenKind::LineComment => COMMENT, 98
45 rustc_lexer::TokenKind::BlockComment { .. } => COMMENT, 99 let token = Token { kind: syntax_kind, len: TextUnit::from_usize(rustc_token.len) };
46 rustc_lexer::TokenKind::Whitespace => WHITESPACE, 100 let error = error.map(|error| {
47 rustc_lexer::TokenKind::Ident => { 101 SyntaxError::new(
48 let token_text = &text[..rustc_token.len]; 102 SyntaxErrorKind::TokenizeError(error),
103 TextRange::from_to(TextUnit::from(0), TextUnit::of_str(text)),
104 )
105 });
106
107 Some((token, error))
108}
109
110// FIXME: simplify TokenizeError to `SyntaxError(String, TextRange)` as per @matklad advice:
111// https://github.com/rust-analyzer/rust-analyzer/pull/2911/files#r371175067
112
113/// Describes the values of `SyntaxErrorKind::TokenizeError` enum variant.
114/// It describes all the types of errors that may happen during the tokenization
115/// of Rust source.
116#[derive(Debug, Clone, PartialEq, Eq, Hash)]
117pub enum TokenizeError {
118 /// Base prefix was provided, but there were no digits
119 /// after it, e.g. `0x`, `0b`.
120 EmptyInt,
121 /// Float exponent lacks digits e.g. `12.34e+`, `12.3E+`, `12e-`, `1_E-`,
122 EmptyExponent,
123
124 /// Block comment lacks trailing delimiter `*/`
125 UnterminatedBlockComment,
126 /// Character literal lacks trailing delimiter `'`
127 UnterminatedChar,
128 /// Characterish byte literal lacks trailing delimiter `'`
129 UnterminatedByte,
130 /// String literal lacks trailing delimiter `"`
131 UnterminatedString,
132 /// Byte string literal lacks trailing delimiter `"`
133 UnterminatedByteString,
134 /// Raw literal lacks trailing delimiter e.g. `"##`
135 UnterminatedRawString,
136 /// Raw byte string literal lacks trailing delimiter e.g. `"##`
137 UnterminatedRawByteString,
138
139 /// Raw string lacks a quote after the pound characters e.g. `r###`
140 UnstartedRawString,
141 /// Raw byte string lacks a quote after the pound characters e.g. `br###`
142 UnstartedRawByteString,
143
144 /// Lifetime starts with a number e.g. `'4ever`
145 LifetimeStartsWithNumber,
146}
147
148fn rustc_token_kind_to_syntax_kind(
149 rustc_token_kind: &rustc_lexer::TokenKind,
150 token_text: &str,
151) -> (SyntaxKind, Option<TokenizeError>) {
152 // A note on an intended tradeoff:
153 // We drop some useful infromation here (see patterns with double dots `..`)
154 // Storing that info in `SyntaxKind` is not possible due to its layout requirements of
155 // being `u16` that come from `rowan::SyntaxKind`.
156
157 let syntax_kind = {
158 use rustc_lexer::TokenKind as TK;
159 use TokenizeError as TE;
160
161 match rustc_token_kind {
162 TK::LineComment => COMMENT,
163
164 TK::BlockComment { terminated: true } => COMMENT,
165 TK::BlockComment { terminated: false } => {
166 return (COMMENT, Some(TE::UnterminatedBlockComment));
167 }
168
169 TK::Whitespace => WHITESPACE,
170
171 TK::Ident => {
49 if token_text == "_" { 172 if token_text == "_" {
50 UNDERSCORE 173 UNDERSCORE
51 } else { 174 } else {
52 SyntaxKind::from_keyword(&text[..rustc_token.len]).unwrap_or(IDENT) 175 SyntaxKind::from_keyword(token_text).unwrap_or(IDENT)
53 } 176 }
54 } 177 }
55 rustc_lexer::TokenKind::RawIdent => IDENT, 178
56 rustc_lexer::TokenKind::Literal { kind, .. } => match_literal_kind(kind), 179 TK::RawIdent => IDENT,
57 rustc_lexer::TokenKind::Lifetime { .. } => LIFETIME, 180 TK::Literal { kind, .. } => return match_literal_kind(&kind),
58 rustc_lexer::TokenKind::Semi => SEMI, 181
59 rustc_lexer::TokenKind::Comma => COMMA, 182 TK::Lifetime { starts_with_number: false } => LIFETIME,
60 rustc_lexer::TokenKind::Dot => DOT, 183 TK::Lifetime { starts_with_number: true } => {
61 rustc_lexer::TokenKind::OpenParen => L_PAREN, 184 return (LIFETIME, Some(TE::LifetimeStartsWithNumber))
62 rustc_lexer::TokenKind::CloseParen => R_PAREN, 185 }
63 rustc_lexer::TokenKind::OpenBrace => L_CURLY, 186
64 rustc_lexer::TokenKind::CloseBrace => R_CURLY, 187 TK::Semi => SEMI,
65 rustc_lexer::TokenKind::OpenBracket => L_BRACK, 188 TK::Comma => COMMA,
66 rustc_lexer::TokenKind::CloseBracket => R_BRACK, 189 TK::Dot => DOT,
67 rustc_lexer::TokenKind::At => AT, 190 TK::OpenParen => L_PAREN,
68 rustc_lexer::TokenKind::Pound => POUND, 191 TK::CloseParen => R_PAREN,
69 rustc_lexer::TokenKind::Tilde => TILDE, 192 TK::OpenBrace => L_CURLY,
70 rustc_lexer::TokenKind::Question => QUESTION, 193 TK::CloseBrace => R_CURLY,
71 rustc_lexer::TokenKind::Colon => COLON, 194 TK::OpenBracket => L_BRACK,
72 rustc_lexer::TokenKind::Dollar => DOLLAR, 195 TK::CloseBracket => R_BRACK,
73 rustc_lexer::TokenKind::Eq => EQ, 196 TK::At => AT,
74 rustc_lexer::TokenKind::Not => EXCL, 197 TK::Pound => POUND,
75 rustc_lexer::TokenKind::Lt => L_ANGLE, 198 TK::Tilde => TILDE,
76 rustc_lexer::TokenKind::Gt => R_ANGLE, 199 TK::Question => QUESTION,
77 rustc_lexer::TokenKind::Minus => MINUS, 200 TK::Colon => COLON,
78 rustc_lexer::TokenKind::And => AMP, 201 TK::Dollar => DOLLAR,
79 rustc_lexer::TokenKind::Or => PIPE, 202 TK::Eq => EQ,
80 rustc_lexer::TokenKind::Plus => PLUS, 203 TK::Not => EXCL,
81 rustc_lexer::TokenKind::Star => STAR, 204 TK::Lt => L_ANGLE,
82 rustc_lexer::TokenKind::Slash => SLASH, 205 TK::Gt => R_ANGLE,
83 rustc_lexer::TokenKind::Caret => CARET, 206 TK::Minus => MINUS,
84 rustc_lexer::TokenKind::Percent => PERCENT, 207 TK::And => AMP,
85 rustc_lexer::TokenKind::Unknown => ERROR, 208 TK::Or => PIPE,
209 TK::Plus => PLUS,
210 TK::Star => STAR,
211 TK::Slash => SLASH,
212 TK::Caret => CARET,
213 TK::Percent => PERCENT,
214 TK::Unknown => ERROR,
215 }
216 };
217
218 return (syntax_kind, None);
219
220 fn match_literal_kind(kind: &rustc_lexer::LiteralKind) -> (SyntaxKind, Option<TokenizeError>) {
221 use rustc_lexer::LiteralKind as LK;
222 use TokenizeError as TE;
223
224 #[rustfmt::skip]
225 let syntax_kind = match *kind {
226 LK::Int { empty_int: false, .. } => INT_NUMBER,
227 LK::Int { empty_int: true, .. } => {
228 return (INT_NUMBER, Some(TE::EmptyInt))
229 }
230
231 LK::Float { empty_exponent: false, .. } => FLOAT_NUMBER,
232 LK::Float { empty_exponent: true, .. } => {
233 return (FLOAT_NUMBER, Some(TE::EmptyExponent))
234 }
235
236 LK::Char { terminated: true } => CHAR,
237 LK::Char { terminated: false } => {
238 return (CHAR, Some(TE::UnterminatedChar))
239 }
240
241 LK::Byte { terminated: true } => BYTE,
242 LK::Byte { terminated: false } => {
243 return (BYTE, Some(TE::UnterminatedByte))
244 }
245
246 LK::Str { terminated: true } => STRING,
247 LK::Str { terminated: false } => {
248 return (STRING, Some(TE::UnterminatedString))
249 }
250
251
252 LK::ByteStr { terminated: true } => BYTE_STRING,
253 LK::ByteStr { terminated: false } => {
254 return (BYTE_STRING, Some(TE::UnterminatedByteString))
255 }
256
257 LK::RawStr { started: true, terminated: true, .. } => RAW_STRING,
258 LK::RawStr { started: true, terminated: false, .. } => {
259 return (RAW_STRING, Some(TE::UnterminatedRawString))
260 }
261 LK::RawStr { started: false, .. } => {
262 return (RAW_STRING, Some(TE::UnstartedRawString))
263 }
264
265 LK::RawByteStr { started: true, terminated: true, .. } => RAW_BYTE_STRING,
266 LK::RawByteStr { started: true, terminated: false, .. } => {
267 return (RAW_BYTE_STRING, Some(TE::UnterminatedRawByteString))
268 }
269 LK::RawByteStr { started: false, .. } => {
270 return (RAW_BYTE_STRING, Some(TE::UnstartedRawByteString))
271 }
86 }; 272 };
87 let token = Token { kind, len: TextUnit::from_usize(rustc_token.len) };
88 acc.push(token);
89 text = &text[rustc_token.len..];
90 }
91 acc
92}
93 273
94pub fn classify_literal(text: &str) -> Option<Token> { 274 (syntax_kind, None)
95 let t = rustc_lexer::first_token(text);
96 if t.len != text.len() {
97 return None;
98 } 275 }
99 let kind = match t.kind {
100 rustc_lexer::TokenKind::Literal { kind, .. } => match_literal_kind(kind),
101 _ => return None,
102 };
103 Some(Token { kind, len: TextUnit::from_usize(t.len) })
104} 276}
diff --git a/crates/ra_syntax/src/parsing/reparsing.rs b/crates/ra_syntax/src/parsing/reparsing.rs
index 06bdda11d..a86da0675 100644
--- a/crates/ra_syntax/src/parsing/reparsing.rs
+++ b/crates/ra_syntax/src/parsing/reparsing.rs
@@ -12,7 +12,7 @@ use ra_text_edit::AtomTextEdit;
12use crate::{ 12use crate::{
13 algo, 13 algo,
14 parsing::{ 14 parsing::{
15 lexer::{tokenize, Token}, 15 lexer::{lex_single_syntax_kind, tokenize, Token},
16 text_token_source::TextTokenSource, 16 text_token_source::TextTokenSource,
17 text_tree_sink::TextTreeSink, 17 text_tree_sink::TextTreeSink,
18 }, 18 },
@@ -41,37 +41,42 @@ fn reparse_token<'node>(
41 root: &'node SyntaxNode, 41 root: &'node SyntaxNode,
42 edit: &AtomTextEdit, 42 edit: &AtomTextEdit,
43) -> Option<(GreenNode, TextRange)> { 43) -> Option<(GreenNode, TextRange)> {
44 let token = algo::find_covering_element(root, edit.delete).as_token()?.clone(); 44 let prev_token = algo::find_covering_element(root, edit.delete).as_token()?.clone();
45 match token.kind() { 45 let prev_token_kind = prev_token.kind();
46 match prev_token_kind {
46 WHITESPACE | COMMENT | IDENT | STRING | RAW_STRING => { 47 WHITESPACE | COMMENT | IDENT | STRING | RAW_STRING => {
47 if token.kind() == WHITESPACE || token.kind() == COMMENT { 48 if prev_token_kind == WHITESPACE || prev_token_kind == COMMENT {
48 // removing a new line may extends previous token 49 // removing a new line may extends previous token
49 if token.text().to_string()[edit.delete - token.text_range().start()].contains('\n') 50 let deleted_range = edit.delete - prev_token.text_range().start();
50 { 51 if prev_token.text()[deleted_range].contains('\n') {
51 return None; 52 return None;
52 } 53 }
53 } 54 }
54 55
55 let text = get_text_after_edit(token.clone().into(), &edit); 56 let mut new_text = get_text_after_edit(prev_token.clone().into(), &edit);
56 let lex_tokens = tokenize(&text); 57 let (new_token_kind, _error) = lex_single_syntax_kind(&new_text)?;
57 let lex_token = match lex_tokens[..] {
58 [lex_token] if lex_token.kind == token.kind() => lex_token,
59 _ => return None,
60 };
61 58
62 if lex_token.kind == IDENT && is_contextual_kw(&text) { 59 if new_token_kind != prev_token_kind
60 || (new_token_kind == IDENT && is_contextual_kw(&new_text))
61 {
63 return None; 62 return None;
64 } 63 }
65 64
66 if let Some(next_char) = root.text().char_at(token.text_range().end()) { 65 // Check that edited token is not a part of the bigger token.
67 let tokens_with_next_char = tokenize(&format!("{}{}", text, next_char)); 66 // E.g. if for source code `bruh"str"` the user removed `ruh`, then
68 if tokens_with_next_char.len() == 1 { 67 // `b` no longer remains an identifier, but becomes a part of byte string literal
68 if let Some(next_char) = root.text().char_at(prev_token.text_range().end()) {
69 new_text.push(next_char);
70 let token_with_next_char = lex_single_syntax_kind(&new_text);
71 if let Some((_kind, _error)) = token_with_next_char {
69 return None; 72 return None;
70 } 73 }
74 new_text.pop();
71 } 75 }
72 76
73 let new_token = GreenToken::new(rowan::SyntaxKind(token.kind().into()), text.into()); 77 let new_token =
74 Some((token.replace_with(new_token), token.text_range())) 78 GreenToken::new(rowan::SyntaxKind(prev_token_kind.into()), new_text.into());
79 Some((prev_token.replace_with(new_token), prev_token.text_range()))
75 } 80 }
76 _ => None, 81 _ => None,
77 } 82 }
@@ -83,20 +88,26 @@ fn reparse_block<'node>(
83) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> { 88) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> {
84 let (node, reparser) = find_reparsable_node(root, edit.delete)?; 89 let (node, reparser) = find_reparsable_node(root, edit.delete)?;
85 let text = get_text_after_edit(node.clone().into(), &edit); 90 let text = get_text_after_edit(node.clone().into(), &edit);
86 let tokens = tokenize(&text); 91
92 let (tokens, new_lexer_errors) = tokenize(&text);
87 if !is_balanced(&tokens) { 93 if !is_balanced(&tokens) {
88 return None; 94 return None;
89 } 95 }
96
90 let mut token_source = TextTokenSource::new(&text, &tokens); 97 let mut token_source = TextTokenSource::new(&text, &tokens);
91 let mut tree_sink = TextTreeSink::new(&text, &tokens); 98 let mut tree_sink = TextTreeSink::new(&text, &tokens);
92 reparser.parse(&mut token_source, &mut tree_sink); 99 reparser.parse(&mut token_source, &mut tree_sink);
93 let (green, new_errors) = tree_sink.finish(); 100
94 Some((node.replace_with(green), new_errors, node.text_range())) 101 let (green, mut new_parser_errors) = tree_sink.finish();
102 new_parser_errors.extend(new_lexer_errors);
103
104 Some((node.replace_with(green), new_parser_errors, node.text_range()))
95} 105}
96 106
97fn get_text_after_edit(element: SyntaxElement, edit: &AtomTextEdit) -> String { 107fn get_text_after_edit(element: SyntaxElement, edit: &AtomTextEdit) -> String {
98 let edit = 108 let edit =
99 AtomTextEdit::replace(edit.delete - element.text_range().start(), edit.insert.clone()); 109 AtomTextEdit::replace(edit.delete - element.text_range().start(), edit.insert.clone());
110
100 let text = match element { 111 let text = match element {
101 NodeOrToken::Token(token) => token.text().to_string(), 112 NodeOrToken::Token(token) => token.text().to_string(),
102 NodeOrToken::Node(node) => node.text().to_string(), 113 NodeOrToken::Node(node) => node.text().to_string(),
@@ -113,6 +124,7 @@ fn is_contextual_kw(text: &str) -> bool {
113 124
114fn find_reparsable_node(node: &SyntaxNode, range: TextRange) -> Option<(SyntaxNode, Reparser)> { 125fn find_reparsable_node(node: &SyntaxNode, range: TextRange) -> Option<(SyntaxNode, Reparser)> {
115 let node = algo::find_covering_element(node, range); 126 let node = algo::find_covering_element(node, range);
127
116 let mut ancestors = match node { 128 let mut ancestors = match node {
117 NodeOrToken::Token(it) => it.parent().ancestors(), 129 NodeOrToken::Token(it) => it.parent().ancestors(),
118 NodeOrToken::Node(it) => it.ancestors(), 130 NodeOrToken::Node(it) => it.ancestors(),
@@ -182,7 +194,6 @@ mod tests {
182 let fully_reparsed = SourceFile::parse(&after); 194 let fully_reparsed = SourceFile::parse(&after);
183 let incrementally_reparsed: Parse<SourceFile> = { 195 let incrementally_reparsed: Parse<SourceFile> = {
184 let f = SourceFile::parse(&before); 196 let f = SourceFile::parse(&before);
185 let edit = AtomTextEdit { delete: range, insert: replace_with.to_string() };
186 let (green, new_errors, range) = 197 let (green, new_errors, range) =
187 incremental_reparse(f.tree().syntax(), &edit, f.errors.to_vec()).unwrap(); 198 incremental_reparse(f.tree().syntax(), &edit, f.errors.to_vec()).unwrap();
188 assert_eq!(range.len(), reparsed_len.into(), "reparsed fragment has wrong length"); 199 assert_eq!(range.len(), reparsed_len.into(), "reparsed fragment has wrong length");
diff --git a/crates/ra_syntax/src/parsing/text_tree_sink.rs b/crates/ra_syntax/src/parsing/text_tree_sink.rs
index c36756d6c..dd202601d 100644
--- a/crates/ra_syntax/src/parsing/text_tree_sink.rs
+++ b/crates/ra_syntax/src/parsing/text_tree_sink.rs
@@ -92,8 +92,8 @@ impl<'a> TreeSink for TextTreeSink<'a> {
92} 92}
93 93
94impl<'a> TextTreeSink<'a> { 94impl<'a> TextTreeSink<'a> {
95 pub(super) fn new(text: &'a str, tokens: &'a [Token]) -> TextTreeSink<'a> { 95 pub(super) fn new(text: &'a str, tokens: &'a [Token]) -> Self {
96 TextTreeSink { 96 Self {
97 text, 97 text,
98 tokens, 98 tokens,
99 text_pos: 0.into(), 99 text_pos: 0.into(),
diff --git a/crates/ra_syntax/src/syntax_error.rs b/crates/ra_syntax/src/syntax_error.rs
index 6c171df8d..7f9d36618 100644
--- a/crates/ra_syntax/src/syntax_error.rs
+++ b/crates/ra_syntax/src/syntax_error.rs
@@ -4,7 +4,7 @@ use std::fmt;
4 4
5use ra_parser::ParseError; 5use ra_parser::ParseError;
6 6
7use crate::{validation::EscapeError, TextRange, TextUnit}; 7use crate::{validation::EscapeError, TextRange, TextUnit, TokenizeError};
8 8
9#[derive(Debug, Clone, PartialEq, Eq, Hash)] 9#[derive(Debug, Clone, PartialEq, Eq, Hash)]
10pub struct SyntaxError { 10pub struct SyntaxError {
@@ -12,6 +12,10 @@ pub struct SyntaxError {
12 location: Location, 12 location: Location,
13} 13}
14 14
15// FIXME: Location should be just `Location(TextRange)`
16// TextUnit enum member just unnecessarily compicates things,
17// we should'n treat it specially, it just as a `TextRange { start: x, end: x + 1 }`
18// see `location_to_range()` in ra_ide/src/diagnostics
15#[derive(Clone, PartialEq, Eq, Hash)] 19#[derive(Clone, PartialEq, Eq, Hash)]
16pub enum Location { 20pub enum Location {
17 Offset(TextUnit), 21 Offset(TextUnit),
@@ -67,6 +71,10 @@ impl SyntaxError {
67 71
68 self 72 self
69 } 73 }
74
75 pub fn debug_dump(&self, acc: &mut impl fmt::Write) {
76 writeln!(acc, "error {:?}: {}", self.location(), self.kind()).unwrap();
77 }
70} 78}
71 79
72impl fmt::Display for SyntaxError { 80impl fmt::Display for SyntaxError {
@@ -79,6 +87,10 @@ impl fmt::Display for SyntaxError {
79pub enum SyntaxErrorKind { 87pub enum SyntaxErrorKind {
80 ParseError(ParseError), 88 ParseError(ParseError),
81 EscapeError(EscapeError), 89 EscapeError(EscapeError),
90 TokenizeError(TokenizeError),
91 // FIXME: the obvious pattern of this enum dictates that the following enum variants
92 // should be wrapped into something like `SemmanticError(SemmanticError)`
93 // or `ValidateError(ValidateError)` or `SemmanticValidateError(...)`
82 InvalidBlockAttr, 94 InvalidBlockAttr,
83 InvalidMatchInnerAttr, 95 InvalidMatchInnerAttr,
84 InvalidTupleIndexFormat, 96 InvalidTupleIndexFormat,
@@ -101,6 +113,7 @@ impl fmt::Display for SyntaxErrorKind {
101 } 113 }
102 ParseError(msg) => write!(f, "{}", msg.0), 114 ParseError(msg) => write!(f, "{}", msg.0),
103 EscapeError(err) => write!(f, "{}", err), 115 EscapeError(err) => write!(f, "{}", err),
116 TokenizeError(err) => write!(f, "{}", err),
104 VisibilityNotAllowed => { 117 VisibilityNotAllowed => {
105 write!(f, "unnecessary visibility qualifier") 118 write!(f, "unnecessary visibility qualifier")
106 } 119 }
@@ -111,6 +124,51 @@ impl fmt::Display for SyntaxErrorKind {
111 } 124 }
112} 125}
113 126
127impl fmt::Display for TokenizeError {
128 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
129 #[rustfmt::skip]
130 let msg = match self {
131 TokenizeError::EmptyInt => {
132 "Missing digits after the integer base prefix"
133 }
134 TokenizeError::EmptyExponent => {
135 "Missing digits after the exponent symbol"
136 }
137 TokenizeError::UnterminatedBlockComment => {
138 "Missing trailing `*/` symbols to terminate the block comment"
139 }
140 TokenizeError::UnterminatedChar => {
141 "Missing trailing `'` symbol to terminate the character literal"
142 }
143 TokenizeError::UnterminatedByte => {
144 "Missing trailing `'` symbol to terminate the byte literal"
145 }
146 TokenizeError::UnterminatedString => {
147 "Missing trailing `\"` symbol to terminate the string literal"
148 }
149 TokenizeError::UnterminatedByteString => {
150 "Missing trailing `\"` symbol to terminate the byte string literal"
151 }
152 TokenizeError::UnterminatedRawString => {
153 "Missing trailing `\"` with `#` symbols to terminate the raw string literal"
154 }
155 TokenizeError::UnterminatedRawByteString => {
156 "Missing trailing `\"` with `#` symbols to terminate the raw byte string literal"
157 }
158 TokenizeError::UnstartedRawString => {
159 "Missing `\"` symbol after `#` symbols to begin the raw string literal"
160 }
161 TokenizeError::UnstartedRawByteString => {
162 "Missing `\"` symbol after `#` symbols to begin the raw byte string literal"
163 }
164 TokenizeError::LifetimeStartsWithNumber => {
165 "Lifetime name cannot start with a number"
166 }
167 };
168 write!(f, "{}", msg)
169 }
170}
171
114impl fmt::Display for EscapeError { 172impl fmt::Display for EscapeError {
115 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 173 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
116 let msg = match self { 174 let msg = match self {
diff --git a/crates/ra_syntax/src/syntax_node.rs b/crates/ra_syntax/src/syntax_node.rs
index b3eb5da63..7c2b18af3 100644
--- a/crates/ra_syntax/src/syntax_node.rs
+++ b/crates/ra_syntax/src/syntax_node.rs
@@ -4,7 +4,7 @@
4//! `SyntaxNode`, and a basic traversal API (parent, children, siblings). 4//! `SyntaxNode`, and a basic traversal API (parent, children, siblings).
5//! 5//!
6//! The *real* implementation is in the (language-agnostic) `rowan` crate, this 6//! The *real* implementation is in the (language-agnostic) `rowan` crate, this
7//! modules just wraps its API. 7//! module just wraps its API.
8 8
9use ra_parser::ParseError; 9use ra_parser::ParseError;
10use rowan::{GreenNodeBuilder, Language}; 10use rowan::{GreenNodeBuilder, Language};
@@ -38,17 +38,12 @@ pub type SyntaxElementChildren = rowan::SyntaxElementChildren<RustLanguage>;
38 38
39pub use rowan::{Direction, NodeOrToken}; 39pub use rowan::{Direction, NodeOrToken};
40 40
41#[derive(Default)]
41pub struct SyntaxTreeBuilder { 42pub struct SyntaxTreeBuilder {
42 errors: Vec<SyntaxError>, 43 errors: Vec<SyntaxError>,
43 inner: GreenNodeBuilder<'static>, 44 inner: GreenNodeBuilder<'static>,
44} 45}
45 46
46impl Default for SyntaxTreeBuilder {
47 fn default() -> SyntaxTreeBuilder {
48 SyntaxTreeBuilder { errors: Vec::new(), inner: GreenNodeBuilder::new() }
49 }
50}
51
52impl SyntaxTreeBuilder { 47impl SyntaxTreeBuilder {
53 pub(crate) fn finish_raw(self) -> (GreenNode, Vec<SyntaxError>) { 48 pub(crate) fn finish_raw(self) -> (GreenNode, Vec<SyntaxError>) {
54 let green = self.inner.finish(); 49 let green = self.inner.finish();
diff --git a/crates/ra_syntax/src/tests.rs b/crates/ra_syntax/src/tests.rs
index 458920607..fb22b9e54 100644
--- a/crates/ra_syntax/src/tests.rs
+++ b/crates/ra_syntax/src/tests.rs
@@ -1,18 +1,28 @@
1use std::{ 1use std::{
2 fmt::Write, 2 fmt::Write,
3 path::{Component, PathBuf}, 3 path::{Component, Path, PathBuf},
4}; 4};
5 5
6use test_utils::{collect_tests, dir_tests, project_dir, read_text}; 6use test_utils::{collect_tests, dir_tests, project_dir, read_text};
7 7
8use crate::{fuzz, SourceFile}; 8use crate::{fuzz, tokenize, Location, SourceFile, SyntaxError, TextRange, Token};
9 9
10#[test] 10#[test]
11fn lexer_tests() { 11fn lexer_tests() {
12 dir_tests(&test_data_dir(), &["lexer"], |text, _| { 12 // FIXME:
13 let tokens = crate::tokenize(text); 13 // * Add tests for unicode escapes in byte-character and [raw]-byte-string literals
14 dump_tokens(&tokens, text) 14 // * Add tests for unescape errors
15 }) 15
16 dir_tests(&test_data_dir(), &["lexer/ok"], |text, path| {
17 let (tokens, errors) = tokenize(text);
18 assert_errors_are_absent(&errors, path);
19 dump_tokens_and_errors(&tokens, &errors, text)
20 });
21 dir_tests(&test_data_dir(), &["lexer/err"], |text, path| {
22 let (tokens, errors) = tokenize(text);
23 assert_errors_are_present(&errors, path);
24 dump_tokens_and_errors(&tokens, &errors, text)
25 });
16} 26}
17 27
18#[test] 28#[test]
@@ -32,18 +42,13 @@ fn parser_tests() {
32 dir_tests(&test_data_dir(), &["parser/inline/ok", "parser/ok"], |text, path| { 42 dir_tests(&test_data_dir(), &["parser/inline/ok", "parser/ok"], |text, path| {
33 let parse = SourceFile::parse(text); 43 let parse = SourceFile::parse(text);
34 let errors = parse.errors(); 44 let errors = parse.errors();
35 assert_eq!( 45 assert_errors_are_absent(&errors, path);
36 errors,
37 &[] as &[crate::SyntaxError],
38 "There should be no errors in the file {:?}",
39 path.display(),
40 );
41 parse.debug_dump() 46 parse.debug_dump()
42 }); 47 });
43 dir_tests(&test_data_dir(), &["parser/err", "parser/inline/err"], |text, path| { 48 dir_tests(&test_data_dir(), &["parser/err", "parser/inline/err"], |text, path| {
44 let parse = SourceFile::parse(text); 49 let parse = SourceFile::parse(text);
45 let errors = parse.errors(); 50 let errors = parse.errors();
46 assert!(!errors.is_empty(), "There should be errors in the file {:?}", path.display()); 51 assert_errors_are_present(&errors, path);
47 parse.debug_dump() 52 parse.debug_dump()
48 }); 53 });
49} 54}
@@ -75,7 +80,7 @@ fn self_hosting_parsing() {
75 .into_iter() 80 .into_iter()
76 .filter_entry(|entry| { 81 .filter_entry(|entry| {
77 !entry.path().components().any(|component| { 82 !entry.path().components().any(|component| {
78 // Get all files which are not in the crates/ra_syntax/tests/data folder 83 // Get all files which are not in the crates/ra_syntax/test_data folder
79 component == Component::Normal(OsStr::new("test_data")) 84 component == Component::Normal(OsStr::new("test_data"))
80 }) 85 })
81 }) 86 })
@@ -101,15 +106,47 @@ fn test_data_dir() -> PathBuf {
101 project_dir().join("crates/ra_syntax/test_data") 106 project_dir().join("crates/ra_syntax/test_data")
102} 107}
103 108
104fn dump_tokens(tokens: &[crate::Token], text: &str) -> String { 109fn assert_errors_are_present(errors: &[SyntaxError], path: &Path) {
110 assert!(!errors.is_empty(), "There should be errors in the file {:?}", path.display());
111}
112fn assert_errors_are_absent(errors: &[SyntaxError], path: &Path) {
113 assert_eq!(
114 errors,
115 &[] as &[SyntaxError],
116 "There should be no errors in the file {:?}",
117 path.display(),
118 );
119}
120
121fn dump_tokens_and_errors(tokens: &[Token], errors: &[SyntaxError], text: &str) -> String {
105 let mut acc = String::new(); 122 let mut acc = String::new();
106 let mut offset = 0; 123 let mut offset = 0;
107 for token in tokens { 124 for token in tokens {
108 let len: u32 = token.len.into(); 125 let token_len = token.len.to_usize();
109 let len = len as usize; 126 let token_text = &text[offset..offset + token_len];
110 let token_text = &text[offset..offset + len]; 127 offset += token_len;
111 offset += len; 128 writeln!(acc, "{:?} {} {:?}", token.kind, token_len, token_text).unwrap();
112 write!(acc, "{:?} {} {:?}\n", token.kind, token.len, token_text).unwrap() 129 }
130 for err in errors {
131 let err_range = location_to_range(err.location());
132 writeln!(
133 acc,
134 "> error{:?} token({:?}) msg({})",
135 err.location(),
136 &text[err_range],
137 err.kind()
138 )
139 .unwrap();
140 }
141 return acc;
142
143 // FIXME: copy-pasted this from `ra_ide/src/diagnostics.rs`
144 // `Location` will be refactored soon in new PR, see todos here:
145 // https://github.com/rust-analyzer/rust-analyzer/issues/223
146 fn location_to_range(location: Location) -> TextRange {
147 match location {
148 Location::Offset(offset) => TextRange::offset_len(offset, 1.into()),
149 Location::Range(range) => range,
150 }
113 } 151 }
114 acc
115} 152}
diff --git a/crates/ra_syntax/src/validation.rs b/crates/ra_syntax/src/validation.rs
index 445e3b3e4..8a5f0e4b7 100644
--- a/crates/ra_syntax/src/validation.rs
+++ b/crates/ra_syntax/src/validation.rs
@@ -94,6 +94,12 @@ impl From<rustc_lexer::unescape::EscapeError> for SyntaxErrorKind {
94} 94}
95 95
96pub(crate) fn validate(root: &SyntaxNode) -> Vec<SyntaxError> { 96pub(crate) fn validate(root: &SyntaxNode) -> Vec<SyntaxError> {
97 // FIXME:
98 // * Add validation of character literal containing only a single char
99 // * Add validation of `crate` keyword not appearing in the middle of the symbol path
100 // * Add validation of doc comments are being attached to nodes
101 // * Remove validation of unterminated literals (it is already implemented in `tokenize()`)
102
97 let mut errors = Vec::new(); 103 let mut errors = Vec::new();
98 for node in root.descendants() { 104 for node in root.descendants() {
99 match_ast! { 105 match_ast! {
diff --git a/crates/ra_syntax/test_data/lexer/0010_comments.rs b/crates/ra_syntax/test_data/lexer/0010_comments.rs
deleted file mode 100644
index 71bdd1f9c..000000000
--- a/crates/ra_syntax/test_data/lexer/0010_comments.rs
+++ /dev/null
@@ -1,3 +0,0 @@
1#!/usr/bin/env bash
2// hello
3//! World
diff --git a/crates/ra_syntax/test_data/lexer/0010_comments.txt b/crates/ra_syntax/test_data/lexer/0010_comments.txt
deleted file mode 100644
index 3c997de3f..000000000
--- a/crates/ra_syntax/test_data/lexer/0010_comments.txt
+++ /dev/null
@@ -1,6 +0,0 @@
1SHEBANG 19 "#!/usr/bin/env bash"
2WHITESPACE 1 "\n"
3COMMENT 8 "// hello"
4WHITESPACE 1 "\n"
5COMMENT 9 "//! World"
6WHITESPACE 1 "\n"
diff --git a/crates/ra_syntax/test_data/lexer/0014_unclosed_char.rs b/crates/ra_syntax/test_data/lexer/0014_unclosed_char.rs
deleted file mode 100644
index 9c0007077..000000000
--- a/crates/ra_syntax/test_data/lexer/0014_unclosed_char.rs
+++ /dev/null
@@ -1 +0,0 @@
1'1 \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/0014_unclosed_char.txt b/crates/ra_syntax/test_data/lexer/0014_unclosed_char.txt
deleted file mode 100644
index 737a300ee..000000000
--- a/crates/ra_syntax/test_data/lexer/0014_unclosed_char.txt
+++ /dev/null
@@ -1 +0,0 @@
1LIFETIME 2 "\'1"
diff --git a/crates/ra_syntax/test_data/lexer/0015_unclosed_string.rs b/crates/ra_syntax/test_data/lexer/0015_unclosed_string.rs
deleted file mode 100644
index d771a26d4..000000000
--- a/crates/ra_syntax/test_data/lexer/0015_unclosed_string.rs
+++ /dev/null
@@ -1 +0,0 @@
1"hello
diff --git a/crates/ra_syntax/test_data/lexer/0015_unclosed_string.txt b/crates/ra_syntax/test_data/lexer/0015_unclosed_string.txt
deleted file mode 100644
index 728c40b66..000000000
--- a/crates/ra_syntax/test_data/lexer/0015_unclosed_string.txt
+++ /dev/null
@@ -1 +0,0 @@
1STRING 7 "\"hello\n"
diff --git a/crates/ra_syntax/test_data/lexer/err/0001_unclosed_char_at_eof.rs b/crates/ra_syntax/test_data/lexer/err/0001_unclosed_char_at_eof.rs
new file mode 100644
index 000000000..ad2823b48
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0001_unclosed_char_at_eof.rs
@@ -0,0 +1 @@
' \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0001_unclosed_char_at_eof.txt b/crates/ra_syntax/test_data/lexer/err/0001_unclosed_char_at_eof.txt
new file mode 100644
index 000000000..f24e1fd32
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0001_unclosed_char_at_eof.txt
@@ -0,0 +1,2 @@
1CHAR 1 "\'"
2> error[0; 1) token("\'") msg(Missing trailing `'` symbol to terminate the character literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0002_unclosed_char_with_ferris.rs b/crates/ra_syntax/test_data/lexer/err/0002_unclosed_char_with_ferris.rs
new file mode 100644
index 000000000..e264a4152
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0002_unclosed_char_with_ferris.rs
@@ -0,0 +1 @@
'🦀 \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0002_unclosed_char_with_ferris.txt b/crates/ra_syntax/test_data/lexer/err/0002_unclosed_char_with_ferris.txt
new file mode 100644
index 000000000..bd08cfc44
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0002_unclosed_char_with_ferris.txt
@@ -0,0 +1,2 @@
1CHAR 5 "\'🦀"
2> error[0; 5) token("\'🦀") msg(Missing trailing `'` symbol to terminate the character literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0003_unclosed_char_with_ascii_escape.rs b/crates/ra_syntax/test_data/lexer/err/0003_unclosed_char_with_ascii_escape.rs
new file mode 100644
index 000000000..cf74b4dad
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0003_unclosed_char_with_ascii_escape.rs
@@ -0,0 +1 @@
'\x7f \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0003_unclosed_char_with_ascii_escape.txt b/crates/ra_syntax/test_data/lexer/err/0003_unclosed_char_with_ascii_escape.txt
new file mode 100644
index 000000000..0ee22912d
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0003_unclosed_char_with_ascii_escape.txt
@@ -0,0 +1,2 @@
1CHAR 5 "\'\\x7f"
2> error[0; 5) token("\'\\x7f") msg(Missing trailing `'` symbol to terminate the character literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0004_unclosed_char_with_unicode_escape.rs b/crates/ra_syntax/test_data/lexer/err/0004_unclosed_char_with_unicode_escape.rs
new file mode 100644
index 000000000..50be91f68
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0004_unclosed_char_with_unicode_escape.rs
@@ -0,0 +1 @@
'\u{20AA} \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0004_unclosed_char_with_unicode_escape.txt b/crates/ra_syntax/test_data/lexer/err/0004_unclosed_char_with_unicode_escape.txt
new file mode 100644
index 000000000..96fac42ce
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0004_unclosed_char_with_unicode_escape.txt
@@ -0,0 +1,2 @@
1CHAR 9 "\'\\u{20AA}"
2> error[0; 9) token("\'\\u{20AA}") msg(Missing trailing `'` symbol to terminate the character literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0005_unclosed_char_with_space.rs b/crates/ra_syntax/test_data/lexer/err/0005_unclosed_char_with_space.rs
new file mode 100644
index 000000000..309ecfe47
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0005_unclosed_char_with_space.rs
@@ -0,0 +1 @@
' \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0005_unclosed_char_with_space.txt b/crates/ra_syntax/test_data/lexer/err/0005_unclosed_char_with_space.txt
new file mode 100644
index 000000000..2059f3f81
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0005_unclosed_char_with_space.txt
@@ -0,0 +1,2 @@
1CHAR 2 "\' "
2> error[0; 2) token("\' ") msg(Missing trailing `'` symbol to terminate the character literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0006_unclosed_char_with_slash.rs b/crates/ra_syntax/test_data/lexer/err/0006_unclosed_char_with_slash.rs
new file mode 100644
index 000000000..6ba258b10
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0006_unclosed_char_with_slash.rs
@@ -0,0 +1 @@
'\ \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0006_unclosed_char_with_slash.txt b/crates/ra_syntax/test_data/lexer/err/0006_unclosed_char_with_slash.txt
new file mode 100644
index 000000000..7dd376e59
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0006_unclosed_char_with_slash.txt
@@ -0,0 +1,2 @@
1CHAR 2 "\'\\"
2> error[0; 2) token("\'\\") msg(Missing trailing `'` symbol to terminate the character literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0007_unclosed_char_with_slash_n.rs b/crates/ra_syntax/test_data/lexer/err/0007_unclosed_char_with_slash_n.rs
new file mode 100644
index 000000000..78bef7e3e
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0007_unclosed_char_with_slash_n.rs
@@ -0,0 +1 @@
'\n \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0007_unclosed_char_with_slash_n.txt b/crates/ra_syntax/test_data/lexer/err/0007_unclosed_char_with_slash_n.txt
new file mode 100644
index 000000000..ef7a0a147
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0007_unclosed_char_with_slash_n.txt
@@ -0,0 +1,2 @@
1CHAR 3 "\'\\n"
2> error[0; 3) token("\'\\n") msg(Missing trailing `'` symbol to terminate the character literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0008_unclosed_char_with_slash_single_quote.rs b/crates/ra_syntax/test_data/lexer/err/0008_unclosed_char_with_slash_single_quote.rs
new file mode 100644
index 000000000..a0e722065
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0008_unclosed_char_with_slash_single_quote.rs
@@ -0,0 +1 @@
'\' \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0008_unclosed_char_with_slash_single_quote.txt b/crates/ra_syntax/test_data/lexer/err/0008_unclosed_char_with_slash_single_quote.txt
new file mode 100644
index 000000000..13fc5ea9a
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0008_unclosed_char_with_slash_single_quote.txt
@@ -0,0 +1,2 @@
1CHAR 3 "\'\\\'"
2> error[0; 3) token("\'\\\'") msg(Missing trailing `'` symbol to terminate the character literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0009_unclosed_byte_at_eof.rs b/crates/ra_syntax/test_data/lexer/err/0009_unclosed_byte_at_eof.rs
new file mode 100644
index 000000000..795dc7e25
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0009_unclosed_byte_at_eof.rs
@@ -0,0 +1 @@
b' \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0009_unclosed_byte_at_eof.txt b/crates/ra_syntax/test_data/lexer/err/0009_unclosed_byte_at_eof.txt
new file mode 100644
index 000000000..269d68c74
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0009_unclosed_byte_at_eof.txt
@@ -0,0 +1,2 @@
1BYTE 2 "b\'"
2> error[0; 2) token("b\'") msg(Missing trailing `'` symbol to terminate the byte literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0010_unclosed_byte_with_ferris.rs b/crates/ra_syntax/test_data/lexer/err/0010_unclosed_byte_with_ferris.rs
new file mode 100644
index 000000000..c9230dc24
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0010_unclosed_byte_with_ferris.rs
@@ -0,0 +1 @@
b'🦀 \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0010_unclosed_byte_with_ferris.txt b/crates/ra_syntax/test_data/lexer/err/0010_unclosed_byte_with_ferris.txt
new file mode 100644
index 000000000..91a76e479
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0010_unclosed_byte_with_ferris.txt
@@ -0,0 +1,2 @@
1BYTE 6 "b\'🦀"
2> error[0; 6) token("b\'🦀") msg(Missing trailing `'` symbol to terminate the byte literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0011_unclosed_byte_with_ascii_escape.rs b/crates/ra_syntax/test_data/lexer/err/0011_unclosed_byte_with_ascii_escape.rs
new file mode 100644
index 000000000..d146a8090
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0011_unclosed_byte_with_ascii_escape.rs
@@ -0,0 +1 @@
b'\x7f \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0011_unclosed_byte_with_ascii_escape.txt b/crates/ra_syntax/test_data/lexer/err/0011_unclosed_byte_with_ascii_escape.txt
new file mode 100644
index 000000000..b8c804a18
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0011_unclosed_byte_with_ascii_escape.txt
@@ -0,0 +1,2 @@
1BYTE 6 "b\'\\x7f"
2> error[0; 6) token("b\'\\x7f") msg(Missing trailing `'` symbol to terminate the byte literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0012_unclosed_byte_with_unicode_escape.rs b/crates/ra_syntax/test_data/lexer/err/0012_unclosed_byte_with_unicode_escape.rs
new file mode 100644
index 000000000..a3dec7c25
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0012_unclosed_byte_with_unicode_escape.rs
@@ -0,0 +1 @@
b'\u{20AA} \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0012_unclosed_byte_with_unicode_escape.txt b/crates/ra_syntax/test_data/lexer/err/0012_unclosed_byte_with_unicode_escape.txt
new file mode 100644
index 000000000..dfca22a59
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0012_unclosed_byte_with_unicode_escape.txt
@@ -0,0 +1,2 @@
1BYTE 10 "b\'\\u{20AA}"
2> error[0; 10) token("b\'\\u{20AA}") msg(Missing trailing `'` symbol to terminate the byte literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0013_unclosed_byte_with_space.rs b/crates/ra_syntax/test_data/lexer/err/0013_unclosed_byte_with_space.rs
new file mode 100644
index 000000000..93b7f9c87
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0013_unclosed_byte_with_space.rs
@@ -0,0 +1 @@
b' \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0013_unclosed_byte_with_space.txt b/crates/ra_syntax/test_data/lexer/err/0013_unclosed_byte_with_space.txt
new file mode 100644
index 000000000..51a1cceab
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0013_unclosed_byte_with_space.txt
@@ -0,0 +1,2 @@
1BYTE 3 "b\' "
2> error[0; 3) token("b\' ") msg(Missing trailing `'` symbol to terminate the byte literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0014_unclosed_byte_with_slash.rs b/crates/ra_syntax/test_data/lexer/err/0014_unclosed_byte_with_slash.rs
new file mode 100644
index 000000000..abffa5037
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0014_unclosed_byte_with_slash.rs
@@ -0,0 +1 @@
b'\ \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0014_unclosed_byte_with_slash.txt b/crates/ra_syntax/test_data/lexer/err/0014_unclosed_byte_with_slash.txt
new file mode 100644
index 000000000..24e835c27
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0014_unclosed_byte_with_slash.txt
@@ -0,0 +1,2 @@
1BYTE 3 "b\'\\"
2> error[0; 3) token("b\'\\") msg(Missing trailing `'` symbol to terminate the byte literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0015_unclosed_byte_with_slash_n.rs b/crates/ra_syntax/test_data/lexer/err/0015_unclosed_byte_with_slash_n.rs
new file mode 100644
index 000000000..4f46836a9
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0015_unclosed_byte_with_slash_n.rs
@@ -0,0 +1 @@
b'\n \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0015_unclosed_byte_with_slash_n.txt b/crates/ra_syntax/test_data/lexer/err/0015_unclosed_byte_with_slash_n.txt
new file mode 100644
index 000000000..f1e39a41b
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0015_unclosed_byte_with_slash_n.txt
@@ -0,0 +1,2 @@
1BYTE 4 "b\'\\n"
2> error[0; 4) token("b\'\\n") msg(Missing trailing `'` symbol to terminate the byte literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0016_unclosed_byte_with_slash_single_quote.rs b/crates/ra_syntax/test_data/lexer/err/0016_unclosed_byte_with_slash_single_quote.rs
new file mode 100644
index 000000000..645b641ee
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0016_unclosed_byte_with_slash_single_quote.rs
@@ -0,0 +1 @@
b'\' \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0016_unclosed_byte_with_slash_single_quote.txt b/crates/ra_syntax/test_data/lexer/err/0016_unclosed_byte_with_slash_single_quote.txt
new file mode 100644
index 000000000..f8ffe815d
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0016_unclosed_byte_with_slash_single_quote.txt
@@ -0,0 +1,2 @@
1BYTE 4 "b\'\\\'"
2> error[0; 4) token("b\'\\\'") msg(Missing trailing `'` symbol to terminate the byte literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0017_unclosed_string_at_eof.rs b/crates/ra_syntax/test_data/lexer/err/0017_unclosed_string_at_eof.rs
new file mode 100644
index 000000000..9d68933c4
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0017_unclosed_string_at_eof.rs
@@ -0,0 +1 @@
" \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0017_unclosed_string_at_eof.txt b/crates/ra_syntax/test_data/lexer/err/0017_unclosed_string_at_eof.txt
new file mode 100644
index 000000000..823daaf6f
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0017_unclosed_string_at_eof.txt
@@ -0,0 +1,2 @@
1STRING 1 "\""
2> error[0; 1) token("\"") msg(Missing trailing `"` symbol to terminate the string literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0018_unclosed_string_with_ferris.rs b/crates/ra_syntax/test_data/lexer/err/0018_unclosed_string_with_ferris.rs
new file mode 100644
index 000000000..d439b8d2a
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0018_unclosed_string_with_ferris.rs
@@ -0,0 +1 @@
"🦀 \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0018_unclosed_string_with_ferris.txt b/crates/ra_syntax/test_data/lexer/err/0018_unclosed_string_with_ferris.txt
new file mode 100644
index 000000000..164580eb3
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0018_unclosed_string_with_ferris.txt
@@ -0,0 +1,2 @@
1STRING 5 "\"🦀"
2> error[0; 5) token("\"🦀") msg(Missing trailing `"` symbol to terminate the string literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0019_unclosed_string_with_ascii_escape.rs b/crates/ra_syntax/test_data/lexer/err/0019_unclosed_string_with_ascii_escape.rs
new file mode 100644
index 000000000..56186a344
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0019_unclosed_string_with_ascii_escape.rs
@@ -0,0 +1 @@
"\x7f \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0019_unclosed_string_with_ascii_escape.txt b/crates/ra_syntax/test_data/lexer/err/0019_unclosed_string_with_ascii_escape.txt
new file mode 100644
index 000000000..4453827c3
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0019_unclosed_string_with_ascii_escape.txt
@@ -0,0 +1,2 @@
1STRING 5 "\"\\x7f"
2> error[0; 5) token("\"\\x7f") msg(Missing trailing `"` symbol to terminate the string literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0020_unclosed_string_with_unicode_escape.rs b/crates/ra_syntax/test_data/lexer/err/0020_unclosed_string_with_unicode_escape.rs
new file mode 100644
index 000000000..ed24095c3
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0020_unclosed_string_with_unicode_escape.rs
@@ -0,0 +1 @@
"\u{20AA} \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0020_unclosed_string_with_unicode_escape.txt b/crates/ra_syntax/test_data/lexer/err/0020_unclosed_string_with_unicode_escape.txt
new file mode 100644
index 000000000..aa614f304
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0020_unclosed_string_with_unicode_escape.txt
@@ -0,0 +1,2 @@
1STRING 9 "\"\\u{20AA}"
2> error[0; 9) token("\"\\u{20AA}") msg(Missing trailing `"` symbol to terminate the string literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0021_unclosed_string_with_space.rs b/crates/ra_syntax/test_data/lexer/err/0021_unclosed_string_with_space.rs
new file mode 100644
index 000000000..72cdc841f
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0021_unclosed_string_with_space.rs
@@ -0,0 +1 @@
" \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0021_unclosed_string_with_space.txt b/crates/ra_syntax/test_data/lexer/err/0021_unclosed_string_with_space.txt
new file mode 100644
index 000000000..b7db1236f
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0021_unclosed_string_with_space.txt
@@ -0,0 +1,2 @@
1STRING 2 "\" "
2> error[0; 2) token("\" ") msg(Missing trailing `"` symbol to terminate the string literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0022_unclosed_string_with_slash.rs b/crates/ra_syntax/test_data/lexer/err/0022_unclosed_string_with_slash.rs
new file mode 100644
index 000000000..00a258400
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0022_unclosed_string_with_slash.rs
@@ -0,0 +1 @@
"\ \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0022_unclosed_string_with_slash.txt b/crates/ra_syntax/test_data/lexer/err/0022_unclosed_string_with_slash.txt
new file mode 100644
index 000000000..9d3df3799
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0022_unclosed_string_with_slash.txt
@@ -0,0 +1,2 @@
1STRING 2 "\"\\"
2> error[0; 2) token("\"\\") msg(Missing trailing `"` symbol to terminate the string literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0023_unclosed_string_with_slash_n.rs b/crates/ra_syntax/test_data/lexer/err/0023_unclosed_string_with_slash_n.rs
new file mode 100644
index 000000000..a0c29b8cf
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0023_unclosed_string_with_slash_n.rs
@@ -0,0 +1 @@
"\n \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0023_unclosed_string_with_slash_n.txt b/crates/ra_syntax/test_data/lexer/err/0023_unclosed_string_with_slash_n.txt
new file mode 100644
index 000000000..e3eb672b6
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0023_unclosed_string_with_slash_n.txt
@@ -0,0 +1,2 @@
1STRING 3 "\"\\n"
2> error[0; 3) token("\"\\n") msg(Missing trailing `"` symbol to terminate the string literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0024_unclosed_string_with_slash_double_quote.rs b/crates/ra_syntax/test_data/lexer/err/0024_unclosed_string_with_slash_double_quote.rs
new file mode 100644
index 000000000..403c2d6dd
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0024_unclosed_string_with_slash_double_quote.rs
@@ -0,0 +1 @@
"\" \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0024_unclosed_string_with_slash_double_quote.txt b/crates/ra_syntax/test_data/lexer/err/0024_unclosed_string_with_slash_double_quote.txt
new file mode 100644
index 000000000..041d7fb6e
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0024_unclosed_string_with_slash_double_quote.txt
@@ -0,0 +1,2 @@
1STRING 3 "\"\\\""
2> error[0; 3) token("\"\\\"") msg(Missing trailing `"` symbol to terminate the string literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0025_unclosed_byte_string_at_eof.rs b/crates/ra_syntax/test_data/lexer/err/0025_unclosed_byte_string_at_eof.rs
new file mode 100644
index 000000000..36f4f4321
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0025_unclosed_byte_string_at_eof.rs
@@ -0,0 +1 @@
b" \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0025_unclosed_byte_string_at_eof.txt b/crates/ra_syntax/test_data/lexer/err/0025_unclosed_byte_string_at_eof.txt
new file mode 100644
index 000000000..be7970a83
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0025_unclosed_byte_string_at_eof.txt
@@ -0,0 +1,2 @@
1BYTE_STRING 2 "b\""
2> error[0; 2) token("b\"") msg(Missing trailing `"` symbol to terminate the byte string literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0026_unclosed_byte_string_with_ferris.rs b/crates/ra_syntax/test_data/lexer/err/0026_unclosed_byte_string_with_ferris.rs
new file mode 100644
index 000000000..3c23a0372
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0026_unclosed_byte_string_with_ferris.rs
@@ -0,0 +1 @@
b"🦀 \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0026_unclosed_byte_string_with_ferris.txt b/crates/ra_syntax/test_data/lexer/err/0026_unclosed_byte_string_with_ferris.txt
new file mode 100644
index 000000000..bf9aab132
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0026_unclosed_byte_string_with_ferris.txt
@@ -0,0 +1,2 @@
1BYTE_STRING 6 "b\"🦀"
2> error[0; 6) token("b\"🦀") msg(Missing trailing `"` symbol to terminate the byte string literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0027_unclosed_byte_string_with_ascii_escape.rs b/crates/ra_syntax/test_data/lexer/err/0027_unclosed_byte_string_with_ascii_escape.rs
new file mode 100644
index 000000000..836c112c1
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0027_unclosed_byte_string_with_ascii_escape.rs
@@ -0,0 +1 @@
b"\x7f \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0027_unclosed_byte_string_with_ascii_escape.txt b/crates/ra_syntax/test_data/lexer/err/0027_unclosed_byte_string_with_ascii_escape.txt
new file mode 100644
index 000000000..76e16d7d3
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0027_unclosed_byte_string_with_ascii_escape.txt
@@ -0,0 +1,2 @@
1BYTE_STRING 6 "b\"\\x7f"
2> error[0; 6) token("b\"\\x7f") msg(Missing trailing `"` symbol to terminate the byte string literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0028_unclosed_byte_string_with_unicode_escape.rs b/crates/ra_syntax/test_data/lexer/err/0028_unclosed_byte_string_with_unicode_escape.rs
new file mode 100644
index 000000000..1c6df1d00
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0028_unclosed_byte_string_with_unicode_escape.rs
@@ -0,0 +1 @@
b"\u{20AA} \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0028_unclosed_byte_string_with_unicode_escape.txt b/crates/ra_syntax/test_data/lexer/err/0028_unclosed_byte_string_with_unicode_escape.txt
new file mode 100644
index 000000000..09adffa16
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0028_unclosed_byte_string_with_unicode_escape.txt
@@ -0,0 +1,2 @@
1BYTE_STRING 10 "b\"\\u{20AA}"
2> error[0; 10) token("b\"\\u{20AA}") msg(Missing trailing `"` symbol to terminate the byte string literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0029_unclosed_byte_string_with_space.rs b/crates/ra_syntax/test_data/lexer/err/0029_unclosed_byte_string_with_space.rs
new file mode 100644
index 000000000..d6898541e
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0029_unclosed_byte_string_with_space.rs
@@ -0,0 +1 @@
b" \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0029_unclosed_byte_string_with_space.txt b/crates/ra_syntax/test_data/lexer/err/0029_unclosed_byte_string_with_space.txt
new file mode 100644
index 000000000..fcb7253c8
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0029_unclosed_byte_string_with_space.txt
@@ -0,0 +1,2 @@
1BYTE_STRING 3 "b\" "
2> error[0; 3) token("b\" ") msg(Missing trailing `"` symbol to terminate the byte string literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0030_unclosed_byte_string_with_slash.rs b/crates/ra_syntax/test_data/lexer/err/0030_unclosed_byte_string_with_slash.rs
new file mode 100644
index 000000000..cce661538
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0030_unclosed_byte_string_with_slash.rs
@@ -0,0 +1 @@
b"\ \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0030_unclosed_byte_string_with_slash.txt b/crates/ra_syntax/test_data/lexer/err/0030_unclosed_byte_string_with_slash.txt
new file mode 100644
index 000000000..0a1b3e269
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0030_unclosed_byte_string_with_slash.txt
@@ -0,0 +1,2 @@
1BYTE_STRING 3 "b\"\\"
2> error[0; 3) token("b\"\\") msg(Missing trailing `"` symbol to terminate the byte string literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0031_unclosed_byte_string_with_slash_n.rs b/crates/ra_syntax/test_data/lexer/err/0031_unclosed_byte_string_with_slash_n.rs
new file mode 100644
index 000000000..5e680aabb
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0031_unclosed_byte_string_with_slash_n.rs
@@ -0,0 +1 @@
b"\n \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0031_unclosed_byte_string_with_slash_n.txt b/crates/ra_syntax/test_data/lexer/err/0031_unclosed_byte_string_with_slash_n.txt
new file mode 100644
index 000000000..1fb89d2b6
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0031_unclosed_byte_string_with_slash_n.txt
@@ -0,0 +1,2 @@
1BYTE_STRING 4 "b\"\\n"
2> error[0; 4) token("b\"\\n") msg(Missing trailing `"` symbol to terminate the byte string literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0032_unclosed_byte_string_with_slash_double_quote.rs b/crates/ra_syntax/test_data/lexer/err/0032_unclosed_byte_string_with_slash_double_quote.rs
new file mode 100644
index 000000000..f2ff58ba9
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0032_unclosed_byte_string_with_slash_double_quote.rs
@@ -0,0 +1 @@
b"\" \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0032_unclosed_byte_string_with_slash_double_quote.txt b/crates/ra_syntax/test_data/lexer/err/0032_unclosed_byte_string_with_slash_double_quote.txt
new file mode 100644
index 000000000..718d36992
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0032_unclosed_byte_string_with_slash_double_quote.txt
@@ -0,0 +1,2 @@
1BYTE_STRING 4 "b\"\\\""
2> error[0; 4) token("b\"\\\"") msg(Missing trailing `"` symbol to terminate the byte string literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0033_unclosed_raw_string_at_eof.rs b/crates/ra_syntax/test_data/lexer/err/0033_unclosed_raw_string_at_eof.rs
new file mode 100644
index 000000000..557c59b62
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0033_unclosed_raw_string_at_eof.rs
@@ -0,0 +1 @@
r##" \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0033_unclosed_raw_string_at_eof.txt b/crates/ra_syntax/test_data/lexer/err/0033_unclosed_raw_string_at_eof.txt
new file mode 100644
index 000000000..93348f548
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0033_unclosed_raw_string_at_eof.txt
@@ -0,0 +1,2 @@
1RAW_STRING 4 "r##\""
2> error[0; 4) token("r##\"") msg(Missing trailing `"` with `#` symbols to terminate the raw string literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0034_unclosed_raw_string_with_ferris.rs b/crates/ra_syntax/test_data/lexer/err/0034_unclosed_raw_string_with_ferris.rs
new file mode 100644
index 000000000..bd046e4bb
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0034_unclosed_raw_string_with_ferris.rs
@@ -0,0 +1 @@
r##"🦀 \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0034_unclosed_raw_string_with_ferris.txt b/crates/ra_syntax/test_data/lexer/err/0034_unclosed_raw_string_with_ferris.txt
new file mode 100644
index 000000000..42c70dfe8
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0034_unclosed_raw_string_with_ferris.txt
@@ -0,0 +1,2 @@
1RAW_STRING 8 "r##\"🦀"
2> error[0; 8) token("r##\"🦀") msg(Missing trailing `"` with `#` symbols to terminate the raw string literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0035_unclosed_raw_string_with_ascii_escape.rs b/crates/ra_syntax/test_data/lexer/err/0035_unclosed_raw_string_with_ascii_escape.rs
new file mode 100644
index 000000000..5bec883dc
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0035_unclosed_raw_string_with_ascii_escape.rs
@@ -0,0 +1 @@
r##"\x7f \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0035_unclosed_raw_string_with_ascii_escape.txt b/crates/ra_syntax/test_data/lexer/err/0035_unclosed_raw_string_with_ascii_escape.txt
new file mode 100644
index 000000000..2bdeea0ff
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0035_unclosed_raw_string_with_ascii_escape.txt
@@ -0,0 +1,2 @@
1RAW_STRING 8 "r##\"\\x7f"
2> error[0; 8) token("r##\"\\x7f") msg(Missing trailing `"` with `#` symbols to terminate the raw string literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0036_unclosed_raw_string_with_unicode_escape.rs b/crates/ra_syntax/test_data/lexer/err/0036_unclosed_raw_string_with_unicode_escape.rs
new file mode 100644
index 000000000..bf05c3913
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0036_unclosed_raw_string_with_unicode_escape.rs
@@ -0,0 +1 @@
r##"\u{20AA} \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0036_unclosed_raw_string_with_unicode_escape.txt b/crates/ra_syntax/test_data/lexer/err/0036_unclosed_raw_string_with_unicode_escape.txt
new file mode 100644
index 000000000..667d4d79f
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0036_unclosed_raw_string_with_unicode_escape.txt
@@ -0,0 +1,2 @@
1RAW_STRING 12 "r##\"\\u{20AA}"
2> error[0; 12) token("r##\"\\u{20AA}") msg(Missing trailing `"` with `#` symbols to terminate the raw string literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0037_unclosed_raw_string_with_space.rs b/crates/ra_syntax/test_data/lexer/err/0037_unclosed_raw_string_with_space.rs
new file mode 100644
index 000000000..f104bae4f
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0037_unclosed_raw_string_with_space.rs
@@ -0,0 +1 @@
r##" \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0037_unclosed_raw_string_with_space.txt b/crates/ra_syntax/test_data/lexer/err/0037_unclosed_raw_string_with_space.txt
new file mode 100644
index 000000000..dd9597a1a
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0037_unclosed_raw_string_with_space.txt
@@ -0,0 +1,2 @@
1RAW_STRING 5 "r##\" "
2> error[0; 5) token("r##\" ") msg(Missing trailing `"` with `#` symbols to terminate the raw string literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0038_unclosed_raw_string_with_slash.rs b/crates/ra_syntax/test_data/lexer/err/0038_unclosed_raw_string_with_slash.rs
new file mode 100644
index 000000000..9242077b8
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0038_unclosed_raw_string_with_slash.rs
@@ -0,0 +1 @@
r##"\ \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0038_unclosed_raw_string_with_slash.txt b/crates/ra_syntax/test_data/lexer/err/0038_unclosed_raw_string_with_slash.txt
new file mode 100644
index 000000000..6ac6e3d62
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0038_unclosed_raw_string_with_slash.txt
@@ -0,0 +1,2 @@
1RAW_STRING 5 "r##\"\\"
2> error[0; 5) token("r##\"\\") msg(Missing trailing `"` with `#` symbols to terminate the raw string literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0039_unclosed_raw_string_with_slash_n.rs b/crates/ra_syntax/test_data/lexer/err/0039_unclosed_raw_string_with_slash_n.rs
new file mode 100644
index 000000000..db1c16f2b
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0039_unclosed_raw_string_with_slash_n.rs
@@ -0,0 +1 @@
r##"\n \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0039_unclosed_raw_string_with_slash_n.txt b/crates/ra_syntax/test_data/lexer/err/0039_unclosed_raw_string_with_slash_n.txt
new file mode 100644
index 000000000..9d35443f5
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0039_unclosed_raw_string_with_slash_n.txt
@@ -0,0 +1,2 @@
1RAW_STRING 6 "r##\"\\n"
2> error[0; 6) token("r##\"\\n") msg(Missing trailing `"` with `#` symbols to terminate the raw string literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0040_unclosed_raw_byte_string_at_eof.rs b/crates/ra_syntax/test_data/lexer/err/0040_unclosed_raw_byte_string_at_eof.rs
new file mode 100644
index 000000000..ae5bae622
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0040_unclosed_raw_byte_string_at_eof.rs
@@ -0,0 +1 @@
br##" \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0040_unclosed_raw_byte_string_at_eof.txt b/crates/ra_syntax/test_data/lexer/err/0040_unclosed_raw_byte_string_at_eof.txt
new file mode 100644
index 000000000..81fa39ea5
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0040_unclosed_raw_byte_string_at_eof.txt
@@ -0,0 +1,2 @@
1RAW_BYTE_STRING 5 "br##\""
2> error[0; 5) token("br##\"") msg(Missing trailing `"` with `#` symbols to terminate the raw byte string literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0041_unclosed_raw_byte_string_with_ferris.rs b/crates/ra_syntax/test_data/lexer/err/0041_unclosed_raw_byte_string_with_ferris.rs
new file mode 100644
index 000000000..9ef01207a
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0041_unclosed_raw_byte_string_with_ferris.rs
@@ -0,0 +1 @@
br##"🦀 \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0041_unclosed_raw_byte_string_with_ferris.txt b/crates/ra_syntax/test_data/lexer/err/0041_unclosed_raw_byte_string_with_ferris.txt
new file mode 100644
index 000000000..c2503a4d0
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0041_unclosed_raw_byte_string_with_ferris.txt
@@ -0,0 +1,2 @@
1RAW_BYTE_STRING 9 "br##\"🦀"
2> error[0; 9) token("br##\"🦀") msg(Missing trailing `"` with `#` symbols to terminate the raw byte string literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0042_unclosed_raw_byte_string_with_ascii_escape.rs b/crates/ra_syntax/test_data/lexer/err/0042_unclosed_raw_byte_string_with_ascii_escape.rs
new file mode 100644
index 000000000..d50270afe
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0042_unclosed_raw_byte_string_with_ascii_escape.rs
@@ -0,0 +1 @@
br##"\x7f \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0042_unclosed_raw_byte_string_with_ascii_escape.txt b/crates/ra_syntax/test_data/lexer/err/0042_unclosed_raw_byte_string_with_ascii_escape.txt
new file mode 100644
index 000000000..3bd3d8152
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0042_unclosed_raw_byte_string_with_ascii_escape.txt
@@ -0,0 +1,2 @@
1RAW_BYTE_STRING 9 "br##\"\\x7f"
2> error[0; 9) token("br##\"\\x7f") msg(Missing trailing `"` with `#` symbols to terminate the raw byte string literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0043_unclosed_raw_byte_string_with_unicode_escape.rs b/crates/ra_syntax/test_data/lexer/err/0043_unclosed_raw_byte_string_with_unicode_escape.rs
new file mode 100644
index 000000000..90e299a1a
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0043_unclosed_raw_byte_string_with_unicode_escape.rs
@@ -0,0 +1 @@
br##"\u{20AA} \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0043_unclosed_raw_byte_string_with_unicode_escape.txt b/crates/ra_syntax/test_data/lexer/err/0043_unclosed_raw_byte_string_with_unicode_escape.txt
new file mode 100644
index 000000000..a512f0428
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0043_unclosed_raw_byte_string_with_unicode_escape.txt
@@ -0,0 +1,2 @@
1RAW_BYTE_STRING 13 "br##\"\\u{20AA}"
2> error[0; 13) token("br##\"\\u{20AA}") msg(Missing trailing `"` with `#` symbols to terminate the raw byte string literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0044_unclosed_raw_byte_string_with_space.rs b/crates/ra_syntax/test_data/lexer/err/0044_unclosed_raw_byte_string_with_space.rs
new file mode 100644
index 000000000..14c602fd2
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0044_unclosed_raw_byte_string_with_space.rs
@@ -0,0 +1 @@
br##" \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0044_unclosed_raw_byte_string_with_space.txt b/crates/ra_syntax/test_data/lexer/err/0044_unclosed_raw_byte_string_with_space.txt
new file mode 100644
index 000000000..dc616a623
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0044_unclosed_raw_byte_string_with_space.txt
@@ -0,0 +1,2 @@
1RAW_BYTE_STRING 6 "br##\" "
2> error[0; 6) token("br##\" ") msg(Missing trailing `"` with `#` symbols to terminate the raw byte string literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0045_unclosed_raw_byte_string_with_slash.rs b/crates/ra_syntax/test_data/lexer/err/0045_unclosed_raw_byte_string_with_slash.rs
new file mode 100644
index 000000000..0b3c015d7
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0045_unclosed_raw_byte_string_with_slash.rs
@@ -0,0 +1 @@
br##"\ \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0045_unclosed_raw_byte_string_with_slash.txt b/crates/ra_syntax/test_data/lexer/err/0045_unclosed_raw_byte_string_with_slash.txt
new file mode 100644
index 000000000..debafe380
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0045_unclosed_raw_byte_string_with_slash.txt
@@ -0,0 +1,2 @@
1RAW_BYTE_STRING 6 "br##\"\\"
2> error[0; 6) token("br##\"\\") msg(Missing trailing `"` with `#` symbols to terminate the raw byte string literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0046_unclosed_raw_byte_string_with_slash_n.rs b/crates/ra_syntax/test_data/lexer/err/0046_unclosed_raw_byte_string_with_slash_n.rs
new file mode 100644
index 000000000..0d8b0e7ab
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0046_unclosed_raw_byte_string_with_slash_n.rs
@@ -0,0 +1 @@
br##"\n \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0046_unclosed_raw_byte_string_with_slash_n.txt b/crates/ra_syntax/test_data/lexer/err/0046_unclosed_raw_byte_string_with_slash_n.txt
new file mode 100644
index 000000000..524e617b7
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0046_unclosed_raw_byte_string_with_slash_n.txt
@@ -0,0 +1,2 @@
1RAW_BYTE_STRING 7 "br##\"\\n"
2> error[0; 7) token("br##\"\\n") msg(Missing trailing `"` with `#` symbols to terminate the raw byte string literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0047_unstarted_raw_string_at_eof.rs b/crates/ra_syntax/test_data/lexer/err/0047_unstarted_raw_string_at_eof.rs
new file mode 100644
index 000000000..eddf8d080
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0047_unstarted_raw_string_at_eof.rs
@@ -0,0 +1 @@
r## \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0047_unstarted_raw_string_at_eof.txt b/crates/ra_syntax/test_data/lexer/err/0047_unstarted_raw_string_at_eof.txt
new file mode 100644
index 000000000..00b046840
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0047_unstarted_raw_string_at_eof.txt
@@ -0,0 +1,2 @@
1RAW_STRING 3 "r##"
2> error[0; 3) token("r##") msg(Missing `"` symbol after `#` symbols to begin the raw string literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0048_unstarted_raw_byte_string_at_eof.rs b/crates/ra_syntax/test_data/lexer/err/0048_unstarted_raw_byte_string_at_eof.rs
new file mode 100644
index 000000000..7e8cadf4f
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0048_unstarted_raw_byte_string_at_eof.rs
@@ -0,0 +1 @@
br## \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0048_unstarted_raw_byte_string_at_eof.txt b/crates/ra_syntax/test_data/lexer/err/0048_unstarted_raw_byte_string_at_eof.txt
new file mode 100644
index 000000000..33b25e60f
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0048_unstarted_raw_byte_string_at_eof.txt
@@ -0,0 +1,2 @@
1RAW_BYTE_STRING 4 "br##"
2> error[0; 4) token("br##") msg(Missing `"` symbol after `#` symbols to begin the raw byte string literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0049_unstarted_raw_string_with_ascii.rs b/crates/ra_syntax/test_data/lexer/err/0049_unstarted_raw_string_with_ascii.rs
new file mode 100644
index 000000000..534668a9b
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0049_unstarted_raw_string_with_ascii.rs
@@ -0,0 +1 @@
r## I lack a quote! \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0049_unstarted_raw_string_with_ascii.txt b/crates/ra_syntax/test_data/lexer/err/0049_unstarted_raw_string_with_ascii.txt
new file mode 100644
index 000000000..782dfd974
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0049_unstarted_raw_string_with_ascii.txt
@@ -0,0 +1,10 @@
1RAW_STRING 4 "r## "
2IDENT 1 "I"
3WHITESPACE 1 " "
4IDENT 4 "lack"
5WHITESPACE 1 " "
6IDENT 1 "a"
7WHITESPACE 1 " "
8IDENT 5 "quote"
9EXCL 1 "!"
10> error[0; 4) token("r## ") msg(Missing `"` symbol after `#` symbols to begin the raw string literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0050_unstarted_raw_byte_string_with_ascii.rs b/crates/ra_syntax/test_data/lexer/err/0050_unstarted_raw_byte_string_with_ascii.rs
new file mode 100644
index 000000000..d9b55455a
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0050_unstarted_raw_byte_string_with_ascii.rs
@@ -0,0 +1 @@
br## I lack a quote! \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0050_unstarted_raw_byte_string_with_ascii.txt b/crates/ra_syntax/test_data/lexer/err/0050_unstarted_raw_byte_string_with_ascii.txt
new file mode 100644
index 000000000..59c40cd65
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0050_unstarted_raw_byte_string_with_ascii.txt
@@ -0,0 +1,10 @@
1RAW_BYTE_STRING 5 "br## "
2IDENT 1 "I"
3WHITESPACE 1 " "
4IDENT 4 "lack"
5WHITESPACE 1 " "
6IDENT 1 "a"
7WHITESPACE 1 " "
8IDENT 5 "quote"
9EXCL 1 "!"
10> error[0; 5) token("br## ") msg(Missing `"` symbol after `#` symbols to begin the raw byte string literal)
diff --git a/crates/ra_syntax/test_data/lexer/err/0051_unclosed_block_comment_at_eof.rs b/crates/ra_syntax/test_data/lexer/err/0051_unclosed_block_comment_at_eof.rs
new file mode 100644
index 000000000..22e83649f
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0051_unclosed_block_comment_at_eof.rs
@@ -0,0 +1 @@
/* \ No newline at end of file
diff --git a/crates/ra_syntax/test_data/lexer/err/0051_unclosed_block_comment_at_eof.txt b/crates/ra_syntax/test_data/lexer/err/0051_unclosed_block_comment_at_eof.txt
new file mode 100644
index 000000000..5d04cdaa4
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0051_unclosed_block_comment_at_eof.txt
@@ -0,0 +1,2 @@
1COMMENT 2 "/*"
2> error[0; 2) token("/*") msg(Missing trailing `*/` symbols to terminate the block comment)
diff --git a/crates/ra_syntax/test_data/lexer/err/0052_unclosed_block_comment_with_content.rs b/crates/ra_syntax/test_data/lexer/err/0052_unclosed_block_comment_with_content.rs
new file mode 100644
index 000000000..c45c2844d
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0052_unclosed_block_comment_with_content.rs
@@ -0,0 +1 @@
/* comment
diff --git a/crates/ra_syntax/test_data/lexer/err/0052_unclosed_block_comment_with_content.txt b/crates/ra_syntax/test_data/lexer/err/0052_unclosed_block_comment_with_content.txt
new file mode 100644
index 000000000..8c6b678e3
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0052_unclosed_block_comment_with_content.txt
@@ -0,0 +1,2 @@
1COMMENT 11 "/* comment\n"
2> error[0; 11) token("/* comment\n") msg(Missing trailing `*/` symbols to terminate the block comment)
diff --git a/crates/ra_syntax/test_data/lexer/err/0053_unclosed_nested_block_comment_entirely.rs b/crates/ra_syntax/test_data/lexer/err/0053_unclosed_nested_block_comment_entirely.rs
new file mode 100644
index 000000000..3fcfc9660
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0053_unclosed_nested_block_comment_entirely.rs
@@ -0,0 +1 @@
/* /* /*
diff --git a/crates/ra_syntax/test_data/lexer/err/0053_unclosed_nested_block_comment_entirely.txt b/crates/ra_syntax/test_data/lexer/err/0053_unclosed_nested_block_comment_entirely.txt
new file mode 100644
index 000000000..250de34d9
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0053_unclosed_nested_block_comment_entirely.txt
@@ -0,0 +1,2 @@
1COMMENT 9 "/* /* /*\n"
2> error[0; 9) token("/* /* /*\n") msg(Missing trailing `*/` symbols to terminate the block comment)
diff --git a/crates/ra_syntax/test_data/lexer/err/0054_unclosed_nested_block_comment_partially.rs b/crates/ra_syntax/test_data/lexer/err/0054_unclosed_nested_block_comment_partially.rs
new file mode 100644
index 000000000..26c898f01
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0054_unclosed_nested_block_comment_partially.rs
@@ -0,0 +1 @@
/** /*! /* comment */ */
diff --git a/crates/ra_syntax/test_data/lexer/err/0054_unclosed_nested_block_comment_partially.txt b/crates/ra_syntax/test_data/lexer/err/0054_unclosed_nested_block_comment_partially.txt
new file mode 100644
index 000000000..f97f2a8c7
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0054_unclosed_nested_block_comment_partially.txt
@@ -0,0 +1,2 @@
1COMMENT 25 "/** /*! /* comment */ */\n"
2> error[0; 25) token("/** /*! /* comment */ */\n") msg(Missing trailing `*/` symbols to terminate the block comment)
diff --git a/crates/ra_syntax/test_data/lexer/err/0055_empty_int.rs b/crates/ra_syntax/test_data/lexer/err/0055_empty_int.rs
new file mode 100644
index 000000000..aa2a9fdca
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0055_empty_int.rs
@@ -0,0 +1,17 @@
10b
20o
30x
4
50b_
60o_
70x_
8
90bnoDigit
100onoDigit
110xnoDigit
12
130xG
140xg
15
160x_g
170x_G
diff --git a/crates/ra_syntax/test_data/lexer/err/0055_empty_int.txt b/crates/ra_syntax/test_data/lexer/err/0055_empty_int.txt
new file mode 100644
index 000000000..2fe5bd950
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0055_empty_int.txt
@@ -0,0 +1,39 @@
1INT_NUMBER 2 "0b"
2WHITESPACE 1 "\n"
3INT_NUMBER 2 "0o"
4WHITESPACE 1 "\n"
5INT_NUMBER 2 "0x"
6WHITESPACE 2 "\n\n"
7INT_NUMBER 3 "0b_"
8WHITESPACE 1 "\n"
9INT_NUMBER 3 "0o_"
10WHITESPACE 1 "\n"
11INT_NUMBER 3 "0x_"
12WHITESPACE 2 "\n\n"
13INT_NUMBER 9 "0bnoDigit"
14WHITESPACE 1 "\n"
15INT_NUMBER 9 "0onoDigit"
16WHITESPACE 1 "\n"
17INT_NUMBER 9 "0xnoDigit"
18WHITESPACE 2 "\n\n"
19INT_NUMBER 3 "0xG"
20WHITESPACE 1 "\n"
21INT_NUMBER 3 "0xg"
22WHITESPACE 2 "\n\n"
23INT_NUMBER 4 "0x_g"
24WHITESPACE 1 "\n"
25INT_NUMBER 4 "0x_G"
26WHITESPACE 1 "\n"
27> error[0; 2) token("0b") msg(Missing digits after the integer base prefix)
28> error[3; 5) token("0o") msg(Missing digits after the integer base prefix)
29> error[6; 8) token("0x") msg(Missing digits after the integer base prefix)
30> error[10; 13) token("0b_") msg(Missing digits after the integer base prefix)
31> error[14; 17) token("0o_") msg(Missing digits after the integer base prefix)
32> error[18; 21) token("0x_") msg(Missing digits after the integer base prefix)
33> error[23; 32) token("0bnoDigit") msg(Missing digits after the integer base prefix)
34> error[33; 42) token("0onoDigit") msg(Missing digits after the integer base prefix)
35> error[43; 52) token("0xnoDigit") msg(Missing digits after the integer base prefix)
36> error[54; 57) token("0xG") msg(Missing digits after the integer base prefix)
37> error[58; 61) token("0xg") msg(Missing digits after the integer base prefix)
38> error[63; 67) token("0x_g") msg(Missing digits after the integer base prefix)
39> error[68; 72) token("0x_G") msg(Missing digits after the integer base prefix)
diff --git a/crates/ra_syntax/test_data/lexer/err/0056_empty_exponent.rs b/crates/ra_syntax/test_data/lexer/err/0056_empty_exponent.rs
new file mode 100644
index 000000000..286584c88
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0056_empty_exponent.rs
@@ -0,0 +1,22 @@
10e
20E
3
442e+
542e-
642E+
742E-
8
942.e+
1042.e-
1142.E+
1242.E-
13
1442.2e+
1542.2e-
1642.2E+
1742.2E-
18
1942.2e+f32
2042.2e-f32
2142.2E+f32
2242.2E-f32
diff --git a/crates/ra_syntax/test_data/lexer/err/0056_empty_exponent.txt b/crates/ra_syntax/test_data/lexer/err/0056_empty_exponent.txt
new file mode 100644
index 000000000..ab35e20a5
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0056_empty_exponent.txt
@@ -0,0 +1,62 @@
1FLOAT_NUMBER 2 "0e"
2WHITESPACE 1 "\n"
3FLOAT_NUMBER 2 "0E"
4WHITESPACE 2 "\n\n"
5FLOAT_NUMBER 4 "42e+"
6WHITESPACE 1 "\n"
7FLOAT_NUMBER 4 "42e-"
8WHITESPACE 1 "\n"
9FLOAT_NUMBER 4 "42E+"
10WHITESPACE 1 "\n"
11FLOAT_NUMBER 4 "42E-"
12WHITESPACE 2 "\n\n"
13INT_NUMBER 2 "42"
14DOT 1 "."
15IDENT 1 "e"
16PLUS 1 "+"
17WHITESPACE 1 "\n"
18INT_NUMBER 2 "42"
19DOT 1 "."
20IDENT 1 "e"
21MINUS 1 "-"
22WHITESPACE 1 "\n"
23INT_NUMBER 2 "42"
24DOT 1 "."
25IDENT 1 "E"
26PLUS 1 "+"
27WHITESPACE 1 "\n"
28INT_NUMBER 2 "42"
29DOT 1 "."
30IDENT 1 "E"
31MINUS 1 "-"
32WHITESPACE 2 "\n\n"
33FLOAT_NUMBER 6 "42.2e+"
34WHITESPACE 1 "\n"
35FLOAT_NUMBER 6 "42.2e-"
36WHITESPACE 1 "\n"
37FLOAT_NUMBER 6 "42.2E+"
38WHITESPACE 1 "\n"
39FLOAT_NUMBER 6 "42.2E-"
40WHITESPACE 2 "\n\n"
41FLOAT_NUMBER 9 "42.2e+f32"
42WHITESPACE 1 "\n"
43FLOAT_NUMBER 9 "42.2e-f32"
44WHITESPACE 1 "\n"
45FLOAT_NUMBER 9 "42.2E+f32"
46WHITESPACE 1 "\n"
47FLOAT_NUMBER 9 "42.2E-f32"
48WHITESPACE 1 "\n"
49> error[0; 2) token("0e") msg(Missing digits after the exponent symbol)
50> error[3; 5) token("0E") msg(Missing digits after the exponent symbol)
51> error[7; 11) token("42e+") msg(Missing digits after the exponent symbol)
52> error[12; 16) token("42e-") msg(Missing digits after the exponent symbol)
53> error[17; 21) token("42E+") msg(Missing digits after the exponent symbol)
54> error[22; 26) token("42E-") msg(Missing digits after the exponent symbol)
55> error[53; 59) token("42.2e+") msg(Missing digits after the exponent symbol)
56> error[60; 66) token("42.2e-") msg(Missing digits after the exponent symbol)
57> error[67; 73) token("42.2E+") msg(Missing digits after the exponent symbol)
58> error[74; 80) token("42.2E-") msg(Missing digits after the exponent symbol)
59> error[82; 91) token("42.2e+f32") msg(Missing digits after the exponent symbol)
60> error[92; 101) token("42.2e-f32") msg(Missing digits after the exponent symbol)
61> error[102; 111) token("42.2E+f32") msg(Missing digits after the exponent symbol)
62> error[112; 121) token("42.2E-f32") msg(Missing digits after the exponent symbol)
diff --git a/crates/ra_syntax/test_data/lexer/err/0057_lifetime_strarts_with_a_number.rs b/crates/ra_syntax/test_data/lexer/err/0057_lifetime_strarts_with_a_number.rs
new file mode 100644
index 000000000..a7698a404
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0057_lifetime_strarts_with_a_number.rs
@@ -0,0 +1,2 @@
1'1
2'1lifetime
diff --git a/crates/ra_syntax/test_data/lexer/err/0057_lifetime_strarts_with_a_number.txt b/crates/ra_syntax/test_data/lexer/err/0057_lifetime_strarts_with_a_number.txt
new file mode 100644
index 000000000..89b38bfac
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/err/0057_lifetime_strarts_with_a_number.txt
@@ -0,0 +1,6 @@
1LIFETIME 2 "\'1"
2WHITESPACE 1 "\n"
3LIFETIME 10 "\'1lifetime"
4WHITESPACE 1 "\n"
5> error[0; 2) token("\'1") msg(Lifetime name cannot start with a number)
6> error[3; 13) token("\'1lifetime") msg(Lifetime name cannot start with a number)
diff --git a/crates/ra_syntax/test_data/lexer/0001_hello.rs b/crates/ra_syntax/test_data/lexer/ok/0001_hello.rs
index 95d09f2b1..95d09f2b1 100644
--- a/crates/ra_syntax/test_data/lexer/0001_hello.rs
+++ b/crates/ra_syntax/test_data/lexer/ok/0001_hello.rs
diff --git a/crates/ra_syntax/test_data/lexer/0001_hello.txt b/crates/ra_syntax/test_data/lexer/ok/0001_hello.txt
index 27a5940a9..27a5940a9 100644
--- a/crates/ra_syntax/test_data/lexer/0001_hello.txt
+++ b/crates/ra_syntax/test_data/lexer/ok/0001_hello.txt
diff --git a/crates/ra_syntax/test_data/lexer/0002_whitespace.rs b/crates/ra_syntax/test_data/lexer/ok/0002_whitespace.rs
index 08fce1418..08fce1418 100644
--- a/crates/ra_syntax/test_data/lexer/0002_whitespace.rs
+++ b/crates/ra_syntax/test_data/lexer/ok/0002_whitespace.rs
diff --git a/crates/ra_syntax/test_data/lexer/0002_whitespace.txt b/crates/ra_syntax/test_data/lexer/ok/0002_whitespace.txt
index 01d260918..01d260918 100644
--- a/crates/ra_syntax/test_data/lexer/0002_whitespace.txt
+++ b/crates/ra_syntax/test_data/lexer/ok/0002_whitespace.txt
diff --git a/crates/ra_syntax/test_data/lexer/0003_ident.rs b/crates/ra_syntax/test_data/lexer/ok/0003_ident.rs
index c05c9c009..c05c9c009 100644
--- a/crates/ra_syntax/test_data/lexer/0003_ident.rs
+++ b/crates/ra_syntax/test_data/lexer/ok/0003_ident.rs
diff --git a/crates/ra_syntax/test_data/lexer/0003_ident.txt b/crates/ra_syntax/test_data/lexer/ok/0003_ident.txt
index 4a0d5c053..4a0d5c053 100644
--- a/crates/ra_syntax/test_data/lexer/0003_ident.txt
+++ b/crates/ra_syntax/test_data/lexer/ok/0003_ident.txt
diff --git a/crates/ra_syntax/test_data/lexer/0004_numbers.rs b/crates/ra_syntax/test_data/lexer/ok/0004_numbers.rs
index dc974b553..bc761c235 100644
--- a/crates/ra_syntax/test_data/lexer/0004_numbers.rs
+++ b/crates/ra_syntax/test_data/lexer/ok/0004_numbers.rs
@@ -1,4 +1,4 @@
10 0b 0o 0x 00 0_ 0. 0e 0E 0z 10 00 0_ 0. 0z
201790 0b1790 0o1790 0x1790aAbBcCdDeEfF 001279 0_1279 0.1279 0e1279 0E1279 201790 0b1790 0o1790 0x1790aAbBcCdDeEfF 001279 0_1279 0.1279 0e1279 0E1279
30..2 30..2
40.foo() 40.foo()
@@ -6,4 +6,4 @@
60.e+1 60.e+1
70.0E-2 70.0E-2
80___0.10000____0000e+111__ 80___0.10000____0000e+111__
91i64 92.0f32 11__s \ No newline at end of file 91i64 92.0f32 11__s
diff --git a/crates/ra_syntax/test_data/lexer/0004_numbers.txt b/crates/ra_syntax/test_data/lexer/ok/0004_numbers.txt
index 7bb89b8ae..e19fc5789 100644
--- a/crates/ra_syntax/test_data/lexer/0004_numbers.txt
+++ b/crates/ra_syntax/test_data/lexer/ok/0004_numbers.txt
@@ -1,21 +1,11 @@
1INT_NUMBER 1 "0" 1INT_NUMBER 1 "0"
2WHITESPACE 1 " " 2WHITESPACE 1 " "
3INT_NUMBER 2 "0b"
4WHITESPACE 1 " "
5INT_NUMBER 2 "0o"
6WHITESPACE 1 " "
7INT_NUMBER 2 "0x"
8WHITESPACE 1 " "
9INT_NUMBER 2 "00" 3INT_NUMBER 2 "00"
10WHITESPACE 1 " " 4WHITESPACE 1 " "
11INT_NUMBER 2 "0_" 5INT_NUMBER 2 "0_"
12WHITESPACE 1 " " 6WHITESPACE 1 " "
13FLOAT_NUMBER 2 "0." 7FLOAT_NUMBER 2 "0."
14WHITESPACE 1 " " 8WHITESPACE 1 " "
15FLOAT_NUMBER 2 "0e"
16WHITESPACE 1 " "
17FLOAT_NUMBER 2 "0E"
18WHITESPACE 1 " "
19INT_NUMBER 2 "0z" 9INT_NUMBER 2 "0z"
20WHITESPACE 1 "\n" 10WHITESPACE 1 "\n"
21INT_NUMBER 5 "01790" 11INT_NUMBER 5 "01790"
@@ -64,3 +54,4 @@ WHITESPACE 1 " "
64FLOAT_NUMBER 7 "92.0f32" 54FLOAT_NUMBER 7 "92.0f32"
65WHITESPACE 1 " " 55WHITESPACE 1 " "
66INT_NUMBER 5 "11__s" 56INT_NUMBER 5 "11__s"
57WHITESPACE 1 "\n"
diff --git a/crates/ra_syntax/test_data/lexer/0005_symbols.rs b/crates/ra_syntax/test_data/lexer/ok/0005_symbols.rs
index 487569b5a..487569b5a 100644
--- a/crates/ra_syntax/test_data/lexer/0005_symbols.rs
+++ b/crates/ra_syntax/test_data/lexer/ok/0005_symbols.rs
diff --git a/crates/ra_syntax/test_data/lexer/0005_symbols.txt b/crates/ra_syntax/test_data/lexer/ok/0005_symbols.txt
index 469a90e42..469a90e42 100644
--- a/crates/ra_syntax/test_data/lexer/0005_symbols.txt
+++ b/crates/ra_syntax/test_data/lexer/ok/0005_symbols.txt
diff --git a/crates/ra_syntax/test_data/lexer/0006_chars.rs b/crates/ra_syntax/test_data/lexer/ok/0006_chars.rs
index 454ee0a5f..454ee0a5f 100644
--- a/crates/ra_syntax/test_data/lexer/0006_chars.rs
+++ b/crates/ra_syntax/test_data/lexer/ok/0006_chars.rs
diff --git a/crates/ra_syntax/test_data/lexer/0006_chars.txt b/crates/ra_syntax/test_data/lexer/ok/0006_chars.txt
index 950954fbc..950954fbc 100644
--- a/crates/ra_syntax/test_data/lexer/0006_chars.txt
+++ b/crates/ra_syntax/test_data/lexer/ok/0006_chars.txt
diff --git a/crates/ra_syntax/test_data/lexer/0007_lifetimes.rs b/crates/ra_syntax/test_data/lexer/ok/0007_lifetimes.rs
index b764f1dce..b764f1dce 100644
--- a/crates/ra_syntax/test_data/lexer/0007_lifetimes.rs
+++ b/crates/ra_syntax/test_data/lexer/ok/0007_lifetimes.rs
diff --git a/crates/ra_syntax/test_data/lexer/0007_lifetimes.txt b/crates/ra_syntax/test_data/lexer/ok/0007_lifetimes.txt
index 005c29100..005c29100 100644
--- a/crates/ra_syntax/test_data/lexer/0007_lifetimes.txt
+++ b/crates/ra_syntax/test_data/lexer/ok/0007_lifetimes.txt
diff --git a/crates/ra_syntax/test_data/lexer/0008_byte_strings.rs b/crates/ra_syntax/test_data/lexer/ok/0008_byte_strings.rs
index b54930f5e..b54930f5e 100644
--- a/crates/ra_syntax/test_data/lexer/0008_byte_strings.rs
+++ b/crates/ra_syntax/test_data/lexer/ok/0008_byte_strings.rs
diff --git a/crates/ra_syntax/test_data/lexer/0008_byte_strings.txt b/crates/ra_syntax/test_data/lexer/ok/0008_byte_strings.txt
index bc03b51a8..bc03b51a8 100644
--- a/crates/ra_syntax/test_data/lexer/0008_byte_strings.txt
+++ b/crates/ra_syntax/test_data/lexer/ok/0008_byte_strings.txt
diff --git a/crates/ra_syntax/test_data/lexer/0009_strings.rs b/crates/ra_syntax/test_data/lexer/ok/0009_strings.rs
index 4ddb5bffc..4ddb5bffc 100644
--- a/crates/ra_syntax/test_data/lexer/0009_strings.rs
+++ b/crates/ra_syntax/test_data/lexer/ok/0009_strings.rs
diff --git a/crates/ra_syntax/test_data/lexer/0009_strings.txt b/crates/ra_syntax/test_data/lexer/ok/0009_strings.txt
index 4cb4d711d..4cb4d711d 100644
--- a/crates/ra_syntax/test_data/lexer/0009_strings.txt
+++ b/crates/ra_syntax/test_data/lexer/ok/0009_strings.txt
diff --git a/crates/ra_syntax/test_data/lexer/ok/0010_single_line_comments.rs b/crates/ra_syntax/test_data/lexer/ok/0010_single_line_comments.rs
new file mode 100644
index 000000000..4b6653f9c
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/ok/0010_single_line_comments.rs
@@ -0,0 +1,12 @@
1#!/usr/bin/env bash
2// hello
3//! World
4//!! Inner line doc
5/// Outer line doc
6//// Just a comment
7
8//
9//!
10//!!
11///
12////
diff --git a/crates/ra_syntax/test_data/lexer/ok/0010_single_line_comments.txt b/crates/ra_syntax/test_data/lexer/ok/0010_single_line_comments.txt
new file mode 100644
index 000000000..98a3818c0
--- /dev/null
+++ b/crates/ra_syntax/test_data/lexer/ok/0010_single_line_comments.txt
@@ -0,0 +1,22 @@
1SHEBANG 19 "#!/usr/bin/env bash"
2WHITESPACE 1 "\n"
3COMMENT 8 "// hello"
4WHITESPACE 1 "\n"
5COMMENT 9 "//! World"
6WHITESPACE 1 "\n"
7COMMENT 19 "//!! Inner line doc"
8WHITESPACE 1 "\n"
9COMMENT 18 "/// Outer line doc"
10WHITESPACE 1 "\n"
11COMMENT 19 "//// Just a comment"
12WHITESPACE 2 "\n\n"
13COMMENT 2 "//"
14WHITESPACE 1 "\n"
15COMMENT 3 "//!"
16WHITESPACE 1 "\n"
17COMMENT 4 "//!!"
18WHITESPACE 1 "\n"
19COMMENT 3 "///"
20WHITESPACE 1 "\n"
21COMMENT 4 "////"
22WHITESPACE 1 "\n"
diff --git a/crates/ra_syntax/test_data/lexer/0011_keywords.rs b/crates/ra_syntax/test_data/lexer/ok/0011_keywords.rs
index 1e91bff4e..1e91bff4e 100644
--- a/crates/ra_syntax/test_data/lexer/0011_keywords.rs
+++ b/crates/ra_syntax/test_data/lexer/ok/0011_keywords.rs
diff --git a/crates/ra_syntax/test_data/lexer/0011_keywords.txt b/crates/ra_syntax/test_data/lexer/ok/0011_keywords.txt
index 22c00eefb..22c00eefb 100644
--- a/crates/ra_syntax/test_data/lexer/0011_keywords.txt
+++ b/crates/ra_syntax/test_data/lexer/ok/0011_keywords.txt
diff --git a/crates/ra_syntax/test_data/lexer/00012_block_comment.rs b/crates/ra_syntax/test_data/lexer/ok/0012_block_comment.rs
index 708aac197..b880a59d9 100644
--- a/crates/ra_syntax/test_data/lexer/00012_block_comment.rs
+++ b/crates/ra_syntax/test_data/lexer/ok/0012_block_comment.rs
@@ -1,4 +1,3 @@
1/* */ 1/* */
2/**/ 2/**/
3/* /* */ */ 3/* /* */ */
4/*
diff --git a/crates/ra_syntax/test_data/lexer/00012_block_comment.txt b/crates/ra_syntax/test_data/lexer/ok/0012_block_comment.txt
index 9958b2518..2618e287e 100644
--- a/crates/ra_syntax/test_data/lexer/00012_block_comment.txt
+++ b/crates/ra_syntax/test_data/lexer/ok/0012_block_comment.txt
@@ -4,4 +4,3 @@ COMMENT 4 "/**/"
4WHITESPACE 1 "\n" 4WHITESPACE 1 "\n"
5COMMENT 11 "/* /* */ */" 5COMMENT 11 "/* /* */ */"
6WHITESPACE 1 "\n" 6WHITESPACE 1 "\n"
7COMMENT 3 "/*\n"
diff --git a/crates/ra_syntax/test_data/lexer/0013_raw_strings.rs b/crates/ra_syntax/test_data/lexer/ok/0013_raw_strings.rs
index e5ed0b693..e5ed0b693 100644
--- a/crates/ra_syntax/test_data/lexer/0013_raw_strings.rs
+++ b/crates/ra_syntax/test_data/lexer/ok/0013_raw_strings.rs
diff --git a/crates/ra_syntax/test_data/lexer/0013_raw_strings.txt b/crates/ra_syntax/test_data/lexer/ok/0013_raw_strings.txt
index 9cf0957d1..9cf0957d1 100644
--- a/crates/ra_syntax/test_data/lexer/0013_raw_strings.txt
+++ b/crates/ra_syntax/test_data/lexer/ok/0013_raw_strings.txt
diff --git a/crates/ra_syntax/test_data/lexer/0016_raw_ident.rs b/crates/ra_syntax/test_data/lexer/ok/0014_raw_ident.rs
index b40a1b6a2..b40a1b6a2 100644
--- a/crates/ra_syntax/test_data/lexer/0016_raw_ident.rs
+++ b/crates/ra_syntax/test_data/lexer/ok/0014_raw_ident.rs
diff --git a/crates/ra_syntax/test_data/lexer/0016_raw_ident.txt b/crates/ra_syntax/test_data/lexer/ok/0014_raw_ident.txt
index 484689693..484689693 100644
--- a/crates/ra_syntax/test_data/lexer/0016_raw_ident.txt
+++ b/crates/ra_syntax/test_data/lexer/ok/0014_raw_ident.txt
diff --git a/crates/ra_syntax/test_data/parser/inline/err/0010_wrong_order_fns.rs b/crates/ra_syntax/test_data/parser/inline/err/0010_wrong_order_fns.rs
index 16edee95d..731e58013 100644
--- a/crates/ra_syntax/test_data/parser/inline/err/0010_wrong_order_fns.rs
+++ b/crates/ra_syntax/test_data/parser/inline/err/0010_wrong_order_fns.rs
@@ -1,2 +1,2 @@
1async unsafe fn foo() {} 1unsafe async fn foo() {}
2unsafe const fn bar() {} 2unsafe const fn bar() {}
diff --git a/crates/ra_syntax/test_data/parser/inline/err/0010_wrong_order_fns.txt b/crates/ra_syntax/test_data/parser/inline/err/0010_wrong_order_fns.txt
index 2ea6a566d..289193b9e 100644
--- a/crates/ra_syntax/test_data/parser/inline/err/0010_wrong_order_fns.txt
+++ b/crates/ra_syntax/test_data/parser/inline/err/0010_wrong_order_fns.txt
@@ -1,9 +1,9 @@
1SOURCE_FILE@[0; 50) 1SOURCE_FILE@[0; 50)
2 ERROR@[0; 5) 2 ERROR@[0; 6)
3 ASYNC_KW@[0; 5) "async" 3 UNSAFE_KW@[0; 6) "unsafe"
4 WHITESPACE@[5; 6) " " 4 WHITESPACE@[6; 7) " "
5 FN_DEF@[6; 24) 5 FN_DEF@[7; 24)
6 UNSAFE_KW@[6; 12) "unsafe" 6 ASYNC_KW@[7; 12) "async"
7 WHITESPACE@[12; 13) " " 7 WHITESPACE@[12; 13) " "
8 FN_KW@[13; 15) "fn" 8 FN_KW@[13; 15) "fn"
9 WHITESPACE@[15; 16) " " 9 WHITESPACE@[15; 16) " "
@@ -37,5 +37,5 @@ SOURCE_FILE@[0; 50)
37 L_CURLY@[47; 48) "{" 37 L_CURLY@[47; 48) "{"
38 R_CURLY@[48; 49) "}" 38 R_CURLY@[48; 49) "}"
39 WHITESPACE@[49; 50) "\n" 39 WHITESPACE@[49; 50) "\n"
40error 5: expected existential, fn, trait or impl 40error 6: expected existential, fn, trait or impl
41error 31: expected existential, fn, trait or impl 41error 31: expected existential, fn, trait or impl
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0004_value_parameters_no_patterns.rs b/crates/ra_syntax/test_data/parser/inline/ok/0004_value_parameters_no_patterns.rs
index d8c23c76a..93636e926 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0004_value_parameters_no_patterns.rs
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0004_value_parameters_no_patterns.rs
@@ -1 +1 @@
type F = Box<Fn(a: i32, &b: &i32, &mut c: &i32, ())>; type F = Box<Fn(i32, &i32, &i32, ())>;
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0004_value_parameters_no_patterns.txt b/crates/ra_syntax/test_data/parser/inline/ok/0004_value_parameters_no_patterns.txt
index 8cfba8420..9241f6fb2 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0004_value_parameters_no_patterns.txt
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0004_value_parameters_no_patterns.txt
@@ -1,5 +1,5 @@
1SOURCE_FILE@[0; 54) 1SOURCE_FILE@[0; 39)
2 TYPE_ALIAS_DEF@[0; 53) 2 TYPE_ALIAS_DEF@[0; 38)
3 TYPE_KW@[0; 4) "type" 3 TYPE_KW@[0; 4) "type"
4 WHITESPACE@[4; 5) " " 4 WHITESPACE@[4; 5) " "
5 NAME@[5; 6) 5 NAME@[5; 6)
@@ -7,75 +7,54 @@ SOURCE_FILE@[0; 54)
7 WHITESPACE@[6; 7) " " 7 WHITESPACE@[6; 7) " "
8 EQ@[7; 8) "=" 8 EQ@[7; 8) "="
9 WHITESPACE@[8; 9) " " 9 WHITESPACE@[8; 9) " "
10 PATH_TYPE@[9; 52) 10 PATH_TYPE@[9; 37)
11 PATH@[9; 52) 11 PATH@[9; 37)
12 PATH_SEGMENT@[9; 52) 12 PATH_SEGMENT@[9; 37)
13 NAME_REF@[9; 12) 13 NAME_REF@[9; 12)
14 IDENT@[9; 12) "Box" 14 IDENT@[9; 12) "Box"
15 TYPE_ARG_LIST@[12; 52) 15 TYPE_ARG_LIST@[12; 37)
16 L_ANGLE@[12; 13) "<" 16 L_ANGLE@[12; 13) "<"
17 TYPE_ARG@[13; 51) 17 TYPE_ARG@[13; 36)
18 PATH_TYPE@[13; 51) 18 PATH_TYPE@[13; 36)
19 PATH@[13; 51) 19 PATH@[13; 36)
20 PATH_SEGMENT@[13; 51) 20 PATH_SEGMENT@[13; 36)
21 NAME_REF@[13; 15) 21 NAME_REF@[13; 15)
22 IDENT@[13; 15) "Fn" 22 IDENT@[13; 15) "Fn"
23 PARAM_LIST@[15; 51) 23 PARAM_LIST@[15; 36)
24 L_PAREN@[15; 16) "(" 24 L_PAREN@[15; 16) "("
25 PARAM@[16; 22) 25 PARAM@[16; 19)
26 BIND_PAT@[16; 17) 26 PATH_TYPE@[16; 19)
27 NAME@[16; 17) 27 PATH@[16; 19)
28 IDENT@[16; 17) "a" 28 PATH_SEGMENT@[16; 19)
29 COLON@[17; 18) ":" 29 NAME_REF@[16; 19)
30 WHITESPACE@[18; 19) " " 30 IDENT@[16; 19) "i32"
31 PATH_TYPE@[19; 22) 31 COMMA@[19; 20) ","
32 PATH@[19; 22) 32 WHITESPACE@[20; 21) " "
33 PATH_SEGMENT@[19; 22) 33 PARAM@[21; 25)
34 NAME_REF@[19; 22) 34 REFERENCE_TYPE@[21; 25)
35 IDENT@[19; 22) "i32" 35 AMP@[21; 22) "&"
36 COMMA@[22; 23) "," 36 PATH_TYPE@[22; 25)
37 WHITESPACE@[23; 24) " " 37 PATH@[22; 25)
38 PARAM@[24; 32) 38 PATH_SEGMENT@[22; 25)
39 REF_PAT@[24; 26) 39 NAME_REF@[22; 25)
40 AMP@[24; 25) "&" 40 IDENT@[22; 25) "i32"
41 BIND_PAT@[25; 26) 41 COMMA@[25; 26) ","
42 NAME@[25; 26) 42 WHITESPACE@[26; 27) " "
43 IDENT@[25; 26) "b" 43 PARAM@[27; 31)
44 COLON@[26; 27) ":" 44 REFERENCE_TYPE@[27; 31)
45 WHITESPACE@[27; 28) " " 45 AMP@[27; 28) "&"
46 REFERENCE_TYPE@[28; 32) 46 PATH_TYPE@[28; 31)
47 AMP@[28; 29) "&" 47 PATH@[28; 31)
48 PATH_TYPE@[29; 32) 48 PATH_SEGMENT@[28; 31)
49 PATH@[29; 32) 49 NAME_REF@[28; 31)
50 PATH_SEGMENT@[29; 32) 50 IDENT@[28; 31) "i32"
51 NAME_REF@[29; 32) 51 COMMA@[31; 32) ","
52 IDENT@[29; 32) "i32" 52 WHITESPACE@[32; 33) " "
53 COMMA@[32; 33) "," 53 PARAM@[33; 35)
54 WHITESPACE@[33; 34) " " 54 TUPLE_TYPE@[33; 35)
55 PARAM@[34; 46) 55 L_PAREN@[33; 34) "("
56 REF_PAT@[34; 40) 56 R_PAREN@[34; 35) ")"
57 AMP@[34; 35) "&" 57 R_PAREN@[35; 36) ")"
58 MUT_KW@[35; 38) "mut" 58 R_ANGLE@[36; 37) ">"
59 WHITESPACE@[38; 39) " " 59 SEMI@[37; 38) ";"
60 BIND_PAT@[39; 40) 60 WHITESPACE@[38; 39) "\n"
61 NAME@[39; 40)
62 IDENT@[39; 40) "c"
63 COLON@[40; 41) ":"
64 WHITESPACE@[41; 42) " "
65 REFERENCE_TYPE@[42; 46)
66 AMP@[42; 43) "&"
67 PATH_TYPE@[43; 46)
68 PATH@[43; 46)
69 PATH_SEGMENT@[43; 46)
70 NAME_REF@[43; 46)
71 IDENT@[43; 46) "i32"
72 COMMA@[46; 47) ","
73 WHITESPACE@[47; 48) " "
74 PARAM@[48; 50)
75 TUPLE_TYPE@[48; 50)
76 L_PAREN@[48; 49) "("
77 R_PAREN@[49; 50) ")"
78 R_PAREN@[50; 51) ")"
79 R_ANGLE@[51; 52) ">"
80 SEMI@[52; 53) ";"
81 WHITESPACE@[53; 54) "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0104_path_fn_trait_args.rs b/crates/ra_syntax/test_data/parser/inline/ok/0104_path_fn_trait_args.rs
index aef45e561..17ed20e5b 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0104_path_fn_trait_args.rs
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0104_path_fn_trait_args.rs
@@ -1 +1 @@
type F = Box<Fn(x: i32) -> ()>; type F = Box<Fn(i32) -> ()>;
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0104_path_fn_trait_args.txt b/crates/ra_syntax/test_data/parser/inline/ok/0104_path_fn_trait_args.txt
index d6f196811..a983d5954 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0104_path_fn_trait_args.txt
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0104_path_fn_trait_args.txt
@@ -1,5 +1,5 @@
1SOURCE_FILE@[0; 32) 1SOURCE_FILE@[0; 29)
2 TYPE_ALIAS_DEF@[0; 31) 2 TYPE_ALIAS_DEF@[0; 28)
3 TYPE_KW@[0; 4) "type" 3 TYPE_KW@[0; 4) "type"
4 WHITESPACE@[4; 5) " " 4 WHITESPACE@[4; 5) " "
5 NAME@[5; 6) 5 NAME@[5; 6)
@@ -7,40 +7,35 @@ SOURCE_FILE@[0; 32)
7 WHITESPACE@[6; 7) " " 7 WHITESPACE@[6; 7) " "
8 EQ@[7; 8) "=" 8 EQ@[7; 8) "="
9 WHITESPACE@[8; 9) " " 9 WHITESPACE@[8; 9) " "
10 PATH_TYPE@[9; 30) 10 PATH_TYPE@[9; 27)
11 PATH@[9; 30) 11 PATH@[9; 27)
12 PATH_SEGMENT@[9; 30) 12 PATH_SEGMENT@[9; 27)
13 NAME_REF@[9; 12) 13 NAME_REF@[9; 12)
14 IDENT@[9; 12) "Box" 14 IDENT@[9; 12) "Box"
15 TYPE_ARG_LIST@[12; 30) 15 TYPE_ARG_LIST@[12; 27)
16 L_ANGLE@[12; 13) "<" 16 L_ANGLE@[12; 13) "<"
17 TYPE_ARG@[13; 29) 17 TYPE_ARG@[13; 26)
18 PATH_TYPE@[13; 29) 18 PATH_TYPE@[13; 26)
19 PATH@[13; 29) 19 PATH@[13; 26)
20 PATH_SEGMENT@[13; 29) 20 PATH_SEGMENT@[13; 26)
21 NAME_REF@[13; 15) 21 NAME_REF@[13; 15)
22 IDENT@[13; 15) "Fn" 22 IDENT@[13; 15) "Fn"
23 PARAM_LIST@[15; 23) 23 PARAM_LIST@[15; 20)
24 L_PAREN@[15; 16) "(" 24 L_PAREN@[15; 16) "("
25 PARAM@[16; 22) 25 PARAM@[16; 19)
26 BIND_PAT@[16; 17) 26 PATH_TYPE@[16; 19)
27 NAME@[16; 17) 27 PATH@[16; 19)
28 IDENT@[16; 17) "x" 28 PATH_SEGMENT@[16; 19)
29 COLON@[17; 18) ":" 29 NAME_REF@[16; 19)
30 WHITESPACE@[18; 19) " " 30 IDENT@[16; 19) "i32"
31 PATH_TYPE@[19; 22) 31 R_PAREN@[19; 20) ")"
32 PATH@[19; 22) 32 WHITESPACE@[20; 21) " "
33 PATH_SEGMENT@[19; 22) 33 RET_TYPE@[21; 26)
34 NAME_REF@[19; 22) 34 THIN_ARROW@[21; 23) "->"
35 IDENT@[19; 22) "i32" 35 WHITESPACE@[23; 24) " "
36 R_PAREN@[22; 23) ")" 36 TUPLE_TYPE@[24; 26)
37 WHITESPACE@[23; 24) " " 37 L_PAREN@[24; 25) "("
38 RET_TYPE@[24; 29) 38 R_PAREN@[25; 26) ")"
39 THIN_ARROW@[24; 26) "->" 39 R_ANGLE@[26; 27) ">"
40 WHITESPACE@[26; 27) " " 40 SEMI@[27; 28) ";"
41 TUPLE_TYPE@[27; 29) 41 WHITESPACE@[28; 29) "\n"
42 L_PAREN@[27; 28) "("
43 R_PAREN@[28; 29) ")"
44 R_ANGLE@[29; 30) ">"
45 SEMI@[30; 31) ";"
46 WHITESPACE@[31; 32) "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0128_combined_fns.rs b/crates/ra_syntax/test_data/parser/inline/ok/0128_combined_fns.rs
index 46af91b82..126287145 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0128_combined_fns.rs
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0128_combined_fns.rs
@@ -1,2 +1,2 @@
1unsafe async fn foo() {} 1async unsafe fn foo() {}
2const unsafe fn bar() {} 2const unsafe fn bar() {}
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0128_combined_fns.txt b/crates/ra_syntax/test_data/parser/inline/ok/0128_combined_fns.txt
index cae75c41d..8a972cdb2 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0128_combined_fns.txt
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0128_combined_fns.txt
@@ -1,8 +1,8 @@
1SOURCE_FILE@[0; 50) 1SOURCE_FILE@[0; 50)
2 FN_DEF@[0; 24) 2 FN_DEF@[0; 24)
3 UNSAFE_KW@[0; 6) "unsafe" 3 ASYNC_KW@[0; 5) "async"
4 WHITESPACE@[6; 7) " " 4 WHITESPACE@[5; 6) " "
5 ASYNC_KW@[7; 12) "async" 5 UNSAFE_KW@[6; 12) "unsafe"
6 WHITESPACE@[12; 13) " " 6 WHITESPACE@[12; 13) " "
7 FN_KW@[13; 15) "fn" 7 FN_KW@[13; 15) "fn"
8 WHITESPACE@[15; 16) " " 8 WHITESPACE@[15; 16) " "
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0152_fn_patterns.rs b/crates/ra_syntax/test_data/parser/inline/ok/0152_fn_patterns.rs
new file mode 100644
index 000000000..b49e872d7
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0152_fn_patterns.rs
@@ -0,0 +1,6 @@
1impl U {
2 fn f1((a, b): (usize, usize)) {}
3 fn f2(S { a, b }: S) {}
4 fn f3(NewType(a): NewType) {}
5 fn f4(&&a: &&usize) {}
6}
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0152_fn_patterns.txt b/crates/ra_syntax/test_data/parser/inline/ok/0152_fn_patterns.txt
new file mode 100644
index 000000000..933f5b7bd
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0152_fn_patterns.txt
@@ -0,0 +1,164 @@
1SOURCE_FILE@[0; 137)
2 IMPL_BLOCK@[0; 136)
3 IMPL_KW@[0; 4) "impl"
4 WHITESPACE@[4; 5) " "
5 PATH_TYPE@[5; 6)
6 PATH@[5; 6)
7 PATH_SEGMENT@[5; 6)
8 NAME_REF@[5; 6)
9 IDENT@[5; 6) "U"
10 WHITESPACE@[6; 7) " "
11 ITEM_LIST@[7; 136)
12 L_CURLY@[7; 8) "{"
13 WHITESPACE@[8; 13) "\n "
14 FN_DEF@[13; 45)
15 FN_KW@[13; 15) "fn"
16 WHITESPACE@[15; 16) " "
17 NAME@[16; 18)
18 IDENT@[16; 18) "f1"
19 PARAM_LIST@[18; 42)
20 L_PAREN@[18; 19) "("
21 PARAM@[19; 41)
22 TUPLE_PAT@[19; 25)
23 L_PAREN@[19; 20) "("
24 BIND_PAT@[20; 21)
25 NAME@[20; 21)
26 IDENT@[20; 21) "a"
27 COMMA@[21; 22) ","
28 WHITESPACE@[22; 23) " "
29 BIND_PAT@[23; 24)
30 NAME@[23; 24)
31 IDENT@[23; 24) "b"
32 R_PAREN@[24; 25) ")"
33 COLON@[25; 26) ":"
34 WHITESPACE@[26; 27) " "
35 TUPLE_TYPE@[27; 41)
36 L_PAREN@[27; 28) "("
37 PATH_TYPE@[28; 33)
38 PATH@[28; 33)
39 PATH_SEGMENT@[28; 33)
40 NAME_REF@[28; 33)
41 IDENT@[28; 33) "usize"
42 COMMA@[33; 34) ","
43 WHITESPACE@[34; 35) " "
44 PATH_TYPE@[35; 40)
45 PATH@[35; 40)
46 PATH_SEGMENT@[35; 40)
47 NAME_REF@[35; 40)
48 IDENT@[35; 40) "usize"
49 R_PAREN@[40; 41) ")"
50 R_PAREN@[41; 42) ")"
51 WHITESPACE@[42; 43) " "
52 BLOCK_EXPR@[43; 45)
53 BLOCK@[43; 45)
54 L_CURLY@[43; 44) "{"
55 R_CURLY@[44; 45) "}"
56 WHITESPACE@[45; 50) "\n "
57 FN_DEF@[50; 73)
58 FN_KW@[50; 52) "fn"
59 WHITESPACE@[52; 53) " "
60 NAME@[53; 55)
61 IDENT@[53; 55) "f2"
62 PARAM_LIST@[55; 70)
63 L_PAREN@[55; 56) "("
64 PARAM@[56; 69)
65 RECORD_PAT@[56; 66)
66 PATH@[56; 57)
67 PATH_SEGMENT@[56; 57)
68 NAME_REF@[56; 57)
69 IDENT@[56; 57) "S"
70 WHITESPACE@[57; 58) " "
71 RECORD_FIELD_PAT_LIST@[58; 66)
72 L_CURLY@[58; 59) "{"
73 WHITESPACE@[59; 60) " "
74 BIND_PAT@[60; 61)
75 NAME@[60; 61)
76 IDENT@[60; 61) "a"
77 COMMA@[61; 62) ","
78 WHITESPACE@[62; 63) " "
79 BIND_PAT@[63; 64)
80 NAME@[63; 64)
81 IDENT@[63; 64) "b"
82 WHITESPACE@[64; 65) " "
83 R_CURLY@[65; 66) "}"
84 COLON@[66; 67) ":"
85 WHITESPACE@[67; 68) " "
86 PATH_TYPE@[68; 69)
87 PATH@[68; 69)
88 PATH_SEGMENT@[68; 69)
89 NAME_REF@[68; 69)
90 IDENT@[68; 69) "S"
91 R_PAREN@[69; 70) ")"
92 WHITESPACE@[70; 71) " "
93 BLOCK_EXPR@[71; 73)
94 BLOCK@[71; 73)
95 L_CURLY@[71; 72) "{"
96 R_CURLY@[72; 73) "}"
97 WHITESPACE@[73; 78) "\n "
98 FN_DEF@[78; 107)
99 FN_KW@[78; 80) "fn"
100 WHITESPACE@[80; 81) " "
101 NAME@[81; 83)
102 IDENT@[81; 83) "f3"
103 PARAM_LIST@[83; 104)
104 L_PAREN@[83; 84) "("
105 PARAM@[84; 103)
106 TUPLE_STRUCT_PAT@[84; 94)
107 PATH@[84; 91)
108 PATH_SEGMENT@[84; 91)
109 NAME_REF@[84; 91)
110 IDENT@[84; 91) "NewType"
111 L_PAREN@[91; 92) "("
112 BIND_PAT@[92; 93)
113 NAME@[92; 93)
114 IDENT@[92; 93) "a"
115 R_PAREN@[93; 94) ")"
116 COLON@[94; 95) ":"
117 WHITESPACE@[95; 96) " "
118 PATH_TYPE@[96; 103)
119 PATH@[96; 103)
120 PATH_SEGMENT@[96; 103)
121 NAME_REF@[96; 103)
122 IDENT@[96; 103) "NewType"
123 R_PAREN@[103; 104) ")"
124 WHITESPACE@[104; 105) " "
125 BLOCK_EXPR@[105; 107)
126 BLOCK@[105; 107)
127 L_CURLY@[105; 106) "{"
128 R_CURLY@[106; 107) "}"
129 WHITESPACE@[107; 112) "\n "
130 FN_DEF@[112; 134)
131 FN_KW@[112; 114) "fn"
132 WHITESPACE@[114; 115) " "
133 NAME@[115; 117)
134 IDENT@[115; 117) "f4"
135 PARAM_LIST@[117; 131)
136 L_PAREN@[117; 118) "("
137 PARAM@[118; 130)
138 REF_PAT@[118; 121)
139 AMP@[118; 119) "&"
140 REF_PAT@[119; 121)
141 AMP@[119; 120) "&"
142 BIND_PAT@[120; 121)
143 NAME@[120; 121)
144 IDENT@[120; 121) "a"
145 COLON@[121; 122) ":"
146 WHITESPACE@[122; 123) " "
147 REFERENCE_TYPE@[123; 130)
148 AMP@[123; 124) "&"
149 REFERENCE_TYPE@[124; 130)
150 AMP@[124; 125) "&"
151 PATH_TYPE@[125; 130)
152 PATH@[125; 130)
153 PATH_SEGMENT@[125; 130)
154 NAME_REF@[125; 130)
155 IDENT@[125; 130) "usize"
156 R_PAREN@[130; 131) ")"
157 WHITESPACE@[131; 132) " "
158 BLOCK_EXPR@[132; 134)
159 BLOCK@[132; 134)
160 L_CURLY@[132; 133) "{"
161 R_CURLY@[133; 134) "}"
162 WHITESPACE@[134; 135) "\n"
163 R_CURLY@[135; 136) "}"
164 WHITESPACE@[136; 137) "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0153_trait_fn_patterns.rs b/crates/ra_syntax/test_data/parser/inline/ok/0153_trait_fn_patterns.rs
new file mode 100644
index 000000000..a94bf378a
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0153_trait_fn_patterns.rs
@@ -0,0 +1,6 @@
1trait T {
2 fn f1((a, b): (usize, usize)) {}
3 fn f2(S { a, b }: S) {}
4 fn f3(NewType(a): NewType) {}
5 fn f4(&&a: &&usize) {}
6}
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0153_trait_fn_patterns.txt b/crates/ra_syntax/test_data/parser/inline/ok/0153_trait_fn_patterns.txt
new file mode 100644
index 000000000..b22df8dbe
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0153_trait_fn_patterns.txt
@@ -0,0 +1,161 @@
1SOURCE_FILE@[0; 138)
2 TRAIT_DEF@[0; 137)
3 TRAIT_KW@[0; 5) "trait"
4 WHITESPACE@[5; 6) " "
5 NAME@[6; 7)
6 IDENT@[6; 7) "T"
7 WHITESPACE@[7; 8) " "
8 ITEM_LIST@[8; 137)
9 L_CURLY@[8; 9) "{"
10 WHITESPACE@[9; 14) "\n "
11 FN_DEF@[14; 46)
12 FN_KW@[14; 16) "fn"
13 WHITESPACE@[16; 17) " "
14 NAME@[17; 19)
15 IDENT@[17; 19) "f1"
16 PARAM_LIST@[19; 43)
17 L_PAREN@[19; 20) "("
18 PARAM@[20; 42)
19 TUPLE_PAT@[20; 26)
20 L_PAREN@[20; 21) "("
21 BIND_PAT@[21; 22)
22 NAME@[21; 22)
23 IDENT@[21; 22) "a"
24 COMMA@[22; 23) ","
25 WHITESPACE@[23; 24) " "
26 BIND_PAT@[24; 25)
27 NAME@[24; 25)
28 IDENT@[24; 25) "b"
29 R_PAREN@[25; 26) ")"
30 COLON@[26; 27) ":"
31 WHITESPACE@[27; 28) " "
32 TUPLE_TYPE@[28; 42)
33 L_PAREN@[28; 29) "("
34 PATH_TYPE@[29; 34)
35 PATH@[29; 34)
36 PATH_SEGMENT@[29; 34)
37 NAME_REF@[29; 34)
38 IDENT@[29; 34) "usize"
39 COMMA@[34; 35) ","
40 WHITESPACE@[35; 36) " "
41 PATH_TYPE@[36; 41)
42 PATH@[36; 41)
43 PATH_SEGMENT@[36; 41)
44 NAME_REF@[36; 41)
45 IDENT@[36; 41) "usize"
46 R_PAREN@[41; 42) ")"
47 R_PAREN@[42; 43) ")"
48 WHITESPACE@[43; 44) " "
49 BLOCK_EXPR@[44; 46)
50 BLOCK@[44; 46)
51 L_CURLY@[44; 45) "{"
52 R_CURLY@[45; 46) "}"
53 WHITESPACE@[46; 51) "\n "
54 FN_DEF@[51; 74)
55 FN_KW@[51; 53) "fn"
56 WHITESPACE@[53; 54) " "
57 NAME@[54; 56)
58 IDENT@[54; 56) "f2"
59 PARAM_LIST@[56; 71)
60 L_PAREN@[56; 57) "("
61 PARAM@[57; 70)
62 RECORD_PAT@[57; 67)
63 PATH@[57; 58)
64 PATH_SEGMENT@[57; 58)
65 NAME_REF@[57; 58)
66 IDENT@[57; 58) "S"
67 WHITESPACE@[58; 59) " "
68 RECORD_FIELD_PAT_LIST@[59; 67)
69 L_CURLY@[59; 60) "{"
70 WHITESPACE@[60; 61) " "
71 BIND_PAT@[61; 62)
72 NAME@[61; 62)
73 IDENT@[61; 62) "a"
74 COMMA@[62; 63) ","
75 WHITESPACE@[63; 64) " "
76 BIND_PAT@[64; 65)
77 NAME@[64; 65)
78 IDENT@[64; 65) "b"
79 WHITESPACE@[65; 66) " "
80 R_CURLY@[66; 67) "}"
81 COLON@[67; 68) ":"
82 WHITESPACE@[68; 69) " "
83 PATH_TYPE@[69; 70)
84 PATH@[69; 70)
85 PATH_SEGMENT@[69; 70)
86 NAME_REF@[69; 70)
87 IDENT@[69; 70) "S"
88 R_PAREN@[70; 71) ")"
89 WHITESPACE@[71; 72) " "
90 BLOCK_EXPR@[72; 74)
91 BLOCK@[72; 74)
92 L_CURLY@[72; 73) "{"
93 R_CURLY@[73; 74) "}"
94 WHITESPACE@[74; 79) "\n "
95 FN_DEF@[79; 108)
96 FN_KW@[79; 81) "fn"
97 WHITESPACE@[81; 82) " "
98 NAME@[82; 84)
99 IDENT@[82; 84) "f3"
100 PARAM_LIST@[84; 105)
101 L_PAREN@[84; 85) "("
102 PARAM@[85; 104)
103 TUPLE_STRUCT_PAT@[85; 95)
104 PATH@[85; 92)
105 PATH_SEGMENT@[85; 92)
106 NAME_REF@[85; 92)
107 IDENT@[85; 92) "NewType"
108 L_PAREN@[92; 93) "("
109 BIND_PAT@[93; 94)
110 NAME@[93; 94)
111 IDENT@[93; 94) "a"
112 R_PAREN@[94; 95) ")"
113 COLON@[95; 96) ":"
114 WHITESPACE@[96; 97) " "
115 PATH_TYPE@[97; 104)
116 PATH@[97; 104)
117 PATH_SEGMENT@[97; 104)
118 NAME_REF@[97; 104)
119 IDENT@[97; 104) "NewType"
120 R_PAREN@[104; 105) ")"
121 WHITESPACE@[105; 106) " "
122 BLOCK_EXPR@[106; 108)
123 BLOCK@[106; 108)
124 L_CURLY@[106; 107) "{"
125 R_CURLY@[107; 108) "}"
126 WHITESPACE@[108; 113) "\n "
127 FN_DEF@[113; 135)
128 FN_KW@[113; 115) "fn"
129 WHITESPACE@[115; 116) " "
130 NAME@[116; 118)
131 IDENT@[116; 118) "f4"
132 PARAM_LIST@[118; 132)
133 L_PAREN@[118; 119) "("
134 PARAM@[119; 131)
135 REF_PAT@[119; 122)
136 AMP@[119; 120) "&"
137 REF_PAT@[120; 122)
138 AMP@[120; 121) "&"
139 BIND_PAT@[121; 122)
140 NAME@[121; 122)
141 IDENT@[121; 122) "a"
142 COLON@[122; 123) ":"
143 WHITESPACE@[123; 124) " "
144 REFERENCE_TYPE@[124; 131)
145 AMP@[124; 125) "&"
146 REFERENCE_TYPE@[125; 131)
147 AMP@[125; 126) "&"
148 PATH_TYPE@[126; 131)
149 PATH@[126; 131)
150 PATH_SEGMENT@[126; 131)
151 NAME_REF@[126; 131)
152 IDENT@[126; 131) "usize"
153 R_PAREN@[131; 132) ")"
154 WHITESPACE@[132; 133) " "
155 BLOCK_EXPR@[133; 135)
156 BLOCK@[133; 135)
157 L_CURLY@[133; 134) "{"
158 R_CURLY@[134; 135) "}"
159 WHITESPACE@[135; 136) "\n"
160 R_CURLY@[136; 137) "}"
161 WHITESPACE@[137; 138) "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0154_fn_pointer_param_ident_path.rs b/crates/ra_syntax/test_data/parser/inline/ok/0154_fn_pointer_param_ident_path.rs
new file mode 100644
index 000000000..80a1701fd
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0154_fn_pointer_param_ident_path.rs
@@ -0,0 +1,2 @@
1type Foo = fn(Bar::Baz);
2type Qux = fn(baz: Bar::Baz);
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0154_fn_pointer_param_ident_path.txt b/crates/ra_syntax/test_data/parser/inline/ok/0154_fn_pointer_param_ident_path.txt
new file mode 100644
index 000000000..cb686854a
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0154_fn_pointer_param_ident_path.txt
@@ -0,0 +1,58 @@
1SOURCE_FILE@[0; 55)
2 TYPE_ALIAS_DEF@[0; 24)
3 TYPE_KW@[0; 4) "type"
4 WHITESPACE@[4; 5) " "
5 NAME@[5; 8)
6 IDENT@[5; 8) "Foo"
7 WHITESPACE@[8; 9) " "
8 EQ@[9; 10) "="
9 WHITESPACE@[10; 11) " "
10 FN_POINTER_TYPE@[11; 23)
11 FN_KW@[11; 13) "fn"
12 PARAM_LIST@[13; 23)
13 L_PAREN@[13; 14) "("
14 PARAM@[14; 22)
15 PATH_TYPE@[14; 22)
16 PATH@[14; 22)
17 PATH@[14; 17)
18 PATH_SEGMENT@[14; 17)
19 NAME_REF@[14; 17)
20 IDENT@[14; 17) "Bar"
21 COLONCOLON@[17; 19) "::"
22 PATH_SEGMENT@[19; 22)
23 NAME_REF@[19; 22)
24 IDENT@[19; 22) "Baz"
25 R_PAREN@[22; 23) ")"
26 SEMI@[23; 24) ";"
27 WHITESPACE@[24; 25) "\n"
28 TYPE_ALIAS_DEF@[25; 54)
29 TYPE_KW@[25; 29) "type"
30 WHITESPACE@[29; 30) " "
31 NAME@[30; 33)
32 IDENT@[30; 33) "Qux"
33 WHITESPACE@[33; 34) " "
34 EQ@[34; 35) "="
35 WHITESPACE@[35; 36) " "
36 FN_POINTER_TYPE@[36; 53)
37 FN_KW@[36; 38) "fn"
38 PARAM_LIST@[38; 53)
39 L_PAREN@[38; 39) "("
40 PARAM@[39; 52)
41 BIND_PAT@[39; 42)
42 NAME@[39; 42)
43 IDENT@[39; 42) "baz"
44 COLON@[42; 43) ":"
45 WHITESPACE@[43; 44) " "
46 PATH_TYPE@[44; 52)
47 PATH@[44; 52)
48 PATH@[44; 47)
49 PATH_SEGMENT@[44; 47)
50 NAME_REF@[44; 47)
51 IDENT@[44; 47) "Bar"
52 COLONCOLON@[47; 49) "::"
53 PATH_SEGMENT@[49; 52)
54 NAME_REF@[49; 52)
55 IDENT@[49; 52) "Baz"
56 R_PAREN@[52; 53) ")"
57 SEMI@[53; 54) ";"
58 WHITESPACE@[54; 55) "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0155_closure_params.rs b/crates/ra_syntax/test_data/parser/inline/ok/0155_closure_params.rs
new file mode 100644
index 000000000..6ca8dd2d6
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0155_closure_params.rs
@@ -0,0 +1,3 @@
1fn main() {
2 let foo = |bar, baz: Baz, qux: Qux::Quux| ();
3}
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0155_closure_params.txt b/crates/ra_syntax/test_data/parser/inline/ok/0155_closure_params.txt
new file mode 100644
index 000000000..98727ae98
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0155_closure_params.txt
@@ -0,0 +1,70 @@
1SOURCE_FILE@[0; 63)
2 FN_DEF@[0; 62)
3 FN_KW@[0; 2) "fn"
4 WHITESPACE@[2; 3) " "
5 NAME@[3; 7)
6 IDENT@[3; 7) "main"
7 PARAM_LIST@[7; 9)
8 L_PAREN@[7; 8) "("
9 R_PAREN@[8; 9) ")"
10 WHITESPACE@[9; 10) " "
11 BLOCK_EXPR@[10; 62)
12 BLOCK@[10; 62)
13 L_CURLY@[10; 11) "{"
14 WHITESPACE@[11; 15) "\n "
15 LET_STMT@[15; 60)
16 LET_KW@[15; 18) "let"
17 WHITESPACE@[18; 19) " "
18 BIND_PAT@[19; 22)
19 NAME@[19; 22)
20 IDENT@[19; 22) "foo"
21 WHITESPACE@[22; 23) " "
22 EQ@[23; 24) "="
23 WHITESPACE@[24; 25) " "
24 LAMBDA_EXPR@[25; 59)
25 PARAM_LIST@[25; 56)
26 PIPE@[25; 26) "|"
27 PARAM@[26; 29)
28 BIND_PAT@[26; 29)
29 NAME@[26; 29)
30 IDENT@[26; 29) "bar"
31 COMMA@[29; 30) ","
32 WHITESPACE@[30; 31) " "
33 PARAM@[31; 39)
34 BIND_PAT@[31; 34)
35 NAME@[31; 34)
36 IDENT@[31; 34) "baz"
37 COLON@[34; 35) ":"
38 WHITESPACE@[35; 36) " "
39 PATH_TYPE@[36; 39)
40 PATH@[36; 39)
41 PATH_SEGMENT@[36; 39)
42 NAME_REF@[36; 39)
43 IDENT@[36; 39) "Baz"
44 COMMA@[39; 40) ","
45 WHITESPACE@[40; 41) " "
46 PARAM@[41; 55)
47 BIND_PAT@[41; 44)
48 NAME@[41; 44)
49 IDENT@[41; 44) "qux"
50 COLON@[44; 45) ":"
51 WHITESPACE@[45; 46) " "
52 PATH_TYPE@[46; 55)
53 PATH@[46; 55)
54 PATH@[46; 49)
55 PATH_SEGMENT@[46; 49)
56 NAME_REF@[46; 49)
57 IDENT@[46; 49) "Qux"
58 COLONCOLON@[49; 51) "::"
59 PATH_SEGMENT@[51; 55)
60 NAME_REF@[51; 55)
61 IDENT@[51; 55) "Quux"
62 PIPE@[55; 56) "|"
63 WHITESPACE@[56; 57) " "
64 TUPLE_EXPR@[57; 59)
65 L_PAREN@[57; 58) "("
66 R_PAREN@[58; 59) ")"
67 SEMI@[59; 60) ";"
68 WHITESPACE@[60; 61) "\n"
69 R_CURLY@[61; 62) "}"
70 WHITESPACE@[62; 63) "\n"
diff --git a/crates/ra_syntax/test_data/parser/ok/0030_traits.rs b/crates/ra_syntax/test_data/parser/ok/0030_traits.rs
index 23c4be0e1..ac30843ef 100644
--- a/crates/ra_syntax/test_data/parser/ok/0030_traits.rs
+++ b/crates/ra_syntax/test_data/parser/ok/0030_traits.rs
@@ -1,7 +1,3 @@
1pub trait WriteMessage {
2 fn write_message(&FrontendMessage);
3}
4
5trait Runnable { 1trait Runnable {
6 fn handler(); 2 fn handler();
7} 3}
diff --git a/crates/ra_syntax/test_data/parser/ok/0030_traits.txt b/crates/ra_syntax/test_data/parser/ok/0030_traits.txt
index b656c1a81..ac314ae50 100644
--- a/crates/ra_syntax/test_data/parser/ok/0030_traits.txt
+++ b/crates/ra_syntax/test_data/parser/ok/0030_traits.txt
@@ -1,93 +1,61 @@
1SOURCE_FILE@[0; 164) 1SOURCE_FILE@[0; 96)
2 TRAIT_DEF@[0; 66) 2 TRAIT_DEF@[0; 36)
3 VISIBILITY@[0; 3) 3 TRAIT_KW@[0; 5) "trait"
4 PUB_KW@[0; 3) "pub" 4 WHITESPACE@[5; 6) " "
5 WHITESPACE@[3; 4) " " 5 NAME@[6; 14)
6 TRAIT_KW@[4; 9) "trait" 6 IDENT@[6; 14) "Runnable"
7 WHITESPACE@[9; 10) " " 7 WHITESPACE@[14; 15) " "
8 NAME@[10; 22) 8 ITEM_LIST@[15; 36)
9 IDENT@[10; 22) "WriteMessage" 9 L_CURLY@[15; 16) "{"
10 WHITESPACE@[22; 23) " " 10 WHITESPACE@[16; 21) "\n "
11 ITEM_LIST@[23; 66) 11 FN_DEF@[21; 34)
12 L_CURLY@[23; 24) "{" 12 FN_KW@[21; 23) "fn"
13 WHITESPACE@[24; 29) "\n " 13 WHITESPACE@[23; 24) " "
14 FN_DEF@[29; 64) 14 NAME@[24; 31)
15 FN_KW@[29; 31) "fn" 15 IDENT@[24; 31) "handler"
16 WHITESPACE@[31; 32) " " 16 PARAM_LIST@[31; 33)
17 NAME@[32; 45) 17 L_PAREN@[31; 32) "("
18 IDENT@[32; 45) "write_message" 18 R_PAREN@[32; 33) ")"
19 PARAM_LIST@[45; 63) 19 SEMI@[33; 34) ";"
20 L_PAREN@[45; 46) "(" 20 WHITESPACE@[34; 35) "\n"
21 PARAM@[46; 62) 21 R_CURLY@[35; 36) "}"
22 REFERENCE_TYPE@[46; 62) 22 WHITESPACE@[36; 38) "\n\n"
23 AMP@[46; 47) "&" 23 TRAIT_DEF@[38; 95)
24 PATH_TYPE@[47; 62) 24 TRAIT_KW@[38; 43) "trait"
25 PATH@[47; 62) 25 WHITESPACE@[43; 44) " "
26 PATH_SEGMENT@[47; 62) 26 NAME@[44; 57)
27 NAME_REF@[47; 62) 27 IDENT@[44; 57) "TraitWithExpr"
28 IDENT@[47; 62) "FrontendMessage" 28 WHITESPACE@[57; 58) " "
29 R_PAREN@[62; 63) ")" 29 ITEM_LIST@[58; 95)
30 SEMI@[63; 64) ";" 30 L_CURLY@[58; 59) "{"
31 WHITESPACE@[64; 65) "\n" 31 WHITESPACE@[59; 64) "\n "
32 R_CURLY@[65; 66) "}" 32 FN_DEF@[64; 93)
33 WHITESPACE@[66; 68) "\n\n" 33 FN_KW@[64; 66) "fn"
34 TRAIT_DEF@[68; 104) 34 WHITESPACE@[66; 67) " "
35 TRAIT_KW@[68; 73) "trait" 35 NAME@[67; 79)
36 WHITESPACE@[73; 74) " " 36 IDENT@[67; 79) "fn_with_expr"
37 NAME@[74; 82) 37 PARAM_LIST@[79; 92)
38 IDENT@[74; 82) "Runnable" 38 L_PAREN@[79; 80) "("
39 WHITESPACE@[82; 83) " " 39 PARAM@[80; 91)
40 ITEM_LIST@[83; 104) 40 BIND_PAT@[80; 81)
41 L_CURLY@[83; 84) "{" 41 NAME@[80; 81)
42 WHITESPACE@[84; 89) "\n " 42 IDENT@[80; 81) "x"
43 FN_DEF@[89; 102) 43 COLON@[81; 82) ":"
44 FN_KW@[89; 91) "fn" 44 WHITESPACE@[82; 83) " "
45 WHITESPACE@[91; 92) " " 45 ARRAY_TYPE@[83; 91)
46 NAME@[92; 99) 46 L_BRACK@[83; 84) "["
47 IDENT@[92; 99) "handler" 47 PATH_TYPE@[84; 87)
48 PARAM_LIST@[99; 101) 48 PATH@[84; 87)
49 L_PAREN@[99; 100) "(" 49 PATH_SEGMENT@[84; 87)
50 R_PAREN@[100; 101) ")" 50 NAME_REF@[84; 87)
51 SEMI@[101; 102) ";" 51 IDENT@[84; 87) "i32"
52 WHITESPACE@[102; 103) "\n" 52 SEMI@[87; 88) ";"
53 R_CURLY@[103; 104) "}" 53 WHITESPACE@[88; 89) " "
54 WHITESPACE@[104; 106) "\n\n" 54 LITERAL@[89; 90)
55 TRAIT_DEF@[106; 163) 55 INT_NUMBER@[89; 90) "1"
56 TRAIT_KW@[106; 111) "trait" 56 R_BRACK@[90; 91) "]"
57 WHITESPACE@[111; 112) " " 57 R_PAREN@[91; 92) ")"
58 NAME@[112; 125) 58 SEMI@[92; 93) ";"
59 IDENT@[112; 125) "TraitWithExpr" 59 WHITESPACE@[93; 94) "\n"
60 WHITESPACE@[125; 126) " " 60 R_CURLY@[94; 95) "}"
61 ITEM_LIST@[126; 163) 61 WHITESPACE@[95; 96) "\n"
62 L_CURLY@[126; 127) "{"
63 WHITESPACE@[127; 132) "\n "
64 FN_DEF@[132; 161)
65 FN_KW@[132; 134) "fn"
66 WHITESPACE@[134; 135) " "
67 NAME@[135; 147)
68 IDENT@[135; 147) "fn_with_expr"
69 PARAM_LIST@[147; 160)
70 L_PAREN@[147; 148) "("
71 PARAM@[148; 159)
72 BIND_PAT@[148; 149)
73 NAME@[148; 149)
74 IDENT@[148; 149) "x"
75 COLON@[149; 150) ":"
76 WHITESPACE@[150; 151) " "
77 ARRAY_TYPE@[151; 159)
78 L_BRACK@[151; 152) "["
79 PATH_TYPE@[152; 155)
80 PATH@[152; 155)
81 PATH_SEGMENT@[152; 155)
82 NAME_REF@[152; 155)
83 IDENT@[152; 155) "i32"
84 SEMI@[155; 156) ";"
85 WHITESPACE@[156; 157) " "
86 LITERAL@[157; 158)
87 INT_NUMBER@[157; 158) "1"
88 R_BRACK@[158; 159) "]"
89 R_PAREN@[159; 160) ")"
90 SEMI@[160; 161) ";"
91 WHITESPACE@[161; 162) "\n"
92 R_CURLY@[162; 163) "}"
93 WHITESPACE@[163; 164) "\n"