@@ -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,43 @@ 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 self
328+ . tcx
329+ . hir ( )
330+ . get_generics ( impl_item_def_id)
331+ . unwrap ( )
332+ . where_clause_span
333+ . contains ( span)
334+ {
335+ self . suggest_copy_trait_method_bounds (
336+ trait_item_def_id,
337+ impl_item_def_id,
338+ & mut err,
339+ ) ;
340+ }
341+ err
342+ }
323343 infer:: CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => {
324344 let mut err = self . report_concrete_failure ( * parent, sub, sup) ;
325-
326345 let trait_item_span = self . tcx . def_span ( trait_item_def_id) ;
327346 let item_name = self . tcx . item_name ( impl_item_def_id. to_def_id ( ) ) ;
328347 err. span_label (
329348 trait_item_span,
330349 format ! ( "definition of `{}` from trait" , item_name) ,
331350 ) ;
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-
351+ self . suggest_copy_trait_method_bounds (
352+ trait_item_def_id,
353+ impl_item_def_id,
354+ & mut err,
355+ ) ;
365356 err
366357 }
367358 infer:: AscribeUserTypeProvePredicate ( span) => {
@@ -388,6 +379,66 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
388379 }
389380 }
390381
382+ pub fn suggest_copy_trait_method_bounds (
383+ & self ,
384+ trait_item_def_id : DefId ,
385+ impl_item_def_id : LocalDefId ,
386+ err : & mut Diagnostic ,
387+ ) {
388+ // FIXME(compiler-errors): Right now this is only being used for region
389+ // predicate mismatches. Ideally, we'd use it for *all* predicate mismatches,
390+ // but right now it's not really very smart when it comes to implicit `Sized`
391+ // predicates and bounds on the trait itself.
392+
393+ let impl_def_id =
394+ self . tcx . associated_item ( impl_item_def_id) . impl_container ( self . tcx ) . unwrap ( ) ;
395+ let trait_substs = self
396+ . tcx
397+ . impl_trait_ref ( impl_def_id)
398+ . unwrap ( )
399+ // Replace the explicit self type with `Self` for better suggestion rendering
400+ . with_self_ty ( self . tcx , self . tcx . mk_ty_param ( 0 , kw:: SelfUpper ) )
401+ . substs ;
402+ let trait_item_substs =
403+ ty:: InternalSubsts :: identity_for_item ( self . tcx , impl_item_def_id. to_def_id ( ) )
404+ . rebase_onto ( self . tcx , impl_def_id, trait_substs) ;
405+
406+ let mut is_suggestable = true ;
407+ let trait_predicates = self
408+ . tcx
409+ . bound_explicit_predicates_of ( trait_item_def_id)
410+ . map_bound ( |p| p. predicates )
411+ . subst_iter_copied ( self . tcx , trait_item_substs)
412+ . map ( |( pred, _) | {
413+ if !pred. is_suggestable ( self . tcx , false ) {
414+ is_suggestable = false ;
415+ }
416+ pred. to_string ( )
417+ } )
418+ . collect :: < Vec < _ > > ( ) ;
419+
420+ let generics = self . tcx . hir ( ) . get_generics ( impl_item_def_id) . unwrap ( ) ;
421+
422+ if is_suggestable {
423+ if trait_predicates. is_empty ( ) {
424+ err. span_suggestion_verbose (
425+ generics. where_clause_span ,
426+ "remove the `where` clause" ,
427+ String :: new ( ) ,
428+ Applicability :: MachineApplicable ,
429+ ) ;
430+ } else {
431+ let space = if generics. where_clause_span . is_empty ( ) { " " } else { "" } ;
432+ err. span_suggestion_verbose (
433+ generics. where_clause_span ,
434+ "copy the `where` clause predicates from the trait" ,
435+ format ! ( "{space}where {}" , trait_predicates. join( ", " ) ) ,
436+ Applicability :: MachineApplicable ,
437+ ) ;
438+ }
439+ }
440+ }
441+
391442 pub ( super ) fn report_placeholder_failure (
392443 & self ,
393444 placeholder_origin : SubregionOrigin < ' tcx > ,
0 commit comments