1
1
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:
matthew healy 2023-05-23 14:48:32 +02:00 committed by GitHub
parent d2f5cb5250
commit b8094824b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
102 changed files with 774 additions and 676 deletions

View File

@ -0,0 +1,5 @@
# test.type = 'error'
#
# [test.metadata]
# error = 'EvalError::Other'
%elem_at% [] 0

View File

@ -0,0 +1,5 @@
# test.type = 'error'
#
# [test.metadata]
# error = 'EvalError::Other'
%elem_at% [true, false, true] 3

View File

@ -0,0 +1,5 @@
# test.type = 'error'
#
# [test.metadata]
# error = 'EvalError::Other'
%elem_at% [1, 2, 3] (-1)

View File

@ -0,0 +1,5 @@
# test.type = 'error'
#
# [test.metadata]
# error = 'EvalError::NAryPrimopTypeError'
%elem_at% {} 0

View File

@ -0,0 +1,5 @@
# test.type = 'error'
#
# [test.metadata]
# error = 'EvalError::Other'
%elem_at% [1, 2, 3] 0.5

View File

@ -0,0 +1,5 @@
# test.type = 'error'
#
# [test.metadata]
# error = 'EvalError::Other'
%array_slice% 1 1 []

View File

@ -0,0 +1,5 @@
# test.type = 'error'
#
# [test.metadata]
# error = 'EvalError::NAryPrimopTypeError'
%array_slice% 0 1 {}

View File

@ -0,0 +1,5 @@
# test.type = 'error'
#
# [test.metadata]
# error = 'EvalError::BlameError'
std.array.at 0 {}

View File

@ -0,0 +1,5 @@
# test.type = 'error'
#
# [test.metadata]
# error = 'EvalError::BlameError'
std.array.at "a" []

View File

@ -0,0 +1,5 @@
# test.type = 'error'
#
# [test.metadata]
# error = 'EvalError::BlameError'
std.array.drop_first 2

View File

@ -0,0 +1,5 @@
# test.type = 'error'
#
# [test.metadata]
# error = 'EvalError::BlameError'
std.array.first false

View 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

View 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

View 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 }]

View File

@ -0,0 +1,8 @@
# test.type = 'error'
#
# [test.metadata]
# error = 'TypecheckError::UnboundIdentifier'
#
# [test.metadata.expectation]
# identifier = 'a'
1 | a

View File

@ -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(()));
}

View File

@ -0,0 +1,2 @@
# test.type = 'pass'
(import "imported/circular_imports.ncl") == { a = 1, b = 1 }

View File

@ -0,0 +1,5 @@
# test.type = 'error'
#
# [test.metadata]
# error = 'EvalError::BlameError'
import "imported/contract_fail.ncl"

View File

@ -1,2 +0,0 @@
# test.type = 'skip'
let x = import "cycle_b.ncl" in {a = 1, b = x.a}

View File

@ -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}

View File

@ -1,4 +0,0 @@
# test.type = 'skip'
let _x = import "cycle.ncl" in
let _y = import "cycle_b.ncl" in
0

View File

@ -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"

View File

@ -0,0 +1,2 @@
# test.type = 'skip'
let x = import "circular_imports1.ncl" in {a = 1, b = x.a}

View 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}

View File

@ -0,0 +1,4 @@
# test.type = 'skip'
let _x = import "circular_imports.ncl" in
let _y = import "circular_imports1.ncl" in
0

View File

@ -1,2 +1,2 @@
# test.type = 'skip'
1 | String
1 | String

View File

@ -0,0 +1,2 @@
# test.type = 'skip'
import "direct_import_loop.ncl"

View File

@ -0,0 +1,4 @@
# test.type = 'skip'
let x = import "two.ncl" in
let y = import "nested.ncl" in
x + y

View File

@ -0,0 +1,2 @@
# test.type = 'skip'
let x = import "two.ncl" in x + 1

View File

