@@ -40,10 +40,13 @@ use suggestions::InferCtxtExt as _;
40
40
pub use rustc_infer:: traits:: error_reporting:: * ;
41
41
42
42
// When outputting impl candidates, prefer showing those that are more similar.
43
+ //
44
+ // We also compare candidates after skipping lifetimes, which has a lower
45
+ // priority than exact matches.
43
46
#[ derive( Debug , Copy , Clone , PartialEq , Eq , PartialOrd , Ord ) ]
44
47
pub enum CandidateSimilarity {
45
- Exact ,
46
- Fuzzy ,
48
+ Exact { ignoring_lifetimes : bool } ,
49
+ Fuzzy { ignoring_lifetimes : bool } ,
47
50
}
48
51
49
52
#[ derive( Debug , Clone , Copy ) ]
@@ -1155,7 +1158,12 @@ trait InferCtxtPrivExt<'hir, 'tcx> {
1155
1158
error : & MismatchedProjectionTypes < ' tcx > ,
1156
1159
) ;
1157
1160
1158
- fn fuzzy_match_tys ( & self , a : Ty < ' tcx > , b : Ty < ' tcx > ) -> bool ;
1161
+ fn fuzzy_match_tys (
1162
+ & self ,
1163
+ a : Ty < ' tcx > ,
1164
+ b : Ty < ' tcx > ,
1165
+ ignoring_lifetimes : bool ,
1166
+ ) -> Option < CandidateSimilarity > ;
1159
1167
1160
1168
fn describe_generator ( & self , body_id : hir:: BodyId ) -> Option < & ' static str > ;
1161
1169
@@ -1458,24 +1466,32 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
1458
1466
} ) ;
1459
1467
}
1460
1468
1461
- fn fuzzy_match_tys ( & self , a : Ty < ' tcx > , b : Ty < ' tcx > ) -> bool {
1469
+ fn fuzzy_match_tys (
1470
+ & self ,
1471
+ mut a : Ty < ' tcx > ,
1472
+ mut b : Ty < ' tcx > ,
1473
+ ignoring_lifetimes : bool ,
1474
+ ) -> Option < CandidateSimilarity > {
1462
1475
/// returns the fuzzy category of a given type, or None
1463
1476
/// if the type can be equated to any type.
1464
- fn type_category ( t : Ty < ' _ > ) -> Option < u32 > {
1477
+ fn type_category ( tcx : TyCtxt < ' _ > , t : Ty < ' _ > ) -> Option < u32 > {
1465
1478
match t. kind ( ) {
1466
1479
ty:: Bool => Some ( 0 ) ,
1467
1480
ty:: Char => Some ( 1 ) ,
1468
1481
ty:: Str => Some ( 2 ) ,
1469
- ty:: Int ( ..) | ty:: Uint ( ..) | ty:: Infer ( ty:: IntVar ( ..) ) => Some ( 3 ) ,
1470
- ty:: Float ( ..) | ty:: Infer ( ty:: FloatVar ( ..) ) => Some ( 4 ) ,
1482
+ ty:: Adt ( def, _) if tcx. is_diagnostic_item ( sym:: String , def. did ) => Some ( 2 ) ,
1483
+ ty:: Int ( ..)
1484
+ | ty:: Uint ( ..)
1485
+ | ty:: Float ( ..)
1486
+ | ty:: Infer ( ty:: IntVar ( ..) | ty:: FloatVar ( ..) ) => Some ( 4 ) ,
1471
1487
ty:: Ref ( ..) | ty:: RawPtr ( ..) => Some ( 5 ) ,
1472
1488
ty:: Array ( ..) | ty:: Slice ( ..) => Some ( 6 ) ,
1473
1489
ty:: FnDef ( ..) | ty:: FnPtr ( ..) => Some ( 7 ) ,
1474
1490
ty:: Dynamic ( ..) => Some ( 8 ) ,
1475
1491
ty:: Closure ( ..) => Some ( 9 ) ,
1476
1492
ty:: Tuple ( ..) => Some ( 10 ) ,
1477
- ty:: Projection ( ..) => Some ( 11 ) ,
1478
- ty:: Param ( ..) => Some ( 12 ) ,
1493
+ ty:: Param ( ..) => Some ( 11 ) ,
1494
+ ty:: Projection ( ..) => Some ( 12 ) ,
1479
1495
ty:: Opaque ( ..) => Some ( 13 ) ,
1480
1496
ty:: Never => Some ( 14 ) ,
1481
1497
ty:: Adt ( ..) => Some ( 15 ) ,
@@ -1497,17 +1513,33 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
1497
1513
}
1498
1514
} ;
1499
1515
1500
- match ( type_category ( a) , type_category ( b) ) {
1501
- ( Some ( cat_a) , Some ( cat_b) ) => match ( a. kind ( ) , b. kind ( ) ) {
1516
+ if !ignoring_lifetimes {
1517
+ a = strip_references ( a) ;
1518
+ b = strip_references ( b) ;
1519
+ }
1520
+
1521
+ let cat_a = type_category ( self . tcx , a) ?;
1522
+ let cat_b = type_category ( self . tcx , b) ?;
1523
+ if a == b {
1524
+ Some ( CandidateSimilarity :: Exact { ignoring_lifetimes } )
1525
+ } else if cat_a == cat_b {
1526
+ match ( a. kind ( ) , b. kind ( ) ) {
1502
1527
( ty:: Adt ( def_a, _) , ty:: Adt ( def_b, _) ) => def_a == def_b,
1503
- _ if cat_a == cat_b => true ,
1504
- ( ty:: Ref ( ..) , _) | ( _, ty:: Ref ( ..) ) => {
1505
- self . fuzzy_match_tys ( strip_references ( a) , strip_references ( b) )
1528
+ // Matching on references results in a lot of unhelpful
1529
+ // suggestions, so let's just not do that for now.
1530
+ //
1531
+ // We still upgrade successful matches to `ignoring_lifetimes: true`
1532
+ // to prioritize that impl.
1533
+ ( ty:: Ref ( ..) | ty:: RawPtr ( ..) , ty:: Ref ( ..) | ty:: RawPtr ( ..) ) => {
1534
+ self . fuzzy_match_tys ( a, b, true ) . is_some ( )
1506
1535
}
1507
- _ => false ,
1508
- } ,
1509
- // infer and error can be equated to all types
1510
- _ => true ,
1536
+ _ => true ,
1537
+ }
1538
+ . then_some ( CandidateSimilarity :: Fuzzy { ignoring_lifetimes } )
1539
+ } else if ignoring_lifetimes {
1540
+ None
1541
+ } else {
1542
+ self . fuzzy_match_tys ( a, b, true )
1511
1543
}
1512
1544
}
1513
1545
@@ -1533,22 +1565,8 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
1533
1565
1534
1566
let imp = self . tcx . impl_trait_ref ( def_id) . unwrap ( ) ;
1535
1567
1536
- // Check for exact match.
1537
- if trait_ref. skip_binder ( ) . self_ty ( ) == imp. self_ty ( ) {
1538
- return Some ( ImplCandidate {
1539
- trait_ref : imp,
1540
- similarity : CandidateSimilarity :: Exact ,
1541
- } ) ;
1542
- }
1543
-
1544
- if self . fuzzy_match_tys ( trait_ref. skip_binder ( ) . self_ty ( ) , imp. self_ty ( ) ) {
1545
- return Some ( ImplCandidate {
1546
- trait_ref : imp,
1547
- similarity : CandidateSimilarity :: Fuzzy ,
1548
- } ) ;
1549
- }
1550
-
1551
- None
1568
+ self . fuzzy_match_tys ( trait_ref. skip_binder ( ) . self_ty ( ) , imp. self_ty ( ) , false )
1569
+ . map ( |similarity| ImplCandidate { trait_ref : imp, similarity } )
1552
1570
} )
1553
1571
. collect ( )
1554
1572
}
0 commit comments