1
+ use crate :: errors:: { WhereClauseBeforeTupleStructBody , WhereClauseBeforeTupleStructBodySugg } ;
2
+
1
3
use super :: { ForceCollect , Parser , TrailingToken } ;
2
4
5
+ use ast:: token:: Delimiter ;
3
6
use rustc_ast:: token;
4
7
use rustc_ast:: {
5
8
self as ast, AttrVec , GenericBounds , GenericParam , GenericParamKind , TyKind , WhereClause ,
6
9
} ;
7
10
use rustc_errors:: { Applicability , PResult } ;
8
- use rustc_span:: symbol:: kw;
11
+ use rustc_span:: symbol:: { kw, Ident } ;
12
+ use rustc_span:: Span ;
13
+
14
+ enum PredicateOrStructBody {
15
+ Predicate ( ast:: WherePredicate ) ,
16
+ StructBody ( Vec < ast:: FieldDef > ) ,
17
+ }
9
18
10
19
impl < ' a > Parser < ' a > {
11
20
/// Parses bounds of a lifetime parameter `BOUND + BOUND + BOUND`, possibly with trailing `+`.
@@ -240,23 +249,39 @@ impl<'a> Parser<'a> {
240
249
} )
241
250
}
242
251
243
- /// Parses an optional where-clause and places it in `generics` .
252
+ /// Parses an optional where-clause.
244
253
///
245
254
/// ```ignore (only-for-syntax-highlight)
246
255
/// where T : Trait<U, V> + 'b, 'a : 'b
247
256
/// ```
248
257
pub ( super ) fn parse_where_clause ( & mut self ) -> PResult < ' a , WhereClause > {
258
+ self . parse_where_clause_common ( None ) . map ( |( clause, _) | clause)
259
+ }
260
+
261
+ pub ( super ) fn parse_struct_where_clause (
262
+ & mut self ,
263
+ struct_name : Ident ,
264
+ body_insertion_point : Span ,
265
+ ) -> PResult < ' a , ( WhereClause , Option < Vec < ast:: FieldDef > > ) > {
266
+ self . parse_where_clause_common ( Some ( ( struct_name, body_insertion_point) ) )
267
+ }
268
+
269
+ fn parse_where_clause_common (
270
+ & mut self ,
271
+ struct_ : Option < ( Ident , Span ) > ,
272
+ ) -> PResult < ' a , ( WhereClause , Option < Vec < ast:: FieldDef > > ) > {
249
273
let mut where_clause = WhereClause {
250
274
has_where_token : false ,
251
275
predicates : Vec :: new ( ) ,
252
276
span : self . prev_token . span . shrink_to_hi ( ) ,
253
277
} ;
278
+ let mut tuple_struct_body = None ;
254
279
255
280
if !self . eat_keyword ( kw:: Where ) {
256
- return Ok ( where_clause) ;
281
+ return Ok ( ( where_clause, None ) ) ;
257
282
}
258
283
where_clause. has_where_token = true ;
259
- let lo = self . prev_token . span ;
284
+ let where_lo = self . prev_token . span ;
260
285
261
286
// We are considering adding generics to the `where` keyword as an alternative higher-rank
262
287
// parameter syntax (as in `where<'a>` or `where<T>`. To avoid that being a breaking
@@ -272,21 +297,30 @@ impl<'a> Parser<'a> {
272
297
}
273
298
274
299
loop {
275
- let lo = self . token . span ;
300
+ let where_sp = where_lo. to ( self . prev_token . span ) ;
301
+ let pred_lo = self . token . span ;
276
302
if self . check_lifetime ( ) && self . look_ahead ( 1 , |t| !t. is_like_plus ( ) ) {
277
303
let lifetime = self . expect_lifetime ( ) ;
278
304
// Bounds starting with a colon are mandatory, but possibly empty.
279
305
self . expect ( & token:: Colon ) ?;
280
306
let bounds = self . parse_lt_param_bounds ( ) ;
281
307
where_clause. predicates . push ( ast:: WherePredicate :: RegionPredicate (
282
308
ast:: WhereRegionPredicate {
283
- span : lo . to ( self . prev_token . span ) ,
309
+ span : pred_lo . to ( self . prev_token . span ) ,
284
310
lifetime,
285
311
bounds,
286
312
} ,
287
313
) ) ;
288
314
} else if self . check_type ( ) {
289
- where_clause. predicates . push ( self . parse_ty_where_predicate ( ) ?) ;
315
+ match self . parse_ty_where_predicate_or_recover_tuple_struct_body (
316
+ struct_, pred_lo, where_sp,
317
+ ) ? {
318
+ PredicateOrStructBody :: Predicate ( pred) => where_clause. predicates . push ( pred) ,
319
+ PredicateOrStructBody :: StructBody ( body) => {
320
+ tuple_struct_body = Some ( body) ;
321
+ break ;
322
+ }
323
+ }
290
324
} else {
291
325
break ;
292
326
}
@@ -297,7 +331,7 @@ impl<'a> Parser<'a> {
297
331
if self . eat_keyword_noexpect ( kw:: Where ) {
298
332
let msg = "cannot define duplicate `where` clauses on an item" ;
299
333
let mut err = self . struct_span_err ( self . token . span , msg) ;
300
- err. span_label ( lo , "previous `where` clause starts here" ) ;
334
+ err. span_label ( pred_lo , "previous `where` clause starts here" ) ;
301
335
err. span_suggestion_verbose (
302
336
prev_token. shrink_to_hi ( ) . to ( self . prev_token . span ) ,
303
337
"consider joining the two `where` clauses into one" ,
@@ -310,8 +344,72 @@ impl<'a> Parser<'a> {
310
344
}
311
345
}
312
346
313
- where_clause. span = lo. to ( self . prev_token . span ) ;
314
- Ok ( where_clause)
347
+ where_clause. span = where_lo. to ( self . prev_token . span ) ;
348
+ Ok ( ( where_clause, tuple_struct_body) )
349
+ }
350
+
351
+ fn parse_ty_where_predicate_or_recover_tuple_struct_body (
352
+ & mut self ,
353
+ struct_ : Option < ( Ident , Span ) > ,
354
+ pred_lo : Span ,
355
+ where_sp : Span ,
356
+ ) -> PResult < ' a , PredicateOrStructBody > {
357
+ let mut snapshot = None ;
358
+
359
+ if let Some ( struct_) = struct_
360
+ && self . may_recover ( )
361
+ && self . token . kind == token:: OpenDelim ( Delimiter :: Parenthesis )
362
+ {
363
+ snapshot = Some ( ( struct_, self . create_snapshot_for_diagnostic ( ) ) ) ;
364
+ } ;
365
+
366
+ match self . parse_ty_where_predicate ( ) {
367
+ Ok ( pred) => Ok ( PredicateOrStructBody :: Predicate ( pred) ) ,
368
+ Err ( type_err) => {
369
+ let Some ( ( ( struct_name, body_insertion_point) , mut snapshot) ) = snapshot else {
370
+ return Err ( type_err) ;
371
+ } ;
372
+
373
+ // Check if we might have encountered an out of place tuple struct body.
374
+ match snapshot. parse_tuple_struct_body ( ) {
375
+ // Since we don't know the exact reason why we failed to parse the
376
+ // predicate (we might have stumbled upon something bogus like `(T): ?`),
377
+ // employ a simple heuristic to weed out some pathological cases:
378
+ // Look for a semicolon (strong indicator) or anything that might mark
379
+ // the end of the item (weak indicator) following the body.
380
+ Ok ( body)
381
+ if matches ! ( snapshot. token. kind, token:: Semi | token:: Eof )
382
+ || snapshot. token . can_begin_item ( ) =>
383
+ {
384
+ type_err. cancel ( ) ;
385
+
386
+ let body_sp = pred_lo. to ( snapshot. prev_token . span ) ;
387
+ let map = self . sess . source_map ( ) ;
388
+
389
+ self . sess . emit_err ( WhereClauseBeforeTupleStructBody {
390
+ span : where_sp,
391
+ name : struct_name. span ,
392
+ body : body_sp,
393
+ sugg : map. span_to_snippet ( body_sp) . ok ( ) . map ( |body| {
394
+ WhereClauseBeforeTupleStructBodySugg {
395
+ left : body_insertion_point. shrink_to_hi ( ) ,
396
+ snippet : body,
397
+ right : map. end_point ( where_sp) . to ( body_sp) ,
398
+ }
399
+ } ) ,
400
+ } ) ;
401
+
402
+ self . restore_snapshot ( snapshot) ;
403
+ Ok ( PredicateOrStructBody :: StructBody ( body) )
404
+ }
405
+ Ok ( _) => Err ( type_err) ,
406
+ Err ( body_err) => {
407
+ body_err. cancel ( ) ;
408
+ Err ( type_err)
409
+ }
410
+ }
411
+ }
412
+ }
315
413
}
316
414
317
415
fn parse_ty_where_predicate ( & mut self ) -> PResult < ' a , ast:: WherePredicate > {
0 commit comments