@ -0,0 +1,2 @@
# test.type = 'skip'
import "nested_syntax_error1.ncl"

View File

@ -0,0 +1,2 @@
# test.type = 'skip'
import "root_path/import.ncl"

View File

@ -0,0 +1,7 @@
# test.type = 'skip'
{
foo = {
bar = [2 @ ],
},
baz = 2
}

View File

@ -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

View File

@ -1,2 +1,2 @@
# test.type = 'skip'
let x = import "two.ncl" in x + 1
# test.type = 'pass'
(import "imported/nested.ncl") == 3

View File

@ -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"

View File

@ -1,2 +1,2 @@
# test.type = 'skip'
import "root_path/import.ncl"
# test.type = 'pass'
(import "imported/root_path.ncl") == 44

View File

@ -0,0 +1,2 @@
# test.type = 'pass'
(std.serialize 'Json (import "imported/serialize.ncl") == (std.serialize 'Json ({ foo = "ab" })))

View 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

View 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"

View File

@ -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"

View File

@ -0,0 +1,5 @@
# test.type = 'error'
#
# [test.metadata]
# error = 'ImportError::ParseError'
import "imported/unexpected_token.ncl"

View File

@ -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

View File

@ -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)
}

View File

@ -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 { .. }))
);
}

View 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)

View File

@ -0,0 +1,6 @@
# test.type = 'error'
# eval = 'typecheck'
#
# [test.metadata]
# error = 'TypecheckError::ExtraDynTail'
({ a = 1 } | { a : Number ; Dyn }) : { a : Number }

View 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 }

View File

@ -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)) : _

View File

@ -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

View File

@ -0,0 +1,9 @@
# test.type = 'error'
# eval = 'typecheck'
#
# [test.metadata]
# error = 'TypecheckError::ExtraRow'
#
# [test.metadata.expectation]
# ident = 'bar'
match { 'foo => 3 } 'bar : Number

View File

@ -0,0 +1,9 @@
# test.type = 'error'
# eval = 'typecheck'
#
# [test.metadata]
# error = 'TypecheckError::ExtraRow'
#
# [test.metadata.expectation]
# ident = 'foo'
'foo : [| 'bar |]

View File

@ -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

View 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)

View 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

View 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

View File

@ -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

View File

@ -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

View 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

View File

@ -0,0 +1,6 @@
# test.type = 'error'
# eval = 'typecheck'
#
# [test.metadata]
# error = 'TypecheckError::MissingDynTail'
{} : { ; Dyn }

View File

@ -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 }

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View 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

View 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

View File

@ -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)

View File

@ -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 }

View File

@ -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 }

View File

@ -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 }

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,9 @@
# test.type = 'error'
# eval = 'typecheck'
#
# [test.metadata]
# error = 'TypecheckError::MissingRow'
#
# [test.metadata.expectation]
# ident = 'bla'
{ blo = 1 } : { bla : Number }

View File

@ -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 }

View File

@ -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)

View File

@ -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)

View File

@ -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)

View 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" }

View File

@ -0,0 +1,10 @@
# test.type = 'error'
# eval = 'typecheck'
#
# [test.metadata]
# error = 'TypecheckError::TypeMismatch'
#
# [test.metadata.expectation]
# expected = 'Number'
# found = 'Bool'
true : Number

View File

@ -0,0 +1,10 @@
# test.type = 'error'
# eval = 'typecheck'
#
# [test.metadata]
# error = 'TypecheckError::TypeMismatch'
#
# [test.metadata.expectation]
# expected = 'Bool'
# found = 'Number'
34.5 : Bool

View File

@ -0,0 +1,10 @@
# test.type = 'error'
# eval = 'typecheck'
#
# [test.metadata]
# error = 'TypecheckError::TypeMismatch'
#
# [test.metadata.expectation]
# expected = 'Number'
# found = 'String'
"hello" : Number

View 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

View 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

View 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

View 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)

View File

@ -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)

View 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

View File

@ -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

View File

@ -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