Merge pull request #2096 from rtfeldman/alias-analysis-pull-heap-cell-out

alias analysis: recursive tag union refactor
This commit is contained in:
Richard Feldman 2021-11-29 09:27:54 -05:00 committed by GitHub
commit adb8ff881c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 182 additions and 112 deletions

View File

@ -686,8 +686,8 @@ where
self.set_last_seen(*sym, stmt, &owning_symbol);
}
}
Expr::Reset(sym) => {
self.set_last_seen(*sym, stmt, &owning_symbol);
Expr::Reset { symbol, .. } => {
self.set_last_seen(*symbol, stmt, &owning_symbol);
}
Expr::EmptyArray => {}
Expr::RuntimeErrorFunction(_) => {}

View File

@ -1108,7 +1108,7 @@ pub fn build_exp_expr<'a, 'ctx, 'env>(
..
} => build_tag(env, scope, union_layout, *tag_id, arguments, None, parent),
Reset(symbol) => {
Reset { symbol, .. } => {
let (tag_ptr, layout) = load_symbol_and_layout(scope, symbol);
let tag_ptr = tag_ptr.into_pointer_value();

View File

@ -20,6 +20,7 @@ use roc_module::symbol::{
};
use roc_mono::ir::{
CapturedSymbols, EntryPoint, ExternalSpecializations, PartialProc, Proc, ProcLayout, Procs,
UpdateModeIds,
};
use roc_mono::layout::{Layout, LayoutCache, LayoutProblem};
use roc_parse::ast::{self, StrLiteral, TypeAnnotation};
@ -835,6 +836,7 @@ enum Msg<'a> {
external_specializations_requested: BumpMap<ModuleId, ExternalSpecializations>,
procedures: MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>,
problems: Vec<roc_mono::ir::MonoProblem>,
update_mode_ids: UpdateModeIds,
module_timing: ModuleTiming,
subs: Subs,
},
@ -2098,6 +2100,7 @@ fn update<'a>(
MadeSpecializations {
module_id,
mut ident_ids,
mut update_mode_ids,
subs,
procedures,
external_specializations_requested,
@ -2124,6 +2127,7 @@ fn update<'a>(
arena,
module_id,
&mut ident_ids,
&mut update_mode_ids,
&mut state.procedures,
);
@ -3922,6 +3926,7 @@ fn make_specializations<'a>(
) -> Msg<'a> {
let make_specializations_start = SystemTime::now();
let mut mono_problems = Vec::new();
let mut update_mode_ids = UpdateModeIds::new();
// do the thing
let mut mono_env = roc_mono::ir::Env {
arena,
@ -3930,7 +3935,7 @@ fn make_specializations<'a>(
home,
ident_ids: &mut ident_ids,
ptr_bytes,
update_mode_counter: 0,
update_mode_ids: &mut update_mode_ids,
// call_specialization_counter=0 is reserved
call_specialization_counter: 1,
};
@ -3973,6 +3978,7 @@ fn make_specializations<'a>(
layout_cache,
procedures,
problems: mono_problems,
update_mode_ids,
subs,
external_specializations_requested,
module_timing,
@ -4016,6 +4022,7 @@ fn build_pending_specializations<'a>(
};
let mut mono_problems = std::vec::Vec::new();
let mut update_mode_ids = UpdateModeIds::new();
let mut subs = solved_subs.into_inner();
let mut mono_env = roc_mono::ir::Env {
arena,
@ -4024,7 +4031,7 @@ fn build_pending_specializations<'a>(
home,
ident_ids: &mut ident_ids,
ptr_bytes,
update_mode_counter: 0,
update_mode_ids: &mut update_mode_ids,
// call_specialization_counter=0 is reserved
call_specialization_counter: 1,
};

View File

