mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 08:11:12 +00:00
Fix generated type var order
This commit is contained in:
parent
47fdedc63e
commit
036a72e6e5
3 changed files with 56 additions and 12 deletions
|
@ -1,3 +1,4 @@
|
||||||
|
use collections::MutMap;
|
||||||
use subs::{Content, FlatType, Subs, Variable};
|
use subs::{Content, FlatType, Subs, Variable};
|
||||||
use types;
|
use types;
|
||||||
|
|
||||||
|
@ -26,25 +27,52 @@ enum Parens {
|
||||||
Unnecessary,
|
Unnecessary,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// How many times a root variable appeared in Subs.
|
||||||
|
///
|
||||||
|
/// We only care about whether it was a single time or multiple times,
|
||||||
|
/// because single appearances get a wildcard (*) and multiple times
|
||||||
|
/// get a generated letter ("a" etc).
|
||||||
|
enum Appearances {
|
||||||
|
Single,
|
||||||
|
Multiple,
|
||||||
|
}
|
||||||
|
|
||||||
/// Generate names for all type variables, replacing FlexVar(None) with
|
/// Generate names for all type variables, replacing FlexVar(None) with
|
||||||
/// FlexVar(Some(name)) where appropriate. Example: for the identity
|
/// FlexVar(Some(name)) where appropriate. Example: for the identity
|
||||||
/// function, generate a name of "a" for both its argument and return
|
/// function, generate a name of "a" for both its argument and return
|
||||||
/// type variables.
|
/// type variables.
|
||||||
pub fn name_all_type_vars(letters_used: u32, variable: Variable, subs: &mut Subs) -> u32 {
|
///
|
||||||
|
/// It's important that we track insertion order, which is why
|
||||||
|
/// names_needed is a Vec. We also want to count how many times a root
|
||||||
|
/// appears, because we should only generate a name for it if it appears
|
||||||
|
/// more than once.
|
||||||
|
fn find_names_needed(
|
||||||
|
variable: Variable,
|
||||||
|
subs: &mut Subs,
|
||||||
|
roots: &mut Vec<Variable>,
|
||||||
|
root_appearances: &mut MutMap<Variable, Appearances>,
|
||||||
|
) {
|
||||||
use subs::Content::*;
|
use subs::Content::*;
|
||||||
use subs::FlatType::*;
|
use subs::FlatType::*;
|
||||||
|
|
||||||
let mut letters_used = letters_used;
|
|
||||||
|
|
||||||
match subs.get(variable).content {
|
match subs.get(variable).content {
|
||||||
FlexVar(None) => {
|
FlexVar(None) => {
|
||||||
let root = subs.get_root_key(variable);
|
let root = subs.get_root_key(variable);
|
||||||
|
|
||||||
// If this var is *not* its own root, then the
|
// If this var is *not* its own root, then the
|
||||||
// root var necessarily appears in multiple places.
|
// root var necessarily appears in multiple places.
|
||||||
// Generate a name for it!
|
// We need a name for it!
|
||||||
if variable != root {
|
match root_appearances.get(&root) {
|
||||||
letters_used = name_root(letters_used, root, subs);
|
Some(Appearances::Single) => {
|
||||||
|
root_appearances.insert(root, Appearances::Multiple);
|
||||||
|
}
|
||||||
|
Some(Appearances::Multiple) => {
|
||||||
|
// It's already multiple, so do nothing!
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
roots.push(root);
|
||||||
|
root_appearances.insert(root, Appearances::Single);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FlexVar(Some(_)) => {
|
FlexVar(Some(_)) => {
|
||||||
|
@ -56,20 +84,36 @@ pub fn name_all_type_vars(letters_used: u32, variable: Variable, subs: &mut Subs
|
||||||
args,
|
args,
|
||||||
}) => {
|
}) => {
|
||||||
for var in args {
|
for var in args {
|
||||||
letters_used = name_all_type_vars(letters_used, var, subs);
|
find_names_needed(var, subs, roots, root_appearances);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Structure(Func(arg_vars, ret_var)) => {
|
Structure(Func(arg_vars, ret_var)) => {
|
||||||
for var in arg_vars {
|
for var in arg_vars {
|
||||||
letters_used = name_all_type_vars(letters_used, var, subs);
|
find_names_needed(var, subs, roots, root_appearances);
|
||||||
}
|
}
|
||||||
|
|
||||||
letters_used = name_all_type_vars(letters_used, ret_var, subs);
|
find_names_needed(ret_var, subs, roots, root_appearances);
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
letters_used
|
pub fn name_all_type_vars(variable: Variable, subs: &mut Subs) {
|
||||||
|
let mut roots = Vec::new();
|
||||||
|
let mut letters_used = 0;
|
||||||
|
let mut appearances = MutMap::default();
|
||||||
|
|
||||||
|
// Populate names_needed
|
||||||
|
find_names_needed(variable, subs, &mut roots, &mut appearances);
|
||||||
|
|
||||||
|
for root in roots {
|
||||||
|
match appearances.get(&root) {
|
||||||
|
Some(Appearances::Multiple) => {
|
||||||
|
letters_used = name_root(letters_used, root, subs);
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn name_root(letters_used: u32, root: Variable, subs: &mut Subs) -> u32 {
|
fn name_root(letters_used: u32, root: Variable, subs: &mut Subs) -> u32 {
|
||||||
|
|
|
@ -8,7 +8,7 @@ pub struct Subs {
|
||||||
utable: UnificationTable<InPlace<Variable>>,
|
utable: UnificationTable<InPlace<Variable>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, PartialEq, Eq, Clone)]
|
#[derive(Copy, PartialEq, Eq, Clone, Hash)]
|
||||||
pub struct Variable(u32);
|
pub struct Variable(u32);
|
||||||
|
|
||||||
impl Variable {
|
impl Variable {
|
||||||
|
|
|
@ -21,7 +21,7 @@ mod test_infer {
|
||||||
|
|
||||||
let content = infer_expr(&mut subs, procedures, &output.constraint, variable);
|
let content = infer_expr(&mut subs, procedures, &output.constraint, variable);
|
||||||
|
|
||||||
name_all_type_vars(0, variable, &mut subs);
|
name_all_type_vars(variable, &mut subs);
|
||||||
|
|
||||||
let actual_str = content_to_string(content, &mut subs);
|
let actual_str = content_to_string(content, &mut subs);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue