Merge pull request #28316 from ProvableHQ/fix/tuple-future

[Fix] Futures in Tuples
This commit is contained in:
d0cd 2024-08-13 08:28:30 -07:00 committed by GitHub
commit 4a7b062175
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 78 additions and 17 deletions

View File

@ -113,9 +113,11 @@ impl Type {
///
/// Returns `true` if the self `Type` is equal to the other `Type` in all aspects besides composite program of origin.
///
/// In the case of futures, it also makes sure that if both are not explicit, they are equal.
///
/// Flattens array syntax: `[[u8; 1]; 2] == [u8; (2, 1)] == true`
///
pub fn eq_flat_relax_composite(&self, other: &Self) -> bool {
pub fn eq_flat_relaxed(&self, other: &Self) -> bool {
match (self, other) {
(Type::Address, Type::Address)
| (Type::Boolean, Type::Boolean)
@ -126,18 +128,18 @@ impl Type {
| (Type::String, Type::String)
| (Type::Unit, Type::Unit) => true,
(Type::Array(left), Type::Array(right)) => {
left.element_type().eq_flat_relax_composite(right.element_type()) && left.length() == right.length()
left.element_type().eq_flat_relaxed(right.element_type()) && left.length() == right.length()
}
(Type::Identifier(left), Type::Identifier(right)) => left.matches(right),
(Type::Integer(left), Type::Integer(right)) => left.eq(right),
(Type::Mapping(left), Type::Mapping(right)) => {
left.key.eq_flat_relax_composite(&right.key) && left.value.eq_flat(&right.value)
left.key.eq_flat_relaxed(&right.key) && left.value.eq_flat_relaxed(&right.value)
}
(Type::Tuple(left), Type::Tuple(right)) if left.length() == right.length() => left
.elements()
.iter()
.zip_eq(right.elements().iter())
.all(|(left_type, right_type)| left_type.eq_flat_relax_composite(right_type)),
.all(|(left_type, right_type)| left_type.eq_flat_relaxed(right_type)),
(Type::Composite(left), Type::Composite(right)) => left.id.name == right.id.name,
// Don't type check when type hasn't been explicitly defined.
(Type::Future(left), Type::Future(right)) if !left.is_explicit || !right.is_explicit => true,
@ -145,7 +147,7 @@ impl Type {
.inputs()
.iter()
.zip_eq(right.inputs().iter())
.all(|(left_type, right_type)| left_type.eq_flat_relax_composite(right_type)),
.all(|(left_type, right_type)| left_type.eq_flat_relaxed(right_type)),
_ => false,
}
}

View File

@ -119,7 +119,7 @@ impl SymbolTable {
return false;
}
for (member1, member2) in new.members.iter().zip(old.members.iter()) {
if member1.name() != member2.name() || !member1.type_.eq_flat_relax_composite(&member2.type_) {
if member1.name() != member2.name() || !member1.type_.eq_flat_relaxed(&member2.type_) {
return false;
}
}

View File

@ -84,7 +84,7 @@ impl ExpressionReconstructor for Flattener<'_> {
};
// Note that type checking guarantees that both expressions have the same same type. This is a sanity check.
assert!(first_type.eq_flat_relax_composite(&second_type));
assert!(first_type.eq_flat_relaxed(&second_type));
match &first_type {
Type::Array(first_type) => self.ternary_array(first_type, &input.condition, &first, &second),

View File

@ -148,15 +148,9 @@ impl<'a, N: Network> ExpressionVisitor<'a> for TypeChecker<'a, N> {
} else {
// Lookup type of tuple index.
let actual = tuple.elements().get(index).expect("failed to get tuple index").clone();
// Emit error for mismatched types.
if let Some(expected) = expected {
// Emit error for mismatched types.
if !actual.eq_flat(expected) {
self.emit_err(TypeCheckerError::type_should_be(
&actual,
expected,
access.span(),
))
}
self.check_eq_types(&Some(actual.clone()), &Some(expected.clone()), access.span());
}
// Return type of tuple index.

View File

@ -143,7 +143,7 @@ impl<'a, N: Network> ProgramVisitor<'a> for TypeChecker<'a, N> {
|need, expected_ty: Type| match input.members.iter().find_map(|Member { identifier, type_, .. }| {
(identifier.name == need).then_some((identifier, type_))
}) {
Some((_, actual_ty)) if expected_ty.eq_flat(actual_ty) => {} // All good, found + right type!
Some((_, actual_ty)) if expected_ty.eq_flat_relaxed(actual_ty) => {} // All good, found + right type!
Some((field, _)) => {
self.emit_err(TypeCheckerError::record_var_wrong_type(field, expected_ty, input.span()));
}

View File

@ -174,7 +174,7 @@ impl<'a, N: Network> TypeChecker<'a, N> {
/// Emits an error if the two given types are not equal.
pub(crate) fn check_eq_types(&self, t1: &Option<Type>, t2: &Option<Type>, span: Span) {
match (t1, t2) {
(Some(t1), Some(t2)) if !Type::eq_flat_relax_composite(t1, t2) => {
(Some(t1), Some(t2)) if !Type::eq_flat_relaxed(t1, t2) => {
// If both types are futures, print them out.
if let (Type::Future(f1), Type::Future(f2)) = (t1, t2) {
println!("Future 1: {:?}", f1);

View File

@ -0,0 +1,31 @@
---
namespace: Compile
expectation: Pass
outputs:
- - compile:
- initial_symbol_table: e19a77f482bf38e20c7ecd69838dadb5e778a6a95c1de2eb56bddc42121b8940
type_checked_symbol_table: 33b1b5c2459bfa8d5c5b4b740965f4d59e09990037934364b94f1cb2e6316c2f
unrolled_symbol_table: 33b1b5c2459bfa8d5c5b4b740965f4d59e09990037934364b94f1cb2e6316c2f
initial_ast: 65074d34d89168f67b8db62c7b091b8c02e93aeda11f79c218c3761e270f8c09
unrolled_ast: 65074d34d89168f67b8db62c7b091b8c02e93aeda11f79c218c3761e270f8c09
ssa_ast: 3b05d816fbca67dce63e2f851a77f8ffa65930e3eb094c01647f05d251305632
flattened_ast: 6fa4c0335842d7ba9412438bbf35dcd75843107f14a25ebeb16b8a150bee11b7
destructured_ast: f21d1fc10d1ebd9a86273f17a20bd1cd1247c1ce1456f9ad252cb7c4f5bb10bb
inlined_ast: 3cb6765aec323b35119157dd2e3264aead6820169d79b182c256f499af1ff5a8
dce_ast: 3cb6765aec323b35119157dd2e3264aead6820169d79b182c256f499af1ff5a8
bytecode: 5650e018cca64d11f7a2eb88b57ed2f9fcc81a2b56856f983f660d34421dd82e
errors: ""
warnings: ""
- initial_symbol_table: fd67d75af194fb6d6fee5a2b15b4b51ae5511e5d0546c6c6f83063611a168123
type_checked_symbol_table: 031e9fc89b17624e259bb154ca42385665d2cf4349bf1579347a2d2487305a1b
unrolled_symbol_table: 031e9fc89b17624e259bb154ca42385665d2cf4349bf1579347a2d2487305a1b
initial_ast: fc9f1985c1e0441e9423e67cfd4cb8252178ccc236dfabae17187c5a5cc98ebe
unrolled_ast: c6fdd37447ee674a058e7fe314096c0df8cf0c02f307ff499e0f08b76cdc6709
ssa_ast: d26ea69b3993a2a3c4b2660a27706c51383f9b01357d27adf6275a5dfffe6e9d
flattened_ast: 5741efe1907a4da96fbad021b725a22e8c3365fa61b2413b06743c3ed01cda35
destructured_ast: 496bea9fd498c2d4ac9d93dd143beb403e13fdf59fc2ff842d8ff932883feda1
inlined_ast: 7c87cc964f8225fd91c634c8683ee0b09aaa301cb29ab85cadc4e4aea65253ba
dce_ast: 7c87cc964f8225fd91c634c8683ee0b09aaa301cb29ab85cadc4e4aea65253ba
bytecode: a3cec0fb931bb7be4c60ea116dec933b1587fc50f37efdd9a0816628889a2f68
errors: ""
warnings: ""

View File

@ -0,0 +1,34 @@
/*
namespace: Compile
expectation: Pass
*/
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 {
async transition send_credits(input: credits.aleo/credits, amount: u64) -> (credits.aleo/credits, Future) {
let result: (credits.aleo/credits, Future) = credits.aleo/transfer_private_to_public(input, self.address, amount);
return (result.0, finish(result.1));
}
async function finish(f: Future) {
f.await();
}
}