@@ -9,14 +9,15 @@ use rustc_hir::intravisit;
9
9
use rustc_hir:: { GenericParamKind , ImplItemKind , TraitItemKind } ;
10
10
use rustc_infer:: infer:: outlives:: env:: OutlivesEnvironment ;
11
11
use rustc_infer:: infer:: type_variable:: { TypeVariableOrigin , TypeVariableOriginKind } ;
12
- use rustc_infer:: infer:: { self , TyCtxtInferExt } ;
12
+ use rustc_infer:: infer:: { self , InferCtxt , TyCtxtInferExt } ;
13
13
use rustc_infer:: traits:: util;
14
14
use rustc_middle:: ty:: error:: { ExpectedFound , TypeError } ;
15
15
use rustc_middle:: ty:: util:: ExplicitSelf ;
16
- use rustc_middle:: ty:: InternalSubsts ;
17
16
use rustc_middle:: ty:: {
18
- self , AssocItem , DefIdTree , Ty , TypeFoldable , TypeFolder , TypeSuperFoldable , TypeVisitable ,
17
+ self , AssocItem , DefIdTree , TraitRef , Ty , TypeFoldable , TypeFolder , TypeSuperFoldable ,
18
+ TypeVisitable ,
19
19
} ;
20
+ use rustc_middle:: ty:: { FnSig , InternalSubsts } ;
20
21
use rustc_middle:: ty:: { GenericParamDefKind , ToPredicate , TyCtxt } ;
21
22
use rustc_span:: Span ;
22
23
use rustc_trait_selection:: traits:: error_reporting:: TypeErrCtxtExt ;
@@ -303,102 +304,19 @@ fn compare_predicate_entailment<'tcx>(
303
304
}
304
305
305
306
if let Err ( terr) = result {
306
- debug ! ( "sub_types failed: impl ty {:?}, trait ty {:?}" , impl_fty, trait_fty) ;
307
+ debug ! ( ?terr , "sub_types failed: impl ty {:?}, trait ty {:?}" , impl_fty, trait_fty) ;
307
308
308
- let ( impl_err_span, trait_err_span) =
309
- extract_spans_for_error_reporting ( & infcx, terr, & cause, impl_m, trait_m) ;
310
-
311
- cause. span = impl_err_span;
312
-
313
- let mut diag = struct_span_err ! (
314
- tcx. sess,
315
- cause. span( ) ,
316
- E0053 ,
317
- "method `{}` has an incompatible type for trait" ,
318
- trait_m. name
319
- ) ;
320
- match & terr {
321
- TypeError :: ArgumentMutability ( 0 ) | TypeError :: ArgumentSorts ( _, 0 )
322
- if trait_m. fn_has_self_parameter =>
323
- {
324
- let ty = trait_sig. inputs ( ) [ 0 ] ;
325
- let sugg = match ExplicitSelf :: determine ( ty, |_| ty == impl_trait_ref. self_ty ( ) ) {
326
- ExplicitSelf :: ByValue => "self" . to_owned ( ) ,
327
- ExplicitSelf :: ByReference ( _, hir:: Mutability :: Not ) => "&self" . to_owned ( ) ,
328
- ExplicitSelf :: ByReference ( _, hir:: Mutability :: Mut ) => "&mut self" . to_owned ( ) ,
329
- _ => format ! ( "self: {ty}" ) ,
330
- } ;
331
-
332
- // When the `impl` receiver is an arbitrary self type, like `self: Box<Self>`, the
333
- // span points only at the type `Box<Self`>, but we want to cover the whole
334
- // argument pattern and type.
335
- let span = match tcx. hir ( ) . expect_impl_item ( impl_m. def_id . expect_local ( ) ) . kind {
336
- ImplItemKind :: Fn ( ref sig, body) => tcx
337
- . hir ( )
338
- . body_param_names ( body)
339
- . zip ( sig. decl . inputs . iter ( ) )
340
- . map ( |( param, ty) | param. span . to ( ty. span ) )
341
- . next ( )
342
- . unwrap_or ( impl_err_span) ,
343
- _ => bug ! ( "{:?} is not a method" , impl_m) ,
344
- } ;
345
-
346
- diag. span_suggestion (
347
- span,
348
- "change the self-receiver type to match the trait" ,
349
- sugg,
350
- Applicability :: MachineApplicable ,
351
- ) ;
352
- }
353
- TypeError :: ArgumentMutability ( i) | TypeError :: ArgumentSorts ( _, i) => {
354
- if trait_sig. inputs ( ) . len ( ) == * i {
355
- // Suggestion to change output type. We do not suggest in `async` functions
356
- // to avoid complex logic or incorrect output.
357
- match tcx. hir ( ) . expect_impl_item ( impl_m. def_id . expect_local ( ) ) . kind {
358
- ImplItemKind :: Fn ( ref sig, _)
359
- if sig. header . asyncness == hir:: IsAsync :: NotAsync =>
360
- {
361
- let msg = "change the output type to match the trait" ;
362
- let ap = Applicability :: MachineApplicable ;
363
- match sig. decl . output {
364
- hir:: FnRetTy :: DefaultReturn ( sp) => {
365
- let sugg = format ! ( "-> {} " , trait_sig. output( ) ) ;
366
- diag. span_suggestion_verbose ( sp, msg, sugg, ap) ;
367
- }
368
- hir:: FnRetTy :: Return ( hir_ty) => {
369
- let sugg = trait_sig. output ( ) ;
370
- diag. span_suggestion ( hir_ty. span , msg, sugg, ap) ;
371
- }
372
- } ;
373
- }
374
- _ => { }
375
- } ;
376
- } else if let Some ( trait_ty) = trait_sig. inputs ( ) . get ( * i) {
377
- diag. span_suggestion (
378
- impl_err_span,
379
- "change the parameter type to match the trait" ,
380
- trait_ty,
381
- Applicability :: MachineApplicable ,
382
- ) ;
383
- }
384
- }
385
- _ => { }
386
- }
387
-
388
- infcx. err_ctxt ( ) . note_type_err (
389
- & mut diag,
390
- & cause,
391
- trait_err_span. map ( |sp| ( sp, "type in trait" . to_owned ( ) ) ) ,
392
- Some ( infer:: ValuePairs :: Terms ( ExpectedFound {
393
- expected : trait_fty. into ( ) ,
394
- found : impl_fty. into ( ) ,
395
- } ) ) ,
309
+ let emitted = report_trait_method_mismatch (
310
+ tcx,
311
+ & mut cause,
312
+ & infcx,
396
313
terr,
397
- false ,
398
- false ,
314
+ ( trait_m, trait_fty) ,
315
+ ( impl_m, impl_fty) ,
316
+ & trait_sig,
317
+ & impl_trait_ref,
399
318
) ;
400
-
401
- return Err ( diag. emit ( ) ) ;
319
+ return Err ( emitted) ;
402
320
}
403
321
404
322
// Check that all obligations are satisfied by the implementation's
@@ -424,6 +342,7 @@ fn compare_predicate_entailment<'tcx>(
424
342
Ok ( ( ) )
425
343
}
426
344
345
+ #[ instrument( skip( tcx) , level = "debug" , ret) ]
427
346
pub fn collect_trait_impl_trait_tys < ' tcx > (
428
347
tcx : TyCtxt < ' tcx > ,
429
348
def_id : DefId ,
@@ -437,7 +356,7 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
437
356
438
357
let impl_m_hir_id = tcx. hir ( ) . local_def_id_to_hir_id ( impl_m. def_id . expect_local ( ) ) ;
439
358
let return_span = tcx. hir ( ) . fn_decl_by_hir_id ( impl_m_hir_id) . unwrap ( ) . output . span ( ) ;
440
- let cause = ObligationCause :: new (
359
+ let mut cause = ObligationCause :: new (
441
360
return_span,
442
361
impl_m_hir_id,
443
362
ObligationCauseCode :: CompareImplItemObligation {
@@ -514,23 +433,35 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
514
433
}
515
434
}
516
435
436
+ debug ! ( ?trait_sig, ?impl_sig, "equating function signatures" ) ;
437
+
438
+ let trait_fty = tcx. mk_fn_ptr ( ty:: Binder :: dummy ( trait_sig) ) ;
439
+ let impl_fty = tcx. mk_fn_ptr ( ty:: Binder :: dummy ( impl_sig) ) ;
440
+
517
441
// Unify the whole function signature. We need to do this to fully infer
518
442
// the lifetimes of the return type, but do this after unifying just the
519
443
// return types, since we want to avoid duplicating errors from
520
444
// `compare_predicate_entailment`.
521
- match infcx
522
- . at ( & cause, param_env)
523
- . eq ( tcx. mk_fn_ptr ( ty:: Binder :: dummy ( trait_sig) ) , tcx. mk_fn_ptr ( ty:: Binder :: dummy ( impl_sig) ) )
524
- {
445
+ match infcx. at ( & cause, param_env) . eq ( trait_fty, impl_fty) {
525
446
Ok ( infer:: InferOk { value : ( ) , obligations } ) => {
526
447
ocx. register_obligations ( obligations) ;
527
448
}
528
449
Err ( terr) => {
529
- let guar = tcx. sess . delay_span_bug (
530
- return_span,
531
- format ! ( "could not unify `{trait_sig}` and `{impl_sig}`: {terr:?}" ) ,
450
+ // This function gets called during `compare_predicate_entailment` when normalizing a
451
+ // signature that contains RPITIT. When the method signatures don't match, we have to
452
+ // emit an error now because `compare_predicate_entailment` will not report the error
453
+ // when normalization fails.
454
+ let emitted = report_trait_method_mismatch (
455
+ tcx,
456
+ & mut cause,
457
+ infcx,
458
+ terr,
459
+ ( trait_m, trait_fty) ,
460
+ ( impl_m, impl_fty) ,
461
+ & trait_sig,
462
+ & impl_trait_ref,
532
463
) ;
533
- return Err ( guar ) ;
464
+ return Err ( emitted ) ;
534
465
}
535
466
}
536
467
@@ -690,6 +621,112 @@ impl<'tcx> TypeFolder<'tcx> for ImplTraitInTraitCollector<'_, 'tcx> {
690
621
}
691
622
}
692
623
624
+ fn report_trait_method_mismatch < ' tcx > (
625
+ tcx : TyCtxt < ' tcx > ,
626
+ cause : & mut ObligationCause < ' tcx > ,
627
+ infcx : & InferCtxt < ' tcx > ,
628
+ terr : TypeError < ' tcx > ,
629
+ ( trait_m, trait_fty) : ( & AssocItem , Ty < ' tcx > ) ,
630
+ ( impl_m, impl_fty) : ( & AssocItem , Ty < ' tcx > ) ,
631
+ trait_sig : & FnSig < ' tcx > ,
632
+ impl_trait_ref : & TraitRef < ' tcx > ,
633
+ ) -> ErrorGuaranteed {
634
+ let ( impl_err_span, trait_err_span) =
635
+ extract_spans_for_error_reporting ( & infcx, terr, & cause, impl_m, trait_m) ;
636
+
637
+ cause. span = impl_err_span;
638
+
639
+ let mut diag = struct_span_err ! (
640
+ tcx. sess,
641
+ cause. span( ) ,
642
+ E0053 ,
643
+ "method `{}` has an incompatible type for trait" ,
644
+ trait_m. name
645
+ ) ;
646
+ match & terr {
647
+ TypeError :: ArgumentMutability ( 0 ) | TypeError :: ArgumentSorts ( _, 0 )
648
+ if trait_m. fn_has_self_parameter =>
649
+ {
650
+ let ty = trait_sig. inputs ( ) [ 0 ] ;
651
+ let sugg = match ExplicitSelf :: determine ( ty, |_| ty == impl_trait_ref. self_ty ( ) ) {
652
+ ExplicitSelf :: ByValue => "self" . to_owned ( ) ,
653
+ ExplicitSelf :: ByReference ( _, hir:: Mutability :: Not ) => "&self" . to_owned ( ) ,
654
+ ExplicitSelf :: ByReference ( _, hir:: Mutability :: Mut ) => "&mut self" . to_owned ( ) ,
655
+ _ => format ! ( "self: {ty}" ) ,
656
+ } ;
657
+
658
+ // When the `impl` receiver is an arbitrary self type, like `self: Box<Self>`, the
659
+ // span points only at the type `Box<Self`>, but we want to cover the whole
660
+ // argument pattern and type.
661
+ let span = match tcx. hir ( ) . expect_impl_item ( impl_m. def_id . expect_local ( ) ) . kind {
662
+ ImplItemKind :: Fn ( ref sig, body) => tcx
663
+ . hir ( )
664
+ . body_param_names ( body)
665
+ . zip ( sig. decl . inputs . iter ( ) )
666
+ . map ( |( param, ty) | param. span . to ( ty. span ) )
667
+ . next ( )
668
+ . unwrap_or ( impl_err_span) ,
669
+ _ => bug ! ( "{:?} is not a method" , impl_m) ,
670
+ } ;
671
+
672
+ diag. span_suggestion (
673
+ span,
674
+ "change the self-receiver type to match the trait" ,
675
+ sugg,
676
+ Applicability :: MachineApplicable ,
677
+ ) ;
678
+ }
679
+ TypeError :: ArgumentMutability ( i) | TypeError :: ArgumentSorts ( _, i) => {
680
+ if trait_sig. inputs ( ) . len ( ) == * i {
681
+ // Suggestion to change output type. We do not suggest in `async` functions
682
+ // to avoid complex logic or incorrect output.
683
+ match tcx. hir ( ) . expect_impl_item ( impl_m. def_id . expect_local ( ) ) . kind {
684
+ ImplItemKind :: Fn ( ref sig, _)
685
+ if sig. header . asyncness == hir:: IsAsync :: NotAsync =>
686
+ {
687
+ let msg = "change the output type to match the trait" ;
688
+ let ap = Applicability :: MachineApplicable ;
689
+ match sig. decl . output {
690
+ hir:: FnRetTy :: DefaultReturn ( sp) => {
691
+ let sugg = format ! ( "-> {} " , trait_sig. output( ) ) ;
692
+ diag. span_suggestion_verbose ( sp, msg, sugg, ap) ;
693
+ }
694
+ hir:: FnRetTy :: Return ( hir_ty) => {
695
+ let sugg = trait_sig. output ( ) ;
696
+ diag. span_suggestion ( hir_ty. span , msg, sugg, ap) ;
697
+ }
698
+ } ;
699
+ }
700
+ _ => { }
701
+ } ;
702
+ } else if let Some ( trait_ty) = trait_sig. inputs ( ) . get ( * i) {
703
+ diag. span_suggestion (
704
+ impl_err_span,
705
+ "change the parameter type to match the trait" ,
706
+ trait_ty,
707
+ Applicability :: MachineApplicable ,
708
+ ) ;
709
+ }
710
+ }
711
+ _ => { }
712
+ }
713
+
714
+ infcx. err_ctxt ( ) . note_type_err (
715
+ & mut diag,
716
+ & cause,
717
+ trait_err_span. map ( |sp| ( sp, "type in trait" . to_owned ( ) ) ) ,
718
+ Some ( infer:: ValuePairs :: Terms ( ExpectedFound {
719
+ expected : trait_fty. into ( ) ,
720
+ found : impl_fty. into ( ) ,
721
+ } ) ) ,
722
+ terr,
723
+ false ,
724
+ false ,
725
+ ) ;
726
+
727
+ return diag. emit ( ) ;
728
+ }
729
+
693
730
fn check_region_bounds_on_impl_item < ' tcx > (
694
731
tcx : TyCtxt < ' tcx > ,
695
732
impl_m : & ty:: AssocItem ,
0 commit comments