@@ -10,9 +10,9 @@ use rustc_errors::{Applicability, DiagnosticBuilder};
1010use rustc_hir as hir;
1111use rustc_hir:: intravisit:: { walk_body, walk_expr, walk_ty, FnKind , NestedVisitorMap , Visitor } ;
1212use rustc_hir:: {
13- BinOpKind , Block , Body , Expr , ExprKind , FnDecl , FnRetTy , FnSig , GenericArg , GenericParamKind , HirId , ImplItem ,
14- ImplItemKind , Item , ItemKind , Lifetime , Lit , Local , MatchSource , MutTy , Mutability , Node , QPath , Stmt , StmtKind ,
15- TraitFn , TraitItem , TraitItemKind , TyKind , UnOp ,
13+ BinOpKind , Block , Body , Expr , ExprKind , FnDecl , FnRetTy , FnSig , GenericArg , GenericBounds , GenericParamKind , HirId ,
14+ ImplItem , ImplItemKind , Item , ItemKind , Lifetime , Lit , Local , MatchSource , MutTy , Mutability , Node , QPath , Stmt ,
15+ StmtKind , SyntheticTyParamKind , TraitFn , TraitItem , TraitItemKind , TyKind , UnOp ,
1616} ;
1717use rustc_lint:: { LateContext , LateLintPass , LintContext } ;
1818use rustc_middle:: hir:: map:: Map ;
@@ -678,17 +678,30 @@ impl Types {
678678 // details.
679679 return ;
680680 }
681+
682+ // When trait objects or opaque types have lifetime or auto-trait bounds,
683+ // we need to add parentheses to avoid a syntax error due to its ambiguity.
684+ // Originally reported as the issue #3128.
685+ let inner_snippet = snippet( cx, inner. span, ".." ) ;
686+ let suggestion = match & inner. kind {
687+ TyKind :: TraitObject ( bounds, lt_bound) if bounds. len( ) > 1 || !lt_bound. is_elided( ) => {
688+ format!( "&{}({})" , ltopt, & inner_snippet)
689+ } ,
690+ TyKind :: Path ( qpath)
691+ if get_bounds_if_impl_trait( cx, qpath, inner. hir_id)
692+ . map_or( false , |bounds| bounds. len( ) > 1 ) =>
693+ {
694+ format!( "&{}({})" , ltopt, & inner_snippet)
695+ } ,
696+ _ => format!( "&{}{}" , ltopt, & inner_snippet) ,
697+ } ;
681698 span_lint_and_sugg(
682699 cx,
683700 BORROWED_BOX ,
684701 hir_ty. span,
685702 "you seem to be trying to use `&Box<T>`. Consider using just `&T`" ,
686703 "try" ,
687- format!(
688- "&{}{}" ,
689- ltopt,
690- & snippet( cx, inner. span, ".." )
691- ) ,
704+ suggestion,
692705 // To make this `MachineApplicable`, at least one needs to check if it isn't a trait item
693706 // because the trait impls of it will break otherwise;
694707 // and there may be other cases that result in invalid code.
@@ -721,6 +734,21 @@ fn is_any_trait(t: &hir::Ty<'_>) -> bool {
721734 false
722735}
723736
737+ fn get_bounds_if_impl_trait < ' tcx > ( cx : & LateContext < ' tcx > , qpath : & QPath < ' _ > , id : HirId ) -> Option < GenericBounds < ' tcx > > {
738+ if_chain ! {
739+ if let Some ( did) = qpath_res( cx, qpath, id) . opt_def_id( ) ;
740+ if let Some ( node) = cx. tcx. hir( ) . get_if_local( did) ;
741+ if let Node :: GenericParam ( generic_param) = node;
742+ if let GenericParamKind :: Type { synthetic, .. } = generic_param. kind;
743+ if synthetic == Some ( SyntheticTyParamKind :: ImplTrait ) ;
744+ then {
745+ Some ( generic_param. bounds)
746+ } else {
747+ None
748+ }
749+ }
750+ }
751+
724752declare_clippy_lint ! {
725753 /// **What it does:** Checks for binding a unit value.
726754 ///
0 commit comments