mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 13:29:12 +00:00
Shove more into a common env
This commit is contained in:
parent
b5ea2c2c99
commit
ad20a2ee41
10 changed files with 565 additions and 623 deletions
|
@ -64,6 +64,26 @@ pub type PExpectedTypeIndex = Index<PExpected<TypeOrVar>>;
|
||||||
pub type TypeOrVar = EitherIndex<TypeTag, Variable>;
|
pub type TypeOrVar = EitherIndex<TypeTag, Variable>;
|
||||||
|
|
||||||
impl Constraints {
|
impl Constraints {
|
||||||
|
pub fn empty() -> Self {
|
||||||
|
Self {
|
||||||
|
constraints: Default::default(),
|
||||||
|
type_slices: Default::default(),
|
||||||
|
variables: Default::default(),
|
||||||
|
loc_symbols: Default::default(),
|
||||||
|
let_constraints: Default::default(),
|
||||||
|
categories: Default::default(),
|
||||||
|
pattern_categories: Default::default(),
|
||||||
|
expectations: Default::default(),
|
||||||
|
pattern_expectations: Default::default(),
|
||||||
|
includes_tags: Default::default(),
|
||||||
|
strings: Default::default(),
|
||||||
|
sketched_rows: Default::default(),
|
||||||
|
eq: Default::default(),
|
||||||
|
pattern_eq: Default::default(),
|
||||||
|
cycles: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let constraints = Vec::new();
|
let constraints = Vec::new();
|
||||||
let type_slices = Vec::with_capacity(16);
|
let type_slices = Vec::with_capacity(16);
|
||||||
|
|
|
@ -5,6 +5,7 @@ use std::sync::{Arc, RwLock};
|
||||||
|
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use roc_can::abilities::AbilitiesStore;
|
use roc_can::abilities::AbilitiesStore;
|
||||||
|
use roc_can::constraint::Constraints;
|
||||||
use roc_can::module::ExposedByModule;
|
use roc_can::module::ExposedByModule;
|
||||||
use roc_collections::MutMap;
|
use roc_collections::MutMap;
|
||||||
use roc_derive::SharedDerivedModule;
|
use roc_derive::SharedDerivedModule;
|
||||||
|
@ -12,13 +13,14 @@ use roc_error_macros::internal_error;
|
||||||
use roc_module::symbol::ModuleId;
|
use roc_module::symbol::ModuleId;
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::Symbol;
|
||||||
use roc_solve::ability::AbilityResolver;
|
use roc_solve::ability::AbilityResolver;
|
||||||
use roc_solve::specialize::{compact_lambda_sets_of_vars, DerivedEnv, Phase};
|
use roc_solve::specialize::{compact_lambda_sets_of_vars, Phase};
|
||||||
use roc_solve::Pools;
|
use roc_solve::Pools;
|
||||||
|
use roc_solve::{DerivedEnv, Env};
|
||||||
use roc_types::subs::{get_member_lambda_sets_at_region, Content, FlatType, LambdaSet};
|
use roc_types::subs::{get_member_lambda_sets_at_region, Content, FlatType, LambdaSet};
|
||||||
use roc_types::subs::{ExposedTypesStorageSubs, Subs, Variable};
|
use roc_types::subs::{ExposedTypesStorageSubs, Subs, Variable};
|
||||||
use roc_types::types::Polarity;
|
use roc_types::types::Polarity;
|
||||||
use roc_unify::unify::MetaCollector;
|
use roc_unify::unify::MetaCollector;
|
||||||
use roc_unify::unify::{Env, Mode, Unified};
|
use roc_unify::unify::{Env as UEnv, Mode, Unified};
|
||||||
|
|
||||||
pub use roc_solve::ability::{ResolveError, Resolved};
|
pub use roc_solve::ability::{ResolveError, Resolved};
|
||||||
pub use roc_types::subs::instantiate_rigids;
|
pub use roc_types::subs::instantiate_rigids;
|
||||||
|
@ -340,6 +342,19 @@ impl MetaCollector for ChangedVariableCollector {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::thread_local! {
|
||||||
|
static SCRATCHPAD_FOR_OCCURS: std::cell::RefCell<Option<Constraints>> = std::cell::RefCell::new(Some(Constraints::empty()));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with_empty_solve_constraints<T>(f: impl FnOnce(&Constraints) -> T) -> T {
|
||||||
|
SCRATCHPAD_FOR_OCCURS.with(|cell| {
|
||||||
|
let constr = cell.take().unwrap();
|
||||||
|
let result = f(&constr);
|
||||||
|
cell.replace(Some(constr));
|
||||||
|
result
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Unifies two variables and performs lambda set compaction.
|
/// Unifies two variables and performs lambda set compaction.
|
||||||
/// Ranks and other ability demands are disregarded.
|
/// Ranks and other ability demands are disregarded.
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
@ -359,7 +374,7 @@ pub fn unify(
|
||||||
"derived module can only unify its subs in its own context!"
|
"derived module can only unify its subs in its own context!"
|
||||||
);
|
);
|
||||||
let unified = roc_unify::unify::unify_with_collector::<ChangedVariableCollector>(
|
let unified = roc_unify::unify::unify_with_collector::<ChangedVariableCollector>(
|
||||||
&mut Env::new(subs),
|
&mut UEnv::new(subs),
|
||||||
left,
|
left,
|
||||||
right,
|
right,
|
||||||
Mode::EQ,
|
Mode::EQ,
|
||||||
|
@ -381,14 +396,17 @@ pub fn unify(
|
||||||
exposed_types: exposed_by_module,
|
exposed_types: exposed_by_module,
|
||||||
};
|
};
|
||||||
|
|
||||||
let must_implement_constraints = compact_lambda_sets_of_vars(
|
let must_implement_constraints = with_empty_solve_constraints(|c| {
|
||||||
|
let mut env = Env {
|
||||||
|
constraints: c,
|
||||||
subs,
|
subs,
|
||||||
&derived_env,
|
derived_env: &derived_env,
|
||||||
arena,
|
arena,
|
||||||
&mut pools,
|
pools: &mut pools,
|
||||||
lambda_sets_to_specialize,
|
};
|
||||||
&late_phase,
|
|
||||||
);
|
compact_lambda_sets_of_vars(&mut env, lambda_sets_to_specialize, &late_phase)
|
||||||
|
});
|
||||||
// At this point we can't do anything with must-implement constraints, since we're no
|
// At this point we can't do anything with must-implement constraints, since we're no
|
||||||
// longer solving. We must assume that they were totally caught during solving.
|
// longer solving. We must assume that they were totally caught during solving.
|
||||||
// After we land https://github.com/roc-lang/roc/issues/3207 this concern should totally
|
// After we land https://github.com/roc-lang/roc/issues/3207 this concern should totally
|
||||||
|
|
|
@ -18,10 +18,11 @@ use roc_types::subs::{
|
||||||
TupleElems, Variable,
|
TupleElems, Variable,
|
||||||
};
|
};
|
||||||
use roc_types::types::{AliasKind, Category, MemberImpl, PatternCategory, Polarity, Types};
|
use roc_types::types::{AliasKind, Category, MemberImpl, PatternCategory, Polarity, Types};
|
||||||
use roc_unify::unify::{Env, MustImplementConstraints};
|
use roc_unify::unify::{Env as UEnv, MustImplementConstraints};
|
||||||
use roc_unify::unify::{MustImplementAbility, Obligated};
|
use roc_unify::unify::{MustImplementAbility, Obligated};
|
||||||
|
|
||||||
use crate::{aliases::Aliases, pools::Pools, to_var::type_to_var};
|
use crate::env::Env;
|
||||||
|
use crate::{aliases::Aliases, to_var::type_to_var};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum AbilityImplError {
|
pub enum AbilityImplError {
|
||||||
|
@ -55,7 +56,7 @@ pub struct PendingDerivesTable(
|
||||||
|
|
||||||
impl PendingDerivesTable {
|
impl PendingDerivesTable {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
subs: &mut Subs,
|
env: &mut Env,
|
||||||
types: &mut Types,
|
types: &mut Types,
|
||||||
aliases: &mut Aliases,
|
aliases: &mut Aliases,
|
||||||
pending_derives: PendingDerives,
|
pending_derives: PendingDerives,
|
||||||
|
@ -80,17 +81,16 @@ impl PendingDerivesTable {
|
||||||
// Neither rank nor pools should matter here.
|
// Neither rank nor pools should matter here.
|
||||||
let typ = types.from_old_type(&typ);
|
let typ = types.from_old_type(&typ);
|
||||||
let opaque_var = type_to_var(
|
let opaque_var = type_to_var(
|
||||||
subs,
|
env,
|
||||||
Rank::toplevel(),
|
Rank::toplevel(),
|
||||||
problems,
|
problems,
|
||||||
abilities_store,
|
abilities_store,
|
||||||
obligation_cache,
|
obligation_cache,
|
||||||
&mut Pools::default(),
|
|
||||||
types,
|
types,
|
||||||
aliases,
|
aliases,
|
||||||
typ,
|
typ,
|
||||||
);
|
);
|
||||||
let real_var = match subs.get_content_without_compacting(opaque_var) {
|
let real_var = match env.subs.get_content_without_compacting(opaque_var) {
|
||||||
Content::Alias(_, _, real_var, AliasKind::Opaque) => real_var,
|
Content::Alias(_, _, real_var, AliasKind::Opaque) => real_var,
|
||||||
_ => internal_error!("Non-opaque in derives table"),
|
_ => internal_error!("Non-opaque in derives table"),
|
||||||
};
|
};
|
||||||
|
@ -1283,7 +1283,7 @@ impl DerivableVisitor for DeriveEq {
|
||||||
|
|
||||||
// Of the floating-point types,
|
// Of the floating-point types,
|
||||||
// only Dec implements Eq.
|
// only Dec implements Eq.
|
||||||
let mut env = Env::new(subs);
|
let mut env = UEnv::new(subs);
|
||||||
let unified = unify(
|
let unified = unify(
|
||||||
&mut env,
|
&mut env,
|
||||||
content_var,
|
content_var,
|
||||||
|
@ -1418,7 +1418,7 @@ pub fn resolve_ability_specialization<R: AbilityResolver>(
|
||||||
|
|
||||||
instantiate_rigids(subs, signature_var);
|
instantiate_rigids(subs, signature_var);
|
||||||
let (_vars, must_implement_ability, _lambda_sets_to_specialize, _meta) = unify(
|
let (_vars, must_implement_ability, _lambda_sets_to_specialize, _meta) = unify(
|
||||||
&mut Env::new(subs),
|
&mut UEnv::new(subs),
|
||||||
specialization_var,
|
specialization_var,
|
||||||
signature_var,
|
signature_var,
|
||||||
Mode::EQ,
|
Mode::EQ,
|
||||||
|
|
|
@ -8,10 +8,8 @@ use roc_types::{
|
||||||
types::{Alias, AliasKind, OptAbleVar, Type, TypeTag, Types},
|
types::{Alias, AliasKind, OptAbleVar, Type, TypeTag, Types},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::ability::ObligationCache;
|
|
||||||
use crate::pools::Pools;
|
|
||||||
use crate::solve::register;
|
|
||||||
use crate::to_var::type_to_var_help;
|
use crate::to_var::type_to_var_help;
|
||||||
|
use crate::{ability::ObligationCache, env::Env};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
struct DelayedAliasVariables {
|
struct DelayedAliasVariables {
|
||||||
|
@ -123,9 +121,8 @@ impl Aliases {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn instantiate_result_result(
|
fn instantiate_result_result(
|
||||||
subs: &mut Subs,
|
env: &mut Env,
|
||||||
rank: Rank,
|
rank: Rank,
|
||||||
pools: &mut Pools,
|
|
||||||
alias_variables: AliasVariables,
|
alias_variables: AliasVariables,
|
||||||
) -> Variable {
|
) -> Variable {
|
||||||
let tag_names_slice = Subs::RESULT_TAG_NAMES;
|
let tag_names_slice = Subs::RESULT_TAG_NAMES;
|
||||||
|
@ -134,51 +131,49 @@ impl Aliases {
|
||||||
let ok_slice = SubsSlice::new(alias_variables.variables_start, 1);
|
let ok_slice = SubsSlice::new(alias_variables.variables_start, 1);
|
||||||
|
|
||||||
let variable_slices =
|
let variable_slices =
|
||||||
SubsSlice::extend_new(&mut subs.variable_slices, [err_slice, ok_slice]);
|
SubsSlice::extend_new(&mut env.subs.variable_slices, [err_slice, ok_slice]);
|
||||||
|
|
||||||
let union_tags = UnionTags::from_slices(tag_names_slice, variable_slices);
|
let union_tags = UnionTags::from_slices(tag_names_slice, variable_slices);
|
||||||
let ext_var = TagExt::Any(Variable::EMPTY_TAG_UNION);
|
let ext_var = TagExt::Any(Variable::EMPTY_TAG_UNION);
|
||||||
let flat_type = FlatType::TagUnion(union_tags, ext_var);
|
let flat_type = FlatType::TagUnion(union_tags, ext_var);
|
||||||
let content = Content::Structure(flat_type);
|
let content = Content::Structure(flat_type);
|
||||||
|
|
||||||
register(subs, rank, pools, content)
|
env.register(rank, content)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build an alias of the form `Num range := range`
|
/// Build an alias of the form `Num range := range`
|
||||||
fn build_num_opaque(
|
fn build_num_opaque(
|
||||||
subs: &mut Subs,
|
env: &mut Env,
|
||||||
rank: Rank,
|
rank: Rank,
|
||||||
pools: &mut Pools,
|
|
||||||
symbol: Symbol,
|
symbol: Symbol,
|
||||||
range_var: Variable,
|
range_var: Variable,
|
||||||
) -> Variable {
|
) -> Variable {
|
||||||
let content = Content::Alias(
|
let content = Content::Alias(
|
||||||
symbol,
|
symbol,
|
||||||
AliasVariables::insert_into_subs(subs, [range_var], [], []),
|
AliasVariables::insert_into_subs(env.subs, [range_var], [], []),
|
||||||
range_var,
|
range_var,
|
||||||
AliasKind::Opaque,
|
AliasKind::Opaque,
|
||||||
);
|
);
|
||||||
|
|
||||||
register(subs, rank, pools, content)
|
env.register(rank, content)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn instantiate_builtin_aliases_real_var(
|
fn instantiate_builtin_aliases_real_var(
|
||||||
&mut self,
|
&mut self,
|
||||||
subs: &mut Subs,
|
env: &mut Env,
|
||||||
rank: Rank,
|
rank: Rank,
|
||||||
pools: &mut Pools,
|
|
||||||
symbol: Symbol,
|
symbol: Symbol,
|
||||||
alias_variables: AliasVariables,
|
alias_variables: AliasVariables,
|
||||||
) -> Option<(Variable, AliasKind)> {
|
) -> Option<(Variable, AliasKind)> {
|
||||||
match symbol {
|
match symbol {
|
||||||
Symbol::RESULT_RESULT => {
|
Symbol::RESULT_RESULT => {
|
||||||
let var = Self::instantiate_result_result(subs, rank, pools, alias_variables);
|
let var = Self::instantiate_result_result(env, rank, alias_variables);
|
||||||
|
|
||||||
Some((var, AliasKind::Structural))
|
Some((var, AliasKind::Structural))
|
||||||
}
|
}
|
||||||
Symbol::NUM_NUM | Symbol::NUM_INTEGER | Symbol::NUM_FLOATINGPOINT => {
|
Symbol::NUM_NUM | Symbol::NUM_INTEGER | Symbol::NUM_FLOATINGPOINT => {
|
||||||
// Num range := range | Integer range := range | FloatingPoint range := range
|
// Num range := range | Integer range := range | FloatingPoint range := range
|
||||||
let range_var = subs.variables[alias_variables.variables_start as usize];
|
let range_var = env.subs.variables[alias_variables.variables_start as usize];
|
||||||
Some((range_var, AliasKind::Opaque))
|
Some((range_var, AliasKind::Opaque))
|
||||||
}
|
}
|
||||||
Symbol::NUM_INT => {
|
Symbol::NUM_INT => {
|
||||||
|
@ -186,16 +181,15 @@ impl Aliases {
|
||||||
//
|
//
|
||||||
// build `Integer range := range`
|
// build `Integer range := range`
|
||||||
let integer_content_var = Self::build_num_opaque(
|
let integer_content_var = Self::build_num_opaque(
|
||||||
subs,
|
env,
|
||||||
rank,
|
rank,
|
||||||
pools,
|
|
||||||
Symbol::NUM_INTEGER,
|
Symbol::NUM_INTEGER,
|
||||||
subs.variables[alias_variables.variables_start as usize],
|
env.subs.variables[alias_variables.variables_start as usize],
|
||||||
);
|
);
|
||||||
|
|
||||||
// build `Num (Integer range) := Integer range`
|
// build `Num (Integer range) := Integer range`
|
||||||
let num_content_var =
|
let num_content_var =
|
||||||
Self::build_num_opaque(subs, rank, pools, Symbol::NUM_NUM, integer_content_var);
|
Self::build_num_opaque(env, rank, Symbol::NUM_NUM, integer_content_var);
|
||||||
|
|
||||||
Some((num_content_var, AliasKind::Structural))
|
Some((num_content_var, AliasKind::Structural))
|
||||||
}
|
}
|
||||||
|
@ -204,16 +198,15 @@ impl Aliases {
|
||||||
//
|
//
|
||||||
// build `FloatingPoint range := range`
|
// build `FloatingPoint range := range`
|
||||||
let fpoint_content_var = Self::build_num_opaque(
|
let fpoint_content_var = Self::build_num_opaque(
|
||||||
subs,
|
env,
|
||||||
rank,
|
rank,
|
||||||
pools,
|
|
||||||
Symbol::NUM_FLOATINGPOINT,
|
Symbol::NUM_FLOATINGPOINT,
|
||||||
subs.variables[alias_variables.variables_start as usize],
|
env.subs.variables[alias_variables.variables_start as usize],
|
||||||
);
|
);
|
||||||
|
|
||||||
// build `Num (FloatingPoint range) := FloatingPoint range`
|
// build `Num (FloatingPoint range) := FloatingPoint range`
|
||||||
let num_content_var =
|
let num_content_var =
|
||||||
Self::build_num_opaque(subs, rank, pools, Symbol::NUM_NUM, fpoint_content_var);
|
Self::build_num_opaque(env, rank, Symbol::NUM_NUM, fpoint_content_var);
|
||||||
|
|
||||||
Some((num_content_var, AliasKind::Structural))
|
Some((num_content_var, AliasKind::Structural))
|
||||||
}
|
}
|
||||||
|
@ -235,9 +228,8 @@ impl Aliases {
|
||||||
|
|
||||||
pub fn instantiate_real_var(
|
pub fn instantiate_real_var(
|
||||||
&mut self,
|
&mut self,
|
||||||
subs: &mut Subs,
|
env: &mut Env,
|
||||||
rank: Rank,
|
rank: Rank,
|
||||||
pools: &mut Pools,
|
|
||||||
problems: &mut Vec<TypeError>,
|
problems: &mut Vec<TypeError>,
|
||||||
abilities_store: &AbilitiesStore,
|
abilities_store: &AbilitiesStore,
|
||||||
obligation_cache: &mut ObligationCache,
|
obligation_cache: &mut ObligationCache,
|
||||||
|
@ -247,14 +239,9 @@ impl Aliases {
|
||||||
alias_variables: AliasVariables,
|
alias_variables: AliasVariables,
|
||||||
) -> (Variable, AliasKind) {
|
) -> (Variable, AliasKind) {
|
||||||
// hardcoded instantiations for builtin aliases
|
// hardcoded instantiations for builtin aliases
|
||||||
if let Some((var, kind)) = Self::instantiate_builtin_aliases_real_var(
|
if let Some((var, kind)) =
|
||||||
self,
|
self.instantiate_builtin_aliases_real_var(env, rank, symbol, alias_variables)
|
||||||
subs,
|
{
|
||||||
rank,
|
|
||||||
pools,
|
|
||||||
symbol,
|
|
||||||
alias_variables,
|
|
||||||
) {
|
|
||||||
return (var, kind);
|
return (var, kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -271,7 +258,7 @@ impl Aliases {
|
||||||
let mut substitutions: MutMap<_, _> = Default::default();
|
let mut substitutions: MutMap<_, _> = Default::default();
|
||||||
|
|
||||||
let old_type_variables = delayed_variables.type_variables(&mut self.variables);
|
let old_type_variables = delayed_variables.type_variables(&mut self.variables);
|
||||||
let new_type_variables = &subs.variables[alias_variables.type_variables().indices()];
|
let new_type_variables = &env.subs.variables[alias_variables.type_variables().indices()];
|
||||||
|
|
||||||
for (old, new) in old_type_variables.iter_mut().zip(new_type_variables) {
|
for (old, new) in old_type_variables.iter_mut().zip(new_type_variables) {
|
||||||
// if constraint gen duplicated a type these variables could be the same
|
// if constraint gen duplicated a type these variables could be the same
|
||||||
|
@ -289,13 +276,13 @@ impl Aliases {
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
{
|
{
|
||||||
debug_assert!(opt_abilities.is_none());
|
debug_assert!(opt_abilities.is_none());
|
||||||
let new_var = subs.fresh_unnamed_flex_var();
|
let new_var = env.subs.fresh_unnamed_flex_var();
|
||||||
substitutions.insert(*rec_var, new_var);
|
substitutions.insert(*rec_var, new_var);
|
||||||
}
|
}
|
||||||
|
|
||||||
let old_lambda_set_variables = delayed_variables.lambda_set_variables(&mut self.variables);
|
let old_lambda_set_variables = delayed_variables.lambda_set_variables(&mut self.variables);
|
||||||
let new_lambda_set_variables =
|
let new_lambda_set_variables =
|
||||||
&subs.variables[alias_variables.lambda_set_variables().indices()];
|
&env.subs.variables[alias_variables.lambda_set_variables().indices()];
|
||||||
|
|
||||||
for (old, new) in old_lambda_set_variables
|
for (old, new) in old_lambda_set_variables
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
|
@ -310,7 +297,7 @@ impl Aliases {
|
||||||
let old_infer_ext_vars =
|
let old_infer_ext_vars =
|
||||||
delayed_variables.infer_ext_in_output_variables(&mut self.variables);
|
delayed_variables.infer_ext_in_output_variables(&mut self.variables);
|
||||||
let new_infer_ext_vars =
|
let new_infer_ext_vars =
|
||||||
&subs.variables[alias_variables.infer_ext_in_output_variables().indices()];
|
&env.subs.variables[alias_variables.infer_ext_in_output_variables().indices()];
|
||||||
|
|
||||||
for (old, new) in old_infer_ext_vars.iter_mut().zip(new_infer_ext_vars) {
|
for (old, new) in old_infer_ext_vars.iter_mut().zip(new_infer_ext_vars) {
|
||||||
debug_assert!(old.opt_abilities.is_none());
|
debug_assert!(old.opt_abilities.is_none());
|
||||||
|
@ -326,9 +313,8 @@ impl Aliases {
|
||||||
};
|
};
|
||||||
|
|
||||||
let alias_variable = type_to_var_help(
|
let alias_variable = type_to_var_help(
|
||||||
subs,
|
env,
|
||||||
rank,
|
rank,
|
||||||
pools,
|
|
||||||
problems,
|
problems,
|
||||||
abilities_store,
|
abilities_store,
|
||||||
obligation_cache,
|
obligation_cache,
|
||||||
|
|
|
@ -10,29 +10,23 @@ use roc_types::{
|
||||||
types::{RecordField, Uls},
|
types::{RecordField, Uls},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::pools::Pools;
|
use crate::env::Env;
|
||||||
|
|
||||||
pub(crate) fn deep_copy_var_in(
|
pub(crate) fn deep_copy_var_in(env: &mut Env, rank: Rank, var: Variable, arena: &Bump) -> Variable {
|
||||||
subs: &mut Subs,
|
|
||||||
rank: Rank,
|
|
||||||
pools: &mut Pools,
|
|
||||||
var: Variable,
|
|
||||||
arena: &Bump,
|
|
||||||
) -> Variable {
|
|
||||||
let mut visited = bumpalo::collections::Vec::with_capacity_in(256, arena);
|
let mut visited = bumpalo::collections::Vec::with_capacity_in(256, arena);
|
||||||
|
|
||||||
let pool = pools.get_mut(rank);
|
let pool = env.pools.get_mut(rank);
|
||||||
|
|
||||||
let var = subs.get_root_key(var);
|
let var = env.subs.get_root_key(var);
|
||||||
match deep_copy_var_decision(subs, rank, var) {
|
match deep_copy_var_decision(env.subs, rank, var) {
|
||||||
ControlFlow::Break(copy) => copy,
|
ControlFlow::Break(copy) => copy,
|
||||||
ControlFlow::Continue(copy) => {
|
ControlFlow::Continue(copy) => {
|
||||||
deep_copy_var_help(subs, rank, pool, &mut visited, var, copy);
|
deep_copy_var_help(env.subs, rank, pool, &mut visited, var, copy);
|
||||||
|
|
||||||
// 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
|
||||||
for var in visited {
|
for var in visited {
|
||||||
subs.set_copy_unchecked(var, OptVariable::NONE);
|
env.subs.set_copy_unchecked(var, OptVariable::NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
copy
|
copy
|
||||||
|
|
75
crates/compiler/solve/src/env.rs
Normal file
75
crates/compiler/solve/src/env.rs
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
use bumpalo::Bump;
|
||||||
|
use roc_can::{constraint::Constraints, module::ExposedByModule};
|
||||||
|
use roc_derive::SharedDerivedModule;
|
||||||
|
use roc_types::subs::{Content, Descriptor, Mark, OptVariable, Rank, Subs, Variable};
|
||||||
|
|
||||||
|
use crate::Pools;
|
||||||
|
|
||||||
|
pub struct DerivedEnv<'a> {
|
||||||
|
pub derived_module: &'a SharedDerivedModule,
|
||||||
|
/// Exposed types needed by the derived module.
|
||||||
|
pub exposed_types: &'a ExposedByModule,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Env<'a> {
|
||||||
|
pub arena: &'a Bump,
|
||||||
|
pub constraints: &'a Constraints,
|
||||||
|
pub derived_env: &'a DerivedEnv<'a>,
|
||||||
|
pub subs: &'a mut Subs,
|
||||||
|
pub pools: &'a mut Pools,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Env<'a> {
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn register(&mut self, rank: Rank, content: Content) -> Variable {
|
||||||
|
let descriptor = Descriptor {
|
||||||
|
content,
|
||||||
|
rank,
|
||||||
|
mark: Mark::NONE,
|
||||||
|
copy: OptVariable::NONE,
|
||||||
|
};
|
||||||
|
|
||||||
|
let var = self.subs.fresh(descriptor);
|
||||||
|
|
||||||
|
self.pools.get_mut(rank).push(var);
|
||||||
|
|
||||||
|
var
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Introduce some variables to Pools at the given rank.
|
||||||
|
/// Also, set each of their ranks in Subs to be the given rank.
|
||||||
|
pub fn introduce(&mut self, rank: Rank, vars: &[Variable]) {
|
||||||
|
let pool: &mut Vec<Variable> = self.pools.get_mut(rank);
|
||||||
|
|
||||||
|
for &var in vars.iter() {
|
||||||
|
self.subs.set_rank(var, rank);
|
||||||
|
}
|
||||||
|
|
||||||
|
pool.extend(vars);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn register_existing_var(&mut self, var: Variable) {
|
||||||
|
self.pools.get_mut(self.subs.get_rank(var)).push(var);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn register_with_known_var(
|
||||||
|
&mut self,
|
||||||
|
var: Variable,
|
||||||
|
rank: Rank,
|
||||||
|
content: Content,
|
||||||
|
) -> Variable {
|
||||||
|
let descriptor = Descriptor {
|
||||||
|
content,
|
||||||
|
rank,
|
||||||
|
mark: Mark::NONE,
|
||||||
|
copy: OptVariable::NONE,
|
||||||
|
};
|
||||||
|
|
||||||
|
self.subs.set(var, descriptor);
|
||||||
|
|
||||||
|
self.pools.get_mut(rank).push(var);
|
||||||
|
|
||||||
|
var
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,8 +11,10 @@ pub mod specialize;
|
||||||
|
|
||||||
mod aliases;
|
mod aliases;
|
||||||
mod deep_copy;
|
mod deep_copy;
|
||||||
|
mod env;
|
||||||
mod pools;
|
mod pools;
|
||||||
mod to_var;
|
mod to_var;
|
||||||
|
|
||||||
pub use aliases::Aliases;
|
pub use aliases::Aliases;
|
||||||
|
pub use env::{DerivedEnv, Env};
|
||||||
pub use pools::Pools;
|
pub use pools::Pools;
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -2,16 +2,11 @@
|
||||||
|
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
use bumpalo::Bump;
|
use roc_can::abilities::{AbilitiesStore, ImplKey};
|
||||||
use roc_can::{
|
|
||||||
abilities::{AbilitiesStore, ImplKey},
|
|
||||||
module::ExposedByModule,
|
|
||||||
};
|
|
||||||
use roc_collections::{VecMap, VecSet};
|
use roc_collections::{VecMap, VecSet};
|
||||||
use roc_debug_flags::dbg_do;
|
use roc_debug_flags::dbg_do;
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
use roc_debug_flags::ROC_TRACE_COMPACTION;
|
use roc_debug_flags::ROC_TRACE_COMPACTION;
|
||||||
use roc_derive::SharedDerivedModule;
|
|
||||||
use roc_derive_key::{DeriveError, DeriveKey};
|
use roc_derive_key::{DeriveError, DeriveKey};
|
||||||
use roc_error_macros::{internal_error, todo_abilities};
|
use roc_error_macros::{internal_error, todo_abilities};
|
||||||
use roc_module::symbol::{ModuleId, Symbol};
|
use roc_module::symbol::{ModuleId, Symbol};
|
||||||
|
@ -25,8 +20,9 @@ use roc_types::{
|
||||||
use roc_unify::unify::{unify, Env as UEnv, Mode, MustImplementConstraints};
|
use roc_unify::unify::{unify, Env as UEnv, Mode, MustImplementConstraints};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ability::builtin_module_with_unlisted_ability_impl, deep_copy::deep_copy_var_in, pools::Pools,
|
ability::builtin_module_with_unlisted_ability_impl,
|
||||||
solve::introduce,
|
deep_copy::deep_copy_var_in,
|
||||||
|
env::{DerivedEnv, Env},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// What phase in the compiler is reaching out to specialize lambda sets?
|
/// What phase in the compiler is reaching out to specialize lambda sets?
|
||||||
|
@ -121,12 +117,6 @@ impl Phase for SolvePhase<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DerivedEnv<'a> {
|
|
||||||
pub derived_module: &'a SharedDerivedModule,
|
|
||||||
/// Exposed types needed by the derived module.
|
|
||||||
pub exposed_types: &'a ExposedByModule,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct AwaitingSpecializations {
|
pub struct AwaitingSpecializations {
|
||||||
// What variables' specialized lambda sets in `uls_of_var` will be unlocked for specialization
|
// What variables' specialized lambda sets in `uls_of_var` will be unlocked for specialization
|
||||||
|
@ -305,10 +295,7 @@ fn unique_unspecialized_lambda(subs: &Subs, c_a: Variable, uls: &[Uls]) -> Optio
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn compact_lambda_sets_of_vars<P: Phase>(
|
pub fn compact_lambda_sets_of_vars<P: Phase>(
|
||||||
subs: &mut Subs,
|
env: &mut Env,
|
||||||
derived_env: &DerivedEnv,
|
|
||||||
arena: &Bump,
|
|
||||||
pools: &mut Pools,
|
|
||||||
uls_of_var: UlsOfVar,
|
uls_of_var: UlsOfVar,
|
||||||
phase: &P,
|
phase: &P,
|
||||||
) -> CompactionResult {
|
) -> CompactionResult {
|
||||||
|
@ -320,7 +307,7 @@ pub fn compact_lambda_sets_of_vars<P: Phase>(
|
||||||
|
|
||||||
// Suppose a type variable `a` with `uls_of_var` mapping `uls_a = {l1, ... ln}` has been instantiated to a concrete type `C_a`.
|
// Suppose a type variable `a` with `uls_of_var` mapping `uls_a = {l1, ... ln}` has been instantiated to a concrete type `C_a`.
|
||||||
while let Some((c_a, uls_a)) = uls_of_var_queue.pop_front() {
|
while let Some((c_a, uls_a)) = uls_of_var_queue.pop_front() {
|
||||||
let c_a = subs.get_root_key_without_compacting(c_a);
|
let c_a = env.subs.get_root_key_without_compacting(c_a);
|
||||||
// 1. Let each `l` in `uls_a` be of form `[solved_lambdas + ... + C:f:r + ...]`.
|
// 1. Let each `l` in `uls_a` be of form `[solved_lambdas + ... + C:f:r + ...]`.
|
||||||
// NB: There may be multiple unspecialized lambdas of form `C:f:r, C:f1:r1, ..., C:fn:rn` in `l`.
|
// NB: There may be multiple unspecialized lambdas of form `C:f:r, C:f1:r1, ..., C:fn:rn` in `l`.
|
||||||
// In this case, let `t1, ... tm` be the other unspecialized lambdas not of form `C:_:_`,
|
// In this case, let `t1, ... tm` be the other unspecialized lambdas not of form `C:_:_`,
|
||||||
|
@ -332,13 +319,13 @@ pub fn compact_lambda_sets_of_vars<P: Phase>(
|
||||||
let mut uls = uls_a.into_vec();
|
let mut uls = uls_a.into_vec();
|
||||||
|
|
||||||
// De-duplicate lambdas by root key.
|
// De-duplicate lambdas by root key.
|
||||||
uls.iter_mut().for_each(|v| *v = subs.get_root_key(*v));
|
uls.iter_mut().for_each(|v| *v = env.subs.get_root_key(*v));
|
||||||
uls.sort();
|
uls.sort();
|
||||||
uls.dedup();
|
uls.dedup();
|
||||||
uls
|
uls
|
||||||
};
|
};
|
||||||
|
|
||||||
trace_compact!(1. subs, c_a, &uls_a);
|
trace_compact!(1. env.subs, c_a, &uls_a);
|
||||||
|
|
||||||
// The flattening step - remove lambda sets that don't reference the concrete var, and for
|
// The flattening step - remove lambda sets that don't reference the concrete var, and for
|
||||||
// flatten lambda sets that reference it more than once.
|
// flatten lambda sets that reference it more than once.
|
||||||
|
@ -350,15 +337,15 @@ pub fn compact_lambda_sets_of_vars<P: Phase>(
|
||||||
recursion_var,
|
recursion_var,
|
||||||
unspecialized,
|
unspecialized,
|
||||||
ambient_function,
|
ambient_function,
|
||||||
} = subs.get_lambda_set(lambda_set);
|
} = env.subs.get_lambda_set(lambda_set);
|
||||||
let lambda_set_rank = subs.get_rank(lambda_set);
|
let lambda_set_rank = env.subs.get_rank(lambda_set);
|
||||||
let unspecialized = subs.get_subs_slice(unspecialized);
|
let unspecialized = env.subs.get_subs_slice(unspecialized);
|
||||||
// TODO: is it faster to traverse once, see if we only have one concrete lambda, and
|
// TODO: is it faster to traverse once, see if we only have one concrete lambda, and
|
||||||
// bail in that happy-path, rather than always splitting?
|
// bail in that happy-path, rather than always splitting?
|
||||||
let (concrete, mut not_concrete): (Vec<_>, Vec<_>) = unspecialized
|
let (concrete, mut not_concrete): (Vec<_>, Vec<_>) = unspecialized
|
||||||
.iter()
|
.iter()
|
||||||
.copied()
|
.copied()
|
||||||
.partition(|Uls(var, _, _)| subs.equivalent_without_compacting(*var, c_a));
|
.partition(|Uls(var, _, _)| env.subs.equivalent_without_compacting(*var, c_a));
|
||||||
if concrete.len() == 1 {
|
if concrete.len() == 1 {
|
||||||
// No flattening needs to be done, just return the lambda set as-is
|
// No flattening needs to be done, just return the lambda set as-is
|
||||||
return vec![lambda_set];
|
return vec![lambda_set];
|
||||||
|
@ -373,7 +360,7 @@ pub fn compact_lambda_sets_of_vars<P: Phase>(
|
||||||
// lambdas, plus all other unspecialized lambdas.
|
// lambdas, plus all other unspecialized lambdas.
|
||||||
// l' = [solved_lambdas + t1 + ... + tm + C:f:r]
|
// l' = [solved_lambdas + t1 + ... + tm + C:f:r]
|
||||||
let unspecialized = SubsSlice::extend_new(
|
let unspecialized = SubsSlice::extend_new(
|
||||||
&mut subs.unspecialized_lambda_sets,
|
&mut env.subs.unspecialized_lambda_sets,
|
||||||
not_concrete
|
not_concrete
|
||||||
.drain(..)
|
.drain(..)
|
||||||
.chain(std::iter::once(concrete_lambda)),
|
.chain(std::iter::once(concrete_lambda)),
|
||||||
|
@ -384,10 +371,10 @@ pub fn compact_lambda_sets_of_vars<P: Phase>(
|
||||||
// lambdas.
|
// lambdas.
|
||||||
// ln = [[] + C:fn:rn]
|
// ln = [[] + C:fn:rn]
|
||||||
let unspecialized = SubsSlice::extend_new(
|
let unspecialized = SubsSlice::extend_new(
|
||||||
&mut subs.unspecialized_lambda_sets,
|
&mut env.subs.unspecialized_lambda_sets,
|
||||||
[concrete_lambda],
|
[concrete_lambda],
|
||||||
);
|
);
|
||||||
let var = subs.fresh(Descriptor {
|
let var = env.subs.fresh(Descriptor {
|
||||||
content: Content::Error,
|
content: Content::Error,
|
||||||
rank: lambda_set_rank,
|
rank: lambda_set_rank,
|
||||||
mark: Mark::NONE,
|
mark: Mark::NONE,
|
||||||
|
@ -396,7 +383,7 @@ pub fn compact_lambda_sets_of_vars<P: Phase>(
|
||||||
(var, unspecialized)
|
(var, unspecialized)
|
||||||
};
|
};
|
||||||
|
|
||||||
subs.set_content(
|
env.subs.set_content(
|
||||||
var,
|
var,
|
||||||
Content::LambdaSet(LambdaSet {
|
Content::LambdaSet(LambdaSet {
|
||||||
solved,
|
solved,
|
||||||
|
@ -414,11 +401,15 @@ pub fn compact_lambda_sets_of_vars<P: Phase>(
|
||||||
// 2. Now, each `l` in `uls_a` has a unique unspecialized lambda of form `C:f:r`.
|
// 2. Now, each `l` in `uls_a` has a unique unspecialized lambda of form `C:f:r`.
|
||||||
// Sort `uls_a` primarily by `f` (arbitrary order), and secondarily by `r` in descending order.
|
// Sort `uls_a` primarily by `f` (arbitrary order), and secondarily by `r` in descending order.
|
||||||
uls_a.sort_by(|v1, v2| {
|
uls_a.sort_by(|v1, v2| {
|
||||||
let unspec_1 = subs.get_subs_slice(subs.get_lambda_set(*v1).unspecialized);
|
let unspec_1 = env
|
||||||
let unspec_2 = subs.get_subs_slice(subs.get_lambda_set(*v2).unspecialized);
|
.subs
|
||||||
|
.get_subs_slice(env.subs.get_lambda_set(*v1).unspecialized);
|
||||||
|
let unspec_2 = env
|
||||||
|
.subs
|
||||||
|
.get_subs_slice(env.subs.get_lambda_set(*v2).unspecialized);
|
||||||
|
|
||||||
let Uls(_, f1, r1) = unique_unspecialized_lambda(subs, c_a, unspec_1).unwrap();
|
let Uls(_, f1, r1) = unique_unspecialized_lambda(env.subs, c_a, unspec_1).unwrap();
|
||||||
let Uls(_, f2, r2) = unique_unspecialized_lambda(subs, c_a, unspec_2).unwrap();
|
let Uls(_, f2, r2) = unique_unspecialized_lambda(env.subs, c_a, unspec_2).unwrap();
|
||||||
|
|
||||||
match f1.cmp(&f2) {
|
match f1.cmp(&f2) {
|
||||||
std::cmp::Ordering::Equal => {
|
std::cmp::Ordering::Equal => {
|
||||||
|
@ -429,7 +420,7 @@ pub fn compact_lambda_sets_of_vars<P: Phase>(
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
trace_compact!(2. subs, &uls_a);
|
trace_compact!(2. env.subs, &uls_a);
|
||||||
|
|
||||||
// 3. For each `l` in `uls_a` with unique unspecialized lambda `C:f:r`:
|
// 3. For each `l` in `uls_a` with unique unspecialized lambda `C:f:r`:
|
||||||
// 1. Let `t_f1` be the directly ambient function of the lambda set containing `C:f:r`. Remove `C:f:r` from `t_f1`'s lambda set.
|
// 1. Let `t_f1` be the directly ambient function of the lambda set containing `C:f:r`. Remove `C:f:r` from `t_f1`'s lambda set.
|
||||||
|
@ -439,8 +430,7 @@ pub fn compact_lambda_sets_of_vars<P: Phase>(
|
||||||
// 3. Unify `t_f1 ~ t_f2`.
|
// 3. Unify `t_f1 ~ t_f2`.
|
||||||
trace_compact!(3start.);
|
trace_compact!(3start.);
|
||||||
for l in uls_a {
|
for l in uls_a {
|
||||||
let compaction_result =
|
let compaction_result = compact_lambda_set(env, c_a, l, phase);
|
||||||
compact_lambda_set(subs, derived_env, arena, pools, c_a, l, phase);
|
|
||||||
|
|
||||||
match compaction_result {
|
match compaction_result {
|
||||||
OneCompactionResult::Compacted {
|
OneCompactionResult::Compacted {
|
||||||
|
@ -474,10 +464,7 @@ enum OneCompactionResult {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn compact_lambda_set<P: Phase>(
|
fn compact_lambda_set<P: Phase>(
|
||||||
subs: &mut Subs,
|
env: &mut Env,
|
||||||
derived_env: &DerivedEnv,
|
|
||||||
arena: &Bump,
|
|
||||||
pools: &mut Pools,
|
|
||||||
resolved_concrete: Variable,
|
resolved_concrete: Variable,
|
||||||
this_lambda_set: Variable,
|
this_lambda_set: Variable,
|
||||||
phase: &P,
|
phase: &P,
|
||||||
|
@ -493,23 +480,24 @@ fn compact_lambda_set<P: Phase>(
|
||||||
recursion_var,
|
recursion_var,
|
||||||
unspecialized,
|
unspecialized,
|
||||||
ambient_function: t_f1,
|
ambient_function: t_f1,
|
||||||
} = subs.get_lambda_set(this_lambda_set);
|
} = env.subs.get_lambda_set(this_lambda_set);
|
||||||
let target_rank = subs.get_rank(this_lambda_set);
|
let target_rank = env.subs.get_rank(this_lambda_set);
|
||||||
|
|
||||||
debug_assert!(!unspecialized.is_empty());
|
debug_assert!(!unspecialized.is_empty());
|
||||||
|
|
||||||
let unspecialized = subs.get_subs_slice(unspecialized);
|
let unspecialized = env.subs.get_subs_slice(unspecialized);
|
||||||
|
|
||||||
// 1. Let `t_f1` be the directly ambient function of the lambda set containing `C:f:r`.
|
// 1. Let `t_f1` be the directly ambient function of the lambda set containing `C:f:r`.
|
||||||
let Uls(c, f, r) = unique_unspecialized_lambda(subs, resolved_concrete, unspecialized).unwrap();
|
let Uls(c, f, r) =
|
||||||
|
unique_unspecialized_lambda(env.subs, resolved_concrete, unspecialized).unwrap();
|
||||||
|
|
||||||
debug_assert!(subs.equivalent_without_compacting(c, resolved_concrete));
|
debug_assert!(env.subs.equivalent_without_compacting(c, resolved_concrete));
|
||||||
|
|
||||||
// Now decide: do we
|
// Now decide: do we
|
||||||
// - proceed with specialization
|
// - proceed with specialization
|
||||||
// - simply drop the specialization lambda set (due to an error)
|
// - simply drop the specialization lambda set (due to an error)
|
||||||
// - or do we need to wait, because we don't know enough information for the specialization yet?
|
// - or do we need to wait, because we don't know enough information for the specialization yet?
|
||||||
let specialization_decision = make_specialization_decision(subs, phase, c, f);
|
let specialization_decision = make_specialization_decision(env.subs, phase, c, f);
|
||||||
let specialization_key_or_drop = match specialization_decision {
|
let specialization_key_or_drop = match specialization_decision {
|
||||||
SpecializeDecision::Specialize(key) => Ok(key),
|
SpecializeDecision::Specialize(key) => Ok(key),
|
||||||
SpecializeDecision::Drop => Err(()),
|
SpecializeDecision::Drop => Err(()),
|
||||||
|
@ -522,7 +510,10 @@ fn compact_lambda_set<P: Phase>(
|
||||||
// 1b. Remove `C:f:r` from `t_f1`'s lambda set.
|
// 1b. Remove `C:f:r` from `t_f1`'s lambda set.
|
||||||
let new_unspecialized: Vec<_> = unspecialized
|
let new_unspecialized: Vec<_> = unspecialized
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|Uls(v, _, _)| !subs.equivalent_without_compacting(*v, resolved_concrete))
|
.filter(|Uls(v, _, _)| {
|
||||||
|
!env.subs
|
||||||
|
.equivalent_without_compacting(*v, resolved_concrete)
|
||||||
|
})
|
||||||
.copied()
|
.copied()
|
||||||
.collect();
|
.collect();
|
||||||
debug_assert_eq!(new_unspecialized.len(), unspecialized.len() - 1);
|
debug_assert_eq!(new_unspecialized.len(), unspecialized.len() - 1);
|
||||||
|
@ -530,12 +521,12 @@ fn compact_lambda_set<P: Phase>(
|
||||||
solved,
|
solved,
|
||||||
recursion_var,
|
recursion_var,
|
||||||
unspecialized: SubsSlice::extend_new(
|
unspecialized: SubsSlice::extend_new(
|
||||||
&mut subs.unspecialized_lambda_sets,
|
&mut env.subs.unspecialized_lambda_sets,
|
||||||
new_unspecialized,
|
new_unspecialized,
|
||||||
),
|
),
|
||||||
ambient_function: t_f1,
|
ambient_function: t_f1,
|
||||||
};
|
};
|
||||||
subs.set_content(
|
env.subs.set_content(
|
||||||
this_lambda_set,
|
this_lambda_set,
|
||||||
Content::LambdaSet(t_f1_lambda_set_without_concrete),
|
Content::LambdaSet(t_f1_lambda_set_without_concrete),
|
||||||
);
|
);
|
||||||
|
@ -545,7 +536,7 @@ fn compact_lambda_set<P: Phase>(
|
||||||
Err(()) => {
|
Err(()) => {
|
||||||
// Do nothing other than to remove the concrete lambda to drop from the lambda set,
|
// Do nothing other than to remove the concrete lambda to drop from the lambda set,
|
||||||
// which we already did in 1b above.
|
// which we already did in 1b above.
|
||||||
trace_compact!(3iter_end_skipped.subs, t_f1);
|
trace_compact!(3iter_end_skipped. env.subs, t_f1);
|
||||||
return OneCompactionResult::Compacted {
|
return OneCompactionResult::Compacted {
|
||||||
new_obligations: Default::default(),
|
new_obligations: Default::default(),
|
||||||
new_lambda_sets_to_specialize: Default::default(),
|
new_lambda_sets_to_specialize: Default::default(),
|
||||||
|
@ -554,8 +545,8 @@ fn compact_lambda_set<P: Phase>(
|
||||||
};
|
};
|
||||||
|
|
||||||
let specialization_ambient_function_var = get_specialization_lambda_set_ambient_function(
|
let specialization_ambient_function_var = get_specialization_lambda_set_ambient_function(
|
||||||
subs,
|
env.subs,
|
||||||
derived_env,
|
env.derived_env,
|
||||||
phase,
|
phase,
|
||||||
f,
|
f,
|
||||||
r,
|
r,
|
||||||
|
@ -568,7 +559,7 @@ fn compact_lambda_set<P: Phase>(
|
||||||
Err(()) => {
|
Err(()) => {
|
||||||
// Do nothing other than to remove the concrete lambda to drop from the lambda set,
|
// Do nothing other than to remove the concrete lambda to drop from the lambda set,
|
||||||
// which we already did in 1b above.
|
// which we already did in 1b above.
|
||||||
trace_compact!(3iter_end_skipped.subs, t_f1);
|
trace_compact!(3iter_end_skipped. env.subs, t_f1);
|
||||||
return OneCompactionResult::Compacted {
|
return OneCompactionResult::Compacted {
|
||||||
new_obligations: Default::default(),
|
new_obligations: Default::default(),
|
||||||
new_lambda_sets_to_specialize: Default::default(),
|
new_lambda_sets_to_specialize: Default::default(),
|
||||||
|
@ -578,21 +569,21 @@ fn compact_lambda_set<P: Phase>(
|
||||||
|
|
||||||
// Ensure the specialized ambient function we'll unify with is not a generalized one, but one
|
// Ensure the specialized ambient function we'll unify with is not a generalized one, but one
|
||||||
// at the rank of the lambda set being compacted.
|
// at the rank of the lambda set being compacted.
|
||||||
let t_f2 = deep_copy_var_in(subs, target_rank, pools, t_f2, arena);
|
let t_f2 = deep_copy_var_in(env, target_rank, t_f2, env.arena);
|
||||||
|
|
||||||
// 3. Unify `t_f1 ~ t_f2`.
|
// 3. Unify `t_f1 ~ t_f2`.
|
||||||
trace_compact!(3iter_start.subs, this_lambda_set, t_f1, t_f2);
|
trace_compact!(3iter_start. env.subs, this_lambda_set, t_f1, t_f2);
|
||||||
let (vars, new_obligations, new_lambda_sets_to_specialize, _meta) = unify(
|
let (vars, new_obligations, new_lambda_sets_to_specialize, _meta) = unify(
|
||||||
&mut UEnv::new(subs),
|
&mut UEnv::new(env.subs),
|
||||||
t_f1,
|
t_f1,
|
||||||
t_f2,
|
t_f2,
|
||||||
Mode::LAMBDA_SET_SPECIALIZATION,
|
Mode::LAMBDA_SET_SPECIALIZATION,
|
||||||
Polarity::Pos,
|
Polarity::Pos,
|
||||||
)
|
)
|
||||||
.expect_success("ambient functions don't unify");
|
.expect_success("ambient functions don't unify");
|
||||||
trace_compact!(3iter_end.subs, t_f1);
|
trace_compact!(3iter_end. env.subs, t_f1);
|
||||||
|
|
||||||
introduce(subs, target_rank, pools, &vars);
|
env.introduce(target_rank, &vars);
|
||||||
|
|
||||||
OneCompactionResult::Compacted {
|
OneCompactionResult::Compacted {
|
||||||
new_obligations,
|
new_obligations,
|
||||||
|
|
|
@ -22,8 +22,7 @@ use roc_unify::unify::{unify, Env as UEnv, Mode, Unified};
|
||||||
use crate::{
|
use crate::{
|
||||||
ability::{AbilityImplError, ObligationCache},
|
ability::{AbilityImplError, ObligationCache},
|
||||||
deep_copy::deep_copy_var_in,
|
deep_copy::deep_copy_var_in,
|
||||||
pools::Pools,
|
env::Env,
|
||||||
solve::{register, register_with_known_var},
|
|
||||||
Aliases,
|
Aliases,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -43,9 +42,8 @@ fn put_scratchpad(scratchpad: bumpalo::Bump) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn either_type_index_to_var(
|
pub(crate) fn either_type_index_to_var(
|
||||||
subs: &mut Subs,
|
env: &mut Env,
|
||||||
rank: Rank,
|
rank: Rank,
|
||||||
pools: &mut Pools,
|
|
||||||
problems: &mut Vec<TypeError>,
|
problems: &mut Vec<TypeError>,
|
||||||
abilities_store: &mut AbilitiesStore,
|
abilities_store: &mut AbilitiesStore,
|
||||||
obligation_cache: &mut ObligationCache,
|
obligation_cache: &mut ObligationCache,
|
||||||
|
@ -57,12 +55,11 @@ pub(crate) fn either_type_index_to_var(
|
||||||
Ok(type_index) => {
|
Ok(type_index) => {
|
||||||
// Converts the celled type to a variable, emplacing the new variable for re-use.
|
// Converts the celled type to a variable, emplacing the new variable for re-use.
|
||||||
let var = type_to_var(
|
let var = type_to_var(
|
||||||
subs,
|
env,
|
||||||
rank,
|
rank,
|
||||||
problems,
|
problems,
|
||||||
abilities_store,
|
abilities_store,
|
||||||
obligation_cache,
|
obligation_cache,
|
||||||
pools,
|
|
||||||
types,
|
types,
|
||||||
aliases,
|
aliases,
|
||||||
type_index,
|
type_index,
|
||||||
|
@ -85,12 +82,11 @@ pub(crate) fn either_type_index_to_var(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn type_to_var(
|
pub(crate) fn type_to_var(
|
||||||
subs: &mut Subs,
|
env: &mut Env,
|
||||||
rank: Rank,
|
rank: Rank,
|
||||||
problems: &mut Vec<TypeError>,
|
problems: &mut Vec<TypeError>,
|
||||||
abilities_store: &mut AbilitiesStore,
|
abilities_store: &mut AbilitiesStore,
|
||||||
obligation_cache: &mut ObligationCache,
|
obligation_cache: &mut ObligationCache,
|
||||||
pools: &mut Pools,
|
|
||||||
types: &mut Types,
|
types: &mut Types,
|
||||||
aliases: &mut Aliases,
|
aliases: &mut Aliases,
|
||||||
typ: Index<TypeTag>,
|
typ: Index<TypeTag>,
|
||||||
|
@ -101,9 +97,8 @@ pub(crate) fn type_to_var(
|
||||||
let mut arena = take_scratchpad();
|
let mut arena = take_scratchpad();
|
||||||
|
|
||||||
let var = type_to_var_help(
|
let var = type_to_var_help(
|
||||||
subs,
|
env,
|
||||||
rank,
|
rank,
|
||||||
pools,
|
|
||||||
problems,
|
problems,
|
||||||
abilities_store,
|
abilities_store,
|
||||||
obligation_cache,
|
obligation_cache,
|
||||||
|
@ -131,9 +126,8 @@ enum RegisterVariable {
|
||||||
|
|
||||||
impl RegisterVariable {
|
impl RegisterVariable {
|
||||||
fn from_type(
|
fn from_type(
|
||||||
subs: &mut Subs,
|
env: &mut Env,
|
||||||
rank: Rank,
|
rank: Rank,
|
||||||
pools: &mut Pools,
|
|
||||||
arena: &'_ bumpalo::Bump,
|
arena: &'_ bumpalo::Bump,
|
||||||
types: &mut Types,
|
types: &mut Types,
|
||||||
typ: Index<TypeTag>,
|
typ: Index<TypeTag>,
|
||||||
|
@ -155,7 +149,7 @@ impl RegisterVariable {
|
||||||
reserved
|
reserved
|
||||||
} else {
|
} else {
|
||||||
// for any other rank, we need to copy; it takes care of adjusting the rank
|
// for any other rank, we need to copy; it takes care of adjusting the rank
|
||||||
deep_copy_var_in(subs, rank, pools, reserved, arena)
|
deep_copy_var_in(env, rank, reserved, arena)
|
||||||
};
|
};
|
||||||
// Safety: the `destination` will become the source-of-truth for the type index, since it
|
// Safety: the `destination` will become the source-of-truth for the type index, since it
|
||||||
// was not already transformed before (if it was, we'd be in the Variable branch!)
|
// was not already transformed before (if it was, we'd be in the Variable branch!)
|
||||||
|
@ -171,18 +165,17 @@ impl RegisterVariable {
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn with_stack(
|
fn with_stack(
|
||||||
subs: &mut Subs,
|
env: &mut Env,
|
||||||
rank: Rank,
|
rank: Rank,
|
||||||
pools: &mut Pools,
|
|
||||||
arena: &'_ bumpalo::Bump,
|
arena: &'_ bumpalo::Bump,
|
||||||
types: &mut Types,
|
types: &mut Types,
|
||||||
typ_index: Index<TypeTag>,
|
typ_index: Index<TypeTag>,
|
||||||
stack: &mut bumpalo::collections::Vec<'_, TypeToVar>,
|
stack: &mut bumpalo::collections::Vec<'_, TypeToVar>,
|
||||||
) -> Variable {
|
) -> Variable {
|
||||||
match Self::from_type(subs, rank, pools, arena, types, typ_index) {
|
match Self::from_type(env, rank, arena, types, typ_index) {
|
||||||
Self::Direct(var) => var,
|
Self::Direct(var) => var,
|
||||||
Self::Deferred => {
|
Self::Deferred => {
|
||||||
let var = subs.fresh_unnamed_flex_var();
|
let var = env.subs.fresh_unnamed_flex_var();
|
||||||
// Safety: the `destination` will become the source-of-truth for the type index, since it
|
// Safety: the `destination` will become the source-of-truth for the type index, since it
|
||||||
// was not already transformed before (if it was, it wouldn't be deferred!)
|
// was not already transformed before (if it was, it wouldn't be deferred!)
|
||||||
let typ = unsafe { types.emplace_variable(typ_index, var) };
|
let typ = unsafe { types.emplace_variable(typ_index, var) };
|
||||||
|
@ -260,9 +253,8 @@ enum TypeToVar {
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub(crate) fn type_to_var_help(
|
pub(crate) fn type_to_var_help(
|
||||||
subs: &mut Subs,
|
env: &mut Env,
|
||||||
rank: Rank,
|
rank: Rank,
|
||||||
pools: &mut Pools,
|
|
||||||
problems: &mut Vec<TypeError>,
|
problems: &mut Vec<TypeError>,
|
||||||
abilities_store: &AbilitiesStore,
|
abilities_store: &AbilitiesStore,
|
||||||
obligation_cache: &mut ObligationCache,
|
obligation_cache: &mut ObligationCache,
|
||||||
|
@ -280,16 +272,16 @@ pub(crate) fn type_to_var_help(
|
||||||
|
|
||||||
macro_rules! helper {
|
macro_rules! helper {
|
||||||
($typ:expr, $ambient_function_policy:expr) => {{
|
($typ:expr, $ambient_function_policy:expr) => {{
|
||||||
match RegisterVariable::from_type(subs, rank, pools, arena, types, $typ) {
|
match RegisterVariable::from_type(env, rank, arena, types, $typ) {
|
||||||
RegisterVariable::Direct(var) => {
|
RegisterVariable::Direct(var) => {
|
||||||
// If the variable is just a type variable but we know we're in a lambda set
|
// If the variable is just a type variable but we know we're in a lambda set
|
||||||
// context, try to link to the ambient function.
|
// context, try to link to the ambient function.
|
||||||
$ambient_function_policy.link_to_alias_lambda_set_var(subs, var);
|
$ambient_function_policy.link_to_alias_lambda_set_var(env.subs, var);
|
||||||
|
|
||||||
var
|
var
|
||||||
}
|
}
|
||||||
RegisterVariable::Deferred => {
|
RegisterVariable::Deferred => {
|
||||||
let var = subs.fresh_unnamed_flex_var();
|
let var = env.subs.fresh_unnamed_flex_var();
|
||||||
|
|
||||||
// Safety: the `destination` will become the source-of-truth for the type index, since it
|
// Safety: the `destination` will become the source-of-truth for the type index, since it
|
||||||
// was not already transformed before (if it was, it wouldn't be deferred!)
|
// was not already transformed before (if it was, it wouldn't be deferred!)
|
||||||
|
@ -328,7 +320,7 @@ pub(crate) fn type_to_var_help(
|
||||||
RangedNumber(range) => {
|
RangedNumber(range) => {
|
||||||
let content = Content::RangedNumber(range);
|
let content = Content::RangedNumber(range);
|
||||||
|
|
||||||
register_with_known_var(subs, destination, rank, pools, content)
|
env.register_with_known_var(destination, rank, content)
|
||||||
}
|
}
|
||||||
Apply {
|
Apply {
|
||||||
symbol,
|
symbol,
|
||||||
|
@ -336,18 +328,18 @@ pub(crate) fn type_to_var_help(
|
||||||
region: _,
|
region: _,
|
||||||
} => {
|
} => {
|
||||||
let arguments = types.get_type_arguments(typ_index);
|
let arguments = types.get_type_arguments(typ_index);
|
||||||
let new_arguments = VariableSubsSlice::reserve_into_subs(subs, arguments.len());
|
let new_arguments = VariableSubsSlice::reserve_into_subs(env.subs, arguments.len());
|
||||||
for (target_index, var_index) in
|
for (target_index, var_index) in
|
||||||
(new_arguments.indices()).zip(arguments.into_iter())
|
(new_arguments.indices()).zip(arguments.into_iter())
|
||||||
{
|
{
|
||||||
let var = helper!(var_index);
|
let var = helper!(var_index);
|
||||||
subs.variables[target_index] = var;
|
env.subs.variables[target_index] = var;
|
||||||
}
|
}
|
||||||
|
|
||||||
let flat_type = FlatType::Apply(symbol, new_arguments);
|
let flat_type = FlatType::Apply(symbol, new_arguments);
|
||||||
let content = Content::Structure(flat_type);
|
let content = Content::Structure(flat_type);
|
||||||
|
|
||||||
register_with_known_var(subs, destination, rank, pools, content)
|
env.register_with_known_var(destination, rank, content)
|
||||||
}
|
}
|
||||||
|
|
||||||
ClosureTag {
|
ClosureTag {
|
||||||
|
@ -355,9 +347,8 @@ pub(crate) fn type_to_var_help(
|
||||||
ambient_function,
|
ambient_function,
|
||||||
} => {
|
} => {
|
||||||
let captures = types.get_type_arguments(typ_index);
|
let captures = types.get_type_arguments(typ_index);
|
||||||
let union_lambdas = create_union_lambda(
|
let union_lambdas =
|
||||||
subs, rank, pools, arena, types, name, captures, &mut stack,
|
create_union_lambda(env, rank, arena, types, name, captures, &mut stack);
|
||||||
);
|
|
||||||
|
|
||||||
let content = Content::LambdaSet(subs::LambdaSet {
|
let content = Content::LambdaSet(subs::LambdaSet {
|
||||||
solved: union_lambdas,
|
solved: union_lambdas,
|
||||||
|
@ -368,11 +359,11 @@ pub(crate) fn type_to_var_help(
|
||||||
ambient_function,
|
ambient_function,
|
||||||
});
|
});
|
||||||
|
|
||||||
register_with_known_var(subs, destination, rank, pools, content)
|
env.register_with_known_var(destination, rank, content)
|
||||||
}
|
}
|
||||||
UnspecializedLambdaSet { unspecialized } => {
|
UnspecializedLambdaSet { unspecialized } => {
|
||||||
let unspecialized_slice = SubsSlice::extend_new(
|
let unspecialized_slice = SubsSlice::extend_new(
|
||||||
&mut subs.unspecialized_lambda_sets,
|
&mut env.subs.unspecialized_lambda_sets,
|
||||||
std::iter::once(unspecialized),
|
std::iter::once(unspecialized),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -397,17 +388,17 @@ pub(crate) fn type_to_var_help(
|
||||||
ambient_function,
|
ambient_function,
|
||||||
});
|
});
|
||||||
|
|
||||||
register_with_known_var(subs, destination, rank, pools, content)
|
env.register_with_known_var(destination, rank, content)
|
||||||
}
|
}
|
||||||
// This case is important for the rank of boolean variables
|
// This case is important for the rank of boolean variables
|
||||||
Function(closure_type, ret_type) => {
|
Function(closure_type, ret_type) => {
|
||||||
let arguments = types.get_type_arguments(typ_index);
|
let arguments = types.get_type_arguments(typ_index);
|
||||||
let new_arguments = VariableSubsSlice::reserve_into_subs(subs, arguments.len());
|
let new_arguments = VariableSubsSlice::reserve_into_subs(env.subs, arguments.len());
|
||||||
for (target_index, var_index) in
|
for (target_index, var_index) in
|
||||||
(new_arguments.indices()).zip(arguments.into_iter())
|
(new_arguments.indices()).zip(arguments.into_iter())
|
||||||
{
|
{
|
||||||
let var = helper!(var_index);
|
let var = helper!(var_index);
|
||||||
subs.variables[target_index] = var;
|
env.subs.variables[target_index] = var;
|
||||||
}
|
}
|
||||||
|
|
||||||
let ret_var = helper!(ret_type);
|
let ret_var = helper!(ret_type);
|
||||||
|
@ -416,7 +407,7 @@ pub(crate) fn type_to_var_help(
|
||||||
let content =
|
let content =
|
||||||
Content::Structure(FlatType::Func(new_arguments, closure_var, ret_var));
|
Content::Structure(FlatType::Func(new_arguments, closure_var, ret_var));
|
||||||
|
|
||||||
register_with_known_var(subs, destination, rank, pools, content)
|
env.register_with_known_var(destination, rank, content)
|
||||||
}
|
}
|
||||||
Record(fields) => {
|
Record(fields) => {
|
||||||
let ext_slice = types.get_type_arguments(typ_index);
|
let ext_slice = types.get_type_arguments(typ_index);
|
||||||
|
@ -448,7 +439,7 @@ pub(crate) fn type_to_var_help(
|
||||||
};
|
};
|
||||||
|
|
||||||
let (it, new_ext_var) =
|
let (it, new_ext_var) =
|
||||||
gather_fields_unsorted_iter(subs, RecordFields::empty(), temp_ext_var)
|
gather_fields_unsorted_iter(env.subs, RecordFields::empty(), temp_ext_var)
|
||||||
.expect("Something ended up weird in this record type");
|
.expect("Something ended up weird in this record type");
|
||||||
|
|
||||||
let it = it
|
let it = it
|
||||||
|
@ -458,11 +449,11 @@ pub(crate) fn type_to_var_help(
|
||||||
field_vars.extend(it);
|
field_vars.extend(it);
|
||||||
insertion_sort_by(&mut field_vars, RecordFields::compare);
|
insertion_sort_by(&mut field_vars, RecordFields::compare);
|
||||||
|
|
||||||
let record_fields = RecordFields::insert_into_subs(subs, field_vars);
|
let record_fields = RecordFields::insert_into_subs(env.subs, field_vars);
|
||||||
|
|
||||||
let content = Content::Structure(FlatType::Record(record_fields, new_ext_var));
|
let content = Content::Structure(FlatType::Record(record_fields, new_ext_var));
|
||||||
|
|
||||||
register_with_known_var(subs, destination, rank, pools, content)
|
env.register_with_known_var(destination, rank, content)
|
||||||
}
|
}
|
||||||
|
|
||||||
Tuple(elems) => {
|
Tuple(elems) => {
|
||||||
|
@ -487,15 +478,15 @@ pub(crate) fn type_to_var_help(
|
||||||
};
|
};
|
||||||
|
|
||||||
let (it, new_ext_var) =
|
let (it, new_ext_var) =
|
||||||
gather_tuple_elems_unsorted_iter(subs, TupleElems::empty(), temp_ext_var)
|
gather_tuple_elems_unsorted_iter(env.subs, TupleElems::empty(), temp_ext_var)
|
||||||
.expect("Something ended up weird in this tuple type");
|
.expect("Something ended up weird in this tuple type");
|
||||||
|
|
||||||
elem_vars.extend(it);
|
elem_vars.extend(it);
|
||||||
let tuple_elems = TupleElems::insert_into_subs(subs, elem_vars);
|
let tuple_elems = TupleElems::insert_into_subs(env.subs, elem_vars);
|
||||||
|
|
||||||
let content = Content::Structure(FlatType::Tuple(tuple_elems, new_ext_var));
|
let content = Content::Structure(FlatType::Tuple(tuple_elems, new_ext_var));
|
||||||
|
|
||||||
register_with_known_var(subs, destination, rank, pools, content)
|
env.register_with_known_var(destination, rank, content)
|
||||||
}
|
}
|
||||||
|
|
||||||
TagUnion(tags, ext_openness) => {
|
TagUnion(tags, ext_openness) => {
|
||||||
|
@ -506,9 +497,8 @@ pub(crate) fn type_to_var_help(
|
||||||
debug_assert!(!tags.is_empty() || !ext_slice.is_empty());
|
debug_assert!(!tags.is_empty() || !ext_slice.is_empty());
|
||||||
|
|
||||||
let (union_tags, ext) = type_to_union_tags(
|
let (union_tags, ext) = type_to_union_tags(
|
||||||
subs,
|
env,
|
||||||
rank,
|
rank,
|
||||||
pools,
|
|
||||||
arena,
|
arena,
|
||||||
types,
|
types,
|
||||||
tags,
|
tags,
|
||||||
|
@ -518,7 +508,7 @@ pub(crate) fn type_to_var_help(
|
||||||
);
|
);
|
||||||
let content = Content::Structure(FlatType::TagUnion(union_tags, ext));
|
let content = Content::Structure(FlatType::TagUnion(union_tags, ext));
|
||||||
|
|
||||||
register_with_known_var(subs, destination, rank, pools, content)
|
env.register_with_known_var(destination, rank, content)
|
||||||
}
|
}
|
||||||
FunctionOrTagUnion(symbol, ext_openness) => {
|
FunctionOrTagUnion(symbol, ext_openness) => {
|
||||||
let ext_slice = types.get_type_arguments(typ_index);
|
let ext_slice = types.get_type_arguments(typ_index);
|
||||||
|
@ -534,7 +524,7 @@ pub(crate) fn type_to_var_help(
|
||||||
};
|
};
|
||||||
|
|
||||||
let (it, ext) = roc_types::types::gather_tags_unsorted_iter(
|
let (it, ext) = roc_types::types::gather_tags_unsorted_iter(
|
||||||
subs,
|
env.subs,
|
||||||
UnionTags::default(),
|
UnionTags::default(),
|
||||||
temp_ext,
|
temp_ext,
|
||||||
)
|
)
|
||||||
|
@ -544,13 +534,13 @@ pub(crate) fn type_to_var_help(
|
||||||
unreachable!("we assert that the ext var is empty; otherwise we'd already know it was a tag union!");
|
unreachable!("we assert that the ext var is empty; otherwise we'd already know it was a tag union!");
|
||||||
}
|
}
|
||||||
|
|
||||||
let tag_names = SubsSlice::extend_new(&mut subs.tag_names, [tag_name]);
|
let tag_names = SubsSlice::extend_new(&mut env.subs.tag_names, [tag_name]);
|
||||||
let symbols = SubsSlice::extend_new(&mut subs.symbol_names, [symbol]);
|
let symbols = SubsSlice::extend_new(&mut env.subs.symbol_names, [symbol]);
|
||||||
|
|
||||||
let content =
|
let content =
|
||||||
Content::Structure(FlatType::FunctionOrTagUnion(tag_names, symbols, ext));
|
Content::Structure(FlatType::FunctionOrTagUnion(tag_names, symbols, ext));
|
||||||
|
|
||||||
register_with_known_var(subs, destination, rank, pools, content)
|
env.register_with_known_var(destination, rank, content)
|
||||||
}
|
}
|
||||||
RecursiveTagUnion(rec_var, tags, ext_openness) => {
|
RecursiveTagUnion(rec_var, tags, ext_openness) => {
|
||||||
let ext_slice = types.get_type_arguments(typ_index);
|
let ext_slice = types.get_type_arguments(typ_index);
|
||||||
|
@ -560,9 +550,8 @@ pub(crate) fn type_to_var_help(
|
||||||
debug_assert!(!tags.is_empty() || !ext_slice.is_empty());
|
debug_assert!(!tags.is_empty() || !ext_slice.is_empty());
|
||||||
|
|
||||||
let (union_tags, ext) = type_to_union_tags(
|
let (union_tags, ext) = type_to_union_tags(
|
||||||
subs,
|
env,
|
||||||
rank,
|
rank,
|
||||||
pools,
|
|
||||||
arena,
|
arena,
|
||||||
types,
|
types,
|
||||||
tags,
|
tags,
|
||||||
|
@ -574,13 +563,11 @@ pub(crate) fn type_to_var_help(
|
||||||
Content::Structure(FlatType::RecursiveTagUnion(rec_var, union_tags, ext));
|
Content::Structure(FlatType::RecursiveTagUnion(rec_var, union_tags, ext));
|
||||||
|
|
||||||
let tag_union_var = destination;
|
let tag_union_var = destination;
|
||||||
register_with_known_var(subs, tag_union_var, rank, pools, content);
|
env.register_with_known_var(tag_union_var, rank, content);
|
||||||
|
|
||||||
register_with_known_var(
|
env.register_with_known_var(
|
||||||
subs,
|
|
||||||
rec_var,
|
rec_var,
|
||||||
rank,
|
rank,
|
||||||
pools,
|
|
||||||
Content::RecursionVar {
|
Content::RecursionVar {
|
||||||
opt_name: None,
|
opt_name: None,
|
||||||
structure: tag_union_var,
|
structure: tag_union_var,
|
||||||
|
@ -605,7 +592,8 @@ pub(crate) fn type_to_var_help(
|
||||||
let all_vars_length = type_arguments.len()
|
let all_vars_length = type_arguments.len()
|
||||||
+ lambda_set_variables.len()
|
+ lambda_set_variables.len()
|
||||||
+ infer_ext_in_output_variables.len();
|
+ infer_ext_in_output_variables.len();
|
||||||
let new_variables = VariableSubsSlice::reserve_into_subs(subs, all_vars_length);
|
let new_variables =
|
||||||
|
VariableSubsSlice::reserve_into_subs(env.subs, all_vars_length);
|
||||||
|
|
||||||
let type_arguments_offset = 0;
|
let type_arguments_offset = 0;
|
||||||
let lambda_set_vars_offset = type_arguments_offset + type_arguments.len();
|
let lambda_set_vars_offset = type_arguments_offset + type_arguments.len();
|
||||||
|
@ -618,7 +606,7 @@ pub(crate) fn type_to_var_help(
|
||||||
.zip(type_argument_abilities.into_iter())
|
.zip(type_argument_abilities.into_iter())
|
||||||
{
|
{
|
||||||
let copy_var = helper!(arg_type);
|
let copy_var = helper!(arg_type);
|
||||||
subs.variables[target_index] = copy_var;
|
env.subs.variables[target_index] = copy_var;
|
||||||
if !types[abilities].is_empty() {
|
if !types[abilities].is_empty() {
|
||||||
let arg_region = types[arg_region];
|
let arg_region = types[arg_region];
|
||||||
bind_to_abilities.push((Loc::at(arg_region, copy_var), abilities));
|
bind_to_abilities.push((Loc::at(arg_region, copy_var), abilities));
|
||||||
|
@ -631,9 +619,8 @@ pub(crate) fn type_to_var_help(
|
||||||
// We MUST do this now, otherwise when linking the ambient function during
|
// We MUST do this now, otherwise when linking the ambient function during
|
||||||
// instantiation of the real var, there will be nothing to link against.
|
// instantiation of the real var, there will be nothing to link against.
|
||||||
let copy_var = type_to_var_help(
|
let copy_var = type_to_var_help(
|
||||||
subs,
|
env,
|
||||||
rank,
|
rank,
|
||||||
pools,
|
|
||||||
problems,
|
problems,
|
||||||
abilities_store,
|
abilities_store,
|
||||||
obligation_cache,
|
obligation_cache,
|
||||||
|
@ -643,14 +630,14 @@ pub(crate) fn type_to_var_help(
|
||||||
ls,
|
ls,
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
subs.variables[target_index] = copy_var;
|
env.subs.variables[target_index] = copy_var;
|
||||||
}
|
}
|
||||||
|
|
||||||
let it = (new_variables.indices().skip(infer_ext_vars_offset))
|
let it = (new_variables.indices().skip(infer_ext_vars_offset))
|
||||||
.zip(infer_ext_in_output_variables.into_iter());
|
.zip(infer_ext_in_output_variables.into_iter());
|
||||||
for (target_index, ext_typ) in it {
|
for (target_index, ext_typ) in it {
|
||||||
let copy_var = helper!(ext_typ);
|
let copy_var = helper!(ext_typ);
|
||||||
subs.variables[target_index] = copy_var;
|
env.subs.variables[target_index] = copy_var;
|
||||||
}
|
}
|
||||||
|
|
||||||
AliasVariables {
|
AliasVariables {
|
||||||
|
@ -662,9 +649,8 @@ pub(crate) fn type_to_var_help(
|
||||||
};
|
};
|
||||||
|
|
||||||
let (alias_variable, kind) = aliases.instantiate_real_var(
|
let (alias_variable, kind) = aliases.instantiate_real_var(
|
||||||
subs,
|
env,
|
||||||
rank,
|
rank,
|
||||||
pools,
|
|
||||||
problems,
|
problems,
|
||||||
abilities_store,
|
abilities_store,
|
||||||
obligation_cache,
|
obligation_cache,
|
||||||
|
@ -676,7 +662,7 @@ pub(crate) fn type_to_var_help(
|
||||||
|
|
||||||
let content = Content::Alias(symbol, alias_variables, alias_variable, kind);
|
let content = Content::Alias(symbol, alias_variables, alias_variable, kind);
|
||||||
|
|
||||||
register_with_known_var(subs, destination, rank, pools, content)
|
env.register_with_known_var(destination, rank, content)
|
||||||
}
|
}
|
||||||
|
|
||||||
StructuralAlias { shared, actual } | OpaqueAlias { shared, actual } => {
|
StructuralAlias { shared, actual } | OpaqueAlias { shared, actual } => {
|
||||||
|
@ -707,7 +693,8 @@ pub(crate) fn type_to_var_help(
|
||||||
let lambda_set_vars_offset = type_arguments_offset + type_arguments.len();
|
let lambda_set_vars_offset = type_arguments_offset + type_arguments.len();
|
||||||
let infer_ext_vars_offset = lambda_set_vars_offset + lambda_set_variables.len();
|
let infer_ext_vars_offset = lambda_set_vars_offset + lambda_set_variables.len();
|
||||||
|
|
||||||
let new_variables = VariableSubsSlice::reserve_into_subs(subs, all_vars_length);
|
let new_variables =
|
||||||
|
VariableSubsSlice::reserve_into_subs(env.subs, all_vars_length);
|
||||||
|
|
||||||
for (((target_index, typ), region), abilities) in
|
for (((target_index, typ), region), abilities) in
|
||||||
(new_variables.indices().skip(type_arguments_offset))
|
(new_variables.indices().skip(type_arguments_offset))
|
||||||
|
@ -716,7 +703,7 @@ pub(crate) fn type_to_var_help(
|
||||||
.zip(type_argument_abilities.into_iter())
|
.zip(type_argument_abilities.into_iter())
|
||||||
{
|
{
|
||||||
let copy_var = helper!(typ);
|
let copy_var = helper!(typ);
|
||||||
subs.variables[target_index] = copy_var;
|
env.subs.variables[target_index] = copy_var;
|
||||||
if !types[abilities].is_empty() {
|
if !types[abilities].is_empty() {
|
||||||
let region = types[region];
|
let region = types[region];
|
||||||
bind_to_abilities.push((Loc::at(region, copy_var), abilities));
|
bind_to_abilities.push((Loc::at(region, copy_var), abilities));
|
||||||
|
@ -727,14 +714,14 @@ pub(crate) fn type_to_var_help(
|
||||||
.zip(lambda_set_variables.into_iter());
|
.zip(lambda_set_variables.into_iter());
|
||||||
for (target_index, ls) in it {
|
for (target_index, ls) in it {
|
||||||
let copy_var = helper!(ls);
|
let copy_var = helper!(ls);
|
||||||
subs.variables[target_index] = copy_var;
|
env.subs.variables[target_index] = copy_var;
|
||||||
}
|
}
|
||||||
|
|
||||||
let it = (new_variables.indices().skip(infer_ext_vars_offset))
|
let it = (new_variables.indices().skip(infer_ext_vars_offset))
|
||||||
.zip(infer_ext_in_output_variables.into_iter());
|
.zip(infer_ext_in_output_variables.into_iter());
|
||||||
for (target_index, ext_typ) in it {
|
for (target_index, ext_typ) in it {
|
||||||
let copy_var = helper!(ext_typ);
|
let copy_var = helper!(ext_typ);
|
||||||
subs.variables[target_index] = copy_var;
|
env.subs.variables[target_index] = copy_var;
|
||||||
}
|
}
|
||||||
|
|
||||||
AliasVariables {
|
AliasVariables {
|
||||||
|
@ -746,13 +733,13 @@ pub(crate) fn type_to_var_help(
|
||||||
};
|
};
|
||||||
|
|
||||||
let alias_variable = if let Symbol::RESULT_RESULT = symbol {
|
let alias_variable = if let Symbol::RESULT_RESULT = symbol {
|
||||||
roc_result_to_var(subs, rank, pools, arena, types, actual, &mut stack)
|
roc_result_to_var(env, rank, arena, types, actual, &mut stack)
|
||||||
} else {
|
} else {
|
||||||
helper!(actual)
|
helper!(actual)
|
||||||
};
|
};
|
||||||
let content = Content::Alias(symbol, alias_variables, alias_variable, kind);
|
let content = Content::Alias(symbol, alias_variables, alias_variable, kind);
|
||||||
|
|
||||||
register_with_known_var(subs, destination, rank, pools, content)
|
env.register_with_known_var(destination, rank, content)
|
||||||
}
|
}
|
||||||
HostExposedAlias {
|
HostExposedAlias {
|
||||||
shared,
|
shared,
|
||||||
|
@ -771,13 +758,13 @@ pub(crate) fn type_to_var_help(
|
||||||
|
|
||||||
let alias_variables = {
|
let alias_variables = {
|
||||||
let length = type_arguments.len() + lambda_set_variables.len();
|
let length = type_arguments.len() + lambda_set_variables.len();
|
||||||
let new_variables = VariableSubsSlice::reserve_into_subs(subs, length);
|
let new_variables = VariableSubsSlice::reserve_into_subs(env.subs, length);
|
||||||
|
|
||||||
for (target_index, arg_type) in
|
for (target_index, arg_type) in
|
||||||
(new_variables.indices()).zip(type_arguments.into_iter())
|
(new_variables.indices()).zip(type_arguments.into_iter())
|
||||||
{
|
{
|
||||||
let copy_var = helper!(arg_type);
|
let copy_var = helper!(arg_type);
|
||||||
subs.variables[target_index] = copy_var;
|
env.subs.variables[target_index] = copy_var;
|
||||||
}
|
}
|
||||||
let it = (new_variables.indices().skip(type_arguments.len()))
|
let it = (new_variables.indices().skip(type_arguments.len()))
|
||||||
.zip(lambda_set_variables.into_iter());
|
.zip(lambda_set_variables.into_iter());
|
||||||
|
@ -785,9 +772,8 @@ pub(crate) fn type_to_var_help(
|
||||||
// We MUST do this now, otherwise when linking the ambient function during
|
// We MUST do this now, otherwise when linking the ambient function during
|
||||||
// instantiation of the real var, there will be nothing to link against.
|
// instantiation of the real var, there will be nothing to link against.
|
||||||
let copy_var = type_to_var_help(
|
let copy_var = type_to_var_help(
|
||||||
subs,
|
env,
|
||||||
rank,
|
rank,
|
||||||
pools,
|
|
||||||
problems,
|
problems,
|
||||||
abilities_store,
|
abilities_store,
|
||||||
obligation_cache,
|
obligation_cache,
|
||||||
|
@ -797,7 +783,7 @@ pub(crate) fn type_to_var_help(
|
||||||
ls,
|
ls,
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
subs.variables[target_index] = copy_var;
|
env.subs.variables[target_index] = copy_var;
|
||||||
}
|
}
|
||||||
|
|
||||||
AliasVariables {
|
AliasVariables {
|
||||||
|
@ -810,9 +796,8 @@ pub(crate) fn type_to_var_help(
|
||||||
|
|
||||||
// cannot use helper! here because this variable may be involved in unification below
|
// cannot use helper! here because this variable may be involved in unification below
|
||||||
let alias_variable = type_to_var_help(
|
let alias_variable = type_to_var_help(
|
||||||
subs,
|
env,
|
||||||
rank,
|
rank,
|
||||||
pools,
|
|
||||||
problems,
|
problems,
|
||||||
abilities_store,
|
abilities_store,
|
||||||
obligation_cache,
|
obligation_cache,
|
||||||
|
@ -830,14 +815,14 @@ pub(crate) fn type_to_var_help(
|
||||||
alias_variable,
|
alias_variable,
|
||||||
AliasKind::Structural,
|
AliasKind::Structural,
|
||||||
);
|
);
|
||||||
let result = register_with_known_var(subs, destination, rank, pools, content);
|
let result = env.register_with_known_var(destination, rank, content);
|
||||||
|
|
||||||
// We only want to unify the actual_var with the alias once
|
// We only want to unify the actual_var with the alias once
|
||||||
// if it's already redirected (and therefore, redundant)
|
// if it's already redirected (and therefore, redundant)
|
||||||
// don't do it again
|
// don't do it again
|
||||||
if !subs.redundant(actual_var) {
|
if !env.subs.redundant(actual_var) {
|
||||||
let descriptor = subs.get(result);
|
let descriptor = env.subs.get(result);
|
||||||
subs.union(result, actual_var, descriptor);
|
env.subs.union(result, actual_var, descriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
result
|
result
|
||||||
|
@ -845,39 +830,39 @@ pub(crate) fn type_to_var_help(
|
||||||
Error => {
|
Error => {
|
||||||
let content = Content::Error;
|
let content = Content::Error;
|
||||||
|
|
||||||
register_with_known_var(subs, destination, rank, pools, content)
|
env.register_with_known_var(destination, rank, content)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Loc { value: var, region }, abilities) in bind_to_abilities {
|
for (Loc { value: var, region }, abilities) in bind_to_abilities {
|
||||||
let abilities = &types[abilities];
|
let abilities = &types[abilities];
|
||||||
match *subs.get_content_unchecked(var) {
|
match *env.subs.get_content_unchecked(var) {
|
||||||
Content::RigidVar(a) => {
|
Content::RigidVar(a) => {
|
||||||
// TODO(multi-abilities): check run cache
|
// TODO(multi-abilities): check run cache
|
||||||
let abilities_slice =
|
let abilities_slice = SubsSlice::extend_new(
|
||||||
SubsSlice::extend_new(&mut subs.symbol_names, abilities.sorted_iter().copied());
|
&mut env.subs.symbol_names,
|
||||||
subs.set_content(var, Content::RigidAbleVar(a, abilities_slice));
|
abilities.sorted_iter().copied(),
|
||||||
|
);
|
||||||
|
env.subs
|
||||||
|
.set_content(var, Content::RigidAbleVar(a, abilities_slice));
|
||||||
}
|
}
|
||||||
Content::RigidAbleVar(_, abs)
|
Content::RigidAbleVar(_, abs)
|
||||||
if (subs.get_subs_slice(abs).iter()).eq(abilities.sorted_iter()) =>
|
if (env.subs.get_subs_slice(abs).iter()).eq(abilities.sorted_iter()) =>
|
||||||
{
|
{
|
||||||
// pass, already bound
|
// pass, already bound
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let abilities_slice =
|
let abilities_slice = SubsSlice::extend_new(
|
||||||
SubsSlice::extend_new(&mut subs.symbol_names, abilities.sorted_iter().copied());
|
&mut env.subs.symbol_names,
|
||||||
|
abilities.sorted_iter().copied(),
|
||||||
let flex_ability = register(
|
|
||||||
subs,
|
|
||||||
rank,
|
|
||||||
pools,
|
|
||||||
Content::FlexAbleVar(None, abilities_slice),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let flex_ability = env.register(rank, Content::FlexAbleVar(None, abilities_slice));
|
||||||
|
|
||||||
let category = Category::OpaqueArg;
|
let category = Category::OpaqueArg;
|
||||||
match unify(
|
match unify(
|
||||||
&mut UEnv::new(subs),
|
&mut UEnv::new(env.subs),
|
||||||
var,
|
var,
|
||||||
flex_ability,
|
flex_ability,
|
||||||
Mode::EQ,
|
Mode::EQ,
|
||||||
|
@ -893,7 +878,7 @@ pub(crate) fn type_to_var_help(
|
||||||
|
|
||||||
if !must_implement_ability.is_empty() {
|
if !must_implement_ability.is_empty() {
|
||||||
let new_problems = obligation_cache.check_obligations(
|
let new_problems = obligation_cache.check_obligations(
|
||||||
subs,
|
env.subs,
|
||||||
abilities_store,
|
abilities_store,
|
||||||
must_implement_ability,
|
must_implement_ability,
|
||||||
AbilityImplError::BadExpr(region, category, flex_ability),
|
AbilityImplError::BadExpr(region, category, flex_ability),
|
||||||
|
@ -926,9 +911,8 @@ pub(crate) fn type_to_var_help(
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn roc_result_to_var(
|
fn roc_result_to_var(
|
||||||
subs: &mut Subs,
|
env: &mut Env,
|
||||||
rank: Rank,
|
rank: Rank,
|
||||||
pools: &mut Pools,
|
|
||||||
arena: &'_ bumpalo::Bump,
|
arena: &'_ bumpalo::Bump,
|
||||||
types: &mut Types,
|
types: &mut Types,
|
||||||
result_type: Index<TypeTag>,
|
result_type: Index<TypeTag>,
|
||||||
|
@ -946,8 +930,8 @@ fn roc_result_to_var(
|
||||||
if let ([err, ok], [err_args, ok_args]) =
|
if let ([err, ok], [err_args, ok_args]) =
|
||||||
(&types[tags_slice], &types[payload_slices_slice])
|
(&types[tags_slice], &types[payload_slices_slice])
|
||||||
{
|
{
|
||||||
debug_assert_eq!(err, &subs.tag_names[0]);
|
debug_assert_eq!(err, &env.subs.tag_names[0]);
|
||||||
debug_assert_eq!(ok, &subs.tag_names[1]);
|
debug_assert_eq!(ok, &env.subs.tag_names[1]);
|
||||||
|
|
||||||
debug_assert_eq!(err_args.len(), 1);
|
debug_assert_eq!(err_args.len(), 1);
|
||||||
debug_assert_eq!(ok_args.len(), 1);
|
debug_assert_eq!(ok_args.len(), 1);
|
||||||
|
@ -955,30 +939,28 @@ fn roc_result_to_var(
|
||||||
if let (Some(err_type), Some(ok_type)) =
|
if let (Some(err_type), Some(ok_type)) =
|
||||||
(err_args.into_iter().next(), ok_args.into_iter().next())
|
(err_args.into_iter().next(), ok_args.into_iter().next())
|
||||||
{
|
{
|
||||||
let err_var = RegisterVariable::with_stack(
|
let err_var =
|
||||||
subs, rank, pools, arena, types, err_type, stack,
|
RegisterVariable::with_stack(env, rank, arena, types, err_type, stack);
|
||||||
);
|
let ok_var =
|
||||||
let ok_var = RegisterVariable::with_stack(
|
RegisterVariable::with_stack(env, rank, arena, types, ok_type, stack);
|
||||||
subs, rank, pools, arena, types, ok_type, stack,
|
|
||||||
);
|
|
||||||
|
|
||||||
let start = subs.variables.len() as u32;
|
let start = env.subs.variables.len() as u32;
|
||||||
let err_slice = SubsSlice::new(start, 1);
|
let err_slice = SubsSlice::new(start, 1);
|
||||||
let ok_slice = SubsSlice::new(start + 1, 1);
|
let ok_slice = SubsSlice::new(start + 1, 1);
|
||||||
|
|
||||||
subs.variables.push(err_var);
|
env.subs.variables.push(err_var);
|
||||||
subs.variables.push(ok_var);
|
env.subs.variables.push(ok_var);
|
||||||
|
|
||||||
let variables = SubsSlice::new(subs.variable_slices.len() as _, 2);
|
let variables = SubsSlice::new(env.subs.variable_slices.len() as _, 2);
|
||||||
subs.variable_slices.push(err_slice);
|
env.subs.variable_slices.push(err_slice);
|
||||||
subs.variable_slices.push(ok_slice);
|
env.subs.variable_slices.push(ok_slice);
|
||||||
|
|
||||||
let union_tags = UnionTags::from_slices(Subs::RESULT_TAG_NAMES, variables);
|
let union_tags = UnionTags::from_slices(Subs::RESULT_TAG_NAMES, variables);
|
||||||
let ext = TagExt::Any(Variable::EMPTY_TAG_UNION);
|
let ext = TagExt::Any(Variable::EMPTY_TAG_UNION);
|
||||||
|
|
||||||
let content = Content::Structure(FlatType::TagUnion(union_tags, ext));
|
let content = Content::Structure(FlatType::TagUnion(union_tags, ext));
|
||||||
|
|
||||||
return register(subs, rank, pools, content);
|
return env.register(rank, content);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1108,9 +1090,8 @@ fn find_tag_name_run(slice: &[TagName], subs: &mut Subs) -> Option<SubsSlice<Tag
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn register_tag_arguments(
|
fn register_tag_arguments(
|
||||||
subs: &mut Subs,
|
env: &mut Env,
|
||||||
rank: Rank,
|
rank: Rank,
|
||||||
pools: &mut Pools,
|
|
||||||
arena: &'_ bumpalo::Bump,
|
arena: &'_ bumpalo::Bump,
|
||||||
types: &mut Types,
|
types: &mut Types,
|
||||||
stack: &mut bumpalo::collections::Vec<'_, TypeToVar>,
|
stack: &mut bumpalo::collections::Vec<'_, TypeToVar>,
|
||||||
|
@ -1119,13 +1100,12 @@ fn register_tag_arguments(
|
||||||
if arguments.is_empty() {
|
if arguments.is_empty() {
|
||||||
VariableSubsSlice::default()
|
VariableSubsSlice::default()
|
||||||
} else {
|
} else {
|
||||||
let new_variables = VariableSubsSlice::reserve_into_subs(subs, arguments.len());
|
let new_variables = VariableSubsSlice::reserve_into_subs(env.subs, arguments.len());
|
||||||
let it = new_variables.indices().zip(arguments.into_iter());
|
let it = new_variables.indices().zip(arguments.into_iter());
|
||||||
|
|
||||||
for (target_index, argument) in it {
|
for (target_index, argument) in it {
|
||||||
let var =
|
let var = RegisterVariable::with_stack(env, rank, arena, types, argument, stack);
|
||||||
RegisterVariable::with_stack(subs, rank, pools, arena, types, argument, stack);
|
env.subs.variables[target_index] = var;
|
||||||
subs.variables[target_index] = var;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
new_variables
|
new_variables
|
||||||
|
@ -1134,9 +1114,8 @@ fn register_tag_arguments(
|
||||||
|
|
||||||
/// Assumes that the tags are sorted and there are no duplicates!
|
/// Assumes that the tags are sorted and there are no duplicates!
|
||||||
fn insert_tags_fast_path(
|
fn insert_tags_fast_path(
|
||||||
subs: &mut Subs,
|
env: &mut Env,
|
||||||
rank: Rank,
|
rank: Rank,
|
||||||
pools: &mut Pools,
|
|
||||||
arena: &'_ bumpalo::Bump,
|
arena: &'_ bumpalo::Bump,
|
||||||
types: &mut Types,
|
types: &mut Types,
|
||||||
union_tags: UnionTags,
|
union_tags: UnionTags,
|
||||||
|
@ -1150,10 +1129,10 @@ fn insert_tags_fast_path(
|
||||||
let arguments_slice = *arguments_slice;
|
let arguments_slice = *arguments_slice;
|
||||||
|
|
||||||
let variable_slice =
|
let variable_slice =
|
||||||
register_tag_arguments(subs, rank, pools, arena, types, stack, arguments_slice);
|
register_tag_arguments(env, rank, arena, types, stack, arguments_slice);
|
||||||
|
|
||||||
let new_variable_slices =
|
let new_variable_slices =
|
||||||
SubsSlice::extend_new(&mut subs.variable_slices, [variable_slice]);
|
SubsSlice::extend_new(&mut env.subs.variable_slices, [variable_slice]);
|
||||||
|
|
||||||
macro_rules! subs_tag_name {
|
macro_rules! subs_tag_name {
|
||||||
($tag_name_slice:expr) => {
|
($tag_name_slice:expr) => {
|
||||||
|
@ -1171,21 +1150,21 @@ fn insert_tags_fast_path(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let new_variable_slices = SubsSlice::reserve_variable_slices(subs, tags.len());
|
let new_variable_slices = SubsSlice::reserve_variable_slices(env.subs, tags.len());
|
||||||
match find_tag_name_run(&types[tags], subs) {
|
match find_tag_name_run(&types[tags], env.subs) {
|
||||||
Some(new_tag_names) => {
|
Some(new_tag_names) => {
|
||||||
let it = (new_variable_slices.indices()).zip(payload_slices.into_iter());
|
let it = (new_variable_slices.indices()).zip(payload_slices.into_iter());
|
||||||
|
|
||||||
for (variable_slice_index, arguments_index) in it {
|
for (variable_slice_index, arguments_index) in it {
|
||||||
let arguments = types[arguments_index];
|
let arguments = types[arguments_index];
|
||||||
subs.variable_slices[variable_slice_index] =
|
env.subs.variable_slices[variable_slice_index] =
|
||||||
register_tag_arguments(subs, rank, pools, arena, types, stack, arguments);
|
register_tag_arguments(env, rank, arena, types, stack, arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
UnionTags::from_slices(new_tag_names, new_variable_slices)
|
UnionTags::from_slices(new_tag_names, new_variable_slices)
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
let new_tag_names = SubsSlice::reserve_tag_names(subs, tags.len());
|
let new_tag_names = SubsSlice::reserve_tag_names(env.subs, tags.len());
|
||||||
|
|
||||||
let it = (new_variable_slices.indices())
|
let it = (new_variable_slices.indices())
|
||||||
.zip(new_tag_names.indices())
|
.zip(new_tag_names.indices())
|
||||||
|
@ -1194,10 +1173,10 @@ fn insert_tags_fast_path(
|
||||||
|
|
||||||
for (((variable_slice_index, tag_name_index), tag_name), arguments_index) in it {
|
for (((variable_slice_index, tag_name_index), tag_name), arguments_index) in it {
|
||||||
let arguments = types[arguments_index];
|
let arguments = types[arguments_index];
|
||||||
subs.variable_slices[variable_slice_index] =
|
env.subs.variable_slices[variable_slice_index] =
|
||||||
register_tag_arguments(subs, rank, pools, arena, types, stack, arguments);
|
register_tag_arguments(env, rank, arena, types, stack, arguments);
|
||||||
|
|
||||||
subs.tag_names[tag_name_index] = types[tag_name].clone();
|
env.subs.tag_names[tag_name_index] = types[tag_name].clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
UnionTags::from_slices(new_tag_names, new_variable_slices)
|
UnionTags::from_slices(new_tag_names, new_variable_slices)
|
||||||
|
@ -1206,9 +1185,8 @@ fn insert_tags_fast_path(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_tags_slow_path(
|
fn insert_tags_slow_path(
|
||||||
subs: &mut Subs,
|
env: &mut Env,
|
||||||
rank: Rank,
|
rank: Rank,
|
||||||
pools: &mut Pools,
|
|
||||||
arena: &'_ bumpalo::Bump,
|
arena: &'_ bumpalo::Bump,
|
||||||
types: &mut Types,
|
types: &mut Types,
|
||||||
union_tags: UnionTags,
|
union_tags: UnionTags,
|
||||||
|
@ -1221,11 +1199,11 @@ fn insert_tags_slow_path(
|
||||||
{
|
{
|
||||||
let tag_argument_types = &types[tag_argument_types_index];
|
let tag_argument_types = &types[tag_argument_types_index];
|
||||||
|
|
||||||
let new_slice = VariableSubsSlice::reserve_into_subs(subs, tag_argument_types.len());
|
let new_slice = VariableSubsSlice::reserve_into_subs(env.subs, tag_argument_types.len());
|
||||||
|
|
||||||
for (i, arg) in (new_slice.indices()).zip(tag_argument_types.into_iter()) {
|
for (i, arg) in (new_slice.indices()).zip(tag_argument_types.into_iter()) {
|
||||||
let var = RegisterVariable::with_stack(subs, rank, pools, arena, types, arg, stack);
|
let var = RegisterVariable::with_stack(env, rank, arena, types, arg, stack);
|
||||||
subs.variables[i] = var;
|
env.subs.variables[i] = var;
|
||||||
}
|
}
|
||||||
|
|
||||||
tag_vars.push((types[tag_index].clone(), new_slice));
|
tag_vars.push((types[tag_index].clone(), new_slice));
|
||||||
|
@ -1233,13 +1211,12 @@ fn insert_tags_slow_path(
|
||||||
|
|
||||||
sort_and_deduplicate(&mut tag_vars);
|
sort_and_deduplicate(&mut tag_vars);
|
||||||
|
|
||||||
UnionTags::insert_slices_into_subs(subs, tag_vars)
|
UnionTags::insert_slices_into_subs(env.subs, tag_vars)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn type_to_union_tags(
|
fn type_to_union_tags(
|
||||||
subs: &mut Subs,
|
env: &mut Env,
|
||||||
rank: Rank,
|
rank: Rank,
|
||||||
pools: &mut Pools,
|
|
||||||
arena: &'_ bumpalo::Bump,
|
arena: &'_ bumpalo::Bump,
|
||||||
types: &mut Types,
|
types: &mut Types,
|
||||||
union_tags: UnionTags,
|
union_tags: UnionTags,
|
||||||
|
@ -1260,10 +1237,10 @@ fn type_to_union_tags(
|
||||||
let ext = Variable::EMPTY_TAG_UNION;
|
let ext = Variable::EMPTY_TAG_UNION;
|
||||||
|
|
||||||
let union_tags = if sorted {
|
let union_tags = if sorted {
|
||||||
insert_tags_fast_path(subs, rank, pools, arena, types, union_tags, stack)
|
insert_tags_fast_path(env, rank, arena, types, union_tags, stack)
|
||||||
} else {
|
} else {
|
||||||
let tag_vars = Vec::with_capacity_in(tags.len(), arena);
|
let tag_vars = Vec::with_capacity_in(tags.len(), arena);
|
||||||
insert_tags_slow_path(subs, rank, pools, arena, types, union_tags, tag_vars, stack)
|
insert_tags_slow_path(env, rank, arena, types, union_tags, tag_vars, stack)
|
||||||
};
|
};
|
||||||
|
|
||||||
(union_tags, TagExt::Any(ext))
|
(union_tags, TagExt::Any(ext))
|
||||||
|
@ -1273,19 +1250,22 @@ fn type_to_union_tags(
|
||||||
|
|
||||||
let temp_ext = {
|
let temp_ext = {
|
||||||
let temp_ext_var =
|
let temp_ext_var =
|
||||||
RegisterVariable::with_stack(subs, rank, pools, arena, types, ext, stack);
|
RegisterVariable::with_stack(env, rank, arena, types, ext, stack);
|
||||||
TagExt::from_can(temp_ext_var, ext_openness)
|
TagExt::from_can(temp_ext_var, ext_openness)
|
||||||
};
|
};
|
||||||
let (it, ext) =
|
let (it, ext) = roc_types::types::gather_tags_unsorted_iter(
|
||||||
roc_types::types::gather_tags_unsorted_iter(subs, UnionTags::default(), temp_ext)
|
env.subs,
|
||||||
|
UnionTags::default(),
|
||||||
|
temp_ext,
|
||||||
|
)
|
||||||
.expect("extension var could not be seen as tag union");
|
.expect("extension var could not be seen as tag union");
|
||||||
|
|
||||||
tag_vars.extend(it.map(|(n, v)| (n.clone(), v)));
|
tag_vars.extend(it.map(|(n, v)| (n.clone(), v)));
|
||||||
|
|
||||||
let union_tags = if tag_vars.is_empty() && sorted {
|
let union_tags = if tag_vars.is_empty() && sorted {
|
||||||
insert_tags_fast_path(subs, rank, pools, arena, types, union_tags, stack)
|
insert_tags_fast_path(env, rank, arena, types, union_tags, stack)
|
||||||
} else {
|
} else {
|
||||||
insert_tags_slow_path(subs, rank, pools, arena, types, union_tags, tag_vars, stack)
|
insert_tags_slow_path(env, rank, arena, types, union_tags, tag_vars, stack)
|
||||||
};
|
};
|
||||||
|
|
||||||
(union_tags, ext)
|
(union_tags, ext)
|
||||||
|
@ -1294,20 +1274,19 @@ fn type_to_union_tags(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_union_lambda(
|
fn create_union_lambda(
|
||||||
subs: &mut Subs,
|
env: &mut Env,
|
||||||
rank: Rank,
|
rank: Rank,
|
||||||
pools: &mut Pools,
|
|
||||||
arena: &'_ bumpalo::Bump,
|
arena: &'_ bumpalo::Bump,
|
||||||
types: &mut Types,
|
types: &mut Types,
|
||||||
closure: Symbol,
|
closure: Symbol,
|
||||||
capture_types: Slice<TypeTag>,
|
capture_types: Slice<TypeTag>,
|
||||||
stack: &mut bumpalo::collections::Vec<'_, TypeToVar>,
|
stack: &mut bumpalo::collections::Vec<'_, TypeToVar>,
|
||||||
) -> UnionLambdas {
|
) -> UnionLambdas {
|
||||||
let variable_slice =
|
let variable_slice = register_tag_arguments(env, rank, arena, types, stack, capture_types);
|
||||||
register_tag_arguments(subs, rank, pools, arena, types, stack, capture_types);
|
let new_variable_slices =
|
||||||
let new_variable_slices = SubsSlice::extend_new(&mut subs.variable_slices, [variable_slice]);
|
SubsSlice::extend_new(&mut env.subs.variable_slices, [variable_slice]);
|
||||||
|
|
||||||
let lambda_name_slice = SubsSlice::extend_new(&mut subs.symbol_names, [closure]);
|
let lambda_name_slice = SubsSlice::extend_new(&mut env.subs.symbol_names, [closure]);
|
||||||
|
|
||||||
UnionLambdas::from_slices(lambda_name_slice, new_variable_slices)
|
UnionLambdas::from_slices(lambda_name_slice, new_variable_slices)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue