Provide default annotation to validators (incl. fallback)

Without that, we may encounter weird error messages when writing
  validators without an explicit `else`. Since we automatically fill it
  with a `fail`; without annotation, it unifies to a generic parameter.

  The existing check that would look for the body being an error term is
  ill-advised as it doesn't work as soon as one adds tracing, or make
  the validator a parameterized validator. Plus, it may simply trigger
  the wrong behavior as one can now annotate a validator with _whatever_
  and get pass the type-checker by plucking a `fail` keyword as body.
This commit is contained in:
KtorZ 2024-08-25 17:08:46 +02:00
parent 1198d7a5ae
commit af9a785d65
No known key found for this signature in database
GPG Key ID: 33173CB6F77F4277
3 changed files with 36 additions and 34 deletions

View File

@ -1,12 +1,10 @@
use chumsky::prelude::*;
use super::function::param;
use crate::{
ast::{self, ArgBy, ArgName},
expr::UntypedExpr,
parser::{annotation, error::ParseError, expr, token::Token},
};
use super::function::param;
use chumsky::prelude::*;
pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError> {
just(Token::Validator)
@ -52,36 +50,38 @@ pub fn parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError
},
));
let location = ast::Span {
start: span.start,
// capture the span from the optional params
end: params_span.end,
};
ast::UntypedDefinition::Validator(ast::Validator {
doc: None,
name,
handlers,
location: ast::Span {
start: span.start,
// capture the span from the optional params
end: params_span.end,
},
location,
params,
end_position: span.end - 1,
fallback: opt_catch_all.unwrap_or(ast::Function {
arguments: vec![ast::UntypedArg {
by: ArgBy::ByName(ArgName::Discarded {
name: "_ctx".to_string(),
label: "_ctx".to_string(),
location: ast::Span::empty(),
name: "_".to_string(),
label: "_".to_string(),
location,
}),
location: ast::Span::empty(),
location,
annotation: None,
doc: None,
is_validator_param: false,
}],
body: UntypedExpr::fail(None, ast::Span::empty()),
body: UntypedExpr::fail(None, location),
doc: None,
location: ast::Span::empty(),
end_position: span.end - 1,
location,
end_position: location.end - 1,
name: "else".to_string(),
public: true,
return_annotation: None,
return_annotation: Some(ast::Annotation::boolean(location)),
return_type: (),
on_test_failure: ast::OnTestFailure::FailImmediately,
}),
@ -103,23 +103,28 @@ pub fn args_and_body() -> impl Parser<Token, ast::UntypedFunction, Error = Parse
.delimited_by(just(Token::LeftBrace), just(Token::RightBrace)),
)
.map_with_span(
|(((arguments, args_span), return_annotation), body), span| ast::Function {
arguments,
body: body.unwrap_or_else(|| UntypedExpr::todo(None, span)),
doc: None,
location: ast::Span {
|(((arguments, args_span), return_annotation), body), span| {
let location = ast::Span {
start: span.start,
end: return_annotation
.as_ref()
.map(|l| l.location().end)
.unwrap_or_else(|| args_span.end),
},
};
ast::Function {
arguments,
body: body.unwrap_or_else(|| UntypedExpr::todo(None, span)),
doc: None,
location,
end_position: span.end - 1,
name: "temp".to_string(),
public: true,
return_annotation,
return_annotation: return_annotation
.or(Some(ast::Annotation::boolean(location))),
return_type: (),
on_test_failure: ast::OnTestFailure::FailImmediately,
}
},
)
}

View File

@ -259,8 +259,7 @@ fn infer_definition(
typed_fallback.name = old_name;
if !typed_fallback.body.is_error_term() && !typed_fallback.return_type.is_bool()
{
if !typed_fallback.return_type.is_bool() {
return Err(Error::ValidatorMustReturnBool {
return_type: typed_fallback.return_type.clone(),
location: typed_fallback.location,

View File

@ -100,9 +100,7 @@ pub fn eval_phase_two_raw(
.or_else(|_| MultiEraTx::decode_for_era(Era::Babbage, tx_bytes))
.or_else(|_| MultiEraTx::decode_for_era(Era::Alonzo, tx_bytes))?;
let cost_mdls = cost_mdls_bytes
.map(|x| CostMdls::decode_fragment(x))
.transpose()?;
let cost_mdls = cost_mdls_bytes.map(CostMdls::decode_fragment).transpose()?;
let budget = ExBudget {
cpu: initial_budget.0 as i64,