mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-04 00:54:36 +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> {
|
fn parse_queries(src: &str) -> Vec<TypeQuery> {
|
||||||
let line_info = LineInfo::new(src);
|
let line_info = LineInfo::new(src);
|
||||||
let mut queries = vec![];
|
let mut queries = vec![];
|
||||||
|
let mut consecutive_query_lines = 0;
|
||||||
for (i, line) in src.lines().enumerate() {
|
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 wher = capture.name("where").unwrap();
|
||||||
let subtract_col = capture
|
let subtract_col = capture
|
||||||
.name("sub")
|
.name("sub")
|
||||||
|
@ -44,7 +54,7 @@ mod solve_expr {
|
||||||
.unwrap_or(0);
|
.unwrap_or(0);
|
||||||
let (start, end) = (wher.start() as u32, wher.end() as u32);
|
let (start, end) = (wher.start() as u32, wher.end() as u32);
|
||||||
let (start, end) = (start - subtract_col, end - subtract_col);
|
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 {
|
let start_lc = LineColumn {
|
||||||
line: last_line,
|
line: last_line,
|
||||||
column: start,
|
column: start,
|
||||||
|
@ -277,6 +287,7 @@ mod solve_expr {
|
||||||
let var = find_type_at(region, &decls)
|
let var = find_type_at(region, &decls)
|
||||||
.unwrap_or_else(|| panic!("No type for {:?} ({:?})!", &text, region));
|
.unwrap_or_else(|| panic!("No type for {:?} ({:?})!", &text, region));
|
||||||
|
|
||||||
|
let snapshot = subs.snapshot();
|
||||||
let actual_str = name_and_print_var(
|
let actual_str = name_and_print_var(
|
||||||
var,
|
var,
|
||||||
subs,
|
subs,
|
||||||
|
@ -287,6 +298,7 @@ mod solve_expr {
|
||||||
print_only_under_alias,
|
print_only_under_alias,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
subs.rollback_to(snapshot);
|
||||||
|
|
||||||
let elaborated =
|
let elaborated =
|
||||||
match find_ability_member_and_owning_type_at(region, &decls, &abilities_store) {
|
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
|
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",
|
"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>,
|
roots: &mut Vec<Variable>,
|
||||||
root_appearances: &mut MutMap<Variable, Appearances>,
|
root_appearances: &mut MutMap<Variable, Appearances>,
|
||||||
names_taken: &mut MutMap<Lowercase, Variable>,
|
names_taken: &mut MutMap<Lowercase, Variable>,
|
||||||
|
find_under_alias: bool,
|
||||||
) {
|
) {
|
||||||
use crate::subs::Content::*;
|
use crate::subs::Content::*;
|
||||||
use crate::subs::FlatType::*;
|
use crate::subs::FlatType::*;
|
||||||
|
@ -190,59 +191,151 @@ fn find_names_needed(
|
||||||
Structure(Apply(_, args)) => {
|
Structure(Apply(_, args)) => {
|
||||||
for index in args.into_iter() {
|
for index in args.into_iter() {
|
||||||
let var = subs[index];
|
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)) => {
|
Structure(Func(arg_vars, _closure_var, ret_var)) => {
|
||||||
for index in arg_vars.into_iter() {
|
for index in arg_vars.into_iter() {
|
||||||
let var = subs[index];
|
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)) => {
|
Structure(Record(sorted_fields, ext_var)) => {
|
||||||
for index in sorted_fields.iter_variables() {
|
for index in sorted_fields.iter_variables() {
|
||||||
let var = subs[index];
|
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)) => {
|
Structure(TagUnion(tags, ext_var)) => {
|
||||||
for slice_index in tags.variables() {
|
for slice_index in tags.variables() {
|
||||||
let slice = subs[slice_index];
|
let slice = subs[slice_index];
|
||||||
for var_index in slice {
|
for var_index in slice {
|
||||||
let var = subs[var_index];
|
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)) => {
|
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)) => {
|
Structure(RecursiveTagUnion(rec_var, tags, ext_var)) => {
|
||||||
for slice_index in tags.variables() {
|
for slice_index in tags.variables() {
|
||||||
let slice = subs[slice_index];
|
let slice = subs[slice_index];
|
||||||
for var_index in slice {
|
for var_index in slice {
|
||||||
let var = subs[var_index];
|
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(
|
||||||
find_names_needed(*rec_var, subs, roots, root_appearances, names_taken);
|
*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!
|
// only find names for named parameters!
|
||||||
for var_index in args.into_iter().take(args.len()) {
|
for var_index in args.into_iter().take(args.len()) {
|
||||||
let var = subs[var_index];
|
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 {
|
LambdaSet(subs::LambdaSet {
|
||||||
solved,
|
solved,
|
||||||
|
@ -253,21 +346,49 @@ fn find_names_needed(
|
||||||
let slice = subs[slice_index];
|
let slice = subs[slice_index];
|
||||||
for var_index in slice {
|
for var_index in slice {
|
||||||
let var = subs[var_index];
|
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() {
|
for uls_index in unspecialized.into_iter() {
|
||||||
let Uls(var, _, _) = subs[uls_index];
|
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() {
|
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, _) => {
|
&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) => {
|
Error | Structure(Erroneous(_)) | Structure(EmptyRecord) | Structure(EmptyTagUnion) => {
|
||||||
// Errors and empty records don't need names.
|
// Errors and empty records don't need names.
|
||||||
|
@ -279,14 +400,25 @@ struct NamedResult {
|
||||||
recursion_structs_to_expand: Vec<Variable>,
|
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 roots = Vec::new();
|
||||||
let mut letters_used = 0;
|
let mut letters_used = 0;
|
||||||
let mut appearances = MutMap::default();
|
let mut appearances = MutMap::default();
|
||||||
let mut taken = MutMap::default();
|
let mut taken = MutMap::default();
|
||||||
|
|
||||||
// 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,
|
||||||
|
find_names_under_alias,
|
||||||
|
);
|
||||||
|
|
||||||
let mut recursion_structs_to_expand = vec![];
|
let mut recursion_structs_to_expand = vec![];
|
||||||
|
|
||||||
|
@ -417,7 +549,7 @@ pub fn name_and_print_var(
|
||||||
interns: &Interns,
|
interns: &Interns,
|
||||||
debug_print: DebugPrint,
|
debug_print: DebugPrint,
|
||||||
) -> String {
|
) -> 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);
|
let content = subs.get_content_without_compacting(var);
|
||||||
content_to_string(content, subs, home, interns, named_result, debug_print)
|
content_to_string(content, subs, home, interns, named_result, debug_print)
|
||||||
}
|
}
|
||||||
|
@ -976,6 +1108,7 @@ fn write_flat_type<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
RecursiveTagUnion(rec_var, tags, ext_var) => {
|
RecursiveTagUnion(rec_var, tags, ext_var) => {
|
||||||
|
write_parens!(parens == Parens::InTypeParam, buf, {
|
||||||
buf.push('[');
|
buf.push('[');
|
||||||
|
|
||||||
let (tags, new_ext_var) = tags.unsorted_tags_and_ext(subs, *ext_var);
|
let (tags, new_ext_var) = tags.unsorted_tags_and_ext(subs, *ext_var);
|
||||||
|
@ -1001,6 +1134,7 @@ fn write_flat_type<'a>(
|
||||||
buf,
|
buf,
|
||||||
parens,
|
parens,
|
||||||
)
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
Erroneous(problem) => {
|
Erroneous(problem) => {
|
||||||
buf.push_str(&format!("<Type Mismatch: {:?}>", problem));
|
buf.push_str(&format!("<Type Mismatch: {:?}>", problem));
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue