mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 16:44:33 +00:00
Add test for types of destructed recursive alias in issue
This commit is contained in:
parent
69ab681f9c
commit
fdba8b26d4
2 changed files with 220 additions and 46 deletions
|
@ -35,8 +35,18 @@ mod solve_expr {
|
|||
fn parse_queries(src: &str) -> Vec<TypeQuery> {
|
||||
let line_info = LineInfo::new(src);
|
||||
let mut queries = vec![];
|
||||
let mut consecutive_query_lines = 0;
|
||||
for (i, line) in src.lines().enumerate() {
|
||||
for capture in RE_TYPE_QUERY.captures_iter(line) {
|
||||
let mut queries_on_line = RE_TYPE_QUERY.captures_iter(line).into_iter().peekable();
|
||||
|
||||
if queries_on_line.peek().is_none() {
|
||||
consecutive_query_lines = 0;
|
||||
continue;
|
||||
} else {
|
||||
consecutive_query_lines += 1;
|
||||
}
|
||||
|
||||
for capture in queries_on_line {
|
||||
let wher = capture.name("where").unwrap();
|
||||
let subtract_col = capture
|
||||
.name("sub")
|
||||
|
@ -44,7 +54,7 @@ mod solve_expr {
|
|||
.unwrap_or(0);
|
||||
let (start, end) = (wher.start() as u32, wher.end() as u32);
|
||||
let (start, end) = (start - subtract_col, end - subtract_col);
|
||||
let last_line = i as u32 - 1;
|
||||
let last_line = i as u32 - consecutive_query_lines;
|
||||
let start_lc = LineColumn {
|
||||
line: last_line,
|
||||
column: start,
|
||||
|
@ -277,6 +287,7 @@ mod solve_expr {
|
|||
let var = find_type_at(region, &decls)
|
||||
.unwrap_or_else(|| panic!("No type for {:?} ({:?})!", &text, region));
|
||||
|
||||
let snapshot = subs.snapshot();
|
||||
let actual_str = name_and_print_var(
|
||||
var,
|
||||
subs,
|
||||
|
@ -287,6 +298,7 @@ mod solve_expr {
|
|||
print_only_under_alias,
|
||||
},
|
||||
);
|
||||
subs.rollback_to(snapshot);
|
||||
|
||||
let elaborated =
|
||||
match find_ability_member_and_owning_type_at(region, &decls, &abilities_store) {
|
||||
|
@ -5480,7 +5492,7 @@ mod solve_expr {
|
|||
Job lst s -> P lst s
|
||||
"#
|
||||
),
|
||||
"[P (List [Job (List a) Str] as a) Str]*",
|
||||
"[P (List ([Job (List a) Str] as a)) Str]*",
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -6861,4 +6873,32 @@ mod solve_expr {
|
|||
"Str -> Str",
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn issue_3261() {
|
||||
infer_queries!(
|
||||
indoc!(
|
||||
r#"
|
||||
Named : [Named Str (List Named)]
|
||||
|
||||
foo : Named
|
||||
foo = Named "outer" [Named "inner" []]
|
||||
#^^^{-1}
|
||||
|
||||
Named name outerList = foo
|
||||
#^^^^^^^^^^^^^^^^^^^^{-1}
|
||||
# ^^^^ ^^^^^^^^^
|
||||
|
||||
{name, outerList}
|
||||
"#
|
||||
),
|
||||
&[
|
||||
"foo : [Named Str (List a)] as a",
|
||||
"Named name outerList : [Named Str (List a)] as a",
|
||||
"name : Str",
|
||||
"outerList : List ([Named Str (List a)] as a)",
|
||||
],
|
||||
print_only_under_alias = true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -90,6 +90,7 @@ fn find_names_needed(
|
|||
roots: &mut Vec<Variable>,
|
||||
root_appearances: &mut MutMap<Variable, Appearances>,
|
||||
names_taken: &mut MutMap<Lowercase, Variable>,
|
||||
find_under_alias: bool,
|
||||
) {
|
||||
use crate::subs::Content::*;
|
||||
use crate::subs::FlatType::*;
|
||||
|
@ -190,59 +191,151 @@ fn find_names_needed(
|
|||
Structure(Apply(_, args)) => {
|
||||
for index in args.into_iter() {
|
||||
let var = subs[index];
|
||||
find_names_needed(var, subs, roots, root_appearances, names_taken);
|
||||
find_names_needed(
|
||||
var,
|
||||
subs,
|
||||
roots,
|
||||
root_appearances,
|
||||
names_taken,
|
||||
find_under_alias,
|
||||
);
|
||||
}
|
||||
}
|
||||
Structure(Func(arg_vars, _closure_var, ret_var)) => {
|
||||
for index in arg_vars.into_iter() {
|
||||
let var = subs[index];
|
||||
find_names_needed(var, subs, roots, root_appearances, names_taken);
|
||||
find_names_needed(
|
||||
var,
|
||||
subs,
|
||||
roots,
|
||||
root_appearances,
|
||||
names_taken,
|
||||
find_under_alias,
|
||||
);
|
||||
}
|
||||
|
||||
find_names_needed(*ret_var, subs, roots, root_appearances, names_taken);
|
||||
find_names_needed(
|
||||
*ret_var,
|
||||
subs,
|
||||
roots,
|
||||
root_appearances,
|
||||
names_taken,
|
||||
find_under_alias,
|
||||
);
|
||||
}
|
||||
Structure(Record(sorted_fields, ext_var)) => {
|
||||
for index in sorted_fields.iter_variables() {
|
||||
let var = subs[index];
|
||||
find_names_needed(var, subs, roots, root_appearances, names_taken);
|
||||
find_names_needed(
|
||||
var,
|
||||
subs,
|
||||
roots,
|
||||
root_appearances,
|
||||
names_taken,
|
||||
find_under_alias,
|
||||
);
|
||||
}
|
||||
|
||||
find_names_needed(*ext_var, subs, roots, root_appearances, names_taken);
|
||||
find_names_needed(
|
||||
*ext_var,
|
||||
subs,
|
||||
roots,
|
||||
root_appearances,
|
||||
names_taken,
|
||||
find_under_alias,
|
||||
);
|
||||
}
|
||||
Structure(TagUnion(tags, ext_var)) => {
|
||||
for slice_index in tags.variables() {
|
||||
let slice = subs[slice_index];
|
||||
for var_index in slice {
|
||||
let var = subs[var_index];
|
||||
find_names_needed(var, subs, roots, root_appearances, names_taken);
|
||||
find_names_needed(
|
||||
var,
|
||||
subs,
|
||||
roots,
|
||||
root_appearances,
|
||||
names_taken,
|
||||
find_under_alias,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
find_names_needed(*ext_var, subs, roots, root_appearances, names_taken);
|
||||
find_names_needed(
|
||||
*ext_var,
|
||||
subs,
|
||||
roots,
|
||||
root_appearances,
|
||||
names_taken,
|
||||
find_under_alias,
|
||||
);
|
||||
}
|
||||
Structure(FunctionOrTagUnion(_, _, ext_var)) => {
|
||||
find_names_needed(*ext_var, subs, roots, root_appearances, names_taken);
|
||||
find_names_needed(
|
||||
*ext_var,
|
||||
subs,
|
||||
roots,
|
||||
root_appearances,
|
||||
names_taken,
|
||||
find_under_alias,
|
||||
);
|
||||
}
|
||||
Structure(RecursiveTagUnion(rec_var, tags, ext_var)) => {
|
||||
for slice_index in tags.variables() {
|
||||
let slice = subs[slice_index];
|
||||
for var_index in slice {
|
||||
let var = subs[var_index];
|
||||
find_names_needed(var, subs, roots, root_appearances, names_taken);
|
||||
find_names_needed(
|
||||
var,
|
||||
subs,
|
||||
roots,
|
||||
root_appearances,
|
||||
names_taken,
|
||||
find_under_alias,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
find_names_needed(*ext_var, subs, roots, root_appearances, names_taken);
|
||||
find_names_needed(*rec_var, subs, roots, root_appearances, names_taken);
|
||||
find_names_needed(
|
||||
*ext_var,
|
||||
subs,
|
||||
roots,
|
||||
root_appearances,
|
||||
names_taken,
|
||||
find_under_alias,
|
||||
);
|
||||
find_names_needed(
|
||||
*rec_var,
|
||||
subs,
|
||||
roots,
|
||||
root_appearances,
|
||||
names_taken,
|
||||
find_under_alias,
|
||||
);
|
||||
}
|
||||
Alias(_symbol, args, _actual, _kind) => {
|
||||
Alias(_symbol, args, actual, _kind) => {
|
||||
// only find names for named parameters!
|
||||
for var_index in args.into_iter().take(args.len()) {
|
||||
let var = subs[var_index];
|
||||
find_names_needed(var, subs, roots, root_appearances, names_taken);
|
||||
find_names_needed(
|
||||
var,
|
||||
subs,
|
||||
roots,
|
||||
root_appearances,
|
||||
names_taken,
|
||||
find_under_alias,
|
||||
);
|
||||
}
|
||||
if find_under_alias {
|
||||
find_names_needed(
|
||||
*actual,
|
||||
subs,
|
||||
roots,
|
||||
root_appearances,
|
||||
names_taken,
|
||||
find_under_alias,
|
||||
);
|
||||
}
|
||||
// TODO should we also look in the actual variable?
|
||||
// find_names_needed(_actual, subs, roots, root_appearances, names_taken);
|
||||
}
|
||||
LambdaSet(subs::LambdaSet {
|
||||
solved,
|
||||
|
@ -253,21 +346,49 @@ fn find_names_needed(
|
|||
let slice = subs[slice_index];
|
||||
for var_index in slice {
|
||||
let var = subs[var_index];
|
||||
find_names_needed(var, subs, roots, root_appearances, names_taken);
|
||||
find_names_needed(
|
||||
var,
|
||||
subs,
|
||||
roots,
|
||||
root_appearances,
|
||||
names_taken,
|
||||
find_under_alias,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for uls_index in unspecialized.into_iter() {
|
||||
let Uls(var, _, _) = subs[uls_index];
|
||||
find_names_needed(var, subs, roots, root_appearances, names_taken);
|
||||
find_names_needed(
|
||||
var,
|
||||
subs,
|
||||
roots,
|
||||
root_appearances,
|
||||
names_taken,
|
||||
find_under_alias,
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(rec_var) = recursion_var.into_variable() {
|
||||
find_names_needed(rec_var, subs, roots, root_appearances, names_taken);
|
||||
find_names_needed(
|
||||
rec_var,
|
||||
subs,
|
||||
roots,
|
||||
root_appearances,
|
||||
names_taken,
|
||||
find_under_alias,
|
||||
);
|
||||
}
|
||||
}
|
||||
&RangedNumber(typ, _) => {
|
||||
find_names_needed(typ, subs, roots, root_appearances, names_taken);
|
||||
find_names_needed(
|
||||
typ,
|
||||
subs,
|
||||
roots,
|
||||
root_appearances,
|
||||
names_taken,
|
||||
find_under_alias,
|
||||
);
|
||||
}
|
||||
Error | Structure(Erroneous(_)) | Structure(EmptyRecord) | Structure(EmptyTagUnion) => {
|
||||
// Errors and empty records don't need names.
|
||||
|
@ -279,14 +400,25 @@ struct NamedResult {
|
|||
recursion_structs_to_expand: Vec<Variable>,
|
||||
}
|
||||
|
||||
fn name_all_type_vars(variable: Variable, subs: &mut Subs) -> NamedResult {
|
||||
fn name_all_type_vars(
|
||||
variable: Variable,
|
||||
subs: &mut Subs,
|
||||
find_names_under_alias: bool,
|
||||
) -> NamedResult {
|
||||
let mut roots = Vec::new();
|
||||
let mut letters_used = 0;
|
||||
let mut appearances = MutMap::default();
|
||||
let mut taken = MutMap::default();
|
||||
|
||||
// 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,
|
||||
find_names_under_alias,
|
||||
);
|
||||
|
||||
let mut recursion_structs_to_expand = vec![];
|
||||
|
||||
|
@ -417,7 +549,7 @@ pub fn name_and_print_var(
|
|||
interns: &Interns,
|
||||
debug_print: DebugPrint,
|
||||
) -> String {
|
||||
let named_result = name_all_type_vars(var, subs);
|
||||
let named_result = name_all_type_vars(var, subs, debug_print.print_only_under_alias);
|
||||
let content = subs.get_content_without_compacting(var);
|
||||
content_to_string(content, subs, home, interns, named_result, debug_print)
|
||||
}
|
||||
|
@ -976,31 +1108,33 @@ fn write_flat_type<'a>(
|
|||
}
|
||||
|
||||
RecursiveTagUnion(rec_var, tags, ext_var) => {
|
||||
buf.push('[');
|
||||
write_parens!(parens == Parens::InTypeParam, buf, {
|
||||
buf.push('[');
|
||||
|
||||
let (tags, new_ext_var) = tags.unsorted_tags_and_ext(subs, *ext_var);
|
||||
write_sorted_tags2(env, ctx, subs, buf, tags, |tag| tag.0.as_str().to_string());
|
||||
let (tags, new_ext_var) = tags.unsorted_tags_and_ext(subs, *ext_var);
|
||||
write_sorted_tags2(env, ctx, subs, buf, tags, |tag| tag.0.as_str().to_string());
|
||||
|
||||
buf.push(']');
|
||||
buf.push(']');
|
||||
|
||||
write_ext_content(
|
||||
env,
|
||||
ctx,
|
||||
subs,
|
||||
buf,
|
||||
ExtContent::from_var(subs, new_ext_var),
|
||||
parens,
|
||||
);
|
||||
write_ext_content(
|
||||
env,
|
||||
ctx,
|
||||
subs,
|
||||
buf,
|
||||
ExtContent::from_var(subs, new_ext_var),
|
||||
parens,
|
||||
);
|
||||
|
||||
buf.push_str(" as ");
|
||||
write_content(
|
||||
env,
|
||||
ctx,
|
||||
subs.get_content_without_compacting(*rec_var),
|
||||
subs,
|
||||
buf,
|
||||
parens,
|
||||
)
|
||||
buf.push_str(" as ");
|
||||
write_content(
|
||||
env,
|
||||
ctx,
|
||||
subs.get_content_without_compacting(*rec_var),
|
||||
subs,
|
||||
buf,
|
||||
parens,
|
||||
)
|
||||
})
|
||||
}
|
||||
Erroneous(problem) => {
|
||||
buf.push_str(&format!("<Type Mismatch: {:?}>", problem));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue