diff --git a/compiler/mono/src/alias_analysis.rs b/compiler/mono/src/alias_analysis.rs index 8714f17655..71e3b97aea 100644 --- a/compiler/mono/src/alias_analysis.rs +++ b/compiler/mono/src/alias_analysis.rs @@ -1,14 +1,15 @@ use morphic_lib::TypeContext; use morphic_lib::{ BlockExpr, BlockId, CalleeSpecVar, FuncDef, FuncDefBuilder, FuncName, ModName, Result, TypeId, - TypeName, ValueId, + TypeName, UpdateModeVar, ValueId, }; use roc_collections::all::MutMap; use roc_module::low_level::LowLevel; use roc_module::symbol::Symbol; +use std::convert::TryFrom; use crate::ir::{Call, CallType, Expr, Literal, Proc, Stmt}; -use crate::layout::{Builtin, Layout, UnionLayout}; +use crate::layout::{Builtin, Layout, ListLayout, UnionLayout}; // just using one module for now const MOD_NUM: ModName = ModName(b"UserApp"); @@ -240,14 +241,19 @@ fn call_spec( } fn lowlevel_spec( - _builder: &mut FuncDefBuilder, + builder: &mut FuncDefBuilder, _env: &Env, - _block: BlockId, + block: BlockId, _layout: &Layout, - _op: &LowLevel, + op: &LowLevel, _arguments: &[Symbol], ) -> Result { - todo!() + use LowLevel::*; + + match op { + NumAdd => builder.add_make_tuple(block, &[]), + _ => todo!(), + } } fn build_variant_types( @@ -343,7 +349,9 @@ fn expr_spec( Array { elem_layout, elems } => { let type_id = layout_spec(builder, elem_layout)?; - let mut bag = builder.add_empty_bag(block, type_id)?; + let list = new_list(builder, block, type_id)?; + + let mut bag = builder.add_get_tuple_field(block, list, LIST_BAG_INDEX)?; for symbol in elems.iter() { let value_id = env.symbols[symbol]; @@ -355,9 +363,20 @@ fn expr_spec( } EmptyArray => { - let type_id = layout_spec(builder, layout)?; + use ListLayout::*; - builder.add_empty_bag(block, type_id) + 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"), + } } Reuse { .. } => todo!("currently unused"), Reset(_) => todo!("currently unused"), @@ -377,7 +396,7 @@ fn literal_spec( use Literal::*; match literal { - Str(_) => todo!("string literals are statically allocated, so what do we do?"), + Str(_) => new_static_string(builder, block), Int(_) | Float(_) | Bool(_) | Byte(_) => builder.add_make_tuple(block, &[]), } } @@ -425,3 +444,29 @@ fn builtin_spec(builder: &mut FuncDefBuilder, builtin: &Builtin) -> TypeId { EmptySet => todo!(), } } + +const LIST_CELL_INDEX: u32 = 0; +const LIST_BAG_INDEX: u32 = 1; +const LIST_LEN_INDEX: u32 = 2; + +fn new_list(builder: &mut FuncDefBuilder, block: BlockId, element_type: TypeId) -> Result { + let cell = builder.add_new_heap_cell(block)?; + let bag = builder.add_empty_bag(block, element_type)?; + let length = new_usize(builder, block)?; + builder.add_make_tuple(block, &[cell, bag, length]) +} + +fn new_usize(builder: &mut FuncDefBuilder, block: BlockId) -> Result { + builder.add_make_tuple(block, &[]) +} + +fn new_static_string(builder: &mut FuncDefBuilder, block: BlockId) -> Result { + let cell = builder.add_new_heap_cell(block)?; + + // immediately mutate the cell, so any future updates on this value are invalid + // updating a static string would cause a crash at runtime + let _ = builder.add_update(block, UpdateModeVar(&[]), cell)?; + + let length = new_usize(builder, block)?; + builder.add_make_tuple(block, &[cell, length]) +} diff --git a/compiler/mono/src/layout.rs b/compiler/mono/src/layout.rs index 96867cbcdb..a54cae902c 100644 --- a/compiler/mono/src/layout.rs +++ b/compiler/mono/src/layout.rs @@ -1980,3 +1980,21 @@ impl<'a> LayoutIds<'a> { LayoutId(answer) } } + +#[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 { + match value { + Layout::Builtin(Builtin::EmptyList) => Ok(ListLayout::EmptyList), + Layout::Builtin(Builtin::List(_, element)) => Ok(ListLayout::List(element)), + _ => Err(()), + } + } +}