Skip to content

Commit

Permalink
Error on futures in arrays, structs, or mappings.
Browse files Browse the repository at this point in the history
This already wouldn't work, but would either give misleading
error messages or would compile to invalid bytecode.
  • Loading branch information
mikebenfield committed Nov 25, 2024
1 parent d9fe41a commit b97f484
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 2 deletions.
12 changes: 10 additions & 2 deletions compiler/passes/src/type_checking/check_program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,13 @@ impl<'a, N: Network> ProgramVisitor<'a> for TypeChecker<'a, N> {
if input.is_record { "record" } else { "struct" },
identifier.span,
));
} else if matches!(type_, Type::Future(..)) {
self.emit_err(TypeCheckerError::composite_data_type_cannot_contain_future(
if input.is_record { "record" } else { "struct" },
identifier.span,
));
}

// Ensure that there are no record members.
self.assert_member_is_not_record(identifier.span, input.identifier.name, type_);
// If the member is a struct, add it to the struct dependency graph.
Expand Down Expand Up @@ -194,8 +200,9 @@ impl<'a, N: Network> ProgramVisitor<'a> for TypeChecker<'a, N> {
fn visit_mapping(&mut self, input: &'a Mapping) {
// Check that a mapping's key type is valid.
self.assert_type_is_valid(&input.key_type, input.span);
// Check that a mapping's key type is not a tuple, record, or mapping.
// Check that a mapping's key type is not a future, tuple, record, or mapping.
match input.key_type.clone() {
Type::Future(_) => self.emit_err(TypeCheckerError::invalid_mapping_type("key", "future", input.span)),
Type::Tuple(_) => self.emit_err(TypeCheckerError::invalid_mapping_type("key", "tuple", input.span)),
Type::Composite(struct_type) => {
if let Some(struct_) = self.lookup_struct(struct_type.program, struct_type.id.name) {
Expand All @@ -211,8 +218,9 @@ impl<'a, N: Network> ProgramVisitor<'a> for TypeChecker<'a, N> {

// Check that a mapping's value type is valid.
self.assert_type_is_valid(&input.value_type, input.span);
// Check that a mapping's value type is not a tuple, record or mapping.
// Check that a mapping's value type is not a future, tuple, record or mapping.
match input.value_type.clone() {
Type::Future(_) => self.emit_err(TypeCheckerError::invalid_mapping_type("value", "future", input.span)),
Type::Tuple(_) => self.emit_err(TypeCheckerError::invalid_mapping_type("value", "tuple", input.span)),
Type::Composite(struct_type) => {
if let Some(struct_) = self.lookup_struct(struct_type.program, struct_type.id.name) {
Expand Down
2 changes: 2 additions & 0 deletions compiler/passes/src/type_checking/checker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1087,6 +1087,8 @@ impl<'a, N: Network> TypeChecker<'a, N> {
}
// Check that the array element type is valid.
match array_type.element_type() {
// Array elements cannot be futures.
Type::Future(_) => self.emit_err(TypeCheckerError::array_element_cannot_be_future(span)),
// Array elements cannot be tuples.
Type::Tuple(_) => self.emit_err(TypeCheckerError::array_element_cannot_be_tuple(span)),
// Array elements cannot be records.
Expand Down
14 changes: 14 additions & 0 deletions errors/src/errors/type_checker/type_checker_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -898,4 +898,18 @@ create_messages!(
msg: format!("Cannot define a function with no parameters."),
help: None,
}

@formatted
composite_data_type_cannot_contain_future {
args: (data_type: impl Display),
msg: format!("A {data_type} cannot contain a future."),
help: None,
}

@formatted
array_element_cannot_be_future {
args: (),
msg: format!("An array cannot have a future as an element type."),
help: None,
}
);
24 changes: 24 additions & 0 deletions tests/expectations/compiler/futures/future_in_composite_fail.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
namespace = "Compile"
expectation = "Fail"
outputs = ["""
Error [ETYC0372114]: A struct cannot contain a future.
--> compiler-test:9:9
|
9 | member: Future,
| ^^^^^^
Error [ETYC0372031]: A mapping's key cannot be a future
--> compiler-test:6:5
|
6 | mapping x: Future => Future;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Error [ETYC0372031]: A mapping's value cannot be a future
--> compiler-test:6:5
|
6 | mapping x: Future => Future;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Error [ETYC0372115]: An array cannot have a future as an element type.
--> compiler-test:14:9
|
14 | let an_array: [Future; 1] = [future];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
"""]
41 changes: 41 additions & 0 deletions tests/tests/compiler/futures/future_in_composite_fail.leo
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
namespace = "Compile"
expectation = "Fail"
*/
program credits.aleo {
record credits {
owner: address,
amount: u64,
}

async transition transfer_private_to_public(input: credits, addr: address, amount:u64) -> (credits, Future) {
let f: Future = finalize();
return (input, f);
}

async function finalize() {
assert_eq(1u8, 1u8);
}
}

// --- Next Program --- //

import credits.aleo;

program test_credits.aleo {
mapping x: Future => Future;

struct S {
member: Future,
}

async transition main() -> Future {
let future: Future = finish();
let an_array: [Future; 1] = [future];
return an_array[0u32];
}

async function finish() {
assert_eq(1u8, 1u8);
}
}

0 comments on commit b97f484

Please sign in to comment.