@@ -9,14 +9,15 @@ use rustc_hir::intravisit;
99use rustc_hir:: { GenericParamKind , ImplItemKind , TraitItemKind } ;
1010use rustc_infer:: infer:: outlives:: env:: OutlivesEnvironment ;
1111use rustc_infer:: infer:: type_variable:: { TypeVariableOrigin , TypeVariableOriginKind } ;
12- use rustc_infer:: infer:: { self , TyCtxtInferExt } ;
12+ use rustc_infer:: infer:: { self , InferCtxt , TyCtxtInferExt } ;
1313use rustc_infer:: traits:: util;
1414use rustc_middle:: ty:: error:: { ExpectedFound , TypeError } ;
1515use rustc_middle:: ty:: util:: ExplicitSelf ;
16- use rustc_middle:: ty:: InternalSubsts ;
1716use rustc_middle:: ty:: {
18- self , AssocItem , DefIdTree , Ty , TypeFoldable , TypeFolder , TypeSuperFoldable , TypeVisitable ,
17+ self , AssocItem , DefIdTree , TraitRef , Ty , TypeFoldable , TypeFolder , TypeSuperFoldable ,
18+ TypeVisitable ,
1919} ;
20+ use rustc_middle:: ty:: { FnSig , InternalSubsts } ;
2021use rustc_middle:: ty:: { GenericParamDefKind , ToPredicate , TyCtxt } ;
2122use rustc_span:: Span ;
2223use rustc_trait_selection:: traits:: error_reporting:: TypeErrCtxtExt ;
@@ -303,102 +304,19 @@ fn compare_predicate_entailment<'tcx>(
303304 }
304305
305306 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) ;
307308
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,
396313 terr,
397- false ,
398- false ,
314+ ( trait_m, trait_fty) ,
315+ ( impl_m, impl_fty) ,
316+ & trait_sig,
317+ & impl_trait_ref,
399318 ) ;
400-
401- return Err ( diag. emit ( ) ) ;
319+ return Err ( emitted) ;
402320 }
403321
404322 // Check that all obligations are satisfied by the implementation's
@@ -424,6 +342,7 @@ fn compare_predicate_entailment<'tcx>(
424342 Ok ( ( ) )
425343}
426344
345+ #[ instrument( skip( tcx) , level = "debug" , ret) ]
427346pub fn collect_trait_impl_trait_tys < ' tcx > (
428347 tcx : TyCtxt < ' tcx > ,
429348 def_id : DefId ,
@@ -437,7 +356,7 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
437356
438357 let impl_m_hir_id = tcx. hir ( ) . local_def_id_to_hir_id ( impl_m. def_id . expect_local ( ) ) ;
439358 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 (
441360 return_span,
442361 impl_m_hir_id,
443362 ObligationCauseCode :: CompareImplItemObligation {
@@ -514,23 +433,35 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
514433 }
515434 }
516435
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+
517441 // Unify the whole function signature. We need to do this to fully infer
518442 // the lifetimes of the return type, but do this after unifying just the
519443 // return types, since we want to avoid duplicating errors from
520444 // `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) {
525446 Ok ( infer:: InferOk { value : ( ) , obligations } ) => {
526447 ocx. register_obligations ( obligations) ;
527448 }
528449 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,
532463 ) ;
533- return Err ( guar ) ;
464+ return Err ( emitted ) ;
534465 }
535466 }
536467
@@ -690,6 +621,112 @@ impl<'tcx> TypeFolder<'tcx> for ImplTraitInTraitCollector<'_, 'tcx> {
690621 }
691622}
692623
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+
693730fn check_region_bounds_on_impl_item < ' tcx > (
694731 tcx : TyCtxt < ' tcx > ,
695732 impl_m : & ty:: AssocItem ,
0 commit comments