Forbid solo-assignment as the only function body
In the similar spirit to what we did for sequences. Yet, we need to handle the case of body being just an assignment -- or a trace of an assignment which is basically the same thing.
This commit is contained in:
parent
2101bb924d
commit
d905f24e7f
|
@ -133,7 +133,7 @@ You can use '{discard}' and numbers to distinguish between similar names.
|
|||
location: Span,
|
||||
},
|
||||
|
||||
#[error("I discovered a function who's ending with an assignment.")]
|
||||
#[error("I discovered a function which is ending with an assignment.")]
|
||||
#[diagnostic(url("https://aiken-lang.org/language-tour/functions#named-functions"))]
|
||||
#[diagnostic(code("illegal::return"))]
|
||||
#[diagnostic(help(r#"In Aiken, functions must return an explicit result in the form of an expression. While assignments are technically speaking expressions, they aren't allowed to be the last expression of a function because they convey a different meaning and this could be error-prone.
|
||||
|
|
|
@ -200,13 +200,33 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(clippy::only_used_in_recursion)]
|
||||
fn assert_no_assignment(&self, expr: &UntypedExpr) -> Result<(), Error> {
|
||||
match expr {
|
||||
UntypedExpr::Assignment { value, .. } => Err(Error::LastExpressionIsAssignment {
|
||||
location: expr.location(),
|
||||
expr: *value.clone(),
|
||||
}),
|
||||
_ => Ok(()),
|
||||
UntypedExpr::Trace { then, .. } => self.assert_no_assignment(then),
|
||||
UntypedExpr::Fn { .. }
|
||||
| UntypedExpr::BinOp { .. }
|
||||
| UntypedExpr::ByteArray { .. }
|
||||
| UntypedExpr::Call { .. }
|
||||
| UntypedExpr::ErrorTerm { .. }
|
||||
| UntypedExpr::FieldAccess { .. }
|
||||
| UntypedExpr::If { .. }
|
||||
| UntypedExpr::Int { .. }
|
||||
| UntypedExpr::List { .. }
|
||||
| UntypedExpr::PipeLine { .. }
|
||||
| UntypedExpr::RecordUpdate { .. }
|
||||
| UntypedExpr::Sequence { .. }
|
||||
| UntypedExpr::String { .. }
|
||||
| UntypedExpr::Todo { .. }
|
||||
| UntypedExpr::Tuple { .. }
|
||||
| UntypedExpr::TupleIndex { .. }
|
||||
| UntypedExpr::UnOp { .. }
|
||||
| UntypedExpr::Var { .. }
|
||||
| UntypedExpr::When { .. } => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1563,6 +1583,8 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
body: UntypedExpr,
|
||||
return_type: Option<Arc<Type>>,
|
||||
) -> Result<(Vec<TypedArg>, TypedExpr), Error> {
|
||||
self.assert_no_assignment(&body)?;
|
||||
|
||||
let (body_rigid_names, body_infer) = self.in_new_scope(|body_typer| {
|
||||
for (arg, t) in args.iter().zip(args.iter().map(|arg| arg.tipo.clone())) {
|
||||
match &arg.arg_name {
|
||||
|
|
Loading…
Reference in New Issue