@@ -48,16 +48,51 @@ struct ExtractedEnumDetails {
4848 n_snapshots : usize ,
4949}
5050
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 ,
5661}
5762
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] ] )
6196 }
6297}
6398
@@ -126,65 +161,69 @@ struct PatternPath {
126161/// Returns an option containing the PatternPath of the underscore pattern, if it exists.
127162fn get_underscore_pattern_path_and_mark_unreachable (
128163 ctx : & mut LoweringContext < ' _ , ' _ > ,
129- arms : & [ MatchArmWrapper ] ,
164+ arms : & [ MatchArmWrapper < ' _ > ] ,
130165 match_type : MatchKind ,
131166) -> Option < PatternPath > {
132167 let otherwise_variant = arms
133168 . iter ( )
134169 . enumerate ( )
135170 . 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 ,
147182 } ;
148183 Some ( PatternPath { arm_index, pattern_index } )
149184 } )
150185 . next ( ) ?;
151186
152187 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+ }
162212 }
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] ;
165218 ctx. diagnostics . report (
166- & pattern,
219+ pattern. stable_ptr ( ) ,
167220 MatchError ( MatchError {
168221 kind : match_type,
169222 error : MatchDiagnostic :: UnreachableMatchArm ,
170223 } ) ,
171224 ) ;
172225 }
173226 }
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- }
188227
189228 Some ( otherwise_variant)
190229}
@@ -289,7 +328,7 @@ impl VariantMatchTree {
289328/// Returns a map from variants to their corresponding pattern path in a match statement.
290329fn get_variant_to_arm_map (
291330 ctx : & mut LoweringContext < ' _ , ' _ > ,
292- arms : & [ MatchArmWrapper ] ,
331+ arms : & [ MatchArmWrapper < ' _ > ] ,
293332 concrete_enum_id : semantic:: ConcreteEnumId ,
294333 match_type : MatchKind ,
295334) -> LoweringResult < UnorderedHashMap < semantic:: ConcreteVariant , PatternPath > > {
@@ -298,7 +337,10 @@ fn get_variant_to_arm_map(
298337 // A::B(_). Check pattern is legal and collect paths.
299338 let mut variant_map = VariantMatchTree :: Empty ;
300339 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 ( ) {
302344 let pattern_path = PatternPath { arm_index, pattern_index : Some ( pattern_index) } ;
303345 let pattern_ptr = ctx. function_body . arenas . patterns [ pattern] . stable_ptr ( ) ;
304346
@@ -531,13 +573,16 @@ fn insert_tuple_path_patterns(
531573/// Returns a map from a matching paths to their corresponding pattern path in a match statement.
532574fn get_variants_to_arm_map_tuple < ' a > (
533575 ctx : & mut LoweringContext < ' _ , ' _ > ,
534- arms : impl Iterator < Item = & ' a MatchArmWrapper > ,
576+ arms : impl Iterator < Item = & ' a MatchArmWrapper < ' a > > ,
535577 extracted_enums_details : & [ ExtractedEnumDetails ] ,
536578 match_type : MatchKind ,
537579) -> LoweringResult < UnorderedHashMap < MatchingPath , PatternPath > > {
538580 let mut map = UnorderedHashMap :: default ( ) ;
539581 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 ( ) {
541586 let pattern = ctx. function_body . arenas . patterns [ * pattern] . clone ( ) ;
542587 if let semantic:: Pattern :: Otherwise ( _) = pattern {
543588 break ;
@@ -599,7 +644,7 @@ struct LoweringMatchTupleContext {
599644fn lower_tuple_match_arm (
600645 ctx : & mut LoweringContext < ' _ , ' _ > ,
601646 mut builder : BlockBuilder ,
602- arms : & [ MatchArmWrapper ] ,
647+ arms : & [ MatchArmWrapper < ' _ > ] ,
603648 match_tuple_ctx : & mut LoweringMatchTupleContext ,
604649 leaves_builders : & mut Vec < MatchLeafBuilder > ,
605650 match_type : MatchKind ,
@@ -623,11 +668,9 @@ fn lower_tuple_match_arm(
623668 } ) ,
624669 ) )
625670 } ) ?;
626- let pattern = pattern_path. pattern_index . map ( |pattern_index| {
627- ctx. function_body . arenas . patterns [ arms[ pattern_path. arm_index ] . patterns [ pattern_index] ]
628- . clone ( )
629- } ) ;
630-
671+ let pattern = pattern_path
672+ . pattern_index
673+ . map ( |i| arms[ pattern_path. arm_index ] . pattern ( ctx, i) . unwrap ( ) . clone ( ) ) ;
631674 let lowering_inner_pattern_result = match pattern {
632675 Some ( semantic:: Pattern :: Tuple ( patterns) ) => patterns
633676 . field_patterns
@@ -664,8 +707,9 @@ fn lower_tuple_match_arm(
664707 . map ( |_| ( ) ) ,
665708 Some ( semantic:: Pattern :: Otherwise ( _) ) | None => Ok ( ( ) ) ,
666709 _ => {
710+ let stable_ptr = pattern. unwrap ( ) . stable_ptr ( ) ;
667711 return Err ( LoweringFlowError :: Failed ( ctx. diagnostics . report (
668- & pattern . unwrap ( ) ,
712+ stable_ptr ,
669713 MatchError ( MatchError {
670714 kind : match_type,
671715 error : MatchDiagnostic :: UnsupportedMatchArmNotATuple ,
@@ -685,7 +729,7 @@ fn lower_tuple_match_arm(
685729fn lower_full_match_tree (
686730 ctx : & mut LoweringContext < ' _ , ' _ > ,
687731 builder : & mut BlockBuilder ,
688- arms : & [ MatchArmWrapper ] ,
732+ arms : & [ MatchArmWrapper < ' _ > ] ,
689733 match_tuple_ctx : & mut LoweringMatchTupleContext ,
690734 extracted_enums_details : & [ ExtractedEnumDetails ] ,
691735 leaves_builders : & mut Vec < MatchLeafBuilder > ,
@@ -775,7 +819,7 @@ pub(crate) fn lower_expr_match_tuple(
775819 expr : LoweredExpr ,
776820 matched_expr : semantic:: ExprId ,
777821 tuple_info : & TupleInfo ,
778- arms : & [ MatchArmWrapper ] ,
822+ arms : & [ MatchArmWrapper < ' _ > ] ,
779823 match_type : MatchKind ,
780824) -> LoweringResult < LoweredExpr > {
781825 let location = expr. location ( ) ;
@@ -897,7 +941,7 @@ pub(crate) fn lower_match_arms(
897941 builder : & mut BlockBuilder ,
898942 matched_expr : semantic:: ExprId ,
899943 lowered_expr : LoweredExpr ,
900- arms : Vec < MatchArmWrapper > ,
944+ arms : Vec < MatchArmWrapper < ' _ > > ,
901945 location : LocationId ,
902946 match_type : MatchKind ,
903947) -> Result < LoweredExpr , LoweringFlowError > {
@@ -934,7 +978,7 @@ pub(crate) fn lower_concrete_enum_match(
934978 builder : & mut BlockBuilder ,
935979 matched_expr : semantic:: ExprId ,
936980 lowered_matched_expr : LoweredExpr ,
937- arms : & [ MatchArmWrapper ] ,
981+ arms : & [ MatchArmWrapper < ' _ > ] ,
938982 location : LocationId ,
939983 match_type : MatchKind ,
940984) -> LoweringResult < LoweredExpr > {
@@ -976,7 +1020,8 @@ pub(crate) fn lower_concrete_enum_match(
9761020 let mut subscope = create_subscope ( ctx, builder) ;
9771021
9781022 let pattern = pattern_index. map ( |pattern_index| {
979- & ctx. function_body . arenas . patterns [ arm. patterns [ pattern_index] ]
1023+ arm. pattern ( ctx, pattern_index)
1024+ . expect ( "Pattern was previously found and should be present in the arm." )
9801025 } ) ;
9811026 let block_id = subscope. block_id ;
9821027 block_ids. push ( block_id) ;
@@ -1005,9 +1050,10 @@ pub(crate) fn lower_concrete_enum_match(
10051050 Pattern :: EnumVariant ( PatternEnumVariant { inner_pattern : None , .. } )
10061051 | Pattern :: Otherwise ( _) ,
10071052 ) => {
1053+ let location = ctx. get_location ( pattern. unwrap ( ) . into ( ) ) ;
10081054 let var_id = ctx. new_var ( VarRequest {
10091055 ty : wrap_in_snapshots ( ctx. db , concrete_variant. ty , n_snapshots) ,
1010- location : ctx . get_location ( pattern . unwrap ( ) . into ( ) ) ,
1056+ location,
10111057 } ) ;
10121058 arm_var_ids. push ( vec ! [ var_id] ) ;
10131059 Ok ( ( ) )
@@ -1071,7 +1117,7 @@ pub(crate) fn lower_optimized_extern_match(
10711117 ctx : & mut LoweringContext < ' _ , ' _ > ,
10721118 builder : & mut BlockBuilder ,
10731119 extern_enum : LoweredExprExternEnum ,
1074- match_arms : & [ MatchArmWrapper ] ,
1120+ match_arms : & [ MatchArmWrapper < ' _ > ] ,
10751121 match_type : MatchKind ,
10761122) -> LoweringResult < LoweredExpr > {
10771123 log:: trace!( "Started lowering of an optimized extern match." ) ;
@@ -1127,9 +1173,8 @@ pub(crate) fn lower_optimized_extern_match(
11271173 } ) ?;
11281174
11291175 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- } ) ;
1176+ let pattern =
1177+ pattern_index. map ( |pattern_index| arm. pattern ( ctx, pattern_index) . unwrap ( ) ) ;
11331178
11341179 let lowering_inner_pattern_result = match pattern {
11351180 Some ( Pattern :: EnumVariant ( PatternEnumVariant {
@@ -1197,7 +1242,7 @@ fn group_match_arms(
11971242 ctx : & mut LoweringContext < ' _ , ' _ > ,
11981243 empty_match_info : MatchInfo ,
11991244 location : LocationId ,
1200- arms : & [ MatchArmWrapper ] ,
1245+ arms : & [ MatchArmWrapper < ' _ > ] ,
12011246 variants_block_builders : Vec < MatchLeafBuilder > ,
12021247 kind : MatchKind ,
12031248) -> LoweringResult < Vec < SealedBlockBuilder > > {
@@ -1220,7 +1265,7 @@ fn group_match_arms(
12201265 return match lowering_inner_pattern_result {
12211266 Ok ( _) => {
12221267 // Lower the arm expression.
1223- match ( arm. expr , kind) {
1268+ match ( arm. expr ( ) , kind) {
12241269 ( Some ( expr) , MatchKind :: IfLet | MatchKind :: Match ) => {
12251270 lower_tail_expr ( ctx, subscope, expr)
12261271 }
@@ -1266,8 +1311,8 @@ fn group_match_arms(
12661311 . map ( |( lowering_inner_pattern_result, subscope) | {
12671312 // Use the first pattern for the location of the for variable assignment block.
12681313 let location = arm
1269- . patterns
1270- . first ( )
1314+ . patterns ( )
1315+ . and_then ( |ps| ps . first ( ) )
12711316 . map ( |pattern| {
12721317 ctx. get_location (
12731318 ctx. function_body . arenas . patterns [ * pattern] . stable_ptr ( ) . untyped ( ) ,
@@ -1292,7 +1337,7 @@ fn group_match_arms(
12921337 sealed_blocks,
12931338 location,
12941339 ) ?;
1295- match ( arm. expr , kind) {
1340+ match ( arm. expr ( ) , kind) {
12961341 ( Some ( expr) , MatchKind :: IfLet | MatchKind :: Match ) => {
12971342 lower_tail_expr ( ctx, outer_subscope, expr)
12981343 }
0 commit comments