mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-03 19:58:18 +00:00
Merge pull request #5286 from roc-lang/i5264
Freshly instantiate nested recursion variables under aliases and opaques
This commit is contained in:
commit
77cf60b866
9 changed files with 367 additions and 446 deletions
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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(())
|
||||
|
|
|
@ -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
|
|
@ -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
|
Loading…
Add table
Add a link
Reference in a new issue