Merge remote-tracking branch 'origin/trunk' into wasm-cli-option

This commit is contained in:
Folkert 2021-08-27 09:35:34 +02:00
commit 8fa4e55c74
36 changed files with 543 additions and 150 deletions

View file

@ -21,6 +21,7 @@ roc_mono = { path = "../mono" }
roc_load = { path = "../load" }
roc_gen_llvm = { path = "../gen_llvm", optional = true }
roc_reporting = { path = "../reporting" }
roc_std = { path = "../../roc_std" }
im = "14" # im and im-rc should always have the same version!
im-rc = "14" # im and im-rc should always have the same version!
bumpalo = { version = "3.6.1", features = ["collections"] }

View file

@ -287,7 +287,7 @@ fn lowlevel_4(symbol: Symbol, op: LowLevel, var_store: &mut VarStore) -> Def {
fn num_max_int(symbol: Symbol, var_store: &mut VarStore) -> Def {
let int_var = var_store.fresh();
let int_precision_var = var_store.fresh();
let body = Int(int_var, int_precision_var, i64::MAX.into());
let body = int(int_var, int_precision_var, i64::MAX.into());
Def {
annotation: None,
@ -302,7 +302,7 @@ fn num_max_int(symbol: Symbol, var_store: &mut VarStore) -> Def {
fn num_min_int(symbol: Symbol, var_store: &mut VarStore) -> Def {
let int_var = var_store.fresh();
let int_precision_var = var_store.fresh();
let body = Int(int_var, int_precision_var, i64::MIN.into());
let body = int(int_var, int_precision_var, i64::MIN.into());
Def {
annotation: None,
@ -687,7 +687,7 @@ fn num_is_zero(symbol: Symbol, var_store: &mut VarStore) -> Def {
op: LowLevel::Eq,
args: vec![
(arg_var, Var(Symbol::ARG_1)),
(arg_var, Num(unbound_zero_var, 0)),
(arg_var, num(unbound_zero_var, 0)),
],
ret_var: bool_var,
};
@ -710,7 +710,7 @@ fn num_is_negative(symbol: Symbol, var_store: &mut VarStore) -> Def {
let body = RunLowLevel {
op: LowLevel::NumGt,
args: vec![
(arg_var, Num(unbound_zero_var, 0)),
(arg_var, num(unbound_zero_var, 0)),
(arg_var, Var(Symbol::ARG_1)),
],
ret_var: bool_var,
@ -735,7 +735,7 @@ fn num_is_positive(symbol: Symbol, var_store: &mut VarStore) -> Def {
op: LowLevel::NumGt,
args: vec![
(arg_var, Var(Symbol::ARG_1)),
(arg_var, Num(unbound_zero_var, 0)),
(arg_var, num(unbound_zero_var, 0)),
],
ret_var: bool_var,
};
@ -758,14 +758,14 @@ 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(), var_store.fresh(), 1)),
(arg_var, int(var_store.fresh(), var_store.fresh(), 1)),
(
arg_var,
RunLowLevel {
op: LowLevel::NumRemUnchecked,
args: vec![
(arg_var, Var(Symbol::ARG_1)),
(arg_var, Num(unbound_two_var, 2)),
(arg_var, num(unbound_two_var, 2)),
],
ret_var: arg_var,
},
@ -792,14 +792,14 @@ fn num_is_even(symbol: Symbol, var_store: &mut VarStore) -> Def {
let body = RunLowLevel {
op: LowLevel::Eq,
args: vec![
(arg_var, Num(arg_num_var, 0)),
(arg_var, num(arg_num_var, 0)),
(
arg_var,
RunLowLevel {
op: LowLevel::NumRemUnchecked,
args: vec![
(arg_var, Var(Symbol::ARG_1)),
(arg_var, Num(arg_num_var, 2)),
(arg_var, num(arg_num_var, 2)),
],
ret_var: arg_var,
},
@ -853,7 +853,7 @@ fn num_sqrt(symbol: Symbol, var_store: &mut VarStore) -> Def {
op: LowLevel::NumGte,
args: vec![
(float_var, Var(Symbol::ARG_1)),
(float_var, Float(unbound_zero_var, precision_var, 0.0)),
(float_var, float(unbound_zero_var, precision_var, 0.0)),
],
ret_var: bool_var,
}),
@ -899,7 +899,7 @@ fn num_log(symbol: Symbol, var_store: &mut VarStore) -> Def {
op: LowLevel::NumGt,
args: vec![
(float_var, Var(Symbol::ARG_1)),
(float_var, Float(unbound_zero_var, precision_var, 0.0)),
(float_var, float(unbound_zero_var, precision_var, 0.0)),
],
ret_var: bool_var,
}),
@ -1139,7 +1139,7 @@ fn num_int_cast(symbol: Symbol, var_store: &mut VarStore) -> Def {
fn num_max_i128(symbol: Symbol, var_store: &mut VarStore) -> Def {
let int_var = var_store.fresh();
let int_precision_var = var_store.fresh();
let body = Int(int_var, int_precision_var, i128::MAX);
let body = int(int_var, int_precision_var, i128::MAX);
let std = roc_builtins::std::types();
let solved = std.get(&symbol).unwrap();
@ -1172,7 +1172,7 @@ fn list_is_empty(symbol: Symbol, var_store: &mut VarStore) -> Def {
let body = RunLowLevel {
op: LowLevel::Eq,
args: vec![
(len_var, Num(unbound_zero_var, 0)),
(len_var, num(unbound_zero_var, 0)),
(
len_var,
RunLowLevel {
@ -2051,7 +2051,7 @@ fn list_sum(symbol: Symbol, var_store: &mut VarStore) -> Def {
args: vec![
(list_var, Var(Symbol::ARG_1)),
(closure_var, list_sum_add(num_var, var_store)),
(num_var, Num(var_store.fresh(), 0)),
(num_var, num(var_store.fresh(), 0)),
],
ret_var,
};
@ -2093,7 +2093,7 @@ fn list_product(symbol: Symbol, var_store: &mut VarStore) -> Def {
args: vec![
(list_var, Var(Symbol::ARG_1)),
(closure_var, list_product_mul(num_var, var_store)),
(num_var, Num(var_store.fresh(), 1)),
(num_var, num(var_store.fresh(), 1)),
],
ret_var,
};
@ -2571,7 +2571,7 @@ fn num_rem(symbol: Symbol, var_store: &mut VarStore) -> Def {
op: LowLevel::NotEq,
args: vec![
(num_var, Var(Symbol::ARG_2)),
(num_var, Num(unbound_zero_var, 0)),
(num_var, num(unbound_zero_var, 0)),
],
ret_var: bool_var,
},
@ -2674,7 +2674,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, precision_var, 0.0)),
(num_var, float(unbound_zero_var, precision_var, 0.0)),
],
ret_var: bool_var,
},
@ -2739,7 +2739,7 @@ fn num_div_int(symbol: Symbol, var_store: &mut VarStore) -> Def {
(num_var, Var(Symbol::ARG_2)),
(
num_var,
Int(unbound_zero_var, unbound_zero_precision_var, 0),
int(unbound_zero_var, unbound_zero_precision_var, 0),
),
],
ret_var: bool_var,
@ -2809,7 +2809,7 @@ fn list_first(symbol: Symbol, var_store: &mut VarStore) -> Def {
RunLowLevel {
op: LowLevel::NotEq,
args: vec![
(len_var, Int(zero_var, zero_precision_var, 0)),
(len_var, int(zero_var, zero_precision_var, 0)),
(
len_var,
RunLowLevel {
@ -2833,7 +2833,7 @@ fn list_first(symbol: Symbol, var_store: &mut VarStore) -> Def {
op: LowLevel::ListGetUnsafe,
args: vec![
(list_var, Var(Symbol::ARG_1)),
(len_var, Int(zero_var, zero_precision_var, 0)),
(len_var, int(zero_var, zero_precision_var, 0)),
],
ret_var: list_elem_var,
},
@ -2890,7 +2890,7 @@ fn list_last(symbol: Symbol, var_store: &mut VarStore) -> Def {
RunLowLevel {
op: LowLevel::NotEq,
args: vec![
(len_var, Int(num_var, num_precision_var, 0)),
(len_var, int(num_var, num_precision_var, 0)),
(
len_var,
RunLowLevel {
@ -2929,7 +2929,7 @@ fn list_last(symbol: Symbol, var_store: &mut VarStore) -> Def {
ret_var: len_var,
},
),
(arg_var, Int(num_var, num_precision_var, 1)),
(arg_var, int(num_var, num_precision_var, 1)),
],
ret_var: len_var,
},
@ -3403,7 +3403,7 @@ fn num_bytes_to(symbol: Symbol, var_store: &mut VarStore, offset: i64, low_level
add_var,
RunLowLevel {
ret_var: cast_var,
args: vec![(cast_var, Num(var_store.fresh(), offset))],
args: vec![(cast_var, num(var_store.fresh(), offset))],
op: LowLevel::NumIntCast,
},
),
@ -3489,3 +3489,18 @@ fn defn_help(
loc_body: Box::new(no_region(body)),
}
}
#[inline(always)]
fn int(num_var: Variable, precision_var: Variable, i: i128) -> Expr {
Int(num_var, precision_var, i.to_string().into_boxed_str(), i)
}
#[inline(always)]
fn float(num_var: Variable, precision_var: Variable, f: f64) -> Expr {
Float(num_var, precision_var, f.to_string().into_boxed_str(), f)
}
#[inline(always)]
fn num(num_var: Variable, i: i64) -> Expr {
Num(num_var, i.to_string().into_boxed_str(), i)
}

View file

@ -742,9 +742,9 @@ fn pattern_to_vars_by_symbol(
}
}
NumLiteral(_, _)
| IntLiteral(_, _)
| FloatLiteral(_, _)
NumLiteral(_, _, _)
| IntLiteral(_, _, _)
| FloatLiteral(_, _, _)
| StrLiteral(_)
| Underscore
| MalformedPattern(_, _)

View file

@ -21,7 +21,7 @@ use roc_region::all::{Located, Region};
use roc_types::subs::{VarStore, Variable};
use roc_types::types::Alias;
use std::fmt::Debug;
use std::{char, i64, u32};
use std::{char, u32};
#[derive(Clone, Default, Debug, PartialEq)]
pub struct Output {
@ -52,11 +52,11 @@ pub enum 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
Num(Variable, i64),
Num(Variable, Box<str>, i64),
// Int and Float store a variable to generate better error messages
Int(Variable, Variable, i128),
Float(Variable, Variable, f64),
Int(Variable, Variable, Box<str>, i128),
Float(Variable, Variable, Box<str>, f64),
Str(Box<str>),
List {
elem_var: Variable,
@ -206,14 +206,23 @@ pub fn canonicalize_expr<'a>(
use Expr::*;
let (expr, output) = match expr {
ast::Expr::Num(string) => {
let answer = num_expr_from_result(var_store, finish_parsing_int(*string), region, env);
ast::Expr::Num(str) => {
let answer = num_expr_from_result(
var_store,
finish_parsing_int(*str).map(|int| (*str, int)),
region,
env,
);
(answer, Output::default())
}
ast::Expr::Float(string) => {
let answer =
float_expr_from_result(var_store, finish_parsing_float(string), region, env);
ast::Expr::Float(str) => {
let answer = float_expr_from_result(
var_store,
finish_parsing_float(str).map(|f| (*str, f)),
region,
env,
);
(answer, Output::default())
}
@ -795,8 +804,16 @@ pub fn canonicalize_expr<'a>(
is_negative,
} => {
// the minus sign is added before parsing, to get correct overflow/underflow behavior
let result = finish_parsing_base(string, *base, *is_negative);
let answer = int_expr_from_result(var_store, result, region, *base, env);
let answer = match finish_parsing_base(string, *base, *is_negative) {
Ok(int) => {
// Done in this kinda round about way with intermediate variables
// to keep borrowed values around and make this compile
let int_string = int.to_string();
let int_str = int_string.as_str();
int_expr_from_result(var_store, Ok((int_str, int as i128)), region, *base, env)
}
Err(e) => int_expr_from_result(var_store, Err(e), region, *base, env),
};
(answer, Output::default())
}
@ -1217,9 +1234,9 @@ pub fn inline_calls(var_store: &mut VarStore, scope: &mut Scope, expr: Expr) ->
match 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 @ Num(_, _, _)
| other @ Int(_, _, _, _)
| other @ Float(_, _, _, _)
| other @ Str { .. }
| other @ RuntimeError(_)
| other @ EmptyRecord

View file

@ -382,9 +382,9 @@ fn fix_values_captured_in_closure_pattern(
}
}
Identifier(_)
| NumLiteral(_, _)
| IntLiteral(_, _)
| FloatLiteral(_, _)
| NumLiteral(_, _, _)
| IntLiteral(_, _, _)
| FloatLiteral(_, _, _)
| StrLiteral(_)
| Underscore
| Shadowed(_, _)
@ -438,9 +438,9 @@ fn fix_values_captured_in_closure_expr(
fix_values_captured_in_closure_expr(&mut loc_body.value, no_capture_symbols);
}
Num(_, _)
| Int(_, _, _)
| Float(_, _, _)
Num(_, _, _)
| Int(_, _, _, _)
| Float(_, _, _, _)
| Str(_)
| Var(_)
| EmptyRecord

View file

@ -16,12 +16,12 @@ use std::i64;
#[inline(always)]
pub fn num_expr_from_result(
var_store: &mut VarStore,
result: Result<i64, (&str, IntErrorKind)>,
result: Result<(&str, i64), (&str, IntErrorKind)>,
region: Region,
env: &mut Env,
) -> Expr {
match result {
Ok(int) => Expr::Num(var_store.fresh(), int),
Ok((str, num)) => Expr::Num(var_store.fresh(), (*str).into(), num),
Err((raw, error)) => {
// (Num *) compiles to Int if it doesn't
// get specialized to something else first,
@ -38,14 +38,14 @@ pub fn num_expr_from_result(
#[inline(always)]
pub fn int_expr_from_result(
var_store: &mut VarStore,
result: Result<i64, (&str, IntErrorKind)>,
result: Result<(&str, i128), (&str, IntErrorKind)>,
region: Region,
base: Base,
env: &mut Env,
) -> Expr {
// Int stores a variable to generate better error messages
match result {
Ok(int) => Expr::Int(var_store.fresh(), var_store.fresh(), int.into()),
Ok((str, int)) => Expr::Int(var_store.fresh(), var_store.fresh(), (*str).into(), int),
Err((raw, error)) => {
let runtime_error = InvalidInt(error, base, region, raw.into());
@ -59,13 +59,13 @@ pub fn int_expr_from_result(
#[inline(always)]
pub fn float_expr_from_result(
var_store: &mut VarStore,
result: Result<f64, (&str, FloatErrorKind)>,
result: Result<(&str, f64), (&str, FloatErrorKind)>,
region: Region,
env: &mut Env,
) -> Expr {
// Float stores a variable to generate better error messages
match result {
Ok(float) => Expr::Float(var_store.fresh(), var_store.fresh(), float),
Ok((str, float)) => Expr::Float(var_store.fresh(), var_store.fresh(), (*str).into(), float),
Err((raw, error)) => {
let runtime_error = InvalidFloat(error, region, raw.into());

View file

@ -25,9 +25,9 @@ pub enum Pattern {
ext_var: Variable,
destructs: Vec<Located<RecordDestruct>>,
},
IntLiteral(Variable, i64),
NumLiteral(Variable, i64),
FloatLiteral(Variable, f64),
IntLiteral(Variable, Box<str>, i64),
NumLiteral(Variable, Box<str>, i64),
FloatLiteral(Variable, Box<str>, f64),
StrLiteral(Box<str>),
Underscore,
@ -85,9 +85,9 @@ pub fn symbols_from_pattern_help(pattern: &Pattern, symbols: &mut Vec<Symbol>) {
}
}
NumLiteral(_, _)
| IntLiteral(_, _)
| FloatLiteral(_, _)
NumLiteral(_, _, _)
| IntLiteral(_, _, _)
| FloatLiteral(_, _, _)
| StrLiteral(_)
| Underscore
| MalformedPattern(_, _)
@ -185,13 +185,13 @@ pub fn canonicalize_pattern<'a>(
}
}
FloatLiteral(string) => match pattern_type {
WhenBranch => match finish_parsing_float(string) {
FloatLiteral(str) => match pattern_type {
WhenBranch => match finish_parsing_float(str) {
Err(_error) => {
let problem = MalformedPatternProblem::MalformedFloat;
malformed_pattern(env, problem, region)
}
Ok(float) => Pattern::FloatLiteral(var_store.fresh(), float),
Ok(float) => Pattern::FloatLiteral(var_store.fresh(), (*str).into(), float),
},
ptype => unsupported_pattern(env, ptype, region),
},
@ -201,13 +201,13 @@ pub fn canonicalize_pattern<'a>(
TopLevelDef | DefExpr => bad_underscore(env, region),
},
NumLiteral(string) => match pattern_type {
WhenBranch => match finish_parsing_int(string) {
NumLiteral(str) => match pattern_type {
WhenBranch => match finish_parsing_int(str) {
Err(_error) => {
let problem = MalformedPatternProblem::MalformedInt;
malformed_pattern(env, problem, region)
}
Ok(int) => Pattern::NumLiteral(var_store.fresh(), int),
Ok(int) => Pattern::NumLiteral(var_store.fresh(), (*str).into(), int),
},
ptype => unsupported_pattern(env, ptype, region),
},
@ -223,11 +223,10 @@ pub fn canonicalize_pattern<'a>(
malformed_pattern(env, problem, region)
}
Ok(int) => {
if *is_negative {
Pattern::IntLiteral(var_store.fresh(), -int)
} else {
Pattern::IntLiteral(var_store.fresh(), int)
}
let sign_str = if *is_negative { "-" } else { "" };
let int_str = format!("{}{}", sign_str, int.to_string()).into_boxed_str();
let i = if *is_negative { -int } else { int };
Pattern::IntLiteral(var_store.fresh(), int_str, i)
}
},
ptype => unsupported_pattern(env, ptype, region),
@ -473,9 +472,9 @@ fn add_bindings_from_patterns(
answer.push((*symbol, *region));
}
}
NumLiteral(_, _)
| IntLiteral(_, _)
| FloatLiteral(_, _)
NumLiteral(_, _, _)
| IntLiteral(_, _, _)
| FloatLiteral(_, _, _)
| StrLiteral(_)
| Underscore
| Shadowed(_, _)

View file

@ -32,7 +32,7 @@ mod test_can {
let actual_out = can_expr_with(&arena, test_home(), input);
match actual_out.loc_expr.value {
Expr::Float(_, _, actual) => {
Expr::Float(_, _, _, actual) => {
assert_eq!(expected, actual);
}
actual => {
@ -46,7 +46,7 @@ mod test_can {
let actual_out = can_expr_with(&arena, test_home(), input);
match actual_out.loc_expr.value {
Expr::Int(_, _, actual) => {
Expr::Int(_, _, _, actual) => {
assert_eq!(expected, actual);
}
actual => {
@ -60,7 +60,7 @@ mod test_can {
let actual_out = can_expr_with(&arena, test_home(), input);
match actual_out.loc_expr.value {
Expr::Num(_, actual) => {
Expr::Num(_, _, actual) => {
assert_eq!(expected, actual);
}
actual => {

View file

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

View file

@ -56,9 +56,9 @@ fn headers_from_annotation_help(
| Shadowed(_, _)
| MalformedPattern(_, _)
| UnsupportedPattern(_)
| NumLiteral(_, _)
| IntLiteral(_, _)
| FloatLiteral(_, _)
| NumLiteral(_, _, _)
| IntLiteral(_, _, _)
| FloatLiteral(_, _, _)
| StrLiteral(_) => true,
RecordDestructure { destructs, .. } => match annotation.value.shallow_dealias() {
@ -143,7 +143,7 @@ pub fn constrain_pattern(
);
}
NumLiteral(var, _) => {
NumLiteral(var, _, _) => {
state.vars.push(*var);
state.constraints.push(Constraint::Pattern(
@ -154,7 +154,7 @@ pub fn constrain_pattern(
));
}
IntLiteral(precision_var, _) => {
IntLiteral(precision_var, _, _) => {
state.constraints.push(Constraint::Pattern(
region,
PatternCategory::Int,
@ -163,7 +163,7 @@ pub fn constrain_pattern(
));
}
FloatLiteral(precision_var, _) => {
FloatLiteral(precision_var, _, _) => {
state.constraints.push(Constraint::Pattern(
region,
PatternCategory::Float,

View file

@ -16,6 +16,7 @@ roc_builtins = { path = "../builtins" }
roc_unify = { path = "../unify" }
roc_solve = { path = "../solve" }
roc_mono = { path = "../mono" }
roc_std = { path = "../../roc_std" }
morphic_lib = { path = "../../vendor/morphic_lib" }
im = "14" # im and im-rc should always have the same version!
im-rc = "14" # im and im-rc should always have the same version!
@ -29,7 +30,6 @@ roc_parse = { path = "../parse" }
roc_load = { path = "../load" }
roc_reporting = { path = "../reporting" }
roc_build = { path = "../build" }
roc_std = { path = "../../roc_std" }
pretty_assertions = "0.5.1"
maplit = "1.0.1"
indoc = "0.3.3"

View file

@ -709,11 +709,6 @@ pub fn float_with_precision<'a, 'ctx, 'env>(
precision: &Builtin,
) -> BasicValueEnum<'ctx> {
match precision {
Builtin::Decimal => call_bitcode_fn(
env,
&[env.context.f64_type().const_float(value).into()],
bitcode::DEC_FROM_F64,
),
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),
@ -738,6 +733,11 @@ pub fn build_exp_literal<'a, 'ctx, 'env>(
_ => panic!("Invalid layout for float literal = {:?}", layout),
},
Decimal(int) => env
.context
.i128_type()
.const_int(int.0 as u64, false)
.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) => {

View file

@ -13,6 +13,7 @@ roc_types = { path = "../types" }
roc_can = { path = "../can" }
roc_unify = { path = "../unify" }
roc_solve = { path = "../solve" }
roc_std = { path = "../../roc_std" }
roc_problem = { path = "../problem" }
ven_pretty = { path = "../../vendor/pretty" }
morphic_lib = { path = "../../vendor/morphic_lib" }

View file

@ -1169,7 +1169,7 @@ fn literal_spec(
match literal {
Str(_) => new_static_string(builder, block),
Int(_) | Float(_) | Bool(_) | Byte(_) => builder.add_make_tuple(block, &[]),
Int(_) | Float(_) | Decimal(_) | Bool(_) | Byte(_) => builder.add_make_tuple(block, &[]),
}
}

View file

@ -7,6 +7,7 @@ use roc_collections::all::{MutMap, MutSet};
use roc_module::ident::TagName;
use roc_module::low_level::LowLevel;
use roc_module::symbol::Symbol;
use roc_std::RocDec;
/// COMPILE CASES
@ -85,8 +86,8 @@ enum Test<'a> {
arguments: Vec<(Pattern<'a>, Layout<'a>)>,
},
IsInt(i128),
// float patterns are stored as u64 so they are comparable/hashable
IsFloat(u64),
IsDecimal(RocDec),
IsStr(Box<str>),
IsBit(bool),
IsByte {
@ -126,6 +127,11 @@ impl<'a> Hash for Test<'a> {
tag_id.hash(state);
num_alts.hash(state);
}
IsDecimal(v) => {
// TODO: Is this okay?
state.write_u8(6);
v.0.hash(state);
}
}
}
}
@ -302,6 +308,7 @@ fn tests_are_complete_help(last_test: &Test, number_of_tests: usize) -> bool {
Test::IsBit(_) => number_of_tests == 2,
Test::IsInt(_) => false,
Test::IsFloat(_) => false,
Test::IsDecimal(_) => false,
Test::IsStr(_) => false,
}
}
@ -556,6 +563,7 @@ fn test_at_path<'a>(
},
IntLiteral(v) => IsInt(*v),
FloatLiteral(v) => IsFloat(*v),
DecimalLiteral(v) => IsDecimal(*v),
StrLiteral(v) => IsStr(v.clone()),
};
@ -823,6 +831,18 @@ fn to_relevant_branch_help<'a>(
_ => None,
},
DecimalLiteral(dec) => match test {
IsDecimal(test_dec) if dec.0 == test_dec.0 => {
start.extend(end);
Some(Branch {
goal: branch.goal,
guard: branch.guard.clone(),
patterns: start,
})
}
_ => None,
},
BitLiteral { value: bit, .. } => match test {
IsBit(test_bit) if bit == *test_bit => {
start.extend(end);
@ -910,6 +930,7 @@ fn needs_tests(pattern: &Pattern) -> bool {
| EnumLiteral { .. }
| IntLiteral(_)
| FloatLiteral(_)
| DecimalLiteral(_)
| StrLiteral(_) => true,
}
}
@ -1279,6 +1300,14 @@ fn test_to_equality<'a>(
(stores, lhs_symbol, rhs_symbol, None)
}
Test::IsDecimal(test_dec) => {
let lhs = Expr::Literal(Literal::Int(test_dec.0));
let lhs_symbol = env.unique_symbol();
stores.push((lhs_symbol, Layout::Builtin(Builtin::Int128), lhs));
(stores, lhs_symbol, rhs_symbol, None)
}
Test::IsByte {
tag_id: test_byte, ..
} => {

View file

@ -2,6 +2,7 @@ use crate::ir::DestructType;
use roc_collections::all::{Index, MutMap};
use roc_module::ident::{Lowercase, TagName};
use roc_region::all::{Located, Region};
use roc_std::RocDec;
use self::Pattern::*;
@ -56,6 +57,7 @@ pub enum Literal {
Bit(bool),
Byte(u8),
Float(u64),
Decimal(RocDec),
Str(Box<str>),
}
@ -65,6 +67,7 @@ fn simplify(pattern: &crate::ir::Pattern) -> Pattern {
match pattern {
IntLiteral(v) => Literal(Literal::Int(*v)),
FloatLiteral(v) => Literal(Literal::Float(*v)),
DecimalLiteral(v) => Literal(Literal::Decimal(*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,7 @@ use roc_module::low_level::LowLevel;
use roc_module::symbol::{IdentIds, ModuleId, Symbol};
use roc_problem::can::RuntimeError;
use roc_region::all::{Located, Region};
use roc_std::RocDec;
use roc_types::solved_types::SolvedType;
use roc_types::subs::{Content, FlatType, Subs, Variable, VariableSubsSlice};
use std::collections::HashMap;
@ -1024,6 +1025,7 @@ pub enum Literal<'a> {
// Literals
Int(i128),
Float(f64),
Decimal(RocDec),
Str(&'a str),
/// Closed tag unions containing exactly two (0-arity) tags compile to Expr::Bool,
/// so they can (at least potentially) be emitted as 1-bit machine bools.
@ -1205,6 +1207,8 @@ impl<'a> Literal<'a> {
match self {
Int(lit) => alloc.text(format!("{}i64", lit)),
Float(lit) => alloc.text(format!("{}f64", lit)),
// TODO: Add proper Dec.to_str
Decimal(lit) => alloc.text(format!("{}Dec", lit.0)),
Bool(lit) => alloc.text(format!("{}", lit)),
Byte(lit) => alloc.text(format!("{}u8", lit)),
Str(lit) => alloc.text(format!("{:?}", lit)),
@ -1702,7 +1706,7 @@ fn pattern_to_when<'a>(
(symbol, Located::at_zero(wrapped_body))
}
IntLiteral(_, _) | NumLiteral(_, _) | FloatLiteral(_, _) | StrLiteral(_) => {
IntLiteral(_, _, _) | NumLiteral(_, _, _) | FloatLiteral(_, _, _) | StrLiteral(_) => {
// These patters are refutable, and thus should never occur outside a `when` expression
// They should have been replaced with `UnsupportedPattern` during canonicalization
unreachable!("refutable pattern {:?} where irrefutable pattern is expected. This should never happen!", pattern.value)
@ -2738,17 +2742,17 @@ pub fn with_hole<'a>(
let arena = env.arena;
match can_expr {
Int(_, precision, num) => {
Int(_, precision, _, int) => {
match num_argument_to_int_or_float(env.subs, env.ptr_bytes, precision, false) {
IntOrFloat::SignedIntType(precision) => Stmt::Let(
assigned,
Expr::Literal(Literal::Int(num)),
Expr::Literal(Literal::Int(int)),
Layout::Builtin(int_precision_to_builtin(precision)),
hole,
),
IntOrFloat::UnsignedIntType(precision) => Stmt::Let(
assigned,
Expr::Literal(Literal::Int(num)),
Expr::Literal(Literal::Int(int)),
Layout::Builtin(int_precision_to_builtin(precision)),
hole,
),
@ -2756,20 +2760,26 @@ pub fn with_hole<'a>(
}
}
Float(_, precision, num) => {
Float(_, precision, float_str, float) => {
match num_argument_to_int_or_float(env.subs, env.ptr_bytes, precision, true) {
IntOrFloat::BinaryFloatType(precision) => Stmt::Let(
assigned,
Expr::Literal(Literal::Float(num as f64)),
Expr::Literal(Literal::Float(float)),
Layout::Builtin(float_precision_to_builtin(precision)),
hole,
),
IntOrFloat::DecimalFloatType => Stmt::Let(
assigned,
Expr::Literal(Literal::Float(num as f64)),
Layout::Builtin(Builtin::Decimal),
hole,
),
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),
};
Stmt::Let(
assigned,
Expr::Literal(Literal::Decimal(dec)),
Layout::Builtin(Builtin::Decimal),
hole,
)
}
_ => unreachable!("unexpected float precision for integer"),
}
}
@ -2781,9 +2791,8 @@ pub fn with_hole<'a>(
hole,
),
Num(var, num) => {
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(
assigned,
@ -2803,12 +2812,18 @@ pub fn with_hole<'a>(
Layout::Builtin(float_precision_to_builtin(precision)),
hole,
),
IntOrFloat::DecimalFloatType => Stmt::Let(
assigned,
Expr::Literal(Literal::Float(num as f64)),
Layout::Builtin(Builtin::Decimal),
hole,
),
IntOrFloat::DecimalFloatType => {
let dec = match RocDec::from_str(&num_str) {
Some(d) => d,
None => panic!("Invalid decimal for float literal = {}. TODO: Make this a nice, user-friendly error message", num_str),
};
Stmt::Let(
assigned,
Expr::Literal(Literal::Decimal(dec)),
Layout::Builtin(Builtin::Decimal),
hole,
)
}
}
}
LetNonRec(def, cont, _) => {
@ -5577,6 +5592,7 @@ fn store_pattern_help<'a>(
}
IntLiteral(_)
| FloatLiteral(_)
| DecimalLiteral(_)
| EnumLiteral { .. }
| BitLiteral { .. }
| StrLiteral(_) => {
@ -5711,6 +5727,7 @@ fn store_tag_pattern<'a>(
}
IntLiteral(_)
| FloatLiteral(_)
| DecimalLiteral(_)
| EnumLiteral { .. }
| BitLiteral { .. }
| StrLiteral(_) => {}
@ -5786,6 +5803,7 @@ fn store_newtype_pattern<'a>(
}
IntLiteral(_)
| FloatLiteral(_)
| DecimalLiteral(_)
| EnumLiteral { .. }
| BitLiteral { .. }
| StrLiteral(_) => {}
@ -5861,6 +5879,7 @@ fn store_record_destruct<'a>(
}
IntLiteral(_)
| FloatLiteral(_)
| DecimalLiteral(_)
| EnumLiteral { .. }
| BitLiteral { .. }
| StrLiteral(_) => {
@ -6832,6 +6851,7 @@ pub enum Pattern<'a> {
Underscore,
IntLiteral(i128),
FloatLiteral(u64),
DecimalLiteral(RocDec),
BitLiteral {
value: bool,
tag_name: TagName,
@ -6908,8 +6928,26 @@ fn from_can_pattern_help<'a>(
match can_pattern {
Underscore => Ok(Pattern::Underscore),
Identifier(symbol) => Ok(Pattern::Identifier(*symbol)),
IntLiteral(_, int) => Ok(Pattern::IntLiteral(*int as i128)),
FloatLiteral(_, float) => Ok(Pattern::FloatLiteral(f64::to_bits(*float))),
IntLiteral(_, _, int) => Ok(Pattern::IntLiteral(*int as i128)),
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(_) => {
panic!("Invalid percision for float literal = {:?}", var)
}
IntOrFloat::UnsignedIntType(_) => {
panic!("Invalid percision for float literal = {:?}", var)
}
IntOrFloat::BinaryFloatType(_) => Ok(Pattern::FloatLiteral(f64::to_bits(*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),
};
Ok(Pattern::DecimalLiteral(dec))
}
}
}
StrLiteral(v) => Ok(Pattern::StrLiteral(v.clone())),
Shadowed(region, ident) => Err(RuntimeError::Shadowing {
original_region: *region,
@ -6920,12 +6958,18 @@ fn from_can_pattern_help<'a>(
// TODO preserve malformed problem information here?
Err(RuntimeError::UnsupportedPattern(*region))
}
NumLiteral(var, num) => {
NumLiteral(var, num_str, num) => {
match num_argument_to_int_or_float(env.subs, env.ptr_bytes, *var, false) {
IntOrFloat::SignedIntType(_) => Ok(Pattern::IntLiteral(*num as i128)),
IntOrFloat::UnsignedIntType(_) => Ok(Pattern::IntLiteral(*num as i128)),
IntOrFloat::BinaryFloatType(_) => Ok(Pattern::FloatLiteral(*num as u64)),
IntOrFloat::DecimalFloatType => Ok(Pattern::FloatLiteral(*num as u64)),
IntOrFloat::DecimalFloatType => {
let dec = match RocDec::from_str(num_str) {
Some(d) => d,
None => panic!("Invalid decimal for float literal = {}. TODO: Make this a nice, user-friendly error message", num_str),
};
Ok(Pattern::DecimalLiteral(dec))
}
}
}

View file

@ -143,6 +143,8 @@ fn pattern_to_doc_help<'b>(
Bit(false) => alloc.text("False"),
Byte(b) => alloc.text(b.to_string()),
Float(f) => alloc.text(f.to_string()),
// TODO: Proper Dec.to_str
Decimal(d) => alloc.text(d.0.to_string()),
Str(s) => alloc.string(s.into()),
},
Ctor(union, tag_id, args) => {