@@ -12,7 +12,7 @@ use hir::{
12
12
} ;
13
13
use hir_def:: {
14
14
body:: { BodySourceMap , SyntheticSyntax } ,
15
- expr:: ExprId ,
15
+ expr:: { ExprId , PatId } ,
16
16
FunctionId ,
17
17
} ;
18
18
use hir_ty:: { Interner , TyExt , TypeFlags } ;
@@ -222,7 +222,11 @@ impl flags::AnalysisStats {
222
222
let mut num_exprs = 0 ;
223
223
let mut num_exprs_unknown = 0 ;
224
224
let mut num_exprs_partially_unknown = 0 ;
225
- let mut num_type_mismatches = 0 ;
225
+ let mut num_expr_type_mismatches = 0 ;
226
+ let mut num_pats = 0 ;
227
+ let mut num_pats_unknown = 0 ;
228
+ let mut num_pats_partially_unknown = 0 ;
229
+ let mut num_pat_type_mismatches = 0 ;
226
230
let analysis = host. analysis ( ) ;
227
231
for f in funcs. iter ( ) . copied ( ) {
228
232
let name = f. name ( db) ;
@@ -255,6 +259,8 @@ impl flags::AnalysisStats {
255
259
let f_id = FunctionId :: from ( f) ;
256
260
let ( body, sm) = db. body_with_source_map ( f_id. into ( ) ) ;
257
261
let inference_result = db. infer ( f_id. into ( ) ) ;
262
+
263
+ // region:expressions
258
264
let ( previous_exprs, previous_unknown, previous_partially_unknown) =
259
265
( num_exprs, num_exprs_unknown, num_exprs_partially_unknown) ;
260
266
for ( expr_id, _) in body. exprs . iter ( ) {
@@ -307,12 +313,12 @@ impl flags::AnalysisStats {
307
313
if unknown_or_partial && self . output == Some ( OutputFormat :: Csv ) {
308
314
println ! (
309
315
r#"{},type,"{}""# ,
310
- location_csv ( db, & analysis, vfs, & sm, expr_id) ,
316
+ location_csv_expr ( db, & analysis, vfs, & sm, expr_id) ,
311
317
ty. display( db)
312
318
) ;
313
319
}
314
320
if let Some ( mismatch) = inference_result. type_mismatch_for_expr ( expr_id) {
315
- num_type_mismatches += 1 ;
321
+ num_expr_type_mismatches += 1 ;
316
322
if verbosity. is_verbose ( ) {
317
323
if let Some ( ( path, start, end) ) =
318
324
expr_syntax_range ( db, & analysis, vfs, & sm, expr_id)
@@ -339,7 +345,7 @@ impl flags::AnalysisStats {
339
345
if self . output == Some ( OutputFormat :: Csv ) {
340
346
println ! (
341
347
r#"{},mismatch,"{}","{}""# ,
342
- location_csv ( db, & analysis, vfs, & sm, expr_id) ,
348
+ location_csv_expr ( db, & analysis, vfs, & sm, expr_id) ,
343
349
mismatch. expected. display( db) ,
344
350
mismatch. actual. display( db)
345
351
) ;
@@ -355,6 +361,109 @@ impl flags::AnalysisStats {
355
361
num_exprs_partially_unknown - previous_partially_unknown
356
362
) ) ;
357
363
}
364
+ // endregion:expressions
365
+
366
+ // region:patterns
367
+ let ( previous_pats, previous_unknown, previous_partially_unknown) =
368
+ ( num_pats, num_pats_unknown, num_pats_partially_unknown) ;
369
+ for ( pat_id, _) in body. pats . iter ( ) {
370
+ let ty = & inference_result[ pat_id] ;
371
+ num_pats += 1 ;
372
+ let unknown_or_partial = if ty. is_unknown ( ) {
373
+ num_pats_unknown += 1 ;
374
+ if verbosity. is_spammy ( ) {
375
+ if let Some ( ( path, start, end) ) =
376
+ pat_syntax_range ( db, & analysis, vfs, & sm, pat_id)
377
+ {
378
+ bar. println ( format ! (
379
+ "{} {}:{}-{}:{}: Unknown type" ,
380
+ path,
381
+ start. line + 1 ,
382
+ start. col,
383
+ end. line + 1 ,
384
+ end. col,
385
+ ) ) ;
386
+ } else {
387
+ bar. println ( format ! ( "{name}: Unknown type" , ) ) ;
388
+ }
389
+ }
390
+ true
391
+ } else {
392
+ let is_partially_unknown =
393
+ ty. data ( Interner ) . flags . contains ( TypeFlags :: HAS_ERROR ) ;
394
+ if is_partially_unknown {
395
+ num_pats_partially_unknown += 1 ;
396
+ }
397
+ is_partially_unknown
398
+ } ;
399
+ if self . only . is_some ( ) && verbosity. is_spammy ( ) {
400
+ // in super-verbose mode for just one function, we print every single pattern
401
+ if let Some ( ( _, start, end) ) = pat_syntax_range ( db, & analysis, vfs, & sm, pat_id)
402
+ {
403
+ bar. println ( format ! (
404
+ "{}:{}-{}:{}: {}" ,
405
+ start. line + 1 ,
406
+ start. col,
407
+ end. line + 1 ,
408
+ end. col,
409
+ ty. display( db)
410
+ ) ) ;
411
+ } else {
412
+ bar. println ( format ! ( "unknown location: {}" , ty. display( db) ) ) ;
413
+ }
414
+ }
415
+ if unknown_or_partial && self . output == Some ( OutputFormat :: Csv ) {
416
+ println ! (
417
+ r#"{},type,"{}""# ,
418
+ location_csv_pat( db, & analysis, vfs, & sm, pat_id) ,
419
+ ty. display( db)
420
+ ) ;
421
+ }
422
+ if let Some ( mismatch) = inference_result. type_mismatch_for_pat ( pat_id) {
423
+ num_pat_type_mismatches += 1 ;
424
+ if verbosity. is_verbose ( ) {
425
+ if let Some ( ( path, start, end) ) =
426
+ pat_syntax_range ( db, & analysis, vfs, & sm, pat_id)
427
+ {
428
+ bar. println ( format ! (
429
+ "{} {}:{}-{}:{}: Expected {}, got {}" ,
430
+ path,
431
+ start. line + 1 ,
432
+ start. col,
433
+ end. line + 1 ,
434
+ end. col,
435
+ mismatch. expected. display( db) ,
436
+ mismatch. actual. display( db)
437
+ ) ) ;
438
+ } else {
439
+ bar. println ( format ! (
440
+ "{}: Expected {}, got {}" ,
441
+ name,
442
+ mismatch. expected. display( db) ,
443
+ mismatch. actual. display( db)
444
+ ) ) ;
445
+ }
446
+ }
447
+ if self . output == Some ( OutputFormat :: Csv ) {
448
+ println ! (
449
+ r#"{},mismatch,"{}","{}""# ,
450
+ location_csv_pat( db, & analysis, vfs, & sm, pat_id) ,
451
+ mismatch. expected. display( db) ,
452
+ mismatch. actual. display( db)
453
+ ) ;
454
+ }
455
+ }
456
+ }
457
+ if verbosity. is_spammy ( ) {
458
+ bar. println ( format ! (
459
+ "In {}: {} pats, {} unknown, {} partial" ,
460
+ full_name,
461
+ num_pats - previous_pats,
462
+ num_pats_unknown - previous_unknown,
463
+ num_pats_partially_unknown - previous_partially_unknown
464
+ ) ) ;
465
+ }
466
+ // endregion:patterns
358
467
bar. inc ( 1 ) ;
359
468
}
360
469
@@ -366,10 +475,21 @@ impl flags::AnalysisStats {
366
475
percentage( num_exprs_unknown, num_exprs) ,
367
476
num_exprs_partially_unknown,
368
477
percentage( num_exprs_partially_unknown, num_exprs) ,
369
- num_type_mismatches
478
+ num_expr_type_mismatches
479
+ ) ;
480
+ eprintln ! (
481
+ " pats: {}, ??ty: {} ({}%), ?ty: {} ({}%), !ty: {}" ,
482
+ num_pats,
483
+ num_pats_unknown,
484
+ percentage( num_pats_unknown, num_pats) ,
485
+ num_pats_partially_unknown,
486
+ percentage( num_pats_partially_unknown, num_pats) ,
487
+ num_pat_type_mismatches
370
488
) ;
371
489
report_metric ( "unknown type" , num_exprs_unknown, "#" ) ;
372
- report_metric ( "type mismatches" , num_type_mismatches, "#" ) ;
490
+ report_metric ( "type mismatches" , num_expr_type_mismatches, "#" ) ;
491
+ report_metric ( "pattern unknown type" , num_pats_unknown, "#" ) ;
492
+ report_metric ( "pattern type mismatches" , num_pat_type_mismatches, "#" ) ;
373
493
374
494
eprintln ! ( "{:<20} {}" , "Inference:" , inference_sw. elapsed( ) ) ;
375
495
}
@@ -379,7 +499,7 @@ impl flags::AnalysisStats {
379
499
}
380
500
}
381
501
382
- fn location_csv (
502
+ fn location_csv_expr (
383
503
db : & RootDatabase ,
384
504
analysis : & Analysis ,
385
505
vfs : & Vfs ,
@@ -401,6 +521,30 @@ fn location_csv(
401
521
format ! ( "{path},{}:{},{}:{}" , start. line + 1 , start. col, end. line + 1 , end. col)
402
522
}
403
523
524
+ fn location_csv_pat (
525
+ db : & RootDatabase ,
526
+ analysis : & Analysis ,
527
+ vfs : & Vfs ,
528
+ sm : & BodySourceMap ,
529
+ pat_id : PatId ,
530
+ ) -> String {
531
+ let src = match sm. pat_syntax ( pat_id) {
532
+ Ok ( s) => s,
533
+ Err ( SyntheticSyntax ) => return "synthetic,," . to_string ( ) ,
534
+ } ;
535
+ let root = db. parse_or_expand ( src. file_id ) . unwrap ( ) ;
536
+ let node = src. map ( |e| {
537
+ e. either ( |it| it. to_node ( & root) . syntax ( ) . clone ( ) , |it| it. to_node ( & root) . syntax ( ) . clone ( ) )
538
+ } ) ;
539
+ let original_range = node. as_ref ( ) . original_file_range ( db) ;
540
+ let path = vfs. file_path ( original_range. file_id ) ;
541
+ let line_index = analysis. file_line_index ( original_range. file_id ) . unwrap ( ) ;
542
+ let text_range = original_range. range ;
543
+ let ( start, end) =
544
+ ( line_index. line_col ( text_range. start ( ) ) , line_index. line_col ( text_range. end ( ) ) ) ;
545
+ format ! ( "{path},{}:{},{}:{}" , start. line + 1 , start. col, end. line + 1 , end. col)
546
+ }
547
+
404
548
fn expr_syntax_range (
405
549
db : & RootDatabase ,
406
550
analysis : & Analysis ,
@@ -423,6 +567,33 @@ fn expr_syntax_range(
423
567
None
424
568
}
425
569
}
570
+ fn pat_syntax_range (
571
+ db : & RootDatabase ,
572
+ analysis : & Analysis ,
573
+ vfs : & Vfs ,
574
+ sm : & BodySourceMap ,
575
+ pat_id : PatId ,
576
+ ) -> Option < ( VfsPath , LineCol , LineCol ) > {
577
+ let src = sm. pat_syntax ( pat_id) ;
578
+ if let Ok ( src) = src {
579
+ let root = db. parse_or_expand ( src. file_id ) . unwrap ( ) ;
580
+ let node = src. map ( |e| {
581
+ e. either (
582
+ |it| it. to_node ( & root) . syntax ( ) . clone ( ) ,
583
+ |it| it. to_node ( & root) . syntax ( ) . clone ( ) ,
584
+ )
585
+ } ) ;
586
+ let original_range = node. as_ref ( ) . original_file_range ( db) ;
587
+ let path = vfs. file_path ( original_range. file_id ) ;
588
+ let line_index = analysis. file_line_index ( original_range. file_id ) . unwrap ( ) ;
589
+ let text_range = original_range. range ;
590
+ let ( start, end) =
591
+ ( line_index. line_col ( text_range. start ( ) ) , line_index. line_col ( text_range. end ( ) ) ) ;
592
+ Some ( ( path, start, end) )
593
+ } else {
594
+ None
595
+ }
596
+ }
426
597
427
598
fn shuffle < T > ( rng : & mut Rand32 , slice : & mut [ T ] ) {
428
599
for i in 0 ..slice. len ( ) {
0 commit comments