@@ -2,7 +2,9 @@ use super::potentially_plural_count;
22use  crate :: errors:: LifetimesOrBoundsMismatchOnTrait ; 
33use  hir:: def_id:: { DefId ,  LocalDefId } ; 
44use  rustc_data_structures:: fx:: { FxHashMap ,  FxIndexSet } ; 
5- use  rustc_errors:: { pluralize,  struct_span_err,  Applicability ,  DiagnosticId ,  ErrorGuaranteed } ; 
5+ use  rustc_errors:: { 
6+     pluralize,  struct_span_err,  Applicability ,  DiagnosticId ,  ErrorGuaranteed ,  MultiSpan , 
7+ } ; 
68use  rustc_hir as  hir; 
79use  rustc_hir:: def:: { DefKind ,  Res } ; 
810use  rustc_hir:: intravisit; 
@@ -320,15 +322,6 @@ fn compare_method_predicate_entailment<'tcx>(
320322            ty:: Binder :: dummy ( ty:: PredicateKind :: WellFormed ( unnormalized_impl_fty. into ( ) ) ) , 
321323        ) ) ; 
322324    } 
323-     let  emit_implied_wf_lint = || { 
324-         infcx. tcx . struct_span_lint_hir ( 
325-             rustc_session:: lint:: builtin:: IMPLIED_BOUNDS_ENTAILMENT , 
326-             impl_m_hir_id, 
327-             infcx. tcx . def_span ( impl_m. def_id ) , 
328-             "impl method assumes more implied bounds than the corresponding trait method" , 
329-             |lint| lint, 
330-         ) ; 
331-     } ; 
332325
333326    // Check that all obligations are satisfied by the implementation's 
334327    // version. 
@@ -346,7 +339,7 @@ fn compare_method_predicate_entailment<'tcx>(
346339                ) 
347340                . map ( |( ) | { 
348341                    // If the skip-mode was successful, emit a lint. 
349-                     emit_implied_wf_lint ( ) ; 
342+                     emit_implied_wf_lint ( infcx . tcx ,  impl_m ,  impl_m_hir_id ,   vec ! [ ] ) ; 
350343                } ) ; 
351344            } 
352345            CheckImpliedWfMode :: Skip  => { 
@@ -382,8 +375,16 @@ fn compare_method_predicate_entailment<'tcx>(
382375                    CheckImpliedWfMode :: Skip , 
383376                ) 
384377                . map ( |( ) | { 
378+                     let  bad_args = extract_bad_args_for_implies_lint ( 
379+                         tcx, 
380+                         & errors, 
381+                         ( trait_m,  trait_sig) , 
382+                         // Unnormalized impl sig corresponds to the HIR types written 
383+                         ( impl_m,  unnormalized_impl_sig) , 
384+                         impl_m_hir_id, 
385+                     ) ; 
385386                    // If the skip-mode was successful, emit a lint. 
386-                     emit_implied_wf_lint ( ) ; 
387+                     emit_implied_wf_lint ( tcx ,  impl_m ,  impl_m_hir_id ,  bad_args ) ; 
387388                } ) ; 
388389            } 
389390            CheckImpliedWfMode :: Skip  => { 
@@ -400,6 +401,141 @@ fn compare_method_predicate_entailment<'tcx>(
400401    Ok ( ( ) ) 
401402} 
402403
404+ fn  extract_bad_args_for_implies_lint < ' tcx > ( 
405+     tcx :  TyCtxt < ' tcx > , 
406+     errors :  & [ infer:: RegionResolutionError < ' tcx > ] , 
407+     ( trait_m,  trait_sig) :  ( & ty:: AssocItem ,  ty:: FnSig < ' tcx > ) , 
408+     ( impl_m,  impl_sig) :  ( & ty:: AssocItem ,  ty:: FnSig < ' tcx > ) , 
409+     hir_id :  hir:: HirId , 
410+ )  -> Vec < ( Span ,  Option < String > ) >  { 
411+     let  mut  blame_generics = vec ! [ ] ; 
412+     for  error in  errors { 
413+         // Look for the subregion origin that contains an input/output type 
414+         let  origin = match  error { 
415+             infer:: RegionResolutionError :: ConcreteFailure ( o,  ..)  => o, 
416+             infer:: RegionResolutionError :: GenericBoundFailure ( o,  ..)  => o, 
417+             infer:: RegionResolutionError :: SubSupConflict ( _,  _,  o,  ..)  => o, 
418+             infer:: RegionResolutionError :: UpperBoundUniverseConflict ( ..,  o,  _)  => o, 
419+         } ; 
420+         // Extract (possible) input/output types from origin 
421+         match  origin { 
422+             infer:: SubregionOrigin :: Subtype ( trace)  => { 
423+                 if  let  Some ( ( a,  b) )  = trace. values . ty ( )  { 
424+                     blame_generics. extend ( [ a,  b] ) ; 
425+                 } 
426+             } 
427+             infer:: SubregionOrigin :: RelateParamBound ( _,  ty,  _)  => blame_generics. push ( * ty) , 
428+             infer:: SubregionOrigin :: ReferenceOutlivesReferent ( ty,  _)  => blame_generics. push ( * ty) , 
429+             _ => { } 
430+         } 
431+     } 
432+ 
433+     let  fn_decl = tcx. hir ( ) . fn_decl_by_hir_id ( hir_id) . unwrap ( ) ; 
434+     let  opt_ret_ty = match  fn_decl. output  { 
435+         hir:: FnRetTy :: DefaultReturn ( _)  => None , 
436+         hir:: FnRetTy :: Return ( ty)  => Some ( ty) , 
437+     } ; 
438+ 
439+     // Map late-bound regions from trait to impl, so the names are right. 
440+     let  mapping = std:: iter:: zip ( 
441+         tcx. fn_sig ( trait_m. def_id ) . bound_vars ( ) , 
442+         tcx. fn_sig ( impl_m. def_id ) . bound_vars ( ) , 
443+     ) 
444+     . filter_map ( |( impl_bv,  trait_bv) | { 
445+         if  let  ty:: BoundVariableKind :: Region ( impl_bv)  = impl_bv
446+             && let  ty:: BoundVariableKind :: Region ( trait_bv)  = trait_bv
447+         { 
448+             Some ( ( impl_bv,  trait_bv) ) 
449+         }  else  { 
450+             None 
451+         } 
452+     } ) 
453+     . collect ( ) ; 
454+ 
455+     // For each arg, see if it was in the "blame" of any of the region errors. 
456+     // If so, then try to produce a suggestion to replace the argument type with 
457+     // one from the trait. 
458+     let  mut  bad_args = vec ! [ ] ; 
459+     for  ( idx,  ( ty,  hir_ty) )  in 
460+         std:: iter:: zip ( impl_sig. inputs_and_output ,  fn_decl. inputs . iter ( ) . chain ( opt_ret_ty) ) 
461+             . enumerate ( ) 
462+     { 
463+         let  expected_ty = trait_sig. inputs_and_output [ idx] 
464+             . fold_with ( & mut  RemapLateBound  {  tcx,  mapping :  & mapping } ) ; 
465+         if  blame_generics. iter ( ) . any ( |blame| ty. contains ( * blame) )  { 
466+             let  expected_ty_sugg = expected_ty. to_string ( ) ; 
467+             bad_args. push ( ( 
468+                 hir_ty. span , 
469+                 // Only suggest something if it actually changed. 
470+                 ( expected_ty_sugg != ty. to_string ( ) ) . then_some ( expected_ty_sugg) , 
471+             ) ) ; 
472+         } 
473+     } 
474+ 
475+     bad_args
476+ } 
477+ 
478+ struct  RemapLateBound < ' a ,  ' tcx >  { 
479+     tcx :  TyCtxt < ' tcx > , 
480+     mapping :  & ' a  FxHashMap < ty:: BoundRegionKind ,  ty:: BoundRegionKind > , 
481+ } 
482+ 
483+ impl < ' tcx >  TypeFolder < ' tcx >  for  RemapLateBound < ' _ ,  ' tcx >  { 
484+     fn  tcx ( & self )  -> TyCtxt < ' tcx >  { 
485+         self . tcx 
486+     } 
487+ 
488+     fn  fold_region ( & mut  self ,  r :  ty:: Region < ' tcx > )  -> ty:: Region < ' tcx >  { 
489+         if  let  ty:: ReFree ( fr)  = * r { 
490+             self . tcx . mk_region ( ty:: ReFree ( ty:: FreeRegion  { 
491+                 bound_region :  self 
492+                     . mapping 
493+                     . get ( & fr. bound_region ) 
494+                     . copied ( ) 
495+                     . unwrap_or ( fr. bound_region ) , 
496+                 ..fr
497+             } ) ) 
498+         }  else  { 
499+             r
500+         } 
501+     } 
502+ } 
503+ 
504+ fn  emit_implied_wf_lint < ' tcx > ( 
505+     tcx :  TyCtxt < ' tcx > , 
506+     impl_m :  & ty:: AssocItem , 
507+     hir_id :  hir:: HirId , 
508+     bad_args :  Vec < ( Span ,  Option < String > ) > , 
509+ )  { 
510+     let  span:  MultiSpan  = if  bad_args. is_empty ( )  { 
511+         tcx. def_span ( impl_m. def_id ) . into ( ) 
512+     }  else  { 
513+         bad_args. iter ( ) . map ( |( span,  _) | * span) . collect :: < Vec < _ > > ( ) . into ( ) 
514+     } ; 
515+     tcx. struct_span_lint_hir ( 
516+         rustc_session:: lint:: builtin:: IMPLIED_BOUNDS_ENTAILMENT , 
517+         hir_id, 
518+         span, 
519+         "impl method assumes more implied bounds than the corresponding trait method" , 
520+         |lint| { 
521+             let  bad_args:  Vec < _ >  =
522+                 bad_args. into_iter ( ) . filter_map ( |( span,  sugg) | Some ( ( span,  sugg?) ) ) . collect ( ) ; 
523+             if  !bad_args. is_empty ( )  { 
524+                 lint. multipart_suggestion ( 
525+                     format ! ( 
526+                         "replace {} type{} to make the impl signature compatible" , 
527+                         pluralize!( "this" ,  bad_args. len( ) ) , 
528+                         pluralize!( bad_args. len( ) ) 
529+                     ) , 
530+                     bad_args, 
531+                     Applicability :: MaybeIncorrect , 
532+                 ) ; 
533+             } 
534+             lint
535+         } , 
536+     ) ; 
537+ } 
538+ 
403539#[ derive( Debug ,  PartialEq ,  Eq ) ]  
404540enum  CheckImpliedWfMode  { 
405541    /// Checks implied well-formedness of the impl method. If it fails, we will 
0 commit comments