Import ambient functions into storage subs properly

This commit is contained in:
Ayaz Hafiz 2022-07-06 12:24:39 -04:00
parent 6c79efa43a
commit ae7ad36d60
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58
3 changed files with 52 additions and 22 deletions

View file

@ -9,7 +9,7 @@ use roc_collections::MutMap;
use roc_derive_key::GlobalDerivedSymbols;
use roc_module::symbol::ModuleId;
use roc_solve::solve::{compact_lambda_sets_of_vars, Phase, Pools};
use roc_types::subs::{Content, LambdaSet};
use roc_types::subs::{Content, FlatType, LambdaSet};
use roc_types::subs::{ExposedTypesStorageSubs, Subs, Variable};
use roc_unify::unify::{unify as unify_unify, Mode, Unified};
@ -121,19 +121,17 @@ impl Phase for LatePhase<'_> {
.as_inner()
.get_lambda_set(storage_lambda_set_var);
todo!("I don't think the ambient function is in the storage subs properly yet");
let copied = module_types
.storage_subs
.export_variable_to(target_subs, storage_lambda_set_var);
let our_lambda_set_var = copied.variable;
.export_variable_to(target_subs, ambient_function);
let our_ambient_function_var = copied.variable;
debug_assert!(matches!(
target_subs.get_content_without_compacting(our_lambda_set_var),
Content::LambdaSet(..)
target_subs.get_content_without_compacting(our_ambient_function_var),
Content::Structure(FlatType::Func(..))
));
our_lambda_set_var
our_ambient_function_var
}
}
}
@ -162,7 +160,7 @@ pub fn unify(
let late_phase = LatePhase { home, abilities };
compact_lambda_sets_of_vars(
let must_implement_constraints = compact_lambda_sets_of_vars(
subs,
arena,
&mut pools,
@ -170,6 +168,11 @@ pub fn unify(
&late_phase,
derived_symbols,
);
// 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.
// After we land https://github.com/rtfeldman/roc/issues/3207 this concern should totally
// go away.
let _ = must_implement_constraints;
// Pools are only used to keep track of variable ranks for generalization purposes.
// Since we break generalization during monomorphization, `pools` is irrelevant
// here. We only need it for `compact_lambda_sets_of_vars`, which is also used in a

View file

@ -6,9 +6,10 @@ use roc_can::module::RigidVariables;
use roc_collections::all::MutMap;
use roc_collections::VecMap;
use roc_derive_key::GlobalDerivedSymbols;
use roc_error_macros::internal_error;
use roc_module::symbol::Symbol;
use roc_types::solved_types::Solved;
use roc_types::subs::{ExposedTypesStorageSubs, StorageSubs, Subs, Variable};
use roc_types::subs::{Content, ExposedTypesStorageSubs, FlatType, StorageSubs, Subs, Variable};
use roc_types::types::Alias;
#[derive(Debug)]
@ -100,10 +101,29 @@ pub fn exposed_types_storage_subs(
for (_, member_specialization) in solved_specializations.iter() {
for (_, &specialization_lset_var) in member_specialization.specialization_lambda_sets.iter()
{
let new_var = storage_subs
.import_variable_from(subs, specialization_lset_var)
let specialization_lset_ambient_function_var = subs
.get_lambda_set(specialization_lset_var)
.ambient_function;
// Import the ambient function of this specialization lambda set; that will import the
// lambda set as well. The ambient function is needed for the lambda set compaction
// algorithm.
let imported_lset_ambient_function_var = storage_subs
.import_variable_from(subs, specialization_lset_ambient_function_var)
.variable;
stored_specialization_lambda_set_vars.insert(specialization_lset_var, new_var);
let imported_lset_var = match storage_subs
.as_inner()
.get_content_without_compacting(imported_lset_ambient_function_var)
{
Content::Structure(FlatType::Func(_, lambda_set_var, _)) => *lambda_set_var,
content => internal_error!(
"ambient lambda set function import is not a function, found: {:?}",
roc_types::subs::SubsFmtContent(content, storage_subs.as_inner())
),
};
stored_specialization_lambda_set_vars
.insert(specialization_lset_var, imported_lset_var);
}
}

View file

@ -1900,11 +1900,11 @@ 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);
// 1. Let each `l` in `uls_a` be of form `[concrete_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`.
// In this case, let `t1, ... tm` be the other unspecialized lambdas not of form `C:_:_`,
// that is, none of which are now specialized to the type `C`. Then, deconstruct
// `l` such that `l' = [concrete_lambdas + t1 + ... + tm + C:f:r]` and `l1 = [[] + C:f1:r1], ..., ln = [[] + C:fn:rn]`.
// `l` such that `l' = [solved_lambdas + t1 + ... + tm + C:f:r]` and `l1 = [[] + C:f1:r1], ..., ln = [[] + C:fn:rn]`.
// Replace `l` with `l', l1, ..., ln` in `uls_a`, flattened.
// TODO: the flattening step described above
let uls_a = uls_a.into_vec();
@ -1939,7 +1939,9 @@ pub fn compact_lambda_sets_of_vars<P: Phase>(
.enumerate()
.map(|(i, concrete_lambda)| {
let (var, unspecialized) = if i == 0 {
// `l' = [concrete_lambdas + t1 + ... + tm + C:f:r`
// The first lambda set contains one concrete lambda, plus all solved
// lambdas, plus all other unspecialized lambdas.
// l' = [solved_lambdas + t1 + ... + tm + C:f:r]
let unspecialized = SubsSlice::extend_new(
&mut subs.unspecialized_lambda_sets,
not_concrete
@ -1948,6 +1950,8 @@ pub fn compact_lambda_sets_of_vars<P: Phase>(
);
(lambda_set, unspecialized)
} else {
// All the other lambda sets consists only of their respective concrete
// lambdas.
// ln = [[] + C:fn:rn]
let unspecialized = SubsSlice::extend_new(
&mut subs.unspecialized_lambda_sets,
@ -2100,7 +2104,7 @@ fn compact_lambda_set<P: Phase>(
let specialization_symbol_slice =
UnionLabels::insert_into_subs(subs, vec![(specialization_symbol, vec![])]);
// TODO: This is WRONG, fix it!
let ambient_function = subs.fresh_unnamed_flex_var();
let ambient_function = Variable::NULL;
let _lambda_set_for_derived = subs.fresh(Descriptor {
content: Content::LambdaSet(subs::LambdaSet {
solved: specialization_symbol_slice,
@ -2501,11 +2505,14 @@ fn type_to_variable<'a>(
($typ:expr, $ambient_function_policy:expr) => {{
match RegisterVariable::from_type(subs, rank, pools, arena, $typ) {
RegisterVariable::Direct(var) => {
if delayed_alias_lambda_set_vars.len() > 0 {
let slice = subs.get_subs_slice(delayed_alias_lambda_set_vars);
if slice.contains(&var) {
$ambient_function_policy.link_to_alias_lambda_set_var(subs, var);
}
let slice = subs.get_subs_slice(delayed_alias_lambda_set_vars);
if slice.contains(&var)
|| matches!(
$ambient_function_policy,
AmbientFunctionPolicy::Function(..)
)
{
$ambient_function_policy.link_to_alias_lambda_set_var(subs, var);
}
var