Merge pull request #5286 from roc-lang/i5264

Freshly instantiate nested recursion variables under aliases and opaques
This commit is contained in:
Ayaz 2023-04-12 18:27:37 -05:00 committed by GitHub
commit 77cf60b866
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 367 additions and 446 deletions

View file

@ -9,6 +9,7 @@ use roc_mono::{
layout::STLayoutInterner,
};
use tempfile::tempdir;
use test_solve_helpers::format_problems;
#[derive(Default)]
pub struct MonoOptions {
@ -20,6 +21,7 @@ pub fn write_compiled_ir<'a>(
test_module: &str,
dependencies: impl IntoIterator<Item = (&'a str, &'a str)>,
options: MonoOptions,
allow_can_errors: bool,
) -> io::Result<()> {
use roc_packaging::cache::RocCacheDir;
use std::path::PathBuf;
@ -70,11 +72,30 @@ pub fn write_compiled_ir<'a>(
exposed_to_host,
mut layout_interner,
interns,
can_problems,
mut type_problems,
sources,
..
} = loaded;
let main_fn_symbol = exposed_to_host.top_level_values.keys().copied().next();
for (module, can_problems) in can_problems.into_iter() {
let type_problems = type_problems.remove(&module).unwrap_or_default();
let source = sources.get(&module).unwrap();
let (can_problems, type_problems) =
format_problems(&source.1, module, &interns, can_problems, type_problems);
if !can_problems.is_empty() && !allow_can_errors {
panic!("Canonicalization problems: {can_problems}");
}
if !type_problems.is_empty() {
panic!("Type problems: {type_problems}");
}
}
if !options.no_check {
check_procedures(arena, &interns, &mut layout_interner, &procedures);
}

View file

@ -36,6 +36,10 @@ lazy_static! {
.join("uitest")
.join("tests");
/// # +opt can:<opt>
static ref RE_OPT_CAN: Regex =
Regex::new(r#"# \+opt can:(?P<opt>.*)"#).unwrap();
/// # +opt infer:<opt>
static ref RE_OPT_INFER: Regex =
Regex::new(r#"# \+opt infer:(?P<opt>.*)"#).unwrap();
@ -90,6 +94,7 @@ fn into_test(path: PathBuf) -> io::Result<Trial> {
fn run_test(path: PathBuf) -> Result<(), Failed> {
let data = std::fs::read_to_string(&path)?;
let TestCase {
can_options,
infer_options,
emit_options,
mono_options,
@ -103,6 +108,7 @@ fn run_test(path: PathBuf) -> Result<(), Failed> {
.iter()
.map(|(md, src)| (&**md, &**src)),
infer_options,
can_options.allow_errors,
)?;
{
@ -115,6 +121,7 @@ fn run_test(path: PathBuf) -> Result<(), Failed> {
&mut fd,
program,
inferred_program,
can_options,
mono_options,
emit_options,
)?;
@ -134,12 +141,18 @@ struct Modules<'a> {
}
struct TestCase<'a> {
can_options: CanOptions,
infer_options: InferOptions,
mono_options: MonoOptions,
emit_options: EmitOptions,
program: Modules<'a>,
}
#[derive(Default)]
struct CanOptions {
allow_errors: bool,
}
#[derive(Default)]
struct EmitOptions {
can_decls: bool,
@ -153,6 +166,7 @@ impl<'a> TestCase<'a> {
data = data[..drop_at].trim_end();
}
let can_options = Self::parse_can_options(data)?;
let infer_options = Self::parse_infer_options(data)?;
let mono_options = Self::parse_mono_options(data)?;
let emit_options = Self::parse_emit_options(data)?;
@ -160,6 +174,7 @@ impl<'a> TestCase<'a> {
let program = Self::parse_modules(data);
Ok(TestCase {
can_options,
infer_options,
mono_options,
emit_options,
@ -214,6 +229,21 @@ impl<'a> TestCase<'a> {
}
}
fn parse_can_options(data: &str) -> Result<CanOptions, Failed> {
let mut can_opts = CanOptions::default();
let found_can_opts = RE_OPT_CAN.captures_iter(data);
for can_opt in found_can_opts {
let opt = can_opt.name("opt").unwrap().as_str();
match opt.trim() {
"allow_errors" => can_opts.allow_errors = true,
other => return Err(format!("unknown can option: {other:?}").into()),
}
}
Ok(can_opts)
}
fn parse_infer_options(data: &str) -> Result<InferOptions, Failed> {
let mut infer_opts = InferOptions {
no_promote: true,
@ -289,6 +319,7 @@ fn assemble_query_output(
writer: &mut impl io::Write,
program: Modules<'_>,
inferred_program: InferredProgram,
can_options: CanOptions,
mono_options: MonoOptions,
emit_options: EmitOptions,
) -> io::Result<()> {
@ -331,7 +362,13 @@ fn assemble_query_output(
// Unfortunately, with the current setup we must now recompile into the IR.
// TODO: extend the data returned by a monomorphized module to include
// that of a solved module.
mono::write_compiled_ir(writer, test_module, other_modules, mono_options)?;
mono::write_compiled_ir(
writer,
test_module,
other_modules,
mono_options,
can_options.allow_errors,
)?;
}
Ok(())

View file

@ -0,0 +1,18 @@
# +opt can:allow_errors
# +opt infer:print_only_under_alias
app "test" provides [single] to "./platform"
LL a : [Nil, Cons a (LL a)]
LinkedList a : LL a
single : a -> LinkedList a
single = \item -> (Cons item Nil)
#^^^^^^{-1} a -[[single(0)]]-> [Cons a b, Nil]* as b
walk : LinkedList elem, state, (state, elem -> state) -> state
walk = \list, state, fn ->
#^^^^{-1} [Cons elem a, Nil] as a, state, (state, elem -[[]]-> state) -[[walk(3)]]-> state
when list is
Nil -> state
Cons first rest -> walk (rest) (fn state first) fn

View file

@ -0,0 +1,16 @@
# +opt can:allow_errors
# +opt infer:print_only_under_alias
app "test" provides [single] to "./platform"
LL a : [Nil, Cons a (LL a)]
LinkedList a := LL a
single = \item -> @LinkedList (Cons item Nil)
#^^^^^^{-1} a -[[single(0)]]-> [Cons a b, Nil] as b
walk = \@LinkedList list, state, fn ->
#^^^^{-1} [Cons a b, Nil] as b, c, (c, a -[[]]-> c) -[[walk(3)]]-> c
when list is
Nil -> state
Cons first rest -> walk (@LinkedList rest) (fn state first) fn