mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-27 22:09:09 +00:00
Print recursion vars correctly
This commit is contained in:
parent
7306e131b9
commit
3497237c99
8 changed files with 79 additions and 57 deletions
|
@ -2051,7 +2051,7 @@ pub mod test_constrain {
|
||||||
let subs = solved.inner_mut();
|
let subs = solved.inner_mut();
|
||||||
|
|
||||||
// name type vars
|
// name type vars
|
||||||
name_all_type_vars(var, subs);
|
let named_result = name_all_type_vars(var, subs);
|
||||||
|
|
||||||
let content = subs.get_content_without_compacting(var);
|
let content = subs.get_content_without_compacting(var);
|
||||||
|
|
||||||
|
@ -2063,7 +2063,7 @@ pub mod test_constrain {
|
||||||
all_ident_ids: dep_idents,
|
all_ident_ids: dep_idents,
|
||||||
};
|
};
|
||||||
|
|
||||||
let actual_str = content_to_string(content, subs, mod_id, &interns);
|
let actual_str = content_to_string(content, subs, mod_id, &interns, named_result);
|
||||||
|
|
||||||
assert_eq!(actual_str, expected_str);
|
assert_eq!(actual_str, expected_str);
|
||||||
}
|
}
|
||||||
|
|
|
@ -237,10 +237,10 @@ mod test_load {
|
||||||
expected_types: &mut HashMap<&str, &str>,
|
expected_types: &mut HashMap<&str, &str>,
|
||||||
) {
|
) {
|
||||||
for (symbol, expr_var) in &def.pattern_vars {
|
for (symbol, expr_var) in &def.pattern_vars {
|
||||||
name_all_type_vars(*expr_var, subs);
|
let named_result = name_all_type_vars(*expr_var, subs);
|
||||||
|
|
||||||
let content = subs.get_content_without_compacting(*expr_var);
|
let content = subs.get_content_without_compacting(*expr_var);
|
||||||
let actual_str = content_to_string(content, subs, home, interns);
|
let actual_str = content_to_string(content, subs, home, interns, named_result);
|
||||||
let fully_qualified = symbol.fully_qualified(interns, home).to_string();
|
let fully_qualified = symbol.fully_qualified(interns, home).to_string();
|
||||||
let expected_type = expected_types
|
let expected_type = expected_types
|
||||||
.remove(fully_qualified.as_str())
|
.remove(fully_qualified.as_str())
|
||||||
|
|
|
@ -172,18 +172,12 @@ mod solve_expr {
|
||||||
|
|
||||||
let subs = solved.inner_mut();
|
let subs = solved.inner_mut();
|
||||||
|
|
||||||
// name type vars
|
|
||||||
for var in exposed_to_host.values() {
|
|
||||||
name_all_type_vars(*var, subs);
|
|
||||||
}
|
|
||||||
|
|
||||||
let content = {
|
|
||||||
debug_assert!(exposed_to_host.len() == 1);
|
debug_assert!(exposed_to_host.len() == 1);
|
||||||
let (_symbol, variable) = exposed_to_host.into_iter().next().unwrap();
|
let (_symbol, variable) = exposed_to_host.into_iter().next().unwrap();
|
||||||
subs.get_content_without_compacting(variable)
|
let named_result = name_all_type_vars(variable, subs);
|
||||||
};
|
let content = subs.get_content_without_compacting(variable);
|
||||||
|
|
||||||
let actual_str = content_to_string(content, subs, home, &interns);
|
let actual_str = content_to_string(content, subs, home, &interns, named_result);
|
||||||
|
|
||||||
Ok((type_problems, can_problems, actual_str))
|
Ok((type_problems, can_problems, actual_str))
|
||||||
}
|
}
|
||||||
|
@ -282,9 +276,9 @@ mod solve_expr {
|
||||||
let var = find_type_at(region, &decls)
|
let var = find_type_at(region, &decls)
|
||||||
.expect(&format!("No type for {} ({:?})!", &text, region));
|
.expect(&format!("No type for {} ({:?})!", &text, region));
|
||||||
|
|
||||||
name_all_type_vars(var, subs);
|
let named_result = name_all_type_vars(var, subs);
|
||||||
let content = subs.get_content_without_compacting(var);
|
let content = subs.get_content_without_compacting(var);
|
||||||
let actual_str = content_to_string(content, subs, home, &interns);
|
let actual_str = content_to_string(content, subs, home, &interns, named_result);
|
||||||
|
|
||||||
solved_queries.push(format!("{} : {}", text, actual_str));
|
solved_queries.push(format!("{} : {}", text, actual_str));
|
||||||
}
|
}
|
||||||
|
@ -5445,26 +5439,19 @@ mod solve_expr {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn copy_vars_referencing_copied_vars_specialized() {
|
fn generalize_and_specialize_recursion_var() {
|
||||||
infer_eq_without_problem(
|
infer_eq_without_problem(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
Job a : [ Job [ Command ] (Job a) (List (Job a)) a ]
|
Job a : [ Job (List (Job a)) a ]
|
||||||
|
|
||||||
job : Job Str
|
job : Job Str
|
||||||
|
|
||||||
when job is
|
when job is
|
||||||
Job _ j lst _ ->
|
Job lst s -> P lst s
|
||||||
when j is
|
|
||||||
Job _ _ _ s ->
|
|
||||||
{ j, lst, s }
|
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
// TODO: this means that we're doing our job correctly, as now both `Job a`s have been
|
"[ P (List [ Job (List a) Str ] as a) Str ]*",
|
||||||
// specialized to the same type, and the second destructuring proves the reified type
|
|
||||||
// is `Job Str`. But we should just print the structure of the recursive type directly.
|
|
||||||
// See https://github.com/rtfeldman/roc/issues/2513
|
|
||||||
"{ j : a, lst : List a, s : Str }",
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -233,7 +233,11 @@ fn find_names_needed(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn name_all_type_vars(variable: Variable, subs: &mut Subs) {
|
pub struct NamedResult {
|
||||||
|
recursion_structs_to_expand: Vec<Variable>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name_all_type_vars(variable: Variable, subs: &mut Subs) -> NamedResult {
|
||||||
let mut roots = Vec::new();
|
let mut roots = Vec::new();
|
||||||
let mut letters_used = 0;
|
let mut letters_used = 0;
|
||||||
let mut appearances = MutMap::default();
|
let mut appearances = MutMap::default();
|
||||||
|
@ -242,12 +246,29 @@ pub fn name_all_type_vars(variable: Variable, subs: &mut Subs) {
|
||||||
// Populate names_needed
|
// Populate names_needed
|
||||||
find_names_needed(variable, subs, &mut roots, &mut appearances, &mut taken);
|
find_names_needed(variable, subs, &mut roots, &mut appearances, &mut taken);
|
||||||
|
|
||||||
|
let mut recursion_structs_to_expand = vec![];
|
||||||
|
|
||||||
for root in roots {
|
for root in roots {
|
||||||
// show the type variable number instead of `*`. useful for debugging
|
// show the type variable number instead of `*`. useful for debugging
|
||||||
// set_root_name(root, (format!("<{:?}>", root).into()), subs);
|
// set_root_name(root, (format!("<{:?}>", root).into()), subs);
|
||||||
if let Some(Appearances::Multiple) = appearances.get(&root) {
|
match appearances.get(&root) {
|
||||||
|
Some(Appearances::Multiple) => {
|
||||||
letters_used = name_root(letters_used, root, subs, &mut taken);
|
letters_used = name_root(letters_used, root, subs, &mut taken);
|
||||||
}
|
}
|
||||||
|
Some(Appearances::Single) => {
|
||||||
|
if let Content::RecursionVar { structure, .. } =
|
||||||
|
subs.get_content_without_compacting(root)
|
||||||
|
{
|
||||||
|
recursion_structs_to_expand.push(*structure);
|
||||||
|
letters_used = name_root(letters_used, root, subs, &mut taken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NamedResult {
|
||||||
|
recursion_structs_to_expand,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -312,6 +333,7 @@ fn set_root_name(root: Variable, name: Lowercase, subs: &mut Subs) {
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct Context<'a> {
|
struct Context<'a> {
|
||||||
able_variables: Vec<(&'a str, Symbol)>,
|
able_variables: Vec<(&'a str, Symbol)>,
|
||||||
|
recursion_structs_to_expand: Vec<Variable>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn content_to_string(
|
pub fn content_to_string(
|
||||||
|
@ -319,10 +341,14 @@ pub fn content_to_string(
|
||||||
subs: &Subs,
|
subs: &Subs,
|
||||||
home: ModuleId,
|
home: ModuleId,
|
||||||
interns: &Interns,
|
interns: &Interns,
|
||||||
|
named_result: NamedResult,
|
||||||
) -> String {
|
) -> String {
|
||||||
let mut buf = String::new();
|
let mut buf = String::new();
|
||||||
let env = Env { home, interns };
|
let env = Env { home, interns };
|
||||||
let mut ctx = Context::default();
|
let mut ctx = Context {
|
||||||
|
able_variables: vec![],
|
||||||
|
recursion_structs_to_expand: named_result.recursion_structs_to_expand,
|
||||||
|
};
|
||||||
|
|
||||||
write_content(&env, &mut ctx, content, subs, &mut buf, Parens::Unnecessary);
|
write_content(&env, &mut ctx, content, subs, &mut buf, Parens::Unnecessary);
|
||||||
|
|
||||||
|
@ -381,12 +407,34 @@ fn write_content<'a>(
|
||||||
ctx.able_variables.push((name, *ability));
|
ctx.able_variables.push((name, *ability));
|
||||||
buf.push_str(name);
|
buf.push_str(name);
|
||||||
}
|
}
|
||||||
RecursionVar { opt_name, .. } => match opt_name {
|
RecursionVar {
|
||||||
|
opt_name,
|
||||||
|
structure,
|
||||||
|
} => match opt_name {
|
||||||
Some(name_index) => {
|
Some(name_index) => {
|
||||||
|
if let Some(idx) = ctx
|
||||||
|
.recursion_structs_to_expand
|
||||||
|
.iter()
|
||||||
|
.position(|v| v == structure)
|
||||||
|
{
|
||||||
|
ctx.recursion_structs_to_expand.swap_remove(idx);
|
||||||
|
|
||||||
|
write_content(
|
||||||
|
env,
|
||||||
|
ctx,
|
||||||
|
subs.get_content_without_compacting(*structure),
|
||||||
|
subs,
|
||||||
|
buf,
|
||||||
|
parens,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
let name = &subs.field_names[name_index.index as usize];
|
let name = &subs.field_names[name_index.index as usize];
|
||||||
buf.push_str(name.as_str())
|
buf.push_str(name.as_str())
|
||||||
}
|
}
|
||||||
None => buf.push_str(WILDCARD),
|
}
|
||||||
|
None => {
|
||||||
|
unreachable!("This should always be filled in!")
|
||||||
|
}
|
||||||
},
|
},
|
||||||
Structure(flat_type) => write_flat_type(env, ctx, flat_type, subs, buf, parens),
|
Structure(flat_type) => write_flat_type(env, ctx, flat_type, subs, buf, parens),
|
||||||
Alias(symbol, args, _actual, _kind) => {
|
Alias(symbol, args, _actual, _kind) => {
|
||||||
|
|
|
@ -2172,23 +2172,6 @@ impl Content {
|
||||||
Content::Structure(FlatType::Apply(Symbol::NUM_NUM, _))
|
Content::Structure(FlatType::Apply(Symbol::NUM_NUM, _))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn dbg(self, subs: &Subs) -> Self {
|
|
||||||
let home = roc_module::symbol::ModuleIds::default().get_or_insert(&"#Dbg".into());
|
|
||||||
let interns = roc_module::symbol::Interns {
|
|
||||||
all_ident_ids: roc_module::symbol::IdentIds::exposed_builtins(0),
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
eprintln!(
|
|
||||||
"{}",
|
|
||||||
crate::pretty_print::content_to_string(&self, subs, home, &interns)
|
|
||||||
);
|
|
||||||
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
|
|
@ -59,6 +59,7 @@ use roc_collections::all::MutMap;
|
||||||
use roc_module::ident::Lowercase;
|
use roc_module::ident::Lowercase;
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::Symbol;
|
||||||
use roc_region::all::Region;
|
use roc_region::all::Region;
|
||||||
|
use roc_types::pretty_print::name_all_type_vars;
|
||||||
use roc_types::solved_types::Solved;
|
use roc_types::solved_types::Solved;
|
||||||
use roc_types::subs::{Subs, Variable};
|
use roc_types::subs::{Subs, Variable};
|
||||||
use roc_types::{pretty_print::content_to_string, subs::VarStore};
|
use roc_types::{pretty_print::content_to_string, subs::VarStore};
|
||||||
|
@ -462,6 +463,8 @@ impl<'a> EdModel<'a> {
|
||||||
|
|
||||||
let subs = solved.inner_mut();
|
let subs = solved.inner_mut();
|
||||||
|
|
||||||
|
let named_result = name_all_type_vars(var, subs);
|
||||||
|
|
||||||
let content = subs.get_content_without_compacting(var);
|
let content = subs.get_content_without_compacting(var);
|
||||||
|
|
||||||
PoolStr::new(
|
PoolStr::new(
|
||||||
|
@ -470,6 +473,7 @@ impl<'a> EdModel<'a> {
|
||||||
subs,
|
subs,
|
||||||
self.module.env.home,
|
self.module.env.home,
|
||||||
&self.loaded_module.interns,
|
&self.loaded_module.interns,
|
||||||
|
named_result,
|
||||||
),
|
),
|
||||||
self.module.env.pool,
|
self.module.env.pool,
|
||||||
)
|
)
|
||||||
|
|
|
@ -227,9 +227,9 @@ fn gen_and_eval_llvm<'a>(
|
||||||
let main_fn_var = *main_fn_var;
|
let main_fn_var = *main_fn_var;
|
||||||
|
|
||||||
// pretty-print the expr type string for later.
|
// pretty-print the expr type string for later.
|
||||||
name_all_type_vars(main_fn_var, &mut subs);
|
let named_result = name_all_type_vars(main_fn_var, &mut subs);
|
||||||
let content = subs.get_content_without_compacting(main_fn_var);
|
let content = subs.get_content_without_compacting(main_fn_var);
|
||||||
let expr_type_str = content_to_string(content, &subs, home, &interns);
|
let expr_type_str = content_to_string(content, &subs, home, &interns, named_result);
|
||||||
|
|
||||||
let (_, main_fn_layout) = match procedures.keys().find(|(s, _)| *s == main_fn_symbol) {
|
let (_, main_fn_layout) = match procedures.keys().find(|(s, _)| *s == main_fn_symbol) {
|
||||||
Some(layout) => *layout,
|
Some(layout) => *layout,
|
||||||
|
|
|
@ -184,9 +184,9 @@ pub async fn entrypoint_from_js(src: String) -> Result<String, String> {
|
||||||
let main_fn_var = *main_fn_var;
|
let main_fn_var = *main_fn_var;
|
||||||
|
|
||||||
// pretty-print the expr type string for later.
|
// pretty-print the expr type string for later.
|
||||||
name_all_type_vars(main_fn_var, &mut subs);
|
let named_result = name_all_type_vars(main_fn_var, &mut subs);
|
||||||
let content = subs.get_content_without_compacting(main_fn_var);
|
let content = subs.get_content_without_compacting(main_fn_var);
|
||||||
let expr_type_str = content_to_string(content, &subs, module_id, &interns);
|
let expr_type_str = content_to_string(content, &subs, module_id, &interns, named_result);
|
||||||
|
|
||||||
let (_, main_fn_layout) = match procedures.keys().find(|(s, _)| *s == main_fn_symbol) {
|
let (_, main_fn_layout) = match procedures.keys().find(|(s, _)| *s == main_fn_symbol) {
|
||||||
Some(layout) => *layout,
|
Some(layout) => *layout,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue