mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 14:24:45 +00:00
Use StorageSubs for pending specializations
This commit is contained in:
parent
9126169fcb
commit
206c8889df
4 changed files with 385 additions and 374 deletions
|
@ -16,7 +16,7 @@ use roc_problem::can::RuntimeError;
|
||||||
use roc_region::all::{Located, Region};
|
use roc_region::all::{Located, Region};
|
||||||
use roc_std::RocDec;
|
use roc_std::RocDec;
|
||||||
use roc_types::solved_types::SolvedType;
|
use roc_types::solved_types::SolvedType;
|
||||||
use roc_types::subs::{Content, FlatType, Subs, Variable, VariableSubsSlice};
|
use roc_types::subs::{Content, FlatType, StorageSubs, Subs, Variable, VariableSubsSlice};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use ven_pretty::{BoxAllocator, DocAllocator, DocBuilder};
|
use ven_pretty::{BoxAllocator, DocAllocator, DocBuilder};
|
||||||
|
|
||||||
|
@ -437,7 +437,7 @@ impl<'a> ExternalSpecializations<'a> {
|
||||||
|
|
||||||
fn insert_external(&mut self, symbol: Symbol, env_subs: &mut Subs, variable: Variable) {
|
fn insert_external(&mut self, symbol: Symbol, env_subs: &mut Subs, variable: Variable) {
|
||||||
let variable =
|
let variable =
|
||||||
roc_solve::solve::deep_copy_var_to(env_subs, &mut self.storage_subs, variable);
|
roc_types::subs::deep_copy_var_to(env_subs, &mut self.storage_subs, variable);
|
||||||
|
|
||||||
match self.symbols.iter().position(|s| *s == symbol) {
|
match self.symbols.iter().position(|s| *s == symbol) {
|
||||||
None => {
|
None => {
|
||||||
|
@ -468,7 +468,7 @@ impl<'a> ExternalSpecializations<'a> {
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Suspended<'a> {
|
pub struct Suspended<'a> {
|
||||||
pub store: Subs,
|
pub store: StorageSubs,
|
||||||
pub symbols: Vec<'a, Symbol>,
|
pub symbols: Vec<'a, Symbol>,
|
||||||
pub layouts: Vec<'a, ProcLayout<'a>>,
|
pub layouts: Vec<'a, ProcLayout<'a>>,
|
||||||
pub variables: Vec<'a, Variable>,
|
pub variables: Vec<'a, Variable>,
|
||||||
|
@ -477,7 +477,7 @@ pub struct Suspended<'a> {
|
||||||
impl<'a> Suspended<'a> {
|
impl<'a> Suspended<'a> {
|
||||||
fn new_in(arena: &'a Bump) -> Self {
|
fn new_in(arena: &'a Bump) -> Self {
|
||||||
Self {
|
Self {
|
||||||
store: Subs::new_from_varstore(Default::default()),
|
store: StorageSubs::new(Subs::new_from_varstore(Default::default())),
|
||||||
symbols: Vec::new_in(arena),
|
symbols: Vec::new_in(arena),
|
||||||
layouts: Vec::new_in(arena),
|
layouts: Vec::new_in(arena),
|
||||||
variables: Vec::new_in(arena),
|
variables: Vec::new_in(arena),
|
||||||
|
@ -505,7 +505,7 @@ impl<'a> Suspended<'a> {
|
||||||
self.symbols.push(symbol);
|
self.symbols.push(symbol);
|
||||||
self.layouts.push(proc_layout);
|
self.layouts.push(proc_layout);
|
||||||
|
|
||||||
let variable = roc_solve::solve::deep_copy_var_to(subs, &mut self.store, variable);
|
let variable = self.store.extend_with_variable(subs, variable);
|
||||||
|
|
||||||
self.variables.push(variable);
|
self.variables.push(variable);
|
||||||
}
|
}
|
||||||
|
@ -1908,20 +1908,20 @@ pub fn specialize_all<'a>(
|
||||||
|
|
||||||
match pending_specializations {
|
match pending_specializations {
|
||||||
PendingSpecializations::Making => {}
|
PendingSpecializations::Making => {}
|
||||||
PendingSpecializations::Finding(mut suspended) => {
|
PendingSpecializations::Finding(suspended) => {
|
||||||
// TODO can we copy everything over in one pass (bumping variables by however many
|
let offset_variable = StorageSubs::merge_into(suspended.store, env.subs);
|
||||||
// variables are in the env's subs?
|
|
||||||
for var in suspended.variables.iter_mut() {
|
|
||||||
debug_assert!((var.index() as usize) < suspended.store.len());
|
|
||||||
|
|
||||||
*var = roc_solve::solve::deep_copy_var_to(&mut suspended.store, env.subs, *var);
|
for (i, (symbol, var)) in suspended
|
||||||
}
|
.symbols
|
||||||
|
.iter()
|
||||||
for (i, symbol) in suspended.symbols.iter().enumerate() {
|
.zip(suspended.variables.iter())
|
||||||
|
.enumerate()
|
||||||
|
{
|
||||||
let name = *symbol;
|
let name = *symbol;
|
||||||
let var = suspended.variables[i];
|
|
||||||
let outside_layout = suspended.layouts[i];
|
let outside_layout = suspended.layouts[i];
|
||||||
|
|
||||||
|
let var = offset_variable(*var);
|
||||||
|
|
||||||
// TODO define our own Entry for Specialized?
|
// TODO define our own Entry for Specialized?
|
||||||
let partial_proc = if procs.specialized.is_specialized(name, &outside_layout) {
|
let partial_proc = if procs.specialized.is_specialized(name, &outside_layout) {
|
||||||
// already specialized, just continue
|
// already specialized, just continue
|
||||||
|
@ -2069,7 +2069,7 @@ fn specialize_externals_others_need<'a>(
|
||||||
};
|
};
|
||||||
|
|
||||||
let variable =
|
let variable =
|
||||||
roc_solve::solve::deep_copy_var_to(&mut store, env.subs, store_variable);
|
roc_types::subs::deep_copy_var_to(&mut store, env.subs, store_variable);
|
||||||
|
|
||||||
// TODO I believe this is also duplicated
|
// TODO I believe this is also duplicated
|
||||||
match specialize_variable(
|
match specialize_variable(
|
||||||
|
|
|
@ -1383,346 +1383,6 @@ fn instantiate_rigids_help(
|
||||||
var
|
var
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deep_copy_var_to(
|
|
||||||
source: &mut Subs, // mut to set the copy
|
|
||||||
target: &mut Subs,
|
|
||||||
var: Variable,
|
|
||||||
) -> Variable {
|
|
||||||
let mut pools = Pools::default();
|
|
||||||
let rank = Rank::toplevel();
|
|
||||||
|
|
||||||
let mut mapping = Vec::with_capacity(100);
|
|
||||||
|
|
||||||
let copy = deep_copy_var_to_help(source, target, rank, &mut pools, &mut mapping, var);
|
|
||||||
|
|
||||||
source.restore(var);
|
|
||||||
|
|
||||||
copy
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deep_copy_var_to_help(
|
|
||||||
// source: &mut Subs, // mut to set the copy
|
|
||||||
source: &mut Subs,
|
|
||||||
target: &mut Subs,
|
|
||||||
max_rank: Rank,
|
|
||||||
pools: &mut Pools,
|
|
||||||
mapping: &mut Vec<OptVariable>, // maps copies in the source to copies in the target
|
|
||||||
var: Variable,
|
|
||||||
) -> Variable {
|
|
||||||
use roc_types::subs::Content::*;
|
|
||||||
use roc_types::subs::FlatType::*;
|
|
||||||
|
|
||||||
let desc = source.get_without_compacting(var);
|
|
||||||
|
|
||||||
if let Some(copy) = desc.copy.into_variable() {
|
|
||||||
debug_assert!(target.contains(copy));
|
|
||||||
return copy;
|
|
||||||
} else if desc.rank != Rank::NONE {
|
|
||||||
// DO NOTHING
|
|
||||||
//
|
|
||||||
// The original deep_copy_var can do
|
|
||||||
// return var;
|
|
||||||
//
|
|
||||||
// but we cannot, because this `var` is in the source, not the target, and we
|
|
||||||
// should only return variables in the target
|
|
||||||
}
|
|
||||||
|
|
||||||
let make_descriptor = |content| Descriptor {
|
|
||||||
content,
|
|
||||||
rank: max_rank,
|
|
||||||
mark: Mark::NONE,
|
|
||||||
copy: OptVariable::NONE,
|
|
||||||
};
|
|
||||||
|
|
||||||
let content = desc.content;
|
|
||||||
// let copy = target.fresh(make_descriptor(content.clone()));
|
|
||||||
let copy = target.fresh_unnamed_flex_var();
|
|
||||||
|
|
||||||
// pools.get_mut(max_rank).push(copy);
|
|
||||||
|
|
||||||
// Link the original variable to the new variable. This lets us
|
|
||||||
// avoid making multiple copies of the variable we are instantiating.
|
|
||||||
//
|
|
||||||
// Need to do this before recursively copying to avoid looping.
|
|
||||||
|
|
||||||
source.set(
|
|
||||||
var,
|
|
||||||
Descriptor {
|
|
||||||
content: content.clone(),
|
|
||||||
rank: desc.rank,
|
|
||||||
mark: Mark::NONE,
|
|
||||||
copy: copy.into(),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
// Now we recursively copy the content of the variable.
|
|
||||||
// We have already marked the variable as copied, so we
|
|
||||||
// will not repeat this work or crawl this variable again.
|
|
||||||
match content {
|
|
||||||
Structure(flat_type) => {
|
|
||||||
let new_flat_type = match flat_type {
|
|
||||||
Apply(symbol, args) => {
|
|
||||||
let mut new_arg_vars = Vec::with_capacity(args.len());
|
|
||||||
|
|
||||||
for index in args.into_iter() {
|
|
||||||
let var = source[index];
|
|
||||||
let copy_var =
|
|
||||||
deep_copy_var_to_help(source, target, max_rank, pools, mapping, var);
|
|
||||||
new_arg_vars.push(copy_var);
|
|
||||||
}
|
|
||||||
|
|
||||||
let arg_vars = VariableSubsSlice::insert_into_subs(target, new_arg_vars);
|
|
||||||
|
|
||||||
Apply(symbol, arg_vars)
|
|
||||||
}
|
|
||||||
|
|
||||||
Func(arg_vars, closure_var, ret_var) => {
|
|
||||||
let new_ret_var =
|
|
||||||
deep_copy_var_to_help(source, target, max_rank, pools, mapping, ret_var);
|
|
||||||
|
|
||||||
let new_closure_var = deep_copy_var_to_help(
|
|
||||||
source,
|
|
||||||
target,
|
|
||||||
max_rank,
|
|
||||||
pools,
|
|
||||||
mapping,
|
|
||||||
closure_var,
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut new_arg_vars = Vec::with_capacity(arg_vars.len());
|
|
||||||
|
|
||||||
for index in arg_vars.into_iter() {
|
|
||||||
let var = source[index];
|
|
||||||
let copy_var =
|
|
||||||
deep_copy_var_to_help(source, target, max_rank, pools, mapping, var);
|
|
||||||
new_arg_vars.push(copy_var);
|
|
||||||
}
|
|
||||||
|
|
||||||
let arg_vars = VariableSubsSlice::insert_into_subs(target, new_arg_vars);
|
|
||||||
|
|
||||||
Func(arg_vars, new_closure_var, new_ret_var)
|
|
||||||
}
|
|
||||||
|
|
||||||
same @ EmptyRecord | same @ EmptyTagUnion | same @ Erroneous(_) => same,
|
|
||||||
|
|
||||||
Record(fields, ext_var) => {
|
|
||||||
let record_fields = {
|
|
||||||
let mut new_vars = Vec::with_capacity(fields.len());
|
|
||||||
|
|
||||||
for index in fields.iter_variables() {
|
|
||||||
let var = source[index];
|
|
||||||
let copy_var = deep_copy_var_to_help(
|
|
||||||
source, target, max_rank, pools, mapping, var,
|
|
||||||
);
|
|
||||||
|
|
||||||
new_vars.push(copy_var);
|
|
||||||
}
|
|
||||||
|
|
||||||
let field_names_start = target.field_names.len() as u32;
|
|
||||||
let variables_start = target.variables.len() as u32;
|
|
||||||
let field_types_start = target.record_fields.len() as u32;
|
|
||||||
|
|
||||||
let mut length = 0;
|
|
||||||
|
|
||||||
for ((i1, _, i3), var) in fields.iter_all().zip(new_vars) {
|
|
||||||
let record_field = source[i3].map(|_| var);
|
|
||||||
|
|
||||||
target.field_names.push(source[i1].clone());
|
|
||||||
target.record_fields.push(record_field.map(|_| ()));
|
|
||||||
target.variables.push(*record_field.as_inner());
|
|
||||||
|
|
||||||
length += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
RecordFields {
|
|
||||||
length,
|
|
||||||
field_names_start,
|
|
||||||
variables_start,
|
|
||||||
field_types_start,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Record(
|
|
||||||
record_fields,
|
|
||||||
deep_copy_var_to_help(source, target, max_rank, pools, mapping, ext_var),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
TagUnion(tags, ext_var) => {
|
|
||||||
let new_ext =
|
|
||||||
deep_copy_var_to_help(source, target, max_rank, pools, mapping, ext_var);
|
|
||||||
|
|
||||||
let mut new_variable_slices = Vec::with_capacity(tags.len());
|
|
||||||
|
|
||||||
let mut new_variables = Vec::new();
|
|
||||||
for index in tags.variables() {
|
|
||||||
let slice = source[index];
|
|
||||||
for var_index in slice {
|
|
||||||
let var = source[var_index];
|
|
||||||
let new_var = deep_copy_var_to_help(
|
|
||||||
source, target, max_rank, pools, mapping, var,
|
|
||||||
);
|
|
||||||
new_variables.push(new_var);
|
|
||||||
}
|
|
||||||
|
|
||||||
let new_slice =
|
|
||||||
VariableSubsSlice::insert_into_subs(target, new_variables.drain(..));
|
|
||||||
|
|
||||||
new_variable_slices.push(new_slice);
|
|
||||||
}
|
|
||||||
|
|
||||||
let new_variables = {
|
|
||||||
let start = target.variable_slices.len() as u32;
|
|
||||||
let length = new_variable_slices.len() as u16;
|
|
||||||
target.variable_slices.extend(new_variable_slices);
|
|
||||||
|
|
||||||
SubsSlice::new(start, length)
|
|
||||||
};
|
|
||||||
|
|
||||||
let new_tag_names = {
|
|
||||||
let tag_names = tags.tag_names();
|
|
||||||
let slice = &source.tag_names[tag_names.start as usize..]
|
|
||||||
[..tag_names.length as usize];
|
|
||||||
|
|
||||||
let start = target.tag_names.len() as u32;
|
|
||||||
let length = tag_names.len() as u16;
|
|
||||||
|
|
||||||
target.tag_names.extend(slice.iter().cloned());
|
|
||||||
|
|
||||||
SubsSlice::new(start, length)
|
|
||||||
};
|
|
||||||
|
|
||||||
let union_tags = UnionTags::from_slices(new_tag_names, new_variables);
|
|
||||||
|
|
||||||
TagUnion(union_tags, new_ext)
|
|
||||||
}
|
|
||||||
|
|
||||||
FunctionOrTagUnion(tag_name, symbol, ext_var) => {
|
|
||||||
let new_tag_name = SubsIndex::new(target.tag_names.len() as u32);
|
|
||||||
|
|
||||||
target.tag_names.push(source[tag_name].clone());
|
|
||||||
|
|
||||||
FunctionOrTagUnion(
|
|
||||||
new_tag_name,
|
|
||||||
symbol,
|
|
||||||
deep_copy_var_to_help(source, target, max_rank, pools, mapping, ext_var),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
RecursiveTagUnion(rec_var, tags, ext_var) => {
|
|
||||||
let mut new_variable_slices = Vec::with_capacity(tags.len());
|
|
||||||
|
|
||||||
let mut new_variables = Vec::new();
|
|
||||||
for index in tags.variables() {
|
|
||||||
let slice = source[index];
|
|
||||||
for var_index in slice {
|
|
||||||
let var = source[var_index];
|
|
||||||
let new_var = deep_copy_var_to_help(
|
|
||||||
source, target, max_rank, pools, mapping, var,
|
|
||||||
);
|
|
||||||
new_variables.push(new_var);
|
|
||||||
}
|
|
||||||
|
|
||||||
let new_slice =
|
|
||||||
VariableSubsSlice::insert_into_subs(target, new_variables.drain(..));
|
|
||||||
|
|
||||||
new_variable_slices.push(new_slice);
|
|
||||||
}
|
|
||||||
|
|
||||||
let new_variables = {
|
|
||||||
let start = target.variable_slices.len() as u32;
|
|
||||||
let length = new_variable_slices.len() as u16;
|
|
||||||
target.variable_slices.extend(new_variable_slices);
|
|
||||||
|
|
||||||
SubsSlice::new(start, length)
|
|
||||||
};
|
|
||||||
|
|
||||||
let new_tag_names = {
|
|
||||||
let tag_names = tags.tag_names();
|
|
||||||
let slice = &source.tag_names[tag_names.start as usize..]
|
|
||||||
[..tag_names.length as usize];
|
|
||||||
|
|
||||||
let start = target.tag_names.len() as u32;
|
|
||||||
let length = tag_names.len() as u16;
|
|
||||||
|
|
||||||
target.tag_names.extend(slice.iter().cloned());
|
|
||||||
|
|
||||||
SubsSlice::new(start, length)
|
|
||||||
};
|
|
||||||
|
|
||||||
let union_tags = UnionTags::from_slices(new_tag_names, new_variables);
|
|
||||||
|
|
||||||
let new_ext =
|
|
||||||
deep_copy_var_to_help(source, target, max_rank, pools, mapping, ext_var);
|
|
||||||
let new_rec_var =
|
|
||||||
deep_copy_var_to_help(source, target, max_rank, pools, mapping, rec_var);
|
|
||||||
|
|
||||||
RecursiveTagUnion(new_rec_var, union_tags, new_ext)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
target.set(copy, make_descriptor(Structure(new_flat_type)));
|
|
||||||
|
|
||||||
copy
|
|
||||||
}
|
|
||||||
|
|
||||||
FlexVar(_) | Error => copy,
|
|
||||||
|
|
||||||
RecursionVar {
|
|
||||||
opt_name,
|
|
||||||
structure,
|
|
||||||
} => {
|
|
||||||
let new_structure =
|
|
||||||
deep_copy_var_to_help(source, target, max_rank, pools, mapping, structure);
|
|
||||||
|
|
||||||
debug_assert!((new_structure.index() as usize) < target.len());
|
|
||||||
|
|
||||||
target.set(
|
|
||||||
copy,
|
|
||||||
make_descriptor(RecursionVar {
|
|
||||||
opt_name,
|
|
||||||
structure: new_structure,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
copy
|
|
||||||
}
|
|
||||||
|
|
||||||
RigidVar(name) => {
|
|
||||||
target.set(copy, make_descriptor(FlexVar(Some(name))));
|
|
||||||
|
|
||||||
copy
|
|
||||||
}
|
|
||||||
|
|
||||||
Alias(symbol, mut args, real_type_var) => {
|
|
||||||
let mut new_vars = Vec::with_capacity(args.variables().len());
|
|
||||||
|
|
||||||
for var_index in args.variables() {
|
|
||||||
let var = source[var_index];
|
|
||||||
let new_var = deep_copy_var_to_help(source, target, max_rank, pools, mapping, var);
|
|
||||||
|
|
||||||
new_vars.push(new_var);
|
|
||||||
}
|
|
||||||
|
|
||||||
args.replace_variables(target, new_vars);
|
|
||||||
|
|
||||||
let lowercases = &source.field_names[args.lowercases_start as usize..]
|
|
||||||
[..args.lowercases_len as usize];
|
|
||||||
|
|
||||||
args.lowercases_start = target.field_names.len() as u32;
|
|
||||||
target.field_names.extend(lowercases.iter().cloned());
|
|
||||||
|
|
||||||
let new_real_type_var =
|
|
||||||
deep_copy_var_to_help(source, target, max_rank, pools, mapping, real_type_var);
|
|
||||||
let new_content = Alias(symbol, args, new_real_type_var);
|
|
||||||
|
|
||||||
target.set(copy, make_descriptor(new_content));
|
|
||||||
|
|
||||||
copy
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deep_copy_var(subs: &mut Subs, rank: Rank, pools: &mut Pools, var: Variable) -> Variable {
|
fn deep_copy_var(subs: &mut Subs, rank: Rank, pools: &mut Pools, var: Variable) -> Variable {
|
||||||
let copy = deep_copy_var_help(subs, rank, pools, var);
|
let copy = deep_copy_var_help(subs, rank, pools, var);
|
||||||
|
|
||||||
|
|
|
@ -1051,6 +1051,7 @@ impl Subs {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn extend_by(&mut self, entries: usize) {
|
pub fn extend_by(&mut self, entries: usize) {
|
||||||
|
self.utable.reserve(entries);
|
||||||
for _ in 0..entries {
|
for _ in 0..entries {
|
||||||
self.utable.new_key(flex_var_descriptor());
|
self.utable.new_key(flex_var_descriptor());
|
||||||
}
|
}
|
||||||
|
@ -2801,11 +2802,12 @@ fn restore_help(subs: &mut Subs, initial: Variable) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct StorageSubs {
|
pub struct StorageSubs {
|
||||||
subs: Subs,
|
subs: Subs,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
struct StorageSubsOffsets {
|
struct StorageSubsOffsets {
|
||||||
utable: u32,
|
utable: u32,
|
||||||
variables: u32,
|
variables: u32,
|
||||||
|
@ -2816,7 +2818,24 @@ struct StorageSubsOffsets {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StorageSubs {
|
impl StorageSubs {
|
||||||
pub fn merge_into(self, target: &mut Subs) {
|
pub fn new(subs: Subs) -> Self {
|
||||||
|
Self { subs }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn extend_with_variable(&mut self, source: &mut Subs, variable: Variable) -> Variable {
|
||||||
|
deep_copy_var_to(source, &mut self.subs, variable)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn merge_into(self, target: &mut Subs) -> impl Fn(Variable) -> Variable {
|
||||||
|
let self_offsets = StorageSubsOffsets {
|
||||||
|
utable: self.subs.utable.len() as u32,
|
||||||
|
variables: self.subs.variables.len() as u32,
|
||||||
|
tag_names: self.subs.tag_names.len() as u32,
|
||||||
|
field_names: self.subs.field_names.len() as u32,
|
||||||
|
record_fields: self.subs.record_fields.len() as u32,
|
||||||
|
variable_slices: self.subs.variable_slices.len() as u32,
|
||||||
|
};
|
||||||
|
|
||||||
let offsets = StorageSubsOffsets {
|
let offsets = StorageSubsOffsets {
|
||||||
utable: target.utable.len() as u32,
|
utable: target.utable.len() as u32,
|
||||||
variables: target.variables.len() as u32,
|
variables: target.variables.len() as u32,
|
||||||
|
@ -2826,33 +2845,36 @@ impl StorageSubs {
|
||||||
variable_slices: target.variable_slices.len() as u32,
|
variable_slices: target.variable_slices.len() as u32,
|
||||||
};
|
};
|
||||||
|
|
||||||
let range = Variable::NUM_RESERVED_VARS..self.subs.utable.len();
|
let range = 0..self.subs.utable.len();
|
||||||
|
|
||||||
target.utable.reserve(range.len());
|
// fill new slots with empty values
|
||||||
|
target.extend_by(range.len());
|
||||||
|
|
||||||
for i in range {
|
for i in range {
|
||||||
let descriptor = self.subs.get_ref(Variable(i as u32));
|
let variable = Variable(i as u32);
|
||||||
|
let descriptor = self.subs.get_ref(variable);
|
||||||
debug_assert!(descriptor.copy.is_none());
|
debug_assert!(descriptor.copy.is_none());
|
||||||
|
|
||||||
let new_content = Self::offset_content(&offsets, &descriptor.content);
|
let new_content = Self::offset_content(&offsets, &descriptor.content);
|
||||||
|
|
||||||
let new_variable = Variable(i as u32 + offsets.utable);
|
|
||||||
|
|
||||||
let new_descriptor = Descriptor {
|
let new_descriptor = Descriptor {
|
||||||
rank: descriptor.rank,
|
rank: descriptor.rank,
|
||||||
mark: descriptor.mark,
|
mark: descriptor.mark,
|
||||||
|
// rank: Rank::NONE,
|
||||||
|
// mark: Mark::NONE,
|
||||||
copy: OptVariable::NONE,
|
copy: OptVariable::NONE,
|
||||||
content: new_content,
|
content: new_content,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let new_variable = Self::offset_variable(&offsets, variable);
|
||||||
target.set(new_variable, new_descriptor);
|
target.set(new_variable, new_descriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
target.variables.extend(
|
target.variables.extend(
|
||||||
self.subs
|
self.subs
|
||||||
.variables
|
.variables
|
||||||
.into_iter()
|
.iter()
|
||||||
.map(|v| Self::offset_variable(&offsets, v)),
|
.map(|v| Self::offset_variable(&offsets, *v)),
|
||||||
);
|
);
|
||||||
|
|
||||||
target.variable_slices.extend(
|
target.variable_slices.extend(
|
||||||
|
@ -2865,6 +2887,21 @@ impl StorageSubs {
|
||||||
target.tag_names.extend(self.subs.tag_names);
|
target.tag_names.extend(self.subs.tag_names);
|
||||||
target.field_names.extend(self.subs.field_names);
|
target.field_names.extend(self.subs.field_names);
|
||||||
target.record_fields.extend(self.subs.record_fields);
|
target.record_fields.extend(self.subs.record_fields);
|
||||||
|
|
||||||
|
debug_assert_eq!(
|
||||||
|
target.utable.len(),
|
||||||
|
(self_offsets.utable + offsets.utable) as usize
|
||||||
|
);
|
||||||
|
|
||||||
|
debug_assert_eq!(
|
||||||
|
target.tag_names.len(),
|
||||||
|
(self_offsets.tag_names + offsets.tag_names) as usize
|
||||||
|
);
|
||||||
|
|
||||||
|
move |v| {
|
||||||
|
let offsets = offsets;
|
||||||
|
Self::offset_variable(&offsets, v)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fn offset_flat_type(offsets: &StorageSubsOffsets, flat_type: &FlatType) -> FlatType {
|
fn offset_flat_type(offsets: &StorageSubsOffsets, flat_type: &FlatType) -> FlatType {
|
||||||
match flat_type {
|
match flat_type {
|
||||||
|
@ -2935,7 +2972,7 @@ impl StorageSubs {
|
||||||
|
|
||||||
fn offset_union_tags(offsets: &StorageSubsOffsets, mut union_tags: UnionTags) -> UnionTags {
|
fn offset_union_tags(offsets: &StorageSubsOffsets, mut union_tags: UnionTags) -> UnionTags {
|
||||||
union_tags.tag_names_start += offsets.tag_names;
|
union_tags.tag_names_start += offsets.tag_names;
|
||||||
union_tags.variables_start += offsets.variables;
|
union_tags.variables_start += offsets.variable_slices;
|
||||||
|
|
||||||
union_tags
|
union_tags
|
||||||
}
|
}
|
||||||
|
@ -2961,19 +2998,331 @@ impl StorageSubs {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn offset_variable(offsets: &StorageSubsOffsets, variable: Variable) -> Variable {
|
fn offset_variable(offsets: &StorageSubsOffsets, variable: Variable) -> Variable {
|
||||||
if variable.index() < Variable::FIRST_USER_SPACE_VAR.index() {
|
let new_index = variable.0 + offsets.utable;
|
||||||
variable
|
Variable(new_index)
|
||||||
} else {
|
|
||||||
Variable(variable.0 + offsets.variables)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn offset_variable_slice(
|
fn offset_variable_slice(
|
||||||
offsets: &StorageSubsOffsets,
|
offsets: &StorageSubsOffsets,
|
||||||
mut slice: VariableSubsSlice,
|
mut slice: VariableSubsSlice,
|
||||||
) -> VariableSubsSlice {
|
) -> VariableSubsSlice {
|
||||||
slice.slice.start += offsets.variable_slices;
|
slice.slice.start += offsets.variables;
|
||||||
|
|
||||||
slice
|
slice
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn deep_copy_var_to(
|
||||||
|
source: &mut Subs, // mut to set the copy
|
||||||
|
target: &mut Subs,
|
||||||
|
var: Variable,
|
||||||
|
) -> Variable {
|
||||||
|
let rank = Rank::toplevel();
|
||||||
|
|
||||||
|
let copy = deep_copy_var_to_help(source, target, rank, var);
|
||||||
|
|
||||||
|
source.restore(var);
|
||||||
|
|
||||||
|
copy
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deep_copy_var_to_help(
|
||||||
|
// source: &mut Subs, // mut to set the copy
|
||||||
|
source: &mut Subs,
|
||||||
|
target: &mut Subs,
|
||||||
|
max_rank: Rank,
|
||||||
|
var: Variable,
|
||||||
|
) -> Variable {
|
||||||
|
use Content::*;
|
||||||
|
use FlatType::*;
|
||||||
|
|
||||||
|
let desc = source.get_without_compacting(var);
|
||||||
|
|
||||||
|
if let Some(copy) = desc.copy.into_variable() {
|
||||||
|
debug_assert!(target.contains(copy));
|
||||||
|
return copy;
|
||||||
|
} else if desc.rank != Rank::NONE {
|
||||||
|
// DO NOTHING
|
||||||
|
//
|
||||||
|
// The original deep_copy_var can do
|
||||||
|
// return var;
|
||||||
|
//
|
||||||
|
// but we cannot, because this `var` is in the source, not the target, and we
|
||||||
|
// should only return variables in the target
|
||||||
|
}
|
||||||
|
|
||||||
|
let make_descriptor = |content| Descriptor {
|
||||||
|
content,
|
||||||
|
rank: max_rank,
|
||||||
|
mark: Mark::NONE,
|
||||||
|
copy: OptVariable::NONE,
|
||||||
|
};
|
||||||
|
|
||||||
|
let content = desc.content;
|
||||||
|
// let copy = target.fresh(make_descriptor(content.clone()));
|
||||||
|
let copy = target.fresh_unnamed_flex_var();
|
||||||
|
|
||||||
|
// pools.get_mut(max_rank).push(copy);
|
||||||
|
|
||||||
|
// Link the original variable to the new variable. This lets us
|
||||||
|
// avoid making multiple copies of the variable we are instantiating.
|
||||||
|
//
|
||||||
|
// Need to do this before recursively copying to avoid looping.
|
||||||
|
|
||||||
|
source.set(
|
||||||
|
var,
|
||||||
|
Descriptor {
|
||||||
|
content: content.clone(),
|
||||||
|
rank: desc.rank,
|
||||||
|
mark: Mark::NONE,
|
||||||
|
copy: copy.into(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// Now we recursively copy the content of the variable.
|
||||||
|
// We have already marked the variable as copied, so we
|
||||||
|
// will not repeat this work or crawl this variable again.
|
||||||
|
match content {
|
||||||
|
Structure(flat_type) => {
|
||||||
|
let new_flat_type = match flat_type {
|
||||||
|
Apply(symbol, args) => {
|
||||||
|
let mut new_arg_vars = Vec::with_capacity(args.len());
|
||||||
|
|
||||||
|
for index in args.into_iter() {
|
||||||
|
let var = source[index];
|
||||||
|
let copy_var = deep_copy_var_to_help(source, target, max_rank, var);
|
||||||
|
new_arg_vars.push(copy_var);
|
||||||
|
}
|
||||||
|
|
||||||
|
let arg_vars = VariableSubsSlice::insert_into_subs(target, new_arg_vars);
|
||||||
|
|
||||||
|
Apply(symbol, arg_vars)
|
||||||
|
}
|
||||||
|
|
||||||
|
Func(arg_vars, closure_var, ret_var) => {
|
||||||
|
let new_ret_var = deep_copy_var_to_help(source, target, max_rank, ret_var);
|
||||||
|
|
||||||
|
let new_closure_var =
|
||||||
|
deep_copy_var_to_help(source, target, max_rank, closure_var);
|
||||||
|
|
||||||
|
let mut new_arg_vars = Vec::with_capacity(arg_vars.len());
|
||||||
|
|
||||||
|
for index in arg_vars.into_iter() {
|
||||||
|
let var = source[index];
|
||||||
|
let copy_var = deep_copy_var_to_help(source, target, max_rank, var);
|
||||||
|
new_arg_vars.push(copy_var);
|
||||||
|
}
|
||||||
|
|
||||||
|
let arg_vars = VariableSubsSlice::insert_into_subs(target, new_arg_vars);
|
||||||
|
|
||||||
|
Func(arg_vars, new_closure_var, new_ret_var)
|
||||||
|
}
|
||||||
|
|
||||||
|
same @ EmptyRecord | same @ EmptyTagUnion | same @ Erroneous(_) => same,
|
||||||
|
|
||||||
|
Record(fields, ext_var) => {
|
||||||
|
let record_fields = {
|
||||||
|
let mut new_vars = Vec::with_capacity(fields.len());
|
||||||
|
|
||||||
|
for index in fields.iter_variables() {
|
||||||
|
let var = source[index];
|
||||||
|
let copy_var = deep_copy_var_to_help(source, target, max_rank, var);
|
||||||
|
|
||||||
|
new_vars.push(copy_var);
|
||||||
|
}
|
||||||
|
|
||||||
|
let field_names_start = target.field_names.len() as u32;
|
||||||
|
let variables_start = target.variables.len() as u32;
|
||||||
|
let field_types_start = target.record_fields.len() as u32;
|
||||||
|
|
||||||
|
let mut length = 0;
|
||||||
|
|
||||||
|
for ((i1, _, i3), var) in fields.iter_all().zip(new_vars) {
|
||||||
|
let record_field = source[i3].map(|_| var);
|
||||||
|
|
||||||
|
target.field_names.push(source[i1].clone());
|
||||||
|
target.record_fields.push(record_field.map(|_| ()));
|
||||||
|
target.variables.push(*record_field.as_inner());
|
||||||
|
|
||||||
|
length += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
RecordFields {
|
||||||
|
length,
|
||||||
|
field_names_start,
|
||||||
|
variables_start,
|
||||||
|
field_types_start,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Record(
|
||||||
|
record_fields,
|
||||||
|
deep_copy_var_to_help(source, target, max_rank, ext_var),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
TagUnion(tags, ext_var) => {
|
||||||
|
let new_ext = deep_copy_var_to_help(source, target, max_rank, ext_var);
|
||||||
|
|
||||||
|
let mut new_variable_slices = Vec::with_capacity(tags.len());
|
||||||
|
|
||||||
|
let mut new_variables = Vec::new();
|
||||||
|
for index in tags.variables() {
|
||||||
|
let slice = source[index];
|
||||||
|
for var_index in slice {
|
||||||
|
let var = source[var_index];
|
||||||
|
let new_var = deep_copy_var_to_help(source, target, max_rank, var);
|
||||||
|
new_variables.push(new_var);
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_slice =
|
||||||
|
VariableSubsSlice::insert_into_subs(target, new_variables.drain(..));
|
||||||
|
|
||||||
|
new_variable_slices.push(new_slice);
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_variables = {
|
||||||
|
let start = target.variable_slices.len() as u32;
|
||||||
|
let length = new_variable_slices.len() as u16;
|
||||||
|
target.variable_slices.extend(new_variable_slices);
|
||||||
|
|
||||||
|
SubsSlice::new(start, length)
|
||||||
|
};
|
||||||
|
|
||||||
|
let new_tag_names = {
|
||||||
|
let tag_names = tags.tag_names();
|
||||||
|
let slice = &source.tag_names[tag_names.start as usize..]
|
||||||
|
[..tag_names.length as usize];
|
||||||
|
|
||||||
|
let start = target.tag_names.len() as u32;
|
||||||
|
let length = tag_names.len() as u16;
|
||||||
|
|
||||||
|
target.tag_names.extend(slice.iter().cloned());
|
||||||
|
|
||||||
|
SubsSlice::new(start, length)
|
||||||
|
};
|
||||||
|
|
||||||
|
let union_tags = UnionTags::from_slices(new_tag_names, new_variables);
|
||||||
|
|
||||||
|
TagUnion(union_tags, new_ext)
|
||||||
|
}
|
||||||
|
|
||||||
|
FunctionOrTagUnion(tag_name, symbol, ext_var) => {
|
||||||
|
let new_tag_name = SubsIndex::new(target.tag_names.len() as u32);
|
||||||
|
|
||||||
|
target.tag_names.push(source[tag_name].clone());
|
||||||
|
|
||||||
|
FunctionOrTagUnion(
|
||||||
|
new_tag_name,
|
||||||
|
symbol,
|
||||||
|
deep_copy_var_to_help(source, target, max_rank, ext_var),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
RecursiveTagUnion(rec_var, tags, ext_var) => {
|
||||||
|
let mut new_variable_slices = Vec::with_capacity(tags.len());
|
||||||
|
|
||||||
|
let mut new_variables = Vec::new();
|
||||||
|
for index in tags.variables() {
|
||||||
|
let slice = source[index];
|
||||||
|
for var_index in slice {
|
||||||
|
let var = source[var_index];
|
||||||
|
let new_var = deep_copy_var_to_help(source, target, max_rank, var);
|
||||||
|
new_variables.push(new_var);
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_slice =
|
||||||
|
VariableSubsSlice::insert_into_subs(target, new_variables.drain(..));
|
||||||
|
|
||||||
|
new_variable_slices.push(new_slice);
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_variables = {
|
||||||
|
let start = target.variable_slices.len() as u32;
|
||||||
|
let length = new_variable_slices.len() as u16;
|
||||||
|
target.variable_slices.extend(new_variable_slices);
|
||||||
|
|
||||||
|
SubsSlice::new(start, length)
|
||||||
|
};
|
||||||
|
|
||||||
|
let new_tag_names = {
|
||||||
|
let tag_names = tags.tag_names();
|
||||||
|
let slice = &source.tag_names[tag_names.start as usize..]
|
||||||
|
[..tag_names.length as usize];
|
||||||
|
|
||||||
|
let start = target.tag_names.len() as u32;
|
||||||
|
let length = tag_names.len() as u16;
|
||||||
|
|
||||||
|
target.tag_names.extend(slice.iter().cloned());
|
||||||
|
|
||||||
|
SubsSlice::new(start, length)
|
||||||
|
};
|
||||||
|
|
||||||
|
let union_tags = UnionTags::from_slices(new_tag_names, new_variables);
|
||||||
|
|
||||||
|
let new_ext = deep_copy_var_to_help(source, target, max_rank, ext_var);
|
||||||
|
let new_rec_var = deep_copy_var_to_help(source, target, max_rank, rec_var);
|
||||||
|
|
||||||
|
RecursiveTagUnion(new_rec_var, union_tags, new_ext)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
target.set(copy, make_descriptor(Structure(new_flat_type)));
|
||||||
|
|
||||||
|
copy
|
||||||
|
}
|
||||||
|
|
||||||
|
FlexVar(_) | Error => copy,
|
||||||
|
|
||||||
|
RecursionVar {
|
||||||
|
opt_name,
|
||||||
|
structure,
|
||||||
|
} => {
|
||||||
|
let new_structure = deep_copy_var_to_help(source, target, max_rank, structure);
|
||||||
|
|
||||||
|
debug_assert!((new_structure.index() as usize) < target.len());
|
||||||
|
|
||||||
|
target.set(
|
||||||
|
copy,
|
||||||
|
make_descriptor(RecursionVar {
|
||||||
|
opt_name,
|
||||||
|
structure: new_structure,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
copy
|
||||||
|
}
|
||||||
|
|
||||||
|
RigidVar(name) => {
|
||||||
|
target.set(copy, make_descriptor(FlexVar(Some(name))));
|
||||||
|
|
||||||
|
copy
|
||||||
|
}
|
||||||
|
|
||||||
|
Alias(symbol, mut args, real_type_var) => {
|
||||||
|
let mut new_vars = Vec::with_capacity(args.variables().len());
|
||||||
|
|
||||||
|
for var_index in args.variables() {
|
||||||
|
let var = source[var_index];
|
||||||
|
let new_var = deep_copy_var_to_help(source, target, max_rank, var);
|
||||||
|
|
||||||
|
new_vars.push(new_var);
|
||||||
|
}
|
||||||
|
|
||||||
|
args.replace_variables(target, new_vars);
|
||||||
|
|
||||||
|
let lowercases = &source.field_names[args.lowercases_start as usize..]
|
||||||
|
[..args.lowercases_len as usize];
|
||||||
|
|
||||||
|
args.lowercases_start = target.field_names.len() as u32;
|
||||||
|
target.field_names.extend(lowercases.iter().cloned());
|
||||||
|
|
||||||
|
let new_real_type_var = deep_copy_var_to_help(source, target, max_rank, real_type_var);
|
||||||
|
let new_content = Alias(symbol, args, new_real_type_var);
|
||||||
|
|
||||||
|
target.set(copy, make_descriptor(new_content));
|
||||||
|
|
||||||
|
copy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -133,12 +133,14 @@ fn unify_context(subs: &mut Subs, pool: &mut Pool, ctx: Context) -> Outcome {
|
||||||
// println!("\n --- \n");
|
// println!("\n --- \n");
|
||||||
// dbg!(ctx.second, type2);
|
// dbg!(ctx.second, type2);
|
||||||
// println!("\n --------------- \n");
|
// println!("\n --------------- \n");
|
||||||
|
let content_1 = subs.get(ctx.first).content;
|
||||||
|
let content_2 = subs.get(ctx.second).content;
|
||||||
println!(
|
println!(
|
||||||
"{:?} {:?} ~ {:?} {:?}",
|
"{:?} {:?} ~ {:?} {:?}",
|
||||||
ctx.first,
|
ctx.first,
|
||||||
subs.get(ctx.first).content,
|
roc_types::subs::SubsFmtContent(&content_1, subs),
|
||||||
ctx.second,
|
ctx.second,
|
||||||
subs.get(ctx.second).content
|
roc_types::subs::SubsFmtContent(&content_2, subs),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
match &ctx.first_desc.content {
|
match &ctx.first_desc.content {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue