diff --git a/compiler/solve/tests/solve_expr.rs b/compiler/solve/tests/solve_expr.rs index 5976444c1a..b4b3340fcb 100644 --- a/compiler/solve/tests/solve_expr.rs +++ b/compiler/solve/tests/solve_expr.rs @@ -35,8 +35,18 @@ mod solve_expr { fn parse_queries(src: &str) -> Vec { 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 + ) + } } diff --git a/compiler/types/src/pretty_print.rs b/compiler/types/src/pretty_print.rs index 1d9724d351..642270cbbf 100644 --- a/compiler/types/src/pretty_print.rs +++ b/compiler/types/src/pretty_print.rs @@ -90,6 +90,7 @@ fn find_names_needed( roots: &mut Vec, root_appearances: &mut MutMap, names_taken: &mut MutMap, + 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, } -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!("", problem));