mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-03 19:58:18 +00:00
Correct when fixpoint-fixed type variables can be reunified
With fixpoint-fixing, we don't want to re-unify type variables that were just fixed, because doing so may change their shapes in ways that we explicitly just set them up not to be changed (as fixpoint-fixing clobbers type variable contents). However, this restriction need only apply when we re-unify two type variables that were both involved in the same fixpoint-fixing cycle. If we have a type variable T that was involved in fixpoint-fixing, and we unify it with U that wasn't, we know that the $U \notin \bar{T}$, where $\bar{T}$ is the recursive closure of T. In these cases, we do want to permit the usual in-band unification of $T \sim U$.
This commit is contained in:
parent
f32e329798
commit
e1afd964c7
3 changed files with 80 additions and 2 deletions
|
@ -8283,4 +8283,41 @@ mod solve_expr {
|
|||
"MDict v -> MDict v | v has Eq",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unify_types_with_fixed_fixpoints_outside_fixing_region() {
|
||||
infer_queries!(indoc!(
|
||||
r#"
|
||||
app "test" provides [main] to "./platform"
|
||||
|
||||
Input := [
|
||||
FromJob Job
|
||||
]
|
||||
|
||||
Job := [
|
||||
Job (List Input)
|
||||
]
|
||||
|
||||
job : List Input -> Job
|
||||
job = \inputs ->
|
||||
@Job (Job inputs)
|
||||
|
||||
helloWorld : Job
|
||||
helloWorld =
|
||||
@Job ( Job [ @Input (FromJob greeting) ] )
|
||||
# ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
greeting : Job
|
||||
greeting =
|
||||
job []
|
||||
|
||||
main = (\_ -> "Which platform am I running on now?\n") helloWorld
|
||||
"#
|
||||
),
|
||||
@r###"
|
||||
@Input (FromJob greeting) : [FromJob ([Job (List [FromJob a])] as a)]
|
||||
"###
|
||||
print_only_under_alias: true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2047,3 +2047,39 @@ fn issue_4077_fixed_fixpoint() {
|
|||
RocStr
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn unify_types_with_fixed_fixpoints_outside_fixing_region() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
app "test" provides [main] to "./platform"
|
||||
|
||||
Input := [
|
||||
FromJob Job (List Str),
|
||||
]
|
||||
|
||||
Job := [
|
||||
Job (List Input)
|
||||
]
|
||||
|
||||
job : List Input -> Job
|
||||
job = \inputs ->
|
||||
@Job (Job inputs)
|
||||
|
||||
helloWorld : Job
|
||||
helloWorld =
|
||||
@Job ( Job [ @Input (FromJob greeting []) ] )
|
||||
|
||||
greeting : Job
|
||||
greeting =
|
||||
job []
|
||||
|
||||
main = (\_ -> "OKAY") helloWorld
|
||||
"#
|
||||
),
|
||||
RocStr::from("OKAY"),
|
||||
RocStr
|
||||
);
|
||||
}
|
||||
|
|
|
@ -2814,8 +2814,13 @@ fn unify_shared_tags_merge_new<M: MetaCollector>(
|
|||
new_ext_var: Variable,
|
||||
recursion_var: Rec,
|
||||
) -> Outcome<M> {
|
||||
let was_fixed = env.was_fixed(ctx.first) || env.was_fixed(ctx.second);
|
||||
if was_fixed {
|
||||
if env.was_fixed(ctx.first) && env.was_fixed(ctx.second) {
|
||||
// Both of the tags we're looking at were just involved in fixpoint-fixing, so their types
|
||||
// should be aligned. As such, do not attempt to unify them and update the recursion
|
||||
// pointer again.
|
||||
debug_assert!(env
|
||||
.subs
|
||||
.equivalent_without_compacting(ctx.first, ctx.second));
|
||||
return Default::default();
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue