mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 08:11:12 +00:00
remove empty layout types (list,str,dict,set)
This commit is contained in:
parent
8d668514e4
commit
a1fd34feef
11 changed files with 94 additions and 296 deletions
|
@ -7,13 +7,12 @@ use morphic_lib::{
|
|||
use roc_collections::all::{MutMap, MutSet};
|
||||
use roc_module::low_level::LowLevel;
|
||||
use roc_module::symbol::Symbol;
|
||||
use std::convert::TryFrom;
|
||||
|
||||
use crate::ir::{
|
||||
Call, CallType, Expr, HigherOrderLowLevel, HostExposedLayouts, ListLiteralElement, Literal,
|
||||
ModifyRc, OptLevel, Proc, Stmt,
|
||||
};
|
||||
use crate::layout::{Builtin, Layout, ListLayout, RawFunctionLayout, UnionLayout};
|
||||
use crate::layout::{Builtin, Layout, RawFunctionLayout, UnionLayout};
|
||||
|
||||
// just using one module for now
|
||||
pub const MOD_APP: ModName = ModName(b"UserApp");
|
||||
|
@ -1305,21 +1304,14 @@ fn lowlevel_spec(
|
|||
|
||||
builder.add_make_tuple(block, &[byte_index, string, is_ok, problem_code])
|
||||
}
|
||||
DictEmpty => {
|
||||
match layout {
|
||||
Layout::Builtin(Builtin::EmptyDict) => {
|
||||
// just make up an element type
|
||||
let type_id = builder.add_tuple_type(&[])?;
|
||||
new_dict(builder, block, type_id, type_id)
|
||||
}
|
||||
Layout::Builtin(Builtin::Dict(key_layout, value_layout)) => {
|
||||
let key_id = layout_spec(builder, key_layout)?;
|
||||
let value_id = layout_spec(builder, value_layout)?;
|
||||
new_dict(builder, block, key_id, value_id)
|
||||
}
|
||||
_ => unreachable!("empty array does not have a list layout"),
|
||||
DictEmpty => match layout {
|
||||
Layout::Builtin(Builtin::Dict(key_layout, value_layout)) => {
|
||||
let key_id = layout_spec(builder, key_layout)?;
|
||||
let value_id = layout_spec(builder, value_layout)?;
|
||||
new_dict(builder, block, key_id, value_id)
|
||||
}
|
||||
}
|
||||
_ => unreachable!("empty array does not have a list layout"),
|
||||
},
|
||||
DictGetUnsafe => {
|
||||
// NOTE DictGetUnsafe returns a { flag: Bool, value: v }
|
||||
// when the flag is True, the value is found and defined;
|
||||
|
@ -1611,22 +1603,13 @@ fn expr_spec<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
EmptyArray => {
|
||||
use ListLayout::*;
|
||||
|
||||
match ListLayout::try_from(layout) {
|
||||
Ok(EmptyList) => {
|
||||
// just make up an element type
|
||||
let type_id = builder.add_tuple_type(&[])?;
|
||||
new_list(builder, block, type_id)
|
||||
}
|
||||
Ok(List(element_layout)) => {
|
||||
let type_id = layout_spec(builder, element_layout)?;
|
||||
new_list(builder, block, type_id)
|
||||
}
|
||||
Err(()) => unreachable!("empty array does not have a list layout"),
|
||||
EmptyArray => match layout {
|
||||
Layout::Builtin(Builtin::List(element_layout)) => {
|
||||
let type_id = layout_spec(builder, element_layout)?;
|
||||
new_list(builder, block, type_id)
|
||||
}
|
||||
}
|
||||
_ => unreachable!("empty array does not have a list layout"),
|
||||
},
|
||||
Reset(symbol) => {
|
||||
let type_id = layout_spec(builder, layout)?;
|
||||
let value_id = env.symbols[symbol];
|
||||
|
@ -1720,7 +1703,7 @@ fn builtin_spec(
|
|||
match builtin {
|
||||
Int(_) | Bool => builder.add_tuple_type(&[]),
|
||||
Decimal | Float(_) => builder.add_tuple_type(&[]),
|
||||
Str | EmptyStr => str_type(builder),
|
||||
Str => str_type(builder),
|
||||
Dict(key_layout, value_layout) => {
|
||||
let value_type = layout_spec_help(builder, value_layout, when_recursive)?;
|
||||
let key_type = layout_spec_help(builder, key_layout, when_recursive)?;
|
||||
|
@ -1745,25 +1728,6 @@ fn builtin_spec(
|
|||
let cell = builder.add_heap_cell_type();
|
||||
let bag = builder.add_bag_type(element_type)?;
|
||||
|
||||
builder.add_tuple_type(&[cell, bag])
|
||||
}
|
||||
EmptyList => {
|
||||
// TODO make sure that we consistently treat the EmptyList as a list of unit values
|
||||
let element_type = builder.add_tuple_type(&[])?;
|
||||
|
||||
let cell = builder.add_heap_cell_type();
|
||||
let bag = builder.add_bag_type(element_type)?;
|
||||
|
||||
builder.add_tuple_type(&[cell, bag])
|
||||
}
|
||||
EmptyDict | EmptySet => {
|
||||
// TODO make sure that we consistently treat the these as a dict of unit values
|
||||
let unit = builder.add_tuple_type(&[])?;
|
||||
let element_type = builder.add_tuple_type(&[unit, unit])?;
|
||||
|
||||
let cell = builder.add_heap_cell_type();
|
||||
let bag = builder.add_bag_type(element_type)?;
|
||||
|
||||
builder.add_tuple_type(&[cell, bag])
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3562,7 +3562,12 @@ pub fn with_hole<'a>(
|
|||
}
|
||||
Err(LayoutProblem::UnresolvedTypeVar(_)) => {
|
||||
let expr = Expr::EmptyArray;
|
||||
Stmt::Let(assigned, expr, Layout::Builtin(Builtin::EmptyList), hole)
|
||||
Stmt::Let(
|
||||
assigned,
|
||||
expr,
|
||||
Layout::Builtin(Builtin::List(&Layout::VOID)),
|
||||
hole,
|
||||
)
|
||||
}
|
||||
Err(LayoutProblem::Erroneous) => panic!("list element is error type"),
|
||||
}
|
||||
|
|
|
@ -688,10 +688,6 @@ pub enum Builtin<'a> {
|
|||
Dict(&'a Layout<'a>, &'a Layout<'a>),
|
||||
Set(&'a Layout<'a>),
|
||||
List(&'a Layout<'a>),
|
||||
EmptyStr,
|
||||
EmptyList,
|
||||
EmptyDict,
|
||||
EmptySet,
|
||||
}
|
||||
|
||||
pub struct Env<'a, 'b> {
|
||||
|
@ -735,6 +731,8 @@ const fn round_up_to_alignment(width: u32, alignment: u32) -> u32 {
|
|||
}
|
||||
|
||||
impl<'a> Layout<'a> {
|
||||
pub const VOID: Self = Layout::Union(UnionLayout::NonRecursive(&[]));
|
||||
|
||||
fn new_help<'b>(
|
||||
env: &mut Env<'a, 'b>,
|
||||
var: Variable,
|
||||
|
@ -1205,10 +1203,10 @@ impl<'a> Builtin<'a> {
|
|||
Float(float) => float.stack_size(),
|
||||
Bool => Builtin::I1_SIZE,
|
||||
Decimal => Builtin::DECIMAL_SIZE,
|
||||
Str | EmptyStr => Builtin::STR_WORDS * pointer_size,
|
||||
Dict(_, _) | EmptyDict => Builtin::DICT_WORDS * pointer_size,
|
||||
Set(_) | EmptySet => Builtin::SET_WORDS * pointer_size,
|
||||
List(_) | EmptyList => Builtin::LIST_WORDS * pointer_size,
|
||||
Str => Builtin::STR_WORDS * pointer_size,
|
||||
Dict(_, _) => Builtin::DICT_WORDS * pointer_size,
|
||||
Set(_) => Builtin::SET_WORDS * pointer_size,
|
||||
List(_) => Builtin::LIST_WORDS * pointer_size,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1224,15 +1222,15 @@ impl<'a> Builtin<'a> {
|
|||
Float(float_width) => float_width.alignment_bytes(),
|
||||
Bool => align_of::<bool>() as u32,
|
||||
Decimal => align_of::<i128>() as u32,
|
||||
Dict(_, _) | EmptyDict => pointer_size,
|
||||
Set(_) | EmptySet => pointer_size,
|
||||
Dict(_, _) => pointer_size,
|
||||
Set(_) => pointer_size,
|
||||
// we often treat these as i128 (64-bit systems)
|
||||
// or i64 (32-bit systems).
|
||||
//
|
||||
// In webassembly, For that to be safe
|
||||
// they must be aligned to allow such access
|
||||
List(_) | EmptyList => pointer_size,
|
||||
Str | EmptyStr => pointer_size,
|
||||
List(_) => pointer_size,
|
||||
Str => pointer_size,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1240,9 +1238,7 @@ impl<'a> Builtin<'a> {
|
|||
use Builtin::*;
|
||||
|
||||
match self {
|
||||
Int(_) | Float(_) | Bool | Decimal | EmptyStr | EmptyDict | EmptyList | EmptySet => {
|
||||
true
|
||||
}
|
||||
Int(_) | Float(_) | Bool | Decimal => true,
|
||||
|
||||
Str | Dict(_, _) | Set(_) | List(_) => false,
|
||||
}
|
||||
|
@ -1253,9 +1249,7 @@ impl<'a> Builtin<'a> {
|
|||
use Builtin::*;
|
||||
|
||||
match self {
|
||||
Int(_) | Float(_) | Bool | Decimal | EmptyStr | EmptyDict | EmptyList | EmptySet => {
|
||||
false
|
||||
}
|
||||
Int(_) | Float(_) | Bool | Decimal => false,
|
||||
List(_) => true,
|
||||
|
||||
Str | Dict(_, _) | Set(_) => true,
|
||||
|
@ -1301,11 +1295,6 @@ impl<'a> Builtin<'a> {
|
|||
Bool => alloc.text("Int1"),
|
||||
Decimal => alloc.text("Decimal"),
|
||||
|
||||
EmptyStr => alloc.text("EmptyStr"),
|
||||
EmptyList => alloc.text("EmptyList"),
|
||||
EmptyDict => alloc.text("EmptyDict"),
|
||||
EmptySet => alloc.text("EmptySet"),
|
||||
|
||||
Str => alloc.text("Str"),
|
||||
List(layout) => alloc
|
||||
.text("List ")
|
||||
|
@ -1333,9 +1322,6 @@ impl<'a> Builtin<'a> {
|
|||
.max(pointer_size),
|
||||
Builtin::Set(k) => k.alignment_bytes(pointer_size).max(pointer_size),
|
||||
Builtin::List(e) => e.alignment_bytes(pointer_size).max(pointer_size),
|
||||
Builtin::EmptyStr | Builtin::EmptyList | Builtin::EmptyDict | Builtin::EmptySet => {
|
||||
unreachable!("not heap-allocated")
|
||||
}
|
||||
};
|
||||
|
||||
allocation.max(pointer_size)
|
||||
|
@ -1578,7 +1564,7 @@ fn layout_from_flat_type<'a>(
|
|||
|
||||
Ok(Layout::Union(union_layout))
|
||||
}
|
||||
EmptyTagUnion => Ok(Layout::Union(UnionLayout::NonRecursive(&[]))),
|
||||
EmptyTagUnion => Ok(Layout::VOID),
|
||||
Erroneous(_) => Err(LayoutProblem::Erroneous),
|
||||
EmptyRecord => Ok(Layout::Struct(&[])),
|
||||
}
|
||||
|
@ -2316,7 +2302,7 @@ fn layout_from_tag_union<'a>(
|
|||
let variant = union_sorted_tags_help_new(arena, tags_vec, opt_rec_var, subs, ptr_bytes);
|
||||
|
||||
match variant {
|
||||
Never => Layout::Union(UnionLayout::NonRecursive(&[])),
|
||||
Never => Layout::VOID,
|
||||
Unit | UnitWithArguments => Layout::Struct(&[]),
|
||||
BoolUnion { .. } => Layout::bool(),
|
||||
ByteUnion(_) => Layout::u8(),
|
||||
|
@ -2552,40 +2538,54 @@ fn dict_layout_from_key_value<'a>(
|
|||
key_var: Variable,
|
||||
value_var: Variable,
|
||||
) -> Result<Layout<'a>, LayoutProblem> {
|
||||
match env.subs.get_content_without_compacting(key_var) {
|
||||
Content::FlexVar(_) | Content::RigidVar(_) => {
|
||||
// If this was still a (Dict * *) then it must have been an empty dict
|
||||
Ok(Layout::Builtin(Builtin::EmptyDict))
|
||||
}
|
||||
key_content => {
|
||||
let value_content = env.subs.get_content_without_compacting(value_var);
|
||||
let key_layout = Layout::new_help(env, key_var, key_content.clone())?;
|
||||
let value_layout = Layout::new_help(env, value_var, value_content.clone())?;
|
||||
let is_variable = |content| matches!(content, &Content::FlexVar(_) | &Content::RigidVar(_));
|
||||
|
||||
// This is a normal list.
|
||||
Ok(Layout::Builtin(Builtin::Dict(
|
||||
env.arena.alloc(key_layout),
|
||||
env.arena.alloc(value_layout),
|
||||
)))
|
||||
}
|
||||
}
|
||||
let key_content = env.subs.get_content_without_compacting(key_var);
|
||||
let value_content = env.subs.get_content_without_compacting(value_var);
|
||||
|
||||
let key_layout = if is_variable(key_content) {
|
||||
Layout::VOID
|
||||
} else {
|
||||
// NOTE: cannot re-use Content, because it may be recursive
|
||||
// then some state is not correctly kept, we have to go through from_var
|
||||
Layout::from_var(env, key_var)?
|
||||
};
|
||||
|
||||
let value_layout = if is_variable(value_content) {
|
||||
Layout::VOID
|
||||
} else {
|
||||
// NOTE: cannot re-use Content, because it may be recursive
|
||||
// then some state is not correctly kept, we have to go through from_var
|
||||
Layout::from_var(env, value_var)?
|
||||
};
|
||||
|
||||
// This is a normal list.
|
||||
Ok(Layout::Builtin(Builtin::Dict(
|
||||
env.arena.alloc(key_layout),
|
||||
env.arena.alloc(value_layout),
|
||||
)))
|
||||
}
|
||||
|
||||
pub fn list_layout_from_elem<'a>(
|
||||
env: &mut Env<'a, '_>,
|
||||
elem_var: Variable,
|
||||
element_var: Variable,
|
||||
) -> Result<Layout<'a>, LayoutProblem> {
|
||||
match env.subs.get_content_without_compacting(elem_var) {
|
||||
Content::FlexVar(_) | Content::RigidVar(_) => {
|
||||
// If this was still a (List *) then it must have been an empty list
|
||||
Ok(Layout::Builtin(Builtin::EmptyList))
|
||||
}
|
||||
_ => {
|
||||
let elem_layout = Layout::from_var(env, elem_var)?;
|
||||
let is_variable = |content| matches!(content, &Content::FlexVar(_) | &Content::RigidVar(_));
|
||||
|
||||
Ok(Layout::Builtin(Builtin::List(env.arena.alloc(elem_layout))))
|
||||
}
|
||||
}
|
||||
let element_content = env.subs.get_content_without_compacting(element_var);
|
||||
|
||||
let element_layout = if is_variable(element_content) {
|
||||
// If this was still a (List *) then it must have been an empty list
|
||||
Layout::VOID
|
||||
} else {
|
||||
// NOTE: cannot re-use Content, because it may be recursive
|
||||
// then some state is not correctly kept, we have to go through from_var
|
||||
Layout::from_var(env, element_var)?
|
||||
};
|
||||
|
||||
Ok(Layout::Builtin(Builtin::List(
|
||||
env.arena.alloc(element_layout),
|
||||
)))
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
|
@ -2708,24 +2708,6 @@ impl<'a> LayoutIds<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum ListLayout<'a> {
|
||||
EmptyList,
|
||||
List(&'a Layout<'a>),
|
||||
}
|
||||
|
||||
impl<'a> std::convert::TryFrom<&Layout<'a>> for ListLayout<'a> {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(value: &Layout<'a>) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
Layout::Builtin(Builtin::EmptyList) => Ok(ListLayout::EmptyList),
|
||||
Layout::Builtin(Builtin::List(element)) => Ok(ListLayout::List(element)),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue