| author | |
| committer | |
| log | 65157d30ab90de01da583dd97ee2409d8ad8aeb0 |
| tree | 0c9767c8c174bfd55fd0d9c5525d4ddef1ec7ceb |
| parent | 77b8bf2b82ffa71fc8ecf85f6780130f27dbeaf3 |
| signature |
Implements the ptr_elem_val air tag. Implementation is unified
with ptr_elem_ptr.21 files changed, 36 insertions(+), 41 deletions(-)
src/codegen/spirv.zig+36-12| ... | @@ -1765,6 +1765,7 @@ pub const DeclGen = struct { | ... | @@ -1765,6 +1765,7 @@ pub const DeclGen = struct { |
| 1765 | .slice_elem_ptr => try self.airSliceElemPtr(inst), | 1765 | .slice_elem_ptr => try self.airSliceElemPtr(inst), |
| 1766 | .slice_elem_val => try self.airSliceElemVal(inst), | 1766 | .slice_elem_val => try self.airSliceElemVal(inst), |
| 1767 | .ptr_elem_ptr => try self.airPtrElemPtr(inst), | 1767 | .ptr_elem_ptr => try self.airPtrElemPtr(inst), |
| 1768 | .ptr_elem_val => try self.airPtrElemVal(inst), | ||
| 1768 | 1769 | ||
| 1769 | .struct_field_val => try self.airStructFieldVal(inst), | 1770 | .struct_field_val => try self.airStructFieldVal(inst), |
| 1770 | 1771 | ||
| ... | @@ -2482,29 +2483,52 @@ pub const DeclGen = struct { | ... | @@ -2482,29 +2483,52 @@ pub const DeclGen = struct { |
| 2482 | return try self.load(slice_ty, elem_ptr); | 2483 | return try self.load(slice_ty, elem_ptr); |
| 2483 | } | 2484 | } |
| 2484 | 2485 | ||
| 2486 | fn ptrElemPtr(self: *DeclGen, ptr_ty: Type, ptr_id: IdRef, index_id: IdRef) !IdRef { | ||
| 2487 | // Construct new pointer type for the resulting pointer | ||
| 2488 | const elem_ty = ptr_ty.elemType2(); // use elemType() so that we get T for *[N]T. | ||
| 2489 | const elem_ty_ref = try self.resolveType(elem_ty, .direct); | ||
| 2490 | const elem_ptr_ty_ref = try self.spv.ptrType(elem_ty_ref, spvStorageClass(ptr_ty.ptrAddressSpace()), 0); | ||
| 2491 | if (ptr_ty.isSinglePointer()) { | ||
| 2492 | // Pointer-to-array. In this case, the resulting pointer is not of the same type | ||
| 2493 | // as the ptr_ty (we want a *T, not a *[N]T), and hence we need to use accessChain. | ||
| 2494 | return try self.accessChain(elem_ptr_ty_ref, ptr_id, &.{index_id}); | ||
| 2495 | } else { | ||
| 2496 | // Resulting pointer type is the same as the ptr_ty, so use ptrAccessChain | ||
| 2497 | return try self.ptrAccessChain(elem_ptr_ty_ref, ptr_id, index_id, &.{}); | ||
| 2498 | } | ||
| 2499 | } | ||
| 2500 | |||
| 2485 | fn airPtrElemPtr(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | 2501 | fn airPtrElemPtr(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 2486 | if (self.liveness.isUnused(inst)) return null; | 2502 | if (self.liveness.isUnused(inst)) return null; |
| 2487 | 2503 | ||
| 2488 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 2504 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 2489 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | 2505 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2490 | const ptr_ty = self.air.typeOf(bin_op.lhs); | 2506 | const ptr_ty = self.air.typeOf(bin_op.lhs); |
| 2491 | const result_ty = self.air.typeOfIndex(inst); | ||
| 2492 | const elem_ty = ptr_ty.childType(); | 2507 | const elem_ty = ptr_ty.childType(); |
| 2493 | // TODO: Make this return a null ptr or something | 2508 | // TODO: Make this return a null ptr or something |
| 2494 | if (!elem_ty.hasRuntimeBitsIgnoreComptime()) return null; | 2509 | if (!elem_ty.hasRuntimeBitsIgnoreComptime()) return null; |
| 2495 | 2510 | ||
| 2496 | const result_ty_ref = try self.resolveType(result_ty, .direct); | 2511 | const ptr_id = try self.resolve(bin_op.lhs); |
| 2497 | const base_ptr = try self.resolve(bin_op.lhs); | 2512 | const index_id = try self.resolve(bin_op.rhs); |
| 2498 | const rhs = try self.resolve(bin_op.rhs); | 2513 | return try self.ptrElemPtr(ptr_ty, ptr_id, index_id); |
| 2514 | } | ||
| 2499 | 2515 | ||
| 2500 | if (ptr_ty.isSinglePointer()) { | 2516 | fn airPtrElemVal(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
| 2501 | // Pointer-to-array. In this case, the resulting pointer is not of the same type | 2517 | const bin_op = self.air.instructions.items(.data)[inst].bin_op; |
| 2502 | // as the ptr_ty, and hence we need to use accessChain. | 2518 | const ptr_ty = self.air.typeOf(bin_op.lhs); |
| 2503 | return try self.accessChain(result_ty_ref, base_ptr, &.{rhs}); | 2519 | const ptr_id = try self.resolve(bin_op.lhs); |
| 2504 | } else { | 2520 | const index_id = try self.resolve(bin_op.rhs); |
| 2505 | // Resulting pointer type is the same as the ptr_ty, so use ptrAccessChain | 2521 | |
| 2506 | return try self.ptrAccessChain(result_ty_ref, base_ptr, rhs, &.{}); | 2522 | const elem_ptr_id = try self.ptrElemPtr(ptr_ty, ptr_id, index_id); |
| 2507 | } | 2523 | |
| 2524 | // If we have a pointer-to-array, construct an element pointer to use with load() | ||
| 2525 | // If we pass ptr_ty directly, it will attempt to load the entire array rather than | ||
| 2526 | // just an element. | ||
| 2527 | var elem_ptr_info = ptr_ty.ptrInfo(); | ||
| 2528 | elem_ptr_info.data.size = .One; | ||
| 2529 | const elem_ptr_ty = Type.initPayload(&elem_ptr_info.base); | ||
| 2530 | |||
| 2531 | return try self.load(elem_ptr_ty, elem_ptr_id); | ||
| 2508 | } | 2532 | } |
| 2509 | 2533 | ||
| 2510 | fn airStructFieldVal(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { | 2534 | fn airStructFieldVal(self: *DeclGen, inst: Air.Inst.Index) !?IdRef { |
test/behavior/align.zig-2| ... | @@ -215,8 +215,6 @@ test "alignment and size of structs with 128-bit fields" { | ... | @@ -215,8 +215,6 @@ test "alignment and size of structs with 128-bit fields" { |
| 215 | } | 215 | } |
| 216 | 216 | ||
| 217 | test "@ptrCast preserves alignment of bigger source" { | 217 | test "@ptrCast preserves alignment of bigger source" { |
| 218 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 219 | |||
| 220 | var x: u32 align(16) = 1234; | 218 | var x: u32 align(16) = 1234; |
| 221 | const ptr = @ptrCast(*u8, &x); | 219 | const ptr = @ptrCast(*u8, &x); |
| 222 | try expect(@TypeOf(ptr) == *align(16) u8); | 220 | try expect(@TypeOf(ptr) == *align(16) u8); |
test/behavior/call.zig-2| ... | @@ -385,8 +385,6 @@ test "generic function with generic function parameter" { | ... | @@ -385,8 +385,6 @@ test "generic function with generic function parameter" { |
| 385 | } | 385 | } |
| 386 | 386 | ||
| 387 | test "recursive inline call with comptime known argument" { | 387 | test "recursive inline call with comptime known argument" { |
| 388 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 389 | |||
| 390 | const S = struct { | 388 | const S = struct { |
| 391 | inline fn foo(x: i32) i32 { | 389 | inline fn foo(x: i32) i32 { |
| 392 | if (x <= 0) { | 390 | if (x <= 0) { |
test/behavior/cast.zig-1| ... | @@ -322,7 +322,6 @@ test "peer result null and comptime_int" { | ... | @@ -322,7 +322,6 @@ test "peer result null and comptime_int" { |
| 322 | test "*const ?[*]const T to [*c]const [*c]const T" { | 322 | test "*const ?[*]const T to [*c]const [*c]const T" { |
| 323 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 323 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 324 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 324 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 325 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 326 | 325 | ||
| 327 | var array = [_]u8{ 'o', 'k' }; | 326 | var array = [_]u8{ 'o', 'k' }; |
| 328 | const opt_array_ptr: ?[*]const u8 = &array; | 327 | const opt_array_ptr: ?[*]const u8 = &array; |
test/behavior/error.zig-1| ... | @@ -22,7 +22,6 @@ test "error values" { | ... | @@ -22,7 +22,6 @@ test "error values" { |
| 22 | } | 22 | } |
| 23 | 23 | ||
| 24 | test "redefinition of error values allowed" { | 24 | test "redefinition of error values allowed" { |
| 25 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 26 | shouldBeNotEqual(error.AnError, error.SecondError); | 25 | shouldBeNotEqual(error.AnError, error.SecondError); |
| 27 | } | 26 | } |
| 28 | fn shouldBeNotEqual(a: anyerror, b: anyerror) void { | 27 | fn shouldBeNotEqual(a: anyerror, b: anyerror) void { |
test/behavior/eval.zig-2| ... | @@ -47,8 +47,6 @@ test "inline variable gets result of const if" { | ... | @@ -47,8 +47,6 @@ test "inline variable gets result of const if" { |
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | test "static function evaluation" { | 49 | test "static function evaluation" { |
| 50 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 51 | |||
| 52 | try expect(statically_added_number == 3); | 50 | try expect(statically_added_number == 3); |
| 53 | } | 51 | } |
| 54 | const statically_added_number = staticAdd(1, 2); | 52 | const statically_added_number = staticAdd(1, 2); |
test/behavior/floatop.zig-1| ... | @@ -620,7 +620,6 @@ test "@floor" { | ... | @@ -620,7 +620,6 @@ test "@floor" { |
| 620 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 620 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 621 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 621 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 622 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 622 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 623 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 624 | 623 | ||
| 625 | comptime try testFloor(); | 624 | comptime try testFloor(); |
| 626 | try testFloor(); | 625 | try testFloor(); |
test/behavior/fn.zig-2| ... | @@ -12,8 +12,6 @@ fn testParamsAdd(a: i32, b: i32) i32 { | ... | @@ -12,8 +12,6 @@ fn testParamsAdd(a: i32, b: i32) i32 { |
| 12 | } | 12 | } |
| 13 | 13 | ||
| 14 | test "local variables" { | 14 | test "local variables" { |
| 15 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 16 | |||
| 17 | testLocVars(2); | 15 | testLocVars(2); |
| 18 | } | 16 | } |
| 19 | fn testLocVars(b: i32) void { | 17 | fn testLocVars(b: i32) void { |
test/behavior/for.zig-2| ... | @@ -39,8 +39,6 @@ fn testBreakOuter() !void { | ... | @@ -39,8 +39,6 @@ fn testBreakOuter() !void { |
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | test "continue outer for loop" { | 41 | test "continue outer for loop" { |
| 42 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 43 | |||
| 44 | try testContinueOuter(); | 42 | try testContinueOuter(); |
| 45 | comptime try testContinueOuter(); | 43 | comptime try testContinueOuter(); |
| 46 | } | 44 | } |
test/behavior/generics.zig-1| ... | @@ -19,7 +19,6 @@ fn checkSize(comptime T: type) usize { | ... | @@ -19,7 +19,6 @@ fn checkSize(comptime T: type) usize { |
| 19 | test "simple generic fn" { | 19 | test "simple generic fn" { |
| 20 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 20 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 21 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 21 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 22 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 23 | 22 | ||
| 24 | try expect(max(i32, 3, -1) == 3); | 23 | try expect(max(i32, 3, -1) == 3); |
| 25 | try expect(max(u8, 1, 100) == 100); | 24 | try expect(max(u8, 1, 100) == 100); |
test/behavior/optional.zig-1| ... | @@ -421,7 +421,6 @@ test "optional of noreturn used with orelse" { | ... | @@ -421,7 +421,6 @@ test "optional of noreturn used with orelse" { |
| 421 | } | 421 | } |
| 422 | 422 | ||
| 423 | test "orelse on C pointer" { | 423 | test "orelse on C pointer" { |
| 424 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 425 | 424 | ||
| 426 | // TODO https://github.com/ziglang/zig/issues/6597 | 425 | // TODO https://github.com/ziglang/zig/issues/6597 |
| 427 | const foo: [*c]const u8 = "hey"; | 426 | const foo: [*c]const u8 = "hey"; |
test/behavior/packed-struct.zig-1| ... | @@ -93,7 +93,6 @@ test "flags in packed structs" { | ... | @@ -93,7 +93,6 @@ test "flags in packed structs" { |
| 93 | 93 | ||
| 94 | test "consistent size of packed structs" { | 94 | test "consistent size of packed structs" { |
| 95 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 95 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 96 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 97 | 96 | ||
| 98 | const TxData1 = packed struct { data: u8, _23: u23, full: bool = false }; | 97 | const TxData1 = packed struct { data: u8, _23: u23, full: bool = false }; |
| 99 | const TxData2 = packed struct { data: u9, _22: u22, full: bool = false }; | 98 | const TxData2 = packed struct { data: u9, _22: u22, full: bool = false }; |
test/behavior/pointers.zig-2| ... | @@ -19,7 +19,6 @@ fn testDerefPtr() !void { | ... | @@ -19,7 +19,6 @@ fn testDerefPtr() !void { |
| 19 | test "pointer arithmetic" { | 19 | test "pointer arithmetic" { |
| 20 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 20 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 21 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 21 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 22 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 23 | 22 | ||
| 24 | var ptr: [*]const u8 = "abcd"; | 23 | var ptr: [*]const u8 = "abcd"; |
| 25 | 24 | ||
| ... | @@ -300,7 +299,6 @@ test "null terminated pointer" { | ... | @@ -300,7 +299,6 @@ test "null terminated pointer" { |
| 300 | test "allow any sentinel" { | 299 | test "allow any sentinel" { |
| 301 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 300 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 302 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 301 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 303 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 304 | 302 | ||
| 305 | const S = struct { | 303 | const S = struct { |
| 306 | fn doTheTest() !void { | 304 | fn doTheTest() !void { |
test/behavior/sizeof_and_typeof.zig-1| ... | @@ -154,7 +154,6 @@ test "@TypeOf() has no runtime side effects" { | ... | @@ -154,7 +154,6 @@ test "@TypeOf() has no runtime side effects" { |
| 154 | 154 | ||
| 155 | test "branching logic inside @TypeOf" { | 155 | test "branching logic inside @TypeOf" { |
| 156 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 156 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 157 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 158 | 157 | ||
| 159 | const S = struct { | 158 | const S = struct { |
| 160 | var data: i32 = 0; | 159 | var data: i32 = 0; |
test/behavior/slice.zig-1| ... | @@ -672,7 +672,6 @@ test "array mult of slice gives ptr to array" { | ... | @@ -672,7 +672,6 @@ test "array mult of slice gives ptr to array" { |
| 672 | 672 | ||
| 673 | test "slice bounds in comptime concatenation" { | 673 | test "slice bounds in comptime concatenation" { |
| 674 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 674 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 675 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 676 | 675 | ||
| 677 | const bs = comptime blk: { | 676 | const bs = comptime blk: { |
| 678 | const b = "........1........"; | 677 | const b = "........1........"; |
test/behavior/struct.zig-2| ... | @@ -121,8 +121,6 @@ test "struct byval assign" { | ... | @@ -121,8 +121,6 @@ test "struct byval assign" { |
| 121 | } | 121 | } |
| 122 | 122 | ||
| 123 | test "call struct static method" { | 123 | test "call struct static method" { |
| 124 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 125 | |||
| 126 | const result = StructWithNoFields.add(3, 4); | 124 | const result = StructWithNoFields.add(3, 4); |
| 127 | try expect(result == 7); | 125 | try expect(result == 7); |
| 128 | } | 126 | } |
test/behavior/switch.zig-2| ... | @@ -348,8 +348,6 @@ fn returnsFalse() bool { | ... | @@ -348,8 +348,6 @@ fn returnsFalse() bool { |
| 348 | } | 348 | } |
| 349 | } | 349 | } |
| 350 | test "switch on const enum with var" { | 350 | test "switch on const enum with var" { |
| 351 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 352 | |||
| 353 | try expect(!returnsFalse()); | 351 | try expect(!returnsFalse()); |
| 354 | } | 352 | } |
| 355 | 353 |
test/behavior/threadlocal.zig-1| ... | @@ -46,7 +46,6 @@ test "reference a global threadlocal variable" { | ... | @@ -46,7 +46,6 @@ test "reference a global threadlocal variable" { |
| 46 | else => return error.SkipZigTest, | 46 | else => return error.SkipZigTest, |
| 47 | }; // TODO | 47 | }; // TODO |
| 48 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 48 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 49 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 50 | 49 | ||
| 51 | _ = nrfx_uart_rx(&g_uart0); | 50 | _ = nrfx_uart_rx(&g_uart0); |
| 52 | } | 51 | } |
test/behavior/type_info.zig-1| ... | @@ -512,7 +512,6 @@ test "type info for async frames" { | ... | @@ -512,7 +512,6 @@ test "type info for async frames" { |
| 512 | 512 | ||
| 513 | test "Declarations are returned in declaration order" { | 513 | test "Declarations are returned in declaration order" { |
| 514 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 514 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 515 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 516 | 515 | ||
| 517 | const S = struct { | 516 | const S = struct { |
| 518 | const a = 1; | 517 | const a = 1; |
test/behavior/var_args.zig-1| ... | @@ -30,7 +30,6 @@ test "send void arg to var args" { | ... | @@ -30,7 +30,6 @@ test "send void arg to var args" { |
| 30 | test "pass args directly" { | 30 | test "pass args directly" { |
| 31 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 31 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 32 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 32 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 33 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 34 | 33 | ||
| 35 | try expect(addSomeStuff(.{ @as(i32, 1), @as(i32, 2), @as(i32, 3), @as(i32, 4) }) == 10); | 34 | try expect(addSomeStuff(.{ @as(i32, 1), @as(i32, 2), @as(i32, 3), @as(i32, 4) }) == 10); |
| 36 | try expect(addSomeStuff(.{@as(i32, 1234)}) == 1234); | 35 | try expect(addSomeStuff(.{@as(i32, 1234)}) == 1234); |
test/behavior/while.zig-2| ... | @@ -38,8 +38,6 @@ fn staticWhileLoop2() i32 { | ... | @@ -38,8 +38,6 @@ fn staticWhileLoop2() i32 { |
| 38 | } | 38 | } |
| 39 | 39 | ||
| 40 | test "while with continue expression" { | 40 | test "while with continue expression" { |
| 41 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; | ||
| 42 | |||
| 43 | var sum: i32 = 0; | 41 | var sum: i32 = 0; |
| 44 | { | 42 | { |
| 45 | var i: i32 = 0; | 43 | var i: i32 = 0; |