Simplify maybe_mark_union_recursive

This commit is contained in:
Ayaz Hafiz 2022-06-01 11:11:16 -05:00
parent 2f29326e7a
commit 0fa4aa8cbd
No known key found for this signature in database
GPG Key ID: 0E2A37416A25EF58
2 changed files with 39 additions and 42 deletions

View File

@ -1758,10 +1758,20 @@ impl Subs {
self.utable.is_redirect(var)
}
/// Determines if there is any variable in [var] that occurs recursively.
///
/// The [Err] variant returns the occuring variable and the chain of variables that led
/// to a recursive occurence, in order of proximity. For example, if the type "r" has a
/// reference chain r -> t1 -> t2 -> r, [occurs] will return `Err(r, [t2, t1, r])`.
///
/// This ignores [Content::RecursionVar]s that occur recursively, because those are
/// already priced in and expected to occur. Use [Subs::occurs_including_recursion_vars] if you
/// need to check for recursion var occurence.
pub fn occurs(&self, var: Variable) -> Result<(), (Variable, Vec<Variable>)> {
occurs(self, &[], var, false)
}
/// Like [Subs::occurs], but also errors when recursion vars occur.
pub fn occurs_including_recursion_vars(
&self,
var: Variable,

View File

@ -1528,50 +1528,37 @@ enum OtherTags2 {
/// Promotes a non-recursive tag union or lambda set to its recursive variant, if it is found to be
/// recursive.
fn maybe_mark_union_recursive(subs: &mut Subs, union_var: Variable) {
'outer: while let Err((recursive, chain)) = subs.occurs(union_var) {
let description = subs.get(recursive);
match description.content {
Content::Structure(FlatType::TagUnion(tags, ext_var)) => {
subs.mark_tag_union_recursive(recursive, tags, ext_var);
}
LambdaSet(self::LambdaSet {
solved,
recursion_var: OptVariable::NONE,
}) => {
subs.mark_lambda_set_recursive(recursive, solved);
}
_ => {
// walk the chain till we find a tag union or lambda set
for v in &chain[..chain.len() - 1] {
let description = subs.get(*v);
match description.content {
Content::Structure(FlatType::TagUnion(tags, ext_var)) => {
subs.mark_tag_union_recursive(*v, tags, ext_var);
continue 'outer;
}
LambdaSet(self::LambdaSet {
solved,
recursion_var: OptVariable::NONE,
}) => {
subs.mark_lambda_set_recursive(*v, solved);
continue 'outer;
}
_ => { /* fall through */ }
}
'outer: while let Err((_, chain)) = subs.occurs(union_var) {
// walk the chain till we find a tag union or lambda set, starting from the variable that
// occurred recursively, which is always at the end of the chain.
for &v in chain.iter().rev() {
let description = subs.get(v);
match description.content {
Content::Structure(FlatType::TagUnion(tags, ext_var)) => {
subs.mark_tag_union_recursive(v, tags, ext_var);
continue 'outer;
}
LambdaSet(self::LambdaSet {
solved,
recursion_var: OptVariable::NONE,
}) => {
subs.mark_lambda_set_recursive(v, solved);
continue 'outer;
}
_ => { /* fall through */ }
}
}
// Might not be any tag union if we only pass through `Apply`s. Otherwise, we have a bug!
if chain.iter().all(|&v| {
matches!(
subs.get_content_without_compacting(v),
Content::Structure(FlatType::Apply(..))
)
}) {
return;
} else {
internal_error!("recursive loop does not contain a tag union")
}
}
// Might not be any tag union if we only pass through `Apply`s. Otherwise, we have a bug!
if chain.iter().all(|&v| {
matches!(
subs.get_content_without_compacting(v),
Content::Structure(FlatType::Apply(..))
)
}) {
return;
} else {
internal_error!("recursive loop does not contain a tag union")
}
}
}