Merge branch 'int-float-size-gen' into temp_numbers

This commit is contained in:
rvcas 2020-12-30 19:41:44 -05:00
commit c33cab57f2
14 changed files with 493 additions and 85 deletions

View file

@ -212,7 +212,8 @@ pub fn builtin_defs(var_store: &mut VarStore) -> MutMap<Symbol, Def> {
/// Num.maxInt : Int
fn num_max_int(symbol: Symbol, var_store: &mut VarStore) -> Def {
let int_var = var_store.fresh();
let body = Int(int_var, i64::MAX);
let int_percision_var = var_store.fresh();
let body = Int(int_var, int_percision_var, i64::MAX);
Def {
annotation: None,
@ -226,7 +227,8 @@ fn num_max_int(symbol: Symbol, var_store: &mut VarStore) -> Def {
/// Num.minInt : Int
fn num_min_int(symbol: Symbol, var_store: &mut VarStore) -> Def {
let int_var = var_store.fresh();
let body = Int(int_var, i64::MIN);
let int_percision_var = var_store.fresh();
let body = Int(int_var, int_percision_var, i64::MIN);
Def {
annotation: None,
@ -846,7 +848,7 @@ fn num_is_odd(symbol: Symbol, var_store: &mut VarStore) -> Def {
let body = RunLowLevel {
op: LowLevel::Eq,
args: vec![
(arg_var, Int(var_store.fresh(), 1)),
(arg_var, Int(var_store.fresh(), var_store.fresh(), 1)),
(
arg_var,
RunLowLevel {
@ -930,6 +932,7 @@ fn num_sqrt(symbol: Symbol, var_store: &mut VarStore) -> Def {
let bool_var = var_store.fresh();
let float_var = var_store.fresh();
let unbound_zero_var = var_store.fresh();
let percision_var = var_store.fresh();
let ret_var = var_store.fresh();
let body = If {
@ -943,7 +946,7 @@ fn num_sqrt(symbol: Symbol, var_store: &mut VarStore) -> Def {
op: LowLevel::NotEq,
args: vec![
(float_var, Var(Symbol::ARG_1)),
(float_var, Float(unbound_zero_var, 0.0)),
(float_var, Float(unbound_zero_var, percision_var, 0.0)),
],
ret_var: bool_var,
},
@ -1896,6 +1899,7 @@ fn num_div_float(symbol: Symbol, var_store: &mut VarStore) -> Def {
let bool_var = var_store.fresh();
let num_var = var_store.fresh();
let unbound_zero_var = var_store.fresh();
let percision_var = var_store.fresh();
let ret_var = var_store.fresh();
let body = If {
@ -1909,7 +1913,7 @@ fn num_div_float(symbol: Symbol, var_store: &mut VarStore) -> Def {
op: LowLevel::NotEq,
args: vec![
(num_var, Var(Symbol::ARG_2)),
(num_var, Float(unbound_zero_var, 0.0)),
(num_var, Float(unbound_zero_var, percision_var, 0.0)),
],
ret_var: bool_var,
},
@ -1958,6 +1962,7 @@ fn num_div_int(symbol: Symbol, var_store: &mut VarStore) -> Def {
let bool_var = var_store.fresh();
let num_var = var_store.fresh();
let unbound_zero_var = var_store.fresh();
let unbound_zero_percision_var = var_store.fresh();
let ret_var = var_store.fresh();
let body = If {
@ -1971,7 +1976,10 @@ fn num_div_int(symbol: Symbol, var_store: &mut VarStore) -> Def {
op: LowLevel::NotEq,
args: vec![
(num_var, Var(Symbol::ARG_2)),
(num_var, Int(unbound_zero_var, 0)),
(
num_var,
Int(unbound_zero_var, unbound_zero_percision_var, 0),
),
],
ret_var: bool_var,
},
@ -2025,6 +2033,7 @@ fn list_first(symbol: Symbol, var_store: &mut VarStore) -> Def {
let list_var = var_store.fresh();
let len_var = var_store.fresh();
let zero_var = var_store.fresh();
let zero_percision_var = var_store.fresh();
let list_elem_var = var_store.fresh();
let ret_var = var_store.fresh();
@ -2039,7 +2048,7 @@ fn list_first(symbol: Symbol, var_store: &mut VarStore) -> Def {
RunLowLevel {
op: LowLevel::NotEq,
args: vec![
(len_var, Int(zero_var, 0)),
(len_var, Int(zero_var, zero_percision_var, 0)),
(
len_var,
RunLowLevel {
@ -2061,7 +2070,10 @@ fn list_first(symbol: Symbol, var_store: &mut VarStore) -> Def {
// List.#getUnsafe list 0
RunLowLevel {
op: LowLevel::ListGetUnsafe,
args: vec![(list_var, Var(Symbol::ARG_1)), (len_var, Int(zero_var, 0))],
args: vec![
(list_var, Var(Symbol::ARG_1)),
(len_var, Int(zero_var, zero_percision_var, 0)),
],
ret_var: list_elem_var,
},
],
@ -2102,6 +2114,7 @@ fn list_last(symbol: Symbol, var_store: &mut VarStore) -> Def {
let list_var = var_store.fresh();
let len_var = var_store.fresh();
let num_var = var_store.fresh();
let num_percision_var = var_store.fresh();
let list_elem_var = var_store.fresh();
let ret_var = var_store.fresh();
@ -2116,7 +2129,7 @@ fn list_last(symbol: Symbol, var_store: &mut VarStore) -> Def {
RunLowLevel {
op: LowLevel::NotEq,
args: vec![
(len_var, Int(num_var, 0)),
(len_var, Int(num_var, num_percision_var, 0)),
(
len_var,
RunLowLevel {
@ -2155,7 +2168,7 @@ fn list_last(symbol: Symbol, var_store: &mut VarStore) -> Def {
ret_var: len_var,
},
),
(arg_var, Int(num_var, 1)),
(arg_var, Int(num_var, num_percision_var, 1)),
],
ret_var: len_var,
},

View file

@ -56,8 +56,8 @@ pub enum Expr {
Num(Variable, i64),
// Int and Float store a variable to generate better error messages
Int(Variable, i64),
Float(Variable, f64),
Int(Variable, Variable, i64),
Float(Variable, Variable, f64),
Str(InlinableString),
List {
list_var: Variable, // required for uniqueness of the list
@ -1170,8 +1170,8 @@ pub fn inline_calls(var_store: &mut VarStore, scope: &mut Scope, expr: Expr) ->
// Num stores the `a` variable in `Num a`. Not the same as the variable
// stored in Int and Float below, which is strictly for better error messages
other @ Num(_, _)
| other @ Int(_, _)
| other @ Float(_, _)
| other @ Int(_, _, _)
| other @ Float(_, _, _)
| other @ Str { .. }
| other @ RuntimeError(_)
| other @ EmptyRecord

View file

@ -414,8 +414,8 @@ fn fix_values_captured_in_closure_expr(
}
Num(_, _)
| Int(_, _)
| Float(_, _)
| Int(_, _, _)
| Float(_, _, _)
| Str(_)
| Var(_)
| EmptyRecord

View file

@ -45,7 +45,7 @@ pub fn int_expr_from_result(
) -> Expr {
// Int stores a variable to generate better error messages
match result {
Ok(int) => Expr::Int(var_store.fresh(), int),
Ok(int) => Expr::Int(var_store.fresh(), var_store.fresh(), int),
Err((raw, error)) => {
let runtime_error = InvalidInt(error, base, region, raw.into());
@ -65,7 +65,7 @@ pub fn float_expr_from_result(
) -> Expr {
// Float stores a variable to generate better error messages
match result {
Ok(float) => Expr::Float(var_store.fresh(), float),
Ok(float) => Expr::Float(var_store.fresh(), var_store.fresh(), float),
Err((raw, error)) => {
let runtime_error = InvalidFloat(error, region, raw.into());

View file

@ -11,30 +11,50 @@ use roc_types::types::Reason;
use roc_types::types::Type::{self, *};
#[inline(always)]
pub fn int_literal(num_var: Variable, expected: Expected<Type>, region: Region) -> Constraint {
pub fn int_literal(
num_var: Variable,
percision_var: Variable,
expected: Expected<Type>,
region: Region,
) -> Constraint {
let num_type = Variable(num_var);
let reason = Reason::IntLiteral;
let expected_literal = ForReason(reason, num_int(Type::Variable(num_var)), region);
exists(
vec![num_var],
And(vec![
Eq(num_type.clone(), expected_literal, Category::Int, region),
Eq(
num_type.clone(),
ForReason(reason, num_int(Type::Variable(percision_var)), region),
Category::Int,
region,
),
Eq(num_type, expected, Category::Int, region),
]),
)
}
#[inline(always)]
pub fn float_literal(num_var: Variable, expected: Expected<Type>, region: Region) -> Constraint {
pub fn float_literal(
num_var: Variable,
percision_var: Variable,
expected: Expected<Type>,
region: Region,
) -> Constraint {
let num_type = Variable(num_var);
let reason = Reason::FloatLiteral;
let expected_literal = ForReason(reason, num_float(Type::Variable(num_var)), region);
dbg!(&expected);
exists(
vec![num_var],
And(vec![
Eq(num_type.clone(), expected_literal, Category::Float, region),
Eq(
num_type.clone(),
ForReason(reason, num_float(Type::Variable(percision_var)), region),
Category::Float,
region,
),
Eq(num_type, expected, Category::Float, region),
]),
)

View file

@ -96,7 +96,7 @@ pub fn constrain_expr(
expected: Expected<Type>,
) -> Constraint {
match expr {
Int(var, _) => int_literal(*var, expected, region),
Int(var, percision, _) => int_literal(*var, *percision, expected, region),
Num(var, _) => exists(
vec![*var],
Eq(
@ -106,7 +106,7 @@ pub fn constrain_expr(
region,
),
),
Float(var, _) => float_literal(*var, expected, region),
Float(var, percision, _) => float_literal(*var, *percision, expected, region),
EmptyRecord => constrain_empty_record(region, expected),
Expr::Record { record_var, fields } => {
if fields.is_empty() {

View file

@ -426,6 +426,7 @@ fn unique_int(
let num_uvar1 = var_store.fresh();
let num_uvar2 = var_store.fresh();
let num_uvar3 = var_store.fresh();
let num_uvar4 = var_store.fresh();
let inner_type = Type::Variable(inner_var);
let attr_inner_type = attr_type(Bool::variable(num_uvar1), inner_type);
@ -444,6 +445,7 @@ fn unique_float(
let num_uvar1 = var_store.fresh();
let num_uvar2 = var_store.fresh();
let num_uvar3 = var_store.fresh();
let num_uvar4 = var_store.fresh();
let inner_type = Type::Variable(inner_var);
let attr_inner_type = attr_type(Bool::variable(num_uvar1), inner_type);
@ -484,7 +486,7 @@ pub fn constrain_expr(
]),
)
}
Int(var, _) => {
Int(var, _, _) => {
let (a, b, c, num_type) = unique_int(*var, var_store);
exists(
@ -500,7 +502,7 @@ pub fn constrain_expr(
]),
)
}
Float(var, _) => {
Float(var, _, _) => {
let (a, b, c, num_type) = unique_float(*var, var_store);
exists(

View file

@ -477,13 +477,27 @@ fn get_inplace_from_layout(layout: &Layout<'_>) -> InPlace {
pub fn build_exp_literal<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout: &Layout<'_>,
literal: &roc_mono::ir::Literal<'a>,
) -> BasicValueEnum<'ctx> {
use roc_mono::ir::Literal::*;
match literal {
Int(num) => env.context.i64_type().const_int(*num as u64, true).into(),
Float(num) => env.context.f64_type().const_float(*num).into(),
Int(int) =>
(match layout {
Layout::Builtin(Builtin::Int128) => env.context.i128_type(), /* TODO file an issue: you can't currently have an int literal bigger than 64 bits long, and also (as we see here), you can't currently have (at least in Inkwell) a when-branch with an i128 literal in its pattren */
Layout::Builtin(Builtin::Int64) => env.context.i64_type(),
Layout::Builtin(Builtin::Int32) => env.context.i32_type(),
Layout::Builtin(Builtin::Int16) => env.context.i16_type(),
Layout::Builtin(Builtin::Int8) => env.context.i8_type(),
_ => panic!("Invalid layout for int literal = {:?}", layout),
}).const_int(*int as u64, false).into(),
Float(num) =>
(match layout {
Layout::Builtin(Builtin::Float64) => env.context.f64_type(),
Layout::Builtin(Builtin::Float32) => env.context.f32_type(),
_ => panic!("Invalid layout for float literal = {:?}", layout),
}).const_float(*num).into(),
Bool(b) => env.context.bool_type().const_int(*b as u64, false).into(),
Byte(b) => env.context.i8_type().const_int(*b as u64, false).into(),
Str(str_literal) => {
@ -622,7 +636,7 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
use roc_mono::ir::Expr::*;
match expr {
Literal(literal) => build_exp_literal(env, literal),
Literal(literal) => build_exp_literal(env, layout, literal),
RunLowLevel(op, symbols) => {
run_low_level(env, layout_ids, scope, parent, layout, *op, symbols)
}
@ -1298,6 +1312,7 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
Let(first_symbol, first_expr, first_layout, mut cont) => {
let mut queue = Vec::new_in(env.arena);
queue.push((first_symbol, first_expr, first_layout));
while let Let(symbol, expr, layout, new_cont) = cont {
@ -1691,6 +1706,15 @@ fn build_switch_ir<'a, 'ctx, 'env>(
.build_bitcast(full_cond, 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);
let full_cond = load_symbol(env, scope, cond_symbol);
builder
.build_bitcast(full_cond, env.context.i32_type(), "")
.into_int_value()
}
Layout::Union(_) => {
// we match on the discriminant, not the whole Tag
cond_layout = Layout::Builtin(Builtin::Int64);
@ -3622,6 +3646,7 @@ fn build_int_unary_op<'a, 'ctx, 'env>(
int_abs_raise_on_overflow(env, arg, arg_layout)
}
NumToFloat => {
// TODO: Handle differnt sized numbers
// This is an Int, so we need to convert it.
bd.build_cast(
InstructionOpcode::SIToFP,
@ -3748,6 +3773,7 @@ fn build_float_unary_op<'a, 'ctx, 'env>(
let bd = env.builder;
// TODO: Handle differnt sized floats
match op {
NumNeg => bd.build_float_neg(arg, "negate_float").into(),
NumAbs => env.call_intrinsic(LLVM_FABS_F64, &[arg.into()]),

View file

@ -15,6 +15,113 @@ mod helpers;
mod gen_num {
use roc_std::RocOrder;
#[test]
fn i32_to_hex() {
assert_evals_to!(
indoc!(
r#"
f : I32
f = 0x123
f
"#
),
0x123,
i32
);
}
#[test]
fn i128_signed_int_alias() {
assert_evals_to!(
indoc!(
r#"
i : I128
i = 15
i
"#
),
15,
i128
);
}
// TODO: Use indoc
#[test]
fn i64_signed_int_alias() {
assert_evals_to!("15 : I64", 15, i64);
}
#[test]
fn i32_signed_int_alias() {
assert_evals_to!("15 : I32", 15, i32);
}
#[test]
fn i16_signed_int_alias() {
assert_evals_to!("15 : I16", 15, i16);
}
#[test]
fn i8_signed_int_alias() {
assert_evals_to!("15 : I8", 15, i8);
}
#[test]
fn i8_signed_int_alias_overflow() {
// TODO: How/where do we handle overflow
assert_evals_to!("(127 + 1): I8", -128, i8);
}
#[test]
fn u128_unsigned_int_alias() {
assert_evals_to!("15 : U128", 15, u128);
}
#[test]
fn u64_unsigned_int_alias() {
assert_evals_to!("15 : U64", 15, u64);
}
#[test]
fn u32_unsigned_int_alias() {
assert_evals_to!("15 : U32", 15, u32);
}
#[test]
fn u16_unsigned_int_alias() {
assert_evals_to!("15 : U16", 15, u16);
}
#[test]
fn u8_unsigned_int_alias() {
assert_evals_to!("15 : u8", 15, u8);
}
#[test]
fn f64_float_alias() {
assert_evals_to!(
indoc!(
r#"
f : F64
f = 3.6
f
"#
),
3.6,
f64
);
}
#[test]
fn f32_float_alias() {
assert_evals_to!(
indoc!(
r#"
f : F32
f = 3.6
f
"#
),
3.6,
f32
);
}
#[test]
fn f64_sqrt() {
// FIXME this works with normal types, but fails when checking uniqueness types

View file

@ -451,7 +451,7 @@ fn test_at_path<'a>(selected_path: &Path, branch: &Branch<'a>, all_tests: &mut V
IntLiteral(v) => {
all_tests.push(guarded(IsInt(*v)));
}
FloatLiteral(v) => {
FloatLiteral(_, v) => {
all_tests.push(IsFloat(*v));
}
StrLiteral(v) => {
@ -655,7 +655,7 @@ fn to_relevant_branch_help<'a>(
_ => None,
},
FloatLiteral(float) => match test {
FloatLiteral(_, float) => match test {
IsFloat(test_float) if float == *test_float => {
start.extend(end);
Some(Branch {
@ -749,7 +749,7 @@ fn needs_tests<'a>(pattern: &Pattern<'a>) -> bool {
| BitLiteral { .. }
| EnumLiteral { .. }
| IntLiteral(_)
| FloatLiteral(_)
| FloatLiteral(_, _)
| StrLiteral(_) => true,
}
}

View file

@ -49,7 +49,7 @@ fn simplify<'a>(pattern: &crate::ir::Pattern<'a>) -> Pattern {
match pattern {
IntLiteral(v) => Literal(Literal::Int(*v)),
FloatLiteral(v) => Literal(Literal::Float(*v)),
FloatLiteral(_, v) => Literal(Literal::Float(*v)),
StrLiteral(v) => Literal(Literal::Str(v.clone())),
// To make sure these are exhaustive, we have to "fake" a union here

View file

@ -14,6 +14,26 @@ use roc_types::subs::{Content, FlatType, Subs, Variable};
use std::collections::HashMap;
use ven_pretty::{BoxAllocator, DocAllocator, DocBuilder};
// Function return type does not match operand type of return inst!
// ret i64 %f1, !dbg !521
// i32define private fastcc i32 @"#UserApp_main_1"() !dbg !517 {
// entry:
// %f = alloca i64
// store i64 291, i64* %f, !dbg !521
// %f1 = load i64, i64* %f, !dbg !521
// ret i64 %f1, !dbg !521
// }
// Function return type does not match operand type of return inst!
// ret i32 %f1, !dbg !521
// i64define private fastcc i64 @"#UserApp_main_1"() !dbg !517 {
// entry:
// %f = alloca i32
// store i32 291, i32* %f, !dbg !521
// %f1 = load i32, i32* %f, !dbg !521
// ret i32 %f1, !dbg !521
// }
pub const PRETTY_PRINT_IR_SYMBOLS: bool = false;
#[derive(Clone, Debug, PartialEq)]
@ -2245,19 +2265,37 @@ pub fn with_hole<'a>(
let arena = env.arena;
match can_expr {
Int(_, num) => Stmt::Let(
Int(_, precision, num) => match num_argument_to_int_or_float(env.subs, precision) {
IntOrFloat::SignedIntType(precision) => Stmt::Let(
assigned,
Expr::Literal(Literal::Int(num)),
Layout::Builtin(Builtin::Int64),
Layout::Builtin(int_precision_to_builtin(precision)),
hole,
),
Float(_, num) => Stmt::Let(
IntOrFloat::UnsignedIntType(precision) => Stmt::Let(
assigned,
Expr::Literal(Literal::Float(num)),
Layout::Builtin(Builtin::Float64),
Expr::Literal(Literal::Int(num)),
Layout::Builtin(int_precision_to_builtin(precision)),
hole,
),
_ => unreachable!("unexpected float precision for integer"),
},
Float(_, precision, num) => match num_argument_to_int_or_float(env.subs, precision) {
IntOrFloat::BinaryFloatType(precision) => Stmt::Let(
assigned,
Expr::Literal(Literal::Float(num as f64)),
Layout::Builtin(float_precision_to_builtin(precision)),
hole,
),
IntOrFloat::DecimalFloatType(precision) => Stmt::Let(
assigned,
Expr::Literal(Literal::Float(num as f64)),
Layout::Builtin(float_precision_to_builtin(precision)),
hole,
),
_ => unreachable!("unexpected float precision for integer"),
},
Str(string) => Stmt::Let(
assigned,
@ -2267,16 +2305,28 @@ pub fn with_hole<'a>(
),
Num(var, num) => match num_argument_to_int_or_float(env.subs, var) {
IntOrFloat::IntType => Stmt::Let(
IntOrFloat::SignedIntType(precision) => Stmt::Let(
assigned,
Expr::Literal(Literal::Int(num)),
Layout::Builtin(Builtin::Int64),
Layout::Builtin(int_precision_to_builtin(precision)),
hole,
),
IntOrFloat::FloatType => Stmt::Let(
IntOrFloat::UnsignedIntType(precision) => Stmt::Let(
assigned,
Expr::Literal(Literal::Int(num)),
Layout::Builtin(int_precision_to_builtin(precision)),
hole,
),
IntOrFloat::BinaryFloatType(precision) => Stmt::Let(
assigned,
Expr::Literal(Literal::Float(num as f64)),
Layout::Builtin(Builtin::Float64),
Layout::Builtin(float_precision_to_builtin(precision)),
hole,
),
IntOrFloat::DecimalFloatType(precision) => Stmt::Let(
assigned,
Expr::Literal(Literal::Float(num as f64)),
Layout::Builtin(float_precision_to_builtin(precision)),
hole,
),
},
@ -4583,7 +4633,7 @@ fn store_pattern<'a>(
// do nothing
}
IntLiteral(_)
| FloatLiteral(_)
| FloatLiteral(_, _)
| EnumLiteral { .. }
| BitLiteral { .. }
| StrLiteral(_) => {}
@ -4623,7 +4673,7 @@ fn store_pattern<'a>(
// ignore
}
IntLiteral(_)
| FloatLiteral(_)
| FloatLiteral(_, _)
| EnumLiteral { .. }
| BitLiteral { .. }
| StrLiteral(_) => {}
@ -4737,7 +4787,7 @@ fn store_record_destruct<'a>(
// internally. But `y` is never used, so we must make sure it't not stored/loaded.
}
IntLiteral(_)
| FloatLiteral(_)
| FloatLiteral(_, _)
| EnumLiteral { .. }
| BitLiteral { .. }
| StrLiteral(_) => {}
@ -5408,7 +5458,7 @@ pub enum Pattern<'a> {
Underscore,
IntLiteral(i64),
FloatLiteral(u64),
FloatLiteral(Variable, u64),
BitLiteral {
value: bool,
tag_name: TagName,
@ -5469,7 +5519,7 @@ pub fn from_can_pattern<'a>(
Underscore => Pattern::Underscore,
Identifier(symbol) => Pattern::Identifier(*symbol),
IntLiteral(_, v) => Pattern::IntLiteral(*v),
FloatLiteral(_, v) => Pattern::FloatLiteral(f64::to_bits(*v)),
FloatLiteral(var, float) => Pattern::FloatLiteral(*var, f64::to_bits(*float)),
StrLiteral(v) => Pattern::StrLiteral(v.clone()),
Shadowed(region, ident) => Pattern::Shadowed(*region, ident.clone()),
UnsupportedPattern(region) => Pattern::UnsupportedPattern(*region),
@ -5478,8 +5528,10 @@ pub fn from_can_pattern<'a>(
Pattern::UnsupportedPattern(*region)
}
NumLiteral(var, num) => match num_argument_to_int_or_float(env.subs, *var) {
IntOrFloat::IntType => Pattern::IntLiteral(*num),
IntOrFloat::FloatType => Pattern::FloatLiteral(*num as u64),
IntOrFloat::SignedIntType(_) => Pattern::IntLiteral(*num),
IntOrFloat::UnsignedIntType(_) => Pattern::IntLiteral(*num),
IntOrFloat::BinaryFloatType(_) => Pattern::FloatLiteral(*var, *num as u64),
IntOrFloat::DecimalFloatType(_) => Pattern::FloatLiteral(*var, *num as u64),
},
AppliedTag {
@ -5854,29 +5906,100 @@ fn optimize_low_level(
}
}
pub enum IntPrecision {
I128,
I64,
I32,
I16,
I8,
}
pub enum FloatPrecision {
F64,
F32,
}
pub enum IntOrFloat {
IntType,
FloatType,
SignedIntType(IntPrecision),
UnsignedIntType(IntPrecision),
BinaryFloatType(FloatPrecision),
DecimalFloatType(FloatPrecision),
}
fn float_precision_to_builtin(precision: FloatPrecision) -> Builtin<'static> {
use FloatPrecision::*;
match precision {
F64 => Builtin::Float64,
F32 => Builtin::Float32,
}
}
fn int_precision_to_builtin(precision: IntPrecision) -> Builtin<'static> {
use IntPrecision::*;
match precision {
I128 => Builtin::Int128,
I64 => Builtin::Int64,
I32 => Builtin::Int32,
I16 => Builtin::Int16,
I8 => Builtin::Int8,
}
}
/// Given the `a` in `Num a`, determines whether it's an int or a float
pub fn num_argument_to_int_or_float(subs: &Subs, var: Variable) -> IntOrFloat {
match subs.get_without_compacting(var).content {
Content::Alias(Symbol::NUM_INTEGER, args, _) => {
debug_assert!(args.len() == 1);
// TODO: we probably need to match on the type of the arg
IntOrFloat::IntType
Content::FlexVar(_) => IntOrFloat::SignedIntType(IntPrecision::I64), // We default (Num *) to I64
Content::Alias(Symbol::NUM_I128, _, _)
| Content::Alias(Symbol::NUM_SIGNED128, _, _)
| Content::Alias(Symbol::NUM_AT_SIGNED128, _, _) => {
IntOrFloat::SignedIntType(IntPrecision::I128)
}
Content::FlexVar(_) => {
// If this was still a (Num *), assume compiling it to an Int
IntOrFloat::IntType
Content::Alias(Symbol::NUM_INTEGER, _, _) // 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)
}
Content::Alias(Symbol::NUM_FLOATINGPOINT, args, _) => {
debug_assert!(args.len() == 1);
// TODO: we probably need to match on the type of the arg
IntOrFloat::FloatType
// TODO: Add ors for aall NUM_SIGNED, NUM_BINARY (maybe NUM_AT_*)
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::Structure(FlatType::Apply(Symbol::ATTR_ATTR, attr_args)) => {
debug_assert!(attr_args.len() == 2);
@ -5884,10 +6007,16 @@ pub fn num_argument_to_int_or_float(subs: &Subs, var: Variable) -> IntOrFloat {
// Recurse on the second argument
num_argument_to_int_or_float(subs, attr_args[1])
}
Content::Alias(Symbol::NUM_F64, args, _) | Content::Alias(Symbol::NUM_F32, args, _) => {
debug_assert!(args.is_empty());
IntOrFloat::FloatType
Content::Alias(Symbol::NUM_FLOATINGPOINT, _, _) // 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_F32, _, _)
| Content::Alias(Symbol::NUM_BINARY32, _, _)
| Content::Alias(Symbol::NUM_AT_BINARY32, _, _) => {
IntOrFloat::BinaryFloatType(FloatPrecision::F32)
}
other => {
panic!(

View file

@ -362,14 +362,60 @@ impl<'a> Layout<'a> {
}
Structure(flat_type) => layout_from_flat_type(env, flat_type),
Alias(Symbol::NUM_INT, args, _) => {
debug_assert!(args.len() == 1);
// 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_FLOAT, args, _) => {
debug_assert!(args.len() == 1);
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))
}
// 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))
}
// 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))
}
Alias(_, _, var) => Self::from_var(env, var),
Error => Err(LayoutProblem::Erroneous),
}
@ -763,14 +809,60 @@ fn layout_from_flat_type<'a>(
match flat_type {
Apply(symbol, args) => {
match symbol {
Symbol::NUM_INT => {
// Ints
Symbol::NUM_I128 => {
debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Int128))
}
Symbol::NUM_I64 => {
debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Int64))
}
Symbol::NUM_FLOAT => {
Symbol::NUM_I32 => {
debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Int64))
}
Symbol::NUM_I16 => {
debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Int64))
}
Symbol::NUM_I8 => {
debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Int64))
}
// I think unsigned and signed use the same layout
Symbol::NUM_U128 => {
debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Int128))
}
Symbol::NUM_U64 => {
debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Int64))
}
Symbol::NUM_U32 => {
debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Int64))
}
Symbol::NUM_U16 => {
debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Int64))
}
Symbol::NUM_U8 => {
debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Int64))
}
// Floats
Symbol::NUM_F64 => {
debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Float64))
}
Symbol::NUM_F32 => {
debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Float32))
}
Symbol::NUM_NUM | Symbol::NUM_AT_NUM => {
// Num.Num should only ever have 1 argument, e.g. Num.Num Int.Integer
debug_assert_eq!(args.len(), 1);
@ -780,6 +872,7 @@ fn layout_from_flat_type<'a>(
layout_from_num_content(content)
}
Symbol::STR_STR => Ok(Layout::Builtin(Builtin::Str)),
Symbol::LIST_LIST => list_layout_from_elem(env, args[0]),
Symbol::ATTR_ATTR => {
@ -1263,8 +1356,26 @@ fn layout_from_num_content<'a>(content: Content) -> Result<Layout<'a>, LayoutPro
Ok(Layout::Builtin(DEFAULT_NUM_BUILTIN))
}
Structure(Apply(symbol, args)) => match symbol {
// Ints
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)),
// I think unsigned and signed use the same layout
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)),
// Floats
Symbol::NUM_FLOATINGPOINT => Ok(Layout::Builtin(Builtin::Float64)),
Symbol::NUM_F64 => Ok(Layout::Builtin(Builtin::Float64)),
Symbol::NUM_F32 => Ok(Layout::Builtin(Builtin::Float32)),
_ => {
panic!(
"Invalid Num.Num type application: {:?}",

View file

@ -785,8 +785,8 @@ pub fn annotate_usage(expr: &Expr, usage: &mut VarUsage) {
match expr {
RuntimeError(_)
| Num(_, _)
| Int(_, _)
| Float(_, _)
| Int(_, _, _)
| Float(_, _, _)
| Str { .. }
| EmptyRecord
| Accessor { .. }