@@ -48,16 +48,51 @@ struct ExtractedEnumDetails {
48
48
n_snapshots : usize ,
49
49
}
50
50
51
- /// MatchArm wrapper that allows for optional expression clause.
52
- /// Used in the case of if-let with missing else clause.
53
- pub struct MatchArmWrapper {
54
- pub patterns : Vec < PatternId > ,
55
- pub expr : Option < semantic:: ExprId > ,
51
+ /// A wrapper enum to provide a unified interface for handling different types of match arms
52
+ /// during the lowering phase of the compiler, allowing for consistent pattern matching
53
+ /// and expression evaluation across different match-like constructs.
54
+ pub enum MatchArmWrapper < ' a > {
55
+ /// A match arm. Patterns (non-empty) guard the expression to evaluate.
56
+ Arm ( & ' a [ PatternId ] , semantic:: ExprId ) ,
57
+ /// Else clause (no patterns) and it's expression to evaluate (if-let).
58
+ ElseClause ( semantic:: ExprId ) ,
59
+ /// Default clause when else clause is not provided (if-let/while-let).
60
+ DefaultClause ,
56
61
}
57
62
58
- impl From < & semantic:: MatchArm > for MatchArmWrapper {
59
- fn from ( arm : & semantic:: MatchArm ) -> Self {
60
- Self { patterns : arm. patterns . clone ( ) , expr : Some ( arm. expression ) }
63
+ impl < ' a > From < & ' a semantic:: MatchArm > for MatchArmWrapper < ' a > {
64
+ fn from ( arm : & ' a semantic:: MatchArm ) -> Self {
65
+ MatchArmWrapper :: Arm ( & arm. patterns , arm. expression )
66
+ }
67
+ }
68
+
69
+ impl MatchArmWrapper < ' _ > {
70
+ /// Returns the expression of the guarded by the match arm.
71
+ pub fn expr ( & self ) -> Option < semantic:: ExprId > {
72
+ match self {
73
+ MatchArmWrapper :: Arm ( _, expr) => Some ( * expr) ,
74
+ MatchArmWrapper :: ElseClause ( expr) => Some ( * expr) ,
75
+ MatchArmWrapper :: DefaultClause => None ,
76
+ }
77
+ }
78
+
79
+ /// Returns the patterns of the match arm.
80
+ pub fn patterns ( & self ) -> Option < & [ PatternId ] > {
81
+ match self {
82
+ MatchArmWrapper :: Arm ( patterns, _) => Some ( patterns) ,
83
+ MatchArmWrapper :: ElseClause ( _) => None ,
84
+ MatchArmWrapper :: DefaultClause => None ,
85
+ }
86
+ }
87
+
88
+ /// Try and extract the pattern from the match arm by index.
89
+ /// Returns None if the arm is a missing clause, else clause.
90
+ pub fn pattern < ' a > (
91
+ & self ,
92
+ ctx : & ' a LoweringContext < ' _ , ' _ > ,
93
+ index : usize ,
94
+ ) -> Option < & ' a Pattern > {
95
+ self . patterns ( ) . map ( |patterns| & ctx. function_body . arenas . patterns [ patterns[ index] ] )
61
96
}
62
97
}
63
98
@@ -126,65 +161,69 @@ struct PatternPath {
126
161
/// Returns an option containing the PatternPath of the underscore pattern, if it exists.
127
162
fn get_underscore_pattern_path_and_mark_unreachable (
128
163
ctx : & mut LoweringContext < ' _ , ' _ > ,
129
- arms : & [ MatchArmWrapper ] ,
164
+ arms : & [ MatchArmWrapper < ' _ > ] ,
130
165
match_type : MatchKind ,
131
166
) -> Option < PatternPath > {
132
167
let otherwise_variant = arms
133
168
. iter ( )
134
169
. enumerate ( )
135
170
. filter_map ( |( arm_index, arm) | {
136
- let pattern_index = if arm. patterns . is_empty ( ) {
137
- // Special path for if-let else clause where no patterns exist.
138
- None
139
- } else {
140
- let position = arm . patterns . iter ( ) . position ( | pattern| {
141
- matches ! (
142
- ctx . function_body . arenas . patterns [ * pattern ] ,
143
- semantic :: Pattern :: Otherwise ( _ )
144
- )
145
- } ) ? ;
146
- Some ( position )
171
+ let pattern_index = match arm {
172
+ MatchArmWrapper :: Arm ( patterns , _ ) => {
173
+ let position = patterns . iter ( ) . position ( |pattern| {
174
+ matches ! (
175
+ ctx . function_body . arenas . patterns [ * pattern] ,
176
+ semantic :: Pattern :: Otherwise ( _ )
177
+ )
178
+ } ) ? ;
179
+ Some ( position )
180
+ }
181
+ MatchArmWrapper :: DefaultClause | MatchArmWrapper :: ElseClause ( _ ) => None ,
147
182
} ;
148
183
Some ( PatternPath { arm_index, pattern_index } )
149
184
} )
150
185
. next ( ) ?;
151
186
152
187
for arm in arms. iter ( ) . skip ( otherwise_variant. arm_index + 1 ) {
153
- if arm. patterns . is_empty ( ) && arm. expr . is_some ( ) {
154
- let expr = ctx. function_body . arenas . exprs [ arm. expr . unwrap ( ) ] . clone ( ) ;
155
- ctx. diagnostics . report (
156
- & expr,
157
- MatchError ( MatchError {
158
- kind : match_type,
159
- error : MatchDiagnostic :: UnreachableMatchArm ,
160
- } ) ,
161
- ) ;
188
+ match arm {
189
+ MatchArmWrapper :: Arm ( patterns, _expr) => {
190
+ for pattern in patterns. iter ( ) {
191
+ let pattern_ptr = ctx. function_body . arenas . patterns [ * pattern] . stable_ptr ( ) ;
192
+ ctx. diagnostics . report (
193
+ pattern_ptr,
194
+ MatchError ( MatchError {
195
+ kind : match_type,
196
+ error : MatchDiagnostic :: UnreachableMatchArm ,
197
+ } ) ,
198
+ ) ;
199
+ }
200
+ }
201
+ MatchArmWrapper :: DefaultClause => continue ,
202
+ MatchArmWrapper :: ElseClause ( e) => {
203
+ let expr_ptr = ctx. function_body . arenas . exprs [ * e] . stable_ptr ( ) ;
204
+ ctx. diagnostics . report (
205
+ expr_ptr,
206
+ MatchError ( MatchError {
207
+ kind : match_type,
208
+ error : MatchDiagnostic :: UnreachableMatchArm ,
209
+ } ) ,
210
+ ) ;
211
+ }
162
212
}
163
- for pattern in arm. patterns . iter ( ) {
164
- let pattern = ctx. function_body . arenas . patterns [ * pattern] . clone ( ) ;
213
+ }
214
+
215
+ if let Some ( patterns) = arms[ otherwise_variant. arm_index ] . patterns ( ) {
216
+ for pattern in patterns. iter ( ) . skip ( otherwise_variant. pattern_index . unwrap_or ( 0 ) + 1 ) {
217
+ let pattern = & ctx. function_body . arenas . patterns [ * pattern] ;
165
218
ctx. diagnostics . report (
166
- & pattern,
219
+ pattern. stable_ptr ( ) ,
167
220
MatchError ( MatchError {
168
221
kind : match_type,
169
222
error : MatchDiagnostic :: UnreachableMatchArm ,
170
223
} ) ,
171
224
) ;
172
225
}
173
226
}
174
- for pattern in arms[ otherwise_variant. arm_index ]
175
- . patterns
176
- . iter ( )
177
- . skip ( otherwise_variant. pattern_index . unwrap_or ( 0 ) + 1 )
178
- {
179
- let pattern = ctx. function_body . arenas . patterns [ * pattern] . clone ( ) ;
180
- ctx. diagnostics . report (
181
- & pattern,
182
- MatchError ( MatchError {
183
- kind : match_type,
184
- error : MatchDiagnostic :: UnreachableMatchArm ,
185
- } ) ,
186
- ) ;
187
- }
188
227
189
228
Some ( otherwise_variant)
190
229
}
@@ -289,7 +328,7 @@ impl VariantMatchTree {
289
328
/// Returns a map from variants to their corresponding pattern path in a match statement.
290
329
fn get_variant_to_arm_map (
291
330
ctx : & mut LoweringContext < ' _ , ' _ > ,
292
- arms : & [ MatchArmWrapper ] ,
331
+ arms : & [ MatchArmWrapper < ' _ > ] ,
293
332
concrete_enum_id : semantic:: ConcreteEnumId ,
294
333
match_type : MatchKind ,
295
334
) -> LoweringResult < UnorderedHashMap < semantic:: ConcreteVariant , PatternPath > > {
@@ -298,7 +337,10 @@ fn get_variant_to_arm_map(
298
337
// A::B(_). Check pattern is legal and collect paths.
299
338
let mut variant_map = VariantMatchTree :: Empty ;
300
339
for ( arm_index, arm) in arms. iter ( ) . enumerate ( ) {
301
- for ( pattern_index, mut pattern) in arm. patterns . iter ( ) . copied ( ) . enumerate ( ) {
340
+ let Some ( patterns) = arm. patterns ( ) else {
341
+ continue ;
342
+ } ;
343
+ for ( pattern_index, mut pattern) in patterns. iter ( ) . copied ( ) . enumerate ( ) {
302
344
let pattern_path = PatternPath { arm_index, pattern_index : Some ( pattern_index) } ;
303
345
let pattern_ptr = ctx. function_body . arenas . patterns [ pattern] . stable_ptr ( ) ;
304
346
@@ -531,13 +573,16 @@ fn insert_tuple_path_patterns(
531
573
/// Returns a map from a matching paths to their corresponding pattern path in a match statement.
532
574
fn get_variants_to_arm_map_tuple < ' a > (
533
575
ctx : & mut LoweringContext < ' _ , ' _ > ,
534
- arms : impl Iterator < Item = & ' a MatchArmWrapper > ,
576
+ arms : impl Iterator < Item = & ' a MatchArmWrapper < ' a > > ,
535
577
extracted_enums_details : & [ ExtractedEnumDetails ] ,
536
578
match_type : MatchKind ,
537
579
) -> LoweringResult < UnorderedHashMap < MatchingPath , PatternPath > > {
538
580
let mut map = UnorderedHashMap :: default ( ) ;
539
581
for ( arm_index, arm) in arms. enumerate ( ) {
540
- for ( pattern_index, pattern) in arm. patterns . iter ( ) . enumerate ( ) {
582
+ let Some ( patterns) = arm. patterns ( ) else {
583
+ continue ;
584
+ } ;
585
+ for ( pattern_index, pattern) in patterns. iter ( ) . enumerate ( ) {
541
586
let pattern = ctx. function_body . arenas . patterns [ * pattern] . clone ( ) ;
542
587
if let semantic:: Pattern :: Otherwise ( _) = pattern {
543
588
break ;
@@ -599,7 +644,7 @@ struct LoweringMatchTupleContext {
599
644
fn lower_tuple_match_arm (
600
645
ctx : & mut LoweringContext < ' _ , ' _ > ,
601
646
mut builder : BlockBuilder ,
602
- arms : & [ MatchArmWrapper ] ,
647
+ arms : & [ MatchArmWrapper < ' _ > ] ,
603
648
match_tuple_ctx : & mut LoweringMatchTupleContext ,
604
649
leaves_builders : & mut Vec < MatchLeafBuilder > ,
605
650
match_type : MatchKind ,
@@ -623,11 +668,12 @@ fn lower_tuple_match_arm(
623
668
} ) ,
624
669
) )
625
670
} ) ?;
626
- let pattern = pattern_path. pattern_index . map ( |pattern_index| {
627
- ctx. function_body . arenas . patterns [ arms[ pattern_path. arm_index ] . patterns [ pattern_index] ]
671
+ let pattern = pattern_path. pattern_index . map ( |i| {
672
+ arms[ pattern_path. arm_index ]
673
+ . pattern ( ctx, i)
674
+ . expect ( "Pattern previously found in arm, but is now missing at index." )
628
675
. clone ( )
629
676
} ) ;
630
-
631
677
let lowering_inner_pattern_result = match pattern {
632
678
Some ( semantic:: Pattern :: Tuple ( patterns) ) => patterns
633
679
. field_patterns
@@ -664,8 +710,9 @@ fn lower_tuple_match_arm(
664
710
. map ( |_| ( ) ) ,
665
711
Some ( semantic:: Pattern :: Otherwise ( _) ) | None => Ok ( ( ) ) ,
666
712
_ => {
713
+ let stable_ptr = pattern. unwrap ( ) . stable_ptr ( ) ;
667
714
return Err ( LoweringFlowError :: Failed ( ctx. diagnostics . report (
668
- & pattern . unwrap ( ) ,
715
+ stable_ptr ,
669
716
MatchError ( MatchError {
670
717
kind : match_type,
671
718
error : MatchDiagnostic :: UnsupportedMatchArmNotATuple ,
@@ -685,7 +732,7 @@ fn lower_tuple_match_arm(
685
732
fn lower_full_match_tree (
686
733
ctx : & mut LoweringContext < ' _ , ' _ > ,
687
734
builder : & mut BlockBuilder ,
688
- arms : & [ MatchArmWrapper ] ,
735
+ arms : & [ MatchArmWrapper < ' _ > ] ,
689
736
match_tuple_ctx : & mut LoweringMatchTupleContext ,
690
737
extracted_enums_details : & [ ExtractedEnumDetails ] ,
691
738
leaves_builders : & mut Vec < MatchLeafBuilder > ,
@@ -775,7 +822,7 @@ pub(crate) fn lower_expr_match_tuple(
775
822
expr : LoweredExpr ,
776
823
matched_expr : semantic:: ExprId ,
777
824
tuple_info : & TupleInfo ,
778
- arms : & [ MatchArmWrapper ] ,
825
+ arms : & [ MatchArmWrapper < ' _ > ] ,
779
826
match_type : MatchKind ,
780
827
) -> LoweringResult < LoweredExpr > {
781
828
let location = expr. location ( ) ;
@@ -897,7 +944,7 @@ pub(crate) fn lower_match_arms(
897
944
builder : & mut BlockBuilder ,
898
945
matched_expr : semantic:: ExprId ,
899
946
lowered_expr : LoweredExpr ,
900
- arms : Vec < MatchArmWrapper > ,
947
+ arms : Vec < MatchArmWrapper < ' _ > > ,
901
948
location : LocationId ,
902
949
match_type : MatchKind ,
903
950
) -> Result < LoweredExpr , LoweringFlowError > {
@@ -934,7 +981,7 @@ pub(crate) fn lower_concrete_enum_match(
934
981
builder : & mut BlockBuilder ,
935
982
matched_expr : semantic:: ExprId ,
936
983
lowered_matched_expr : LoweredExpr ,
937
- arms : & [ MatchArmWrapper ] ,
984
+ arms : & [ MatchArmWrapper < ' _ > ] ,
938
985
location : LocationId ,
939
986
match_type : MatchKind ,
940
987
) -> LoweringResult < LoweredExpr > {
@@ -976,7 +1023,8 @@ pub(crate) fn lower_concrete_enum_match(
976
1023
let mut subscope = create_subscope ( ctx, builder) ;
977
1024
978
1025
let pattern = pattern_index. map ( |pattern_index| {
979
- & ctx. function_body . arenas . patterns [ arm. patterns [ pattern_index] ]
1026
+ arm. pattern ( ctx, pattern_index)
1027
+ . expect ( "Pattern was previously found and should be present in the arm." )
980
1028
} ) ;
981
1029
let block_id = subscope. block_id ;
982
1030
block_ids. push ( block_id) ;
@@ -1005,9 +1053,10 @@ pub(crate) fn lower_concrete_enum_match(
1005
1053
Pattern :: EnumVariant ( PatternEnumVariant { inner_pattern : None , .. } )
1006
1054
| Pattern :: Otherwise ( _) ,
1007
1055
) => {
1056
+ let location = ctx. get_location ( pattern. unwrap ( ) . into ( ) ) ;
1008
1057
let var_id = ctx. new_var ( VarRequest {
1009
1058
ty : wrap_in_snapshots ( ctx. db , concrete_variant. ty , n_snapshots) ,
1010
- location : ctx . get_location ( pattern . unwrap ( ) . into ( ) ) ,
1059
+ location,
1011
1060
} ) ;
1012
1061
arm_var_ids. push ( vec ! [ var_id] ) ;
1013
1062
Ok ( ( ) )
@@ -1071,7 +1120,7 @@ pub(crate) fn lower_optimized_extern_match(
1071
1120
ctx : & mut LoweringContext < ' _ , ' _ > ,
1072
1121
builder : & mut BlockBuilder ,
1073
1122
extern_enum : LoweredExprExternEnum ,
1074
- match_arms : & [ MatchArmWrapper ] ,
1123
+ match_arms : & [ MatchArmWrapper < ' _ > ] ,
1075
1124
match_type : MatchKind ,
1076
1125
) -> LoweringResult < LoweredExpr > {
1077
1126
log:: trace!( "Started lowering of an optimized extern match." ) ;
@@ -1127,9 +1176,8 @@ pub(crate) fn lower_optimized_extern_match(
1127
1176
} ) ?;
1128
1177
1129
1178
let arm = & match_arms[ * arm_index] ;
1130
- let pattern = pattern_index. map ( |pattern_index| {
1131
- & ctx. function_body . arenas . patterns [ arm. patterns [ pattern_index] ]
1132
- } ) ;
1179
+ let pattern =
1180
+ pattern_index. map ( |pattern_index| arm. pattern ( ctx, pattern_index) . unwrap ( ) ) ;
1133
1181
1134
1182
let lowering_inner_pattern_result = match pattern {
1135
1183
Some ( Pattern :: EnumVariant ( PatternEnumVariant {
@@ -1197,7 +1245,7 @@ fn group_match_arms(
1197
1245
ctx : & mut LoweringContext < ' _ , ' _ > ,
1198
1246
empty_match_info : MatchInfo ,
1199
1247
location : LocationId ,
1200
- arms : & [ MatchArmWrapper ] ,
1248
+ arms : & [ MatchArmWrapper < ' _ > ] ,
1201
1249
variants_block_builders : Vec < MatchLeafBuilder > ,
1202
1250
kind : MatchKind ,
1203
1251
) -> LoweringResult < Vec < SealedBlockBuilder > > {
@@ -1220,7 +1268,7 @@ fn group_match_arms(
1220
1268
return match lowering_inner_pattern_result {
1221
1269
Ok ( _) => {
1222
1270
// Lower the arm expression.
1223
- match ( arm. expr , kind) {
1271
+ match ( arm. expr ( ) , kind) {
1224
1272
( Some ( expr) , MatchKind :: IfLet | MatchKind :: Match ) => {
1225
1273
lower_tail_expr ( ctx, subscope, expr)
1226
1274
}
@@ -1266,8 +1314,8 @@ fn group_match_arms(
1266
1314
. map ( |( lowering_inner_pattern_result, subscope) | {
1267
1315
// Use the first pattern for the location of the for variable assignment block.
1268
1316
let location = arm
1269
- . patterns
1270
- . first ( )
1317
+ . patterns ( )
1318
+ . and_then ( |ps| ps . first ( ) )
1271
1319
. map ( |pattern| {
1272
1320
ctx. get_location (
1273
1321
ctx. function_body . arenas . patterns [ * pattern] . stable_ptr ( ) . untyped ( ) ,
@@ -1292,7 +1340,7 @@ fn group_match_arms(
1292
1340
sealed_blocks,
1293
1341
location,
1294
1342
) ?;
1295
- match ( arm. expr , kind) {
1343
+ match ( arm. expr ( ) , kind) {
1296
1344
( Some ( expr) , MatchKind :: IfLet | MatchKind :: Match ) => {
1297
1345
lower_tail_expr ( ctx, outer_subscope, expr)
1298
1346
}
0 commit comments