Skip to content

Commit

Permalink
Handle closures that are invalid for Aleo.
Browse files Browse the repository at this point in the history
In particular,

1. Insert a dummy instruction for empty closures
and finalizers. SnarkVM won't parse these with no instructions.

2. Give an error for Leo functions with
no parameters (rather than just generating
an invalid Aleo closure).

Fixes #28401
  • Loading branch information
mikebenfield committed Oct 23, 2024
1 parent 0cda2c2 commit 0a5a698
Show file tree
Hide file tree
Showing 57 changed files with 145 additions and 93 deletions.
8 changes: 8 additions & 0 deletions compiler/passes/src/code_generation/visit_program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,14 @@ impl<'a> CodeGenerator<'a> {

// Construct and append the function body.
let block_string = self.visit_block(&function.block);
if matches!(self.variant.unwrap(), Variant::Function | Variant::AsyncFunction)
&& block_string.lines().all(|line| line.starts_with(" output "))
{
// There are no real instructions, which is invalid in Aleo, so
// add a dummy instruction.
function_string.push_str(" assert.eq true true;\n");
}

function_string.push_str(&block_string);

function_string
Expand Down
9 changes: 4 additions & 5 deletions compiler/passes/src/type_checking/check_program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,11 +263,6 @@ impl<'a, N: Network> ProgramVisitor<'a> for TypeChecker<'a, N> {
self.check_function_signature(function);

if self.scope_state.variant == Some(Variant::AsyncFunction) {
// Async functions cannot have empty blocks
if function.block.statements.is_empty() {
self.emit_err(TypeCheckerError::finalize_block_must_not_be_empty(function.block.span));
}

// Initialize the list of input futures. Each one must be awaited before the end of the function.
self.await_checker.set_futures(
function
Expand All @@ -280,6 +275,10 @@ impl<'a, N: Network> ProgramVisitor<'a> for TypeChecker<'a, N> {
);
}

if function.variant == Variant::Function && function.input.is_empty() {
self.emit_err(TypeCheckerError::empty_function_arglist(function.span));
}

self.visit_block(&function.block);

// If the function has a return type, then check that it has a return.
Expand Down
2 changes: 1 addition & 1 deletion errors/src/errors/parser/parser_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ create_messages!(
}

/// For when the parser encountered a mix of commas and semi-colons in struct member variables.
// TODO unused
// TODO This error is unused. Remove it in a future version.
@formatted
mixed_commas_and_semicolons {
args: (),
Expand Down
8 changes: 8 additions & 0 deletions errors/src/errors/type_checker/type_checker_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,7 @@ create_messages!(
help: None,
}

// TODO This error is unused. Remove it in a future version.
@formatted
finalize_block_must_not_be_empty {
args: (),
Expand Down Expand Up @@ -886,4 +887,11 @@ create_messages!(
msg: "A struct must have at least one member.".to_string(),
help: None,
}

@formatted
empty_function_arglist {
args: (),
msg: format!("Cannot define a function with no parameters."),
help: None,
}
);
16 changes: 16 additions & 0 deletions tests/expectations/compiler/finalize/empty_finalize.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace = "Compile"
expectation = "Pass"
outputs = [[{ compile = [{ initial_symbol_table = "1594125e96833cb52afcad4c876e44d61b2944a6c146e019b23fa0ad5d39db2a", type_checked_symbol_table = "95d8ce7541440d2568f633e1b7800d3d5d06e1147642eec802bfca4a9115e61c", unrolled_symbol_table = "95d8ce7541440d2568f633e1b7800d3d5d06e1147642eec802bfca4a9115e61c", initial_ast = "45d32cf0414a246717747dc917b07ffe55ff7587589d4c494479e18667e61a03", unrolled_ast = "45d32cf0414a246717747dc917b07ffe55ff7587589d4c494479e18667e61a03", ssa_ast = "eb6eff57864e407c245edbba3ab2949a2536643b3b864a8a42b65c348523a31f", flattened_ast = "6e8cc40e042029b3124b7b9a7e66905525207fb6cf0bfe5b71abfecbf10d7c72", destructured_ast = "22c2d4f79894ead71296929de2982b8289e2b43f7d83dc497a1be4532945ea17", inlined_ast = "e18c2f95e617c4c42c2359ea8a09924311f89c0c3a0bfa1e2ffe23c6ff933846", dce_ast = "e18c2f95e617c4c42c2359ea8a09924311f89c0c3a0bfa1e2ffe23c6ff933846", bytecode = """
program test.aleo;

function mint_public:
input r0 as address.public;
input r1 as u64.public;
async mint_public r0 r1 into r2;
output r2 as test.aleo/mint_public.future;

finalize mint_public:
input r0 as address.public;
input r1 as u64.public;
assert.eq true true;
""", errors = "", warnings = "" }] }]]
9 changes: 0 additions & 9 deletions tests/expectations/compiler/finalize/empty_finalize_fail.out

This file was deleted.

18 changes: 18 additions & 0 deletions tests/expectations/compiler/function/empty_arglist_fail.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
namespace = "Compile"
expectation = "Fail"
outputs = ["""
Error [ETYC0372113]: Cannot define a function with no parameters.
--> compiler-test:4:5
|
4 | function x() -> u8 {
5 | return 0u8;
6 | }
| ^
Error [ETYC0372083]: A program must have at least one transition function.
--> compiler-test:1:1
|
1 |
2 |
3 | program test.aleo {
| ^^^^^^^^^^^^
"""]
15 changes: 15 additions & 0 deletions tests/expectations/compiler/function/empty_function.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace = "Compile"
expectation = "Pass"
outputs = [[{ compile = [{ initial_symbol_table = "4ccc1709fb6b2aad9ee9a247bb37098d9330087d64e14af2a5c064287f701105", type_checked_symbol_table = "979420a8fc4bfbc81aeabe709704af919277f62699a09b0858c37544622a725a", unrolled_symbol_table = "979420a8fc4bfbc81aeabe709704af919277f62699a09b0858c37544622a725a", initial_ast = "52950f91033f987381d1b9a5ff69b626a8911d003da7edb503e97bd6e6637d2c", unrolled_ast = "52950f91033f987381d1b9a5ff69b626a8911d003da7edb503e97bd6e6637d2c", ssa_ast = "5314cb0ebd490a53c7ded487668632260992a4f49a10f1e247980b5c6647ad22", flattened_ast = "85fd8c8ed0cae4cd4b711d8d909d5aec0a176028fa91452fae92fbe5f6091f63", destructured_ast = "fc6b028060914573cc2c1885155f4f2bb5c90ed03caf720bff4d5b05eb299327", inlined_ast = "6b8711898970669f70badb94f5ce2abd87be07fbb764523dd2d9e6d94336e7cd", dce_ast = "6b8711898970669f70badb94f5ce2abd87be07fbb764523dd2d9e6d94336e7cd", bytecode = """
program test.aleo;

closure x:
input r0 as boolean;
assert.eq true true;
output 0u8 as u8;

function t:
input r0 as boolean.private;
call x r0 into r1;
output r1 as u8.private;
""", errors = "", warnings = "" }] }]]
6 changes: 3 additions & 3 deletions tests/expectations/compiler/tuple/tuple_not_allowed_fail.out
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ Error [ETYC0372051]: A function cannot take in a tuple as input.
8 | function foo(a: (u8, u16)) -> (u8, u16) {
| ^
Error [ETYC0372049]: A tuple type cannot contain a tuple.
--> compiler-test:12:28
--> compiler-test:12:36
|
12 | function bar() -> (u8, (u16, u32)) {
| ^^^^^^^^^^
12 | function bar(zz: bool) -> (u8, (u16, u32)) {
| ^^^^^^^^^^
Error [ETYC0372052]: A tuple expression cannot contain another tuple expression.
--> compiler-test:13:22
|
Expand Down
22 changes: 0 additions & 22 deletions tests/expectations/parser/functions/empty2.out

This file was deleted.

2 changes: 1 addition & 1 deletion tests/tests/compiler/core/algorithms/pedersen_fail.leo
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ expectation = "Fail"
*/

program test.aleo {
function main() -> bool {
function main(zz: bool) -> bool {
let a: group = Pedersen64::hash_to_field(1u128); // Pedersen64 hash_to_field returns a field type

return true;
Expand Down
2 changes: 1 addition & 1 deletion tests/tests/compiler/field/no_space_between_literal.leo
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ expectation = "Fail"
*/

program test.aleo {
function main() {
function main(x: bool) {
let f = 1 field;
}}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
namespace = "Compile"
expectation = "Fail"
expectation = "Pass"
*/

program test.aleo {
Expand Down
10 changes: 10 additions & 0 deletions tests/tests/compiler/function/empty_arglist_fail.leo
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*
namespace = "Compile"
expectation = "Fail"
*/

program test.aleo {
function x() -> u8 {
return 0u8;
}
}
16 changes: 16 additions & 0 deletions tests/tests/compiler/function/empty_function.leo
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
namespace = "Compile"
expectation = "Pass"
*/

program test.aleo {
// This should pass and insert
// a dummy instruction into the empty function.
function x(a: bool) -> u8 {
return 0u8;
}

transition t(a: bool) -> u8 {
return x(a);
}
}
2 changes: 1 addition & 1 deletion tests/tests/compiler/function/undefined_fail.leo
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ expectation = "Fail"
*/

program test.aleo {
function main() -> u8 {
function main(zz: bool) -> u8 {
my_function();
return 0u8;
}
Expand Down
2 changes: 1 addition & 1 deletion tests/tests/compiler/group/no_space_between_literal.leo
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ expectation = "Fail"
*/

program test.aleo {
function main() -> group {
function main(x: bool) -> group {
let g: group = (0,1) group;
return g;
}}
2 changes: 1 addition & 1 deletion tests/tests/compiler/integers/i128/max_fail.leo
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ expectation = "Fail"
*/

program test.aleo {
function main() {
function main(x: bool) {
let a: i128 = 170141183460469231731687303715884105728i128;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ expectation = "Fail"
*/

program test.aleo {
function main() {
function main(x: bool) {
let i = 1 i128;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ expectation = "Fail"
*/

program test.aleo {
function main() {
function main(x: bool) {
let i = 1 i16;
}
}
2 changes: 1 addition & 1 deletion tests/tests/compiler/integers/i32/max_fail.leo
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ expectation = "Fail"
*/

program test.aleo {
function main() {
function main(x: bool) {
let a: i32 = 2147483648i32;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ expectation = "Fail"
*/

program test.aleo {
function main() {
function main(x: bool) {
let i = 1 i32;
}
}
2 changes: 1 addition & 1 deletion tests/tests/compiler/integers/i64/max_fail.leo
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ expectation = "Fail"
*/

program test.aleo {
function main() {
function main(x: bool) {
let a: i64 = 9223372036854775808i64;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ expectation = "Fail"
*/

program test.aleo {
function main() {
function main(x: bool) {
let i = 1 i64;
}
}
2 changes: 1 addition & 1 deletion tests/tests/compiler/integers/i8/max_fail.leo
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ expectation = "Fail"
*/

program test.aleo {
function main() {
function main(x: bool) {
let a: i8 = 128i8;
}}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ expectation = "Fail"
*/

program test.aleo {
function main() {
function main(x: bool) {
let i = 1 i8;
}
}
2 changes: 1 addition & 1 deletion tests/tests/compiler/integers/u128/hex_min_fail.leo
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ expectation = "Fail"
*/

program test.aleo {
function main() {
function main(x: bool) {
let a: u128 = -0x1u128;
}
}
2 changes: 1 addition & 1 deletion tests/tests/compiler/integers/u128/max_fail.leo
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ expectation = "Fail"
*/

program test.aleo {
function main() {
function main(x: bool) {
let a: u128 = 340282366920938463463374607431768211456u128;
}
}
2 changes: 1 addition & 1 deletion tests/tests/compiler/integers/u128/min_fail.leo
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ expectation = "Fail"
*/

program test.aleo {
function main() {
function main(x: bool) {
let a: u128 = -1u128;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ expectation = "Fail"
*/

program test.aleo {
function main() {
function main(x: bool) {
let i = 1 u128;
}
}
2 changes: 1 addition & 1 deletion tests/tests/compiler/integers/u16/hex_min_fail.leo
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ expectation = "Fail"
*/

program test.aleo {
function main() {
function main(x: bool) {
let a: u16 = -0x1u16;
}
}
2 changes: 1 addition & 1 deletion tests/tests/compiler/integers/u16/max_fail.leo
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ expectation = "Fail"
*/

program test.aleo {
function main() {
function main(x: bool) {
let a: u16 = 65536u16;
}
}
2 changes: 1 addition & 1 deletion tests/tests/compiler/integers/u16/min_fail.leo
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ expectation = "Fail"
*/

program test.aleo {
function main() {
function main(x: bool) {
let a: u16 = -1u16;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ expectation = "Fail"
*/

program test.aleo {
function main() {
function main(x: bool) {
let i = 1 u16;
}
}
2 changes: 1 addition & 1 deletion tests/tests/compiler/integers/u32/hex_min_fail.leo
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ expectation = "Fail"
*/

program test.aleo {
function main() {
function main(x: bool) {
let a: u32 = -0x1u32;
}
}
Loading

0 comments on commit 0a5a698

Please sign in to comment.