@@ -1499,16 +1499,18 @@ fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, vs: &'tcx [hir::Variant<'tcx>], def_id: L
14991499 check_transparent ( tcx, sp, def) ;
15001500}
15011501
1502+ /// Part of enum check, errors if two or more discriminants are equal
15021503fn detect_discriminant_duplicate < ' tcx > (
15031504 tcx : TyCtxt < ' tcx > ,
15041505 mut discrs : Vec < ( VariantIdx , Discr < ' tcx > ) > ,
15051506 vs : & ' tcx [ hir:: Variant < ' tcx > ] ,
15061507 self_span : Span ,
15071508) {
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 > ,
15101511 idx : usize ,
15111512 err : & mut DiagnosticBuilder < ' _ , ErrorGuaranteed > | {
1513+ let var = & vs[ idx] ;
15121514 let ( span, display_discr) = match var. disr_expr {
15131515 Some ( ref expr) => {
15141516 // In the case the discriminant is both a duplicate and overflowed, let the user know
@@ -1517,11 +1519,16 @@ fn detect_discriminant_duplicate<'tcx>(
15171519 && * lit_value != dis. val
15181520 {
15191521 ( tcx. hir ( ) . span ( expr. hir_id ) , format ! ( "`{dis}` (overflowed from `{lit_value}`)" ) )
1522+ // Otherwise, format the value as-is
15201523 } else {
15211524 ( tcx. hir ( ) . span ( expr. hir_id ) , format ! ( "`{dis}`" ) )
15221525 }
15231526 }
15241527 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
15251532 if let Some ( ( n, hir:: Variant { span, ident, .. } ) ) =
15261533 vs[ ..idx] . iter ( ) . rev ( ) . enumerate ( ) . find ( |v| v. 1 . disr_expr . is_some ( ) )
15271534 {
@@ -1542,16 +1549,20 @@ fn detect_discriminant_duplicate<'tcx>(
15421549 err. span_label ( span, format ! ( "{display_discr} assigned here" ) ) ;
15431550 } ;
15441551
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).
15451558 let mut i = 0 ;
15461559 while i < discrs. len ( ) {
15471560 let hir_var_i_idx = discrs[ i] . 0 . index ( ) ;
1548- let hir_var_i = & vs[ hir_var_i_idx] ;
15491561 let mut error: Option < DiagnosticBuilder < ' _ , _ > > = None ;
15501562
15511563 let mut o = i + 1 ;
15521564 while o < discrs. len ( ) {
15531565 let hir_var_o_idx = discrs[ o] . 0 . index ( ) ;
1554- let hir_var_o = & vs[ hir_var_o_idx] ;
15551566
15561567 if discrs[ i] . 1 . val == discrs[ o] . 1 . val {
15571568 let err = error. get_or_insert_with ( || {
@@ -1563,13 +1574,14 @@ fn detect_discriminant_duplicate<'tcx>(
15631574 discrs[ i] . 1 ,
15641575 ) ;
15651576
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) ;
15671578
15681579 ret
15691580 } ) ;
15701581
1571- report ( hir_var_o , discrs[ o] . 1 , hir_var_o_idx, err) ;
1582+ report ( discrs[ o] . 1 , hir_var_o_idx, err) ;
15721583
1584+ // Safe to unwrap here, as we wouldn't reach this point if `discrs` was empty
15731585 discrs[ o] = * discrs. last ( ) . unwrap ( ) ;
15741586 discrs. pop ( ) ;
15751587 } else {
0 commit comments