mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-04 12:18:19 +00:00
Make loading from struct a method
This commit is contained in:
parent
bb3cfb9cd3
commit
e1f8d68055
2 changed files with 70 additions and 49 deletions
|
@ -7,7 +7,7 @@ use crate::llvm::expect::{clone_to_shared_memory, SharedMemoryPointer};
|
|||
use crate::llvm::refcounting::{
|
||||
build_reset, decrement_refcount_layout, increment_refcount_layout, PointerToRefcount,
|
||||
};
|
||||
use crate::llvm::struct_::{self, struct_from_fields, RocStruct};
|
||||
use crate::llvm::struct_::{struct_from_fields, RocStruct};
|
||||
use bumpalo::collections::Vec;
|
||||
use bumpalo::Bump;
|
||||
use inkwell::attributes::{Attribute, AttributeLoc};
|
||||
|
@ -1269,8 +1269,9 @@ pub(crate) fn build_exp_expr<'a, 'ctx>(
|
|||
index, structure, ..
|
||||
} => {
|
||||
let (value, layout) = scope.load_symbol_and_layout(structure);
|
||||
let struct_val = RocStruct::from(value);
|
||||
|
||||
struct_::load_at_index(env, layout_interner, layout, value, *index)
|
||||
struct_val.load_at_index(env, layout_interner, layout, *index)
|
||||
}
|
||||
|
||||
EmptyArray => empty_polymorphic_list(env),
|
||||
|
|
|
@ -61,6 +61,7 @@ fn basic_type_from_record<'a, 'ctx>(
|
|||
.struct_type(field_types.into_bump_slice(), false)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum RocStruct<'ctx> {
|
||||
/// The roc struct should be passed by rvalue.
|
||||
ByValue(StructValue<'ctx>),
|
||||
|
@ -72,6 +73,16 @@ impl<'ctx> Into<BasicValueEnum<'ctx>> for RocStruct<'ctx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'ctx> From<BasicValueEnum<'ctx>> for RocStruct<'ctx> {
|
||||
#[track_caller]
|
||||
fn from(basic_value: BasicValueEnum<'ctx>) -> Self {
|
||||
match basic_value {
|
||||
BasicValueEnum::StructValue(struct_value) => RocStruct::ByValue(struct_value),
|
||||
_ => panic!("Expected struct value"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx> RocStruct<'ctx> {
|
||||
pub fn build<'a>(
|
||||
env: &Env<'a, 'ctx, '_>,
|
||||
|
@ -88,6 +99,62 @@ impl<'ctx> RocStruct<'ctx> {
|
|||
RocStruct::ByValue(struct_val) => struct_val.as_basic_value_enum(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_at_index<'a>(
|
||||
&self,
|
||||
env: &Env<'a, 'ctx, '_>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout: InLayout<'a>,
|
||||
index: u64,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let layout = if let LayoutRepr::LambdaSet(lambda_set) = layout_interner.get_repr(layout) {
|
||||
lambda_set.runtime_representation()
|
||||
} else {
|
||||
layout
|
||||
};
|
||||
|
||||
match (self, layout_interner.get_repr(layout)) {
|
||||
(Self::ByValue(argument), LayoutRepr::Struct(field_layouts)) => {
|
||||
index_struct_value(env, layout_interner, field_layouts, *argument, index)
|
||||
}
|
||||
(other, layout) => {
|
||||
unreachable!(
|
||||
"can only index into struct layout\nValue: {:?}\nLayout: {:?}\nIndex: {:?}",
|
||||
other, layout, index
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn index_struct_value<'a, 'ctx>(
|
||||
env: &Env<'a, 'ctx, '_>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
field_layouts: &[InLayout<'a>],
|
||||
argument: StructValue<'ctx>,
|
||||
index: u64,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
debug_assert!(!field_layouts.is_empty());
|
||||
|
||||
let field_value = env
|
||||
.builder
|
||||
.build_extract_value(
|
||||
argument,
|
||||
index as u32,
|
||||
env.arena
|
||||
.alloc(format!("struct_field_access_record_{}", index)),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let field_layout = field_layouts[index as usize];
|
||||
|
||||
use_roc_value(
|
||||
env,
|
||||
layout_interner,
|
||||
field_layout,
|
||||
field_value,
|
||||
"struct_field_tag",
|
||||
)
|
||||
}
|
||||
|
||||
fn build_struct_value<'a, 'ctx>(
|
||||
|
@ -157,50 +224,3 @@ where
|
|||
|
||||
struct_value.into_struct_value()
|
||||
}
|
||||
|
||||
pub fn load_at_index<'a, 'ctx>(
|
||||
env: &Env<'a, 'ctx, '_>,
|
||||
layout_interner: &mut STLayoutInterner<'a>,
|
||||
layout: InLayout<'a>,
|
||||
value: BasicValueEnum<'ctx>,
|
||||
index: u64,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let layout = if let LayoutRepr::LambdaSet(lambda_set) = layout_interner.get_repr(layout) {
|
||||
lambda_set.runtime_representation()
|
||||
} else {
|
||||
layout
|
||||
};
|
||||
|
||||
// extract field from a record
|
||||
match (value, layout_interner.get_repr(layout)) {
|
||||
(BasicValueEnum::StructValue(argument), LayoutRepr::Struct(field_layouts)) => {
|
||||
debug_assert!(!field_layouts.is_empty());
|
||||
|
||||
let field_value = env
|
||||
.builder
|
||||
.build_extract_value(
|
||||
argument,
|
||||
index as u32,
|
||||
env.arena
|
||||
.alloc(format!("struct_field_access_record_{}", index)),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let field_layout = field_layouts[index as usize];
|
||||
use_roc_value(
|
||||
env,
|
||||
layout_interner,
|
||||
field_layout,
|
||||
field_value,
|
||||
"struct_field_tag",
|
||||
)
|
||||
}
|
||||
(other, layout) => {
|
||||
// potential cause: indexing into an unwrapped 1-element record/tag?
|
||||
unreachable!(
|
||||
"can only index into struct layout\nValue: {:?}\nLayout: {:?}\nIndex: {:?}",
|
||||
other, layout, index
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue