mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 06:14:46 +00:00
Merge remote-tracking branch 'origin/trunk' into wasm-cli-option
This commit is contained in:
commit
8fa4e55c74
36 changed files with 543 additions and 150 deletions
|
@ -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"] }
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -742,9 +742,9 @@ fn pattern_to_vars_by_symbol(
|
|||
}
|
||||
}
|
||||
|
||||
NumLiteral(_, _)
|
||||
| IntLiteral(_, _)
|
||||
| FloatLiteral(_, _)
|
||||
NumLiteral(_, _, _)
|
||||
| IntLiteral(_, _, _)
|
||||
| FloatLiteral(_, _, _)
|
||||
| StrLiteral(_)
|
||||
| Underscore
|
||||
| MalformedPattern(_, _)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
|
@ -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(_, _)
|
||||
|
|
|
@ -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 => {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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, &[]),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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, ..
|
||||
} => {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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) => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue