feat: enforcement that spend first arg is option

This commit is contained in:
rvcas 2024-08-22 17:03:47 -04:00 committed by KtorZ
parent c57009bf99
commit 4589c51cd3
No known key found for this signature in database
GPG Key ID: 33173CB6F77F4277
3 changed files with 33 additions and 11 deletions

View File

@ -278,6 +278,10 @@ impl TypedFunction {
}) })
} }
pub fn is_spend(&self) -> bool {
self.name == HANDLER_SPEND
}
pub fn has_valid_purpose_name(&self) -> bool { pub fn has_valid_purpose_name(&self) -> bool {
self.name == HANDLER_SPEND self.name == HANDLER_SPEND
|| self.name == HANDLER_PUBLISH || self.name == HANDLER_PUBLISH

View File

@ -358,7 +358,7 @@ fn expect_multi_patterns() {
fn validator_correct_form() { fn validator_correct_form() {
let source_code = r#" let source_code = r#"
validator foo { validator foo {
spend(d, r, oref, c) { spend(d: Option<Data>, r, oref, c) {
True True
} }
} }
@ -389,7 +389,7 @@ fn validator_in_lib_warning() {
fn multi_validator() { fn multi_validator() {
let source_code = r#" let source_code = r#"
validator foo(foo: ByteArray, bar: Int) { validator foo(foo: ByteArray, bar: Int) {
spend(_d, _r, _oref, _c) { spend(_d: Option<Data>, _r, _oref, _c) {
foo == #"aabb" foo == #"aabb"
} }
@ -408,7 +408,7 @@ fn multi_validator() {
fn multi_validator_warning() { fn multi_validator_warning() {
let source_code = r#" let source_code = r#"
validator foo(foo: ByteArray, bar: Int) { validator foo(foo: ByteArray, bar: Int) {
spend(_d, _r, _oref, _c) { spend(_d: Option<Data>, _r, _oref, _c) {
foo == #"aabb" foo == #"aabb"
} }
@ -458,7 +458,7 @@ fn exhaustiveness_simple() {
fn validator_args_no_annotation() { fn validator_args_no_annotation() {
let source_code = r#" let source_code = r#"
validator hello(d) { validator hello(d) {
spend(a, b, oref, c) { spend(a: Option<Data>, b, oref, c) {
True True
} }
} }
@ -475,9 +475,13 @@ fn validator_args_no_annotation() {
assert!(param.tipo.is_data()); assert!(param.tipo.is_data());
}); });
validator.handlers[0].arguments.iter().for_each(|arg| { validator.handlers[0]
assert!(arg.tipo.is_data()); .arguments
}) .iter()
.skip(1)
.for_each(|arg| {
assert!(arg.tipo.is_data());
})
}) })
} }
@ -2471,8 +2475,10 @@ fn validator_private_type_leak() {
} }
validator bar { validator bar {
spend(datum: Datum, redeemer: Redeemer, _oref, _ctx) { spend(datum: Option<Datum>, redeemer: Redeemer, _oref, _ctx) {
datum.foo == redeemer.bar expect Some(d) = datum
d.foo == redeemer.bar
} }
} }
"#; "#;
@ -2495,8 +2501,10 @@ fn validator_public() {
} }
validator bar { validator bar {
spend(datum: Datum, redeemer: Redeemer, _oref, _ctx) { spend(datum: Option<Datum>, redeemer: Redeemer, _oref, _ctx) {
datum.foo == redeemer.bar expect Some(d) = datum
d.foo == redeemer.bar
} }
} }
"#; "#;

View File

@ -225,6 +225,16 @@ fn infer_definition(
}); });
} }
if typed_fun.is_spend() && !typed_fun.arguments[0].tipo.is_option() {
return Err(Error::CouldNotUnify {
location: typed_fun.arguments[0].location,
expected: Type::option(typed_fun.arguments[0].tipo.clone()),
given: typed_fun.arguments[0].tipo.clone(),
situation: None,
rigid_type_names: Default::default(),
});
}
for arg in typed_fun.arguments.iter_mut() { for arg in typed_fun.arguments.iter_mut() {
if arg.tipo.is_unbound() { if arg.tipo.is_unbound() {
arg.tipo = Type::data(); arg.tipo = Type::data();