[fine] All error sentinels carry diagnostics
The system has an invariant that if you ever return an error sentinel (error environment, error type) then that sentinel is caused by an error that was reported to the user. We have had too many bugs over the last little while where that was not the case! (An example is if we mis-interpret the tree by calling `nth_tree` with the wrong index or something, and get `None`, and think "oh must be a syntax error", but it was really just the wrong index. Then there's an error sentinel with no error diagnostic and we don't discover the mistake until much farther along.) Now we enforce this by requiring that whoever constructs the error sentinel *prove* that they can do so by providing a diagnostic. It's less efficient but prevents the problem. This actually uncovered a couple of latent bugs where we were generating error sentinels instead of a more appropriate type! Whoops!
This commit is contained in:
parent
8779aade24
commit
85ffc0c7dd
6 changed files with 276 additions and 170 deletions
|
|
@ -198,7 +198,7 @@ fn assert_type_at(module: Rc<fine::Module>, pos: usize, expected: &str, _source_
|
|||
|
||||
fn assert_type_error_at(
|
||||
module: Rc<fine::Module>,
|
||||
errors: &[Error],
|
||||
errors: &[Rc<Error>],
|
||||
pos: usize,
|
||||
expected: &str,
|
||||
_source_path: &str,
|
||||
|
|
@ -219,7 +219,7 @@ fn assert_type_error_at(
|
|||
semantic_assert!(
|
||||
&semantics,
|
||||
Some(tree_ref),
|
||||
matches!(tree_type, Type::Error),
|
||||
matches!(tree_type, Type::Error(_)),
|
||||
"The type of the {:?} tree at position {pos} was '{tree_type:?}', not an error",
|
||||
tree[tree_ref].kind
|
||||
);
|
||||
|
|
@ -286,10 +286,10 @@ fn assert_compiles_to(module: Rc<fine::Module>, expected: &str, source_path: &st
|
|||
}
|
||||
}
|
||||
|
||||
fn assert_no_errors(module: Rc<fine::Module>, errors: &[Error]) {
|
||||
fn assert_no_errors(module: Rc<fine::Module>, errors: &[Rc<Error>]) {
|
||||
let semantics = module.semantics();
|
||||
|
||||
let expected_errors: &[Error] = &[];
|
||||
let expected_errors: &[Rc<Error>] = &[];
|
||||
semantic_assert_eq!(
|
||||
&semantics,
|
||||
None,
|
||||
|
|
@ -341,7 +341,7 @@ fn assert_eval_ok(module: Rc<fine::Module>, expected: &str) {
|
|||
}
|
||||
}
|
||||
|
||||
fn assert_errors(module: Rc<fine::Module>, errors: &[Error], expected_errors: Vec<&str>) {
|
||||
fn assert_errors(module: Rc<fine::Module>, errors: &[Rc<Error>], expected_errors: Vec<&str>) {
|
||||
let semantics = module.semantics();
|
||||
|
||||
let errors: Vec<String> = errors.iter().map(|e| format!("{}", e)).collect();
|
||||
|
|
@ -355,7 +355,7 @@ fn assert_errors(module: Rc<fine::Module>, errors: &[Error], expected_errors: Ve
|
|||
);
|
||||
}
|
||||
|
||||
fn assert_check_error(module: Rc<fine::Module>, errors: &[Error], expected: &str) {
|
||||
fn assert_check_error(module: Rc<fine::Module>, errors: &[Rc<Error>], expected: &str) {
|
||||
let semantics = module.semantics();
|
||||
|
||||
semantic_assert!(
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
fun something() -> f64 {
|
||||
return
|
||||
}
|
||||
|
||||
fun test() -> f64 {
|
||||
if false {
|
||||
return "no way!";
|
||||
|
|
@ -6,4 +10,5 @@ fun test() -> f64 {
|
|||
}
|
||||
|
||||
// @expect-errors:
|
||||
// | __test__:3:4: callers of this function expect a value of type 'f64' but this statement returns a value of type 'string'
|
||||
// | __test__:2:2: callers of this function expect a value of type 'f64' but this statement returns a value of type 'nothing'
|
||||
// | __test__:7:4: callers of this function expect a value of type 'f64' but this statement returns a value of type 'string'
|
||||
Loading…
Add table
Add a link
Reference in a new issue