Deep copy var

This commit is contained in:
Richard Feldman 2019-12-20 18:18:16 -05:00
parent 94cc22f9ca
commit aa24cdbef3
2 changed files with 91 additions and 3 deletions

View file

@ -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);
}

View file

@ -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);
}
}
}