diff --git a/compiler/passes/src/code_generation/visit_program.rs b/compiler/passes/src/code_generation/visit_program.rs index e0409f0393..7e7f07c807 100644 --- a/compiler/passes/src/code_generation/visit_program.rs +++ b/compiler/passes/src/code_generation/visit_program.rs @@ -292,13 +292,12 @@ impl<'a> CodeGenerator<'a> { // Note that this unwrap is safe since all struct and records have been added to the composite mapping. let (is_record, _) = self.composite_mapping.get(&identifier.name).unwrap(); match is_record { - // If the type is a record, then declare the type as is. // If the type is a struct, then add the public modifier. - false => format!("{identifier}.public"), + false => self.visit_type_with_visibility(type_, Mode::Public), true => unreachable!("Type checking guarantees that mappings cannot contain records."), } } - type_ => format!("{type_}.public"), + type_ => self.visit_type_with_visibility(type_, Mode::Public), } }; diff --git a/compiler/passes/src/flattening/flatten_expression.rs b/compiler/passes/src/flattening/flatten_expression.rs index 3a26a3cdbc..ef37593980 100644 --- a/compiler/passes/src/flattening/flatten_expression.rs +++ b/compiler/passes/src/flattening/flatten_expression.rs @@ -73,25 +73,26 @@ impl ExpressionReconstructor for Flattener<'_> { match (*input.if_true, *input.if_false) { // If both expressions are identifiers which are arrays, construct ternary expressions for each of the members and an array expression for the result. (Expression::Identifier(first), Expression::Identifier(second)) => { - match (self.type_table.get(&first.id()), self.type_table.get(&second.id())) { - (Some(Type::Array(first_type)), Some(Type::Array(second_type))) => { - // Note that type checking guarantees that both expressions have the same same type. This is a sanity check. - assert_eq!(first_type, second_type); - self.ternary_array(&first_type, &input.condition, &first, &second) - } - (Some(Type::Identifier(first_type)), Some(Type::Identifier(second_type))) => { + let first_type = match self.type_table.get(&first.id()) { + Some(first_type) => first_type, + _ => unreachable!("Type checking guarantees that all expressions are typed."), + }; + let second_type = match self.type_table.get(&second.id()) { + Some(second_type) => second_type, + _ => unreachable!("Type checking guarantees that all expressions are typed."), + }; + + // Note that type checking guarantees that both expressions have the same same type. This is a sanity check. + assert!(first_type.eq_flat(&second_type)); + + match &first_type { + Type::Array(first_type) => self.ternary_array(&first_type, &input.condition, &first, &second), + Type::Identifier(first_type) => { // Get the struct definitions. let first_type = self.symbol_table.lookup_struct(first_type.name).unwrap(); - let second_type = self.symbol_table.lookup_struct(second_type.name).unwrap(); - // Note that type checking guarantees that both expressions have the same same type. This is a sanity check. - assert_eq!(first_type, second_type); - self.ternary_struct(first_type, &input.condition, &first, &second) - } - (Some(Type::Tuple(first_type)), Some(Type::Tuple(second_type))) => { - // Note that type checking guarantees that both expressions have the same same type. This is a sanity check. - assert_eq!(first_type, second_type); - self.ternary_tuple(&first_type, &input.condition, &first, &second) + self.ternary_struct(&first_type, &input.condition, &first, &second) } + Type::Tuple(first_type) => self.ternary_tuple(&first_type, &input.condition, &first, &second), _ => { // Reconstruct the true case. let (if_true, stmts) = self.reconstruct_expression(Expression::Identifier(first)); @@ -117,9 +118,7 @@ impl ExpressionReconstructor for Flattener<'_> { } } } - (expr1, expr2) => { - println!("expr1: {:?}", expr1); - println!("expr2: {:?}", expr2); + _ => { unreachable!("SSA guarantees that the subexpressions of a ternary expression are identifiers.") } } diff --git a/compiler/passes/src/static_single_assignment/rename_expression.rs b/compiler/passes/src/static_single_assignment/rename_expression.rs index 984eaf2d0f..ef0ac09492 100644 --- a/compiler/passes/src/static_single_assignment/rename_expression.rs +++ b/compiler/passes/src/static_single_assignment/rename_expression.rs @@ -18,6 +18,7 @@ use crate::StaticSingleAssigner; use leo_ast::{ AccessExpression, + ArrayAccess, ArrayExpression, AssociatedFunction, BinaryExpression, @@ -101,6 +102,19 @@ impl ExpressionConsumer for StaticSingleAssigner<'_> { statements, ) } + AccessExpression::Array(input) => { + let (array, statements) = self.consume_expression(*input.array); + + ( + AccessExpression::Array(ArrayAccess { + array: Box::new(array), + index: input.index, + span: input.span, + id: input.id, + }), + statements, + ) + } expr => (expr, Vec::new()), }; let (place, statement) = self.unique_simple_assign_statement(Expression::Access(expr)); diff --git a/compiler/passes/src/type_checking/check_expressions.rs b/compiler/passes/src/type_checking/check_expressions.rs index 8c2bedae4a..9fbcac688f 100644 --- a/compiler/passes/src/type_checking/check_expressions.rs +++ b/compiler/passes/src/type_checking/check_expressions.rs @@ -555,7 +555,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> { // Assert right type is a magnitude (u8, u16, u32). self.assert_magnitude_type(&t2, input.right.span()); - return_incorrect_type(t1, t2, destination) + t1 } } } diff --git a/tests/expectations/compiler/array/array_in_composite_data_types.out b/tests/expectations/compiler/array/array_in_composite_data_types.out index 095aa49b8e..322f75a8b3 100644 --- a/tests/expectations/compiler/array/array_in_composite_data_types.out +++ b/tests/expectations/compiler/array/array_in_composite_data_types.out @@ -7,10 +7,10 @@ outputs: unrolled_symbol_table: ada5f23ac25bb1d9459045c27095fce0e36e746d84ca57cd7499c322773aa334 initial_ast: efb843c1ad9ab3c9702e6a7371a6d82ee7cee6a9373cb50f6dfc2a73e7de5336 unrolled_ast: efb843c1ad9ab3c9702e6a7371a6d82ee7cee6a9373cb50f6dfc2a73e7de5336 - ssa_ast: 3ce96d3ff2764de26ca950390ed39d4ef11257f7c254ea4b9843f99f75607f6f - flattened_ast: b204db3b8936f01d4d8c157ceda34c5de887d622b5c4cce307dba772e2f9fa31 - destructured_ast: b4f45fe4b1d71e31f8e2b6354a8c7239ecdb6129e40b81c634e1e75ac0cc70e3 - inlined_ast: b4f45fe4b1d71e31f8e2b6354a8c7239ecdb6129e40b81c634e1e75ac0cc70e3 - dce_ast: b4f45fe4b1d71e31f8e2b6354a8c7239ecdb6129e40b81c634e1e75ac0cc70e3 + ssa_ast: 23b7fcac156b953db56e1c45fc27570a2156499fd9b7f6e77ceb04f33fc99fac + flattened_ast: 0be4a04e516edc0a6729fcd364cb393ccf181d9c21e24aa57c284ff87763686f + destructured_ast: 9df17c7ff4d181afd738c449f79119bcbb10519b07441fb45dcb6d0b93c8f80d + inlined_ast: 9df17c7ff4d181afd738c449f79119bcbb10519b07441fb45dcb6d0b93c8f80d + dce_ast: 9df17c7ff4d181afd738c449f79119bcbb10519b07441fb45dcb6d0b93c8f80d bytecode: a3539a0515c22f4ec653aa601063d7a414db833dc25273cee463985b052b72bc warnings: "" diff --git a/tests/expectations/compiler/array/array_in_mapping.out b/tests/expectations/compiler/array/array_in_mapping.out new file mode 100644 index 0000000000..cb3e67ca5b --- /dev/null +++ b/tests/expectations/compiler/array/array_in_mapping.out @@ -0,0 +1,16 @@ +--- +namespace: Compile +expectation: Pass +outputs: + - - initial_symbol_table: 002a658ff3a2db38eb21e316458d2473313bbe50f2b4a7cd4aa6e04444c2ed3c + type_checked_symbol_table: e6cbe752fa16e7a820685d02f654c97c2ccf509f7bb3287ea7060017bda0a139 + unrolled_symbol_table: e6cbe752fa16e7a820685d02f654c97c2ccf509f7bb3287ea7060017bda0a139 + initial_ast: 6eefbb8a62e5c5b798129574876dee19ee0e3b75de9337f539a3a005b18ea1f7 + unrolled_ast: 6eefbb8a62e5c5b798129574876dee19ee0e3b75de9337f539a3a005b18ea1f7 + ssa_ast: 6eefbb8a62e5c5b798129574876dee19ee0e3b75de9337f539a3a005b18ea1f7 + flattened_ast: 2f4a5e927ab19fb770caabe0c4a3ceda8d765d4303c59ad1a0c8350cecd8a9fd + destructured_ast: 1dc62a6fcfea66fe2a10e3a5584057ab22f8b737252efb2902778b1c651fcd8f + inlined_ast: 1dc62a6fcfea66fe2a10e3a5584057ab22f8b737252efb2902778b1c651fcd8f + dce_ast: 1dc62a6fcfea66fe2a10e3a5584057ab22f8b737252efb2902778b1c651fcd8f + bytecode: b39b7b375dab7194cd24f4f2dde6f8c4c13e6a25b9107af52fddb45df9e3435f + warnings: "" diff --git a/tests/expectations/compiler/array/array_write_fail.out b/tests/expectations/compiler/array/array_write_fail.out new file mode 100644 index 0000000000..3f3c803150 --- /dev/null +++ b/tests/expectations/compiler/array/array_write_fail.out @@ -0,0 +1,5 @@ +--- +namespace: Compile +expectation: Fail +outputs: + - "Error [ETYC0372000]: invalid assignment target\n --> compiler-test:5:9\n |\n 5 | a[0u32] = false;\n | ^^^^^^^\nError [ETYC0372000]: invalid assignment target\n --> compiler-test:6:9\n |\n 6 | a[1u32] = true;\n | ^^^^^^^\n" diff --git a/tests/expectations/compiler/array/nested_array_sum_fail.out b/tests/expectations/compiler/array/nested_array_sum_fail.out new file mode 100644 index 0000000000..88b037296d --- /dev/null +++ b/tests/expectations/compiler/array/nested_array_sum_fail.out @@ -0,0 +1,5 @@ +--- +namespace: Compile +expectation: Fail +outputs: + - "Error [ETYC0372007]: Expected one type from `array`, but got `u32`\n --> compiler-test:9:29\n |\n 9 | sum = sum + a[i][j];\n | ^^^^\nError [ETYC0372003]: Expected type `u32` but type `no type` was found\n --> compiler-test:9:23\n |\n 9 | sum = sum + a[i][j];\n | ^^^^^^^^^^^^^\n" diff --git a/tests/expectations/compiler/expression/ternary.out b/tests/expectations/compiler/expression/ternary.out new file mode 100644 index 0000000000..2c437ecf29 --- /dev/null +++ b/tests/expectations/compiler/expression/ternary.out @@ -0,0 +1,16 @@ +--- +namespace: Compile +expectation: Pass +outputs: + - - initial_symbol_table: 03511070212594f877945470becbe3258d1dbc7c5673adb0d2fa56fc7b9d52ae + type_checked_symbol_table: 9a9deaa022f73e57c24c8336dffa974f8cddb35e9b81c5b383571a37d2531bf2 + unrolled_symbol_table: 9a9deaa022f73e57c24c8336dffa974f8cddb35e9b81c5b383571a37d2531bf2 + initial_ast: 12e8c9a76387f6e9b54a59010089629f2f3c0736c56da880208280e86611e3fb + unrolled_ast: 12e8c9a76387f6e9b54a59010089629f2f3c0736c56da880208280e86611e3fb + ssa_ast: eb96cfc44c8d578ec0cf3172f2e794e36c0052aab90eeef12f8ec7c8f8922758 + flattened_ast: 9f508e380ec0e1c97854f3101a18b33de757b26cb241c07995f7ad387544ea7c + destructured_ast: 621c185f09c1cffc1ac757e55ced700b67068c08837c58dc9462dcdc5605faa7 + inlined_ast: 621c185f09c1cffc1ac757e55ced700b67068c08837c58dc9462dcdc5605faa7 + dce_ast: 621c185f09c1cffc1ac757e55ced700b67068c08837c58dc9462dcdc5605faa7 + bytecode: 11706f359e35f6269b2f879e483f2e1dc1df99c710fc8476dfb1e3c6115d8268 + warnings: "" diff --git a/tests/expectations/compiler/function/flatten_arrays.out b/tests/expectations/compiler/function/flatten_arrays.out new file mode 100644 index 0000000000..87587aef81 --- /dev/null +++ b/tests/expectations/compiler/function/flatten_arrays.out @@ -0,0 +1,16 @@ +--- +namespace: Compile +expectation: Pass +outputs: + - - initial_symbol_table: db965bbea0fe710347e590189a11c632e67356d6eb3dcff1ee3746f59abada67 + type_checked_symbol_table: 7388f185d6d4bf6f50baf94b543d24759c53a72ebe46a730911eb7c13b429970 + unrolled_symbol_table: 7388f185d6d4bf6f50baf94b543d24759c53a72ebe46a730911eb7c13b429970 + initial_ast: 89e5ca97a429005c3b5c6fdd40756114ed302961d90fc8109c25218613dbe305 + unrolled_ast: 89e5ca97a429005c3b5c6fdd40756114ed302961d90fc8109c25218613dbe305 + ssa_ast: daa92399cb5b70a35693c15d2f3a59ae0f75a9203c7be55ddb12a083adeeb2c4 + flattened_ast: cf3dd007fa44453a99893d32369678eaa8bdce11ebe676fd5383fe726f5b2f39 + destructured_ast: 12970e30a633c72202544f4d9fcdd174a63d0cd52595a7cb499b92baf1da028f + inlined_ast: 12970e30a633c72202544f4d9fcdd174a63d0cd52595a7cb499b92baf1da028f + dce_ast: 12970e30a633c72202544f4d9fcdd174a63d0cd52595a7cb499b92baf1da028f + bytecode: 789b22bc0c6e954ae7fed24a064342bf0729393fab7e8d8206b0923f53240dd1 + warnings: "" diff --git a/tests/tests/compiler/array/array_in_mapping.leo b/tests/tests/compiler/array/array_in_mapping.leo new file mode 100644 index 0000000000..43fce814e2 --- /dev/null +++ b/tests/tests/compiler/array/array_in_mapping.leo @@ -0,0 +1,16 @@ +/* +namespace: Compile +expectation: Pass +*/ + +program test.aleo { + mapping data: address => [bool; 8]; + + transition foo(a: [bool; 8]) { + return then finalize(self.caller, a); + } + + finalize foo(caller: address, a: [bool; 8]) { + data.set(caller, a); + } +} diff --git a/tests/tests/compiler/array/array_write_fail.leo b/tests/tests/compiler/array/array_write_fail.leo new file mode 100644 index 0000000000..bdef62b730 --- /dev/null +++ b/tests/tests/compiler/array/array_write_fail.leo @@ -0,0 +1,12 @@ +/* +namespace: Compile +expectation: Fail +*/ + +program test.aleo { + transition foo(a: [bool; 8]) -> [bool; 8] { + a[0u32] = false; + a[1u32] = true; + return a; + } +} diff --git a/tests/tests/compiler/array/nested_array_sum_fail.leo b/tests/tests/compiler/array/nested_array_sum_fail.leo new file mode 100644 index 0000000000..b476326602 --- /dev/null +++ b/tests/tests/compiler/array/nested_array_sum_fail.leo @@ -0,0 +1,16 @@ +/* +namespace: Compile +expectation: Fail +*/ + + +program test.aleo { + transition foo(a: [u32; 4]) { + let sum: u32 = 0u32; + for i: u32 in 0u32..4u32 { + for j: u32 in 0u32..4u32 { + sum = sum + a[i][j]; + } + } + } +} diff --git a/tests/tests/compiler/expression/ternary.leo b/tests/tests/compiler/expression/ternary.leo new file mode 100644 index 0000000000..bb3e73e425 --- /dev/null +++ b/tests/tests/compiler/expression/ternary.leo @@ -0,0 +1,28 @@ +/* +namespace: Compile +expectation: Pass +*/ + +program test.aleo { + transition main( + a: address, b: bool, c: field, d: i8, e: i16, f: i64, g: i128, h: u8, i: u16, j: u32, k: u64, l: u128, m: scalar, n: i32 + ) -> ( + address, bool, field, i8, i16, i64, i128, u8, u16, u32, u64, u128, scalar, i32 + ) { + let one: address = b ? a : a; + let two: bool = b ? b : b; + let three: field = b ? c : c; + let four: i8 = b ? d : d; + let five: i16 = b ? e : e; + let six: i64 = b ? f : f; + let seven: i128 = b ? g : g; + let eight: u8 = b ? h : h; + let nine: u16 = b ? i : i; + let ten: u32 = b ? j : j; + let eleven: u64 = b ? k : k; + let twelve: u128 = b ? l : l; + let thirteen: scalar = b ? m : m; + let fourteen: i32 = b ? n : n; + return (one, two, three, four, five, six, seven, eight, nine, ten, eleven, twelve, thirteen, fourteen); + } +} diff --git a/tests/tests/compiler/function/flatten_arrays.leo b/tests/tests/compiler/function/flatten_arrays.leo new file mode 100644 index 0000000000..f7f3361567 --- /dev/null +++ b/tests/tests/compiler/function/flatten_arrays.leo @@ -0,0 +1,37 @@ +/* +namespace: Compile +expectation: Pass +*/ + +program test.aleo { + + struct Data { + data: [u8; 2], + } + + function foo(a: u8, b: u8) -> [Data; 2] { + let data_1: Data = Data { data: [a, b] }; + let data_2: Data = Data { data: [b, a] }; + if (a == b) { + return [data_1, data_2]; + } + + let data_3: Data = Data { data: [2u8 * data_1.data[0u8], 4u8 * data_2.data[1u8]] }; + + return [data_2, data_3]; + } + + transition bar(flag1: bool, flag2: bool, a: u8, b: u8) -> [Data; 2] { + let start: [Data; 2] = foo(a, b); + if flag1 { + start = foo(start[0u8].data[0u8], start[1u8].data[1u8]); + } else { + if flag2 { + start = foo(start[1u8].data[0u8], start[0u8].data[1u8]); + } else { + start = foo(start[0u8].data[1u8], start[1u8].data[0u8]); + } + } + return start; + } +}