@@ -2203,12 +2203,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2203
2203
let mut spans: MultiSpan = def_span. into ( ) ;
2204
2204
2205
2205
let params_with_generics = self . get_hir_params_with_generics ( def_id, is_method) ;
2206
+ let mut generics_with_unmatched_params = Vec :: new ( ) ;
2206
2207
2207
2208
let mut check_for_matched_generics = false ;
2208
2209
if matched_inputs. iter ( ) . any ( |x| x. is_some ( ) )
2209
2210
&& params_with_generics. iter ( ) . any ( |x| x. 0 . is_some ( ) )
2210
2211
{
2211
2212
for ( idx, ( generic, _) ) in params_with_generics. iter ( ) . enumerate ( ) {
2213
+ if check_for_matched_generics {
2214
+ break ;
2215
+ }
2216
+
2212
2217
// Param has to have a generic and be matched to be relevant
2213
2218
if matched_inputs[ idx. into ( ) ] . is_none ( ) {
2214
2219
continue ;
@@ -2226,146 +2231,106 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2226
2231
{
2227
2232
// We found a parameter that didn't match that needed to
2228
2233
check_for_matched_generics = true ;
2234
+ break ;
2229
2235
}
2230
2236
}
2231
2237
}
2232
2238
}
2233
2239
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
+ } ;
2302
2251
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
2304
2261
. 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 ;
2312
2272
}
2273
+ other_generic_param. name . ident ( ) == generic_param. name . ident ( )
2313
2274
} )
2275
+ . map ( |( other_idx, ( _, other_param) ) | ( other_idx, * other_param) )
2314
2276
. collect ( ) ;
2315
2277
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
2327
2280
. 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
+ {
2330
2284
format ! ( "`{ident}`" )
2331
2285
} else {
2332
2286
"{unknown}" . to_string ( )
2333
2287
}
2334
2288
} )
2335
2289
. collect ( ) ;
2336
2290
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 , "" ) ;
2362
2306
}
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 ( ) ;
2363
2327
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
2366
2330
. 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
+ {
2369
2334
format ! ( "`{ident}`" )
2370
2335
} else {
2371
2336
"{unknown}" . to_string ( )
@@ -2374,28 +2339,70 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
2374
2339
. collect ( ) ;
2375
2340
2376
2341
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 )
2378
2343
. sort_string ( self . tcx ) ;
2379
2344
2380
2345
spans. push_span_label (
2381
- matched_param . 1 . span ,
2346
+ param . span ,
2382
2347
format ! (
2383
2348
"{} {} to match the {} type of this parameter" ,
2384
- display_list_with_comma_and( & idents ) ,
2349
+ display_list_with_comma_and( & other_param_matched_names ) ,
2385
2350
format!(
2386
2351
"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
+ } )
2388
2357
) ,
2389
2358
matched_ty,
2390
2359
) ,
2391
2360
) ;
2361
+ generics_with_unmatched_params. push ( generic_param) ;
2362
+ } else {
2363
+ spans. push_span_label ( param. span , "" ) ;
2392
2364
}
2393
2365
}
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
+ ) ;
2399
2406
}
2400
2407
}
2401
2408
0 commit comments