mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-30 15:21:12 +00:00
Include floats in bounds for unspecified numbers
This commit is contained in:
parent
3fffca48bb
commit
c5d918e68c
8 changed files with 129 additions and 180 deletions
|
@ -76,7 +76,7 @@ pub fn expr_to_expr2<'a>(
|
||||||
}
|
}
|
||||||
Num(string) => {
|
Num(string) => {
|
||||||
match finish_parsing_num(string) {
|
match finish_parsing_num(string) {
|
||||||
Ok(ParsedNumResult::UnknownNum(int) | ParsedNumResult::Int(int, _)) => {
|
Ok(ParsedNumResult::UnknownNum(int, _) | ParsedNumResult::Int(int, _)) => {
|
||||||
let expr = Expr2::SmallInt {
|
let expr = Expr2::SmallInt {
|
||||||
number: IntVal::I64(match int {
|
number: IntVal::I64(match int {
|
||||||
IntValue::U128(_) => todo!(),
|
IntValue::U128(_) => todo!(),
|
||||||
|
|
|
@ -196,7 +196,7 @@ pub fn to_pattern2<'a>(
|
||||||
let problem = MalformedPatternProblem::MalformedInt;
|
let problem = MalformedPatternProblem::MalformedInt;
|
||||||
malformed_pattern(env, problem, region)
|
malformed_pattern(env, problem, region)
|
||||||
}
|
}
|
||||||
Ok(ParsedNumResult::UnknownNum(int)) => {
|
Ok(ParsedNumResult::UnknownNum(int, _bound)) => {
|
||||||
Pattern2::NumLiteral(
|
Pattern2::NumLiteral(
|
||||||
env.var_store.fresh(),
|
env.var_store.fresh(),
|
||||||
match int {
|
match int {
|
||||||
|
|
|
@ -17,8 +17,8 @@ pub fn num_expr_from_result(
|
||||||
env: &mut Env,
|
env: &mut Env,
|
||||||
) -> Expr {
|
) -> Expr {
|
||||||
match result {
|
match result {
|
||||||
Ok((str, ParsedNumResult::UnknownNum(num))) => {
|
Ok((str, ParsedNumResult::UnknownNum(num, bound))) => {
|
||||||
Expr::Num(var_store.fresh(), (*str).into(), num, NumericBound::None)
|
Expr::Num(var_store.fresh(), (*str).into(), num, bound)
|
||||||
}
|
}
|
||||||
Ok((str, ParsedNumResult::Int(num, bound))) => Expr::Int(
|
Ok((str, ParsedNumResult::Int(num, bound))) => Expr::Int(
|
||||||
var_store.fresh(),
|
var_store.fresh(),
|
||||||
|
@ -103,27 +103,14 @@ 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),
|
UnknownNum(IntValue, NumericBound),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn finish_parsing_num(raw: &str) -> Result<ParsedNumResult, (&str, IntErrorKind)> {
|
pub fn finish_parsing_num(raw: &str) -> Result<ParsedNumResult, (&str, IntErrorKind)> {
|
||||||
// Ignore underscores.
|
// Ignore underscores.
|
||||||
let radix = 10;
|
let radix = 10;
|
||||||
let (num, bound) =
|
from_str_radix(raw.replace("_", "").as_str(), radix).map_err(|e| (raw, e))
|
||||||
from_str_radix(raw.replace("_", "").as_str(), radix).map_err(|e| (raw, e))?;
|
|
||||||
// Let's try to specialize the number
|
|
||||||
Ok(match bound {
|
|
||||||
NumericBound::None => ParsedNumResult::UnknownNum(num),
|
|
||||||
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, fb)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -145,13 +132,13 @@ pub fn finish_parsing_base(
|
||||||
} else {
|
} else {
|
||||||
from_str_radix(raw.replace("_", "").as_str(), radix)
|
from_str_radix(raw.replace("_", "").as_str(), radix)
|
||||||
})
|
})
|
||||||
.and_then(|(n, bound)| {
|
.and_then(|parsed| match parsed {
|
||||||
let bound = match bound {
|
ParsedNumResult::Float(..) => return Err(IntErrorKind::FloatSuffix),
|
||||||
NumericBound::None => IntBound::None,
|
ParsedNumResult::Int(val, bound) => Ok((val, bound)),
|
||||||
NumericBound::Int(ib) => ib,
|
ParsedNumResult::UnknownNum(val, NumericBound::None) => Ok((val, IntBound::None)),
|
||||||
NumericBound::Float(_) => return Err(IntErrorKind::FloatSuffix),
|
ParsedNumResult::UnknownNum(val, NumericBound::AtLeastIntOrFloat { sign, width }) => {
|
||||||
};
|
Ok((val, IntBound::AtLeast { sign, width }))
|
||||||
Ok((n, bound))
|
}
|
||||||
})
|
})
|
||||||
.map_err(|e| (raw, e))
|
.map_err(|e| (raw, e))
|
||||||
}
|
}
|
||||||
|
@ -223,7 +210,7 @@ fn parse_literal_suffix(num_str: &str) -> (Option<ParsedWidth>, &str) {
|
||||||
/// the LEGAL_DETAILS file in the root directory of this distribution.
|
/// the LEGAL_DETAILS file in the root directory of this distribution.
|
||||||
///
|
///
|
||||||
/// Thanks to the Rust project and its contributors!
|
/// Thanks to the Rust project and its contributors!
|
||||||
fn from_str_radix(src: &str, radix: u32) -> Result<(IntValue, NumericBound), IntErrorKind> {
|
fn from_str_radix(src: &str, radix: u32) -> Result<ParsedNumResult, IntErrorKind> {
|
||||||
use self::IntErrorKind::*;
|
use self::IntErrorKind::*;
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
|
@ -273,25 +260,30 @@ fn from_str_radix(src: &str, radix: u32) -> Result<(IntValue, NumericBound), Int
|
||||||
} else {
|
} else {
|
||||||
SignDemand::NoDemand
|
SignDemand::NoDemand
|
||||||
};
|
};
|
||||||
Ok((
|
Ok(ParsedNumResult::UnknownNum(
|
||||||
result,
|
result,
|
||||||
IntBound::AtLeast {
|
NumericBound::AtLeastIntOrFloat {
|
||||||
sign: sign_demand,
|
sign: sign_demand,
|
||||||
width: lower_bound,
|
width: lower_bound,
|
||||||
}
|
},
|
||||||
.into(),
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
Some(ParsedWidth::Float(fw)) => {
|
Some(ParsedWidth::Float(fw)) => {
|
||||||
// For now, assume floats can represent all integers
|
// For now, assume floats can represent all integers
|
||||||
// TODO: this is somewhat incorrect, revisit
|
// TODO: this is somewhat incorrect, revisit
|
||||||
Ok((result, FloatBound::Exact(fw).into()))
|
Ok(ParsedNumResult::Float(
|
||||||
|
match result {
|
||||||
|
IntValue::I128(n) => n as f64,
|
||||||
|
IntValue::U128(n) => n as f64,
|
||||||
|
},
|
||||||
|
FloatBound::Exact(fw),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
Some(ParsedWidth::Int(exact_width)) => {
|
Some(ParsedWidth::Int(exact_width)) => {
|
||||||
// We need to check if the exact bound >= lower bound.
|
// We need to check if the exact bound >= lower bound.
|
||||||
if exact_width.is_superset(&lower_bound, is_negative) {
|
if exact_width.is_superset(&lower_bound, is_negative) {
|
||||||
// Great! Use the exact bound.
|
// Great! Use the exact bound.
|
||||||
Ok((result, IntBound::Exact(exact_width).into()))
|
Ok(ParsedNumResult::Int(result, IntBound::Exact(exact_width)))
|
||||||
} else {
|
} else {
|
||||||
// This is something like 200i8; the lower bound is u8, which holds strictly more
|
// 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
|
// ints on the positive side than i8 does. Report an error depending on which side
|
||||||
|
@ -512,20 +504,9 @@ pub enum FloatBound {
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
pub enum NumericBound {
|
pub enum NumericBound {
|
||||||
None,
|
None,
|
||||||
Int(IntBound),
|
/// Must be an integer of a certain size, or any float.
|
||||||
Float(FloatBound),
|
AtLeastIntOrFloat {
|
||||||
}
|
sign: SignDemand,
|
||||||
|
width: IntWidth,
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -216,8 +216,8 @@ pub fn canonicalize_pattern<'a>(
|
||||||
let problem = MalformedPatternProblem::MalformedInt;
|
let problem = MalformedPatternProblem::MalformedInt;
|
||||||
malformed_pattern(env, problem, region)
|
malformed_pattern(env, problem, region)
|
||||||
}
|
}
|
||||||
Ok(ParsedNumResult::UnknownNum(int)) => {
|
Ok(ParsedNumResult::UnknownNum(int, bound)) => {
|
||||||
Pattern::NumLiteral(var_store.fresh(), (str).into(), int, NumericBound::None)
|
Pattern::NumLiteral(var_store.fresh(), (str).into(), int, bound)
|
||||||
}
|
}
|
||||||
Ok(ParsedNumResult::Int(int, bound)) => Pattern::IntLiteral(
|
Ok(ParsedNumResult::Int(int, bound)) => Pattern::IntLiteral(
|
||||||
var_store.fresh(),
|
var_store.fresh(),
|
||||||
|
|
|
@ -324,8 +324,11 @@ impl TypedNumericBound for NumericBound {
|
||||||
fn bounded_range(&self) -> Vec<Variable> {
|
fn bounded_range(&self) -> Vec<Variable> {
|
||||||
match self {
|
match self {
|
||||||
NumericBound::None => vec![],
|
NumericBound::None => vec![],
|
||||||
NumericBound::Int(ib) => ib.bounded_range(),
|
&NumericBound::AtLeastIntOrFloat { sign, width } => {
|
||||||
NumericBound::Float(fb) => fb.bounded_range(),
|
let mut range = IntBound::AtLeast { sign, width }.bounded_range();
|
||||||
|
range.extend_from_slice(&[Variable::F32, Variable::F64, Variable::DEC]);
|
||||||
|
range
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -164,7 +164,7 @@ mod solve_expr {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn int_literal() {
|
fn int_literal() {
|
||||||
infer_eq("5", "Int *");
|
infer_eq("5", "Num *");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -334,7 +334,7 @@ mod solve_expr {
|
||||||
[42]
|
[42]
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
"List (Int *)",
|
"List (Num *)",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -346,7 +346,7 @@ mod solve_expr {
|
||||||
[[[ 5 ]]]
|
[[[ 5 ]]]
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
"List (List (List (Int *)))",
|
"List (List (List (Num *)))",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -358,7 +358,7 @@ mod solve_expr {
|
||||||
[ 1, 2, 3 ]
|
[ 1, 2, 3 ]
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
"List (Int *)",
|
"List (Num *)",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -370,7 +370,7 @@ mod solve_expr {
|
||||||
[ [ 1 ], [ 2, 3 ] ]
|
[ [ 1 ], [ 2, 3 ] ]
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
"List (List (Int *))",
|
"List (List (Num *))",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -518,7 +518,7 @@ mod solve_expr {
|
||||||
\_, _ -> 42
|
\_, _ -> 42
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
"*, * -> Int *",
|
"*, * -> Num *",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -689,7 +689,7 @@ mod solve_expr {
|
||||||
func
|
func
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
"*, * -> Int *",
|
"*, * -> Num *",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -753,7 +753,7 @@ mod solve_expr {
|
||||||
c
|
c
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
"Int *",
|
"Num *",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -788,7 +788,7 @@ mod solve_expr {
|
||||||
alwaysFive "stuff"
|
alwaysFive "stuff"
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
"Int *",
|
"Num *",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -835,7 +835,7 @@ mod solve_expr {
|
||||||
x
|
x
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
"Int *",
|
"Num *",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -849,7 +849,7 @@ mod solve_expr {
|
||||||
enlist 5
|
enlist 5
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
"List (Int *)",
|
"List (Num *)",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -876,7 +876,7 @@ mod solve_expr {
|
||||||
1 |> (\a -> a)
|
1 |> (\a -> a)
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
"Int *",
|
"Num *",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -890,7 +890,7 @@ mod solve_expr {
|
||||||
1 |> always2 "foo"
|
1 |> always2 "foo"
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
"Int *",
|
"Num *",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -955,7 +955,7 @@ mod solve_expr {
|
||||||
apply identity 5
|
apply identity 5
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
"Int *",
|
"Num *",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -984,7 +984,7 @@ mod solve_expr {
|
||||||
// flip neverendingInt
|
// flip neverendingInt
|
||||||
// "#
|
// "#
|
||||||
// ),
|
// ),
|
||||||
// "(Int *, (a -> a)) -> Int *",
|
// "(Num *, (a -> a)) -> Num *",
|
||||||
// );
|
// );
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
@ -1058,7 +1058,7 @@ mod solve_expr {
|
||||||
// 1 // 2
|
// 1 // 2
|
||||||
// "#
|
// "#
|
||||||
// ),
|
// ),
|
||||||
// "Int *",
|
// "Num *",
|
||||||
// );
|
// );
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
@ -1070,7 +1070,7 @@ mod solve_expr {
|
||||||
// 1 + 2
|
// 1 + 2
|
||||||
// "#
|
// "#
|
||||||
// ),
|
// ),
|
||||||
// "Int *",
|
// "Num *",
|
||||||
// );
|
// );
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
@ -1119,7 +1119,7 @@ mod solve_expr {
|
||||||
[ alwaysFive "foo", alwaysFive [] ]
|
[ alwaysFive "foo", alwaysFive [] ]
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
"List (Int *)",
|
"List (Num *)",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1134,7 +1134,7 @@ mod solve_expr {
|
||||||
24
|
24
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
"Int *",
|
"Num *",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1148,7 +1148,7 @@ mod solve_expr {
|
||||||
3 -> 4
|
3 -> 4
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
"Int *",
|
"Num *",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1161,17 +1161,17 @@ mod solve_expr {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn one_field_record() {
|
fn one_field_record() {
|
||||||
infer_eq("{ x: 5 }", "{ x : Int * }");
|
infer_eq("{ x: 5 }", "{ x : Num * }");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn two_field_record() {
|
fn two_field_record() {
|
||||||
infer_eq("{ x: 5, y : 3.14 }", "{ x : Int *, y : Float * }");
|
infer_eq("{ x: 5, y : 3.14 }", "{ x : Num *, y : Float * }");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn record_literal_accessor() {
|
fn record_literal_accessor() {
|
||||||
infer_eq("{ x: 5, y : 3.14 }.x", "Int *");
|
infer_eq("{ x: 5, y : 3.14 }.x", "Num *");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1230,7 +1230,7 @@ mod solve_expr {
|
||||||
infer_eq(
|
infer_eq(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
foo : Int * -> custom
|
foo : Num * -> custom
|
||||||
|
|
||||||
foo 2
|
foo 2
|
||||||
"#
|
"#
|
||||||
|
@ -1327,7 +1327,7 @@ mod solve_expr {
|
||||||
\Foo -> 42
|
\Foo -> 42
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
"[ Foo ] -> Int *",
|
"[ Foo ] -> Num *",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1339,7 +1339,7 @@ mod solve_expr {
|
||||||
\@Foo -> 42
|
\@Foo -> 42
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
"[ @Foo ] -> Int *",
|
"[ @Foo ] -> Num *",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1354,7 +1354,7 @@ mod solve_expr {
|
||||||
False -> 0
|
False -> 0
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
"[ False, True ] -> Int *",
|
"[ False, True ] -> Num *",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1366,7 +1366,7 @@ mod solve_expr {
|
||||||
Foo "happy" 2020
|
Foo "happy" 2020
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
"[ Foo Str (Int *) ]*",
|
"[ Foo Str (Num *) ]*",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1378,7 +1378,7 @@ mod solve_expr {
|
||||||
@Foo "happy" 2020
|
@Foo "happy" 2020
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
"[ @Foo Str (Int *) ]*",
|
"[ @Foo Str (Num *) ]*",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1407,7 +1407,7 @@ mod solve_expr {
|
||||||
{ x: 4 } -> 4
|
{ x: 4 } -> 4
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
"Int *",
|
"Num *",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2347,7 +2347,7 @@ mod solve_expr {
|
||||||
{ numIdentity, x : numIdentity 42, y }
|
{ numIdentity, x : numIdentity 42, y }
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
"{ numIdentity : Num a -> Num a, x : Int *, y : F64 }",
|
"{ numIdentity : Num a -> Num a, x : Num a, y : F64 }",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2383,7 +2383,7 @@ mod solve_expr {
|
||||||
f
|
f
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
"Int * -> Int *",
|
"Num * -> Num *",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2416,7 +2416,7 @@ mod solve_expr {
|
||||||
toBit
|
toBit
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
"[ False, True ] -> Int *",
|
"[ False, True ] -> Num *",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2453,7 +2453,7 @@ mod solve_expr {
|
||||||
fromBit
|
fromBit
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
"Int * -> [ False, True ]*",
|
"Num * -> [ False, True ]*",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2505,7 +2505,7 @@ mod solve_expr {
|
||||||
foo { x: 5 }
|
foo { x: 5 }
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
"Int *",
|
"Num *",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2774,7 +2774,7 @@ mod solve_expr {
|
||||||
// infer_eq_without_problem(
|
// infer_eq_without_problem(
|
||||||
// indoc!(
|
// indoc!(
|
||||||
// r#"
|
// r#"
|
||||||
// s : Int *
|
// s : Num *
|
||||||
// s = 3.1
|
// s = 3.1
|
||||||
|
|
||||||
// s
|
// s
|
||||||
|
@ -3214,7 +3214,7 @@ mod solve_expr {
|
||||||
List.get [ 10, 9, 8, 7 ] 1
|
List.get [ 10, 9, 8, 7 ] 1
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
"Result (Int *) [ OutOfBounds ]*",
|
"Result (Num *) [ OutOfBounds ]*",
|
||||||
);
|
);
|
||||||
|
|
||||||
infer_eq_without_problem(
|
infer_eq_without_problem(
|
||||||
|
@ -3497,7 +3497,7 @@ mod solve_expr {
|
||||||
f
|
f
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
"{ p : *, q : * }* -> Int *",
|
"{ p : *, q : * }* -> Num *",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3552,7 +3552,7 @@ mod solve_expr {
|
||||||
_ -> 3
|
_ -> 3
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
"Int * -> Int *",
|
"Num * -> Num *",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3724,8 +3724,7 @@ mod solve_expr {
|
||||||
negatePoint { x: 1, y: 2.1, z: 0x3 }
|
negatePoint { x: 1, y: 2.1, z: 0x3 }
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
// TODO this should be "Int a", FIXME
|
"{ x : Num a, y : F64, z : Int * }",
|
||||||
"{ x : Int *, y : F64, z : Int * }",
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3742,8 +3741,7 @@ mod solve_expr {
|
||||||
{ a, b }
|
{ a, b }
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
// TODO this should be "Int a", FIXME
|
"{ a : { x : Num a, y : F64, z : c }, b : { blah : Str, x : Num a, y : F64, z : c } }",
|
||||||
"{ a : { x : Int *, y : F64, z : c }, b : { blah : Str, x : Int *, y : F64, z : c } }",
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3755,7 +3753,7 @@ mod solve_expr {
|
||||||
\{ x, y ? 0 } -> x + y
|
\{ x, y ? 0 } -> x + y
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
"{ x : Int a, y ? Int a }* -> Int a",
|
"{ x : Num a, y ? Num a }* -> Num a",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3769,7 +3767,7 @@ mod solve_expr {
|
||||||
x + y
|
x + y
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
"Int *",
|
"Num *",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3783,7 +3781,7 @@ mod solve_expr {
|
||||||
{ x, y ? 0 } -> x + y
|
{ x, y ? 0 } -> x + y
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
"{ x : Int a, y ? Int a }* -> Int a",
|
"{ x : Num a, y ? Num a }* -> Num a",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3948,7 +3946,7 @@ mod solve_expr {
|
||||||
g
|
g
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
"Int a -> Int a",
|
"Num a -> Num a",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3987,10 +3985,10 @@ mod solve_expr {
|
||||||
Foo Bar 1
|
Foo Bar 1
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
"[ Foo [ Bar ]* (Int *) ]*",
|
"[ Foo [ Bar ]* (Num *) ]*",
|
||||||
);
|
);
|
||||||
|
|
||||||
infer_eq_without_problem("Foo Bar 1", "[ Foo [ Bar ]* (Int *) ]*");
|
infer_eq_without_problem("Foo Bar 1", "[ Foo [ Bar ]* (Num *) ]*");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -4682,7 +4680,7 @@ mod solve_expr {
|
||||||
x
|
x
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
"Int *",
|
"Num *",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4983,7 +4981,7 @@ mod solve_expr {
|
||||||
None -> 0
|
None -> 0
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
"[ None, Some { tag : [ A, B ] }* ] -> Int *",
|
"[ None, Some { tag : [ A, B ] }* ] -> Num *",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5016,7 +5014,7 @@ mod solve_expr {
|
||||||
{ x: Red, y ? 5 } -> y
|
{ x: Red, y ? 5 } -> y
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
"{ x : [ Blue, Red ], y ? Int a }* -> Int a",
|
"{ x : [ Blue, Red ], y ? Num a }* -> Num a",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5029,8 +5027,7 @@ mod solve_expr {
|
||||||
\UserId id -> id + 1
|
\UserId id -> id + 1
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
// TODO needs parantheses
|
"[ UserId (Num a) ] -> Num a",
|
||||||
"[ UserId Int a ] -> Int a",
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -66,11 +66,11 @@ pub fn type_problem<'b>(
|
||||||
let last = range.len() - 1;
|
let last = range.len() - 1;
|
||||||
for (i, choice) in range.into_iter().enumerate() {
|
for (i, choice) in range.into_iter().enumerate() {
|
||||||
if i == last && i == 1 {
|
if i == last && i == 1 {
|
||||||
range_choices.push(alloc.text(" or "));
|
range_choices.push(alloc.reflow(" or "));
|
||||||
} else if i == last && i > 1 {
|
} else if i == last && i > 1 {
|
||||||
range_choices.push(alloc.text(", or "));
|
range_choices.push(alloc.reflow(", or "));
|
||||||
} else if i > 1 {
|
} else if i > 0 {
|
||||||
range_choices.push(alloc.text(", "));
|
range_choices.push(alloc.reflow(", "));
|
||||||
}
|
}
|
||||||
|
|
||||||
range_choices.push(to_doc(alloc, Parens::Unnecessary, choice));
|
range_choices.push(to_doc(alloc, Parens::Unnecessary, choice));
|
||||||
|
|
|
@ -862,9 +862,9 @@ mod test_reporting {
|
||||||
2│> 2 if 1 -> 0x0
|
2│> 2 if 1 -> 0x0
|
||||||
3│ _ -> 0x1
|
3│ _ -> 0x1
|
||||||
|
|
||||||
Right now it’s an integer of type:
|
Right now it’s a number of type:
|
||||||
|
|
||||||
Int a
|
Num a
|
||||||
|
|
||||||
But I need every `if` guard condition to evaluate to a Bool—either
|
But I need every `if` guard condition to evaluate to a Bool—either
|
||||||
`True` or `False`.
|
`True` or `False`.
|
||||||
|
@ -896,7 +896,7 @@ mod test_reporting {
|
||||||
|
|
||||||
but the `then` branch has the type:
|
but the `then` branch has the type:
|
||||||
|
|
||||||
Int a
|
Num a
|
||||||
|
|
||||||
I need all branches in an `if` to have the same type!
|
I need all branches in an `if` to have the same type!
|
||||||
"#
|
"#
|
||||||
|
@ -927,7 +927,7 @@ mod test_reporting {
|
||||||
|
|
||||||
But all the previous branches have type:
|
But all the previous branches have type:
|
||||||
|
|
||||||
Int a
|
Num a
|
||||||
|
|
||||||
I need all branches in an `if` to have the same type!
|
I need all branches in an `if` to have the same type!
|
||||||
"#
|
"#
|
||||||
|
@ -993,7 +993,7 @@ mod test_reporting {
|
||||||
|
|
||||||
However, the preceding elements in the list all have the type:
|
However, the preceding elements in the list all have the type:
|
||||||
|
|
||||||
Int a
|
Num a
|
||||||
|
|
||||||
I need every element in a list to have the same type!
|
I need every element in a list to have the same type!
|
||||||
"#
|
"#
|
||||||
|
@ -1250,8 +1250,8 @@ mod test_reporting {
|
||||||
2│ x = if True then 3.14 else 4
|
2│ x = if True then 3.14 else 4
|
||||||
^
|
^
|
||||||
|
|
||||||
It can only be used as a
|
It can only be used as a `I8`, `U8`, `I16`, `U16`, `I32`, `U32`, `I64`, `Nat`, `U64`,
|
||||||
`I8``U8`, `I16`, `U16`, `I32`, `U32`, `I64`, `Nat`, `U64`, `I128`, or `U128`
|
`I128`, `U128`, `F32`, `F64`, or `Dec`
|
||||||
|
|
||||||
But it is being used as:
|
But it is being used as:
|
||||||
|
|
||||||
|
@ -1439,7 +1439,7 @@ mod test_reporting {
|
||||||
|
|
||||||
But the expression between `when` and `is` has the type:
|
But the expression between `when` and `is` has the type:
|
||||||
|
|
||||||
Int a
|
Num a
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -1470,7 +1470,7 @@ mod test_reporting {
|
||||||
|
|
||||||
But all the previous branches match:
|
But all the previous branches match:
|
||||||
|
|
||||||
Int a
|
Num a
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -1500,7 +1500,7 @@ mod test_reporting {
|
||||||
|
|
||||||
But the expression between `when` and `is` has the type:
|
But the expression between `when` and `is` has the type:
|
||||||
|
|
||||||
{ foo : Int a }
|
{ foo : Num a }
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -1620,13 +1620,13 @@ mod test_reporting {
|
||||||
2│ {} | 1 -> 3
|
2│ {} | 1 -> 3
|
||||||
^^^^^^
|
^^^^^^
|
||||||
|
|
||||||
The first pattern is trying to match integers:
|
The first pattern is trying to match numbers:
|
||||||
|
|
||||||
Int a
|
Num a
|
||||||
|
|
||||||
But the expression between `when` and `is` has the type:
|
But the expression between `when` and `is` has the type:
|
||||||
|
|
||||||
{ foo : Int a }
|
{ foo : Num a }
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -1652,9 +1652,9 @@ mod test_reporting {
|
||||||
1│ (Foo x) = 42
|
1│ (Foo x) = 42
|
||||||
^^
|
^^
|
||||||
|
|
||||||
It is an integer of type:
|
It is a number of type:
|
||||||
|
|
||||||
Int a
|
Num a
|
||||||
|
|
||||||
But you are trying to use it as:
|
But you are trying to use it as:
|
||||||
|
|
||||||
|
@ -2177,8 +2177,8 @@ mod test_reporting {
|
||||||
|
|
||||||
This is usually a typo. Here are the `x` fields that are most similar:
|
This is usually a typo. Here are the `x` fields that are most similar:
|
||||||
|
|
||||||
{ fo : Int b
|
{ fo : Num b
|
||||||
, bar : Int a
|
, bar : Num a
|
||||||
}
|
}
|
||||||
|
|
||||||
So maybe `.foo` should be `.fo`?
|
So maybe `.foo` should be `.fo`?
|
||||||
|
@ -2244,10 +2244,10 @@ mod test_reporting {
|
||||||
|
|
||||||
This is usually a typo. Here are the `x` fields that are most similar:
|
This is usually a typo. Here are the `x` fields that are most similar:
|
||||||
|
|
||||||
{ fo : Int c
|
{ fo : Num c
|
||||||
, foobar : Int d
|
, foobar : Num d
|
||||||
, bar : Int a
|
, bar : Num a
|
||||||
, baz : Int b
|
, baz : Num b
|
||||||
, ...
|
, ...
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2342,7 +2342,7 @@ mod test_reporting {
|
||||||
|
|
||||||
But `add` needs the 2nd argument to be:
|
But `add` needs the 2nd argument to be:
|
||||||
|
|
||||||
Num (Integer a)
|
Num a
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -3375,8 +3375,8 @@ mod test_reporting {
|
||||||
|
|
||||||
This `ACons` global tag application has the type:
|
This `ACons` global tag application has the type:
|
||||||
|
|
||||||
[ ACons Int Signed64 [ BCons (Int a) [ ACons Str [ BNil ]b ]c ]d,
|
[ ACons Num (Integer Signed64) [ BCons (Num a) [ ACons Str [ BNil
|
||||||
ANil ]
|
]b ]c ]d, ANil ]
|
||||||
|
|
||||||
But the type annotation on `x` says it should be:
|
But the type annotation on `x` says it should be:
|
||||||
|
|
||||||
|
@ -3401,9 +3401,7 @@ mod test_reporting {
|
||||||
minlit = -170_141_183_460_469_231_731_687_303_715_884_105_728
|
minlit = -170_141_183_460_469_231_731_687_303_715_884_105_728
|
||||||
maxlit = 340_282_366_920_938_463_463_374_607_431_768_211_455
|
maxlit = 340_282_366_920_938_463_463_374_607_431_768_211_455
|
||||||
|
|
||||||
getI128 = \_ -> 1i128
|
x + y + h + l + minlit + maxlit
|
||||||
|
|
||||||
x + y + h + l + minlit + (getI128 maxlit)
|
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
indoc!(
|
indoc!(
|
||||||
|
@ -4990,7 +4988,7 @@ mod test_reporting {
|
||||||
|
|
||||||
This `insert` call produces:
|
This `insert` call produces:
|
||||||
|
|
||||||
Dict Str (Int a)
|
Dict Str (Num a)
|
||||||
|
|
||||||
But the type annotation on `myDict` says it should be:
|
But the type annotation on `myDict` says it should be:
|
||||||
|
|
||||||
|
@ -5652,7 +5650,7 @@ mod test_reporting {
|
||||||
|
|
||||||
but the `then` branch has the type:
|
but the `then` branch has the type:
|
||||||
|
|
||||||
Int a
|
Num a
|
||||||
|
|
||||||
I need all branches in an `if` to have the same type!
|
I need all branches in an `if` to have the same type!
|
||||||
"#
|
"#
|
||||||
|
@ -6293,7 +6291,7 @@ I need all branches in an `if` to have the same type!
|
||||||
|
|
||||||
This `map` call produces:
|
This `map` call produces:
|
||||||
|
|
||||||
List [ Foo Int a ]
|
List [ Foo Num a ]
|
||||||
|
|
||||||
But the type annotation on `x` says it should be:
|
But the type annotation on `x` says it should be:
|
||||||
|
|
||||||
|
@ -6543,11 +6541,11 @@ I need all branches in an `if` to have the same type!
|
||||||
|
|
||||||
This argument is an anonymous function of type:
|
This argument is an anonymous function of type:
|
||||||
|
|
||||||
Num (Integer a) -> Num (Integer a)
|
Num a -> Num a
|
||||||
|
|
||||||
But `map` needs the 2nd argument to be:
|
But `map` needs the 2nd argument to be:
|
||||||
|
|
||||||
Str -> Num (Integer a)
|
Str -> Num a
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -6649,21 +6647,6 @@ I need all branches in an `if` to have the same type!
|
||||||
But the type annotation on `mult` says it should be:
|
But the type annotation on `mult` says it should be:
|
||||||
|
|
||||||
F64
|
F64
|
||||||
|
|
||||||
── TYPE MISMATCH ───────────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
The 2nd argument to `mult` is not what I expect:
|
|
||||||
|
|
||||||
4│ mult 0 0
|
|
||||||
^
|
|
||||||
|
|
||||||
This argument is an integer of type:
|
|
||||||
|
|
||||||
Int a
|
|
||||||
|
|
||||||
But `mult` needs the 2nd argument to be:
|
|
||||||
|
|
||||||
F64
|
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -6712,21 +6695,6 @@ I need all branches in an `if` to have the same type!
|
||||||
But the type annotation on `mult` says it should be:
|
But the type annotation on `mult` says it should be:
|
||||||
|
|
||||||
F64
|
F64
|
||||||
|
|
||||||
── TYPE MISMATCH ───────────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
The 2nd argument to `mult` is not what I expect:
|
|
||||||
|
|
||||||
4│ mult 0 0
|
|
||||||
^
|
|
||||||
|
|
||||||
This argument is an integer of type:
|
|
||||||
|
|
||||||
Int a
|
|
||||||
|
|
||||||
But `mult` needs the 2nd argument to be:
|
|
||||||
|
|
||||||
F64
|
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -7078,9 +7046,9 @@ I need all branches in an `if` to have the same type!
|
||||||
5│ f = \c -> c 6
|
5│ f = \c -> c 6
|
||||||
^
|
^
|
||||||
|
|
||||||
This argument is an integer of type:
|
This argument is a number of type:
|
||||||
|
|
||||||
Int a
|
Num a
|
||||||
|
|
||||||
But `c` needs the 1st argument to be:
|
But `c` needs the 1st argument to be:
|
||||||
|
|
||||||
|
@ -7088,7 +7056,7 @@ I need all branches in an `if` to have the same type!
|
||||||
|
|
||||||
Tip: The type annotation uses the type variable `a` to say that this
|
Tip: The type annotation uses the type variable `a` to say that this
|
||||||
definition can produce any type of value. But in the body I see that
|
definition can produce any type of value. But in the body I see that
|
||||||
it will only produce a `Int` value of a single specific type. Maybe
|
it will only produce a `Num` value of a single specific type. Maybe
|
||||||
change the type annotation to be more specific? Maybe change the code
|
change the type annotation to be more specific? Maybe change the code
|
||||||
to be more general?
|
to be more general?
|
||||||
"#
|
"#
|
||||||
|
@ -7914,7 +7882,7 @@ I need all branches in an `if` to have the same type!
|
||||||
2│ List.get [1,2,3] a
|
2│ List.get [1,2,3] a
|
||||||
^
|
^
|
||||||
|
|
||||||
It can only be used as a `I64` or `I128`
|
It can only be used as a `I64`, `I128`, `F32`, `F64`, or `Dec`
|
||||||
|
|
||||||
But it is being used as:
|
But it is being used as:
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue