mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-27 05:49:08 +00:00
Merge pull request #3541 from rtfeldman/rocasync
Changes to get roc-async working
This commit is contained in:
commit
ca38ec4eb5
6 changed files with 158 additions and 164 deletions
|
@ -890,15 +890,7 @@ fn unify_structure<M: MetaCollector>(
|
|||
RecursionVar { structure, .. } => match flat_type {
|
||||
FlatType::TagUnion(_, _) => {
|
||||
// unify the structure with this unrecursive tag union
|
||||
let mut outcome = unify_pool(subs, pool, ctx.first, *structure, ctx.mode);
|
||||
|
||||
if outcome.mismatches.is_empty() {
|
||||
outcome.union(fix_tag_union_recursion_variable(
|
||||
subs, ctx, ctx.first, other,
|
||||
));
|
||||
}
|
||||
|
||||
outcome
|
||||
unify_pool(subs, pool, ctx.first, *structure, ctx.mode)
|
||||
}
|
||||
FlatType::RecursiveTagUnion(rec, _, _) => {
|
||||
debug_assert!(is_recursion_var(subs, *rec));
|
||||
|
@ -907,15 +899,7 @@ fn unify_structure<M: MetaCollector>(
|
|||
}
|
||||
FlatType::FunctionOrTagUnion(_, _, _) => {
|
||||
// unify the structure with this unrecursive tag union
|
||||
let mut outcome = unify_pool(subs, pool, ctx.first, *structure, ctx.mode);
|
||||
|
||||
if outcome.mismatches.is_empty() {
|
||||
outcome.union(fix_tag_union_recursion_variable(
|
||||
subs, ctx, ctx.first, other,
|
||||
));
|
||||
}
|
||||
|
||||
outcome
|
||||
unify_pool(subs, pool, ctx.first, *structure, ctx.mode)
|
||||
}
|
||||
// Only tag unions can be recursive; everything else is an error.
|
||||
_ => mismatch!(
|
||||
|
@ -1376,57 +1360,6 @@ fn unify_lambda_set_help<M: MetaCollector>(
|
|||
whole_outcome
|
||||
}
|
||||
|
||||
/// Ensures that a non-recursive tag union, when unified with a recursion var to become a recursive
|
||||
/// tag union, properly contains a recursion variable that recurses on itself.
|
||||
//
|
||||
// When might this not be the case? For example, in the code
|
||||
//
|
||||
// Indirect : [Indirect ConsList]
|
||||
//
|
||||
// ConsList : [Nil, Cons Indirect]
|
||||
//
|
||||
// l : ConsList
|
||||
// l = Cons (Indirect (Cons (Indirect Nil)))
|
||||
// # ^^^^^^^^^^^^^^^~~~~~~~~~~~~~~~~~~~~~^ region-a
|
||||
// # ~~~~~~~~~~~~~~~~~~~~~ region-b
|
||||
// l
|
||||
//
|
||||
// Suppose `ConsList` has the expanded type `[Nil, Cons [Indirect <rec>]] as <rec>`.
|
||||
// After unifying the tag application annotated "region-b" with the recursion variable `<rec>`,
|
||||
// the tentative total-type of the application annotated "region-a" would be
|
||||
// `<v> = [Nil, Cons [Indirect <v>]] as <rec>`. That is, the type of the recursive tag union
|
||||
// would be inlined at the site "v", rather than passing through the correct recursion variable
|
||||
// "rec" first.
|
||||
//
|
||||
// This is not incorrect from a type perspective, but causes problems later on for e.g. layout
|
||||
// determination, which expects recursion variables to be placed correctly. Attempting to detect
|
||||
// this during layout generation does not work so well because it may be that there *are* recursive
|
||||
// tag unions that should be inlined, and not pass through recursion variables. So instead, try to
|
||||
// resolve these cases here.
|
||||
//
|
||||
// See tests labeled "issue_2810" for more examples.
|
||||
fn fix_tag_union_recursion_variable<M: MetaCollector>(
|
||||
subs: &mut Subs,
|
||||
ctx: &Context,
|
||||
tag_union_promoted_to_recursive: Variable,
|
||||
recursion_var: &Content,
|
||||
) -> Outcome<M> {
|
||||
debug_assert!(matches!(
|
||||
subs.get_content_without_compacting(tag_union_promoted_to_recursive),
|
||||
Structure(FlatType::RecursiveTagUnion(..))
|
||||
));
|
||||
|
||||
let has_recursing_recursive_variable = subs
|
||||
.occurs_including_recursion_vars(tag_union_promoted_to_recursive)
|
||||
.is_err();
|
||||
|
||||
if !has_recursing_recursive_variable {
|
||||
merge(subs, ctx, *recursion_var)
|
||||
} else {
|
||||
Outcome::default()
|
||||
}
|
||||
}
|
||||
|
||||
fn unify_record<M: MetaCollector>(
|
||||
subs: &mut Subs,
|
||||
pool: &mut Pool,
|
||||
|
@ -2097,14 +2030,47 @@ fn unify_shared_tags_new<M: MetaCollector>(
|
|||
|
||||
outcome.union(unify_pool(subs, pool, actual, expected, ctx.mode));
|
||||
|
||||
// clearly, this is very suspicious: these variables have just been unified. And yet,
|
||||
// not doing this leads to stack overflows
|
||||
if let Rec::Right(_) = recursion_var {
|
||||
if outcome.mismatches.is_empty() {
|
||||
matching_vars.push(expected);
|
||||
}
|
||||
} else if outcome.mismatches.is_empty() {
|
||||
matching_vars.push(actual);
|
||||
if outcome.mismatches.is_empty() {
|
||||
// If one of the variables is a recursion var, keep that one, so that we avoid inlining
|
||||
// a recursive tag union type content where we should have a recursion var instead.
|
||||
//
|
||||
// When might this happen? For example, in the code
|
||||
//
|
||||
// Indirect : [Indirect ConsList]
|
||||
//
|
||||
// ConsList : [Nil, Cons Indirect]
|
||||
//
|
||||
// l : ConsList
|
||||
// l = Cons (Indirect (Cons (Indirect Nil)))
|
||||
// # ^^^^^^^^^^^^^^^~~~~~~~~~~~~~~~~~~~~~^ region-a
|
||||
// # ~~~~~~~~~~~~~~~~~~~~~ region-b
|
||||
// l
|
||||
//
|
||||
// Suppose `ConsList` has the expanded type `[Nil, Cons [Indirect <rec>]] as <rec>`.
|
||||
// After unifying the tag application annotated "region-b" with the recursion variable `<rec>`,
|
||||
// we might have that e.g. `actual` is `<rec>` and `expected` is `[Cons (Indirect ...)]`.
|
||||
//
|
||||
// Now, we need to be careful to set the type we choose to represent the merged type
|
||||
// here to be `<rec>`, not the tag union content of `expected`! Otherwise, we will
|
||||
// have lost a recursion variable in the recursive tag union.
|
||||
//
|
||||
// This would not be incorrect from a type perspective, but causes problems later on for e.g.
|
||||
// layout generation, which expects recursion variables to be placed correctly. Attempting to detect
|
||||
// this during layout generation does not work so well because it may be that there *are* recursive
|
||||
// tag unions that should be inlined, and not pass through recursion variables. So instead, resolve
|
||||
// these cases here.
|
||||
//
|
||||
// See tests labeled "issue_2810" for more examples.
|
||||
let merged_var = match (
|
||||
(actual, subs.get_content_unchecked(actual)),
|
||||
(expected, subs.get_content_unchecked(expected)),
|
||||
) {
|
||||
((var, Content::RecursionVar { .. }), _)
|
||||
| (_, (var, Content::RecursionVar { .. })) => var,
|
||||
_ => actual,
|
||||
};
|
||||
|
||||
matching_vars.push(merged_var);
|
||||
}
|
||||
|
||||
total_outcome.union(outcome);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue