| ... | ... | @@ -1125,6 +1125,7 @@ fn analyzeBodyInner( |
| 1125 | 1125 | .array_base_ptr => try sema.zirArrayBasePtr(block, inst), |
| 1126 | 1126 | .field_base_ptr => try sema.zirFieldBasePtr(block, inst), |
| 1127 | 1127 | .for_len => try sema.zirForLen(block, inst), |
| 1128 | .opt_eu_base_ty => try sema.zirOptEuBaseTy(block, inst), |
| 1128 | 1129 | |
| 1129 | 1130 | .clz => try sema.zirBitCount(block, inst, .clz, Value.clz), |
| 1130 | 1131 | .ctz => try sema.zirBitCount(block, inst, .ctz, Value.ctz), |
| ... | ... | @@ -1359,12 +1360,12 @@ fn analyzeBodyInner( |
| 1359 | 1360 | continue; |
| 1360 | 1361 | }, |
| 1361 | 1362 | .validate_array_init_ty => { |
| 1362 | | try sema.validateArrayInitTy(block, inst); |
| 1363 | try sema.zirValidateArrayInitTy(block, inst); |
| 1363 | 1364 | i += 1; |
| 1364 | 1365 | continue; |
| 1365 | 1366 | }, |
| 1366 | 1367 | .validate_struct_init_ty => { |
| 1367 | | try sema.validateStructInitTy(block, inst); |
| 1368 | try sema.zirValidateStructInitTy(block, inst); |
| 1368 | 1369 | i += 1; |
| 1369 | 1370 | continue; |
| 1370 | 1371 | }, |
| ... | ... | @@ -4312,7 +4313,31 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 4312 | 4313 | return len; |
| 4313 | 4314 | } |
| 4314 | 4315 | |
| 4315 | | fn validateArrayInitTy( |
| 4316 | fn zirOptEuBaseTy( |
| 4317 | sema: *Sema, |
| 4318 | block: *Block, |
| 4319 | inst: Zir.Inst.Index, |
| 4320 | ) CompileError!Air.Inst.Ref { |
| 4321 | const mod = sema.mod; |
| 4322 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 4323 | var ty = sema.resolveType(block, .unneeded, inst_data.operand) catch |err| switch (err) { |
| 4324 | // Since this is a ZIR instruction that returns a type, encountering |
| 4325 | // generic poison should not result in a failed compilation, but the |
| 4326 | // generic poison type. This prevents unnecessary failures when |
| 4327 | // constructing types at compile-time. |
| 4328 | error.GenericPoison => return .generic_poison_type, |
| 4329 | else => |e| return e, |
| 4330 | }; |
| 4331 | while (true) { |
| 4332 | switch (ty.zigTypeTag(mod)) { |
| 4333 | .Optional => ty = ty.optionalChild(mod), |
| 4334 | .ErrorUnion => ty = ty.errorUnionPayload(mod), |
| 4335 | else => return sema.addType(ty), |
| 4336 | } |
| 4337 | } |
| 4338 | } |
| 4339 | |
| 4340 | fn zirValidateArrayInitTy( |
| 4316 | 4341 | sema: *Sema, |
| 4317 | 4342 | block: *Block, |
| 4318 | 4343 | inst: Zir.Inst.Index, |
| ... | ... | @@ -4322,7 +4347,11 @@ fn validateArrayInitTy( |
| 4322 | 4347 | const src = inst_data.src(); |
| 4323 | 4348 | const ty_src: LazySrcLoc = .{ .node_offset_init_ty = inst_data.src_node }; |
| 4324 | 4349 | const extra = sema.code.extraData(Zir.Inst.ArrayInit, inst_data.payload_index).data; |
| 4325 | | const ty = try sema.resolveType(block, ty_src, extra.ty); |
| 4350 | const ty = sema.resolveType(block, ty_src, extra.ty) catch |err| switch (err) { |
| 4351 | // It's okay for the type to be unknown: this will result in an anonymous array init. |
| 4352 | error.GenericPoison => return, |
| 4353 | else => |e| return e, |
| 4354 | }; |
| 4326 | 4355 | |
| 4327 | 4356 | switch (ty.zigTypeTag(mod)) { |
| 4328 | 4357 | .Array => { |
| ... | ... | @@ -4358,7 +4387,7 @@ fn validateArrayInitTy( |
| 4358 | 4387 | return sema.failWithArrayInitNotSupported(block, ty_src, ty); |
| 4359 | 4388 | } |
| 4360 | 4389 | |
| 4361 | | fn validateStructInitTy( |
| 4390 | fn zirValidateStructInitTy( |
| 4362 | 4391 | sema: *Sema, |
| 4363 | 4392 | block: *Block, |
| 4364 | 4393 | inst: Zir.Inst.Index, |
| ... | ... | @@ -4366,7 +4395,11 @@ fn validateStructInitTy( |
| 4366 | 4395 | const mod = sema.mod; |
| 4367 | 4396 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 4368 | 4397 | const src = inst_data.src(); |
| 4369 | | const ty = try sema.resolveType(block, src, inst_data.operand); |
| 4398 | const ty = sema.resolveType(block, src, inst_data.operand) catch |err| switch (err) { |
| 4399 | // It's okay for the type to be unknown: this will result in an anonymous struct init. |
| 4400 | error.GenericPoison => return, |
| 4401 | else => |e| return e, |
| 4402 | }; |
| 4370 | 4403 | |
| 4371 | 4404 | switch (ty.zigTypeTag(mod)) { |
| 4372 | 4405 | .Struct, .Union => return, |
| ... | ... | @@ -7744,7 +7777,15 @@ fn zirOptionalType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro |
| 7744 | 7777 | fn zirElemTypeIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 7745 | 7778 | const mod = sema.mod; |
| 7746 | 7779 | const bin = sema.code.instructions.items(.data)[inst].bin; |
| 7747 | | const indexable_ty = try sema.resolveType(block, .unneeded, bin.lhs); |
| 7780 | const operand = sema.resolveType(block, .unneeded, bin.lhs) catch |err| switch (err) { |
| 7781 | // Since this is a ZIR instruction that returns a type, encountering |
| 7782 | // generic poison should not result in a failed compilation, but the |
| 7783 | // generic poison type. This prevents unnecessary failures when |
| 7784 | // constructing types at compile-time. |
| 7785 | error.GenericPoison => return .generic_poison_type, |
| 7786 | else => |e| return e, |
| 7787 | }; |
| 7788 | const indexable_ty = try sema.resolveTypeFields(operand); |
| 7748 | 7789 | assert(indexable_ty.isIndexable(mod)); // validated by a previous instruction |
| 7749 | 7790 | if (indexable_ty.zigTypeTag(mod) == .Struct) { |
| 7750 | 7791 | const elem_type = indexable_ty.structFieldType(@intFromEnum(bin.rhs), mod); |
| ... | ... | @@ -18794,7 +18835,13 @@ fn zirStructInit( |
| 18794 | 18835 | const first_item = sema.code.extraData(Zir.Inst.StructInit.Item, extra.end).data; |
| 18795 | 18836 | const first_field_type_data = zir_datas[first_item.field_type].pl_node; |
| 18796 | 18837 | const first_field_type_extra = sema.code.extraData(Zir.Inst.FieldType, first_field_type_data.payload_index).data; |
| 18797 | | const resolved_ty = try sema.resolveType(block, src, first_field_type_extra.container_type); |
| 18838 | const resolved_ty = sema.resolveType(block, src, first_field_type_extra.container_type) catch |err| switch (err) { |
| 18839 | error.GenericPoison => { |
| 18840 | // The type wasn't actually known, so treat this as an anon struct init. |
| 18841 | return sema.structInitAnon(block, src, .typed_init, extra.data, extra.end, is_ref); |
| 18842 | }, |
| 18843 | else => |e| return e, |
| 18844 | }; |
| 18798 | 18845 | try sema.resolveTypeLayout(resolved_ty); |
| 18799 | 18846 | |
| 18800 | 18847 | if (resolved_ty.zigTypeTag(mod) == .Struct) { |
| ... | ... | @@ -19037,26 +19084,57 @@ fn zirStructInitAnon( |
| 19037 | 19084 | inst: Zir.Inst.Index, |
| 19038 | 19085 | is_ref: bool, |
| 19039 | 19086 | ) CompileError!Air.Inst.Ref { |
| 19040 | | const mod = sema.mod; |
| 19041 | | const gpa = sema.gpa; |
| 19042 | 19087 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 19043 | 19088 | const src = inst_data.src(); |
| 19044 | 19089 | const extra = sema.code.extraData(Zir.Inst.StructInitAnon, inst_data.payload_index); |
| 19045 | | const types = try sema.arena.alloc(InternPool.Index, extra.data.fields_len); |
| 19090 | return sema.structInitAnon(block, src, .anon_init, extra.data, extra.end, is_ref); |
| 19091 | } |
| 19092 | |
| 19093 | fn structInitAnon( |
| 19094 | sema: *Sema, |
| 19095 | block: *Block, |
| 19096 | src: LazySrcLoc, |
| 19097 | /// It is possible for a typed struct_init to be downgraded to an anonymous init due to a |
| 19098 | /// generic poison type. In this case, we need to know to interpret the extra data differently. |
| 19099 | comptime kind: enum { anon_init, typed_init }, |
| 19100 | extra_data: switch (kind) { |
| 19101 | .anon_init => Zir.Inst.StructInitAnon, |
| 19102 | .typed_init => Zir.Inst.StructInit, |
| 19103 | }, |
| 19104 | extra_end: usize, |
| 19105 | is_ref: bool, |
| 19106 | ) CompileError!Air.Inst.Ref { |
| 19107 | const mod = sema.mod; |
| 19108 | const gpa = sema.gpa; |
| 19109 | const zir_datas = sema.code.instructions.items(.data); |
| 19110 | |
| 19111 | const types = try sema.arena.alloc(InternPool.Index, extra_data.fields_len); |
| 19046 | 19112 | const values = try sema.arena.alloc(InternPool.Index, types.len); |
| 19113 | |
| 19047 | 19114 | var fields = std.AutoArrayHashMap(InternPool.NullTerminatedString, u32).init(sema.arena); |
| 19048 | 19115 | try fields.ensureUnusedCapacity(types.len); |
| 19049 | 19116 | |
| 19050 | 19117 | // Find which field forces the expression to be runtime, if any. |
| 19051 | 19118 | const opt_runtime_index = rs: { |
| 19052 | 19119 | var runtime_index: ?usize = null; |
| 19053 | | var extra_index = extra.end; |
| 19120 | var extra_index = extra_end; |
| 19054 | 19121 | for (types, 0..) |*field_ty, i_usize| { |
| 19055 | | const i = @as(u32, @intCast(i_usize)); |
| 19056 | | const item = sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index); |
| 19122 | const i: u32 = @intCast(i_usize); |
| 19123 | const item = switch (kind) { |
| 19124 | .anon_init => sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index), |
| 19125 | .typed_init => sema.code.extraData(Zir.Inst.StructInit.Item, extra_index), |
| 19126 | }; |
| 19057 | 19127 | extra_index = item.end; |
| 19058 | 19128 | |
| 19059 | | const name = sema.code.nullTerminatedString(item.data.field_name); |
| 19129 | const name = switch (kind) { |
| 19130 | .anon_init => sema.code.nullTerminatedString(item.data.field_name), |
| 19131 | .typed_init => name: { |
| 19132 | // `item.data.field_type` references a `field_type` instruction |
| 19133 | const field_type_data = zir_datas[item.data.field_type].pl_node; |
| 19134 | const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index); |
| 19135 | break :name sema.code.nullTerminatedString(field_type_extra.data.name_start); |
| 19136 | }, |
| 19137 | }; |
| 19060 | 19138 | const name_ip = try mod.intern_pool.getOrPutString(gpa, name); |
| 19061 | 19139 | const gop = fields.getOrPutAssumeCapacity(name_ip); |
| 19062 | 19140 | if (gop.found_existing) { |
| ... | ... | @@ -19129,10 +19207,13 @@ fn zirStructInitAnon( |
| 19129 | 19207 | .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) }, |
| 19130 | 19208 | }); |
| 19131 | 19209 | const alloc = try block.addTy(.alloc, alloc_ty); |
| 19132 | | var extra_index = extra.end; |
| 19210 | var extra_index = extra_end; |
| 19133 | 19211 | for (types, 0..) |field_ty, i_usize| { |
| 19134 | 19212 | const i = @as(u32, @intCast(i_usize)); |
| 19135 | | const item = sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index); |
| 19213 | const item = switch (kind) { |
| 19214 | .anon_init => sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index), |
| 19215 | .typed_init => sema.code.extraData(Zir.Inst.StructInit.Item, extra_index), |
| 19216 | }; |
| 19136 | 19217 | extra_index = item.end; |
| 19137 | 19218 | |
| 19138 | 19219 | const field_ptr_ty = try mod.ptrType(.{ |
| ... | ... | @@ -19150,9 +19231,12 @@ fn zirStructInitAnon( |
| 19150 | 19231 | } |
| 19151 | 19232 | |
| 19152 | 19233 | const element_refs = try sema.arena.alloc(Air.Inst.Ref, types.len); |
| 19153 | | var extra_index = extra.end; |
| 19234 | var extra_index = extra_end; |
| 19154 | 19235 | for (types, 0..) |_, i| { |
| 19155 | | const item = sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index); |
| 19236 | const item = switch (kind) { |
| 19237 | .anon_init => sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index), |
| 19238 | .typed_init => sema.code.extraData(Zir.Inst.StructInit.Item, extra_index), |
| 19239 | }; |
| 19156 | 19240 | extra_index = item.end; |
| 19157 | 19241 | element_refs[i] = try sema.resolveInst(item.data.init); |
| 19158 | 19242 | } |
| ... | ... | @@ -19175,7 +19259,13 @@ fn zirArrayInit( |
| 19175 | 19259 | const args = sema.code.refSlice(extra.end, extra.data.operands_len); |
| 19176 | 19260 | assert(args.len >= 2); // array_ty + at least one element |
| 19177 | 19261 | |
| 19178 | | const array_ty = try sema.resolveType(block, src, args[0]); |
| 19262 | const array_ty = sema.resolveType(block, src, args[0]) catch |err| switch (err) { |
| 19263 | error.GenericPoison => { |
| 19264 | // The type wasn't actually known, so treat this as an anon array init. |
| 19265 | return sema.arrayInitAnon(block, src, args[1..], is_ref); |
| 19266 | }, |
| 19267 | else => |e| return e, |
| 19268 | }; |
| 19179 | 19269 | const sentinel_val = array_ty.sentinel(mod); |
| 19180 | 19270 | |
| 19181 | 19271 | const resolved_args = try gpa.alloc(Air.Inst.Ref, args.len - 1 + @intFromBool(sentinel_val != null)); |
| ... | ... | @@ -19283,6 +19373,16 @@ fn zirArrayInitAnon( |
| 19283 | 19373 | const src = inst_data.src(); |
| 19284 | 19374 | const extra = sema.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index); |
| 19285 | 19375 | const operands = sema.code.refSlice(extra.end, extra.data.operands_len); |
| 19376 | return sema.arrayInitAnon(block, src, operands, is_ref); |
| 19377 | } |
| 19378 | |
| 19379 | fn arrayInitAnon( |
| 19380 | sema: *Sema, |
| 19381 | block: *Block, |
| 19382 | src: LazySrcLoc, |
| 19383 | operands: []const Zir.Inst.Ref, |
| 19384 | is_ref: bool, |
| 19385 | ) CompileError!Air.Inst.Ref { |
| 19286 | 19386 | const mod = sema.mod; |
| 19287 | 19387 | |
| 19288 | 19388 | const types = try sema.arena.alloc(InternPool.Index, operands.len); |