Merge branch 'trunk' into list-eq

This commit is contained in:
Richard Feldman 2021-01-04 22:53:14 -05:00 committed by GitHub
commit ba9448619a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
49 changed files with 1440 additions and 4168 deletions

View file

@ -29,6 +29,7 @@ pub fn build_file(
) -> Result<PathBuf, LoadingProblem> { ) -> Result<PathBuf, LoadingProblem> {
let compilation_start = SystemTime::now(); let compilation_start = SystemTime::now();
let arena = Bump::new(); let arena = Bump::new();
let ptr_bytes = target.pointer_width().unwrap().bytes() as u32;
// Step 1: compile the app and generate the .o file // Step 1: compile the app and generate the .o file
let subs_by_module = MutMap::default(); let subs_by_module = MutMap::default();
@ -36,7 +37,7 @@ pub fn build_file(
// Release builds use uniqueness optimizations // Release builds use uniqueness optimizations
let stdlib = match opt_level { let stdlib = match opt_level {
OptLevel::Normal => roc_builtins::std::standard_stdlib(), OptLevel::Normal => roc_builtins::std::standard_stdlib(),
OptLevel::Optimize => roc_builtins::unique::uniq_stdlib(), OptLevel::Optimize => roc_builtins::std::standard_stdlib(),
}; };
let loaded = roc_load::file::load_and_monomorphize( let loaded = roc_load::file::load_and_monomorphize(
&arena, &arena,
@ -44,6 +45,7 @@ pub fn build_file(
stdlib, stdlib,
src_dir.as_path(), src_dir.as_path(),
subs_by_module, subs_by_module,
ptr_bytes,
)?; )?;
let path_to_platform = loaded.platform_path.clone(); let path_to_platform = loaded.platform_path.clone();

View file

@ -35,6 +35,8 @@ pub fn gen_and_eval(src: &[u8], target: Triple, opt_level: OptLevel) -> Result<R
let module_src = promote_expr_to_module(src_str); let module_src = promote_expr_to_module(src_str);
let ptr_bytes = target.pointer_width().unwrap().bytes() as u32;
let exposed_types = MutMap::default(); let exposed_types = MutMap::default();
let loaded = roc_load::file::load_and_monomorphize_from_str( let loaded = roc_load::file::load_and_monomorphize_from_str(
&arena, &arena,
@ -43,6 +45,7 @@ pub fn gen_and_eval(src: &[u8], target: Triple, opt_level: OptLevel) -> Result<R
stdlib, stdlib,
src_dir, src_dir,
exposed_types, exposed_types,
ptr_bytes,
); );
let mut loaded = loaded.expect("failed to load module"); let mut loaded = loaded.expect("failed to load module");

View file

@ -54,22 +54,22 @@ mod repl_eval {
#[test] #[test]
fn literal_0x0() { fn literal_0x0() {
expect_success("0x0", "0 : I64"); expect_success("0x0", "0 : Int *");
} }
#[test] #[test]
fn literal_0x42() { fn literal_0x42() {
expect_success("0x42", "66 : I64"); expect_success("0x42", "66 : Int *");
} }
#[test] #[test]
fn literal_0point0() { fn literal_0point0() {
expect_success("0.0", "0 : F64"); expect_success("0.0", "0 : Float *");
} }
#[test] #[test]
fn literal_4point2() { fn literal_4point2() {
expect_success("4.2", "4.2 : F64"); expect_success("4.2", "4.2 : Float *");
} }
#[test] #[test]
@ -89,7 +89,7 @@ mod repl_eval {
#[test] #[test]
fn num_rem() { fn num_rem() {
expect_success("299 % 10", "Ok 9 : Result I64 [ DivByZero ]*"); expect_success("299 % 10", "Ok 9 : Result (Int *) [ DivByZero ]*");
} }
#[test] #[test]
@ -153,7 +153,7 @@ mod repl_eval {
#[test] #[test]
fn single_element_tag_union() { fn single_element_tag_union() {
expect_success("True 1", "True 1 : [ True (Num *) ]*"); expect_success("True 1", "True 1 : [ True (Num *) ]*");
expect_success("Foo 1 3.14", "Foo 1 3.14 : [ Foo (Num *) F64 ]*"); expect_success("Foo 1 3.14", "Foo 1 3.14 : [ Foo (Num *) (Float *) ]*");
} }
#[test] #[test]
@ -162,7 +162,7 @@ mod repl_eval {
expect_success( expect_success(
"if 1 == 1 then True 3 else False 3.14", "if 1 == 1 then True 3 else False 3.14",
"True 3 : [ False F64, True (Num *) ]*", "True 3 : [ False (Float *), True (Num *) ]*",
) )
} }
@ -191,7 +191,7 @@ mod repl_eval {
#[test] #[test]
fn str_count_graphemes() { fn str_count_graphemes() {
expect_success("Str.countGraphemes \"å🤔\"", "2 : I64"); expect_success("Str.countGraphemes \"å🤔\"", "2 : Int *");
} }
#[test] #[test]
@ -206,12 +206,12 @@ mod repl_eval {
#[test] #[test]
fn literal_int_list() { fn literal_int_list() {
expect_success("[ 0x1, 0x2, 0x3 ]", "[ 1, 2, 3 ] : List I64"); expect_success("[ 0x1, 0x2, 0x3 ]", "[ 1, 2, 3 ] : List (Int *)");
} }
#[test] #[test]
fn literal_float_list() { fn literal_float_list() {
expect_success("[ 1.1, 2.2, 3.3 ]", "[ 1.1, 2.2, 3.3 ] : List F64"); expect_success("[ 1.1, 2.2, 3.3 ]", "[ 1.1, 2.2, 3.3 ] : List (Float *)");
} }
#[test] #[test]
@ -253,26 +253,26 @@ mod repl_eval {
#[test] #[test]
fn num_bitwise_and() { fn num_bitwise_and() {
expect_success("Num.bitwiseAnd 20 20", "20 : I64"); expect_success("Num.bitwiseAnd 20 20", "20 : Int *");
expect_success("Num.bitwiseAnd 25 10", "8 : I64"); expect_success("Num.bitwiseAnd 25 10", "8 : Int *");
expect_success("Num.bitwiseAnd 200 0", "0 : I64") expect_success("Num.bitwiseAnd 200 0", "0 : Int *")
} }
#[test] #[test]
fn num_add_wrap() { fn num_add_wrap() {
expect_success("Num.addWrap Num.maxInt 1", "-9223372036854775808 : I64"); expect_success("Num.addWrap Num.maxInt 1", "-9223372036854775808 : Int *");
} }
#[test] #[test]
fn num_sub_wrap() { fn num_sub_wrap() {
expect_success("Num.subWrap Num.minInt 1", "9223372036854775807 : I64"); expect_success("Num.subWrap Num.minInt 1", "9223372036854775807 : Int *");
} }
#[test] #[test]
fn num_mul_wrap() { fn num_mul_wrap() {
expect_success("Num.mulWrap Num.maxInt 2", "-2 : I64"); expect_success("Num.mulWrap Num.maxInt 2", "-2 : Int *");
} }
#[test] #[test]
@ -309,7 +309,7 @@ mod repl_eval {
fn list_concat() { fn list_concat() {
expect_success( expect_success(
"List.concat [ 1.1, 2.2 ] [ 3.3, 4.4, 5.5 ]", "List.concat [ 1.1, 2.2 ] [ 3.3, 4.4, 5.5 ]",
"[ 1.1, 2.2, 3.3, 4.4, 5.5 ] : List F64", "[ 1.1, 2.2, 3.3, 4.4, 5.5 ] : List (Float *)",
); );
} }
@ -368,7 +368,7 @@ mod repl_eval {
fn basic_1_field_f64_record() { fn basic_1_field_f64_record() {
// Even though this gets unwrapped at runtime, the repl should still // Even though this gets unwrapped at runtime, the repl should still
// report it as a record // report it as a record
expect_success("{ foo: 4.2 }", "{ foo: 4.2 } : { foo : F64 }"); expect_success("{ foo: 4.2 }", "{ foo: 4.2 } : { foo : Float * }");
} }
#[test] #[test]
@ -387,7 +387,7 @@ mod repl_eval {
// report it as a record // report it as a record
expect_success( expect_success(
"{ foo: { bar: { baz: 4.2 } } }", "{ foo: { bar: { baz: 4.2 } } }",
"{ foo: { bar: { baz: 4.2 } } } : { foo : { bar : { baz : F64 } } }", "{ foo: { bar: { baz: 4.2 } } } : { foo : { bar : { baz : Float * } } }",
); );
} }
@ -395,7 +395,7 @@ mod repl_eval {
fn basic_2_field_i64_record() { fn basic_2_field_i64_record() {
expect_success( expect_success(
"{ foo: 0x4, bar: 0x2 }", "{ foo: 0x4, bar: 0x2 }",
"{ bar: 2, foo: 4 } : { bar : I64, foo : I64 }", "{ bar: 2, foo: 4 } : { bar : Int *, foo : Int * }",
); );
} }
@ -403,7 +403,7 @@ mod repl_eval {
fn basic_2_field_f64_record() { fn basic_2_field_f64_record() {
expect_success( expect_success(
"{ foo: 4.1, bar: 2.3 }", "{ foo: 4.1, bar: 2.3 }",
"{ bar: 2.3, foo: 4.1 } : { bar : F64, foo : F64 }", "{ bar: 2.3, foo: 4.1 } : { bar : Float *, foo : Float * }",
); );
} }
@ -411,7 +411,7 @@ mod repl_eval {
fn basic_2_field_mixed_record() { fn basic_2_field_mixed_record() {
expect_success( expect_success(
"{ foo: 4.1, bar: 2 }", "{ foo: 4.1, bar: 2 }",
"{ bar: 2, foo: 4.1 } : { bar : Num *, foo : F64 }", "{ bar: 2, foo: 4.1 } : { bar : Num *, foo : Float * }",
); );
} }
@ -419,7 +419,7 @@ mod repl_eval {
fn basic_3_field_record() { fn basic_3_field_record() {
expect_success( expect_success(
"{ foo: 4.1, bar: 2, baz: 0x5 }", "{ foo: 4.1, bar: 2, baz: 0x5 }",
"{ bar: 2, baz: 5, foo: 4.1 } : { bar : Num *, baz : I64, foo : F64 }", "{ bar: 2, baz: 5, foo: 4.1 } : { bar : Num *, baz : Int *, foo : Float * }",
); );
} }
@ -434,7 +434,7 @@ mod repl_eval {
fn list_of_2_field_records() { fn list_of_2_field_records() {
expect_success( expect_success(
"[ { foo: 4.1, bar: 2 } ]", "[ { foo: 4.1, bar: 2 } ]",
"[ { bar: 2, foo: 4.1 } ] : List { bar : Num *, foo : F64 }", "[ { bar: 2, foo: 4.1 } ] : List { bar : Num *, foo : Float * }",
); );
} }
@ -466,7 +466,7 @@ mod repl_eval {
fn list_of_3_field_records() { fn list_of_3_field_records() {
expect_success( expect_success(
"[ { foo: 4.1, bar: 2, baz: 0x3 } ]", "[ { foo: 4.1, bar: 2, baz: 0x3 } ]",
"[ { bar: 2, baz: 3, foo: 4.1 } ] : List { bar : Num *, baz : I64, foo : F64 }", "[ { bar: 2, baz: 3, foo: 4.1 } ] : List { bar : Num *, baz : Int *, foo : Float * }",
); );
} }

View file

@ -91,10 +91,13 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
), ),
); );
// addWrap : Int, Int -> Int // addWrap : Int range, Int range -> Int range
add_type( add_type(
Symbol::NUM_ADD_WRAP, Symbol::NUM_ADD_WRAP,
top_level_function(vec![int_type(), int_type()], Box::new(int_type())), top_level_function(
vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))],
Box::new(int_type(flex(TVAR1))),
),
); );
// sub or (-) : Num a, Num a -> Num a // sub or (-) : Num a, Num a -> Num a
@ -106,10 +109,13 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
), ),
); );
// subWrap : Int, Int -> Int // subWrap : Int range, Int range -> Int range
add_type( add_type(
Symbol::NUM_SUB_WRAP, Symbol::NUM_SUB_WRAP,
top_level_function(vec![int_type(), int_type()], Box::new(int_type())), top_level_function(
vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))],
Box::new(int_type(flex(TVAR1))),
),
); );
// subChecked : Num a, Num a -> Result (Num a) [ Overflow ]* // subChecked : Num a, Num a -> Result (Num a) [ Overflow ]*
@ -130,10 +136,13 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
), ),
); );
// mulWrap : Int, Int -> Int // mulWrap : Int range, Int range -> Int range
add_type( add_type(
Symbol::NUM_MUL_WRAP, Symbol::NUM_MUL_WRAP,
top_level_function(vec![int_type(), int_type()], Box::new(int_type())), top_level_function(
vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))],
Box::new(int_type(flex(TVAR1))),
),
); );
// mulChecked : Num a, Num a -> Result (Num a) [ Overflow ]* // mulChecked : Num a, Num a -> Result (Num a) [ Overflow ]*
@ -214,10 +223,13 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
), ),
); );
// toFloat : Num a -> Float // toFloat : Num * -> Float *
add_type( add_type(
Symbol::NUM_TO_FLOAT, Symbol::NUM_TO_FLOAT,
top_level_function(vec![num_type(flex(TVAR1))], Box::new(float_type())), top_level_function(
vec![num_type(flex(TVAR1))],
Box::new(float_type(flex(TVAR2))),
),
); );
// isNegative : Num a -> Bool // isNegative : Num a -> Bool
@ -250,11 +262,11 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
top_level_function(vec![num_type(flex(TVAR1))], Box::new(bool_type())), top_level_function(vec![num_type(flex(TVAR1))], Box::new(bool_type())),
); );
// maxInt : Int // maxInt : Int range
add_type(Symbol::NUM_MAX_INT, int_type()); add_type(Symbol::NUM_MAX_INT, int_type(flex(TVAR1)));
// minInt : Int // minInt : Int range
add_type(Symbol::NUM_MIN_INT, int_type()); add_type(Symbol::NUM_MIN_INT, int_type(flex(TVAR1)));
// div : Int, Int -> Result Int [ DivByZero ]* // div : Int, Int -> Result Int [ DivByZero ]*
let div_by_zero = SolvedType::TagUnion( let div_by_zero = SolvedType::TagUnion(
@ -265,56 +277,59 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
add_type( add_type(
Symbol::NUM_DIV_INT, Symbol::NUM_DIV_INT,
top_level_function( top_level_function(
vec![int_type(), int_type()], vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))],
Box::new(result_type(int_type(), div_by_zero.clone())), Box::new(result_type(int_type(flex(TVAR1)), div_by_zero.clone())),
), ),
); );
// bitwiseAnd : Int, Int -> Int // bitwiseAnd : Int a, Int a -> Int a
add_type( add_type(
Symbol::NUM_BITWISE_AND, Symbol::NUM_BITWISE_AND,
top_level_function(vec![int_type(), int_type()], Box::new(int_type())), top_level_function(
vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))],
Box::new(int_type(flex(TVAR1))),
),
); );
// rem : Int, Int -> Result Int [ DivByZero ]* // rem : Int a, Int a -> Result (Int a) [ DivByZero ]*
add_type( add_type(
Symbol::NUM_REM, Symbol::NUM_REM,
top_level_function( top_level_function(
vec![int_type(), int_type()], vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))],
Box::new(result_type(int_type(), div_by_zero.clone())), Box::new(result_type(int_type(flex(TVAR1)), div_by_zero.clone())),
), ),
); );
// mod : Int, Int -> Result Int [ DivByZero ]* // mod : Int a, Int a -> Result (Int a) [ DivByZero ]*
add_type( add_type(
Symbol::NUM_MOD_INT, Symbol::NUM_MOD_INT,
top_level_function( top_level_function(
vec![int_type(), int_type()], vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))],
Box::new(result_type(int_type(), div_by_zero.clone())), Box::new(result_type(int_type(flex(TVAR1)), div_by_zero.clone())),
), ),
); );
// Float module // Float module
// div : Float, Float -> Float // div : Float a, Float a -> Float a
add_type( add_type(
Symbol::NUM_DIV_FLOAT, Symbol::NUM_DIV_FLOAT,
top_level_function( top_level_function(
vec![float_type(), float_type()], vec![float_type(flex(TVAR1)), float_type(flex(TVAR1))],
Box::new(result_type(float_type(), div_by_zero.clone())), Box::new(result_type(float_type(flex(TVAR1)), div_by_zero.clone())),
), ),
); );
// mod : Float, Float -> Result Int [ DivByZero ]* // mod : Float a, Float a -> Result (Float a) [ DivByZero ]*
add_type( add_type(
Symbol::NUM_MOD_FLOAT, Symbol::NUM_MOD_FLOAT,
top_level_function( top_level_function(
vec![float_type(), float_type()], vec![float_type(flex(TVAR1)), float_type(flex(TVAR1))],
Box::new(result_type(float_type(), div_by_zero)), Box::new(result_type(float_type(flex(TVAR1)), div_by_zero)),
), ),
); );
// sqrt : Float -> Float // sqrt : Float a -> Float a
let sqrt_of_negative = SolvedType::TagUnion( let sqrt_of_negative = SolvedType::TagUnion(
vec![(TagName::Global("SqrtOfNegative".into()), vec![])], vec![(TagName::Global("SqrtOfNegative".into()), vec![])],
Box::new(SolvedType::Wildcard), Box::new(SolvedType::Wildcard),
@ -323,81 +338,114 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
add_type( add_type(
Symbol::NUM_SQRT, Symbol::NUM_SQRT,
top_level_function( top_level_function(
vec![float_type()], vec![float_type(flex(TVAR1))],
Box::new(result_type(float_type(), sqrt_of_negative)), Box::new(result_type(float_type(flex(TVAR1)), sqrt_of_negative)),
), ),
); );
// round : Float -> Int // round : Float a -> Int b
add_type( add_type(
Symbol::NUM_ROUND, Symbol::NUM_ROUND,
top_level_function(vec![float_type()], Box::new(int_type())), top_level_function(
vec![float_type(flex(TVAR1))],
Box::new(int_type(flex(TVAR2))),
),
); );
// sin : Float -> Float // sin : Float a -> Float a
add_type( add_type(
Symbol::NUM_SIN, Symbol::NUM_SIN,
top_level_function(vec![float_type()], Box::new(float_type())), top_level_function(
vec![float_type(flex(TVAR1))],
Box::new(float_type(flex(TVAR1))),
),
); );
// cos : Float -> Float // cos : Float a -> Float a
add_type( add_type(
Symbol::NUM_COS, Symbol::NUM_COS,
top_level_function(vec![float_type()], Box::new(float_type())), top_level_function(
vec![float_type(flex(TVAR1))],
Box::new(float_type(flex(TVAR1))),
),
); );
// tan : Float -> Float // tan : Float a -> Float a
add_type( add_type(
Symbol::NUM_TAN, Symbol::NUM_TAN,
top_level_function(vec![float_type()], Box::new(float_type())), top_level_function(
vec![float_type(flex(TVAR1))],
Box::new(float_type(flex(TVAR1))),
),
); );
// maxFloat : Float // maxFloat : Float a
add_type(Symbol::NUM_MAX_FLOAT, float_type()); add_type(Symbol::NUM_MAX_FLOAT, float_type(flex(TVAR1)));
// minFloat : Float // minFloat : Float a
add_type(Symbol::NUM_MIN_FLOAT, float_type()); add_type(Symbol::NUM_MIN_FLOAT, float_type(flex(TVAR1)));
// pow : Float, Float -> Float // pow : Float a, Float a -> Float a
add_type( add_type(
Symbol::NUM_POW, Symbol::NUM_POW,
top_level_function(vec![float_type(), float_type()], Box::new(float_type())), top_level_function(
vec![float_type(flex(TVAR1)), float_type(flex(TVAR1))],
Box::new(float_type(flex(TVAR1))),
),
); );
// ceiling : Float -> Int // ceiling : Float a -> Int b
add_type( add_type(
Symbol::NUM_CEILING, Symbol::NUM_CEILING,
top_level_function(vec![float_type()], Box::new(int_type())), top_level_function(
vec![float_type(flex(TVAR1))],
Box::new(int_type(flex(TVAR2))),
),
); );
// powInt : Int, Int -> Int // powInt : Int a, Int a -> Int a
add_type( add_type(
Symbol::NUM_POW_INT, Symbol::NUM_POW_INT,
top_level_function(vec![int_type(), int_type()], Box::new(int_type())), top_level_function(
vec![int_type(flex(TVAR1)), int_type(flex(TVAR1))],
Box::new(int_type(flex(TVAR1))),
),
); );
// floor : Float -> Int // floor : Float a -> Int b
add_type( add_type(
Symbol::NUM_FLOOR, Symbol::NUM_FLOOR,
top_level_function(vec![float_type()], Box::new(int_type())), top_level_function(
vec![float_type(flex(TVAR1))],
Box::new(int_type(flex(TVAR2))),
),
); );
// atan : Float -> Float // atan : Float a -> Float a
add_type( add_type(
Symbol::NUM_ATAN, Symbol::NUM_ATAN,
top_level_function(vec![float_type()], Box::new(float_type())), top_level_function(
vec![float_type(flex(TVAR1))],
Box::new(float_type(flex(TVAR1))),
),
); );
// acos : Float -> Float // acos : Float a -> Float a
add_type( add_type(
Symbol::NUM_ACOS, Symbol::NUM_ACOS,
top_level_function(vec![float_type()], Box::new(float_type())), top_level_function(
vec![float_type(flex(TVAR1))],
Box::new(float_type(flex(TVAR1))),
),
); );
// asin : Float -> Float // asin : Float a -> Float a
add_type( add_type(
Symbol::NUM_ASIN, Symbol::NUM_ASIN,
top_level_function(vec![float_type()], Box::new(float_type())), top_level_function(
vec![float_type(flex(TVAR1))],
Box::new(float_type(flex(TVAR1))),
),
); );
// Bool module // Bool module
@ -461,16 +509,16 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
top_level_function(vec![str_type(), str_type()], Box::new(bool_type())), top_level_function(vec![str_type(), str_type()], Box::new(bool_type())),
); );
// countGraphemes : Str -> Int // countGraphemes : Str -> Int a
add_type( add_type(
Symbol::STR_COUNT_GRAPHEMES, Symbol::STR_COUNT_GRAPHEMES,
top_level_function(vec![str_type()], Box::new(int_type())), top_level_function(vec![str_type()], Box::new(int_type(flex(TVAR1)))),
); );
// fromInt : Int -> Str // fromInt : Int a -> Str
add_type( add_type(
Symbol::STR_FROM_INT, Symbol::STR_FROM_INT,
top_level_function(vec![int_type()], Box::new(str_type())), top_level_function(vec![int_type(flex(TVAR1))], Box::new(str_type())),
); );
// List module // List module
@ -484,7 +532,7 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
add_type( add_type(
Symbol::LIST_GET, Symbol::LIST_GET,
top_level_function( top_level_function(
vec![list_type(flex(TVAR1)), int_type()], vec![list_type(flex(TVAR1)), int_type(flex(TVAR2))],
Box::new(result_type(flex(TVAR1), index_out_of_bounds)), Box::new(result_type(flex(TVAR1), index_out_of_bounds)),
), ),
); );
@ -512,11 +560,11 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
), ),
); );
// set : List elem, Int, elem -> List elem // set : List elem, Int a, elem -> List elem
add_type( add_type(
Symbol::LIST_SET, Symbol::LIST_SET,
top_level_function( top_level_function(
vec![list_type(flex(TVAR1)), int_type(), flex(TVAR1)], vec![list_type(flex(TVAR1)), int_type(flex(TVAR2)), flex(TVAR1)],
Box::new(list_type(flex(TVAR1))), Box::new(list_type(flex(TVAR1))),
), ),
); );
@ -631,11 +679,11 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
top_level_function(vec![flex(TVAR1)], Box::new(list_type(flex(TVAR1)))), top_level_function(vec![flex(TVAR1)], Box::new(list_type(flex(TVAR1)))),
); );
// repeat : Int, elem -> List elem // repeat : Int a, elem -> List elem
add_type( add_type(
Symbol::LIST_REPEAT, Symbol::LIST_REPEAT,
top_level_function( top_level_function(
vec![int_type(), flex(TVAR1)], vec![int_type(flex(TVAR1)), flex(TVAR2)],
Box::new(list_type(flex(TVAR1))), Box::new(list_type(flex(TVAR1))),
), ),
); );
@ -649,10 +697,13 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
), ),
); );
// len : List * -> Int // len : List * -> Int a
add_type( add_type(
Symbol::LIST_LEN, Symbol::LIST_LEN,
top_level_function(vec![list_type(flex(TVAR1))], Box::new(int_type())), top_level_function(
vec![list_type(flex(TVAR1))],
Box::new(int_type(flex(TVAR2))),
),
); );
// isEmpty : List * -> Bool // isEmpty : List * -> Bool

View file

