| ... | ... | @@ -8059,6 +8059,78 @@ fn zirBitNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 8059 | 8059 | return block.addTyOp(.not, operand_type, operand); |
| 8060 | 8060 | } |
| 8061 | 8061 | |
| 8062 | fn analyzeTupleCat( |
| 8063 | sema: *Sema, |
| 8064 | block: *Block, |
| 8065 | src_node: i32, |
| 8066 | lhs: Air.Inst.Ref, |
| 8067 | rhs: Air.Inst.Ref, |
| 8068 | ) CompileError!Air.Inst.Ref { |
| 8069 | const lhs_ty = sema.typeOf(lhs); |
| 8070 | const rhs_ty = sema.typeOf(rhs); |
| 8071 | const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = src_node }; |
| 8072 | const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = src_node }; |
| 8073 | |
| 8074 | const lhs_tuple = lhs_ty.tupleFields(); |
| 8075 | const rhs_tuple = rhs_ty.tupleFields(); |
| 8076 | const dest_fields = lhs_tuple.types.len + rhs_tuple.types.len; |
| 8077 | |
| 8078 | if (dest_fields == 0) { |
| 8079 | return sema.addConstant(Type.initTag(.empty_struct_literal), Value.initTag(.empty_struct_value)); |
| 8080 | } |
| 8081 | |
| 8082 | const types = try sema.arena.alloc(Type, dest_fields); |
| 8083 | const values = try sema.arena.alloc(Value, dest_fields); |
| 8084 | |
| 8085 | const opt_runtime_src = rs: { |
| 8086 | var runtime_src: ?LazySrcLoc = null; |
| 8087 | for (lhs_tuple.types) |ty, i| { |
| 8088 | types[i] = ty; |
| 8089 | values[i] = lhs_tuple.values[i]; |
| 8090 | const operand_src = lhs_src; // TODO better source location |
| 8091 | if (values[i].tag() == .unreachable_value) { |
| 8092 | runtime_src = operand_src; |
| 8093 | } |
| 8094 | } |
| 8095 | const offset = lhs_tuple.types.len; |
| 8096 | for (rhs_tuple.types) |ty, i| { |
| 8097 | types[i + offset] = ty; |
| 8098 | values[i + offset] = rhs_tuple.values[i]; |
| 8099 | const operand_src = rhs_src; // TODO better source location |
| 8100 | if (rhs_tuple.values[i].tag() == .unreachable_value) { |
| 8101 | runtime_src = operand_src; |
| 8102 | } |
| 8103 | } |
| 8104 | break :rs runtime_src; |
| 8105 | }; |
| 8106 | |
| 8107 | const tuple_ty = try Type.Tag.tuple.create(sema.arena, .{ |
| 8108 | .types = types, |
| 8109 | .values = values, |
| 8110 | }); |
| 8111 | |
| 8112 | const runtime_src = opt_runtime_src orelse { |
| 8113 | const tuple_val = try Value.Tag.@"struct".create(sema.arena, values); |
| 8114 | return sema.addConstant(tuple_ty, tuple_val); |
| 8115 | }; |
| 8116 | |
| 8117 | try sema.requireRuntimeBlock(block, runtime_src); |
| 8118 | |
| 8119 | const element_refs = try sema.arena.alloc(Air.Inst.Ref, dest_fields); |
| 8120 | for (lhs_tuple.types) |_, i| { |
| 8121 | const operand_src = lhs_src; // TODO better source location |
| 8122 | element_refs[i] = try sema.tupleFieldValByIndex(block, operand_src, lhs, @intCast(u32, i), lhs_ty); |
| 8123 | } |
| 8124 | const offset = lhs_tuple.types.len; |
| 8125 | for (rhs_tuple.types) |_, i| { |
| 8126 | const operand_src = rhs_src; // TODO better source location |
| 8127 | element_refs[i + offset] = |
| 8128 | try sema.tupleFieldValByIndex(block, operand_src, rhs, @intCast(u32, i), rhs_ty); |
| 8129 | } |
| 8130 | |
| 8131 | return block.addAggregateInit(tuple_ty, element_refs); |
| 8132 | } |
| 8133 | |
| 8062 | 8134 | fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 8063 | 8135 | const tracy = trace(@src()); |
| 8064 | 8136 | defer tracy.end(); |
| ... | ... | @@ -8069,6 +8141,11 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 8069 | 8141 | const rhs = sema.resolveInst(extra.rhs); |
| 8070 | 8142 | const lhs_ty = sema.typeOf(lhs); |
| 8071 | 8143 | const rhs_ty = sema.typeOf(rhs); |
| 8144 | |
| 8145 | if (lhs_ty.isTuple() and rhs_ty.isTuple()) { |
| 8146 | return sema.analyzeTupleCat(block, inst_data.src_node, lhs, rhs); |
| 8147 | } |
| 8148 | |
| 8072 | 8149 | const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; |
| 8073 | 8150 | const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; |
| 8074 | 8151 | |
| ... | ... | @@ -8165,6 +8242,72 @@ fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, inst: Air.Inst.R |
| 8165 | 8242 | }; |
| 8166 | 8243 | } |
| 8167 | 8244 | |
| 8245 | fn analyzeTupleMul( |
| 8246 | sema: *Sema, |
| 8247 | block: *Block, |
| 8248 | src_node: i32, |
| 8249 | operand: Air.Inst.Ref, |
| 8250 | factor: u64, |
| 8251 | ) CompileError!Air.Inst.Ref { |
| 8252 | const operand_ty = sema.typeOf(operand); |
| 8253 | const operand_tuple = operand_ty.tupleFields(); |
| 8254 | const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = src_node }; |
| 8255 | const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = src_node }; |
| 8256 | |
| 8257 | const tuple_len = operand_tuple.types.len; |
| 8258 | const final_len_u64 = std.math.mul(u64, tuple_len, factor) catch |
| 8259 | return sema.fail(block, rhs_src, "operation results in overflow", .{}); |
| 8260 | |
| 8261 | if (final_len_u64 == 0) { |
| 8262 | return sema.addConstant(Type.initTag(.empty_struct_literal), Value.initTag(.empty_struct_value)); |
| 8263 | } |
| 8264 | |
| 8265 | const types = try sema.arena.alloc(Type, final_len_u64); |
| 8266 | const values = try sema.arena.alloc(Value, final_len_u64); |
| 8267 | |
| 8268 | const opt_runtime_src = rs: { |
| 8269 | var runtime_src: ?LazySrcLoc = null; |
| 8270 | for (operand_tuple.types) |ty, i| { |
| 8271 | types[i] = ty; |
| 8272 | values[i] = operand_tuple.values[i]; |
| 8273 | const operand_src = lhs_src; // TODO better source location |
| 8274 | if (values[i].tag() == .unreachable_value) { |
| 8275 | runtime_src = operand_src; |
| 8276 | } |
| 8277 | } |
| 8278 | var i: usize = 1; |
| 8279 | while (i < factor) : (i += 1) { |
| 8280 | mem.copy(Type, types[tuple_len * i ..], operand_tuple.types); |
| 8281 | mem.copy(Value, values[tuple_len * i ..], operand_tuple.values); |
| 8282 | } |
| 8283 | break :rs runtime_src; |
| 8284 | }; |
| 8285 | |
| 8286 | const tuple_ty = try Type.Tag.tuple.create(sema.arena, .{ |
| 8287 | .types = types, |
| 8288 | .values = values, |
| 8289 | }); |
| 8290 | |
| 8291 | const runtime_src = opt_runtime_src orelse { |
| 8292 | const tuple_val = try Value.Tag.@"struct".create(sema.arena, values); |
| 8293 | return sema.addConstant(tuple_ty, tuple_val); |
| 8294 | }; |
| 8295 | |
| 8296 | try sema.requireRuntimeBlock(block, runtime_src); |
| 8297 | |
| 8298 | const element_refs = try sema.arena.alloc(Air.Inst.Ref, final_len_u64); |
| 8299 | for (operand_tuple.types) |_, i| { |
| 8300 | const operand_src = lhs_src; // TODO better source location |
| 8301 | element_refs[i] = try sema.tupleFieldValByIndex(block, operand_src, operand, @intCast(u32, i), operand_ty); |
| 8302 | } |
| 8303 | var i: usize = 1; |
| 8304 | while (i < factor) : (i += 1) { |
| 8305 | mem.copy(Air.Inst.Ref, element_refs[tuple_len * i ..], element_refs[0..tuple_len]); |
| 8306 | } |
| 8307 | |
| 8308 | return block.addAggregateInit(tuple_ty, element_refs); |
| 8309 | } |
| 8310 | |
| 8168 | 8311 | fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 8169 | 8312 | const tracy = trace(@src()); |
| 8170 | 8313 | defer tracy.end(); |
| ... | ... | @@ -8179,6 +8322,11 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 8179 | 8322 | |
| 8180 | 8323 | // In `**` rhs has to be comptime-known, but lhs can be runtime-known |
| 8181 | 8324 | const factor = try sema.resolveInt(block, rhs_src, extra.rhs, Type.usize); |
| 8325 | |
| 8326 | if (lhs_ty.isTuple()) { |
| 8327 | return sema.analyzeTupleMul(block, inst_data.src_node, lhs, factor); |
| 8328 | } |
| 8329 | |
| 8182 | 8330 | const mulinfo = (try sema.getArrayCatInfo(block, lhs_src, lhs)) orelse |
| 8183 | 8331 | return sema.fail(block, lhs_src, "expected array, found '{}'", .{lhs_ty}); |
| 8184 | 8332 | |
| ... | ... | @@ -14754,6 +14902,11 @@ fn tupleFieldVal( |
| 14754 | 14902 | tuple_ty, field_name, @errorName(err), |
| 14755 | 14903 | }); |
| 14756 | 14904 | }; |
| 14905 | if (field_index >= tuple_ty.structFieldCount()) { |
| 14906 | return sema.fail(block, field_name_src, "tuple {} has no such field '{s}'", .{ |
| 14907 | tuple_ty, field_name, |
| 14908 | }); |
| 14909 | } |
| 14757 | 14910 | return tupleFieldValByIndex(sema, block, src, tuple_byval, field_index, tuple_ty); |
| 14758 | 14911 | } |
| 14759 | 14912 | |