mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 16:44:33 +00:00
Deep copy var
This commit is contained in:
parent
94cc22f9ca
commit
aa24cdbef3
2 changed files with 91 additions and 3 deletions
31
src/solve.rs
31
src/solve.rs
|
@ -120,7 +120,23 @@ fn solve(
|
|||
)
|
||||
});
|
||||
|
||||
let actual = var;
|
||||
// Deep copy the vars associated with this symbol before unifying them.
|
||||
// Otherwise, suppose we have this:
|
||||
//
|
||||
// identity = \a -> a
|
||||
//
|
||||
// x = identity 5
|
||||
//
|
||||
// When we call (identity 5), it's important that we not unify
|
||||
// on identity's original vars. If we do, the type of `identity` will be
|
||||
// mutated to be `Int -> Int` instead of `a -> `, which would be incorrect;
|
||||
// the type of `identity` is more general than that!
|
||||
//
|
||||
// Instead, we want to unify on a *copy* of its vars. If the copy unifies
|
||||
// successfully (in this case, to `Int -> Int`), we can use that to
|
||||
// infer the type of this lookup (in this case, `Int`) without ever
|
||||
// having mutated the original.
|
||||
let actual = deep_copy_var(subs, rank, pools, var);
|
||||
let expected = type_to_var(subs, rank, pools, expected_type.clone().get_type());
|
||||
|
||||
// TODO use region when reporting a problem
|
||||
|
@ -501,9 +517,18 @@ fn pool_to_rank_table(
|
|||
|
||||
// Sort the variables into buckets by rank.
|
||||
for &var in young_vars.iter() {
|
||||
let rank = subs.get(var).rank;
|
||||
let desc = subs.get(var);
|
||||
let rank = desc.rank;
|
||||
|
||||
subs.set_mark(var, young_mark);
|
||||
subs.set(
|
||||
var,
|
||||
Descriptor {
|
||||
rank,
|
||||
mark: young_mark,
|
||||
content: desc.content,
|
||||
copy: desc.copy,
|
||||
},
|
||||
);
|
||||
|
||||
pools.get_mut(rank).push(var);
|
||||
}
|
||||
|
|
63
src/subs.rs
63
src/subs.rs
|
@ -239,6 +239,26 @@ impl Subs {
|
|||
|
||||
var_to_err_type(self, &mut state, var)
|
||||
}
|
||||
|
||||
pub fn restore(&mut self, var: Variable) {
|
||||
let desc = self.get(var);
|
||||
|
||||
if desc.copy.is_some() {
|
||||
let content = desc.content;
|
||||
|
||||
self.set(
|
||||
var,
|
||||
Descriptor {
|
||||
content: content.clone(),
|
||||
rank: Rank::none(),
|
||||
mark: Mark::none(),
|
||||
copy: None,
|
||||
},
|
||||
);
|
||||
|
||||
restore_content(self, &content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
@ -644,3 +664,46 @@ fn get_fresh_var_name(state: &mut NameState) -> Lowercase {
|
|||
|
||||
name
|
||||
}
|
||||
|
||||
fn restore_content(subs: &mut Subs, content: &Content) {
|
||||
use crate::subs::Content::*;
|
||||
use crate::subs::FlatType::*;
|
||||
|
||||
match content {
|
||||
FlexVar(_) | RigidVar(_) | Error(_) => (),
|
||||
|
||||
Structure(flat_type) => match flat_type {
|
||||
Apply { args, .. } => {
|
||||
for &var in args {
|
||||
subs.restore(var);
|
||||
}
|
||||
}
|
||||
|
||||
Func(arg_vars, ret_var) => {
|
||||
for &var in arg_vars {
|
||||
subs.restore(var);
|
||||
}
|
||||
|
||||
subs.restore(*ret_var);
|
||||
}
|
||||
|
||||
EmptyRecord => (),
|
||||
|
||||
Record(fields, ext_var) => {
|
||||
for (_, var) in fields {
|
||||
subs.restore(*var);
|
||||
}
|
||||
|
||||
subs.restore(*ext_var);
|
||||
}
|
||||
Erroneous(_) => (),
|
||||
},
|
||||
Alias(_, _, args, var) => {
|
||||
for (_, arg_var) in args {
|
||||
subs.restore(*arg_var);
|
||||
}
|
||||
|
||||
subs.restore(*var);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue