@@ -5,18 +5,15 @@ use crate::ast::{
55} ;
66use crate :: parse:: { SeqSep , token, PResult , Parser } ;
77use crate :: parse:: parser:: { BlockMode , PathStyle , SemiColonMode , TokenType , TokenExpectType } ;
8- use crate :: parse:: token;
98use crate :: print:: pprust;
109use crate :: ptr:: P ;
1110use crate :: source_map:: Spanned ;
1211use crate :: symbol:: kw;
1312use crate :: ThinVec ;
14- use crate :: tokenstream:: TokenTree ;
1513use crate :: util:: parser:: AssocOp ;
16- use errors:: { Applicability , DiagnosticBuilder , DiagnosticId , FatalError } ;
14+ use errors:: { Applicability , DiagnosticBuilder , DiagnosticId } ;
1715use syntax_pos:: { Span , DUMMY_SP , MultiSpan } ;
1816use log:: { debug, trace} ;
19- use std:: slice;
2017
2118pub enum Error {
2219 FileNotFoundForModule {
@@ -148,36 +145,8 @@ impl RecoverQPath for Expr {
148145}
149146
150147impl < ' 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-
179148 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)
181150 }
182151
183152 pub fn span_fatal < S : Into < MultiSpan > > ( & self , sp : S , m : & str ) -> DiagnosticBuilder < ' a > {
@@ -243,6 +212,145 @@ impl<'a> Parser<'a> {
243212 err
244213 }
245214
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+
246354 /// Eats and discards tokens until one of `kets` is encountered. Respects token trees,
247355 /// passes through any errors encountered. Used for error recovery.
248356 crate fn eat_to_tokens ( & mut self , kets : & [ & token:: Token ] ) {
@@ -939,9 +1047,6 @@ impl<'a> Parser<'a> {
9391047 String :: new ( ) ,
9401048 Applicability :: MachineApplicable ,
9411049 ) ;
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>") ;
9451050 err. emit ( ) ;
9461051 }
9471052 }
@@ -1050,12 +1155,12 @@ impl<'a> Parser<'a> {
10501155 ) -> PResult < ' a , ast:: Arg > {
10511156 let sp = arg. pat . span ;
10521157 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" ) ;
10541159 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 " ) ;
10561161 } 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" ) ;
10591164 }
10601165 err. emit ( ) ;
10611166 Ok ( arg)
0 commit comments