@@ -21,7 +21,7 @@ use rustc_middle::ty::visit::TypeVisitableExt;
2121use rustc_middle:: ty:: { self , IsSuggestable , Ty , TyCtxt } ;
2222use rustc_middle:: { bug, span_bug} ;
2323use rustc_session:: Session ;
24- use rustc_span:: { DUMMY_SP , Ident , Span , kw, sym} ;
24+ use rustc_span:: { DUMMY_SP , Ident , Span , Symbol , kw, sym} ;
2525use rustc_trait_selection:: error_reporting:: infer:: { FailureCode , ObligationCauseExt } ;
2626use rustc_trait_selection:: infer:: InferCtxtExt ;
2727use rustc_trait_selection:: traits:: { self , ObligationCauseCode , ObligationCtxt , SelectionContext } ;
@@ -2414,11 +2414,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
24142414 } )
24152415 {
24162416 let Some ( generic_param) = generic_param else {
2417- spans. push_span_label ( param. span , "" ) ;
2417+ spans. push_span_label ( param. span ( ) , "" ) ;
24182418 continue ;
24192419 } ;
24202420
2421- let other_params_matched: Vec < ( ExpectedIdx , & hir :: Param < ' _ > ) > =
2421+ let other_params_matched: Vec < ( ExpectedIdx , FnParam < ' _ > ) > =
24222422 params_with_generics
24232423 . iter_enumerated ( )
24242424 . filter ( |& ( other_idx, & ( other_generic_param, _) ) | {
@@ -2447,9 +2447,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
24472447 let other_param_matched_names: Vec < String > = other_params_matched
24482448 . iter ( )
24492449 . map ( |( idx, other_param) | {
2450- if let hir:: PatKind :: Binding ( _, _, ident, _) = other_param. pat . kind
2451- {
2452- format ! ( "`{ident}`" )
2450+ if let Some ( name) = other_param. name ( ) {
2451+ format ! ( "`{name}`" )
24532452 } else {
24542453 format ! ( "parameter #{}" , idx. as_u32( ) + 1 )
24552454 }
@@ -2462,7 +2461,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
24622461
24632462 if matched_inputs[ idx] . is_some ( ) {
24642463 spans. push_span_label (
2465- param. span ,
2464+ param. span ( ) ,
24662465 format ! (
24672466 "{} need{} to match the {} type of this parameter" ,
24682467 listify( & other_param_matched_names, |n| n. to_string( ) )
@@ -2477,7 +2476,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
24772476 ) ;
24782477 } else {
24792478 spans. push_span_label (
2480- param. span ,
2479+ param. span ( ) ,
24812480 format ! (
24822481 "this parameter needs to match the {} type of {}" ,
24832482 matched_ty,
@@ -2488,7 +2487,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
24882487 }
24892488 generics_with_unmatched_params. push ( generic_param) ;
24902489 } else {
2491- spans. push_span_label ( param. span , "" ) ;
2490+ spans. push_span_label ( param. span ( ) , "" ) ;
24922491 }
24932492 }
24942493
@@ -2515,8 +2514,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
25152514 }
25162515 } )
25172516 . map ( |( idx, & ( _, param) ) | {
2518- if let hir :: PatKind :: Binding ( _ , _ , ident , _ ) = param. pat . kind {
2519- format ! ( "`{ident }`" )
2517+ if let Some ( name ) = param. name ( ) {
2518+ format ! ( "`{name }`" )
25202519 } else {
25212520 format ! ( "parameter #{}" , idx. as_u32( ) + 1 )
25222521 }
@@ -2673,35 +2672,56 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
26732672 & self ,
26742673 def_id : DefId ,
26752674 is_method : bool ,
2676- ) -> Option < IndexVec < ExpectedIdx , ( Option < & hir:: GenericParam < ' _ > > , & hir:: Param < ' _ > ) > > {
2677- let fn_node = self . tcx . hir ( ) . get_if_local ( def_id) ?;
2678- let fn_decl = fn_node. fn_decl ( ) ?;
2679- let generic_params = fn_node. generics ( ) ?. params ;
2680-
2681- // Remove both the receiver and variadic arguments. Neither can have an unmatched generic
2682- // parameter.
2683- let params = self . tcx . hir ( ) . body ( fn_node. body_id ( ) ?) . params ;
2684- let params = params. get ( is_method as usize ..params. len ( ) - fn_decl. c_variadic as usize ) ?;
2685- let fn_inputs = fn_decl. inputs . get ( is_method as usize ..) ?;
2686- debug_assert_eq ! ( params. len( ) , fn_inputs. len( ) ) ;
2687-
2688- Some (
2689- fn_inputs
2690- . into_iter ( )
2691- . map ( |param| {
2692- if let hir:: TyKind :: Path ( QPath :: Resolved (
2693- _,
2694- & hir:: Path { res : Res :: Def ( _, res_def_id) , .. } ,
2695- ) ) = param. kind
2696- {
2697- generic_params. iter ( ) . find ( |param| param. def_id . to_def_id ( ) == res_def_id)
2698- } else {
2699- None
2700- }
2701- } )
2702- . zip ( params)
2703- . collect ( ) ,
2704- )
2675+ ) -> Option < IndexVec < ExpectedIdx , ( Option < & hir:: GenericParam < ' _ > > , FnParam < ' _ > ) > > {
2676+ let ( sig, generics, body_id, param_names) = match self . tcx . hir ( ) . get_if_local ( def_id) ? {
2677+ hir:: Node :: TraitItem ( & hir:: TraitItem {
2678+ generics,
2679+ kind : hir:: TraitItemKind :: Fn ( sig, trait_fn) ,
2680+ ..
2681+ } ) => match trait_fn {
2682+ hir:: TraitFn :: Required ( params) => ( sig, generics, None , Some ( params) ) ,
2683+ hir:: TraitFn :: Provided ( body) => ( sig, generics, Some ( body) , None ) ,
2684+ } ,
2685+ hir:: Node :: ImplItem ( & hir:: ImplItem {
2686+ generics,
2687+ kind : hir:: ImplItemKind :: Fn ( sig, body) ,
2688+ ..
2689+ } )
2690+ | hir:: Node :: Item ( & hir:: Item {
2691+ kind : hir:: ItemKind :: Fn { sig, generics, body, .. } ,
2692+ ..
2693+ } ) => ( sig, generics, Some ( body) , None ) ,
2694+ _ => return None ,
2695+ } ;
2696+
2697+ // Make sure to remove both the receiver and variadic argument. Both are removed
2698+ // when matching parameter types.
2699+ let fn_inputs = sig. decl . inputs . get ( is_method as usize ..) ?. iter ( ) . map ( |param| {
2700+ if let hir:: TyKind :: Path ( QPath :: Resolved (
2701+ _,
2702+ & hir:: Path { res : Res :: Def ( _, res_def_id) , .. } ,
2703+ ) ) = param. kind
2704+ {
2705+ generics. params . iter ( ) . find ( |param| param. def_id . to_def_id ( ) == res_def_id)
2706+ } else {
2707+ None
2708+ }
2709+ } ) ;
2710+ match ( body_id, param_names) {
2711+ ( Some ( _) , Some ( _) ) | ( None , None ) => unreachable ! ( ) ,
2712+ ( Some ( body) , None ) => {
2713+ let params = self . tcx . hir ( ) . body ( body) . params ;
2714+ let params =
2715+ params. get ( is_method as usize ..params. len ( ) - sig. decl . c_variadic as usize ) ?;
2716+ debug_assert_eq ! ( params. len( ) , fn_inputs. len( ) ) ;
2717+ Some ( fn_inputs. zip ( params. iter ( ) . map ( |param| FnParam :: Param ( param) ) ) . collect ( ) )
2718+ }
2719+ ( None , Some ( params) ) => {
2720+ let params = params. get ( is_method as usize ..) ?;
2721+ debug_assert_eq ! ( params. len( ) , fn_inputs. len( ) ) ;
2722+ Some ( fn_inputs. zip ( params. iter ( ) . map ( |param| FnParam :: Name ( param) ) ) . collect ( ) )
2723+ }
2724+ }
27052725 }
27062726}
27072727
@@ -2724,3 +2744,27 @@ impl<'tcx> Visitor<'tcx> for FindClosureArg<'tcx> {
27242744 hir:: intravisit:: walk_expr ( self , ex) ;
27252745 }
27262746}
2747+
2748+ #[ derive( Clone , Copy ) ]
2749+ enum FnParam < ' hir > {
2750+ Param ( & ' hir hir:: Param < ' hir > ) ,
2751+ Name ( & ' hir Ident ) ,
2752+ }
2753+ impl FnParam < ' _ > {
2754+ fn span ( & self ) -> Span {
2755+ match self {
2756+ Self :: Param ( x) => x. span ,
2757+ Self :: Name ( x) => x. span ,
2758+ }
2759+ }
2760+
2761+ fn name ( & self ) -> Option < Symbol > {
2762+ match self {
2763+ Self :: Param ( x) if let hir:: PatKind :: Binding ( _, _, ident, _) = x. pat . kind => {
2764+ Some ( ident. name )
2765+ }
2766+ Self :: Name ( x) if x. name != kw:: Empty => Some ( x. name ) ,
2767+ _ => None ,
2768+ }
2769+ }
2770+ }
0 commit comments