Skip to content

Commit

Permalink
Add check asserting that command is only used in finalize block
Browse files Browse the repository at this point in the history
  • Loading branch information
d0cd committed Jun 28, 2023
1 parent 652e1f4 commit 186b500
Show file tree
Hide file tree
Showing 6 changed files with 208 additions and 1 deletion.
170 changes: 170 additions & 0 deletions compiler/ast/src/functions/core_function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -561,4 +561,174 @@ impl CoreFunction {
Self::GroupToYCoordinate => 1,
}
}

/// Returns whether or not this function is finalize command.
pub fn is_finalize_command(&self) -> bool {
match self {
CoreFunction::ChaChaRandAddress
| CoreFunction::ChaChaRandBool
| CoreFunction::ChaChaRandField
| CoreFunction::ChaChaRandGroup
| CoreFunction::ChaChaRandI8
| CoreFunction::ChaChaRandI16
| CoreFunction::ChaChaRandI32
| CoreFunction::ChaChaRandI64
| CoreFunction::ChaChaRandI128
| CoreFunction::ChaChaRandU8
| CoreFunction::ChaChaRandU16
| CoreFunction::ChaChaRandU32
| CoreFunction::ChaChaRandU64
| CoreFunction::ChaChaRandU128
| CoreFunction::MappingGet
| CoreFunction::MappingGetOrUse
| CoreFunction::ChaChaRandScalar
| CoreFunction::MappingSet => true,
CoreFunction::BHP256CommitToAddress
| CoreFunction::BHP256CommitToField
| CoreFunction::BHP256CommitToGroup
| CoreFunction::BHP256HashToAddress
| CoreFunction::BHP256HashToField
| CoreFunction::BHP256HashToGroup
| CoreFunction::BHP256HashToI8
| CoreFunction::BHP256HashToI16
| CoreFunction::BHP256HashToI32
| CoreFunction::BHP256HashToI64
| CoreFunction::BHP256HashToI128
| CoreFunction::BHP256HashToU8
| CoreFunction::BHP256HashToU16
| CoreFunction::BHP256HashToU32
| CoreFunction::BHP256HashToU64
| CoreFunction::BHP256HashToU128
| CoreFunction::BHP256HashToScalar
| CoreFunction::BHP512CommitToAddress
| CoreFunction::BHP512CommitToField
| CoreFunction::BHP512CommitToGroup
| CoreFunction::BHP512HashToAddress
| CoreFunction::BHP512HashToField
| CoreFunction::BHP512HashToGroup
| CoreFunction::BHP512HashToI8
| CoreFunction::BHP512HashToI16
| CoreFunction::BHP512HashToI32
| CoreFunction::BHP512HashToI64
| CoreFunction::BHP512HashToI128
| CoreFunction::BHP512HashToU8
| CoreFunction::BHP512HashToU16
| CoreFunction::BHP512HashToU32
| CoreFunction::BHP512HashToU64
| CoreFunction::BHP512HashToU128
| CoreFunction::BHP512HashToScalar
| CoreFunction::BHP768CommitToAddress
| CoreFunction::BHP768CommitToField
| CoreFunction::BHP768CommitToGroup
| CoreFunction::BHP768HashToAddress
| CoreFunction::BHP768HashToField
| CoreFunction::BHP768HashToGroup
| CoreFunction::BHP768HashToI8
| CoreFunction::BHP768HashToI16
| CoreFunction::BHP768HashToI32
| CoreFunction::BHP768HashToI64
| CoreFunction::BHP768HashToI128
| CoreFunction::BHP768HashToU8
| CoreFunction::BHP768HashToU16
| CoreFunction::BHP768HashToU32
| CoreFunction::BHP768HashToU64
| CoreFunction::BHP768HashToU128
| CoreFunction::BHP768HashToScalar
| CoreFunction::BHP1024CommitToAddress
| CoreFunction::BHP1024CommitToField
| CoreFunction::BHP1024CommitToGroup
| CoreFunction::BHP1024HashToAddress
| CoreFunction::BHP1024HashToField
| CoreFunction::BHP1024HashToGroup
| CoreFunction::BHP1024HashToI8
| CoreFunction::BHP1024HashToI16
| CoreFunction::BHP1024HashToI32
| CoreFunction::BHP1024HashToI64
| CoreFunction::BHP1024HashToI128
| CoreFunction::BHP1024HashToU8
| CoreFunction::BHP1024HashToU16
| CoreFunction::BHP1024HashToU32
| CoreFunction::BHP1024HashToU64
| CoreFunction::BHP1024HashToU128
| CoreFunction::BHP1024HashToScalar
| CoreFunction::Pedersen64CommitToAddress
| CoreFunction::Pedersen64CommitToField
| CoreFunction::Pedersen64CommitToGroup
| CoreFunction::Pedersen64HashToAddress
| CoreFunction::Pedersen64HashToField
| CoreFunction::Pedersen64HashToGroup
| CoreFunction::Pedersen64HashToI8
| CoreFunction::Pedersen64HashToI16
| CoreFunction::Pedersen64HashToI32
| CoreFunction::Pedersen64HashToI64
| CoreFunction::Pedersen64HashToI128
| CoreFunction::Pedersen64HashToU8
| CoreFunction::Pedersen64HashToU16
| CoreFunction::Pedersen64HashToU32
| CoreFunction::Pedersen64HashToU64
| CoreFunction::Pedersen64HashToU128
| CoreFunction::Pedersen64HashToScalar
| CoreFunction::Pedersen128CommitToAddress
| CoreFunction::Pedersen128CommitToField
| CoreFunction::Pedersen128CommitToGroup
| CoreFunction::Pedersen128HashToAddress
| CoreFunction::Pedersen128HashToField
| CoreFunction::Pedersen128HashToGroup
| CoreFunction::Pedersen128HashToI8
| CoreFunction::Pedersen128HashToI16
| CoreFunction::Pedersen128HashToI32
| CoreFunction::Pedersen128HashToI64
| CoreFunction::Pedersen128HashToI128
| CoreFunction::Pedersen128HashToU8
| CoreFunction::Pedersen128HashToU16
| CoreFunction::Pedersen128HashToU32
| CoreFunction::Pedersen128HashToU64
| CoreFunction::Pedersen128HashToU128
| CoreFunction::Pedersen128HashToScalar
| CoreFunction::Poseidon2HashToAddress
| CoreFunction::Poseidon2HashToField
| CoreFunction::Poseidon2HashToGroup
| CoreFunction::Poseidon2HashToI8
| CoreFunction::Poseidon2HashToI16
| CoreFunction::Poseidon2HashToI32
| CoreFunction::Poseidon2HashToI64
| CoreFunction::Poseidon2HashToI128
| CoreFunction::Poseidon2HashToU8
| CoreFunction::Poseidon2HashToU16
| CoreFunction::Poseidon2HashToU32
| CoreFunction::Poseidon2HashToU64
| CoreFunction::Poseidon2HashToU128
| CoreFunction::Poseidon2HashToScalar
| CoreFunction::Poseidon4HashToAddress
| CoreFunction::Poseidon4HashToField
| CoreFunction::Poseidon4HashToGroup
| CoreFunction::Poseidon4HashToI8
| CoreFunction::Poseidon4HashToI16
| CoreFunction::Poseidon4HashToI32
| CoreFunction::Poseidon4HashToI64
| CoreFunction::Poseidon4HashToI128
| CoreFunction::Poseidon4HashToU8
| CoreFunction::Poseidon4HashToU16
| CoreFunction::Poseidon4HashToU32
| CoreFunction::Poseidon4HashToU64
| CoreFunction::Poseidon4HashToU128
| CoreFunction::Poseidon4HashToScalar
| CoreFunction::Poseidon8HashToAddress
| CoreFunction::Poseidon8HashToField
| CoreFunction::Poseidon8HashToGroup
| CoreFunction::Poseidon8HashToI8
| CoreFunction::Poseidon8HashToI16
| CoreFunction::Poseidon8HashToI32
| CoreFunction::Poseidon8HashToI64
| CoreFunction::Poseidon8HashToI128
| CoreFunction::Poseidon8HashToU8
| CoreFunction::Poseidon8HashToU16
| CoreFunction::Poseidon8HashToU32
| CoreFunction::Poseidon8HashToU64
| CoreFunction::Poseidon8HashToU128
| CoreFunction::Poseidon8HashToScalar
| CoreFunction::GroupToXCoordinate
| CoreFunction::GroupToYCoordinate => false,
}
}
}
6 changes: 6 additions & 0 deletions compiler/passes/src/type_checking/check_expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
AccessExpression::AssociatedFunction(access) => {
// Check core struct name and function.
if let Some(core_instruction) = self.get_core_function_call(&access.ty, &access.name) {
// Check that operation is not restricted to finalize blocks.
if !self.is_finalize && core_instruction.is_finalize_command() {
self.emit_err(TypeCheckerError::operation_must_be_in_finalize_block(input.span()));
}

// Get the types of the arguments.
let argument_types = access
.arguments
Expand All @@ -59,6 +64,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
if let Some(expected) = expected {
self.assert_type(&return_type, expected, input.span());
}

return return_type;
} else {
self.emit_err(TypeCheckerError::invalid_core_function_call(access, access.span()));
Expand Down
7 changes: 7 additions & 0 deletions errors/src/errors/type_checker/type_checker_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -635,4 +635,11 @@ create_messages!(
msg: format!("`{operation}` is not a valid operand in a finalize context."),
help: None,
}

@formatted
operation_must_be_in_finalize_block {
args: (),
msg: format!("This operation can only be used in a `finalize` block."),
help: None,
}
);
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
namespace: Compile
expectation: Fail
outputs:
- "Error [ETYC0372035]: `Mapping::set` must be inside a finalize block.\n --> compiler-test:8:9\n |\n 8 | Mapping::set(values, 0u8, 1u8);\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nError [ETYC0372035]: `Mapping::get_or` must be inside a finalize block.\n --> compiler-test:9:9\n |\n 9 | Mapping::get_or_use(account, self.caller, 1u64);\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nError [ETYC0372035]: `Mapping::get` must be inside a finalize block.\n --> compiler-test:10:9\n |\n 10 | Mapping::get(values, 1u8);\n | ^^^^^^^^^^^^^^^^^^^^^^^^^\nError [ETYC0372035]: `Mapping::set` must be inside a finalize block.\n --> compiler-test:14:9\n |\n 14 | Mapping::set(values, 0u8, 1u8);\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nError [ETYC0372035]: `Mapping::get_or` must be inside a finalize block.\n --> compiler-test:15:9\n |\n 15 | Mapping::get_or_use(account, self.caller, 1u64);\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nError [ETYC0372035]: `Mapping::get` must be inside a finalize block.\n --> compiler-test:16:9\n |\n 16 | Mapping::get(values, 0u8);\n | ^^^^^^^^^^^^^^^^^^^^^^^^^\nError [ETYC0372044]: Function must contain a `finalize` statement on all execution paths.\n --> compiler-test:13:5\n |\n 13 | inline bar() {\n 14 | Mapping::set(values, 0u8, 1u8);\n 15 | Mapping::get_or_use(account, self.caller, 1u64);\n 16 | Mapping::get(values, 0u8);\n 17 | }\n | ^\nError [ETYC0372031]: Only transition functions can have a `finalize` block.\n --> compiler-test:19:5\n |\n 19 | finalize finalize_no_params() {\n 20 | foo();\n 21 | bar();\n 22 | }\n | ^\n |\n = Remove the `finalize` block or use the keyword `transition` instead of `function`.\nError [ETYC0372045]: `finalize` name `bar` does not match function name `finalize_no_params`\n --> compiler-test:19:5\n |\n 19 | finalize finalize_no_params() {\n 20 | foo();\n 21 | bar();\n 22 | }\n | ^\nError [ETYC0372066]: Cyclic dependency between functions: `bar` --> `bar`\n"
- "Error [ETYC0372077]: This operation can only be used in a `finalize` block.\n --> compiler-test:8:9\n |\n 8 | Mapping::set(values, 0u8, 1u8);\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nError [ETYC0372035]: `Mapping::set` must be inside a finalize block.\n --> compiler-test:8:9\n |\n 8 | Mapping::set(values, 0u8, 1u8);\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nError [ETYC0372077]: This operation can only be used in a `finalize` block.\n --> compiler-test:9:9\n |\n 9 | Mapping::get_or_use(account, self.caller, 1u64);\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nError [ETYC0372035]: `Mapping::get_or` must be inside a finalize block.\n --> compiler-test:9:9\n |\n 9 | Mapping::get_or_use(account, self.caller, 1u64);\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nError [ETYC0372077]: This operation can only be used in a `finalize` block.\n --> compiler-test:10:9\n |\n 10 | Mapping::get(values, 1u8);\n | ^^^^^^^^^^^^^^^^^^^^^^^^^\nError [ETYC0372035]: `Mapping::get` must be inside a finalize block.\n --> compiler-test:10:9\n |\n 10 | Mapping::get(values, 1u8);\n | ^^^^^^^^^^^^^^^^^^^^^^^^^\nError [ETYC0372077]: This operation can only be used in a `finalize` block.\n --> compiler-test:14:9\n |\n 14 | Mapping::set(values, 0u8, 1u8);\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nError [ETYC0372035]: `Mapping::set` must be inside a finalize block.\n --> compiler-test:14:9\n |\n 14 | Mapping::set(values, 0u8, 1u8);\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nError [ETYC0372077]: This operation can only be used in a `finalize` block.\n --> compiler-test:15:9\n |\n 15 | Mapping::get_or_use(account, self.caller, 1u64);\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nError [ETYC0372035]: `Mapping::get_or` must be inside a finalize block.\n --> compiler-test:15:9\n |\n 15 | Mapping::get_or_use(account, self.caller, 1u64);\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nError [ETYC0372077]: This operation can only be used in a `finalize` block.\n --> compiler-test:16:9\n |\n 16 | Mapping::get(values, 0u8);\n | ^^^^^^^^^^^^^^^^^^^^^^^^^\nError [ETYC0372035]: `Mapping::get` must be inside a finalize block.\n --> compiler-test:16:9\n |\n 16 | Mapping::get(values, 0u8);\n | ^^^^^^^^^^^^^^^^^^^^^^^^^\nError [ETYC0372044]: Function must contain a `finalize` statement on all execution paths.\n --> compiler-test:13:5\n |\n 13 | inline bar() {\n 14 | Mapping::set(values, 0u8, 1u8);\n 15 | Mapping::get_or_use(account, self.caller, 1u64);\n 16 | Mapping::get(values, 0u8);\n 17 | }\n | ^\nError [ETYC0372031]: Only transition functions can have a `finalize` block.\n --> compiler-test:19:5\n |\n 19 | finalize finalize_no_params() {\n 20 | foo();\n 21 | bar();\n 22 | }\n | ^\n |\n = Remove the `finalize` block or use the keyword `transition` instead of `function`.\nError [ETYC0372045]: `finalize` name `bar` does not match function name `finalize_no_params`\n --> compiler-test:19:5\n |\n 19 | finalize finalize_no_params() {\n 20 | foo();\n 21 | bar();\n 22 | }\n | ^\nError [ETYC0372066]: Cyclic dependency between functions: `bar` --> `bar`\n"
5 changes: 5 additions & 0 deletions tests/expectations/compiler/finalize/rand_not_in_finalize.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
namespace: Compile
expectation: Fail
outputs:
- "Error [ETYC0372077]: This operation can only be used in a `finalize` block.\n --> compiler-test:8:25\n |\n 8 | let a: scalar = ChaCha::rand_scalar();\n | ^^^^^^^^^^^^^^^^^^^^^\n"
19 changes: 19 additions & 0 deletions tests/tests/compiler/finalize/rand_not_in_finalize.leo
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
namespace: Compile
expectation: Fail
*/

program test.aleo {

mapping values: scalar => group;

transition foo() {
let a: scalar = ChaCha::rand_scalar();
return then finalize(a);
}

finalize foo(a: scalar) {
let b: group = ChaCha::rand_group();
values.set(a, b);
}
}

0 comments on commit 186b500

Please sign in to comment.