| ... | @@ -1125,6 +1125,7 @@ fn analyzeBodyInner( | ... | @@ -1125,6 +1125,7 @@ fn analyzeBodyInner( |
| 1125 | .array_base_ptr => try sema.zirArrayBasePtr(block, inst), | 1125 | .array_base_ptr => try sema.zirArrayBasePtr(block, inst), |
| 1126 | .field_base_ptr => try sema.zirFieldBasePtr(block, inst), | 1126 | .field_base_ptr => try sema.zirFieldBasePtr(block, inst), |
| 1127 | .for_len => try sema.zirForLen(block, inst), | 1127 | .for_len => try sema.zirForLen(block, inst), |
| | 1128 | .opt_eu_base_ty => try sema.zirOptEuBaseTy(block, inst), |
| 1128 | | 1129 | |
| 1129 | .clz => try sema.zirBitCount(block, inst, .clz, Value.clz), | 1130 | .clz => try sema.zirBitCount(block, inst, .clz, Value.clz), |
| 1130 | .ctz => try sema.zirBitCount(block, inst, .ctz, Value.ctz), | 1131 | .ctz => try sema.zirBitCount(block, inst, .ctz, Value.ctz), |
| ... | @@ -1359,12 +1360,12 @@ fn analyzeBodyInner( | ... | @@ -1359,12 +1360,12 @@ fn analyzeBodyInner( |
| 1359 | continue; | 1360 | continue; |
| 1360 | }, | 1361 | }, |
| 1361 | .validate_array_init_ty => { | 1362 | .validate_array_init_ty => { |
| 1362 | try sema.validateArrayInitTy(block, inst); | 1363 | try sema.zirValidateArrayInitTy(block, inst); |
| 1363 | i += 1; | 1364 | i += 1; |
| 1364 | continue; | 1365 | continue; |
| 1365 | }, | 1366 | }, |
| 1366 | .validate_struct_init_ty => { | 1367 | .validate_struct_init_ty => { |
| 1367 | try sema.validateStructInitTy(block, inst); | 1368 | try sema.zirValidateStructInitTy(block, inst); |
| 1368 | i += 1; | 1369 | i += 1; |
| 1369 | continue; | 1370 | continue; |
| 1370 | }, | 1371 | }, |
| ... | @@ -4312,7 +4313,31 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. | ... | @@ -4312,7 +4313,31 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 4312 | return len; | 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 | sema: *Sema, | 4341 | sema: *Sema, |
| 4317 | block: *Block, | 4342 | block: *Block, |
| 4318 | inst: Zir.Inst.Index, | 4343 | inst: Zir.Inst.Index, |
| ... | @@ -4322,7 +4347,11 @@ fn validateArrayInitTy( | ... | @@ -4322,7 +4347,11 @@ fn validateArrayInitTy( |
| 4322 | const src = inst_data.src(); | 4347 | const src = inst_data.src(); |
| 4323 | const ty_src: LazySrcLoc = .{ .node_offset_init_ty = inst_data.src_node }; | 4348 | const ty_src: LazySrcLoc = .{ .node_offset_init_ty = inst_data.src_node }; |
| 4324 | const extra = sema.code.extraData(Zir.Inst.ArrayInit, inst_data.payload_index).data; | 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 | switch (ty.zigTypeTag(mod)) { | 4356 | switch (ty.zigTypeTag(mod)) { |
| 4328 | .Array => { | 4357 | .Array => { |
| ... | @@ -4358,7 +4387,7 @@ fn validateArrayInitTy( | ... | @@ -4358,7 +4387,7 @@ fn validateArrayInitTy( |
| 4358 | return sema.failWithArrayInitNotSupported(block, ty_src, ty); | 4387 | return sema.failWithArrayInitNotSupported(block, ty_src, ty); |
| 4359 | } | 4388 | } |
| 4360 | | 4389 | |
| 4361 | fn validateStructInitTy( | 4390 | fn zirValidateStructInitTy( |
| 4362 | sema: *Sema, | 4391 | sema: *Sema, |
| 4363 | block: *Block, | 4392 | block: *Block, |
| 4364 | inst: Zir.Inst.Index, | 4393 | inst: Zir.Inst.Index, |
| ... | @@ -4366,7 +4395,11 @@ fn validateStructInitTy( | ... | @@ -4366,7 +4395,11 @@ fn validateStructInitTy( |
| 4366 | const mod = sema.mod; | 4395 | const mod = sema.mod; |
| 4367 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 4396 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 4368 | const src = inst_data.src(); | 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 | switch (ty.zigTypeTag(mod)) { | 4404 | switch (ty.zigTypeTag(mod)) { |
| 4372 | .Struct, .Union => return, | 4405 | .Struct, .Union => return, |
| ... | @@ -7744,7 +7777,15 @@ fn zirOptionalType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro | ... | @@ -7744,7 +7777,15 @@ fn zirOptionalType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro |
| 7744 | fn zirElemTypeIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 7777 | fn zirElemTypeIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 7745 | const mod = sema.mod; | 7778 | const mod = sema.mod; |
| 7746 | const bin = sema.code.instructions.items(.data)[inst].bin; | 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 | assert(indexable_ty.isIndexable(mod)); // validated by a previous instruction | 7789 | assert(indexable_ty.isIndexable(mod)); // validated by a previous instruction |
| 7749 | if (indexable_ty.zigTypeTag(mod) == .Struct) { | 7790 | if (indexable_ty.zigTypeTag(mod) == .Struct) { |
| 7750 | const elem_type = indexable_ty.structFieldType(@intFromEnum(bin.rhs), mod); | 7791 | const elem_type = indexable_ty.structFieldType(@intFromEnum(bin.rhs), mod); |
| ... | @@ -18794,7 +18835,13 @@ fn zirStructInit( | ... | @@ -18794,7 +18835,13 @@ fn zirStructInit( |
| 18794 | const first_item = sema.code.extraData(Zir.Inst.StructInit.Item, extra.end).data; | 18835 | const first_item = sema.code.extraData(Zir.Inst.StructInit.Item, extra.end).data; |
| 18795 | const first_field_type_data = zir_datas[first_item.field_type].pl_node; | 18836 | const first_field_type_data = zir_datas[first_item.field_type].pl_node; |
| 18796 | const first_field_type_extra = sema.code.extraData(Zir.Inst.FieldType, first_field_type_data.payload_index).data; | 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 | try sema.resolveTypeLayout(resolved_ty); | 18845 | try sema.resolveTypeLayout(resolved_ty); |
| 18799 | | 18846 | |
| 18800 | if (resolved_ty.zigTypeTag(mod) == .Struct) { | 18847 | if (resolved_ty.zigTypeTag(mod) == .Struct) { |
| ... | @@ -19037,26 +19084,57 @@ fn zirStructInitAnon( | ... | @@ -19037,26 +19084,57 @@ fn zirStructInitAnon( |
| 19037 | inst: Zir.Inst.Index, | 19084 | inst: Zir.Inst.Index, |
| 19038 | is_ref: bool, | 19085 | is_ref: bool, |
| 19039 | ) CompileError!Air.Inst.Ref { | 19086 | ) CompileError!Air.Inst.Ref { |
| 19040 | const mod = sema.mod; | | |
| 19041 | const gpa = sema.gpa; | | |
| 19042 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 19087 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 19043 | const src = inst_data.src(); | 19088 | const src = inst_data.src(); |
| 19044 | const extra = sema.code.extraData(Zir.Inst.StructInitAnon, inst_data.payload_index); | 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 | const values = try sema.arena.alloc(InternPool.Index, types.len); | 19112 | const values = try sema.arena.alloc(InternPool.Index, types.len); |
| | 19113 | |
| 19047 | var fields = std.AutoArrayHashMap(InternPool.NullTerminatedString, u32).init(sema.arena); | 19114 | var fields = std.AutoArrayHashMap(InternPool.NullTerminatedString, u32).init(sema.arena); |
| 19048 | try fields.ensureUnusedCapacity(types.len); | 19115 | try fields.ensureUnusedCapacity(types.len); |
| 19049 | | 19116 | |
| 19050 | // Find which field forces the expression to be runtime, if any. | 19117 | // Find which field forces the expression to be runtime, if any. |
| 19051 | const opt_runtime_index = rs: { | 19118 | const opt_runtime_index = rs: { |
| 19052 | var runtime_index: ?usize = null; | 19119 | var runtime_index: ?usize = null; |
| 19053 | var extra_index = extra.end; | 19120 | var extra_index = extra_end; |
| 19054 | for (types, 0..) |*field_ty, i_usize| { | 19121 | for (types, 0..) |*field_ty, i_usize| { |
| 19055 | const i = @as(u32, @intCast(i_usize)); | 19122 | const i: u32 = @intCast(i_usize); |
| 19056 | const item = sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index); | 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 | extra_index = item.end; | 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 | const name_ip = try mod.intern_pool.getOrPutString(gpa, name); | 19138 | const name_ip = try mod.intern_pool.getOrPutString(gpa, name); |
| 19061 | const gop = fields.getOrPutAssumeCapacity(name_ip); | 19139 | const gop = fields.getOrPutAssumeCapacity(name_ip); |
| 19062 | if (gop.found_existing) { | 19140 | if (gop.found_existing) { |
| ... | @@ -19129,10 +19207,13 @@ fn zirStructInitAnon( | ... | @@ -19129,10 +19207,13 @@ fn zirStructInitAnon( |
| 19129 | .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) }, | 19207 | .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) }, |
| 19130 | }); | 19208 | }); |
| 19131 | const alloc = try block.addTy(.alloc, alloc_ty); | 19209 | const alloc = try block.addTy(.alloc, alloc_ty); |
| 19132 | var extra_index = extra.end; | 19210 | var extra_index = extra_end; |
| 19133 | for (types, 0..) |field_ty, i_usize| { | 19211 | for (types, 0..) |field_ty, i_usize| { |
| 19134 | const i = @as(u32, @intCast(i_usize)); | 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 | extra_index = item.end; | 19217 | extra_index = item.end; |
| 19137 | | 19218 | |
| 19138 | const field_ptr_ty = try mod.ptrType(.{ | 19219 | const field_ptr_ty = try mod.ptrType(.{ |
| ... | @@ -19150,9 +19231,12 @@ fn zirStructInitAnon( | ... | @@ -19150,9 +19231,12 @@ fn zirStructInitAnon( |
| 19150 | } | 19231 | } |
| 19151 | | 19232 | |
| 19152 | const element_refs = try sema.arena.alloc(Air.Inst.Ref, types.len); | 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 | for (types, 0..) |_, i| { | 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 | extra_index = item.end; | 19240 | extra_index = item.end; |
| 19157 | element_refs[i] = try sema.resolveInst(item.data.init); | 19241 | element_refs[i] = try sema.resolveInst(item.data.init); |
| 19158 | } | 19242 | } |
| ... | @@ -19175,7 +19259,13 @@ fn zirArrayInit( | ... | @@ -19175,7 +19259,13 @@ fn zirArrayInit( |
| 19175 | const args = sema.code.refSlice(extra.end, extra.data.operands_len); | 19259 | const args = sema.code.refSlice(extra.end, extra.data.operands_len); |
| 19176 | assert(args.len >= 2); // array_ty + at least one element | 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 | const sentinel_val = array_ty.sentinel(mod); | 19269 | const sentinel_val = array_ty.sentinel(mod); |
| 19180 | | 19270 | |
| 19181 | const resolved_args = try gpa.alloc(Air.Inst.Ref, args.len - 1 + @intFromBool(sentinel_val != null)); | 19271 | const resolved_args = try gpa.alloc(Air.Inst.Ref, args.len - 1 + @intFromBool(sentinel_val != null)); |
| ... | @@ -19283,6 +19373,16 @@ fn zirArrayInitAnon( | ... | @@ -19283,6 +19373,16 @@ fn zirArrayInitAnon( |
| 19283 | const src = inst_data.src(); | 19373 | const src = inst_data.src(); |
| 19284 | const extra = sema.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index); | 19374 | const extra = sema.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index); |
| 19285 | const operands = sema.code.refSlice(extra.end, extra.data.operands_len); | 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 | const mod = sema.mod; | 19386 | const mod = sema.mod; |
| 19287 | | 19387 | |
| 19288 | const types = try sema.arena.alloc(InternPool.Index, operands.len); | 19388 | const types = try sema.arena.alloc(InternPool.Index, operands.len); |