@@ -2,11 +2,14 @@ use crate::errors::RegionOriginNote;
2
2
use crate :: infer:: error_reporting:: { note_and_explain_region, TypeErrCtxt } ;
3
3
use crate :: infer:: { self , SubregionOrigin } ;
4
4
use rustc_errors:: {
5
- fluent, struct_span_err, AddToDiagnostic , Diagnostic , DiagnosticBuilder , ErrorGuaranteed ,
5
+ fluent, struct_span_err, AddToDiagnostic , Applicability , Diagnostic , DiagnosticBuilder ,
6
+ ErrorGuaranteed ,
6
7
} ;
8
+ use rustc_hir:: def_id:: { DefId , LocalDefId } ;
7
9
use rustc_middle:: traits:: ObligationCauseCode ;
8
10
use 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;
10
13
11
14
use super :: ObligationCauseAsDiagArg ;
12
15
@@ -313,55 +316,38 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
313
316
) ;
314
317
err
315
318
}
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 (
318
321
span,
319
322
impl_item_def_id,
320
323
trait_item_def_id,
321
324
& 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
+ }
323
338
infer:: CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => {
324
339
let mut err = self . report_concrete_failure ( * parent, sub, sup) ;
325
-
326
340
let trait_item_span = self . tcx . def_span ( trait_item_def_id) ;
327
341
let item_name = self . tcx . item_name ( impl_item_def_id. to_def_id ( ) ) ;
328
342
err. span_label (
329
343
trait_item_span,
330
344
format ! ( "definition of `{}` from trait" , item_name) ,
331
345
) ;
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
+ ) ;
365
351
err
366
352
}
367
353
infer:: AscribeUserTypeProvePredicate ( span) => {
@@ -388,6 +374,65 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
388
374
}
389
375
}
390
376
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
+
391
436
pub ( super ) fn report_placeholder_failure (
392
437
& self ,
393
438
placeholder_origin : SubregionOrigin < ' tcx > ,
0 commit comments