mirror of
https://github.com/roc-lang/roc.git
synced 2024-09-20 23:37:56 +03:00
Support ordering floats in numeric literal bounds
This commit is contained in:
parent
1905e1815d
commit
5a18490050
@ -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, NumBound};
|
use crate::num::{FloatBound, IntBound, IntLitWidth, 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;
|
||||||
@ -1577,7 +1577,7 @@ fn str_to_num(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
|||||||
errorcode_var,
|
errorcode_var,
|
||||||
Variable::UNSIGNED8,
|
Variable::UNSIGNED8,
|
||||||
0,
|
0,
|
||||||
IntBound::Exact(IntWidth::U8),
|
IntBound::Exact(IntLitWidth::U8),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -2175,7 +2175,7 @@ fn list_split(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
|||||||
index_var,
|
index_var,
|
||||||
Variable::NATURAL,
|
Variable::NATURAL,
|
||||||
0,
|
0,
|
||||||
IntBound::Exact(IntWidth::Nat),
|
IntBound::Exact(IntLitWidth::Nat),
|
||||||
);
|
);
|
||||||
|
|
||||||
let clos = Closure(ClosureData {
|
let clos = Closure(ClosureData {
|
||||||
|
@ -5,7 +5,7 @@ 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};
|
pub use roc_types::num::{FloatBound, FloatWidth, IntBound, IntLitWidth, NumBound, SignDemand};
|
||||||
use roc_types::subs::VarStore;
|
use roc_types::subs::VarStore;
|
||||||
|
|
||||||
use std::str;
|
use std::str;
|
||||||
@ -174,7 +174,7 @@ pub fn finish_parsing_float(raw: &str) -> Result<(&str, f64, FloatBound), (&str,
|
|||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
enum ParsedWidth {
|
enum ParsedWidth {
|
||||||
Int(IntWidth),
|
Int(IntLitWidth),
|
||||||
Float(FloatWidth),
|
Float(FloatWidth),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,17 +188,17 @@ fn parse_literal_suffix(num_str: &str) -> (Option<ParsedWidth>, &str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
parse_num_suffix! {
|
parse_num_suffix! {
|
||||||
"u8", ParsedWidth::Int(IntWidth::U8)
|
"u8", ParsedWidth::Int(IntLitWidth::U8)
|
||||||
"u16", ParsedWidth::Int(IntWidth::U16)
|
"u16", ParsedWidth::Int(IntLitWidth::U16)
|
||||||
"u32", ParsedWidth::Int(IntWidth::U32)
|
"u32", ParsedWidth::Int(IntLitWidth::U32)
|
||||||
"u64", ParsedWidth::Int(IntWidth::U64)
|
"u64", ParsedWidth::Int(IntLitWidth::U64)
|
||||||
"u128", ParsedWidth::Int(IntWidth::U128)
|
"u128", ParsedWidth::Int(IntLitWidth::U128)
|
||||||
"i8", ParsedWidth::Int(IntWidth::I8)
|
"i8", ParsedWidth::Int(IntLitWidth::I8)
|
||||||
"i16", ParsedWidth::Int(IntWidth::I16)
|
"i16", ParsedWidth::Int(IntLitWidth::I16)
|
||||||
"i32", ParsedWidth::Int(IntWidth::I32)
|
"i32", ParsedWidth::Int(IntLitWidth::I32)
|
||||||
"i64", ParsedWidth::Int(IntWidth::I64)
|
"i64", ParsedWidth::Int(IntLitWidth::I64)
|
||||||
"i128", ParsedWidth::Int(IntWidth::I128)
|
"i128", ParsedWidth::Int(IntLitWidth::I128)
|
||||||
"nat", ParsedWidth::Int(IntWidth::Nat)
|
"nat", ParsedWidth::Int(IntLitWidth::Nat)
|
||||||
"dec", ParsedWidth::Float(FloatWidth::Dec)
|
"dec", ParsedWidth::Float(FloatWidth::Dec)
|
||||||
"f32", ParsedWidth::Float(FloatWidth::F32)
|
"f32", ParsedWidth::Float(FloatWidth::F32)
|
||||||
"f64", ParsedWidth::Float(FloatWidth::F64)
|
"f64", ParsedWidth::Float(FloatWidth::F64)
|
||||||
@ -256,9 +256,9 @@ fn from_str_radix(src: &str, radix: u32) -> Result<ParsedNumResult, IntErrorKind
|
|||||||
IntValue::I128(bytes) => {
|
IntValue::I128(bytes) => {
|
||||||
let num = i128::from_ne_bytes(bytes);
|
let num = i128::from_ne_bytes(bytes);
|
||||||
|
|
||||||
(lower_bound_of_int(num), num < 0)
|
(lower_bound_of_int_literal(num), num < 0)
|
||||||
}
|
}
|
||||||
IntValue::U128(_) => (IntWidth::U128, false),
|
IntValue::U128(_) => (IntLitWidth::U128, false),
|
||||||
};
|
};
|
||||||
|
|
||||||
match opt_exact_bound {
|
match opt_exact_bound {
|
||||||
@ -314,8 +314,8 @@ fn from_str_radix(src: &str, radix: u32) -> Result<ParsedNumResult, IntErrorKind
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_bound_of_int(result: i128) -> IntWidth {
|
fn lower_bound_of_int_literal(result: i128) -> IntLitWidth {
|
||||||
use IntWidth::*;
|
use IntLitWidth::*;
|
||||||
if result >= 0 {
|
if result >= 0 {
|
||||||
// Positive
|
// Positive
|
||||||
let result = result as u128;
|
let result = result as u128;
|
||||||
@ -323,12 +323,16 @@ fn lower_bound_of_int(result: i128) -> IntWidth {
|
|||||||
I128
|
I128
|
||||||
} else if result > I64.max_value() {
|
} else if result > I64.max_value() {
|
||||||
U64
|
U64
|
||||||
} else if result > U32.max_value() {
|
} else if result > F64.max_value() {
|
||||||
I64
|
I64
|
||||||
|
} else if result > U32.max_value() {
|
||||||
|
F64
|
||||||
} else if result > I32.max_value() {
|
} else if result > I32.max_value() {
|
||||||
U32
|
U32
|
||||||
} else if result > U16.max_value() {
|
} else if result > F32.max_value() {
|
||||||
I32
|
I32
|
||||||
|
} else if result > U16.max_value() {
|
||||||
|
F32
|
||||||
} else if result > I16.max_value() {
|
} else if result > I16.max_value() {
|
||||||
U16
|
U16
|
||||||
} else if result > U8.max_value() {
|
} else if result > U8.max_value() {
|
||||||
@ -342,10 +346,14 @@ fn lower_bound_of_int(result: i128) -> IntWidth {
|
|||||||
// Negative
|
// Negative
|
||||||
if result < I64.min_value() {
|
if result < I64.min_value() {
|
||||||
I128
|
I128
|
||||||
} else if result < I32.min_value() {
|
} else if result < F64.min_value() {
|
||||||
I64
|
I64
|
||||||
} else if result < I16.min_value() {
|
} else if result < I32.min_value() {
|
||||||
|
F64
|
||||||
|
} else if result < F32.min_value() {
|
||||||
I32
|
I32
|
||||||
|
} else if result < I16.min_value() {
|
||||||
|
F32
|
||||||
} else if result < I8.min_value() {
|
} else if result < I8.min_value() {
|
||||||
I16
|
I16
|
||||||
} else {
|
} else {
|
||||||
|
@ -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, NumBound, SignDemand};
|
use roc_can::num::{FloatBound, FloatWidth, IntBound, IntLitWidth, 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::num::NumericRange;
|
use roc_types::num::NumericRange;
|
||||||
@ -23,7 +23,7 @@ pub fn add_numeric_bound_constr(
|
|||||||
let range = bound.numeric_bound();
|
let range = bound.numeric_bound();
|
||||||
let total_num_type = num_type;
|
let total_num_type = num_type;
|
||||||
|
|
||||||
use roc_types::num::{float_width_to_variable, int_width_to_variable};
|
use roc_types::num::{float_width_to_variable, int_lit_width_to_variable};
|
||||||
|
|
||||||
match range {
|
match range {
|
||||||
NumericBound::None => {
|
NumericBound::None => {
|
||||||
@ -41,7 +41,7 @@ pub fn add_numeric_bound_constr(
|
|||||||
total_num_type
|
total_num_type
|
||||||
}
|
}
|
||||||
NumericBound::IntExact(width) => {
|
NumericBound::IntExact(width) => {
|
||||||
let actual_type = Variable(int_width_to_variable(width));
|
let actual_type = Variable(int_lit_width_to_variable(width));
|
||||||
let expected = Expected::ForReason(Reason::NumericLiteralSuffix, actual_type, region);
|
let expected = Expected::ForReason(Reason::NumericLiteralSuffix, actual_type, region);
|
||||||
let because_suffix =
|
let because_suffix =
|
||||||
constraints.equal_types(total_num_type.clone(), expected, category, region);
|
constraints.equal_types(total_num_type.clone(), expected, category, region);
|
||||||
@ -330,6 +330,6 @@ impl TypedNumericBound for NumBound {
|
|||||||
pub enum NumericBound {
|
pub enum NumericBound {
|
||||||
None,
|
None,
|
||||||
FloatExact(FloatWidth),
|
FloatExact(FloatWidth),
|
||||||
IntExact(IntWidth),
|
IntExact(IntLitWidth),
|
||||||
Range(NumericRange),
|
Range(NumericRange),
|
||||||
}
|
}
|
||||||
|
@ -5,26 +5,26 @@ use roc_module::symbol::Symbol;
|
|||||||
/// e.g. `-5` cannot be unsigned, and 300 does not fit in a U8
|
/// e.g. `-5` cannot be unsigned, and 300 does not fit in a U8
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum NumericRange {
|
pub enum NumericRange {
|
||||||
IntAtLeastSigned(IntWidth),
|
IntAtLeastSigned(IntLitWidth),
|
||||||
IntAtLeastEitherSign(IntWidth),
|
IntAtLeastEitherSign(IntLitWidth),
|
||||||
NumAtLeastSigned(IntWidth),
|
NumAtLeastSigned(IntLitWidth),
|
||||||
NumAtLeastEitherSign(IntWidth),
|
NumAtLeastEitherSign(IntLitWidth),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NumericRange {
|
impl NumericRange {
|
||||||
pub fn contains_symbol(&self, symbol: Symbol) -> Option<bool> {
|
pub fn contains_symbol(&self, symbol: Symbol) -> Option<bool> {
|
||||||
let contains = match symbol {
|
let contains = match symbol {
|
||||||
Symbol::NUM_I8 => self.contains_int_width(IntWidth::I8),
|
Symbol::NUM_I8 => self.contains_int_width(IntLitWidth::I8),
|
||||||
Symbol::NUM_U8 => self.contains_int_width(IntWidth::U8),
|
Symbol::NUM_U8 => self.contains_int_width(IntLitWidth::U8),
|
||||||
Symbol::NUM_I16 => self.contains_int_width(IntWidth::I16),
|
Symbol::NUM_I16 => self.contains_int_width(IntLitWidth::I16),
|
||||||
Symbol::NUM_U16 => self.contains_int_width(IntWidth::U16),
|
Symbol::NUM_U16 => self.contains_int_width(IntLitWidth::U16),
|
||||||
Symbol::NUM_I32 => self.contains_int_width(IntWidth::I32),
|
Symbol::NUM_I32 => self.contains_int_width(IntLitWidth::I32),
|
||||||
Symbol::NUM_U32 => self.contains_int_width(IntWidth::U32),
|
Symbol::NUM_U32 => self.contains_int_width(IntLitWidth::U32),
|
||||||
Symbol::NUM_I64 => self.contains_int_width(IntWidth::I64),
|
Symbol::NUM_I64 => self.contains_int_width(IntLitWidth::I64),
|
||||||
Symbol::NUM_NAT => self.contains_int_width(IntWidth::Nat),
|
Symbol::NUM_NAT => self.contains_int_width(IntLitWidth::Nat),
|
||||||
Symbol::NUM_U64 => self.contains_int_width(IntWidth::U64),
|
Symbol::NUM_U64 => self.contains_int_width(IntLitWidth::U64),
|
||||||
Symbol::NUM_I128 => self.contains_int_width(IntWidth::I128),
|
Symbol::NUM_I128 => self.contains_int_width(IntLitWidth::I128),
|
||||||
Symbol::NUM_U128 => self.contains_int_width(IntWidth::U128),
|
Symbol::NUM_U128 => self.contains_int_width(IntLitWidth::U128),
|
||||||
|
|
||||||
Symbol::NUM_DEC => self.contains_float_width(FloatWidth::Dec),
|
Symbol::NUM_DEC => self.contains_float_width(FloatWidth::Dec),
|
||||||
Symbol::NUM_F32 => self.contains_float_width(FloatWidth::F32),
|
Symbol::NUM_F32 => self.contains_float_width(FloatWidth::F32),
|
||||||
@ -48,7 +48,7 @@ impl NumericRange {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn contains_int_width(&self, width: IntWidth) -> bool {
|
fn contains_int_width(&self, width: IntLitWidth) -> bool {
|
||||||
use NumericRange::*;
|
use NumericRange::*;
|
||||||
|
|
||||||
let (range_signedness, at_least_width) = match self {
|
let (range_signedness, at_least_width) = match self {
|
||||||
@ -68,7 +68,7 @@ impl NumericRange {
|
|||||||
width.signedness_and_width().1 >= at_least_width.signedness_and_width().1
|
width.signedness_and_width().1 >= at_least_width.signedness_and_width().1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn width(&self) -> IntWidth {
|
fn width(&self) -> IntLitWidth {
|
||||||
use NumericRange::*;
|
use NumericRange::*;
|
||||||
match self {
|
match self {
|
||||||
IntAtLeastSigned(w)
|
IntAtLeastSigned(w)
|
||||||
@ -83,7 +83,7 @@ impl NumericRange {
|
|||||||
pub fn intersection(&self, other: &Self) -> Option<Self> {
|
pub fn intersection(&self, other: &Self) -> Option<Self> {
|
||||||
use NumericRange::*;
|
use NumericRange::*;
|
||||||
let (left, right) = (self.width(), other.width());
|
let (left, right) = (self.width(), other.width());
|
||||||
let constructor: fn(IntWidth) -> NumericRange = match (self, other) {
|
let constructor: fn(IntLitWidth) -> NumericRange = match (self, other) {
|
||||||
// Matching against a signed int, the intersection must also be a signed int
|
// Matching against a signed int, the intersection must also be a signed int
|
||||||
(IntAtLeastSigned(_), _) | (_, IntAtLeastSigned(_)) => IntAtLeastSigned,
|
(IntAtLeastSigned(_), _) | (_, IntAtLeastSigned(_)) => IntAtLeastSigned,
|
||||||
// It's a signed number, but also an int, so the intersection must be a signed int
|
// It's a signed number, but also an int, so the intersection must be a signed int
|
||||||
@ -114,27 +114,27 @@ impl NumericRange {
|
|||||||
|
|
||||||
match self {
|
match self {
|
||||||
IntAtLeastSigned(width) => {
|
IntAtLeastSigned(width) => {
|
||||||
let target = int_width_to_variable(*width);
|
let target = int_lit_width_to_variable(*width);
|
||||||
let start = SIGNED_VARIABLES.iter().position(|v| *v == target).unwrap();
|
let start = SIGNED_VARIABLES.iter().position(|v| *v == target).unwrap();
|
||||||
let end = SIGNED_VARIABLES.len() - 3;
|
let end = SIGNED_VARIABLES.len() - 3;
|
||||||
|
|
||||||
&SIGNED_VARIABLES[start..end]
|
&SIGNED_VARIABLES[start..end]
|
||||||
}
|
}
|
||||||
IntAtLeastEitherSign(width) => {
|
IntAtLeastEitherSign(width) => {
|
||||||
let target = int_width_to_variable(*width);
|
let target = int_lit_width_to_variable(*width);
|
||||||
let start = ALL_VARIABLES.iter().position(|v| *v == target).unwrap();
|
let start = ALL_VARIABLES.iter().position(|v| *v == target).unwrap();
|
||||||
let end = ALL_VARIABLES.len() - 3;
|
let end = ALL_VARIABLES.len() - 3;
|
||||||
|
|
||||||
&ALL_VARIABLES[start..end]
|
&ALL_VARIABLES[start..end]
|
||||||
}
|
}
|
||||||
NumAtLeastSigned(width) => {
|
NumAtLeastSigned(width) => {
|
||||||
let target = int_width_to_variable(*width);
|
let target = int_lit_width_to_variable(*width);
|
||||||
let start = SIGNED_VARIABLES.iter().position(|v| *v == target).unwrap();
|
let start = SIGNED_VARIABLES.iter().position(|v| *v == target).unwrap();
|
||||||
|
|
||||||
&SIGNED_VARIABLES[start..]
|
&SIGNED_VARIABLES[start..]
|
||||||
}
|
}
|
||||||
NumAtLeastEitherSign(width) => {
|
NumAtLeastEitherSign(width) => {
|
||||||
let target = int_width_to_variable(*width);
|
let target = int_lit_width_to_variable(*width);
|
||||||
let start = ALL_VARIABLES.iter().position(|v| *v == target).unwrap();
|
let start = ALL_VARIABLES.iter().position(|v| *v == target).unwrap();
|
||||||
|
|
||||||
&ALL_VARIABLES[start..]
|
&ALL_VARIABLES[start..]
|
||||||
@ -150,7 +150,7 @@ enum IntSignedness {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
pub enum IntWidth {
|
pub enum IntLitWidth {
|
||||||
U8,
|
U8,
|
||||||
U16,
|
U16,
|
||||||
U32,
|
U32,
|
||||||
@ -162,13 +162,21 @@ pub enum IntWidth {
|
|||||||
I64,
|
I64,
|
||||||
I128,
|
I128,
|
||||||
Nat,
|
Nat,
|
||||||
|
// An int literal can be promoted to an f32/f64/Dec if appropriate. The respective widths for
|
||||||
|
// integers that can be stored in these float types without losing precision are:
|
||||||
|
// f32: +/- 2^24
|
||||||
|
// f64: +/- 2^53
|
||||||
|
// dec: Int128::MAX/Int128::MIN
|
||||||
|
F32,
|
||||||
|
F64,
|
||||||
|
Dec,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntWidth {
|
impl IntLitWidth {
|
||||||
/// Returns the `IntSignedness` and bit width of a variant.
|
/// Returns the `IntSignedness` and bit width of a variant.
|
||||||
fn signedness_and_width(&self) -> (IntSignedness, u32) {
|
fn signedness_and_width(&self) -> (IntSignedness, u32) {
|
||||||
|
use IntLitWidth::*;
|
||||||
use IntSignedness::*;
|
use IntSignedness::*;
|
||||||
use IntWidth::*;
|
|
||||||
match self {
|
match self {
|
||||||
U8 => (Unsigned, 8),
|
U8 => (Unsigned, 8),
|
||||||
U16 => (Unsigned, 16),
|
U16 => (Unsigned, 16),
|
||||||
@ -180,13 +188,16 @@ impl IntWidth {
|
|||||||
I32 => (Signed, 32),
|
I32 => (Signed, 32),
|
||||||
I64 => (Signed, 64),
|
I64 => (Signed, 64),
|
||||||
I128 => (Signed, 128),
|
I128 => (Signed, 128),
|
||||||
// TODO: this is platform specific!
|
// TODO: Nat is platform specific!
|
||||||
Nat => (Unsigned, 64),
|
Nat => (Unsigned, 64),
|
||||||
|
F32 => (Signed, 24),
|
||||||
|
F64 => (Signed, 53),
|
||||||
|
Dec => (Signed, 128),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_str(&self) -> &'static str {
|
pub fn type_str(&self) -> &'static str {
|
||||||
use IntWidth::*;
|
use IntLitWidth::*;
|
||||||
match self {
|
match self {
|
||||||
U8 => "U8",
|
U8 => "U8",
|
||||||
U16 => "U16",
|
U16 => "U16",
|
||||||
@ -199,11 +210,14 @@ impl IntWidth {
|
|||||||
I64 => "I64",
|
I64 => "I64",
|
||||||
I128 => "I128",
|
I128 => "I128",
|
||||||
Nat => "Nat",
|
Nat => "Nat",
|
||||||
|
F32 => "F32",
|
||||||
|
F64 => "F64",
|
||||||
|
Dec => "Dec",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn max_value(&self) -> u128 {
|
pub fn max_value(&self) -> u128 {
|
||||||
use IntWidth::*;
|
use IntLitWidth::*;
|
||||||
match self {
|
match self {
|
||||||
U8 => u8::MAX as u128,
|
U8 => u8::MAX as u128,
|
||||||
U16 => u16::MAX as u128,
|
U16 => u16::MAX as u128,
|
||||||
@ -217,11 +231,17 @@ impl IntWidth {
|
|||||||
I128 => i128::MAX as u128,
|
I128 => i128::MAX as u128,
|
||||||
// TODO: this is platform specific!
|
// TODO: this is platform specific!
|
||||||
Nat => u64::MAX as u128,
|
Nat => u64::MAX as u128,
|
||||||
|
// Max int value without losing precision: 2^24
|
||||||
|
F32 => 16_777_216,
|
||||||
|
// Max int value without losing precision: 2^53
|
||||||
|
F64 => 9_007_199_254_740_992,
|
||||||
|
// Max int value without losing precision: I128::MAX
|
||||||
|
Dec => i128::MAX as u128,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn min_value(&self) -> i128 {
|
pub fn min_value(&self) -> i128 {
|
||||||
use IntWidth::*;
|
use IntLitWidth::*;
|
||||||
match self {
|
match self {
|
||||||
U8 | U16 | U32 | U64 | U128 | Nat => 0,
|
U8 | U16 | U32 | U64 | U128 | Nat => 0,
|
||||||
I8 => i8::MIN as i128,
|
I8 => i8::MIN as i128,
|
||||||
@ -229,6 +249,12 @@ impl IntWidth {
|
|||||||
I32 => i32::MIN as i128,
|
I32 => i32::MIN as i128,
|
||||||
I64 => i64::MIN as i128,
|
I64 => i64::MIN as i128,
|
||||||
I128 => i128::MIN,
|
I128 => i128::MIN,
|
||||||
|
// Min int value without losing precision: -2^24
|
||||||
|
F32 => -16_777_216,
|
||||||
|
// Min int value without losing precision: -2^53
|
||||||
|
F64 => -9_007_199_254_740_992,
|
||||||
|
// Min int value without losing precision: I128::MIN
|
||||||
|
Dec => i128::MIN,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -294,9 +320,12 @@ pub enum IntBound {
|
|||||||
/// There is no bound on the width.
|
/// There is no bound on the width.
|
||||||
None,
|
None,
|
||||||
/// Must have an exact width.
|
/// Must have an exact width.
|
||||||
Exact(IntWidth),
|
Exact(IntLitWidth),
|
||||||
/// Must have a certain sign and a minimum width.
|
/// Must have a certain sign and a minimum width.
|
||||||
AtLeast { sign: SignDemand, width: IntWidth },
|
AtLeast {
|
||||||
|
sign: SignDemand,
|
||||||
|
width: IntLitWidth,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
@ -311,23 +340,26 @@ pub enum NumBound {
|
|||||||
/// Must be an integer of a certain size, or any float.
|
/// Must be an integer of a certain size, or any float.
|
||||||
AtLeastIntOrFloat {
|
AtLeastIntOrFloat {
|
||||||
sign: SignDemand,
|
sign: SignDemand,
|
||||||
width: IntWidth,
|
width: IntLitWidth,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn int_width_to_variable(w: IntWidth) -> Variable {
|
pub const fn int_lit_width_to_variable(w: IntLitWidth) -> Variable {
|
||||||
match w {
|
match w {
|
||||||
IntWidth::U8 => Variable::U8,
|
IntLitWidth::U8 => Variable::U8,
|
||||||
IntWidth::U16 => Variable::U16,
|
IntLitWidth::U16 => Variable::U16,
|
||||||
IntWidth::U32 => Variable::U32,
|
IntLitWidth::U32 => Variable::U32,
|
||||||
IntWidth::U64 => Variable::U64,
|
IntLitWidth::U64 => Variable::U64,
|
||||||
IntWidth::U128 => Variable::U128,
|
IntLitWidth::U128 => Variable::U128,
|
||||||
IntWidth::I8 => Variable::I8,
|
IntLitWidth::I8 => Variable::I8,
|
||||||
IntWidth::I16 => Variable::I16,
|
IntLitWidth::I16 => Variable::I16,
|
||||||
IntWidth::I32 => Variable::I32,
|
IntLitWidth::I32 => Variable::I32,
|
||||||
IntWidth::I64 => Variable::I64,
|
IntLitWidth::I64 => Variable::I64,
|
||||||
IntWidth::I128 => Variable::I128,
|
IntLitWidth::I128 => Variable::I128,
|
||||||
IntWidth::Nat => Variable::NAT,
|
IntLitWidth::Nat => Variable::NAT,
|
||||||
|
IntLitWidth::F32 => Variable::F32,
|
||||||
|
IntLitWidth::F64 => Variable::F64,
|
||||||
|
IntLitWidth::Dec => Variable::DEC,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -344,25 +376,25 @@ const ALL_VARIABLES: &[Variable] = &[
|
|||||||
Variable::U8,
|
Variable::U8,
|
||||||
Variable::I16,
|
Variable::I16,
|
||||||
Variable::U16,
|
Variable::U16,
|
||||||
|
Variable::F32,
|
||||||
Variable::I32,
|
Variable::I32,
|
||||||
Variable::U32,
|
Variable::U32,
|
||||||
|
Variable::F64,
|
||||||
Variable::I64,
|
Variable::I64,
|
||||||
Variable::NAT, // FIXME: Nat's order here depends on the platfor,
|
Variable::NAT, // FIXME: Nat's order here depends on the platform
|
||||||
Variable::U64,
|
Variable::U64,
|
||||||
Variable::I128,
|
Variable::I128,
|
||||||
Variable::U128,
|
|
||||||
Variable::F32,
|
|
||||||
Variable::F64,
|
|
||||||
Variable::DEC,
|
Variable::DEC,
|
||||||
|
Variable::U128,
|
||||||
];
|
];
|
||||||
|
|
||||||
const SIGNED_VARIABLES: &[Variable] = &[
|
const SIGNED_VARIABLES: &[Variable] = &[
|
||||||
Variable::I8,
|
Variable::I8,
|
||||||
Variable::I16,
|
Variable::I16,
|
||||||
|
Variable::F32,
|
||||||
Variable::I32,
|
Variable::I32,
|
||||||
|
Variable::F64,
|
||||||
Variable::I64,
|
Variable::I64,
|
||||||
Variable::I128,
|
Variable::I128,
|
||||||
Variable::F32,
|
|
||||||
Variable::F64,
|
|
||||||
Variable::DEC,
|
Variable::DEC,
|
||||||
];
|
];
|
||||||
|
@ -7197,7 +7197,7 @@ All branches in an `if` must have the same type!
|
|||||||
|
|
||||||
This argument is a number of type:
|
This argument is a number of type:
|
||||||
|
|
||||||
I8, I16, I32, I64, I128, F32, F64, or Dec
|
I8, I16, F32, I32, F64, I64, I128, or Dec
|
||||||
|
|
||||||
But `get` needs the 2nd argument to be:
|
But `get` needs the 2nd argument to be:
|
||||||
|
|
||||||
@ -7223,7 +7223,7 @@ All branches in an `if` must have the same type!
|
|||||||
|
|
||||||
This `a` value is a:
|
This `a` value is a:
|
||||||
|
|
||||||
I64, I128, F32, F64, or Dec
|
F64, I64, I128, or Dec
|
||||||
|
|
||||||
But `get` needs the 2nd argument to be:
|
But `get` needs the 2nd argument to be:
|
||||||
|
|
||||||
@ -7250,7 +7250,7 @@ All branches in an `if` must have the same type!
|
|||||||
|
|
||||||
This `b` value is a:
|
This `b` value is a:
|
||||||
|
|
||||||
I64, I128, F32, F64, or Dec
|
F64, I64, I128, or Dec
|
||||||
|
|
||||||
But `get` needs the 2nd argument to be:
|
But `get` needs the 2nd argument to be:
|
||||||
|
|
||||||
@ -7278,7 +7278,7 @@ All branches in an `if` must have the same type!
|
|||||||
|
|
||||||
The `when` condition is a number of type:
|
The `when` condition is a number of type:
|
||||||
|
|
||||||
I8, I16, I32, I64, I128, F32, F64, or Dec
|
I8, I16, F32, I32, F64, I64, I128, or Dec
|
||||||
|
|
||||||
But the branch patterns have type:
|
But the branch patterns have type:
|
||||||
|
|
||||||
@ -9461,4 +9461,29 @@ All branches in an `if` must have the same type!
|
|||||||
U128
|
U128
|
||||||
"###
|
"###
|
||||||
);
|
);
|
||||||
|
|
||||||
|
test_report!(
|
||||||
|
num_literals_cannot_fit_in_same_type,
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
170141183460469231731687303715884105728 == -170141183460469231731687303715884105728
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
@r###"
|
||||||
|
── TYPE MISMATCH ───────────────────────────────────────── /code/proj/Main.roc ─
|
||||||
|
|
||||||
|
The 2nd argument to `isEq` is not what I expect:
|
||||||
|
|
||||||
|
4│ 170141183460469231731687303715884105728 == -170141183460469231731687303715884105728
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
This argument is a number of type:
|
||||||
|
|
||||||
|
I128 or Dec
|
||||||
|
|
||||||
|
But `isEq` needs the 2nd argument to be:
|
||||||
|
|
||||||
|
U128
|
||||||
|
"###
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user