mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 21:39:07 +00:00
136 lines
4.3 KiB
Rust
136 lines
4.3 KiB
Rust
use bumpalo::{collections::Vec, Bump};
|
|
use roc_module::symbol::Symbol;
|
|
|
|
use crate::{
|
|
inc_dec::Ownership,
|
|
ir::{Call, CallType, Expr, Proc, Stmt},
|
|
layout::{Builtin, InLayout, LayoutInterner, LayoutRepr},
|
|
};
|
|
|
|
#[allow(unused)]
|
|
pub(crate) fn infer_borrow_signature<'a>(
|
|
arena: &'a Bump,
|
|
interner: &impl LayoutInterner<'a>,
|
|
proc: &'a Proc<'a>,
|
|
) -> &'a [Ownership] {
|
|
let mut state = State::new(arena, interner, proc);
|
|
state.inspect_stmt(&proc.body);
|
|
state.borrow_signature
|
|
}
|
|
|
|
struct State<'a> {
|
|
/// Argument symbols with a layout of `List *` or `Str`, i.e. the layouts
|
|
/// for which borrow inference might decide to pass as borrowed
|
|
args: &'a [(InLayout<'a>, Symbol)],
|
|
borrow_signature: &'a mut [Ownership],
|
|
}
|
|
|
|
fn layout_to_ownership<'a>(
|
|
in_layout: InLayout<'a>,
|
|
interner: &impl LayoutInterner<'a>,
|
|
) -> Ownership {
|
|
match interner.get_repr(in_layout) {
|
|
LayoutRepr::Builtin(Builtin::Str | Builtin::List(_)) => Ownership::Borrowed,
|
|
LayoutRepr::LambdaSet(inner) => {
|
|
layout_to_ownership(inner.runtime_representation(), interner)
|
|
}
|
|
_ => Ownership::Owned,
|
|
}
|
|
}
|
|
|
|
impl<'a> State<'a> {
|
|
fn new(arena: &'a Bump, interner: &impl LayoutInterner<'a>, proc: &'a Proc<'a>) -> Self {
|
|
let borrow_signature = Vec::from_iter_in(
|
|
proc.args
|
|
.iter()
|
|
.map(|(in_layout, _)| layout_to_ownership(*in_layout, interner)),
|
|
arena,
|
|
)
|
|
.into_bump_slice_mut();
|
|
|
|
Self {
|
|
args: proc.args,
|
|
borrow_signature,
|
|
}
|
|
}
|
|
|
|
fn mark_owned(&mut self, symbol: Symbol) {
|
|
if let Some(index) = self.args.iter().position(|(_, s)| *s == symbol) {
|
|
self.borrow_signature[index] = Ownership::Owned;
|
|
}
|
|
}
|
|
|
|
fn inspect_stmt(&mut self, stmt: &'a Stmt<'a>) {
|
|
match stmt {
|
|
Stmt::Let(_, expr, _, stmt) => {
|
|
self.inspect_expr(expr);
|
|
self.inspect_stmt(stmt);
|
|
}
|
|
Stmt::Switch {
|
|
branches,
|
|
default_branch,
|
|
..
|
|
} => {
|
|
for (_, _, stmt) in branches.iter() {
|
|
self.inspect_stmt(stmt);
|
|
}
|
|
self.inspect_stmt(default_branch.1);
|
|
}
|
|
Stmt::Ret(_) => todo!(),
|
|
Stmt::Refcounting(_, _) => todo!(),
|
|
Stmt::Expect { .. } | Stmt::ExpectFx { .. } => {
|
|
// TODO do we rely on values being passed by-value here?
|
|
// it would be better to pass by-reference in general
|
|
}
|
|
Stmt::Dbg { .. } => {
|
|
// TODO do we rely on values being passed by-value here?
|
|
// it would be better to pass by-reference in general
|
|
}
|
|
Stmt::Join {
|
|
body, remainder, ..
|
|
} => {
|
|
self.inspect_stmt(body);
|
|
self.inspect_stmt(remainder);
|
|
}
|
|
|
|
Stmt::Jump(_, _) | Stmt::Crash(_, _) => { /* not relevant for ownership */ }
|
|
}
|
|
}
|
|
|
|
fn inspect_expr(&mut self, expr: &'a Expr<'a>) {
|
|
if let Expr::Call(call) = expr {
|
|
self.inspect_call(call)
|
|
}
|
|
}
|
|
|
|
fn inspect_call(&mut self, call: &'a Call<'a>) {
|
|
let Call {
|
|
call_type,
|
|
arguments,
|
|
} = call;
|
|
|
|
match call_type {
|
|
CallType::ByName { name: _, .. } => {
|
|
// TODO ownership should depend on the borrow signature of the called function
|
|
for argument in arguments.iter() {
|
|
self.mark_owned(*argument)
|
|
}
|
|
}
|
|
CallType::LowLevel { op, .. } => {
|
|
// if the lowlevel must own the argument, mark it as owned
|
|
let borrow_signature = crate::inc_dec::lowlevel_borrow_signature(*op);
|
|
|
|
for (argument, ownership) in arguments.iter().zip(borrow_signature) {
|
|
if ownership.is_owned() {
|
|
self.mark_owned(*argument);
|
|
}
|
|
}
|
|
}
|
|
CallType::ByPointer { .. } | CallType::Foreign { .. } | CallType::HigherOrder(_) => {
|
|
for argument in arguments.iter() {
|
|
self.mark_owned(*argument)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|