mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 22:34:45 +00:00
wrap by-pointer functions so they own all arguments
This commit is contained in:
parent
68a459cd95
commit
0d64d5ac1b
4 changed files with 76 additions and 67 deletions
|
@ -227,7 +227,6 @@ mod cli_run {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[ignore]
|
|
||||||
#[test]
|
#[test]
|
||||||
#[serial(closure1)]
|
#[serial(closure1)]
|
||||||
fn closure1() {
|
fn closure1() {
|
||||||
|
@ -240,7 +239,6 @@ mod cli_run {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[ignore]
|
|
||||||
#[test]
|
#[test]
|
||||||
#[serial(closure2)]
|
#[serial(closure2)]
|
||||||
fn closure2() {
|
fn closure2() {
|
||||||
|
@ -253,8 +251,8 @@ mod cli_run {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[ignore]
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[ignore]
|
||||||
#[serial(closure3)]
|
#[serial(closure3)]
|
||||||
fn closure3() {
|
fn closure3() {
|
||||||
check_output(
|
check_output(
|
||||||
|
@ -266,7 +264,6 @@ mod cli_run {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[ignore]
|
|
||||||
#[test]
|
#[test]
|
||||||
#[serial(closure4)]
|
#[serial(closure4)]
|
||||||
fn closure4() {
|
fn closure4() {
|
||||||
|
|
|
@ -16,21 +16,12 @@ fn should_borrow_layout(layout: &Layout) -> bool {
|
||||||
pub fn infer_borrow<'a>(
|
pub fn infer_borrow<'a>(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
procs: &MutMap<(Symbol, Layout<'a>), Proc<'a>>,
|
procs: &MutMap<(Symbol, Layout<'a>), Proc<'a>>,
|
||||||
passed_by_pointer: &MutMap<(Symbol, Layout<'a>), Symbol>,
|
_passed_by_pointer: &MutMap<(Symbol, Layout<'a>), Symbol>,
|
||||||
) -> ParamMap<'a> {
|
) -> ParamMap<'a> {
|
||||||
let mut param_map = ParamMap {
|
let mut param_map = ParamMap {
|
||||||
items: MutMap::default(),
|
items: MutMap::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
for (key, other) in passed_by_pointer {
|
|
||||||
if let Some(proc) = procs.get(key) {
|
|
||||||
let mut proc: Proc = proc.clone();
|
|
||||||
proc.name = *other;
|
|
||||||
|
|
||||||
param_map.visit_proc_always_owned(arena, &proc, key.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (key, proc) in procs {
|
for (key, proc) in procs {
|
||||||
param_map.visit_proc(arena, proc, key.clone());
|
param_map.visit_proc(arena, proc, key.clone());
|
||||||
}
|
}
|
||||||
|
@ -159,6 +150,10 @@ impl<'a> ParamMap<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_proc(&mut self, arena: &'a Bump, proc: &Proc<'a>, key: (Symbol, Layout<'a>)) {
|
fn visit_proc(&mut self, arena: &'a Bump, proc: &Proc<'a>, key: (Symbol, Layout<'a>)) {
|
||||||
|
if proc.must_own_arguments {
|
||||||
|
self.visit_proc_always_owned(arena, proc, key);
|
||||||
|
return;
|
||||||
|
}
|
||||||
let already_in_there = self.items.insert(
|
let already_in_there = self.items.insert(
|
||||||
Key::Declaration(proc.name, key.1),
|
Key::Declaration(proc.name, key.1),
|
||||||
Self::init_borrow_args(arena, proc.args),
|
Self::init_borrow_args(arena, proc.args),
|
||||||
|
|
|
@ -118,6 +118,7 @@ pub struct Proc<'a> {
|
||||||
pub closure_data_layout: Option<Layout<'a>>,
|
pub closure_data_layout: Option<Layout<'a>>,
|
||||||
pub ret_layout: Layout<'a>,
|
pub ret_layout: Layout<'a>,
|
||||||
pub is_self_recursive: SelfRecursive,
|
pub is_self_recursive: SelfRecursive,
|
||||||
|
pub must_own_arguments: bool,
|
||||||
pub host_exposed_layouts: HostExposedLayouts<'a>,
|
pub host_exposed_layouts: HostExposedLayouts<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1935,6 +1936,7 @@ fn specialize_external<'a>(
|
||||||
closure_data_layout,
|
closure_data_layout,
|
||||||
ret_layout: full_layout,
|
ret_layout: full_layout,
|
||||||
is_self_recursive: recursivity,
|
is_self_recursive: recursivity,
|
||||||
|
must_own_arguments: false,
|
||||||
host_exposed_layouts,
|
host_exposed_layouts,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2071,6 +2073,7 @@ fn specialize_external<'a>(
|
||||||
closure_data_layout,
|
closure_data_layout,
|
||||||
ret_layout,
|
ret_layout,
|
||||||
is_self_recursive: recursivity,
|
is_self_recursive: recursivity,
|
||||||
|
must_own_arguments: false,
|
||||||
host_exposed_layouts,
|
host_exposed_layouts,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -5707,11 +5710,26 @@ fn call_by_pointer<'a>(
|
||||||
symbol: Symbol,
|
symbol: Symbol,
|
||||||
layout: Layout<'a>,
|
layout: Layout<'a>,
|
||||||
) -> Expr<'a> {
|
) -> Expr<'a> {
|
||||||
|
// when we call a known function by-pointer, we must make sure we call a function that owns all
|
||||||
|
// its arguments (in an RC sense). we can't know this at this point, so we wrap such calls in
|
||||||
|
// a proc that we guarantee owns all its arguments. E.g. we turn
|
||||||
|
//
|
||||||
|
// foo = \x -> ...
|
||||||
|
//
|
||||||
|
// x = List.map [ ... ] foo
|
||||||
|
//
|
||||||
|
// into
|
||||||
|
//
|
||||||
|
// foo = \x -> ...
|
||||||
|
//
|
||||||
|
// @owns_all_arguments
|
||||||
|
// foo1 = \x -> foo x
|
||||||
|
//
|
||||||
|
// x = List.map [ ... ] foo1
|
||||||
if env.is_imported_symbol(symbol) || procs.partial_procs.contains_key(&symbol) {
|
if env.is_imported_symbol(symbol) || procs.partial_procs.contains_key(&symbol) {
|
||||||
// println!("going to specialize {:?} {:?}", symbol, layout);
|
|
||||||
|
|
||||||
match layout {
|
match layout {
|
||||||
Layout::FunctionPointer(arg_layouts, ret_layout) => {
|
Layout::FunctionPointer(arg_layouts, ret_layout) => {
|
||||||
|
if arg_layouts.iter().any(|l| l.contains_refcounted()) {
|
||||||
let name = env.unique_symbol();
|
let name = env.unique_symbol();
|
||||||
let mut args = Vec::with_capacity_in(arg_layouts.len(), env.arena);
|
let mut args = Vec::with_capacity_in(arg_layouts.len(), env.arena);
|
||||||
let mut arg_symbols = Vec::with_capacity_in(arg_layouts.len(), env.arena);
|
let mut arg_symbols = Vec::with_capacity_in(arg_layouts.len(), env.arena);
|
||||||
|
@ -5724,9 +5742,8 @@ fn call_by_pointer<'a>(
|
||||||
let args = args.into_bump_slice();
|
let args = args.into_bump_slice();
|
||||||
|
|
||||||
let call_symbol = env.unique_symbol();
|
let call_symbol = env.unique_symbol();
|
||||||
let callable_symbol = env.unique_symbol();
|
let call_type = CallType::ByName {
|
||||||
let call_type = CallType::ByPointer {
|
name: symbol,
|
||||||
name: callable_symbol,
|
|
||||||
full_layout: layout.clone(),
|
full_layout: layout.clone(),
|
||||||
ret_layout: ret_layout.clone(),
|
ret_layout: ret_layout.clone(),
|
||||||
arg_layouts,
|
arg_layouts,
|
||||||
|
@ -5741,14 +5758,6 @@ fn call_by_pointer<'a>(
|
||||||
|
|
||||||
body = Stmt::Let(call_symbol, expr, ret_layout.clone(), env.arena.alloc(body));
|
body = Stmt::Let(call_symbol, expr, ret_layout.clone(), env.arena.alloc(body));
|
||||||
|
|
||||||
let fpointer = Expr::FunctionPointer(symbol, layout.clone());
|
|
||||||
body = Stmt::Let(
|
|
||||||
callable_symbol,
|
|
||||||
fpointer,
|
|
||||||
ret_layout.clone(),
|
|
||||||
env.arena.alloc(body),
|
|
||||||
);
|
|
||||||
|
|
||||||
let closure_data_layout = None;
|
let closure_data_layout = None;
|
||||||
let proc = Proc {
|
let proc = Proc {
|
||||||
name,
|
name,
|
||||||
|
@ -5757,6 +5766,7 @@ fn call_by_pointer<'a>(
|
||||||
closure_data_layout,
|
closure_data_layout,
|
||||||
ret_layout: ret_layout.clone(),
|
ret_layout: ret_layout.clone(),
|
||||||
is_self_recursive: SelfRecursive::NotSelfRecursive,
|
is_self_recursive: SelfRecursive::NotSelfRecursive,
|
||||||
|
must_own_arguments: true,
|
||||||
host_exposed_layouts: HostExposedLayouts::NotHostExposed,
|
host_exposed_layouts: HostExposedLayouts::NotHostExposed,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -5764,6 +5774,11 @@ fn call_by_pointer<'a>(
|
||||||
.specialized
|
.specialized
|
||||||
.insert((name, layout.clone()), InProgressProc::Done(proc));
|
.insert((name, layout.clone()), InProgressProc::Done(proc));
|
||||||
Expr::FunctionPointer(name, layout)
|
Expr::FunctionPointer(name, layout)
|
||||||
|
} else {
|
||||||
|
// if none of the arguments is refcounted, then owning the arguments has no
|
||||||
|
// meaning
|
||||||
|
Expr::FunctionPointer(symbol, layout)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => unreachable!("not a function pointer layout"),
|
_ => unreachable!("not a function pointer layout"),
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,4 +12,6 @@ main =
|
||||||
|
|
||||||
Task.succeed {}
|
Task.succeed {}
|
||||||
|> Task.map (\_ -> x)
|
|> Task.map (\_ -> x)
|
||||||
|> Task.map (\_ -> {})
|
|> Task.map toUnit
|
||||||
|
|
||||||
|
toUnit = (\_ -> {})
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue