working mono

This commit is contained in:
Folkert 2021-11-20 23:25:30 +01:00
parent 25a64f4a57
commit c4ec9aa898
15 changed files with 431 additions and 358 deletions

1
Cargo.lock generated
View file

@ -3458,6 +3458,7 @@ dependencies = [
"bumpalo", "bumpalo",
"hashbrown 0.11.2", "hashbrown 0.11.2",
"morphic_lib", "morphic_lib",
"roc_builtins",
"roc_can", "roc_can",
"roc_collections", "roc_collections",
"roc_module", "roc_module",

View file

@ -71,7 +71,7 @@ fn jit_to_ast_help<'a>(
content: &Content, content: &Content,
) -> Result<Expr<'a>, ToAstProblem> { ) -> Result<Expr<'a>, ToAstProblem> {
match layout { match layout {
Layout::Builtin(Builtin::Int1) => Ok(run_jit_function!(lib, main_fn_name, bool, |num| { Layout::Builtin(Builtin::Bool) => Ok(run_jit_function!(lib, main_fn_name, bool, |num| {
bool_to_ast(env, num, content) bool_to_ast(env, num, content)
})), })),
Layout::Builtin(Builtin::Int8) => { Layout::Builtin(Builtin::Int8) => {
@ -248,7 +248,7 @@ fn jit_to_ast_help<'a>(
.unwrap_or(0); .unwrap_or(0);
let tag_id = match union_layout.tag_id_builtin() { let tag_id = match union_layout.tag_id_builtin() {
Builtin::Int1 => { Builtin::Bool => {
*(ptr.add(offset as usize) as *const i8) as i64 *(ptr.add(offset as usize) as *const i8) as i64
} }
Builtin::Int8 => { Builtin::Int8 => {
@ -406,7 +406,7 @@ fn ptr_to_ast<'a>(
num_to_ast(env, number_literal_to_ast(env.arena, num), content) num_to_ast(env, number_literal_to_ast(env.arena, num), content)
} }
Layout::Builtin(Builtin::Int1) => { Layout::Builtin(Builtin::Bool) => {
// TODO: bits are not as expected here. // TODO: bits are not as expected here.
// num is always false at the moment. // num is always false at the moment.
let num = unsafe { *(ptr as *const bool) }; let num = unsafe { *(ptr as *const bool) };

View file

@ -1,3 +1,4 @@
use roc_module::symbol::Symbol;
use std::ops::Index; use std::ops::Index;
pub const BUILTINS_HOST_OBJ_PATH: &str = env!( pub const BUILTINS_HOST_OBJ_PATH: &str = env!(
@ -27,13 +28,55 @@ pub enum DecWidth {
} }
#[repr(u8)] #[repr(u8)]
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum FloatWidth { pub enum FloatWidth {
F32, F32,
F64, F64,
F128, F128,
} }
impl FloatWidth {
pub const fn stack_size(&self) -> u32 {
use FloatWidth::*;
match self {
F32 => 4,
F64 => 8,
F128 => 16,
}
}
pub const fn alignment_bytes(&self) -> u32 {
use std::mem::align_of;
use FloatWidth::*;
// TODO actually alignment is architecture-specific
match self {
F32 => align_of::<f32>() as u32,
F64 => align_of::<f64>() as u32,
F128 => align_of::<i128>() as u32,
}
}
pub const fn try_from_symbol(symbol: Symbol) -> Option<Self> {
match symbol {
Symbol::NUM_FLOAT => Some(FloatWidth::F64),
Symbol::NUM_F64 | Symbol::NUM_BINARY64 | Symbol::NUM_AT_BINARY64 => {
Some(FloatWidth::F64)
}
Symbol::NUM_F32 | Symbol::NUM_BINARY32 | Symbol::NUM_AT_BINARY32 => {
Some(FloatWidth::F32)
}
_ => None,
}
}
}
#[repr(u8)] #[repr(u8)]
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum IntWidth { pub enum IntWidth {
U8, U8,
U16, U16,
@ -47,6 +90,61 @@ pub enum IntWidth {
I128, I128,
} }
impl IntWidth {
pub const fn stack_size(&self) -> u32 {
use IntWidth::*;
match self {
U8 | I8 => 1,
U16 | I16 => 2,
U32 | I32 => 4,
U64 | I64 => 8,
U128 | I128 => 16,
}
}
pub const fn alignment_bytes(&self) -> u32 {
use std::mem::align_of;
use IntWidth::*;
// TODO actually alignment is architecture-specific
match self {
U8 | I8 => align_of::<i8>() as u32,
U16 | I16 => align_of::<i16>() as u32,
U32 | I32 => align_of::<i32>() as u32,
U64 | I64 => align_of::<i64>() as u32,
U128 | I128 => align_of::<i128>() as u32,
}
}
pub const fn try_from_symbol(symbol: Symbol) -> Option<Self> {
match symbol {
Symbol::NUM_INT => Some(IntWidth::I64),
Symbol::NUM_I128 | Symbol::NUM_SIGNED128 | Symbol::NUM_AT_SIGNED128 => {
Some(IntWidth::I128)
}
Symbol::NUM_I64 | Symbol::NUM_SIGNED64 | Symbol::NUM_AT_SIGNED64 => Some(IntWidth::I64),
Symbol::NUM_I32 | Symbol::NUM_SIGNED32 | Symbol::NUM_AT_SIGNED32 => Some(IntWidth::I32),
Symbol::NUM_I16 | Symbol::NUM_SIGNED16 | Symbol::NUM_AT_SIGNED16 => Some(IntWidth::I16),
Symbol::NUM_I8 | Symbol::NUM_SIGNED8 | Symbol::NUM_AT_SIGNED8 => Some(IntWidth::I8),
Symbol::NUM_U128 | Symbol::NUM_UNSIGNED128 | Symbol::NUM_AT_UNSIGNED128 => {
Some(IntWidth::U128)
}
Symbol::NUM_U64 | Symbol::NUM_UNSIGNED64 | Symbol::NUM_AT_UNSIGNED64 => {
Some(IntWidth::U64)
}
Symbol::NUM_U32 | Symbol::NUM_UNSIGNED32 | Symbol::NUM_AT_UNSIGNED32 => {
Some(IntWidth::U32)
}
Symbol::NUM_U16 | Symbol::NUM_UNSIGNED16 | Symbol::NUM_AT_UNSIGNED16 => {
Some(IntWidth::U16)
}
Symbol::NUM_U8 | Symbol::NUM_UNSIGNED8 | Symbol::NUM_AT_UNSIGNED8 => Some(IntWidth::U8),
_ => None,
}
}
}
impl Index<DecWidth> for IntrinsicName { impl Index<DecWidth> for IntrinsicName {
type Output = str; type Output = str;

View file

@ -410,7 +410,7 @@ where
"Eq: expected all arguments of to have the same layout" "Eq: expected all arguments of to have the same layout"
); );
debug_assert_eq!( debug_assert_eq!(
Layout::Builtin(Builtin::Int1), Layout::Builtin(Builtin::Bool),
*ret_layout, *ret_layout,
"Eq: expected to have return layout of type I1" "Eq: expected to have return layout of type I1"
); );
@ -427,7 +427,7 @@ where
"NotEq: expected all arguments of to have the same layout" "NotEq: expected all arguments of to have the same layout"
); );
debug_assert_eq!( debug_assert_eq!(
Layout::Builtin(Builtin::Int1), Layout::Builtin(Builtin::Bool),
*ret_layout, *ret_layout,
"NotEq: expected to have return layout of type I1" "NotEq: expected to have return layout of type I1"
); );

View file

@ -715,7 +715,7 @@ pub fn int_with_precision<'a, 'ctx, 'env>(
Builtin::Int32 => env.context.i32_type().const_int(value as u64, false), Builtin::Int32 => env.context.i32_type().const_int(value as u64, false),
Builtin::Int16 => env.context.i16_type().const_int(value as u64, false), Builtin::Int16 => env.context.i16_type().const_int(value as u64, false),
Builtin::Int8 => env.context.i8_type().const_int(value as u64, false), Builtin::Int8 => env.context.i8_type().const_int(value as u64, false),
Builtin::Int1 => env.context.bool_type().const_int(value as u64, false), Builtin::Bool => env.context.bool_type().const_int(value as u64, false),
_ => panic!("Invalid layout for int literal = {:?}", precision), _ => panic!("Invalid layout for int literal = {:?}", precision),
} }
} }
@ -3072,7 +3072,7 @@ fn build_switch_ir<'a, 'ctx, 'env>(
// Build the cases // Build the cases
let mut incoming = Vec::with_capacity_in(branches.len(), arena); let mut incoming = Vec::with_capacity_in(branches.len(), arena);
if let Layout::Builtin(Builtin::Int1) = cond_layout { if let Layout::Builtin(Builtin::Bool) = cond_layout {
match (branches, default_branch) { match (branches, default_branch) {
([(0, _, false_branch)], true_branch) | ([(1, _, true_branch)], false_branch) => { ([(0, _, false_branch)], true_branch) | ([(1, _, true_branch)], false_branch) => {
let then_block = context.append_basic_block(parent, "then_block"); let then_block = context.append_basic_block(parent, "then_block");
@ -5133,7 +5133,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
closure_layout, closure_layout,
function_owns_closure_data, function_owns_closure_data,
argument_layouts, argument_layouts,
Layout::Builtin(Builtin::Int1), Layout::Builtin(Builtin::Bool),
); );
list_any(env, roc_function_call, list, element_layout) list_any(env, roc_function_call, list, element_layout)
@ -5160,7 +5160,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
closure_layout, closure_layout,
function_owns_closure_data, function_owns_closure_data,
argument_layouts, argument_layouts,
Layout::Builtin(Builtin::Int1), Layout::Builtin(Builtin::Bool),
); );
list_all(env, roc_function_call, list, element_layout) list_all(env, roc_function_call, list, element_layout)
@ -5193,7 +5193,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
closure_layout, closure_layout,
function_owns_closure_data, function_owns_closure_data,
argument_layouts, argument_layouts,
Layout::Builtin(Builtin::Int1), Layout::Builtin(Builtin::Bool),
); );
list_find_unsafe(env, layout_ids, roc_function_call, list, element_layout) list_find_unsafe(env, layout_ids, roc_function_call, list, element_layout)
} }
@ -6101,7 +6101,7 @@ fn to_cc_type_builtin<'a, 'ctx, 'env>(
| Builtin::Int32 | Builtin::Int32
| Builtin::Int16 | Builtin::Int16
| Builtin::Int8 | Builtin::Int8
| Builtin::Int1 | Builtin::Bool
| Builtin::Usize | Builtin::Usize
| Builtin::Decimal | Builtin::Decimal
| Builtin::Float128 | Builtin::Float128

View file

@ -128,7 +128,7 @@ fn hash_builtin<'a, 'ctx, 'env>(
| Builtin::Int32 | Builtin::Int32
| Builtin::Int16 | Builtin::Int16
| Builtin::Int8 | Builtin::Int8
| Builtin::Int1 | Builtin::Bool
| Builtin::Float64 | Builtin::Float64
| Builtin::Float32 | Builtin::Float32
| Builtin::Float128 | Builtin::Float128

View file

@ -93,7 +93,7 @@ fn build_eq_builtin<'a, 'ctx, 'env>(
Builtin::Int32 => int_cmp(IntPredicate::EQ, "eq_i32"), Builtin::Int32 => int_cmp(IntPredicate::EQ, "eq_i32"),
Builtin::Int16 => int_cmp(IntPredicate::EQ, "eq_i16"), Builtin::Int16 => int_cmp(IntPredicate::EQ, "eq_i16"),
Builtin::Int8 => int_cmp(IntPredicate::EQ, "eq_i8"), Builtin::Int8 => int_cmp(IntPredicate::EQ, "eq_i8"),
Builtin::Int1 => int_cmp(IntPredicate::EQ, "eq_i1"), Builtin::Bool => int_cmp(IntPredicate::EQ, "eq_i1"),
Builtin::Usize => int_cmp(IntPredicate::EQ, "eq_usize"), Builtin::Usize => int_cmp(IntPredicate::EQ, "eq_usize"),
@ -236,7 +236,7 @@ fn build_neq_builtin<'a, 'ctx, 'env>(
Builtin::Int32 => int_cmp(IntPredicate::NE, "neq_i32"), Builtin::Int32 => int_cmp(IntPredicate::NE, "neq_i32"),
Builtin::Int16 => int_cmp(IntPredicate::NE, "neq_i16"), Builtin::Int16 => int_cmp(IntPredicate::NE, "neq_i16"),
Builtin::Int8 => int_cmp(IntPredicate::NE, "neq_i8"), Builtin::Int8 => int_cmp(IntPredicate::NE, "neq_i8"),
Builtin::Int1 => int_cmp(IntPredicate::NE, "neq_i1"), Builtin::Bool => int_cmp(IntPredicate::NE, "neq_i1"),
Builtin::Usize => int_cmp(IntPredicate::NE, "neq_usize"), Builtin::Usize => int_cmp(IntPredicate::NE, "neq_usize"),

View file

@ -151,7 +151,7 @@ pub fn basic_type_from_builtin<'a, 'ctx, 'env>(
Int32 => context.i32_type().as_basic_type_enum(), Int32 => context.i32_type().as_basic_type_enum(),
Int16 => context.i16_type().as_basic_type_enum(), Int16 => context.i16_type().as_basic_type_enum(),
Int8 => context.i8_type().as_basic_type_enum(), Int8 => context.i8_type().as_basic_type_enum(),
Int1 => context.bool_type().as_basic_type_enum(), Bool => context.bool_type().as_basic_type_enum(),
Usize => ptr_int(context, ptr_bytes).as_basic_type_enum(), Usize => ptr_int(context, ptr_bytes).as_basic_type_enum(),
Decimal => context.i128_type().as_basic_type_enum(), Decimal => context.i128_type().as_basic_type_enum(),
Float128 => context.f128_type().as_basic_type_enum(), Float128 => context.f128_type().as_basic_type_enum(),

View file

@ -328,7 +328,7 @@ impl<'a> WasmBackend<'a> {
self.start_block(BlockType::NoResult) self.start_block(BlockType::NoResult)
} }
let is_bool = matches!(cond_layout, Layout::Builtin(Builtin::Int1)); let is_bool = matches!(cond_layout, Layout::Builtin(Builtin::Bool));
let cond_type = WasmLayout::new(cond_layout).value_type(); let cond_type = WasmLayout::new(cond_layout).value_type();
// then, we jump whenever the value under scrutiny is equal to the value of a branch // then, we jump whenever the value under scrutiny is equal to the value of a branch

View file

@ -26,7 +26,7 @@ impl WasmLayout {
let alignment_bytes = layout.alignment_bytes(PTR_SIZE); let alignment_bytes = layout.alignment_bytes(PTR_SIZE);
match layout { match layout {
Layout::Builtin(Int32 | Int16 | Int8 | Int1 | Usize) => Self::Primitive(I32, size), Layout::Builtin(Int32 | Int16 | Int8 | Bool | Usize) => Self::Primitive(I32, size),
Layout::Builtin(Int64) => Self::Primitive(I64, size), Layout::Builtin(Int64) => Self::Primitive(I64, size),

View file

@ -15,6 +15,7 @@ roc_unify = { path = "../unify" }
roc_solve = { path = "../solve" } roc_solve = { path = "../solve" }
roc_std = { path = "../../roc_std" } roc_std = { path = "../../roc_std" }
roc_problem = { path = "../problem" } roc_problem = { path = "../problem" }
roc_builtins = { path = "../builtins" }
ven_pretty = { path = "../../vendor/pretty" } ven_pretty = { path = "../../vendor/pretty" }
morphic_lib = { path = "../../vendor/morphic_lib" } morphic_lib = { path = "../../vendor/morphic_lib" }
bumpalo = { version = "3.8.0", features = ["collections"] } bumpalo = { version = "3.8.0", features = ["collections"] }

View file

@ -590,7 +590,7 @@ impl<'a> ResultRepr<'a> {
err: tags[ERR_TAG_ID as usize][0], err: tags[ERR_TAG_ID as usize][0],
ok: tags[OK_TAG_ID as usize][0], ok: tags[OK_TAG_ID as usize][0],
}, },
Layout::Builtin(Builtin::Int1) => ResultRepr::Int1, Layout::Builtin(Builtin::Bool) => ResultRepr::Int1,
other => unreachable!("unexpected layout: {:?}", other), other => unreachable!("unexpected layout: {:?}", other),
} }
} }
@ -1086,7 +1086,7 @@ fn call_spec(
Ok(new_state) Ok(new_state)
}; };
let state_layout = Layout::Builtin(Builtin::Int1); let state_layout = Layout::Builtin(Builtin::Bool);
let state_type = layout_spec(builder, &state_layout)?; let state_type = layout_spec(builder, &state_layout)?;
let init_state = new_num(builder, block)?; let init_state = new_num(builder, block)?;
@ -1105,7 +1105,7 @@ fn call_spec(
Ok(new_state) Ok(new_state)
}; };
let state_layout = Layout::Builtin(Builtin::Int1); let state_layout = Layout::Builtin(Builtin::Bool);
let state_type = layout_spec(builder, &state_layout)?; let state_type = layout_spec(builder, &state_layout)?;
let init_state = new_num(builder, block)?; let init_state = new_num(builder, block)?;
@ -1116,7 +1116,7 @@ fn call_spec(
let list = env.symbols[xs]; let list = env.symbols[xs];
// ListFindUnsafe returns { value: v, found: Bool=Int1 } // ListFindUnsafe returns { value: v, found: Bool=Int1 }
let output_layouts = vec![arg_layouts[0], Layout::Builtin(Builtin::Int1)]; let output_layouts = vec![arg_layouts[0], Layout::Builtin(Builtin::Bool)];
let output_layout = Layout::Struct(&output_layouts); let output_layout = Layout::Struct(&output_layouts);
let output_type = layout_spec(builder, &output_layout)?; let output_type = layout_spec(builder, &output_layout)?;
@ -1718,8 +1718,8 @@ fn builtin_spec(
use Builtin::*; use Builtin::*;
match builtin { match builtin {
Int128 | Int64 | Int32 | Int16 | Int8 | Int1 | Usize => builder.add_tuple_type(&[]), Int(_) | Usize | Bool => builder.add_tuple_type(&[]),
Decimal | Float128 | Float64 | Float32 => builder.add_tuple_type(&[]), Decimal | Float(_) => builder.add_tuple_type(&[]),
Str | EmptyStr => str_type(builder), Str | EmptyStr => str_type(builder),
Dict(key_layout, value_layout) => { Dict(key_layout, value_layout) => {
let value_type = layout_spec_help(builder, value_layout, when_recursive)?; let value_type = layout_spec_help(builder, value_layout, when_recursive)?;

View file

@ -1,9 +1,9 @@
use crate::exhaustive::{Ctor, RenderAs, TagId, Union}; use crate::exhaustive::{Ctor, RenderAs, TagId, Union};
use crate::ir::{ use crate::ir::{
BranchInfo, DestructType, Env, Expr, FloatPrecision, IntPrecision, JoinPointId, Literal, Param, BranchInfo, DestructType, Env, Expr, JoinPointId, Literal, Param, Pattern, Procs, Stmt,
Pattern, Procs, Stmt,
}; };
use crate::layout::{Builtin, Layout, LayoutCache, TagIdIntType, UnionLayout}; use crate::layout::{Builtin, Layout, LayoutCache, TagIdIntType, UnionLayout};
use roc_builtins::bitcode::{FloatWidth, IntWidth};
use roc_collections::all::{MutMap, MutSet}; use roc_collections::all::{MutMap, MutSet};
use roc_module::ident::TagName; use roc_module::ident::TagName;
use roc_module::low_level::LowLevel; use roc_module::low_level::LowLevel;
@ -86,8 +86,8 @@ enum Test<'a> {
union: crate::exhaustive::Union, union: crate::exhaustive::Union,
arguments: Vec<(Pattern<'a>, Layout<'a>)>, arguments: Vec<(Pattern<'a>, Layout<'a>)>,
}, },
IsInt(i128, IntPrecision), IsInt(i128, IntWidth),
IsFloat(u64, FloatPrecision), IsFloat(u64, FloatWidth),
IsDecimal(RocDec), IsDecimal(RocDec),
IsStr(Box<str>), IsStr(Box<str>),
IsBit(bool), IsBit(bool),
@ -1300,7 +1300,7 @@ fn test_to_equality<'a>(
debug_assert!(test_int <= i64::MAX as i128); debug_assert!(test_int <= i64::MAX as i128);
let lhs = Expr::Literal(Literal::Int(test_int as i128)); let lhs = Expr::Literal(Literal::Int(test_int as i128));
let lhs_symbol = env.unique_symbol(); let lhs_symbol = env.unique_symbol();
stores.push((lhs_symbol, precision.as_layout(), lhs)); stores.push((lhs_symbol, Layout::int_width(precision), lhs));
(stores, lhs_symbol, rhs_symbol, None) (stores, lhs_symbol, rhs_symbol, None)
} }
@ -1310,7 +1310,7 @@ fn test_to_equality<'a>(
let test_float = f64::from_bits(test_int as u64); let test_float = f64::from_bits(test_int as u64);
let lhs = Expr::Literal(Literal::Float(test_float)); let lhs = Expr::Literal(Literal::Float(test_float));
let lhs_symbol = env.unique_symbol(); let lhs_symbol = env.unique_symbol();
stores.push((lhs_symbol, precision.as_layout(), lhs)); stores.push((lhs_symbol, Layout::float_width(precision), lhs));
(stores, lhs_symbol, rhs_symbol, None) (stores, lhs_symbol, rhs_symbol, None)
} }
@ -1330,7 +1330,7 @@ fn test_to_equality<'a>(
let lhs = Expr::Literal(Literal::Byte(test_byte as u8)); let lhs = Expr::Literal(Literal::Byte(test_byte as u8));
let lhs_symbol = env.unique_symbol(); let lhs_symbol = env.unique_symbol();
stores.push((lhs_symbol, Layout::Builtin(Builtin::Int8), lhs)); stores.push((lhs_symbol, Layout::u8(), lhs));
(stores, lhs_symbol, rhs_symbol, None) (stores, lhs_symbol, rhs_symbol, None)
} }
@ -1338,7 +1338,7 @@ fn test_to_equality<'a>(
Test::IsBit(test_bit) => { Test::IsBit(test_bit) => {
let lhs = Expr::Literal(Literal::Bool(test_bit)); let lhs = Expr::Literal(Literal::Bool(test_bit));
let lhs_symbol = env.unique_symbol(); let lhs_symbol = env.unique_symbol();
stores.push((lhs_symbol, Layout::Builtin(Builtin::Int1), lhs)); stores.push((lhs_symbol, Layout::Builtin(Builtin::Bool), lhs));
(stores, lhs_symbol, rhs_symbol, None) (stores, lhs_symbol, rhs_symbol, None)
} }
@ -1459,7 +1459,7 @@ fn compile_test_help<'a>(
cond = Stmt::Switch { cond = Stmt::Switch {
cond_symbol: test_symbol, cond_symbol: test_symbol,
cond_layout: Layout::Builtin(Builtin::Int1), cond_layout: Layout::Builtin(Builtin::Bool),
ret_layout, ret_layout,
branches, branches,
default_branch, default_branch,
@ -1478,7 +1478,7 @@ fn compile_test_help<'a>(
cond = Stmt::Let( cond = Stmt::Let(
test_symbol, test_symbol,
test, test,
Layout::Builtin(Builtin::Int1), Layout::Builtin(Builtin::Bool),
arena.alloc(cond), arena.alloc(cond),
); );
@ -1622,7 +1622,7 @@ fn decide_to_branching<'a>(
let decide = crate::ir::cond( let decide = crate::ir::cond(
env, env,
test_symbol, test_symbol,
Layout::Builtin(Builtin::Int1), Layout::Builtin(Builtin::Bool),
pass_expr, pass_expr,
fail_expr, fail_expr,
ret_layout, ret_layout,
@ -1631,7 +1631,7 @@ fn decide_to_branching<'a>(
// calculate the guard value // calculate the guard value
let param = Param { let param = Param {
symbol: test_symbol, symbol: test_symbol,
layout: Layout::Builtin(Builtin::Int1), layout: Layout::Builtin(Builtin::Bool),
borrow: false, borrow: false,
}; };

View file

@ -7,6 +7,7 @@ use crate::layout::{
}; };
use bumpalo::collections::Vec; use bumpalo::collections::Vec;
use bumpalo::Bump; use bumpalo::Bump;
use roc_builtins::bitcode::{FloatWidth, IntWidth};
use roc_can::expr::ClosureData; use roc_can::expr::ClosureData;
use roc_collections::all::{default_hasher, BumpMap, BumpMapDefault, MutMap}; use roc_collections::all::{default_hasher, BumpMap, BumpMapDefault, MutMap};
use roc_module::ident::{ForeignSymbol, Lowercase, TagName}; use roc_module::ident::{ForeignSymbol, Lowercase, TagName};
@ -2424,11 +2425,11 @@ fn specialize_external<'a>(
} }
ClosureRepresentation::Other(layout) => match layout { ClosureRepresentation::Other(layout) => match layout {
Layout::Builtin(Builtin::Int1) => { Layout::Builtin(Builtin::Bool) => {
// just ignore this value // just ignore this value
// IDEA don't pass this value in the future // IDEA don't pass this value in the future
} }
Layout::Builtin(Builtin::Int8) => { Layout::Builtin(Builtin::Int(IntWidth::U8)) => {
// just ignore this value // just ignore this value
// IDEA don't pass this value in the future // IDEA don't pass this value in the future
} }
@ -2953,16 +2954,14 @@ fn try_make_literal<'a>(
match can_expr { match can_expr {
Int(_, precision, _, int) => { Int(_, precision, _, int) => {
match num_argument_to_int_or_float(env.subs, env.ptr_bytes, *precision, false) { match num_argument_to_int_or_float(env.subs, env.ptr_bytes, *precision, false) {
IntOrFloat::SignedIntType(_) | IntOrFloat::UnsignedIntType(_) => { IntOrFloat::Int(_) | IntOrFloat::Natural => Some(Literal::Int(*int)),
Some(Literal::Int(*int))
}
_ => unreachable!("unexpected float precision for integer"), _ => unreachable!("unexpected float precision for integer"),
} }
} }
Float(_, precision, float_str, float) => { Float(_, precision, float_str, float) => {
match num_argument_to_int_or_float(env.subs, env.ptr_bytes, *precision, true) { match num_argument_to_int_or_float(env.subs, env.ptr_bytes, *precision, true) {
IntOrFloat::BinaryFloatType(_) => Some(Literal::Float(*float)), IntOrFloat::Float(_) => Some(Literal::Float(*float)),
IntOrFloat::DecimalFloatType => { IntOrFloat::DecimalFloatType => {
let dec = match RocDec::from_str(float_str) { let dec = match RocDec::from_str(float_str) {
Some(d) => d, Some(d) => d,
@ -2980,10 +2979,8 @@ fn try_make_literal<'a>(
Num(var, num_str, num) => { Num(var, num_str, num) => {
// first figure out what kind of number this is // first figure out what kind of number this is
match num_argument_to_int_or_float(env.subs, env.ptr_bytes, *var, false) { match num_argument_to_int_or_float(env.subs, env.ptr_bytes, *var, false) {
IntOrFloat::SignedIntType(_) | IntOrFloat::UnsignedIntType(_) => { IntOrFloat::Int(_) | IntOrFloat::Natural => Some(Literal::Int((*num).into())),
Some(Literal::Int((*num).into())) IntOrFloat::Float(_) => Some(Literal::Float(*num as f64)),
}
IntOrFloat::BinaryFloatType(_) => Some(Literal::Float(*num as f64)),
IntOrFloat::DecimalFloatType => { IntOrFloat::DecimalFloatType => {
let dec = match RocDec::from_str(num_str) { let dec = match RocDec::from_str(num_str) {
Some(d) => d, Some(d) => d,
@ -3017,16 +3014,16 @@ pub fn with_hole<'a>(
match can_expr { match can_expr {
Int(_, precision, _, int) => { Int(_, precision, _, int) => {
match num_argument_to_int_or_float(env.subs, env.ptr_bytes, precision, false) { match num_argument_to_int_or_float(env.subs, env.ptr_bytes, precision, false) {
IntOrFloat::SignedIntType(precision) => Stmt::Let( IntOrFloat::Int(precision) => Stmt::Let(
assigned, assigned,
Expr::Literal(Literal::Int(int)), Expr::Literal(Literal::Int(int)),
precision.as_layout(), Layout::Builtin(Builtin::Int(precision)),
hole, hole,
), ),
IntOrFloat::UnsignedIntType(precision) => Stmt::Let( IntOrFloat::Natural => Stmt::Let(
assigned, assigned,
Expr::Literal(Literal::Int(int)), Expr::Literal(Literal::Int(int)),
precision.as_layout(), Layout::usize(),
hole, hole,
), ),
_ => unreachable!("unexpected float precision for integer"), _ => unreachable!("unexpected float precision for integer"),
@ -3035,10 +3032,10 @@ pub fn with_hole<'a>(
Float(_, precision, float_str, float) => { Float(_, precision, float_str, float) => {
match num_argument_to_int_or_float(env.subs, env.ptr_bytes, precision, true) { match num_argument_to_int_or_float(env.subs, env.ptr_bytes, precision, true) {
IntOrFloat::BinaryFloatType(precision) => Stmt::Let( IntOrFloat::Float(precision) => Stmt::Let(
assigned, assigned,
Expr::Literal(Literal::Float(float)), Expr::Literal(Literal::Float(float)),
precision.as_layout(), Layout::Builtin(Builtin::Float(precision)),
hole, hole,
), ),
IntOrFloat::DecimalFloatType => { IntOrFloat::DecimalFloatType => {
@ -3067,22 +3064,22 @@ pub fn with_hole<'a>(
Num(var, num_str, num) => { Num(var, num_str, num) => {
// first figure out what kind of number this is // first figure out what kind of number this is
match num_argument_to_int_or_float(env.subs, env.ptr_bytes, var, false) { match num_argument_to_int_or_float(env.subs, env.ptr_bytes, var, false) {
IntOrFloat::SignedIntType(precision) => Stmt::Let( IntOrFloat::Int(precision) => Stmt::Let(
assigned, assigned,
Expr::Literal(Literal::Int(num.into())), Expr::Literal(Literal::Int(num.into())),
precision.as_layout(), Layout::int_width(precision),
hole, hole,
), ),
IntOrFloat::UnsignedIntType(precision) => Stmt::Let( IntOrFloat::Natural => Stmt::Let(
assigned, assigned,
Expr::Literal(Literal::Int(num.into())), Expr::Literal(Literal::Int(num.into())),
precision.as_layout(), Layout::usize(),
hole, hole,
), ),
IntOrFloat::BinaryFloatType(precision) => Stmt::Let( IntOrFloat::Float(precision) => Stmt::Let(
assigned, assigned,
Expr::Literal(Literal::Float(num as f64)), Expr::Literal(Literal::Float(num as f64)),
precision.as_layout(), Layout::float_width(precision),
hole, hole,
), ),
IntOrFloat::DecimalFloatType => { IntOrFloat::DecimalFloatType => {
@ -4467,7 +4464,7 @@ fn construct_closure_data<'a>(
Stmt::Let(assigned, expr, lambda_set_layout, hole) Stmt::Let(assigned, expr, lambda_set_layout, hole)
} }
ClosureRepresentation::Other(Layout::Builtin(Builtin::Int1)) => { ClosureRepresentation::Other(Layout::Builtin(Builtin::Bool)) => {
debug_assert_eq!(symbols.len(), 0); debug_assert_eq!(symbols.len(), 0);
debug_assert_eq!(lambda_set.set.len(), 2); debug_assert_eq!(lambda_set.set.len(), 2);
@ -4476,7 +4473,7 @@ fn construct_closure_data<'a>(
Stmt::Let(assigned, expr, lambda_set_layout, hole) Stmt::Let(assigned, expr, lambda_set_layout, hole)
} }
ClosureRepresentation::Other(Layout::Builtin(Builtin::Int8)) => { ClosureRepresentation::Other(Layout::Builtin(Builtin::Int(IntWidth::U8))) => {
debug_assert_eq!(symbols.len(), 0); debug_assert_eq!(symbols.len(), 0);
debug_assert!(lambda_set.set.len() > 2); debug_assert!(lambda_set.set.len() > 2);
@ -4533,7 +4530,7 @@ fn convert_tag_union<'a>(
BoolUnion { ttrue, .. } => Stmt::Let( BoolUnion { ttrue, .. } => Stmt::Let(
assigned, assigned,
Expr::Literal(Literal::Bool(tag_name == ttrue)), Expr::Literal(Literal::Bool(tag_name == ttrue)),
Layout::Builtin(Builtin::Int1), Layout::Builtin(Builtin::Bool),
hole, hole,
), ),
ByteUnion(tag_names) => { ByteUnion(tag_names) => {
@ -4543,7 +4540,7 @@ fn convert_tag_union<'a>(
Some(tag_id) => Stmt::Let( Some(tag_id) => Stmt::Let(
assigned, assigned,
Expr::Literal(Literal::Byte(tag_id as u8)), Expr::Literal(Literal::Byte(tag_id as u8)),
Layout::Builtin(Builtin::Int8), Layout::Builtin(Builtin::Int(IntWidth::U8)),
hole, hole,
), ),
None => Stmt::RuntimeError("tag must be in its own type"), None => Stmt::RuntimeError("tag must be in its own type"),
@ -5054,7 +5051,7 @@ pub fn from_can<'a>(
Expect(condition, rest) => { Expect(condition, rest) => {
let rest = from_can(env, variable, rest.value, procs, layout_cache); let rest = from_can(env, variable, rest.value, procs, layout_cache);
let bool_layout = Layout::Builtin(Builtin::Int1); let bool_layout = Layout::Builtin(Builtin::Bool);
let cond_symbol = env.unique_symbol(); let cond_symbol = env.unique_symbol();
let op = LowLevel::ExpectTrue; let op = LowLevel::ExpectTrue;
@ -7237,8 +7234,8 @@ fn call_specialized_proc<'a>(
pub enum Pattern<'a> { pub enum Pattern<'a> {
Identifier(Symbol), Identifier(Symbol),
Underscore, Underscore,
IntLiteral(i128, IntPrecision), IntLiteral(i128, IntWidth),
FloatLiteral(u64, FloatPrecision), FloatLiteral(u64, FloatWidth),
DecimalLiteral(RocDec), DecimalLiteral(RocDec),
BitLiteral { BitLiteral {
value: bool, value: bool,
@ -7318,9 +7315,8 @@ fn from_can_pattern_help<'a>(
Identifier(symbol) => Ok(Pattern::Identifier(*symbol)), Identifier(symbol) => Ok(Pattern::Identifier(*symbol)),
IntLiteral(var, _, int) => { IntLiteral(var, _, int) => {
match num_argument_to_int_or_float(env.subs, env.ptr_bytes, *var, false) { match num_argument_to_int_or_float(env.subs, env.ptr_bytes, *var, false) {
IntOrFloat::SignedIntType(precision) | IntOrFloat::UnsignedIntType(precision) => { IntOrFloat::Natural => todo!(),
Ok(Pattern::IntLiteral(*int as i128, precision)) IntOrFloat::Int(precision) => Ok(Pattern::IntLiteral(*int as i128, precision)),
}
other => { other => {
panic!( panic!(
"Invalid precision for int pattern: {:?} has {:?}", "Invalid precision for int pattern: {:?} has {:?}",
@ -7332,10 +7328,10 @@ fn from_can_pattern_help<'a>(
FloatLiteral(var, float_str, float) => { FloatLiteral(var, float_str, float) => {
// TODO: Can I reuse num_argument_to_int_or_float here if I pass in true? // TODO: Can I reuse num_argument_to_int_or_float here if I pass in true?
match num_argument_to_int_or_float(env.subs, env.ptr_bytes, *var, true) { match num_argument_to_int_or_float(env.subs, env.ptr_bytes, *var, true) {
IntOrFloat::SignedIntType(_) | IntOrFloat::UnsignedIntType(_) => { IntOrFloat::Int(_) | IntOrFloat::Natural => {
panic!("Invalid precision for float pattern {:?}", var) panic!("Invalid precision for float pattern {:?}", var)
} }
IntOrFloat::BinaryFloatType(precision) => { IntOrFloat::Float(precision) => {
Ok(Pattern::FloatLiteral(f64::to_bits(*float), precision)) Ok(Pattern::FloatLiteral(f64::to_bits(*float), precision))
} }
IntOrFloat::DecimalFloatType => { IntOrFloat::DecimalFloatType => {
@ -7362,15 +7358,9 @@ fn from_can_pattern_help<'a>(
} }
NumLiteral(var, num_str, num) => { NumLiteral(var, num_str, num) => {
match num_argument_to_int_or_float(env.subs, env.ptr_bytes, *var, false) { match num_argument_to_int_or_float(env.subs, env.ptr_bytes, *var, false) {
IntOrFloat::SignedIntType(precision) => { IntOrFloat::Int(precision) => Ok(Pattern::IntLiteral(*num as i128, precision)),
Ok(Pattern::IntLiteral(*num as i128, precision)) IntOrFloat::Float(precision) => Ok(Pattern::FloatLiteral(*num as u64, precision)),
} IntOrFloat::Natural => todo!(),
IntOrFloat::UnsignedIntType(precision) => {
Ok(Pattern::IntLiteral(*num as i128, precision))
}
IntOrFloat::BinaryFloatType(precision) => {
Ok(Pattern::FloatLiteral(*num as u64, precision))
}
IntOrFloat::DecimalFloatType => { IntOrFloat::DecimalFloatType => {
let dec = match RocDec::from_str(num_str) { let dec = match RocDec::from_str(num_str) {
Some(d) => d, Some(d) => d,
@ -7952,60 +7942,12 @@ fn from_can_record_destruct<'a>(
}) })
} }
#[derive(Debug, Clone, Copy, PartialEq, Hash)]
pub enum IntPrecision {
Usize,
I128,
I64,
I32,
I16,
I8,
}
impl IntPrecision {
pub fn as_layout(&self) -> Layout<'static> {
Layout::Builtin(self.as_builtin())
}
pub fn as_builtin(&self) -> Builtin<'static> {
use IntPrecision::*;
match self {
I128 => Builtin::Int128,
I64 => Builtin::Int64,
I32 => Builtin::Int32,
I16 => Builtin::Int16,
I8 => Builtin::Int8,
Usize => Builtin::Usize,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Hash)]
pub enum FloatPrecision {
F64,
F32,
}
impl FloatPrecision {
pub fn as_layout(&self) -> Layout<'static> {
Layout::Builtin(self.as_builtin())
}
pub fn as_builtin(&self) -> Builtin<'static> {
use FloatPrecision::*;
match self {
F64 => Builtin::Float64,
F32 => Builtin::Float32,
}
}
}
#[derive(Debug)] #[derive(Debug)]
pub enum IntOrFloat { pub enum IntOrFloat {
SignedIntType(IntPrecision), Int(IntWidth),
UnsignedIntType(IntPrecision), Float(FloatWidth),
BinaryFloatType(FloatPrecision),
DecimalFloatType, DecimalFloatType,
Natural,
} }
/// Given the `a` in `Num a`, determines whether it's an int or a float /// Given the `a` in `Num a`, determines whether it's an int or a float
@ -8016,8 +7958,10 @@ pub fn num_argument_to_int_or_float(
known_to_be_float: bool, known_to_be_float: bool,
) -> IntOrFloat { ) -> IntOrFloat {
match subs.get_content_without_compacting(var) { match subs.get_content_without_compacting(var) {
Content::FlexVar(_) | Content::RigidVar(_) if known_to_be_float => IntOrFloat::BinaryFloatType(FloatPrecision::F64), Content::FlexVar(_) | Content::RigidVar(_) if known_to_be_float => {
Content::FlexVar(_) | Content::RigidVar(_) => IntOrFloat::SignedIntType(IntPrecision::I64), // We default (Num *) to I64 IntOrFloat::Float(FloatWidth::F64)
}
Content::FlexVar(_) | Content::RigidVar(_) => IntOrFloat::Int(IntWidth::I64), // We default (Num *) to I64
Content::Alias(Symbol::NUM_INTEGER, args, _) => { Content::Alias(Symbol::NUM_INTEGER, args, _) => {
debug_assert!(args.len() == 1); debug_assert!(args.len() == 1);
@ -8027,85 +7971,39 @@ pub fn num_argument_to_int_or_float(
num_argument_to_int_or_float(subs, ptr_bytes, var, false) num_argument_to_int_or_float(subs, ptr_bytes, var, false)
} }
Content::Alias(Symbol::NUM_I128, _, _) other @ Content::Alias(symbol, args, _) => {
| Content::Alias(Symbol::NUM_SIGNED128, _, _) if let Some(int_width) = IntWidth::try_from_symbol(*symbol) {
| Content::Alias(Symbol::NUM_AT_SIGNED128, _, _) => { return IntOrFloat::Int(int_width);
IntOrFloat::SignedIntType(IntPrecision::I128)
} }
Content::Alias(Symbol::NUM_INT, _, _)// We default Integer to I64
| Content::Alias(Symbol::NUM_I64, _, _) if let Some(float_width) = FloatWidth::try_from_symbol(*symbol) {
| Content::Alias(Symbol::NUM_SIGNED64, _, _) return IntOrFloat::Float(float_width);
| Content::Alias(Symbol::NUM_AT_SIGNED64, _, _) => {
IntOrFloat::SignedIntType(IntPrecision::I64)
} }
Content::Alias(Symbol::NUM_I32, _, _)
| Content::Alias(Symbol::NUM_SIGNED32, _, _) match *symbol {
| Content::Alias(Symbol::NUM_AT_SIGNED32, _, _) => { Symbol::NUM_FLOATINGPOINT => {
IntOrFloat::SignedIntType(IntPrecision::I32)
}
Content::Alias(Symbol::NUM_I16, _, _)
| Content::Alias(Symbol::NUM_SIGNED16, _, _)
| Content::Alias(Symbol::NUM_AT_SIGNED16, _, _) => {
IntOrFloat::SignedIntType(IntPrecision::I16)
}
Content::Alias(Symbol::NUM_I8, _, _)
| Content::Alias(Symbol::NUM_SIGNED8, _, _)
| Content::Alias(Symbol::NUM_AT_SIGNED8, _, _) => {
IntOrFloat::SignedIntType(IntPrecision::I8)
}
Content::Alias(Symbol::NUM_U128, _, _)
| Content::Alias(Symbol::NUM_UNSIGNED128, _, _)
| Content::Alias(Symbol::NUM_AT_UNSIGNED128, _, _) => {
IntOrFloat::UnsignedIntType(IntPrecision::I128)
}
Content::Alias(Symbol::NUM_U64, _, _)
| Content::Alias(Symbol::NUM_UNSIGNED64, _, _)
| Content::Alias(Symbol::NUM_AT_UNSIGNED64, _, _) => {
IntOrFloat::UnsignedIntType(IntPrecision::I64)
}
Content::Alias(Symbol::NUM_U32, _, _)
| Content::Alias(Symbol::NUM_UNSIGNED32, _, _)
| Content::Alias(Symbol::NUM_AT_UNSIGNED32, _, _) => {
IntOrFloat::UnsignedIntType(IntPrecision::I32)
}
Content::Alias(Symbol::NUM_U16, _, _)
| Content::Alias(Symbol::NUM_UNSIGNED16, _, _)
| Content::Alias(Symbol::NUM_AT_UNSIGNED16, _, _) => {
IntOrFloat::UnsignedIntType(IntPrecision::I16)
}
Content::Alias(Symbol::NUM_U8, _, _)
| Content::Alias(Symbol::NUM_UNSIGNED8, _, _)
| Content::Alias(Symbol::NUM_AT_UNSIGNED8, _, _) => {
IntOrFloat::UnsignedIntType(IntPrecision::I8)
}
Content::Alias(Symbol::NUM_FLOATINGPOINT, args, _) => {
debug_assert!(args.len() == 1); debug_assert!(args.len() == 1);
// Recurse on the second argument // Recurse on the second argument
let var = subs[args.variables().into_iter().next().unwrap()]; let var = subs[args.variables().into_iter().next().unwrap()];
num_argument_to_int_or_float(subs, ptr_bytes, var, true) num_argument_to_int_or_float(subs, ptr_bytes, var, true)
} }
Content::Alias(Symbol::NUM_FLOAT, _, _) // We default FloatingPoint to F64
| Content::Alias(Symbol::NUM_F64, _, _)
| Content::Alias(Symbol::NUM_BINARY64, _, _)
| Content::Alias(Symbol::NUM_AT_BINARY64, _, _) => {
IntOrFloat::BinaryFloatType(FloatPrecision::F64)
}
Content::Alias(Symbol::NUM_DECIMAL, _, _)
| Content::Alias(Symbol::NUM_AT_DECIMAL, _, _) => {
IntOrFloat::DecimalFloatType
}
Content::Alias(Symbol::NUM_F32, _, _)
| Content::Alias(Symbol::NUM_BINARY32, _, _)
| Content::Alias(Symbol::NUM_AT_BINARY32, _, _) => {
IntOrFloat::BinaryFloatType(FloatPrecision::F32)
}
Content::Alias(Symbol::NUM_NAT, _, _)
| Content::Alias(Symbol::NUM_NATURAL, _, _)
| Content::Alias(Symbol::NUM_AT_NATURAL, _, _) => {
IntOrFloat::UnsignedIntType(IntPrecision::Usize)
Symbol::NUM_DECIMAL | Symbol::NUM_AT_DECIMAL => {
return IntOrFloat::DecimalFloatType;
} }
Symbol::NUM_NAT | Symbol::NUM_NATURAL | Symbol::NUM_AT_NATURAL => {
return IntOrFloat::Natural;
}
_ => panic!(
"Unrecognized Num type argument for var {:?} with Content: {:?}",
var, other
),
}
}
other => { other => {
panic!( panic!(
"Unrecognized Num type argument for var {:?} with Content: {:?}", "Unrecognized Num type argument for var {:?} with Content: {:?}",
@ -8187,14 +8085,14 @@ where
hole.clone() hole.clone()
} }
}, },
Layout::Builtin(Builtin::Int1) => { Layout::Builtin(Builtin::Bool) => {
let closure_tag_id_symbol = closure_data_symbol; let closure_tag_id_symbol = closure_data_symbol;
lowlevel_enum_lambda_set_to_switch( lowlevel_enum_lambda_set_to_switch(
env, env,
lambda_set.set, lambda_set.set,
closure_tag_id_symbol, closure_tag_id_symbol,
Layout::Builtin(Builtin::Int1), Layout::Builtin(Builtin::Bool),
closure_data_symbol, closure_data_symbol,
lambda_set.is_represented(), lambda_set.is_represented(),
to_lowlevel_call, to_lowlevel_call,
@ -8203,14 +8101,14 @@ where
hole, hole,
) )
} }
Layout::Builtin(Builtin::Int8) => { Layout::Builtin(Builtin::Int(IntWidth::U8)) => {
let closure_tag_id_symbol = closure_data_symbol; let closure_tag_id_symbol = closure_data_symbol;
lowlevel_enum_lambda_set_to_switch( lowlevel_enum_lambda_set_to_switch(
env, env,
lambda_set.set, lambda_set.set,
closure_tag_id_symbol, closure_tag_id_symbol,
Layout::Builtin(Builtin::Int8), Layout::Builtin(Builtin::Int(IntWidth::U8)),
closure_data_symbol, closure_data_symbol,
lambda_set.is_represented(), lambda_set.is_represented(),
to_lowlevel_call, to_lowlevel_call,
@ -8351,14 +8249,14 @@ fn match_on_lambda_set<'a>(
hole, hole,
) )
} }
Layout::Builtin(Builtin::Int1) => { Layout::Builtin(Builtin::Bool) => {
let closure_tag_id_symbol = closure_data_symbol; let closure_tag_id_symbol = closure_data_symbol;
enum_lambda_set_to_switch( enum_lambda_set_to_switch(
env, env,
lambda_set.set, lambda_set.set,
closure_tag_id_symbol, closure_tag_id_symbol,
Layout::Builtin(Builtin::Int1), Layout::Builtin(Builtin::Bool),
closure_data_symbol, closure_data_symbol,
argument_symbols, argument_symbols,
argument_layouts, argument_layouts,
@ -8367,14 +8265,14 @@ fn match_on_lambda_set<'a>(
hole, hole,
) )
} }
Layout::Builtin(Builtin::Int8) => { Layout::Builtin(Builtin::Int(IntWidth::U8)) => {
let closure_tag_id_symbol = closure_data_symbol; let closure_tag_id_symbol = closure_data_symbol;
enum_lambda_set_to_switch( enum_lambda_set_to_switch(
env, env,
lambda_set.set, lambda_set.set,
closure_tag_id_symbol, closure_tag_id_symbol,
Layout::Builtin(Builtin::Int8), Layout::Builtin(Builtin::Int(IntWidth::U8)),
closure_data_symbol, closure_data_symbol,
argument_symbols, argument_symbols,
argument_layouts, argument_layouts,
@ -8502,7 +8400,9 @@ fn union_lambda_set_branch_help<'a>(
hole: &'a Stmt<'a>, hole: &'a Stmt<'a>,
) -> Stmt<'a> { ) -> Stmt<'a> {
let (argument_layouts, argument_symbols) = match closure_data_layout { let (argument_layouts, argument_symbols) = match closure_data_layout {
Layout::Struct(&[]) | Layout::Builtin(Builtin::Int1) | Layout::Builtin(Builtin::Int8) => { Layout::Struct(&[])
| Layout::Builtin(Builtin::Bool)
| Layout::Builtin(Builtin::Int(IntWidth::U8)) => {
(argument_layouts_slice, argument_symbols_slice) (argument_layouts_slice, argument_symbols_slice)
} }
_ if lambda_set.member_does_not_need_closure_argument(function_symbol) => { _ if lambda_set.member_does_not_need_closure_argument(function_symbol) => {
@ -8627,7 +8527,9 @@ fn enum_lambda_set_branch<'a>(
let assigned = result_symbol; let assigned = result_symbol;
let (argument_layouts, argument_symbols) = match closure_data_layout { let (argument_layouts, argument_symbols) = match closure_data_layout {
Layout::Struct(&[]) | Layout::Builtin(Builtin::Int1) | Layout::Builtin(Builtin::Int8) => { Layout::Struct(&[])
| Layout::Builtin(Builtin::Bool)
| Layout::Builtin(Builtin::Int(IntWidth::U8)) => {
(argument_layouts_slice, argument_symbols_slice) (argument_layouts_slice, argument_symbols_slice)
} }
_ => { _ => {

View file

@ -1,6 +1,7 @@
use crate::ir::Parens; use crate::ir::Parens;
use bumpalo::collections::Vec; use bumpalo::collections::Vec;
use bumpalo::Bump; use bumpalo::Bump;
use roc_builtins::bitcode::{FloatWidth, IntWidth};
use roc_collections::all::{default_hasher, MutMap}; use roc_collections::all::{default_hasher, MutMap};
use roc_module::ident::{Lowercase, TagName}; use roc_module::ident::{Lowercase, TagName};
use roc_module::symbol::{Interns, Symbol}; use roc_module::symbol::{Interns, Symbol};
@ -24,9 +25,6 @@ pub type TagIdIntType = u16;
pub const MAX_ENUM_SIZE: usize = (std::mem::size_of::<TagIdIntType>() * 8) as usize; pub const MAX_ENUM_SIZE: usize = (std::mem::size_of::<TagIdIntType>() * 8) as usize;
const GENERATE_NULLABLE: bool = true; const GENERATE_NULLABLE: bool = true;
/// If a (Num *) gets translated to a Layout, this is the numeric type it defaults to.
const DEFAULT_NUM_BUILTIN: Builtin<'_> = Builtin::Int64;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum LayoutProblem { pub enum LayoutProblem {
UnresolvedTypeVar(Variable), UnresolvedTypeVar(Variable),
@ -61,60 +59,61 @@ impl<'a> RawFunctionLayout<'a> {
// Ints // Ints
Alias(Symbol::NUM_I128, args, _) => { Alias(Symbol::NUM_I128, args, _) => {
debug_assert!(args.is_empty()); debug_assert!(args.is_empty());
Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Int128))) Ok(Self::ZeroArgumentThunk(Layout::i128()))
} }
Alias(Symbol::NUM_I64, args, _) => { Alias(Symbol::NUM_I64, args, _) => {
debug_assert!(args.is_empty()); debug_assert!(args.is_empty());
Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Int64))) Ok(Self::ZeroArgumentThunk(Layout::i64()))
} }
Alias(Symbol::NUM_I32, args, _) => { Alias(Symbol::NUM_I32, args, _) => {
debug_assert!(args.is_empty()); debug_assert!(args.is_empty());
Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Int32))) Ok(Self::ZeroArgumentThunk(Layout::i32()))
} }
Alias(Symbol::NUM_I16, args, _) => { Alias(Symbol::NUM_I16, args, _) => {
debug_assert!(args.is_empty()); debug_assert!(args.is_empty());
Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Int16))) Ok(Self::ZeroArgumentThunk(Layout::i16()))
} }
Alias(Symbol::NUM_I8, args, _) => { Alias(Symbol::NUM_I8, args, _) => {
debug_assert!(args.is_empty()); debug_assert!(args.is_empty());
Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Int8))) Ok(Self::ZeroArgumentThunk(Layout::i8()))
} }
// I think unsigned and signed use the same layout // I think unsigned and signed use the same layout
Alias(Symbol::NUM_U128, args, _) => { Alias(Symbol::NUM_U128, args, _) => {
debug_assert!(args.is_empty()); debug_assert!(args.is_empty());
Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Int128))) Ok(Self::ZeroArgumentThunk(Layout::u128()))
} }
Alias(Symbol::NUM_U64, args, _) => { Alias(Symbol::NUM_U64, args, _) => {
debug_assert!(args.is_empty()); debug_assert!(args.is_empty());
Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Int64))) Ok(Self::ZeroArgumentThunk(Layout::u64()))
} }
Alias(Symbol::NUM_U32, args, _) => { Alias(Symbol::NUM_U32, args, _) => {
debug_assert!(args.is_empty()); debug_assert!(args.is_empty());
Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Int32))) Ok(Self::ZeroArgumentThunk(Layout::u32()))
} }
Alias(Symbol::NUM_U16, args, _) => { Alias(Symbol::NUM_U16, args, _) => {
debug_assert!(args.is_empty()); debug_assert!(args.is_empty());
Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Int16))) Ok(Self::ZeroArgumentThunk(Layout::u16()))
} }
Alias(Symbol::NUM_U8, args, _) => { Alias(Symbol::NUM_U8, args, _) => {
debug_assert!(args.is_empty()); debug_assert!(args.is_empty());
Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Int8))) Ok(Self::ZeroArgumentThunk(Layout::u8()))
}
Alias(Symbol::NUM_NAT, args, _) => {
debug_assert!(args.is_empty());
Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Usize)))
} }
// Floats // Floats
Alias(Symbol::NUM_F64, args, _) => { Alias(Symbol::NUM_F64, args, _) => {
debug_assert!(args.is_empty()); debug_assert!(args.is_empty());
Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Float64))) Ok(Self::ZeroArgumentThunk(Layout::f64()))
} }
Alias(Symbol::NUM_F32, args, _) => { Alias(Symbol::NUM_F32, args, _) => {
debug_assert!(args.is_empty()); debug_assert!(args.is_empty());
Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Float32))) Ok(Self::ZeroArgumentThunk(Layout::f32()))
}
// Nat
Alias(Symbol::NUM_NAT, args, _) => {
debug_assert!(args.is_empty());
Ok(Self::ZeroArgumentThunk(Layout::usize()))
} }
Alias(symbol, _, _) if symbol.is_builtin() => Ok(Self::ZeroArgumentThunk( Alias(symbol, _, _) if symbol.is_builtin() => Ok(Self::ZeroArgumentThunk(
@ -315,9 +314,9 @@ impl<'a> UnionLayout<'a> {
fn tag_id_builtin_help(union_size: usize) -> Builtin<'a> { fn tag_id_builtin_help(union_size: usize) -> Builtin<'a> {
if union_size <= u8::MAX as usize { if union_size <= u8::MAX as usize {
Builtin::Int8 Builtin::Int(IntWidth::U8)
} else if union_size <= u16::MAX as usize { } else if union_size <= u16::MAX as usize {
Builtin::Int16 Builtin::Int(IntWidth::U16)
} else { } else {
panic!("tag union is too big") panic!("tag union is too big")
} }
@ -332,7 +331,7 @@ impl<'a> UnionLayout<'a> {
// The quicksort-benchmarks version of Quicksort.roc segfaults when // The quicksort-benchmarks version of Quicksort.roc segfaults when
// this number is not I64. There must be some dependence on that fact // this number is not I64. There must be some dependence on that fact
// somewhere in the code, I have not found where that is yet... // somewhere in the code, I have not found where that is yet...
Builtin::Int64 Builtin::Int(IntWidth::U64)
} }
UnionLayout::Recursive(tags) => { UnionLayout::Recursive(tags) => {
let union_size = tags.len(); let union_size = tags.len();
@ -343,8 +342,8 @@ impl<'a> UnionLayout<'a> {
UnionLayout::NullableWrapped { other_tags, .. } => { UnionLayout::NullableWrapped { other_tags, .. } => {
Self::tag_id_builtin_help(other_tags.len() + 1) Self::tag_id_builtin_help(other_tags.len() + 1)
} }
UnionLayout::NonNullableUnwrapped(_) => Builtin::Int1, UnionLayout::NonNullableUnwrapped(_) => Builtin::Bool,
UnionLayout::NullableUnwrapped { .. } => Builtin::Int1, UnionLayout::NullableUnwrapped { .. } => Builtin::Bool,
} }
} }
@ -546,7 +545,8 @@ impl<'a> LambdaSet<'a> {
// singleton, so we pass no extra argument // singleton, so we pass no extra argument
argument_layouts argument_layouts
} }
Layout::Builtin(Builtin::Int1) | Layout::Builtin(Builtin::Int8) => { Layout::Builtin(Builtin::Bool)
| Layout::Builtin(Builtin::Int(IntWidth::I8 | IntWidth::U8)) => {
// we don't pass this along either // we don't pass this along either
argument_layouts argument_layouts
} }
@ -628,8 +628,8 @@ impl<'a> LambdaSet<'a> {
use UnionVariant::*; use UnionVariant::*;
match variant { match variant {
Never => Layout::Union(UnionLayout::NonRecursive(&[])), Never => Layout::Union(UnionLayout::NonRecursive(&[])),
BoolUnion { .. } => Layout::Builtin(Builtin::Int1), BoolUnion { .. } => Layout::bool(),
ByteUnion { .. } => Layout::Builtin(Builtin::Int8), ByteUnion { .. } => Layout::u8(),
Unit | UnitWithArguments => { Unit | UnitWithArguments => {
// no useful information to store // no useful information to store
Layout::Struct(&[]) Layout::Struct(&[])
@ -680,17 +680,11 @@ impl<'a> LambdaSet<'a> {
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum Builtin<'a> { pub enum Builtin<'a> {
Int128, Int(IntWidth),
Int64, Float(FloatWidth),
Int32, Bool,
Int16,
Int8,
Int1,
Usize, Usize,
Decimal, Decimal,
Float128,
Float64,
Float32,
Str, Str,
Dict(&'a Layout<'a>, &'a Layout<'a>), Dict(&'a Layout<'a>, &'a Layout<'a>),
Set(&'a Layout<'a>), Set(&'a Layout<'a>),
@ -759,61 +753,61 @@ impl<'a> Layout<'a> {
// Ints // Ints
Alias(Symbol::NUM_I128, args, _) => { Alias(Symbol::NUM_I128, args, _) => {
debug_assert!(args.is_empty()); debug_assert!(args.is_empty());
Ok(Layout::Builtin(Builtin::Int128)) Ok(Layout::i128())
} }
Alias(Symbol::NUM_I64, args, _) => { Alias(Symbol::NUM_I64, args, _) => {
debug_assert!(args.is_empty()); debug_assert!(args.is_empty());
Ok(Layout::Builtin(Builtin::Int64)) Ok(Layout::i64())
} }
Alias(Symbol::NUM_I32, args, _) => { Alias(Symbol::NUM_I32, args, _) => {
debug_assert!(args.is_empty()); debug_assert!(args.is_empty());
Ok(Layout::Builtin(Builtin::Int32)) Ok(Layout::i32())
} }
Alias(Symbol::NUM_I16, args, _) => { Alias(Symbol::NUM_I16, args, _) => {
debug_assert!(args.is_empty()); debug_assert!(args.is_empty());
Ok(Layout::Builtin(Builtin::Int16)) Ok(Layout::i16())
} }
Alias(Symbol::NUM_I8, args, _) => { Alias(Symbol::NUM_I8, args, _) => {
debug_assert!(args.is_empty()); debug_assert!(args.is_empty());
Ok(Layout::Builtin(Builtin::Int8)) Ok(Layout::i8())
} }
// I think unsigned and signed use the same layout // I think unsigned and signed use the same layout
Alias(Symbol::NUM_U128, args, _) => { Alias(Symbol::NUM_U128, args, _) => {
debug_assert!(args.is_empty()); debug_assert!(args.is_empty());
Ok(Layout::Builtin(Builtin::Int128)) Ok(Layout::u128())
} }
Alias(Symbol::NUM_U64, args, _) => { Alias(Symbol::NUM_U64, args, _) => {
debug_assert!(args.is_empty()); debug_assert!(args.is_empty());
Ok(Layout::Builtin(Builtin::Int64)) Ok(Layout::u64())
} }
Alias(Symbol::NUM_U32, args, _) => { Alias(Symbol::NUM_U32, args, _) => {
debug_assert!(args.is_empty()); debug_assert!(args.is_empty());
Ok(Layout::Builtin(Builtin::Int32)) Ok(Layout::u32())
} }
Alias(Symbol::NUM_U16, args, _) => { Alias(Symbol::NUM_U16, args, _) => {
debug_assert!(args.is_empty()); debug_assert!(args.is_empty());
Ok(Layout::Builtin(Builtin::Int16)) Ok(Layout::u16())
} }
Alias(Symbol::NUM_U8, args, _) => { Alias(Symbol::NUM_U8, args, _) => {
debug_assert!(args.is_empty()); debug_assert!(args.is_empty());
Ok(Layout::Builtin(Builtin::Int8)) Ok(Layout::u8())
} }
// Floats // Floats
Alias(Symbol::NUM_F64, args, _) => { Alias(Symbol::NUM_F64, args, _) => {
debug_assert!(args.is_empty()); debug_assert!(args.is_empty());
Ok(Layout::Builtin(Builtin::Float64)) Ok(Layout::f64())
} }
Alias(Symbol::NUM_F32, args, _) => { Alias(Symbol::NUM_F32, args, _) => {
debug_assert!(args.is_empty()); debug_assert!(args.is_empty());
Ok(Layout::Builtin(Builtin::Float32)) Ok(Layout::f32())
} }
// Nat // Nat
Alias(Symbol::NUM_NAT, args, _) => { Alias(Symbol::NUM_NAT, args, _) => {
debug_assert!(args.is_empty()); debug_assert!(args.is_empty());
Ok(Layout::Builtin(Builtin::Usize)) Ok(Layout::usize())
} }
Alias(_, _, var) => Self::from_var(env, var), Alias(_, _, var) => Self::from_var(env, var),
@ -1148,6 +1142,76 @@ impl<'a> LayoutCache<'a> {
// placeholder for the type ven_ena::unify::Snapshot<ven_ena::unify::InPlace<CachedVariable<'a>>> // placeholder for the type ven_ena::unify::Snapshot<ven_ena::unify::InPlace<CachedVariable<'a>>>
pub struct SnapshotKeyPlaceholder; pub struct SnapshotKeyPlaceholder;
impl<'a> Layout<'a> {
pub fn int_width(width: IntWidth) -> Layout<'a> {
Layout::Builtin(Builtin::Int(width))
}
pub fn float_width(width: FloatWidth) -> Layout<'a> {
Layout::Builtin(Builtin::Float(width))
}
pub fn f64() -> Layout<'a> {
Layout::Builtin(Builtin::Float(FloatWidth::F64))
}
pub fn f32() -> Layout<'a> {
Layout::Builtin(Builtin::Float(FloatWidth::F32))
}
pub fn usize() -> Layout<'a> {
Layout::Builtin(Builtin::Usize)
}
pub fn bool() -> Layout<'a> {
Layout::Builtin(Builtin::Bool)
}
pub fn u8() -> Layout<'a> {
Layout::Builtin(Builtin::Int(IntWidth::U8))
}
pub fn u16() -> Layout<'a> {
Layout::Builtin(Builtin::Int(IntWidth::U16))
}
pub fn u32() -> Layout<'a> {
Layout::Builtin(Builtin::Int(IntWidth::U32))
}
pub fn u64() -> Layout<'a> {
Layout::Builtin(Builtin::Int(IntWidth::U64))
}
pub fn u128() -> Layout<'a> {
Layout::Builtin(Builtin::Int(IntWidth::U128))
}
pub fn i8() -> Layout<'a> {
Layout::Builtin(Builtin::Int(IntWidth::I8))
}
pub fn i16() -> Layout<'a> {
Layout::Builtin(Builtin::Int(IntWidth::I16))
}
pub fn i32() -> Layout<'a> {
Layout::Builtin(Builtin::Int(IntWidth::I32))
}
pub fn i64() -> Layout<'a> {
Layout::Builtin(Builtin::Int(IntWidth::I64))
}
pub fn i128() -> Layout<'a> {
Layout::Builtin(Builtin::Int(IntWidth::I128))
}
pub fn default_integer() -> Layout<'a> {
Layout::i64()
}
}
impl<'a> Builtin<'a> { impl<'a> Builtin<'a> {
const I128_SIZE: u32 = std::mem::size_of::<i128>() as u32; const I128_SIZE: u32 = std::mem::size_of::<i128>() as u32;
const I64_SIZE: u32 = std::mem::size_of::<i64>() as u32; const I64_SIZE: u32 = std::mem::size_of::<i64>() as u32;
@ -1177,17 +1241,11 @@ impl<'a> Builtin<'a> {
use Builtin::*; use Builtin::*;
match self { match self {
Int128 => Builtin::I128_SIZE, Int(int) => int.stack_size(),
Int64 => Builtin::I64_SIZE, Float(float) => float.stack_size(),
Int32 => Builtin::I32_SIZE, Bool => Builtin::I1_SIZE,
Int16 => Builtin::I16_SIZE,
Int8 => Builtin::I8_SIZE,
Int1 => Builtin::I1_SIZE,
Usize => pointer_size, Usize => pointer_size,
Decimal => Builtin::DECIMAL_SIZE, Decimal => Builtin::DECIMAL_SIZE,
Float128 => Builtin::F128_SIZE,
Float64 => Builtin::F64_SIZE,
Float32 => Builtin::F32_SIZE,
Str | EmptyStr => Builtin::STR_WORDS * pointer_size, Str | EmptyStr => Builtin::STR_WORDS * pointer_size,
Dict(_, _) | EmptyDict => Builtin::DICT_WORDS * pointer_size, Dict(_, _) | EmptyDict => Builtin::DICT_WORDS * pointer_size,
Set(_) | EmptySet => Builtin::SET_WORDS * pointer_size, Set(_) | EmptySet => Builtin::SET_WORDS * pointer_size,
@ -1203,17 +1261,11 @@ impl<'a> Builtin<'a> {
// since both of those are one pointer size, the alignment of that structure is a pointer // since both of those are one pointer size, the alignment of that structure is a pointer
// size // size
match self { match self {
Int128 => align_of::<i128>() as u32, Int(int_width) => int_width.alignment_bytes(),
Int64 => align_of::<i64>() as u32, Float(float_width) => float_width.alignment_bytes(),
Int32 => align_of::<i32>() as u32, Bool => align_of::<bool>() as u32,
Int16 => align_of::<i16>() as u32,
Int8 => align_of::<i8>() as u32,
Int1 => align_of::<bool>() as u32,
Usize => pointer_size, Usize => pointer_size,
Decimal => align_of::<i128>() as u32, Decimal => align_of::<i128>() as u32,
Float128 => align_of::<i128>() as u32,
Float64 => align_of::<f64>() as u32,
Float32 => align_of::<f32>() as u32,
Dict(_, _) | EmptyDict => pointer_size, Dict(_, _) | EmptyDict => pointer_size,
Set(_) | EmptySet => pointer_size, Set(_) | EmptySet => pointer_size,
// we often treat these as i128 (64-bit systems) // we often treat these as i128 (64-bit systems)
@ -1230,8 +1282,9 @@ impl<'a> Builtin<'a> {
use Builtin::*; use Builtin::*;
match self { match self {
Int128 | Int64 | Int32 | Int16 | Int8 | Int1 | Usize | Decimal | Float128 | Float64 Int(_) | Usize | Float(_) | Bool | Decimal | EmptyStr | EmptyDict | EmptyList
| Float32 | EmptyStr | EmptyDict | EmptyList | EmptySet => true, | EmptySet => true,
Str | Dict(_, _) | Set(_) | List(_) => false, Str | Dict(_, _) | Set(_) | List(_) => false,
} }
} }
@ -1241,8 +1294,8 @@ impl<'a> Builtin<'a> {
use Builtin::*; use Builtin::*;
match self { match self {
Int128 | Int64 | Int32 | Int16 | Int8 | Int1 | Usize | Decimal | Float128 | Float64 Int(_) | Usize | Float(_) | Bool | Decimal | EmptyStr | EmptyDict | EmptyList
| Float32 | EmptyStr | EmptyDict | EmptyList | EmptySet => false, | EmptySet => false,
List(_) => true, List(_) => true,
Str | Dict(_, _) | Set(_) => true, Str | Dict(_, _) | Set(_) => true,
@ -1258,17 +1311,36 @@ impl<'a> Builtin<'a> {
use Builtin::*; use Builtin::*;
match self { match self {
Int128 => alloc.text("Int128"), Int(int_width) => {
Int64 => alloc.text("Int64"), use IntWidth::*;
Int32 => alloc.text("Int32"),
Int16 => alloc.text("Int16"), match int_width {
Int8 => alloc.text("Int8"), I128 => alloc.text("I128"),
Int1 => alloc.text("Int1"), I64 => alloc.text("I64"),
I32 => alloc.text("I32"),
I16 => alloc.text("I16"),
I8 => alloc.text("I8"),
U128 => alloc.text("U128"),
U64 => alloc.text("U64"),
U32 => alloc.text("U32"),
U16 => alloc.text("U16"),
U8 => alloc.text("U8"),
}
}
Float(float_width) => {
use FloatWidth::*;
match float_width {
F128 => alloc.text("Float128"),
F64 => alloc.text("Float64"),
F32 => alloc.text("Float32"),
}
}
Bool => alloc.text("Int1"),
Usize => alloc.text("Usize"), Usize => alloc.text("Usize"),
Decimal => alloc.text("Decimal"), Decimal => alloc.text("Decimal"),
Float128 => alloc.text("Float128"),
Float64 => alloc.text("Float64"),
Float32 => alloc.text("Float32"),
EmptyStr => alloc.text("EmptyStr"), EmptyStr => alloc.text("EmptyStr"),
EmptyList => alloc.text("EmptyList"), EmptyList => alloc.text("EmptyList"),
@ -1292,17 +1364,11 @@ impl<'a> Builtin<'a> {
pub fn allocation_alignment_bytes(&self, pointer_size: u32) -> u32 { pub fn allocation_alignment_bytes(&self, pointer_size: u32) -> u32 {
let allocation = match self { let allocation = match self {
Builtin::Int128 Builtin::Int(_)
| Builtin::Int64 | Builtin::Float(_)
| Builtin::Int32 | Builtin::Bool
| Builtin::Int16
| Builtin::Int8
| Builtin::Int1
| Builtin::Usize | Builtin::Usize
| Builtin::Decimal | Builtin::Decimal => unreachable!("not heap-allocated"),
| Builtin::Float128
| Builtin::Float64
| Builtin::Float32 => unreachable!("not heap-allocated"),
Builtin::Str => pointer_size, Builtin::Str => pointer_size,
Builtin::Dict(k, v) => k Builtin::Dict(k, v) => k
.alignment_bytes(pointer_size) .alignment_bytes(pointer_size)
@ -1342,44 +1408,44 @@ fn layout_from_flat_type<'a>(
Symbol::NUM_I128 => { Symbol::NUM_I128 => {
debug_assert_eq!(args.len(), 0); debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Int128)) Ok(Layout::i128())
} }
Symbol::NUM_I64 => { Symbol::NUM_I64 => {
debug_assert_eq!(args.len(), 0); debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Int64)) Ok(Layout::i64())
} }
Symbol::NUM_I32 => { Symbol::NUM_I32 => {
debug_assert_eq!(args.len(), 0); debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Int32)) Ok(Layout::i32())
} }
Symbol::NUM_I16 => { Symbol::NUM_I16 => {
debug_assert_eq!(args.len(), 0); debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Int16)) Ok(Layout::i16())
} }
Symbol::NUM_I8 => { Symbol::NUM_I8 => {
debug_assert_eq!(args.len(), 0); debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Int8)) Ok(Layout::i8())
} }
Symbol::NUM_U128 => { Symbol::NUM_U128 => {
debug_assert_eq!(args.len(), 0); debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Int128)) Ok(Layout::u128())
} }
Symbol::NUM_U64 => { Symbol::NUM_U64 => {
debug_assert_eq!(args.len(), 0); debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Int64)) Ok(Layout::u64())
} }
Symbol::NUM_U32 => { Symbol::NUM_U32 => {
debug_assert_eq!(args.len(), 0); debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Int32)) Ok(Layout::u32())
} }
Symbol::NUM_U16 => { Symbol::NUM_U16 => {
debug_assert_eq!(args.len(), 0); debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Int16)) Ok(Layout::u16())
} }
Symbol::NUM_U8 => { Symbol::NUM_U8 => {
debug_assert_eq!(args.len(), 0); debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Int8)) Ok(Layout::u8())
} }
// Floats // Floats
@ -1389,11 +1455,11 @@ fn layout_from_flat_type<'a>(
} }
Symbol::NUM_F64 => { Symbol::NUM_F64 => {
debug_assert_eq!(args.len(), 0); debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Float64)) Ok(Layout::f64())
} }
Symbol::NUM_F32 => { Symbol::NUM_F32 => {
debug_assert_eq!(args.len(), 0); debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Float32)) Ok(Layout::f32())
} }
Symbol::NUM_NUM | Symbol::NUM_AT_NUM => { Symbol::NUM_NUM | Symbol::NUM_AT_NUM => {
@ -2295,8 +2361,8 @@ fn layout_from_tag_union<'a>(
match variant { match variant {
Never => Layout::Union(UnionLayout::NonRecursive(&[])), Never => Layout::Union(UnionLayout::NonRecursive(&[])),
Unit | UnitWithArguments => Layout::Struct(&[]), Unit | UnitWithArguments => Layout::Struct(&[]),
BoolUnion { .. } => Layout::Builtin(Builtin::Int1), BoolUnion { .. } => Layout::bool(),
ByteUnion(_) => Layout::Builtin(Builtin::Int8), ByteUnion(_) => Layout::u8(),
Newtype { Newtype {
arguments: field_layouts, arguments: field_layouts,
.. ..
@ -2396,30 +2462,32 @@ fn layout_from_num_content<'a>(content: &Content) -> Result<Layout<'a>, LayoutPr
// type variable, then assume it's a 64-bit integer. // type variable, then assume it's a 64-bit integer.
// //
// (e.g. for (5 + 5) assume both 5s are 64-bit integers.) // (e.g. for (5 + 5) assume both 5s are 64-bit integers.)
Ok(Layout::Builtin(DEFAULT_NUM_BUILTIN)) Ok(Layout::default_integer())
} }
Structure(Apply(symbol, args)) => match *symbol { Structure(Apply(symbol, args)) => match *symbol {
// Ints // Ints
Symbol::NUM_NAT => Ok(Layout::Builtin(Builtin::Usize)), Symbol::NUM_NAT => Ok(Layout::usize()),
Symbol::NUM_INTEGER => Ok(Layout::Builtin(Builtin::Int64)), Symbol::NUM_INTEGER => Ok(Layout::i64()),
Symbol::NUM_I128 => Ok(Layout::Builtin(Builtin::Int128)), Symbol::NUM_I128 => Ok(Layout::i128()),
Symbol::NUM_I64 => Ok(Layout::Builtin(Builtin::Int64)), Symbol::NUM_I64 => Ok(Layout::i64()),
Symbol::NUM_I32 => Ok(Layout::Builtin(Builtin::Int32)), Symbol::NUM_I32 => Ok(Layout::i32()),
Symbol::NUM_I16 => Ok(Layout::Builtin(Builtin::Int16)), Symbol::NUM_I16 => Ok(Layout::i16()),
Symbol::NUM_I8 => Ok(Layout::Builtin(Builtin::Int8)), Symbol::NUM_I8 => Ok(Layout::i8()),
Symbol::NUM_U128 => Ok(Layout::Builtin(Builtin::Int128)), Symbol::NUM_U128 => Ok(Layout::u128()),
Symbol::NUM_U64 => Ok(Layout::Builtin(Builtin::Int64)), Symbol::NUM_U64 => Ok(Layout::u64()),
Symbol::NUM_U32 => Ok(Layout::Builtin(Builtin::Int32)), Symbol::NUM_U32 => Ok(Layout::u32()),
Symbol::NUM_U16 => Ok(Layout::Builtin(Builtin::Int16)), Symbol::NUM_U16 => Ok(Layout::u16()),
Symbol::NUM_U8 => Ok(Layout::Builtin(Builtin::Int8)), Symbol::NUM_U8 => Ok(Layout::u8()),
// Floats // Floats
Symbol::NUM_FLOATINGPOINT => Ok(Layout::Builtin(Builtin::Float64)), Symbol::NUM_FLOATINGPOINT => Ok(Layout::f64()),
Symbol::NUM_F64 => Ok(Layout::f64()),
Symbol::NUM_F32 => Ok(Layout::f32()),
// Dec
Symbol::NUM_DEC => Ok(Layout::Builtin(Builtin::Decimal)), Symbol::NUM_DEC => Ok(Layout::Builtin(Builtin::Decimal)),
Symbol::NUM_F64 => Ok(Layout::Builtin(Builtin::Float64)),
Symbol::NUM_F32 => Ok(Layout::Builtin(Builtin::Float32)),
_ => { _ => {
panic!( panic!(
@ -2451,26 +2519,29 @@ fn unwrap_num_tag<'a>(subs: &Subs, var: Variable) -> Result<Layout<'a>, LayoutPr
Content::Alias(symbol, args, _) => { Content::Alias(symbol, args, _) => {
debug_assert!(args.is_empty()); debug_assert!(args.is_empty());
let builtin = match *symbol { let width = match *symbol {
Symbol::NUM_SIGNED128 => Builtin::Int128, Symbol::NUM_SIGNED128 => IntWidth::I128,
Symbol::NUM_SIGNED64 => Builtin::Int64, Symbol::NUM_SIGNED64 => IntWidth::I64,
Symbol::NUM_SIGNED32 => Builtin::Int32, Symbol::NUM_SIGNED32 => IntWidth::I32,
Symbol::NUM_SIGNED16 => Builtin::Int16, Symbol::NUM_SIGNED16 => IntWidth::I16,
Symbol::NUM_SIGNED8 => Builtin::Int8, Symbol::NUM_SIGNED8 => IntWidth::I8,
Symbol::NUM_UNSIGNED128 => Builtin::Int128, Symbol::NUM_UNSIGNED128 => IntWidth::U128,
Symbol::NUM_UNSIGNED64 => Builtin::Int64, Symbol::NUM_UNSIGNED64 => IntWidth::U64,
Symbol::NUM_UNSIGNED32 => Builtin::Int32, Symbol::NUM_UNSIGNED32 => IntWidth::U32,
Symbol::NUM_UNSIGNED16 => Builtin::Int16, Symbol::NUM_UNSIGNED16 => IntWidth::U16,
Symbol::NUM_UNSIGNED8 => Builtin::Int8, Symbol::NUM_UNSIGNED8 => IntWidth::U8,
Symbol::NUM_NATURAL => Builtin::Usize, Symbol::NUM_NATURAL => {
return Ok(Layout::usize());
}
_ => unreachable!("not a valid int variant: {:?} {:?}", symbol, args), _ => unreachable!("not a valid int variant: {:?} {:?}", symbol, args),
}; };
Ok(Layout::Builtin(builtin)) Ok(Layout::Builtin(Builtin::Int(width)))
} }
Content::FlexVar(_) | Content::RigidVar(_) => { Content::FlexVar(_) | Content::RigidVar(_) => {
// default to i64 // default to i64
Ok(Layout::Builtin(Builtin::Int64)) Ok(Layout::i64())
} }
_ => unreachable!("not a valid int variant: {:?}", precision), _ => unreachable!("not a valid int variant: {:?}", precision),
} }
@ -2486,12 +2557,12 @@ fn unwrap_num_tag<'a>(subs: &Subs, var: Variable) -> Result<Layout<'a>, LayoutPr
Content::Alias(Symbol::NUM_BINARY32, args, _) => { Content::Alias(Symbol::NUM_BINARY32, args, _) => {
debug_assert!(args.is_empty()); debug_assert!(args.is_empty());
Ok(Layout::Builtin(Builtin::Float32)) Ok(Layout::f32())
} }
Content::Alias(Symbol::NUM_BINARY64, args, _) => { Content::Alias(Symbol::NUM_BINARY64, args, _) => {
debug_assert!(args.is_empty()); debug_assert!(args.is_empty());
Ok(Layout::Builtin(Builtin::Float64)) Ok(Layout::f64())
} }
Content::Alias(Symbol::NUM_DECIMAL, args, _) => { Content::Alias(Symbol::NUM_DECIMAL, args, _) => {
debug_assert!(args.is_empty()); debug_assert!(args.is_empty());
@ -2500,14 +2571,14 @@ fn unwrap_num_tag<'a>(subs: &Subs, var: Variable) -> Result<Layout<'a>, LayoutPr
} }
Content::FlexVar(_) | Content::RigidVar(_) => { Content::FlexVar(_) | Content::RigidVar(_) => {
// default to f64 // default to f64
Ok(Layout::Builtin(Builtin::Float64)) Ok(Layout::f64())
} }
_ => unreachable!("not a valid float variant: {:?}", precision), _ => unreachable!("not a valid float variant: {:?}", precision),
} }
} }
Content::FlexVar(_) | Content::RigidVar(_) => { Content::FlexVar(_) | Content::RigidVar(_) => {
// If this was still a (Num *) then default to compiling it to i64 // If this was still a (Num *) then default to compiling it to i64
Ok(Layout::Builtin(DEFAULT_NUM_BUILTIN)) Ok(Layout::default_integer())
} }
other => { other => {
todo!("TODO non structure Num.@Num flat_type {:?}", other); todo!("TODO non structure Num.@Num flat_type {:?}", other);