add closure size variable

This commit is contained in:
Folkert 2020-10-02 00:50:18 +02:00
parent 0422d565ce
commit 2e1e87ad6a
21 changed files with 546 additions and 262 deletions

View File

@ -105,11 +105,18 @@ pub fn gen(
Declare(def) | Builtin(def) => match def.loc_pattern.value {
Identifier(symbol) => {
match def.loc_expr.value {
Closure(annotation, _, recursivity, loc_args, boxed_body) => {
Closure {
function_type: annotation,
return_type: ret_var,
recursive: recursivity,
arguments: loc_args,
loc_body: boxed_body,
..
} => {
let is_tail_recursive =
matches!(recursivity, roc_can::expr::Recursive::TailRecursive);
let (loc_body, ret_var) = *boxed_body;
let loc_body = *boxed_body;
// If this is an exposed symbol, we need to
// register it as such. Otherwise, since it

View File

@ -42,6 +42,8 @@ const NUM_BUILTIN_IMPORTS: usize = 7;
const TVAR1: VarId = VarId::from_u32(1);
const TVAR2: VarId = VarId::from_u32(2);
const TVAR3: VarId = VarId::from_u32(3);
const TVAR4: VarId = VarId::from_u32(4);
const TOP_LEVEL_CLOSURE_VAR: VarId = VarId::from_u32(5);
pub fn aliases() -> MutMap<Symbol, BuiltinAlias> {
let mut aliases = HashMap::with_capacity_and_hasher(NUM_BUILTIN_IMPORTS, default_hasher());
@ -181,7 +183,7 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// add or (+) : Num a, Num a -> Num a
add_type(
Symbol::NUM_ADD,
SolvedType::Func(
top_level_function(
vec![num_type(flex(TVAR1)), num_type(flex(TVAR1))],
Box::new(num_type(flex(TVAR1))),
),
@ -195,7 +197,7 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
add_type(
Symbol::NUM_ADD_CHECKED,
SolvedType::Func(
top_level_function(
vec![num_type(flex(TVAR1)), num_type(flex(TVAR1))],
Box::new(result_type(num_type(flex(TVAR1)), overflow)),
),
@ -204,13 +206,13 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// addWrap : Int, Int -> Int
add_type(
Symbol::NUM_ADD_WRAP,
SolvedType::Func(vec![int_type(), int_type()], Box::new(int_type())),
top_level_function(vec![int_type(), int_type()], Box::new(int_type())),
);
// sub or (-) : Num a, Num a -> Num a
add_type(
Symbol::NUM_SUB,
SolvedType::Func(
top_level_function(
vec![num_type(flex(TVAR1)), num_type(flex(TVAR1))],
Box::new(num_type(flex(TVAR1))),
),
@ -219,7 +221,7 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// mul or (*) : Num a, Num a -> Num a
add_type(
Symbol::NUM_MUL,
SolvedType::Func(
top_level_function(
vec![num_type(flex(TVAR1)), num_type(flex(TVAR1))],
Box::new(num_type(flex(TVAR1))),
),
@ -228,31 +230,31 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// abs : Num a -> Num a
add_type(
Symbol::NUM_ABS,
SolvedType::Func(vec![num_type(flex(TVAR1))], Box::new(num_type(flex(TVAR1)))),
top_level_function(vec![num_type(flex(TVAR1))], Box::new(num_type(flex(TVAR1)))),
);
// neg : Num a -> Num a
add_type(
Symbol::NUM_NEG,
SolvedType::Func(vec![num_type(flex(TVAR1))], Box::new(num_type(flex(TVAR1)))),
top_level_function(vec![num_type(flex(TVAR1))], Box::new(num_type(flex(TVAR1)))),
);
// isEq or (==) : a, a -> Bool
add_type(
Symbol::BOOL_EQ,
SolvedType::Func(vec![flex(TVAR1), flex(TVAR1)], Box::new(bool_type())),
top_level_function(vec![flex(TVAR1), flex(TVAR1)], Box::new(bool_type())),
);
// isNeq or (!=) : a, a -> Bool
add_type(
Symbol::BOOL_NEQ,
SolvedType::Func(vec![flex(TVAR1), flex(TVAR1)], Box::new(bool_type())),
top_level_function(vec![flex(TVAR1), flex(TVAR1)], Box::new(bool_type())),
);
// isLt or (<) : Num a, Num a -> Bool
add_type(
Symbol::NUM_LT,
SolvedType::Func(
top_level_function(
vec![num_type(flex(TVAR1)), num_type(flex(TVAR1))],
Box::new(bool_type()),
),
@ -261,7 +263,7 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// isLte or (<=) : Num a, Num a -> Bool
add_type(
Symbol::NUM_LTE,
SolvedType::Func(
top_level_function(
vec![num_type(flex(TVAR1)), num_type(flex(TVAR1))],
Box::new(bool_type()),
),
@ -270,7 +272,7 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// isGt or (>) : Num a, Num a -> Bool
add_type(
Symbol::NUM_GT,
SolvedType::Func(
top_level_function(
vec![num_type(flex(TVAR1)), num_type(flex(TVAR1))],
Box::new(bool_type()),
),
@ -279,7 +281,7 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// isGte or (>=) : Num a, Num a -> Bool
add_type(
Symbol::NUM_GTE,
SolvedType::Func(
top_level_function(
vec![num_type(flex(TVAR1)), num_type(flex(TVAR1))],
Box::new(bool_type()),
),
@ -288,7 +290,7 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// compare : Num a, Num a -> [ LT, EQ, GT ]
add_type(
Symbol::NUM_COMPARE,
SolvedType::Func(
top_level_function(
vec![num_type(flex(TVAR1)), num_type(flex(TVAR1))],
Box::new(ordering_type()),
),
@ -297,37 +299,37 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// toFloat : Num a -> Float
add_type(
Symbol::NUM_TO_FLOAT,
SolvedType::Func(vec![num_type(flex(TVAR1))], Box::new(float_type())),
top_level_function(vec![num_type(flex(TVAR1))], Box::new(float_type())),
);
// isNegative : Num a -> Bool
add_type(
Symbol::NUM_IS_NEGATIVE,
SolvedType::Func(vec![num_type(flex(TVAR1))], Box::new(bool_type())),
top_level_function(vec![num_type(flex(TVAR1))], Box::new(bool_type())),
);
// isPositive : Num a -> Bool
add_type(
Symbol::NUM_IS_POSITIVE,
SolvedType::Func(vec![num_type(flex(TVAR1))], Box::new(bool_type())),
top_level_function(vec![num_type(flex(TVAR1))], Box::new(bool_type())),
);
// isZero : Num a -> Bool
add_type(
Symbol::NUM_IS_ZERO,
SolvedType::Func(vec![num_type(flex(TVAR1))], Box::new(bool_type())),
top_level_function(vec![num_type(flex(TVAR1))], Box::new(bool_type())),
);
// isEven : Num a -> Bool
add_type(
Symbol::NUM_IS_EVEN,
SolvedType::Func(vec![num_type(flex(TVAR1))], Box::new(bool_type())),
top_level_function(vec![num_type(flex(TVAR1))], Box::new(bool_type())),
);
// isOdd : Num a -> Bool
add_type(
Symbol::NUM_IS_ODD,
SolvedType::Func(vec![num_type(flex(TVAR1))], Box::new(bool_type())),
top_level_function(vec![num_type(flex(TVAR1))], Box::new(bool_type())),
);
// maxInt : Int
@ -344,7 +346,7 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
add_type(
Symbol::NUM_DIV_INT,
SolvedType::Func(
top_level_function(
vec![int_type(), int_type()],
Box::new(result_type(int_type(), div_by_zero.clone())),
),
@ -353,7 +355,7 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// rem : Int, Int -> Result Int [ DivByZero ]*
add_type(
Symbol::NUM_REM,
SolvedType::Func(
top_level_function(
vec![int_type(), int_type()],
Box::new(result_type(int_type(), div_by_zero.clone())),
),
@ -362,7 +364,7 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// mod : Int, Int -> Result Int [ DivByZero ]*
add_type(
Symbol::NUM_MOD_INT,
SolvedType::Func(
top_level_function(
vec![int_type(), int_type()],
Box::new(result_type(int_type(), div_by_zero.clone())),
),
@ -373,7 +375,7 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// div : Float, Float -> Float
add_type(
Symbol::NUM_DIV_FLOAT,
SolvedType::Func(
top_level_function(
vec![float_type(), float_type()],
Box::new(result_type(float_type(), div_by_zero.clone())),
),
@ -382,7 +384,7 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// mod : Float, Float -> Result Int [ DivByZero ]*
add_type(
Symbol::NUM_MOD_FLOAT,
SolvedType::Func(
top_level_function(
vec![float_type(), float_type()],
Box::new(result_type(float_type(), div_by_zero)),
),
@ -396,7 +398,7 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
add_type(
Symbol::NUM_SQRT,
SolvedType::Func(
top_level_function(
vec![float_type()],
Box::new(result_type(float_type(), sqrt_of_negative)),
),
@ -405,25 +407,25 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// round : Float -> Int
add_type(
Symbol::NUM_ROUND,
SolvedType::Func(vec![float_type()], Box::new(int_type())),
top_level_function(vec![float_type()], Box::new(int_type())),
);
// sin : Float -> Float
add_type(
Symbol::NUM_SIN,
SolvedType::Func(vec![float_type()], Box::new(float_type())),
top_level_function(vec![float_type()], Box::new(float_type())),
);
// cos : Float -> Float
add_type(
Symbol::NUM_COS,
SolvedType::Func(vec![float_type()], Box::new(float_type())),
top_level_function(vec![float_type()], Box::new(float_type())),
);
// tan : Float -> Float
add_type(
Symbol::NUM_TAN,
SolvedType::Func(vec![float_type()], Box::new(float_type())),
top_level_function(vec![float_type()], Box::new(float_type())),
);
// maxFloat : Float
@ -435,31 +437,31 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// pow : Float, Float -> Float
add_type(
Symbol::NUM_POW,
SolvedType::Func(vec![float_type(), float_type()], Box::new(float_type())),
top_level_function(vec![float_type(), float_type()], Box::new(float_type())),
);
// ceiling : Float -> Int
add_type(
Symbol::NUM_CEILING,
SolvedType::Func(vec![float_type()], Box::new(int_type())),
top_level_function(vec![float_type()], Box::new(int_type())),
);
// powInt : Int, Int -> Int
add_type(
Symbol::NUM_POW_INT,
SolvedType::Func(vec![int_type(), int_type()], Box::new(int_type())),
top_level_function(vec![int_type(), int_type()], Box::new(int_type())),
);
// floor : Float -> Int
add_type(
Symbol::NUM_FLOOR,
SolvedType::Func(vec![float_type()], Box::new(int_type())),
top_level_function(vec![float_type()], Box::new(int_type())),
);
// atan : Float -> Float
add_type(
Symbol::NUM_ATAN,
SolvedType::Func(vec![float_type()], Box::new(float_type())),
top_level_function(vec![float_type()], Box::new(float_type())),
);
// Bool module
@ -467,25 +469,25 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// and : Bool, Bool -> Bool
add_type(
Symbol::BOOL_AND,
SolvedType::Func(vec![bool_type(), bool_type()], Box::new(bool_type())),
top_level_function(vec![bool_type(), bool_type()], Box::new(bool_type())),
);
// or : Bool, Bool -> Bool
add_type(
Symbol::BOOL_OR,
SolvedType::Func(vec![bool_type(), bool_type()], Box::new(bool_type())),
top_level_function(vec![bool_type(), bool_type()], Box::new(bool_type())),
);
// xor : Bool, Bool -> Bool
add_type(
Symbol::BOOL_XOR,
SolvedType::Func(vec![bool_type(), bool_type()], Box::new(bool_type())),
top_level_function(vec![bool_type(), bool_type()], Box::new(bool_type())),
);
// not : Bool -> Bool
add_type(
Symbol::BOOL_NOT,
SolvedType::Func(vec![bool_type()], Box::new(bool_type())),
top_level_function(vec![bool_type()], Box::new(bool_type())),
);
// Str module
@ -493,13 +495,13 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// Str.concat : Str, Str -> Str
add_type(
Symbol::STR_CONCAT,
SolvedType::Func(vec![str_type(), str_type()], Box::new(str_type())),
top_level_function(vec![str_type(), str_type()], Box::new(str_type())),
);
// isEmpty : Str -> Bool
add_type(
Symbol::STR_IS_EMPTY,
SolvedType::Func(vec![str_type()], Box::new(bool_type())),
top_level_function(vec![str_type()], Box::new(bool_type())),
);
// List module
@ -512,7 +514,7 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
add_type(
Symbol::LIST_GET,
SolvedType::Func(
top_level_function(
vec![list_type(flex(TVAR1)), int_type()],
Box::new(result_type(flex(TVAR1), index_out_of_bounds)),
),
@ -526,7 +528,7 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
add_type(
Symbol::LIST_FIRST,
SolvedType::Func(
top_level_function(
vec![list_type(flex(TVAR1))],
Box::new(result_type(flex(TVAR1), list_was_empty)),
),
@ -535,7 +537,7 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// set : List elem, Int, elem -> List elem
add_type(
Symbol::LIST_SET,
SolvedType::Func(
top_level_function(
vec![list_type(flex(TVAR1)), int_type(), flex(TVAR1)],
Box::new(list_type(flex(TVAR1))),
),
@ -544,7 +546,7 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// concat : List elem, List elem -> List elem
add_type(
Symbol::LIST_CONCAT,
SolvedType::Func(
top_level_function(
vec![list_type(flex(TVAR1)), list_type(flex(TVAR1))],
Box::new(list_type(flex(TVAR1))),
),
@ -553,10 +555,10 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// walkRight : List elem, (elem -> accum -> accum), accum -> accum
add_type(
Symbol::LIST_WALK_RIGHT,
SolvedType::Func(
top_level_function(
vec![
list_type(flex(TVAR1)),
SolvedType::Func(vec![flex(TVAR1), flex(TVAR2)], Box::new(flex(TVAR2))),
closure(vec![flex(TVAR1), flex(TVAR2)], TVAR3, Box::new(flex(TVAR2))),
flex(TVAR2),
],
Box::new(flex(TVAR2)),
@ -566,10 +568,10 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// keepIf : List elem, (elem -> Bool) -> List elem
add_type(
Symbol::LIST_KEEP_IF,
SolvedType::Func(
top_level_function(
vec![
list_type(flex(TVAR1)),
SolvedType::Func(vec![flex(TVAR1)], Box::new(bool_type())),
closure(vec![flex(TVAR1)], TVAR2, Box::new(bool_type())),
],
Box::new(list_type(flex(TVAR1))),
),
@ -578,10 +580,10 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// map : List before, (before -> after) -> List after
add_type(
Symbol::LIST_MAP,
SolvedType::Func(
top_level_function(
vec![
list_type(flex(TVAR1)),
SolvedType::Func(vec![flex(TVAR1)], Box::new(flex(TVAR2))),
closure(vec![flex(TVAR1)], TVAR3, Box::new(flex(TVAR2))),
],
Box::new(list_type(flex(TVAR2))),
),
@ -590,7 +592,7 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// append : List elem, elem -> List elem
add_type(
Symbol::LIST_APPEND,
SolvedType::Func(
top_level_function(
vec![list_type(flex(TVAR1)), flex(TVAR1)],
Box::new(list_type(flex(TVAR1))),
),
@ -599,7 +601,7 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// prepend : List elem, elem -> List elem
add_type(
Symbol::LIST_PREPEND,
SolvedType::Func(
top_level_function(
vec![list_type(flex(TVAR1)), flex(TVAR1)],
Box::new(list_type(flex(TVAR1))),
),
@ -608,7 +610,7 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// join : List (List elem) -> List elem
add_type(
Symbol::LIST_JOIN,
SolvedType::Func(
top_level_function(
vec![list_type(list_type(flex(TVAR1)))],
Box::new(list_type(flex(TVAR1))),
),
@ -617,13 +619,13 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// single : a -> List a
add_type(
Symbol::LIST_SINGLE,
SolvedType::Func(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
add_type(
Symbol::LIST_REPEAT,
SolvedType::Func(
top_level_function(
vec![int_type(), flex(TVAR1)],
Box::new(list_type(flex(TVAR1))),
),
@ -632,7 +634,7 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// reverse : List elem -> List elem
add_type(
Symbol::LIST_REVERSE,
SolvedType::Func(
top_level_function(
vec![list_type(flex(TVAR1))],
Box::new(list_type(flex(TVAR1))),
),
@ -641,13 +643,13 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// len : List * -> Int
add_type(
Symbol::LIST_LEN,
SolvedType::Func(vec![list_type(flex(TVAR1))], Box::new(int_type())),
top_level_function(vec![list_type(flex(TVAR1))], Box::new(int_type())),
);
// isEmpty : List * -> Bool
add_type(
Symbol::LIST_IS_EMPTY,
SolvedType::Func(vec![list_type(flex(TVAR1))], Box::new(bool_type())),
top_level_function(vec![list_type(flex(TVAR1))], Box::new(bool_type())),
);
// Map module
@ -658,7 +660,7 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// singleton : k, v -> Map k v
add_type(
Symbol::MAP_SINGLETON,
SolvedType::Func(
top_level_function(
vec![flex(TVAR1), flex(TVAR2)],
Box::new(map_type(flex(TVAR1), flex(TVAR2))),
),
@ -672,7 +674,7 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
add_type(
Symbol::MAP_GET,
SolvedType::Func(
top_level_function(
vec![map_type(flex(TVAR1), flex(TVAR2)), flex(TVAR1)],
Box::new(result_type(flex(TVAR2), key_not_found)),
),
@ -680,7 +682,7 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
add_type(
Symbol::MAP_INSERT,
SolvedType::Func(
top_level_function(
vec![map_type(flex(TVAR1), flex(TVAR2)), flex(TVAR1), flex(TVAR2)],
Box::new(map_type(flex(TVAR1), flex(TVAR2))),
),
@ -694,13 +696,13 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// singleton : a -> Set a
add_type(
Symbol::SET_SINGLETON,
SolvedType::Func(vec![flex(TVAR1)], Box::new(set_type(flex(TVAR1)))),
top_level_function(vec![flex(TVAR1)], Box::new(set_type(flex(TVAR1)))),
);
// union : Set a, Set a -> Set a
add_type(
Symbol::SET_UNION,
SolvedType::Func(
top_level_function(
vec![set_type(flex(TVAR1)), set_type(flex(TVAR1))],
Box::new(set_type(flex(TVAR1))),
),
@ -709,7 +711,7 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// diff : Set a, Set a -> Set a
add_type(
Symbol::SET_DIFF,
SolvedType::Func(
top_level_function(
vec![set_type(flex(TVAR1)), set_type(flex(TVAR1))],
Box::new(set_type(flex(TVAR1))),
),
@ -718,10 +720,10 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// foldl : Set a, (a -> b -> b), b -> b
add_type(
Symbol::SET_FOLDL,
SolvedType::Func(
top_level_function(
vec![
set_type(flex(TVAR1)),
SolvedType::Func(vec![flex(TVAR1), flex(TVAR2)], Box::new(flex(TVAR2))),
closure(vec![flex(TVAR1), flex(TVAR2)], TVAR3, Box::new(flex(TVAR2))),
flex(TVAR2),
],
Box::new(flex(TVAR2)),
@ -730,7 +732,7 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
add_type(
Symbol::SET_INSERT,
SolvedType::Func(
top_level_function(
vec![set_type(flex(TVAR1)), flex(TVAR1)],
Box::new(set_type(flex(TVAR1))),
),
@ -738,7 +740,7 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
add_type(
Symbol::SET_REMOVE,
SolvedType::Func(
top_level_function(
vec![set_type(flex(TVAR1)), flex(TVAR1)],
Box::new(set_type(flex(TVAR1))),
),
@ -749,10 +751,10 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// map : Result a err, (a -> b) -> Result b err
add_type(
Symbol::RESULT_MAP,
SolvedType::Func(
top_level_function(
vec![
result_type(flex(TVAR1), flex(TVAR3)),
SolvedType::Func(vec![flex(TVAR1)], Box::new(flex(TVAR2))),
closure(vec![flex(TVAR1)], TVAR4, Box::new(flex(TVAR2))),
],
Box::new(result_type(flex(TVAR2), flex(TVAR3))),
),
@ -766,6 +768,20 @@ fn flex(tvar: VarId) -> SolvedType {
SolvedType::Flex(tvar)
}
#[inline(always)]
fn top_level_function(arguments: Vec<SolvedType>, ret: Box<SolvedType>) -> SolvedType {
SolvedType::Func(
arguments,
Box::new(SolvedType::Flex(TOP_LEVEL_CLOSURE_VAR)),
ret,
)
}
#[inline(always)]
fn closure(arguments: Vec<SolvedType>, closure_var: VarId, ret: Box<SolvedType>) -> SolvedType {
SolvedType::Func(arguments, Box::new(SolvedType::Flex(closure_var)), ret)
}
#[inline(always)]
fn float_type() -> SolvedType {
SolvedType::Apply(Symbol::NUM_FLOAT, Vec::new())

View File

@ -37,6 +37,7 @@ const NUM_BUILTIN_IMPORTS: usize = 7;
/// These can be shared between definitions, they will get instantiated when converted to Type
const FUVAR: VarId = VarId::from_u32(1000);
const TOP_LEVEL_CLOSURE_VAR: VarId = VarId::from_u32(1001);
fn shared(base: SolvedType) -> SolvedType {
SolvedType::Apply(
@ -831,12 +832,16 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// , Attr Shared (a -> b)
// -> Attr * (List b)
add_type(Symbol::LIST_MAP, {
let_tvars! { a, b, star1, star2 };
let_tvars! { a, b, star1, star2, closure };
unique_function(
vec![
list_type(star1, a),
shared(SolvedType::Func(vec![flex(a)], Box::new(flex(b)))),
shared(SolvedType::Func(
vec![flex(a)],
Box::new(flex(closure)),
Box::new(flex(b)),
)),
],
list_type(star2, b),
)
@ -846,12 +851,16 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// , Attr Shared (a -> Attr * Bool)
// -> Attr * (List a)
add_type(Symbol::LIST_KEEP_IF, {
let_tvars! { a, star1, star2, star3 };
let_tvars! { a, star1, star2, star3, closure };
unique_function(
vec![
list_type(star1, a),
shared(SolvedType::Func(vec![flex(a)], Box::new(bool_type(star2)))),
shared(SolvedType::Func(
vec![flex(a)],
Box::new(flex(closure)),
Box::new(bool_type(star2)),
)),
],
list_type(star3, a),
)
@ -862,7 +871,7 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// , b
// -> b
add_type(Symbol::LIST_WALK_RIGHT, {
let_tvars! { u, a, b, star1 };
let_tvars! { u, a, b, star1, closure };
unique_function(
vec![
@ -875,6 +884,7 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
),
shared(SolvedType::Func(
vec![attr_type(u, a), flex(b)],
Box::new(flex(closure)),
Box::new(flex(b)),
)),
flex(b),
@ -1032,7 +1042,7 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// , b
// -> b
add_type(Symbol::SET_FOLDL, {
let_tvars! { star, u, a, b };
let_tvars! { star, u, a, b, closure };
unique_function(
vec![
@ -1045,6 +1055,7 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
),
shared(SolvedType::Func(
vec![attr_type(u, a), flex(b)],
Box::new(flex(closure)),
Box::new(flex(b)),
)),
flex(b),
@ -1129,7 +1140,7 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
// , Attr * (a -> b)
// -> Attr * (Result b e)
add_type(Symbol::RESULT_MAP, {
let_tvars! { star1, star2, star3, a, b, e };
let_tvars! { star1, star2, star3, a, b, e, closure };
unique_function(
vec![
SolvedType::Apply(
@ -1143,7 +1154,7 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
Symbol::ATTR_ATTR,
vec![
flex(star2),
SolvedType::Func(vec![flex(a)], Box::new(flex(b))),
SolvedType::Func(vec![flex(a)], Box::new(flex(closure)), Box::new(flex(b))),
],
),
],
@ -1169,7 +1180,14 @@ fn flex(tvar: VarId) -> SolvedType {
fn unique_function(args: Vec<SolvedType>, ret: SolvedType) -> SolvedType {
SolvedType::Apply(
Symbol::ATTR_ATTR,
vec![flex(FUVAR), SolvedType::Func(args, Box::new(ret))],
vec![
flex(FUVAR),
SolvedType::Func(
args,
Box::new(SolvedType::Flex(TOP_LEVEL_CLOSURE_VAR)),
Box::new(ret),
),
],
)
}

View File

@ -130,7 +130,9 @@ fn can_annotation_help(
references,
);
Type::Function(args, Box::new(ret))
let closure = Type::Variable(var_store.fresh());
Type::Function(args, Box::new(closure), Box::new(ret))
}
Apply(module_name, ident, type_arguments) => {
let symbol = if module_name.is_empty() {

View File

@ -1590,13 +1590,15 @@ fn defn(
.map(|(var, symbol)| (var, no_region(Identifier(symbol))))
.collect();
let expr = Closure(
var_store.fresh(),
fn_name,
Recursive::NotRecursive,
closure_args,
Box::new((no_region(body), ret_var)),
);
let expr = Closure {
function_type: var_store.fresh(),
closure_type: var_store.fresh(),
return_type: ret_var,
name: fn_name,
recursive: Recursive::NotRecursive,
arguments: closure_args,
loc_body: Box::new(no_region(body)),
};
Def {
loc_pattern: Located {

View File

@ -650,12 +650,12 @@ fn group_to_declaration(
let mut new_def = can_def.clone();
// Determine recursivity of closures that are not tail-recursive
if let Closure(fn_var, name, Recursive::NotRecursive, args, body) =
new_def.loc_expr.value
if let Closure {
recursive: recursive @ Recursive::NotRecursive,
..
} = &mut new_def.loc_expr.value
{
let recursion = closure_recursivity(*symbol, closures);
new_def.loc_expr.value = Closure(fn_var, name, recursion, args, body);
*recursive = closure_recursivity(*symbol, closures);
}
let is_recursive = successors(&symbol).contains(&symbol);
@ -678,12 +678,12 @@ fn group_to_declaration(
let mut new_def = can_def.clone();
// Determine recursivity of closures that are not tail-recursive
if let Closure(fn_var, name, Recursive::NotRecursive, args, body) =
new_def.loc_expr.value
if let Closure {
recursive: recursive @ Recursive::NotRecursive,
..
} = &mut new_def.loc_expr.value
{
let recursion = closure_recursivity(symbol, closures);
new_def.loc_expr.value = Closure(fn_var, name, recursion, args, body);
*recursive = closure_recursivity(symbol, closures);
}
if !seen_pattern_regions.contains(&new_def.loc_pattern.region) {
@ -808,16 +808,16 @@ fn canonicalize_pending_def<'a>(
region: loc_ann.region,
};
let body = Box::new((body_expr, var_store.fresh()));
Located {
value: Closure(
var_store.fresh(),
symbol,
Recursive::NotRecursive,
underscores,
body,
),
value: Closure {
function_type: var_store.fresh(),
closure_type: var_store.fresh(),
return_type: var_store.fresh(),
name: symbol,
recursive: Recursive::NotRecursive,
arguments: underscores,
loc_body: Box::new(body_expr),
},
region: loc_ann.region,
}
};
@ -962,7 +962,15 @@ fn canonicalize_pending_def<'a>(
if let (
&ast::Pattern::Identifier(ref _name),
&Pattern::Identifier(ref defined_symbol),
&Closure(fn_var, ref symbol, _, ref arguments, ref body),
&Closure {
function_type,
closure_type,
return_type,
name: ref symbol,
ref arguments,
loc_body: ref body,
..
},
) = (
&loc_pattern.value,
&loc_can_pattern.value,
@ -1000,13 +1008,15 @@ fn canonicalize_pending_def<'a>(
});
// renamed_closure_def = Some(&defined_symbol);
loc_can_expr.value = Closure(
fn_var,
*symbol,
is_recursive,
arguments.clone(),
body.clone(),
);
loc_can_expr.value = Closure {
function_type,
closure_type,
return_type,
name: *symbol,
recursive: is_recursive,
arguments: arguments.clone(),
loc_body: body.clone(),
};
}
// Store the referenced locals in the refs_by_symbol map, so we can later figure out
@ -1086,7 +1096,15 @@ fn canonicalize_pending_def<'a>(
if let (
&ast::Pattern::Identifier(ref _name),
&Pattern::Identifier(ref defined_symbol),
&Closure(fn_var, ref symbol, _, ref arguments, ref body),
&Closure {
function_type,
closure_type,
return_type,
name: ref symbol,
ref arguments,
loc_body: ref body,
..
},
) = (
&loc_pattern.value,
&loc_can_pattern.value,
@ -1123,13 +1141,15 @@ fn canonicalize_pending_def<'a>(
refs.lookups = refs.lookups.without(defined_symbol);
});
loc_can_expr.value = Closure(
fn_var,
*symbol,
is_recursive,
arguments.clone(),
body.clone(),
);
loc_can_expr.value = Closure {
function_type,
closure_type,
return_type,
name: *symbol,
recursive: is_recursive,
arguments: arguments.clone(),
loc_body: body.clone(),
};
}
// Store the referenced locals in the refs_by_symbol map, so we can later figure out

View File

@ -87,7 +87,7 @@ pub enum Expr {
/// This is *only* for calling functions, not for tag application.
/// The Tag variant contains any applied values inside it.
Call(
Box<(Variable, Located<Expr>, Variable)>,
Box<(Variable, Located<Expr>, Variable, Variable)>,
Vec<(Variable, Located<Expr>)>,
CalledVia,
),
@ -97,13 +97,15 @@ pub enum Expr {
ret_var: Variable,
},
Closure(
Variable,
Symbol,
Recursive,
Vec<(Variable, Located<Pattern>)>,
Box<(Located<Expr>, Variable)>,
),
Closure {
function_type: Variable,
closure_type: Variable,
return_type: Variable,
name: Symbol,
recursive: Recursive,
arguments: Vec<(Variable, Located<Pattern>)>,
loc_body: Box<Located<Expr>>,
},
// Product Types
Record {
@ -125,6 +127,7 @@ pub enum Expr {
/// field accessor as a function, e.g. (.foo) expr
Accessor {
record_var: Variable,
closure_var: Variable,
ext_var: Variable,
field_var: Variable,
field: Lowercase,
@ -323,7 +326,12 @@ pub fn canonicalize_expr<'a>(
};
Call(
Box::new((var_store.fresh(), fn_expr, var_store.fresh())),
Box::new((
var_store.fresh(),
fn_expr,
var_store.fresh(),
var_store.fresh(),
)),
args,
*application_style,
)
@ -346,7 +354,12 @@ pub fn canonicalize_expr<'a>(
_ => {
// This could be something like ((if True then fn1 else fn2) arg1 arg2).
Call(
Box::new((var_store.fresh(), fn_expr, var_store.fresh())),
Box::new((
var_store.fresh(),
fn_expr,
var_store.fresh(),
var_store.fresh(),
)),
args,
*application_style,
)
@ -471,13 +484,15 @@ pub fn canonicalize_expr<'a>(
env.register_closure(symbol, output.references.clone());
(
Closure(
var_store.fresh(),
symbol,
Recursive::NotRecursive,
can_args,
Box::new((loc_body_expr, var_store.fresh())),
),
Closure {
function_type: var_store.fresh(),
closure_type: var_store.fresh(),
return_type: var_store.fresh(),
name: symbol,
recursive: Recursive::NotRecursive,
arguments: can_args,
loc_body: Box::new(loc_body_expr),
},
output,
)
}
@ -537,6 +552,7 @@ pub fn canonicalize_expr<'a>(
Accessor {
record_var: var_store.fresh(),
ext_var: var_store.fresh(),
closure_var: var_store.fresh(),
field_var: var_store.fresh(),
field: (*field).into(),
},
@ -1193,20 +1209,30 @@ pub fn inline_calls(var_store: &mut VarStore, scope: &mut Scope, expr: Expr) ->
LetNonRec(Box::new(def), Box::new(loc_expr), var, aliases)
}
Closure(var, symbol, recursive, patterns, boxed_expr) => {
let (loc_expr, expr_var) = *boxed_expr;
Closure {
function_type,
closure_type,
return_type,
recursive,
name,
arguments,
loc_body,
} => {
let loc_expr = *loc_body;
let loc_expr = Located {
value: inline_calls(var_store, scope, loc_expr.value),
region: loc_expr.region,
};
Closure(
var,
symbol,
Closure {
function_type,
closure_type,
return_type,
recursive,
patterns,
Box::new((loc_expr, expr_var)),
)
name,
arguments,
loc_body: Box::new(loc_expr),
}
}
Record { record_var, fields } => {
@ -1243,14 +1269,20 @@ pub fn inline_calls(var_store: &mut VarStore, scope: &mut Scope, expr: Expr) ->
}
Call(boxed_tuple, args, called_via) => {
let (fn_var, loc_expr, expr_var) = *boxed_tuple;
let (fn_var, loc_expr, closure_var, expr_var) = *boxed_tuple;
match loc_expr.value {
Var(symbol) if symbol.is_builtin() => match builtin_defs(var_store).get(&symbol) {
Some(Def {
loc_expr:
Located {
value: Closure(_var, _, recursive, params, boxed_body),
value:
Closure {
recursive,
arguments: params,
loc_body: boxed_body,
..
},
..
},
..
@ -1263,7 +1295,7 @@ pub fn inline_calls(var_store: &mut VarStore, scope: &mut Scope, expr: Expr) ->
debug_assert_eq!(params.len(), args.len());
// Start with the function's body as the answer.
let (mut loc_answer, _body_var) = *boxed_body.clone();
let mut loc_answer = *boxed_body.clone();
// Wrap the body in one LetNonRec for each argument,
// such that at the end we have all the arguments in
@ -1311,7 +1343,11 @@ pub fn inline_calls(var_store: &mut VarStore, scope: &mut Scope, expr: Expr) ->
},
_ => {
// For now, we only inline calls to builtins. Leave this alone!
Call(Box::new((fn_var, loc_expr, expr_var)), args, called_via)
Call(
Box::new((fn_var, loc_expr, closure_var, expr_var)),
args,
called_via,
)
}
}
}
@ -1458,7 +1494,12 @@ fn desugar_str_segments(var_store: &mut VarStore, segments: Vec<StrSegment>) ->
let fn_expr = Located::new(0, 0, 0, 0, Expr::Var(Symbol::STR_CONCAT));
let expr = Expr::Call(
Box::new((var_store.fresh(), fn_expr, var_store.fresh())),
Box::new((
var_store.fresh(),
fn_expr,
var_store.fresh(),
var_store.fresh(),
)),
vec![
(var_store.fresh(), loc_new_expr),
(var_store.fresh(), loc_expr),

View File

@ -309,7 +309,10 @@ mod test_can {
match expr {
LetRec(assignments, body, _, _) => {
match &assignments.get(i).map(|def| &def.loc_expr.value) {
Some(Closure(_, _, recursion, _, _)) => recursion.clone(),
Some(Closure {
recursive: recursion,
..
}) => recursion.clone(),
Some(other @ _) => {
panic!("assignment at {} is not a closure, but a {:?}", i, other)
}
@ -328,7 +331,10 @@ mod test_can {
get_closure(&body.value, i - 1)
} else {
match &def.loc_expr.value {
Closure(_, _, recursion, _, _) => recursion.clone(),
Closure {
recursive: recursion,
..
} => recursion.clone(),
other @ _ => {
panic!("assignment at {} is not a closure, but a {:?}", i, other)
}

View File

@ -239,7 +239,7 @@ pub fn constrain_expr(
}
}
Call(boxed, loc_args, _application_style) => {
let (fn_var, loc_fn, ret_var) = &**boxed;
let (fn_var, loc_fn, closure_var, ret_var) = &**boxed;
// The expression that evaluates to the function being called, e.g. `foo` in
// (foo) bar baz
let opt_symbol = if let Var(symbol) = loc_fn.value {
@ -262,11 +262,15 @@ pub fn constrain_expr(
// The function's return type
let ret_type = Variable(*ret_var);
// type of values captured in the closure
let closure_type = Variable(*closure_var);
// This will be used in the occurs check
let mut vars = Vec::with_capacity(2 + loc_args.len());
vars.push(*fn_var);
vars.push(*ret_var);
vars.push(*closure_var);
let mut arg_types = Vec::with_capacity(loc_args.len());
let mut arg_cons = Vec::with_capacity(loc_args.len());
@ -289,7 +293,11 @@ pub fn constrain_expr(
let expected_fn_type = ForReason(
fn_reason,
Function(arg_types, Box::new(ret_type.clone())),
Function(
arg_types,
Box::new(closure_type),
Box::new(ret_type.clone()),
),
region,
);
@ -306,21 +314,31 @@ pub fn constrain_expr(
)
}
Var(symbol) => Lookup(*symbol, expected, region),
Closure(fn_var, _symbol, _recursive, args, boxed) => {
let (loc_body_expr, ret_var) = boxed.as_ref();
Closure {
function_type: fn_var,
closure_type: closure_var,
return_type: ret_var,
arguments,
loc_body: boxed,
..
} => {
let loc_body_expr = &**boxed;
let mut state = PatternState {
headers: SendMap::default(),
vars: Vec::with_capacity(args.len()),
vars: Vec::with_capacity(arguments.len()),
constraints: Vec::with_capacity(1),
};
let mut vars = Vec::with_capacity(state.vars.capacity() + 1);
let mut pattern_types = Vec::with_capacity(state.vars.capacity());
let ret_var = *ret_var;
let closure_var = *closure_var;
let ret_type = Type::Variable(ret_var);
let closure_type = Type::Variable(closure_var);
vars.push(ret_var);
vars.push(closure_var);
for (pattern_var, loc_pattern) in args {
for (pattern_var, loc_pattern) in arguments {
let pattern_type = Type::Variable(*pattern_var);
let pattern_expected = PExpected::NoExpectation(pattern_type.clone());
@ -337,7 +355,11 @@ pub fn constrain_expr(
vars.push(*pattern_var);
}
let fn_type = Type::Function(pattern_types, Box::new(ret_type.clone()));
let fn_type = Type::Function(
pattern_types,
Box::new(closure_type),
Box::new(ret_type.clone()),
);
let body_type = NoExpectation(ret_type);
let ret_constraint =
constrain_expr(env, loc_body_expr.region, &loc_body_expr.value, body_type);
@ -655,6 +677,7 @@ pub fn constrain_expr(
Accessor {
field,
record_var,
closure_var,
ext_var,
field_var,
} => {
@ -679,10 +702,14 @@ pub fn constrain_expr(
);
exists(
vec![*record_var, field_var, ext_var],
vec![*record_var, *closure_var, field_var, ext_var],
And(vec![
Eq(
Type::Function(vec![record_type], Box::new(field_type)),
Type::Function(
vec![record_type],
Box::new(Type::Variable(*closure_var)),
Box::new(field_type),
),
expected,
category,
region,
@ -1032,26 +1059,36 @@ fn constrain_def(env: &Env, def: &Def, body_con: Constraint) -> Constraint {
// instead of the more generic "something is wrong with the body of `f`"
match (&def.loc_expr.value, &signature) {
(
Closure(fn_var, _symbol, _recursive, args, boxed),
Type::Function(arg_types, _),
Closure {
function_type: fn_var,
closure_type: closure_var,
return_type: ret_var,
arguments,
loc_body,
..
},
Type::Function(arg_types, _, _),
) => {
let expected = annotation_expected;
let region = def.loc_expr.region;
let (loc_body_expr, ret_var) = boxed.as_ref();
let loc_body_expr = &**loc_body;
let mut state = PatternState {
headers: SendMap::default(),
vars: Vec::with_capacity(args.len()),
vars: Vec::with_capacity(arguments.len()),
constraints: Vec::with_capacity(1),
};
let mut vars = Vec::with_capacity(state.vars.capacity() + 1);
let mut pattern_types = Vec::with_capacity(state.vars.capacity());
let ret_var = *ret_var;
let closure_var = *closure_var;
let ret_type = Type::Variable(ret_var);
let closure_type = Type::Variable(closure_var);
vars.push(ret_var);
vars.push(closure_var);
let it = args.iter().zip(arg_types.iter()).enumerate();
let it = arguments.iter().zip(arg_types.iter()).enumerate();
for (index, ((pattern_var, loc_pattern), loc_ann)) in it {
{
// ensure type matches the one in the annotation
@ -1098,7 +1135,11 @@ fn constrain_def(env: &Env, def: &Def, body_con: Constraint) -> Constraint {
}
}
let fn_type = Type::Function(pattern_types, Box::new(ret_type.clone()));
let fn_type = Type::Function(
pattern_types,
Box::new(closure_type),
Box::new(ret_type.clone()),
);
let body_type = NoExpectation(ret_type);
let ret_constraint =
constrain_expr(env, loc_body_expr.region, &loc_body_expr.value, body_type);

View File

@ -178,7 +178,7 @@ fn to_type(solved_type: &SolvedType, free_vars: &mut FreeVars, var_store: &mut V
use roc_types::solved_types::SolvedType::*;
match solved_type {
Func(args, ret) => {
Func(args, closure, ret) => {
let mut new_args = Vec::with_capacity(args.len());
for arg in args {
@ -186,8 +186,9 @@ fn to_type(solved_type: &SolvedType, free_vars: &mut FreeVars, var_store: &mut V
}
let new_ret = to_type(&ret, free_vars, var_store);
let new_closure = to_type(&closure, free_vars, var_store);
Type::Function(new_args, Box::new(new_ret))
Type::Function(new_args, Box::new(new_closure), Box::new(new_ret))
}
Apply(symbol, args) => {
let mut new_args = Vec::with_capacity(args.len());

View File

@ -707,24 +707,35 @@ pub fn constrain_expr(
expected,
)
}
Closure(fn_var, _symbol, recursion, args, boxed) => {
Closure {
function_type: fn_var,
return_type: ret_var,
closure_type: closure_var,
recursive: recursion,
arguments,
loc_body: boxed,
..
} => {
use roc_can::expr::Recursive;
let (loc_body_expr, ret_var) = &**boxed;
let loc_body_expr = &**boxed;
let mut state = PatternState {
headers: SendMap::default(),
vars: Vec::with_capacity(args.len()),
vars: Vec::with_capacity(arguments.len()),
constraints: Vec::with_capacity(1),
};
let mut vars = Vec::with_capacity(state.vars.capacity() + 1);
let mut pattern_types = Vec::with_capacity(state.vars.capacity());
let ret_var = *ret_var;
let ret_type = Type::Variable(ret_var);
let closure_var = *closure_var;
let closure_type = Type::Variable(closure_var);
vars.push(ret_var);
vars.push(closure_var);
vars.push(*fn_var);
for (pattern_var, loc_pattern) in args {
for (pattern_var, loc_pattern) in arguments {
let pattern_type = Type::Variable(*pattern_var);
let pattern_expected = PExpected::NoExpectation(pattern_type.clone());
@ -755,7 +766,11 @@ pub fn constrain_expr(
let fn_type = attr_type(
fn_uniq_type,
Type::Function(pattern_types, Box::new(ret_type.clone())),
Type::Function(
pattern_types,
Box::new(closure_type),
Box::new(ret_type.clone()),
),
);
let body_type = Expected::NoExpectation(ret_type);
let ret_constraint = constrain_expr(
@ -795,9 +810,10 @@ pub fn constrain_expr(
}
Call(boxed, loc_args, _) => {
let (fn_var, fn_expr, ret_var) = &**boxed;
let (fn_var, fn_expr, closure_var, ret_var) = &**boxed;
let fn_type = Variable(*fn_var);
let ret_type = Variable(*ret_var);
let closure_type = Variable(*closure_var);
let fn_expected = Expected::NoExpectation(fn_type.clone());
let fn_region = fn_expr.region;
@ -811,6 +827,7 @@ pub fn constrain_expr(
vars.push(*fn_var);
vars.push(*ret_var);
vars.push(*closure_var);
// Canonicalize the function expression and its arguments
let fn_con = constrain_expr(
@ -862,7 +879,11 @@ pub fn constrain_expr(
fn_reason,
attr_type(
Bool::variable(expected_uniq_type),
Function(arg_types, Box::new(ret_type.clone())),
Function(
arg_types,
Box::new(closure_type),
Box::new(ret_type.clone()),
),
),
region,
);
@ -1426,6 +1447,7 @@ pub fn constrain_expr(
Accessor {
field,
record_var,
closure_var,
field_var,
ext_var,
} => {
@ -1455,14 +1477,20 @@ pub fn constrain_expr(
);
let fn_uniq_var = var_store.fresh();
let closure_type = Type::Variable(*closure_var);
let fn_type = attr_type(
Bool::variable(fn_uniq_var),
Type::Function(vec![record_type], Box::new(field_type)),
Type::Function(
vec![record_type],
Box::new(closure_type),
Box::new(field_type),
),
);
exists(
vec![
*record_var,
*closure_var,
*field_var,
*ext_var,
fn_uniq_var,
@ -1873,21 +1901,28 @@ fn annotation_to_attr_type(
)
}
Function(arguments, result) => {
Function(arguments, closure, result) => {
let uniq_var = var_store.fresh();
let (mut arg_vars, args_lifted) =
annotation_to_attr_type_many(var_store, arguments, rigids, change_var_kind);
let (closure_vars, closure_lifted) =
annotation_to_attr_type(var_store, closure, rigids, change_var_kind);
let (result_vars, result_lifted) =
annotation_to_attr_type(var_store, result, rigids, change_var_kind);
arg_vars.extend(result_vars);
arg_vars.extend(closure_vars);
arg_vars.push(uniq_var);
(
arg_vars,
attr_type(
Bool::variable(uniq_var),
Type::Function(args_lifted, Box::new(result_lifted)),
Type::Function(
args_lifted,
Box::new(closure_lifted),
Box::new(result_lifted),
),
),
)
}
@ -2542,8 +2577,9 @@ fn fix_mutual_recursive_alias_help_help(rec_var: Variable, attribute: &Type, int
use Type::*;
match into_type {
Function(args, ret) => {
Function(args, closure, ret) => {
fix_mutual_recursive_alias_help(rec_var, attribute, ret);
fix_mutual_recursive_alias_help(rec_var, attribute, closure);
args.iter_mut()
.for_each(|arg| fix_mutual_recursive_alias_help(rec_var, attribute, arg));
}

View File

@ -438,7 +438,9 @@ impl<'a> Procs<'a> {
fn get_args_ret_var(subs: &Subs, var: Variable) -> Option<(std::vec::Vec<Variable>, Variable)> {
match subs.get_without_compacting(var).content {
Content::Structure(FlatType::Func(pattern_vars, ret_var)) => Some((pattern_vars, ret_var)),
Content::Structure(FlatType::Func(pattern_vars, _closure_var, ret_var)) => {
Some((pattern_vars, ret_var))
}
Content::Structure(FlatType::Apply(Symbol::ATTR_ATTR, args)) => {
get_args_ret_var(subs, args[1])
}
@ -1334,24 +1336,32 @@ pub fn with_hole<'a>(
},
LetNonRec(def, cont, _, _) => {
if let roc_can::pattern::Pattern::Identifier(symbol) = &def.loc_pattern.value {
if let Closure(ann, _, recursivity, loc_args, boxed_body) = def.loc_expr.value {
if let Closure {
function_type,
return_type,
recursive,
arguments,
loc_body: boxed_body,
..
} = def.loc_expr.value
{
// Extract Procs, but discard the resulting Expr::Load.
// That Load looks up the pointer, which we won't use here!
let (loc_body, ret_var) = *boxed_body;
let loc_body = *boxed_body;
let is_self_recursive =
!matches!(recursivity, roc_can::expr::Recursive::NotRecursive);
!matches!(recursive, roc_can::expr::Recursive::NotRecursive);
procs.insert_named(
env,
layout_cache,
*symbol,
ann,
loc_args,
function_type,
arguments,
loc_body,
is_self_recursive,
ret_var,
return_type,
);
return with_hole(env, cont.value, procs, layout_cache, assigned, hole);
@ -1418,24 +1428,32 @@ pub fn with_hole<'a>(
// because Roc is strict, only functions can be recursive!
for def in defs.into_iter() {
if let roc_can::pattern::Pattern::Identifier(symbol) = &def.loc_pattern.value {
if let Closure(ann, _, recursivity, loc_args, boxed_body) = def.loc_expr.value {
if let Closure {
function_type,
return_type,
recursive,
arguments,
loc_body: boxed_body,
..
} = def.loc_expr.value
{
// Extract Procs, but discard the resulting Expr::Load.
// That Load looks up the pointer, which we won't use here!
let (loc_body, ret_var) = *boxed_body;
let loc_body = *boxed_body;
let is_self_recursive =
!matches!(recursivity, roc_can::expr::Recursive::NotRecursive);
!matches!(recursive, roc_can::expr::Recursive::NotRecursive);
procs.insert_named(
env,
layout_cache,
*symbol,
ann,
loc_args,
function_type,
arguments,
loc_body,
is_self_recursive,
ret_var,
return_type,
);
continue;
@ -1943,11 +1961,25 @@ pub fn with_hole<'a>(
Accessor { .. } | Update { .. } => todo!("record access/accessor/update"),
Closure(ann, name, _, loc_args, boxed_body) => {
let (loc_body, ret_var) = *boxed_body;
Closure {
function_type,
return_type,
name,
arguments,
loc_body: boxed_body,
..
} => {
let loc_body = *boxed_body;
match procs.insert_anonymous(env, name, ann, loc_args, loc_body, ret_var, layout_cache)
{
match procs.insert_anonymous(
env,
name,
function_type,
arguments,
loc_body,
return_type,
layout_cache,
) {
Ok(layout) => {
// TODO should the let have layout Pointer?
Stmt::Let(
@ -1965,7 +1997,7 @@ pub fn with_hole<'a>(
}
Call(boxed, loc_args, _) => {
let (fn_var, loc_expr, ret_var) = *boxed;
let (fn_var, loc_expr, _closure_var, ret_var) = *boxed;
// even if a call looks like it's by name, it may in fact be by-pointer.
// E.g. in `(\f, x -> f x)` the call is in fact by pointer.
@ -2197,24 +2229,31 @@ pub fn from_can<'a>(
// Now that we know for sure it's a closure, get an owned
// version of these variant args so we can use them properly.
match def.loc_expr.value {
Closure(ann, _, recursivity, loc_args, boxed_body) => {
Closure {
function_type,
return_type,
recursive,
arguments,
loc_body: boxed_body,
..
} => {
// Extract Procs, but discard the resulting Expr::Load.
// That Load looks up the pointer, which we won't use here!
let (loc_body, ret_var) = *boxed_body;
let loc_body = *boxed_body;
let is_self_recursive =
!matches!(recursivity, roc_can::expr::Recursive::NotRecursive);
!matches!(recursive, roc_can::expr::Recursive::NotRecursive);
procs.insert_named(
env,
layout_cache,
*symbol,
ann,
loc_args,
function_type,
arguments,
loc_body,
is_self_recursive,
ret_var,
return_type,
);
continue;
@ -2229,28 +2268,35 @@ pub fn from_can<'a>(
}
LetNonRec(def, cont, _, _) => {
if let roc_can::pattern::Pattern::Identifier(symbol) = &def.loc_pattern.value {
if let Closure(_, _, _, _, _) = &def.loc_expr.value {
if let Closure { .. } = &def.loc_expr.value {
// Now that we know for sure it's a closure, get an owned
// version of these variant args so we can use them properly.
match def.loc_expr.value {
Closure(ann, _, recursivity, loc_args, boxed_body) => {
Closure {
function_type,
return_type,
recursive,
arguments,
loc_body: boxed_body,
..
} => {
// Extract Procs, but discard the resulting Expr::Load.
// That Load looks up the pointer, which we won't use here!
let (loc_body, ret_var) = *boxed_body;
let loc_body = *boxed_body;
let is_self_recursive =
!matches!(recursivity, roc_can::expr::Recursive::NotRecursive);
!matches!(recursive, roc_can::expr::Recursive::NotRecursive);
procs.insert_named(
env,
layout_cache,
*symbol,
ann,
loc_args,
function_type,
arguments,
loc_body,
is_self_recursive,
ret_var,
return_type,
);
return from_can(env, cont.value, procs, layout_cache);

View File

@ -391,7 +391,7 @@ fn layout_from_flat_type<'a>(
}
}
}
Func(args, ret_var) => {
Func(args, _, ret_var) => {
let mut fn_args = Vec::with_capacity_in(args.len(), arena);
for arg_var in args {

View File

@ -796,7 +796,7 @@ fn count_arguments(tipe: &ErrorType) -> usize {
use ErrorType::*;
match tipe {
Function(args, _) => args.len(),
Function(args, _, _) => args.len(),
Type(Symbol::ATTR_ATTR, args) => count_arguments(&args[1]),
Alias(_, _, actual) => count_arguments(actual),
_ => 0,
@ -1334,7 +1334,7 @@ pub fn to_doc<'b>(
use ErrorType::*;
match tipe {
Function(args, ret) => report_text::function(
Function(args, _, ret) => report_text::function(
alloc,
parens,
args.into_iter()
@ -1474,7 +1474,7 @@ fn to_diff<'b>(
(FlexVar(x), FlexVar(y)) if x == y => same(alloc, parens, type1),
(RigidVar(x), RigidVar(y)) if x == y => same(alloc, parens, type1),
(Function(args1, ret1), Function(args2, ret2)) => {
(Function(args1, _, ret1), Function(args2, _, ret2)) => {
if args1.len() == args2.len() {
let mut status = Status::Similar;
let arg_diff = traverse(alloc, Parens::InFn, args1, args2);
@ -2406,7 +2406,7 @@ fn type_problem_to_pretty<'b>(
match tipe {
Infinite | Error | FlexVar(_) => alloc.nil(),
RigidVar(y) => bad_double_rigid(x, y),
Function(_, _) => bad_rigid_var(x, alloc.reflow("a function value")),
Function(_, _, _) => bad_rigid_var(x, alloc.reflow("a function value")),
Record(_, _) => bad_rigid_var(x, alloc.reflow("a record value")),
TagUnion(_, _) | RecursiveTagUnion(_, _, _) => {
bad_rigid_var(x, alloc.reflow("a tag value"))

View File

@ -599,7 +599,7 @@ fn type_to_variable(
register(subs, rank, pools, content)
}
Function(args, ret_type) => {
Function(args, closure_type, ret_type) => {
let mut arg_vars = Vec::with_capacity(args.len());
for arg in args {
@ -607,7 +607,8 @@ fn type_to_variable(
}
let ret_var = type_to_variable(subs, rank, pools, cached, ret_type);
let content = Content::Structure(FlatType::Func(arg_vars, ret_var));
let closure_var = type_to_variable(subs, rank, pools, cached, closure_type);
let content = Content::Structure(FlatType::Func(arg_vars, closure_var, ret_var));
register(subs, rank, pools, content)
}
@ -1075,9 +1076,17 @@ fn adjust_rank_content(
rank
}
Func(arg_vars, ret_var) => {
Func(arg_vars, closure_var, ret_var) => {
let mut rank = adjust_rank(subs, young_mark, visit_mark, group_rank, ret_var);
rank = rank.max(adjust_rank(
subs,
young_mark,
visit_mark,
group_rank,
closure_var,
));
for var in arg_vars {
rank = rank.max(adjust_rank(subs, young_mark, visit_mark, group_rank, var));
}
@ -1239,14 +1248,15 @@ fn deep_copy_var_help(
Apply(symbol, args)
}
Func(arg_vars, ret_var) => {
Func(arg_vars, closure_var, ret_var) => {
let new_ret_var = deep_copy_var_help(subs, max_rank, pools, ret_var);
let new_closure_var = deep_copy_var_help(subs, max_rank, pools, closure_var);
let arg_vars = arg_vars
.into_iter()
.map(|var| deep_copy_var_help(subs, max_rank, pools, var))
.collect();
Func(arg_vars, new_ret_var)
Func(arg_vars, new_closure_var, new_ret_var)
}
same @ EmptyRecord | same @ EmptyTagUnion | same @ Erroneous(_) => same,

View File

@ -150,7 +150,7 @@ fn find_names_needed(
find_names_needed(var, subs, roots, root_appearances, names_taken);
}
}
Structure(Func(arg_vars, ret_var)) => {
Structure(Func(arg_vars, _closure_var, ret_var)) => {
for var in arg_vars {
find_names_needed(var, subs, roots, root_appearances, names_taken);
}
@ -376,7 +376,7 @@ fn write_flat_type(env: &Env, flat_type: FlatType, subs: &Subs, buf: &mut String
Apply(symbol, args) => write_apply(env, symbol, args, subs, buf, parens),
EmptyRecord => buf.push_str(EMPTY_RECORD),
EmptyTagUnion => buf.push_str(EMPTY_TAG_UNION),
Func(args, ret) => write_fn(env, args, ret, subs, buf, parens),
Func(args, _closure, ret) => write_fn(env, args, ret, subs, buf, parens),
Record(fields, ext_var) => {
use crate::types::{gather_fields, RecordStructure};

View File

@ -24,7 +24,7 @@ impl<T> Solved<T> {
#[derive(Debug, Clone, PartialEq)]
pub enum SolvedType {
/// A function. The types of its arguments, then the type of its return value.
Func(Vec<SolvedType>, Box<SolvedType>),
Func(Vec<SolvedType>, Box<SolvedType>, Box<SolvedType>),
/// Applying a type to some arguments (e.g. Map.Map String Int)
Apply(Symbol, Vec<SolvedType>),
/// A bound type variable, e.g. `a` in `(a -> a)`
@ -107,8 +107,9 @@ impl SolvedType {
SolvedType::Apply(symbol, solved_types)
}
Function(args, box_ret) => {
Function(args, box_closure, box_ret) => {
let solved_ret = Self::from_type(solved_subs, *box_ret);
let solved_closure = Self::from_type(solved_subs, *box_closure);
let mut solved_args = Vec::with_capacity(args.len());
for arg in args.into_iter() {
@ -117,7 +118,7 @@ impl SolvedType {
solved_args.push(solved_arg);
}
SolvedType::Func(solved_args, Box::new(solved_ret))
SolvedType::Func(solved_args, Box::new(solved_closure), Box::new(solved_ret))
}
Record(fields, box_ext) => {
let solved_ext = Self::from_type(solved_subs, *box_ext);
@ -227,7 +228,7 @@ impl SolvedType {
SolvedType::Apply(symbol, new_args)
}
Func(args, ret) => {
Func(args, closure, ret) => {
let mut new_args = Vec::with_capacity(args.len());
for var in args {
@ -235,8 +236,9 @@ impl SolvedType {
}
let ret = Self::from_var(subs, ret);
let closure = Self::from_var(subs, closure);
SolvedType::Func(new_args, Box::new(ret))
SolvedType::Func(new_args, Box::new(closure), Box::new(ret))
}
Record(fields, ext_var) => {
let mut new_fields = Vec::with_capacity(fields.len());

View File

@ -565,7 +565,7 @@ impl Content {
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum FlatType {
Apply(Symbol, Vec<Variable>),
Func(Vec<Variable>, Variable),
Func(Vec<Variable>, Variable, Variable),
Record(MutMap<Lowercase, RecordField<Variable>>, Variable),
TagUnion(MutMap<TagName, Vec<Variable>>, Variable),
RecursiveTagUnion(Variable, MutMap<TagName, Vec<Variable>>, Variable),
@ -606,8 +606,10 @@ fn occurs(
match flat_type {
Apply(_, args) => short_circuit(subs, root_var, &new_seen, args.iter()),
Func(arg_vars, ret_var) => {
let it = once(&ret_var).chain(arg_vars.iter());
Func(arg_vars, closure_var, ret_var) => {
let it = once(&ret_var)
.chain(once(&closure_var))
.chain(arg_vars.iter());
short_circuit(subs, root_var, &new_seen, it)
}
Record(vars_by_field, ext_var) => {
@ -699,14 +701,19 @@ fn explicit_substitute(
subs.set_content(in_var, Structure(Apply(symbol, new_args)));
}
Func(arg_vars, ret_var) => {
Func(arg_vars, closure_var, ret_var) => {
let new_arg_vars = arg_vars
.iter()
.map(|var| explicit_substitute(subs, from, to, *var, seen))
.collect();
let new_ret_var = explicit_substitute(subs, from, to, ret_var, seen);
let new_closure_var =
explicit_substitute(subs, from, to, closure_var, seen);
subs.set_content(in_var, Structure(Func(new_arg_vars, new_ret_var)));
subs.set_content(
in_var,
Structure(Func(new_arg_vars, new_closure_var, new_ret_var)),
);
}
TagUnion(mut tags, ext_var) => {
let new_ext_var = explicit_substitute(subs, from, to, ext_var, seen);
@ -804,8 +811,9 @@ fn get_var_names(
})
}
FlatType::Func(arg_vars, ret_var) => {
FlatType::Func(arg_vars, closure_var, ret_var) => {
let taken_names = get_var_names(subs, ret_var, taken_names);
let taken_names = get_var_names(subs, closure_var, taken_names);
arg_vars.into_iter().fold(taken_names, |answer, arg_var| {
get_var_names(subs, arg_var, answer)
@ -998,14 +1006,15 @@ fn flat_type_to_err_type(
ErrorType::Type(symbol, arg_types)
}
Func(arg_vars, ret_var) => {
Func(arg_vars, closure_var, ret_var) => {
let args = arg_vars
.into_iter()
.map(|arg_var| var_to_err_type(subs, state, arg_var))
.collect();
let ret = var_to_err_type(subs, state, ret_var);
let closure = var_to_err_type(subs, state, closure_var);
ErrorType::Function(args, Box::new(ret))
ErrorType::Function(args, Box::new(closure), Box::new(ret))
}
EmptyRecord => ErrorType::Record(SendMap::default(), TypeExt::Closed),
@ -1145,12 +1154,13 @@ fn restore_content(subs: &mut Subs, content: &Content) {
}
}
Func(arg_vars, ret_var) => {
Func(arg_vars, closure_var, ret_var) => {
for &var in arg_vars {
subs.restore(var);
}
subs.restore(*ret_var);
subs.restore(*closure_var);
}
EmptyRecord => (),

View File

@ -138,8 +138,8 @@ impl RecordField<Type> {
pub enum Type {
EmptyRec,
EmptyTagUnion,
/// A function. The types of its arguments, then the type of its return value.
Function(Vec<Type>, Box<Type>),
/// A function. The types of its arguments, size of its closure, then the type of its return value.
Function(Vec<Type>, Box<Type>, Box<Type>),
Record(SendMap<Lowercase, RecordField<Type>>, Box<Type>),
TagUnion(Vec<(TagName, Vec<Type>)>, Box<Type>),
Alias(Symbol, Vec<(Lowercase, Type)>, Box<Type>),
@ -158,7 +158,7 @@ impl fmt::Debug for Type {
match self {
Type::EmptyRec => write!(f, "{{}}"),
Type::EmptyTagUnion => write!(f, "[]"),
Type::Function(args, ret) => {
Type::Function(args, _closure, ret) => {
write!(f, "Fn(")?;
for (index, arg) in args.iter().enumerate() {
@ -339,7 +339,7 @@ impl fmt::Debug for Type {
impl Type {
pub fn arity(&self) -> usize {
if let Type::Function(args, _) = self {
if let Type::Function(args, _, _) = self {
args.len()
} else {
0
@ -369,10 +369,11 @@ impl Type {
*self = replacement.clone();
}
}
Function(args, ret) => {
Function(args, closure, ret) => {
for arg in args {
arg.substitute(substitutions);
}
closure.substitute(substitutions);
ret.substitute(substitutions);
}
TagUnion(tags, ext) => {
@ -427,10 +428,11 @@ impl Type {
use Type::*;
match self {
Function(args, ret) => {
Function(args, closure, ret) => {
for arg in args {
arg.substitute_alias(rep_symbol, actual);
}
closure.substitute_alias(rep_symbol, actual);
ret.substitute_alias(rep_symbol, actual);
}
RecursiveTagUnion(_, tags, ext) | TagUnion(tags, ext) => {
@ -472,8 +474,9 @@ impl Type {
use Type::*;
match self {
Function(args, ret) => {
Function(args, closure, ret) => {
ret.contains_symbol(rep_symbol)
|| closure.contains_symbol(rep_symbol)
|| args.iter().any(|arg| arg.contains_symbol(rep_symbol))
}
RecursiveTagUnion(_, tags, ext) | TagUnion(tags, ext) => {
@ -503,8 +506,9 @@ impl Type {
match self {
Variable(v) => *v == rep_variable,
Function(args, ret) => {
Function(args, closure, ret) => {
ret.contains_variable(rep_variable)
|| closure.contains_variable(rep_variable)
|| args.iter().any(|arg| arg.contains_variable(rep_variable))
}
RecursiveTagUnion(_, tags, ext) | TagUnion(tags, ext) => {
@ -553,10 +557,11 @@ impl Type {
use Type::*;
match self {
Function(args, ret) => {
Function(args, closure, ret) => {
for arg in args {
arg.instantiate_aliases(region, aliases, var_store, introduced);
}
closure.instantiate_aliases(region, aliases, var_store, introduced);
ret.instantiate_aliases(region, aliases, var_store, introduced);
}
RecursiveTagUnion(_, tags, ext) | TagUnion(tags, ext) => {
@ -726,8 +731,9 @@ fn symbols_help(tipe: &Type, accum: &mut ImSet<Symbol>) {
use Type::*;
match tipe {
Function(args, ret) => {
Function(args, closure, ret) => {
symbols_help(&ret, accum);
symbols_help(&closure, accum);
args.iter().for_each(|arg| symbols_help(arg, accum));
}
RecursiveTagUnion(_, tags, ext) | TagUnion(tags, ext) => {
@ -776,10 +782,11 @@ fn variables_help(tipe: &Type, accum: &mut ImSet<Variable>) {
accum.insert(*v);
}
Function(args, ret) => {
Function(args, closure, ret) => {
for arg in args {
variables_help(arg, accum);
}
variables_help(closure, accum);
variables_help(ret, accum);
}
Record(fields, ext) => {
@ -1014,7 +1021,7 @@ pub enum ErrorType {
Record(SendMap<Lowercase, RecordField<ErrorType>>, TypeExt),
TagUnion(SendMap<TagName, Vec<ErrorType>>, TypeExt),
RecursiveTagUnion(Box<ErrorType>, SendMap<TagName, Vec<ErrorType>>, TypeExt),
Function(Vec<ErrorType>, Box<ErrorType>),
Function(Vec<ErrorType>, Box<ErrorType>, Box<ErrorType>),
Alias(Symbol, Vec<(Lowercase, ErrorType)>, Box<ErrorType>),
Boolean(boolean_algebra::Bool),
Error,
@ -1102,7 +1109,7 @@ fn write_error_type_help(
}
}
}
Function(arguments, result) => {
Function(arguments, _closure, result) => {
let write_parens = parens != Parens::Unnecessary;
if write_parens {
@ -1246,7 +1253,7 @@ fn write_debug_error_type_help(error_type: ErrorType, buf: &mut String, parens:
buf.push(')');
}
}
Function(arguments, result) => {
Function(arguments, _closure, result) => {
let write_parens = parens != Parens::Unnecessary;
if write_parens {

View File

@ -140,6 +140,13 @@ fn unify_context(subs: &mut Subs, pool: &mut Pool, ctx: Context) -> Outcome {
println!("\n --- \n");
dbg!(ctx.second, type2);
println!("\n --------------- \n");
println!(
"{:?} {:?} ~ {:?} {:?}",
ctx.first,
subs.get(ctx.first).content,
ctx.second,
subs.get(ctx.second).content
);
}
match &ctx.first_desc.content {
FlexVar(opt_name) => unify_flex(subs, &ctx, opt_name, &ctx.second_desc.content),
@ -849,15 +856,23 @@ fn unify_flat_type(
problems
}
}
(Func(l_args, l_ret), Func(r_args, r_ret)) if l_args.len() == r_args.len() => {
(Func(l_args, l_closure, l_ret), Func(r_args, r_closure, r_ret))
if l_args.len() == r_args.len() =>
{
let arg_problems = unify_zip(subs, pool, l_args.iter(), r_args.iter());
let ret_problems = unify_pool(subs, pool, *l_ret, *r_ret);
let closure_problems = unify_pool(subs, pool, *l_closure, *r_closure);
if arg_problems.is_empty() && ret_problems.is_empty() {
merge(subs, ctx, Structure(Func((*r_args).clone(), *r_ret)))
if arg_problems.is_empty() && closure_problems.is_empty() && ret_problems.is_empty() {
merge(
subs,
ctx,
Structure(Func((*r_args).clone(), *r_closure, *r_ret)),
)
} else {
let mut problems = ret_problems;
problems.extend(closure_problems);
problems.extend(arg_problems);
problems

View File

@ -923,13 +923,17 @@ pub fn annotate_usage(expr: &Expr, usage: &mut VarUsage) {
annotate_usage(&arg.value, usage);
}
}
Closure(_, _, _, args, body) => {
Closure {
arguments,
loc_body,
..
} => {
// annotate defaults of optional record fields
for (_, loc_pattern) in args {
for (_, loc_pattern) in arguments {
annotate_usage_pattern(&loc_pattern.value, usage);
}
annotate_usage(&body.0.value, usage);
annotate_usage(&loc_body.value, usage);
}
Tag { arguments, .. } => {