mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-30 07:14:46 +00:00
Add toF32/64 and checked versions
This commit is contained in:
parent
bd623d65bc
commit
cd00a98636
11 changed files with 108 additions and 11 deletions
|
@ -628,6 +628,15 @@ toU16 : Int * -> U16
|
||||||
toU32 : Int * -> U32
|
toU32 : Int * -> U32
|
||||||
toU64 : Int * -> U64
|
toU64 : Int * -> U64
|
||||||
toU128 : Int * -> U128
|
toU128 : Int * -> U128
|
||||||
|
|
||||||
|
## Convert a [Num] to a [F32]. If the given number can't be precisely represented in a [F32],
|
||||||
|
## there will be a loss of precision.
|
||||||
|
toF32 : Num * -> F32
|
||||||
|
|
||||||
|
## Convert a [Num] to a [F64]. If the given number can't be precisely represented in a [F64],
|
||||||
|
## there will be a loss of precision.
|
||||||
|
toF64 : Num * -> F64
|
||||||
|
|
||||||
## Convert any [Int] to a specifically-sized [Int], after checking validity.
|
## Convert any [Int] to a specifically-sized [Int], after checking validity.
|
||||||
## These are checked bitwise operations,
|
## These are checked bitwise operations,
|
||||||
## so if the source number is outside the target range, then these will
|
## so if the source number is outside the target range, then these will
|
||||||
|
@ -643,6 +652,9 @@ toU32Checked : Int * -> Result U32 [ OutOfBounds ]*
|
||||||
toU64Checked : Int * -> Result U64 [ OutOfBounds ]*
|
toU64Checked : Int * -> Result U64 [ OutOfBounds ]*
|
||||||
toU128Checked : Int * -> Result U128 [ OutOfBounds ]*
|
toU128Checked : Int * -> Result U128 [ OutOfBounds ]*
|
||||||
|
|
||||||
|
toF32Checked : Num * -> Result F32 [ OutOfBounds ]
|
||||||
|
toF64Checked : Num * -> Result F64 [ OutOfBounds ]*
|
||||||
|
|
||||||
## Convert a number to a [Str].
|
## Convert a number to a [Str].
|
||||||
##
|
##
|
||||||
## This is the same as calling `Num.format {}` - so for more details on
|
## This is the same as calling `Num.format {}` - so for more details on
|
||||||
|
@ -765,14 +777,6 @@ toU32 : Int * -> U32
|
||||||
toU64 : Int * -> U64
|
toU64 : Int * -> U64
|
||||||
toU128 : Int * -> U128
|
toU128 : Int * -> U128
|
||||||
|
|
||||||
## Convert a #Num to a #F32. If the given number can't be precisely represented in a #F32,
|
|
||||||
## there will be a loss of precision.
|
|
||||||
toF32 : Num * -> F32
|
|
||||||
|
|
||||||
## Convert a #Num to a #F64. If the given number can't be precisely represented in a #F64,
|
|
||||||
## there will be a loss of precision.
|
|
||||||
toF64 : Num * -> F64
|
|
||||||
|
|
||||||
## Convert a #Num to a #Dec. If the given number can't be precisely represented in a #Dec,
|
## Convert a #Num to a #Dec. If the given number can't be precisely represented in a #Dec,
|
||||||
## there will be a loss of precision.
|
## there will be a loss of precision.
|
||||||
toDec : Num * -> Dec
|
toDec : Num * -> Dec
|
||||||
|
|
|
@ -336,6 +336,9 @@ toU32 : Int * -> U32
|
||||||
toU64 : Int * -> U64
|
toU64 : Int * -> U64
|
||||||
toU128 : Int * -> U128
|
toU128 : Int * -> U128
|
||||||
|
|
||||||
|
toF32 : Num * -> F32
|
||||||
|
toF64 : Num * -> F64
|
||||||
|
|
||||||
toI8Checked : Int * -> Result I8 [ OutOfBounds ]*
|
toI8Checked : Int * -> Result I8 [ OutOfBounds ]*
|
||||||
toI16Checked : Int * -> Result I16 [ OutOfBounds ]*
|
toI16Checked : Int * -> Result I16 [ OutOfBounds ]*
|
||||||
toI32Checked : Int * -> Result I32 [ OutOfBounds ]*
|
toI32Checked : Int * -> Result I32 [ OutOfBounds ]*
|
||||||
|
@ -346,3 +349,5 @@ toU16Checked : Int * -> Result U16 [ OutOfBounds ]*
|
||||||
toU32Checked : Int * -> Result U32 [ OutOfBounds ]*
|
toU32Checked : Int * -> Result U32 [ OutOfBounds ]*
|
||||||
toU64Checked : Int * -> Result U64 [ OutOfBounds ]*
|
toU64Checked : Int * -> Result U64 [ OutOfBounds ]*
|
||||||
toU128Checked : Int * -> Result U128 [ OutOfBounds ]*
|
toU128Checked : Int * -> Result U128 [ OutOfBounds ]*
|
||||||
|
toF32Checked : Num * -> Result F32 [ OutOfBounds ]*
|
||||||
|
toF64Checked : Num * -> Result F64 [ OutOfBounds ]*
|
||||||
|
|
|
@ -615,7 +615,35 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
|
||||||
add_top_level_function_type!(
|
add_top_level_function_type!(
|
||||||
Symbol::NUM_TO_NAT_CHECKED,
|
Symbol::NUM_TO_NAT_CHECKED,
|
||||||
vec![int_type(flex(TVAR1))],
|
vec![int_type(flex(TVAR1))],
|
||||||
Box::new(result_type(nat_type(), out_of_bounds)),
|
Box::new(result_type(nat_type(), out_of_bounds.clone())),
|
||||||
|
);
|
||||||
|
|
||||||
|
// toF32 : Num * -> F32
|
||||||
|
add_top_level_function_type!(
|
||||||
|
Symbol::NUM_TO_F32,
|
||||||
|
vec![num_type(flex(TVAR1))],
|
||||||
|
Box::new(f32_type()),
|
||||||
|
);
|
||||||
|
|
||||||
|
// toF32Checked : Num * -> Result F32 [ OutOfBounds ]*
|
||||||
|
add_top_level_function_type!(
|
||||||
|
Symbol::NUM_TO_F32_CHECKED,
|
||||||
|
vec![num_type(flex(TVAR1))],
|
||||||
|
Box::new(result_type(f32_type(), out_of_bounds.clone())),
|
||||||
|
);
|
||||||
|
|
||||||
|
// toF64 : Num * -> F64
|
||||||
|
add_top_level_function_type!(
|
||||||
|
Symbol::NUM_TO_F64,
|
||||||
|
vec![num_type(flex(TVAR1))],
|
||||||
|
Box::new(f64_type()),
|
||||||
|
);
|
||||||
|
|
||||||
|
// toF64Checked : Num * -> Result F64 [ OutOfBounds ]*
|
||||||
|
add_top_level_function_type!(
|
||||||
|
Symbol::NUM_TO_F64_CHECKED,
|
||||||
|
vec![num_type(flex(TVAR1))],
|
||||||
|
Box::new(result_type(f64_type(), out_of_bounds)),
|
||||||
);
|
);
|
||||||
|
|
||||||
// toStr : Num a -> Str
|
// toStr : Num a -> Str
|
||||||
|
|
|
@ -482,6 +482,18 @@ fn num_to_nat(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
lowlevel_1(symbol, LowLevel::NumIntCast, var_store)
|
lowlevel_1(symbol, LowLevel::NumIntCast, var_store)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Num.toF32 : Num * -> F32
|
||||||
|
fn num_to_f32(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
|
// Defer to NumToFloatCast
|
||||||
|
lowlevel_1(symbol, LowLevel::NumToFloatCast, var_store)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Num.toF64 : Num * -> F64
|
||||||
|
fn num_to_f64(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
|
// Defer to NumToFloatCast
|
||||||
|
lowlevel_1(symbol, LowLevel::NumToFloatCast, var_store)
|
||||||
|
}
|
||||||
|
|
||||||
fn to_num_checked(symbol: Symbol, var_store: &mut VarStore, lowlevel: LowLevel) -> Def {
|
fn to_num_checked(symbol: Symbol, var_store: &mut VarStore, lowlevel: LowLevel) -> Def {
|
||||||
let bool_var = var_store.fresh();
|
let bool_var = var_store.fresh();
|
||||||
let num_var_1 = var_store.fresh();
|
let num_var_1 = var_store.fresh();
|
||||||
|
@ -589,6 +601,8 @@ num_to_checked! {
|
||||||
num_to_u64_checked
|
num_to_u64_checked
|
||||||
num_to_u128_checked
|
num_to_u128_checked
|
||||||
num_to_nat_checked
|
num_to_nat_checked
|
||||||
|
num_to_f32_checked
|
||||||
|
num_to_f64_checked
|
||||||
}
|
}
|
||||||
|
|
||||||
// Num.toStr : Num a -> Str
|
// Num.toStr : Num a -> Str
|
||||||
|
|
|
@ -5865,6 +5865,23 @@ fn run_low_level<'a, 'ctx, 'env>(
|
||||||
.build_int_cast_sign_flag(arg, to, to_signed, "inc_cast")
|
.build_int_cast_sign_flag(arg, to, to_signed, "inc_cast")
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
NumToFloatCast => {
|
||||||
|
debug_assert_eq!(args.len(), 1);
|
||||||
|
|
||||||
|
let arg = load_symbol(scope, &args[0]).into_int_value();
|
||||||
|
|
||||||
|
todo!("TODO if it's a float, cast; if it's an int, do either signed_int_to_float or unsigned_int_to_float; if it's Dec, panic for now");
|
||||||
|
// let to = basic_type_from_layout(env, layout).into_int_type();
|
||||||
|
// let to_signed = intwidth_from_layout(*layout).is_signed();
|
||||||
|
|
||||||
|
// env.builder
|
||||||
|
// .build_int_cast_sign_flag(arg, to, to_signed, "inc_cast")
|
||||||
|
// .into()
|
||||||
|
}
|
||||||
|
NumToFloatChecked => {
|
||||||
|
// NOTE: For some reason there's no entry here for NumToIntChecked - why is that?
|
||||||
|
todo!("implement checked float conversion");
|
||||||
|
}
|
||||||
Eq => {
|
Eq => {
|
||||||
debug_assert_eq!(args.len(), 2);
|
debug_assert_eq!(args.len(), 2);
|
||||||
|
|
||||||
|
|
|
@ -677,9 +677,15 @@ impl<'a> LowLevelCall<'a> {
|
||||||
_ => todo!("{:?}: {:?} -> {:?}", self.lowlevel, arg_type, ret_type),
|
_ => todo!("{:?}: {:?} -> {:?}", self.lowlevel, arg_type, ret_type),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
NumToFloatCast => {
|
||||||
|
todo!("implement toF32 and toF64");
|
||||||
|
}
|
||||||
NumToIntChecked => {
|
NumToIntChecked => {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
NumToFloatChecked => {
|
||||||
|
todo!("implement toF32Checked and toF64Checked");
|
||||||
|
}
|
||||||
And => {
|
And => {
|
||||||
self.load_args(backend);
|
self.load_args(backend);
|
||||||
backend.code_builder.i32_and();
|
backend.code_builder.i32_and();
|
||||||
|
|
|
@ -111,7 +111,9 @@ pub enum LowLevel {
|
||||||
NumShiftRightBy,
|
NumShiftRightBy,
|
||||||
NumShiftRightZfBy,
|
NumShiftRightZfBy,
|
||||||
NumIntCast,
|
NumIntCast,
|
||||||
|
NumToFloatCast,
|
||||||
NumToIntChecked,
|
NumToIntChecked,
|
||||||
|
NumToFloatChecked,
|
||||||
NumToStr,
|
NumToStr,
|
||||||
Eq,
|
Eq,
|
||||||
NotEq,
|
NotEq,
|
||||||
|
|
|
@ -1053,6 +1053,10 @@ define_builtins! {
|
||||||
144 NUM_TO_U128_CHECKED: "toU128Checked"
|
144 NUM_TO_U128_CHECKED: "toU128Checked"
|
||||||
145 NUM_TO_NAT: "toNat"
|
145 NUM_TO_NAT: "toNat"
|
||||||
146 NUM_TO_NAT_CHECKED: "toNatChecked"
|
146 NUM_TO_NAT_CHECKED: "toNatChecked"
|
||||||
|
147 NUM_TO_F32: "toF32"
|
||||||
|
148 NUM_TO_F32_CHECKED: "toF32Checked"
|
||||||
|
149 NUM_TO_F64: "toF64"
|
||||||
|
150 NUM_TO_F64_CHECKED: "toF64Checked"
|
||||||
}
|
}
|
||||||
2 BOOL: "Bool" => {
|
2 BOOL: "Bool" => {
|
||||||
0 BOOL_BOOL: "Bool" imported // the Bool.Bool type alias
|
0 BOOL_BOOL: "Bool" imported // the Bool.Bool type alias
|
||||||
|
@ -1103,7 +1107,6 @@ define_builtins! {
|
||||||
32 STR_TO_I16: "toI16"
|
32 STR_TO_I16: "toI16"
|
||||||
33 STR_TO_U8: "toU8"
|
33 STR_TO_U8: "toU8"
|
||||||
34 STR_TO_I8: "toI8"
|
34 STR_TO_I8: "toI8"
|
||||||
|
|
||||||
}
|
}
|
||||||
4 LIST: "List" => {
|
4 LIST: "List" => {
|
||||||
0 LIST_LIST: "List" imported // the List.List type alias
|
0 LIST_LIST: "List" imported // the List.List type alias
|
||||||
|
|
|
@ -1001,7 +1001,9 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[bool] {
|
||||||
|
|
||||||
NumToStr | NumAbs | NumNeg | NumSin | NumCos | NumSqrtUnchecked | NumLogUnchecked
|
NumToStr | NumAbs | NumNeg | NumSin | NumCos | NumSqrtUnchecked | NumLogUnchecked
|
||||||
| NumRound | NumCeiling | NumFloor | NumToFloat | Not | NumIsFinite | NumAtan | NumAcos
|
| NumRound | NumCeiling | NumFloor | NumToFloat | Not | NumIsFinite | NumAtan | NumAcos
|
||||||
| NumAsin | NumIntCast | NumToIntChecked => arena.alloc_slice_copy(&[irrelevant]),
|
| NumAsin | NumIntCast | NumToIntChecked | NumToFloatCast | NumToFloatChecked => {
|
||||||
|
arena.alloc_slice_copy(&[irrelevant])
|
||||||
|
}
|
||||||
NumBytesToU16 => arena.alloc_slice_copy(&[borrowed, irrelevant]),
|
NumBytesToU16 => arena.alloc_slice_copy(&[borrowed, irrelevant]),
|
||||||
NumBytesToU32 => arena.alloc_slice_copy(&[borrowed, irrelevant]),
|
NumBytesToU32 => arena.alloc_slice_copy(&[borrowed, irrelevant]),
|
||||||
StrStartsWith | StrEndsWith => arena.alloc_slice_copy(&[owned, borrowed]),
|
StrStartsWith | StrEndsWith => arena.alloc_slice_copy(&[owned, borrowed]),
|
||||||
|
|
|
@ -170,6 +170,7 @@ enum FirstOrder {
|
||||||
NumBytesToU32,
|
NumBytesToU32,
|
||||||
NumShiftRightZfBy,
|
NumShiftRightZfBy,
|
||||||
NumIntCast,
|
NumIntCast,
|
||||||
|
NumFloatCast,
|
||||||
Eq,
|
Eq,
|
||||||
NotEq,
|
NotEq,
|
||||||
And,
|
And,
|
||||||
|
|
|
@ -5271,6 +5271,21 @@ mod solve_expr {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn to_float() {
|
||||||
|
infer_eq_without_problem(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
{
|
||||||
|
toF32: Num.toF32,
|
||||||
|
toF64: Num.toF64,
|
||||||
|
}
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
r#"{ toF32 : Num * -> F32, toF64 : Num * -> F64 }"#,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn opaque_wrap_infer() {
|
fn opaque_wrap_infer() {
|
||||||
infer_eq_without_problem(
|
infer_eq_without_problem(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue