Attempt occurs checks for recursive lambda sets only during monomorphization

This commit is contained in:
Ayaz Hafiz 2022-08-31 16:44:55 -05:00
parent 5d31ec762d
commit 086f7a7e9d
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58
2 changed files with 22 additions and 9 deletions

View file

@ -156,6 +156,7 @@ pub trait MetaCollector: Default + std::fmt::Debug {
/// be kept around, and the record `(member, 1) => specialization-lambda-set` will be
/// associated via [`Self::record_specialization_lambda_set`].
const UNIFYING_SPECIALIZATION: bool;
const IS_LATE: bool;
fn record_specialization_lambda_set(&mut self, member: Symbol, region: u8, var: Variable);
@ -168,6 +169,7 @@ pub trait MetaCollector: Default + std::fmt::Debug {
pub struct NoCollector;
impl MetaCollector for NoCollector {
const UNIFYING_SPECIALIZATION: bool = false;
const IS_LATE: bool = false;
#[inline(always)]
fn record_specialization_lambda_set(&mut self, _member: Symbol, _region: u8, _var: Variable) {}
@ -184,6 +186,7 @@ pub struct SpecializationLsetCollector(pub VecMap<(Symbol, u8), Variable>);
impl MetaCollector for SpecializationLsetCollector {
const UNIFYING_SPECIALIZATION: bool = true;
const IS_LATE: bool = false;
#[inline(always)]
fn record_specialization_lambda_set(&mut self, member: Symbol, region: u8, var: Variable) {
@ -1240,15 +1243,24 @@ fn separate_union_lambdas<M: MetaCollector>(
for (var1, var2) in (left_slice.into_iter()).zip(right_slice.into_iter()) {
let (var1, var2) = (env.subs[var1], env.subs[var2]);
// Lambda sets are effectively tags under another name, and their usage can also result
// in the arguments of a lambda name being recursive. It very well may happen that
// during unification, a lambda set previously marked as not recursive becomes
// recursive. See the docs of [LambdaSet] for one example, or https://github.com/roc-lang/roc/pull/2307.
//
// Like with tag unions, if it has, we'll always pass through this branch. So, take
// this opportunity to promote the lambda set to recursive if need be.
maybe_mark_union_recursive(env, var1);
maybe_mark_union_recursive(env, var2);
if M::IS_LATE {
// Lambda sets are effectively tags under another name, and their usage can also result
// in the arguments of a lambda name being recursive. It very well may happen that
// during unification, a lambda set previously marked as not recursive becomes
// recursive. See the docs of [LambdaSet] for one example, or https://github.com/roc-lang/roc/pull/2307.
//
// Like with tag unions, if it is, we'll always pass through this branch. So, take
// this opportunity to promote the lambda set to recursive if need be.
//
// THEORY: observe that this check only happens in late unification
// (i.e. code generation, typically). We believe this to be correct
// because while recursive lambda sets must be collapsed to the
// code generator, we have not yet observed a case where they must
// collapsed to the type checker of the surface syntax.
// It is possible this assumption will be invalidated!
maybe_mark_union_recursive(env, var1);
maybe_mark_union_recursive(env, var2);
}
// Check whether the two type variables in the closure set are
// unifiable. If they are, we can unify them and continue on assuming