Merge pull request #5028 from roc-lang/i5026

Do not fixup recursion pointers in non-recursive lambda sets
This commit is contained in:
Folkert de Vries 2023-02-14 15:21:05 +01:00 committed by GitHub
commit c8d418218e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 172 additions and 189 deletions

View File

@ -1,4 +1,5 @@
use crate::ir::Parens;
use crate::layout::intern::NeedsRecursionPointerFixup;
use bitvec::vec::BitVec;
use bumpalo::collections::Vec;
use bumpalo::Bump;
@ -1883,12 +1884,16 @@ impl<'a> LambdaSet<'a> {
);
cache_criteria.and(criteria);
let needs_recursive_fixup = NeedsRecursionPointerFixup(
opt_recursion_var.is_some() && set_captures_have_naked_rec_ptr,
);
let lambda_set = env.cache.interner.insert_lambda_set(
env.arena,
fn_args,
ret,
env.arena.alloc(set.into_bump_slice()),
set_captures_have_naked_rec_ptr,
needs_recursive_fixup,
representation,
);
@ -1902,7 +1907,7 @@ impl<'a> LambdaSet<'a> {
fn_args,
ret,
&(&[] as &[(Symbol, &[InLayout])]),
false,
NeedsRecursionPointerFixup(false),
Layout::UNIT,
);
Cacheable(Ok(lambda_set), cache_criteria)

View File

