[fine] Some fixes around return statements
This commit is contained in:
parent
44bc072b04
commit
55749af917
3 changed files with 59 additions and 4 deletions
|
|
@ -858,7 +858,7 @@ impl<'a> Semantics<'a> {
|
|||
(Type::Error, _) => Some(Type::Error),
|
||||
(_, Some(Type::Error)) => Some(Type::Error),
|
||||
|
||||
(Type::Unreachable, None) => Some(Type::Unreachable),
|
||||
(Type::Unreachable, None) => Some(Type::Nothing),
|
||||
(Type::Unreachable, Some(t)) => Some(t),
|
||||
(t, Some(Type::Unreachable)) => Some(t),
|
||||
|
||||
|
|
@ -1004,13 +1004,14 @@ impl<'a> Semantics<'a> {
|
|||
for p in param_list.child_trees() {
|
||||
let param = &self.syntax_tree[p];
|
||||
|
||||
// TODO: Shouldn't this just be type_of(param)?
|
||||
// TODO: Missing type expression means it's a generic function.
|
||||
let parameter_type = param.child_of_kind(self.syntax_tree, TreeKind::TypeExpression)?;
|
||||
parameter_types.push(Box::new(self.type_of(parameter_type)));
|
||||
}
|
||||
|
||||
let return_type = match tree.child_tree_of_kind(self.syntax_tree, TreeKind::ReturnType) {
|
||||
Some(t) => self.type_of(t.child_of_kind(self.syntax_tree, TreeKind::TypeExpression)?),
|
||||
let return_type = match tree.child_of_kind(self.syntax_tree, TreeKind::ReturnType) {
|
||||
Some(t) => self.type_of(t),
|
||||
None => Type::Nothing,
|
||||
};
|
||||
let return_type = Box::new(return_type);
|
||||
|
|
@ -1114,7 +1115,7 @@ pub fn check(s: &Semantics) {
|
|||
TreeKind::LetStatement => {
|
||||
let _ = s.environment_of(t);
|
||||
}
|
||||
TreeKind::ReturnStatement => {}
|
||||
TreeKind::ReturnStatement => check_return_statement(s, tree),
|
||||
TreeKind::ExpressionStatement
|
||||
| TreeKind::LiteralExpression
|
||||
| TreeKind::GroupingExpression
|
||||
|
|
@ -1169,6 +1170,49 @@ fn check_function_decl(s: &Semantics, t: TreeRef, tree: &Tree) {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_return_statement(s: &Semantics, tree: &Tree) {
|
||||
assert_eq!(tree.kind, TreeKind::ReturnStatement);
|
||||
|
||||
let mut enclosing_function = tree.parent;
|
||||
while let Some(fp) = enclosing_function {
|
||||
let fpt = &s.syntax_tree[fp];
|
||||
if fpt.kind == TreeKind::FunctionDecl {
|
||||
break;
|
||||
}
|
||||
|
||||
enclosing_function = fpt.parent;
|
||||
}
|
||||
let Some(enclosing_function) = enclosing_function else {
|
||||
s.report_error_tree(
|
||||
tree,
|
||||
"a return statement can only be used inside a function",
|
||||
);
|
||||
return;
|
||||
};
|
||||
|
||||
let function_type = s.type_of(enclosing_function);
|
||||
match function_type {
|
||||
Type::Function(_, expected_type) => {
|
||||
let actual_type = if let Some(expr) = tree.nth_tree(1) {
|
||||
s.type_of(expr)
|
||||
} else {
|
||||
Type::Error
|
||||
};
|
||||
|
||||
if !expected_type.compatible_with(&actual_type) {
|
||||
s.report_error_tree(tree, format!("callers of this function expect a value of type `{expected_type}` but this statement returns a value of type `{actual_type}`"));
|
||||
}
|
||||
}
|
||||
Type::Error => (),
|
||||
_ => s.internal_compiler_error(
|
||||
Some(enclosing_function),
|
||||
"a return statement in here expected this to yield a function type",
|
||||
),
|
||||
}
|
||||
|
||||
// OK this one is a little bit messed up because it reaches *up*, sorry.
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
|
|||
3
fine/tests/errors/return_statement_only_function.fine
Normal file
3
fine/tests/errors/return_statement_only_function.fine
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
return "skidoo!";
|
||||
|
||||
// @check-error: a return statement can only be used inside a function
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fun test() -> f64 {
|
||||
if false {
|
||||
return "no way!";
|
||||
}
|
||||
23.0
|
||||
}
|
||||
|
||||
// @check-error: 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