mirror of
https://github.com/roc-lang/roc.git
synced 2025-11-02 22:01:20 +00:00
Refactor solve test helpers into a new module
This commit is contained in:
parent
0bb8c60b93
commit
1227d10731
4 changed files with 293 additions and 270 deletions
|
|
@ -7,6 +7,11 @@ edition.workspace = true
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
version.workspace = true
|
version.workspace = true
|
||||||
|
|
||||||
|
[[test]]
|
||||||
|
name = "instantiate"
|
||||||
|
path = "tests/instantiate.rs"
|
||||||
|
harness = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
roc_can = { path = "../can" }
|
roc_can = { path = "../can" }
|
||||||
roc_collections = { path = "../collections" }
|
roc_collections = { path = "../collections" }
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,16 @@
|
||||||
extern crate bumpalo;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use regex::Regex;
|
||||||
|
use roc_can::traverse::{find_ability_member_and_owning_type_at, find_type_at};
|
||||||
|
use roc_load::LoadedModule;
|
||||||
|
use roc_module::symbol::{Interns, ModuleId};
|
||||||
|
use roc_packaging::cache::RocCacheDir;
|
||||||
|
use roc_problem::can::Problem;
|
||||||
|
use roc_region::all::{LineColumn, LineColumnRegion, LineInfo, Region};
|
||||||
|
use roc_reporting::report::{can_problem, type_problem, RocDocAllocator};
|
||||||
|
use roc_solve_problem::TypeError;
|
||||||
|
use roc_types::pretty_print::{name_and_print_var, DebugPrint};
|
||||||
|
|
||||||
/// Used in the with_larger_debug_stack() function, for tests that otherwise
|
/// Used in the with_larger_debug_stack() function, for tests that otherwise
|
||||||
/// run out of stack space in debug builds (but don't in --release builds)
|
/// run out of stack space in debug builds (but don't in --release builds)
|
||||||
|
|
@ -39,3 +51,272 @@ where
|
||||||
{
|
{
|
||||||
run_test()
|
run_test()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn promote_expr_to_module(src: &str) -> String {
|
||||||
|
let mut buffer = String::from(indoc!(
|
||||||
|
r#"
|
||||||
|
app "test"
|
||||||
|
imports []
|
||||||
|
provides [main] to "./platform"
|
||||||
|
|
||||||
|
main =
|
||||||
|
"#
|
||||||
|
));
|
||||||
|
|
||||||
|
for line in src.lines() {
|
||||||
|
// indent the body!
|
||||||
|
buffer.push_str(" ");
|
||||||
|
buffer.push_str(line);
|
||||||
|
buffer.push('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run_load_and_infer(src: &str) -> Result<(LoadedModule, String), std::io::Error> {
|
||||||
|
use bumpalo::Bump;
|
||||||
|
use tempfile::tempdir;
|
||||||
|
|
||||||
|
let arena = &Bump::new();
|
||||||
|
|
||||||
|
let module_src;
|
||||||
|
let temp;
|
||||||
|
if src.starts_with("app") {
|
||||||
|
// this is already a module
|
||||||
|
module_src = src;
|
||||||
|
} else {
|
||||||
|
// this is an expression, promote it to a module
|
||||||
|
temp = promote_expr_to_module(src);
|
||||||
|
module_src = &temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
let loaded = {
|
||||||
|
let dir = tempdir()?;
|
||||||
|
let filename = PathBuf::from("Test.roc");
|
||||||
|
let file_path = dir.path().join(filename);
|
||||||
|
let result = roc_load::load_and_typecheck_str(
|
||||||
|
arena,
|
||||||
|
file_path,
|
||||||
|
module_src,
|
||||||
|
dir.path().to_path_buf(),
|
||||||
|
roc_target::TargetInfo::default_x86_64(),
|
||||||
|
roc_reporting::report::RenderTarget::Generic,
|
||||||
|
RocCacheDir::Disallowed,
|
||||||
|
roc_reporting::report::DEFAULT_PALETTE,
|
||||||
|
);
|
||||||
|
|
||||||
|
dir.close()?;
|
||||||
|
|
||||||
|
result
|
||||||
|
};
|
||||||
|
|
||||||
|
let loaded = loaded.expect("failed to load module");
|
||||||
|
Ok((loaded, module_src.to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn format_problems(
|
||||||
|
src: &str,
|
||||||
|
home: ModuleId,
|
||||||
|
interns: &Interns,
|
||||||
|
can_problems: Vec<Problem>,
|
||||||
|
type_problems: Vec<TypeError>,
|
||||||
|
) -> (String, String) {
|
||||||
|
let filename = PathBuf::from("test.roc");
|
||||||
|
let src_lines: Vec<&str> = src.split('\n').collect();
|
||||||
|
let lines = LineInfo::new(src);
|
||||||
|
let alloc = RocDocAllocator::new(&src_lines, home, interns);
|
||||||
|
|
||||||
|
let mut can_reports = vec![];
|
||||||
|
let mut type_reports = vec![];
|
||||||
|
|
||||||
|
for problem in can_problems {
|
||||||
|
let report = can_problem(&alloc, &lines, filename.clone(), problem.clone());
|
||||||
|
can_reports.push(report.pretty(&alloc));
|
||||||
|
}
|
||||||
|
|
||||||
|
for problem in type_problems {
|
||||||
|
if let Some(report) = type_problem(&alloc, &lines, filename.clone(), problem.clone()) {
|
||||||
|
type_reports.push(report.pretty(&alloc));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut can_reports_buf = String::new();
|
||||||
|
let mut type_reports_buf = String::new();
|
||||||
|
use roc_reporting::report::CiWrite;
|
||||||
|
alloc
|
||||||
|
.stack(can_reports)
|
||||||
|
.1
|
||||||
|
.render_raw(70, &mut CiWrite::new(&mut can_reports_buf))
|
||||||
|
.unwrap();
|
||||||
|
alloc
|
||||||
|
.stack(type_reports)
|
||||||
|
.1
|
||||||
|
.render_raw(70, &mut CiWrite::new(&mut type_reports_buf))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
(can_reports_buf, type_reports_buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
/// Queries of the form
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// ^^^{(directive),*}?
|
||||||
|
///
|
||||||
|
/// directive :=
|
||||||
|
/// -\d+ # shift the query left by N columns
|
||||||
|
/// inst # instantiate the given generic instance
|
||||||
|
/// ```
|
||||||
|
static ref RE_TYPE_QUERY: Regex =
|
||||||
|
Regex::new(r#"(?P<where>\^+)(?:\{-(?P<sub>\d+)\})?"#).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
struct TypeQuery(Region);
|
||||||
|
|
||||||
|
/// Parse inference queries in a Roc program.
|
||||||
|
/// See [RE_TYPE_QUERY].
|
||||||
|
fn parse_queries(src: &str) -> Vec<TypeQuery> {
|
||||||
|
let line_info = LineInfo::new(src);
|
||||||
|
let mut queries = vec![];
|
||||||
|
let mut consecutive_query_lines = 0;
|
||||||
|
for (i, line) in src.lines().enumerate() {
|
||||||
|
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")
|
||||||
|
.and_then(|m| str::parse(m.as_str()).ok())
|
||||||
|
.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 - consecutive_query_lines;
|
||||||
|
let start_lc = LineColumn {
|
||||||
|
line: last_line,
|
||||||
|
column: start,
|
||||||
|
};
|
||||||
|
let end_lc = LineColumn {
|
||||||
|
line: last_line,
|
||||||
|
column: end,
|
||||||
|
};
|
||||||
|
let lc_region = LineColumnRegion::new(start_lc, end_lc);
|
||||||
|
let region = line_info.convert_line_column_region(lc_region);
|
||||||
|
|
||||||
|
queries.push(TypeQuery(region));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
queries
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct InferOptions {
|
||||||
|
pub print_can_decls: bool,
|
||||||
|
pub print_only_under_alias: bool,
|
||||||
|
pub allow_errors: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn infer_queries_help(src: &str, expected: impl FnOnce(&str), options: InferOptions) {
|
||||||
|
let (
|
||||||
|
LoadedModule {
|
||||||
|
module_id: home,
|
||||||
|
mut can_problems,
|
||||||
|
mut type_problems,
|
||||||
|
mut declarations_by_id,
|
||||||
|
mut solved,
|
||||||
|
interns,
|
||||||
|
abilities_store,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
src,
|
||||||
|
) = run_load_and_infer(src).unwrap();
|
||||||
|
|
||||||
|
let decls = declarations_by_id.remove(&home).unwrap();
|
||||||
|
let subs = solved.inner_mut();
|
||||||
|
|
||||||
|
let can_problems = can_problems.remove(&home).unwrap_or_default();
|
||||||
|
let type_problems = type_problems.remove(&home).unwrap_or_default();
|
||||||
|
|
||||||
|
let (can_problems, type_problems) =
|
||||||
|
format_problems(&src, home, &interns, can_problems, type_problems);
|
||||||
|
|
||||||
|
if !options.allow_errors {
|
||||||
|
assert!(
|
||||||
|
can_problems.is_empty(),
|
||||||
|
"Canonicalization problems: {}",
|
||||||
|
can_problems
|
||||||
|
);
|
||||||
|
assert!(type_problems.is_empty(), "Type problems: {}", type_problems);
|
||||||
|
}
|
||||||
|
|
||||||
|
let queries = parse_queries(&src);
|
||||||
|
assert!(!queries.is_empty(), "No queries provided!");
|
||||||
|
|
||||||
|
let mut output_parts = Vec::with_capacity(queries.len() + 2);
|
||||||
|
|
||||||
|
if options.print_can_decls {
|
||||||
|
use roc_can::debug::{pretty_print_declarations, PPCtx};
|
||||||
|
let ctx = PPCtx {
|
||||||
|
home,
|
||||||
|
interns: &interns,
|
||||||
|
print_lambda_names: true,
|
||||||
|
};
|
||||||
|
let pretty_decls = pretty_print_declarations(&ctx, &decls);
|
||||||
|
output_parts.push(pretty_decls);
|
||||||
|
output_parts.push("\n".to_owned());
|
||||||
|
}
|
||||||
|
|
||||||
|
for TypeQuery(region) in queries.into_iter() {
|
||||||
|
let start = region.start().offset;
|
||||||
|
let end = region.end().offset;
|
||||||
|
let text = &src[start as usize..end as usize];
|
||||||
|
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,
|
||||||
|
home,
|
||||||
|
&interns,
|
||||||
|
DebugPrint {
|
||||||
|
print_lambda_sets: true,
|
||||||
|
print_only_under_alias: options.print_only_under_alias,
|
||||||
|
ignore_polarity: true,
|
||||||
|
print_weakened_vars: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
subs.rollback_to(snapshot);
|
||||||
|
|
||||||
|
let elaborated =
|
||||||
|
match find_ability_member_and_owning_type_at(region, &decls, &abilities_store) {
|
||||||
|
Some((spec_type, spec_symbol)) => {
|
||||||
|
format!(
|
||||||
|
"{}#{}({}) : {}",
|
||||||
|
spec_type.as_str(&interns),
|
||||||
|
text,
|
||||||
|
spec_symbol.ident_id().index(),
|
||||||
|
actual_str
|
||||||
|
)
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
format!("{} : {}", text, actual_str)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
output_parts.push(elaborated);
|
||||||
|
}
|
||||||
|
|
||||||
|
let pretty_output = output_parts.join("\n");
|
||||||
|
|
||||||
|
expected(&pretty_output);
|
||||||
|
}
|
||||||
|
|
|
||||||
1
crates/compiler/solve/tests/instantiate.rs
Normal file
1
crates/compiler/solve/tests/instantiate.rs
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
fn main() {}
|
||||||
|
|
@ -9,160 +9,20 @@ mod helpers;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod solve_expr {
|
mod solve_expr {
|
||||||
use crate::helpers::with_larger_debug_stack;
|
use crate::helpers::{
|
||||||
use lazy_static::lazy_static;
|
format_problems, infer_queries_help, run_load_and_infer, with_larger_debug_stack,
|
||||||
use regex::Regex;
|
InferOptions,
|
||||||
use roc_can::{
|
|
||||||
abilities::ImplKey,
|
|
||||||
traverse::{find_ability_member_and_owning_type_at, find_type_at},
|
|
||||||
};
|
};
|
||||||
|
use roc_can::abilities::ImplKey;
|
||||||
use roc_load::LoadedModule;
|
use roc_load::LoadedModule;
|
||||||
use roc_module::symbol::{Interns, ModuleId};
|
|
||||||
use roc_packaging::cache::RocCacheDir;
|
|
||||||
use roc_problem::can::Problem;
|
|
||||||
use roc_region::all::{LineColumn, LineColumnRegion, LineInfo, Region};
|
|
||||||
use roc_reporting::report::{can_problem, type_problem, RocDocAllocator};
|
|
||||||
use roc_solve_problem::TypeError;
|
|
||||||
use roc_types::{
|
use roc_types::{
|
||||||
pretty_print::{name_and_print_var, DebugPrint},
|
pretty_print::{name_and_print_var, DebugPrint},
|
||||||
types::MemberImpl,
|
types::MemberImpl,
|
||||||
};
|
};
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
// HELPERS
|
// HELPERS
|
||||||
|
|
||||||
lazy_static! {
|
|
||||||
static ref RE_TYPE_QUERY: Regex =
|
|
||||||
Regex::new(r#"(?P<where>\^+)(?:\{-(?P<sub>\d+)\})?"#).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
struct TypeQuery(Region);
|
|
||||||
|
|
||||||
fn parse_queries(src: &str) -> Vec<TypeQuery> {
|
|
||||||
let line_info = LineInfo::new(src);
|
|
||||||
let mut queries = vec![];
|
|
||||||
let mut consecutive_query_lines = 0;
|
|
||||||
for (i, line) in src.lines().enumerate() {
|
|
||||||
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")
|
|
||||||
.and_then(|m| str::parse(m.as_str()).ok())
|
|
||||||
.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 - consecutive_query_lines;
|
|
||||||
let start_lc = LineColumn {
|
|
||||||
line: last_line,
|
|
||||||
column: start,
|
|
||||||
};
|
|
||||||
let end_lc = LineColumn {
|
|
||||||
line: last_line,
|
|
||||||
column: end,
|
|
||||||
};
|
|
||||||
let lc_region = LineColumnRegion::new(start_lc, end_lc);
|
|
||||||
let region = line_info.convert_line_column_region(lc_region);
|
|
||||||
|
|
||||||
queries.push(TypeQuery(region));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
queries
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_load_and_infer(src: &str) -> Result<(LoadedModule, String), std::io::Error> {
|
|
||||||
use bumpalo::Bump;
|
|
||||||
use tempfile::tempdir;
|
|
||||||
|
|
||||||
let arena = &Bump::new();
|
|
||||||
|
|
||||||
let module_src;
|
|
||||||
let temp;
|
|
||||||
if src.starts_with("app") {
|
|
||||||
// this is already a module
|
|
||||||
module_src = src;
|
|
||||||
} else {
|
|
||||||
// this is an expression, promote it to a module
|
|
||||||
temp = promote_expr_to_module(src);
|
|
||||||
module_src = &temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
let loaded = {
|
|
||||||
let dir = tempdir()?;
|
|
||||||
let filename = PathBuf::from("Test.roc");
|
|
||||||
let file_path = dir.path().join(filename);
|
|
||||||
let result = roc_load::load_and_typecheck_str(
|
|
||||||
arena,
|
|
||||||
file_path,
|
|
||||||
module_src,
|
|
||||||
dir.path().to_path_buf(),
|
|
||||||
roc_target::TargetInfo::default_x86_64(),
|
|
||||||
roc_reporting::report::RenderTarget::Generic,
|
|
||||||
RocCacheDir::Disallowed,
|
|
||||||
roc_reporting::report::DEFAULT_PALETTE,
|
|
||||||
);
|
|
||||||
|
|
||||||
dir.close()?;
|
|
||||||
|
|
||||||
result
|
|
||||||
};
|
|
||||||
|
|
||||||
let loaded = loaded.expect("failed to load module");
|
|
||||||
Ok((loaded, module_src.to_string()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn format_problems(
|
|
||||||
src: &str,
|
|
||||||
home: ModuleId,
|
|
||||||
interns: &Interns,
|
|
||||||
can_problems: Vec<Problem>,
|
|
||||||
type_problems: Vec<TypeError>,
|
|
||||||
) -> (String, String) {
|
|
||||||
let filename = PathBuf::from("test.roc");
|
|
||||||
let src_lines: Vec<&str> = src.split('\n').collect();
|
|
||||||
let lines = LineInfo::new(src);
|
|
||||||
let alloc = RocDocAllocator::new(&src_lines, home, interns);
|
|
||||||
|
|
||||||
let mut can_reports = vec![];
|
|
||||||
let mut type_reports = vec![];
|
|
||||||
|
|
||||||
for problem in can_problems {
|
|
||||||
let report = can_problem(&alloc, &lines, filename.clone(), problem.clone());
|
|
||||||
can_reports.push(report.pretty(&alloc));
|
|
||||||
}
|
|
||||||
|
|
||||||
for problem in type_problems {
|
|
||||||
if let Some(report) = type_problem(&alloc, &lines, filename.clone(), problem.clone()) {
|
|
||||||
type_reports.push(report.pretty(&alloc));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut can_reports_buf = String::new();
|
|
||||||
let mut type_reports_buf = String::new();
|
|
||||||
use roc_reporting::report::CiWrite;
|
|
||||||
alloc
|
|
||||||
.stack(can_reports)
|
|
||||||
.1
|
|
||||||
.render_raw(70, &mut CiWrite::new(&mut can_reports_buf))
|
|
||||||
.unwrap();
|
|
||||||
alloc
|
|
||||||
.stack(type_reports)
|
|
||||||
.1
|
|
||||||
.render_raw(70, &mut CiWrite::new(&mut type_reports_buf))
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
(can_reports_buf, type_reports_buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn infer_eq_help(src: &str) -> Result<(String, String, String), std::io::Error> {
|
fn infer_eq_help(src: &str) -> Result<(String, String, String), std::io::Error> {
|
||||||
let (
|
let (
|
||||||
LoadedModule {
|
LoadedModule {
|
||||||
|
|
@ -205,27 +65,6 @@ mod solve_expr {
|
||||||
Ok((type_problems, can_problems, actual_str))
|
Ok((type_problems, can_problems, actual_str))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn promote_expr_to_module(src: &str) -> String {
|
|
||||||
let mut buffer = String::from(indoc!(
|
|
||||||
r#"
|
|
||||||
app "test"
|
|
||||||
imports []
|
|
||||||
provides [main] to "./platform"
|
|
||||||
|
|
||||||
main =
|
|
||||||
"#
|
|
||||||
));
|
|
||||||
|
|
||||||
for line in src.lines() {
|
|
||||||
// indent the body!
|
|
||||||
buffer.push_str(" ");
|
|
||||||
buffer.push_str(line);
|
|
||||||
buffer.push('\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer
|
|
||||||
}
|
|
||||||
|
|
||||||
fn infer_eq(src: &str, expected: &str) {
|
fn infer_eq(src: &str, expected: &str) {
|
||||||
let (_, can_problems, actual) = infer_eq_help(src).unwrap();
|
let (_, can_problems, actual) = infer_eq_help(src).unwrap();
|
||||||
|
|
||||||
|
|
@ -258,109 +97,6 @@ mod solve_expr {
|
||||||
assert_eq!(actual, expected.to_string());
|
assert_eq!(actual, expected.to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
struct InferOptions {
|
|
||||||
print_can_decls: bool,
|
|
||||||
print_only_under_alias: bool,
|
|
||||||
allow_errors: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn infer_queries_help(src: &str, expected: impl FnOnce(&str), options: InferOptions) {
|
|
||||||
let (
|
|
||||||
LoadedModule {
|
|
||||||
module_id: home,
|
|
||||||
mut can_problems,
|
|
||||||
mut type_problems,
|
|
||||||
mut declarations_by_id,
|
|
||||||
mut solved,
|
|
||||||
interns,
|
|
||||||
abilities_store,
|
|
||||||
..
|
|
||||||
},
|
|
||||||
src,
|
|
||||||
) = run_load_and_infer(src).unwrap();
|
|
||||||
|
|
||||||
let decls = declarations_by_id.remove(&home).unwrap();
|
|
||||||
let subs = solved.inner_mut();
|
|
||||||
|
|
||||||
let can_problems = can_problems.remove(&home).unwrap_or_default();
|
|
||||||
let type_problems = type_problems.remove(&home).unwrap_or_default();
|
|
||||||
|
|
||||||
let (can_problems, type_problems) =
|
|
||||||
format_problems(&src, home, &interns, can_problems, type_problems);
|
|
||||||
|
|
||||||
if !options.allow_errors {
|
|
||||||
assert!(
|
|
||||||
can_problems.is_empty(),
|
|
||||||
"Canonicalization problems: {}",
|
|
||||||
can_problems
|
|
||||||
);
|
|
||||||
assert!(type_problems.is_empty(), "Type problems: {}", type_problems);
|
|
||||||
}
|
|
||||||
|
|
||||||
let queries = parse_queries(&src);
|
|
||||||
assert!(!queries.is_empty(), "No queries provided!");
|
|
||||||
|
|
||||||
let mut output_parts = Vec::with_capacity(queries.len() + 2);
|
|
||||||
|
|
||||||
if options.print_can_decls {
|
|
||||||
use roc_can::debug::{pretty_print_declarations, PPCtx};
|
|
||||||
let ctx = PPCtx {
|
|
||||||
home,
|
|
||||||
interns: &interns,
|
|
||||||
print_lambda_names: true,
|
|
||||||
};
|
|
||||||
let pretty_decls = pretty_print_declarations(&ctx, &decls);
|
|
||||||
output_parts.push(pretty_decls);
|
|
||||||
output_parts.push("\n".to_owned());
|
|
||||||
}
|
|
||||||
|
|
||||||
for TypeQuery(region) in queries.into_iter() {
|
|
||||||
let start = region.start().offset;
|
|
||||||
let end = region.end().offset;
|
|
||||||
let text = &src[start as usize..end as usize];
|
|
||||||
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,
|
|
||||||
home,
|
|
||||||
&interns,
|
|
||||||
DebugPrint {
|
|
||||||
print_lambda_sets: true,
|
|
||||||
print_only_under_alias: options.print_only_under_alias,
|
|
||||||
ignore_polarity: true,
|
|
||||||
print_weakened_vars: true,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
subs.rollback_to(snapshot);
|
|
||||||
|
|
||||||
let elaborated =
|
|
||||||
match find_ability_member_and_owning_type_at(region, &decls, &abilities_store) {
|
|
||||||
Some((spec_type, spec_symbol)) => {
|
|
||||||
format!(
|
|
||||||
"{}#{}({}) : {}",
|
|
||||||
spec_type.as_str(&interns),
|
|
||||||
text,
|
|
||||||
spec_symbol.ident_id().index(),
|
|
||||||
actual_str
|
|
||||||
)
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
format!("{} : {}", text, actual_str)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
output_parts.push(elaborated);
|
|
||||||
}
|
|
||||||
|
|
||||||
let pretty_output = output_parts.join("\n");
|
|
||||||
|
|
||||||
expected(&pretty_output);
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! infer_queries {
|
macro_rules! infer_queries {
|
||||||
($program:expr, @$queries:literal $($option:ident: $value:expr)*) => {
|
($program:expr, @$queries:literal $($option:ident: $value:expr)*) => {
|
||||||
infer_queries_help($program, |golden| insta::assert_snapshot!(golden, @$queries), InferOptions {
|
infer_queries_help($program, |golden| insta::assert_snapshot!(golden, @$queries), InferOptions {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue