roc/editor/tests/solve_expr2.rs

373 lines
7.0 KiB
Rust
Raw Normal View History

2021-04-10 19:58:44 +03:00
#[macro_use]
extern crate pretty_assertions;
#[macro_use]
extern crate indoc;
use bumpalo::Bump;
use roc_can::expected::Expected;
use roc_collections::all::MutMap;
use roc_editor::lang::solve;
2021-04-10 19:58:44 +03:00
use roc_editor::lang::{
constrain::constrain_expr,
constrain::Constraint,
2021-04-10 19:58:44 +03:00
expr::{str_to_expr2, Env},
pool::Pool,
scope::Scope,
types::Type2,
};
2021-04-13 00:29:07 +03:00
use roc_module::ident::Lowercase;
2021-04-27 18:05:47 +03:00
use roc_module::symbol::Interns;
use roc_module::symbol::Symbol;
2021-04-10 19:58:44 +03:00
use roc_module::symbol::{IdentIds, ModuleIds};
use roc_region::all::Region;
use roc_types::solved_types::Solved;
use roc_types::subs::{Subs, Variable};
2021-04-13 00:29:07 +03:00
use roc_types::{pretty_print::content_to_string, subs::VarStore};
2021-04-10 19:58:44 +03:00
fn run_solve<'a>(
arena: &'a Bump,
2021-04-13 00:29:07 +03:00
mempool: &mut Pool,
aliases: MutMap<Symbol, roc_types::types::Alias>,
rigid_variables: MutMap<Variable, Lowercase>,
constraint: Constraint,
var_store: VarStore,
) -> (Solved<Subs>, solve::Env, Vec<solve::TypeError>) {
let env = solve::Env {
vars_by_symbol: MutMap::default(),
aliases,
};
2021-05-08 19:43:15 +03:00
let mut subs = Subs::new(var_store);
for (var, name) in rigid_variables {
subs.rigid_var(var, name);
}
// Now that the module is parsed, canonicalized, and constrained,
// we need to type check it.
let mut problems = Vec::new();
// Run the solver to populate Subs.
let (solved_subs, solved_env) =
solve::run(arena, mempool, &env, &mut problems, subs, &constraint);
(solved_subs, solved_env, problems)
}
2021-04-10 19:58:44 +03:00
fn infer_eq(actual: &str, expected_str: &str) {
let mut env_pool = Pool::with_capacity(1024);
let env_arena = Bump::new();
let code_arena = Bump::new();
let mut var_store = VarStore::default();
let var = var_store.fresh();
let dep_idents = IdentIds::exposed_builtins(8);
let exposed_ident_ids = IdentIds::default();
let mut module_ids = ModuleIds::default();
let mod_id = module_ids.get_or_insert(&"ModId123".into());
let mut env = Env::new(
mod_id,
&env_arena,
&mut env_pool,
&mut var_store,
dep_idents,
&module_ids,
exposed_ident_ids,
);
let mut scope = Scope::new(env.home, env.pool, env.var_store);
let region = Region::zero();
let expr2_result = str_to_expr2(&code_arena, actual, &mut env, &mut scope, region);
match expr2_result {
Ok((expr, _)) => {
let constraint = constrain_expr(
&code_arena,
2021-04-10 19:58:44 +03:00
&mut env,
&expr,
Expected::NoExpectation(Type2::Variable(var)),
2021-04-16 04:41:15 +03:00
Region::zero(),
2021-04-10 19:58:44 +03:00
);
2021-04-13 00:29:07 +03:00
let Env {
pool,
var_store: ref_var_store,
2021-08-04 23:10:55 +03:00
mut dep_idents,
2021-04-13 00:29:07 +03:00
..
} = env;
// extract the var_store out of the env again
let mut var_store = VarStore::default();
std::mem::swap(ref_var_store, &mut var_store);
2021-04-10 19:58:44 +03:00
let (mut solved, _, _) = run_solve(
&code_arena,
2021-04-13 00:29:07 +03:00
pool,
2021-04-10 19:58:44 +03:00
Default::default(),
Default::default(),
constraint,
var_store,
);
2021-04-13 00:29:07 +03:00
let subs = solved.inner_mut();
2021-04-10 19:58:44 +03:00
let content = subs.get_content_without_compacting(var);
2021-04-10 19:58:44 +03:00
2021-08-04 23:10:55 +03:00
// Connect the ModuleId to it's IdentIds
dep_idents.insert(mod_id, env.ident_ids);
2021-04-27 18:05:47 +03:00
let interns = Interns {
2021-06-28 18:53:47 +03:00
module_ids: env.module_ids.clone(),
2021-04-27 18:05:47 +03:00
all_ident_ids: dep_idents,
};
2021-06-29 16:25:16 +03:00
2021-07-29 18:32:08 +03:00
let actual_str = content_to_string(content, subs, mod_id, &interns);
2021-04-10 19:58:44 +03:00
assert_eq!(actual_str, expected_str);
}
Err(e) => panic!("syntax error {:?}", e),
}
}
#[test]
fn constrain_str() {
infer_eq(
indoc!(
r#"
"type inference!"
"#
),
"Str",
)
}
2021-04-16 04:41:15 +03:00
// This will be more useful once we actually map
// strings less than 15 chars to SmallStr
#[test]
fn constrain_small_str() {
infer_eq(
indoc!(
r#"
"a"
"#
),
"Str",
)
}
2021-04-16 04:41:15 +03:00
#[test]
fn constrain_empty_record() {
infer_eq(
indoc!(
r#"
{}
"#
),
"{}",
)
}
#[test]
fn constrain_small_int() {
infer_eq(
indoc!(
r#"
12
"#
),
2021-05-06 05:58:50 +03:00
"Num *",
)
}
2021-05-01 04:50:21 +03:00
#[test]
fn constrain_float() {
infer_eq(
indoc!(
r#"
3.14
"#
),
"Float *",
)
}
2021-05-05 17:45:11 +03:00
#[test]
fn constrain_record() {
infer_eq(
indoc!(
r#"
{ x : 1, y : "hi" }
"#
),
2021-05-06 05:59:23 +03:00
"{ x : Num *, y : Str }",
2021-05-05 17:45:11 +03:00
)
}
#[test]
fn constrain_empty_list() {
infer_eq(
indoc!(
r#"
[]
"#
),
"List *",
)
}
#[test]
fn constrain_list() {
infer_eq(
indoc!(
r#"
[ 1, 2 ]
"#
),
"List (Num *)",
)
}
#[test]
fn constrain_list_of_records() {
infer_eq(
indoc!(
r#"
[ { x: 1 }, { x: 3 } ]
"#
),
"List { x : Num * }",
)
}
2021-05-10 04:00:09 +03:00
#[test]
fn constrain_global_tag() {
infer_eq(
indoc!(
r#"
Foo
"#
),
"[ Foo ]*",
)
}
2021-05-17 04:58:16 +03:00
2021-08-04 23:10:55 +03:00
#[test]
fn constrain_private_tag() {
infer_eq(
indoc!(
r#"
@Foo
"#
),
"[ @Foo ]*",
)
}
2021-05-17 04:58:16 +03:00
#[test]
fn constrain_call_and_accessor() {
infer_eq(
indoc!(
r#"
.foo { foo: "bar" }
"#
),
"Str",
)
}
#[test]
fn constrain_access() {
infer_eq(
indoc!(
r#"
{ foo: "bar" }.foo
"#
),
"Str",
)
}
2021-05-28 19:57:45 +03:00
#[test]
fn constrain_if() {
infer_eq(
indoc!(
r#"
if True then Green else Red
"#
),
"[ Green, Red ]*",
)
}
2021-06-16 02:21:20 +03:00
#[test]
fn constrain_when() {
infer_eq(
indoc!(
r#"
when if True then Green else Red is
Green -> Blue
Red -> Purple
"#
),
"[ Blue, Purple ]*",
)
}
2021-06-21 07:19:00 +03:00
2021-06-22 00:26:55 +03:00
#[test]
fn constrain_let_value() {
infer_eq(
indoc!(
r#"
person = { name: "roc" }
person
"#
),
"{ name : Str }",
)
}
2021-06-21 07:19:00 +03:00
#[test]
fn constrain_update() {
infer_eq(
indoc!(
r#"
2021-06-22 00:26:55 +03:00
person = { name: "roc" }
2021-06-21 07:19:00 +03:00
2021-06-22 00:26:55 +03:00
{ person & name: "bird" }
2021-06-21 07:19:00 +03:00
"#
),
2021-06-22 00:26:55 +03:00
"{ name : Str }",
2021-06-21 07:19:00 +03:00
)
}
2021-07-30 21:21:01 +03:00
#[ignore = "TODO: implement builtins in the editor"]
#[test]
fn constrain_run_low_level() {
infer_eq(
indoc!(
r#"
List.map [ { name: "roc" }, { name: "bird" } ] .name
"#
),
"List Str",
)
}
#[test]
fn constrain_closure() {
infer_eq(
indoc!(
r#"
x = 1
\{} -> x
"#
),
"{}* -> Num *",
)
}