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,
|
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(url("https://aiken-lang.org/language-tour/functions#named-functions"))]
|
||||||
#[diagnostic(code("illegal::return"))]
|
#[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.
|
#[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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::only_used_in_recursion)]
|
||||||
fn assert_no_assignment(&self, expr: &UntypedExpr) -> Result<(), Error> {
|
fn assert_no_assignment(&self, expr: &UntypedExpr) -> Result<(), Error> {
|
||||||
match expr {
|
match expr {
|
||||||
UntypedExpr::Assignment { value, .. } => Err(Error::LastExpressionIsAssignment {
|
UntypedExpr::Assignment { value, .. } => Err(Error::LastExpressionIsAssignment {
|
||||||
location: expr.location(),
|
location: expr.location(),
|
||||||
expr: *value.clone(),
|
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,
|
body: UntypedExpr,
|
||||||
return_type: Option<Arc<Type>>,
|
return_type: Option<Arc<Type>>,
|
||||||
) -> Result<(Vec<TypedArg>, TypedExpr), Error> {
|
) -> Result<(Vec<TypedArg>, TypedExpr), Error> {
|
||||||
|
self.assert_no_assignment(&body)?;
|
||||||
|
|
||||||
let (body_rigid_names, body_infer) = self.in_new_scope(|body_typer| {
|
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())) {
|
for (arg, t) in args.iter().zip(args.iter().map(|arg| arg.tipo.clone())) {
|
||||||
match &arg.arg_name {
|
match &arg.arg_name {
|
||||||
|
|
Loading…
Reference in New Issue