roc/tests/test_infer.rs
2019-08-30 00:57:47 -04:00

458 lines
9.3 KiB
Rust

#[macro_use] extern crate pretty_assertions;
#[macro_use] extern crate indoc;
extern crate roc;
extern crate combine;
mod helpers;
#[cfg(test)]
mod test_infer {
use helpers::{loc, parse_without_loc};
use roc::canonicalize::{self, Expr, Symbol, Procedure};
use roc::expr::{Ident, VariantName};
use roc::collections::{MutMap, ImMap};
use roc::types::{Type, Problem};
use roc::types::Type::*;
use roc::subs::Content::{self, *};
use roc::subs::{FlatType, Variable};
use roc::subs::Subs;
use roc::region::{Located, Region};
use roc::infer::infer_expr;
use roc::pretty_print_types::content_to_string;
// HELPERS
fn infer_eq(src: &str, expected: &str) {
let (expr, procedures) = can_expr(src);
let mut subs = Subs::new();
let content = infer_expr(&mut subs, loc(expr), procedures);
let actual_str = content_to_string(content, &mut subs);
assert_eq!(actual_str, expected.to_string());
}
fn can_expr(expr_str: &str) -> (Expr, MutMap<Symbol, Procedure>) {
can_expr_with("blah", expr_str, &ImMap::default(), &ImMap::default())
}
fn can_expr_with(
name: &str,
expr_str: &str,
declared_idents: &ImMap<Ident, (Symbol, Region)>,
declared_variants: &ImMap<Symbol, Located<VariantName>>,
) -> (Expr, MutMap<Symbol, Procedure>) {
let (expr, unparsed) = parse_without_loc(expr_str).unwrap_or_else(|errors| {
panic!("Parse error trying to parse \"{}\" - {}", expr_str.to_string(), errors.to_string())
});
assert_eq!(unparsed, "".to_string());
let home = "Test".to_string();
let (loc_expr, _, problems, procedures) =
canonicalize::canonicalize_declaration(home, name, loc(expr), declared_idents, declared_variants);
assert_eq!(problems, vec![]);
(loc_expr.value, procedures)
}
fn apply(module_name: &str, type_name: &str, args: Vec<Variable>) -> Content {
Structure(FlatType::Apply(module_name.to_string(), type_name.to_string(), args))
}
fn var(num: u32) -> Variable {
Variable::new_for_testing_only(num)
}
#[test]
fn empty_record() {
infer_eq("{}", "{}");
}
#[test]
fn int_literal() {
infer_eq("5", "Num.Num *");
}
#[test]
fn fractional_literal() {
infer_eq("0.5", "Num.Num (Num.Fractional *)");
}
#[test]
fn string_literal() {
infer_eq(
indoc!(r#"
"type inference!"
"#),
"String.String"
);
}
#[test]
fn empty_string() {
infer_eq(
indoc!(r#"
""
"#),
"String.String"
);
}
// LIST
#[test]
fn empty_list() {
infer_eq(
indoc!(r#"
[]
"#),
"List.List *"
);
}
#[test]
fn list_of_lists() {
infer_eq(
indoc!(r#"
[[]]
"#),
"List.List (List.List *)"
);
}
#[test]
fn triple_nested_list() {
infer_eq(
indoc!(r#"
[[[]]]
"#),
"List.List (List.List (List.List *))"
);
}
#[test]
fn nested_empty_list() {
infer_eq(
indoc!(r#"
[ [], [ [] ] ]
"#),
"List.List (List.List (List.List *))"
);
}
#[test]
fn list_of_one_num() {
infer_eq(
indoc!(r#"
[42]
"#),
"List.List (Num.Num *)"
);
}
#[test]
fn triple_nested_num_list() {
infer_eq(
indoc!(r#"
[[[ 5 ]]]
"#),
"List.List (List.List (List.List (Num.Num *)))"
);
}
#[test]
fn list_of_nums() {
infer_eq(
indoc!(r#"
[ 1, 2, 3 ]
"#),
"List.List (Num.Num *)"
);
}
#[test]
fn nested_list_of_nums() {
infer_eq(
indoc!(r#"
[ [ 1 ], [ 2, 3 ] ]
"#),
"List.List (List.List (Num.Num *))"
);
}
#[test]
fn list_of_one_string() {
infer_eq(
indoc!(r#"
[ "cowabunga" ]
"#),
"List.List String.String"
);
}
#[test]
fn triple_nested_string_list() {
infer_eq(
indoc!(r#"
[[[ "foo" ]]]
"#),
"List.List (List.List (List.List String.String))"
);
}
#[test]
fn list_of_strings() {
infer_eq(
indoc!(r#"
[ "foo", "bar" ]
"#),
"List.List String.String"
);
}
// INTERPOLATED STRING
#[test]
fn infer_interpolated_string() {
infer_eq(
indoc!(r#"
whatItIs = "great"
"type inference is \(whatItIs)!"
"#),
"String.String"
);
}
// LIST MISMATCH
#[test]
fn mismatch_heterogeneous_list() {
infer_eq(
indoc!(r#"
[ "foo", 5 ]
"#),
"List.List <type mismatch>"
);
}
#[test]
fn mismatch_heterogeneous_nested_list() {
infer_eq(
indoc!(r#"
[ [ "foo", 5 ] ]
"#),
"List.List (List.List <type mismatch>)"
);
}
#[test]
fn mismatch_heterogeneous_nested_empty_list() {
infer_eq(
indoc!(r#"
[ [ 1 ], [ [] ] ]
"#),
"List.List (List.List <type mismatch>)"
);
}
// CLOSURE
#[test]
fn always_return_empty_record() {
infer_eq(
indoc!(r#"
\_ -> {}
"#),
"* -> {}"
);
}
#[test]
fn two_arg_return_num() {
infer_eq(
indoc!(r#"
\_ _ -> 42
"#),
"*, * -> Num.Num *"
);
}
#[test]
fn three_arg_return_string() {
infer_eq(
indoc!(r#"
\_ _ _ -> "test!"
"#),
"*, *, * -> String.String"
);
}
// ASSIGN
#[test]
fn assign_empty_record() {
infer_eq(
indoc!(r#"
foo = {}
foo
"#),
"{}"
);
}
#[test]
fn assign_string() {
infer_eq(
indoc!(r#"
str = "thing"
str
"#),
"String.String"
);
}
#[test]
fn assign_1_arg_closure() {
infer_eq(
indoc!(r#"
fn = \_ -> {}
fn
"#),
"* -> {}"
);
}
#[test]
fn assign_2_arg_closure() {
infer_eq(
indoc!(r#"
func = \_ _ -> 42
func
"#),
"*, * -> Num.Num *"
);
}
#[test]
fn assign_3_arg_closure() {
infer_eq(
indoc!(r#"
f = \_ _ _ -> "test!"
f
"#),
"*, *, * -> String.String"
);
}
#[test]
fn assign_multiple() {
infer_eq(
indoc!(r#"
a = \_ _ _ -> "test!"
b = a
b
"#),
"*, *, * -> String.String"
);
}
// #[test]
// fn int_thunk() {
// assert_eq!(
// infer(indoc!(r#"
// \_ -> 5
// "#)),
// Function(vec![var(0)], Box::new(Builtin(Int)))
// );
// }
// #[test]
// fn string_thunk() {
// assert_eq!(
// infer(indoc!(r#"
// \_ -> "thunk!"
// "#)),
// Function(vec![var(0)], Box::new(Builtin(Str)))
// );
// }
// #[test]
// fn identity_function() {
// assert_eq!(
// infer(indoc!(r#"
// \val -> val
// "#)),
// Function(vec![var(0)], box_var(0))
// );
// }
// #[test]
// fn always_function() {
// assert_eq!(
// infer(indoc!(r#"
// \val -> \_ -> val
// "#)),
// Function(
// vec![var(0)],
// Box::new(Function(vec![var(1)], box_var(0)))
// )
// );
// }
// #[test]
// fn basic_circular_type() {
// assert_eq!(
// infer(indoc!(r#"
// \x -> x x
// "#)),
// Erroneous(Problem::CircularType)
// );
// }
// #[test]
// fn y_combinator_has_circular_type() {
// assert_eq!(
// infer(indoc!(r#"
// \f -> (\x -> f x x) (\x -> f x x)
// "#)),
// Erroneous(Problem::CircularType)
// );
// }
// #[test]
// fn infer_multiply() {
// assert_eq!(
// infer("2 * 3"),
// Builtin(Int)
// );
// assert_eq!(
// infer("2.5 * 3.5"),
// Builtin(Frac)
// );
// }
// #[test]
// fn infer_basic_case() {
// assert_eq!(
// infer("case 42 when 1 then 2.5 when _ then 3.5"),
// Builtin(Frac)
// );
// }
}