mirror of
https://github.com/tweag/nickel.git
synced 2024-10-06 08:07:37 +03:00
Convert tests to new annotated format, pt. 3 (#1314)
* Convert stdlib_arrays_fail test to new annotated format * Convert typecheck_fail to new annotated format * Convert unbound_type_variables to new annotated format * Convert imports to new annotated format
This commit is contained in:
parent
d2f5cb5250
commit
b8094824b0
5
tests/integration/fail/arrays/elem_at_empty_array.ncl
Normal file
5
tests/integration/fail/arrays/elem_at_empty_array.ncl
Normal file
@ -0,0 +1,5 @@
|
||||
# test.type = 'error'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'EvalError::Other'
|
||||
%elem_at% [] 0
|
@ -0,0 +1,5 @@
|
||||
# test.type = 'error'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'EvalError::Other'
|
||||
%elem_at% [true, false, true] 3
|
5
tests/integration/fail/arrays/elem_at_negative_index.ncl
Normal file
5
tests/integration/fail/arrays/elem_at_negative_index.ncl
Normal file
@ -0,0 +1,5 @@
|
||||
# test.type = 'error'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'EvalError::Other'
|
||||
%elem_at% [1, 2, 3] (-1)
|
5
tests/integration/fail/arrays/elem_at_non_array_arg.ncl
Normal file
5
tests/integration/fail/arrays/elem_at_non_array_arg.ncl
Normal file
@ -0,0 +1,5 @@
|
||||
# test.type = 'error'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'EvalError::NAryPrimopTypeError'
|
||||
%elem_at% {} 0
|
5
tests/integration/fail/arrays/elem_at_non_int_index.ncl
Normal file
5
tests/integration/fail/arrays/elem_at_non_int_index.ncl
Normal file
@ -0,0 +1,5 @@
|
||||
# test.type = 'error'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'EvalError::Other'
|
||||
%elem_at% [1, 2, 3] 0.5
|
5
tests/integration/fail/arrays/slice_empty_array.ncl
Normal file
5
tests/integration/fail/arrays/slice_empty_array.ncl
Normal file
@ -0,0 +1,5 @@
|
||||
# test.type = 'error'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'EvalError::Other'
|
||||
%array_slice% 1 1 []
|
5
tests/integration/fail/arrays/slice_non_array.ncl
Normal file
5
tests/integration/fail/arrays/slice_non_array.ncl
Normal file
@ -0,0 +1,5 @@
|
||||
# test.type = 'error'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'EvalError::NAryPrimopTypeError'
|
||||
%array_slice% 0 1 {}
|
@ -0,0 +1,5 @@
|
||||
# test.type = 'error'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'EvalError::BlameError'
|
||||
std.array.at 0 {}
|
@ -0,0 +1,5 @@
|
||||
# test.type = 'error'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'EvalError::BlameError'
|
||||
std.array.at "a" []
|
@ -0,0 +1,5 @@
|
||||
# test.type = 'error'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'EvalError::BlameError'
|
||||
std.array.drop_first 2
|
@ -0,0 +1,5 @@
|
||||
# test.type = 'error'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'EvalError::BlameError'
|
||||
std.array.first false
|
10
tests/integration/fail/type_var_outside_forall.ncl
Normal file
10
tests/integration/fail/type_var_outside_forall.ncl
Normal file
@ -0,0 +1,10 @@
|
||||
# test.type = 'error'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::UnboundIdentifier'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# identifier = 'a'
|
||||
let f | a -> (forall a. a -> a) =
|
||||
fun x => builtin.seq x null
|
||||
in null
|
10
tests/integration/fail/unbound_record_tail_var.ncl
Normal file
10
tests/integration/fail/unbound_record_tail_var.ncl
Normal file
@ -0,0 +1,10 @@
|
||||
# test.type = 'error'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::UnboundTypeVariable'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# identifier = 'e'
|
||||
let f : forall a b c. a -> (b -> Array c) -> { foo : Array {field : a}, bar: a; e } =
|
||||
fun bar_ _g => { foo = [{ field = bar_ }], bar = bar_ }
|
||||
in null
|
10
tests/integration/fail/unbound_type_variable.ncl
Normal file
10
tests/integration/fail/unbound_type_variable.ncl
Normal file
@ -0,0 +1,10 @@
|
||||
# test.type = 'error'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::UnboundIdentifier'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# identifier = 'd'
|
||||
let f | forall a b c. a -> (b -> Array c) -> {foo : Array {_ : d}, bar: a; Dyn}
|
||||
= fun bar_ _g => {foo = [{field = 1}], bar = bar_}
|
||||
in (f 1 (fun _x => [])).foo == [{ field = 1 }]
|
8
tests/integration/fail/unbound_var_in_contract.ncl
Normal file
8
tests/integration/fail/unbound_var_in_contract.ncl
Normal file
@ -0,0 +1,8 @@
|
||||
# test.type = 'error'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::UnboundIdentifier'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# identifier = 'a'
|
||||
1 | a
|
@ -1,201 +0,0 @@
|
||||
use assert_matches::assert_matches;
|
||||
use nickel_lang::error::{Error, EvalError, ImportError, TypecheckError};
|
||||
use nickel_lang::term::{make as mk_term, RichTerm, Term};
|
||||
use nickel_lang_utilities::test_program::TestProgram;
|
||||
use std::io::BufReader;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn mk_import(file: &str) -> String {
|
||||
let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
path.push(format!("tests/integration/imports/{file}"));
|
||||
format!(
|
||||
"import \"{}\"",
|
||||
path.into_os_string().into_string().unwrap()
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nested() {
|
||||
let mut prog = TestProgram::new_from_source(
|
||||
BufReader::new(mk_import("nested.ncl").as_bytes()),
|
||||
"should_be = 3",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
prog.eval().map(RichTerm::without_pos),
|
||||
Ok(mk_term::integer(3))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn root_path() {
|
||||
let mut prog = TestProgram::new_from_source(
|
||||
BufReader::new(mk_import("root_path.ncl").as_bytes()),
|
||||
"should_be = 44",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
prog.eval().map(RichTerm::without_pos),
|
||||
Ok(mk_term::integer(44))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multi_imports() {
|
||||
let mut prog = TestProgram::new_from_source(
|
||||
BufReader::new(mk_import("multi_imports.ncl").as_bytes()),
|
||||
"should_be = 5",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
prog.eval().map(RichTerm::without_pos),
|
||||
Ok(mk_term::integer(5))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn contract_fail() {
|
||||
let mut prog = TestProgram::new_from_source(
|
||||
BufReader::new(mk_import("contract-fail.ncl").as_bytes()),
|
||||
"should_fail",
|
||||
)
|
||||
.unwrap();
|
||||
assert_matches!(
|
||||
prog.eval(),
|
||||
Err(Error::EvalError(EvalError::BlameError { .. }))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn typecheck_fail() {
|
||||
let mut prog = TestProgram::new_from_source(
|
||||
BufReader::new(mk_import("typecheck-fail.ncl").as_bytes()),
|
||||
"should_fail",
|
||||
)
|
||||
.unwrap();
|
||||
assert_matches!(
|
||||
prog.eval(),
|
||||
Err(Error::TypecheckError(TypecheckError::TypeMismatch(..)))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn static_typing_fail() {
|
||||
let mut prog = TestProgram::new_from_source(
|
||||
BufReader::new(format!("(let x = {} in x) : String", mk_import("two.ncl")).as_bytes()),
|
||||
"should_fail",
|
||||
)
|
||||
.unwrap();
|
||||
assert_matches!(
|
||||
prog.eval(),
|
||||
Err(Error::TypecheckError(TypecheckError::TypeMismatch(..)))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialize() {
|
||||
use nickel_lang::term::Term;
|
||||
let mut prog = TestProgram::new_from_source(
|
||||
BufReader::new(
|
||||
format!(
|
||||
"(std.serialize 'Json ({})) == (std.serialize 'Json ({{foo = \"ab\"}}))",
|
||||
mk_import("record.ncl")
|
||||
)
|
||||
.as_bytes(),
|
||||
),
|
||||
"should_succeed",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(prog.eval().map(Term::from), Ok(Term::Bool(true)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn circular_imports_fail() {
|
||||
let mut prog = TestProgram::new_from_source(
|
||||
BufReader::new(mk_import("cycle.ncl").as_bytes()),
|
||||
"should_succeed",
|
||||
)
|
||||
.unwrap();
|
||||
assert_matches!(
|
||||
prog.eval().map(Term::from),
|
||||
Ok(Term::RecRecord(..)) | Ok(Term::Record(..))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn import_unexpected_token_fail() {
|
||||
let mut prog = TestProgram::new_from_source(
|
||||
BufReader::new(mk_import("unexpected_token.ncl").as_bytes()),
|
||||
"should_fail",
|
||||
)
|
||||
.unwrap();
|
||||
assert_matches!(
|
||||
prog.eval(),
|
||||
Err(Error::ImportError(ImportError::ParseErrors(..)))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn import_unexpected_token_in_record_fail() {
|
||||
let mut prog = TestProgram::new_from_source(
|
||||
BufReader::new(
|
||||
format!(
|
||||
"let x = {} in \"Hello, \" ++ x.name",
|
||||
mk_import("unexpected_token_in_record.ncl")
|
||||
)
|
||||
.as_bytes(),
|
||||
),
|
||||
"should_fail",
|
||||
)
|
||||
.unwrap();
|
||||
assert_matches!(
|
||||
prog.eval(),
|
||||
Err(Error::ImportError(ImportError::ParseErrors(..)))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn import_unexpected_token_buried_fail() {
|
||||
let mut prog = TestProgram::new_from_source(
|
||||
BufReader::new(
|
||||
format!(
|
||||
"let _ign = {} in 1",
|
||||
mk_import("unexpected_token_buried.ncl")
|
||||
)
|
||||
.as_bytes(),
|
||||
),
|
||||
"should_fail",
|
||||
)
|
||||
.unwrap();
|
||||
assert_matches!(
|
||||
prog.eval(),
|
||||
Err(Error::ImportError(ImportError::ParseErrors(..)))
|
||||
);
|
||||
}
|
||||
|
||||
// Regression test for #1090 (https://github.com/tweag/nickel/issues/1090)
|
||||
#[test]
|
||||
fn nested_syntax_error() {
|
||||
let mut prog = TestProgram::new_from_source(
|
||||
BufReader::new(mk_import("nested_syntax_error.ncl").as_bytes()),
|
||||
"should_fail",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_matches!(
|
||||
prog.eval(),
|
||||
Err(Error::ImportError(ImportError::ParseErrors(..)))
|
||||
);
|
||||
}
|
||||
|
||||
// Regression test for simple import loop making the typechecker overflow
|
||||
#[test]
|
||||
fn direct_import_loop() {
|
||||
let mut prog = TestProgram::new_from_source(
|
||||
BufReader::new(mk_import("direct_import_loop.ncl").as_bytes()),
|
||||
"should_typecheck",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_matches!(prog.typecheck(), Ok(()));
|
||||
}
|
2
tests/integration/imports/circular_imports.ncl
Normal file
2
tests/integration/imports/circular_imports.ncl
Normal file
@ -0,0 +1,2 @@
|
||||
# test.type = 'pass'
|
||||
(import "imported/circular_imports.ncl") == { a = 1, b = 1 }
|
5
tests/integration/imports/contract_fail.ncl
Normal file
5
tests/integration/imports/contract_fail.ncl
Normal file
@ -0,0 +1,5 @@
|
||||
# test.type = 'error'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'EvalError::BlameError'
|
||||
import "imported/contract_fail.ncl"
|
@ -1,2 +0,0 @@
|
||||
# test.type = 'skip'
|
||||
let x = import "cycle_b.ncl" in {a = 1, b = x.a}
|
@ -1,4 +0,0 @@
|
||||
# test.type = 'skip'
|
||||
let x = import "cycle.ncl" in
|
||||
let y = import "cycle_c.ncl" in
|
||||
{a = x.a, b = y}
|
@ -1,4 +0,0 @@
|
||||
# test.type = 'skip'
|
||||
let _x = import "cycle.ncl" in
|
||||
let _y = import "cycle_b.ncl" in
|
||||
0
|
@ -1,2 +1,5 @@
|
||||
# test.type = 'skip'
|
||||
import "direct_import_loop.ncl"
|
||||
# test.type = 'pass'
|
||||
# eval = 'typecheck'
|
||||
|
||||
# Regression test for simple import loop making the typechecker overflow
|
||||
import "imported/direct_import_loop.ncl"
|
2
tests/integration/imports/imported/circular_imports.ncl
Normal file
2
tests/integration/imports/imported/circular_imports.ncl
Normal file
@ -0,0 +1,2 @@
|
||||
# test.type = 'skip'
|
||||
let x = import "circular_imports1.ncl" in {a = 1, b = x.a}
|
4
tests/integration/imports/imported/circular_imports1.ncl
Normal file
4
tests/integration/imports/imported/circular_imports1.ncl
Normal file
@ -0,0 +1,4 @@
|
||||
# test.type = 'skip'
|
||||
let x = import "circular_imports.ncl" in
|
||||
let y = import "circular_imports2.ncl" in
|
||||
{a = x.a, b = y}
|
4
tests/integration/imports/imported/circular_imports2.ncl
Normal file
4
tests/integration/imports/imported/circular_imports2.ncl
Normal file
@ -0,0 +1,4 @@
|
||||
# test.type = 'skip'
|
||||
let _x = import "circular_imports.ncl" in
|
||||
let _y = import "circular_imports1.ncl" in
|
||||
0
|
@ -1,2 +1,2 @@
|
||||
# test.type = 'skip'
|
||||
1 | String
|
||||
1 | String
|
@ -0,0 +1,2 @@
|
||||
# test.type = 'skip'
|
||||
import "direct_import_loop.ncl"
|
4
tests/integration/imports/imported/multi_imports.ncl
Normal file
4
tests/integration/imports/imported/multi_imports.ncl
Normal file
@ -0,0 +1,4 @@
|
||||
# test.type = 'skip'
|
||||
let x = import "two.ncl" in
|
||||
let y = import "nested.ncl" in
|
||||
x + y
|
2
tests/integration/imports/imported/nested.ncl
Normal file
2
tests/integration/imports/imported/nested.ncl
Normal file
@ -0,0 +1,2 @@
|
||||
# test.type = 'skip'
|
||||
let x = import "two.ncl" in x + 1
|
@ -0,0 +1,2 @@
|
||||
# test.type = 'skip'
|
||||
import "nested_syntax_error1.ncl"
|
2
tests/integration/imports/imported/root_path.ncl
Normal file
2
tests/integration/imports/imported/root_path.ncl
Normal file
@ -0,0 +1,2 @@
|
||||
# test.type = 'skip'
|
||||
import "root_path/import.ncl"
|
@ -0,0 +1,7 @@
|
||||
# test.type = 'skip'
|
||||
{
|
||||
foo = {
|
||||
bar = [2 @ ],
|
||||
},
|
||||
baz = 2
|
||||
}
|
@ -1,4 +1,2 @@
|
||||
# test.type = 'skip'
|
||||
let x = import "two.ncl" in
|
||||
let y = import "nested.ncl" in
|
||||
x + y
|
||||
# test.type = 'pass'
|
||||
(import "imported/multi_imports.ncl") == 5
|
@ -1,2 +1,2 @@
|
||||
# test.type = 'skip'
|
||||
let x = import "two.ncl" in x + 1
|
||||
# test.type = 'pass'
|
||||
(import "imported/nested.ncl") == 3
|
@ -1,2 +1,7 @@
|
||||
# test.type = 'skip'
|
||||
import "nested_syntax_error1.ncl"
|
||||
# test.type = 'error'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'ImportError::ParseError'
|
||||
|
||||
# Regression test for #1090
|
||||
import "imported/nested_syntax_error.ncl"
|
@ -1,2 +1,2 @@
|
||||
# test.type = 'skip'
|
||||
import "root_path/import.ncl"
|
||||
# test.type = 'pass'
|
||||
(import "imported/root_path.ncl") == 44
|
2
tests/integration/imports/serialize.ncl
Normal file
2
tests/integration/imports/serialize.ncl
Normal file
@ -0,0 +1,2 @@
|
||||
# test.type = 'pass'
|
||||
(std.serialize 'Json (import "imported/serialize.ncl") == (std.serialize 'Json ({ foo = "ab" })))
|
9
tests/integration/imports/static_typing_fail.ncl
Normal file
9
tests/integration/imports/static_typing_fail.ncl
Normal file
@ -0,0 +1,9 @@
|
||||
# test.type = 'error'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::TypeMismatch'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# expected = 'String'
|
||||
# found = 'Number'
|
||||
(let x = import "imported/two.ncl" in x) : String
|
9
tests/integration/imports/typecheck_fail.ncl
Normal file
9
tests/integration/imports/typecheck_fail.ncl
Normal file
@ -0,0 +1,9 @@
|
||||
# test.type = 'error'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::TypeMismatch'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# expected = 'Number'
|
||||
# found = 'Bool'
|
||||
import "imported/typecheck_fail.ncl"
|
@ -1,7 +1,5 @@
|
||||
# test.type = 'skip'
|
||||
{
|
||||
foo = {
|
||||
bar = [2 @ ],
|
||||
},
|
||||
baz = 2
|
||||
}
|
||||
# test.type = 'error'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'ImportError::ParseError'
|
||||
import "imported/unexpected_token_buried.ncl"
|
5
tests/integration/imports/unexpected_token_fail.ncl
Normal file
5
tests/integration/imports/unexpected_token_fail.ncl
Normal file
@ -0,0 +1,5 @@
|
||||
# test.type = 'error'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'ImportError::ParseError'
|
||||
import "imported/unexpected_token.ncl"
|
@ -0,0 +1,6 @@
|
||||
# test.type = 'error'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'ImportError::ParseError'
|
||||
let x = import "imported/unexpected_token_in_record.ncl"
|
||||
in "Hello, " ++ x.name
|
@ -1,7 +1,7 @@
|
||||
use std::{io::Cursor, thread};
|
||||
|
||||
use nickel_lang::{
|
||||
error::{Error, EvalError, TypecheckError},
|
||||
error::{Error, EvalError, ImportError, TypecheckError},
|
||||
term::Term,
|
||||
};
|
||||
use nickel_lang_utilities::{
|
||||
@ -13,13 +13,9 @@ use test_generator::test_resources;
|
||||
|
||||
mod contract_label_path;
|
||||
mod free_vars;
|
||||
mod imports;
|
||||
mod pretty;
|
||||
mod query;
|
||||
mod stdlib_arrays_fail;
|
||||
mod stdlib_typecheck;
|
||||
mod typecheck_fail;
|
||||
mod unbound_type_variables;
|
||||
|
||||
#[test_resources("./tests/integration/**/*.ncl")]
|
||||
fn check_annotated_nickel_file(path: &str) {
|
||||
@ -46,31 +42,19 @@ fn run_test(test_case: TestCase<Test>, path: String) {
|
||||
let program = test_case.program;
|
||||
let test = test_case.annotation.test;
|
||||
|
||||
let eval = |mut p: TestProgram| match eval_strategy {
|
||||
EvalStrategy::Full => p.eval_full(),
|
||||
EvalStrategy::Standard => p.eval(),
|
||||
};
|
||||
|
||||
for _ in 0..repeat {
|
||||
let p =
|
||||
TestProgram::new_from_source(Cursor::new(program.clone()), path.as_str()).expect("");
|
||||
match test.clone() {
|
||||
Expectation::Error(expected_err) => {
|
||||
let result = eval(p);
|
||||
let err = result.expect_err(
|
||||
format!(
|
||||
"Expected error: {}, but program evaluated successfully.",
|
||||
expected_err
|
||||
)
|
||||
.as_str(),
|
||||
);
|
||||
let err = eval_strategy.eval_program_to_err(p);
|
||||
assert_eq!(expected_err, err, "wrong error evaluating file {path}")
|
||||
}
|
||||
Expectation::Pass => {
|
||||
let result = eval(p);
|
||||
let result = eval_strategy.eval_program_to_term(p);
|
||||
assert_eq!(
|
||||
result.map(Term::from),
|
||||
Ok(Term::Bool(true)),
|
||||
result,
|
||||
Term::Bool(true),
|
||||
"unexpected error evaluating file {path}",
|
||||
)
|
||||
}
|
||||
@ -92,6 +76,28 @@ enum EvalStrategy {
|
||||
Full,
|
||||
#[serde(rename = "standard")]
|
||||
Standard,
|
||||
#[serde(rename = "typecheck")]
|
||||
TypeCheck,
|
||||
}
|
||||
|
||||
impl EvalStrategy {
|
||||
fn eval_program_to_term(&self, mut p: TestProgram) -> Term {
|
||||
match self {
|
||||
EvalStrategy::Full => p.eval_full().map(Term::from),
|
||||
EvalStrategy::Standard => p.eval().map(Term::from),
|
||||
EvalStrategy::TypeCheck => p.typecheck().map(|_| Term::Bool(true)),
|
||||
}
|
||||
.expect("Expected evaluation to succeed but got an error")
|
||||
}
|
||||
|
||||
fn eval_program_to_err(&self, mut p: TestProgram) -> Error {
|
||||
match self {
|
||||
EvalStrategy::Full => p.eval_full().map(|_| ()),
|
||||
EvalStrategy::Standard => p.eval().map(|_| ()),
|
||||
EvalStrategy::TypeCheck => p.typecheck(),
|
||||
}
|
||||
.expect_err("Expected an error but program evaluated successfully")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize)]
|
||||
@ -131,14 +137,26 @@ enum ErrorExpectation {
|
||||
EvalMergeIncompatibleArgs,
|
||||
#[serde(rename = "TypecheckError::UnboundIdentifier")]
|
||||
TypecheckUnboundIdentifier { identifier: String },
|
||||
#[serde(rename = "TypecheckError::UnboundTypeVariable")]
|
||||
TypecheckUnboundTypeVariable { identifier: String },
|
||||
#[serde(rename = "TypecheckError::TypeMismatch")]
|
||||
TypecheckTypeMismatch { expected: String, found: String },
|
||||
#[serde(rename = "TypecheckError::MissingRow")]
|
||||
TypecheckMissingRow { ident: String },
|
||||
#[serde(rename = "TypecheckError::ExtraRow")]
|
||||
TypecheckExtraRow { ident: String },
|
||||
#[serde(rename = "TypecheckError::RowConflict")]
|
||||
TypecheckRowConflict { row: String },
|
||||
#[serde(rename = "TypecheckError::RowMismatch")]
|
||||
TypecheckRowMismatch,
|
||||
#[serde(rename = "TypecheckError::ExtraDynTail")]
|
||||
TypecheckExtraDynTail,
|
||||
#[serde(rename = "TypecheckError::MissingDynTail")]
|
||||
TypecheckMissingDynTail,
|
||||
#[serde(rename = "ParseError")]
|
||||
ParseError,
|
||||
#[serde(rename = "ImportError::ParseError")]
|
||||
ImportParseError,
|
||||
}
|
||||
|
||||
impl PartialEq<Error> for ErrorExpectation {
|
||||
@ -160,28 +178,54 @@ impl PartialEq<Error> for ErrorExpectation {
|
||||
)
|
||||
| (EvalOther, Error::EvalError(EvalError::Other(..)))
|
||||
| (TypecheckRowMismatch, Error::TypecheckError(TypecheckError::RowMismatch(..)))
|
||||
| (
|
||||
TypecheckMissingDynTail,
|
||||
Error::TypecheckError(TypecheckError::MissingDynTail(..)),
|
||||
)
|
||||
| (TypecheckExtraDynTail, Error::TypecheckError(TypecheckError::ExtraDynTail(..)))
|
||||
| (ImportParseError, Error::ImportError(ImportError::ParseErrors(..)))
|
||||
| (ParseError, Error::ParseErrors(..)) => true,
|
||||
(EvalFieldMissing { field }, Error::EvalError(EvalError::FieldMissing(ident, ..)))
|
||||
if field == ident =>
|
||||
{
|
||||
true
|
||||
(EvalFieldMissing { field }, Error::EvalError(EvalError::FieldMissing(ident, ..))) => {
|
||||
field == ident
|
||||
}
|
||||
(
|
||||
EvalMissingFieldDef { field },
|
||||
Error::EvalError(EvalError::MissingFieldDef { id, .. }),
|
||||
) if field == id.label() => true,
|
||||
) => field == id.label(),
|
||||
(
|
||||
TypecheckUnboundIdentifier { identifier },
|
||||
Error::TypecheckError(TypecheckError::UnboundIdentifier(ident, ..)),
|
||||
) if ident.label() == identifier => true,
|
||||
) => ident.label() == identifier,
|
||||
(
|
||||
TypecheckUnboundTypeVariable { identifier },
|
||||
Error::TypecheckError(TypecheckError::UnboundTypeVariable(ident)),
|
||||
) => identifier == ident.label(),
|
||||
(
|
||||
TypecheckTypeMismatch { expected, found },
|
||||
Error::TypecheckError(TypecheckError::TypeMismatch(expected1, found1, ..)),
|
||||
Error::TypecheckError(
|
||||
TypecheckError::TypeMismatch(expected1, found1, ..)
|
||||
| TypecheckError::ArrowTypeMismatch(expected1, found1, ..),
|
||||
),
|
||||
) if expected == &expected1.to_string() && found == &found1.to_string() => true,
|
||||
(
|
||||
TypecheckMissingRow { ident },
|
||||
Error::TypecheckError(TypecheckError::MissingRow(row, ..)),
|
||||
) if ident == row.label() => true,
|
||||
(
|
||||
TypecheckExtraRow { ident },
|
||||
Error::TypecheckError(TypecheckError::ExtraRow(ident1, ..)),
|
||||
) if ident == ident1.label() => true,
|
||||
(
|
||||
TypecheckRowConflict { row },
|
||||
Error::TypecheckError(TypecheckError::RowConflict(ident, ..)),
|
||||
) => row == ident.label(),
|
||||
(
|
||||
TypecheckRowConflict { row },
|
||||
Error::TypecheckError(TypecheckError::ArrowTypeMismatch(_, _, _, boxed_err, ..)),
|
||||
) => match boxed_err.as_ref() {
|
||||
TypecheckError::RowConflict(ident, ..) => row == ident.label(),
|
||||
_ => false,
|
||||
},
|
||||
(_, _) => false,
|
||||
}
|
||||
}
|
||||
@ -191,6 +235,8 @@ impl std::fmt::Display for ErrorExpectation {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
use ErrorExpectation::*;
|
||||
let name = match self {
|
||||
ParseError => "ParseError".to_owned(),
|
||||
ImportParseError => "ImportError::ParseError".to_owned(),
|
||||
EvalBlameError => "EvalError::BlameError".to_owned(),
|
||||
EvalTypeError => "EvalError::TypeError".to_owned(),
|
||||
EvalEqError => "EvalError::EqError".to_owned(),
|
||||
@ -210,14 +256,24 @@ impl std::fmt::Display for ErrorExpectation {
|
||||
TypecheckUnboundIdentifier { identifier } => {
|
||||
format!("TypecheckError::UnboundIdentifier({identifier})")
|
||||
}
|
||||
TypecheckUnboundTypeVariable { identifier } => {
|
||||
format!("TypecheckError::UnboundTypeVariable({identifier})")
|
||||
}
|
||||
TypecheckTypeMismatch { expected, found } => {
|
||||
format!("TypecheckError::TypeMismatch({expected}, {found})")
|
||||
}
|
||||
TypecheckMissingRow { ident } => {
|
||||
format!("TypecheckError::MissingRow({ident})")
|
||||
}
|
||||
TypecheckExtraRow { ident } => {
|
||||
format!("TypecheckError::ExtraRow({ident})")
|
||||
}
|
||||
TypecheckRowMismatch => "TypecheckError::RowMismatch".to_owned(),
|
||||
ParseError => "ParseError".to_owned(),
|
||||
TypecheckRowConflict { row } => {
|
||||
format!("TypecheckError::RowConflict({row})")
|
||||
}
|
||||
TypecheckExtraDynTail => "TypecheckError::ExtraDynTail".to_owned(),
|
||||
TypecheckMissingDynTail => "TypecheckError::MissingDynTail".to_owned(),
|
||||
};
|
||||
write!(f, "{}", name)
|
||||
}
|
||||
|
@ -1,71 +0,0 @@
|
||||
use assert_matches::assert_matches;
|
||||
use nickel_lang::error::{Error, EvalError};
|
||||
|
||||
use nickel_lang_utilities::test_program::eval;
|
||||
|
||||
#[test]
|
||||
fn elem_at() {
|
||||
assert_matches!(
|
||||
eval("%elem_at% [] 0"),
|
||||
Err(Error::EvalError(EvalError::Other(..)))
|
||||
);
|
||||
assert_matches!(
|
||||
eval("%elem_at% [1,2,3] (-1)"),
|
||||
Err(Error::EvalError(EvalError::Other(..)))
|
||||
);
|
||||
assert_matches!(
|
||||
eval("%elem_at% [true, false, true] 3"),
|
||||
Err(Error::EvalError(EvalError::Other(..)))
|
||||
);
|
||||
assert_matches!(
|
||||
eval("%elem_at% {} 0"),
|
||||
Err(Error::EvalError(EvalError::NAryPrimopTypeError { .. }))
|
||||
);
|
||||
assert_matches!(
|
||||
eval("%elem_at% [1, 2, 3] 0.5"),
|
||||
Err(Error::EvalError(EvalError::Other(..)))
|
||||
);
|
||||
|
||||
assert_matches!(
|
||||
eval("std.array.at 0 {} 0"),
|
||||
Err(Error::EvalError(EvalError::BlameError { .. }))
|
||||
);
|
||||
assert_matches!(
|
||||
eval("std.array.at \"a\" []"),
|
||||
Err(Error::EvalError(EvalError::BlameError { .. }))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn head_tail() {
|
||||
assert_matches!(
|
||||
eval("%elem_at% [] 0"),
|
||||
Err(Error::EvalError(EvalError::Other(..)))
|
||||
);
|
||||
assert_matches!(
|
||||
eval("%array_slice% 1 1 []"),
|
||||
Err(Error::EvalError(EvalError::Other(..)))
|
||||
);
|
||||
assert_matches!(
|
||||
eval("%array_slice% 0 1 {}"),
|
||||
Err(Error::EvalError(EvalError::NAryPrimopTypeError { .. }))
|
||||
);
|
||||
|
||||
// TODO: add non-empty contract to the input of array.first and array.tail
|
||||
// assert_matches!(
|
||||
// eval("array.first []"),
|
||||
// Err(Error::EvalError(EvalError::BlameError {..}))
|
||||
// );
|
||||
// assert_matches!(
|
||||
// eval("array.tail []"),
|
||||
// Err(Error::EvalError(EvalError::BlameError {..}))
|
||||
// );
|
||||
assert_matches!(
|
||||
eval("std.array.first false"),
|
||||
Err(Error::EvalError(EvalError::BlameError { .. }))
|
||||
);
|
||||
assert_matches!(
|
||||
eval("std.array.drop_first 2"),
|
||||
Err(Error::EvalError(EvalError::BlameError { .. }))
|
||||
);
|
||||
}
|
10
tests/integration/typecheck/fail/contracts_dont_unify.ncl
Normal file
10
tests/integration/typecheck/fail/contracts_dont_unify.ncl
Normal file
@ -0,0 +1,10 @@
|
||||
# test.type = 'error'
|
||||
# eval = 'typecheck'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::TypeMismatch'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# expected = 'fun l t => t'
|
||||
# found = 'fun l t => t'
|
||||
(fun x => x) : (fun l t => t) -> (fun l t => t)
|
@ -0,0 +1,6 @@
|
||||
# test.type = 'error'
|
||||
# eval = 'typecheck'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::ExtraDynTail'
|
||||
({ a = 1 } | { a : Number ; Dyn }) : { a : Number }
|
11
tests/integration/typecheck/fail/dynamic_record_field.ncl
Normal file
11
tests/integration/typecheck/fail/dynamic_record_field.ncl
Normal file
@ -0,0 +1,11 @@
|
||||
# test.type = 'error'
|
||||
# eval = 'typecheck'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::TypeMismatch'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# expected = '{ foo: Number }'
|
||||
# found = '{ _ : _a }'
|
||||
let x = "foo"
|
||||
in { "%{x}" = 1 } : { foo : Number }
|
@ -0,0 +1,10 @@
|
||||
# test.type = 'error'
|
||||
# eval = 'typecheck'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::TypeMismatch'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# expected = 'Array _a'
|
||||
# found = 'Number'
|
||||
(let head = fun l => (%elem_at% l 0) in (head 10)) : _
|
@ -0,0 +1,10 @@
|
||||
# test.type = 'error'
|
||||
# eval = 'typecheck'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::TypeMismatch'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# expected = 'Number'
|
||||
# found = 'Bool'
|
||||
match { 'foo => 3, 'bar => true } 'bar : Number
|
@ -0,0 +1,9 @@
|
||||
# test.type = 'error'
|
||||
# eval = 'typecheck'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::ExtraRow'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# ident = 'bar'
|
||||
match { 'foo => 3 } 'bar : Number
|
@ -0,0 +1,9 @@
|
||||
# test.type = 'error'
|
||||
# eval = 'typecheck'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::ExtraRow'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# ident = 'foo'
|
||||
'foo : [| 'bar |]
|
@ -0,0 +1,13 @@
|
||||
# test.type = 'error'
|
||||
# eval = 'typecheck'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::TypeMismatch'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# expected = 'lib.Contract'
|
||||
# found = 'lib.Contract'
|
||||
let lib = { Contract = fun label value => value } in
|
||||
let foo | lib.Contract = null in
|
||||
let lib = { Contract = fun label value => value } in
|
||||
foo : lib.Contract
|
10
tests/integration/typecheck/fail/mismatch_array_elem_at.ncl
Normal file
10
tests/integration/typecheck/fail/mismatch_array_elem_at.ncl
Normal file
@ -0,0 +1,10 @@
|
||||
# test.type = 'error'
|
||||
# eval = 'typecheck'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::TypeMismatch'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# expected = 'b'
|
||||
# found = 'a'
|
||||
(fun l => %elem_at% l 0) : forall a b. (Array a -> b)
|
10
tests/integration/typecheck/fail/mismatch_array_entry.ncl
Normal file
10
tests/integration/typecheck/fail/mismatch_array_entry.ncl
Normal file
@ -0,0 +1,10 @@
|
||||
# test.type = 'error'
|
||||
# eval = 'typecheck'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::TypeMismatch'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# expected = 'Number'
|
||||
# found = 'Bool'
|
||||
[1, 2, false] : Array Number
|
10
tests/integration/typecheck/fail/mismatch_array_map.ncl
Normal file
10
tests/integration/typecheck/fail/mismatch_array_map.ncl
Normal file
@ -0,0 +1,10 @@
|
||||
# test.type = 'error'
|
||||
# eval = 'typecheck'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::TypeMismatch'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# expected = 'Dyn -> _a'
|
||||
# found = 'a -> b'
|
||||
(fun f l => %map% l f) : forall a b. (a -> b) -> Array Dyn -> b
|
@ -0,0 +1,10 @@
|
||||
# test.type = 'error'
|
||||
# eval = 'typecheck'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::TypeMismatch'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# expected = 'String'
|
||||
# found = 'Number'
|
||||
[1, 2, "3"] : Array String
|
@ -0,0 +1,10 @@
|
||||
# test.type = 'error'
|
||||
# eval = 'typecheck'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::TypeMismatch'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# expected = 'String'
|
||||
# found = 'Dyn'
|
||||
[(1 : String), true, "b"] : Array Dyn
|
10
tests/integration/typecheck/fail/mismatch_contract_type.ncl
Normal file
10
tests/integration/typecheck/fail/mismatch_contract_type.ncl
Normal file
@ -0,0 +1,10 @@
|
||||
# test.type = 'error'
|
||||
# eval = 'typecheck'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::TypeMismatch'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# expected = 'Number'
|
||||
# found = 'Bool'
|
||||
(101 | Bool) : Number
|
@ -0,0 +1,6 @@
|
||||
# test.type = 'error'
|
||||
# eval = 'typecheck'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::MissingDynTail'
|
||||
{} : { ; Dyn }
|
@ -0,0 +1,9 @@
|
||||
# test.type = 'error'
|
||||
# eval = 'typecheck'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::ExtraRow'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# ident = 'b'
|
||||
{ a = 1, b = 2 } : { a : Number ; Dyn }
|
@ -0,0 +1,14 @@
|
||||
# test.type = 'error'
|
||||
# eval = 'typecheck'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::MissingRow'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# ident = 'blo'
|
||||
|
||||
# TODO: it would be lovely if this could statically typecheck, but it requires
|
||||
# row subtyping, which is non-trivial.
|
||||
(fun x =>
|
||||
(x |> match { 'bla => 1, 'bli => 2 }) +
|
||||
(x |> match { 'bla => 6, 'blo => 20 })) 'bla : Number
|
@ -0,0 +1,13 @@
|
||||
# test.type = 'error'
|
||||
# eval = 'typecheck'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::ExtraRow'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# ident = 'bli'
|
||||
(match {
|
||||
'bla => 1,
|
||||
'ble => 2,
|
||||
'bli => 3,
|
||||
}) : [| 'bla, 'ble |] -> Number
|
@ -0,0 +1,12 @@
|
||||
# test.type = 'error'
|
||||
# eval = 'typecheck'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::TypeMismatch'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# expected = 'p'
|
||||
# found = "[| 'blo ; _a |]"
|
||||
let f : forall r. (forall p. [| 'blo, 'ble ; r |] -> [| 'bla, 'bli; p |]) =
|
||||
match { 'blo => 'bla, 'ble => 'bli, _ => 'blo }
|
||||
in f 'bli
|
@ -0,0 +1,12 @@
|
||||
# test.type = 'error'
|
||||
# eval = 'typecheck'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::TypeMismatch'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# expected = 'r'
|
||||
# found = "[| 'bli |]"
|
||||
let f : forall r. [| 'blo, 'ble; r |] -> Number =
|
||||
match { 'blo => 1, 'ble => 2, 'bli => 3 }
|
||||
in f
|
@ -0,0 +1,12 @@
|
||||
# test.type = 'error'
|
||||
# eval = 'typecheck'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::TypeMismatch'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# expected = 'a'
|
||||
# found = 'Number'
|
||||
let g : Number -> Number = fun x => x in
|
||||
let f : forall a. a -> a = fun x => g x in
|
||||
f
|
@ -0,0 +1,12 @@
|
||||
# test.type = 'error'
|
||||
# eval = 'typecheck'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::TypeMismatch'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# expected = 'a'
|
||||
# found = 'b'
|
||||
let f : forall a. (forall b. a -> b -> a) =
|
||||
fun x y => y
|
||||
in f
|
13
tests/integration/typecheck/fail/mismatch_in_fun_body.ncl
Normal file
13
tests/integration/typecheck/fail/mismatch_in_fun_body.ncl
Normal file
@ -0,0 +1,13 @@
|
||||
# test.type = 'error'
|
||||
# eval = 'typecheck'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::TypeMismatch'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# expected = 'Number'
|
||||
# found = 'Bool'
|
||||
let f : Bool -> Number =
|
||||
fun x =>
|
||||
if x then x + 1 else 34
|
||||
in f false
|
14
tests/integration/typecheck/fail/mismatch_let_inference.ncl
Normal file
14
tests/integration/typecheck/fail/mismatch_let_inference.ncl
Normal file
@ -0,0 +1,14 @@
|
||||
# test.type = 'error'
|
||||
# eval = 'typecheck'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::TypeMismatch'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# expected = 'String'
|
||||
# found = 'Number'
|
||||
(
|
||||
let x = 1 + 2
|
||||
in let f = fun x => x ++ "a"
|
||||
in f x
|
||||
) : Number
|
@ -0,0 +1,14 @@
|
||||
# test.type = 'error'
|
||||
# eval = 'typecheck'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::TypeMismatch'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# expected = 'forall a. a -> a'
|
||||
# found = '_b -> _b'
|
||||
((fun f =>
|
||||
let g : forall b. b -> b =
|
||||
fun y => y
|
||||
in f g) : ((forall a. a -> a) -> Number) -> Number)
|
||||
(fun x => 3)
|
@ -0,0 +1,10 @@
|
||||
# test.type = 'error'
|
||||
# eval = 'typecheck'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::TypeMismatch'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# expected = 'Number'
|
||||
# found = 'Bool'
|
||||
{ a : Number = true, b = a + 1 } : { a : Number, b : Number }
|
@ -0,0 +1,12 @@
|
||||
# test.type = 'error'
|
||||
# eval = 'typecheck'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::TypeMismatch'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# expected = 'Bool'
|
||||
# found = 'Number'
|
||||
{
|
||||
f = fun x => if x == 0 then false else 1 + (f (x + (-1)))
|
||||
} : { f : Number -> Number }
|
@ -0,0 +1,10 @@
|
||||
# test.type = 'error'
|
||||
# eval = 'typecheck'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::TypeMismatch'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# expected = 'Bool'
|
||||
# found = 'Number'
|
||||
{ a = 1, b : Bool = a } : { a : Number, b : Bool }
|
@ -0,0 +1,13 @@
|
||||
# test.type = 'error'
|
||||
# eval = 'typecheck'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::TypeMismatch'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# expected = '{ bla: _a ; _a }'
|
||||
# found = '{ _ : _b }'
|
||||
({
|
||||
"%{if true then "foo" else "bar"}" = 2,
|
||||
"foo" = true,
|
||||
}."bla") : Number
|
@ -0,0 +1,10 @@
|
||||
# test.type = 'error'
|
||||
# eval = 'typecheck'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::TypeMismatch'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# expected = 'Bool'
|
||||
# found = 'Number'
|
||||
{ blo = 1 }.blo : Bool
|
@ -0,0 +1,9 @@
|
||||
# test.type = 'error'
|
||||
# eval = 'typecheck'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::MissingRow'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# ident = 'bla'
|
||||
{ blo = 1 } : { bla : Number }
|
@ -0,0 +1,10 @@
|
||||
# test.type = 'error'
|
||||
# eval = 'typecheck'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::TypeMismatch'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# expected = 'Number'
|
||||
# found = 'Bool'
|
||||
{ bla = true } : { bla : Number }
|
@ -0,0 +1,14 @@
|
||||
# test.type = 'error'
|
||||
# eval = 'typecheck'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::TypeMismatch'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# expected = 'r'
|
||||
# found = 'Number'
|
||||
|
||||
# TODO: the expected/found types above seem wrong here
|
||||
let f : forall a. (forall r. { bla : Bool, blo: a, ble: a; r } -> a) =
|
||||
fun r => if r.bla then (r.blo + 1) else r.ble
|
||||
in (f { bla = true, blo = 1, ble = 2, blip = 'blip } : Number)
|
@ -0,0 +1,12 @@
|
||||
# test.type = 'error'
|
||||
# eval = 'typecheck'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::TypeMismatch'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# expected = 'Number'
|
||||
# found = 'Bool'
|
||||
let f : forall a. { bla : Bool, blo: a, ble: a } -> a =
|
||||
fun r => if r.bla then r.blo else r.ble
|
||||
in (f { bla = true, blo = 1, ble = true } : Number)
|
@ -0,0 +1,10 @@
|
||||
# test.type = 'error'
|
||||
# eval = 'typecheck'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::TypeMismatch'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# expected = '_a -> _b'
|
||||
# found = 'Dyn'
|
||||
(fun id => { a : Number = id 4, b : Bool = id true }) (fun x => x)
|
10
tests/integration/typecheck/fail/piecewise_signature.ncl
Normal file
10
tests/integration/typecheck/fail/piecewise_signature.ncl
Normal file
@ -0,0 +1,10 @@
|
||||
# test.type = 'error'
|
||||
# eval = 'typecheck'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::TypeMismatch'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# expected = 'Number'
|
||||
# found = 'String'
|
||||
{ foo : Number, foo = "bar" }
|
@ -0,0 +1,10 @@
|
||||
# test.type = 'error'
|
||||
# eval = 'typecheck'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::TypeMismatch'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# expected = 'Number'
|
||||
# found = 'Bool'
|
||||
true : Number
|
@ -0,0 +1,10 @@
|
||||
# test.type = 'error'
|
||||
# eval = 'typecheck'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::TypeMismatch'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# expected = 'Bool'
|
||||
# found = 'Number'
|
||||
34.5 : Bool
|
@ -0,0 +1,10 @@
|
||||
# test.type = 'error'
|
||||
# eval = 'typecheck'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::TypeMismatch'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# expected = 'Number'
|
||||
# found = 'String'
|
||||
"hello" : Number
|
12
tests/integration/typecheck/fail/recursive_let.ncl
Normal file
12
tests/integration/typecheck/fail/recursive_let.ncl
Normal file
@ -0,0 +1,12 @@
|
||||
# test.type = 'error'
|
||||
# eval = 'typecheck'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::TypeMismatch'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# expected = 'Number'
|
||||
# found = 'String'
|
||||
let rec f : Number -> Number =
|
||||
fun x => f "hmm"
|
||||
in null
|
14
tests/integration/typecheck/fail/row_conflict_extend.ncl
Normal file
14
tests/integration/typecheck/fail/row_conflict_extend.ncl
Normal file
@ -0,0 +1,14 @@
|
||||
# test.type = 'error'
|
||||
# eval = 'typecheck'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::RowConflict'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# row = 'a'
|
||||
|
||||
# Regression test following [#144](https://github.com/tweag/nickel/issues/144). Check that
|
||||
# polymorphic type variables appearing inside a row type are correctly constrained at
|
||||
# instantiation.
|
||||
let extend | forall c. { ; c } -> { a : String ; c} = null
|
||||
in (let bad = extend { a = 1 } in 0) : Number
|
14
tests/integration/typecheck/fail/row_conflict_remove.ncl
Normal file
14
tests/integration/typecheck/fail/row_conflict_remove.ncl
Normal file
@ -0,0 +1,14 @@
|
||||
# test.type = 'error'
|
||||
# eval = 'typecheck'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::MissingRow'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# ident = 'a'
|
||||
|
||||
# Regression test following [#144](https://github.com/tweag/nickel/issues/144). Check that
|
||||
# polymorphic type variables appearing inside a row type are correctly constrained at
|
||||
# instantiation.
|
||||
let remove | forall c. { a : String ; c } -> { ; c } = null
|
||||
in (let bad = remove (remove { a = "a" }) in 0) : Number
|
10
tests/integration/typecheck/fail/shallow_type_inference.ncl
Normal file
10
tests/integration/typecheck/fail/shallow_type_inference.ncl
Normal file
@ -0,0 +1,10 @@
|
||||
# test.type = 'error'
|
||||
# eval = 'typecheck'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::TypeMismatch'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# expected = 'Number'
|
||||
# found = 'Dyn'
|
||||
let x = (1 + 1) in (x + 1 : Number)
|
@ -0,0 +1,11 @@
|
||||
# test.type = 'error'
|
||||
# eval = 'typecheck'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::TypeMismatch'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# expected = '_a -> _b'
|
||||
# found = 'Dyn'
|
||||
let id = fun x => x
|
||||
in (id 4 : Number)
|
9
tests/integration/typecheck/fail/unbound_variable.ncl
Normal file
9
tests/integration/typecheck/fail/unbound_variable.ncl
Normal file
@ -0,0 +1,9 @@
|
||||
# test.type = 'error'
|
||||
# eval = 'typecheck'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::UnboundIdentifier'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# identifier = 'i_am_unbound'
|
||||
i_am_unbound
|
@ -0,0 +1,12 @@
|
||||
# test.type = 'error'
|
||||
# eval = 'typecheck'
|
||||
#
|
||||
# [test.metadata]
|
||||
# error = 'TypecheckError::TypeMismatch'
|
||||
#
|
||||
# [test.metadata.expectation]
|
||||
# expected = '_a -> _b'
|
||||
# found = 'Dyn'
|
||||
let f : _ -> _ = fun x => x + 1 in
|
||||
let g : Number = f 0 in
|
||||
g
|
@ -0,0 +1,4 @@
|
||||
# test.type = 'pass'
|
||||
# eval = 'typecheck'
|
||||
let head = fun l => (%elem_at% l 0)
|
||||
in head 10
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user