@@ -24,28 +24,67 @@ use super::{DecisionTree, PathInstruction, ScrutineePath};
2424/// variables that may be reassigned in arm bodies.
2525pub ( crate ) struct EmitContext {
2626 /// The root scrutinee variable.
27- pub root_scrutinee : ArcVarId ,
27+ pub ( crate ) root_scrutinee : ArcVarId ,
2828 /// Pool type of the root scrutinee (for type-aware path resolution).
29- pub root_scrutinee_ty : Idx ,
29+ pub ( crate ) root_scrutinee_ty : Idx ,
3030 /// The merge block all arms jump to after executing their body.
31- pub merge_block : crate :: ir:: ArcBlockId ,
31+ pub ( crate ) merge_block : crate :: ir:: ArcBlockId ,
3232 /// The body expression for each arm (indexed by `arm_index`).
33- pub arm_bodies : Vec < ori_ir:: canon:: CanId > ,
33+ pub ( crate ) arm_bodies : Vec < ori_ir:: canon:: CanId > ,
3434 /// Span of the match expression.
35- pub span : Span ,
35+ pub ( crate ) span : Span ,
3636 /// Scope snapshot from before the match. Each arm resets to this
3737 /// before lowering its body, ensuring arm-to-arm scope isolation.
38- pub pre_scope : ArcScope ,
38+ pub ( crate ) pre_scope : ArcScope ,
3939 /// Mutable variable names to pass as merge block params (in order).
4040 /// These serve as SSA phi inputs at the match convergence point.
41- pub mutable_var_names : Vec < Name > ,
41+ pub ( crate ) mutable_var_names : Vec < Name > ,
4242 /// Variant context stack for type-aware path resolution.
4343 ///
4444 /// Each entry is `(enum_type, variant_index)` pushed by `emit_tag_switch`
4545 /// when entering a specific variant's case block. `resolve_path` uses this
4646 /// to look up the actual field type for `TagPayload` steps, which is
4747 /// critical for recursive enums where fields may be RC-boxed pointers.
48- pub variant_stack : Vec < ( Idx , u32 ) > ,
48+ variant_stack : Vec < ( Idx , u32 ) > ,
49+ }
50+
51+ impl EmitContext {
52+ /// Create a new emit context for decision tree emission.
53+ pub ( crate ) fn new (
54+ root_scrutinee : ArcVarId ,
55+ root_scrutinee_ty : Idx ,
56+ merge_block : crate :: ir:: ArcBlockId ,
57+ arm_bodies : Vec < ori_ir:: canon:: CanId > ,
58+ span : Span ,
59+ pre_scope : ArcScope ,
60+ mutable_var_names : Vec < Name > ,
61+ ) -> Self {
62+ Self {
63+ root_scrutinee,
64+ root_scrutinee_ty,
65+ merge_block,
66+ arm_bodies,
67+ span,
68+ pre_scope,
69+ mutable_var_names,
70+ variant_stack : Vec :: new ( ) ,
71+ }
72+ }
73+
74+ /// Push a variant onto the context stack (entering a variant's case block).
75+ pub ( crate ) fn push_variant ( & mut self , enum_type : Idx , variant_index : u32 ) {
76+ self . variant_stack . push ( ( enum_type, variant_index) ) ;
77+ }
78+
79+ /// Pop the most recent variant from the context stack (leaving a variant's case block).
80+ pub ( crate ) fn pop_variant ( & mut self ) {
81+ self . variant_stack . pop ( ) ;
82+ }
83+
84+ /// Get the current variant stack (for path resolution).
85+ pub ( crate ) fn variant_stack ( & self ) -> & [ ( Idx , u32 ) ] {
86+ & self . variant_stack
87+ }
4988}
5089
5190/// Emit a decision tree as ARC IR basic blocks.
@@ -266,10 +305,35 @@ pub(super) fn resolve_path(
266305 } ;
267306 ( * idx, elem_ty)
268307 }
269- // List rest (slicing) not yet supported in LLVM backend.
270- // Emit element 0 as a placeholder — will be replaced when
271- // list pattern codegen is fully implemented.
272- PathInstruction :: ListRest ( _) => ( 0 , Idx :: UNIT ) ,
308+ PathInstruction :: ListRest ( start_idx) => {
309+ // Emit a runtime call to slice the list from `start_idx` onward.
310+ // The ARC IR uses Apply("ori_list_slice_drop", [list, start]),
311+ // and the LLVM emitter expands this into the full sret call
312+ // (extracting data/len/cap, computing elem_size, calling runtime).
313+ let resolved = pool. resolve_fully ( current_ty) ;
314+ let list_ty = current_ty;
315+ let elem_ty = if pool. tag ( resolved) == Tag :: List {
316+ pool. list_elem ( resolved)
317+ } else {
318+ Idx :: UNIT
319+ } ;
320+ let _ = elem_ty; // Used by LLVM emitter via the list type
321+ let start_const = lowerer. builder . emit_let (
322+ Idx :: INT ,
323+ crate :: ir:: ArcValue :: Literal ( crate :: ir:: LitValue :: Int ( i64:: from ( * start_idx) ) ) ,
324+ Some ( span) ,
325+ ) ;
326+ let slice_fn = lowerer. interner . intern ( "ori_list_slice_drop" ) ;
327+ let result = lowerer. builder . emit_apply (
328+ list_ty,
329+ slice_fn,
330+ vec ! [ current, start_const] ,
331+ Some ( span) ,
332+ ) ;
333+ current = result;
334+ current_ty = list_ty;
335+ continue ;
336+ }
273337 } ;
274338 current = lowerer
275339 . builder
@@ -332,7 +396,7 @@ fn bind_pattern_variables(
332396 ctx. root_scrutinee_ty ,
333397 path,
334398 ctx. span ,
335- & ctx. variant_stack ,
399+ ctx. variant_stack ( ) ,
336400 ) ;
337401 lowerer. scope . bind ( * name, var) ;
338402 }
0 commit comments