First pass

This commit is contained in:
ayazhafiz 2022-02-04 08:46:27 -05:00
parent d25e891fb0
commit 5e0d90ac53
8 changed files with 391 additions and 263 deletions

View file

@ -1,7 +1,7 @@
use crate::def::Def;
use crate::expr::{self, ClosureData, Expr::*, IntValue};
use crate::expr::{Expr, Field, Recursive};
use crate::num::{FloatWidth, IntWidth, NumWidth, NumericBound};
use crate::num::{FloatBound, IntBound, IntWidth, NumericBound};
use crate::pattern::Pattern;
use roc_collections::all::SendMap;
use roc_module::called_via::CalledVia;
@ -867,7 +867,7 @@ fn num_is_odd(symbol: Symbol, var_store: &mut VarStore) -> Def {
args: vec![
(
arg_var,
int::<i128>(var_store.fresh(), var_store.fresh(), 1, num_no_bound()),
int::<i128>(var_store.fresh(), var_store.fresh(), 1, int_no_bound()),
),
(
arg_var,
@ -965,7 +965,7 @@ fn num_sqrt(symbol: Symbol, var_store: &mut VarStore) -> Def {
(float_var, Var(Symbol::ARG_1)),
(
float_var,
float(unbound_zero_var, precision_var, 0.0, num_no_bound()),
float(unbound_zero_var, precision_var, 0.0, float_no_bound()),
),
],
ret_var: bool_var,
@ -1014,7 +1014,7 @@ fn num_log(symbol: Symbol, var_store: &mut VarStore) -> Def {
(float_var, Var(Symbol::ARG_1)),
(
float_var,
float(unbound_zero_var, precision_var, 0.0, num_no_bound()),
float(unbound_zero_var, precision_var, 0.0, float_no_bound()),
),
],
ret_var: bool_var,
@ -1253,162 +1253,82 @@ fn num_int_cast(symbol: Symbol, var_store: &mut VarStore) -> Def {
/// Num.minI8: I8
fn num_min_i8(symbol: Symbol, var_store: &mut VarStore) -> Def {
int_min_or_max::<i8>(
symbol,
var_store,
i8::MIN,
NumericBound::Exact(IntWidth::I8),
)
int_min_or_max::<i8>(symbol, var_store, i8::MIN, IntBound::Exact(IntWidth::I8))
}
/// Num.maxI8: I8
fn num_max_i8(symbol: Symbol, var_store: &mut VarStore) -> Def {
int_min_or_max::<i8>(
symbol,
var_store,
i8::MAX,
NumericBound::Exact(IntWidth::I8),
)
int_min_or_max::<i8>(symbol, var_store, i8::MAX, IntBound::Exact(IntWidth::I8))
}
/// Num.minU8: U8
fn num_min_u8(symbol: Symbol, var_store: &mut VarStore) -> Def {
int_min_or_max::<u8>(
symbol,
var_store,
u8::MIN,
NumericBound::Exact(IntWidth::U8),
)
int_min_or_max::<u8>(symbol, var_store, u8::MIN, IntBound::Exact(IntWidth::U8))
}
/// Num.maxU8: U8
fn num_max_u8(symbol: Symbol, var_store: &mut VarStore) -> Def {
int_min_or_max::<u8>(
symbol,
var_store,
u8::MAX,
NumericBound::Exact(IntWidth::U8),
)
int_min_or_max::<u8>(symbol, var_store, u8::MAX, IntBound::Exact(IntWidth::U8))
}
/// Num.minI16: I16
fn num_min_i16(symbol: Symbol, var_store: &mut VarStore) -> Def {
int_min_or_max::<i16>(
symbol,
var_store,
i16::MIN,
NumericBound::Exact(IntWidth::I16),
)
int_min_or_max::<i16>(symbol, var_store, i16::MIN, IntBound::Exact(IntWidth::I16))
}
/// Num.maxI16: I16
fn num_max_i16(symbol: Symbol, var_store: &mut VarStore) -> Def {
int_min_or_max::<i16>(
symbol,
var_store,
i16::MAX,
NumericBound::Exact(IntWidth::I16),
)
int_min_or_max::<i16>(symbol, var_store, i16::MAX, IntBound::Exact(IntWidth::I16))
}
/// Num.minU16: U16
fn num_min_u16(symbol: Symbol, var_store: &mut VarStore) -> Def {
int_min_or_max::<u16>(
symbol,
var_store,
u16::MIN,
NumericBound::Exact(IntWidth::U16),
)
int_min_or_max::<u16>(symbol, var_store, u16::MIN, IntBound::Exact(IntWidth::U16))
}
/// Num.maxU16: U16
fn num_max_u16(symbol: Symbol, var_store: &mut VarStore) -> Def {
int_min_or_max::<u16>(
symbol,
var_store,
u16::MAX,
NumericBound::Exact(IntWidth::U16),
)
int_min_or_max::<u16>(symbol, var_store, u16::MAX, IntBound::Exact(IntWidth::U16))
}
/// Num.minI32: I32
fn num_min_i32(symbol: Symbol, var_store: &mut VarStore) -> Def {
int_min_or_max::<i32>(
symbol,
var_store,
i32::MIN,
NumericBound::Exact(IntWidth::I32),
)
int_min_or_max::<i32>(symbol, var_store, i32::MIN, IntBound::Exact(IntWidth::I32))
}
/// Num.maxI32: I32
fn num_max_i32(symbol: Symbol, var_store: &mut VarStore) -> Def {
int_min_or_max::<i32>(
symbol,
var_store,
i32::MAX,
NumericBound::Exact(IntWidth::I32),
)
int_min_or_max::<i32>(symbol, var_store, i32::MAX, IntBound::Exact(IntWidth::I32))
}
/// Num.minU32: U32
fn num_min_u32(symbol: Symbol, var_store: &mut VarStore) -> Def {
int_min_or_max::<u32>(
symbol,
var_store,
u32::MIN,
NumericBound::Exact(IntWidth::U32),
)
int_min_or_max::<u32>(symbol, var_store, u32::MIN, IntBound::Exact(IntWidth::U32))
}
/// Num.maxU32: U32
fn num_max_u32(symbol: Symbol, var_store: &mut VarStore) -> Def {
int_min_or_max::<u32>(
symbol,
var_store,
u32::MAX,
NumericBound::Exact(IntWidth::U32),
)
int_min_or_max::<u32>(symbol, var_store, u32::MAX, IntBound::Exact(IntWidth::U32))
}
/// Num.minI64: I64
fn num_min_i64(symbol: Symbol, var_store: &mut VarStore) -> Def {
int_min_or_max::<i64>(
symbol,
var_store,
i64::MIN,
NumericBound::Exact(IntWidth::I64),
)
int_min_or_max::<i64>(symbol, var_store, i64::MIN, IntBound::Exact(IntWidth::I64))
}
/// Num.maxI64: I64
fn num_max_i64(symbol: Symbol, var_store: &mut VarStore) -> Def {
int_min_or_max::<i64>(
symbol,
var_store,
i64::MAX,
NumericBound::Exact(IntWidth::I64),
)
int_min_or_max::<i64>(symbol, var_store, i64::MAX, IntBound::Exact(IntWidth::I64))
}
/// Num.minU64: U64
fn num_min_u64(symbol: Symbol, var_store: &mut VarStore) -> Def {
int_min_or_max::<u64>(
symbol,
var_store,
u64::MIN,
NumericBound::Exact(IntWidth::U64),
)
int_min_or_max::<u64>(symbol, var_store, u64::MIN, IntBound::Exact(IntWidth::U64))
}
/// Num.maxU64: U64
fn num_max_u64(symbol: Symbol, var_store: &mut VarStore) -> Def {
int_min_or_max::<u64>(
symbol,
var_store,
u64::MAX,
NumericBound::Exact(IntWidth::U64),
)
int_min_or_max::<u64>(symbol, var_store, u64::MAX, IntBound::Exact(IntWidth::U64))
}
/// Num.minI128: I128
@ -1417,7 +1337,7 @@ fn num_min_i128(symbol: Symbol, var_store: &mut VarStore) -> Def {
symbol,
var_store,
i128::MIN,
NumericBound::Exact(IntWidth::I128),
IntBound::Exact(IntWidth::I128),
)
}
@ -1427,7 +1347,7 @@ fn num_max_i128(symbol: Symbol, var_store: &mut VarStore) -> Def {
symbol,
var_store,
i128::MAX,
NumericBound::Exact(IntWidth::I128),
IntBound::Exact(IntWidth::I128),
)
}
@ -1559,7 +1479,7 @@ fn str_to_num(symbol: Symbol, var_store: &mut VarStore) -> Def {
errorcode_var,
Variable::UNSIGNED8,
0,
NumericBound::Exact(IntWidth::U8),
IntBound::Exact(IntWidth::U8),
),
),
],
@ -2307,7 +2227,7 @@ fn list_take_first(symbol: Symbol, var_store: &mut VarStore) -> Def {
len_var,
Variable::NATURAL,
0,
NumericBound::Exact(IntWidth::Nat),
IntBound::Exact(IntWidth::Nat),
);
let body = RunLowLevel {
@ -2338,7 +2258,7 @@ fn list_take_last(symbol: Symbol, var_store: &mut VarStore) -> Def {
len_var,
Variable::NATURAL,
0,
NumericBound::Exact(IntWidth::Nat),
IntBound::Exact(IntWidth::Nat),
);
let bool_var = var_store.fresh();
@ -2453,7 +2373,7 @@ fn list_intersperse(symbol: Symbol, var_store: &mut VarStore) -> Def {
int_var,
Variable::NATURAL,
0,
NumericBound::Exact(IntWidth::Nat),
IntBound::Exact(IntWidth::Nat),
);
// \acc, elem -> acc |> List.append sep |> List.append elem
@ -2538,7 +2458,7 @@ fn list_split(symbol: Symbol, var_store: &mut VarStore) -> Def {
index_var,
Variable::NATURAL,
0,
NumericBound::Exact(IntWidth::Nat),
IntBound::Exact(IntWidth::Nat),
);
let clos = Closure(ClosureData {
@ -2703,7 +2623,7 @@ fn list_drop_first(symbol: Symbol, var_store: &mut VarStore) -> Def {
(list_var, Var(Symbol::ARG_1)),
(
index_var,
int::<i128>(num_var, num_precision_var, 0, num_no_bound()),
int::<i128>(num_var, num_precision_var, 0, int_no_bound()),
),
],
ret_var: list_var,
@ -2803,7 +2723,7 @@ fn list_drop_last(symbol: Symbol, var_store: &mut VarStore) -> Def {
),
(
arg_var,
int::<i128>(num_var, num_precision_var, 1, num_no_bound()),
int::<i128>(num_var, num_precision_var, 1, int_no_bound()),
),
],
ret_var: len_var,
@ -3004,7 +2924,7 @@ fn list_min(symbol: Symbol, var_store: &mut VarStore) -> Def {
args: vec![
(
len_var,
int::<i128>(num_var, num_precision_var, 0, num_no_bound()),
int::<i128>(num_var, num_precision_var, 0, int_no_bound()),
),
(
len_var,
@ -3042,7 +2962,7 @@ fn list_min(symbol: Symbol, var_store: &mut VarStore) -> Def {
num_var,
num_precision_var,
0,
num_no_bound(),
int_no_bound(),
),
),
],
@ -3145,7 +3065,7 @@ fn list_max(symbol: Symbol, var_store: &mut VarStore) -> Def {
args: vec![
(
len_var,
int::<i128>(num_var, num_precision_var, 0, num_no_bound()),
int::<i128>(num_var, num_precision_var, 0, int_no_bound()),
),
(
len_var,
@ -3183,7 +3103,7 @@ fn list_max(symbol: Symbol, var_store: &mut VarStore) -> Def {
num_var,
num_precision_var,
0,
num_no_bound(),
int_no_bound(),
),
),
],
@ -4076,7 +3996,7 @@ fn num_div_float(symbol: Symbol, var_store: &mut VarStore) -> Def {
(num_var, Var(Symbol::ARG_2)),
(
num_var,
float(unbound_zero_var, precision_var, 0.0, num_no_bound()),
float(unbound_zero_var, precision_var, 0.0, float_no_bound()),
),
],
ret_var: bool_var,
@ -4146,7 +4066,7 @@ fn num_div_int(symbol: Symbol, var_store: &mut VarStore) -> Def {
unbound_zero_var,
unbound_zero_precision_var,
0,
num_no_bound(),
int_no_bound(),
),
),
],
@ -4217,7 +4137,7 @@ fn num_div_ceil(symbol: Symbol, var_store: &mut VarStore) -> Def {
unbound_zero_var,
unbound_zero_precision_var,
0,
num_no_bound(),
int_no_bound(),
),
),
],
@ -4290,7 +4210,7 @@ fn list_first(symbol: Symbol, var_store: &mut VarStore) -> Def {
args: vec![
(
len_var,
int::<i128>(zero_var, zero_precision_var, 0, num_no_bound()),
int::<i128>(zero_var, zero_precision_var, 0, int_no_bound()),
),
(
len_var,
@ -4317,7 +4237,7 @@ fn list_first(symbol: Symbol, var_store: &mut VarStore) -> Def {
(list_var, Var(Symbol::ARG_1)),
(
len_var,
int::<i128>(zero_var, zero_precision_var, 0, num_no_bound()),
int::<i128>(zero_var, zero_precision_var, 0, int_no_bound()),
),
],
ret_var: list_elem_var,
@ -4377,7 +4297,7 @@ fn list_last(symbol: Symbol, var_store: &mut VarStore) -> Def {
args: vec![
(
len_var,
int::<i128>(num_var, num_precision_var, 0, num_no_bound()),
int::<i128>(num_var, num_precision_var, 0, int_no_bound()),
),
(
len_var,
@ -4423,7 +4343,7 @@ fn list_last(symbol: Symbol, var_store: &mut VarStore) -> Def {
num_var,
num_precision_var,
1,
num_no_bound(),
int_no_bound(),
),
),
],
@ -5144,12 +5064,7 @@ fn defn_help(
}
#[inline(always)]
fn int_min_or_max<I128>(
symbol: Symbol,
var_store: &mut VarStore,
i: I128,
bound: NumericBound<IntWidth>,
) -> Def
fn int_min_or_max<I128>(symbol: Symbol, var_store: &mut VarStore, i: I128, bound: IntBound) -> Def
where
I128: Into<i128>,
{
@ -5178,17 +5093,20 @@ where
}
}
fn num_no_bound<W: Copy>() -> NumericBound<W> {
fn num_no_bound() -> NumericBound {
NumericBound::None
}
fn int_no_bound() -> IntBound {
IntBound::None
}
fn float_no_bound() -> FloatBound {
FloatBound::None
}
#[inline(always)]
fn int<I128>(
num_var: Variable,
precision_var: Variable,
i: I128,
bound: NumericBound<IntWidth>,
) -> Expr
fn int<I128>(num_var: Variable, precision_var: Variable, i: I128, bound: IntBound) -> Expr
where
I128: Into<i128>,
{
@ -5203,12 +5121,7 @@ where
}
#[inline(always)]
fn float(
num_var: Variable,
precision_var: Variable,
f: f64,
bound: NumericBound<FloatWidth>,
) -> Expr {
fn float(num_var: Variable, precision_var: Variable, f: f64, bound: FloatBound) -> Expr {
Float(
num_var,
precision_var,
@ -5219,7 +5132,7 @@ fn float(
}
#[inline(always)]
fn num<I: Into<i128>>(num_var: Variable, i: I, bound: NumericBound<NumWidth>) -> Expr {
fn num<I: Into<i128>>(num_var: Variable, i: I, bound: NumericBound) -> Expr {
let i = i.into();
Num(
num_var,

View file

@ -27,6 +27,14 @@ pub enum Constraint {
Let(Box<LetConstraint>),
And(Vec<Constraint>),
Present(Type, PresenceConstraint),
/// `EqBoundedRange(Ts, U, ...)` means there must be at least one `T` in the *ordered* range `Ts`
/// that unifies (via `Eq`) with `U`.
///
/// This is only used for integers, where we may see e.g. the number literal `-1` and know it
/// has the bounded range `[I8, I16, I32, I64, I128]`, at least one of which must unify with
/// the type the number literal is used as.
EqBoundedRange(Type, Expected<Vec<Type>>, Category, Region),
}
#[derive(Debug, Clone, PartialEq)]
@ -87,6 +95,7 @@ impl Constraint {
}
Constraint::And(cs) => cs.iter().any(|c| c.contains_save_the_environment()),
Constraint::Present(_, _) => false,
Constraint::EqBoundedRange(_, _, _, _) => false,
}
}
}
@ -171,5 +180,11 @@ fn validate_help(constraint: &Constraint, declared: &Declared, accum: &mut Varia
}
}
}
Constraint::EqBoundedRange(typ, one_of, _, _) => {
subtract(declared, &typ.variables_detail(), accum);
for typ in one_of.get_type_ref() {
subtract(declared, &typ.variables_detail(), accum);
}
}
}
}

View file

@ -4,7 +4,7 @@ use crate::def::{can_defs_with_return, Def};
use crate::env::Env;
use crate::num::{
finish_parsing_base, finish_parsing_float, finish_parsing_num, float_expr_from_result,
int_expr_from_result, num_expr_from_result, FloatWidth, IntWidth, NumWidth, NumericBound,
int_expr_from_result, num_expr_from_result, FloatBound, IntBound, NumericBound,
};
use crate::pattern::{canonicalize_pattern, Pattern};
use crate::procedure::References;
@ -67,17 +67,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, Box<str>, IntValue, NumericBound<NumWidth>),
Num(Variable, Box<str>, IntValue, NumericBound),
// Int and Float store a variable to generate better error messages
Int(
Variable,
Variable,
Box<str>,
IntValue,
NumericBound<IntWidth>,
),
Float(Variable, Variable, Box<str>, f64, NumericBound<FloatWidth>),
Int(Variable, Variable, Box<str>, IntValue, IntBound),
Float(Variable, Variable, Box<str>, f64, FloatBound),
Str(Box<str>),
List {
elem_var: Variable,

View file

@ -50,7 +50,7 @@ pub fn num_expr_from_result(
#[inline(always)]
pub fn int_expr_from_result(
var_store: &mut VarStore,
result: Result<(&str, IntValue, NumericBound<IntWidth>), (&str, IntErrorKind)>,
result: Result<(&str, IntValue, IntBound), (&str, IntErrorKind)>,
region: Region,
base: Base,
env: &mut Env,
@ -77,7 +77,7 @@ pub fn int_expr_from_result(
#[inline(always)]
pub fn float_expr_from_result(
var_store: &mut VarStore,
result: Result<(&str, f64, NumericBound<FloatWidth>), (&str, FloatErrorKind)>,
result: Result<(&str, f64, FloatBound), (&str, FloatErrorKind)>,
region: Region,
env: &mut Env,
) -> Expr {
@ -101,8 +101,8 @@ pub fn float_expr_from_result(
}
pub enum ParsedNumResult {
Int(IntValue, NumericBound<IntWidth>),
Float(f64, NumericBound<FloatWidth>),
Int(IntValue, IntBound),
Float(f64, FloatBound),
UnknownNum(IntValue),
}
@ -115,15 +115,13 @@ pub fn finish_parsing_num(raw: &str) -> Result<ParsedNumResult, (&str, IntErrorK
// Let's try to specialize the number
Ok(match bound {
NumericBound::None => ParsedNumResult::UnknownNum(num),
NumericBound::Exact(NumWidth::Int(iw)) => {
ParsedNumResult::Int(num, NumericBound::Exact(iw))
}
NumericBound::Exact(NumWidth::Float(fw)) => {
NumericBound::Int(ib) => ParsedNumResult::Int(num, ib),
NumericBound::Float(fb) => {
let num = match num {
IntValue::I128(n) => n as f64,
IntValue::U128(n) => n as f64,
};
ParsedNumResult::Float(num, NumericBound::Exact(fw))
ParsedNumResult::Float(num, fb)
}
})
}
@ -133,7 +131,7 @@ pub fn finish_parsing_base(
raw: &str,
base: Base,
is_negative: bool,
) -> Result<(IntValue, NumericBound<IntWidth>), (&str, IntErrorKind)> {
) -> Result<(IntValue, IntBound), (&str, IntErrorKind)> {
let radix = match base {
Base::Hex => 16,
Base::Decimal => 10,
@ -149,9 +147,9 @@ pub fn finish_parsing_base(
})
.and_then(|(n, bound)| {
let bound = match bound {
NumericBound::None => NumericBound::None,
NumericBound::Exact(NumWidth::Int(iw)) => NumericBound::Exact(iw),
NumericBound::Exact(NumWidth::Float(_)) => return Err(IntErrorKind::FloatSuffix),
NumericBound::None => IntBound::None,
NumericBound::Int(ib) => ib,
NumericBound::Float(_) => return Err(IntErrorKind::FloatSuffix),
};
Ok((n, bound))
})
@ -159,15 +157,13 @@ pub fn finish_parsing_base(
}
#[inline(always)]
pub fn finish_parsing_float(
raw: &str,
) -> Result<(f64, NumericBound<FloatWidth>), (&str, FloatErrorKind)> {
pub fn finish_parsing_float(raw: &str) -> Result<(f64, FloatBound), (&str, FloatErrorKind)> {
let (opt_bound, raw_without_suffix) = parse_literal_suffix(raw);
let bound = match opt_bound {
None => NumericBound::None,
Some(NumWidth::Float(fw)) => NumericBound::Exact(fw),
Some(NumWidth::Int(_)) => return Err((raw, FloatErrorKind::IntSuffix)),
None => FloatBound::None,
Some(ParsedWidth::Float(fw)) => FloatBound::Exact(fw),
Some(ParsedWidth::Int(_)) => return Err((raw, FloatErrorKind::IntSuffix)),
};
// Ignore underscores.
@ -184,7 +180,13 @@ pub fn finish_parsing_float(
}
}
fn parse_literal_suffix(num_str: &str) -> (Option<NumWidth>, &str) {
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
enum ParsedWidth {
Int(IntWidth),
Float(FloatWidth),
}
fn parse_literal_suffix(num_str: &str) -> (Option<ParsedWidth>, &str) {
macro_rules! parse_num_suffix {
($($suffix:expr, $width:expr)*) => {$(
if num_str.ends_with($suffix) {
@ -194,20 +196,20 @@ fn parse_literal_suffix(num_str: &str) -> (Option<NumWidth>, &str) {
}
parse_num_suffix! {
"u8", NumWidth::Int(IntWidth::U8)
"u16", NumWidth::Int(IntWidth::U16)
"u32", NumWidth::Int(IntWidth::U32)
"u64", NumWidth::Int(IntWidth::U64)
"u128", NumWidth::Int(IntWidth::U128)
"i8", NumWidth::Int(IntWidth::I8)
"i16", NumWidth::Int(IntWidth::I16)
"i32", NumWidth::Int(IntWidth::I32)
"i64", NumWidth::Int(IntWidth::I64)
"i128", NumWidth::Int(IntWidth::I128)
"nat", NumWidth::Int(IntWidth::Nat)
"dec", NumWidth::Float(FloatWidth::Dec)
"f32", NumWidth::Float(FloatWidth::F32)
"f64", NumWidth::Float(FloatWidth::F64)
"u8", ParsedWidth::Int(IntWidth::U8)
"u16", ParsedWidth::Int(IntWidth::U16)
"u32", ParsedWidth::Int(IntWidth::U32)
"u64", ParsedWidth::Int(IntWidth::U64)
"u128", ParsedWidth::Int(IntWidth::U128)
"i8", ParsedWidth::Int(IntWidth::I8)
"i16", ParsedWidth::Int(IntWidth::I16)
"i32", ParsedWidth::Int(IntWidth::I32)
"i64", ParsedWidth::Int(IntWidth::I64)
"i128", ParsedWidth::Int(IntWidth::I128)
"nat", ParsedWidth::Int(IntWidth::Nat)
"dec", ParsedWidth::Float(FloatWidth::Dec)
"f32", ParsedWidth::Float(FloatWidth::F32)
"f64", ParsedWidth::Float(FloatWidth::F64)
}
(None, num_str)
@ -221,10 +223,7 @@ fn parse_literal_suffix(num_str: &str) -> (Option<NumWidth>, &str) {
/// the LEGAL_DETAILS file in the root directory of this distribution.
///
/// Thanks to the Rust project and its contributors!
fn from_str_radix(
src: &str,
radix: u32,
) -> Result<(IntValue, NumericBound<NumWidth>), IntErrorKind> {
fn from_str_radix(src: &str, radix: u32) -> Result<(IntValue, NumericBound), IntErrorKind> {
use self::IntErrorKind::*;
assert!(
@ -268,19 +267,31 @@ fn from_str_radix(
match opt_exact_bound {
None => {
// TODO: use the lower bound
Ok((result, NumericBound::None))
// There's no exact bound, but we do have a lower bound.
let sign_demand = if is_negative {
SignDemand::Signed
} else {
SignDemand::NoDemand
};
Ok((
result,
IntBound::AtLeast {
sign: sign_demand,
width: lower_bound,
}
.into(),
))
}
Some(bound @ NumWidth::Float(_)) => {
Some(ParsedWidth::Float(fw)) => {
// For now, assume floats can represent all integers
// TODO: this is somewhat incorrect, revisit
Ok((result, NumericBound::Exact(bound)))
Ok((result, FloatBound::Exact(fw).into()))
}
Some(NumWidth::Int(exact_width)) => {
Some(ParsedWidth::Int(exact_width)) => {
// We need to check if the exact bound >= lower bound.
if exact_width.is_superset(&lower_bound, is_negative) {
// Great! Use the exact bound.
Ok((result, NumericBound::Exact(NumWidth::Int(exact_width))))
Ok((result, IntBound::Exact(exact_width).into()))
} else {
// This is something like 200i8; the lower bound is u8, which holds strictly more
// ints on the positive side than i8 does. Report an error depending on which side
@ -474,19 +485,47 @@ pub enum FloatWidth {
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum NumWidth {
Int(IntWidth),
Float(FloatWidth),
pub enum SignDemand {
/// Can be signed or unsigned.
NoDemand,
/// Must be signed.
Signed,
}
/// Describes a bound on the width of a numeric literal.
/// Describes a bound on the width of an integer.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum NumericBound<W>
where
W: Copy,
{
pub enum IntBound {
/// There is no bound on the width.
None,
/// Must have exactly the width `W`.
Exact(W),
/// Must have an exact width.
Exact(IntWidth),
/// Must have a certain sign and a minimum width.
AtLeast { sign: SignDemand, width: IntWidth },
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum FloatBound {
None,
Exact(FloatWidth),
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum NumericBound {
None,
Int(IntBound),
Float(FloatBound),
}
impl From<IntBound> for NumericBound {
#[inline(always)]
fn from(ib: IntBound) -> Self {
Self::Int(ib)
}
}
impl From<FloatBound> for NumericBound {
#[inline(always)]
fn from(fb: FloatBound) -> Self {
Self::Float(fb)
}
}

View file

@ -1,7 +1,7 @@
use crate::env::Env;
use crate::expr::{canonicalize_expr, unescape_char, Expr, IntValue, Output};
use crate::num::{
finish_parsing_base, finish_parsing_float, finish_parsing_num, FloatWidth, IntWidth, NumWidth,
finish_parsing_base, finish_parsing_float, finish_parsing_num, FloatBound, IntBound,
NumericBound, ParsedNumResult,
};
use crate::scope::Scope;
@ -29,15 +29,9 @@ pub enum Pattern {
ext_var: Variable,
destructs: Vec<Loc<RecordDestruct>>,
},
NumLiteral(Variable, Box<str>, IntValue, NumericBound<NumWidth>),
IntLiteral(
Variable,
Variable,
Box<str>,
IntValue,
NumericBound<IntWidth>,
),
FloatLiteral(Variable, Variable, Box<str>, f64, NumericBound<FloatWidth>),
NumLiteral(Variable, Box<str>, IntValue, NumericBound),
IntLiteral(Variable, Variable, Box<str>, IntValue, IntBound),
FloatLiteral(Variable, Variable, Box<str>, f64, FloatBound),
StrLiteral(Box<str>),
Underscore,