mirror of
https://github.com/roc-lang/roc.git
synced 2025-07-24 06:55:15 +00:00
Merge pull request #5452 from JTeeuwissen/save-construction-children
Add construction (Struct/TagId/List/Box) to known parent/child relations
This commit is contained in:
commit
ef05ec6906
18 changed files with 246 additions and 150 deletions
|
@ -3115,7 +3115,6 @@ fn update<'a>(
|
|||
&mut layout_interner,
|
||||
module_id,
|
||||
ident_ids,
|
||||
state.target_info,
|
||||
&mut state.procedures,
|
||||
);
|
||||
|
||||
|
|
|
@ -15,11 +15,10 @@ use bumpalo::collections::CollectIn;
|
|||
|
||||
use roc_module::low_level::LowLevel;
|
||||
use roc_module::symbol::{IdentIds, ModuleId, Symbol};
|
||||
use roc_target::TargetInfo;
|
||||
|
||||
use crate::ir::{
|
||||
BranchInfo, Call, CallType, Expr, JoinPointId, Literal, ModifyRc, Proc, ProcLayout, Stmt,
|
||||
UpdateModeId,
|
||||
BranchInfo, Call, CallType, Expr, JoinPointId, ListLiteralElement, Literal, ModifyRc, Proc,
|
||||
ProcLayout, Stmt, UpdateModeId,
|
||||
};
|
||||
use crate::layout::{
|
||||
Builtin, InLayout, Layout, LayoutInterner, LayoutRepr, STLayoutInterner, UnionLayout,
|
||||
|
@ -27,7 +26,7 @@ use crate::layout::{
|
|||
|
||||
use bumpalo::Bump;
|
||||
|
||||
use roc_collections::{MutMap, MutSet};
|
||||
use roc_collections::MutMap;
|
||||
|
||||
/**
|
||||
Try to find increments of symbols followed by decrements of the symbol they were indexed out of (their parent).
|
||||
|
@ -38,12 +37,10 @@ pub fn specialize_drops<'a, 'i>(
|
|||
layout_interner: &'i mut STLayoutInterner<'a>,
|
||||
home: ModuleId,
|
||||
ident_ids: &'i mut IdentIds,
|
||||
target_info: TargetInfo,
|
||||
procs: &mut MutMap<(Symbol, ProcLayout<'a>), Proc<'a>>,
|
||||
) {
|
||||
for ((_symbol, proc_layout), proc) in procs.iter_mut() {
|
||||
let mut environment =
|
||||
DropSpecializationEnvironment::new(arena, home, proc_layout.result, target_info);
|
||||
let mut environment = DropSpecializationEnvironment::new(arena, home, proc_layout.result);
|
||||
specialize_drops_proc(arena, layout_interner, ident_ids, &mut environment, proc);
|
||||
}
|
||||
}
|
||||
|
@ -104,7 +101,7 @@ fn specialize_drops_stmt<'a, 'i>(
|
|||
_ => unreachable!("List get should have two arguments"),
|
||||
};
|
||||
|
||||
environment.add_list_child(*structure, *binding, index);
|
||||
environment.add_list_child_symbol(*structure, *binding, index);
|
||||
|
||||
alloc_let_with_continuation!(environment)
|
||||
}
|
||||
|
@ -114,9 +111,18 @@ fn specialize_drops_stmt<'a, 'i>(
|
|||
RC::NoRc => alloc_let_with_continuation!(environment),
|
||||
// We probably should not pass the increments to the continuation.
|
||||
RC::Rc | RC::Uknown => {
|
||||
let mut new_environment = environment.clone_without_incremented();
|
||||
let incremented_symbols = environment.incremented_symbols.drain();
|
||||
|
||||
alloc_let_with_continuation!(&mut new_environment)
|
||||
let new_stmt = alloc_let_with_continuation!(environment);
|
||||
|
||||
// The new_environment might have inserted increments that were set to 0 before. We need to add th
|
||||
for (symbol, increment) in incremented_symbols.map.into_iter() {
|
||||
environment
|
||||
.incremented_symbols
|
||||
.insert_count(symbol, increment);
|
||||
}
|
||||
|
||||
new_stmt
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
|
@ -127,16 +133,62 @@ fn specialize_drops_stmt<'a, 'i>(
|
|||
// the parent might be deallocated before the function can use it.
|
||||
// Thus forget everything about any increments.
|
||||
|
||||
let mut new_environment = environment.clone_without_incremented();
|
||||
let incremented_symbols = environment.incremented_symbols.drain();
|
||||
|
||||
alloc_let_with_continuation!(&mut new_environment)
|
||||
let new_stmt = alloc_let_with_continuation!(environment);
|
||||
|
||||
// The new_environment might have inserted increments that were set to 0 before. We need to add th
|
||||
for (symbol, increment) in incremented_symbols.map.into_iter() {
|
||||
environment
|
||||
.incremented_symbols
|
||||
.insert_count(symbol, increment);
|
||||
}
|
||||
|
||||
new_stmt
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Expr::Tag { tag_id, .. } => {
|
||||
Expr::Tag {
|
||||
tag_id,
|
||||
arguments: children,
|
||||
..
|
||||
} => {
|
||||
environment.symbol_tag.insert(*binding, *tag_id);
|
||||
|
||||
for (index, child) in children.iter().enumerate() {
|
||||
environment.add_union_child(*binding, *child, *tag_id, index as u64);
|
||||
}
|
||||
|
||||
alloc_let_with_continuation!(environment)
|
||||
}
|
||||
Expr::Struct(children) => {
|
||||
for (index, child) in children.iter().enumerate() {
|
||||
environment.add_struct_child(*binding, *child, index as u64);
|
||||
}
|
||||
|
||||
alloc_let_with_continuation!(environment)
|
||||
}
|
||||
Expr::ExprBox { symbol: child } => {
|
||||
environment.add_box_child(*binding, *child);
|
||||
|
||||
alloc_let_with_continuation!(environment)
|
||||
}
|
||||
Expr::Array {
|
||||
elems: children, ..
|
||||
} => {
|
||||
for (index, child) in
|
||||
children
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(index, child)| match child {
|
||||
ListLiteralElement::Literal(_) => None,
|
||||
ListLiteralElement::Symbol(s) => Some((index, s)),
|
||||
})
|
||||
{
|
||||
environment.add_list_child(*binding, *child, index as u64);
|
||||
}
|
||||
|
||||
alloc_let_with_continuation!(environment)
|
||||
}
|
||||
Expr::StructAtIndex {
|
||||
|
@ -188,13 +240,10 @@ fn specialize_drops_stmt<'a, 'i>(
|
|||
}
|
||||
alloc_let_with_continuation!(environment)
|
||||
}
|
||||
Expr::Struct(_)
|
||||
| Expr::RuntimeErrorFunction(_)
|
||||
| Expr::ExprBox { .. }
|
||||
Expr::RuntimeErrorFunction(_)
|
||||
| Expr::NullPointer
|
||||
| Expr::GetTagId { .. }
|
||||
| Expr::EmptyArray
|
||||
| Expr::Array { .. } => {
|
||||
| Expr::EmptyArray => {
|
||||
// Does nothing relevant to drop specialization. So we can just continue.
|
||||
alloc_let_with_continuation!(environment)
|
||||
}
|
||||
|
@ -283,10 +332,12 @@ fn specialize_drops_stmt<'a, 'i>(
|
|||
};
|
||||
|
||||
// Find the lowest symbol count for each symbol in each branch, and update the environment to match.
|
||||
for (symbol, count) in environment.incremented_symbols.iter_mut() {
|
||||
for (symbol, count) in environment.incremented_symbols.map.iter_mut() {
|
||||
let consumed = branch_envs
|
||||
.iter()
|
||||
.map(|branch_env| branch_env.incremented_symbols.get(symbol).unwrap_or(&0))
|
||||
.map(|branch_env| {
|
||||
branch_env.incremented_symbols.map.get(symbol).unwrap_or(&0)
|
||||
})
|
||||
.min()
|
||||
.unwrap();
|
||||
|
||||
|
@ -300,10 +351,14 @@ fn specialize_drops_stmt<'a, 'i>(
|
|||
let symbol_differences =
|
||||
environment
|
||||
.incremented_symbols
|
||||
.map
|
||||
.iter()
|
||||
.filter_map(|(symbol, count)| {
|
||||
let branch_count =
|
||||
$branch_env.incremented_symbols.get(symbol).unwrap_or(&0);
|
||||
let branch_count = $branch_env
|
||||
.incremented_symbols
|
||||
.map
|
||||
.get(symbol)
|
||||
.unwrap_or(&0);
|
||||
|
||||
match branch_count - count {
|
||||
0 => None,
|
||||
|
@ -338,11 +393,6 @@ fn specialize_drops_stmt<'a, 'i>(
|
|||
(info.clone(), new_branch)
|
||||
};
|
||||
|
||||
// Remove all 0 counts as cleanup.
|
||||
environment
|
||||
.incremented_symbols
|
||||
.retain(|_, count| *count > 0);
|
||||
|
||||
arena.alloc(Stmt::Switch {
|
||||
cond_symbol: *cond_symbol,
|
||||
cond_layout: *cond_layout,
|
||||
|
@ -354,10 +404,12 @@ fn specialize_drops_stmt<'a, 'i>(
|
|||
Stmt::Ret(symbol) => arena.alloc(Stmt::Ret(*symbol)),
|
||||
Stmt::Refcounting(rc, continuation) => match rc {
|
||||
ModifyRc::Inc(symbol, count) => {
|
||||
let any = environment.any_incremented(symbol);
|
||||
let inc_before = environment.incremented_symbols.contains(symbol);
|
||||
|
||||
// Add a symbol for every increment performed.
|
||||
environment.add_incremented(*symbol, *count);
|
||||
environment
|
||||
.incremented_symbols
|
||||
.insert_count(*symbol, *count);
|
||||
|
||||
let new_continuation = specialize_drops_stmt(
|
||||
arena,
|
||||
|
@ -367,12 +419,17 @@ fn specialize_drops_stmt<'a, 'i>(
|
|||
continuation,
|
||||
);
|
||||
|
||||
if any {
|
||||
if inc_before {
|
||||
// There were increments before this one, best to let the first one do the increments.
|
||||
// Or there are no increments left, so we can just continue.
|
||||
new_continuation
|
||||
} else {
|
||||
match environment.get_incremented(symbol) {
|
||||
match environment
|
||||
.incremented_symbols
|
||||
.map
|
||||
.remove(symbol)
|
||||
.unwrap_or(0)
|
||||
{
|
||||
// This is the first increment, but all increments are consumed. So don't insert any.
|
||||
0 => new_continuation,
|
||||
// We still need to do some increments.
|
||||
|
@ -393,7 +450,7 @@ fn specialize_drops_stmt<'a, 'i>(
|
|||
// dec a
|
||||
// dec b
|
||||
|
||||
if environment.pop_incremented(symbol) {
|
||||
if environment.incremented_symbols.pop(symbol) {
|
||||
// This decremented symbol was incremented before, so we can remove it.
|
||||
specialize_drops_stmt(
|
||||
arena,
|
||||
|
@ -411,10 +468,10 @@ fn specialize_drops_stmt<'a, 'i>(
|
|||
// As a might get dropped as a result of the decrement of b.
|
||||
let mut incremented_children = {
|
||||
let mut todo_children = bumpalo::vec![in arena; *symbol];
|
||||
let mut incremented_children = MutSet::default();
|
||||
let mut incremented_children = CountingMap::new();
|
||||
|
||||
while let Some(child) = todo_children.pop() {
|
||||
if environment.pop_incremented(&child) {
|
||||
if environment.incremented_symbols.pop(&child) {
|
||||
incremented_children.insert(child);
|
||||
} else {
|
||||
todo_children.extend(environment.get_children(&child));
|
||||
|
@ -485,8 +542,10 @@ fn specialize_drops_stmt<'a, 'i>(
|
|||
};
|
||||
|
||||
// Add back the increments for the children to the environment.
|
||||
for child_symbol in incremented_children.iter() {
|
||||
environment.add_incremented(*child_symbol, 1)
|
||||
for (child_symbol, symbol_count) in incremented_children.map.into_iter() {
|
||||
environment
|
||||
.incremented_symbols
|
||||
.insert_count(child_symbol, symbol_count)
|
||||
}
|
||||
|
||||
updated_stmt
|
||||
|
@ -565,7 +624,8 @@ fn specialize_drops_stmt<'a, 'i>(
|
|||
body,
|
||||
remainder,
|
||||
} => {
|
||||
let mut new_environment = environment.clone_without_incremented();
|
||||
let mut new_environment = environment.clone();
|
||||
new_environment.incremented_symbols.clear();
|
||||
|
||||
for param in parameters.iter() {
|
||||
new_environment.add_symbol_layout(param.symbol, param.layout);
|
||||
|
@ -604,7 +664,7 @@ fn specialize_struct<'a, 'i>(
|
|||
environment: &mut DropSpecializationEnvironment<'a>,
|
||||
symbol: &Symbol,
|
||||
struct_layout: &'a [InLayout],
|
||||
incremented_children: &mut MutSet<Child>,
|
||||
incremented_children: &mut CountingMap<Child>,
|
||||
continuation: &'a Stmt<'a>,
|
||||
) -> &'a Stmt<'a> {
|
||||
match environment.struct_children.get(symbol) {
|
||||
|
@ -620,7 +680,7 @@ fn specialize_struct<'a, 'i>(
|
|||
|
||||
for (index, _layout) in struct_layout.iter().enumerate() {
|
||||
for (child, _i) in children_clone.iter().filter(|(_, i)| *i == index as u64) {
|
||||
let removed = incremented_children.remove(child);
|
||||
let removed = incremented_children.pop(child);
|
||||
index_symbols.insert(index, (*child, removed));
|
||||
|
||||
if removed {
|
||||
|
@ -693,7 +753,7 @@ fn specialize_union<'a, 'i>(
|
|||
environment: &mut DropSpecializationEnvironment<'a>,
|
||||
symbol: &Symbol,
|
||||
union_layout: UnionLayout<'a>,
|
||||
incremented_children: &mut MutSet<Child>,
|
||||
incremented_children: &mut CountingMap<Child>,
|
||||
continuation: &'a Stmt<'a>,
|
||||
) -> &'a Stmt<'a> {
|
||||
let current_tag = environment.symbol_tag.get(symbol).copied();
|
||||
|
@ -736,7 +796,7 @@ fn specialize_union<'a, 'i>(
|
|||
{
|
||||
debug_assert_eq!(tag, *t);
|
||||
|
||||
let removed = incremented_children.remove(child);
|
||||
let removed = incremented_children.pop(child);
|
||||
index_symbols.insert(index, (*child, removed));
|
||||
|
||||
if removed {
|
||||
|
@ -898,14 +958,14 @@ fn specialize_boxed<'a, 'i>(
|
|||
layout_interner: &'i mut STLayoutInterner<'a>,
|
||||
ident_ids: &'i mut IdentIds,
|
||||
environment: &mut DropSpecializationEnvironment<'a>,
|
||||
incremented_children: &mut MutSet<Child>,
|
||||
incremented_children: &mut CountingMap<Child>,
|
||||
symbol: &Symbol,
|
||||
continuation: &'a Stmt<'a>,
|
||||
) -> &'a Stmt<'a> {
|
||||
let removed = match incremented_children.iter().next() {
|
||||
Some(s) => {
|
||||
let removed = match incremented_children.map.iter().next() {
|
||||
Some((s, _)) => {
|
||||
let s = *s;
|
||||
incremented_children.remove(&s);
|
||||
incremented_children.pop(&s);
|
||||
Some(s)
|
||||
}
|
||||
None => None,
|
||||
|
@ -924,23 +984,20 @@ fn specialize_boxed<'a, 'i>(
|
|||
*symbol,
|
||||
// If the symbol is unique:
|
||||
// - free the box
|
||||
|_, _, _| {
|
||||
|_, _, continuation| {
|
||||
arena.alloc(Stmt::Refcounting(
|
||||
// TODO can be replaced by free if ever added to the IR.
|
||||
ModifyRc::DecRef(*symbol),
|
||||
new_continuation,
|
||||
continuation,
|
||||
))
|
||||
},
|
||||
// If the symbol is not unique:
|
||||
// - increment the child
|
||||
// - decref the box
|
||||
|_, _, _| {
|
||||
|_, _, continuation| {
|
||||
arena.alloc(Stmt::Refcounting(
|
||||
ModifyRc::Inc(s, 1),
|
||||
arena.alloc(Stmt::Refcounting(
|
||||
ModifyRc::DecRef(*symbol),
|
||||
new_continuation,
|
||||
)),
|
||||
arena.alloc(Stmt::Refcounting(ModifyRc::DecRef(*symbol), continuation)),
|
||||
))
|
||||
},
|
||||
new_continuation,
|
||||
|
@ -958,7 +1015,7 @@ fn specialize_list<'a, 'i>(
|
|||
layout_interner: &'i mut STLayoutInterner<'a>,
|
||||
ident_ids: &'i mut IdentIds,
|
||||
environment: &mut DropSpecializationEnvironment<'a>,
|
||||
incremented_children: &mut MutSet<Child>,
|
||||
incremented_children: &mut CountingMap<Child>,
|
||||
symbol: &Symbol,
|
||||
item_layout: InLayout,
|
||||
continuation: &'a Stmt<'a>,
|
||||
|
@ -993,7 +1050,7 @@ fn specialize_list<'a, 'i>(
|
|||
for (child, i) in children_clone.iter().filter(|(_child, i)| *i == index) {
|
||||
debug_assert!(length > *i);
|
||||
|
||||
let removed = incremented_children.remove(child);
|
||||
let removed = incremented_children.pop(child);
|
||||
index_symbols.insert(index, (*child, removed));
|
||||
|
||||
if removed {
|
||||
|
@ -1214,7 +1271,6 @@ struct DropSpecializationEnvironment<'a> {
|
|||
arena: &'a Bump,
|
||||
home: ModuleId,
|
||||
layout: InLayout<'a>,
|
||||
target_info: TargetInfo,
|
||||
|
||||
symbol_layouts: MutMap<Symbol, InLayout<'a>>,
|
||||
|
||||
|
@ -1231,7 +1287,7 @@ struct DropSpecializationEnvironment<'a> {
|
|||
list_children: MutMap<Parent, Vec<'a, (Child, Index)>>,
|
||||
|
||||
// Keeps track of all incremented symbols.
|
||||
incremented_symbols: MutMap<Symbol, u64>,
|
||||
incremented_symbols: CountingMap<Symbol>,
|
||||
|
||||
// Map containing the current known tag of a layout.
|
||||
symbol_tag: MutMap<Symbol, Tag>,
|
||||
|
@ -1244,42 +1300,23 @@ struct DropSpecializationEnvironment<'a> {
|
|||
}
|
||||
|
||||
impl<'a> DropSpecializationEnvironment<'a> {
|
||||
fn new(arena: &'a Bump, home: ModuleId, layout: InLayout<'a>, target_info: TargetInfo) -> Self {
|
||||
fn new(arena: &'a Bump, home: ModuleId, layout: InLayout<'a>) -> Self {
|
||||
Self {
|
||||
arena,
|
||||
home,
|
||||
layout,
|
||||
target_info,
|
||||
symbol_layouts: MutMap::default(),
|
||||
struct_children: MutMap::default(),
|
||||
union_children: MutMap::default(),
|
||||
box_children: MutMap::default(),
|
||||
list_children: MutMap::default(),
|
||||
incremented_symbols: MutMap::default(),
|
||||
incremented_symbols: CountingMap::new(),
|
||||
symbol_tag: MutMap::default(),
|
||||
symbol_index: MutMap::default(),
|
||||
list_length: MutMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn clone_without_incremented(&self) -> Self {
|
||||
Self {
|
||||
arena: self.arena,
|
||||
home: self.home,
|
||||
layout: self.layout,
|
||||
target_info: self.target_info,
|
||||
symbol_layouts: self.symbol_layouts.clone(),
|
||||
struct_children: self.struct_children.clone(),
|
||||
union_children: self.union_children.clone(),
|
||||
box_children: self.box_children.clone(),
|
||||
list_children: self.list_children.clone(),
|
||||
incremented_symbols: MutMap::default(),
|
||||
symbol_tag: self.symbol_tag.clone(),
|
||||
symbol_index: self.symbol_index.clone(),
|
||||
list_length: self.list_length.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
fn create_symbol<'i>(&self, ident_ids: &'i mut IdentIds, debug_name: &str) -> Symbol {
|
||||
let ident_id = ident_ids.add_str(debug_name);
|
||||
Symbol::new(self.home, ident_id)
|
||||
|
@ -1316,12 +1353,16 @@ impl<'a> DropSpecializationEnvironment<'a> {
|
|||
.push(child);
|
||||
}
|
||||
|
||||
fn add_list_child(&mut self, parent: Parent, child: Child, index: &Symbol) {
|
||||
fn add_list_child(&mut self, parent: Parent, child: Child, index: u64) {
|
||||
self.list_children
|
||||
.entry(parent)
|
||||
.or_insert_with(|| Vec::new_in(self.arena))
|
||||
.push((child, index));
|
||||
}
|
||||
|
||||
fn add_list_child_symbol(&mut self, parent: Parent, child: Child, index: &Symbol) {
|
||||
if let Some(index) = self.symbol_index.get(index) {
|
||||
self.list_children
|
||||
.entry(parent)
|
||||
.or_insert_with(|| Vec::new_in(self.arena))
|
||||
.push((child, *index));
|
||||
self.add_list_child(parent, child, *index)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1346,39 +1387,6 @@ impl<'a> DropSpecializationEnvironment<'a> {
|
|||
|
||||
res
|
||||
}
|
||||
|
||||
/**
|
||||
Add a symbol for every increment performed.
|
||||
*/
|
||||
fn add_incremented(&mut self, symbol: Symbol, count: u64) {
|
||||
self.incremented_symbols
|
||||
.entry(symbol)
|
||||
.and_modify(|c| *c += count)
|
||||
.or_insert(count);
|
||||
}
|
||||
|
||||
fn any_incremented(&self, symbol: &Symbol) -> bool {
|
||||
self.incremented_symbols.contains_key(symbol)
|
||||
}
|
||||
|
||||
/**
|
||||
Return the amount of times a symbol still has to be incremented.
|
||||
Accounting for later consumtion and removal of the increment.
|
||||
*/
|
||||
fn get_incremented(&mut self, symbol: &Symbol) -> u64 {
|
||||
self.incremented_symbols.remove(symbol).unwrap_or(0)
|
||||
}
|
||||
|
||||
fn pop_incremented(&mut self, symbol: &Symbol) -> bool {
|
||||
match self.incremented_symbols.get_mut(symbol) {
|
||||
Some(0) => false,
|
||||
Some(c) => {
|
||||
*c -= 1;
|
||||
true
|
||||
}
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1490,3 +1498,59 @@ fn low_level_no_rc(lowlevel: &LowLevel) -> RC {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Map that contains a count for each key.
|
||||
/// Keys with a count of 0 are kept around, so that it can be seen that they were once present.
|
||||
#[derive(Clone)]
|
||||
struct CountingMap<K> {
|
||||
map: MutMap<K, u64>,
|
||||
}
|
||||
|
||||
impl<K> CountingMap<K>
|
||||
where
|
||||
K: Eq + std::hash::Hash + Clone,
|
||||
{
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
map: MutMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn insert(&mut self, key: K) {
|
||||
self.insert_count(key, 1);
|
||||
}
|
||||
|
||||
fn insert_count(&mut self, key: K, count: u64) {
|
||||
self.map
|
||||
.entry(key)
|
||||
.and_modify(|c| *c += count)
|
||||
.or_insert(count);
|
||||
}
|
||||
|
||||
fn pop(&mut self, key: &K) -> bool {
|
||||
match self.map.get_mut(key) {
|
||||
Some(0) => false,
|
||||
Some(c) => {
|
||||
*c -= 1;
|
||||
true
|
||||
}
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn contains(&self, symbol: &K) -> bool {
|
||||
self.map.contains_key(symbol)
|
||||
}
|
||||
|
||||
fn drain(&mut self) -> Self {
|
||||
let res = self.clone();
|
||||
for (_, v) in self.map.iter_mut() {
|
||||
*v = 0;
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
fn clear(&mut self) {
|
||||
self.map.clear();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
procedure Test.0 ():
|
||||
let Test.2 : Str = "value";
|
||||
let Test.3 : {Str, Str} = Struct {Test.2, Test.2};
|
||||
dec Test.2;
|
||||
let Test.4 : Str = "result";
|
||||
ret Test.4;
|
|
@ -697,8 +697,8 @@ procedure Json.25 (Json.183):
|
|||
let Json.1906 : List U8 = CallByName List.8 Json.1907 Json.1908;
|
||||
ret Json.1906;
|
||||
else
|
||||
let Json.1948 : U64 = StructAtIndex 0 Json.186;
|
||||
inc Json.184;
|
||||
let Json.1948 : U64 = StructAtIndex 0 Json.186;
|
||||
let Json.1947 : {List U8, List U8} = CallByName List.52 Json.184 Json.1948;
|
||||
let Json.210 : List U8 = StructAtIndex 0 Json.1947;
|
||||
let Json.212 : List U8 = StructAtIndex 1 Json.1947;
|
||||
|
|
|
@ -623,8 +623,8 @@ procedure Json.25 (Json.183):
|
|||
let Json.1532 : List U8 = CallByName List.8 Json.1533 Json.1534;
|
||||
ret Json.1532;
|
||||
else
|
||||
let Json.1574 : U64 = StructAtIndex 0 Json.186;
|
||||
inc Json.184;
|
||||
let Json.1574 : U64 = StructAtIndex 0 Json.186;
|
||||
let Json.1573 : {List U8, List U8} = CallByName List.52 Json.184 Json.1574;
|
||||
let Json.210 : List U8 = StructAtIndex 0 Json.1573;
|
||||
let Json.212 : List U8 = StructAtIndex 1 Json.1573;
|
||||
|
|
|
@ -630,8 +630,8 @@ procedure Json.25 (Json.183):
|
|||
let Json.1532 : List U8 = CallByName List.8 Json.1533 Json.1534;
|
||||
ret Json.1532;
|
||||
else
|
||||
let Json.1574 : U64 = StructAtIndex 0 Json.186;
|
||||
inc Json.184;
|
||||
let Json.1574 : U64 = StructAtIndex 0 Json.186;
|
||||
let Json.1573 : {List U8, List U8} = CallByName List.52 Json.184 Json.1574;
|
||||
let Json.210 : List U8 = StructAtIndex 0 Json.1573;
|
||||
let Json.212 : List U8 = StructAtIndex 1 Json.1573;
|
||||
|
|
|
@ -118,8 +118,8 @@ procedure Json.25 (Json.183):
|
|||
let Json.1179 : List U8 = CallByName List.8 Json.1180 Json.1181;
|
||||
ret Json.1179;
|
||||
else
|
||||
let Json.1221 : U64 = StructAtIndex 0 Json.186;
|
||||
inc Json.184;
|
||||
let Json.1221 : U64 = StructAtIndex 0 Json.186;
|
||||
let Json.1220 : {List U8, List U8} = CallByName List.52 Json.184 Json.1221;
|
||||
let Json.210 : List U8 = StructAtIndex 0 Json.1220;
|
||||
let Json.212 : List U8 = StructAtIndex 1 Json.1220;
|
||||
|
|
|
@ -147,8 +147,8 @@ procedure Json.25 (Json.183):
|
|||
let Json.1220 : List U8 = CallByName List.8 Json.1221 Json.1222;
|
||||
ret Json.1220;
|
||||
else
|
||||
let Json.1262 : U64 = StructAtIndex 0 Json.186;
|
||||
inc Json.184;
|
||||
let Json.1262 : U64 = StructAtIndex 0 Json.186;
|
||||
let Json.1261 : {List U8, List U8} = CallByName List.52 Json.184 Json.1262;
|
||||
let Json.210 : List U8 = StructAtIndex 0 Json.1261;
|
||||
let Json.212 : List U8 = StructAtIndex 1 Json.1261;
|
||||
|
|
|
@ -150,8 +150,8 @@ procedure Json.25 (Json.183):
|
|||
let Json.1220 : List U8 = CallByName List.8 Json.1221 Json.1222;
|
||||
ret Json.1220;
|
||||
else
|
||||
let Json.1262 : U64 = StructAtIndex 0 Json.186;
|
||||
inc Json.184;
|
||||
let Json.1262 : U64 = StructAtIndex 0 Json.186;
|
||||
let Json.1261 : {List U8, List U8} = CallByName List.52 Json.184 Json.1262;
|
||||
let Json.210 : List U8 = StructAtIndex 0 Json.1261;
|
||||
let Json.212 : List U8 = StructAtIndex 1 Json.1261;
|
||||
|
|
|
@ -179,8 +179,8 @@ procedure Json.60 (Json.540):
|
|||
let Json.1336 : U8 = GetTagId Json.1327;
|
||||
let Json.1337 : Int1 = lowlevel Eq Json.1335 Json.1336;
|
||||
if Json.1337 then
|
||||
let Json.542 : U64 = UnionAtIndex (Id 2) (Index 0) Json.1327;
|
||||
inc Json.540;
|
||||
let Json.542 : U64 = UnionAtIndex (Id 2) (Index 0) Json.1327;
|
||||
let Json.1329 : List U8 = CallByName List.29 Json.540 Json.542;
|
||||
let Json.1332 : U64 = 0i64;
|
||||
let Json.1331 : {U64, U64} = Struct {Json.542, Json.1332};
|
||||
|
@ -532,18 +532,15 @@ procedure Json.68 ():
|
|||
procedure Json.69 (Json.1467):
|
||||
joinpoint Json.1197 Json.1165:
|
||||
let Json.599 : List U8 = StructAtIndex 0 Json.1165;
|
||||
inc Json.599;
|
||||
inc 4 Json.599;
|
||||
let Json.600 : List U8 = StructAtIndex 1 Json.1165;
|
||||
let Json.1315 : U64 = 0i64;
|
||||
let Json.601 : [C {}, C U8] = CallByName List.2 Json.599 Json.1315;
|
||||
let Json.1314 : U64 = 1i64;
|
||||
inc Json.599;
|
||||
let Json.602 : [C {}, C U8] = CallByName List.2 Json.599 Json.1314;
|
||||
let Json.1313 : U64 = 2i64;
|
||||
inc Json.599;
|
||||
let Json.603 : List U8 = CallByName List.29 Json.599 Json.1313;
|
||||
let Json.1312 : U64 = 6i64;
|
||||
inc Json.599;
|
||||
let Json.604 : List U8 = CallByName List.29 Json.599 Json.1312;
|
||||
let Json.1198 : {[C {}, C U8], [C {}, C U8]} = Struct {Json.601, Json.602};
|
||||
joinpoint Json.1277:
|
||||
|
@ -832,7 +829,7 @@ procedure Test.3 ():
|
|||
let Test.7 : Str = "Roc";
|
||||
let Test.6 : [C [C List U8, C ], C Str] = TagId(1) Test.7;
|
||||
let Test.5 : Int1 = CallByName Bool.11 Test.1 Test.6;
|
||||
dec Test.6;
|
||||
dec Test.7;
|
||||
expect Test.5;
|
||||
dec Test.0;
|
||||
dec Test.1;
|
||||
|
|
|
@ -153,8 +153,8 @@ procedure Json.60 (Json.540):
|
|||
let Json.1336 : U8 = GetTagId Json.1327;
|
||||
let Json.1337 : Int1 = lowlevel Eq Json.1335 Json.1336;
|
||||
if Json.1337 then
|
||||
let Json.542 : U64 = UnionAtIndex (Id 2) (Index 0) Json.1327;
|
||||
inc Json.540;
|
||||
let Json.542 : U64 = UnionAtIndex (Id 2) (Index 0) Json.1327;
|
||||
let Json.1329 : List U8 = CallByName List.29 Json.540 Json.542;
|
||||
let Json.1332 : U64 = 0i64;
|
||||
let Json.1331 : {U64, U64} = Struct {Json.542, Json.1332};
|
||||
|
@ -506,18 +506,15 @@ procedure Json.68 ():
|
|||
procedure Json.69 (Json.1467):
|
||||
joinpoint Json.1197 Json.1165:
|
||||
let Json.599 : List U8 = StructAtIndex 0 Json.1165;
|
||||
inc Json.599;
|
||||
inc 4 Json.599;
|
||||
let Json.600 : List U8 = StructAtIndex 1 Json.1165;
|
||||
let Json.1315 : U64 = 0i64;
|
||||
let Json.601 : [C {}, C U8] = CallByName List.2 Json.599 Json.1315;
|
||||
let Json.1314 : U64 = 1i64;
|
||||
inc Json.599;
|
||||
let Json.602 : [C {}, C U8] = CallByName List.2 Json.599 Json.1314;
|
||||
let Json.1313 : U64 = 2i64;
|
||||
inc Json.599;
|
||||
let Json.603 : List U8 = CallByName List.29 Json.599 Json.1313;
|
||||
let Json.1312 : U64 = 6i64;
|
||||
inc Json.599;
|
||||
let Json.604 : List U8 = CallByName List.29 Json.599 Json.1312;
|
||||
let Json.1198 : {[C {}, C U8], [C {}, C U8]} = Struct {Json.601, Json.602};
|
||||
joinpoint Json.1277:
|
||||
|
@ -865,7 +862,7 @@ procedure Test.12 ():
|
|||
let Test.16 : {List U8, I64} = Struct {Test.17, Test.18};
|
||||
let Test.15 : [C Str, C {List U8, I64}] = TagId(1) Test.16;
|
||||
let Test.14 : Int1 = CallByName Bool.11 Test.10 Test.15;
|
||||
dec Test.15;
|
||||
dec Test.16;
|
||||
expect Test.14;
|
||||
dec Test.10;
|
||||
let Test.13 : {} = Struct {};
|
||||
|
|
|
@ -5,7 +5,8 @@ procedure Test.0 ():
|
|||
let Test.9 : U64 = 1i64;
|
||||
let Test.10 : Int1 = lowlevel Eq Test.8 Test.9;
|
||||
if Test.10 then
|
||||
dec Test.1;
|
||||
dec Test.11;
|
||||
decref Test.1;
|
||||
let Test.3 : Str = "B";
|
||||
ret Test.3;
|
||||
else
|
||||
|
|
|
@ -5,11 +5,20 @@ procedure Test.0 ():
|
|||
let Test.2 : [<rnu><null>, C *self] = TagId(0) Test.13;
|
||||
let Test.10 : U8 = 1i64;
|
||||
let Test.11 : U8 = GetTagId Test.2;
|
||||
dec Test.2;
|
||||
let Test.12 : Int1 = lowlevel Eq Test.10 Test.11;
|
||||
if Test.12 then
|
||||
let Test.8 : I64 = 0i64;
|
||||
ret Test.8;
|
||||
joinpoint #Derived_gen.0:
|
||||
let Test.12 : Int1 = lowlevel Eq Test.10 Test.11;
|
||||
if Test.12 then
|
||||
let Test.8 : I64 = 0i64;
|
||||
ret Test.8;
|
||||
else
|
||||
let Test.9 : I64 = 1i64;
|
||||
ret Test.9;
|
||||
in
|
||||
let #Derived_gen.1 : Int1 = lowlevel RefCountIsUnique Test.2;
|
||||
if #Derived_gen.1 then
|
||||
dec Test.13;
|
||||
decref Test.2;
|
||||
jump #Derived_gen.0;
|
||||
else
|
||||
let Test.9 : I64 = 1i64;
|
||||
ret Test.9;
|
||||
decref Test.2;
|
||||
jump #Derived_gen.0;
|
||||
|
|
|
@ -30,6 +30,15 @@ procedure Test.0 ():
|
|||
let Test.16 : Str = "";
|
||||
let Test.15 : [<r>C List *self, C Str] = TagId(1) Test.16;
|
||||
let Test.13 : Int1 = CallByName Bool.11 Test.14 Test.15;
|
||||
dec Test.15;
|
||||
dec Test.14;
|
||||
ret Test.13;
|
||||
joinpoint #Derived_gen.0:
|
||||
dec Test.14;
|
||||
ret Test.13;
|
||||
in
|
||||
let #Derived_gen.1 : Int1 = lowlevel RefCountIsUnique Test.15;
|
||||
if #Derived_gen.1 then
|
||||
dec Test.16;
|
||||
decref Test.15;
|
||||
jump #Derived_gen.0;
|
||||
else
|
||||
decref Test.15;
|
||||
jump #Derived_gen.0;
|
||||
|
|
|
@ -45,10 +45,9 @@ procedure Num.22 (#Attr.2, #Attr.3):
|
|||
|
||||
procedure Test.1 (Test.2):
|
||||
let Test.28 : U64 = 0i64;
|
||||
inc Test.2;
|
||||
inc 2 Test.2;
|
||||
let Test.26 : [C {}, C I64] = CallByName List.2 Test.2 Test.28;
|
||||
let Test.27 : U64 = 0i64;
|
||||
inc Test.2;
|
||||
let Test.25 : [C {}, C I64] = CallByName List.2 Test.2 Test.27;
|
||||
let Test.8 : {[C {}, C I64], [C {}, C I64]} = Struct {Test.25, Test.26};
|
||||
joinpoint Test.22:
|
||||
|
|
|
@ -44,9 +44,8 @@ procedure Num.22 (#Attr.2, #Attr.3):
|
|||
ret Num.283;
|
||||
|
||||
procedure Test.1 (Test.2, Test.3, Test.4):
|
||||
inc Test.4;
|
||||
inc 2 Test.4;
|
||||
let Test.29 : [C {}, C I64] = CallByName List.2 Test.4 Test.3;
|
||||
inc Test.4;
|
||||
let Test.28 : [C {}, C I64] = CallByName List.2 Test.4 Test.2;
|
||||
let Test.13 : {[C {}, C I64], [C {}, C I64]} = Struct {Test.28, Test.29};
|
||||
joinpoint Test.25:
|
||||
|
|
|
@ -136,8 +136,8 @@ procedure Json.25 (Json.183):
|
|||
let Json.1223 : List U8 = CallByName List.8 Json.1224 Json.1225;
|
||||
ret Json.1223;
|
||||
else
|
||||
let Json.1265 : U64 = StructAtIndex 0 Json.186;
|
||||
inc Json.184;
|
||||
let Json.1265 : U64 = StructAtIndex 0 Json.186;
|
||||
let Json.1264 : {List U8, List U8} = CallByName List.52 Json.184 Json.1265;
|
||||
let Json.210 : List U8 = StructAtIndex 0 Json.1264;
|
||||
let Json.212 : List U8 = StructAtIndex 1 Json.1264;
|
||||
|
|
|
@ -3050,3 +3050,19 @@ fn specialize_after_match() {
|
|||
"#
|
||||
)
|
||||
}
|
||||
|
||||
#[mono_test]
|
||||
fn drop_specialize_after_struct() {
|
||||
indoc!(
|
||||
r#"
|
||||
app "test" provides [main] to "./platform"
|
||||
|
||||
Tuple a b : { left : a, right : b }
|
||||
|
||||
main =
|
||||
v = "value"
|
||||
t = { left: v, right: v }
|
||||
"result"
|
||||
"#
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue