diff --git a/compiler/passes/src/type_checking/check_program.rs b/compiler/passes/src/type_checking/check_program.rs index 913b55647f..fd6935c1e9 100644 --- a/compiler/passes/src/type_checking/check_program.rs +++ b/compiler/passes/src/type_checking/check_program.rs @@ -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. @@ -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) { @@ -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) { diff --git a/compiler/passes/src/type_checking/checker.rs b/compiler/passes/src/type_checking/checker.rs index 7e4cc3a72f..ff24e68aad 100644 --- a/compiler/passes/src/type_checking/checker.rs +++ b/compiler/passes/src/type_checking/checker.rs @@ -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. diff --git a/errors/src/errors/type_checker/type_checker_error.rs b/errors/src/errors/type_checker/type_checker_error.rs index 5ff27a64a7..db2970685a 100644 --- a/errors/src/errors/type_checker/type_checker_error.rs +++ b/errors/src/errors/type_checker/type_checker_error.rs @@ -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, + } ); diff --git a/tests/expectations/compiler/futures/future_in_composite_fail.out b/tests/expectations/compiler/futures/future_in_composite_fail.out new file mode 100644 index 0000000000..9c531d1fd5 --- /dev/null +++ b/tests/expectations/compiler/futures/future_in_composite_fail.out @@ -0,0 +1,24 @@ +namespace = "Compile" +expectation = "Fail" +outputs = [""" +Error [ETYC0372114]: A struct cannot contain a future. + --> compiler-test:7:9 + | + 7 | member: Future, + | ^^^^^^ +Error [ETYC0372031]: A mapping's key cannot be a future + --> compiler-test:4:5 + | + 4 | mapping x: Future => Future; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error [ETYC0372031]: A mapping's value cannot be a future + --> compiler-test:4:5 + | + 4 | mapping x: Future => Future; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Error [ETYC0372115]: An array cannot have a future as an element type. + --> compiler-test:12:9 + | + 12 | let an_array: [Future; 1] = [future]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +"""] diff --git a/tests/tests/compiler/futures/future_in_composite_fail.leo b/tests/tests/compiler/futures/future_in_composite_fail.leo new file mode 100644 index 0000000000..3c18efa56d --- /dev/null +++ b/tests/tests/compiler/futures/future_in_composite_fail.leo @@ -0,0 +1,22 @@ +/* +namespace = "Compile" +expectation = "Fail" +*/ + +program test.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); + } +}