aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_ide/src/diagnostics.rs10
-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
56 files changed, 452 insertions, 650 deletions
diff --git a/crates/ra_ide/src/diagnostics.rs b/crates/ra_ide/src/diagnostics.rs
index 22bd49723..82596c665 100644
--- a/crates/ra_ide/src/diagnostics.rs
+++ b/crates/ra_ide/src/diagnostics.rs
@@ -10,7 +10,7 @@ use ra_prof::profile;
10use ra_syntax::{ 10use ra_syntax::{
11 algo, 11 algo,
12 ast::{self, make, AstNode}, 12 ast::{self, make, AstNode},
13 Location, SyntaxNode, TextRange, T, 13 SyntaxNode, TextRange, T,
14}; 14};
15use ra_text_edit::{TextEdit, TextEditBuilder}; 15use ra_text_edit::{TextEdit, TextEditBuilder};
16 16
@@ -29,7 +29,7 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic>
29 let mut res = Vec::new(); 29 let mut res = Vec::new();
30 30
31 res.extend(parse.errors().iter().map(|err| Diagnostic { 31 res.extend(parse.errors().iter().map(|err| Diagnostic {
32 range: location_to_range(err.location()), 32 range: err.range(),
33 message: format!("Syntax Error: {}", err), 33 message: format!("Syntax Error: {}", err),
34 severity: Severity::Error, 34 severity: Severity::Error,
35 fix: None, 35 fix: None,
@@ -116,12 +116,6 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic>
116 drop(sink); 116 drop(sink);
117 res.into_inner() 117 res.into_inner()
118} 118}
119fn location_to_range(location: Location) -> TextRange {
120 match location {
121 Location::Offset(offset) => TextRange::offset_len(offset, 1.into()),
122 Location::Range(range) => range,
123 }
124}
125 119
126fn check_unnecessary_braces_in_use_statement( 120fn check_unnecessary_braces_in_use_statement(
127 acc: &mut Vec<Diagnostic>, 121 acc: &mut Vec<Diagnostic>,
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