@ -210,12 +210,15 @@ where
let mut builder = TypeDefBuilder::new();
let variant_types = build_variant_types(&mut builder, &union_layout)?;
let variant_types = recursive_variant_types(&mut builder, &union_layout)?;
let root_type = if let UnionLayout::NonNullableUnwrapped(_) = union_layout {
debug_assert_eq!(variant_types.len(), 1);
variant_types[0]
} else {
builder.add_union_type(&variant_types)?
let data_type = builder.add_union_type(&variant_types)?;
let cell_type = builder.add_heap_cell_type();
builder.add_tuple_type(&[cell_type, data_type])?
};
let type_def = builder.build(root_type)?;
@ -867,8 +870,7 @@ fn call_spec(
builder.add_update(block, update_mode_var, cell)?;
let new_cell = builder.add_new_heap_cell(block)?;
builder.add_make_tuple(block, &[new_cell, bag])
with_new_heap_cell(builder, block, bag)
};
let state_layout = Layout::Builtin(Builtin::List(&arg_layouts[0]));
@ -998,9 +1000,8 @@ fn call_spec(
builder.add_recursive_touch(block, removed_element)?;
let new_bag = builder.add_get_tuple_field(block, removed, 0)?;
let new_cell = builder.add_new_heap_cell(block)?;
builder.add_make_tuple(block, &[new_cell, new_bag])
with_new_heap_cell(builder, block, new_bag)
};
let state_layout = Layout::Builtin(Builtin::List(&arg_layouts[0]));
@ -1181,8 +1182,7 @@ fn list_append(
let new_bag = builder.add_bag_insert(block, bag, to_insert)?;
let new_cell = builder.add_new_heap_cell(block)?;
builder.add_make_tuple(block, &[new_cell, new_bag])
with_new_heap_cell(builder, block, new_bag)
}
fn lowlevel_spec(
@ -1268,8 +1268,7 @@ fn lowlevel_spec(
builder.add_bag_insert(block, bag, to_insert)?;
let new_cell = builder.add_new_heap_cell(block)?;
builder.add_make_tuple(block, &[new_cell, bag])
with_new_heap_cell(builder, block, bag)
}
ListSwap => {
let list = env.symbols[&arguments[0]];
@ -1279,8 +1278,7 @@ fn lowlevel_spec(
let _unit = builder.add_update(block, update_mode_var, cell)?;
let new_cell = builder.add_new_heap_cell(block)?;
builder.add_make_tuple(block, &[new_cell, bag])
with_new_heap_cell(builder, block, bag)
}
ListReverse => {
let list = env.symbols[&arguments[0]];
@ -1290,8 +1288,7 @@ fn lowlevel_spec(
let _unit = builder.add_update(block, update_mode_var, cell)?;
let new_cell = builder.add_new_heap_cell(block)?;
builder.add_make_tuple(block, &[new_cell, bag])
with_new_heap_cell(builder, block, bag)
}
ListAppend => {
let list = env.symbols[&arguments[0]];
@ -1359,8 +1356,7 @@ fn lowlevel_spec(
builder.add_bag_insert(block, bag, key_value)?;
let new_cell = builder.add_new_heap_cell(block)?;
builder.add_make_tuple(block, &[new_cell, bag])
with_new_heap_cell(builder, block, bag)
}
_other => {
// println!("missing {:?}", _other);
@ -1381,13 +1377,10 @@ fn recursive_tag_variant(
) -> Result<TypeId> {
let when_recursive = WhenRecursive::Loop(*union_layout);
let data_id = build_recursive_tuple_type(builder, fields, &when_recursive)?;
let cell_id = builder.add_heap_cell_type();
builder.add_tuple_type(&[cell_id, data_id])
build_recursive_tuple_type(builder, fields, &when_recursive)
}
fn build_variant_types(
fn recursive_variant_types(
builder: &mut impl TypeContext,
union_layout: &UnionLayout,
) -> Result<Vec<TypeId>> {
@ -1396,12 +1389,8 @@ fn build_variant_types(
let mut result;
match union_layout {
NonRecursive(tags) => {
result = Vec::with_capacity(tags.len());
for tag in tags.iter() {
result.push(build_tuple_type(builder, tag)?);
}
NonRecursive(_) => {
unreachable!()
}
Recursive(tags) => {
result = Vec::with_capacity(tags.len());
@ -1425,8 +1414,7 @@ fn build_variant_types(
result.push(recursive_tag_variant(builder, union_layout, tag)?);
}
let unit = builder.add_tuple_type(&[])?;
result.push(unit);
result.push(recursive_tag_variant(builder, union_layout, &[])?);
for tag in tags[cutoff..].iter() {
result.push(recursive_tag_variant(builder, union_layout, tag)?);
@ -1436,7 +1424,7 @@ fn build_variant_types(
nullable_id,
other_fields: fields,
} => {
let unit = builder.add_tuple_type(&[])?;
let unit = recursive_tag_variant(builder, union_layout, &[])?;
let other_type = recursive_tag_variant(builder, union_layout, fields)?;
if *nullable_id {
@ -1482,18 +1470,16 @@ fn expr_spec<'a>(
tag_id,
arguments,
} => {
let variant_types = build_variant_types(builder, tag_layout)?;
let data_id = build_tuple_value(builder, env, block, arguments)?;
let cell_id = builder.add_new_heap_cell(block)?;
let value_id = match tag_layout {
UnionLayout::NonRecursive(_) => {
UnionLayout::NonRecursive(tags) => {
let variant_types = non_recursive_variant_types(builder, tags)?;
let value_id = build_tuple_value(builder, env, block, arguments)?;
return builder.add_make_union(block, &variant_types, *tag_id as u32, value_id);
}
UnionLayout::NonNullableUnwrapped(_) => {
let value_id = builder.add_make_tuple(block, &[cell_id, data_id])?;
let value_id = data_id;
let type_name_bytes = recursive_tag_union_name_bytes(tag_layout).as_bytes();
let type_name = TypeName(&type_name_bytes);
@ -1502,32 +1488,24 @@ fn expr_spec<'a>(
return builder.add_make_named(block, MOD_APP, type_name, value_id);
}
UnionLayout::Recursive(_) => builder.add_make_tuple(block, &[cell_id, data_id])?,
UnionLayout::NullableWrapped { nullable_id, .. } => {
if *tag_id == *nullable_id as _ {
data_id
} else {
builder.add_make_tuple(block, &[cell_id, data_id])?
}
}
UnionLayout::NullableUnwrapped { nullable_id, .. } => {
if *tag_id == *nullable_id as _ {
data_id
} else {
builder.add_make_tuple(block, &[cell_id, data_id])?
}
}
UnionLayout::Recursive(_) => data_id,
UnionLayout::NullableWrapped { .. } => data_id,
UnionLayout::NullableUnwrapped { .. } => data_id,
};
let variant_types = recursive_variant_types(builder, tag_layout)?;
let union_id =
builder.add_make_union(block, &variant_types, *tag_id as u32, value_id)?;
let tag_value_id = with_new_heap_cell(builder, block, union_id)?;
let type_name_bytes = recursive_tag_union_name_bytes(tag_layout).as_bytes();
let type_name = TypeName(&type_name_bytes);
env.type_names.insert(*tag_layout);
builder.add_make_named(block, MOD_APP, type_name, union_id)
builder.add_make_named(block, MOD_APP, type_name, tag_value_id)
}
Struct(fields) => build_tuple_value(builder, env, block, fields),
UnionAtIndex {
@ -1553,16 +1531,20 @@ fn expr_spec<'a>(
let type_name_bytes = recursive_tag_union_name_bytes(union_layout).as_bytes();
let type_name = TypeName(&type_name_bytes);
// unwrap the named wrapper
let union_id = builder.add_unwrap_named(block, MOD_APP, type_name, tag_value_id)?;
let variant_id = builder.add_unwrap_union(block, union_id, *tag_id as u32)?;
// now we have a tuple (cell, union { ... }); decompose
let heap_cell = builder.add_get_tuple_field(block, union_id, TAG_CELL_INDEX)?;
let union_data = builder.add_get_tuple_field(block, union_id, TAG_DATA_INDEX)?;
// we're reading from this value, so touch the heap cell
let heap_cell = builder.add_get_tuple_field(block, variant_id, 0)?;
builder.add_touch(block, heap_cell)?;
let tuple_value_id = builder.add_get_tuple_field(block, variant_id, 1)?;
// next, unwrap the union at the tag id that we've got
let variant_id = builder.add_unwrap_union(block, union_data, *tag_id as u32)?;
builder.add_get_tuple_field(block, tuple_value_id, index)
builder.add_get_tuple_field(block, variant_id, index)
}
UnionLayout::NonNullableUnwrapped { .. } => {
let index = (*index) as u32;
@ -1573,16 +1555,20 @@ fn expr_spec<'a>(
let type_name_bytes = recursive_tag_union_name_bytes(union_layout).as_bytes();
let type_name = TypeName(&type_name_bytes);
let variant_id =
builder.add_unwrap_named(block, MOD_APP, type_name, tag_value_id)?;
// a tuple ( cell, union { ... } )
let union_id = builder.add_unwrap_named(block, MOD_APP, type_name, tag_value_id)?;
// decompose
let heap_cell = builder.add_get_tuple_field(block, union_id, TAG_CELL_INDEX)?;
let union_data = builder.add_get_tuple_field(block, union_id, TAG_DATA_INDEX)?;
// we're reading from this value, so touch the heap cell
let heap_cell = builder.add_get_tuple_field(block, variant_id, 0)?;
builder.add_touch(block, heap_cell)?;
let tuple_value_id = builder.add_get_tuple_field(block, variant_id, 1)?;
// next, unwrap the union at the tag id that we've got
let variant_id = builder.add_unwrap_union(block, union_data, *tag_id as u32)?;
builder.add_get_tuple_field(block, tuple_value_id, index)
builder.add_get_tuple_field(block, variant_id, index)
}
},
StructAtIndex {
@ -1613,9 +1599,7 @@ fn expr_spec<'a>(
if all_constants {
new_static_list(builder, block)
} else {
let cell = builder.add_new_heap_cell(block)?;
builder.add_make_tuple(block, &[cell, bag])
with_new_heap_cell(builder, block, bag)
}
}
@ -1626,7 +1610,7 @@ fn expr_spec<'a>(
}
_ => unreachable!("empty array does not have a list layout"),
},
Reset(symbol) => {
Reset { symbol, .. } => {
let type_id = layout_spec(builder, layout)?;
let value_id = env.symbols[symbol];
@ -1637,7 +1621,11 @@ fn expr_spec<'a>(
builder.add_terminate(block, type_id)
}
GetTagId { .. } => builder.add_make_tuple(block, &[]),
GetTagId { .. } => {
// TODO touch heap cell in recursive cases
builder.add_make_tuple(block, &[])
}
}
}
@ -1658,6 +1646,19 @@ fn layout_spec(builder: &mut impl TypeContext, layout: &Layout) -> Result<TypeId
layout_spec_help(builder, layout, &WhenRecursive::Unreachable)
}
fn non_recursive_variant_types(
builder: &mut impl TypeContext,
tags: &[&[Layout]],
) -> Result<Vec<TypeId>> {
let mut result = Vec::with_capacity(tags.len());
for tag in tags.iter() {
result.push(build_tuple_type(builder, tag)?);
}
Ok(result)
}
fn layout_spec_help(
builder: &mut impl TypeContext,
layout: &Layout,
@ -1674,8 +1675,6 @@ fn layout_spec_help(
when_recursive,
),
Union(union_layout) => {
let variant_types = build_variant_types(builder, union_layout)?;
match union_layout {
UnionLayout::NonRecursive(&[]) => {
// must model Void as Unit, otherwise we run into problems where
@ -1683,7 +1682,10 @@ fn layout_spec_help(
// which is of course not possible
builder.add_tuple_type(&[])
}
UnionLayout::NonRecursive(_) => builder.add_union_type(&variant_types),
UnionLayout::NonRecursive(tags) => {
let variant_types = non_recursive_variant_types(builder, tags)?;
builder.add_union_type(&variant_types)
}
UnionLayout::Recursive(_)
| UnionLayout::NullableUnwrapped { .. }
| UnionLayout::NullableWrapped { .. }
@ -1777,10 +1779,21 @@ const LIST_BAG_INDEX: u32 = 1;
const DICT_CELL_INDEX: u32 = LIST_CELL_INDEX;
const DICT_BAG_INDEX: u32 = LIST_BAG_INDEX;
fn new_list(builder: &mut FuncDefBuilder, block: BlockId, element_type: TypeId) -> Result<ValueId> {
const TAG_CELL_INDEX: u32 = 0;
const TAG_DATA_INDEX: u32 = 1;
fn with_new_heap_cell(
builder: &mut FuncDefBuilder,
block: BlockId,
value: ValueId,
) -> Result<ValueId> {
let cell = builder.add_new_heap_cell(block)?;
builder.add_make_tuple(block, &[cell, value])
}
fn new_list(builder: &mut FuncDefBuilder, block: BlockId, element_type: TypeId) -> Result<ValueId> {
let bag = builder.add_empty_bag(block, element_type)?;
builder.add_make_tuple(block, &[cell, bag])
with_new_heap_cell(builder, block, bag)
}
fn new_dict(
@ -1789,10 +1802,9 @@ fn new_dict(
key_type: TypeId,
value_type: TypeId,
) -> Result<ValueId> {
let cell = builder.add_new_heap_cell(block)?;
let element_type = builder.add_tuple_type(&[key_type, value_type])?;
let bag = builder.add_empty_bag(block, element_type)?;
builder.add_make_tuple(block, &[cell, bag])
with_new_heap_cell(builder, block, bag)
}
fn new_static_string(builder: &mut FuncDefBuilder, block: BlockId) -> Result<ValueId> {

View File

@ -726,7 +726,7 @@ impl<'a> BorrowInfState<'a> {
// the function must take it as an owned parameter
self.own_args_if_param(xs);
}
Reset(x) => {
Reset { symbol: x, .. } => {
self.own_var(z);
self.own_var(*x);
}

View File

@ -110,7 +110,7 @@ pub fn occurring_variables_expr(expr: &Expr<'_>, result: &mut MutSet<Symbol>) {
result.extend(arguments.iter().copied());
result.insert(*symbol);
}
Reset(x) => {
Reset { symbol: x, .. } => {
result.insert(*x);
}
@ -761,7 +761,7 @@ impl<'a> Context<'a> {
self.arena.alloc(Stmt::Let(z, v, l, b))
}
EmptyArray | Literal(_) | Reset(_) | RuntimeErrorFunction(_) => {
EmptyArray | Literal(_) | Reset { .. } | RuntimeErrorFunction(_) => {
// EmptyArray is always stack-allocated
// function pointers are persistent
self.arena.alloc(Stmt::Let(z, v, l, b))
@ -779,7 +779,7 @@ impl<'a> Context<'a> {
// must this value be consumed?
let consume = consume_expr(&self.vars, expr);
let reset = matches!(expr, Expr::Reset(_));
let reset = matches!(expr, Expr::Reset { .. });
self.update_var_info_help(symbol, layout, persistent, consume, reset)
}

View File

@ -37,8 +37,8 @@ static_assertions::assert_eq_size!([u8; 19 * 8], Stmt);
#[cfg(target_arch = "aarch64")]
static_assertions::assert_eq_size!([u8; 20 * 8], Stmt);
static_assertions::assert_eq_size!([u8; 6 * 8], ProcLayout);
static_assertions::assert_eq_size!([u8; 8 * 8], Call);
static_assertions::assert_eq_size!([u8; 6 * 8], CallType);
static_assertions::assert_eq_size!([u8; 7 * 8], Call);
static_assertions::assert_eq_size!([u8; 5 * 8], CallType);
macro_rules! return_on_layout_error {
($env:expr, $layout_result:expr) => {
@ -318,11 +318,17 @@ impl<'a> Proc<'a> {
arena: &'a Bump,
home: ModuleId,
ident_ids: &'i mut IdentIds,
update_mode_ids: &'i mut UpdateModeIds,
procs: &mut MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>,
) {
for (_, proc) in procs.iter_mut() {
let new_proc =
crate::reset_reuse::insert_reset_reuse(arena, home, ident_ids, proc.clone());
let new_proc = crate::reset_reuse::insert_reset_reuse(
arena,
home,
ident_ids,
update_mode_ids,
proc.clone(),
);
*proc = new_proc;
}
}
@ -988,8 +994,8 @@ pub struct Env<'a, 'i> {
pub home: ModuleId,
pub ident_ids: &'i mut IdentIds,
pub ptr_bytes: u32,
pub update_mode_counter: u64,
pub call_specialization_counter: u64,
pub update_mode_ids: &'i mut UpdateModeIds,
pub call_specialization_counter: u32,
}
impl<'a, 'i> Env<'a, 'i> {
@ -1000,13 +1006,7 @@ impl<'a, 'i> Env<'a, 'i> {
}
pub fn next_update_mode_id(&mut self) -> UpdateModeId {
let id = UpdateModeId {
id: self.update_mode_counter,
};
self.update_mode_counter += 1;
id
self.update_mode_ids.next_id()
}
pub fn next_call_specialization_id(&mut self) -> CallSpecId {
@ -1282,26 +1282,43 @@ impl<'a> Call<'a> {
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct CallSpecId {
id: u64,
id: u32,
}
impl CallSpecId {
pub fn to_bytes(self) -> [u8; 8] {
pub fn to_bytes(self) -> [u8; 4] {
self.id.to_ne_bytes()
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct UpdateModeId {
id: u64,
id: u32,
}
impl UpdateModeId {
pub fn to_bytes(self) -> [u8; 8] {
pub fn to_bytes(self) -> [u8; 4] {
self.id.to_ne_bytes()
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct UpdateModeIds {
next: u32,
}
impl UpdateModeIds {
pub const fn new() -> Self {
Self { next: 0 }
}
pub fn next_id(&mut self) -> UpdateModeId {
let id = UpdateModeId { id: self.next };
self.next += 1;
id
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum CallType<'a> {
ByName {
@ -1390,13 +1407,17 @@ pub enum Expr<'a> {
Reuse {
symbol: Symbol,
update_tag_id: bool,
update_mode: UpdateModeId,
// normal Tag fields
tag_layout: UnionLayout<'a>,
tag_name: TagName,
tag_id: TagIdIntType,
arguments: &'a [Symbol],
},
Reset(Symbol),
Reset {
symbol: Symbol,
update_mode: UpdateModeId,
},
RuntimeErrorFunction(&'a str),
}
@ -1491,6 +1512,7 @@ impl<'a> Expr<'a> {
symbol,
tag_name,
arguments,
update_mode,
..
} => {
let doc_tag = match tag_name {
@ -1508,11 +1530,19 @@ impl<'a> Expr<'a> {
.text("Reuse ")
.append(symbol_to_doc(alloc, *symbol))
.append(alloc.space())
.append(format!("{:?}", update_mode))
.append(alloc.space())
.append(doc_tag)
.append(alloc.space())
.append(alloc.intersperse(it, " "))
}
Reset(symbol) => alloc.text("Reset ").append(symbol_to_doc(alloc, *symbol)),
Reset {
symbol,
update_mode,
} => alloc.text(format!(
"Reset {{ symbol: {:?}, id: {} }}",
symbol, update_mode.id
)),
Struct(args) => {
let it = args.iter().map(|s| symbol_to_doc(alloc, *s));
@ -5715,7 +5745,7 @@ fn substitute_in_expr<'a>(
}
}
Reuse { .. } | Reset(_) => unreachable!("reset/reuse have not been introduced yet"),
Reuse { .. } | Reset { .. } => unreachable!("reset/reuse have not been introduced yet"),
Struct(args) => {
let mut did_change = false;

View File

@ -1,5 +1,7 @@
use crate::inc_dec::{collect_stmt, occurring_variables_expr, JPLiveVarMap, LiveVarSet};
use crate::ir::{BranchInfo, Call, Expr, ListLiteralElement, Proc, Stmt};
use crate::ir::{
BranchInfo, Call, Expr, ListLiteralElement, Proc, Stmt, UpdateModeId, UpdateModeIds,
};
use crate::layout::{Layout, TagIdIntType, UnionLayout};
use bumpalo::collections::Vec;
use bumpalo::Bump;
@ -10,12 +12,14 @@ pub fn insert_reset_reuse<'a, 'i>(
arena: &'a Bump,
home: ModuleId,
ident_ids: &'i mut IdentIds,
update_mode_ids: &'i mut UpdateModeIds,
mut proc: Proc<'a>,
) -> Proc<'a> {
let mut env = Env {
arena,
home,
ident_ids,
update_mode_ids,
jp_live_vars: Default::default(),
};
@ -50,6 +54,7 @@ struct Env<'a, 'i> {
/// required for creating new `Symbol`s
home: ModuleId,
ident_ids: &'i mut IdentIds,
update_mode_ids: &'i mut UpdateModeIds,
jp_live_vars: JPLiveVarMap,
}
@ -64,7 +69,7 @@ impl<'a, 'i> Env<'a, 'i> {
fn function_s<'a, 'i>(
env: &mut Env<'a, 'i>,
w: Symbol,
w: Opportunity,
c: &CtorInfo<'a>,
stmt: &'a Stmt<'a>,
) -> &'a Stmt<'a> {
@ -84,7 +89,8 @@ fn function_s<'a, 'i>(
let update_tag_id = true;
let new_expr = Expr::Reuse {
symbol: w,
symbol: w.symbol,
update_mode: w.update_mode,
update_tag_id,
tag_layout: *tag_layout,
tag_id: *tag_id,
@ -175,13 +181,22 @@ fn function_s<'a, 'i>(
}
}
#[derive(Clone, Copy)]
struct Opportunity {
symbol: Symbol,
update_mode: UpdateModeId,
}
fn try_function_s<'a, 'i>(
env: &mut Env<'a, 'i>,
x: Symbol,
c: &CtorInfo<'a>,
stmt: &'a Stmt<'a>,
) -> &'a Stmt<'a> {
let w = env.unique_symbol();
let w = Opportunity {
symbol: env.unique_symbol(),
update_mode: env.update_mode_ids.next_id(),
};
let new_stmt = function_s(env, w, c, stmt);
@ -194,7 +209,7 @@ fn try_function_s<'a, 'i>(
fn insert_reset<'a>(
env: &mut Env<'a, '_>,
w: Symbol,
w: Opportunity,
x: Symbol,
union_layout: UnionLayout<'a>,
mut stmt: &'a Stmt<'a>,
@ -216,16 +231,21 @@ fn insert_reset<'a>(
| Array { .. }
| EmptyArray
| Reuse { .. }
| Reset(_)
| Reset { .. }
| RuntimeErrorFunction(_) => break,
}
}
let reset_expr = Expr::Reset(x);
let reset_expr = Expr::Reset {
symbol: x,
update_mode: w.update_mode,
};
let layout = Layout::Union(union_layout);
stmt = env.arena.alloc(Stmt::Let(w, reset_expr, layout, stmt));
stmt = env
.arena
.alloc(Stmt::Let(w.symbol, reset_expr, layout, stmt));
for (symbol, expr, expr_layout) in stack.into_iter().rev() {
stmt = env
@ -584,7 +604,7 @@ fn has_live_var_expr<'a>(expr: &'a Expr<'a>, needle: Symbol) -> bool {
Expr::Reuse {
symbol, arguments, ..
} => needle == *symbol || arguments.iter().any(|s| *s == needle),
Expr::Reset(symbol) => needle == *symbol,
Expr::Reset { symbol, .. } => needle == *symbol,
Expr::RuntimeErrorFunction(_) => false,
}
}

View File

@ -13,7 +13,7 @@ mod test_reporting {
use crate::helpers::{can_expr, infer_expr, CanExprOut, ParseErrOut};
use bumpalo::Bump;
use roc_module::symbol::{Interns, ModuleId};
use roc_mono::ir::{Procs, Stmt};
use roc_mono::ir::{Procs, Stmt, UpdateModeIds};
use roc_mono::layout::LayoutCache;
use roc_reporting::report::{
can_problem, mono_problem, parse_problem, type_problem, Report, Severity, BLUE_CODE,
@ -91,6 +91,7 @@ mod test_reporting {
// Compile and add all the Procs before adding main
let mut procs = Procs::new_in(&arena);
let mut ident_ids = interns.all_ident_ids.remove(&home).unwrap();
let mut update_mode_ids = UpdateModeIds::new();
// Populate Procs and Subs, and get the low-level Expr from the canonical Expr
let ptr_bytes = 8;
@ -101,8 +102,8 @@ mod test_reporting {
problems: &mut mono_problems,
home,
ident_ids: &mut ident_ids,
update_mode_ids: &mut update_mode_ids,
ptr_bytes,
update_mode_counter: 0,
// call_specialization_counter=0 is reserved
call_specialization_counter: 1,
};