This commit is contained in:
Folkert 2022-05-21 20:50:06 +02:00
parent 98ce9f4d09
commit d43bda83b4
No known key found for this signature in database
GPG Key ID: 1F17F6FFD112B97C
5 changed files with 37 additions and 113 deletions

View File

@ -4,7 +4,7 @@ use roc_can::expected::Expected::{self, *};
use roc_can::num::{FloatBound, FloatWidth, IntBound, IntWidth, NumBound, SignDemand};
use roc_module::symbol::Symbol;
use roc_region::all::Region;
use roc_types::num::NumericBound;
use roc_types::num::NumericRange;
use roc_types::subs::Variable;
use roc_types::types::Type::{self, *};
use roc_types::types::{AliasKind, Category};
@ -23,6 +23,8 @@ pub fn add_numeric_bound_constr(
let range = bound.numeric_bound();
let total_num_type = num_type;
use roc_types::num::{float_width_to_variable, int_width_to_variable};
match range {
NumericBound::None => {
// no additional constraints
@ -48,10 +50,7 @@ pub fn add_numeric_bound_constr(
total_num_type
}
NumericBound::IntAtLeastSigned(_)
| NumericBound::IntAtLeastEitherSign(_)
| NumericBound::NumAtLeastSigned(_)
| NumericBound::NumAtLeastEitherSign(_) => RangedNumber(Box::new(total_num_type), range),
NumericBound::Range(range) => RangedNumber(Box::new(total_num_type), range),
}
}
@ -280,68 +279,10 @@ pub fn num_num(typ: Type) -> Type {
}
pub trait TypedNumericBound {
fn bounded_range(&self) -> Vec<Variable>;
fn numeric_bound(&self) -> NumericBound;
}
const fn int_width_to_variable(w: IntWidth) -> Variable {
match w {
IntWidth::U8 => Variable::U8,
IntWidth::U16 => Variable::U16,
IntWidth::U32 => Variable::U32,
IntWidth::U64 => Variable::U64,
IntWidth::U128 => Variable::U128,
IntWidth::I8 => Variable::I8,
IntWidth::I16 => Variable::I16,
IntWidth::I32 => Variable::I32,
IntWidth::I64 => Variable::I64,
IntWidth::I128 => Variable::I128,
IntWidth::Nat => Variable::NAT,
}
}
const NO_DEMAND_INT_VARIABLES: &[(IntWidth, Variable)] = &[
(IntWidth::I8, Variable::I8),
(IntWidth::U8, Variable::U8),
(IntWidth::I16, Variable::I16),
(IntWidth::U16, Variable::U16),
(IntWidth::I32, Variable::I32),
(IntWidth::U32, Variable::U32),
(IntWidth::I64, Variable::I64),
(IntWidth::Nat, Variable::NAT), // FIXME: Nat's order here depends on the platform!
(IntWidth::U64, Variable::U64),
(IntWidth::I128, Variable::I128),
(IntWidth::U128, Variable::U128),
];
const SIGNED_INT_VARIABLES: &[(IntWidth, Variable)] = &[
(IntWidth::I8, Variable::I8),
(IntWidth::I16, Variable::I16),
(IntWidth::I32, Variable::I32),
(IntWidth::I64, Variable::I64),
(IntWidth::I128, Variable::I128),
];
impl TypedNumericBound for IntBound {
fn bounded_range(&self) -> Vec<Variable> {
match self {
IntBound::None => vec![],
IntBound::Exact(w) => vec![int_width_to_variable(*w)],
IntBound::AtLeast { sign, width } => {
let whole_range: &[(IntWidth, Variable)] = match sign {
SignDemand::NoDemand => NO_DEMAND_INT_VARIABLES,
SignDemand::Signed => SIGNED_INT_VARIABLES,
};
whole_range
.iter()
.skip_while(|(lower_bound, _)| *lower_bound != *width)
.map(|(_, var)| *var)
.collect()
}
}
}
fn numeric_bound(&self) -> NumericBound {
match self {
IntBound::None => NumericBound::None,
@ -349,35 +290,16 @@ impl TypedNumericBound for IntBound {
IntBound::AtLeast {
sign: SignDemand::NoDemand,
width,
} => NumericBound::IntAtLeastEitherSign(*width),
} => NumericBound::Range(NumericRange::IntAtLeastEitherSign(*width)),
IntBound::AtLeast {
sign: SignDemand::Signed,
width,
} => NumericBound::IntAtLeastSigned(*width),
} => NumericBound::Range(NumericRange::IntAtLeastSigned(*width)),
}
}
}
const fn float_width_to_variable(w: FloatWidth) -> Variable {
match w {
FloatWidth::Dec => Variable::DEC,
FloatWidth::F32 => Variable::F32,
FloatWidth::F64 => Variable::F64,
}
}
impl TypedNumericBound for FloatBound {
fn bounded_range(&self) -> Vec<Variable> {
match self {
FloatBound::None => vec![],
FloatBound::Exact(w) => vec![match w {
FloatWidth::Dec => Variable::DEC,
FloatWidth::F32 => Variable::F32,
FloatWidth::F64 => Variable::F64,
}],
}
}
fn numeric_bound(&self) -> NumericBound {
match self {
FloatBound::None => NumericBound::None,
@ -387,28 +309,27 @@ impl TypedNumericBound for FloatBound {
}
impl TypedNumericBound for NumBound {
fn bounded_range(&self) -> Vec<Variable> {
match self {
NumBound::None => vec![],
&NumBound::AtLeastIntOrFloat { sign, width } => {
let mut range = IntBound::AtLeast { sign, width }.bounded_range();
range.extend_from_slice(&[Variable::F32, Variable::F64, Variable::DEC]);
range
}
}
}
fn numeric_bound(&self) -> NumericBound {
match self {
NumBound::None => NumericBound::None,
&NumBound::AtLeastIntOrFloat {
sign: SignDemand::NoDemand,
width,
} => NumericBound::NumAtLeastEitherSign(width),
} => NumericBound::Range(NumericRange::NumAtLeastEitherSign(width)),
&NumBound::AtLeastIntOrFloat {
sign: SignDemand::Signed,
width,
} => NumericBound::NumAtLeastSigned(width),
} => NumericBound::Range(NumericRange::NumAtLeastSigned(width)),
}
}
}
/// A bound placed on a number because of its literal value.
/// e.g. `-5` cannot be unsigned, and 300 does not fit in a U8
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NumericBound {
None,
FloatExact(FloatWidth),
IntExact(IntWidth),
Range(NumericRange),
}

View File

@ -4,17 +4,14 @@ use roc_module::symbol::Symbol;
/// A bound placed on a number because of its literal value.
/// e.g. `-5` cannot be unsigned, and 300 does not fit in a U8
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NumericBound {
None,
FloatExact(FloatWidth),
IntExact(IntWidth),
pub enum NumericRange {
IntAtLeastSigned(IntWidth),
IntAtLeastEitherSign(IntWidth),
NumAtLeastSigned(IntWidth),
NumAtLeastEitherSign(IntWidth),
}
impl NumericBound {
impl NumericRange {
pub fn contains_symbol(&self, symbol: Symbol) -> bool {
match symbol {
Symbol::NUM_I8 => self.contains_int_width(IntWidth::I8),
@ -47,14 +44,13 @@ impl NumericBound {
}
fn contains_int_width(&self, width: IntWidth) -> bool {
use NumericBound::*;
use NumericRange::*;
let (range_sign, at_least_width) = match self {
IntAtLeastSigned(width) => (SignDemand::Signed, width),
IntAtLeastEitherSign(width) => (SignDemand::NoDemand, width),
NumAtLeastSigned(width) => (SignDemand::Signed, width),
NumAtLeastEitherSign(width) => (SignDemand::NoDemand, width),
_ => panic!(),
};
let (actual_sign, _) = width.sign_and_width();
@ -67,7 +63,7 @@ impl NumericBound {
}
pub fn variable_slice(&self) -> &'static [Variable] {
use NumericBound::*;
use NumericRange::*;
match self {
IntAtLeastSigned(width) => {
@ -96,7 +92,6 @@ impl NumericBound {
&ALL_VARIABLES[start..]
}
_ => panic!(),
}
}
}
@ -267,7 +262,7 @@ pub enum NumBound {
},
}
const fn int_width_to_variable(w: IntWidth) -> Variable {
pub const fn int_width_to_variable(w: IntWidth) -> Variable {
match w {
IntWidth::U8 => Variable::U8,
IntWidth::U16 => Variable::U16,
@ -283,6 +278,14 @@ const fn int_width_to_variable(w: IntWidth) -> Variable {
}
}
pub const fn float_width_to_variable(w: FloatWidth) -> Variable {
match w {
FloatWidth::Dec => Variable::DEC,
FloatWidth::F32 => Variable::F32,
FloatWidth::F64 => Variable::F64,
}
}
const ALL_VARIABLES: &[Variable] = &[
Variable::I8,
Variable::U8,

View File

@ -2008,7 +2008,7 @@ pub enum Content {
},
Structure(FlatType),
Alias(Symbol, AliasVariables, Variable, AliasKind),
RangedNumber(Variable, crate::num::NumericBound),
RangedNumber(Variable, crate::num::NumericRange),
Error,
}

View File

@ -1,4 +1,4 @@
use crate::num::NumericBound;
use crate::num::NumericRange;
use crate::pretty_print::Parens;
use crate::subs::{
GetSubsSlice, RecordFields, Subs, UnionTags, VarStore, Variable, VariableSubsSlice,
@ -255,7 +255,7 @@ pub enum Type {
/// Applying a type to some arguments (e.g. Dict.Dict String Int)
Apply(Symbol, Vec<Type>, Region),
Variable(Variable),
RangedNumber(Box<Type>, NumericBound),
RangedNumber(Box<Type>, NumericRange),
/// A type error, which will code gen to a runtime error
Erroneous(Problem),
}

View File

@ -5,7 +5,7 @@ use roc_debug_flags::{ROC_PRINT_MISMATCHES, ROC_PRINT_UNIFICATIONS};
use roc_error_macros::internal_error;
use roc_module::ident::{Lowercase, TagName};
use roc_module::symbol::Symbol;
use roc_types::num::NumericBound;
use roc_types::num::NumericRange;
use roc_types::subs::Content::{self, *};
use roc_types::subs::{
AliasVariables, Descriptor, ErrorTypeContext, FlatType, GetSubsSlice, Mark, OptVariable,
@ -414,7 +414,7 @@ fn unify_ranged_number(
pool: &mut Pool,
ctx: &Context,
real_var: Variable,
range_vars: NumericBound,
range_vars: NumericRange,
) -> Outcome {
let other_content = &ctx.second_desc.content;
@ -448,7 +448,7 @@ fn unify_ranged_number(
check_valid_range(subs, ctx.second, range_vars)
}
fn check_valid_range(subs: &mut Subs, var: Variable, range: NumericBound) -> Outcome {
fn check_valid_range(subs: &mut Subs, var: Variable, range: NumericRange) -> Outcome {
let content = subs.get_content_without_compacting(var);
match content {