mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 22:34:45 +00:00
Merge branch 'trunk' into dev-backend-num-is-zero
This commit is contained in:
commit
0085272cb8
40 changed files with 1382 additions and 892 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -3458,6 +3458,7 @@ dependencies = [
|
|||
"bumpalo",
|
||||
"hashbrown 0.11.2",
|
||||
"morphic_lib",
|
||||
"roc_builtins",
|
||||
"roc_can",
|
||||
"roc_collections",
|
||||
"roc_module",
|
||||
|
|
|
@ -2492,4 +2492,121 @@ pub mod test_constrain {
|
|||
"custom",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inference_var_inside_arrow() {
|
||||
infer_eq(
|
||||
indoc!(
|
||||
r#"
|
||||
id : _ -> _
|
||||
id = \x -> x
|
||||
id
|
||||
"#
|
||||
),
|
||||
"a -> a",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "TODO: Type2::substitute"]
|
||||
fn inference_var_inside_ctor() {
|
||||
infer_eq(
|
||||
indoc!(
|
||||
r#"
|
||||
canIGo : _ -> Result _ _
|
||||
canIGo = \color ->
|
||||
when color is
|
||||
"green" -> Ok "go!"
|
||||
"yellow" -> Err (SlowIt "whoa, let's slow down!")
|
||||
"red" -> Err (StopIt "absolutely not")
|
||||
_ -> Err (UnknownColor "this is a weird stoplight")
|
||||
canIGo
|
||||
"#
|
||||
),
|
||||
"Str -> Result Str [ SlowIt Str, StopIt Str, UnknownColor Str ]*",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "TODO: Gives { x : *, y : * } -> { x : *, y : * }. This is a bug in typechecking defs with annotations."]
|
||||
fn inference_var_inside_ctor_linked() {
|
||||
infer_eq(
|
||||
indoc!(
|
||||
r#"
|
||||
swapRcd: {x: _, y: _} -> {x: _, y: _}
|
||||
swapRcd = \{x, y} -> {x: y, y: x}
|
||||
swapRcd
|
||||
"#
|
||||
),
|
||||
"{ x : a, y : b } -> { x : b, y : a }",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inference_var_link_with_rigid() {
|
||||
infer_eq(
|
||||
indoc!(
|
||||
r#"
|
||||
swapRcd: {x: tx, y: ty} -> {x: _, y: _}
|
||||
swapRcd = \{x, y} -> {x: y, y: x}
|
||||
swapRcd
|
||||
"#
|
||||
),
|
||||
"{ x : tx, y : ty } -> { x : ty, y : tx }",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "TODO: Type2::substitute"]
|
||||
fn inference_var_inside_tag_ctor() {
|
||||
infer_eq(
|
||||
indoc!(
|
||||
r#"
|
||||
badComics: Bool -> [ CowTools _, Thagomizer _ ]
|
||||
badComics = \c ->
|
||||
when c is
|
||||
True -> CowTools "The Far Side"
|
||||
False -> Thagomizer "The Far Side"
|
||||
badComics
|
||||
"#
|
||||
),
|
||||
"Bool -> [ CowTools Str, Thagomizer Str ]",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inference_var_tag_union_ext() {
|
||||
// TODO: we should really be inferring [ Blue, Orange ]a -> [ Lavender, Peach ]a here.
|
||||
// See https://github.com/rtfeldman/roc/issues/2053
|
||||
infer_eq(
|
||||
indoc!(
|
||||
r#"
|
||||
pastelize: _ -> [ Lavender, Peach ]_
|
||||
pastelize = \color ->
|
||||
when color is
|
||||
Blue -> Lavender
|
||||
Orange -> Peach
|
||||
col -> col
|
||||
pastelize
|
||||
"#
|
||||
),
|
||||
"[ Blue, Lavender, Orange, Peach ]a -> [ Blue, Lavender, Orange, Peach ]a",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "TODO: gives { email : a, name : b }c -> { email : a, name : b }c. This is a bug in typechecking defs with annotations."]
|
||||
fn inference_var_rcd_union_ext() {
|
||||
infer_eq(
|
||||
indoc!(
|
||||
r#"
|
||||
setRocEmail : _ -> { name: Str, email: Str }_
|
||||
setRocEmail = \person ->
|
||||
{ person & email: "\(person.name)@roclang.com" }
|
||||
setRocEmail
|
||||
"#
|
||||
),
|
||||
"{ email : Str, name : Str }a -> { email : Str, name : Str }a",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -390,7 +390,9 @@ pub fn to_type2<'a>(
|
|||
}
|
||||
}
|
||||
Inferred => {
|
||||
unimplemented!();
|
||||
let var = env.var_store.fresh();
|
||||
|
||||
Type2::Variable(var)
|
||||
}
|
||||
Wildcard | Malformed(_) => {
|
||||
let var = env.var_store.fresh();
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use bumpalo::collections::Vec;
|
||||
use bumpalo::Bump;
|
||||
use libloading::Library;
|
||||
use roc_builtins::bitcode::{FloatWidth, IntWidth};
|
||||
use roc_gen_llvm::{run_jit_function, run_jit_function_dynamic_type};
|
||||
use roc_module::called_via::CalledVia;
|
||||
use roc_module::ident::TagName;
|
||||
|
@ -71,60 +72,59 @@ fn jit_to_ast_help<'a>(
|
|||
content: &Content,
|
||||
) -> Result<Expr<'a>, ToAstProblem> {
|
||||
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)
|
||||
})),
|
||||
Layout::Builtin(Builtin::Int8) => {
|
||||
Ok(
|
||||
// NOTE: this is does not handle 8-bit numbers yet
|
||||
run_jit_function!(lib, main_fn_name, u8, |num| byte_to_ast(env, num, content)),
|
||||
)
|
||||
}
|
||||
Layout::Builtin(Builtin::Usize) => Ok(run_jit_function!(lib, main_fn_name, usize, |num| {
|
||||
num_to_ast(env, number_literal_to_ast(env.arena, num), content)
|
||||
})),
|
||||
Layout::Builtin(Builtin::Int16) => {
|
||||
Ok(run_jit_function!(lib, main_fn_name, i16, |num| num_to_ast(
|
||||
Layout::Builtin(Builtin::Int(int_width)) => {
|
||||
use IntWidth::*;
|
||||
|
||||
macro_rules! helper {
|
||||
($ty:ty) => {
|
||||
run_jit_function!(lib, main_fn_name, $ty, |num| num_to_ast(
|
||||
env,
|
||||
number_literal_to_ast(env.arena, num),
|
||||
content
|
||||
)))
|
||||
}
|
||||
Layout::Builtin(Builtin::Int32) => {
|
||||
Ok(run_jit_function!(lib, main_fn_name, i32, |num| num_to_ast(
|
||||
env,
|
||||
number_literal_to_ast(env.arena, num),
|
||||
content
|
||||
)))
|
||||
}
|
||||
Layout::Builtin(Builtin::Int64) => {
|
||||
Ok(run_jit_function!(lib, main_fn_name, i64, |num| num_to_ast(
|
||||
env,
|
||||
number_literal_to_ast(env.arena, num),
|
||||
content
|
||||
)))
|
||||
}
|
||||
Layout::Builtin(Builtin::Int128) => {
|
||||
Ok(run_jit_function!(
|
||||
lib,
|
||||
main_fn_name,
|
||||
i128,
|
||||
|num| num_to_ast(env, number_literal_to_ast(env.arena, num), content)
|
||||
))
|
||||
};
|
||||
}
|
||||
Layout::Builtin(Builtin::Float32) => {
|
||||
Ok(run_jit_function!(lib, main_fn_name, f32, |num| num_to_ast(
|
||||
|
||||
let result = match int_width {
|
||||
U8 | I8 => {
|
||||
// NOTE: this is does not handle 8-bit numbers yet
|
||||
run_jit_function!(lib, main_fn_name, u8, |num| byte_to_ast(env, num, content))
|
||||
}
|
||||
U16 => helper!(u16),
|
||||
U32 => helper!(u32),
|
||||
U64 => helper!(u64),
|
||||
U128 => helper!(u128),
|
||||
I16 => helper!(i16),
|
||||
I32 => helper!(i32),
|
||||
I64 => helper!(i64),
|
||||
I128 => helper!(i128),
|
||||
};
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
Layout::Builtin(Builtin::Float(float_width)) => {
|
||||
use FloatWidth::*;
|
||||
|
||||
macro_rules! helper {
|
||||
($ty:ty) => {
|
||||
run_jit_function!(lib, main_fn_name, $ty, |num| num_to_ast(
|
||||
env,
|
||||
number_literal_to_ast(env.arena, num),
|
||||
content
|
||||
)))
|
||||
))
|
||||
};
|
||||
}
|
||||
Layout::Builtin(Builtin::Float64) => {
|
||||
Ok(run_jit_function!(lib, main_fn_name, f64, |num| num_to_ast(
|
||||
env,
|
||||
number_literal_to_ast(env.arena, num),
|
||||
content
|
||||
)))
|
||||
|
||||
let result = match float_width {
|
||||
F32 => helper!(f32),
|
||||
F64 => helper!(f64),
|
||||
F128 => todo!("F128 not implemented"),
|
||||
};
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
Layout::Builtin(Builtin::Str) | Layout::Builtin(Builtin::EmptyStr) => Ok(
|
||||
run_jit_function!(lib, main_fn_name, &'static str, |string: &'static str| {
|
||||
|
@ -192,7 +192,7 @@ fn jit_to_ast_help<'a>(
|
|||
}
|
||||
};
|
||||
|
||||
let fields = [Layout::Builtin(Builtin::Int64), *layout];
|
||||
let fields = [Layout::u64(), *layout];
|
||||
let layout = Layout::Struct(&fields);
|
||||
|
||||
let result_stack_size = layout.stack_size(env.ptr_bytes);
|
||||
|
@ -248,16 +248,16 @@ fn jit_to_ast_help<'a>(
|
|||
.unwrap_or(0);
|
||||
|
||||
let tag_id = match union_layout.tag_id_builtin() {
|
||||
Builtin::Int1 => {
|
||||
Builtin::Bool => {
|
||||
*(ptr.add(offset as usize) as *const i8) as i64
|
||||
}
|
||||
Builtin::Int8 => {
|
||||
Builtin::Int(IntWidth::U8) => {
|
||||
*(ptr.add(offset as usize) as *const i8) as i64
|
||||
}
|
||||
Builtin::Int16 => {
|
||||
Builtin::Int(IntWidth::U16) => {
|
||||
*(ptr.add(offset as usize) as *const i16) as i64
|
||||
}
|
||||
Builtin::Int64 => {
|
||||
Builtin::Int(IntWidth::U64) => {
|
||||
// used by non-recursive unions at the
|
||||
// moment, remove if that is no longer the case
|
||||
*(ptr.add(offset as usize) as *const i64) as i64
|
||||
|
@ -380,53 +380,46 @@ fn ptr_to_ast<'a>(
|
|||
layout: &Layout<'a>,
|
||||
content: &Content,
|
||||
) -> Expr<'a> {
|
||||
macro_rules! helper {
|
||||
($ty:ty) => {{
|
||||
let num = unsafe { *(ptr as *const $ty) };
|
||||
|
||||
num_to_ast(env, number_literal_to_ast(env.arena, num), content)
|
||||
}};
|
||||
}
|
||||
|
||||
match layout {
|
||||
Layout::Builtin(Builtin::Int128) => {
|
||||
let num = unsafe { *(ptr as *const i128) };
|
||||
|
||||
num_to_ast(env, number_literal_to_ast(env.arena, num), content)
|
||||
}
|
||||
Layout::Builtin(Builtin::Int64) => {
|
||||
let num = unsafe { *(ptr as *const i64) };
|
||||
|
||||
num_to_ast(env, number_literal_to_ast(env.arena, num), content)
|
||||
}
|
||||
Layout::Builtin(Builtin::Int32) => {
|
||||
let num = unsafe { *(ptr as *const i32) };
|
||||
|
||||
num_to_ast(env, number_literal_to_ast(env.arena, num), content)
|
||||
}
|
||||
Layout::Builtin(Builtin::Int16) => {
|
||||
let num = unsafe { *(ptr as *const i16) };
|
||||
|
||||
num_to_ast(env, number_literal_to_ast(env.arena, num), content)
|
||||
}
|
||||
Layout::Builtin(Builtin::Int8) => {
|
||||
let num = unsafe { *(ptr as *const i8) };
|
||||
|
||||
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.
|
||||
// num is always false at the moment.
|
||||
let num = unsafe { *(ptr as *const bool) };
|
||||
|
||||
bool_to_ast(env, num, content)
|
||||
}
|
||||
Layout::Builtin(Builtin::Usize) => {
|
||||
let num = unsafe { *(ptr as *const usize) };
|
||||
Layout::Builtin(Builtin::Int(int_width)) => {
|
||||
use IntWidth::*;
|
||||
|
||||
num_to_ast(env, number_literal_to_ast(env.arena, num), content)
|
||||
match int_width {
|
||||
U8 => helper!(u8),
|
||||
U16 => helper!(u16),
|
||||
U32 => helper!(u32),
|
||||
U64 => helper!(u64),
|
||||
U128 => helper!(u128),
|
||||
I8 => helper!(i8),
|
||||
I16 => helper!(i16),
|
||||
I32 => helper!(i32),
|
||||
I64 => helper!(i64),
|
||||
I128 => helper!(i128),
|
||||
}
|
||||
Layout::Builtin(Builtin::Float64) => {
|
||||
let num = unsafe { *(ptr as *const f64) };
|
||||
|
||||
num_to_ast(env, number_literal_to_ast(env.arena, num), content)
|
||||
}
|
||||
Layout::Builtin(Builtin::Float32) => {
|
||||
let num = unsafe { *(ptr as *const f32) };
|
||||
Layout::Builtin(Builtin::Float(float_width)) => {
|
||||
use FloatWidth::*;
|
||||
|
||||
num_to_ast(env, number_literal_to_ast(env.arena, num), content)
|
||||
match float_width {
|
||||
F32 => helper!(f32),
|
||||
F64 => helper!(f64),
|
||||
F128 => todo!("F128 not implemented"),
|
||||
}
|
||||
}
|
||||
Layout::Builtin(Builtin::EmptyList) => Expr::List(Collection::empty()),
|
||||
Layout::Builtin(Builtin::List(elem_layout)) => {
|
||||
|
|
1
cli_utils/Cargo.lock
generated
1
cli_utils/Cargo.lock
generated
|
@ -2709,6 +2709,7 @@ dependencies = [
|
|||
"bumpalo",
|
||||
"hashbrown 0.11.2",
|
||||
"morphic_lib",
|
||||
"roc_builtins",
|
||||
"roc_can",
|
||||
"roc_collections",
|
||||
"roc_module",
|
||||
|
|
|
@ -975,7 +975,6 @@ pub fn listRange(width: utils.IntWidth, low: Opaque, high: Opaque) callconv(.C)
|
|||
.I32 => helper1(i32, low, high),
|
||||
.I64 => helper1(i64, low, high),
|
||||
.I128 => helper1(i128, low, high),
|
||||
.Usize => helper1(usize, low, high),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -92,17 +92,16 @@ pub const REFCOUNT_ONE_ISIZE: isize = std.math.minInt(isize);
|
|||
pub const REFCOUNT_ONE: usize = @bitCast(usize, REFCOUNT_ONE_ISIZE);
|
||||
|
||||
pub const IntWidth = enum(u8) {
|
||||
U8,
|
||||
U16,
|
||||
U32,
|
||||
U64,
|
||||
U128,
|
||||
I8,
|
||||
I16,
|
||||
I32,
|
||||
I64,
|
||||
I128,
|
||||
Usize,
|
||||
U8 = 0,
|
||||
U16 = 1,
|
||||
U32 = 2,
|
||||
U64 = 3,
|
||||
U128 = 4,
|
||||
I8 = 5,
|
||||
I16 = 6,
|
||||
I32 = 7,
|
||||
I64 = 8,
|
||||
I128 = 9,
|
||||
};
|
||||
|
||||
pub fn decrefC(
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use roc_module::symbol::Symbol;
|
||||
use std::ops::Index;
|
||||
|
||||
pub const BUILTINS_HOST_OBJ_PATH: &str = env!(
|
||||
|
@ -27,24 +28,123 @@ pub enum DecWidth {
|
|||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub enum FloatWidth {
|
||||
F32,
|
||||
F64,
|
||||
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_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)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub enum IntWidth {
|
||||
U8,
|
||||
U16,
|
||||
U32,
|
||||
U64,
|
||||
U128,
|
||||
I8,
|
||||
I16,
|
||||
I32,
|
||||
I64,
|
||||
I128,
|
||||
U8 = 0,
|
||||
U16 = 1,
|
||||
U32 = 2,
|
||||
U64 = 3,
|
||||
U128 = 4,
|
||||
I8 = 5,
|
||||
I16 = 6,
|
||||
I32 = 7,
|
||||
I64 = 8,
|
||||
I128 = 9,
|
||||
}
|
||||
|
||||
impl IntWidth {
|
||||
pub const fn is_signed(&self) -> bool {
|
||||
use IntWidth::*;
|
||||
|
||||
matches!(self, I8 | I16 | I32 | I64 | I128)
|
||||
}
|
||||
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_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 {
|
||||
|
|
|
@ -387,17 +387,6 @@ fn can_annotation_help(
|
|||
},
|
||||
|
||||
Record { fields, ext, .. } => {
|
||||
let field_types = can_assigned_fields(
|
||||
env,
|
||||
&fields.items,
|
||||
region,
|
||||
scope,
|
||||
var_store,
|
||||
introduced_variables,
|
||||
local_aliases,
|
||||
references,
|
||||
);
|
||||
|
||||
let ext_type = match ext {
|
||||
Some(loc_ann) => can_annotation_help(
|
||||
env,
|
||||
|
@ -412,12 +401,21 @@ fn can_annotation_help(
|
|||
None => Type::EmptyRec,
|
||||
};
|
||||
|
||||
Type::Record(field_types, Box::new(ext_type))
|
||||
if fields.is_empty() {
|
||||
match ext {
|
||||
Some(_) => {
|
||||
// just `a` does not mean the same as `{}a`, so even
|
||||
// if there are no fields, still make this a `Record`,
|
||||
// not an EmptyRec
|
||||
Type::Record(Default::default(), Box::new(ext_type))
|
||||
}
|
||||
TagUnion { tags, ext, .. } => {
|
||||
let tag_types = can_tags(
|
||||
|
||||
None => Type::EmptyRec,
|
||||
}
|
||||
} else {
|
||||
let field_types = can_assigned_fields(
|
||||
env,
|
||||
tags.items,
|
||||
&fields.items,
|
||||
region,
|
||||
scope,
|
||||
var_store,
|
||||
|
@ -426,6 +424,10 @@ fn can_annotation_help(
|
|||
references,
|
||||
);
|
||||
|
||||
Type::Record(field_types, Box::new(ext_type))
|
||||
}
|
||||
}
|
||||
TagUnion { tags, ext, .. } => {
|
||||
let ext_type = match ext {
|
||||
Some(loc_ann) => can_annotation_help(
|
||||
env,
|
||||
|
@ -440,8 +442,32 @@ fn can_annotation_help(
|
|||
None => Type::EmptyTagUnion,
|
||||
};
|
||||
|
||||
if tags.is_empty() {
|
||||
match ext {
|
||||
Some(_) => {
|
||||
// just `a` does not mean the same as `{}a`, so even
|
||||
// if there are no fields, still make this a `Record`,
|
||||
// not an EmptyRec
|
||||
Type::TagUnion(Default::default(), Box::new(ext_type))
|
||||
}
|
||||
|
||||
None => Type::EmptyTagUnion,
|
||||
}
|
||||
} else {
|
||||
let tag_types = can_tags(
|
||||
env,
|
||||
tags.items,
|
||||
region,
|
||||
scope,
|
||||
var_store,
|
||||
introduced_variables,
|
||||
local_aliases,
|
||||
references,
|
||||
);
|
||||
|
||||
Type::TagUnion(tag_types, Box::new(ext_type))
|
||||
}
|
||||
}
|
||||
SpaceBefore(nested, _) | SpaceAfter(nested, _) => can_annotation_help(
|
||||
env,
|
||||
nested,
|
||||
|
@ -460,7 +486,10 @@ fn can_annotation_help(
|
|||
Type::Variable(var)
|
||||
}
|
||||
Inferred => {
|
||||
unimplemented!();
|
||||
// Inference variables aren't bound to a rigid or a wildcard, so all we have to do is
|
||||
// make a fresh unconstrained variable, and let the type solver fill it in for us 🤠
|
||||
let var = var_store.fresh();
|
||||
Type::Variable(var)
|
||||
}
|
||||
Malformed(string) => {
|
||||
malformed(env, region, string);
|
||||
|
|
|
@ -22,17 +22,7 @@ pub struct ConstrainedModule {
|
|||
pub constraint: Constraint,
|
||||
}
|
||||
|
||||
pub fn constrain_module(
|
||||
aliases: &MutMap<Symbol, Alias>,
|
||||
declarations: &[Declaration],
|
||||
home: ModuleId,
|
||||
) -> Constraint {
|
||||
let mut send_aliases = SendMap::default();
|
||||
|
||||
for (symbol, alias) in aliases.iter() {
|
||||
send_aliases.insert(*symbol, alias.clone());
|
||||
}
|
||||
|
||||
pub fn constrain_module(declarations: &[Declaration], home: ModuleId) -> Constraint {
|
||||
constrain_decls(home, declarations)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::{Backend, Env, Relocation};
|
||||
use bumpalo::collections::Vec;
|
||||
use roc_builtins::bitcode::{FloatWidth, IntWidth};
|
||||
use roc_collections::all::{MutMap, MutSet};
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_mono::ir::{BranchInfo, JoinPointId, Literal, Param, SelfRecursive, Stmt};
|
||||
|
@ -502,12 +503,12 @@ impl<
|
|||
|
||||
// move return value to dst.
|
||||
match ret_layout {
|
||||
Layout::Builtin(Builtin::Int64 | Builtin::Int1) => {
|
||||
Layout::Builtin(Builtin::Int(IntWidth::I64 | IntWidth::U64) | Builtin::Bool) => {
|
||||
let dst_reg = self.claim_general_reg(dst)?;
|
||||
ASM::mov_reg64_reg64(&mut self.buf, dst_reg, CC::GENERAL_RETURN_REGS[0]);
|
||||
Ok(())
|
||||
}
|
||||
Layout::Builtin(Builtin::Float64) => {
|
||||
Layout::Builtin(Builtin::Float(FloatWidth::F64)) => {
|
||||
let dst_reg = self.claim_float_reg(dst)?;
|
||||
ASM::mov_freg64_freg64(&mut self.buf, dst_reg, CC::FLOAT_RETURN_REGS[0]);
|
||||
Ok(())
|
||||
|
@ -742,13 +743,13 @@ impl<
|
|||
layout: &Layout<'a>,
|
||||
) -> Result<(), String> {
|
||||
match layout {
|
||||
Layout::Builtin(Builtin::Int64) => {
|
||||
Layout::Builtin(Builtin::Int(IntWidth::I64 | IntWidth::U64)) => {
|
||||
let dst_reg = self.claim_general_reg(dst)?;
|
||||
let src_reg = self.load_to_general_reg(src)?;
|
||||
ASM::abs_reg64_reg64(&mut self.buf, dst_reg, src_reg);
|
||||
Ok(())
|
||||
}
|
||||
Layout::Builtin(Builtin::Float64) => {
|
||||
Layout::Builtin(Builtin::Float(FloatWidth::F64)) => {
|
||||
let dst_reg = self.claim_float_reg(dst)?;
|
||||
let src_reg = self.load_to_float_reg(src)?;
|
||||
ASM::abs_freg64_freg64(&mut self.buf, &mut self.relocs, dst_reg, src_reg);
|
||||
|
@ -766,14 +767,14 @@ impl<
|
|||
layout: &Layout<'a>,
|
||||
) -> Result<(), String> {
|
||||
match layout {
|
||||
Layout::Builtin(Builtin::Int64) => {
|
||||
Layout::Builtin(Builtin::Int(IntWidth::I64 | IntWidth::U64)) => {
|
||||
let dst_reg = self.claim_general_reg(dst)?;
|
||||
let src1_reg = self.load_to_general_reg(src1)?;
|
||||
let src2_reg = self.load_to_general_reg(src2)?;
|
||||
ASM::add_reg64_reg64_reg64(&mut self.buf, dst_reg, src1_reg, src2_reg);
|
||||
Ok(())
|
||||
}
|
||||
Layout::Builtin(Builtin::Float64) => {
|
||||
Layout::Builtin(Builtin::Float(FloatWidth::F64)) => {
|
||||
let dst_reg = self.claim_float_reg(dst)?;
|
||||
let src1_reg = self.load_to_float_reg(src1)?;
|
||||
let src2_reg = self.load_to_float_reg(src2)?;
|
||||
|
@ -792,7 +793,7 @@ impl<
|
|||
layout: &Layout<'a>,
|
||||
) -> Result<(), String> {
|
||||
match layout {
|
||||
Layout::Builtin(Builtin::Int64) => {
|
||||
Layout::Builtin(Builtin::Int(IntWidth::I64 | IntWidth::U64)) => {
|
||||
let dst_reg = self.claim_general_reg(dst)?;
|
||||
let src1_reg = self.load_to_general_reg(src1)?;
|
||||
let src2_reg = self.load_to_general_reg(src2)?;
|
||||
|
@ -810,7 +811,7 @@ impl<
|
|||
layout: &Layout<'a>,
|
||||
) -> Result<(), String> {
|
||||
match layout {
|
||||
Layout::Builtin(Builtin::Int64) => {
|
||||
Layout::Builtin(Builtin::Int(IntWidth::I64 | IntWidth::U64)) => {
|
||||
let dst_reg = self.claim_general_reg(dst)?;
|
||||
let src_reg = self.load_to_general_reg(src)?;
|
||||
ASM::neg_reg64_reg64(&mut self.buf, dst_reg, src_reg);
|
||||
|
@ -828,7 +829,7 @@ impl<
|
|||
layout: &Layout<'a>,
|
||||
) -> Result<(), String> {
|
||||
match layout {
|
||||
Layout::Builtin(Builtin::Int64) => {
|
||||
Layout::Builtin(Builtin::Int(IntWidth::I64 | IntWidth::U64)) => {
|
||||
let dst_reg = self.claim_general_reg(dst)?;
|
||||
let src1_reg = self.load_to_general_reg(src1)?;
|
||||
let src2_reg = self.load_to_general_reg(src2)?;
|
||||
|
@ -847,7 +848,7 @@ impl<
|
|||
arg_layout: &Layout<'a>,
|
||||
) -> Result<(), String> {
|
||||
match arg_layout {
|
||||
Layout::Builtin(Builtin::Int64) => {
|
||||
Layout::Builtin(Builtin::Int(IntWidth::I64 | IntWidth::U64)) => {
|
||||
let dst_reg = self.claim_general_reg(dst)?;
|
||||
let src1_reg = self.load_to_general_reg(src1)?;
|
||||
let src2_reg = self.load_to_general_reg(src2)?;
|
||||
|
@ -866,7 +867,7 @@ impl<
|
|||
arg_layout: &Layout<'a>,
|
||||
) -> Result<(), String> {
|
||||
match arg_layout {
|
||||
Layout::Builtin(Builtin::Int64) => {
|
||||
Layout::Builtin(Builtin::Int(IntWidth::I64 | IntWidth::U64)) => {
|
||||
let dst_reg = self.claim_general_reg(dst)?;
|
||||
let src1_reg = self.load_to_general_reg(src1)?;
|
||||
let src2_reg = self.load_to_general_reg(src2)?;
|
||||
|
@ -885,7 +886,7 @@ impl<
|
|||
arg_layout: &Layout<'a>,
|
||||
) -> Result<(), String> {
|
||||
match arg_layout {
|
||||
Layout::Builtin(Builtin::Int64) => {
|
||||
Layout::Builtin(Builtin::Int(IntWidth::I64 | IntWidth::U64)) => {
|
||||
let dst_reg = self.claim_general_reg(dst)?;
|
||||
let src1_reg = self.load_to_general_reg(src1)?;
|
||||
let src2_reg = self.load_to_general_reg(src2)?;
|
||||
|
@ -903,7 +904,7 @@ impl<
|
|||
arg_layout: &Layout<'a>,
|
||||
) -> Result<(), String> {
|
||||
match arg_layout {
|
||||
Layout::Builtin(Builtin::Int64) => {
|
||||
Layout::Builtin(Builtin::Int(IntWidth::I64)) => {
|
||||
let dst_reg = self.claim_general_reg(dst)?;
|
||||
let src_reg = self.load_to_general_reg(src)?;
|
||||
ASM::is_zero_reg64_reg64(&mut self.buf, dst_reg, src_reg);
|
||||
|
@ -1149,10 +1150,10 @@ impl<
|
|||
ASM::mov_freg64_freg64(&mut self.buf, CC::FLOAT_RETURN_REGS[0], *reg);
|
||||
}
|
||||
Some(SymbolStorage::Base { offset, size, .. }) => match layout {
|
||||
Layout::Builtin(Builtin::Int64) => {
|
||||
Layout::Builtin(Builtin::Int(IntWidth::I64 | IntWidth::U64)) => {
|
||||
ASM::mov_reg64_base32(&mut self.buf, CC::GENERAL_RETURN_REGS[0], *offset);
|
||||
}
|
||||
Layout::Builtin(Builtin::Float64) => {
|
||||
Layout::Builtin(Builtin::Float(FloatWidth::F64)) => {
|
||||
ASM::mov_freg64_base32(&mut self.buf, CC::FLOAT_RETURN_REGS[0], *offset);
|
||||
}
|
||||
Layout::Builtin(Builtin::Str) => {
|
||||
|
@ -1505,12 +1506,12 @@ impl<
|
|||
layout: &Layout<'a>,
|
||||
) -> Result<(), String> {
|
||||
match layout {
|
||||
Layout::Builtin(Builtin::Int64) => {
|
||||
Layout::Builtin(Builtin::Int(IntWidth::I64 | IntWidth::U64)) => {
|
||||
let reg = self.load_to_general_reg(sym)?;
|
||||
ASM::mov_base32_reg64(&mut self.buf, to_offset, reg);
|
||||
Ok(())
|
||||
}
|
||||
Layout::Builtin(Builtin::Float64) => {
|
||||
Layout::Builtin(Builtin::Float(FloatWidth::F64)) => {
|
||||
let reg = self.load_to_float_reg(sym)?;
|
||||
ASM::mov_base32_freg64(&mut self.buf, to_offset, reg);
|
||||
Ok(())
|
||||
|
@ -1590,19 +1591,24 @@ impl<
|
|||
#[macro_export]
|
||||
macro_rules! single_register_integers {
|
||||
() => {
|
||||
Builtin::Int1
|
||||
| Builtin::Int8
|
||||
| Builtin::Int16
|
||||
| Builtin::Int32
|
||||
| Builtin::Int64
|
||||
| Builtin::Usize
|
||||
Builtin::Bool
|
||||
| Builtin::Int(
|
||||
IntWidth::I8
|
||||
| IntWidth::I16
|
||||
| IntWidth::I32
|
||||
| IntWidth::I64
|
||||
| IntWidth::U8
|
||||
| IntWidth::U16
|
||||
| IntWidth::U32
|
||||
| IntWidth::U64,
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! single_register_floats {
|
||||
() => {
|
||||
Builtin::Float32 | Builtin::Float64
|
||||
Builtin::Float(FloatWidth::F32 | FloatWidth::F64)
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ use crate::{
|
|||
single_register_builtins, single_register_floats, single_register_integers, Relocation,
|
||||
};
|
||||
use bumpalo::collections::Vec;
|
||||
use roc_builtins::bitcode::{FloatWidth, IntWidth};
|
||||
use roc_collections::all::MutMap;
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_mono::layout::{Builtin, Layout};
|
||||
|
|
|
@ -413,9 +413,9 @@ where
|
|||
"Eq: expected all arguments of to have the same layout"
|
||||
);
|
||||
debug_assert_eq!(
|
||||
Layout::Builtin(Builtin::Int1),
|
||||
Layout::Builtin(Builtin::Bool),
|
||||
*ret_layout,
|
||||
"Eq: expected to have return layout of type I1"
|
||||
"Eq: expected to have return layout of type Bool"
|
||||
);
|
||||
self.build_eq(sym, &args[0], &args[1], &arg_layouts[0])
|
||||
}
|
||||
|
@ -430,9 +430,9 @@ where
|
|||
"NotEq: expected all arguments of to have the same layout"
|
||||
);
|
||||
debug_assert_eq!(
|
||||
Layout::Builtin(Builtin::Int1),
|
||||
Layout::Builtin(Builtin::Bool),
|
||||
*ret_layout,
|
||||
"NotEq: expected to have return layout of type I1"
|
||||
"NotEq: expected to have return layout of type Bool"
|
||||
);
|
||||
self.build_neq(sym, &args[0], &args[1], &arg_layouts[0])
|
||||
}
|
||||
|
@ -447,9 +447,9 @@ where
|
|||
"NumLt: expected all arguments of to have the same layout"
|
||||
);
|
||||
debug_assert_eq!(
|
||||
Layout::Builtin(Builtin::Int1),
|
||||
Layout::Builtin(Builtin::Bool),
|
||||
*ret_layout,
|
||||
"NumLt: expected to have return layout of type I1"
|
||||
"NumLt: expected to have return layout of type Bool"
|
||||
);
|
||||
self.build_num_lt(sym, &args[0], &args[1], &arg_layouts[0])
|
||||
}
|
||||
|
@ -489,7 +489,7 @@ where
|
|||
"NumIsZero: expected to have exactly one argument"
|
||||
);
|
||||
debug_assert_eq!(
|
||||
Layout::Builtin(Builtin::Int1),
|
||||
Layout::Builtin(Builtin::Bool),
|
||||
*ret_layout,
|
||||
"NumIsZero: expected to have return layout of type I1"
|
||||
);
|
||||
|
|
|
@ -22,8 +22,8 @@ use crate::llvm::build_str::{
|
|||
};
|
||||
use crate::llvm::compare::{generic_eq, generic_neq};
|
||||
use crate::llvm::convert::{
|
||||
basic_type_from_builtin, basic_type_from_layout, basic_type_from_layout_1,
|
||||
block_of_memory_slices, ptr_int,
|
||||
self, basic_type_from_builtin, basic_type_from_layout, basic_type_from_layout_1,
|
||||
block_of_memory_slices,
|
||||
};
|
||||
use crate::llvm::refcounting::{
|
||||
build_reset, decrement_refcount_layout, increment_refcount_layout, PointerToRefcount,
|
||||
|
@ -190,7 +190,18 @@ impl<'a, 'ctx, 'env> Env<'a, 'ctx, 'env> {
|
|||
/// on 64-bit systems, this is i64
|
||||
/// on 32-bit systems, this is i32
|
||||
pub fn ptr_int(&self) -> IntType<'ctx> {
|
||||
ptr_int(self.context, self.ptr_bytes)
|
||||
let ctx = self.context;
|
||||
|
||||
match self.ptr_bytes {
|
||||
1 => ctx.i8_type(),
|
||||
2 => ctx.i16_type(),
|
||||
4 => ctx.i32_type(),
|
||||
8 => ctx.i64_type(),
|
||||
_ => panic!(
|
||||
"Invalid target: Roc does't support compiling to {}-bit systems.",
|
||||
self.ptr_bytes * 8
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// The integer type representing a RocList or RocStr when following the C ABI
|
||||
|
@ -703,32 +714,31 @@ fn promote_to_main_function<'a, 'ctx, 'env>(
|
|||
(main_fn_name, main_fn)
|
||||
}
|
||||
|
||||
pub fn int_with_precision<'a, 'ctx, 'env>(
|
||||
fn int_with_precision<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
value: i128,
|
||||
precision: &Builtin,
|
||||
int_width: IntWidth,
|
||||
) -> IntValue<'ctx> {
|
||||
match precision {
|
||||
Builtin::Usize => ptr_int(env.context, env.ptr_bytes).const_int(value as u64, false),
|
||||
Builtin::Int128 => const_i128(env, value),
|
||||
Builtin::Int64 => env.context.i64_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::Int8 => env.context.i8_type().const_int(value as u64, false),
|
||||
Builtin::Int1 => env.context.bool_type().const_int(value as u64, false),
|
||||
_ => panic!("Invalid layout for int literal = {:?}", precision),
|
||||
use IntWidth::*;
|
||||
|
||||
match int_width {
|
||||
U128 | I128 => const_i128(env, value),
|
||||
U64 | I64 => env.context.i64_type().const_int(value as u64, false),
|
||||
U32 | I32 => env.context.i32_type().const_int(value as u64, false),
|
||||
U16 | I16 => env.context.i16_type().const_int(value as u64, false),
|
||||
U8 | I8 => env.context.i8_type().const_int(value as u64, false),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn float_with_precision<'a, 'ctx, 'env>(
|
||||
fn float_with_precision<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
value: f64,
|
||||
precision: &Builtin,
|
||||
float_width: FloatWidth,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
match precision {
|
||||
Builtin::Float64 => env.context.f64_type().const_float(value).into(),
|
||||
Builtin::Float32 => env.context.f32_type().const_float(value).into(),
|
||||
_ => panic!("Invalid layout for float literal = {:?}", precision),
|
||||
match float_width {
|
||||
FloatWidth::F64 => env.context.f64_type().const_float(value).into(),
|
||||
FloatWidth::F32 => env.context.f32_type().const_float(value).into(),
|
||||
FloatWidth::F128 => todo!("F128 is not implemented"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -741,12 +751,19 @@ pub fn build_exp_literal<'a, 'ctx, 'env>(
|
|||
|
||||
match literal {
|
||||
Int(int) => match layout {
|
||||
Layout::Builtin(builtin) => int_with_precision(env, *int as i128, builtin).into(),
|
||||
Layout::Builtin(Builtin::Bool) => {
|
||||
env.context.bool_type().const_int(*int as u64, false).into()
|
||||
}
|
||||
Layout::Builtin(Builtin::Int(int_width)) => {
|
||||
int_with_precision(env, *int as i128, *int_width).into()
|
||||
}
|
||||
_ => panic!("Invalid layout for int literal = {:?}", layout),
|
||||
},
|
||||
|
||||
Float(float) => match layout {
|
||||
Layout::Builtin(builtin) => float_with_precision(env, *float, builtin),
|
||||
Layout::Builtin(Builtin::Float(float_width)) => {
|
||||
float_with_precision(env, *float, *float_width)
|
||||
}
|
||||
_ => panic!("Invalid layout for float literal = {:?}", layout),
|
||||
},
|
||||
|
||||
|
@ -2131,7 +2148,6 @@ pub fn allocate_with_refcount_help<'a, 'ctx, 'env>(
|
|||
initial_refcount: IntValue<'ctx>,
|
||||
) -> PointerValue<'ctx> {
|
||||
let builder = env.builder;
|
||||
let ctx = env.context;
|
||||
|
||||
let len_type = env.ptr_int();
|
||||
|
||||
|
@ -2150,7 +2166,7 @@ pub fn allocate_with_refcount_help<'a, 'ctx, 'env>(
|
|||
|
||||
// We must return a pointer to the first element:
|
||||
let data_ptr = {
|
||||
let int_type = ptr_int(ctx, env.ptr_bytes);
|
||||
let int_type = env.ptr_int();
|
||||
let as_usize_ptr = builder
|
||||
.build_bitcast(
|
||||
ptr,
|
||||
|
@ -3044,20 +3060,18 @@ fn build_switch_ir<'a, 'ctx, 'env>(
|
|||
|
||||
// Build the condition
|
||||
let cond = match cond_layout {
|
||||
Layout::Builtin(Builtin::Float64) => {
|
||||
Layout::Builtin(Builtin::Float(float_width)) => {
|
||||
// float matches are done on the bit pattern
|
||||
cond_layout = Layout::Builtin(Builtin::Int64);
|
||||
cond_layout = Layout::float_width(float_width);
|
||||
|
||||
let int_type = match float_width {
|
||||
FloatWidth::F32 => env.context.i32_type(),
|
||||
FloatWidth::F64 => env.context.i64_type(),
|
||||
FloatWidth::F128 => env.context.i128_type(),
|
||||
};
|
||||
|
||||
builder
|
||||
.build_bitcast(cond_value, env.context.i64_type(), "")
|
||||
.into_int_value()
|
||||
}
|
||||
Layout::Builtin(Builtin::Float32) => {
|
||||
// float matches are done on the bit pattern
|
||||
cond_layout = Layout::Builtin(Builtin::Int32);
|
||||
|
||||
builder
|
||||
.build_bitcast(cond_value, env.context.i32_type(), "")
|
||||
.build_bitcast(cond_value, int_type, "")
|
||||
.into_int_value()
|
||||
}
|
||||
Layout::Union(variant) => {
|
||||
|
@ -3072,7 +3086,7 @@ fn build_switch_ir<'a, 'ctx, 'env>(
|
|||
// Build the cases
|
||||
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) {
|
||||
([(0, _, false_branch)], true_branch) | ([(1, _, true_branch)], false_branch) => {
|
||||
let then_block = context.append_basic_block(parent, "then_block");
|
||||
|
@ -3333,7 +3347,7 @@ fn expose_function_to_host_help_c_abi_generic<'a, 'ctx, 'env>(
|
|||
|
||||
builder.position_at_end(entry);
|
||||
|
||||
let wrapped_layout = roc_result_layout(env.arena, return_layout);
|
||||
let wrapped_layout = roc_result_layout(env.arena, return_layout, env.ptr_bytes);
|
||||
call_roc_function(env, roc_function, &wrapped_layout, arguments_for_call)
|
||||
} else {
|
||||
call_roc_function(env, roc_function, &return_layout, arguments_for_call)
|
||||
|
@ -3433,7 +3447,7 @@ fn expose_function_to_host_help_c_abi_gen_test<'a, 'ctx, 'env>(
|
|||
call_roc_function(
|
||||
env,
|
||||
roc_wrapper_function,
|
||||
&Layout::Struct(&[Layout::Builtin(Builtin::Int64), return_layout]),
|
||||
&Layout::Struct(&[Layout::u64(), return_layout]),
|
||||
arguments_for_call,
|
||||
)
|
||||
};
|
||||
|
@ -3810,12 +3824,8 @@ fn make_exception_catcher<'a, 'ctx, 'env>(
|
|||
function_value
|
||||
}
|
||||
|
||||
fn roc_result_layout<'a>(arena: &'a Bump, return_layout: Layout<'a>) -> Layout<'a> {
|
||||
let elements = [
|
||||
Layout::Builtin(Builtin::Int64),
|
||||
Layout::Builtin(Builtin::Usize),
|
||||
return_layout,
|
||||
];
|
||||
fn roc_result_layout<'a>(arena: &'a Bump, return_layout: Layout<'a>, ptr_bytes: u32) -> Layout<'a> {
|
||||
let elements = [Layout::u64(), Layout::usize(ptr_bytes), return_layout];
|
||||
|
||||
Layout::Struct(arena.alloc(elements))
|
||||
}
|
||||
|
@ -4940,7 +4950,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
|||
Layout::Builtin(Builtin::List(element_layout)),
|
||||
Layout::Builtin(Builtin::List(result_layout)),
|
||||
) => {
|
||||
let argument_layouts = &[Layout::Builtin(Builtin::Usize), **element_layout];
|
||||
let argument_layouts = &[Layout::usize(env.ptr_bytes), **element_layout];
|
||||
|
||||
let roc_function_call = roc_function_call(
|
||||
env,
|
||||
|
@ -5133,7 +5143,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
|||
closure_layout,
|
||||
function_owns_closure_data,
|
||||
argument_layouts,
|
||||
Layout::Builtin(Builtin::Int1),
|
||||
Layout::Builtin(Builtin::Bool),
|
||||
);
|
||||
|
||||
list_any(env, roc_function_call, list, element_layout)
|
||||
|
@ -5160,7 +5170,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
|||
closure_layout,
|
||||
function_owns_closure_data,
|
||||
argument_layouts,
|
||||
Layout::Builtin(Builtin::Int1),
|
||||
Layout::Builtin(Builtin::Bool),
|
||||
);
|
||||
|
||||
list_all(env, roc_function_call, list, element_layout)
|
||||
|
@ -5193,7 +5203,7 @@ fn run_higher_order_low_level<'a, 'ctx, 'env>(
|
|||
closure_layout,
|
||||
function_owns_closure_data,
|
||||
argument_layouts,
|
||||
Layout::Builtin(Builtin::Int1),
|
||||
Layout::Builtin(Builtin::Bool),
|
||||
);
|
||||
list_find_unsafe(env, layout_ids, roc_function_call, list, element_layout)
|
||||
}
|
||||
|
@ -5297,7 +5307,15 @@ fn run_low_level<'a, 'ctx, 'env>(
|
|||
// Str.fromInt : Int -> Str
|
||||
debug_assert_eq!(args.len(), 1);
|
||||
|
||||
str_from_int(env, scope, args[0])
|
||||
let (int, int_layout) = load_symbol_and_layout(scope, &args[0]);
|
||||
let int = int.into_int_value();
|
||||
|
||||
let int_width = match int_layout {
|
||||
Layout::Builtin(Builtin::Int(int_width)) => *int_width,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
str_from_int(env, int, int_width)
|
||||
}
|
||||
StrFromFloat => {
|
||||
// Str.fromFloat : Float * -> Str
|
||||
|
@ -5439,12 +5457,12 @@ fn run_low_level<'a, 'ctx, 'env>(
|
|||
let (low, low_layout) = load_symbol_and_layout(scope, &args[0]);
|
||||
let high = load_symbol(scope, &args[1]);
|
||||
|
||||
let builtin = match low_layout {
|
||||
Layout::Builtin(builtin) => builtin,
|
||||
let int_width = match low_layout {
|
||||
Layout::Builtin(Builtin::Int(int_width)) => *int_width,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
list_range(env, *builtin, low.into_int_value(), high.into_int_value())
|
||||
list_range(env, int_width, low.into_int_value(), high.into_int_value())
|
||||
}
|
||||
ListAppend => {
|
||||
// List.append : List elem, elem -> List elem
|
||||
|
@ -5553,17 +5571,12 @@ fn run_low_level<'a, 'ctx, 'env>(
|
|||
use roc_mono::layout::Builtin::*;
|
||||
|
||||
match arg_builtin {
|
||||
Usize | Int128 | Int64 | Int32 | Int16 | Int8 => {
|
||||
build_int_unary_op(env, arg.into_int_value(), arg_builtin, op)
|
||||
Int(int_width) => {
|
||||
let int_type = convert::int_type_from_int_width(env, *int_width);
|
||||
build_int_unary_op(env, arg.into_int_value(), int_type, op)
|
||||
}
|
||||
Float32 => {
|
||||
build_float_unary_op(env, arg.into_float_value(), op, FloatWidth::F32)
|
||||
}
|
||||
Float64 => {
|
||||
build_float_unary_op(env, arg.into_float_value(), op, FloatWidth::F64)
|
||||
}
|
||||
Float128 => {
|
||||
build_float_unary_op(env, arg.into_float_value(), op, FloatWidth::F128)
|
||||
Float(float_width) => {
|
||||
build_float_unary_op(env, arg.into_float_value(), op, *float_width)
|
||||
}
|
||||
_ => {
|
||||
unreachable!("Compiler bug: tried to run numeric operation {:?} on invalid builtin layout: ({:?})", op, arg_layout);
|
||||
|
@ -5633,15 +5646,22 @@ fn run_low_level<'a, 'ctx, 'env>(
|
|||
let tag_lt = env.context.i8_type().const_int(2_u64, false);
|
||||
|
||||
match lhs_builtin {
|
||||
Usize | Int128 | Int64 | Int32 | Int16 | Int8 => {
|
||||
Int(int_width) => {
|
||||
let are_equal = env.builder.build_int_compare(
|
||||
IntPredicate::EQ,
|
||||
lhs_arg.into_int_value(),
|
||||
rhs_arg.into_int_value(),
|
||||
"int_eq",
|
||||
);
|
||||
|
||||
let predicate = if int_width.is_signed() {
|
||||
IntPredicate::SLT
|
||||
} else {
|
||||
IntPredicate::ULT
|
||||
};
|
||||
|
||||
let is_less_than = env.builder.build_int_compare(
|
||||
IntPredicate::SLT,
|
||||
predicate,
|
||||
lhs_arg.into_int_value(),
|
||||
rhs_arg.into_int_value(),
|
||||
"int_compare",
|
||||
|
@ -5658,7 +5678,7 @@ fn run_low_level<'a, 'ctx, 'env>(
|
|||
"lt_or_gt",
|
||||
)
|
||||
}
|
||||
Float128 | Float64 | Float32 => {
|
||||
Float(_) => {
|
||||
let are_equal = env.builder.build_float_compare(
|
||||
FloatPredicate::OEQ,
|
||||
lhs_arg.into_float_value(),
|
||||
|
@ -5711,13 +5731,15 @@ fn run_low_level<'a, 'ctx, 'env>(
|
|||
let (lhs_arg, lhs_layout) = load_symbol_and_layout(scope, &args[0]);
|
||||
let (rhs_arg, rhs_layout) = load_symbol_and_layout(scope, &args[1]);
|
||||
|
||||
debug_assert_eq!(lhs_layout, rhs_layout);
|
||||
let int_width = intwidth_from_layout(*lhs_layout);
|
||||
|
||||
build_int_binop(
|
||||
env,
|
||||
parent,
|
||||
int_width,
|
||||
lhs_arg.into_int_value(),
|
||||
lhs_layout,
|
||||
rhs_arg.into_int_value(),
|
||||
rhs_layout,
|
||||
op,
|
||||
)
|
||||
}
|
||||
|
@ -5727,13 +5749,15 @@ fn run_low_level<'a, 'ctx, 'env>(
|
|||
let (lhs_arg, lhs_layout) = load_symbol_and_layout(scope, &args[0]);
|
||||
let (rhs_arg, rhs_layout) = load_symbol_and_layout(scope, &args[1]);
|
||||
|
||||
debug_assert_eq!(lhs_layout, rhs_layout);
|
||||
let int_width = intwidth_from_layout(*lhs_layout);
|
||||
|
||||
build_int_binop(
|
||||
env,
|
||||
parent,
|
||||
int_width,
|
||||
lhs_arg.into_int_value(),
|
||||
lhs_layout,
|
||||
rhs_arg.into_int_value(),
|
||||
rhs_layout,
|
||||
op,
|
||||
)
|
||||
}
|
||||
|
@ -6096,17 +6120,9 @@ fn to_cc_type_builtin<'a, 'ctx, 'env>(
|
|||
builtin: &Builtin<'a>,
|
||||
) -> BasicTypeEnum<'ctx> {
|
||||
match builtin {
|
||||
Builtin::Int128
|
||||
| Builtin::Int64
|
||||
| Builtin::Int32
|
||||
| Builtin::Int16
|
||||
| Builtin::Int8
|
||||
| Builtin::Int1
|
||||
| Builtin::Usize
|
||||
| Builtin::Decimal
|
||||
| Builtin::Float128
|
||||
| Builtin::Float64
|
||||
| Builtin::Float32 => basic_type_from_builtin(env, builtin),
|
||||
Builtin::Int(_) | Builtin::Float(_) | Builtin::Bool | Builtin::Decimal => {
|
||||
basic_type_from_builtin(env, builtin)
|
||||
}
|
||||
Builtin::Str | Builtin::EmptyStr | Builtin::List(_) | Builtin::EmptyList => {
|
||||
env.str_list_c_abi().into()
|
||||
}
|
||||
|
@ -6325,27 +6341,10 @@ fn throw_on_overflow<'a, 'ctx, 'env>(
|
|||
.unwrap()
|
||||
}
|
||||
|
||||
pub fn intwidth_from_builtin(builtin: Builtin<'_>, ptr_bytes: u32) -> IntWidth {
|
||||
use IntWidth::*;
|
||||
|
||||
match builtin {
|
||||
Builtin::Int128 => I128,
|
||||
Builtin::Int64 => I64,
|
||||
Builtin::Int32 => I32,
|
||||
Builtin::Int16 => I16,
|
||||
Builtin::Int8 => I8,
|
||||
Builtin::Usize => match ptr_bytes {
|
||||
4 => I32,
|
||||
8 => I64,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn intwidth_from_layout(layout: Layout<'_>, ptr_bytes: u32) -> IntWidth {
|
||||
fn intwidth_from_layout(layout: Layout<'_>) -> IntWidth {
|
||||
match layout {
|
||||
Layout::Builtin(builtin) => intwidth_from_builtin(builtin, ptr_bytes),
|
||||
Layout::Builtin(Builtin::Int(int_width)) => int_width,
|
||||
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
@ -6353,10 +6352,9 @@ fn intwidth_from_layout(layout: Layout<'_>, ptr_bytes: u32) -> IntWidth {
|
|||
fn build_int_binop<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
parent: FunctionValue<'ctx>,
|
||||
int_width: IntWidth,
|
||||
lhs: IntValue<'ctx>,
|
||||
lhs_layout: &Layout<'a>,
|
||||
rhs: IntValue<'ctx>,
|
||||
_rhs_layout: &Layout<'a>,
|
||||
op: LowLevel,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
use inkwell::IntPredicate::*;
|
||||
|
@ -6364,8 +6362,6 @@ fn build_int_binop<'a, 'ctx, 'env>(
|
|||
|
||||
let bd = env.builder;
|
||||
|
||||
let int_width = intwidth_from_layout(*lhs_layout, env.ptr_bytes);
|
||||
|
||||
match op {
|
||||
NumAdd => {
|
||||
let result = env
|
||||
|
@ -6541,27 +6537,24 @@ pub fn build_num_binop<'a, 'ctx, 'env>(
|
|||
build_float_binop(
|
||||
env,
|
||||
parent,
|
||||
float_width,
|
||||
lhs_arg.into_float_value(),
|
||||
rhs_arg.into_float_value(),
|
||||
float_width,
|
||||
op,
|
||||
)
|
||||
};
|
||||
|
||||
match lhs_builtin {
|
||||
Usize | Int128 | Int64 | Int32 | Int16 | Int8 => build_int_binop(
|
||||
Int(int_width) => build_int_binop(
|
||||
env,
|
||||
parent,
|
||||
*int_width,
|
||||
lhs_arg.into_int_value(),
|
||||
lhs_layout,
|
||||
rhs_arg.into_int_value(),
|
||||
rhs_layout,
|
||||
op,
|
||||
),
|
||||
|
||||
Float32 => float_binop(FloatWidth::F32),
|
||||
Float64 => float_binop(FloatWidth::F64),
|
||||
Float128 => float_binop(FloatWidth::F128),
|
||||
Float(float_width) => float_binop(*float_width),
|
||||
|
||||
Decimal => {
|
||||
build_dec_binop(env, parent, lhs_arg, lhs_layout, rhs_arg, rhs_layout, op)
|
||||
|
@ -6580,9 +6573,9 @@ pub fn build_num_binop<'a, 'ctx, 'env>(
|
|||
fn build_float_binop<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
parent: FunctionValue<'ctx>,
|
||||
float_width: FloatWidth,
|
||||
lhs: FloatValue<'ctx>,
|
||||
rhs: FloatValue<'ctx>,
|
||||
float_width: FloatWidth,
|
||||
op: LowLevel,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
use inkwell::FloatPredicate::*;
|
||||
|
@ -6843,20 +6836,10 @@ fn int_type_signed_min(int_type: IntType) -> IntValue {
|
|||
}
|
||||
}
|
||||
|
||||
fn builtin_to_int_type<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
builtin: &Builtin<'a>,
|
||||
) -> IntType<'ctx> {
|
||||
let result = basic_type_from_builtin(env, builtin);
|
||||
debug_assert!(result.is_int_type());
|
||||
|
||||
result.into_int_type()
|
||||
}
|
||||
|
||||
fn build_int_unary_op<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
arg: IntValue<'ctx>,
|
||||
arg_layout: &Builtin<'a>,
|
||||
int_type: IntType<'ctx>,
|
||||
op: LowLevel,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
use roc_module::low_level::LowLevel::*;
|
||||
|
@ -6866,11 +6849,11 @@ fn build_int_unary_op<'a, 'ctx, 'env>(
|
|||
match op {
|
||||
NumNeg => {
|
||||
// integer abs overflows when applied to the minimum value of a signed type
|
||||
int_neg_raise_on_overflow(env, arg, arg_layout)
|
||||
int_neg_raise_on_overflow(env, arg, int_type)
|
||||
}
|
||||
NumAbs => {
|
||||
// integer abs overflows when applied to the minimum value of a signed type
|
||||
int_abs_raise_on_overflow(env, arg, arg_layout)
|
||||
int_abs_raise_on_overflow(env, arg, int_type)
|
||||
}
|
||||
NumToFloat => {
|
||||
// TODO: Handle different sized numbers
|
||||
|
@ -6891,11 +6874,11 @@ fn build_int_unary_op<'a, 'ctx, 'env>(
|
|||
fn int_neg_raise_on_overflow<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
arg: IntValue<'ctx>,
|
||||
builtin: &Builtin<'a>,
|
||||
int_type: IntType<'ctx>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let builder = env.builder;
|
||||
|
||||
let min_val = int_type_signed_min(builtin_to_int_type(env, builtin));
|
||||
let min_val = int_type_signed_min(int_type);
|
||||
let condition = builder.build_int_compare(IntPredicate::EQ, arg, min_val, "is_min_val");
|
||||
|
||||
let block = env.builder.get_insert_block().expect("to be in a function");
|
||||
|
@ -6921,11 +6904,11 @@ fn int_neg_raise_on_overflow<'a, 'ctx, 'env>(
|
|||
fn int_abs_raise_on_overflow<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
arg: IntValue<'ctx>,
|
||||
builtin: &Builtin<'a>,
|
||||
int_type: IntType<'ctx>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let builder = env.builder;
|
||||
|
||||
let min_val = int_type_signed_min(builtin_to_int_type(env, builtin));
|
||||
let min_val = int_type_signed_min(int_type);
|
||||
let condition = builder.build_int_compare(IntPredicate::EQ, arg, min_val, "is_min_val");
|
||||
|
||||
let block = env.builder.get_insert_block().expect("to be in a function");
|
||||
|
@ -6945,13 +6928,13 @@ fn int_abs_raise_on_overflow<'a, 'ctx, 'env>(
|
|||
|
||||
builder.position_at_end(else_block);
|
||||
|
||||
int_abs_with_overflow(env, arg, builtin)
|
||||
int_abs_with_overflow(env, arg, int_type)
|
||||
}
|
||||
|
||||
fn int_abs_with_overflow<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
arg: IntValue<'ctx>,
|
||||
arg_layout: &Builtin<'a>,
|
||||
int_type: IntType<'ctx>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
// This is how libc's abs() is implemented - it uses no branching!
|
||||
//
|
||||
|
@ -6964,10 +6947,10 @@ fn int_abs_with_overflow<'a, 'ctx, 'env>(
|
|||
let ctx = env.context;
|
||||
let shifted_name = "abs_shift_right";
|
||||
let shifted_alloca = {
|
||||
let bits_to_shift = ((arg_layout.stack_size(env.ptr_bytes) as u64) * 8) - 1;
|
||||
let bits_to_shift = int_type.get_bit_width() as u64 - 1;
|
||||
let shift_val = ctx.i64_type().const_int(bits_to_shift, false);
|
||||
let shifted = bd.build_right_shift(arg, shift_val, true, shifted_name);
|
||||
let alloca = bd.build_alloca(basic_type_from_builtin(env, arg_layout), "#int_abs_help");
|
||||
let alloca = bd.build_alloca(int_type, "#int_abs_help");
|
||||
|
||||
// shifted = arg >>> 63
|
||||
bd.build_store(alloca, shifted);
|
||||
|
|
|
@ -123,17 +123,7 @@ fn hash_builtin<'a, 'ctx, 'env>(
|
|||
let ptr_bytes = env.ptr_bytes;
|
||||
|
||||
match builtin {
|
||||
Builtin::Int128
|
||||
| Builtin::Int64
|
||||
| Builtin::Int32
|
||||
| Builtin::Int16
|
||||
| Builtin::Int8
|
||||
| Builtin::Int1
|
||||
| Builtin::Float64
|
||||
| Builtin::Float32
|
||||
| Builtin::Float128
|
||||
| Builtin::Decimal
|
||||
| Builtin::Usize => {
|
||||
Builtin::Int(_) | Builtin::Float(_) | Builtin::Bool | Builtin::Decimal => {
|
||||
let hash_bytes = store_and_use_as_u8_ptr(env, val, layout);
|
||||
hash_bitcode_fn(env, seed, hash_bytes, layout.stack_size(ptr_bytes))
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ use inkwell::types::{BasicType, BasicTypeEnum, PointerType};
|
|||
use inkwell::values::{BasicValueEnum, FunctionValue, IntValue, PointerValue, StructValue};
|
||||
use inkwell::{AddressSpace, IntPredicate};
|
||||
use morphic_lib::UpdateMode;
|
||||
use roc_builtins::bitcode;
|
||||
use roc_builtins::bitcode::{self, IntWidth};
|
||||
use roc_mono::layout::{Builtin, Layout, LayoutIds};
|
||||
|
||||
use super::build::{load_roc_value, store_roc_value};
|
||||
|
@ -183,7 +183,7 @@ pub fn list_reverse<'a, 'ctx, 'env>(
|
|||
let element_layout = match *list_layout {
|
||||
Layout::Builtin(Builtin::EmptyList) => {
|
||||
// this pointer will never actually be dereferenced
|
||||
Layout::Builtin(Builtin::Int64)
|
||||
Layout::i64()
|
||||
}
|
||||
|
||||
Layout::Builtin(Builtin::List(elem_layout)) => *elem_layout,
|
||||
|
@ -514,7 +514,7 @@ pub fn list_walk_generic<'a, 'ctx, 'env>(
|
|||
/// List.range : Int a, Int a -> List (Int a)
|
||||
pub fn list_range<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
builtin: Builtin<'a>,
|
||||
int_width: IntWidth,
|
||||
low: IntValue<'ctx>,
|
||||
high: IntValue<'ctx>,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
|
@ -529,10 +529,7 @@ pub fn list_range<'a, 'ctx, 'env>(
|
|||
let int_width = env
|
||||
.context
|
||||
.i8_type()
|
||||
.const_int(
|
||||
crate::llvm::build::intwidth_from_builtin(builtin, env.ptr_bytes) as u64,
|
||||
false,
|
||||
)
|
||||
.const_int(int_width as u64, false)
|
||||
.into();
|
||||
|
||||
call_bitcode_fn(
|
||||
|
|
|
@ -7,13 +7,13 @@ use inkwell::builder::Builder;
|
|||
use inkwell::values::{BasicValueEnum, FunctionValue, IntValue, PointerValue, StructValue};
|
||||
use inkwell::AddressSpace;
|
||||
use morphic_lib::UpdateMode;
|
||||
use roc_builtins::bitcode;
|
||||
use roc_builtins::bitcode::{self, IntWidth};
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_mono::layout::{Builtin, Layout};
|
||||
|
||||
use super::build::{intwidth_from_builtin, load_symbol, load_symbol_and_layout};
|
||||
use super::build::load_symbol;
|
||||
|
||||
pub static CHAR_LAYOUT: Layout = Layout::Builtin(Builtin::Int8);
|
||||
pub static CHAR_LAYOUT: Layout = Layout::u8();
|
||||
|
||||
/// Str.repeat : Str, Nat -> Str
|
||||
pub fn str_repeat<'a, 'ctx, 'env>(
|
||||
|
@ -282,36 +282,10 @@ pub fn str_trim_right<'a, 'ctx, 'env>(
|
|||
/// Str.fromInt : Int -> Str
|
||||
pub fn str_from_int<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
scope: &Scope<'a, 'ctx>,
|
||||
int_symbol: Symbol,
|
||||
value: IntValue<'ctx>,
|
||||
int_width: IntWidth,
|
||||
) -> BasicValueEnum<'ctx> {
|
||||
let (int, int_layout) = load_symbol_and_layout(scope, &int_symbol);
|
||||
|
||||
match int_layout {
|
||||
Layout::Builtin(builtin) => match builtin {
|
||||
Builtin::Usize
|
||||
| Builtin::Int128
|
||||
| Builtin::Int64
|
||||
| Builtin::Int32
|
||||
| Builtin::Int16
|
||||
| Builtin::Int8 => {
|
||||
let intwidth = intwidth_from_builtin(*builtin, env.ptr_bytes);
|
||||
call_bitcode_fn(env, &[int], &bitcode::STR_FROM_INT[intwidth])
|
||||
}
|
||||
_ => {
|
||||
unreachable!(
|
||||
"Compiler bug: tried to convert numeric on invalid builtin layout: ({:?})",
|
||||
int_layout
|
||||
);
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
unreachable!(
|
||||
"Compiler bug: tried to convert numeric on invalid layout: {:?}",
|
||||
int_layout
|
||||
);
|
||||
}
|
||||
}
|
||||
call_bitcode_fn(env, &[value.into()], &bitcode::STR_FROM_INT[int_width])
|
||||
}
|
||||
|
||||
/// Str.toUtf8 : Str -> List U8
|
||||
|
|
|
@ -10,6 +10,7 @@ use inkwell::values::{
|
|||
};
|
||||
use inkwell::{AddressSpace, FloatPredicate, IntPredicate};
|
||||
use roc_builtins::bitcode;
|
||||
use roc_builtins::bitcode::{FloatWidth, IntWidth};
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_mono::layout::{Builtin, Layout, LayoutIds, UnionLayout};
|
||||
|
||||
|
@ -88,19 +89,39 @@ fn build_eq_builtin<'a, 'ctx, 'env>(
|
|||
};
|
||||
|
||||
match builtin {
|
||||
Builtin::Int128 => int_cmp(IntPredicate::EQ, "eq_i128"),
|
||||
Builtin::Int64 => int_cmp(IntPredicate::EQ, "eq_i64"),
|
||||
Builtin::Int32 => int_cmp(IntPredicate::EQ, "eq_i32"),
|
||||
Builtin::Int16 => int_cmp(IntPredicate::EQ, "eq_i16"),
|
||||
Builtin::Int8 => int_cmp(IntPredicate::EQ, "eq_i8"),
|
||||
Builtin::Int1 => int_cmp(IntPredicate::EQ, "eq_i1"),
|
||||
Builtin::Int(int_width) => {
|
||||
use IntWidth::*;
|
||||
|
||||
Builtin::Usize => int_cmp(IntPredicate::EQ, "eq_usize"),
|
||||
let name = match int_width {
|
||||
I128 => "eq_i128",
|
||||
I64 => "eq_i64",
|
||||
I32 => "eq_i32",
|
||||
I16 => "eq_i16",
|
||||
I8 => "eq_i8",
|
||||
U128 => "eq_u128",
|
||||
U64 => "eq_u64",
|
||||
U32 => "eq_u32",
|
||||
U16 => "eq_u16",
|
||||
U8 => "eq_u8",
|
||||
};
|
||||
|
||||
int_cmp(IntPredicate::EQ, name)
|
||||
}
|
||||
|
||||
Builtin::Float(float_width) => {
|
||||
use FloatWidth::*;
|
||||
|
||||
let name = match float_width {
|
||||
F128 => "eq_f128",
|
||||
F64 => "eq_f64",
|
||||
F32 => "eq_f32",
|
||||
};
|
||||
|
||||
float_cmp(FloatPredicate::OEQ, name)
|
||||
}
|
||||
|
||||
Builtin::Bool => int_cmp(IntPredicate::EQ, "eq_i1"),
|
||||
Builtin::Decimal => call_bitcode_fn(env, &[lhs_val, rhs_val], bitcode::DEC_EQ),
|
||||
Builtin::Float128 => float_cmp(FloatPredicate::OEQ, "eq_f128"),
|
||||
Builtin::Float64 => float_cmp(FloatPredicate::OEQ, "eq_f64"),
|
||||
Builtin::Float32 => float_cmp(FloatPredicate::OEQ, "eq_f32"),
|
||||
|
||||
Builtin::Str => str_equal(env, lhs_val, rhs_val),
|
||||
Builtin::List(elem) => build_list_eq(
|
||||
|
@ -231,19 +252,39 @@ fn build_neq_builtin<'a, 'ctx, 'env>(
|
|||
};
|
||||
|
||||
match builtin {
|
||||
Builtin::Int128 => int_cmp(IntPredicate::NE, "neq_i128"),
|
||||
Builtin::Int64 => int_cmp(IntPredicate::NE, "neq_i64"),
|
||||
Builtin::Int32 => int_cmp(IntPredicate::NE, "neq_i32"),
|
||||
Builtin::Int16 => int_cmp(IntPredicate::NE, "neq_i16"),
|
||||
Builtin::Int8 => int_cmp(IntPredicate::NE, "neq_i8"),
|
||||
Builtin::Int1 => int_cmp(IntPredicate::NE, "neq_i1"),
|
||||
Builtin::Int(int_width) => {
|
||||
use IntWidth::*;
|
||||
|
||||
Builtin::Usize => int_cmp(IntPredicate::NE, "neq_usize"),
|
||||
let name = match int_width {
|
||||
I128 => "neq_i128",
|
||||
I64 => "neq_i64",
|
||||
I32 => "neq_i32",
|
||||
I16 => "neq_i16",
|
||||
I8 => "neq_i8",
|
||||
U128 => "neq_u128",
|
||||
U64 => "neq_u64",
|
||||
U32 => "neq_u32",
|
||||
U16 => "neq_u16",
|
||||
U8 => "neq_u8",
|
||||
};
|
||||
|
||||
int_cmp(IntPredicate::NE, name)
|
||||
}
|
||||
|
||||
Builtin::Float(float_width) => {
|
||||
use FloatWidth::*;
|
||||
|
||||
let name = match float_width {
|
||||
F128 => "neq_f128",
|
||||
F64 => "neq_f64",
|
||||
F32 => "neq_f32",
|
||||
};
|
||||
|
||||
float_cmp(FloatPredicate::ONE, name)
|
||||
}
|
||||
|
||||
Builtin::Bool => int_cmp(IntPredicate::NE, "neq_i1"),
|
||||
Builtin::Decimal => call_bitcode_fn(env, &[lhs_val, rhs_val], bitcode::DEC_NEQ),
|
||||
Builtin::Float128 => float_cmp(FloatPredicate::ONE, "neq_f128"),
|
||||
Builtin::Float64 => float_cmp(FloatPredicate::ONE, "neq_f64"),
|
||||
Builtin::Float32 => float_cmp(FloatPredicate::ONE, "neq_f32"),
|
||||
|
||||
Builtin::Str => {
|
||||
let is_equal = str_equal(env, lhs_val, rhs_val).into_int_value();
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
use bumpalo::collections::Vec;
|
||||
use inkwell::context::Context;
|
||||
use inkwell::types::{BasicType, BasicTypeEnum, IntType, StructType};
|
||||
use inkwell::types::{BasicType, BasicTypeEnum, FloatType, IntType, StructType};
|
||||
use inkwell::AddressSpace;
|
||||
use roc_builtins::bitcode::{FloatWidth, IntWidth};
|
||||
use roc_mono::layout::{Builtin, Layout, UnionLayout};
|
||||
|
||||
fn basic_type_from_record<'a, 'ctx, 'env>(
|
||||
|
@ -143,20 +144,12 @@ pub fn basic_type_from_builtin<'a, 'ctx, 'env>(
|
|||
use Builtin::*;
|
||||
|
||||
let context = env.context;
|
||||
let ptr_bytes = env.ptr_bytes;
|
||||
|
||||
match builtin {
|
||||
Int128 => context.i128_type().as_basic_type_enum(),
|
||||
Int64 => context.i64_type().as_basic_type_enum(),
|
||||
Int32 => context.i32_type().as_basic_type_enum(),
|
||||
Int16 => context.i16_type().as_basic_type_enum(),
|
||||
Int8 => context.i8_type().as_basic_type_enum(),
|
||||
Int1 => context.bool_type().as_basic_type_enum(),
|
||||
Usize => ptr_int(context, ptr_bytes).as_basic_type_enum(),
|
||||
Int(int_width) => int_type_from_int_width(env, *int_width).as_basic_type_enum(),
|
||||
Float(float_width) => float_type_from_float_width(env, *float_width).as_basic_type_enum(),
|
||||
Bool => context.bool_type().as_basic_type_enum(),
|
||||
Decimal => context.i128_type().as_basic_type_enum(),
|
||||
Float128 => context.f128_type().as_basic_type_enum(),
|
||||
Float64 => context.f64_type().as_basic_type_enum(),
|
||||
Float32 => context.f32_type().as_basic_type_enum(),
|
||||
Dict(_, _) | EmptyDict => zig_dict_type(env).into(),
|
||||
Set(_) | EmptySet => zig_dict_type(env).into(),
|
||||
List(_) | EmptyList => zig_list_type(env).into(),
|
||||
|
@ -164,6 +157,34 @@ pub fn basic_type_from_builtin<'a, 'ctx, 'env>(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn int_type_from_int_width<'a, 'ctx, 'env>(
|
||||
env: &crate::llvm::build::Env<'a, 'ctx, 'env>,
|
||||
int_width: IntWidth,
|
||||
) -> IntType<'ctx> {
|
||||
use IntWidth::*;
|
||||
|
||||
match int_width {
|
||||
U128 | I128 => env.context.i128_type(),
|
||||
U64 | I64 => env.context.i64_type(),
|
||||
U32 | I32 => env.context.i32_type(),
|
||||
U16 | I16 => env.context.i16_type(),
|
||||
U8 | I8 => env.context.i8_type(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn float_type_from_float_width<'a, 'ctx, 'env>(
|
||||
env: &crate::llvm::build::Env<'a, 'ctx, 'env>,
|
||||
float_width: FloatWidth,
|
||||
) -> FloatType<'ctx> {
|
||||
use FloatWidth::*;
|
||||
|
||||
match float_width {
|
||||
F128 => todo!("F128 is not implemented"),
|
||||
F64 => env.context.f64_type(),
|
||||
F32 => env.context.f32_type(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn block_of_memory_slices<'ctx>(
|
||||
context: &'ctx Context,
|
||||
layouts: &[&[Layout<'_>]],
|
||||
|
@ -241,19 +262,6 @@ fn block_of_memory_help(context: &Context, union_size: u32) -> BasicTypeEnum<'_>
|
|||
}
|
||||
}
|
||||
|
||||
pub fn ptr_int(ctx: &Context, ptr_bytes: u32) -> IntType<'_> {
|
||||
match ptr_bytes {
|
||||
1 => ctx.i8_type(),
|
||||
2 => ctx.i16_type(),
|
||||
4 => ctx.i32_type(),
|
||||
8 => ctx.i64_type(),
|
||||
_ => panic!(
|
||||
"Invalid target: Roc does't support compiling to {}-bit systems.",
|
||||
ptr_bytes * 8
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// The int type that the C ABI turns our RocList/RocStr into
|
||||
pub fn str_list_int(ctx: &Context, ptr_bytes: u32) -> IntType<'_> {
|
||||
match ptr_bytes {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use crate::llvm::build::Env;
|
||||
use crate::llvm::build::{add_func, C_CALL_CONV};
|
||||
use crate::llvm::convert::ptr_int;
|
||||
use inkwell::module::Linkage;
|
||||
use inkwell::values::BasicValue;
|
||||
use inkwell::AddressSpace;
|
||||
|
@ -11,9 +10,8 @@ pub fn add_default_roc_externs(env: &Env<'_, '_, '_>) {
|
|||
let ctx = env.context;
|
||||
let module = env.module;
|
||||
let builder = env.builder;
|
||||
let ptr_bytes = env.ptr_bytes;
|
||||
|
||||
let usize_type = ptr_int(ctx, ptr_bytes);
|
||||
let usize_type = env.ptr_int();
|
||||
let i8_ptr_type = ctx.i8_type().ptr_type(AddressSpace::Generic);
|
||||
|
||||
// roc_alloc
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::llvm::build::{
|
|||
FAST_CALL_CONV, TAG_DATA_INDEX, TAG_ID_INDEX,
|
||||
};
|
||||
use crate::llvm::build_list::{incrementing_elem_loop, list_len, load_list};
|
||||
use crate::llvm::convert::{basic_type_from_layout, basic_type_from_layout_1, ptr_int};
|
||||
use crate::llvm::convert::{basic_type_from_layout, basic_type_from_layout_1};
|
||||
use bumpalo::collections::Vec;
|
||||
use inkwell::basic_block::BasicBlock;
|
||||
use inkwell::context::Context;
|
||||
|
@ -46,7 +46,7 @@ impl<'ctx> PointerToRefcount<'ctx> {
|
|||
/// alignment works out that way.
|
||||
pub unsafe fn from_ptr<'a, 'env>(env: &Env<'a, 'ctx, 'env>, ptr: PointerValue<'ctx>) -> Self {
|
||||
// must make sure it's a pointer to usize
|
||||
let refcount_type = ptr_int(env.context, env.ptr_bytes);
|
||||
let refcount_type = env.ptr_int();
|
||||
|
||||
let value = env
|
||||
.builder
|
||||
|
@ -66,7 +66,7 @@ impl<'ctx> PointerToRefcount<'ctx> {
|
|||
) -> Self {
|
||||
let builder = env.builder;
|
||||
// pointer to usize
|
||||
let refcount_type = ptr_int(env.context, env.ptr_bytes);
|
||||
let refcount_type = env.ptr_int();
|
||||
let refcount_ptr_type = refcount_type.ptr_type(AddressSpace::Generic);
|
||||
|
||||
let ptr_as_usize_ptr = builder
|
||||
|
@ -127,7 +127,7 @@ impl<'ctx> PointerToRefcount<'ctx> {
|
|||
fn increment<'a, 'env>(&self, amount: IntValue<'ctx>, env: &Env<'a, 'ctx, 'env>) {
|
||||
let refcount = self.get_refcount(env);
|
||||
let builder = env.builder;
|
||||
let refcount_type = ptr_int(env.context, env.ptr_bytes);
|
||||
let refcount_type = env.ptr_int();
|
||||
|
||||
let is_static_allocation = builder.build_int_compare(
|
||||
IntPredicate::EQ,
|
||||
|
@ -857,7 +857,7 @@ fn modify_refcount_str_help<'a, 'ctx, 'env>(
|
|||
let is_big_and_non_empty = builder.build_int_compare(
|
||||
IntPredicate::SGT,
|
||||
len,
|
||||
ptr_int(ctx, env.ptr_bytes).const_zero(),
|
||||
env.ptr_int().const_zero(),
|
||||
"is_big_str",
|
||||
);
|
||||
|
||||
|
@ -979,7 +979,7 @@ fn modify_refcount_dict_help<'a, 'ctx, 'env>(
|
|||
let is_non_empty = builder.build_int_compare(
|
||||
IntPredicate::SGT,
|
||||
len,
|
||||
ptr_int(ctx, env.ptr_bytes).const_zero(),
|
||||
env.ptr_int().const_zero(),
|
||||
"is_non_empty",
|
||||
);
|
||||
|
||||
|
@ -1027,7 +1027,7 @@ fn build_header<'a, 'ctx, 'env>(
|
|||
env,
|
||||
fn_name,
|
||||
env.context.void_type().into(),
|
||||
&[arg_type, ptr_int(env.context, env.ptr_bytes).into()],
|
||||
&[arg_type, env.ptr_int().into()],
|
||||
),
|
||||
Mode::Dec => build_header_help(env, fn_name, env.context.void_type().into(), &[arg_type]),
|
||||
}
|
||||
|
|
|
@ -277,6 +277,7 @@ impl<'a> WasmBackend<'a> {
|
|||
location,
|
||||
size,
|
||||
alignment_bytes,
|
||||
..
|
||||
} => {
|
||||
let (from_ptr, from_offset) =
|
||||
location.local_and_offset(self.storage.stack_frame_pointer);
|
||||
|
@ -328,7 +329,7 @@ impl<'a> WasmBackend<'a> {
|
|||
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();
|
||||
|
||||
// then, we jump whenever the value under scrutiny is equal to the value of a branch
|
||||
|
@ -623,6 +624,21 @@ impl<'a> WasmBackend<'a> {
|
|||
}
|
||||
|
||||
StoredValue::StackMemory { location, .. } => match lit {
|
||||
Literal::Decimal(decimal) => {
|
||||
let (local_id, offset) =
|
||||
location.local_and_offset(self.storage.stack_frame_pointer);
|
||||
|
||||
let lower_bits = decimal.0 as i64;
|
||||
let upper_bits = (decimal.0 >> 64) as i64;
|
||||
|
||||
self.code_builder.get_local(local_id);
|
||||
self.code_builder.i64_const(lower_bits);
|
||||
self.code_builder.i64_store(Align::Bytes8, offset);
|
||||
|
||||
self.code_builder.get_local(local_id);
|
||||
self.code_builder.i64_const(upper_bits);
|
||||
self.code_builder.i64_store(Align::Bytes8, offset + 8);
|
||||
}
|
||||
Literal::Str(string) => {
|
||||
let (local_id, offset) =
|
||||
location.local_and_offset(self.storage.stack_frame_pointer);
|
||||
|
|
|
@ -1,7 +1,17 @@
|
|||
use roc_builtins::bitcode::{FloatWidth, IntWidth};
|
||||
use roc_mono::layout::{Layout, UnionLayout};
|
||||
|
||||
use crate::{wasm_module::ValueType, PTR_SIZE, PTR_TYPE};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum StackMemoryFormat {
|
||||
/// Record, Str, List, Dict, etc.
|
||||
Aggregate,
|
||||
Int128,
|
||||
Float128,
|
||||
Decimal,
|
||||
}
|
||||
|
||||
// See README for background information on Wasm locals, memory and function calls
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum WasmLayout {
|
||||
|
@ -10,7 +20,11 @@ pub enum WasmLayout {
|
|||
Primitive(ValueType, u32),
|
||||
|
||||
// Local pointer to stack memory
|
||||
StackMemory { size: u32, alignment_bytes: u32 },
|
||||
StackMemory {
|
||||
size: u32,
|
||||
alignment_bytes: u32,
|
||||
format: StackMemoryFormat,
|
||||
},
|
||||
|
||||
// Local pointer to heap memory
|
||||
HeapMemory,
|
||||
|
@ -26,32 +40,51 @@ impl WasmLayout {
|
|||
let alignment_bytes = layout.alignment_bytes(PTR_SIZE);
|
||||
|
||||
match layout {
|
||||
Layout::Builtin(Int32 | Int16 | Int8 | Int1 | Usize) => Self::Primitive(I32, size),
|
||||
Layout::Builtin(Int(int_width)) => {
|
||||
use IntWidth::*;
|
||||
|
||||
Layout::Builtin(Int64) => Self::Primitive(I64, size),
|
||||
match int_width {
|
||||
I32 | U32 | I16 | U16 | I8 | U8 => Self::Primitive(ValueType::I32, size),
|
||||
I64 | U64 => Self::Primitive(ValueType::I64, size),
|
||||
I128 | U128 => Self::StackMemory {
|
||||
size,
|
||||
alignment_bytes,
|
||||
format: StackMemoryFormat::Int128,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Layout::Builtin(Float32) => Self::Primitive(F32, size),
|
||||
Layout::Builtin(Bool) => Self::Primitive(I32, size),
|
||||
|
||||
Layout::Builtin(Float64) => Self::Primitive(F64, size),
|
||||
Layout::Builtin(Float(float_width)) => {
|
||||
use FloatWidth::*;
|
||||
|
||||
match float_width {
|
||||
F32 => Self::Primitive(ValueType::F32, size),
|
||||
F64 => Self::Primitive(ValueType::F64, size),
|
||||
F128 => Self::StackMemory {
|
||||
size,
|
||||
alignment_bytes,
|
||||
format: StackMemoryFormat::Float128,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Layout::Builtin(Decimal) => Self::StackMemory {
|
||||
size,
|
||||
alignment_bytes,
|
||||
format: StackMemoryFormat::Decimal,
|
||||
},
|
||||
|
||||
Layout::Builtin(
|
||||
Int128
|
||||
| Decimal
|
||||
| Float128
|
||||
| Str
|
||||
| Dict(_, _)
|
||||
| Set(_)
|
||||
| List(_)
|
||||
| EmptyStr
|
||||
| EmptyList
|
||||
| EmptyDict
|
||||
| EmptySet,
|
||||
Str | Dict(_, _) | Set(_) | List(_) | EmptyStr | EmptyList | EmptyDict | EmptySet,
|
||||
)
|
||||
| Layout::Struct(_)
|
||||
| Layout::LambdaSet(_)
|
||||
| Layout::Union(NonRecursive(_)) => Self::StackMemory {
|
||||
size,
|
||||
alignment_bytes,
|
||||
format: StackMemoryFormat::Aggregate,
|
||||
},
|
||||
|
||||
Layout::Union(
|
||||
|
|
|
@ -4,7 +4,7 @@ use bumpalo::Bump;
|
|||
use roc_collections::all::MutMap;
|
||||
use roc_module::symbol::Symbol;
|
||||
|
||||
use crate::layout::WasmLayout;
|
||||
use crate::layout::{StackMemoryFormat, WasmLayout};
|
||||
use crate::wasm_module::{Align, CodeBuilder, LocalId, ValueType, VmSymbolState};
|
||||
use crate::{copy_memory, round_up_to_alignment, CopyMemoryConfig, PTR_SIZE, PTR_TYPE};
|
||||
|
||||
|
@ -50,6 +50,7 @@ pub enum StoredValue {
|
|||
location: StackMemoryLocation,
|
||||
size: u32,
|
||||
alignment_bytes: u32,
|
||||
format: StackMemoryFormat,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -147,6 +148,7 @@ impl<'a> Storage<'a> {
|
|||
WasmLayout::StackMemory {
|
||||
size,
|
||||
alignment_bytes,
|
||||
format,
|
||||
} => {
|
||||
let location = match kind {
|
||||
StoredValueKind::Parameter => {
|
||||
|
@ -175,6 +177,7 @@ impl<'a> Storage<'a> {
|
|||
location,
|
||||
size: *size,
|
||||
alignment_bytes: *alignment_bytes,
|
||||
format: *format,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -239,13 +242,26 @@ impl<'a> Storage<'a> {
|
|||
code_builder.set_top_symbol(sym);
|
||||
}
|
||||
|
||||
StoredValue::StackMemory { location, .. } => {
|
||||
StoredValue::StackMemory {
|
||||
location, format, ..
|
||||
} => {
|
||||
let (local_id, offset) = location.local_and_offset(self.stack_frame_pointer);
|
||||
|
||||
// Load the address of the value
|
||||
code_builder.get_local(local_id);
|
||||
if offset != 0 {
|
||||
code_builder.i32_const(offset as i32);
|
||||
code_builder.i32_add();
|
||||
}
|
||||
|
||||
if format != StackMemoryFormat::Aggregate {
|
||||
// It's one of the 128-bit numbers, all of which we load as two i64's
|
||||
// Mark the same Symbol twice in the VM value stack! Shouldn't matter except debug.
|
||||
code_builder.i64_load(Align::Bytes8, offset);
|
||||
code_builder.set_top_symbol(sym);
|
||||
code_builder.i64_load(Align::Bytes8, offset + 8);
|
||||
}
|
||||
|
||||
code_builder.set_top_symbol(sym);
|
||||
}
|
||||
}
|
||||
|
@ -292,6 +308,7 @@ impl<'a> Storage<'a> {
|
|||
location,
|
||||
size,
|
||||
alignment_bytes,
|
||||
format: StackMemoryFormat::Aggregate,
|
||||
} = self.get(sym)
|
||||
{
|
||||
if *size == 0 {
|
||||
|
@ -334,6 +351,7 @@ impl<'a> Storage<'a> {
|
|||
location,
|
||||
size,
|
||||
alignment_bytes,
|
||||
..
|
||||
} => {
|
||||
let (from_ptr, from_offset) = location.local_and_offset(self.stack_frame_pointer);
|
||||
copy_memory(
|
||||
|
@ -390,6 +408,7 @@ impl<'a> Storage<'a> {
|
|||
location,
|
||||
size,
|
||||
alignment_bytes,
|
||||
..
|
||||
} => {
|
||||
let (to_ptr, to_offset) = location.local_and_offset(self.stack_frame_pointer);
|
||||
copy_memory(
|
||||
|
@ -490,11 +509,13 @@ impl<'a> Storage<'a> {
|
|||
location: to_location,
|
||||
size: to_size,
|
||||
alignment_bytes: to_alignment_bytes,
|
||||
..
|
||||
},
|
||||
StackMemory {
|
||||
location: from_location,
|
||||
size: from_size,
|
||||
alignment_bytes: from_alignment_bytes,
|
||||
..
|
||||
},
|
||||
) => {
|
||||
let (from_ptr, from_offset) =
|
||||
|
|
|
@ -3627,11 +3627,7 @@ fn fabricate_effects_module<'a>(
|
|||
scope,
|
||||
};
|
||||
|
||||
let constraint = constrain_module(
|
||||
&module_output.aliases,
|
||||
&module_output.declarations,
|
||||
module_id,
|
||||
);
|
||||
let constraint = constrain_module(&module_output.declarations, module_id);
|
||||
|
||||
let module = Module {
|
||||
module_id,
|
||||
|
@ -3764,11 +3760,7 @@ where
|
|||
)),
|
||||
};
|
||||
|
||||
let constraint = constrain_module(
|
||||
&module_output.aliases,
|
||||
&module_output.declarations,
|
||||
module_id,
|
||||
);
|
||||
let constraint = constrain_module(&module_output.declarations, module_id);
|
||||
|
||||
let module = Module {
|
||||
module_id,
|
||||
|
|
|
@ -15,6 +15,7 @@ roc_unify = { path = "../unify" }
|
|||
roc_solve = { path = "../solve" }
|
||||
roc_std = { path = "../../roc_std" }
|
||||
roc_problem = { path = "../problem" }
|
||||
roc_builtins = { path = "../builtins" }
|
||||
ven_pretty = { path = "../../vendor/pretty" }
|
||||
morphic_lib = { path = "../../vendor/morphic_lib" }
|
||||
bumpalo = { version = "3.8.0", features = ["collections"] }
|
||||
|
|
|
@ -590,7 +590,7 @@ impl<'a> ResultRepr<'a> {
|
|||
err: tags[ERR_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),
|
||||
}
|
||||
}
|
||||
|
@ -1086,7 +1086,7 @@ fn call_spec(
|
|||
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 init_state = new_num(builder, block)?;
|
||||
|
@ -1105,7 +1105,7 @@ fn call_spec(
|
|||
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 init_state = new_num(builder, block)?;
|
||||
|
@ -1116,7 +1116,7 @@ fn call_spec(
|
|||
let list = env.symbols[xs];
|
||||
|
||||
// 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_type = layout_spec(builder, &output_layout)?;
|
||||
|
||||
|
@ -1718,8 +1718,8 @@ fn builtin_spec(
|
|||
use Builtin::*;
|
||||
|
||||
match builtin {
|
||||
Int128 | Int64 | Int32 | Int16 | Int8 | Int1 | Usize => builder.add_tuple_type(&[]),
|
||||
Decimal | Float128 | Float64 | Float32 => builder.add_tuple_type(&[]),
|
||||
Int(_) | Bool => builder.add_tuple_type(&[]),
|
||||
Decimal | Float(_) => builder.add_tuple_type(&[]),
|
||||
Str | EmptyStr => str_type(builder),
|
||||
Dict(key_layout, value_layout) => {
|
||||
let value_type = layout_spec_help(builder, value_layout, when_recursive)?;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use crate::exhaustive::{Ctor, RenderAs, TagId, Union};
|
||||
use crate::ir::{
|
||||
BranchInfo, DestructType, Env, Expr, FloatPrecision, IntPrecision, JoinPointId, Literal, Param,
|
||||
Pattern, Procs, Stmt,
|
||||
BranchInfo, DestructType, Env, Expr, JoinPointId, Literal, Param, Pattern, Procs, Stmt,
|
||||
};
|
||||
use crate::layout::{Builtin, Layout, LayoutCache, TagIdIntType, UnionLayout};
|
||||
use roc_builtins::bitcode::{FloatWidth, IntWidth};
|
||||
use roc_collections::all::{MutMap, MutSet};
|
||||
use roc_module::ident::TagName;
|
||||
use roc_module::low_level::LowLevel;
|
||||
|
@ -86,8 +86,8 @@ enum Test<'a> {
|
|||
union: crate::exhaustive::Union,
|
||||
arguments: Vec<(Pattern<'a>, Layout<'a>)>,
|
||||
},
|
||||
IsInt(i128, IntPrecision),
|
||||
IsFloat(u64, FloatPrecision),
|
||||
IsInt(i128, IntWidth),
|
||||
IsFloat(u64, FloatWidth),
|
||||
IsDecimal(RocDec),
|
||||
IsStr(Box<str>),
|
||||
IsBit(bool),
|
||||
|
@ -1300,7 +1300,7 @@ fn test_to_equality<'a>(
|
|||
debug_assert!(test_int <= i64::MAX as i128);
|
||||
let lhs = Expr::Literal(Literal::Int(test_int as i128));
|
||||
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)
|
||||
}
|
||||
|
@ -1310,7 +1310,7 @@ fn test_to_equality<'a>(
|
|||
let test_float = f64::from_bits(test_int as u64);
|
||||
let lhs = Expr::Literal(Literal::Float(test_float));
|
||||
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)
|
||||
}
|
||||
|
@ -1330,7 +1330,7 @@ fn test_to_equality<'a>(
|
|||
|
||||
let lhs = Expr::Literal(Literal::Byte(test_byte as u8));
|
||||
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)
|
||||
}
|
||||
|
@ -1338,7 +1338,7 @@ fn test_to_equality<'a>(
|
|||
Test::IsBit(test_bit) => {
|
||||
let lhs = Expr::Literal(Literal::Bool(test_bit));
|
||||
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)
|
||||
}
|
||||
|
@ -1459,7 +1459,7 @@ fn compile_test_help<'a>(
|
|||
|
||||
cond = Stmt::Switch {
|
||||
cond_symbol: test_symbol,
|
||||
cond_layout: Layout::Builtin(Builtin::Int1),
|
||||
cond_layout: Layout::Builtin(Builtin::Bool),
|
||||
ret_layout,
|
||||
branches,
|
||||
default_branch,
|
||||
|
@ -1478,7 +1478,7 @@ fn compile_test_help<'a>(
|
|||
cond = Stmt::Let(
|
||||
test_symbol,
|
||||
test,
|
||||
Layout::Builtin(Builtin::Int1),
|
||||
Layout::Builtin(Builtin::Bool),
|
||||
arena.alloc(cond),
|
||||
);
|
||||
|
||||
|
@ -1622,7 +1622,7 @@ fn decide_to_branching<'a>(
|
|||
let decide = crate::ir::cond(
|
||||
env,
|
||||
test_symbol,
|
||||
Layout::Builtin(Builtin::Int1),
|
||||
Layout::Builtin(Builtin::Bool),
|
||||
pass_expr,
|
||||
fail_expr,
|
||||
ret_layout,
|
||||
|
@ -1631,7 +1631,7 @@ fn decide_to_branching<'a>(
|
|||
// calculate the guard value
|
||||
let param = Param {
|
||||
symbol: test_symbol,
|
||||
layout: Layout::Builtin(Builtin::Int1),
|
||||
layout: Layout::Builtin(Builtin::Bool),
|
||||
borrow: false,
|
||||
};
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ use crate::layout::{
|
|||
};
|
||||
use bumpalo::collections::Vec;
|
||||
use bumpalo::Bump;
|
||||
use roc_builtins::bitcode::{FloatWidth, IntWidth};
|
||||
use roc_can::expr::ClosureData;
|
||||
use roc_collections::all::{default_hasher, BumpMap, BumpMapDefault, MutMap};
|
||||
use roc_module::ident::{ForeignSymbol, Lowercase, TagName};
|
||||
|
@ -1139,8 +1140,17 @@ impl<'a> BranchInfo<'a> {
|
|||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum ModifyRc {
|
||||
/// Increment a reference count
|
||||
Inc(Symbol, u64),
|
||||
/// Decrement a reference count
|
||||
Dec(Symbol),
|
||||
/// A DecRef is a non-recursive reference count decrement
|
||||
/// e.g. If we Dec a list of lists, then if the reference count of the outer list is one,
|
||||
/// a Dec will recursively decrement all elements, then free the memory of the outer list.
|
||||
/// A DecRef would just free the outer list.
|
||||
/// That is dangerous because you may not free the elements, but in our Zig builtins,
|
||||
/// sometimes we know we already dealt with the elements (e.g. by copying them all over
|
||||
/// to a new list) and so we can just do a DecRef, which is much cheaper in such a case.
|
||||
DecRef(Symbol),
|
||||
}
|
||||
|
||||
|
@ -2431,11 +2441,11 @@ fn specialize_external<'a>(
|
|||
}
|
||||
|
||||
ClosureRepresentation::Other(layout) => match layout {
|
||||
Layout::Builtin(Builtin::Int1) => {
|
||||
Layout::Builtin(Builtin::Bool) => {
|
||||
// just ignore this value
|
||||
// IDEA don't pass this value in the future
|
||||
}
|
||||
Layout::Builtin(Builtin::Int8) => {
|
||||
Layout::Builtin(Builtin::Int(IntWidth::U8)) => {
|
||||
// just ignore this value
|
||||
// IDEA don't pass this value in the future
|
||||
}
|
||||
|
@ -2888,20 +2898,21 @@ fn try_make_literal<'a>(
|
|||
match can_expr {
|
||||
Int(_, precision, _, int) => {
|
||||
match num_argument_to_int_or_float(env.subs, env.ptr_bytes, *precision, false) {
|
||||
IntOrFloat::SignedIntType(_) | IntOrFloat::UnsignedIntType(_) => {
|
||||
Some(Literal::Int(*int))
|
||||
}
|
||||
IntOrFloat::Int(_) => Some(Literal::Int(*int)),
|
||||
_ => unreachable!("unexpected float precision for integer"),
|
||||
}
|
||||
}
|
||||
|
||||
Float(_, precision, float_str, float) => {
|
||||
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 => {
|
||||
let dec = match RocDec::from_str(float_str) {
|
||||
Some(d) => d,
|
||||
None => panic!("Invalid decimal for float literal = {}. TODO: Make this a nice, user-friendly error message", float_str),
|
||||
None => panic!(
|
||||
r"Invalid decimal for float literal = {}. TODO: Make this a nice, user-friendly error message",
|
||||
float_str
|
||||
),
|
||||
};
|
||||
|
||||
Some(Literal::Decimal(dec))
|
||||
|
@ -2915,10 +2926,8 @@ fn try_make_literal<'a>(
|
|||
Num(var, num_str, num) => {
|
||||
// first figure out what kind of number this is
|
||||
match num_argument_to_int_or_float(env.subs, env.ptr_bytes, *var, false) {
|
||||
IntOrFloat::SignedIntType(_) | IntOrFloat::UnsignedIntType(_) => {
|
||||
Some(Literal::Int((*num).into()))
|
||||
}
|
||||
IntOrFloat::BinaryFloatType(_) => Some(Literal::Float(*num as f64)),
|
||||
IntOrFloat::Int(_) => Some(Literal::Int((*num).into())),
|
||||
IntOrFloat::Float(_) => Some(Literal::Float(*num as f64)),
|
||||
IntOrFloat::DecimalFloatType => {
|
||||
let dec = match RocDec::from_str(num_str) {
|
||||
Some(d) => d,
|
||||
|
@ -2952,16 +2961,10 @@ pub fn with_hole<'a>(
|
|||
match can_expr {
|
||||
Int(_, precision, _, int) => {
|
||||
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,
|
||||
Expr::Literal(Literal::Int(int)),
|
||||
precision.as_layout(),
|
||||
hole,
|
||||
),
|
||||
IntOrFloat::UnsignedIntType(precision) => Stmt::Let(
|
||||
assigned,
|
||||
Expr::Literal(Literal::Int(int)),
|
||||
precision.as_layout(),
|
||||
Layout::Builtin(Builtin::Int(precision)),
|
||||
hole,
|
||||
),
|
||||
_ => unreachable!("unexpected float precision for integer"),
|
||||
|
@ -2970,10 +2973,10 @@ pub fn with_hole<'a>(
|
|||
|
||||
Float(_, precision, float_str, float) => {
|
||||
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,
|
||||
Expr::Literal(Literal::Float(float)),
|
||||
precision.as_layout(),
|
||||
Layout::Builtin(Builtin::Float(precision)),
|
||||
hole,
|
||||
),
|
||||
IntOrFloat::DecimalFloatType => {
|
||||
|
@ -3002,22 +3005,16 @@ pub fn with_hole<'a>(
|
|||
Num(var, num_str, num) => {
|
||||
// first figure out what kind of number this is
|
||||
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,
|
||||
Expr::Literal(Literal::Int(num.into())),
|
||||
precision.as_layout(),
|
||||
Layout::int_width(precision),
|
||||
hole,
|
||||
),
|
||||
IntOrFloat::UnsignedIntType(precision) => Stmt::Let(
|
||||
assigned,
|
||||
Expr::Literal(Literal::Int(num.into())),
|
||||
precision.as_layout(),
|
||||
hole,
|
||||
),
|
||||
IntOrFloat::BinaryFloatType(precision) => Stmt::Let(
|
||||
IntOrFloat::Float(precision) => Stmt::Let(
|
||||
assigned,
|
||||
Expr::Literal(Literal::Float(num as f64)),
|
||||
precision.as_layout(),
|
||||
Layout::float_width(precision),
|
||||
hole,
|
||||
),
|
||||
IntOrFloat::DecimalFloatType => {
|
||||
|
@ -4402,7 +4399,7 @@ fn construct_closure_data<'a>(
|
|||
|
||||
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!(lambda_set.set.len(), 2);
|
||||
|
@ -4411,7 +4408,7 @@ fn construct_closure_data<'a>(
|
|||
|
||||
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!(lambda_set.set.len() > 2);
|
||||
|
@ -4468,7 +4465,7 @@ fn convert_tag_union<'a>(
|
|||
BoolUnion { ttrue, .. } => Stmt::Let(
|
||||
assigned,
|
||||
Expr::Literal(Literal::Bool(tag_name == ttrue)),
|
||||
Layout::Builtin(Builtin::Int1),
|
||||
Layout::Builtin(Builtin::Bool),
|
||||
hole,
|
||||
),
|
||||
ByteUnion(tag_names) => {
|
||||
|
@ -4478,7 +4475,7 @@ fn convert_tag_union<'a>(
|
|||
Some(tag_id) => Stmt::Let(
|
||||
assigned,
|
||||
Expr::Literal(Literal::Byte(tag_id as u8)),
|
||||
Layout::Builtin(Builtin::Int8),
|
||||
Layout::Builtin(Builtin::Int(IntWidth::U8)),
|
||||
hole,
|
||||
),
|
||||
None => Stmt::RuntimeError("tag must be in its own type"),
|
||||
|
@ -4989,7 +4986,7 @@ pub fn from_can<'a>(
|
|||
Expect(condition, rest) => {
|
||||
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 op = LowLevel::ExpectTrue;
|
||||
|
@ -7172,8 +7169,8 @@ fn call_specialized_proc<'a>(
|
|||
pub enum Pattern<'a> {
|
||||
Identifier(Symbol),
|
||||
Underscore,
|
||||
IntLiteral(i128, IntPrecision),
|
||||
FloatLiteral(u64, FloatPrecision),
|
||||
IntLiteral(i128, IntWidth),
|
||||
FloatLiteral(u64, FloatWidth),
|
||||
DecimalLiteral(RocDec),
|
||||
BitLiteral {
|
||||
value: bool,
|
||||
|
@ -7253,9 +7250,7 @@ fn from_can_pattern_help<'a>(
|
|||
Identifier(symbol) => Ok(Pattern::Identifier(*symbol)),
|
||||
IntLiteral(var, _, int) => {
|
||||
match num_argument_to_int_or_float(env.subs, env.ptr_bytes, *var, false) {
|
||||
IntOrFloat::SignedIntType(precision) | IntOrFloat::UnsignedIntType(precision) => {
|
||||
Ok(Pattern::IntLiteral(*int as i128, precision))
|
||||
}
|
||||
IntOrFloat::Int(precision) => Ok(Pattern::IntLiteral(*int as i128, precision)),
|
||||
other => {
|
||||
panic!(
|
||||
"Invalid precision for int pattern: {:?} has {:?}",
|
||||
|
@ -7267,10 +7262,10 @@ fn from_can_pattern_help<'a>(
|
|||
FloatLiteral(var, float_str, float) => {
|
||||
// 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) {
|
||||
IntOrFloat::SignedIntType(_) | IntOrFloat::UnsignedIntType(_) => {
|
||||
IntOrFloat::Int(_) => {
|
||||
panic!("Invalid precision for float pattern {:?}", var)
|
||||
}
|
||||
IntOrFloat::BinaryFloatType(precision) => {
|
||||
IntOrFloat::Float(precision) => {
|
||||
Ok(Pattern::FloatLiteral(f64::to_bits(*float), precision))
|
||||
}
|
||||
IntOrFloat::DecimalFloatType => {
|
||||
|
@ -7297,15 +7292,8 @@ fn from_can_pattern_help<'a>(
|
|||
}
|
||||
NumLiteral(var, num_str, num) => {
|
||||
match num_argument_to_int_or_float(env.subs, env.ptr_bytes, *var, false) {
|
||||
IntOrFloat::SignedIntType(precision) => {
|
||||
Ok(Pattern::IntLiteral(*num as i128, precision))
|
||||
}
|
||||
IntOrFloat::UnsignedIntType(precision) => {
|
||||
Ok(Pattern::IntLiteral(*num as i128, precision))
|
||||
}
|
||||
IntOrFloat::BinaryFloatType(precision) => {
|
||||
Ok(Pattern::FloatLiteral(*num as u64, precision))
|
||||
}
|
||||
IntOrFloat::Int(precision) => Ok(Pattern::IntLiteral(*num as i128, precision)),
|
||||
IntOrFloat::Float(precision) => Ok(Pattern::FloatLiteral(*num as u64, precision)),
|
||||
IntOrFloat::DecimalFloatType => {
|
||||
let dec = match RocDec::from_str(num_str) {
|
||||
Some(d) => d,
|
||||
|
@ -7887,59 +7875,10 @@ 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)]
|
||||
pub enum IntOrFloat {
|
||||
SignedIntType(IntPrecision),
|
||||
UnsignedIntType(IntPrecision),
|
||||
BinaryFloatType(FloatPrecision),
|
||||
Int(IntWidth),
|
||||
Float(FloatWidth),
|
||||
DecimalFloatType,
|
||||
}
|
||||
|
||||
|
@ -7950,9 +7889,11 @@ pub fn num_argument_to_int_or_float(
|
|||
var: Variable,
|
||||
known_to_be_float: bool,
|
||||
) -> IntOrFloat {
|
||||
match subs.get_content_without_compacting(var){
|
||||
Content::FlexVar(_) | Content::RigidVar(_) if known_to_be_float => IntOrFloat::BinaryFloatType(FloatPrecision::F64),
|
||||
Content::FlexVar(_) | Content::RigidVar(_) => IntOrFloat::SignedIntType(IntPrecision::I64), // We default (Num *) to I64
|
||||
match subs.get_content_without_compacting(var) {
|
||||
Content::FlexVar(_) | Content::RigidVar(_) if known_to_be_float => {
|
||||
IntOrFloat::Float(FloatWidth::F64)
|
||||
}
|
||||
Content::FlexVar(_) | Content::RigidVar(_) => IntOrFloat::Int(IntWidth::I64), // We default (Num *) to I64
|
||||
|
||||
Content::Alias(Symbol::NUM_INTEGER, args, _) => {
|
||||
debug_assert!(args.len() == 1);
|
||||
|
@ -7962,85 +7903,43 @@ pub fn num_argument_to_int_or_float(
|
|||
num_argument_to_int_or_float(subs, ptr_bytes, var, false)
|
||||
}
|
||||
|
||||
Content::Alias(Symbol::NUM_I128, _, _)
|
||||
| Content::Alias(Symbol::NUM_SIGNED128, _, _)
|
||||
| Content::Alias(Symbol::NUM_AT_SIGNED128, _, _) => {
|
||||
IntOrFloat::SignedIntType(IntPrecision::I128)
|
||||
other @ Content::Alias(symbol, args, _) => {
|
||||
if let Some(int_width) = IntWidth::try_from_symbol(*symbol) {
|
||||
return IntOrFloat::Int(int_width);
|
||||
}
|
||||
Content::Alias(Symbol::NUM_INT, _, _)// We default Integer to I64
|
||||
| Content::Alias(Symbol::NUM_I64, _, _)
|
||||
| Content::Alias(Symbol::NUM_SIGNED64, _, _)
|
||||
| Content::Alias(Symbol::NUM_AT_SIGNED64, _, _) => {
|
||||
IntOrFloat::SignedIntType(IntPrecision::I64)
|
||||
|
||||
if let Some(float_width) = FloatWidth::try_from_symbol(*symbol) {
|
||||
return IntOrFloat::Float(float_width);
|
||||
}
|
||||
Content::Alias(Symbol::NUM_I32, _, _)
|
||||
| Content::Alias(Symbol::NUM_SIGNED32, _, _)
|
||||
| Content::Alias(Symbol::NUM_AT_SIGNED32, _, _) => {
|
||||
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, _) => {
|
||||
|
||||
match *symbol {
|
||||
Symbol::NUM_FLOATINGPOINT => {
|
||||
debug_assert!(args.len() == 1);
|
||||
|
||||
// Recurse on the second argument
|
||||
let var = subs[args.variables().into_iter().next().unwrap()];
|
||||
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 => IntOrFloat::DecimalFloatType,
|
||||
|
||||
Symbol::NUM_NAT | Symbol::NUM_NATURAL | Symbol::NUM_AT_NATURAL => {
|
||||
let int_width = match ptr_bytes {
|
||||
4 => IntWidth::U32,
|
||||
8 => IntWidth::U64,
|
||||
_ => panic!("unsupported word size"),
|
||||
};
|
||||
|
||||
IntOrFloat::Int(int_width)
|
||||
}
|
||||
|
||||
_ => panic!(
|
||||
"Unrecognized Num type argument for var {:?} with Content: {:?}",
|
||||
var, other
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
other => {
|
||||
panic!(
|
||||
"Unrecognized Num type argument for var {:?} with Content: {:?}",
|
||||
|
@ -8122,14 +8021,14 @@ where
|
|||
hole.clone()
|
||||
}
|
||||
},
|
||||
Layout::Builtin(Builtin::Int1) => {
|
||||
Layout::Builtin(Builtin::Bool) => {
|
||||
let closure_tag_id_symbol = closure_data_symbol;
|
||||
|
||||
lowlevel_enum_lambda_set_to_switch(
|
||||
env,
|
||||
lambda_set.set,
|
||||
closure_tag_id_symbol,
|
||||
Layout::Builtin(Builtin::Int1),
|
||||
Layout::Builtin(Builtin::Bool),
|
||||
closure_data_symbol,
|
||||
lambda_set.is_represented(),
|
||||
to_lowlevel_call,
|
||||
|
@ -8138,14 +8037,14 @@ where
|
|||
hole,
|
||||
)
|
||||
}
|
||||
Layout::Builtin(Builtin::Int8) => {
|
||||
Layout::Builtin(Builtin::Int(IntWidth::U8)) => {
|
||||
let closure_tag_id_symbol = closure_data_symbol;
|
||||
|
||||
lowlevel_enum_lambda_set_to_switch(
|
||||
env,
|
||||
lambda_set.set,
|
||||
closure_tag_id_symbol,
|
||||
Layout::Builtin(Builtin::Int8),
|
||||
Layout::Builtin(Builtin::Int(IntWidth::U8)),
|
||||
closure_data_symbol,
|
||||
lambda_set.is_represented(),
|
||||
to_lowlevel_call,
|
||||
|
@ -8286,14 +8185,14 @@ fn match_on_lambda_set<'a>(
|
|||
hole,
|
||||
)
|
||||
}
|
||||
Layout::Builtin(Builtin::Int1) => {
|
||||
Layout::Builtin(Builtin::Bool) => {
|
||||
let closure_tag_id_symbol = closure_data_symbol;
|
||||
|
||||
enum_lambda_set_to_switch(
|
||||
env,
|
||||
lambda_set.set,
|
||||
closure_tag_id_symbol,
|
||||
Layout::Builtin(Builtin::Int1),
|
||||
Layout::Builtin(Builtin::Bool),
|
||||
closure_data_symbol,
|
||||
argument_symbols,
|
||||
argument_layouts,
|
||||
|
@ -8302,14 +8201,14 @@ fn match_on_lambda_set<'a>(
|
|||
hole,
|
||||
)
|
||||
}
|
||||
Layout::Builtin(Builtin::Int8) => {
|
||||
Layout::Builtin(Builtin::Int(IntWidth::U8)) => {
|
||||
let closure_tag_id_symbol = closure_data_symbol;
|
||||
|
||||
enum_lambda_set_to_switch(
|
||||
env,
|
||||
lambda_set.set,
|
||||
closure_tag_id_symbol,
|
||||
Layout::Builtin(Builtin::Int8),
|
||||
Layout::Builtin(Builtin::Int(IntWidth::U8)),
|
||||
closure_data_symbol,
|
||||
argument_symbols,
|
||||
argument_layouts,
|
||||
|
@ -8437,7 +8336,9 @@ fn union_lambda_set_branch_help<'a>(
|
|||
hole: &'a Stmt<'a>,
|
||||
) -> Stmt<'a> {
|
||||
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)
|
||||
}
|
||||
_ if lambda_set.member_does_not_need_closure_argument(function_symbol) => {
|
||||
|
@ -8562,7 +8463,9 @@ fn enum_lambda_set_branch<'a>(
|
|||
let assigned = result_symbol;
|
||||
|
||||
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)
|
||||
}
|
||||
_ => {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::ir::Parens;
|
||||
use bumpalo::collections::Vec;
|
||||
use bumpalo::Bump;
|
||||
use roc_builtins::bitcode::{FloatWidth, IntWidth};
|
||||
use roc_collections::all::{default_hasher, MutMap};
|
||||
use roc_module::ident::{Lowercase, TagName};
|
||||
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;
|
||||
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)]
|
||||
pub enum LayoutProblem {
|
||||
UnresolvedTypeVar(Variable),
|
||||
|
@ -61,60 +59,61 @@ impl<'a> RawFunctionLayout<'a> {
|
|||
// Ints
|
||||
Alias(Symbol::NUM_I128, args, _) => {
|
||||
debug_assert!(args.is_empty());
|
||||
Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Int128)))
|
||||
Ok(Self::ZeroArgumentThunk(Layout::i128()))
|
||||
}
|
||||
Alias(Symbol::NUM_I64, args, _) => {
|
||||
debug_assert!(args.is_empty());
|
||||
Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Int64)))
|
||||
Ok(Self::ZeroArgumentThunk(Layout::i64()))
|
||||
}
|
||||
Alias(Symbol::NUM_I32, args, _) => {
|
||||
debug_assert!(args.is_empty());
|
||||
Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Int32)))
|
||||
Ok(Self::ZeroArgumentThunk(Layout::i32()))
|
||||
}
|
||||
Alias(Symbol::NUM_I16, args, _) => {
|
||||
debug_assert!(args.is_empty());
|
||||
Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Int16)))
|
||||
Ok(Self::ZeroArgumentThunk(Layout::i16()))
|
||||
}
|
||||
Alias(Symbol::NUM_I8, args, _) => {
|
||||
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
|
||||
Alias(Symbol::NUM_U128, args, _) => {
|
||||
debug_assert!(args.is_empty());
|
||||
Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Int128)))
|
||||
Ok(Self::ZeroArgumentThunk(Layout::u128()))
|
||||
}
|
||||
Alias(Symbol::NUM_U64, args, _) => {
|
||||
debug_assert!(args.is_empty());
|
||||
Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Int64)))
|
||||
Ok(Self::ZeroArgumentThunk(Layout::u64()))
|
||||
}
|
||||
Alias(Symbol::NUM_U32, args, _) => {
|
||||
debug_assert!(args.is_empty());
|
||||
Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Int32)))
|
||||
Ok(Self::ZeroArgumentThunk(Layout::u32()))
|
||||
}
|
||||
Alias(Symbol::NUM_U16, args, _) => {
|
||||
debug_assert!(args.is_empty());
|
||||
Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Int16)))
|
||||
Ok(Self::ZeroArgumentThunk(Layout::u16()))
|
||||
}
|
||||
Alias(Symbol::NUM_U8, args, _) => {
|
||||
debug_assert!(args.is_empty());
|
||||
Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Int8)))
|
||||
}
|
||||
|
||||
Alias(Symbol::NUM_NAT, args, _) => {
|
||||
debug_assert!(args.is_empty());
|
||||
Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Usize)))
|
||||
Ok(Self::ZeroArgumentThunk(Layout::u8()))
|
||||
}
|
||||
|
||||
// Floats
|
||||
Alias(Symbol::NUM_F64, args, _) => {
|
||||
debug_assert!(args.is_empty());
|
||||
Ok(Self::ZeroArgumentThunk(Layout::Builtin(Builtin::Float64)))
|
||||
Ok(Self::ZeroArgumentThunk(Layout::f64()))
|
||||
}
|
||||
Alias(Symbol::NUM_F32, args, _) => {
|
||||
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(env.ptr_bytes)))
|
||||
}
|
||||
|
||||
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> {
|
||||
if union_size <= u8::MAX as usize {
|
||||
Builtin::Int8
|
||||
Builtin::Int(IntWidth::U8)
|
||||
} else if union_size <= u16::MAX as usize {
|
||||
Builtin::Int16
|
||||
Builtin::Int(IntWidth::U16)
|
||||
} else {
|
||||
panic!("tag union is too big")
|
||||
}
|
||||
|
@ -332,7 +331,7 @@ impl<'a> UnionLayout<'a> {
|
|||
// The quicksort-benchmarks version of Quicksort.roc segfaults when
|
||||
// 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...
|
||||
Builtin::Int64
|
||||
Builtin::Int(IntWidth::U64)
|
||||
}
|
||||
UnionLayout::Recursive(tags) => {
|
||||
let union_size = tags.len();
|
||||
|
@ -343,8 +342,8 @@ impl<'a> UnionLayout<'a> {
|
|||
UnionLayout::NullableWrapped { other_tags, .. } => {
|
||||
Self::tag_id_builtin_help(other_tags.len() + 1)
|
||||
}
|
||||
UnionLayout::NonNullableUnwrapped(_) => Builtin::Int1,
|
||||
UnionLayout::NullableUnwrapped { .. } => Builtin::Int1,
|
||||
UnionLayout::NonNullableUnwrapped(_) => Builtin::Bool,
|
||||
UnionLayout::NullableUnwrapped { .. } => Builtin::Bool,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -546,7 +545,8 @@ impl<'a> LambdaSet<'a> {
|
|||
// singleton, so we pass no extra argument
|
||||
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
|
||||
argument_layouts
|
||||
}
|
||||
|
@ -628,8 +628,8 @@ impl<'a> LambdaSet<'a> {
|
|||
use UnionVariant::*;
|
||||
match variant {
|
||||
Never => Layout::Union(UnionLayout::NonRecursive(&[])),
|
||||
BoolUnion { .. } => Layout::Builtin(Builtin::Int1),
|
||||
ByteUnion { .. } => Layout::Builtin(Builtin::Int8),
|
||||
BoolUnion { .. } => Layout::bool(),
|
||||
ByteUnion { .. } => Layout::u8(),
|
||||
Unit | UnitWithArguments => {
|
||||
// no useful information to store
|
||||
Layout::Struct(&[])
|
||||
|
@ -680,17 +680,10 @@ impl<'a> LambdaSet<'a> {
|
|||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum Builtin<'a> {
|
||||
Int128,
|
||||
Int64,
|
||||
Int32,
|
||||
Int16,
|
||||
Int8,
|
||||
Int1,
|
||||
Usize,
|
||||
Int(IntWidth),
|
||||
Float(FloatWidth),
|
||||
Bool,
|
||||
Decimal,
|
||||
Float128,
|
||||
Float64,
|
||||
Float32,
|
||||
Str,
|
||||
Dict(&'a Layout<'a>, &'a Layout<'a>),
|
||||
Set(&'a Layout<'a>),
|
||||
|
@ -756,67 +749,28 @@ impl<'a> Layout<'a> {
|
|||
}
|
||||
Structure(flat_type) => layout_from_flat_type(env, flat_type),
|
||||
|
||||
// Ints
|
||||
Alias(Symbol::NUM_I128, args, _) => {
|
||||
debug_assert!(args.is_empty());
|
||||
Ok(Layout::Builtin(Builtin::Int128))
|
||||
}
|
||||
Alias(Symbol::NUM_I64, args, _) => {
|
||||
debug_assert!(args.is_empty());
|
||||
Ok(Layout::Builtin(Builtin::Int64))
|
||||
}
|
||||
Alias(Symbol::NUM_I32, args, _) => {
|
||||
debug_assert!(args.is_empty());
|
||||
Ok(Layout::Builtin(Builtin::Int32))
|
||||
}
|
||||
Alias(Symbol::NUM_I16, args, _) => {
|
||||
debug_assert!(args.is_empty());
|
||||
Ok(Layout::Builtin(Builtin::Int16))
|
||||
}
|
||||
Alias(Symbol::NUM_I8, args, _) => {
|
||||
debug_assert!(args.is_empty());
|
||||
Ok(Layout::Builtin(Builtin::Int8))
|
||||
Alias(symbol, _args, actual_var) => {
|
||||
if let Some(int_width) = IntWidth::try_from_symbol(symbol) {
|
||||
return Ok(Layout::Builtin(Builtin::Int(int_width)));
|
||||
}
|
||||
|
||||
// I think unsigned and signed use the same layout
|
||||
Alias(Symbol::NUM_U128, args, _) => {
|
||||
debug_assert!(args.is_empty());
|
||||
Ok(Layout::Builtin(Builtin::Int128))
|
||||
}
|
||||
Alias(Symbol::NUM_U64, args, _) => {
|
||||
debug_assert!(args.is_empty());
|
||||
Ok(Layout::Builtin(Builtin::Int64))
|
||||
}
|
||||
Alias(Symbol::NUM_U32, args, _) => {
|
||||
debug_assert!(args.is_empty());
|
||||
Ok(Layout::Builtin(Builtin::Int32))
|
||||
}
|
||||
Alias(Symbol::NUM_U16, args, _) => {
|
||||
debug_assert!(args.is_empty());
|
||||
Ok(Layout::Builtin(Builtin::Int16))
|
||||
}
|
||||
Alias(Symbol::NUM_U8, args, _) => {
|
||||
debug_assert!(args.is_empty());
|
||||
Ok(Layout::Builtin(Builtin::Int8))
|
||||
if let Some(float_width) = FloatWidth::try_from_symbol(symbol) {
|
||||
return Ok(Layout::Builtin(Builtin::Float(float_width)));
|
||||
}
|
||||
|
||||
// Floats
|
||||
Alias(Symbol::NUM_F64, args, _) => {
|
||||
debug_assert!(args.is_empty());
|
||||
Ok(Layout::Builtin(Builtin::Float64))
|
||||
}
|
||||
Alias(Symbol::NUM_F32, args, _) => {
|
||||
debug_assert!(args.is_empty());
|
||||
Ok(Layout::Builtin(Builtin::Float32))
|
||||
match symbol {
|
||||
Symbol::NUM_DECIMAL | Symbol::NUM_AT_DECIMAL => {
|
||||
return Ok(Layout::Builtin(Builtin::Decimal))
|
||||
}
|
||||
|
||||
// Nat
|
||||
Alias(Symbol::NUM_NAT, args, _) => {
|
||||
debug_assert!(args.is_empty());
|
||||
Ok(Layout::Builtin(Builtin::Usize))
|
||||
Symbol::NUM_NAT | Symbol::NUM_NATURAL | Symbol::NUM_AT_NATURAL => {
|
||||
return Ok(Layout::usize(env.ptr_bytes))
|
||||
}
|
||||
|
||||
_ => Self::from_var(env, actual_var),
|
||||
}
|
||||
}
|
||||
|
||||
Alias(_, _, var) => Self::from_var(env, var),
|
||||
Error => Err(LayoutProblem::Erroneous),
|
||||
}
|
||||
}
|
||||
|
@ -1148,17 +1102,87 @@ impl<'a> LayoutCache<'a> {
|
|||
// placeholder for the type ven_ena::unify::Snapshot<ven_ena::unify::InPlace<CachedVariable<'a>>>
|
||||
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(ptr_bytes: u32) -> Layout<'a> {
|
||||
match ptr_bytes {
|
||||
4 => Self::u32(),
|
||||
8 => Self::u64(),
|
||||
_ => panic!("width of usize {} not supported", ptr_bytes),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bool() -> Layout<'a> {
|
||||
Layout::Builtin(Builtin::Bool)
|
||||
}
|
||||
|
||||
pub const 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()
|
||||
}
|
||||
|
||||
pub fn default_float() -> Layout<'a> {
|
||||
Layout::f64()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Builtin<'a> {
|
||||
const I128_SIZE: u32 = std::mem::size_of::<i128>() as u32;
|
||||
const I64_SIZE: u32 = std::mem::size_of::<i64>() as u32;
|
||||
const I32_SIZE: u32 = std::mem::size_of::<i32>() as u32;
|
||||
const I16_SIZE: u32 = std::mem::size_of::<i16>() as u32;
|
||||
const I8_SIZE: u32 = std::mem::size_of::<i8>() as u32;
|
||||
const I1_SIZE: u32 = std::mem::size_of::<bool>() as u32;
|
||||
const DECIMAL_SIZE: u32 = std::mem::size_of::<i128>() as u32;
|
||||
const F128_SIZE: u32 = 16;
|
||||
const F64_SIZE: u32 = std::mem::size_of::<f64>() as u32;
|
||||
const F32_SIZE: u32 = std::mem::size_of::<f32>() as u32;
|
||||
|
||||
/// Number of machine words in an empty one of these
|
||||
pub const STR_WORDS: u32 = 2;
|
||||
|
@ -1177,17 +1201,10 @@ impl<'a> Builtin<'a> {
|
|||
use Builtin::*;
|
||||
|
||||
match self {
|
||||
Int128 => Builtin::I128_SIZE,
|
||||
Int64 => Builtin::I64_SIZE,
|
||||
Int32 => Builtin::I32_SIZE,
|
||||
Int16 => Builtin::I16_SIZE,
|
||||
Int8 => Builtin::I8_SIZE,
|
||||
Int1 => Builtin::I1_SIZE,
|
||||
Usize => pointer_size,
|
||||
Int(int) => int.stack_size(),
|
||||
Float(float) => float.stack_size(),
|
||||
Bool => Builtin::I1_SIZE,
|
||||
Decimal => Builtin::DECIMAL_SIZE,
|
||||
Float128 => Builtin::F128_SIZE,
|
||||
Float64 => Builtin::F64_SIZE,
|
||||
Float32 => Builtin::F32_SIZE,
|
||||
Str | EmptyStr => Builtin::STR_WORDS * pointer_size,
|
||||
Dict(_, _) | EmptyDict => Builtin::DICT_WORDS * pointer_size,
|
||||
Set(_) | EmptySet => Builtin::SET_WORDS * pointer_size,
|
||||
|
@ -1203,17 +1220,10 @@ impl<'a> Builtin<'a> {
|
|||
// since both of those are one pointer size, the alignment of that structure is a pointer
|
||||
// size
|
||||
match self {
|
||||
Int128 => align_of::<i128>() as u32,
|
||||
Int64 => align_of::<i64>() as u32,
|
||||
Int32 => align_of::<i32>() as u32,
|
||||
Int16 => align_of::<i16>() as u32,
|
||||
Int8 => align_of::<i8>() as u32,
|
||||
Int1 => align_of::<bool>() as u32,
|
||||
Usize => pointer_size,
|
||||
Int(int_width) => int_width.alignment_bytes(),
|
||||
Float(float_width) => float_width.alignment_bytes(),
|
||||
Bool => align_of::<bool>() 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,
|
||||
Set(_) | EmptySet => pointer_size,
|
||||
// we often treat these as i128 (64-bit systems)
|
||||
|
@ -1230,8 +1240,10 @@ impl<'a> Builtin<'a> {
|
|||
use Builtin::*;
|
||||
|
||||
match self {
|
||||
Int128 | Int64 | Int32 | Int16 | Int8 | Int1 | Usize | Decimal | Float128 | Float64
|
||||
| Float32 | EmptyStr | EmptyDict | EmptyList | EmptySet => true,
|
||||
Int(_) | Float(_) | Bool | Decimal | EmptyStr | EmptyDict | EmptyList | EmptySet => {
|
||||
true
|
||||
}
|
||||
|
||||
Str | Dict(_, _) | Set(_) | List(_) => false,
|
||||
}
|
||||
}
|
||||
|
@ -1241,8 +1253,9 @@ impl<'a> Builtin<'a> {
|
|||
use Builtin::*;
|
||||
|
||||
match self {
|
||||
Int128 | Int64 | Int32 | Int16 | Int8 | Int1 | Usize | Decimal | Float128 | Float64
|
||||
| Float32 | EmptyStr | EmptyDict | EmptyList | EmptySet => false,
|
||||
Int(_) | Float(_) | Bool | Decimal | EmptyStr | EmptyDict | EmptyList | EmptySet => {
|
||||
false
|
||||
}
|
||||
List(_) => true,
|
||||
|
||||
Str | Dict(_, _) | Set(_) => true,
|
||||
|
@ -1258,17 +1271,35 @@ impl<'a> Builtin<'a> {
|
|||
use Builtin::*;
|
||||
|
||||
match self {
|
||||
Int128 => alloc.text("Int128"),
|
||||
Int64 => alloc.text("Int64"),
|
||||
Int32 => alloc.text("Int32"),
|
||||
Int16 => alloc.text("Int16"),
|
||||
Int8 => alloc.text("Int8"),
|
||||
Int1 => alloc.text("Int1"),
|
||||
Usize => alloc.text("Usize"),
|
||||
Int(int_width) => {
|
||||
use IntWidth::*;
|
||||
|
||||
match int_width {
|
||||
I128 => alloc.text("I128"),
|
||||
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"),
|
||||
Decimal => alloc.text("Decimal"),
|
||||
Float128 => alloc.text("Float128"),
|
||||
Float64 => alloc.text("Float64"),
|
||||
Float32 => alloc.text("Float32"),
|
||||
|
||||
EmptyStr => alloc.text("EmptyStr"),
|
||||
EmptyList => alloc.text("EmptyList"),
|
||||
|
@ -1292,17 +1323,9 @@ impl<'a> Builtin<'a> {
|
|||
|
||||
pub fn allocation_alignment_bytes(&self, pointer_size: u32) -> u32 {
|
||||
let allocation = match self {
|
||||
Builtin::Int128
|
||||
| Builtin::Int64
|
||||
| Builtin::Int32
|
||||
| Builtin::Int16
|
||||
| Builtin::Int8
|
||||
| Builtin::Int1
|
||||
| Builtin::Usize
|
||||
| Builtin::Decimal
|
||||
| Builtin::Float128
|
||||
| Builtin::Float64
|
||||
| Builtin::Float32 => unreachable!("not heap-allocated"),
|
||||
Builtin::Int(_) | Builtin::Float(_) | Builtin::Bool | Builtin::Decimal => {
|
||||
unreachable!("not heap-allocated")
|
||||
}
|
||||
Builtin::Str => pointer_size,
|
||||
Builtin::Dict(k, v) => k
|
||||
.alignment_bytes(pointer_size)
|
||||
|
@ -1337,49 +1360,49 @@ fn layout_from_flat_type<'a>(
|
|||
// Ints
|
||||
Symbol::NUM_NAT => {
|
||||
debug_assert_eq!(args.len(), 0);
|
||||
Ok(Layout::Builtin(Builtin::Usize))
|
||||
Ok(Layout::usize(env.ptr_bytes))
|
||||
}
|
||||
|
||||
Symbol::NUM_I128 => {
|
||||
debug_assert_eq!(args.len(), 0);
|
||||
Ok(Layout::Builtin(Builtin::Int128))
|
||||
Ok(Layout::i128())
|
||||
}
|
||||
Symbol::NUM_I64 => {
|
||||
debug_assert_eq!(args.len(), 0);
|
||||
Ok(Layout::Builtin(Builtin::Int64))
|
||||
Ok(Layout::i64())
|
||||
}
|
||||
Symbol::NUM_I32 => {
|
||||
debug_assert_eq!(args.len(), 0);
|
||||
Ok(Layout::Builtin(Builtin::Int32))
|
||||
Ok(Layout::i32())
|
||||
}
|
||||
Symbol::NUM_I16 => {
|
||||
debug_assert_eq!(args.len(), 0);
|
||||
Ok(Layout::Builtin(Builtin::Int16))
|
||||
Ok(Layout::i16())
|
||||
}
|
||||
Symbol::NUM_I8 => {
|
||||
debug_assert_eq!(args.len(), 0);
|
||||
Ok(Layout::Builtin(Builtin::Int8))
|
||||
Ok(Layout::i8())
|
||||
}
|
||||
|
||||
Symbol::NUM_U128 => {
|
||||
debug_assert_eq!(args.len(), 0);
|
||||
Ok(Layout::Builtin(Builtin::Int128))
|
||||
Ok(Layout::u128())
|
||||
}
|
||||
Symbol::NUM_U64 => {
|
||||
debug_assert_eq!(args.len(), 0);
|
||||
Ok(Layout::Builtin(Builtin::Int64))
|
||||
Ok(Layout::u64())
|
||||
}
|
||||
Symbol::NUM_U32 => {
|
||||
debug_assert_eq!(args.len(), 0);
|
||||
Ok(Layout::Builtin(Builtin::Int32))
|
||||
Ok(Layout::u32())
|
||||
}
|
||||
Symbol::NUM_U16 => {
|
||||
debug_assert_eq!(args.len(), 0);
|
||||
Ok(Layout::Builtin(Builtin::Int16))
|
||||
Ok(Layout::u16())
|
||||
}
|
||||
Symbol::NUM_U8 => {
|
||||
debug_assert_eq!(args.len(), 0);
|
||||
Ok(Layout::Builtin(Builtin::Int8))
|
||||
Ok(Layout::u8())
|
||||
}
|
||||
|
||||
// Floats
|
||||
|
@ -1389,11 +1412,11 @@ fn layout_from_flat_type<'a>(
|
|||
}
|
||||
Symbol::NUM_F64 => {
|
||||
debug_assert_eq!(args.len(), 0);
|
||||
Ok(Layout::Builtin(Builtin::Float64))
|
||||
Ok(Layout::f64())
|
||||
}
|
||||
Symbol::NUM_F32 => {
|
||||
debug_assert_eq!(args.len(), 0);
|
||||
Ok(Layout::Builtin(Builtin::Float32))
|
||||
Ok(Layout::f32())
|
||||
}
|
||||
|
||||
Symbol::NUM_NUM | Symbol::NUM_AT_NUM => {
|
||||
|
@ -1555,9 +1578,7 @@ fn layout_from_flat_type<'a>(
|
|||
|
||||
Ok(Layout::Union(union_layout))
|
||||
}
|
||||
EmptyTagUnion => {
|
||||
panic!("TODO make Layout for empty Tag Union");
|
||||
}
|
||||
EmptyTagUnion => Ok(Layout::Union(UnionLayout::NonRecursive(&[]))),
|
||||
Erroneous(_) => Err(LayoutProblem::Erroneous),
|
||||
EmptyRecord => Ok(Layout::Struct(&[])),
|
||||
}
|
||||
|
@ -1824,7 +1845,7 @@ fn union_sorted_tags_help_new<'a>(
|
|||
match tag_name {
|
||||
TagName::Private(Symbol::NUM_AT_NUM) => {
|
||||
let var = subs[arguments.into_iter().next().unwrap()];
|
||||
layouts.push(unwrap_num_tag(subs, var).expect("invalid num layout"));
|
||||
layouts.push(unwrap_num_tag(subs, var, ptr_bytes).expect("invalid num layout"));
|
||||
}
|
||||
_ => {
|
||||
for var_index in arguments {
|
||||
|
@ -2027,7 +2048,9 @@ pub fn union_sorted_tags_help<'a>(
|
|||
// special-case NUM_AT_NUM: if its argument is a FlexVar, make it Int
|
||||
match tag_name {
|
||||
TagName::Private(Symbol::NUM_AT_NUM) => {
|
||||
layouts.push(unwrap_num_tag(subs, arguments[0]).expect("invalid num layout"));
|
||||
layouts.push(
|
||||
unwrap_num_tag(subs, arguments[0], ptr_bytes).expect("invalid num layout"),
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
for var in arguments {
|
||||
|
@ -2239,7 +2262,7 @@ fn layout_from_newtype<'a>(
|
|||
let tag_name = &subs[tag_name_index];
|
||||
|
||||
if tag_name == &TagName::Private(Symbol::NUM_AT_NUM) {
|
||||
unwrap_num_tag(subs, var).expect("invalid Num argument")
|
||||
unwrap_num_tag(subs, var, ptr_bytes).expect("invalid Num argument")
|
||||
} else {
|
||||
let mut env = Env {
|
||||
arena,
|
||||
|
@ -2286,7 +2309,7 @@ fn layout_from_tag_union<'a>(
|
|||
let var_index = arguments.into_iter().next().unwrap();
|
||||
let var = subs[var_index];
|
||||
|
||||
unwrap_num_tag(subs, var).expect("invalid Num argument")
|
||||
unwrap_num_tag(subs, var, ptr_bytes).expect("invalid Num argument")
|
||||
}
|
||||
_ => {
|
||||
let opt_rec_var = None;
|
||||
|
@ -2295,8 +2318,8 @@ fn layout_from_tag_union<'a>(
|
|||
match variant {
|
||||
Never => Layout::Union(UnionLayout::NonRecursive(&[])),
|
||||
Unit | UnitWithArguments => Layout::Struct(&[]),
|
||||
BoolUnion { .. } => Layout::Builtin(Builtin::Int1),
|
||||
ByteUnion(_) => Layout::Builtin(Builtin::Int8),
|
||||
BoolUnion { .. } => Layout::bool(),
|
||||
ByteUnion(_) => Layout::u8(),
|
||||
Newtype {
|
||||
arguments: field_layouts,
|
||||
..
|
||||
|
@ -2389,6 +2412,8 @@ fn layout_from_num_content<'a>(content: &Content) -> Result<Layout<'a>, LayoutPr
|
|||
use roc_types::subs::Content::*;
|
||||
use roc_types::subs::FlatType::*;
|
||||
|
||||
let ptr_bytes = 8;
|
||||
|
||||
match content {
|
||||
RecursionVar { .. } => panic!("recursion var in num"),
|
||||
FlexVar(_) | RigidVar(_) => {
|
||||
|
@ -2396,30 +2421,32 @@ fn layout_from_num_content<'a>(content: &Content) -> Result<Layout<'a>, LayoutPr
|
|||
// type variable, then assume it's a 64-bit integer.
|
||||
//
|
||||
// (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 {
|
||||
// Ints
|
||||
Symbol::NUM_NAT => Ok(Layout::Builtin(Builtin::Usize)),
|
||||
Symbol::NUM_NAT => Ok(Layout::usize(ptr_bytes)),
|
||||
|
||||
Symbol::NUM_INTEGER => Ok(Layout::Builtin(Builtin::Int64)),
|
||||
Symbol::NUM_I128 => Ok(Layout::Builtin(Builtin::Int128)),
|
||||
Symbol::NUM_I64 => Ok(Layout::Builtin(Builtin::Int64)),
|
||||
Symbol::NUM_I32 => Ok(Layout::Builtin(Builtin::Int32)),
|
||||
Symbol::NUM_I16 => Ok(Layout::Builtin(Builtin::Int16)),
|
||||
Symbol::NUM_I8 => Ok(Layout::Builtin(Builtin::Int8)),
|
||||
Symbol::NUM_INTEGER => Ok(Layout::i64()),
|
||||
Symbol::NUM_I128 => Ok(Layout::i128()),
|
||||
Symbol::NUM_I64 => Ok(Layout::i64()),
|
||||
Symbol::NUM_I32 => Ok(Layout::i32()),
|
||||
Symbol::NUM_I16 => Ok(Layout::i16()),
|
||||
Symbol::NUM_I8 => Ok(Layout::i8()),
|
||||
|
||||
Symbol::NUM_U128 => Ok(Layout::Builtin(Builtin::Int128)),
|
||||
Symbol::NUM_U64 => Ok(Layout::Builtin(Builtin::Int64)),
|
||||
Symbol::NUM_U32 => Ok(Layout::Builtin(Builtin::Int32)),
|
||||
Symbol::NUM_U16 => Ok(Layout::Builtin(Builtin::Int16)),
|
||||
Symbol::NUM_U8 => Ok(Layout::Builtin(Builtin::Int8)),
|
||||
Symbol::NUM_U128 => Ok(Layout::u128()),
|
||||
Symbol::NUM_U64 => Ok(Layout::u64()),
|
||||
Symbol::NUM_U32 => Ok(Layout::u32()),
|
||||
Symbol::NUM_U16 => Ok(Layout::u16()),
|
||||
Symbol::NUM_U8 => Ok(Layout::u8()),
|
||||
|
||||
// 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_F64 => Ok(Layout::Builtin(Builtin::Float64)),
|
||||
Symbol::NUM_F32 => Ok(Layout::Builtin(Builtin::Float32)),
|
||||
|
||||
_ => {
|
||||
panic!(
|
||||
|
@ -2438,7 +2465,11 @@ fn layout_from_num_content<'a>(content: &Content) -> Result<Layout<'a>, LayoutPr
|
|||
}
|
||||
}
|
||||
|
||||
fn unwrap_num_tag<'a>(subs: &Subs, var: Variable) -> Result<Layout<'a>, LayoutProblem> {
|
||||
fn unwrap_num_tag<'a>(
|
||||
subs: &Subs,
|
||||
var: Variable,
|
||||
ptr_bytes: u32,
|
||||
) -> Result<Layout<'a>, LayoutProblem> {
|
||||
match subs.get_content_without_compacting(var) {
|
||||
Content::Alias(Symbol::NUM_INTEGER, args, _) => {
|
||||
debug_assert!(args.len() == 1);
|
||||
|
@ -2451,26 +2482,27 @@ fn unwrap_num_tag<'a>(subs: &Subs, var: Variable) -> Result<Layout<'a>, LayoutPr
|
|||
Content::Alias(symbol, args, _) => {
|
||||
debug_assert!(args.is_empty());
|
||||
|
||||
let builtin = match *symbol {
|
||||
Symbol::NUM_SIGNED128 => Builtin::Int128,
|
||||
Symbol::NUM_SIGNED64 => Builtin::Int64,
|
||||
Symbol::NUM_SIGNED32 => Builtin::Int32,
|
||||
Symbol::NUM_SIGNED16 => Builtin::Int16,
|
||||
Symbol::NUM_SIGNED8 => Builtin::Int8,
|
||||
Symbol::NUM_UNSIGNED128 => Builtin::Int128,
|
||||
Symbol::NUM_UNSIGNED64 => Builtin::Int64,
|
||||
Symbol::NUM_UNSIGNED32 => Builtin::Int32,
|
||||
Symbol::NUM_UNSIGNED16 => Builtin::Int16,
|
||||
Symbol::NUM_UNSIGNED8 => Builtin::Int8,
|
||||
Symbol::NUM_NATURAL => Builtin::Usize,
|
||||
let layout = match *symbol {
|
||||
Symbol::NUM_SIGNED128 => Layout::i128(),
|
||||
Symbol::NUM_SIGNED64 => Layout::i64(),
|
||||
Symbol::NUM_SIGNED32 => Layout::i32(),
|
||||
Symbol::NUM_SIGNED16 => Layout::i16(),
|
||||
Symbol::NUM_SIGNED8 => Layout::i8(),
|
||||
Symbol::NUM_UNSIGNED128 => Layout::u128(),
|
||||
Symbol::NUM_UNSIGNED64 => Layout::u64(),
|
||||
Symbol::NUM_UNSIGNED32 => Layout::u32(),
|
||||
Symbol::NUM_UNSIGNED16 => Layout::u16(),
|
||||
Symbol::NUM_UNSIGNED8 => Layout::u8(),
|
||||
Symbol::NUM_NATURAL => Layout::usize(ptr_bytes),
|
||||
|
||||
_ => unreachable!("not a valid int variant: {:?} {:?}", symbol, args),
|
||||
};
|
||||
|
||||
Ok(Layout::Builtin(builtin))
|
||||
Ok(layout)
|
||||
}
|
||||
Content::FlexVar(_) | Content::RigidVar(_) => {
|
||||
// default to i64
|
||||
Ok(Layout::Builtin(Builtin::Int64))
|
||||
Ok(Layout::i64())
|
||||
}
|
||||
_ => unreachable!("not a valid int variant: {:?}", precision),
|
||||
}
|
||||
|
@ -2486,12 +2518,12 @@ fn unwrap_num_tag<'a>(subs: &Subs, var: Variable) -> Result<Layout<'a>, LayoutPr
|
|||
Content::Alias(Symbol::NUM_BINARY32, args, _) => {
|
||||
debug_assert!(args.is_empty());
|
||||
|
||||
Ok(Layout::Builtin(Builtin::Float32))
|
||||
Ok(Layout::f32())
|
||||
}
|
||||
Content::Alias(Symbol::NUM_BINARY64, args, _) => {
|
||||
debug_assert!(args.is_empty());
|
||||
|
||||
Ok(Layout::Builtin(Builtin::Float64))
|
||||
Ok(Layout::f64())
|
||||
}
|
||||
Content::Alias(Symbol::NUM_DECIMAL, args, _) => {
|
||||
debug_assert!(args.is_empty());
|
||||
|
@ -2500,14 +2532,14 @@ fn unwrap_num_tag<'a>(subs: &Subs, var: Variable) -> Result<Layout<'a>, LayoutPr
|
|||
}
|
||||
Content::FlexVar(_) | Content::RigidVar(_) => {
|
||||
// default to f64
|
||||
Ok(Layout::Builtin(Builtin::Float64))
|
||||
Ok(Layout::f64())
|
||||
}
|
||||
_ => unreachable!("not a valid float variant: {:?}", precision),
|
||||
}
|
||||
}
|
||||
Content::FlexVar(_) | Content::RigidVar(_) => {
|
||||
// If this was still a (Num *) then default to compiling it to i64
|
||||
Ok(Layout::Builtin(DEFAULT_NUM_BUILTIN))
|
||||
Ok(Layout::default_integer())
|
||||
}
|
||||
other => {
|
||||
todo!("TODO non structure Num.@Num flat_type {:?}", other);
|
||||
|
|
|
@ -686,6 +686,10 @@ fn type_to_variable<'a>(
|
|||
register(subs, rank, pools, content)
|
||||
}
|
||||
Record(fields, ext) => {
|
||||
// An empty fields is inefficient (but would be correct)
|
||||
// If hit, try to turn the value into an EmptyRecord in canonicalization
|
||||
debug_assert!(!fields.is_empty() || !ext.is_empty_record());
|
||||
|
||||
let mut field_vars = Vec::with_capacity_in(fields.len(), arena);
|
||||
|
||||
for (field, field_type) in fields {
|
||||
|
@ -714,6 +718,10 @@ fn type_to_variable<'a>(
|
|||
register(subs, rank, pools, content)
|
||||
}
|
||||
TagUnion(tags, ext) => {
|
||||
// An empty tags is inefficient (but would be correct)
|
||||
// If hit, try to turn the value into an EmptyTagUnion in canonicalization
|
||||
debug_assert!(!tags.is_empty() || !ext.is_empty_tag_union());
|
||||
|
||||
let (union_tags, ext) = type_to_union_tags(subs, rank, pools, arena, tags, ext);
|
||||
let content = Content::Structure(FlatType::TagUnion(union_tags, ext));
|
||||
|
||||
|
@ -742,6 +750,10 @@ fn type_to_variable<'a>(
|
|||
register(subs, rank, pools, content)
|
||||
}
|
||||
RecursiveTagUnion(rec_var, tags, ext) => {
|
||||
// An empty tags is inefficient (but would be correct)
|
||||
// If hit, try to turn the value into an EmptyTagUnion in canonicalization
|
||||
debug_assert!(!tags.is_empty() || !ext.is_empty_tag_union());
|
||||
|
||||
let (union_tags, ext) = type_to_union_tags(subs, rank, pools, arena, tags, ext);
|
||||
let content =
|
||||
Content::Structure(FlatType::RecursiveTagUnion(*rec_var, union_tags, ext));
|
||||
|
|
|
@ -4604,4 +4604,117 @@ mod solve_expr {
|
|||
"RBTree {}",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inference_var_inside_arrow() {
|
||||
infer_eq_without_problem(
|
||||
indoc!(
|
||||
r#"
|
||||
id : _ -> _
|
||||
id = \x -> x
|
||||
id
|
||||
"#
|
||||
),
|
||||
"a -> a",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inference_var_inside_ctor() {
|
||||
infer_eq_without_problem(
|
||||
indoc!(
|
||||
r#"
|
||||
canIGo : _ -> Result _ _
|
||||
canIGo = \color ->
|
||||
when color is
|
||||
"green" -> Ok "go!"
|
||||
"yellow" -> Err (SlowIt "whoa, let's slow down!")
|
||||
"red" -> Err (StopIt "absolutely not")
|
||||
_ -> Err (UnknownColor "this is a weird stoplight")
|
||||
canIGo
|
||||
"#
|
||||
),
|
||||
"Str -> Result Str [ SlowIt Str, StopIt Str, UnknownColor Str ]*",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inference_var_inside_ctor_linked() {
|
||||
infer_eq_without_problem(
|
||||
indoc!(
|
||||
r#"
|
||||
swapRcd: {x: _, y: _} -> {x: _, y: _}
|
||||
swapRcd = \{x, y} -> {x: y, y: x}
|
||||
swapRcd
|
||||
"#
|
||||
),
|
||||
"{ x : a, y : b } -> { x : b, y : a }",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inference_var_link_with_rigid() {
|
||||
infer_eq_without_problem(
|
||||
indoc!(
|
||||
r#"
|
||||
swapRcd: {x: tx, y: ty} -> {x: _, y: _}
|
||||
swapRcd = \{x, y} -> {x: y, y: x}
|
||||
swapRcd
|
||||
"#
|
||||
),
|
||||
"{ x : tx, y : ty } -> { x : ty, y : tx }",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inference_var_inside_tag_ctor() {
|
||||
infer_eq_without_problem(
|
||||
indoc!(
|
||||
r#"
|
||||
badComics: Bool -> [ CowTools _, Thagomizer _ ]
|
||||
badComics = \c ->
|
||||
when c is
|
||||
True -> CowTools "The Far Side"
|
||||
False -> Thagomizer "The Far Side"
|
||||
badComics
|
||||
"#
|
||||
),
|
||||
"Bool -> [ CowTools Str, Thagomizer Str ]",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inference_var_tag_union_ext() {
|
||||
// TODO: we should really be inferring [ Blue, Orange ]a -> [ Lavender, Peach ]a here.
|
||||
// See https://github.com/rtfeldman/roc/issues/2053
|
||||
infer_eq_without_problem(
|
||||
indoc!(
|
||||
r#"
|
||||
pastelize: _ -> [ Lavender, Peach ]_
|
||||
pastelize = \color ->
|
||||
when color is
|
||||
Blue -> Lavender
|
||||
Orange -> Peach
|
||||
col -> col
|
||||
pastelize
|
||||
"#
|
||||
),
|
||||
"[ Blue, Lavender, Orange, Peach ]a -> [ Blue, Lavender, Orange, Peach ]a",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inference_var_rcd_union_ext() {
|
||||
infer_eq_without_problem(
|
||||
indoc!(
|
||||
r#"
|
||||
setRocEmail : _ -> { name: Str, email: Str }_
|
||||
setRocEmail = \person ->
|
||||
{ person & email: "\(person.name)@roclang.com" }
|
||||
setRocEmail
|
||||
"#
|
||||
),
|
||||
"{ email : Str, name : Str }a -> { email : Str, name : Str }a",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -358,7 +358,7 @@ fn u8_hex_int_alias() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn dec_float_alias() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
|
|
|
@ -16,11 +16,10 @@ use roc_std::{RocList, RocStr};
|
|||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm"))]
|
||||
fn width_and_alignment_u8_u8() {
|
||||
use roc_mono::layout::Builtin;
|
||||
use roc_mono::layout::Layout;
|
||||
use roc_mono::layout::UnionLayout;
|
||||
|
||||
let t = &[Layout::Builtin(Builtin::Int8)] as &[_];
|
||||
let t = &[Layout::u8()] as &[_];
|
||||
let tt = [t, t];
|
||||
|
||||
let layout = Layout::Union(UnionLayout::NonRecursive(&tt));
|
||||
|
|
|
@ -5,6 +5,9 @@ use roc_can::builtins::builtin_defs_map;
|
|||
use roc_collections::all::MutMap;
|
||||
use tempfile::tempdir;
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use roc_mono::ir::PRETTY_PRINT_IR_SYMBOLS;
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn promote_expr_to_module(src: &str) -> String {
|
||||
let mut buffer = String::from("app \"test\" provides [ main ] to \"./platform\"\n\nmain =\n");
|
||||
|
@ -77,7 +80,14 @@ pub fn helper(
|
|||
// while you're working on the dev backend!
|
||||
{
|
||||
// println!("=========== Procedures ==========");
|
||||
// println!("{:?}", procedures);
|
||||
// if PRETTY_PRINT_IR_SYMBOLS {
|
||||
// println!("");
|
||||
// for proc in procedures.values() {
|
||||
// println!("{}", proc.to_pretty(200));
|
||||
// }
|
||||
// } else {
|
||||
// println!("{:?}", procedures.values());
|
||||
// }
|
||||
// println!("=================================\n");
|
||||
|
||||
// println!("=========== Interns ==========");
|
||||
|
|
|
@ -17,6 +17,9 @@ use roc_gen_wasm::wasm_module::{
|
|||
};
|
||||
use roc_gen_wasm::MEMORY_NAME;
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use roc_mono::ir::PRETTY_PRINT_IR_SYMBOLS;
|
||||
|
||||
const TEST_WRAPPER_NAME: &str = "test_wrapper";
|
||||
|
||||
std::thread_local! {
|
||||
|
@ -60,6 +63,7 @@ pub fn helper_wasm<'a, T: Wasm32TestResult>(
|
|||
}
|
||||
|
||||
let exposed_types = MutMap::default();
|
||||
let ptr_bytes = 4;
|
||||
let loaded = roc_load::file::load_and_monomorphize_from_str(
|
||||
arena,
|
||||
filename,
|
||||
|
@ -67,7 +71,7 @@ pub fn helper_wasm<'a, T: Wasm32TestResult>(
|
|||
stdlib,
|
||||
src_dir,
|
||||
exposed_types,
|
||||
8,
|
||||
ptr_bytes,
|
||||
builtin_defs_map,
|
||||
);
|
||||
|
||||
|
@ -83,9 +87,16 @@ pub fn helper_wasm<'a, T: Wasm32TestResult>(
|
|||
|
||||
// You can comment and uncomment this block out to get more useful information
|
||||
// while you're working on the wasm backend!
|
||||
// {
|
||||
{
|
||||
// println!("=========== Procedures ==========");
|
||||
// println!("{:?}", procedures);
|
||||
// if PRETTY_PRINT_IR_SYMBOLS {
|
||||
// println!("");
|
||||
// for proc in procedures.values() {
|
||||
// println!("{}", proc.to_pretty(200));
|
||||
// }
|
||||
// } else {
|
||||
// println!("{:?}", procedures.values());
|
||||
// }
|
||||
// println!("=================================\n");
|
||||
|
||||
// println!("=========== Interns ==========");
|
||||
|
@ -95,7 +106,7 @@ pub fn helper_wasm<'a, T: Wasm32TestResult>(
|
|||
// println!("=========== Exposed ==========");
|
||||
// println!("{:?}", exposed_to_host);
|
||||
// println!("=================================\n");
|
||||
// }
|
||||
}
|
||||
|
||||
debug_assert_eq!(exposed_to_host.len(), 1);
|
||||
|
||||
|
|
|
@ -1057,12 +1057,14 @@ impl Subs {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn fresh(&mut self, value: Descriptor) -> Variable {
|
||||
self.utable.new_key(value)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn fresh_unnamed_flex_var(&mut self) -> Variable {
|
||||
self.fresh(unnamed_flex_var().into())
|
||||
self.fresh(Descriptor::from(unnamed_flex_var()))
|
||||
}
|
||||
|
||||
pub fn rigid_var(&mut self, var: Variable, name: Lowercase) {
|
||||
|
@ -1091,6 +1093,7 @@ impl Subs {
|
|||
&self.utable.probe_value_ref(key).value
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get_ref_mut(&mut self, key: Variable) -> &mut Descriptor {
|
||||
&mut self.utable.probe_value_ref_mut(key).value
|
||||
}
|
||||
|
@ -1109,6 +1112,7 @@ impl Subs {
|
|||
(desc.rank, desc.mark)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get_without_compacting(&self, key: Variable) -> Descriptor {
|
||||
self.utable.probe_value_without_compacting(key)
|
||||
}
|
||||
|
@ -1125,6 +1129,7 @@ impl Subs {
|
|||
self.utable.get_root_key_without_compacting(key)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn set(&mut self, key: Variable, r_value: Descriptor) {
|
||||
let l_key = self.utable.get_root_key(key);
|
||||
|
||||
|
@ -1261,7 +1266,7 @@ fn flex_var_descriptor() -> Descriptor {
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn unnamed_flex_var() -> Content {
|
||||
const fn unnamed_flex_var() -> Content {
|
||||
Content::FlexVar(None)
|
||||
}
|
||||
|
||||
|
|
|
@ -436,6 +436,14 @@ impl Type {
|
|||
matches!(self, Type::RecursiveTagUnion(_, _, _))
|
||||
}
|
||||
|
||||
pub fn is_empty_tag_union(&self) -> bool {
|
||||
matches!(self, Type::EmptyTagUnion)
|
||||
}
|
||||
|
||||
pub fn is_empty_record(&self) -> bool {
|
||||
matches!(self, Type::EmptyRec)
|
||||
}
|
||||
|
||||
pub fn variables(&self) -> ImSet<Variable> {
|
||||
let mut result = ImSet::default();
|
||||
variables_help(self, &mut result);
|
||||
|
|
|
@ -6667,4 +6667,102 @@ I need all branches in an `if` to have the same type!
|
|||
),
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inference_var_not_enough_in_alias() {
|
||||
report_problem_as(
|
||||
indoc!(
|
||||
r#"
|
||||
canIGo : _ -> Result _
|
||||
canIGo = \color ->
|
||||
when color is
|
||||
"green" -> Ok "go!"
|
||||
"yellow" -> Err (SlowIt "whoa, let's slow down!")
|
||||
"red" -> Err (StopIt "absolutely not")
|
||||
_ -> Err (UnknownColor "this is a weird stoplight")
|
||||
canIGo
|
||||
"#
|
||||
),
|
||||
indoc!(
|
||||
r#"
|
||||
── TOO FEW TYPE ARGUMENTS ──────────────────────────────────────────────────────
|
||||
|
||||
The `Result` alias expects 2 type arguments, but it got 1 instead:
|
||||
|
||||
1│ canIGo : _ -> Result _
|
||||
^^^^^^^^
|
||||
|
||||
Are there missing parentheses?
|
||||
"#
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inference_var_too_many_in_alias() {
|
||||
report_problem_as(
|
||||
indoc!(
|
||||
r#"
|
||||
canIGo : _ -> Result _ _ _
|
||||
canIGo = \color ->
|
||||
when color is
|
||||
"green" -> Ok "go!"
|
||||
"yellow" -> Err (SlowIt "whoa, let's slow down!")
|
||||
"red" -> Err (StopIt "absolutely not")
|
||||
_ -> Err (UnknownColor "this is a weird stoplight")
|
||||
canIGo
|
||||
"#
|
||||
),
|
||||
indoc!(
|
||||
r#"
|
||||
── TOO MANY TYPE ARGUMENTS ─────────────────────────────────────────────────────
|
||||
|
||||
The `Result` alias expects 2 type arguments, but it got 3 instead:
|
||||
|
||||
1│ canIGo : _ -> Result _ _ _
|
||||
^^^^^^^^^^^^
|
||||
|
||||
Are there missing parentheses?
|
||||
"#
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inference_var_conflict_in_rigid_links() {
|
||||
report_problem_as(
|
||||
indoc!(
|
||||
r#"
|
||||
f : a -> (_ -> b)
|
||||
f = \x -> \y -> if x == y then x else y
|
||||
f
|
||||
"#
|
||||
),
|
||||
// TODO: We should tell the user that we inferred `_` as `a`
|
||||
indoc!(
|
||||
r#"
|
||||
── TYPE MISMATCH ───────────────────────────────────────────────────────────────
|
||||
|
||||
Something is off with the body of the `f` definition:
|
||||
|
||||
1│ f : a -> (_ -> b)
|
||||
2│ f = \x -> \y -> if x == y then x else y
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The body is an anonymous function of type:
|
||||
|
||||
a -> a
|
||||
|
||||
But the type annotation on `f` says it should be:
|
||||
|
||||
a -> b
|
||||
|
||||
Tip: Your type annotation uses `a` and `b` as separate type variables.
|
||||
Your code seems to be saying they are the same though. Maybe they
|
||||
should be the same your type annotation? Maybe your code uses them in
|
||||
a weird way?
|
||||
"#
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
15
vendor/ena/src/unify/mod.rs
vendored
15
vendor/ena/src/unify/mod.rs
vendored
|
@ -186,6 +186,7 @@ impl<K: UnifyKey> VarValue<K> {
|
|||
self.value = value;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn parent(&self, self_key: K) -> Option<K> {
|
||||
self.if_not_self(self.parent, self_key)
|
||||
}
|
||||
|
@ -194,6 +195,7 @@ impl<K: UnifyKey> VarValue<K> {
|
|||
self.parent
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn if_not_self(&self, key: K, self_key: K) -> Option<K> {
|
||||
if key == self_key {
|
||||
None
|
||||
|
@ -311,11 +313,12 @@ impl<S: UnificationStore> UnificationTable<S> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_root_key_without_compacting(&self, vid: S::Key) -> S::Key {
|
||||
match self.value(vid).parent(vid) {
|
||||
None => vid,
|
||||
Some(redirect) => self.get_root_key_without_compacting(redirect),
|
||||
pub fn get_root_key_without_compacting(&self, mut vid: S::Key) -> S::Key {
|
||||
while let Some(redirect) = self.value(vid).parent(vid) {
|
||||
vid = redirect;
|
||||
}
|
||||
|
||||
vid
|
||||
}
|
||||
|
||||
pub fn is_redirect(&self, vid: S::Key) -> bool {
|
||||
|
@ -437,6 +440,7 @@ where
|
|||
|
||||
/// Returns the current value for the given key. If the key has
|
||||
/// been union'd, this will give the value from the current root.
|
||||
#[inline(always)]
|
||||
pub fn probe_value<K1>(&mut self, id: K1) -> V
|
||||
where
|
||||
K1: Into<K>,
|
||||
|
@ -448,6 +452,7 @@ where
|
|||
|
||||
/// Returns the current value for the given key. If the key has
|
||||
/// been union'd, this will give the value from the current root.
|
||||
#[inline(always)]
|
||||
pub fn probe_value_ref<K1>(&self, id: K1) -> &VarValue<K>
|
||||
where
|
||||
K1: Into<K>,
|
||||
|
@ -459,6 +464,7 @@ where
|
|||
|
||||
/// Returns the current value for the given key. If the key has
|
||||
/// been union'd, this will give the value from the current root.
|
||||
#[inline(always)]
|
||||
pub fn probe_value_ref_mut<K1>(&mut self, id: K1) -> &mut VarValue<K>
|
||||
where
|
||||
K1: Into<K>,
|
||||
|
@ -469,6 +475,7 @@ where
|
|||
}
|
||||
|
||||
/// This is for a debug_assert! in solve() only. Do not use it elsewhere!
|
||||
#[inline(always)]
|
||||
pub fn probe_value_without_compacting<K1>(&self, id: K1) -> V
|
||||
where
|
||||
K1: Into<K>,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue