aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-02-18 12:57:26 +0000
committerGitHub <[email protected]>2020-02-18 12:57:26 +0000
commitc447fe9bc06006a7080da782cf67d739c91b534c (patch)
tree45cbc9578b24437da3eedc6a234784be22b1f38c /crates/ra_syntax
parent742459c8fe08e359ae380e3e1dc0d059c0b4f871 (diff)
parent053ccf4121797e4e559e3225d46d3f23cb1ad70b (diff)
Merge #3026
3026: ra_syntax: reshape SyntaxError for the sake of removing redundancy r=matklad a=Veetaha Followup of #2911, also puts some crosses to the todo list of #223. **AHTUNG!** A big part of the diff of this PR are test data files changes. Simplified `SyntaxError` that was `SyntaxError { kind: { /* big enum */ }, location: Location }` to `SyntaxError(String, TextRange)`. I am not sure whether the tuple struct here is best fit, I am inclined to add names to the fields, because I already provide getters `SyntaxError::message()`, `SyntaxError::range()`. I also removed `Location` altogether ... This is currently WIP, because the following is not done: - [ ] ~~Add tests to `test_data` dir for unescape errors *// I don't know where to put these errors in particular, because they are out of the scope of the lexer and parser. However, I have an idea in mind that we move all validators we have right now to parsing stage, but this is up to discussion...*~~ **[UPD]** I came to a conclusion that tree validation logic, which unescape errors are a part of, should be rethought of, we currently have no tests and no place to put tests for tree validations. So I'd like to extract potential redesign (maybe move of tree validation to ra_parser) and adding tests for this into a separate task. Co-authored-by: Veetaha <[email protected]> Co-authored-by: Veetaha <[email protected]>
Diffstat (limited to 'crates/ra_syntax')
-rw-r--r--crates/ra_syntax/src/lib.rs8
-rw-r--r--crates/ra_syntax/src/parsing/lexer.rs92
-rw-r--r--crates/ra_syntax/src/parsing/reparsing.rs84
-rw-r--r--crates/ra_syntax/src/syntax_error.rs213
-rw-r--r--crates/ra_syntax/src/syntax_node.rs11
-rw-r--r--crates/ra_syntax/src/tests.rs25
-rw-r--r--crates/ra_syntax/src/validation.rs155
-rw-r--r--crates/ra_syntax/src/validation/block.rs14
-rw-r--r--crates/ra_syntax/test_data/parser/err/0000_struct_field_missing_comma.txt2
-rw-r--r--crates/ra_syntax/test_data/parser/err/0001_item_recovery_in_file.txt4
-rw-r--r--crates/ra_syntax/test_data/parser/err/0002_duplicate_shebang.txt22
-rw-r--r--crates/ra_syntax/test_data/parser/err/0003_C++_semicolon.txt2
-rw-r--r--crates/ra_syntax/test_data/parser/err/0004_use_path_bad_segment.txt2
-rw-r--r--crates/ra_syntax/test_data/parser/err/0005_attribute_recover.txt6
-rw-r--r--crates/ra_syntax/test_data/parser/err/0006_named_field_recovery.txt16
-rw-r--r--crates/ra_syntax/test_data/parser/err/0007_stray_curly_in_file.txt6
-rw-r--r--crates/ra_syntax/test_data/parser/err/0008_item_block_recovery.txt6
-rw-r--r--crates/ra_syntax/test_data/parser/err/0009_broken_struct_type_parameter.txt22
-rw-r--r--crates/ra_syntax/test_data/parser/err/0010_unsafe_lambda_block.txt2
-rw-r--r--crates/ra_syntax/test_data/parser/err/0011_extern_struct.txt2
-rw-r--r--crates/ra_syntax/test_data/parser/err/0013_invalid_type.txt36
-rw-r--r--crates/ra_syntax/test_data/parser/err/0014_where_no_bounds.txt2
-rw-r--r--crates/ra_syntax/test_data/parser/err/0015_curly_in_params.txt12
-rw-r--r--crates/ra_syntax/test_data/parser/err/0016_missing_semi.txt2
-rw-r--r--crates/ra_syntax/test_data/parser/err/0017_incomplete_binexpr.txt2
-rw-r--r--crates/ra_syntax/test_data/parser/err/0018_incomplete_fn.txt10
-rw-r--r--crates/ra_syntax/test_data/parser/err/0019_let_recover.txt20
-rw-r--r--crates/ra_syntax/test_data/parser/err/0020_fn_recover.txt6
-rw-r--r--crates/ra_syntax/test_data/parser/err/0021_incomplete_param.txt4
-rw-r--r--crates/ra_syntax/test_data/parser/err/0022_bad_exprs.txt66
-rw-r--r--crates/ra_syntax/test_data/parser/err/0023_mismatched_paren.txt4
-rw-r--r--crates/ra_syntax/test_data/parser/err/0024_many_type_parens.txt58
-rw-r--r--crates/ra_syntax/test_data/parser/err/0025_nope.txt22
-rw-r--r--crates/ra_syntax/test_data/parser/err/0026_imp_recovery.txt4
-rw-r--r--crates/ra_syntax/test_data/parser/err/0027_incomplere_where_for.txt4
-rw-r--r--crates/ra_syntax/test_data/parser/err/0029_field_completion.txt2
-rw-r--r--crates/ra_syntax/test_data/parser/err/0032_match_arms_inner_attrs.txt22
-rw-r--r--crates/ra_syntax/test_data/parser/err/0033_match_arms_outer_attrs.txt6
-rw-r--r--crates/ra_syntax/test_data/parser/err/0034_bad_box_pattern.txt12
-rw-r--r--crates/ra_syntax/test_data/parser/err/0035_use_recover.txt8
-rw-r--r--crates/ra_syntax/test_data/parser/err/0036_partial_use.txt20
-rw-r--r--crates/ra_syntax/test_data/parser/err/0037_visibility_in_traits.txt6
-rw-r--r--crates/ra_syntax/test_data/parser/err/0039_lambda_recovery.txt2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0001_array_type_missing_semi.txt10
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0002_misplaced_label_err.txt8
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0003_pointer_type_no_mutability.txt2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0004_impl_type.txt8
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0005_fn_pointer_type_missing_fn.txt10
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0006_unsafe_block_in_mod.txt4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0007_async_without_semicolon.txt2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0008_pub_expr.txt2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0009_attr_on_expr_not_allowed.txt4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0010_wrong_order_fns.txt4
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0013_static_underscore.txt2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/err/0014_default_fn_type.txt12
55 files changed, 450 insertions, 642 deletions
diff --git a/crates/ra_syntax/src/lib.rs b/crates/ra_syntax/src/lib.rs
index f8f4b64c1..e3f74da6d 100644
--- a/crates/ra_syntax/src/lib.rs
+++ b/crates/ra_syntax/src/lib.rs
@@ -41,11 +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::{ 44 parsing::{lex_single_syntax_kind, lex_single_valid_syntax_kind, tokenize, Token},
45 lex_single_syntax_kind, lex_single_valid_syntax_kind, tokenize, Token, TokenizeError,
46 },
47 ptr::{AstPtr, SyntaxNodePtr}, 45 ptr::{AstPtr, SyntaxNodePtr},
48 syntax_error::{Location, SyntaxError, SyntaxErrorKind}, 46 syntax_error::SyntaxError,
49 syntax_node::{ 47 syntax_node::{
50 Direction, NodeOrToken, SyntaxElement, SyntaxNode, SyntaxToken, SyntaxTreeBuilder, 48 Direction, NodeOrToken, SyntaxElement, SyntaxNode, SyntaxToken, SyntaxTreeBuilder,
51 }, 49 },
@@ -117,7 +115,7 @@ impl Parse<SourceFile> {
117 pub fn debug_dump(&self) -> String { 115 pub fn debug_dump(&self) -> String {
118 let mut buf = format!("{:#?}", self.tree().syntax()); 116 let mut buf = format!("{:#?}", self.tree().syntax());
119 for err in self.errors.iter() { 117 for err in self.errors.iter() {
120 writeln!(buf, "error {:?}: {}", err.location(), err.kind()).unwrap(); 118 writeln!(buf, "error {:?}: {}", err.range(), err).unwrap();
121 } 119 }
122 buf 120 buf
123 } 121 }
diff --git a/crates/ra_syntax/src/parsing/lexer.rs b/crates/ra_syntax/src/parsing/lexer.rs
index f889e6a1d..f2684c852 100644
--- a/crates/ra_syntax/src/parsing/lexer.rs
+++ b/crates/ra_syntax/src/parsing/lexer.rs
@@ -2,7 +2,7 @@
2//! It is just a bridge to `rustc_lexer`. 2//! It is just a bridge to `rustc_lexer`.
3 3
4use crate::{ 4use crate::{
5 SyntaxError, SyntaxErrorKind, 5 SyntaxError,
6 SyntaxKind::{self, *}, 6 SyntaxKind::{self, *},
7 TextRange, TextUnit, 7 TextRange, TextUnit,
8}; 8};
@@ -41,13 +41,13 @@ pub fn tokenize(text: &str) -> (Vec<Token>, Vec<SyntaxError>) {
41 let token_len = TextUnit::from_usize(rustc_token.len); 41 let token_len = TextUnit::from_usize(rustc_token.len);
42 let token_range = TextRange::offset_len(TextUnit::from_usize(offset), token_len); 42 let token_range = TextRange::offset_len(TextUnit::from_usize(offset), token_len);
43 43
44 let (syntax_kind, error) = 44 let (syntax_kind, err_message) =
45 rustc_token_kind_to_syntax_kind(&rustc_token.kind, &text[token_range]); 45 rustc_token_kind_to_syntax_kind(&rustc_token.kind, &text[token_range]);
46 46
47 tokens.push(Token { kind: syntax_kind, len: token_len }); 47 tokens.push(Token { kind: syntax_kind, len: token_len });
48 48
49 if let Some(error) = error { 49 if let Some(err_message) = err_message {
50 errors.push(SyntaxError::new(SyntaxErrorKind::TokenizeError(error), token_range)); 50 errors.push(SyntaxError::new(err_message, token_range));
51 } 51 }
52 52
53 offset += rustc_token.len; 53 offset += rustc_token.len;
@@ -94,61 +94,21 @@ fn lex_first_token(text: &str) -> Option<(Token, Option<SyntaxError>)> {
94 } 94 }
95 95
96 let rustc_token = rustc_lexer::first_token(text); 96 let rustc_token = rustc_lexer::first_token(text);
97 let (syntax_kind, error) = rustc_token_kind_to_syntax_kind(&rustc_token.kind, text); 97 let (syntax_kind, err_message) = rustc_token_kind_to_syntax_kind(&rustc_token.kind, text);
98 98
99 let token = Token { kind: syntax_kind, len: TextUnit::from_usize(rustc_token.len) }; 99 let token = Token { kind: syntax_kind, len: TextUnit::from_usize(rustc_token.len) };
100 let error = error.map(|error| { 100 let optional_error = err_message.map(|err_message| {
101 SyntaxError::new( 101 SyntaxError::new(err_message, TextRange::from_to(0.into(), TextUnit::of_str(text)))
102 SyntaxErrorKind::TokenizeError(error),
103 TextRange::from_to(TextUnit::from(0), TextUnit::of_str(text)),
104 )
105 }); 102 });
106 103
107 Some((token, error)) 104 Some((token, optional_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} 105}
147 106
107/// Returns `SyntaxKind` and an optional tokenize error message.
148fn rustc_token_kind_to_syntax_kind( 108fn rustc_token_kind_to_syntax_kind(
149 rustc_token_kind: &rustc_lexer::TokenKind, 109 rustc_token_kind: &rustc_lexer::TokenKind,
150 token_text: &str, 110 token_text: &str,
151) -> (SyntaxKind, Option<TokenizeError>) { 111) -> (SyntaxKind, Option<&'static str>) {
152 // A note on an intended tradeoff: 112 // A note on an intended tradeoff:
153 // We drop some useful infromation here (see patterns with double dots `..`) 113 // 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 114 // Storing that info in `SyntaxKind` is not possible due to its layout requirements of
@@ -156,14 +116,15 @@ fn rustc_token_kind_to_syntax_kind(
156 116
157 let syntax_kind = { 117 let syntax_kind = {
158 use rustc_lexer::TokenKind as TK; 118 use rustc_lexer::TokenKind as TK;
159 use TokenizeError as TE;
160
161 match rustc_token_kind { 119 match rustc_token_kind {
162 TK::LineComment => COMMENT, 120 TK::LineComment => COMMENT,
163 121
164 TK::BlockComment { terminated: true } => COMMENT, 122 TK::BlockComment { terminated: true } => COMMENT,
165 TK::BlockComment { terminated: false } => { 123 TK::BlockComment { terminated: false } => {
166 return (COMMENT, Some(TE::UnterminatedBlockComment)); 124 return (
125 COMMENT,
126 Some("Missing trailing `*/` symbols to terminate the block comment"),
127 );
167 } 128 }
168 129
169 TK::Whitespace => WHITESPACE, 130 TK::Whitespace => WHITESPACE,
@@ -181,7 +142,7 @@ fn rustc_token_kind_to_syntax_kind(
181 142
182 TK::Lifetime { starts_with_number: false } => LIFETIME, 143 TK::Lifetime { starts_with_number: false } => LIFETIME,
183 TK::Lifetime { starts_with_number: true } => { 144 TK::Lifetime { starts_with_number: true } => {
184 return (LIFETIME, Some(TE::LifetimeStartsWithNumber)) 145 return (LIFETIME, Some("Lifetime name cannot start with a number"))
185 } 146 }
186 147
187 TK::Semi => SEMI, 148 TK::Semi => SEMI,
@@ -217,57 +178,56 @@ fn rustc_token_kind_to_syntax_kind(
217 178
218 return (syntax_kind, None); 179 return (syntax_kind, None);
219 180
220 fn match_literal_kind(kind: &rustc_lexer::LiteralKind) -> (SyntaxKind, Option<TokenizeError>) { 181 fn match_literal_kind(kind: &rustc_lexer::LiteralKind) -> (SyntaxKind, Option<&'static str>) {
221 use rustc_lexer::LiteralKind as LK; 182 use rustc_lexer::LiteralKind as LK;
222 use TokenizeError as TE;
223 183
224 #[rustfmt::skip] 184 #[rustfmt::skip]
225 let syntax_kind = match *kind { 185 let syntax_kind = match *kind {
226 LK::Int { empty_int: false, .. } => INT_NUMBER, 186 LK::Int { empty_int: false, .. } => INT_NUMBER,
227 LK::Int { empty_int: true, .. } => { 187 LK::Int { empty_int: true, .. } => {
228 return (INT_NUMBER, Some(TE::EmptyInt)) 188 return (INT_NUMBER, Some("Missing digits after the integer base prefix"))
229 } 189 }
230 190
231 LK::Float { empty_exponent: false, .. } => FLOAT_NUMBER, 191 LK::Float { empty_exponent: false, .. } => FLOAT_NUMBER,
232 LK::Float { empty_exponent: true, .. } => { 192 LK::Float { empty_exponent: true, .. } => {
233 return (FLOAT_NUMBER, Some(TE::EmptyExponent)) 193 return (FLOAT_NUMBER, Some("Missing digits after the exponent symbol"))
234 } 194 }
235 195
236 LK::Char { terminated: true } => CHAR, 196 LK::Char { terminated: true } => CHAR,
237 LK::Char { terminated: false } => { 197 LK::Char { terminated: false } => {
238 return (CHAR, Some(TE::UnterminatedChar)) 198 return (CHAR, Some("Missing trailing `'` symbol to terminate the character literal"))
239 } 199 }
240 200
241 LK::Byte { terminated: true } => BYTE, 201 LK::Byte { terminated: true } => BYTE,
242 LK::Byte { terminated: false } => { 202 LK::Byte { terminated: false } => {
243 return (BYTE, Some(TE::UnterminatedByte)) 203 return (BYTE, Some("Missing trailing `'` symbol to terminate the byte literal"))
244 } 204 }
245 205
246 LK::Str { terminated: true } => STRING, 206 LK::Str { terminated: true } => STRING,
247 LK::Str { terminated: false } => { 207 LK::Str { terminated: false } => {
248 return (STRING, Some(TE::UnterminatedString)) 208 return (STRING, Some("Missing trailing `\"` symbol to terminate the string literal"))
249 } 209 }
250 210
251 211
252 LK::ByteStr { terminated: true } => BYTE_STRING, 212 LK::ByteStr { terminated: true } => BYTE_STRING,
253 LK::ByteStr { terminated: false } => { 213 LK::ByteStr { terminated: false } => {
254 return (BYTE_STRING, Some(TE::UnterminatedByteString)) 214 return (BYTE_STRING, Some("Missing trailing `\"` symbol to terminate the byte string literal"))
255 } 215 }
256 216
257 LK::RawStr { started: true, terminated: true, .. } => RAW_STRING, 217 LK::RawStr { started: true, terminated: true, .. } => RAW_STRING,
258 LK::RawStr { started: true, terminated: false, .. } => { 218 LK::RawStr { started: true, terminated: false, .. } => {
259 return (RAW_STRING, Some(TE::UnterminatedRawString)) 219 return (RAW_STRING, Some("Missing trailing `\"` with `#` symbols to terminate the raw string literal"))
260 } 220 }
261 LK::RawStr { started: false, .. } => { 221 LK::RawStr { started: false, .. } => {
262 return (RAW_STRING, Some(TE::UnstartedRawString)) 222 return (RAW_STRING, Some("Missing `\"` symbol after `#` symbols to begin the raw string literal"))
263 } 223 }
264 224
265 LK::RawByteStr { started: true, terminated: true, .. } => RAW_BYTE_STRING, 225 LK::RawByteStr { started: true, terminated: true, .. } => RAW_BYTE_STRING,
266 LK::RawByteStr { started: true, terminated: false, .. } => { 226 LK::RawByteStr { started: true, terminated: false, .. } => {
267 return (RAW_BYTE_STRING, Some(TE::UnterminatedRawByteString)) 227 return (RAW_BYTE_STRING, Some("Missing trailing `\"` with `#` symbols to terminate the raw byte string literal"))
268 } 228 }
269 LK::RawByteStr { started: false, .. } => { 229 LK::RawByteStr { started: false, .. } => {
270 return (RAW_BYTE_STRING, Some(TE::UnstartedRawByteString)) 230 return (RAW_BYTE_STRING, Some("Missing `\"` symbol after `#` symbols to begin the raw byte string literal"))
271 } 231 }
272 }; 232 };
273 233
diff --git a/crates/ra_syntax/src/parsing/reparsing.rs b/crates/ra_syntax/src/parsing/reparsing.rs
index a86da0675..aad70d015 100644
--- a/crates/ra_syntax/src/parsing/reparsing.rs
+++ b/crates/ra_syntax/src/parsing/reparsing.rs
@@ -27,8 +27,8 @@ pub(crate) fn incremental_reparse(
27 edit: &AtomTextEdit, 27 edit: &AtomTextEdit,
28 errors: Vec<SyntaxError>, 28 errors: Vec<SyntaxError>,
29) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> { 29) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> {
30 if let Some((green, old_range)) = reparse_token(node, &edit) { 30 if let Some((green, new_errors, old_range)) = reparse_token(node, &edit) {
31 return Some((green, merge_errors(errors, Vec::new(), old_range, edit), old_range)); 31 return Some((green, merge_errors(errors, new_errors, old_range, edit), old_range));
32 } 32 }
33 33
34 if let Some((green, new_errors, old_range)) = reparse_block(node, &edit) { 34 if let Some((green, new_errors, old_range)) = reparse_block(node, &edit) {
@@ -40,7 +40,7 @@ pub(crate) fn incremental_reparse(
40fn reparse_token<'node>( 40fn reparse_token<'node>(
41 root: &'node SyntaxNode, 41 root: &'node SyntaxNode,
42 edit: &AtomTextEdit, 42 edit: &AtomTextEdit,
43) -> Option<(GreenNode, TextRange)> { 43) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> {
44 let prev_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 let prev_token_kind = prev_token.kind(); 45 let prev_token_kind = prev_token.kind();
46 match prev_token_kind { 46 match prev_token_kind {
@@ -54,7 +54,7 @@ fn reparse_token<'node>(
54 } 54 }
55 55
56 let mut new_text = get_text_after_edit(prev_token.clone().into(), &edit); 56 let mut new_text = get_text_after_edit(prev_token.clone().into(), &edit);
57 let (new_token_kind, _error) = lex_single_syntax_kind(&new_text)?; 57 let (new_token_kind, new_err) = lex_single_syntax_kind(&new_text)?;
58 58
59 if new_token_kind != prev_token_kind 59 if new_token_kind != prev_token_kind
60 || (new_token_kind == IDENT && is_contextual_kw(&new_text)) 60 || (new_token_kind == IDENT && is_contextual_kw(&new_text))
@@ -76,7 +76,11 @@ fn reparse_token<'node>(
76 76
77 let new_token = 77 let new_token =
78 GreenToken::new(rowan::SyntaxKind(prev_token_kind.into()), new_text.into()); 78 GreenToken::new(rowan::SyntaxKind(prev_token_kind.into()), new_text.into());
79 Some((prev_token.replace_with(new_token), prev_token.text_range())) 79 Some((
80 prev_token.replace_with(new_token),
81 new_err.into_iter().collect(),
82 prev_token.text_range(),
83 ))
80 } 84 }
81 _ => None, 85 _ => None,
82 } 86 }
@@ -87,7 +91,7 @@ fn reparse_block<'node>(
87 edit: &AtomTextEdit, 91 edit: &AtomTextEdit,
88) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> { 92) -> Option<(GreenNode, Vec<SyntaxError>, TextRange)> {
89 let (node, reparser) = find_reparsable_node(root, edit.delete)?; 93 let (node, reparser) = find_reparsable_node(root, edit.delete)?;
90 let text = get_text_after_edit(node.clone().into(), &edit); 94 let text = get_text_after_edit(node.clone().into(), edit);
91 95
92 let (tokens, new_lexer_errors) = tokenize(&text); 96 let (tokens, new_lexer_errors) = tokenize(&text);
93 if !is_balanced(&tokens) { 97 if !is_balanced(&tokens) {
@@ -162,20 +166,27 @@ fn is_balanced(tokens: &[Token]) -> bool {
162fn merge_errors( 166fn merge_errors(
163 old_errors: Vec<SyntaxError>, 167 old_errors: Vec<SyntaxError>,
164 new_errors: Vec<SyntaxError>, 168 new_errors: Vec<SyntaxError>,
165 old_range: TextRange, 169 range_before_reparse: TextRange,
166 edit: &AtomTextEdit, 170 edit: &AtomTextEdit,
167) -> Vec<SyntaxError> { 171) -> Vec<SyntaxError> {
168 let mut res = Vec::new(); 172 let mut res = Vec::new();
169 for e in old_errors { 173
170 if e.offset() <= old_range.start() { 174 for old_err in old_errors {
171 res.push(e) 175 let old_err_range = old_err.range();
172 } else if e.offset() >= old_range.end() { 176 // FIXME: make sure that .start() was here previously by a mistake
173 res.push(e.add_offset(TextUnit::of_str(&edit.insert), edit.delete.len())); 177 if old_err_range.end() <= range_before_reparse.start() {
178 res.push(old_err);
179 } else if old_err_range.start() >= range_before_reparse.end() {
180 let inserted_len = TextUnit::of_str(&edit.insert);
181 res.push(old_err.with_range((old_err_range + inserted_len) - edit.delete.len()));
182 // Note: extra parens are intentional to prevent uint underflow, HWAB (here was a bug)
174 } 183 }
175 } 184 }
176 for e in new_errors { 185 res.extend(new_errors.into_iter().map(|new_err| {
177 res.push(e.add_offset(old_range.start(), 0.into())); 186 // fighting borrow checker with a variable ;)
178 } 187 let offseted_range = new_err.range() + range_before_reparse.start();
188 new_err.with_range(offseted_range)
189 }));
179 res 190 res
180} 191}
181 192
@@ -193,9 +204,9 @@ mod tests {
193 204
194 let fully_reparsed = SourceFile::parse(&after); 205 let fully_reparsed = SourceFile::parse(&after);
195 let incrementally_reparsed: Parse<SourceFile> = { 206 let incrementally_reparsed: Parse<SourceFile> = {
196 let f = SourceFile::parse(&before); 207 let before = SourceFile::parse(&before);
197 let (green, new_errors, range) = 208 let (green, new_errors, range) =
198 incremental_reparse(f.tree().syntax(), &edit, f.errors.to_vec()).unwrap(); 209 incremental_reparse(before.tree().syntax(), &edit, before.errors.to_vec()).unwrap();
199 assert_eq!(range.len(), reparsed_len.into(), "reparsed fragment has wrong length"); 210 assert_eq!(range.len(), reparsed_len.into(), "reparsed fragment has wrong length");
200 Parse::new(green, new_errors) 211 Parse::new(green, new_errors)
201 }; 212 };
@@ -204,6 +215,7 @@ mod tests {
204 &format!("{:#?}", fully_reparsed.tree().syntax()), 215 &format!("{:#?}", fully_reparsed.tree().syntax()),
205 &format!("{:#?}", incrementally_reparsed.tree().syntax()), 216 &format!("{:#?}", incrementally_reparsed.tree().syntax()),
206 ); 217 );
218 assert_eq!(fully_reparsed.errors(), incrementally_reparsed.errors());
207 } 219 }
208 220
209 #[test] // FIXME: some test here actually test token reparsing 221 #[test] // FIXME: some test here actually test token reparsing
@@ -402,4 +414,42 @@ enum Foo {
402 4, 414 4,
403 ); 415 );
404 } 416 }
417
418 #[test]
419 fn reparse_str_token_with_error_unchanged() {
420 do_check(r#""<|>Unclosed<|> string literal"#, "Still unclosed", 24);
421 }
422
423 #[test]
424 fn reparse_str_token_with_error_fixed() {
425 do_check(r#""unterinated<|><|>"#, "\"", 12);
426 }
427
428 #[test]
429 fn reparse_block_with_error_in_middle_unchanged() {
430 do_check(
431 r#"fn main() {
432 if {}
433 32 + 4<|><|>
434 return
435 if {}
436 }"#,
437 "23",
438 105,
439 )
440 }
441
442 #[test]
443 fn reparse_block_with_error_in_middle_fixed() {
444 do_check(
445 r#"fn main() {
446 if {}
447 32 + 4<|><|>
448 return
449 if {}
450 }"#,
451 ";",
452 105,
453 )
454 }
405} 455}
diff --git a/crates/ra_syntax/src/syntax_error.rs b/crates/ra_syntax/src/syntax_error.rs
index 7f9d36618..54acf7847 100644
--- a/crates/ra_syntax/src/syntax_error.rs
+++ b/crates/ra_syntax/src/syntax_error.rs
@@ -1,209 +1,44 @@
1//! FIXME: write short doc here 1//! See docs for `SyntaxError`.
2 2
3use std::fmt; 3use std::fmt;
4 4
5use ra_parser::ParseError; 5use crate::{TextRange, TextUnit};
6
7use crate::{validation::EscapeError, TextRange, TextUnit, TokenizeError};
8 6
7/// Represents the result of unsuccessful tokenization, parsing
8/// or tree validation.
9#[derive(Debug, Clone, PartialEq, Eq, Hash)] 9#[derive(Debug, Clone, PartialEq, Eq, Hash)]
10pub struct SyntaxError { 10pub struct SyntaxError(String, TextRange);
11 kind: SyntaxErrorKind, 11
12 location: Location, 12// FIXME: there was an unused SyntaxErrorKind previously (before this enum was removed)
13} 13// It was introduced in this PR: https://github.com/rust-analyzer/rust-analyzer/pull/846/files#diff-827da9b03b8f9faa1bade5cdd44d5dafR95
14 14// but it was not removed by a mistake.
15// FIXME: Location should be just `Location(TextRange)` 15//
16// TextUnit enum member just unnecessarily compicates things, 16// So, we need to find a place where to stick validation for attributes in match clauses.
17// we should'n treat it specially, it just as a `TextRange { start: x, end: x + 1 }` 17// Code before refactor:
18// see `location_to_range()` in ra_ide/src/diagnostics 18// InvalidMatchInnerAttr => {
19#[derive(Clone, PartialEq, Eq, Hash)] 19// write!(f, "Inner attributes are only allowed directly after the opening brace of the match expression")
20pub enum Location { 20// }
21 Offset(TextUnit),
22 Range(TextRange),
23}
24
25impl From<TextUnit> for Location {
26 fn from(offset: TextUnit) -> Location {
27 Location::Offset(offset)
28 }
29}
30
31impl From<TextRange> for Location {
32 fn from(range: TextRange) -> Location {
33 Location::Range(range)
34 }
35}
36
37impl fmt::Debug for Location {
38 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
39 match self {
40 Location::Offset(it) => fmt::Debug::fmt(it, f),
41 Location::Range(it) => fmt::Debug::fmt(it, f),
42 }
43 }
44}
45 21
46impl SyntaxError { 22impl SyntaxError {
47 pub fn new<L: Into<Location>>(kind: SyntaxErrorKind, loc: L) -> SyntaxError { 23 pub fn new(message: impl Into<String>, range: TextRange) -> Self {
48 SyntaxError { kind, location: loc.into() } 24 Self(message.into(), range)
49 } 25 }
50 26 pub fn new_at_offset(message: impl Into<String>, offset: TextUnit) -> Self {
51 pub fn kind(&self) -> SyntaxErrorKind { 27 Self(message.into(), TextRange::offset_len(offset, 0.into()))
52 self.kind.clone()
53 } 28 }
54 29
55 pub fn location(&self) -> Location { 30 pub fn range(&self) -> TextRange {
56 self.location.clone() 31 self.1
57 } 32 }
58 33
59 pub fn offset(&self) -> TextUnit { 34 pub fn with_range(mut self, range: TextRange) -> Self {
60 match self.location { 35 self.1 = range;
61 Location::Offset(offset) => offset,
62 Location::Range(range) => range.start(),
63 }
64 }
65
66 pub fn add_offset(mut self, plus_offset: TextUnit, minus_offset: TextUnit) -> SyntaxError {
67 self.location = match self.location {
68 Location::Range(range) => Location::Range(range + plus_offset - minus_offset),
69 Location::Offset(offset) => Location::Offset(offset + plus_offset - minus_offset),
70 };
71
72 self 36 self
73 } 37 }
74
75 pub fn debug_dump(&self, acc: &mut impl fmt::Write) {
76 writeln!(acc, "error {:?}: {}", self.location(), self.kind()).unwrap();
77 }
78} 38}
79 39
80impl fmt::Display for SyntaxError { 40impl fmt::Display for SyntaxError {
81 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 41 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
82 self.kind.fmt(f) 42 self.0.fmt(f)
83 }
84}
85
86#[derive(Debug, Clone, PartialEq, Eq, Hash)]
87pub enum SyntaxErrorKind {
88 ParseError(ParseError),
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(...)`
94 InvalidBlockAttr,
95 InvalidMatchInnerAttr,
96 InvalidTupleIndexFormat,
97 VisibilityNotAllowed,
98 InclusiveRangeMissingEnd,
99}
100
101impl fmt::Display for SyntaxErrorKind {
102 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
103 use self::SyntaxErrorKind::*;
104 match self {
105 InvalidBlockAttr => {
106 write!(f, "A block in this position cannot accept inner attributes")
107 }
108 InvalidMatchInnerAttr => {
109 write!(f, "Inner attributes are only allowed directly after the opening brace of the match expression")
110 }
111 InvalidTupleIndexFormat => {
112 write!(f, "Tuple (struct) field access is only allowed through decimal integers with no underscores or suffix")
113 }
114 ParseError(msg) => write!(f, "{}", msg.0),
115 EscapeError(err) => write!(f, "{}", err),
116 TokenizeError(err) => write!(f, "{}", err),
117 VisibilityNotAllowed => {
118 write!(f, "unnecessary visibility qualifier")
119 }
120 InclusiveRangeMissingEnd => {
121 write!(f, "An inclusive range must have an end expression")
122 }
123 }
124 }
125}
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
172impl fmt::Display for EscapeError {
173 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
174 let msg = match self {
175 EscapeError::ZeroChars => "Empty literal",
176 EscapeError::MoreThanOneChar => "Literal should be one character long",
177 EscapeError::LoneSlash => "Character must be escaped: '\\'",
178 EscapeError::InvalidEscape => "Invalid escape sequence",
179 EscapeError::BareCarriageReturn => "Character must be escaped: '\r'",
180 EscapeError::EscapeOnlyChar => "Character must be escaped",
181 EscapeError::TooShortHexEscape => "Escape sequence should have two digits",
182 EscapeError::InvalidCharInHexEscape => "Escape sequence should be a hexadecimal number",
183 EscapeError::OutOfRangeHexEscape => "Escape sequence should be ASCII",
184 EscapeError::NoBraceInUnicodeEscape => "Invalid escape sequence",
185 EscapeError::InvalidCharInUnicodeEscape => "Invalid escape sequence",
186 EscapeError::EmptyUnicodeEscape => "Invalid escape sequence",
187 EscapeError::UnclosedUnicodeEscape => "Missing '}'",
188 EscapeError::LeadingUnderscoreUnicodeEscape => "Invalid escape sequence",
189 EscapeError::OverlongUnicodeEscape => {
190 "Unicode escape sequence should have at most 6 digits"
191 }
192 EscapeError::LoneSurrogateUnicodeEscape => {
193 "Unicode escape code should not be a surrogate"
194 }
195 EscapeError::OutOfRangeUnicodeEscape => {
196 "Unicode escape code should be at most 0x10FFFF"
197 }
198 EscapeError::UnicodeEscapeInByte => "Unicode escapes are not allowed in bytes",
199 EscapeError::NonAsciiCharInByte => "Non ASCII characters are not allowed in bytes",
200 };
201 write!(f, "{}", msg)
202 }
203}
204
205impl From<EscapeError> for SyntaxErrorKind {
206 fn from(err: EscapeError) -> Self {
207 SyntaxErrorKind::EscapeError(err)
208 } 43 }
209} 44}
diff --git a/crates/ra_syntax/src/syntax_node.rs b/crates/ra_syntax/src/syntax_node.rs
index 7c2b18af3..4e3a1460d 100644
--- a/crates/ra_syntax/src/syntax_node.rs
+++ b/crates/ra_syntax/src/syntax_node.rs
@@ -6,13 +6,9 @@
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//! module just wraps its API. 7//! module just wraps its API.
8 8
9use ra_parser::ParseError;
10use rowan::{GreenNodeBuilder, Language}; 9use rowan::{GreenNodeBuilder, Language};
11 10
12use crate::{ 11use crate::{Parse, SmolStr, SyntaxError, SyntaxKind, TextUnit};
13 syntax_error::{SyntaxError, SyntaxErrorKind},
14 Parse, SmolStr, SyntaxKind, TextUnit,
15};
16 12
17pub(crate) use rowan::{GreenNode, GreenToken}; 13pub(crate) use rowan::{GreenNode, GreenToken};
18 14
@@ -73,8 +69,7 @@ impl SyntaxTreeBuilder {
73 self.inner.finish_node() 69 self.inner.finish_node()
74 } 70 }
75 71
76 pub fn error(&mut self, error: ParseError, text_pos: TextUnit) { 72 pub fn error(&mut self, error: ra_parser::ParseError, text_pos: TextUnit) {
77 let error = SyntaxError::new(SyntaxErrorKind::ParseError(error), text_pos); 73 self.errors.push(SyntaxError::new_at_offset(error.0, text_pos))
78 self.errors.push(error)
79 } 74 }
80} 75}
diff --git a/crates/ra_syntax/src/tests.rs b/crates/ra_syntax/src/tests.rs
index fb22b9e54..912e6aec0 100644
--- a/crates/ra_syntax/src/tests.rs
+++ b/crates/ra_syntax/src/tests.rs
@@ -5,7 +5,7 @@ use std::{
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, tokenize, Location, SourceFile, SyntaxError, TextRange, Token}; 8use crate::{fuzz, tokenize, SourceFile, SyntaxError, Token};
9 9
10#[test] 10#[test]
11fn lexer_tests() { 11fn lexer_tests() {
@@ -128,25 +128,8 @@ fn dump_tokens_and_errors(tokens: &[Token], errors: &[SyntaxError], text: &str)
128 writeln!(acc, "{:?} {} {:?}", token.kind, token_len, token_text).unwrap(); 128 writeln!(acc, "{:?} {} {:?}", token.kind, token_len, token_text).unwrap();
129 } 129 }
130 for err in errors { 130 for err in errors {
131 let err_range = location_to_range(err.location()); 131 writeln!(acc, "> error{:?} token({:?}) msg({})", err.range(), &text[err.range()], err)
132 writeln!( 132 .unwrap();
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 }
151 } 133 }
134 acc
152} 135}
diff --git a/crates/ra_syntax/src/validation.rs b/crates/ra_syntax/src/validation.rs
index 8a5f0e4b7..863859dca 100644
--- a/crates/ra_syntax/src/validation.rs
+++ b/crates/ra_syntax/src/validation.rs
@@ -5,92 +5,76 @@ mod block;
5use rustc_lexer::unescape; 5use rustc_lexer::unescape;
6 6
7use crate::{ 7use crate::{
8 ast, match_ast, AstNode, SyntaxError, SyntaxErrorKind, 8 ast, match_ast, AstNode, SyntaxError,
9 SyntaxKind::{BYTE, BYTE_STRING, CHAR, CONST_DEF, FN_DEF, INT_NUMBER, STRING, TYPE_ALIAS_DEF}, 9 SyntaxKind::{BYTE, BYTE_STRING, CHAR, CONST_DEF, FN_DEF, INT_NUMBER, STRING, TYPE_ALIAS_DEF},
10 SyntaxNode, SyntaxToken, TextUnit, T, 10 SyntaxNode, SyntaxToken, TextUnit, T,
11}; 11};
12 12
13#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] 13fn rustc_unescape_error_to_string(err: unescape::EscapeError) -> &'static str {
14pub enum EscapeError { 14 use unescape::EscapeError as EE;
15 ZeroChars,
16 MoreThanOneChar,
17 LoneSlash,
18 InvalidEscape,
19 BareCarriageReturn,
20 EscapeOnlyChar,
21 TooShortHexEscape,
22 InvalidCharInHexEscape,
23 OutOfRangeHexEscape,
24 NoBraceInUnicodeEscape,
25 InvalidCharInUnicodeEscape,
26 EmptyUnicodeEscape,
27 UnclosedUnicodeEscape,
28 LeadingUnderscoreUnicodeEscape,
29 OverlongUnicodeEscape,
30 LoneSurrogateUnicodeEscape,
31 OutOfRangeUnicodeEscape,
32 UnicodeEscapeInByte,
33 NonAsciiCharInByte,
34}
35 15
36impl From<rustc_lexer::unescape::EscapeError> for EscapeError { 16 #[rustfmt::skip]
37 fn from(err: rustc_lexer::unescape::EscapeError) -> Self { 17 let err_message = match err {
38 match err { 18 EE::ZeroChars => {
39 rustc_lexer::unescape::EscapeError::ZeroChars => EscapeError::ZeroChars, 19 "Literal must not be empty"
40 rustc_lexer::unescape::EscapeError::MoreThanOneChar => EscapeError::MoreThanOneChar,
41 rustc_lexer::unescape::EscapeError::LoneSlash => EscapeError::LoneSlash,
42 rustc_lexer::unescape::EscapeError::InvalidEscape => EscapeError::InvalidEscape,
43 rustc_lexer::unescape::EscapeError::BareCarriageReturn
44 | rustc_lexer::unescape::EscapeError::BareCarriageReturnInRawString => {
45 EscapeError::BareCarriageReturn
46 }
47 rustc_lexer::unescape::EscapeError::EscapeOnlyChar => EscapeError::EscapeOnlyChar,
48 rustc_lexer::unescape::EscapeError::TooShortHexEscape => EscapeError::TooShortHexEscape,
49 rustc_lexer::unescape::EscapeError::InvalidCharInHexEscape => {
50 EscapeError::InvalidCharInHexEscape
51 }
52 rustc_lexer::unescape::EscapeError::OutOfRangeHexEscape => {
53 EscapeError::OutOfRangeHexEscape
54 }
55 rustc_lexer::unescape::EscapeError::NoBraceInUnicodeEscape => {
56 EscapeError::NoBraceInUnicodeEscape
57 }
58 rustc_lexer::unescape::EscapeError::InvalidCharInUnicodeEscape => {
59 EscapeError::InvalidCharInUnicodeEscape
60 }
61 rustc_lexer::unescape::EscapeError::EmptyUnicodeEscape => {
62 EscapeError::EmptyUnicodeEscape
63 }
64 rustc_lexer::unescape::EscapeError::UnclosedUnicodeEscape => {
65 EscapeError::UnclosedUnicodeEscape
66 }
67 rustc_lexer::unescape::EscapeError::LeadingUnderscoreUnicodeEscape => {
68 EscapeError::LeadingUnderscoreUnicodeEscape
69 }
70 rustc_lexer::unescape::EscapeError::OverlongUnicodeEscape => {
71 EscapeError::OverlongUnicodeEscape
72 }
73 rustc_lexer::unescape::EscapeError::LoneSurrogateUnicodeEscape => {
74 EscapeError::LoneSurrogateUnicodeEscape
75 }
76 rustc_lexer::unescape::EscapeError::OutOfRangeUnicodeEscape => {
77 EscapeError::OutOfRangeUnicodeEscape
78 }
79 rustc_lexer::unescape::EscapeError::UnicodeEscapeInByte => {
80 EscapeError::UnicodeEscapeInByte
81 }
82 rustc_lexer::unescape::EscapeError::NonAsciiCharInByte
83 | rustc_lexer::unescape::EscapeError::NonAsciiCharInByteString => {
84 EscapeError::NonAsciiCharInByte
85 }
86 } 20 }
87 } 21 EE::MoreThanOneChar => {
88} 22 "Literal must be one character long"
23 }
24 EE::LoneSlash => {
25 "Character must be escaped: `\\`"
26 }
27 EE::InvalidEscape => {
28 "Invalid escape"
29 }
30 EE::BareCarriageReturn | EE::BareCarriageReturnInRawString => {
31 "Character must be escaped: `\r`"
32 }
33 EE::EscapeOnlyChar => {
34 "Escape character `\\` must be escaped itself"
35 }
36 EE::TooShortHexEscape => {
37 "ASCII hex escape code must have exactly two digits"
38 }
39 EE::InvalidCharInHexEscape => {
40 "ASCII hex escape code must contain only hex characters"
41 }
42 EE::OutOfRangeHexEscape => {
43 "ASCII hex escape code must be at most 0x7F"
44 }
45 EE::NoBraceInUnicodeEscape => {
46 "Missing `{` to begin the unicode escape"
47 }
48 EE::InvalidCharInUnicodeEscape => {
49 "Unicode escape must contain only hex characters and underscores"
50 }
51 EE::EmptyUnicodeEscape => {
52 "Unicode escape must not be empty"
53 }
54 EE::UnclosedUnicodeEscape => {
55 "Missing '}' to terminate the unicode escape"
56 }
57 EE::LeadingUnderscoreUnicodeEscape => {
58 "Unicode escape code must not begin with an underscore"
59 }
60 EE::OverlongUnicodeEscape => {
61 "Unicode escape code must have at most 6 digits"
62 }
63 EE::LoneSurrogateUnicodeEscape => {
64 "Unicode escape code must not be a surrogate"
65 }
66 EE::OutOfRangeUnicodeEscape => {
67 "Unicode escape code must be at most 0x10FFFF"
68 }
69 EE::UnicodeEscapeInByte => {
70 "Byte literals must not contain unicode escapes"
71 }
72 EE::NonAsciiCharInByte | EE::NonAsciiCharInByteString => {
73 "Byte literals must not contain non-ASCII characters"
74 }
75 };
89 76
90impl From<rustc_lexer::unescape::EscapeError> for SyntaxErrorKind { 77 err_message
91 fn from(err: rustc_lexer::unescape::EscapeError) -> Self {
92 SyntaxErrorKind::EscapeError(err.into())
93 }
94} 78}
95 79
96pub(crate) fn validate(root: &SyntaxNode) -> Vec<SyntaxError> { 80pub(crate) fn validate(root: &SyntaxNode) -> Vec<SyntaxError> {
@@ -118,6 +102,7 @@ pub(crate) fn validate(root: &SyntaxNode) -> Vec<SyntaxError> {
118} 102}
119 103
120fn validate_literal(literal: ast::Literal, acc: &mut Vec<SyntaxError>) { 104fn validate_literal(literal: ast::Literal, acc: &mut Vec<SyntaxError>) {
105 // FIXME: move this function to outer scope (https://github.com/rust-analyzer/rust-analyzer/pull/2834#discussion_r366196658)
121 fn unquote(text: &str, prefix_len: usize, end_delimiter: char) -> Option<&str> { 106 fn unquote(text: &str, prefix_len: usize, end_delimiter: char) -> Option<&str> {
122 text.rfind(end_delimiter).and_then(|end| text.get(prefix_len..end)) 107 text.rfind(end_delimiter).and_then(|end| text.get(prefix_len..end))
123 } 108 }
@@ -125,9 +110,10 @@ fn validate_literal(literal: ast::Literal, acc: &mut Vec<SyntaxError>) {
125 let token = literal.token(); 110 let token = literal.token();
126 let text = token.text().as_str(); 111 let text = token.text().as_str();
127 112
113 // FIXME: lift this lambda refactor to `fn` (https://github.com/rust-analyzer/rust-analyzer/pull/2834#discussion_r366199205)
128 let mut push_err = |prefix_len, (off, err): (usize, unescape::EscapeError)| { 114 let mut push_err = |prefix_len, (off, err): (usize, unescape::EscapeError)| {
129 let off = token.text_range().start() + TextUnit::from_usize(off + prefix_len); 115 let off = token.text_range().start() + TextUnit::from_usize(off + prefix_len);
130 acc.push(SyntaxError::new(err.into(), off)); 116 acc.push(SyntaxError::new_at_offset(rustc_unescape_error_to_string(err), off));
131 }; 117 };
132 118
133 match token.kind() { 119 match token.kind() {
@@ -195,7 +181,8 @@ fn validate_numeric_name(name_ref: Option<ast::NameRef>, errors: &mut Vec<Syntax
195 if let Some(int_token) = int_token(name_ref) { 181 if let Some(int_token) = int_token(name_ref) {
196 if int_token.text().chars().any(|c| !c.is_digit(10)) { 182 if int_token.text().chars().any(|c| !c.is_digit(10)) {
197 errors.push(SyntaxError::new( 183 errors.push(SyntaxError::new(
198 SyntaxErrorKind::InvalidTupleIndexFormat, 184 "Tuple (struct) field access is only allowed through \
185 decimal integers with no underscores or suffix",
199 int_token.text_range(), 186 int_token.text_range(),
200 )); 187 ));
201 } 188 }
@@ -215,21 +202,21 @@ fn validate_visibility(vis: ast::Visibility, errors: &mut Vec<SyntaxError>) {
215 FN_DEF | CONST_DEF | TYPE_ALIAS_DEF => (), 202 FN_DEF | CONST_DEF | TYPE_ALIAS_DEF => (),
216 _ => return, 203 _ => return,
217 } 204 }
205
218 let impl_block = match parent.parent().and_then(|it| it.parent()).and_then(ast::ImplBlock::cast) 206 let impl_block = match parent.parent().and_then(|it| it.parent()).and_then(ast::ImplBlock::cast)
219 { 207 {
220 Some(it) => it, 208 Some(it) => it,
221 None => return, 209 None => return,
222 }; 210 };
223 if impl_block.target_trait().is_some() { 211 if impl_block.target_trait().is_some() {
224 errors 212 errors.push(SyntaxError::new("Unnecessary visibility qualifier", vis.syntax.text_range()));
225 .push(SyntaxError::new(SyntaxErrorKind::VisibilityNotAllowed, vis.syntax.text_range()))
226 } 213 }
227} 214}
228 215
229fn validate_range_expr(expr: ast::RangeExpr, errors: &mut Vec<SyntaxError>) { 216fn validate_range_expr(expr: ast::RangeExpr, errors: &mut Vec<SyntaxError>) {
230 if expr.op_kind() == Some(ast::RangeOp::Inclusive) && expr.end().is_none() { 217 if expr.op_kind() == Some(ast::RangeOp::Inclusive) && expr.end().is_none() {
231 errors.push(SyntaxError::new( 218 errors.push(SyntaxError::new(
232 SyntaxErrorKind::InclusiveRangeMissingEnd, 219 "An inclusive range must have an end expression",
233 expr.syntax().text_range(), 220 expr.syntax().text_range(),
234 )); 221 ));
235 } 222 }
diff --git a/crates/ra_syntax/src/validation/block.rs b/crates/ra_syntax/src/validation/block.rs
index c85bbc1f4..8e962ab5b 100644
--- a/crates/ra_syntax/src/validation/block.rs
+++ b/crates/ra_syntax/src/validation/block.rs
@@ -1,9 +1,8 @@
1//! FIXME: write short doc here 1//! Logic for validating block expressions i.e. `ast::BlockExpr`.
2 2
3use crate::{ 3use crate::{
4 ast::{self, AstNode, AttrsOwner}, 4 ast::{self, AstNode, AttrsOwner},
5 SyntaxError, 5 SyntaxError,
6 SyntaxErrorKind::*,
7 SyntaxKind::*, 6 SyntaxKind::*,
8}; 7};
9 8
@@ -15,10 +14,11 @@ pub(crate) fn validate_block_expr(expr: ast::BlockExpr, errors: &mut Vec<SyntaxE
15 } 14 }
16 } 15 }
17 if let Some(block) = expr.block() { 16 if let Some(block) = expr.block() {
18 errors.extend( 17 errors.extend(block.attrs().map(|attr| {
19 block 18 SyntaxError::new(
20 .attrs() 19 "A block in this position cannot accept inner attributes",
21 .map(|attr| SyntaxError::new(InvalidBlockAttr, attr.syntax().text_range())), 20 attr.syntax().text_range(),
22 ) 21 )
22 }))
23 } 23 }
24} 24}
diff --git a/crates/ra_syntax/test_data/parser/err/0000_struct_field_missing_comma.txt b/crates/ra_syntax/test_data/parser/err/0000_struct_field_missing_comma.txt
index dc143945a..edcd936b0 100644
--- a/crates/ra_syntax/test_data/parser/err/0000_struct_field_missing_comma.txt
+++ b/crates/ra_syntax/test_data/parser/err/0000_struct_field_missing_comma.txt
@@ -31,4 +31,4 @@ SOURCE_FILE@[0; 34)
31 IDENT@[29; 32) "u32" 31 IDENT@[29; 32) "u32"
32 WHITESPACE@[32; 33) "\n" 32 WHITESPACE@[32; 33) "\n"
33 R_CURLY@[33; 34) "}" 33 R_CURLY@[33; 34) "}"
34error 21: expected COMMA 34error [21; 21): expected COMMA
diff --git a/crates/ra_syntax/test_data/parser/err/0001_item_recovery_in_file.txt b/crates/ra_syntax/test_data/parser/err/0001_item_recovery_in_file.txt
index 181bcdb9e..2d653715e 100644
--- a/crates/ra_syntax/test_data/parser/err/0001_item_recovery_in_file.txt
+++ b/crates/ra_syntax/test_data/parser/err/0001_item_recovery_in_file.txt
@@ -14,5 +14,5 @@ SOURCE_FILE@[0; 21)
14 RECORD_FIELD_DEF_LIST@[19; 21) 14 RECORD_FIELD_DEF_LIST@[19; 21)
15 L_CURLY@[19; 20) "{" 15 L_CURLY@[19; 20) "{"
16 R_CURLY@[20; 21) "}" 16 R_CURLY@[20; 21) "}"
17error 0: expected an item 17error [0; 0): expected an item
18error 3: expected an item 18error [3; 3): expected an item
diff --git a/crates/ra_syntax/test_data/parser/err/0002_duplicate_shebang.txt b/crates/ra_syntax/test_data/parser/err/0002_duplicate_shebang.txt
index bdb5fa6c5..002680583 100644
--- a/crates/ra_syntax/test_data/parser/err/0002_duplicate_shebang.txt
+++ b/crates/ra_syntax/test_data/parser/err/0002_duplicate_shebang.txt
@@ -26,14 +26,14 @@ SOURCE_FILE@[0; 42)
26 NAME@[36; 41) 26 NAME@[36; 41)
27 IDENT@[36; 41) "rusti" 27 IDENT@[36; 41) "rusti"
28 WHITESPACE@[41; 42) "\n" 28 WHITESPACE@[41; 42) "\n"
29error 23: expected `[` 29error [23; 23): expected `[`
30error 23: expected an item 30error [23; 23): expected an item
31error 27: expected one of `*`, `::`, `{`, `self`, `super` or an identifier 31error [27; 27): expected one of `*`, `::`, `{`, `self`, `super` or an identifier
32error 28: expected SEMI 32error [28; 28): expected SEMI
33error 31: expected EXCL 33error [31; 31): expected EXCL
34error 31: expected `{`, `[`, `(` 34error [31; 31): expected `{`, `[`, `(`
35error 31: expected SEMI 35error [31; 31): expected SEMI
36error 31: expected an item 36error [31; 31): expected an item
37error 35: expected EXCL 37error [35; 35): expected EXCL
38error 41: expected `{`, `[`, `(` 38error [41; 41): expected `{`, `[`, `(`
39error 41: expected SEMI 39error [41; 41): expected SEMI
diff --git a/crates/ra_syntax/test_data/parser/err/0003_C++_semicolon.txt b/crates/ra_syntax/test_data/parser/err/0003_C++_semicolon.txt
index 58d005902..8039a8913 100644
--- a/crates/ra_syntax/test_data/parser/err/0003_C++_semicolon.txt
+++ b/crates/ra_syntax/test_data/parser/err/0003_C++_semicolon.txt
@@ -35,5 +35,5 @@ SOURCE_FILE@[0; 40)
35 R_CURLY@[38; 39) "}" 35 R_CURLY@[38; 39) "}"
36 ERROR@[39; 40) 36 ERROR@[39; 40)
37 SEMI@[39; 40) ";" 37 SEMI@[39; 40) ";"
38error 39: expected item, found `;` 38error [39; 39): expected item, found `;`
39consider removing this semicolon 39consider removing this semicolon
diff --git a/crates/ra_syntax/test_data/parser/err/0004_use_path_bad_segment.txt b/crates/ra_syntax/test_data/parser/err/0004_use_path_bad_segment.txt
index 5210a884d..5f6e10986 100644
--- a/crates/ra_syntax/test_data/parser/err/0004_use_path_bad_segment.txt
+++ b/crates/ra_syntax/test_data/parser/err/0004_use_path_bad_segment.txt
@@ -13,4 +13,4 @@ SOURCE_FILE@[0; 12)
13 ERROR@[9; 11) 13 ERROR@[9; 11)
14 INT_NUMBER@[9; 11) "92" 14 INT_NUMBER@[9; 11) "92"
15 SEMI@[11; 12) ";" 15 SEMI@[11; 12) ";"
16error 9: expected identifier 16error [9; 9): expected identifier
diff --git a/crates/ra_syntax/test_data/parser/err/0005_attribute_recover.txt b/crates/ra_syntax/test_data/parser/err/0005_attribute_recover.txt
index 7c1a23170..cc11421a9 100644
--- a/crates/ra_syntax/test_data/parser/err/0005_attribute_recover.txt
+++ b/crates/ra_syntax/test_data/parser/err/0005_attribute_recover.txt
@@ -55,6 +55,6 @@ SOURCE_FILE@[0; 54)
55 WHITESPACE@[51; 52) "\n" 55 WHITESPACE@[51; 52) "\n"
56 R_CURLY@[52; 53) "}" 56 R_CURLY@[52; 53) "}"
57 WHITESPACE@[53; 54) "\n" 57 WHITESPACE@[53; 54) "\n"
58error 53: expected R_PAREN 58error [53; 53): expected R_PAREN
59error 53: expected `]` 59error [53; 53): expected `]`
60error 53: expected an item 60error [53; 53): expected an item
diff --git a/crates/ra_syntax/test_data/parser/err/0006_named_field_recovery.txt b/crates/ra_syntax/test_data/parser/err/0006_named_field_recovery.txt
index 5f5198b31..84fd92862 100644
--- a/crates/ra_syntax/test_data/parser/err/0006_named_field_recovery.txt
+++ b/crates/ra_syntax/test_data/parser/err/0006_named_field_recovery.txt
@@ -64,11 +64,11 @@ SOURCE_FILE@[0; 74)
64 WHITESPACE@[71; 72) "\n" 64 WHITESPACE@[71; 72) "\n"
65 R_CURLY@[72; 73) "}" 65 R_CURLY@[72; 73) "}"
66 WHITESPACE@[73; 74) "\n" 66 WHITESPACE@[73; 74) "\n"
67error 31: expected field declaration 67error [31; 31): expected field declaration
68error 33: expected COMMA 68error [33; 33): expected COMMA
69error 38: expected field declaration 69error [38; 38): expected field declaration
70error 39: expected COMMA 70error [39; 39): expected COMMA
71error 40: expected field declaration 71error [40; 40): expected field declaration
72error 41: expected COMMA 72error [41; 41): expected COMMA
73error 42: expected field declaration 73error [42; 42): expected field declaration
74error 43: expected COMMA 74error [43; 43): expected COMMA
diff --git a/crates/ra_syntax/test_data/parser/err/0007_stray_curly_in_file.txt b/crates/ra_syntax/test_data/parser/err/0007_stray_curly_in_file.txt
index 7ae417441..1978f30fa 100644
--- a/crates/ra_syntax/test_data/parser/err/0007_stray_curly_in_file.txt
+++ b/crates/ra_syntax/test_data/parser/err/0007_stray_curly_in_file.txt
@@ -28,6 +28,6 @@ SOURCE_FILE@[0; 31)
28 ERROR@[29; 30) 28 ERROR@[29; 30)
29 R_CURLY@[29; 30) "}" 29 R_CURLY@[29; 30) "}"
30 WHITESPACE@[30; 31) "\n" 30 WHITESPACE@[30; 31) "\n"
31error 0: unmatched `}` 31error [0; 0): unmatched `}`
32error 14: unmatched `}` 32error [14; 14): unmatched `}`
33error 29: unmatched `}` 33error [29; 29): unmatched `}`
diff --git a/crates/ra_syntax/test_data/parser/err/0008_item_block_recovery.txt b/crates/ra_syntax/test_data/parser/err/0008_item_block_recovery.txt
index 1a4b40a2b..98248227d 100644
--- a/crates/ra_syntax/test_data/parser/err/0008_item_block_recovery.txt
+++ b/crates/ra_syntax/test_data/parser/err/0008_item_block_recovery.txt
@@ -76,6 +76,6 @@ SOURCE_FILE@[0; 95)
76 WHITESPACE@[92; 93) "\n" 76 WHITESPACE@[92; 93) "\n"
77 R_CURLY@[93; 94) "}" 77 R_CURLY@[93; 94) "}"
78 WHITESPACE@[94; 95) "\n" 78 WHITESPACE@[94; 95) "\n"
79error 17: expected EXCL 79error [17; 17): expected EXCL
80error 19: expected SEMI 80error [19; 19): expected SEMI
81error 20: expected an item 81error [20; 20): expected an item
diff --git a/crates/ra_syntax/test_data/parser/err/0009_broken_struct_type_parameter.txt b/crates/ra_syntax/test_data/parser/err/0009_broken_struct_type_parameter.txt
index e147d6424..ca508ac7c 100644
--- a/crates/ra_syntax/test_data/parser/err/0009_broken_struct_type_parameter.txt
+++ b/crates/ra_syntax/test_data/parser/err/0009_broken_struct_type_parameter.txt
@@ -45,14 +45,14 @@ SOURCE_FILE@[0; 43)
45 IDENT@[40; 41) "T" 45 IDENT@[40; 41) "T"
46 SEMI@[41; 42) ";" 46 SEMI@[41; 42) ";"
47 WHITESPACE@[42; 43) "\n" 47 WHITESPACE@[42; 43) "\n"
48error 9: expected type parameter 48error [9; 9): expected type parameter
49error 11: expected COMMA 49error [11; 11): expected COMMA
50error 11: expected R_ANGLE 50error [11; 11): expected R_ANGLE
51error 11: expected `;`, `{`, or `(` 51error [11; 11): expected `;`, `{`, or `(`
52error 12: expected an item 52error [12; 12): expected an item
53error 14: expected an item 53error [14; 14): expected an item
54error 15: expected an item 54error [15; 15): expected an item
55error 17: expected an item 55error [17; 17): expected an item
56error 24: expected SEMI 56error [24; 24): expected SEMI
57error 24: expected expression 57error [24; 24): expected expression
58error 25: expected SEMI 58error [25; 25): expected SEMI
diff --git a/crates/ra_syntax/test_data/parser/err/0010_unsafe_lambda_block.txt b/crates/ra_syntax/test_data/parser/err/0010_unsafe_lambda_block.txt
index b73dda5ad..e0edf6a2d 100644
--- a/crates/ra_syntax/test_data/parser/err/0010_unsafe_lambda_block.txt
+++ b/crates/ra_syntax/test_data/parser/err/0010_unsafe_lambda_block.txt
@@ -40,4 +40,4 @@ SOURCE_FILE@[0; 42)
40 WHITESPACE@[39; 40) "\n" 40 WHITESPACE@[39; 40) "\n"
41 R_CURLY@[40; 41) "}" 41 R_CURLY@[40; 41) "}"
42 WHITESPACE@[41; 42) "\n" 42 WHITESPACE@[41; 42) "\n"
43error 24: expected `{` 43error [24; 24): expected `{`
diff --git a/crates/ra_syntax/test_data/parser/err/0011_extern_struct.txt b/crates/ra_syntax/test_data/parser/err/0011_extern_struct.txt
index 381147dc0..900894dcf 100644
--- a/crates/ra_syntax/test_data/parser/err/0011_extern_struct.txt
+++ b/crates/ra_syntax/test_data/parser/err/0011_extern_struct.txt
@@ -10,4 +10,4 @@ SOURCE_FILE@[0; 19)
10 IDENT@[14; 17) "Foo" 10 IDENT@[14; 17) "Foo"
11 SEMI@[17; 18) ";" 11 SEMI@[17; 18) ";"
12 WHITESPACE@[18; 19) "\n" 12 WHITESPACE@[18; 19) "\n"
13error 6: expected existential, fn, trait or impl 13error [6; 6): expected existential, fn, trait or impl
diff --git a/crates/ra_syntax/test_data/parser/err/0013_invalid_type.txt b/crates/ra_syntax/test_data/parser/err/0013_invalid_type.txt
index 4907bac6d..7a934cf66 100644
--- a/crates/ra_syntax/test_data/parser/err/0013_invalid_type.txt
+++ b/crates/ra_syntax/test_data/parser/err/0013_invalid_type.txt
@@ -69,21 +69,21 @@ SOURCE_FILE@[0; 86)
69 ERROR@[83; 84) 69 ERROR@[83; 84)
70 SEMI@[83; 84) ";" 70 SEMI@[83; 84) ";"
71 WHITESPACE@[84; 86) "\n\n" 71 WHITESPACE@[84; 86) "\n\n"
72error 67: expected type 72error [67; 67): expected type
73error 68: expected COMMA 73error [68; 68): expected COMMA
74error 68: expected R_ANGLE 74error [68; 68): expected R_ANGLE
75error 68: expected COMMA 75error [68; 68): expected COMMA
76error 68: expected R_ANGLE 76error [68; 68): expected R_ANGLE
77error 68: expected COMMA 77error [68; 68): expected COMMA
78error 68: expected R_ANGLE 78error [68; 68): expected R_ANGLE
79error 68: expected COMMA 79error [68; 68): expected COMMA
80error 72: expected COMMA 80error [72; 72): expected COMMA
81error 72: expected a type 81error [72; 72): expected a type
82error 72: expected R_PAREN 82error [72; 72): expected R_PAREN
83error 72: expected SEMI 83error [72; 72): expected SEMI
84error 72: expected an item 84error [72; 72): expected an item
85error 73: expected an item 85error [73; 73): expected an item
86error 79: expected an item 86error [79; 79): expected an item
87error 80: expected an item 87error [80; 80): expected an item
88error 82: expected an item 88error [82; 82): expected an item
89error 83: expected an item 89error [83; 83): expected an item
diff --git a/crates/ra_syntax/test_data/parser/err/0014_where_no_bounds.txt b/crates/ra_syntax/test_data/parser/err/0014_where_no_bounds.txt
index 0ba17cf8d..a25d641b8 100644
--- a/crates/ra_syntax/test_data/parser/err/0014_where_no_bounds.txt
+++ b/crates/ra_syntax/test_data/parser/err/0014_where_no_bounds.txt
@@ -29,4 +29,4 @@ SOURCE_FILE@[0; 23)
29 L_CURLY@[20; 21) "{" 29 L_CURLY@[20; 21) "{"
30 R_CURLY@[21; 22) "}" 30 R_CURLY@[21; 22) "}"
31 WHITESPACE@[22; 23) "\n" 31 WHITESPACE@[22; 23) "\n"
32error 19: expected colon 32error [19; 19): expected colon
diff --git a/crates/ra_syntax/test_data/parser/err/0015_curly_in_params.txt b/crates/ra_syntax/test_data/parser/err/0015_curly_in_params.txt
index 23ca0c446..36b848be3 100644
--- a/crates/ra_syntax/test_data/parser/err/0015_curly_in_params.txt
+++ b/crates/ra_syntax/test_data/parser/err/0015_curly_in_params.txt
@@ -16,9 +16,9 @@ SOURCE_FILE@[0; 14)
16 WHITESPACE@[11; 12) "\n" 16 WHITESPACE@[11; 12) "\n"
17 R_CURLY@[12; 13) "}" 17 R_CURLY@[12; 13) "}"
18 WHITESPACE@[13; 14) "\n" 18 WHITESPACE@[13; 14) "\n"
19error 7: expected value parameter 19error [7; 7): expected value parameter
20error 7: expected R_PAREN 20error [7; 7): expected R_PAREN
21error 7: expected a block 21error [7; 7): expected a block
22error 7: unmatched `}` 22error [7; 7): unmatched `}`
23error 8: expected an item 23error [8; 8): expected an item
24error 10: expected an item 24error [10; 10): expected an item
diff --git a/crates/ra_syntax/test_data/parser/err/0016_missing_semi.txt b/crates/ra_syntax/test_data/parser/err/0016_missing_semi.txt
index bc5be6a66..6343580e0 100644
--- a/crates/ra_syntax/test_data/parser/err/0016_missing_semi.txt
+++ b/crates/ra_syntax/test_data/parser/err/0016_missing_semi.txt
@@ -41,4 +41,4 @@ SOURCE_FILE@[0; 56)
41 WHITESPACE@[53; 54) "\n" 41 WHITESPACE@[53; 54) "\n"
42 R_CURLY@[54; 55) "}" 42 R_CURLY@[54; 55) "}"
43 WHITESPACE@[55; 56) "\n" 43 WHITESPACE@[55; 56) "\n"
44error 38: expected SEMI 44error [38; 38): expected SEMI
diff --git a/crates/ra_syntax/test_data/parser/err/0017_incomplete_binexpr.txt b/crates/ra_syntax/test_data/parser/err/0017_incomplete_binexpr.txt
index 9033a5b38..59480e999 100644
--- a/crates/ra_syntax/test_data/parser/err/0017_incomplete_binexpr.txt
+++ b/crates/ra_syntax/test_data/parser/err/0017_incomplete_binexpr.txt
@@ -44,4 +44,4 @@ SOURCE_FILE@[0; 47)
44 WHITESPACE@[44; 45) "\n" 44 WHITESPACE@[44; 45) "\n"
45 R_CURLY@[45; 46) "}" 45 R_CURLY@[45; 46) "}"
46 WHITESPACE@[46; 47) "\n" 46 WHITESPACE@[46; 47) "\n"
47error 44: expected expression 47error [44; 44): expected expression
diff --git a/crates/ra_syntax/test_data/parser/err/0018_incomplete_fn.txt b/crates/ra_syntax/test_data/parser/err/0018_incomplete_fn.txt
index d12f4c99b..b9e60f6c1 100644
--- a/crates/ra_syntax/test_data/parser/err/0018_incomplete_fn.txt
+++ b/crates/ra_syntax/test_data/parser/err/0018_incomplete_fn.txt
@@ -125,8 +125,8 @@ SOURCE_FILE@[0; 183)
125 WHITESPACE@[180; 181) "\n" 125 WHITESPACE@[180; 181) "\n"
126 R_CURLY@[181; 182) "}" 126 R_CURLY@[181; 182) "}"
127 WHITESPACE@[182; 183) "\n" 127 WHITESPACE@[182; 183) "\n"
128error 34: expected pattern 128error [34; 34): expected pattern
129error 34: expected COLON 129error [34; 34): expected COLON
130error 34: expected type 130error [34; 34): expected type
131error 180: expected function arguments 131error [180; 180): expected function arguments
132error 180: expected a block 132error [180; 180): expected a block
diff --git a/crates/ra_syntax/test_data/parser/err/0019_let_recover.txt b/crates/ra_syntax/test_data/parser/err/0019_let_recover.txt
index cc3578e54..97e91a94f 100644
--- a/crates/ra_syntax/test_data/parser/err/0019_let_recover.txt
+++ b/crates/ra_syntax/test_data/parser/err/0019_let_recover.txt
@@ -95,13 +95,13 @@ SOURCE_FILE@[0; 139)
95 WHITESPACE@[136; 137) "\n" 95 WHITESPACE@[136; 137) "\n"
96 R_CURLY@[137; 138) "}" 96 R_CURLY@[137; 138) "}"
97 WHITESPACE@[138; 139) "\n" 97 WHITESPACE@[138; 139) "\n"
98error 24: expected expression 98error [24; 24): expected expression
99error 24: expected SEMI 99error [24; 24): expected SEMI
100error 49: expected pattern 100error [49; 49): expected pattern
101error 49: expected SEMI 101error [49; 49): expected SEMI
102error 75: expected pattern 102error [75; 75): expected pattern
103error 75: expected SEMI 103error [75; 75): expected SEMI
104error 98: expected pattern 104error [98; 98): expected pattern
105error 98: expected SEMI 105error [98; 98): expected SEMI
106error 124: expected pattern 106error [124; 124): expected pattern
107error 124: expected SEMI 107error [124; 124): expected SEMI
diff --git a/crates/ra_syntax/test_data/parser/err/0020_fn_recover.txt b/crates/ra_syntax/test_data/parser/err/0020_fn_recover.txt
index 70727d059..c11dc23f5 100644
--- a/crates/ra_syntax/test_data/parser/err/0020_fn_recover.txt
+++ b/crates/ra_syntax/test_data/parser/err/0020_fn_recover.txt
@@ -16,6 +16,6 @@ SOURCE_FILE@[0; 16)
16 L_CURLY@[13; 14) "{" 16 L_CURLY@[13; 14) "{"
17 R_CURLY@[14; 15) "}" 17 R_CURLY@[14; 15) "}"
18 WHITESPACE@[15; 16) "\n" 18 WHITESPACE@[15; 16) "\n"
19error 2: expected a name 19error [2; 2): expected a name
20error 2: expected function arguments 20error [2; 2): expected function arguments
21error 2: expected a block 21error [2; 2): expected a block
diff --git a/crates/ra_syntax/test_data/parser/err/0021_incomplete_param.txt b/crates/ra_syntax/test_data/parser/err/0021_incomplete_param.txt
index 333782480..ae04122d8 100644
--- a/crates/ra_syntax/test_data/parser/err/0021_incomplete_param.txt
+++ b/crates/ra_syntax/test_data/parser/err/0021_incomplete_param.txt
@@ -31,5 +31,5 @@ SOURCE_FILE@[0; 22)
31 WHITESPACE@[19; 20) "\n" 31 WHITESPACE@[19; 20) "\n"
32 R_CURLY@[20; 21) "}" 32 R_CURLY@[20; 21) "}"
33 WHITESPACE@[21; 22) "\n" 33 WHITESPACE@[21; 22) "\n"
34error 16: expected COLON 34error [16; 16): expected COLON
35error 16: expected type 35error [16; 16): expected type
diff --git a/crates/ra_syntax/test_data/parser/err/0022_bad_exprs.txt b/crates/ra_syntax/test_data/parser/err/0022_bad_exprs.txt
index cb45eb2fc..bb87022b0 100644
--- a/crates/ra_syntax/test_data/parser/err/0022_bad_exprs.txt
+++ b/crates/ra_syntax/test_data/parser/err/0022_bad_exprs.txt
@@ -148,36 +148,36 @@ SOURCE_FILE@[0; 112)
148 WHITESPACE@[109; 110) " " 148 WHITESPACE@[109; 110) " "
149 R_CURLY@[110; 111) "}" 149 R_CURLY@[110; 111) "}"
150 WHITESPACE@[111; 112) "\n" 150 WHITESPACE@[111; 112) "\n"
151error 16: expected expression 151error [16; 16): expected expression
152error 17: expected R_BRACK 152error [17; 17): expected R_BRACK
153error 17: expected SEMI 153error [17; 17): expected SEMI
154error 17: expected expression 154error [17; 17): expected expression
155error 18: expected SEMI 155error [18; 18): expected SEMI
156error 25: expected a name 156error [25; 25): expected a name
157error 26: expected `;`, `{`, or `(` 157error [26; 26): expected `;`, `{`, or `(`
158error 30: expected pattern 158error [30; 30): expected pattern
159error 31: expected SEMI 159error [31; 31): expected SEMI
160error 53: expected expression 160error [53; 53): expected expression
161error 54: expected SEMI 161error [54; 54): expected SEMI
162error 54: expected expression 162error [54; 54): expected expression
163error 55: expected SEMI 163error [55; 55): expected SEMI
164error 60: expected type 164error [60; 60): expected type
165error 60: expected `{` 165error [60; 60): expected `{`
166error 60: expected expression 166error [60; 60): expected expression
167error 61: expected SEMI 167error [61; 61): expected SEMI
168error 65: expected pattern 168error [65; 65): expected pattern
169error 65: expected SEMI 169error [65; 65): expected SEMI
170error 65: expected expression 170error [65; 65): expected expression
171error 92: expected expression 171error [92; 92): expected expression
172error 93: expected SEMI 172error [93; 93): expected SEMI
173error 93: expected expression 173error [93; 93): expected expression
174error 94: expected SEMI 174error [94; 94): expected SEMI
175error 95: expected expression 175error [95; 95): expected expression
176error 96: expected SEMI 176error [96; 96): expected SEMI
177error 96: expected expression 177error [96; 96): expected expression
178error 97: expected SEMI 178error [97; 97): expected SEMI
179error 103: expected a name 179error [103; 103): expected a name
180error 104: expected `{` 180error [104; 104): expected `{`
181error 108: expected pattern 181error [108; 108): expected pattern
182error 108: expected SEMI 182error [108; 108): expected SEMI
183error 108: expected expression 183error [108; 108): expected expression
diff --git a/crates/ra_syntax/test_data/parser/err/0023_mismatched_paren.txt b/crates/ra_syntax/test_data/parser/err/0023_mismatched_paren.txt
index 6dd04f80e..775e4b0da 100644
--- a/crates/ra_syntax/test_data/parser/err/0023_mismatched_paren.txt
+++ b/crates/ra_syntax/test_data/parser/err/0023_mismatched_paren.txt
@@ -40,5 +40,5 @@ SOURCE_FILE@[0; 94)
40 ERROR@[92; 93) 40 ERROR@[92; 93)
41 R_CURLY@[92; 93) "}" 41 R_CURLY@[92; 93) "}"
42 WHITESPACE@[93; 94) "\n" 42 WHITESPACE@[93; 94) "\n"
43error 49: unmatched `}` 43error [49; 49): unmatched `}`
44error 92: unmatched `}` 44error [92; 92): unmatched `}`
diff --git a/crates/ra_syntax/test_data/parser/err/0024_many_type_parens.txt b/crates/ra_syntax/test_data/parser/err/0024_many_type_parens.txt
index 0a93e11a5..c5c8a29ba 100644
--- a/crates/ra_syntax/test_data/parser/err/0024_many_type_parens.txt
+++ b/crates/ra_syntax/test_data/parser/err/0024_many_type_parens.txt
@@ -290,32 +290,32 @@ SOURCE_FILE@[0; 240)
290 WHITESPACE@[237; 238) "\n" 290 WHITESPACE@[237; 238) "\n"
291 R_CURLY@[238; 239) "}" 291 R_CURLY@[238; 239) "}"
292 WHITESPACE@[239; 240) "\n" 292 WHITESPACE@[239; 240) "\n"
293error 88: expected COMMA 293error [88; 88): expected COMMA
294error 88: expected R_ANGLE 294error [88; 88): expected R_ANGLE
295error 121: expected SEMI 295error [121; 121): expected SEMI
296error 121: expected expression 296error [121; 121): expected expression
297error 140: expected type 297error [140; 140): expected type
298error 141: expected R_PAREN 298error [141; 141): expected R_PAREN
299error 141: expected COMMA 299error [141; 141): expected COMMA
300error 141: expected R_ANGLE 300error [141; 141): expected R_ANGLE
301error 141: expected SEMI 301error [141; 141): expected SEMI
302error 146: expected SEMI 302error [146; 146): expected SEMI
303error 146: expected expression 303error [146; 146): expected expression
304error 147: expected SEMI 304error [147; 147): expected SEMI
305error 148: expected expression 305error [148; 148): expected expression
306error 149: expected SEMI 306error [149; 149): expected SEMI
307error 154: expected pattern 307error [154; 154): expected pattern
308error 155: expected IN_KW 308error [155; 155): expected IN_KW
309error 155: expected expression 309error [155; 155): expected expression
310error 157: expected a block 310error [157; 157): expected a block
311error 165: expected expression 311error [165; 165): expected expression
312error 168: expected expression 312error [168; 168): expected expression
313error 179: expected expression 313error [179; 179): expected expression
314error 180: expected COMMA 314error [180; 180): expected COMMA
315error 180: expected expression 315error [180; 180): expected expression
316error 180: expected R_PAREN 316error [180; 180): expected R_PAREN
317error 180: expected SEMI 317error [180; 180): expected SEMI
318error 215: expected COMMA 318error [215; 215): expected COMMA
319error 215: expected R_ANGLE 319error [215; 215): expected R_ANGLE
320error 235: expected SEMI 320error [235; 235): expected SEMI
321error 235: expected expression 321error [235; 235): expected expression
diff --git a/crates/ra_syntax/test_data/parser/err/0025_nope.txt b/crates/ra_syntax/test_data/parser/err/0025_nope.txt
index 8369f4bda..ca7f2d255 100644
--- a/crates/ra_syntax/test_data/parser/err/0025_nope.txt
+++ b/crates/ra_syntax/test_data/parser/err/0025_nope.txt
@@ -191,14 +191,14 @@ SOURCE_FILE@[0; 575)
191 WHITESPACE@[572; 573) "\n" 191 WHITESPACE@[572; 573) "\n"
192 R_CURLY@[573; 574) "}" 192 R_CURLY@[573; 574) "}"
193 WHITESPACE@[574; 575) "\n" 193 WHITESPACE@[574; 575) "\n"
194error 95: expected type 194error [95; 95): expected type
195error 95: expected COMMA 195error [95; 95): expected COMMA
196error 96: expected field 196error [96; 96): expected field
197error 98: expected field declaration 197error [98; 98): expected field declaration
198error 371: expected COMMA 198error [371; 371): expected COMMA
199error 372: expected a type 199error [372; 372): expected a type
200error 372: expected R_PAREN 200error [372; 372): expected R_PAREN
201error 372: expected COMMA 201error [372; 372): expected COMMA
202error 372: expected enum variant 202error [372; 372): expected enum variant
203error 374: expected enum variant 203error [374; 374): expected enum variant
204error 508: expected expression 204error [508; 508): expected expression
diff --git a/crates/ra_syntax/test_data/parser/err/0026_imp_recovery.txt b/crates/ra_syntax/test_data/parser/err/0026_imp_recovery.txt
index d3da2f54f..3942e0904 100644
--- a/crates/ra_syntax/test_data/parser/err/0026_imp_recovery.txt
+++ b/crates/ra_syntax/test_data/parser/err/0026_imp_recovery.txt
@@ -45,5 +45,5 @@ SOURCE_FILE@[0; 38)
45 L_CURLY@[35; 36) "{" 45 L_CURLY@[35; 36) "{"
46 R_CURLY@[36; 37) "}" 46 R_CURLY@[36; 37) "}"
47 WHITESPACE@[37; 38) "\n" 47 WHITESPACE@[37; 38) "\n"
48error 14: expected trait or type 48error [14; 14): expected trait or type
49error 14: expected `{` 49error [14; 14): expected `{`
diff --git a/crates/ra_syntax/test_data/parser/err/0027_incomplere_where_for.txt b/crates/ra_syntax/test_data/parser/err/0027_incomplere_where_for.txt
index 9298b45a4..4a28bcabf 100644
--- a/crates/ra_syntax/test_data/parser/err/0027_incomplere_where_for.txt
+++ b/crates/ra_syntax/test_data/parser/err/0027_incomplere_where_for.txt
@@ -25,5 +25,5 @@ SOURCE_FILE@[0; 30)
25 L_CURLY@[27; 28) "{" 25 L_CURLY@[27; 28) "{"
26 R_CURLY@[28; 29) "}" 26 R_CURLY@[28; 29) "}"
27 WHITESPACE@[29; 30) "\n" 27 WHITESPACE@[29; 30) "\n"
28error 26: expected a path 28error [26; 26): expected a path
29error 26: expected colon 29error [26; 26): expected colon
diff --git a/crates/ra_syntax/test_data/parser/err/0029_field_completion.txt b/crates/ra_syntax/test_data/parser/err/0029_field_completion.txt
index e3e1282ec..177849476 100644
--- a/crates/ra_syntax/test_data/parser/err/0029_field_completion.txt
+++ b/crates/ra_syntax/test_data/parser/err/0029_field_completion.txt
@@ -33,4 +33,4 @@ SOURCE_FILE@[0; 24)
33 WHITESPACE@[21; 22) "\n" 33 WHITESPACE@[21; 22) "\n"
34 R_CURLY@[22; 23) "}" 34 R_CURLY@[22; 23) "}"
35 WHITESPACE@[23; 24) "\n" 35 WHITESPACE@[23; 24) "\n"
36error 21: expected field name or number 36error [21; 21): expected field name or number
diff --git a/crates/ra_syntax/test_data/parser/err/0032_match_arms_inner_attrs.txt b/crates/ra_syntax/test_data/parser/err/0032_match_arms_inner_attrs.txt
index dbc0081ac..c36e2f770 100644
--- a/crates/ra_syntax/test_data/parser/err/0032_match_arms_inner_attrs.txt
+++ b/crates/ra_syntax/test_data/parser/err/0032_match_arms_inner_attrs.txt
@@ -191,14 +191,14 @@ SOURCE_FILE@[0; 293)
191 WHITESPACE@[290; 291) "\n" 191 WHITESPACE@[290; 291) "\n"
192 R_CURLY@[291; 292) "}" 192 R_CURLY@[291; 292) "}"
193 WHITESPACE@[292; 293) "\n" 193 WHITESPACE@[292; 293) "\n"
194error 52: expected `[` 194error [52; 52): expected `[`
195error 52: expected pattern 195error [52; 52): expected pattern
196error 53: expected FAT_ARROW 196error [53; 53): expected FAT_ARROW
197error 78: expected COMMA 197error [78; 78): expected COMMA
198error 161: expected `[` 198error [161; 161): expected `[`
199error 161: expected pattern 199error [161; 161): expected pattern
200error 162: expected FAT_ARROW 200error [162; 162): expected FAT_ARROW
201error 232: expected `[` 201error [232; 232): expected `[`
202error 232: expected pattern 202error [232; 232): expected pattern
203error 233: expected FAT_ARROW 203error [233; 233): expected FAT_ARROW
204error 250: expected COMMA 204error [250; 250): expected COMMA
diff --git a/crates/ra_syntax/test_data/parser/err/0033_match_arms_outer_attrs.txt b/crates/ra_syntax/test_data/parser/err/0033_match_arms_outer_attrs.txt
index fd5ccc3f2..e914e688b 100644
--- a/crates/ra_syntax/test_data/parser/err/0033_match_arms_outer_attrs.txt
+++ b/crates/ra_syntax/test_data/parser/err/0033_match_arms_outer_attrs.txt
@@ -62,6 +62,6 @@ SOURCE_FILE@[0; 89)
62 WHITESPACE@[86; 87) "\n" 62 WHITESPACE@[86; 87) "\n"
63 R_CURLY@[87; 88) "}" 63 R_CURLY@[87; 88) "}"
64 WHITESPACE@[88; 89) "\n" 64 WHITESPACE@[88; 89) "\n"
65error 80: expected pattern 65error [80; 80): expected pattern
66error 80: expected FAT_ARROW 66error [80; 80): expected FAT_ARROW
67error 80: expected expression 67error [80; 80): expected expression
diff --git a/crates/ra_syntax/test_data/parser/err/0034_bad_box_pattern.txt b/crates/ra_syntax/test_data/parser/err/0034_bad_box_pattern.txt
index 21269fb02..2c91b6841 100644
--- a/crates/ra_syntax/test_data/parser/err/0034_bad_box_pattern.txt
+++ b/crates/ra_syntax/test_data/parser/err/0034_bad_box_pattern.txt
@@ -88,9 +88,9 @@ SOURCE_FILE@[0; 91)
88 WHITESPACE@[87; 88) "\n" 88 WHITESPACE@[87; 88) "\n"
89 R_CURLY@[88; 89) "}" 89 R_CURLY@[88; 89) "}"
90 WHITESPACE@[89; 91) "\n\n" 90 WHITESPACE@[89; 91) "\n\n"
91error 24: expected a name 91error [24; 24): expected a name
92error 27: expected SEMI 92error [27; 27): expected SEMI
93error 48: expected a name 93error [48; 48): expected a name
94error 51: expected SEMI 94error [51; 51): expected SEMI
95error 76: expected a name 95error [76; 76): expected a name
96error 79: expected SEMI 96error [79; 79): expected SEMI
diff --git a/crates/ra_syntax/test_data/parser/err/0035_use_recover.txt b/crates/ra_syntax/test_data/parser/err/0035_use_recover.txt
index 636840828..8cb4ea796 100644
--- a/crates/ra_syntax/test_data/parser/err/0035_use_recover.txt
+++ b/crates/ra_syntax/test_data/parser/err/0035_use_recover.txt
@@ -48,7 +48,7 @@ SOURCE_FILE@[0; 48)
48 L_CURLY@[45; 46) "{" 48 L_CURLY@[45; 46) "{"
49 R_CURLY@[46; 47) "}" 49 R_CURLY@[46; 47) "}"
50 WHITESPACE@[47; 48) "\n" 50 WHITESPACE@[47; 48) "\n"
51error 17: expected one of `*`, `::`, `{`, `self`, `super` or an identifier 51error [17; 17): expected one of `*`, `::`, `{`, `self`, `super` or an identifier
52error 17: expected SEMI 52error [17; 17): expected SEMI
53error 37: expected one of `*`, `::`, `{`, `self`, `super` or an identifier 53error [37; 37): expected one of `*`, `::`, `{`, `self`, `super` or an identifier
54error 37: expected SEMI 54error [37; 37): expected SEMI
diff --git a/crates/ra_syntax/test_data/parser/err/0036_partial_use.txt b/crates/ra_syntax/test_data/parser/err/0036_partial_use.txt
index 181f408c8..f5490fbe8 100644
--- a/crates/ra_syntax/test_data/parser/err/0036_partial_use.txt
+++ b/crates/ra_syntax/test_data/parser/err/0036_partial_use.txt
@@ -39,13 +39,13 @@ SOURCE_FILE@[0; 37)
39 ERROR@[35; 36) 39 ERROR@[35; 36)
40 SEMI@[35; 36) ";" 40 SEMI@[35; 36) ";"
41 WHITESPACE@[36; 37) "\n" 41 WHITESPACE@[36; 37) "\n"
42error 22: expected COMMA 42error [22; 22): expected COMMA
43error 22: expected one of `*`, `::`, `{`, `self`, `super` or an identifier 43error [22; 22): expected one of `*`, `::`, `{`, `self`, `super` or an identifier
44error 23: expected COMMA 44error [23; 23): expected COMMA
45error 24: expected one of `*`, `::`, `{`, `self`, `super` or an identifier 45error [24; 24): expected one of `*`, `::`, `{`, `self`, `super` or an identifier
46error 27: expected COMMA 46error [27; 27): expected COMMA
47error 35: expected COMMA 47error [35; 35): expected COMMA
48error 35: expected one of `*`, `::`, `{`, `self`, `super` or an identifier 48error [35; 35): expected one of `*`, `::`, `{`, `self`, `super` or an identifier
49error 36: expected COMMA 49error [36; 36): expected COMMA
50error 36: expected R_CURLY 50error [36; 36): expected R_CURLY
51error 36: expected SEMI 51error [36; 36): expected SEMI
diff --git a/crates/ra_syntax/test_data/parser/err/0037_visibility_in_traits.txt b/crates/ra_syntax/test_data/parser/err/0037_visibility_in_traits.txt
index 749c8cddb..d0a128a5f 100644
--- a/crates/ra_syntax/test_data/parser/err/0037_visibility_in_traits.txt
+++ b/crates/ra_syntax/test_data/parser/err/0037_visibility_in_traits.txt
@@ -94,6 +94,6 @@ SOURCE_FILE@[0; 118)
94 WHITESPACE@[115; 116) "\n" 94 WHITESPACE@[115; 116) "\n"
95 R_CURLY@[116; 117) "}" 95 R_CURLY@[116; 117) "}"
96 WHITESPACE@[117; 118) "\n" 96 WHITESPACE@[117; 118) "\n"
97error [36; 39): unnecessary visibility qualifier 97error [36; 39): Unnecessary visibility qualifier
98error [56; 66): unnecessary visibility qualifier 98error [56; 66): Unnecessary visibility qualifier
99error [86; 96): unnecessary visibility qualifier 99error [86; 96): Unnecessary visibility qualifier
diff --git a/crates/ra_syntax/test_data/parser/err/0039_lambda_recovery.txt b/crates/ra_syntax/test_data/parser/err/0039_lambda_recovery.txt
index d1544634c..4a2f0a696 100644
--- a/crates/ra_syntax/test_data/parser/err/0039_lambda_recovery.txt
+++ b/crates/ra_syntax/test_data/parser/err/0039_lambda_recovery.txt
@@ -80,4 +80,4 @@ SOURCE_FILE@[0; 83)
80 WHITESPACE@[80; 81) "\n" 80 WHITESPACE@[80; 81) "\n"
81 R_CURLY@[81; 82) "}" 81 R_CURLY@[81; 82) "}"
82 WHITESPACE@[82; 83) "\n" 82 WHITESPACE@[82; 83) "\n"
83error 56: expected expression 83error [56; 56): expected expression
diff --git a/crates/ra_syntax/test_data/parser/inline/err/0001_array_type_missing_semi.txt b/crates/ra_syntax/test_data/parser/inline/err/0001_array_type_missing_semi.txt
index 3f0f1b480..530533b71 100644
--- a/crates/ra_syntax/test_data/parser/inline/err/0001_array_type_missing_semi.txt
+++ b/crates/ra_syntax/test_data/parser/inline/err/0001_array_type_missing_semi.txt
@@ -20,8 +20,8 @@ SOURCE_FILE@[0; 18)
20 ERROR@[16; 17) 20 ERROR@[16; 17)
21 SEMI@[16; 17) ";" 21 SEMI@[16; 17) ";"
22 WHITESPACE@[17; 18) "\n" 22 WHITESPACE@[17; 18) "\n"
23error 12: expected `;` or `]` 23error [12; 12): expected `;` or `]`
24error 12: expected SEMI 24error [12; 12): expected SEMI
25error 13: expected an item 25error [13; 13): expected an item
26error 15: expected an item 26error [15; 15): expected an item
27error 16: expected an item 27error [16; 16): expected an item
diff --git a/crates/ra_syntax/test_data/parser/inline/err/0002_misplaced_label_err.txt b/crates/ra_syntax/test_data/parser/inline/err/0002_misplaced_label_err.txt
index 2950d77ef..0187d872d 100644
--- a/crates/ra_syntax/test_data/parser/inline/err/0002_misplaced_label_err.txt
+++ b/crates/ra_syntax/test_data/parser/inline/err/0002_misplaced_label_err.txt
@@ -23,7 +23,7 @@ SOURCE_FILE@[0; 30)
23 WHITESPACE@[27; 28) "\n" 23 WHITESPACE@[27; 28) "\n"
24 R_CURLY@[28; 29) "}" 24 R_CURLY@[28; 29) "}"
25 WHITESPACE@[29; 30) "\n" 25 WHITESPACE@[29; 30) "\n"
26error 22: expected a loop 26error [22; 22): expected a loop
27error 22: expected SEMI 27error [22; 22): expected SEMI
28error 27: expected type 28error [27; 27): expected type
29error 27: expected `{` 29error [27; 27): expected `{`
diff --git a/crates/ra_syntax/test_data/parser/inline/err/0003_pointer_type_no_mutability.txt b/crates/ra_syntax/test_data/parser/inline/err/0003_pointer_type_no_mutability.txt
index b97e339bb..2ab29eecc 100644
--- a/crates/ra_syntax/test_data/parser/inline/err/0003_pointer_type_no_mutability.txt
+++ b/crates/ra_syntax/test_data/parser/inline/err/0003_pointer_type_no_mutability.txt
@@ -14,4 +14,4 @@ SOURCE_FILE@[0; 14)
14 R_PAREN@[11; 12) ")" 14 R_PAREN@[11; 12) ")"
15 SEMI@[12; 13) ";" 15 SEMI@[12; 13) ";"
16 WHITESPACE@[13; 14) "\n" 16 WHITESPACE@[13; 14) "\n"
17error 10: expected mut or const in raw pointer type (use `*mut T` or `*const T` as appropriate) 17error [10; 10): expected mut or const in raw pointer type (use `*mut T` or `*const T` as appropriate)
diff --git a/crates/ra_syntax/test_data/parser/inline/err/0004_impl_type.txt b/crates/ra_syntax/test_data/parser/inline/err/0004_impl_type.txt
index 43321b1ed..d5aea05c2 100644
--- a/crates/ra_syntax/test_data/parser/inline/err/0004_impl_type.txt
+++ b/crates/ra_syntax/test_data/parser/inline/err/0004_impl_type.txt
@@ -73,7 +73,7 @@ SOURCE_FILE@[0; 87)
73 L_CURLY@[84; 85) "{" 73 L_CURLY@[84; 85) "{"
74 R_CURLY@[85; 86) "}" 74 R_CURLY@[85; 86) "}"
75 WHITESPACE@[86; 87) "\n" 75 WHITESPACE@[86; 87) "\n"
76error 38: expected trait or type 76error [38; 38): expected trait or type
77error 38: expected `{` 77error [38; 38): expected `{`
78error 70: expected trait or type 78error [70; 70): expected trait or type
79error 70: expected `{` 79error [70; 70): expected `{`
diff --git a/crates/ra_syntax/test_data/parser/inline/err/0005_fn_pointer_type_missing_fn.txt b/crates/ra_syntax/test_data/parser/inline/err/0005_fn_pointer_type_missing_fn.txt
index 451f29d39..9e9186ad4 100644
--- a/crates/ra_syntax/test_data/parser/inline/err/0005_fn_pointer_type_missing_fn.txt
+++ b/crates/ra_syntax/test_data/parser/inline/err/0005_fn_pointer_type_missing_fn.txt
@@ -16,8 +16,8 @@ SOURCE_FILE@[0; 20)
16 ERROR@[18; 19) 16 ERROR@[18; 19)
17 SEMI@[18; 19) ";" 17 SEMI@[18; 19) ";"
18 WHITESPACE@[19; 20) "\n" 18 WHITESPACE@[19; 20) "\n"
19error 15: expected `fn` 19error [15; 15): expected `fn`
20error 15: expected SEMI 20error [15; 15): expected SEMI
21error 16: expected an item 21error [16; 16): expected an item
22error 17: expected an item 22error [17; 17): expected an item
23error 18: expected an item 23error [18; 18): expected an item
diff --git a/crates/ra_syntax/test_data/parser/inline/err/0006_unsafe_block_in_mod.txt b/crates/ra_syntax/test_data/parser/inline/err/0006_unsafe_block_in_mod.txt
index f3fbc4828..690acdca3 100644
--- a/crates/ra_syntax/test_data/parser/inline/err/0006_unsafe_block_in_mod.txt
+++ b/crates/ra_syntax/test_data/parser/inline/err/0006_unsafe_block_in_mod.txt
@@ -33,5 +33,5 @@ SOURCE_FILE@[0; 33)
33 L_CURLY@[30; 31) "{" 33 L_CURLY@[30; 31) "{"
34 R_CURLY@[31; 32) "}" 34 R_CURLY@[31; 32) "}"
35 WHITESPACE@[32; 33) "\n" 35 WHITESPACE@[32; 33) "\n"
36error 11: expected an item 36error [11; 11): expected an item
37error 18: expected an item 37error [18; 18): expected an item
diff --git a/crates/ra_syntax/test_data/parser/inline/err/0007_async_without_semicolon.txt b/crates/ra_syntax/test_data/parser/inline/err/0007_async_without_semicolon.txt
index 5cfe766d7..a4002a998 100644
--- a/crates/ra_syntax/test_data/parser/inline/err/0007_async_without_semicolon.txt
+++ b/crates/ra_syntax/test_data/parser/inline/err/0007_async_without_semicolon.txt
@@ -29,4 +29,4 @@ SOURCE_FILE@[0; 30)
29 WHITESPACE@[27; 28) " " 29 WHITESPACE@[27; 28) " "
30 R_CURLY@[28; 29) "}" 30 R_CURLY@[28; 29) "}"
31 WHITESPACE@[29; 30) "\n" 31 WHITESPACE@[29; 30) "\n"
32error 27: expected SEMI 32error [27; 27): expected SEMI
diff --git a/crates/ra_syntax/test_data/parser/inline/err/0008_pub_expr.txt b/crates/ra_syntax/test_data/parser/inline/err/0008_pub_expr.txt
index 0594f148f..6f45a4fa6 100644
--- a/crates/ra_syntax/test_data/parser/inline/err/0008_pub_expr.txt
+++ b/crates/ra_syntax/test_data/parser/inline/err/0008_pub_expr.txt
@@ -23,4 +23,4 @@ SOURCE_FILE@[0; 21)
23 WHITESPACE@[18; 19) " " 23 WHITESPACE@[18; 19) " "
24 R_CURLY@[19; 20) "}" 24 R_CURLY@[19; 20) "}"
25 WHITESPACE@[20; 21) "\n" 25 WHITESPACE@[20; 21) "\n"
26error 14: expected an item 26error [14; 14): expected an item
diff --git a/crates/ra_syntax/test_data/parser/inline/err/0009_attr_on_expr_not_allowed.txt b/crates/ra_syntax/test_data/parser/inline/err/0009_attr_on_expr_not_allowed.txt
index 2ca5b8f32..e6d3a5c95 100644
--- a/crates/ra_syntax/test_data/parser/inline/err/0009_attr_on_expr_not_allowed.txt
+++ b/crates/ra_syntax/test_data/parser/inline/err/0009_attr_on_expr_not_allowed.txt
@@ -57,5 +57,5 @@ SOURCE_FILE@[0; 48)
57 WHITESPACE@[45; 46) "\n" 57 WHITESPACE@[45; 46) "\n"
58 R_CURLY@[46; 47) "}" 58 R_CURLY@[46; 47) "}"
59 WHITESPACE@[47; 48) "\n" 59 WHITESPACE@[47; 48) "\n"
60error 24: attributes are not allowed on BIN_EXPR 60error [24; 24): attributes are not allowed on BIN_EXPR
61error 44: attributes are not allowed on IF_EXPR 61error [44; 44): attributes are not allowed on IF_EXPR
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 289193b9e..f6ac0feaf 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
@@ -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 6: expected existential, fn, trait or impl 40error [6; 6): expected existential, fn, trait or impl
41error 31: expected existential, fn, trait or impl 41error [31; 31): expected existential, fn, trait or impl
diff --git a/crates/ra_syntax/test_data/parser/inline/err/0013_static_underscore.txt b/crates/ra_syntax/test_data/parser/inline/err/0013_static_underscore.txt
index 28f75a341..5b3dc5af2 100644
--- a/crates/ra_syntax/test_data/parser/inline/err/0013_static_underscore.txt
+++ b/crates/ra_syntax/test_data/parser/inline/err/0013_static_underscore.txt
@@ -18,4 +18,4 @@ SOURCE_FILE@[0; 19)
18 INT_NUMBER@[16; 17) "5" 18 INT_NUMBER@[16; 17) "5"
19 SEMI@[17; 18) ";" 19 SEMI@[17; 18) ";"
20 WHITESPACE@[18; 19) "\n" 20 WHITESPACE@[18; 19) "\n"
21error 7: expected a name 21error [7; 7): expected a name
diff --git a/crates/ra_syntax/test_data/parser/inline/err/0014_default_fn_type.txt b/crates/ra_syntax/test_data/parser/inline/err/0014_default_fn_type.txt
index a1a0bd7c4..25d80be1d 100644
--- a/crates/ra_syntax/test_data/parser/inline/err/0014_default_fn_type.txt
+++ b/crates/ra_syntax/test_data/parser/inline/err/0014_default_fn_type.txt
@@ -51,9 +51,9 @@ SOURCE_FILE@[0; 62)
51 WHITESPACE@[59; 60) "\n" 51 WHITESPACE@[59; 60) "\n"
52 R_CURLY@[60; 61) "}" 52 R_CURLY@[60; 61) "}"
53 WHITESPACE@[61; 62) "\n" 53 WHITESPACE@[61; 62) "\n"
54error 21: expected EXCL 54error [21; 21): expected EXCL
55error 21: expected `{`, `[`, `(` 55error [21; 21): expected `{`, `[`, `(`
56error 21: expected SEMI 56error [21; 21): expected SEMI
57error 47: expected EXCL 57error [47; 47): expected EXCL
58error 47: expected `{`, `[`, `(` 58error [47; 47): expected `{`, `[`, `(`
59error 47: expected SEMI 59error [47; 47): expected SEMI