@@ -7,7 +7,7 @@ use rustc_ast::{
7
7
Pinnedness , PolyTraitRef , PreciseCapturingArg , TraitBoundModifiers , TraitObjectSyntax , Ty ,
8
8
TyKind , UnsafeBinderTy ,
9
9
} ;
10
- use rustc_errors:: { Applicability , PResult } ;
10
+ use rustc_errors:: { Applicability , Diag , PResult } ;
11
11
use rustc_span:: { ErrorGuaranteed , Ident , Span , kw, sym} ;
12
12
use thin_vec:: { ThinVec , thin_vec} ;
13
13
@@ -411,6 +411,9 @@ impl<'a> Parser<'a> {
411
411
TyKind :: Path ( None , path) if maybe_bounds => {
412
412
self . parse_remaining_bounds_path ( ThinVec :: new ( ) , path, lo, true )
413
413
}
414
+ // For `('a) + …`, we know that `'a` in type position already lead to an error being
415
+ // emitted. To reduce output, let's indirectly suppress E0178 (bad `+` in type) and
416
+ // other irrelevant consequential errors.
414
417
TyKind :: TraitObject ( bounds, TraitObjectSyntax :: None )
415
418
if maybe_bounds && bounds. len ( ) == 1 && !trailing_plus =>
416
419
{
@@ -425,12 +428,60 @@ impl<'a> Parser<'a> {
425
428
}
426
429
427
430
fn parse_bare_trait_object ( & mut self , lo : Span , allow_plus : AllowPlus ) -> PResult < ' a , TyKind > {
428
- let lt_no_plus = self . check_lifetime ( ) && !self . look_ahead ( 1 , |t| t. is_like_plus ( ) ) ;
429
- let bounds = self . parse_generic_bounds_common ( allow_plus) ?;
430
- if lt_no_plus {
431
- self . dcx ( ) . emit_err ( NeedPlusAfterTraitObjectLifetime { span : lo } ) ;
431
+ // A lifetime only begins a bare trait object type if it is followed by `+`!
432
+ if self . token . is_lifetime ( ) && !self . look_ahead ( 1 , |t| t. is_like_plus ( ) ) {
433
+ // In Rust 2021 and beyond, we assume that the user didn't intend to write a bare trait
434
+ // object type with a leading lifetime bound since that seems very unlikely given the
435
+ // fact that `dyn`-less trait objects are *semantically* invalid.
436
+ if self . psess . edition . at_least_rust_2021 ( ) {
437
+ let lt = self . expect_lifetime ( ) ;
438
+ let mut err = self . dcx ( ) . struct_span_err ( lo, "expected type, found lifetime" ) ;
439
+ err. span_label ( lo, "expected type" ) ;
440
+ return Ok ( match self . maybe_recover_ref_ty_no_leading_ampersand ( lt, lo, err) {
441
+ Ok ( ref_ty) => ref_ty,
442
+ Err ( err) => TyKind :: Err ( err. emit ( ) ) ,
443
+ } ) ;
444
+ }
445
+
446
+ self . dcx ( ) . emit_err ( NeedPlusAfterTraitObjectLifetime {
447
+ span : lo,
448
+ suggestion : lo. shrink_to_hi ( ) ,
449
+ } ) ;
450
+ }
451
+ Ok ( TyKind :: TraitObject (
452
+ self . parse_generic_bounds_common ( allow_plus) ?,
453
+ TraitObjectSyntax :: None ,
454
+ ) )
455
+ }
456
+
457
+ fn maybe_recover_ref_ty_no_leading_ampersand < ' cx > (
458
+ & mut self ,
459
+ lt : Lifetime ,
460
+ lo : Span ,
461
+ mut err : Diag < ' cx > ,
462
+ ) -> Result < TyKind , Diag < ' cx > > {
463
+ if !self . may_recover ( ) {
464
+ return Err ( err) ;
465
+ }
466
+ let snapshot = self . create_snapshot_for_diagnostic ( ) ;
467
+ let mutbl = self . parse_mutability ( ) ;
468
+ match self . parse_ty_no_plus ( ) {
469
+ Ok ( ty) => {
470
+ err. span_suggestion_verbose (
471
+ lo. shrink_to_lo ( ) ,
472
+ "you might have meant to write a reference type here" ,
473
+ "&" ,
474
+ Applicability :: MaybeIncorrect ,
475
+ ) ;
476
+ err. emit ( ) ;
477
+ Ok ( TyKind :: Ref ( Some ( lt) , MutTy { ty, mutbl } ) )
478
+ }
479
+ Err ( diag) => {
480
+ diag. cancel ( ) ;
481
+ self . restore_snapshot ( snapshot) ;
482
+ Err ( err)
483
+ }
432
484
}
433
- Ok ( TyKind :: TraitObject ( bounds, TraitObjectSyntax :: None ) )
434
485
}
435
486
436
487
fn parse_remaining_bounds_path (
0 commit comments