mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-27 05:49:08 +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
|
@ -2,16 +2,11 @@
|
|||
|
||||
use std::collections::VecDeque;
|
||||
|
||||
use bumpalo::Bump;
|
||||
use roc_can::{
|
||||
abilities::{AbilitiesStore, ImplKey},
|
||||
module::ExposedByModule,
|
||||
};
|
||||
use roc_can::abilities::{AbilitiesStore, ImplKey};
|
||||
use roc_collections::{VecMap, VecSet};
|
||||
use roc_debug_flags::dbg_do;
|
||||
#[cfg(debug_assertions)]
|
||||
use roc_debug_flags::ROC_TRACE_COMPACTION;
|
||||
use roc_derive::SharedDerivedModule;
|
||||
use roc_derive_key::{DeriveError, DeriveKey};
|
||||
use roc_error_macros::{internal_error, todo_abilities};
|
||||
use roc_module::symbol::{ModuleId, Symbol};
|
||||
|
@ -25,8 +20,9 @@ use roc_types::{
|
|||
use roc_unify::unify::{unify, Env as UEnv, Mode, MustImplementConstraints};
|
||||
|
||||
use crate::{
|
||||
ability::builtin_module_with_unlisted_ability_impl, deep_copy::deep_copy_var_in, pools::Pools,
|
||||
solve::introduce,
|
||||
ability::builtin_module_with_unlisted_ability_impl,
|
||||
deep_copy::deep_copy_var_in,
|
||||
env::{DerivedEnv, Env},
|
||||
};
|
||||
|
||||
/// 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)]
|
||||
pub struct AwaitingSpecializations {
|
||||
// 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]
|
||||
pub fn compact_lambda_sets_of_vars<P: Phase>(
|
||||
subs: &mut Subs,
|
||||
derived_env: &DerivedEnv,
|
||||
arena: &Bump,
|
||||
pools: &mut Pools,
|
||||
env: &mut Env,
|
||||
uls_of_var: UlsOfVar,
|
||||
phase: &P,
|
||||
) -> 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`.
|
||||
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 + ...]`.
|
||||
// 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:_:_`,
|
||||
|
@ -332,13 +319,13 @@ pub fn compact_lambda_sets_of_vars<P: Phase>(
|
|||
let mut uls = uls_a.into_vec();
|
||||
|
||||
// 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.dedup();
|
||||
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
|
||||
// flatten lambda sets that reference it more than once.
|
||||
|
@ -350,15 +337,15 @@ pub fn compact_lambda_sets_of_vars<P: Phase>(
|
|||
recursion_var,
|
||||
unspecialized,
|
||||
ambient_function,
|
||||
} = subs.get_lambda_set(lambda_set);
|
||||
let lambda_set_rank = subs.get_rank(lambda_set);
|
||||
let unspecialized = subs.get_subs_slice(unspecialized);
|
||||
} = env.subs.get_lambda_set(lambda_set);
|
||||
let lambda_set_rank = env.subs.get_rank(lambda_set);
|
||||
let unspecialized = env.subs.get_subs_slice(unspecialized);
|
||||
// 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?
|
||||
let (concrete, mut not_concrete): (Vec<_>, Vec<_>) = unspecialized
|
||||
.iter()
|
||||
.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 {
|
||||
// No flattening needs to be done, just return the lambda set as-is
|
||||
return vec![lambda_set];
|
||||
|
@ -373,7 +360,7 @@ pub fn compact_lambda_sets_of_vars<P: Phase>(
|
|||
// lambdas, plus all other unspecialized lambdas.
|
||||
// l' = [solved_lambdas + t1 + ... + tm + C:f:r]
|
||||
let unspecialized = SubsSlice::extend_new(
|
||||
&mut subs.unspecialized_lambda_sets,
|
||||
&mut env.subs.unspecialized_lambda_sets,
|
||||
not_concrete
|
||||
.drain(..)
|
||||
.chain(std::iter::once(concrete_lambda)),
|
||||
|
@ -384,10 +371,10 @@ pub fn compact_lambda_sets_of_vars<P: Phase>(
|
|||
// lambdas.
|
||||
// ln = [[] + C:fn:rn]
|
||||
let unspecialized = SubsSlice::extend_new(
|
||||
&mut subs.unspecialized_lambda_sets,
|
||||
&mut env.subs.unspecialized_lambda_sets,
|
||||
[concrete_lambda],
|
||||
);
|
||||
let var = subs.fresh(Descriptor {
|
||||
let var = env.subs.fresh(Descriptor {
|
||||
content: Content::Error,
|
||||
rank: lambda_set_rank,
|
||||
mark: Mark::NONE,
|
||||
|
@ -396,7 +383,7 @@ pub fn compact_lambda_sets_of_vars<P: Phase>(
|
|||
(var, unspecialized)
|
||||
};
|
||||
|
||||
subs.set_content(
|
||||
env.subs.set_content(
|
||||
var,
|
||||
Content::LambdaSet(LambdaSet {
|
||||
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`.
|
||||
// Sort `uls_a` primarily by `f` (arbitrary order), and secondarily by `r` in descending order.
|
||||
uls_a.sort_by(|v1, v2| {
|
||||
let unspec_1 = subs.get_subs_slice(subs.get_lambda_set(*v1).unspecialized);
|
||||
let unspec_2 = subs.get_subs_slice(subs.get_lambda_set(*v2).unspecialized);
|
||||
let unspec_1 = env
|
||||
.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(_, f2, r2) = unique_unspecialized_lambda(subs, c_a, unspec_2).unwrap();
|
||||
let Uls(_, f1, r1) = unique_unspecialized_lambda(env.subs, c_a, unspec_1).unwrap();
|
||||
let Uls(_, f2, r2) = unique_unspecialized_lambda(env.subs, c_a, unspec_2).unwrap();
|
||||
|
||||
match f1.cmp(&f2) {
|
||||
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`:
|
||||
// 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`.
|
||||
trace_compact!(3start.);
|
||||
for l in uls_a {
|
||||
let compaction_result =
|
||||
compact_lambda_set(subs, derived_env, arena, pools, c_a, l, phase);
|
||||
let compaction_result = compact_lambda_set(env, c_a, l, phase);
|
||||
|
||||
match compaction_result {
|
||||
OneCompactionResult::Compacted {
|
||||
|
@ -474,10 +464,7 @@ enum OneCompactionResult {
|
|||
#[must_use]
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn compact_lambda_set<P: Phase>(
|
||||
subs: &mut Subs,
|
||||
derived_env: &DerivedEnv,
|
||||
arena: &Bump,
|
||||
pools: &mut Pools,
|
||||
env: &mut Env,
|
||||
resolved_concrete: Variable,
|
||||
this_lambda_set: Variable,
|
||||
phase: &P,
|
||||
|
@ -493,23 +480,24 @@ fn compact_lambda_set<P: Phase>(
|
|||
recursion_var,
|
||||
unspecialized,
|
||||
ambient_function: t_f1,
|
||||
} = subs.get_lambda_set(this_lambda_set);
|
||||
let target_rank = subs.get_rank(this_lambda_set);
|
||||
} = env.subs.get_lambda_set(this_lambda_set);
|
||||
let target_rank = env.subs.get_rank(this_lambda_set);
|
||||
|
||||
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`.
|
||||
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
|
||||
// - proceed with specialization
|
||||
// - 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?
|
||||
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 {
|
||||
SpecializeDecision::Specialize(key) => Ok(key),
|
||||
SpecializeDecision::Drop => Err(()),
|
||||
|
@ -522,7 +510,10 @@ fn compact_lambda_set<P: Phase>(
|
|||
// 1b. Remove `C:f:r` from `t_f1`'s lambda set.
|
||||
let new_unspecialized: Vec<_> = unspecialized
|
||||
.iter()
|
||||
.filter(|Uls(v, _, _)| !subs.equivalent_without_compacting(*v, resolved_concrete))
|
||||
.filter(|Uls(v, _, _)| {
|
||||
!env.subs
|
||||
.equivalent_without_compacting(*v, resolved_concrete)
|
||||
})
|
||||
.copied()
|
||||
.collect();
|
||||
debug_assert_eq!(new_unspecialized.len(), unspecialized.len() - 1);
|
||||
|
@ -530,12 +521,12 @@ fn compact_lambda_set<P: Phase>(
|
|||
solved,
|
||||
recursion_var,
|
||||
unspecialized: SubsSlice::extend_new(
|
||||
&mut subs.unspecialized_lambda_sets,
|
||||
&mut env.subs.unspecialized_lambda_sets,
|
||||
new_unspecialized,
|
||||
),
|
||||
ambient_function: t_f1,
|
||||
};
|
||||
subs.set_content(
|
||||
env.subs.set_content(
|
||||
this_lambda_set,
|
||||
Content::LambdaSet(t_f1_lambda_set_without_concrete),
|
||||
);
|
||||
|
@ -545,7 +536,7 @@ fn compact_lambda_set<P: Phase>(
|
|||
Err(()) => {
|
||||
// Do nothing other than to remove the concrete lambda to drop from the lambda set,
|
||||
// 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 {
|
||||
new_obligations: 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(
|
||||
subs,
|
||||
derived_env,
|
||||
env.subs,
|
||||
env.derived_env,
|
||||
phase,
|
||||
f,
|
||||
r,
|
||||
|
@ -568,7 +559,7 @@ fn compact_lambda_set<P: Phase>(
|
|||
Err(()) => {
|
||||
// Do nothing other than to remove the concrete lambda to drop from the lambda set,
|
||||
// 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 {
|
||||
new_obligations: 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
|
||||
// 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`.
|
||||
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(
|
||||
&mut UEnv::new(subs),
|
||||
&mut UEnv::new(env.subs),
|
||||
t_f1,
|
||||
t_f2,
|
||||
Mode::LAMBDA_SET_SPECIALIZATION,
|
||||
Polarity::Pos,
|
||||
)
|
||||
.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 {
|
||||
new_obligations,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue