Support box/unbox for types that are typically only on the stack

Closes #2786
This commit is contained in:
Ayaz Hafiz 2022-04-09 16:21:41 -04:00
parent ebb03f60dd
commit a102a7497e
No known key found for this signature in database
GPG Key ID: 0E2A37416A25EF58
2 changed files with 53 additions and 5 deletions

View File

@ -468,7 +468,7 @@ impl<'a> UnionLayout<'a> {
pub fn allocation_alignment_bytes(&self, target_info: TargetInfo) -> u32 { pub fn allocation_alignment_bytes(&self, target_info: TargetInfo) -> u32 {
let allocation = match self { let allocation = match self {
UnionLayout::NonRecursive(_) => unreachable!("not heap-allocated"), UnionLayout::NonRecursive(tags) => Self::tags_alignment_bytes(tags, target_info),
UnionLayout::Recursive(tags) => Self::tags_alignment_bytes(tags, target_info), UnionLayout::Recursive(tags) => Self::tags_alignment_bytes(tags, target_info),
UnionLayout::NonNullableUnwrapped(field_layouts) => { UnionLayout::NonNullableUnwrapped(field_layouts) => {
Layout::struct_no_name_order(field_layouts).alignment_bytes(target_info) Layout::struct_no_name_order(field_layouts).alignment_bytes(target_info)
@ -1150,9 +1150,11 @@ impl<'a> Layout<'a> {
} }
pub fn allocation_alignment_bytes(&self, target_info: TargetInfo) -> u32 { pub fn allocation_alignment_bytes(&self, target_info: TargetInfo) -> u32 {
let ptr_width = target_info.ptr_width() as u32;
match self { match self {
Layout::Builtin(builtin) => builtin.allocation_alignment_bytes(target_info), Layout::Builtin(builtin) => builtin.allocation_alignment_bytes(target_info),
Layout::Struct { .. } => unreachable!("not heap-allocated"), Layout::Struct { .. } => self.alignment_bytes(target_info).max(ptr_width),
Layout::Union(union_layout) => union_layout.allocation_alignment_bytes(target_info), Layout::Union(union_layout) => union_layout.allocation_alignment_bytes(target_info),
Layout::LambdaSet(lambda_set) => lambda_set Layout::LambdaSet(lambda_set) => lambda_set
.runtime_representation() .runtime_representation()
@ -1545,9 +1547,6 @@ impl<'a> Builtin<'a> {
let ptr_width = target_info.ptr_width() as u32; let ptr_width = target_info.ptr_width() as u32;
let allocation = match self { let allocation = match self {
Builtin::Int(_) | Builtin::Float(_) | Builtin::Bool | Builtin::Decimal => {
unreachable!("not heap-allocated")
}
Builtin::Str => ptr_width, Builtin::Str => ptr_width,
Builtin::Dict(k, v) => k Builtin::Dict(k, v) => k
.alignment_bytes(target_info) .alignment_bytes(target_info)
@ -1555,6 +1554,11 @@ impl<'a> Builtin<'a> {
.max(ptr_width), .max(ptr_width),
Builtin::Set(k) => k.alignment_bytes(target_info).max(ptr_width), Builtin::Set(k) => k.alignment_bytes(target_info).max(ptr_width),
Builtin::List(e) => e.alignment_bytes(target_info).max(ptr_width), Builtin::List(e) => e.alignment_bytes(target_info).max(ptr_width),
// The following are usually not heap-allocated, but they might be when inside a Box.
Builtin::Int(int_width) => int_width.alignment_bytes(target_info).max(ptr_width),
Builtin::Float(float_width) => float_width.alignment_bytes(target_info).max(ptr_width),
Builtin::Bool => (core::mem::align_of::<bool>() as u32).max(ptr_width),
Builtin::Decimal => IntWidth::I128.alignment_bytes(target_info).max(ptr_width),
}; };
allocation.max(ptr_width) allocation.max(ptr_width)

View File

@ -3275,3 +3275,47 @@ fn box_and_unbox_string() {
RocStr RocStr
) )
} }
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn box_and_unbox_num() {
assert_evals_to!(
indoc!(
r#"
Box.unbox (Box.box (123u8))
"#
),
123,
u8
)
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn box_and_unbox_record() {
assert_evals_to!(
indoc!(
r#"
Box.unbox (Box.box { a: 15u8, b: 27u8 })
"#
),
(15, 27),
(u8, u8)
)
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn box_and_unbox_tag_union() {
assert_evals_to!(
indoc!(
r#"
v : [ A U8, B U8 ] # usually stack allocated
v = B 27u8
Box.unbox (Box.box v)
"#
),
(27, 1),
(u8, u8)
)
}