@@ -5,18 +5,15 @@ use crate::ast::{
5
5
} ;
6
6
use crate :: parse:: { SeqSep , token, PResult , Parser } ;
7
7
use crate :: parse:: parser:: { BlockMode , PathStyle , SemiColonMode , TokenType , TokenExpectType } ;
8
- use crate :: parse:: token;
9
8
use crate :: print:: pprust;
10
9
use crate :: ptr:: P ;
11
10
use crate :: source_map:: Spanned ;
12
11
use crate :: symbol:: kw;
13
12
use crate :: ThinVec ;
14
- use crate :: tokenstream:: TokenTree ;
15
13
use crate :: util:: parser:: AssocOp ;
16
- use errors:: { Applicability , DiagnosticBuilder , DiagnosticId , FatalError } ;
14
+ use errors:: { Applicability , DiagnosticBuilder , DiagnosticId } ;
17
15
use syntax_pos:: { Span , DUMMY_SP , MultiSpan } ;
18
16
use log:: { debug, trace} ;
19
- use std:: slice;
20
17
21
18
pub enum Error {
22
19
FileNotFoundForModule {
@@ -148,36 +145,8 @@ impl RecoverQPath for Expr {
148
145
}
149
146
150
147
impl < ' a > Parser < ' a > {
151
- pub fn look_ahead < R , F > ( & self , dist : usize , f : F ) -> R where
152
- F : FnOnce ( & token:: Token ) -> R ,
153
- {
154
- if dist == 0 {
155
- return f ( & self . token )
156
- }
157
-
158
- f ( & match self . token_cursor . frame . tree_cursor . look_ahead ( dist - 1 ) {
159
- Some ( tree) => match tree {
160
- TokenTree :: Token ( _, tok) => tok,
161
- TokenTree :: Delimited ( _, delim, _) => token:: OpenDelim ( delim) ,
162
- } ,
163
- None => token:: CloseDelim ( self . token_cursor . frame . delim ) ,
164
- } )
165
- }
166
-
167
- crate fn look_ahead_span ( & self , dist : usize ) -> Span {
168
- if dist == 0 {
169
- return self . span
170
- }
171
-
172
- match self . token_cursor . frame . tree_cursor . look_ahead ( dist - 1 ) {
173
- Some ( TokenTree :: Token ( span, _) ) => span,
174
- Some ( TokenTree :: Delimited ( span, ..) ) => span. entire ( ) ,
175
- None => self . look_ahead_span ( dist - 1 ) ,
176
- }
177
- }
178
-
179
148
pub fn fatal ( & self , m : & str ) -> DiagnosticBuilder < ' a > {
180
- self . sess . span_diagnostic . struct_span_fatal ( self . span , m)
149
+ self . span_fatal ( self . span , m)
181
150
}
182
151
183
152
pub fn span_fatal < S : Into < MultiSpan > > ( & self , sp : S , m : & str ) -> DiagnosticBuilder < ' a > {
@@ -243,6 +212,145 @@ impl<'a> Parser<'a> {
243
212
err
244
213
}
245
214
215
+ pub fn expected_one_of_not_found (
216
+ & mut self ,
217
+ edible : & [ token:: Token ] ,
218
+ inedible : & [ token:: Token ] ,
219
+ ) -> PResult < ' a , bool /* recovered */ > {
220
+ fn tokens_to_string ( tokens : & [ TokenType ] ) -> String {
221
+ let mut i = tokens. iter ( ) ;
222
+ // This might be a sign we need a connect method on Iterator.
223
+ let b = i. next ( )
224
+ . map_or ( String :: new ( ) , |t| t. to_string ( ) ) ;
225
+ i. enumerate ( ) . fold ( b, |mut b, ( i, a) | {
226
+ if tokens. len ( ) > 2 && i == tokens. len ( ) - 2 {
227
+ b. push_str ( ", or " ) ;
228
+ } else if tokens. len ( ) == 2 && i == tokens. len ( ) - 2 {
229
+ b. push_str ( " or " ) ;
230
+ } else {
231
+ b. push_str ( ", " ) ;
232
+ }
233
+ b. push_str ( & a. to_string ( ) ) ;
234
+ b
235
+ } )
236
+ }
237
+
238
+ let mut expected = edible. iter ( )
239
+ . map ( |x| TokenType :: Token ( x. clone ( ) ) )
240
+ . chain ( inedible. iter ( ) . map ( |x| TokenType :: Token ( x. clone ( ) ) ) )
241
+ . chain ( self . expected_tokens . iter ( ) . cloned ( ) )
242
+ . collect :: < Vec < _ > > ( ) ;
243
+ expected. sort_by_cached_key ( |x| x. to_string ( ) ) ;
244
+ expected. dedup ( ) ;
245
+ let expect = tokens_to_string ( & expected[ ..] ) ;
246
+ let actual = self . this_token_to_string ( ) ;
247
+ let ( msg_exp, ( label_sp, label_exp) ) = if expected. len ( ) > 1 {
248
+ let short_expect = if expected. len ( ) > 6 {
249
+ format ! ( "{} possible tokens" , expected. len( ) )
250
+ } else {
251
+ expect. clone ( )
252
+ } ;
253
+ ( format ! ( "expected one of {}, found `{}`" , expect, actual) ,
254
+ ( self . sess . source_map ( ) . next_point ( self . prev_span ) ,
255
+ format ! ( "expected one of {} here" , short_expect) ) )
256
+ } else if expected. is_empty ( ) {
257
+ ( format ! ( "unexpected token: `{}`" , actual) ,
258
+ ( self . prev_span , "unexpected token after this" . to_string ( ) ) )
259
+ } else {
260
+ ( format ! ( "expected {}, found `{}`" , expect, actual) ,
261
+ ( self . sess . source_map ( ) . next_point ( self . prev_span ) ,
262
+ format ! ( "expected {} here" , expect) ) )
263
+ } ;
264
+ self . last_unexpected_token_span = Some ( self . span ) ;
265
+ let mut err = self . fatal ( & msg_exp) ;
266
+ if self . token . is_ident_named ( "and" ) {
267
+ err. span_suggestion_short (
268
+ self . span ,
269
+ "use `&&` instead of `and` for the boolean operator" ,
270
+ "&&" . to_string ( ) ,
271
+ Applicability :: MaybeIncorrect ,
272
+ ) ;
273
+ }
274
+ if self . token . is_ident_named ( "or" ) {
275
+ err. span_suggestion_short (
276
+ self . span ,
277
+ "use `||` instead of `or` for the boolean operator" ,
278
+ "||" . to_string ( ) ,
279
+ Applicability :: MaybeIncorrect ,
280
+ ) ;
281
+ }
282
+ let sp = if self . token == token:: Token :: Eof {
283
+ // This is EOF, don't want to point at the following char, but rather the last token
284
+ self . prev_span
285
+ } else {
286
+ label_sp
287
+ } ;
288
+ match self . recover_closing_delimiter ( & expected. iter ( ) . filter_map ( |tt| match tt {
289
+ TokenType :: Token ( t) => Some ( t. clone ( ) ) ,
290
+ _ => None ,
291
+ } ) . collect :: < Vec < _ > > ( ) , err) {
292
+ Err ( e) => err = e,
293
+ Ok ( recovered) => {
294
+ return Ok ( recovered) ;
295
+ }
296
+ }
297
+
298
+ let is_semi_suggestable = expected. iter ( ) . any ( |t| match t {
299
+ TokenType :: Token ( token:: Semi ) => true , // we expect a `;` here
300
+ _ => false ,
301
+ } ) && ( // a `;` would be expected before the current keyword
302
+ self . token . is_keyword ( kw:: Break ) ||
303
+ self . token . is_keyword ( kw:: Continue ) ||
304
+ self . token . is_keyword ( kw:: For ) ||
305
+ self . token . is_keyword ( kw:: If ) ||
306
+ self . token . is_keyword ( kw:: Let ) ||
307
+ self . token . is_keyword ( kw:: Loop ) ||
308
+ self . token . is_keyword ( kw:: Match ) ||
309
+ self . token . is_keyword ( kw:: Return ) ||
310
+ self . token . is_keyword ( kw:: While )
311
+ ) ;
312
+ let cm = self . sess . source_map ( ) ;
313
+ match ( cm. lookup_line ( self . span . lo ( ) ) , cm. lookup_line ( sp. lo ( ) ) ) {
314
+ ( Ok ( ref a) , Ok ( ref b) ) if a. line != b. line && is_semi_suggestable => {
315
+ // The spans are in different lines, expected `;` and found `let` or `return`.
316
+ // High likelihood that it is only a missing `;`.
317
+ err. span_suggestion_short (
318
+ label_sp,
319
+ "a semicolon may be missing here" ,
320
+ ";" . to_string ( ) ,
321
+ Applicability :: MaybeIncorrect ,
322
+ ) ;
323
+ err. emit ( ) ;
324
+ return Ok ( true ) ;
325
+ }
326
+ ( Ok ( ref a) , Ok ( ref b) ) if a. line == b. line => {
327
+ // When the spans are in the same line, it means that the only content between
328
+ // them is whitespace, point at the found token in that case:
329
+ //
330
+ // X | () => { syntax error };
331
+ // | ^^^^^ expected one of 8 possible tokens here
332
+ //
333
+ // instead of having:
334
+ //
335
+ // X | () => { syntax error };
336
+ // | -^^^^^ unexpected token
337
+ // | |
338
+ // | expected one of 8 possible tokens here
339
+ err. span_label ( self . span , label_exp) ;
340
+ }
341
+ _ if self . prev_span == syntax_pos:: DUMMY_SP => {
342
+ // Account for macro context where the previous span might not be
343
+ // available to avoid incorrect output (#54841).
344
+ err. span_label ( self . span , "unexpected token" ) ;
345
+ }
346
+ _ => {
347
+ err. span_label ( sp, label_exp) ;
348
+ err. span_label ( self . span , "unexpected token" ) ;
349
+ }
350
+ }
351
+ Err ( err)
352
+ }
353
+
246
354
/// Eats and discards tokens until one of `kets` is encountered. Respects token trees,
247
355
/// passes through any errors encountered. Used for error recovery.
248
356
crate fn eat_to_tokens ( & mut self , kets : & [ & token:: Token ] ) {
@@ -939,9 +1047,6 @@ impl<'a> Parser<'a> {
939
1047
String :: new ( ) ,
940
1048
Applicability :: MachineApplicable ,
941
1049
) ;
942
- err. note ( "if you meant to use emplacement syntax, it is obsolete (for now, anyway)" ) ;
943
- err. note ( "for more information on the status of emplacement syntax, see <\
944
- https://github.com/rust-lang/rust/issues/27779#issuecomment-378416911>") ;
945
1050
err. emit ( ) ;
946
1051
}
947
1052
}
@@ -1050,12 +1155,12 @@ impl<'a> Parser<'a> {
1050
1155
) -> PResult < ' a , ast:: Arg > {
1051
1156
let sp = arg. pat . span ;
1052
1157
arg. ty . node = TyKind :: Err ;
1053
- let mut err = self . struct_span_err ( sp, "unexpected `self` argument in function" ) ;
1158
+ let mut err = self . struct_span_err ( sp, "unexpected `self` parameter in function" ) ;
1054
1159
if is_trait_item {
1055
- err. span_label ( sp, "must be the first associated function argument " ) ;
1160
+ err. span_label ( sp, "must be the first associated function parameter " ) ;
1056
1161
} else {
1057
- err. span_label ( sp, "not valid as function argument " ) ;
1058
- err. note ( "`self` is only valid as the first argument of an associated function" ) ;
1162
+ err. span_label ( sp, "not valid as function parameter " ) ;
1163
+ err. note ( "`self` is only valid as the first parameter of an associated function" ) ;
1059
1164
}
1060
1165
err. emit ( ) ;
1061
1166
Ok ( arg)
0 commit comments