authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-05-25 22:23:32-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-05-25 22:33:48-07:00
log83f69af971723d3a0774deb9dfda4b3fcbf0006f
treeba516b2bdd17b1492c6764dd1cc6bbd198cea853
parentb82081e7092a6198e6f8c65524a5829e2e08527b

stage2: implement runtime array multiplication

Additionally: * Sema: fix array cat/mul not setting the sentinel value - This required an LLVM backend enhancement to the handling of the AIR instruction aggregate_init that likely needs to be propagated to the other backends. * Sema: report integer overflow of array concatenation in a proper compile error instead of crashing. * Sema: fix not using proper pointer address space for array cat/mul

4 files changed, 236 insertions(+), 93 deletions(-)

src/Air.zig+2
...@@ -609,6 +609,8 @@ pub const Inst = struct {...@@ -609,6 +609,8 @@ pub const Inst = struct {
609 /// Some of the elements may be comptime-known.609 /// Some of the elements may be comptime-known.
610 /// Uses the `ty_pl` field, payload is index of an array of elements, each of which610 /// Uses the `ty_pl` field, payload is index of an array of elements, each of which
611 /// is a `Ref`. Length of the array is given by the vector type.611 /// is a `Ref`. Length of the array is given by the vector type.
612 /// If the type is an array with a sentinel, the AIR elements do not include it
613 /// explicitly.
612 aggregate_init,614 aggregate_init,
613615
614 /// Constructs a union from a field index and a runtime-known init value.616 /// Constructs a union from a field index and a runtime-known init value.
src/Sema.zig+126-72
...@@ -9264,10 +9264,8 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -9264,10 +9264,8 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
9264 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };9264 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
9265 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };9265 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
92669266
9267 const lhs_info = (try sema.getArrayCatInfo(block, lhs_src, lhs)) orelse9267 const lhs_info = try sema.getArrayCatInfo(block, lhs_src, lhs);
9268 return sema.fail(block, lhs_src, "expected array, found '{}'", .{lhs_ty.fmt(sema.mod)});9268 const rhs_info = try sema.getArrayCatInfo(block, rhs_src, rhs);
9269 const rhs_info = (try sema.getArrayCatInfo(block, rhs_src, rhs)) orelse
9270 return sema.fail(block, rhs_src, "expected array, found '{}'", .{rhs_ty.fmt(sema.mod)});
92719269
9272 const resolved_elem_ty = t: {9270 const resolved_elem_ty = t: {
9273 var trash_block = block.makeSubBlock();9271 var trash_block = block.makeSubBlock();
...@@ -9319,9 +9317,21 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -9319,9 +9317,21 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
93199317
9320 const lhs_len = try sema.usizeCast(block, lhs_src, lhs_info.len);9318 const lhs_len = try sema.usizeCast(block, lhs_src, lhs_info.len);
9321 const rhs_len = try sema.usizeCast(block, lhs_src, rhs_info.len);9319 const rhs_len = try sema.usizeCast(block, lhs_src, rhs_info.len);
9322 const result_len = lhs_len + rhs_len;9320 const result_len = std.math.add(usize, lhs_len, rhs_len) catch |err| switch (err) {
9321 error.Overflow => return sema.fail(
9322 block,
9323 src,
9324 "concatenating arrays of length {d} and {d} produces an array too large for this compiler implementation to handle",
9325 .{ lhs_len, rhs_len },
9326 ),
9327 };
9328
9323 const result_ty = try Type.array(sema.arena, result_len, res_sent_val, resolved_elem_ty, sema.mod);9329 const result_ty = try Type.array(sema.arena, result_len, res_sent_val, resolved_elem_ty, sema.mod);
9324 const is_ref = lhs_ty.zigTypeTag() == .Pointer or rhs_ty.zigTypeTag() == .Pointer;9330 const ptr_addrspace = p: {
9331 if (lhs_ty.zigTypeTag() == .Pointer) break :p lhs_ty.ptrAddressSpace();
9332 if (rhs_ty.zigTypeTag() == .Pointer) break :p rhs_ty.ptrAddressSpace();
9333 break :p null;
9334 };
93259335
9326 const runtime_src = if (try sema.resolveDefinedValue(block, lhs_src, lhs)) |lhs_val| rs: {9336 const runtime_src = if (try sema.resolveDefinedValue(block, lhs_src, lhs)) |lhs_val| rs: {
9327 if (try sema.resolveDefinedValue(block, rhs_src, rhs)) |rhs_val| {9337 if (try sema.resolveDefinedValue(block, rhs_src, rhs)) |rhs_val| {
...@@ -9348,22 +9358,21 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -9348,22 +9358,21 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
9348 element_vals[result_len] = sent_val;9358 element_vals[result_len] = sent_val;
9349 }9359 }
9350 const val = try Value.Tag.aggregate.create(sema.arena, element_vals);9360 const val = try Value.Tag.aggregate.create(sema.arena, element_vals);
9351 return sema.addConstantMaybeRef(block, src, result_ty, val, is_ref);9361 return sema.addConstantMaybeRef(block, src, result_ty, val, ptr_addrspace != null);
9352 } else break :rs rhs_src;9362 } else break :rs rhs_src;
9353 } else lhs_src;9363 } else lhs_src;
93549364
9355 try sema.requireRuntimeBlock(block, runtime_src);9365 try sema.requireRuntimeBlock(block, runtime_src);
93569366
9357 if (is_ref) {9367 if (ptr_addrspace) |ptr_as| {
9358 const target = sema.mod.getTarget();
9359 const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{9368 const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{
9360 .pointee_type = result_ty,9369 .pointee_type = result_ty,
9361 .@"addrspace" = target_util.defaultAddressSpace(target, .local),9370 .@"addrspace" = ptr_as,
9362 });9371 });
9363 const alloc = try block.addTy(.alloc, alloc_ty);9372 const alloc = try block.addTy(.alloc, alloc_ty);
9364 const elem_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{9373 const elem_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
9365 .pointee_type = resolved_elem_ty,9374 .pointee_type = resolved_elem_ty,
9366 .@"addrspace" = target_util.defaultAddressSpace(target, .local),9375 .@"addrspace" = ptr_as,
9367 });9376 });
93689377
9369 var elem_i: usize = 0;9378 var elem_i: usize = 0;
...@@ -9380,6 +9389,12 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -9380,6 +9389,12 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
9380 const init = try sema.elemVal(block, rhs_src, rhs, rhs_index, src);9389 const init = try sema.elemVal(block, rhs_src, rhs, rhs_index, src);
9381 try sema.storePtr2(block, src, elem_ptr, src, init, rhs_src, .store);9390 try sema.storePtr2(block, src, elem_ptr, src, init, rhs_src, .store);
9382 }9391 }
9392 if (res_sent_val) |sent_val| {
9393 const elem_index = try sema.addIntUnsigned(Type.usize, result_len);
9394 const elem_ptr = try block.addPtrElemPtr(alloc, elem_index, elem_ptr_ty);
9395 const init = try sema.addConstant(lhs_info.elem_type, sent_val);
9396 try sema.storePtr2(block, src, elem_ptr, src, init, lhs_src, .store);
9397 }
93839398
9384 return alloc;9399 return alloc;
9385 }9400 }
...@@ -9402,30 +9417,35 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -9402,30 +9417,35 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
9402 return block.addAggregateInit(result_ty, element_refs);9417 return block.addAggregateInit(result_ty, element_refs);
9403}9418}
94049419
9405fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, inst: Air.Inst.Ref) !?Type.ArrayInfo {9420fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Inst.Ref) !Type.ArrayInfo {
9406 const t = sema.typeOf(inst);9421 const operand_ty = sema.typeOf(operand);
9407 return switch (t.zigTypeTag()) {9422 switch (operand_ty.zigTypeTag()) {
9408 .Array => t.arrayInfo(),9423 .Array => return operand_ty.arrayInfo(),
9409 .Pointer => blk: {9424 .Pointer => {
9410 const ptrinfo = t.ptrInfo().data;9425 const ptr_info = operand_ty.ptrInfo().data;
9411 switch (ptrinfo.size) {9426 switch (ptr_info.size) {
9427 // TODO: in the Many case here this should only work if the type
9428 // has a sentinel, and this code should compute the length based
9429 // on the sentinel value.
9412 .Slice, .Many => {9430 .Slice, .Many => {
9413 const val = try sema.resolveConstValue(block, src, inst);9431 const val = try sema.resolveConstValue(block, src, operand);
9414 return Type.ArrayInfo{9432 return Type.ArrayInfo{
9415 .elem_type = t.childType(),9433 .elem_type = ptr_info.pointee_type,
9416 .sentinel = t.sentinel(),9434 .sentinel = ptr_info.sentinel,
9417 .len = val.sliceLen(sema.mod),9435 .len = val.sliceLen(sema.mod),
9418 };9436 };
9419 },9437 },
9420 .One => {9438 .One => {
9421 if (ptrinfo.pointee_type.zigTypeTag() != .Array) return null;9439 if (ptr_info.pointee_type.zigTypeTag() == .Array) {
9422 break :blk ptrinfo.pointee_type.arrayInfo();9440 return ptr_info.pointee_type.arrayInfo();
9441 }
9423 },9442 },
9424 .C => return null,9443 .C => {},
9425 }9444 }
9426 },9445 },
9427 else => null,9446 else => {},
9428 };9447 }
9448 return sema.fail(block, src, "expected indexable; found '{}'", .{operand_ty.fmt(sema.mod)});
9429}9449}
94309450
9431fn analyzeTupleMul(9451fn analyzeTupleMul(
...@@ -9514,65 +9534,99 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -9514,65 +9534,99 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
9514 return sema.analyzeTupleMul(block, inst_data.src_node, lhs, factor);9534 return sema.analyzeTupleMul(block, inst_data.src_node, lhs, factor);
9515 }9535 }
95169536
9517 const mulinfo = (try sema.getArrayCatInfo(block, lhs_src, lhs)) orelse9537 const lhs_info = try sema.getArrayCatInfo(block, lhs_src, lhs);
9518 return sema.fail(block, lhs_src, "expected array, found '{}'", .{lhs_ty.fmt(sema.mod)});
95199538
9520 const final_len_u64 = std.math.mul(u64, mulinfo.len, factor) catch9539 const result_len_u64 = std.math.mul(u64, lhs_info.len, factor) catch
9521 return sema.fail(block, rhs_src, "operation results in overflow", .{});9540 return sema.fail(block, rhs_src, "operation results in overflow", .{});
9541 const result_len = try sema.usizeCast(block, src, result_len_u64);
95229542
9523 if (try sema.resolveDefinedValue(block, lhs_src, lhs)) |lhs_val| {9543 const result_ty = try Type.array(sema.arena, result_len, lhs_info.sentinel, lhs_info.elem_type, sema.mod);
9524 const final_len = try sema.usizeCast(block, src, final_len_u64);
9525 const final_len_including_sent = final_len + @boolToInt(mulinfo.sentinel != null);
9526 const lhs_len = try sema.usizeCast(block, lhs_src, mulinfo.len);
95279544
9528 const is_single_ptr = lhs_ty.zigTypeTag() == .Pointer and !lhs_ty.isSlice();9545 const ptr_addrspace = if (lhs_ty.zigTypeTag() == .Pointer) lhs_ty.ptrAddressSpace() else null;
9529 const lhs_sub_val = if (is_single_ptr) (try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty)).? else lhs_val;9546 const lhs_len = try sema.usizeCast(block, lhs_src, lhs_info.len);
95309547
9531 var anon_decl = try block.startAnonDecl(src);9548 if (try sema.resolveDefinedValue(block, lhs_src, lhs)) |lhs_val| {
9532 defer anon_decl.deinit();9549 const final_len_including_sent = result_len + @boolToInt(lhs_info.sentinel != null);
95339550
9534 const final_ty = if (mulinfo.sentinel) |sent|9551 const lhs_sub_val = if (lhs_ty.isSinglePointer())
9535 try Type.Tag.array_sentinel.create(anon_decl.arena(), .{9552 (try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty)).?
9536 .len = final_len,
9537 .elem_type = try mulinfo.elem_type.copy(anon_decl.arena()),
9538 .sentinel = try sent.copy(anon_decl.arena()),
9539 })
9540 else9553 else
9541 try Type.Tag.array.create(anon_decl.arena(), .{9554 lhs_val;
9542 .len = final_len,9555
9543 .elem_type = try mulinfo.elem_type.copy(anon_decl.arena()),9556 const val = v: {
9544 });9557 // Optimization for the common pattern of a single element repeated N times, such
9545 const buf = try anon_decl.arena().alloc(Value, final_len_including_sent);9558 // as zero-filling a byte array.
95469559 if (lhs_len == 1) {
9547 // Optimization for the common pattern of a single element repeated N times, such9560 const elem_val = try lhs_sub_val.elemValue(sema.mod, sema.arena, 0);
9548 // as zero-filling a byte array.9561 break :v try Value.Tag.repeated.create(sema.arena, elem_val);
9549 const val = if (lhs_len == 1) blk: {9562 }
9550 const elem_val = try lhs_sub_val.elemValue(sema.mod, sema.arena, 0);9563
9551 const copied_val = try elem_val.copy(anon_decl.arena());9564 const element_vals = try sema.arena.alloc(Value, final_len_including_sent);
9552 break :blk try Value.Tag.repeated.create(anon_decl.arena(), copied_val);9565 var elem_i: usize = 0;
9553 } else blk: {9566 while (elem_i < result_len) {
9554 // the actual loop9567 var lhs_i: usize = 0;
9555 var i: usize = 0;9568 while (lhs_i < lhs_len) : (lhs_i += 1) {
9556 while (i < factor) : (i += 1) {9569 const elem_val = try lhs_sub_val.elemValue(sema.mod, sema.arena, lhs_i);
9557 var j: usize = 0;9570 element_vals[elem_i] = elem_val;
9558 while (j < lhs_len) : (j += 1) {9571 elem_i += 1;
9559 const val = try lhs_sub_val.elemValue(sema.mod, sema.arena, j);
9560 buf[lhs_len * i + j] = try val.copy(anon_decl.arena());
9561 }9572 }
9562 }9573 }
9563 if (mulinfo.sentinel) |sent| {9574 if (lhs_info.sentinel) |sent_val| {
9564 buf[final_len] = try sent.copy(anon_decl.arena());9575 element_vals[result_len] = sent_val;
9565 }9576 }
9566 break :blk try Value.Tag.aggregate.create(anon_decl.arena(), buf);9577 break :v try Value.Tag.aggregate.create(sema.arena, element_vals);
9567 };9578 };
9568 const decl = try anon_decl.finish(final_ty, val, 0);9579 return sema.addConstantMaybeRef(block, src, result_ty, val, ptr_addrspace != null);
9569 if (lhs_ty.zigTypeTag() == .Pointer) {9580 }
9570 return sema.analyzeDeclRef(decl);9581
9571 } else {9582 try sema.requireRuntimeBlock(block, lhs_src);
9572 return sema.analyzeDeclVal(block, .unneeded, decl);9583
9584 if (ptr_addrspace) |ptr_as| {
9585 const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{
9586 .pointee_type = result_ty,
9587 .@"addrspace" = ptr_as,
9588 });
9589 const alloc = try block.addTy(.alloc, alloc_ty);
9590 const elem_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
9591 .pointee_type = lhs_info.elem_type,
9592 .@"addrspace" = ptr_as,
9593 });
9594
9595 var elem_i: usize = 0;
9596 while (elem_i < result_len) {
9597 var lhs_i: usize = 0;
9598 while (lhs_i < lhs_len) : (lhs_i += 1) {
9599 const elem_index = try sema.addIntUnsigned(Type.usize, elem_i);
9600 elem_i += 1;
9601 const lhs_index = try sema.addIntUnsigned(Type.usize, lhs_i);
9602 const elem_ptr = try block.addPtrElemPtr(alloc, elem_index, elem_ptr_ty);
9603 const init = try sema.elemVal(block, lhs_src, lhs, lhs_index, src);
9604 try sema.storePtr2(block, src, elem_ptr, src, init, lhs_src, .store);
9605 }
9606 }
9607 if (lhs_info.sentinel) |sent_val| {
9608 const elem_index = try sema.addIntUnsigned(Type.usize, result_len);
9609 const elem_ptr = try block.addPtrElemPtr(alloc, elem_index, elem_ptr_ty);
9610 const init = try sema.addConstant(lhs_info.elem_type, sent_val);
9611 try sema.storePtr2(block, src, elem_ptr, src, init, lhs_src, .store);
9612 }
9613
9614 return alloc;
9615 }
9616
9617 const element_refs = try sema.arena.alloc(Air.Inst.Ref, result_len);
9618 var elem_i: usize = 0;
9619 while (elem_i < result_len) {
9620 var lhs_i: usize = 0;
9621 while (lhs_i < lhs_len) : (lhs_i += 1) {
9622 const lhs_index = try sema.addIntUnsigned(Type.usize, lhs_i);
9623 const init = try sema.elemVal(block, lhs_src, lhs, lhs_index, src);
9624 element_refs[elem_i] = init;
9625 elem_i += 1;
9573 }9626 }
9574 }9627 }
9575 return sema.fail(block, lhs_src, "TODO runtime array_mul", .{});9628
9629 return block.addAggregateInit(result_ty, element_refs);
9576}9630}
95779631
9578fn zirNegate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {9632fn zirNegate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
src/codegen/llvm.zig+20-7
...@@ -7728,7 +7728,14 @@ pub const FuncGen = struct {...@@ -7728,7 +7728,14 @@ pub const FuncGen = struct {
7728 const alloca_inst = self.buildAlloca(llvm_result_ty);7728 const alloca_inst = self.buildAlloca(llvm_result_ty);
7729 alloca_inst.setAlignment(result_ty.abiAlignment(target));7729 alloca_inst.setAlignment(result_ty.abiAlignment(target));
77307730
7731 const elem_ty = result_ty.childType();7731 const array_info = result_ty.arrayInfo();
7732 var elem_ptr_payload: Type.Payload.Pointer = .{
7733 .data = .{
7734 .pointee_type = array_info.elem_type,
7735 .@"addrspace" = .generic,
7736 },
7737 };
7738 const elem_ptr_ty = Type.initPayload(&elem_ptr_payload.base);
77327739
7733 for (elements) |elem, i| {7740 for (elements) |elem, i| {
7734 const indices: [2]*const llvm.Value = .{7741 const indices: [2]*const llvm.Value = .{
...@@ -7737,13 +7744,19 @@ pub const FuncGen = struct {...@@ -7737,13 +7744,19 @@ pub const FuncGen = struct {
7737 };7744 };
7738 const elem_ptr = self.builder.buildInBoundsGEP(alloca_inst, &indices, indices.len, "");7745 const elem_ptr = self.builder.buildInBoundsGEP(alloca_inst, &indices, indices.len, "");
7739 const llvm_elem = try self.resolveInst(elem);7746 const llvm_elem = try self.resolveInst(elem);
7740 var elem_ptr_payload: Type.Payload.Pointer = .{7747 self.store(elem_ptr, elem_ptr_ty, llvm_elem, .NotAtomic);
7741 .data = .{7748 }
7742 .pointee_type = elem_ty,7749 if (array_info.sentinel) |sent_val| {
7743 .@"addrspace" = .generic,7750 const indices: [2]*const llvm.Value = .{
7744 },7751 llvm_usize.constNull(),
7752 llvm_usize.constInt(@intCast(c_uint, array_info.len), .False),
7745 };7753 };
7746 const elem_ptr_ty = Type.initPayload(&elem_ptr_payload.base);7754 const elem_ptr = self.builder.buildInBoundsGEP(alloca_inst, &indices, indices.len, "");
7755 const llvm_elem = try self.dg.lowerValue(.{
7756 .ty = array_info.elem_type,
7757 .val = sent_val,
7758 });
7759
7747 self.store(elem_ptr, elem_ptr_ty, llvm_elem, .NotAtomic);7760 self.store(elem_ptr, elem_ptr_ty, llvm_elem, .NotAtomic);
7748 }7761 }
77497762
test/behavior/eval.zig+88-14
...@@ -742,6 +742,23 @@ test "array concatenation of function calls" {...@@ -742,6 +742,23 @@ test "array concatenation of function calls" {
742 try expect(std.mem.eql(i32, &a, &[_]i32{ 3, 4 }));742 try expect(std.mem.eql(i32, &a, &[_]i32{ 3, 4 }));
743}743}
744744
745test "array multiplication of function calls" {
746 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
747 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
748 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
749
750 var a = oneItem(3) ** scalar(2);
751 try expect(std.mem.eql(i32, &a, &[_]i32{ 3, 3 }));
752}
753
754fn oneItem(x: i32) [1]i32 {
755 return [_]i32{x};
756}
757
758fn scalar(x: u32) u32 {
759 return x;
760}
761
745test "array concatenation peer resolves element types - value" {762test "array concatenation peer resolves element types - value" {
746 if (builtin.zig_backend == .stage1) return error.SkipZigTest;763 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
747 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;764 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
...@@ -751,7 +768,7 @@ test "array concatenation peer resolves element types - value" {...@@ -751,7 +768,7 @@ test "array concatenation peer resolves element types - value" {
751 var a = [2]u3{ 1, 7 };768 var a = [2]u3{ 1, 7 };
752 var b = [3]u8{ 200, 225, 255 };769 var b = [3]u8{ 200, 225, 255 };
753 var c = a ++ b;770 var c = a ++ b;
754 try expect(@TypeOf(c) == [5]u8);771 comptime assert(@TypeOf(c) == [5]u8);
755 try expect(c[0] == 1);772 try expect(c[0] == 1);
756 try expect(c[1] == 7);773 try expect(c[1] == 7);
757 try expect(c[2] == 200);774 try expect(c[2] == 200);
...@@ -768,7 +785,7 @@ test "array concatenation peer resolves element types - pointer" {...@@ -768,7 +785,7 @@ test "array concatenation peer resolves element types - pointer" {
768 var a = [2]u3{ 1, 7 };785 var a = [2]u3{ 1, 7 };
769 var b = [3]u8{ 200, 225, 255 };786 var b = [3]u8{ 200, 225, 255 };
770 var c = &a ++ &b;787 var c = &a ++ &b;
771 try expect(@TypeOf(c) == *[5]u8);788 comptime assert(@TypeOf(c) == *[5]u8);
772 try expect(c[0] == 1);789 try expect(c[0] == 1);
773 try expect(c[1] == 7);790 try expect(c[1] == 7);
774 try expect(c[2] == 200);791 try expect(c[2] == 200);
...@@ -776,23 +793,80 @@ test "array concatenation peer resolves element types - pointer" {...@@ -776,23 +793,80 @@ test "array concatenation peer resolves element types - pointer" {
776 try expect(c[4] == 255);793 try expect(c[4] == 255);
777}794}
778795
779test "array multiplication forces comptime" {796test "array concatenation sets the sentinel - value" {
780 if (builtin.zig_backend != .stage1) {797 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
781 // note: our plan is to change the language to support runtime array798 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
782 // multiplication instead of making this test pass.799 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
783 return error.SkipZigTest; // TODO800 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
784 }801 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
802 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
785803
786 var a = oneItem(3) ** scalar(2);804 var a = [2]u3{ 1, 7 };
787 try expect(std.mem.eql(i32, &a, &[_]i32{ 3, 3 }));805 var b = [3:69]u8{ 200, 225, 255 };
806 var c = a ++ b;
807 comptime assert(@TypeOf(c) == [5:69]u8);
808 try expect(c[0] == 1);
809 try expect(c[1] == 7);
810 try expect(c[2] == 200);
811 try expect(c[3] == 225);
812 try expect(c[4] == 255);
813 var ptr: [*]const u8 = &c;
814 try expect(ptr[5] == 69);
788}815}
789816
790fn oneItem(x: i32) [1]i32 {817test "array concatenation sets the sentinel - pointer" {
791 return [_]i32{x};818 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
819 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
820 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
821 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
822
823 var a = [2]u3{ 1, 7 };
824 var b = [3:69]u8{ 200, 225, 255 };
825 var c = &a ++ &b;
826 comptime assert(@TypeOf(c) == *[5:69]u8);
827 try expect(c[0] == 1);
828 try expect(c[1] == 7);
829 try expect(c[2] == 200);
830 try expect(c[3] == 225);
831 try expect(c[4] == 255);
832 var ptr: [*]const u8 = c;
833 try expect(ptr[5] == 69);
792}834}
793835
794fn scalar(x: u32) u32 {836test "array multiplication sets the sentinel - value" {
795 return x;837 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
838 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
839 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
840 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
841 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
842 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
843
844 var a = [2:7]u3{ 1, 6 };
845 var b = a ** 2;
846 comptime assert(@TypeOf(b) == [4:7]u3);
847 try expect(b[0] == 1);
848 try expect(b[1] == 6);
849 try expect(b[2] == 1);
850 try expect(b[3] == 6);
851 var ptr: [*]const u3 = &b;
852 try expect(ptr[4] == 7);
853}
854
855test "array multiplication sets the sentinel - pointer" {
856 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
857 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
858 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
859 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
860
861 var a = [2:7]u3{ 1, 6 };
862 var b = &a ** 2;
863 comptime assert(@TypeOf(b) == *[4:7]u3);
864 try expect(b[0] == 1);
865 try expect(b[1] == 6);
866 try expect(b[2] == 1);
867 try expect(b[3] == 6);
868 var ptr: [*]const u3 = b;
869 try expect(ptr[4] == 7);
796}870}
797871
798test "comptime assign int to optional int" {872test "comptime assign int to optional int" {