@@ -2,11 +2,14 @@ use crate::errors::RegionOriginNote;
22use crate :: infer:: error_reporting:: { note_and_explain_region, TypeErrCtxt } ;
33use crate :: infer:: { self , SubregionOrigin } ;
44use rustc_errors:: {
5- fluent, struct_span_err, AddToDiagnostic , Diagnostic , DiagnosticBuilder , ErrorGuaranteed ,
5+ fluent, struct_span_err, AddToDiagnostic , Applicability , Diagnostic , DiagnosticBuilder ,
6+ ErrorGuaranteed ,
67} ;
8+ use rustc_hir:: def_id:: { DefId , LocalDefId } ;
79use rustc_middle:: traits:: ObligationCauseCode ;
810use rustc_middle:: ty:: error:: TypeError ;
9- use rustc_middle:: ty:: { self , Region } ;
11+ use rustc_middle:: ty:: { self , IsSuggestable , Region } ;
12+ use rustc_span:: symbol:: kw;
1013
1114use super :: ObligationCauseAsDiagArg ;
1215
@@ -313,55 +316,38 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
313316 ) ;
314317 err
315318 }
316- infer:: CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => self
317- . report_extra_impl_obligation (
319+ infer:: CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => {
320+ let mut err = self . report_extra_impl_obligation (
318321 span,
319322 impl_item_def_id,
320323 trait_item_def_id,
321324 & format ! ( "`{}: {}`" , sup, sub) ,
322- ) ,
325+ ) ;
326+ // We should only suggest rewriting the `where` clause if the predicate is within that `where` clause
327+ if let Some ( generics) = self . tcx . hir ( ) . get_generics ( impl_item_def_id)
328+ && generics. where_clause_span . contains ( span)
329+ {
330+ self . suggest_copy_trait_method_bounds (
331+ trait_item_def_id,
332+ impl_item_def_id,
333+ & mut err,
334+ ) ;
335+ }
336+ err
337+ }
323338 infer:: CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => {
324339 let mut err = self . report_concrete_failure ( * parent, sub, sup) ;
325-
326340 let trait_item_span = self . tcx . def_span ( trait_item_def_id) ;
327341 let item_name = self . tcx . item_name ( impl_item_def_id. to_def_id ( ) ) ;
328342 err. span_label (
329343 trait_item_span,
330344 format ! ( "definition of `{}` from trait" , item_name) ,
331345 ) ;
332-
333- let trait_predicates = self . tcx . explicit_predicates_of ( trait_item_def_id) ;
334- let impl_predicates = self . tcx . explicit_predicates_of ( impl_item_def_id) ;
335-
336- let impl_predicates: rustc_data_structures:: fx:: FxHashSet < _ > =
337- impl_predicates. predicates . into_iter ( ) . map ( |( pred, _) | pred) . collect ( ) ;
338- let clauses: Vec < _ > = trait_predicates
339- . predicates
340- . into_iter ( )
341- . filter ( |& ( pred, _) | !impl_predicates. contains ( pred) )
342- . map ( |( pred, _) | format ! ( "{}" , pred) )
343- . collect ( ) ;
344-
345- if !clauses. is_empty ( ) {
346- let generics = self . tcx . hir ( ) . get_generics ( impl_item_def_id) . unwrap ( ) ;
347- let where_clause_span = generics. tail_span_for_predicate_suggestion ( ) ;
348-
349- let suggestion = format ! (
350- "{} {}" ,
351- generics. add_where_or_trailing_comma( ) ,
352- clauses. join( ", " ) ,
353- ) ;
354- err. span_suggestion (
355- where_clause_span,
356- & format ! (
357- "try copying {} from the trait" ,
358- if clauses. len( ) > 1 { "these clauses" } else { "this clause" }
359- ) ,
360- suggestion,
361- rustc_errors:: Applicability :: MaybeIncorrect ,
362- ) ;
363- }
364-
346+ self . suggest_copy_trait_method_bounds (
347+ trait_item_def_id,
348+ impl_item_def_id,
349+ & mut err,
350+ ) ;
365351 err
366352 }
367353 infer:: AscribeUserTypeProvePredicate ( span) => {
@@ -388,6 +374,65 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
388374 }
389375 }
390376
377+ pub fn suggest_copy_trait_method_bounds (
378+ & self ,
379+ trait_item_def_id : DefId ,
380+ impl_item_def_id : LocalDefId ,
381+ err : & mut Diagnostic ,
382+ ) {
383+ // FIXME(compiler-errors): Right now this is only being used for region
384+ // predicate mismatches. Ideally, we'd use it for *all* predicate mismatches,
385+ // but right now it's not really very smart when it comes to implicit `Sized`
386+ // predicates and bounds on the trait itself.
387+
388+ let Some ( impl_def_id) =
389+ self . tcx . associated_item ( impl_item_def_id) . impl_container ( self . tcx ) else { return ; } ;
390+ let Some ( trait_ref) = self
391+ . tcx
392+ . impl_trait_ref ( impl_def_id)
393+ else { return ; } ;
394+ let trait_substs = trait_ref
395+ // Replace the explicit self type with `Self` for better suggestion rendering
396+ . with_self_ty ( self . tcx , self . tcx . mk_ty_param ( 0 , kw:: SelfUpper ) )
397+ . substs ;
398+ let trait_item_substs =
399+ ty:: InternalSubsts :: identity_for_item ( self . tcx , impl_item_def_id. to_def_id ( ) )
400+ . rebase_onto ( self . tcx , impl_def_id, trait_substs) ;
401+
402+ let Ok ( trait_predicates) = self
403+ . tcx
404+ . bound_explicit_predicates_of ( trait_item_def_id)
405+ . map_bound ( |p| p. predicates )
406+ . subst_iter_copied ( self . tcx , trait_item_substs)
407+ . map ( |( pred, _) | {
408+ if pred. is_suggestable ( self . tcx , false ) {
409+ Ok ( pred. to_string ( ) )
410+ } else {
411+ Err ( ( ) )
412+ }
413+ } )
414+ . collect :: < Result < Vec < _ > , ( ) > > ( ) else { return ; } ;
415+
416+ let Some ( generics) = self . tcx . hir ( ) . get_generics ( impl_item_def_id) else { return ; } ;
417+
418+ if trait_predicates. is_empty ( ) {
419+ err. span_suggestion_verbose (
420+ generics. where_clause_span ,
421+ "remove the `where` clause" ,
422+ String :: new ( ) ,
423+ Applicability :: MachineApplicable ,
424+ ) ;
425+ } else {
426+ let space = if generics. where_clause_span . is_empty ( ) { " " } else { "" } ;
427+ err. span_suggestion_verbose (
428+ generics. where_clause_span ,
429+ "copy the `where` clause predicates from the trait" ,
430+ format ! ( "{space}where {}" , trait_predicates. join( ", " ) ) ,
431+ Applicability :: MachineApplicable ,
432+ ) ;
433+ }
434+ }
435+
391436 pub ( super ) fn report_placeholder_failure (
392437 & self ,
393438 placeholder_origin : SubregionOrigin < ' tcx > ,
0 commit comments