use rustyfi_lang::{elaborate, primitives, typecheck, CompileError};
fn typecheck_str(src: &str) -> Result<(), CompileError> {
let file = rustyfi_syntax::parse_file(src)?;
let env = primitives::base_env();
let store = rustyfi_lang::symbol::SymbolStore::new();
let scope = elaborate::Scope::new(&store, env.names());
let program = elaborate::elaborate_program(&file, &scope)?;
typecheck::typecheck(&program)?;
Ok(())
}
fn assert_well_typed(src: &str) {
if let Err(e) = typecheck_str(src) {
panic!("expected {src:?} to type-check, got error: {e}");
}
}
fn assert_type_error(src: &str) -> CompileError {
match typecheck_str(src) {
Ok(()) => panic!("expected {src:?} to be rejected by the typechecker, but it passed"),
Err(e @ CompileError::Type(_)) => e,
Err(other) => panic!("expected {src:?} to fail with a type error, got: {other}"),
}
}
#[test]
fn zero_param_synonym_expands_in_ctor_payload() {
assert_well_typed(
"type point = length * length
type mark = | Mark of point
in
Mark (1pt, 2pt)",
);
}
#[test]
fn zero_param_synonym_payload_mismatch_is_rejected() {
assert_type_error(
"type point = length * length
type mark = | Mark of point
in
Mark (1, 2)",
);
}
#[test]
fn multi_arrow_product_synonym_typechecks() {
assert_well_typed(
"type paren = length -> length -> length -> length -> int -> bool * (length -> length)
type holder = | Hold of paren
in
Hold (fun a b c d e -> (true, fun x -> x))",
);
}
#[test]
fn multi_arrow_product_synonym_mismatch_is_rejected() {
assert_type_error(
"type paren = length -> length -> length -> length -> int -> bool * (length -> length)
type holder = | Hold of paren
in
Hold (fun a b c d e -> (1, fun x -> x))",
);
}
#[test]
fn upstream_pervasives_examples_parse_and_register() {
assert_well_typed(
"type point = length * length
type paren = length -> length -> length -> length -> color -> inline-boxes * (length -> length)
in
0",
);
}
#[test]
fn mutually_cyclic_synonym_is_rejected() {
assert_type_error(
"type a = b
type b = a
in
0",
);
}
#[test]
fn self_referential_synonym_is_rejected() {
assert_type_error(
"type a = a
in
0",
);
}
#[test]
fn parameterized_synonym_declares_without_error_when_unused() {
assert_well_typed(
"type 'a box = 'a * 'a
in
1 + 2",
);
}
#[test]
fn parameterized_synonym_reference_reports_arity_mismatch() {
assert_type_error(
"type 'a box = 'a * 'a
type wrap = | Wrap of box
in
Wrap (1, 2)",
);
}