Skip to content

Instantly share code, notes, and snippets.

@re-masashi
Created October 21, 2025 21:50
Show Gist options
  • Select an option

  • Save re-masashi/836d7dc66bd4b9069633271cfcf14255 to your computer and use it in GitHub Desktop.

Select an option

Save re-masashi/836d7dc66bd4b9069633271cfcf14255 to your computer and use it in GitHub Desktop.
use std::collections::HashMap;
use std::ops::Range;
use crate::ast::{BinOp, UnOp, AssignOp, Visibility, Kind};
use crate::typechecker::EffectSet;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MemorySlotId(pub usize);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct AllocationId(pub usize);
#[derive(Debug, Clone)]
pub enum MemoryKind {
Stack, // Stack allocated (no GC)
Heap, // Heap allocated (GC'd)
Static, // Static lifetime
Escaping, // Escapes current scope (needs allocation)
Temporary, // Temporary value (may be optimized away)
}
// Unique IDs for IR elements
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct FunctionId(pub usize);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct StructId(pub usize);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct EnumId(pub usize);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct EffectId(pub usize);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct VariantId(pub usize);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct FieldId(pub usize);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct BasicBlockId(pub usize);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ValueId(pub usize);
// Target information for cross-platform compilation
#[derive(Debug, Clone)]
pub struct TargetInfo {
pub pointer_size: usize, // 4 (32-bit) or 8 (64-bit)
pub int_size: usize, // Target int size
pub float_size: usize, // Target float size
pub bool_size: usize, // Usually 1
pub alignment_rules: AlignmentRules,
}
#[derive(Debug, Clone)]
pub enum AlignmentRules {
Packed, // No padding (smaller but slower)
Natural, // Align to size (fast but bigger)
SystemV, // System V ABI
MsvcABI, // MSVC ABI
}
impl TargetInfo {
pub fn vm_target() -> Self {
Self {
pointer_size: 8,
int_size: 8,
float_size: 8,
bool_size: 1,
alignment_rules: AlignmentRules::Natural, // Performance!
}
}
// Host target for JIT
pub fn host_target() -> Self {
Self {
pointer_size: std::mem::size_of::<*const ()>(),
int_size: std::mem::size_of::<i64>(),
float_size: std::mem::size_of::<f64>(),
bool_size: std::mem::size_of::<bool>(),
alignment_rules: AlignmentRules::Natural,
}
}
// For AOT backend
pub fn from_triple(triple: &str) -> Self {
// use defaults based on triplet
todo!("Implement LLVM target info")
}
}
impl TargetInfo {
pub fn size_of(&self, type_: &IRType, module: &IRModule) -> Option<usize> {
match type_ {
IRType::Bool => Some(self.bool_size),
IRType::Int => Some(self.int_size),
IRType::Float => Some(self.float_size),
IRType::Unit => Some(0),
IRType::String => Some(self.pointer_size),
IRType::Never => None,
IRType::Pointer(_) => Some(self.pointer_size),
IRType::Function { .. } => Some(self.pointer_size),
IRType::StructRef(struct_id) => {
let idx = *module.struct_map.get(struct_id)?;
Some(module.structs.get(idx)?.memory_layout.size)
},
IRType::EnumRef(enum_id) => {
let idx = *module.enum_map.get(enum_id)?;
Some(module.enums.get(idx)?.memory_layout.size)
},
IRType::Tuple(types) => {
self.compute_tuple_layout(types, module).map(|layout| layout.size)
},
IRType::Variable(_, _) => None,
IRType::Union(_) => None,
IRType::Named(_, _) => None,
IRType::Error => None,
}
}
pub fn align_of(&self, type_: &IRType, module: &IRModule) -> Option<usize> {
match type_ {
IRType::Bool => Some(self.bool_size),
IRType::Int => Some(self.int_size),
IRType::Float => Some(self.float_size),
IRType::Unit => Some(1),
IRType::String => Some(self.pointer_size),
IRType::Never => None,
IRType::Pointer(_) => Some(self.pointer_size),
IRType::Function { .. } => Some(self.pointer_size),
IRType::StructRef(struct_id) => {
let idx = *module.struct_map.get(struct_id)?;
Some(module.structs.get(idx)?.memory_layout.alignment)
},
IRType::EnumRef(enum_id) => {
let idx = *module.enum_map.get(enum_id)?;
Some(module.enums.get(idx)?.memory_layout.alignment)
},
IRType::Tuple(types) => {
// Max alignment of all fields
types.iter()
.filter_map(|t| self.align_of(&t.type_, module))
.max()
},
IRType::Variable(_, _) => None,
IRType::Union(_) => None,
IRType::Named(_, _) => None,
IRType::Error => None,
}
}
// Compute tuple layout with padding (for performance)
fn compute_tuple_layout(&self, types: &[IRTypeWithMemory], module: &IRModule) -> Option<TupleLayout> {
match self.alignment_rules {
AlignmentRules::Packed => {
// No padding - just sum sizes
let size = types.iter()
.filter_map(|t| self.size_of(&t.type_, module))
.sum();
Some(TupleLayout { size, alignment: 1, field_offsets: vec![] })
},
AlignmentRules::Natural | AlignmentRules::SystemV | AlignmentRules::MsvcABI => {
// With padding for alignment (PERF!)
let mut offset = 0;
let mut max_align = 1;
let mut field_offsets = Vec::new();
for type_with_mem in types {
let size = self.size_of(&type_with_mem.type_, module)?;
let align = self.align_of(&type_with_mem.type_, module)?;
// Align current offset to this field's alignment
offset = (offset + align - 1) & !(align - 1);
field_offsets.push(offset);
offset += size;
max_align = max_align.max(align);
}
// Align total size to max alignment (tail padding)
offset = (offset + max_align - 1) & !(max_align - 1);
Some(TupleLayout {
size: offset,
alignment: max_align,
field_offsets,
})
},
}
}
// Compute struct/enum layout
pub fn compute_aggregate_layout(
&self,
fields: &[(FieldId, &IRType)],
module: &IRModule,
) -> Option<MemoryLayout> {
let mut offset = 0;
let mut max_align = 1;
let mut field_offsets = Vec::new();
let mut padding_bytes = Vec::new();
for (field_id, field_type) in fields {
let size = self.size_of(field_type, module)?;
let align = self.align_of(field_type, module)?;
// Check if padding needed
let aligned_offset = (offset + align - 1) & !(align - 1);
if aligned_offset > offset {
padding_bytes.push(PaddingInfo {
offset,
size: aligned_offset - offset,
reason: PaddingReason::FieldAlignment,
});
}
offset = aligned_offset;
field_offsets.push((*field_id, offset));
offset += size;
max_align = max_align.max(align);
}
// Tail padding
let final_size = (offset + max_align - 1) & !(max_align - 1);
if final_size > offset {
padding_bytes.push(PaddingInfo {
offset,
size: final_size - offset,
reason: PaddingReason::TailPadding,
});
}
Some(MemoryLayout {
size: final_size,
alignment: max_align,
field_offsets,
discriminant_offset: None,
discriminant_size: None,
discriminant_encoding: None,
padding_bytes,
})
}
}
struct TupleLayout {
size: usize,
alignment: usize,
field_offsets: Vec<usize>,
}
#[derive(Debug)]
pub struct PaddingInfo {
pub offset: usize, // Where padding starts
pub size: usize, // How many padding bytes
pub reason: PaddingReason,
}
#[derive(Debug)]
pub enum PaddingReason {
FieldAlignment, // Between fields for alignment
TailPadding, // At end for struct alignment
}
// Main IR module
#[derive(Debug)]
pub struct IRModule {
pub functions: Vec<IRFunction>,
pub structs: Vec<IRStruct>,
pub enums: Vec<IREnum>,
pub effects: Vec<IREffect>,
// Maps for quick lookups by ID
pub function_map: HashMap<FunctionId, usize>,
pub struct_map: HashMap<StructId, usize>,
pub enum_map: HashMap<EnumId, usize>,
pub effect_map: HashMap<EffectId, usize>,
// ADD THIS
pub target: TargetInfo, // Target architecture info
}
impl IRModule {
pub fn new(target: TargetInfo) -> Self {
Self {
functions: Vec::new(),
structs: Vec::new(),
enums: Vec::new(),
effects: Vec::new(),
function_map: HashMap::new(),
struct_map: HashMap::new(),
enum_map: HashMap::new(),
effect_map: HashMap::new(),
target,
}
}
pub fn size_of(&self, type_: &IRType) -> Option<usize> {
self.target.size_of(type_, self)
}
pub fn align_of(&self, type_: &IRType) -> Option<usize> {
self.target.align_of(type_, self)
}
}
// IR Type system - includes debug span and memory information
#[derive(Debug, Clone)]
pub struct IRTypeWithMemory {
pub type_: IRType,
pub span: Range<usize>,
pub file: String,
pub memory_kind: MemoryKind,
pub allocation_id: Option<AllocationId>, // For tracking allocations
}
#[derive(Debug, Clone)]
pub enum IRType {
// Primitives (typically stack allocated)
Bool,
Int,
Float,
String,
Unit,
Never,
// Named types
Named(String, Vec<IRTypeWithMemory>), // Generic named types
// Function type with effects
Function {
params: Vec<IRTypeWithMemory>,
return_type: Box<IRTypeWithMemory>,
effects: EffectSet,
},
// Tuple type
Tuple(Vec<IRTypeWithMemory>),
// Union type
Union(Vec<IRTypeWithMemory>),
// Struct and Enum references
StructRef(StructId),
EnumRef(EnumId),
// Pointer type for FFI
Pointer(Box<IRTypeWithMemory>),
// Type variable (for generics)
Variable(usize, Kind),
// Error type
Error,
}
// Instruction metadata for memory tracking
#[derive(Debug, Clone)]
pub struct InstructionMetadata {
pub memory_slot: Option<MemorySlotId>,
pub allocation_site: Option<AllocationId>,
}
// IR Value - represents SSA values (separate from memory locations)
#[derive(Debug, Clone)]
pub enum IRValue {
// Immediate values (stack allocated)
Int(i64),
Float(f64),
Bool(bool),
String(String),
// SSA values (each ValueId is defined exactly once)
SSA(ValueId),
// Function references
FunctionRef(FunctionId),
// Constant expressions
Constant(Constant),
// Memory addresses
MemoryAddress(MemorySlotId),
// Error value
Error,
}
#[derive(Debug, Clone)]
pub enum Constant {
// Simple constants (stack allocated)
Int(i64),
Float(f64),
Bool(bool),
String(String),
// Complex constants with memory information
Array(Vec<IRValue>),
Tuple(Vec<IRValue>),
// Error
Error,
}
// Basic Block - represents a sequence of instructions
#[derive(Debug)]
pub struct BasicBlock {
pub id: BasicBlockId,
pub phi_nodes: Vec<IRInstruction>, // Only PHI instructions (must be at start)
pub instructions: Vec<IRInstruction>, // All other instructions
pub terminator: Option<IRTerminator>,
}
impl BasicBlock {
pub fn new(id: BasicBlockId) -> Self {
Self {
id,
phi_nodes: Vec::new(),
instructions: Vec::new(),
terminator: None,
}
}
// Helper to add PHI (validates it's actually a PHI)
pub fn add_phi(&mut self, phi: IRInstruction) {
match phi {
IRInstruction::Phi { .. } => self.phi_nodes.push(phi),
_ => panic!("Only PHI instructions allowed in phi_nodes"),
}
}
// Helper to add regular instruction (validates it's NOT a PHI)
pub fn add_instruction(&mut self, inst: IRInstruction) {
match inst {
IRInstruction::Phi { .. } => panic!("PHI nodes must be added via add_phi()"),
_ => self.instructions.push(inst),
}
}
}
// SSA instruction - with memory management
#[derive(Debug)]
pub enum IRInstruction {
// Binary operations
BinOp {
result: ValueId,
metadata: InstructionMetadata,
left: IRValue,
op: BinOp,
right: IRValue,
span: Range<usize>,
file: String,
},
// Unary operations
UnOp {
result: ValueId,
metadata: InstructionMetadata,
op: UnOp,
operand: IRValue,
span: Range<usize>,
file: String,
},
// Assignment operations
Assign {
result: ValueId,
metadata: InstructionMetadata,
l_val: IRValue,
r_val: IRValue,
op: AssignOp,
span: Range<usize>,
file: String,
},
// Variable binding
Let {
result: ValueId,
metadata: InstructionMetadata,
var: String,
value: IRValue,
var_type: IRTypeWithMemory,
span: Range<usize>,
file: String,
},
// Array construction (heap allocation)
Array {
result: ValueId,
metadata: InstructionMetadata,
elements: Vec<IRValue>,
element_type: IRTypeWithMemory,
span: Range<usize>,
file: String,
},
// Tuple construction (stack or heap based on size/escape)
Tuple {
result: ValueId,
metadata: InstructionMetadata,
elements: Vec<IRValue>,
span: Range<usize>,
file: String,
},
// Map construction (heap allocation)
Map {
result: ValueId,
metadata: InstructionMetadata,
entries: Vec<(IRValue, IRValue)>,
key_type: IRTypeWithMemory,
value_type: IRTypeWithMemory,
span: Range<usize>,
file: String,
},
// Enum construction
EnumConstruct {
result: ValueId,
metadata: InstructionMetadata,
enum_id: EnumId,
variant_id: VariantId,
args: Vec<IRValue>,
span: Range<usize>,
file: String,
},
// Struct construction
StructConstruct {
result: ValueId,
metadata: InstructionMetadata,
struct_id: StructId,
fields: Vec<(FieldId, IRValue)>,
span: Range<usize>,
file: String,
},
// Effect operations
Perform {
result: ValueId,
metadata: InstructionMetadata,
effect_id: EffectId,
operation_id: usize, // Which operation of this effect
args: Vec<IRValue>,
span: Range<usize>,
file: String,
},
// Function call
Call {
result: ValueId,
metadata: InstructionMetadata,
function: IRValue,
args: Vec<IRValue>,
type_args: Vec<IRTypeWithMemory>,
span: Range<usize>,
file: String,
},
// Cast
Cast {
result: ValueId,
metadata: InstructionMetadata,
expr: IRValue,
target_type: IRTypeWithMemory,
span: Range<usize>,
file: String,
},
// Index access
Index {
result: ValueId,
metadata: InstructionMetadata,
target: IRValue,
index: IRValue,
element_type: IRTypeWithMemory,
span: Range<usize>,
file: String,
},
// Field access
FieldAccess {
result: ValueId,
metadata: InstructionMetadata,
target: IRValue,
field_id: FieldId,
field_type: IRTypeWithMemory,
span: Range<usize>,
file: String,
},
// Optional chain
OptionalChain {
result: ValueId,
metadata: InstructionMetadata,
target: IRValue,
field_id: FieldId,
field_type: IRTypeWithMemory,
span: Range<usize>,
file: String,
},
// Copy/Move operations
Copy {
result: ValueId,
metadata: InstructionMetadata,
source: IRValue,
span: Range<usize>,
file: String,
},
// PHI node for SSA form
Phi {
result: ValueId,
metadata: InstructionMetadata,
incoming: Vec<(IRValue, BasicBlockId)>, // (value, source_block)
span: Range<usize>,
file: String,
},
// Memory allocation
Allocate {
result: ValueId,
metadata: InstructionMetadata,
allocation_id: AllocationId,
size: AllocationSize,
memory_kind: MemoryKind,
type_info: IRTypeWithMemory,
span: Range<usize>,
file: String,
},
// Memory deallocation (for non-GC systems)
Deallocate {
memory_slot: MemorySlotId,
allocation_id: AllocationId,
span: Range<usize>,
file: String,
},
// Memory copy
MemoryCopy {
dest: IRValue, // Can be any address
src: IRValue, // Can be any address
size: AllocationSize, // Can be dynamic
span: Range<usize>,
file: String,
},
// Load from memory
Load {
result: ValueId,
address: IRValue,
address_kind: AddressKind,
type_info: IRTypeWithMemory,
span: Range<usize>,
file: String,
},
// Store to memory
Store {
address: IRValue,
address_kind: AddressKind,
value: IRValue,
type_info: IRTypeWithMemory,
span: Range<usize>,
file: String,
},
// Closure construction
ConstructClosure {
result: ValueId,
metadata: InstructionMetadata,
function_id: FunctionId,
captures: Vec<(ValueId, CaptureMode)>,
allocation_kind: MemoryKind,
span: Range<usize>,
file: String,
},
// GC safepoint
GCSafepoint {
live_values: Vec<ValueId>,
span: Range<usize>,
file: String,
},
// Declare GC root
DeclareRoot {
value: ValueId,
is_root: bool,
span: Range<usize>,
file: String,
},
// Trap instruction for runtime checks
Trap {
kind: TrapKind,
span: Range<usize>,
file: String,
},
// Select/Conditional move instruction
Select {
result: ValueId,
metadata: InstructionMetadata,
condition: IRValue,
if_true: IRValue,
if_false: IRValue,
span: Range<usize>,
file: String,
},
// Error instruction
Error {
span: Range<usize>,
file: String,
},
}
#[derive(Debug, Clone)]
pub enum TrapKind {
BoundsCheck { index: IRValue, length: IRValue },
NullCheck { value: IRValue },
DivideByZero { divisor: IRValue },
IntegerOverflow { operation: BinOp, left: IRValue, right: IRValue },
Unreachable,
}
// Address kind for load/store operations
#[derive(Debug, Clone)]
pub enum AddressKind {
StackSlot(MemorySlotId),
HeapObject(AllocationId),
StructField { base: ValueId, field: FieldId },
ArrayElement { base: ValueId, index: ValueId },
Computed, // Generic pointer arithmetic
}
// Capture mode for closures
#[derive(Debug, Clone)]
pub enum CaptureMode {
ByValue,
ByReference,
ByMutableReference,
}
// Allocation size (static or dynamic)
#[derive(Debug, Clone)]
pub enum AllocationSize {
Static(usize),
Dynamic(IRValue), // Runtime-computed size
}
// Basic block terminators
#[derive(Debug)]
pub enum IRTerminator {
// Return statement
Return {
value: Option<IRValue>,
span: Range<usize>,
file: String,
},
// Unconditional jump
Jump {
target: BasicBlockId,
span: Range<usize>,
file: String,
},
// Conditional branch
Branch {
condition: IRValue,
then_block: BasicBlockId,
else_block: BasicBlockId,
span: Range<usize>,
file: String,
},
// Switch/Match statement
Switch {
value: IRValue,
cases: Vec<(IRValue, BasicBlockId)>, // (pattern, target_block)
default: Option<BasicBlockId>, // None if exhaustive
is_exhaustive: bool, // New field
span: Range<usize>,
file: String,
},
// Loop back edge
Loop {
condition: IRValue,
body: BasicBlockId,
continue_block: BasicBlockId,
span: Range<usize>,
file: String,
},
// Unreachable
Unreachable {
span: Range<usize>,
file: String,
},
// Effect handler
Handle {
body: BasicBlockId,
handlers: Vec<EffectHandlerBlock>,
return_type: IRTypeWithMemory,
span: Range<usize>,
file: String,
},
// Error terminator
Error {
span: Range<usize>,
file: String,
},
}
#[derive(Debug)]
pub struct EffectHandlerBlock {
pub effect_id: EffectId,
pub params: Vec<(ValueId, MemorySlotId, IRTypeWithMemory)>, // (binding_id, memory_slot, type)
pub resume_param: ValueId,
pub resume_memory: MemorySlotId,
pub resume_type: IRTypeWithMemory,
pub continuation_type: ContinuationType, // New field
pub body: BasicBlockId,
pub span: Range<usize>,
pub file: String,
}
#[derive(Debug)]
pub struct ContinuationType {
pub input_type: IRTypeWithMemory, // What resume takes
pub output_type: IRTypeWithMemory, // What resume returns
pub captured_effects: EffectSet, // Effects in scope
}
// IR Function definition with memory information
#[derive(Debug)]
pub struct IRFunction {
pub id: FunctionId,
pub name: String,
pub vis: Visibility,
pub args: Vec<IRFunctionArg>,
pub return_type: IRTypeWithMemory,
pub effects: EffectSet,
pub function_type: IRTypeWithMemory,
pub basic_blocks: Vec<BasicBlock>,
pub cfg: ControlFlowGraph,
pub span: Range<usize>,
pub file: String,
pub body: Option<BasicBlockId>, // ID of the entry block
pub memory_usage: MemoryUsage, // Information about memory usage for analysis
pub optimization_hints: OptimizationHints, // Optimization hints
}
#[derive(Debug)]
pub struct ControlFlowGraph {
pub blocks: HashMap<BasicBlockId, BasicBlockInfo>,
pub entry: BasicBlockId,
pub exits: Vec<BasicBlockId>,
}
#[derive(Debug)]
pub struct BasicBlockInfo {
pub id: BasicBlockId,
pub predecessors: Vec<BasicBlockId>,
pub successors: Vec<BasicBlockId>,
pub dominators: Option<DominatorInfo>,
}
#[derive(Debug)]
pub struct DominatorInfo {
pub immediate_dominator: Option<BasicBlockId>,
pub dominated_blocks: Vec<BasicBlockId>,
pub dominance_frontier: Vec<BasicBlockId>,
}
#[derive(Debug)]
pub struct MemoryUsage {
pub max_stack_size: usize,
pub heap_allocations: Vec<AllocationId>,
pub escape_analysis_info: EscapeAnalysisInfo,
}
#[derive(Debug)]
pub struct OptimizationHints {
pub inline: InlineHint,
pub is_pure: bool, // No side effects
pub is_cold: bool, // Rarely executed
pub should_unroll: Option<usize>, // Loop unrolling
}
#[derive(Debug)]
pub enum InlineHint {
Always,
Never,
Heuristic,
}
#[derive(Debug)]
pub struct EscapeAnalysisInfo {
// Results
pub escaping_values: Vec<ValueId>,
pub stack_allocated_values: Vec<ValueId>,
pub heap_allocated_values: Vec<ValueId>,
// Analysis data
pub value_lifetimes: HashMap<ValueId, Lifetime>,
pub escape_reasons: HashMap<ValueId, EscapeReason>,
pub capture_sets: HashMap<ValueId, Vec<ValueId>>, // For closures
}
#[derive(Debug)]
pub struct Lifetime {
pub first_def: BasicBlockId,
pub last_use: BasicBlockId,
pub scope_depth: usize,
pub escapes_to_caller: bool,
pub escapes_to_heap: bool,
}
#[derive(Debug)]
pub enum EscapeReason {
ReturnedFromFunction,
StoredInHeapObject,
CapturedByClosure,
PassedToUnknownFunction,
ExceedsStackLimit,
}
#[derive(Debug)]
pub struct IRFunctionArg {
pub name: String,
pub binding_id: usize, // The binding ID from the AST
pub type_: IRTypeWithMemory,
pub memory_slot: MemorySlotId,
pub span: Range<usize>,
pub file: String,
}
// IR Struct definition
#[derive(Debug)]
pub struct IRStruct {
pub id: StructId,
pub name: String,
pub vis: Visibility,
pub fields: Vec<IRStructField>,
pub span: Range<usize>,
pub file: String,
pub struct_type: IRTypeWithMemory,
pub memory_layout: MemoryLayout, // Information about memory layout
}
#[derive(Debug)]
pub struct MemoryLayout {
pub size: usize,
pub alignment: usize,
pub field_offsets: Vec<(FieldId, usize)>, // (field_id, offset_in_bytes)
pub discriminant_offset: Option<usize>, // For enums
pub discriminant_size: Option<usize>, // u8, u16, u32, etc.
pub discriminant_encoding: Option<DiscriminantEncoding>,
pub padding_bytes: Vec<PaddingInfo>, // Where padding occurs
}
#[derive(Debug)]
pub enum DiscriminantEncoding {
Explicit, // Separate tag field
NicheOptimized, // Using pointer null/values
}
#[derive(Debug)]
pub struct IRStructField {
pub name: String,
pub field_id: FieldId,
pub type_: IRTypeWithMemory,
pub vis: Visibility,
pub span: Range<usize>,
pub file: String,
pub offset: usize, // Offset in the struct
}
// IR Enum definition
#[derive(Debug)]
pub struct IREnum {
pub id: EnumId,
pub name: String,
pub vis: Visibility,
pub variants: Vec<IREnumVariant>,
pub span: Range<usize>,
pub file: String,
pub enum_type: IRTypeWithMemory,
pub memory_layout: MemoryLayout, // Information about memory layout
}
#[derive(Debug)]
pub struct IREnumVariant {
pub name: String,
pub variant_id: VariantId,
pub types: Vec<IRTypeWithMemory>,
pub constructor_type: IRTypeWithMemory,
pub span: Range<usize>,
pub file: String,
pub data_offset: usize, // Offset of THIS variant's data (after discriminant)
pub discriminant_value: usize, // The tag value for this variant
}
// IR Effect definition
#[derive(Debug)]
pub struct IREffect {
pub id: EffectId,
pub name: String,
pub vis: Visibility,
pub operations: Vec<IREffectOperation>,
pub span: Range<usize>,
pub file: String,
}
#[derive(Debug)]
pub struct IREffectOperation {
pub name: String,
pub params: Vec<IRTypeWithMemory>,
pub return_type: IRTypeWithMemory,
pub operation_type: IRTypeWithMemory,
pub span: Range<usize>,
pub file: String,
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment