mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 21:39:07 +00:00
refactor number bounds
This commit is contained in:
parent
b46721e43b
commit
cb40aab21f
7 changed files with 186 additions and 185 deletions
|
@ -1,7 +1,7 @@
|
||||||
use crate::def::Def;
|
use crate::def::Def;
|
||||||
use crate::expr::{self, AnnotatedMark, ClosureData, Expr::*, IntValue};
|
use crate::expr::{self, AnnotatedMark, ClosureData, Expr::*, IntValue};
|
||||||
use crate::expr::{Expr, Field, Recursive};
|
use crate::expr::{Expr, Field, Recursive};
|
||||||
use crate::num::{FloatBound, IntBound, IntWidth, NumericBound};
|
use crate::num::{FloatBound, IntBound, IntWidth, NumBound};
|
||||||
use crate::pattern::Pattern;
|
use crate::pattern::Pattern;
|
||||||
use roc_collections::all::SendMap;
|
use roc_collections::all::SendMap;
|
||||||
use roc_module::called_via::CalledVia;
|
use roc_module::called_via::CalledVia;
|
||||||
|
@ -5414,8 +5414,8 @@ fn defn_help(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn num_no_bound() -> NumericBound {
|
fn num_no_bound() -> NumBound {
|
||||||
NumericBound::None
|
NumBound::None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn int_no_bound() -> IntBound {
|
fn int_no_bound() -> IntBound {
|
||||||
|
@ -5453,7 +5453,7 @@ fn frac(num_var: Variable, precision_var: Variable, f: f64, bound: FloatBound) -
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn num<I: Into<i128>>(num_var: Variable, i: I, bound: NumericBound) -> Expr {
|
fn num<I: Into<i128>>(num_var: Variable, i: I, bound: NumBound) -> Expr {
|
||||||
let i = i.into();
|
let i = i.into();
|
||||||
Num(
|
Num(
|
||||||
num_var,
|
num_var,
|
||||||
|
|
|
@ -5,7 +5,7 @@ use crate::def::{can_defs_with_return, Def};
|
||||||
use crate::env::Env;
|
use crate::env::Env;
|
||||||
use crate::num::{
|
use crate::num::{
|
||||||
finish_parsing_base, finish_parsing_float, finish_parsing_num, float_expr_from_result,
|
finish_parsing_base, finish_parsing_float, finish_parsing_num, float_expr_from_result,
|
||||||
int_expr_from_result, num_expr_from_result, FloatBound, IntBound, NumericBound,
|
int_expr_from_result, num_expr_from_result, FloatBound, IntBound, NumBound,
|
||||||
};
|
};
|
||||||
use crate::pattern::{canonicalize_pattern, BindingsFromPattern, Pattern};
|
use crate::pattern::{canonicalize_pattern, BindingsFromPattern, Pattern};
|
||||||
use crate::procedure::References;
|
use crate::procedure::References;
|
||||||
|
@ -82,7 +82,7 @@ pub enum Expr {
|
||||||
|
|
||||||
// Num stores the `a` variable in `Num a`. Not the same as the variable
|
// 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
|
// stored in Int and Float below, which is strictly for better error messages
|
||||||
Num(Variable, Box<str>, IntValue, NumericBound),
|
Num(Variable, Box<str>, IntValue, NumBound),
|
||||||
|
|
||||||
// Int and Float store a variable to generate better error messages
|
// Int and Float store a variable to generate better error messages
|
||||||
Int(Variable, Variable, Box<str>, IntValue, IntBound),
|
Int(Variable, Variable, Box<str>, IntValue, IntBound),
|
||||||
|
|
|
@ -5,8 +5,9 @@ use roc_problem::can::Problem;
|
||||||
use roc_problem::can::RuntimeError::*;
|
use roc_problem::can::RuntimeError::*;
|
||||||
use roc_problem::can::{FloatErrorKind, IntErrorKind};
|
use roc_problem::can::{FloatErrorKind, IntErrorKind};
|
||||||
use roc_region::all::Region;
|
use roc_region::all::Region;
|
||||||
|
pub use roc_types::num::{FloatBound, FloatWidth, IntBound, IntWidth, NumBound, SignDemand};
|
||||||
use roc_types::subs::VarStore;
|
use roc_types::subs::VarStore;
|
||||||
use std::i64;
|
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -103,7 +104,7 @@ pub fn float_expr_from_result(
|
||||||
pub enum ParsedNumResult {
|
pub enum ParsedNumResult {
|
||||||
Int(IntValue, IntBound),
|
Int(IntValue, IntBound),
|
||||||
Float(f64, FloatBound),
|
Float(f64, FloatBound),
|
||||||
UnknownNum(IntValue, NumericBound),
|
UnknownNum(IntValue, NumBound),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -139,8 +140,8 @@ pub fn finish_parsing_base(
|
||||||
.and_then(|parsed| match parsed {
|
.and_then(|parsed| match parsed {
|
||||||
ParsedNumResult::Float(..) => Err(IntErrorKind::FloatSuffix),
|
ParsedNumResult::Float(..) => Err(IntErrorKind::FloatSuffix),
|
||||||
ParsedNumResult::Int(val, bound) => Ok((val, bound)),
|
ParsedNumResult::Int(val, bound) => Ok((val, bound)),
|
||||||
ParsedNumResult::UnknownNum(val, NumericBound::None) => Ok((val, IntBound::None)),
|
ParsedNumResult::UnknownNum(val, NumBound::None) => Ok((val, IntBound::None)),
|
||||||
ParsedNumResult::UnknownNum(val, NumericBound::AtLeastIntOrFloat { sign, width }) => {
|
ParsedNumResult::UnknownNum(val, NumBound::AtLeastIntOrFloat { sign, width }) => {
|
||||||
Ok((val, IntBound::AtLeast { sign, width }))
|
Ok((val, IntBound::AtLeast { sign, width }))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -270,7 +271,7 @@ fn from_str_radix(src: &str, radix: u32) -> Result<ParsedNumResult, IntErrorKind
|
||||||
};
|
};
|
||||||
Ok(ParsedNumResult::UnknownNum(
|
Ok(ParsedNumResult::UnknownNum(
|
||||||
result,
|
result,
|
||||||
NumericBound::AtLeastIntOrFloat {
|
NumBound::AtLeastIntOrFloat {
|
||||||
sign: sign_demand,
|
sign: sign_demand,
|
||||||
width: lower_bound,
|
width: lower_bound,
|
||||||
},
|
},
|
||||||
|
@ -352,169 +353,3 @@ fn lower_bound_of_int(result: i128) -> IntWidth {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
|
||||||
enum IntSign {
|
|
||||||
Unsigned,
|
|
||||||
Signed,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
|
||||||
pub enum IntWidth {
|
|
||||||
U8,
|
|
||||||
U16,
|
|
||||||
U32,
|
|
||||||
U64,
|
|
||||||
U128,
|
|
||||||
I8,
|
|
||||||
I16,
|
|
||||||
I32,
|
|
||||||
I64,
|
|
||||||
I128,
|
|
||||||
Nat,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IntWidth {
|
|
||||||
/// Returns the `IntSign` and bit width of a variant.
|
|
||||||
fn sign_and_width(&self) -> (IntSign, u32) {
|
|
||||||
use IntSign::*;
|
|
||||||
use IntWidth::*;
|
|
||||||
match self {
|
|
||||||
U8 => (Unsigned, 8),
|
|
||||||
U16 => (Unsigned, 16),
|
|
||||||
U32 => (Unsigned, 32),
|
|
||||||
U64 => (Unsigned, 64),
|
|
||||||
U128 => (Unsigned, 128),
|
|
||||||
I8 => (Signed, 8),
|
|
||||||
I16 => (Signed, 16),
|
|
||||||
I32 => (Signed, 32),
|
|
||||||
I64 => (Signed, 64),
|
|
||||||
I128 => (Signed, 128),
|
|
||||||
// TODO: this is platform specific!
|
|
||||||
Nat => (Unsigned, 64),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn type_str(&self) -> &'static str {
|
|
||||||
use IntWidth::*;
|
|
||||||
match self {
|
|
||||||
U8 => "U8",
|
|
||||||
U16 => "U16",
|
|
||||||
U32 => "U32",
|
|
||||||
U64 => "U64",
|
|
||||||
U128 => "U128",
|
|
||||||
I8 => "I8",
|
|
||||||
I16 => "I16",
|
|
||||||
I32 => "I32",
|
|
||||||
I64 => "I64",
|
|
||||||
I128 => "I128",
|
|
||||||
Nat => "Nat",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn max_value(&self) -> u128 {
|
|
||||||
use IntWidth::*;
|
|
||||||
match self {
|
|
||||||
U8 => u8::MAX as u128,
|
|
||||||
U16 => u16::MAX as u128,
|
|
||||||
U32 => u32::MAX as u128,
|
|
||||||
U64 => u64::MAX as u128,
|
|
||||||
U128 => u128::MAX,
|
|
||||||
I8 => i8::MAX as u128,
|
|
||||||
I16 => i16::MAX as u128,
|
|
||||||
I32 => i32::MAX as u128,
|
|
||||||
I64 => i64::MAX as u128,
|
|
||||||
I128 => i128::MAX as u128,
|
|
||||||
// TODO: this is platform specific!
|
|
||||||
Nat => u64::MAX as u128,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn min_value(&self) -> i128 {
|
|
||||||
use IntWidth::*;
|
|
||||||
match self {
|
|
||||||
U8 | U16 | U32 | U64 | U128 | Nat => 0,
|
|
||||||
I8 => i8::MIN as i128,
|
|
||||||
I16 => i16::MIN as i128,
|
|
||||||
I32 => i32::MIN as i128,
|
|
||||||
I64 => i64::MIN as i128,
|
|
||||||
I128 => i128::MIN,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks if `self` represents superset of integers that `lower_bound` represents, on a particular
|
|
||||||
/// side of the integers relative to 0.
|
|
||||||
///
|
|
||||||
/// If `is_negative` is true, the negative side is checked; otherwise the positive side is checked.
|
|
||||||
pub fn is_superset(&self, lower_bound: &Self, is_negative: bool) -> bool {
|
|
||||||
use IntSign::*;
|
|
||||||
|
|
||||||
if is_negative {
|
|
||||||
match (self.sign_and_width(), lower_bound.sign_and_width()) {
|
|
||||||
((Signed, us), (Signed, lower_bound)) => us >= lower_bound,
|
|
||||||
// Unsigned ints can never represent negative numbers; signed (non-zero width)
|
|
||||||
// ints always can.
|
|
||||||
((Unsigned, _), (Signed, _)) => false,
|
|
||||||
((Signed, _), (Unsigned, _)) => true,
|
|
||||||
// Trivially true; both can only express 0.
|
|
||||||
((Unsigned, _), (Unsigned, _)) => true,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
match (self.sign_and_width(), lower_bound.sign_and_width()) {
|
|
||||||
((Signed, us), (Signed, lower_bound))
|
|
||||||
| ((Unsigned, us), (Unsigned, lower_bound)) => us >= lower_bound,
|
|
||||||
|
|
||||||
// Unsigned ints with the same bit width as their unsigned counterparts can always
|
|
||||||
// express 2x more integers on the positive side as unsigned ints.
|
|
||||||
((Unsigned, us), (Signed, lower_bound)) => us >= lower_bound,
|
|
||||||
|
|
||||||
// ...but that means signed int widths can represent less than their unsigned
|
|
||||||
// counterparts, so the below is true iff the bit width is strictly greater. E.g.
|
|
||||||
// i16 is a superset of u8, but i16 is not a superset of u16.
|
|
||||||
((Signed, us), (Unsigned, lower_bound)) => us > lower_bound,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
|
||||||
pub enum FloatWidth {
|
|
||||||
Dec,
|
|
||||||
F32,
|
|
||||||
F64,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
|
||||||
pub enum SignDemand {
|
|
||||||
/// Can be signed or unsigned.
|
|
||||||
NoDemand,
|
|
||||||
/// Must be signed.
|
|
||||||
Signed,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Describes a bound on the width of an integer.
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
|
||||||
pub enum IntBound {
|
|
||||||
/// There is no bound on the width.
|
|
||||||
None,
|
|
||||||
/// 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,
|
|
||||||
/// Must be an integer of a certain size, or any float.
|
|
||||||
AtLeastIntOrFloat {
|
|
||||||
sign: SignDemand,
|
|
||||||
width: IntWidth,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,8 +2,8 @@ use crate::annotation::freshen_opaque_def;
|
||||||
use crate::env::Env;
|
use crate::env::Env;
|
||||||
use crate::expr::{canonicalize_expr, unescape_char, Expr, IntValue, Output};
|
use crate::expr::{canonicalize_expr, unescape_char, Expr, IntValue, Output};
|
||||||
use crate::num::{
|
use crate::num::{
|
||||||
finish_parsing_base, finish_parsing_float, finish_parsing_num, FloatBound, IntBound,
|
finish_parsing_base, finish_parsing_float, finish_parsing_num, FloatBound, IntBound, NumBound,
|
||||||
NumericBound, ParsedNumResult,
|
ParsedNumResult,
|
||||||
};
|
};
|
||||||
use crate::scope::Scope;
|
use crate::scope::Scope;
|
||||||
use roc_module::ident::{Ident, Lowercase, TagName};
|
use roc_module::ident::{Ident, Lowercase, TagName};
|
||||||
|
@ -55,7 +55,7 @@ pub enum Pattern {
|
||||||
ext_var: Variable,
|
ext_var: Variable,
|
||||||
destructs: Vec<Loc<RecordDestruct>>,
|
destructs: Vec<Loc<RecordDestruct>>,
|
||||||
},
|
},
|
||||||
NumLiteral(Variable, Box<str>, IntValue, NumericBound),
|
NumLiteral(Variable, Box<str>, IntValue, NumBound),
|
||||||
IntLiteral(Variable, Variable, Box<str>, IntValue, IntBound),
|
IntLiteral(Variable, Variable, Box<str>, IntValue, IntBound),
|
||||||
FloatLiteral(Variable, Variable, Box<str>, f64, FloatBound),
|
FloatLiteral(Variable, Variable, Box<str>, f64, FloatBound),
|
||||||
StrLiteral(Box<str>),
|
StrLiteral(Box<str>),
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use arrayvec::ArrayVec;
|
use arrayvec::ArrayVec;
|
||||||
use roc_can::constraint::{Constraint, Constraints};
|
use roc_can::constraint::{Constraint, Constraints};
|
||||||
use roc_can::expected::Expected::{self, *};
|
use roc_can::expected::Expected::{self, *};
|
||||||
use roc_can::num::{FloatBound, FloatWidth, IntBound, IntWidth, NumericBound, SignDemand};
|
use roc_can::num::{FloatBound, FloatWidth, IntBound, IntWidth, NumBound, SignDemand};
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::Symbol;
|
||||||
use roc_region::all::Region;
|
use roc_region::all::Region;
|
||||||
use roc_types::subs::Variable;
|
use roc_types::subs::Variable;
|
||||||
|
@ -117,7 +117,7 @@ pub fn num_literal(
|
||||||
num_var: Variable,
|
num_var: Variable,
|
||||||
expected: Expected<Type>,
|
expected: Expected<Type>,
|
||||||
region: Region,
|
region: Region,
|
||||||
bound: NumericBound,
|
bound: NumBound,
|
||||||
) -> Constraint {
|
) -> Constraint {
|
||||||
let open_number_type = crate::builtins::num_num(Type::Variable(num_var));
|
let open_number_type = crate::builtins::num_num(Type::Variable(num_var));
|
||||||
|
|
||||||
|
@ -338,11 +338,11 @@ impl TypedNumericBound for FloatBound {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypedNumericBound for NumericBound {
|
impl TypedNumericBound for NumBound {
|
||||||
fn bounded_range(&self) -> Vec<Variable> {
|
fn bounded_range(&self) -> Vec<Variable> {
|
||||||
match self {
|
match self {
|
||||||
NumericBound::None => vec![],
|
NumBound::None => vec![],
|
||||||
&NumericBound::AtLeastIntOrFloat { sign, width } => {
|
&NumBound::AtLeastIntOrFloat { sign, width } => {
|
||||||
let mut range = IntBound::AtLeast { sign, width }.bounded_range();
|
let mut range = IntBound::AtLeast { sign, width }.bounded_range();
|
||||||
range.extend_from_slice(&[Variable::F32, Variable::F64, Variable::DEC]);
|
range.extend_from_slice(&[Variable::F32, Variable::F64, Variable::DEC]);
|
||||||
range
|
range
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
// See github.com/rtfeldman/roc/issues/800 for discussion of the large_enum_variant check.
|
// See github.com/rtfeldman/roc/issues/800 for discussion of the large_enum_variant check.
|
||||||
#![allow(clippy::large_enum_variant)]
|
#![allow(clippy::large_enum_variant)]
|
||||||
pub mod builtin_aliases;
|
pub mod builtin_aliases;
|
||||||
|
pub mod num;
|
||||||
pub mod pretty_print;
|
pub mod pretty_print;
|
||||||
pub mod solved_types;
|
pub mod solved_types;
|
||||||
pub mod subs;
|
pub mod subs;
|
||||||
|
|
165
compiler/types/src/num.rs
Normal file
165
compiler/types/src/num.rs
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
|
pub enum IntSign {
|
||||||
|
Unsigned,
|
||||||
|
Signed,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
|
pub enum IntWidth {
|
||||||
|
U8,
|
||||||
|
U16,
|
||||||
|
U32,
|
||||||
|
U64,
|
||||||
|
U128,
|
||||||
|
I8,
|
||||||
|
I16,
|
||||||
|
I32,
|
||||||
|
I64,
|
||||||
|
I128,
|
||||||
|
Nat,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntWidth {
|
||||||
|
/// Returns the `IntSign` and bit width of a variant.
|
||||||
|
pub fn sign_and_width(&self) -> (IntSign, u32) {
|
||||||
|
use IntSign::*;
|
||||||
|
use IntWidth::*;
|
||||||
|
match self {
|
||||||
|
U8 => (Unsigned, 8),
|
||||||
|
U16 => (Unsigned, 16),
|
||||||
|
U32 => (Unsigned, 32),
|
||||||
|
U64 => (Unsigned, 64),
|
||||||
|
U128 => (Unsigned, 128),
|
||||||
|
I8 => (Signed, 8),
|
||||||
|
I16 => (Signed, 16),
|
||||||
|
I32 => (Signed, 32),
|
||||||
|
I64 => (Signed, 64),
|
||||||
|
I128 => (Signed, 128),
|
||||||
|
// TODO: this is platform specific!
|
||||||
|
Nat => (Unsigned, 64),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn type_str(&self) -> &'static str {
|
||||||
|
use IntWidth::*;
|
||||||
|
match self {
|
||||||
|
U8 => "U8",
|
||||||
|
U16 => "U16",
|
||||||
|
U32 => "U32",
|
||||||
|
U64 => "U64",
|
||||||
|
U128 => "U128",
|
||||||
|
I8 => "I8",
|
||||||
|
I16 => "I16",
|
||||||
|
I32 => "I32",
|
||||||
|
I64 => "I64",
|
||||||
|
I128 => "I128",
|
||||||
|
Nat => "Nat",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn max_value(&self) -> u128 {
|
||||||
|
use IntWidth::*;
|
||||||
|
match self {
|
||||||
|
U8 => u8::MAX as u128,
|
||||||
|
U16 => u16::MAX as u128,
|
||||||
|
U32 => u32::MAX as u128,
|
||||||
|
U64 => u64::MAX as u128,
|
||||||
|
U128 => u128::MAX,
|
||||||
|
I8 => i8::MAX as u128,
|
||||||
|
I16 => i16::MAX as u128,
|
||||||
|
I32 => i32::MAX as u128,
|
||||||
|
I64 => i64::MAX as u128,
|
||||||
|
I128 => i128::MAX as u128,
|
||||||
|
// TODO: this is platform specific!
|
||||||
|
Nat => u64::MAX as u128,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn min_value(&self) -> i128 {
|
||||||
|
use IntWidth::*;
|
||||||
|
match self {
|
||||||
|
U8 | U16 | U32 | U64 | U128 | Nat => 0,
|
||||||
|
I8 => i8::MIN as i128,
|
||||||
|
I16 => i16::MIN as i128,
|
||||||
|
I32 => i32::MIN as i128,
|
||||||
|
I64 => i64::MIN as i128,
|
||||||
|
I128 => i128::MIN,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks if `self` represents superset of integers that `lower_bound` represents, on a particular
|
||||||
|
/// side of the integers relative to 0.
|
||||||
|
///
|
||||||
|
/// If `is_negative` is true, the negative side is checked; otherwise the positive side is checked.
|
||||||
|
pub fn is_superset(&self, lower_bound: &Self, is_negative: bool) -> bool {
|
||||||
|
use IntSign::*;
|
||||||
|
|
||||||
|
if is_negative {
|
||||||
|
match (self.sign_and_width(), lower_bound.sign_and_width()) {
|
||||||
|
((Signed, us), (Signed, lower_bound)) => us >= lower_bound,
|
||||||
|
// Unsigned ints can never represent negative numbers; signed (non-zero width)
|
||||||
|
// ints always can.
|
||||||
|
((Unsigned, _), (Signed, _)) => false,
|
||||||
|
((Signed, _), (Unsigned, _)) => true,
|
||||||
|
// Trivially true; both can only express 0.
|
||||||
|
((Unsigned, _), (Unsigned, _)) => true,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match (self.sign_and_width(), lower_bound.sign_and_width()) {
|
||||||
|
((Signed, us), (Signed, lower_bound))
|
||||||
|
| ((Unsigned, us), (Unsigned, lower_bound)) => us >= lower_bound,
|
||||||
|
|
||||||
|
// Unsigned ints with the same bit width as their unsigned counterparts can always
|
||||||
|
// express 2x more integers on the positive side as unsigned ints.
|
||||||
|
((Unsigned, us), (Signed, lower_bound)) => us >= lower_bound,
|
||||||
|
|
||||||
|
// ...but that means signed int widths can represent less than their unsigned
|
||||||
|
// counterparts, so the below is true iff the bit width is strictly greater. E.g.
|
||||||
|
// i16 is a superset of u8, but i16 is not a superset of u16.
|
||||||
|
((Signed, us), (Unsigned, lower_bound)) => us > lower_bound,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
|
pub enum FloatWidth {
|
||||||
|
Dec,
|
||||||
|
F32,
|
||||||
|
F64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
|
pub enum SignDemand {
|
||||||
|
/// Can be signed or unsigned.
|
||||||
|
NoDemand,
|
||||||
|
/// Must be signed.
|
||||||
|
Signed,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Describes a bound on the width of an integer.
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
|
pub enum IntBound {
|
||||||
|
/// There is no bound on the width.
|
||||||
|
None,
|
||||||
|
/// 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 NumBound {
|
||||||
|
None,
|
||||||
|
/// Must be an integer of a certain size, or any float.
|
||||||
|
AtLeastIntOrFloat {
|
||||||
|
sign: SignDemand,
|
||||||
|
width: IntWidth,
|
||||||
|
},
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue