@@ -222,6 +222,15 @@ pub trait TypeErrCtxtExt<'tcx> {
222222 param_env : ty:: ParamEnv < ' tcx > ,
223223 ) -> DiagnosticBuilder < ' tcx , ErrorGuaranteed > ;
224224
225+ fn note_conflicting_fn_args (
226+ & self ,
227+ err : & mut Diagnostic ,
228+ cause : & ObligationCauseCode < ' tcx > ,
229+ expected : Ty < ' tcx > ,
230+ found : Ty < ' tcx > ,
231+ param_env : ty:: ParamEnv < ' tcx > ,
232+ ) ;
233+
225234 fn note_conflicting_closure_bounds (
226235 & self ,
227236 cause : & ObligationCauseCode < ' tcx > ,
@@ -2006,6 +2015,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
20062015 let signature_kind = format ! ( "{argument_kind} signature" ) ;
20072016 err. note_expected_found ( & signature_kind, expected_str, & signature_kind, found_str) ;
20082017
2018+ self . note_conflicting_fn_args ( & mut err, cause, expected, found, param_env) ;
20092019 self . note_conflicting_closure_bounds ( cause, & mut err) ;
20102020
20112021 if let Some ( found_node) = found_node {
@@ -2015,6 +2025,152 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
20152025 err
20162026 }
20172027
2028+ fn note_conflicting_fn_args (
2029+ & self ,
2030+ err : & mut Diagnostic ,
2031+ cause : & ObligationCauseCode < ' tcx > ,
2032+ expected : Ty < ' tcx > ,
2033+ found : Ty < ' tcx > ,
2034+ param_env : ty:: ParamEnv < ' tcx > ,
2035+ ) {
2036+ let ObligationCauseCode :: FunctionArgumentObligation { arg_hir_id, .. } = cause else {
2037+ return ;
2038+ } ;
2039+ let ty:: FnPtr ( expected) = expected. kind ( ) else {
2040+ return ;
2041+ } ;
2042+ let ty:: FnPtr ( found) = found. kind ( ) else {
2043+ return ;
2044+ } ;
2045+ let Some ( Node :: Expr ( arg) ) = self . tcx . hir ( ) . find ( * arg_hir_id) else {
2046+ return ;
2047+ } ;
2048+ let hir:: ExprKind :: Path ( path) = arg. kind else {
2049+ return ;
2050+ } ;
2051+ let expected_inputs = self . tcx . erase_late_bound_regions ( * expected) . inputs ( ) ;
2052+ let found_inputs = self . tcx . erase_late_bound_regions ( * found) . inputs ( ) ;
2053+ let both_tys = expected_inputs. iter ( ) . cloned ( ) . zip ( found_inputs. iter ( ) . cloned ( ) ) ;
2054+
2055+ let arg_expr = |infcx : & InferCtxt < ' tcx > , name, expected : Ty < ' tcx > , found : Ty < ' tcx > | {
2056+ let ( expected_ty, expected_refs) = get_deref_type_and_refs ( expected) ;
2057+ let ( found_ty, found_refs) = get_deref_type_and_refs ( found) ;
2058+
2059+ if infcx. can_eq ( param_env, found_ty, expected_ty) {
2060+ if found_refs. len ( ) == expected_refs. len ( )
2061+ && found_refs. iter ( ) . zip ( expected_refs. iter ( ) ) . all ( |( e, f) | e == f)
2062+ {
2063+ name
2064+ } else if found_refs. len ( ) > expected_refs. len ( ) {
2065+ if found_refs[ ..found_refs. len ( ) - expected_refs. len ( ) ]
2066+ . iter ( )
2067+ . zip ( expected_refs. iter ( ) )
2068+ . any ( |( e, f) | e != f)
2069+ {
2070+ // The refs have different mutability.
2071+ format ! (
2072+ "{}*{name}" ,
2073+ found_refs[ ..found_refs. len( ) - expected_refs. len( ) ]
2074+ . iter( )
2075+ . map( |mutbl| format!( "&{}" , mutbl. prefix_str( ) ) )
2076+ . collect:: <Vec <_>>( )
2077+ . join( "" ) ,
2078+ )
2079+ } else {
2080+ format ! (
2081+ "{}{name}" ,
2082+ found_refs[ ..found_refs. len( ) - expected_refs. len( ) ]
2083+ . iter( )
2084+ . map( |mutbl| format!( "&{}" , mutbl. prefix_str( ) ) )
2085+ . collect:: <Vec <_>>( )
2086+ . join( "" ) ,
2087+ )
2088+ }
2089+ } else if expected_refs. len ( ) > found_refs. len ( ) {
2090+ format ! (
2091+ "{}{name}" ,
2092+ ( 0 ..( expected_refs. len( ) - found_refs. len( ) ) )
2093+ . map( |_| "*" )
2094+ . collect:: <Vec <_>>( )
2095+ . join( "" ) ,
2096+ )
2097+ } else {
2098+ format ! (
2099+ "{}{name}" ,
2100+ found_refs
2101+ . iter( )
2102+ . map( |mutbl| format!( "&{}" , mutbl. prefix_str( ) ) )
2103+ . chain( found_refs. iter( ) . map( |_| "*" . to_string( ) ) )
2104+ . collect:: <Vec <_>>( )
2105+ . join( "" ) ,
2106+ )
2107+ }
2108+ } else {
2109+ format ! ( "/* {found} */" )
2110+ }
2111+ } ;
2112+ let ( closure_names, call_names) : ( Vec < _ > , Vec < _ > ) =
2113+ if both_tys. clone ( ) . all ( |( expected, found) | {
2114+ let ( expected_ty, _) = get_deref_type_and_refs ( expected) ;
2115+ let ( found_ty, _) = get_deref_type_and_refs ( found) ;
2116+ self . can_eq ( param_env, found_ty, expected_ty)
2117+ } ) && !expected_inputs. is_empty ( )
2118+ && expected_inputs. len ( ) == found_inputs. len ( )
2119+ && let hir:: QPath :: Resolved ( _, path) = path
2120+ && let hir:: def:: Res :: Def ( _, fn_def_id) = path. res
2121+ && let Some ( node) = self . tcx . hir ( ) . get_if_local ( fn_def_id)
2122+ && let Some ( body_id) = node. body_id ( )
2123+ {
2124+ let closure = self
2125+ . tcx
2126+ . hir ( )
2127+ . body_param_names ( body_id)
2128+ . map ( |name| format ! ( "{name}" ) )
2129+ . collect ( ) ;
2130+ let args = self
2131+ . tcx
2132+ . hir ( )
2133+ . body_param_names ( body_id)
2134+ . zip ( both_tys)
2135+ . map ( |( name, ( expected, found) ) | {
2136+ arg_expr ( self . infcx , format ! ( "{name}" ) , expected, found)
2137+ } )
2138+ . collect ( ) ;
2139+ ( closure, args)
2140+ } else {
2141+ let closure_args = expected_inputs
2142+ . iter ( )
2143+ . enumerate ( )
2144+ . map ( |( i, _) | format ! ( "arg{i}" ) )
2145+ . collect :: < Vec < _ > > ( ) ;
2146+ let call_args = both_tys
2147+ . enumerate ( )
2148+ . map ( |( i, ( expected, found) ) | {
2149+ arg_expr ( self . infcx , format ! ( "arg{i}" ) , expected, found)
2150+ } )
2151+ . collect :: < Vec < _ > > ( ) ;
2152+ ( closure_args, call_args)
2153+ } ;
2154+ let closure_names: Vec < _ > = closure_names
2155+ . into_iter ( )
2156+ . zip ( expected_inputs. iter ( ) )
2157+ . map ( |( name, ty) | {
2158+ format ! (
2159+ "{name}{}" ,
2160+ if ty. has_infer_types( ) { String :: new( ) } else { format!( ": {ty}" ) }
2161+ )
2162+ } )
2163+ . collect ( ) ;
2164+ err. multipart_suggestion (
2165+ format ! ( "consider wrapping the function in a closure" ) ,
2166+ vec ! [
2167+ ( arg. span. shrink_to_lo( ) , format!( "|{}| " , closure_names. join( ", " ) ) ) ,
2168+ ( arg. span. shrink_to_hi( ) , format!( "({})" , call_names. join( ", " ) ) ) ,
2169+ ] ,
2170+ Applicability :: MaybeIncorrect ,
2171+ ) ;
2172+ }
2173+
20182174 // Add a note if there are two `Fn`-family bounds that have conflicting argument
20192175 // requirements, which will always cause a closure to have a type error.
20202176 fn note_conflicting_closure_bounds (
@@ -4366,17 +4522,6 @@ fn hint_missing_borrow<'tcx>(
43664522
43674523 let args = fn_decl. inputs . iter ( ) ;
43684524
4369- fn get_deref_type_and_refs ( mut ty : Ty < ' _ > ) -> ( Ty < ' _ > , Vec < hir:: Mutability > ) {
4370- let mut refs = vec ! [ ] ;
4371-
4372- while let ty:: Ref ( _, new_ty, mutbl) = ty. kind ( ) {
4373- ty = * new_ty;
4374- refs. push ( * mutbl) ;
4375- }
4376-
4377- ( ty, refs)
4378- }
4379-
43804525 let mut to_borrow = Vec :: new ( ) ;
43814526 let mut remove_borrow = Vec :: new ( ) ;
43824527
@@ -4669,3 +4814,14 @@ pub fn suggest_desugaring_async_fn_to_impl_future_in_trait<'tcx>(
46694814
46704815 Some ( sugg)
46714816}
4817+
4818+ fn get_deref_type_and_refs ( mut ty : Ty < ' _ > ) -> ( Ty < ' _ > , Vec < hir:: Mutability > ) {
4819+ let mut refs = vec ! [ ] ;
4820+
4821+ while let ty:: Ref ( _, new_ty, mutbl) = ty. kind ( ) {
4822+ ty = * new_ty;
4823+ refs. push ( * mutbl) ;
4824+ }
4825+
4826+ ( ty, refs)
4827+ }
0 commit comments