44//! - Sequences: `{a b c}` - siblings matched in order
55//! - Alternations: `[a b c]` - first matching branch wins
66
7+ use std:: collections:: BTreeMap ;
8+
9+ use plotnik_core:: Symbol ;
10+
11+ use crate :: analyze:: type_check:: { TypeId , TypeShape } ;
712use crate :: bytecode:: ir:: { EffectIR , Instruction , Label , MatchIR , MemberRef } ;
813use crate :: bytecode:: { EffectOpcode , Nav } ;
914use crate :: parser:: ast:: { self , Expr , SeqItem } ;
10- use crate :: analyze:: type_check:: TypeShape ;
1115
1216use super :: capture:: CaptureEffects ;
1317use super :: navigation:: { compute_nav_modes, is_down_nav, is_skippable_quantifier, repeat_nav_for} ;
@@ -190,11 +194,15 @@ impl Compiler<'_> {
190194 let alt_type_shape = alt_type_id. and_then ( |id| self . type_ctx . get_type ( id) ) ;
191195 let is_enum = alt_type_shape. is_some_and ( |shape| matches ! ( shape, TypeShape :: Enum ( _) ) ) ;
192196
193- // For tagged alternations: get variant types for scope pushing
194- // For untagged alternations: get merged struct fields for Null injection
195- let variant_types: Vec < _ > = match alt_type_shape {
196- Some ( TypeShape :: Enum ( variants) ) => variants. values ( ) . copied ( ) . collect ( ) ,
197- _ => vec ! [ ] ,
197+ // For tagged alternations: build map from label Symbol to (member index, payload TypeId)
198+ // This ensures we use the correct BTreeMap order indices, not AST iteration order
199+ let variant_info: BTreeMap < Symbol , ( u16 , TypeId ) > = match alt_type_shape {
200+ Some ( TypeShape :: Enum ( variants) ) => variants
201+ . iter ( )
202+ . enumerate ( )
203+ . map ( |( idx, ( & sym, & type_id) ) | ( sym, ( idx as u16 , type_id) ) )
204+ . collect ( ) ,
205+ _ => BTreeMap :: new ( ) ,
198206 } ;
199207 let merged_fields = alt_type_id. and_then ( |id| self . type_ctx . get_struct_fields ( id) ) ;
200208
@@ -206,12 +214,21 @@ impl Compiler<'_> {
206214
207215 // Compile each branch, collecting entry labels
208216 let mut successors = Vec :: new ( ) ;
209- for ( variant_idx , branch) in branches. iter ( ) . enumerate ( ) {
217+ for branch in branches. iter ( ) {
210218 let Some ( body) = branch. body ( ) else {
211219 continue ;
212220 } ;
213221
214222 if is_enum {
223+ // Look up variant info by branch label (using BTreeMap order, not AST order)
224+ let label = branch. label ( ) . expect ( "tagged branch must have label" ) ;
225+ let label_text = label. text ( ) ;
226+ let ( variant_idx, payload_type_id) = variant_info
227+ . iter ( )
228+ . find ( |( sym, _) | self . interner . resolve ( * * sym) == label_text)
229+ . map ( |( _, info) | * info)
230+ . expect ( "variant must exist for labeled branch" ) ;
231+
215232 // Tagged branch: E(variant_ref) → body → EndE → exit
216233 // Outer capture effects go on EndEnum, not on the branch body
217234 let mut end_effects = vec ! [ EffectIR :: simple( EffectOpcode :: EndEnum , 0 ) ] ;
@@ -230,19 +247,15 @@ impl Compiler<'_> {
230247 } ) ) ;
231248
232249 // Compile body with variant's scope (no outer capture - it's on EndEnum)
233- let body_entry = if let Some ( & payload_type_id) = variant_types. get ( variant_idx) {
234- self . with_scope ( payload_type_id, |this| {
235- this. compile_expr_inner ( & body, ende_step, branch_nav, CaptureEffects :: default ( ) )
236- } )
237- } else {
238- self . compile_expr_inner ( & body, ende_step, branch_nav, CaptureEffects :: default ( ) )
239- } ;
250+ let body_entry = self . with_scope ( payload_type_id, |this| {
251+ this. compile_expr_inner ( & body, ende_step, branch_nav, CaptureEffects :: default ( ) )
252+ } ) ;
240253
241254 // Create deferred member reference for the enum variant
242255 let e_effect = if let Some ( type_id) = alt_type_id {
243- EffectIR :: with_member ( EffectOpcode :: Enum , MemberRef :: deferred ( type_id, variant_idx as u16 ) )
256+ EffectIR :: with_member ( EffectOpcode :: Enum , MemberRef :: deferred ( type_id, variant_idx) )
244257 } else {
245- EffectIR :: simple ( EffectOpcode :: Enum , variant_idx)
258+ EffectIR :: simple ( EffectOpcode :: Enum , variant_idx as usize )
246259 } ;
247260
248261 let e_step = self . fresh_label ( ) ;
0 commit comments