mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 00:24:34 +00:00
Introduce unspecialized lambda sets to Content::LambdaSet
This commit is contained in:
parent
67b730c137
commit
feea727697
10 changed files with 303 additions and 54 deletions
|
@ -1411,6 +1411,8 @@ fn adjust_rank_content(
|
||||||
LambdaSet(subs::LambdaSet {
|
LambdaSet(subs::LambdaSet {
|
||||||
solved,
|
solved,
|
||||||
recursion_var,
|
recursion_var,
|
||||||
|
// TODO: handle unspecialized
|
||||||
|
unspecialized: _,
|
||||||
}) => {
|
}) => {
|
||||||
let mut rank = group_rank;
|
let mut rank = group_rank;
|
||||||
|
|
||||||
|
@ -1611,6 +1613,8 @@ fn instantiate_rigids_help(
|
||||||
LambdaSet(subs::LambdaSet {
|
LambdaSet(subs::LambdaSet {
|
||||||
solved,
|
solved,
|
||||||
recursion_var,
|
recursion_var,
|
||||||
|
// TODO: handle unspecialized
|
||||||
|
unspecialized: _,
|
||||||
}) => {
|
}) => {
|
||||||
if let Some(rec_var) = recursion_var.into_variable() {
|
if let Some(rec_var) = recursion_var.into_variable() {
|
||||||
instantiate_rigids_help(subs, max_rank, pools, rec_var);
|
instantiate_rigids_help(subs, max_rank, pools, rec_var);
|
||||||
|
@ -1892,6 +1896,7 @@ fn deep_copy_var_help(
|
||||||
LambdaSet(subs::LambdaSet {
|
LambdaSet(subs::LambdaSet {
|
||||||
solved,
|
solved,
|
||||||
recursion_var,
|
recursion_var,
|
||||||
|
unspecialized,
|
||||||
}) => {
|
}) => {
|
||||||
let mut new_variable_slices = Vec::with_capacity(solved.len());
|
let mut new_variable_slices = Vec::with_capacity(solved.len());
|
||||||
|
|
||||||
|
@ -1924,6 +1929,8 @@ fn deep_copy_var_help(
|
||||||
let new_content = LambdaSet(subs::LambdaSet {
|
let new_content = LambdaSet(subs::LambdaSet {
|
||||||
solved: new_solved,
|
solved: new_solved,
|
||||||
recursion_var: new_rec_var,
|
recursion_var: new_rec_var,
|
||||||
|
// TODO: actually copy
|
||||||
|
unspecialized,
|
||||||
});
|
});
|
||||||
|
|
||||||
subs.set(copy, make_descriptor(new_content));
|
subs.set(copy, make_descriptor(new_content));
|
||||||
|
|
|
@ -123,7 +123,15 @@ fn add_type_help<'a>(
|
||||||
Content::LambdaSet(LambdaSet {
|
Content::LambdaSet(LambdaSet {
|
||||||
solved,
|
solved,
|
||||||
recursion_var: _,
|
recursion_var: _,
|
||||||
}) => add_union(env, opt_name, solved, var, types),
|
unspecialized,
|
||||||
|
}) => {
|
||||||
|
debug_assert!(
|
||||||
|
unspecialized.is_empty(),
|
||||||
|
"unspecialized lambda sets left over"
|
||||||
|
);
|
||||||
|
|
||||||
|
add_union(env, opt_name, solved, var, types)
|
||||||
|
}
|
||||||
Content::Structure(FlatType::TagUnion(tags, ext_var)) => {
|
Content::Structure(FlatType::TagUnion(tags, ext_var)) => {
|
||||||
debug_assert!(ext_var_is_empty_tag_union(subs, *ext_var));
|
debug_assert!(ext_var_is_empty_tag_union(subs, *ext_var));
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,12 @@ use roc_can::{
|
||||||
def::Def,
|
def::Def,
|
||||||
expr::{AccessorData, ClosureData, Expr, Field, WhenBranch},
|
expr::{AccessorData, ClosureData, Expr, Field, WhenBranch},
|
||||||
};
|
};
|
||||||
use roc_types::subs::{
|
use roc_types::{
|
||||||
|
subs::{
|
||||||
self, AliasVariables, Descriptor, OptVariable, RecordFields, Subs, SubsSlice, UnionLambdas,
|
self, AliasVariables, Descriptor, OptVariable, RecordFields, Subs, SubsSlice, UnionLambdas,
|
||||||
UnionTags, Variable, VariableSubsSlice,
|
UnionTags, Variable, VariableSubsSlice,
|
||||||
|
},
|
||||||
|
types::Uls,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Deep copies the type variables in the type hosted by [`var`] into [`expr`].
|
/// Deep copies the type variables in the type hosted by [`var`] into [`expr`].
|
||||||
|
@ -610,12 +613,17 @@ fn deep_copy_type_vars<'a>(
|
||||||
LambdaSet(subs::LambdaSet {
|
LambdaSet(subs::LambdaSet {
|
||||||
solved,
|
solved,
|
||||||
recursion_var,
|
recursion_var,
|
||||||
|
unspecialized,
|
||||||
}) => {
|
}) => {
|
||||||
let new_rec_var = recursion_var.map(|var| descend_var!(var));
|
let new_rec_var = recursion_var.map(|var| descend_var!(var));
|
||||||
for variables_slice_index in solved.variables() {
|
for variables_slice_index in solved.variables() {
|
||||||
let variables_slice = subs[variables_slice_index];
|
let variables_slice = subs[variables_slice_index];
|
||||||
descend_slice!(variables_slice);
|
descend_slice!(variables_slice);
|
||||||
}
|
}
|
||||||
|
for uls_index in unspecialized {
|
||||||
|
let Uls(var, _, _) = subs[uls_index];
|
||||||
|
descend_var!(var);
|
||||||
|
}
|
||||||
|
|
||||||
perform_clone!({
|
perform_clone!({
|
||||||
let new_variable_slices =
|
let new_variable_slices =
|
||||||
|
@ -630,9 +638,19 @@ fn deep_copy_type_vars<'a>(
|
||||||
let new_solved =
|
let new_solved =
|
||||||
UnionLambdas::from_slices(solved.labels(), new_variable_slices);
|
UnionLambdas::from_slices(solved.labels(), new_variable_slices);
|
||||||
|
|
||||||
|
let new_unspecialized = SubsSlice::reserve_uls_slice(subs, unspecialized.len());
|
||||||
|
for (target_index, uls_index) in
|
||||||
|
(new_unspecialized.into_iter()).zip(unspecialized.into_iter())
|
||||||
|
{
|
||||||
|
let Uls(var, sym, region) = subs[uls_index];
|
||||||
|
let copy_var = subs.get_copy(var).into_variable().unwrap_or(var);
|
||||||
|
subs[target_index] = Uls(copy_var, sym, region);
|
||||||
|
}
|
||||||
|
|
||||||
LambdaSet(subs::LambdaSet {
|
LambdaSet(subs::LambdaSet {
|
||||||
solved: new_solved,
|
solved: new_solved,
|
||||||
recursion_var: new_rec_var,
|
recursion_var: new_rec_var,
|
||||||
|
unspecialized: new_unspecialized,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1698,7 +1698,16 @@ fn layout_from_lambda_set<'a>(
|
||||||
let subs::LambdaSet {
|
let subs::LambdaSet {
|
||||||
solved,
|
solved,
|
||||||
recursion_var,
|
recursion_var,
|
||||||
|
unspecialized,
|
||||||
} = lset;
|
} = lset;
|
||||||
|
|
||||||
|
if !unspecialized.is_empty() {
|
||||||
|
internal_error!(
|
||||||
|
"unspecialized lambda sets remain during layout generation for {:?}",
|
||||||
|
roc_types::subs::SubsFmtContent(&Content::LambdaSet(lset), env.subs)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
match recursion_var.into_variable() {
|
match recursion_var.into_variable() {
|
||||||
None => {
|
None => {
|
||||||
let labels = solved.unsorted_lambdas(env.subs);
|
let labels = solved.unsorted_lambdas(env.subs);
|
||||||
|
|
|
@ -276,8 +276,11 @@ impl LambdaSet {
|
||||||
let subs::LambdaSet {
|
let subs::LambdaSet {
|
||||||
solved,
|
solved,
|
||||||
recursion_var: _,
|
recursion_var: _,
|
||||||
|
unspecialized: _,
|
||||||
} = lset;
|
} = lset;
|
||||||
|
|
||||||
|
// TODO: handle unspecialized
|
||||||
|
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
!solved.is_empty(),
|
!solved.is_empty(),
|
||||||
"lambda set must contain atleast the function itself"
|
"lambda set must contain atleast the function itself"
|
||||||
|
@ -696,8 +699,11 @@ impl Layout {
|
||||||
let subs::LambdaSet {
|
let subs::LambdaSet {
|
||||||
solved,
|
solved,
|
||||||
recursion_var,
|
recursion_var,
|
||||||
|
unspecialized: _,
|
||||||
} = lset;
|
} = lset;
|
||||||
|
|
||||||
|
// TODO: handle unspecialized lambda set
|
||||||
|
|
||||||
match recursion_var.into_variable() {
|
match recursion_var.into_variable() {
|
||||||
Some(rec_var) => {
|
Some(rec_var) => {
|
||||||
let rec_var = subs.get_root_key_without_compacting(rec_var);
|
let rec_var = subs.get_root_key_without_compacting(rec_var);
|
||||||
|
|
|
@ -19,13 +19,14 @@ use roc_problem::can::CycleEntry;
|
||||||
use roc_region::all::{Loc, Region};
|
use roc_region::all::{Loc, Region};
|
||||||
use roc_types::solved_types::Solved;
|
use roc_types::solved_types::Solved;
|
||||||
use roc_types::subs::{
|
use roc_types::subs::{
|
||||||
self, AliasVariables, Content, Descriptor, FlatType, Mark, OptVariable, Rank, RecordFields,
|
self, AliasVariables, Content, Descriptor, FlatType, GetSubsSlice, Mark, OptVariable, Rank,
|
||||||
Subs, SubsIndex, SubsSlice, UnionLabels, UnionLambdas, UnionTags, Variable, VariableSubsSlice,
|
RecordFields, Subs, SubsIndex, SubsSlice, UnionLabels, UnionLambdas, UnionTags, Variable,
|
||||||
|
VariableSubsSlice,
|
||||||
};
|
};
|
||||||
use roc_types::types::Type::{self, *};
|
use roc_types::types::Type::{self, *};
|
||||||
use roc_types::types::{
|
use roc_types::types::{
|
||||||
gather_fields_unsorted_iter, AliasCommon, AliasKind, Category, ErrorType, OptAbleType,
|
gather_fields_unsorted_iter, AliasCommon, AliasKind, Category, ErrorType, OptAbleType,
|
||||||
OptAbleVar, PatternCategory, Reason, TypeExtension,
|
OptAbleVar, PatternCategory, Reason, TypeExtension, Uls,
|
||||||
};
|
};
|
||||||
use roc_unify::unify::{unify, Mode, Obligated, Unified::*};
|
use roc_unify::unify::{unify, Mode, Obligated, Unified::*};
|
||||||
|
|
||||||
|
@ -1883,17 +1884,20 @@ fn type_to_variable<'a>(
|
||||||
// We may figure out the lambda set is recursive during solving, but it never
|
// We may figure out the lambda set is recursive during solving, but it never
|
||||||
// is to begin with.
|
// is to begin with.
|
||||||
recursion_var: OptVariable::NONE,
|
recursion_var: OptVariable::NONE,
|
||||||
|
unspecialized: SubsSlice::default(),
|
||||||
});
|
});
|
||||||
|
|
||||||
register_with_known_var(subs, destination, rank, pools, content)
|
register_with_known_var(subs, destination, rank, pools, content)
|
||||||
}
|
}
|
||||||
UnspecializedLambdaSet(..) => {
|
UnspecializedLambdaSet(uls) => {
|
||||||
// TODO: instantiate properly!
|
let unspecialized = SubsSlice::extend_new(
|
||||||
let union_lambdas =
|
&mut subs.unspecialized_lambda_sets,
|
||||||
UnionLambdas::from_slices(SubsSlice::new(0, 0), SubsSlice::new(0, 0));
|
std::iter::once(*uls),
|
||||||
|
);
|
||||||
|
|
||||||
let content = Content::LambdaSet(subs::LambdaSet {
|
let content = Content::LambdaSet(subs::LambdaSet {
|
||||||
solved: union_lambdas,
|
unspecialized,
|
||||||
|
solved: UnionLabels::default(),
|
||||||
recursion_var: OptVariable::NONE,
|
recursion_var: OptVariable::NONE,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -2555,8 +2559,9 @@ fn check_for_infinite_type(
|
||||||
&Content::LambdaSet(subs::LambdaSet {
|
&Content::LambdaSet(subs::LambdaSet {
|
||||||
solved,
|
solved,
|
||||||
recursion_var: _,
|
recursion_var: _,
|
||||||
|
unspecialized,
|
||||||
}) => {
|
}) => {
|
||||||
subs.mark_lambda_set_recursive(recursive, solved);
|
subs.mark_lambda_set_recursive(recursive, solved, unspecialized);
|
||||||
}
|
}
|
||||||
|
|
||||||
_other => circular_error(subs, problems, symbol, &loc_var),
|
_other => circular_error(subs, problems, symbol, &loc_var),
|
||||||
|
@ -2903,6 +2908,7 @@ fn adjust_rank_content(
|
||||||
LambdaSet(subs::LambdaSet {
|
LambdaSet(subs::LambdaSet {
|
||||||
solved,
|
solved,
|
||||||
recursion_var,
|
recursion_var,
|
||||||
|
unspecialized,
|
||||||
}) => {
|
}) => {
|
||||||
let mut rank = group_rank;
|
let mut rank = group_rank;
|
||||||
|
|
||||||
|
@ -2914,6 +2920,11 @@ fn adjust_rank_content(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for uls_index in *unspecialized {
|
||||||
|
let Uls(var, _, _) = subs[uls_index];
|
||||||
|
rank = rank.max(adjust_rank(subs, young_mark, visit_mark, group_rank, var));
|
||||||
|
}
|
||||||
|
|
||||||
if let (true, Some(rec_var)) = (cfg!(debug_assertions), recursion_var.into_variable()) {
|
if let (true, Some(rec_var)) = (cfg!(debug_assertions), recursion_var.into_variable()) {
|
||||||
// THEORY: unlike the situation for recursion vars under recursive tag unions,
|
// THEORY: unlike the situation for recursion vars under recursive tag unions,
|
||||||
// recursive vars inside lambda sets can't escape into higher let-generalized regions
|
// recursive vars inside lambda sets can't escape into higher let-generalized regions
|
||||||
|
@ -3092,6 +3103,7 @@ fn instantiate_rigids_help(subs: &mut Subs, max_rank: Rank, initial: Variable) {
|
||||||
LambdaSet(subs::LambdaSet {
|
LambdaSet(subs::LambdaSet {
|
||||||
solved,
|
solved,
|
||||||
recursion_var,
|
recursion_var,
|
||||||
|
unspecialized,
|
||||||
}) => {
|
}) => {
|
||||||
for slice_index in solved.variables() {
|
for slice_index in solved.variables() {
|
||||||
let slice = subs.variable_slices[slice_index.index as usize];
|
let slice = subs.variable_slices[slice_index.index as usize];
|
||||||
|
@ -3101,6 +3113,10 @@ fn instantiate_rigids_help(subs: &mut Subs, max_rank: Rank, initial: Variable) {
|
||||||
if let Some(rec_var) = recursion_var.into_variable() {
|
if let Some(rec_var) = recursion_var.into_variable() {
|
||||||
stack.push(rec_var);
|
stack.push(rec_var);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for Uls(var, _, _) in subs.get_subs_slice(*unspecialized) {
|
||||||
|
stack.push(*var);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
&RangedNumber(typ, _) => {
|
&RangedNumber(typ, _) => {
|
||||||
stack.push(typ);
|
stack.push(typ);
|
||||||
|
@ -3364,15 +3380,31 @@ fn deep_copy_var_help(
|
||||||
LambdaSet(subs::LambdaSet {
|
LambdaSet(subs::LambdaSet {
|
||||||
solved,
|
solved,
|
||||||
recursion_var,
|
recursion_var,
|
||||||
|
unspecialized,
|
||||||
}) => {
|
}) => {
|
||||||
let new_solved = copy_union!(solved);
|
let new_solved = copy_union!(solved);
|
||||||
let new_rec_var = recursion_var.map(|v| work!(v));
|
let new_rec_var = recursion_var.map(|v| work!(v));
|
||||||
|
let new_unspecialized = SubsSlice::reserve_uls_slice(subs, unspecialized.len());
|
||||||
|
|
||||||
|
for (new_uls_index, uls_index) in
|
||||||
|
(new_unspecialized.into_iter()).zip(unspecialized.into_iter())
|
||||||
|
{
|
||||||
|
let Uls(var, sym, region) = subs[uls_index];
|
||||||
|
let new_var = work!(var);
|
||||||
|
|
||||||
|
deep_copy_uls_precondition(subs, var, new_var);
|
||||||
|
|
||||||
|
subs[new_uls_index] = Uls(new_var, sym, region);
|
||||||
|
|
||||||
|
// TODO: bookkeeping of new_var -> lambda set
|
||||||
|
}
|
||||||
|
|
||||||
subs.set_content_unchecked(
|
subs.set_content_unchecked(
|
||||||
copy,
|
copy,
|
||||||
LambdaSet(subs::LambdaSet {
|
LambdaSet(subs::LambdaSet {
|
||||||
solved: new_solved,
|
solved: new_solved,
|
||||||
recursion_var: new_rec_var,
|
recursion_var: new_rec_var,
|
||||||
|
unspecialized: new_unspecialized,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -3388,6 +3420,26 @@ fn deep_copy_var_help(
|
||||||
initial_copy
|
initial_copy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn deep_copy_uls_precondition(subs: &Subs, original_var: Variable, new_var: Variable) {
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
let content = subs.get_content_without_compacting(original_var);
|
||||||
|
|
||||||
|
debug_assert!(
|
||||||
|
matches!(
|
||||||
|
content,
|
||||||
|
Content::FlexAbleVar(..) | Content::RigidAbleVar(..)
|
||||||
|
),
|
||||||
|
"var in unspecialized lamba set is not bound to an ability, it is {:?}",
|
||||||
|
roc_types::subs::SubsFmtContent(&content, subs)
|
||||||
|
);
|
||||||
|
debug_assert!(
|
||||||
|
original_var != new_var,
|
||||||
|
"unspecialized lamba set var was not instantiated"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn register(subs: &mut Subs, rank: Rank, pools: &mut Pools, content: Content) -> Variable {
|
fn register(subs: &mut Subs, rank: Rank, pools: &mut Pools, content: Content) -> Variable {
|
||||||
let descriptor = Descriptor {
|
let descriptor = Descriptor {
|
||||||
|
|
|
@ -2,7 +2,7 @@ use crate::subs::{
|
||||||
self, AliasVariables, Content, FlatType, GetSubsSlice, Label, Subs, SubsIndex, UnionLabels,
|
self, AliasVariables, Content, FlatType, GetSubsSlice, Label, Subs, SubsIndex, UnionLabels,
|
||||||
UnionTags, Variable,
|
UnionTags, Variable,
|
||||||
};
|
};
|
||||||
use crate::types::{name_type_var, RecordField};
|
use crate::types::{name_type_var, RecordField, Uls};
|
||||||
use roc_collections::all::MutMap;
|
use roc_collections::all::MutMap;
|
||||||
use roc_error_macros::internal_error;
|
use roc_error_macros::internal_error;
|
||||||
use roc_module::ident::{Lowercase, TagName};
|
use roc_module::ident::{Lowercase, TagName};
|
||||||
|
@ -234,6 +234,7 @@ fn find_names_needed(
|
||||||
LambdaSet(subs::LambdaSet {
|
LambdaSet(subs::LambdaSet {
|
||||||
solved,
|
solved,
|
||||||
recursion_var,
|
recursion_var,
|
||||||
|
unspecialized,
|
||||||
}) => {
|
}) => {
|
||||||
for slice_index in solved.variables() {
|
for slice_index in solved.variables() {
|
||||||
let slice = subs[slice_index];
|
let slice = subs[slice_index];
|
||||||
|
@ -243,6 +244,11 @@ fn find_names_needed(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for uls_index in unspecialized.into_iter() {
|
||||||
|
let Uls(var, _, _) = subs[uls_index];
|
||||||
|
find_names_needed(var, subs, roots, root_appearances, names_taken);
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(rec_var) = recursion_var.into_variable() {
|
if let Some(rec_var) = recursion_var.into_variable() {
|
||||||
find_names_needed(rec_var, subs, roots, root_appearances, names_taken);
|
find_names_needed(rec_var, subs, roots, root_appearances, names_taken);
|
||||||
}
|
}
|
||||||
|
@ -965,7 +971,12 @@ pub fn resolve_lambda_set(subs: &Subs, mut var: Variable) -> ResolvedLambdaSet {
|
||||||
Content::LambdaSet(subs::LambdaSet {
|
Content::LambdaSet(subs::LambdaSet {
|
||||||
solved,
|
solved,
|
||||||
recursion_var: _,
|
recursion_var: _,
|
||||||
|
unspecialized,
|
||||||
}) => {
|
}) => {
|
||||||
|
debug_assert!(
|
||||||
|
unspecialized.is_empty(),
|
||||||
|
"unspecialized lambda sets left over during resolution"
|
||||||
|
);
|
||||||
push_union(subs, solved, &mut set);
|
push_union(subs, solved, &mut set);
|
||||||
return ResolvedLambdaSet::Set(set);
|
return ResolvedLambdaSet::Set(set);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#![deny(unsafe_op_in_unsafe_fn)]
|
#![deny(unsafe_op_in_unsafe_fn)]
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
name_type_var, AliasKind, ErrorType, Problem, RecordField, RecordFieldsError, TypeExt,
|
name_type_var, AliasKind, ErrorType, Problem, RecordField, RecordFieldsError, TypeExt, Uls,
|
||||||
};
|
};
|
||||||
use roc_collections::all::{ImMap, ImSet, MutSet, SendMap};
|
use roc_collections::all::{ImMap, ImSet, MutSet, SendMap};
|
||||||
use roc_error_macros::internal_error;
|
use roc_error_macros::internal_error;
|
||||||
|
@ -75,6 +75,7 @@ struct SubsHeader {
|
||||||
field_names: u64,
|
field_names: u64,
|
||||||
record_fields: u64,
|
record_fields: u64,
|
||||||
variable_slices: u64,
|
variable_slices: u64,
|
||||||
|
unspecialized_lambda_sets: u64,
|
||||||
exposed_vars_by_symbol: u64,
|
exposed_vars_by_symbol: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,6 +93,7 @@ impl SubsHeader {
|
||||||
field_names: subs.field_names.len() as u64,
|
field_names: subs.field_names.len() as u64,
|
||||||
record_fields: subs.record_fields.len() as u64,
|
record_fields: subs.record_fields.len() as u64,
|
||||||
variable_slices: subs.variable_slices.len() as u64,
|
variable_slices: subs.variable_slices.len() as u64,
|
||||||
|
unspecialized_lambda_sets: subs.unspecialized_lambda_sets.len() as u64,
|
||||||
exposed_vars_by_symbol: exposed_vars_by_symbol as u64,
|
exposed_vars_by_symbol: exposed_vars_by_symbol as u64,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -138,6 +140,7 @@ impl Subs {
|
||||||
written = Self::serialize_field_names(&self.field_names, writer, written)?;
|
written = Self::serialize_field_names(&self.field_names, writer, written)?;
|
||||||
written = Self::serialize_slice(&self.record_fields, writer, written)?;
|
written = Self::serialize_slice(&self.record_fields, writer, written)?;
|
||||||
written = Self::serialize_slice(&self.variable_slices, writer, written)?;
|
written = Self::serialize_slice(&self.variable_slices, writer, written)?;
|
||||||
|
written = Self::serialize_slice(&self.unspecialized_lambda_sets, writer, written)?;
|
||||||
written = Self::serialize_slice(exposed_vars_by_symbol, writer, written)?;
|
written = Self::serialize_slice(exposed_vars_by_symbol, writer, written)?;
|
||||||
|
|
||||||
Ok(written)
|
Ok(written)
|
||||||
|
@ -221,6 +224,8 @@ impl Subs {
|
||||||
Self::deserialize_slice(bytes, header.record_fields as usize, offset);
|
Self::deserialize_slice(bytes, header.record_fields as usize, offset);
|
||||||
let (variable_slices, offset) =
|
let (variable_slices, offset) =
|
||||||
Self::deserialize_slice(bytes, header.variable_slices as usize, offset);
|
Self::deserialize_slice(bytes, header.variable_slices as usize, offset);
|
||||||
|
let (unspecialized_lambda_sets, offset) =
|
||||||
|
Self::deserialize_slice(bytes, header.unspecialized_lambda_sets as usize, offset);
|
||||||
let (exposed_vars_by_symbol, _) =
|
let (exposed_vars_by_symbol, _) =
|
||||||
Self::deserialize_slice(bytes, header.exposed_vars_by_symbol as usize, offset);
|
Self::deserialize_slice(bytes, header.exposed_vars_by_symbol as usize, offset);
|
||||||
|
|
||||||
|
@ -233,6 +238,7 @@ impl Subs {
|
||||||
field_names,
|
field_names,
|
||||||
record_fields: record_fields.to_vec(),
|
record_fields: record_fields.to_vec(),
|
||||||
variable_slices: variable_slices.to_vec(),
|
variable_slices: variable_slices.to_vec(),
|
||||||
|
unspecialized_lambda_sets: unspecialized_lambda_sets.to_vec(),
|
||||||
tag_name_cache: Default::default(),
|
tag_name_cache: Default::default(),
|
||||||
problems: Default::default(),
|
problems: Default::default(),
|
||||||
},
|
},
|
||||||
|
@ -309,6 +315,7 @@ pub struct Subs {
|
||||||
pub field_names: Vec<Lowercase>,
|
pub field_names: Vec<Lowercase>,
|
||||||
pub record_fields: Vec<RecordField<()>>,
|
pub record_fields: Vec<RecordField<()>>,
|
||||||
pub variable_slices: Vec<VariableSubsSlice>,
|
pub variable_slices: Vec<VariableSubsSlice>,
|
||||||
|
pub unspecialized_lambda_sets: Vec<Uls>,
|
||||||
pub tag_name_cache: TagNameCache,
|
pub tag_name_cache: TagNameCache,
|
||||||
pub problems: Vec<Problem>,
|
pub problems: Vec<Problem>,
|
||||||
}
|
}
|
||||||
|
@ -408,6 +415,20 @@ impl std::ops::IndexMut<SubsIndex<Symbol>> for Subs {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::ops::Index<SubsIndex<Uls>> for Subs {
|
||||||
|
type Output = Uls;
|
||||||
|
|
||||||
|
fn index(&self, index: SubsIndex<Uls>) -> &Self::Output {
|
||||||
|
&self.unspecialized_lambda_sets[index.index as usize]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::IndexMut<SubsIndex<Uls>> for Subs {
|
||||||
|
fn index_mut(&mut self, index: SubsIndex<Uls>) -> &mut Self::Output {
|
||||||
|
&mut self.unspecialized_lambda_sets[index.index as usize]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl std::ops::IndexMut<SubsIndex<Lowercase>> for Subs {
|
impl std::ops::IndexMut<SubsIndex<Lowercase>> for Subs {
|
||||||
fn index_mut(&mut self, index: SubsIndex<Lowercase>) -> &mut Self::Output {
|
fn index_mut(&mut self, index: SubsIndex<Lowercase>) -> &mut Self::Output {
|
||||||
&mut self.field_names[index.index as usize]
|
&mut self.field_names[index.index as usize]
|
||||||
|
@ -567,6 +588,17 @@ impl SubsSlice<TagName> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl SubsSlice<Uls> {
|
||||||
|
pub fn reserve_uls_slice(subs: &mut Subs, length: usize) -> Self {
|
||||||
|
let start = subs.unspecialized_lambda_sets.len() as u32;
|
||||||
|
|
||||||
|
subs.unspecialized_lambda_sets
|
||||||
|
.extend(std::iter::repeat(Uls(Variable::NULL, Symbol::UNDERSCORE, 0)).take(length));
|
||||||
|
|
||||||
|
Self::new(start, length as u16)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> SubsIndex<T> {
|
impl<T> SubsIndex<T> {
|
||||||
pub const fn new(start: u32) -> Self {
|
pub const fn new(start: u32) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -640,6 +672,12 @@ impl GetSubsSlice<Symbol> for Subs {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl GetSubsSlice<Uls> for Subs {
|
||||||
|
fn get_subs_slice(&self, subs_slice: SubsSlice<Uls>) -> &[Uls] {
|
||||||
|
subs_slice.get_slice(&self.unspecialized_lambda_sets)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Subs {
|
impl fmt::Debug for Subs {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
writeln!(f)?;
|
writeln!(f)?;
|
||||||
|
@ -711,6 +749,7 @@ fn subs_fmt_content(this: &Content, subs: &Subs, f: &mut fmt::Formatter) -> fmt:
|
||||||
Content::LambdaSet(LambdaSet {
|
Content::LambdaSet(LambdaSet {
|
||||||
solved,
|
solved,
|
||||||
recursion_var,
|
recursion_var,
|
||||||
|
unspecialized,
|
||||||
}) => {
|
}) => {
|
||||||
write!(f, "LambdaSet([")?;
|
write!(f, "LambdaSet([")?;
|
||||||
|
|
||||||
|
@ -727,7 +766,14 @@ fn subs_fmt_content(this: &Content, subs: &Subs, f: &mut fmt::Formatter) -> fmt:
|
||||||
write!(f, ", ")?;
|
write!(f, ", ")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
write!(f, "<{:?}>])", recursion_var)
|
write!(f, "]")?;
|
||||||
|
if let Some(rec_var) = recursion_var.into_variable() {
|
||||||
|
write!(f, " as <{:?}>", rec_var)?;
|
||||||
|
}
|
||||||
|
for uls in subs.get_subs_slice(*unspecialized) {
|
||||||
|
write!(f, " + {:?}", uls)?;
|
||||||
|
}
|
||||||
|
write!(f, ")")
|
||||||
}
|
}
|
||||||
Content::RangedNumber(typ, range) => {
|
Content::RangedNumber(typ, range) => {
|
||||||
write!(f, "RangedNumber({:?}, {:?})", typ, range)
|
write!(f, "RangedNumber({:?}, {:?})", typ, range)
|
||||||
|
@ -1518,6 +1564,7 @@ impl Subs {
|
||||||
// store an empty slice at the first position
|
// store an empty slice at the first position
|
||||||
// used for "TagOrFunction"
|
// used for "TagOrFunction"
|
||||||
variable_slices: vec![VariableSubsSlice::default()],
|
variable_slices: vec![VariableSubsSlice::default()],
|
||||||
|
unspecialized_lambda_sets: Vec::new(),
|
||||||
tag_name_cache: Default::default(),
|
tag_name_cache: Default::default(),
|
||||||
problems: Vec::new(),
|
problems: Vec::new(),
|
||||||
};
|
};
|
||||||
|
@ -1765,12 +1812,18 @@ impl Subs {
|
||||||
self.set_content(recursive, Content::Structure(flat_type));
|
self.set_content(recursive, Content::Structure(flat_type));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mark_lambda_set_recursive(&mut self, recursive: Variable, solved_lambdas: UnionLambdas) {
|
pub fn mark_lambda_set_recursive(
|
||||||
|
&mut self,
|
||||||
|
recursive: Variable,
|
||||||
|
solved_lambdas: UnionLambdas,
|
||||||
|
unspecialized_lambdas: SubsSlice<Uls>,
|
||||||
|
) {
|
||||||
let (rec_var, new_tags) = self.mark_union_recursive_help(recursive, solved_lambdas);
|
let (rec_var, new_tags) = self.mark_union_recursive_help(recursive, solved_lambdas);
|
||||||
|
|
||||||
let new_lambda_set = Content::LambdaSet(LambdaSet {
|
let new_lambda_set = Content::LambdaSet(LambdaSet {
|
||||||
solved: new_tags,
|
solved: new_tags,
|
||||||
recursion_var: OptVariable::from(rec_var),
|
recursion_var: OptVariable::from(rec_var),
|
||||||
|
unspecialized: unspecialized_lambdas,
|
||||||
});
|
});
|
||||||
|
|
||||||
self.set_content(recursive, new_lambda_set);
|
self.set_content(recursive, new_lambda_set);
|
||||||
|
@ -2059,6 +2112,8 @@ pub struct LambdaSet {
|
||||||
///
|
///
|
||||||
/// However, we don't know if a lambda set is recursive or not until type inference.
|
/// However, we don't know if a lambda set is recursive or not until type inference.
|
||||||
pub recursion_var: OptVariable,
|
pub recursion_var: OptVariable,
|
||||||
|
/// Lambdas we won't know until an ability specialization is resolved.
|
||||||
|
pub unspecialized: SubsSlice<Uls>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default)]
|
#[derive(Clone, Copy, Debug, Default)]
|
||||||
|
@ -2935,6 +2990,7 @@ fn occurs(
|
||||||
LambdaSet(self::LambdaSet {
|
LambdaSet(self::LambdaSet {
|
||||||
solved,
|
solved,
|
||||||
recursion_var,
|
recursion_var,
|
||||||
|
unspecialized: _,
|
||||||
}) => {
|
}) => {
|
||||||
let mut new_seen = seen.to_owned();
|
let mut new_seen = seen.to_owned();
|
||||||
new_seen.push(root_var);
|
new_seen.push(root_var);
|
||||||
|
@ -2945,6 +3001,9 @@ fn occurs(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// unspecialized lambda vars excluded because they are not explicitly part of the
|
||||||
|
// type (they only matter after being resolved).
|
||||||
|
|
||||||
occurs_union(subs, root_var, &new_seen, include_recursion_var, solved)
|
occurs_union(subs, root_var, &new_seen, include_recursion_var, solved)
|
||||||
}
|
}
|
||||||
RangedNumber(typ, _range_vars) => {
|
RangedNumber(typ, _range_vars) => {
|
||||||
|
@ -3122,15 +3181,21 @@ fn explicit_substitute(
|
||||||
LambdaSet(self::LambdaSet {
|
LambdaSet(self::LambdaSet {
|
||||||
solved,
|
solved,
|
||||||
recursion_var,
|
recursion_var,
|
||||||
|
unspecialized,
|
||||||
}) => {
|
}) => {
|
||||||
// NOTE recursion_var is not substituted, verify that this is correct!
|
// NOTE recursion_var is not substituted, verify that this is correct!
|
||||||
let new_solved = explicit_substitute_union(subs, from, to, solved, seen);
|
let new_solved = explicit_substitute_union(subs, from, to, solved, seen);
|
||||||
|
|
||||||
|
for Uls(v, _, _) in subs.get_subs_slice(unspecialized) {
|
||||||
|
debug_assert!(*v != from, "unspecialized lambda set vars should never occur in a position where they need to be explicitly substituted.");
|
||||||
|
}
|
||||||
|
|
||||||
subs.set_content(
|
subs.set_content(
|
||||||
in_var,
|
in_var,
|
||||||
LambdaSet(self::LambdaSet {
|
LambdaSet(self::LambdaSet {
|
||||||
solved: new_solved,
|
solved: new_solved,
|
||||||
recursion_var,
|
recursion_var,
|
||||||
|
unspecialized,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -3239,12 +3304,18 @@ fn get_var_names(
|
||||||
LambdaSet(self::LambdaSet {
|
LambdaSet(self::LambdaSet {
|
||||||
solved,
|
solved,
|
||||||
recursion_var,
|
recursion_var,
|
||||||
|
unspecialized,
|
||||||
}) => {
|
}) => {
|
||||||
let taken_names = get_var_names_union(subs, solved, taken_names);
|
let taken_names = get_var_names_union(subs, solved, taken_names);
|
||||||
match recursion_var.into_variable() {
|
let mut taken_names = match recursion_var.into_variable() {
|
||||||
Some(v) => get_var_names(subs, v, taken_names),
|
Some(v) => get_var_names(subs, v, taken_names),
|
||||||
None => taken_names,
|
None => taken_names,
|
||||||
|
};
|
||||||
|
for uls_index in unspecialized {
|
||||||
|
let Uls(v, _, _) = subs[uls_index];
|
||||||
|
taken_names = get_var_names(subs, v, taken_names);
|
||||||
}
|
}
|
||||||
|
taken_names
|
||||||
}
|
}
|
||||||
|
|
||||||
RangedNumber(typ, _) => get_var_names(subs, typ, taken_names),
|
RangedNumber(typ, _) => get_var_names(subs, typ, taken_names),
|
||||||
|
@ -3483,10 +3554,7 @@ fn content_to_err_type(
|
||||||
ErrorType::Alias(symbol, err_args, Box::new(err_type), kind)
|
ErrorType::Alias(symbol, err_args, Box::new(err_type), kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
LambdaSet(self::LambdaSet {
|
LambdaSet(self::LambdaSet { .. }) => {
|
||||||
solved: _,
|
|
||||||
recursion_var: _r,
|
|
||||||
}) => {
|
|
||||||
// Don't print lambda sets since we don't expect them to be exposed to the user
|
// Don't print lambda sets since we don't expect them to be exposed to the user
|
||||||
ErrorType::Error
|
ErrorType::Error
|
||||||
}
|
}
|
||||||
|
@ -3727,6 +3795,7 @@ struct StorageSubsOffsets {
|
||||||
field_names: u32,
|
field_names: u32,
|
||||||
record_fields: u32,
|
record_fields: u32,
|
||||||
variable_slices: u32,
|
variable_slices: u32,
|
||||||
|
unspecialized_lambda_sets: u32,
|
||||||
problems: u32,
|
problems: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3744,7 +3813,7 @@ impl StorageSubs {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn extend_with_variable(&mut self, source: &mut Subs, variable: Variable) -> Variable {
|
pub fn extend_with_variable(&mut self, source: &mut Subs, variable: Variable) -> Variable {
|
||||||
deep_copy_var_to(source, &mut self.subs, variable)
|
storage_copy_var_to(source, &mut self.subs, variable)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn import_variable_from(&mut self, source: &mut Subs, variable: Variable) -> CopiedImport {
|
pub fn import_variable_from(&mut self, source: &mut Subs, variable: Variable) -> CopiedImport {
|
||||||
|
@ -3764,6 +3833,7 @@ impl StorageSubs {
|
||||||
field_names: self.subs.field_names.len() as u32,
|
field_names: self.subs.field_names.len() as u32,
|
||||||
record_fields: self.subs.record_fields.len() as u32,
|
record_fields: self.subs.record_fields.len() as u32,
|
||||||
variable_slices: self.subs.variable_slices.len() as u32,
|
variable_slices: self.subs.variable_slices.len() as u32,
|
||||||
|
unspecialized_lambda_sets: self.subs.unspecialized_lambda_sets.len() as u32,
|
||||||
problems: self.subs.problems.len() as u32,
|
problems: self.subs.problems.len() as u32,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3775,6 +3845,7 @@ impl StorageSubs {
|
||||||
field_names: target.field_names.len() as u32,
|
field_names: target.field_names.len() as u32,
|
||||||
record_fields: target.record_fields.len() as u32,
|
record_fields: target.record_fields.len() as u32,
|
||||||
variable_slices: target.variable_slices.len() as u32,
|
variable_slices: target.variable_slices.len() as u32,
|
||||||
|
unspecialized_lambda_sets: target.unspecialized_lambda_sets.len() as u32,
|
||||||
problems: target.problems.len() as u32,
|
problems: target.problems.len() as u32,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3821,6 +3892,9 @@ impl StorageSubs {
|
||||||
target.closure_names.extend(self.subs.closure_names);
|
target.closure_names.extend(self.subs.closure_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);
|
||||||
|
target
|
||||||
|
.unspecialized_lambda_sets
|
||||||
|
.extend(self.subs.unspecialized_lambda_sets);
|
||||||
target.problems.extend(self.subs.problems);
|
target.problems.extend(self.subs.problems);
|
||||||
|
|
||||||
debug_assert_eq!(
|
debug_assert_eq!(
|
||||||
|
@ -3905,9 +3979,11 @@ impl StorageSubs {
|
||||||
LambdaSet(self::LambdaSet {
|
LambdaSet(self::LambdaSet {
|
||||||
solved,
|
solved,
|
||||||
recursion_var,
|
recursion_var,
|
||||||
|
unspecialized,
|
||||||
}) => LambdaSet(self::LambdaSet {
|
}) => LambdaSet(self::LambdaSet {
|
||||||
solved: Self::offset_lambda_set(offsets, *solved),
|
solved: Self::offset_lambda_set(offsets, *solved),
|
||||||
recursion_var: recursion_var.map(|v| Self::offset_variable(offsets, v)),
|
recursion_var: recursion_var.map(|v| Self::offset_variable(offsets, v)),
|
||||||
|
unspecialized: Self::offset_uls_slice(offsets, *unspecialized),
|
||||||
}),
|
}),
|
||||||
RangedNumber(typ, range) => RangedNumber(Self::offset_variable(offsets, *typ), *range),
|
RangedNumber(typ, range) => RangedNumber(Self::offset_variable(offsets, *typ), *range),
|
||||||
Error => Content::Error,
|
Error => Content::Error,
|
||||||
|
@ -3978,6 +4054,12 @@ impl StorageSubs {
|
||||||
slice
|
slice
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn offset_uls_slice(offsets: &StorageSubsOffsets, mut slice: SubsSlice<Uls>) -> SubsSlice<Uls> {
|
||||||
|
slice.start += offsets.unspecialized_lambda_sets;
|
||||||
|
|
||||||
|
slice
|
||||||
|
}
|
||||||
|
|
||||||
fn offset_problem(
|
fn offset_problem(
|
||||||
offsets: &StorageSubsOffsets,
|
offsets: &StorageSubsOffsets,
|
||||||
mut problem_index: SubsIndex<Problem>,
|
mut problem_index: SubsIndex<Problem>,
|
||||||
|
@ -4004,7 +4086,7 @@ fn put_scratchpad(scratchpad: bumpalo::Bump) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deep_copy_var_to(
|
pub fn storage_copy_var_to(
|
||||||
source: &mut Subs, // mut to set the copy
|
source: &mut Subs, // mut to set the copy
|
||||||
target: &mut Subs,
|
target: &mut Subs,
|
||||||
var: Variable,
|
var: Variable,
|
||||||
|
@ -4016,14 +4098,14 @@ pub fn deep_copy_var_to(
|
||||||
let copy = {
|
let copy = {
|
||||||
let visited = bumpalo::collections::Vec::with_capacity_in(256, &arena);
|
let visited = bumpalo::collections::Vec::with_capacity_in(256, &arena);
|
||||||
|
|
||||||
let mut env = DeepCopyVarToEnv {
|
let mut env = StorageCopyVarToEnv {
|
||||||
visited,
|
visited,
|
||||||
source,
|
source,
|
||||||
target,
|
target,
|
||||||
max_rank: rank,
|
max_rank: rank,
|
||||||
};
|
};
|
||||||
|
|
||||||
let copy = deep_copy_var_to_help(&mut env, var);
|
let copy = storage_copy_var_to_help(&mut env, var);
|
||||||
|
|
||||||
// we have tracked all visited variables, and can now traverse them
|
// we have tracked all visited variables, and can now traverse them
|
||||||
// in one go (without looking at the UnificationTable) and clear the copy field
|
// in one go (without looking at the UnificationTable) and clear the copy field
|
||||||
|
@ -4046,7 +4128,7 @@ pub fn deep_copy_var_to(
|
||||||
copy
|
copy
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DeepCopyVarToEnv<'a> {
|
struct StorageCopyVarToEnv<'a> {
|
||||||
visited: bumpalo::collections::Vec<'a, Variable>,
|
visited: bumpalo::collections::Vec<'a, Variable>,
|
||||||
source: &'a mut Subs,
|
source: &'a mut Subs,
|
||||||
target: &'a mut Subs,
|
target: &'a mut Subs,
|
||||||
|
@ -4054,8 +4136,8 @@ struct DeepCopyVarToEnv<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn deep_copy_union<L: Label>(
|
fn storage_copy_union<L: Label>(
|
||||||
env: &mut DeepCopyVarToEnv<'_>,
|
env: &mut StorageCopyVarToEnv<'_>,
|
||||||
tags: UnionLabels<L>,
|
tags: UnionLabels<L>,
|
||||||
) -> UnionLabels<L> {
|
) -> UnionLabels<L> {
|
||||||
let new_variable_slices = SubsSlice::reserve_variable_slices(env.target, tags.len());
|
let new_variable_slices = SubsSlice::reserve_variable_slices(env.target, tags.len());
|
||||||
|
@ -4068,7 +4150,7 @@ fn deep_copy_union<L: Label>(
|
||||||
let it = (new_variables.indices()).zip(slice);
|
let it = (new_variables.indices()).zip(slice);
|
||||||
for (target_index, var_index) in it {
|
for (target_index, var_index) in it {
|
||||||
let var = env.source[var_index];
|
let var = env.source[var_index];
|
||||||
let copy_var = deep_copy_var_to_help(env, var);
|
let copy_var = storage_copy_var_to_help(env, var);
|
||||||
env.target.variables[target_index] = copy_var;
|
env.target.variables[target_index] = copy_var;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4085,7 +4167,7 @@ fn deep_copy_union<L: Label>(
|
||||||
UnionLabels::from_slices(new_tag_names, new_variable_slices)
|
UnionLabels::from_slices(new_tag_names, new_variable_slices)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deep_copy_var_to_help(env: &mut DeepCopyVarToEnv<'_>, var: Variable) -> Variable {
|
fn storage_copy_var_to_help(env: &mut StorageCopyVarToEnv<'_>, var: Variable) -> Variable {
|
||||||
use Content::*;
|
use Content::*;
|
||||||
use FlatType::*;
|
use FlatType::*;
|
||||||
|
|
||||||
|
@ -4138,7 +4220,7 @@ fn deep_copy_var_to_help(env: &mut DeepCopyVarToEnv<'_>, var: Variable) -> Varia
|
||||||
|
|
||||||
for (target_index, var_index) in (new_arguments.indices()).zip(arguments) {
|
for (target_index, var_index) in (new_arguments.indices()).zip(arguments) {
|
||||||
let var = env.source[var_index];
|
let var = env.source[var_index];
|
||||||
let copy_var = deep_copy_var_to_help(env, var);
|
let copy_var = storage_copy_var_to_help(env, var);
|
||||||
env.target.variables[target_index] = copy_var;
|
env.target.variables[target_index] = copy_var;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4146,15 +4228,15 @@ fn deep_copy_var_to_help(env: &mut DeepCopyVarToEnv<'_>, var: Variable) -> Varia
|
||||||
}
|
}
|
||||||
|
|
||||||
Func(arguments, closure_var, ret_var) => {
|
Func(arguments, closure_var, ret_var) => {
|
||||||
let new_ret_var = deep_copy_var_to_help(env, ret_var);
|
let new_ret_var = storage_copy_var_to_help(env, ret_var);
|
||||||
|
|
||||||
let new_closure_var = deep_copy_var_to_help(env, closure_var);
|
let new_closure_var = storage_copy_var_to_help(env, closure_var);
|
||||||
|
|
||||||
let new_arguments = SubsSlice::reserve_into_subs(env.target, arguments.len());
|
let new_arguments = SubsSlice::reserve_into_subs(env.target, arguments.len());
|
||||||
|
|
||||||
for (target_index, var_index) in (new_arguments.indices()).zip(arguments) {
|
for (target_index, var_index) in (new_arguments.indices()).zip(arguments) {
|
||||||
let var = env.source[var_index];
|
let var = env.source[var_index];
|
||||||
let copy_var = deep_copy_var_to_help(env, var);
|
let copy_var = storage_copy_var_to_help(env, var);
|
||||||
env.target.variables[target_index] = copy_var;
|
env.target.variables[target_index] = copy_var;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4171,7 +4253,7 @@ fn deep_copy_var_to_help(env: &mut DeepCopyVarToEnv<'_>, var: Variable) -> Varia
|
||||||
let it = (new_variables.indices()).zip(fields.iter_variables());
|
let it = (new_variables.indices()).zip(fields.iter_variables());
|
||||||
for (target_index, var_index) in it {
|
for (target_index, var_index) in it {
|
||||||
let var = env.source[var_index];
|
let var = env.source[var_index];
|
||||||
let copy_var = deep_copy_var_to_help(env, var);
|
let copy_var = storage_copy_var_to_help(env, var);
|
||||||
env.target.variables[target_index] = copy_var;
|
env.target.variables[target_index] = copy_var;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4195,12 +4277,12 @@ fn deep_copy_var_to_help(env: &mut DeepCopyVarToEnv<'_>, var: Variable) -> Varia
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Record(record_fields, deep_copy_var_to_help(env, ext_var))
|
Record(record_fields, storage_copy_var_to_help(env, ext_var))
|
||||||
}
|
}
|
||||||
|
|
||||||
TagUnion(tags, ext_var) => {
|
TagUnion(tags, ext_var) => {
|
||||||
let new_ext = deep_copy_var_to_help(env, ext_var);
|
let new_ext = storage_copy_var_to_help(env, ext_var);
|
||||||
let union_tags = deep_copy_union(env, tags);
|
let union_tags = storage_copy_union(env, tags);
|
||||||
|
|
||||||
TagUnion(union_tags, new_ext)
|
TagUnion(union_tags, new_ext)
|
||||||
}
|
}
|
||||||
|
@ -4210,14 +4292,14 @@ fn deep_copy_var_to_help(env: &mut DeepCopyVarToEnv<'_>, var: Variable) -> Varia
|
||||||
|
|
||||||
env.target.tag_names.push(env.source[tag_name].clone());
|
env.target.tag_names.push(env.source[tag_name].clone());
|
||||||
|
|
||||||
FunctionOrTagUnion(new_tag_name, symbol, deep_copy_var_to_help(env, ext_var))
|
FunctionOrTagUnion(new_tag_name, symbol, storage_copy_var_to_help(env, ext_var))
|
||||||
}
|
}
|
||||||
|
|
||||||
RecursiveTagUnion(rec_var, tags, ext_var) => {
|
RecursiveTagUnion(rec_var, tags, ext_var) => {
|
||||||
let union_tags = deep_copy_union(env, tags);
|
let union_tags = storage_copy_union(env, tags);
|
||||||
|
|
||||||
let new_ext = deep_copy_var_to_help(env, ext_var);
|
let new_ext = storage_copy_var_to_help(env, ext_var);
|
||||||
let new_rec_var = deep_copy_var_to_help(env, rec_var);
|
let new_rec_var = storage_copy_var_to_help(env, rec_var);
|
||||||
|
|
||||||
RecursiveTagUnion(new_rec_var, union_tags, new_ext)
|
RecursiveTagUnion(new_rec_var, union_tags, new_ext)
|
||||||
}
|
}
|
||||||
|
@ -4245,7 +4327,7 @@ fn deep_copy_var_to_help(env: &mut DeepCopyVarToEnv<'_>, var: Variable) -> Varia
|
||||||
opt_name,
|
opt_name,
|
||||||
structure,
|
structure,
|
||||||
} => {
|
} => {
|
||||||
let new_structure = deep_copy_var_to_help(env, structure);
|
let new_structure = storage_copy_var_to_help(env, structure);
|
||||||
|
|
||||||
debug_assert!((new_structure.index() as usize) < env.target.len());
|
debug_assert!((new_structure.index() as usize) < env.target.len());
|
||||||
|
|
||||||
|
@ -4299,7 +4381,7 @@ fn deep_copy_var_to_help(env: &mut DeepCopyVarToEnv<'_>, var: Variable) -> Varia
|
||||||
(new_variables.indices()).zip(arguments.all_variables())
|
(new_variables.indices()).zip(arguments.all_variables())
|
||||||
{
|
{
|
||||||
let var = env.source[var_index];
|
let var = env.source[var_index];
|
||||||
let copy_var = deep_copy_var_to_help(env, var);
|
let copy_var = storage_copy_var_to_help(env, var);
|
||||||
env.target.variables[target_index] = copy_var;
|
env.target.variables[target_index] = copy_var;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4308,7 +4390,7 @@ fn deep_copy_var_to_help(env: &mut DeepCopyVarToEnv<'_>, var: Variable) -> Varia
|
||||||
..arguments
|
..arguments
|
||||||
};
|
};
|
||||||
|
|
||||||
let new_real_type_var = deep_copy_var_to_help(env, real_type_var);
|
let new_real_type_var = storage_copy_var_to_help(env, real_type_var);
|
||||||
let new_content = Alias(symbol, new_arguments, new_real_type_var, kind);
|
let new_content = Alias(symbol, new_arguments, new_real_type_var, kind);
|
||||||
|
|
||||||
env.target.set(copy, make_descriptor(new_content));
|
env.target.set(copy, make_descriptor(new_content));
|
||||||
|
@ -4319,20 +4401,33 @@ fn deep_copy_var_to_help(env: &mut DeepCopyVarToEnv<'_>, var: Variable) -> Varia
|
||||||
LambdaSet(self::LambdaSet {
|
LambdaSet(self::LambdaSet {
|
||||||
solved,
|
solved,
|
||||||
recursion_var,
|
recursion_var,
|
||||||
|
unspecialized,
|
||||||
}) => {
|
}) => {
|
||||||
let new_solved = deep_copy_union(env, solved);
|
let new_solved = storage_copy_union(env, solved);
|
||||||
let new_rec_var = recursion_var.map(|v| deep_copy_var_to_help(env, v));
|
let new_rec_var = recursion_var.map(|v| storage_copy_var_to_help(env, v));
|
||||||
|
|
||||||
|
// NB: we are only copying into storage here, not instantiating like in solve::deep_copy_var.
|
||||||
|
// So no bookkeeping should be done for the new unspecialized lambda sets.
|
||||||
|
let new_unspecialized = SubsSlice::reserve_uls_slice(env.target, unspecialized.len());
|
||||||
|
for (target_index, source_index) in
|
||||||
|
(new_unspecialized.into_iter()).zip(unspecialized.into_iter())
|
||||||
|
{
|
||||||
|
let Uls(var, sym, region) = env.source[source_index];
|
||||||
|
let new_var = storage_copy_var_to_help(env, var);
|
||||||
|
env.target[target_index] = Uls(new_var, sym, region);
|
||||||
|
}
|
||||||
|
|
||||||
let new_content = LambdaSet(self::LambdaSet {
|
let new_content = LambdaSet(self::LambdaSet {
|
||||||
solved: new_solved,
|
solved: new_solved,
|
||||||
recursion_var: new_rec_var,
|
recursion_var: new_rec_var,
|
||||||
|
unspecialized: new_unspecialized,
|
||||||
});
|
});
|
||||||
env.target.set(copy, make_descriptor(new_content));
|
env.target.set(copy, make_descriptor(new_content));
|
||||||
copy
|
copy
|
||||||
}
|
}
|
||||||
|
|
||||||
RangedNumber(typ, range) => {
|
RangedNumber(typ, range) => {
|
||||||
let new_typ = deep_copy_var_to_help(env, typ);
|
let new_typ = storage_copy_var_to_help(env, typ);
|
||||||
|
|
||||||
let new_content = RangedNumber(new_typ, range);
|
let new_content = RangedNumber(new_typ, range);
|
||||||
|
|
||||||
|
@ -4769,14 +4864,27 @@ fn copy_import_to_help(env: &mut CopyImportEnv<'_>, max_rank: Rank, var: Variabl
|
||||||
LambdaSet(self::LambdaSet {
|
LambdaSet(self::LambdaSet {
|
||||||
solved,
|
solved,
|
||||||
recursion_var,
|
recursion_var,
|
||||||
|
unspecialized,
|
||||||
}) => {
|
}) => {
|
||||||
let new_solved = copy_union(env, max_rank, solved);
|
let new_solved = copy_union(env, max_rank, solved);
|
||||||
let new_rec_var =
|
let new_rec_var =
|
||||||
recursion_var.map(|rec_var| copy_import_to_help(env, max_rank, rec_var));
|
recursion_var.map(|rec_var| copy_import_to_help(env, max_rank, rec_var));
|
||||||
|
|
||||||
|
// NB: we are only copying across subs here, not instantiating like in deep_copy_var.
|
||||||
|
// So no bookkeeping should be done for the new unspecialized lambda sets.
|
||||||
|
let new_unspecialized = SubsSlice::reserve_uls_slice(env.target, unspecialized.len());
|
||||||
|
for (target_index, source_index) in
|
||||||
|
(new_unspecialized.into_iter()).zip(unspecialized.into_iter())
|
||||||
|
{
|
||||||
|
let Uls(var, sym, region) = env.source[source_index];
|
||||||
|
let new_var = copy_import_to_help(env, max_rank, var);
|
||||||
|
env.target[target_index] = Uls(new_var, sym, region);
|
||||||
|
}
|
||||||
|
|
||||||
let new_content = LambdaSet(self::LambdaSet {
|
let new_content = LambdaSet(self::LambdaSet {
|
||||||
solved: new_solved,
|
solved: new_solved,
|
||||||
recursion_var: new_rec_var,
|
recursion_var: new_rec_var,
|
||||||
|
unspecialized: new_unspecialized,
|
||||||
});
|
});
|
||||||
|
|
||||||
env.target.set(copy, make_descriptor(new_content));
|
env.target.set(copy, make_descriptor(new_content));
|
||||||
|
|
|
@ -273,8 +273,14 @@ pub enum Type {
|
||||||
/// usage site. Unspecialized lambda sets aid us in recovering those lambda sets; when we
|
/// usage site. Unspecialized lambda sets aid us in recovering those lambda sets; when we
|
||||||
/// instantiate `a` with a proper type `T`, we'll know to resolve the lambda set by extracting
|
/// instantiate `a` with a proper type `T`, we'll know to resolve the lambda set by extracting
|
||||||
/// it at region "1" from the specialization of "default" for `T`.
|
/// it at region "1" from the specialization of "default" for `T`.
|
||||||
#[derive(PartialEq, Eq, Clone, Copy)]
|
#[derive(PartialEq, Eq, Clone, Copy, PartialOrd, Ord)]
|
||||||
pub struct Uls(Variable, Symbol, u8);
|
pub struct Uls(pub Variable, pub Symbol, pub u8);
|
||||||
|
|
||||||
|
impl std::fmt::Debug for Uls {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "Uls({:?}:{:?}:{:?})", self.0, self.1, self.2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static mut TYPE_CLONE_COUNT: std::sync::atomic::AtomicUsize =
|
static mut TYPE_CLONE_COUNT: std::sync::atomic::AtomicUsize =
|
||||||
std::sync::atomic::AtomicUsize::new(0);
|
std::sync::atomic::AtomicUsize::new(0);
|
||||||
|
@ -648,8 +654,8 @@ impl fmt::Debug for Type {
|
||||||
Type::RangedNumber(typ, range_vars) => {
|
Type::RangedNumber(typ, range_vars) => {
|
||||||
write!(f, "Ranged({:?}, {:?})", typ, range_vars)
|
write!(f, "Ranged({:?}, {:?})", typ, range_vars)
|
||||||
}
|
}
|
||||||
Type::UnspecializedLambdaSet(Uls(a, mem, region)) => {
|
Type::UnspecializedLambdaSet(uls) => {
|
||||||
write!(f, "ULS({:?}:{:?}:{:?})", a, mem, region)
|
write!(f, "{:?}", uls)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -815,10 +815,12 @@ fn unify_lambda_set_help(
|
||||||
let LambdaSet {
|
let LambdaSet {
|
||||||
solved: solved1,
|
solved: solved1,
|
||||||
recursion_var: rec1,
|
recursion_var: rec1,
|
||||||
|
unspecialized: uls1,
|
||||||
} = lset1;
|
} = lset1;
|
||||||
let LambdaSet {
|
let LambdaSet {
|
||||||
solved: solved2,
|
solved: solved2,
|
||||||
recursion_var: rec2,
|
recursion_var: rec2,
|
||||||
|
unspecialized: uls2,
|
||||||
} = lset2;
|
} = lset2;
|
||||||
|
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
|
@ -893,10 +895,30 @@ fn unify_lambda_set_help(
|
||||||
(None, None) => OptVariable::NONE,
|
(None, None) => OptVariable::NONE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Combine the unspecialized lambda sets as needed. Note that we don't need to update the
|
||||||
|
// bookkeeping of variable -> lambda set to be resolved, because if we had v1 -> lset1, and
|
||||||
|
// now lset1 ~ lset2, then afterward either lset1 still resolves to itself or re-points to
|
||||||
|
// lset2. In either case the merged unspecialized lambda sets will be there.
|
||||||
|
let merged_unspecialized = match (uls1.is_empty(), uls2.is_empty()) {
|
||||||
|
(true, true) => SubsSlice::default(),
|
||||||
|
(false, true) => uls1,
|
||||||
|
(true, false) => uls2,
|
||||||
|
(false, false) => {
|
||||||
|
let mut all_uls = (subs.get_subs_slice(uls1).iter())
|
||||||
|
.chain(subs.get_subs_slice(uls2))
|
||||||
|
.copied()
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
all_uls.sort();
|
||||||
|
all_uls.dedup();
|
||||||
|
SubsSlice::extend_new(&mut subs.unspecialized_lambda_sets, all_uls)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let new_solved = UnionLabels::insert_into_subs(subs, all_lambdas);
|
let new_solved = UnionLabels::insert_into_subs(subs, all_lambdas);
|
||||||
let new_lambda_set = Content::LambdaSet(LambdaSet {
|
let new_lambda_set = Content::LambdaSet(LambdaSet {
|
||||||
solved: new_solved,
|
solved: new_solved,
|
||||||
recursion_var,
|
recursion_var,
|
||||||
|
unspecialized: merged_unspecialized,
|
||||||
});
|
});
|
||||||
|
|
||||||
merge(subs, ctx, new_lambda_set)
|
merge(subs, ctx, new_lambda_set)
|
||||||
|
@ -1523,8 +1545,9 @@ fn maybe_mark_union_recursive(subs: &mut Subs, union_var: Variable) {
|
||||||
LambdaSet(self::LambdaSet {
|
LambdaSet(self::LambdaSet {
|
||||||
solved,
|
solved,
|
||||||
recursion_var: OptVariable::NONE,
|
recursion_var: OptVariable::NONE,
|
||||||
|
unspecialized,
|
||||||
}) => {
|
}) => {
|
||||||
subs.mark_lambda_set_recursive(v, solved);
|
subs.mark_lambda_set_recursive(v, solved, unspecialized);
|
||||||
continue 'outer;
|
continue 'outer;
|
||||||
}
|
}
|
||||||
_ => { /* fall through */ }
|
_ => { /* fall through */ }
|
||||||
|
@ -2246,6 +2269,7 @@ fn unify_function_or_tag_union_and_func(
|
||||||
let lambda_set_content = LambdaSet(self::LambdaSet {
|
let lambda_set_content = LambdaSet(self::LambdaSet {
|
||||||
solved: union_tags,
|
solved: union_tags,
|
||||||
recursion_var: OptVariable::NONE,
|
recursion_var: OptVariable::NONE,
|
||||||
|
unspecialized: SubsSlice::default(),
|
||||||
});
|
});
|
||||||
|
|
||||||
let tag_lambda_set = register(
|
let tag_lambda_set = register(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue