authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2022-12-24 02:32:13-05:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2022-12-24 02:40:33-05:00
log0559cdb5542a2acb50ce49363c1973f3ca70365e
tree3c44549cc3b1b6aaff0b98893ee0585199d2b49f
parentc9e3524d0b12e11488519bb377e7dcf60047963a

Sema: support concat of tuple and array

Closes #14041

2 files changed, 51 insertions(+), 13 deletions(-)

src/Sema.zig+33-13
...@@ -12178,17 +12178,21 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -12178,17 +12178,21 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
12178 const rhs_ty = sema.typeOf(rhs);12178 const rhs_ty = sema.typeOf(rhs);
12179 const src = inst_data.src();12179 const src = inst_data.src();
1218012180
12181 if (lhs_ty.isTuple() and rhs_ty.isTuple()) {12181 const lhs_is_tuple = lhs_ty.isTuple();
12182 const rhs_is_tuple = rhs_ty.isTuple();
12183 if (lhs_is_tuple and rhs_is_tuple) {
12182 return sema.analyzeTupleCat(block, inst_data.src_node, lhs, rhs);12184 return sema.analyzeTupleCat(block, inst_data.src_node, lhs, rhs);
12183 }12185 }
1218412186
12185 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };12187 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
12186 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };12188 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
1218712189
12188 const lhs_info = try sema.getArrayCatInfo(block, lhs_src, lhs) orelse {12190 const lhs_info = try sema.getArrayCatInfo(block, lhs_src, lhs, rhs_ty) orelse lhs_info: {
12191 if (lhs_is_tuple) break :lhs_info @as(Type.ArrayInfo, undefined);
12189 return sema.fail(block, lhs_src, "expected indexable; found '{}'", .{lhs_ty.fmt(sema.mod)});12192 return sema.fail(block, lhs_src, "expected indexable; found '{}'", .{lhs_ty.fmt(sema.mod)});
12190 };12193 };
12191 const rhs_info = try sema.getArrayCatInfo(block, rhs_src, rhs) orelse {12194 const rhs_info = try sema.getArrayCatInfo(block, rhs_src, rhs, lhs_ty) orelse {
12195 assert(!rhs_is_tuple);
12192 return sema.fail(block, rhs_src, "expected indexable; found '{}'", .{rhs_ty.fmt(sema.mod)});12196 return sema.fail(block, rhs_src, "expected indexable; found '{}'", .{rhs_ty.fmt(sema.mod)});
12193 };12197 };
1219412198
...@@ -12274,18 +12278,24 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -12274,18 +12278,24 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
12274 const element_vals = try sema.arena.alloc(Value, final_len_including_sent);12278 const element_vals = try sema.arena.alloc(Value, final_len_including_sent);
12275 var elem_i: usize = 0;12279 var elem_i: usize = 0;
12276 while (elem_i < lhs_len) : (elem_i += 1) {12280 while (elem_i < lhs_len) : (elem_i += 1) {
12277 const elem_val = try lhs_sub_val.elemValue(sema.mod, sema.arena, elem_i);12281 const lhs_elem_i = elem_i;
12278 const elem_val_inst = try sema.addConstant(lhs_info.elem_type, elem_val);12282 const elem_ty = if (lhs_is_tuple) lhs_ty.structFieldType(lhs_elem_i) else lhs_info.elem_type;
12283 const elem_default_val = if (lhs_is_tuple) lhs_ty.structFieldDefaultValue(lhs_elem_i) else Value.initTag(.unreachable_value);
12284 const elem_val = if (elem_default_val.tag() == .unreachable_value) try lhs_sub_val.elemValue(sema.mod, sema.arena, lhs_elem_i) else elem_default_val;
12285 const elem_val_inst = try sema.addConstant(elem_ty, elem_val);
12279 const coerced_elem_val_inst = try sema.coerce(block, resolved_elem_ty, elem_val_inst, .unneeded);12286 const coerced_elem_val_inst = try sema.coerce(block, resolved_elem_ty, elem_val_inst, .unneeded);
12280 const coereced_elem_val = try sema.resolveConstMaybeUndefVal(block, .unneeded, coerced_elem_val_inst, "");12287 const coerced_elem_val = try sema.resolveConstMaybeUndefVal(block, .unneeded, coerced_elem_val_inst, "");
12281 element_vals[elem_i] = coereced_elem_val;12288 element_vals[elem_i] = coerced_elem_val;
12282 }12289 }
12283 while (elem_i < result_len) : (elem_i += 1) {12290 while (elem_i < result_len) : (elem_i += 1) {
12284 const elem_val = try rhs_sub_val.elemValue(sema.mod, sema.arena, elem_i - lhs_len);12291 const rhs_elem_i = elem_i - lhs_len;
12285 const elem_val_inst = try sema.addConstant(lhs_info.elem_type, elem_val);12292 const elem_ty = if (rhs_is_tuple) rhs_ty.structFieldType(rhs_elem_i) else rhs_info.elem_type;
12293 const elem_default_val = if (rhs_is_tuple) rhs_ty.structFieldDefaultValue(rhs_elem_i) else Value.initTag(.unreachable_value);
12294 const elem_val = if (elem_default_val.tag() == .unreachable_value) try rhs_sub_val.elemValue(sema.mod, sema.arena, rhs_elem_i) else elem_default_val;
12295 const elem_val_inst = try sema.addConstant(elem_ty, elem_val);
12286 const coerced_elem_val_inst = try sema.coerce(block, resolved_elem_ty, elem_val_inst, .unneeded);12296 const coerced_elem_val_inst = try sema.coerce(block, resolved_elem_ty, elem_val_inst, .unneeded);
12287 const coereced_elem_val = try sema.resolveConstMaybeUndefVal(block, .unneeded, coerced_elem_val_inst, "");12297 const coerced_elem_val = try sema.resolveConstMaybeUndefVal(block, .unneeded, coerced_elem_val_inst, "");
12288 element_vals[elem_i] = coereced_elem_val;12298 element_vals[elem_i] = coerced_elem_val;
12289 }12299 }
12290 if (res_sent_val) |sent_val| {12300 if (res_sent_val) |sent_val| {
12291 element_vals[result_len] = sent_val;12301 element_vals[result_len] = sent_val;
...@@ -12350,7 +12360,7 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -12350,7 +12360,7 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
12350 return block.addAggregateInit(result_ty, element_refs);12360 return block.addAggregateInit(result_ty, element_refs);
12351}12361}
1235212362
12353fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Inst.Ref) !?Type.ArrayInfo {12363fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Inst.Ref, peer_ty: Type) !?Type.ArrayInfo {
12354 const operand_ty = sema.typeOf(operand);12364 const operand_ty = sema.typeOf(operand);
12355 switch (operand_ty.zigTypeTag()) {12365 switch (operand_ty.zigTypeTag()) {
12356 .Array => return operand_ty.arrayInfo(),12366 .Array => return operand_ty.arrayInfo(),
...@@ -12376,6 +12386,16 @@ fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Ins...@@ -12376,6 +12386,16 @@ fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Ins
12376 .C => {},12386 .C => {},
12377 }12387 }
12378 },12388 },
12389 .Struct => {
12390 if (operand_ty.isTuple() and peer_ty.isIndexable()) {
12391 assert(!peer_ty.isTuple());
12392 return .{
12393 .elem_type = peer_ty.elemType2(),
12394 .sentinel = null,
12395 .len = operand_ty.arrayLen(),
12396 };
12397 }
12398 },
12379 else => {},12399 else => {},
12380 }12400 }
12381 return null;12401 return null;
...@@ -12470,7 +12490,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -12470,7 +12490,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
12470 }12490 }
1247112491
12472 // Analyze the lhs first, to catch the case that someone tried to do exponentiation12492 // Analyze the lhs first, to catch the case that someone tried to do exponentiation
12473 const lhs_info = try sema.getArrayCatInfo(block, lhs_src, lhs) orelse {12493 const lhs_info = try sema.getArrayCatInfo(block, lhs_src, lhs, lhs_ty) orelse {
12474 const msg = msg: {12494 const msg = msg: {
12475 const msg = try sema.errMsg(block, lhs_src, "expected indexable; found '{}'", .{lhs_ty.fmt(sema.mod)});12495 const msg = try sema.errMsg(block, lhs_src, "expected indexable; found '{}'", .{lhs_ty.fmt(sema.mod)});
12476 errdefer msg.destroy(sema.gpa);12496 errdefer msg.destroy(sema.gpa);
test/behavior/array.zig+18
...@@ -45,6 +45,24 @@ fn getArrayLen(a: []const u32) usize {...@@ -45,6 +45,24 @@ fn getArrayLen(a: []const u32) usize {
45 return a.len;45 return a.len;
46}46}
4747
48test "array concat with tuple" {
49 const array: [2]u8 = .{ 1, 2 };
50 {
51 const seq = array ++ .{ 3, 4 };
52 try std.testing.expectEqualSlices(u8, &.{ 1, 2, 3, 4 }, &seq);
53 }
54 {
55 const seq = .{ 3, 4 } ++ array;
56 try std.testing.expectEqualSlices(u8, &.{ 3, 4, 1, 2 }, &seq);
57 }
58}
59
60test "array init with concat" {
61 const a = 'a';
62 var i: [4]u8 = [2]u8{ a, 'b' } ++ [2]u8{ 'c', 'd' };
63 try expect(std.mem.eql(u8, &i, "abcd"));
64}
65
48test "array init with mult" {66test "array init with mult" {
49 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;67 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
50 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO68 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO