@@ -1499,16 +1499,18 @@ fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, vs: &'tcx [hir::Variant<'tcx>], def_id: L
1499
1499
check_transparent ( tcx, sp, def) ;
1500
1500
}
1501
1501
1502
+ /// Part of enum check, errors if two or more discriminants are equal
1502
1503
fn detect_discriminant_duplicate < ' tcx > (
1503
1504
tcx : TyCtxt < ' tcx > ,
1504
1505
mut discrs : Vec < ( VariantIdx , Discr < ' tcx > ) > ,
1505
1506
vs : & ' tcx [ hir:: Variant < ' tcx > ] ,
1506
1507
self_span : Span ,
1507
1508
) {
1508
- let report = | var : & hir :: Variant < ' _ > ,
1509
- dis : Discr < ' tcx > ,
1509
+ // Helper closure to reduce duplicate code. This gets called everytime we detect a duplicate
1510
+ let report = | dis : Discr < ' tcx > ,
1510
1511
idx : usize ,
1511
1512
err : & mut DiagnosticBuilder < ' _ , ErrorGuaranteed > | {
1513
+ let var = & vs[ idx] ;
1512
1514
let ( span, display_discr) = match var. disr_expr {
1513
1515
Some ( ref expr) => {
1514
1516
// In the case the discriminant is both a duplicate and overflowed, let the user know
@@ -1517,11 +1519,16 @@ fn detect_discriminant_duplicate<'tcx>(
1517
1519
&& * lit_value != dis. val
1518
1520
{
1519
1521
( tcx. hir ( ) . span ( expr. hir_id ) , format ! ( "`{dis}` (overflowed from `{lit_value}`)" ) )
1522
+ // Otherwise, format the value as-is
1520
1523
} else {
1521
1524
( tcx. hir ( ) . span ( expr. hir_id ) , format ! ( "`{dis}`" ) )
1522
1525
}
1523
1526
}
1524
1527
None => {
1528
+ // At this point we know this discriminant is a duplicate, and was not explicitly
1529
+ // assigned by the user. Here we iterate backwards to fetch the hir for the last
1530
+ // explictly assigned discriminant, and letting the user know that this was the
1531
+ // increment startpoint, and how many steps from there leading to the duplicate
1525
1532
if let Some ( ( n, hir:: Variant { span, ident, .. } ) ) =
1526
1533
vs[ ..idx] . iter ( ) . rev ( ) . enumerate ( ) . find ( |v| v. 1 . disr_expr . is_some ( ) )
1527
1534
{
@@ -1542,16 +1549,20 @@ fn detect_discriminant_duplicate<'tcx>(
1542
1549
err. span_label ( span, format ! ( "{display_discr} assigned here" ) ) ;
1543
1550
} ;
1544
1551
1552
+ // Here we are looping through the discriminant vec, comparing each discriminant to oneanother.
1553
+ // When a duplicate is detected, we instatiate an error and add a spanned note pointing to both
1554
+ // initial and duplicate value. The duplicate discriminant is then discarded from the vec by swapping
1555
+ // it with the last element and decrementing the vec.len by 1 (which is why we have to evaluate
1556
+ // `discrs.len()` anew every iteration, and why this could be tricky to do in a functional style as
1557
+ // we are mutating `discrs` on the fly).
1545
1558
let mut i = 0 ;
1546
1559
while i < discrs. len ( ) {
1547
1560
let hir_var_i_idx = discrs[ i] . 0 . index ( ) ;
1548
- let hir_var_i = & vs[ hir_var_i_idx] ;
1549
1561
let mut error: Option < DiagnosticBuilder < ' _ , _ > > = None ;
1550
1562
1551
1563
let mut o = i + 1 ;
1552
1564
while o < discrs. len ( ) {
1553
1565
let hir_var_o_idx = discrs[ o] . 0 . index ( ) ;
1554
- let hir_var_o = & vs[ hir_var_o_idx] ;
1555
1566
1556
1567
if discrs[ i] . 1 . val == discrs[ o] . 1 . val {
1557
1568
let err = error. get_or_insert_with ( || {
@@ -1563,13 +1574,14 @@ fn detect_discriminant_duplicate<'tcx>(
1563
1574
discrs[ i] . 1 ,
1564
1575
) ;
1565
1576
1566
- report ( hir_var_i , discrs[ i] . 1 , hir_var_i_idx, & mut ret) ;
1577
+ report ( discrs[ i] . 1 , hir_var_i_idx, & mut ret) ;
1567
1578
1568
1579
ret
1569
1580
} ) ;
1570
1581
1571
- report ( hir_var_o , discrs[ o] . 1 , hir_var_o_idx, err) ;
1582
+ report ( discrs[ o] . 1 , hir_var_o_idx, err) ;
1572
1583
1584
+ // Safe to unwrap here, as we wouldn't reach this point if `discrs` was empty
1573
1585
discrs[ o] = * discrs. last ( ) . unwrap ( ) ;
1574
1586
discrs. pop ( ) ;
1575
1587
} else {
0 commit comments