diff --git a/crates/compiler/late_solve/src/lib.rs b/crates/compiler/late_solve/src/lib.rs index b32686b014..343c87558d 100644 --- a/crates/compiler/late_solve/src/lib.rs +++ b/crates/compiler/late_solve/src/lib.rs @@ -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 diff --git a/crates/compiler/solve/src/module.rs b/crates/compiler/solve/src/module.rs index 46b1f7d7bc..0267d542a1 100644 --- a/crates/compiler/solve/src/module.rs +++ b/crates/compiler/solve/src/module.rs @@ -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); } } diff --git a/crates/compiler/solve/src/solve.rs b/crates/compiler/solve/src/solve.rs index 3ccfc85559..dd016afea2 100644 --- a/crates/compiler/solve/src/solve.rs +++ b/crates/compiler/solve/src/solve.rs @@ -1900,11 +1900,11 @@ pub fn compact_lambda_sets_of_vars( // 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( .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( ); (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( 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