diff --git a/crates/rue-air/src/inst.rs b/crates/rue-air/src/inst.rs index c5980c146..8781a0a8f 100644 --- a/crates/rue-air/src/inst.rs +++ b/crates/rue-air/src/inst.rs @@ -32,6 +32,29 @@ pub enum AirArgMode { Borrow, } +impl AirArgMode { + /// Convert to u32 for storage in extra array. + #[inline] + pub fn as_u32(self) -> u32 { + match self { + AirArgMode::Normal => 0, + AirArgMode::Inout => 1, + AirArgMode::Borrow => 2, + } + } + + /// Convert from u32 stored in extra array. + #[inline] + pub fn from_u32(v: u32) -> Self { + match v { + 0 => AirArgMode::Normal, + 1 => AirArgMode::Inout, + 2 => AirArgMode::Borrow, + _ => panic!("invalid AirArgMode value: {}", v), + } + } +} + /// An argument in a function call (AIR level). #[derive(Debug, Clone)] pub struct AirCallArg { @@ -82,6 +105,98 @@ pub enum AirPattern { }, } +/// Pattern type tags for extra array encoding. +const PATTERN_WILDCARD: u32 = 0; +const PATTERN_INT: u32 = 1; +const PATTERN_BOOL: u32 = 2; +const PATTERN_ENUM_VARIANT: u32 = 3; + +impl AirPattern { + /// Encode this pattern to the extra array, returning the number of u32s written. + /// Format: + /// - Wildcard: [tag, body_ref] = 2 words + /// - Int: [tag, body_ref, lo, hi] = 4 words (i64 as two u32s) + /// - Bool: [tag, body_ref, value] = 3 words + /// - EnumVariant: [tag, body_ref, enum_id, variant_index] = 4 words + pub fn encode(&self, body: AirRef, out: &mut Vec) { + match self { + AirPattern::Wildcard => { + out.push(PATTERN_WILDCARD); + out.push(body.as_u32()); + } + AirPattern::Int(n) => { + out.push(PATTERN_INT); + out.push(body.as_u32()); + // Encode i64 as two u32s (low, high) + out.push(*n as u32); + out.push((*n >> 32) as u32); + } + AirPattern::Bool(b) => { + out.push(PATTERN_BOOL); + out.push(body.as_u32()); + out.push(if *b { 1 } else { 0 }); + } + AirPattern::EnumVariant { + enum_id, + variant_index, + } => { + out.push(PATTERN_ENUM_VARIANT); + out.push(body.as_u32()); + out.push(enum_id.0); + out.push(*variant_index); + } + } + } +} + +/// Iterator for reading match arms from the extra array. +pub struct MatchArmIterator<'a> { + data: &'a [u32], + remaining: usize, +} + +impl Iterator for MatchArmIterator<'_> { + type Item = (AirPattern, AirRef); + + fn next(&mut self) -> Option { + if self.remaining == 0 { + return None; + } + self.remaining -= 1; + + let tag = self.data[0]; + let body = AirRef::from_raw(self.data[1]); + + let (pattern, advance) = match tag { + PATTERN_WILDCARD => (AirPattern::Wildcard, 2), + PATTERN_INT => { + let lo = self.data[2] as i64; + let hi = (self.data[3] as i64) << 32; + (AirPattern::Int(lo | hi), 4) + } + PATTERN_BOOL => { + let b = self.data[2] != 0; + (AirPattern::Bool(b), 3) + } + PATTERN_ENUM_VARIANT => { + let enum_id = crate::types::EnumId(self.data[2]); + let variant_index = self.data[3]; + ( + AirPattern::EnumVariant { + enum_id, + variant_index, + }, + 4, + ) + } + _ => panic!("invalid pattern tag: {}", tag), + }; + + self.data = &self.data[advance..]; + Some((pattern, body)) + } +} + /// A reference to an instruction in the AIR. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct AirRef(u32); @@ -102,6 +217,8 @@ impl AirRef { #[derive(Debug, Default)] pub struct Air { instructions: Vec, + /// Extra data for variable-length instruction payloads (args, elements, etc.) + extra: Vec, /// The return type of this function return_type: Type, } @@ -111,6 +228,7 @@ impl Air { pub fn new(return_type: Type) -> Self { Self { instructions: Vec::new(), + extra: Vec::new(), return_type, } } @@ -153,6 +271,89 @@ impl Air { .enumerate() .map(|(i, inst)| (AirRef::from_raw(i as u32), inst)) } + + /// Add extra data and return the start index. + pub fn add_extra(&mut self, data: &[u32]) -> u32 { + // Debug assertions for u32 overflow + debug_assert!( + self.extra.len() <= u32::MAX as usize, + "AIR extra data overflow: {} entries exceeds u32::MAX", + self.extra.len() + ); + debug_assert!( + self.extra.len().saturating_add(data.len()) <= u32::MAX as usize, + "AIR extra data would overflow: {} + {} exceeds u32::MAX", + self.extra.len(), + data.len() + ); + + let start = self.extra.len() as u32; + self.extra.extend_from_slice(data); + start + } + + /// Get extra data slice by start index and length. + #[inline] + pub fn get_extra(&self, start: u32, len: u32) -> &[u32] { + let start = start as usize; + let end = start + len as usize; + &self.extra[start..end] + } + + // Helper methods for reading structured data from extra array + + /// Get AirRefs from extra array (for blocks, array elements, intrinsic args, etc.). + #[inline] + pub fn get_air_refs(&self, start: u32, len: u32) -> impl Iterator + '_ { + self.get_extra(start, len) + .iter() + .map(|&v| AirRef::from_raw(v)) + } + + /// Get call arguments from extra array. + /// Each call arg is encoded as 2 u32s: (air_ref, mode). + #[inline] + pub fn get_call_args(&self, start: u32, len: u32) -> impl Iterator + '_ { + let data = self.get_extra(start, len * 2); + data.chunks_exact(2).map(|chunk| AirCallArg { + value: AirRef::from_raw(chunk[0]), + mode: AirArgMode::from_u32(chunk[1]), + }) + } + + /// Get match arms from extra array. + /// Each match arm is encoded based on pattern type plus the body AirRef. + #[inline] + pub fn get_match_arms( + &self, + start: u32, + len: u32, + ) -> impl Iterator + '_ { + MatchArmIterator { + data: &self.extra[start as usize..], + remaining: len as usize, + } + } + + /// Get struct init data from extra array. + /// Returns (field_refs_iterator, source_order_iterator). + #[inline] + pub fn get_struct_init( + &self, + fields_start: u32, + fields_len: u32, + source_order_start: u32, + ) -> ( + impl Iterator + '_, + impl Iterator + '_, + ) { + let fields = self.get_air_refs(fields_start, fields_len); + let source_order = self + .get_extra(source_order_start, fields_len) + .iter() + .map(|&v| v as usize); + (fields, source_order) + } } /// A single AIR instruction. @@ -248,8 +449,10 @@ pub enum AirInstData { Match { /// The value being matched (scrutinee) scrutinee: AirRef, - /// Match arms: [(pattern, body), ...] - arms: Vec<(AirPattern, AirRef)>, + /// Start index into extra array for match arms + arms_start: u32, + /// Number of match arms + arms_len: u32, }, /// Break: exits the innermost loop @@ -297,16 +500,20 @@ pub enum AirInstData { Call { /// Function name (interned symbol) name: Symbol, - /// Arguments with inout flags - args: Vec, + /// Start index into extra array for arguments + args_start: u32, + /// Number of arguments + args_len: u32, }, /// Intrinsic call (e.g., @dbg) Intrinsic { /// Intrinsic name (without @) name: String, - /// Argument AIR refs - args: Vec, + /// Start index into extra array for arguments + args_start: u32, + /// Number of arguments + args_len: u32, }, /// Reference to a function parameter @@ -319,8 +526,10 @@ pub enum AirInstData { /// Used to group side-effect statements with their result value, /// enabling demand-driven lowering for short-circuit evaluation. Block { - /// Side-effect statements to execute in order - statements: Vec, + /// Start index into extra array for statement refs + stmts_start: u32, + /// Number of statements + stmts_len: u32, /// The block's resulting value value: AirRef, }, @@ -330,12 +539,13 @@ pub enum AirInstData { StructInit { /// The struct type being created struct_id: StructId, - /// Field values in declaration order (for storage layout) - fields: Vec, - /// Evaluation order: indices into `fields` in source order - /// e.g., for `Point { y: 10, x: 20 }` with declaration order [x, y], - /// source_order would be [1, 0] meaning evaluate fields[1] (y) first, then fields[0] (x) - source_order: Vec, + /// Start index into extra array for field refs (in declaration order) + fields_start: u32, + /// Number of fields + fields_len: u32, + /// Start index into extra array for source order indices + /// Each entry is an index into fields, specifying evaluation order + source_order_start: u32, }, /// Load a field from a struct value @@ -379,8 +589,10 @@ pub enum AirInstData { ArrayInit { /// The array type array_type_id: ArrayTypeId, - /// Element values - elements: Vec, + /// Start index into extra array for element refs + elems_start: u32, + /// Number of elements + elems_len: u32, }, /// Load an element from an array @@ -516,9 +728,14 @@ impl fmt::Display for Air { } AirInstData::Loop { cond, body } => writeln!(f, "loop {}, {}", cond, body)?, AirInstData::InfiniteLoop { body } => writeln!(f, "infinite_loop {}", body)?, - AirInstData::Match { scrutinee, arms } => { + AirInstData::Match { + scrutinee, + arms_start, + arms_len, + } => { write!(f, "match {} {{ ", scrutinee)?; - for (i, (pat, body)) in arms.iter().enumerate() { + for (i, (pat, body)) in self.get_match_arms(*arms_start, *arms_len).enumerate() + { if i > 0 { write!(f, ", ")?; } @@ -550,9 +767,13 @@ impl fmt::Display for Air { writeln!(f, "ret")? } } - AirInstData::Call { name, args } => { + AirInstData::Call { + name, + args_start, + args_len, + } => { write!(f, "call @{}(", name.as_u32())?; - for (i, arg) in args.iter().enumerate() { + for (i, arg) in self.get_call_args(*args_start, *args_len).enumerate() { if i > 0 { write!(f, ", ")?; } @@ -560,9 +781,13 @@ impl fmt::Display for Air { } writeln!(f, ")")?; } - AirInstData::Intrinsic { name, args } => { + AirInstData::Intrinsic { + name, + args_start, + args_len, + } => { write!(f, "intrinsic @{}(", name)?; - for (i, arg) in args.iter().enumerate() { + for (i, arg) in self.get_air_refs(*args_start, *args_len).enumerate() { if i > 0 { write!(f, ", ")?; } @@ -571,9 +796,13 @@ impl fmt::Display for Air { writeln!(f, ")")?; } AirInstData::Param { index } => writeln!(f, "param {}", index)?, - AirInstData::Block { statements, value } => { + AirInstData::Block { + stmts_start, + stmts_len, + value, + } => { write!(f, "block [")?; - for (i, s) in statements.iter().enumerate() { + for (i, s) in self.get_air_refs(*stmts_start, *stmts_len).enumerate() { if i > 0 { write!(f, ", ")?; } @@ -583,18 +812,21 @@ impl fmt::Display for Air { } AirInstData::StructInit { struct_id, - fields, - source_order, + fields_start, + fields_len, + source_order_start, } => { write!(f, "struct_init #{} {{", struct_id.0)?; - for (i, field) in fields.iter().enumerate() { + let (fields, source_order) = + self.get_struct_init(*fields_start, *fields_len, *source_order_start); + for (i, field) in fields.enumerate() { if i > 0 { write!(f, ", ")?; } write!(f, "{}", field)?; } write!(f, "}} eval_order=[")?; - for (i, &idx) in source_order.iter().enumerate() { + for (i, idx) in source_order.enumerate() { if i > 0 { write!(f, ", ")?; } @@ -636,10 +868,11 @@ impl fmt::Display for Air { } AirInstData::ArrayInit { array_type_id, - elements, + elems_start, + elems_len, } => { write!(f, "array_init @{} [", array_type_id.0)?; - for (i, elem) in elements.iter().enumerate() { + for (i, elem) in self.get_air_refs(*elems_start, *elems_len).enumerate() { if i > 0 { write!(f, ", ")?; } diff --git a/crates/rue-air/src/sema.rs b/crates/rue-air/src/sema.rs index 07a2c9383..9a163df2d 100644 --- a/crates/rue-air/src/sema.rs +++ b/crates/rue-air/src/sema.rs @@ -2140,10 +2140,20 @@ impl<'a> Sema<'a> { } let final_type = result_type.unwrap_or(Type::Unit); + + // Encode match arms into extra array + let arms_len = air_arms.len() as u32; + let mut extra_data = Vec::new(); + for (pattern, body) in &air_arms { + pattern.encode(*body, &mut extra_data); + } + let arms_start = air.add_extra(&extra_data); + let air_ref = air.add_inst(AirInst { data: AirInstData::Match { scrutinee: scrutinee_result.air_ref, - arms: air_arms, + arms_start, + arms_len, }, ty: final_type, span: inst.span, @@ -2213,9 +2223,11 @@ impl<'a> Sema<'a> { }); // Return a block containing both StorageLive and Alloc + let stmts_start = air.add_extra(&[storage_live_ref.as_u32()]); let block_ref = air.add_inst(AirInst { data: AirInstData::Block { - statements: vec![storage_live_ref], + stmts_start, + stmts_len: 1, value: alloc_ref, }, ty: Type::Unit, @@ -2564,9 +2576,14 @@ impl<'a> Sema<'a> { } else { // Block type comes from HM inference let ty = last.ty; + // Encode statements into extra array + let stmt_u32s: Vec = statements.iter().map(|r| r.as_u32()).collect(); + let stmts_start = air.add_extra(&stmt_u32s); + let stmts_len = statements.len() as u32; let air_ref = air.add_inst(AirInst { data: AirInstData::Block { - statements, + stmts_start, + stmts_len, value: last.air_ref, }, ty, @@ -2630,10 +2647,20 @@ impl<'a> Sema<'a> { // Analyze arguments (move checking happens in analyze_inst for VarRef) let air_args = self.analyze_call_args(air, args, ctx)?; + // Encode call args into extra array: each arg is (air_ref, mode) + let args_len = air_args.len() as u32; + let mut extra_data = Vec::with_capacity(air_args.len() * 2); + for arg in &air_args { + extra_data.push(arg.value.as_u32()); + extra_data.push(arg.mode.as_u32()); + } + let args_start = air.add_extra(&extra_data); + let air_ref = air.add_inst(AirInst { data: AirInstData::Call { name: *name, - args: air_args, + args_start, + args_len, }, ty: return_type, span: inst.span, @@ -2763,11 +2790,19 @@ impl<'a> Sema<'a> { .map(|opt| opt.expect("all fields should be initialized")) .collect(); + // Encode into extra array: first field refs, then source order + let fields_len = field_refs.len() as u32; + let field_u32s: Vec = field_refs.iter().map(|r| r.as_u32()).collect(); + let fields_start = air.add_extra(&field_u32s); + let source_order_u32s: Vec = source_order.iter().map(|&i| i as u32).collect(); + let source_order_start = air.add_extra(&source_order_u32s); + let air_ref = air.add_inst(AirInst { data: AirInstData::StructInit { struct_id, - fields: field_refs, - source_order, + fields_start, + fields_len, + source_order_start, }, ty: struct_type, span: inst.span, @@ -3110,10 +3145,13 @@ impl<'a> Sema<'a> { )); } + // Encode args into extra array + let args_start = air.add_extra(&[arg_result.air_ref.as_u32()]); let air_ref = air.add_inst(AirInst { data: AirInstData::Intrinsic { name: intrinsic_name, - args: vec![arg_result.air_ref], + args_start, + args_len: 1, }, ty: Type::Unit, span: inst.span, @@ -3295,11 +3333,17 @@ impl<'a> Sema<'a> { element_refs.push(elem_result.air_ref); } + // Encode elements into extra array + let elems_len = element_refs.len() as u32; + let elem_u32s: Vec = element_refs.iter().map(|r| r.as_u32()).collect(); + let elems_start = air.add_extra(&elem_u32s); + let array_type = Type::Array(array_type_id); let air_ref = air.add_inst(AirInst { data: AirInstData::ArrayInit { array_type_id, - elements: element_refs, + elems_start, + elems_len, }, ty: array_type, span: inst.span, @@ -3763,10 +3807,20 @@ impl<'a> Sema<'a> { let call_name = format!("{}.{}", struct_name_str, method_name_str); let call_name_sym = self.interner.intern(&call_name); + // Encode call args into extra array + let args_len = air_args.len() as u32; + let mut extra_data = Vec::with_capacity(air_args.len() * 2); + for arg in &air_args { + extra_data.push(arg.value.as_u32()); + extra_data.push(arg.mode.as_u32()); + } + let args_start = air.add_extra(&extra_data); + let air_ref = air.add_inst(AirInst { data: AirInstData::Call { name: call_name_sym, - args: air_args, + args_start, + args_len, }, ty: return_type, span: inst.span, @@ -3849,10 +3903,20 @@ impl<'a> Sema<'a> { let call_name = format!("{}::{}", type_name_str, function_name_str); let call_name_sym = self.interner.intern(&call_name); + // Encode call args into extra array + let args_len = air_args.len() as u32; + let mut extra_data = Vec::with_capacity(air_args.len() * 2); + for arg in &air_args { + extra_data.push(arg.value.as_u32()); + extra_data.push(arg.mode.as_u32()); + } + let args_start = air.add_extra(&extra_data); + let air_ref = air.add_inst(AirInst { data: AirInstData::Call { name: call_name_sym, - args: air_args, + args_start, + args_len, }, ty: return_type, span: inst.span, @@ -4338,10 +4402,13 @@ impl<'a> Sema<'a> { // Generate a call to String__new (runtime function) // We use double underscore because :: is not valid in C symbol names let call_name = self.interner.intern("String__new"); + // No args to encode + let args_start = air.add_extra(&[]); let air_ref = air.add_inst(AirInst { data: AirInstData::Call { name: call_name, - args: vec![], + args_start, + args_len: 0, }, ty: Type::String, span, @@ -4377,13 +4444,14 @@ impl<'a> Sema<'a> { // Generate a call to String__with_capacity (runtime function) let call_name = self.interner.intern("String__with_capacity"); + // Encode args into extra array + let args_start = + air.add_extra(&[cap_result.air_ref.as_u32(), AirArgMode::Normal.as_u32()]); let air_ref = air.add_inst(AirInst { data: AirInstData::Call { name: call_name, - args: vec![AirCallArg { - value: cap_result.air_ref, - mode: AirArgMode::Normal, - }], + args_start, + args_len: 1, }, ty: Type::String, span, @@ -4528,19 +4596,17 @@ impl<'a> Sema<'a> { // Call String__push_str(self, other) -> String let call_name = self.interner.intern("String__push_str"); + let args_start = air.add_extra(&[ + receiver.air_ref.as_u32(), + AirArgMode::Normal.as_u32(), + other_result.air_ref.as_u32(), + AirArgMode::Normal.as_u32(), + ]); let call_ref = air.add_inst(AirInst { data: AirInstData::Call { name: call_name, - args: vec![ - AirCallArg { - value: receiver.air_ref, - mode: AirArgMode::Normal, - }, - AirCallArg { - value: other_result.air_ref, - mode: AirArgMode::Normal, - }, - ], + args_start, + args_len: 2, }, ty: Type::String, span, @@ -4578,19 +4644,17 @@ impl<'a> Sema<'a> { // Call String__push(self, byte) -> String let call_name = self.interner.intern("String__push"); + let args_start = air.add_extra(&[ + receiver.air_ref.as_u32(), + AirArgMode::Normal.as_u32(), + byte_result.air_ref.as_u32(), + AirArgMode::Normal.as_u32(), + ]); let call_ref = air.add_inst(AirInst { data: AirInstData::Call { name: call_name, - args: vec![ - AirCallArg { - value: receiver.air_ref, - mode: AirArgMode::Normal, - }, - AirCallArg { - value: byte_result.air_ref, - mode: AirArgMode::Normal, - }, - ], + args_start, + args_len: 2, }, ty: Type::String, span, @@ -4614,13 +4678,13 @@ impl<'a> Sema<'a> { // Call String__clear(self) -> String let call_name = self.interner.intern("String__clear"); + let args_start = + air.add_extra(&[receiver.air_ref.as_u32(), AirArgMode::Normal.as_u32()]); let call_ref = air.add_inst(AirInst { data: AirInstData::Call { name: call_name, - args: vec![AirCallArg { - value: receiver.air_ref, - mode: AirArgMode::Normal, - }], + args_start, + args_len: 1, }, ty: Type::String, span, @@ -4658,19 +4722,17 @@ impl<'a> Sema<'a> { // Call String__reserve(self, additional) -> String let call_name = self.interner.intern("String__reserve"); + let args_start = air.add_extra(&[ + receiver.air_ref.as_u32(), + AirArgMode::Normal.as_u32(), + additional_result.air_ref.as_u32(), + AirArgMode::Normal.as_u32(), + ]); let call_ref = air.add_inst(AirInst { data: AirInstData::Call { name: call_name, - args: vec![ - AirCallArg { - value: receiver.air_ref, - mode: AirArgMode::Normal, - }, - AirCallArg { - value: additional_result.air_ref, - mode: AirArgMode::Normal, - }, - ], + args_start, + args_len: 2, }, ty: Type::String, span, @@ -4758,13 +4820,13 @@ impl<'a> Sema<'a> { // Using Normal mode instead of Borrow because String's 3 fields should be // passed directly, not by reference. let call_name = self.interner.intern("String__len"); + let args_start = + air.add_extra(&[receiver.air_ref.as_u32(), AirArgMode::Normal.as_u32()]); let air_ref = air.add_inst(AirInst { data: AirInstData::Call { name: call_name, - args: vec![AirCallArg { - value: receiver.air_ref, - mode: AirArgMode::Normal, - }], + args_start, + args_len: 1, }, ty: Type::U64, span, @@ -4788,13 +4850,13 @@ impl<'a> Sema<'a> { // Generate a call to String__capacity (runtime function) // Same pattern as len() - pass by value, don't consume. let call_name = self.interner.intern("String__capacity"); + let args_start = + air.add_extra(&[receiver.air_ref.as_u32(), AirArgMode::Normal.as_u32()]); let air_ref = air.add_inst(AirInst { data: AirInstData::Call { name: call_name, - args: vec![AirCallArg { - value: receiver.air_ref, - mode: AirArgMode::Normal, - }], + args_start, + args_len: 1, }, ty: Type::U64, span, @@ -4818,13 +4880,13 @@ impl<'a> Sema<'a> { // Generate a call to String__is_empty (runtime function) // Same pattern as len() - pass by value, don't consume. let call_name = self.interner.intern("String__is_empty"); + let args_start = + air.add_extra(&[receiver.air_ref.as_u32(), AirArgMode::Normal.as_u32()]); let air_ref = air.add_inst(AirInst { data: AirInstData::Call { name: call_name, - args: vec![AirCallArg { - value: receiver.air_ref, - mode: AirArgMode::Normal, - }], + args_start, + args_len: 1, }, ty: Type::Bool, span, @@ -4849,13 +4911,13 @@ impl<'a> Sema<'a> { // Takes the String (ptr, len, cap) and returns a new String (ptr, len, cap) // where the new ptr points to freshly allocated memory with copied content. let call_name = self.interner.intern("String__clone"); + let args_start = + air.add_extra(&[receiver.air_ref.as_u32(), AirArgMode::Normal.as_u32()]); let air_ref = air.add_inst(AirInst { data: AirInstData::Call { name: call_name, - args: vec![AirCallArg { - value: receiver.air_ref, - mode: AirArgMode::Normal, - }], + args_start, + args_len: 1, }, ty: Type::String, span, diff --git a/crates/rue-cfg/src/build.rs b/crates/rue-cfg/src/build.rs index 81de8aac5..4a2f0f537 100644 --- a/crates/rue-cfg/src/build.rs +++ b/crates/rue-cfg/src/build.rs @@ -630,9 +630,13 @@ impl<'a> CfgBuilder<'a> { } } - AirInstData::Call { name, args } => { + AirInstData::Call { + name, + args_start, + args_len, + } => { let mut arg_vals = Vec::new(); - for arg in args { + for arg in self.air.get_call_args(*args_start, *args_len) { let Some(value) = self.lower_value(arg.value) else { return Self::diverged(); }; @@ -656,10 +660,14 @@ impl<'a> CfgBuilder<'a> { } } - AirInstData::Intrinsic { name, args } => { + AirInstData::Intrinsic { + name, + args_start, + args_len, + } => { let mut arg_vals = Vec::new(); - for arg in args { - let Some(val) = self.lower_value(*arg) else { + for arg in self.air.get_air_refs(*args_start, *args_len) { + let Some(val) = self.lower_value(arg) else { return Self::diverged(); }; arg_vals.push(val); @@ -683,13 +691,20 @@ impl<'a> CfgBuilder<'a> { AirInstData::StructInit { struct_id, - fields, - source_order, + fields_start, + fields_len, + source_order_start, } => { // Evaluate field initializers in SOURCE ORDER (spec 4.0:8) // The source_order tells us which declaration-order index to evaluate at each step + let (fields, source_order) = + self.air + .get_struct_init(*fields_start, *fields_len, *source_order_start); + let fields: Vec = fields.collect(); + let source_order: Vec = source_order.collect(); + let mut lowered_fields: Vec> = vec![None; fields.len()]; - for &decl_idx in source_order { + for decl_idx in source_order { let Some(lowered) = self.lower_value(fields[decl_idx]) else { return Self::diverged(); }; @@ -793,7 +808,15 @@ impl<'a> CfgBuilder<'a> { } } - AirInstData::Block { statements, value } => { + AirInstData::Block { + stmts_start, + stmts_len, + value, + } => { + // Collect statements into a Vec for iteration (needed for checking remaining) + let statements: Vec = + self.air.get_air_refs(*stmts_start, *stmts_len).collect(); + // Check if this is a "wrapper block" that only contains StorageLive statements. // These are synthetic blocks created to pair StorageLive with Alloc, and they // should NOT create a new scope for drop elaboration. @@ -1170,12 +1193,20 @@ impl<'a> CfgBuilder<'a> { } } - AirInstData::Match { scrutinee, arms } => { + AirInstData::Match { + scrutinee, + arms_start, + arms_len, + } => { // Lower the scrutinee let Some(scrutinee_val) = self.lower_value(*scrutinee) else { return Self::diverged(); }; + // Collect arms into a Vec for iteration + let arms: Vec<(AirPattern, AirRef)> = + self.air.get_match_arms(*arms_start, *arms_len).collect(); + // Create blocks for each arm and a join block let arm_blocks: Vec<_> = arms.iter().map(|_| self.cfg.new_block()).collect(); let join_block = self.cfg.new_block(); @@ -1372,11 +1403,12 @@ impl<'a> CfgBuilder<'a> { AirInstData::ArrayInit { array_type_id, - elements, + elems_start, + elems_len, } => { let mut element_vals = Vec::new(); - for elem in elements { - let Some(val) = self.lower_value(*elem) else { + for elem in self.air.get_air_refs(*elems_start, *elems_len) { + let Some(val) = self.lower_value(elem) else { return Self::diverged(); }; element_vals.push(val); diff --git a/crates/rue-compiler/src/drop_glue.rs b/crates/rue-compiler/src/drop_glue.rs index b5500b06a..e0683e4ed 100644 --- a/crates/rue-compiler/src/drop_glue.rs +++ b/crates/rue-compiler/src/drop_glue.rs @@ -217,9 +217,14 @@ fn create_drop_glue_function( let return_value = if drop_statements.is_empty() { unit_const } else { + // Encode statements into extra array + let stmt_u32s: Vec = drop_statements.iter().map(|r| r.as_u32()).collect(); + let stmts_start = air.add_extra(&stmt_u32s); + let stmts_len = drop_statements.len() as u32; air.add_inst(AirInst { data: AirInstData::Block { - statements: drop_statements, + stmts_start, + stmts_len, value: unit_const, }, ty: Type::Unit,