diff --git a/compiler/gen/src/crane/build.rs b/compiler/gen/src/crane/build.rs index cb45836e22..493642cd56 100644 --- a/compiler/gen/src/crane/build.rs +++ b/compiler/gen/src/crane/build.rs @@ -194,16 +194,59 @@ pub fn build_expr<'a, B: Backend>( builder.ins().stack_store(val, slot, Offset32::new(offset)); } - let ir_type = type_from_layout(cfg, layout); - builder.ins().stack_addr(ir_type, slot, Offset32::new(0)) + builder + .ins() + .stack_addr(cfg.pointer_type(), slot, Offset32::new(0)) + } + Access { + label, + field_layout, + struct_layout: Layout::Struct(fields), + record, + } => { + let cfg = env.cfg; + + // Reconstruct the struct to determine the combined layout + // TODO get rid of clones + let mut reconstructed_struct_layout = + Vec::with_capacity_in(fields.len() + 1, env.arena); + for field in fields.iter() { + reconstructed_struct_layout.push(field.clone()); + } + reconstructed_struct_layout.push((label.clone(), field_layout.clone())); + reconstructed_struct_layout.sort_by(|a, b| { + a.0.partial_cmp(&b.0) + .expect("TODO: failed to sort struct fields in crane access") + }); + + // Find the offset we are trying to access + let mut offset = 0; + for (local_label, layout) in reconstructed_struct_layout.iter() { + if local_label == label { + break; + } + + let field_size = match layout { + Layout::Builtin(Builtin::Int64) => std::mem::size_of::(), + _ => panic!( + "Missing struct field size in offset calculation for struct access for {:?}", + layout + ), + }; + + offset += field_size; + } + + let offset = i32::try_from(offset) + .expect("TODO gracefully handle usize -> i32 conversion in struct access"); + + let mem_flags = MemFlags::new(); + let record = build_expr(env, scope, module, builder, record, procs); + + builder + .ins() + .load(cfg.pointer_type(), mem_flags, record, Offset32::new(offset)) } - // Access { - // label, - // field_layout, - // struct_layout, - // } => { - // panic!("I don't yet know how to crane build {:?}", expr); - // } Str(str_literal) => { if str_literal.is_empty() { panic!("TODO build an empty string in Crane"); diff --git a/compiler/gen/src/crane/convert.rs b/compiler/gen/src/crane/convert.rs index 4039fabb68..6a0c9ad2ef 100644 --- a/compiler/gen/src/crane/convert.rs +++ b/compiler/gen/src/crane/convert.rs @@ -10,20 +10,7 @@ pub fn type_from_layout(cfg: TargetFrontendConfig, layout: &Layout<'_>) -> Type use roc_mono::layout::Layout::*; match layout { - Pointer(_) | FunctionPointer(_, _) => cfg.pointer_type(), - Struct(fields) => { - // This will change as we add more fields and field types to the tests - let naive_all_ints = fields.iter().all(|ref field| match field.1 { - Builtin(Int64) => true, - _ => false, - }); - - if naive_all_ints && fields.len() == 3 { - types::I64.by(4).unwrap() - } else { - panic!("TODO layout_to_crane_type for Struct"); - } - } + Pointer(_) | FunctionPointer(_, _) | Struct(_) => cfg.pointer_type(), Builtin(builtin) => match builtin { Int64 => types::I64, Float64 => types::F64, diff --git a/compiler/gen/tests/test_gen.rs b/compiler/gen/tests/test_gen.rs index 464f680ddd..e82f274709 100644 --- a/compiler/gen/tests/test_gen.rs +++ b/compiler/gen/tests/test_gen.rs @@ -873,9 +873,7 @@ mod test_gen { // assert_evals_to!( // indoc!( // r#" - // point = { x: 15, y: 17, z: 19 } - - // point.x + // { y: 17, x: 15, z: 19 }.x // "# // ), // 15, @@ -885,20 +883,17 @@ mod test_gen { // assert_evals_to!( // indoc!( // r#" - // point = { x: 15, y: 17, z: 19 } - - // point.y + // { x: 15, y: 17, z: 19 }.y // "# // ), // 17, // i64 // ); + // assert_evals_to!( // indoc!( // r#" - // point = { x: 15, y: 17, z: 19 } - - // point.z + // { x: 15, y: 17, z: 19 }.z // "# // ), // 19, diff --git a/compiler/mono/src/expr.rs b/compiler/mono/src/expr.rs index d9b6c9a928..63762aa15b 100644 --- a/compiler/mono/src/expr.rs +++ b/compiler/mono/src/expr.rs @@ -101,6 +101,7 @@ pub enum Expr<'a> { label: Lowercase, field_layout: Layout<'a>, struct_layout: Layout<'a>, + record: &'a Expr<'a>, }, Array { @@ -398,7 +399,7 @@ fn from_can<'a>( ext_var, field_var, field, - .. + loc_expr, } => { let subs = env.subs; let arena = env.arena; @@ -419,10 +420,13 @@ fn from_can<'a>( } }; + let record = arena.alloc(from_can(env, loc_expr.value, procs, None)); + Expr::Access { label: field, field_layout, struct_layout, + record, } }