@@ -1006,6 +1006,10 @@ struct Candidate<'pat, 'tcx> {
1006
1006
/// If the candidate matches, bindings and ascriptions must be established.
1007
1007
extra_data : PatternExtraData < ' tcx > ,
1008
1008
1009
+ /// If we filled `self.subcandidate`, we store here the span of the or-pattern they came from.
1010
+ // Invariant: it is `None` iff `subcandidates.is_empty()`.
1011
+ or_span : Option < Span > ,
1012
+
1009
1013
/// The block before the `bindings` have been established.
1010
1014
pre_binding_block : Option < BasicBlock > ,
1011
1015
/// The pre-binding block of the next candidate.
@@ -1028,6 +1032,7 @@ impl<'tcx, 'pat> Candidate<'pat, 'tcx> {
1028
1032
extra_data : flat_pat. extra_data ,
1029
1033
has_guard,
1030
1034
subcandidates : Vec :: new ( ) ,
1035
+ or_span : None ,
1031
1036
otherwise_block : None ,
1032
1037
pre_binding_block : None ,
1033
1038
next_candidate_pre_binding_block : None ,
@@ -1277,7 +1282,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1277
1282
//
1278
1283
// only generates a single switch.
1279
1284
candidate. subcandidates = self . create_or_subcandidates ( pats, candidate. has_guard ) ;
1280
- candidate. match_pairs . pop ( ) ;
1285
+ let first_match_pair = candidate. match_pairs . pop ( ) . unwrap ( ) ;
1286
+ candidate. or_span = Some ( first_match_pair. pattern . span ) ;
1281
1287
split_or_candidate = true ;
1282
1288
}
1283
1289
}
@@ -1287,8 +1293,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1287
1293
// At least one of the candidates has been split into subcandidates.
1288
1294
// We need to change the candidate list to include those.
1289
1295
let mut new_candidates = Vec :: new ( ) ;
1290
-
1291
- for candidate in candidates {
1296
+ for candidate in candidates. iter_mut ( ) {
1292
1297
candidate. visit_leaves ( |leaf_candidate| new_candidates. push ( leaf_candidate) ) ;
1293
1298
}
1294
1299
self . match_simplified_candidates (
@@ -1298,6 +1303,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1298
1303
otherwise_block,
1299
1304
& mut * new_candidates,
1300
1305
) ;
1306
+
1307
+ for candidate in candidates {
1308
+ self . merge_trivial_subcandidates ( candidate) ;
1309
+ }
1301
1310
} else {
1302
1311
self . match_simplified_candidates (
1303
1312
span,
@@ -1531,16 +1540,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1531
1540
& mut or_candidate_refs,
1532
1541
) ;
1533
1542
candidate. subcandidates = or_candidates;
1534
- self . merge_trivial_subcandidates ( candidate, self . source_info ( or_span) ) ;
1543
+ candidate. or_span = Some ( or_span) ;
1544
+ self . merge_trivial_subcandidates ( candidate) ;
1535
1545
}
1536
1546
1537
1547
/// Try to merge all of the subcandidates of the given candidate into one.
1538
1548
/// This avoids exponentially large CFGs in cases like `(1 | 2, 3 | 4, ...)`.
1539
- fn merge_trivial_subcandidates (
1540
- & mut self ,
1541
- candidate : & mut Candidate < ' _ , ' tcx > ,
1542
- source_info : SourceInfo ,
1543
- ) {
1549
+ fn merge_trivial_subcandidates ( & mut self , candidate : & mut Candidate < ' _ , ' tcx > ) {
1544
1550
if candidate. subcandidates . is_empty ( ) || candidate. has_guard {
1545
1551
// FIXME(or_patterns; matthewjasper) Don't give up if we have a guard.
1546
1552
return ;
@@ -1550,7 +1556,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1550
1556
1551
1557
// Not `Iterator::all` because we don't want to short-circuit.
1552
1558
for subcandidate in & mut candidate. subcandidates {
1553
- self . merge_trivial_subcandidates ( subcandidate, source_info ) ;
1559
+ self . merge_trivial_subcandidates ( subcandidate) ;
1554
1560
1555
1561
// FIXME(or_patterns; matthewjasper) Try to be more aggressive here.
1556
1562
can_merge &=
@@ -1559,6 +1565,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1559
1565
1560
1566
if can_merge {
1561
1567
let any_matches = self . cfg . start_new_block ( ) ;
1568
+ let or_span = candidate. or_span . take ( ) . unwrap ( ) ;
1569
+ let source_info = self . source_info ( or_span) ;
1562
1570
for subcandidate in mem:: take ( & mut candidate. subcandidates ) {
1563
1571
let or_block = subcandidate. pre_binding_block . unwrap ( ) ;
1564
1572
self . cfg . goto ( or_block, source_info, any_matches) ;
0 commit comments