Merge pull request #3201 from rtfeldman/addt-uls-fixes

Additional unspecialized lambda set fixes and tests
This commit is contained in:
Folkert de Vries 2022-06-08 16:00:30 +02:00 committed by GitHub
commit 9ab0a8f41d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 264 additions and 68 deletions

View file

@ -1938,7 +1938,7 @@ pub mod test_constrain {
use roc_parse::parser::{SourceError, SyntaxError}; use roc_parse::parser::{SourceError, SyntaxError};
use roc_region::all::Region; use roc_region::all::Region;
use roc_types::{ use roc_types::{
pretty_print::{name_and_print_var, PrintLambdaSets}, pretty_print::{name_and_print_var, DebugPrint},
solved_types::Solved, solved_types::Solved,
subs::{Subs, VarStore, Variable}, subs::{Subs, VarStore, Variable},
}; };
@ -2060,7 +2060,7 @@ pub mod test_constrain {
}; };
let actual_str = let actual_str =
name_and_print_var(var, subs, mod_id, &interns, PrintLambdaSets::No); name_and_print_var(var, subs, mod_id, &interns, DebugPrint::NOTHING);
assert_eq!(actual_str, expected_str); assert_eq!(actual_str, expected_str);
} }

View file

@ -30,7 +30,7 @@ mod test_load {
use roc_reporting::report::RocDocAllocator; use roc_reporting::report::RocDocAllocator;
use roc_target::TargetInfo; use roc_target::TargetInfo;
use roc_types::pretty_print::name_and_print_var; use roc_types::pretty_print::name_and_print_var;
use roc_types::pretty_print::PrintLambdaSets; use roc_types::pretty_print::DebugPrint;
use roc_types::subs::Subs; use roc_types::subs::Subs;
use std::collections::HashMap; use std::collections::HashMap;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
@ -239,7 +239,7 @@ mod test_load {
) { ) {
for (symbol, expr_var) in &def.pattern_vars { for (symbol, expr_var) in &def.pattern_vars {
let actual_str = let actual_str =
name_and_print_var(*expr_var, subs, home, interns, PrintLambdaSets::No); name_and_print_var(*expr_var, subs, home, interns, DebugPrint::NOTHING);
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())

View file

@ -1791,14 +1791,14 @@ fn compact_lambda_set(
arena: &Bump, arena: &Bump,
pools: &mut Pools, pools: &mut Pools,
abilities_store: &AbilitiesStore, abilities_store: &AbilitiesStore,
lambda_set: Variable, this_lambda_set: Variable,
) { ) {
let LambdaSet { let LambdaSet {
solved, solved,
recursion_var, recursion_var,
unspecialized, unspecialized,
} = subs.get_lambda_set(lambda_set); } = subs.get_lambda_set(this_lambda_set);
let target_rank = subs.get_rank(lambda_set); let target_rank = subs.get_rank(this_lambda_set);
if unspecialized.is_empty() { if unspecialized.is_empty() {
return; return;
@ -1854,7 +1854,9 @@ fn compact_lambda_set(
}; };
// Ensure the specialization lambda set is already compacted. // Ensure the specialization lambda set is already compacted.
compact_lambda_set(subs, arena, pools, abilities_store, specialized_lambda_set); if subs.get_root_key(specialized_lambda_set) != subs.get_root_key(this_lambda_set) {
compact_lambda_set(subs, arena, pools, abilities_store, specialized_lambda_set);
}
// Ensure the specialization lambda set we'll unify with is not a generalized one, but one // Ensure the specialization lambda set we'll unify with is not a generalized one, but one
// at the rank of the lambda set being compacted. // at the rank of the lambda set being compacted.
@ -1871,14 +1873,14 @@ fn compact_lambda_set(
recursion_var, recursion_var,
unspecialized: new_unspecialized_slice, unspecialized: new_unspecialized_slice,
}); });
subs.set_content(lambda_set, partial_compacted_lambda_set); subs.set_content(this_lambda_set, partial_compacted_lambda_set);
for other_specialized in specialized_to_unify_with.into_iter() { for other_specialized in specialized_to_unify_with.into_iter() {
let (vars, must_implement_ability, lambda_sets_to_specialize) = let (vars, must_implement_ability, lambda_sets_to_specialize) =
unify(subs, lambda_set, other_specialized, Mode::EQ) unify(subs, this_lambda_set, other_specialized, Mode::EQ)
.expect_success("lambda sets don't unify"); .expect_success("lambda sets don't unify");
introduce(subs, subs.get_rank(lambda_set), pools, &vars); introduce(subs, subs.get_rank(this_lambda_set), pools, &vars);
debug_assert!( debug_assert!(
must_implement_ability.is_empty(), must_implement_ability.is_empty(),

View file

@ -19,7 +19,7 @@ mod solve_expr {
use roc_region::all::{LineColumn, LineColumnRegion, LineInfo, Region}; use roc_region::all::{LineColumn, LineColumnRegion, LineInfo, Region};
use roc_reporting::report::{can_problem, type_problem, RocDocAllocator}; use roc_reporting::report::{can_problem, type_problem, RocDocAllocator};
use roc_solve::solve::TypeError; use roc_solve::solve::TypeError;
use roc_types::pretty_print::{name_and_print_var, PrintLambdaSets}; use roc_types::pretty_print::{name_and_print_var, DebugPrint};
use std::path::PathBuf; use std::path::PathBuf;
// HELPERS // HELPERS
@ -177,7 +177,7 @@ mod solve_expr {
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();
let actual_str = name_and_print_var(variable, subs, home, &interns, PrintLambdaSets::No); let actual_str = name_and_print_var(variable, subs, home, &interns, DebugPrint::NOTHING);
Ok((type_problems, can_problems, actual_str)) Ok((type_problems, can_problems, actual_str))
} }
@ -235,7 +235,7 @@ mod solve_expr {
assert_eq!(actual, expected.to_string()); assert_eq!(actual, expected.to_string());
} }
fn infer_queries(src: &str, expected: &[&'static str]) { fn infer_queries_help(src: &str, expected: &[&'static str], print_only_under_alias: bool) {
let ( let (
LoadedModule { LoadedModule {
module_id: home, module_id: home,
@ -277,7 +277,16 @@ 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 actual_str = name_and_print_var(var, subs, home, &interns, PrintLambdaSets::Yes); let actual_str = name_and_print_var(
var,
subs,
home,
&interns,
DebugPrint {
print_lambda_sets: true,
print_only_under_alias,
},
);
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) {
@ -301,6 +310,15 @@ mod solve_expr {
assert_eq!(solved_queries, expected) assert_eq!(solved_queries, expected)
} }
macro_rules! infer_queries {
($program:expr, $queries:expr $(,)?) => {
infer_queries_help($program, $queries, false)
};
($program:expr, $queries:expr, print_only_under_alias=true $(,)?) => {
infer_queries_help($program, $queries, true)
};
}
fn check_inferred_abilities<'a, I>(src: &'a str, expected_specializations: I) fn check_inferred_abilities<'a, I>(src: &'a str, expected_specializations: I)
where where
I: IntoIterator<Item = (&'a str, &'a str)>, I: IntoIterator<Item = (&'a str, &'a str)>,
@ -6150,7 +6168,7 @@ mod solve_expr {
#[test] #[test]
fn intermediate_branch_types() { fn intermediate_branch_types() {
infer_queries( infer_queries!(
indoc!( indoc!(
r#" r#"
app "test" provides [foo] to "./platform" app "test" provides [foo] to "./platform"
@ -6278,7 +6296,7 @@ mod solve_expr {
#[test] #[test]
fn encoder() { fn encoder() {
infer_queries( infer_queries!(
indoc!( indoc!(
r#" r#"
app "test" provides [myU8Bytes] to "./platform" app "test" provides [myU8Bytes] to "./platform"
@ -6324,7 +6342,7 @@ mod solve_expr {
#[test] #[test]
fn decoder() { fn decoder() {
infer_queries( infer_queries!(
indoc!( indoc!(
r#" r#"
app "test" provides [myU8] to "./platform" app "test" provides [myU8] to "./platform"
@ -6406,7 +6424,7 @@ mod solve_expr {
#[test] #[test]
fn static_specialization() { fn static_specialization() {
infer_queries( infer_queries!(
indoc!( indoc!(
r#" r#"
app "test" provides [main] to "./platform" app "test" provides [main] to "./platform"
@ -6455,7 +6473,7 @@ mod solve_expr {
#[test] #[test]
fn encode_record() { fn encode_record() {
infer_queries( infer_queries!(
indoc!( indoc!(
r#" r#"
app "test" app "test"
@ -6474,7 +6492,7 @@ mod solve_expr {
#[test] #[test]
fn encode_record_with_nested_custom_impl() { fn encode_record_with_nested_custom_impl() {
infer_queries( infer_queries!(
indoc!( indoc!(
r#" r#"
app "test" app "test"
@ -6494,7 +6512,7 @@ mod solve_expr {
#[test] #[test]
fn resolve_lambda_set_generalized_ability_alias() { fn resolve_lambda_set_generalized_ability_alias() {
infer_queries( infer_queries!(
indoc!( indoc!(
r#" r#"
app "test" provides [main] to "./platform" app "test" provides [main] to "./platform"
@ -6529,7 +6547,7 @@ mod solve_expr {
#[test] #[test]
fn resolve_lambda_set_ability_chain() { fn resolve_lambda_set_ability_chain() {
infer_queries( infer_queries!(
indoc!( indoc!(
r#" r#"
app "test" provides [main] to "./platform" app "test" provides [main] to "./platform"
@ -6565,7 +6583,7 @@ mod solve_expr {
#[test] #[test]
fn resolve_lambda_set_branches_ability_vs_non_ability() { fn resolve_lambda_set_branches_ability_vs_non_ability() {
infer_queries( infer_queries!(
indoc!( indoc!(
r#" r#"
app "test" provides [main] to "./platform" app "test" provides [main] to "./platform"
@ -6603,7 +6621,7 @@ mod solve_expr {
#[test] #[test]
fn resolve_lambda_set_branches_same_ability() { fn resolve_lambda_set_branches_same_ability() {
infer_queries( infer_queries!(
indoc!( indoc!(
r#" r#"
app "test" provides [main] to "./platform" app "test" provides [main] to "./platform"
@ -6634,4 +6652,169 @@ mod solve_expr {
], ],
) )
} }
#[test]
fn resolve_unspecialized_lambda_set_behind_alias() {
infer_queries!(
indoc!(
r#"
app "test" provides [main] to "./platform"
Thunk a : {} -> a
Id has id : a -> Thunk a | a has Id
A := {}
id = \@A {} -> \{} -> @A {}
#^^{-1}
main =
alias = id
# ^^
a : A
a = (alias (@A {})) {}
# ^^^^^
a
"#
),
&[
"A#id(7) : {} -[[id(7)]]-> ({} -[[8(8)]]-> {})",
"Id#id(6) : {} -[[id(7)]]-> ({} -[[8(8)]]-> {})",
"alias : {} -[[id(7)]]-> ({} -[[8(8)]]-> {})",
],
print_only_under_alias = true,
)
}
#[test]
fn resolve_unspecialized_lambda_set_behind_opaque() {
infer_queries!(
indoc!(
r#"
app "test" provides [main] to "./platform"
Thunk a := {} -> a
Id has id : a -> Thunk a | a has Id
A := {}
id = \@A {} -> @Thunk (\{} -> @A {})
#^^{-1}
main =
thunk = id (@A {})
@Thunk it = thunk
it {}
#^^{-1}
"#
),
&[
"A#id(7) : {} -[[id(7)]]-> ({} -[[8(8)]]-> {})",
"it : {} -[[8(8)]]-> {}",
],
print_only_under_alias = true,
)
}
#[test]
fn resolve_two_unspecialized_lambda_sets_in_one_lambda_set() {
infer_queries!(
indoc!(
r#"
app "test" provides [main] to "./platform"
Thunk a : {} -> a
Id has id : a -> Thunk a | a has Id
A := {}
id = \@A {} -> \{} -> @A {}
#^^{-1}
main =
a : A
a = (id (@A {})) {}
# ^^
a
"#
),
&[
"A#id(7) : {} -[[id(7)]]-> ({} -[[8(8)]]-> {})",
"A#id(7) : {} -[[id(7)]]-> ({} -[[8(8)]]-> {})",
],
print_only_under_alias = true,
)
}
#[test]
fn resolve_recursive_ability_lambda_set() {
infer_queries!(
indoc!(
r#"
app "test" provides [main] to "./platform"
Diverge has diverge : a -> a | a has Diverge
A := {}
diverge = \@A {} -> diverge (@A {})
#^^^^^^^{-1} ^^^^^^^
main =
a : A
a = diverge (@A {})
# ^^^^^^^
a
"#
),
&[
"A#diverge(5) : A -[[diverge(5)]]-> A",
"Diverge#diverge(4) : A -[[diverge(5)]]-> A",
//
"A#diverge(5) : A -[[diverge(5)]]-> A",
],
)
}
#[test]
fn resolve_mutually_recursive_ability_lambda_sets() {
infer_queries!(
indoc!(
r#"
app "test" provides [main] to "./platform"
Bounce has
ping : a -> a | a has Bounce
pong : a -> a | a has Bounce
A := {}
ping = \@A {} -> pong (@A {})
#^^^^{-1} ^^^^
pong = \@A {} -> ping (@A {})
#^^^^{-1} ^^^^
main =
a : A
a = ping (@A {})
# ^^^^
a
"#
),
&[
"A#ping(7) : A -[[ping(7)]]-> A",
"Bounce#pong(6) : A -[[pong(8)]]-> A",
//
"A#pong(8) : A -[[pong(8)]]-> A",
"A#ping(7) : A -[[ping(7)]]-> A",
//
"A#ping(7) : A -[[ping(7)]]-> A",
],
)
}
} }

View file

@ -48,15 +48,22 @@ macro_rules! write_parens {
}; };
} }
pub enum PrintLambdaSets { pub struct DebugPrint {
Yes, pub print_lambda_sets: bool,
No, pub print_only_under_alias: bool,
}
impl DebugPrint {
pub const NOTHING: DebugPrint = DebugPrint {
print_lambda_sets: false,
print_only_under_alias: false,
};
} }
struct Env<'a> { struct Env<'a> {
home: ModuleId, home: ModuleId,
interns: &'a Interns, interns: &'a Interns,
print_lambda_sets: PrintLambdaSets, debug: DebugPrint,
} }
/// How many times a root variable appeared in Subs. /// How many times a root variable appeared in Subs.
@ -376,13 +383,13 @@ fn content_to_string(
home: ModuleId, home: ModuleId,
interns: &Interns, interns: &Interns,
named_result: NamedResult, named_result: NamedResult,
print_lambda_sets: PrintLambdaSets, debug_print: DebugPrint,
) -> String { ) -> String {
let mut buf = String::new(); let mut buf = String::new();
let env = Env { let env = Env {
home, home,
interns, interns,
print_lambda_sets, debug: debug_print,
}; };
let mut ctx = Context { let mut ctx = Context {
able_variables: vec![], able_variables: vec![],
@ -408,18 +415,11 @@ pub fn name_and_print_var(
subs: &mut Subs, subs: &mut Subs,
home: ModuleId, home: ModuleId,
interns: &Interns, interns: &Interns,
print_lambda_sets: PrintLambdaSets, debug_print: DebugPrint,
) -> String { ) -> String {
let named_result = 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);
content_to_string( content_to_string(content, subs, home, interns, named_result, debug_print)
content,
subs,
home,
interns,
named_result,
print_lambda_sets,
)
} }
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) -> &'a Content {
@ -495,7 +495,7 @@ fn write_content<'a>(
} }
}, },
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) => {
let write_parens = parens == Parens::InTypeParam && !args.is_empty(); let write_parens = parens == Parens::InTypeParam && !args.is_empty();
match *symbol { match *symbol {
@ -553,6 +553,11 @@ fn write_content<'a>(
write_parens, write_parens,
), ),
_ if env.debug.print_only_under_alias => write_parens!(write_parens, buf, {
let content = subs.get_content_without_compacting(*actual);
write_content(env, ctx, content, subs, buf, parens)
}),
_ => write_parens!(write_parens, buf, { _ => write_parens!(write_parens, buf, {
write_symbol(env, *symbol, buf); write_symbol(env, *symbol, buf);
@ -571,7 +576,7 @@ fn write_content<'a>(
roc_debug_flags::dbg_do!(roc_debug_flags::ROC_PRETTY_PRINT_ALIAS_CONTENTS, { roc_debug_flags::dbg_do!(roc_debug_flags::ROC_PRETTY_PRINT_ALIAS_CONTENTS, {
buf.push_str("[[ but really "); buf.push_str("[[ but really ");
let content = subs.get_content_without_compacting(*_actual); let content = subs.get_content_without_compacting(*actual);
write_content(env, ctx, content, subs, buf, parens); write_content(env, ctx, content, subs, buf, parens);
buf.push_str("]]"); buf.push_str("]]");
}); });
@ -583,7 +588,7 @@ fn write_content<'a>(
recursion_var, recursion_var,
unspecialized, unspecialized,
}) => { }) => {
debug_assert!(matches!(env.print_lambda_sets, PrintLambdaSets::Yes)); debug_assert!(env.debug.print_lambda_sets);
buf.push_str("[["); buf.push_str("[[");
@ -1192,22 +1197,19 @@ fn write_fn<'a>(
); );
} }
match env.print_lambda_sets { if !env.debug.print_lambda_sets {
PrintLambdaSets::No => { buf.push_str(" -> ");
buf.push_str(" -> "); } else {
} buf.push_str(" -");
PrintLambdaSets::Yes => { write_content(
buf.push_str(" -"); env,
write_content( ctx,
env, subs.get_content_without_compacting(closure),
ctx, subs,
subs.get_content_without_compacting(closure), buf,
subs, parens,
buf, );
parens, buf.push_str("-> ");
);
buf.push_str("-> ");
}
} }
write_content( write_content(

View file

@ -2786,7 +2786,10 @@ fn instantiate_lambda_sets_as_unspecialized(
type_arguments, type_arguments,
lambda_set_variables, lambda_set_variables,
}) => { }) => {
stack.extend(lambda_set_variables.iter_mut().rev().map(|ls| &mut ls.0)); for lambda_set in lambda_set_variables.iter_mut() {
debug_assert!(matches!(lambda_set.0, Type::Variable(_)));
lambda_set.0 = new_uls();
}
stack.extend(type_arguments.iter_mut().rev()); stack.extend(type_arguments.iter_mut().rev());
} }
Type::Alias { Type::Alias {
@ -2796,8 +2799,11 @@ fn instantiate_lambda_sets_as_unspecialized(
actual, actual,
kind: _, kind: _,
} => { } => {
for lambda_set in lambda_set_variables.iter_mut() {
debug_assert!(matches!(lambda_set.0, Type::Variable(_)));
lambda_set.0 = new_uls();
}
stack.push(actual); stack.push(actual);
stack.extend(lambda_set_variables.iter_mut().rev().map(|ls| &mut ls.0));
stack.extend(type_arguments.iter_mut().rev().map(|t| &mut t.typ)); stack.extend(type_arguments.iter_mut().rev().map(|t| &mut t.typ));
} }
Type::HostExposedAlias { Type::HostExposedAlias {
@ -2807,8 +2813,11 @@ fn instantiate_lambda_sets_as_unspecialized(
actual_var: _, actual_var: _,
actual, actual,
} => { } => {
for lambda_set in lambda_set_variables.iter_mut() {
debug_assert!(matches!(lambda_set.0, Type::Variable(_)));
lambda_set.0 = new_uls();
}
stack.push(actual); stack.push(actual);
stack.extend(lambda_set_variables.iter_mut().rev().map(|ls| &mut ls.0));
stack.extend(type_arguments.iter_mut().rev()); stack.extend(type_arguments.iter_mut().rev());
} }
Type::Apply(_sym, args, _region) => { Type::Apply(_sym, args, _region) => {

View file

@ -60,7 +60,7 @@ 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_and_print_var; use roc_types::pretty_print::name_and_print_var;
use roc_types::pretty_print::PrintLambdaSets; use roc_types::pretty_print::DebugPrint;
use roc_types::solved_types::Solved; use roc_types::solved_types::Solved;
use roc_types::subs::{Subs, VarStore, Variable}; use roc_types::subs::{Subs, VarStore, Variable};
use snafu::OptionExt; use snafu::OptionExt;
@ -468,7 +468,7 @@ impl<'a> EdModel<'a> {
subs, subs,
self.module.env.home, self.module.env.home,
&self.loaded_module.interns, &self.loaded_module.interns,
PrintLambdaSets::No, DebugPrint::NOTHING,
); );
PoolStr::new(&pretty_var, self.module.env.pool) PoolStr::new(&pretty_var, self.module.env.pool)

View file

@ -23,7 +23,7 @@ use roc_repl_eval::{ReplApp, ReplAppMemory};
use roc_reporting::report::DEFAULT_PALETTE; use roc_reporting::report::DEFAULT_PALETTE;
use roc_std::RocStr; use roc_std::RocStr;
use roc_target::TargetInfo; use roc_target::TargetInfo;
use roc_types::pretty_print::{name_and_print_var, PrintLambdaSets}; use roc_types::pretty_print::{name_and_print_var, DebugPrint};
const BLUE: &str = "\u{001b}[36m"; const BLUE: &str = "\u{001b}[36m";
const PINK: &str = "\u{001b}[35m"; const PINK: &str = "\u{001b}[35m";
@ -228,7 +228,7 @@ fn gen_and_eval_llvm<'a>(
// pretty-print the expr type string for later. // pretty-print the expr type string for later.
let expr_type_str = let expr_type_str =
name_and_print_var(main_fn_var, &mut subs, home, &interns, PrintLambdaSets::No); name_and_print_var(main_fn_var, &mut subs, home, &interns, DebugPrint::NOTHING);
let content = subs.get_content_without_compacting(main_fn_var); let content = subs.get_content_without_compacting(main_fn_var);
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) {

View file

@ -12,7 +12,7 @@ use roc_repl_eval::{
}; };
use roc_reporting::report::DEFAULT_PALETTE_HTML; use roc_reporting::report::DEFAULT_PALETTE_HTML;
use roc_target::TargetInfo; use roc_target::TargetInfo;
use roc_types::pretty_print::{name_and_print_var, PrintLambdaSets}; use roc_types::pretty_print::{name_and_print_var, DebugPrint};
use crate::{js_create_app, js_get_result_and_memory, js_run_app}; use crate::{js_create_app, js_get_result_and_memory, js_run_app};
@ -189,7 +189,7 @@ pub async fn entrypoint_from_js(src: String) -> Result<String, String> {
&mut subs, &mut subs,
module_id, module_id,
&interns, &interns,
PrintLambdaSets::No, DebugPrint::NOTHING,
); );
let content = subs.get_content_without_compacting(main_fn_var); let content = subs.get_content_without_compacting(main_fn_var);