@ -166,8 +166,8 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// addWrap : Int, Int -> Int // addWrap : Int, Int -> Int
add_type(Symbol::NUM_ADD_WRAP, { add_type(Symbol::NUM_ADD_WRAP, {
let_tvars! { u, v, w }; let_tvars! { u, v, w, int };
unique_function(vec![int_type(u), int_type(v)], int_type(w)) unique_function(vec![int_type(u, int), int_type(v, int)], int_type(w, int))
}); });
// sub or (-) : Num a, Num a -> Num a // sub or (-) : Num a, Num a -> Num a
@ -199,8 +199,8 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// mulWrap : Int, Int -> Int // mulWrap : Int, Int -> Int
add_type(Symbol::NUM_MUL_WRAP, { add_type(Symbol::NUM_MUL_WRAP, {
let_tvars! { u, v, w }; let_tvars! { u, v, w , int };
unique_function(vec![int_type(u), int_type(v)], int_type(w)) unique_function(vec![int_type(u, int), int_type(v, int)], int_type(w, int))
}); });
// mulChecked : Num a, Num a -> Result (Num a) [ Overflow ]* // mulChecked : Num a, Num a -> Result (Num a) [ Overflow ]*
@ -257,38 +257,41 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// rem : Attr * Int, Attr * Int -> Attr * (Result (Attr * Int) (Attr * [ DivByZero ]*)) // rem : Attr * Int, Attr * Int -> Attr * (Result (Attr * Int) (Attr * [ DivByZero ]*))
add_type(Symbol::NUM_REM, { add_type(Symbol::NUM_REM, {
let_tvars! { star1, star2, star3, star4, star5 }; let_tvars! { star1, star2, star3, star4, star5, int };
unique_function( unique_function(
vec![int_type(star1), int_type(star2)], vec![int_type(star1, int), int_type(star2, int)],
result_type(star3, int_type(star4), lift(star5, div_by_zero())), result_type(star3, int_type(star4, int), lift(star5, div_by_zero())),
) )
}); });
// maxInt : Int // maxInt : Int
add_type(Symbol::NUM_MAX_INT, { add_type(Symbol::NUM_MAX_INT, {
let_tvars! { star }; let_tvars! { star, int };
int_type(star) int_type(star, int)
}); });
// minInt : Int // minInt : Int
add_type(Symbol::NUM_MIN_INT, { add_type(Symbol::NUM_MIN_INT, {
let_tvars! { star }; let_tvars! { star, int };
int_type(star) int_type(star, int)
}); });
// divFloor or (//) : Int, Int -> Result Int [ DivByZero ]* // divFloor or (//) : Int, Int -> Result Int [ DivByZero ]*
add_type(Symbol::NUM_DIV_INT, { add_type(Symbol::NUM_DIV_INT, {
let_tvars! { star1, star2, star3, star4, star5 }; let_tvars! { star1, star2, star3, star4, star5, int };
unique_function( unique_function(
vec![int_type(star1), int_type(star2)], vec![int_type(star1, int), int_type(star2, int)],
result_type(star3, int_type(star4), lift(star5, div_by_zero())), result_type(star3, int_type(star4, int), lift(star5, div_by_zero())),
) )
}); });
// bitwiseAnd : Attr * Int, Attr * Int -> Attr * Int // bitwiseAnd : Attr * Int, Attr * Int -> Attr * Int
add_type(Symbol::NUM_BITWISE_AND, { add_type(Symbol::NUM_BITWISE_AND, {
let_tvars! { star1, star2, star3 }; let_tvars! { star1, star2, star3, int };
unique_function(vec![int_type(star1), int_type(star2)], int_type(star3)) unique_function(
vec![int_type(star1, int), int_type(star2, int)],
int_type(star3, int),
)
}); });
// divFloat : Float, Float -> Float // divFloat : Float, Float -> Float
@ -302,8 +305,8 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// round : Float -> Int // round : Float -> Int
add_type(Symbol::NUM_ROUND, { add_type(Symbol::NUM_ROUND, {
let_tvars! { star1, star2 }; let_tvars! { star1, star2, int };
unique_function(vec![float_type(star1)], int_type(star2)) unique_function(vec![float_type(star1)], int_type(star2, int))
}); });
// sqrt : Float -> Float // sqrt : Float -> Float
@ -391,20 +394,23 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// ceiling : Float -> Int // ceiling : Float -> Int
add_type(Symbol::NUM_CEILING, { add_type(Symbol::NUM_CEILING, {
let_tvars! { star1, star2 }; let_tvars! { star1, star2, int };
unique_function(vec![float_type(star1)], int_type(star2)) unique_function(vec![float_type(star1)], int_type(star2, int))
}); });
// powInt : Int, Int -> Int // powInt : Int, Int -> Int
add_type(Symbol::NUM_POW_INT, { add_type(Symbol::NUM_POW_INT, {
let_tvars! { star1, star2, star3 }; let_tvars! { star1, star2, star3 , int };
unique_function(vec![int_type(star1), int_type(star2)], int_type(star3)) unique_function(
vec![int_type(star1, int), int_type(star2, int)],
int_type(star3, int),
)
}); });
// floor : Float -> Int // floor : Float -> Int
add_type(Symbol::NUM_FLOOR, { add_type(Symbol::NUM_FLOOR, {
let_tvars! { star1, star2 }; let_tvars! { star1, star2 , int};
unique_function(vec![float_type(star1)], int_type(star2)) unique_function(vec![float_type(star1)], int_type(star2, int))
}); });
// atan : Float -> Float // atan : Float -> Float
@ -479,8 +485,8 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// len : Attr * (List *) -> Attr * Int // len : Attr * (List *) -> Attr * Int
add_type(Symbol::LIST_LEN, { add_type(Symbol::LIST_LEN, {
let_tvars! { star1, a, star2 }; let_tvars! { star1, a, star2 , int };
unique_function(vec![list_type(star1, a)], int_type(star2)) unique_function(vec![list_type(star1, a)], int_type(star2, int))
}); });
fn list_was_empty() -> SolvedType { fn list_was_empty() -> SolvedType {
@ -536,7 +542,7 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
); );
add_type(Symbol::LIST_GET, { add_type(Symbol::LIST_GET, {
let_tvars! { a, u, star1, star2, star3, star4 }; let_tvars! { a, u, star1, star2, star3, star4, int};
unique_function( unique_function(
vec![ vec![
@ -547,7 +553,7 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
SolvedType::Apply(Symbol::LIST_LIST, vec![attr_type(u, a)]), SolvedType::Apply(Symbol::LIST_LIST, vec![attr_type(u, a)]),
], ],
), ),
int_type(star2), int_type(star2, int),
], ],
result_type(star3, attr_type(u, a), lift(star4, index_out_of_bounds)), result_type(star3, attr_type(u, a), lift(star4, index_out_of_bounds)),
) )
@ -559,7 +565,7 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// Attr (u | v) a // Attr (u | v) a
// -> Attr * (List (Attr u a)) // -> Attr * (List (Attr u a))
add_type(Symbol::LIST_SET, { add_type(Symbol::LIST_SET, {
let_tvars! { u, v, w, star1, star2, a }; let_tvars! { u, v, w, star1, star2, a, int};
unique_function( unique_function(
vec![ vec![
@ -570,7 +576,7 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
SolvedType::Apply(Symbol::LIST_LIST, vec![attr_type(u, a)]), SolvedType::Apply(Symbol::LIST_LIST, vec![attr_type(u, a)]),
], ],
), ),
int_type(star1), int_type(star1, int),
SolvedType::Apply(Symbol::ATTR_ATTR, vec![container(u, vec![v]), flex(a)]), SolvedType::Apply(Symbol::ATTR_ATTR, vec![container(u, vec![v]), flex(a)]),
], ],
SolvedType::Apply( SolvedType::Apply(
@ -627,10 +633,10 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// , Attr Shared a // , Attr Shared a
// -> Attr * (List (Attr Shared a)) // -> Attr * (List (Attr Shared a))
add_type(Symbol::LIST_REPEAT, { add_type(Symbol::LIST_REPEAT, {
let_tvars! { a, star1, star2 }; let_tvars! { a, star1, star2, int };
unique_function( unique_function(
vec![int_type(star1), shared(flex(a))], vec![int_type(star1, int), shared(flex(a))],
SolvedType::Apply( SolvedType::Apply(
Symbol::ATTR_ATTR, Symbol::ATTR_ATTR,
vec![ vec![
@ -1162,14 +1168,14 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// Str.countGraphemes : Attr * Str, -> Attr * Int // Str.countGraphemes : Attr * Str, -> Attr * Int
add_type(Symbol::STR_COUNT_GRAPHEMES, { add_type(Symbol::STR_COUNT_GRAPHEMES, {
let_tvars! { star1, star2 }; let_tvars! { star1, star2, int };
unique_function(vec![str_type(star1)], int_type(star2)) unique_function(vec![str_type(star1)], int_type(star2, int))
}); });
// fromInt : Attr * Int -> Attr * Str // fromInt : Attr * Int -> Attr * Str
add_type(Symbol::STR_FROM_INT, { add_type(Symbol::STR_FROM_INT, {
let_tvars! { star1, star2 }; let_tvars! { star1, star2, int };
unique_function(vec![int_type(star1)], str_type(star2)) unique_function(vec![int_type(star1, int)], str_type(star2))
}); });
// Result module // Result module
@ -1242,9 +1248,8 @@ fn lift(u: VarId, a: SolvedType) -> SolvedType {
#[inline(always)] #[inline(always)]
fn float_type(u: VarId) -> SolvedType { fn float_type(u: VarId) -> SolvedType {
let b_64 = builtin_aliases::binary64_type(); let inner_type = lift(u, flex(u));
let attr_b_64 = lift(u, b_64); let fp = builtin_aliases::floatingpoint_type(inner_type.clone());
let fp = builtin_aliases::floatingpoint_type(attr_b_64);
let attr_fb = lift(u, fp); let attr_fb = lift(u, fp);
let num = builtin_aliases::num_type(attr_fb); let num = builtin_aliases::num_type(attr_fb);
@ -1252,16 +1257,19 @@ fn float_type(u: VarId) -> SolvedType {
Symbol::ATTR_ATTR, Symbol::ATTR_ATTR,
vec![ vec![
flex(u), flex(u),
SolvedType::Alias(Symbol::NUM_F64, Vec::new(), Box::new(num)), SolvedType::Alias(
Symbol::NUM_FLOAT,
vec![("range".into(), inner_type)],
Box::new(num),
),
], ],
) )
} }
#[inline(always)] #[inline(always)]
fn int_type(u: VarId) -> SolvedType { fn int_type(u: VarId, range: VarId) -> SolvedType {
let signed_64 = builtin_aliases::signed64_type(); let inner_type = lift(u, flex(range));
let attr_signed_64 = lift(u, signed_64); let integer = builtin_aliases::integer_type(inner_type.clone());
let integer = builtin_aliases::integer_type(attr_signed_64);
let attr_fb = lift(u, integer); let attr_fb = lift(u, integer);
let num = builtin_aliases::num_type(attr_fb); let num = builtin_aliases::num_type(attr_fb);
@ -1269,7 +1277,11 @@ fn int_type(u: VarId) -> SolvedType {
Symbol::ATTR_ATTR, Symbol::ATTR_ATTR,
vec![ vec![
flex(u), flex(u),
SolvedType::Alias(Symbol::NUM_I64, Vec::new(), Box::new(num)), SolvedType::Alias(
Symbol::NUM_INT,
vec![("range".into(), inner_type)],
Box::new(num),
),
], ],
) )
} }

View file

@ -212,7 +212,8 @@ pub fn builtin_defs(var_store: &mut VarStore) -> MutMap<Symbol, Def> {
/// Num.maxInt : Int /// Num.maxInt : Int
fn num_max_int(symbol: Symbol, var_store: &mut VarStore) -> Def { fn num_max_int(symbol: Symbol, var_store: &mut VarStore) -> Def {
let int_var = var_store.fresh(); let int_var = var_store.fresh();
let body = Int(int_var, i64::MAX); let int_percision_var = var_store.fresh();
let body = Int(int_var, int_percision_var, i64::MAX);
Def { Def {
annotation: None, annotation: None,
@ -226,7 +227,8 @@ fn num_max_int(symbol: Symbol, var_store: &mut VarStore) -> Def {
/// Num.minInt : Int /// Num.minInt : Int
fn num_min_int(symbol: Symbol, var_store: &mut VarStore) -> Def { fn num_min_int(symbol: Symbol, var_store: &mut VarStore) -> Def {
let int_var = var_store.fresh(); let int_var = var_store.fresh();
let body = Int(int_var, i64::MIN); let int_percision_var = var_store.fresh();
let body = Int(int_var, int_percision_var, i64::MIN);
Def { Def {
annotation: None, annotation: None,
@ -846,7 +848,7 @@ fn num_is_odd(symbol: Symbol, var_store: &mut VarStore) -> Def {
let body = RunLowLevel { let body = RunLowLevel {
op: LowLevel::Eq, op: LowLevel::Eq,
args: vec![ args: vec![
(arg_var, Int(var_store.fresh(), 1)), (arg_var, Int(var_store.fresh(), var_store.fresh(), 1)),
( (
arg_var, arg_var,
RunLowLevel { RunLowLevel {
@ -930,6 +932,7 @@ fn num_sqrt(symbol: Symbol, var_store: &mut VarStore) -> Def {
let bool_var = var_store.fresh(); let bool_var = var_store.fresh();
let float_var = var_store.fresh(); let float_var = var_store.fresh();
let unbound_zero_var = var_store.fresh(); let unbound_zero_var = var_store.fresh();
let percision_var = var_store.fresh();
let ret_var = var_store.fresh(); let ret_var = var_store.fresh();
let body = If { let body = If {
@ -943,7 +946,7 @@ fn num_sqrt(symbol: Symbol, var_store: &mut VarStore) -> Def {
op: LowLevel::NotEq, op: LowLevel::NotEq,
args: vec![ args: vec![
(float_var, Var(Symbol::ARG_1)), (float_var, Var(Symbol::ARG_1)),
(float_var, Float(unbound_zero_var, 0.0)), (float_var, Float(unbound_zero_var, percision_var, 0.0)),
], ],
ret_var: bool_var, ret_var: bool_var,
}, },
@ -1896,6 +1899,7 @@ fn num_div_float(symbol: Symbol, var_store: &mut VarStore) -> Def {
let bool_var = var_store.fresh(); let bool_var = var_store.fresh();
let num_var = var_store.fresh(); let num_var = var_store.fresh();
let unbound_zero_var = var_store.fresh(); let unbound_zero_var = var_store.fresh();
let percision_var = var_store.fresh();
let ret_var = var_store.fresh(); let ret_var = var_store.fresh();
let body = If { let body = If {
@ -1909,7 +1913,7 @@ fn num_div_float(symbol: Symbol, var_store: &mut VarStore) -> Def {
op: LowLevel::NotEq, op: LowLevel::NotEq,
args: vec![ args: vec![
(num_var, Var(Symbol::ARG_2)), (num_var, Var(Symbol::ARG_2)),
(num_var, Float(unbound_zero_var, 0.0)), (num_var, Float(unbound_zero_var, percision_var, 0.0)),
], ],
ret_var: bool_var, ret_var: bool_var,
}, },
@ -1958,6 +1962,7 @@ fn num_div_int(symbol: Symbol, var_store: &mut VarStore) -> Def {
let bool_var = var_store.fresh(); let bool_var = var_store.fresh();
let num_var = var_store.fresh(); let num_var = var_store.fresh();
let unbound_zero_var = var_store.fresh(); let unbound_zero_var = var_store.fresh();
let unbound_zero_percision_var = var_store.fresh();
let ret_var = var_store.fresh(); let ret_var = var_store.fresh();
let body = If { let body = If {
@ -1971,7 +1976,10 @@ fn num_div_int(symbol: Symbol, var_store: &mut VarStore) -> Def {
op: LowLevel::NotEq, op: LowLevel::NotEq,
args: vec![ args: vec![
(num_var, Var(Symbol::ARG_2)), (num_var, Var(Symbol::ARG_2)),
(num_var, Int(unbound_zero_var, 0)), (
num_var,
Int(unbound_zero_var, unbound_zero_percision_var, 0),
),
], ],
ret_var: bool_var, ret_var: bool_var,
}, },
@ -2025,6 +2033,7 @@ fn list_first(symbol: Symbol, var_store: &mut VarStore) -> Def {
let list_var = var_store.fresh(); let list_var = var_store.fresh();
let len_var = var_store.fresh(); let len_var = var_store.fresh();
let zero_var = var_store.fresh(); let zero_var = var_store.fresh();
let zero_percision_var = var_store.fresh();
let list_elem_var = var_store.fresh(); let list_elem_var = var_store.fresh();
let ret_var = var_store.fresh(); let ret_var = var_store.fresh();
@ -2039,7 +2048,7 @@ fn list_first(symbol: Symbol, var_store: &mut VarStore) -> Def {
RunLowLevel { RunLowLevel {
op: LowLevel::NotEq, op: LowLevel::NotEq,
args: vec![ args: vec![
(len_var, Int(zero_var, 0)), (len_var, Int(zero_var, zero_percision_var, 0)),
( (
len_var, len_var,
RunLowLevel { RunLowLevel {
@ -2061,7 +2070,10 @@ fn list_first(symbol: Symbol, var_store: &mut VarStore) -> Def {
// List.#getUnsafe list 0 // List.#getUnsafe list 0
RunLowLevel { RunLowLevel {
op: LowLevel::ListGetUnsafe, op: LowLevel::ListGetUnsafe,
args: vec![(list_var, Var(Symbol::ARG_1)), (len_var, Int(zero_var, 0))], args: vec![
(list_var, Var(Symbol::ARG_1)),
(len_var, Int(zero_var, zero_percision_var, 0)),
],
ret_var: list_elem_var, ret_var: list_elem_var,
}, },
], ],
@ -2102,6 +2114,7 @@ fn list_last(symbol: Symbol, var_store: &mut VarStore) -> Def {
let list_var = var_store.fresh(); let list_var = var_store.fresh();
let len_var = var_store.fresh(); let len_var = var_store.fresh();
let num_var = var_store.fresh(); let num_var = var_store.fresh();
let num_percision_var = var_store.fresh();
let list_elem_var = var_store.fresh(); let list_elem_var = var_store.fresh();
let ret_var = var_store.fresh(); let ret_var = var_store.fresh();
@ -2116,7 +2129,7 @@ fn list_last(symbol: Symbol, var_store: &mut VarStore) -> Def {
RunLowLevel { RunLowLevel {
op: LowLevel::NotEq, op: LowLevel::NotEq,
args: vec![ args: vec![
(len_var, Int(num_var, 0)), (len_var, Int(num_var, num_percision_var, 0)),
( (
len_var, len_var,
RunLowLevel { RunLowLevel {
@ -2155,7 +2168,7 @@ fn list_last(symbol: Symbol, var_store: &mut VarStore) -> Def {
ret_var: len_var, ret_var: len_var,
}, },
), ),
(arg_var, Int(num_var, 1)), (arg_var, Int(num_var, num_percision_var, 1)),
], ],
ret_var: len_var, ret_var: len_var,
}, },

View file

@ -735,8 +735,8 @@ fn pattern_to_vars_by_symbol(
} }
NumLiteral(_, _) NumLiteral(_, _)
| IntLiteral(_) | IntLiteral(_, _)
| FloatLiteral(_) | FloatLiteral(_, _)
| StrLiteral(_) | StrLiteral(_)
| Underscore | Underscore
| MalformedPattern(_, _) | MalformedPattern(_, _)
@ -864,7 +864,9 @@ fn canonicalize_pending_def<'a>(
} }
} }
Alias { name, ann, vars } => { Alias {
name, ann, vars, ..
} => {
let symbol = name.value; let symbol = name.value;
let can_ann = canonicalize_annotation(env, scope, &ann.value, ann.region, var_store); let can_ann = canonicalize_annotation(env, scope, &ann.value, ann.region, var_store);
@ -1407,7 +1409,9 @@ fn to_pending_def<'a>(
} }
} }
Alias { name, vars, ann } => { Alias {
name, vars, ann, ..
} => {
let region = Region::span_across(&name.region, &ann.region); let region = Region::span_across(&name.region, &ann.region);
match scope.introduce( match scope.introduce(

View file

@ -56,8 +56,8 @@ pub enum Expr {
Num(Variable, i64), Num(Variable, i64),
// Int and Float store a variable to generate better error messages // Int and Float store a variable to generate better error messages
Int(Variable, i64), Int(Variable, Variable, i64),
Float(Variable, f64), Float(Variable, Variable, f64),
Str(InlinableString), Str(InlinableString),
List { List {
list_var: Variable, // required for uniqueness of the list list_var: Variable, // required for uniqueness of the list
@ -1168,8 +1168,8 @@ pub fn inline_calls(var_store: &mut VarStore, scope: &mut Scope, expr: 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
other @ Num(_, _) other @ Num(_, _)
| other @ Int(_, _) | other @ Int(_, _, _)
| other @ Float(_, _) | other @ Float(_, _, _)
| other @ Str { .. } | other @ Str { .. }
| other @ RuntimeError(_) | other @ RuntimeError(_)
| other @ EmptyRecord | other @ EmptyRecord

View file

@ -363,8 +363,8 @@ fn fix_values_captured_in_closure_pattern(
} }
Identifier(_) Identifier(_)
| NumLiteral(_, _) | NumLiteral(_, _)
| IntLiteral(_) | IntLiteral(_, _)
| FloatLiteral(_) | FloatLiteral(_, _)
| StrLiteral(_) | StrLiteral(_)
| Underscore | Underscore
| Shadowed(_, _) | Shadowed(_, _)
@ -414,8 +414,8 @@ fn fix_values_captured_in_closure_expr(
} }
Num(_, _) Num(_, _)
| Int(_, _) | Int(_, _, _)
| Float(_, _) | Float(_, _, _)
| Str(_) | Str(_)
| Var(_) | Var(_)
| EmptyRecord | EmptyRecord

View file

@ -45,7 +45,7 @@ pub fn int_expr_from_result(
) -> Expr { ) -> Expr {
// Int stores a variable to generate better error messages // Int stores a variable to generate better error messages
match result { match result {
Ok(int) => Expr::Int(var_store.fresh(), int), Ok(int) => Expr::Int(var_store.fresh(), var_store.fresh(), int),
Err((raw, error)) => { Err((raw, error)) => {
let runtime_error = InvalidInt(error, base, region, raw.into()); let runtime_error = InvalidInt(error, base, region, raw.into());
@ -65,7 +65,7 @@ pub fn float_expr_from_result(
) -> Expr { ) -> Expr {
// Float stores a variable to generate better error messages // Float stores a variable to generate better error messages
match result { match result {
Ok(float) => Expr::Float(var_store.fresh(), float), Ok(float) => Expr::Float(var_store.fresh(), var_store.fresh(), float),
Err((raw, error)) => { Err((raw, error)) => {
let runtime_error = InvalidFloat(error, region, raw.into()); let runtime_error = InvalidFloat(error, region, raw.into());

View file

@ -25,9 +25,9 @@ pub enum Pattern {
ext_var: Variable, ext_var: Variable,
destructs: Vec<Located<RecordDestruct>>, destructs: Vec<Located<RecordDestruct>>,
}, },
IntLiteral(i64), IntLiteral(Variable, i64),
NumLiteral(Variable, i64), NumLiteral(Variable, i64),
FloatLiteral(f64), FloatLiteral(Variable, f64),
StrLiteral(Box<str>), StrLiteral(Box<str>),
Underscore, Underscore,
@ -86,8 +86,8 @@ pub fn symbols_from_pattern_help(pattern: &Pattern, symbols: &mut Vec<Symbol>) {
} }
NumLiteral(_, _) NumLiteral(_, _)
| IntLiteral(_) | IntLiteral(_, _)
| FloatLiteral(_) | FloatLiteral(_, _)
| StrLiteral(_) | StrLiteral(_)
| Underscore | Underscore
| MalformedPattern(_, _) | MalformedPattern(_, _)
@ -191,7 +191,7 @@ pub fn canonicalize_pattern<'a>(
let problem = MalformedPatternProblem::MalformedFloat; let problem = MalformedPatternProblem::MalformedFloat;
malformed_pattern(env, problem, region) malformed_pattern(env, problem, region)
} }
Ok(float) => Pattern::FloatLiteral(float), Ok(float) => Pattern::FloatLiteral(var_store.fresh(), float),
}, },
ptype => unsupported_pattern(env, ptype, region), ptype => unsupported_pattern(env, ptype, region),
}, },
@ -224,9 +224,9 @@ pub fn canonicalize_pattern<'a>(
} }
Ok(int) => { Ok(int) => {
if *is_negative { if *is_negative {
Pattern::IntLiteral(-int) Pattern::IntLiteral(var_store.fresh(), -int)
} else { } else {
Pattern::IntLiteral(int) Pattern::IntLiteral(var_store.fresh(), int)
} }
} }
}, },
@ -455,8 +455,8 @@ fn add_bindings_from_patterns(
} }
} }
NumLiteral(_, _) NumLiteral(_, _)
| IntLiteral(_) | IntLiteral(_, _)
| FloatLiteral(_) | FloatLiteral(_, _)
| StrLiteral(_) | StrLiteral(_)
| Underscore | Underscore
| Shadowed(_, _) | Shadowed(_, _)

View file

@ -32,7 +32,7 @@ mod test_can {
let actual_out = can_expr_with(&arena, test_home(), input); let actual_out = can_expr_with(&arena, test_home(), input);
match actual_out.loc_expr.value { match actual_out.loc_expr.value {
Expr::Float(_, actual) => { Expr::Float(_, _, actual) => {
assert_eq!(expected, actual); assert_eq!(expected, actual);
} }
actual => { actual => {
@ -46,11 +46,11 @@ mod test_can {
let actual_out = can_expr_with(&arena, test_home(), input); let actual_out = can_expr_with(&arena, test_home(), input);
match actual_out.loc_expr.value { match actual_out.loc_expr.value {
Expr::Int(_, actual) => { Expr::Int(_, _, actual) => {
assert_eq!(expected, actual); assert_eq!(expected, actual);
} }
actual => { actual => {
panic!("Expected an I64, but got: {:?}", actual); panic!("Expected an Int *, but got: {:?}", actual);
} }
} }
} }
@ -249,7 +249,7 @@ mod test_can {
fn correct_annotated_body() { fn correct_annotated_body() {
let src = indoc!( let src = indoc!(
r#" r#"
f : I64 -> I64 f : Int * -> Int *
f = \ a -> a f = \ a -> a
f f
@ -265,7 +265,7 @@ mod test_can {
fn correct_annotated_body_with_comments() { fn correct_annotated_body_with_comments() {
let src = indoc!( let src = indoc!(
r#" r#"
f : I64 -> I64 # comment f : Int * -> Int * # comment
f = \ a -> a f = \ a -> a
f f
@ -281,7 +281,7 @@ mod test_can {
fn name_mismatch_annotated_body() { fn name_mismatch_annotated_body() {
let src = indoc!( let src = indoc!(
r#" r#"
f : I64 -> I64 f : Int * -> Int *
g = \ a -> a g = \ a -> a
g g
@ -307,7 +307,7 @@ mod test_can {
fn name_mismatch_annotated_body_with_comment() { fn name_mismatch_annotated_body_with_comment() {
let src = indoc!( let src = indoc!(
r#" r#"
f : I64 -> I64 # comment f : Int * -> Int * # comment
g = \ a -> a g = \ a -> a
g g
@ -333,7 +333,7 @@ mod test_can {
fn separated_annotated_body() { fn separated_annotated_body() {
let src = indoc!( let src = indoc!(
r#" r#"
f : I64 -> I64 f : Int * -> Int *
f = \ a -> a f = \ a -> a
@ -354,7 +354,7 @@ mod test_can {
fn separated_annotated_body_with_comment() { fn separated_annotated_body_with_comment() {
let src = indoc!( let src = indoc!(
r#" r#"
f : I64 -> I64 f : Int * -> Int *
# comment # comment
f = \ a -> a f = \ a -> a
@ -375,9 +375,9 @@ mod test_can {
fn shadowed_annotation() { fn shadowed_annotation() {
let src = indoc!( let src = indoc!(
r#" r#"
f : I64 -> I64 f : Int * -> Int *
f : I64 -> I64 f : Int * -> Int *
f f
"# "#
@ -397,7 +397,7 @@ mod test_can {
fn correct_nested_unannotated_body() { fn correct_nested_unannotated_body() {
let src = indoc!( let src = indoc!(
r#" r#"
f : I64 f : Int *
f = f =
g = 42 g = 42
@ -416,9 +416,9 @@ mod test_can {
fn correct_nested_annotated_body() { fn correct_nested_annotated_body() {
let src = indoc!( let src = indoc!(
r#" r#"
f : I64 f : Int *
f = f =
g : I64 g : Int *
g = 42 g = 42
g + 1 g + 1
@ -436,11 +436,11 @@ mod test_can {
fn correct_nested_body_annotated_multiple_lines() { fn correct_nested_body_annotated_multiple_lines() {
let src = indoc!( let src = indoc!(
r#" r#"
f : I64 f : Int *
f = f =
g : I64 g : Int *
g = 42 g = 42
h : I64 h : Int *
h = 5 h = 5
z = 4 z = 4
g + h + z g + h + z
@ -458,10 +458,10 @@ mod test_can {
fn correct_nested_body_unannotated_multiple_lines() { fn correct_nested_body_unannotated_multiple_lines() {
let src = indoc!( let src = indoc!(
r#" r#"
f : I64 f : Int *
f = f =
g = 42 g = 42
h : I64 h : Int *
h = 5 h = 5
z = 4 z = 4
g + h + z g + h + z
@ -478,7 +478,7 @@ mod test_can {
fn correct_double_nested_body() { fn correct_double_nested_body() {
let src = indoc!( let src = indoc!(
r#" r#"
f : I64 f : Int *
f = f =
g = g =
h = 42 h = 42
@ -499,7 +499,7 @@ mod test_can {
fn annotation_followed_with_unrelated_affectation() { fn annotation_followed_with_unrelated_affectation() {
let src = indoc!( let src = indoc!(
r#" r#"
F : I64 F : Int *
x = 1 x = 1
@ -520,9 +520,9 @@ mod test_can {
fn two_annotations_followed_with_unrelated_affectation() { fn two_annotations_followed_with_unrelated_affectation() {
let src = indoc!( let src = indoc!(
r#" r#"
G : I64 G : Int *
F : I64 F : Int *
x = 1 x = 1

View file

@ -11,30 +11,48 @@ use roc_types::types::Reason;
use roc_types::types::Type::{self, *}; use roc_types::types::Type::{self, *};
#[inline(always)] #[inline(always)]
pub fn int_literal(num_var: Variable, expected: Expected<Type>, region: Region) -> Constraint { pub fn int_literal(
num_var: Variable,
percision_var: Variable,
expected: Expected<Type>,
region: Region,
) -> Constraint {
let num_type = Variable(num_var); let num_type = Variable(num_var);
let reason = Reason::IntLiteral; let reason = Reason::IntLiteral;
let expected_literal = ForReason(reason, num_int(), region);
exists( exists(
vec![num_var], vec![num_var],
And(vec![ And(vec![
Eq(num_type.clone(), expected_literal, Category::Int, region), Eq(
num_type.clone(),
ForReason(reason, num_int(Type::Variable(percision_var)), region),
Category::Int,
region,
),
Eq(num_type, expected, Category::Int, region), Eq(num_type, expected, Category::Int, region),
]), ]),
) )
} }
#[inline(always)] #[inline(always)]
pub fn float_literal(num_var: Variable, expected: Expected<Type>, region: Region) -> Constraint { pub fn float_literal(
num_var: Variable,
percision_var: Variable,
expected: Expected<Type>,
region: Region,
) -> Constraint {
let num_type = Variable(num_var); let num_type = Variable(num_var);
let reason = Reason::FloatLiteral; let reason = Reason::FloatLiteral;
let expected_literal = ForReason(reason, num_float(), region);
exists( exists(
vec![num_var], vec![num_var],
And(vec![ And(vec![
Eq(num_type.clone(), expected_literal, Category::Float, region), Eq(
num_type.clone(),
ForReason(reason, num_float(Type::Variable(percision_var)), region),
Category::Float,
region,
),
Eq(num_type, expected, Category::Float, region), Eq(num_type, expected, Category::Float, region),
]), ]),
) )
@ -72,11 +90,11 @@ pub fn str_type() -> Type {
} }
#[inline(always)] #[inline(always)]
pub fn num_float() -> Type { pub fn num_float(range: Type) -> Type {
Type::Alias( Type::Alias(
Symbol::NUM_F64, Symbol::NUM_FLOAT,
vec![], vec![("range".into(), range.clone())],
Box::new(num_num(num_floatingpoint(num_binary64()))), Box::new(num_num(num_floatingpoint(range))),
) )
} }
@ -108,11 +126,11 @@ pub fn num_binary64() -> Type {
} }
#[inline(always)] #[inline(always)]
pub fn num_int() -> Type { pub fn num_int(range: Type) -> Type {
Type::Alias( Type::Alias(
Symbol::NUM_I64, Symbol::NUM_INT,
vec![], vec![("range".into(), range.clone())],
Box::new(num_num(num_integer(num_signed64()))), Box::new(num_num(num_integer(range))),
) )
} }

View file

@ -96,7 +96,7 @@ pub fn constrain_expr(
expected: Expected<Type>, expected: Expected<Type>,
) -> Constraint { ) -> Constraint {
match expr { match expr {
Int(var, _) => int_literal(*var, expected, region), Int(var, percision, _) => int_literal(*var, *percision, expected, region),
Num(var, _) => exists( Num(var, _) => exists(
vec![*var], vec![*var],
Eq( Eq(
@ -106,7 +106,7 @@ pub fn constrain_expr(
region, region,
), ),
), ),
Float(var, _) => float_literal(*var, expected, region), Float(var, percision, _) => float_literal(*var, *percision, expected, region),
EmptyRecord => constrain_empty_record(region, expected), EmptyRecord => constrain_empty_record(region, expected),
Expr::Record { record_var, fields } => { Expr::Record { record_var, fields } => {
if fields.is_empty() { if fields.is_empty() {

View file

@ -57,8 +57,8 @@ fn headers_from_annotation_help(
| MalformedPattern(_, _) | MalformedPattern(_, _)
| UnsupportedPattern(_) | UnsupportedPattern(_)
| NumLiteral(_, _) | NumLiteral(_, _)
| IntLiteral(_) | IntLiteral(_, _)
| FloatLiteral(_) | FloatLiteral(_, _)
| StrLiteral(_) => true, | StrLiteral(_) => true,
RecordDestructure { destructs, .. } => match annotation.value.shallow_dealias() { RecordDestructure { destructs, .. } => match annotation.value.shallow_dealias() {
@ -154,20 +154,20 @@ pub fn constrain_pattern(
)); ));
} }
IntLiteral(_) => { IntLiteral(precision_var, _) => {
state.constraints.push(Constraint::Pattern( state.constraints.push(Constraint::Pattern(
region, region,
PatternCategory::Int, PatternCategory::Int,
builtins::num_int(), builtins::num_int(Type::Variable(*precision_var)),
expected, expected,
)); ));
} }
FloatLiteral(_) => { FloatLiteral(precision_var, _) => {
state.constraints.push(Constraint::Pattern( state.constraints.push(Constraint::Pattern(
region, region,
PatternCategory::Float, PatternCategory::Float,
builtins::num_float(), builtins::num_float(Type::Variable(*precision_var)),
expected, expected,
)); ));
} }

View file

@ -1,4 +1,4 @@
use crate::builtins::{num_binary64, num_floatingpoint, num_integer, num_num, num_signed64}; use crate::builtins::{num_floatingpoint, num_integer, num_num};
use crate::expr::{exists, Info}; use crate::expr::{exists, Info};
use roc_can::annotation::IntroducedVariables; use roc_can::annotation::IntroducedVariables;
use roc_can::constraint::Constraint::{self, *}; use roc_can::constraint::Constraint::{self, *};
@ -173,18 +173,19 @@ fn constrain_pattern(
)); ));
} }
IntLiteral(_) => { IntLiteral(inner_var, _) => {
let (a, b, c, num_type) = unique_int(var_store); let (a, b, c, num_type) = unique_int(var_store);
state.constraints.push(exists( state.constraints.push(exists(
vec![a, b, c], vec![*inner_var, a, b, c],
Constraint::Pattern(pattern.region, PatternCategory::Int, num_type, expected), Constraint::Pattern(pattern.region, PatternCategory::Int, num_type, expected),
)); ));
} }
FloatLiteral(_) => { FloatLiteral(inner_var, _) => {
let (a, b, c, num_type) = unique_float(var_store); let (a, b, c, num_type) = unique_float(var_store);
state.constraints.push(exists( state.constraints.push(exists(
vec![a, b, c], vec![*inner_var, a, b, c],
Constraint::Pattern(pattern.region, PatternCategory::Float, num_type, expected), Constraint::Pattern(pattern.region, PatternCategory::Float, num_type, expected),
)); ));
} }
@ -423,10 +424,9 @@ fn unique_int(var_store: &mut VarStore) -> (Variable, Variable, Variable, Type)
let num_uvar1 = var_store.fresh(); let num_uvar1 = var_store.fresh();
let num_uvar2 = var_store.fresh(); let num_uvar2 = var_store.fresh();
let num_uvar3 = var_store.fresh(); let num_uvar3 = var_store.fresh();
let num_uvar4 = var_store.fresh();
let signed_64 = num_signed64(); let integer = num_integer(Type::Variable(num_uvar4));
let attr_signed_64 = attr_type(Bool::variable(num_uvar1), signed_64);
let integer = num_integer(attr_signed_64);
let attr_int = attr_type(Bool::variable(num_uvar2), integer); let attr_int = attr_type(Bool::variable(num_uvar2), integer);
let num = num_num(attr_int); let num = num_num(attr_int);
let attr_num = attr_type(Bool::variable(num_uvar3), num); let attr_num = attr_type(Bool::variable(num_uvar3), num);
@ -438,10 +438,9 @@ fn unique_float(var_store: &mut VarStore) -> (Variable, Variable, Variable, Type
let num_uvar1 = var_store.fresh(); let num_uvar1 = var_store.fresh();
let num_uvar2 = var_store.fresh(); let num_uvar2 = var_store.fresh();
let num_uvar3 = var_store.fresh(); let num_uvar3 = var_store.fresh();
let num_uvar4 = var_store.fresh();
let binary_64 = num_binary64(); let fp = num_floatingpoint(Type::Variable(num_uvar4));
let attr_binary_64 = attr_type(Bool::variable(num_uvar1), binary_64);
let fp = num_floatingpoint(attr_binary_64);
let attr_fp = attr_type(Bool::variable(num_uvar2), fp); let attr_fp = attr_type(Bool::variable(num_uvar2), fp);
let num = num_num(attr_fp); let num = num_num(attr_fp);
let attr_num = attr_type(Bool::variable(num_uvar3), num); let attr_num = attr_type(Bool::variable(num_uvar3), num);
@ -478,7 +477,7 @@ pub fn constrain_expr(
]), ]),
) )
} }
Int(var, _) => { Int(var, _, _) => {
let (a, b, c, num_type) = unique_int(var_store); let (a, b, c, num_type) = unique_int(var_store);
exists( exists(
@ -494,7 +493,7 @@ pub fn constrain_expr(
]), ]),
) )
} }
Float(var, _) => { Float(var, _, _) => {
let (a, b, c, num_type) = unique_float(var_store); let (a, b, c, num_type) = unique_float(var_store);
exists( exists(
@ -532,7 +531,9 @@ pub fn constrain_expr(
), ),
) )
} }
Record { record_var, fields } => { Record {
record_var, fields, ..
} => {
// NOTE: canonicalization guarantees at least one field // NOTE: canonicalization guarantees at least one field
// zero fields generates an EmptyRecord // zero fields generates an EmptyRecord
let mut field_types = SendMap::default(); let mut field_types = SendMap::default();

View file

@ -762,8 +762,8 @@ mod test_fmt {
expr_formats_to( expr_formats_to(
indoc!( indoc!(
r#" r#"
f: { y : I64, f: { y : Int *,
x : I64 , x : Int * ,
} }
f"# f"#
@ -772,8 +772,8 @@ mod test_fmt {
r#" r#"
f : f :
{ {
y : I64, y : Int *,
x : I64, x : Int *,
} }
f"# f"#
@ -787,8 +787,8 @@ mod test_fmt {
r#" r#"
f : f :
{ {
y : I64, y : Int *,
x : I64, x : Int *,
} }
f"# f"#
@ -800,7 +800,7 @@ mod test_fmt {
expr_formats_same(indoc!( expr_formats_same(indoc!(
r#" r#"
f : f :
I64 Int *
f"# f"#
)); ));
@ -880,7 +880,7 @@ mod test_fmt {
r#" r#"
f : f :
{ {
x: I64 # comment 1 x: Int * # comment 1
, ,
# comment 2 # comment 2
} }
@ -891,7 +891,7 @@ mod test_fmt {
r#" r#"
f : f :
{ {
x : I64, x : Int *,
# comment 1 # comment 1
# comment 2 # comment 2
} }
@ -2557,7 +2557,7 @@ mod test_fmt {
fn record_type() { fn record_type() {
expr_formats_same(indoc!( expr_formats_same(indoc!(
r#" r#"
f : { foo : I64 } f : { foo : Int * }
f = { foo: 1000 } f = { foo: 1000 }
a a
@ -2608,11 +2608,11 @@ mod test_fmt {
// r#" // r#"
// f : // f :
// Result a // Result a
// { x : I64 // { x : Int *
// , y : Float // , y : Float
// } // }
// c // c
// -> I64 // -> Int *
// f = // f =
// \_ -> 4 // \_ -> 4
// "# // "#

View file

@ -486,13 +486,28 @@ fn get_inplace_from_layout(layout: &Layout<'_>) -> InPlace {
pub fn build_exp_literal<'a, 'ctx, 'env>( pub fn build_exp_literal<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>, env: &Env<'a, 'ctx, 'env>,
layout: &Layout<'_>,
literal: &roc_mono::ir::Literal<'a>, literal: &roc_mono::ir::Literal<'a>,
) -> BasicValueEnum<'ctx> { ) -> BasicValueEnum<'ctx> {
use roc_mono::ir::Literal::*; use roc_mono::ir::Literal::*;
match literal { match literal {
Int(num) => env.context.i64_type().const_int(*num as u64, true).into(), Int(int) =>
Float(num) => env.context.f64_type().const_float(*num).into(), (match layout {
Layout::Builtin(Builtin::Usize) => ptr_int(env.context, env.ptr_bytes),
Layout::Builtin(Builtin::Int128) => env.context.i128_type(), /* TODO file an issue: you can't currently have an int literal bigger than 64 bits long, and also (as we see here), you can't currently have (at least in Inkwell) a when-branch with an i128 literal in its pattren */
Layout::Builtin(Builtin::Int64) => env.context.i64_type(),
Layout::Builtin(Builtin::Int32) => env.context.i32_type(),
Layout::Builtin(Builtin::Int16) => env.context.i16_type(),
Layout::Builtin(Builtin::Int8) => env.context.i8_type(),
_ => panic!("Invalid layout for int literal = {:?}", layout),
}).const_int(*int as u64, false).into(),
Float(num) =>
(match layout {
Layout::Builtin(Builtin::Float64) => env.context.f64_type(),
Layout::Builtin(Builtin::Float32) => env.context.f32_type(),
_ => panic!("Invalid layout for float literal = {:?}", layout),
}).const_float(*num).into(),
Bool(b) => env.context.bool_type().const_int(*b as u64, false).into(), Bool(b) => env.context.bool_type().const_int(*b as u64, false).into(),
Byte(b) => env.context.i8_type().const_int(*b as u64, false).into(), Byte(b) => env.context.i8_type().const_int(*b as u64, false).into(),
Str(str_literal) => { Str(str_literal) => {
@ -774,7 +789,7 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
use roc_mono::ir::Expr::*; use roc_mono::ir::Expr::*;
match expr { match expr {
Literal(literal) => build_exp_literal(env, literal), Literal(literal) => build_exp_literal(env, layout, literal),
Call(call) => build_exp_call(env, layout_ids, scope, parent, layout, call), Call(call) => build_exp_call(env, layout_ids, scope, parent, layout, call),
@ -1805,6 +1820,15 @@ fn build_switch_ir<'a, 'ctx, 'env>(
.build_bitcast(full_cond, env.context.i64_type(), "") .build_bitcast(full_cond, env.context.i64_type(), "")
.into_int_value() .into_int_value()
} }
Layout::Builtin(Builtin::Float32) => {
// float matches are done on the bit pattern
cond_layout = Layout::Builtin(Builtin::Int32);
let full_cond = load_symbol(env, scope, cond_symbol);
builder
.build_bitcast(full_cond, env.context.i32_type(), "")
.into_int_value()
}
Layout::Union(_) => { Layout::Union(_) => {
// we match on the discriminant, not the whole Tag // we match on the discriminant, not the whole Tag
cond_layout = Layout::Builtin(Builtin::Int64); cond_layout = Layout::Builtin(Builtin::Int64);
@ -1832,8 +1856,11 @@ fn build_switch_ir<'a, 'ctx, 'env>(
// //
// they either need to all be i8, or i64 // they either need to all be i8, or i64
let int_val = match cond_layout { let int_val = match cond_layout {
Layout::Builtin(Builtin::Int128) => context.i128_type().const_int(*int as u64, false), /* TODO file an issue: you can't currently have an int literal bigger than 64 bits long, and also (as we see here), you can't currently have (at least in Inkwell) a when-branch with an i128 literal in its pattren */ Layout::Builtin(Builtin::Usize) => {
ptr_int(env.context, env.ptr_bytes).const_int(*int as u64, false)
}
Layout::Builtin(Builtin::Int64) => context.i64_type().const_int(*int as u64, false), Layout::Builtin(Builtin::Int64) => context.i64_type().const_int(*int as u64, false),
Layout::Builtin(Builtin::Int128) => context.i128_type().const_int(*int as u64, false), /* TODO file an issue: you can't currently have an int literal bigger than 64 bits long, and also (as we see here), you can't currently have (at least in Inkwell) a when-branch with an i128 literal in its pattren */
Layout::Builtin(Builtin::Int32) => context.i32_type().const_int(*int as u64, false), Layout::Builtin(Builtin::Int32) => context.i32_type().const_int(*int as u64, false),
Layout::Builtin(Builtin::Int16) => context.i16_type().const_int(*int as u64, false), Layout::Builtin(Builtin::Int16) => context.i16_type().const_int(*int as u64, false),
Layout::Builtin(Builtin::Int8) => context.i8_type().const_int(*int as u64, false), Layout::Builtin(Builtin::Int8) => context.i8_type().const_int(*int as u64, false),
@ -3053,7 +3080,7 @@ fn run_low_level<'a, 'ctx, 'env>(
use roc_mono::layout::Builtin::*; use roc_mono::layout::Builtin::*;
match arg_builtin { match arg_builtin {
Int128 | Int64 | Int32 | Int16 | Int8 => { Usize | Int128 | Int64 | Int32 | Int16 | Int8 => {
build_int_unary_op(env, arg.into_int_value(), arg_builtin, op) build_int_unary_op(env, arg.into_int_value(), arg_builtin, op)
} }
Float128 | Float64 | Float32 | Float16 => { Float128 | Float64 | Float32 | Float16 => {
@ -3091,7 +3118,7 @@ fn run_low_level<'a, 'ctx, 'env>(
let tag_lt = env.context.i8_type().const_int(2_u64, false); let tag_lt = env.context.i8_type().const_int(2_u64, false);
match lhs_builtin { match lhs_builtin {
Int128 | Int64 | Int32 | Int16 | Int8 => { Usize | Int128 | Int64 | Int32 | Int16 | Int8 => {
let are_equal = env.builder.build_int_compare( let are_equal = env.builder.build_int_compare(
IntPredicate::EQ, IntPredicate::EQ,
lhs_arg.into_int_value(), lhs_arg.into_int_value(),
@ -3515,7 +3542,7 @@ pub fn build_num_binop<'a, 'ctx, 'env>(
use roc_mono::layout::Builtin::*; use roc_mono::layout::Builtin::*;
match lhs_builtin { match lhs_builtin {
Int128 | Int64 | Int32 | Int16 | Int8 => build_int_binop( Usize | Int128 | Int64 | Int32 | Int16 | Int8 => build_int_binop(
env, env,
parent, parent,
lhs_arg.into_int_value(), lhs_arg.into_int_value(),
@ -3766,6 +3793,7 @@ fn build_int_unary_op<'a, 'ctx, 'env>(
int_abs_raise_on_overflow(env, arg, arg_layout) int_abs_raise_on_overflow(env, arg, arg_layout)
} }
NumToFloat => { NumToFloat => {
// TODO: Handle differnt sized numbers
// This is an Int, so we need to convert it. // This is an Int, so we need to convert it.
bd.build_cast( bd.build_cast(
InstructionOpcode::SIToFP, InstructionOpcode::SIToFP,
@ -3892,6 +3920,7 @@ fn build_float_unary_op<'a, 'ctx, 'env>(
let bd = env.builder; let bd = env.builder;
// TODO: Handle differnt sized floats
match op { match op {
NumNeg => bd.build_float_neg(arg, "negate_float").into(), NumNeg => bd.build_float_neg(arg, "negate_float").into(),
NumAbs => env.call_intrinsic(LLVM_FABS_F64, &[arg.into()]), NumAbs => env.call_intrinsic(LLVM_FABS_F64, &[arg.into()]),

View file

@ -165,6 +165,7 @@ pub fn basic_type_from_builtin<'ctx>(
Int16 => context.i16_type().as_basic_type_enum(), Int16 => context.i16_type().as_basic_type_enum(),
Int8 => context.i8_type().as_basic_type_enum(), Int8 => context.i8_type().as_basic_type_enum(),
Int1 => context.bool_type().as_basic_type_enum(), Int1 => context.bool_type().as_basic_type_enum(),
Usize => ptr_int(context, ptr_bytes).as_basic_type_enum(),
Float128 => context.f128_type().as_basic_type_enum(), Float128 => context.f128_type().as_basic_type_enum(),
Float64 => context.f64_type().as_basic_type_enum(), Float64 => context.f64_type().as_basic_type_enum(),
Float32 => context.f32_type().as_basic_type_enum(), Float32 => context.f32_type().as_basic_type_enum(),

View file

@ -1273,7 +1273,7 @@ mod gen_list {
app "quicksort" provides [ main ] to "./platform" app "quicksort" provides [ main ] to "./platform"
swap : I64, I64, List a -> List a swap : Int *, Int *, List a -> List a
swap = \i, j, list -> swap = \i, j, list ->
when Pair (List.get list i) (List.get list j) is when Pair (List.get list i) (List.get list j) is
Pair (Ok atI) (Ok atJ) -> Pair (Ok atI) (Ok atJ) ->
@ -1396,7 +1396,7 @@ mod gen_list {
quicksortHelp list 0 (n - 1) quicksortHelp list 0 (n - 1)
quicksortHelp : List (Num a), I64, I64 -> List (Num a) quicksortHelp : List (Num a), Int *, Int * -> List (Num a)
quicksortHelp = \list, low, high -> quicksortHelp = \list, low, high ->
if low < high then if low < high then
when partition low high list is when partition low high list is
@ -1408,7 +1408,7 @@ mod gen_list {
list list
swap : I64, I64, List a -> List a swap : Int *, Int *, List a -> List a
swap = \i, j, list -> swap = \i, j, list ->
when Pair (List.get list i) (List.get list j) is when Pair (List.get list i) (List.get list j) is
Pair (Ok atI) (Ok atJ) -> Pair (Ok atI) (Ok atJ) ->
@ -1419,7 +1419,7 @@ mod gen_list {
_ -> _ ->
[] []
partition : I64, I64, List (Num a) -> [ Pair I64 (List (Num a)) ] partition : Int *, Int *, List (Num a) -> [ Pair (Int *) (List (Num a)) ]
partition = \low, high, initialList -> partition = \low, high, initialList ->
when List.get initialList high is when List.get initialList high is
Ok pivot -> Ok pivot ->
@ -1431,7 +1431,7 @@ mod gen_list {
Pair (low - 1) initialList Pair (low - 1) initialList
partitionHelp : I64, I64, List (Num a), I64, (Num a) -> [ Pair I64 (List (Num a)) ] partitionHelp : Int *, Int *, List (Num a), Int *, (Num a) -> [ Pair (Int *) (List (Num a)) ]
partitionHelp = \i, j, list, high, pivot -> partitionHelp = \i, j, list, high, pivot ->
if j < high then if j < high then
when List.get list j is when List.get list j is
@ -1466,7 +1466,7 @@ mod gen_list {
quicksortHelp list 0 (List.len list - 1) quicksortHelp list 0 (List.len list - 1)
quicksortHelp : List (Num a), I64, I64 -> List (Num a) quicksortHelp : List (Num a), Int *, Int * -> List (Num a)
quicksortHelp = \list, low, high -> quicksortHelp = \list, low, high ->
if low < high then if low < high then
when partition low high list is when partition low high list is
@ -1478,7 +1478,7 @@ mod gen_list {
list list
swap : I64, I64, List a -> List a swap : Int *, Int *, List a -> List a
swap = \i, j, list -> swap = \i, j, list ->
when Pair (List.get list i) (List.get list j) is when Pair (List.get list i) (List.get list j) is
Pair (Ok atI) (Ok atJ) -> Pair (Ok atI) (Ok atJ) ->
@ -1489,7 +1489,7 @@ mod gen_list {
_ -> _ ->
[] []
partition : I64, I64, List (Num a) -> [ Pair I64 (List (Num a)) ] partition : Int *, Int *, List (Num a) -> [ Pair (Int *) (List (Num a)) ]
partition = \low, high, initialList -> partition = \low, high, initialList ->
when List.get initialList high is when List.get initialList high is
Ok pivot -> Ok pivot ->
@ -1501,7 +1501,7 @@ mod gen_list {
Pair (low - 1) initialList Pair (low - 1) initialList
partitionHelp : I64, I64, List (Num a), I64, Num a -> [ Pair I64 (List (Num a)) ] partitionHelp : Int *, Int *, List (Num a), Int *, Num a -> [ Pair (Int *) (List (Num a)) ]
partitionHelp = \i, j, list, high, pivot -> partitionHelp = \i, j, list, high, pivot ->
# if j < high then # if j < high then
if False then if False then
@ -1539,7 +1539,7 @@ mod gen_list {
quicksortHelp list 0 (List.len list - 1) quicksortHelp list 0 (List.len list - 1)
quicksortHelp : List (Num a), I64, I64 -> List (Num a) quicksortHelp : List (Num a), Int *, Int * -> List (Num a)
quicksortHelp = \list, low, high -> quicksortHelp = \list, low, high ->
if low < high then if low < high then
when partition low high list is when partition low high list is
@ -1551,7 +1551,7 @@ mod gen_list {
list list
swap : I64, I64, List a -> List a swap : Int *, Int *, List a -> List a
swap = \i, j, list -> swap = \i, j, list ->
when Pair (List.get list i) (List.get list j) is when Pair (List.get list i) (List.get list j) is
Pair (Ok atI) (Ok atJ) -> Pair (Ok atI) (Ok atJ) ->
@ -1562,7 +1562,7 @@ mod gen_list {
_ -> _ ->
[] []
partition : I64, I64, List (Num a) -> [ Pair I64 (List (Num a)) ] partition : Int *, Int *, List (Num a) -> [ Pair (Int *) (List (Num a)) ]
partition = \low, high, initialList -> partition = \low, high, initialList ->
when List.get initialList high is when List.get initialList high is
Ok pivot -> Ok pivot ->
@ -1574,7 +1574,7 @@ mod gen_list {
Pair (low - 1) initialList Pair (low - 1) initialList
partitionHelp : I64, I64, List (Num a), I64, Num a -> [ Pair I64 (List (Num a)) ] partitionHelp : Int *, Int *, List (Num a), Int *, Num a -> [ Pair (Int *) (List (Num a)) ]
partitionHelp = \i, j, list, high, pivot -> partitionHelp = \i, j, list, high, pivot ->
if j < high then if j < high then
when List.get list j is when List.get list j is

View file

@ -15,6 +15,357 @@ mod helpers;
mod gen_num { mod gen_num {
use roc_std::RocOrder; use roc_std::RocOrder;
#[test]
fn nat_alias() {
assert_evals_to!(
indoc!(
r#"
i : Nat
i = 1
i
"#
),
1,
usize
);
}
#[test]
fn i128_signed_int_alias() {
assert_evals_to!(
indoc!(
r#"
i : I128
i = 128
i
"#
),
128,
i128
);
}
#[test]
fn i64_signed_int_alias() {
assert_evals_to!(
indoc!(
r#"
i : I64
i = 64
i
"#
),
64,
i64
);
}
#[test]
fn i32_signed_int_alias() {
assert_evals_to!(
indoc!(
r#"
i : I32
i = 32
i
"#
),
32,
i32
);
}
#[test]
fn i16_signed_int_alias() {
assert_evals_to!(
indoc!(
r#"
i : I16
i = 16
i
"#
),
16,
i16
);
}
#[test]
fn i8_signed_int_alias() {
assert_evals_to!(
indoc!(
r#"
i : I8
i = 8
i
"#
),
8,
i8
);
}
#[test]
fn i128_hex_int_alias() {
assert_evals_to!(
indoc!(
r#"
f : I128
f = 0x123
f
"#
),
0x123,
i128
);
}
#[test]
fn i64_hex_int_alias() {
assert_evals_to!(
indoc!(
r#"
f : I64
f = 0x123
f
"#
),
0x123,
i64
);
}
#[test]
fn i32_hex_int_alias() {
assert_evals_to!(
indoc!(
r#"
f : I32
f = 0x123
f
"#
),
0x123,
i32
);
}
#[test]
fn i16_hex_int_alias() {
assert_evals_to!(
indoc!(
r#"
f : I16
f = 0x123
f
"#
),
0x123,
i16
);
}
#[test]
fn i8_hex_int_alias() {
assert_evals_to!(
indoc!(
r#"
f : I8
f = 0xA
f
"#
),
0xA,
i8
);
}
#[test]
fn u128_signed_int_alias() {
assert_evals_to!(
indoc!(
r#"
i : U128
i = 128
i
"#
),
128,
u128
);
}
#[test]
fn u64_signed_int_alias() {
assert_evals_to!(
indoc!(
r#"
i : U64
i = 64
i
"#
),
64,
u64
);
}
#[test]
fn u32_signed_int_alias() {
assert_evals_to!(
indoc!(
r#"
i : U32
i = 32
i
"#
),
32,
u32
);
}
#[test]
fn u16_signed_int_alias() {
assert_evals_to!(
indoc!(
r#"
i : U16
i = 16
i
"#
),
16,
u16
);
}
#[test]
fn u8_signed_int_alias() {
assert_evals_to!(
indoc!(
r#"
i : U8
i = 8
i
"#
),
8,
u8
);
}
#[test]
fn u128_hex_int_alias() {
assert_evals_to!(
indoc!(
r#"
f : U128
f = 0x123
f
"#
),
0x123,
i128
);
}
#[test]
fn u64_hex_int_alias() {
assert_evals_to!(
indoc!(
r#"
f : U64
f = 0x123
f
"#
),
0x123,
u64
);
}
#[test]
fn u32_hex_int_alias() {
assert_evals_to!(
indoc!(
r#"
f : U32
f = 0x123
f
"#
),
0x123,
u32
);
}
#[test]
fn u16_hex_int_alias() {
assert_evals_to!(
indoc!(
r#"
f : U16
f = 0x123
f
"#
),
0x123,
u16
);
}
#[test]
fn u8_hex_int_alias() {
assert_evals_to!(
indoc!(
r#"
f : U8
f = 0xA
f
"#
),
0xA,
u8
);
}
#[test]
fn f64_float_alias() {
assert_evals_to!(
indoc!(
r#"
f : F64
f = 3.6
f
"#
),
3.6,
f64
);
}
#[test]
fn f32_float_alias() {
assert_evals_to!(
indoc!(
r#"
f : F32
f = 3.6
f
"#
),
3.6,
f32
);
}
#[test] #[test]
fn f64_sqrt() { fn f64_sqrt() {
// FIXME this works with normal types, but fails when checking uniqueness types // FIXME this works with normal types, but fails when checking uniqueness types

View file

@ -135,7 +135,7 @@ mod gen_primitives {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r#"
x : [ Pair I64 I64 ] x : [ Pair (Int *) (Int *) ]
x = Pair 0x2 0x3 x = Pair 0x2 0x3
when x is when x is
@ -152,7 +152,7 @@ mod gen_primitives {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r#"
x : [A I64, B I64] x : [A (Int *), B (Int *)]
x = A 0x2 x = A 0x2
when x is when x is
@ -170,7 +170,7 @@ mod gen_primitives {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r#"
x : [A I64, B I64] x : [A (Int *), B (Int *)]
x = B 0x3 x = B 0x3
when x is when x is
@ -293,7 +293,7 @@ mod gen_primitives {
indoc!( indoc!(
r#" r#"
wrapper = \{} -> wrapper = \{} ->
alwaysFloatIdentity : I64 -> (F64 -> F64) alwaysFloatIdentity : Int * -> (Float * -> Float *)
alwaysFloatIdentity = \_ -> alwaysFloatIdentity = \_ ->
(\a -> a) (\a -> a)
@ -557,14 +557,14 @@ mod gen_primitives {
LinkedList a : [ Nil, Cons a (LinkedList a) ] LinkedList a : [ Nil, Cons a (LinkedList a) ]
len : LinkedList a -> I64 len : LinkedList a -> Int *
len = \list -> len = \list ->
when list is when list is
Nil -> 0 Nil -> 0
Cons _ rest -> 1 + len rest Cons _ rest -> 1 + len rest
main = main =
nil : LinkedList I64 nil : LinkedList (Int *)
nil = Nil nil = Nil
len nil len nil
@ -584,10 +584,10 @@ mod gen_primitives {
LinkedList a : [ Nil, Cons a (LinkedList a) ] LinkedList a : [ Nil, Cons a (LinkedList a) ]
nil : LinkedList I64 nil : LinkedList (Int *)
nil = Nil nil = Nil
length : LinkedList a -> I64 length : LinkedList a -> Int *
length = \list -> length = \list ->
when list is when list is
Nil -> 0 Nil -> 0
@ -611,10 +611,10 @@ mod gen_primitives {
LinkedList a : [ Nil, Cons a (LinkedList a) ] LinkedList a : [ Nil, Cons a (LinkedList a) ]
one : LinkedList I64 one : LinkedList (Int *)
one = Cons 1 Nil one = Cons 1 Nil
length : LinkedList a -> I64 length : LinkedList a -> Int *
length = \list -> length = \list ->
when list is when list is
Nil -> 0 Nil -> 0
@ -638,10 +638,10 @@ mod gen_primitives {
LinkedList a : [ Nil, Cons a (LinkedList a) ] LinkedList a : [ Nil, Cons a (LinkedList a) ]
one : LinkedList I64 one : LinkedList (Int *)
one = Cons 1 Nil one = Cons 1 Nil
length : LinkedList a -> I64 length : LinkedList a -> Int *
length = \list -> length = \list ->
when list is when list is
Nil -> 0 Nil -> 0
@ -665,10 +665,10 @@ mod gen_primitives {
LinkedList a : [ Nil, Cons a (LinkedList a) ] LinkedList a : [ Nil, Cons a (LinkedList a) ]
three : LinkedList I64 three : LinkedList (Int *)
three = Cons 3 (Cons 2 (Cons 1 Nil)) three = Cons 3 (Cons 2 (Cons 1 Nil))
length : LinkedList a -> I64 length : LinkedList a -> Int *
length = \list -> length = \list ->
when list is when list is
Nil -> 0 Nil -> 0
@ -693,7 +693,7 @@ mod gen_primitives {
LinkedList a : [ Nil, Cons a (LinkedList a) ] LinkedList a : [ Nil, Cons a (LinkedList a) ]
three : LinkedList I64 three : LinkedList (Int *)
three = Cons 3 (Cons 2 (Cons 1 Nil)) three = Cons 3 (Cons 2 (Cons 1 Nil))
@ -721,10 +721,10 @@ mod gen_primitives {
LinkedList a : [ Nil, Cons a (LinkedList a) ] LinkedList a : [ Nil, Cons a (LinkedList a) ]
zero : LinkedList I64 zero : LinkedList (Int *)
zero = Nil zero = Nil
sum : LinkedList I64 -> I64 sum : LinkedList (Int *) -> Int *
sum = \list -> sum = \list ->
when list is when list is
Nil -> 0 Nil -> 0
@ -748,7 +748,7 @@ mod gen_primitives {
LinkedList a : [ Nil, Cons a (LinkedList a) ] LinkedList a : [ Nil, Cons a (LinkedList a) ]
three : LinkedList I64 three : LinkedList (Int *)
three = Cons 3 (Cons 2 (Cons 1 Nil)) three = Cons 3 (Cons 2 (Cons 1 Nil))
sum : LinkedList (Num a) -> Num a sum : LinkedList (Num a) -> Num a
@ -779,7 +779,7 @@ mod gen_primitives {
r#" r#"
Maybe a : [ Nothing, Just a ] Maybe a : [ Nothing, Just a ]
x : Maybe (Maybe I64) x : Maybe (Maybe (Int *))
x = Just (Just 41) x = Just (Just 41)
when x is when x is
@ -796,7 +796,7 @@ mod gen_primitives {
r#" r#"
Maybe a : [ Nothing, Just a ] Maybe a : [ Nothing, Just a ]
x : Maybe (Maybe I64) x : Maybe (Maybe (Int *))
x = Just Nothing x = Just Nothing
when x is when x is
@ -814,7 +814,7 @@ mod gen_primitives {
r#" r#"
Maybe a : [ Nothing, Just a ] Maybe a : [ Nothing, Just a ]
x : Maybe (Maybe I64) x : Maybe (Maybe (Int *))
x = Nothing x = Nothing
when x is when x is
@ -908,7 +908,7 @@ mod gen_primitives {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r#"
foo : I64 foo : Int *
foo foo
@ -1033,11 +1033,11 @@ mod gen_primitives {
runEffect : Effect a -> a runEffect : Effect a -> a
runEffect = \@Effect thunk -> thunk {} runEffect = \@Effect thunk -> thunk {}
foo : Effect F64 foo : Effect (Float *)
foo = foo =
succeed 3.14 succeed 3.14
main : F64 main : Float *
main = main =
runEffect foo runEffect foo
@ -1058,14 +1058,14 @@ mod gen_primitives {
# succeed : a -> ({} -> a) # succeed : a -> ({} -> a)
succeed = \x -> \{} -> x succeed = \x -> \{} -> x
foo : {} -> F64 foo : {} -> Float *
foo = foo =
succeed 3.14 succeed 3.14
# runEffect : ({} -> a) -> a # runEffect : ({} -> a) -> a
runEffect = \thunk -> thunk {} runEffect = \thunk -> thunk {}
main : F64 main : Float *
main = main =
runEffect foo runEffect foo
"# "#
@ -1145,7 +1145,7 @@ mod gen_primitives {
main : Bool main : Bool
main = main =
myList : ConsList I64 myList : ConsList (Int *)
myList = empty myList = empty
isEmpty myList isEmpty myList
@ -1176,7 +1176,7 @@ mod gen_primitives {
main : Bool main : Bool
main = main =
myList : ConsList I64 myList : ConsList (Int *)
myList = Cons 0x1 Nil myList = Cons 0x1 Nil
isEmpty myList isEmpty myList
@ -1194,16 +1194,16 @@ mod gen_primitives {
r#" r#"
app "test" provides [ main ] to "./platform" app "test" provides [ main ] to "./platform"
State a : { count : I64, x : a } State a : { count : Int *, x : a }
foo : State a -> I64 foo : State a -> Int *
foo = \state -> foo = \state ->
if state.count == 0 then if state.count == 0 then
0 0
else else
1 + foo { count: state.count - 1, x: state.x } 1 + foo { count: state.count - 1, x: state.x }
main : I64 main : Int *
main = main =
foo { count: 3, x: {} } foo { count: 3, x: {} }
"# "#
@ -1284,7 +1284,7 @@ mod gen_primitives {
_ -> _ ->
Node color key value left right Node color key value left right
main : RedBlackTree I64 {} main : RedBlackTree (Int *) {}
main = main =
insert 0 {} Empty insert 0 {} Empty
"# "#
@ -1325,7 +1325,7 @@ mod gen_primitives {
_ -> _ ->
Empty Empty
main : RedBlackTree I64 main : RedBlackTree (Int *)
main = main =
balance Red 0 Empty Empty balance Red 0 Empty Empty
"# "#
@ -1348,7 +1348,7 @@ mod gen_primitives {
balance = \key, left -> balance = \key, left ->
Node key left Empty Node key left Empty
main : RedBlackTree I64 main : RedBlackTree (Int *)
main = main =
balance 0 Empty balance 0 Empty
"# "#
@ -1395,7 +1395,7 @@ mod gen_primitives {
_ -> _ ->
Empty Empty
main : RedBlackTree I64 I64 main : RedBlackTree (Int *) (Int *)
main = main =
balance Red 0 0 Empty Empty balance Red 0 0 Empty Empty
"# "#
@ -1445,7 +1445,7 @@ mod gen_primitives {
_ -> _ ->
Node color key value left right Node color key value left right
main : RedBlackTree I64 I64 main : RedBlackTree (Int *) (Int *)
main = main =
balance Red 0 0 Empty Empty balance Red 0 0 Empty Empty
"# "#
@ -1465,7 +1465,7 @@ mod gen_primitives {
ConsList a : [ Cons a (ConsList a), Nil ] ConsList a : [ Cons a (ConsList a), Nil ]
balance : ConsList I64 -> I64 balance : ConsList (Int *) -> Int *
balance = \right -> balance = \right ->
when right is when right is
Cons 1 foo -> Cons 1 foo ->
@ -1474,7 +1474,7 @@ mod gen_primitives {
_ -> 3 _ -> 3
_ -> 3 _ -> 3
main : I64 main : Int *
main = main =
when balance Nil is when balance Nil is
_ -> 3 _ -> 3
@ -1491,13 +1491,13 @@ mod gen_primitives {
ConsList a : [ Cons a (ConsList a), Nil ] ConsList a : [ Cons a (ConsList a), Nil ]
balance : ConsList I64 -> I64 balance : ConsList (Int *) -> Int *
balance = \right -> balance = \right ->
when right is when right is
Cons 1 (Cons 1 _) -> 3 Cons 1 (Cons 1 _) -> 3
_ -> 3 _ -> 3
main : I64 main : Int *
main = main =
when balance Nil is when balance Nil is
_ -> 3 _ -> 3
@ -1519,7 +1519,7 @@ mod gen_primitives {
ConsList a : [ Cons a (ConsList a), Nil ] ConsList a : [ Cons a (ConsList a), Nil ]
balance : ConsList I64 -> I64 balance : ConsList (Int *) -> Int *
balance = \right -> balance = \right ->
when right is when right is
Cons 1 foo -> Cons 1 foo ->
@ -1528,7 +1528,7 @@ mod gen_primitives {
_ -> 3 _ -> 3
_ -> 3 _ -> 3
main : I64 main : Int *
main = main =
when balance Nil is when balance Nil is
_ -> 3 _ -> 3
@ -1548,13 +1548,13 @@ mod gen_primitives {
ConsList a : [ Cons a (ConsList a), Nil ] ConsList a : [ Cons a (ConsList a), Nil ]
foo : ConsList I64 -> I64 foo : ConsList (Int *) -> Int *
foo = \list -> foo = \list ->
when list is when list is
Cons _ (Cons x _) -> x Cons _ (Cons x _) -> x
_ -> 0 _ -> 0
main : I64 main : Int *
main = main =
foo (Cons 1 (Cons 32 Nil)) foo (Cons 1 (Cons 32 Nil))
"# "#
@ -1571,15 +1571,15 @@ mod gen_primitives {
r#" r#"
app "test" provides [ main ] to "./platform" app "test" provides [ main ] to "./platform"
BTree : [ Node BTree BTree, Leaf I64 ] BTree : [ Node BTree BTree, Leaf (Int *) ]
foo : BTree -> I64 foo : BTree -> Int *
foo = \btree -> foo = \btree ->
when btree is when btree is
Node (Node (Leaf x) _) _ -> x Node (Node (Leaf x) _) _ -> x
_ -> 0 _ -> 0
main : I64 main : Int *
main = main =
foo (Node (Node (Leaf 32) (Leaf 0)) (Leaf 0)) foo (Node (Node (Leaf 32) (Leaf 0)) (Leaf 0))
"# "#
@ -1603,7 +1603,7 @@ mod gen_primitives {
A -> (\_ -> 3.14) A -> (\_ -> 3.14)
B -> (\_ -> 3.14) B -> (\_ -> 3.14)
main : F64 main : Float *
main = main =
(foo {}) 0 (foo {}) 0
"# "#
@ -1646,7 +1646,7 @@ mod gen_primitives {
Ok x -> transform x Ok x -> transform x
Err e -> fail e Err e -> fail e
main : Task {} F64 main : Task {} (Float *)
main = after (always "foo") (\_ -> always {}) main = after (always "foo") (\_ -> always {})
"# "#
@ -1676,7 +1676,7 @@ mod gen_primitives {
@Effect inner @Effect inner
main : Task {} F64 main : Task {} (Float *)
main = always {} main = always {}
"# "#
), ),
@ -1707,7 +1707,7 @@ mod gen_primitives {
Task a err : Effect (Result a err) Task a err : Effect (Result a err)
always : a -> Task a F64 always : a -> Task a (Float *)
always = \x -> effectAlways (Ok x) always = \x -> effectAlways (Ok x)
# the problem is that this restricts to `Task {} *` # the problem is that this restricts to `Task {} *`
@ -1722,7 +1722,7 @@ mod gen_primitives {
# but here it must be `forall b. Task b {}` # but here it must be `forall b. Task b {}`
Err e -> fail e Err e -> fail e
main : Task {} F64 main : Task {} (Float *)
main = main =
after (always "foo") (\_ -> always {}) after (always "foo") (\_ -> always {})
"# "#
@ -1774,7 +1774,7 @@ mod gen_primitives {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r#"
x : Result I64 F64 x : Result (Int *) (Float *)
x = Ok 4 x = Ok 4
(Ok y) = x (Ok y) = x

View file

@ -41,6 +41,9 @@ pub fn helper<'a>(
module_src = &temp; module_src = &temp;
} }
let target = target_lexicon::Triple::host();
let ptr_bytes = target.pointer_width().unwrap().bytes() as u32;
let exposed_types = MutMap::default(); let exposed_types = MutMap::default();
let loaded = roc_load::file::load_and_monomorphize_from_str( let loaded = roc_load::file::load_and_monomorphize_from_str(
arena, arena,
@ -49,6 +52,7 @@ pub fn helper<'a>(
stdlib, stdlib,
src_dir, src_dir,
exposed_types, exposed_types,
ptr_bytes,
); );
let mut loaded = loaded.expect("failed to load module"); let mut loaded = loaded.expect("failed to load module");
@ -73,9 +77,6 @@ pub fn helper<'a>(
), ),
}; };
let target = target_lexicon::Triple::host();
let ptr_bytes = target.pointer_width().unwrap().bytes() as u32;
let mut lines = Vec::new(); let mut lines = Vec::new();
// errors whose reporting we delay (so we can see that code gen generates runtime errors) // errors whose reporting we delay (so we can see that code gen generates runtime errors)
let mut delayed_errors = Vec::new(); let mut delayed_errors = Vec::new();
@ -308,7 +309,9 @@ macro_rules! assert_opt_evals_to {
let context = Context::create(); let context = Context::create();
let stdlib = roc_builtins::unique::uniq_stdlib(); // don't use uniqueness types any more
// let stdlib = roc_builtins::unique::uniq_stdlib();
let stdlib = roc_builtins::std::standard_stdlib();
let (main_fn_name, errors, lib) = let (main_fn_name, errors, lib) =
$crate::helpers::eval::helper(&arena, $src, stdlib, $leak, &context); $crate::helpers::eval::helper(&arena, $src, stdlib, $leak, &context);

View file

@ -50,6 +50,7 @@ pub fn helper<'a>(
stdlib, stdlib,
src_dir, src_dir,
exposed_types, exposed_types,
8,
); );
let mut loaded = loaded.expect("failed to load module"); let mut loaded = loaded.expect("failed to load module");

View file

@ -947,6 +947,7 @@ pub fn load_and_typecheck(
stdlib: StdLib, stdlib: StdLib,
src_dir: &Path, src_dir: &Path,
exposed_types: SubsByModule, exposed_types: SubsByModule,
ptr_bytes: u32,
) -> Result<LoadedModule, LoadingProblem> { ) -> Result<LoadedModule, LoadingProblem> {
use LoadResult::*; use LoadResult::*;
@ -959,6 +960,7 @@ pub fn load_and_typecheck(
src_dir, src_dir,
exposed_types, exposed_types,
Phase::SolveTypes, Phase::SolveTypes,
ptr_bytes,
)? { )? {
Monomorphized(_) => unreachable!(""), Monomorphized(_) => unreachable!(""),
TypeChecked(module) => Ok(module), TypeChecked(module) => Ok(module),
@ -971,6 +973,7 @@ pub fn load_and_monomorphize<'a>(
stdlib: StdLib, stdlib: StdLib,
src_dir: &Path, src_dir: &Path,
exposed_types: SubsByModule, exposed_types: SubsByModule,
ptr_bytes: u32,
) -> Result<MonomorphizedModule<'a>, LoadingProblem> { ) -> Result<MonomorphizedModule<'a>, LoadingProblem> {
use LoadResult::*; use LoadResult::*;
@ -983,6 +986,7 @@ pub fn load_and_monomorphize<'a>(
src_dir, src_dir,
exposed_types, exposed_types,
Phase::MakeSpecializations, Phase::MakeSpecializations,
ptr_bytes,
)? { )? {
Monomorphized(module) => Ok(module), Monomorphized(module) => Ok(module),
TypeChecked(_) => unreachable!(""), TypeChecked(_) => unreachable!(""),
@ -996,6 +1000,7 @@ pub fn load_and_monomorphize_from_str<'a>(
stdlib: StdLib, stdlib: StdLib,
src_dir: &Path, src_dir: &Path,
exposed_types: SubsByModule, exposed_types: SubsByModule,
ptr_bytes: u32,
) -> Result<MonomorphizedModule<'a>, LoadingProblem> { ) -> Result<MonomorphizedModule<'a>, LoadingProblem> {
use LoadResult::*; use LoadResult::*;
@ -1008,6 +1013,7 @@ pub fn load_and_monomorphize_from_str<'a>(
src_dir, src_dir,
exposed_types, exposed_types,
Phase::MakeSpecializations, Phase::MakeSpecializations,
ptr_bytes,
)? { )? {
Monomorphized(module) => Ok(module), Monomorphized(module) => Ok(module),
TypeChecked(_) => unreachable!(""), TypeChecked(_) => unreachable!(""),
@ -1144,6 +1150,7 @@ fn load<'a>(
src_dir: &Path, src_dir: &Path,
exposed_types: SubsByModule, exposed_types: SubsByModule,
goal_phase: Phase, goal_phase: Phase,
ptr_bytes: u32,
) -> Result<LoadResult<'a>, LoadingProblem> ) -> Result<LoadResult<'a>, LoadingProblem>
where where
{ {
@ -1259,7 +1266,13 @@ where
// added. In that case, do nothing, and keep waiting // added. In that case, do nothing, and keep waiting
// until we receive a Shutdown message. // until we receive a Shutdown message.
if let Some(task) = find_task(&worker, injector, stealers) { if let Some(task) = find_task(&worker, injector, stealers) {
run_task(task, worker_arena, src_dir, msg_tx.clone()) run_task(
task,
worker_arena,
src_dir,
msg_tx.clone(),
ptr_bytes,
)
.expect("Msg channel closed unexpectedly."); .expect("Msg channel closed unexpectedly.");
} }
} }
@ -3341,6 +3354,7 @@ fn make_specializations<'a>(
mut layout_cache: LayoutCache<'a>, mut layout_cache: LayoutCache<'a>,
specializations_we_must_make: ExternalSpecializations, specializations_we_must_make: ExternalSpecializations,
mut module_timing: ModuleTiming, mut module_timing: ModuleTiming,
ptr_bytes: u32,
) -> Msg<'a> { ) -> Msg<'a> {
let make_specializations_start = SystemTime::now(); let make_specializations_start = SystemTime::now();
let mut mono_problems = Vec::new(); let mut mono_problems = Vec::new();
@ -3351,6 +3365,7 @@ fn make_specializations<'a>(
subs: &mut subs, subs: &mut subs,
home, home,
ident_ids: &mut ident_ids, ident_ids: &mut ident_ids,
ptr_bytes,
}; };
procs procs
@ -3396,6 +3411,7 @@ fn build_pending_specializations<'a>(
decls: Vec<Declaration>, decls: Vec<Declaration>,
mut module_timing: ModuleTiming, mut module_timing: ModuleTiming,
mut layout_cache: LayoutCache<'a>, mut layout_cache: LayoutCache<'a>,
ptr_bytes: u32,
// TODO remove // TODO remove
exposed_to_host: MutMap<Symbol, Variable>, exposed_to_host: MutMap<Symbol, Variable>,
) -> Msg<'a> { ) -> Msg<'a> {
@ -3410,6 +3426,7 @@ fn build_pending_specializations<'a>(
subs: &mut subs, subs: &mut subs,
home, home,
ident_ids: &mut ident_ids, ident_ids: &mut ident_ids,
ptr_bytes,
}; };
// Add modules' decls to Procs // Add modules' decls to Procs
@ -3613,6 +3630,7 @@ fn run_task<'a>(
arena: &'a Bump, arena: &'a Bump,
src_dir: &Path, src_dir: &Path,
msg_tx: MsgSender<'a>, msg_tx: MsgSender<'a>,
ptr_bytes: u32,
) -> Result<(), LoadingProblem> { ) -> Result<(), LoadingProblem> {
use BuildTask::*; use BuildTask::*;
@ -3685,6 +3703,7 @@ fn run_task<'a>(
decls, decls,
module_timing, module_timing,
layout_cache, layout_cache,
ptr_bytes,
exposed_to_host, exposed_to_host,
)), )),
MakeSpecializations { MakeSpecializations {
@ -3704,6 +3723,7 @@ fn run_task<'a>(
layout_cache, layout_cache,
specializations_we_must_make, specializations_we_must_make,
module_timing, module_timing,
ptr_bytes,
)), )),
}?; }?;

View file

@ -1,6 +1,6 @@
app "quicksort" provides [ swap, partition, partitionHelp, quicksort ] to "./platform" app "quicksort" provides [ swap, partition, partitionHelp, quicksort ] to "./platform"
quicksort : List (Num a), I64, I64 -> List (Num a) quicksort : List (Num a), Int *, Int * -> List (Num a)
quicksort = \list, low, high -> quicksort = \list, low, high ->
when partition low high list is when partition low high list is
Pair partitionIndex partitioned -> Pair partitionIndex partitioned ->
@ -9,7 +9,7 @@ quicksort = \list, low, high ->
|> quicksort (partitionIndex + 1) high |> quicksort (partitionIndex + 1) high
swap : I64, I64, List a -> List a swap : Int *, Int *, List a -> List a
swap = \i, j, list -> swap = \i, j, list ->
when Pair (List.get list i) (List.get list j) is when Pair (List.get list i) (List.get list j) is
Pair (Ok atI) (Ok atJ) -> Pair (Ok atI) (Ok atJ) ->
@ -21,7 +21,7 @@ swap = \i, j, list ->
[] []
partition : I64, I64, List (Num a) -> [ Pair I64 (List (Num a)) ] partition : Int *, Int *, List (Num a) -> [ Pair (Int *) (List (Num a)) ]
partition = \low, high, initialList -> partition = \low, high, initialList ->
when List.get initialList high is when List.get initialList high is
Ok pivot -> Ok pivot ->
@ -33,7 +33,7 @@ partition = \low, high, initialList ->
Pair (low - 1) initialList Pair (low - 1) initialList
partitionHelp : I64, I64, List (Num a), I64, (Num a) -> [ Pair I64 (List (Num a)) ] partitionHelp : Int *, Int *, List (Num a), Int *, (Num a) -> [ Pair (Int *) (List (Num a)) ]
partitionHelp = \i, j, list, high, pivot -> partitionHelp = \i, j, list, high, pivot ->
if j < high then if j < high then
when List.get list j is when List.get list j is

View file

@ -1,7 +1,7 @@
app "quicksort" provides [ quicksort ] to "./platform" app "quicksort" provides [ quicksort ] to "./platform"
quicksort = \originalList -> quicksort = \originalList ->
quicksortHelp : List (Num a), I64, I64 -> List (Num a) quicksortHelp : List (Num a), Int *, Int * -> List (Num a)
quicksortHelp = \list, low, high -> quicksortHelp = \list, low, high ->
if low < high then if low < high then
when partition low high list is when partition low high list is
@ -13,7 +13,7 @@ quicksort = \originalList ->
list list
swap : I64, I64, List a -> List a swap : Int *, Int *, List a -> List a
swap = \i, j, list -> swap = \i, j, list ->
when Pair (List.get list i) (List.get list j) is when Pair (List.get list i) (List.get list j) is
Pair (Ok atI) (Ok atJ) -> Pair (Ok atI) (Ok atJ) ->
@ -24,7 +24,7 @@ quicksort = \originalList ->
_ -> _ ->
[] []
partition : I64, I64, List (Num a) -> [ Pair I64 (List (Num a)) ] partition : Int *, Int *, List (Num a) -> [ Pair (Int *) (List (Num a)) ]
partition = \low, high, initialList -> partition = \low, high, initialList ->
when List.get initialList high is when List.get initialList high is
Ok pivot -> Ok pivot ->
@ -36,7 +36,7 @@ quicksort = \originalList ->
Pair (low - 1) initialList Pair (low - 1) initialList
partitionHelp : I64, I64, List (Num a), I64, (Num a) -> [ Pair I64 (List (Num a)) ] partitionHelp : Int *, Int *, List (Num a), Int *, (Num a) -> [ Pair (Int *) (List (Num a)) ]
partitionHelp = \i, j, list, high, pivot -> partitionHelp = \i, j, list, high, pivot ->
if j < high then if j < high then
when List.get list j is when List.get list j is

View file

@ -2,7 +2,7 @@ interface Quicksort
exposes [ swap, partition, quicksort ] exposes [ swap, partition, quicksort ]
imports [] imports []
quicksort : List (Num a), I64, I64 -> List (Num a) quicksort : List (Num a), Int *, Int * -> List (Num a)
quicksort = \list, low, high -> quicksort = \list, low, high ->
when partition low high list is when partition low high list is
Pair partitionIndex partitioned -> Pair partitionIndex partitioned ->
@ -11,7 +11,7 @@ quicksort = \list, low, high ->
|> quicksort (partitionIndex + 1) high |> quicksort (partitionIndex + 1) high
swap : I64, I64, List a -> List a swap : Int *, Int *, List a -> List a
swap = \i, j, list -> swap = \i, j, list ->
when Pair (List.get list i) (List.get list j) is when Pair (List.get list i) (List.get list j) is
Pair (Ok atI) (Ok atJ) -> Pair (Ok atI) (Ok atJ) ->
@ -23,7 +23,7 @@ swap = \i, j, list ->
[] []
partition : I64, I64, List (Num a) -> [ Pair I64 (List (Num a)) ] partition : Int *, Int *, List (Num a) -> [ Pair (Int *) (List (Num a)) ]
partition = \low, high, initialList -> partition = \low, high, initialList ->
when List.get initialList high is when List.get initialList high is
Ok pivot -> Ok pivot ->
@ -35,7 +35,7 @@ partition = \low, high, initialList ->
Pair (low - 1) initialList Pair (low - 1) initialList
partitionHelp : I64, I64, List (Num a), I64, (Num a) -> [ Pair I64 (List (Num a)) ] partitionHelp : Int *, Int *, List (Num a), Int *, (Num a) -> [ Pair (Int *) (List (Num a)) ]
partitionHelp = \i, j, list, high, pivot -> partitionHelp = \i, j, list, high, pivot ->
if j < high then if j < high then
when List.get list j is when List.get list j is

View file

@ -85,6 +85,7 @@ mod test_load {
stdlib, stdlib,
dir.path(), dir.path(),
exposed_types, exposed_types,
8,
) )
}; };
@ -126,6 +127,7 @@ mod test_load {
roc_builtins::std::standard_stdlib(), roc_builtins::std::standard_stdlib(),
src_dir.as_path(), src_dir.as_path(),
subs_by_module, subs_by_module,
8,
); );
let mut loaded_module = loaded.expect("Test module failed to load"); let mut loaded_module = loaded.expect("Test module failed to load");
@ -288,6 +290,7 @@ mod test_load {
roc_builtins::std::standard_stdlib(), roc_builtins::std::standard_stdlib(),
src_dir.as_path(), src_dir.as_path(),
subs_by_module, subs_by_module,
8,
); );
let mut loaded_module = loaded.expect("Test module failed to load"); let mut loaded_module = loaded.expect("Test module failed to load");
@ -357,14 +360,14 @@ mod test_load {
expect_types( expect_types(
loaded_module, loaded_module,
hashmap! { hashmap! {
"floatTest" => "F64", "floatTest" => "Float *",
"divisionFn" => "F64, F64 -> Result F64 [ DivByZero ]*", "divisionFn" => "Float a, Float a -> Result (Float a) [ DivByZero ]*",
"divisionTest" => "Result F64 [ DivByZero ]*", "divisionTest" => "Result (Float *) [ DivByZero ]*",
"intTest" => "I64", "intTest" => "Int *",
"x" => "F64", "x" => "Float *",
"constantNum" => "Num *", "constantNum" => "Num *",
"divDep1ByDep2" => "Result F64 [ DivByZero ]*", "divDep1ByDep2" => "Result (Float *) [ DivByZero ]*",
"fromDep2" => "F64", "fromDep2" => "Float *",
}, },
); );
} }
@ -377,10 +380,10 @@ mod test_load {
expect_types( expect_types(
loaded_module, loaded_module,
hashmap! { hashmap! {
"swap" => "I64, I64, List a -> List a", "swap" => "Int *, Int *, List a -> List a",
"partition" => "I64, I64, List (Num a) -> [ Pair I64 (List (Num a)) ]", "partition" => "Int b, Int b, List (Num a) -> [ Pair (Int b) (List (Num a)) ]",
"partitionHelp" => "I64, I64, List (Num a), I64, Num a -> [ Pair I64 (List (Num a)) ]", "partitionHelp" => "Int b, Int c, List (Num a), Int c, Num a -> [ Pair (Int b) (List (Num a)) ]",
"quicksort" => "List (Num a), I64, I64 -> List (Num a)", "quicksort" => "List (Num a), Int b, Int b -> List (Num a)",
}, },
); );
} }
@ -406,10 +409,10 @@ mod test_load {
expect_types( expect_types(
loaded_module, loaded_module,
hashmap! { hashmap! {
"swap" => "I64, I64, List a -> List a", "swap" => "Int *, Int *, List a -> List a",
"partition" => "I64, I64, List (Num a) -> [ Pair I64 (List (Num a)) ]", "partition" => "Int b, Int b, List (Num a) -> [ Pair (Int b) (List (Num a)) ]",
"partitionHelp" => "I64, I64, List (Num a), I64, Num a -> [ Pair I64 (List (Num a)) ]", "partitionHelp" => "Int b, Int c, List (Num a), Int c, Num a -> [ Pair (Int b) (List (Num a)) ]",
"quicksort" => "List (Num a), I64, I64 -> List (Num a)", "quicksort" => "List (Num a), Int b, Int b -> List (Num a)",
}, },
); );
} }
@ -454,7 +457,7 @@ mod test_load {
expect_types( expect_types(
loaded_module, loaded_module,
hashmap! { hashmap! {
"blah2" => "F64", "blah2" => "Float *",
"blah3" => "Str", "blah3" => "Str",
"str" => "Str", "str" => "Str",
"alwaysThree" => "* -> Str", "alwaysThree" => "* -> Str",
@ -476,7 +479,7 @@ mod test_load {
expect_types( expect_types(
loaded_module, loaded_module,
hashmap! { hashmap! {
"blah2" => "F64", "blah2" => "Float *",
"blah3" => "Str", "blah3" => "Str",
"str" => "Str", "str" => "Str",
"alwaysThree" => "* -> Str", "alwaysThree" => "* -> Str",

View file

@ -1,423 +0,0 @@
#[macro_use]
extern crate pretty_assertions;
#[macro_use]
extern crate maplit;
extern crate bumpalo;
extern crate inlinable_string;
extern crate roc_collections;
extern crate roc_load;
extern crate roc_module;
mod helpers;
#[cfg(test)]
mod test_uniq_load {
use crate::helpers::fixtures_dir;
use bumpalo::Bump;
use inlinable_string::InlinableString;
use roc_builtins::unique;
use roc_can::def::Declaration::*;
use roc_can::def::Def;
use roc_collections::all::MutMap;
use roc_constrain::module::SubsByModule;
use roc_load::file::LoadedModule;
use roc_module::ident::ModuleName;
use roc_module::symbol::{Interns, ModuleId};
use roc_types::pretty_print::{content_to_string, name_all_type_vars};
use roc_types::subs::Subs;
use std::collections::HashMap;
// HELPERS
fn load_fixture(
dir_name: &str,
module_name: &str,
subs_by_module: SubsByModule,
) -> LoadedModule {
let arena = Bump::new();
let src_dir = fixtures_dir().join(dir_name);
let filename = src_dir.join(format!("{}.roc", module_name));
let loaded = roc_load::file::load_and_typecheck(
&arena,
filename,
unique::uniq_stdlib(),
src_dir.as_path(),
subs_by_module,
);
let mut loaded_module = loaded.expect("Test module failed to load");
let home = loaded_module.module_id;
assert_eq!(
loaded_module.can_problems.remove(&home).unwrap_or_default(),
Vec::new()
);
assert_eq!(
loaded_module
.type_problems
.remove(&home)
.unwrap_or_default(),
Vec::new()
);
let expected_name = loaded_module
.interns
.module_ids
.get_name(loaded_module.module_id)
.expect("Test ModuleID not found in module_ids");
// App module names are hardcoded and not based on anything user-specified
if expected_name != ModuleName::APP {
assert_eq!(expected_name, &InlinableString::from(module_name));
}
loaded_module
}
fn expect_def(
interns: &Interns,
subs: &mut Subs,
home: ModuleId,
def: &Def,
expected_types: &mut HashMap<&str, &str>,
) {
for (symbol, expr_var) in &def.pattern_vars {
let content = subs.get(*expr_var).content;
name_all_type_vars(*expr_var, subs);
let actual_str = content_to_string(content, subs, home, &interns);
let fully_qualified = symbol.fully_qualified(&interns, home).to_string();
let expected_type = expected_types
.remove(fully_qualified.as_str())
.unwrap_or_else(|| {
panic!("Defs included an unexpected symbol: {:?}", fully_qualified)
});
assert_eq!((&symbol, expected_type), (&symbol, actual_str.as_str()));
}
}
fn expect_types(mut loaded_module: LoadedModule, mut expected_types: HashMap<&str, &str>) {
let home = loaded_module.module_id;
let mut subs = loaded_module.solved.into_inner();
assert_eq!(
loaded_module.can_problems.remove(&home).unwrap_or_default(),
Vec::new()
);
assert_eq!(
loaded_module
.type_problems
.remove(&home)
.unwrap_or_default(),
Vec::new()
);
for decl in loaded_module.declarations_by_id.remove(&home).unwrap() {
match decl {
Declare(def) => expect_def(
&loaded_module.interns,
&mut subs,
home,
&def,
&mut expected_types,
),
DeclareRec(defs) => {
for def in defs {
expect_def(
&loaded_module.interns,
&mut subs,
home,
&def,
&mut expected_types,
);
}
}
Builtin(_) => {}
cycle @ InvalidCycle(_, _) => {
panic!("Unexpected cyclic def in module declarations: {:?}", cycle);
}
};
}
assert_eq!(
expected_types,
HashMap::default(),
"Some expected types were not found in the defs"
);
}
// TESTS
#[test]
fn interface_with_deps() {
let arena = Bump::new();
let subs_by_module = MutMap::default();
let src_dir = fixtures_dir().join("interface_with_deps");
let filename = src_dir.join("Primary.roc");
let loaded = roc_load::file::load_and_typecheck(
&arena,
filename,
roc_builtins::std::standard_stdlib(),
src_dir.as_path(),
subs_by_module,
);
let mut loaded_module = loaded.expect("Test module failed to load");
let home = loaded_module.module_id;
assert_eq!(
loaded_module.can_problems.remove(&home).unwrap_or_default(),
Vec::new()
);
assert_eq!(
loaded_module
.type_problems
.remove(&home)
.unwrap_or_default(),
Vec::new()
);
let def_count: usize = loaded_module
.declarations_by_id
.remove(&loaded_module.module_id)
.unwrap()
.into_iter()
.map(|decl| decl.def_count())
.sum();
let expected_name = loaded_module
.interns
.module_ids
.get_name(loaded_module.module_id)
.expect("Test ModuleID not found in module_ids");
assert_eq!(expected_name, &InlinableString::from("Primary"));
assert_eq!(def_count, 10);
}
#[test]
fn load_unit() {
let subs_by_module = MutMap::default();
let loaded_module = load_fixture("no_deps", "Unit", subs_by_module);
expect_types(
loaded_module,
hashmap! {
"unit" => "Attr * Unit",
},
);
}
#[test]
fn import_alias() {
let subs_by_module = MutMap::default();
let loaded_module = load_fixture("interface_with_deps", "ImportAlias", subs_by_module);
expect_types(
loaded_module,
hashmap! {
"unit" => "Attr * Dep1.Unit",
},
);
}
#[test]
fn load_and_typecheck() {
let subs_by_module = MutMap::default();
let loaded_module = load_fixture("interface_with_deps", "WithBuiltins", subs_by_module);
expect_types(
loaded_module,
hashmap! {
"floatTest" => "Attr Shared F64",
"divisionFn" => "Attr Shared (Attr * F64, Attr * F64 -> Attr * (Result (Attr * F64) (Attr * [ DivByZero ]*)))",
"divisionTest" => "Attr * (Result (Attr * F64) (Attr * [ DivByZero ]*))",
"intTest" => "Attr * I64",
"x" => "Attr * F64",
"constantNum" => "Attr * (Num (Attr * *))",
"divDep1ByDep2" => "Attr * (Result (Attr * F64) (Attr * [ DivByZero ]*))",
"fromDep2" => "Attr * F64",
},
);
}
#[test]
#[ignore]
fn load_astar() {
let subs_by_module = MutMap::default();
let loaded_module = load_fixture("interface_with_deps", "AStar", subs_by_module);
expect_types(
loaded_module,
hashmap! {
"findPath" => "Attr * (Attr * { costFunction : Attr Shared (Attr Shared position, Attr Shared position -> Attr * F64), end : Attr Shared position, moveFunction : Attr Shared (Attr Shared position -> Attr * (Set (Attr * position))), start : Attr Shared position } -> Attr * (Result (Attr * (List (Attr Shared position))) (Attr * [ KeyNotFound ]*)))",
"initialModel" => "Attr * (Attr Shared position -> Attr * (Model (Attr Shared position)))",
"reconstructPath" => "Attr Shared (Attr Shared (Map (Attr * position) (Attr Shared position)), Attr Shared position -> Attr * (List (Attr Shared position)))",
"updateCost" => "Attr * (Attr Shared position, Attr Shared position, Attr Shared (Model (Attr Shared position)) -> Attr Shared (Model (Attr Shared position)))",
"cheapestOpen" => "Attr * (Attr * (Attr Shared position -> Attr * F64), Attr (* | a | b | c) (Model (Attr Shared position)) -> Attr * (Result (Attr Shared position) (Attr * [ KeyNotFound ]*)))",
"astar" => "Attr Shared (Attr Shared (Attr Shared position, Attr Shared position -> Attr * F64), Attr Shared (Attr Shared position -> Attr * (Set (Attr * position))), Attr Shared position, Attr Shared (Model (Attr Shared position)) -> Attr * [ Err (Attr * [ KeyNotFound ]*), Ok (Attr * (List (Attr Shared position))) ]*)",
},
);
}
#[test]
fn load_and_typecheck_quicksort() {
let subs_by_module = MutMap::default();
let loaded_module = load_fixture("interface_with_deps", "Quicksort", subs_by_module);
expect_types(
loaded_module,
hashmap! {
"swap" => "Attr * (Attr * I64, Attr * I64, Attr * (List (Attr Shared a)) -> Attr * (List (Attr Shared a)))",
"partition" => "Attr * (Attr Shared I64, Attr Shared I64, Attr b (List (Attr Shared (Num (Attr Shared a)))) -> Attr * [ Pair (Attr * I64) (Attr b (List (Attr Shared (Num (Attr Shared a))))) ])",
"partitionHelp" => "Attr Shared (Attr b I64, Attr Shared I64, Attr c (List (Attr Shared (Num (Attr Shared a)))), Attr Shared I64, Attr Shared (Num (Attr Shared a)) -> Attr * [ Pair (Attr b I64) (Attr c (List (Attr Shared (Num (Attr Shared a))))) ])",
"quicksort" => "Attr Shared (Attr b (List (Attr Shared (Num (Attr Shared a)))), Attr Shared I64, Attr Shared I64 -> Attr b (List (Attr Shared (Num (Attr Shared a)))))",
},
);
}
#[test]
fn quickcheck_nested_let() {
let subs_by_module = MutMap::default();
let loaded_module = load_fixture("app_with_deps", "QuicksortOneDef", subs_by_module);
expect_types(
loaded_module,
hashmap! {
"quicksort" => "Attr * (Attr b (List (Attr Shared (Num (Attr Shared a)))) -> Attr b (List (Attr Shared (Num (Attr Shared a)))))",
},
);
}
#[test]
fn load_principal_types() {
let subs_by_module = MutMap::default();
let loaded_module = load_fixture("no_deps", "Principal", subs_by_module);
expect_types(
loaded_module,
hashmap! {
"intVal" => "Attr * Str",
"identity" => "Attr * (a -> a)",
},
);
}
#[test]
#[ignore]
fn load_dep_types() {
let subs_by_module = MutMap::default();
let loaded_module = load_fixture("interface_with_deps", "Primary", subs_by_module);
// the inferred signature for withDefault is wrong, part of the alias in alias issue.
// "withDefault" => "Attr * (Attr * (Res.Res (Attr a b) (Attr * *)), Attr a b -> Attr a b)",
expect_types(
loaded_module,
hashmap! {
"blah2" => "Attr * F64",
"blah3" => "Attr * Str",
"str" => "Attr * Str",
"alwaysThree" => "Attr * (* -> Attr * Str)",
"identity" => "Attr * (a -> a)",
"z" => "Attr * Str",
"w" => "Attr * (Dep1.Identity (Attr * {}))",
"succeed" => "Attr * (Attr b a -> Attr * (Dep1.Identity (Attr b a)))",
"yay" => "Attr * (Res.Res (Attr * {}) (Attr * err))",
"withDefault" => "Attr * (Attr (* | b | c) (Res.Res (Attr b a) (Attr c *)), Attr b a -> Attr b a)",
},
);
}
#[test]
#[ignore]
fn load_custom_res() {
let subs_by_module = MutMap::default();
let loaded_module = load_fixture("interface_with_deps", "Res", subs_by_module);
expect_types(
loaded_module,
hashmap! {
"withDefault" =>"Attr * (Attr (* | b | c) (Res (Attr b a) (Attr c err)), Attr b a -> Attr b a)",
"map" => "Attr * (Attr (* | c | d) (Res (Attr c a) (Attr d err)), Attr * (Attr c a -> Attr e b) -> Attr * (Res (Attr e b) (Attr d err)))",
"andThen" => "Attr * (Attr (* | c | d) (Res (Attr c a) (Attr d err)), Attr * (Attr c a -> Attr f (Res (Attr e b) (Attr d err))) -> Attr f (Res (Attr e b) (Attr d err)))",
},
);
}
#[test]
fn imported_dep_regression() {
let subs_by_module = MutMap::default();
let loaded_module = load_fixture("interface_with_deps", "OneDep", subs_by_module);
expect_types(
loaded_module,
hashmap! {
"str" => "Attr * Str",
},
);
}
// #[test]
// fn load_records() {
// test_async(async {
// use roc::types::{ErrorType, Mismatch, Problem, TypeExt};
// let subs_by_module = MutMap::default();
// let loaded_module =
// load_fixture("interface_with_deps", "Records", subs_by_module);
// // NOTE: `a` here is unconstrained, so unifies with <type error>
// let expected_types = hashmap! {
// "Records.intVal" => "a",
// };
// let a = ErrorType::FlexVar("a".into());
// let mut record = SendMap::default();
// record.insert("x".into(), a);
// let problem = Problem::Mismatch(
// Mismatch::TypeMismatch,
// ErrorType::Record(SendMap::default(), TypeExt::Closed),
// ErrorType::Record(record, TypeExt::FlexOpen("b".into())),
// );
// assert_eq!(loaded_module.problems, vec![problem]);
// assert_eq!(expected_types.len(), loaded_module.declarations.len());
// let mut subs = loaded_module.solved.into_inner();
// for decl in loaded_module.declarations {
// let def = match decl {
// Declare(def) => def,
// rec_decl @ DeclareRec(_) => {
// panic!(
// "Unexpected recursive def in module declarations: {:?}",
// rec_decl
// );
// }
// cycle @ InvalidCycle(_, _) => {
// panic!("Unexpected cyclic def in module declarations: {:?}", cycle);
// }
// };
// for (symbol, expr_var) in def.pattern_vars {
// let content = subs.get(expr_var).content;
// name_all_type_vars(expr_var, &mut subs);
// let actual_str = content_to_string(content, &mut subs);
// let expected_type = expected_types.get(symbol.as_str()).unwrap_or_else(|| {
// panic!("Defs included an unexpected symbol: {:?}", symbol)
// });
// assert_eq!((&symbol, expected_type), (&symbol, &actual_str.as_str()));
// }
// }
// });
// }
}

View file

@ -827,6 +827,11 @@ define_builtins! {
83 NUM_SUB_CHECKED: "subChecked" 83 NUM_SUB_CHECKED: "subChecked"
84 NUM_MUL_WRAP: "mulWrap" 84 NUM_MUL_WRAP: "mulWrap"
85 NUM_MUL_CHECKED: "mulChecked" 85 NUM_MUL_CHECKED: "mulChecked"
86 NUM_INT: "Int" imported
87 NUM_FLOAT: "Float" imported
88 NUM_AT_NATURAL: "@Natural"
89 NUM_NATURAL: "Natural" imported
90 NUM_NAT: "Nat" imported
} }
2 BOOL: "Bool" => { 2 BOOL: "Bool" => {
0 BOOL_BOOL: "Bool" imported // the Bool.Bool type alias 0 BOOL_BOOL: "Bool" imported // the Bool.Bool type alias

View file

@ -445,10 +445,10 @@ fn test_at_path<'a>(selected_path: &Path, branch: &Branch<'a>, all_tests: &mut V
num_alts: union.alternatives.len(), num_alts: union.alternatives.len(),
}); });
} }
IntLiteral(v) => { IntLiteral(_, v) => {
all_tests.push(guarded(IsInt(*v))); all_tests.push(guarded(IsInt(*v)));
} }
FloatLiteral(v) => { FloatLiteral(_, v) => {
all_tests.push(IsFloat(*v)); all_tests.push(IsFloat(*v));
} }
StrLiteral(v) => { StrLiteral(v) => {
@ -636,7 +636,7 @@ fn to_relevant_branch_help<'a>(
_ => None, _ => None,
}, },
IntLiteral(int) => match test { IntLiteral(_, int) => match test {
IsInt(is_int) if int == *is_int => { IsInt(is_int) if int == *is_int => {
start.extend(end); start.extend(end);
Some(Branch { Some(Branch {
@ -647,7 +647,7 @@ fn to_relevant_branch_help<'a>(
_ => None, _ => None,
}, },
FloatLiteral(float) => match test { FloatLiteral(_, float) => match test {
IsFloat(test_float) if float == *test_float => { IsFloat(test_float) if float == *test_float => {
start.extend(end); start.extend(end);
Some(Branch { Some(Branch {
@ -740,8 +740,8 @@ fn needs_tests(pattern: &Pattern) -> bool {
| AppliedTag { .. } | AppliedTag { .. }
| BitLiteral { .. } | BitLiteral { .. }
| EnumLiteral { .. } | EnumLiteral { .. }
| IntLiteral(_) | IntLiteral(_, _)
| FloatLiteral(_) | FloatLiteral(_, _)
| StrLiteral(_) => true, | StrLiteral(_) => true,
} }
} }

View file

@ -48,8 +48,8 @@ fn simplify(pattern: &crate::ir::Pattern) -> Pattern {
use crate::ir::Pattern::*; use crate::ir::Pattern::*;
match pattern { match pattern {
IntLiteral(v) => Literal(Literal::Int(*v)), IntLiteral(_, v) => Literal(Literal::Int(*v)),
FloatLiteral(v) => Literal(Literal::Float(*v)), FloatLiteral(_, v) => Literal(Literal::Float(*v)),
StrLiteral(v) => Literal(Literal::Str(v.clone())), StrLiteral(v) => Literal(Literal::Str(v.clone())),
// To make sure these are exhaustive, we have to "fake" a union here // To make sure these are exhaustive, we have to "fake" a union here

View file

@ -1,6 +1,6 @@
use self::InProgressProc::*; use self::InProgressProc::*;
use crate::exhaustive::{Ctor, Guard, RenderAs, TagId}; use crate::exhaustive::{Ctor, Guard, RenderAs, TagId};
use crate::layout::{Builtin, ClosureLayout, Layout, LayoutCache, LayoutProblem}; use crate::layout::{Builtin, ClosureLayout, Layout, LayoutCache, LayoutProblem, TAG_SIZE};
use bumpalo::collections::Vec; use bumpalo::collections::Vec;
use bumpalo::Bump; use bumpalo::Bump;
use roc_collections::all::{default_hasher, MutMap, MutSet}; use roc_collections::all::{default_hasher, MutMap, MutSet};
@ -691,6 +691,7 @@ pub struct Env<'a, 'i> {
pub problems: &'i mut std::vec::Vec<MonoProblem>, pub problems: &'i mut std::vec::Vec<MonoProblem>,
pub home: ModuleId, pub home: ModuleId,
pub ident_ids: &'i mut IdentIds, pub ident_ids: &'i mut IdentIds,
pub ptr_bytes: u32,
} }
impl<'a, 'i> Env<'a, 'i> { impl<'a, 'i> Env<'a, 'i> {
@ -1492,7 +1493,7 @@ fn pattern_to_when<'a>(
(symbol, Located::at_zero(wrapped_body)) (symbol, Located::at_zero(wrapped_body))
} }
IntLiteral(_) | NumLiteral(_, _) | FloatLiteral(_) | StrLiteral(_) => { IntLiteral(_, _) | NumLiteral(_, _) | FloatLiteral(_, _) | StrLiteral(_) => {
// These patters are refutable, and thus should never occur outside a `when` expression // These patters are refutable, and thus should never occur outside a `when` expression
// They should have been replaced with `UnsupportedPattern` during canonicalization // They should have been replaced with `UnsupportedPattern` during canonicalization
unreachable!("refutable pattern {:?} where irrefutable pattern is expected. This should never happen!", pattern.value) unreachable!("refutable pattern {:?} where irrefutable pattern is expected. This should never happen!", pattern.value)
@ -2357,19 +2358,41 @@ pub fn with_hole<'a>(
let arena = env.arena; let arena = env.arena;
match can_expr { match can_expr {
Int(_, num) => Stmt::Let( Int(_, precision, num) => {
match num_argument_to_int_or_float(env.subs, env.ptr_bytes, precision, false) {
IntOrFloat::SignedIntType(precision) => Stmt::Let(
assigned, assigned,
Expr::Literal(Literal::Int(num)), Expr::Literal(Literal::Int(num)),
Layout::Builtin(Builtin::Int64), Layout::Builtin(int_precision_to_builtin(precision)),
hole, hole,
), ),
IntOrFloat::UnsignedIntType(precision) => Stmt::Let(
Float(_, num) => Stmt::Let(
assigned, assigned,
Expr::Literal(Literal::Float(num)), Expr::Literal(Literal::Int(num)),
Layout::Builtin(Builtin::Float64), Layout::Builtin(int_precision_to_builtin(precision)),
hole, hole,
), ),
_ => unreachable!("unexpected float precision for integer"),
}
}
Float(_, precision, num) => {
match num_argument_to_int_or_float(env.subs, env.ptr_bytes, precision, true) {
IntOrFloat::BinaryFloatType(precision) => Stmt::Let(
assigned,
Expr::Literal(Literal::Float(num as f64)),
Layout::Builtin(float_precision_to_builtin(precision)),
hole,
),
IntOrFloat::DecimalFloatType(precision) => Stmt::Let(
assigned,
Expr::Literal(Literal::Float(num as f64)),
Layout::Builtin(float_precision_to_builtin(precision)),
hole,
),
_ => unreachable!("unexpected float precision for integer"),
}
}
Str(string) => Stmt::Let( Str(string) => Stmt::Let(
assigned, assigned,
@ -2378,17 +2401,29 @@ pub fn with_hole<'a>(
hole, hole,
), ),
Num(var, num) => match num_argument_to_int_or_float(env.subs, var) { Num(var, num) => match num_argument_to_int_or_float(env.subs, env.ptr_bytes, var, false) {
IntOrFloat::IntType => Stmt::Let( IntOrFloat::SignedIntType(precision) => Stmt::Let(
assigned, assigned,
Expr::Literal(Literal::Int(num)), Expr::Literal(Literal::Int(num)),
Layout::Builtin(Builtin::Int64), Layout::Builtin(int_precision_to_builtin(precision)),
hole, hole,
), ),
IntOrFloat::FloatType => Stmt::Let( IntOrFloat::UnsignedIntType(precision) => Stmt::Let(
assigned,
Expr::Literal(Literal::Int(num)),
Layout::Builtin(int_precision_to_builtin(precision)),
hole,
),
IntOrFloat::BinaryFloatType(precision) => Stmt::Let(
assigned, assigned,
Expr::Literal(Literal::Float(num as f64)), Expr::Literal(Literal::Float(num as f64)),
Layout::Builtin(Builtin::Float64), Layout::Builtin(float_precision_to_builtin(precision)),
hole,
),
IntOrFloat::DecimalFloatType(precision) => Stmt::Let(
assigned,
Expr::Literal(Literal::Float(num as f64)),
Layout::Builtin(float_precision_to_builtin(precision)),
hole, hole,
), ),
}, },
@ -2778,7 +2813,7 @@ pub fn with_hole<'a>(
stmt = Stmt::Let( stmt = Stmt::Let(
tag_id_symbol, tag_id_symbol,
Expr::Literal(Literal::Int(tag_id as i64)), Expr::Literal(Literal::Int(tag_id as i64)),
Layout::Builtin(Builtin::Int64), Layout::Builtin(TAG_SIZE),
arena.alloc(stmt), arena.alloc(stmt),
); );
@ -4739,8 +4774,8 @@ fn store_pattern<'a>(
Underscore => { Underscore => {
// do nothing // do nothing
} }
IntLiteral(_) IntLiteral(_, _)
| FloatLiteral(_) | FloatLiteral(_, _)
| EnumLiteral { .. } | EnumLiteral { .. }
| BitLiteral { .. } | BitLiteral { .. }
| StrLiteral(_) => {} | StrLiteral(_) => {}
@ -4754,7 +4789,7 @@ fn store_pattern<'a>(
if write_tag { if write_tag {
// add an element for the tag discriminant // add an element for the tag discriminant
arg_layouts.push(Layout::Builtin(Builtin::Int64)); arg_layouts.push(Layout::Builtin(TAG_SIZE));
} }
for (_, layout) in arguments { for (_, layout) in arguments {
@ -4779,8 +4814,8 @@ fn store_pattern<'a>(
Underscore => { Underscore => {
// ignore // ignore
} }
IntLiteral(_) IntLiteral(_, _)
| FloatLiteral(_) | FloatLiteral(_, _)
| EnumLiteral { .. } | EnumLiteral { .. }
| BitLiteral { .. } | BitLiteral { .. }
| StrLiteral(_) => {} | StrLiteral(_) => {}
@ -4874,8 +4909,8 @@ fn store_record_destruct<'a>(
// //
// internally. But `y` is never used, so we must make sure it't not stored/loaded. // internally. But `y` is never used, so we must make sure it't not stored/loaded.
} }
IntLiteral(_) IntLiteral(_, _)
| FloatLiteral(_) | FloatLiteral(_, _)
| EnumLiteral { .. } | EnumLiteral { .. }
| BitLiteral { .. } | BitLiteral { .. }
| StrLiteral(_) => {} | StrLiteral(_) => {}
@ -5619,9 +5654,8 @@ fn call_by_name<'a>(
pub enum Pattern<'a> { pub enum Pattern<'a> {
Identifier(Symbol), Identifier(Symbol),
Underscore, Underscore,
IntLiteral(Variable, i64),
IntLiteral(i64), FloatLiteral(Variable, u64),
FloatLiteral(u64),
BitLiteral { BitLiteral {
value: bool, value: bool,
tag_name: TagName, tag_name: TagName,
@ -5694,23 +5728,28 @@ fn from_can_pattern_help<'a>(
match can_pattern { match can_pattern {
Underscore => Ok(Pattern::Underscore), Underscore => Ok(Pattern::Underscore),
Identifier(symbol) => Ok(Pattern::Identifier(*symbol)), Identifier(symbol) => Ok(Pattern::Identifier(*symbol)),
IntLiteral(v) => Ok(Pattern::IntLiteral(*v)), IntLiteral(precision_var, int) => Ok(Pattern::IntLiteral(*precision_var, *int)),
FloatLiteral(v) => Ok(Pattern::FloatLiteral(f64::to_bits(*v))), FloatLiteral(precision_var, float) => {
Ok(Pattern::FloatLiteral(*precision_var, f64::to_bits(*float)))
}
StrLiteral(v) => Ok(Pattern::StrLiteral(v.clone())), StrLiteral(v) => Ok(Pattern::StrLiteral(v.clone())),
Shadowed(region, ident) => Err(RuntimeError::Shadowing { Shadowed(region, ident) => Err(RuntimeError::Shadowing {
original_region: *region, original_region: *region,
shadow: ident.clone(), shadow: ident.clone(),
}), }),
UnsupportedPattern(region) => Err(RuntimeError::UnsupportedPattern(*region)), UnsupportedPattern(region) => Err(RuntimeError::UnsupportedPattern(*region)),
MalformedPattern(_problem, region) => { MalformedPattern(_problem, region) => {
// TODO preserve malformed problem information here? // TODO preserve malformed problem information here?
Err(RuntimeError::UnsupportedPattern(*region)) Err(RuntimeError::UnsupportedPattern(*region))
} }
NumLiteral(var, num) => match num_argument_to_int_or_float(env.subs, *var) { NumLiteral(var, num) => {
IntOrFloat::IntType => Ok(Pattern::IntLiteral(*num)), match num_argument_to_int_or_float(env.subs, env.ptr_bytes, *var, false) {
IntOrFloat::FloatType => Ok(Pattern::FloatLiteral(*num as u64)), IntOrFloat::SignedIntType(_) => Ok(Pattern::IntLiteral(*var, *num)),
}, IntOrFloat::UnsignedIntType(_) => Ok(Pattern::IntLiteral(*var, *num)),
IntOrFloat::BinaryFloatType(_) => Ok(Pattern::FloatLiteral(*var, *num as u64)),
IntOrFloat::DecimalFloatType(_) => Ok(Pattern::FloatLiteral(*var, *num as u64)),
}
}
AppliedTag { AppliedTag {
whole_var, whole_var,
@ -5798,13 +5837,11 @@ fn from_can_pattern_help<'a>(
let mut arguments = arguments.clone(); let mut arguments = arguments.clone();
arguments.sort_by(|arg1, arg2| { arguments.sort_by(|arg1, arg2| {
let ptr_bytes = 8;
let layout1 = layout_cache.from_var(env.arena, arg1.0, env.subs).unwrap(); let layout1 = layout_cache.from_var(env.arena, arg1.0, env.subs).unwrap();
let layout2 = layout_cache.from_var(env.arena, arg2.0, env.subs).unwrap(); let layout2 = layout_cache.from_var(env.arena, arg2.0, env.subs).unwrap();
let size1 = layout1.alignment_bytes(ptr_bytes); let size1 = layout1.alignment_bytes(env.ptr_bytes);
let size2 = layout2.alignment_bytes(ptr_bytes); let size2 = layout2.alignment_bytes(env.ptr_bytes);
size2.cmp(&size1) size2.cmp(&size1)
}); });
@ -5855,13 +5892,11 @@ fn from_can_pattern_help<'a>(
let mut arguments = arguments.clone(); let mut arguments = arguments.clone();
arguments.sort_by(|arg1, arg2| { arguments.sort_by(|arg1, arg2| {
let ptr_bytes = 8;
let layout1 = layout_cache.from_var(env.arena, arg1.0, env.subs).unwrap(); let layout1 = layout_cache.from_var(env.arena, arg1.0, env.subs).unwrap();
let layout2 = layout_cache.from_var(env.arena, arg2.0, env.subs).unwrap(); let layout2 = layout_cache.from_var(env.arena, arg2.0, env.subs).unwrap();
let size1 = layout1.alignment_bytes(ptr_bytes); let size1 = layout1.alignment_bytes(env.ptr_bytes);
let size2 = layout2.alignment_bytes(ptr_bytes); let size2 = layout2.alignment_bytes(env.ptr_bytes);
size2.cmp(&size1) size2.cmp(&size1)
}); });
@ -6084,40 +6119,150 @@ fn optimize_low_level(
} }
} }
pub enum IntPrecision {
I128,
I64,
I32,
I16,
I8,
}
pub enum FloatPrecision {
F64,
F32,
}
pub enum IntOrFloat { pub enum IntOrFloat {
IntType, SignedIntType(IntPrecision),
FloatType, UnsignedIntType(IntPrecision),
BinaryFloatType(FloatPrecision),
DecimalFloatType(FloatPrecision),
}
fn float_precision_to_builtin(precision: FloatPrecision) -> Builtin<'static> {
use FloatPrecision::*;
match precision {
F64 => Builtin::Float64,
F32 => Builtin::Float32,
}
}
fn int_precision_to_builtin(precision: IntPrecision) -> Builtin<'static> {
use IntPrecision::*;
match precision {
I128 => Builtin::Int128,
I64 => Builtin::Int64,
I32 => Builtin::Int32,
I16 => Builtin::Int16,
I8 => Builtin::Int8,
}
} }
/// Given the `a` in `Num a`, determines whether it's an int or a float /// Given the `a` in `Num a`, determines whether it's an int or a float
pub fn num_argument_to_int_or_float(subs: &Subs, var: Variable) -> IntOrFloat { pub fn num_argument_to_int_or_float(
subs: &Subs,
ptr_bytes: u32,
var: Variable,
known_to_be_float: bool,
) -> IntOrFloat {
match subs.get_without_compacting(var).content { match subs.get_without_compacting(var).content {
Content::FlexVar(_) if known_to_be_float => IntOrFloat::BinaryFloatType(FloatPrecision::F64),
Content::FlexVar(_) => IntOrFloat::SignedIntType(IntPrecision::I64), // We default (Num *) to I64
Content::Alias(Symbol::NUM_INTEGER, args, _) => { Content::Alias(Symbol::NUM_INTEGER, args, _) => {
debug_assert!(args.len() == 1); debug_assert!(args.len() == 1);
// TODO: we probably need to match on the type of the arg // Recurse on the second argument
IntOrFloat::IntType num_argument_to_int_or_float(subs, ptr_bytes, args[0].1, false)
} }
Content::FlexVar(_) => {
// If this was still a (Num *), assume compiling it to an Int
IntOrFloat::IntType
}
Content::Alias(Symbol::NUM_FLOATINGPOINT, args, _) => {
debug_assert!(args.len() == 1);
// TODO: we probably need to match on the type of the arg Content::Alias(Symbol::NUM_I128, _, _)
IntOrFloat::FloatType | Content::Alias(Symbol::NUM_SIGNED128, _, _)
| Content::Alias(Symbol::NUM_AT_SIGNED128, _, _) => {
IntOrFloat::SignedIntType(IntPrecision::I128)
}
Content::Alias(Symbol::NUM_INT, _, _)// We default Integer to I64
| Content::Alias(Symbol::NUM_I64, _, _)
| Content::Alias(Symbol::NUM_SIGNED64, _, _)
| Content::Alias(Symbol::NUM_AT_SIGNED64, _, _) => {
IntOrFloat::SignedIntType(IntPrecision::I64)
}
Content::Alias(Symbol::NUM_I32, _, _)
| Content::Alias(Symbol::NUM_SIGNED32, _, _)
| Content::Alias(Symbol::NUM_AT_SIGNED32, _, _) => {
IntOrFloat::SignedIntType(IntPrecision::I32)
}
Content::Alias(Symbol::NUM_I16, _, _)
| Content::Alias(Symbol::NUM_SIGNED16, _, _)
| Content::Alias(Symbol::NUM_AT_SIGNED16, _, _) => {
IntOrFloat::SignedIntType(IntPrecision::I16)
}
Content::Alias(Symbol::NUM_I8, _, _)
| Content::Alias(Symbol::NUM_SIGNED8, _, _)
| Content::Alias(Symbol::NUM_AT_SIGNED8, _, _) => {
IntOrFloat::SignedIntType(IntPrecision::I8)
}
Content::Alias(Symbol::NUM_U128, _, _)
| Content::Alias(Symbol::NUM_UNSIGNED128, _, _)
| Content::Alias(Symbol::NUM_AT_UNSIGNED128, _, _) => {
IntOrFloat::UnsignedIntType(IntPrecision::I128)
}
Content::Alias(Symbol::NUM_U64, _, _)
| Content::Alias(Symbol::NUM_UNSIGNED64, _, _)
| Content::Alias(Symbol::NUM_AT_UNSIGNED64, _, _) => {
IntOrFloat::UnsignedIntType(IntPrecision::I64)
}
Content::Alias(Symbol::NUM_U32, _, _)
| Content::Alias(Symbol::NUM_UNSIGNED32, _, _)
| Content::Alias(Symbol::NUM_AT_UNSIGNED32, _, _) => {
IntOrFloat::UnsignedIntType(IntPrecision::I32)
}
Content::Alias(Symbol::NUM_U16, _, _)
| Content::Alias(Symbol::NUM_UNSIGNED16, _, _)
| Content::Alias(Symbol::NUM_AT_UNSIGNED16, _, _) => {
IntOrFloat::UnsignedIntType(IntPrecision::I16)
}
Content::Alias(Symbol::NUM_U8, _, _)
| Content::Alias(Symbol::NUM_UNSIGNED8, _, _)
| Content::Alias(Symbol::NUM_AT_UNSIGNED8, _, _) => {
IntOrFloat::UnsignedIntType(IntPrecision::I8)
} }
Content::Structure(FlatType::Apply(Symbol::ATTR_ATTR, attr_args)) => { Content::Structure(FlatType::Apply(Symbol::ATTR_ATTR, attr_args)) => {
debug_assert!(attr_args.len() == 2); debug_assert!(attr_args.len() == 2);
// Recurse on the second argument // Recurse on the second argument
num_argument_to_int_or_float(subs, attr_args[1]) num_argument_to_int_or_float(subs, ptr_bytes, attr_args[1], false)
} }
Content::Alias(Symbol::NUM_F64, args, _) | Content::Alias(Symbol::NUM_F32, args, _) => { Content::Alias(Symbol::NUM_FLOATINGPOINT, args, _) => {
debug_assert!(args.is_empty()); debug_assert!(args.len() == 1);
IntOrFloat::FloatType // Recurse on the second argument
num_argument_to_int_or_float(subs, ptr_bytes, args[0].1, true)
}
Content::Alias(Symbol::NUM_FLOAT, _, _) // We default FloatingPoint to F64
| Content::Alias(Symbol::NUM_F64, _, _)
| Content::Alias(Symbol::NUM_BINARY64, _, _)
| Content::Alias(Symbol::NUM_AT_BINARY64, _, _) => {
IntOrFloat::BinaryFloatType(FloatPrecision::F64)
}
Content::Alias(Symbol::NUM_F32, _, _)
| Content::Alias(Symbol::NUM_BINARY32, _, _)
| Content::Alias(Symbol::NUM_AT_BINARY32, _, _) => {
IntOrFloat::BinaryFloatType(FloatPrecision::F32)
}
Content::Alias(Symbol::NUM_NAT, _, _)
| Content::Alias(Symbol::NUM_NATURAL, _, _)
| Content::Alias(Symbol::NUM_AT_NATURAL, _, _) => {
match ptr_bytes {
1 => IntOrFloat::UnsignedIntType(IntPrecision::I8),
2 => IntOrFloat::UnsignedIntType(IntPrecision::I16),
4 => IntOrFloat::UnsignedIntType(IntPrecision::I32),
8 => IntOrFloat::UnsignedIntType(IntPrecision::I64),
_ => panic!(
"Invalid target for Num type arguement: Roc does't support compiling to {}-bit systems.",
ptr_bytes * 8
),
}
} }
other => { other => {
panic!( panic!(

View file

@ -11,6 +11,7 @@ pub const MAX_ENUM_SIZE: usize = (std::mem::size_of::<u8>() * 8) as usize;
/// If a (Num *) gets translated to a Layout, this is the numeric type it defaults to. /// If a (Num *) gets translated to a Layout, this is the numeric type it defaults to.
const DEFAULT_NUM_BUILTIN: Builtin<'_> = Builtin::Int64; const DEFAULT_NUM_BUILTIN: Builtin<'_> = Builtin::Int64;
pub const TAG_SIZE: Builtin<'_> = Builtin::Int64;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum LayoutProblem { pub enum LayoutProblem {
@ -312,6 +313,7 @@ pub enum Builtin<'a> {
Int16, Int16,
Int8, Int8,
Int1, Int1,
Usize,
Float128, Float128,
Float64, Float64,
Float32, Float32,
@ -362,14 +364,60 @@ impl<'a> Layout<'a> {
} }
Structure(flat_type) => layout_from_flat_type(env, flat_type), Structure(flat_type) => layout_from_flat_type(env, flat_type),
// Ints
Alias(Symbol::NUM_I128, args, _) => {
debug_assert!(args.is_empty());
Ok(Layout::Builtin(Builtin::Int128))
}
Alias(Symbol::NUM_I64, args, _) => { Alias(Symbol::NUM_I64, args, _) => {
debug_assert!(args.is_empty()); debug_assert!(args.is_empty());
Ok(Layout::Builtin(Builtin::Int64)) Ok(Layout::Builtin(Builtin::Int64))
} }
Alias(Symbol::NUM_I32, args, _) => {
debug_assert!(args.is_empty());
Ok(Layout::Builtin(Builtin::Int32))
}
Alias(Symbol::NUM_I16, args, _) => {
debug_assert!(args.is_empty());
Ok(Layout::Builtin(Builtin::Int16))
}
Alias(Symbol::NUM_I8, args, _) => {
debug_assert!(args.is_empty());
Ok(Layout::Builtin(Builtin::Int8))
}
// I think unsigned and signed use the same layout
Alias(Symbol::NUM_U128, args, _) => {
debug_assert!(args.is_empty());
Ok(Layout::Builtin(Builtin::Int128))
}
Alias(Symbol::NUM_U64, args, _) => {
debug_assert!(args.is_empty());
Ok(Layout::Builtin(Builtin::Int64))
}
Alias(Symbol::NUM_U32, args, _) => {
debug_assert!(args.is_empty());
Ok(Layout::Builtin(Builtin::Int32))
}
Alias(Symbol::NUM_U16, args, _) => {
debug_assert!(args.is_empty());
Ok(Layout::Builtin(Builtin::Int16))
}
Alias(Symbol::NUM_U8, args, _) => {
debug_assert!(args.is_empty());
Ok(Layout::Builtin(Builtin::Int8))
}
// Floats
Alias(Symbol::NUM_F64, args, _) => { Alias(Symbol::NUM_F64, args, _) => {
debug_assert!(args.is_empty()); debug_assert!(args.is_empty());
Ok(Layout::Builtin(Builtin::Float64)) Ok(Layout::Builtin(Builtin::Float64))
} }
Alias(Symbol::NUM_F32, args, _) => {
debug_assert!(args.is_empty());
Ok(Layout::Builtin(Builtin::Float32))
}
Alias(_, _, var) => Self::from_var(env, var), Alias(_, _, var) => Self::from_var(env, var),
Error => Err(LayoutProblem::Erroneous), Error => Err(LayoutProblem::Erroneous),
} }
@ -654,6 +702,7 @@ impl<'a> Builtin<'a> {
const I16_SIZE: u32 = std::mem::size_of::<i16>() as u32; const I16_SIZE: u32 = std::mem::size_of::<i16>() as u32;
const I8_SIZE: u32 = std::mem::size_of::<i8>() as u32; const I8_SIZE: u32 = std::mem::size_of::<i8>() as u32;
const I1_SIZE: u32 = std::mem::size_of::<bool>() as u32; const I1_SIZE: u32 = std::mem::size_of::<bool>() as u32;
const USIZE_SIZE: u32 = std::mem::size_of::<usize>() as u32;
const F128_SIZE: u32 = 16; const F128_SIZE: u32 = 16;
const F64_SIZE: u32 = std::mem::size_of::<f64>() as u32; const F64_SIZE: u32 = std::mem::size_of::<f64>() as u32;
const F32_SIZE: u32 = std::mem::size_of::<f32>() as u32; const F32_SIZE: u32 = std::mem::size_of::<f32>() as u32;
@ -682,6 +731,7 @@ impl<'a> Builtin<'a> {
Int16 => Builtin::I16_SIZE, Int16 => Builtin::I16_SIZE,
Int8 => Builtin::I8_SIZE, Int8 => Builtin::I8_SIZE,
Int1 => Builtin::I1_SIZE, Int1 => Builtin::I1_SIZE,
Usize => Builtin::USIZE_SIZE,
Float128 => Builtin::F128_SIZE, Float128 => Builtin::F128_SIZE,
Float64 => Builtin::F64_SIZE, Float64 => Builtin::F64_SIZE,
Float32 => Builtin::F32_SIZE, Float32 => Builtin::F32_SIZE,
@ -707,6 +757,7 @@ impl<'a> Builtin<'a> {
Int16 => align_of::<i16>() as u32, Int16 => align_of::<i16>() as u32,
Int8 => align_of::<i8>() as u32, Int8 => align_of::<i8>() as u32,
Int1 => align_of::<bool>() as u32, Int1 => align_of::<bool>() as u32,
Usize => align_of::<usize>() as u32,
Float128 => align_of::<i128>() as u32, Float128 => align_of::<i128>() as u32,
Float64 => align_of::<f64>() as u32, Float64 => align_of::<f64>() as u32,
Float32 => align_of::<f32>() as u32, Float32 => align_of::<f32>() as u32,
@ -722,7 +773,7 @@ impl<'a> Builtin<'a> {
use Builtin::*; use Builtin::*;
match self { match self {
Int128 | Int64 | Int32 | Int16 | Int8 | Int1 | Float128 | Float64 | Float32 Int128 | Int64 | Int32 | Int16 | Int8 | Int1 | Usize | Float128 | Float64 | Float32
| Float16 | EmptyStr | EmptyDict | EmptyList | EmptySet => true, | Float16 | EmptyStr | EmptyDict | EmptyList | EmptySet => true,
Str | Dict(_, _) | Set(_) | List(_, _) => false, Str | Dict(_, _) | Set(_) | List(_, _) => false,
} }
@ -733,7 +784,7 @@ impl<'a> Builtin<'a> {
use Builtin::*; use Builtin::*;
match self { match self {
Int128 | Int64 | Int32 | Int16 | Int8 | Int1 | Float128 | Float64 | Float32 Int128 | Int64 | Int32 | Int16 | Int8 | Int1 | Usize | Float128 | Float64 | Float32
| Float16 | EmptyStr | EmptyDict | EmptyList | EmptySet => false, | Float16 | EmptyStr | EmptyDict | EmptyList | EmptySet => false,
List(mode, element_layout) => match mode { List(mode, element_layout) => match mode {
MemoryMode::Refcounted => true, MemoryMode::Refcounted => true,
@ -757,14 +808,64 @@ fn layout_from_flat_type<'a>(
match flat_type { match flat_type {
Apply(symbol, args) => { Apply(symbol, args) => {
match symbol { match symbol {
// Ints
Symbol::NUM_NAT => {
debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Usize))
}
Symbol::NUM_I128 => {
debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Int128))
}
Symbol::NUM_I64 => { Symbol::NUM_I64 => {
debug_assert_eq!(args.len(), 0); debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Int64)) Ok(Layout::Builtin(Builtin::Int64))
} }
Symbol::NUM_I32 => {
debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Int32))
}
Symbol::NUM_I16 => {
debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Int16))
}
Symbol::NUM_I8 => {
debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Int8))
}
Symbol::NUM_U128 => {
debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Int128))
}
Symbol::NUM_U64 => {
debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Int64))
}
Symbol::NUM_U32 => {
debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Int32))
}
Symbol::NUM_U16 => {
debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Int16))
}
Symbol::NUM_U8 => {
debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Int8))
}
// Floats
Symbol::NUM_F64 => { Symbol::NUM_F64 => {
debug_assert_eq!(args.len(), 0); debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Float64)) Ok(Layout::Builtin(Builtin::Float64))
} }
Symbol::NUM_F32 => {
debug_assert_eq!(args.len(), 0);
Ok(Layout::Builtin(Builtin::Float32))
}
Symbol::NUM_NUM | Symbol::NUM_AT_NUM => { Symbol::NUM_NUM | Symbol::NUM_AT_NUM => {
// Num.Num should only ever have 1 argument, e.g. Num.Num Int.Integer // Num.Num should only ever have 1 argument, e.g. Num.Num Int.Integer
debug_assert_eq!(args.len(), 1); debug_assert_eq!(args.len(), 1);
@ -774,6 +875,7 @@ fn layout_from_flat_type<'a>(
layout_from_num_content(content) layout_from_num_content(content)
} }
Symbol::STR_STR => Ok(Layout::Builtin(Builtin::Str)), Symbol::STR_STR => Ok(Layout::Builtin(Builtin::Str)),
Symbol::LIST_LIST => list_layout_from_elem(env, args[0]), Symbol::LIST_LIST => list_layout_from_elem(env, args[0]),
Symbol::ATTR_ATTR => { Symbol::ATTR_ATTR => {
@ -888,7 +990,7 @@ fn layout_from_flat_type<'a>(
let mut tag_layout = Vec::with_capacity_in(variables.len() + 1, arena); let mut tag_layout = Vec::with_capacity_in(variables.len() + 1, arena);
// store the discriminant // store the discriminant
tag_layout.push(Layout::Builtin(Builtin::Int64)); tag_layout.push(Layout::Builtin(TAG_SIZE));
for var in variables { for var in variables {
// TODO does this cause problems with mutually recursive unions? // TODO does this cause problems with mutually recursive unions?
@ -1119,7 +1221,7 @@ pub fn union_sorted_tags_help<'a>(
let mut arg_layouts = Vec::with_capacity_in(arguments.len() + 1, arena); let mut arg_layouts = Vec::with_capacity_in(arguments.len() + 1, arena);
// add the tag discriminant (size currently always hardcoded to i64) // add the tag discriminant (size currently always hardcoded to i64)
arg_layouts.push(Layout::Builtin(Builtin::Int64)); arg_layouts.push(Layout::Builtin(TAG_SIZE));
for var in arguments { for var in arguments {
match Layout::from_var(&mut env, var) { match Layout::from_var(&mut env, var) {
@ -1257,8 +1359,27 @@ fn layout_from_num_content<'a>(content: Content) -> Result<Layout<'a>, LayoutPro
Ok(Layout::Builtin(DEFAULT_NUM_BUILTIN)) Ok(Layout::Builtin(DEFAULT_NUM_BUILTIN))
} }
Structure(Apply(symbol, args)) => match symbol { Structure(Apply(symbol, args)) => match symbol {
// Ints
Symbol::NUM_NAT => Ok(Layout::Builtin(Builtin::Usize)),
Symbol::NUM_INTEGER => Ok(Layout::Builtin(Builtin::Int64)), Symbol::NUM_INTEGER => Ok(Layout::Builtin(Builtin::Int64)),
Symbol::NUM_I128 => Ok(Layout::Builtin(Builtin::Int128)),
Symbol::NUM_I64 => Ok(Layout::Builtin(Builtin::Int64)),
Symbol::NUM_I32 => Ok(Layout::Builtin(Builtin::Int32)),
Symbol::NUM_I16 => Ok(Layout::Builtin(Builtin::Int16)),
Symbol::NUM_I8 => Ok(Layout::Builtin(Builtin::Int8)),
Symbol::NUM_U128 => Ok(Layout::Builtin(Builtin::Int128)),
Symbol::NUM_U64 => Ok(Layout::Builtin(Builtin::Int64)),
Symbol::NUM_U32 => Ok(Layout::Builtin(Builtin::Int32)),
Symbol::NUM_U16 => Ok(Layout::Builtin(Builtin::Int16)),
Symbol::NUM_U8 => Ok(Layout::Builtin(Builtin::Int8)),
// Floats
Symbol::NUM_FLOATINGPOINT => Ok(Layout::Builtin(Builtin::Float64)), Symbol::NUM_FLOATINGPOINT => Ok(Layout::Builtin(Builtin::Float64)),
Symbol::NUM_F64 => Ok(Layout::Builtin(Builtin::Float64)),
Symbol::NUM_F32 => Ok(Layout::Builtin(Builtin::Float32)),
_ => { _ => {
panic!( panic!(
"Invalid Num.Num type application: {:?}", "Invalid Num.Num type application: {:?}",
@ -1293,17 +1414,63 @@ fn unwrap_num_tag<'a>(subs: &Subs, var: Variable) -> Result<Layout<'a>, LayoutPr
Content::Alias(Symbol::NUM_INTEGER, args, _) => { Content::Alias(Symbol::NUM_INTEGER, args, _) => {
debug_assert!(args.len() == 1); debug_assert!(args.len() == 1);
// TODO: we probably need to match on the type of the arg let (_, precision_var) = args[0];
// and return the correct builtin ex: Builtin::{Int32, Int16}
let precision = subs.get_without_compacting(precision_var).content;
match precision {
Content::Alias(symbol, args, _) => {
debug_assert!(args.is_empty());
let builtin = match symbol {
Symbol::NUM_SIGNED128 => Builtin::Int128,
Symbol::NUM_SIGNED64 => Builtin::Int64,
Symbol::NUM_SIGNED32 => Builtin::Int32,
Symbol::NUM_SIGNED16 => Builtin::Int16,
Symbol::NUM_SIGNED8 => Builtin::Int8,
Symbol::NUM_UNSIGNED128 => Builtin::Int128,
Symbol::NUM_UNSIGNED64 => Builtin::Int64,
Symbol::NUM_UNSIGNED32 => Builtin::Int32,
Symbol::NUM_UNSIGNED16 => Builtin::Int16,
Symbol::NUM_UNSIGNED8 => Builtin::Int8,
Symbol::NUM_NATURAL => Builtin::Usize,
_ => unreachable!("not a valid int variant: {:?} {:?}", symbol, args),
};
Ok(Layout::Builtin(builtin))
}
Content::FlexVar(_) | Content::RigidVar(_) => {
// default to i64
Ok(Layout::Builtin(Builtin::Int64)) Ok(Layout::Builtin(Builtin::Int64))
} }
_ => unreachable!("not a valid int variant: {:?}", precision),
}
}
Content::Alias(Symbol::NUM_FLOATINGPOINT, args, _) => { Content::Alias(Symbol::NUM_FLOATINGPOINT, args, _) => {
debug_assert!(args.len() == 1); debug_assert!(args.len() == 1);
// TODO: we probably need to match on the type of the arg let (_, precision_var) = args[0];
// and return the correct builtin ex: Builtin::Float32
let precision = subs.get_without_compacting(precision_var).content;
match precision {
Content::Alias(Symbol::NUM_BINARY32, args, _) => {
debug_assert!(args.is_empty());
Ok(Layout::Builtin(Builtin::Float32))
}
Content::Alias(Symbol::NUM_BINARY64, args, _) => {
debug_assert!(args.is_empty());
Ok(Layout::Builtin(Builtin::Float64)) Ok(Layout::Builtin(Builtin::Float64))
} }
Content::FlexVar(_) | Content::RigidVar(_) => {
// default to f64
Ok(Layout::Builtin(Builtin::Float64))
}
_ => unreachable!("not a valid float variant: {:?}", precision),
}
}
Content::FlexVar(_) | Content::RigidVar(_) => { Content::FlexVar(_) | Content::RigidVar(_) => {
// If this was still a (Num *) then default to compiling it to i64 // If this was still a (Num *) then default to compiling it to i64
Ok(Layout::Builtin(DEFAULT_NUM_BUILTIN)) Ok(Layout::Builtin(DEFAULT_NUM_BUILTIN))

View file

@ -61,6 +61,7 @@ mod test_mono {
stdlib, stdlib,
src_dir, src_dir,
exposed_types, exposed_types,
8,
); );
let mut loaded = loaded.expect("failed to load module"); let mut loaded = loaded.expect("failed to load module");

View file

@ -1624,8 +1624,8 @@ fn to_diff<'b>(
let right = to_doc(alloc, Parens::Unnecessary, type2); let right = to_doc(alloc, Parens::Unnecessary, type2);
let is_int = |t: &ErrorType| match t { let is_int = |t: &ErrorType| match t {
ErrorType::Type(Symbol::NUM_I64, _) => true, ErrorType::Type(Symbol::NUM_INT, _) => true,
ErrorType::Alias(Symbol::NUM_I64, _, _) => true, ErrorType::Alias(Symbol::NUM_INT, _, _) => true,
ErrorType::Type(Symbol::NUM_NUM, args) => { ErrorType::Type(Symbol::NUM_NUM, args) => {
matches!( &args.get(0) ,Some(ErrorType::Type(Symbol::NUM_INTEGER, _)) | Some(ErrorType::Alias(Symbol::NUM_INTEGER, _, _))) matches!( &args.get(0) ,Some(ErrorType::Type(Symbol::NUM_INTEGER, _)) | Some(ErrorType::Alias(Symbol::NUM_INTEGER, _, _)))
@ -1636,8 +1636,8 @@ fn to_diff<'b>(
_ => false, _ => false,
}; };
let is_float = |t: &ErrorType| match t { let is_float = |t: &ErrorType| match t {
ErrorType::Type(Symbol::NUM_F64, _) => true, ErrorType::Type(Symbol::NUM_FLOAT, _) => true,
ErrorType::Alias(Symbol::NUM_F64, _, _) => true, ErrorType::Alias(Symbol::NUM_FLOAT, _, _) => true,
ErrorType::Type(Symbol::NUM_NUM, args) => { ErrorType::Type(Symbol::NUM_NUM, args) => {
matches!(&args.get(0), Some(ErrorType::Type(Symbol::NUM_FLOATINGPOINT, _)) | Some(ErrorType::Alias(Symbol::NUM_FLOATINGPOINT, _, _))) matches!(&args.get(0), Some(ErrorType::Type(Symbol::NUM_FLOATINGPOINT, _)) | Some(ErrorType::Alias(Symbol::NUM_FLOATINGPOINT, _, _)))
@ -1891,7 +1891,7 @@ fn diff_tag_union<'b>(
alloc.tag_name(field.clone()), alloc.tag_name(field.clone()),
// TODO add spaces between args // TODO add spaces between args
args.iter() args.iter()
.map(|arg| to_doc(alloc, Parens::Unnecessary, arg.clone())) .map(|arg| to_doc(alloc, Parens::InTypeParam, arg.clone()))
.collect(), .collect(),
) )
}; };

View file

@ -94,6 +94,7 @@ mod test_reporting {
problems: &mut mono_problems, problems: &mut mono_problems,
home, home,
ident_ids: &mut ident_ids, ident_ids: &mut ident_ids,
ptr_bytes: 8,
}; };
let _mono_expr = Stmt::new( let _mono_expr = Stmt::new(
&mut mono_env, &mut mono_env,
@ -446,9 +447,9 @@ mod test_reporting {
these names seem close though: these names seem close though:
baz baz
Nat
Str Str
U8 U8
F64
"# "#
), ),
) )
@ -960,7 +961,7 @@ mod test_reporting {
r#" r#"
bar = { bar : 0x3 } bar = { bar : 0x3 }
f : { foo : I64 } -> Bool f : { foo : Int * } -> Bool
f = \_ -> True f = \_ -> True
f bar f bar
@ -977,11 +978,11 @@ mod test_reporting {
This `bar` value is a: This `bar` value is a:
{ bar : I64 } { bar : Int a }
But `f` needs the 1st argument to be: But `f` needs the 1st argument to be:
{ foo : I64 } { foo : Int a }
Tip: Seems like a record field typo. Maybe `bar` should be `foo`? Tip: Seems like a record field typo. Maybe `bar` should be `foo`?
@ -1036,7 +1037,7 @@ mod test_reporting {
report_problem_as( report_problem_as(
indoc!( indoc!(
r#" r#"
f : [ Red I64, Green Bool ] -> Bool f : [ Red (Int *), Green Bool ] -> Bool
f = \_ -> True f = \_ -> True
f (Blue 3.14) f (Blue 3.14)
@ -1053,11 +1054,11 @@ mod test_reporting {
This `Blue` global tag application has the type: This `Blue` global tag application has the type:
[ Blue F64 ]a [ Blue (Float a) ]b
But `f` needs the 1st argument to be: But `f` needs the 1st argument to be:
[ Green Bool, Red I64 ] [ Green Bool, Red (Int a) ]
Tip: Seems like a tag typo. Maybe `Blue` should be `Red`? Tip: Seems like a tag typo. Maybe `Blue` should be `Red`?
@ -1074,7 +1075,7 @@ mod test_reporting {
report_problem_as( report_problem_as(
indoc!( indoc!(
r#" r#"
x : I64 x : Int *
x = if True then 3.14 else 4 x = if True then 3.14 else 4
x x
@ -1091,11 +1092,11 @@ mod test_reporting {
The 1st branch is a float of type: The 1st branch is a float of type:
F64 Float a
But the type annotation on `x` says it should be: But the type annotation on `x` says it should be:
I64 Int b
Tip: You can convert between Int and Float using functions like Tip: You can convert between Int and Float using functions like
`Num.toFloat` and `Num.round`. `Num.toFloat` and `Num.round`.
@ -1109,7 +1110,7 @@ mod test_reporting {
report_problem_as( report_problem_as(
indoc!( indoc!(
r#" r#"
x : I64 x : Int *
x = x =
when True is when True is
_ -> 3.14 _ -> 3.14
@ -1123,18 +1124,18 @@ mod test_reporting {
Something is off with the body of the `x` definition: Something is off with the body of the `x` definition:
1 x : I64 1 x : Int *
2 x = 2 x =
3> when True is 3> when True is
4> _ -> 3.14 4> _ -> 3.14
This `when`expression produces: This `when`expression produces:
F64 Float a
But the type annotation on `x` says it should be: But the type annotation on `x` says it should be:
I64 Int b
Tip: You can convert between Int and Float using functions like Tip: You can convert between Int and Float using functions like
`Num.toFloat` and `Num.round`. `Num.toFloat` and `Num.round`.
@ -1148,7 +1149,7 @@ mod test_reporting {
report_problem_as( report_problem_as(
indoc!( indoc!(
r#" r#"
x : I64 -> I64 x : Int * -> Int *
x = \_ -> 3.14 x = \_ -> 3.14
x x
@ -1160,17 +1161,17 @@ mod test_reporting {
Something is off with the body of the `x` definition: Something is off with the body of the `x` definition:
1 x : I64 -> I64 1 x : Int * -> Int *
2 x = \_ -> 3.14 2 x = \_ -> 3.14
^^^^ ^^^^
The body is a float of type: The body is a float of type:
F64 Float a
But the type annotation on `x` says it should be: But the type annotation on `x` says it should be:
I64 Int b
Tip: You can convert between Int and Float using functions like Tip: You can convert between Int and Float using functions like
`Num.toFloat` and `Num.round`. `Num.toFloat` and `Num.round`.
@ -1373,7 +1374,7 @@ mod test_reporting {
Bool Bool
U8 U8
F64 F64
Str Nat
"# "#
), ),
) )
@ -1482,7 +1483,7 @@ mod test_reporting {
report_problem_as( report_problem_as(
indoc!( indoc!(
r#" r#"
{ x } : { x : I64 } { x } : { x : Int * }
{ x } = { x: 4.0 } { x } = { x: 4.0 }
x x
@ -1494,17 +1495,17 @@ mod test_reporting {
Something is off with the body of this definition: Something is off with the body of this definition:
1 { x } : { x : I64 } 1 { x } : { x : Int * }
2 { x } = { x: 4.0 } 2 { x } = { x: 4.0 }
^^^^^^^^^^ ^^^^^^^^^^
The body is a record of type: The body is a record of type:
{ x : F64 } { x : Float a }
But the type annotation says it should be: But the type annotation says it should be:
{ x : I64 } { x : Int b }
Tip: You can convert between Int and Float using functions like Tip: You can convert between Int and Float using functions like
`Num.toFloat` and `Num.round`. `Num.toFloat` and `Num.round`.
@ -1643,7 +1644,7 @@ mod test_reporting {
report_problem_as( report_problem_as(
indoc!( indoc!(
r#" r#"
x : { a : I64, b : F64, c : Bool } x : { a : Int *, b : Float *, c : Bool }
x = { b: 4.0 } x = { b: 4.0 }
x x
@ -1655,17 +1656,17 @@ mod test_reporting {
Something is off with the body of the `x` definition: Something is off with the body of the `x` definition:
1 x : { a : I64, b : F64, c : Bool } 1 x : { a : Int *, b : Float *, c : Bool }
2 x = { b: 4.0 } 2 x = { b: 4.0 }
^^^^^^^^^^ ^^^^^^^^^^
The body is a record of type: The body is a record of type:
{ b : F64 } { b : Float a }
But the type annotation on `x` says it should be: But the type annotation on `x` says it should be:
{ a : I64, b : F64, c : Bool } { a : Int a, b : Float b, c : Bool }
Tip: Looks like the c and a fields are missing. Tip: Looks like the c and a fields are missing.
"# "#
@ -1787,7 +1788,7 @@ mod test_reporting {
The body is an integer of type: The body is an integer of type:
I64 Int a
But the type annotation on `f` says it should be: But the type annotation on `f` says it should be:
@ -1795,7 +1796,7 @@ mod test_reporting {
Tip: The type annotation uses the type variable `msg` to say that this Tip: The type annotation uses the type variable `msg` 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 `I64` value of a single specific type. Maybe it will only produce a `Int` 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?
"# "#
@ -2093,7 +2094,7 @@ mod test_reporting {
But `add` needs the 2nd argument to be: But `add` needs the 2nd argument to be:
Num (Integer Signed64) Num (Integer a)
"# "#
), ),
) )
@ -2118,11 +2119,11 @@ mod test_reporting {
This argument is a float of type: This argument is a float of type:
F64 Float a
But `add` needs the 2nd argument to be: But `add` needs the 2nd argument to be:
Num (Integer Signed64) Num (Integer a)
Tip: You can convert between Int and Float using functions like Tip: You can convert between Int and Float using functions like
`Num.toFloat` and `Num.round`. `Num.toFloat` and `Num.round`.
@ -2580,9 +2581,9 @@ mod test_reporting {
report_problem_as( report_problem_as(
indoc!( indoc!(
r#" r#"
Foo : { x : I64 } Foo : { x : Int * }
f : Foo -> I64 f : Foo -> Int *
f = \r -> r.x f = \r -> r.x
f { y: 3.14 } f { y: 3.14 }
@ -2600,11 +2601,11 @@ mod test_reporting {
This argument is a record of type: This argument is a record of type:
{ y : F64 } { y : Float a }
But `f` needs the 1st argument to be: But `f` needs the 1st argument to be:
{ x : I64 } { x : Int a }
Tip: Seems like a record field typo. Maybe `y` should be `x`? Tip: Seems like a record field typo. Maybe `y` should be `x`?

View file

@ -62,6 +62,7 @@ mod solve_expr {
stdlib, stdlib,
dir.path(), dir.path(),
exposed_types, exposed_types,
8,
); );
dir.close()?; dir.close()?;
@ -169,7 +170,7 @@ mod solve_expr {
#[test] #[test]
fn float_literal() { fn float_literal() {
infer_eq("0.5", "F64"); infer_eq("0.5", "Float *");
} }
#[test] #[test]
@ -762,7 +763,7 @@ mod solve_expr {
(\a -> a) 3.14 (\a -> a) 3.14
"# "#
), ),
"F64", "Float *",
); );
} }
@ -1026,7 +1027,7 @@ mod solve_expr {
#[test] #[test]
fn two_field_record() { fn two_field_record() {
infer_eq("{ x: 5, y : 3.14 }", "{ x : Num *, y : F64 }"); infer_eq("{ x: 5, y : 3.14 }", "{ x : Num *, y : Float * }");
} }
#[test] #[test]
@ -2385,7 +2386,7 @@ mod solve_expr {
threePointZero threePointZero
"# "#
), ),
"F64", "Float *",
); );
} }
@ -2982,7 +2983,7 @@ mod solve_expr {
infer_eq_without_problem( infer_eq_without_problem(
indoc!( indoc!(
r#" r#"
partition : I64, I64, List I64 -> [ Pair I64 (List I64) ] partition : Int a, Int *, List (Int b) -> [ Pair (Int a) (List (Int b)) ]
partition = \low, high, initialList -> partition = \low, high, initialList ->
when List.get initialList high is when List.get initialList high is
Ok _ -> Ok _ ->
@ -2994,7 +2995,7 @@ mod solve_expr {
partition partition
"# "#
), ),
"I64, I64, List I64 -> [ Pair I64 (List I64) ]", "Int a, Int *, List (Int b) -> [ Pair (Int a) (List (Int b)) ]",
); );
} }
@ -3004,7 +3005,7 @@ mod solve_expr {
infer_eq_without_problem( infer_eq_without_problem(
indoc!( indoc!(
r#" r#"
swap : I64, I64, List a -> List a swap : Int *, Int *, List a -> List a
swap = \i, j, list -> swap = \i, j, list ->
when Pair (List.get list i) (List.get list j) is when Pair (List.get list i) (List.get list j) is
Pair (Ok atI) (Ok atJ) -> Pair (Ok atI) (Ok atJ) ->
@ -3015,7 +3016,7 @@ mod solve_expr {
_ -> _ ->
list list
partition : I64, I64, List I64 -> [ Pair I64 (List I64) ] partition : I64, I64, List (Int a) -> [ Pair I64 (List (Int a)) ]
partition = \low, high, initialList -> partition = \low, high, initialList ->
when List.get initialList high is when List.get initialList high is
Ok pivot -> Ok pivot ->
@ -3043,7 +3044,7 @@ mod solve_expr {
partition partition
"# "#
), ),
"I64, I64, List I64 -> [ Pair I64 (List I64) ]", "I64, I64, List (Int a) -> [ Pair I64 (List (Int a)) ]",
); );
}); });
} }
@ -3077,6 +3078,15 @@ mod solve_expr {
), ),
"Result (Num *) [ OutOfBounds ]*", "Result (Num *) [ OutOfBounds ]*",
); );
infer_eq_without_problem(
indoc!(
r#"
List.get
"#
),
"List a, Int * -> Result a [ OutOfBounds ]*",
);
} }
#[test] #[test]
@ -3117,7 +3127,7 @@ mod solve_expr {
Num.toFloat Num.toFloat
"# "#
), ),
"Num * -> F64", "Num * -> Float *",
); );
} }
@ -3129,7 +3139,7 @@ mod solve_expr {
Num.pow Num.pow
"# "#
), ),
"F64, F64 -> F64", "Float a, Float a -> Float a",
); );
} }
@ -3141,7 +3151,7 @@ mod solve_expr {
Num.ceiling Num.ceiling
"# "#
), ),
"F64 -> I64", "Float * -> Int *",
); );
} }
@ -3153,7 +3163,7 @@ mod solve_expr {
Num.floor Num.floor
"# "#
), ),
"F64 -> I64", "Float * -> Int *",
); );
} }
@ -3165,7 +3175,7 @@ mod solve_expr {
Num.powInt Num.powInt
"# "#
), ),
"I64, I64 -> I64", "Int a, Int a -> Int a",
); );
} }
@ -3177,7 +3187,7 @@ mod solve_expr {
Num.atan Num.atan
"# "#
), ),
"F64 -> F64", "Float a -> Float a",
); );
} }
@ -3444,7 +3454,7 @@ mod solve_expr {
negatePoint { x: 1, y: 2.1, z: 0x3 } negatePoint { x: 1, y: 2.1, z: 0x3 }
"# "#
), ),
"{ x : Num a, y : F64, z : I64 }", "{ x : Num a, y : F64, z : Int * }",
); );
} }
@ -4096,7 +4106,7 @@ mod solve_expr {
r#" r#"
app "test" provides [ partitionHelp ] to "./platform" app "test" provides [ partitionHelp ] to "./platform"
swap : I64, I64, List a -> List a swap : Int *, Int *, List a -> List a
swap = \i, j, list -> swap = \i, j, list ->
when Pair (List.get list i) (List.get list j) is when Pair (List.get list i) (List.get list j) is
Pair (Ok atI) (Ok atJ) -> Pair (Ok atI) (Ok atJ) ->

File diff suppressed because it is too large Load diff

View file

@ -28,6 +28,26 @@ pub fn aliases() -> MutMap<Symbol, BuiltinAlias> {
aliases.insert(symbol, alias); aliases.insert(symbol, alias);
}; };
// Int range : [ @Int range ]
add_alias(
Symbol::NUM_INT,
BuiltinAlias {
region: Region::zero(),
vars: vec![Located::at(Region::zero(), "range".into())],
typ: int_alias_content(flex(TVAR1)),
},
);
// Float range : [ @Float range ]
add_alias(
Symbol::NUM_FLOAT,
BuiltinAlias {
region: Region::zero(),
vars: vec![Located::at(Region::zero(), "range".into())],
typ: float_alias_content(flex(TVAR1)),
},
);
// Num range : [ @Num range ] // Num range : [ @Num range ]
add_alias( add_alias(
Symbol::NUM_NUM, Symbol::NUM_NUM,
@ -48,6 +68,26 @@ pub fn aliases() -> MutMap<Symbol, BuiltinAlias> {
}, },
); );
// Natural : [ @Natural ]
add_alias(
Symbol::NUM_NATURAL,
BuiltinAlias {
region: Region::zero(),
vars: vec![],
typ: natural_alias_content(),
},
);
// Nat : Int Natural
add_alias(
Symbol::NUM_NAT,
BuiltinAlias {
region: Region::zero(),
vars: Vec::new(),
typ: int_alias_content(natural_type()),
},
);
// Signed128 : [ @Signed128 ] // Signed128 : [ @Signed128 ]
add_alias( add_alias(
Symbol::NUM_SIGNED128, Symbol::NUM_SIGNED128,
@ -58,7 +98,7 @@ pub fn aliases() -> MutMap<Symbol, BuiltinAlias> {
}, },
); );
// I128 : Num (Integer Signed128) // I128 : Int Signed128
add_alias( add_alias(
Symbol::NUM_I128, Symbol::NUM_I128,
BuiltinAlias { BuiltinAlias {
@ -68,7 +108,7 @@ pub fn aliases() -> MutMap<Symbol, BuiltinAlias> {
}, },
); );
// U128 : Num (Integer Unsigned128) // U128 : Int Unsigned128
add_alias( add_alias(
Symbol::NUM_U128, Symbol::NUM_U128,
BuiltinAlias { BuiltinAlias {
@ -88,7 +128,7 @@ pub fn aliases() -> MutMap<Symbol, BuiltinAlias> {
}, },
); );
// I64 : Num (Integer Signed64) // I64 : Int Signed64
add_alias( add_alias(
Symbol::NUM_I64, Symbol::NUM_I64,
BuiltinAlias { BuiltinAlias {
@ -98,7 +138,7 @@ pub fn aliases() -> MutMap<Symbol, BuiltinAlias> {
}, },
); );
// U64 : Num (Integer Unsigned64) // U64 : Int Unsigned64
add_alias( add_alias(
Symbol::NUM_U64, Symbol::NUM_U64,
BuiltinAlias { BuiltinAlias {
@ -118,7 +158,7 @@ pub fn aliases() -> MutMap<Symbol, BuiltinAlias> {
}, },
); );
// I32 : Num (Integer Signed32) // I32 : Int Signed32
add_alias( add_alias(
Symbol::NUM_I32, Symbol::NUM_I32,
BuiltinAlias { BuiltinAlias {
@ -128,7 +168,7 @@ pub fn aliases() -> MutMap<Symbol, BuiltinAlias> {
}, },
); );
// U32 : Num (Integer Unsigned32) // U32 : Int Unsigned32
add_alias( add_alias(
Symbol::NUM_U32, Symbol::NUM_U32,
BuiltinAlias { BuiltinAlias {
@ -148,7 +188,7 @@ pub fn aliases() -> MutMap<Symbol, BuiltinAlias> {
}, },
); );
// I16 : Num (Integer Signed16) // I16 : Int Signed16
add_alias( add_alias(
Symbol::NUM_I16, Symbol::NUM_I16,
BuiltinAlias { BuiltinAlias {
@ -158,7 +198,7 @@ pub fn aliases() -> MutMap<Symbol, BuiltinAlias> {
}, },
); );
// U16 : Num (Integer Unsigned16) // U16 : Int Unsigned16
add_alias( add_alias(
Symbol::NUM_U16, Symbol::NUM_U16,
BuiltinAlias { BuiltinAlias {
@ -178,7 +218,7 @@ pub fn aliases() -> MutMap<Symbol, BuiltinAlias> {
}, },
); );
// I8 : Num (Integer Signed8) // I8 : Int Signed8
add_alias( add_alias(
Symbol::NUM_I8, Symbol::NUM_I8,
BuiltinAlias { BuiltinAlias {
@ -188,7 +228,7 @@ pub fn aliases() -> MutMap<Symbol, BuiltinAlias> {
}, },
); );
// U8 : Num (Integer Unsigned8) // U8 : Int Unsigned8
add_alias( add_alias(
Symbol::NUM_U8, Symbol::NUM_U8,
BuiltinAlias { BuiltinAlias {
@ -228,7 +268,7 @@ pub fn aliases() -> MutMap<Symbol, BuiltinAlias> {
}, },
); );
// F64 : Num (FloatingPoint Binary64) // F64 : Float Binary64
add_alias( add_alias(
Symbol::NUM_F64, Symbol::NUM_F64,
BuiltinAlias { BuiltinAlias {
@ -238,7 +278,7 @@ pub fn aliases() -> MutMap<Symbol, BuiltinAlias> {
}, },
); );
// F32 : Num (FloatingPoint Binary32) // F32 : Float Binary32
add_alias( add_alias(
Symbol::NUM_F32, Symbol::NUM_F32,
BuiltinAlias { BuiltinAlias {
@ -312,27 +352,39 @@ fn floatingpoint_alias_content(range: SolvedType) -> SolvedType {
// FLOAT // FLOAT
#[inline(always)] #[inline(always)]
pub fn float_type() -> SolvedType { pub fn float_type(range: SolvedType) -> SolvedType {
SolvedType::Alias( SolvedType::Alias(
Symbol::NUM_F64, Symbol::NUM_FLOAT,
Vec::new(), vec![("range".into(), range.clone())],
Box::new(float_alias_content(binary64_type())), Box::new(float_alias_content(range)),
) )
} }
#[inline(always)] #[inline(always)]
fn float_alias_content(typ: SolvedType) -> SolvedType { fn float_alias_content(range: SolvedType) -> SolvedType {
num_type(floatingpoint_type(typ)) num_type(floatingpoint_type(range))
}
// Nat
#[inline(always)]
pub fn nat_type() -> SolvedType {
SolvedType::Alias(Symbol::NUM_NAT, vec![], Box::new(nat_alias_content()))
}
#[inline(always)]
fn nat_alias_content() -> SolvedType {
int_alias_content(natural_type())
} }
// INT // INT
#[inline(always)] #[inline(always)]
pub fn int_type() -> SolvedType { pub fn int_type(range: SolvedType) -> SolvedType {
SolvedType::Alias( SolvedType::Alias(
Symbol::NUM_I64, Symbol::NUM_INT,
Vec::new(), vec![("range".into(), range.clone())],
Box::new(int_alias_content(signed64_type())), Box::new(int_alias_content(range)),
) )
} }
@ -385,6 +437,20 @@ fn binary32_alias_content() -> SolvedType {
single_private_tag(Symbol::NUM_AT_BINARY32, vec![]) single_private_tag(Symbol::NUM_AT_BINARY32, vec![])
} }
#[inline(always)]
pub fn natural_type() -> SolvedType {
SolvedType::Alias(
Symbol::NUM_NATURAL,
vec![],
Box::new(natural_alias_content()),
)
}
#[inline(always)]
fn natural_alias_content() -> SolvedType {
single_private_tag(Symbol::NUM_AT_NATURAL, vec![])
}
#[inline(always)] #[inline(always)]
pub fn signed128_type() -> SolvedType { pub fn signed128_type() -> SolvedType {
SolvedType::Alias( SolvedType::Alias(

View file

@ -14,7 +14,7 @@ use roc_types::types::Type::{self, *};
pub fn int_literal(num_var: Variable, expected: Expected<Type>, region: Region) -> Constraint { pub fn int_literal(num_var: Variable, expected: Expected<Type>, region: Region) -> Constraint {
let num_type = Variable(num_var); let num_type = Variable(num_var);
let reason = Reason::IntLiteral; let reason = Reason::IntLiteral;
let int_type = builtin_type(Symbol::NUM_I64, vec![]); let int_type = builtin_type(Symbol::NUM_INT, vec![]);
let expected_literal = ForReason(reason, int_type, region); let expected_literal = ForReason(reason, int_type, region);
exists( exists(
@ -30,7 +30,7 @@ pub fn int_literal(num_var: Variable, expected: Expected<Type>, region: Region)
pub fn float_literal(num_var: Variable, expected: Expected<Type>, region: Region) -> Constraint { pub fn float_literal(num_var: Variable, expected: Expected<Type>, region: Region) -> Constraint {
let num_type = Variable(num_var); let num_type = Variable(num_var);
let reason = Reason::FloatLiteral; let reason = Reason::FloatLiteral;
let float_type = builtin_type(Symbol::NUM_F64, vec![]); let float_type = builtin_type(Symbol::NUM_FLOAT, vec![]);
let expected_literal = ForReason(reason, float_type, region); let expected_literal = ForReason(reason, float_type, region);
exists( exists(

View file

@ -752,9 +752,9 @@ fn annotate_usage_pattern(pattern: &Pattern, usage: &mut VarUsage) {
match pattern { match pattern {
Identifier(_) Identifier(_)
| IntLiteral(_) | IntLiteral(_, _)
| NumLiteral(_, _) | NumLiteral(_, _)
| FloatLiteral(_) | FloatLiteral(_, _)
| StrLiteral(_) | StrLiteral(_)
| Underscore | Underscore
| Shadowed(_, _) | Shadowed(_, _)
@ -785,8 +785,8 @@ pub fn annotate_usage(expr: &Expr, usage: &mut VarUsage) {
match expr { match expr {
RuntimeError(_) RuntimeError(_)
| Num(_, _) | Num(_, _)
| Int(_, _) | Int(_, _, _)
| Float(_, _) | Float(_, _, _)
| Str { .. } | Str { .. }
| EmptyRecord | EmptyRecord
| Accessor { .. } | Accessor { .. }

View file

@ -132,6 +132,7 @@ fn files_to_documentations(
std_lib.clone(), std_lib.clone(),
src_dir, src_dir,
MutMap::default(), MutMap::default(),
8, // TODO: Is it okay to hardcode ptr_bytes here? I think it should be fine since we'er only type checking (also, 8 => 32bit system)
) )
.expect("TODO gracefully handle load failing"); .expect("TODO gracefully handle load failing");
files_docs.extend(loaded.documentation.drain().map(|x| x.1)); files_docs.extend(loaded.documentation.drain().map(|x| x.1));

View file

@ -1,6 +1,6 @@
app "closure" provides [ makeClosure ] to "./platform/" app "closure" provides [ makeClosure ] to "./platform/"
makeClosure : ({} -> I64) as MyClosure makeClosure : ({} -> Int *) as MyClosure
makeClosure = makeClosure =
x = 42 x = 42
y = 42 y = 42

View file

@ -5,7 +5,7 @@ ConsList a : [ Cons a (ConsList a), Nil ]
empty : ConsList a empty : ConsList a
empty = Nil empty = Nil
len : ConsList a -> I64 len : ConsList a -> Int *
len = \list -> len = \list ->
when list is when list is
Cons _ rest -> 1 + len rest Cons _ rest -> 1 + len rest

View file

@ -21,11 +21,11 @@ singleton = \key, value ->
Node Black key value Empty Empty Node Black key value Empty Empty
# {-| Determine the number of key-value pairs in the dictionary. -} # {-| Determine the number of key-value pairs in the dictionary. -}
size : Dict k v -> I64 size : Dict k v -> Int *
size = \dict -> size = \dict ->
sizeHelp 0 dict sizeHelp 0 dict
sizeHelp : I64, Dict k v -> I64 sizeHelp : Int *, Dict k v -> Int *
sizeHelp = \n, dict -> sizeHelp = \n, dict ->
when dict is when dict is
Empty -> Empty ->

View file

@ -5,7 +5,7 @@ app "quicksort"
quicksort = \originalList -> quicksort = \originalList ->
quicksortHelp : List (Num a), I64, I64 -> List (Num a) quicksortHelp : List (Num a), Int *, Int * -> List (Num a)
quicksortHelp = \list, low, high -> quicksortHelp = \list, low, high ->
if low < high then if low < high then
when partition low high list is when partition low high list is
@ -17,7 +17,7 @@ quicksort = \originalList ->
list list
partition : I64, I64, List (Num a) -> [ Pair I64 (List (Num a)) ] partition : Int a, Int a, List (Num b) -> [ Pair (Int a) (List (Num b)) ]
partition = \low, high, initialList -> partition = \low, high, initialList ->
when List.get initialList high is when List.get initialList high is
Ok pivot -> Ok pivot ->
@ -28,7 +28,7 @@ quicksort = \originalList ->
Err _ -> Err _ ->
Pair (low - 1) initialList Pair (low - 1) initialList
partitionHelp : I64, I64, List (Num a), I64, (Num a) -> [ Pair I64 (List (Num a)) ] partitionHelp : Int a, Int b, List (Num c), Int b, (Num c) -> [ Pair (Int a) (List (Num c)) ]
partitionHelp = \i, j, list, high, pivot -> partitionHelp = \i, j, list, high, pivot ->
if j < high then if j < high then
when List.get list j is when List.get list j is
@ -44,7 +44,7 @@ quicksort = \originalList ->
Pair i list Pair i list
swap : I64, I64, List a -> List a swap : Int *, Int *, List a -> List a
swap = \i, j, list -> swap = \i, j, list ->
when Pair (List.get list i) (List.get list j) is when Pair (List.get list i) (List.get list j) is
Pair (Ok atI) (Ok atJ) -> Pair (Ok atI) (Ok atJ) ->

View file

@ -1,12 +1,12 @@
app "quicksort" packages { base: "./platform" } provides [ quicksort ] to base app "quicksort" packages { base: "./platform" } provides [ quicksort ] to base
quicksort : List I64 -> List I64 quicksort : List Int * -> List Int *
quicksort = \originalList -> helper originalList quicksort = \originalList -> helper originalList
helper : List I64 -> List I64 helper : List Int * -> List Int *
helper = \originalList -> helper = \originalList ->
quicksortHelp : List (Num a), I64, I64 -> List (Num a) quicksortHelp : List (Num a), Int *, Int * -> List (Num a)
quicksortHelp = \list, low, high -> quicksortHelp = \list, low, high ->
if low < high then if low < high then
when partition low high list is when partition low high list is
@ -18,7 +18,7 @@ helper = \originalList ->
list list
swap : I64, I64, List a -> List a swap : Int *, Int *, List a -> List a
swap = \i, j, list -> swap = \i, j, list ->
when Pair (List.get list i) (List.get list j) is when Pair (List.get list i) (List.get list j) is
Pair (Ok atI) (Ok atJ) -> Pair (Ok atI) (Ok atJ) ->
@ -29,7 +29,7 @@ helper = \originalList ->
_ -> _ ->
[] []
partition : I64, I64, List (Num a) -> [ Pair I64 (List (Num a)) ] partition : Int *, Int *, List (Num a) -> [ Pair (Int *) (List (Num a)) ]
partition = \low, high, initialList -> partition = \low, high, initialList ->
when List.get initialList high is when List.get initialList high is
Ok pivot -> Ok pivot ->
@ -41,7 +41,7 @@ helper = \originalList ->
Pair (low - 1) initialList Pair (low - 1) initialList
partitionHelp : I64, I64, List (Num a), I64, (Num a) -> [ Pair I64 (List (Num a)) ] partitionHelp : Int *, Int *, List (Num a), Int *, (Num a) -> [ Pair (Int *) (List (Num a)) ]
partitionHelp = \i, j, list, high, pivot -> partitionHelp = \i, j, list, high, pivot ->
if j < high then if j < high then
when List.get list j is when List.get list j is