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) 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>)> { pub fn occurs(&self, var: Variable) -> Result<(), (Variable, Vec<Variable>)> {
occurs(self, &[], var, false) occurs(self, &[], var, false)
} }
/// Like [Subs::occurs], but also errors when recursion vars occur.
pub fn occurs_including_recursion_vars( pub fn occurs_including_recursion_vars(
&self, &self,
var: Variable, 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 /// Promotes a non-recursive tag union or lambda set to its recursive variant, if it is found to be
/// recursive. /// recursive.
fn maybe_mark_union_recursive(subs: &mut Subs, union_var: Variable) { fn maybe_mark_union_recursive(subs: &mut Subs, union_var: Variable) {
'outer: while let Err((recursive, chain)) = subs.occurs(union_var) { 'outer: while let Err((_, chain)) = subs.occurs(union_var) {
let description = subs.get(recursive); // walk the chain till we find a tag union or lambda set, starting from the variable that
match description.content { // occurred recursively, which is always at the end of the chain.
Content::Structure(FlatType::TagUnion(tags, ext_var)) => { for &v in chain.iter().rev() {
subs.mark_tag_union_recursive(recursive, tags, ext_var); let description = subs.get(v);
} match description.content {
LambdaSet(self::LambdaSet { Content::Structure(FlatType::TagUnion(tags, ext_var)) => {
solved, subs.mark_tag_union_recursive(v, tags, ext_var);
recursion_var: OptVariable::NONE, continue 'outer;
}) => {
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 */ }
}
} }
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! // Might not be any tag union if we only pass through `Apply`s. Otherwise, we have a bug!
if chain.iter().all(|&v| { if chain.iter().all(|&v| {
matches!( matches!(
subs.get_content_without_compacting(v), subs.get_content_without_compacting(v),
Content::Structure(FlatType::Apply(..)) Content::Structure(FlatType::Apply(..))
) )
}) { }) {
return; return;
} else { } else {
internal_error!("recursive loop does not contain a tag union") internal_error!("recursive loop does not contain a tag union")
}
}
} }
} }
} }