@@ -153,18 +153,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
153
153
arms. iter ( )
154
154
. map ( |arm| {
155
155
let arm_has_guard = arm. guard . is_some ( ) ;
156
- let arm_candidate = Candidate {
157
- span : arm. pattern . span ,
158
- match_pairs : smallvec ! [ MatchPair :: new( * scrutinee, & arm. pattern) , ] ,
159
- bindings : vec ! [ ] ,
160
- ascriptions : vec ! [ ] ,
161
- has_guard : arm_has_guard,
162
- needs_otherwise_block : arm_has_guard,
163
- otherwise_block : None ,
164
- pre_binding_block : None ,
165
- next_candidate_pre_binding_block : None ,
166
- subcandidates : vec ! [ ] ,
167
- } ;
156
+ let arm_candidate = Candidate :: new ( * scrutinee, & arm. pattern , arm_has_guard) ;
168
157
( arm, arm_candidate)
169
158
} )
170
159
. collect ( )
@@ -195,10 +184,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
195
184
self . match_candidates ( scrutinee_span, block, & mut otherwise, candidates, & mut fake_borrows) ;
196
185
197
186
if let Some ( otherwise_block) = otherwise {
187
+ // See the doc comment on `match_candidates` for why we may have an
188
+ // otherwise block. Match checking will ensure this is actually
189
+ // unreachable.
198
190
let source_info = self . source_info ( scrutinee_span) ;
199
191
self . cfg . terminate ( otherwise_block, source_info, TerminatorKind :: Unreachable ) ;
200
192
}
201
193
194
+ // Link each leaf candidate to the `pre_binding_block` of the next one.
202
195
let mut previous_candidate: Option < & mut Candidate < ' _ , ' _ > > = None ;
203
196
204
197
for candidate in candidates {
@@ -449,29 +442,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
449
442
initializer : & Place < ' tcx > ,
450
443
set_match_place : bool ,
451
444
) -> BlockAnd < ( ) > {
452
- // create a dummy candidate
453
- let mut candidate = Candidate {
454
- span : irrefutable_pat. span ,
455
- has_guard : false ,
456
- needs_otherwise_block : false ,
457
- match_pairs : smallvec ! [ MatchPair :: new( * initializer, & irrefutable_pat) ] ,
458
- bindings : vec ! [ ] ,
459
- ascriptions : vec ! [ ] ,
460
-
461
- // since we don't call `match_candidates`, next fields are unused
462
- otherwise_block : None ,
463
- pre_binding_block : None ,
464
- next_candidate_pre_binding_block : None ,
465
- subcandidates : vec ! [ ] ,
466
- } ;
445
+ let mut candidate = Candidate :: new ( * initializer, & irrefutable_pat, false ) ;
467
446
468
447
let fake_borrow_temps =
469
448
self . lower_match_tree ( block, irrefutable_pat. span , false , & mut [ & mut candidate] ) ;
470
449
471
- // for matches and function arguments, the place that is being matched
450
+ // For matches and function arguments, the place that is being matched
472
451
// can be set when creating the variables. But the place for
473
452
// let PATTERN = ... might not even exist until we do the assignment.
474
- // so we set it here instead
453
+ // so we set it here instead.
475
454
if set_match_place {
476
455
let mut candidate_ref = & candidate;
477
456
while let Some ( next) = {
@@ -487,6 +466,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
487
466
bug ! ( "Let binding to non-user variable." )
488
467
}
489
468
}
469
+ // All of the subcandidates should bind the same locals, so we
470
+ // only visit the first one.
490
471
candidate_ref. subcandidates . get ( 0 )
491
472
} {
492
473
candidate_ref = next;
@@ -666,10 +647,6 @@ struct Candidate<'pat, 'tcx> {
666
647
/// This `Candidate` has a guard.
667
648
has_guard : bool ,
668
649
669
- /// This `Candidate` needs and otherwise block, either because it has a
670
- /// guard or it has subcandidates.
671
- needs_otherwise_block : bool ,
672
-
673
650
/// All of these must be satisfied...
674
651
match_pairs : SmallVec < [ MatchPair < ' pat , ' tcx > ; 1 ] > ,
675
652
@@ -690,7 +667,21 @@ struct Candidate<'pat, 'tcx> {
690
667
next_candidate_pre_binding_block : Option < BasicBlock > ,
691
668
}
692
669
693
- impl Candidate < ' _ , ' _ > {
670
+ impl < ' tcx , ' pat > Candidate < ' pat , ' tcx > {
671
+ fn new ( place : Place < ' tcx > , pattern : & ' pat Pat < ' tcx > , has_guard : bool ) -> Self {
672
+ Candidate {
673
+ span : pattern. span ,
674
+ has_guard,
675
+ match_pairs : smallvec ! [ MatchPair { place, pattern } ] ,
676
+ bindings : Vec :: new ( ) ,
677
+ ascriptions : Vec :: new ( ) ,
678
+ subcandidates : Vec :: new ( ) ,
679
+ otherwise_block : None ,
680
+ pre_binding_block : None ,
681
+ next_candidate_pre_binding_block : None ,
682
+ }
683
+ }
684
+
694
685
/// Visit the leaf candidates (those with no subcandidates) contained in
695
686
/// this candidate.
696
687
fn visit_leaves < ' a > ( & ' a mut self , mut visit_leaf : impl FnMut ( & ' a mut Self ) ) {
@@ -839,6 +830,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
839
830
///
840
831
/// If `fake_borrows` is Some, then places which need fake borrows
841
832
/// will be added to it.
833
+ ///
834
+ /// For an example of a case where we set `otherwise_block`, even for an
835
+ /// exhaustive match consider:
836
+ ///
837
+ /// match x {
838
+ /// (true, true) => (),
839
+ /// (_, false) => (),
840
+ /// (false, true) => (),
841
+ /// }
842
+ ///
843
+ /// For this match we check if `x.0` matches `true` (for the first
844
+ /// arm) if that's false we check `x.1`, if it's `true` we check if
845
+ /// `x.0` matches `false` (for the third arm). In the (impossible at
846
+ /// runtime) case when `x.0` is now `true` we branch to
847
+ /// `otherwise_block`.
842
848
fn match_candidates < ' pat > (
843
849
& mut self ,
844
850
span : Span ,
@@ -1009,7 +1015,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1009
1015
1010
1016
let fully_matched_with_guard = matched_candidates
1011
1017
. iter ( )
1012
- . position ( |c| !c. needs_otherwise_block )
1018
+ . position ( |c| !c. has_guard )
1013
1019
. unwrap_or ( matched_candidates. len ( ) - 1 ) ;
1014
1020
1015
1021
let ( reachable_candidates, unreachable_candidates) =
@@ -1021,7 +1027,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1021
1027
assert ! ( candidate. otherwise_block. is_none( ) ) ;
1022
1028
assert ! ( candidate. pre_binding_block. is_none( ) ) ;
1023
1029
candidate. pre_binding_block = Some ( next_prebinding) ;
1024
- if candidate. needs_otherwise_block {
1030
+ if candidate. has_guard {
1031
+ // Create the otherwise block for this candidate, which is the
1032
+ // pre-binding block for the next candidate.
1025
1033
next_prebinding = self . cfg . start_new_block ( ) ;
1026
1034
candidate. otherwise_block = Some ( next_prebinding) ;
1027
1035
}
@@ -1039,6 +1047,53 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1039
1047
reachable_candidates. last_mut ( ) . unwrap ( ) . otherwise_block
1040
1048
}
1041
1049
1050
+ /// Tests a candidate where there are only or-patterns left to test, or
1051
+ /// forwards to [Builder::test_candidates].
1052
+ ///
1053
+ /// Given a pattern `(P | Q, R | S)` we (in principle) generate a CFG like
1054
+ /// so
1055
+ ///
1056
+ /// ```text
1057
+ /// [ start ]
1058
+ /// |
1059
+ /// [ match P, Q ]
1060
+ /// |
1061
+ /// +----------------------------------------+------------------------------------+
1062
+ /// | | |
1063
+ /// [ P matches ] [ Q matches ] [ otherwise ]
1064
+ /// | | |
1065
+ /// [ match R, S ] [ match R, S ] |
1066
+ /// | | |
1067
+ /// +--------------+------------+ +--------------+------------+ |
1068
+ /// | | | | | | |
1069
+ /// [ R matches ] [ S matches ] [otherwise ] [ R matches ] [ S matches ] [otherwise ] |
1070
+ /// | | | | | | |
1071
+ /// +--------------+------------|------------+--------------+ | |
1072
+ /// | | | |
1073
+ /// | +----------------------------------------+--------+
1074
+ /// | |
1075
+ /// [ Success ] [ Failure ]
1076
+ /// ```
1077
+ ///
1078
+ /// In practice there are some complications:
1079
+ ///
1080
+ /// * If there's a guard, then the otherwise branch of the first match on
1081
+ /// `R | S` goes to a test for whether `Q` matches.
1082
+ /// * If neither `P` or `Q` has any bindings or type ascriptions and there
1083
+ /// isn't a match guard, then we create a smaller CFG like:
1084
+ ///
1085
+ /// ```text
1086
+ /// ...
1087
+ /// +---------------+------------+
1088
+ /// | | |
1089
+ /// [ P matches ] [ Q matches ] [ otherwise ]
1090
+ /// | | |
1091
+ /// +---------------+ |
1092
+ /// | ...
1093
+ /// [ match R, S ]
1094
+ /// |
1095
+ /// ...
1096
+ /// ```
1042
1097
fn test_candidates_with_or (
1043
1098
& mut self ,
1044
1099
span : Span ,
@@ -1049,42 +1104,53 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1049
1104
) {
1050
1105
let ( first_candidate, remaining_candidates) = candidates. split_first_mut ( ) . unwrap ( ) ;
1051
1106
1052
- if let PatKind :: Or { .. } = * first_candidate. match_pairs [ 0 ] . pattern . kind {
1053
- let match_pairs = mem:: take ( & mut first_candidate. match_pairs ) ;
1054
- first_candidate. needs_otherwise_block = true ;
1055
- first_candidate. pre_binding_block = Some ( block) ;
1107
+ match * first_candidate. match_pairs [ 0 ] . pattern . kind {
1108
+ PatKind :: Or { .. } => ( ) ,
1109
+ _ => {
1110
+ self . test_candidates ( span, candidates, block, otherwise_block, fake_borrows) ;
1111
+ return ;
1112
+ }
1113
+ }
1056
1114
1057
- // We sort or-patterns to the end in `simplify_candidate`, so all
1058
- // the remaining match pairs are or-patterns.
1059
- for match_pair in match_pairs {
1060
- if let PatKind :: Or { ref pats } = * match_pair. pattern . kind {
1061
- let or_span = match_pair. pattern . span ;
1062
- let place = & match_pair. place ;
1115
+ let match_pairs = mem:: take ( & mut first_candidate. match_pairs ) ;
1116
+ first_candidate. pre_binding_block = Some ( block) ;
1063
1117
1064
- first_candidate. visit_leaves ( |leaf_candidate| {
1065
- self . test_or_pattern ( leaf_candidate, pats, or_span, place, fake_borrows) ;
1066
- } ) ;
1067
- } else {
1068
- bug ! ( "Or patterns should have been sorted to the end" ) ;
1069
- }
1118
+ let mut otherwise = None ;
1119
+ for match_pair in match_pairs {
1120
+ if let PatKind :: Or { ref pats } = * match_pair. pattern . kind {
1121
+ let or_span = match_pair. pattern . span ;
1122
+ let place = & match_pair. place ;
1123
+
1124
+ first_candidate. visit_leaves ( |leaf_candidate| {
1125
+ self . test_or_pattern (
1126
+ leaf_candidate,
1127
+ & mut otherwise,
1128
+ pats,
1129
+ or_span,
1130
+ place,
1131
+ fake_borrows,
1132
+ ) ;
1133
+ } ) ;
1134
+ } else {
1135
+ bug ! ( "Or-patterns should have been sorted to the end" ) ;
1070
1136
}
1071
- let remainder_start =
1072
- first_candidate. otherwise_block . unwrap_or_else ( || self . cfg . start_new_block ( ) ) ;
1073
- self . match_candidates (
1074
- span,
1075
- remainder_start,
1076
- otherwise_block,
1077
- remaining_candidates,
1078
- fake_borrows,
1079
- )
1080
- } else {
1081
- self . test_candidates ( span, candidates, block, otherwise_block, fake_borrows)
1082
1137
}
1138
+
1139
+ let remainder_start = otherwise. unwrap_or_else ( || self . cfg . start_new_block ( ) ) ;
1140
+
1141
+ self . match_candidates (
1142
+ span,
1143
+ remainder_start,
1144
+ otherwise_block,
1145
+ remaining_candidates,
1146
+ fake_borrows,
1147
+ )
1083
1148
}
1084
1149
1085
1150
fn test_or_pattern < ' pat > (
1086
1151
& mut self ,
1087
1152
candidate : & mut Candidate < ' pat , ' tcx > ,
1153
+ otherwise : & mut Option < BasicBlock > ,
1088
1154
pats : & ' pat [ Pat < ' tcx > ] ,
1089
1155
or_span : Span ,
1090
1156
place : & Place < ' tcx > ,
@@ -1093,27 +1159,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1093
1159
debug ! ( "test_or_pattern:\n candidate={:#?}\n pats={:#?}" , candidate, pats) ;
1094
1160
let mut or_candidates: Vec < _ > = pats
1095
1161
. iter ( )
1096
- . map ( |pat| {
1097
- let new_match_pair = smallvec ! [ MatchPair { pattern: pat, place: place. clone( ) } ] ;
1098
- Candidate {
1099
- span : pat. span ,
1100
- has_guard : candidate. has_guard ,
1101
- needs_otherwise_block : candidate. needs_otherwise_block ,
1102
- match_pairs : new_match_pair,
1103
- bindings : Vec :: new ( ) ,
1104
- ascriptions : Vec :: new ( ) ,
1105
- otherwise_block : None ,
1106
- pre_binding_block : None ,
1107
- next_candidate_pre_binding_block : None ,
1108
- subcandidates : Vec :: new ( ) ,
1109
- }
1110
- } )
1162
+ . map ( |pat| Candidate :: new ( place. clone ( ) , pat, candidate. has_guard ) )
1111
1163
. collect ( ) ;
1112
1164
let mut or_candidate_refs: Vec < _ > = or_candidates. iter_mut ( ) . collect ( ) ;
1165
+ let otherwise = if candidate. otherwise_block . is_some ( ) {
1166
+ & mut candidate. otherwise_block
1167
+ } else {
1168
+ otherwise
1169
+ } ;
1113
1170
self . match_candidates (
1114
1171
or_span,
1115
1172
candidate. pre_binding_block . unwrap ( ) ,
1116
- & mut candidate . otherwise_block ,
1173
+ otherwise ,
1117
1174
& mut or_candidate_refs,
1118
1175
fake_borrows,
1119
1176
) ;
@@ -1128,10 +1185,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1128
1185
candidate : & mut Candidate < ' _ , ' tcx > ,
1129
1186
source_info : SourceInfo ,
1130
1187
) {
1131
- if candidate. subcandidates . is_empty ( ) {
1188
+ if candidate. subcandidates . is_empty ( ) || candidate. has_guard {
1189
+ // FIXME(or_patterns; matthewjasper) Don't give up if we have a guard.
1132
1190
return ;
1133
1191
}
1134
- let mut can_merge = !candidate. has_guard ;
1192
+
1193
+ let mut can_merge = true ;
1135
1194
1136
1195
// Not `Iterator::all` because we don't want to short-circuit.
1137
1196
for subcandidate in & mut candidate. subcandidates {
0 commit comments