@ -121,6 +121,13 @@ impl<'a> Layout<'a> {
}
}
/// Whether a recursive lambda set being inserted into an interner needs fixing-up of naked
/// recursion pointers in the capture set.
/// Applicable only if
/// - the lambda set is indeed recursive, and
/// - its capture set contain naked pointer references
pub struct NeedsRecursionPointerFixup(pub bool);
pub trait LayoutInterner<'a>: Sized {
/// Interns a value, returning its interned representation.
/// If the value has been interned before, the old interned representation will be re-used.
@ -139,7 +146,7 @@ pub trait LayoutInterner<'a>: Sized {
args: &'a &'a [InLayout<'a>],
ret: InLayout<'a>,
set: &'a &'a [(Symbol, &'a [InLayout<'a>])],
set_may_have_naked_rec_ptr: bool,
needs_recursive_fixup: NeedsRecursionPointerFixup,
representation: InLayout<'a>,
) -> LambdaSet<'a>;
@ -550,7 +557,7 @@ impl<'a> GlobalLayoutInterner<'a> {
&self,
arena: &'a Bump,
normalized: LambdaSet<'a>,
set_may_have_naked_rec_ptr: bool,
needs_recursive_fixup: NeedsRecursionPointerFixup,
normalized_hash: u64,
) -> WrittenGlobalLambdaSet<'a> {
let mut normalized_lambda_set_map = self.0.normalized_lambda_set_map.lock();
@ -574,7 +581,7 @@ impl<'a> GlobalLayoutInterner<'a> {
let slot = unsafe { InLayout::from_index(vec.len()) };
vec.push(Layout::VOID_NAKED);
let set = if set_may_have_naked_rec_ptr {
let set = if needs_recursive_fixup.0 {
let mut interner = LockedGlobalInterner {
map: &mut map,
normalized_lambda_set_map: &mut normalized_lambda_set_map,
@ -708,7 +715,7 @@ impl<'a> LayoutInterner<'a> for TLLayoutInterner<'a> {
args: &'a &'a [InLayout<'a>],
ret: InLayout<'a>,
set: &'a &'a [(Symbol, &'a [InLayout<'a>])],
set_may_have_naked_rec_ptr: bool,
needs_recursive_fixup: NeedsRecursionPointerFixup,
representation: InLayout<'a>,
) -> LambdaSet<'a> {
// The tricky bit of inserting a lambda set is we need to fill in the `full_layout` only
@ -737,7 +744,7 @@ impl<'a> LayoutInterner<'a> for TLLayoutInterner<'a> {
} = global.get_or_insert_hashed_normalized_lambda_set(
arena,
normalized,
set_may_have_naked_rec_ptr,
needs_recursive_fixup,
normalized_hash,
);
@ -865,7 +872,7 @@ macro_rules! st_impl {
args: &'a &'a [InLayout<'a>],
ret: InLayout<'a>,
set: &'a &'a [(Symbol, &'a [InLayout<'a>])],
set_may_have_naked_rec_ptr: bool,
needs_recursive_fixup: NeedsRecursionPointerFixup,
representation: InLayout<'a>,
) -> LambdaSet<'a> {
// IDEA:
@ -884,7 +891,7 @@ macro_rules! st_impl {
let slot = unsafe { InLayout::from_index(self.vec.len()) };
self.vec.push(Layout::VOID_NAKED);
let set = if set_may_have_naked_rec_ptr {
let set = if needs_recursive_fixup.0 {
reify::reify_lambda_set_captures(arena, self, slot, set)
} else {
set
@ -957,7 +964,7 @@ mod reify {
use crate::layout::{Builtin, LambdaSet, Layout, UnionLayout};
use super::{InLayout, LayoutInterner};
use super::{InLayout, LayoutInterner, NeedsRecursionPointerFixup};
// TODO: if recursion becomes a problem we could make this iterative
pub fn reify_recursive_layout<'a>(
@ -1103,7 +1110,8 @@ mod reify {
arena.alloc(args),
ret,
arena.alloc(set),
true,
// All nested recursive pointers should been fixed up, since we just did that above.
NeedsRecursionPointerFixup(false),
representation,
)
}
@ -1420,7 +1428,7 @@ mod insert_lambda_set {
use crate::layout::{LambdaSet, Layout};
use super::{GlobalLayoutInterner, InLayout, LayoutInterner};
use super::{GlobalLayoutInterner, InLayout, LayoutInterner, NeedsRecursionPointerFixup};
const TARGET_INFO: TargetInfo = TargetInfo::default_x86_64();
const TEST_SET: &&[(Symbol, &[InLayout])] =
@ -1428,6 +1436,8 @@ mod insert_lambda_set {
const TEST_ARGS: &&[InLayout] = &(&[Layout::UNIT] as &[_]);
const TEST_RET: InLayout = Layout::UNIT;
const FIXUP: NeedsRecursionPointerFixup = NeedsRecursionPointerFixup(true);
#[test]
fn two_threads_write() {
for _ in 0..100 {
@ -1440,7 +1450,7 @@ mod insert_lambda_set {
for arena in arenas.iter_mut() {
let mut interner = global.fork();
handles.push(s.spawn(move || {
interner.insert_lambda_set(arena, TEST_ARGS, TEST_RET, set, true, repr)
interner.insert_lambda_set(arena, TEST_ARGS, TEST_RET, set, FIXUP, repr)
}))
}
let ins: Vec<LambdaSet> = handles.into_iter().map(|t| t.join().unwrap()).collect();
@ -1457,7 +1467,7 @@ mod insert_lambda_set {
let mut interner = global.fork();
let lambda_set =
interner.insert_lambda_set(arena, TEST_ARGS, TEST_RET, TEST_SET, true, Layout::UNIT);
interner.insert_lambda_set(arena, TEST_ARGS, TEST_RET, TEST_SET, FIXUP, Layout::UNIT);
let lambda_set_layout_in = interner.insert(Layout::LambdaSet(lambda_set));
assert_eq!(lambda_set.full_layout, lambda_set_layout_in);
}
@ -1471,12 +1481,12 @@ mod insert_lambda_set {
let in1 = {
let mut interner = global.fork();
interner.insert_lambda_set(arena, TEST_ARGS, TEST_RET, set, true, repr)
interner.insert_lambda_set(arena, TEST_ARGS, TEST_RET, set, FIXUP, repr)
};
let in2 = {
let mut st_interner = global.unwrap().unwrap();
st_interner.insert_lambda_set(arena, TEST_ARGS, TEST_RET, set, true, repr)
st_interner.insert_lambda_set(arena, TEST_ARGS, TEST_RET, set, FIXUP, repr)
};
assert_eq!(in1, in2);
@ -1491,12 +1501,12 @@ mod insert_lambda_set {
let set = TEST_SET;
let repr = Layout::UNIT;
let in1 = st_interner.insert_lambda_set(arena, TEST_ARGS, TEST_RET, set, true, repr);
let in1 = st_interner.insert_lambda_set(arena, TEST_ARGS, TEST_RET, set, FIXUP, repr);
let global = st_interner.into_global();
let mut interner = global.fork();
let in2 = interner.insert_lambda_set(arena, TEST_ARGS, TEST_RET, set, true, repr);
let in2 = interner.insert_lambda_set(arena, TEST_ARGS, TEST_RET, set, FIXUP, repr);
assert_eq!(in1, in2);
}

View File

@ -7805,8 +7805,8 @@ mod solve_expr {
),
@r###"
const : Str -[[const(2)]]-> (Str -[[closCompose(7) (Str -a-> Str) (Str -[[]]-> Str), closConst(10) Str] as a]-> Str)
compose : (Str -a-> Str), (Str -[[]]-> Str) -[[compose(1)]]-> (Str -a-> Str)
\c1, c2 -> compose c1 c2 : (Str -a-> Str), (Str -[[]]-> Str) -[[11]]-> (Str -a-> Str)
compose : (Str -[[closCompose(7) (Str -a-> Str) (Str -[[]]-> Str), closConst(10) Str] as a]-> Str), (Str -[[]]-> Str) -[[compose(1)]]-> (Str -[[closCompose(7) (Str -a-> Str) (Str -[[]]-> Str), closConst(10) Str] as a]-> Str)
\c1, c2 -> compose c1 c2 : (Str -[[closCompose(7) (Str -a-> Str) (Str -[[]]-> Str), closConst(10) Str] as a]-> Str), (Str -[[]]-> Str) -[[11]]-> (Str -[[closCompose(7) (Str -a-> Str) (Str -[[]]-> Str), closConst(10) Str] as a]-> Str)
res : Str -[[closCompose(7) (Str -a-> Str) (Str -[[]]-> Str), closConst(10) Str] as a]-> Str
res : Str -[[closCompose(7) (Str -a-> Str) (Str -[[]]-> Str), closConst(10) Str] as a]-> Str
"###
@ -8330,7 +8330,7 @@ mod solve_expr {
"#
),
@r###"
job : { lst : List [Bar, FromG a] } -[[job(0)]]-> [G { lst : List [Bar, FromG a] }] as a
job : { lst : List [Bar, FromG ([G { lst : List [Bar, FromG a] }] as a)] } -[[job(0)]]-> [G { lst : List [Bar, FromG a] }] as a
config : { lst : List [Bar, FromG ([G { lst : List [Bar, FromG a] }] as a)] }
G config : [G { lst : List [Bar, FromG a] }] as a
"###

View File

@ -0,0 +1,55 @@
procedure Bool.2 ():
let Bool.23 : Int1 = true;
ret Bool.23;
procedure Test.10 (Test.28):
let Test.32 : Int1 = CallByName Bool.2;
if Test.32 then
let Test.33 : [<rnu><null>, C {}] = CallByName Test.0;
ret Test.33;
else
let Test.29 : [<rnu><null>, C {}] = TagId(1) ;
ret Test.29;
procedure Test.11 (Test.30):
let Test.31 : Str = "done";
ret Test.31;
procedure Test.2 (Test.5):
let Test.17 : [<rnu><null>, C {}] = TagId(0) Test.5;
ret Test.17;
procedure Test.3 (Test.7):
let Test.14 : [<rnu><null>, C {}] = CallByName Test.2 Test.7;
ret Test.14;
procedure Test.6 (Test.16, #Attr.12):
let Test.5 : {} = UnionAtIndex (Id 0) (Index 0) #Attr.12;
dec #Attr.12;
let Test.19 : {} = Struct {};
let Test.25 : Str = "foobar";
let Test.20 : [<rnu><null>, C {}] = CallByName Test.8 Test.25 Test.5;
dec Test.25;
let Test.21 : U8 = GetTagId Test.20;
joinpoint Test.22 Test.18:
ret Test.18;
in
switch Test.21:
case 0:
let Test.23 : Str = CallByName Test.6 Test.19 Test.20;
jump Test.22 Test.23;
default:
dec Test.20;
let Test.24 : Str = CallByName Test.11 Test.19;
jump Test.22 Test.24;
procedure Test.8 (Test.9, Test.7):
let Test.27 : [<rnu><null>, C {}] = CallByName Test.10 Test.9;
ret Test.27;
procedure Test.0 ():
let Test.13 : {} = Struct {};
let Test.12 : [<rnu><null>, C {}] = CallByName Test.3 Test.13;
ret Test.12;

View File

@ -2551,3 +2551,23 @@ fn recursively_build_effect() {
"#
)
}
#[mono_test]
fn recursive_lambda_set_has_nested_non_recursive_lambda_sets_issue_5026() {
indoc!(
r#"
app "test" provides [looper] to "./platform"
Effect : {} -> Str
after = \buildNext ->
afterInner = \{} -> (buildNext "foobar") {}
afterInner
await : (Str -> Effect) -> Effect
await = \cont -> after (\result -> cont result)
looper = await \_ -> if Bool.true then looper else \{} -> "done"
"#
)
}

View File

@ -8,6 +8,7 @@ use crate::types::{
name_type_var, name_type_var_with_hint, AbilitySet, Polarity, RecordField, Uls,
};
use roc_collections::all::MutMap;
use roc_collections::VecSet;
use roc_module::ident::{Lowercase, TagName};
use roc_module::symbol::{Interns, ModuleId, Symbol};
@ -404,7 +405,7 @@ fn find_names_needed(
}
struct NamedResult {
recursion_structs_to_expand: Vec<Variable>,
recursion_structs_to_expand: VecSet<Variable>,
}
fn name_all_type_vars(variable: Variable, subs: &mut Subs, debug_print: DebugPrint) -> NamedResult {
@ -423,20 +424,27 @@ fn name_all_type_vars(variable: Variable, subs: &mut Subs, debug_print: DebugPri
debug_print.print_only_under_alias,
);
let mut recursion_structs_to_expand = vec![];
let mut recursion_structs_to_expand = VecSet::default();
for root in roots {
// show the type variable number instead of `*`. useful for debugging
// set_root_name(root, (format!("<{:?}>", root).into()), subs);
match appearances.get(&root) {
Some(Appearances::Multiple) => {
if let Content::RecursionVar { structure, .. } =
subs.get_content_without_compacting(root)
{
recursion_structs_to_expand
.insert(subs.get_root_key_without_compacting(*structure));
}
letters_used = name_root(letters_used, root, subs, &mut taken, debug_print);
}
Some(Appearances::Single) => {
if let Content::RecursionVar { structure, .. } =
subs.get_content_without_compacting(root)
{
recursion_structs_to_expand.push(*structure);
recursion_structs_to_expand
.insert(subs.get_root_key_without_compacting(*structure));
letters_used = name_root(letters_used, root, subs, &mut taken, debug_print);
} else if debug_print.print_weakened_vars && is_weakened_unbound(subs, root) {
letters_used = name_root(letters_used, root, subs, &mut taken, debug_print);
@ -554,11 +562,11 @@ fn set_root_name(root: Variable, name: Lowercase, subs: &mut Subs) {
#[derive(Default)]
struct Context<'a> {
able_variables: Vec<(&'a str, AbilitySet)>,
recursion_structs_to_expand: Vec<Variable>,
recursion_structs_to_expand: VecSet<Variable>,
}
fn content_to_string(
content: &Content,
fn variable_to_string(
var: Variable,
subs: &Subs,
home: ModuleId,
interns: &Interns,
@ -580,7 +588,7 @@ fn content_to_string(
write_content(
&env,
&mut ctx,
content,
var,
subs,
&mut buf,
Parens::Unnecessary,
@ -613,9 +621,8 @@ pub fn name_and_print_var(
debug_print: DebugPrint,
) -> String {
let named_result = name_all_type_vars(var, subs, debug_print);
let content = subs.get_content_without_compacting(var);
content_to_string(
content,
variable_to_string(
var,
subs,
home,
interns,
@ -625,21 +632,20 @@ pub fn name_and_print_var(
)
}
pub fn get_single_arg<'a>(subs: &'a Subs, args: &'a AliasVariables) -> &'a Content {
pub fn get_single_arg<'a>(subs: &'a Subs, args: &'a AliasVariables) -> Variable {
debug_assert_eq!(args.len(), 1);
let arg_var_index = args
.into_iter()
.next()
.expect("Num was not applied to a type argument!");
let arg_var = subs[arg_var_index];
subs.get_content_without_compacting(arg_var)
subs[arg_var_index]
}
fn write_content<'a>(
env: &Env,
ctx: &mut Context<'a>,
content: &Content,
var: Variable,
subs: &'a Subs,
buf: &mut String,
parens: Parens,
@ -647,7 +653,7 @@ fn write_content<'a>(
) {
use crate::subs::Content::*;
match content {
match subs.get_content_without_compacting(var) {
FlexVar(Some(name_index)) => {
let name = &subs.field_names[name_index.index as usize];
buf.push_str(name.as_str())
@ -676,22 +682,11 @@ fn write_content<'a>(
structure,
} => match opt_name {
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);
let structure_root = subs.get_root_key_without_compacting(*structure);
if ctx.recursion_structs_to_expand.remove(&structure_root) {
write_content(env, ctx, *structure, subs, buf, parens, pol);
write_content(
env,
ctx,
subs.get_content_without_compacting(*structure),
subs,
buf,
parens,
pol,
);
ctx.recursion_structs_to_expand.insert(structure_root);
} else {
let name = &subs.field_names[name_index.index as usize];
buf.push_str(name.as_str())
@ -701,14 +696,14 @@ fn write_content<'a>(
unreachable!("This should always be filled in!")
}
},
Structure(flat_type) => write_flat_type(env, ctx, flat_type, subs, buf, parens, pol),
Structure(flat_type) => write_flat_type(env, ctx, var, flat_type, subs, buf, parens, pol),
Alias(symbol, args, actual, _kind) => {
let write_parens = parens == Parens::InTypeParam && !args.is_empty();
match *symbol {
Symbol::NUM_NUM => {
let content = get_single_arg(subs, args);
match *content {
match *subs.get_content_without_compacting(content) {
Alias(nested, args, _actual, _kind) => match nested {
Symbol::NUM_INTEGER => {
write_integer(
@ -769,8 +764,7 @@ fn write_content<'a>(
|| args.any_infer_ext_var_is_material(subs) =>
{
write_parens!(write_parens, buf, {
let content = subs.get_content_without_compacting(*actual);
write_content(env, ctx, content, subs, buf, parens, pol)
write_content(env, ctx, *actual, subs, buf, parens, pol)
})
}
@ -780,21 +774,12 @@ fn write_content<'a>(
for var_index in args.named_type_arguments() {
let var = subs[var_index];
buf.push(' ');
write_content(
env,
ctx,
subs.get_content_without_compacting(var),
subs,
buf,
Parens::InTypeParam,
pol,
);
write_content(env, ctx, var, subs, buf, Parens::InTypeParam, pol);
}
roc_debug_flags::dbg_do!(roc_debug_flags::ROC_PRETTY_PRINT_ALIAS_CONTENTS, {
buf.push_str("[[ but really ");
let content = subs.get_content_without_compacting(*actual);
write_content(env, ctx, content, subs, buf, parens, pol);
write_content(env, ctx, *actual, subs, buf, parens, pol);
buf.push_str("]]");
});
}),
@ -846,28 +831,12 @@ fn write_content<'a>(
if let Some(rec_var) = recursion_var.into_variable() {
buf.push_str(" as ");
write_content(
env,
ctx,
subs.get_content_without_compacting(rec_var),
subs,
buf,
parens,
pol,
)
write_content(env, ctx, rec_var, subs, buf, parens, pol)
}
for Uls(var, member, region) in subs.get_subs_slice(*unspecialized) {
buf.push_str(" + ");
write_content(
env,
ctx,
subs.get_content_without_compacting(*var),
subs,
buf,
Parens::Unnecessary,
pol,
);
write_content(env, ctx, *var, subs, buf, Parens::Unnecessary, pol);
buf.push(':');
buf.push_str(&print_symbol(member));
buf.push(':');
@ -882,15 +851,7 @@ fn write_content<'a>(
if i > 0 {
buf.push_str(", ");
}
write_content(
env,
ctx,
subs.get_content_without_compacting(var),
subs,
buf,
Parens::Unnecessary,
pol,
);
write_content(env, ctx, var, subs, buf, Parens::Unnecessary, pol);
}
buf.push(')');
}
@ -901,7 +862,7 @@ fn write_content<'a>(
fn write_float<'a>(
env: &Env,
ctx: &mut Context<'a>,
content: &Content,
var: Variable,
subs: &'a Subs,
buf: &mut String,
parens: Parens,
@ -909,13 +870,13 @@ fn write_float<'a>(
pol: Polarity,
) {
use crate::subs::Content::*;
match content {
match subs.get_content_without_compacting(var) {
Alias(Symbol::NUM_BINARY32, _, _, _) => buf.push_str("F32"),
Alias(Symbol::NUM_BINARY64, _, _, _) => buf.push_str("F64"),
Alias(Symbol::NUM_DECIMAL, _, _, _) => buf.push_str("Dec"),
_ => write_parens!(write_parens, buf, {
buf.push_str("Float ");
write_content(env, ctx, content, subs, buf, parens, pol);
write_content(env, ctx, var, subs, buf, parens, pol);
}),
}
}
@ -923,7 +884,7 @@ fn write_float<'a>(
fn write_integer<'a>(
env: &Env,
ctx: &mut Context<'a>,
content: &Content,
var: Variable,
subs: &'a Subs,
buf: &mut String,
parens: Parens,
@ -934,19 +895,19 @@ fn write_integer<'a>(
macro_rules! derive_num_writes {
($($lit:expr, $tag:path)*) => {
match content {
match subs.get_content_without_compacting(var) {
$(
&Alias($tag, _, _, _) => {
buf.push_str($lit)
},
)*
actual => {
_ => {
write_parens!(
write_parens,
buf,
{
buf.push_str("Int ");
write_content(env, ctx, actual, subs, buf, parens, pol);
write_content(env, ctx, var, subs, buf, parens, pol);
}
)
}
@ -1008,13 +969,13 @@ fn write_ext_content<'a>(
parens: Parens,
pol: Polarity,
) {
if let ExtContent::Content(_, content) = ext_content {
if let ExtContent::Content(var, _) = ext_content {
// This is an open record or tag union, so print the variable
// right after the '}' or ']'
//
// e.g. the "*" at the end of `{ x: I64 }*`
// or the "r" at the end of `{ x: I64 }r`
write_content(env, ctx, content, subs, buf, parens, pol)
write_content(env, ctx, var, subs, buf, parens, pol)
}
}
@ -1046,15 +1007,7 @@ fn write_sorted_tags2<'a, L>(
for var in vars {
buf.push(' ');
write_content(
env,
ctx,
subs.get_content_without_compacting(*var),
subs,
buf,
Parens::InTypeParam,
pol,
);
write_content(env, ctx, *var, subs, buf, Parens::InTypeParam, pol);
}
}
}
@ -1099,15 +1052,7 @@ fn write_sorted_tags<'a>(
for var in vars {
buf.push(' ');
write_content(
env,
ctx,
subs.get_content_without_compacting(*var),
subs,
buf,
Parens::InTypeParam,
pol,
);
write_content(env, ctx, *var, subs, buf, Parens::InTypeParam, pol);
}
}
@ -1117,6 +1062,7 @@ fn write_sorted_tags<'a>(
fn write_flat_type<'a>(
env: &Env,
ctx: &mut Context<'a>,
var: Variable,
flat_type: &FlatType,
subs: &'a Subs,
buf: &mut String,
@ -1185,15 +1131,7 @@ fn write_flat_type<'a>(
Required(_) | Demanded(_) | RigidRequired(_) => buf.push_str(" : "),
};
write_content(
env,
ctx,
subs.get_content_without_compacting(var),
subs,
buf,
Parens::Unnecessary,
pol,
);
write_content(env, ctx, var, subs, buf, Parens::Unnecessary, pol);
}
buf.push_str(" }");
@ -1203,13 +1141,13 @@ fn write_flat_type<'a>(
Content::Structure(EmptyRecord) => {
// This is a closed record. We're done!
}
content => {
_ => {
// This is an open record, so print the variable
// right after the '}'
//
// e.g. the "*" at the end of `{ x: I64 }*`
// or the "r" at the end of `{ x: I64 }r`
write_content(env, ctx, content, subs, buf, parens, pol)
write_content(env, ctx, ext_var, subs, buf, parens, pol)
}
}
}
@ -1247,15 +1185,7 @@ fn write_flat_type<'a>(
}
expected_next_index = index + 1;
write_content(
env,
ctx,
subs.get_content_without_compacting(var),
subs,
buf,
Parens::Unnecessary,
pol,
);
write_content(env, ctx, var, subs, buf, Parens::Unnecessary, pol);
}
buf.push_str(" )");
@ -1264,13 +1194,13 @@ fn write_flat_type<'a>(
Content::Structure(EmptyTuple) => {
// This is a closed tuple. We're done!
}
content => {
_ => {
// This is an open tuple, so print the variable
// right after the ')'
//
// e.g. the "*" at the end of `( I64, I64 )*`
// or the "r" at the end of `( I64, I64 )r`
write_content(env, ctx, content, subs, buf, parens, pol)
write_content(env, ctx, ext_var, subs, buf, parens, pol)
}
}
}
@ -1319,6 +1249,9 @@ fn write_flat_type<'a>(
}
RecursiveTagUnion(rec_var, tags, ext_var) => {
ctx.recursion_structs_to_expand
.remove(&subs.get_root_key_without_compacting(var));
write_parens!(parens == Parens::InTypeParam, buf, {
buf.push('[');
@ -1346,15 +1279,7 @@ fn write_flat_type<'a>(
);
buf.push_str(" as ");
write_content(
env,
ctx,
subs.get_content_without_compacting(*rec_var),
subs,
buf,
parens,
pol,
)
write_content(env, ctx, *rec_var, subs, buf, parens, pol)
})
}
}
@ -1474,9 +1399,9 @@ fn write_apply<'a>(
Symbol::NUM_FLOATINGPOINT if nested_args.len() == 1 => {
buf.push_str("F64");
}
_ => default_case(subs, arg_content),
_ => default_case(subs, *arg),
},
_ => default_case(subs, arg_content),
_ => default_case(subs, *arg),
}
}
_ => {
@ -1488,15 +1413,7 @@ fn write_apply<'a>(
for arg in args {
buf.push(' ');
write_content(
env,
ctx,
subs.get_content_without_compacting(*arg),
subs,
buf,
Parens::InTypeParam,
pol,
);
write_content(env, ctx, *arg, subs, buf, Parens::InTypeParam, pol);
}
if write_parens {
@ -1532,42 +1449,18 @@ fn write_fn<'a>(
needs_comma = true;
}
write_content(
env,
ctx,
subs.get_content_without_compacting(*arg),
subs,
buf,
Parens::InFn,
Polarity::Neg,
);
write_content(env, ctx, *arg, subs, buf, Parens::InFn, Polarity::Neg);
}
if !env.debug.print_lambda_sets {
buf.push_str(" -> ");
} else {
buf.push_str(" -");
write_content(
env,
ctx,
subs.get_content_without_compacting(closure),
subs,
buf,
parens,
pol,
);
write_content(env, ctx, closure, subs, buf, parens, pol);
buf.push_str("-> ");
}
write_content(
env,
ctx,
subs.get_content_without_compacting(ret),
subs,
buf,
Parens::InFn,
Polarity::Pos,
);
write_content(env, ctx, ret, subs, buf, Parens::InFn, Polarity::Pos);
if use_parens {
buf.push(')');