@@ -2203,12 +2203,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
22032203 let mut spans: MultiSpan = def_span. into ( ) ;
22042204
22052205 let params_with_generics = self . get_hir_params_with_generics ( def_id, is_method) ;
2206+ let mut generics_with_unmatched_params = Vec :: new ( ) ;
22062207
22072208 let mut check_for_matched_generics = false ;
22082209 if matched_inputs. iter ( ) . any ( |x| x. is_some ( ) )
22092210 && params_with_generics. iter ( ) . any ( |x| x. 0 . is_some ( ) )
22102211 {
22112212 for ( idx, ( generic, _) ) in params_with_generics. iter ( ) . enumerate ( ) {
2213+ if check_for_matched_generics {
2214+ break ;
2215+ }
2216+
22122217 // Param has to have a generic and be matched to be relevant
22132218 if matched_inputs[ idx. into ( ) ] . is_none ( ) {
22142219 continue ;
@@ -2226,146 +2231,106 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
22262231 {
22272232 // We found a parameter that didn't match that needed to
22282233 check_for_matched_generics = true ;
2234+ break ;
22292235 }
22302236 }
22312237 }
22322238 }
22332239
2234- if check_for_matched_generics {
2235- let mut generics_map: Vec < ( usize , & hir:: GenericParam < ' _ > ) > = Vec :: new ( ) ;
2236- // This is a map from the index of the generic to the index of the parameter and the
2237- // parameter
2238- let mut matched_params_map: Vec < ( usize , usize , & hir:: Param < ' _ > ) > = Vec :: new ( ) ;
2239- let mut unmatched_params_map: Vec < ( usize , & hir:: Param < ' _ > ) > = Vec :: new ( ) ;
2240-
2241- for ( idx, ( generic, param) ) in params_with_generics. iter ( ) . enumerate ( ) {
2242- if matched_inputs[ idx. into ( ) ] . is_none ( ) {
2243- spans. push_span_label ( param. span , "" ) ;
2244- continue ;
2245- }
2246-
2247- let Some ( generic) = generic else {
2248- spans. push_span_label ( param. span , "" ) ;
2249- continue ;
2250- } ;
2251-
2252- let mut found_unmatched_generic_params = vec ! [ ] ;
2253-
2254- for unmatching_idx in idx + 1 ..params_with_generics. len ( ) {
2255- if matched_inputs[ unmatching_idx. into ( ) ] . is_none ( )
2256- && let Some ( unmatched_idx_param_generic) =
2257- params_with_generics[ unmatching_idx] . 0
2258- && unmatched_idx_param_generic. name . ident ( ) == generic. name . ident ( )
2259- {
2260- found_unmatched_generic_params
2261- . push ( params_with_generics[ unmatching_idx] . 1 ) ;
2262- }
2263- }
2264-
2265- if found_unmatched_generic_params. is_empty ( ) {
2266- spans. push_span_label ( param. span , "" ) ;
2267- continue ;
2268- }
2269-
2270- let generics_idx = generics_map
2271- . iter ( )
2272- . filter ( |x| x. 1 . name . ident ( ) == generic. name . ident ( ) )
2273- . next ( )
2274- . map ( |x| x. 0 ) ;
2275-
2276- let generics_idx = generics_idx. unwrap_or_else ( || {
2277- let generics_map_len = generics_map. len ( ) ;
2278- generics_map. push ( ( generics_map_len, generic) ) ;
2279- generics_map_len
2280- } ) ;
2281- matched_params_map. push ( ( generics_idx, idx, param) ) ;
2282- if unmatched_params_map. iter ( ) . filter ( |x| x. 0 == generics_idx) . count ( ) > 0 {
2283- // Already processed the unmatched params
2284- continue ;
2285- }
2286- for unmatched_param in & found_unmatched_generic_params {
2287- unmatched_params_map. push ( ( generics_idx, unmatched_param) ) ;
2288- }
2289- }
2290-
2291- for ( generic_idx, generic) in & generics_map {
2292- let matched_params: Vec < ( usize , & hir:: Param < ' _ > ) > = matched_params_map
2293- . iter ( )
2294- . filter ( |x| x. 0 == * generic_idx)
2295- . map ( |x| ( x. 1 , x. 2 ) )
2296- . collect ( ) ;
2297- let unmatched_params: Vec < & hir:: Param < ' _ > > = unmatched_params_map
2298- . iter ( )
2299- . filter ( |x| x. 0 == * generic_idx)
2300- . map ( |x| x. 1 )
2301- . collect ( ) ;
2240+ for ( idx, ( generic_param, param) ) in
2241+ params_with_generics. iter ( ) . enumerate ( ) . filter ( |( idx, _) | {
2242+ check_for_matched_generics
2243+ || expected_idx. map_or ( true , |expected_idx| expected_idx == * idx)
2244+ } )
2245+ {
2246+ // TODO: Must be a better thing we can do here
2247+ let Some ( generic_param) = generic_param else {
2248+ spans. push_span_label ( param. span , "" ) ;
2249+ continue ;
2250+ } ;
23022251
2303- let all_param_idents: Vec < String > = matched_params
2252+ tracing:: debug!(
2253+ "label_fn_like: idx: {:?}, generic_param: {:?}" ,
2254+ idx,
2255+ matched_inputs
2256+ ) ;
2257+ if matched_inputs[ idx. into ( ) ] . is_none ( ) {
2258+ // If no matching input then we check other params to see if it should have
2259+ // matched, if so we print info about that failure to match.
2260+ let other_params_matched: Vec < ( usize , & hir:: Param < ' _ > ) > = params_with_generics
23042261 . iter ( )
2305- . map ( |x| & x. 1 )
2306- . chain ( unmatched_params. iter ( ) )
2307- . map ( |x| {
2308- if let hir:: PatKind :: Binding ( _, _, ident, _) = x. pat . kind {
2309- format ! ( "`{ident}`" )
2310- } else {
2311- "{unknown}" . to_string ( )
2262+ . enumerate ( )
2263+ . filter ( |( other_idx, ( other_generic_param, _) ) | {
2264+ if * other_idx == idx {
2265+ return false ;
2266+ }
2267+ let Some ( other_generic_param) = other_generic_param else {
2268+ return false ;
2269+ } ;
2270+ if matched_inputs[ ( * other_idx) . into ( ) ] . is_none ( ) {
2271+ return false ;
23122272 }
2273+ other_generic_param. name . ident ( ) == generic_param. name . ident ( )
23132274 } )
2275+ . map ( |( other_idx, ( _, other_param) ) | ( other_idx, * other_param) )
23142276 . collect ( ) ;
23152277
2316- spans. push_span_label (
2317- generic. span ,
2318- format ! (
2319- "{} all reference this parameter {}" ,
2320- display_list_with_comma_and( & all_param_idents) ,
2321- generic. name. ident( ) . name,
2322- ) ,
2323- ) ;
2324-
2325- for unmatched_param in & unmatched_params {
2326- let idents: Vec < String > = matched_params
2278+ if other_params_matched. len ( ) > 0 {
2279+ let other_param_matched_names: Vec < String > = other_params_matched
23272280 . iter ( )
2328- . map ( |x| {
2329- if let hir:: PatKind :: Binding ( _, _, ident, _) = x. 1 . pat . kind {
2281+ . map ( |( _, other_param) | {
2282+ if let hir:: PatKind :: Binding ( _, _, ident, _) = other_param. pat . kind
2283+ {
23302284 format ! ( "`{ident}`" )
23312285 } else {
23322286 "{unknown}" . to_string ( )
23332287 }
23342288 } )
23352289 . collect ( ) ;
23362290
2337- let matched_ty = matched_params
2338- . iter ( )
2339- . next ( )
2340- . map ( |x| formal_and_expected_inputs[ x. 0 . into ( ) ] ) ;
2341-
2342- if let Some ( matched_ty) = matched_ty {
2343- let matched_ty =
2344- self . resolve_vars_if_possible ( matched_ty. 0 ) . sort_string ( self . tcx ) ;
2345- spans. push_span_label (
2346- unmatched_param. span ,
2347- format ! (
2348- "this parameter needs to match the {} type of {}" ,
2349- matched_ty,
2350- display_list_with_comma_and( & idents)
2351- ) ,
2352- ) ;
2353- } else {
2354- spans. push_span_label (
2355- unmatched_param. span ,
2356- format ! (
2357- "this parameter needs to match the type of {}" ,
2358- display_list_with_comma_and( & idents)
2359- ) ,
2360- ) ;
2361- }
2291+ let matched_ty = self
2292+ . resolve_vars_if_possible ( formal_and_expected_inputs[ idx. into ( ) ] . 1 )
2293+ . sort_string ( self . tcx ) ;
2294+
2295+ spans. push_span_label (
2296+ param. span ,
2297+ format ! (
2298+ "this parameter needs to match the {} type of {}" ,
2299+ matched_ty,
2300+ display_list_with_comma_and( & other_param_matched_names) ,
2301+ ) ,
2302+ ) ;
2303+ generics_with_unmatched_params. push ( generic_param) ;
2304+ } else {
2305+ spans. push_span_label ( param. span , "" ) ;
23622306 }
2307+ } else {
2308+ // If we have a matched input then we check other params to see if we have
2309+ // anything unmatched, if so we print info about those unmatched parameters.
2310+ let other_params_matched: Vec < ( usize , & hir:: Param < ' _ > ) > = params_with_generics
2311+ . iter ( )
2312+ . enumerate ( )
2313+ . filter ( |( other_idx, ( other_generic_param, _) ) | {
2314+ if * other_idx == idx {
2315+ return false ;
2316+ }
2317+ let Some ( other_generic_param) = other_generic_param else {
2318+ return false ;
2319+ } ;
2320+ if matched_inputs[ ( * other_idx) . into ( ) ] . is_some ( ) {
2321+ return false ;
2322+ }
2323+ other_generic_param. name . ident ( ) == generic_param. name . ident ( )
2324+ } )
2325+ . map ( |( other_idx, ( _, other_param) ) | ( other_idx, * other_param) )
2326+ . collect ( ) ;
23632327
2364- for ( idx , matched_param ) in matched_params . iter ( ) . enumerate ( ) {
2365- let idents : Vec < String > = unmatched_params
2328+ if other_params_matched . len ( ) > 0 {
2329+ let other_param_matched_names : Vec < String > = other_params_matched
23662330 . iter ( )
2367- . map ( |x| {
2368- if let hir:: PatKind :: Binding ( _, _, ident, _) = x. pat . kind {
2331+ . map ( |( _, other_param) | {
2332+ if let hir:: PatKind :: Binding ( _, _, ident, _) = other_param. pat . kind
2333+ {
23692334 format ! ( "`{ident}`" )
23702335 } else {
23712336 "{unknown}" . to_string ( )
@@ -2374,28 +2339,70 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
23742339 . collect ( ) ;
23752340
23762341 let matched_ty = self
2377- . resolve_vars_if_possible ( formal_and_expected_inputs[ idx. into ( ) ] . 0 )
2342+ . resolve_vars_if_possible ( formal_and_expected_inputs[ idx. into ( ) ] . 1 )
23782343 . sort_string ( self . tcx ) ;
23792344
23802345 spans. push_span_label (
2381- matched_param . 1 . span ,
2346+ param . span ,
23822347 format ! (
23832348 "{} {} to match the {} type of this parameter" ,
2384- display_list_with_comma_and( & idents ) ,
2349+ display_list_with_comma_and( & other_param_matched_names ) ,
23852350 format!(
23862351 "need{}" ,
2387- pluralize!( if idents. len( ) == 1 { 0 } else { 1 } )
2352+ pluralize!( if other_param_matched_names. len( ) == 1 {
2353+ 0
2354+ } else {
2355+ 1
2356+ } )
23882357 ) ,
23892358 matched_ty,
23902359 ) ,
23912360 ) ;
2361+ generics_with_unmatched_params. push ( generic_param) ;
2362+ } else {
2363+ spans. push_span_label ( param. span , "" ) ;
23922364 }
23932365 }
2394- } else {
2395- for ( _, ( _, param) ) in params_with_generics. iter ( ) . enumerate ( ) . filter ( |( idx, _) | {
2396- expected_idx. map_or ( true , |expected_idx| expected_idx == * idx)
2397- } ) {
2398- spans. push_span_label ( param. span , "" ) ;
2366+ }
2367+
2368+ for generic_param in self
2369+ . tcx
2370+ . hir ( )
2371+ . get_if_local ( def_id)
2372+ . and_then ( |node| node. generics ( ) )
2373+ . into_iter ( )
2374+ . flat_map ( |x| x. params )
2375+ . filter ( |x| {
2376+ generics_with_unmatched_params. iter ( ) . any ( |y| x. name . ident ( ) == y. name . ident ( ) )
2377+ } )
2378+ {
2379+ let param_idents_matching: Vec < String > = params_with_generics
2380+ . iter ( )
2381+ . filter ( |( generic, _) | {
2382+ if let Some ( generic) = generic {
2383+ generic. name . ident ( ) == generic_param. name . ident ( )
2384+ } else {
2385+ false
2386+ }
2387+ } )
2388+ . map ( |( _, param) | {
2389+ if let hir:: PatKind :: Binding ( _, _, ident, _) = param. pat . kind {
2390+ format ! ( "`{ident}`" )
2391+ } else {
2392+ "{unknown}" . to_string ( )
2393+ }
2394+ } )
2395+ . collect ( ) ;
2396+
2397+ if param_idents_matching. len ( ) > 0 {
2398+ spans. push_span_label (
2399+ generic_param. span ,
2400+ format ! (
2401+ "{} all reference this parameter {}" ,
2402+ display_list_with_comma_and( & param_idents_matching) ,
2403+ generic_param. name. ident( ) . name,
2404+ ) ,
2405+ ) ;
23992406 }
24002407 }
24012408
0 commit comments