Merge remote-tracking branch 'origin/main' into abilities-syntax

This commit is contained in:
Richard Feldman 2023-08-10 20:29:27 -04:00
commit 2da41be29f
No known key found for this signature in database
GPG key ID: F1F21AA5B1D9E43B
524 changed files with 47536 additions and 15089 deletions

View file

@ -1,5 +1,6 @@
use roc_can::abilities::AbilitiesStore;
use roc_can::expr::PendingDerives;
use roc_checkmate::with_checkmate;
use roc_collections::{VecMap, VecSet};
use roc_debug_flags::dbg_do;
#[cfg(debug_assertions)]
@ -12,17 +13,19 @@ use roc_solve_problem::{
NotDerivableContext, NotDerivableDecode, NotDerivableEncode, NotDerivableEq, TypeError,
UnderivableReason, Unfulfilled,
};
use roc_solve_schema::UnificationMode;
use roc_types::num::NumericRange;
use roc_types::subs::{
instantiate_rigids, Content, FlatType, GetSubsSlice, Rank, RecordFields, Subs, SubsSlice,
TupleElems, Variable,
};
use roc_types::types::{AliasKind, Category, MemberImpl, PatternCategory, Polarity, Types};
use roc_unify::unify::{Env, MustImplementConstraints};
use roc_unify::unify::MustImplementConstraints;
use roc_unify::unify::{MustImplementAbility, Obligated};
use roc_unify::Env as UEnv;
use crate::solve::type_to_var;
use crate::solve::{Aliases, Pools};
use crate::env::InferenceEnv;
use crate::{aliases::Aliases, to_var::type_to_var};
#[derive(Debug, Clone)]
pub enum AbilityImplError {
@ -56,7 +59,7 @@ pub struct PendingDerivesTable(
impl PendingDerivesTable {
pub fn new(
subs: &mut Subs,
env: &mut InferenceEnv,
types: &mut Types,
aliases: &mut Aliases,
pending_derives: PendingDerives,
@ -81,17 +84,16 @@ impl PendingDerivesTable {
// Neither rank nor pools should matter here.
let typ = types.from_old_type(&typ);
let opaque_var = type_to_var(
subs,
env,
Rank::toplevel(),
problems,
abilities_store,
obligation_cache,
&mut Pools::default(),
types,
aliases,
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,
_ => internal_error!("Non-opaque in derives table"),
};
@ -828,6 +830,12 @@ trait DerivableVisitor {
context: NotDerivableContext::NoContext,
})
}
ErasedLambda => {
return Err(NotDerivable {
var,
context: NotDerivableContext::NoContext,
})
}
Error => {
return Err(NotDerivable {
var,
@ -1280,16 +1288,19 @@ impl DerivableVisitor for DeriveEq {
subs: &mut Subs,
content_var: Variable,
) -> Result<Descend, NotDerivable> {
use roc_unify::unify::{unify, Mode};
use roc_unify::unify::unify;
// Of the floating-point types,
// only Dec implements Eq.
let mut env = Env::new(subs);
// TODO(checkmate): pass checkmate through
let unified = unify(
&mut env,
&mut with_checkmate!({
on => UEnv::new(subs, None),
off => UEnv::new(subs),
}),
content_var,
Variable::DECIMAL,
Mode::EQ,
UnificationMode::EQ,
Polarity::Pos,
);
match unified {
@ -1323,8 +1334,7 @@ pub fn type_implementing_specialization(
.filter(|mia| mia.ability == ability)
.count()
} < 2,
"Multiple variables bound to an ability - this is ambiguous and should have been caught in canonicalization: {:?}",
specialization_must_implement_constraints
"Multiple variables bound to an ability - this is ambiguous and should have been caught in canonicalization: {specialization_must_implement_constraints:?}"
);
specialization_must_implement_constraints
@ -1408,7 +1418,7 @@ pub fn resolve_ability_specialization<R: AbilityResolver>(
ability_member: Symbol,
specialization_var: Variable,
) -> Result<Resolved, ResolveError> {
use roc_unify::unify::{unify, Mode};
use roc_unify::unify::unify;
let (parent_ability, signature_var) = resolver
.member_parent_and_signature_var(ability_member, subs)
@ -1419,10 +1429,14 @@ pub fn resolve_ability_specialization<R: AbilityResolver>(
instantiate_rigids(subs, signature_var);
let (_vars, must_implement_ability, _lambda_sets_to_specialize, _meta) = unify(
&mut Env::new(subs),
// TODO(checkmate): pass checkmate through
&mut with_checkmate!({
on => UEnv::new(subs, None),
off => UEnv::new(subs),
}),
specialization_var,
signature_var,
Mode::EQ,
UnificationMode::EQ,
Polarity::Pos,
)
.expect_success(

View file

@ -0,0 +1,329 @@
use roc_can::abilities::AbilitiesStore;
use roc_collections::{soa::Index, MutMap};
use roc_error_macros::internal_error;
use roc_module::symbol::Symbol;
use roc_solve_problem::TypeError;
use roc_types::{
subs::{AliasVariables, Content, FlatType, Rank, Subs, SubsSlice, TagExt, UnionTags, Variable},
types::{Alias, AliasKind, OptAbleVar, Type, TypeTag, Types},
};
use crate::to_var::type_to_var_help;
use crate::{ability::ObligationCache, env::InferenceEnv};
#[derive(Debug, Clone, Copy)]
struct DelayedAliasVariables {
start: u32,
type_variables_len: u8,
lambda_set_variables_len: u8,
recursion_variables_len: u8,
infer_ext_in_output_variables_len: u8,
}
impl DelayedAliasVariables {
fn recursion_variables(self, variables: &mut [OptAbleVar]) -> &mut [OptAbleVar] {
let start = self.start as usize
+ (self.type_variables_len + self.lambda_set_variables_len) as usize;
let length = self.recursion_variables_len as usize;
&mut variables[start..][..length]
}
fn lambda_set_variables(self, variables: &mut [OptAbleVar]) -> &mut [OptAbleVar] {
let start = self.start as usize + self.type_variables_len as usize;
let length = self.lambda_set_variables_len as usize;
&mut variables[start..][..length]
}
fn type_variables(self, variables: &mut [OptAbleVar]) -> &mut [OptAbleVar] {
let start = self.start as usize;
let length = self.type_variables_len as usize;
&mut variables[start..][..length]
}
fn infer_ext_in_output_variables(self, variables: &mut [OptAbleVar]) -> &mut [OptAbleVar] {
let start = self.start as usize
+ (self.type_variables_len
+ self.lambda_set_variables_len
+ self.recursion_variables_len) as usize;
let length = self.infer_ext_in_output_variables_len as usize;
&mut variables[start..][..length]
}
}
#[derive(Debug, Default)]
pub struct Aliases {
aliases: Vec<(Symbol, Index<TypeTag>, DelayedAliasVariables, AliasKind)>,
variables: Vec<OptAbleVar>,
}
impl Aliases {
pub fn with_capacity(cap: usize) -> Self {
Self {
aliases: Vec::with_capacity(cap),
variables: Vec::with_capacity(cap * 2),
}
}
pub fn insert(&mut self, types: &mut Types, symbol: Symbol, alias: Alias) {
let alias_variables =
{
let start = self.variables.len() as _;
self.variables.extend(
alias
.type_variables
.iter()
.map(|x| OptAbleVar::from(&x.value)),
);
self.variables.extend(alias.lambda_set_variables.iter().map(
|x| match x.as_inner() {
Type::Variable(v) => OptAbleVar::unbound(*v),
_ => unreachable!("lambda set type is not a variable"),
},
));
let recursion_variables_len = alias.recursion_variables.len() as _;
self.variables.extend(
alias
.recursion_variables
.iter()
.copied()
.map(OptAbleVar::unbound),
);
self.variables.extend(
alias
.infer_ext_in_output_variables
.iter()
.map(|v| OptAbleVar::unbound(*v)),
);
DelayedAliasVariables {
start,
type_variables_len: alias.type_variables.len() as _,
lambda_set_variables_len: alias.lambda_set_variables.len() as _,
recursion_variables_len,
infer_ext_in_output_variables_len: alias.infer_ext_in_output_variables.len()
as _,
}
};
// TODO: can we construct Aliases from TypeTag directly?
let alias_typ = types.from_old_type(&alias.typ);
self.aliases
.push((symbol, alias_typ, alias_variables, alias.kind));
}
fn instantiate_result_result(
env: &mut InferenceEnv,
rank: Rank,
alias_variables: AliasVariables,
) -> Variable {
let tag_names_slice = Subs::RESULT_TAG_NAMES;
let err_slice = SubsSlice::new(alias_variables.variables_start + 1, 1);
let ok_slice = SubsSlice::new(alias_variables.variables_start, 1);
let variable_slices =
SubsSlice::extend_new(&mut env.subs.variable_slices, [err_slice, ok_slice]);
let union_tags = UnionTags::from_slices(tag_names_slice, variable_slices);
let ext_var = TagExt::Any(Variable::EMPTY_TAG_UNION);
let flat_type = FlatType::TagUnion(union_tags, ext_var);
let content = Content::Structure(flat_type);
env.register(rank, content)
}
/// Build an alias of the form `Num range := range`
fn build_num_opaque(
env: &mut InferenceEnv,
rank: Rank,
symbol: Symbol,
range_var: Variable,
) -> Variable {
let content = Content::Alias(
symbol,
AliasVariables::insert_into_subs(env.subs, [range_var], [], []),
range_var,
AliasKind::Opaque,
);
env.register(rank, content)
}
fn instantiate_builtin_aliases_real_var(
&mut self,
env: &mut InferenceEnv,
rank: Rank,
symbol: Symbol,
alias_variables: AliasVariables,
) -> Option<(Variable, AliasKind)> {
match symbol {
Symbol::RESULT_RESULT => {
let var = Self::instantiate_result_result(env, rank, alias_variables);
Some((var, AliasKind::Structural))
}
Symbol::NUM_NUM | Symbol::NUM_INTEGER | Symbol::NUM_FLOATINGPOINT => {
// Num range := range | Integer range := range | FloatingPoint range := range
let range_var = env.subs.variables[alias_variables.variables_start as usize];
Some((range_var, AliasKind::Opaque))
}
Symbol::NUM_INT => {
// Int range : Num (Integer range)
//
// build `Integer range := range`
let integer_content_var = Self::build_num_opaque(
env,
rank,
Symbol::NUM_INTEGER,
env.subs.variables[alias_variables.variables_start as usize],
);
// build `Num (Integer range) := Integer range`
let num_content_var =
Self::build_num_opaque(env, rank, Symbol::NUM_NUM, integer_content_var);
Some((num_content_var, AliasKind::Structural))
}
Symbol::NUM_FRAC => {
// Frac range : Num (FloatingPoint range)
//
// build `FloatingPoint range := range`
let fpoint_content_var = Self::build_num_opaque(
env,
rank,
Symbol::NUM_FLOATINGPOINT,
env.subs.variables[alias_variables.variables_start as usize],
);
// build `Num (FloatingPoint range) := FloatingPoint range`
let num_content_var =
Self::build_num_opaque(env, rank, Symbol::NUM_NUM, fpoint_content_var);
Some((num_content_var, AliasKind::Structural))
}
Symbol::NUM_SIGNED8 => Some((Variable::SIGNED8, AliasKind::Opaque)),
Symbol::NUM_SIGNED16 => Some((Variable::SIGNED16, AliasKind::Opaque)),
Symbol::NUM_SIGNED32 => Some((Variable::SIGNED32, AliasKind::Opaque)),
Symbol::NUM_SIGNED64 => Some((Variable::SIGNED64, AliasKind::Opaque)),
Symbol::NUM_SIGNED128 => Some((Variable::SIGNED128, AliasKind::Opaque)),
Symbol::NUM_UNSIGNED8 => Some((Variable::UNSIGNED8, AliasKind::Opaque)),
Symbol::NUM_UNSIGNED16 => Some((Variable::UNSIGNED16, AliasKind::Opaque)),
Symbol::NUM_UNSIGNED32 => Some((Variable::UNSIGNED32, AliasKind::Opaque)),
Symbol::NUM_UNSIGNED64 => Some((Variable::UNSIGNED64, AliasKind::Opaque)),
Symbol::NUM_UNSIGNED128 => Some((Variable::UNSIGNED128, AliasKind::Opaque)),
Symbol::NUM_BINARY32 => Some((Variable::BINARY32, AliasKind::Opaque)),
Symbol::NUM_BINARY64 => Some((Variable::BINARY64, AliasKind::Opaque)),
_ => None,
}
}
pub fn instantiate_real_var(
&mut self,
env: &mut InferenceEnv,
rank: Rank,
problems: &mut Vec<TypeError>,
abilities_store: &AbilitiesStore,
obligation_cache: &mut ObligationCache,
arena: &bumpalo::Bump,
types: &mut Types,
symbol: Symbol,
alias_variables: AliasVariables,
) -> (Variable, AliasKind) {
// hardcoded instantiations for builtin aliases
if let Some((var, kind)) =
self.instantiate_builtin_aliases_real_var(env, rank, symbol, alias_variables)
{
return (var, kind);
}
let (typ, delayed_variables, kind) =
match self.aliases.iter().find(|(s, _, _, _)| *s == symbol) {
None => internal_error!(
"Alias {:?} not registered in delayed aliases! {:?}",
symbol,
&self.aliases
),
Some(&(_, typ, delayed_variables, kind)) => (typ, delayed_variables, kind),
};
let mut substitutions: MutMap<_, _> = Default::default();
let old_type_variables = delayed_variables.type_variables(&mut self.variables);
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) {
// if constraint gen duplicated a type these variables could be the same
// (happens very often in practice)
if old.var != *new {
substitutions.insert(old.var, *new);
}
}
for OptAbleVar {
var: rec_var,
opt_abilities,
} in delayed_variables
.recursion_variables(&mut self.variables)
.iter_mut()
{
debug_assert!(opt_abilities.is_none());
let new_var = env.subs.fresh_unnamed_flex_var();
substitutions.insert(*rec_var, new_var);
}
let old_lambda_set_variables = delayed_variables.lambda_set_variables(&mut self.variables);
let new_lambda_set_variables =
&env.subs.variables[alias_variables.lambda_set_variables().indices()];
for (old, new) in old_lambda_set_variables
.iter_mut()
.zip(new_lambda_set_variables)
{
debug_assert!(old.opt_abilities.is_none());
if old.var != *new {
substitutions.insert(old.var, *new);
}
}
let old_infer_ext_vars =
delayed_variables.infer_ext_in_output_variables(&mut self.variables);
let new_infer_ext_vars =
&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) {
debug_assert!(old.opt_abilities.is_none());
if old.var != *new {
substitutions.insert(old.var, *new);
}
}
let typ = if !substitutions.is_empty() {
types.clone_with_variable_substitutions(typ, &substitutions)
} else {
typ
};
let alias_variable = type_to_var_help(
env,
rank,
problems,
abilities_store,
obligation_cache,
arena,
self,
types,
typ,
false,
);
(alias_variable, kind)
}
}

View file

@ -0,0 +1,375 @@
use std::ops::ControlFlow;
use bumpalo::Bump;
use roc_error_macros::internal_error;
use roc_types::{
subs::{
self, AliasVariables, Content, Descriptor, FlatType, GetSubsSlice, Mark, OptVariable, Rank,
RecordFields, Subs, SubsSlice, TagExt, TupleElems, UnionLabels, Variable,
},
types::{RecordField, Uls},
};
use crate::env::SolveEnv;
// TODO: eventually, we could possibly use the arena in Env instead.
pub(crate) fn deep_copy_var_in(
env: &mut SolveEnv,
rank: Rank,
var: Variable,
arena: &Bump,
) -> Variable {
let mut visited = bumpalo::collections::Vec::with_capacity_in(256, arena);
let pool = env.pools.get_mut(rank);
let var = env.subs.get_root_key(var);
match deep_copy_var_decision(env.subs, rank, var) {
ControlFlow::Break(copy) => copy,
ControlFlow::Continue(copy) => {
deep_copy_var_help(env.subs, rank, pool, &mut visited, var, copy);
// we have tracked all visited variables, and can now traverse them
// in one go (without looking at the UnificationTable) and clear the copy field
for var in visited {
env.subs.set_copy_unchecked(var, OptVariable::NONE);
}
copy
}
}
}
#[inline]
fn has_trivial_copy(subs: &Subs, root_var: Variable) -> Option<Variable> {
let existing_copy = subs.get_copy_unchecked(root_var);
if let Some(copy) = existing_copy.into_variable() {
Some(copy)
} else if subs.get_rank_unchecked(root_var) != Rank::GENERALIZED {
Some(root_var)
} else {
None
}
}
#[inline]
fn deep_copy_var_decision(
subs: &mut Subs,
max_rank: Rank,
var: Variable,
) -> ControlFlow<Variable, Variable> {
let var = subs.get_root_key(var);
if let Some(copy) = has_trivial_copy(subs, var) {
ControlFlow::Break(copy)
} else {
let copy_descriptor = Descriptor {
content: Content::Structure(FlatType::EmptyTagUnion),
rank: max_rank,
mark: Mark::NONE,
copy: OptVariable::NONE,
};
let copy = subs.fresh(copy_descriptor);
// Link the original variable to the new variable. This lets us
// avoid making multiple copies of the variable we are instantiating.
//
// Need to do this before recursively copying to avoid looping.
subs.set_mark_unchecked(var, Mark::NONE);
subs.set_copy_unchecked(var, copy.into());
ControlFlow::Continue(copy)
}
}
fn deep_copy_var_help(
subs: &mut Subs,
max_rank: Rank,
pool: &mut Vec<Variable>,
visited: &mut bumpalo::collections::Vec<'_, Variable>,
initial_source: Variable,
initial_copy: Variable,
) -> Variable {
use roc_types::subs::Content::*;
use roc_types::subs::FlatType::*;
struct DeepCopyVarWork {
source: Variable,
copy: Variable,
}
let initial = DeepCopyVarWork {
source: initial_source,
copy: initial_copy,
};
let mut stack = vec![initial];
macro_rules! work {
($variable:expr) => {{
let var = subs.get_root_key($variable);
match deep_copy_var_decision(subs, max_rank, var) {
ControlFlow::Break(copy) => copy,
ControlFlow::Continue(copy) => {
stack.push(DeepCopyVarWork { source: var, copy });
copy
}
}
}};
}
macro_rules! copy_sequence {
($length:expr, $variables:expr) => {{
let new_variables = SubsSlice::reserve_into_subs(subs, $length as _);
for (target_index, var_index) in (new_variables.indices()).zip($variables) {
let var = subs[var_index];
let copy_var = work!(var);
subs.variables[target_index] = copy_var;
}
new_variables
}};
}
macro_rules! copy_union {
($tags:expr) => {{
let new_variable_slices = SubsSlice::reserve_variable_slices(subs, $tags.len());
let it = (new_variable_slices.indices()).zip($tags.variables());
for (target_index, index) in it {
let slice = subs[index];
let new_variables = copy_sequence!(slice.len(), slice);
subs.variable_slices[target_index] = new_variables;
}
UnionLabels::from_slices($tags.labels(), new_variable_slices)
}};
}
// When generalizing annotations with `Openness` extensions
// we want to promote them to `Any`, so that usages at
// specialized sites can grow unboundedly and are not bound to
// openness-polymorphism.
macro_rules! copy_tag_ext {
($ext:expr) => {
TagExt::Any(work!($ext.var()))
};
}
while let Some(DeepCopyVarWork { source: var, copy }) = stack.pop() {
visited.push(var);
pool.push(copy);
let content = *subs.get_content_unchecked(var);
// Now we recursively copy the content of the variable.
// We have already marked the variable as copied, so we
// will not repeat this work or crawl this variable again.
match content {
Structure(flat_type) => {
let new_flat_type = match flat_type {
Apply(symbol, arguments) => {
let new_arguments = copy_sequence!(arguments.len(), arguments);
Apply(symbol, new_arguments)
}
Func(arguments, closure_var, ret_var) => {
let new_ret_var = work!(ret_var);
let new_closure_var = work!(closure_var);
let new_arguments = copy_sequence!(arguments.len(), arguments);
Func(new_arguments, new_closure_var, new_ret_var)
}
same @ EmptyRecord | same @ EmptyTuple | same @ EmptyTagUnion => same,
Record(fields, ext_var) => {
let record_fields = {
let new_variables =
copy_sequence!(fields.len(), fields.iter_variables());
// When copying a let-generalized record to a specialized region, rigid
// optionals just become optionals.
let field_types = subs.get_subs_slice(fields.record_fields());
let has_rigid_optional_field = field_types
.iter()
.any(|f| matches!(f, RecordField::RigidOptional(..)));
let new_field_types_start = if has_rigid_optional_field {
let field_types = field_types.to_vec();
let slice = SubsSlice::extend_new(
&mut subs.record_fields,
field_types.into_iter().map(|f| match f {
RecordField::RigidOptional(())
| RecordField::RigidRequired(()) => internal_error!("Rigid optional/required should be generalized to non-rigid by this point"),
RecordField::Demanded(_)
| RecordField::Required(_)
| RecordField::Optional(_) => f,
}),
);
slice.start
} else {
fields.field_types_start
};
RecordFields {
length: fields.length,
field_names_start: fields.field_names_start,
variables_start: new_variables.start,
field_types_start: new_field_types_start,
}
};
Record(record_fields, work!(ext_var))
}
Tuple(elems, ext_var) => {
let tuple_elems = {
let new_variables = copy_sequence!(elems.len(), elems.iter_variables());
TupleElems {
length: elems.length,
variables_start: new_variables.start,
elem_index_start: elems.elem_index_start,
}
};
Tuple(tuple_elems, work!(ext_var))
}
TagUnion(tags, ext_var) => {
let union_tags = copy_union!(tags);
TagUnion(union_tags, copy_tag_ext!(ext_var))
}
FunctionOrTagUnion(tag_name, symbol, ext_var) => {
FunctionOrTagUnion(tag_name, symbol, copy_tag_ext!(ext_var))
}
RecursiveTagUnion(rec_var, tags, ext_var) => {
let union_tags = copy_union!(tags);
RecursiveTagUnion(work!(rec_var), union_tags, copy_tag_ext!(ext_var))
}
};
subs.set_content_unchecked(copy, Structure(new_flat_type));
}
FlexVar(_) | FlexAbleVar(_, _) | Error | ErasedLambda => {
subs.set_content_unchecked(copy, content);
}
RecursionVar {
opt_name,
structure,
} => {
let content = RecursionVar {
opt_name,
structure: work!(structure),
};
subs.set_content_unchecked(copy, content);
}
RigidVar(name) => {
subs.set_content_unchecked(copy, FlexVar(Some(name)));
}
RigidAbleVar(name, ability) => {
subs.set_content_unchecked(copy, FlexAbleVar(Some(name), ability));
}
Alias(symbol, arguments, real_type_var, kind) => {
let new_variables =
copy_sequence!(arguments.all_variables_len, arguments.all_variables());
let new_arguments = AliasVariables {
variables_start: new_variables.start,
..arguments
};
let new_real_type_var = work!(real_type_var);
let new_content = Alias(symbol, new_arguments, new_real_type_var, kind);
subs.set_content_unchecked(copy, new_content);
}
LambdaSet(subs::LambdaSet {
solved,
recursion_var,
unspecialized,
ambient_function: ambient_function_var,
}) => {
let lambda_set_var = copy;
let new_solved = copy_union!(solved);
let new_rec_var = recursion_var.map(|v| work!(v));
let new_unspecialized = SubsSlice::reserve_uls_slice(subs, unspecialized.len());
for (new_uls_index, uls_index) in
(new_unspecialized.into_iter()).zip(unspecialized.into_iter())
{
let Uls(var, sym, region) = subs[uls_index];
let new_var = work!(var);
deep_copy_uls_precondition(subs, var, new_var);
subs[new_uls_index] = Uls(new_var, sym, region);
subs.uls_of_var.add(new_var, lambda_set_var);
}
let new_ambient_function_var = work!(ambient_function_var);
debug_assert_ne!(
ambient_function_var, new_ambient_function_var,
"lambda set cloned but its ambient function wasn't?"
);
subs.set_content_unchecked(
lambda_set_var,
LambdaSet(subs::LambdaSet {
solved: new_solved,
recursion_var: new_rec_var,
unspecialized: new_unspecialized,
ambient_function: new_ambient_function_var,
}),
);
}
RangedNumber(range) => {
let new_content = RangedNumber(range);
subs.set_content_unchecked(copy, new_content);
}
}
}
initial_copy
}
#[inline(always)]
fn deep_copy_uls_precondition(subs: &Subs, original_var: Variable, new_var: Variable) {
if cfg!(debug_assertions) {
let content = subs.get_content_without_compacting(original_var);
debug_assert!(
matches!(
content,
Content::FlexAbleVar(..) | Content::RigidAbleVar(..)
),
"var in unspecialized lamba set is not bound to an ability, it is {:?}",
roc_types::subs::SubsFmtContent(content, subs)
);
debug_assert!(
original_var != new_var,
"unspecialized lamba set var was not instantiated"
);
}
}

View file

@ -0,0 +1,132 @@
use bumpalo::Bump;
use roc_can::{constraint::Constraints, module::ExposedByModule};
use roc_checkmate::with_checkmate;
use roc_derive::SharedDerivedModule;
use roc_types::subs::{Content, Descriptor, Mark, OptVariable, Rank, Subs, Variable};
use roc_unify::Env as UEnv;
use crate::{FunctionKind, Pools};
pub struct DerivedEnv<'a> {
pub derived_module: &'a SharedDerivedModule,
/// Exposed types needed by the derived module.
pub exposed_types: &'a ExposedByModule,
}
/// Environment necessary for solving and specialization.
pub struct SolveEnv<'a> {
pub arena: &'a Bump,
pub derived_env: &'a DerivedEnv<'a>,
pub subs: &'a mut Subs,
pub pools: &'a mut Pools,
#[cfg(debug_assertions)]
pub checkmate: &'a mut Option<roc_checkmate::Collector>,
}
/// Environment necessary for inference.
pub struct InferenceEnv<'a> {
pub constraints: &'a Constraints,
pub function_kind: FunctionKind,
pub arena: &'a Bump,
pub derived_env: &'a DerivedEnv<'a>,
pub subs: &'a mut Subs,
pub pools: &'a mut Pools,
#[cfg(debug_assertions)]
pub checkmate: Option<roc_checkmate::Collector>,
}
impl<'a> SolveEnv<'a> {
/// 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]) {
introduce(self.subs, self.pools, rank, vars);
}
/// Retrieves an environment for unification.
pub fn uenv(&mut self) -> UEnv {
with_checkmate!({
on => UEnv::new(self.subs, self.checkmate.as_mut()),
off => UEnv::new(self.subs),
})
}
}
impl<'a> InferenceEnv<'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]) {
introduce(self.subs, self.pools, rank, 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
}
/// Retrieves an environment for unification.
pub fn uenv(&mut self) -> UEnv {
with_checkmate!({
on => UEnv::new(self.subs, self.checkmate.as_mut()),
off => UEnv::new(self.subs),
})
}
pub fn as_solve_env(&mut self) -> SolveEnv {
SolveEnv {
arena: self.arena,
derived_env: self.derived_env,
subs: self.subs,
pools: self.pools,
#[cfg(debug_assertions)]
checkmate: &mut self.checkmate,
}
}
}
/// Introduce some variables to Pools at the given rank.
/// Also, set each of their ranks in Subs to be the given rank.
fn introduce(subs: &mut Subs, pools: &mut Pools, rank: Rank, vars: &[Variable]) {
let pool: &mut Vec<Variable> = pools.get_mut(rank);
for &var in vars.iter() {
subs.set_rank(var, rank);
}
pool.extend(vars);
}

View file

@ -0,0 +1,8 @@
/// How function kinds should be represented in the type system.
#[derive(Debug, Clone, Copy)]
pub enum FunctionKind {
/// Function values are solved to lambda sets; lambda sets are the kind.
LambdaSet,
/// Function values are erased, no kind is introduced.
Erased,
}

View file

@ -3,8 +3,23 @@
#![warn(clippy::dbg_macro)]
// See github.com/roc-lang/roc/issues/800 for discussion of the large_enum_variant check.
#![allow(clippy::large_enum_variant)]
// TODO to be removed
#![allow(clippy::too_many_arguments)]
pub mod ability;
pub mod module;
pub mod solve;
pub mod specialize;
mod aliases;
mod deep_copy;
mod env;
mod kinds;
mod pools;
mod to_var;
pub use aliases::Aliases;
pub use env::{DerivedEnv, InferenceEnv, SolveEnv};
pub use kinds::FunctionKind;
pub use pools::Pools;
pub use to_var::type_to_var;

View file

@ -1,6 +1,8 @@
use crate::solve::{self, Aliases};
use crate::solve::RunSolveOutput;
use crate::FunctionKind;
use crate::{aliases::Aliases, solve};
use roc_can::abilities::{AbilitiesStore, ResolvedImpl};
use roc_can::constraint::{Constraint as ConstraintSoa, Constraints};
use roc_can::constraint::{Constraint, Constraints};
use roc_can::expr::PendingDerives;
use roc_can::module::{ExposedByModule, ResolvedImplementations, RigidVariables};
use roc_collections::all::MutMap;
@ -53,20 +55,50 @@ pub struct SolvedModule {
pub exposed_types: ExposedTypesStorageSubs,
}
#[allow(clippy::too_many_arguments)] // TODO: put params in a context/env var
pub struct SolveConfig<'a> {
/// The module we are solving.
pub home: ModuleId,
pub constraints: &'a Constraints,
pub root_constraint: Constraint,
/// All types introduced in the module. Canonicalized, but not necessarily yet associated with
/// a variable substitution.
pub types: Types,
/// How functions should be kinded.
pub function_kind: FunctionKind,
/// Table of types introduced in this module that claim to derive an ability implementation.
/// Due for checking and instantiation after the solver runs over the module.
pub pending_derives: PendingDerives,
/// Types exposed by other modules.
/// Available for late instantiation of imports, lambda sets, or ability types.
pub exposed_by_module: &'a ExposedByModule,
/// The unique `#Derived` module, used to generate and retrieve derived ability
/// implementations.
/// Needed during solving to resolve lambda sets from derived implementations that escape into
/// the user module.
pub derived_module: SharedDerivedModule,
#[cfg(debug_assertions)]
/// The checkmate collector for this module.
pub checkmate: Option<roc_checkmate::Collector>,
}
pub struct SolveOutput {
pub subs: Solved<Subs>,
pub scope: solve::Scope,
pub errors: Vec<TypeError>,
pub resolved_abilities_store: AbilitiesStore,
#[cfg(debug_assertions)]
pub checkmate: Option<roc_checkmate::Collector>,
}
pub fn run_solve(
home: ModuleId,
types: Types,
constraints: &Constraints,
constraint: ConstraintSoa,
config: SolveConfig<'_>,
rigid_variables: RigidVariables,
mut subs: Subs,
mut aliases: Aliases,
mut abilities_store: AbilitiesStore,
pending_derives: PendingDerives,
exposed_by_module: &ExposedByModule,
derived_module: SharedDerivedModule,
) -> (Solved<Subs>, solve::Env, Vec<TypeError>, AbilitiesStore) {
) -> SolveOutput {
for (var, name) in rigid_variables.named {
subs.rigid_var(var, name);
}
@ -84,21 +116,27 @@ pub fn run_solve(
let mut problems = Vec::new();
// Run the solver to populate Subs.
let (solved_subs, solved_env) = solve::run(
home,
types,
constraints,
let RunSolveOutput {
solved,
scope,
#[cfg(debug_assertions)]
checkmate,
} = solve::run(
config,
&mut problems,
subs,
&mut aliases,
&constraint,
pending_derives,
&mut abilities_store,
exposed_by_module,
derived_module,
);
(solved_subs, solved_env, problems, abilities_store)
SolveOutput {
subs: solved,
scope,
errors: problems,
resolved_abilities_store: abilities_store,
#[cfg(debug_assertions)]
checkmate,
}
}
/// Copies exposed types and all ability specializations, which may be implicitly exposed.

View file

@ -0,0 +1,59 @@
use roc_types::subs::{Rank, Variable};
const DEFAULT_POOLS: usize = 8;
#[derive(Clone, Debug)]
pub struct Pools(Vec<Vec<Variable>>);
impl Default for Pools {
fn default() -> Self {
Pools::new(DEFAULT_POOLS)
}
}
impl Pools {
pub fn new(num_pools: usize) -> Self {
Pools(vec![Vec::new(); num_pools])
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn get_mut(&mut self, rank: Rank) -> &mut Vec<Variable> {
match self.0.get_mut(rank.into_usize()) {
Some(reference) => reference,
None => panic!("Compiler bug: could not find pool at rank {rank}"),
}
}
pub fn get(&self, rank: Rank) -> &Vec<Variable> {
match self.0.get(rank.into_usize()) {
Some(reference) => reference,
None => panic!("Compiler bug: could not find pool at rank {rank}"),
}
}
pub fn iter(&self) -> std::slice::Iter<'_, Vec<Variable>> {
self.0.iter()
}
pub fn split_last(mut self) -> (Vec<Variable>, Vec<Vec<Variable>>) {
let last = self
.0
.pop()
.unwrap_or_else(|| panic!("Attempted to split_last() on non-empty Pools"));
(last, self.0)
}
pub fn extend_to(&mut self, n: usize) {
for _ in self.len()..n {
self.0.push(Vec::new());
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,40 @@
use roc_module::symbol::Symbol;
use roc_types::subs::Variable;
/// The scope of the solver, as symbols are introduced.
#[derive(Clone, Debug, Default)]
pub struct Scope {
symbols: Vec<Symbol>,
variables: Vec<Variable>,
}
impl Scope {
pub fn vars_by_symbol(&self) -> impl Iterator<Item = (Symbol, Variable)> + '_ {
let it1 = self.symbols.iter().copied();
let it2 = self.variables.iter().copied();
it1.zip(it2)
}
#[inline(always)]
pub fn get_var_by_symbol(&self, symbol: &Symbol) -> Option<Variable> {
self.symbols
.iter()
.position(|s| s == symbol)
.map(|index| self.variables[index])
}
#[inline(always)]
pub fn insert_symbol_var_if_vacant(&mut self, symbol: Symbol, var: Variable) {
match self.symbols.iter().position(|s| *s == symbol) {
None => {
// symbol is not in vars_by_symbol yet; insert it
self.symbols.push(symbol);
self.variables.push(var);
}
Some(_) => {
// do nothing
}
}
}
}

View file

@ -2,19 +2,15 @@
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};
use roc_solve_schema::UnificationMode;
use roc_types::{
subs::{
get_member_lambda_sets_at_region, Content, Descriptor, GetSubsSlice, LambdaSet, Mark,
@ -22,11 +18,12 @@ use roc_types::{
},
types::{AliasKind, MemberImpl, Polarity, Uls},
};
use roc_unify::unify::{unify, Env as UEnv, Mode, MustImplementConstraints};
use roc_unify::unify::{unify, MustImplementConstraints};
use crate::{
ability::builtin_module_with_unlisted_ability_impl,
solve::{deep_copy_var_in, introduce, Pools},
deep_copy::deep_copy_var_in,
env::{DerivedEnv, SolveEnv},
};
/// What phase in the compiler is reaching out to specialize lambda sets?
@ -121,12 +118,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
@ -197,9 +188,9 @@ fn trace_compaction_step_1(subs: &Subs, c_a: Variable, uls_a: &[Variable]) {
.collect::<Vec<_>>()
.join(",");
eprintln!("===lambda set compaction===");
eprintln!(" concrete type: {:?}", c_a);
eprintln!(" concrete type: {c_a:?}");
eprintln!(" step 1:");
eprintln!(" uls_a = {{ {} }}", uls_a);
eprintln!(" uls_a = {{ {uls_a} }}");
}
#[cfg(debug_assertions)]
@ -215,7 +206,7 @@ fn trace_compaction_step_2(subs: &Subs, uls_a: &[Variable]) {
.collect::<Vec<_>>()
.join(",");
eprintln!(" step 2:");
eprintln!(" uls_a' = {{ {} }}", uls_a);
eprintln!(" uls_a' = {{ {uls_a} }}");
}
#[cfg(debug_assertions)]
@ -236,9 +227,9 @@ fn trace_compaction_step_3iter_start(
);
let t_f1 = roc_types::subs::SubsFmtContent(subs.get_content_without_compacting(t_f1), subs);
let t_f2 = roc_types::subs::SubsFmtContent(subs.get_content_without_compacting(t_f2), subs);
eprintln!(" - iteration: {:?}", iteration_lambda_set);
eprintln!(" {:?}", t_f1);
eprintln!(" ~ {:?}", t_f2);
eprintln!(" - iteration: {iteration_lambda_set:?}");
eprintln!(" {t_f1:?}");
eprintln!(" ~ {t_f2:?}");
}
#[cfg(debug_assertions)]
@ -249,7 +240,7 @@ fn trace_compaction_step_3iter_end(subs: &Subs, t_f_result: Variable, skipped: b
if skipped {
eprintln!(" SKIP");
}
eprintln!(" = {:?}\n", t_f_result);
eprintln!(" = {t_f_result:?}\n");
}
macro_rules! trace_compact {
@ -305,10 +296,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 SolveEnv,
uls_of_var: UlsOfVar,
phase: &P,
) -> CompactionResult {
@ -320,7 +308,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 +320,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 +338,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 +361,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 +372,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 +384,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 +402,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 +421,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 +431,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 +465,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 SolveEnv,
resolved_concrete: Variable,
this_lambda_set: Variable,
phase: &P,
@ -493,23 +481,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 +511,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 +522,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 +537,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 +546,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 +560,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 +570,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 env.uenv(),
t_f1,
t_f2,
Mode::LAMBDA_SET_SPECIALIZATION,
UnificationMode::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,
@ -699,6 +691,7 @@ fn make_specialization_decision<P: Phase>(
| FlexVar(..)
| RigidVar(..)
| LambdaSet(..)
| ErasedLambda
| RangedNumber(..) => {
internal_error!("unexpected")
}

File diff suppressed because it is too large Load diff