Include floats in bounds for unspecified numbers

This commit is contained in:
ayazhafiz 2022-02-06 12:31:37 -05:00
parent 3fffca48bb
commit c5d918e68c
8 changed files with 129 additions and 180 deletions

View file

@ -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!(),

View file

@ -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 {

View file

@ -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)
}
} }

View file

@ -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(),

View file

@ -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
}
} }
} }
} }

View file

@ -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",
) )
} }

View file

@ -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));

View file

@ -862,9 +862,9 @@ mod test_reporting {
2> 2 if 1 -> 0x0 2> 2 if 1 -> 0x0
3 _ -> 0x1 3 _ -> 0x1
Right now its an integer of type: Right now its a number of type:
Int a Num a
But I need every `if` guard condition to evaluate to a Booleither But I need every `if` guard condition to evaluate to a Booleither
`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: