Types SoA for aliases instantiated during solving

This commit is contained in:
Ayaz Hafiz 2022-11-08 12:57:30 -06:00
parent b0bcda4117
commit 7034a4d692
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58
2 changed files with 287 additions and 92 deletions

View file

@ -326,41 +326,19 @@ impl Aliases {
Some((_, typ, delayed_variables, kind)) => (typ, delayed_variables, kind),
};
// TODO(types-soa) store SoA type in aliases directly
let typ = types.from_old_type(typ);
let mut substitutions: MutMap<_, _> = Default::default();
let old_type_variables = delayed_variables.type_variables(&mut self.variables);
let new_type_variables = &subs.variables[alias_variables.type_variables().indices()];
let some_new_vars_are_equivalent = {
// In practice the number of type variables is tiny, so just do a quadratic check
// without allocating.
let mut some_equivalent = false;
for (i, var) in new_type_variables.iter().enumerate() {
for other_var in new_type_variables.iter().skip(i + 1) {
some_equivalent = some_equivalent || var == other_var;
}
}
some_equivalent
};
// If some type variables are equivalent, we have to work over a cloned type variable,
// otherwise we will leave in place an alias without preserving the property of unique
// type variables.
//
// For example, if a delayed alias `Foo a b` is instantiated with args `t1 t1` without cloning,
// then the delayed alias would be updated to `Foo t1 t1`, and now the distinction between the
// two type variables is lost.
let can_reuse_old_definition = !some_new_vars_are_equivalent;
for (old, new) in old_type_variables.iter_mut().zip(new_type_variables) {
// if constraint gen duplicated a type these variables could be the same
// (happens very often in practice)
if old.var != *new {
substitutions.insert(old.var, *new);
if can_reuse_old_definition {
old.var = *new;
}
}
}
@ -374,10 +352,6 @@ impl Aliases {
debug_assert!(opt_abilities.is_none());
let new_var = subs.fresh_unnamed_flex_var();
substitutions.insert(*rec_var, new_var);
if can_reuse_old_definition {
*rec_var = new_var;
}
}
let old_lambda_set_variables = delayed_variables.lambda_set_variables(&mut self.variables);
@ -391,10 +365,6 @@ impl Aliases {
debug_assert!(old.opt_abilities.is_none());
if old.var != *new {
substitutions.insert(old.var, *new);
if can_reuse_old_definition {
old.var = *new;
}
}
}
@ -407,70 +377,29 @@ impl Aliases {
debug_assert!(old.opt_abilities.is_none());
if old.var != *new {
substitutions.insert(old.var, *new);
if can_reuse_old_definition {
old.var = *new;
}
}
}
if !can_reuse_old_definition {
let mut typ = typ.clone();
typ.substitute_variables(&substitutions);
let typ = types.from_old_type(&typ);
let alias_variable = type_to_variable(
subs,
rank,
pools,
problems,
abilities_store,
obligation_cache,
arena,
self,
types,
typ,
false,
);
(alias_variable, kind)
let typ = if !substitutions.is_empty() {
types.clone_with_variable_substitutions(typ, &substitutions)
} else {
if !substitutions.is_empty() {
typ.substitute_variables(&substitutions);
}
typ
};
let mut t = Type::EmptyRec;
std::mem::swap(typ, &mut t);
// assumption: an alias does not (transitively) syntactically contain itself
// (if it did it would have to be a recursive tag union, which we should have fixed up
// during canonicalization)
let t_index = types.from_old_type(&t);
let alias_variable = type_to_variable(
subs,
rank,
pools,
problems,
abilities_store,
obligation_cache,
arena,
self,
types,
t_index,
false,
);
{
match self.aliases.iter_mut().find(|(s, _, _, _)| *s == symbol) {
None => unreachable!(),
Some((_, typ, _, _)) => {
// swap typ back
std::mem::swap(typ, &mut t);
}
}
}
(alias_variable, kind)
}
let alias_variable = type_to_variable(
subs,
rank,
pools,
problems,
abilities_store,
obligation_cache,
arena,
self,
types,
typ,
false,
);
(alias_variable, kind)
}
}