| author | |
| committer | |
| log | 510ea6f61f93c722c4cb2c2b39605201cc2f9c32 |
| tree | 476e4e20e0f9a872c13033c800212f7540eb06f5 |
| parent | 5e8397d5e03269d8a39efb22605ea20102848084 |
| signature |
29 files changed, 7266 insertions(+), 11278 deletions(-)
lib/std/math/big/int.zig+12-2| ... | ... | @@ -924,7 +924,12 @@ pub const Mutable = struct { |
| 924 | 924 | /// Asserts the result fits in `r`. Upper bound on the number of limbs needed by |
| 925 | 925 | /// r is `calcTwosCompLimbCount(bit_count)`. |
| 926 | 926 | pub fn bitReverse(r: *Mutable, a: Const, signedness: Signedness, bit_count: usize) void { |
| 927 | if (bit_count == 0) return; | |
| 927 | if (bit_count == 0) { | |
| 928 | r.limbs[0] = 0; | |
| 929 | r.len = 1; | |
| 930 | r.positive = true; | |
| 931 | return; | |
| 932 | } | |
| 928 | 933 | |
| 929 | 934 | r.copy(a); |
| 930 | 935 | |
| ... | ... | @@ -986,7 +991,12 @@ pub const Mutable = struct { |
| 986 | 991 | /// Asserts the result fits in `r`. Upper bound on the number of limbs needed by |
| 987 | 992 | /// r is `calcTwosCompLimbCount(8*byte_count)`. |
| 988 | 993 | pub fn byteSwap(r: *Mutable, a: Const, signedness: Signedness, byte_count: usize) void { |
| 989 | if (byte_count == 0) return; | |
| 994 | if (byte_count == 0) { | |
| 995 | r.limbs[0] = 0; | |
| 996 | r.len = 1; | |
| 997 | r.positive = true; | |
| 998 | return; | |
| 999 | } | |
| 990 | 1000 | |
| 991 | 1001 | r.copy(a); |
| 992 | 1002 | const limbs_required = calcTwosCompLimbCount(8 * byte_count); |
lib/std/zig/Zir.zig+1-15| ... | ... | @@ -3710,7 +3710,7 @@ pub const Inst = struct { |
| 3710 | 3710 | }; |
| 3711 | 3711 | } |
| 3712 | 3712 | |
| 3713 | pub fn layout(k: Kind) std.builtin.ContainerLayout { | |
| 3713 | pub fn layout(k: Kind) std.builtin.Type.ContainerLayout { | |
| 3714 | 3714 | return switch (k) { |
| 3715 | 3715 | .auto, .tagged_explicit, .tagged_enum, .tagged_enum_explicit => .auto, |
| 3716 | 3716 | .@"extern" => .@"extern", |
| ... | ... | @@ -4008,20 +4008,6 @@ pub const Inst = struct { |
| 4008 | 4008 | }; |
| 4009 | 4009 | }; |
| 4010 | 4010 | |
| 4011 | /// MLUGG TODO: delete this! | |
| 4012 | pub const DeclIterator = struct { | |
| 4013 | decls: []const Inst.Index, | |
| 4014 | index: usize, | |
| 4015 | pub fn next(it: *DeclIterator) ?Inst.Index { | |
| 4016 | if (it.index == it.decls.len) return null; | |
| 4017 | defer it.index += 1; | |
| 4018 | return it.decls[it.index]; | |
| 4019 | } | |
| 4020 | }; | |
| 4021 | pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator { | |
| 4022 | return .{ .decls = zir.typeDecls(decl_inst), .index = 0 }; | |
| 4023 | } | |
| 4024 | ||
| 4025 | 4011 | /// `DeclContents` contains all "interesting" instructions found within a declaration by `findTrackable`. |
| 4026 | 4012 | /// These instructions are partitioned into a few different sets, since this makes ZIR instruction mapping |
| 4027 | 4013 | /// more effective. |
lib/std/zig/target.zig+2-4| ... | ... | @@ -503,8 +503,7 @@ pub fn intByteSize(target: *const std.Target, bits: u16) u16 { |
| 503 | 503 | pub fn intAlignment(target: *const std.Target, bits: u16) u16 { |
| 504 | 504 | return switch (target.cpu.arch) { |
| 505 | 505 | .x86 => switch (bits) { |
| 506 | 0 => 0, | |
| 507 | 1...8 => 1, | |
| 506 | 0...8 => 1, | |
| 508 | 507 | 9...16 => 2, |
| 509 | 508 | 17...32 => 4, |
| 510 | 509 | 33...64 => switch (target.os.tag) { |
| ... | ... | @@ -514,8 +513,7 @@ pub fn intAlignment(target: *const std.Target, bits: u16) u16 { |
| 514 | 513 | else => 16, |
| 515 | 514 | }, |
| 516 | 515 | .x86_64 => switch (bits) { |
| 517 | 0 => 0, | |
| 518 | 1...8 => 1, | |
| 516 | 0...8 => 1, | |
| 519 | 517 | 9...16 => 2, |
| 520 | 518 | 17...32 => 4, |
| 521 | 519 | 33...64 => 8, |
src/Air.zig+5-8| ... | ... | @@ -14,7 +14,6 @@ const Type = @import("Type.zig"); |
| 14 | 14 | const Value = @import("Value.zig"); |
| 15 | 15 | const Zcu = @import("Zcu.zig"); |
| 16 | 16 | const print = @import("Air/print.zig"); |
| 17 | const types_resolved = @import("Air/types_resolved.zig"); | |
| 18 | 17 | |
| 19 | 18 | pub const Legalize = @import("Air/Legalize.zig"); |
| 20 | 19 | pub const Liveness = @import("Air/Liveness.zig"); |
| ... | ... | @@ -173,8 +172,8 @@ pub const Inst = struct { |
| 173 | 172 | /// outside the provenance of the operand, the result is undefined. |
| 174 | 173 | /// |
| 175 | 174 | /// Uses the `ty_pl` field. Payload is `Bin`. The lhs is the pointer, |
| 176 | /// rhs is the offset. Result type is the same as lhs. The operand may | |
| 177 | /// be a slice. | |
| 175 | /// rhs is the offset. Result type is the same as lhs. The operand type's | |
| 176 | /// pointer size may be `.slice`, `.many`, or `.c`. | |
| 178 | 177 | ptr_add, |
| 179 | 178 | /// Subtract an offset, in element type units, from a pointer, |
| 180 | 179 | /// returning a new pointer. Element type may not be zero bits. |
| ... | ... | @@ -183,8 +182,8 @@ pub const Inst = struct { |
| 183 | 182 | /// outside the provenance of the operand, the result is undefined. |
| 184 | 183 | /// |
| 185 | 184 | /// Uses the `ty_pl` field. Payload is `Bin`. The lhs is the pointer, |
| 186 | /// rhs is the offset. Result type is the same as lhs. The operand may | |
| 187 | /// be a slice. | |
| 185 | /// rhs is the offset. Result type is the same as lhs. The operand type's | |
| 186 | /// pointer size may be `.slice`, `.many`, or `.c`. | |
| 188 | 187 | ptr_sub, |
| 189 | 188 | /// Given two operands which can be floats, integers, or vectors, returns the |
| 190 | 189 | /// greater of the operands. For vectors it operates element-wise. |
| ... | ... | @@ -693,6 +692,7 @@ pub const Inst = struct { |
| 693 | 692 | /// Uses the `ty_pl` field with payload `Bin`. |
| 694 | 693 | slice_elem_ptr, |
| 695 | 694 | /// Given a pointer value, and element index, return the element value at that index. |
| 695 | /// The pointer size is either `.c` or `.many`. | |
| 696 | 696 | /// Result type is the element type of the pointer operand. |
| 697 | 697 | /// Uses the `bin_op` field. |
| 698 | 698 | ptr_elem_val, |
| ... | ... | @@ -2440,9 +2440,6 @@ pub fn unwrapShuffleTwo(air: *const Air, zcu: *const Zcu, inst_index: Inst.Index |
| 2440 | 2440 | }; |
| 2441 | 2441 | } |
| 2442 | 2442 | |
| 2443 | pub const typesFullyResolved = types_resolved.typesFullyResolved; | |
| 2444 | pub const typeFullyResolved = types_resolved.checkType; | |
| 2445 | pub const valFullyResolved = types_resolved.checkVal; | |
| 2446 | 2443 | pub const legalize = Legalize.legalize; |
| 2447 | 2444 | pub const write = print.write; |
| 2448 | 2445 | pub const writeInst = print.writeInst; |
src/Air/types_resolved.zig deleted-536| ... | ... | @@ -1,536 +0,0 @@ |
| 1 | const Air = @import("../Air.zig"); | |
| 2 | const Zcu = @import("../Zcu.zig"); | |
| 3 | const Type = @import("../Type.zig"); | |
| 4 | const Value = @import("../Value.zig"); | |
| 5 | const InternPool = @import("../InternPool.zig"); | |
| 6 | ||
| 7 | /// Given a body of AIR instructions, returns whether all type resolution necessary for codegen is complete. | |
| 8 | /// If `false`, then type resolution must have failed, so codegen cannot proceed. | |
| 9 | pub fn typesFullyResolved(air: Air, zcu: *Zcu) bool { | |
| 10 | return checkBody(air, air.getMainBody(), zcu); | |
| 11 | } | |
| 12 | ||
| 13 | fn checkBody(air: Air, body: []const Air.Inst.Index, zcu: *Zcu) bool { | |
| 14 | const tags = air.instructions.items(.tag); | |
| 15 | const datas = air.instructions.items(.data); | |
| 16 | ||
| 17 | for (body) |inst| { | |
| 18 | const data = datas[@intFromEnum(inst)]; | |
| 19 | switch (tags[@intFromEnum(inst)]) { | |
| 20 | .inferred_alloc, .inferred_alloc_comptime => unreachable, | |
| 21 | ||
| 22 | .arg => { | |
| 23 | if (!checkType(data.arg.ty.toType(), zcu)) return false; | |
| 24 | }, | |
| 25 | ||
| 26 | .add, | |
| 27 | .add_safe, | |
| 28 | .add_optimized, | |
| 29 | .add_wrap, | |
| 30 | .add_sat, | |
| 31 | .sub, | |
| 32 | .sub_safe, | |
| 33 | .sub_optimized, | |
| 34 | .sub_wrap, | |
| 35 | .sub_sat, | |
| 36 | .mul, | |
| 37 | .mul_safe, | |
| 38 | .mul_optimized, | |
| 39 | .mul_wrap, | |
| 40 | .mul_sat, | |
| 41 | .div_float, | |
| 42 | .div_float_optimized, | |
| 43 | .div_trunc, | |
| 44 | .div_trunc_optimized, | |
| 45 | .div_floor, | |
| 46 | .div_floor_optimized, | |
| 47 | .div_exact, | |
| 48 | .div_exact_optimized, | |
| 49 | .rem, | |
| 50 | .rem_optimized, | |
| 51 | .mod, | |
| 52 | .mod_optimized, | |
| 53 | .max, | |
| 54 | .min, | |
| 55 | .bit_and, | |
| 56 | .bit_or, | |
| 57 | .shr, | |
| 58 | .shr_exact, | |
| 59 | .shl, | |
| 60 | .shl_exact, | |
| 61 | .shl_sat, | |
| 62 | .xor, | |
| 63 | .cmp_lt, | |
| 64 | .cmp_lt_optimized, | |
| 65 | .cmp_lte, | |
| 66 | .cmp_lte_optimized, | |
| 67 | .cmp_eq, | |
| 68 | .cmp_eq_optimized, | |
| 69 | .cmp_gte, | |
| 70 | .cmp_gte_optimized, | |
| 71 | .cmp_gt, | |
| 72 | .cmp_gt_optimized, | |
| 73 | .cmp_neq, | |
| 74 | .cmp_neq_optimized, | |
| 75 | .bool_and, | |
| 76 | .bool_or, | |
| 77 | .store, | |
| 78 | .store_safe, | |
| 79 | .set_union_tag, | |
| 80 | .array_elem_val, | |
| 81 | .slice_elem_val, | |
| 82 | .ptr_elem_val, | |
| 83 | .memset, | |
| 84 | .memset_safe, | |
| 85 | .memcpy, | |
| 86 | .memmove, | |
| 87 | .atomic_store_unordered, | |
| 88 | .atomic_store_monotonic, | |
| 89 | .atomic_store_release, | |
| 90 | .atomic_store_seq_cst, | |
| 91 | .legalize_vec_elem_val, | |
| 92 | => { | |
| 93 | if (!checkRef(data.bin_op.lhs, zcu)) return false; | |
| 94 | if (!checkRef(data.bin_op.rhs, zcu)) return false; | |
| 95 | }, | |
| 96 | ||
| 97 | .not, | |
| 98 | .bitcast, | |
| 99 | .clz, | |
| 100 | .ctz, | |
| 101 | .popcount, | |
| 102 | .byte_swap, | |
| 103 | .bit_reverse, | |
| 104 | .abs, | |
| 105 | .load, | |
| 106 | .fptrunc, | |
| 107 | .fpext, | |
| 108 | .intcast, | |
| 109 | .intcast_safe, | |
| 110 | .trunc, | |
| 111 | .optional_payload, | |
| 112 | .optional_payload_ptr, | |
| 113 | .optional_payload_ptr_set, | |
| 114 | .wrap_optional, | |
| 115 | .unwrap_errunion_payload, | |
| 116 | .unwrap_errunion_err, | |
| 117 | .unwrap_errunion_payload_ptr, | |
| 118 | .unwrap_errunion_err_ptr, | |
| 119 | .errunion_payload_ptr_set, | |
| 120 | .wrap_errunion_payload, | |
| 121 | .wrap_errunion_err, | |
| 122 | .struct_field_ptr_index_0, | |
| 123 | .struct_field_ptr_index_1, | |
| 124 | .struct_field_ptr_index_2, | |
| 125 | .struct_field_ptr_index_3, | |
| 126 | .get_union_tag, | |
| 127 | .slice_len, | |
| 128 | .slice_ptr, | |
| 129 | .ptr_slice_len_ptr, | |
| 130 | .ptr_slice_ptr_ptr, | |
| 131 | .array_to_slice, | |
| 132 | .int_from_float, | |
| 133 | .int_from_float_optimized, | |
| 134 | .int_from_float_safe, | |
| 135 | .int_from_float_optimized_safe, | |
| 136 | .float_from_int, | |
| 137 | .splat, | |
| 138 | .error_set_has_value, | |
| 139 | .addrspace_cast, | |
| 140 | .c_va_arg, | |
| 141 | .c_va_copy, | |
| 142 | => { | |
| 143 | if (!checkType(data.ty_op.ty.toType(), zcu)) return false; | |
| 144 | if (!checkRef(data.ty_op.operand, zcu)) return false; | |
| 145 | }, | |
| 146 | ||
| 147 | .alloc, | |
| 148 | .ret_ptr, | |
| 149 | .c_va_start, | |
| 150 | => { | |
| 151 | if (!checkType(data.ty, zcu)) return false; | |
| 152 | }, | |
| 153 | ||
| 154 | .ptr_add, | |
| 155 | .ptr_sub, | |
| 156 | .add_with_overflow, | |
| 157 | .sub_with_overflow, | |
| 158 | .mul_with_overflow, | |
| 159 | .shl_with_overflow, | |
| 160 | .slice, | |
| 161 | .slice_elem_ptr, | |
| 162 | .ptr_elem_ptr, | |
| 163 | => { | |
| 164 | const bin = air.extraData(Air.Bin, data.ty_pl.payload).data; | |
| 165 | if (!checkType(data.ty_pl.ty.toType(), zcu)) return false; | |
| 166 | if (!checkRef(bin.lhs, zcu)) return false; | |
| 167 | if (!checkRef(bin.rhs, zcu)) return false; | |
| 168 | }, | |
| 169 | ||
| 170 | .block, | |
| 171 | .loop, | |
| 172 | => { | |
| 173 | const block = air.unwrapBlock(inst); | |
| 174 | if (!checkType(block.ty, zcu)) return false; | |
| 175 | if (!checkBody( | |
| 176 | air, | |
| 177 | block.body, | |
| 178 | zcu, | |
| 179 | )) return false; | |
| 180 | }, | |
| 181 | ||
| 182 | .dbg_inline_block => { | |
| 183 | const block = air.unwrapDbgBlock(inst); | |
| 184 | if (!checkType(block.ty, zcu)) return false; | |
| 185 | if (!checkBody( | |
| 186 | air, | |
| 187 | block.body, | |
| 188 | zcu, | |
| 189 | )) return false; | |
| 190 | }, | |
| 191 | ||
| 192 | .sqrt, | |
| 193 | .sin, | |
| 194 | .cos, | |
| 195 | .tan, | |
| 196 | .exp, | |
| 197 | .exp2, | |
| 198 | .log, | |
| 199 | .log2, | |
| 200 | .log10, | |
| 201 | .floor, | |
| 202 | .ceil, | |
| 203 | .round, | |
| 204 | .trunc_float, | |
| 205 | .neg, | |
| 206 | .neg_optimized, | |
| 207 | .is_null, | |
| 208 | .is_non_null, | |
| 209 | .is_null_ptr, | |
| 210 | .is_non_null_ptr, | |
| 211 | .is_err, | |
| 212 | .is_non_err, | |
| 213 | .is_err_ptr, | |
| 214 | .is_non_err_ptr, | |
| 215 | .ret, | |
| 216 | .ret_safe, | |
| 217 | .ret_load, | |
| 218 | .is_named_enum_value, | |
| 219 | .tag_name, | |
| 220 | .error_name, | |
| 221 | .cmp_lt_errors_len, | |
| 222 | .c_va_end, | |
| 223 | .set_err_return_trace, | |
| 224 | => { | |
| 225 | if (!checkRef(data.un_op, zcu)) return false; | |
| 226 | }, | |
| 227 | ||
| 228 | .br, .switch_dispatch => { | |
| 229 | if (!checkRef(data.br.operand, zcu)) return false; | |
| 230 | }, | |
| 231 | ||
| 232 | .cmp_vector, | |
| 233 | .cmp_vector_optimized, | |
| 234 | => { | |
| 235 | const extra = air.extraData(Air.VectorCmp, data.ty_pl.payload).data; | |
| 236 | if (!checkType(data.ty_pl.ty.toType(), zcu)) return false; | |
| 237 | if (!checkRef(extra.lhs, zcu)) return false; | |
| 238 | if (!checkRef(extra.rhs, zcu)) return false; | |
| 239 | }, | |
| 240 | ||
| 241 | .reduce, | |
| 242 | .reduce_optimized, | |
| 243 | => { | |
| 244 | if (!checkRef(data.reduce.operand, zcu)) return false; | |
| 245 | }, | |
| 246 | ||
| 247 | .struct_field_ptr, | |
| 248 | .struct_field_val, | |
| 249 | => { | |
| 250 | const extra = air.extraData(Air.StructField, data.ty_pl.payload).data; | |
| 251 | if (!checkType(data.ty_pl.ty.toType(), zcu)) return false; | |
| 252 | if (!checkRef(extra.struct_operand, zcu)) return false; | |
| 253 | }, | |
| 254 | ||
| 255 | .shuffle_one => { | |
| 256 | const unwrapped = air.unwrapShuffleOne(zcu, inst); | |
| 257 | if (!checkType(unwrapped.result_ty, zcu)) return false; | |
| 258 | if (!checkRef(unwrapped.operand, zcu)) return false; | |
| 259 | for (unwrapped.mask) |m| switch (m.unwrap()) { | |
| 260 | .elem => {}, | |
| 261 | .value => |val| if (!checkVal(.fromInterned(val), zcu)) return false, | |
| 262 | }; | |
| 263 | }, | |
| 264 | ||
| 265 | .shuffle_two => { | |
| 266 | const unwrapped = air.unwrapShuffleTwo(zcu, inst); | |
| 267 | if (!checkType(unwrapped.result_ty, zcu)) return false; | |
| 268 | if (!checkRef(unwrapped.operand_a, zcu)) return false; | |
| 269 | if (!checkRef(unwrapped.operand_b, zcu)) return false; | |
| 270 | // No values to check because there are no comptime-known values other than undef | |
| 271 | }, | |
| 272 | ||
| 273 | .cmpxchg_weak, | |
| 274 | .cmpxchg_strong, | |
| 275 | => { | |
| 276 | const extra = air.extraData(Air.Cmpxchg, data.ty_pl.payload).data; | |
| 277 | if (!checkType(data.ty_pl.ty.toType(), zcu)) return false; | |
| 278 | if (!checkRef(extra.ptr, zcu)) return false; | |
| 279 | if (!checkRef(extra.expected_value, zcu)) return false; | |
| 280 | if (!checkRef(extra.new_value, zcu)) return false; | |
| 281 | }, | |
| 282 | ||
| 283 | .aggregate_init => { | |
| 284 | const ty = data.ty_pl.ty.toType(); | |
| 285 | const elems_len: usize = @intCast(ty.arrayLen(zcu)); | |
| 286 | const elems: []const Air.Inst.Ref = @ptrCast(air.extra.items[data.ty_pl.payload..][0..elems_len]); | |
| 287 | if (!checkType(ty, zcu)) return false; | |
| 288 | if (ty.zigTypeTag(zcu) == .@"struct") { | |
| 289 | for (elems, 0..) |elem, elem_idx| { | |
| 290 | if (ty.structFieldIsComptime(elem_idx, zcu)) continue; | |
| 291 | if (!checkRef(elem, zcu)) return false; | |
| 292 | } | |
| 293 | } else { | |
| 294 | for (elems) |elem| { | |
| 295 | if (!checkRef(elem, zcu)) return false; | |
| 296 | } | |
| 297 | } | |
| 298 | }, | |
| 299 | ||
| 300 | .union_init => { | |
| 301 | const extra = air.extraData(Air.UnionInit, data.ty_pl.payload).data; | |
| 302 | if (!checkType(data.ty_pl.ty.toType(), zcu)) return false; | |
| 303 | if (!checkRef(extra.init, zcu)) return false; | |
| 304 | }, | |
| 305 | ||
| 306 | .field_parent_ptr => { | |
| 307 | const extra = air.extraData(Air.FieldParentPtr, data.ty_pl.payload).data; | |
| 308 | if (!checkType(data.ty_pl.ty.toType(), zcu)) return false; | |
| 309 | if (!checkRef(extra.field_ptr, zcu)) return false; | |
| 310 | }, | |
| 311 | ||
| 312 | .atomic_load => { | |
| 313 | if (!checkRef(data.atomic_load.ptr, zcu)) return false; | |
| 314 | }, | |
| 315 | ||
| 316 | .prefetch => { | |
| 317 | if (!checkRef(data.prefetch.ptr, zcu)) return false; | |
| 318 | }, | |
| 319 | ||
| 320 | .runtime_nav_ptr => { | |
| 321 | if (!checkType(.fromInterned(data.ty_nav.ty), zcu)) return false; | |
| 322 | }, | |
| 323 | ||
| 324 | .select, | |
| 325 | .mul_add, | |
| 326 | .legalize_vec_store_elem, | |
| 327 | => { | |
| 328 | const bin = air.extraData(Air.Bin, data.pl_op.payload).data; | |
| 329 | if (!checkRef(data.pl_op.operand, zcu)) return false; | |
| 330 | if (!checkRef(bin.lhs, zcu)) return false; | |
| 331 | if (!checkRef(bin.rhs, zcu)) return false; | |
| 332 | }, | |
| 333 | ||
| 334 | .atomic_rmw => { | |
| 335 | const extra = air.extraData(Air.AtomicRmw, data.pl_op.payload).data; | |
| 336 | if (!checkRef(data.pl_op.operand, zcu)) return false; | |
| 337 | if (!checkRef(extra.operand, zcu)) return false; | |
| 338 | }, | |
| 339 | ||
| 340 | .call, | |
| 341 | .call_always_tail, | |
| 342 | .call_never_tail, | |
| 343 | .call_never_inline, | |
| 344 | => { | |
| 345 | const call = air.unwrapCall(inst); | |
| 346 | const args = call.args; | |
| 347 | if (!checkRef(call.callee, zcu)) return false; | |
| 348 | for (args) |arg| if (!checkRef(arg, zcu)) return false; | |
| 349 | }, | |
| 350 | ||
| 351 | .dbg_var_ptr, | |
| 352 | .dbg_var_val, | |
| 353 | .dbg_arg_inline, | |
| 354 | => { | |
| 355 | if (!checkRef(data.pl_op.operand, zcu)) return false; | |
| 356 | }, | |
| 357 | ||
| 358 | .@"try", .try_cold => { | |
| 359 | const unwrapped_try = air.unwrapTry(inst); | |
| 360 | if (!checkRef(unwrapped_try.error_union, zcu)) return false; | |
| 361 | if (!checkBody( | |
| 362 | air, | |
| 363 | unwrapped_try.else_body, | |
| 364 | zcu, | |
| 365 | )) return false; | |
| 366 | }, | |
| 367 | ||
| 368 | .try_ptr, .try_ptr_cold => { | |
| 369 | const unwrapped_try = air.unwrapTryPtr(inst); | |
| 370 | if (!checkType(unwrapped_try.error_union_payload_ptr_ty.toType(), zcu)) return false; | |
| 371 | if (!checkRef(unwrapped_try.error_union_ptr, zcu)) return false; | |
| 372 | if (!checkBody( | |
| 373 | air, | |
| 374 | unwrapped_try.else_body, | |
| 375 | zcu, | |
| 376 | )) return false; | |
| 377 | }, | |
| 378 | ||
| 379 | .cond_br => { | |
| 380 | const cond_br = air.unwrapCondBr(inst); | |
| 381 | if (!checkRef(cond_br.condition, zcu)) return false; | |
| 382 | if (!checkBody( | |
| 383 | air, | |
| 384 | cond_br.then_body, | |
| 385 | zcu, | |
| 386 | )) return false; | |
| 387 | if (!checkBody( | |
| 388 | air, | |
| 389 | cond_br.else_body, | |
| 390 | zcu, | |
| 391 | )) return false; | |
| 392 | }, | |
| 393 | ||
| 394 | .switch_br, .loop_switch_br => { | |
| 395 | const switch_br = air.unwrapSwitch(inst); | |
| 396 | if (!checkRef(switch_br.operand, zcu)) return false; | |
| 397 | var it = switch_br.iterateCases(); | |
| 398 | while (it.next()) |case| { | |
| 399 | for (case.items) |item| if (!checkRef(item, zcu)) return false; | |
| 400 | for (case.ranges) |range| { | |
| 401 | if (!checkRef(range[0], zcu)) return false; | |
| 402 | if (!checkRef(range[1], zcu)) return false; | |
| 403 | } | |
| 404 | if (!checkBody(air, case.body, zcu)) return false; | |
| 405 | } | |
| 406 | if (!checkBody(air, it.elseBody(), zcu)) return false; | |
| 407 | }, | |
| 408 | ||
| 409 | .assembly => { | |
| 410 | const unwrapped_asm = air.unwrapAsm(inst); | |
| 411 | if (!checkType(data.ty_pl.ty.toType(), zcu)) return false; | |
| 412 | // Luckily, we only care about the inputs and outputs, so we don't have to do | |
| 413 | // the whole null-terminated string dance. | |
| 414 | const outputs = unwrapped_asm.outputs; | |
| 415 | const inputs = unwrapped_asm.inputs; | |
| 416 | ||
| 417 | for (outputs) |output| if (output != .none and !checkRef(output, zcu)) return false; | |
| 418 | for (inputs) |input| if (input != .none and !checkRef(input, zcu)) return false; | |
| 419 | }, | |
| 420 | ||
| 421 | .legalize_compiler_rt_call => { | |
| 422 | const rt_call = air.unwrapCompilerRtCall(inst); | |
| 423 | const args = rt_call.args; | |
| 424 | for (args) |arg| if (!checkRef(arg, zcu)) return false; | |
| 425 | }, | |
| 426 | ||
| 427 | .trap, | |
| 428 | .breakpoint, | |
| 429 | .ret_addr, | |
| 430 | .frame_addr, | |
| 431 | .unreach, | |
| 432 | .wasm_memory_size, | |
| 433 | .wasm_memory_grow, | |
| 434 | .work_item_id, | |
| 435 | .work_group_size, | |
| 436 | .work_group_id, | |
| 437 | .dbg_stmt, | |
| 438 | .dbg_empty_stmt, | |
| 439 | .err_return_trace, | |
| 440 | .save_err_return_trace_index, | |
| 441 | .repeat, | |
| 442 | => {}, | |
| 443 | } | |
| 444 | } | |
| 445 | return true; | |
| 446 | } | |
| 447 | ||
| 448 | fn checkRef(ref: Air.Inst.Ref, zcu: *Zcu) bool { | |
| 449 | const ip_index = ref.toInterned() orelse { | |
| 450 | // This operand refers back to a previous instruction. | |
| 451 | // We have already checked that instruction's type. | |
| 452 | // So, there's no need to check this operand's type. | |
| 453 | return true; | |
| 454 | }; | |
| 455 | return checkVal(Value.fromInterned(ip_index), zcu); | |
| 456 | } | |
| 457 | ||
| 458 | pub fn checkVal(val: Value, zcu: *Zcu) bool { | |
| 459 | const ty = val.typeOf(zcu); | |
| 460 | if (!checkType(ty, zcu)) return false; | |
| 461 | if (val.isUndef(zcu)) return true; | |
| 462 | if (ty.toIntern() == .type_type and !checkType(val.toType(), zcu)) return false; | |
| 463 | // Check for lazy values | |
| 464 | switch (zcu.intern_pool.indexToKey(val.toIntern())) { | |
| 465 | .int => |int| switch (int.storage) { | |
| 466 | .u64, .i64, .big_int => return true, | |
| 467 | .lazy_align, .lazy_size => |ty_index| { | |
| 468 | return checkType(Type.fromInterned(ty_index), zcu); | |
| 469 | }, | |
| 470 | }, | |
| 471 | else => return true, | |
| 472 | } | |
| 473 | } | |
| 474 | ||
| 475 | pub fn checkType(ty: Type, zcu: *Zcu) bool { | |
| 476 | const ip = &zcu.intern_pool; | |
| 477 | if (ty.isGenericPoison()) return true; | |
| 478 | return switch (ty.zigTypeTag(zcu)) { | |
| 479 | .type, | |
| 480 | .void, | |
| 481 | .bool, | |
| 482 | .noreturn, | |
| 483 | .int, | |
| 484 | .float, | |
| 485 | .error_set, | |
| 486 | .@"enum", | |
| 487 | .@"opaque", | |
| 488 | .vector, | |
| 489 | // These types can appear due to some dummy instructions Sema introduces and expects to be omitted by Liveness. | |
| 490 | // It's a little silly -- but fine, we'll return `true`. | |
| 491 | .comptime_float, | |
| 492 | .comptime_int, | |
| 493 | .undefined, | |
| 494 | .null, | |
| 495 | .enum_literal, | |
| 496 | => true, | |
| 497 | ||
| 498 | .frame, | |
| 499 | .@"anyframe", | |
| 500 | => @panic("TODO Air.types_resolved.checkType async frames"), | |
| 501 | ||
| 502 | .optional => checkType(ty.childType(zcu), zcu), | |
| 503 | .error_union => checkType(ty.errorUnionPayload(zcu), zcu), | |
| 504 | .pointer => checkType(ty.childType(zcu), zcu), | |
| 505 | .array => checkType(ty.childType(zcu), zcu), | |
| 506 | ||
| 507 | .@"fn" => { | |
| 508 | const info = zcu.typeToFunc(ty).?; | |
| 509 | for (0..info.param_types.len) |i| { | |
| 510 | const param_ty = info.param_types.get(ip)[i]; | |
| 511 | if (!checkType(Type.fromInterned(param_ty), zcu)) return false; | |
| 512 | } | |
| 513 | return checkType(Type.fromInterned(info.return_type), zcu); | |
| 514 | }, | |
| 515 | .@"struct" => switch (ip.indexToKey(ty.toIntern())) { | |
| 516 | .struct_type => { | |
| 517 | const struct_obj = zcu.typeToStruct(ty).?; | |
| 518 | return switch (struct_obj.layout) { | |
| 519 | .@"packed" => struct_obj.backingIntTypeUnordered(ip) != .none, | |
| 520 | .auto, .@"extern" => struct_obj.flagsUnordered(ip).fully_resolved, | |
| 521 | }; | |
| 522 | }, | |
| 523 | .tuple_type => |tuple| { | |
| 524 | for (0..tuple.types.len) |i| { | |
| 525 | const field_is_comptime = tuple.values.get(ip)[i] != .none; | |
| 526 | if (field_is_comptime) continue; | |
| 527 | const field_ty = tuple.types.get(ip)[i]; | |
| 528 | if (!checkType(Type.fromInterned(field_ty), zcu)) return false; | |
| 529 | } | |
| 530 | return true; | |
| 531 | }, | |
| 532 | else => unreachable, | |
| 533 | }, | |
| 534 | .@"union" => return zcu.typeToUnion(ty).?.flagsUnordered(ip).status == .fully_resolved, | |
| 535 | }; | |
| 536 | } |
src/Compilation.zig+89-96| ... | ... | @@ -126,15 +126,7 @@ oneshot_prelink_tasks: std.ArrayList(link.PrelinkTask), |
| 126 | 126 | /// work is queued or not. |
| 127 | 127 | queued_jobs: QueuedJobs, |
| 128 | 128 | |
| 129 | work_queues: [ | |
| 130 | len: { | |
| 131 | var len: usize = 0; | |
| 132 | for (std.enums.values(Job.Tag)) |tag| { | |
| 133 | len = @max(Job.stage(tag) + 1, len); | |
| 134 | } | |
| 135 | break :len len; | |
| 136 | } | |
| 137 | ]std.Deque(Job), | |
| 129 | work_queues: [2]std.Deque(Job), | |
| 138 | 130 | |
| 139 | 131 | /// These jobs are to invoke the Clang compiler to create an object file, which |
| 140 | 132 | /// gets linked with the Compilation. |
| ... | ... | @@ -990,35 +982,27 @@ const Job = union(enum) { |
| 990 | 982 | update_line_number: InternPool.TrackedInst.Index, |
| 991 | 983 | /// The `AnalUnit`, which is *not* a `func`, must be semantically analyzed. |
| 992 | 984 | /// This may be its first time being analyzed, or it may be outdated. |
| 993 | /// If the unit is a test function, an `analyze_func` job will then be queued. | |
| 994 | analyze_comptime_unit: InternPool.AnalUnit, | |
| 995 | /// This function must be semantically analyzed. | |
| 996 | /// This may be its first time being analyzed, or it may be outdated. | |
| 997 | /// After analysis, a `codegen_func` job will be queued. | |
| 998 | /// These must be separate jobs to ensure any needed type resolution occurs *before* codegen. | |
| 999 | /// This job is separate from `analyze_comptime_unit` because it has a different priority. | |
| 1000 | analyze_func: InternPool.Index, | |
| 985 | /// If the unit is a function, a `codegen_func` job will be queued after analysis completes. | |
| 986 | /// If the unit is a *test* function, an `analyze_func` job will also be queued. | |
| 987 | analyze_unit: InternPool.AnalUnit, | |
| 1001 | 988 | /// The main source file for the module needs to be analyzed. |
| 1002 | 989 | analyze_mod: *Package.Module, |
| 1003 | /// Fully resolve the given `struct` or `union` type. | |
| 1004 | resolve_type_fully: InternPool.Index, | |
| 1005 | 990 | |
| 1006 | 991 | /// The value is the index into `windows_libs`. |
| 1007 | 992 | windows_import_lib: usize, |
| 1008 | 993 | |
| 1009 | const Tag = @typeInfo(Job).@"union".tag_type.?; | |
| 1010 | fn stage(tag: Tag) usize { | |
| 1011 | return switch (tag) { | |
| 1012 | // Prioritize functions so that codegen can get to work on them on a | |
| 1013 | // separate thread, while Sema goes back to its own work. | |
| 1014 | .resolve_type_fully, .analyze_func, .codegen_func => 0, | |
| 994 | fn stage(job: *const Job) usize { | |
| 995 | // Prioritize functions so that codegen can get to work on them on a | |
| 996 | // separate thread, while Sema goes back to its own work. | |
| 997 | return switch (job.*) { | |
| 998 | .codegen_func => 0, | |
| 999 | .analyze_unit => |unit| switch (unit.unwrap()) { | |
| 1000 | .func => 0, | |
| 1001 | else => 1, | |
| 1002 | }, | |
| 1015 | 1003 | else => 1, |
| 1016 | 1004 | }; |
| 1017 | 1005 | } |
| 1018 | comptime { | |
| 1019 | // Job dependencies | |
| 1020 | assert(stage(.resolve_type_fully) <= stage(.codegen_func)); | |
| 1021 | } | |
| 1022 | 1006 | }; |
| 1023 | 1007 | |
| 1024 | 1008 | pub const CObject = struct { |
| ... | ... | @@ -3728,7 +3712,9 @@ const Header = extern struct { |
| 3728 | 3712 | src_hash_deps_len: u32, |
| 3729 | 3713 | nav_val_deps_len: u32, |
| 3730 | 3714 | nav_ty_deps_len: u32, |
| 3731 | interned_deps_len: u32, | |
| 3715 | type_layout_deps_len: u32, | |
| 3716 | type_inits_deps_len: u32, | |
| 3717 | func_ies_deps_len: u32, | |
| 3732 | 3718 | zon_file_deps_len: u32, |
| 3733 | 3719 | embed_file_deps_len: u32, |
| 3734 | 3720 | namespace_deps_len: u32, |
| ... | ... | @@ -3776,7 +3762,9 @@ pub fn saveState(comp: *Compilation) !void { |
| 3776 | 3762 | .src_hash_deps_len = @intCast(ip.src_hash_deps.count()), |
| 3777 | 3763 | .nav_val_deps_len = @intCast(ip.nav_val_deps.count()), |
| 3778 | 3764 | .nav_ty_deps_len = @intCast(ip.nav_ty_deps.count()), |
| 3779 | .interned_deps_len = @intCast(ip.interned_deps.count()), | |
| 3765 | .type_layout_deps_len = @intCast(ip.type_layout_deps.count()), | |
| 3766 | .type_inits_deps_len = @intCast(ip.type_inits_deps.count()), | |
| 3767 | .func_ies_deps_len = @intCast(ip.func_ies_deps.count()), | |
| 3780 | 3768 | .zon_file_deps_len = @intCast(ip.zon_file_deps.count()), |
| 3781 | 3769 | .embed_file_deps_len = @intCast(ip.embed_file_deps.count()), |
| 3782 | 3770 | .namespace_deps_len = @intCast(ip.namespace_deps.count()), |
| ... | ... | @@ -3800,7 +3788,7 @@ pub fn saveState(comp: *Compilation) !void { |
| 3800 | 3788 | }, |
| 3801 | 3789 | }); |
| 3802 | 3790 | |
| 3803 | try bufs.ensureTotalCapacityPrecise(22 + 9 * pt_headers.items.len); | |
| 3791 | try bufs.ensureTotalCapacityPrecise(26 + 9 * pt_headers.items.len); | |
| 3804 | 3792 | addBuf(&bufs, mem.asBytes(&header)); |
| 3805 | 3793 | addBuf(&bufs, @ptrCast(pt_headers.items)); |
| 3806 | 3794 | |
| ... | ... | @@ -3810,8 +3798,12 @@ pub fn saveState(comp: *Compilation) !void { |
| 3810 | 3798 | addBuf(&bufs, @ptrCast(ip.nav_val_deps.values())); |
| 3811 | 3799 | addBuf(&bufs, @ptrCast(ip.nav_ty_deps.keys())); |
| 3812 | 3800 | addBuf(&bufs, @ptrCast(ip.nav_ty_deps.values())); |
| 3813 | addBuf(&bufs, @ptrCast(ip.interned_deps.keys())); | |
| 3814 | addBuf(&bufs, @ptrCast(ip.interned_deps.values())); | |
| 3801 | addBuf(&bufs, @ptrCast(ip.type_layout_deps.keys())); | |
| 3802 | addBuf(&bufs, @ptrCast(ip.type_layout_deps.values())); | |
| 3803 | addBuf(&bufs, @ptrCast(ip.type_inits_deps.keys())); | |
| 3804 | addBuf(&bufs, @ptrCast(ip.type_inits_deps.values())); | |
| 3805 | addBuf(&bufs, @ptrCast(ip.func_ies_deps.keys())); | |
| 3806 | addBuf(&bufs, @ptrCast(ip.func_ies_deps.values())); | |
| 3815 | 3807 | addBuf(&bufs, @ptrCast(ip.zon_file_deps.keys())); |
| 3816 | 3808 | addBuf(&bufs, @ptrCast(ip.zon_file_deps.values())); |
| 3817 | 3809 | addBuf(&bufs, @ptrCast(ip.embed_file_deps.keys())); |
| ... | ... | @@ -4489,7 +4481,7 @@ pub fn addModuleErrorMsg( |
| 4489 | 4481 | const root_name: ?[]const u8 = switch (ref.referencer.unwrap()) { |
| 4490 | 4482 | .@"comptime" => "comptime", |
| 4491 | 4483 | .nav_val, .nav_ty => |nav| ip.getNav(nav).name.toSlice(ip), |
| 4492 | .type => |ty| Type.fromInterned(ty).containerTypeName(ip).toSlice(ip), | |
| 4484 | .type_layout, .type_inits => |ty| Type.fromInterned(ty).containerTypeName(ip).toSlice(ip), | |
| 4493 | 4485 | .func => |f| ip.getNav(zcu.funcInfo(f).owner_nav).name.toSlice(ip), |
| 4494 | 4486 | .memoized_state => null, |
| 4495 | 4487 | }; |
| ... | ... | @@ -4900,15 +4892,7 @@ fn performAllTheWork( |
| 4900 | 4892 | // If there's no work queued, check if there's anything outdated |
| 4901 | 4893 | // which we need to work on, and queue it if so. |
| 4902 | 4894 | if (try zcu.findOutdatedToAnalyze()) |outdated| { |
| 4903 | try comp.queueJob(switch (outdated.unwrap()) { | |
| 4904 | .func => |f| .{ .analyze_func = f }, | |
| 4905 | .memoized_state, | |
| 4906 | .@"comptime", | |
| 4907 | .nav_ty, | |
| 4908 | .nav_val, | |
| 4909 | .type, | |
| 4910 | => .{ .analyze_comptime_unit = outdated }, | |
| 4911 | }); | |
| 4895 | try comp.queueJob(.{ .analyze_unit = outdated }); | |
| 4912 | 4896 | continue; |
| 4913 | 4897 | } |
| 4914 | 4898 | zcu.sema_prog_node.end(); |
| ... | ... | @@ -5151,7 +5135,7 @@ fn dispatchPrelinkWork(comp: *Compilation, main_progress_node: std.Progress.Node |
| 5151 | 5135 | const JobError = Allocator.Error || Io.Cancelable; |
| 5152 | 5136 | |
| 5153 | 5137 | pub fn queueJob(comp: *Compilation, job: Job) !void { |
| 5154 | try comp.work_queues[Job.stage(job)].pushBack(comp.gpa, job); | |
| 5138 | try comp.work_queues[job.stage()].pushBack(comp.gpa, job); | |
| 5155 | 5139 | } |
| 5156 | 5140 | |
| 5157 | 5141 | pub fn queueJobs(comp: *Compilation, jobs: []const Job) !void { |
| ... | ... | @@ -5166,13 +5150,24 @@ fn processOneJob(tid: Zcu.PerThread.Id, comp: *Compilation, job: Job) JobError!v |
| 5166 | 5150 | var owned_air: ?Air = func.air; |
| 5167 | 5151 | defer if (owned_air) |*air| air.deinit(gpa); |
| 5168 | 5152 | |
| 5169 | if (!owned_air.?.typesFullyResolved(zcu)) { | |
| 5170 | // Type resolution failed in a way which affects this function. This is a transitive | |
| 5171 | // failure, but it doesn't need recording, because this function semantically depends | |
| 5172 | // on the failed type, so when it is changed the function is updated. | |
| 5173 | zcu.codegen_prog_node.completeOne(); | |
| 5174 | comp.link_prog_node.completeOne(); | |
| 5175 | return; | |
| 5153 | { | |
| 5154 | const pt: Zcu.PerThread = .activate(zcu, @enumFromInt(tid)); | |
| 5155 | defer pt.deactivate(); | |
| 5156 | pt.resolveAirTypesForCodegen(&owned_air.?) catch |err| switch (err) { | |
| 5157 | error.OutOfMemory, | |
| 5158 | error.Canceled, | |
| 5159 | => |e| return e, | |
| 5160 | ||
| 5161 | error.AnalysisFail => { | |
| 5162 | // Type resolution failed, making codegen of this function impossible. This | |
| 5163 | // is a transitive failure, but it doesn't need recording, because this | |
| 5164 | // function semantically depends on the failed type, so when it is changed | |
| 5165 | // the function will be updated. | |
| 5166 | zcu.codegen_prog_node.completeOne(); | |
| 5167 | comp.link_prog_node.completeOne(); | |
| 5168 | return; | |
| 5169 | }, | |
| 5170 | }; | |
| 5176 | 5171 | } |
| 5177 | 5172 | |
| 5178 | 5173 | // Some linkers need to refer to the AIR. In that case, the linker is not running |
| ... | ... | @@ -5198,45 +5193,54 @@ fn processOneJob(tid: Zcu.PerThread.Id, comp: *Compilation, job: Job) JobError!v |
| 5198 | 5193 | } |
| 5199 | 5194 | } |
| 5200 | 5195 | assert(nav.status == .fully_resolved); |
| 5201 | if (!Air.valFullyResolved(zcu.navValue(nav_index), zcu)) { | |
| 5202 | // Type resolution failed in a way which affects this `Nav`. This is a transitive | |
| 5203 | // failure, but it doesn't need recording, because this `Nav` semantically depends | |
| 5204 | // on the failed type, so when it is changed the `Nav` will be updated. | |
| 5205 | comp.link_prog_node.completeOne(); | |
| 5206 | return; | |
| 5196 | { | |
| 5197 | const pt: Zcu.PerThread = .activate(zcu, @enumFromInt(tid)); | |
| 5198 | defer pt.deactivate(); | |
| 5199 | pt.resolveValueTypesForCodegen(zcu.navValue(nav_index)) catch |err| switch (err) { | |
| 5200 | error.OutOfMemory, | |
| 5201 | error.Canceled, | |
| 5202 | => |e| return e, | |
| 5203 | ||
| 5204 | error.AnalysisFail => { | |
| 5205 | // Type resolution failed, making codegen of this `Nav` impossible. This is | |
| 5206 | // a transitive failure, but it doesn't need recording, because this `Nav` | |
| 5207 | // semantically depends on the failed type, so when it is changed the value | |
| 5208 | // of the `Nav` will be updated. | |
| 5209 | comp.link_prog_node.completeOne(); | |
| 5210 | return; | |
| 5211 | }, | |
| 5212 | }; | |
| 5207 | 5213 | } |
| 5208 | 5214 | try comp.link_queue.enqueueZcu(comp, tid, .{ .link_nav = nav_index }); |
| 5209 | 5215 | }, |
| 5210 | 5216 | .link_type => |ty| { |
| 5211 | 5217 | const zcu = comp.zcu.?; |
| 5212 | 5218 | if (zcu.failed_types.fetchSwapRemove(ty)) |*entry| entry.value.deinit(zcu.gpa); |
| 5213 | if (!Air.typeFullyResolved(.fromInterned(ty), zcu)) { | |
| 5214 | // Type resolution failed in a way which affects this type. This is a transitive | |
| 5215 | // failure, but it doesn't need recording, because this type semantically depends | |
| 5216 | // on the failed type, so when that is changed, this type will be updated. | |
| 5217 | comp.link_prog_node.completeOne(); | |
| 5218 | return; | |
| 5219 | { | |
| 5220 | const pt: Zcu.PerThread = .activate(zcu, @enumFromInt(tid)); | |
| 5221 | defer pt.deactivate(); | |
| 5222 | pt.resolveTypeForCodegen(.fromInterned(ty)) catch |err| switch (err) { | |
| 5223 | error.OutOfMemory, | |
| 5224 | error.Canceled, | |
| 5225 | => |e| return e, | |
| 5226 | ||
| 5227 | error.AnalysisFail => { | |
| 5228 | // Type resolution failed, making codegen of this type impossible. This is | |
| 5229 | // a transitive failure, but it doesn't need recording, because this type | |
| 5230 | // semantically depends on the failed type, so when it is changed the type | |
| 5231 | // will be updated appropriately. | |
| 5232 | comp.link_prog_node.completeOne(); | |
| 5233 | return; | |
| 5234 | }, | |
| 5235 | }; | |
| 5219 | 5236 | } |
| 5220 | 5237 | try comp.link_queue.enqueueZcu(comp, tid, .{ .link_type = ty }); |
| 5221 | 5238 | }, |
| 5222 | 5239 | .update_line_number => |tracked_inst| { |
| 5223 | 5240 | try comp.link_queue.enqueueZcu(comp, tid, .{ .update_line_number = tracked_inst }); |
| 5224 | 5241 | }, |
| 5225 | .analyze_func => |func| { | |
| 5226 | const tracy_trace = traceNamed(@src(), "analyze_func"); | |
| 5227 | defer tracy_trace.end(); | |
| 5228 | ||
| 5229 | const pt: Zcu.PerThread = .activate(comp.zcu.?, tid); | |
| 5230 | defer pt.deactivate(); | |
| 5231 | ||
| 5232 | pt.ensureFuncBodyUpToDate(func) catch |err| switch (err) { | |
| 5233 | error.OutOfMemory => |e| return e, | |
| 5234 | error.Canceled => |e| return e, | |
| 5235 | error.AnalysisFail => return, | |
| 5236 | }; | |
| 5237 | }, | |
| 5238 | .analyze_comptime_unit => |unit| { | |
| 5239 | const tracy_trace = traceNamed(@src(), "analyze_comptime_unit"); | |
| 5242 | .analyze_unit => |unit| { | |
| 5243 | const tracy_trace = traceNamed(@src(), "analyze_unit"); | |
| 5240 | 5244 | defer tracy_trace.end(); |
| 5241 | 5245 | |
| 5242 | 5246 | const pt: Zcu.PerThread = .activate(comp.zcu.?, tid); |
| ... | ... | @@ -5246,9 +5250,10 @@ fn processOneJob(tid: Zcu.PerThread.Id, comp: *Compilation, job: Job) JobError!v |
| 5246 | 5250 | .@"comptime" => |cu| pt.ensureComptimeUnitUpToDate(cu), |
| 5247 | 5251 | .nav_ty => |nav| pt.ensureNavTypeUpToDate(nav), |
| 5248 | 5252 | .nav_val => |nav| pt.ensureNavValUpToDate(nav), |
| 5249 | .type => |ty| if (pt.ensureTypeUpToDate(ty)) |_| {} else |err| err, | |
| 5253 | .type_layout => |ty| pt.ensureTypeLayoutUpToDate(.fromInterned(ty)), | |
| 5254 | .type_inits => |ty| pt.ensureTypeInitsUpToDate(.fromInterned(ty)), | |
| 5250 | 5255 | .memoized_state => |stage| pt.ensureMemoizedStateUpToDate(stage), |
| 5251 | .func => unreachable, | |
| 5256 | .func => |func| pt.ensureFuncBodyUpToDate(func), | |
| 5252 | 5257 | }; |
| 5253 | 5258 | maybe_err catch |err| switch (err) { |
| 5254 | 5259 | error.OutOfMemory => |e| return e, |
| ... | ... | @@ -5275,27 +5280,15 @@ fn processOneJob(tid: Zcu.PerThread.Id, comp: *Compilation, job: Job) JobError!v |
| 5275 | 5280 | try pt.zcu.ensureFuncBodyAnalysisQueued(ip.getNav(nav).status.fully_resolved.val); |
| 5276 | 5281 | } |
| 5277 | 5282 | }, |
| 5278 | .resolve_type_fully => |ty| { | |
| 5279 | const tracy_trace = traceNamed(@src(), "resolve_type_fully"); | |
| 5280 | defer tracy_trace.end(); | |
| 5281 | ||
| 5282 | const pt: Zcu.PerThread = .activate(comp.zcu.?, tid); | |
| 5283 | defer pt.deactivate(); | |
| 5284 | Type.fromInterned(ty).resolveFully(pt) catch |err| switch (err) { | |
| 5285 | error.OutOfMemory, error.Canceled => |e| return e, | |
| 5286 | error.AnalysisFail => return, | |
| 5287 | }; | |
| 5288 | }, | |
| 5289 | 5283 | .analyze_mod => |mod| { |
| 5290 | 5284 | const tracy_trace = traceNamed(@src(), "analyze_mod"); |
| 5291 | 5285 | defer tracy_trace.end(); |
| 5292 | 5286 | |
| 5293 | 5287 | const pt: Zcu.PerThread = .activate(comp.zcu.?, tid); |
| 5294 | 5288 | defer pt.deactivate(); |
| 5295 | pt.semaMod(mod) catch |err| switch (err) { | |
| 5296 | error.OutOfMemory, error.Canceled => |e| return e, | |
| 5297 | error.AnalysisFail => return, | |
| 5298 | }; | |
| 5289 | ||
| 5290 | const mod_root_file = pt.zcu.module_roots.get(mod).?.unwrap().?; | |
| 5291 | try pt.ensureFileAnalyzed(mod_root_file); | |
| 5299 | 5292 | }, |
| 5300 | 5293 | .windows_import_lib => |index| { |
| 5301 | 5294 | const tracy_trace = traceNamed(@src(), "windows_import_lib"); |
src/IncrementalDebugServer.zig+6-8| ... | ... | @@ -306,12 +306,8 @@ fn handleCommand(zcu: *Zcu, w: *Io.Writer, cmd_str: []const u8, arg_str: []const |
| 306 | 306 | try w.print("[{d}] ", .{i}); |
| 307 | 307 | switch (dependee) { |
| 308 | 308 | .src_hash, .namespace, .namespace_name, .zon_file, .embed_file => try w.print("{f}", .{zcu.fmtDependee(dependee)}), |
| 309 | .nav_val, .nav_ty => |nav| try w.print("{s} {d}", .{ @tagName(dependee), @intFromEnum(nav) }), | |
| 310 | .interned => |ip_index| switch (ip.indexToKey(ip_index)) { | |
| 311 | .struct_type, .union_type, .enum_type => try w.print("type {d}", .{@intFromEnum(ip_index)}), | |
| 312 | .func => try w.print("func {d}", .{@intFromEnum(ip_index)}), | |
| 313 | else => unreachable, | |
| 314 | }, | |
| 309 | .nav_val, .nav_ty => |nav| try w.print("{t} {d}", .{ dependee, @intFromEnum(nav) }), | |
| 310 | .type_layout, .type_inits, .func_ies => |ip_index| try w.print("{t} {d}", .{ dependee, @intFromEnum(ip_index) }), | |
| 315 | 311 | .memoized_state => |stage| try w.print("memoized_state {s}", .{@tagName(stage)}), |
| 316 | 312 | } |
| 317 | 313 | try w.writeByte('\n'); |
| ... | ... | @@ -376,8 +372,10 @@ fn parseAnalUnit(str: []const u8) ?AnalUnit { |
| 376 | 372 | return .wrap(.{ .nav_val = @enumFromInt(parseIndex(idx_str) orelse return null) }); |
| 377 | 373 | } else if (std.mem.eql(u8, kind, "nav_ty")) { |
| 378 | 374 | return .wrap(.{ .nav_ty = @enumFromInt(parseIndex(idx_str) orelse return null) }); |
| 379 | } else if (std.mem.eql(u8, kind, "type")) { | |
| 380 | return .wrap(.{ .type = @enumFromInt(parseIndex(idx_str) orelse return null) }); | |
| 375 | } else if (std.mem.eql(u8, kind, "type_layout")) { | |
| 376 | return .wrap(.{ .type_layout = @enumFromInt(parseIndex(idx_str) orelse return null) }); | |
| 377 | } else if (std.mem.eql(u8, kind, "type_inits")) { | |
| 378 | return .wrap(.{ .type_inits = @enumFromInt(parseIndex(idx_str) orelse return null) }); | |
| 381 | 379 | } else if (std.mem.eql(u8, kind, "func")) { |
| 382 | 380 | return .wrap(.{ .func = @enumFromInt(parseIndex(idx_str) orelse return null) }); |
| 383 | 381 | } else if (std.mem.eql(u8, kind, "memoized_state")) { |
src/InternPool.zig+1942-2736| ... | ... | @@ -47,11 +47,15 @@ nav_val_deps: std.AutoArrayHashMapUnmanaged(Nav.Index, DepEntry.Index), |
| 47 | 47 | /// Dependencies on the type of a Nav. |
| 48 | 48 | /// Value is index into `dep_entries` of the first dependency on this Nav value. |
| 49 | 49 | nav_ty_deps: std.AutoArrayHashMapUnmanaged(Nav.Index, DepEntry.Index), |
| 50 | /// Dependencies on an interned value, either: | |
| 51 | /// * a runtime function (invalidated when its IES changes) | |
| 52 | /// * a container type requiring resolution (invalidated when the type must be recreated at a new index) | |
| 53 | /// Value is index into `dep_entries` of the first dependency on this interned value. | |
| 54 | interned_deps: std.AutoArrayHashMapUnmanaged(Index, DepEntry.Index), | |
| 50 | /// Dependencies on a function's inferred error set. Key is the function body, not the IES. | |
| 51 | /// Value is index into `dep_entries` of the first dependency on this function's IES. | |
| 52 | func_ies_deps: std.AutoArrayHashMapUnmanaged(Index, DepEntry.Index), | |
| 53 | /// Dependencies on the resolved layout of a `struct` or `union` type. | |
| 54 | /// Value is index into `dep_entries` of the first dependency on this type's layout. | |
| 55 | type_layout_deps: std.AutoArrayHashMapUnmanaged(Index, DepEntry.Index), | |
| 56 | /// Dependencies on the resolved initializers of a `struct` or `enum` type. | |
| 57 | /// Value is index into `dep_entries` of the first dependency on this type's inits. | |
| 58 | type_inits_deps: std.AutoArrayHashMapUnmanaged(Index, DepEntry.Index), | |
| 55 | 59 | /// Dependencies on a ZON file. Triggered by `@import` of ZON. |
| 56 | 60 | /// Value is index into `dep_entries` of the first dependency on this ZON file. |
| 57 | 61 | zon_file_deps: std.AutoArrayHashMapUnmanaged(FileIndex, DepEntry.Index), |
| ... | ... | @@ -104,7 +108,9 @@ pub const empty: InternPool = .{ |
| 104 | 108 | .src_hash_deps = .empty, |
| 105 | 109 | .nav_val_deps = .empty, |
| 106 | 110 | .nav_ty_deps = .empty, |
| 107 | .interned_deps = .empty, | |
| 111 | .func_ies_deps = .empty, | |
| 112 | .type_layout_deps = .empty, | |
| 113 | .type_inits_deps = .empty, | |
| 108 | 114 | .zon_file_deps = .empty, |
| 109 | 115 | .embed_file_deps = .empty, |
| 110 | 116 | .namespace_deps = .empty, |
| ... | ... | @@ -415,7 +421,8 @@ pub const AnalUnit = packed struct(u64) { |
| 415 | 421 | @"comptime", |
| 416 | 422 | nav_val, |
| 417 | 423 | nav_ty, |
| 418 | type, | |
| 424 | type_layout, | |
| 425 | type_inits, | |
| 419 | 426 | func, |
| 420 | 427 | memoized_state, |
| 421 | 428 | }; |
| ... | ... | @@ -427,9 +434,11 @@ pub const AnalUnit = packed struct(u64) { |
| 427 | 434 | nav_val: Nav.Index, |
| 428 | 435 | /// This `AnalUnit` resolves the type of the given `Nav`. |
| 429 | 436 | nav_ty: Nav.Index, |
| 430 | /// This `AnalUnit` resolves the given `struct`/`union`/`enum` type. | |
| 431 | /// Generated tag enums are never used here (they do not undergo type resolution). | |
| 432 | type: InternPool.Index, | |
| 437 | /// This `AnalUnit` resolves the layout of the given `struct` or `union` type. | |
| 438 | type_layout: InternPool.Index, | |
| 439 | /// This `AnalUnit` resolves the field inits of the given `struct` or `enum` type. | |
| 440 | /// The type may be a union's auto-generated tag enum, if the union has explicit field values. | |
| 441 | type_inits: InternPool.Index, | |
| 433 | 442 | /// This `AnalUnit` analyzes the body of the given runtime function. |
| 434 | 443 | func: InternPool.Index, |
| 435 | 444 | /// This `AnalUnit` resolves all state which is memoized in fields on `Zcu`. |
| ... | ... | @@ -840,7 +849,10 @@ pub const Dependee = union(enum) { |
| 840 | 849 | src_hash: TrackedInst.Index, |
| 841 | 850 | nav_val: Nav.Index, |
| 842 | 851 | nav_ty: Nav.Index, |
| 843 | interned: Index, | |
| 852 | /// Index is the function, not its IES. | |
| 853 | func_ies: Index, | |
| 854 | type_layout: Index, | |
| 855 | type_inits: Index, | |
| 844 | 856 | zon_file: FileIndex, |
| 845 | 857 | embed_file: Zcu.EmbedFile.Index, |
| 846 | 858 | namespace: TrackedInst.Index, |
| ... | ... | @@ -892,7 +904,9 @@ pub fn dependencyIterator(ip: *const InternPool, dependee: Dependee) DependencyI |
| 892 | 904 | .src_hash => |x| ip.src_hash_deps.get(x), |
| 893 | 905 | .nav_val => |x| ip.nav_val_deps.get(x), |
| 894 | 906 | .nav_ty => |x| ip.nav_ty_deps.get(x), |
| 895 | .interned => |x| ip.interned_deps.get(x), | |
| 907 | .func_ies => |x| ip.func_ies_deps.get(x), | |
| 908 | .type_layout => |x| ip.type_layout_deps.get(x), | |
| 909 | .type_inits => |x| ip.type_inits_deps.get(x), | |
| 896 | 910 | .zon_file => |x| ip.zon_file_deps.get(x), |
| 897 | 911 | .embed_file => |x| ip.embed_file_deps.get(x), |
| 898 | 912 | .namespace => |x| ip.namespace_deps.get(x), |
| ... | ... | @@ -965,7 +979,9 @@ pub fn addDependency(ip: *InternPool, gpa: Allocator, depender: AnalUnit, depend |
| 965 | 979 | .src_hash => ip.src_hash_deps, |
| 966 | 980 | .nav_val => ip.nav_val_deps, |
| 967 | 981 | .nav_ty => ip.nav_ty_deps, |
| 968 | .interned => ip.interned_deps, | |
| 982 | .func_ies => ip.func_ies_deps, | |
| 983 | .type_layout => ip.type_layout_deps, | |
| 984 | .type_inits => ip.type_inits_deps, | |
| 969 | 985 | .zon_file => ip.zon_file_deps, |
| 970 | 986 | .embed_file => ip.embed_file_deps, |
| 971 | 987 | .namespace => ip.namespace_deps, |
| ... | ... | @@ -2065,15 +2081,15 @@ pub const Key = union(enum) { |
| 2065 | 2081 | simple_type: SimpleType, |
| 2066 | 2082 | /// This represents a struct that has been explicitly declared in source code, |
| 2067 | 2083 | /// or was created with `@Struct`. It is unique and based on a declaration. |
| 2068 | struct_type: NamespaceType, | |
| 2084 | struct_type: ContainerType, | |
| 2069 | 2085 | /// This is a tuple type. Tuples are logically similar to structs, but have some |
| 2070 | 2086 | /// important differences in semantics; they do not undergo staged type resolution, |
| 2071 | 2087 | /// so cannot be self-referential, and they are not considered container/namespace |
| 2072 | 2088 | /// types, so cannot have declarations and have structural equality properties. |
| 2073 | 2089 | tuple_type: TupleType, |
| 2074 | union_type: NamespaceType, | |
| 2075 | opaque_type: NamespaceType, | |
| 2076 | enum_type: NamespaceType, | |
| 2090 | union_type: ContainerType, | |
| 2091 | opaque_type: ContainerType, | |
| 2092 | enum_type: ContainerType, | |
| 2077 | 2093 | func_type: FuncType, |
| 2078 | 2094 | error_set_type: ErrorSetType, |
| 2079 | 2095 | /// The payload is the function body, either a `func_decl` or `func_instance`. |
| ... | ... | @@ -2211,16 +2227,10 @@ pub const Key = union(enum) { |
| 2211 | 2227 | /// * `loadUnionType` |
| 2212 | 2228 | /// * `loadEnumType` |
| 2213 | 2229 | /// * `loadOpaqueType` |
| 2214 | pub const NamespaceType = union(enum) { | |
| 2230 | pub const ContainerType = union(enum) { | |
| 2215 | 2231 | /// This type corresponds to an actual source declaration, e.g. `struct { ... }`. |
| 2216 | 2232 | /// It is hashed based on its ZIR instruction index and set of captures. |
| 2217 | 2233 | declared: Declared, |
| 2218 | /// This type is an automatically-generated enum tag type for a union. | |
| 2219 | /// It is hashed based on the index of the union type it corresponds to. | |
| 2220 | generated_tag: struct { | |
| 2221 | /// The union for which this is a tag type. | |
| 2222 | union_type: Index, | |
| 2223 | }, | |
| 2224 | 2234 | /// This type originates from a reification via `@Enum`, `@Struct`, `@Union` or from an anonymous initialization. |
| 2225 | 2235 | /// It is hashed based on its ZIR instruction index and fields, attributes, etc. |
| 2226 | 2236 | /// To avoid making this key overly complex, the type-specific data is hashed by Sema. |
| ... | ... | @@ -2231,10 +2241,17 @@ pub const Key = union(enum) { |
| 2231 | 2241 | /// A hash of this type's attributes, fields, etc, generated by Sema. |
| 2232 | 2242 | type_hash: u64, |
| 2233 | 2243 | }, |
| 2244 | /// This type is an automatically-generated enum tag type for this union type. | |
| 2245 | /// It is hashed based on the index of the union type it corresponds to. | |
| 2246 | generated_union_tag: Index, | |
| 2234 | 2247 | |
| 2235 | 2248 | pub const Declared = struct { |
| 2236 | 2249 | /// A `struct_decl`, `union_decl`, `enum_decl`, or `opaque_decl` instruction. |
| 2237 | 2250 | zir_index: TrackedInst.Index, |
| 2251 | /// If the type declaration had an argument type (tag type or packed backing type), this | |
| 2252 | /// is that type. Otherwise, this is `.none`. It is always `.none` for `opaque` types as | |
| 2253 | /// `opaque(T)` does not exist. | |
| 2254 | arg_ty: Index, | |
| 2238 | 2255 | /// The captured values of this type. These values must be fully resolved per the language spec. |
| 2239 | 2256 | captures: union(enum) { |
| 2240 | 2257 | owned: CaptureValue.Slice, |
| ... | ... | @@ -2254,7 +2271,6 @@ pub const Key = union(enum) { |
| 2254 | 2271 | noalias_bits: u32, |
| 2255 | 2272 | cc: std.builtin.CallingConvention, |
| 2256 | 2273 | is_var_args: bool, |
| 2257 | is_generic: bool, | |
| 2258 | 2274 | is_noinline: bool, |
| 2259 | 2275 | |
| 2260 | 2276 | pub fn paramIsComptime(self: @This(), i: u5) bool { |
| ... | ... | @@ -2273,7 +2289,6 @@ pub const Key = union(enum) { |
| 2273 | 2289 | a.comptime_bits == b.comptime_bits and |
| 2274 | 2290 | a.noalias_bits == b.noalias_bits and |
| 2275 | 2291 | a.is_var_args == b.is_var_args and |
| 2276 | a.is_generic == b.is_generic and | |
| 2277 | 2292 | a.is_noinline == b.is_noinline and |
| 2278 | 2293 | std.meta.eql(a.cc, b.cc); |
| 2279 | 2294 | } |
| ... | ... | @@ -2287,7 +2302,6 @@ pub const Key = union(enum) { |
| 2287 | 2302 | std.hash.autoHash(hasher, self.noalias_bits); |
| 2288 | 2303 | std.hash.autoHash(hasher, self.cc); |
| 2289 | 2304 | std.hash.autoHash(hasher, self.is_var_args); |
| 2290 | std.hash.autoHash(hasher, self.is_generic); | |
| 2291 | 2305 | std.hash.autoHash(hasher, self.is_noinline); |
| 2292 | 2306 | } |
| 2293 | 2307 | }; |
| ... | ... | @@ -2471,8 +2485,6 @@ pub const Key = union(enum) { |
| 2471 | 2485 | u64: u64, |
| 2472 | 2486 | i64: i64, |
| 2473 | 2487 | big_int: BigIntConst, |
| 2474 | lazy_align: Index, | |
| 2475 | lazy_size: Index, | |
| 2476 | 2488 | |
| 2477 | 2489 | /// Big enough to fit any non-BigInt value |
| 2478 | 2490 | pub const BigIntSpace = struct { |
| ... | ... | @@ -2485,7 +2497,6 @@ pub const Key = union(enum) { |
| 2485 | 2497 | return switch (storage) { |
| 2486 | 2498 | .big_int => |x| x, |
| 2487 | 2499 | inline .u64, .i64 => |x| BigIntMutable.init(&space.limbs, x).toConst(), |
| 2488 | .lazy_align, .lazy_size => unreachable, | |
| 2489 | 2500 | }; |
| 2490 | 2501 | } |
| 2491 | 2502 | }; |
| ... | ... | @@ -2734,6 +2745,7 @@ pub const Key = union(enum) { |
| 2734 | 2745 | switch (namespace_type) { |
| 2735 | 2746 | .declared => |declared| { |
| 2736 | 2747 | std.hash.autoHash(&hasher, declared.zir_index); |
| 2748 | std.hash.autoHash(&hasher, declared.arg_ty); | |
| 2737 | 2749 | const captures = switch (declared.captures) { |
| 2738 | 2750 | .owned => |cvs| cvs.get(ip), |
| 2739 | 2751 | .external => |cvs| cvs, |
| ... | ... | @@ -2742,13 +2754,13 @@ pub const Key = union(enum) { |
| 2742 | 2754 | std.hash.autoHash(&hasher, cv); |
| 2743 | 2755 | } |
| 2744 | 2756 | }, |
| 2745 | .generated_tag => |generated_tag| { | |
| 2746 | std.hash.autoHash(&hasher, generated_tag.union_type); | |
| 2747 | }, | |
| 2748 | 2757 | .reified => |reified| { |
| 2749 | 2758 | std.hash.autoHash(&hasher, reified.zir_index); |
| 2750 | 2759 | std.hash.autoHash(&hasher, reified.type_hash); |
| 2751 | 2760 | }, |
| 2761 | .generated_union_tag => |union_type| { | |
| 2762 | std.hash.autoHash(&hasher, union_type); | |
| 2763 | }, | |
| 2752 | 2764 | } |
| 2753 | 2765 | return hasher.final(); |
| 2754 | 2766 | }, |
| ... | ... | @@ -2756,23 +2768,12 @@ pub const Key = union(enum) { |
| 2756 | 2768 | .int => |int| { |
| 2757 | 2769 | var hasher = Hash.init(seed); |
| 2758 | 2770 | // Canonicalize all integers by converting them to BigIntConst. |
| 2759 | switch (int.storage) { | |
| 2760 | .u64, .i64, .big_int => { | |
| 2761 | var buffer: Key.Int.Storage.BigIntSpace = undefined; | |
| 2762 | const big_int = int.storage.toBigInt(&buffer); | |
| 2763 | ||
| 2764 | std.hash.autoHash(&hasher, int.ty); | |
| 2765 | std.hash.autoHash(&hasher, big_int.positive); | |
| 2766 | for (big_int.limbs) |limb| std.hash.autoHash(&hasher, limb); | |
| 2767 | }, | |
| 2768 | .lazy_align, .lazy_size => |lazy_ty| { | |
| 2769 | std.hash.autoHash( | |
| 2770 | &hasher, | |
| 2771 | @as(@typeInfo(Key.Int.Storage).@"union".tag_type.?, int.storage), | |
| 2772 | ); | |
| 2773 | std.hash.autoHash(&hasher, lazy_ty); | |
| 2774 | }, | |
| 2775 | } | |
| 2771 | var buffer: Key.Int.Storage.BigIntSpace = undefined; | |
| 2772 | const big_int = int.storage.toBigInt(&buffer); | |
| 2773 | ||
| 2774 | std.hash.autoHash(&hasher, int.ty); | |
| 2775 | std.hash.autoHash(&hasher, big_int.positive); | |
| 2776 | for (big_int.limbs) |limb| std.hash.autoHash(&hasher, limb); | |
| 2776 | 2777 | return hasher.final(); |
| 2777 | 2778 | }, |
| 2778 | 2779 | |
| ... | ... | @@ -3102,27 +3103,16 @@ pub const Key = union(enum) { |
| 3102 | 3103 | .u64 => |bb| aa == bb, |
| 3103 | 3104 | .i64 => |bb| aa == bb, |
| 3104 | 3105 | .big_int => |bb| bb.orderAgainstScalar(aa) == .eq, |
| 3105 | .lazy_align, .lazy_size => false, | |
| 3106 | 3106 | }, |
| 3107 | 3107 | .i64 => |aa| switch (b_info.storage) { |
| 3108 | 3108 | .u64 => |bb| aa == bb, |
| 3109 | 3109 | .i64 => |bb| aa == bb, |
| 3110 | 3110 | .big_int => |bb| bb.orderAgainstScalar(aa) == .eq, |
| 3111 | .lazy_align, .lazy_size => false, | |
| 3112 | 3111 | }, |
| 3113 | 3112 | .big_int => |aa| switch (b_info.storage) { |
| 3114 | 3113 | .u64 => |bb| aa.orderAgainstScalar(bb) == .eq, |
| 3115 | 3114 | .i64 => |bb| aa.orderAgainstScalar(bb) == .eq, |
| 3116 | 3115 | .big_int => |bb| aa.eql(bb), |
| 3117 | .lazy_align, .lazy_size => false, | |
| 3118 | }, | |
| 3119 | .lazy_align => |aa| switch (b_info.storage) { | |
| 3120 | .u64, .i64, .big_int, .lazy_size => false, | |
| 3121 | .lazy_align => |bb| aa == bb, | |
| 3122 | }, | |
| 3123 | .lazy_size => |aa| switch (b_info.storage) { | |
| 3124 | .u64, .i64, .big_int, .lazy_align => false, | |
| 3125 | .lazy_size => |bb| aa == bb, | |
| 3126 | 3116 | }, |
| 3127 | 3117 | }; |
| 3128 | 3118 | }, |
| ... | ... | @@ -3165,6 +3155,7 @@ pub const Key = union(enum) { |
| 3165 | 3155 | .declared => |a_d| { |
| 3166 | 3156 | const b_d = b_info.declared; |
| 3167 | 3157 | if (a_d.zir_index != b_d.zir_index) return false; |
| 3158 | if (a_d.arg_ty != b_d.arg_ty) return false; | |
| 3168 | 3159 | const a_captures = switch (a_d.captures) { |
| 3169 | 3160 | .owned => |s| s.get(ip), |
| 3170 | 3161 | .external => |cvs| cvs, |
| ... | ... | @@ -3175,12 +3166,12 @@ pub const Key = union(enum) { |
| 3175 | 3166 | }; |
| 3176 | 3167 | return std.mem.eql(u32, @ptrCast(a_captures), @ptrCast(b_captures)); |
| 3177 | 3168 | }, |
| 3178 | .generated_tag => |a_gt| return a_gt.union_type == b_info.generated_tag.union_type, | |
| 3179 | 3169 | .reified => |a_r| { |
| 3180 | 3170 | const b_r = b_info.reified; |
| 3181 | 3171 | return a_r.zir_index == b_r.zir_index and |
| 3182 | 3172 | a_r.type_hash == b_r.type_hash; |
| 3183 | 3173 | }, |
| 3174 | .generated_union_tag => |a_union_ty| return a_union_ty == b_info.generated_union_tag, | |
| 3184 | 3175 | } |
| 3185 | 3176 | }, |
| 3186 | 3177 | .aggregate => |a_info| { |
| ... | ... | @@ -3313,374 +3304,40 @@ pub const Key = union(enum) { |
| 3313 | 3304 | } |
| 3314 | 3305 | }; |
| 3315 | 3306 | |
| 3316 | pub const RequiresComptime = enum(u2) { no, yes, unknown, wip }; | |
| 3317 | ||
| 3318 | // Unlike `Tag.TypeUnion` which is an encoding, and `Key.UnionType` which is a | |
| 3319 | // minimal hashmap key, this type is a convenience type that contains info | |
| 3320 | // needed by semantic analysis. | |
| 3321 | pub const LoadedUnionType = struct { | |
| 3322 | tid: Zcu.PerThread.Id, | |
| 3323 | /// The index of the `Tag.TypeUnion` payload. | |
| 3324 | extra_index: u32, | |
| 3325 | // TODO: the non-fqn will be needed by the new dwarf structure | |
| 3326 | /// The name of this union type. | |
| 3327 | name: NullTerminatedString, | |
| 3328 | /// Represents the declarations inside this union. | |
| 3329 | namespace: NamespaceIndex, | |
| 3330 | /// If this is a declared type with the `.parent` name strategy, this is the `Nav` it was named after. | |
| 3331 | /// Otherwise, this is `.none`. | |
| 3332 | name_nav: Nav.Index.Optional, | |
| 3333 | /// The enum tag type. | |
| 3334 | enum_tag_ty: Index, | |
| 3335 | /// List of field types in declaration order. | |
| 3336 | /// These are `none` until `status` is `have_field_types` or `have_layout`. | |
| 3337 | field_types: Index.Slice, | |
| 3338 | /// List of field alignments in declaration order. | |
| 3339 | /// `none` means the ABI alignment of the type. | |
| 3340 | /// If this slice has length 0 it means all elements are `none`. | |
| 3341 | field_aligns: Alignment.Slice, | |
| 3342 | /// Index of the union_decl or reify ZIR instruction. | |
| 3307 | pub const LoadedStructType = struct { | |
| 3308 | /// Index of the `struct_decl` or `reify` ZIR instruction. | |
| 3343 | 3309 | zir_index: TrackedInst.Index, |
| 3344 | 3310 | captures: CaptureValue.Slice, |
| 3345 | 3311 | |
| 3346 | pub const RuntimeTag = enum(u2) { | |
| 3347 | none, | |
| 3348 | safety, | |
| 3349 | tagged, | |
| 3350 | ||
| 3351 | pub fn hasTag(self: RuntimeTag) bool { | |
| 3352 | return switch (self) { | |
| 3353 | .none => false, | |
| 3354 | .tagged, .safety => true, | |
| 3355 | }; | |
| 3356 | } | |
| 3357 | }; | |
| 3358 | ||
| 3359 | pub const Status = enum(u3) { | |
| 3360 | none, | |
| 3361 | field_types_wip, | |
| 3362 | have_field_types, | |
| 3363 | layout_wip, | |
| 3364 | have_layout, | |
| 3365 | fully_resolved_wip, | |
| 3366 | /// The types and all its fields have had their layout resolved. | |
| 3367 | /// Even through pointer, which `have_layout` does not ensure. | |
| 3368 | fully_resolved, | |
| 3369 | ||
| 3370 | pub fn haveFieldTypes(status: Status) bool { | |
| 3371 | return switch (status) { | |
| 3372 | .none, | |
| 3373 | .field_types_wip, | |
| 3374 | => false, | |
| 3375 | .have_field_types, | |
| 3376 | .layout_wip, | |
| 3377 | .have_layout, | |
| 3378 | .fully_resolved_wip, | |
| 3379 | .fully_resolved, | |
| 3380 | => true, | |
| 3381 | }; | |
| 3382 | } | |
| 3383 | ||
| 3384 | pub fn haveLayout(status: Status) bool { | |
| 3385 | return switch (status) { | |
| 3386 | .none, | |
| 3387 | .field_types_wip, | |
| 3388 | .have_field_types, | |
| 3389 | .layout_wip, | |
| 3390 | => false, | |
| 3391 | .have_layout, | |
| 3392 | .fully_resolved_wip, | |
| 3393 | .fully_resolved, | |
| 3394 | => true, | |
| 3395 | }; | |
| 3396 | } | |
| 3397 | }; | |
| 3398 | ||
| 3399 | pub fn loadTagType(self: LoadedUnionType, ip: *const InternPool) LoadedEnumType { | |
| 3400 | return ip.loadEnumType(self.enum_tag_ty); | |
| 3401 | } | |
| 3402 | ||
| 3403 | /// Pointer to an enum type which is used for the tag of the union. | |
| 3404 | /// This type is created even for untagged unions, even when the memory | |
| 3405 | /// layout does not store the tag. | |
| 3406 | /// Whether zig chooses this type or the user specifies it, it is stored here. | |
| 3407 | /// This will be set to the null type until status is `have_field_types`. | |
| 3408 | /// This accessor is provided so that the tag type can be mutated, and so that | |
| 3409 | /// when it is mutated, the mutations are observed. | |
| 3410 | /// The returned pointer expires with any addition to the `InternPool`. | |
| 3411 | fn tagTypePtr(self: LoadedUnionType, ip: *const InternPool) *Index { | |
| 3412 | const extra = ip.getLocalShared(self.tid).extra.acquire(); | |
| 3413 | const field_index = std.meta.fieldIndex(Tag.TypeUnion, "tag_ty").?; | |
| 3414 | return @ptrCast(&extra.view().items(.@"0")[self.extra_index + field_index]); | |
| 3415 | } | |
| 3416 | ||
| 3417 | pub fn tagTypeUnordered(u: LoadedUnionType, ip: *const InternPool) Index { | |
| 3418 | return @atomicLoad(Index, u.tagTypePtr(ip), .unordered); | |
| 3419 | } | |
| 3420 | ||
| 3421 | pub fn setTagType(u: LoadedUnionType, ip: *InternPool, io: Io, tag_type: Index) void { | |
| 3422 | const extra_mutex = &ip.getLocal(u.tid).mutate.extra.mutex; | |
| 3423 | extra_mutex.lockUncancelable(io); | |
| 3424 | defer extra_mutex.unlock(io); | |
| 3425 | ||
| 3426 | @atomicStore(Index, u.tagTypePtr(ip), tag_type, .release); | |
| 3427 | } | |
| 3428 | ||
| 3429 | /// The returned pointer expires with any addition to the `InternPool`. | |
| 3430 | fn flagsPtr(self: LoadedUnionType, ip: *const InternPool) *Tag.TypeUnion.Flags { | |
| 3431 | const extra = ip.getLocalShared(self.tid).extra.acquire(); | |
| 3432 | const field_index = std.meta.fieldIndex(Tag.TypeUnion, "flags").?; | |
| 3433 | return @ptrCast(&extra.view().items(.@"0")[self.extra_index + field_index]); | |
| 3434 | } | |
| 3435 | ||
| 3436 | pub fn flagsUnordered(u: LoadedUnionType, ip: *const InternPool) Tag.TypeUnion.Flags { | |
| 3437 | return @atomicLoad(Tag.TypeUnion.Flags, u.flagsPtr(ip), .unordered); | |
| 3438 | } | |
| 3439 | ||
| 3440 | pub fn setStatus(u: LoadedUnionType, ip: *InternPool, io: Io, status: Status) void { | |
| 3441 | const extra_mutex = &ip.getLocal(u.tid).mutate.extra.mutex; | |
| 3442 | extra_mutex.lockUncancelable(io); | |
| 3443 | defer extra_mutex.unlock(io); | |
| 3444 | ||
| 3445 | const flags_ptr = u.flagsPtr(ip); | |
| 3446 | var flags = flags_ptr.*; | |
| 3447 | flags.status = status; | |
| 3448 | @atomicStore(Tag.TypeUnion.Flags, flags_ptr, flags, .release); | |
| 3449 | } | |
| 3450 | ||
| 3451 | pub fn setStatusIfLayoutWip(u: LoadedUnionType, ip: *InternPool, io: Io, status: Status) void { | |
| 3452 | const extra_mutex = &ip.getLocal(u.tid).mutate.extra.mutex; | |
| 3453 | extra_mutex.lockUncancelable(io); | |
| 3454 | defer extra_mutex.unlock(io); | |
| 3455 | ||
| 3456 | const flags_ptr = u.flagsPtr(ip); | |
| 3457 | var flags = flags_ptr.*; | |
| 3458 | if (flags.status == .layout_wip) flags.status = status; | |
| 3459 | @atomicStore(Tag.TypeUnion.Flags, flags_ptr, flags, .release); | |
| 3460 | } | |
| 3461 | ||
| 3462 | pub fn setAlignment(u: LoadedUnionType, ip: *InternPool, io: Io, alignment: Alignment) void { | |
| 3463 | const extra_mutex = &ip.getLocal(u.tid).mutate.extra.mutex; | |
| 3464 | extra_mutex.lockUncancelable(io); | |
| 3465 | defer extra_mutex.unlock(io); | |
| 3466 | ||
| 3467 | const flags_ptr = u.flagsPtr(ip); | |
| 3468 | var flags = flags_ptr.*; | |
| 3469 | flags.alignment = alignment; | |
| 3470 | @atomicStore(Tag.TypeUnion.Flags, flags_ptr, flags, .release); | |
| 3471 | } | |
| 3472 | ||
| 3473 | pub fn assumeRuntimeBitsIfFieldTypesWip(u: LoadedUnionType, ip: *InternPool, io: Io) bool { | |
| 3474 | const extra_mutex = &ip.getLocal(u.tid).mutate.extra.mutex; | |
| 3475 | extra_mutex.lockUncancelable(io); | |
| 3476 | defer extra_mutex.unlock(io); | |
| 3477 | ||
| 3478 | const flags_ptr = u.flagsPtr(ip); | |
| 3479 | var flags = flags_ptr.*; | |
| 3480 | defer if (flags.status == .field_types_wip) { | |
| 3481 | flags.assumed_runtime_bits = true; | |
| 3482 | @atomicStore(Tag.TypeUnion.Flags, flags_ptr, flags, .release); | |
| 3483 | }; | |
| 3484 | return flags.status == .field_types_wip; | |
| 3485 | } | |
| 3486 | ||
| 3487 | pub fn requiresComptime(u: LoadedUnionType, ip: *const InternPool) RequiresComptime { | |
| 3488 | return u.flagsUnordered(ip).requires_comptime; | |
| 3489 | } | |
| 3490 | ||
| 3491 | pub fn setRequiresComptimeWip(u: LoadedUnionType, ip: *InternPool, io: Io) RequiresComptime { | |
| 3492 | const extra_mutex = &ip.getLocal(u.tid).mutate.extra.mutex; | |
| 3493 | extra_mutex.lockUncancelable(io); | |
| 3494 | defer extra_mutex.unlock(io); | |
| 3495 | ||
| 3496 | const flags_ptr = u.flagsPtr(ip); | |
| 3497 | var flags = flags_ptr.*; | |
| 3498 | defer if (flags.requires_comptime == .unknown) { | |
| 3499 | flags.requires_comptime = .wip; | |
| 3500 | @atomicStore(Tag.TypeUnion.Flags, flags_ptr, flags, .release); | |
| 3501 | }; | |
| 3502 | return flags.requires_comptime; | |
| 3503 | } | |
| 3504 | ||
| 3505 | pub fn setRequiresComptime(u: LoadedUnionType, ip: *InternPool, io: Io, requires_comptime: RequiresComptime) void { | |
| 3506 | assert(requires_comptime != .wip); // see setRequiresComptimeWip | |
| 3507 | ||
| 3508 | const extra_mutex = &ip.getLocal(u.tid).mutate.extra.mutex; | |
| 3509 | extra_mutex.lockUncancelable(io); | |
| 3510 | defer extra_mutex.unlock(io); | |
| 3511 | ||
| 3512 | const flags_ptr = u.flagsPtr(ip); | |
| 3513 | var flags = flags_ptr.*; | |
| 3514 | flags.requires_comptime = requires_comptime; | |
| 3515 | @atomicStore(Tag.TypeUnion.Flags, flags_ptr, flags, .release); | |
| 3516 | } | |
| 3517 | ||
| 3518 | pub fn assumePointerAlignedIfFieldTypesWip(u: LoadedUnionType, ip: *InternPool, io: Io, ptr_align: Alignment) bool { | |
| 3519 | const extra_mutex = &ip.getLocal(u.tid).mutate.extra.mutex; | |
| 3520 | extra_mutex.lockUncancelable(io); | |
| 3521 | defer extra_mutex.unlock(io); | |
| 3522 | ||
| 3523 | const flags_ptr = u.flagsPtr(ip); | |
| 3524 | var flags = flags_ptr.*; | |
| 3525 | defer if (flags.status == .field_types_wip) { | |
| 3526 | flags.alignment = ptr_align; | |
| 3527 | flags.assumed_pointer_aligned = true; | |
| 3528 | @atomicStore(Tag.TypeUnion.Flags, flags_ptr, flags, .release); | |
| 3529 | }; | |
| 3530 | return flags.status == .field_types_wip; | |
| 3531 | } | |
| 3532 | ||
| 3533 | /// The returned pointer expires with any addition to the `InternPool`. | |
| 3534 | fn sizePtr(self: LoadedUnionType, ip: *const InternPool) *u32 { | |
| 3535 | const extra = ip.getLocalShared(self.tid).extra.acquire(); | |
| 3536 | const field_index = std.meta.fieldIndex(Tag.TypeUnion, "size").?; | |
| 3537 | return &extra.view().items(.@"0")[self.extra_index + field_index]; | |
| 3538 | } | |
| 3539 | ||
| 3540 | pub fn sizeUnordered(u: LoadedUnionType, ip: *const InternPool) u32 { | |
| 3541 | return @atomicLoad(u32, u.sizePtr(ip), .unordered); | |
| 3542 | } | |
| 3543 | ||
| 3544 | /// The returned pointer expires with any addition to the `InternPool`. | |
| 3545 | fn paddingPtr(self: LoadedUnionType, ip: *const InternPool) *u32 { | |
| 3546 | const extra = ip.getLocalShared(self.tid).extra.acquire(); | |
| 3547 | const field_index = std.meta.fieldIndex(Tag.TypeUnion, "padding").?; | |
| 3548 | return &extra.view().items(.@"0")[self.extra_index + field_index]; | |
| 3549 | } | |
| 3550 | ||
| 3551 | pub fn paddingUnordered(u: LoadedUnionType, ip: *const InternPool) u32 { | |
| 3552 | return @atomicLoad(u32, u.paddingPtr(ip), .unordered); | |
| 3553 | } | |
| 3554 | ||
| 3555 | pub fn hasTag(self: LoadedUnionType, ip: *const InternPool) bool { | |
| 3556 | return self.flagsUnordered(ip).runtime_tag.hasTag(); | |
| 3557 | } | |
| 3558 | ||
| 3559 | pub fn haveFieldTypes(self: LoadedUnionType, ip: *const InternPool) bool { | |
| 3560 | return self.flagsUnordered(ip).status.haveFieldTypes(); | |
| 3561 | } | |
| 3562 | ||
| 3563 | pub fn haveLayout(self: LoadedUnionType, ip: *const InternPool) bool { | |
| 3564 | return self.flagsUnordered(ip).status.haveLayout(); | |
| 3565 | } | |
| 3566 | ||
| 3567 | pub fn setHaveLayout(u: LoadedUnionType, ip: *InternPool, io: Io, size: u32, padding: u32, alignment: Alignment) void { | |
| 3568 | const extra_mutex = &ip.getLocal(u.tid).mutate.extra.mutex; | |
| 3569 | extra_mutex.lockUncancelable(io); | |
| 3570 | defer extra_mutex.unlock(io); | |
| 3571 | ||
| 3572 | @atomicStore(u32, u.sizePtr(ip), size, .unordered); | |
| 3573 | @atomicStore(u32, u.paddingPtr(ip), padding, .unordered); | |
| 3574 | const flags_ptr = u.flagsPtr(ip); | |
| 3575 | var flags = flags_ptr.*; | |
| 3576 | flags.alignment = alignment; | |
| 3577 | flags.status = .have_layout; | |
| 3578 | @atomicStore(Tag.TypeUnion.Flags, flags_ptr, flags, .release); | |
| 3579 | } | |
| 3580 | ||
| 3581 | pub fn fieldAlign(self: LoadedUnionType, ip: *const InternPool, field_index: usize) Alignment { | |
| 3582 | if (self.field_aligns.len == 0) return .none; | |
| 3583 | return self.field_aligns.get(ip)[field_index]; | |
| 3584 | } | |
| 3585 | ||
| 3586 | /// This does not mutate the field of LoadedUnionType. | |
| 3587 | pub fn setZirIndex(self: LoadedUnionType, ip: *InternPool, new_zir_index: TrackedInst.Index.Optional) void { | |
| 3588 | const flags_field_index = std.meta.fieldIndex(Tag.TypeUnion, "flags").?; | |
| 3589 | const zir_index_field_index = std.meta.fieldIndex(Tag.TypeUnion, "zir_index").?; | |
| 3590 | const ptr: *TrackedInst.Index.Optional = | |
| 3591 | @ptrCast(&ip.extra_.items[self.flags_index - flags_field_index + zir_index_field_index]); | |
| 3592 | ptr.* = new_zir_index; | |
| 3593 | } | |
| 3594 | ||
| 3595 | pub fn setFieldTypes(self: LoadedUnionType, ip: *const InternPool, types: []const Index) void { | |
| 3596 | @memcpy(self.field_types.get(ip), types); | |
| 3597 | } | |
| 3598 | ||
| 3599 | pub fn setFieldAligns(self: LoadedUnionType, ip: *const InternPool, aligns: []const Alignment) void { | |
| 3600 | if (aligns.len == 0) return; | |
| 3601 | assert(self.flagsUnordered(ip).any_aligned_fields); | |
| 3602 | @memcpy(self.field_aligns.get(ip), aligns); | |
| 3603 | } | |
| 3604 | }; | |
| 3605 | ||
| 3606 | pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType { | |
| 3607 | const unwrapped_index = index.unwrap(ip); | |
| 3608 | const extra_list = unwrapped_index.getExtra(ip); | |
| 3609 | const data = unwrapped_index.getData(ip); | |
| 3610 | const type_union = extraDataTrail(extra_list, Tag.TypeUnion, data); | |
| 3611 | const fields_len = type_union.data.fields_len; | |
| 3612 | ||
| 3613 | var extra_index = type_union.end; | |
| 3614 | const captures_len = if (type_union.data.flags.any_captures) c: { | |
| 3615 | const len = extra_list.view().items(.@"0")[extra_index]; | |
| 3616 | extra_index += 1; | |
| 3617 | break :c len; | |
| 3618 | } else 0; | |
| 3619 | ||
| 3620 | const captures: CaptureValue.Slice = .{ | |
| 3621 | .tid = unwrapped_index.tid, | |
| 3622 | .start = extra_index, | |
| 3623 | .len = captures_len, | |
| 3624 | }; | |
| 3625 | extra_index += captures_len; | |
| 3626 | if (type_union.data.flags.is_reified) { | |
| 3627 | extra_index += 2; // PackedU64 | |
| 3628 | } | |
| 3629 | ||
| 3630 | const field_types: Index.Slice = .{ | |
| 3631 | .tid = unwrapped_index.tid, | |
| 3632 | .start = extra_index, | |
| 3633 | .len = fields_len, | |
| 3634 | }; | |
| 3635 | extra_index += fields_len; | |
| 3636 | ||
| 3637 | const field_aligns = if (type_union.data.flags.any_aligned_fields) a: { | |
| 3638 | const a: Alignment.Slice = .{ | |
| 3639 | .tid = unwrapped_index.tid, | |
| 3640 | .start = extra_index, | |
| 3641 | .len = fields_len, | |
| 3642 | }; | |
| 3643 | extra_index += std.math.divCeil(u32, fields_len, 4) catch unreachable; | |
| 3644 | break :a a; | |
| 3645 | } else Alignment.Slice.empty; | |
| 3646 | ||
| 3647 | return .{ | |
| 3648 | .tid = unwrapped_index.tid, | |
| 3649 | .extra_index = data, | |
| 3650 | .name = type_union.data.name, | |
| 3651 | .name_nav = type_union.data.name_nav, | |
| 3652 | .namespace = type_union.data.namespace, | |
| 3653 | .enum_tag_ty = type_union.data.tag_ty, | |
| 3654 | .field_types = field_types, | |
| 3655 | .field_aligns = field_aligns, | |
| 3656 | .zir_index = type_union.data.zir_index, | |
| 3657 | .captures = captures, | |
| 3658 | }; | |
| 3659 | } | |
| 3660 | ||
| 3661 | pub const LoadedStructType = struct { | |
| 3662 | tid: Zcu.PerThread.Id, | |
| 3663 | /// The index of the `Tag.TypeStruct` or `Tag.TypeStructPacked` payload. | |
| 3664 | extra_index: u32, | |
| 3665 | 3312 | // TODO: the non-fqn will be needed by the new dwarf structure |
| 3666 | 3313 | /// The name of this struct type. |
| 3667 | 3314 | name: NullTerminatedString, |
| 3668 | namespace: NamespaceIndex, | |
| 3669 | 3315 | /// If this is a declared type with the `.parent` name strategy, this is the `Nav` it was named after. |
| 3670 | 3316 | /// Otherwise, or if this is a file's root struct type, this is `.none`. |
| 3671 | 3317 | name_nav: Nav.Index.Optional, |
| 3672 | /// Index of the `struct_decl` or `reify` ZIR instruction. | |
| 3673 | zir_index: TrackedInst.Index, | |
| 3318 | namespace: NamespaceIndex, | |
| 3319 | ||
| 3674 | 3320 | layout: std.builtin.Type.ContainerLayout, |
| 3321 | /// May be `undefined` if `layout != .@"packed"`. | |
| 3322 | packed_backing_mode: PackedBackingMode, | |
| 3323 | /// May be `undefined` if `layout != .@"packed", | |
| 3324 | packed_backing_int_type: Index, | |
| 3325 | ||
| 3326 | field_name_map: MapIndex, | |
| 3675 | 3327 | field_names: NullTerminatedString.Slice, |
| 3676 | 3328 | field_types: Index.Slice, |
| 3677 | field_inits: Index.Slice, | |
| 3329 | field_defaults: Index.Slice, | |
| 3678 | 3330 | field_aligns: Alignment.Slice, |
| 3679 | runtime_order: RuntimeOrder.Slice, | |
| 3680 | comptime_bits: ComptimeBits, | |
| 3681 | offsets: Offsets, | |
| 3682 | names_map: OptionalMapIndex, | |
| 3683 | captures: CaptureValue.Slice, | |
| 3331 | field_is_comptime_bits: ComptimeBits, | |
| 3332 | field_runtime_order: RuntimeOrder.Slice, | |
| 3333 | field_offsets: Offsets, | |
| 3334 | ||
| 3335 | // These fields are only valid once the layout is resolved, and are never valid for `layout == .@"packed"`. | |
| 3336 | has_no_possible_value: bool, | |
| 3337 | has_one_possible_value: bool, | |
| 3338 | comptime_only: bool, | |
| 3339 | size: u32, | |
| 3340 | alignment: Alignment, | |
| 3684 | 3341 | |
| 3685 | 3342 | pub const ComptimeBits = struct { |
| 3686 | 3343 | tid: Zcu.PerThread.Id, |
| ... | ... | @@ -3690,22 +3347,14 @@ pub const LoadedStructType = struct { |
| 3690 | 3347 | |
| 3691 | 3348 | pub const empty: ComptimeBits = .{ .tid = .main, .start = 0, .len = 0 }; |
| 3692 | 3349 | |
| 3693 | pub fn get(this: ComptimeBits, ip: *const InternPool) []u32 { | |
| 3350 | pub fn getAll(this: ComptimeBits, ip: *const InternPool) []u32 { | |
| 3694 | 3351 | const extra = ip.getLocalShared(this.tid).extra.acquire(); |
| 3695 | 3352 | return extra.view().items(.@"0")[this.start..][0..this.len]; |
| 3696 | 3353 | } |
| 3697 | 3354 | |
| 3698 | pub fn getBit(this: ComptimeBits, ip: *const InternPool, i: usize) bool { | |
| 3355 | pub fn get(this: ComptimeBits, ip: *const InternPool, i: usize) bool { | |
| 3699 | 3356 | if (this.len == 0) return false; |
| 3700 | return @as(u1, @truncate(this.get(ip)[i / 32] >> @intCast(i % 32))) != 0; | |
| 3701 | } | |
| 3702 | ||
| 3703 | pub fn setBit(this: ComptimeBits, ip: *const InternPool, i: usize) void { | |
| 3704 | this.get(ip)[i / 32] |= @as(u32, 1) << @intCast(i % 32); | |
| 3705 | } | |
| 3706 | ||
| 3707 | pub fn clearBit(this: ComptimeBits, ip: *const InternPool, i: usize) void { | |
| 3708 | this.get(ip)[i / 32] &= ~(@as(u32, 1) << @intCast(i % 32)); | |
| 3357 | return @as(u1, @truncate(this.getAll(ip)[i / 32] >> @intCast(i % 32))) != 0; | |
| 3709 | 3358 | } |
| 3710 | 3359 | }; |
| 3711 | 3360 | |
| ... | ... | @@ -3753,865 +3402,550 @@ pub const LoadedStructType = struct { |
| 3753 | 3402 | |
| 3754 | 3403 | /// Look up field index based on field name. |
| 3755 | 3404 | pub fn nameIndex(s: LoadedStructType, ip: *const InternPool, name: NullTerminatedString) ?u32 { |
| 3756 | const names_map = s.names_map.unwrap() orelse { | |
| 3757 | const i = name.toUnsigned(ip) orelse return null; | |
| 3758 | if (i >= s.field_types.len) return null; | |
| 3759 | return i; | |
| 3760 | }; | |
| 3761 | const map = names_map.get(ip); | |
| 3405 | const map = s.field_name_map.get(ip); | |
| 3762 | 3406 | const adapter: NullTerminatedString.Adapter = .{ .strings = s.field_names.get(ip) }; |
| 3763 | 3407 | const field_index = map.getIndexAdapted(name, adapter) orelse return null; |
| 3764 | 3408 | return @intCast(field_index); |
| 3765 | 3409 | } |
| 3766 | 3410 | |
| 3767 | /// Returns the already-existing field with the same name, if any. | |
| 3768 | pub fn addFieldName( | |
| 3769 | s: LoadedStructType, | |
| 3770 | ip: *InternPool, | |
| 3771 | name: NullTerminatedString, | |
| 3772 | ) ?u32 { | |
| 3773 | const extra = ip.getLocalShared(s.tid).extra.acquire(); | |
| 3774 | return ip.addFieldName(extra, s.names_map.unwrap().?, s.field_names.start, name); | |
| 3775 | } | |
| 3776 | ||
| 3777 | pub fn fieldAlign(s: LoadedStructType, ip: *const InternPool, i: usize) Alignment { | |
| 3778 | if (s.field_aligns.len == 0) return .none; | |
| 3779 | return s.field_aligns.get(ip)[i]; | |
| 3780 | } | |
| 3781 | ||
| 3782 | pub fn fieldInit(s: LoadedStructType, ip: *const InternPool, i: usize) Index { | |
| 3783 | if (s.field_inits.len == 0) return .none; | |
| 3784 | assert(s.haveFieldInits(ip)); | |
| 3785 | return s.field_inits.get(ip)[i]; | |
| 3786 | } | |
| 3787 | ||
| 3788 | pub fn fieldName(s: LoadedStructType, ip: *const InternPool, i: usize) NullTerminatedString { | |
| 3789 | return s.field_names.get(ip)[i]; | |
| 3790 | } | |
| 3791 | ||
| 3792 | pub fn fieldIsComptime(s: LoadedStructType, ip: *const InternPool, i: usize) bool { | |
| 3793 | return s.comptime_bits.getBit(ip, i); | |
| 3794 | } | |
| 3795 | ||
| 3796 | pub fn setFieldComptime(s: LoadedStructType, ip: *InternPool, i: usize) void { | |
| 3797 | s.comptime_bits.setBit(ip, i); | |
| 3798 | } | |
| 3799 | ||
| 3800 | /// The returned pointer expires with any addition to the `InternPool`. | |
| 3411 | /// Iterates over non-comptime fields in the order they are laid out in memory at runtime. | |
| 3412 | /// May or may not include zero-bit fields. | |
| 3801 | 3413 | /// Asserts the struct is not packed. |
| 3802 | fn flagsPtr(s: LoadedStructType, ip: *const InternPool) *Tag.TypeStruct.Flags { | |
| 3803 | assert(s.layout != .@"packed"); | |
| 3804 | const extra = ip.getLocalShared(s.tid).extra.acquire(); | |
| 3805 | const flags_field_index = std.meta.fieldIndex(Tag.TypeStruct, "flags").?; | |
| 3806 | return @ptrCast(&extra.view().items(.@"0")[s.extra_index + flags_field_index]); | |
| 3807 | } | |
| 3808 | ||
| 3809 | pub fn flagsUnordered(s: LoadedStructType, ip: *const InternPool) Tag.TypeStruct.Flags { | |
| 3810 | return @atomicLoad(Tag.TypeStruct.Flags, s.flagsPtr(ip), .unordered); | |
| 3811 | } | |
| 3812 | ||
| 3813 | /// The returned pointer expires with any addition to the `InternPool`. | |
| 3814 | /// Asserts that the struct is packed. | |
| 3815 | fn packedFlagsPtr(s: LoadedStructType, ip: *const InternPool) *Tag.TypeStructPacked.Flags { | |
| 3816 | assert(s.layout == .@"packed"); | |
| 3817 | const extra = ip.getLocalShared(s.tid).extra.acquire(); | |
| 3818 | const flags_field_index = std.meta.fieldIndex(Tag.TypeStructPacked, "flags").?; | |
| 3819 | return @ptrCast(&extra.view().items(.@"0")[s.extra_index + flags_field_index]); | |
| 3820 | } | |
| 3821 | ||
| 3822 | pub fn packedFlagsUnordered(s: LoadedStructType, ip: *const InternPool) Tag.TypeStructPacked.Flags { | |
| 3823 | return @atomicLoad(Tag.TypeStructPacked.Flags, s.packedFlagsPtr(ip), .unordered); | |
| 3414 | pub fn iterateRuntimeOrder(s: *const LoadedStructType, ip: *InternPool) RuntimeOrderIterator { | |
| 3415 | switch (s.layout) { | |
| 3416 | .auto => { | |
| 3417 | const ro = std.mem.sliceTo(s.field_runtime_order.get(ip), .omitted); | |
| 3418 | return .{ | |
| 3419 | .runtime_order = ro, | |
| 3420 | .fields_len = @intCast(ro.len), | |
| 3421 | .next_index = 0, | |
| 3422 | }; | |
| 3423 | }, | |
| 3424 | .@"extern" => return .{ | |
| 3425 | .runtime_order = null, | |
| 3426 | .fields_len = s.field_names.len, | |
| 3427 | .next_index = 0, | |
| 3428 | }, | |
| 3429 | .@"packed" => unreachable, | |
| 3430 | } | |
| 3824 | 3431 | } |
| 3432 | pub const RuntimeOrderIterator = struct { | |
| 3433 | runtime_order: ?[]const RuntimeOrder, | |
| 3434 | fields_len: u32, | |
| 3435 | next_index: u32, | |
| 3436 | pub fn next(it: *RuntimeOrderIterator) ?u32 { | |
| 3437 | const i = it.next_index; | |
| 3438 | if (i == it.fields_len) return null; | |
| 3439 | it.next_index = i + 1; | |
| 3440 | const ro = it.runtime_order orelse return i; | |
| 3441 | return ro[i].toInt().?; | |
| 3442 | } | |
| 3443 | }; | |
| 3825 | 3444 | |
| 3826 | /// Reads the non-opv flag calculated during AstGen. Used to short-circuit more | |
| 3827 | /// complicated logic. | |
| 3828 | pub fn knownNonOpv(s: LoadedStructType, ip: *const InternPool) bool { | |
| 3829 | return switch (s.layout) { | |
| 3830 | .@"packed" => false, | |
| 3831 | .auto, .@"extern" => s.flagsUnordered(ip).known_non_opv, | |
| 3832 | }; | |
| 3445 | pub fn iterateRuntimeOrderReverse(s: *const LoadedStructType, ip: *InternPool) ReverseRuntimeOrderIterator { | |
| 3446 | switch (s.layout) { | |
| 3447 | .auto => { | |
| 3448 | const ro = std.mem.sliceTo(s.field_runtime_order.get(ip), .omitted); | |
| 3449 | return .{ | |
| 3450 | .runtime_order = ro, | |
| 3451 | .last_index = @intCast(ro.len), | |
| 3452 | }; | |
| 3453 | }, | |
| 3454 | .@"extern" => return .{ | |
| 3455 | .runtime_order = null, | |
| 3456 | .last_index = s.field_names.len, | |
| 3457 | }, | |
| 3458 | .@"packed" => unreachable, | |
| 3459 | } | |
| 3833 | 3460 | } |
| 3461 | pub const ReverseRuntimeOrderIterator = struct { | |
| 3462 | runtime_order: ?[]const RuntimeOrder, | |
| 3463 | last_index: u32, | |
| 3464 | pub fn next(it: *ReverseRuntimeOrderIterator) ?u32 { | |
| 3465 | if (it.last_index == 0) return null; | |
| 3466 | const i = it.last_index - 1; | |
| 3467 | it.last_index = i; | |
| 3468 | const ro = it.runtime_order orelse return i; | |
| 3469 | return ro[i].toInt().?; | |
| 3470 | } | |
| 3471 | }; | |
| 3472 | }; | |
| 3834 | 3473 | |
| 3835 | pub fn requiresComptime(s: LoadedStructType, ip: *const InternPool) RequiresComptime { | |
| 3836 | return s.flagsUnordered(ip).requires_comptime; | |
| 3837 | } | |
| 3474 | /// Unlike `Tag.TypeUnion` which is an encoding, and `Key.UnionType` which is a | |
| 3475 | /// minimal hashmap key, this type is a convenience type that contains info | |
| 3476 | /// needed by semantic analysis. | |
| 3477 | pub const LoadedUnionType = struct { | |
| 3478 | /// Index of the `union_decl` or `reify` ZIR instruction. | |
| 3479 | zir_index: TrackedInst.Index, | |
| 3480 | captures: CaptureValue.Slice, | |
| 3838 | 3481 | |
| 3839 | pub fn setRequiresComptimeWip(s: LoadedStructType, ip: *InternPool, io: Io) RequiresComptime { | |
| 3840 | const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex; | |
| 3841 | extra_mutex.lockUncancelable(io); | |
| 3842 | defer extra_mutex.unlock(io); | |
| 3482 | // TODO: the non-fqn will be needed by the new dwarf structure | |
| 3483 | /// The name of this union type. | |
| 3484 | name: NullTerminatedString, | |
| 3485 | /// If this is a declared type with the `.parent` name strategy, this is the `Nav` it was named after. | |
| 3486 | /// Otherwise, this is `.none`. | |
| 3487 | name_nav: Nav.Index.Optional, | |
| 3488 | namespace: NamespaceIndex, | |
| 3843 | 3489 | |
| 3844 | const flags_ptr = s.flagsPtr(ip); | |
| 3845 | var flags = flags_ptr.*; | |
| 3846 | defer if (flags.requires_comptime == .unknown) { | |
| 3847 | flags.requires_comptime = .wip; | |
| 3848 | @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release); | |
| 3849 | }; | |
| 3850 | return flags.requires_comptime; | |
| 3851 | } | |
| 3490 | layout: std.builtin.Type.ContainerLayout, | |
| 3491 | runtime_tag: RuntimeTag, | |
| 3492 | /// Even if `runtime_tag == .none`, this is populated with the union's "hypothetical" tag type. | |
| 3493 | enum_tag_type: Index, | |
| 3494 | /// May be `undefined` if `layout != .@"packed"`. | |
| 3495 | packed_backing_mode: PackedBackingMode, | |
| 3496 | /// May be `undefined` if `layout != .@"packed", | |
| 3497 | packed_backing_int_type: Index, | |
| 3498 | ||
| 3499 | // Field names are not stored here, because fields are guaranteed to map one-to-one to the | |
| 3500 | // fields of the enum tag type. If you need field names, load them from `enum_tag_type`. | |
| 3501 | field_types: Index.Slice, | |
| 3502 | field_aligns: Alignment.Slice, | |
| 3852 | 3503 | |
| 3853 | pub fn setRequiresComptime(s: LoadedStructType, ip: *InternPool, io: Io, requires_comptime: RequiresComptime) void { | |
| 3854 | assert(requires_comptime != .wip); // see setRequiresComptimeWip | |
| 3504 | // These fields are only valid once the layout is resolved, and are never valid for `layout == .@"packed"`. | |
| 3505 | has_no_possible_value: bool, | |
| 3506 | has_one_possible_value: bool, | |
| 3507 | comptime_only: bool, | |
| 3508 | size: u32, | |
| 3509 | padding: u32, | |
| 3510 | alignment: Alignment, | |
| 3855 | 3511 | |
| 3856 | const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex; | |
| 3857 | extra_mutex.lockUncancelable(io); | |
| 3858 | defer extra_mutex.unlock(io); | |
| 3512 | pub const RuntimeTag = enum(u2) { | |
| 3513 | none, | |
| 3514 | safety, | |
| 3515 | tagged, | |
| 3516 | }; | |
| 3517 | }; | |
| 3859 | 3518 | |
| 3860 | const flags_ptr = s.flagsPtr(ip); | |
| 3861 | var flags = flags_ptr.*; | |
| 3862 | flags.requires_comptime = requires_comptime; | |
| 3863 | @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release); | |
| 3864 | } | |
| 3519 | pub const LoadedEnumType = struct { | |
| 3520 | /// This is `none` iff this is a generated tag type. | |
| 3521 | /// Otherwise, index of the `enum_decl` or `reify` ZIR instruction. | |
| 3522 | zir_index: TrackedInst.Index.Optional, | |
| 3523 | captures: CaptureValue.Slice, | |
| 3524 | /// If `zir_index` is `.none`, this is the union type for which this enum is the tag type. | |
| 3525 | owner_union: Index, | |
| 3865 | 3526 | |
| 3866 | pub fn assumeRuntimeBitsIfFieldTypesWip(s: LoadedStructType, ip: *InternPool, io: Io) bool { | |
| 3867 | if (s.layout == .@"packed") return false; | |
| 3527 | // TODO: the non-fqn will be needed by the new dwarf structure | |
| 3528 | /// The name of this enum type. | |
| 3529 | name: NullTerminatedString, | |
| 3530 | /// If this is a declared type with the `.parent` name strategy, this is the `Nav` it was named after. | |
| 3531 | /// Otherwise, this is `.none`. | |
| 3532 | name_nav: Nav.Index.Optional, | |
| 3533 | namespace: NamespaceIndex, | |
| 3868 | 3534 | |
| 3869 | const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex; | |
| 3870 | extra_mutex.lockUncancelable(io); | |
| 3871 | defer extra_mutex.unlock(io); | |
| 3535 | /// An integer type which is used for the numerical value of the enum. Populated immediately, regardless | |
| 3536 | /// of whether the integer tag type was explicitly provided or inferred by the compiler. | |
| 3537 | int_tag_type: Index, | |
| 3538 | int_tag_is_explicit: bool, | |
| 3539 | nonexhaustive: bool, | |
| 3540 | ||
| 3541 | /// Uses `NullTerminatedString.Adapter` with `field_names`. | |
| 3542 | field_name_map: MapIndex, | |
| 3543 | /// If this is `.none`, the enum tag type is auto-generated and so the fields are auto-numbered. | |
| 3544 | /// Otherwise, uses `Index.Adapter` with `field_values`. | |
| 3545 | field_value_map: OptionalMapIndex, | |
| 3546 | field_names: NullTerminatedString.Slice, | |
| 3547 | /// Empty if `field_value_map` is `.none`. | |
| 3548 | field_values: Index.Slice, | |
| 3872 | 3549 | |
| 3873 | const flags_ptr = s.flagsPtr(ip); | |
| 3874 | var flags = flags_ptr.*; | |
| 3875 | defer if (flags.field_types_wip) { | |
| 3876 | flags.assumed_runtime_bits = true; | |
| 3877 | @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release); | |
| 3878 | }; | |
| 3879 | return flags.field_types_wip; | |
| 3550 | /// Look up field index based on field name. | |
| 3551 | pub fn nameIndex(e: LoadedEnumType, ip: *const InternPool, name: NullTerminatedString) ?u32 { | |
| 3552 | const map = e.field_name_map.get(ip); | |
| 3553 | const adapter: NullTerminatedString.Adapter = .{ .strings = e.field_names.get(ip) }; | |
| 3554 | const field_index = map.getIndexAdapted(name, adapter) orelse return null; | |
| 3555 | return @intCast(field_index); | |
| 3880 | 3556 | } |
| 3881 | 3557 | |
| 3882 | pub fn setFieldTypesWip(s: LoadedStructType, ip: *InternPool, io: Io) bool { | |
| 3883 | if (s.layout == .@"packed") return false; | |
| 3884 | ||
| 3885 | const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex; | |
| 3886 | extra_mutex.lockUncancelable(io); | |
| 3887 | defer extra_mutex.unlock(io); | |
| 3888 | ||
| 3889 | const flags_ptr = s.flagsPtr(ip); | |
| 3890 | var flags = flags_ptr.*; | |
| 3891 | defer { | |
| 3892 | flags.field_types_wip = true; | |
| 3893 | @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release); | |
| 3558 | /// Look up field index based on integer tag value. | |
| 3559 | /// Asserts that the type of `tag_val` is `enum_obj.int_tag_type`. | |
| 3560 | /// Asserts that `tag_val` is not `undefined`. | |
| 3561 | pub fn tagValueIndex(e: LoadedEnumType, ip: *const InternPool, tag_val: Index) ?u32 { | |
| 3562 | assert(ip.typeOf(tag_val) == e.int_tag_type); | |
| 3563 | assert(ip.indexToKey(tag_val) == .int); | |
| 3564 | if (e.field_value_map.unwrap()) |field_value_map| { | |
| 3565 | const map = field_value_map.get(ip); | |
| 3566 | const adapter: Index.Adapter = .{ .indexes = e.field_values.get(ip) }; | |
| 3567 | const field_index = map.getIndexAdapted(tag_val, adapter) orelse return null; | |
| 3568 | return @intCast(field_index); | |
| 3894 | 3569 | } |
| 3895 | return flags.field_types_wip; | |
| 3570 | // Auto-numbered enum, so convert `tag_val` to field index | |
| 3571 | const field_index = switch (ip.indexToKey(tag_val).int.storage) { | |
| 3572 | inline .u64, .i64 => |x| std.math.cast(u32, x) orelse return null, | |
| 3573 | .big_int => |x| x.toInt(u32) catch return null, | |
| 3574 | }; | |
| 3575 | return if (field_index < e.field_names.len) field_index else null; | |
| 3896 | 3576 | } |
| 3577 | }; | |
| 3897 | 3578 | |
| 3898 | pub fn clearFieldTypesWip(s: LoadedStructType, ip: *InternPool, io: Io) void { | |
| 3899 | if (s.layout == .@"packed") return; | |
| 3579 | pub const LoadedOpaqueType = struct { | |
| 3580 | /// Index of the `opaque_decl` instruction. | |
| 3581 | zir_index: TrackedInst.Index, | |
| 3582 | captures: CaptureValue.Slice, | |
| 3900 | 3583 | |
| 3901 | const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex; | |
| 3902 | extra_mutex.lockUncancelable(io); | |
| 3903 | defer extra_mutex.unlock(io); | |
| 3904 | ||
| 3905 | const flags_ptr = s.flagsPtr(ip); | |
| 3906 | var flags = flags_ptr.*; | |
| 3907 | flags.field_types_wip = false; | |
| 3908 | @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release); | |
| 3909 | } | |
| 3910 | ||
| 3911 | pub fn setLayoutWip(s: LoadedStructType, ip: *InternPool, io: Io) bool { | |
| 3912 | if (s.layout == .@"packed") return false; | |
| 3913 | ||
| 3914 | const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex; | |
| 3915 | extra_mutex.lockUncancelable(io); | |
| 3916 | defer extra_mutex.unlock(io); | |
| 3917 | ||
| 3918 | const flags_ptr = s.flagsPtr(ip); | |
| 3919 | var flags = flags_ptr.*; | |
| 3920 | defer { | |
| 3921 | flags.layout_wip = true; | |
| 3922 | @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release); | |
| 3923 | } | |
| 3924 | return flags.layout_wip; | |
| 3925 | } | |
| 3926 | ||
| 3927 | pub fn clearLayoutWip(s: LoadedStructType, ip: *InternPool, io: Io) void { | |
| 3928 | if (s.layout == .@"packed") return; | |
| 3929 | ||
| 3930 | const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex; | |
| 3931 | extra_mutex.lockUncancelable(io); | |
| 3932 | defer extra_mutex.unlock(io); | |
| 3933 | ||
| 3934 | const flags_ptr = s.flagsPtr(ip); | |
| 3935 | var flags = flags_ptr.*; | |
| 3936 | flags.layout_wip = false; | |
| 3937 | @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release); | |
| 3938 | } | |
| 3939 | ||
| 3940 | pub fn setAlignment(s: LoadedStructType, ip: *InternPool, io: Io, alignment: Alignment) void { | |
| 3941 | const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex; | |
| 3942 | extra_mutex.lockUncancelable(io); | |
| 3943 | defer extra_mutex.unlock(io); | |
| 3944 | ||
| 3945 | const flags_ptr = s.flagsPtr(ip); | |
| 3946 | var flags = flags_ptr.*; | |
| 3947 | flags.alignment = alignment; | |
| 3948 | @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release); | |
| 3949 | } | |
| 3950 | ||
| 3951 | pub fn assumePointerAlignedIfFieldTypesWip(s: LoadedStructType, ip: *InternPool, io: Io, ptr_align: Alignment) bool { | |
| 3952 | const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex; | |
| 3953 | extra_mutex.lockUncancelable(io); | |
| 3954 | defer extra_mutex.unlock(io); | |
| 3955 | ||
| 3956 | const flags_ptr = s.flagsPtr(ip); | |
| 3957 | var flags = flags_ptr.*; | |
| 3958 | defer if (flags.field_types_wip) { | |
| 3959 | flags.alignment = ptr_align; | |
| 3960 | flags.assumed_pointer_aligned = true; | |
| 3961 | @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release); | |
| 3962 | }; | |
| 3963 | return flags.field_types_wip; | |
| 3964 | } | |
| 3965 | ||
| 3966 | pub fn assumePointerAlignedIfWip(s: LoadedStructType, ip: *InternPool, io: Io, ptr_align: Alignment) bool { | |
| 3967 | const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex; | |
| 3968 | extra_mutex.lockUncancelable(io); | |
| 3969 | defer extra_mutex.unlock(io); | |
| 3970 | ||
| 3971 | const flags_ptr = s.flagsPtr(ip); | |
| 3972 | var flags = flags_ptr.*; | |
| 3973 | defer { | |
| 3974 | if (flags.alignment_wip) { | |
| 3975 | flags.alignment = ptr_align; | |
| 3976 | flags.assumed_pointer_aligned = true; | |
| 3977 | } else flags.alignment_wip = true; | |
| 3978 | @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release); | |
| 3979 | } | |
| 3980 | return flags.alignment_wip; | |
| 3981 | } | |
| 3982 | ||
| 3983 | pub fn clearAlignmentWip(s: LoadedStructType, ip: *InternPool, io: Io) void { | |
| 3984 | if (s.layout == .@"packed") return; | |
| 3985 | ||
| 3986 | const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex; | |
| 3987 | extra_mutex.lockUncancelable(io); | |
| 3988 | defer extra_mutex.unlock(io); | |
| 3989 | ||
| 3990 | const flags_ptr = s.flagsPtr(ip); | |
| 3991 | var flags = flags_ptr.*; | |
| 3992 | flags.alignment_wip = false; | |
| 3993 | @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release); | |
| 3994 | } | |
| 3995 | ||
| 3996 | pub fn setInitsWip(s: LoadedStructType, ip: *InternPool, io: Io) bool { | |
| 3997 | const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex; | |
| 3998 | extra_mutex.lockUncancelable(io); | |
| 3999 | defer extra_mutex.unlock(io); | |
| 4000 | ||
| 4001 | switch (s.layout) { | |
| 4002 | .@"packed" => { | |
| 4003 | const flags_ptr = s.packedFlagsPtr(ip); | |
| 4004 | var flags = flags_ptr.*; | |
| 4005 | defer { | |
| 4006 | flags.field_inits_wip = true; | |
| 4007 | @atomicStore(Tag.TypeStructPacked.Flags, flags_ptr, flags, .release); | |
| 4008 | } | |
| 4009 | return flags.field_inits_wip; | |
| 4010 | }, | |
| 4011 | .auto, .@"extern" => { | |
| 4012 | const flags_ptr = s.flagsPtr(ip); | |
| 4013 | var flags = flags_ptr.*; | |
| 4014 | defer { | |
| 4015 | flags.field_inits_wip = true; | |
| 4016 | @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release); | |
| 4017 | } | |
| 4018 | return flags.field_inits_wip; | |
| 4019 | }, | |
| 4020 | } | |
| 4021 | } | |
| 4022 | ||
| 4023 | pub fn clearInitsWip(s: LoadedStructType, ip: *InternPool, io: Io) void { | |
| 4024 | const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex; | |
| 4025 | extra_mutex.lockUncancelable(io); | |
| 4026 | defer extra_mutex.unlock(io); | |
| 4027 | ||
| 4028 | switch (s.layout) { | |
| 4029 | .@"packed" => { | |
| 4030 | const flags_ptr = s.packedFlagsPtr(ip); | |
| 4031 | var flags = flags_ptr.*; | |
| 4032 | flags.field_inits_wip = false; | |
| 4033 | @atomicStore(Tag.TypeStructPacked.Flags, flags_ptr, flags, .release); | |
| 4034 | }, | |
| 4035 | .auto, .@"extern" => { | |
| 4036 | const flags_ptr = s.flagsPtr(ip); | |
| 4037 | var flags = flags_ptr.*; | |
| 4038 | flags.field_inits_wip = false; | |
| 4039 | @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release); | |
| 4040 | }, | |
| 4041 | } | |
| 4042 | } | |
| 4043 | ||
| 4044 | pub fn setFullyResolved(s: LoadedStructType, ip: *InternPool, io: Io) bool { | |
| 4045 | if (s.layout == .@"packed") return true; | |
| 4046 | ||
| 4047 | const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex; | |
| 4048 | extra_mutex.lockUncancelable(io); | |
| 4049 | defer extra_mutex.unlock(io); | |
| 4050 | ||
| 4051 | const flags_ptr = s.flagsPtr(ip); | |
| 4052 | var flags = flags_ptr.*; | |
| 4053 | defer { | |
| 4054 | flags.fully_resolved = true; | |
| 4055 | @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release); | |
| 4056 | } | |
| 4057 | return flags.fully_resolved; | |
| 4058 | } | |
| 4059 | ||
| 4060 | pub fn clearFullyResolved(s: LoadedStructType, ip: *InternPool, io: Io) void { | |
| 4061 | const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex; | |
| 4062 | extra_mutex.lockUncancelable(io); | |
| 4063 | defer extra_mutex.unlock(io); | |
| 4064 | ||
| 4065 | const flags_ptr = s.flagsPtr(ip); | |
| 4066 | var flags = flags_ptr.*; | |
| 4067 | flags.fully_resolved = false; | |
| 4068 | @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release); | |
| 4069 | } | |
| 4070 | ||
| 4071 | /// The returned pointer expires with any addition to the `InternPool`. | |
| 4072 | /// Asserts the struct is not packed. | |
| 4073 | fn sizePtr(s: LoadedStructType, ip: *const InternPool) *u32 { | |
| 4074 | assert(s.layout != .@"packed"); | |
| 4075 | const extra = ip.getLocalShared(s.tid).extra.acquire(); | |
| 4076 | const size_field_index = std.meta.fieldIndex(Tag.TypeStruct, "size").?; | |
| 4077 | return @ptrCast(&extra.view().items(.@"0")[s.extra_index + size_field_index]); | |
| 4078 | } | |
| 4079 | ||
| 4080 | pub fn sizeUnordered(s: LoadedStructType, ip: *const InternPool) u32 { | |
| 4081 | return @atomicLoad(u32, s.sizePtr(ip), .unordered); | |
| 4082 | } | |
| 4083 | ||
| 4084 | /// The backing integer type of the packed struct. Whether zig chooses | |
| 4085 | /// this type or the user specifies it, it is stored here. This will be | |
| 4086 | /// set to `none` until the layout is resolved. | |
| 4087 | /// Asserts the struct is packed. | |
| 4088 | fn backingIntTypePtr(s: LoadedStructType, ip: *const InternPool) *Index { | |
| 4089 | assert(s.layout == .@"packed"); | |
| 4090 | const extra = ip.getLocalShared(s.tid).extra.acquire(); | |
| 4091 | const field_index = std.meta.fieldIndex(Tag.TypeStructPacked, "backing_int_ty").?; | |
| 4092 | return @ptrCast(&extra.view().items(.@"0")[s.extra_index + field_index]); | |
| 4093 | } | |
| 4094 | ||
| 4095 | pub fn backingIntTypeUnordered(s: LoadedStructType, ip: *const InternPool) Index { | |
| 4096 | return @atomicLoad(Index, s.backingIntTypePtr(ip), .unordered); | |
| 4097 | } | |
| 4098 | ||
| 4099 | pub fn setBackingIntType(s: LoadedStructType, ip: *InternPool, io: Io, backing_int_ty: Index) void { | |
| 4100 | const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex; | |
| 4101 | extra_mutex.lockUncancelable(io); | |
| 4102 | defer extra_mutex.unlock(io); | |
| 4103 | ||
| 4104 | @atomicStore(Index, s.backingIntTypePtr(ip), backing_int_ty, .release); | |
| 4105 | } | |
| 4106 | ||
| 4107 | /// Asserts the struct is not packed. | |
| 4108 | pub fn setZirIndex(s: LoadedStructType, ip: *InternPool, new_zir_index: TrackedInst.Index.Optional) void { | |
| 4109 | assert(s.layout != .@"packed"); | |
| 4110 | const field_index = std.meta.fieldIndex(Tag.TypeStruct, "zir_index").?; | |
| 4111 | ip.extra_.items[s.extra_index + field_index] = @intFromEnum(new_zir_index); | |
| 4112 | } | |
| 4113 | ||
| 4114 | pub fn haveFieldTypes(s: LoadedStructType, ip: *const InternPool) bool { | |
| 4115 | const types = s.field_types.get(ip); | |
| 4116 | return types.len == 0 or types[types.len - 1] != .none; | |
| 4117 | } | |
| 4118 | ||
| 4119 | pub fn haveFieldInits(s: LoadedStructType, ip: *const InternPool) bool { | |
| 4120 | return switch (s.layout) { | |
| 4121 | .@"packed" => s.packedFlagsUnordered(ip).inits_resolved, | |
| 4122 | .auto, .@"extern" => s.flagsUnordered(ip).inits_resolved, | |
| 4123 | }; | |
| 4124 | } | |
| 4125 | ||
| 4126 | pub fn setHaveFieldInits(s: LoadedStructType, ip: *InternPool, io: Io) void { | |
| 4127 | const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex; | |
| 4128 | extra_mutex.lockUncancelable(io); | |
| 4129 | defer extra_mutex.unlock(io); | |
| 4130 | ||
| 4131 | switch (s.layout) { | |
| 4132 | .@"packed" => { | |
| 4133 | const flags_ptr = s.packedFlagsPtr(ip); | |
| 4134 | var flags = flags_ptr.*; | |
| 4135 | flags.inits_resolved = true; | |
| 4136 | @atomicStore(Tag.TypeStructPacked.Flags, flags_ptr, flags, .release); | |
| 4137 | }, | |
| 4138 | .auto, .@"extern" => { | |
| 4139 | const flags_ptr = s.flagsPtr(ip); | |
| 4140 | var flags = flags_ptr.*; | |
| 4141 | flags.inits_resolved = true; | |
| 4142 | @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release); | |
| 4143 | }, | |
| 4144 | } | |
| 4145 | } | |
| 4146 | ||
| 4147 | pub fn haveLayout(s: LoadedStructType, ip: *const InternPool) bool { | |
| 4148 | return switch (s.layout) { | |
| 4149 | .@"packed" => s.backingIntTypeUnordered(ip) != .none, | |
| 4150 | .auto, .@"extern" => s.flagsUnordered(ip).layout_resolved, | |
| 4151 | }; | |
| 4152 | } | |
| 4153 | ||
| 4154 | pub fn setLayoutResolved(s: LoadedStructType, ip: *InternPool, io: Io, size: u32, alignment: Alignment) void { | |
| 4155 | const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex; | |
| 4156 | extra_mutex.lockUncancelable(io); | |
| 4157 | defer extra_mutex.unlock(io); | |
| 4158 | ||
| 4159 | @atomicStore(u32, s.sizePtr(ip), size, .unordered); | |
| 4160 | const flags_ptr = s.flagsPtr(ip); | |
| 4161 | var flags = flags_ptr.*; | |
| 4162 | flags.alignment = alignment; | |
| 4163 | flags.layout_resolved = true; | |
| 4164 | @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release); | |
| 4165 | } | |
| 4166 | ||
| 4167 | pub fn hasReorderedFields(s: LoadedStructType) bool { | |
| 4168 | return s.layout == .auto; | |
| 4169 | } | |
| 4170 | ||
| 4171 | pub const RuntimeOrderIterator = struct { | |
| 4172 | ip: *InternPool, | |
| 4173 | field_index: u32, | |
| 4174 | struct_type: InternPool.LoadedStructType, | |
| 4175 | ||
| 4176 | pub fn next(it: *@This()) ?u32 { | |
| 4177 | var i = it.field_index; | |
| 4178 | ||
| 4179 | if (i >= it.struct_type.field_types.len) | |
| 4180 | return null; | |
| 4181 | ||
| 4182 | if (it.struct_type.hasReorderedFields()) { | |
| 4183 | it.field_index += 1; | |
| 4184 | return it.struct_type.runtime_order.get(it.ip)[i].toInt(); | |
| 4185 | } | |
| 4186 | ||
| 4187 | while (it.struct_type.fieldIsComptime(it.ip, i)) { | |
| 4188 | i += 1; | |
| 4189 | if (i >= it.struct_type.field_types.len) | |
| 4190 | return null; | |
| 4191 | } | |
| 4192 | ||
| 4193 | it.field_index = i + 1; | |
| 4194 | return i; | |
| 4195 | } | |
| 4196 | }; | |
| 4197 | ||
| 4198 | /// Iterates over non-comptime fields in the order they are laid out in memory at runtime. | |
| 4199 | /// May or may not include zero-bit fields. | |
| 4200 | /// Asserts the struct is not packed. | |
| 4201 | pub fn iterateRuntimeOrder(s: LoadedStructType, ip: *InternPool) RuntimeOrderIterator { | |
| 4202 | assert(s.layout != .@"packed"); | |
| 4203 | return .{ | |
| 4204 | .ip = ip, | |
| 4205 | .field_index = 0, | |
| 4206 | .struct_type = s, | |
| 4207 | }; | |
| 4208 | } | |
| 4209 | ||
| 4210 | pub const ReverseRuntimeOrderIterator = struct { | |
| 4211 | ip: *InternPool, | |
| 4212 | last_index: u32, | |
| 4213 | struct_type: InternPool.LoadedStructType, | |
| 4214 | ||
| 4215 | pub fn next(it: *@This()) ?u32 { | |
| 4216 | if (it.last_index == 0) | |
| 4217 | return null; | |
| 4218 | ||
| 4219 | if (it.struct_type.hasReorderedFields()) { | |
| 4220 | it.last_index -= 1; | |
| 4221 | const order = it.struct_type.runtime_order.get(it.ip); | |
| 4222 | while (order[it.last_index] == .omitted) { | |
| 4223 | it.last_index -= 1; | |
| 4224 | if (it.last_index == 0) | |
| 4225 | return null; | |
| 4226 | } | |
| 4227 | return order[it.last_index].toInt(); | |
| 4228 | } | |
| 4229 | ||
| 4230 | it.last_index -= 1; | |
| 4231 | while (it.struct_type.fieldIsComptime(it.ip, it.last_index)) { | |
| 4232 | it.last_index -= 1; | |
| 4233 | if (it.last_index == 0) | |
| 4234 | return null; | |
| 4235 | } | |
| 4236 | ||
| 4237 | return it.last_index; | |
| 4238 | } | |
| 4239 | }; | |
| 4240 | ||
| 4241 | pub fn iterateRuntimeOrderReverse(s: LoadedStructType, ip: *InternPool) ReverseRuntimeOrderIterator { | |
| 4242 | assert(s.layout != .@"packed"); | |
| 4243 | return .{ | |
| 4244 | .ip = ip, | |
| 4245 | .last_index = s.field_types.len, | |
| 4246 | .struct_type = s, | |
| 4247 | }; | |
| 4248 | } | |
| 4249 | }; | |
| 3584 | // TODO: the non-fqn will be needed by the new dwarf structure | |
| 3585 | /// The name of this opaque type. | |
| 3586 | name: NullTerminatedString, | |
| 3587 | /// If this is a declared type with the `.parent` name strategy, this is the `Nav` it was named after. | |
| 3588 | /// Otherwise, this is `.none`. | |
| 3589 | name_nav: Nav.Index.Optional, | |
| 3590 | namespace: NamespaceIndex, | |
| 3591 | }; | |
| 4250 | 3592 | |
| 4251 | 3593 | pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType { |
| 4252 | 3594 | const unwrapped_index = index.unwrap(ip); |
| 4253 | 3595 | const extra_list = unwrapped_index.getExtra(ip); |
| 4254 | 3596 | const extra_items = extra_list.view().items(.@"0"); |
| 4255 | 3597 | const item = unwrapped_index.getItem(ip); |
| 4256 | switch (item.tag) { | |
| 3598 | // Exiting this `switch` means this is a `packed struct`. | |
| 3599 | const backing_mode: PackedBackingMode, const any_defaults: bool = switch (item.tag) { | |
| 3600 | .type_struct_packed_auto => .{ .auto, false }, | |
| 3601 | .type_struct_packed_explicit => .{ .explicit, false }, | |
| 3602 | .type_struct_packed_auto_defaults => .{ .auto, true }, | |
| 3603 | .type_struct_packed_explicit_defaults => .{ .explicit, true }, | |
| 4257 | 3604 | .type_struct => { |
| 4258 | const name: NullTerminatedString = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "name").?]); | |
| 4259 | const name_nav: Nav.Index.Optional = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "name_nav").?]); | |
| 4260 | const namespace: NamespaceIndex = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "namespace").?]); | |
| 4261 | const zir_index: TrackedInst.Index = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "zir_index").?]); | |
| 4262 | const fields_len = extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "fields_len").?]; | |
| 4263 | const flags: Tag.TypeStruct.Flags = @bitCast(@atomicLoad(u32, &extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "flags").?], .unordered)); | |
| 4264 | var extra_index = item.data + @as(u32, @typeInfo(Tag.TypeStruct).@"struct".fields.len); | |
| 4265 | const captures_len = if (flags.any_captures) c: { | |
| 4266 | const len = extra_list.view().items(.@"0")[extra_index]; | |
| 4267 | extra_index += 1; | |
| 4268 | break :c len; | |
| 4269 | } else 0; | |
| 4270 | const captures: CaptureValue.Slice = .{ | |
| 3605 | const extra = extraDataTrail(extra_list, Tag.TypeStruct, item.data); | |
| 3606 | var extra_index = extra.end; | |
| 3607 | const captures: CaptureValue.Slice = switch (extra.data.flags.any_captures) { | |
| 3608 | .reified => captures: { | |
| 3609 | extra_index += 2; // type_hash: PackedU64 | |
| 3610 | break :captures .empty; | |
| 3611 | }, | |
| 3612 | .false => .empty, | |
| 3613 | .true => captures: { | |
| 3614 | const len = extra_items[extra_index]; | |
| 3615 | extra_index += 1; | |
| 3616 | break :captures .{ | |
| 3617 | .tid = unwrapped_index.tid, | |
| 3618 | .start = extra_index, | |
| 3619 | .len = len, | |
| 3620 | }; | |
| 3621 | }, | |
| 3622 | }; | |
| 3623 | extra_index += captures.len; | |
| 3624 | const field_names: NullTerminatedString.Slice = .{ | |
| 4271 | 3625 | .tid = unwrapped_index.tid, |
| 4272 | 3626 | .start = extra_index, |
| 4273 | .len = captures_len, | |
| 3627 | .len = extra.data.fields_len, | |
| 4274 | 3628 | }; |
| 4275 | extra_index += captures_len; | |
| 4276 | if (flags.is_reified) { | |
| 4277 | extra_index += 2; // type_hash: PackedU64 | |
| 4278 | } | |
| 3629 | extra_index += field_names.len; | |
| 4279 | 3630 | const field_types: Index.Slice = .{ |
| 4280 | 3631 | .tid = unwrapped_index.tid, |
| 4281 | 3632 | .start = extra_index, |
| 4282 | .len = fields_len, | |
| 4283 | }; | |
| 4284 | extra_index += fields_len; | |
| 4285 | const names_map: OptionalMapIndex, const names = n: { | |
| 4286 | const names_map: OptionalMapIndex = @enumFromInt(extra_list.view().items(.@"0")[extra_index]); | |
| 4287 | extra_index += 1; | |
| 4288 | const names: NullTerminatedString.Slice = .{ | |
| 4289 | .tid = unwrapped_index.tid, | |
| 4290 | .start = extra_index, | |
| 4291 | .len = fields_len, | |
| 4292 | }; | |
| 4293 | extra_index += fields_len; | |
| 4294 | break :n .{ names_map, names }; | |
| 3633 | .len = extra.data.fields_len, | |
| 4295 | 3634 | }; |
| 4296 | const inits: Index.Slice = if (flags.any_default_inits) i: { | |
| 4297 | const inits: Index.Slice = .{ | |
| 4298 | .tid = unwrapped_index.tid, | |
| 4299 | .start = extra_index, | |
| 4300 | .len = fields_len, | |
| 4301 | }; | |
| 4302 | extra_index += fields_len; | |
| 4303 | break :i inits; | |
| 4304 | } else Index.Slice.empty; | |
| 4305 | const aligns: Alignment.Slice = if (flags.any_aligned_fields) a: { | |
| 4306 | const a: Alignment.Slice = .{ | |
| 4307 | .tid = unwrapped_index.tid, | |
| 4308 | .start = extra_index, | |
| 4309 | .len = fields_len, | |
| 4310 | }; | |
| 4311 | extra_index += std.math.divCeil(u32, fields_len, 4) catch unreachable; | |
| 4312 | break :a a; | |
| 4313 | } else Alignment.Slice.empty; | |
| 4314 | const comptime_bits: LoadedStructType.ComptimeBits = if (flags.any_comptime_fields) c: { | |
| 4315 | const len = std.math.divCeil(u32, fields_len, 32) catch unreachable; | |
| 4316 | const c: LoadedStructType.ComptimeBits = .{ | |
| 4317 | .tid = unwrapped_index.tid, | |
| 4318 | .start = extra_index, | |
| 4319 | .len = len, | |
| 4320 | }; | |
| 4321 | extra_index += len; | |
| 4322 | break :c c; | |
| 4323 | } else LoadedStructType.ComptimeBits.empty; | |
| 4324 | const runtime_order: LoadedStructType.RuntimeOrder.Slice = if (!flags.is_extern) ro: { | |
| 4325 | const ro: LoadedStructType.RuntimeOrder.Slice = .{ | |
| 4326 | .tid = unwrapped_index.tid, | |
| 4327 | .start = extra_index, | |
| 4328 | .len = fields_len, | |
| 4329 | }; | |
| 4330 | extra_index += fields_len; | |
| 4331 | break :ro ro; | |
| 4332 | } else LoadedStructType.RuntimeOrder.Slice.empty; | |
| 4333 | const offsets: LoadedStructType.Offsets = o: { | |
| 4334 | const o: LoadedStructType.Offsets = .{ | |
| 4335 | .tid = unwrapped_index.tid, | |
| 4336 | .start = extra_index, | |
| 4337 | .len = fields_len, | |
| 4338 | }; | |
| 4339 | extra_index += fields_len; | |
| 4340 | break :o o; | |
| 4341 | }; | |
| 4342 | return .{ | |
| 3635 | extra_index += field_types.len; | |
| 3636 | const field_defaults: Index.Slice = if (extra.data.flags.any_field_defaults) .{ | |
| 4343 | 3637 | .tid = unwrapped_index.tid, |
| 4344 | .extra_index = item.data, | |
| 4345 | .name = name, | |
| 4346 | .name_nav = name_nav, | |
| 4347 | .namespace = namespace, | |
| 4348 | .zir_index = zir_index, | |
| 4349 | .layout = if (flags.is_extern) .@"extern" else .auto, | |
| 4350 | .field_names = names, | |
| 4351 | .field_types = field_types, | |
| 4352 | .field_inits = inits, | |
| 4353 | .field_aligns = aligns, | |
| 4354 | .runtime_order = runtime_order, | |
| 4355 | .comptime_bits = comptime_bits, | |
| 4356 | .offsets = offsets, | |
| 4357 | .names_map = names_map, | |
| 4358 | .captures = captures, | |
| 4359 | }; | |
| 4360 | }, | |
| 4361 | .type_struct_packed, .type_struct_packed_inits => { | |
| 4362 | const name: NullTerminatedString = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "name").?]); | |
| 4363 | const name_nav: Nav.Index.Optional = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "name_nav").?]); | |
| 4364 | const zir_index: TrackedInst.Index = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "zir_index").?]); | |
| 4365 | const fields_len = extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "fields_len").?]; | |
| 4366 | const namespace: NamespaceIndex = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "namespace").?]); | |
| 4367 | const names_map: MapIndex = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "names_map").?]); | |
| 4368 | const flags: Tag.TypeStructPacked.Flags = @bitCast(@atomicLoad(u32, &extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "flags").?], .unordered)); | |
| 4369 | var extra_index = item.data + @as(u32, @typeInfo(Tag.TypeStructPacked).@"struct".fields.len); | |
| 4370 | const has_inits = item.tag == .type_struct_packed_inits; | |
| 4371 | const captures_len = if (flags.any_captures) c: { | |
| 4372 | const len = extra_list.view().items(.@"0")[extra_index]; | |
| 4373 | extra_index += 1; | |
| 4374 | break :c len; | |
| 4375 | } else 0; | |
| 4376 | const captures: CaptureValue.Slice = .{ | |
| 3638 | .start = extra_index, | |
| 3639 | .len = extra.data.fields_len, | |
| 3640 | } else .empty; | |
| 3641 | extra_index += field_defaults.len; | |
| 3642 | const field_aligns: Alignment.Slice = if (extra.data.flags.any_field_aligns) .{ | |
| 4377 | 3643 | .tid = unwrapped_index.tid, |
| 4378 | 3644 | .start = extra_index, |
| 4379 | .len = captures_len, | |
| 4380 | }; | |
| 4381 | extra_index += captures_len; | |
| 4382 | if (flags.is_reified) { | |
| 4383 | extra_index += 2; // PackedU64 | |
| 4384 | } | |
| 4385 | const field_types: Index.Slice = .{ | |
| 3645 | .len = extra.data.fields_len, | |
| 3646 | } else .empty; | |
| 3647 | extra_index += std.math.divCeil(u32, field_aligns.len, 4) catch unreachable; | |
| 3648 | const field_is_comptime_bits: LoadedStructType.ComptimeBits = if (extra.data.flags.any_comptime_fields) .{ | |
| 4386 | 3649 | .tid = unwrapped_index.tid, |
| 4387 | 3650 | .start = extra_index, |
| 4388 | .len = fields_len, | |
| 4389 | }; | |
| 4390 | extra_index += fields_len; | |
| 4391 | const field_names: NullTerminatedString.Slice = .{ | |
| 3651 | .len = std.math.divCeil(u32, extra.data.fields_len, 32) catch unreachable, | |
| 3652 | } else .empty; | |
| 3653 | extra_index += field_is_comptime_bits.len; | |
| 3654 | const field_runtime_order: LoadedStructType.RuntimeOrder.Slice = if (extra.data.flags.layout == .auto) .{ | |
| 4392 | 3655 | .tid = unwrapped_index.tid, |
| 4393 | 3656 | .start = extra_index, |
| 4394 | .len = fields_len, | |
| 3657 | .len = extra.data.fields_len, | |
| 3658 | } else .empty; | |
| 3659 | extra_index += field_runtime_order.len; | |
| 3660 | const field_offsets: LoadedStructType.Offsets = .{ | |
| 3661 | .tid = unwrapped_index.tid, | |
| 3662 | .start = extra_index, | |
| 3663 | .len = extra.data.fields_len, | |
| 4395 | 3664 | }; |
| 4396 | extra_index += fields_len; | |
| 4397 | const field_inits: Index.Slice = if (has_inits) inits: { | |
| 4398 | const i: Index.Slice = .{ | |
| 4399 | .tid = unwrapped_index.tid, | |
| 4400 | .start = extra_index, | |
| 4401 | .len = fields_len, | |
| 4402 | }; | |
| 4403 | extra_index += fields_len; | |
| 4404 | break :inits i; | |
| 4405 | } else Index.Slice.empty; | |
| 3665 | extra_index += field_offsets.len; | |
| 3666 | ||
| 4406 | 3667 | return .{ |
| 4407 | .tid = unwrapped_index.tid, | |
| 4408 | .extra_index = item.data, | |
| 4409 | .name = name, | |
| 4410 | .name_nav = name_nav, | |
| 4411 | .namespace = namespace, | |
| 4412 | .zir_index = zir_index, | |
| 4413 | .layout = .@"packed", | |
| 3668 | .zir_index = extra.data.zir_index, | |
| 3669 | .captures = captures, | |
| 3670 | .name = extra.data.name, | |
| 3671 | .name_nav = extra.data.name_nav, | |
| 3672 | .namespace = extra.data.namespace, | |
| 3673 | .layout = switch (extra.data.flags.layout) { | |
| 3674 | .auto => .auto, | |
| 3675 | .@"extern" => .@"extern", | |
| 3676 | }, | |
| 3677 | .packed_backing_mode = undefined, | |
| 3678 | .packed_backing_int_type = undefined, | |
| 3679 | .field_name_map = extra.data.field_name_map, | |
| 4414 | 3680 | .field_names = field_names, |
| 4415 | 3681 | .field_types = field_types, |
| 4416 | .field_inits = field_inits, | |
| 4417 | .field_aligns = Alignment.Slice.empty, | |
| 4418 | .runtime_order = LoadedStructType.RuntimeOrder.Slice.empty, | |
| 4419 | .comptime_bits = LoadedStructType.ComptimeBits.empty, | |
| 4420 | .offsets = LoadedStructType.Offsets.empty, | |
| 4421 | .names_map = names_map.toOptional(), | |
| 4422 | .captures = captures, | |
| 3682 | .field_defaults = field_defaults, | |
| 3683 | .field_aligns = field_aligns, | |
| 3684 | .field_is_comptime_bits = field_is_comptime_bits, | |
| 3685 | .field_runtime_order = field_runtime_order, | |
| 3686 | .field_offsets = field_offsets, | |
| 3687 | .has_no_possible_value = extra.data.flags.has_no_possible_value, | |
| 3688 | .has_one_possible_value = extra.data.flags.has_one_possible_value, | |
| 3689 | .comptime_only = extra.data.flags.comptime_only, | |
| 3690 | .size = extra.data.size, | |
| 3691 | .alignment = extra.data.flags.alignment, | |
| 4423 | 3692 | }; |
| 4424 | 3693 | }, |
| 4425 | 3694 | else => unreachable, |
| 4426 | } | |
| 4427 | } | |
| 4428 | ||
| 4429 | pub const LoadedEnumType = struct { | |
| 4430 | // TODO: the non-fqn will be needed by the new dwarf structure | |
| 4431 | /// The name of this enum type. | |
| 4432 | name: NullTerminatedString, | |
| 4433 | /// Represents the declarations inside this enum. | |
| 4434 | namespace: NamespaceIndex, | |
| 4435 | /// If this is a declared type with the `.parent` name strategy, this is the `Nav` it was named after. | |
| 4436 | /// Otherwise, this is `.none`. | |
| 4437 | name_nav: Nav.Index.Optional, | |
| 4438 | /// An integer type which is used for the numerical value of the enum. | |
| 4439 | /// This field is present regardless of whether the enum has an | |
| 4440 | /// explicitly provided tag type or auto-numbered. | |
| 4441 | tag_ty: Index, | |
| 4442 | /// Set of field names in declaration order. | |
| 4443 | names: NullTerminatedString.Slice, | |
| 4444 | /// Maps integer tag value to field index. | |
| 4445 | /// Entries are in declaration order, same as `fields`. | |
| 4446 | /// If this is empty, it means the enum tags are auto-numbered. | |
| 4447 | values: Index.Slice, | |
| 4448 | tag_mode: TagMode, | |
| 4449 | names_map: MapIndex, | |
| 4450 | /// This is guaranteed to not be `.none` if explicit values are provided. | |
| 4451 | values_map: OptionalMapIndex, | |
| 4452 | /// This is `none` only if this is a generated tag type. | |
| 4453 | zir_index: TrackedInst.Index.Optional, | |
| 4454 | captures: CaptureValue.Slice, | |
| 4455 | ||
| 4456 | pub const TagMode = enum { | |
| 4457 | /// The integer tag type was auto-numbered by zig. | |
| 4458 | auto, | |
| 4459 | /// The integer tag type was provided by the enum declaration, and the enum | |
| 4460 | /// is exhaustive. | |
| 4461 | explicit, | |
| 4462 | /// The integer tag type was provided by the enum declaration, and the enum | |
| 4463 | /// is non-exhaustive. | |
| 4464 | nonexhaustive, | |
| 4465 | 3695 | }; |
| 3696 | const extra = extraDataTrail(extra_list, Tag.TypeStructPacked, item.data); | |
| 3697 | var extra_index = extra.end; | |
| 3698 | const captures: CaptureValue.Slice = switch (extra.data.captures_len) { | |
| 3699 | .reified => captures: { | |
| 3700 | extra_index += 2; // type_hash: PackedU64 | |
| 3701 | break :captures .empty; | |
| 3702 | }, | |
| 3703 | _ => .{ | |
| 3704 | .tid = unwrapped_index.tid, | |
| 3705 | .start = extra_index, | |
| 3706 | .len = @intFromEnum(extra.data.captures_len), | |
| 3707 | }, | |
| 3708 | }; | |
| 3709 | extra_index += captures.len; | |
| 3710 | const field_names: NullTerminatedString.Slice = .{ | |
| 3711 | .tid = unwrapped_index.tid, | |
| 3712 | .start = extra_index, | |
| 3713 | .len = extra.data.fields_len, | |
| 3714 | }; | |
| 3715 | extra_index += field_names.len; | |
| 3716 | const field_types: Index.Slice = .{ | |
| 3717 | .tid = unwrapped_index.tid, | |
| 3718 | .start = extra_index, | |
| 3719 | .len = extra.data.fields_len, | |
| 3720 | }; | |
| 3721 | extra_index += field_types.len; | |
| 3722 | const field_defaults: Index.Slice = if (any_defaults) .{ | |
| 3723 | .tid = unwrapped_index.tid, | |
| 3724 | .start = extra_index, | |
| 3725 | .len = extra.data.fields_len, | |
| 3726 | } else .empty; | |
| 3727 | extra_index += field_defaults.len; | |
| 3728 | return .{ | |
| 3729 | .zir_index = extra.data.zir_index, | |
| 3730 | .captures = captures, | |
| 3731 | .name = extra.data.name, | |
| 3732 | .name_nav = extra.data.name_nav, | |
| 3733 | .namespace = extra.data.namespace, | |
| 3734 | .layout = .@"packed", | |
| 3735 | .packed_backing_mode = backing_mode, | |
| 3736 | .packed_backing_int_type = extra.data.backing_int_type, | |
| 3737 | .field_name_map = extra.data.field_name_map, | |
| 3738 | .field_names = field_names, | |
| 3739 | .field_types = field_types, | |
| 3740 | .field_defaults = field_defaults, | |
| 3741 | .field_aligns = .empty, | |
| 3742 | .field_is_comptime_bits = .empty, | |
| 3743 | .field_runtime_order = .empty, | |
| 3744 | .field_offsets = .empty, | |
| 3745 | .has_no_possible_value = undefined, | |
| 3746 | .has_one_possible_value = undefined, | |
| 3747 | .comptime_only = undefined, | |
| 3748 | .size = undefined, | |
| 3749 | .alignment = undefined, | |
| 3750 | }; | |
| 3751 | } | |
| 4466 | 3752 | |
| 4467 | /// Look up field index based on field name. | |
| 4468 | pub fn nameIndex(self: LoadedEnumType, ip: *const InternPool, name: NullTerminatedString) ?u32 { | |
| 4469 | const map = self.names_map.get(ip); | |
| 4470 | const adapter: NullTerminatedString.Adapter = .{ .strings = self.names.get(ip) }; | |
| 4471 | const field_index = map.getIndexAdapted(name, adapter) orelse return null; | |
| 4472 | return @intCast(field_index); | |
| 4473 | } | |
| 4474 | ||
| 4475 | /// Look up field index based on tag value. | |
| 4476 | /// Asserts that `values_map` is not `none`. | |
| 4477 | /// This function returns `null` when `tag_val` does not have the | |
| 4478 | /// integer tag type of the enum. | |
| 4479 | pub fn tagValueIndex(self: LoadedEnumType, ip: *const InternPool, tag_val: Index) ?u32 { | |
| 4480 | assert(tag_val != .none); | |
| 4481 | // TODO: we should probably decide a single interface for this function, but currently | |
| 4482 | // it's being called with both tag values and underlying ints. Fix this! | |
| 4483 | const int_tag_val = switch (ip.indexToKey(tag_val)) { | |
| 4484 | .enum_tag => |enum_tag| enum_tag.int, | |
| 4485 | .int => tag_val, | |
| 4486 | else => unreachable, | |
| 4487 | }; | |
| 4488 | if (self.values_map.unwrap()) |values_map| { | |
| 4489 | const map = values_map.get(ip); | |
| 4490 | const adapter: Index.Adapter = .{ .indexes = self.values.get(ip) }; | |
| 4491 | const field_index = map.getIndexAdapted(int_tag_val, adapter) orelse return null; | |
| 4492 | return @intCast(field_index); | |
| 4493 | } | |
| 4494 | // Auto-numbered enum. Convert `int_tag_val` to field index. | |
| 4495 | const field_index = switch (ip.indexToKey(int_tag_val).int.storage) { | |
| 4496 | inline .u64, .i64 => |x| std.math.cast(u32, x) orelse return null, | |
| 4497 | .big_int => |x| x.toInt(u32) catch return null, | |
| 4498 | .lazy_align, .lazy_size => unreachable, | |
| 4499 | }; | |
| 4500 | return if (field_index < self.names.len) field_index else null; | |
| 4501 | } | |
| 4502 | }; | |
| 4503 | ||
| 4504 | pub fn loadEnumType(ip: *const InternPool, index: Index) LoadedEnumType { | |
| 3753 | pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType { | |
| 4505 | 3754 | const unwrapped_index = index.unwrap(ip); |
| 4506 | 3755 | const extra_list = unwrapped_index.getExtra(ip); |
| 3756 | const extra_items = extra_list.view().items(.@"0"); | |
| 4507 | 3757 | const item = unwrapped_index.getItem(ip); |
| 4508 | const tag_mode: LoadedEnumType.TagMode = switch (item.tag) { | |
| 4509 | .type_enum_auto => { | |
| 4510 | const extra = extraDataTrail(extra_list, EnumAuto, item.data); | |
| 4511 | var extra_index: u32 = @intCast(extra.end); | |
| 4512 | if (extra.data.zir_index == .none) { | |
| 4513 | extra_index += 1; // owner_union | |
| 4514 | } | |
| 4515 | const captures_len = if (extra.data.captures_len == std.math.maxInt(u32)) c: { | |
| 4516 | extra_index += 2; // type_hash: PackedU64 | |
| 4517 | break :c 0; | |
| 4518 | } else extra.data.captures_len; | |
| 3758 | // Exiting this `switch` means this is a `packed union`. | |
| 3759 | const backing_mode: PackedBackingMode = switch (item.tag) { | |
| 3760 | .type_union_packed_auto => .auto, | |
| 3761 | .type_union_packed_explicit => .explicit, | |
| 3762 | .type_union => { | |
| 3763 | const extra = extraDataTrail(extra_list, Tag.TypeUnion, item.data); | |
| 3764 | var extra_index = extra.end; | |
| 3765 | const captures: CaptureValue.Slice = switch (extra.data.flags.any_captures) { | |
| 3766 | .reified => captures: { | |
| 3767 | extra_index += 2; // type_hash: PackedU64 | |
| 3768 | break :captures .empty; | |
| 3769 | }, | |
| 3770 | .false => .empty, | |
| 3771 | .true => captures: { | |
| 3772 | const len = extra_items[extra_index]; | |
| 3773 | extra_index += 1; | |
| 3774 | break :captures .{ | |
| 3775 | .tid = unwrapped_index.tid, | |
| 3776 | .start = extra_index, | |
| 3777 | .len = len, | |
| 3778 | }; | |
| 3779 | }, | |
| 3780 | }; | |
| 3781 | extra_index += captures.len; | |
| 3782 | const field_types: Index.Slice = .{ | |
| 3783 | .tid = unwrapped_index.tid, | |
| 3784 | .start = extra_index, | |
| 3785 | .len = extra.data.fields_len, | |
| 3786 | }; | |
| 3787 | extra_index += field_types.len; | |
| 3788 | const field_aligns: Alignment.Slice = if (extra.data.flags.any_field_aligns) .{ | |
| 3789 | .tid = unwrapped_index.tid, | |
| 3790 | .start = extra_index, | |
| 3791 | .len = extra.data.fields_len, | |
| 3792 | } else .empty; | |
| 3793 | extra_index += std.math.divCeil(u32, field_aligns.len, 4) catch unreachable; | |
| 3794 | ||
| 4519 | 3795 | return .{ |
| 3796 | .zir_index = extra.data.zir_index, | |
| 3797 | .captures = captures, | |
| 4520 | 3798 | .name = extra.data.name, |
| 4521 | 3799 | .name_nav = extra.data.name_nav, |
| 4522 | 3800 | .namespace = extra.data.namespace, |
| 4523 | .tag_ty = extra.data.int_tag_type, | |
| 4524 | .names = .{ | |
| 4525 | .tid = unwrapped_index.tid, | |
| 4526 | .start = extra_index + captures_len, | |
| 4527 | .len = extra.data.fields_len, | |
| 4528 | }, | |
| 4529 | .values = Index.Slice.empty, | |
| 4530 | .tag_mode = .auto, | |
| 4531 | .names_map = extra.data.names_map, | |
| 4532 | .values_map = .none, | |
| 4533 | .zir_index = extra.data.zir_index, | |
| 4534 | .captures = .{ | |
| 4535 | .tid = unwrapped_index.tid, | |
| 4536 | .start = extra_index, | |
| 4537 | .len = captures_len, | |
| 3801 | .layout = switch (extra.data.flags.layout) { | |
| 3802 | .auto => .auto, | |
| 3803 | .@"extern" => .@"extern", | |
| 4538 | 3804 | }, |
| 3805 | .runtime_tag = extra.data.flags.runtime_tag, | |
| 3806 | .enum_tag_type = extra.data.enum_tag_type, | |
| 3807 | .packed_backing_mode = undefined, | |
| 3808 | .packed_backing_int_type = undefined, | |
| 3809 | .field_types = field_types, | |
| 3810 | .field_aligns = field_aligns, | |
| 3811 | .has_no_possible_value = extra.data.flags.has_no_possible_value, | |
| 3812 | .has_one_possible_value = extra.data.flags.has_one_possible_value, | |
| 3813 | .comptime_only = extra.data.flags.comptime_only, | |
| 3814 | .size = extra.data.size, | |
| 3815 | .padding = extra.data.padding, | |
| 3816 | .alignment = extra.data.flags.alignment, | |
| 4539 | 3817 | }; |
| 4540 | 3818 | }, |
| 4541 | .type_enum_explicit => .explicit, | |
| 4542 | .type_enum_nonexhaustive => .nonexhaustive, | |
| 4543 | 3819 | else => unreachable, |
| 4544 | 3820 | }; |
| 4545 | const extra = extraDataTrail(extra_list, EnumExplicit, item.data); | |
| 4546 | var extra_index: u32 = @intCast(extra.end); | |
| 4547 | if (extra.data.zir_index == .none) { | |
| 4548 | extra_index += 1; // owner_union | |
| 4549 | } | |
| 4550 | const captures_len = if (extra.data.captures_len == std.math.maxInt(u32)) c: { | |
| 4551 | extra_index += 2; // type_hash: PackedU64 | |
| 4552 | break :c 0; | |
| 4553 | } else extra.data.captures_len; | |
| 4554 | return .{ | |
| 4555 | .name = extra.data.name, | |
| 4556 | .name_nav = extra.data.name_nav, | |
| 4557 | .namespace = extra.data.namespace, | |
| 4558 | .tag_ty = extra.data.int_tag_type, | |
| 4559 | .names = .{ | |
| 4560 | .tid = unwrapped_index.tid, | |
| 4561 | .start = extra_index + captures_len, | |
| 4562 | .len = extra.data.fields_len, | |
| 4563 | }, | |
| 4564 | .values = .{ | |
| 4565 | .tid = unwrapped_index.tid, | |
| 4566 | .start = extra_index + captures_len + extra.data.fields_len, | |
| 4567 | .len = if (extra.data.values_map != .none) extra.data.fields_len else 0, | |
| 3821 | const extra = extraDataTrail(extra_list, Tag.TypeUnionPacked, item.data); | |
| 3822 | var extra_index = extra.end; | |
| 3823 | const captures: CaptureValue.Slice = switch (extra.data.captures_len) { | |
| 3824 | .reified => captures: { | |
| 3825 | extra_index += 2; // type_hash: PackedU64 | |
| 3826 | break :captures .empty; | |
| 4568 | 3827 | }, |
| 4569 | .tag_mode = tag_mode, | |
| 4570 | .names_map = extra.data.names_map, | |
| 4571 | .values_map = extra.data.values_map, | |
| 4572 | .zir_index = extra.data.zir_index, | |
| 4573 | .captures = .{ | |
| 3828 | _ => .{ | |
| 4574 | 3829 | .tid = unwrapped_index.tid, |
| 4575 | 3830 | .start = extra_index, |
| 4576 | .len = captures_len, | |
| 3831 | .len = @intFromEnum(extra.data.captures_len), | |
| 4577 | 3832 | }, |
| 4578 | 3833 | }; |
| 4579 | } | |
| 4580 | ||
| 4581 | /// Note that this type doubles as the payload for `Tag.type_opaque`. | |
| 4582 | pub const LoadedOpaqueType = struct { | |
| 4583 | /// Contains the declarations inside this opaque. | |
| 4584 | namespace: NamespaceIndex, | |
| 4585 | // TODO: the non-fqn will be needed by the new dwarf structure | |
| 4586 | /// The name of this opaque type. | |
| 4587 | name: NullTerminatedString, | |
| 4588 | /// If this is a declared type with the `.parent` name strategy, this is the `Nav` it was named after. | |
| 4589 | /// Otherwise, this is `.none`. | |
| 4590 | name_nav: Nav.Index.Optional, | |
| 4591 | /// Index of the `opaque_decl` or `reify` instruction. | |
| 4592 | zir_index: TrackedInst.Index, | |
| 4593 | captures: CaptureValue.Slice, | |
| 4594 | }; | |
| 3834 | extra_index += captures.len; | |
| 3835 | const field_types: Index.Slice = .{ | |
| 3836 | .tid = unwrapped_index.tid, | |
| 3837 | .start = extra_index, | |
| 3838 | .len = extra.data.fields_len, | |
| 3839 | }; | |
| 3840 | extra_index += field_types.len; | |
| 3841 | return .{ | |
| 3842 | .zir_index = extra.data.zir_index, | |
| 3843 | .captures = captures, | |
| 3844 | .name = extra.data.name, | |
| 3845 | .name_nav = extra.data.name_nav, | |
| 3846 | .namespace = extra.data.namespace, | |
| 3847 | .layout = .@"packed", | |
| 3848 | .runtime_tag = .none, | |
| 3849 | .enum_tag_type = extra.data.enum_tag_type, | |
| 3850 | .packed_backing_mode = backing_mode, | |
| 3851 | .packed_backing_int_type = extra.data.backing_int_type, | |
| 3852 | .field_types = field_types, | |
| 3853 | .field_aligns = .empty, | |
| 3854 | .has_no_possible_value = undefined, | |
| 3855 | .has_one_possible_value = undefined, | |
| 3856 | .comptime_only = undefined, | |
| 3857 | .size = undefined, | |
| 3858 | .padding = undefined, | |
| 3859 | .alignment = undefined, | |
| 3860 | }; | |
| 3861 | } | |
| 4595 | 3862 | |
| 4596 | pub fn loadOpaqueType(ip: *const InternPool, index: Index) LoadedOpaqueType { | |
| 3863 | pub fn loadEnumType(ip: *const InternPool, index: Index) LoadedEnumType { | |
| 4597 | 3864 | const unwrapped_index = index.unwrap(ip); |
| 3865 | const extra_list = unwrapped_index.getExtra(ip); | |
| 3866 | const extra_items = extra_list.view().items(.@"0"); | |
| 4598 | 3867 | const item = unwrapped_index.getItem(ip); |
| 4599 | assert(item.tag == .type_opaque); | |
| 4600 | const extra = extraDataTrail(unwrapped_index.getExtra(ip), Tag.TypeOpaque, item.data); | |
| 4601 | const captures_len = if (extra.data.captures_len == std.math.maxInt(u32)) | |
| 4602 | 0 | |
| 4603 | else | |
| 4604 | extra.data.captures_len; | |
| 3868 | const explicit_int_tag: bool, const nonexhaustive: bool = switch (item.tag) { | |
| 3869 | .type_enum_auto => .{ false, false }, | |
| 3870 | .type_enum_explicit => .{ true, false }, | |
| 3871 | .type_enum_nonexhaustive => .{ true, true }, | |
| 3872 | else => unreachable, | |
| 3873 | }; | |
| 3874 | const extra = extraDataTrail(extra_list, Tag.TypeEnum, item.data); | |
| 3875 | var extra_index: u32 = @intCast(extra.end); | |
| 3876 | const zir_index: TrackedInst.Index.Optional, const captures: CaptureValue.Slice, const owner_union: Index = switch (extra.data.captures_len) { | |
| 3877 | .reified => info: { | |
| 3878 | const zir_index: TrackedInst.Index = @enumFromInt(extra_items[extra_index]); | |
| 3879 | extra_index += 1; | |
| 3880 | extra_index += 2; // type_hash: PackedU64 | |
| 3881 | break :info .{ zir_index.toOptional(), .empty, .none }; | |
| 3882 | }, | |
| 3883 | .generated_union_tag => info: { | |
| 3884 | const owner_union: Index = @enumFromInt(extra_items[extra_index]); | |
| 3885 | extra_index += 1; | |
| 3886 | break :info .{ .none, .empty, owner_union }; | |
| 3887 | }, | |
| 3888 | _ => info: { | |
| 3889 | const zir_index: TrackedInst.Index = @enumFromInt(extra_items[extra_index]); | |
| 3890 | extra_index += 1; | |
| 3891 | const captures: CaptureValue.Slice = .{ | |
| 3892 | .tid = unwrapped_index.tid, | |
| 3893 | .start = extra_index, | |
| 3894 | .len = @intFromEnum(extra.data.captures_len), | |
| 3895 | }; | |
| 3896 | extra_index += captures.len; | |
| 3897 | break :info .{ zir_index.toOptional(), captures, .none }; | |
| 3898 | }, | |
| 3899 | }; | |
| 3900 | const field_value_map: OptionalMapIndex = if (explicit_int_tag) m: { | |
| 3901 | const map: MapIndex = @enumFromInt(extra_items[extra_index]); | |
| 3902 | extra_index += 1; | |
| 3903 | break :m map.toOptional(); | |
| 3904 | } else .none; | |
| 3905 | const field_names: NullTerminatedString.Slice = .{ | |
| 3906 | .tid = unwrapped_index.tid, | |
| 3907 | .start = extra_index, | |
| 3908 | .len = extra.data.fields_len, | |
| 3909 | }; | |
| 3910 | extra_index += field_names.len; | |
| 3911 | const field_values: Index.Slice = if (explicit_int_tag) .{ | |
| 3912 | .tid = unwrapped_index.tid, | |
| 3913 | .start = extra_index, | |
| 3914 | .len = extra.data.fields_len, | |
| 3915 | } else .empty; | |
| 3916 | extra_index += field_values.len; | |
| 4605 | 3917 | return .{ |
| 3918 | .zir_index = zir_index, | |
| 3919 | .captures = captures, | |
| 3920 | .owner_union = owner_union, | |
| 4606 | 3921 | .name = extra.data.name, |
| 4607 | 3922 | .name_nav = extra.data.name_nav, |
| 4608 | 3923 | .namespace = extra.data.namespace, |
| 3924 | .int_tag_type = extra.data.int_tag_type, | |
| 3925 | .int_tag_is_explicit = explicit_int_tag, | |
| 3926 | .nonexhaustive = nonexhaustive, | |
| 3927 | .field_name_map = extra.data.field_name_map, | |
| 3928 | .field_value_map = field_value_map, | |
| 3929 | .field_names = field_names, | |
| 3930 | .field_values = field_values, | |
| 3931 | }; | |
| 3932 | } | |
| 3933 | ||
| 3934 | pub fn loadOpaqueType(ip: *const InternPool, index: Index) LoadedOpaqueType { | |
| 3935 | const unwrapped_index = index.unwrap(ip); | |
| 3936 | const item = unwrapped_index.getItem(ip); | |
| 3937 | assert(item.tag == .type_opaque); | |
| 3938 | const extra = extraDataTrail(unwrapped_index.getExtra(ip), Tag.TypeOpaque, item.data); | |
| 3939 | return .{ | |
| 4609 | 3940 | .zir_index = extra.data.zir_index, |
| 4610 | 3941 | .captures = .{ |
| 4611 | 3942 | .tid = unwrapped_index.tid, |
| 4612 | 3943 | .start = extra.end, |
| 4613 | .len = captures_len, | |
| 3944 | .len = extra.data.captures_len, | |
| 4614 | 3945 | }, |
| 3946 | .name = extra.data.name, | |
| 3947 | .name_nav = extra.data.name_nav, | |
| 3948 | .namespace = extra.data.namespace, | |
| 4615 | 3949 | }; |
| 4616 | 3950 | } |
| 4617 | 3951 | |
| ... | ... | @@ -4819,7 +4153,7 @@ pub const Index = enum(u32) { |
| 4819 | 4153 | }; |
| 4820 | 4154 | |
| 4821 | 4155 | /// Used for a map of `Index` values to the index within a list of `Index` values. |
| 4822 | const Adapter = struct { | |
| 4156 | pub const Adapter = struct { | |
| 4823 | 4157 | indexes: []const Index, |
| 4824 | 4158 | |
| 4825 | 4159 | pub fn eql(ctx: @This(), a: Index, b_void: void, b_map_index: usize) bool { |
| ... | ... | @@ -4891,26 +4225,6 @@ pub const Index = enum(u32) { |
| 4891 | 4225 | /// Tag to encoding mapping to facilitate fancy debug printing for this type. |
| 4892 | 4226 | fn dbHelper(self: *Index, tag_to_encoding_map: *struct { |
| 4893 | 4227 | const DataIsIndex = struct { data: Index }; |
| 4894 | const DataIsExtraIndexOfEnumExplicit = struct { | |
| 4895 | const @"data.fields_len" = opaque {}; | |
| 4896 | data: *EnumExplicit, | |
| 4897 | @"trailing.names.len": *@"data.fields_len", | |
| 4898 | @"trailing.values.len": *@"data.fields_len", | |
| 4899 | trailing: struct { | |
| 4900 | names: []NullTerminatedString, | |
| 4901 | values: []Index, | |
| 4902 | }, | |
| 4903 | }; | |
| 4904 | const DataIsExtraIndexOfTypeTuple = struct { | |
| 4905 | const @"data.fields_len" = opaque {}; | |
| 4906 | data: *TypeTuple, | |
| 4907 | @"trailing.types.len": *@"data.fields_len", | |
| 4908 | @"trailing.values.len": *@"data.fields_len", | |
| 4909 | trailing: struct { | |
| 4910 | types: []Index, | |
| 4911 | values: []Index, | |
| 4912 | }, | |
| 4913 | }; | |
| 4914 | 4228 | |
| 4915 | 4229 | removed: void, |
| 4916 | 4230 | type_int_signed: struct { data: u32 }, |
| ... | ... | @@ -4931,21 +4245,7 @@ pub const Index = enum(u32) { |
| 4931 | 4245 | trailing: struct { names: []NullTerminatedString }, |
| 4932 | 4246 | }, |
| 4933 | 4247 | type_inferred_error_set: DataIsIndex, |
| 4934 | type_enum_auto: struct { | |
| 4935 | const @"data.fields_len" = opaque {}; | |
| 4936 | data: *EnumAuto, | |
| 4937 | @"trailing.names.len": *@"data.fields_len", | |
| 4938 | trailing: struct { names: []NullTerminatedString }, | |
| 4939 | }, | |
| 4940 | type_enum_explicit: DataIsExtraIndexOfEnumExplicit, | |
| 4941 | type_enum_nonexhaustive: DataIsExtraIndexOfEnumExplicit, | |
| 4942 | 4248 | simple_type: void, |
| 4943 | type_opaque: struct { data: *Tag.TypeOpaque }, | |
| 4944 | type_struct: struct { data: *Tag.TypeStruct }, | |
| 4945 | type_struct_packed: struct { data: *Tag.TypeStructPacked }, | |
| 4946 | type_struct_packed_inits: struct { data: *Tag.TypeStructPacked }, | |
| 4947 | type_tuple: DataIsExtraIndexOfTypeTuple, | |
| 4948 | type_union: struct { data: *Tag.TypeUnion }, | |
| 4949 | 4249 | type_function: struct { |
| 4950 | 4250 | const @"data.flags.has_comptime_bits" = opaque {}; |
| 4951 | 4251 | const @"data.flags.has_noalias_bits" = opaque {}; |
| ... | ... | @@ -4956,6 +4256,29 @@ pub const Index = enum(u32) { |
| 4956 | 4256 | @"trailing.param_types.len": *@"data.params_len", |
| 4957 | 4257 | trailing: struct { comptime_bits: []u32, noalias_bits: []u32, param_types: []Index }, |
| 4958 | 4258 | }, |
| 4259 | type_tuple: struct { | |
| 4260 | const @"data.fields_len" = opaque {}; | |
| 4261 | data: *TypeTuple, | |
| 4262 | @"trailing.types.len": *@"data.fields_len", | |
| 4263 | @"trailing.values.len": *@"data.fields_len", | |
| 4264 | trailing: struct { | |
| 4265 | types: []Index, | |
| 4266 | values: []Index, | |
| 4267 | }, | |
| 4268 | }, | |
| 4269 | ||
| 4270 | type_struct: struct { data: *Tag.TypeStruct }, | |
| 4271 | type_struct_packed_auto: struct { data: *Tag.TypeStructPacked }, | |
| 4272 | type_struct_packed_explicit: struct { data: *Tag.TypeStructPacked }, | |
| 4273 | type_struct_packed_auto_defaults: struct { data: *Tag.TypeStructPacked }, | |
| 4274 | type_struct_packed_explicit_defaults: struct { data: *Tag.TypeStructPacked }, | |
| 4275 | type_union: struct { data: *Tag.TypeUnion }, | |
| 4276 | type_union_packed_auto: struct { data: *Tag.TypeUnionPacked }, | |
| 4277 | type_union_packed_explicit: struct { data: *Tag.TypeUnionPacked }, | |
| 4278 | type_enum_auto: struct { data: *Tag.TypeEnum }, | |
| 4279 | type_enum_explicit: struct { data: *Tag.TypeEnum }, | |
| 4280 | type_enum_nonexhaustive: struct { data: *Tag.TypeEnum }, | |
| 4281 | type_opaque: struct { data: *Tag.TypeOpaque }, | |
| 4959 | 4282 | |
| 4960 | 4283 | undef: DataIsIndex, |
| 4961 | 4284 | simple_value: void, |
| ... | ... | @@ -4982,8 +4305,6 @@ pub const Index = enum(u32) { |
| 4982 | 4305 | int_small: struct { data: *IntSmall }, |
| 4983 | 4306 | int_positive: struct { data: u32 }, |
| 4984 | 4307 | int_negative: struct { data: u32 }, |
| 4985 | int_lazy_align: struct { data: *IntLazy }, | |
| 4986 | int_lazy_size: struct { data: *IntLazy }, | |
| 4987 | 4308 | error_set_error: struct { data: *Key.Error }, |
| 4988 | 4309 | error_union_error: struct { data: *Key.Error }, |
| 4989 | 4310 | error_union_payload: struct { data: *Tag.TypeValue }, |
| ... | ... | @@ -5485,6 +4806,8 @@ pub const Tag = enum(u8) { |
| 5485 | 4806 | /// assert not this tag. `data` is unused. |
| 5486 | 4807 | removed, |
| 5487 | 4808 | |
| 4809 | /// A type that can be represented with only an enum tag. | |
| 4810 | simple_type, | |
| 5488 | 4811 | /// An integer type. |
| 5489 | 4812 | /// data is number of bits |
| 5490 | 4813 | type_int_signed, |
| ... | ... | @@ -5524,41 +4847,68 @@ pub const Tag = enum(u8) { |
| 5524 | 4847 | /// The inferred error set type of a function. |
| 5525 | 4848 | /// data is `Index` of a `func_decl` or `func_instance`. |
| 5526 | 4849 | type_inferred_error_set, |
| 5527 | /// An enum type with auto-numbered tag values. | |
| 5528 | /// The enum is exhaustive. | |
| 5529 | /// data is payload index to `EnumAuto`. | |
| 5530 | type_enum_auto, | |
| 5531 | /// An enum type with an explicitly provided integer tag type. | |
| 5532 | /// The enum is exhaustive. | |
| 5533 | /// data is payload index to `EnumExplicit`. | |
| 5534 | type_enum_explicit, | |
| 5535 | /// An enum type with an explicitly provided integer tag type. | |
| 5536 | /// The enum is non-exhaustive. | |
| 5537 | /// data is payload index to `EnumExplicit`. | |
| 5538 | type_enum_nonexhaustive, | |
| 5539 | /// A type that can be represented with only an enum tag. | |
| 5540 | simple_type, | |
| 5541 | /// An opaque type. | |
| 5542 | /// data is index of Tag.TypeOpaque in extra. | |
| 5543 | type_opaque, | |
| 4850 | /// A function body type. | |
| 4851 | /// `data` is extra index to `TypeFunction`. | |
| 4852 | type_function, | |
| 4853 | /// A `TupleType`. | |
| 4854 | /// data is extra index of `TypeTuple`. | |
| 4855 | type_tuple, | |
| 4856 | ||
| 5544 | 4857 | /// A non-packed struct type. |
| 5545 | /// data is 0 or extra index of `TypeStruct`. | |
| 4858 | /// data is extra index of `TypeStruct`. | |
| 5546 | 4859 | type_struct, |
| 5547 | /// A packed struct, no fields have any init values. | |
| 4860 | /// `packed struct { ... }` with no default field values. | |
| 5548 | 4861 | /// data is extra index of `TypeStructPacked`. |
| 5549 | type_struct_packed, | |
| 5550 | /// A packed struct, one or more fields have init values. | |
| 4862 | type_struct_packed_auto, | |
| 4863 | /// `packed struct(T) { ... }` with no default field values. | |
| 5551 | 4864 | /// data is extra index of `TypeStructPacked`. |
| 5552 | type_struct_packed_inits, | |
| 5553 | /// A `TupleType`. | |
| 5554 | /// data is extra index of `TypeTuple`. | |
| 5555 | type_tuple, | |
| 5556 | /// A union type. | |
| 5557 | /// `data` is extra index of `TypeUnion`. | |
| 4865 | type_struct_packed_explicit, | |
| 4866 | /// `packed struct { ... }` with one or more default field values. | |
| 4867 | /// data is extra index of `TypeStructPacked`. | |
| 4868 | type_struct_packed_auto_defaults, | |
| 4869 | /// `packed struct(T) { ... }` with one or more default field values. | |
| 4870 | /// data is extra index of `TypeStructPacked`. | |
| 4871 | type_struct_packed_explicit_defaults, | |
| 4872 | ||
| 4873 | /// A non-packed union type. | |
| 4874 | /// data is extra index of `TypeUnion`. | |
| 5558 | 4875 | type_union, |
| 5559 | /// A function body type. | |
| 5560 | /// `data` is extra index to `TypeFunction`. | |
| 5561 | type_function, | |
| 4876 | /// `packed union { ... }`. | |
| 4877 | /// data is extra index of `TypeUnionPacked`. | |
| 4878 | type_union_packed_auto, | |
| 4879 | /// `packed union(T) { ... }`. | |
| 4880 | /// data is extra index of `TypeUnionPacked`. | |
| 4881 | type_union_packed_explicit, | |
| 4882 | ||
| 4883 | /// An exhaustive enum type *without* an explicit integer tag type. The tag type is inferred. | |
| 4884 | /// | |
| 4885 | /// Because the tag type is inferred, there are no explicit field values. | |
| 4886 | /// | |
| 4887 | /// May be the generated tag type for a `union(enum)`. | |
| 4888 | /// | |
| 4889 | /// data is extra index of `TypeEnum`. | |
| 4890 | type_enum_auto, | |
| 4891 | /// An exhaustive enum type *with* an explicit integer tag type. | |
| 4892 | /// | |
| 4893 | /// May have explicit field values. | |
| 4894 | /// | |
| 4895 | /// May be the generated tag type for a `union(enum(T))`. | |
| 4896 | /// | |
| 4897 | /// data is extra index of `TypeEnum`. | |
| 4898 | type_enum_explicit, | |
| 4899 | /// An non-exhaustive enum type (with an explicit integer tag type, since it is required for | |
| 4900 | /// non-exhaustive enums). | |
| 4901 | /// | |
| 4902 | /// May have explicit field values. | |
| 4903 | /// | |
| 4904 | /// This is *not* a union's generated tag type, because such types are always exhaustive. | |
| 4905 | /// | |
| 4906 | /// data is extra index of `TypeEnum`. | |
| 4907 | type_enum_nonexhaustive, | |
| 4908 | ||
| 4909 | /// An opaque type. | |
| 4910 | /// data is extra index of `TypeOpaque`. | |
| 4911 | type_opaque, | |
| 5562 | 4912 | |
| 5563 | 4913 | /// Typed `undefined`. |
| 5564 | 4914 | /// `data` is `Index` of the type. |
| ... | ... | @@ -5644,12 +4994,6 @@ pub const Tag = enum(u8) { |
| 5644 | 4994 | /// A negative integer value. |
| 5645 | 4995 | /// data is a limbs index to `Int`. |
| 5646 | 4996 | int_negative, |
| 5647 | /// The ABI alignment of a lazy type. | |
| 5648 | /// data is extra index of `IntLazy`. | |
| 5649 | int_lazy_align, | |
| 5650 | /// The ABI size of a lazy type. | |
| 5651 | /// data is extra index of `IntLazy`. | |
| 5652 | int_lazy_size, | |
| 5653 | 4997 | /// An error value. |
| 5654 | 4998 | /// data is extra index of `Key.Error`. |
| 5655 | 4999 | error_set_error, |
| ... | ... | @@ -5747,24 +5091,77 @@ pub const Tag = enum(u8) { |
| 5747 | 5091 | const Union = Key.Union; |
| 5748 | 5092 | const TypePointer = Key.PtrType; |
| 5749 | 5093 | |
| 5750 | const enum_explicit_encoding = .{ | |
| 5094 | const struct_packed_encoding = .{ | |
| 5095 | .summary = .@"{.payload.name%summary#\"}", | |
| 5096 | .payload = TypeStructPacked, | |
| 5097 | .trailing = struct { | |
| 5098 | type_hash: ?u64, | |
| 5099 | captures: ?[]CaptureValue, | |
| 5100 | field_names: []NullTerminatedString, | |
| 5101 | field_types: []Index, | |
| 5102 | }, | |
| 5103 | .config = .{ | |
| 5104 | .@"trailing.type_hash.?" = .@"payload.captures_len == .reified", | |
| 5105 | .@"trailing.captures.?" = .@"payload.captures_len != .reified", | |
| 5106 | .@"trailing.captures.?.len" = .@"@intFromEnum(payload.captures_len)", | |
| 5107 | .@"trailing.field_names.len" = .@"payload.fields_len", | |
| 5108 | .@"trailing.field_types.len" = .@"payload.fields_len", | |
| 5109 | }, | |
| 5110 | }; | |
| 5111 | const struct_packed_defaults_encoding = .{ | |
| 5112 | .summary = .@"{.payload.name%summary#\"}", | |
| 5113 | .payload = TypeStructPacked, | |
| 5114 | .trailing = struct { | |
| 5115 | type_hash: ?u64, | |
| 5116 | captures: ?[]CaptureValue, | |
| 5117 | field_names: []NullTerminatedString, | |
| 5118 | field_types: []Index, | |
| 5119 | field_defaults: []Index, | |
| 5120 | }, | |
| 5121 | .config = .{ | |
| 5122 | .@"trailing.type_hash.?" = .@"payload.captures_len == .reified", | |
| 5123 | .@"trailing.captures.?" = .@"payload.captures_len != .reified", | |
| 5124 | .@"trailing.captures.?.len" = .@"@intFromEnum(payload.captures_len)", | |
| 5125 | .@"trailing.field_names.len" = .@"payload.fields_len", | |
| 5126 | .@"trailing.field_types.len" = .@"payload.fields_len", | |
| 5127 | .@"trailing.field_defaults.len" = .@"payload.fields_len", | |
| 5128 | }, | |
| 5129 | }; | |
| 5130 | const union_packed_encoding = .{ | |
| 5751 | 5131 | .summary = .@"{.payload.name%summary#\"}", |
| 5752 | .payload = EnumExplicit, | |
| 5132 | .payload = TypeUnionPacked, | |
| 5753 | 5133 | .trailing = struct { |
| 5754 | owner_union: Index, | |
| 5134 | type_hash: ?u64, | |
| 5755 | 5135 | captures: ?[]CaptureValue, |
| 5136 | field_types: []Index, | |
| 5137 | }, | |
| 5138 | .config = .{ | |
| 5139 | .@"trailing.type_hash.?" = .@"payload.captures_len == .reified", | |
| 5140 | .@"trailing.captures.?" = .@"payload.captures_len != .reified", | |
| 5141 | .@"trailing.captures.?.len" = .@"@intFromEnum(payload.captures_len)", | |
| 5142 | .@"trailing.field_types.len" = .@"payload.fields_len", | |
| 5143 | }, | |
| 5144 | }; | |
| 5145 | const enum_explicit_encoding = .{ | |
| 5146 | .summary = .@"{.payload.name%summary#\"}", | |
| 5147 | .payload = TypeEnum, | |
| 5148 | .trailing = struct { | |
| 5149 | owner_union: ?Index, | |
| 5150 | zir_index: ?TrackedInst.Index, | |
| 5756 | 5151 | type_hash: ?u64, |
| 5152 | captures: ?[]CaptureValue, | |
| 5153 | field_value_map: MapIndex, | |
| 5757 | 5154 | field_names: []NullTerminatedString, |
| 5758 | tag_values: []Index, | |
| 5155 | field_values: []Index, | |
| 5759 | 5156 | }, |
| 5760 | 5157 | .config = .{ |
| 5761 | .@"trailing.owner_union.?" = .@"payload.zir_index == .none", | |
| 5762 | .@"trailing.cau.?" = .@"payload.zir_index != .none", | |
| 5763 | .@"trailing.captures.?" = .@"payload.captures_len < 0xffffffff", | |
| 5764 | .@"trailing.captures.?.len" = .@"payload.captures_len", | |
| 5765 | .@"trailing.type_hash.?" = .@"payload.captures_len == 0xffffffff", | |
| 5158 | .@"trailing.owner_union.?" = .@"payload.captures_len == .generated_union_tag", | |
| 5159 | .@"trailing.zir_index.?" = .@"payload.captures_len != .generated_union_tag", | |
| 5160 | .@"trailing.type_hash.?" = .@"payload.captures_len == .reified", | |
| 5161 | .@"trailing.captures.?" = .@"payload.captures_len != .reified and payload.captures_len != .generated_enum_tag", | |
| 5162 | .@"trailing.captures.?.len" = .@"@intFromEnum(payload.captures_len)", | |
| 5766 | 5163 | .@"trailing.field_names.len" = .@"payload.fields_len", |
| 5767 | .@"trailing.tag_values.len" = .@"payload.fields_len", | |
| 5164 | .@"trailing.field_values.len" = .@"payload.fields_len", | |
| 5768 | 5165 | }, |
| 5769 | 5166 | }; |
| 5770 | 5167 | const encodings = .{ |
| ... | ... | @@ -5792,153 +5189,121 @@ pub const Tag = enum(u8) { |
| 5792 | 5189 | .summary = .@"@typeInfo(@typeInfo(@TypeOf({.data%summary})).@\"fn\".return_type.?).error_union.error_set", |
| 5793 | 5190 | .data = Index, |
| 5794 | 5191 | }, |
| 5795 | .type_enum_auto = .{ | |
| 5796 | .summary = .@"{.payload.name%summary#\"}", | |
| 5797 | .payload = EnumAuto, | |
| 5192 | .simple_type = .{ .summary = .@"{.index%value#.}", .index = SimpleType }, | |
| 5193 | .type_tuple = .{ | |
| 5194 | .summary = .@"struct {...}", | |
| 5195 | .payload = TypeTuple, | |
| 5798 | 5196 | .trailing = struct { |
| 5799 | owner_union: ?Index, | |
| 5800 | captures: ?[]CaptureValue, | |
| 5801 | type_hash: ?u64, | |
| 5802 | field_names: []NullTerminatedString, | |
| 5197 | field_types: []Index, | |
| 5198 | field_values: []Index, | |
| 5803 | 5199 | }, |
| 5804 | 5200 | .config = .{ |
| 5805 | .@"trailing.owner_union.?" = .@"payload.zir_index == .none", | |
| 5806 | .@"trailing.cau.?" = .@"payload.zir_index != .none", | |
| 5807 | .@"trailing.captures.?" = .@"payload.captures_len < 0xffffffff", | |
| 5808 | .@"trailing.captures.?.len" = .@"payload.captures_len", | |
| 5809 | .@"trailing.type_hash.?" = .@"payload.captures_len == 0xffffffff", | |
| 5810 | .@"trailing.field_names.len" = .@"payload.fields_len", | |
| 5201 | .@"trailing.field_types.len" = .@"payload.fields_len", | |
| 5202 | .@"trailing.field_values.len" = .@"payload.fields_len", | |
| 5811 | 5203 | }, |
| 5812 | 5204 | }, |
| 5813 | .type_enum_explicit = enum_explicit_encoding, | |
| 5814 | .type_enum_nonexhaustive = enum_explicit_encoding, | |
| 5815 | .simple_type = .{ .summary = .@"{.index%value#.}", .index = SimpleType }, | |
| 5816 | .type_opaque = .{ | |
| 5817 | .summary = .@"{.payload.name%summary#\"}", | |
| 5818 | .payload = TypeOpaque, | |
| 5819 | .trailing = struct { captures: []CaptureValue }, | |
| 5820 | .config = .{ .@"trailing.captures.len" = .@"payload.captures_len" }, | |
| 5205 | .type_function = .{ | |
| 5206 | .summary = .@"fn (...) ... {.payload.return_type%summary}", | |
| 5207 | .payload = TypeFunction, | |
| 5208 | .trailing = struct { | |
| 5209 | param_comptime_bits: ?[]u32, | |
| 5210 | param_noalias_bits: ?[]u32, | |
| 5211 | param_type: []Index, | |
| 5212 | }, | |
| 5213 | .config = .{ | |
| 5214 | .@"trailing.param_comptime_bits.?" = .@"payload.flags.has_comptime_bits", | |
| 5215 | .@"trailing.param_comptime_bits.?.len" = .@"(payload.params_len + 31) / 32", | |
| 5216 | .@"trailing.param_noalias_bits.?" = .@"payload.flags.has_noalias_bits", | |
| 5217 | .@"trailing.param_noalias_bits.?.len" = .@"(payload.params_len + 31) / 32", | |
| 5218 | .@"trailing.param_type.len" = .@"payload.params_len", | |
| 5219 | }, | |
| 5821 | 5220 | }, |
| 5221 | ||
| 5822 | 5222 | .type_struct = .{ |
| 5823 | 5223 | .summary = .@"{.payload.name%summary#\"}", |
| 5824 | 5224 | .payload = TypeStruct, |
| 5825 | 5225 | .trailing = struct { |
| 5226 | type_hash: ?u64, | |
| 5826 | 5227 | captures_len: ?u32, |
| 5827 | 5228 | captures: ?[]CaptureValue, |
| 5828 | type_hash: ?u64, | |
| 5829 | field_types: []Index, | |
| 5830 | field_names_map: OptionalMapIndex, | |
| 5831 | 5229 | field_names: []NullTerminatedString, |
| 5832 | field_inits: ?[]Index, | |
| 5230 | field_types: []Index, | |
| 5231 | field_defaults: ?[]Index, | |
| 5833 | 5232 | field_aligns: ?[]Alignment, |
| 5834 | 5233 | field_is_comptime_bits: ?[]u32, |
| 5835 | field_index: ?[]LoadedStructType.RuntimeOrder, | |
| 5836 | field_offset: []u32, | |
| 5234 | field_runtime_order: ?[]u32, | |
| 5235 | field_offsets: []u32, | |
| 5837 | 5236 | }, |
| 5838 | 5237 | .config = .{ |
| 5839 | .@"trailing.captures_len.?" = .@"payload.flags.any_captures", | |
| 5840 | .@"trailing.captures.?" = .@"payload.flags.any_captures", | |
| 5238 | .@"trailing.type_hash.?" = .@"payload.flags.any_captures == .reified", | |
| 5239 | .@"trailing.captures_len.?" = .@"payload.flags.any_captures == .true", | |
| 5240 | .@"trailing.captures.?" = .@"payload.flags.any_captures == .true", | |
| 5841 | 5241 | .@"trailing.captures.?.len" = .@"trailing.captures_len.?", |
| 5842 | .@"trailing.type_hash.?" = .@"payload.flags.is_reified", | |
| 5843 | .@"trailing.field_types.len" = .@"payload.fields_len", | |
| 5844 | 5242 | .@"trailing.field_names.len" = .@"payload.fields_len", |
| 5845 | .@"trailing.field_inits.?" = .@"payload.flags.any_default_inits", | |
| 5846 | .@"trailing.field_inits.?.len" = .@"payload.fields_len", | |
| 5847 | .@"trailing.field_aligns.?" = .@"payload.flags.any_aligned_fields", | |
| 5243 | .@"trailing.field_types.len" = .@"payload.fields_len", | |
| 5244 | .@"trailing.field_defaults.?" = .@"payload.flags.any_field_defaults", | |
| 5245 | .@"trailing.field_defaults.?.len" = .@"payload.fields_len", | |
| 5246 | .@"trailing.field_aligns.?" = .@"payload.flags.any_field_aligns", | |
| 5848 | 5247 | .@"trailing.field_aligns.?.len" = .@"payload.fields_len", |
| 5849 | 5248 | .@"trailing.field_is_comptime_bits.?" = .@"payload.flags.any_comptime_fields", |
| 5850 | 5249 | .@"trailing.field_is_comptime_bits.?.len" = .@"(payload.fields_len + 31) / 32", |
| 5851 | .@"trailing.field_index.?" = .@"!payload.flags.is_extern", | |
| 5852 | .@"trailing.field_index.?.len" = .@"payload.fields_len", | |
| 5853 | .@"trailing.field_offset.len" = .@"payload.fields_len", | |
| 5250 | .@"trailing.field_runtime_order.?" = .@"payload.flags.layout == .auto", | |
| 5251 | .@"trailing.field_runtime_order.?.len" = .@"payload.fields_len", | |
| 5252 | .@"trailing.field_offsets.len" = .@"payload.fields_len", | |
| 5854 | 5253 | }, |
| 5855 | 5254 | }, |
| 5856 | .type_struct_packed = .{ | |
| 5255 | .type_struct_packed_auto = struct_packed_encoding, | |
| 5256 | .type_struct_packed_explicit = struct_packed_encoding, | |
| 5257 | .type_struct_packed_auto_defaults = struct_packed_defaults_encoding, | |
| 5258 | .type_struct_packed_explicit_defaults = struct_packed_defaults_encoding, | |
| 5259 | .type_union = .{ | |
| 5857 | 5260 | .summary = .@"{.payload.name%summary#\"}", |
| 5858 | .payload = TypeStructPacked, | |
| 5261 | .payload = TypeUnion, | |
| 5859 | 5262 | .trailing = struct { |
| 5263 | type_hash: ?u64, | |
| 5860 | 5264 | captures_len: ?u32, |
| 5861 | 5265 | captures: ?[]CaptureValue, |
| 5862 | type_hash: ?u64, | |
| 5863 | 5266 | field_types: []Index, |
| 5864 | field_names: []NullTerminatedString, | |
| 5267 | field_aligns: ?[]Alignment, | |
| 5865 | 5268 | }, |
| 5866 | 5269 | .config = .{ |
| 5867 | .@"trailing.captures_len.?" = .@"payload.flags.any_captures", | |
| 5868 | .@"trailing.captures.?" = .@"payload.flags.any_captures", | |
| 5270 | .@"trailing.type_hash.?" = .@"payload.flags.any_captures == .reified", | |
| 5271 | .@"trailing.captures_len.?" = .@"payload.flags.any_captures == .true", | |
| 5272 | .@"trailing.captures.?" = .@"payload.flags.any_captures == .true", | |
| 5869 | 5273 | .@"trailing.captures.?.len" = .@"trailing.captures_len.?", |
| 5870 | .@"trailing.type_hash.?" = .@"payload.is_flags.is_reified", | |
| 5871 | 5274 | .@"trailing.field_types.len" = .@"payload.fields_len", |
| 5872 | .@"trailing.field_names.len" = .@"payload.fields_len", | |
| 5275 | .@"trailing.field_aligns.?" = .@"payloads.flags.any_field_aligns", | |
| 5276 | .@"trailing.field_aligns.?.len" = .@"payload.fields_len", | |
| 5873 | 5277 | }, |
| 5874 | 5278 | }, |
| 5875 | .type_struct_packed_inits = .{ | |
| 5279 | .type_union_packed_auto = union_packed_encoding, | |
| 5280 | .type_union_packed_explicit = union_packed_encoding, | |
| 5281 | .type_enum_auto = .{ | |
| 5876 | 5282 | .summary = .@"{.payload.name%summary#\"}", |
| 5877 | .payload = TypeStructPacked, | |
| 5283 | .payload = TypeEnum, | |
| 5878 | 5284 | .trailing = struct { |
| 5879 | captures_len: ?u32, | |
| 5880 | captures: ?[]CaptureValue, | |
| 5285 | owner_union: ?Index, | |
| 5286 | zir_index: ?TrackedInst.Index, | |
| 5881 | 5287 | type_hash: ?u64, |
| 5882 | field_types: []Index, | |
| 5288 | captures: ?[]CaptureValue, | |
| 5883 | 5289 | field_names: []NullTerminatedString, |
| 5884 | field_inits: []Index, | |
| 5885 | 5290 | }, |
| 5886 | 5291 | .config = .{ |
| 5887 | .@"trailing.captures_len.?" = .@"payload.flags.any_captures", | |
| 5888 | .@"trailing.captures.?" = .@"payload.flags.any_captures", | |
| 5889 | .@"trailing.captures.?.len" = .@"trailing.captures_len.?", | |
| 5890 | .@"trailing.type_hash.?" = .@"payload.is_flags.is_reified", | |
| 5891 | .@"trailing.field_types.len" = .@"payload.fields_len", | |
| 5292 | .@"trailing.owner_union.?" = .@"payload.captures_len == .generated_union_tag", | |
| 5293 | .@"trailing.zir_index.?" = .@"payload.captures_len != .generated_union_tag", | |
| 5294 | .@"trailing.type_hash.?" = .@"payload.captures_len == .reified", | |
| 5295 | .@"trailing.captures.?" = .@"payload.captures_len != .reified and payload.captures_len != .generated_enum_tag", | |
| 5296 | .@"trailing.captures.?.len" = .@"@intFromEnum(payload.captures_len)", | |
| 5892 | 5297 | .@"trailing.field_names.len" = .@"payload.fields_len", |
| 5893 | .@"trailing.field_inits.len" = .@"payload.fields_len", | |
| 5894 | }, | |
| 5895 | }, | |
| 5896 | .type_tuple = .{ | |
| 5897 | .summary = .@"struct {...}", | |
| 5898 | .payload = TypeTuple, | |
| 5899 | .trailing = struct { | |
| 5900 | field_types: []Index, | |
| 5901 | field_values: []Index, | |
| 5902 | }, | |
| 5903 | .config = .{ | |
| 5904 | .@"trailing.field_types.len" = .@"payload.fields_len", | |
| 5905 | .@"trailing.field_values.len" = .@"payload.fields_len", | |
| 5906 | 5298 | }, |
| 5907 | 5299 | }, |
| 5908 | .type_union = .{ | |
| 5300 | .type_enum_explicit = enum_explicit_encoding, | |
| 5301 | .type_enum_nonexhaustive = enum_explicit_encoding, | |
| 5302 | .type_opaque = .{ | |
| 5909 | 5303 | .summary = .@"{.payload.name%summary#\"}", |
| 5910 | .payload = TypeUnion, | |
| 5911 | .trailing = struct { | |
| 5912 | captures_len: ?u32, | |
| 5913 | captures: ?[]CaptureValue, | |
| 5914 | type_hash: ?u64, | |
| 5915 | field_types: []Index, | |
| 5916 | field_aligns: []Alignment, | |
| 5917 | }, | |
| 5918 | .config = .{ | |
| 5919 | .@"trailing.captures_len.?" = .@"payload.flags.any_captures", | |
| 5920 | .@"trailing.captures.?" = .@"payload.flags.any_captures", | |
| 5921 | .@"trailing.captures.?.len" = .@"trailing.captures_len.?", | |
| 5922 | .@"trailing.type_hash.?" = .@"payload.is_flags.is_reified", | |
| 5923 | .@"trailing.field_types.len" = .@"payload.fields_len", | |
| 5924 | .@"trailing.field_aligns.len" = .@"payload.fields_len", | |
| 5925 | }, | |
| 5926 | }, | |
| 5927 | .type_function = .{ | |
| 5928 | .summary = .@"fn (...) ... {.payload.return_type%summary}", | |
| 5929 | .payload = TypeFunction, | |
| 5930 | .trailing = struct { | |
| 5931 | param_comptime_bits: ?[]u32, | |
| 5932 | param_noalias_bits: ?[]u32, | |
| 5933 | param_type: []Index, | |
| 5934 | }, | |
| 5935 | .config = .{ | |
| 5936 | .@"trailing.param_comptime_bits.?" = .@"payload.flags.has_comptime_bits", | |
| 5937 | .@"trailing.param_comptime_bits.?.len" = .@"(payload.params_len + 31) / 32", | |
| 5938 | .@"trailing.param_noalias_bits.?" = .@"payload.flags.has_noalias_bits", | |
| 5939 | .@"trailing.param_noalias_bits.?.len" = .@"(payload.params_len + 31) / 32", | |
| 5940 | .@"trailing.param_type.len" = .@"payload.params_len", | |
| 5941 | }, | |
| 5304 | .payload = TypeOpaque, | |
| 5305 | .trailing = struct { captures: []CaptureValue }, | |
| 5306 | .config = .{ .@"trailing.captures.len" = .@"payload.captures_len" }, | |
| 5942 | 5307 | }, |
| 5943 | 5308 | |
| 5944 | 5309 | .undef = .{ .summary = .@"@as({.data%summary}, undefined)", .data = Index }, |
| ... | ... | @@ -5999,8 +5364,6 @@ pub const Tag = enum(u8) { |
| 5999 | 5364 | .int_small = .{ .summary = .@"@as({.payload.ty%summary}, {.payload.value%value})", .payload = IntSmall }, |
| 6000 | 5365 | .int_positive = .{}, |
| 6001 | 5366 | .int_negative = .{}, |
| 6002 | .int_lazy_align = .{ .summary = .@"@as({.payload.ty%summary}, @alignOf({.payload.lazy_ty%summary}))", .payload = IntLazy }, | |
| 6003 | .int_lazy_size = .{ .summary = .@"@as({.payload.ty%summary}, @sizeOf({.payload.lazy_ty%summary}))", .payload = IntLazy }, | |
| 6004 | 5367 | .error_set_error = .{ .summary = .@"@as({.payload.ty%summary}, error.@{.payload.name%summary})", .payload = Error }, |
| 6005 | 5368 | .error_union_error = .{ .summary = .@"@as({.payload.ty%summary}, error.@{.payload.name%summary})", .payload = Error }, |
| 6006 | 5369 | .error_union_payload = .{ .summary = .@"@as({.payload.ty%summary}, {.payload.val%summary})", .payload = TypeValue }, |
| ... | ... | @@ -6166,164 +5529,242 @@ pub const Tag = enum(u8) { |
| 6166 | 5529 | pub const Flags = packed struct(u32) { |
| 6167 | 5530 | cc: PackedCallingConvention, |
| 6168 | 5531 | is_var_args: bool, |
| 6169 | is_generic: bool, | |
| 6170 | 5532 | has_comptime_bits: bool, |
| 6171 | 5533 | has_noalias_bits: bool, |
| 6172 | 5534 | is_noinline: bool, |
| 6173 | _: u9 = 0, | |
| 5535 | _: u10 = 0, | |
| 6174 | 5536 | }; |
| 6175 | 5537 | }; |
| 6176 | 5538 | |
| 5539 | /// At first I thought of storing the denormalized data externally, such as... | |
| 5540 | /// | |
| 5541 | /// * runtime field order | |
| 5542 | /// * calculated field offsets | |
| 5543 | /// * size and alignment of the struct | |
| 5544 | /// | |
| 5545 | /// ...since these can be computed based on the other data here. However, | |
| 5546 | /// this data does need to be memoized, and therefore stored in memory | |
| 5547 | /// while the compiler is running, in order to avoid O(N^2) logic in many | |
| 5548 | /// places. Since the data can be stored compactly in the InternPool | |
| 5549 | /// representation, it is better for memory usage to store denormalized data | |
| 5550 | /// here, and potentially also better for performance as well. It's also simpler | |
| 5551 | /// than coming up with some other scheme for the data. | |
| 5552 | /// | |
| 6177 | 5553 | /// Trailing: |
| 6178 | /// 0. captures_len: u32 // if `any_captures` | |
| 6179 | /// 1. capture: CaptureValue // for each `captures_len` | |
| 6180 | /// 2. type_hash: PackedU64 // if `is_reified` | |
| 6181 | /// 3. field type: Index for each field; declaration order | |
| 6182 | /// 4. field align: Alignment for each field; declaration order | |
| 6183 | pub const TypeUnion = struct { | |
| 5554 | /// 0. type_hash: PackedU64 // if `any_captures == .reified` | |
| 5555 | /// 1. captures_len: u32 // if `any_captures == .true` | |
| 5556 | /// 2. capture: CaptureValue // for each `captures_len` | |
| 5557 | /// 3. field_name: NullTerminatedString // for each `fields_len` | |
| 5558 | /// 4. field_type: Index // for each `fields_len` | |
| 5559 | /// 5. field_default: Index // if `any_field_defaults`; for each `fields_len` | |
| 5560 | /// 6. field_align: Alignment // if `any_field_aligns`; for each `fields_len` | |
| 5561 | /// 7. field_is_comptime_bits: u32 // if `any_comptime_fields`; minimum `u32` for `fields_len`; LSB is field 0 | |
| 5562 | /// 8. field_runtime_order: RuntimeOrder // if `layout == .auto`; for each `fields_len` | |
| 5563 | /// 9. field_offset: u32 // for each `fields_len` | |
| 5564 | pub const TypeStruct = struct { | |
| 5565 | zir_index: TrackedInst.Index, | |
| 5566 | ||
| 6184 | 5567 | name: NullTerminatedString, |
| 6185 | 5568 | name_nav: Nav.Index.Optional, |
| 6186 | flags: Flags, | |
| 6187 | /// This could be provided through the tag type, but it is more convenient | |
| 6188 | /// to store it directly. This is also necessary for `dumpStatsFallible` to | |
| 6189 | /// work on unresolved types. | |
| 5569 | namespace: NamespaceIndex, | |
| 5570 | ||
| 6190 | 5571 | fields_len: u32, |
| 6191 | /// Only valid after .have_layout | |
| 5572 | field_name_map: MapIndex, | |
| 5573 | ||
| 5574 | /// Size in bytes of the whole struct. Always 0 until layout resolved. | |
| 6192 | 5575 | size: u32, |
| 6193 | /// Only valid after .have_layout | |
| 6194 | padding: u32, | |
| 6195 | namespace: NamespaceIndex, | |
| 6196 | /// The enum that provides the list of field names and values. | |
| 6197 | tag_ty: Index, | |
| 6198 | zir_index: TrackedInst.Index, | |
| 5576 | ||
| 5577 | flags: Flags, | |
| 6199 | 5578 | |
| 6200 | 5579 | pub const Flags = packed struct(u32) { |
| 6201 | any_captures: bool, | |
| 6202 | runtime_tag: LoadedUnionType.RuntimeTag, | |
| 6203 | /// If false, the field alignment trailing data is omitted. | |
| 6204 | any_aligned_fields: bool, | |
| 6205 | layout: std.builtin.Type.ContainerLayout, | |
| 6206 | status: LoadedUnionType.Status, | |
| 6207 | requires_comptime: RequiresComptime, | |
| 6208 | assumed_runtime_bits: bool, | |
| 6209 | assumed_pointer_aligned: bool, | |
| 5580 | any_captures: enum(u2) { true, false, reified }, | |
| 5581 | ||
| 5582 | /// `packed` layout is represented separately by `TypeStructPacked`. | |
| 5583 | layout: enum(u1) { auto, @"extern" }, | |
| 5584 | ||
| 5585 | any_comptime_fields: bool, | |
| 5586 | any_field_defaults: bool, | |
| 5587 | any_field_aligns: bool, | |
| 5588 | ||
| 5589 | /// Whether the struct is an OPV type. Always `false` until layout resolved. | |
| 5590 | /// The actual OPV is not cached, but caching this bit of state means we avoid | |
| 5591 | /// repeatedly doing redundant checks to find that the struct is not OPV! | |
| 5592 | has_one_possible_value: bool, | |
| 5593 | /// Like `has_one_possible_value`, but for a "noreturn" union (where all fields are noreturn). | |
| 5594 | has_no_possible_value: bool, | |
| 5595 | /// Whether the struct is comptime-only. Always `false` until layout resolved. | |
| 5596 | comptime_only: bool, | |
| 5597 | /// Alignment of the whole struct. Always `.none` until layout resolved. | |
| 6210 | 5598 | alignment: Alignment, |
| 6211 | is_reified: bool, | |
| 6212 | _: u12 = 0, | |
| 5599 | ||
| 5600 | _: u17 = 0, | |
| 6213 | 5601 | }; |
| 6214 | 5602 | }; |
| 6215 | 5603 | |
| 6216 | 5604 | /// Trailing: |
| 6217 | /// 0. captures_len: u32 // if `any_captures` | |
| 6218 | /// 1. capture: CaptureValue // for each `captures_len` | |
| 6219 | /// 2. type_hash: PackedU64 // if `is_reified` | |
| 6220 | /// 3. type: Index for each fields_len | |
| 6221 | /// 4. name: NullTerminatedString for each fields_len | |
| 6222 | /// 5. init: Index for each fields_len // if tag is type_struct_packed_inits | |
| 5605 | /// 0. type_hash: PackedU64 // if `captures_len == .reified` | |
| 5606 | /// 1. capture: CaptureValue // if `captures_len != .reified`; for each `captures_len` | |
| 5607 | /// 2. field_name: NullTerminatedString // for each `fields_len` | |
| 5608 | /// 3. field_type: Index // for each `fields_len` | |
| 5609 | /// 4. field_default: Index // if item tag implies field defaults; for each `fields_len` | |
| 6223 | 5610 | pub const TypeStructPacked = struct { |
| 5611 | zir_index: TrackedInst.Index, | |
| 5612 | captures_len: enum(u32) { | |
| 5613 | reified = std.math.maxInt(u32), | |
| 5614 | _, | |
| 5615 | }, | |
| 5616 | ||
| 6224 | 5617 | name: NullTerminatedString, |
| 6225 | 5618 | name_nav: Nav.Index.Optional, |
| 6226 | zir_index: TrackedInst.Index, | |
| 5619 | namespace: NamespaceIndex, | |
| 5620 | ||
| 5621 | /// The corresponding `PackedBackingMode` depends on the item's `Tag`. | |
| 5622 | backing_int_type: Index, | |
| 5623 | ||
| 6227 | 5624 | fields_len: u32, |
| 5625 | field_name_map: MapIndex, | |
| 5626 | }; | |
| 5627 | ||
| 5628 | /// Field names are intentionally omitted---they are available in `enum_tag_type`. | |
| 5629 | /// | |
| 5630 | /// Trailing: | |
| 5631 | /// 0. type_hash: PackedU64 // if `any_captures == .reified` | |
| 5632 | /// 1. captures_len: u32 // if `any_captures == .true` | |
| 5633 | /// 2. capture: CaptureValue // if `any_captures == .true`; for each `captures_len` | |
| 5634 | /// 3. field_type: Index // for each `fields_len` | |
| 5635 | /// 4. field_align: Alignment // for each `fields_len` if `any_field_aligns` | |
| 5636 | pub const TypeUnion = struct { | |
| 5637 | zir_index: TrackedInst.Index, | |
| 5638 | ||
| 5639 | name: NullTerminatedString, | |
| 5640 | name_nav: Nav.Index.Optional, | |
| 6228 | 5641 | namespace: NamespaceIndex, |
| 6229 | backing_int_ty: Index, | |
| 6230 | names_map: MapIndex, | |
| 5642 | /// The enum that provides the list of field names and values. | |
| 5643 | enum_tag_type: Index, | |
| 5644 | ||
| 5645 | /// This could be provided through the tag type, but it is more convenient | |
| 5646 | /// to store it directly. This is also necessary for `dumpStatsFallible` to | |
| 5647 | /// work on unresolved types. | |
| 5648 | /// MLUGG TODO: reconsider, because we resolve the tag type eagerly now. | |
| 5649 | fields_len: u32, | |
| 5650 | ||
| 5651 | /// Always 0 until layout resolved. | |
| 5652 | size: u32, | |
| 5653 | /// Always 0 until layout resolved. | |
| 5654 | padding: u32, | |
| 5655 | ||
| 6231 | 5656 | flags: Flags, |
| 6232 | 5657 | |
| 6233 | 5658 | pub const Flags = packed struct(u32) { |
| 6234 | any_captures: bool = false, | |
| 6235 | /// Dependency loop detection when resolving field inits. | |
| 6236 | field_inits_wip: bool = false, | |
| 6237 | inits_resolved: bool = false, | |
| 6238 | is_reified: bool = false, | |
| 6239 | _: u28 = 0, | |
| 5659 | any_captures: enum(u2) { true, false, reified }, | |
| 5660 | ||
| 5661 | /// Whether `enum_tag_type` was explicitly specified with `union(E)` syntax. | |
| 5662 | /// | |
| 5663 | /// For `union(enum(E))` syntax, this is `false`, but the generated enum tag type is | |
| 5664 | /// considered to have an explicitly specified integer tag type. | |
| 5665 | explicit_tag_type: bool, | |
| 5666 | ||
| 5667 | /// `packed` layout is represented separately by `TypeStructPacked`. | |
| 5668 | layout: enum(u1) { auto, @"extern" }, | |
| 5669 | ||
| 5670 | any_field_aligns: bool, | |
| 5671 | runtime_tag: LoadedUnionType.RuntimeTag, | |
| 5672 | ||
| 5673 | /// Whether the union is an OPV type. Always `false` until layout resolved. | |
| 5674 | /// The actual OPV is not cached, but caching this bit of state means we avoid | |
| 5675 | /// repeatedly doing redundant checks to find that the union is not OPV! | |
| 5676 | has_one_possible_value: bool, | |
| 5677 | /// Like `has_one_possible_value`, but for a "noreturn" union (where all fields are noreturn). | |
| 5678 | has_no_possible_value: bool, | |
| 5679 | /// Whether the union is comptime-only. Always `false` until layout resolved. | |
| 5680 | comptime_only: bool, | |
| 5681 | /// Alignment of the whole union. Always `.none` until layout resolved. | |
| 5682 | alignment: Alignment, | |
| 5683 | ||
| 5684 | _: u16 = 0, | |
| 6240 | 5685 | }; |
| 6241 | 5686 | }; |
| 6242 | 5687 | |
| 6243 | /// At first I thought of storing the denormalized data externally, such as... | |
| 6244 | /// | |
| 6245 | /// * runtime field order | |
| 6246 | /// * calculated field offsets | |
| 6247 | /// * size and alignment of the struct | |
| 6248 | /// | |
| 6249 | /// ...since these can be computed based on the other data here. However, | |
| 6250 | /// this data does need to be memoized, and therefore stored in memory | |
| 6251 | /// while the compiler is running, in order to avoid O(N^2) logic in many | |
| 6252 | /// places. Since the data can be stored compactly in the InternPool | |
| 6253 | /// representation, it is better for memory usage to store denormalized data | |
| 6254 | /// here, and potentially also better for performance as well. It's also simpler | |
| 6255 | /// than coming up with some other scheme for the data. | |
| 5688 | /// Field names are intentionally omitted---they are available in `enum_tag_type`. | |
| 6256 | 5689 | /// |
| 6257 | 5690 | /// Trailing: |
| 6258 | /// 0. captures_len: u32 // if `any_captures` | |
| 6259 | /// 1. capture: CaptureValue // for each `captures_len` | |
| 6260 | /// 2. type_hash: PackedU64 // if `is_reified` | |
| 6261 | /// 3. type: Index for each field in declared order | |
| 6262 | /// 4. if any_default_inits: | |
| 6263 | /// init: Index // for each field in declared order | |
| 6264 | /// 5. if any_aligned_fields: | |
| 6265 | /// align: Alignment // for each field in declared order | |
| 6266 | /// 6. if any_comptime_fields: | |
| 6267 | /// field_is_comptime_bits: u32 // minimal number of u32s needed, LSB is field 0 | |
| 6268 | /// 7. if not is_extern: | |
| 6269 | /// field_index: RuntimeOrder // for each field in runtime order | |
| 6270 | /// 8. field_offset: u32 // for each field in declared order, undef until layout_resolved | |
| 6271 | pub const TypeStruct = struct { | |
| 5691 | /// 0. type_hash: PackedU64 // if `captures_len == .reified` | |
| 5692 | /// 1. capture: CaptureValue // if `captures_len != .reified`; for each `captures_len` | |
| 5693 | /// 2. field_type: Index // for each `fields_len` | |
| 5694 | pub const TypeUnionPacked = struct { | |
| 5695 | zir_index: TrackedInst.Index, | |
| 5696 | captures_len: enum(u32) { | |
| 5697 | reified = std.math.maxInt(u32), | |
| 5698 | _, | |
| 5699 | }, | |
| 5700 | ||
| 6272 | 5701 | name: NullTerminatedString, |
| 6273 | 5702 | name_nav: Nav.Index.Optional, |
| 6274 | zir_index: TrackedInst.Index, | |
| 6275 | 5703 | namespace: NamespaceIndex, |
| 5704 | ||
| 5705 | /// The corresponding `PackedBackingMode` depends on the item's `Tag`. | |
| 5706 | backing_int_type: Index, | |
| 5707 | /// Although packed unions do not semantically have a tag type, the compiler still assigns | |
| 5708 | /// them a "hypothetical" tag type. | |
| 5709 | enum_tag_type: Index, | |
| 5710 | ||
| 5711 | /// This could be provided through the tag type, but it is more convenient | |
| 5712 | /// to store it directly. This is also necessary for `dumpStatsFallible` to | |
| 5713 | /// work on unresolved types. | |
| 5714 | /// MLUGG TODO: reconsider, because we resolve the tag type eagerly now. | |
| 6276 | 5715 | fields_len: u32, |
| 6277 | flags: Flags, | |
| 6278 | size: u32, | |
| 5716 | }; | |
| 6279 | 5717 | |
| 6280 | pub const Flags = packed struct(u32) { | |
| 6281 | any_captures: bool = false, | |
| 6282 | is_extern: bool = false, | |
| 6283 | known_non_opv: bool = false, | |
| 6284 | requires_comptime: RequiresComptime = @enumFromInt(0), | |
| 6285 | assumed_runtime_bits: bool = false, | |
| 6286 | assumed_pointer_aligned: bool = false, | |
| 6287 | any_comptime_fields: bool = false, | |
| 6288 | any_default_inits: bool = false, | |
| 6289 | any_aligned_fields: bool = false, | |
| 6290 | /// `.none` until layout_resolved | |
| 6291 | alignment: Alignment = @enumFromInt(0), | |
| 6292 | /// Dependency loop detection when resolving struct alignment. | |
| 6293 | alignment_wip: bool = false, | |
| 6294 | /// Dependency loop detection when resolving field types. | |
| 6295 | field_types_wip: bool = false, | |
| 6296 | /// Dependency loop detection when resolving struct layout. | |
| 6297 | layout_wip: bool = false, | |
| 6298 | /// Indicates whether `size`, `alignment`, runtime field order, and | |
| 6299 | /// field offets are populated. | |
| 6300 | layout_resolved: bool = false, | |
| 6301 | /// Dependency loop detection when resolving field inits. | |
| 6302 | field_inits_wip: bool = false, | |
| 6303 | /// Indicates whether `field_inits` has been resolved. | |
| 6304 | inits_resolved: bool = false, | |
| 6305 | // The types and all its fields have had their layout resolved. Even through pointer = false, | |
| 6306 | // which `layout_resolved` does not ensure. | |
| 6307 | fully_resolved: bool = false, | |
| 6308 | is_reified: bool = false, | |
| 6309 | _: u8 = 0, | |
| 6310 | }; | |
| 5718 | /// Trailing: | |
| 5719 | /// 0. owner_union: Index // if `captures_len == .generated_union_tag` | |
| 5720 | /// 1. zir_index: TrackedInst.Index // if `captures_len != .generated_union_tag` | |
| 5721 | /// 2. type_hash: PackedU64 // if `captures_len == .reified` | |
| 5722 | /// 3. capture: CaptureValue // if `captures_len` is not a named tag; for each `captures_len` | |
| 5723 | /// 4. field_value_map: MapIndex // if tag is not `.type_enum_auto` | |
| 5724 | /// 5. field_name: NullTerminatedString // for each `fields_len` | |
| 5725 | /// 6. field_value: Index // if tag is not `.type_enum_auto`; for each `fields_len` | |
| 5726 | pub const TypeEnum = struct { | |
| 5727 | captures_len: enum(u32) { | |
| 5728 | reified = std.math.maxInt(u32), | |
| 5729 | generated_union_tag = std.math.maxInt(u32) - 1, | |
| 5730 | _, | |
| 5731 | }, | |
| 5732 | ||
| 5733 | name: NullTerminatedString, | |
| 5734 | name_nav: Nav.Index.Optional, | |
| 5735 | namespace: NamespaceIndex, | |
| 5736 | ||
| 5737 | /// An integer type which is used for the numerical value of the enum. Whether this was | |
| 5738 | /// user-provided or inferred by the compiler depends on the tag. Either way, the field | |
| 5739 | /// is populated immediately (i.e. does not require any type resolution). | |
| 5740 | int_tag_type: Index, | |
| 5741 | ||
| 5742 | fields_len: u32, | |
| 5743 | field_name_map: MapIndex, | |
| 6311 | 5744 | }; |
| 6312 | 5745 | |
| 6313 | 5746 | /// Trailing: |
| 6314 | 5747 | /// 0. capture: CaptureValue // for each `captures_len` |
| 6315 | 5748 | pub const TypeOpaque = struct { |
| 5749 | zir_index: TrackedInst.Index, | |
| 5750 | captures_len: u32, | |
| 5751 | ||
| 6316 | 5752 | name: NullTerminatedString, |
| 6317 | 5753 | name_nav: Nav.Index.Optional, |
| 6318 | /// Contains the declarations inside this opaque. | |
| 6319 | 5754 | namespace: NamespaceIndex, |
| 6320 | /// The index of the `opaque_decl` instruction. | |
| 6321 | zir_index: TrackedInst.Index, | |
| 6322 | /// `std.math.maxInt(u32)` indicates this type is reified. | |
| 6323 | captures_len: u32, | |
| 6324 | 5755 | }; |
| 6325 | 5756 | }; |
| 6326 | 5757 | |
| 5758 | /// Differentiates between user-provided and compiler-generated backing types for packed aggregates. | |
| 5759 | pub const PackedBackingMode = enum(u1) { | |
| 5760 | /// The backing type was explicitly provided by the user, i.e. `packed struct(T)` or `packed union(T)`. | |
| 5761 | /// Type resolution simply *validates* that type. | |
| 5762 | explicit, | |
| 5763 | /// No backing type was explicitly provided by the user. Type layout resolution will populate the | |
| 5764 | /// backing type based on the field types; before then it is invalid (probably `.none`). | |
| 5765 | auto, | |
| 5766 | }; | |
| 5767 | ||
| 6327 | 5768 | /// State that is mutable during semantic analysis. This data is not used for |
| 6328 | 5769 | /// equality or hashing, except for `inferred_error_set` which is considered |
| 6329 | 5770 | /// to be part of the type of the function. |
| ... | ... | @@ -6536,10 +5977,8 @@ pub const Alignment = enum(u6) { |
| 6536 | 5977 | pub const empty: Slice = .{ .tid = .main, .start = 0, .len = 0 }; |
| 6537 | 5978 | |
| 6538 | 5979 | pub fn get(slice: Slice, ip: *const InternPool) []Alignment { |
| 6539 | // TODO: implement @ptrCast between slices changing the length | |
| 6540 | 5980 | const extra = ip.getLocalShared(slice.tid).extra.acquire(); |
| 6541 | //const bytes: []u8 = @ptrCast(extra.view().items(.@"0")[slice.start..]); | |
| 6542 | const bytes: []u8 = std.mem.sliceAsBytes(extra.view().items(.@"0")[slice.start..]); | |
| 5981 | const bytes: []u8 = @ptrCast(extra.view().items(.@"0")[slice.start..]); | |
| 6543 | 5982 | return @ptrCast(bytes[0..slice.len]); |
| 6544 | 5983 | } |
| 6545 | 5984 | }; |
| ... | ... | @@ -6596,55 +6035,6 @@ pub const Array = struct { |
| 6596 | 6035 | } |
| 6597 | 6036 | }; |
| 6598 | 6037 | |
| 6599 | /// Trailing: | |
| 6600 | /// 0. owner_union: Index // if `zir_index == .none` | |
| 6601 | /// 1. capture: CaptureValue // for each `captures_len` | |
| 6602 | /// 2. type_hash: PackedU64 // if reified (`captures_len == std.math.maxInt(u32)`) | |
| 6603 | /// 3. field name: NullTerminatedString for each fields_len; declaration order | |
| 6604 | /// 4. tag value: Index for each fields_len; declaration order | |
| 6605 | pub const EnumExplicit = struct { | |
| 6606 | name: NullTerminatedString, | |
| 6607 | name_nav: Nav.Index.Optional, | |
| 6608 | /// `std.math.maxInt(u32)` indicates this type is reified. | |
| 6609 | captures_len: u32, | |
| 6610 | namespace: NamespaceIndex, | |
| 6611 | /// An integer type which is used for the numerical value of the enum, which | |
| 6612 | /// has been explicitly provided by the enum declaration. | |
| 6613 | int_tag_type: Index, | |
| 6614 | fields_len: u32, | |
| 6615 | /// Maps field names to declaration index. | |
| 6616 | names_map: MapIndex, | |
| 6617 | /// Maps field values to declaration index. | |
| 6618 | /// If this is `none`, it means the trailing tag values are absent because | |
| 6619 | /// they are auto-numbered. | |
| 6620 | values_map: OptionalMapIndex, | |
| 6621 | /// `none` means this is a generated tag type. | |
| 6622 | /// There will be a trailing union type for which this is a tag. | |
| 6623 | zir_index: TrackedInst.Index.Optional, | |
| 6624 | }; | |
| 6625 | ||
| 6626 | /// Trailing: | |
| 6627 | /// 0. owner_union: Index // if `zir_index == .none` | |
| 6628 | /// 1. capture: CaptureValue // for each `captures_len` | |
| 6629 | /// 2. type_hash: PackedU64 // if reified (`captures_len == std.math.maxInt(u32)`) | |
| 6630 | /// 3. field name: NullTerminatedString for each fields_len; declaration order | |
| 6631 | pub const EnumAuto = struct { | |
| 6632 | name: NullTerminatedString, | |
| 6633 | name_nav: Nav.Index.Optional, | |
| 6634 | /// `std.math.maxInt(u32)` indicates this type is reified. | |
| 6635 | captures_len: u32, | |
| 6636 | namespace: NamespaceIndex, | |
| 6637 | /// An integer type which is used for the numerical value of the enum, which | |
| 6638 | /// was inferred by Zig based on the number of tags. | |
| 6639 | int_tag_type: Index, | |
| 6640 | fields_len: u32, | |
| 6641 | /// Maps field names to declaration index. | |
| 6642 | names_map: MapIndex, | |
| 6643 | /// `none` means this is a generated tag type. | |
| 6644 | /// There will be a trailing union type for which this is a tag. | |
| 6645 | zir_index: TrackedInst.Index.Optional, | |
| 6646 | }; | |
| 6647 | ||
| 6648 | 6038 | pub const PackedU64 = packed struct(u64) { |
| 6649 | 6039 | a: u32, |
| 6650 | 6040 | b: u32, |
| ... | ... | @@ -6827,11 +6217,6 @@ pub const IntSmall = struct { |
| 6827 | 6217 | value: u32, |
| 6828 | 6218 | }; |
| 6829 | 6219 | |
| 6830 | pub const IntLazy = struct { | |
| 6831 | ty: Index, | |
| 6832 | lazy_ty: Index, | |
| 6833 | }; | |
| 6834 | ||
| 6835 | 6220 | /// A f64 value, broken up into 2 u32 parts. |
| 6836 | 6221 | pub const Float64 = struct { |
| 6837 | 6222 | piece0: u32, |
| ... | ... | @@ -6994,7 +6379,9 @@ pub fn deinit(ip: *InternPool, gpa: Allocator, io: Io) void { |
| 6994 | 6379 | ip.src_hash_deps.deinit(gpa); |
| 6995 | 6380 | ip.nav_val_deps.deinit(gpa); |
| 6996 | 6381 | ip.nav_ty_deps.deinit(gpa); |
| 6997 | ip.interned_deps.deinit(gpa); | |
| 6382 | ip.func_ies_deps.deinit(gpa); | |
| 6383 | ip.type_layout_deps.deinit(gpa); | |
| 6384 | ip.type_inits_deps.deinit(gpa); | |
| 6998 | 6385 | ip.zon_file_deps.deinit(gpa); |
| 6999 | 6386 | ip.embed_file_deps.deinit(gpa); |
| 7000 | 6387 | ip.namespace_deps.deinit(gpa); |
| ... | ... | @@ -7130,132 +6517,138 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { |
| 7130 | 6517 | .type_inferred_error_set => .{ |
| 7131 | 6518 | .inferred_error_set_type = @enumFromInt(data), |
| 7132 | 6519 | }, |
| 7133 | ||
| 7134 | .type_opaque => .{ .opaque_type = ns: { | |
| 7135 | const extra = extraDataTrail(unwrapped_index.getExtra(ip), Tag.TypeOpaque, data); | |
| 7136 | if (extra.data.captures_len == std.math.maxInt(u32)) { | |
| 7137 | break :ns .{ .reified = .{ | |
| 7138 | .zir_index = extra.data.zir_index, | |
| 7139 | .type_hash = 0, | |
| 7140 | } }; | |
| 7141 | } | |
| 7142 | break :ns .{ .declared = .{ | |
| 7143 | .zir_index = extra.data.zir_index, | |
| 7144 | .captures = .{ .owned = .{ | |
| 7145 | .tid = unwrapped_index.tid, | |
| 7146 | .start = extra.end, | |
| 7147 | .len = extra.data.captures_len, | |
| 7148 | } }, | |
| 7149 | } }; | |
| 7150 | } }, | |
| 6520 | .type_function => .{ .func_type = extraFuncType(unwrapped_index.tid, unwrapped_index.getExtra(ip), data) }, | |
| 6521 | .type_tuple => .{ .tuple_type = extraTypeTuple(unwrapped_index.tid, unwrapped_index.getExtra(ip), data) }, | |
| 7151 | 6522 | |
| 7152 | 6523 | .type_struct => .{ .struct_type = ns: { |
| 7153 | 6524 | const extra_list = unwrapped_index.getExtra(ip); |
| 7154 | const extra_items = extra_list.view().items(.@"0"); | |
| 7155 | const zir_index: TrackedInst.Index = @enumFromInt(extra_items[data + std.meta.fieldIndex(Tag.TypeStruct, "zir_index").?]); | |
| 7156 | const flags: Tag.TypeStruct.Flags = @bitCast(@atomicLoad(u32, &extra_items[data + std.meta.fieldIndex(Tag.TypeStruct, "flags").?], .unordered)); | |
| 7157 | const end_extra_index = data + @as(u32, @typeInfo(Tag.TypeStruct).@"struct".fields.len); | |
| 7158 | if (flags.is_reified) { | |
| 7159 | assert(!flags.any_captures); | |
| 7160 | break :ns .{ .reified = .{ | |
| 7161 | .zir_index = zir_index, | |
| 7162 | .type_hash = extraData(extra_list, PackedU64, end_extra_index).get(), | |
| 7163 | } }; | |
| 7164 | } | |
| 7165 | break :ns .{ .declared = .{ | |
| 7166 | .zir_index = zir_index, | |
| 7167 | .captures = .{ .owned = if (flags.any_captures) .{ | |
| 7168 | .tid = unwrapped_index.tid, | |
| 7169 | .start = end_extra_index + 1, | |
| 7170 | .len = extra_list.view().items(.@"0")[end_extra_index], | |
| 7171 | } else CaptureValue.Slice.empty }, | |
| 7172 | } }; | |
| 6525 | const extra = extraDataTrail(extra_list, Tag.TypeStruct, data); | |
| 6526 | break :ns switch (extra.data.flags.any_captures) { | |
| 6527 | .reified => .{ .reified = .{ | |
| 6528 | .zir_index = extra.data.zir_index, | |
| 6529 | .type_hash = extraData(extra_list, PackedU64, extra.end).get(), | |
| 6530 | } }, | |
| 6531 | .false => .{ .declared = .{ | |
| 6532 | .zir_index = extra.data.zir_index, | |
| 6533 | .arg_ty = .none, | |
| 6534 | .captures = .{ .owned = .empty }, | |
| 6535 | } }, | |
| 6536 | .true => .{ .declared = .{ | |
| 6537 | .zir_index = extra.data.zir_index, | |
| 6538 | .arg_ty = .none, | |
| 6539 | .captures = .{ .owned = .{ | |
| 6540 | .tid = unwrapped_index.tid, | |
| 6541 | .start = extra.end + 1, | |
| 6542 | .len = extra_list.view().items(.@"0")[extra.end], | |
| 6543 | } }, | |
| 6544 | } }, | |
| 6545 | }; | |
| 7173 | 6546 | } }, |
| 7174 | ||
| 7175 | .type_struct_packed, .type_struct_packed_inits => .{ .struct_type = ns: { | |
| 6547 | .type_struct_packed_auto, | |
| 6548 | .type_struct_packed_explicit, | |
| 6549 | .type_struct_packed_auto_defaults, | |
| 6550 | .type_struct_packed_explicit_defaults, | |
| 6551 | => .{ .struct_type = ns: { | |
| 7176 | 6552 | const extra_list = unwrapped_index.getExtra(ip); |
| 7177 | const extra_items = extra_list.view().items(.@"0"); | |
| 7178 | const zir_index: TrackedInst.Index = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "zir_index").?]); | |
| 7179 | const flags: Tag.TypeStructPacked.Flags = @bitCast(@atomicLoad(u32, &extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "flags").?], .unordered)); | |
| 7180 | const end_extra_index = data + @as(u32, @typeInfo(Tag.TypeStructPacked).@"struct".fields.len); | |
| 7181 | if (flags.is_reified) { | |
| 7182 | assert(!flags.any_captures); | |
| 7183 | break :ns .{ .reified = .{ | |
| 7184 | .zir_index = zir_index, | |
| 7185 | .type_hash = extraData(extra_list, PackedU64, end_extra_index).get(), | |
| 7186 | } }; | |
| 7187 | } | |
| 7188 | break :ns .{ .declared = .{ | |
| 7189 | .zir_index = zir_index, | |
| 7190 | .captures = .{ .owned = if (flags.any_captures) .{ | |
| 7191 | .tid = unwrapped_index.tid, | |
| 7192 | .start = end_extra_index + 1, | |
| 7193 | .len = extra_items[end_extra_index], | |
| 7194 | } else CaptureValue.Slice.empty }, | |
| 7195 | } }; | |
| 6553 | const extra = extraDataTrail(extra_list, Tag.TypeStructPacked, data); | |
| 6554 | break :ns switch (extra.data.captures_len) { | |
| 6555 | .reified => .{ .reified = .{ | |
| 6556 | .zir_index = extra.data.zir_index, | |
| 6557 | .type_hash = extraData(extra_list, PackedU64, extra.end).get(), | |
| 6558 | } }, | |
| 6559 | _ => .{ .declared = .{ | |
| 6560 | .zir_index = extra.data.zir_index, | |
| 6561 | .arg_ty = switch (item.tag) { | |
| 6562 | .type_struct_packed_auto, .type_struct_packed_auto_defaults => .none, | |
| 6563 | .type_struct_packed_explicit, .type_struct_packed_explicit_defaults => extra.data.backing_int_type, | |
| 6564 | else => unreachable, | |
| 6565 | }, | |
| 6566 | .captures = .{ .owned = .{ | |
| 6567 | .tid = unwrapped_index.tid, | |
| 6568 | .start = extra.end, | |
| 6569 | .len = @intFromEnum(extra.data.captures_len), | |
| 6570 | } }, | |
| 6571 | } }, | |
| 6572 | }; | |
| 7196 | 6573 | } }, |
| 7197 | .type_tuple => .{ .tuple_type = extraTypeTuple(unwrapped_index.tid, unwrapped_index.getExtra(ip), data) }, | |
| 7198 | 6574 | .type_union => .{ .union_type = ns: { |
| 7199 | 6575 | const extra_list = unwrapped_index.getExtra(ip); |
| 7200 | 6576 | const extra = extraDataTrail(extra_list, Tag.TypeUnion, data); |
| 7201 | if (extra.data.flags.is_reified) { | |
| 7202 | assert(!extra.data.flags.any_captures); | |
| 7203 | break :ns .{ .reified = .{ | |
| 6577 | break :ns switch (extra.data.flags.any_captures) { | |
| 6578 | .reified => .{ .reified = .{ | |
| 7204 | 6579 | .zir_index = extra.data.zir_index, |
| 7205 | 6580 | .type_hash = extraData(extra_list, PackedU64, extra.end).get(), |
| 7206 | } }; | |
| 7207 | } | |
| 7208 | break :ns .{ .declared = .{ | |
| 7209 | .zir_index = extra.data.zir_index, | |
| 7210 | .captures = .{ .owned = if (extra.data.flags.any_captures) .{ | |
| 7211 | .tid = unwrapped_index.tid, | |
| 7212 | .start = extra.end + 1, | |
| 7213 | .len = extra_list.view().items(.@"0")[extra.end], | |
| 7214 | } else CaptureValue.Slice.empty }, | |
| 7215 | } }; | |
| 6581 | } }, | |
| 6582 | .false => .{ .declared = .{ | |
| 6583 | .zir_index = extra.data.zir_index, | |
| 6584 | .arg_ty = if (extra.data.flags.explicit_tag_type) extra.data.enum_tag_type else .none, | |
| 6585 | .captures = .{ .owned = .empty }, | |
| 6586 | } }, | |
| 6587 | .true => .{ .declared = .{ | |
| 6588 | .zir_index = extra.data.zir_index, | |
| 6589 | .arg_ty = if (extra.data.flags.explicit_tag_type) extra.data.enum_tag_type else .none, | |
| 6590 | .captures = .{ .owned = .{ | |
| 6591 | .tid = unwrapped_index.tid, | |
| 6592 | .start = extra.end + 1, | |
| 6593 | .len = extra_list.view().items(.@"0")[extra.end], | |
| 6594 | } }, | |
| 6595 | } }, | |
| 6596 | }; | |
| 7216 | 6597 | } }, |
| 7217 | ||
| 7218 | .type_enum_auto => .{ .enum_type = ns: { | |
| 6598 | .type_union_packed_auto, .type_union_packed_explicit => .{ .union_type = ns: { | |
| 7219 | 6599 | const extra_list = unwrapped_index.getExtra(ip); |
| 7220 | const extra = extraDataTrail(extra_list, EnumAuto, data); | |
| 7221 | const zir_index = extra.data.zir_index.unwrap() orelse { | |
| 7222 | assert(extra.data.captures_len == 0); | |
| 7223 | break :ns .{ .generated_tag = .{ | |
| 7224 | .union_type = @enumFromInt(extra_list.view().items(.@"0")[extra.end]), | |
| 7225 | } }; | |
| 7226 | }; | |
| 7227 | if (extra.data.captures_len == std.math.maxInt(u32)) { | |
| 7228 | break :ns .{ .reified = .{ | |
| 7229 | .zir_index = zir_index, | |
| 6600 | const extra = extraDataTrail(extra_list, Tag.TypeUnionPacked, data); | |
| 6601 | break :ns switch (extra.data.captures_len) { | |
| 6602 | .reified => .{ .reified = .{ | |
| 6603 | .zir_index = extra.data.zir_index, | |
| 7230 | 6604 | .type_hash = extraData(extra_list, PackedU64, extra.end).get(), |
| 7231 | } }; | |
| 7232 | } | |
| 7233 | break :ns .{ .declared = .{ | |
| 7234 | .zir_index = zir_index, | |
| 7235 | .captures = .{ .owned = .{ | |
| 7236 | .tid = unwrapped_index.tid, | |
| 7237 | .start = extra.end, | |
| 7238 | .len = extra.data.captures_len, | |
| 7239 | 6605 | } }, |
| 7240 | } }; | |
| 6606 | _ => .{ .declared = .{ | |
| 6607 | .zir_index = extra.data.zir_index, | |
| 6608 | .arg_ty = switch (item.tag) { | |
| 6609 | .type_union_packed_auto => .none, | |
| 6610 | .type_union_packed_explicit => extra.data.backing_int_type, | |
| 6611 | else => unreachable, | |
| 6612 | }, | |
| 6613 | .captures = .{ .owned = .{ | |
| 6614 | .tid = unwrapped_index.tid, | |
| 6615 | .start = extra.end, | |
| 6616 | .len = @intFromEnum(extra.data.captures_len), | |
| 6617 | } }, | |
| 6618 | } }, | |
| 6619 | }; | |
| 7241 | 6620 | } }, |
| 7242 | .type_enum_explicit, .type_enum_nonexhaustive => .{ .enum_type = ns: { | |
| 6621 | .type_enum_auto, .type_enum_explicit, .type_enum_nonexhaustive => .{ .enum_type = ns: { | |
| 7243 | 6622 | const extra_list = unwrapped_index.getExtra(ip); |
| 7244 | const extra = extraDataTrail(extra_list, EnumExplicit, data); | |
| 7245 | const zir_index = extra.data.zir_index.unwrap() orelse { | |
| 7246 | assert(extra.data.captures_len == 0); | |
| 7247 | break :ns .{ .generated_tag = .{ | |
| 7248 | .union_type = @enumFromInt(extra_list.view().items(.@"0")[extra.end]), | |
| 7249 | } }; | |
| 6623 | const extra = extraDataTrail(extra_list, Tag.TypeEnum, data); | |
| 6624 | break :ns switch (extra.data.captures_len) { | |
| 6625 | .reified => .{ .reified = .{ | |
| 6626 | .zir_index = @enumFromInt(extra_list.view().items(.@"0")[extra.end]), | |
| 6627 | .type_hash = extraData(extra_list, PackedU64, extra.end + 1).get(), | |
| 6628 | } }, | |
| 6629 | .generated_union_tag => .{ .generated_union_tag = owner_union: { | |
| 6630 | break :owner_union @enumFromInt(extra_list.view().items(.@"0")[extra.end]); | |
| 6631 | } }, | |
| 6632 | _ => .{ .declared = .{ | |
| 6633 | .zir_index = @enumFromInt(extra_list.view().items(.@"0")[extra.end]), | |
| 6634 | .arg_ty = switch (item.tag) { | |
| 6635 | .type_enum_auto => .none, | |
| 6636 | .type_enum_explicit, .type_enum_nonexhaustive => extra.data.int_tag_type, | |
| 6637 | else => unreachable, | |
| 6638 | }, | |
| 6639 | .captures = .{ .owned = .{ | |
| 6640 | .tid = unwrapped_index.tid, | |
| 6641 | .start = extra.end + 1, | |
| 6642 | .len = @intFromEnum(extra.data.captures_len), | |
| 6643 | } }, | |
| 6644 | } }, | |
| 7250 | 6645 | }; |
| 7251 | if (extra.data.captures_len == std.math.maxInt(u32)) { | |
| 7252 | break :ns .{ .reified = .{ | |
| 7253 | .zir_index = zir_index, | |
| 7254 | .type_hash = extraData(extra_list, PackedU64, extra.end).get(), | |
| 7255 | } }; | |
| 7256 | } | |
| 6646 | } }, | |
| 6647 | .type_opaque => .{ .opaque_type = ns: { | |
| 6648 | const extra = extraDataTrail(unwrapped_index.getExtra(ip), Tag.TypeOpaque, data); | |
| 7257 | 6649 | break :ns .{ .declared = .{ |
| 7258 | .zir_index = zir_index, | |
| 6650 | .zir_index = extra.data.zir_index, | |
| 6651 | .arg_ty = .none, | |
| 7259 | 6652 | .captures = .{ .owned = .{ |
| 7260 | 6653 | .tid = unwrapped_index.tid, |
| 7261 | 6654 | .start = extra.end, |
| ... | ... | @@ -7263,7 +6656,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { |
| 7263 | 6656 | } }, |
| 7264 | 6657 | } }; |
| 7265 | 6658 | } }, |
| 7266 | .type_function => .{ .func_type = extraFuncType(unwrapped_index.tid, unwrapped_index.getExtra(ip), data) }, | |
| 7267 | 6659 | |
| 7268 | 6660 | .undef => .{ .undef = @enumFromInt(data) }, |
| 7269 | 6661 | .opt_null => .{ .opt = .{ |
| ... | ... | @@ -7390,17 +6782,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { |
| 7390 | 6782 | .storage = .{ .u64 = info.value }, |
| 7391 | 6783 | } }; |
| 7392 | 6784 | }, |
| 7393 | .int_lazy_align, .int_lazy_size => |tag| { | |
| 7394 | const info = extraData(unwrapped_index.getExtra(ip), IntLazy, data); | |
| 7395 | return .{ .int = .{ | |
| 7396 | .ty = info.ty, | |
| 7397 | .storage = switch (tag) { | |
| 7398 | .int_lazy_align => .{ .lazy_align = info.lazy_ty }, | |
| 7399 | .int_lazy_size => .{ .lazy_size = info.lazy_ty }, | |
| 7400 | else => unreachable, | |
| 7401 | }, | |
| 7402 | } }; | |
| 7403 | }, | |
| 7404 | 6785 | .float_f16 => .{ .float = .{ |
| 7405 | 6786 | .ty = .f16_type, |
| 7406 | 6787 | .storage = .{ .f16 = @bitCast(@as(u16, @intCast(data))) }, |
| ... | ... | @@ -7488,7 +6869,9 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { |
| 7488 | 6869 | }, |
| 7489 | 6870 | .type_array_small, |
| 7490 | 6871 | .type_vector, |
| 7491 | .type_struct_packed, | |
| 6872 | // MLUGG TODO: is this still possible? also, i hate .only_possible_value, it should die in a fire. | |
| 6873 | .type_struct_packed_auto, | |
| 6874 | .type_struct_packed_explicit, | |
| 7492 | 6875 | => .{ .aggregate = .{ |
| 7493 | 6876 | .ty = ty, |
| 7494 | 6877 | .storage = .{ .elems = &.{} }, |
| ... | ... | @@ -7496,11 +6879,15 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { |
| 7496 | 6879 | |
| 7497 | 6880 | // There is only one possible value precisely due to the |
| 7498 | 6881 | // fact that this values slice is fully populated! |
| 7499 | .type_struct, .type_struct_packed_inits => { | |
| 6882 | .type_struct, | |
| 6883 | // MLUGG TODO: is this still possible? also, i hate .only_possible_value, it should die in a fire. | |
| 6884 | .type_struct_packed_auto_defaults, | |
| 6885 | .type_struct_packed_explicit_defaults, | |
| 6886 | => { | |
| 7500 | 6887 | const info = loadStructType(ip, ty); |
| 7501 | 6888 | return .{ .aggregate = .{ |
| 7502 | 6889 | .ty = ty, |
| 7503 | .storage = .{ .elems = @ptrCast(info.field_inits.get(ip)) }, | |
| 6890 | .storage = .{ .elems = @ptrCast(info.field_defaults.get(ip)) }, | |
| 7504 | 6891 | } }; |
| 7505 | 6892 | }, |
| 7506 | 6893 | |
| ... | ... | @@ -7634,7 +7021,6 @@ fn extraFuncType(tid: Zcu.PerThread.Id, extra: Local.Extra, extra_index: u32) Ke |
| 7634 | 7021 | .cc = type_function.data.flags.cc.unpack(), |
| 7635 | 7022 | .is_var_args = type_function.data.flags.is_var_args, |
| 7636 | 7023 | .is_noinline = type_function.data.flags.is_noinline, |
| 7637 | .is_generic = type_function.data.flags.is_generic, | |
| 7638 | 7024 | }; |
| 7639 | 7025 | } |
| 7640 | 7026 | |
| ... | ... | @@ -7893,45 +7279,6 @@ fn getOrPutKeyEnsuringAdditionalCapacity( |
| 7893 | 7279 | .map_index = map_index, |
| 7894 | 7280 | } }; |
| 7895 | 7281 | } |
| 7896 | /// Like `getOrPutKey`, but asserts that the key already exists, and prepares to replace | |
| 7897 | /// its shard entry with a new `Index` anyway. After finalizing this, the old index remains | |
| 7898 | /// valid (in that `indexToKey` and similar queries will behave as before), but it will | |
| 7899 | /// never be returned from a lookup (`getOrPutKey` etc). | |
| 7900 | /// This is used by incremental compilation when an existing container type is outdated. In | |
| 7901 | /// this case, the type must be recreated at a new `InternPool.Index`, but the old index must | |
| 7902 | /// remain valid since now-unreferenced `AnalUnit`s may retain references to it. The old index | |
| 7903 | /// will be cleaned up when the `Zcu` undergoes garbage collection. | |
| 7904 | fn putKeyReplace( | |
| 7905 | ip: *InternPool, | |
| 7906 | io: Io, | |
| 7907 | tid: Zcu.PerThread.Id, | |
| 7908 | key: Key, | |
| 7909 | ) GetOrPutKey { | |
| 7910 | const full_hash = key.hash64(ip); | |
| 7911 | const hash: u32 = @truncate(full_hash >> 32); | |
| 7912 | const shard = &ip.shards[@intCast(full_hash & (ip.shards.len - 1))]; | |
| 7913 | shard.mutate.map.mutex.lock(io, tid); | |
| 7914 | errdefer shard.mutate.map.mutex.unlock(io); | |
| 7915 | const map = shard.shared.map; | |
| 7916 | const map_mask = map.header().mask(); | |
| 7917 | var map_index = hash; | |
| 7918 | while (true) : (map_index += 1) { | |
| 7919 | map_index &= map_mask; | |
| 7920 | const entry = &map.entries[map_index]; | |
| 7921 | const index = entry.value; | |
| 7922 | assert(index != .none); // key not present | |
| 7923 | if (entry.hash == hash and ip.indexToKey(index).eql(key, ip)) { | |
| 7924 | break; // we found the entry to replace | |
| 7925 | } | |
| 7926 | } | |
| 7927 | return .{ .new = .{ | |
| 7928 | .ip = ip, | |
| 7929 | .tid = tid, | |
| 7930 | .io = io, | |
| 7931 | .shard = shard, | |
| 7932 | .map_index = map_index, | |
| 7933 | } }; | |
| 7934 | } | |
| 7935 | 7282 | |
| 7936 | 7283 | pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key: Key) Allocator.Error!Index { |
| 7937 | 7284 | var gop = try ip.getOrPutKey(gpa, io, tid, key); |
| ... | ... | @@ -8249,23 +7596,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key: |
| 8249 | 7596 | |
| 8250 | 7597 | .int => |int| b: { |
| 8251 | 7598 | assert(ip.isIntegerType(int.ty)); |
| 8252 | switch (int.storage) { | |
| 8253 | .u64, .i64, .big_int => {}, | |
| 8254 | .lazy_align, .lazy_size => |lazy_ty| { | |
| 8255 | items.appendAssumeCapacity(.{ | |
| 8256 | .tag = switch (int.storage) { | |
| 8257 | else => unreachable, | |
| 8258 | .lazy_align => .int_lazy_align, | |
| 8259 | .lazy_size => .int_lazy_size, | |
| 8260 | }, | |
| 8261 | .data = try addExtra(extra, IntLazy{ | |
| 8262 | .ty = int.ty, | |
| 8263 | .lazy_ty = lazy_ty, | |
| 8264 | }), | |
| 8265 | }); | |
| 8266 | return gop.put(); | |
| 8267 | }, | |
| 8268 | } | |
| 8269 | 7599 | switch (int.ty) { |
| 8270 | 7600 | .u8_type => switch (int.storage) { |
| 8271 | 7601 | .big_int => |big_int| { |
| ... | ... | @@ -8282,7 +7612,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key: |
| 8282 | 7612 | }); |
| 8283 | 7613 | break :b; |
| 8284 | 7614 | }, |
| 8285 | .lazy_align, .lazy_size => unreachable, | |
| 8286 | 7615 | }, |
| 8287 | 7616 | .u16_type => switch (int.storage) { |
| 8288 | 7617 | .big_int => |big_int| { |
| ... | ... | @@ -8299,7 +7628,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key: |
| 8299 | 7628 | }); |
| 8300 | 7629 | break :b; |
| 8301 | 7630 | }, |
| 8302 | .lazy_align, .lazy_size => unreachable, | |
| 8303 | 7631 | }, |
| 8304 | 7632 | .u32_type => switch (int.storage) { |
| 8305 | 7633 | .big_int => |big_int| { |
| ... | ... | @@ -8316,7 +7644,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key: |
| 8316 | 7644 | }); |
| 8317 | 7645 | break :b; |
| 8318 | 7646 | }, |
| 8319 | .lazy_align, .lazy_size => unreachable, | |
| 8320 | 7647 | }, |
| 8321 | 7648 | .i32_type => switch (int.storage) { |
| 8322 | 7649 | .big_int => |big_int| { |
| ... | ... | @@ -8334,7 +7661,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key: |
| 8334 | 7661 | }); |
| 8335 | 7662 | break :b; |
| 8336 | 7663 | }, |
| 8337 | .lazy_align, .lazy_size => unreachable, | |
| 8338 | 7664 | }, |
| 8339 | 7665 | .usize_type => switch (int.storage) { |
| 8340 | 7666 | .big_int => |big_int| { |
| ... | ... | @@ -8355,7 +7681,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key: |
| 8355 | 7681 | break :b; |
| 8356 | 7682 | } |
| 8357 | 7683 | }, |
| 8358 | .lazy_align, .lazy_size => unreachable, | |
| 8359 | 7684 | }, |
| 8360 | 7685 | .comptime_int_type => switch (int.storage) { |
| 8361 | 7686 | .big_int => |big_int| { |
| ... | ... | @@ -8390,7 +7715,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key: |
| 8390 | 7715 | break :b; |
| 8391 | 7716 | } |
| 8392 | 7717 | }, |
| 8393 | .lazy_align, .lazy_size => unreachable, | |
| 8394 | 7718 | }, |
| 8395 | 7719 | else => {}, |
| 8396 | 7720 | } |
| ... | ... | @@ -8427,7 +7751,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key: |
| 8427 | 7751 | const tag: Tag = if (big_int.positive) .int_positive else .int_negative; |
| 8428 | 7752 | try addInt(ip, gpa, io, tid, int.ty, tag, big_int.limbs); |
| 8429 | 7753 | }, |
| 8430 | .lazy_align, .lazy_size => unreachable, | |
| 8431 | 7754 | } |
| 8432 | 7755 | }, |
| 8433 | 7756 | |
| ... | ... | @@ -8468,7 +7791,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key: |
| 8468 | 7791 | assert(ip.isEnumType(enum_tag.ty)); |
| 8469 | 7792 | switch (ip.indexToKey(enum_tag.ty)) { |
| 8470 | 7793 | .simple_type => assert(ip.isIntegerType(ip.typeOf(enum_tag.int))), |
| 8471 | .enum_type => assert(ip.typeOf(enum_tag.int) == ip.loadEnumType(enum_tag.ty).tag_ty), | |
| 7794 | .enum_type => assert(ip.typeOf(enum_tag.int) == ip.loadEnumType(enum_tag.ty).int_tag_type), | |
| 8472 | 7795 | else => unreachable, |
| 8473 | 7796 | } |
| 8474 | 7797 | items.appendAssumeCapacity(.{ |
| ... | ... | @@ -8735,465 +8058,637 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key: |
| 8735 | 8058 | return gop.put(); |
| 8736 | 8059 | } |
| 8737 | 8060 | |
| 8738 | pub fn getUnion( | |
| 8739 | ip: *InternPool, | |
| 8740 | gpa: Allocator, | |
| 8741 | io: Io, | |
| 8742 | tid: Zcu.PerThread.Id, | |
| 8743 | un: Key.Union, | |
| 8744 | ) Allocator.Error!Index { | |
| 8745 | var gop = try ip.getOrPutKey(gpa, io, tid, .{ .un = un }); | |
| 8746 | defer gop.deinit(); | |
| 8747 | if (gop == .existing) return gop.existing; | |
| 8748 | const local = ip.getLocal(tid); | |
| 8749 | const items = local.getMutableItems(gpa, io); | |
| 8750 | const extra = local.getMutableExtra(gpa, io); | |
| 8751 | try items.ensureUnusedCapacity(1); | |
| 8752 | ||
| 8753 | assert(un.ty != .none); | |
| 8754 | assert(un.val != .none); | |
| 8755 | items.appendAssumeCapacity(.{ | |
| 8756 | .tag = .union_value, | |
| 8757 | .data = try addExtra(extra, un), | |
| 8758 | }); | |
| 8759 | ||
| 8760 | return gop.put(); | |
| 8761 | } | |
| 8762 | ||
| 8763 | pub const UnionTypeInit = struct { | |
| 8764 | flags: packed struct { | |
| 8765 | runtime_tag: LoadedUnionType.RuntimeTag, | |
| 8766 | any_aligned_fields: bool, | |
| 8767 | layout: std.builtin.Type.ContainerLayout, | |
| 8768 | status: LoadedUnionType.Status, | |
| 8769 | requires_comptime: RequiresComptime, | |
| 8770 | assumed_runtime_bits: bool, | |
| 8771 | assumed_pointer_aligned: bool, | |
| 8772 | alignment: Alignment, | |
| 8773 | }, | |
| 8061 | pub fn getStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, ini: struct { | |
| 8774 | 8062 | fields_len: u32, |
| 8775 | enum_tag_ty: Index, | |
| 8776 | /// May have length 0 which leaves the values unset until later. | |
| 8777 | field_types: []const Index, | |
| 8778 | /// May have length 0 which leaves the values unset until later. | |
| 8779 | /// The logic for `any_aligned_fields` is asserted to have been done before | |
| 8780 | /// calling this function. | |
| 8781 | field_aligns: []const Alignment, | |
| 8063 | layout: std.builtin.Type.ContainerLayout, | |
| 8064 | /// The following only applies if `layout == .@"packed"`; this field is ignored otherwise. | |
| 8065 | /// | |
| 8066 | /// The explicitly specified backing integer type. `.none` means the backing integer is inferred | |
| 8067 | /// by the compiler. Asserts that this is an integer type. | |
| 8068 | explicit_packed_backing_type: Index, | |
| 8069 | any_comptime_fields: bool, | |
| 8070 | any_field_defaults: bool, | |
| 8071 | any_field_aligns: bool, | |
| 8782 | 8072 | key: union(enum) { |
| 8783 | 8073 | declared: struct { |
| 8784 | 8074 | zir_index: TrackedInst.Index, |
| 8785 | 8075 | captures: []const CaptureValue, |
| 8786 | 8076 | }, |
| 8787 | declared_owned_captures: struct { | |
| 8788 | zir_index: TrackedInst.Index, | |
| 8789 | captures: CaptureValue.Slice, | |
| 8790 | }, | |
| 8791 | 8077 | reified: struct { |
| 8792 | 8078 | zir_index: TrackedInst.Index, |
| 8793 | 8079 | type_hash: u64, |
| 8794 | 8080 | }, |
| 8795 | 8081 | }, |
| 8796 | }; | |
| 8797 | ||
| 8798 | pub fn getUnionType( | |
| 8799 | ip: *InternPool, | |
| 8800 | gpa: Allocator, | |
| 8801 | io: Io, | |
| 8802 | tid: Zcu.PerThread.Id, | |
| 8803 | ini: UnionTypeInit, | |
| 8804 | /// If it is known that there is an existing type with this key which is outdated, | |
| 8805 | /// this is passed as `true`, and the type is replaced with one at a fresh index. | |
| 8806 | replace_existing: bool, | |
| 8807 | ) Allocator.Error!WipNamespaceType.Result { | |
| 8808 | const key: Key = .{ .union_type = switch (ini.key) { | |
| 8082 | }) Allocator.Error!WipContainerType.Result { | |
| 8083 | const key: Key = .{ .struct_type = switch (ini.key) { | |
| 8809 | 8084 | .declared => |d| .{ .declared = .{ |
| 8810 | 8085 | .zir_index = d.zir_index, |
| 8086 | .arg_ty = switch (ini.layout) { | |
| 8087 | .auto, .@"extern" => .none, | |
| 8088 | .@"packed" => ini.explicit_packed_backing_type, | |
| 8089 | }, | |
| 8811 | 8090 | .captures = .{ .external = d.captures }, |
| 8812 | 8091 | } }, |
| 8813 | .declared_owned_captures => |d| .{ .declared = .{ | |
| 8814 | .zir_index = d.zir_index, | |
| 8815 | .captures = .{ .owned = d.captures }, | |
| 8816 | } }, | |
| 8817 | 8092 | .reified => |r| .{ .reified = .{ |
| 8818 | 8093 | .zir_index = r.zir_index, |
| 8819 | 8094 | .type_hash = r.type_hash, |
| 8820 | 8095 | } }, |
| 8821 | 8096 | } }; |
| 8822 | var gop = if (replace_existing) | |
| 8823 | ip.putKeyReplace(io, tid, key) | |
| 8824 | else | |
| 8825 | try ip.getOrPutKey(gpa, io, tid, key); | |
| 8097 | var gop = try ip.getOrPutKey(gpa, io, tid, key); | |
| 8826 | 8098 | defer gop.deinit(); |
| 8827 | 8099 | if (gop == .existing) return .{ .existing = gop.existing }; |
| 8828 | 8100 | |
| 8829 | 8101 | const local = ip.getLocal(tid); |
| 8830 | 8102 | const items = local.getMutableItems(gpa, io); |
| 8831 | try items.ensureUnusedCapacity(1); | |
| 8832 | 8103 | const extra = local.getMutableExtra(gpa, io); |
| 8104 | try items.ensureUnusedCapacity(1); | |
| 8833 | 8105 | |
| 8834 | const align_elements_len = if (ini.flags.any_aligned_fields) (ini.fields_len + 3) / 4 else 0; | |
| 8835 | const align_element: u32 = @bitCast([1]u8{@intFromEnum(Alignment.none)} ** 4); | |
| 8836 | try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeUnion).@"struct".fields.len + | |
| 8837 | // TODO: fmt bug | |
| 8838 | // zig fmt: off | |
| 8839 | switch (ini.key) { | |
| 8840 | inline .declared, .declared_owned_captures => |d| @intFromBool(d.captures.len != 0) + d.captures.len, | |
| 8841 | .reified => 2, // type_hash: PackedU64 | |
| 8842 | } + | |
| 8843 | // zig fmt: on | |
| 8844 | ini.fields_len + // field types | |
| 8845 | align_elements_len); | |
| 8106 | const field_name_map = try ip.addMap(gpa, io, tid, ini.fields_len); | |
| 8107 | errdefer local.mutate.maps.len -= 1; | |
| 8846 | 8108 | |
| 8847 | const extra_index = addExtraAssumeCapacity(extra, Tag.TypeUnion{ | |
| 8848 | .flags = .{ | |
| 8849 | .any_captures = switch (ini.key) { | |
| 8850 | inline .declared, .declared_owned_captures => |d| d.captures.len != 0, | |
| 8851 | .reified => false, | |
| 8852 | }, | |
| 8853 | .runtime_tag = ini.flags.runtime_tag, | |
| 8854 | .any_aligned_fields = ini.flags.any_aligned_fields, | |
| 8855 | .layout = ini.flags.layout, | |
| 8856 | .status = ini.flags.status, | |
| 8857 | .requires_comptime = ini.flags.requires_comptime, | |
| 8858 | .assumed_runtime_bits = ini.flags.assumed_runtime_bits, | |
| 8859 | .assumed_pointer_aligned = ini.flags.assumed_pointer_aligned, | |
| 8860 | .alignment = ini.flags.alignment, | |
| 8861 | .is_reified = switch (ini.key) { | |
| 8862 | .declared, .declared_owned_captures => false, | |
| 8863 | .reified => true, | |
| 8864 | }, | |
| 8109 | const zir_index, const type_hash_captures_extra_len = switch (ini.key) { | |
| 8110 | .declared => |d| .{ d.zir_index, d.captures.len + @intFromBool(ini.layout != .@"packed") }, | |
| 8111 | .reified => |r| .{ r.zir_index, 2 }, | |
| 8112 | }; | |
| 8113 | ||
| 8114 | const is_extern = switch (ini.layout) { | |
| 8115 | .auto => false, | |
| 8116 | .@"extern" => true, | |
| 8117 | .@"packed" => { | |
| 8118 | try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeStructPacked).@"struct".fields.len + | |
| 8119 | type_hash_captures_extra_len + | |
| 8120 | ini.fields_len + // field_name | |
| 8121 | ini.fields_len + // field_type | |
| 8122 | (if (ini.any_field_defaults) ini.fields_len else 0)); // field_default | |
| 8123 | ||
| 8124 | const extra_index = addExtraAssumeCapacity(extra, Tag.TypeStructPacked{ | |
| 8125 | .zir_index = zir_index, | |
| 8126 | .captures_len = switch (ini.key) { | |
| 8127 | .declared => |d| @enumFromInt(d.captures.len), | |
| 8128 | .reified => .reified, | |
| 8129 | }, | |
| 8130 | .name = undefined, // set by `finish` | |
| 8131 | .name_nav = undefined, // set by `finish` | |
| 8132 | .namespace = undefined, // set by `finish` | |
| 8133 | .backing_int_type = ini.explicit_packed_backing_type, | |
| 8134 | .fields_len = ini.fields_len, | |
| 8135 | .field_name_map = field_name_map, | |
| 8136 | }); | |
| 8137 | switch (ini.key) { | |
| 8138 | .declared => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}), | |
| 8139 | .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)), | |
| 8140 | } | |
| 8141 | const field_names_start = extra.mutate.len; | |
| 8142 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // field_name | |
| 8143 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_type | |
| 8144 | if (ini.any_field_defaults) { | |
| 8145 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_default | |
| 8146 | } | |
| 8147 | items.appendAssumeCapacity(.{ | |
| 8148 | .tag = switch (ini.explicit_packed_backing_type) { | |
| 8149 | .none => if (ini.any_field_defaults) .type_struct_packed_auto_defaults else .type_struct_packed_auto, | |
| 8150 | else => if (ini.any_field_defaults) .type_struct_packed_explicit_defaults else .type_struct_packed_explicit, | |
| 8151 | }, | |
| 8152 | .data = extra_index, | |
| 8153 | }); | |
| 8154 | return .{ .wip = .{ | |
| 8155 | .index = gop.put(), | |
| 8156 | .tid = tid, | |
| 8157 | .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "name").?, | |
| 8158 | .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "name_nav").?, | |
| 8159 | .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "namespace").?, | |
| 8160 | .tag_type_index = null, | |
| 8161 | .fields_len = ini.fields_len, | |
| 8162 | .field_name_map = field_name_map, | |
| 8163 | .field_names_start = field_names_start, | |
| 8164 | .field_comptime_bits_start = null, | |
| 8165 | } }; | |
| 8865 | 8166 | }, |
| 8866 | .fields_len = ini.fields_len, | |
| 8867 | .size = std.math.maxInt(u32), | |
| 8868 | .padding = std.math.maxInt(u32), | |
| 8167 | }; | |
| 8168 | ||
| 8169 | try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeStruct).@"struct".fields.len + | |
| 8170 | type_hash_captures_extra_len + | |
| 8171 | ini.fields_len + // field_name | |
| 8172 | ini.fields_len + // field_type | |
| 8173 | (if (ini.any_field_defaults) ini.fields_len else 0) + // field_default | |
| 8174 | (if (ini.any_field_aligns) (ini.fields_len + 3) / 4 else 0) + // field_align | |
| 8175 | (if (ini.any_comptime_fields) (ini.fields_len + 31) / 32 else 0) + // field_is_comptime_bits | |
| 8176 | (if (!is_extern) ini.fields_len else 0) + // field_runtime_order | |
| 8177 | ini.fields_len); // field_offset | |
| 8178 | ||
| 8179 | const extra_index = addExtraAssumeCapacity(extra, Tag.TypeStruct{ | |
| 8180 | .zir_index = zir_index, | |
| 8869 | 8181 | .name = undefined, // set by `finish` |
| 8870 | 8182 | .name_nav = undefined, // set by `finish` |
| 8871 | 8183 | .namespace = undefined, // set by `finish` |
| 8872 | .tag_ty = ini.enum_tag_ty, | |
| 8873 | .zir_index = switch (ini.key) { | |
| 8874 | inline else => |x| x.zir_index, | |
| 8184 | .fields_len = ini.fields_len, | |
| 8185 | .field_name_map = field_name_map, | |
| 8186 | .size = 0, | |
| 8187 | .flags = .{ | |
| 8188 | .any_captures = switch (ini.key) { | |
| 8189 | .declared => |d| if (d.captures.len != 0) .true else .false, | |
| 8190 | .reified => .reified, | |
| 8191 | }, | |
| 8192 | .layout = if (is_extern) .@"extern" else .auto, | |
| 8193 | .any_comptime_fields = ini.any_comptime_fields, | |
| 8194 | .any_field_defaults = ini.any_field_defaults, | |
| 8195 | .any_field_aligns = ini.any_field_aligns, | |
| 8196 | .has_one_possible_value = false, | |
| 8197 | .has_no_possible_value = false, | |
| 8198 | .comptime_only = false, | |
| 8199 | .alignment = .none, | |
| 8875 | 8200 | }, |
| 8876 | 8201 | }); |
| 8877 | ||
| 8878 | items.appendAssumeCapacity(.{ | |
| 8879 | .tag = .type_union, | |
| 8880 | .data = extra_index, | |
| 8881 | }); | |
| 8882 | ||
| 8883 | 8202 | switch (ini.key) { |
| 8884 | 8203 | .declared => |d| if (d.captures.len != 0) { |
| 8885 | 8204 | extra.appendAssumeCapacity(.{@intCast(d.captures.len)}); |
| 8886 | 8205 | extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}); |
| 8887 | 8206 | }, |
| 8888 | .declared_owned_captures => |d| if (d.captures.len != 0) { | |
| 8889 | extra.appendAssumeCapacity(.{@intCast(d.captures.len)}); | |
| 8890 | extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures.get(ip))}); | |
| 8891 | }, | |
| 8892 | 8207 | .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)), |
| 8893 | 8208 | } |
| 8894 | ||
| 8895 | // field types | |
| 8896 | if (ini.field_types.len > 0) { | |
| 8897 | assert(ini.field_types.len == ini.fields_len); | |
| 8898 | extra.appendSliceAssumeCapacity(.{@ptrCast(ini.field_types)}); | |
| 8899 | } else { | |
| 8900 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); | |
| 8209 | const field_names_start = extra.mutate.len; | |
| 8210 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // field_name | |
| 8211 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_type | |
| 8212 | if (ini.any_field_defaults) { | |
| 8213 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_default | |
| 8901 | 8214 | } |
| 8902 | ||
| 8903 | // field alignments | |
| 8904 | if (ini.flags.any_aligned_fields) { | |
| 8905 | extra.appendNTimesAssumeCapacity(.{align_element}, align_elements_len); | |
| 8906 | if (ini.field_aligns.len > 0) { | |
| 8907 | assert(ini.field_aligns.len == ini.fields_len); | |
| 8908 | @memcpy((Alignment.Slice{ | |
| 8909 | .tid = tid, | |
| 8910 | .start = @intCast(extra.mutate.len - align_elements_len), | |
| 8911 | .len = @intCast(ini.field_aligns.len), | |
| 8912 | }).get(ip), ini.field_aligns); | |
| 8913 | } | |
| 8914 | } else { | |
| 8915 | assert(ini.field_aligns.len == 0); | |
| 8215 | if (ini.any_field_aligns) { | |
| 8216 | extra.appendNTimesAssumeCapacity(.{0}, (ini.fields_len + 3) / 4); // field_align | |
| 8916 | 8217 | } |
| 8917 | ||
| 8218 | const field_comptime_bits_start: ?u32 = if (ini.any_comptime_fields) start: { | |
| 8219 | const start = extra.mutate.len; | |
| 8220 | extra.appendNTimesAssumeCapacity(.{0}, (ini.fields_len + 31) / 32); // field_is_comptime_bits | |
| 8221 | break :start start; | |
| 8222 | } else null; | |
| 8223 | if (!is_extern) { | |
| 8224 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(LoadedStructType.RuntimeOrder.unresolved)}, ini.fields_len); // field_runtime_order | |
| 8225 | } | |
| 8226 | extra.appendNTimesAssumeCapacity(.{0}, ini.fields_len); // field_offset | |
| 8227 | items.appendAssumeCapacity(.{ | |
| 8228 | .tag = .type_struct, | |
| 8229 | .data = extra_index, | |
| 8230 | }); | |
| 8918 | 8231 | return .{ .wip = .{ |
| 8919 | .tid = tid, | |
| 8920 | 8232 | .index = gop.put(), |
| 8921 | .type_name_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name").?, | |
| 8922 | .name_nav_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name_nav").?, | |
| 8923 | .namespace_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "namespace").?, | |
| 8233 | .tid = tid, | |
| 8234 | .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "name").?, | |
| 8235 | .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "name_nav").?, | |
| 8236 | .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "namespace").?, | |
| 8237 | .tag_type_index = null, | |
| 8238 | .fields_len = ini.fields_len, | |
| 8239 | .field_name_map = field_name_map, | |
| 8240 | .field_names_start = field_names_start, | |
| 8241 | .field_comptime_bits_start = field_comptime_bits_start, | |
| 8924 | 8242 | } }; |
| 8925 | 8243 | } |
| 8926 | 8244 | |
| 8927 | pub const WipNamespaceType = struct { | |
| 8928 | tid: Zcu.PerThread.Id, | |
| 8929 | index: Index, | |
| 8930 | type_name_extra_index: u32, | |
| 8931 | namespace_extra_index: u32, | |
| 8932 | name_nav_extra_index: u32, | |
| 8933 | ||
| 8934 | pub fn setName( | |
| 8935 | wip: WipNamespaceType, | |
| 8936 | ip: *InternPool, | |
| 8937 | type_name: NullTerminatedString, | |
| 8938 | /// This should be the `Nav` we are named after if we use the `.parent` name strategy; `.none` otherwise. | |
| 8939 | /// This is also `.none` if we use `.parent` because we are the root struct type for a file. | |
| 8940 | name_nav: Nav.Index.Optional, | |
| 8941 | ) void { | |
| 8942 | const extra = ip.getLocalShared(wip.tid).extra.acquire(); | |
| 8943 | const extra_items = extra.view().items(.@"0"); | |
| 8944 | extra_items[wip.type_name_extra_index] = @intFromEnum(type_name); | |
| 8945 | extra_items[wip.name_nav_extra_index] = @intFromEnum(name_nav); | |
| 8946 | } | |
| 8947 | ||
| 8948 | pub fn finish( | |
| 8949 | wip: WipNamespaceType, | |
| 8950 | ip: *InternPool, | |
| 8951 | namespace: NamespaceIndex, | |
| 8952 | ) Index { | |
| 8953 | const extra = ip.getLocalShared(wip.tid).extra.acquire(); | |
| 8954 | const extra_items = extra.view().items(.@"0"); | |
| 8955 | ||
| 8956 | extra_items[wip.namespace_extra_index] = @intFromEnum(namespace); | |
| 8957 | ||
| 8958 | return wip.index; | |
| 8959 | } | |
| 8960 | ||
| 8961 | pub fn cancel(wip: WipNamespaceType, ip: *InternPool, tid: Zcu.PerThread.Id) void { | |
| 8962 | ip.remove(tid, wip.index); | |
| 8963 | } | |
| 8964 | ||
| 8965 | pub const Result = union(enum) { | |
| 8966 | wip: WipNamespaceType, | |
| 8967 | existing: Index, | |
| 8968 | }; | |
| 8969 | }; | |
| 8970 | ||
| 8971 | pub const StructTypeInit = struct { | |
| 8972 | layout: std.builtin.Type.ContainerLayout, | |
| 8245 | pub fn getUnionType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, ini: struct { | |
| 8973 | 8246 | fields_len: u32, |
| 8974 | known_non_opv: bool, | |
| 8975 | requires_comptime: RequiresComptime, | |
| 8976 | any_comptime_fields: bool, | |
| 8977 | any_default_inits: bool, | |
| 8978 | inits_resolved: bool, | |
| 8979 | any_aligned_fields: bool, | |
| 8247 | layout: std.builtin.Type.ContainerLayout, | |
| 8248 | /// The explicitly specified backing integer type for a `packed union`. | |
| 8249 | /// `.none` means the backing integer is inferred by the compiler. If set, | |
| 8250 | /// must be an integer type. If the union is not packed, must be `.none`. | |
| 8251 | explicit_packed_backing_type: Index, | |
| 8252 | runtime_tag: LoadedUnionType.RuntimeTag, | |
| 8253 | /// `true` for `union(T)`, but `false` for anything else, including `union(enum(T))`. | |
| 8254 | have_explicit_enum_tag: bool, | |
| 8255 | any_field_aligns: bool, | |
| 8980 | 8256 | key: union(enum) { |
| 8981 | 8257 | declared: struct { |
| 8982 | 8258 | zir_index: TrackedInst.Index, |
| 8983 | 8259 | captures: []const CaptureValue, |
| 8984 | }, | |
| 8985 | declared_owned_captures: struct { | |
| 8986 | zir_index: TrackedInst.Index, | |
| 8987 | captures: CaptureValue.Slice, | |
| 8260 | /// This is the `T` in one of the following: | |
| 8261 | /// * `union(T)` (enum tag type) | |
| 8262 | /// * `union(enum(T))` (int tag type) | |
| 8263 | /// * `packed union(T)` (int backing type) | |
| 8264 | /// Or `.none` otherwise. | |
| 8265 | arg_ty: InternPool.Index, | |
| 8988 | 8266 | }, |
| 8989 | 8267 | reified: struct { |
| 8990 | 8268 | zir_index: TrackedInst.Index, |
| 8991 | 8269 | type_hash: u64, |
| 8992 | 8270 | }, |
| 8993 | 8271 | }, |
| 8994 | }; | |
| 8995 | ||
| 8996 | pub fn getStructType( | |
| 8997 | ip: *InternPool, | |
| 8998 | gpa: Allocator, | |
| 8999 | io: Io, | |
| 9000 | tid: Zcu.PerThread.Id, | |
| 9001 | ini: StructTypeInit, | |
| 9002 | /// If it is known that there is an existing type with this key which is outdated, | |
| 9003 | /// this is passed as `true`, and the type is replaced with one at a fresh index. | |
| 9004 | replace_existing: bool, | |
| 9005 | ) Allocator.Error!WipNamespaceType.Result { | |
| 9006 | const key: Key = .{ .struct_type = switch (ini.key) { | |
| 8272 | }) Allocator.Error!WipContainerType.Result { | |
| 8273 | if (ini.explicit_packed_backing_type != .none) { | |
| 8274 | assert(ip.zigTypeTag(ini.explicit_packed_backing_type) == .int); | |
| 8275 | if (ini.key == .declared) assert(ini.key.declared.arg_ty == ini.explicit_packed_backing_type); | |
| 8276 | } | |
| 8277 | const key: Key = .{ .union_type = switch (ini.key) { | |
| 9007 | 8278 | .declared => |d| .{ .declared = .{ |
| 9008 | 8279 | .zir_index = d.zir_index, |
| 8280 | .arg_ty = d.arg_ty, | |
| 9009 | 8281 | .captures = .{ .external = d.captures }, |
| 9010 | 8282 | } }, |
| 9011 | .declared_owned_captures => |d| .{ .declared = .{ | |
| 9012 | .zir_index = d.zir_index, | |
| 9013 | .captures = .{ .owned = d.captures }, | |
| 9014 | } }, | |
| 9015 | 8283 | .reified => |r| .{ .reified = .{ |
| 9016 | 8284 | .zir_index = r.zir_index, |
| 9017 | 8285 | .type_hash = r.type_hash, |
| 9018 | 8286 | } }, |
| 9019 | 8287 | } }; |
| 9020 | var gop = if (replace_existing) | |
| 9021 | ip.putKeyReplace(io, tid, key) | |
| 9022 | else | |
| 9023 | try ip.getOrPutKey(gpa, io, tid, key); | |
| 8288 | var gop = try ip.getOrPutKey(gpa, io, tid, key); | |
| 9024 | 8289 | defer gop.deinit(); |
| 9025 | 8290 | if (gop == .existing) return .{ .existing = gop.existing }; |
| 9026 | 8291 | |
| 9027 | 8292 | const local = ip.getLocal(tid); |
| 9028 | 8293 | const items = local.getMutableItems(gpa, io); |
| 9029 | 8294 | const extra = local.getMutableExtra(gpa, io); |
| 8295 | try items.ensureUnusedCapacity(1); | |
| 9030 | 8296 | |
| 9031 | const names_map = try ip.addMap(gpa, io, tid, ini.fields_len); | |
| 9032 | errdefer local.mutate.maps.len -= 1; | |
| 9033 | ||
| 9034 | const zir_index = switch (ini.key) { | |
| 9035 | inline else => |x| x.zir_index, | |
| 8297 | const zir_index, const type_hash_captures_extra_len = switch (ini.key) { | |
| 8298 | .declared => |d| .{ d.zir_index, d.captures.len + @intFromBool(ini.layout != .@"packed") }, | |
| 8299 | .reified => |r| .{ r.zir_index, 2 }, | |
| 9036 | 8300 | }; |
| 9037 | 8301 | |
| 9038 | 8302 | const is_extern = switch (ini.layout) { |
| 9039 | 8303 | .auto => false, |
| 9040 | 8304 | .@"extern" => true, |
| 9041 | 8305 | .@"packed" => { |
| 9042 | try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeStructPacked).@"struct".fields.len + | |
| 9043 | // TODO: fmt bug | |
| 9044 | // zig fmt: off | |
| 9045 | switch (ini.key) { | |
| 9046 | inline .declared, .declared_owned_captures => |d| @intFromBool(d.captures.len != 0) + d.captures.len, | |
| 9047 | .reified => 2, // type_hash: PackedU64 | |
| 9048 | } + | |
| 9049 | // zig fmt: on | |
| 9050 | ini.fields_len + // types | |
| 9051 | ini.fields_len + // names | |
| 9052 | ini.fields_len); // inits | |
| 9053 | const extra_index = addExtraAssumeCapacity(extra, Tag.TypeStructPacked{ | |
| 8306 | try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeUnionPacked).@"struct".fields.len + | |
| 8307 | type_hash_captures_extra_len + | |
| 8308 | ini.fields_len); // field_type | |
| 8309 | ||
| 8310 | const extra_index = addExtraAssumeCapacity(extra, Tag.TypeUnionPacked{ | |
| 8311 | .zir_index = zir_index, | |
| 8312 | .captures_len = switch (ini.key) { | |
| 8313 | .declared => |d| @enumFromInt(d.captures.len), | |
| 8314 | .reified => .reified, | |
| 8315 | }, | |
| 9054 | 8316 | .name = undefined, // set by `finish` |
| 9055 | 8317 | .name_nav = undefined, // set by `finish` |
| 9056 | .zir_index = zir_index, | |
| 9057 | .fields_len = ini.fields_len, | |
| 9058 | 8318 | .namespace = undefined, // set by `finish` |
| 9059 | .backing_int_ty = .none, | |
| 9060 | .names_map = names_map, | |
| 9061 | .flags = .{ | |
| 9062 | .any_captures = switch (ini.key) { | |
| 9063 | inline .declared, .declared_owned_captures => |d| d.captures.len != 0, | |
| 9064 | .reified => false, | |
| 9065 | }, | |
| 9066 | .field_inits_wip = false, | |
| 9067 | .inits_resolved = ini.inits_resolved, | |
| 9068 | .is_reified = switch (ini.key) { | |
| 9069 | .declared, .declared_owned_captures => false, | |
| 9070 | .reified => true, | |
| 9071 | }, | |
| 9072 | }, | |
| 9073 | }); | |
| 9074 | try items.append(.{ | |
| 9075 | .tag = if (ini.any_default_inits) .type_struct_packed_inits else .type_struct_packed, | |
| 9076 | .data = extra_index, | |
| 8319 | .backing_int_type = ini.explicit_packed_backing_type, | |
| 8320 | .enum_tag_type = .none, // set by `setTagType` | |
| 8321 | .fields_len = ini.fields_len, | |
| 9077 | 8322 | }); |
| 9078 | 8323 | switch (ini.key) { |
| 9079 | .declared => |d| if (d.captures.len != 0) { | |
| 9080 | extra.appendAssumeCapacity(.{@intCast(d.captures.len)}); | |
| 9081 | extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}); | |
| 9082 | }, | |
| 9083 | .declared_owned_captures => |d| if (d.captures.len != 0) { | |
| 9084 | extra.appendAssumeCapacity(.{@intCast(d.captures.len)}); | |
| 9085 | extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures.get(ip))}); | |
| 8324 | .declared => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}), | |
| 8325 | .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)), | |
| 8326 | } | |
| 8327 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_type | |
| 8328 | items.appendAssumeCapacity(.{ | |
| 8329 | .tag = switch (ini.explicit_packed_backing_type) { | |
| 8330 | .none => .type_union_packed_auto, | |
| 8331 | else => .type_union_packed_explicit, | |
| 9086 | 8332 | }, |
| 9087 | .reified => |r| { | |
| 9088 | _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)); | |
| 8333 | .data = extra_index, | |
| 8334 | }); | |
| 8335 | return .{ | |
| 8336 | .wip = .{ | |
| 8337 | .index = gop.put(), | |
| 8338 | .tid = tid, | |
| 8339 | .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "name").?, | |
| 8340 | .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "name_nav").?, | |
| 8341 | .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "namespace").?, | |
| 8342 | .tag_type_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "enum_tag_type").?, | |
| 8343 | .fields_len = 0, // the fields come from the enum, so nothing to set | |
| 8344 | .field_name_map = undefined, | |
| 8345 | .field_names_start = undefined, | |
| 8346 | .field_comptime_bits_start = undefined, | |
| 9089 | 8347 | }, |
| 9090 | } | |
| 9091 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); | |
| 9092 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(OptionalNullTerminatedString.none)}, ini.fields_len); | |
| 9093 | if (ini.any_default_inits) { | |
| 9094 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); | |
| 9095 | } | |
| 9096 | return .{ .wip = .{ | |
| 9097 | .tid = tid, | |
| 9098 | .index = gop.put(), | |
| 9099 | .type_name_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "name").?, | |
| 9100 | .name_nav_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "name_nav").?, | |
| 9101 | .namespace_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "namespace").?, | |
| 9102 | } }; | |
| 8348 | }; | |
| 9103 | 8349 | }, |
| 9104 | 8350 | }; |
| 9105 | 8351 | |
| 9106 | const align_elements_len = if (ini.any_aligned_fields) (ini.fields_len + 3) / 4 else 0; | |
| 9107 | const align_element: u32 = @bitCast([1]u8{@intFromEnum(Alignment.none)} ** 4); | |
| 9108 | const comptime_elements_len = if (ini.any_comptime_fields) (ini.fields_len + 31) / 32 else 0; | |
| 8352 | try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeUnion).@"struct".fields.len + | |
| 8353 | type_hash_captures_extra_len + | |
| 8354 | ini.fields_len + // field_type | |
| 8355 | (if (ini.any_field_aligns) (ini.fields_len + 3) / 4 else 0)); // field_align | |
| 9109 | 8356 | |
| 9110 | try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeStruct).@"struct".fields.len + | |
| 9111 | // TODO: fmt bug | |
| 9112 | // zig fmt: off | |
| 9113 | switch (ini.key) { | |
| 9114 | inline .declared, .declared_owned_captures => |d| @intFromBool(d.captures.len != 0) + d.captures.len, | |
| 9115 | .reified => 2, // type_hash: PackedU64 | |
| 9116 | } + | |
| 9117 | // zig fmt: on | |
| 9118 | (ini.fields_len * 5) + // types, names, inits, runtime order, offsets | |
| 9119 | align_elements_len + comptime_elements_len + | |
| 9120 | 1); // names_map | |
| 9121 | const extra_index = addExtraAssumeCapacity(extra, Tag.TypeStruct{ | |
| 8357 | const extra_index = addExtraAssumeCapacity(extra, Tag.TypeUnion{ | |
| 8358 | .zir_index = zir_index, | |
| 9122 | 8359 | .name = undefined, // set by `finish` |
| 9123 | 8360 | .name_nav = undefined, // set by `finish` |
| 9124 | .zir_index = zir_index, | |
| 9125 | 8361 | .namespace = undefined, // set by `finish` |
| 8362 | .enum_tag_type = .none, // set by `setTagType` | |
| 9126 | 8363 | .fields_len = ini.fields_len, |
| 9127 | .size = std.math.maxInt(u32), | |
| 8364 | .size = 0, | |
| 8365 | .padding = 0, | |
| 9128 | 8366 | .flags = .{ |
| 9129 | 8367 | .any_captures = switch (ini.key) { |
| 9130 | inline .declared, .declared_owned_captures => |d| d.captures.len != 0, | |
| 9131 | .reified => false, | |
| 8368 | .declared => |d| if (d.captures.len != 0) .true else .false, | |
| 8369 | .reified => .reified, | |
| 9132 | 8370 | }, |
| 9133 | .is_extern = is_extern, | |
| 9134 | .known_non_opv = ini.known_non_opv, | |
| 9135 | .requires_comptime = ini.requires_comptime, | |
| 9136 | .assumed_runtime_bits = false, | |
| 9137 | .assumed_pointer_aligned = false, | |
| 9138 | .any_comptime_fields = ini.any_comptime_fields, | |
| 9139 | .any_default_inits = ini.any_default_inits, | |
| 9140 | .any_aligned_fields = ini.any_aligned_fields, | |
| 8371 | .explicit_tag_type = ini.have_explicit_enum_tag, | |
| 8372 | .layout = if (is_extern) .@"extern" else .auto, | |
| 8373 | .any_field_aligns = ini.any_field_aligns, | |
| 8374 | .runtime_tag = ini.runtime_tag, | |
| 8375 | .has_one_possible_value = false, | |
| 8376 | .has_no_possible_value = false, | |
| 8377 | .comptime_only = false, | |
| 9141 | 8378 | .alignment = .none, |
| 9142 | .alignment_wip = false, | |
| 9143 | .field_types_wip = false, | |
| 9144 | .layout_wip = false, | |
| 9145 | .layout_resolved = false, | |
| 9146 | .field_inits_wip = false, | |
| 9147 | .inits_resolved = ini.inits_resolved, | |
| 9148 | .fully_resolved = false, | |
| 9149 | .is_reified = switch (ini.key) { | |
| 9150 | .declared, .declared_owned_captures => false, | |
| 9151 | .reified => true, | |
| 9152 | }, | |
| 9153 | 8379 | }, |
| 9154 | 8380 | }); |
| 9155 | try items.append(.{ | |
| 9156 | .tag = .type_struct, | |
| 9157 | .data = extra_index, | |
| 9158 | }); | |
| 9159 | 8381 | switch (ini.key) { |
| 9160 | 8382 | .declared => |d| if (d.captures.len != 0) { |
| 9161 | 8383 | extra.appendAssumeCapacity(.{@intCast(d.captures.len)}); |
| 9162 | 8384 | extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}); |
| 9163 | 8385 | }, |
| 9164 | .declared_owned_captures => |d| if (d.captures.len != 0) { | |
| 9165 | extra.appendAssumeCapacity(.{@intCast(d.captures.len)}); | |
| 9166 | extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures.get(ip))}); | |
| 9167 | }, | |
| 9168 | .reified => |r| { | |
| 9169 | _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)); | |
| 9170 | }, | |
| 9171 | } | |
| 9172 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); | |
| 9173 | extra.appendAssumeCapacity(.{@intFromEnum(names_map)}); | |
| 9174 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(OptionalNullTerminatedString.none)}, ini.fields_len); | |
| 9175 | if (ini.any_default_inits) { | |
| 9176 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); | |
| 8386 | .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)), | |
| 9177 | 8387 | } |
| 9178 | if (ini.any_aligned_fields) { | |
| 9179 | extra.appendNTimesAssumeCapacity(.{align_element}, align_elements_len); | |
| 8388 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_type | |
| 8389 | if (ini.any_field_aligns) { | |
| 8390 | extra.appendNTimesAssumeCapacity(.{0}, (ini.fields_len + 3) / 4); // field_align | |
| 9180 | 8391 | } |
| 9181 | if (ini.any_comptime_fields) { | |
| 9182 | extra.appendNTimesAssumeCapacity(.{0}, comptime_elements_len); | |
| 9183 | } | |
| 9184 | if (ini.layout == .auto) { | |
| 9185 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(LoadedStructType.RuntimeOrder.unresolved)}, ini.fields_len); | |
| 8392 | items.appendAssumeCapacity(.{ | |
| 8393 | .tag = .type_union, | |
| 8394 | .data = extra_index, | |
| 8395 | }); | |
| 8396 | return .{ | |
| 8397 | .wip = .{ | |
| 8398 | .index = gop.put(), | |
| 8399 | .tid = tid, | |
| 8400 | .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name").?, | |
| 8401 | .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name_nav").?, | |
| 8402 | .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "namespace").?, | |
| 8403 | .tag_type_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "enum_tag_type").?, | |
| 8404 | .fields_len = 0, // the fields come from the enum, so nothing to set | |
| 8405 | .field_name_map = undefined, | |
| 8406 | .field_names_start = undefined, | |
| 8407 | .field_comptime_bits_start = undefined, | |
| 8408 | }, | |
| 8409 | }; | |
| 8410 | } | |
| 8411 | ||
| 8412 | pub fn getEnumType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, ini: struct { | |
| 8413 | fields_len: u32, | |
| 8414 | /// For `enum(T)` or `union(enum(T))`, this is `T`. Asserts `T` is an integer type. | |
| 8415 | /// Otherwise, `.none`. | |
| 8416 | explicit_int_tag_type: Index, | |
| 8417 | nonexhaustive: bool, | |
| 8418 | key: union(enum) { | |
| 8419 | declared: struct { | |
| 8420 | zir_index: TrackedInst.Index, | |
| 8421 | captures: []const CaptureValue, | |
| 8422 | }, | |
| 8423 | reified: struct { | |
| 8424 | zir_index: TrackedInst.Index, | |
| 8425 | type_hash: u64, | |
| 8426 | }, | |
| 8427 | generated_union_tag: Index, | |
| 8428 | }, | |
| 8429 | }) Allocator.Error!WipContainerType.Result { | |
| 8430 | const key: Key = .{ .enum_type = switch (ini.key) { | |
| 8431 | .declared => |d| .{ .declared = .{ | |
| 8432 | .zir_index = d.zir_index, | |
| 8433 | .arg_ty = ini.explicit_int_tag_type, | |
| 8434 | .captures = .{ .external = d.captures }, | |
| 8435 | } }, | |
| 8436 | .reified => |r| .{ .reified = .{ | |
| 8437 | .zir_index = r.zir_index, | |
| 8438 | .type_hash = r.type_hash, | |
| 8439 | } }, | |
| 8440 | .generated_union_tag => |u| .{ .generated_union_tag = u }, | |
| 8441 | } }; | |
| 8442 | var gop = try ip.getOrPutKey(gpa, io, tid, key); | |
| 8443 | defer gop.deinit(); | |
| 8444 | if (gop == .existing) return .{ .existing = gop.existing }; | |
| 8445 | ||
| 8446 | const local = ip.getLocal(tid); | |
| 8447 | const items = local.getMutableItems(gpa, io); | |
| 8448 | const extra = local.getMutableExtra(gpa, io); | |
| 8449 | try items.ensureUnusedCapacity(1); | |
| 8450 | ||
| 8451 | const tag: Tag, const have_values: bool = if (ini.nonexhaustive) | |
| 8452 | .{ .type_enum_nonexhaustive, true } | |
| 8453 | else if (ini.explicit_int_tag_type != .none) | |
| 8454 | .{ .type_enum_explicit, true } | |
| 8455 | else | |
| 8456 | .{ .type_enum_auto, false }; | |
| 8457 | ||
| 8458 | const field_name_map = try ip.addMap(gpa, io, tid, ini.fields_len); | |
| 8459 | errdefer local.mutate.maps.len -= 1; | |
| 8460 | ||
| 8461 | const field_value_map = if (have_values) try ip.addMap(gpa, io, tid, ini.fields_len) else undefined; | |
| 8462 | errdefer local.mutate.maps.len -= @intFromBool(have_values); | |
| 8463 | ||
| 8464 | try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeEnum).@"struct".fields.len + | |
| 8465 | switch (ini.key) { | |
| 8466 | .declared => |d| 1 + d.captures.len, // `zir_index` and `capture` | |
| 8467 | .reified => 3, // `zir_index` and `type_hash` | |
| 8468 | .generated_union_tag => 1, // owner_union | |
| 8469 | } + | |
| 8470 | @intFromBool(have_values) + // field_value_map | |
| 8471 | ini.fields_len + // field_name | |
| 8472 | (if (have_values) ini.fields_len else 0)); // field_value | |
| 8473 | ||
| 8474 | const extra_index = addExtraAssumeCapacity(extra, Tag.TypeEnum{ | |
| 8475 | .captures_len = switch (ini.key) { | |
| 8476 | .declared => |d| @enumFromInt(d.captures.len), | |
| 8477 | .reified => .reified, | |
| 8478 | .generated_union_tag => .generated_union_tag, | |
| 8479 | }, | |
| 8480 | .name = undefined, // set by `finish` | |
| 8481 | .name_nav = undefined, // set by `finish` | |
| 8482 | .namespace = undefined, // set by `finish` | |
| 8483 | .int_tag_type = ini.explicit_int_tag_type, | |
| 8484 | .fields_len = ini.fields_len, | |
| 8485 | .field_name_map = field_name_map, | |
| 8486 | }); | |
| 8487 | switch (ini.key) { | |
| 8488 | .declared => |d| { | |
| 8489 | extra.appendAssumeCapacity(.{@intFromEnum(d.zir_index)}); // zir_index | |
| 8490 | extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}); // capture | |
| 8491 | }, | |
| 8492 | .reified => |r| { | |
| 8493 | extra.appendAssumeCapacity(.{@intFromEnum(r.zir_index)}); // zir_index | |
| 8494 | _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)); // type_hash | |
| 8495 | }, | |
| 8496 | .generated_union_tag => |owner_union| { | |
| 8497 | extra.appendAssumeCapacity(.{@intFromEnum(owner_union)}); // owner_union | |
| 8498 | }, | |
| 9186 | 8499 | } |
| 9187 | extra.appendNTimesAssumeCapacity(.{std.math.maxInt(u32)}, ini.fields_len); | |
| 8500 | if (have_values) extra.appendAssumeCapacity(.{@intFromEnum(field_value_map)}); | |
| 8501 | const field_names_start = extra.mutate.len; | |
| 8502 | extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // field_name | |
| 8503 | if (have_values) extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_value | |
| 8504 | items.appendAssumeCapacity(.{ | |
| 8505 | .tag = tag, | |
| 8506 | .data = extra_index, | |
| 8507 | }); | |
| 9188 | 8508 | return .{ .wip = .{ |
| 8509 | .index = gop.put(), | |
| 9189 | 8510 | .tid = tid, |
| 8511 | .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name").?, | |
| 8512 | .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name_nav").?, | |
| 8513 | .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "namespace").?, | |
| 8514 | .tag_type_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "int_tag_type").?, | |
| 8515 | .fields_len = ini.fields_len, | |
| 8516 | .field_name_map = field_name_map, | |
| 8517 | .field_names_start = field_names_start, | |
| 8518 | .field_comptime_bits_start = null, | |
| 8519 | } }; | |
| 8520 | } | |
| 8521 | ||
| 8522 | pub fn getOpaqueType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, ini: struct { | |
| 8523 | zir_index: TrackedInst.Index, | |
| 8524 | captures: []const CaptureValue, | |
| 8525 | }) Allocator.Error!WipContainerType.Result { | |
| 8526 | var gop = try ip.getOrPutKey(gpa, io, tid, .{ .opaque_type = .{ .declared = .{ | |
| 8527 | .zir_index = ini.zir_index, | |
| 8528 | .captures = .{ .external = ini.captures }, | |
| 8529 | .arg_ty = .none, | |
| 8530 | } } }); | |
| 8531 | defer gop.deinit(); | |
| 8532 | if (gop == .existing) return .{ .existing = gop.existing }; | |
| 8533 | ||
| 8534 | const local = ip.getLocal(tid); | |
| 8535 | const items = local.getMutableItems(gpa, io); | |
| 8536 | const extra = local.getMutableExtra(gpa, io); | |
| 8537 | try items.ensureUnusedCapacity(1); | |
| 8538 | ||
| 8539 | try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeOpaque).@"struct".fields.len + ini.captures.len); | |
| 8540 | const extra_index = addExtraAssumeCapacity(extra, Tag.TypeOpaque{ | |
| 8541 | .zir_index = ini.zir_index, | |
| 8542 | .captures_len = @intCast(ini.captures.len), | |
| 8543 | .name = undefined, // set by `finish` | |
| 8544 | .name_nav = undefined, // set by `finish` | |
| 8545 | .namespace = undefined, // set by `finish` | |
| 8546 | }); | |
| 8547 | extra.appendSliceAssumeCapacity(.{@ptrCast(ini.captures)}); | |
| 8548 | items.appendAssumeCapacity(.{ | |
| 8549 | .tag = .type_opaque, | |
| 8550 | .data = extra_index, | |
| 8551 | }); | |
| 8552 | return .{ .wip = .{ | |
| 9190 | 8553 | .index = gop.put(), |
| 9191 | .type_name_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "name").?, | |
| 9192 | .name_nav_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "name_nav").?, | |
| 9193 | .namespace_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "namespace").?, | |
| 8554 | .tid = tid, | |
| 8555 | .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "name").?, | |
| 8556 | .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "name_nav").?, | |
| 8557 | .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "namespace").?, | |
| 8558 | .tag_type_index = null, | |
| 8559 | .fields_len = 0, | |
| 8560 | .field_name_map = undefined, | |
| 8561 | .field_names_start = undefined, | |
| 8562 | .field_comptime_bits_start = undefined, | |
| 9194 | 8563 | } }; |
| 9195 | 8564 | } |
| 9196 | 8565 | |
| 8566 | pub const WipContainerType = struct { | |
| 8567 | index: Index, | |
| 8568 | tid: Zcu.PerThread.Id, | |
| 8569 | type_name_index: u32, | |
| 8570 | name_nav_index: u32, | |
| 8571 | namespace_index: u32, | |
| 8572 | ||
| 8573 | tag_type_index: ?u32, | |
| 8574 | ||
| 8575 | fields_len: u32, | |
| 8576 | field_name_map: MapIndex, | |
| 8577 | field_names_start: u32, | |
| 8578 | field_comptime_bits_start: ?u32, | |
| 8579 | ||
| 8580 | pub fn setName( | |
| 8581 | wip: WipContainerType, | |
| 8582 | ip: *InternPool, | |
| 8583 | type_name: NullTerminatedString, | |
| 8584 | /// This should be the `Nav` we are named after if we use the `.parent` name strategy; `.none` otherwise. | |
| 8585 | /// This is also `.none` if we use `.parent` because we are the root struct type for a file. | |
| 8586 | name_nav: Nav.Index.Optional, | |
| 8587 | ) void { | |
| 8588 | const extra = ip.getLocalShared(wip.tid).extra.acquire(); | |
| 8589 | const extra_items = extra.view().items(.@"0"); | |
| 8590 | extra_items[wip.type_name_index] = @intFromEnum(type_name); | |
| 8591 | extra_items[wip.name_nav_index] = @intFromEnum(name_nav); | |
| 8592 | } | |
| 8593 | ||
| 8594 | pub fn setTagType( | |
| 8595 | wip: WipContainerType, | |
| 8596 | ip: *InternPool, | |
| 8597 | tag_ty: Index, | |
| 8598 | ) void { | |
| 8599 | const extra = ip.getLocalShared(wip.tid).extra.acquire(); | |
| 8600 | const extra_items = extra.view().items(.@"0"); | |
| 8601 | const i = wip.tag_type_index.?; | |
| 8602 | const old_val: InternPool.Index = @enumFromInt(extra_items[i]); | |
| 8603 | assert(old_val == .none); | |
| 8604 | assert(tag_ty != .none); | |
| 8605 | extra_items[i] = @intFromEnum(tag_ty); | |
| 8606 | } | |
| 8607 | ||
| 8608 | /// Returns the already-existing field with the same name, if any. | |
| 8609 | pub fn nextField( | |
| 8610 | wip: WipContainerType, | |
| 8611 | ip: *InternPool, | |
| 8612 | name: NullTerminatedString, | |
| 8613 | marked_comptime: bool, | |
| 8614 | ) ?u32 { | |
| 8615 | assert(wip.fields_len > 0); | |
| 8616 | const extra = ip.getLocalShared(wip.tid).extra.acquire(); | |
| 8617 | const extra_items = extra.view().items(.@"0"); | |
| 8618 | const map = wip.field_name_map.get(ip); | |
| 8619 | const field_idx = map.count(); | |
| 8620 | assert(field_idx < wip.fields_len); | |
| 8621 | const names: []NullTerminatedString = @ptrCast(extra_items[wip.field_names_start..][0..wip.fields_len]); | |
| 8622 | const adapter: NullTerminatedString.Adapter = .{ .strings = names[0..field_idx] }; | |
| 8623 | const gop = map.getOrPutAssumeCapacityAdapted(name, adapter); | |
| 8624 | if (gop.found_existing) return @intCast(gop.index); | |
| 8625 | names[field_idx] = name; | |
| 8626 | if (wip.field_comptime_bits_start) |start_idx| { | |
| 8627 | if (marked_comptime) { | |
| 8628 | extra_items[start_idx + field_idx / 32] |= @as(u32, 1) << @intCast(field_idx % 32); | |
| 8629 | } | |
| 8630 | } else { | |
| 8631 | assert(!marked_comptime); | |
| 8632 | } | |
| 8633 | return null; | |
| 8634 | } | |
| 8635 | ||
| 8636 | pub fn finish( | |
| 8637 | wip: WipContainerType, | |
| 8638 | ip: *InternPool, | |
| 8639 | namespace: NamespaceIndex, | |
| 8640 | ) Index { | |
| 8641 | const extra = ip.getLocalShared(wip.tid).extra.acquire(); | |
| 8642 | const extra_items = extra.view().items(.@"0"); | |
| 8643 | ||
| 8644 | extra_items[wip.namespace_index] = @intFromEnum(namespace); | |
| 8645 | ||
| 8646 | if (wip.fields_len > 0) { | |
| 8647 | assert(wip.field_name_map.get(ip).count() == wip.fields_len); | |
| 8648 | } | |
| 8649 | if (wip.tag_type_index) |i| { | |
| 8650 | const tag_ty: Index = @enumFromInt(extra_items[i]); | |
| 8651 | assert(tag_ty != .none); | |
| 8652 | } | |
| 8653 | ||
| 8654 | return wip.index; | |
| 8655 | } | |
| 8656 | ||
| 8657 | pub fn cancel(wip: WipContainerType, ip: *InternPool, tid: Zcu.PerThread.Id) void { | |
| 8658 | ip.remove(tid, wip.index); | |
| 8659 | } | |
| 8660 | ||
| 8661 | pub const Result = union(enum) { | |
| 8662 | wip: WipContainerType, | |
| 8663 | existing: Index, | |
| 8664 | }; | |
| 8665 | }; | |
| 8666 | ||
| 8667 | pub fn getUnion( | |
| 8668 | ip: *InternPool, | |
| 8669 | gpa: Allocator, | |
| 8670 | io: Io, | |
| 8671 | tid: Zcu.PerThread.Id, | |
| 8672 | un: Key.Union, | |
| 8673 | ) Allocator.Error!Index { | |
| 8674 | var gop = try ip.getOrPutKey(gpa, io, tid, .{ .un = un }); | |
| 8675 | defer gop.deinit(); | |
| 8676 | if (gop == .existing) return gop.existing; | |
| 8677 | const local = ip.getLocal(tid); | |
| 8678 | const items = local.getMutableItems(gpa, io); | |
| 8679 | const extra = local.getMutableExtra(gpa, io); | |
| 8680 | try items.ensureUnusedCapacity(1); | |
| 8681 | ||
| 8682 | assert(un.ty != .none); | |
| 8683 | assert(un.val != .none); | |
| 8684 | items.appendAssumeCapacity(.{ | |
| 8685 | .tag = .union_value, | |
| 8686 | .data = try addExtra(extra, un), | |
| 8687 | }); | |
| 8688 | ||
| 8689 | return gop.put(); | |
| 8690 | } | |
| 8691 | ||
| 9197 | 8692 | pub const TupleTypeInit = struct { |
| 9198 | 8693 | types: []const Index, |
| 9199 | 8694 | /// These elements may be `none`, indicating runtime-known. |
| ... | ... | @@ -9252,10 +8747,7 @@ pub const GetFuncTypeKey = struct { |
| 9252 | 8747 | /// `null` means generic. |
| 9253 | 8748 | cc: ?std.builtin.CallingConvention = .auto, |
| 9254 | 8749 | is_var_args: bool = false, |
| 9255 | is_generic: bool = false, | |
| 9256 | 8750 | is_noinline: bool = false, |
| 9257 | section_is_generic: bool = false, | |
| 9258 | addrspace_is_generic: bool = false, | |
| 9259 | 8751 | }; |
| 9260 | 8752 | |
| 9261 | 8753 | pub fn getFuncType( |
| ... | ... | @@ -9293,7 +8785,6 @@ pub fn getFuncType( |
| 9293 | 8785 | .is_var_args = key.is_var_args, |
| 9294 | 8786 | .has_comptime_bits = key.comptime_bits != 0, |
| 9295 | 8787 | .has_noalias_bits = key.noalias_bits != 0, |
| 9296 | .is_generic = key.is_generic, | |
| 9297 | 8788 | .is_noinline = key.is_noinline, |
| 9298 | 8789 | }, |
| 9299 | 8790 | }); |
| ... | ... | @@ -9480,7 +8971,6 @@ pub const GetFuncDeclIesKey = struct { |
| 9480 | 8971 | /// null means generic. |
| 9481 | 8972 | cc: ?std.builtin.CallingConvention, |
| 9482 | 8973 | is_var_args: bool, |
| 9483 | is_generic: bool, | |
| 9484 | 8974 | is_noinline: bool, |
| 9485 | 8975 | zir_body_inst: TrackedInst.Index, |
| 9486 | 8976 | lbrace_line: u32, |
| ... | ... | @@ -9564,7 +9054,6 @@ pub fn getFuncDeclIes( |
| 9564 | 9054 | .is_var_args = key.is_var_args, |
| 9565 | 9055 | .has_comptime_bits = key.comptime_bits != 0, |
| 9566 | 9056 | .has_noalias_bits = key.noalias_bits != 0, |
| 9567 | .is_generic = key.is_generic, | |
| 9568 | 9057 | .is_noinline = key.is_noinline, |
| 9569 | 9058 | }, |
| 9570 | 9059 | }); |
| ... | ... | @@ -9864,7 +9353,6 @@ fn getFuncInstanceIes( |
| 9864 | 9353 | .is_var_args = false, |
| 9865 | 9354 | .has_comptime_bits = false, |
| 9866 | 9355 | .has_noalias_bits = arg.noalias_bits != 0, |
| 9867 | .is_generic = false, | |
| 9868 | 9356 | .is_noinline = arg.is_noinline, |
| 9869 | 9357 | }, |
| 9870 | 9358 | }); |
| ... | ... | @@ -9876,538 +9364,100 @@ fn getFuncInstanceIes( |
| 9876 | 9364 | .tag = &.{ |
| 9877 | 9365 | .func_instance, |
| 9878 | 9366 | .type_error_union, |
| 9879 | .type_inferred_error_set, | |
| 9880 | .type_function, | |
| 9881 | }, | |
| 9882 | .data = &.{ | |
| 9883 | func_extra_index, | |
| 9884 | addExtraAssumeCapacity(extra, Tag.ErrorUnionType{ | |
| 9885 | .error_set_type = error_set_type, | |
| 9886 | .payload_type = arg.bare_return_type, | |
| 9887 | }), | |
| 9888 | @intFromEnum(func_index), | |
| 9889 | func_type_extra_index, | |
| 9890 | }, | |
| 9891 | }); | |
| 9892 | errdefer { | |
| 9893 | items.mutate.len -= 4; | |
| 9894 | extra.mutate.len = prev_extra_len; | |
| 9895 | } | |
| 9896 | ||
| 9897 | var func_gop = try ip.getOrPutKeyEnsuringAdditionalCapacity(gpa, io, tid, .{ | |
| 9898 | .func = ip.extraFuncInstance(tid, extra.list.*, func_extra_index), | |
| 9899 | }, 3); | |
| 9900 | defer func_gop.deinit(); | |
| 9901 | if (func_gop == .existing) { | |
| 9902 | // Hot path: undo the additions to our two arrays. | |
| 9903 | items.mutate.len -= 4; | |
| 9904 | extra.mutate.len = prev_extra_len; | |
| 9905 | return func_gop.existing; | |
| 9906 | } | |
| 9907 | func_gop.putTentative(func_index); | |
| 9908 | var error_union_type_gop = try ip.getOrPutKeyEnsuringAdditionalCapacity(gpa, io, tid, .{ .error_union_type = .{ | |
| 9909 | .error_set_type = error_set_type, | |
| 9910 | .payload_type = arg.bare_return_type, | |
| 9911 | } }, 2); | |
| 9912 | defer error_union_type_gop.deinit(); | |
| 9913 | error_union_type_gop.putTentative(error_union_type); | |
| 9914 | var error_set_type_gop = try ip.getOrPutKeyEnsuringAdditionalCapacity(gpa, io, tid, .{ | |
| 9915 | .inferred_error_set_type = func_index, | |
| 9916 | }, 1); | |
| 9917 | defer error_set_type_gop.deinit(); | |
| 9918 | error_set_type_gop.putTentative(error_set_type); | |
| 9919 | var func_ty_gop = try ip.getOrPutKey(gpa, io, tid, .{ | |
| 9920 | .func_type = extraFuncType(tid, extra.list.*, func_type_extra_index), | |
| 9921 | }); | |
| 9922 | defer func_ty_gop.deinit(); | |
| 9923 | func_ty_gop.putTentative(func_ty); | |
| 9924 | try finishFuncInstance( | |
| 9925 | ip, | |
| 9926 | gpa, | |
| 9927 | io, | |
| 9928 | tid, | |
| 9929 | extra, | |
| 9930 | generic_owner, | |
| 9931 | func_index, | |
| 9932 | func_extra_index, | |
| 9933 | ); | |
| 9934 | ||
| 9935 | func_gop.putFinal(func_index); | |
| 9936 | error_union_type_gop.putFinal(error_union_type); | |
| 9937 | error_set_type_gop.putFinal(error_set_type); | |
| 9938 | func_ty_gop.putFinal(func_ty); | |
| 9939 | return func_index; | |
| 9940 | } | |
| 9941 | ||
| 9942 | fn finishFuncInstance( | |
| 9943 | ip: *InternPool, | |
| 9944 | gpa: Allocator, | |
| 9945 | io: Io, | |
| 9946 | tid: Zcu.PerThread.Id, | |
| 9947 | extra: Local.Extra.Mutable, | |
| 9948 | generic_owner: Index, | |
| 9949 | func_index: Index, | |
| 9950 | func_extra_index: u32, | |
| 9951 | ) Allocator.Error!void { | |
| 9952 | const fn_owner_nav = ip.getNav(ip.funcDeclInfo(generic_owner).owner_nav); | |
| 9953 | const fn_namespace = fn_owner_nav.analysis.?.namespace; | |
| 9954 | ||
| 9955 | // TODO: improve this name | |
| 9956 | const nav_name = try ip.getOrPutStringFmt(gpa, io, tid, "{f}__anon_{d}", .{ | |
| 9957 | fn_owner_nav.name.fmt(ip), @intFromEnum(func_index), | |
| 9958 | }, .no_embedded_nulls); | |
| 9959 | const nav_index = try ip.createNav(gpa, io, tid, .{ | |
| 9960 | .name = nav_name, | |
| 9961 | .fqn = try ip.namespacePtr(fn_namespace).internFullyQualifiedName(ip, gpa, io, tid, nav_name), | |
| 9962 | .val = func_index, | |
| 9963 | .is_const = fn_owner_nav.status.fully_resolved.is_const, | |
| 9964 | .alignment = fn_owner_nav.status.fully_resolved.alignment, | |
| 9965 | .@"linksection" = fn_owner_nav.status.fully_resolved.@"linksection", | |
| 9966 | .@"addrspace" = fn_owner_nav.status.fully_resolved.@"addrspace", | |
| 9967 | }); | |
| 9968 | ||
| 9969 | // Populate the owner_nav field which was left undefined until now. | |
| 9970 | extra.view().items(.@"0")[ | |
| 9971 | func_extra_index + std.meta.fieldIndex(Tag.FuncInstance, "owner_nav").? | |
| 9972 | ] = @intFromEnum(nav_index); | |
| 9973 | } | |
| 9974 | ||
| 9975 | pub const EnumTypeInit = struct { | |
| 9976 | has_values: bool, | |
| 9977 | tag_mode: LoadedEnumType.TagMode, | |
| 9978 | fields_len: u32, | |
| 9979 | key: union(enum) { | |
| 9980 | declared: struct { | |
| 9981 | zir_index: TrackedInst.Index, | |
| 9982 | captures: []const CaptureValue, | |
| 9983 | }, | |
| 9984 | declared_owned_captures: struct { | |
| 9985 | zir_index: TrackedInst.Index, | |
| 9986 | captures: CaptureValue.Slice, | |
| 9987 | }, | |
| 9988 | reified: struct { | |
| 9989 | zir_index: TrackedInst.Index, | |
| 9990 | type_hash: u64, | |
| 9991 | }, | |
| 9992 | }, | |
| 9993 | }; | |
| 9994 | ||
| 9995 | pub const WipEnumType = struct { | |
| 9996 | tid: Zcu.PerThread.Id, | |
| 9997 | index: Index, | |
| 9998 | tag_ty_index: u32, | |
| 9999 | type_name_extra_index: u32, | |
| 10000 | namespace_extra_index: u32, | |
| 10001 | name_nav_extra_index: u32, | |
| 10002 | names_map: MapIndex, | |
| 10003 | names_start: u32, | |
| 10004 | values_map: OptionalMapIndex, | |
| 10005 | values_start: u32, | |
| 10006 | ||
| 10007 | pub fn setName( | |
| 10008 | wip: WipEnumType, | |
| 10009 | ip: *InternPool, | |
| 10010 | type_name: NullTerminatedString, | |
| 10011 | /// This should be the `Nav` we are named after if we use the `.parent` name strategy; `.none` otherwise. | |
| 10012 | name_nav: Nav.Index.Optional, | |
| 10013 | ) void { | |
| 10014 | const extra = ip.getLocalShared(wip.tid).extra.acquire(); | |
| 10015 | const extra_items = extra.view().items(.@"0"); | |
| 10016 | extra_items[wip.type_name_extra_index] = @intFromEnum(type_name); | |
| 10017 | extra_items[wip.name_nav_extra_index] = @intFromEnum(name_nav); | |
| 10018 | } | |
| 10019 | ||
| 10020 | pub fn prepare( | |
| 10021 | wip: WipEnumType, | |
| 10022 | ip: *InternPool, | |
| 10023 | namespace: NamespaceIndex, | |
| 10024 | ) void { | |
| 10025 | const extra = ip.getLocalShared(wip.tid).extra.acquire(); | |
| 10026 | const extra_items = extra.view().items(.@"0"); | |
| 10027 | ||
| 10028 | extra_items[wip.namespace_extra_index] = @intFromEnum(namespace); | |
| 10029 | } | |
| 10030 | ||
| 10031 | pub fn setTagTy(wip: WipEnumType, ip: *InternPool, tag_ty: Index) void { | |
| 10032 | assert(ip.isIntegerType(tag_ty)); | |
| 10033 | const extra = ip.getLocalShared(wip.tid).extra.acquire(); | |
| 10034 | extra.view().items(.@"0")[wip.tag_ty_index] = @intFromEnum(tag_ty); | |
| 10035 | } | |
| 10036 | ||
| 10037 | pub const FieldConflict = struct { | |
| 10038 | kind: enum { name, value }, | |
| 10039 | prev_field_idx: u32, | |
| 10040 | }; | |
| 10041 | ||
| 10042 | /// Returns the already-existing field with the same name or value, if any. | |
| 10043 | /// If the enum is automatially numbered, `value` must be `.none`. | |
| 10044 | /// Otherwise, the type of `value` must be the integer tag type of the enum. | |
| 10045 | pub fn nextField(wip: WipEnumType, ip: *InternPool, name: NullTerminatedString, value: Index) ?FieldConflict { | |
| 10046 | const unwrapped_index = wip.index.unwrap(ip); | |
| 10047 | const extra_list = ip.getLocalShared(unwrapped_index.tid).extra.acquire(); | |
| 10048 | const extra_items = extra_list.view().items(.@"0"); | |
| 10049 | if (ip.addFieldName(extra_list, wip.names_map, wip.names_start, name)) |conflict| { | |
| 10050 | return .{ .kind = .name, .prev_field_idx = conflict }; | |
| 10051 | } | |
| 10052 | if (value == .none) { | |
| 10053 | assert(wip.values_map == .none); | |
| 10054 | return null; | |
| 10055 | } | |
| 10056 | assert(ip.typeOf(value) == @as(Index, @enumFromInt(extra_items[wip.tag_ty_index]))); | |
| 10057 | const map = wip.values_map.unwrap().?.get(ip); | |
| 10058 | const field_index = map.count(); | |
| 10059 | const indexes = extra_items[wip.values_start..][0..field_index]; | |
| 10060 | const adapter: Index.Adapter = .{ .indexes = @ptrCast(indexes) }; | |
| 10061 | const gop = map.getOrPutAssumeCapacityAdapted(value, adapter); | |
| 10062 | if (gop.found_existing) { | |
| 10063 | return .{ .kind = .value, .prev_field_idx = @intCast(gop.index) }; | |
| 10064 | } | |
| 10065 | extra_items[wip.values_start + field_index] = @intFromEnum(value); | |
| 10066 | return null; | |
| 10067 | } | |
| 10068 | ||
| 10069 | pub fn cancel(wip: WipEnumType, ip: *InternPool, tid: Zcu.PerThread.Id) void { | |
| 10070 | ip.remove(tid, wip.index); | |
| 10071 | } | |
| 10072 | ||
| 10073 | pub const Result = union(enum) { | |
| 10074 | wip: WipEnumType, | |
| 10075 | existing: Index, | |
| 10076 | }; | |
| 10077 | }; | |
| 10078 | ||
| 10079 | pub fn getEnumType( | |
| 10080 | ip: *InternPool, | |
| 10081 | gpa: Allocator, | |
| 10082 | io: Io, | |
| 10083 | tid: Zcu.PerThread.Id, | |
| 10084 | ini: EnumTypeInit, | |
| 10085 | /// If it is known that there is an existing type with this key which is outdated, | |
| 10086 | /// this is passed as `true`, and the type is replaced with one at a fresh index. | |
| 10087 | replace_existing: bool, | |
| 10088 | ) Allocator.Error!WipEnumType.Result { | |
| 10089 | const key: Key = .{ .enum_type = switch (ini.key) { | |
| 10090 | .declared => |d| .{ .declared = .{ | |
| 10091 | .zir_index = d.zir_index, | |
| 10092 | .captures = .{ .external = d.captures }, | |
| 10093 | } }, | |
| 10094 | .declared_owned_captures => |d| .{ .declared = .{ | |
| 10095 | .zir_index = d.zir_index, | |
| 10096 | .captures = .{ .owned = d.captures }, | |
| 10097 | } }, | |
| 10098 | .reified => |r| .{ .reified = .{ | |
| 10099 | .zir_index = r.zir_index, | |
| 10100 | .type_hash = r.type_hash, | |
| 10101 | } }, | |
| 10102 | } }; | |
| 10103 | var gop = if (replace_existing) | |
| 10104 | ip.putKeyReplace(io, tid, key) | |
| 10105 | else | |
| 10106 | try ip.getOrPutKey(gpa, io, tid, key); | |
| 10107 | defer gop.deinit(); | |
| 10108 | if (gop == .existing) return .{ .existing = gop.existing }; | |
| 10109 | ||
| 10110 | const local = ip.getLocal(tid); | |
| 10111 | const items = local.getMutableItems(gpa, io); | |
| 10112 | try items.ensureUnusedCapacity(1); | |
| 10113 | const extra = local.getMutableExtra(gpa, io); | |
| 10114 | ||
| 10115 | const names_map = try ip.addMap(gpa, io, tid, ini.fields_len); | |
| 10116 | errdefer local.mutate.maps.len -= 1; | |
| 10117 | ||
| 10118 | switch (ini.tag_mode) { | |
| 10119 | .auto => { | |
| 10120 | assert(!ini.has_values); | |
| 10121 | try extra.ensureUnusedCapacity(@typeInfo(EnumAuto).@"struct".fields.len + | |
| 10122 | // TODO: fmt bug | |
| 10123 | // zig fmt: off | |
| 10124 | switch (ini.key) { | |
| 10125 | inline .declared, .declared_owned_captures => |d| d.captures.len, | |
| 10126 | .reified => 2, // type_hash: PackedU64 | |
| 10127 | } + | |
| 10128 | // zig fmt: on | |
| 10129 | ini.fields_len); // field types | |
| 10130 | ||
| 10131 | const extra_index = addExtraAssumeCapacity(extra, EnumAuto{ | |
| 10132 | .name = undefined, // set by `prepare` | |
| 10133 | .name_nav = undefined, // set by `prepare` | |
| 10134 | .captures_len = switch (ini.key) { | |
| 10135 | inline .declared, .declared_owned_captures => |d| @intCast(d.captures.len), | |
| 10136 | .reified => std.math.maxInt(u32), | |
| 10137 | }, | |
| 10138 | .namespace = undefined, // set by `prepare` | |
| 10139 | .int_tag_type = .none, // set by `prepare` | |
| 10140 | .fields_len = ini.fields_len, | |
| 10141 | .names_map = names_map, | |
| 10142 | .zir_index = switch (ini.key) { | |
| 10143 | inline else => |x| x.zir_index, | |
| 10144 | }.toOptional(), | |
| 10145 | }); | |
| 10146 | items.appendAssumeCapacity(.{ | |
| 10147 | .tag = .type_enum_auto, | |
| 10148 | .data = extra_index, | |
| 10149 | }); | |
| 10150 | switch (ini.key) { | |
| 10151 | .declared => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}), | |
| 10152 | .declared_owned_captures => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures.get(ip))}), | |
| 10153 | .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)), | |
| 10154 | } | |
| 10155 | const names_start = extra.mutate.len; | |
| 10156 | _ = extra.addManyAsSliceAssumeCapacity(ini.fields_len); | |
| 10157 | return .{ .wip = .{ | |
| 10158 | .tid = tid, | |
| 10159 | .index = gop.put(), | |
| 10160 | .tag_ty_index = extra_index + std.meta.fieldIndex(EnumAuto, "int_tag_type").?, | |
| 10161 | .type_name_extra_index = extra_index + std.meta.fieldIndex(EnumAuto, "name").?, | |
| 10162 | .name_nav_extra_index = extra_index + std.meta.fieldIndex(EnumAuto, "name_nav").?, | |
| 10163 | .namespace_extra_index = extra_index + std.meta.fieldIndex(EnumAuto, "namespace").?, | |
| 10164 | .names_map = names_map, | |
| 10165 | .names_start = @intCast(names_start), | |
| 10166 | .values_map = .none, | |
| 10167 | .values_start = undefined, | |
| 10168 | } }; | |
| 10169 | }, | |
| 10170 | .explicit, .nonexhaustive => { | |
| 10171 | const values_map: OptionalMapIndex = if (!ini.has_values) .none else m: { | |
| 10172 | const values_map = try ip.addMap(gpa, io, tid, ini.fields_len); | |
| 10173 | break :m values_map.toOptional(); | |
| 10174 | }; | |
| 10175 | errdefer if (ini.has_values) { | |
| 10176 | local.mutate.maps.len -= 1; | |
| 10177 | }; | |
| 10178 | ||
| 10179 | try extra.ensureUnusedCapacity(@typeInfo(EnumExplicit).@"struct".fields.len + | |
| 10180 | // TODO: fmt bug | |
| 10181 | // zig fmt: off | |
| 10182 | switch (ini.key) { | |
| 10183 | inline .declared, .declared_owned_captures => |d| d.captures.len, | |
| 10184 | .reified => 2, // type_hash: PackedU64 | |
| 10185 | } + | |
| 10186 | // zig fmt: on | |
| 10187 | ini.fields_len + // field types | |
| 10188 | ini.fields_len * @intFromBool(ini.has_values)); // field values | |
| 10189 | ||
| 10190 | const extra_index = addExtraAssumeCapacity(extra, EnumExplicit{ | |
| 10191 | .name = undefined, // set by `prepare` | |
| 10192 | .name_nav = undefined, // set by `prepare` | |
| 10193 | .captures_len = switch (ini.key) { | |
| 10194 | inline .declared, .declared_owned_captures => |d| @intCast(d.captures.len), | |
| 10195 | .reified => std.math.maxInt(u32), | |
| 10196 | }, | |
| 10197 | .namespace = undefined, // set by `prepare` | |
| 10198 | .int_tag_type = .none, // set by `prepare` | |
| 10199 | .fields_len = ini.fields_len, | |
| 10200 | .names_map = names_map, | |
| 10201 | .values_map = values_map, | |
| 10202 | .zir_index = switch (ini.key) { | |
| 10203 | inline else => |x| x.zir_index, | |
| 10204 | }.toOptional(), | |
| 10205 | }); | |
| 10206 | items.appendAssumeCapacity(.{ | |
| 10207 | .tag = switch (ini.tag_mode) { | |
| 10208 | .auto => unreachable, | |
| 10209 | .explicit => .type_enum_explicit, | |
| 10210 | .nonexhaustive => .type_enum_nonexhaustive, | |
| 10211 | }, | |
| 10212 | .data = extra_index, | |
| 10213 | }); | |
| 10214 | switch (ini.key) { | |
| 10215 | .declared => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}), | |
| 10216 | .declared_owned_captures => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures.get(ip))}), | |
| 10217 | .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)), | |
| 10218 | } | |
| 10219 | const names_start = extra.mutate.len; | |
| 10220 | _ = extra.addManyAsSliceAssumeCapacity(ini.fields_len); | |
| 10221 | const values_start = extra.mutate.len; | |
| 10222 | if (ini.has_values) { | |
| 10223 | _ = extra.addManyAsSliceAssumeCapacity(ini.fields_len); | |
| 10224 | } | |
| 10225 | return .{ .wip = .{ | |
| 10226 | .tid = tid, | |
| 10227 | .index = gop.put(), | |
| 10228 | .tag_ty_index = extra_index + std.meta.fieldIndex(EnumExplicit, "int_tag_type").?, | |
| 10229 | .type_name_extra_index = extra_index + std.meta.fieldIndex(EnumExplicit, "name").?, | |
| 10230 | .name_nav_extra_index = extra_index + std.meta.fieldIndex(EnumExplicit, "name_nav").?, | |
| 10231 | .namespace_extra_index = extra_index + std.meta.fieldIndex(EnumExplicit, "namespace").?, | |
| 10232 | .names_map = names_map, | |
| 10233 | .names_start = @intCast(names_start), | |
| 10234 | .values_map = values_map, | |
| 10235 | .values_start = @intCast(values_start), | |
| 10236 | } }; | |
| 10237 | }, | |
| 10238 | } | |
| 10239 | } | |
| 10240 | ||
| 10241 | const GeneratedTagEnumTypeInit = struct { | |
| 10242 | name: NullTerminatedString, | |
| 10243 | owner_union_ty: Index, | |
| 10244 | tag_ty: Index, | |
| 10245 | names: []const NullTerminatedString, | |
| 10246 | values: []const Index, | |
| 10247 | tag_mode: LoadedEnumType.TagMode, | |
| 10248 | parent_namespace: NamespaceIndex, | |
| 10249 | }; | |
| 10250 | ||
| 10251 | /// Creates an enum type which was automatically-generated as the tag type of a | |
| 10252 | /// `union` with no explicit tag type. Since this is only called once per union | |
| 10253 | /// type, it asserts that no matching type yet exists. | |
| 10254 | pub fn getGeneratedTagEnumType( | |
| 10255 | ip: *InternPool, | |
| 10256 | gpa: Allocator, | |
| 10257 | io: Io, | |
| 10258 | tid: Zcu.PerThread.Id, | |
| 10259 | ini: GeneratedTagEnumTypeInit, | |
| 10260 | ) Allocator.Error!Index { | |
| 10261 | assert(ip.isUnion(ini.owner_union_ty)); | |
| 10262 | assert(ip.isIntegerType(ini.tag_ty)); | |
| 10263 | for (ini.values) |val| assert(ip.typeOf(val) == ini.tag_ty); | |
| 10264 | ||
| 10265 | const local = ip.getLocal(tid); | |
| 10266 | const items = local.getMutableItems(gpa, io); | |
| 10267 | try items.ensureUnusedCapacity(1); | |
| 10268 | const extra = local.getMutableExtra(gpa, io); | |
| 10269 | ||
| 10270 | const names_map = try ip.addMap(gpa, io, tid, ini.names.len); | |
| 10271 | errdefer local.mutate.maps.len -= 1; | |
| 10272 | ip.addStringsToMap(names_map, ini.names); | |
| 10273 | ||
| 10274 | const fields_len: u32 = @intCast(ini.names.len); | |
| 10275 | ||
| 10276 | // Predict the index the enum will live at so we can construct the namespace before releasing the shard's mutex. | |
| 10277 | const enum_index = Index.Unwrapped.wrap(.{ | |
| 10278 | .tid = tid, | |
| 10279 | .index = items.mutate.len, | |
| 10280 | }, ip); | |
| 10281 | const parent_namespace = ip.namespacePtr(ini.parent_namespace); | |
| 10282 | const namespace = try ip.createNamespace(gpa, io, tid, .{ | |
| 10283 | .parent = ini.parent_namespace.toOptional(), | |
| 10284 | .owner_type = enum_index, | |
| 10285 | .file_scope = parent_namespace.file_scope, | |
| 10286 | .generation = parent_namespace.generation, | |
| 10287 | }); | |
| 10288 | errdefer ip.destroyNamespace(tid, namespace); | |
| 10289 | ||
| 10290 | const prev_extra_len = extra.mutate.len; | |
| 10291 | switch (ini.tag_mode) { | |
| 10292 | .auto => { | |
| 10293 | try extra.ensureUnusedCapacity(@typeInfo(EnumAuto).@"struct".fields.len + | |
| 10294 | 1 + // owner_union | |
| 10295 | fields_len); // field names | |
| 10296 | items.appendAssumeCapacity(.{ | |
| 10297 | .tag = .type_enum_auto, | |
| 10298 | .data = addExtraAssumeCapacity(extra, EnumAuto{ | |
| 10299 | .name = ini.name, | |
| 10300 | .name_nav = .none, | |
| 10301 | .captures_len = 0, | |
| 10302 | .namespace = namespace, | |
| 10303 | .int_tag_type = ini.tag_ty, | |
| 10304 | .fields_len = fields_len, | |
| 10305 | .names_map = names_map, | |
| 10306 | .zir_index = .none, | |
| 10307 | }), | |
| 10308 | }); | |
| 10309 | extra.appendAssumeCapacity(.{@intFromEnum(ini.owner_union_ty)}); | |
| 10310 | extra.appendSliceAssumeCapacity(.{@ptrCast(ini.names)}); | |
| 10311 | }, | |
| 10312 | .explicit, .nonexhaustive => { | |
| 10313 | try extra.ensureUnusedCapacity(@typeInfo(EnumExplicit).@"struct".fields.len + | |
| 10314 | 1 + // owner_union | |
| 10315 | fields_len + // field names | |
| 10316 | ini.values.len); // field values | |
| 10317 | ||
| 10318 | const values_map: OptionalMapIndex = if (ini.values.len != 0) m: { | |
| 10319 | const map = try ip.addMap(gpa, io, tid, ini.values.len); | |
| 10320 | ip.addIndexesToMap(map, ini.values); | |
| 10321 | break :m map.toOptional(); | |
| 10322 | } else .none; | |
| 10323 | // We don't clean up the values map on error! | |
| 10324 | errdefer @compileError("error path leaks values_map"); | |
| 10325 | ||
| 10326 | items.appendAssumeCapacity(.{ | |
| 10327 | .tag = switch (ini.tag_mode) { | |
| 10328 | .explicit => .type_enum_explicit, | |
| 10329 | .nonexhaustive => .type_enum_nonexhaustive, | |
| 10330 | .auto => unreachable, | |
| 10331 | }, | |
| 10332 | .data = addExtraAssumeCapacity(extra, EnumExplicit{ | |
| 10333 | .name = ini.name, | |
| 10334 | .name_nav = .none, | |
| 10335 | .captures_len = 0, | |
| 10336 | .namespace = namespace, | |
| 10337 | .int_tag_type = ini.tag_ty, | |
| 10338 | .fields_len = fields_len, | |
| 10339 | .names_map = names_map, | |
| 10340 | .values_map = values_map, | |
| 10341 | .zir_index = .none, | |
| 10342 | }), | |
| 10343 | }); | |
| 10344 | extra.appendAssumeCapacity(.{@intFromEnum(ini.owner_union_ty)}); | |
| 10345 | extra.appendSliceAssumeCapacity(.{@ptrCast(ini.names)}); | |
| 10346 | extra.appendSliceAssumeCapacity(.{@ptrCast(ini.values)}); | |
| 9367 | .type_inferred_error_set, | |
| 9368 | .type_function, | |
| 10347 | 9369 | }, |
| 10348 | } | |
| 10349 | errdefer extra.mutate.len = prev_extra_len; | |
| 10350 | errdefer switch (ini.tag_mode) { | |
| 10351 | .auto => {}, | |
| 10352 | .explicit, .nonexhaustive => if (ini.values.len != 0) { | |
| 10353 | local.mutate.maps.len -= 1; | |
| 9370 | .data = &.{ | |
| 9371 | func_extra_index, | |
| 9372 | addExtraAssumeCapacity(extra, Tag.ErrorUnionType{ | |
| 9373 | .error_set_type = error_set_type, | |
| 9374 | .payload_type = arg.bare_return_type, | |
| 9375 | }), | |
| 9376 | @intFromEnum(func_index), | |
| 9377 | func_type_extra_index, | |
| 10354 | 9378 | }, |
| 10355 | }; | |
| 9379 | }); | |
| 9380 | errdefer { | |
| 9381 | items.mutate.len -= 4; | |
| 9382 | extra.mutate.len = prev_extra_len; | |
| 9383 | } | |
| 10356 | 9384 | |
| 10357 | var gop = try ip.getOrPutKey(gpa, io, tid, .{ .enum_type = .{ | |
| 10358 | .generated_tag = .{ .union_type = ini.owner_union_ty }, | |
| 10359 | } }); | |
| 10360 | defer gop.deinit(); | |
| 10361 | assert(gop.put() == enum_index); | |
| 10362 | return enum_index; | |
| 10363 | } | |
| 9385 | var func_gop = try ip.getOrPutKeyEnsuringAdditionalCapacity(gpa, io, tid, .{ | |
| 9386 | .func = ip.extraFuncInstance(tid, extra.list.*, func_extra_index), | |
| 9387 | }, 3); | |
| 9388 | defer func_gop.deinit(); | |
| 9389 | if (func_gop == .existing) { | |
| 9390 | // Hot path: undo the additions to our two arrays. | |
| 9391 | items.mutate.len -= 4; | |
| 9392 | extra.mutate.len = prev_extra_len; | |
| 9393 | return func_gop.existing; | |
| 9394 | } | |
| 9395 | func_gop.putTentative(func_index); | |
| 9396 | var error_union_type_gop = try ip.getOrPutKeyEnsuringAdditionalCapacity(gpa, io, tid, .{ .error_union_type = .{ | |
| 9397 | .error_set_type = error_set_type, | |
| 9398 | .payload_type = arg.bare_return_type, | |
| 9399 | } }, 2); | |
| 9400 | defer error_union_type_gop.deinit(); | |
| 9401 | error_union_type_gop.putTentative(error_union_type); | |
| 9402 | var error_set_type_gop = try ip.getOrPutKeyEnsuringAdditionalCapacity(gpa, io, tid, .{ | |
| 9403 | .inferred_error_set_type = func_index, | |
| 9404 | }, 1); | |
| 9405 | defer error_set_type_gop.deinit(); | |
| 9406 | error_set_type_gop.putTentative(error_set_type); | |
| 9407 | var func_ty_gop = try ip.getOrPutKey(gpa, io, tid, .{ | |
| 9408 | .func_type = extraFuncType(tid, extra.list.*, func_type_extra_index), | |
| 9409 | }); | |
| 9410 | defer func_ty_gop.deinit(); | |
| 9411 | func_ty_gop.putTentative(func_ty); | |
| 9412 | try finishFuncInstance( | |
| 9413 | ip, | |
| 9414 | gpa, | |
| 9415 | io, | |
| 9416 | tid, | |
| 9417 | extra, | |
| 9418 | generic_owner, | |
| 9419 | func_index, | |
| 9420 | func_extra_index, | |
| 9421 | ); | |
| 10364 | 9422 | |
| 10365 | pub const OpaqueTypeInit = struct { | |
| 10366 | zir_index: TrackedInst.Index, | |
| 10367 | captures: []const CaptureValue, | |
| 10368 | }; | |
| 9423 | func_gop.putFinal(func_index); | |
| 9424 | error_union_type_gop.putFinal(error_union_type); | |
| 9425 | error_set_type_gop.putFinal(error_set_type); | |
| 9426 | func_ty_gop.putFinal(func_ty); | |
| 9427 | return func_index; | |
| 9428 | } | |
| 10369 | 9429 | |
| 10370 | pub fn getOpaqueType( | |
| 9430 | fn finishFuncInstance( | |
| 10371 | 9431 | ip: *InternPool, |
| 10372 | 9432 | gpa: Allocator, |
| 10373 | 9433 | io: Io, |
| 10374 | 9434 | tid: Zcu.PerThread.Id, |
| 10375 | ini: OpaqueTypeInit, | |
| 10376 | ) Allocator.Error!WipNamespaceType.Result { | |
| 10377 | var gop = try ip.getOrPutKey(gpa, io, tid, .{ .opaque_type = .{ .declared = .{ | |
| 10378 | .zir_index = ini.zir_index, | |
| 10379 | .captures = .{ .external = ini.captures }, | |
| 10380 | } } }); | |
| 10381 | defer gop.deinit(); | |
| 10382 | if (gop == .existing) return .{ .existing = gop.existing }; | |
| 10383 | ||
| 10384 | const local = ip.getLocal(tid); | |
| 10385 | const items = local.getMutableItems(gpa, io); | |
| 10386 | const extra = local.getMutableExtra(gpa, io); | |
| 10387 | try items.ensureUnusedCapacity(1); | |
| 9435 | extra: Local.Extra.Mutable, | |
| 9436 | generic_owner: Index, | |
| 9437 | func_index: Index, | |
| 9438 | func_extra_index: u32, | |
| 9439 | ) Allocator.Error!void { | |
| 9440 | const fn_owner_nav = ip.getNav(ip.funcDeclInfo(generic_owner).owner_nav); | |
| 9441 | const fn_namespace = fn_owner_nav.analysis.?.namespace; | |
| 10388 | 9442 | |
| 10389 | try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeOpaque).@"struct".fields.len + ini.captures.len); | |
| 10390 | const extra_index = addExtraAssumeCapacity(extra, Tag.TypeOpaque{ | |
| 10391 | .name = undefined, // set by `finish` | |
| 10392 | .name_nav = undefined, // set by `finish` | |
| 10393 | .namespace = undefined, // set by `finish` | |
| 10394 | .zir_index = ini.zir_index, | |
| 10395 | .captures_len = @intCast(ini.captures.len), | |
| 10396 | }); | |
| 10397 | items.appendAssumeCapacity(.{ | |
| 10398 | .tag = .type_opaque, | |
| 10399 | .data = extra_index, | |
| 9443 | // TODO: improve this name | |
| 9444 | const nav_name = try ip.getOrPutStringFmt(gpa, io, tid, "{f}__anon_{d}", .{ | |
| 9445 | fn_owner_nav.name.fmt(ip), @intFromEnum(func_index), | |
| 9446 | }, .no_embedded_nulls); | |
| 9447 | const nav_index = try ip.createNav(gpa, io, tid, .{ | |
| 9448 | .name = nav_name, | |
| 9449 | .fqn = try ip.namespacePtr(fn_namespace).internFullyQualifiedName(ip, gpa, io, tid, nav_name), | |
| 9450 | .val = func_index, | |
| 9451 | .is_const = fn_owner_nav.status.fully_resolved.is_const, | |
| 9452 | .alignment = fn_owner_nav.status.fully_resolved.alignment, | |
| 9453 | .@"linksection" = fn_owner_nav.status.fully_resolved.@"linksection", | |
| 9454 | .@"addrspace" = fn_owner_nav.status.fully_resolved.@"addrspace", | |
| 10400 | 9455 | }); |
| 10401 | extra.appendSliceAssumeCapacity(.{@ptrCast(ini.captures)}); | |
| 10402 | return .{ | |
| 10403 | .wip = .{ | |
| 10404 | .tid = tid, | |
| 10405 | .index = gop.put(), | |
| 10406 | .type_name_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "name").?, | |
| 10407 | .name_nav_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "name_nav").?, | |
| 10408 | .namespace_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "namespace").?, | |
| 10409 | }, | |
| 10410 | }; | |
| 9456 | ||
| 9457 | // Populate the owner_nav field which was left undefined until now. | |
| 9458 | extra.view().items(.@"0")[ | |
| 9459 | func_extra_index + std.meta.fieldIndex(Tag.FuncInstance, "owner_nav").? | |
| 9460 | ] = @intFromEnum(nav_index); | |
| 10411 | 9461 | } |
| 10412 | 9462 | |
| 10413 | 9463 | pub fn getIfExists(ip: *const InternPool, key: Key) ?Index { |
| ... | ... | @@ -10534,6 +9584,9 @@ fn addExtraAssumeCapacity(extra: Local.Extra.Mutable, item: anytype) u32 { |
| 10534 | 9584 | TrackedInst.Index, |
| 10535 | 9585 | TrackedInst.Index.Optional, |
| 10536 | 9586 | ComptimeAllocIndex, |
| 9587 | @FieldType(Tag.TypeStructPacked, "captures_len"), | |
| 9588 | @FieldType(Tag.TypeUnionPacked, "captures_len"), | |
| 9589 | @FieldType(Tag.TypeEnum, "captures_len"), | |
| 10537 | 9590 | => @intFromEnum(@field(item, field.name)), |
| 10538 | 9591 | |
| 10539 | 9592 | u32, |
| ... | ... | @@ -10545,7 +9598,6 @@ fn addExtraAssumeCapacity(extra: Local.Extra.Mutable, item: anytype) u32 { |
| 10545 | 9598 | Tag.TypePointer.PackedOffset, |
| 10546 | 9599 | Tag.TypeUnion.Flags, |
| 10547 | 9600 | Tag.TypeStruct.Flags, |
| 10548 | Tag.TypeStructPacked.Flags, | |
| 10549 | 9601 | => @bitCast(@field(item, field.name)), |
| 10550 | 9602 | |
| 10551 | 9603 | else => @compileError("bad field type: " ++ @typeName(field.type)), |
| ... | ... | @@ -10597,6 +9649,9 @@ fn extraDataTrail(extra: Local.Extra, comptime T: type, index: u32) struct { dat |
| 10597 | 9649 | TrackedInst.Index, |
| 10598 | 9650 | TrackedInst.Index.Optional, |
| 10599 | 9651 | ComptimeAllocIndex, |
| 9652 | @FieldType(Tag.TypeStructPacked, "captures_len"), | |
| 9653 | @FieldType(Tag.TypeUnionPacked, "captures_len"), | |
| 9654 | @FieldType(Tag.TypeEnum, "captures_len"), | |
| 10600 | 9655 | => @enumFromInt(extra_item), |
| 10601 | 9656 | |
| 10602 | 9657 | u32, |
| ... | ... | @@ -10607,7 +9662,6 @@ fn extraDataTrail(extra: Local.Extra, comptime T: type, index: u32) struct { dat |
| 10607 | 9662 | Tag.TypePointer.PackedOffset, |
| 10608 | 9663 | Tag.TypeUnion.Flags, |
| 10609 | 9664 | Tag.TypeStruct.Flags, |
| 10610 | Tag.TypeStructPacked.Flags, | |
| 10611 | 9665 | FuncAnalysis, |
| 10612 | 9666 | => @bitCast(extra_item), |
| 10613 | 9667 | |
| ... | ... | @@ -10786,7 +9840,7 @@ pub fn getCoerced( |
| 10786 | 9840 | .int => |int| switch (ip.indexToKey(new_ty)) { |
| 10787 | 9841 | .enum_type => return ip.get(gpa, io, tid, .{ .enum_tag = .{ |
| 10788 | 9842 | .ty = new_ty, |
| 10789 | .int = try ip.getCoerced(gpa, io, tid, val, ip.loadEnumType(new_ty).tag_ty), | |
| 9843 | .int = try ip.getCoerced(gpa, io, tid, val, ip.loadEnumType(new_ty).int_tag_type), | |
| 10790 | 9844 | } }), |
| 10791 | 9845 | .ptr_type => switch (int.storage) { |
| 10792 | 9846 | inline .u64, .i64 => |int_val| return ip.get(gpa, io, tid, .{ .ptr = .{ |
| ... | ... | @@ -10795,7 +9849,6 @@ pub fn getCoerced( |
| 10795 | 9849 | .byte_offset = @intCast(int_val), |
| 10796 | 9850 | } }), |
| 10797 | 9851 | .big_int => unreachable, // must be a usize |
| 10798 | .lazy_align, .lazy_size => {}, | |
| 10799 | 9852 | }, |
| 10800 | 9853 | else => if (ip.isIntegerType(new_ty)) |
| 10801 | 9854 | return ip.getCoercedInts(gpa, io, tid, int, new_ty), |
| ... | ... | @@ -10825,11 +9878,11 @@ pub fn getCoerced( |
| 10825 | 9878 | const index = enum_type.nameIndex(ip, enum_literal).?; |
| 10826 | 9879 | return ip.get(gpa, io, tid, .{ .enum_tag = .{ |
| 10827 | 9880 | .ty = new_ty, |
| 10828 | .int = if (enum_type.values.len != 0) | |
| 10829 | enum_type.values.get(ip)[index] | |
| 9881 | .int = if (enum_type.field_values.len != 0) | |
| 9882 | enum_type.field_values.get(ip)[index] | |
| 10830 | 9883 | else |
| 10831 | 9884 | try ip.get(gpa, io, tid, .{ .int = .{ |
| 10832 | .ty = enum_type.tag_ty, | |
| 9885 | .ty = enum_type.int_tag_type, | |
| 10833 | 9886 | .storage = .{ .u64 = index }, |
| 10834 | 9887 | } }), |
| 10835 | 9888 | } }); |
| ... | ... | @@ -11266,98 +10319,137 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo |
| 11266 | 10319 | break :b @sizeOf(Tag.ErrorSet) + (@sizeOf(u32) * info.names_len); |
| 11267 | 10320 | }, |
| 11268 | 10321 | .type_inferred_error_set => 0, |
| 11269 | .type_enum_explicit, .type_enum_nonexhaustive => b: { | |
| 11270 | const info = extraData(extra_list, EnumExplicit, data); | |
| 11271 | var ints = @typeInfo(EnumExplicit).@"struct".fields.len; | |
| 11272 | if (info.zir_index == .none) ints += 1; | |
| 11273 | ints += if (info.captures_len != std.math.maxInt(u32)) | |
| 11274 | info.captures_len | |
| 11275 | else | |
| 11276 | @typeInfo(PackedU64).@"struct".fields.len; | |
| 11277 | ints += info.fields_len; | |
| 11278 | if (info.values_map != .none) ints += info.fields_len; | |
| 11279 | break :b @sizeOf(u32) * ints; | |
| 11280 | }, | |
| 11281 | .type_enum_auto => b: { | |
| 11282 | const info = extraData(extra_list, EnumAuto, data); | |
| 11283 | const ints = @typeInfo(EnumAuto).@"struct".fields.len + info.captures_len + info.fields_len; | |
| 11284 | break :b @sizeOf(u32) * ints; | |
| 10322 | .type_tuple => b: { | |
| 10323 | const info = extraData(extra_list, TypeTuple, data); | |
| 10324 | break :b @sizeOf(TypeTuple) + (@sizeOf(u32) * 2 * info.fields_len); | |
| 11285 | 10325 | }, |
| 11286 | .type_opaque => b: { | |
| 11287 | const info = extraData(extra_list, Tag.TypeOpaque, data); | |
| 11288 | const ints = @typeInfo(Tag.TypeOpaque).@"struct".fields.len + info.captures_len; | |
| 11289 | break :b @sizeOf(u32) * ints; | |
| 10326 | .type_function => b: { | |
| 10327 | const info = extraData(extra_list, Tag.TypeFunction, data); | |
| 10328 | break :b @sizeOf(Tag.TypeFunction) + | |
| 10329 | (@sizeOf(Index) * info.params_len) + | |
| 10330 | (@as(u32, 4) * @intFromBool(info.flags.has_comptime_bits)) + | |
| 10331 | (@as(u32, 4) * @intFromBool(info.flags.has_noalias_bits)); | |
| 11290 | 10332 | }, |
| 10333 | ||
| 11291 | 10334 | .type_struct => b: { |
| 10335 | var n: usize = @typeInfo(Tag.TypeStruct).@"struct".fields.len; | |
| 11292 | 10336 | const extra = extraDataTrail(extra_list, Tag.TypeStruct, data); |
| 11293 | const info = extra.data; | |
| 11294 | var ints: usize = @typeInfo(Tag.TypeStruct).@"struct".fields.len; | |
| 11295 | if (info.flags.any_captures) { | |
| 11296 | const captures_len = extra_items[extra.end]; | |
| 11297 | ints += 1 + captures_len; | |
| 10337 | switch (extra.data.flags.any_captures) { | |
| 10338 | .reified => n += 2, // type_hash: PackedU64 | |
| 10339 | .true => { | |
| 10340 | n += 1; // captures_len: u32 | |
| 10341 | n += extra_items[extra.end]; // capture: CaptureValue | |
| 10342 | }, | |
| 10343 | .false => {}, | |
| 10344 | } | |
| 10345 | n += extra.data.fields_len; // field_name: NullTerminatedString | |
| 10346 | n += extra.data.fields_len; // field_type: Index | |
| 10347 | if (extra.data.flags.any_field_defaults) { | |
| 10348 | n += extra.data.fields_len; // field_default: Index | |
| 10349 | } | |
| 10350 | if (extra.data.flags.any_field_aligns) { | |
| 10351 | n += (extra.data.fields_len + 3) / 4; // field_align: Alignment | |
| 10352 | } | |
| 10353 | if (extra.data.flags.any_comptime_fields) { | |
| 10354 | n += (extra.data.fields_len + 31) / 32; // field_is_comptime_bits: u32 | |
| 11298 | 10355 | } |
| 11299 | ints += info.fields_len; // types | |
| 11300 | ints += 1; // names_map | |
| 11301 | ints += info.fields_len; // names | |
| 11302 | if (info.flags.any_default_inits) | |
| 11303 | ints += info.fields_len; // inits | |
| 11304 | if (info.flags.any_aligned_fields) | |
| 11305 | ints += (info.fields_len + 3) / 4; // aligns | |
| 11306 | if (info.flags.any_comptime_fields) | |
| 11307 | ints += (info.fields_len + 31) / 32; // comptime bits | |
| 11308 | if (!info.flags.is_extern) | |
| 11309 | ints += info.fields_len; // runtime order | |
| 11310 | ints += info.fields_len; // offsets | |
| 11311 | break :b @sizeOf(u32) * ints; | |
| 10356 | if (extra.data.flags.layout == .auto) { | |
| 10357 | n += extra.data.fields_len; // field_runtime_order: RuntimeOrder | |
| 10358 | } | |
| 10359 | n += extra.data.fields_len; // field_offset: u32 | |
| 10360 | break :b n * @sizeOf(u32); | |
| 11312 | 10361 | }, |
| 11313 | .type_struct_packed => b: { | |
| 10362 | .type_struct_packed_auto, .type_struct_packed_explicit => b: { | |
| 10363 | var n: usize = @typeInfo(Tag.TypeStructPacked).@"struct".fields.len; | |
| 11314 | 10364 | const extra = extraDataTrail(extra_list, Tag.TypeStructPacked, data); |
| 11315 | const captures_len = if (extra.data.flags.any_captures) | |
| 11316 | extra_items[extra.end] | |
| 11317 | else | |
| 11318 | 0; | |
| 11319 | break :b @sizeOf(u32) * (@typeInfo(Tag.TypeStructPacked).@"struct".fields.len + | |
| 11320 | @intFromBool(extra.data.flags.any_captures) + captures_len + | |
| 11321 | extra.data.fields_len * 2); | |
| 10365 | switch (extra.data.captures_len) { | |
| 10366 | .reified => n += 2, // type_hash: PackedU64 | |
| 10367 | _ => |len| n += @intFromEnum(len), // capture: CaptureValue | |
| 10368 | } | |
| 10369 | n += extra.data.fields_len; // field_name: NullTerminatedString | |
| 10370 | n += extra.data.fields_len; // field_type: Index | |
| 10371 | break :b n * @sizeOf(u32); | |
| 11322 | 10372 | }, |
| 11323 | .type_struct_packed_inits => b: { | |
| 10373 | .type_struct_packed_auto_defaults, .type_struct_packed_explicit_defaults => b: { | |
| 10374 | var n: usize = @typeInfo(Tag.TypeStructPacked).@"struct".fields.len; | |
| 11324 | 10375 | const extra = extraDataTrail(extra_list, Tag.TypeStructPacked, data); |
| 11325 | const captures_len = if (extra.data.flags.any_captures) | |
| 11326 | extra_items[extra.end] | |
| 11327 | else | |
| 11328 | 0; | |
| 11329 | break :b @sizeOf(u32) * (@typeInfo(Tag.TypeStructPacked).@"struct".fields.len + | |
| 11330 | @intFromBool(extra.data.flags.any_captures) + captures_len + | |
| 11331 | extra.data.fields_len * 3); | |
| 11332 | }, | |
| 11333 | .type_tuple => b: { | |
| 11334 | const info = extraData(extra_list, TypeTuple, data); | |
| 11335 | break :b @sizeOf(TypeTuple) + (@sizeOf(u32) * 2 * info.fields_len); | |
| 10376 | switch (extra.data.captures_len) { | |
| 10377 | .reified => n += 2, // type_hash: PackedU64 | |
| 10378 | _ => |len| n += @intFromEnum(len), // capture: CaptureValue | |
| 10379 | } | |
| 10380 | n += extra.data.fields_len; // field_name: NullTerminatedString | |
| 10381 | n += extra.data.fields_len; // field_type: Index | |
| 10382 | n += extra.data.fields_len; // field_default: Index | |
| 10383 | break :b n * @sizeOf(u32); | |
| 11336 | 10384 | }, |
| 11337 | ||
| 11338 | 10385 | .type_union => b: { |
| 10386 | var n: usize = @typeInfo(Tag.TypeUnion).@"struct".fields.len; | |
| 11339 | 10387 | const extra = extraDataTrail(extra_list, Tag.TypeUnion, data); |
| 11340 | const captures_len = if (extra.data.flags.any_captures) | |
| 11341 | extra_items[extra.end] | |
| 11342 | else | |
| 11343 | 0; | |
| 11344 | const per_field = @sizeOf(u32); // field type | |
| 11345 | // 1 byte per field for alignment, rounded up to the nearest 4 bytes | |
| 11346 | const alignments = if (extra.data.flags.any_aligned_fields) | |
| 11347 | ((extra.data.fields_len + 3) / 4) * 4 | |
| 11348 | else | |
| 11349 | 0; | |
| 11350 | break :b @sizeOf(Tag.TypeUnion) + | |
| 11351 | 4 * (@intFromBool(extra.data.flags.any_captures) + captures_len) + | |
| 11352 | (extra.data.fields_len * per_field) + alignments; | |
| 10388 | switch (extra.data.flags.any_captures) { | |
| 10389 | .reified => n += 2, // type_hash: PackedU64 | |
| 10390 | .true => { | |
| 10391 | n += 1; // captures_len: u32 | |
| 10392 | n += extra_items[extra.end]; // capture: CaptureValue | |
| 10393 | }, | |
| 10394 | .false => {}, | |
| 10395 | } | |
| 10396 | n += extra.data.fields_len; // field_type: Index | |
| 10397 | if (extra.data.flags.any_field_aligns) { | |
| 10398 | n += (extra.data.fields_len + 3) / 4; // field_align: Alignment | |
| 10399 | } | |
| 10400 | break :b n * @sizeOf(u32); | |
| 11353 | 10401 | }, |
| 11354 | ||
| 11355 | .type_function => b: { | |
| 11356 | const info = extraData(extra_list, Tag.TypeFunction, data); | |
| 11357 | break :b @sizeOf(Tag.TypeFunction) + | |
| 11358 | (@sizeOf(Index) * info.params_len) + | |
| 11359 | (@as(u32, 4) * @intFromBool(info.flags.has_comptime_bits)) + | |
| 11360 | (@as(u32, 4) * @intFromBool(info.flags.has_noalias_bits)); | |
| 10402 | .type_union_packed_auto, .type_union_packed_explicit => b: { | |
| 10403 | var n: usize = @typeInfo(Tag.TypeUnionPacked).@"struct".fields.len; | |
| 10404 | const extra = extraDataTrail(extra_list, Tag.TypeUnionPacked, data); | |
| 10405 | switch (extra.data.captures_len) { | |
| 10406 | .reified => n += 2, // type_hash: PackedU64 | |
| 10407 | _ => |len| n += @intFromEnum(len), // capture: CaptureValue | |
| 10408 | } | |
| 10409 | n += extra.data.fields_len; // field_type: Index | |
| 10410 | break :b n * @sizeOf(u32); | |
| 10411 | }, | |
| 10412 | .type_enum_auto => b: { | |
| 10413 | var n: usize = @typeInfo(Tag.TypeEnum).@"struct".fields.len; | |
| 10414 | const extra = extraData(extra_list, Tag.TypeEnum, data); | |
| 10415 | switch (extra.captures_len) { | |
| 10416 | .generated_union_tag => n += 1, // owner_union: Index | |
| 10417 | .reified => { | |
| 10418 | n += 1; // zir_index: TrackedInst.Index, | |
| 10419 | n += 2; // type_hash: PackedU64 | |
| 10420 | }, | |
| 10421 | _ => |len| { | |
| 10422 | n += 1; // zir_index: TrackedInst.Index, | |
| 10423 | n += @intFromEnum(len); // capture: CaptureValue | |
| 10424 | }, | |
| 10425 | } | |
| 10426 | n += extra.fields_len; // field_name: NullTerminatedString | |
| 10427 | break :b n * @sizeOf(u32); | |
| 10428 | }, | |
| 10429 | .type_enum_explicit, .type_enum_nonexhaustive => b: { | |
| 10430 | var n: usize = @typeInfo(Tag.TypeEnum).@"struct".fields.len; | |
| 10431 | const extra = extraData(extra_list, Tag.TypeEnum, data); | |
| 10432 | switch (extra.captures_len) { | |
| 10433 | .generated_union_tag => n += 1, // owner_union: Index | |
| 10434 | .reified => { | |
| 10435 | n += 1; // zir_index: TrackedInst.Index, | |
| 10436 | n += 2; // type_hash: PackedU64 | |
| 10437 | }, | |
| 10438 | _ => |len| { | |
| 10439 | n += 1; // zir_index: TrackedInst.Index, | |
| 10440 | n += @intFromEnum(len); // capture: CaptureValue | |
| 10441 | }, | |
| 10442 | } | |
| 10443 | n += 1; // field_value_map: MapIndex | |
| 10444 | n += extra.fields_len; // field_name: NullTerminatedString | |
| 10445 | n += extra.fields_len; // field_value: Index | |
| 10446 | break :b n * @sizeOf(u32); | |
| 10447 | }, | |
| 10448 | .type_opaque => b: { | |
| 10449 | var n: usize = @typeInfo(Tag.TypeEnum).@"struct".fields.len; | |
| 10450 | const extra = extraData(extra_list, Tag.TypeOpaque, data); | |
| 10451 | n += extra.captures_len; // capture: CaptureValue | |
| 10452 | break :b n * @sizeOf(u32); | |
| 11361 | 10453 | }, |
| 11362 | 10454 | |
| 11363 | 10455 | .undef => 0, |
| ... | ... | @@ -11393,8 +10485,6 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo |
| 11393 | 10485 | break :b @sizeOf(Int) + int.limbs_len * @sizeOf(Limb); |
| 11394 | 10486 | }, |
| 11395 | 10487 | |
| 11396 | .int_lazy_align, .int_lazy_size => @sizeOf(IntLazy), | |
| 11397 | ||
| 11398 | 10488 | .error_set_error, .error_union_error => @sizeOf(Key.Error), |
| 11399 | 10489 | .error_union_payload => @sizeOf(Tag.TypeValue), |
| 11400 | 10490 | .enum_literal => 0, |
| ... | ... | @@ -11484,16 +10574,20 @@ fn dumpAllFallible(ip: *const InternPool, w: *Io.Writer) anyerror!void { |
| 11484 | 10574 | .type_anyerror_union, |
| 11485 | 10575 | .type_error_set, |
| 11486 | 10576 | .type_inferred_error_set, |
| 10577 | .type_tuple, | |
| 10578 | .type_function, | |
| 10579 | .type_struct, | |
| 10580 | .type_struct_packed_auto, | |
| 10581 | .type_struct_packed_explicit, | |
| 10582 | .type_struct_packed_auto_defaults, | |
| 10583 | .type_struct_packed_explicit_defaults, | |
| 10584 | .type_union, | |
| 10585 | .type_union_packed_auto, | |
| 10586 | .type_union_packed_explicit, | |
| 10587 | .type_enum_auto, | |
| 11487 | 10588 | .type_enum_explicit, |
| 11488 | 10589 | .type_enum_nonexhaustive, |
| 11489 | .type_enum_auto, | |
| 11490 | 10590 | .type_opaque, |
| 11491 | .type_struct, | |
| 11492 | .type_struct_packed, | |
| 11493 | .type_struct_packed_inits, | |
| 11494 | .type_tuple, | |
| 11495 | .type_union, | |
| 11496 | .type_function, | |
| 11497 | 10591 | .undef, |
| 11498 | 10592 | .ptr_nav, |
| 11499 | 10593 | .ptr_comptime_alloc, |
| ... | ... | @@ -11517,8 +10611,6 @@ fn dumpAllFallible(ip: *const InternPool, w: *Io.Writer) anyerror!void { |
| 11517 | 10611 | .int_small, |
| 11518 | 10612 | .int_positive, |
| 11519 | 10613 | .int_negative, |
| 11520 | .int_lazy_align, | |
| 11521 | .int_lazy_size, | |
| 11522 | 10614 | .error_set_error, |
| 11523 | 10615 | .error_union_error, |
| 11524 | 10616 | .error_union_payload, |
| ... | ... | @@ -12245,16 +11337,20 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index { |
| 12245 | 11337 | .type_anyerror_union, |
| 12246 | 11338 | .type_error_set, |
| 12247 | 11339 | .type_inferred_error_set, |
| 11340 | .type_tuple, | |
| 11341 | .type_function, | |
| 11342 | .type_struct, | |
| 11343 | .type_struct_packed_auto, | |
| 11344 | .type_struct_packed_explicit, | |
| 11345 | .type_struct_packed_auto_defaults, | |
| 11346 | .type_struct_packed_explicit_defaults, | |
| 11347 | .type_union, | |
| 11348 | .type_union_packed_auto, | |
| 11349 | .type_union_packed_explicit, | |
| 12248 | 11350 | .type_enum_auto, |
| 12249 | 11351 | .type_enum_explicit, |
| 12250 | 11352 | .type_enum_nonexhaustive, |
| 12251 | 11353 | .type_opaque, |
| 12252 | .type_struct, | |
| 12253 | .type_struct_packed, | |
| 12254 | .type_struct_packed_inits, | |
| 12255 | .type_tuple, | |
| 12256 | .type_union, | |
| 12257 | .type_function, | |
| 12258 | 11354 | => .type_type, |
| 12259 | 11355 | |
| 12260 | 11356 | .undef, |
| ... | ... | @@ -12278,8 +11374,6 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index { |
| 12278 | 11374 | .opt_payload, |
| 12279 | 11375 | .error_union_payload, |
| 12280 | 11376 | .int_small, |
| 12281 | .int_lazy_align, | |
| 12282 | .int_lazy_size, | |
| 12283 | 11377 | .error_set_error, |
| 12284 | 11378 | .error_union_error, |
| 12285 | 11379 | .enum_tag, |
| ... | ... | @@ -12613,22 +11707,26 @@ pub fn zigTypeTag(ip: *const InternPool, index: Index) std.builtin.TypeId { |
| 12613 | 11707 | .type_inferred_error_set, |
| 12614 | 11708 | => .error_set, |
| 12615 | 11709 | |
| 12616 | .type_enum_auto, | |
| 12617 | .type_enum_explicit, | |
| 12618 | .type_enum_nonexhaustive, | |
| 12619 | => .@"enum", | |
| 12620 | ||
| 12621 | 11710 | .simple_type => unreachable, // handled via Index tag above |
| 12622 | 11711 | |
| 12623 | .type_opaque => .@"opaque", | |
| 11712 | .type_tuple => .@"struct", | |
| 12624 | 11713 | |
| 12625 | 11714 | .type_struct, |
| 12626 | .type_struct_packed, | |
| 12627 | .type_struct_packed_inits, | |
| 12628 | .type_tuple, | |
| 11715 | .type_struct_packed_auto, | |
| 11716 | .type_struct_packed_explicit, | |
| 11717 | .type_struct_packed_auto_defaults, | |
| 11718 | .type_struct_packed_explicit_defaults, | |
| 12629 | 11719 | => .@"struct", |
| 12630 | ||
| 12631 | .type_union => .@"union", | |
| 11720 | .type_union, | |
| 11721 | .type_union_packed_auto, | |
| 11722 | .type_union_packed_explicit, | |
| 11723 | => .@"union", | |
| 11724 | .type_enum_auto, | |
| 11725 | .type_enum_explicit, | |
| 11726 | .type_enum_nonexhaustive, | |
| 11727 | => .@"enum", | |
| 11728 | .type_opaque, | |
| 11729 | => .@"opaque", | |
| 12632 | 11730 | |
| 12633 | 11731 | .type_function => .@"fn", |
| 12634 | 11732 | |
| ... | ... | @@ -12658,8 +11756,6 @@ pub fn zigTypeTag(ip: *const InternPool, index: Index) std.builtin.TypeId { |
| 12658 | 11756 | .int_small, |
| 12659 | 11757 | .int_positive, |
| 12660 | 11758 | .int_negative, |
| 12661 | .int_lazy_align, | |
| 12662 | .int_lazy_size, | |
| 12663 | 11759 | .error_set_error, |
| 12664 | 11760 | .error_union_error, |
| 12665 | 11761 | .error_union_payload, |
| ... | ... | @@ -13169,3 +12265,113 @@ const PackedCallingConvention = packed struct(u18) { |
| 13169 | 12265 | }; |
| 13170 | 12266 | } |
| 13171 | 12267 | }; |
| 12268 | ||
| 12269 | /// Asserts that `struct_type` is a non-packed struct type. | |
| 12270 | /// As well as calling this function, the caller must also populate these arrays: | |
| 12271 | /// * `field_types` | |
| 12272 | /// * `field_aligns` | |
| 12273 | /// * `field_runtime_order` | |
| 12274 | /// * `field_offsets` | |
| 12275 | pub fn resolveStructLayout( | |
| 12276 | ip: *InternPool, | |
| 12277 | io: Io, | |
| 12278 | struct_type: Index, | |
| 12279 | size: u32, | |
| 12280 | alignment: Alignment, | |
| 12281 | has_no_possible_value: bool, | |
| 12282 | has_one_possible_value: bool, | |
| 12283 | comptime_only: bool, | |
| 12284 | ) void { | |
| 12285 | const unwrapped_index = struct_type.unwrap(ip); | |
| 12286 | ||
| 12287 | const local = ip.getLocal(unwrapped_index.tid); | |
| 12288 | local.mutate.extra.mutex.lockUncancelable(io); | |
| 12289 | defer local.mutate.extra.mutex.unlock(io); | |
| 12290 | ||
| 12291 | const extra_items = local.shared.extra.view().items(.@"0"); | |
| 12292 | const item = unwrapped_index.getItem(ip); | |
| 12293 | assert(item.tag == .type_struct); | |
| 12294 | ||
| 12295 | extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "size").?] = size; | |
| 12296 | const flags: *Tag.TypeStruct.Flags = @ptrCast(&extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "flags").?]); | |
| 12297 | flags.has_no_possible_value = has_no_possible_value; | |
| 12298 | flags.has_one_possible_value = has_one_possible_value; | |
| 12299 | flags.comptime_only = comptime_only; | |
| 12300 | flags.alignment = alignment; | |
| 12301 | } | |
| 12302 | ||
| 12303 | /// Asserts that `union_type` is a non-packed union type. | |
| 12304 | /// As well as calling this function, the caller must also populate these arrays: | |
| 12305 | /// * `field_types` | |
| 12306 | /// * `field_aligns` | |
| 12307 | pub fn resolveUnionLayout( | |
| 12308 | ip: *InternPool, | |
| 12309 | io: Io, | |
| 12310 | union_type: Index, | |
| 12311 | size: u32, | |
| 12312 | padding: u32, | |
| 12313 | alignment: Alignment, | |
| 12314 | has_no_possible_value: bool, | |
| 12315 | has_one_possible_value: bool, | |
| 12316 | comptime_only: bool, | |
| 12317 | ) void { | |
| 12318 | const unwrapped_index = union_type.unwrap(ip); | |
| 12319 | ||
| 12320 | const local = ip.getLocal(unwrapped_index.tid); | |
| 12321 | local.mutate.extra.mutex.lockUncancelable(io); | |
| 12322 | defer local.mutate.extra.mutex.unlock(io); | |
| 12323 | ||
| 12324 | const extra_items = local.shared.extra.view().items(.@"0"); | |
| 12325 | const item = unwrapped_index.getItem(ip); | |
| 12326 | assert(item.tag == .type_union); | |
| 12327 | ||
| 12328 | extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnion, "size").?] = size; | |
| 12329 | extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnion, "padding").?] = padding; | |
| 12330 | const flags: *Tag.TypeUnion.Flags = @ptrCast(&extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnion, "flags").?]); | |
| 12331 | flags.has_no_possible_value = has_no_possible_value; | |
| 12332 | flags.has_one_possible_value = has_one_possible_value; | |
| 12333 | flags.comptime_only = comptime_only; | |
| 12334 | flags.alignment = alignment; | |
| 12335 | } | |
| 12336 | ||
| 12337 | /// Asserts that `struct_type` is a packed struct type. | |
| 12338 | pub fn resolvePackedStructBackingInt(ip: *InternPool, io: Io, struct_type: Index, backing_int_type: Index) void { | |
| 12339 | const unwrapped_index = struct_type.unwrap(ip); | |
| 12340 | ||
| 12341 | const local = ip.getLocal(unwrapped_index.tid); | |
| 12342 | local.mutate.extra.mutex.lockUncancelable(io); | |
| 12343 | defer local.mutate.extra.mutex.unlock(io); | |
| 12344 | ||
| 12345 | const extra_items = local.shared.extra.view().items(.@"0"); | |
| 12346 | const item = unwrapped_index.getItem(ip); | |
| 12347 | switch (item.tag) { | |
| 12348 | .type_struct_packed_auto, | |
| 12349 | .type_struct_packed_explicit, | |
| 12350 | .type_struct_packed_auto_defaults, | |
| 12351 | .type_struct_packed_explicit_defaults, | |
| 12352 | => {}, | |
| 12353 | else => unreachable, | |
| 12354 | } | |
| 12355 | ||
| 12356 | extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "backing_int_type").?] = @intFromEnum(backing_int_type); | |
| 12357 | } | |
| 12358 | ||
| 12359 | /// Asserts that `union_type` is a packed union type. | |
| 12360 | pub fn resolvePackedUnionBackingInt(ip: *InternPool, io: Io, union_type: Index, backing_int_type: Index) void { | |
| 12361 | const unwrapped_index = union_type.unwrap(ip); | |
| 12362 | ||
| 12363 | const local = ip.getLocal(unwrapped_index.tid); | |
| 12364 | local.mutate.extra.mutex.lockUncancelable(io); | |
| 12365 | defer local.mutate.extra.mutex.unlock(io); | |
| 12366 | ||
| 12367 | const extra_items = local.shared.extra.view().items(.@"0"); | |
| 12368 | const item = unwrapped_index.getItem(ip); | |
| 12369 | switch (item.tag) { | |
| 12370 | .type_union_packed_auto, | |
| 12371 | .type_union_packed_explicit, | |
| 12372 | => {}, | |
| 12373 | else => unreachable, | |
| 12374 | } | |
| 12375 | ||
| 12376 | extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnionPacked, "backing_int_type").?] = @intFromEnum(backing_int_type); | |
| 12377 | } |
src/Sema.zig+2201-4328| ... | ... | @@ -173,13 +173,17 @@ const ComptimeAlloc = struct { |
| 173 | 173 | runtime_index: RuntimeIndex, |
| 174 | 174 | }; |
| 175 | 175 | |
| 176 | /// Asserts that `ty` is not an OPV type. | |
| 176 | 177 | /// `src` may be `null` if `is_const` will be set. |
| 177 | 178 | fn newComptimeAlloc(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type, alignment: Alignment) !ComptimeAllocIndex { |
| 178 | 179 | const pt = sema.pt; |
| 179 | const init_val = try sema.typeHasOnePossibleValue(ty) orelse try pt.undefValue(ty); | |
| 180 | ||
| 181 | // Explicit guard because this call mutates the InternPool so cannot be optimized out. | |
| 182 | if (std.debug.runtime_safety) assert(ty.onePossibleValue(pt) catch @panic("") == null); | |
| 183 | ||
| 180 | 184 | const idx = sema.comptime_allocs.items.len; |
| 181 | 185 | try sema.comptime_allocs.append(sema.gpa, .{ |
| 182 | .val = .{ .interned = init_val.toIntern() }, | |
| 186 | .val = .{ .interned = (try pt.undefValue(ty)).toIntern() }, | |
| 183 | 187 | .is_const = false, |
| 184 | 188 | .src = src, |
| 185 | 189 | .alignment = alignment, |
| ... | ... | @@ -1382,10 +1386,10 @@ fn analyzeBodyInner( |
| 1382 | 1386 | const extended = datas[@intFromEnum(inst)].extended; |
| 1383 | 1387 | break :ext switch (extended.opcode) { |
| 1384 | 1388 | // zig fmt: off |
| 1385 | .struct_decl => try sema.zirStructDecl( block, extended, inst), | |
| 1386 | .enum_decl => try sema.zirEnumDecl( block, extended, inst), | |
| 1387 | .union_decl => try sema.zirUnionDecl( block, extended, inst), | |
| 1388 | .opaque_decl => try sema.zirOpaqueDecl( block, extended, inst), | |
| 1389 | .struct_decl => try sema.zirStructDecl( block, inst), | |
| 1390 | .enum_decl => try sema.zirEnumDecl( block, inst), | |
| 1391 | .union_decl => try sema.zirUnionDecl( block, inst), | |
| 1392 | .opaque_decl => try sema.zirOpaqueDecl( block, inst), | |
| 1389 | 1393 | .tuple_decl => try sema.zirTupleDecl( block, extended), |
| 1390 | 1394 | .this => try sema.zirThis( block, extended), |
| 1391 | 1395 | .ret_addr => try sema.zirRetAddr( block, extended), |
| ... | ... | @@ -1993,6 +1997,24 @@ fn analyzeBodyInner( |
| 1993 | 1997 | assert(sema.isNoReturn(block.instructions.items[block.instructions.items.len - 1].toRef())); |
| 1994 | 1998 | break; |
| 1995 | 1999 | } |
| 2000 | // <MLUGG TODO REMOVE THIS BLOCK, SILLY OPV CHECK> | |
| 2001 | if (air_inst.toIndex()) |air_inst_index| { | |
| 2002 | switch (sema.air_instructions.items(.tag)[@intFromEnum(air_inst_index)]) { | |
| 2003 | .inferred_alloc, .inferred_alloc_comptime => {}, | |
| 2004 | else => { | |
| 2005 | assert(sema.typeOf(air_inst).onePossibleValue(pt) catch @panic("") == null); | |
| 2006 | sema.typeOf(air_inst).assertHasLayout(zcu); | |
| 2007 | }, | |
| 2008 | } | |
| 2009 | } else { | |
| 2010 | switch (tags[@intFromEnum(inst)]) { | |
| 2011 | // MLUGG TODO: do we actually *want* this exception? we could arguably simplify things without it | |
| 2012 | // e.g. analyzeNavVal could stop doing ensureLayoutResolved in most cases (`extern` is an exception) and instead do `assertHasLayout` | |
| 2013 | .func, .func_inferred, .func_fancy => {}, // exception: we're in a func decl, layout will get resolved in a bit by `analyzeNavVal` | |
| 2014 | else => sema.typeOf(air_inst).assertHasLayout(zcu), | |
| 2015 | } | |
| 2016 | } | |
| 2017 | // </MLUGG TODO REMOVE THIS BLOCK, SILLY OPV CHECK> | |
| 1996 | 2018 | map.putAssumeCapacity(inst, air_inst); |
| 1997 | 2019 | i += 1; |
| 1998 | 2020 | } |
| ... | ... | @@ -2190,7 +2212,7 @@ fn genericPoisonReason(sema: *Sema, block: *Block, ref: Zir.Inst.Ref) GenericPoi |
| 2190 | 2212 | } |
| 2191 | 2213 | } |
| 2192 | 2214 | |
| 2193 | fn analyzeAsType( | |
| 2215 | pub fn analyzeAsType( | |
| 2194 | 2216 | sema: *Sema, |
| 2195 | 2217 | block: *Block, |
| 2196 | 2218 | src: LazySrcLoc, |
| ... | ... | @@ -2227,7 +2249,6 @@ pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize) |
| 2227 | 2249 | |
| 2228 | 2250 | // var st: StackTrace = undefined; |
| 2229 | 2251 | const stack_trace_ty = try sema.getBuiltinType(block.nodeOffset(.zero), .StackTrace); |
| 2230 | try stack_trace_ty.resolveFields(pt); | |
| 2231 | 2252 | const st_ptr = try err_trace_block.addTy(.alloc, try pt.singleMutPtrType(stack_trace_ty)); |
| 2232 | 2253 | |
| 2233 | 2254 | // st.instruction_addresses = &addrs; |
| ... | ... | @@ -2247,14 +2268,11 @@ pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize) |
| 2247 | 2268 | } |
| 2248 | 2269 | |
| 2249 | 2270 | /// Return the Value corresponding to a given AIR ref, or `null` if it refers to a runtime value. |
| 2250 | fn resolveValue(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Value { | |
| 2271 | /// TODO MLUGG: remove the error union return! | |
| 2272 | fn resolveValue(sema: *Sema, inst: Air.Inst.Ref) error{}!?Value { | |
| 2251 | 2273 | const zcu = sema.pt.zcu; |
| 2252 | 2274 | assert(inst != .none); |
| 2253 | 2275 | |
| 2254 | if (try sema.typeHasOnePossibleValue(sema.typeOf(inst))) |opv| { | |
| 2255 | return opv; | |
| 2256 | } | |
| 2257 | ||
| 2258 | 2276 | if (inst.toInterned()) |ip_index| { |
| 2259 | 2277 | const val: Value = .fromInterned(ip_index); |
| 2260 | 2278 | assert(val.getVariable(zcu) == null); |
| ... | ... | @@ -2267,12 +2285,18 @@ fn resolveValue(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Value { |
| 2267 | 2285 | .inferred_alloc_comptime => unreachable, // assertion failure |
| 2268 | 2286 | else => {}, |
| 2269 | 2287 | } |
| 2288 | // Assert that the type is not OPV -- if it was, the value would have been comptime-known. | |
| 2289 | // Explicit guard because this could add to the InternPool so cannot be optimized away. | |
| 2290 | if (std.debug.runtime_safety) { | |
| 2291 | const opv = sema.typeOf(inst).onePossibleValue(sema.pt) catch @panic("oom in assert"); | |
| 2292 | assert(opv == null); | |
| 2293 | } | |
| 2270 | 2294 | return null; |
| 2271 | 2295 | } |
| 2272 | 2296 | } |
| 2273 | 2297 | |
| 2274 | 2298 | /// Like `resolveValue`, but emits an error if the value is not comptime-known. |
| 2275 | fn resolveConstValue( | |
| 2299 | pub fn resolveConstValue( | |
| 2276 | 2300 | sema: *Sema, |
| 2277 | 2301 | block: *Block, |
| 2278 | 2302 | src: LazySrcLoc, |
| ... | ... | @@ -2301,7 +2325,7 @@ fn resolveDefinedValue( |
| 2301 | 2325 | } |
| 2302 | 2326 | |
| 2303 | 2327 | /// Like `resolveValue`, but emits an error if the value is not comptime-known or is undefined. |
| 2304 | fn resolveConstDefinedValue( | |
| 2328 | pub fn resolveConstDefinedValue( | |
| 2305 | 2329 | sema: *Sema, |
| 2306 | 2330 | block: *Block, |
| 2307 | 2331 | src: LazySrcLoc, |
| ... | ... | @@ -2315,11 +2339,6 @@ fn resolveConstDefinedValue( |
| 2315 | 2339 | return val; |
| 2316 | 2340 | } |
| 2317 | 2341 | |
| 2318 | /// Like `resolveValue`, but recursively resolves lazy values before returning. | |
| 2319 | fn resolveValueResolveLazy(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Value { | |
| 2320 | return try sema.resolveLazyValue((try sema.resolveValue(inst)) orelse return null); | |
| 2321 | } | |
| 2322 | ||
| 2323 | 2342 | /// Value Tag may be `undef` or `variable`. |
| 2324 | 2343 | pub fn resolveFinalDeclValue( |
| 2325 | 2344 | sema: *Sema, |
| ... | ... | @@ -2439,13 +2458,14 @@ fn failWithExpectedOptionalType(sema: *Sema, block: *Block, src: LazySrcLoc, non |
| 2439 | 2458 | |
| 2440 | 2459 | fn failWithArrayInitNotSupported(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError { |
| 2441 | 2460 | const pt = sema.pt; |
| 2461 | const zcu = pt.zcu; | |
| 2442 | 2462 | const msg = msg: { |
| 2443 | 2463 | const msg = try sema.errMsg(src, "type '{f}' does not support array initialization syntax", .{ |
| 2444 | 2464 | ty.fmt(pt), |
| 2445 | 2465 | }); |
| 2446 | 2466 | errdefer msg.destroy(sema.gpa); |
| 2447 | if (ty.isSlice(pt.zcu)) { | |
| 2448 | try sema.errNote(src, msg, "inferred array length is specified with an underscore: '[_]{f}'", .{ty.elemType2(pt.zcu).fmt(pt)}); | |
| 2467 | if (ty.isSlice(zcu)) { | |
| 2468 | try sema.errNote(src, msg, "inferred array length is specified with an underscore: '[_]{f}'", .{ty.childType(zcu).fmt(pt)}); | |
| 2449 | 2469 | } |
| 2450 | 2470 | break :msg msg; |
| 2451 | 2471 | }; |
| ... | ... | @@ -2644,7 +2664,7 @@ pub fn fail( |
| 2644 | 2664 | src: LazySrcLoc, |
| 2645 | 2665 | comptime format: []const u8, |
| 2646 | 2666 | args: anytype, |
| 2647 | ) CompileError { | |
| 2667 | ) SemaError { | |
| 2648 | 2668 | const err_msg = try sema.errMsg(src, format, args); |
| 2649 | 2669 | inline for (args) |arg| { |
| 2650 | 2670 | if (@TypeOf(arg) == Type.Formatter) { |
| ... | ... | @@ -2798,27 +2818,26 @@ fn analyzeAsInt( |
| 2798 | 2818 | ) !u64 { |
| 2799 | 2819 | const coerced = try sema.coerce(block, dest_ty, air_ref, src); |
| 2800 | 2820 | const val = try sema.resolveConstDefinedValue(block, src, coerced, reason); |
| 2801 | return try val.toUnsignedIntSema(sema.pt); | |
| 2821 | return val.toUnsignedInt(sema.pt.zcu); | |
| 2802 | 2822 | } |
| 2803 | 2823 | |
| 2804 | 2824 | fn analyzeValueAsCallconv( |
| 2805 | 2825 | sema: *Sema, |
| 2806 | 2826 | block: *Block, |
| 2807 | 2827 | src: LazySrcLoc, |
| 2808 | unresolved_val: Value, | |
| 2828 | val: Value, | |
| 2809 | 2829 | ) !std.builtin.CallingConvention { |
| 2810 | return interpretBuiltinType(sema, block, src, unresolved_val, std.builtin.CallingConvention); | |
| 2830 | return interpretBuiltinType(sema, block, src, val, std.builtin.CallingConvention); | |
| 2811 | 2831 | } |
| 2812 | 2832 | |
| 2813 | 2833 | fn interpretBuiltinType( |
| 2814 | 2834 | sema: *Sema, |
| 2815 | 2835 | block: *Block, |
| 2816 | 2836 | src: LazySrcLoc, |
| 2817 | unresolved_val: Value, | |
| 2837 | val: Value, | |
| 2818 | 2838 | comptime T: type, |
| 2819 | 2839 | ) !T { |
| 2820 | const resolved_val = try sema.resolveLazyValue(unresolved_val); | |
| 2821 | return resolved_val.interpret(T, sema.pt) catch |err| switch (err) { | |
| 2840 | return val.interpret(T, sema.pt) catch |err| switch (err) { | |
| 2822 | 2841 | error.OutOfMemory => |e| return e, |
| 2823 | 2842 | error.UndefinedValue => return sema.failWithUseOfUndef(block, src, null), |
| 2824 | 2843 | error.TypeMismatch => @panic("std.builtin is corrupt"), |
| ... | ... | @@ -2913,7 +2932,13 @@ fn validateTupleFieldType( |
| 2913 | 2932 | |
| 2914 | 2933 | /// Given a ZIR extra index which points to a list of `Zir.Inst.Capture`, |
| 2915 | 2934 | /// resolves this into a list of `InternPool.CaptureValue` allocated by `arena`. |
| 2916 | fn getCaptures(sema: *Sema, block: *Block, type_src: LazySrcLoc, extra_index: usize, captures_len: u32) ![]InternPool.CaptureValue { | |
| 2935 | fn getCaptures( | |
| 2936 | sema: *Sema, | |
| 2937 | block: *Block, | |
| 2938 | type_src: LazySrcLoc, | |
| 2939 | zir_captures: []const Zir.Inst.Capture, | |
| 2940 | zir_capture_names: []const Zir.NullTerminatedString, | |
| 2941 | ) ![]InternPool.CaptureValue { | |
| 2917 | 2942 | const pt = sema.pt; |
| 2918 | 2943 | const zcu = pt.zcu; |
| 2919 | 2944 | const comp = zcu.comp; |
| ... | ... | @@ -2924,41 +2949,38 @@ fn getCaptures(sema: *Sema, block: *Block, type_src: LazySrcLoc, extra_index: us |
| 2924 | 2949 | const parent_ty: Type = .fromInterned(zcu.namespacePtr(block.namespace).owner_type); |
| 2925 | 2950 | const parent_captures: InternPool.CaptureValue.Slice = parent_ty.getCaptures(zcu); |
| 2926 | 2951 | |
| 2927 | const captures = try sema.arena.alloc(InternPool.CaptureValue, captures_len); | |
| 2952 | const captures = try sema.arena.alloc(InternPool.CaptureValue, zir_captures.len); | |
| 2928 | 2953 | |
| 2929 | for (sema.code.extra[extra_index..][0..captures_len], sema.code.extra[extra_index + captures_len ..][0..captures_len], captures) |raw, raw_name, *capture| { | |
| 2930 | const zir_capture: Zir.Inst.Capture = @bitCast(raw); | |
| 2931 | const zir_name: Zir.NullTerminatedString = @enumFromInt(raw_name); | |
| 2954 | for (zir_captures, zir_capture_names, captures) |zir_capture, zir_name, *capture| { | |
| 2932 | 2955 | const zir_name_slice = sema.code.nullTerminatedString(zir_name); |
| 2933 | 2956 | capture.* = switch (zir_capture.unwrap()) { |
| 2934 | 2957 | .nested => |parent_idx| parent_captures.get(ip)[parent_idx], |
| 2935 | .instruction_load => |ptr_inst| InternPool.CaptureValue.wrap(capture: { | |
| 2958 | .instruction_load => |ptr_inst| capture: { | |
| 2936 | 2959 | const ptr_ref = try sema.resolveInst(ptr_inst.toRef()); |
| 2937 | 2960 | const ptr_val = try sema.resolveValue(ptr_ref) orelse { |
| 2938 | break :capture .{ .runtime = sema.typeOf(ptr_ref).childType(zcu).toIntern() }; | |
| 2961 | break :capture .wrap(.{ .runtime = sema.typeOf(ptr_ref).childType(zcu).toIntern() }); | |
| 2939 | 2962 | }; |
| 2940 | 2963 | // TODO: better source location |
| 2941 | const unresolved_loaded_val = try sema.pointerDeref(block, type_src, ptr_val, sema.typeOf(ptr_ref)) orelse { | |
| 2942 | break :capture .{ .runtime = sema.typeOf(ptr_ref).childType(zcu).toIntern() }; | |
| 2964 | const loaded_val = try sema.pointerDeref(block, type_src, ptr_val, sema.typeOf(ptr_ref)) orelse { | |
| 2965 | break :capture .wrap(.{ .runtime = sema.typeOf(ptr_ref).childType(zcu).toIntern() }); | |
| 2943 | 2966 | }; |
| 2944 | const loaded_val = try sema.resolveLazyValue(unresolved_loaded_val); | |
| 2945 | 2967 | if (loaded_val.canMutateComptimeVarState(zcu)) { |
| 2946 | 2968 | const field_name = try ip.getOrPutString(gpa, io, pt.tid, zir_name_slice, .no_embedded_nulls); |
| 2947 | 2969 | return sema.failWithContainsReferenceToComptimeVar(block, type_src, field_name, "captured value", loaded_val); |
| 2948 | 2970 | } |
| 2949 | break :capture .{ .@"comptime" = loaded_val.toIntern() }; | |
| 2950 | }), | |
| 2951 | .instruction => |inst| InternPool.CaptureValue.wrap(capture: { | |
| 2971 | break :capture .wrap(.{ .@"comptime" = loaded_val.toIntern() }); | |
| 2972 | }, | |
| 2973 | .instruction => |inst| capture: { | |
| 2952 | 2974 | const air_ref = try sema.resolveInst(inst.toRef()); |
| 2953 | if (try sema.resolveValueResolveLazy(air_ref)) |val| { | |
| 2975 | if (try sema.resolveValue(air_ref)) |val| { | |
| 2954 | 2976 | if (val.canMutateComptimeVarState(zcu)) { |
| 2955 | 2977 | const field_name = try ip.getOrPutString(gpa, io, pt.tid, zir_name_slice, .no_embedded_nulls); |
| 2956 | 2978 | return sema.failWithContainsReferenceToComptimeVar(block, type_src, field_name, "captured value", val); |
| 2957 | 2979 | } |
| 2958 | break :capture .{ .@"comptime" = val.toIntern() }; | |
| 2980 | break :capture .wrap(.{ .@"comptime" = val.toIntern() }); | |
| 2959 | 2981 | } |
| 2960 | break :capture .{ .runtime = sema.typeOf(air_ref).toIntern() }; | |
| 2961 | }), | |
| 2982 | break :capture .wrap(.{ .runtime = sema.typeOf(air_ref).toIntern() }); | |
| 2983 | }, | |
| 2962 | 2984 | .decl_val => |str| capture: { |
| 2963 | 2985 | const decl_name = try ip.getOrPutString( |
| 2964 | 2986 | gpa, |
| ... | ... | @@ -2968,7 +2990,7 @@ fn getCaptures(sema: *Sema, block: *Block, type_src: LazySrcLoc, extra_index: us |
| 2968 | 2990 | .no_embedded_nulls, |
| 2969 | 2991 | ); |
| 2970 | 2992 | const nav = try sema.lookupIdentifier(block, decl_name); |
| 2971 | break :capture InternPool.CaptureValue.wrap(.{ .nav_val = nav }); | |
| 2993 | break :capture .wrap(.{ .nav_val = nav }); | |
| 2972 | 2994 | }, |
| 2973 | 2995 | .decl_ref => |str| capture: { |
| 2974 | 2996 | const decl_name = try ip.getOrPutString( |
| ... | ... | @@ -2987,621 +3009,6 @@ fn getCaptures(sema: *Sema, block: *Block, type_src: LazySrcLoc, extra_index: us |
| 2987 | 3009 | return captures; |
| 2988 | 3010 | } |
| 2989 | 3011 | |
| 2990 | fn zirStructDecl( | |
| 2991 | sema: *Sema, | |
| 2992 | block: *Block, | |
| 2993 | extended: Zir.Inst.Extended.InstData, | |
| 2994 | inst: Zir.Inst.Index, | |
| 2995 | ) CompileError!Air.Inst.Ref { | |
| 2996 | const pt = sema.pt; | |
| 2997 | const zcu = pt.zcu; | |
| 2998 | const comp = zcu.comp; | |
| 2999 | const gpa = comp.gpa; | |
| 3000 | const io = comp.io; | |
| 3001 | const ip = &zcu.intern_pool; | |
| 3002 | ||
| 3003 | const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small); | |
| 3004 | const extra = sema.code.extraData(Zir.Inst.StructDecl, extended.operand); | |
| 3005 | ||
| 3006 | const tracked_inst = try block.trackZir(inst); | |
| 3007 | const src: LazySrcLoc = .{ | |
| 3008 | .base_node_inst = tracked_inst, | |
| 3009 | .offset = LazySrcLoc.Offset.nodeOffset(.zero), | |
| 3010 | }; | |
| 3011 | ||
| 3012 | var extra_index = extra.end; | |
| 3013 | ||
| 3014 | const captures_len = if (small.has_captures_len) blk: { | |
| 3015 | const captures_len = sema.code.extra[extra_index]; | |
| 3016 | extra_index += 1; | |
| 3017 | break :blk captures_len; | |
| 3018 | } else 0; | |
| 3019 | const fields_len = if (small.has_fields_len) blk: { | |
| 3020 | const fields_len = sema.code.extra[extra_index]; | |
| 3021 | extra_index += 1; | |
| 3022 | break :blk fields_len; | |
| 3023 | } else 0; | |
| 3024 | const decls_len = if (small.has_decls_len) blk: { | |
| 3025 | const decls_len = sema.code.extra[extra_index]; | |
| 3026 | extra_index += 1; | |
| 3027 | break :blk decls_len; | |
| 3028 | } else 0; | |
| 3029 | ||
| 3030 | const captures = try sema.getCaptures(block, src, extra_index, captures_len); | |
| 3031 | extra_index += captures_len * 2; | |
| 3032 | ||
| 3033 | if (small.has_backing_int) { | |
| 3034 | const backing_int_body_len = sema.code.extra[extra_index]; | |
| 3035 | extra_index += 1; // backing_int_body_len | |
| 3036 | if (backing_int_body_len == 0) { | |
| 3037 | extra_index += 1; // backing_int_ref | |
| 3038 | } else { | |
| 3039 | extra_index += backing_int_body_len; // backing_int_body_inst | |
| 3040 | } | |
| 3041 | } | |
| 3042 | ||
| 3043 | const struct_init: InternPool.StructTypeInit = .{ | |
| 3044 | .layout = small.layout, | |
| 3045 | .fields_len = fields_len, | |
| 3046 | .known_non_opv = small.known_non_opv, | |
| 3047 | .requires_comptime = if (small.known_comptime_only) .yes else .unknown, | |
| 3048 | .any_comptime_fields = small.any_comptime_fields, | |
| 3049 | .any_default_inits = small.any_default_inits, | |
| 3050 | .inits_resolved = false, | |
| 3051 | .any_aligned_fields = small.any_aligned_fields, | |
| 3052 | .key = .{ .declared = .{ | |
| 3053 | .zir_index = tracked_inst, | |
| 3054 | .captures = captures, | |
| 3055 | } }, | |
| 3056 | }; | |
| 3057 | const wip_ty = switch (try ip.getStructType(gpa, io, pt.tid, struct_init, false)) { | |
| 3058 | .existing => |ty| { | |
| 3059 | const new_ty = try pt.ensureTypeUpToDate(ty); | |
| 3060 | ||
| 3061 | // Make sure we update the namespace if the declaration is re-analyzed, to pick | |
| 3062 | // up on e.g. changed comptime decls. | |
| 3063 | try pt.ensureNamespaceUpToDate(Type.fromInterned(new_ty).getNamespaceIndex(zcu)); | |
| 3064 | ||
| 3065 | try sema.declareDependency(.{ .interned = new_ty }); | |
| 3066 | try sema.addTypeReferenceEntry(src, new_ty); | |
| 3067 | return Air.internedToRef(new_ty); | |
| 3068 | }, | |
| 3069 | .wip => |wip| wip, | |
| 3070 | }; | |
| 3071 | errdefer wip_ty.cancel(ip, pt.tid); | |
| 3072 | ||
| 3073 | const type_name = try sema.createTypeName( | |
| 3074 | block, | |
| 3075 | small.name_strategy, | |
| 3076 | "struct", | |
| 3077 | inst, | |
| 3078 | wip_ty.index, | |
| 3079 | ); | |
| 3080 | wip_ty.setName(ip, type_name.name, type_name.nav); | |
| 3081 | ||
| 3082 | const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{ | |
| 3083 | .parent = block.namespace.toOptional(), | |
| 3084 | .owner_type = wip_ty.index, | |
| 3085 | .file_scope = block.getFileScopeIndex(zcu), | |
| 3086 | .generation = zcu.generation, | |
| 3087 | }); | |
| 3088 | errdefer pt.destroyNamespace(new_namespace_index); | |
| 3089 | ||
| 3090 | if (pt.zcu.comp.config.incremental) { | |
| 3091 | try pt.addDependency(.wrap(.{ .type = wip_ty.index }), .{ .src_hash = tracked_inst }); | |
| 3092 | } | |
| 3093 | ||
| 3094 | const decls = sema.code.bodySlice(extra_index, decls_len); | |
| 3095 | try pt.scanNamespace(new_namespace_index, decls); | |
| 3096 | ||
| 3097 | try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index }); | |
| 3098 | codegen_type: { | |
| 3099 | if (zcu.comp.config.use_llvm) break :codegen_type; | |
| 3100 | if (block.ownerModule().strip) break :codegen_type; | |
| 3101 | // This job depends on any resolve_type_fully jobs queued up before it. | |
| 3102 | zcu.comp.link_prog_node.increaseEstimatedTotalItems(1); | |
| 3103 | try zcu.comp.queueJob(.{ .link_type = wip_ty.index }); | |
| 3104 | } | |
| 3105 | try sema.declareDependency(.{ .interned = wip_ty.index }); | |
| 3106 | try sema.addTypeReferenceEntry(src, wip_ty.index); | |
| 3107 | if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index); | |
| 3108 | return Air.internedToRef(wip_ty.finish(ip, new_namespace_index)); | |
| 3109 | } | |
| 3110 | ||
| 3111 | pub fn createTypeName( | |
| 3112 | sema: *Sema, | |
| 3113 | block: *Block, | |
| 3114 | name_strategy: Zir.Inst.NameStrategy, | |
| 3115 | anon_prefix: []const u8, | |
| 3116 | inst: ?Zir.Inst.Index, | |
| 3117 | /// This is used purely to give the type a unique name in the `anon` case. | |
| 3118 | type_index: InternPool.Index, | |
| 3119 | ) CompileError!struct { | |
| 3120 | name: InternPool.NullTerminatedString, | |
| 3121 | nav: InternPool.Nav.Index.Optional, | |
| 3122 | } { | |
| 3123 | const pt = sema.pt; | |
| 3124 | const zcu = pt.zcu; | |
| 3125 | const comp = zcu.comp; | |
| 3126 | const gpa = comp.gpa; | |
| 3127 | const io = comp.io; | |
| 3128 | const ip = &zcu.intern_pool; | |
| 3129 | ||
| 3130 | switch (name_strategy) { | |
| 3131 | .anon => {}, // handled after switch | |
| 3132 | .parent => return .{ | |
| 3133 | .name = block.type_name_ctx, | |
| 3134 | .nav = sema.owner.unwrap().nav_val.toOptional(), | |
| 3135 | }, | |
| 3136 | .func => func_strat: { | |
| 3137 | const fn_info = sema.code.getFnInfo(ip.funcZirBodyInst(sema.func_index).resolve(ip) orelse return error.AnalysisFail); | |
| 3138 | const zir_tags = sema.code.instructions.items(.tag); | |
| 3139 | ||
| 3140 | var aw: std.Io.Writer.Allocating = .init(gpa); | |
| 3141 | defer aw.deinit(); | |
| 3142 | const w = &aw.writer; | |
| 3143 | w.print("{f}(", .{block.type_name_ctx.fmt(ip)}) catch return error.OutOfMemory; | |
| 3144 | ||
| 3145 | var arg_i: usize = 0; | |
| 3146 | for (fn_info.param_body) |zir_inst| switch (zir_tags[@intFromEnum(zir_inst)]) { | |
| 3147 | .param, .param_comptime, .param_anytype, .param_anytype_comptime => { | |
| 3148 | const arg = sema.inst_map.get(zir_inst).?; | |
| 3149 | // If this is being called in a generic function then analyzeCall will | |
| 3150 | // have already resolved the args and this will work. | |
| 3151 | // If not then this is a struct type being returned from a non-generic | |
| 3152 | // function and the name doesn't matter since it will later | |
| 3153 | // result in a compile error. | |
| 3154 | const arg_val = try sema.resolveValue(arg) orelse break :func_strat; // fall through to anon strat | |
| 3155 | ||
| 3156 | if (arg_i != 0) w.writeByte(',') catch return error.OutOfMemory; | |
| 3157 | ||
| 3158 | // Limiting the depth here helps avoid type names getting too long, which | |
| 3159 | // in turn helps to avoid unreasonably long symbol names for namespaced | |
| 3160 | // symbols. Such names should ideally be human-readable, and additionally, | |
| 3161 | // some tooling may not support very long symbol names. | |
| 3162 | w.print("{f}", .{Value.fmtValueSemaFull(.{ | |
| 3163 | .val = arg_val, | |
| 3164 | .pt = pt, | |
| 3165 | .opt_sema = sema, | |
| 3166 | .depth = 1, | |
| 3167 | })}) catch return error.OutOfMemory; | |
| 3168 | ||
| 3169 | arg_i += 1; | |
| 3170 | continue; | |
| 3171 | }, | |
| 3172 | else => continue, | |
| 3173 | }; | |
| 3174 | ||
| 3175 | w.writeByte(')') catch return error.OutOfMemory; | |
| 3176 | return .{ | |
| 3177 | .name = try ip.getOrPutString(gpa, io, pt.tid, aw.written(), .no_embedded_nulls), | |
| 3178 | .nav = .none, | |
| 3179 | }; | |
| 3180 | }, | |
| 3181 | .dbg_var => { | |
| 3182 | // TODO: this logic is questionable. We ideally should be traversing the `Block` rather than relying on the order of AstGen instructions. | |
| 3183 | const ref = inst.?.toRef(); | |
| 3184 | const zir_tags = sema.code.instructions.items(.tag); | |
| 3185 | const zir_data = sema.code.instructions.items(.data); | |
| 3186 | for (@intFromEnum(inst.?)..zir_tags.len) |i| switch (zir_tags[i]) { | |
| 3187 | .dbg_var_ptr, .dbg_var_val => if (zir_data[i].str_op.operand == ref) { | |
| 3188 | return .{ | |
| 3189 | .name = try ip.getOrPutStringFmt(gpa, io, pt.tid, "{f}.{s}", .{ | |
| 3190 | block.type_name_ctx.fmt(ip), zir_data[i].str_op.getStr(sema.code), | |
| 3191 | }, .no_embedded_nulls), | |
| 3192 | .nav = .none, | |
| 3193 | }; | |
| 3194 | }, | |
| 3195 | else => {}, | |
| 3196 | }; | |
| 3197 | // fall through to anon strat | |
| 3198 | }, | |
| 3199 | } | |
| 3200 | ||
| 3201 | // anon strat handling | |
| 3202 | ||
| 3203 | // It would be neat to have "struct:line:column" but this name has | |
| 3204 | // to survive incremental updates, where it may have been shifted down | |
| 3205 | // or up to a different line, but unchanged, and thus not unnecessarily | |
| 3206 | // semantically analyzed. | |
| 3207 | // TODO: that would be possible, by detecting line number changes and renaming | |
| 3208 | // types appropriately. However, `@typeName` becomes a problem then. If we remove | |
| 3209 | // that builtin from the language, we can consider this. | |
| 3210 | ||
| 3211 | return .{ | |
| 3212 | .name = try ip.getOrPutStringFmt(gpa, io, pt.tid, "{f}__{s}_{d}", .{ | |
| 3213 | block.type_name_ctx.fmt(ip), anon_prefix, @intFromEnum(type_index), | |
| 3214 | }, .no_embedded_nulls), | |
| 3215 | .nav = .none, | |
| 3216 | }; | |
| 3217 | } | |
| 3218 | ||
| 3219 | fn zirEnumDecl( | |
| 3220 | sema: *Sema, | |
| 3221 | block: *Block, | |
| 3222 | extended: Zir.Inst.Extended.InstData, | |
| 3223 | inst: Zir.Inst.Index, | |
| 3224 | ) CompileError!Air.Inst.Ref { | |
| 3225 | const tracy = trace(@src()); | |
| 3226 | defer tracy.end(); | |
| 3227 | ||
| 3228 | const pt = sema.pt; | |
| 3229 | const zcu = pt.zcu; | |
| 3230 | const comp = zcu.comp; | |
| 3231 | const gpa = comp.gpa; | |
| 3232 | const io = comp.io; | |
| 3233 | const ip = &zcu.intern_pool; | |
| 3234 | ||
| 3235 | const small: Zir.Inst.EnumDecl.Small = @bitCast(extended.small); | |
| 3236 | const extra = sema.code.extraData(Zir.Inst.EnumDecl, extended.operand); | |
| 3237 | var extra_index: usize = extra.end; | |
| 3238 | ||
| 3239 | const tracked_inst = try block.trackZir(inst); | |
| 3240 | const src: LazySrcLoc = .{ .base_node_inst = tracked_inst, .offset = LazySrcLoc.Offset.nodeOffset(.zero) }; | |
| 3241 | ||
| 3242 | const tag_type_ref = if (small.has_tag_type) blk: { | |
| 3243 | const tag_type_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]); | |
| 3244 | extra_index += 1; | |
| 3245 | break :blk tag_type_ref; | |
| 3246 | } else .none; | |
| 3247 | ||
| 3248 | const captures_len = if (small.has_captures_len) blk: { | |
| 3249 | const captures_len = sema.code.extra[extra_index]; | |
| 3250 | extra_index += 1; | |
| 3251 | break :blk captures_len; | |
| 3252 | } else 0; | |
| 3253 | ||
| 3254 | const body_len = if (small.has_body_len) blk: { | |
| 3255 | const body_len = sema.code.extra[extra_index]; | |
| 3256 | extra_index += 1; | |
| 3257 | break :blk body_len; | |
| 3258 | } else 0; | |
| 3259 | ||
| 3260 | const fields_len = if (small.has_fields_len) blk: { | |
| 3261 | const fields_len = sema.code.extra[extra_index]; | |
| 3262 | extra_index += 1; | |
| 3263 | break :blk fields_len; | |
| 3264 | } else 0; | |
| 3265 | ||
| 3266 | const decls_len = if (small.has_decls_len) blk: { | |
| 3267 | const decls_len = sema.code.extra[extra_index]; | |
| 3268 | extra_index += 1; | |
| 3269 | break :blk decls_len; | |
| 3270 | } else 0; | |
| 3271 | ||
| 3272 | const captures = try sema.getCaptures(block, src, extra_index, captures_len); | |
| 3273 | extra_index += captures_len * 2; | |
| 3274 | ||
| 3275 | const decls = sema.code.bodySlice(extra_index, decls_len); | |
| 3276 | extra_index += decls_len; | |
| 3277 | ||
| 3278 | const body = sema.code.bodySlice(extra_index, body_len); | |
| 3279 | extra_index += body.len; | |
| 3280 | ||
| 3281 | const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable; | |
| 3282 | const body_end = extra_index; | |
| 3283 | extra_index += bit_bags_count; | |
| 3284 | ||
| 3285 | const any_values = for (sema.code.extra[body_end..][0..bit_bags_count]) |bag| { | |
| 3286 | if (bag != 0) break true; | |
| 3287 | } else false; | |
| 3288 | ||
| 3289 | const enum_init: InternPool.EnumTypeInit = .{ | |
| 3290 | .has_values = any_values, | |
| 3291 | .tag_mode = if (small.nonexhaustive) | |
| 3292 | .nonexhaustive | |
| 3293 | else if (tag_type_ref == .none) | |
| 3294 | .auto | |
| 3295 | else | |
| 3296 | .explicit, | |
| 3297 | .fields_len = fields_len, | |
| 3298 | .key = .{ .declared = .{ | |
| 3299 | .zir_index = tracked_inst, | |
| 3300 | .captures = captures, | |
| 3301 | } }, | |
| 3302 | }; | |
| 3303 | const wip_ty = switch (try ip.getEnumType(gpa, io, pt.tid, enum_init, false)) { | |
| 3304 | .existing => |ty| { | |
| 3305 | const new_ty = try pt.ensureTypeUpToDate(ty); | |
| 3306 | ||
| 3307 | // Make sure we update the namespace if the declaration is re-analyzed, to pick | |
| 3308 | // up on e.g. changed comptime decls. | |
| 3309 | try pt.ensureNamespaceUpToDate(Type.fromInterned(new_ty).getNamespaceIndex(zcu)); | |
| 3310 | ||
| 3311 | try sema.declareDependency(.{ .interned = new_ty }); | |
| 3312 | try sema.addTypeReferenceEntry(src, new_ty); | |
| 3313 | ||
| 3314 | // Since this is an enum, it has to be resolved immediately. | |
| 3315 | // `ensureTypeUpToDate` has resolved the new type if necessary. | |
| 3316 | // We just need to check for resolution failures. | |
| 3317 | const ty_unit: AnalUnit = .wrap(.{ .type = new_ty }); | |
| 3318 | if (zcu.failed_analysis.contains(ty_unit) or zcu.transitive_failed_analysis.contains(ty_unit)) { | |
| 3319 | return error.AnalysisFail; | |
| 3320 | } | |
| 3321 | ||
| 3322 | return Air.internedToRef(new_ty); | |
| 3323 | }, | |
| 3324 | .wip => |wip| wip, | |
| 3325 | }; | |
| 3326 | ||
| 3327 | // Once this is `true`, we will not delete the decl or type even upon failure, since we | |
| 3328 | // have finished constructing the type and are in the process of analyzing it. | |
| 3329 | var done = false; | |
| 3330 | ||
| 3331 | errdefer if (!done) wip_ty.cancel(ip, pt.tid); | |
| 3332 | ||
| 3333 | const type_name = try sema.createTypeName( | |
| 3334 | block, | |
| 3335 | small.name_strategy, | |
| 3336 | "enum", | |
| 3337 | inst, | |
| 3338 | wip_ty.index, | |
| 3339 | ); | |
| 3340 | wip_ty.setName(ip, type_name.name, type_name.nav); | |
| 3341 | ||
| 3342 | const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{ | |
| 3343 | .parent = block.namespace.toOptional(), | |
| 3344 | .owner_type = wip_ty.index, | |
| 3345 | .file_scope = block.getFileScopeIndex(zcu), | |
| 3346 | .generation = zcu.generation, | |
| 3347 | }); | |
| 3348 | errdefer if (!done) pt.destroyNamespace(new_namespace_index); | |
| 3349 | ||
| 3350 | try pt.scanNamespace(new_namespace_index, decls); | |
| 3351 | ||
| 3352 | try sema.declareDependency(.{ .interned = wip_ty.index }); | |
| 3353 | try sema.addTypeReferenceEntry(src, wip_ty.index); | |
| 3354 | ||
| 3355 | // We've finished the initial construction of this type, and are about to perform analysis. | |
| 3356 | // Set the namespace appropriately, and don't destroy anything on failure. | |
| 3357 | if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index); | |
| 3358 | wip_ty.prepare(ip, new_namespace_index); | |
| 3359 | done = true; | |
| 3360 | ||
| 3361 | { | |
| 3362 | const tracked_unit = zcu.trackUnitSema(type_name.name.toSlice(ip), null); | |
| 3363 | defer tracked_unit.end(zcu); | |
| 3364 | try Sema.resolveDeclaredEnum( | |
| 3365 | pt, | |
| 3366 | wip_ty, | |
| 3367 | inst, | |
| 3368 | tracked_inst, | |
| 3369 | new_namespace_index, | |
| 3370 | type_name.name, | |
| 3371 | small, | |
| 3372 | body, | |
| 3373 | tag_type_ref, | |
| 3374 | any_values, | |
| 3375 | fields_len, | |
| 3376 | sema.code, | |
| 3377 | body_end, | |
| 3378 | ); | |
| 3379 | } | |
| 3380 | ||
| 3381 | codegen_type: { | |
| 3382 | if (zcu.comp.config.use_llvm) break :codegen_type; | |
| 3383 | if (block.ownerModule().strip) break :codegen_type; | |
| 3384 | // This job depends on any resolve_type_fully jobs queued up before it. | |
| 3385 | zcu.comp.link_prog_node.increaseEstimatedTotalItems(1); | |
| 3386 | try zcu.comp.queueJob(.{ .link_type = wip_ty.index }); | |
| 3387 | } | |
| 3388 | return Air.internedToRef(wip_ty.index); | |
| 3389 | } | |
| 3390 | ||
| 3391 | fn zirUnionDecl( | |
| 3392 | sema: *Sema, | |
| 3393 | block: *Block, | |
| 3394 | extended: Zir.Inst.Extended.InstData, | |
| 3395 | inst: Zir.Inst.Index, | |
| 3396 | ) CompileError!Air.Inst.Ref { | |
| 3397 | const tracy = trace(@src()); | |
| 3398 | defer tracy.end(); | |
| 3399 | ||
| 3400 | const pt = sema.pt; | |
| 3401 | const zcu = pt.zcu; | |
| 3402 | const comp = zcu.comp; | |
| 3403 | const gpa = comp.gpa; | |
| 3404 | const io = comp.io; | |
| 3405 | const ip = &zcu.intern_pool; | |
| 3406 | ||
| 3407 | const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small); | |
| 3408 | const extra = sema.code.extraData(Zir.Inst.UnionDecl, extended.operand); | |
| 3409 | var extra_index: usize = extra.end; | |
| 3410 | ||
| 3411 | const tracked_inst = try block.trackZir(inst); | |
| 3412 | const src: LazySrcLoc = .{ .base_node_inst = tracked_inst, .offset = LazySrcLoc.Offset.nodeOffset(.zero) }; | |
| 3413 | ||
| 3414 | extra_index += @intFromBool(small.has_tag_type); | |
| 3415 | const captures_len = if (small.has_captures_len) blk: { | |
| 3416 | const captures_len = sema.code.extra[extra_index]; | |
| 3417 | extra_index += 1; | |
| 3418 | break :blk captures_len; | |
| 3419 | } else 0; | |
| 3420 | extra_index += @intFromBool(small.has_body_len); | |
| 3421 | const fields_len = if (small.has_fields_len) blk: { | |
| 3422 | const fields_len = sema.code.extra[extra_index]; | |
| 3423 | extra_index += 1; | |
| 3424 | break :blk fields_len; | |
| 3425 | } else 0; | |
| 3426 | ||
| 3427 | const decls_len = if (small.has_decls_len) blk: { | |
| 3428 | const decls_len = sema.code.extra[extra_index]; | |
| 3429 | extra_index += 1; | |
| 3430 | break :blk decls_len; | |
| 3431 | } else 0; | |
| 3432 | ||
| 3433 | const captures = try sema.getCaptures(block, src, extra_index, captures_len); | |
| 3434 | extra_index += captures_len * 2; | |
| 3435 | ||
| 3436 | const union_init: InternPool.UnionTypeInit = .{ | |
| 3437 | .flags = .{ | |
| 3438 | .layout = small.layout, | |
| 3439 | .status = .none, | |
| 3440 | .runtime_tag = if (small.has_tag_type or small.auto_enum_tag) | |
| 3441 | .tagged | |
| 3442 | else if (small.layout != .auto) | |
| 3443 | .none | |
| 3444 | else switch (block.wantSafeTypes()) { | |
| 3445 | true => .safety, | |
| 3446 | false => .none, | |
| 3447 | }, | |
| 3448 | .any_aligned_fields = small.any_aligned_fields, | |
| 3449 | .requires_comptime = .unknown, | |
| 3450 | .assumed_runtime_bits = false, | |
| 3451 | .assumed_pointer_aligned = false, | |
| 3452 | .alignment = .none, | |
| 3453 | }, | |
| 3454 | .fields_len = fields_len, | |
| 3455 | .enum_tag_ty = .none, // set later | |
| 3456 | .field_types = &.{}, // set later | |
| 3457 | .field_aligns = &.{}, // set later | |
| 3458 | .key = .{ .declared = .{ | |
| 3459 | .zir_index = tracked_inst, | |
| 3460 | .captures = captures, | |
| 3461 | } }, | |
| 3462 | }; | |
| 3463 | const wip_ty = switch (try ip.getUnionType(gpa, io, pt.tid, union_init, false)) { | |
| 3464 | .existing => |ty| { | |
| 3465 | const new_ty = try pt.ensureTypeUpToDate(ty); | |
| 3466 | ||
| 3467 | // Make sure we update the namespace if the declaration is re-analyzed, to pick | |
| 3468 | // up on e.g. changed comptime decls. | |
| 3469 | try pt.ensureNamespaceUpToDate(Type.fromInterned(new_ty).getNamespaceIndex(zcu)); | |
| 3470 | ||
| 3471 | try sema.declareDependency(.{ .interned = new_ty }); | |
| 3472 | try sema.addTypeReferenceEntry(src, new_ty); | |
| 3473 | return Air.internedToRef(new_ty); | |
| 3474 | }, | |
| 3475 | .wip => |wip| wip, | |
| 3476 | }; | |
| 3477 | errdefer wip_ty.cancel(ip, pt.tid); | |
| 3478 | ||
| 3479 | const type_name = try sema.createTypeName( | |
| 3480 | block, | |
| 3481 | small.name_strategy, | |
| 3482 | "union", | |
| 3483 | inst, | |
| 3484 | wip_ty.index, | |
| 3485 | ); | |
| 3486 | wip_ty.setName(ip, type_name.name, type_name.nav); | |
| 3487 | ||
| 3488 | const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{ | |
| 3489 | .parent = block.namespace.toOptional(), | |
| 3490 | .owner_type = wip_ty.index, | |
| 3491 | .file_scope = block.getFileScopeIndex(zcu), | |
| 3492 | .generation = zcu.generation, | |
| 3493 | }); | |
| 3494 | errdefer pt.destroyNamespace(new_namespace_index); | |
| 3495 | ||
| 3496 | if (pt.zcu.comp.config.incremental) { | |
| 3497 | try pt.addDependency(.wrap(.{ .type = wip_ty.index }), .{ .src_hash = tracked_inst }); | |
| 3498 | } | |
| 3499 | ||
| 3500 | const decls = sema.code.bodySlice(extra_index, decls_len); | |
| 3501 | try pt.scanNamespace(new_namespace_index, decls); | |
| 3502 | ||
| 3503 | try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index }); | |
| 3504 | codegen_type: { | |
| 3505 | if (zcu.comp.config.use_llvm) break :codegen_type; | |
| 3506 | if (block.ownerModule().strip) break :codegen_type; | |
| 3507 | // This job depends on any resolve_type_fully jobs queued up before it. | |
| 3508 | zcu.comp.link_prog_node.increaseEstimatedTotalItems(1); | |
| 3509 | try zcu.comp.queueJob(.{ .link_type = wip_ty.index }); | |
| 3510 | } | |
| 3511 | try sema.declareDependency(.{ .interned = wip_ty.index }); | |
| 3512 | try sema.addTypeReferenceEntry(src, wip_ty.index); | |
| 3513 | if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index); | |
| 3514 | return Air.internedToRef(wip_ty.finish(ip, new_namespace_index)); | |
| 3515 | } | |
| 3516 | ||
| 3517 | fn zirOpaqueDecl( | |
| 3518 | sema: *Sema, | |
| 3519 | block: *Block, | |
| 3520 | extended: Zir.Inst.Extended.InstData, | |
| 3521 | inst: Zir.Inst.Index, | |
| 3522 | ) CompileError!Air.Inst.Ref { | |
| 3523 | const tracy = trace(@src()); | |
| 3524 | defer tracy.end(); | |
| 3525 | ||
| 3526 | const pt = sema.pt; | |
| 3527 | const zcu = pt.zcu; | |
| 3528 | const comp = zcu.comp; | |
| 3529 | const gpa = comp.gpa; | |
| 3530 | const io = comp.io; | |
| 3531 | const ip = &zcu.intern_pool; | |
| 3532 | ||
| 3533 | const small: Zir.Inst.OpaqueDecl.Small = @bitCast(extended.small); | |
| 3534 | const extra = sema.code.extraData(Zir.Inst.OpaqueDecl, extended.operand); | |
| 3535 | var extra_index: usize = extra.end; | |
| 3536 | ||
| 3537 | const tracked_inst = try block.trackZir(inst); | |
| 3538 | const src: LazySrcLoc = .{ .base_node_inst = tracked_inst, .offset = LazySrcLoc.Offset.nodeOffset(.zero) }; | |
| 3539 | ||
| 3540 | const captures_len = if (small.has_captures_len) blk: { | |
| 3541 | const captures_len = sema.code.extra[extra_index]; | |
| 3542 | extra_index += 1; | |
| 3543 | break :blk captures_len; | |
| 3544 | } else 0; | |
| 3545 | ||
| 3546 | const decls_len = if (small.has_decls_len) blk: { | |
| 3547 | const decls_len = sema.code.extra[extra_index]; | |
| 3548 | extra_index += 1; | |
| 3549 | break :blk decls_len; | |
| 3550 | } else 0; | |
| 3551 | ||
| 3552 | const captures = try sema.getCaptures(block, src, extra_index, captures_len); | |
| 3553 | extra_index += captures_len * 2; | |
| 3554 | ||
| 3555 | const opaque_init: InternPool.OpaqueTypeInit = .{ | |
| 3556 | .zir_index = tracked_inst, | |
| 3557 | .captures = captures, | |
| 3558 | }; | |
| 3559 | const wip_ty = switch (try ip.getOpaqueType(gpa, io, pt.tid, opaque_init)) { | |
| 3560 | .existing => |ty| { | |
| 3561 | // Make sure we update the namespace if the declaration is re-analyzed, to pick | |
| 3562 | // up on e.g. changed comptime decls. | |
| 3563 | try pt.ensureNamespaceUpToDate(Type.fromInterned(ty).getNamespaceIndex(zcu)); | |
| 3564 | ||
| 3565 | try sema.declareDependency(.{ .interned = ty }); | |
| 3566 | try sema.addTypeReferenceEntry(src, ty); | |
| 3567 | return Air.internedToRef(ty); | |
| 3568 | }, | |
| 3569 | .wip => |wip| wip, | |
| 3570 | }; | |
| 3571 | errdefer wip_ty.cancel(ip, pt.tid); | |
| 3572 | ||
| 3573 | const type_name = try sema.createTypeName( | |
| 3574 | block, | |
| 3575 | small.name_strategy, | |
| 3576 | "opaque", | |
| 3577 | inst, | |
| 3578 | wip_ty.index, | |
| 3579 | ); | |
| 3580 | wip_ty.setName(ip, type_name.name, type_name.nav); | |
| 3581 | ||
| 3582 | const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{ | |
| 3583 | .parent = block.namespace.toOptional(), | |
| 3584 | .owner_type = wip_ty.index, | |
| 3585 | .file_scope = block.getFileScopeIndex(zcu), | |
| 3586 | .generation = zcu.generation, | |
| 3587 | }); | |
| 3588 | errdefer pt.destroyNamespace(new_namespace_index); | |
| 3589 | ||
| 3590 | const decls = sema.code.bodySlice(extra_index, decls_len); | |
| 3591 | try pt.scanNamespace(new_namespace_index, decls); | |
| 3592 | ||
| 3593 | codegen_type: { | |
| 3594 | if (zcu.comp.config.use_llvm) break :codegen_type; | |
| 3595 | if (block.ownerModule().strip) break :codegen_type; | |
| 3596 | // This job depends on any resolve_type_fully jobs queued up before it. | |
| 3597 | zcu.comp.link_prog_node.increaseEstimatedTotalItems(1); | |
| 3598 | try zcu.comp.queueJob(.{ .link_type = wip_ty.index }); | |
| 3599 | } | |
| 3600 | try sema.addTypeReferenceEntry(src, wip_ty.index); | |
| 3601 | if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index); | |
| 3602 | return Air.internedToRef(wip_ty.finish(ip, new_namespace_index)); | |
| 3603 | } | |
| 3604 | ||
| 3605 | 3012 | fn zirErrorSetDecl( |
| 3606 | 3013 | sema: *Sema, |
| 3607 | 3014 | inst: Zir.Inst.Index, |
| ... | ... | @@ -3640,16 +3047,16 @@ fn zirRetPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 3640 | 3047 | defer tracy.end(); |
| 3641 | 3048 | |
| 3642 | 3049 | const pt = sema.pt; |
| 3050 | const zcu = pt.zcu; | |
| 3643 | 3051 | |
| 3644 | 3052 | const src = block.nodeOffset(sema.code.instructions.items(.data)[@intFromEnum(inst)].node); |
| 3645 | 3053 | |
| 3646 | if (block.isComptime() or try sema.fn_ret_ty.comptimeOnlySema(pt)) { | |
| 3647 | try sema.fn_ret_ty.resolveFields(pt); | |
| 3054 | if (block.isComptime() or sema.fn_ret_ty.comptimeOnly(zcu)) { | |
| 3648 | 3055 | return sema.analyzeComptimeAlloc(block, src, sema.fn_ret_ty, .none); |
| 3649 | 3056 | } |
| 3650 | 3057 | |
| 3651 | const target = pt.zcu.getTarget(); | |
| 3652 | const ptr_type = try pt.ptrTypeSema(.{ | |
| 3058 | const target = zcu.getTarget(); | |
| 3059 | const ptr_type = try pt.ptrType(.{ | |
| 3653 | 3060 | .child = sema.fn_ret_ty.toIntern(), |
| 3654 | 3061 | .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) }, |
| 3655 | 3062 | }); |
| ... | ... | @@ -3826,6 +3233,7 @@ fn zirAllocExtended( |
| 3826 | 3233 | extended: Zir.Inst.Extended.InstData, |
| 3827 | 3234 | ) CompileError!Air.Inst.Ref { |
| 3828 | 3235 | const pt = sema.pt; |
| 3236 | const zcu = pt.zcu; | |
| 3829 | 3237 | const gpa = sema.gpa; |
| 3830 | 3238 | const extra = sema.code.extraData(Zir.Inst.AllocExtended, extended.operand); |
| 3831 | 3239 | const var_src = block.nodeOffset(extra.data.src_node); |
| ... | ... | @@ -3847,37 +3255,20 @@ fn zirAllocExtended( |
| 3847 | 3255 | break :blk try sema.resolveAlign(block, align_src, align_ref); |
| 3848 | 3256 | } else .none; |
| 3849 | 3257 | |
| 3850 | if (block.isComptime() or small.is_comptime) { | |
| 3851 | if (small.has_type) { | |
| 3258 | if (small.has_type) { | |
| 3259 | try sema.ensureLayoutResolved(var_ty); | |
| 3260 | if (block.isComptime() or small.is_comptime or var_ty.comptimeOnly(zcu)) { | |
| 3852 | 3261 | return sema.analyzeComptimeAlloc(block, var_src, var_ty, alignment); |
| 3853 | } else { | |
| 3854 | try sema.air_instructions.append(gpa, .{ | |
| 3855 | .tag = .inferred_alloc_comptime, | |
| 3856 | .data = .{ .inferred_alloc_comptime = .{ | |
| 3857 | .alignment = alignment, | |
| 3858 | .is_const = small.is_const, | |
| 3859 | .ptr = undefined, | |
| 3860 | } }, | |
| 3861 | }); | |
| 3862 | return @as(Air.Inst.Index, @enumFromInt(sema.air_instructions.len - 1)).toRef(); | |
| 3863 | 3262 | } |
| 3864 | } | |
| 3865 | ||
| 3866 | if (small.has_type and try var_ty.comptimeOnlySema(pt)) { | |
| 3867 | return sema.analyzeComptimeAlloc(block, var_src, var_ty, alignment); | |
| 3868 | } | |
| 3869 | ||
| 3870 | if (small.has_type) { | |
| 3871 | 3263 | if (!small.is_const) { |
| 3872 | 3264 | try sema.validateVarType(block, ty_src, var_ty, false); |
| 3873 | 3265 | } |
| 3874 | 3266 | const target = pt.zcu.getTarget(); |
| 3875 | try var_ty.resolveLayout(pt); | |
| 3876 | if (sema.func_is_naked and try var_ty.hasRuntimeBitsSema(pt)) { | |
| 3267 | if (sema.func_is_naked and var_ty.hasRuntimeBits(zcu)) { | |
| 3877 | 3268 | const store_src = block.src(.{ .node_offset_store_ptr = extra.data.src_node }); |
| 3878 | 3269 | return sema.fail(block, store_src, "local variable in naked function", .{}); |
| 3879 | 3270 | } |
| 3880 | const ptr_type = try sema.pt.ptrTypeSema(.{ | |
| 3271 | const ptr_type = try pt.ptrType(.{ | |
| 3881 | 3272 | .child = var_ty.toIntern(), |
| 3882 | 3273 | .flags = .{ |
| 3883 | 3274 | .alignment = alignment, |
| ... | ... | @@ -3893,6 +3284,19 @@ fn zirAllocExtended( |
| 3893 | 3284 | return ptr; |
| 3894 | 3285 | } |
| 3895 | 3286 | |
| 3287 | if (block.isComptime() or small.is_comptime) { | |
| 3288 | const iac_index: Air.Inst.Index = @enumFromInt(sema.air_instructions.len); | |
| 3289 | try sema.air_instructions.append(gpa, .{ | |
| 3290 | .tag = .inferred_alloc_comptime, | |
| 3291 | .data = .{ .inferred_alloc_comptime = .{ | |
| 3292 | .alignment = alignment, | |
| 3293 | .is_const = small.is_const, | |
| 3294 | .ptr = undefined, | |
| 3295 | } }, | |
| 3296 | }); | |
| 3297 | return iac_index.toRef(); | |
| 3298 | } | |
| 3299 | ||
| 3896 | 3300 | const result_index = try block.addInstAsIndex(.{ |
| 3897 | 3301 | .tag = .inferred_alloc, |
| 3898 | 3302 | .data = .{ .inferred_alloc = .{ |
| ... | ... | @@ -3916,6 +3320,7 @@ fn zirAllocComptime(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr |
| 3916 | 3320 | const ty_src = block.src(.{ .node_offset_var_decl_ty = inst_data.src_node }); |
| 3917 | 3321 | const var_src = block.nodeOffset(inst_data.src_node); |
| 3918 | 3322 | const var_ty = try sema.resolveType(block, ty_src, inst_data.operand); |
| 3323 | try sema.ensureLayoutResolved(var_ty); | |
| 3919 | 3324 | return sema.analyzeComptimeAlloc(block, var_src, var_ty, .none); |
| 3920 | 3325 | } |
| 3921 | 3326 | |
| ... | ... | @@ -3978,7 +3383,7 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro |
| 3978 | 3383 | return sema.makePtrConst(block, Air.internedToRef(ptr_val)); |
| 3979 | 3384 | } |
| 3980 | 3385 | |
| 3981 | if (try elem_ty.comptimeOnlySema(pt)) { | |
| 3386 | if (elem_ty.comptimeOnly(zcu)) { | |
| 3982 | 3387 | // The value was initialized through RLS, so we didn't detect the runtime condition earlier. |
| 3983 | 3388 | // TODO: source location of runtime control flow |
| 3984 | 3389 | const init_src = block.src(.{ .node_offset_var_decl_init = inst_data.src_node }); |
| ... | ... | @@ -4001,20 +3406,23 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref, |
| 4001 | 3406 | const alloc_ty = resolved_alloc_ty orelse sema.typeOf(alloc); |
| 4002 | 3407 | const ptr_info = alloc_ty.ptrInfo(zcu); |
| 4003 | 3408 | const elem_ty: Type = .fromInterned(ptr_info.child); |
| 3409 | elem_ty.assertHasLayout(zcu); | |
| 4004 | 3410 | |
| 4005 | 3411 | const alloc_inst = alloc.toIndex() orelse return null; |
| 4006 | 3412 | const comptime_info = sema.maybe_comptime_allocs.fetchRemove(alloc_inst) orelse return null; |
| 4007 | 3413 | const stores = comptime_info.value.stores.items(.inst); |
| 4008 | 3414 | |
| 3415 | // If the elem type is OPV, no need to faff about with `stores`; just use the OPV. | |
| 3416 | if (try elem_ty.onePossibleValue(pt)) |opv| { | |
| 3417 | return sema.finishResolveComptimeKnownAllocPtr(block, alloc_ty, opv.toIntern(), null, alloc_inst, comptime_info.value); | |
| 3418 | } | |
| 3419 | ||
| 3420 | // Since the elem type isn't OPV, there should have been at least one store. | |
| 3421 | assert(stores.len > 0); | |
| 3422 | ||
| 4009 | 3423 | // Since the entry existed in `maybe_comptime_allocs`, the allocation is comptime-known. |
| 4010 | 3424 | // We will resolve and return its value. |
| 4011 | 3425 | |
| 4012 | // We expect to have emitted at least one store, unless the elem type is OPV. | |
| 4013 | if (stores.len == 0) { | |
| 4014 | const val = (try sema.typeHasOnePossibleValue(elem_ty)).?.toIntern(); | |
| 4015 | return sema.finishResolveComptimeKnownAllocPtr(block, alloc_ty, val, null, alloc_inst, comptime_info.value); | |
| 4016 | } | |
| 4017 | ||
| 4018 | 3426 | // In general, we want to create a comptime alloc of the correct type and |
| 4019 | 3427 | // apply the stores to that alloc in order. However, before going to all |
| 4020 | 3428 | // that effort, let's optimize for the common case of a single store. |
| ... | ... | @@ -4118,7 +3526,7 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref, |
| 4118 | 3526 | const idx_val = (try sema.resolveValue(data.rhs)).?; |
| 4119 | 3527 | break :blk .{ |
| 4120 | 3528 | data.lhs, |
| 4121 | .{ .elem = try idx_val.toUnsignedIntSema(pt) }, | |
| 3529 | .{ .elem = idx_val.toUnsignedInt(zcu) }, | |
| 4122 | 3530 | }; |
| 4123 | 3531 | }, |
| 4124 | 3532 | .bitcast => .{ |
| ... | ... | @@ -4150,7 +3558,7 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref, |
| 4150 | 3558 | // If the payload is OPV, we must use that value instead of undef. |
| 4151 | 3559 | const opt_ty = Value.fromInterned(decl_parent_ptr).typeOf(zcu).childType(zcu); |
| 4152 | 3560 | const payload_ty = opt_ty.optionalChild(zcu); |
| 4153 | const payload_val = try sema.typeHasOnePossibleValue(payload_ty) orelse try pt.undefValue(payload_ty); | |
| 3561 | const payload_val = try payload_ty.onePossibleValue(pt) orelse try pt.undefValue(payload_ty); | |
| 4154 | 3562 | const opt_val = try pt.intern(.{ .opt = .{ |
| 4155 | 3563 | .ty = opt_ty.toIntern(), |
| 4156 | 3564 | .val = payload_val.toIntern(), |
| ... | ... | @@ -4163,7 +3571,7 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref, |
| 4163 | 3571 | // If the payload is OPV, we must use that value instead of undef. |
| 4164 | 3572 | const eu_ty = Value.fromInterned(decl_parent_ptr).typeOf(zcu).childType(zcu); |
| 4165 | 3573 | const payload_ty = eu_ty.errorUnionPayload(zcu); |
| 4166 | const payload_val = try sema.typeHasOnePossibleValue(payload_ty) orelse try pt.undefValue(payload_ty); | |
| 3574 | const payload_val = try payload_ty.onePossibleValue(pt) orelse try pt.undefValue(payload_ty); | |
| 4167 | 3575 | const eu_val = try pt.intern(.{ .error_union = .{ |
| 4168 | 3576 | .ty = eu_ty.toIntern(), |
| 4169 | 3577 | .val = .{ .payload = payload_val.toIntern() }, |
| ... | ... | @@ -4178,7 +3586,7 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref, |
| 4178 | 3586 | // The payload value will be stored later, so undef is a sufficent payload for now. |
| 4179 | 3587 | const payload_ty: Type = .fromInterned(union_obj.field_types.get(&zcu.intern_pool)[idx]); |
| 4180 | 3588 | const payload_val = try pt.undefValue(payload_ty); |
| 4181 | const tag_val = try pt.enumValueFieldIndex(.fromInterned(union_obj.enum_tag_ty), idx); | |
| 3589 | const tag_val = try pt.enumValueFieldIndex(.fromInterned(union_obj.enum_tag_type), idx); | |
| 4182 | 3590 | const store_val = try pt.unionValue(maybe_union_ty, tag_val, payload_val); |
| 4183 | 3591 | try sema.storePtrVal(block, .unneeded, .fromInterned(decl_parent_ptr), store_val, maybe_union_ty); |
| 4184 | 3592 | } |
| ... | ... | @@ -4207,7 +3615,7 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref, |
| 4207 | 3615 | const tag_val: Value = .fromInterned(store_inst.data.bin_op.rhs.toInterned().?); |
| 4208 | 3616 | const union_ty = union_ptr_val.typeOf(zcu).childType(zcu); |
| 4209 | 3617 | const field_ty = union_ty.unionFieldType(tag_val, zcu).?; |
| 4210 | if (try sema.typeHasOnePossibleValue(field_ty)) |payload_val| { | |
| 3618 | if (try field_ty.onePossibleValue(pt)) |payload_val| { | |
| 4211 | 3619 | const new_union_val = try pt.unionValue(union_ty, tag_val, payload_val); |
| 4212 | 3620 | try sema.storePtrVal(block, .unneeded, union_ptr_val, new_union_val, union_ty); |
| 4213 | 3621 | } |
| ... | ... | @@ -4289,7 +3697,7 @@ fn finishResolveComptimeKnownAllocPtr( |
| 4289 | 3697 | fn makePtrTyConst(sema: *Sema, ptr_ty: Type) CompileError!Type { |
| 4290 | 3698 | var ptr_info = ptr_ty.ptrInfo(sema.pt.zcu); |
| 4291 | 3699 | ptr_info.flags.is_const = true; |
| 4292 | return sema.pt.ptrTypeSema(ptr_info); | |
| 3700 | return sema.pt.ptrType(ptr_info); | |
| 4293 | 3701 | } |
| 4294 | 3702 | |
| 4295 | 3703 | fn makePtrConst(sema: *Sema, block: *Block, alloc: Air.Inst.Ref) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -4326,21 +3734,23 @@ fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I |
| 4326 | 3734 | defer tracy.end(); |
| 4327 | 3735 | |
| 4328 | 3736 | const pt = sema.pt; |
| 3737 | const zcu = pt.zcu; | |
| 4329 | 3738 | |
| 4330 | 3739 | const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; |
| 4331 | 3740 | const ty_src = block.src(.{ .node_offset_var_decl_ty = inst_data.src_node }); |
| 4332 | 3741 | const var_src = block.nodeOffset(inst_data.src_node); |
| 4333 | 3742 | |
| 4334 | 3743 | const var_ty = try sema.resolveType(block, ty_src, inst_data.operand); |
| 4335 | if (block.isComptime() or try var_ty.comptimeOnlySema(pt)) { | |
| 3744 | try sema.ensureLayoutResolved(var_ty); | |
| 3745 | if (block.isComptime() or var_ty.comptimeOnly(zcu)) { | |
| 4336 | 3746 | return sema.analyzeComptimeAlloc(block, var_src, var_ty, .none); |
| 4337 | 3747 | } |
| 4338 | if (sema.func_is_naked and try var_ty.hasRuntimeBitsSema(pt)) { | |
| 3748 | if (sema.func_is_naked and var_ty.hasRuntimeBits(zcu)) { | |
| 4339 | 3749 | const mut_src = block.src(.{ .node_offset_store_ptr = inst_data.src_node }); |
| 4340 | 3750 | return sema.fail(block, mut_src, "local variable in naked function", .{}); |
| 4341 | 3751 | } |
| 4342 | const target = pt.zcu.getTarget(); | |
| 4343 | const ptr_type = try pt.ptrTypeSema(.{ | |
| 3752 | const target = zcu.getTarget(); | |
| 3753 | const ptr_type = try pt.ptrType(.{ | |
| 4344 | 3754 | .child = var_ty.toIntern(), |
| 4345 | 3755 | .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) }, |
| 4346 | 3756 | }); |
| ... | ... | @@ -4356,21 +3766,24 @@ fn zirAllocMut(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 4356 | 3766 | defer tracy.end(); |
| 4357 | 3767 | |
| 4358 | 3768 | const pt = sema.pt; |
| 3769 | const zcu = pt.zcu; | |
| 4359 | 3770 | |
| 4360 | 3771 | const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; |
| 4361 | 3772 | const ty_src = block.src(.{ .node_offset_var_decl_ty = inst_data.src_node }); |
| 4362 | 3773 | const var_src = block.nodeOffset(inst_data.src_node); |
| 3774 | ||
| 4363 | 3775 | const var_ty = try sema.resolveType(block, ty_src, inst_data.operand); |
| 3776 | try sema.ensureLayoutResolved(var_ty); | |
| 4364 | 3777 | if (block.isComptime()) { |
| 4365 | 3778 | return sema.analyzeComptimeAlloc(block, var_src, var_ty, .none); |
| 4366 | 3779 | } |
| 4367 | if (sema.func_is_naked and try var_ty.hasRuntimeBitsSema(pt)) { | |
| 3780 | if (sema.func_is_naked and var_ty.hasRuntimeBits(zcu)) { | |
| 4368 | 3781 | const store_src = block.src(.{ .node_offset_store_ptr = inst_data.src_node }); |
| 4369 | 3782 | return sema.fail(block, store_src, "local variable in naked function", .{}); |
| 4370 | 3783 | } |
| 4371 | 3784 | try sema.validateVarType(block, ty_src, var_ty, false); |
| 4372 | const target = pt.zcu.getTarget(); | |
| 4373 | const ptr_type = try pt.ptrTypeSema(.{ | |
| 3785 | const target = zcu.getTarget(); | |
| 3786 | const ptr_type = try pt.ptrType(.{ | |
| 4374 | 3787 | .child = var_ty.toIntern(), |
| 4375 | 3788 | .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) }, |
| 4376 | 3789 | }); |
| ... | ... | @@ -4430,8 +3843,9 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com |
| 4430 | 3843 | |
| 4431 | 3844 | switch (sema.air_instructions.items(.tag)[@intFromEnum(ptr_inst)]) { |
| 4432 | 3845 | .inferred_alloc_comptime => { |
| 4433 | // The work was already done for us by `Sema.storeToInferredAllocComptime`. | |
| 4434 | // All we need to do is return the pointer. | |
| 3846 | // The work was already done for us by `Sema.storeToInferredAllocComptime`. Also, since | |
| 3847 | // we had a value of the exact correct type to store, the result type's layout must be | |
| 3848 | // already resolved. So all we need to do here is return the pointer. | |
| 4435 | 3849 | const iac = sema.air_instructions.items(.data)[@intFromEnum(ptr_inst)].inferred_alloc_comptime; |
| 4436 | 3850 | const resolved_ptr = iac.ptr; |
| 4437 | 3851 | |
| ... | ... | @@ -4450,7 +3864,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com |
| 4450 | 3864 | }; |
| 4451 | 3865 | if (zcu.intern_pool.isFuncBody(val)) { |
| 4452 | 3866 | const ty: Type = .fromInterned(zcu.intern_pool.typeOf(val)); |
| 4453 | if (try ty.fnHasRuntimeBitsSema(pt)) { | |
| 3867 | if (ty.fnHasRuntimeBits(zcu)) { | |
| 4454 | 3868 | const orig_fn_index = zcu.intern_pool.unwrapCoercedFunc(val); |
| 4455 | 3869 | try sema.addReferenceEntry(block, src, .wrap(.{ .func = orig_fn_index })); |
| 4456 | 3870 | try zcu.ensureFuncBodyAnalysisQueued(orig_fn_index); |
| ... | ... | @@ -4469,8 +3883,10 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com |
| 4469 | 3883 | peer_val.* = bin_op.rhs; |
| 4470 | 3884 | } |
| 4471 | 3885 | const final_elem_ty = try sema.resolvePeerTypes(block, ty_src, peer_vals, .none); |
| 3886 | // The layout of the peers is already resolved, so the layout of `final_elem_ty` is too. | |
| 3887 | final_elem_ty.assertHasLayout(zcu); | |
| 4472 | 3888 | |
| 4473 | const final_ptr_ty = try pt.ptrTypeSema(.{ | |
| 3889 | const final_ptr_ty = try pt.ptrType(.{ | |
| 4474 | 3890 | .child = final_elem_ty.toIntern(), |
| 4475 | 3891 | .flags = .{ |
| 4476 | 3892 | .alignment = ia1.alignment, |
| ... | ... | @@ -4484,21 +3900,16 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com |
| 4484 | 3900 | const const_ptr_ty = try sema.makePtrTyConst(final_ptr_ty); |
| 4485 | 3901 | const new_const_ptr = try pt.getCoerced(Value.fromInterned(ptr_val), const_ptr_ty); |
| 4486 | 3902 | |
| 4487 | // Unless the block is comptime, `alloc_inferred` always produces | |
| 4488 | // a runtime constant. The final inferred type needs to be | |
| 4489 | // fully resolved so it can be lowered in codegen. | |
| 4490 | try final_elem_ty.resolveFully(pt); | |
| 4491 | ||
| 4492 | 3903 | return Air.internedToRef(new_const_ptr.toIntern()); |
| 4493 | 3904 | } |
| 4494 | 3905 | |
| 4495 | if (try final_elem_ty.comptimeOnlySema(pt)) { | |
| 3906 | if (final_elem_ty.comptimeOnly(zcu)) { | |
| 4496 | 3907 | // The alloc wasn't comptime-known per the above logic, so the |
| 4497 | 3908 | // type cannot be comptime-only. |
| 4498 | 3909 | // TODO: source location of runtime control flow |
| 4499 | 3910 | return sema.fail(block, src, "value with comptime-only type '{f}' depends on runtime control flow", .{final_elem_ty.fmt(pt)}); |
| 4500 | 3911 | } |
| 4501 | if (sema.func_is_naked and try final_elem_ty.hasRuntimeBitsSema(pt)) { | |
| 3912 | if (sema.func_is_naked and final_elem_ty.hasRuntimeBits(zcu)) { | |
| 4502 | 3913 | const mut_src = block.src(.{ .node_offset_store_ptr = inst_data.src_node }); |
| 4503 | 3914 | return sema.fail(block, mut_src, "local variable in naked function", .{}); |
| 4504 | 3915 | } |
| ... | ... | @@ -4812,7 +4223,7 @@ fn zirTryOperandTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is_ref: boo |
| 4812 | 4223 | if (is_ref) { |
| 4813 | 4224 | var ptr_info = operand_ty.ptrInfo(zcu); |
| 4814 | 4225 | ptr_info.child = eu_ty.toIntern(); |
| 4815 | const eu_ptr_ty = try pt.ptrTypeSema(ptr_info); | |
| 4226 | const eu_ptr_ty = try pt.ptrType(ptr_info); | |
| 4816 | 4227 | return Air.internedToRef(eu_ptr_ty.toIntern()); |
| 4817 | 4228 | } else { |
| 4818 | 4229 | return Air.internedToRef(eu_ty.toIntern()); |
| ... | ... | @@ -4935,7 +4346,6 @@ fn validateArrayInitTy( |
| 4935 | 4346 | return; |
| 4936 | 4347 | }, |
| 4937 | 4348 | .@"struct" => if (ty.isTuple(zcu)) { |
| 4938 | try ty.resolveFields(pt); | |
| 4939 | 4349 | const array_len = ty.arrayLen(zcu); |
| 4940 | 4350 | if (init_count > array_len) { |
| 4941 | 4351 | return sema.fail(block, src, "expected at most {d} tuple fields; found {d}", .{ |
| ... | ... | @@ -5097,12 +4507,16 @@ fn validateStructInit( |
| 5097 | 4507 | errdefer if (root_msg) |msg| msg.destroy(sema.gpa); |
| 5098 | 4508 | |
| 5099 | 4509 | for (found_fields, 0..) |explicit, i_usize| { |
| 5100 | if (explicit) continue; | |
| 5101 | 4510 | const i: u32 = @intCast(i_usize); |
| 5102 | 4511 | |
| 5103 | try struct_ty.resolveStructFieldInits(pt); | |
| 5104 | const default_val = struct_ty.structFieldDefaultValue(i, zcu); | |
| 5105 | if (default_val.toIntern() == .unreachable_value) { | |
| 4512 | if (explicit) continue; | |
| 4513 | if (struct_ty.structFieldIsComptime(i, zcu)) continue; | |
| 4514 | ||
| 4515 | if (!struct_ty.isTuple(zcu)) { | |
| 4516 | try sema.ensureFieldInitsResolved(struct_ty); | |
| 4517 | } | |
| 4518 | ||
| 4519 | const default_val = struct_ty.structFieldDefaultValue(i, zcu) orelse { | |
| 5106 | 4520 | const field_name = struct_ty.structFieldName(i, zcu).unwrap() orelse { |
| 5107 | 4521 | const template = "missing tuple field with index {d}"; |
| 5108 | 4522 | if (root_msg) |msg| { |
| ... | ... | @@ -5120,7 +4534,7 @@ fn validateStructInit( |
| 5120 | 4534 | root_msg = try sema.errMsg(init_src, template, args); |
| 5121 | 4535 | } |
| 5122 | 4536 | continue; |
| 5123 | } | |
| 4537 | }; | |
| 5124 | 4538 | |
| 5125 | 4539 | const field_src = init_src; // TODO better source location |
| 5126 | 4540 | const default_field_ptr = if (struct_ty.isTuple(zcu)) |
| ... | ... | @@ -5166,11 +4580,9 @@ fn zirValidatePtrArrayInit( |
| 5166 | 4580 | var root_msg: ?*Zcu.ErrorMsg = null; |
| 5167 | 4581 | errdefer if (root_msg) |msg| msg.destroy(sema.gpa); |
| 5168 | 4582 | |
| 5169 | try array_ty.resolveStructFieldInits(pt); | |
| 5170 | 4583 | var i = instrs.len; |
| 5171 | 4584 | while (i < array_len) : (i += 1) { |
| 5172 | const default_val = array_ty.structFieldDefaultValue(i, zcu).toIntern(); | |
| 5173 | if (default_val == .unreachable_value) { | |
| 4585 | if (array_ty.structFieldDefaultValue(i, zcu) == null) { | |
| 5174 | 4586 | const template = "missing tuple field with index {d}"; |
| 5175 | 4587 | if (root_msg) |msg| { |
| 5176 | 4588 | try sema.errNote(init_src, msg, template, .{i}); |
| ... | ... | @@ -5224,17 +4636,19 @@ fn zirValidateDeref(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr |
| 5224 | 4636 | .slice => return sema.fail(block, src, "index syntax required for slice type '{f}'", .{operand_ty.fmt(pt)}), |
| 5225 | 4637 | } |
| 5226 | 4638 | |
| 5227 | if ((try sema.typeHasOnePossibleValue(operand_ty.childType(zcu))) != null) { | |
| 4639 | const elem_ty = operand_ty.childType(zcu); | |
| 4640 | try sema.ensureLayoutResolved(elem_ty); | |
| 4641 | ||
| 4642 | if (try elem_ty.onePossibleValue(pt) != null) { | |
| 5228 | 4643 | // No need to validate the actual pointer value, we don't need it! |
| 5229 | 4644 | return; |
| 5230 | 4645 | } |
| 5231 | 4646 | |
| 5232 | const elem_ty = operand_ty.elemType2(zcu); | |
| 5233 | 4647 | if (try sema.resolveValue(operand)) |val| { |
| 5234 | 4648 | if (val.isUndef(zcu)) { |
| 5235 | 4649 | return sema.fail(block, src, "cannot dereference undefined value", .{}); |
| 5236 | 4650 | } |
| 5237 | } else if (try elem_ty.comptimeOnlySema(pt)) { | |
| 4651 | } else if (elem_ty.comptimeOnly(zcu)) { | |
| 5238 | 4652 | const msg = msg: { |
| 5239 | 4653 | const msg = try sema.errMsg( |
| 5240 | 4654 | src, |
| ... | ... | @@ -5373,7 +4787,7 @@ fn failWithBadUnionFieldAccess( |
| 5373 | 4787 | return sema.failWithOwnedErrorMsg(block, msg); |
| 5374 | 4788 | } |
| 5375 | 4789 | |
| 5376 | fn addDeclaredHereNote(sema: *Sema, parent: *Zcu.ErrorMsg, decl_ty: Type) !void { | |
| 4790 | pub fn addDeclaredHereNote(sema: *Sema, parent: *Zcu.ErrorMsg, decl_ty: Type) !void { | |
| 5377 | 4791 | const zcu = sema.pt.zcu; |
| 5378 | 4792 | const src_loc = decl_ty.srcLocOrNull(zcu) orelse return; |
| 5379 | 4793 | const category = switch (decl_ty.zigTypeTag(zcu)) { |
| ... | ... | @@ -5443,14 +4857,16 @@ fn storeToInferredAllocComptime( |
| 5443 | 4857 | const operand_val = try sema.resolveValue(operand) orelse { |
| 5444 | 4858 | return sema.failWithNeededComptime(block, src, .{ .simple = .stored_to_comptime_var }); |
| 5445 | 4859 | }; |
| 5446 | const alloc_ty = try pt.ptrTypeSema(.{ | |
| 4860 | const alloc_ty = try pt.ptrType(.{ | |
| 5447 | 4861 | .child = operand_ty.toIntern(), |
| 5448 | 4862 | .flags = .{ |
| 5449 | 4863 | .alignment = iac.alignment, |
| 5450 | 4864 | .is_const = iac.is_const, |
| 5451 | 4865 | }, |
| 5452 | 4866 | }); |
| 5453 | if (iac.is_const and !operand_val.canMutateComptimeVarState(zcu)) { | |
| 4867 | if (try operand_ty.onePossibleValue(pt) != null or | |
| 4868 | (iac.is_const and !operand_val.canMutateComptimeVarState(zcu))) | |
| 4869 | { | |
| 5454 | 4870 | iac.ptr = try pt.intern(.{ .ptr = .{ |
| 5455 | 4871 | .ty = alloc_ty.toIntern(), |
| 5456 | 4872 | .base_addr = .{ .uav = .{ |
| ... | ... | @@ -5624,7 +5040,7 @@ fn zirCompileLog( |
| 5624 | 5040 | |
| 5625 | 5041 | const arg = try sema.resolveInst(arg_ref); |
| 5626 | 5042 | const arg_ty = sema.typeOf(arg); |
| 5627 | if (try sema.resolveValueResolveLazy(arg)) |val| { | |
| 5043 | if (try sema.resolveValue(arg)) |val| { | |
| 5628 | 5044 | writer.print("@as({f}, {f})", .{ |
| 5629 | 5045 | arg_ty.fmt(pt), val.fmtValueSema(pt, sema), |
| 5630 | 5046 | }) catch return error.OutOfMemory; |
| ... | ... | @@ -5928,10 +5344,9 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr |
| 5928 | 5344 | return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)}); |
| 5929 | 5345 | |
| 5930 | 5346 | try pt.ensureFileAnalyzed(new_file_index); |
| 5931 | const ty = zcu.fileRootType(new_file_index); | |
| 5932 | try sema.declareDependency(.{ .interned = ty }); | |
| 5347 | const ty: Type = .fromInterned(zcu.fileRootType(new_file_index)); | |
| 5933 | 5348 | try sema.addTypeReferenceEntry(src, ty); |
| 5934 | return Air.internedToRef(ty); | |
| 5349 | return .fromType(ty); | |
| 5935 | 5350 | } |
| 5936 | 5351 | |
| 5937 | 5352 | fn zirSuspendBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -6177,10 +5592,11 @@ fn resolveAnalyzedBlock( |
| 6177 | 5592 | // to emit a jump instruction to after the block when it encounters the break. |
| 6178 | 5593 | try parent_block.instructions.append(gpa, merges.block_inst); |
| 6179 | 5594 | const resolved_ty = try sema.resolvePeerTypes(parent_block, src, merges.results.items, .{ .override = merges.src_locs.items }); |
| 5595 | resolved_ty.assertHasLayout(zcu); | |
| 6180 | 5596 | // TODO add note "missing else causes void value" |
| 6181 | 5597 | |
| 6182 | 5598 | const type_src = src; // TODO: better source location |
| 6183 | if (try resolved_ty.comptimeOnlySema(pt)) { | |
| 5599 | if (resolved_ty.comptimeOnly(zcu)) { | |
| 6184 | 5600 | const msg = msg: { |
| 6185 | 5601 | const msg = try sema.errMsg(type_src, "value with comptime-only type '{f}' depends on runtime control flow", .{resolved_ty.fmt(pt)}); |
| 6186 | 5602 | errdefer msg.destroy(sema.gpa); |
| ... | ... | @@ -6274,10 +5690,7 @@ fn resolveAnalyzedBlock( |
| 6274 | 5690 | }); |
| 6275 | 5691 | } |
| 6276 | 5692 | |
| 6277 | if (try sema.typeHasOnePossibleValue(resolved_ty)) |block_only_value| { | |
| 6278 | return Air.internedToRef(block_only_value.toIntern()); | |
| 6279 | } | |
| 6280 | ||
| 5693 | if (try resolved_ty.onePossibleValue(pt)) |opv| return .fromValue(opv); | |
| 6281 | 5694 | return merges.block_inst.toRef(); |
| 6282 | 5695 | } |
| 6283 | 5696 | |
| ... | ... | @@ -6413,7 +5826,8 @@ fn zirDisableInstrumentation(sema: *Sema) CompileError!void { |
| 6413 | 5826 | .@"comptime", |
| 6414 | 5827 | .nav_val, |
| 6415 | 5828 | .nav_ty, |
| 6416 | .type, | |
| 5829 | .type_layout, | |
| 5830 | .type_inits, | |
| 6417 | 5831 | .memoized_state, |
| 6418 | 5832 | => return, // does nothing outside a function |
| 6419 | 5833 | }; |
| ... | ... | @@ -6431,7 +5845,8 @@ fn zirDisableIntrinsics(sema: *Sema) CompileError!void { |
| 6431 | 5845 | .@"comptime", |
| 6432 | 5846 | .nav_val, |
| 6433 | 5847 | .nav_ty, |
| 6434 | .type, | |
| 5848 | .type_layout, | |
| 5849 | .type_inits, | |
| 6435 | 5850 | .memoized_state, |
| 6436 | 5851 | => return, // does nothing outside a function |
| 6437 | 5852 | }; |
| ... | ... | @@ -6589,8 +6004,8 @@ fn addDbgVar( |
| 6589 | 6004 | .dbg_var_val, .dbg_arg_inline => operand_ty, |
| 6590 | 6005 | else => unreachable, |
| 6591 | 6006 | }; |
| 6592 | if (try val_ty.comptimeOnlySema(pt)) return; | |
| 6593 | if (!(try val_ty.hasRuntimeBitsSema(pt))) return; | |
| 6007 | if (val_ty.comptimeOnly(zcu)) return; | |
| 6008 | if (!val_ty.hasRuntimeBits(zcu)) return; | |
| 6594 | 6009 | if (try sema.resolveValue(operand)) |operand_val| { |
| 6595 | 6010 | if (operand_val.canMutateComptimeVarState(zcu)) return; |
| 6596 | 6011 | } |
| ... | ... | @@ -6759,7 +6174,6 @@ pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref |
| 6759 | 6174 | if (!block.ownerModule().error_tracing) return .none; |
| 6760 | 6175 | |
| 6761 | 6176 | const stack_trace_ty = try sema.getBuiltinType(block.nodeOffset(.zero), .StackTrace); |
| 6762 | try stack_trace_ty.resolveFields(pt); | |
| 6763 | 6177 | const field_name = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, "index", .no_embedded_nulls); |
| 6764 | 6178 | const field_index = sema.structFieldIndex(block, stack_trace_ty, field_name, LazySrcLoc.unneeded) catch |err| switch (err) { |
| 6765 | 6179 | error.AnalysisFail => @panic("std.builtin.StackTrace is corrupt"), |
| ... | ... | @@ -6803,7 +6217,6 @@ fn popErrorReturnTrace( |
| 6803 | 6217 | // the result is comptime-known to be a non-error. Either way, pop unconditionally. |
| 6804 | 6218 | |
| 6805 | 6219 | const stack_trace_ty = try sema.getBuiltinType(src, .StackTrace); |
| 6806 | try stack_trace_ty.resolveFields(pt); | |
| 6807 | 6220 | const ptr_stack_trace_ty = try pt.singleMutPtrType(stack_trace_ty); |
| 6808 | 6221 | const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty); |
| 6809 | 6222 | const field_name = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, "index", .no_embedded_nulls); |
| ... | ... | @@ -6829,7 +6242,6 @@ fn popErrorReturnTrace( |
| 6829 | 6242 | |
| 6830 | 6243 | // If non-error, then pop the error return trace by restoring the index. |
| 6831 | 6244 | const stack_trace_ty = try sema.getBuiltinType(src, .StackTrace); |
| 6832 | try stack_trace_ty.resolveFields(pt); | |
| 6833 | 6245 | const ptr_stack_trace_ty = try pt.singleMutPtrType(stack_trace_ty); |
| 6834 | 6246 | const err_return_trace = try then_block.addTy(.err_return_trace, ptr_stack_trace_ty); |
| 6835 | 6247 | const field_name = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, "index", .no_embedded_nulls); |
| ... | ... | @@ -6969,7 +6381,6 @@ fn zirCall( |
| 6969 | 6381 | // need to clean-up our own trace if we were passed to a non-error-handling expression. |
| 6970 | 6382 | if (input_is_error or (pop_error_return_trace and return_ty.isError(zcu))) { |
| 6971 | 6383 | const stack_trace_ty = try sema.getBuiltinType(call_src, .StackTrace); |
| 6972 | try stack_trace_ty.resolveFields(pt); | |
| 6973 | 6384 | const field_name = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, "index", .no_embedded_nulls); |
| 6974 | 6385 | const field_index = try sema.structFieldIndex(block, stack_trace_ty, field_name, call_src); |
| 6975 | 6386 | |
| ... | ... | @@ -7318,6 +6729,8 @@ fn analyzeCall( |
| 7318 | 6729 | } else func_src; |
| 7319 | 6730 | |
| 7320 | 6731 | const func_ty_info = zcu.typeToFunc(func_ty).?; |
| 6732 | // MLUGG TODO: this isn't quite the check i want. this includes inline functions, which aren't *generic*... | |
| 6733 | const func_is_generic = !func_ty.fnHasRuntimeBits(zcu); | |
| 7321 | 6734 | if (!callConvIsCallable(func_ty_info.cc)) { |
| 7322 | 6735 | return sema.failWithOwnedErrorMsg(block, msg: { |
| 7323 | 6736 | const msg = try sema.errMsg( |
| ... | ... | @@ -7353,7 +6766,7 @@ fn analyzeCall( |
| 7353 | 6766 | else => unreachable, |
| 7354 | 6767 | } else .{ null, false }; |
| 7355 | 6768 | |
| 7356 | if (func_ty_info.is_generic and func_val == null) { | |
| 6769 | if (func_is_generic and func_val == null) { | |
| 7357 | 6770 | return sema.failWithNeededComptime(block, func_src, .{ .simple = .generic_call_target }); |
| 7358 | 6771 | } |
| 7359 | 6772 | |
| ... | ... | @@ -7369,19 +6782,18 @@ fn analyzeCall( |
| 7369 | 6782 | .src = call_src, |
| 7370 | 6783 | .r = .{ .simple = .comptime_call_modifier }, |
| 7371 | 6784 | } }; |
| 7372 | } else if (!inline_requested and try Type.fromInterned(func_ty_info.return_type).comptimeOnlySema(pt)) { | |
| 7373 | block.comptime_reason = .{ | |
| 7374 | .reason = .{ | |
| 6785 | } else if (!inline_requested) { | |
| 6786 | const ret_ty: Type = .fromInterned(func_ty_info.return_type); | |
| 6787 | if (ret_ty.comptimeOnly(zcu)) { | |
| 6788 | block.comptime_reason = .{ .reason = .{ | |
| 7375 | 6789 | .src = call_src, |
| 7376 | .r = .{ | |
| 7377 | .comptime_only_ret_ty = .{ | |
| 7378 | .ty = .fromInterned(func_ty_info.return_type), | |
| 7379 | .is_generic_inst = false, | |
| 7380 | .ret_ty_src = func_ret_ty_src, | |
| 7381 | }, | |
| 7382 | }, | |
| 7383 | }, | |
| 7384 | }; | |
| 6790 | .r = .{ .comptime_only_ret_ty = .{ | |
| 6791 | .ty = .fromInterned(func_ty_info.return_type), | |
| 6792 | .is_generic_inst = false, | |
| 6793 | .ret_ty_src = func_ret_ty_src, | |
| 6794 | } }, | |
| 6795 | } }; | |
| 6796 | } | |
| 7385 | 6797 | } |
| 7386 | 6798 | } |
| 7387 | 6799 | |
| ... | ... | @@ -7403,13 +6815,13 @@ fn analyzeCall( |
| 7403 | 6815 | // This is the `inst_map` used when evaluating generic parameters and return types. |
| 7404 | 6816 | var generic_inst_map: InstMap = .{}; |
| 7405 | 6817 | defer generic_inst_map.deinit(gpa); |
| 7406 | if (func_ty_info.is_generic) { | |
| 6818 | if (func_is_generic) { | |
| 7407 | 6819 | try generic_inst_map.ensureSpaceForInstructions(gpa, fn_zir_info.param_body); |
| 7408 | 6820 | } |
| 7409 | 6821 | |
| 7410 | 6822 | // This exists so that `generic_block` below can include a "called from here" note back to this |
| 7411 | 6823 | // call site when analyzing generic parameter/return types. |
| 7412 | var generic_inlining: Block.Inlining = if (func_ty_info.is_generic) .{ | |
| 6824 | var generic_inlining: Block.Inlining = if (func_is_generic) .{ | |
| 7413 | 6825 | .call_block = block, |
| 7414 | 6826 | .call_src = call_src, |
| 7415 | 6827 | .func = func_val.?.toIntern(), |
| ... | ... | @@ -7422,7 +6834,7 @@ fn analyzeCall( |
| 7422 | 6834 | // This is the block in which we evaluate generic function components: that is, generic parameter |
| 7423 | 6835 | // types and the generic return type. This must not be used if the function is not generic. |
| 7424 | 6836 | // `comptime_reason` is set as needed. |
| 7425 | var generic_block: Block = if (func_ty_info.is_generic) .{ | |
| 6837 | var generic_block: Block = if (func_is_generic) .{ | |
| 7426 | 6838 | .parent = null, |
| 7427 | 6839 | .sema = sema, |
| 7428 | 6840 | .namespace = fn_nav.analysis.?.namespace, |
| ... | ... | @@ -7431,9 +6843,9 @@ fn analyzeCall( |
| 7431 | 6843 | .src_base_inst = fn_nav.analysis.?.zir_index, |
| 7432 | 6844 | .type_name_ctx = fn_nav.fqn, |
| 7433 | 6845 | } else undefined; |
| 7434 | defer if (func_ty_info.is_generic) generic_block.instructions.deinit(gpa); | |
| 6846 | defer if (func_is_generic) generic_block.instructions.deinit(gpa); | |
| 7435 | 6847 | |
| 7436 | if (func_ty_info.is_generic) { | |
| 6848 | if (func_is_generic) { | |
| 7437 | 6849 | // We certainly depend on the generic owner's signature! |
| 7438 | 6850 | try sema.declareDependency(.{ .src_hash = fn_tracked_inst }); |
| 7439 | 6851 | } |
| ... | ... | @@ -7445,7 +6857,7 @@ fn analyzeCall( |
| 7445 | 6857 | if (raw != .generic_poison_type) break :ty .fromInterned(raw); |
| 7446 | 6858 | |
| 7447 | 6859 | // We must discover the generic parameter type. |
| 7448 | assert(func_ty_info.is_generic); | |
| 6860 | assert(func_is_generic); | |
| 7449 | 6861 | const param_inst_idx = fn_zir_info.param_body[arg_idx]; |
| 7450 | 6862 | const param_inst = fn_zir.instructions.get(@intFromEnum(param_inst_idx)); |
| 7451 | 6863 | switch (param_inst.tag) { |
| ... | ... | @@ -7494,11 +6906,11 @@ fn analyzeCall( |
| 7494 | 6906 | return arg.*; // terminate analysis here |
| 7495 | 6907 | } |
| 7496 | 6908 | |
| 7497 | if (func_ty_info.is_generic) { | |
| 6909 | if (func_is_generic) { | |
| 7498 | 6910 | // We need to put the argument into `generic_inst_map` so that other parameters can refer to it. |
| 7499 | 6911 | const param_inst_idx = fn_zir_info.param_body[arg_idx]; |
| 7500 | 6912 | const declared_comptime = if (std.math.cast(u5, arg_idx)) |i| func_ty_info.paramIsComptime(i) else false; |
| 7501 | const param_is_comptime = declared_comptime or try arg_ty.comptimeOnlySema(pt); | |
| 6913 | const param_is_comptime = declared_comptime or arg_ty.comptimeOnly(zcu); | |
| 7502 | 6914 | // We allow comptime-known arguments to propagate to generic types not only for comptime |
| 7503 | 6915 | // parameters, but if the call is known to be inline. |
| 7504 | 6916 | if (param_is_comptime or early_known_inline) { |
| ... | ... | @@ -7516,6 +6928,10 @@ fn analyzeCall( |
| 7516 | 6928 | ); |
| 7517 | 6929 | } |
| 7518 | 6930 | generic_inst_map.putAssumeCapacityNoClobber(param_inst_idx, arg.*); |
| 6931 | } else if (try arg_ty.onePossibleValue(pt)) |opv| { | |
| 6932 | // The argument is comptime-known, even though this is a generic instantiation (as | |
| 6933 | // opposed to an inline call), because the parameter type is OPV. | |
| 6934 | generic_inst_map.putAssumeCapacityNoClobber(param_inst_idx, .fromValue(opv)); | |
| 7519 | 6935 | } else { |
| 7520 | 6936 | // We need a dummy instruction with this type. It doesn't actually need to be in any block, |
| 7521 | 6937 | // since it will never be referenced at runtime! |
| ... | ... | @@ -7532,7 +6948,7 @@ fn analyzeCall( |
| 7532 | 6948 | // calls (where it should be the IES of the instantiation). However, it's how we print this |
| 7533 | 6949 | // in error messages. |
| 7534 | 6950 | const resolved_ret_ty: Type = ret_ty: { |
| 7535 | if (!func_ty_info.is_generic) break :ret_ty .fromInterned(func_ty_info.return_type); | |
| 6951 | if (!func_is_generic) break :ret_ty .fromInterned(func_ty_info.return_type); | |
| 7536 | 6952 | |
| 7537 | 6953 | const maybe_poison_bare = if (fn_zir_info.inferred_error_set) maybe_poison: { |
| 7538 | 6954 | break :maybe_poison ip.errorUnionPayload(func_ty_info.return_type); |
| ... | ... | @@ -7542,7 +6958,7 @@ fn analyzeCall( |
| 7542 | 6958 | |
| 7543 | 6959 | // Evaluate the generic return type. As with generic parameters, we switch out `sema.code` and `sema.inst_map`. |
| 7544 | 6960 | |
| 7545 | assert(func_ty_info.is_generic); | |
| 6961 | assert(func_is_generic); | |
| 7546 | 6962 | |
| 7547 | 6963 | const old_code = sema.code; |
| 7548 | 6964 | const old_inst_map = sema.inst_map; |
| ... | ... | @@ -7584,10 +7000,11 @@ fn analyzeCall( |
| 7584 | 7000 | |
| 7585 | 7001 | break :ret_ty full_ty; |
| 7586 | 7002 | }; |
| 7003 | try sema.ensureLayoutResolved(resolved_ret_ty); | |
| 7587 | 7004 | |
| 7588 | 7005 | // If we've discovered after evaluating arguments that a generic function instantiation is |
| 7589 | 7006 | // comptime-only, then we can mark the block as comptime *now*. |
| 7590 | if (!inline_requested and !block.isComptime() and try resolved_ret_ty.comptimeOnlySema(pt)) { | |
| 7007 | if (!inline_requested and !block.isComptime() and resolved_ret_ty.comptimeOnly(zcu)) { | |
| 7591 | 7008 | block.comptime_reason = .{ |
| 7592 | 7009 | .reason = .{ |
| 7593 | 7010 | .src = call_src, |
| ... | ... | @@ -7618,7 +7035,7 @@ fn analyzeCall( |
| 7618 | 7035 | }); |
| 7619 | 7036 | if (func_ty_info.cc == .auto) { |
| 7620 | 7037 | switch (sema.owner.unwrap()) { |
| 7621 | .@"comptime", .nav_ty, .nav_val, .type, .memoized_state => {}, | |
| 7038 | .@"comptime", .nav_ty, .nav_val, .type_layout, .type_inits, .memoized_state => {}, | |
| 7622 | 7039 | .func => |owner_func| ip.funcSetHasErrorTrace(io, owner_func, true), |
| 7623 | 7040 | } |
| 7624 | 7041 | } |
| ... | ... | @@ -7626,7 +7043,7 @@ fn analyzeCall( |
| 7626 | 7043 | try sema.validateRuntimeValue(block, args_info.argSrc(block, arg_idx), arg); |
| 7627 | 7044 | } |
| 7628 | 7045 | const runtime_func: Air.Inst.Ref, const runtime_args: []const Air.Inst.Ref = func: { |
| 7629 | if (!func_ty_info.is_generic) break :func .{ callee, args }; | |
| 7046 | if (!func_is_generic) break :func .{ callee, args }; | |
| 7630 | 7047 | |
| 7631 | 7048 | // Instantiate the generic function! |
| 7632 | 7049 | |
| ... | ... | @@ -7648,7 +7065,7 @@ fn analyzeCall( |
| 7648 | 7065 | break :c true; |
| 7649 | 7066 | } |
| 7650 | 7067 | } |
| 7651 | break :c try arg_ty.comptimeOnlySema(pt); | |
| 7068 | break :c arg_ty.comptimeOnly(zcu); | |
| 7652 | 7069 | }; |
| 7653 | 7070 | const is_noalias = if (std.math.cast(u5, arg_idx)) |i| func_ty_info.paramIsNoalias(i) else false; |
| 7654 | 7071 | |
| ... | ... | @@ -7680,6 +7097,7 @@ fn analyzeCall( |
| 7680 | 7097 | .generic_owner = func_val.?.toIntern(), |
| 7681 | 7098 | .comptime_args = comptime_args, |
| 7682 | 7099 | }); |
| 7100 | try sema.ensureLayoutResolved(.fromInterned(ip.typeOf(func_instance))); | |
| 7683 | 7101 | if (zcu.comp.debugIncremental()) { |
| 7684 | 7102 | const nav = ip.indexToKey(func_instance).func.owner_nav; |
| 7685 | 7103 | const gop = try zcu.incremental_debug_state.navs.getOrPut(gpa, nav); |
| ... | ... | @@ -7753,12 +7171,12 @@ fn analyzeCall( |
| 7753 | 7171 | return .unreachable_value; |
| 7754 | 7172 | } |
| 7755 | 7173 | |
| 7756 | const result: Air.Inst.Ref = if (try sema.typeHasOnePossibleValue(sema.typeOf(maybe_opv))) |opv| | |
| 7757 | .fromValue(opv) | |
| 7758 | else | |
| 7759 | maybe_opv; | |
| 7760 | ||
| 7761 | return result; | |
| 7174 | try sema.ensureLayoutResolved(sema.typeOf(maybe_opv)); | |
| 7175 | if (try sema.typeOf(maybe_opv).onePossibleValue(pt)) |opv| { | |
| 7176 | return .fromValue(opv); | |
| 7177 | } else { | |
| 7178 | return maybe_opv; | |
| 7179 | } | |
| 7762 | 7180 | } |
| 7763 | 7181 | |
| 7764 | 7182 | // This is an inline call. The function must be comptime-known. We will analyze its body directly using this `Sema`. |
| ... | ... | @@ -7824,6 +7242,11 @@ fn analyzeCall( |
| 7824 | 7242 | } |
| 7825 | 7243 | } |
| 7826 | 7244 | |
| 7245 | // We're about to do an inline call; if the return type expression was generic, the return type | |
| 7246 | // may not be resolved yet. It's correct to resolve it because the function is going to return a | |
| 7247 | // value of this type. | |
| 7248 | try sema.ensureLayoutResolved(resolved_ret_ty); | |
| 7249 | ||
| 7827 | 7250 | // For an inline call, we depend on the source code of the whole function definition. |
| 7828 | 7251 | try sema.declareDependency(.{ .src_hash = fn_nav.analysis.?.zir_index }); |
| 7829 | 7252 | |
| ... | ... | @@ -8000,6 +7423,10 @@ fn analyzeCall( |
| 8000 | 7423 | break :result try sema.resolveAnalyzedBlock(block, call_src, &child_block, &inlining.merges, need_debug_scope); |
| 8001 | 7424 | }; |
| 8002 | 7425 | |
| 7426 | if (sema.typeOf(result_raw).isNoReturn(zcu)) { | |
| 7427 | return .unreachable_value; | |
| 7428 | } | |
| 7429 | ||
| 8003 | 7430 | const maybe_opv: Air.Inst.Ref = if (try sema.resolveValue(result_raw)) |result_val| r: { |
| 8004 | 7431 | const val_resolved = try sema.resolveAdHocInferredErrorSet(block, call_src, result_val.toIntern()); |
| 8005 | 7432 | break :r Air.internedToRef(val_resolved); |
| ... | ... | @@ -8080,16 +7507,16 @@ fn zirArrayInitElemType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compil |
| 8080 | 7507 | const zcu = pt.zcu; |
| 8081 | 7508 | const bin = sema.code.instructions.items(.data)[@intFromEnum(inst)].bin; |
| 8082 | 7509 | const maybe_wrapped_indexable_ty = try sema.resolveTypeOrPoison(block, LazySrcLoc.unneeded, bin.lhs) orelse return .generic_poison_type; |
| 7510 | try sema.ensureLayoutResolved(maybe_wrapped_indexable_ty); | |
| 8083 | 7511 | const indexable_ty = maybe_wrapped_indexable_ty.optEuBaseType(zcu); |
| 8084 | try indexable_ty.resolveFields(pt); | |
| 8085 | 7512 | assert(indexable_ty.isIndexable(zcu)); // validated by a previous instruction |
| 8086 | if (indexable_ty.zigTypeTag(zcu) == .@"struct") { | |
| 8087 | const elem_type = indexable_ty.fieldType(@intFromEnum(bin.rhs), zcu); | |
| 8088 | return Air.internedToRef(elem_type.toIntern()); | |
| 8089 | } else { | |
| 8090 | const elem_type = indexable_ty.elemType2(zcu); | |
| 8091 | return Air.internedToRef(elem_type.toIntern()); | |
| 8092 | } | |
| 7513 | const elem_ty = switch (indexable_ty.zigTypeTag(zcu)) { | |
| 7514 | .@"struct" => indexable_ty.fieldType(@intFromEnum(bin.rhs), zcu), | |
| 7515 | .array, .vector => indexable_ty.childType(zcu), | |
| 7516 | .pointer => indexable_ty.indexablePtrElem(zcu), | |
| 7517 | else => unreachable, | |
| 7518 | }; | |
| 7519 | return .fromType(elem_ty); | |
| 8093 | 7520 | } |
| 8094 | 7521 | |
| 8095 | 7522 | fn zirElemType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -8355,7 +7782,7 @@ fn zirErrorFromInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD |
| 8355 | 7782 | const operand = try sema.coerce(block, err_int_ty, uncasted_operand, operand_src); |
| 8356 | 7783 | |
| 8357 | 7784 | if (try sema.resolveDefinedValue(block, operand_src, operand)) |value| { |
| 8358 | const int = try sema.usizeCast(block, operand_src, try value.toUnsignedIntSema(pt)); | |
| 7785 | const int = try sema.usizeCast(block, operand_src, value.toUnsignedInt(zcu)); | |
| 8359 | 7786 | if (int > len: { |
| 8360 | 7787 | const mutate = &ip.global_error_set.mutate; |
| 8361 | 7788 | mutate.map.mutex.lockUncancelable(io); |
| ... | ... | @@ -8539,7 +7966,6 @@ fn zirIntFromEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 8539 | 7966 | const enum_tag: Air.Inst.Ref = switch (operand_ty.zigTypeTag(zcu)) { |
| 8540 | 7967 | .@"enum" => operand, |
| 8541 | 7968 | .@"union" => blk: { |
| 8542 | try operand_ty.resolveFields(pt); | |
| 8543 | 7969 | const tag_ty = operand_ty.unionTagType(zcu) orelse { |
| 8544 | 7970 | return sema.fail( |
| 8545 | 7971 | block, |
| ... | ... | @@ -8568,17 +7994,9 @@ fn zirIntFromEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 8568 | 7994 | }); |
| 8569 | 7995 | } |
| 8570 | 7996 | |
| 8571 | if (try sema.typeHasOnePossibleValue(enum_tag_ty)) |opv| { | |
| 8572 | return Air.internedToRef((try pt.getCoerced(opv, int_tag_ty)).toIntern()); | |
| 8573 | } | |
| 8574 | ||
| 8575 | 7997 | if (try sema.resolveValue(enum_tag)) |enum_tag_val| { |
| 8576 | if (enum_tag_val.isUndef(zcu)) { | |
| 8577 | return pt.undefRef(int_tag_ty); | |
| 8578 | } | |
| 8579 | ||
| 8580 | const val = try enum_tag_val.intFromEnum(enum_tag_ty, pt); | |
| 8581 | return Air.internedToRef(val.toIntern()); | |
| 7998 | if (enum_tag_val.isUndef(zcu)) return pt.undefRef(int_tag_ty); | |
| 7999 | return .fromValue(enum_tag_val.intFromEnum(zcu)); | |
| 8582 | 8000 | } |
| 8583 | 8001 | |
| 8584 | 8002 | try sema.requireRuntimeBlock(block, src, operand_src); |
| ... | ... | @@ -8626,19 +8044,15 @@ fn zirEnumFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 8626 | 8044 | return sema.failWithNeededComptime(block, operand_src, .{ .simple = .casted_to_comptime_enum }); |
| 8627 | 8045 | } |
| 8628 | 8046 | |
| 8629 | if (try sema.typeHasOnePossibleValue(dest_ty)) |opv| { | |
| 8047 | if (try dest_ty.onePossibleValue(pt)) |opv| { | |
| 8630 | 8048 | if (block.wantSafety()) { |
| 8631 | 8049 | // The operand is runtime-known but the result is comptime-known. In |
| 8632 | 8050 | // this case we still need a safety check. |
| 8633 | const expect_int_val = switch (zcu.intern_pool.indexToKey(opv.toIntern())) { | |
| 8634 | .enum_tag => |enum_tag| enum_tag.int, | |
| 8635 | else => unreachable, | |
| 8636 | }; | |
| 8637 | const expect_int_coerced = try pt.getCoerced(.fromInterned(expect_int_val), operand_ty); | |
| 8638 | const ok = try block.addBinOp(.cmp_eq, operand, Air.internedToRef(expect_int_coerced.toIntern())); | |
| 8051 | const expect_int = try pt.getCoerced(opv.intFromEnum(zcu), operand_ty); | |
| 8052 | const ok = try block.addBinOp(.cmp_eq, operand, .fromValue(expect_int)); | |
| 8639 | 8053 | try sema.addSafetyCheck(block, src, ok, .invalid_enum_value); |
| 8640 | 8054 | } |
| 8641 | return Air.internedToRef(opv.toIntern()); | |
| 8055 | return .fromValue(opv); | |
| 8642 | 8056 | } |
| 8643 | 8057 | |
| 8644 | 8058 | try sema.requireRuntimeBlock(block, src, operand_src); |
| ... | ... | @@ -8666,6 +8080,7 @@ fn zirOptionalPayloadPtr( |
| 8666 | 8080 | return sema.analyzeOptionalPayloadPtr(block, src, optional_ptr, safety_check, false); |
| 8667 | 8081 | } |
| 8668 | 8082 | |
| 8083 | /// MLUGG TODO: pre-resolved child? | |
| 8669 | 8084 | fn analyzeOptionalPayloadPtr( |
| 8670 | 8085 | sema: *Sema, |
| 8671 | 8086 | block: *Block, |
| ... | ... | @@ -8685,7 +8100,8 @@ fn analyzeOptionalPayloadPtr( |
| 8685 | 8100 | } |
| 8686 | 8101 | |
| 8687 | 8102 | const child_type = opt_type.optionalChild(zcu); |
| 8688 | const child_pointer = try pt.ptrTypeSema(.{ | |
| 8103 | try sema.ensureLayoutResolved(child_type); | |
| 8104 | const child_pointer = try pt.ptrType(.{ | |
| 8689 | 8105 | .child = child_type.toIntern(), |
| 8690 | 8106 | .flags = .{ |
| 8691 | 8107 | .is_const = optional_ptr_ty.isConstPtr(zcu), |
| ... | ... | @@ -8698,7 +8114,7 @@ fn analyzeOptionalPayloadPtr( |
| 8698 | 8114 | if (sema.isComptimeMutablePtr(ptr_val)) { |
| 8699 | 8115 | // Set the optional to non-null at comptime. |
| 8700 | 8116 | // If the payload is OPV, we must use that value instead of undef. |
| 8701 | const payload_val = try sema.typeHasOnePossibleValue(child_type) orelse try pt.undefValue(child_type); | |
| 8117 | const payload_val = try child_type.onePossibleValue(pt) orelse try pt.undefValue(child_type); | |
| 8702 | 8118 | const opt_val = try pt.intern(.{ .opt = .{ |
| 8703 | 8119 | .ty = opt_type.toIntern(), |
| 8704 | 8120 | .val = payload_val.toIntern(), |
| ... | ... | @@ -8759,7 +8175,7 @@ fn zirOptionalPayload( |
| 8759 | 8175 | // TODO https://github.com/ziglang/zig/issues/6597 |
| 8760 | 8176 | if (true) break :t operand_ty; |
| 8761 | 8177 | const ptr_info = operand_ty.ptrInfo(zcu); |
| 8762 | break :t try pt.ptrTypeSema(.{ | |
| 8178 | break :t try pt.ptrType(.{ | |
| 8763 | 8179 | .child = ptr_info.child, |
| 8764 | 8180 | .flags = .{ |
| 8765 | 8181 | .alignment = ptr_info.flags.alignment, |
| ... | ... | @@ -8784,11 +8200,14 @@ fn zirOptionalPayload( |
| 8784 | 8200 | return .unreachable_value; |
| 8785 | 8201 | } |
| 8786 | 8202 | |
| 8787 | try sema.requireRuntimeBlock(block, src, null); | |
| 8788 | 8203 | if (safety_check and block.wantSafety()) { |
| 8789 | 8204 | const is_non_null = try block.addUnOp(.is_non_null, operand); |
| 8790 | 8205 | try sema.addSafetyCheck(block, src, is_non_null, .unwrap_null); |
| 8791 | 8206 | } |
| 8207 | ||
| 8208 | // If the payload is OPV, we need the safety check but have a comptime-known result. | |
| 8209 | if (try result_ty.onePossibleValue(pt)) |opv| return .fromValue(opv); | |
| 8210 | ||
| 8792 | 8211 | return block.addTyOp(.optional_payload, result_ty, operand); |
| 8793 | 8212 | } |
| 8794 | 8213 | |
| ... | ... | @@ -8844,8 +8263,8 @@ fn analyzeErrUnionPayload( |
| 8844 | 8263 | try sema.addSafetyCheckUnwrapError(block, src, operand, .unwrap_errunion_err, .is_non_err); |
| 8845 | 8264 | } |
| 8846 | 8265 | |
| 8847 | if (try sema.typeHasOnePossibleValue(payload_ty)) |payload_only_value| { | |
| 8848 | return Air.internedToRef(payload_only_value.toIntern()); | |
| 8266 | if (try payload_ty.onePossibleValue(pt)) |payload_opv| { | |
| 8267 | return .fromValue(payload_opv); | |
| 8849 | 8268 | } |
| 8850 | 8269 | |
| 8851 | 8270 | return block.addTyOp(.unwrap_errunion_payload, payload_ty, operand); |
| ... | ... | @@ -8867,6 +8286,7 @@ fn zirErrUnionPayloadPtr( |
| 8867 | 8286 | return sema.analyzeErrUnionPayloadPtr(block, src, operand, false, false); |
| 8868 | 8287 | } |
| 8869 | 8288 | |
| 8289 | /// MLUGG TODO LAYOUT: already-resolved child? | |
| 8870 | 8290 | fn analyzeErrUnionPayloadPtr( |
| 8871 | 8291 | sema: *Sema, |
| 8872 | 8292 | block: *Block, |
| ... | ... | @@ -8888,7 +8308,8 @@ fn analyzeErrUnionPayloadPtr( |
| 8888 | 8308 | |
| 8889 | 8309 | const err_union_ty = operand_ty.childType(zcu); |
| 8890 | 8310 | const payload_ty = err_union_ty.errorUnionPayload(zcu); |
| 8891 | const operand_pointer_ty = try pt.ptrTypeSema(.{ | |
| 8311 | try sema.ensureLayoutResolved(payload_ty); | |
| 8312 | const operand_pointer_ty = try pt.ptrType(.{ | |
| 8892 | 8313 | .child = payload_ty.toIntern(), |
| 8893 | 8314 | .flags = .{ |
| 8894 | 8315 | .is_const = operand_ty.isConstPtr(zcu), |
| ... | ... | @@ -8901,7 +8322,7 @@ fn analyzeErrUnionPayloadPtr( |
| 8901 | 8322 | if (sema.isComptimeMutablePtr(ptr_val)) { |
| 8902 | 8323 | // Set the error union to non-error at comptime. |
| 8903 | 8324 | // If the payload is OPV, we must use that value instead of undef. |
| 8904 | const payload_val = try sema.typeHasOnePossibleValue(payload_ty) orelse try pt.undefValue(payload_ty); | |
| 8325 | const payload_val = try payload_ty.onePossibleValue(pt) orelse try pt.undefValue(payload_ty); | |
| 8905 | 8326 | const eu_val = try pt.intern(.{ .error_union = .{ |
| 8906 | 8327 | .ty = err_union_ty.toIntern(), |
| 8907 | 8328 | .val = .{ .payload = payload_val.toIntern() }, |
| ... | ... | @@ -9571,10 +8992,6 @@ fn funcCommon( |
| 9571 | 8992 | |
| 9572 | 8993 | const ret_ty_src = block.src(.{ .node_offset_fn_type_ret_ty = src_node_offset }); |
| 9573 | 8994 | const cc_src = block.src(.{ .node_offset_fn_type_cc = src_node_offset }); |
| 9574 | const func_src = block.nodeOffset(src_node_offset); | |
| 9575 | ||
| 9576 | const ret_ty_requires_comptime = try bare_return_type.comptimeOnlySema(pt); | |
| 9577 | var is_generic = bare_return_type.isGenericPoison() or ret_ty_requires_comptime; | |
| 9578 | 8995 | |
| 9579 | 8996 | var comptime_bits: u32 = 0; |
| 9580 | 8997 | for (block.params.items(.ty), block.params.items(.is_comptime), 0..) |param_ty_ip, param_is_comptime, i| { |
| ... | ... | @@ -9587,11 +9004,7 @@ fn funcCommon( |
| 9587 | 9004 | .fn_proto_node_offset = src_node_offset, |
| 9588 | 9005 | .param_index = @intCast(i), |
| 9589 | 9006 | } }); |
| 9590 | const param_ty_comptime = try param_ty.comptimeOnlySema(pt); | |
| 9591 | 9007 | const param_ty_generic = param_ty.isGenericPoison(); |
| 9592 | if (param_is_comptime or param_ty_comptime or param_ty_generic) { | |
| 9593 | is_generic = true; | |
| 9594 | } | |
| 9595 | 9008 | if (param_is_comptime) { |
| 9596 | 9009 | comptime_bits |= @as(u32, 1) << @intCast(i); // TODO: handle cast error |
| 9597 | 9010 | } |
| ... | ... | @@ -9609,24 +9022,6 @@ fn funcCommon( |
| 9609 | 9022 | param_src, |
| 9610 | 9023 | cc, |
| 9611 | 9024 | ); |
| 9612 | if (param_ty_comptime and !param_is_comptime and has_body and !block.isComptime()) { | |
| 9613 | const msg = msg: { | |
| 9614 | const msg = try sema.errMsg(param_src, "parameter of type '{f}' must be declared comptime", .{ | |
| 9615 | param_ty.fmt(pt), | |
| 9616 | }); | |
| 9617 | errdefer msg.destroy(sema.gpa); | |
| 9618 | ||
| 9619 | try sema.explainWhyTypeIsComptime(msg, param_src, param_ty); | |
| 9620 | ||
| 9621 | try sema.addDeclaredHereNote(msg, param_ty); | |
| 9622 | break :msg msg; | |
| 9623 | }; | |
| 9624 | return sema.failWithOwnedErrorMsg(block, msg); | |
| 9625 | } | |
| 9626 | } | |
| 9627 | ||
| 9628 | if (var_args and is_generic) { | |
| 9629 | return sema.fail(block, func_src, "generic function cannot be variadic", .{}); | |
| 9630 | 9025 | } |
| 9631 | 9026 | |
| 9632 | 9027 | try sema.checkReturnTypeAndCallConvCommon( |
| ... | ... | @@ -9643,46 +9038,6 @@ fn funcCommon( |
| 9643 | 9038 | is_noinline, |
| 9644 | 9039 | ); |
| 9645 | 9040 | |
| 9646 | // If the return type is comptime-only but not dependent on parameters then | |
| 9647 | // all parameter types also need to be comptime. | |
| 9648 | if (has_body and ret_ty_requires_comptime and !block.isComptime()) comptime_check: { | |
| 9649 | for (block.params.items(.is_comptime)) |is_comptime| { | |
| 9650 | if (!is_comptime) break; | |
| 9651 | } else break :comptime_check; | |
| 9652 | const ies_ret_ty_prefix: []const u8 = if (inferred_error_set) "!" else ""; | |
| 9653 | const msg = try sema.errMsg( | |
| 9654 | ret_ty_src, | |
| 9655 | "function with comptime-only return type '{s}{f}' requires all parameters to be comptime", | |
| 9656 | .{ ies_ret_ty_prefix, bare_return_type.fmt(pt) }, | |
| 9657 | ); | |
| 9658 | errdefer msg.destroy(sema.gpa); | |
| 9659 | try sema.explainWhyTypeIsComptime(msg, ret_ty_src, bare_return_type); | |
| 9660 | ||
| 9661 | const tags = sema.code.instructions.items(.tag); | |
| 9662 | const data = sema.code.instructions.items(.data); | |
| 9663 | const param_body = sema.code.getParamBody(func_inst); | |
| 9664 | for ( | |
| 9665 | block.params.items(.is_comptime), | |
| 9666 | block.params.items(.name), | |
| 9667 | param_body[0..block.params.len], | |
| 9668 | ) |is_comptime, name_nts, param_index| { | |
| 9669 | if (!is_comptime) { | |
| 9670 | const param_src = block.tokenOffset(switch (tags[@intFromEnum(param_index)]) { | |
| 9671 | .param => data[@intFromEnum(param_index)].pl_tok.src_tok, | |
| 9672 | .param_anytype => data[@intFromEnum(param_index)].str_tok.src_tok, | |
| 9673 | else => unreachable, | |
| 9674 | }); | |
| 9675 | const name = sema.code.nullTerminatedString(name_nts); | |
| 9676 | if (name.len != 0) { | |
| 9677 | try sema.errNote(param_src, msg, "param '{s}' is required to be comptime", .{name}); | |
| 9678 | } else { | |
| 9679 | try sema.errNote(param_src, msg, "param is required to be comptime", .{}); | |
| 9680 | } | |
| 9681 | } | |
| 9682 | } | |
| 9683 | return sema.failWithOwnedErrorMsg(block, msg); | |
| 9684 | } | |
| 9685 | ||
| 9686 | 9041 | const param_types = block.params.items(.ty); |
| 9687 | 9042 | |
| 9688 | 9043 | if (inferred_error_set) { |
| ... | ... | @@ -9696,7 +9051,6 @@ fn funcCommon( |
| 9696 | 9051 | .bare_return_type = bare_return_type.toIntern(), |
| 9697 | 9052 | .cc = cc, |
| 9698 | 9053 | .is_var_args = var_args, |
| 9699 | .is_generic = is_generic, | |
| 9700 | 9054 | .is_noinline = is_noinline, |
| 9701 | 9055 | |
| 9702 | 9056 | .zir_body_inst = try block.trackZir(func_inst), |
| ... | ... | @@ -9714,7 +9068,6 @@ fn funcCommon( |
| 9714 | 9068 | .return_type = bare_return_type.toIntern(), |
| 9715 | 9069 | .cc = cc, |
| 9716 | 9070 | .is_var_args = var_args, |
| 9717 | .is_generic = is_generic, | |
| 9718 | 9071 | .is_noinline = is_noinline, |
| 9719 | 9072 | }); |
| 9720 | 9073 | |
| ... | ... | @@ -9845,16 +9198,7 @@ fn zirIntFromPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! |
| 9845 | 9198 | if (!ptr_ty.isPtrAtRuntime(zcu)) { |
| 9846 | 9199 | return sema.fail(block, ptr_src, "expected pointer, found '{f}'", .{ptr_ty.fmt(pt)}); |
| 9847 | 9200 | } |
| 9848 | const pointee_ty = ptr_ty.childType(zcu); | |
| 9849 | if (try ptr_ty.comptimeOnlySema(pt)) { | |
| 9850 | const msg = msg: { | |
| 9851 | const msg = try sema.errMsg(ptr_src, "comptime-only type '{f}' has no pointer address", .{pointee_ty.fmt(pt)}); | |
| 9852 | errdefer msg.destroy(sema.gpa); | |
| 9853 | try sema.explainWhyTypeIsComptime(msg, ptr_src, pointee_ty); | |
| 9854 | break :msg msg; | |
| 9855 | }; | |
| 9856 | return sema.failWithOwnedErrorMsg(block, msg); | |
| 9857 | } | |
| 9201 | ||
| 9858 | 9202 | const len = if (is_vector) operand_ty.vectorLen(zcu) else undefined; |
| 9859 | 9203 | const dest_ty: Type = if (is_vector) try pt.vectorType(.{ .child = .usize_type, .len = len }) else .usize; |
| 9860 | 9204 | |
| ... | ... | @@ -9863,7 +9207,7 @@ fn zirIntFromPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! |
| 9863 | 9207 | if (operand_val.isUndef(zcu)) { |
| 9864 | 9208 | return .undef_usize; |
| 9865 | 9209 | } |
| 9866 | const addr = try operand_val.getUnsignedIntSema(pt) orelse { | |
| 9210 | const addr = operand_val.getUnsignedInt(zcu) orelse { | |
| 9867 | 9211 | // Wasn't an integer pointer. This is a runtime operation. |
| 9868 | 9212 | break :ct; |
| 9869 | 9213 | }; |
| ... | ... | @@ -9879,7 +9223,7 @@ fn zirIntFromPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! |
| 9879 | 9223 | new_elem.* = .undef_usize; |
| 9880 | 9224 | continue; |
| 9881 | 9225 | } |
| 9882 | const addr = try ptr_val.getUnsignedIntSema(pt) orelse { | |
| 9226 | const addr = ptr_val.getUnsignedInt(zcu) orelse { | |
| 9883 | 9227 | // A vector element wasn't an integer pointer. This is a runtime operation. |
| 9884 | 9228 | break :ct; |
| 9885 | 9229 | }; |
| ... | ... | @@ -10044,7 +9388,7 @@ fn intCast( |
| 10044 | 9388 | try sema.checkVectorizableBinaryOperands(block, operand_src, dest_ty, operand_ty, dest_ty_src, operand_src); |
| 10045 | 9389 | const is_vector = dest_ty.zigTypeTag(zcu) == .vector; |
| 10046 | 9390 | |
| 10047 | if ((try sema.typeHasOnePossibleValue(dest_ty))) |opv| { | |
| 9391 | if (try dest_ty.onePossibleValue(pt)) |opv| { | |
| 10048 | 9392 | // requirement: intCast(u0, input) iff input == 0 |
| 10049 | 9393 | if (block.wantSafety()) { |
| 10050 | 9394 | try sema.requireRuntimeBlock(block, src, operand_src); |
| ... | ... | @@ -10382,6 +9726,8 @@ fn zirElemPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 10382 | 9726 | }; |
| 10383 | 9727 | return sema.failWithOwnedErrorMsg(block, msg); |
| 10384 | 9728 | } |
| 9729 | try sema.checkIndexable(block, src, indexable_ty); | |
| 9730 | try sema.ensureLayoutResolved(indexable_ty.childType(zcu)); | |
| 10385 | 9731 | return sema.elemPtrOneLayerOnly(block, src, array_ptr, elem_index, src, false, false); |
| 10386 | 9732 | } |
| 10387 | 9733 | |
| ... | ... | @@ -10764,7 +10110,8 @@ fn analyzeSwitchBlock( |
| 10764 | 10110 | .{ raw_operand, .none }; |
| 10765 | 10111 | |
| 10766 | 10112 | const operand_ty = sema.typeOf(val); |
| 10767 | const maybe_operand_opv = try sema.typeHasOnePossibleValue(operand_ty); | |
| 10113 | operand_ty.assertHasLayout(zcu); | |
| 10114 | const maybe_operand_opv = try operand_ty.onePossibleValue(pt); | |
| 10768 | 10115 | const init_cond: Air.Inst.Ref, const item_ty: Type = switch (operand_ty.zigTypeTag(zcu)) { |
| 10769 | 10116 | .@"union" => tag: { |
| 10770 | 10117 | const tag_ty = operand_ty.unionTagType(zcu).?; |
| ... | ... | @@ -10776,6 +10123,7 @@ fn analyzeSwitchBlock( |
| 10776 | 10123 | operand_ty, |
| 10777 | 10124 | }, |
| 10778 | 10125 | }; |
| 10126 | item_ty.assertHasLayout(zcu); | |
| 10779 | 10127 | |
| 10780 | 10128 | if (zir_switch.has_continue and !block.isComptime()) { |
| 10781 | 10129 | const operand_alloc: Air.Inst.Ref = if (zir_switch.any_maybe_runtime_capture and |
| ... | ... | @@ -10881,7 +10229,7 @@ fn analyzeSwitchBlock( |
| 10881 | 10229 | unreachable; |
| 10882 | 10230 | } |
| 10883 | 10231 | |
| 10884 | if (try sema.typeHasOnePossibleValue(item_ty)) |item_opv| { | |
| 10232 | if (try item_ty.onePossibleValue(pt)) |item_opv| { | |
| 10885 | 10233 | // We simplify conditions with OPV to either a `loop` or a `block` since |
| 10886 | 10234 | // we cannot switch on a value which doesn't exist at runtime. |
| 10887 | 10235 | assert(operand == .loop); // `simple` should have already been comptime-resolved above! |
| ... | ... | @@ -11249,8 +10597,8 @@ fn finishSwitchBr( |
| 11249 | 10597 | var item = sema.resolveConstDefinedValue(block, .unneeded, range_ref[0], undefined) catch unreachable; |
| 11250 | 10598 | const item_last = sema.resolveConstDefinedValue(block, .unneeded, range_ref[1], undefined) catch unreachable; |
| 11251 | 10599 | |
| 11252 | if (try item.getUnsignedIntSema(pt)) |first_int| { | |
| 11253 | if (try item_last.getUnsignedIntSema(pt)) |last_int| { | |
| 10600 | if (item.getUnsignedInt(zcu)) |first_int| { | |
| 10601 | if (item_last.getUnsignedInt(zcu)) |last_int| { | |
| 11254 | 10602 | if (std.math.cast(u32, last_int - first_int)) |range_len| { |
| 11255 | 10603 | try branch_hints.ensureUnusedCapacity(gpa, range_len); |
| 11256 | 10604 | } |
| ... | ... | @@ -11259,7 +10607,6 @@ fn finishSwitchBr( |
| 11259 | 10607 | |
| 11260 | 10608 | var prev_result_overflowed = false; |
| 11261 | 10609 | while (item.compareScalar(.lte, item_last, operand_ty, zcu)) : ({ |
| 11262 | // Previous validation has resolved any possible lazy values. | |
| 11263 | 10610 | const int_val: Value, const int_ty: Type = switch (operand_ty.zigTypeTag(zcu)) { |
| 11264 | 10611 | .int => .{ item, operand_ty }, |
| 11265 | 10612 | .@"enum" => b: { |
| ... | ... | @@ -11896,72 +11243,68 @@ fn validateSwitchBlock( |
| 11896 | 11243 | try sema.inst_map.ensureSpaceForInstructions(gpa, &.{tag_capture_inst}); |
| 11897 | 11244 | } |
| 11898 | 11245 | |
| 11899 | const operand_ty: Type, const item_ty: Type = check_operand: { | |
| 11900 | const operand_ty = operand_ty: { | |
| 11901 | const raw_operand_ty = sema.typeOf(raw_operand); | |
| 11902 | if (operand_is_ref) { | |
| 11903 | try sema.checkPtrType(block, operand_src, raw_operand_ty, false); | |
| 11904 | break :operand_ty raw_operand_ty.childType(zcu); | |
| 11905 | } | |
| 11906 | break :operand_ty raw_operand_ty; | |
| 11907 | }; | |
| 11908 | ||
| 11909 | const item_ty: Type = item_ty: { | |
| 11910 | switch (operand_ty.zigTypeTag(zcu)) { | |
| 11911 | .@"enum", | |
| 11912 | .error_set, | |
| 11913 | .int, | |
| 11914 | .comptime_int, | |
| 11915 | .type, | |
| 11916 | .enum_literal, | |
| 11917 | .@"fn", | |
| 11918 | .bool, | |
| 11919 | .void, | |
| 11920 | => break :item_ty operand_ty, | |
| 11246 | const operand_ty = operand_ty: { | |
| 11247 | const raw_operand_ty = sema.typeOf(raw_operand); | |
| 11248 | if (operand_is_ref) { | |
| 11249 | try sema.checkPtrType(block, operand_src, raw_operand_ty, false); | |
| 11250 | break :operand_ty raw_operand_ty.childType(zcu); | |
| 11251 | } | |
| 11252 | break :operand_ty raw_operand_ty; | |
| 11253 | }; | |
| 11254 | try sema.ensureLayoutResolved(operand_ty); | |
| 11921 | 11255 | |
| 11922 | .@"union" => { | |
| 11923 | try operand_ty.resolveFields(pt); | |
| 11924 | const enum_ty = operand_ty.unionTagType(zcu) orelse { | |
| 11925 | return sema.failWithOwnedErrorMsg(block, msg: { | |
| 11926 | const msg = try sema.errMsg(operand_src, "switch on union with no attached enum", .{}); | |
| 11927 | errdefer msg.destroy(sema.gpa); | |
| 11928 | if (operand_ty.srcLocOrNull(zcu)) |union_src| { | |
| 11929 | try sema.errNote(union_src, msg, "consider 'union(enum)' here", .{}); | |
| 11930 | } | |
| 11931 | break :msg msg; | |
| 11932 | }); | |
| 11933 | }; | |
| 11934 | break :item_ty enum_ty; | |
| 11935 | }, | |
| 11256 | const item_ty: Type = item_ty: { | |
| 11257 | switch (operand_ty.zigTypeTag(zcu)) { | |
| 11258 | .@"enum", | |
| 11259 | .error_set, | |
| 11260 | .int, | |
| 11261 | .comptime_int, | |
| 11262 | .type, | |
| 11263 | .enum_literal, | |
| 11264 | .@"fn", | |
| 11265 | .bool, | |
| 11266 | .void, | |
| 11267 | => break :item_ty operand_ty, | |
| 11936 | 11268 | |
| 11937 | .pointer => { | |
| 11938 | if (!operand_ty.isSlice(zcu)) { | |
| 11939 | break :item_ty operand_ty; | |
| 11940 | } | |
| 11941 | }, | |
| 11269 | .@"union" => { | |
| 11270 | const enum_ty = operand_ty.unionTagType(zcu) orelse { | |
| 11271 | return sema.failWithOwnedErrorMsg(block, msg: { | |
| 11272 | const msg = try sema.errMsg(operand_src, "switch on union with no attached enum", .{}); | |
| 11273 | errdefer msg.destroy(sema.gpa); | |
| 11274 | if (operand_ty.srcLocOrNull(zcu)) |union_src| { | |
| 11275 | try sema.errNote(union_src, msg, "consider 'union(enum)' here", .{}); | |
| 11276 | } | |
| 11277 | break :msg msg; | |
| 11278 | }); | |
| 11279 | }; | |
| 11280 | break :item_ty enum_ty; | |
| 11281 | }, | |
| 11942 | 11282 | |
| 11943 | else => {}, | |
| 11944 | } | |
| 11945 | return sema.fail(block, operand_src, "switch on type '{f}'", .{operand_ty.fmt(pt)}); | |
| 11946 | }; | |
| 11283 | .pointer => { | |
| 11284 | if (!operand_ty.isSlice(zcu)) { | |
| 11285 | break :item_ty operand_ty; | |
| 11286 | } | |
| 11287 | }, | |
| 11947 | 11288 | |
| 11948 | if (zir_switch.has_continue and !block.isComptime()) { | |
| 11949 | if (try operand_ty.comptimeOnlySema(pt)) { | |
| 11950 | // Even if the operand is comptime-known, this `switch` is runtime. | |
| 11951 | return sema.failWithOwnedErrorMsg(block, msg: { | |
| 11952 | const msg = try sema.errMsg(operand_src, "operand of switch loop has comptime-only type '{f}'", .{operand_ty.fmt(pt)}); | |
| 11953 | errdefer msg.destroy(gpa); | |
| 11954 | try sema.errNote(operand_src, msg, "switch loops are evaluated at runtime outside of comptime scopes", .{}); | |
| 11955 | try sema.explainWhyTypeIsComptime(msg, operand_src, operand_ty); | |
| 11956 | break :msg msg; | |
| 11957 | }); | |
| 11958 | } | |
| 11959 | try sema.validateRuntimeValue(block, operand_src, raw_operand); | |
| 11289 | else => {}, | |
| 11960 | 11290 | } |
| 11961 | ||
| 11962 | break :check_operand .{ operand_ty, item_ty }; | |
| 11291 | return sema.fail(block, operand_src, "switch on type '{f}'", .{operand_ty.fmt(pt)}); | |
| 11963 | 11292 | }; |
| 11964 | 11293 | |
| 11294 | if (zir_switch.has_continue and !block.isComptime()) { | |
| 11295 | if (operand_ty.comptimeOnly(zcu)) { | |
| 11296 | // Even if the operand is comptime-known, this `switch` is runtime. | |
| 11297 | return sema.failWithOwnedErrorMsg(block, msg: { | |
| 11298 | const msg = try sema.errMsg(operand_src, "operand of switch loop has comptime-only type '{f}'", .{operand_ty.fmt(pt)}); | |
| 11299 | errdefer msg.destroy(gpa); | |
| 11300 | try sema.errNote(operand_src, msg, "switch loops are evaluated at runtime outside of comptime scopes", .{}); | |
| 11301 | try sema.explainWhyTypeIsComptime(msg, operand_src, operand_ty); | |
| 11302 | break :msg msg; | |
| 11303 | }); | |
| 11304 | } | |
| 11305 | try sema.validateRuntimeValue(block, operand_src, raw_operand); | |
| 11306 | } | |
| 11307 | ||
| 11965 | 11308 | const has_else = zir_switch.else_case != null; |
| 11966 | 11309 | const has_under = zir_switch.has_under; |
| 11967 | 11310 | |
| ... | ... | @@ -12305,7 +11648,7 @@ fn resolveSwitchBlock( |
| 12305 | 11648 | child_block: *Block, |
| 12306 | 11649 | operand: SwitchOperand, |
| 12307 | 11650 | raw_operand_ty: Type, |
| 12308 | maybe_lazy_cond_val: Value, | |
| 11651 | cond_val: Value, | |
| 12309 | 11652 | merges: *Block.Merges, |
| 12310 | 11653 | switch_inst: Zir.Inst.Index, |
| 12311 | 11654 | zir_switch: *const Zir.UnwrappedSwitchBlock, |
| ... | ... | @@ -12325,9 +11668,6 @@ fn resolveSwitchBlock( |
| 12325 | 11668 | const err_set = item_ty.zigTypeTag(zcu) == .error_set; |
| 12326 | 11669 | |
| 12327 | 11670 | const cond_ref = operand.simple.cond; |
| 12328 | // We have to resolve lazy values to ensure that comparisons with switch | |
| 12329 | // prong items don't produce false negatives. | |
| 12330 | const cond_val = try sema.resolveLazyValue(maybe_lazy_cond_val); | |
| 12331 | 11671 | |
| 12332 | 11672 | const case_vals = validated_switch.case_vals; |
| 12333 | 11673 | var case_val_idx: usize = 0; |
| ... | ... | @@ -12617,14 +11957,12 @@ fn wantSwitchProngBodyAnalysis( |
| 12617 | 11957 | ) bool { |
| 12618 | 11958 | const zcu = sema.pt.zcu; |
| 12619 | 11959 | if (union_originally) { |
| 12620 | const unresolved_item_val = sema.resolveConstDefinedValue(block, .unneeded, item_ref, undefined) catch unreachable; | |
| 12621 | const item_val = sema.resolveLazyValue(unresolved_item_val) catch unreachable; | |
| 11960 | const item_val = sema.resolveConstDefinedValue(block, .unneeded, item_ref, undefined) catch unreachable; | |
| 12622 | 11961 | const field_ty = operand_ty.unionFieldType(item_val, zcu).?; |
| 12623 | 11962 | if (field_ty.isNoReturn(zcu)) return false; |
| 12624 | 11963 | } |
| 12625 | 11964 | if (err_set and prong_is_comptime_unreach) { |
| 12626 | const unresolved_item_val = sema.resolveConstDefinedValue(block, .unneeded, item_ref, undefined) catch unreachable; | |
| 12627 | const item_val = sema.resolveLazyValue(unresolved_item_val) catch unreachable; | |
| 11965 | const item_val = sema.resolveConstDefinedValue(block, .unneeded, item_ref, undefined) catch unreachable; | |
| 12628 | 11966 | const err_name = item_val.getErrorName(zcu).unwrap().?; |
| 12629 | 11967 | if (!Type.errorSetHasFieldIp(&zcu.intern_pool, operand_ty.toIntern(), err_name)) return false; |
| 12630 | 11968 | } |
| ... | ... | @@ -12807,7 +12145,7 @@ fn analyzeSwitchPayloadCapture( |
| 12807 | 12145 | const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]); |
| 12808 | 12146 | if (capture_by_ref) { |
| 12809 | 12147 | const operand_ptr_info = sema.typeOf(operand_ptr).ptrInfo(zcu); |
| 12810 | const ptr_field_ty = try pt.ptrTypeSema(.{ | |
| 12148 | const ptr_field_ty = try pt.ptrType(.{ | |
| 12811 | 12149 | .child = field_ty.toIntern(), |
| 12812 | 12150 | .flags = .{ |
| 12813 | 12151 | .is_const = operand_ptr_info.flags.is_const, |
| ... | ... | @@ -12821,6 +12159,7 @@ fn analyzeSwitchPayloadCapture( |
| 12821 | 12159 | const tag_and_val = ip.indexToKey(union_val.toIntern()).un; |
| 12822 | 12160 | return .fromIntern(tag_and_val.val); |
| 12823 | 12161 | } |
| 12162 | if (try field_ty.onePossibleValue(pt)) |opv| return .fromValue(opv); | |
| 12824 | 12163 | return case_block.addStructFieldVal(operand_val, field_index, field_ty); |
| 12825 | 12164 | } |
| 12826 | 12165 | } else if (capture_by_ref) { |
| ... | ... | @@ -12914,13 +12253,27 @@ fn analyzeSwitchPayloadCapture( |
| 12914 | 12253 | const dummy_captures = try sema.arena.alloc(Air.Inst.Ref, case_vals.len); |
| 12915 | 12254 | for (field_indices, dummy_captures) |field_idx, *dummy| { |
| 12916 | 12255 | const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_idx]); |
| 12917 | const field_ptr_ty = try pt.ptrTypeSema(.{ | |
| 12256 | const field_ptr_ty = try pt.ptrType(.{ | |
| 12918 | 12257 | .child = field_ty.toIntern(), |
| 12919 | 12258 | .flags = .{ |
| 12920 | 12259 | .is_const = operand_ptr_info.flags.is_const, |
| 12921 | 12260 | .is_volatile = operand_ptr_info.flags.is_volatile, |
| 12922 | 12261 | .address_space = operand_ptr_info.flags.address_space, |
| 12923 | .alignment = union_obj.fieldAlign(ip, field_idx), | |
| 12262 | // TODO MLUGG: double-check this. and, um, EVERYWHERE we do ptr alignment... | |
| 12263 | .alignment = a: { | |
| 12264 | if (operand_ty.explicitFieldAlignment(field_idx, zcu) == .none and | |
| 12265 | operand_ptr_info.flags.alignment == .none) | |
| 12266 | { | |
| 12267 | break :a .none; | |
| 12268 | } | |
| 12269 | ||
| 12270 | const union_align = switch (operand_ptr_info.flags.alignment) { | |
| 12271 | .none => operand_ty.abiAlignment(zcu), | |
| 12272 | else => |a| a, | |
| 12273 | }; | |
| 12274 | const field_align = operand_ty.resolvedFieldAlignment(field_idx, zcu); | |
| 12275 | break :a .minStrict(union_align, field_align); | |
| 12276 | }, | |
| 12924 | 12277 | }, |
| 12925 | 12278 | }); |
| 12926 | 12279 | dummy.* = try pt.undefRef(field_ptr_ty); |
| ... | ... | @@ -12963,6 +12316,8 @@ fn analyzeSwitchPayloadCapture( |
| 12963 | 12316 | return case_block.addStructFieldPtr(operand_ptr, first_field_index, capture_ptr_ty); |
| 12964 | 12317 | } |
| 12965 | 12318 | |
| 12319 | if (try capture_ty.onePossibleValue(pt)) |opv| return .fromValue(opv); | |
| 12320 | ||
| 12966 | 12321 | if (try sema.resolveDefinedValue(case_block, operand_src, operand_val)) |operand_val_val| { |
| 12967 | 12322 | if (operand_val_val.isUndef(zcu)) return pt.undefRef(capture_ty); |
| 12968 | 12323 | const union_val = ip.indexToKey(operand_val_val.toIntern()).un; |
| ... | ... | @@ -13119,7 +12474,7 @@ fn analyzeSwitchPayloadCapture( |
| 13119 | 12474 | try sema.air_instructions.append(sema.gpa, .{ |
| 13120 | 12475 | .tag = .get_union_tag, |
| 13121 | 12476 | .data = .{ .ty_op = .{ |
| 13122 | .ty = .fromIntern(union_obj.enum_tag_ty), | |
| 12477 | .ty = .fromIntern(union_obj.enum_tag_type), | |
| 13123 | 12478 | .operand = operand_val, |
| 13124 | 12479 | } }, |
| 13125 | 12480 | }); |
| ... | ... | @@ -13261,17 +12616,8 @@ fn resolveSwitchItem( |
| 13261 | 12616 | } |
| 13262 | 12617 | break :item_ref try sema.coerce(block, item_ty, uncoerced, item_src); |
| 13263 | 12618 | }; |
| 13264 | const maybe_lazy = try sema.resolveConstDefinedValue(block, item_src, item_ref, .{ .simple = .switch_item }); | |
| 13265 | ||
| 13266 | // We have to resolve lazy values here to avoid false negatives when detecting | |
| 13267 | // duplicate items and comparing items to a comptime-known switch operand. | |
| 13268 | ||
| 13269 | const val = try sema.resolveLazyValue(maybe_lazy); | |
| 13270 | const ref: Air.Inst.Ref = if (val.toIntern() == maybe_lazy.toIntern()) | |
| 13271 | item_ref | |
| 13272 | else | |
| 13273 | .fromValue(val); | |
| 13274 | return .{ .{ .ref = ref, .val = val }, end }; | |
| 12619 | const val = try sema.resolveConstDefinedValue(block, item_src, item_ref, .{ .simple = .switch_item }); | |
| 12620 | return .{ .{ .ref = item_ref, .val = val }, end }; | |
| 13275 | 12621 | } |
| 13276 | 12622 | |
| 13277 | 12623 | fn validateSwitchItemOrRange( |
| ... | ... | @@ -13488,7 +12834,7 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 13488 | 12834 | const name_src = block.builtinCallArgSrc(inst_data.src_node, 1); |
| 13489 | 12835 | const ty = try sema.resolveType(block, ty_src, extra.lhs); |
| 13490 | 12836 | const field_name = try sema.resolveConstStringIntern(block, name_src, extra.rhs, .{ .simple = .field_name }); |
| 13491 | try ty.resolveFields(pt); | |
| 12837 | try sema.ensureLayoutResolved(ty); | |
| 13492 | 12838 | const ip = &zcu.intern_pool; |
| 13493 | 12839 | |
| 13494 | 12840 | const has_field = hf: { |
| ... | ... | @@ -13510,7 +12856,8 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 13510 | 12856 | }, |
| 13511 | 12857 | .union_type => { |
| 13512 | 12858 | const union_type = ip.loadUnionType(ty.toIntern()); |
| 13513 | break :hf union_type.loadTagType(ip).nameIndex(ip, field_name) != null; | |
| 12859 | const enum_type = ip.loadEnumType(union_type.enum_tag_type); | |
| 12860 | break :hf enum_type.nameIndex(ip, field_name) != null; | |
| 13514 | 12861 | }, |
| 13515 | 12862 | .enum_type => { |
| 13516 | 12863 | break :hf ip.loadEnumType(ty.toIntern()).nameIndex(ip, field_name) != null; |
| ... | ... | @@ -13569,10 +12916,9 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 13569 | 12916 | switch (file.getMode()) { |
| 13570 | 12917 | .zig => { |
| 13571 | 12918 | try pt.ensureFileAnalyzed(file_index); |
| 13572 | const ty = zcu.fileRootType(file_index); | |
| 13573 | try sema.declareDependency(.{ .interned = ty }); | |
| 12919 | const ty: Type = .fromInterned(zcu.fileRootType(file_index)); | |
| 13574 | 12920 | try sema.addTypeReferenceEntry(operand_src, ty); |
| 13575 | return Air.internedToRef(ty); | |
| 12921 | return .fromType(ty); | |
| 13576 | 12922 | }, |
| 13577 | 12923 | .zon => { |
| 13578 | 12924 | const res_ty: InternPool.Index = b: { |
| ... | ... | @@ -13692,8 +13038,8 @@ fn zirShl( |
| 13692 | 13038 | // we already know `scalar_rhs_ty` is valid for `.shl` -- we only need to validate for `.shl_sat`. |
| 13693 | 13039 | if (air_tag == .shl_sat) _ = try sema.checkIntType(block, rhs_src, scalar_rhs_ty); |
| 13694 | 13040 | |
| 13695 | const maybe_lhs_val = try sema.resolveValueResolveLazy(lhs); | |
| 13696 | const maybe_rhs_val = try sema.resolveValueResolveLazy(rhs); | |
| 13041 | const maybe_lhs_val = try sema.resolveValue(lhs); | |
| 13042 | const maybe_rhs_val = try sema.resolveValue(rhs); | |
| 13697 | 13043 | |
| 13698 | 13044 | const runtime_src = rs: { |
| 13699 | 13045 | if (maybe_rhs_val) |rhs_val| { |
| ... | ... | @@ -13713,11 +13059,11 @@ fn zirShl( |
| 13713 | 13059 | const bits = scalar_ty.intInfo(zcu).bits; |
| 13714 | 13060 | switch (rhs_ty.zigTypeTag(zcu)) { |
| 13715 | 13061 | .int, .comptime_int => { |
| 13716 | switch (try rhs_val.orderAgainstZeroSema(pt)) { | |
| 13062 | switch (Value.order(rhs_val, .zero_comptime_int, zcu)) { | |
| 13717 | 13063 | .gt => { |
| 13718 | 13064 | if (air_tag != .shl_sat) { |
| 13719 | 13065 | var rhs_space: Value.BigIntSpace = undefined; |
| 13720 | const rhs_bigint = try rhs_val.toBigIntSema(&rhs_space, pt); | |
| 13066 | const rhs_bigint = rhs_val.toBigInt(&rhs_space, zcu); | |
| 13721 | 13067 | if (rhs_bigint.orderAgainstScalar(bits) != .lt) { |
| 13722 | 13068 | return sema.failWithTooLargeShiftAmount(block, lhs_ty, rhs_val, rhs_src, null); |
| 13723 | 13069 | } |
| ... | ... | @@ -13736,11 +13082,11 @@ fn zirShl( |
| 13736 | 13082 | .shl, .shl_exact => return sema.failWithUseOfUndef(block, rhs_src, elem_idx), |
| 13737 | 13083 | else => unreachable, |
| 13738 | 13084 | }; |
| 13739 | switch (try rhs_elem.orderAgainstZeroSema(pt)) { | |
| 13085 | switch (Value.order(rhs_elem, .zero_comptime_int, zcu)) { | |
| 13740 | 13086 | .gt => { |
| 13741 | 13087 | if (air_tag != .shl_sat) { |
| 13742 | 13088 | var rhs_elem_space: Value.BigIntSpace = undefined; |
| 13743 | const rhs_elem_bigint = try rhs_elem.toBigIntSema(&rhs_elem_space, pt); | |
| 13089 | const rhs_elem_bigint = rhs_elem.toBigInt(&rhs_elem_space, zcu); | |
| 13744 | 13090 | if (rhs_elem_bigint.orderAgainstScalar(bits) != .lt) { |
| 13745 | 13091 | return sema.failWithTooLargeShiftAmount(block, lhs_ty, rhs_elem, rhs_src, elem_idx); |
| 13746 | 13092 | } |
| ... | ... | @@ -13769,7 +13115,7 @@ fn zirShl( |
| 13769 | 13115 | .shl, .shl_exact => try sema.checkAllScalarsDefined(block, lhs_src, lhs_val), |
| 13770 | 13116 | else => unreachable, |
| 13771 | 13117 | } |
| 13772 | if (try lhs_val.compareAllWithZeroSema(.eq, pt)) return lhs; | |
| 13118 | if (lhs_val.compareAllWithZero(.eq, zcu)) return lhs; | |
| 13773 | 13119 | } |
| 13774 | 13120 | } |
| 13775 | 13121 | break :rs rhs_src; |
| ... | ... | @@ -13785,13 +13131,13 @@ fn zirShl( |
| 13785 | 13131 | const rt_rhs_scalar_ty = try pt.smallestUnsignedInt(bit_count); |
| 13786 | 13132 | if (!rhs_ty.isVector(zcu)) break :rt_rhs try pt.intValue( |
| 13787 | 13133 | rt_rhs_scalar_ty, |
| 13788 | @min(try rhs_val.getUnsignedIntSema(pt) orelse bit_count, bit_count), | |
| 13134 | @min(rhs_val.getUnsignedInt(zcu) orelse bit_count, bit_count), | |
| 13789 | 13135 | ); |
| 13790 | 13136 | const rhs_len = rhs_ty.vectorLen(zcu); |
| 13791 | 13137 | const rhs_elems = try sema.arena.alloc(InternPool.Index, rhs_len); |
| 13792 | 13138 | for (rhs_elems, 0..) |*rhs_elem, i| rhs_elem.* = (try pt.intValue( |
| 13793 | 13139 | rt_rhs_scalar_ty, |
| 13794 | @min(try (try rhs_val.elemValue(pt, i)).getUnsignedIntSema(pt) orelse bit_count, bit_count), | |
| 13140 | @min((try rhs_val.elemValue(pt, i)).getUnsignedInt(zcu) orelse bit_count, bit_count), | |
| 13795 | 13141 | )).toIntern(); |
| 13796 | 13142 | break :rt_rhs try pt.aggregateValue(try pt.vectorType(.{ |
| 13797 | 13143 | .len = rhs_len, |
| ... | ... | @@ -13875,8 +13221,8 @@ fn zirShr( |
| 13875 | 13221 | try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src); |
| 13876 | 13222 | const scalar_ty = lhs_ty.scalarType(zcu); |
| 13877 | 13223 | |
| 13878 | const maybe_lhs_val = try sema.resolveValueResolveLazy(lhs); | |
| 13879 | const maybe_rhs_val = try sema.resolveValueResolveLazy(rhs); | |
| 13224 | const maybe_lhs_val = try sema.resolveValue(lhs); | |
| 13225 | const maybe_rhs_val = try sema.resolveValue(rhs); | |
| 13880 | 13226 | |
| 13881 | 13227 | const runtime_src = rs: { |
| 13882 | 13228 | if (maybe_rhs_val) |rhs_val| { |
| ... | ... | @@ -13893,10 +13239,10 @@ fn zirShr( |
| 13893 | 13239 | const bits = scalar_ty.intInfo(zcu).bits; |
| 13894 | 13240 | switch (rhs_ty.zigTypeTag(zcu)) { |
| 13895 | 13241 | .int, .comptime_int => { |
| 13896 | switch (try rhs_val.orderAgainstZeroSema(pt)) { | |
| 13242 | switch (Value.order(rhs_val, .zero_comptime_int, zcu)) { | |
| 13897 | 13243 | .gt => { |
| 13898 | 13244 | var rhs_space: Value.BigIntSpace = undefined; |
| 13899 | const rhs_bigint = try rhs_val.toBigIntSema(&rhs_space, pt); | |
| 13245 | const rhs_bigint = rhs_val.toBigInt(&rhs_space, zcu); | |
| 13900 | 13246 | if (rhs_bigint.orderAgainstScalar(bits) != .lt) { |
| 13901 | 13247 | return sema.failWithTooLargeShiftAmount(block, lhs_ty, rhs_val, rhs_src, null); |
| 13902 | 13248 | } |
| ... | ... | @@ -13912,10 +13258,10 @@ fn zirShr( |
| 13912 | 13258 | if (rhs_elem.isUndef(zcu)) { |
| 13913 | 13259 | return sema.failWithUseOfUndef(block, rhs_src, elem_idx); |
| 13914 | 13260 | } |
| 13915 | switch (try rhs_elem.orderAgainstZeroSema(pt)) { | |
| 13261 | switch (Value.order(rhs_elem, .zero_comptime_int, zcu)) { | |
| 13916 | 13262 | .gt => { |
| 13917 | 13263 | var rhs_elem_space: Value.BigIntSpace = undefined; |
| 13918 | const rhs_elem_bigint = try rhs_elem.toBigIntSema(&rhs_elem_space, pt); | |
| 13264 | const rhs_elem_bigint = rhs_elem.toBigInt(&rhs_elem_space, zcu); | |
| 13919 | 13265 | if (rhs_elem_bigint.orderAgainstScalar(bits) != .lt) { |
| 13920 | 13266 | return sema.failWithTooLargeShiftAmount(block, lhs_ty, rhs_elem, rhs_src, elem_idx); |
| 13921 | 13267 | } |
| ... | ... | @@ -13936,7 +13282,7 @@ fn zirShr( |
| 13936 | 13282 | } |
| 13937 | 13283 | if (maybe_lhs_val) |lhs_val| { |
| 13938 | 13284 | try sema.checkAllScalarsDefined(block, lhs_src, lhs_val); |
| 13939 | if (try lhs_val.compareAllWithZeroSema(.eq, pt)) return lhs; | |
| 13285 | if (lhs_val.compareAllWithZero(.eq, zcu)) return lhs; | |
| 13940 | 13286 | } |
| 13941 | 13287 | } |
| 13942 | 13288 | break :rs rhs_src; |
| ... | ... | @@ -14011,8 +13357,8 @@ fn zirBitwise( |
| 14011 | 13357 | const runtime_src = runtime: { |
| 14012 | 13358 | // TODO: ask the linker what kind of relocations are available, and |
| 14013 | 13359 | // in some cases emit a Value that means "this decl's address AND'd with this operand". |
| 14014 | if (try sema.resolveValueResolveLazy(casted_lhs)) |lhs_val| { | |
| 14015 | if (try sema.resolveValueResolveLazy(casted_rhs)) |rhs_val| { | |
| 13360 | if (try sema.resolveValue(casted_lhs)) |lhs_val| { | |
| 13361 | if (try sema.resolveValue(casted_rhs)) |rhs_val| { | |
| 14016 | 13362 | const result_val = switch (air_tag) { |
| 14017 | 13363 | // zig fmt: off |
| 14018 | 13364 | .bit_and => try arith.bitwiseBin(sema, resolved_type, lhs_val, rhs_val, .@"and"), |
| ... | ... | @@ -14106,13 +13452,13 @@ fn analyzeTupleCat( |
| 14106 | 13452 | var i: u32 = 0; |
| 14107 | 13453 | while (i < lhs_len) : (i += 1) { |
| 14108 | 13454 | types[i] = lhs_ty.fieldType(i, zcu).toIntern(); |
| 14109 | const default_val = lhs_ty.structFieldDefaultValue(i, zcu); | |
| 14110 | values[i] = default_val.toIntern(); | |
| 14111 | 13455 | const operand_src = block.src(.{ .array_cat_lhs = .{ |
| 14112 | 13456 | .array_cat_offset = src_node, |
| 14113 | 13457 | .elem_index = i, |
| 14114 | 13458 | } }); |
| 14115 | if (default_val.toIntern() == .unreachable_value) { | |
| 13459 | if (lhs_ty.structFieldDefaultValue(i, zcu)) |default_val| { | |
| 13460 | values[i] = default_val.toIntern(); | |
| 13461 | } else { | |
| 14116 | 13462 | runtime_src = operand_src; |
| 14117 | 13463 | values[i] = .none; |
| 14118 | 13464 | } |
| ... | ... | @@ -14120,13 +13466,13 @@ fn analyzeTupleCat( |
| 14120 | 13466 | i = 0; |
| 14121 | 13467 | while (i < rhs_len) : (i += 1) { |
| 14122 | 13468 | types[i + lhs_len] = rhs_ty.fieldType(i, zcu).toIntern(); |
| 14123 | const default_val = rhs_ty.structFieldDefaultValue(i, zcu); | |
| 14124 | values[i + lhs_len] = default_val.toIntern(); | |
| 14125 | 13469 | const operand_src = block.src(.{ .array_cat_rhs = .{ |
| 14126 | 13470 | .array_cat_offset = src_node, |
| 14127 | 13471 | .elem_index = i, |
| 14128 | 13472 | } }); |
| 14129 | if (default_val.toIntern() == .unreachable_value) { | |
| 13473 | if (rhs_ty.structFieldDefaultValue(i, zcu)) |default_val| { | |
| 13474 | values[i + lhs_len] = default_val.toIntern(); | |
| 13475 | } else { | |
| 14130 | 13476 | runtime_src = operand_src; |
| 14131 | 13477 | values[i + lhs_len] = .none; |
| 14132 | 13478 | } |
| ... | ... | @@ -14290,8 +13636,8 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 14290 | 13636 | var elem_i: u32 = 0; |
| 14291 | 13637 | while (elem_i < lhs_len) : (elem_i += 1) { |
| 14292 | 13638 | const lhs_elem_i = elem_i; |
| 14293 | const elem_default_val = if (lhs_is_tuple) lhs_ty.structFieldDefaultValue(lhs_elem_i, zcu) else Value.@"unreachable"; | |
| 14294 | const elem_val = if (elem_default_val.toIntern() == .unreachable_value) try lhs_sub_val.elemValue(pt, lhs_elem_i) else elem_default_val; | |
| 13639 | const elem_default_val: ?Value = if (lhs_is_tuple) lhs_ty.structFieldDefaultValue(lhs_elem_i, zcu) else null; | |
| 13640 | const elem_val = elem_default_val orelse try lhs_sub_val.elemValue(pt, lhs_elem_i); | |
| 14295 | 13641 | const elem_val_inst = Air.internedToRef(elem_val.toIntern()); |
| 14296 | 13642 | const operand_src = block.src(.{ .array_cat_lhs = .{ |
| 14297 | 13643 | .array_cat_offset = inst_data.src_node, |
| ... | ... | @@ -14303,8 +13649,8 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 14303 | 13649 | } |
| 14304 | 13650 | while (elem_i < result_len) : (elem_i += 1) { |
| 14305 | 13651 | const rhs_elem_i = elem_i - lhs_len; |
| 14306 | const elem_default_val = if (rhs_is_tuple) rhs_ty.structFieldDefaultValue(rhs_elem_i, zcu) else Value.@"unreachable"; | |
| 14307 | const elem_val = if (elem_default_val.toIntern() == .unreachable_value) try rhs_sub_val.elemValue(pt, rhs_elem_i) else elem_default_val; | |
| 13652 | const elem_default_val: ?Value = if (rhs_is_tuple) rhs_ty.structFieldDefaultValue(rhs_elem_i, zcu) else null; | |
| 13653 | const elem_val = elem_default_val orelse try rhs_sub_val.elemValue(pt, rhs_elem_i); | |
| 14308 | 13654 | const elem_val_inst = Air.internedToRef(elem_val.toIntern()); |
| 14309 | 13655 | const operand_src = block.src(.{ .array_cat_rhs = .{ |
| 14310 | 13656 | .array_cat_offset = inst_data.src_node, |
| ... | ... | @@ -14324,18 +13670,18 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 14324 | 13670 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| 14325 | 13671 | |
| 14326 | 13672 | if (ptr_addrspace) |ptr_as| { |
| 14327 | const constant_alloc_ty = try pt.ptrTypeSema(.{ | |
| 13673 | const constant_alloc_ty = try pt.ptrType(.{ | |
| 14328 | 13674 | .child = result_ty.toIntern(), |
| 14329 | 13675 | .flags = .{ |
| 14330 | 13676 | .address_space = ptr_as, |
| 14331 | 13677 | .is_const = true, |
| 14332 | 13678 | }, |
| 14333 | 13679 | }); |
| 14334 | const alloc_ty = try pt.ptrTypeSema(.{ | |
| 13680 | const alloc_ty = try pt.ptrType(.{ | |
| 14335 | 13681 | .child = result_ty.toIntern(), |
| 14336 | 13682 | .flags = .{ .address_space = ptr_as }, |
| 14337 | 13683 | }); |
| 14338 | const elem_ptr_ty = try pt.ptrTypeSema(.{ | |
| 13684 | const elem_ptr_ty = try pt.ptrType(.{ | |
| 14339 | 13685 | .child = resolved_elem_ty.toIntern(), |
| 14340 | 13686 | .flags = .{ .address_space = ptr_as }, |
| 14341 | 13687 | }); |
| ... | ... | @@ -14347,7 +13693,7 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 14347 | 13693 | if (lhs_ty.zigTypeTag(zcu) == .pointer and |
| 14348 | 13694 | rhs_ty.zigTypeTag(zcu) == .pointer) |
| 14349 | 13695 | { |
| 14350 | const slice_ty = try pt.ptrTypeSema(.{ | |
| 13696 | const slice_ty = try pt.ptrType(.{ | |
| 14351 | 13697 | .child = resolved_elem_ty.toIntern(), |
| 14352 | 13698 | .flags = .{ |
| 14353 | 13699 | .size = .slice, |
| ... | ... | @@ -14486,7 +13832,7 @@ fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Ins |
| 14486 | 13832 | .none => null, |
| 14487 | 13833 | else => Value.fromInterned(ptr_info.sentinel), |
| 14488 | 13834 | }, |
| 14489 | .len = try val.sliceLen(pt), | |
| 13835 | .len = val.sliceLen(zcu), | |
| 14490 | 13836 | }; |
| 14491 | 13837 | }, |
| 14492 | 13838 | .one => { |
| ... | ... | @@ -14500,8 +13846,20 @@ fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Ins |
| 14500 | 13846 | .@"struct" => { |
| 14501 | 13847 | if (operand_ty.isTuple(zcu) and peer_ty.isIndexable(zcu)) { |
| 14502 | 13848 | assert(!peer_ty.isTuple(zcu)); |
| 13849 | const peer_elem_ty = switch (peer_ty.zigTypeTag(zcu)) { | |
| 13850 | .pointer => switch (peer_ty.ptrSize(zcu)) { | |
| 13851 | .one => switch (peer_ty.childType(zcu).zigTypeTag(zcu)) { | |
| 13852 | .array, .vector => peer_ty.childType(zcu).childType(zcu), | |
| 13853 | .@"struct" => return null, | |
| 13854 | else => unreachable, | |
| 13855 | }, | |
| 13856 | .many, .c, .slice => peer_ty.childType(zcu), | |
| 13857 | }, | |
| 13858 | .vector, .array => peer_ty.childType(zcu), | |
| 13859 | else => unreachable, | |
| 13860 | }; | |
| 14503 | 13861 | return .{ |
| 14504 | .elem_type = peer_ty.elemType2(zcu), | |
| 13862 | .elem_type = peer_elem_ty, | |
| 14505 | 13863 | .sentinel = null, |
| 14506 | 13864 | .len = operand_ty.arrayLen(zcu), |
| 14507 | 13865 | }; |
| ... | ... | @@ -14543,12 +13901,13 @@ fn analyzeTupleMul( |
| 14543 | 13901 | var runtime_src: ?LazySrcLoc = null; |
| 14544 | 13902 | for (0..tuple_len) |i| { |
| 14545 | 13903 | types[i] = operand_ty.fieldType(i, zcu).toIntern(); |
| 14546 | values[i] = operand_ty.structFieldDefaultValue(i, zcu).toIntern(); | |
| 14547 | 13904 | const operand_src = block.src(.{ .array_cat_lhs = .{ |
| 14548 | 13905 | .array_cat_offset = src_node, |
| 14549 | 13906 | .elem_index = @intCast(i), |
| 14550 | 13907 | } }); |
| 14551 | if (values[i] == .unreachable_value) { | |
| 13908 | if (operand_ty.structFieldDefaultValue(i, zcu)) |default_val| { | |
| 13909 | values[i] = default_val.toIntern(); | |
| 13910 | } else { | |
| 14552 | 13911 | runtime_src = operand_src; |
| 14553 | 13912 | values[i] = .none; // TODO don't treat unreachable_value as special |
| 14554 | 13913 | } |
| ... | ... | @@ -14714,7 +14073,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 14714 | 14073 | } |
| 14715 | 14074 | |
| 14716 | 14075 | if (ptr_addrspace) |ptr_as| { |
| 14717 | const alloc_ty = try pt.ptrTypeSema(.{ | |
| 14076 | const alloc_ty = try pt.ptrType(.{ | |
| 14718 | 14077 | .child = result_ty.toIntern(), |
| 14719 | 14078 | .flags = .{ |
| 14720 | 14079 | .address_space = ptr_as, |
| ... | ... | @@ -14722,7 +14081,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 14722 | 14081 | }, |
| 14723 | 14082 | }); |
| 14724 | 14083 | const alloc = try block.addTy(.alloc, alloc_ty); |
| 14725 | const elem_ptr_ty = try pt.ptrTypeSema(.{ | |
| 14084 | const elem_ptr_ty = try pt.ptrType(.{ | |
| 14726 | 14085 | .child = lhs_info.elem_type.toIntern(), |
| 14727 | 14086 | .flags = .{ .address_space = ptr_as }, |
| 14728 | 14087 | }); |
| ... | ... | @@ -14859,8 +14218,8 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins |
| 14859 | 14218 | |
| 14860 | 14219 | try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div); |
| 14861 | 14220 | |
| 14862 | const maybe_lhs_val = try sema.resolveValueResolveLazy(casted_lhs); | |
| 14863 | const maybe_rhs_val = try sema.resolveValueResolveLazy(casted_rhs); | |
| 14221 | const maybe_lhs_val = try sema.resolveValue(casted_lhs); | |
| 14222 | const maybe_rhs_val = try sema.resolveValue(casted_rhs); | |
| 14864 | 14223 | |
| 14865 | 14224 | if ((lhs_ty.zigTypeTag(zcu) == .comptime_float and rhs_ty.zigTypeTag(zcu) == .comptime_int) or |
| 14866 | 14225 | (lhs_ty.zigTypeTag(zcu) == .comptime_int and rhs_ty.zigTypeTag(zcu) == .comptime_float)) |
| ... | ... | @@ -14968,8 +14327,8 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 14968 | 14327 | |
| 14969 | 14328 | try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div_exact); |
| 14970 | 14329 | |
| 14971 | const maybe_lhs_val = try sema.resolveValueResolveLazy(casted_lhs); | |
| 14972 | const maybe_rhs_val = try sema.resolveValueResolveLazy(casted_rhs); | |
| 14330 | const maybe_lhs_val = try sema.resolveValue(casted_lhs); | |
| 14331 | const maybe_rhs_val = try sema.resolveValue(casted_rhs); | |
| 14973 | 14332 | |
| 14974 | 14333 | // Because `@divExact` can trigger Illegal Behavior, undefined operands trigger Illegal Behavior. |
| 14975 | 14334 | |
| ... | ... | @@ -15064,8 +14423,8 @@ fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 15064 | 14423 | |
| 15065 | 14424 | try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div_floor); |
| 15066 | 14425 | |
| 15067 | const maybe_lhs_val = try sema.resolveValueResolveLazy(casted_lhs); | |
| 15068 | const maybe_rhs_val = try sema.resolveValueResolveLazy(casted_rhs); | |
| 14426 | const maybe_lhs_val = try sema.resolveValue(casted_lhs); | |
| 14427 | const maybe_rhs_val = try sema.resolveValue(casted_rhs); | |
| 15069 | 14428 | |
| 15070 | 14429 | const allow_div_zero = !is_int and |
| 15071 | 14430 | resolved_type.toIntern() != .comptime_float_type and |
| ... | ... | @@ -15129,8 +14488,8 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 15129 | 14488 | |
| 15130 | 14489 | try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div_trunc); |
| 15131 | 14490 | |
| 15132 | const maybe_lhs_val = try sema.resolveValueResolveLazy(casted_lhs); | |
| 15133 | const maybe_rhs_val = try sema.resolveValueResolveLazy(casted_rhs); | |
| 14491 | const maybe_lhs_val = try sema.resolveValue(casted_lhs); | |
| 14492 | const maybe_rhs_val = try sema.resolveValue(casted_rhs); | |
| 15134 | 14493 | |
| 15135 | 14494 | const allow_div_zero = !is_int and |
| 15136 | 14495 | resolved_type.toIntern() != .comptime_float_type and |
| ... | ... | @@ -15341,8 +14700,8 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 15341 | 14700 | |
| 15342 | 14701 | try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .mod_rem); |
| 15343 | 14702 | |
| 15344 | const maybe_lhs_val = try sema.resolveValueResolveLazy(casted_lhs); | |
| 15345 | const maybe_rhs_val = try sema.resolveValueResolveLazy(casted_rhs); | |
| 14703 | const maybe_lhs_val = try sema.resolveValue(casted_lhs); | |
| 14704 | const maybe_rhs_val = try sema.resolveValue(casted_rhs); | |
| 15346 | 14705 | |
| 15347 | 14706 | const lhs_maybe_negative = a: { |
| 15348 | 14707 | if (lhs_scalar_ty.isUnsignedInt(zcu)) break :a false; |
| ... | ... | @@ -15440,8 +14799,8 @@ fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins |
| 15440 | 14799 | |
| 15441 | 14800 | try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .mod); |
| 15442 | 14801 | |
| 15443 | const maybe_lhs_val = try sema.resolveValueResolveLazy(casted_lhs); | |
| 15444 | const maybe_rhs_val = try sema.resolveValueResolveLazy(casted_rhs); | |
| 14802 | const maybe_lhs_val = try sema.resolveValue(casted_lhs); | |
| 14803 | const maybe_rhs_val = try sema.resolveValue(casted_rhs); | |
| 15445 | 14804 | |
| 15446 | 14805 | const allow_div_zero = !is_int and |
| 15447 | 14806 | resolved_type.toIntern() != .comptime_float_type and |
| ... | ... | @@ -15504,8 +14863,8 @@ fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins |
| 15504 | 14863 | |
| 15505 | 14864 | try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .rem); |
| 15506 | 14865 | |
| 15507 | const maybe_lhs_val = try sema.resolveValueResolveLazy(casted_lhs); | |
| 15508 | const maybe_rhs_val = try sema.resolveValueResolveLazy(casted_rhs); | |
| 14866 | const maybe_lhs_val = try sema.resolveValue(casted_lhs); | |
| 14867 | const maybe_rhs_val = try sema.resolveValue(casted_rhs); | |
| 15509 | 14868 | |
| 15510 | 14869 | const allow_div_zero = !is_int and |
| 15511 | 14870 | resolved_type.toIntern() != .comptime_float_type and |
| ... | ... | @@ -15601,12 +14960,12 @@ fn zirOverflowArithmetic( |
| 15601 | 14960 | // to the result, even if it is undefined.. |
| 15602 | 14961 | // Otherwise, if either of the argument is undefined, undefined is returned. |
| 15603 | 14962 | if (maybe_lhs_val) |lhs_val| { |
| 15604 | if (!lhs_val.isUndef(zcu) and (try lhs_val.compareAllWithZeroSema(.eq, pt))) { | |
| 14963 | if (!lhs_val.isUndef(zcu) and lhs_val.compareAllWithZero(.eq, zcu)) { | |
| 15605 | 14964 | break :result .{ .overflow_bit = try sema.splat(overflow_ty, .zero_u1), .inst = rhs }; |
| 15606 | 14965 | } |
| 15607 | 14966 | } |
| 15608 | 14967 | if (maybe_rhs_val) |rhs_val| { |
| 15609 | if (!rhs_val.isUndef(zcu) and (try rhs_val.compareAllWithZeroSema(.eq, pt))) { | |
| 14968 | if (!rhs_val.isUndef(zcu) and rhs_val.compareAllWithZero(.eq, zcu)) { | |
| 15610 | 14969 | break :result .{ .overflow_bit = try sema.splat(overflow_ty, .zero_u1), .inst = lhs }; |
| 15611 | 14970 | } |
| 15612 | 14971 | } |
| ... | ... | @@ -15627,7 +14986,7 @@ fn zirOverflowArithmetic( |
| 15627 | 14986 | if (maybe_rhs_val) |rhs_val| { |
| 15628 | 14987 | if (rhs_val.isUndef(zcu)) { |
| 15629 | 14988 | break :result .{ .overflow_bit = .undef, .wrapped = .undef }; |
| 15630 | } else if (try rhs_val.compareAllWithZeroSema(.eq, pt)) { | |
| 14989 | } else if (rhs_val.compareAllWithZero(.eq, zcu)) { | |
| 15631 | 14990 | break :result .{ .overflow_bit = try sema.splat(overflow_ty, .zero_u1), .inst = lhs }; |
| 15632 | 14991 | } else if (maybe_lhs_val) |lhs_val| { |
| 15633 | 14992 | if (lhs_val.isUndef(zcu)) { |
| ... | ... | @@ -15642,12 +15001,12 @@ fn zirOverflowArithmetic( |
| 15642 | 15001 | .mul_with_overflow => { |
| 15643 | 15002 | // If either of the arguments is zero, the result is zero and no overflow occured. |
| 15644 | 15003 | if (maybe_lhs_val) |lhs_val| { |
| 15645 | if (!lhs_val.isUndef(zcu) and try lhs_val.compareAllWithZeroSema(.eq, pt)) { | |
| 15004 | if (!lhs_val.isUndef(zcu) and lhs_val.compareAllWithZero(.eq, zcu)) { | |
| 15646 | 15005 | break :result .{ .overflow_bit = try sema.splat(overflow_ty, .zero_u1), .inst = lhs }; |
| 15647 | 15006 | } |
| 15648 | 15007 | } |
| 15649 | 15008 | if (maybe_rhs_val) |rhs_val| { |
| 15650 | if (!rhs_val.isUndef(zcu) and try rhs_val.compareAllWithZeroSema(.eq, pt)) { | |
| 15009 | if (!rhs_val.isUndef(zcu) and rhs_val.compareAllWithZero(.eq, zcu)) { | |
| 15651 | 15010 | break :result .{ .overflow_bit = try sema.splat(overflow_ty, .zero_u1), .inst = rhs }; |
| 15652 | 15011 | } |
| 15653 | 15012 | } |
| ... | ... | @@ -15694,10 +15053,10 @@ fn zirOverflowArithmetic( |
| 15694 | 15053 | const bits = scalar_ty.intInfo(zcu).bits; |
| 15695 | 15054 | switch (rhs_ty.zigTypeTag(zcu)) { |
| 15696 | 15055 | .int, .comptime_int => { |
| 15697 | switch (try rhs_val.orderAgainstZeroSema(pt)) { | |
| 15056 | switch (Value.order(rhs_val, .zero_comptime_int, zcu)) { | |
| 15698 | 15057 | .gt => { |
| 15699 | 15058 | var rhs_space: Value.BigIntSpace = undefined; |
| 15700 | const rhs_bigint = try rhs_val.toBigIntSema(&rhs_space, pt); | |
| 15059 | const rhs_bigint = rhs_val.toBigInt(&rhs_space, zcu); | |
| 15701 | 15060 | if (rhs_bigint.orderAgainstScalar(bits) != .lt) { |
| 15702 | 15061 | return sema.failWithTooLargeShiftAmount(block, lhs_ty, rhs_val, rhs_src, null); |
| 15703 | 15062 | } |
| ... | ... | @@ -15711,10 +15070,10 @@ fn zirOverflowArithmetic( |
| 15711 | 15070 | for (0..rhs_ty.vectorLen(zcu)) |elem_idx| { |
| 15712 | 15071 | const rhs_elem = try rhs_val.elemValue(pt, elem_idx); |
| 15713 | 15072 | if (rhs_elem.isUndef(zcu)) return sema.failWithUseOfUndef(block, rhs_src, elem_idx); |
| 15714 | switch (try rhs_elem.orderAgainstZeroSema(pt)) { | |
| 15073 | switch (Value.order(rhs_elem, .zero_comptime_int, zcu)) { | |
| 15715 | 15074 | .gt => { |
| 15716 | 15075 | var rhs_elem_space: Value.BigIntSpace = undefined; |
| 15717 | const rhs_elem_bigint = try rhs_elem.toBigIntSema(&rhs_elem_space, pt); | |
| 15076 | const rhs_elem_bigint = rhs_elem.toBigInt(&rhs_elem_space, zcu); | |
| 15718 | 15077 | if (rhs_elem_bigint.orderAgainstScalar(bits) != .lt) { |
| 15719 | 15078 | return sema.failWithTooLargeShiftAmount(block, lhs_ty, rhs_elem, rhs_src, elem_idx); |
| 15720 | 15079 | } |
| ... | ... | @@ -15728,7 +15087,7 @@ fn zirOverflowArithmetic( |
| 15728 | 15087 | }, |
| 15729 | 15088 | else => unreachable, |
| 15730 | 15089 | } |
| 15731 | if (try rhs_val.compareAllWithZeroSema(.eq, pt)) { | |
| 15090 | if (rhs_val.compareAllWithZero(.eq, zcu)) { | |
| 15732 | 15091 | break :result .{ .overflow_bit = try sema.splat(overflow_ty, .zero_u1), .inst = lhs }; |
| 15733 | 15092 | } |
| 15734 | 15093 | } else { |
| ... | ... | @@ -15737,7 +15096,7 @@ fn zirOverflowArithmetic( |
| 15737 | 15096 | } |
| 15738 | 15097 | if (maybe_lhs_val) |lhs_val| { |
| 15739 | 15098 | try sema.checkAllScalarsDefined(block, lhs_src, lhs_val); |
| 15740 | if (try lhs_val.compareAllWithZeroSema(.eq, pt)) { | |
| 15099 | if (lhs_val.compareAllWithZero(.eq, zcu)) { | |
| 15741 | 15100 | break :result .{ .overflow_bit = try sema.splat(overflow_ty, .zero_u1), .inst = lhs }; |
| 15742 | 15101 | } |
| 15743 | 15102 | } |
| ... | ... | @@ -15817,16 +15176,16 @@ fn analyzeArithmetic( |
| 15817 | 15176 | if (zir_tag != .sub) { |
| 15818 | 15177 | return sema.failWithInvalidPtrArithmetic(block, src, "pointer-pointer", "subtraction"); |
| 15819 | 15178 | } |
| 15820 | if (!lhs_ty.elemType2(zcu).eql(rhs_ty.elemType2(zcu), zcu)) { | |
| 15179 | if (!lhs_ty.childType(zcu).eql(rhs_ty.childType(zcu), zcu)) { | |
| 15821 | 15180 | return sema.fail(block, src, "incompatible pointer arithmetic operands '{f}' and '{f}'", .{ |
| 15822 | 15181 | lhs_ty.fmt(pt), rhs_ty.fmt(pt), |
| 15823 | 15182 | }); |
| 15824 | 15183 | } |
| 15825 | 15184 | |
| 15826 | const elem_size = lhs_ty.elemType2(zcu).abiSize(zcu); | |
| 15185 | const elem_size = lhs_ty.childType(zcu).abiSize(zcu); | |
| 15827 | 15186 | if (elem_size == 0) { |
| 15828 | return sema.fail(block, src, "pointer arithmetic requires element type '{f}' to have runtime bits", .{ | |
| 15829 | lhs_ty.elemType2(zcu).fmt(pt), | |
| 15187 | return sema.fail(block, src, "pointer subtraction requires element type '{f}' to have runtime bits", .{ | |
| 15188 | lhs_ty.childType(zcu).fmt(pt), | |
| 15830 | 15189 | }); |
| 15831 | 15190 | } |
| 15832 | 15191 | |
| ... | ... | @@ -15875,11 +15234,7 @@ fn analyzeArithmetic( |
| 15875 | 15234 | else => return sema.failWithInvalidPtrArithmetic(block, src, "pointer-integer", "addition and subtraction"), |
| 15876 | 15235 | }; |
| 15877 | 15236 | |
| 15878 | if (!try lhs_ty.elemType2(zcu).hasRuntimeBitsSema(pt)) { | |
| 15879 | return sema.fail(block, src, "pointer arithmetic requires element type '{f}' to have runtime bits", .{ | |
| 15880 | lhs_ty.elemType2(zcu).fmt(pt), | |
| 15881 | }); | |
| 15882 | } | |
| 15237 | try sema.ensureLayoutResolved(lhs_ty.childType(zcu)); | |
| 15883 | 15238 | return sema.analyzePtrArithmetic(block, src, lhs, rhs, air_tag, lhs_src, rhs_src); |
| 15884 | 15239 | }, |
| 15885 | 15240 | } |
| ... | ... | @@ -15915,8 +15270,8 @@ fn analyzeArithmetic( |
| 15915 | 15270 | else => unreachable, |
| 15916 | 15271 | }; |
| 15917 | 15272 | |
| 15918 | const maybe_lhs_val = try sema.resolveValueResolveLazy(casted_lhs); | |
| 15919 | const maybe_rhs_val = try sema.resolveValueResolveLazy(casted_rhs); | |
| 15273 | const maybe_lhs_val = try sema.resolveValue(casted_lhs); | |
| 15274 | const maybe_rhs_val = try sema.resolveValue(casted_rhs); | |
| 15920 | 15275 | |
| 15921 | 15276 | if (maybe_lhs_val) |lhs_val| { |
| 15922 | 15277 | if (maybe_rhs_val) |rhs_val| { |
| ... | ... | @@ -15972,6 +15327,7 @@ fn analyzeArithmetic( |
| 15972 | 15327 | return block.addBinOp(air_tag, casted_lhs, casted_rhs); |
| 15973 | 15328 | } |
| 15974 | 15329 | |
| 15330 | /// Asserts that the layout of the pointer child type is already resolved. | |
| 15975 | 15331 | fn analyzePtrArithmetic( |
| 15976 | 15332 | sema: *Sema, |
| 15977 | 15333 | block: *Block, |
| ... | ... | @@ -15993,7 +15349,10 @@ fn analyzePtrArithmetic( |
| 15993 | 15349 | const ptr_info = ptr_ty.ptrInfo(zcu); |
| 15994 | 15350 | assert(ptr_info.flags.size == .many or ptr_info.flags.size == .c); |
| 15995 | 15351 | |
| 15996 | if ((try sema.typeHasOnePossibleValue(.fromInterned(ptr_info.child))) != null) { | |
| 15352 | const elem_ty: Type = .fromInterned(ptr_info.child); | |
| 15353 | elem_ty.assertHasLayout(zcu); | |
| 15354 | ||
| 15355 | if (elem_ty.abiSize(zcu) == 0) { | |
| 15997 | 15356 | // Offset will be multiplied by zero, so result is the same as the base pointer. |
| 15998 | 15357 | return ptr; |
| 15999 | 15358 | } |
| ... | ... | @@ -16007,9 +15366,9 @@ fn analyzePtrArithmetic( |
| 16007 | 15366 | } |
| 16008 | 15367 | // If the addend is not a comptime-known value we can still count on |
| 16009 | 15368 | // it being a multiple of the type size. |
| 16010 | const elem_size = try Type.fromInterned(ptr_info.child).abiSizeSema(pt); | |
| 15369 | const elem_size = elem_ty.abiSize(zcu); | |
| 16011 | 15370 | const addend = if (opt_off_val) |off_val| a: { |
| 16012 | const off_int = try sema.usizeCast(block, offset_src, try off_val.toUnsignedIntSema(pt)); | |
| 15371 | const off_int = try sema.usizeCast(block, offset_src, off_val.toUnsignedInt(zcu)); | |
| 16013 | 15372 | break :a elem_size * off_int; |
| 16014 | 15373 | } else elem_size; |
| 16015 | 15374 | |
| ... | ... | @@ -16022,7 +15381,7 @@ fn analyzePtrArithmetic( |
| 16022 | 15381 | )); |
| 16023 | 15382 | assert(new_align != .none); |
| 16024 | 15383 | |
| 16025 | break :t try pt.ptrTypeSema(.{ | |
| 15384 | break :t try pt.ptrType(.{ | |
| 16026 | 15385 | .child = ptr_info.child, |
| 16027 | 15386 | .sentinel = ptr_info.sentinel, |
| 16028 | 15387 | .flags = .{ |
| ... | ... | @@ -16041,10 +15400,10 @@ fn analyzePtrArithmetic( |
| 16041 | 15400 | if (opt_off_val) |offset_val| { |
| 16042 | 15401 | if (ptr_val.isUndef(zcu)) return pt.undefRef(new_ptr_ty); |
| 16043 | 15402 | |
| 16044 | const offset_int = try sema.usizeCast(block, offset_src, try offset_val.toUnsignedIntSema(pt)); | |
| 15403 | const offset_int = try sema.usizeCast(block, offset_src, offset_val.toUnsignedInt(zcu)); | |
| 16045 | 15404 | if (offset_int == 0) return ptr; |
| 16046 | 15405 | if (air_tag == .ptr_sub) { |
| 16047 | const elem_size = try Type.fromInterned(ptr_info.child).abiSizeSema(pt); | |
| 15406 | const elem_size = elem_ty.abiSize(zcu); | |
| 16048 | 15407 | const new_ptr_val = try sema.ptrSubtract(block, op_src, ptr_val, offset_int * elem_size, new_ptr_ty); |
| 16049 | 15408 | return Air.internedToRef(new_ptr_val.toIntern()); |
| 16050 | 15409 | } else { |
| ... | ... | @@ -16248,6 +15607,7 @@ fn zirAsm( |
| 16248 | 15607 | buffer[input.c.len + 1 + input.n.len] = 0; |
| 16249 | 15608 | sema.air_extra.items.len += (input.c.len + input.n.len + (2 + 3)) / 4; |
| 16250 | 15609 | } |
| 15610 | if (try expr_ty.toType().onePossibleValue(pt)) |opv| return .fromValue(opv); | |
| 16251 | 15611 | return asm_air; |
| 16252 | 15612 | } |
| 16253 | 15613 | |
| ... | ... | @@ -16343,7 +15703,6 @@ fn analyzeCmpUnionTag( |
| 16343 | 15703 | const pt = sema.pt; |
| 16344 | 15704 | const zcu = pt.zcu; |
| 16345 | 15705 | const union_ty = sema.typeOf(un); |
| 16346 | try union_ty.resolveFields(pt); | |
| 16347 | 15706 | const union_tag_ty = union_ty.unionTagType(zcu) orelse { |
| 16348 | 15707 | const msg = msg: { |
| 16349 | 15708 | const msg = try sema.errMsg(un_src, "comparison of union and enum literal is only valid for tagged union types", .{}); |
| ... | ... | @@ -16534,10 +15893,11 @@ fn runtimeBoolCmp( |
| 16534 | 15893 | |
| 16535 | 15894 | fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 16536 | 15895 | const pt = sema.pt; |
| 15896 | const zcu = pt.zcu; | |
| 16537 | 15897 | const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; |
| 16538 | 15898 | const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0); |
| 16539 | 15899 | const ty = try sema.resolveType(block, operand_src, inst_data.operand); |
| 16540 | switch (ty.zigTypeTag(pt.zcu)) { | |
| 15900 | switch (ty.zigTypeTag(zcu)) { | |
| 16541 | 15901 | .@"fn", |
| 16542 | 15902 | .noreturn, |
| 16543 | 15903 | .undefined, |
| ... | ... | @@ -16568,8 +15928,8 @@ fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 16568 | 15928 | .@"anyframe", |
| 16569 | 15929 | => {}, |
| 16570 | 15930 | } |
| 16571 | const val = try ty.abiSizeLazy(pt); | |
| 16572 | return Air.internedToRef(val.toIntern()); | |
| 15931 | try sema.ensureLayoutResolved(ty); | |
| 15932 | return .fromValue(try pt.intValue(.comptime_int, ty.abiSize(zcu))); | |
| 16573 | 15933 | } |
| 16574 | 15934 | |
| 16575 | 15935 | fn zirBitSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -16609,8 +15969,8 @@ fn zirBitSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 16609 | 15969 | .@"anyframe", |
| 16610 | 15970 | => {}, |
| 16611 | 15971 | } |
| 16612 | const bit_size = try operand_ty.bitSizeSema(pt); | |
| 16613 | return pt.intRef(.comptime_int, bit_size); | |
| 15972 | try sema.ensureLayoutResolved(operand_ty); | |
| 15973 | return .fromValue(try pt.intValue(.comptime_int, operand_ty.bitSize(zcu))); | |
| 16614 | 15974 | } |
| 16615 | 15975 | |
| 16616 | 15976 | fn zirThis( |
| ... | ... | @@ -16619,34 +15979,16 @@ fn zirThis( |
| 16619 | 15979 | extended: Zir.Inst.Extended.InstData, |
| 16620 | 15980 | ) CompileError!Air.Inst.Ref { |
| 16621 | 15981 | _ = extended; |
| 16622 | const pt = sema.pt; | |
| 16623 | const zcu = pt.zcu; | |
| 16624 | const namespace = pt.zcu.namespacePtr(block.namespace); | |
| 15982 | const zcu = sema.pt.zcu; | |
| 15983 | const namespace = zcu.namespacePtr(block.namespace); | |
| 16625 | 15984 | |
| 16626 | switch (pt.zcu.intern_pool.indexToKey(namespace.owner_type)) { | |
| 16627 | .opaque_type => { | |
| 16628 | // Opaque types are never outdated since they don't undergo type resolution, so nothing to do! | |
| 16629 | return Air.internedToRef(namespace.owner_type); | |
| 16630 | }, | |
| 16631 | .struct_type, .union_type => { | |
| 16632 | const new_ty = try pt.ensureTypeUpToDate(namespace.owner_type); | |
| 16633 | try sema.declareDependency(.{ .interned = new_ty }); | |
| 16634 | return Air.internedToRef(new_ty); | |
| 16635 | }, | |
| 16636 | .enum_type => { | |
| 16637 | const new_ty = try pt.ensureTypeUpToDate(namespace.owner_type); | |
| 16638 | try sema.declareDependency(.{ .interned = new_ty }); | |
| 16639 | // Since this is an enum, it has to be resolved immediately. | |
| 16640 | // `ensureTypeUpToDate` has resolved the new type if necessary. | |
| 16641 | // We just need to check for resolution failures. | |
| 16642 | const ty_unit: AnalUnit = .wrap(.{ .type = new_ty }); | |
| 16643 | if (zcu.failed_analysis.contains(ty_unit) or zcu.transitive_failed_analysis.contains(ty_unit)) { | |
| 16644 | return error.AnalysisFail; | |
| 16645 | } | |
| 16646 | return Air.internedToRef(new_ty); | |
| 16647 | }, | |
| 15985 | switch (zcu.intern_pool.indexToKey(namespace.owner_type)) { | |
| 15986 | .opaque_type, .struct_type, .union_type => {}, | |
| 15987 | // Enum inits are resolved eagerly. TODO MLUGG: honestly i don't think they SHOULD be lol | |
| 15988 | .enum_type => try sema.ensureFieldInitsResolved(.fromInterned(namespace.owner_type)), | |
| 16648 | 15989 | else => unreachable, |
| 16649 | 15990 | } |
| 15991 | return .fromIntern(namespace.owner_type); | |
| 16650 | 15992 | } |
| 16651 | 15993 | |
| 16652 | 15994 | fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -16739,7 +16081,7 @@ fn zirRetAddr( |
| 16739 | 16081 | _ = sema; |
| 16740 | 16082 | _ = extended; |
| 16741 | 16083 | if (block.isComptime()) { |
| 16742 | // TODO: we could give a meaningful lazy value here. #14938 | |
| 16084 | // TODO: we could give a meaningful value here. #14938 | |
| 16743 | 16085 | return .zero_usize; |
| 16744 | 16086 | } else { |
| 16745 | 16087 | return block.addNoOp(.ret_addr); |
| ... | ... | @@ -16886,6 +16228,8 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16886 | 16228 | try sema.declareDependency(.{ .namespace = type_decl_inst }); |
| 16887 | 16229 | } |
| 16888 | 16230 | |
| 16231 | try sema.ensureLayoutResolved(ty); | |
| 16232 | ||
| 16889 | 16233 | switch (ty.zigTypeTag(zcu)) { |
| 16890 | 16234 | .type, |
| 16891 | 16235 | .void, |
| ... | ... | @@ -16934,7 +16278,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16934 | 16278 | .child = param_info_ty.toIntern(), |
| 16935 | 16279 | }); |
| 16936 | 16280 | const new_decl_val = (try pt.aggregateValue(new_decl_ty, param_vals)).toIntern(); |
| 16937 | const slice_ty = (try pt.ptrTypeSema(.{ | |
| 16281 | const slice_ty = (try pt.ptrType(.{ | |
| 16938 | 16282 | .child = param_info_ty.toIntern(), |
| 16939 | 16283 | .flags = .{ |
| 16940 | 16284 | .size = .slice, |
| ... | ... | @@ -16976,11 +16320,14 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16976 | 16320 | error.OutOfMemory => |e| return e, |
| 16977 | 16321 | }; |
| 16978 | 16322 | |
| 16323 | // MLUGG TODO | |
| 16324 | const func_is_generic = false; | |
| 16325 | ||
| 16979 | 16326 | const field_values: [5]InternPool.Index = .{ |
| 16980 | 16327 | // calling_convention: CallingConvention, |
| 16981 | 16328 | callconv_val.toIntern(), |
| 16982 | 16329 | // is_generic: bool, |
| 16983 | Value.makeBool(func_ty_info.is_generic).toIntern(), | |
| 16330 | Value.makeBool(func_is_generic).toIntern(), | |
| 16984 | 16331 | // is_var_args: bool, |
| 16985 | 16332 | Value.makeBool(func_ty_info.is_var_args).toIntern(), |
| 16986 | 16333 | // return_type: ?type, |
| ... | ... | @@ -17015,7 +16362,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 17015 | 16362 | |
| 17016 | 16363 | const field_vals = .{ |
| 17017 | 16364 | // bits: u16, |
| 17018 | (try pt.intValue(.u16, ty.bitSize(zcu))).toIntern(), | |
| 16365 | (try pt.intValue(.u16, ty.floatBits(zcu.getTarget()))).toIntern(), | |
| 17019 | 16366 | }; |
| 17020 | 16367 | return Air.internedToRef((try pt.internUnion(.{ |
| 17021 | 16368 | .ty = type_info_ty.toIntern(), |
| ... | ... | @@ -17025,10 +16372,13 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 17025 | 16372 | }, |
| 17026 | 16373 | .pointer => { |
| 17027 | 16374 | const info = ty.ptrInfo(zcu); |
| 17028 | const alignment = if (info.flags.alignment.toByteUnits()) |alignment| | |
| 17029 | try pt.intValue(.comptime_int, alignment) | |
| 17030 | else | |
| 17031 | try Type.fromInterned(info.child).lazyAbiAlignment(pt); | |
| 16375 | const alignment_val = try pt.intValue(.comptime_int, bytes: { | |
| 16376 | if (info.flags.alignment.toByteUnits()) |b| break :bytes b; | |
| 16377 | const elem_ty: Type = .fromInterned(info.child); | |
| 16378 | // MLUGG TODO: this resolution is sus, but i doubt i'll solve it in this branch | |
| 16379 | try sema.ensureLayoutResolved(elem_ty); | |
| 16380 | break :bytes elem_ty.abiAlignment(zcu).toByteUnits().?; | |
| 16381 | }); | |
| 17032 | 16382 | |
| 17033 | 16383 | const addrspace_ty = try sema.getBuiltinType(src, .AddressSpace); |
| 17034 | 16384 | const pointer_ty = try sema.getBuiltinType(src, .@"Type.Pointer"); |
| ... | ... | @@ -17042,7 +16392,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 17042 | 16392 | // is_volatile: bool, |
| 17043 | 16393 | Value.makeBool(info.flags.is_volatile).toIntern(), |
| 17044 | 16394 | // alignment: comptime_int, |
| 17045 | alignment.toIntern(), | |
| 16395 | alignment_val.toIntern(), | |
| 17046 | 16396 | // address_space: AddressSpace |
| 17047 | 16397 | (try pt.enumValueFieldIndex(addrspace_ty, @intFromEnum(info.flags.address_space))).toIntern(), |
| 17048 | 16398 | // child: type, |
| ... | ... | @@ -17159,7 +16509,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 17159 | 16509 | }; |
| 17160 | 16510 | |
| 17161 | 16511 | // Build our ?[]const Error value |
| 17162 | const slice_errors_ty = try pt.ptrTypeSema(.{ | |
| 16512 | const slice_errors_ty = try pt.ptrType(.{ | |
| 17163 | 16513 | .child = error_field_ty.toIntern(), |
| 17164 | 16514 | .flags = .{ |
| 17165 | 16515 | .size = .slice, |
| ... | ... | @@ -17215,19 +16565,19 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 17215 | 16565 | }))); |
| 17216 | 16566 | }, |
| 17217 | 16567 | .@"enum" => { |
| 17218 | const is_exhaustive = Value.makeBool(ip.loadEnumType(ty.toIntern()).tag_mode != .nonexhaustive); | |
| 16568 | const enum_obj = ip.loadEnumType(ty.toIntern()); | |
| 16569 | const is_exhaustive: Value = .makeBool(!enum_obj.nonexhaustive); | |
| 17219 | 16570 | |
| 17220 | 16571 | const enum_field_ty = try sema.getBuiltinType(src, .@"Type.EnumField"); |
| 17221 | 16572 | |
| 17222 | const enum_field_vals = try sema.arena.alloc(InternPool.Index, ip.loadEnumType(ty.toIntern()).names.len); | |
| 16573 | const enum_field_vals = try sema.arena.alloc(InternPool.Index, enum_obj.field_names.len); | |
| 17223 | 16574 | for (enum_field_vals, 0..) |*field_val, tag_index| { |
| 17224 | const enum_type = ip.loadEnumType(ty.toIntern()); | |
| 17225 | const value_val = if (enum_type.values.len > 0) | |
| 16575 | const value_val = if (enum_obj.field_values.len > 0) | |
| 17226 | 16576 | try ip.getCoercedInts( |
| 17227 | 16577 | gpa, |
| 17228 | 16578 | io, |
| 17229 | 16579 | pt.tid, |
| 17230 | ip.indexToKey(enum_type.values.get(ip)[tag_index]).int, | |
| 16580 | ip.indexToKey(enum_obj.field_values.get(ip)[tag_index]).int, | |
| 17231 | 16581 | .comptime_int_type, |
| 17232 | 16582 | ) |
| 17233 | 16583 | else |
| ... | ... | @@ -17235,7 +16585,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 17235 | 16585 | |
| 17236 | 16586 | // TODO: write something like getCoercedInts to avoid needing to dupe |
| 17237 | 16587 | const name_val = v: { |
| 17238 | const tag_name = enum_type.names.get(ip)[tag_index]; | |
| 16588 | const tag_name = enum_obj.field_names.get(ip)[tag_index]; | |
| 17239 | 16589 | const tag_name_len = tag_name.length(ip); |
| 17240 | 16590 | const new_decl_ty = try pt.arrayType(.{ |
| 17241 | 16591 | .len = tag_name_len, |
| ... | ... | @@ -17275,7 +16625,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 17275 | 16625 | .child = enum_field_ty.toIntern(), |
| 17276 | 16626 | }); |
| 17277 | 16627 | const new_decl_val = (try pt.aggregateValue(fields_array_ty, enum_field_vals)).toIntern(); |
| 17278 | const slice_ty = (try pt.ptrTypeSema(.{ | |
| 16628 | const slice_ty = (try pt.ptrType(.{ | |
| 17279 | 16629 | .child = enum_field_ty.toIntern(), |
| 17280 | 16630 | .flags = .{ |
| 17281 | 16631 | .size = .slice, |
| ... | ... | @@ -17303,7 +16653,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 17303 | 16653 | |
| 17304 | 16654 | const field_values = .{ |
| 17305 | 16655 | // tag_type: type, |
| 17306 | ip.loadEnumType(ty.toIntern()).tag_ty, | |
| 16656 | ip.loadEnumType(ty.toIntern()).int_tag_type, | |
| 17307 | 16657 | // fields: []const EnumField, |
| 17308 | 16658 | fields_val, |
| 17309 | 16659 | // decls: []const Declaration, |
| ... | ... | @@ -17321,17 +16671,16 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 17321 | 16671 | const type_union_ty = try sema.getBuiltinType(src, .@"Type.Union"); |
| 17322 | 16672 | const union_field_ty = try sema.getBuiltinType(src, .@"Type.UnionField"); |
| 17323 | 16673 | |
| 17324 | try ty.resolveLayout(pt); // Getting alignment requires type layout | |
| 17325 | const union_obj = zcu.typeToUnion(ty).?; | |
| 17326 | const tag_type = union_obj.loadTagType(ip); | |
| 17327 | const layout = union_obj.flagsUnordered(ip).layout; | |
| 16674 | const union_obj = ip.loadUnionType(ty.toIntern()); | |
| 16675 | const enum_obj = ip.loadEnumType(union_obj.enum_tag_type); | |
| 16676 | const layout = union_obj.layout; | |
| 17328 | 16677 | |
| 17329 | const union_field_vals = try gpa.alloc(InternPool.Index, tag_type.names.len); | |
| 16678 | const union_field_vals = try gpa.alloc(InternPool.Index, enum_obj.field_names.len); | |
| 17330 | 16679 | defer gpa.free(union_field_vals); |
| 17331 | 16680 | |
| 17332 | 16681 | for (union_field_vals, 0..) |*field_val, field_index| { |
| 17333 | 16682 | const name_val = v: { |
| 17334 | const field_name = tag_type.names.get(ip)[field_index]; | |
| 16683 | const field_name = enum_obj.field_names.get(ip)[field_index]; | |
| 17335 | 16684 | const field_name_len = field_name.length(ip); |
| 17336 | 16685 | const new_decl_ty = try pt.arrayType(.{ |
| 17337 | 16686 | .len = field_name_len, |
| ... | ... | @@ -17357,7 +16706,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 17357 | 16706 | }; |
| 17358 | 16707 | |
| 17359 | 16708 | const alignment = switch (layout) { |
| 17360 | .auto, .@"extern" => try ty.fieldAlignmentSema(field_index, pt), | |
| 16709 | .auto, .@"extern" => ty.resolvedFieldAlignment(field_index, zcu), | |
| 17361 | 16710 | .@"packed" => .none, |
| 17362 | 16711 | }; |
| 17363 | 16712 | |
| ... | ... | @@ -17379,7 +16728,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 17379 | 16728 | .child = union_field_ty.toIntern(), |
| 17380 | 16729 | }); |
| 17381 | 16730 | const new_decl_val = (try pt.aggregateValue(array_fields_ty, union_field_vals)).toIntern(); |
| 17382 | const slice_ty = (try pt.ptrTypeSema(.{ | |
| 16731 | const slice_ty = (try pt.ptrType(.{ | |
| 17383 | 16732 | .child = union_field_ty.toIntern(), |
| 17384 | 16733 | .flags = .{ |
| 17385 | 16734 | .size = .slice, |
| ... | ... | @@ -17431,8 +16780,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 17431 | 16780 | const type_struct_ty = try sema.getBuiltinType(src, .@"Type.Struct"); |
| 17432 | 16781 | const struct_field_ty = try sema.getBuiltinType(src, .@"Type.StructField"); |
| 17433 | 16782 | |
| 17434 | try ty.resolveLayout(pt); // Getting alignment requires type layout | |
| 17435 | ||
| 17436 | 16783 | var struct_field_vals: []InternPool.Index = &.{}; |
| 17437 | 16784 | defer gpa.free(struct_field_vals); |
| 17438 | 16785 | fv: { |
| ... | ... | @@ -17468,8 +16815,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 17468 | 16815 | } }); |
| 17469 | 16816 | }; |
| 17470 | 16817 | |
| 17471 | try Type.fromInterned(field_ty).resolveLayout(pt); | |
| 17472 | ||
| 17473 | 16818 | const is_comptime = field_val != .none; |
| 17474 | 16819 | const opt_default_val = if (is_comptime) Value.fromInterned(field_val) else null; |
| 17475 | 16820 | const default_val_ptr = try sema.optRefValue(opt_default_val); |
| ... | ... | @@ -17492,16 +16837,17 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 17492 | 16837 | .struct_type => ip.loadStructType(ty.toIntern()), |
| 17493 | 16838 | else => unreachable, |
| 17494 | 16839 | }; |
| 16840 | try sema.ensureFieldInitsResolved(ty); // can't do this sooner, since it's not allowed on tuples | |
| 17495 | 16841 | struct_field_vals = try gpa.alloc(InternPool.Index, struct_type.field_types.len); |
| 17496 | 16842 | |
| 17497 | try ty.resolveStructFieldInits(pt); | |
| 17498 | ||
| 17499 | 16843 | for (struct_field_vals, 0..) |*field_val, field_index| { |
| 17500 | const field_name = struct_type.fieldName(ip, field_index); | |
| 16844 | const field_name = struct_type.field_names.get(ip)[field_index]; | |
| 17501 | 16845 | const field_name_len = field_name.length(ip); |
| 17502 | 16846 | const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]); |
| 17503 | const field_init = struct_type.fieldInit(ip, field_index); | |
| 17504 | const field_is_comptime = struct_type.fieldIsComptime(ip, field_index); | |
| 16847 | const field_default: InternPool.Index = if (struct_type.field_defaults.len > 0) d: { | |
| 16848 | break :d struct_type.field_defaults.get(ip)[field_index]; | |
| 16849 | } else .none; | |
| 16850 | const field_is_comptime = struct_type.field_is_comptime_bits.get(ip, field_index); | |
| 17505 | 16851 | const name_val = v: { |
| 17506 | 16852 | const new_decl_ty = try pt.arrayType(.{ |
| 17507 | 16853 | .len = field_name_len, |
| ... | ... | @@ -17526,15 +16872,11 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 17526 | 16872 | } }); |
| 17527 | 16873 | }; |
| 17528 | 16874 | |
| 17529 | const opt_default_val = if (field_init == .none) null else Value.fromInterned(field_init); | |
| 16875 | const opt_default_val: ?Value = if (field_default == .none) null else .fromInterned(field_default); | |
| 17530 | 16876 | const default_val_ptr = try sema.optRefValue(opt_default_val); |
| 17531 | 16877 | const alignment = switch (struct_type.layout) { |
| 16878 | .auto, .@"extern" => ty.resolvedFieldAlignment(field_index, zcu), | |
| 17532 | 16879 | .@"packed" => .none, |
| 17533 | else => try field_ty.structFieldAlignmentSema( | |
| 17534 | struct_type.fieldAlign(ip, field_index), | |
| 17535 | struct_type.layout, | |
| 17536 | pt, | |
| 17537 | ), | |
| 17538 | 16880 | }; |
| 17539 | 16881 | |
| 17540 | 16882 | const struct_field_fields = .{ |
| ... | ... | @@ -17559,7 +16901,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 17559 | 16901 | .child = struct_field_ty.toIntern(), |
| 17560 | 16902 | }); |
| 17561 | 16903 | const new_decl_val = (try pt.aggregateValue(array_fields_ty, struct_field_vals)).toIntern(); |
| 17562 | const slice_ty = (try pt.ptrTypeSema(.{ | |
| 16904 | const slice_ty = (try pt.ptrType(.{ | |
| 17563 | 16905 | .child = struct_field_ty.toIntern(), |
| 17564 | 16906 | .flags = .{ |
| 17565 | 16907 | .size = .slice, |
| ... | ... | @@ -17585,9 +16927,9 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 17585 | 16927 | |
| 17586 | 16928 | const backing_integer_val = try pt.intern(.{ .opt = .{ |
| 17587 | 16929 | .ty = (try pt.optionalType(.type_type)).toIntern(), |
| 17588 | .val = if (zcu.typeToPackedStruct(ty)) |packed_struct| val: { | |
| 17589 | assert(Type.fromInterned(packed_struct.backingIntTypeUnordered(ip)).isInt(zcu)); | |
| 17590 | break :val packed_struct.backingIntTypeUnordered(ip); | |
| 16930 | .val = if (zcu.typeToPackedStruct(ty)) |struct_obj| val: { | |
| 16931 | assert(Type.fromInterned(struct_obj.packed_backing_int_type).isInt(zcu)); | |
| 16932 | break :val struct_obj.packed_backing_int_type; | |
| 17591 | 16933 | } else .none, |
| 17592 | 16934 | } }); |
| 17593 | 16935 | |
| ... | ... | @@ -17616,7 +16958,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 17616 | 16958 | .@"opaque" => { |
| 17617 | 16959 | const type_opaque_ty = try sema.getBuiltinType(src, .@"Type.Opaque"); |
| 17618 | 16960 | |
| 17619 | try ty.resolveFields(pt); | |
| 17620 | 16961 | const decls_val = try sema.typeInfoDecls(src, ty.getNamespace(zcu)); |
| 17621 | 16962 | |
| 17622 | 16963 | const field_values = .{ |
| ... | ... | @@ -17658,7 +16999,7 @@ fn typeInfoDecls( |
| 17658 | 16999 | .child = declaration_ty.toIntern(), |
| 17659 | 17000 | }); |
| 17660 | 17001 | const new_decl_val = (try pt.aggregateValue(array_decl_ty, decl_vals.items)).toIntern(); |
| 17661 | const slice_ty = (try pt.ptrTypeSema(.{ | |
| 17002 | const slice_ty = (try pt.ptrType(.{ | |
| 17662 | 17003 | .child = declaration_ty.toIntern(), |
| 17663 | 17004 | .flags = .{ |
| 17664 | 17005 | .size = .slice, |
| ... | ... | @@ -17783,22 +17124,12 @@ fn log2IntType(sema: *Sema, block: *Block, operand: Type, src: LazySrcLoc) Compi |
| 17783 | 17124 | const zcu = pt.zcu; |
| 17784 | 17125 | switch (operand.zigTypeTag(zcu)) { |
| 17785 | 17126 | .comptime_int => return .comptime_int, |
| 17786 | .int => { | |
| 17787 | const bits = operand.bitSize(zcu); | |
| 17788 | const count = if (bits == 0) | |
| 17789 | 0 | |
| 17790 | else blk: { | |
| 17791 | var count: u16 = 0; | |
| 17792 | var s = bits - 1; | |
| 17793 | while (s != 0) : (s >>= 1) { | |
| 17794 | count += 1; | |
| 17795 | } | |
| 17796 | break :blk count; | |
| 17797 | }; | |
| 17798 | return pt.intType(.unsigned, count); | |
| 17799 | }, | |
| 17127 | .int => return pt.intType(.unsigned, switch (operand.intInfo(zcu).bits) { | |
| 17128 | 0 => 0, | |
| 17129 | else => |b| std.math.log2_int_ceil(u16, b), | |
| 17130 | }), | |
| 17800 | 17131 | .vector => { |
| 17801 | const elem_ty = operand.elemType2(zcu); | |
| 17132 | const elem_ty = operand.childType(zcu); | |
| 17802 | 17133 | const log2_elem_ty = try sema.log2IntType(block, elem_ty, src); |
| 17803 | 17134 | return pt.vectorType(.{ |
| 17804 | 17135 | .len = operand.vectorLen(zcu), |
| ... | ... | @@ -18082,13 +17413,15 @@ fn zirIsNonNullPtr( |
| 18082 | 17413 | const src = block.nodeOffset(inst_data.src_node); |
| 18083 | 17414 | const ptr = try sema.resolveInst(inst_data.operand); |
| 18084 | 17415 | const ptr_ty = sema.typeOf(ptr); |
| 18085 | try sema.checkNullableType(block, src, sema.typeOf(ptr).elemType2(zcu)); | |
| 17416 | assert(ptr_ty.zigTypeTag(zcu) == .pointer); | |
| 17417 | const nullable_ty = ptr_ty.childType(zcu); | |
| 17418 | try sema.checkNullableType(block, src, nullable_ty); | |
| 18086 | 17419 | if (try sema.resolveValue(ptr)) |ptr_val| { |
| 18087 | if (try sema.pointerDeref(block, src, ptr_val, ptr_ty)) |loaded_val| { | |
| 18088 | return sema.analyzeIsNull(block, Air.internedToRef(loaded_val.toIntern()), true); | |
| 17420 | if (try sema.pointerDeref(block, src, ptr_val, ptr_ty)) |nullable_val| { | |
| 17421 | return sema.analyzeIsNull(block, .fromValue(nullable_val), true); | |
| 18089 | 17422 | } |
| 18090 | 17423 | } |
| 18091 | if (ptr_ty.childType(zcu).isNullFromType(zcu)) |is_null| { | |
| 17424 | if (nullable_ty.isNullFromType(zcu)) |is_null| { | |
| 18092 | 17425 | return if (is_null) .bool_false else .bool_true; |
| 18093 | 17426 | } |
| 18094 | 17427 | return block.addUnOp(.is_non_null_ptr, ptr); |
| ... | ... | @@ -18125,7 +17458,10 @@ fn zirIsNonErrPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 18125 | 17458 | const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; |
| 18126 | 17459 | const src = block.nodeOffset(inst_data.src_node); |
| 18127 | 17460 | const ptr = try sema.resolveInst(inst_data.operand); |
| 18128 | try sema.checkErrorType(block, src, sema.typeOf(ptr).elemType2(zcu)); | |
| 17461 | const ptr_ty = sema.typeOf(ptr); | |
| 17462 | assert(ptr_ty.zigTypeTag(zcu) == .pointer); | |
| 17463 | const error_ty = ptr_ty.childType(zcu); | |
| 17464 | try sema.checkErrorType(block, src, error_ty); | |
| 18129 | 17465 | const loaded = try sema.analyzeLoad(block, src, ptr, src); |
| 18130 | 17466 | return sema.analyzeIsNonErr(block, src, loaded); |
| 18131 | 17467 | } |
| ... | ... | @@ -18294,6 +17630,11 @@ fn zirTry(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError! |
| 18294 | 17630 | } }, |
| 18295 | 17631 | }); |
| 18296 | 17632 | sema.air_extra.appendSliceAssumeCapacity(@ptrCast(sub_block.instructions.items)); |
| 17633 | ||
| 17634 | // The payload type might still be OPV, in which case `try_inst` is just there for the runtime | |
| 17635 | // control flow and we should return a comptime-known result. | |
| 17636 | if (try err_union_ty.errorUnionPayload(zcu).onePossibleValue(pt)) |opv| return .fromValue(opv); | |
| 17637 | ||
| 18297 | 17638 | return try_inst; |
| 18298 | 17639 | } |
| 18299 | 17640 | |
| ... | ... | @@ -18347,7 +17688,7 @@ fn zirTryPtr(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErr |
| 18347 | 17688 | |
| 18348 | 17689 | const operand_ty = sema.typeOf(operand); |
| 18349 | 17690 | const ptr_info = operand_ty.ptrInfo(zcu); |
| 18350 | const res_ty = try pt.ptrTypeSema(.{ | |
| 17691 | const res_ty = try pt.ptrType(.{ | |
| 18351 | 17692 | .child = err_union_ty.errorUnionPayload(zcu).toIntern(), |
| 18352 | 17693 | .flags = .{ |
| 18353 | 17694 | .is_const = ptr_info.flags.is_const, |
| ... | ... | @@ -18512,7 +17853,7 @@ fn zirRetImplicit( |
| 18512 | 17853 | |
| 18513 | 17854 | const operand = try sema.resolveInst(inst_data.operand); |
| 18514 | 17855 | const ret_ty_src = block.src(.{ .node_offset_fn_type_ret_ty = .zero }); |
| 18515 | const base_tag = sema.fn_ret_ty.baseZigTypeTag(zcu); | |
| 17856 | const base_tag = sema.fn_ret_ty.optEuBaseType(zcu).zigTypeTag(zcu); | |
| 18516 | 17857 | if (base_tag == .noreturn) { |
| 18517 | 17858 | const msg = msg: { |
| 18518 | 17859 | const msg = try sema.errMsg(ret_ty_src, "function declared '{f}' implicitly returns", .{ |
| ... | ... | @@ -18809,8 +18150,6 @@ fn analyzeRet( |
| 18809 | 18150 | return sema.failWithOwnedErrorMsg(block, msg); |
| 18810 | 18151 | } |
| 18811 | 18152 | |
| 18812 | try sema.fn_ret_ty.resolveLayout(pt); | |
| 18813 | ||
| 18814 | 18153 | try sema.validateRuntimeValue(block, operand_src, operand); |
| 18815 | 18154 | |
| 18816 | 18155 | const air_tag: Air.Inst.Tag = if (block.wantSafety()) .ret_safe else .ret; |
| ... | ... | @@ -18889,16 +18228,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 18889 | 18228 | extra_i += 1; |
| 18890 | 18229 | const coerced = try sema.coerce(block, align_ty, try sema.resolveInst(ref), align_src); |
| 18891 | 18230 | const val = try sema.resolveConstDefinedValue(block, align_src, coerced, .{ .simple = .@"align" }); |
| 18892 | // Check if this happens to be the lazy alignment of our element type, in | |
| 18893 | // which case we can make this 0 without resolving it. | |
| 18894 | switch (zcu.intern_pool.indexToKey(val.toIntern())) { | |
| 18895 | .int => |int| switch (int.storage) { | |
| 18896 | .lazy_align => |lazy_ty| if (lazy_ty == elem_ty.toIntern()) break :blk .none, | |
| 18897 | else => {}, | |
| 18898 | }, | |
| 18899 | else => {}, | |
| 18900 | } | |
| 18901 | const align_bytes = (try val.getUnsignedIntSema(pt)).?; | |
| 18231 | const align_bytes = val.toUnsignedInt(zcu); | |
| 18902 | 18232 | break :blk try sema.validateAlign(block, align_src, align_bytes); |
| 18903 | 18233 | } else .none; |
| 18904 | 18234 | |
| ... | ... | @@ -18928,7 +18258,8 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 18928 | 18258 | elem_ty.fmt(pt), bit_offset, bit_offset - host_size * 8, host_size, |
| 18929 | 18259 | }); |
| 18930 | 18260 | } |
| 18931 | const elem_bit_size = try elem_ty.bitSizeSema(pt); | |
| 18261 | try sema.ensureLayoutResolved(elem_ty); | |
| 18262 | const elem_bit_size = elem_ty.bitSize(zcu); | |
| 18932 | 18263 | if (elem_bit_size > host_size * 8 - bit_offset) { |
| 18933 | 18264 | return sema.fail(block, bitoffset_src, "packed type '{f}' at bit offset {d} ends {d} bits after the end of a {d} byte host integer", .{ |
| 18934 | 18265 | elem_ty.fmt(pt), bit_offset, elem_bit_size - (host_size * 8 - bit_offset), host_size, |
| ... | ... | @@ -18957,16 +18288,16 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 18957 | 18288 | } |
| 18958 | 18289 | } |
| 18959 | 18290 | |
| 18960 | if (host_size != 0 and !try sema.validatePackedType(elem_ty)) { | |
| 18291 | if (host_size != 0 and !elem_ty.packable(zcu)) { | |
| 18961 | 18292 | return sema.failWithOwnedErrorMsg(block, msg: { |
| 18962 | 18293 | const msg = try sema.errMsg(elem_ty_src, "bit-pointer cannot refer to value of type '{f}'", .{elem_ty.fmt(pt)}); |
| 18963 | 18294 | errdefer msg.destroy(sema.gpa); |
| 18964 | try sema.explainWhyTypeIsNotPacked(msg, elem_ty_src, elem_ty); | |
| 18295 | try sema.explainWhyTypeIsNotPackable(msg, elem_ty_src, elem_ty); | |
| 18965 | 18296 | break :msg msg; |
| 18966 | 18297 | }); |
| 18967 | 18298 | } |
| 18968 | 18299 | |
| 18969 | const ty = try pt.ptrTypeSema(.{ | |
| 18300 | const ty = try pt.ptrType(.{ | |
| 18970 | 18301 | .child = elem_ty.toIntern(), |
| 18971 | 18302 | .sentinel = sentinel, |
| 18972 | 18303 | .flags = .{ |
| ... | ... | @@ -18996,6 +18327,8 @@ fn zirStructInitEmpty(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE |
| 18996 | 18327 | const pt = sema.pt; |
| 18997 | 18328 | const zcu = pt.zcu; |
| 18998 | 18329 | |
| 18330 | try sema.ensureLayoutResolved(obj_ty); | |
| 18331 | ||
| 18999 | 18332 | switch (obj_ty.zigTypeTag(zcu)) { |
| 19000 | 18333 | .@"struct" => return sema.structInitEmpty(block, obj_ty, src, src), |
| 19001 | 18334 | .array, .vector => return sema.arrayInitEmpty(block, src, obj_ty), |
| ... | ... | @@ -19058,6 +18391,9 @@ fn zirStructInitEmptyResult(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is |
| 19058 | 18391 | .child = ptr_ty.childType(zcu).toIntern(), |
| 19059 | 18392 | }); |
| 19060 | 18393 | } else ty_operand; |
| 18394 | ||
| 18395 | try sema.ensureLayoutResolved(init_ty); | |
| 18396 | ||
| 19061 | 18397 | const obj_ty = init_ty.optEuBaseType(zcu); |
| 19062 | 18398 | |
| 19063 | 18399 | const empty_ref = switch (obj_ty.zigTypeTag(zcu)) { |
| ... | ... | @@ -19076,6 +18412,7 @@ fn zirStructInitEmptyResult(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is |
| 19076 | 18412 | } |
| 19077 | 18413 | } |
| 19078 | 18414 | |
| 18415 | /// Asserts that the layout of `struct_ty` is already resolved. | |
| 19079 | 18416 | fn structInitEmpty( |
| 19080 | 18417 | sema: *Sema, |
| 19081 | 18418 | block: *Block, |
| ... | ... | @@ -19087,7 +18424,7 @@ fn structInitEmpty( |
| 19087 | 18424 | const zcu = pt.zcu; |
| 19088 | 18425 | const gpa = sema.gpa; |
| 19089 | 18426 | // This logic must be synchronized with that in `zirStructInit`. |
| 19090 | try struct_ty.resolveFields(pt); | |
| 18427 | struct_ty.assertHasLayout(zcu); | |
| 19091 | 18428 | |
| 19092 | 18429 | // The init values to use for the struct instance. |
| 19093 | 18430 | const field_inits = try gpa.alloc(Air.Inst.Ref, struct_ty.structFieldCount(zcu)); |
| ... | ... | @@ -19202,8 +18539,8 @@ fn zirStructInit( |
| 19202 | 18539 | // The type wasn't actually known, so treat this as an anon struct init. |
| 19203 | 18540 | return sema.structInitAnon(block, src, inst, .typed_init, extra.data, extra.end, is_ref); |
| 19204 | 18541 | }; |
| 18542 | try sema.ensureLayoutResolved(result_ty); | |
| 19205 | 18543 | const resolved_ty = result_ty.optEuBaseType(zcu); |
| 19206 | try resolved_ty.resolveLayout(pt); | |
| 19207 | 18544 | |
| 19208 | 18545 | if (resolved_ty.zigTypeTag(zcu) == .@"struct") { |
| 19209 | 18546 | // This logic must be synchronized with that in `zirStructInitEmpty`. |
| ... | ... | @@ -19226,7 +18563,6 @@ fn zirStructInit( |
| 19226 | 18563 | var field_i: u32 = 0; |
| 19227 | 18564 | var extra_index = extra.end; |
| 19228 | 18565 | |
| 19229 | const is_packed = resolved_ty.containerLayout(zcu) == .@"packed"; | |
| 19230 | 18566 | while (field_i < extra.data.fields_len) : (field_i += 1) { |
| 19231 | 18567 | const item = sema.code.extraData(Zir.Inst.StructInit.Item, extra_index); |
| 19232 | 18568 | extra_index = item.end; |
| ... | ... | @@ -19251,16 +18587,16 @@ fn zirStructInit( |
| 19251 | 18587 | const uncoerced_init = try sema.resolveInst(item.data.init); |
| 19252 | 18588 | const field_ty = resolved_ty.fieldType(field_index, zcu); |
| 19253 | 18589 | field_inits[field_index] = try sema.coerce(block, field_ty, uncoerced_init, field_src); |
| 19254 | if (!is_packed) { | |
| 19255 | try resolved_ty.resolveStructFieldInits(pt); | |
| 19256 | if (try resolved_ty.structFieldValueComptime(pt, field_index)) |default_value| { | |
| 19257 | const init_val = (try sema.resolveValue(field_inits[field_index])) orelse { | |
| 19258 | return sema.failWithNeededComptime(block, field_src, .{ .simple = .stored_to_comptime_field }); | |
| 19259 | }; | |
| 19260 | ||
| 19261 | if (!init_val.eql(default_value, resolved_ty.fieldType(field_index, zcu), zcu)) { | |
| 19262 | return sema.failWithInvalidComptimeFieldStore(block, field_src, resolved_ty, field_index); | |
| 19263 | } | |
| 18590 | if (resolved_ty.structFieldIsComptime(field_index, zcu)) { | |
| 18591 | if (!resolved_ty.isTuple(zcu)) { | |
| 18592 | try sema.ensureFieldInitsResolved(resolved_ty); | |
| 18593 | } | |
| 18594 | const default_value = (try resolved_ty.structFieldValueComptime(pt, field_index)).?; | |
| 18595 | const init_val = (try sema.resolveValue(field_inits[field_index])) orelse { | |
| 18596 | return sema.failWithNeededComptime(block, field_src, .{ .simple = .stored_to_comptime_field }); | |
| 18597 | }; | |
| 18598 | if (!init_val.eql(default_value, resolved_ty.fieldType(field_index, zcu), zcu)) { | |
| 18599 | return sema.failWithInvalidComptimeFieldStore(block, field_src, resolved_ty, field_index); | |
| 19264 | 18600 | } |
| 19265 | 18601 | } |
| 19266 | 18602 | } |
| ... | ... | @@ -19315,7 +18651,7 @@ fn zirStructInit( |
| 19315 | 18651 | return sema.addConstantMaybeRef(final_val.toIntern(), is_ref); |
| 19316 | 18652 | } |
| 19317 | 18653 | |
| 19318 | if (try resolved_ty.comptimeOnlySema(pt)) { | |
| 18654 | if (resolved_ty.comptimeOnly(zcu)) { | |
| 19319 | 18655 | return sema.failWithNeededComptime(block, field_src, .{ .comptime_only = .{ |
| 19320 | 18656 | .ty = resolved_ty, |
| 19321 | 18657 | .msg = .union_init, |
| ... | ... | @@ -19326,7 +18662,7 @@ fn zirStructInit( |
| 19326 | 18662 | |
| 19327 | 18663 | if (is_ref) { |
| 19328 | 18664 | const target = zcu.getTarget(); |
| 19329 | const alloc_ty = try pt.ptrTypeSema(.{ | |
| 18665 | const alloc_ty = try pt.ptrType(.{ | |
| 19330 | 18666 | .child = result_ty.toIntern(), |
| 19331 | 18667 | .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) }, |
| 19332 | 18668 | }); |
| ... | ... | @@ -19334,9 +18670,8 @@ fn zirStructInit( |
| 19334 | 18670 | const base_ptr = try sema.optEuBasePtrInit(block, alloc, src); |
| 19335 | 18671 | const field_ptr = try sema.unionFieldPtr(block, field_src, base_ptr, field_name, field_src, resolved_ty, true); |
| 19336 | 18672 | try sema.storePtr(block, src, field_ptr, init_inst); |
| 19337 | if ((try sema.typeHasOnePossibleValue(tag_ty)) == null) { | |
| 19338 | const new_tag = Air.internedToRef(tag_val.toIntern()); | |
| 19339 | _ = try block.addBinOp(.set_union_tag, base_ptr, new_tag); | |
| 18673 | if (try tag_ty.onePossibleValue(pt) == null) { | |
| 18674 | _ = try block.addBinOp(.set_union_tag, base_ptr, .fromValue(tag_val)); | |
| 19340 | 18675 | } |
| 19341 | 18676 | return sema.makePtrConst(block, alloc); |
| 19342 | 18677 | } |
| ... | ... | @@ -19409,20 +18744,24 @@ fn finishStructInit( |
| 19409 | 18744 | continue; |
| 19410 | 18745 | } |
| 19411 | 18746 | |
| 19412 | try struct_ty.resolveStructFieldInits(pt); | |
| 18747 | try sema.ensureFieldInitsResolved(struct_ty); | |
| 19413 | 18748 | |
| 19414 | const field_init = struct_type.fieldInit(ip, i); | |
| 19415 | if (field_init == .none) { | |
| 19416 | const field_name = struct_type.field_names.get(ip)[i]; | |
| 19417 | const template = "missing struct field: {f}"; | |
| 19418 | const args = .{field_name.fmt(ip)}; | |
| 19419 | if (root_msg) |msg| { | |
| 19420 | try sema.errNote(init_src, msg, template, args); | |
| 19421 | } else { | |
| 19422 | root_msg = try sema.errMsg(init_src, template, args); | |
| 19423 | } | |
| 18749 | const field_default: InternPool.Index = d: { | |
| 18750 | if (struct_type.field_defaults.len == 0) break :d .none; | |
| 18751 | break :d struct_type.field_defaults.get(ip)[i]; | |
| 18752 | }; | |
| 18753 | if (field_default != .none) { | |
| 18754 | field_inits[i] = .fromIntern(field_default); | |
| 18755 | continue; | |
| 18756 | } | |
| 18757 | ||
| 18758 | const field_name = struct_type.field_names.get(ip)[i]; | |
| 18759 | const template = "missing struct field: {f}"; | |
| 18760 | const args = .{field_name.fmt(ip)}; | |
| 18761 | if (root_msg) |msg| { | |
| 18762 | try sema.errNote(init_src, msg, template, args); | |
| 19424 | 18763 | } else { |
| 19425 | field_inits[i] = Air.internedToRef(field_init); | |
| 18764 | root_msg = try sema.errMsg(init_src, template, args); | |
| 19426 | 18765 | } |
| 19427 | 18766 | } |
| 19428 | 18767 | }, |
| ... | ... | @@ -19453,7 +18792,7 @@ fn finishStructInit( |
| 19453 | 18792 | return sema.addConstantMaybeRef(final_val.toIntern(), is_ref); |
| 19454 | 18793 | }; |
| 19455 | 18794 | |
| 19456 | if (try struct_ty.comptimeOnlySema(pt)) { | |
| 18795 | if (struct_ty.comptimeOnly(zcu)) { | |
| 19457 | 18796 | return sema.failWithNeededComptime(block, block.src(.{ .init_elem = .{ |
| 19458 | 18797 | .init_node_offset = init_src.offset.node_offset.x, |
| 19459 | 18798 | .elem_index = @intCast(runtime_index), |
| ... | ... | @@ -19468,9 +18807,8 @@ fn finishStructInit( |
| 19468 | 18807 | } |
| 19469 | 18808 | |
| 19470 | 18809 | if (is_ref) { |
| 19471 | try struct_ty.resolveLayout(pt); | |
| 19472 | 18810 | const target = zcu.getTarget(); |
| 19473 | const alloc_ty = try pt.ptrTypeSema(.{ | |
| 18811 | const alloc_ty = try pt.ptrType(.{ | |
| 19474 | 18812 | .child = result_ty.toIntern(), |
| 19475 | 18813 | .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) }, |
| 19476 | 18814 | }); |
| ... | ... | @@ -19489,7 +18827,6 @@ fn finishStructInit( |
| 19489 | 18827 | .init_node_offset = init_src.offset.node_offset.x, |
| 19490 | 18828 | .elem_index = @intCast(runtime_index), |
| 19491 | 18829 | } })); |
| 19492 | try struct_ty.resolveStructFieldInits(pt); | |
| 19493 | 18830 | const struct_val = try block.addAggregateInit(struct_ty, field_inits); |
| 19494 | 18831 | return sema.coerce(block, result_ty, struct_val, init_src); |
| 19495 | 18832 | } |
| ... | ... | @@ -19585,12 +18922,11 @@ fn structInitAnon( |
| 19585 | 18922 | break :rs runtime_index; |
| 19586 | 18923 | }; |
| 19587 | 18924 | |
| 19588 | // We treat anonymous struct types as reified types, because there are similarities: | |
| 19589 | // * They use a form of structural equivalence, which we can easily model using a custom hash | |
| 19590 | // * They do not have captures | |
| 19591 | // * They immediately have their fields resolved | |
| 19592 | // In general, other code should treat anon struct types and reified struct types identically, | |
| 19593 | // so there's no point having a separate `InternPool.NamespaceType` field for them. | |
| 18925 | // We treat anonymous struct types as reified types, because there are similarities: they have | |
| 18926 | // no captures, and instead use a form of structural equivalence which we can easy represent by | |
| 18927 | // hashing the field names/types/values. They also perform layout resolution immediately. These | |
| 18928 | // similarities mean that other code should actually treat anon struct types and reified struct | |
| 18929 | // types identically anyway, so sharing the representation makes everything simpler. | |
| 19594 | 18930 | const type_hash: u64 = hash: { |
| 19595 | 18931 | var hasher = std.hash.Wyhash.init(0); |
| 19596 | 18932 | hasher.update(std.mem.sliceAsBytes(types)); |
| ... | ... | @@ -19599,36 +18935,36 @@ fn structInitAnon( |
| 19599 | 18935 | break :hash hasher.final(); |
| 19600 | 18936 | }; |
| 19601 | 18937 | const tracked_inst = try block.trackZir(inst); |
| 19602 | const struct_ty = switch (try ip.getStructType(gpa, io, pt.tid, .{ | |
| 19603 | .layout = .auto, | |
| 18938 | const struct_ty: Type = switch (try ip.getStructType(gpa, io, pt.tid, .{ | |
| 19604 | 18939 | .fields_len = extra_data.fields_len, |
| 19605 | .known_non_opv = false, | |
| 19606 | .requires_comptime = .unknown, | |
| 18940 | .layout = .auto, | |
| 18941 | .explicit_packed_backing_type = .none, | |
| 19607 | 18942 | .any_comptime_fields = any_values, |
| 19608 | .any_default_inits = any_values, | |
| 19609 | .inits_resolved = true, | |
| 19610 | .any_aligned_fields = false, | |
| 18943 | .any_field_defaults = any_values, | |
| 18944 | .any_field_aligns = false, | |
| 19611 | 18945 | .key = .{ .reified = .{ |
| 19612 | 18946 | .zir_index = tracked_inst, |
| 19613 | 18947 | .type_hash = type_hash, |
| 19614 | 18948 | } }, |
| 19615 | }, false)) { | |
| 18949 | })) { | |
| 19616 | 18950 | .wip => |wip| ty: { |
| 19617 | 18951 | errdefer wip.cancel(ip, pt.tid); |
| 19618 | const type_name = try sema.createTypeName(block, .anon, "struct", inst, wip.index); | |
| 19619 | wip.setName(ip, type_name.name, type_name.nav); | |
| 18952 | // MLUGG TODO obvs this sux | |
| 18953 | const anon_prefix = (try sema.createTypeName(block, .anon, "struct", inst)).anon_prefix; | |
| 18954 | wip.setName(ip, try ip.getOrPutStringFmt(gpa, io, pt.tid, "{s}_{d}", .{ anon_prefix, @intFromEnum(wip.index) }, .no_embedded_nulls), .none); | |
| 19620 | 18955 | |
| 19621 | 18956 | const struct_type = ip.loadStructType(wip.index); |
| 19622 | 18957 | |
| 19623 | for (names, values, 0..) |name, init_val, field_idx| { | |
| 19624 | assert(struct_type.addFieldName(ip, name) == null); | |
| 19625 | if (init_val != .none) struct_type.setFieldComptime(ip, field_idx); | |
| 18958 | for (names, values) |name, init_val| { | |
| 18959 | assert(wip.nextField(ip, name, init_val != .none) == null); // AstGen validated no duplicates for us | |
| 19626 | 18960 | } |
| 19627 | 18961 | |
| 18962 | // Populating these means the type is already resolved; we don't need to add it to `zcu.outdated` or anything. | |
| 18963 | // That's important because type resolution relies on types being declared. | |
| 19628 | 18964 | @memcpy(struct_type.field_types.get(ip), types); |
| 19629 | if (any_values) { | |
| 19630 | @memcpy(struct_type.field_inits.get(ip), values); | |
| 19631 | } | |
| 18965 | @memcpy(struct_type.field_defaults.get(ip), if (any_values) values else @as([]const InternPool.Index, &.{})); | |
| 18966 | ||
| 18967 | try type_resolution.finishStructLayout(sema, block, src, wip.index, &struct_type); | |
| 19632 | 18968 | |
| 19633 | 18969 | const new_namespace_index = try pt.createNamespace(.{ |
| 19634 | 18970 | .parent = block.namespace.toOptional(), |
| ... | ... | @@ -19636,7 +18972,6 @@ fn structInitAnon( |
| 19636 | 18972 | .file_scope = block.getFileScopeIndex(zcu), |
| 19637 | 18973 | .generation = zcu.generation, |
| 19638 | 18974 | }); |
| 19639 | try zcu.comp.queueJob(.{ .resolve_type_fully = wip.index }); | |
| 19640 | 18975 | codegen_type: { |
| 19641 | 18976 | if (zcu.comp.config.use_llvm) break :codegen_type; |
| 19642 | 18977 | if (block.ownerModule().strip) break :codegen_type; |
| ... | ... | @@ -19644,22 +18979,21 @@ fn structInitAnon( |
| 19644 | 18979 | try zcu.comp.queueJob(.{ .link_type = wip.index }); |
| 19645 | 18980 | } |
| 19646 | 18981 | if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index); |
| 19647 | break :ty wip.finish(ip, new_namespace_index); | |
| 18982 | break :ty .fromInterned(wip.finish(ip, new_namespace_index)); | |
| 19648 | 18983 | }, |
| 19649 | .existing => |ty| ty, | |
| 18984 | .existing => |ty| .fromInterned(ty), | |
| 19650 | 18985 | }; |
| 19651 | try sema.declareDependency(.{ .interned = struct_ty }); | |
| 19652 | 18986 | try sema.addTypeReferenceEntry(src, struct_ty); |
| 19653 | 18987 | |
| 19654 | 18988 | _ = opt_runtime_index orelse { |
| 19655 | const struct_val = try pt.aggregateValue(.fromInterned(struct_ty), values); | |
| 18989 | const struct_val = try pt.aggregateValue(struct_ty, values); | |
| 19656 | 18990 | return sema.addConstantMaybeRef(struct_val.toIntern(), is_ref); |
| 19657 | 18991 | }; |
| 19658 | 18992 | |
| 19659 | 18993 | if (is_ref) { |
| 19660 | 18994 | const target = zcu.getTarget(); |
| 19661 | const alloc_ty = try pt.ptrTypeSema(.{ | |
| 19662 | .child = struct_ty, | |
| 18995 | const alloc_ty = try pt.ptrType(.{ | |
| 18996 | .child = struct_ty.toIntern(), | |
| 19663 | 18997 | .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) }, |
| 19664 | 18998 | }); |
| 19665 | 18999 | const alloc = try block.addTy(.alloc, alloc_ty); |
| ... | ... | @@ -19672,7 +19006,7 @@ fn structInitAnon( |
| 19672 | 19006 | }; |
| 19673 | 19007 | extra_index = item.end; |
| 19674 | 19008 | |
| 19675 | const field_ptr_ty = try pt.ptrTypeSema(.{ | |
| 19009 | const field_ptr_ty = try pt.ptrType(.{ | |
| 19676 | 19010 | .child = field_ty, |
| 19677 | 19011 | .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) }, |
| 19678 | 19012 | }); |
| ... | ... | @@ -19697,7 +19031,7 @@ fn structInitAnon( |
| 19697 | 19031 | element_refs[i] = try sema.resolveInst(item.data.init); |
| 19698 | 19032 | } |
| 19699 | 19033 | |
| 19700 | return block.addAggregateInit(.fromInterned(struct_ty), element_refs); | |
| 19034 | return block.addAggregateInit(struct_ty, element_refs); | |
| 19701 | 19035 | } |
| 19702 | 19036 | |
| 19703 | 19037 | fn zirArrayInit( |
| ... | ... | @@ -19737,17 +19071,16 @@ fn zirArrayInit( |
| 19737 | 19071 | } }); |
| 19738 | 19072 | // Less inits than needed. |
| 19739 | 19073 | if (i + 2 > args.len) if (is_tuple) { |
| 19740 | const default_val = array_ty.structFieldDefaultValue(i, zcu).toIntern(); | |
| 19741 | if (default_val == .unreachable_value) { | |
| 19074 | const default_val = array_ty.structFieldDefaultValue(i, zcu) orelse { | |
| 19742 | 19075 | const template = "missing tuple field with index {d}"; |
| 19743 | 19076 | if (root_msg) |msg| { |
| 19744 | 19077 | try sema.errNote(src, msg, template, .{i}); |
| 19745 | 19078 | } else { |
| 19746 | 19079 | root_msg = try sema.errMsg(src, template, .{i}); |
| 19747 | 19080 | } |
| 19748 | } else { | |
| 19749 | dest.* = Air.internedToRef(default_val); | |
| 19750 | } | |
| 19081 | continue; | |
| 19082 | }; | |
| 19083 | dest.* = .fromValue(default_val); | |
| 19751 | 19084 | continue; |
| 19752 | 19085 | } else { |
| 19753 | 19086 | dest.* = Air.internedToRef(sentinel_val.?.toIntern()); |
| ... | ... | @@ -19759,11 +19092,9 @@ fn zirArrayInit( |
| 19759 | 19092 | const elem_ty = if (is_tuple) |
| 19760 | 19093 | array_ty.fieldType(i, zcu) |
| 19761 | 19094 | else |
| 19762 | array_ty.elemType2(zcu); | |
| 19095 | array_ty.childType(zcu); | |
| 19763 | 19096 | dest.* = try sema.coerce(block, elem_ty, resolved_arg, elem_src); |
| 19764 | 19097 | if (is_tuple) { |
| 19765 | if (array_ty.structFieldIsComptime(i, zcu)) | |
| 19766 | try array_ty.resolveStructFieldInits(pt); | |
| 19767 | 19098 | if (try array_ty.structFieldValueComptime(pt, i)) |field_val| { |
| 19768 | 19099 | const init_val = try sema.resolveConstValue(block, elem_src, dest.*, .{ .simple = .stored_to_comptime_field }); |
| 19769 | 19100 | if (!field_val.eql(init_val, elem_ty, zcu)) { |
| ... | ... | @@ -19798,7 +19129,7 @@ fn zirArrayInit( |
| 19798 | 19129 | |
| 19799 | 19130 | if (is_ref) { |
| 19800 | 19131 | const target = zcu.getTarget(); |
| 19801 | const alloc_ty = try pt.ptrTypeSema(.{ | |
| 19132 | const alloc_ty = try pt.ptrType(.{ | |
| 19802 | 19133 | .child = result_ty.toIntern(), |
| 19803 | 19134 | .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) }, |
| 19804 | 19135 | }); |
| ... | ... | @@ -19807,7 +19138,7 @@ fn zirArrayInit( |
| 19807 | 19138 | |
| 19808 | 19139 | if (is_tuple) { |
| 19809 | 19140 | for (resolved_args, 0..) |arg, i| { |
| 19810 | const elem_ptr_ty = try pt.ptrTypeSema(.{ | |
| 19141 | const elem_ptr_ty = try pt.ptrType(.{ | |
| 19811 | 19142 | .child = array_ty.fieldType(i, zcu).toIntern(), |
| 19812 | 19143 | .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) }, |
| 19813 | 19144 | }); |
| ... | ... | @@ -19820,8 +19151,8 @@ fn zirArrayInit( |
| 19820 | 19151 | return sema.makePtrConst(block, alloc); |
| 19821 | 19152 | } |
| 19822 | 19153 | |
| 19823 | const elem_ptr_ty = try pt.ptrTypeSema(.{ | |
| 19824 | .child = array_ty.elemType2(zcu).toIntern(), | |
| 19154 | const elem_ptr_ty = try pt.ptrType(.{ | |
| 19155 | .child = array_ty.childType(zcu).toIntern(), | |
| 19825 | 19156 | .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) }, |
| 19826 | 19157 | }); |
| 19827 | 19158 | const elem_ptr_ty_ref = Air.internedToRef(elem_ptr_ty.toIntern()); |
| ... | ... | @@ -19932,14 +19263,14 @@ fn arrayInitAnon( |
| 19932 | 19263 | |
| 19933 | 19264 | if (is_ref) { |
| 19934 | 19265 | const target = sema.pt.zcu.getTarget(); |
| 19935 | const alloc_ty = try pt.ptrTypeSema(.{ | |
| 19266 | const alloc_ty = try pt.ptrType(.{ | |
| 19936 | 19267 | .child = tuple_ty.toIntern(), |
| 19937 | 19268 | .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) }, |
| 19938 | 19269 | }); |
| 19939 | 19270 | const alloc = try block.addTy(.alloc, alloc_ty); |
| 19940 | 19271 | for (operands, 0..) |operand, i_usize| { |
| 19941 | 19272 | const i: u32 = @intCast(i_usize); |
| 19942 | const field_ptr_ty = try pt.ptrTypeSema(.{ | |
| 19273 | const field_ptr_ty = try pt.ptrType(.{ | |
| 19943 | 19274 | .child = types[i], |
| 19944 | 19275 | .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) }, |
| 19945 | 19276 | }); |
| ... | ... | @@ -19971,6 +19302,7 @@ fn zirFieldTypeRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro |
| 19971 | 19302 | const field_src = block.builtinCallArgSrc(inst_data.src_node, 1); |
| 19972 | 19303 | const aggregate_ty = try sema.resolveType(block, ty_src, extra.container_type); |
| 19973 | 19304 | const field_name = try sema.resolveConstStringIntern(block, field_src, extra.field_name, .{ .simple = .field_name }); |
| 19305 | try sema.ensureLayoutResolved(aggregate_ty); | |
| 19974 | 19306 | return sema.fieldType(block, aggregate_ty, field_name, field_src, ty_src); |
| 19975 | 19307 | } |
| 19976 | 19308 | |
| ... | ... | @@ -19990,9 +19322,11 @@ fn zirStructInitFieldType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp |
| 19990 | 19322 | const aggregate_ty = wrapped_aggregate_ty.optEuBaseType(zcu); |
| 19991 | 19323 | const zir_field_name = sema.code.nullTerminatedString(extra.name_start); |
| 19992 | 19324 | const field_name = try ip.getOrPutString(gpa, io, pt.tid, zir_field_name, .no_embedded_nulls); |
| 19325 | try sema.ensureLayoutResolved(aggregate_ty); | |
| 19993 | 19326 | return sema.fieldType(block, aggregate_ty, field_name, field_name_src, ty_src); |
| 19994 | 19327 | } |
| 19995 | 19328 | |
| 19329 | /// Asserts that the layout of `aggregate_ty` is resolved. | |
| 19996 | 19330 | fn fieldType( |
| 19997 | 19331 | sema: *Sema, |
| 19998 | 19332 | block: *Block, |
| ... | ... | @@ -20006,7 +19340,6 @@ fn fieldType( |
| 20006 | 19340 | const ip = &zcu.intern_pool; |
| 20007 | 19341 | var cur_ty = aggregate_ty; |
| 20008 | 19342 | while (true) { |
| 20009 | try cur_ty.resolveFields(pt); | |
| 20010 | 19343 | switch (cur_ty.zigTypeTag(zcu)) { |
| 20011 | 19344 | .@"struct" => switch (ip.indexToKey(cur_ty.toIntern())) { |
| 20012 | 19345 | .tuple_type => |tuple| { |
| ... | ... | @@ -20024,10 +19357,11 @@ fn fieldType( |
| 20024 | 19357 | }, |
| 20025 | 19358 | .@"union" => { |
| 20026 | 19359 | const union_obj = zcu.typeToUnion(cur_ty).?; |
| 20027 | const field_index = union_obj.loadTagType(ip).nameIndex(ip, field_name) orelse | |
| 19360 | const enum_obj = ip.loadEnumType(union_obj.enum_tag_type); | |
| 19361 | const field_index = enum_obj.nameIndex(ip, field_name) orelse | |
| 20028 | 19362 | return sema.failWithBadUnionFieldAccess(block, cur_ty, union_obj, field_src, field_name); |
| 20029 | 19363 | const field_ty = union_obj.field_types.get(ip)[field_index]; |
| 20030 | return Air.internedToRef(field_ty); | |
| 19364 | return .fromIntern(field_ty); | |
| 20031 | 19365 | }, |
| 20032 | 19366 | .optional => { |
| 20033 | 19367 | // Struct/array init through optional requires the child type to not be a pointer. |
| ... | ... | @@ -20056,7 +19390,6 @@ fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref { |
| 20056 | 19390 | const zcu = pt.zcu; |
| 20057 | 19391 | const ip = &zcu.intern_pool; |
| 20058 | 19392 | const stack_trace_ty = try sema.getBuiltinType(block.nodeOffset(.zero), .StackTrace); |
| 20059 | try stack_trace_ty.resolveFields(pt); | |
| 20060 | 19393 | const ptr_stack_trace_ty = try pt.singleMutPtrType(stack_trace_ty); |
| 20061 | 19394 | const opt_ptr_stack_trace_ty = try pt.optionalType(ptr_stack_trace_ty.toIntern()); |
| 20062 | 19395 | |
| ... | ... | @@ -20064,7 +19397,7 @@ fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref { |
| 20064 | 19397 | .func => |func| if (ip.funcAnalysisUnordered(func).has_error_trace and block.ownerModule().error_tracing) { |
| 20065 | 19398 | return block.addTy(.err_return_trace, opt_ptr_stack_trace_ty); |
| 20066 | 19399 | }, |
| 20067 | .@"comptime", .nav_ty, .nav_val, .type, .memoized_state => {}, | |
| 19400 | .@"comptime", .nav_ty, .nav_val, .type_layout, .type_inits, .memoized_state => {}, | |
| 20068 | 19401 | } |
| 20069 | 19402 | return Air.internedToRef(try pt.intern(.{ .opt = .{ |
| 20070 | 19403 | .ty = opt_ptr_stack_trace_ty.toIntern(), |
| ... | ... | @@ -20083,15 +19416,16 @@ fn zirFrame( |
| 20083 | 19416 | } |
| 20084 | 19417 | |
| 20085 | 19418 | fn zirAlignOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 20086 | const zcu = sema.pt.zcu; | |
| 19419 | const pt = sema.pt; | |
| 19420 | const zcu = pt.zcu; | |
| 20087 | 19421 | const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node; |
| 20088 | 19422 | const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0); |
| 20089 | 19423 | const ty = try sema.resolveType(block, operand_src, inst_data.operand); |
| 20090 | 19424 | if (ty.isNoReturn(zcu)) { |
| 20091 | 19425 | return sema.fail(block, operand_src, "no align available for type '{f}'", .{ty.fmt(sema.pt)}); |
| 20092 | 19426 | } |
| 20093 | const val = try ty.lazyAbiAlignment(sema.pt); | |
| 20094 | return Air.internedToRef(val.toIntern()); | |
| 19427 | try sema.ensureLayoutResolved(ty); | |
| 19428 | return .fromValue(try pt.intValue(.comptime_int, ty.abiAlignment(zcu).toByteUnits().?)); | |
| 20095 | 19429 | } |
| 20096 | 19430 | |
| 20097 | 19431 | fn zirIntFromBool(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -20249,7 +19583,6 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 20249 | 19583 | const pt = sema.pt; |
| 20250 | 19584 | const zcu = pt.zcu; |
| 20251 | 19585 | const ip = &zcu.intern_pool; |
| 20252 | try operand_ty.resolveLayout(pt); | |
| 20253 | 19586 | const enum_ty = switch (operand_ty.zigTypeTag(zcu)) { |
| 20254 | 19587 | .enum_literal => { |
| 20255 | 19588 | const val = (try sema.resolveDefinedValue(block, operand_src, operand)).?; |
| ... | ... | @@ -20332,7 +19665,7 @@ fn zirReifySliceArgTy( |
| 20332 | 19665 | // zig fmt: on |
| 20333 | 19666 | }; |
| 20334 | 19667 | |
| 20335 | const operand_ty = try pt.ptrTypeSema(.{ | |
| 19668 | const operand_ty = try pt.ptrType(.{ | |
| 20336 | 19669 | .child = in_scalar_ty.toIntern(), |
| 20337 | 19670 | .flags = .{ .size = .slice, .is_const = true }, |
| 20338 | 19671 | }); |
| ... | ... | @@ -20342,7 +19675,7 @@ fn zirReifySliceArgTy( |
| 20342 | 19675 | const operand_val = try sema.resolveConstDefinedValue(block, src, operand_coerced, .{ .simple = comptime_reason }); |
| 20343 | 19676 | const len_val: Value = .fromInterned(zcu.intern_pool.indexToKey(operand_val.toIntern()).slice.len); |
| 20344 | 19677 | if (len_val.isUndef(zcu)) return sema.failWithUseOfUndef(block, src, null); |
| 20345 | const len = try len_val.toUnsignedIntSema(pt); | |
| 19678 | const len = len_val.toUnsignedInt(zcu); | |
| 20346 | 19679 | |
| 20347 | 19680 | return .fromType(try pt.singleConstPtrType(try pt.arrayType(.{ |
| 20348 | 19681 | .len = len, |
| ... | ... | @@ -20370,7 +19703,7 @@ fn zirReifyEnumValueSliceTy( |
| 20370 | 19703 | const operand_val = try sema.resolveConstDefinedValue(block, field_names_src, operand_coerced, .{ .simple = .enum_field_names }); |
| 20371 | 19704 | const len_val: Value = .fromInterned(zcu.intern_pool.indexToKey(operand_val.toIntern()).slice.len); |
| 20372 | 19705 | if (len_val.isUndef(zcu)) return sema.failWithUseOfUndef(block, field_names_src, null); |
| 20373 | const len = try len_val.toUnsignedIntSema(pt); | |
| 19706 | const len = len_val.toUnsignedInt(zcu); | |
| 20374 | 19707 | |
| 20375 | 19708 | return .fromType(try pt.singleConstPtrType(try pt.arrayType(.{ |
| 20376 | 19709 | .len = len, |
| ... | ... | @@ -20422,6 +19755,7 @@ fn zirReifyTuple( |
| 20422 | 19755 | if (field_ty_val.isUndef(zcu)) { |
| 20423 | 19756 | return sema.failWithUseOfUndef(block, operand_src, null); |
| 20424 | 19757 | } |
| 19758 | try sema.validateTupleFieldType(block, field_ty_val.toType(), operand_src); | |
| 20425 | 19759 | field_ty.* = field_ty_val.toIntern(); |
| 20426 | 19760 | } |
| 20427 | 19761 | |
| ... | ... | @@ -20516,7 +19850,7 @@ fn zirReifyPointer( |
| 20516 | 19850 | } |
| 20517 | 19851 | } |
| 20518 | 19852 | |
| 20519 | return .fromType(try pt.ptrTypeSema(.{ | |
| 19853 | return .fromType(try pt.ptrType(.{ | |
| 20520 | 19854 | .child = elem_ty.toIntern(), |
| 20521 | 19855 | .sentinel = if (opt_sentinel) |s| s.toIntern() else .none, |
| 20522 | 19856 | .flags = .{ |
| ... | ... | @@ -20571,6 +19905,7 @@ fn zirReifyFn( |
| 20571 | 19905 | const param_attrs_arr = try sema.derefSliceAsArray(block, param_attrs_src, param_attrs_slice, .{ .simple = .fn_param_attrs }); |
| 20572 | 19906 | |
| 20573 | 19907 | const ret_ty = try sema.resolveType(block, ret_ty_src, extra.ret_ty); |
| 19908 | try sema.ensureLayoutResolved(ret_ty); | |
| 20574 | 19909 | |
| 20575 | 19910 | const fn_attrs_uncoerced = try sema.resolveInst(extra.fn_attrs); |
| 20576 | 19911 | const fn_attrs_coerced = try sema.coerce(block, fn_attrs_ty, fn_attrs_uncoerced, fn_attrs_src); |
| ... | ... | @@ -20595,7 +19930,8 @@ fn zirReifyFn( |
| 20595 | 19930 | param_types_src, |
| 20596 | 19931 | fn_attrs.@"callconv", |
| 20597 | 19932 | ); |
| 20598 | if (try param_ty.comptimeOnlySema(pt)) { | |
| 19933 | try sema.ensureLayoutResolved(param_ty); | |
| 19934 | if (param_ty.comptimeOnly(zcu)) { | |
| 20599 | 19935 | return sema.fail(block, param_attrs_src, "cannot reify function type with comptime-only parameter type '{f}'", .{param_ty.fmt(pt)}); |
| 20600 | 19936 | } |
| 20601 | 19937 | if (param_attrs.@"noalias") { |
| ... | ... | @@ -20621,7 +19957,7 @@ fn zirReifyFn( |
| 20621 | 19957 | false, |
| 20622 | 19958 | false, |
| 20623 | 19959 | ); |
| 20624 | if (try ret_ty.comptimeOnlySema(pt)) { | |
| 19960 | if (ret_ty.comptimeOnly(zcu)) { | |
| 20625 | 19961 | return sema.fail(block, param_attrs_src, "cannot reify function type with comptime-only return type '{f}'", .{ret_ty.fmt(pt)}); |
| 20626 | 19962 | } |
| 20627 | 19963 | |
| ... | ... | @@ -20632,7 +19968,6 @@ fn zirReifyFn( |
| 20632 | 19968 | .return_type = ret_ty.toIntern(), |
| 20633 | 19969 | .cc = fn_attrs.@"callconv", |
| 20634 | 19970 | .is_var_args = fn_attrs.varargs, |
| 20635 | .is_generic = false, | |
| 20636 | 19971 | .is_noinline = false, |
| 20637 | 19972 | })); |
| 20638 | 19973 | } |
| ... | ... | @@ -20791,8 +20126,7 @@ fn zirReifyStruct( |
| 20791 | 20126 | field_attrs_src, |
| 20792 | 20127 | .{ .simple = .struct_field_default_value }, |
| 20793 | 20128 | ); |
| 20794 | // Resolve the value so that lazy values do not create distinct types. | |
| 20795 | break :d (try sema.resolveLazyValue(deref_val)).toIntern(); | |
| 20129 | break :d deref_val.toIntern(); | |
| 20796 | 20130 | }; |
| 20797 | 20131 | |
| 20798 | 20132 | std.hash.autoHash(&hasher, .{ |
| ... | ... | @@ -20823,36 +20157,31 @@ fn zirReifyStruct( |
| 20823 | 20157 | } |
| 20824 | 20158 | |
| 20825 | 20159 | const wip_ty = switch (try ip.getStructType(gpa, io, pt.tid, .{ |
| 20826 | .layout = layout, | |
| 20827 | 20160 | .fields_len = @intCast(fields_len), |
| 20828 | .known_non_opv = false, | |
| 20829 | .requires_comptime = .unknown, | |
| 20161 | .layout = layout, | |
| 20162 | .explicit_packed_backing_type = if (backing_int_ty) |t| t.toIntern() else .none, | |
| 20830 | 20163 | .any_comptime_fields = any_comptime_fields, |
| 20831 | .any_default_inits = any_default_inits, | |
| 20832 | .any_aligned_fields = any_aligned_fields, | |
| 20833 | .inits_resolved = true, | |
| 20164 | .any_field_defaults = any_default_inits, | |
| 20165 | .any_field_aligns = any_aligned_fields, | |
| 20834 | 20166 | .key = .{ .reified = .{ |
| 20835 | 20167 | .zir_index = tracked_inst, |
| 20836 | 20168 | .type_hash = hasher.final(), |
| 20837 | 20169 | } }, |
| 20838 | }, false)) { | |
| 20170 | })) { | |
| 20839 | 20171 | .wip => |wip| wip, |
| 20840 | 20172 | .existing => |ty| { |
| 20841 | try sema.declareDependency(.{ .interned = ty }); | |
| 20842 | try sema.addTypeReferenceEntry(src, ty); | |
| 20843 | return Air.internedToRef(ty); | |
| 20173 | try sema.addTypeReferenceEntry(src, .fromInterned(ty)); | |
| 20174 | return .fromIntern(ty); | |
| 20844 | 20175 | }, |
| 20845 | 20176 | }; |
| 20846 | 20177 | errdefer wip_ty.cancel(ip, pt.tid); |
| 20847 | 20178 | |
| 20848 | const type_name = try sema.createTypeName( | |
| 20179 | _ = try (try sema.createTypeName( | |
| 20849 | 20180 | block, |
| 20850 | 20181 | name_strategy, |
| 20851 | 20182 | "struct", |
| 20852 | 20183 | inst, |
| 20853 | wip_ty.index, | |
| 20854 | ); | |
| 20855 | wip_ty.setName(ip, type_name.name, type_name.nav); | |
| 20184 | )).apply(&wip_ty, pt); | |
| 20856 | 20185 | |
| 20857 | 20186 | const wip_struct_type = ip.loadStructType(wip_ty.index); |
| 20858 | 20187 | |
| ... | ... | @@ -20860,15 +20189,9 @@ fn zirReifyStruct( |
| 20860 | 20189 | const field_name_val = try field_names_arr.elemValue(pt, field_idx); |
| 20861 | 20190 | const field_attrs_val = try field_attrs_arr.elemValue(pt, field_idx); |
| 20862 | 20191 | |
| 20863 | const field_ty = (try field_types_arr.elemValue(pt, field_idx)).toType(); | |
| 20864 | ||
| 20865 | 20192 | // Don't pass a reason; first loop acts as a check that this is valid. |
| 20866 | 20193 | const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, undefined); |
| 20867 | if (wip_struct_type.addFieldName(ip, field_name)) |prev_index| { | |
| 20868 | _ = prev_index; // TODO: better source location | |
| 20869 | return sema.fail(block, field_names_src, "duplicate struct field name {f}", .{field_name.fmt(ip)}); | |
| 20870 | } | |
| 20871 | ||
| 20194 | const field_ty = (try field_types_arr.elemValue(pt, field_idx)).toType(); | |
| 20872 | 20195 | const field_attr_comptime = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex( |
| 20873 | 20196 | std.builtin.Type.StructField.Attributes, |
| 20874 | 20197 | "comptime", |
| ... | ... | @@ -20882,14 +20205,9 @@ fn zirReifyStruct( |
| 20882 | 20205 | "default_value_ptr", |
| 20883 | 20206 | ).?); |
| 20884 | 20207 | |
| 20885 | if (field_attr_align.optionalValue(zcu)) |field_align_val| { | |
| 20886 | assert(layout != .@"packed"); | |
| 20887 | const bytes = try field_align_val.toUnsignedIntSema(pt); | |
| 20888 | const a = try sema.validateAlign(block, field_attrs_src, bytes); | |
| 20889 | wip_struct_type.field_aligns.get(ip)[field_idx] = a; | |
| 20890 | } else if (any_aligned_fields) { | |
| 20891 | assert(layout != .@"packed"); | |
| 20892 | wip_struct_type.field_aligns.get(ip)[field_idx] = .none; | |
| 20208 | if (wip_ty.nextField(ip, field_name, field_attr_comptime.toBool())) |prev_index| { | |
| 20209 | _ = prev_index; // TODO: better source location | |
| 20210 | return sema.fail(block, field_names_src, "duplicate struct field name {f}", .{field_name.fmt(ip)}); | |
| 20893 | 20211 | } |
| 20894 | 20212 | |
| 20895 | 20213 | const field_default: InternPool.Index = d: { |
| ... | ... | @@ -20902,20 +20220,11 @@ fn zirReifyStruct( |
| 20902 | 20220 | if (deref_val.canMutateComptimeVarState(zcu)) { |
| 20903 | 20221 | return sema.failWithContainsReferenceToComptimeVar(block, field_attrs_src, field_name, "field default value", deref_val); |
| 20904 | 20222 | } |
| 20905 | break :d (try sema.resolveLazyValue(deref_val)).toIntern(); | |
| 20223 | break :d deref_val.toIntern(); | |
| 20906 | 20224 | }; |
| 20907 | 20225 | |
| 20908 | if (field_attr_comptime.toBool()) { | |
| 20909 | assert(layout == .auto); | |
| 20910 | if (field_default == .none) { | |
| 20911 | return sema.fail(block, field_attrs_src, "comptime field without default initialization value", .{}); | |
| 20912 | } | |
| 20913 | wip_struct_type.setFieldComptime(ip, field_idx); | |
| 20914 | } | |
| 20915 | ||
| 20916 | wip_struct_type.field_types.get(ip)[field_idx] = field_ty.toIntern(); | |
| 20917 | if (field_default != .none) { | |
| 20918 | wip_struct_type.field_inits.get(ip)[field_idx] = field_default; | |
| 20226 | if (field_attr_comptime.toBool() and field_default == .none) { | |
| 20227 | return sema.fail(block, field_attrs_src, "comptime field without default initialization value", .{}); | |
| 20919 | 20228 | } |
| 20920 | 20229 | |
| 20921 | 20230 | switch (field_ty.zigTypeTag(zcu)) { |
| ... | ... | @@ -20945,32 +20254,55 @@ fn zirReifyStruct( |
| 20945 | 20254 | break :msg msg; |
| 20946 | 20255 | }); |
| 20947 | 20256 | }, |
| 20948 | .@"packed" => if (!try sema.validatePackedType(field_ty)) { | |
| 20257 | .@"packed" => if (!field_ty.packable(zcu)) { | |
| 20949 | 20258 | return sema.failWithOwnedErrorMsg(block, msg: { |
| 20950 | 20259 | const msg = try sema.errMsg(field_types_src, "packed structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); |
| 20951 | 20260 | errdefer msg.destroy(gpa); |
| 20952 | try sema.explainWhyTypeIsNotPacked(msg, field_types_src, field_ty); | |
| 20261 | try sema.explainWhyTypeIsNotPackable(msg, field_types_src, field_ty); | |
| 20953 | 20262 | try sema.addDeclaredHereNote(msg, field_ty); |
| 20954 | 20263 | break :msg msg; |
| 20955 | 20264 | }); |
| 20956 | 20265 | }, |
| 20957 | 20266 | } |
| 20267 | ||
| 20268 | wip_struct_type.field_types.get(ip)[field_idx] = field_ty.toIntern(); | |
| 20269 | if (field_default != .none) { | |
| 20270 | wip_struct_type.field_defaults.get(ip)[field_idx] = field_default; | |
| 20271 | } | |
| 20272 | ||
| 20273 | if (field_attr_align.optionalValue(zcu)) |field_align_val| { | |
| 20274 | assert(layout != .@"packed"); | |
| 20275 | const bytes = field_align_val.toUnsignedInt(zcu); | |
| 20276 | const a = try sema.validateAlign(block, field_attrs_src, bytes); | |
| 20277 | wip_struct_type.field_aligns.get(ip)[field_idx] = a; | |
| 20278 | } else if (any_aligned_fields) { | |
| 20279 | assert(layout != .@"packed"); | |
| 20280 | wip_struct_type.field_aligns.get(ip)[field_idx] = .none; | |
| 20281 | } | |
| 20958 | 20282 | } |
| 20959 | 20283 | |
| 20960 | 20284 | if (layout == .@"packed") { |
| 20961 | var fields_bit_sum: u64 = 0; | |
| 20962 | for (0..wip_struct_type.field_types.len) |field_idx| { | |
| 20285 | var field_bits: u64 = 0; | |
| 20286 | for (0..fields_len) |field_idx| { | |
| 20963 | 20287 | const field_ty: Type = .fromInterned(wip_struct_type.field_types.get(ip)[field_idx]); |
| 20964 | try field_ty.resolveLayout(pt); | |
| 20965 | fields_bit_sum += field_ty.bitSize(zcu); | |
| 20966 | } | |
| 20967 | if (backing_int_ty) |ty| { | |
| 20968 | try sema.checkBackingIntType(block, src, ty, fields_bit_sum); | |
| 20969 | wip_struct_type.setBackingIntType(ip, io, ty.toIntern()); | |
| 20970 | } else { | |
| 20971 | const ty = try pt.intType(.unsigned, @intCast(fields_bit_sum)); | |
| 20972 | wip_struct_type.setBackingIntType(ip, io, ty.toIntern()); | |
| 20288 | try sema.ensureLayoutResolved(field_ty); | |
| 20289 | field_bits += field_ty.bitSize(zcu); | |
| 20973 | 20290 | } |
| 20291 | try type_resolution.resolvePackedStructBackingInt( | |
| 20292 | sema, | |
| 20293 | block, | |
| 20294 | field_bits, | |
| 20295 | .fromInterned(wip_ty.index), | |
| 20296 | &wip_struct_type, | |
| 20297 | ); | |
| 20298 | } else { | |
| 20299 | try type_resolution.finishStructLayout( | |
| 20300 | sema, | |
| 20301 | block, | |
| 20302 | src, | |
| 20303 | wip_ty.index, | |
| 20304 | &wip_struct_type, | |
| 20305 | ); | |
| 20974 | 20306 | } |
| 20975 | 20307 | |
| 20976 | 20308 | const new_namespace_index = try pt.createNamespace(.{ |
| ... | ... | @@ -20980,16 +20312,13 @@ fn zirReifyStruct( |
| 20980 | 20312 | .generation = zcu.generation, |
| 20981 | 20313 | }); |
| 20982 | 20314 | |
| 20983 | try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index }); | |
| 20984 | 20315 | codegen_type: { |
| 20985 | 20316 | if (zcu.comp.config.use_llvm) break :codegen_type; |
| 20986 | 20317 | if (block.ownerModule().strip) break :codegen_type; |
| 20987 | // This job depends on any resolve_type_fully jobs queued up before it. | |
| 20988 | 20318 | zcu.comp.link_prog_node.increaseEstimatedTotalItems(1); |
| 20989 | 20319 | try zcu.comp.queueJob(.{ .link_type = wip_ty.index }); |
| 20990 | 20320 | } |
| 20991 | try sema.declareDependency(.{ .interned = wip_ty.index }); | |
| 20992 | try sema.addTypeReferenceEntry(src, wip_ty.index); | |
| 20321 | try sema.addTypeReferenceEntry(src, .fromInterned(wip_ty.index)); | |
| 20993 | 20322 | if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index); |
| 20994 | 20323 | return .fromIntern(wip_ty.finish(ip, new_namespace_index)); |
| 20995 | 20324 | } |
| ... | ... | @@ -21134,62 +20463,52 @@ fn zirReifyUnion( |
| 21134 | 20463 | } |
| 21135 | 20464 | |
| 21136 | 20465 | // Some basic validation to avoid a bogus `getUnionType` call... |
| 21137 | const explicit_tag_ty: ?Type = if (arg_ty_val.optionalValue(zcu)) |arg_ty| ty: { | |
| 20466 | const explicit_tag_ty: ?Type, const explicit_packed_backing_type: ?Type = ty: { | |
| 20467 | const arg_ty = arg_ty_val.optionalValue(zcu) orelse break :ty .{ null, null }; | |
| 21138 | 20468 | switch (layout) { |
| 21139 | .@"extern", .@"packed" => return sema.fail(block, arg_ty_src, "{t} union does not support enum tag type", .{layout}), | |
| 21140 | .auto => {}, | |
| 20469 | .@"extern" => return sema.fail(block, arg_ty_src, "extern union does not support enum tag type", .{}), | |
| 20470 | .@"packed" => break :ty .{ null, arg_ty.toType() }, | |
| 20471 | .auto => break :ty .{ arg_ty.toType(), null }, | |
| 21141 | 20472 | } |
| 21142 | break :ty arg_ty.toType(); | |
| 21143 | } else null; | |
| 20473 | }; | |
| 21144 | 20474 | if (any_aligned_fields and layout == .@"packed") { |
| 21145 | 20475 | return sema.fail(block, field_attrs_src, "packed union fields cannot be aligned", .{}); |
| 21146 | 20476 | } |
| 21147 | 20477 | |
| 21148 | 20478 | const wip_ty = switch (try ip.getUnionType(gpa, io, pt.tid, .{ |
| 21149 | .flags = .{ | |
| 21150 | .layout = layout, | |
| 21151 | .status = .none, | |
| 21152 | .runtime_tag = rt: { | |
| 21153 | if (explicit_tag_ty != null) break :rt .tagged; | |
| 21154 | if (layout == .auto and block.wantSafeTypes()) break :rt .safety; | |
| 21155 | break :rt .none; | |
| 21156 | }, | |
| 21157 | .any_aligned_fields = any_aligned_fields, | |
| 21158 | .requires_comptime = .unknown, | |
| 21159 | .assumed_runtime_bits = false, | |
| 21160 | .assumed_pointer_aligned = false, | |
| 21161 | .alignment = .none, | |
| 21162 | }, | |
| 21163 | 20479 | .fields_len = @intCast(fields_len), |
| 21164 | .enum_tag_ty = .none, // set later because not yet validated | |
| 21165 | .field_types = &.{}, // set later | |
| 21166 | .field_aligns = &.{}, // set later | |
| 20480 | .layout = layout, | |
| 20481 | .explicit_packed_backing_type = if (explicit_packed_backing_type) |t| t.toIntern() else .none, | |
| 20482 | .runtime_tag = rt: { | |
| 20483 | if (explicit_tag_ty != null) break :rt .tagged; | |
| 20484 | if (layout == .auto and block.wantSafeTypes()) break :rt .safety; | |
| 20485 | break :rt .none; | |
| 20486 | }, | |
| 20487 | .have_explicit_enum_tag = explicit_tag_ty != null, | |
| 20488 | .any_field_aligns = any_aligned_fields, | |
| 21167 | 20489 | .key = .{ .reified = .{ |
| 21168 | 20490 | .zir_index = tracked_inst, |
| 21169 | 20491 | .type_hash = hasher.final(), |
| 21170 | 20492 | } }, |
| 21171 | }, false)) { | |
| 20493 | })) { | |
| 21172 | 20494 | .wip => |wip| wip, |
| 21173 | 20495 | .existing => |ty| { |
| 21174 | try sema.declareDependency(.{ .interned = ty }); | |
| 21175 | try sema.addTypeReferenceEntry(src, ty); | |
| 21176 | return Air.internedToRef(ty); | |
| 20496 | try sema.addTypeReferenceEntry(src, .fromInterned(ty)); | |
| 20497 | return .fromIntern(ty); | |
| 21177 | 20498 | }, |
| 21178 | 20499 | }; |
| 21179 | 20500 | errdefer wip_ty.cancel(ip, pt.tid); |
| 21180 | 20501 | |
| 21181 | const type_name = try sema.createTypeName( | |
| 20502 | const type_name = try (try sema.createTypeName( | |
| 21182 | 20503 | block, |
| 21183 | 20504 | name_strategy, |
| 21184 | 20505 | "union", |
| 21185 | 20506 | inst, |
| 21186 | wip_ty.index, | |
| 21187 | ); | |
| 21188 | wip_ty.setName(ip, type_name.name, type_name.nav); | |
| 20507 | )).apply(&wip_ty, pt); | |
| 21189 | 20508 | |
| 21190 | 20509 | const loaded_union = ip.loadUnionType(wip_ty.index); |
| 21191 | 20510 | |
| 21192 | const enum_tag_ty, const has_explicit_tag = if (explicit_tag_ty) |enum_tag_ty| tag: { | |
| 20511 | const generated_tag_ty: InternPool.Index = if (explicit_tag_ty) |enum_tag_ty| generated_tag: { | |
| 21193 | 20512 | if (enum_tag_ty.zigTypeTag(zcu) != .@"enum") { |
| 21194 | 20513 | return sema.fail(block, arg_ty_src, "tag type must be an enum type", .{}); |
| 21195 | 20514 | } |
| ... | ... | @@ -21227,26 +20546,67 @@ fn zirReifyUnion( |
| 21227 | 20546 | try sema.addDeclaredHereNote(msg, enum_tag_ty); |
| 21228 | 20547 | break :msg msg; |
| 21229 | 20548 | }); |
| 21230 | break :tag .{ enum_tag_ty.toIntern(), true }; | |
| 21231 | } else tag: { | |
| 21232 | // We must track field names and set up the tag type ourselves. | |
| 21233 | var field_names: std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void) = .empty; | |
| 21234 | try field_names.ensureTotalCapacity(sema.arena, fields_len); | |
| 20549 | wip_ty.setTagType(ip, enum_tag_ty.toIntern()); | |
| 20550 | break :generated_tag .none; | |
| 20551 | } else generated_tag: { | |
| 20552 | // Generate the union's hypothetical tag type. | |
| 20553 | const wip_tag_ty = switch (try ip.getEnumType(gpa, io, pt.tid, .{ | |
| 20554 | .fields_len = @intCast(fields_len), | |
| 20555 | .explicit_int_tag_type = .none, | |
| 20556 | .nonexhaustive = false, | |
| 20557 | .key = .{ .generated_union_tag = wip_ty.index }, | |
| 20558 | })) { | |
| 20559 | .existing => unreachable, // enum type is keyed on this union type which we're only just creating | |
| 20560 | .wip => |wip_tag_ty| wip_tag_ty, | |
| 20561 | }; | |
| 20562 | errdefer wip_tag_ty.cancel(ip, pt.tid); | |
| 21235 | 20563 | |
| 20564 | // Set its name based on the union's name | |
| 20565 | _ = wip_tag_ty.setName(ip, try ip.getOrPutStringFmt( | |
| 20566 | gpa, | |
| 20567 | io, | |
| 20568 | pt.tid, | |
| 20569 | "@typeInfo({f}).@\"union\".tag_type.?", | |
| 20570 | .{type_name.fmt(ip)}, | |
| 20571 | .no_embedded_nulls, | |
| 20572 | ), .none); | |
| 20573 | ||
| 20574 | // Populate its fields (and report any duplicates) | |
| 21236 | 20575 | for (0..fields_len) |field_idx| { |
| 21237 | 20576 | const field_name_val = try field_names_arr.elemValue(pt, field_idx); |
| 21238 | 20577 | // Don't pass a reason; first loop acts as a check that this is valid. |
| 21239 | 20578 | const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, undefined); |
| 21240 | const gop = field_names.getOrPutAssumeCapacity(field_name); | |
| 21241 | if (gop.found_existing) { | |
| 21242 | // TODO: better source location | |
| 21243 | return sema.fail(block, field_names_src, "duplicate union field {f}", .{field_name.fmt(ip)}); | |
| 21244 | } | |
| 20579 | if (wip_tag_ty.nextField(ip, field_name, false)) |prev_field_idx| return sema.failWithOwnedErrorMsg(block, msg: { | |
| 20580 | const msg = try sema.errMsg(src, "duplicate union field '{f}' at index '{d}", .{ field_name.fmt(ip), field_idx }); | |
| 20581 | errdefer msg.destroy(gpa); | |
| 20582 | try sema.errNote(src, msg, "previous field at index '{d}'", .{prev_field_idx}); | |
| 20583 | break :msg msg; | |
| 20584 | }); | |
| 21245 | 20585 | } |
| 21246 | const enum_tag_ty = try sema.generateUnionTagTypeSimple(block, field_names.keys(), wip_ty.index, type_name.name); | |
| 21247 | break :tag .{ enum_tag_ty, false }; | |
| 20586 | ||
| 20587 | // Populate the enum tag type's *integer* tag type | |
| 20588 | wip_tag_ty.setTagType(ip, int_tag_ty: { | |
| 20589 | // Infer the int tag type from the field count | |
| 20590 | const bits = Type.smallestUnsignedBits(fields_len -| 1); | |
| 20591 | break :int_tag_ty (try pt.intType(.unsigned, bits)).toIntern(); | |
| 20592 | }); | |
| 20593 | ||
| 20594 | // Lastly, it needs a dummy namespace | |
| 20595 | const enum_tag_type_namespace = try pt.createNamespace(.{ | |
| 20596 | .parent = block.namespace.toOptional(), | |
| 20597 | .owner_type = wip_tag_ty.index, | |
| 20598 | .file_scope = block.getFileScopeIndex(zcu), | |
| 20599 | .generation = zcu.generation, | |
| 20600 | }); | |
| 20601 | errdefer pt.destroyNamespace(enum_tag_type_namespace); | |
| 20602 | ||
| 20603 | wip_ty.setTagType(ip, wip_tag_ty.index); | |
| 20604 | ||
| 20605 | break :generated_tag wip_tag_ty.finish(ip, enum_tag_type_namespace); | |
| 21248 | 20606 | }; |
| 21249 | errdefer if (!has_explicit_tag) ip.remove(pt.tid, enum_tag_ty); // remove generated tag type on error | |
| 20607 | // If we fail to create the union type, we must delete the generated enum tag type, since it | |
| 20608 | // would hold a reference to the deleted union. | |
| 20609 | errdefer if (generated_tag_ty != .none) ip.remove(pt.tid, generated_tag_ty); | |
| 21250 | 20610 | |
| 21251 | 20611 | for (0..fields_len) |field_idx| { |
| 21252 | 20612 | const field_ty = (try field_types_arr.elemValue(pt, field_idx)).toType(); |
| ... | ... | @@ -21279,12 +20639,12 @@ fn zirReifyUnion( |
| 21279 | 20639 | break :msg msg; |
| 21280 | 20640 | }); |
| 21281 | 20641 | }, |
| 21282 | .@"packed" => if (!try sema.validatePackedType(field_ty)) { | |
| 20642 | .@"packed" => if (!field_ty.packable(zcu)) { | |
| 21283 | 20643 | return sema.failWithOwnedErrorMsg(block, msg: { |
| 21284 | 20644 | const msg = try sema.errMsg(field_types_src, "packed unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); |
| 21285 | 20645 | errdefer msg.destroy(gpa); |
| 21286 | 20646 | |
| 21287 | try sema.explainWhyTypeIsNotPacked(msg, field_types_src, field_ty); | |
| 20647 | try sema.explainWhyTypeIsNotPackable(msg, field_types_src, field_ty); | |
| 21288 | 20648 | |
| 21289 | 20649 | try sema.addDeclaredHereNote(msg, field_ty); |
| 21290 | 20650 | break :msg msg; |
| ... | ... | @@ -21303,8 +20663,24 @@ fn zirReifyUnion( |
| 21303 | 20663 | } |
| 21304 | 20664 | } |
| 21305 | 20665 | |
| 21306 | loaded_union.setTagType(ip, io, enum_tag_ty); | |
| 21307 | loaded_union.setStatus(ip, io, .have_field_types); | |
| 20666 | if (layout == .@"packed") { | |
| 20667 | try type_resolution.resolvePackedUnionBackingInt( | |
| 20668 | sema, | |
| 20669 | block, | |
| 20670 | .fromInterned(wip_ty.index), | |
| 20671 | &loaded_union, | |
| 20672 | true, | |
| 20673 | ); | |
| 20674 | } else { | |
| 20675 | try type_resolution.finishUnionLayout( | |
| 20676 | sema, | |
| 20677 | block, | |
| 20678 | src, | |
| 20679 | wip_ty.index, | |
| 20680 | &loaded_union, | |
| 20681 | explicit_tag_ty orelse .fromInterned(generated_tag_ty), | |
| 20682 | ); | |
| 20683 | } | |
| 21308 | 20684 | |
| 21309 | 20685 | const new_namespace_index = try pt.createNamespace(.{ |
| 21310 | 20686 | .parent = block.namespace.toOptional(), |
| ... | ... | @@ -21313,17 +20689,16 @@ fn zirReifyUnion( |
| 21313 | 20689 | .generation = zcu.generation, |
| 21314 | 20690 | }); |
| 21315 | 20691 | |
| 21316 | try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index }); | |
| 21317 | 20692 | codegen_type: { |
| 21318 | 20693 | if (zcu.comp.config.use_llvm) break :codegen_type; |
| 21319 | 20694 | if (block.ownerModule().strip) break :codegen_type; |
| 21320 | // This job depends on any resolve_type_fully jobs queued up before it. | |
| 21321 | 20695 | zcu.comp.link_prog_node.increaseEstimatedTotalItems(1); |
| 21322 | 20696 | try zcu.comp.queueJob(.{ .link_type = wip_ty.index }); |
| 21323 | 20697 | } |
| 21324 | try sema.declareDependency(.{ .interned = wip_ty.index }); | |
| 21325 | try sema.addTypeReferenceEntry(src, wip_ty.index); | |
| 21326 | if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index); | |
| 20698 | try sema.addTypeReferenceEntry(src, .fromInterned(wip_ty.index)); | |
| 20699 | if (zcu.comp.debugIncremental()) { | |
| 20700 | try zcu.incremental_debug_state.newType(zcu, wip_ty.index); | |
| 20701 | } | |
| 21327 | 20702 | return .fromIntern(wip_ty.finish(ip, new_namespace_index)); |
| 21328 | 20703 | } |
| 21329 | 20704 | |
| ... | ... | @@ -21436,86 +20811,84 @@ fn zirReifyEnum( |
| 21436 | 20811 | } |
| 21437 | 20812 | |
| 21438 | 20813 | const wip_ty = switch (try ip.getEnumType(gpa, io, pt.tid, .{ |
| 21439 | .has_values = true, | |
| 21440 | .tag_mode = if (nonexhaustive) .nonexhaustive else .explicit, | |
| 21441 | 20814 | .fields_len = @intCast(fields_len), |
| 20815 | .explicit_int_tag_type = tag_ty.toIntern(), | |
| 20816 | .nonexhaustive = nonexhaustive, | |
| 21442 | 20817 | .key = .{ .reified = .{ |
| 21443 | 20818 | .zir_index = tracked_inst, |
| 21444 | 20819 | .type_hash = hasher.final(), |
| 21445 | 20820 | } }, |
| 21446 | }, false)) { | |
| 20821 | })) { | |
| 21447 | 20822 | .wip => |wip| wip, |
| 21448 | 20823 | .existing => |ty| { |
| 21449 | try sema.declareDependency(.{ .interned = ty }); | |
| 21450 | try sema.addTypeReferenceEntry(src, ty); | |
| 20824 | try sema.addTypeReferenceEntry(src, .fromInterned(ty)); | |
| 21451 | 20825 | return .fromIntern(ty); |
| 21452 | 20826 | }, |
| 21453 | 20827 | }; |
| 21454 | var done = false; | |
| 21455 | errdefer if (!done) wip_ty.cancel(ip, pt.tid); | |
| 20828 | errdefer wip_ty.cancel(ip, pt.tid); | |
| 21456 | 20829 | |
| 21457 | const type_name = try sema.createTypeName( | |
| 20830 | _ = try (try sema.createTypeName( | |
| 21458 | 20831 | block, |
| 21459 | 20832 | name_strategy, |
| 21460 | 20833 | "enum", |
| 21461 | 20834 | inst, |
| 21462 | wip_ty.index, | |
| 21463 | ); | |
| 21464 | wip_ty.setName(ip, type_name.name, type_name.nav); | |
| 21465 | ||
| 21466 | const new_namespace_index = try pt.createNamespace(.{ | |
| 21467 | .parent = block.namespace.toOptional(), | |
| 21468 | .owner_type = wip_ty.index, | |
| 21469 | .file_scope = block.getFileScopeIndex(zcu), | |
| 21470 | .generation = zcu.generation, | |
| 21471 | }); | |
| 21472 | ||
| 21473 | try sema.declareDependency(.{ .interned = wip_ty.index }); | |
| 21474 | try sema.addTypeReferenceEntry(src, wip_ty.index); | |
| 21475 | if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index); | |
| 21476 | wip_ty.prepare(ip, new_namespace_index); | |
| 21477 | wip_ty.setTagTy(ip, tag_ty.toIntern()); | |
| 21478 | done = true; | |
| 20835 | )).apply(&wip_ty, pt); | |
| 21479 | 20836 | |
| 21480 | 20837 | for (0..fields_len) |field_idx| { |
| 21481 | 20838 | const field_name_val = try field_names_arr.elemValue(pt, field_idx); |
| 21482 | 20839 | // Don't pass a reason; first loop acts as a check that this is valid. |
| 21483 | 20840 | const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, undefined); |
| 20841 | if (wip_ty.nextField(ip, field_name, false)) |prev_field_idx| return sema.failWithOwnedErrorMsg(block, msg: { | |
| 20842 | const msg = try sema.errMsg(field_names_src, "duplicate enum field '{f}' at index '{d}'", .{ field_name.fmt(ip), field_idx }); | |
| 20843 | errdefer msg.destroy(gpa); | |
| 20844 | try sema.errNote(field_names_src, msg, "previous field at index '{d}'", .{prev_field_idx}); | |
| 20845 | break :msg msg; | |
| 20846 | }); | |
| 20847 | } | |
| 21484 | 20848 | |
| 20849 | const enum_obj = ip.loadEnumType(wip_ty.index); | |
| 20850 | const field_value_map = enum_obj.field_value_map.unwrap().?; | |
| 20851 | for (0..fields_len) |field_idx| { | |
| 21485 | 20852 | const field_val = try field_values_arr.elemValue(pt, field_idx); |
| 21486 | ||
| 21487 | if (wip_ty.nextField(ip, field_name, field_val.toIntern())) |conflict| { | |
| 21488 | return sema.failWithOwnedErrorMsg(block, switch (conflict.kind) { | |
| 21489 | .name => msg: { | |
| 21490 | const msg = try sema.errMsg(field_names_src, "duplicate enum field '{f}'", .{field_name.fmt(ip)}); | |
| 21491 | errdefer msg.destroy(gpa); | |
| 21492 | _ = conflict.prev_field_idx; // TODO: this note is incorrect | |
| 21493 | try sema.errNote(field_names_src, msg, "other field here", .{}); | |
| 21494 | break :msg msg; | |
| 21495 | }, | |
| 21496 | .value => msg: { | |
| 21497 | const msg = try sema.errMsg(field_values_src, "enum tag value {f} already taken", .{field_val.fmtValueSema(pt, sema)}); | |
| 21498 | errdefer msg.destroy(gpa); | |
| 21499 | _ = conflict.prev_field_idx; // TODO: this note is incorrect | |
| 21500 | try sema.errNote(field_values_src, msg, "other enum tag value here", .{}); | |
| 21501 | break :msg msg; | |
| 21502 | }, | |
| 20853 | const field_values = enum_obj.field_values.get(ip); | |
| 20854 | field_values[field_idx] = field_val.toIntern(); | |
| 20855 | const adapter: InternPool.Index.Adapter = .{ .indexes = field_values[0..field_idx] }; | |
| 20856 | const gop = field_value_map.get(ip).getOrPutAssumeCapacityAdapted(field_val.toIntern(), adapter); | |
| 20857 | if (gop.found_existing) return sema.failWithOwnedErrorMsg(block, msg: { | |
| 20858 | const field_names = enum_obj.field_names.get(ip); | |
| 20859 | const this_field_name = field_names[field_idx]; | |
| 20860 | const prev_field_name = field_names[gop.index]; | |
| 20861 | const msg = try sema.errMsg(field_names_src, "duplicate enum tag value '{f}' in field '{f}'", .{ | |
| 20862 | field_val.fmtValueSema(pt, sema), | |
| 20863 | this_field_name.fmt(ip), | |
| 21503 | 20864 | }); |
| 21504 | } | |
| 20865 | errdefer msg.destroy(gpa); | |
| 20866 | try sema.errNote(field_names_src, msg, "previous usage in field '{f}'", .{prev_field_name.fmt(ip)}); | |
| 20867 | break :msg msg; | |
| 20868 | }); | |
| 21505 | 20869 | } |
| 21506 | 20870 | |
| 21507 | 20871 | if (nonexhaustive and fields_len > 1 and std.math.log2_int(u64, fields_len) == tag_ty.bitSize(zcu)) { |
| 21508 | 20872 | return sema.fail(block, src, "non-exhaustive enum specified every value", .{}); |
| 21509 | 20873 | } |
| 21510 | 20874 | |
| 20875 | const new_namespace_index = try pt.createNamespace(.{ | |
| 20876 | .parent = block.namespace.toOptional(), | |
| 20877 | .owner_type = wip_ty.index, | |
| 20878 | .file_scope = block.getFileScopeIndex(zcu), | |
| 20879 | .generation = zcu.generation, | |
| 20880 | }); | |
| 20881 | ||
| 21511 | 20882 | codegen_type: { |
| 21512 | 20883 | if (zcu.comp.config.use_llvm) break :codegen_type; |
| 21513 | 20884 | if (block.ownerModule().strip) break :codegen_type; |
| 21514 | // This job depends on any resolve_type_fully jobs queued up before it. | |
| 21515 | 20885 | zcu.comp.link_prog_node.increaseEstimatedTotalItems(1); |
| 21516 | 20886 | try zcu.comp.queueJob(.{ .link_type = wip_ty.index }); |
| 21517 | 20887 | } |
| 21518 | return Air.internedToRef(wip_ty.index); | |
| 20888 | ||
| 20889 | try sema.addTypeReferenceEntry(src, .fromInterned(wip_ty.index)); | |
| 20890 | if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index); | |
| 20891 | return .fromIntern(wip_ty.finish(ip, new_namespace_index)); | |
| 21519 | 20892 | } |
| 21520 | 20893 | |
| 21521 | 20894 | fn resolveVaListRef(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -21573,7 +20946,8 @@ fn zirCVaEnd(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) C |
| 21573 | 20946 | const va_list_ref = try sema.resolveVaListRef(block, va_list_src, extra.operand); |
| 21574 | 20947 | |
| 21575 | 20948 | try sema.requireRuntimeBlock(block, src, null); |
| 21576 | return block.addUnOp(.c_va_end, va_list_ref); | |
| 20949 | _ = try block.addUnOp(.c_va_end, va_list_ref); | |
| 20950 | return .void_value; | |
| 21577 | 20951 | } |
| 21578 | 20952 | |
| 21579 | 20953 | fn zirCVaStart(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -21683,8 +21057,20 @@ fn zirFloatFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro |
| 21683 | 21057 | _ = try sema.checkIntType(block, operand_src, operand_scalar_ty); |
| 21684 | 21058 | |
| 21685 | 21059 | if (try sema.resolveValue(operand)) |operand_val| { |
| 21686 | const result_val = try operand_val.floatFromIntAdvanced(sema.arena, operand_ty, dest_ty, pt, .sema); | |
| 21687 | return Air.internedToRef(result_val.toIntern()); | |
| 21060 | if (operand_val.isUndef(zcu)) return .fromValue(try pt.undefValue(dest_ty)); | |
| 21061 | if (dest_ty.zigTypeTag(zcu) != .vector) { | |
| 21062 | return .fromValue(try pt.floatValue(dest_ty, operand_val.toFloat(f128, zcu))); | |
| 21063 | } | |
| 21064 | const dest_elems = try sema.arena.alloc(InternPool.Index, dest_ty.vectorLen(zcu)); | |
| 21065 | for (dest_elems, 0..) |*out_elem, elem_idx| { | |
| 21066 | const orig_elem = try operand_val.elemValue(pt, elem_idx); | |
| 21067 | const casted_elem = if (orig_elem.isUndef(zcu)) | |
| 21068 | try pt.undefValue(dest_scalar_ty) | |
| 21069 | else | |
| 21070 | try pt.floatValue(dest_scalar_ty, orig_elem.toFloat(f128, zcu)); | |
| 21071 | out_elem.* = casted_elem.toIntern(); | |
| 21072 | } | |
| 21073 | return .fromValue(try pt.aggregateValue(dest_ty, dest_elems)); | |
| 21688 | 21074 | } else if (dest_scalar_ty.zigTypeTag(zcu) == .comptime_float) { |
| 21689 | 21075 | return sema.failWithNeededComptime(block, operand_src, .{ .simple = .casted_to_comptime_float }); |
| 21690 | 21076 | } |
| ... | ... | @@ -21719,8 +21105,11 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! |
| 21719 | 21105 | const ptr_ty = dest_ty.scalarType(zcu); |
| 21720 | 21106 | try sema.checkPtrType(block, src, ptr_ty, true); |
| 21721 | 21107 | |
| 21722 | const elem_ty = ptr_ty.elemType2(zcu); | |
| 21723 | const ptr_align = try ptr_ty.ptrAlignmentSema(pt); | |
| 21108 | const elem_ty = ptr_ty.nullablePtrElem(zcu); | |
| 21109 | ||
| 21110 | // We'll need to validate the pointer alignment. | |
| 21111 | try sema.ensureLayoutResolved(elem_ty); | |
| 21112 | const ptr_align = ptr_ty.ptrAlignment(zcu); | |
| 21724 | 21113 | |
| 21725 | 21114 | if (ptr_ty.isSlice(zcu)) { |
| 21726 | 21115 | const msg = msg: { |
| ... | ... | @@ -21746,18 +21135,9 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! |
| 21746 | 21135 | } |
| 21747 | 21136 | return Air.internedToRef((try pt.aggregateValue(dest_ty, new_elems)).toIntern()); |
| 21748 | 21137 | } |
| 21749 | if (try ptr_ty.comptimeOnlySema(pt)) { | |
| 21750 | return sema.failWithOwnedErrorMsg(block, msg: { | |
| 21751 | const msg = try sema.errMsg(src, "pointer to comptime-only type '{f}' must be comptime-known, but operand is runtime-known", .{ptr_ty.fmt(pt)}); | |
| 21752 | errdefer msg.destroy(sema.gpa); | |
| 21753 | ||
| 21754 | try sema.explainWhyTypeIsComptime(msg, src, ptr_ty); | |
| 21755 | break :msg msg; | |
| 21756 | }); | |
| 21757 | } | |
| 21758 | 21138 | try sema.requireRuntimeBlock(block, src, operand_src); |
| 21759 | 21139 | try sema.checkLogicalPtrOperation(block, src, ptr_ty); |
| 21760 | if (block.wantSafety() and (try elem_ty.hasRuntimeBitsSema(pt) or elem_ty.zigTypeTag(zcu) == .@"fn")) { | |
| 21140 | if (block.wantSafety()) { | |
| 21761 | 21141 | if (!ptr_ty.isAllowzeroPtr(zcu)) { |
| 21762 | 21142 | const is_non_zero = if (is_vector) all_non_zero: { |
| 21763 | 21143 | const zero_usize = Air.internedToRef((try sema.splat(operand_ty, .zero_usize)).toIntern()); |
| ... | ... | @@ -21804,7 +21184,7 @@ fn ptrFromIntVal( |
| 21804 | 21184 | } |
| 21805 | 21185 | return sema.failWithUseOfUndef(block, operand_src, vec_idx); |
| 21806 | 21186 | } |
| 21807 | const addr = try operand_val.toUnsignedIntSema(pt); | |
| 21187 | const addr = operand_val.toUnsignedInt(zcu); | |
| 21808 | 21188 | if (!ptr_ty.isAllowzeroPtr(zcu) and addr == 0) |
| 21809 | 21189 | return sema.fail(block, operand_src, "pointer type '{f}' does not allow address zero", .{ptr_ty.fmt(pt)}); |
| 21810 | 21190 | if (addr != 0 and ptr_align != .none) { |
| ... | ... | @@ -22043,8 +21423,8 @@ fn ptrCastFull( |
| 22043 | 21423 | const src_info = operand_ty.ptrInfo(zcu); |
| 22044 | 21424 | const dest_info = dest_ty.ptrInfo(zcu); |
| 22045 | 21425 | |
| 22046 | try Type.fromInterned(src_info.child).resolveLayout(pt); | |
| 22047 | try Type.fromInterned(dest_info.child).resolveLayout(pt); | |
| 21426 | try sema.ensureLayoutResolved(.fromInterned(src_info.child)); | |
| 21427 | try sema.ensureLayoutResolved(.fromInterned(dest_info.child)); | |
| 22048 | 21428 | |
| 22049 | 21429 | const DestSliceLen = union(enum) { |
| 22050 | 21430 | undef, |
| ... | ... | @@ -22079,9 +21459,9 @@ fn ptrCastFull( |
| 22079 | 21459 | .pointer => operand_val, |
| 22080 | 21460 | else => unreachable, |
| 22081 | 21461 | }; |
| 22082 | const slice_len_resolved = try sema.resolveLazyValue(.fromInterned(zcu.intern_pool.sliceLen(slice_val.toIntern()))); | |
| 22083 | if (slice_len_resolved.isUndef(zcu)) break :len .undef; | |
| 22084 | break :src .{ .fromInterned(src_info.child), slice_len_resolved.toUnsignedInt(zcu) }; | |
| 21462 | const slice_len: Value = .fromInterned(zcu.intern_pool.sliceLen(slice_val.toIntern())); | |
| 21463 | if (slice_len.isUndef(zcu)) break :len .undef; | |
| 21464 | break :src .{ .fromInterned(src_info.child), slice_len.toUnsignedInt(zcu) }; | |
| 22085 | 21465 | }, |
| 22086 | 21466 | .many, .c => { |
| 22087 | 21467 | return sema.fail(block, src, "cannot infer length of slice from {s}", .{pointerSizeString(src_info.flags.size)}); |
| ... | ... | @@ -22395,7 +21775,7 @@ fn ptrCastFull( |
| 22395 | 21775 | }; |
| 22396 | 21776 | |
| 22397 | 21777 | if (dest_align.compare(.gt, src_align)) { |
| 22398 | if (try ptr_val.getUnsignedIntSema(pt)) |addr| { | |
| 21778 | if (ptr_val.getUnsignedInt(zcu)) |addr| { | |
| 22399 | 21779 | const masked_addr = if (Type.fromInterned(dest_info.child).fnPtrMaskOrNull(zcu)) |mask| |
| 22400 | 21780 | addr & mask |
| 22401 | 21781 | else |
| ... | ... | @@ -22464,7 +21844,7 @@ fn ptrCastFull( |
| 22464 | 21844 | // Now, do an addrspace cast if necessary! |
| 22465 | 21845 | if (!flags.addrspace_cast) break :ptr pre_addrspace_cast; |
| 22466 | 21846 | |
| 22467 | const intermediate_ptr_ty = try pt.ptrTypeSema(info: { | |
| 21847 | const intermediate_ptr_ty = try pt.ptrType(info: { | |
| 22468 | 21848 | var info = src_info; |
| 22469 | 21849 | info.flags.address_space = dest_info.flags.address_space; |
| 22470 | 21850 | break :info info; |
| ... | ... | @@ -22638,7 +22018,7 @@ fn zirPtrCastNoDest(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst |
| 22638 | 22018 | if (flags.volatile_cast) ptr_info.flags.is_volatile = false; |
| 22639 | 22019 | |
| 22640 | 22020 | const dest_ty = blk: { |
| 22641 | const dest_ty = try pt.ptrTypeSema(ptr_info); | |
| 22021 | const dest_ty = try pt.ptrType(ptr_info); | |
| 22642 | 22022 | if (operand_ty.zigTypeTag(zcu) == .optional) { |
| 22643 | 22023 | break :blk try pt.optionalType(dest_ty.toIntern()); |
| 22644 | 22024 | } |
| ... | ... | @@ -22678,48 +22058,24 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 22678 | 22058 | return sema.coerce(block, dest_ty, operand, operand_src); |
| 22679 | 22059 | } |
| 22680 | 22060 | |
| 22681 | const dest_info = dest_scalar_ty.intInfo(zcu); | |
| 22061 | if (try dest_ty.onePossibleValue(pt)) |opv| return .fromValue(opv); | |
| 22682 | 22062 | |
| 22683 | if (try sema.typeHasOnePossibleValue(dest_ty)) |val| { | |
| 22684 | return Air.internedToRef(val.toIntern()); | |
| 22685 | } | |
| 22063 | const dest_info = dest_scalar_ty.intInfo(zcu); | |
| 22686 | 22064 | |
| 22687 | 22065 | if (operand_scalar_ty.zigTypeTag(zcu) != .comptime_int) { |
| 22688 | 22066 | const operand_info = operand_ty.intInfo(zcu); |
| 22689 | if (try sema.typeHasOnePossibleValue(operand_ty)) |val| { | |
| 22690 | return Air.internedToRef(val.toIntern()); | |
| 22691 | } | |
| 22692 | 22067 | |
| 22693 | 22068 | if (operand_info.signedness != dest_info.signedness) { |
| 22694 | 22069 | return sema.fail(block, operand_src, "expected {s} integer type, found '{f}'", .{ |
| 22695 | 22070 | @tagName(dest_info.signedness), operand_ty.fmt(pt), |
| 22696 | 22071 | }); |
| 22697 | 22072 | } |
| 22698 | switch (std.math.order(dest_info.bits, operand_info.bits)) { | |
| 22699 | .gt => { | |
| 22700 | const msg = msg: { | |
| 22701 | const msg = try sema.errMsg( | |
| 22702 | src, | |
| 22703 | "destination type '{f}' has more bits than source type '{f}'", | |
| 22704 | .{ dest_ty.fmt(pt), operand_ty.fmt(pt) }, | |
| 22705 | ); | |
| 22706 | errdefer msg.destroy(sema.gpa); | |
| 22707 | try sema.errNote(src, msg, "destination type has {d} bits", .{ | |
| 22708 | dest_info.bits, | |
| 22709 | }); | |
| 22710 | try sema.errNote(operand_src, msg, "operand type has {d} bits", .{ | |
| 22711 | operand_info.bits, | |
| 22712 | }); | |
| 22713 | break :msg msg; | |
| 22714 | }; | |
| 22715 | return sema.failWithOwnedErrorMsg(block, msg); | |
| 22716 | }, | |
| 22717 | .eq => return operand, | |
| 22718 | .lt => {}, | |
| 22073 | if (dest_info.bits >= operand_info.bits) { | |
| 22074 | return sema.coerce(block, dest_ty, operand, operand_src); | |
| 22719 | 22075 | } |
| 22720 | 22076 | } |
| 22721 | 22077 | |
| 22722 | if (try sema.resolveValueResolveLazy(operand)) |val| { | |
| 22078 | if (try sema.resolveValue(operand)) |val| { | |
| 22723 | 22079 | const result_val = try arith.truncate(sema, val, operand_ty, dest_ty, dest_info.signedness, dest_info.bits); |
| 22724 | 22080 | return Air.internedToRef(result_val.toIntern()); |
| 22725 | 22081 | } |
| ... | ... | @@ -22745,10 +22101,6 @@ fn zirBitCount( |
| 22745 | 22101 | _ = try sema.checkIntOrVector(block, operand, operand_src); |
| 22746 | 22102 | const bits = operand_ty.intInfo(zcu).bits; |
| 22747 | 22103 | |
| 22748 | if (try sema.typeHasOnePossibleValue(operand_ty)) |val| { | |
| 22749 | return Air.internedToRef(val.toIntern()); | |
| 22750 | } | |
| 22751 | ||
| 22752 | 22104 | const result_scalar_ty = try pt.smallestUnsignedInt(bits); |
| 22753 | 22105 | switch (operand_ty.zigTypeTag(zcu)) { |
| 22754 | 22106 | .vector => { |
| ... | ... | @@ -22774,7 +22126,7 @@ fn zirBitCount( |
| 22774 | 22126 | } |
| 22775 | 22127 | }, |
| 22776 | 22128 | .int => { |
| 22777 | if (try sema.resolveValueResolveLazy(operand)) |val| { | |
| 22129 | if (try sema.resolveValue(operand)) |val| { | |
| 22778 | 22130 | if (val.isUndef(zcu)) return pt.undefRef(result_scalar_ty); |
| 22779 | 22131 | return pt.intRef(result_scalar_ty, comptimeOp(val, operand_ty, zcu)); |
| 22780 | 22132 | } else { |
| ... | ... | @@ -22803,9 +22155,6 @@ fn zirByteSwap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 22803 | 22155 | .{ scalar_ty.fmt(pt), bits }, |
| 22804 | 22156 | ); |
| 22805 | 22157 | } |
| 22806 | if (try sema.typeHasOnePossibleValue(operand_ty)) |val| { | |
| 22807 | return .fromValue(val); | |
| 22808 | } | |
| 22809 | 22158 | if (try sema.resolveValue(operand)) |operand_val| { |
| 22810 | 22159 | return .fromValue(try arith.byteSwap(sema, operand_val, operand_ty)); |
| 22811 | 22160 | } |
| ... | ... | @@ -22819,9 +22168,6 @@ fn zirBitReverse(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! |
| 22819 | 22168 | const operand_ty = sema.typeOf(operand); |
| 22820 | 22169 | _ = try sema.checkIntOrVector(block, operand, operand_src); |
| 22821 | 22170 | |
| 22822 | if (try sema.typeHasOnePossibleValue(operand_ty)) |val| { | |
| 22823 | return .fromValue(val); | |
| 22824 | } | |
| 22825 | 22171 | if (try sema.resolveValue(operand)) |operand_val| { |
| 22826 | 22172 | return .fromValue(try arith.bitReverse(sema, operand_val, operand_ty)); |
| 22827 | 22173 | } |
| ... | ... | @@ -22849,10 +22195,11 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6 |
| 22849 | 22195 | const ty = try sema.resolveType(block, ty_src, extra.lhs); |
| 22850 | 22196 | const field_name = try sema.resolveConstStringIntern(block, field_name_src, extra.rhs, .{ .simple = .field_name }); |
| 22851 | 22197 | |
| 22198 | try sema.ensureLayoutResolved(ty); | |
| 22199 | ||
| 22852 | 22200 | const pt = sema.pt; |
| 22853 | 22201 | const zcu = pt.zcu; |
| 22854 | 22202 | const ip = &zcu.intern_pool; |
| 22855 | try ty.resolveLayout(pt); | |
| 22856 | 22203 | switch (ty.zigTypeTag(zcu)) { |
| 22857 | 22204 | .@"struct" => {}, |
| 22858 | 22205 | else => return sema.fail(block, ty_src, "expected struct type, found '{f}'", .{ty.fmt(pt)}), |
| ... | ... | @@ -23126,7 +22473,7 @@ fn checkAtomicPtrOperand( |
| 23126 | 22473 | const ptr_data = switch (ptr_ty.zigTypeTag(zcu)) { |
| 23127 | 22474 | .pointer => ptr_ty.ptrInfo(zcu), |
| 23128 | 22475 | else => { |
| 23129 | const wanted_ptr_ty = try pt.ptrTypeSema(wanted_ptr_data); | |
| 22476 | const wanted_ptr_ty = try pt.ptrType(wanted_ptr_data); | |
| 23130 | 22477 | _ = try sema.coerce(block, wanted_ptr_ty, ptr, ptr_src); |
| 23131 | 22478 | unreachable; |
| 23132 | 22479 | }, |
| ... | ... | @@ -23136,7 +22483,7 @@ fn checkAtomicPtrOperand( |
| 23136 | 22483 | wanted_ptr_data.flags.is_allowzero = ptr_data.flags.is_allowzero; |
| 23137 | 22484 | wanted_ptr_data.flags.is_volatile = ptr_data.flags.is_volatile; |
| 23138 | 22485 | |
| 23139 | const wanted_ptr_ty = try pt.ptrTypeSema(wanted_ptr_data); | |
| 22486 | const wanted_ptr_ty = try pt.ptrType(wanted_ptr_data); | |
| 23140 | 22487 | const casted_ptr = try sema.coerce(block, wanted_ptr_ty, ptr, ptr_src); |
| 23141 | 22488 | |
| 23142 | 22489 | return casted_ptr; |
| ... | ... | @@ -23470,11 +22817,8 @@ fn zirCmpxchg( |
| 23470 | 22817 | const result_ty = try pt.optionalType(elem_ty.toIntern()); |
| 23471 | 22818 | |
| 23472 | 22819 | // special case zero bit types |
| 23473 | if ((try sema.typeHasOnePossibleValue(elem_ty)) != null) { | |
| 23474 | return Air.internedToRef((try pt.intern(.{ .opt = .{ | |
| 23475 | .ty = result_ty.toIntern(), | |
| 23476 | .val = .none, | |
| 23477 | } }))); | |
| 22820 | if (try elem_ty.onePossibleValue(pt) != null) { | |
| 22821 | return .fromValue(try pt.nullValue(result_ty)); | |
| 23478 | 22822 | } |
| 23479 | 22823 | |
| 23480 | 22824 | const runtime_src = if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| rs: { |
| ... | ... | @@ -23537,11 +22881,7 @@ fn zirSplat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I |
| 23537 | 22881 | |
| 23538 | 22882 | const len = try sema.usizeCast(block, src, dest_ty.arrayLen(zcu)); |
| 23539 | 22883 | |
| 23540 | if (try sema.typeHasOnePossibleValue(dest_ty)) |val| { | |
| 23541 | return Air.internedToRef(val.toIntern()); | |
| 23542 | } | |
| 23543 | ||
| 23544 | // We also need this case because `[0:s]T` is not OPV. | |
| 22884 | // If the length is 0, the result is comptime-known even if the operand isn't. | |
| 23545 | 22885 | if (len == 0) return .fromValue(try pt.aggregateValue(dest_ty, &.{})); |
| 23546 | 22886 | |
| 23547 | 22887 | const maybe_sentinel = dest_ty.sentinel(zcu); |
| ... | ... | @@ -23733,7 +23073,7 @@ fn analyzeShuffle( |
| 23733 | 23073 | continue; |
| 23734 | 23074 | } |
| 23735 | 23075 | // Safe because mask elements are `i32` and we already checked for undef: |
| 23736 | const raw = (try sema.resolveLazyValue(mask_val)).toSignedInt(zcu); | |
| 23076 | const raw = mask_val.toSignedInt(zcu); | |
| 23737 | 23077 | if (raw >= 0) { |
| 23738 | 23078 | const idx: u32 = @intCast(raw); |
| 23739 | 23079 | a_used = true; |
| ... | ... | @@ -23938,6 +23278,8 @@ fn zirAtomicLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! |
| 23938 | 23278 | const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, true); |
| 23939 | 23279 | const order = try sema.resolveAtomicOrder(block, order_src, extra.ordering, .{ .simple = .atomic_order }); |
| 23940 | 23280 | |
| 23281 | try sema.ensureLayoutResolved(elem_ty); | |
| 23282 | ||
| 23941 | 23283 | switch (order) { |
| 23942 | 23284 | .release, .acq_rel => { |
| 23943 | 23285 | return sema.fail( |
| ... | ... | @@ -23950,9 +23292,7 @@ fn zirAtomicLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! |
| 23950 | 23292 | else => {}, |
| 23951 | 23293 | } |
| 23952 | 23294 | |
| 23953 | if (try sema.typeHasOnePossibleValue(elem_ty)) |val| { | |
| 23954 | return Air.internedToRef(val.toIntern()); | |
| 23955 | } | |
| 23295 | if (try elem_ty.onePossibleValue(sema.pt)) |opv| return .fromValue(opv); | |
| 23956 | 23296 | |
| 23957 | 23297 | if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| { |
| 23958 | 23298 | if (try sema.pointerDeref(block, ptr_src, ptr_val, sema.typeOf(ptr))) |elem_val| { |
| ... | ... | @@ -24009,9 +23349,7 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 24009 | 23349 | } |
| 24010 | 23350 | |
| 24011 | 23351 | // special case zero bit types |
| 24012 | if (try sema.typeHasOnePossibleValue(elem_ty)) |val| { | |
| 24013 | return Air.internedToRef(val.toIntern()); | |
| 24014 | } | |
| 23352 | if (try elem_ty.onePossibleValue(pt)) |opv| return .fromValue(opv); | |
| 24015 | 23353 | |
| 24016 | 23354 | const runtime_src = if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| rs: { |
| 24017 | 23355 | const maybe_operand_val = try sema.resolveValue(operand); |
| ... | ... | @@ -24260,11 +23598,11 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins |
| 24260 | 23598 | return sema.fail(block, inst_src, "expected single pointer type, found '{f}'", .{parent_ptr_ty.fmt(pt)}); |
| 24261 | 23599 | } |
| 24262 | 23600 | const parent_ty: Type = .fromInterned(parent_ptr_info.child); |
| 23601 | try sema.ensureLayoutResolved(parent_ty); | |
| 24263 | 23602 | switch (parent_ty.zigTypeTag(zcu)) { |
| 24264 | 23603 | .@"struct", .@"union" => {}, |
| 24265 | 23604 | else => return sema.fail(block, inst_src, "expected pointer to struct or union type, found '{f}'", .{parent_ptr_ty.fmt(pt)}), |
| 24266 | 23605 | } |
| 24267 | try parent_ty.resolveLayout(pt); | |
| 24268 | 23606 | |
| 24269 | 23607 | const field_name = try sema.resolveConstStringIntern(block, field_name_src, extra.field_name, .{ .simple = .field_name }); |
| 24270 | 23608 | const field_index = switch (parent_ty.zigTypeTag(zcu)) { |
| ... | ... | @@ -24293,7 +23631,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins |
| 24293 | 23631 | var actual_parent_ptr_info: InternPool.Key.PtrType = .{ |
| 24294 | 23632 | .child = parent_ty.toIntern(), |
| 24295 | 23633 | .flags = .{ |
| 24296 | .alignment = try parent_ptr_ty.ptrAlignmentSema(pt), | |
| 23634 | .alignment = parent_ptr_ty.ptrAlignment(zcu), | |
| 24297 | 23635 | .is_const = field_ptr_info.flags.is_const, |
| 24298 | 23636 | .is_volatile = field_ptr_info.flags.is_volatile, |
| 24299 | 23637 | .is_allowzero = field_ptr_info.flags.is_allowzero, |
| ... | ... | @@ -24305,7 +23643,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins |
| 24305 | 23643 | var actual_field_ptr_info: InternPool.Key.PtrType = .{ |
| 24306 | 23644 | .child = field_ty.toIntern(), |
| 24307 | 23645 | .flags = .{ |
| 24308 | .alignment = try field_ptr_ty.ptrAlignmentSema(pt), | |
| 23646 | .alignment = field_ptr_ty.ptrAlignment(zcu), | |
| 24309 | 23647 | .is_const = field_ptr_info.flags.is_const, |
| 24310 | 23648 | .is_volatile = field_ptr_info.flags.is_volatile, |
| 24311 | 23649 | .is_allowzero = field_ptr_info.flags.is_allowzero, |
| ... | ... | @@ -24315,23 +23653,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins |
| 24315 | 23653 | }; |
| 24316 | 23654 | switch (parent_ty.containerLayout(zcu)) { |
| 24317 | 23655 | .auto => { |
| 24318 | actual_parent_ptr_info.flags.alignment = actual_field_ptr_info.flags.alignment.minStrict( | |
| 24319 | if (zcu.typeToStruct(parent_ty)) |struct_obj| | |
| 24320 | try field_ty.structFieldAlignmentSema( | |
| 24321 | struct_obj.fieldAlign(ip, field_index), | |
| 24322 | struct_obj.layout, | |
| 24323 | pt, | |
| 24324 | ) | |
| 24325 | else if (zcu.typeToUnion(parent_ty)) |union_obj| | |
| 24326 | try field_ty.unionFieldAlignmentSema( | |
| 24327 | union_obj.fieldAlign(ip, field_index), | |
| 24328 | union_obj.flagsUnordered(ip).layout, | |
| 24329 | pt, | |
| 24330 | ) | |
| 24331 | else | |
| 24332 | actual_field_ptr_info.flags.alignment, | |
| 24333 | ); | |
| 24334 | ||
| 23656 | actual_parent_ptr_info.flags.alignment = parent_ty.resolvedFieldAlignment(field_index, zcu); | |
| 24335 | 23657 | actual_parent_ptr_info.packed_offset = .{ .bit_offset = 0, .host_size = 0 }; |
| 24336 | 23658 | actual_field_ptr_info.packed_offset = .{ .bit_offset = 0, .host_size = 0 }; |
| 24337 | 23659 | }, |
| ... | ... | @@ -24357,9 +23679,9 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins |
| 24357 | 23679 | }, |
| 24358 | 23680 | } |
| 24359 | 23681 | |
| 24360 | const actual_field_ptr_ty = try pt.ptrTypeSema(actual_field_ptr_info); | |
| 23682 | const actual_field_ptr_ty = try pt.ptrType(actual_field_ptr_info); | |
| 24361 | 23683 | const casted_field_ptr = try sema.coerce(block, actual_field_ptr_ty, field_ptr, field_ptr_src); |
| 24362 | const actual_parent_ptr_ty = try pt.ptrTypeSema(actual_parent_ptr_info); | |
| 23684 | const actual_parent_ptr_ty = try pt.ptrType(actual_parent_ptr_info); | |
| 24363 | 23685 | |
| 24364 | 23686 | const result = if (try sema.resolveDefinedValue(block, field_ptr_src, casted_field_ptr)) |field_ptr_val| result: { |
| 24365 | 23687 | switch (parent_ty.zigTypeTag(zcu)) { |
| ... | ... | @@ -24590,7 +23912,7 @@ fn analyzeMinMax( |
| 24590 | 23912 | const operand_scalar_ty = sema.typeOf(operand).scalarType(zcu); |
| 24591 | 23913 | const want_strat: TypeStrat = switch (operand_scalar_ty.zigTypeTag(zcu)) { |
| 24592 | 23914 | .comptime_int => s: { |
| 24593 | const val = (try sema.resolveValueResolveLazy(operand)).?; | |
| 23915 | const val = (try sema.resolveValue(operand)).?; | |
| 24594 | 23916 | if (val.isUndef(zcu)) break :s .none; |
| 24595 | 23917 | break :s .{ .int = .{ |
| 24596 | 23918 | .all_comptime_int = true, |
| ... | ... | @@ -24609,7 +23931,7 @@ fn analyzeMinMax( |
| 24609 | 23931 | // (replaced with just the simple calls to `Type.minInt`/`Type.maxInt`) so that we only |
| 24610 | 23932 | // use the input *types* to determine the result type. |
| 24611 | 23933 | const min: Value, const max: Value = bounds: { |
| 24612 | if (try sema.resolveValueResolveLazy(operand)) |operand_val| { | |
| 23934 | if (try sema.resolveValue(operand)) |operand_val| { | |
| 24613 | 23935 | if (vector_len) |len| { |
| 24614 | 23936 | var min = try operand_val.elemValue(pt, 0); |
| 24615 | 23937 | var max = min; |
| ... | ... | @@ -24696,6 +24018,9 @@ fn analyzeMinMax( |
| 24696 | 24018 | .child = intermediate_scalar_ty.toIntern(), |
| 24697 | 24019 | }) else intermediate_scalar_ty; |
| 24698 | 24020 | |
| 24021 | // We might have refined all the way down to an OPV type---check now. | |
| 24022 | if (try result_ty.onePossibleValue(pt)) |opv| return .fromValue(opv); | |
| 24023 | ||
| 24699 | 24024 | // This value, if not `null`, will have type `intermediate_ty`. |
| 24700 | 24025 | const comptime_part: ?Value = ct: { |
| 24701 | 24026 | // Contains the comptime-known scalar result values. |
| ... | ... | @@ -24712,7 +24037,7 @@ fn analyzeMinMax( |
| 24712 | 24037 | var opt_runtime_src: ?LazySrcLoc = null; |
| 24713 | 24038 | |
| 24714 | 24039 | for (operands, operand_srcs) |operand, operand_src| { |
| 24715 | const operand_val = try sema.resolveValueResolveLazy(operand) orelse { | |
| 24040 | const operand_val = try sema.resolveValue(operand) orelse { | |
| 24716 | 24041 | if (opt_runtime_src == null) opt_runtime_src = operand_src; |
| 24717 | 24042 | continue; |
| 24718 | 24043 | }; |
| ... | ... | @@ -24819,7 +24144,7 @@ fn upgradeToArrayPtr(sema: *Sema, block: *Block, ptr: Air.Inst.Ref, len: u64) !A |
| 24819 | 24144 | // Already an array pointer. |
| 24820 | 24145 | return ptr; |
| 24821 | 24146 | } |
| 24822 | const new_ty = try pt.ptrTypeSema(.{ | |
| 24147 | const new_ty = try pt.ptrType(.{ | |
| 24823 | 24148 | .child = (try pt.arrayType(.{ |
| 24824 | 24149 | .len = len, |
| 24825 | 24150 | .sentinel = info.sentinel, |
| ... | ... | @@ -24883,6 +24208,9 @@ fn zirMemcpy( |
| 24883 | 24208 | const dest_elem_ty = dest_ty.indexablePtrElem(zcu); |
| 24884 | 24209 | const src_elem_ty = src_ty.indexablePtrElem(zcu); |
| 24885 | 24210 | |
| 24211 | try sema.ensureLayoutResolved(dest_elem_ty); | |
| 24212 | try sema.ensureLayoutResolved(src_elem_ty); | |
| 24213 | ||
| 24886 | 24214 | const imc = try sema.coerceInMemoryAllowed( |
| 24887 | 24215 | block, |
| 24888 | 24216 | dest_elem_ty, |
| ... | ... | @@ -24946,13 +24274,13 @@ fn zirMemcpy( |
| 24946 | 24274 | } |
| 24947 | 24275 | |
| 24948 | 24276 | zero_bit: { |
| 24949 | const src_comptime = try src_elem_ty.comptimeOnlySema(pt); | |
| 24950 | const dest_comptime = try dest_elem_ty.comptimeOnlySema(pt); | |
| 24277 | const src_comptime = src_elem_ty.comptimeOnly(zcu); | |
| 24278 | const dest_comptime = dest_elem_ty.comptimeOnly(zcu); | |
| 24951 | 24279 | assert(src_comptime == dest_comptime); // IMC |
| 24952 | 24280 | if (src_comptime) break :zero_bit; |
| 24953 | 24281 | |
| 24954 | const src_has_bits = try src_elem_ty.hasRuntimeBitsIgnoreComptimeSema(pt); | |
| 24955 | const dest_has_bits = try dest_elem_ty.hasRuntimeBitsIgnoreComptimeSema(pt); | |
| 24282 | const src_has_bits = src_elem_ty.hasRuntimeBits(zcu); | |
| 24283 | const dest_has_bits = dest_elem_ty.hasRuntimeBits(zcu); | |
| 24956 | 24284 | assert(src_has_bits == dest_has_bits); // IMC |
| 24957 | 24285 | if (src_has_bits) break :zero_bit; |
| 24958 | 24286 | |
| ... | ... | @@ -24968,7 +24296,7 @@ fn zirMemcpy( |
| 24968 | 24296 | const raw_dest_ptr = if (dest_ty.isSlice(zcu)) dest_ptr_val.slicePtr(zcu) else dest_ptr_val; |
| 24969 | 24297 | const raw_src_ptr = if (src_ty.isSlice(zcu)) src_ptr_val.slicePtr(zcu) else src_ptr_val; |
| 24970 | 24298 | |
| 24971 | const len_u64 = try len_val.?.toUnsignedIntSema(pt); | |
| 24299 | const len_u64 = len_val.?.toUnsignedInt(zcu); | |
| 24972 | 24300 | |
| 24973 | 24301 | if (check_aliasing) { |
| 24974 | 24302 | if (Value.doPointersOverlap( |
| ... | ... | @@ -25018,7 +24346,7 @@ fn zirMemcpy( |
| 25018 | 24346 | var new_dest_ptr = dest_ptr; |
| 25019 | 24347 | var new_src_ptr = src_ptr; |
| 25020 | 24348 | if (len_val) |val| { |
| 25021 | const len = try val.toUnsignedIntSema(pt); | |
| 24349 | const len = val.toUnsignedInt(zcu); | |
| 25022 | 24350 | if (len == 0) { |
| 25023 | 24351 | // This AIR instruction guarantees length > 0 if it is comptime-known. |
| 25024 | 24352 | return; |
| ... | ... | @@ -25067,7 +24395,7 @@ fn zirMemcpy( |
| 25067 | 24395 | assert(dest_manyptr_ty_key.flags.size == .one); |
| 25068 | 24396 | dest_manyptr_ty_key.child = dest_elem_ty.toIntern(); |
| 25069 | 24397 | dest_manyptr_ty_key.flags.size = .many; |
| 25070 | break :ptr try sema.coerceCompatiblePtrs(block, try pt.ptrTypeSema(dest_manyptr_ty_key), new_dest_ptr, dest_src); | |
| 24398 | break :ptr try sema.coerceCompatiblePtrs(block, try pt.ptrType(dest_manyptr_ty_key), new_dest_ptr, dest_src); | |
| 25071 | 24399 | } else new_dest_ptr; |
| 25072 | 24400 | |
| 25073 | 24401 | const new_src_ptr_ty = sema.typeOf(new_src_ptr); |
| ... | ... | @@ -25078,7 +24406,7 @@ fn zirMemcpy( |
| 25078 | 24406 | assert(src_manyptr_ty_key.flags.size == .one); |
| 25079 | 24407 | src_manyptr_ty_key.child = src_elem_ty.toIntern(); |
| 25080 | 24408 | src_manyptr_ty_key.flags.size = .many; |
| 25081 | break :ptr try sema.coerceCompatiblePtrs(block, try pt.ptrTypeSema(src_manyptr_ty_key), new_src_ptr, src_src); | |
| 24409 | break :ptr try sema.coerceCompatiblePtrs(block, try pt.ptrType(src_manyptr_ty_key), new_src_ptr, src_src); | |
| 25082 | 24410 | } else new_src_ptr; |
| 25083 | 24411 | |
| 25084 | 24412 | // ok1: dest >= src + len |
| ... | ... | @@ -25148,7 +24476,7 @@ fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void |
| 25148 | 24476 | const runtime_src = rs: { |
| 25149 | 24477 | const len_air_ref = try sema.fieldVal(block, src, dest_ptr, try ip.getOrPutString(gpa, io, pt.tid, "len", .no_embedded_nulls), dest_src); |
| 25150 | 24478 | const len_val = (try sema.resolveDefinedValue(block, dest_src, len_air_ref)) orelse break :rs dest_src; |
| 25151 | const len_u64 = try len_val.toUnsignedIntSema(pt); | |
| 24479 | const len_u64 = len_val.toUnsignedInt(zcu); | |
| 25152 | 24480 | const len = try sema.usizeCast(block, dest_src, len_u64); |
| 25153 | 24481 | if (len == 0) { |
| 25154 | 24482 | // This AIR instruction guarantees length > 0 if it is comptime-known. |
| ... | ... | @@ -25436,7 +24764,7 @@ fn resolvePrefetchOptions( |
| 25436 | 24764 | |
| 25437 | 24765 | return std.builtin.PrefetchOptions{ |
| 25438 | 24766 | .rw = try sema.interpretBuiltinType(block, rw_src, rw_val, std.builtin.PrefetchOptions.Rw), |
| 25439 | .locality = @intCast(try locality_val.toUnsignedIntSema(pt)), | |
| 24767 | .locality = @intCast(locality_val.toUnsignedInt(zcu)), | |
| 25440 | 24768 | .cache = try sema.interpretBuiltinType(block, cache_src, cache_val, std.builtin.PrefetchOptions.Cache), |
| 25441 | 24769 | }; |
| 25442 | 24770 | } |
| ... | ... | @@ -25626,7 +24954,7 @@ fn zirBuiltinExtern( |
| 25626 | 24954 | // So, for now, just use our containing `declaration`. |
| 25627 | 24955 | .zir_index = switch (sema.owner.unwrap()) { |
| 25628 | 24956 | .@"comptime" => |cu| ip.getComptimeUnit(cu).zir_index, |
| 25629 | .type => |owner_ty| Type.fromInterned(owner_ty).typeDeclInst(zcu).?, | |
| 24957 | .type_layout, .type_inits => |owner_ty| Type.fromInterned(owner_ty).typeDeclInstAllowGeneratedTag(zcu).?, | |
| 25630 | 24958 | .memoized_state => unreachable, |
| 25631 | 24959 | .nav_ty, .nav_val => |nav| ip.getNav(nav).analysis.?.zir_index, |
| 25632 | 24960 | .func => |func| zir_index: { |
| ... | ... | @@ -25839,7 +25167,8 @@ fn requireRuntimeBlock(sema: *Sema, block: *Block, src: LazySrcLoc, runtime_src: |
| 25839 | 25167 | } |
| 25840 | 25168 | } |
| 25841 | 25169 | |
| 25842 | /// Emit a compile error if type cannot be used for a runtime variable. | |
| 25170 | /// Emit a compile error if `var_ty` cannot be used for a runtime variable. | |
| 25171 | /// Asserts that the layout of `var_ty` is already resolved. | |
| 25843 | 25172 | pub fn validateVarType( |
| 25844 | 25173 | sema: *Sema, |
| 25845 | 25174 | block: *Block, |
| ... | ... | @@ -25849,6 +25178,7 @@ pub fn validateVarType( |
| 25849 | 25178 | ) CompileError!void { |
| 25850 | 25179 | const pt = sema.pt; |
| 25851 | 25180 | const zcu = pt.zcu; |
| 25181 | var_ty.assertHasLayout(zcu); | |
| 25852 | 25182 | if (is_extern) { |
| 25853 | 25183 | if (!try sema.validateExternType(var_ty, .other)) { |
| 25854 | 25184 | const msg = msg: { |
| ... | ... | @@ -25870,7 +25200,7 @@ pub fn validateVarType( |
| 25870 | 25200 | } |
| 25871 | 25201 | } |
| 25872 | 25202 | |
| 25873 | if (!try var_ty.comptimeOnlySema(pt)) return; | |
| 25203 | if (!var_ty.comptimeOnly(zcu)) return; | |
| 25874 | 25204 | |
| 25875 | 25205 | const msg = msg: { |
| 25876 | 25206 | const msg = try sema.errMsg(src, "variable of type '{f}' must be const or comptime", .{var_ty.fmt(pt)}); |
| ... | ... | @@ -25886,49 +25216,28 @@ pub fn validateVarType( |
| 25886 | 25216 | return sema.failWithOwnedErrorMsg(block, msg); |
| 25887 | 25217 | } |
| 25888 | 25218 | |
| 25889 | const TypeSet = std.AutoHashMapUnmanaged(InternPool.Index, void); | |
| 25890 | ||
| 25891 | 25219 | fn explainWhyTypeIsComptime( |
| 25892 | 25220 | sema: *Sema, |
| 25893 | 25221 | msg: *Zcu.ErrorMsg, |
| 25894 | src_loc: LazySrcLoc, | |
| 25895 | ty: Type, | |
| 25896 | ) CompileError!void { | |
| 25897 | var type_set = TypeSet{}; | |
| 25898 | defer type_set.deinit(sema.gpa); | |
| 25899 | ||
| 25900 | try ty.resolveFully(sema.pt); | |
| 25901 | return sema.explainWhyTypeIsComptimeInner(msg, src_loc, ty, &type_set); | |
| 25902 | } | |
| 25903 | ||
| 25904 | fn explainWhyTypeIsComptimeInner( | |
| 25905 | sema: *Sema, | |
| 25906 | msg: *Zcu.ErrorMsg, | |
| 25907 | src_loc: LazySrcLoc, | |
| 25222 | src: LazySrcLoc, | |
| 25908 | 25223 | ty: Type, |
| 25909 | type_set: *TypeSet, | |
| 25910 | 25224 | ) CompileError!void { |
| 25911 | 25225 | const pt = sema.pt; |
| 25912 | 25226 | const zcu = pt.zcu; |
| 25913 | 25227 | const ip = &zcu.intern_pool; |
| 25228 | assert(ty.comptimeOnly(zcu)); | |
| 25914 | 25229 | switch (ty.zigTypeTag(zcu)) { |
| 25915 | 25230 | .bool, |
| 25916 | 25231 | .int, |
| 25917 | 25232 | .float, |
| 25918 | 25233 | .error_set, |
| 25919 | .@"enum", | |
| 25920 | 25234 | .frame, |
| 25921 | 25235 | .@"anyframe", |
| 25922 | 25236 | .void, |
| 25923 | => return, | |
| 25924 | ||
| 25925 | .@"fn" => { | |
| 25926 | try sema.errNote(src_loc, msg, "use '*const {f}' for a function pointer type", .{ty.fmt(pt)}); | |
| 25927 | }, | |
| 25928 | ||
| 25929 | .type => { | |
| 25930 | try sema.errNote(src_loc, msg, "types are not available at runtime", .{}); | |
| 25931 | }, | |
| 25237 | .@"enum", | |
| 25238 | .@"opaque", | |
| 25239 | .pointer, | |
| 25240 | => unreachable, // not comptime-only | |
| 25932 | 25241 | |
| 25933 | 25242 | .comptime_float, |
| 25934 | 25243 | .comptime_int, |
| ... | ... | @@ -25936,78 +25245,53 @@ fn explainWhyTypeIsComptimeInner( |
| 25936 | 25245 | .noreturn, |
| 25937 | 25246 | .undefined, |
| 25938 | 25247 | .null, |
| 25939 | => return, | |
| 25940 | ||
| 25941 | .@"opaque" => { | |
| 25942 | try sema.errNote(src_loc, msg, "opaque type '{f}' has undefined size", .{ty.fmt(pt)}); | |
| 25943 | }, | |
| 25944 | ||
| 25945 | .array, .vector => { | |
| 25946 | try sema.explainWhyTypeIsComptimeInner(msg, src_loc, ty.childType(zcu), type_set); | |
| 25947 | }, | |
| 25948 | .pointer => { | |
| 25949 | const elem_ty = ty.elemType2(zcu); | |
| 25950 | if (elem_ty.zigTypeTag(zcu) == .@"fn") { | |
| 25951 | const fn_info = zcu.typeToFunc(elem_ty).?; | |
| 25952 | if (fn_info.is_generic) { | |
| 25953 | try sema.errNote(src_loc, msg, "function is generic", .{}); | |
| 25954 | } | |
| 25955 | switch (fn_info.cc) { | |
| 25956 | .@"inline" => try sema.errNote(src_loc, msg, "function has inline calling convention", .{}), | |
| 25957 | else => {}, | |
| 25958 | } | |
| 25959 | if (Type.fromInterned(fn_info.return_type).comptimeOnly(zcu)) { | |
| 25960 | try sema.errNote(src_loc, msg, "function has a comptime-only return type", .{}); | |
| 25961 | } | |
| 25962 | return; | |
| 25963 | } | |
| 25964 | try sema.explainWhyTypeIsComptimeInner(msg, src_loc, ty.childType(zcu), type_set); | |
| 25965 | }, | |
| 25966 | ||
| 25967 | .optional => { | |
| 25968 | try sema.explainWhyTypeIsComptimeInner(msg, src_loc, ty.optionalChild(zcu), type_set); | |
| 25969 | }, | |
| 25970 | .error_union => { | |
| 25971 | try sema.explainWhyTypeIsComptimeInner(msg, src_loc, ty.errorUnionPayload(zcu), type_set); | |
| 25972 | }, | |
| 25248 | => return, // no explanation needed | |
| 25973 | 25249 | |
| 25974 | .@"struct" => { | |
| 25975 | if ((try type_set.getOrPut(sema.gpa, ty.toIntern())).found_existing) return; | |
| 25250 | .array, .vector => try sema.explainWhyTypeIsComptime(msg, src, ty.childType(zcu)), | |
| 25251 | .optional => try sema.explainWhyTypeIsComptime(msg, src, ty.optionalChild(zcu)), | |
| 25252 | .error_union => try sema.explainWhyTypeIsComptime(msg, src, ty.errorUnionPayload(zcu)), | |
| 25976 | 25253 | |
| 25977 | if (zcu.typeToStruct(ty)) |struct_type| { | |
| 25978 | for (0..struct_type.field_types.len) |i| { | |
| 25979 | const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[i]); | |
| 25980 | const field_src: LazySrcLoc = .{ | |
| 25981 | .base_node_inst = struct_type.zir_index, | |
| 25982 | .offset = .{ .container_field_type = @intCast(i) }, | |
| 25983 | }; | |
| 25254 | .@"fn" => try sema.errNote(src, msg, "use '*const {f}' for a function pointer type", .{ty.fmt(pt)}), | |
| 25255 | .type => try sema.errNote(src, msg, "types are not available at runtime", .{}), | |
| 25984 | 25256 | |
| 25985 | if (try field_ty.comptimeOnlySema(pt)) { | |
| 25986 | try sema.errNote(field_src, msg, "struct requires comptime because of this field", .{}); | |
| 25987 | try sema.explainWhyTypeIsComptimeInner(msg, field_src, field_ty, type_set); | |
| 25988 | } | |
| 25989 | } | |
| 25257 | .@"struct" => if (zcu.typeToStruct(ty)) |struct_type| { | |
| 25258 | ty.assertHasLayout(zcu); | |
| 25259 | for (0..struct_type.field_types.len) |i| { | |
| 25260 | const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[i]); | |
| 25261 | if (!field_ty.comptimeOnly(zcu)) continue; | |
| 25262 | const field_src: LazySrcLoc = .{ | |
| 25263 | .base_node_inst = struct_type.zir_index, | |
| 25264 | .offset = .{ .container_field_type = @intCast(i) }, | |
| 25265 | }; | |
| 25266 | try sema.errNote(field_src, msg, "struct requires comptime because of this field", .{}); | |
| 25267 | return sema.explainWhyTypeIsComptime(msg, field_src, field_ty); | |
| 25990 | 25268 | } |
| 25991 | // TODO tuples | |
| 25269 | unreachable; | |
| 25270 | } else { | |
| 25271 | const tuple = ip.indexToKey(ty.toIntern()).tuple_type; | |
| 25272 | for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty_ip, field_val_ip| { | |
| 25273 | if (field_val_ip != .none) continue; | |
| 25274 | const field_ty: Type = .fromInterned(field_ty_ip); | |
| 25275 | if (!field_ty.comptimeOnly(zcu)) continue; | |
| 25276 | try sema.errNote(src, msg, "tuple requires comptime because of field of type '{f}'", .{field_ty.fmt(pt)}); | |
| 25277 | return sema.explainWhyTypeIsComptime(msg, src, field_ty); | |
| 25278 | } | |
| 25279 | unreachable; | |
| 25992 | 25280 | }, |
| 25993 | 25281 | |
| 25994 | 25282 | .@"union" => { |
| 25995 | if ((try type_set.getOrPut(sema.gpa, ty.toIntern())).found_existing) return; | |
| 25996 | ||
| 25997 | if (zcu.typeToUnion(ty)) |union_obj| { | |
| 25998 | for (0..union_obj.field_types.len) |i| { | |
| 25999 | const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[i]); | |
| 26000 | const field_src: LazySrcLoc = .{ | |
| 26001 | .base_node_inst = union_obj.zir_index, | |
| 26002 | .offset = .{ .container_field_type = @intCast(i) }, | |
| 26003 | }; | |
| 26004 | ||
| 26005 | if (try field_ty.comptimeOnlySema(pt)) { | |
| 26006 | try sema.errNote(field_src, msg, "union requires comptime because of this field", .{}); | |
| 26007 | try sema.explainWhyTypeIsComptimeInner(msg, field_src, field_ty, type_set); | |
| 26008 | } | |
| 26009 | } | |
| 25283 | const union_obj = zcu.typeToUnion(ty).?; | |
| 25284 | for (0..union_obj.field_types.len) |i| { | |
| 25285 | const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[i]); | |
| 25286 | if (!field_ty.comptimeOnly(zcu)) continue; | |
| 25287 | const field_src: LazySrcLoc = .{ | |
| 25288 | .base_node_inst = union_obj.zir_index, | |
| 25289 | .offset = .{ .container_field_type = @intCast(i) }, | |
| 25290 | }; | |
| 25291 | try sema.errNote(field_src, msg, "union requires comptime because of this field", .{}); | |
| 25292 | return sema.explainWhyTypeIsComptime(msg, field_src, field_ty); | |
| 26010 | 25293 | } |
| 25294 | unreachable; | |
| 26011 | 25295 | }, |
| 26012 | 25296 | } |
| 26013 | 25297 | } |
| ... | ... | @@ -26022,9 +25306,8 @@ const ExternPosition = enum { |
| 26022 | 25306 | }; |
| 26023 | 25307 | |
| 26024 | 25308 | /// Returns true if `ty` is allowed in extern types. |
| 26025 | /// Does *NOT* require `ty` to be resolved in any way. | |
| 26026 | /// Calls `resolveLayout` for packed containers. | |
| 26027 | fn validateExternType( | |
| 25309 | /// Does not require `ty` to be resolved in any way. | |
| 25310 | pub fn validateExternType( | |
| 26028 | 25311 | sema: *Sema, |
| 26029 | 25312 | ty: Type, |
| 26030 | 25313 | position: ExternPosition, |
| ... | ... | @@ -26042,7 +25325,16 @@ fn validateExternType( |
| 26042 | 25325 | .error_set, |
| 26043 | 25326 | .frame, |
| 26044 | 25327 | => return false, |
| 26045 | .void => return position == .union_field or position == .ret_ty or position == .struct_field or position == .element, | |
| 25328 | .void => return switch (position) { | |
| 25329 | .ret_ty, | |
| 25330 | .union_field, | |
| 25331 | .struct_field, | |
| 25332 | .element, | |
| 25333 | => true, | |
| 25334 | .param_ty, | |
| 25335 | .other, | |
| 25336 | => false, | |
| 25337 | }, | |
| 26046 | 25338 | .noreturn => return position == .ret_ty, |
| 26047 | 25339 | .@"opaque", |
| 26048 | 25340 | .bool, |
| ... | ... | @@ -26050,10 +25342,12 @@ fn validateExternType( |
| 26050 | 25342 | .@"anyframe", |
| 26051 | 25343 | => return true, |
| 26052 | 25344 | .pointer => { |
| 26053 | if (ty.childType(zcu).zigTypeTag(zcu) == .@"fn") { | |
| 26054 | return ty.isConstPtr(zcu) and try sema.validateExternType(ty.childType(zcu), .other); | |
| 25345 | if (ty.isSlice(zcu)) return false; | |
| 25346 | const child_ty = ty.childType(zcu); | |
| 25347 | if (child_ty.zigTypeTag(zcu) == .@"fn") { | |
| 25348 | return ty.isConstPtr(zcu) and try sema.validateExternType(child_ty, .other); | |
| 26055 | 25349 | } |
| 26056 | return !(ty.isSlice(zcu) or try ty.comptimeOnlySema(pt)); | |
| 25350 | return true; | |
| 26057 | 25351 | }, |
| 26058 | 25352 | .int => switch (ty.intInfo(zcu).bits) { |
| 26059 | 25353 | 0, 8, 16, 32, 64, 128 => return true, |
| ... | ... | @@ -26069,29 +25363,42 @@ fn validateExternType( |
| 26069 | 25363 | return !target_util.fnCallConvAllowsZigTypes(ty.fnCallingConvention(zcu)); |
| 26070 | 25364 | }, |
| 26071 | 25365 | .@"enum" => { |
| 26072 | return sema.validateExternType(ty.intTagType(zcu), position); | |
| 26073 | }, | |
| 26074 | .@"struct", .@"union" => switch (ty.containerLayout(zcu)) { | |
| 26075 | .@"extern" => return true, | |
| 26076 | .@"packed" => { | |
| 26077 | const bit_size = try ty.bitSizeSema(pt); | |
| 26078 | switch (bit_size) { | |
| 26079 | 0, 8, 16, 32, 64, 128 => return true, | |
| 26080 | else => return false, | |
| 26081 | } | |
| 26082 | }, | |
| 26083 | .auto => return !(try ty.hasRuntimeBitsSema(pt)), | |
| 25366 | const enum_obj = zcu.intern_pool.loadEnumType(ty.toIntern()); | |
| 25367 | if (!enum_obj.int_tag_is_explicit) return false; | |
| 25368 | return sema.validateExternType(.fromInterned(enum_obj.int_tag_type), position); | |
| 25369 | }, | |
| 25370 | .@"struct" => { | |
| 25371 | const struct_obj = zcu.intern_pool.loadStructType(ty.toIntern()); | |
| 25372 | return switch (struct_obj.layout) { | |
| 25373 | .auto => false, | |
| 25374 | .@"extern" => true, | |
| 25375 | .@"packed" => switch (struct_obj.packed_backing_mode) { | |
| 25376 | .auto => false, | |
| 25377 | .explicit => try sema.validateExternType(.fromInterned(struct_obj.packed_backing_int_type), position), | |
| 25378 | }, | |
| 25379 | }; | |
| 25380 | }, | |
| 25381 | .@"union" => { | |
| 25382 | const union_obj = zcu.intern_pool.loadUnionType(ty.toIntern()); | |
| 25383 | return switch (union_obj.layout) { | |
| 25384 | .auto => false, | |
| 25385 | .@"extern" => true, | |
| 25386 | .@"packed" => switch (union_obj.packed_backing_mode) { | |
| 25387 | .auto => false, | |
| 25388 | .explicit => try sema.validateExternType(.fromInterned(union_obj.packed_backing_int_type), position), | |
| 25389 | }, | |
| 25390 | }; | |
| 26084 | 25391 | }, |
| 26085 | 25392 | .array => { |
| 26086 | 25393 | if (position == .ret_ty or position == .param_ty) return false; |
| 26087 | return sema.validateExternType(ty.elemType2(zcu), .element); | |
| 25394 | return sema.validateExternType(ty.childType(zcu), .element); | |
| 26088 | 25395 | }, |
| 26089 | .vector => return sema.validateExternType(ty.elemType2(zcu), .element), | |
| 25396 | .vector => return sema.validateExternType(ty.childType(zcu), .element), | |
| 26090 | 25397 | .optional => return ty.isPtrLikeOptional(zcu), |
| 26091 | 25398 | } |
| 26092 | 25399 | } |
| 26093 | 25400 | |
| 26094 | fn explainWhyTypeIsNotExtern( | |
| 25401 | pub fn explainWhyTypeIsNotExtern( | |
| 26095 | 25402 | sema: *Sema, |
| 26096 | 25403 | msg: *Zcu.ErrorMsg, |
| 26097 | 25404 | src_loc: LazySrcLoc, |
| ... | ... | @@ -26125,9 +25432,6 @@ fn explainWhyTypeIsNotExtern( |
| 26125 | 25432 | const pointee_ty = ty.childType(zcu); |
| 26126 | 25433 | if (!ty.isConstPtr(zcu) and pointee_ty.zigTypeTag(zcu) == .@"fn") { |
| 26127 | 25434 | try sema.errNote(src_loc, msg, "pointer to extern function must be 'const'", .{}); |
| 26128 | } else if (try ty.comptimeOnlySema(pt)) { | |
| 26129 | try sema.errNote(src_loc, msg, "pointer to comptime-only type '{f}'", .{pointee_ty.fmt(pt)}); | |
| 26130 | try sema.explainWhyTypeIsComptime(msg, src_loc, ty); | |
| 26131 | 25435 | } |
| 26132 | 25436 | try sema.explainWhyTypeIsNotExtern(msg, src_loc, pointee_ty, .other); |
| 26133 | 25437 | } |
| ... | ... | @@ -26157,6 +25461,7 @@ fn explainWhyTypeIsNotExtern( |
| 26157 | 25461 | try sema.errNote(src_loc, msg, "enum tag type '{f}' is not extern compatible", .{tag_ty.fmt(pt)}); |
| 26158 | 25462 | try sema.explainWhyTypeIsNotExtern(msg, src_loc, tag_ty, position); |
| 26159 | 25463 | }, |
| 25464 | // MLUGG TODO: these notes are bad now (because ABI sized packed type also needs explicit backing type) | |
| 26160 | 25465 | .@"struct" => try sema.errNote(src_loc, msg, "only extern structs and ABI sized packed structs are extern compatible", .{}), |
| 26161 | 25466 | .@"union" => try sema.errNote(src_loc, msg, "only extern unions and ABI sized packed unions are extern compatible", .{}), |
| 26162 | 25467 | .array => { |
| ... | ... | @@ -26165,51 +25470,14 @@ fn explainWhyTypeIsNotExtern( |
| 26165 | 25470 | } else if (position == .param_ty) { |
| 26166 | 25471 | return sema.errNote(src_loc, msg, "arrays are not allowed as a parameter type", .{}); |
| 26167 | 25472 | } |
| 26168 | try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.elemType2(zcu), .element); | |
| 25473 | try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.childType(zcu), .element); | |
| 26169 | 25474 | }, |
| 26170 | .vector => try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.elemType2(zcu), .element), | |
| 25475 | .vector => try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.childType(zcu), .element), | |
| 26171 | 25476 | .optional => try sema.errNote(src_loc, msg, "only pointer like optionals are extern compatible", .{}), |
| 26172 | 25477 | } |
| 26173 | 25478 | } |
| 26174 | 25479 | |
| 26175 | /// Returns true if `ty` is allowed in packed types. | |
| 26176 | /// Does not require `ty` to be resolved in any way, but may resolve whether it is comptime-only. | |
| 26177 | fn validatePackedType(sema: *Sema, ty: Type) !bool { | |
| 26178 | const pt = sema.pt; | |
| 26179 | const zcu = pt.zcu; | |
| 26180 | return switch (ty.zigTypeTag(zcu)) { | |
| 26181 | .type, | |
| 26182 | .comptime_float, | |
| 26183 | .comptime_int, | |
| 26184 | .enum_literal, | |
| 26185 | .undefined, | |
| 26186 | .null, | |
| 26187 | .error_union, | |
| 26188 | .error_set, | |
| 26189 | .frame, | |
| 26190 | .noreturn, | |
| 26191 | .@"opaque", | |
| 26192 | .@"anyframe", | |
| 26193 | .@"fn", | |
| 26194 | .array, | |
| 26195 | => false, | |
| 26196 | .optional => return ty.isPtrLikeOptional(zcu), | |
| 26197 | .void, | |
| 26198 | .bool, | |
| 26199 | .float, | |
| 26200 | .int, | |
| 26201 | .vector, | |
| 26202 | => true, | |
| 26203 | .@"enum" => switch (zcu.intern_pool.loadEnumType(ty.toIntern()).tag_mode) { | |
| 26204 | .auto => false, | |
| 26205 | .explicit, .nonexhaustive => true, | |
| 26206 | }, | |
| 26207 | .pointer => !ty.isSlice(zcu) and !try ty.comptimeOnlySema(pt), | |
| 26208 | .@"struct", .@"union" => ty.containerLayout(zcu) == .@"packed", | |
| 26209 | }; | |
| 26210 | } | |
| 26211 | ||
| 26212 | fn explainWhyTypeIsNotPacked( | |
| 25480 | pub fn explainWhyTypeIsNotPackable( | |
| 26213 | 25481 | sema: *Sema, |
| 26214 | 25482 | msg: *Zcu.ErrorMsg, |
| 26215 | 25483 | src_loc: LazySrcLoc, |
| ... | ... | @@ -26250,8 +25518,8 @@ fn explainWhyTypeIsNotPacked( |
| 26250 | 25518 | try sema.errNote(src_loc, msg, "type has no guaranteed in-memory representation", .{}); |
| 26251 | 25519 | try sema.errNote(src_loc, msg, "use '*const ' to make a function pointer type", .{}); |
| 26252 | 25520 | }, |
| 26253 | .@"struct" => try sema.errNote(src_loc, msg, "only packed structs layout are allowed in packed types", .{}), | |
| 26254 | .@"union" => try sema.errNote(src_loc, msg, "only packed unions layout are allowed in packed types", .{}), | |
| 25521 | .@"struct" => try sema.errNote(src_loc, msg, "struct in packed type must have packed layout", .{}), | |
| 25522 | .@"union" => try sema.errNote(src_loc, msg, "union in packed type must have packed layout", .{}), | |
| 26255 | 25523 | } |
| 26256 | 25524 | } |
| 26257 | 25525 | |
| ... | ... | @@ -26277,7 +25545,7 @@ fn getPanicIdFunc(sema: *Sema, src: LazySrcLoc, panic_id: Zcu.SimplePanicId) !In |
| 26277 | 25545 | try sema.ensureMemoizedStateResolved(src, .panic); |
| 26278 | 25546 | const panic_fn_index = zcu.builtin_decl_values.get(panic_id.toBuiltin()); |
| 26279 | 25547 | switch (sema.owner.unwrap()) { |
| 26280 | .@"comptime", .nav_ty, .nav_val, .type, .memoized_state => {}, | |
| 25548 | .@"comptime", .nav_ty, .nav_val, .type_layout, .type_inits, .memoized_state => {}, | |
| 26281 | 25549 | .func => |owner_func| zcu.intern_pool.funcSetHasErrorTrace(io, owner_func, true), |
| 26282 | 25550 | } |
| 26283 | 25551 | return panic_fn_index; |
| ... | ... | @@ -26555,7 +25823,8 @@ fn fieldPtrLoad( |
| 26555 | 25823 | const zcu = pt.zcu; |
| 26556 | 25824 | const object_ptr_ty = sema.typeOf(object_ptr); |
| 26557 | 25825 | const pointee_ty = object_ptr_ty.childType(zcu); |
| 26558 | if (try typeHasOnePossibleValue(sema, pointee_ty)) |opv| { | |
| 25826 | try sema.ensureLayoutResolved(pointee_ty); // MLUGG TODO | |
| 25827 | if (try pointee_ty.onePossibleValue(pt)) |opv| { | |
| 26559 | 25828 | const object: Air.Inst.Ref = .fromValue(opv); |
| 26560 | 25829 | return fieldVal(sema, block, src, object, field_name, field_name_src); |
| 26561 | 25830 | } |
| ... | ... | @@ -26603,7 +25872,7 @@ fn fieldVal( |
| 26603 | 25872 | return Air.internedToRef((try pt.intValue(.usize, inner_ty.arrayLen(zcu))).toIntern()); |
| 26604 | 25873 | } else if (field_name.eqlSlice("ptr", ip) and is_pointer_to) { |
| 26605 | 25874 | const ptr_info = object_ty.ptrInfo(zcu); |
| 26606 | const result_ty = try pt.ptrTypeSema(.{ | |
| 25875 | const result_ty = try pt.ptrType(.{ | |
| 26607 | 25876 | .child = Type.fromInterned(ptr_info.child).childType(zcu).toIntern(), |
| 26608 | 25877 | .sentinel = if (inner_ty.sentinel(zcu)) |s| s.toIntern() else .none, |
| 26609 | 25878 | .flags = .{ |
| ... | ... | @@ -26693,7 +25962,6 @@ fn fieldVal( |
| 26693 | 25962 | if (try sema.namespaceLookupVal(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| { |
| 26694 | 25963 | return inst; |
| 26695 | 25964 | } |
| 26696 | try child_type.resolveFields(pt); | |
| 26697 | 25965 | if (child_type.unionTagType(zcu)) |enum_ty| { |
| 26698 | 25966 | if (enum_ty.enumFieldIndex(field_name, zcu)) |field_index_usize| { |
| 26699 | 25967 | const field_index: u32 = @intCast(field_index_usize); |
| ... | ... | @@ -26731,6 +25999,7 @@ fn fieldVal( |
| 26731 | 25999 | }, |
| 26732 | 26000 | .@"struct" => if (is_pointer_to) { |
| 26733 | 26001 | // Avoid loading the entire struct by fetching a pointer and loading that |
| 26002 | try sema.ensureLayoutResolved(inner_ty); | |
| 26734 | 26003 | const field_ptr = try sema.structFieldPtr(block, src, object, field_name, field_name_src, inner_ty, false); |
| 26735 | 26004 | return sema.analyzeLoad(block, src, field_ptr, object_src); |
| 26736 | 26005 | } else { |
| ... | ... | @@ -26738,6 +26007,7 @@ fn fieldVal( |
| 26738 | 26007 | }, |
| 26739 | 26008 | .@"union" => if (is_pointer_to) { |
| 26740 | 26009 | // Avoid loading the entire union by fetching a pointer and loading that |
| 26010 | try sema.ensureLayoutResolved(inner_ty); | |
| 26741 | 26011 | const field_ptr = try sema.unionFieldPtr(block, src, object, field_name, field_name_src, inner_ty, false); |
| 26742 | 26012 | return sema.analyzeLoad(block, src, field_ptr, object_src); |
| 26743 | 26013 | } else { |
| ... | ... | @@ -26787,7 +26057,7 @@ fn fieldPtr( |
| 26787 | 26057 | return uavRef(sema, int_val.toIntern()); |
| 26788 | 26058 | } else if (field_name.eqlSlice("ptr", ip) and is_pointer_to) { |
| 26789 | 26059 | const ptr_info = object_ty.ptrInfo(zcu); |
| 26790 | const new_ptr_ty = try pt.ptrTypeSema(.{ | |
| 26060 | const new_ptr_ty = try pt.ptrType(.{ | |
| 26791 | 26061 | .child = Type.fromInterned(ptr_info.child).childType(zcu).toIntern(), |
| 26792 | 26062 | .sentinel = if (inner_ty.sentinel(zcu)) |s| s.toIntern() else .none, |
| 26793 | 26063 | .flags = .{ |
| ... | ... | @@ -26802,7 +26072,7 @@ fn fieldPtr( |
| 26802 | 26072 | .packed_offset = ptr_info.packed_offset, |
| 26803 | 26073 | }); |
| 26804 | 26074 | const ptr_ptr_info = object_ptr_ty.ptrInfo(zcu); |
| 26805 | const result_ty = try pt.ptrTypeSema(.{ | |
| 26075 | const result_ty = try pt.ptrType(.{ | |
| 26806 | 26076 | .child = new_ptr_ty.toIntern(), |
| 26807 | 26077 | .sentinel = if (object_ptr_ty.sentinel(zcu)) |s| s.toIntern() else .none, |
| 26808 | 26078 | .flags = .{ |
| ... | ... | @@ -26836,7 +26106,7 @@ fn fieldPtr( |
| 26836 | 26106 | if (field_name.eqlSlice("ptr", ip)) { |
| 26837 | 26107 | const slice_ptr_ty = inner_ty.slicePtrFieldType(zcu); |
| 26838 | 26108 | |
| 26839 | const result_ty = try pt.ptrTypeSema(.{ | |
| 26109 | const result_ty = try pt.ptrType(.{ | |
| 26840 | 26110 | .child = slice_ptr_ty.toIntern(), |
| 26841 | 26111 | .flags = .{ |
| 26842 | 26112 | .is_const = !attr_ptr_ty.ptrIsMutable(zcu), |
| ... | ... | @@ -26854,7 +26124,7 @@ fn fieldPtr( |
| 26854 | 26124 | try sema.checkKnownAllocPtr(block, inner_ptr, field_ptr); |
| 26855 | 26125 | return field_ptr; |
| 26856 | 26126 | } else if (field_name.eqlSlice("len", ip)) { |
| 26857 | const result_ty = try pt.ptrTypeSema(.{ | |
| 26127 | const result_ty = try pt.ptrType(.{ | |
| 26858 | 26128 | .child = .usize_type, |
| 26859 | 26129 | .flags = .{ |
| 26860 | 26130 | .is_const = !attr_ptr_ty.ptrIsMutable(zcu), |
| ... | ... | @@ -26925,7 +26195,6 @@ fn fieldPtr( |
| 26925 | 26195 | if (try sema.namespaceLookupRef(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| { |
| 26926 | 26196 | return inst; |
| 26927 | 26197 | } |
| 26928 | try child_type.resolveFields(pt); | |
| 26929 | 26198 | if (child_type.unionTagType(zcu)) |enum_ty| { |
| 26930 | 26199 | if (enum_ty.enumFieldIndex(field_name, zcu)) |field_index| { |
| 26931 | 26200 | const field_index_u32: u32 = @intCast(field_index); |
| ... | ... | @@ -26960,6 +26229,7 @@ fn fieldPtr( |
| 26960 | 26229 | try sema.analyzeLoad(block, src, object_ptr, object_ptr_src) |
| 26961 | 26230 | else |
| 26962 | 26231 | object_ptr; |
| 26232 | try sema.ensureLayoutResolved(inner_ty); | |
| 26963 | 26233 | const field_ptr = try sema.structFieldPtr(block, src, inner_ptr, field_name, field_name_src, inner_ty, initializing); |
| 26964 | 26234 | try sema.checkKnownAllocPtr(block, inner_ptr, field_ptr); |
| 26965 | 26235 | return field_ptr; |
| ... | ... | @@ -26969,6 +26239,7 @@ fn fieldPtr( |
| 26969 | 26239 | try sema.analyzeLoad(block, src, object_ptr, object_ptr_src) |
| 26970 | 26240 | else |
| 26971 | 26241 | object_ptr; |
| 26242 | try sema.ensureLayoutResolved(inner_ty); | |
| 26972 | 26243 | const field_ptr = try sema.unionFieldPtr(block, src, inner_ptr, field_name, field_name_src, inner_ty, initializing); |
| 26973 | 26244 | try sema.checkKnownAllocPtr(block, inner_ptr, field_ptr); |
| 26974 | 26245 | return field_ptr; |
| ... | ... | @@ -27012,6 +26283,7 @@ fn fieldCallBind( |
| 27012 | 26283 | // Optionally dereference a second pointer to get the concrete type. |
| 27013 | 26284 | const is_double_ptr = inner_ty.zigTypeTag(zcu) == .pointer and inner_ty.ptrSize(zcu) == .one; |
| 27014 | 26285 | const concrete_ty = if (is_double_ptr) inner_ty.childType(zcu) else inner_ty; |
| 26286 | try sema.ensureLayoutResolved(concrete_ty); | |
| 27015 | 26287 | const ptr_ty = if (is_double_ptr) inner_ty else raw_ptr_ty; |
| 27016 | 26288 | const object_ptr = if (is_double_ptr) |
| 27017 | 26289 | try sema.analyzeLoad(block, src, raw_ptr, src) |
| ... | ... | @@ -27021,10 +26293,8 @@ fn fieldCallBind( |
| 27021 | 26293 | find_field: { |
| 27022 | 26294 | switch (concrete_ty.zigTypeTag(zcu)) { |
| 27023 | 26295 | .@"struct" => { |
| 27024 | try concrete_ty.resolveFields(pt); | |
| 27025 | 26296 | if (zcu.typeToStruct(concrete_ty)) |struct_type| { |
| 27026 | const field_index = struct_type.nameIndex(ip, field_name) orelse | |
| 27027 | break :find_field; | |
| 26297 | const field_index = struct_type.nameIndex(ip, field_name) orelse break :find_field; | |
| 27028 | 26298 | const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]); |
| 27029 | 26299 | |
| 27030 | 26300 | return sema.finishFieldCallBind(block, src, ptr_ty, field_ty, field_index, object_ptr); |
| ... | ... | @@ -27047,9 +26317,9 @@ fn fieldCallBind( |
| 27047 | 26317 | } |
| 27048 | 26318 | }, |
| 27049 | 26319 | .@"union" => { |
| 27050 | try concrete_ty.resolveFields(pt); | |
| 27051 | 26320 | const union_obj = zcu.typeToUnion(concrete_ty).?; |
| 27052 | _ = union_obj.loadTagType(ip).nameIndex(ip, field_name) orelse break :find_field; | |
| 26321 | const enum_obj = ip.loadEnumType(union_obj.enum_tag_type); | |
| 26322 | if (enum_obj.nameIndex(ip, field_name) == null) break :find_field; | |
| 27053 | 26323 | const field_ptr = try unionFieldPtr(sema, block, src, object_ptr, field_name, field_name_src, concrete_ty, false); |
| 27054 | 26324 | return .{ .direct = try sema.analyzeLoad(block, src, field_ptr, src) }; |
| 27055 | 26325 | }, |
| ... | ... | @@ -27163,7 +26433,7 @@ fn finishFieldCallBind( |
| 27163 | 26433 | ) CompileError!ResolvedFieldCallee { |
| 27164 | 26434 | const pt = sema.pt; |
| 27165 | 26435 | const zcu = pt.zcu; |
| 27166 | const ptr_field_ty = try pt.ptrTypeSema(.{ | |
| 26436 | const ptr_field_ty = try pt.ptrType(.{ | |
| 27167 | 26437 | .child = field_ty.toIntern(), |
| 27168 | 26438 | .flags = .{ |
| 27169 | 26439 | .is_const = !ptr_ty.ptrIsMutable(zcu), |
| ... | ... | @@ -27174,7 +26444,9 @@ fn finishFieldCallBind( |
| 27174 | 26444 | const container_ty = ptr_ty.childType(zcu); |
| 27175 | 26445 | if (container_ty.zigTypeTag(zcu) == .@"struct") { |
| 27176 | 26446 | if (container_ty.structFieldIsComptime(field_index, zcu)) { |
| 27177 | try container_ty.resolveStructFieldInits(pt); | |
| 26447 | if (!container_ty.isTuple(zcu)) { | |
| 26448 | try sema.ensureFieldInitsResolved(container_ty); | |
| 26449 | } | |
| 27178 | 26450 | const default_val = (try container_ty.structFieldValueComptime(pt, field_index)).?; |
| 27179 | 26451 | return .{ .direct = Air.internedToRef(default_val.toIntern()) }; |
| 27180 | 26452 | } |
| ... | ... | @@ -27239,6 +26511,7 @@ fn namespaceLookupVal( |
| 27239 | 26511 | return try sema.analyzeNavVal(block, src, nav); |
| 27240 | 26512 | } |
| 27241 | 26513 | |
| 26514 | /// Asserts that the layout of `struct_ty` is already resolved. | |
| 27242 | 26515 | fn structFieldPtr( |
| 27243 | 26516 | sema: *Sema, |
| 27244 | 26517 | block: *Block, |
| ... | ... | @@ -27252,10 +26525,9 @@ fn structFieldPtr( |
| 27252 | 26525 | const pt = sema.pt; |
| 27253 | 26526 | const zcu = pt.zcu; |
| 27254 | 26527 | const ip = &zcu.intern_pool; |
| 27255 | assert(struct_ty.zigTypeTag(zcu) == .@"struct"); | |
| 27256 | 26528 | |
| 27257 | try struct_ty.resolveFields(pt); | |
| 27258 | try struct_ty.resolveLayout(pt); | |
| 26529 | assert(struct_ty.zigTypeTag(zcu) == .@"struct"); | |
| 26530 | struct_ty.assertHasLayout(zcu); | |
| 27259 | 26531 | |
| 27260 | 26532 | if (struct_ty.isTuple(zcu)) { |
| 27261 | 26533 | if (field_name.eqlSlice("len", ip)) { |
| ... | ... | @@ -27274,6 +26546,7 @@ fn structFieldPtr( |
| 27274 | 26546 | return sema.structFieldPtrByIndex(block, src, struct_ptr, field_index, struct_ty); |
| 27275 | 26547 | } |
| 27276 | 26548 | |
| 26549 | /// Asserts that the layout of `struct_ty` is already resolved. | |
| 27277 | 26550 | fn structFieldPtrByIndex( |
| 27278 | 26551 | sema: *Sema, |
| 27279 | 26552 | block: *Block, |
| ... | ... | @@ -27286,8 +26559,10 @@ fn structFieldPtrByIndex( |
| 27286 | 26559 | const zcu = pt.zcu; |
| 27287 | 26560 | const ip = &zcu.intern_pool; |
| 27288 | 26561 | |
| 26562 | struct_ty.assertHasLayout(zcu); | |
| 26563 | ||
| 27289 | 26564 | const struct_type = zcu.typeToStruct(struct_ty).?; |
| 27290 | const field_is_comptime = struct_type.fieldIsComptime(ip, field_index); | |
| 26565 | const field_is_comptime = struct_type.field_is_comptime_bits.get(ip, field_index); | |
| 27291 | 26566 | |
| 27292 | 26567 | // Comptime fields are handled later |
| 27293 | 26568 | if (!field_is_comptime) { |
| ... | ... | @@ -27300,6 +26575,7 @@ fn structFieldPtrByIndex( |
| 27300 | 26575 | const field_ty = struct_type.field_types.get(ip)[field_index]; |
| 27301 | 26576 | const struct_ptr_ty = sema.typeOf(struct_ptr); |
| 27302 | 26577 | const struct_ptr_ty_info = struct_ptr_ty.ptrInfo(zcu); |
| 26578 | assert(struct_ptr_ty_info.child == struct_ty.toIntern()); | |
| 27303 | 26579 | |
| 27304 | 26580 | var ptr_ty_data: InternPool.Key.PtrType = .{ |
| 27305 | 26581 | .child = field_ty, |
| ... | ... | @@ -27313,7 +26589,7 @@ fn structFieldPtrByIndex( |
| 27313 | 26589 | const parent_align = if (struct_ptr_ty_info.flags.alignment != .none) |
| 27314 | 26590 | struct_ptr_ty_info.flags.alignment |
| 27315 | 26591 | else |
| 27316 | try Type.fromInterned(struct_ptr_ty_info.child).abiAlignmentSema(pt); | |
| 26592 | struct_ty.abiAlignment(zcu); | |
| 27317 | 26593 | |
| 27318 | 26594 | if (struct_type.layout == .@"packed") { |
| 27319 | 26595 | assert(!field_is_comptime); |
| ... | ... | @@ -27325,31 +26601,32 @@ fn structFieldPtrByIndex( |
| 27325 | 26601 | // For extern structs, field alignment might be bigger than type's |
| 27326 | 26602 | // natural alignment. Eg, in `extern struct { x: u32, y: u16 }` the |
| 27327 | 26603 | // second field is aligned as u32. |
| 27328 | const field_offset = struct_ty.structFieldOffset(field_index, zcu); | |
| 27329 | ptr_ty_data.flags.alignment = if (parent_align == .none) | |
| 27330 | .none | |
| 27331 | else | |
| 27332 | @enumFromInt(@min(@intFromEnum(parent_align), @ctz(field_offset))); | |
| 26604 | ptr_ty_data.flags.alignment = a: { | |
| 26605 | const field_off = struct_ty.structFieldOffset(field_index, zcu); | |
| 26606 | if (field_off == 0) break :a struct_ptr_ty_info.flags.alignment; | |
| 26607 | const true_field_align: Alignment = .fromLog2Units(@ctz(field_off)); | |
| 26608 | if (struct_ptr_ty_info.flags.alignment == .none and | |
| 26609 | true_field_align == Type.fromInterned(field_ty).abiAlignment(zcu)) | |
| 26610 | { | |
| 26611 | break :a .none; | |
| 26612 | } | |
| 26613 | break :a .minStrict(true_field_align, parent_align); | |
| 26614 | }; | |
| 27333 | 26615 | } else { |
| 27334 | 26616 | // Our alignment is capped at the field alignment. |
| 27335 | const field_align = try Type.fromInterned(field_ty).structFieldAlignmentSema( | |
| 27336 | struct_type.fieldAlign(ip, field_index), | |
| 27337 | struct_type.layout, | |
| 27338 | pt, | |
| 27339 | ); | |
| 27340 | 26617 | ptr_ty_data.flags.alignment = if (struct_ptr_ty_info.flags.alignment == .none) |
| 27341 | field_align | |
| 26618 | struct_ty.explicitFieldAlignment(field_index, zcu) | |
| 27342 | 26619 | else |
| 27343 | field_align.min(parent_align); | |
| 26620 | struct_ty.resolvedFieldAlignment(field_index, zcu).min(parent_align); | |
| 27344 | 26621 | } |
| 27345 | 26622 | |
| 27346 | const ptr_field_ty = try pt.ptrTypeSema(ptr_ty_data); | |
| 26623 | const ptr_field_ty = try pt.ptrType(ptr_ty_data); | |
| 27347 | 26624 | |
| 27348 | 26625 | if (field_is_comptime) { |
| 27349 | try struct_ty.resolveStructFieldInits(pt); | |
| 26626 | try sema.ensureFieldInitsResolved(struct_ty); | |
| 27350 | 26627 | const val = try pt.intern(.{ .ptr = .{ |
| 27351 | 26628 | .ty = ptr_field_ty.toIntern(), |
| 27352 | .base_addr = .{ .comptime_field = struct_type.field_inits.get(ip)[field_index] }, | |
| 26629 | .base_addr = .{ .comptime_field = struct_type.field_defaults.get(ip)[field_index] }, | |
| 27353 | 26630 | .byte_offset = 0, |
| 27354 | 26631 | } }); |
| 27355 | 26632 | return Air.internedToRef(val); |
| ... | ... | @@ -27371,32 +26648,26 @@ fn structFieldVal( |
| 27371 | 26648 | const ip = &zcu.intern_pool; |
| 27372 | 26649 | assert(struct_ty.zigTypeTag(zcu) == .@"struct"); |
| 27373 | 26650 | |
| 27374 | try struct_ty.resolveFields(pt); | |
| 27375 | ||
| 27376 | 26651 | switch (ip.indexToKey(struct_ty.toIntern())) { |
| 27377 | 26652 | .struct_type => { |
| 27378 | 26653 | const struct_type = ip.loadStructType(struct_ty.toIntern()); |
| 27379 | 26654 | |
| 27380 | 26655 | const field_index = struct_type.nameIndex(ip, field_name) orelse |
| 27381 | 26656 | return sema.failWithBadStructFieldAccess(block, struct_ty, struct_type, field_name_src, field_name); |
| 27382 | if (struct_type.fieldIsComptime(ip, field_index)) { | |
| 27383 | try struct_ty.resolveStructFieldInits(pt); | |
| 27384 | return Air.internedToRef(struct_type.field_inits.get(ip)[field_index]); | |
| 26657 | if (struct_type.field_is_comptime_bits.get(ip, field_index)) { | |
| 26658 | try sema.ensureFieldInitsResolved(struct_ty); | |
| 26659 | return .fromIntern(struct_type.field_defaults.get(ip)[field_index]); | |
| 27385 | 26660 | } |
| 27386 | 26661 | |
| 27387 | 26662 | const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]); |
| 27388 | if (try sema.typeHasOnePossibleValue(field_ty)) |field_val| | |
| 27389 | return Air.internedToRef(field_val.toIntern()); | |
| 26663 | if (try field_ty.onePossibleValue(pt)) |field_val| | |
| 26664 | return .fromValue(field_val); | |
| 27390 | 26665 | |
| 27391 | 26666 | if (try sema.resolveValue(struct_byval)) |struct_val| { |
| 27392 | 26667 | if (struct_val.isUndef(zcu)) return pt.undefRef(field_ty); |
| 27393 | if ((try sema.typeHasOnePossibleValue(field_ty))) |opv| { | |
| 27394 | return Air.internedToRef(opv.toIntern()); | |
| 27395 | } | |
| 27396 | return Air.internedToRef((try struct_val.fieldValue(pt, field_index)).toIntern()); | |
| 26668 | return .fromValue(try struct_val.fieldValue(pt, field_index)); | |
| 27397 | 26669 | } |
| 27398 | 26670 | |
| 27399 | try field_ty.resolveLayout(pt); | |
| 27400 | 26671 | return block.addStructFieldVal(struct_byval, field_index, field_ty); |
| 27401 | 26672 | }, |
| 27402 | 26673 | .tuple_type => { |
| ... | ... | @@ -27457,16 +26728,13 @@ fn tupleFieldValByIndex( |
| 27457 | 26728 | const zcu = pt.zcu; |
| 27458 | 26729 | const field_ty = tuple_ty.fieldType(field_index, zcu); |
| 27459 | 26730 | |
| 27460 | if (tuple_ty.structFieldIsComptime(field_index, zcu)) | |
| 27461 | try tuple_ty.resolveStructFieldInits(pt); | |
| 27462 | 26731 | if (try tuple_ty.structFieldValueComptime(pt, field_index)) |default_value| { |
| 27463 | 26732 | return Air.internedToRef(default_value.toIntern()); |
| 27464 | 26733 | } |
| 27465 | 26734 | |
| 26735 | if (try field_ty.onePossibleValue(pt)) |opv| return .fromValue(opv); | |
| 26736 | ||
| 27466 | 26737 | if (try sema.resolveValue(tuple_byval)) |tuple_val| { |
| 27467 | if ((try sema.typeHasOnePossibleValue(field_ty))) |opv| { | |
| 27468 | return Air.internedToRef(opv.toIntern()); | |
| 27469 | } | |
| 27470 | 26738 | return switch (zcu.intern_pool.indexToKey(tuple_val.toIntern())) { |
| 27471 | 26739 | .undef => pt.undefRef(field_ty), |
| 27472 | 26740 | .aggregate => |aggregate| Air.internedToRef(switch (aggregate.storage) { |
| ... | ... | @@ -27478,10 +26746,10 @@ fn tupleFieldValByIndex( |
| 27478 | 26746 | }; |
| 27479 | 26747 | } |
| 27480 | 26748 | |
| 27481 | try field_ty.resolveLayout(pt); | |
| 27482 | 26749 | return block.addStructFieldVal(tuple_byval, field_index, field_ty); |
| 27483 | 26750 | } |
| 27484 | 26751 | |
| 26752 | /// Asserts that the layout of `union_ty` is already resolved. | |
| 27485 | 26753 | fn unionFieldPtr( |
| 27486 | 26754 | sema: *Sema, |
| 27487 | 26755 | block: *Block, |
| ... | ... | @@ -27497,31 +26765,31 @@ fn unionFieldPtr( |
| 27497 | 26765 | const ip = &zcu.intern_pool; |
| 27498 | 26766 | |
| 27499 | 26767 | assert(union_ty.zigTypeTag(zcu) == .@"union"); |
| 26768 | union_ty.assertHasLayout(zcu); | |
| 27500 | 26769 | |
| 27501 | 26770 | const union_ptr_ty = sema.typeOf(union_ptr); |
| 27502 | 26771 | const union_ptr_info = union_ptr_ty.ptrInfo(zcu); |
| 27503 | try union_ty.resolveFields(pt); | |
| 27504 | 26772 | const union_obj = zcu.typeToUnion(union_ty).?; |
| 27505 | 26773 | const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src); |
| 27506 | 26774 | const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]); |
| 27507 | const ptr_field_ty = try pt.ptrTypeSema(.{ | |
| 26775 | const ptr_field_ty = try pt.ptrType(.{ | |
| 27508 | 26776 | .child = field_ty.toIntern(), |
| 27509 | 26777 | .flags = .{ |
| 27510 | 26778 | .is_const = union_ptr_info.flags.is_const, |
| 27511 | 26779 | .is_volatile = union_ptr_info.flags.is_volatile, |
| 27512 | 26780 | .address_space = union_ptr_info.flags.address_space, |
| 27513 | .alignment = if (union_obj.flagsUnordered(ip).layout == .auto) blk: { | |
| 27514 | const union_align = if (union_ptr_info.flags.alignment != .none) | |
| 27515 | union_ptr_info.flags.alignment | |
| 27516 | else | |
| 27517 | try union_ty.abiAlignmentSema(pt); | |
| 27518 | const field_align = try union_ty.fieldAlignmentSema(field_index, pt); | |
| 27519 | break :blk union_align.min(field_align); | |
| 27520 | } else union_ptr_info.flags.alignment, | |
| 26781 | .alignment = a: { | |
| 26782 | if (union_obj.layout != .auto) break :a union_ptr_info.flags.alignment; | |
| 26783 | if (union_ptr_info.flags.alignment == .none) { | |
| 26784 | break :a union_ty.explicitFieldAlignment(field_index, zcu); | |
| 26785 | } | |
| 26786 | const field_align = union_ty.resolvedFieldAlignment(field_index, zcu); | |
| 26787 | break :a union_ptr_info.flags.alignment.min(field_align); | |
| 26788 | }, | |
| 27521 | 26789 | }, |
| 27522 | 26790 | .packed_offset = union_ptr_info.packed_offset, |
| 27523 | 26791 | }); |
| 27524 | const enum_field_index: u32 = @intCast(Type.fromInterned(union_obj.enum_tag_ty).enumFieldIndex(field_name, zcu).?); | |
| 26792 | const enum_field_index: u32 = @intCast(Type.fromInterned(union_obj.enum_tag_type).enumFieldIndex(field_name, zcu).?); | |
| 27525 | 26793 | |
| 27526 | 26794 | if (initializing and field_ty.zigTypeTag(zcu) == .noreturn) { |
| 27527 | 26795 | const msg = msg: { |
| ... | ... | @@ -27538,16 +26806,16 @@ fn unionFieldPtr( |
| 27538 | 26806 | } |
| 27539 | 26807 | |
| 27540 | 26808 | if (try sema.resolveDefinedValue(block, src, union_ptr)) |union_ptr_val| ct: { |
| 27541 | switch (union_obj.flagsUnordered(ip).layout) { | |
| 26809 | switch (union_obj.layout) { | |
| 27542 | 26810 | .auto => if (initializing) { |
| 27543 | 26811 | if (!sema.isComptimeMutablePtr(union_ptr_val)) { |
| 27544 | 26812 | // The initialization is a runtime operation. |
| 27545 | 26813 | break :ct; |
| 27546 | 26814 | } |
| 27547 | 26815 | // Store to the union to initialize the tag. |
| 27548 | const field_tag = try pt.enumValueFieldIndex(.fromInterned(union_obj.enum_tag_ty), enum_field_index); | |
| 26816 | const field_tag = try pt.enumValueFieldIndex(.fromInterned(union_obj.enum_tag_type), enum_field_index); | |
| 27549 | 26817 | const payload_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]); |
| 27550 | const new_union_val = try pt.unionValue(union_ty, field_tag, try pt.undefValue(payload_ty)); | |
| 26818 | const new_union_val = try pt.unionValue(union_ty, field_tag, try payload_ty.onePossibleValue(pt) orelse try pt.undefValue(payload_ty)); | |
| 27551 | 26819 | try sema.storePtrVal(block, src, union_ptr_val, new_union_val, union_ty); |
| 27552 | 26820 | } else { |
| 27553 | 26821 | const union_val = (try sema.pointerDeref(block, src, union_ptr_val, union_ptr_ty)) orelse |
| ... | ... | @@ -27556,12 +26824,12 @@ fn unionFieldPtr( |
| 27556 | 26824 | return sema.failWithUseOfUndef(block, src, null); |
| 27557 | 26825 | } |
| 27558 | 26826 | const un = ip.indexToKey(union_val.toIntern()).un; |
| 27559 | const field_tag = try pt.enumValueFieldIndex(.fromInterned(union_obj.enum_tag_ty), enum_field_index); | |
| 26827 | const field_tag = try pt.enumValueFieldIndex(.fromInterned(union_obj.enum_tag_type), enum_field_index); | |
| 27560 | 26828 | const tag_matches = un.tag == field_tag.toIntern(); |
| 27561 | 26829 | if (!tag_matches) { |
| 27562 | 26830 | const msg = msg: { |
| 27563 | const active_index = Type.fromInterned(union_obj.enum_tag_ty).enumTagFieldIndex(Value.fromInterned(un.tag), zcu).?; | |
| 27564 | const active_field_name = Type.fromInterned(union_obj.enum_tag_ty).enumFieldName(active_index, zcu); | |
| 26831 | const active_index = Type.fromInterned(union_obj.enum_tag_type).enumTagFieldIndex(Value.fromInterned(un.tag), zcu).?; | |
| 26832 | const active_field_name = Type.fromInterned(union_obj.enum_tag_type).enumFieldName(active_index, zcu); | |
| 27565 | 26833 | const msg = try sema.errMsg(src, "access of union field '{f}' while field '{f}' is active", .{ |
| 27566 | 26834 | field_name.fmt(ip), |
| 27567 | 26835 | active_field_name.fmt(ip), |
| ... | ... | @@ -27582,15 +26850,15 @@ fn unionFieldPtr( |
| 27582 | 26850 | // If the union has a tag, we must either set or or safety check it depending on `initializing`. |
| 27583 | 26851 | tag: { |
| 27584 | 26852 | if (union_ty.containerLayout(zcu) != .auto) break :tag; |
| 27585 | const tag_ty: Type = .fromInterned(union_obj.enum_tag_ty); | |
| 27586 | if (try sema.typeHasOnePossibleValue(tag_ty) != null) break :tag; | |
| 26853 | const tag_ty: Type = .fromInterned(union_obj.enum_tag_type); | |
| 26854 | if (try tag_ty.onePossibleValue(pt) != null) break :tag; | |
| 27587 | 26855 | // There is a hypothetical non-trivial tag. We must set it even if not there at runtime, but |
| 27588 | 26856 | // only emit a safety check if it's available at runtime (i.e. it's safety-tagged). |
| 27589 | 26857 | const want_tag = try pt.enumValueFieldIndex(tag_ty, enum_field_index); |
| 27590 | 26858 | if (initializing) { |
| 27591 | 26859 | const set_tag_inst = try block.addBinOp(.set_union_tag, union_ptr, .fromValue(want_tag)); |
| 27592 | 26860 | try sema.checkComptimeKnownStore(block, set_tag_inst, .unneeded); // `unneeded` since this isn't a "proper" store |
| 27593 | } else if (block.wantSafety() and union_obj.hasTag(ip)) { | |
| 26861 | } else if (block.wantSafety() and union_obj.runtime_tag != .none) { | |
| 27594 | 26862 | // The tag exists at runtime (safety tag), so emit a safety check. |
| 27595 | 26863 | // TODO would it be better if get_union_tag supported pointers to unions? |
| 27596 | 26864 | const union_val = try block.addTyOp(.load, union_ty, union_ptr); |
| ... | ... | @@ -27619,26 +26887,25 @@ fn unionFieldVal( |
| 27619 | 26887 | const ip = &zcu.intern_pool; |
| 27620 | 26888 | assert(union_ty.zigTypeTag(zcu) == .@"union"); |
| 27621 | 26889 | |
| 27622 | try union_ty.resolveFields(pt); | |
| 27623 | 26890 | const union_obj = zcu.typeToUnion(union_ty).?; |
| 27624 | 26891 | const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src); |
| 27625 | 26892 | const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]); |
| 27626 | const enum_field_index: u32 = @intCast(Type.fromInterned(union_obj.enum_tag_ty).enumFieldIndex(field_name, zcu).?); | |
| 26893 | const enum_field_index: u32 = @intCast(Type.fromInterned(union_obj.enum_tag_type).enumFieldIndex(field_name, zcu).?); | |
| 27627 | 26894 | |
| 27628 | 26895 | if (try sema.resolveValue(union_byval)) |union_val| { |
| 27629 | 26896 | if (union_val.isUndef(zcu)) return pt.undefRef(field_ty); |
| 27630 | 26897 | |
| 27631 | 26898 | const un = ip.indexToKey(union_val.toIntern()).un; |
| 27632 | const field_tag = try pt.enumValueFieldIndex(.fromInterned(union_obj.enum_tag_ty), enum_field_index); | |
| 26899 | const field_tag = try pt.enumValueFieldIndex(.fromInterned(union_obj.enum_tag_type), enum_field_index); | |
| 27633 | 26900 | const tag_matches = un.tag == field_tag.toIntern(); |
| 27634 | switch (union_obj.flagsUnordered(ip).layout) { | |
| 26901 | switch (union_obj.layout) { | |
| 27635 | 26902 | .auto => { |
| 27636 | 26903 | if (tag_matches) { |
| 27637 | 26904 | return Air.internedToRef(un.val); |
| 27638 | 26905 | } else { |
| 27639 | 26906 | const msg = msg: { |
| 27640 | const active_index = Type.fromInterned(union_obj.enum_tag_ty).enumTagFieldIndex(Value.fromInterned(un.tag), zcu).?; | |
| 27641 | const active_field_name = Type.fromInterned(union_obj.enum_tag_ty).enumFieldName(active_index, zcu); | |
| 26907 | const active_index = Type.fromInterned(union_obj.enum_tag_type).enumTagFieldIndex(Value.fromInterned(un.tag), zcu).?; | |
| 26908 | const active_field_name = Type.fromInterned(union_obj.enum_tag_type).enumFieldName(active_index, zcu); | |
| 27642 | 26909 | const msg = try sema.errMsg(src, "access of union field '{f}' while field '{f}' is active", .{ |
| 27643 | 26910 | field_name.fmt(ip), active_field_name.fmt(ip), |
| 27644 | 26911 | }); |
| ... | ... | @@ -27658,18 +26925,18 @@ fn unionFieldVal( |
| 27658 | 26925 | .@"packed" => if (tag_matches) { |
| 27659 | 26926 | // Fast path - no need to use bitcast logic. |
| 27660 | 26927 | return Air.internedToRef(un.val); |
| 27661 | } else if (try sema.bitCastVal(union_val, field_ty, 0, try union_ty.bitSizeSema(pt), 0)) |field_val| { | |
| 26928 | } else if (try sema.bitCastVal(union_val, field_ty, 0, union_ty.bitSize(zcu), 0)) |field_val| { | |
| 27662 | 26929 | return Air.internedToRef(field_val.toIntern()); |
| 27663 | 26930 | }, |
| 27664 | 26931 | } |
| 27665 | 26932 | } |
| 27666 | 26933 | |
| 27667 | if (union_obj.flagsUnordered(ip).layout == .auto and block.wantSafety() and | |
| 26934 | if (union_obj.layout == .auto and block.wantSafety() and | |
| 27668 | 26935 | union_ty.unionTagTypeSafety(zcu) != null and union_obj.field_types.len > 1) |
| 27669 | 26936 | { |
| 27670 | const wanted_tag_val = try pt.enumValueFieldIndex(.fromInterned(union_obj.enum_tag_ty), enum_field_index); | |
| 26937 | const wanted_tag_val = try pt.enumValueFieldIndex(.fromInterned(union_obj.enum_tag_type), enum_field_index); | |
| 27671 | 26938 | const wanted_tag = Air.internedToRef(wanted_tag_val.toIntern()); |
| 27672 | const active_tag = try block.addTyOp(.get_union_tag, .fromInterned(union_obj.enum_tag_ty), union_byval); | |
| 26939 | const active_tag = try block.addTyOp(.get_union_tag, .fromInterned(union_obj.enum_tag_type), union_byval); | |
| 27673 | 26940 | try sema.addSafetyCheckInactiveUnionField(block, src, active_tag, wanted_tag); |
| 27674 | 26941 | } |
| 27675 | 26942 | |
| ... | ... | @@ -27678,11 +26945,8 @@ fn unionFieldVal( |
| 27678 | 26945 | return .unreachable_value; |
| 27679 | 26946 | } |
| 27680 | 26947 | |
| 27681 | if (try sema.typeHasOnePossibleValue(field_ty)) |field_only_value| { | |
| 27682 | return Air.internedToRef(field_only_value.toIntern()); | |
| 27683 | } | |
| 26948 | if (try field_ty.onePossibleValue(pt)) |opv| return .fromValue(opv); | |
| 27684 | 26949 | |
| 27685 | try field_ty.resolveLayout(pt); | |
| 27686 | 26950 | return block.addStructFieldVal(union_byval, field_index, field_ty); |
| 27687 | 26951 | } |
| 27688 | 26952 | |
| ... | ... | @@ -27706,17 +26970,19 @@ fn elemPtr( |
| 27706 | 26970 | else => return sema.fail(block, indexable_ptr_src, "expected pointer, found '{f}'", .{indexable_ptr_ty.fmt(pt)}), |
| 27707 | 26971 | }; |
| 27708 | 26972 | try sema.checkIndexable(block, src, indexable_ty); |
| 26973 | try sema.ensureLayoutResolved(indexable_ty); | |
| 27709 | 26974 | |
| 27710 | 26975 | const elem_ptr = switch (indexable_ty.zigTypeTag(zcu)) { |
| 27711 | 26976 | .array, .vector => try sema.elemPtrArray(block, src, indexable_ptr_src, indexable_ptr, elem_index_src, elem_index, init, oob_safety), |
| 27712 | 26977 | .@"struct" => blk: { |
| 27713 | 26978 | // Tuple field access. |
| 27714 | 26979 | const index_val = try sema.resolveConstDefinedValue(block, elem_index_src, elem_index, .{ .simple = .tuple_field_index }); |
| 27715 | const index: u32 = @intCast(try index_val.toUnsignedIntSema(pt)); | |
| 26980 | const index: u32 = @intCast(index_val.toUnsignedInt(zcu)); | |
| 27716 | 26981 | break :blk try sema.tupleFieldPtr(block, src, indexable_ptr, elem_index_src, index, init); |
| 27717 | 26982 | }, |
| 27718 | 26983 | else => { |
| 27719 | 26984 | const indexable = try sema.analyzeLoad(block, indexable_ptr_src, indexable_ptr, indexable_ptr_src); |
| 26985 | try sema.ensureLayoutResolved(sema.typeOf(indexable).childType(zcu)); | |
| 27720 | 26986 | return elemPtrOneLayerOnly(sema, block, src, indexable, elem_index, elem_index_src, init, oob_safety); |
| 27721 | 26987 | }, |
| 27722 | 26988 | }; |
| ... | ... | @@ -27725,7 +26991,7 @@ fn elemPtr( |
| 27725 | 26991 | return elem_ptr; |
| 27726 | 26992 | } |
| 27727 | 26993 | |
| 27728 | /// Asserts that the type of indexable is pointer. | |
| 26994 | /// Asserts that `indexable` is an indexable pointer whose child type has its layout already resolved. | |
| 27729 | 26995 | fn elemPtrOneLayerOnly( |
| 27730 | 26996 | sema: *Sema, |
| 27731 | 26997 | block: *Block, |
| ... | ... | @@ -27741,7 +27007,10 @@ fn elemPtrOneLayerOnly( |
| 27741 | 27007 | const pt = sema.pt; |
| 27742 | 27008 | const zcu = pt.zcu; |
| 27743 | 27009 | |
| 27744 | try sema.checkIndexable(block, src, indexable_ty); | |
| 27010 | assert(indexable_ty.isIndexable(zcu)); | |
| 27011 | assert(indexable_ty.zigTypeTag(zcu) == .pointer); | |
| 27012 | const child_ty = indexable_ty.childType(zcu); | |
| 27013 | child_ty.assertHasLayout(zcu); | |
| 27745 | 27014 | |
| 27746 | 27015 | switch (indexable_ty.ptrSize(zcu)) { |
| 27747 | 27016 | .slice => return sema.elemPtrSlice(block, src, indexable_src, indexable, elem_index_src, elem_index, oob_safety), |
| ... | ... | @@ -27751,7 +27020,7 @@ fn elemPtrOneLayerOnly( |
| 27751 | 27020 | ct: { |
| 27752 | 27021 | const ptr_val = maybe_ptr_val orelse break :ct; |
| 27753 | 27022 | const index_val = maybe_index_val orelse break :ct; |
| 27754 | const index: usize = @intCast(try index_val.toUnsignedIntSema(pt)); | |
| 27023 | const index: usize = @intCast(index_val.toUnsignedInt(zcu)); | |
| 27755 | 27024 | const elem_ptr = try ptr_val.ptrElem(index, pt); |
| 27756 | 27025 | return Air.internedToRef(elem_ptr.toIntern()); |
| 27757 | 27026 | } |
| ... | ... | @@ -27762,7 +27031,7 @@ fn elemPtrOneLayerOnly( |
| 27762 | 27031 | try sema.validateRuntimeElemAccess(block, elem_index_src, result_ty, indexable_ty, indexable_src); |
| 27763 | 27032 | try sema.validateRuntimeValue(block, indexable_src, indexable); |
| 27764 | 27033 | |
| 27765 | if (!try result_ty.childType(zcu).hasRuntimeBitsIgnoreComptimeSema(pt)) { | |
| 27034 | if (result_ty.childType(zcu).abiSize(zcu) == 0) { | |
| 27766 | 27035 | // zero-bit child type; just bitcast the pointer |
| 27767 | 27036 | return block.addBitCast(result_ty, indexable); |
| 27768 | 27037 | } |
| ... | ... | @@ -27770,13 +27039,12 @@ fn elemPtrOneLayerOnly( |
| 27770 | 27039 | return block.addPtrElemPtr(indexable, elem_index, result_ty); |
| 27771 | 27040 | }, |
| 27772 | 27041 | .one => { |
| 27773 | const child_ty = indexable_ty.childType(zcu); | |
| 27774 | 27042 | const elem_ptr = switch (child_ty.zigTypeTag(zcu)) { |
| 27775 | 27043 | .array, .vector => try sema.elemPtrArray(block, src, indexable_src, indexable, elem_index_src, elem_index, init, oob_safety), |
| 27776 | 27044 | .@"struct" => blk: { |
| 27777 | 27045 | assert(child_ty.isTuple(zcu)); |
| 27778 | 27046 | const index_val = try sema.resolveConstDefinedValue(block, elem_index_src, elem_index, .{ .simple = .tuple_field_index }); |
| 27779 | const index: u32 = @intCast(try index_val.toUnsignedIntSema(pt)); | |
| 27047 | const index: u32 = @intCast(index_val.toUnsignedInt(zcu)); | |
| 27780 | 27048 | break :blk try sema.tupleFieldPtr(block, indexable_src, indexable, elem_index_src, index, false); |
| 27781 | 27049 | }, |
| 27782 | 27050 | else => unreachable, // Guaranteed by checkIndexable |
| ... | ... | @@ -27808,45 +27076,45 @@ fn elemVal( |
| 27808 | 27076 | const elem_index = try sema.coerce(block, .usize, elem_index_uncasted, elem_index_src); |
| 27809 | 27077 | |
| 27810 | 27078 | switch (indexable_ty.zigTypeTag(zcu)) { |
| 27811 | .pointer => switch (indexable_ty.ptrSize(zcu)) { | |
| 27812 | .slice => return sema.elemValSlice(block, src, indexable_src, indexable, elem_index_src, elem_index, oob_safety), | |
| 27813 | .many, .c => { | |
| 27814 | const maybe_indexable_val = try sema.resolveDefinedValue(block, indexable_src, indexable); | |
| 27815 | const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); | |
| 27816 | const elem_ty = indexable_ty.elemType2(zcu); | |
| 27817 | ||
| 27818 | ct: { | |
| 27819 | const indexable_val = maybe_indexable_val orelse break :ct; | |
| 27820 | const index_val = maybe_index_val orelse break :ct; | |
| 27821 | const index: usize = @intCast(try index_val.toUnsignedIntSema(pt)); | |
| 27822 | const many_ptr_ty = try pt.manyConstPtrType(elem_ty); | |
| 27823 | const many_ptr_val = try pt.getCoerced(indexable_val, many_ptr_ty); | |
| 27824 | const elem_ptr_ty = try pt.singleConstPtrType(elem_ty); | |
| 27825 | const elem_ptr_val = try many_ptr_val.ptrElem(index, pt); | |
| 27826 | const elem_val = try sema.pointerDeref(block, indexable_src, elem_ptr_val, elem_ptr_ty) orelse break :ct; | |
| 27827 | return Air.internedToRef((try pt.getCoerced(elem_val, elem_ty)).toIntern()); | |
| 27828 | } | |
| 27079 | .pointer => { | |
| 27080 | const child_ty = indexable_ty.childType(zcu); | |
| 27081 | try sema.ensureLayoutResolved(child_ty); | |
| 27082 | switch (indexable_ty.ptrSize(zcu)) { | |
| 27083 | .slice => return sema.elemValSlice(block, src, indexable_src, indexable, elem_index_src, elem_index, oob_safety), | |
| 27084 | .many, .c => { | |
| 27085 | const maybe_indexable_val = try sema.resolveDefinedValue(block, indexable_src, indexable); | |
| 27086 | const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); | |
| 27087 | ||
| 27088 | ct: { | |
| 27089 | const indexable_val = maybe_indexable_val orelse break :ct; | |
| 27090 | const index_val = maybe_index_val orelse break :ct; | |
| 27091 | const index: usize = @intCast(index_val.toUnsignedInt(zcu)); | |
| 27092 | const many_ptr_ty = try pt.manyConstPtrType(child_ty); | |
| 27093 | const many_ptr_val = try pt.getCoerced(indexable_val, many_ptr_ty); | |
| 27094 | const elem_ptr_ty = try pt.singleConstPtrType(child_ty); | |
| 27095 | const elem_ptr_val = try many_ptr_val.ptrElem(index, pt); | |
| 27096 | const elem_val = try sema.pointerDeref(block, indexable_src, elem_ptr_val, elem_ptr_ty) orelse break :ct; | |
| 27097 | return Air.internedToRef((try pt.getCoerced(elem_val, child_ty)).toIntern()); | |
| 27098 | } | |
| 27829 | 27099 | |
| 27830 | if (try sema.typeHasOnePossibleValue(elem_ty)) |elem_only_value| { | |
| 27831 | return Air.internedToRef(elem_only_value.toIntern()); | |
| 27832 | } | |
| 27100 | if (try child_ty.onePossibleValue(pt)) |opv| return .fromValue(opv); | |
| 27833 | 27101 | |
| 27834 | try sema.checkLogicalPtrOperation(block, src, indexable_ty); | |
| 27835 | return block.addBinOp(.ptr_elem_val, indexable, elem_index); | |
| 27836 | }, | |
| 27837 | .one => { | |
| 27838 | arr_sent: { | |
| 27839 | const inner_ty = indexable_ty.childType(zcu); | |
| 27840 | if (inner_ty.zigTypeTag(zcu) != .array) break :arr_sent; | |
| 27841 | const sentinel = inner_ty.sentinel(zcu) orelse break :arr_sent; | |
| 27842 | const index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index) orelse break :arr_sent; | |
| 27843 | const index = try sema.usizeCast(block, src, try index_val.toUnsignedIntSema(pt)); | |
| 27844 | if (index != inner_ty.arrayLen(zcu)) break :arr_sent; | |
| 27845 | return Air.internedToRef(sentinel.toIntern()); | |
| 27846 | } | |
| 27847 | const elem_ptr = try sema.elemPtr(block, indexable_src, indexable, elem_index, elem_index_src, false, oob_safety); | |
| 27848 | return sema.analyzeLoad(block, indexable_src, elem_ptr, elem_index_src); | |
| 27849 | }, | |
| 27102 | try sema.checkLogicalPtrOperation(block, src, indexable_ty); | |
| 27103 | return block.addBinOp(.ptr_elem_val, indexable, elem_index); | |
| 27104 | }, | |
| 27105 | .one => { | |
| 27106 | arr_sent: { | |
| 27107 | if (child_ty.zigTypeTag(zcu) != .array) break :arr_sent; | |
| 27108 | const sentinel = child_ty.sentinel(zcu) orelse break :arr_sent; | |
| 27109 | const index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index) orelse break :arr_sent; | |
| 27110 | const index = try sema.usizeCast(block, src, index_val.toUnsignedInt(zcu)); | |
| 27111 | if (index != child_ty.arrayLen(zcu)) break :arr_sent; | |
| 27112 | return .fromValue(sentinel); | |
| 27113 | } | |
| 27114 | const elem_ptr = try sema.elemPtr(block, indexable_src, indexable, elem_index, elem_index_src, false, oob_safety); | |
| 27115 | return sema.analyzeLoad(block, indexable_src, elem_ptr, elem_index_src); | |
| 27116 | }, | |
| 27117 | } | |
| 27850 | 27118 | }, |
| 27851 | 27119 | .array => return sema.elemValArray(block, src, indexable_src, indexable, elem_index_src, elem_index, oob_safety), |
| 27852 | 27120 | .vector => { |
| ... | ... | @@ -27856,7 +27124,7 @@ fn elemVal( |
| 27856 | 27124 | .@"struct" => { |
| 27857 | 27125 | // Tuple field access. |
| 27858 | 27126 | const index_val = try sema.resolveConstDefinedValue(block, elem_index_src, elem_index, .{ .simple = .tuple_field_index }); |
| 27859 | const index: u32 = @intCast(try index_val.toUnsignedIntSema(pt)); | |
| 27127 | const index: u32 = @intCast(index_val.toUnsignedInt(zcu)); | |
| 27860 | 27128 | return sema.tupleField(block, indexable_src, indexable, elem_index_src, index); |
| 27861 | 27129 | }, |
| 27862 | 27130 | else => unreachable, |
| ... | ... | @@ -27864,6 +27132,7 @@ fn elemVal( |
| 27864 | 27132 | } |
| 27865 | 27133 | |
| 27866 | 27134 | /// Called when the index or indexable is runtime known. |
| 27135 | /// Asserts that the layout of `elem_ty` is already resolved. | |
| 27867 | 27136 | fn validateRuntimeElemAccess( |
| 27868 | 27137 | sema: *Sema, |
| 27869 | 27138 | block: *Block, |
| ... | ... | @@ -27875,7 +27144,7 @@ fn validateRuntimeElemAccess( |
| 27875 | 27144 | const pt = sema.pt; |
| 27876 | 27145 | const zcu = pt.zcu; |
| 27877 | 27146 | |
| 27878 | if (try elem_ty.comptimeOnlySema(sema.pt)) { | |
| 27147 | if (elem_ty.comptimeOnly(zcu)) { | |
| 27879 | 27148 | const msg = msg: { |
| 27880 | 27149 | const msg = try sema.errMsg( |
| 27881 | 27150 | elem_index_src, |
| ... | ... | @@ -27900,6 +27169,7 @@ fn validateRuntimeElemAccess( |
| 27900 | 27169 | } |
| 27901 | 27170 | } |
| 27902 | 27171 | |
| 27172 | /// Asserts that the layout of the tuple type is already resolved. | |
| 27903 | 27173 | fn tupleFieldPtr( |
| 27904 | 27174 | sema: *Sema, |
| 27905 | 27175 | block: *Block, |
| ... | ... | @@ -27914,9 +27184,10 @@ fn tupleFieldPtr( |
| 27914 | 27184 | const tuple_ptr_ty = sema.typeOf(tuple_ptr); |
| 27915 | 27185 | const tuple_ptr_info = tuple_ptr_ty.ptrInfo(zcu); |
| 27916 | 27186 | const tuple_ty: Type = .fromInterned(tuple_ptr_info.child); |
| 27917 | try tuple_ty.resolveFields(pt); | |
| 27918 | 27187 | const field_count = tuple_ty.structFieldCount(zcu); |
| 27919 | 27188 | |
| 27189 | tuple_ty.assertHasLayout(zcu); | |
| 27190 | ||
| 27920 | 27191 | if (field_count == 0) { |
| 27921 | 27192 | return sema.fail(block, tuple_ptr_src, "indexing into empty tuple is not allowed", .{}); |
| 27922 | 27193 | } |
| ... | ... | @@ -27928,7 +27199,7 @@ fn tupleFieldPtr( |
| 27928 | 27199 | } |
| 27929 | 27200 | |
| 27930 | 27201 | const field_ty = tuple_ty.fieldType(field_index, zcu); |
| 27931 | const ptr_field_ty = try pt.ptrTypeSema(.{ | |
| 27202 | const ptr_field_ty = try pt.ptrType(.{ | |
| 27932 | 27203 | .child = field_ty.toIntern(), |
| 27933 | 27204 | .flags = .{ |
| 27934 | 27205 | .is_const = tuple_ptr_info.flags.is_const, |
| ... | ... | @@ -27938,15 +27209,12 @@ fn tupleFieldPtr( |
| 27938 | 27209 | if (tuple_ptr_info.flags.alignment == .none) break :a .none; |
| 27939 | 27210 | // The tuple pointer isn't naturally aligned, so the field pointer might be underaligned. |
| 27940 | 27211 | const tuple_align = tuple_ptr_info.flags.alignment; |
| 27941 | const field_align = try field_ty.abiAlignmentSema(pt); | |
| 27212 | const field_align = field_ty.abiAlignment(zcu); | |
| 27942 | 27213 | break :a tuple_align.min(field_align); |
| 27943 | 27214 | }, |
| 27944 | 27215 | }, |
| 27945 | 27216 | }); |
| 27946 | 27217 | |
| 27947 | if (tuple_ty.structFieldIsComptime(field_index, zcu)) | |
| 27948 | try tuple_ty.resolveStructFieldInits(pt); | |
| 27949 | ||
| 27950 | 27218 | if (try tuple_ty.structFieldValueComptime(pt, field_index)) |default_val| { |
| 27951 | 27219 | return Air.internedToRef((try pt.intern(.{ .ptr = .{ |
| 27952 | 27220 | .ty = ptr_field_ty.toIntern(), |
| ... | ... | @@ -27978,7 +27246,6 @@ fn tupleField( |
| 27978 | 27246 | const pt = sema.pt; |
| 27979 | 27247 | const zcu = pt.zcu; |
| 27980 | 27248 | const tuple_ty = sema.typeOf(tuple); |
| 27981 | try tuple_ty.resolveFields(pt); | |
| 27982 | 27249 | const field_count = tuple_ty.structFieldCount(zcu); |
| 27983 | 27250 | |
| 27984 | 27251 | if (field_count == 0) { |
| ... | ... | @@ -27993,8 +27260,6 @@ fn tupleField( |
| 27993 | 27260 | |
| 27994 | 27261 | const field_ty = tuple_ty.fieldType(field_index, zcu); |
| 27995 | 27262 | |
| 27996 | if (tuple_ty.structFieldIsComptime(field_index, zcu)) | |
| 27997 | try tuple_ty.resolveStructFieldInits(pt); | |
| 27998 | 27263 | if (try tuple_ty.structFieldValueComptime(pt, field_index)) |default_value| { |
| 27999 | 27264 | return Air.internedToRef(default_value.toIntern()); // comptime field |
| 28000 | 27265 | } |
| ... | ... | @@ -28006,7 +27271,6 @@ fn tupleField( |
| 28006 | 27271 | |
| 28007 | 27272 | try sema.validateRuntimeElemAccess(block, field_index_src, field_ty, tuple_ty, tuple_src); |
| 28008 | 27273 | |
| 28009 | try field_ty.resolveLayout(pt); | |
| 28010 | 27274 | return block.addStructFieldVal(tuple, field_index, field_ty); |
| 28011 | 27275 | } |
| 28012 | 27276 | |
| ... | ... | @@ -28037,7 +27301,7 @@ fn elemValArray( |
| 28037 | 27301 | const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index); |
| 28038 | 27302 | |
| 28039 | 27303 | if (maybe_index_val) |index_val| { |
| 28040 | const index: usize = @intCast(try index_val.toUnsignedIntSema(pt)); | |
| 27304 | const index: usize = @intCast(index_val.toUnsignedInt(zcu)); | |
| 28041 | 27305 | if (array_sent) |s| { |
| 28042 | 27306 | if (index == array_len) { |
| 28043 | 27307 | return Air.internedToRef(s.toIntern()); |
| ... | ... | @@ -28053,10 +27317,11 @@ fn elemValArray( |
| 28053 | 27317 | return pt.undefRef(elem_ty); |
| 28054 | 27318 | } |
| 28055 | 27319 | if (maybe_index_val) |index_val| { |
| 28056 | const index: usize = @intCast(try index_val.toUnsignedIntSema(pt)); | |
| 28057 | const elem_val = try array_val.elemValue(pt, index); | |
| 28058 | return Air.internedToRef(elem_val.toIntern()); | |
| 27320 | const index: usize = @intCast(index_val.toUnsignedInt(zcu)); | |
| 27321 | return .fromValue(try array_val.elemValue(pt, index)); | |
| 28059 | 27322 | } |
| 27323 | // Since the array is comptime-known, it might be OPV, in which case the index is irrelevant. | |
| 27324 | if (try elem_ty.onePossibleValue(pt)) |opv| return .fromValue(opv); | |
| 28060 | 27325 | } |
| 28061 | 27326 | |
| 28062 | 27327 | try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ty, array_ty, array_src); |
| ... | ... | @@ -28071,12 +27336,10 @@ fn elemValArray( |
| 28071 | 27336 | } |
| 28072 | 27337 | } |
| 28073 | 27338 | |
| 28074 | if (try sema.typeHasOnePossibleValue(elem_ty)) |elem_val| | |
| 28075 | return Air.internedToRef(elem_val.toIntern()); | |
| 28076 | ||
| 28077 | 27339 | return block.addBinOp(.array_elem_val, array, elem_index); |
| 28078 | 27340 | } |
| 28079 | 27341 | |
| 27342 | /// Asserts that the layout of the array or vector is already resolved. | |
| 28080 | 27343 | fn elemPtrArray( |
| 28081 | 27344 | sema: *Sema, |
| 28082 | 27345 | block: *Block, |
| ... | ... | @@ -28103,7 +27366,7 @@ fn elemPtrArray( |
| 28103 | 27366 | const maybe_undef_array_ptr_val = try sema.resolveValue(array_ptr); |
| 28104 | 27367 | // The index must not be undefined since it can be out of bounds. |
| 28105 | 27368 | const offset: ?usize = if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| o: { |
| 28106 | const index = try sema.usizeCast(block, elem_index_src, try index_val.toUnsignedIntSema(pt)); | |
| 27369 | const index = try sema.usizeCast(block, elem_index_src, index_val.toUnsignedInt(zcu)); | |
| 28107 | 27370 | if (index >= array_len_s) { |
| 28108 | 27371 | const sentinel_label: []const u8 = if (array_sent) " +1 (sentinel)" else ""; |
| 28109 | 27372 | return sema.fail(block, elem_index_src, "index {d} outside array of length {d}{s}", .{ index, array_len, sentinel_label }); |
| ... | ... | @@ -28115,6 +27378,7 @@ fn elemPtrArray( |
| 28115 | 27378 | return sema.fail(block, elem_index_src, "vector index not comptime known", .{}); |
| 28116 | 27379 | } |
| 28117 | 27380 | |
| 27381 | array_ty.assertHasLayout(zcu); | |
| 28118 | 27382 | const elem_ptr_ty = try array_ptr_ty.elemPtrType(offset, pt); |
| 28119 | 27383 | |
| 28120 | 27384 | if (maybe_undef_array_ptr_val) |array_ptr_val| { |
| ... | ... | @@ -28128,7 +27392,7 @@ fn elemPtrArray( |
| 28128 | 27392 | } |
| 28129 | 27393 | |
| 28130 | 27394 | if (!init) { |
| 28131 | try sema.validateRuntimeElemAccess(block, elem_index_src, array_ty.elemType2(zcu), array_ty, array_ptr_src); | |
| 27395 | try sema.validateRuntimeElemAccess(block, elem_index_src, array_ty.childType(zcu), array_ty, array_ptr_src); | |
| 28132 | 27396 | try sema.validateRuntimeValue(block, array_ptr_src, array_ptr); |
| 28133 | 27397 | } |
| 28134 | 27398 | |
| ... | ... | @@ -28142,6 +27406,7 @@ fn elemPtrArray( |
| 28142 | 27406 | return block.addPtrElemPtr(array_ptr, elem_index, elem_ptr_ty); |
| 28143 | 27407 | } |
| 28144 | 27408 | |
| 27409 | /// Asserts that the layout of the slice element type is already resolved. | |
| 28145 | 27410 | fn elemValSlice( |
| 28146 | 27411 | sema: *Sema, |
| 28147 | 27412 | block: *Block, |
| ... | ... | @@ -28156,9 +27421,11 @@ fn elemValSlice( |
| 28156 | 27421 | const zcu = pt.zcu; |
| 28157 | 27422 | const slice_ty = sema.typeOf(slice); |
| 28158 | 27423 | const slice_sent = slice_ty.sentinel(zcu) != null; |
| 28159 | const elem_ty = slice_ty.elemType2(zcu); | |
| 27424 | const elem_ty = slice_ty.childType(zcu); | |
| 28160 | 27425 | var runtime_src = slice_src; |
| 28161 | 27426 | |
| 27427 | elem_ty.assertHasLayout(zcu); | |
| 27428 | ||
| 28162 | 27429 | // slice must be defined since it can dereferenced as null |
| 28163 | 27430 | const maybe_slice_val = try sema.resolveDefinedValue(block, slice_src, slice); |
| 28164 | 27431 | // index must be defined since it can index out of bounds |
| ... | ... | @@ -28166,13 +27433,13 @@ fn elemValSlice( |
| 28166 | 27433 | |
| 28167 | 27434 | if (maybe_slice_val) |slice_val| { |
| 28168 | 27435 | runtime_src = elem_index_src; |
| 28169 | const slice_len = try slice_val.sliceLen(pt); | |
| 27436 | const slice_len = slice_val.sliceLen(zcu); | |
| 28170 | 27437 | const slice_len_s = slice_len + @intFromBool(slice_sent); |
| 28171 | 27438 | if (slice_len_s == 0) { |
| 28172 | 27439 | return sema.fail(block, slice_src, "indexing into empty slice is not allowed", .{}); |
| 28173 | 27440 | } |
| 28174 | 27441 | if (maybe_index_val) |index_val| { |
| 28175 | const index: usize = @intCast(try index_val.toUnsignedIntSema(pt)); | |
| 27442 | const index: usize = @intCast(index_val.toUnsignedInt(zcu)); | |
| 28176 | 27443 | if (index >= slice_len_s) { |
| 28177 | 27444 | const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else ""; |
| 28178 | 27445 | return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label }); |
| ... | ... | @@ -28186,16 +27453,14 @@ fn elemValSlice( |
| 28186 | 27453 | } |
| 28187 | 27454 | } |
| 28188 | 27455 | |
| 28189 | if (try sema.typeHasOnePossibleValue(elem_ty)) |elem_only_value| { | |
| 28190 | return Air.internedToRef(elem_only_value.toIntern()); | |
| 28191 | } | |
| 27456 | if (try elem_ty.onePossibleValue(pt)) |opv| return .fromValue(opv); | |
| 28192 | 27457 | |
| 28193 | 27458 | try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ty, slice_ty, slice_src); |
| 28194 | 27459 | try sema.validateRuntimeValue(block, slice_src, slice); |
| 28195 | 27460 | |
| 28196 | 27461 | if (oob_safety and block.wantSafety()) { |
| 28197 | 27462 | const len_inst = if (maybe_slice_val) |slice_val| |
| 28198 | try pt.intRef(.usize, try slice_val.sliceLen(pt)) | |
| 27463 | try pt.intRef(.usize, slice_val.sliceLen(zcu)) | |
| 28199 | 27464 | else |
| 28200 | 27465 | try block.addTyOp(.slice_len, .usize, slice); |
| 28201 | 27466 | const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt; |
| ... | ... | @@ -28204,6 +27469,7 @@ fn elemValSlice( |
| 28204 | 27469 | return block.addBinOp(.slice_elem_val, slice, elem_index); |
| 28205 | 27470 | } |
| 28206 | 27471 | |
| 27472 | /// Asserts that the layout of the slice element type is already resolved. | |
| 28207 | 27473 | fn elemPtrSlice( |
| 28208 | 27474 | sema: *Sema, |
| 28209 | 27475 | block: *Block, |
| ... | ... | @@ -28219,11 +27485,12 @@ fn elemPtrSlice( |
| 28219 | 27485 | const slice_ty = sema.typeOf(slice); |
| 28220 | 27486 | const slice_sent = slice_ty.sentinel(zcu) != null; |
| 28221 | 27487 | |
| 27488 | slice_ty.childType(zcu).assertHasLayout(zcu); | |
| 27489 | ||
| 28222 | 27490 | const maybe_undef_slice_val = try sema.resolveValue(slice); |
| 28223 | 27491 | // The index must not be undefined since it can be out of bounds. |
| 28224 | 27492 | const offset: ?usize = if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| o: { |
| 28225 | const index = try sema.usizeCast(block, elem_index_src, try index_val.toUnsignedIntSema(pt)); | |
| 28226 | break :o index; | |
| 27493 | break :o try sema.usizeCast(block, elem_index_src, index_val.toUnsignedInt(zcu)); | |
| 28227 | 27494 | } else null; |
| 28228 | 27495 | |
| 28229 | 27496 | const elem_ptr_ty = try slice_ty.elemPtrType(offset, pt); |
| ... | ... | @@ -28232,7 +27499,7 @@ fn elemPtrSlice( |
| 28232 | 27499 | if (slice_val.isUndef(zcu)) { |
| 28233 | 27500 | return pt.undefRef(elem_ptr_ty); |
| 28234 | 27501 | } |
| 28235 | const slice_len = try slice_val.sliceLen(pt); | |
| 27502 | const slice_len = slice_val.sliceLen(zcu); | |
| 28236 | 27503 | const slice_len_s = slice_len + @intFromBool(slice_sent); |
| 28237 | 27504 | if (slice_len_s == 0) { |
| 28238 | 27505 | return sema.fail(block, slice_src, "indexing into empty slice is not allowed", .{}); |
| ... | ... | @@ -28254,13 +27521,13 @@ fn elemPtrSlice( |
| 28254 | 27521 | const len_inst = len: { |
| 28255 | 27522 | if (maybe_undef_slice_val) |slice_val| |
| 28256 | 27523 | if (!slice_val.isUndef(zcu)) |
| 28257 | break :len try pt.intRef(.usize, try slice_val.sliceLen(pt)); | |
| 27524 | break :len try pt.intRef(.usize, slice_val.sliceLen(zcu)); | |
| 28258 | 27525 | break :len try block.addTyOp(.slice_len, .usize, slice); |
| 28259 | 27526 | }; |
| 28260 | 27527 | const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt; |
| 28261 | 27528 | try sema.addSafetyCheckIndexOob(block, src, elem_index, len_inst, cmp_op); |
| 28262 | 27529 | } |
| 28263 | if (!try slice_ty.childType(zcu).hasRuntimeBitsIgnoreComptimeSema(pt)) { | |
| 27530 | if (slice_ty.childType(zcu).abiSize(zcu) == 0) { | |
| 28264 | 27531 | // zero-bit child type; just extract the pointer and bitcast it |
| 28265 | 27532 | const slice_ptr = try block.addTyOp(.slice_ptr, slice_ty.slicePtrFieldType(zcu), slice); |
| 28266 | 27533 | return block.addBitCast(elem_ptr_ty, slice_ptr); |
| ... | ... | @@ -28331,10 +27598,12 @@ fn coerceExtra( |
| 28331 | 27598 | if (dest_ty.isGenericPoison()) return inst; |
| 28332 | 27599 | |
| 28333 | 27600 | const dest_ty_src = inst_src; // TODO better source location |
| 28334 | try dest_ty.resolveFields(pt); | |
| 28335 | 27601 | const inst_ty = sema.typeOf(inst); |
| 28336 | try inst_ty.resolveFields(pt); | |
| 28337 | 27602 | const target = zcu.getTarget(); |
| 27603 | ||
| 27604 | inst_ty.assertHasLayout(zcu); | |
| 27605 | try sema.ensureLayoutResolved(dest_ty); | |
| 27606 | ||
| 28338 | 27607 | // If the types are the same, we can return the operand. |
| 28339 | 27608 | if (dest_ty.eql(inst_ty, zcu)) |
| 28340 | 27609 | return inst; |
| ... | ... | @@ -28357,7 +27626,7 @@ fn coerceExtra( |
| 28357 | 27626 | if (maybe_inst_val) |val| { |
| 28358 | 27627 | // undefined sets the optional bit also to undefined. |
| 28359 | 27628 | if (val.toIntern() == .undef) { |
| 28360 | return pt.undefRef(dest_ty); | |
| 27629 | return .fromValue(try dest_ty.onePossibleValue(pt) orelse try pt.undefValue(dest_ty)); | |
| 28361 | 27630 | } |
| 28362 | 27631 | |
| 28363 | 27632 | // null to ?T |
| ... | ... | @@ -28372,11 +27641,11 @@ fn coerceExtra( |
| 28372 | 27641 | // cast from ?*T and ?[*]T to ?*anyopaque |
| 28373 | 27642 | // but don't do it if the source type is a double pointer |
| 28374 | 27643 | if (dest_ty.isPtrLikeOptional(zcu) and |
| 28375 | dest_ty.elemType2(zcu).toIntern() == .anyopaque_type and | |
| 27644 | dest_ty.nullablePtrElem(zcu).toIntern() == .anyopaque_type and | |
| 28376 | 27645 | inst_ty.isPtrAtRuntime(zcu)) |
| 28377 | 27646 | anyopaque_check: { |
| 28378 | 27647 | if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :optional; |
| 28379 | const elem_ty = inst_ty.elemType2(zcu); | |
| 27648 | const elem_ty = inst_ty.nullablePtrElem(zcu); | |
| 28380 | 27649 | if (elem_ty.zigTypeTag(zcu) == .pointer or elem_ty.isPtrLikeOptional(zcu)) { |
| 28381 | 27650 | in_memory_result = .{ .double_ptr_to_anyopaque = .{ |
| 28382 | 27651 | .actual = inst_ty, |
| ... | ... | @@ -28520,7 +27789,7 @@ fn coerceExtra( |
| 28520 | 27789 | // but don't do it if the source type is a double pointer |
| 28521 | 27790 | if (dest_info.child == .anyopaque_type and inst_ty.zigTypeTag(zcu) == .pointer) to_anyopaque: { |
| 28522 | 27791 | if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :pointer; |
| 28523 | const elem_ty = inst_ty.elemType2(zcu); | |
| 27792 | const elem_ty = inst_ty.childType(zcu); | |
| 28524 | 27793 | if (elem_ty.zigTypeTag(zcu) == .pointer or elem_ty.isPtrLikeOptional(zcu)) { |
| 28525 | 27794 | in_memory_result = .{ .double_ptr_to_anyopaque = .{ |
| 28526 | 27795 | .actual = inst_ty, |
| ... | ... | @@ -28616,7 +27885,9 @@ fn coerceExtra( |
| 28616 | 27885 | // empty tuple to zero-length slice |
| 28617 | 27886 | // note that this allows coercing to a mutable slice. |
| 28618 | 27887 | if (inst_child_ty.structFieldCount(zcu) == 0) { |
| 28619 | const align_val = try dest_ty.ptrAlignmentSema(pt); | |
| 27888 | // TODO MLUGG: this is *unacceptably* stupid. we're resolving the child for the alignment value | |
| 27889 | try sema.ensureLayoutResolved(dest_ty.childType(zcu)); | |
| 27890 | const align_val = dest_ty.ptrAlignment(zcu); | |
| 28620 | 27891 | return Air.internedToRef(try pt.intern(.{ .slice = .{ |
| 28621 | 27892 | .ty = dest_ty.toIntern(), |
| 28622 | 27893 | .ptr = try pt.intern(.{ .ptr = .{ |
| ... | ... | @@ -28689,7 +27960,7 @@ fn coerceExtra( |
| 28689 | 27960 | return sema.fail(block, inst_src, "type '{f}' cannot represent integer value '{f}'", .{ dest_ty.fmt(pt), val.fmtValueSema(pt, sema) }); |
| 28690 | 27961 | } |
| 28691 | 27962 | return switch (zcu.intern_pool.indexToKey(val.toIntern())) { |
| 28692 | .undef => try pt.undefRef(dest_ty), | |
| 27963 | .undef => .fromValue(try dest_ty.onePossibleValue(pt) orelse try pt.undefValue(dest_ty)), | |
| 28693 | 27964 | .int => |int| Air.internedToRef( |
| 28694 | 27965 | try zcu.intern_pool.getCoercedInts(gpa, io, pt.tid, int, dest_ty.toIntern()), |
| 28695 | 27966 | ), |
| ... | ... | @@ -28768,7 +28039,7 @@ fn coerceExtra( |
| 28768 | 28039 | } |
| 28769 | 28040 | break :int; |
| 28770 | 28041 | }; |
| 28771 | const result_val = try val.floatFromIntAdvanced(sema.arena, inst_ty, dest_ty, pt, .sema); | |
| 28042 | const result_val = try pt.floatValue(dest_ty, val.toFloat(f128, zcu)); | |
| 28772 | 28043 | const fits: bool = switch (ip.indexToKey(result_val.toIntern())) { |
| 28773 | 28044 | else => unreachable, |
| 28774 | 28045 | .undef => true, |
| ... | ... | @@ -28905,11 +28176,11 @@ fn coerceExtra( |
| 28905 | 28176 | else => true, |
| 28906 | 28177 | }; |
| 28907 | 28178 | |
| 28908 | if (can_coerce_to) { | |
| 28179 | if (can_coerce_to and inst == .undef) { | |
| 28909 | 28180 | // undefined to anything. We do this after the big switch above so that |
| 28910 | 28181 | // special logic has a chance to run first, such as `*[N]T` to `[]T` which |
| 28911 | 28182 | // should initialize the length field of the slice. |
| 28912 | if (maybe_inst_val) |val| if (val.toIntern() == .undef) return pt.undefRef(dest_ty); | |
| 28183 | return .fromValue(try dest_ty.onePossibleValue(pt) orelse try pt.undefValue(dest_ty)); | |
| 28913 | 28184 | } |
| 28914 | 28185 | |
| 28915 | 28186 | if (!opts.report_err) return error.NotCoercible; |
| ... | ... | @@ -29444,17 +28715,13 @@ pub fn coerceInMemoryAllowed( |
| 29444 | 28715 | } |
| 29445 | 28716 | |
| 29446 | 28717 | // Pointers / Pointer-like Optionals |
| 29447 | const maybe_dest_ptr_ty = try sema.typePtrOrOptionalPtrTy(dest_ty); | |
| 29448 | const maybe_src_ptr_ty = try sema.typePtrOrOptionalPtrTy(src_ty); | |
| 29449 | if (maybe_dest_ptr_ty) |dest_ptr_ty| { | |
| 29450 | if (maybe_src_ptr_ty) |src_ptr_ty| { | |
| 29451 | return try sema.coerceInMemoryAllowedPtrs(block, dest_ty, src_ty, dest_ptr_ty, src_ptr_ty, dest_is_mut, target, dest_src, src_src); | |
| 29452 | } | |
| 28718 | if (dest_ty.isPtrAtRuntime(zcu) and src_ty.isPtrAtRuntime(zcu)) { | |
| 28719 | return try sema.coerceInMemoryAllowedPtrs(block, dest_ty, src_ty, dest_is_mut, target, dest_src, src_src); | |
| 29453 | 28720 | } |
| 29454 | 28721 | |
| 29455 | 28722 | // Slices |
| 29456 | 28723 | if (dest_ty.isSlice(zcu) and src_ty.isSlice(zcu)) { |
| 29457 | return try sema.coerceInMemoryAllowedPtrs(block, dest_ty, src_ty, dest_ty, src_ty, dest_is_mut, target, dest_src, src_src); | |
| 28724 | return try sema.coerceInMemoryAllowedPtrs(block, dest_ty, src_ty, dest_is_mut, target, dest_src, src_src); | |
| 29458 | 28725 | } |
| 29459 | 28726 | |
| 29460 | 28727 | // Functions |
| ... | ... | @@ -29554,7 +28821,8 @@ pub fn coerceInMemoryAllowed( |
| 29554 | 28821 | |
| 29555 | 28822 | // Optionals |
| 29556 | 28823 | if (dest_tag == .optional and src_tag == .optional) { |
| 29557 | if ((maybe_dest_ptr_ty != null) != (maybe_src_ptr_ty != null)) { | |
| 28824 | if (dest_ty.isPtrAtRuntime(zcu) or src_ty.isPtrAtRuntime(zcu)) { | |
| 28825 | // Only one is, because we already handled when both are. | |
| 29558 | 28826 | return .{ .optional_shape = .{ |
| 29559 | 28827 | .actual = src_ty, |
| 29560 | 28828 | .wanted = dest_ty, |
| ... | ... | @@ -29581,7 +28849,7 @@ pub fn coerceInMemoryAllowed( |
| 29581 | 28849 | const field_count = dest_ty.structFieldCount(zcu); |
| 29582 | 28850 | for (0..field_count) |field_idx| { |
| 29583 | 28851 | if (dest_ty.structFieldIsComptime(field_idx, zcu) != src_ty.structFieldIsComptime(field_idx, zcu)) break :tuple; |
| 29584 | if (dest_ty.fieldAlignment(field_idx, zcu) != src_ty.fieldAlignment(field_idx, zcu)) break :tuple; | |
| 28852 | if (dest_ty.resolvedFieldAlignment(field_idx, zcu) != src_ty.resolvedFieldAlignment(field_idx, zcu)) break :tuple; | |
| 29585 | 28853 | const dest_field_ty = dest_ty.fieldType(field_idx, zcu); |
| 29586 | 28854 | const src_field_ty = src_ty.fieldType(field_idx, zcu); |
| 29587 | 28855 | const field = try sema.coerceInMemoryAllowed(block, dest_field_ty, src_field_ty, dest_is_mut, target, dest_src, src_src, null); |
| ... | ... | @@ -29714,11 +28982,7 @@ fn coerceInMemoryAllowedFns( |
| 29714 | 28982 | |
| 29715 | 28983 | { |
| 29716 | 28984 | if (dest_info.is_var_args != src_info.is_var_args) { |
| 29717 | return InMemoryCoercionResult{ .fn_var_args = dest_info.is_var_args }; | |
| 29718 | } | |
| 29719 | ||
| 29720 | if (dest_info.is_generic != src_info.is_generic) { | |
| 29721 | return InMemoryCoercionResult{ .fn_generic = dest_info.is_generic }; | |
| 28985 | return .{ .fn_var_args = dest_info.is_var_args }; | |
| 29722 | 28986 | } |
| 29723 | 28987 | |
| 29724 | 28988 | const callconv_ok = callconvCoerceAllowed(target, src_info.cc, dest_info.cc) and |
| ... | ... | @@ -29731,6 +28995,12 @@ fn coerceInMemoryAllowedFns( |
| 29731 | 28995 | } }; |
| 29732 | 28996 | } |
| 29733 | 28997 | |
| 28998 | try sema.ensureLayoutResolved(src_ty); | |
| 28999 | try sema.ensureLayoutResolved(dest_ty); | |
| 29000 | const src_is_runtime = src_ty.fnHasRuntimeBits(zcu); | |
| 29001 | const dest_is_runtime = dest_ty.fnHasRuntimeBits(zcu); | |
| 29002 | if (src_is_runtime != dest_is_runtime) return .{ .fn_generic = !dest_is_runtime }; | |
| 29003 | ||
| 29734 | 29004 | if (!switch (src_info.return_type) { |
| 29735 | 29005 | .generic_poison_type => true, |
| 29736 | 29006 | .noreturn_type => !dest_is_mut, |
| ... | ... | @@ -29780,7 +29050,8 @@ fn coerceInMemoryAllowedFns( |
| 29780 | 29050 | const src_is_comptime = src_info.paramIsComptime(@intCast(param_i)); |
| 29781 | 29051 | const dest_is_comptime = dest_info.paramIsComptime(@intCast(param_i)); |
| 29782 | 29052 | if (src_is_comptime == dest_is_comptime) break :comptime_param; |
| 29783 | if (!dest_is_mut and src_is_comptime and !dest_is_comptime and try dest_param_ty.comptimeOnlySema(pt)) { | |
| 29053 | try sema.ensureLayoutResolved(dest_param_ty); | |
| 29054 | if (!dest_is_mut and src_is_comptime and !dest_is_comptime and dest_param_ty.comptimeOnly(zcu)) { | |
| 29784 | 29055 | // A parameter which is marked `comptime` can drop that annotation if the type is comptime-only. |
| 29785 | 29056 | // The function remains generic, and the parameter is going to be comptime-resolved either way, |
| 29786 | 29057 | // so this just affects whether or not the argument is comptime-evaluated at the call site. |
| ... | ... | @@ -29861,8 +29132,6 @@ fn coerceInMemoryAllowedPtrs( |
| 29861 | 29132 | block: *Block, |
| 29862 | 29133 | dest_ty: Type, |
| 29863 | 29134 | src_ty: Type, |
| 29864 | dest_ptr_ty: Type, | |
| 29865 | src_ptr_ty: Type, | |
| 29866 | 29135 | /// If set, the coercion must be valid in both directions. |
| 29867 | 29136 | dest_is_mut: bool, |
| 29868 | 29137 | target: *const std.Target, |
| ... | ... | @@ -29875,8 +29144,8 @@ fn coerceInMemoryAllowedPtrs( |
| 29875 | 29144 | const gpa = comp.gpa; |
| 29876 | 29145 | const io = comp.io; |
| 29877 | 29146 | |
| 29878 | const dest_info = dest_ptr_ty.ptrInfo(zcu); | |
| 29879 | const src_info = src_ptr_ty.ptrInfo(zcu); | |
| 29147 | const dest_info = dest_ty.ptrInfo(zcu); | |
| 29148 | const src_info = src_ty.ptrInfo(zcu); | |
| 29880 | 29149 | |
| 29881 | 29150 | const ok_ptr_size = src_info.flags.size == dest_info.flags.size or |
| 29882 | 29151 | src_info.flags.size == .c or dest_info.flags.size == .c; |
| ... | ... | @@ -30008,16 +29277,14 @@ fn coerceInMemoryAllowedPtrs( |
| 30008 | 29277 | if (src_info.flags.alignment != .none or dest_info.flags.alignment != .none or |
| 30009 | 29278 | dest_info.child != src_info.child) |
| 30010 | 29279 | { |
| 30011 | const src_align = if (src_info.flags.alignment != .none) | |
| 30012 | src_info.flags.alignment | |
| 30013 | else | |
| 30014 | try Type.fromInterned(src_info.child).abiAlignmentSema(pt); | |
| 30015 | ||
| 30016 | const dest_align = if (dest_info.flags.alignment != .none) | |
| 30017 | dest_info.flags.alignment | |
| 30018 | else | |
| 30019 | try Type.fromInterned(dest_info.child).abiAlignmentSema(pt); | |
| 30020 | ||
| 29280 | const src_align = if (src_info.flags.alignment == .none) a: { | |
| 29281 | try sema.ensureLayoutResolved(src_child); | |
| 29282 | break :a src_child.abiAlignment(zcu); | |
| 29283 | } else src_info.flags.alignment; | |
| 29284 | const dest_align = if (dest_info.flags.alignment == .none) a: { | |
| 29285 | try sema.ensureLayoutResolved(dest_child); | |
| 29286 | break :a dest_child.abiAlignment(zcu); | |
| 29287 | } else dest_info.flags.alignment; | |
| 30021 | 29288 | if (dest_align.compare(if (dest_is_mut) .neq else .gt, src_align)) { |
| 30022 | 29289 | return InMemoryCoercionResult{ .ptr_alignment = .{ |
| 30023 | 29290 | .actual = src_align, |
| ... | ... | @@ -30180,9 +29447,16 @@ fn storePtr2( |
| 30180 | 29447 | return sema.storePtrVal(block, src, ptr_val, operand_val, elem_ty); |
| 30181 | 29448 | }; |
| 30182 | 29449 | |
| 29450 | // We do this after the possible comptime store above, for the case of field_ptr stores | |
| 29451 | // to unions because we want the comptime tag to be set, even if the field type is void. | |
| 29452 | // MLUGG TODO: that's insane, the runtime and comptime sematics should be the same. just set the tag at the same damn time | |
| 29453 | if (try elem_ty.onePossibleValue(pt) != null) { | |
| 29454 | return; | |
| 29455 | } | |
| 29456 | ||
| 30183 | 29457 | // We're performing the store at runtime; as such, we need to make sure the pointee type |
| 30184 | 29458 | // is not comptime-only. We can hit this case with a `@ptrFromInt` pointer. |
| 30185 | if (try elem_ty.comptimeOnlySema(pt)) { | |
| 29459 | if (elem_ty.comptimeOnly(zcu)) { | |
| 30186 | 29460 | return sema.failWithOwnedErrorMsg(block, msg: { |
| 30187 | 29461 | const msg = try sema.errMsg(src, "cannot store comptime-only type '{f}' at runtime", .{elem_ty.fmt(pt)}); |
| 30188 | 29462 | errdefer msg.destroy(sema.gpa); |
| ... | ... | @@ -30191,12 +29465,6 @@ fn storePtr2( |
| 30191 | 29465 | }); |
| 30192 | 29466 | } |
| 30193 | 29467 | |
| 30194 | // We do this after the possible comptime store above, for the case of field_ptr stores | |
| 30195 | // to unions because we want the comptime tag to be set, even if the field type is void. | |
| 30196 | if ((try sema.typeHasOnePossibleValue(elem_ty)) != null) { | |
| 30197 | return; | |
| 30198 | } | |
| 30199 | ||
| 30200 | 29468 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| 30201 | 29469 | |
| 30202 | 29470 | const store_inst = if (is_ret) |
| ... | ... | @@ -30361,10 +29629,10 @@ fn bitCast( |
| 30361 | 29629 | ) CompileError!Air.Inst.Ref { |
| 30362 | 29630 | const pt = sema.pt; |
| 30363 | 29631 | const zcu = pt.zcu; |
| 30364 | try dest_ty.resolveLayout(pt); | |
| 30365 | ||
| 30366 | 29632 | const old_ty = sema.typeOf(inst); |
| 30367 | try old_ty.resolveLayout(pt); | |
| 29633 | ||
| 29634 | old_ty.assertHasLayout(zcu); | |
| 29635 | try sema.ensureLayoutResolved(dest_ty); | |
| 30368 | 29636 | |
| 30369 | 29637 | const dest_bits = dest_ty.bitSize(zcu); |
| 30370 | 29638 | const old_bits = old_ty.bitSize(zcu); |
| ... | ... | @@ -30510,9 +29778,7 @@ fn coerceCompatiblePtrs( |
| 30510 | 29778 | } |
| 30511 | 29779 | try sema.requireRuntimeBlock(block, inst_src, null); |
| 30512 | 29780 | const inst_allows_zero = inst_ty.zigTypeTag(zcu) != .pointer or inst_ty.ptrAllowsZero(zcu); |
| 30513 | if (block.wantSafety() and inst_allows_zero and !dest_ty.ptrAllowsZero(zcu) and | |
| 30514 | (try dest_ty.elemType2(zcu).hasRuntimeBitsSema(pt) or dest_ty.elemType2(zcu).zigTypeTag(zcu) == .@"fn")) | |
| 30515 | { | |
| 29781 | if (block.wantSafety() and inst_allows_zero and !dest_ty.ptrAllowsZero(zcu)) { | |
| 30516 | 29782 | try sema.checkLogicalPtrOperation(block, inst_src, inst_ty); |
| 30517 | 29783 | const actual_ptr = if (inst_ty.isSlice(zcu)) |
| 30518 | 29784 | try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty) |
| ... | ... | @@ -30532,6 +29798,7 @@ fn coerceCompatiblePtrs( |
| 30532 | 29798 | return new_ptr; |
| 30533 | 29799 | } |
| 30534 | 29800 | |
| 29801 | /// Asserts that the layout of `union_ty` is already resolved. | |
| 30535 | 29802 | fn coerceEnumToUnion( |
| 30536 | 29803 | sema: *Sema, |
| 30537 | 29804 | block: *Block, |
| ... | ... | @@ -30545,18 +29812,21 @@ fn coerceEnumToUnion( |
| 30545 | 29812 | const ip = &zcu.intern_pool; |
| 30546 | 29813 | const inst_ty = sema.typeOf(inst); |
| 30547 | 29814 | |
| 30548 | const tag_ty = union_ty.unionTagType(zcu) orelse { | |
| 30549 | const msg = msg: { | |
| 30550 | const msg = try sema.typeMismatchErrMsg(inst_src, union_ty, inst_ty); | |
| 30551 | errdefer msg.destroy(sema.gpa); | |
| 30552 | try sema.errNote(union_ty_src, msg, "cannot coerce enum to untagged union", .{}); | |
| 30553 | try sema.addDeclaredHereNote(msg, union_ty); | |
| 30554 | break :msg msg; | |
| 30555 | }; | |
| 30556 | return sema.failWithOwnedErrorMsg(block, msg); | |
| 30557 | }; | |
| 29815 | union_ty.assertHasLayout(zcu); | |
| 29816 | ||
| 29817 | const union_obj = zcu.typeToUnion(union_ty).?; | |
| 29818 | const enum_ty: Type = .fromInterned(union_obj.enum_tag_type); | |
| 29819 | const enum_obj = ip.loadEnumType(enum_ty.toIntern()); | |
| 29820 | ||
| 29821 | if (union_obj.runtime_tag != .tagged) return sema.failWithOwnedErrorMsg(block, msg: { | |
| 29822 | const msg = try sema.typeMismatchErrMsg(inst_src, union_ty, inst_ty); | |
| 29823 | errdefer msg.destroy(sema.gpa); | |
| 29824 | try sema.errNote(union_ty_src, msg, "cannot coerce enum to untagged union", .{}); | |
| 29825 | try sema.addDeclaredHereNote(msg, union_ty); | |
| 29826 | break :msg msg; | |
| 29827 | }); | |
| 30558 | 29828 | |
| 30559 | const enum_tag = try sema.coerce(block, tag_ty, inst, inst_src); | |
| 29829 | const enum_tag = try sema.coerce(block, enum_ty, inst, inst_src); | |
| 30560 | 29830 | if (try sema.resolveDefinedValue(block, inst_src, enum_tag)) |val| { |
| 30561 | 29831 | const field_index = union_ty.unionTagFieldIndex(val, pt.zcu) orelse { |
| 30562 | 29832 | return sema.fail(block, inst_src, "union '{f}' has no tag with value '{f}'", .{ |
| ... | ... | @@ -30564,15 +29834,12 @@ fn coerceEnumToUnion( |
| 30564 | 29834 | }); |
| 30565 | 29835 | }; |
| 30566 | 29836 | |
| 30567 | const union_obj = zcu.typeToUnion(union_ty).?; | |
| 29837 | const field_name = enum_obj.field_names.get(ip)[field_index]; | |
| 30568 | 29838 | const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]); |
| 30569 | try field_ty.resolveFields(pt); | |
| 30570 | 29839 | if (field_ty.zigTypeTag(zcu) == .noreturn) { |
| 30571 | 29840 | const msg = msg: { |
| 30572 | 29841 | const msg = try sema.errMsg(inst_src, "cannot initialize 'noreturn' field of union", .{}); |
| 30573 | 29842 | errdefer msg.destroy(sema.gpa); |
| 30574 | ||
| 30575 | const field_name = union_obj.loadTagType(ip).names.get(ip)[field_index]; | |
| 30576 | 29843 | try sema.addFieldErrNote(union_ty, field_index, msg, "field '{f}' declared here", .{ |
| 30577 | 29844 | field_name.fmt(ip), |
| 30578 | 29845 | }); |
| ... | ... | @@ -30581,42 +29848,35 @@ fn coerceEnumToUnion( |
| 30581 | 29848 | }; |
| 30582 | 29849 | return sema.failWithOwnedErrorMsg(block, msg); |
| 30583 | 29850 | } |
| 30584 | const opv = (try sema.typeHasOnePossibleValue(field_ty)) orelse { | |
| 30585 | const msg = msg: { | |
| 30586 | const field_name = union_obj.loadTagType(ip).names.get(ip)[field_index]; | |
| 30587 | const msg = try sema.errMsg(inst_src, "coercion from enum '{f}' to union '{f}' must initialize '{f}' field '{f}'", .{ | |
| 30588 | inst_ty.fmt(pt), union_ty.fmt(pt), | |
| 30589 | field_ty.fmt(pt), field_name.fmt(ip), | |
| 30590 | }); | |
| 30591 | errdefer msg.destroy(sema.gpa); | |
| 29851 | const opv = try field_ty.onePossibleValue(pt) orelse return sema.failWithOwnedErrorMsg(block, msg: { | |
| 29852 | const msg = try sema.errMsg(inst_src, "coercion from enum '{f}' to union '{f}' must initialize '{f}' field '{f}'", .{ | |
| 29853 | inst_ty.fmt(pt), union_ty.fmt(pt), | |
| 29854 | field_ty.fmt(pt), field_name.fmt(ip), | |
| 29855 | }); | |
| 29856 | errdefer msg.destroy(sema.gpa); | |
| 30592 | 29857 | |
| 30593 | try sema.addFieldErrNote(union_ty, field_index, msg, "field '{f}' declared here", .{ | |
| 30594 | field_name.fmt(ip), | |
| 30595 | }); | |
| 30596 | try sema.addDeclaredHereNote(msg, union_ty); | |
| 30597 | break :msg msg; | |
| 30598 | }; | |
| 30599 | return sema.failWithOwnedErrorMsg(block, msg); | |
| 30600 | }; | |
| 29858 | try sema.addFieldErrNote(union_ty, field_index, msg, "field '{f}' declared here", .{field_name.fmt(ip)}); | |
| 29859 | try sema.addDeclaredHereNote(msg, union_ty); | |
| 29860 | break :msg msg; | |
| 29861 | }); | |
| 30601 | 29862 | |
| 30602 | 29863 | return Air.internedToRef((try pt.unionValue(union_ty, val, opv)).toIntern()); |
| 30603 | 29864 | } |
| 30604 | 29865 | |
| 30605 | 29866 | try sema.requireRuntimeBlock(block, inst_src, null); |
| 30606 | 29867 | |
| 30607 | if (tag_ty.isNonexhaustiveEnum(zcu)) { | |
| 29868 | if (enum_ty.isNonexhaustiveEnum(zcu)) { | |
| 30608 | 29869 | const msg = msg: { |
| 30609 | 29870 | const msg = try sema.errMsg(inst_src, "runtime coercion to union '{f}' from non-exhaustive enum", .{ |
| 30610 | 29871 | union_ty.fmt(pt), |
| 30611 | 29872 | }); |
| 30612 | 29873 | errdefer msg.destroy(sema.gpa); |
| 30613 | try sema.addDeclaredHereNote(msg, tag_ty); | |
| 29874 | try sema.addDeclaredHereNote(msg, enum_ty); | |
| 30614 | 29875 | break :msg msg; |
| 30615 | 29876 | }; |
| 30616 | 29877 | return sema.failWithOwnedErrorMsg(block, msg); |
| 30617 | 29878 | } |
| 30618 | 29879 | |
| 30619 | const union_obj = zcu.typeToUnion(union_ty).?; | |
| 30620 | 29880 | { |
| 30621 | 29881 | var msg: ?*Zcu.ErrorMsg = null; |
| 30622 | 29882 | errdefer if (msg) |some| some.destroy(sema.gpa); |
| ... | ... | @@ -30626,7 +29886,7 @@ fn coerceEnumToUnion( |
| 30626 | 29886 | const err_msg = msg orelse try sema.errMsg( |
| 30627 | 29887 | inst_src, |
| 30628 | 29888 | "runtime coercion from enum '{f}' to union '{f}' which has a 'noreturn' field", |
| 30629 | .{ tag_ty.fmt(pt), union_ty.fmt(pt) }, | |
| 29889 | .{ enum_ty.fmt(pt), union_ty.fmt(pt) }, | |
| 30630 | 29890 | ); |
| 30631 | 29891 | msg = err_msg; |
| 30632 | 29892 | |
| ... | ... | @@ -30649,14 +29909,14 @@ fn coerceEnumToUnion( |
| 30649 | 29909 | const msg = try sema.errMsg( |
| 30650 | 29910 | inst_src, |
| 30651 | 29911 | "runtime coercion from enum '{f}' to union '{f}' which has non-void fields", |
| 30652 | .{ tag_ty.fmt(pt), union_ty.fmt(pt) }, | |
| 29912 | .{ enum_ty.fmt(pt), union_ty.fmt(pt) }, | |
| 30653 | 29913 | ); |
| 30654 | 29914 | errdefer msg.destroy(sema.gpa); |
| 30655 | 29915 | |
| 30656 | 29916 | for (0..union_obj.field_types.len) |field_index| { |
| 30657 | const field_name = union_obj.loadTagType(ip).names.get(ip)[field_index]; | |
| 29917 | const field_name = enum_obj.field_names.get(ip)[field_index]; | |
| 30658 | 29918 | const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]); |
| 30659 | if (!(try field_ty.hasRuntimeBitsSema(pt))) continue; | |
| 29919 | if (try field_ty.onePossibleValue(pt) != null) continue; | |
| 30660 | 29920 | try sema.addFieldErrNote(union_ty, field_index, msg, "field '{f}' has type '{f}'", .{ |
| 30661 | 29921 | field_name.fmt(ip), |
| 30662 | 29922 | field_ty.fmt(pt), |
| ... | ... | @@ -30904,19 +30164,16 @@ fn coerceTupleToTuple( |
| 30904 | 30164 | const field_i: u32 = @intCast(field_index_usize); |
| 30905 | 30165 | const field_src = inst_src; // TODO better source location |
| 30906 | 30166 | |
| 30907 | const field_ty = switch (ip.indexToKey(tuple_ty.toIntern())) { | |
| 30908 | .tuple_type => |tuple_type| tuple_type.types.get(ip)[field_index_usize], | |
| 30909 | .struct_type => ip.loadStructType(tuple_ty.toIntern()).field_types.get(ip)[field_index_usize], | |
| 30910 | else => unreachable, | |
| 30911 | }; | |
| 30912 | const default_val = switch (ip.indexToKey(tuple_ty.toIntern())) { | |
| 30913 | .tuple_type => |tuple_type| tuple_type.values.get(ip)[field_index_usize], | |
| 30914 | .struct_type => ip.loadStructType(tuple_ty.toIntern()).fieldInit(ip, field_index_usize), | |
| 30915 | else => unreachable, | |
| 30916 | }; | |
| 30917 | ||
| 30918 | 30167 | const field_index: u32 = @intCast(field_index_usize); |
| 30919 | 30168 | |
| 30169 | const field_ty, const default_val = field: { | |
| 30170 | const tuple_type = ip.indexToKey(tuple_ty.toIntern()).tuple_type; | |
| 30171 | break :field .{ | |
| 30172 | tuple_type.types.get(ip)[field_index], | |
| 30173 | tuple_type.values.get(ip)[field_index], | |
| 30174 | }; | |
| 30175 | }; | |
| 30176 | ||
| 30920 | 30177 | const elem_ref = try sema.tupleField(block, inst_src, inst, field_src, field_i); |
| 30921 | 30178 | const coerced = try sema.coerce(block, .fromInterned(field_ty), elem_ref, field_src); |
| 30922 | 30179 | field_refs[field_index] = coerced; |
| ... | ... | @@ -30946,11 +30203,7 @@ fn coerceTupleToTuple( |
| 30946 | 30203 | const i: u32 = @intCast(i_usize); |
| 30947 | 30204 | if (field_ref.* != .none) continue; |
| 30948 | 30205 | |
| 30949 | const default_val = switch (ip.indexToKey(tuple_ty.toIntern())) { | |
| 30950 | .tuple_type => |tuple_type| tuple_type.values.get(ip)[i], | |
| 30951 | .struct_type => ip.loadStructType(tuple_ty.toIntern()).fieldInit(ip, i), | |
| 30952 | else => unreachable, | |
| 30953 | }; | |
| 30206 | const default_val = ip.indexToKey(tuple_ty.toIntern()).tuple_type.values.get(ip)[i]; | |
| 30954 | 30207 | |
| 30955 | 30208 | const field_src = inst_src; // TODO better source location |
| 30956 | 30209 | if (default_val == .none) { |
| ... | ... | @@ -31019,13 +30272,13 @@ fn addReferenceEntry( |
| 31019 | 30272 | pub fn addTypeReferenceEntry( |
| 31020 | 30273 | sema: *Sema, |
| 31021 | 30274 | src: LazySrcLoc, |
| 31022 | referenced_type: InternPool.Index, | |
| 30275 | referenced_type: Type, | |
| 31023 | 30276 | ) !void { |
| 31024 | 30277 | const zcu = sema.pt.zcu; |
| 31025 | 30278 | if (!zcu.comp.config.incremental and zcu.comp.reference_trace == 0) return; |
| 31026 | const gop = try sema.type_references.getOrPut(sema.gpa, referenced_type); | |
| 30279 | const gop = try sema.type_references.getOrPut(sema.gpa, referenced_type.toIntern()); | |
| 31027 | 30280 | if (gop.found_existing) return; |
| 31028 | try zcu.addTypeReference(sema.owner, referenced_type, src); | |
| 30281 | try zcu.addTypeReference(sema.owner, referenced_type.toIntern(), src); | |
| 31029 | 30282 | } |
| 31030 | 30283 | |
| 31031 | 30284 | fn ensureMemoizedStateResolved(sema: *Sema, src: LazySrcLoc, stage: InternPool.MemoizedStateStage) SemaError!void { |
| ... | ... | @@ -31143,7 +30396,7 @@ fn analyzeNavRefInner(sema: *Sema, block: *Block, src: LazySrcLoc, orig_nav_inde |
| 31143 | 30396 | .type_resolved => |r| .{ r.type, r.alignment, r.@"addrspace", r.is_const }, |
| 31144 | 30397 | .fully_resolved => |r| .{ ip.typeOf(r.val), r.alignment, r.@"addrspace", r.is_const }, |
| 31145 | 30398 | }; |
| 31146 | const ptr_ty = try pt.ptrTypeSema(.{ | |
| 30399 | const ptr_ty = try pt.ptrType(.{ | |
| 31147 | 30400 | .child = ty, |
| 31148 | 30401 | .flags = .{ |
| 31149 | 30402 | .alignment = alignment, |
| ... | ... | @@ -31185,7 +30438,7 @@ fn maybeQueueFuncBodyAnalysis(sema: *Sema, block: *Block, src: LazySrcLoc, nav_i |
| 31185 | 30438 | try sema.ensureNavResolved(block, src, nav_index, .type); |
| 31186 | 30439 | const nav_ty: Type = .fromInterned(ip.getNav(nav_index).typeOf(ip)); |
| 31187 | 30440 | if (nav_ty.zigTypeTag(zcu) != .@"fn") return; |
| 31188 | if (!try nav_ty.fnHasRuntimeBitsSema(pt)) return; | |
| 30441 | if (!nav_ty.fnHasRuntimeBits(zcu)) return; | |
| 31189 | 30442 | |
| 31190 | 30443 | try sema.ensureNavResolved(block, src, nav_index, .fully); |
| 31191 | 30444 | const nav_val = zcu.navValue(nav_index); |
| ... | ... | @@ -31218,14 +30471,14 @@ fn analyzeRef( |
| 31218 | 30471 | // it's just that we can only use the *type* of the result, since the value is runtime-known. |
| 31219 | 30472 | |
| 31220 | 30473 | const address_space = target_util.defaultAddressSpace(zcu.getTarget(), .local); |
| 31221 | const ptr_type = try pt.ptrTypeSema(.{ | |
| 30474 | const ptr_type = try pt.ptrType(.{ | |
| 31222 | 30475 | .child = operand_ty.toIntern(), |
| 31223 | 30476 | .flags = .{ |
| 31224 | 30477 | .is_const = true, |
| 31225 | 30478 | .address_space = address_space, |
| 31226 | 30479 | }, |
| 31227 | 30480 | }); |
| 31228 | const mut_ptr_type = try pt.ptrTypeSema(.{ | |
| 30481 | const mut_ptr_type = try pt.ptrType(.{ | |
| 31229 | 30482 | .child = operand_ty.toIntern(), |
| 31230 | 30483 | .flags = .{ .address_space = address_space }, |
| 31231 | 30484 | }); |
| ... | ... | @@ -31261,9 +30514,8 @@ fn analyzeLoad( |
| 31261 | 30514 | return sema.fail(block, ptr_src, "cannot load opaque type '{f}'", .{elem_ty.fmt(pt)}); |
| 31262 | 30515 | } |
| 31263 | 30516 | |
| 31264 | if (try sema.typeHasOnePossibleValue(elem_ty)) |opv| { | |
| 31265 | return Air.internedToRef(opv.toIntern()); | |
| 31266 | } | |
| 30517 | try sema.ensureLayoutResolved(elem_ty); | |
| 30518 | if (try elem_ty.onePossibleValue(pt)) |opv| return .fromValue(opv); | |
| 31267 | 30519 | |
| 31268 | 30520 | if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| { |
| 31269 | 30521 | if (try sema.pointerDeref(block, src, ptr_val, ptr_ty)) |elem_val| { |
| ... | ... | @@ -31271,6 +30523,13 @@ fn analyzeLoad( |
| 31271 | 30523 | } |
| 31272 | 30524 | } |
| 31273 | 30525 | |
| 30526 | if (elem_ty.comptimeOnly(zcu)) return sema.failWithOwnedErrorMsg(block, msg: { | |
| 30527 | const msg = try sema.errMsg(src, "cannot load comptime-only type '{f}'", .{elem_ty.fmt(pt)}); | |
| 30528 | errdefer msg.destroy(zcu.gpa); | |
| 30529 | try sema.errNote(ptr_src, msg, "pointer of type '{f}' is runtime-known", .{ptr_ty.fmt(pt)}); | |
| 30530 | break :msg msg; | |
| 30531 | }); | |
| 30532 | ||
| 31274 | 30533 | return block.addTyOp(.load, elem_ty, ptr); |
| 31275 | 30534 | } |
| 31276 | 30535 | |
| ... | ... | @@ -31332,7 +30591,7 @@ fn analyzeSliceLen( |
| 31332 | 30591 | if (slice_val.isUndef(zcu)) { |
| 31333 | 30592 | return .undef_usize; |
| 31334 | 30593 | } |
| 31335 | return pt.intRef(.usize, try slice_val.sliceLen(pt)); | |
| 30594 | return pt.intRef(.usize, slice_val.sliceLen(zcu)); | |
| 31336 | 30595 | } |
| 31337 | 30596 | try sema.requireRuntimeBlock(block, src, null); |
| 31338 | 30597 | return block.addTyOp(.slice_len, .usize, slice_inst); |
| ... | ... | @@ -31682,6 +30941,8 @@ fn analyzeSlice( |
| 31682 | 30941 | else => return sema.fail(block, src, "slice of non-array type '{f}'", .{ptr_ptr_child_ty.fmt(pt)}), |
| 31683 | 30942 | } |
| 31684 | 30943 | |
| 30944 | try sema.ensureLayoutResolved(elem_ty); | |
| 30945 | ||
| 31685 | 30946 | const ptr = if (slice_ty.isSlice(zcu)) |
| 31686 | 30947 | try sema.analyzeSlicePtr(block, ptr_src, ptr_or_slice, slice_ty) |
| 31687 | 30948 | else if (array_ty.zigTypeTag(zcu) == .array) ptr: { |
| ... | ... | @@ -31690,7 +30951,7 @@ fn analyzeSlice( |
| 31690 | 30951 | assert(manyptr_ty_key.flags.size == .one); |
| 31691 | 30952 | manyptr_ty_key.child = elem_ty.toIntern(); |
| 31692 | 30953 | manyptr_ty_key.flags.size = .many; |
| 31693 | break :ptr try sema.coerceCompatiblePtrs(block, try pt.ptrTypeSema(manyptr_ty_key), ptr_or_slice, ptr_src); | |
| 30954 | break :ptr try sema.coerceCompatiblePtrs(block, try pt.ptrType(manyptr_ty_key), ptr_or_slice, ptr_src); | |
| 31694 | 30955 | } else ptr_or_slice; |
| 31695 | 30956 | |
| 31696 | 30957 | const start = try sema.coerce(block, .usize, uncasted_start, start_src); |
| ... | ... | @@ -31759,7 +31020,7 @@ fn analyzeSlice( |
| 31759 | 31020 | return sema.fail(block, src, "slice of undefined", .{}); |
| 31760 | 31021 | } |
| 31761 | 31022 | const has_sentinel = slice_ty.sentinel(zcu) != null; |
| 31762 | const slice_len = try slice_val.sliceLen(pt); | |
| 31023 | const slice_len = slice_val.sliceLen(zcu); | |
| 31763 | 31024 | const len_plus_sent = slice_len + @intFromBool(has_sentinel); |
| 31764 | 31025 | const slice_len_val_with_sentinel = try pt.intValue(.usize, len_plus_sent); |
| 31765 | 31026 | if (!(try sema.compareAll(end_val, .lte, slice_len_val_with_sentinel, .usize))) { |
| ... | ... | @@ -31774,7 +31035,7 @@ fn analyzeSlice( |
| 31774 | 31035 | "end index {f} out of bounds for slice of length {d}{s}", |
| 31775 | 31036 | .{ |
| 31776 | 31037 | end_val.fmtValueSema(pt, sema), |
| 31777 | try slice_val.sliceLen(pt), | |
| 31038 | slice_val.sliceLen(zcu), | |
| 31778 | 31039 | sentinel_label, |
| 31779 | 31040 | }, |
| 31780 | 31041 | ); |
| ... | ... | @@ -31943,9 +31204,9 @@ fn analyzeSlice( |
| 31943 | 31204 | const new_allowzero = new_ptr_ty_info.flags.is_allowzero and sema.typeOf(ptr).ptrSize(zcu) != .c; |
| 31944 | 31205 | |
| 31945 | 31206 | if (opt_new_len_val) |new_len_val| { |
| 31946 | const new_len_int = try new_len_val.toUnsignedIntSema(pt); | |
| 31207 | const new_len_int = new_len_val.toUnsignedInt(zcu); | |
| 31947 | 31208 | |
| 31948 | const return_ty = try pt.ptrTypeSema(.{ | |
| 31209 | const return_ty = try pt.ptrType(.{ | |
| 31949 | 31210 | .child = (try pt.arrayType(.{ |
| 31950 | 31211 | .len = new_len_int, |
| 31951 | 31212 | .sentinel = if (sentinel) |s| s.toIntern() else .none, |
| ... | ... | @@ -32009,7 +31270,7 @@ fn analyzeSlice( |
| 32009 | 31270 | return sema.fail(block, src, "non-zero length slice of undefined pointer", .{}); |
| 32010 | 31271 | } |
| 32011 | 31272 | |
| 32012 | const return_ty = try pt.ptrTypeSema(.{ | |
| 31273 | const return_ty = try pt.ptrType(.{ | |
| 32013 | 31274 | .child = elem_ty.toIntern(), |
| 32014 | 31275 | .sentinel = if (sentinel) |s| s.toIntern() else .none, |
| 32015 | 31276 | .flags = .{ |
| ... | ... | @@ -32037,7 +31298,7 @@ fn analyzeSlice( |
| 32037 | 31298 | if (try sema.resolveDefinedValue(block, src, ptr_or_slice)) |slice_val| { |
| 32038 | 31299 | // we don't need to add one for sentinels because the |
| 32039 | 31300 | // underlying value data includes the sentinel |
| 32040 | break :blk try pt.intRef(.usize, try slice_val.sliceLen(pt)); | |
| 31301 | break :blk try pt.intRef(.usize, slice_val.sliceLen(zcu)); | |
| 32041 | 31302 | } |
| 32042 | 31303 | |
| 32043 | 31304 | const slice_len_inst = try block.addTyOp(.slice_len, .usize, ptr_or_slice); |
| ... | ... | @@ -32158,16 +31419,10 @@ fn cmpNumeric( |
| 32158 | 31419 | |
| 32159 | 31420 | const runtime_src: LazySrcLoc = if (maybe_lhs_val) |lhs_val| rs: { |
| 32160 | 31421 | if (maybe_rhs_val) |rhs_val| { |
| 32161 | const res = try Value.compareHeteroSema(lhs_val, op, rhs_val, pt); | |
| 32162 | return if (res) .bool_true else .bool_false; | |
| 31422 | return .fromValue(.makeBool(Value.compareHetero(lhs_val, op, rhs_val, zcu))); | |
| 32163 | 31423 | } else break :rs rhs_src; |
| 32164 | 31424 | } else lhs_src; |
| 32165 | 31425 | |
| 32166 | // TODO handle comparisons against lazy zero values | |
| 32167 | // Some values can be compared against zero without being runtime-known or without forcing | |
| 32168 | // a full resolution of their value, for example `@sizeOf(@Frame(function))` is known to | |
| 32169 | // always be nonzero, and we benefit from not forcing the full evaluation and stack frame layout | |
| 32170 | // of this function if we don't need to. | |
| 32171 | 31426 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| 32172 | 31427 | |
| 32173 | 31428 | // For floats, emit a float comparison instruction. |
| ... | ... | @@ -32207,11 +31462,11 @@ fn cmpNumeric( |
| 32207 | 31462 | // a signed integer with mantissa bits + 1, and if there was any non-integral part of the float, |
| 32208 | 31463 | // add/subtract 1. |
| 32209 | 31464 | const lhs_is_signed = if (maybe_lhs_val) |lhs_val| |
| 32210 | !(try lhs_val.compareAllWithZeroSema(.gte, pt)) | |
| 31465 | !lhs_val.compareAllWithZero(.gte, zcu) | |
| 32211 | 31466 | else |
| 32212 | 31467 | (lhs_ty.isRuntimeFloat() or lhs_ty.isSignedInt(zcu)); |
| 32213 | 31468 | const rhs_is_signed = if (maybe_rhs_val) |rhs_val| |
| 32214 | !(try rhs_val.compareAllWithZeroSema(.gte, pt)) | |
| 31469 | !rhs_val.compareAllWithZero(.gte, zcu) | |
| 32215 | 31470 | else |
| 32216 | 31471 | (rhs_ty.isRuntimeFloat() or rhs_ty.isSignedInt(zcu)); |
| 32217 | 31472 | const dest_int_is_signed = lhs_is_signed or rhs_is_signed; |
| ... | ... | @@ -32219,10 +31474,9 @@ fn cmpNumeric( |
| 32219 | 31474 | var dest_float_type: ?Type = null; |
| 32220 | 31475 | |
| 32221 | 31476 | var lhs_bits: usize = undefined; |
| 32222 | if (maybe_lhs_val) |unresolved_lhs_val| { | |
| 32223 | const lhs_val = try sema.resolveLazyValue(unresolved_lhs_val); | |
| 31477 | if (maybe_lhs_val) |lhs_val| { | |
| 32224 | 31478 | if (!rhs_is_signed) { |
| 32225 | switch (lhs_val.orderAgainstZero(zcu)) { | |
| 31479 | switch (Value.order(lhs_val, .zero_comptime_int, zcu)) { | |
| 32226 | 31480 | .gt => {}, |
| 32227 | 31481 | .eq => switch (op) { // LHS = 0, RHS is unsigned |
| 32228 | 31482 | .lte => return .bool_true, |
| ... | ... | @@ -32263,10 +31517,9 @@ fn cmpNumeric( |
| 32263 | 31517 | } |
| 32264 | 31518 | |
| 32265 | 31519 | var rhs_bits: usize = undefined; |
| 32266 | if (maybe_rhs_val) |unresolved_rhs_val| { | |
| 32267 | const rhs_val = try sema.resolveLazyValue(unresolved_rhs_val); | |
| 31520 | if (maybe_rhs_val) |rhs_val| { | |
| 32268 | 31521 | if (!lhs_is_signed) { |
| 32269 | switch (rhs_val.orderAgainstZero(zcu)) { | |
| 31522 | switch (Value.order(rhs_val, .zero_comptime_int, zcu)) { | |
| 32270 | 31523 | .gt => {}, |
| 32271 | 31524 | .eq => switch (op) { // RHS = 0, LHS is unsigned |
| 32272 | 31525 | .gte => return .bool_true, |
| ... | ... | @@ -32328,7 +31581,7 @@ fn compareIntsOnlyPossibleResult( |
| 32328 | 31581 | lhs_val: Value, |
| 32329 | 31582 | op: std.math.CompareOperator, |
| 32330 | 31583 | rhs_ty: Type, |
| 32331 | ) SemaError!?bool { | |
| 31584 | ) Allocator.Error!?bool { | |
| 32332 | 31585 | const pt = sema.pt; |
| 32333 | 31586 | const zcu = pt.zcu; |
| 32334 | 31587 | |
| ... | ... | @@ -32337,11 +31590,11 @@ fn compareIntsOnlyPossibleResult( |
| 32337 | 31590 | |
| 32338 | 31591 | if (min_rhs.toIntern() == max_rhs.toIntern()) { |
| 32339 | 31592 | // RHS is effectively comptime-known. |
| 32340 | return try Value.compareHeteroSema(lhs_val, op, min_rhs, pt); | |
| 31593 | return Value.compareHetero(lhs_val, op, min_rhs, zcu); | |
| 32341 | 31594 | } |
| 32342 | 31595 | |
| 32343 | const against_min = try lhs_val.orderAdvanced(min_rhs, .sema, zcu, pt.tid); | |
| 32344 | const against_max = try lhs_val.orderAdvanced(max_rhs, .sema, zcu, pt.tid); | |
| 31596 | const against_min = lhs_val.order(min_rhs, zcu); | |
| 31597 | const against_max = lhs_val.order(max_rhs, zcu); | |
| 32345 | 31598 | |
| 32346 | 31599 | switch (op) { |
| 32347 | 31600 | .eq => { |
| ... | ... | @@ -32529,9 +31782,7 @@ fn unionToTag( |
| 32529 | 31782 | ) !Air.Inst.Ref { |
| 32530 | 31783 | const pt = sema.pt; |
| 32531 | 31784 | const zcu = pt.zcu; |
| 32532 | if ((try sema.typeHasOnePossibleValue(enum_ty))) |opv| { | |
| 32533 | return Air.internedToRef(opv.toIntern()); | |
| 32534 | } | |
| 31785 | if (try enum_ty.onePossibleValue(pt)) |opv| return .fromValue(opv); | |
| 32535 | 31786 | if (try sema.resolveValue(un)) |un_val| { |
| 32536 | 31787 | const tag_val = un_val.unionTag(zcu).?; |
| 32537 | 31788 | if (tag_val.isUndef(zcu)) |
| ... | ... | @@ -33240,18 +32491,24 @@ fn resolvePeerTypesInner( |
| 33240 | 32491 | ptr_info.sentinel = .none; |
| 33241 | 32492 | } |
| 33242 | 32493 | |
| 33243 | // Note that the align can be always non-zero; Zcu.ptrType will canonicalize it | |
| 33244 | ptr_info.flags.alignment = InternPool.Alignment.min( | |
| 33245 | if (ptr_info.flags.alignment != .none) | |
| 33246 | ptr_info.flags.alignment | |
| 33247 | else | |
| 33248 | Type.fromInterned(ptr_info.child).abiAlignment(zcu), | |
| 33249 | ||
| 33250 | if (peer_info.flags.alignment != .none) | |
| 33251 | peer_info.flags.alignment | |
| 33252 | else | |
| 33253 | Type.fromInterned(peer_info.child).abiAlignment(zcu), | |
| 33254 | ); | |
| 32494 | ptr_info.flags.alignment = a: { | |
| 32495 | // If both alignments are implicit, the result alignment is implicit. | |
| 32496 | // e.g. '[*c]u32' + '[*c]c_uint' -> '[*c]u32' | |
| 32497 | if (ptr_info.flags.alignment == .none and peer_info.flags.alignment == .none) { | |
| 32498 | break :a .none; | |
| 32499 | } | |
| 32500 | // Otherwise (if either alignment is explicit), the result alignment is explicit. | |
| 32501 | // e.g. '[*c]u32' + '[*c]align(4) c_uint' -> '[*c]align(4) u32' | |
| 32502 | const cur_align = switch (ptr_info.flags.alignment) { | |
| 32503 | .none => Type.fromInterned(ptr_info.child).abiAlignment(zcu), | |
| 32504 | else => ptr_info.flags.alignment, | |
| 32505 | }; | |
| 32506 | const new_align = switch (peer_info.flags.alignment) { | |
| 32507 | .none => Type.fromInterned(peer_info.child).abiAlignment(zcu), | |
| 32508 | else => peer_info.flags.alignment, | |
| 32509 | }; | |
| 32510 | break :a .minStrict(cur_align, new_align); | |
| 32511 | }; | |
| 33255 | 32512 | if (ptr_info.flags.address_space != peer_info.flags.address_space) { |
| 33256 | 32513 | return .{ .conflict = .{ |
| 33257 | 32514 | .peer_idx_a = first_idx, |
| ... | ... | @@ -33273,7 +32530,7 @@ fn resolvePeerTypesInner( |
| 33273 | 32530 | |
| 33274 | 32531 | opt_ptr_info = ptr_info; |
| 33275 | 32532 | } |
| 33276 | return .{ .success = try pt.ptrTypeSema(opt_ptr_info.?) }; | |
| 32533 | return .{ .success = try pt.ptrType(opt_ptr_info.?) }; | |
| 33277 | 32534 | }, |
| 33278 | 32535 | |
| 33279 | 32536 | .ptr => { |
| ... | ... | @@ -33281,7 +32538,6 @@ fn resolvePeerTypesInner( |
| 33281 | 32538 | // if there were no actual slices. Else, we want the slice index to report a conflict. |
| 33282 | 32539 | var opt_slice_idx: ?usize = null; |
| 33283 | 32540 | |
| 33284 | var any_abi_aligned = false; | |
| 33285 | 32541 | var opt_ptr_info: ?InternPool.Key.PtrType = null; |
| 33286 | 32542 | var first_idx: usize = undefined; |
| 33287 | 32543 | var other_idx: usize = undefined; // We sometimes need a second peer index to report a generic error |
| ... | ... | @@ -33325,15 +32581,24 @@ fn resolvePeerTypesInner( |
| 33325 | 32581 | .peer_idx_b = i, |
| 33326 | 32582 | } }; |
| 33327 | 32583 | |
| 33328 | // Note that the align can be always non-zero; Type.ptr will canonicalize it | |
| 33329 | if (peer_info.flags.alignment == .none) { | |
| 33330 | any_abi_aligned = true; | |
| 33331 | } else if (ptr_info.flags.alignment == .none) { | |
| 33332 | any_abi_aligned = true; | |
| 33333 | ptr_info.flags.alignment = peer_info.flags.alignment; | |
| 33334 | } else { | |
| 33335 | ptr_info.flags.alignment = ptr_info.flags.alignment.minStrict(peer_info.flags.alignment); | |
| 33336 | } | |
| 32584 | ptr_info.flags.alignment = a: { | |
| 32585 | // If both alignments are implicit, the result alignment is implicit. | |
| 32586 | // e.g. '[*c]u32' + '[*c]c_uint' -> '[*c]u32' | |
| 32587 | if (ptr_info.flags.alignment == .none and peer_info.flags.alignment == .none) { | |
| 32588 | break :a .none; | |
| 32589 | } | |
| 32590 | // Otherwise (if either alignment is explicit), the result alignment is explicit. | |
| 32591 | // e.g. '[*c]u32' + '[*c]align(4) c_uint' -> '[*c]align(4) u32' | |
| 32592 | const cur_align = switch (ptr_info.flags.alignment) { | |
| 32593 | .none => Type.fromInterned(ptr_info.child).abiAlignment(zcu), | |
| 32594 | else => ptr_info.flags.alignment, | |
| 32595 | }; | |
| 32596 | const new_align = switch (peer_info.flags.alignment) { | |
| 32597 | .none => Type.fromInterned(peer_info.child).abiAlignment(zcu), | |
| 32598 | else => peer_info.flags.alignment, | |
| 32599 | }; | |
| 32600 | break :a .minStrict(cur_align, new_align); | |
| 32601 | }; | |
| 33337 | 32602 | |
| 33338 | 32603 | if (ptr_info.flags.address_space != peer_info.flags.address_space) { |
| 33339 | 32604 | return generic_err; |
| ... | ... | @@ -33582,13 +32847,7 @@ fn resolvePeerTypesInner( |
| 33582 | 32847 | }, |
| 33583 | 32848 | } |
| 33584 | 32849 | |
| 33585 | if (any_abi_aligned and opt_ptr_info.?.flags.alignment != .none) { | |
| 33586 | opt_ptr_info.?.flags.alignment = opt_ptr_info.?.flags.alignment.minStrict( | |
| 33587 | try Type.fromInterned(pointee).abiAlignmentSema(pt), | |
| 33588 | ); | |
| 33589 | } | |
| 33590 | ||
| 33591 | return .{ .success = try pt.ptrTypeSema(opt_ptr_info.?) }; | |
| 32850 | return .{ .success = try pt.ptrType(opt_ptr_info.?) }; | |
| 33592 | 32851 | }, |
| 33593 | 32852 | |
| 33594 | 32853 | .func => { |
| ... | ... | @@ -33731,7 +32990,7 @@ fn resolvePeerTypesInner( |
| 33731 | 32990 | .peer_idx_b = i, |
| 33732 | 32991 | } }; |
| 33733 | 32992 | any_comptime_known = true; |
| 33734 | ptr_opt_val.* = try sema.resolveLazyValue(opt_val.?); | |
| 32993 | ptr_opt_val.* = opt_val.?; | |
| 33735 | 32994 | continue; |
| 33736 | 32995 | }, |
| 33737 | 32996 | .int => {}, |
| ... | ... | @@ -33924,7 +33183,6 @@ fn resolvePeerTypesInner( |
| 33924 | 33183 | var comptime_val: ?Value = null; |
| 33925 | 33184 | for (peer_tys) |opt_ty| { |
| 33926 | 33185 | const struct_ty = opt_ty orelse continue; |
| 33927 | try struct_ty.resolveStructFieldInits(pt); | |
| 33928 | 33186 | |
| 33929 | 33187 | const uncoerced_field_val = try struct_ty.structFieldValueComptime(pt, field_index) orelse { |
| 33930 | 33188 | comptime_val = null; |
| ... | ... | @@ -34058,344 +33316,6 @@ pub fn resolveIes(sema: *Sema, block: *Block, src: LazySrcLoc) CompileError!void |
| 34058 | 33316 | } |
| 34059 | 33317 | } |
| 34060 | 33318 | |
| 34061 | pub fn resolveFnTypes(sema: *Sema, fn_ty: Type, src: LazySrcLoc) CompileError!void { | |
| 34062 | const pt = sema.pt; | |
| 34063 | const zcu = pt.zcu; | |
| 34064 | const ip = &zcu.intern_pool; | |
| 34065 | const fn_ty_info = zcu.typeToFunc(fn_ty).?; | |
| 34066 | ||
| 34067 | try Type.fromInterned(fn_ty_info.return_type).resolveFully(pt); | |
| 34068 | ||
| 34069 | if (zcu.comp.config.any_error_tracing and | |
| 34070 | Type.fromInterned(fn_ty_info.return_type).isError(zcu)) | |
| 34071 | { | |
| 34072 | // Ensure the type exists so that backends can assume that. | |
| 34073 | _ = try sema.getBuiltinType(src, .StackTrace); | |
| 34074 | } | |
| 34075 | ||
| 34076 | for (0..fn_ty_info.param_types.len) |i| { | |
| 34077 | try Type.fromInterned(fn_ty_info.param_types.get(ip)[i]).resolveFully(pt); | |
| 34078 | } | |
| 34079 | } | |
| 34080 | ||
| 34081 | fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value { | |
| 34082 | return val.resolveLazy(sema.arena, sema.pt); | |
| 34083 | } | |
| 34084 | ||
| 34085 | /// Resolve a struct's alignment only without triggering resolution of its layout. | |
| 34086 | /// Asserts that the alignment is not yet resolved and the layout is non-packed. | |
| 34087 | pub fn resolveStructAlignment( | |
| 34088 | sema: *Sema, | |
| 34089 | ty: InternPool.Index, | |
| 34090 | struct_type: InternPool.LoadedStructType, | |
| 34091 | ) SemaError!void { | |
| 34092 | const pt = sema.pt; | |
| 34093 | const zcu = pt.zcu; | |
| 34094 | const io = zcu.comp.io; | |
| 34095 | const ip = &zcu.intern_pool; | |
| 34096 | const target = zcu.getTarget(); | |
| 34097 | ||
| 34098 | assert(sema.owner.unwrap().type == ty); | |
| 34099 | ||
| 34100 | assert(struct_type.layout != .@"packed"); | |
| 34101 | assert(struct_type.flagsUnordered(ip).alignment == .none); | |
| 34102 | ||
| 34103 | const ptr_align = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8)); | |
| 34104 | ||
| 34105 | // We'll guess "pointer-aligned", if the struct has an | |
| 34106 | // underaligned pointer field then some allocations | |
| 34107 | // might require explicit alignment. | |
| 34108 | if (struct_type.assumePointerAlignedIfFieldTypesWip(ip, io, ptr_align)) return; | |
| 34109 | ||
| 34110 | try sema.resolveStructFieldTypes(ty, struct_type); | |
| 34111 | ||
| 34112 | // We'll guess "pointer-aligned", if the struct has an | |
| 34113 | // underaligned pointer field then some allocations | |
| 34114 | // might require explicit alignment. | |
| 34115 | if (struct_type.assumePointerAlignedIfWip(ip, io, ptr_align)) return; | |
| 34116 | defer struct_type.clearAlignmentWip(ip, io); | |
| 34117 | ||
| 34118 | // No `zcu.trackUnitSema` calls, since this phase isn't really doing any semantic analysis. | |
| 34119 | // It's just triggering *other* analysis, alongside a simple loop over already-resolved info. | |
| 34120 | ||
| 34121 | var alignment: Alignment = .@"1"; | |
| 34122 | ||
| 34123 | for (0..struct_type.field_types.len) |i| { | |
| 34124 | const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[i]); | |
| 34125 | if (struct_type.fieldIsComptime(ip, i) or try field_ty.comptimeOnlySema(pt)) | |
| 34126 | continue; | |
| 34127 | const field_align = try field_ty.structFieldAlignmentSema( | |
| 34128 | struct_type.fieldAlign(ip, i), | |
| 34129 | struct_type.layout, | |
| 34130 | pt, | |
| 34131 | ); | |
| 34132 | alignment = alignment.maxStrict(field_align); | |
| 34133 | } | |
| 34134 | ||
| 34135 | struct_type.setAlignment(ip, io, alignment); | |
| 34136 | } | |
| 34137 | ||
| 34138 | pub fn resolveStructLayout(sema: *Sema, ty: Type) SemaError!void { | |
| 34139 | const pt = sema.pt; | |
| 34140 | const zcu = pt.zcu; | |
| 34141 | const ip = &zcu.intern_pool; | |
| 34142 | const io = zcu.comp.io; | |
| 34143 | const struct_type = zcu.typeToStruct(ty) orelse return; | |
| 34144 | ||
| 34145 | assert(sema.owner.unwrap().type == ty.toIntern()); | |
| 34146 | ||
| 34147 | if (struct_type.haveLayout(ip)) | |
| 34148 | return; | |
| 34149 | ||
| 34150 | try sema.resolveStructFieldTypes(ty.toIntern(), struct_type); | |
| 34151 | ||
| 34152 | // No `zcu.trackUnitSema` calls, since this phase isn't really doing any semantic analysis. | |
| 34153 | // It's just triggering *other* analysis, alongside a simple loop over already-resolved info. | |
| 34154 | ||
| 34155 | if (struct_type.layout == .@"packed") { | |
| 34156 | sema.backingIntType(struct_type) catch |err| switch (err) { | |
| 34157 | error.AnalysisFail, error.OutOfMemory, error.Canceled => |e| return e, | |
| 34158 | error.ComptimeBreak, error.ComptimeReturn => unreachable, | |
| 34159 | }; | |
| 34160 | return; | |
| 34161 | } | |
| 34162 | ||
| 34163 | if (struct_type.setLayoutWip(ip, io)) { | |
| 34164 | const msg = try sema.errMsg( | |
| 34165 | ty.srcLoc(zcu), | |
| 34166 | "struct '{f}' depends on itself", | |
| 34167 | .{ty.fmt(pt)}, | |
| 34168 | ); | |
| 34169 | return sema.failWithOwnedErrorMsg(null, msg); | |
| 34170 | } | |
| 34171 | defer struct_type.clearLayoutWip(ip, io); | |
| 34172 | ||
| 34173 | const aligns = try sema.arena.alloc(Alignment, struct_type.field_types.len); | |
| 34174 | const sizes = try sema.arena.alloc(u64, struct_type.field_types.len); | |
| 34175 | ||
| 34176 | var big_align: Alignment = .@"1"; | |
| 34177 | ||
| 34178 | for (aligns, sizes, 0..) |*field_align, *field_size, i| { | |
| 34179 | const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[i]); | |
| 34180 | if (struct_type.fieldIsComptime(ip, i) or try field_ty.comptimeOnlySema(pt)) { | |
| 34181 | struct_type.offsets.get(ip)[i] = 0; | |
| 34182 | field_size.* = 0; | |
| 34183 | field_align.* = .none; | |
| 34184 | continue; | |
| 34185 | } | |
| 34186 | ||
| 34187 | field_size.* = field_ty.abiSizeSema(pt) catch |err| switch (err) { | |
| 34188 | error.AnalysisFail => { | |
| 34189 | const msg = sema.err orelse return err; | |
| 34190 | try sema.addFieldErrNote(ty, i, msg, "while checking this field", .{}); | |
| 34191 | return err; | |
| 34192 | }, | |
| 34193 | else => return err, | |
| 34194 | }; | |
| 34195 | field_align.* = try field_ty.structFieldAlignmentSema( | |
| 34196 | struct_type.fieldAlign(ip, i), | |
| 34197 | struct_type.layout, | |
| 34198 | pt, | |
| 34199 | ); | |
| 34200 | big_align = big_align.maxStrict(field_align.*); | |
| 34201 | } | |
| 34202 | ||
| 34203 | if (struct_type.flagsUnordered(ip).assumed_runtime_bits and !(try ty.hasRuntimeBitsSema(pt))) { | |
| 34204 | const msg = try sema.errMsg( | |
| 34205 | ty.srcLoc(zcu), | |
| 34206 | "struct layout depends on it having runtime bits", | |
| 34207 | .{}, | |
| 34208 | ); | |
| 34209 | return sema.failWithOwnedErrorMsg(null, msg); | |
| 34210 | } | |
| 34211 | ||
| 34212 | if (struct_type.flagsUnordered(ip).assumed_pointer_aligned and | |
| 34213 | big_align.compareStrict(.neq, Alignment.fromByteUnits(@divExact(zcu.getTarget().ptrBitWidth(), 8)))) | |
| 34214 | { | |
| 34215 | const msg = try sema.errMsg( | |
| 34216 | ty.srcLoc(zcu), | |
| 34217 | "struct layout depends on being pointer aligned", | |
| 34218 | .{}, | |
| 34219 | ); | |
| 34220 | return sema.failWithOwnedErrorMsg(null, msg); | |
| 34221 | } | |
| 34222 | ||
| 34223 | if (struct_type.hasReorderedFields()) { | |
| 34224 | const runtime_order = struct_type.runtime_order.get(ip); | |
| 34225 | ||
| 34226 | for (runtime_order, 0..) |*ro, i| { | |
| 34227 | const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[i]); | |
| 34228 | if (struct_type.fieldIsComptime(ip, i) or try field_ty.comptimeOnlySema(pt)) { | |
| 34229 | ro.* = .omitted; | |
| 34230 | } else { | |
| 34231 | ro.* = @enumFromInt(i); | |
| 34232 | } | |
| 34233 | } | |
| 34234 | ||
| 34235 | const RuntimeOrder = InternPool.LoadedStructType.RuntimeOrder; | |
| 34236 | ||
| 34237 | const AlignSortContext = struct { | |
| 34238 | aligns: []const Alignment, | |
| 34239 | ||
| 34240 | fn lessThan(ctx: @This(), a: RuntimeOrder, b: RuntimeOrder) bool { | |
| 34241 | if (a == .omitted) return false; | |
| 34242 | if (b == .omitted) return true; | |
| 34243 | const a_align = ctx.aligns[@intFromEnum(a)]; | |
| 34244 | const b_align = ctx.aligns[@intFromEnum(b)]; | |
| 34245 | return a_align.compare(.gt, b_align); | |
| 34246 | } | |
| 34247 | }; | |
| 34248 | if (!zcu.backendSupportsFeature(.field_reordering)) { | |
| 34249 | // TODO: we should probably also reorder tuple fields? This is a bit weird because it'll involve | |
| 34250 | // mutating the `InternPool` for a non-container type. | |
| 34251 | // | |
| 34252 | // TODO: implement field reordering support in all the backends! | |
| 34253 | // | |
| 34254 | // This logic does not reorder fields; it only moves the omitted ones to the end | |
| 34255 | // so that logic elsewhere does not need to special-case here. | |
| 34256 | var i: usize = 0; | |
| 34257 | var off: usize = 0; | |
| 34258 | while (i + off < runtime_order.len) { | |
| 34259 | if (runtime_order[i + off] == .omitted) { | |
| 34260 | off += 1; | |
| 34261 | continue; | |
| 34262 | } | |
| 34263 | runtime_order[i] = runtime_order[i + off]; | |
| 34264 | i += 1; | |
| 34265 | } | |
| 34266 | @memset(runtime_order[i..], .omitted); | |
| 34267 | } else { | |
| 34268 | mem.sortUnstable(RuntimeOrder, runtime_order, AlignSortContext{ | |
| 34269 | .aligns = aligns, | |
| 34270 | }, AlignSortContext.lessThan); | |
| 34271 | } | |
| 34272 | } | |
| 34273 | ||
| 34274 | // Calculate size, alignment, and field offsets. | |
| 34275 | const offsets = struct_type.offsets.get(ip); | |
| 34276 | var it = struct_type.iterateRuntimeOrder(ip); | |
| 34277 | var offset: u64 = 0; | |
| 34278 | while (it.next()) |i| { | |
| 34279 | offsets[i] = @intCast(aligns[i].forward(offset)); | |
| 34280 | offset = offsets[i] + sizes[i]; | |
| 34281 | } | |
| 34282 | const size = std.math.cast(u32, big_align.forward(offset)) orelse { | |
| 34283 | const msg = try sema.errMsg( | |
| 34284 | ty.srcLoc(zcu), | |
| 34285 | "struct layout requires size {d}, this compiler implementation supports up to {d}", | |
| 34286 | .{ big_align.forward(offset), std.math.maxInt(u32) }, | |
| 34287 | ); | |
| 34288 | return sema.failWithOwnedErrorMsg(null, msg); | |
| 34289 | }; | |
| 34290 | struct_type.setLayoutResolved(ip, io, size, big_align); | |
| 34291 | _ = try ty.comptimeOnlySema(pt); | |
| 34292 | } | |
| 34293 | ||
| 34294 | fn backingIntType( | |
| 34295 | sema: *Sema, | |
| 34296 | struct_type: InternPool.LoadedStructType, | |
| 34297 | ) CompileError!void { | |
| 34298 | const pt = sema.pt; | |
| 34299 | const zcu = pt.zcu; | |
| 34300 | const comp = zcu.comp; | |
| 34301 | const gpa = comp.gpa; | |
| 34302 | const io = comp.io; | |
| 34303 | const ip = &zcu.intern_pool; | |
| 34304 | ||
| 34305 | var analysis_arena = std.heap.ArenaAllocator.init(gpa); | |
| 34306 | defer analysis_arena.deinit(); | |
| 34307 | ||
| 34308 | var block: Block = .{ | |
| 34309 | .parent = null, | |
| 34310 | .sema = sema, | |
| 34311 | .namespace = struct_type.namespace, | |
| 34312 | .instructions = .{}, | |
| 34313 | .inlining = null, | |
| 34314 | .comptime_reason = null, // set below if needed | |
| 34315 | .src_base_inst = struct_type.zir_index, | |
| 34316 | .type_name_ctx = struct_type.name, | |
| 34317 | }; | |
| 34318 | defer assert(block.instructions.items.len == 0); | |
| 34319 | ||
| 34320 | const fields_bit_sum = blk: { | |
| 34321 | var accumulator: u64 = 0; | |
| 34322 | for (0..struct_type.field_types.len) |i| { | |
| 34323 | const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[i]); | |
| 34324 | accumulator += try field_ty.bitSizeSema(pt); | |
| 34325 | } | |
| 34326 | break :blk accumulator; | |
| 34327 | }; | |
| 34328 | ||
| 34329 | const zir = zcu.namespacePtr(struct_type.namespace).fileScope(zcu).zir.?; | |
| 34330 | const zir_index = struct_type.zir_index.resolve(ip) orelse return error.AnalysisFail; | |
| 34331 | const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended; | |
| 34332 | assert(extended.opcode == .struct_decl); | |
| 34333 | const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small); | |
| 34334 | ||
| 34335 | if (small.has_backing_int) { | |
| 34336 | var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).@"struct".fields.len; | |
| 34337 | const captures_len = if (small.has_captures_len) blk: { | |
| 34338 | const captures_len = zir.extra[extra_index]; | |
| 34339 | extra_index += 1; | |
| 34340 | break :blk captures_len; | |
| 34341 | } else 0; | |
| 34342 | extra_index += @intFromBool(small.has_fields_len); | |
| 34343 | extra_index += @intFromBool(small.has_decls_len); | |
| 34344 | ||
| 34345 | extra_index += captures_len * 2; | |
| 34346 | ||
| 34347 | const backing_int_body_len = zir.extra[extra_index]; | |
| 34348 | extra_index += 1; | |
| 34349 | ||
| 34350 | const backing_int_src: LazySrcLoc = .{ | |
| 34351 | .base_node_inst = struct_type.zir_index, | |
| 34352 | .offset = .{ .node_offset_container_tag = .zero }, | |
| 34353 | }; | |
| 34354 | block.comptime_reason = .{ .reason = .{ | |
| 34355 | .src = backing_int_src, | |
| 34356 | .r = .{ .simple = .type }, | |
| 34357 | } }; | |
| 34358 | const backing_int_ty = blk: { | |
| 34359 | if (backing_int_body_len == 0) { | |
| 34360 | const backing_int_ref: Zir.Inst.Ref = @enumFromInt(zir.extra[extra_index]); | |
| 34361 | break :blk try sema.resolveType(&block, backing_int_src, backing_int_ref); | |
| 34362 | } else { | |
| 34363 | const body = zir.bodySlice(extra_index, backing_int_body_len); | |
| 34364 | const ty_ref = try sema.resolveInlineBody(&block, body, zir_index); | |
| 34365 | break :blk try sema.analyzeAsType(&block, backing_int_src, ty_ref); | |
| 34366 | } | |
| 34367 | }; | |
| 34368 | ||
| 34369 | try sema.checkBackingIntType(&block, backing_int_src, backing_int_ty, fields_bit_sum); | |
| 34370 | struct_type.setBackingIntType(ip, io, backing_int_ty.toIntern()); | |
| 34371 | } else { | |
| 34372 | if (fields_bit_sum > std.math.maxInt(u16)) { | |
| 34373 | return sema.fail(&block, block.nodeOffset(.zero), "size of packed struct '{d}' exceeds maximum bit width of 65535", .{fields_bit_sum}); | |
| 34374 | } | |
| 34375 | const backing_int_ty = try pt.intType(.unsigned, @intCast(fields_bit_sum)); | |
| 34376 | struct_type.setBackingIntType(ip, io, backing_int_ty.toIntern()); | |
| 34377 | } | |
| 34378 | ||
| 34379 | try sema.flushExports(); | |
| 34380 | } | |
| 34381 | ||
| 34382 | fn checkBackingIntType(sema: *Sema, block: *Block, src: LazySrcLoc, backing_int_ty: Type, fields_bit_sum: u64) CompileError!void { | |
| 34383 | const pt = sema.pt; | |
| 34384 | const zcu = pt.zcu; | |
| 34385 | ||
| 34386 | if (!backing_int_ty.isInt(zcu)) { | |
| 34387 | return sema.fail(block, src, "expected backing integer type, found '{f}'", .{backing_int_ty.fmt(pt)}); | |
| 34388 | } | |
| 34389 | if (backing_int_ty.bitSize(zcu) != fields_bit_sum) { | |
| 34390 | return sema.fail( | |
| 34391 | block, | |
| 34392 | src, | |
| 34393 | "backing integer type '{f}' has bit size {d} but the struct fields have a total bit size of {d}", | |
| 34394 | .{ backing_int_ty.fmt(pt), backing_int_ty.bitSize(zcu), fields_bit_sum }, | |
| 34395 | ); | |
| 34396 | } | |
| 34397 | } | |
| 34398 | ||
| 34399 | 33319 | fn checkIndexable(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void { |
| 34400 | 33320 | const pt = sema.pt; |
| 34401 | 33321 | if (!ty.isIndexable(pt.zcu)) { |
| ... | ... | @@ -34432,358 +33352,6 @@ fn checkMemOperand(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void |
| 34432 | 33352 | return sema.failWithOwnedErrorMsg(block, msg); |
| 34433 | 33353 | } |
| 34434 | 33354 | |
| 34435 | /// Resolve a unions's alignment only without triggering resolution of its layout. | |
| 34436 | /// Asserts that the alignment is not yet resolved. | |
| 34437 | pub fn resolveUnionAlignment( | |
| 34438 | sema: *Sema, | |
| 34439 | ty: Type, | |
| 34440 | union_type: InternPool.LoadedUnionType, | |
| 34441 | ) SemaError!void { | |
| 34442 | const pt = sema.pt; | |
| 34443 | const zcu = pt.zcu; | |
| 34444 | const io = zcu.comp.io; | |
| 34445 | const ip = &zcu.intern_pool; | |
| 34446 | const target = zcu.getTarget(); | |
| 34447 | ||
| 34448 | assert(sema.owner.unwrap().type == ty.toIntern()); | |
| 34449 | ||
| 34450 | assert(!union_type.haveLayout(ip)); | |
| 34451 | ||
| 34452 | const ptr_align = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8)); | |
| 34453 | ||
| 34454 | // We'll guess "pointer-aligned", if the union has an | |
| 34455 | // underaligned pointer field then some allocations | |
| 34456 | // might require explicit alignment. | |
| 34457 | if (union_type.assumePointerAlignedIfFieldTypesWip(ip, io, ptr_align)) return; | |
| 34458 | ||
| 34459 | try sema.resolveUnionFieldTypes(ty, union_type); | |
| 34460 | ||
| 34461 | // No `zcu.trackUnitSema` calls, since this phase isn't really doing any semantic analysis. | |
| 34462 | // It's just triggering *other* analysis, alongside a simple loop over already-resolved info. | |
| 34463 | ||
| 34464 | var max_align: Alignment = .@"1"; | |
| 34465 | for (0..union_type.field_types.len) |field_index| { | |
| 34466 | const field_ty: Type = .fromInterned(union_type.field_types.get(ip)[field_index]); | |
| 34467 | if (!(try field_ty.hasRuntimeBitsSema(pt))) continue; | |
| 34468 | ||
| 34469 | const explicit_align = union_type.fieldAlign(ip, field_index); | |
| 34470 | const field_align = if (explicit_align != .none) | |
| 34471 | explicit_align | |
| 34472 | else | |
| 34473 | try field_ty.abiAlignmentSema(sema.pt); | |
| 34474 | ||
| 34475 | max_align = max_align.max(field_align); | |
| 34476 | } | |
| 34477 | ||
| 34478 | union_type.setAlignment(ip, io, max_align); | |
| 34479 | } | |
| 34480 | ||
| 34481 | /// This logic must be kept in sync with `Type.getUnionLayout`. | |
| 34482 | pub fn resolveUnionLayout(sema: *Sema, ty: Type) SemaError!void { | |
| 34483 | const pt = sema.pt; | |
| 34484 | const io = pt.zcu.comp.io; | |
| 34485 | const ip = &pt.zcu.intern_pool; | |
| 34486 | ||
| 34487 | try sema.resolveUnionFieldTypes(ty, ip.loadUnionType(ty.ip_index)); | |
| 34488 | ||
| 34489 | // Load again, since the tag type might have changed due to resolution. | |
| 34490 | const union_type = ip.loadUnionType(ty.ip_index); | |
| 34491 | ||
| 34492 | assert(sema.owner.unwrap().type == ty.toIntern()); | |
| 34493 | ||
| 34494 | const old_flags = union_type.flagsUnordered(ip); | |
| 34495 | switch (old_flags.status) { | |
| 34496 | .none, .have_field_types => {}, | |
| 34497 | .field_types_wip, .layout_wip => { | |
| 34498 | const msg = try sema.errMsg( | |
| 34499 | ty.srcLoc(pt.zcu), | |
| 34500 | "union '{f}' depends on itself", | |
| 34501 | .{ty.fmt(pt)}, | |
| 34502 | ); | |
| 34503 | return sema.failWithOwnedErrorMsg(null, msg); | |
| 34504 | }, | |
| 34505 | .have_layout, .fully_resolved_wip, .fully_resolved => return, | |
| 34506 | } | |
| 34507 | ||
| 34508 | errdefer union_type.setStatusIfLayoutWip(ip, io, old_flags.status); | |
| 34509 | ||
| 34510 | union_type.setStatus(ip, io, .layout_wip); | |
| 34511 | ||
| 34512 | // No `zcu.trackUnitSema` calls, since this phase isn't really doing any semantic analysis. | |
| 34513 | // It's just triggering *other* analysis, alongside a simple loop over already-resolved info. | |
| 34514 | ||
| 34515 | var max_size: u64 = 0; | |
| 34516 | var max_align: Alignment = .@"1"; | |
| 34517 | for (0..union_type.field_types.len) |field_index| { | |
| 34518 | const field_ty: Type = .fromInterned(union_type.field_types.get(ip)[field_index]); | |
| 34519 | if (field_ty.isNoReturn(pt.zcu)) continue; | |
| 34520 | ||
| 34521 | // We need to call `hasRuntimeBits` before calling `abiSize` to prevent reachable `unreachable`s, | |
| 34522 | // but `hasRuntimeBits` only resolves field types and so may infinite recurse on a layout wip type, | |
| 34523 | // so we must resolve the layout manually first, instead of waiting for `abiSize` to do it for us. | |
| 34524 | // This is arguably just hacking around bugs in both `abiSize` for not allowing arbitrary types to | |
| 34525 | // be queried, enabling failures to be handled with the emission of a compile error, and also in | |
| 34526 | // `hasRuntimeBits` for ever being able to infinite recurse in the first place. | |
| 34527 | try field_ty.resolveLayout(pt); | |
| 34528 | ||
| 34529 | if (try field_ty.hasRuntimeBitsSema(pt)) { | |
| 34530 | max_size = @max(max_size, field_ty.abiSizeSema(pt) catch |err| switch (err) { | |
| 34531 | error.AnalysisFail => { | |
| 34532 | const msg = sema.err orelse return err; | |
| 34533 | try sema.addFieldErrNote(ty, field_index, msg, "while checking this field", .{}); | |
| 34534 | return err; | |
| 34535 | }, | |
| 34536 | else => return err, | |
| 34537 | }); | |
| 34538 | } | |
| 34539 | ||
| 34540 | const explicit_align = union_type.fieldAlign(ip, field_index); | |
| 34541 | const field_align = if (explicit_align != .none) | |
| 34542 | explicit_align | |
| 34543 | else | |
| 34544 | try field_ty.abiAlignmentSema(pt); | |
| 34545 | max_align = max_align.max(field_align); | |
| 34546 | } | |
| 34547 | ||
| 34548 | const has_runtime_tag = union_type.flagsUnordered(ip).runtime_tag.hasTag() and | |
| 34549 | try Type.fromInterned(union_type.enum_tag_ty).hasRuntimeBitsSema(pt); | |
| 34550 | const size, const alignment, const padding = if (has_runtime_tag) layout: { | |
| 34551 | const enum_tag_type: Type = .fromInterned(union_type.enum_tag_ty); | |
| 34552 | const tag_align = try enum_tag_type.abiAlignmentSema(pt); | |
| 34553 | const tag_size = try enum_tag_type.abiSizeSema(pt); | |
| 34554 | ||
| 34555 | // Put the tag before or after the payload depending on which one's | |
| 34556 | // alignment is greater. | |
| 34557 | var size: u64 = 0; | |
| 34558 | var padding: u32 = 0; | |
| 34559 | if (tag_align.order(max_align).compare(.gte)) { | |
| 34560 | // {Tag, Payload} | |
| 34561 | size += tag_size; | |
| 34562 | size = max_align.forward(size); | |
| 34563 | size += max_size; | |
| 34564 | const prev_size = size; | |
| 34565 | size = tag_align.forward(size); | |
| 34566 | padding = @intCast(size - prev_size); | |
| 34567 | } else { | |
| 34568 | // {Payload, Tag} | |
| 34569 | size += max_size; | |
| 34570 | size = switch (pt.zcu.getTarget().ofmt) { | |
| 34571 | .c => max_align, | |
| 34572 | else => tag_align, | |
| 34573 | }.forward(size); | |
| 34574 | size += tag_size; | |
| 34575 | const prev_size = size; | |
| 34576 | size = max_align.forward(size); | |
| 34577 | padding = @intCast(size - prev_size); | |
| 34578 | } | |
| 34579 | ||
| 34580 | break :layout .{ size, max_align.max(tag_align), padding }; | |
| 34581 | } else .{ max_align.forward(max_size), max_align, 0 }; | |
| 34582 | ||
| 34583 | const casted_size = std.math.cast(u32, size) orelse { | |
| 34584 | const msg = try sema.errMsg( | |
| 34585 | ty.srcLoc(pt.zcu), | |
| 34586 | "union layout requires size {d}, this compiler implementation supports up to {d}", | |
| 34587 | .{ size, std.math.maxInt(u32) }, | |
| 34588 | ); | |
| 34589 | return sema.failWithOwnedErrorMsg(null, msg); | |
| 34590 | }; | |
| 34591 | union_type.setHaveLayout(ip, io, casted_size, padding, alignment); | |
| 34592 | ||
| 34593 | if (union_type.flagsUnordered(ip).assumed_runtime_bits and !(try ty.hasRuntimeBitsSema(pt))) { | |
| 34594 | const msg = try sema.errMsg( | |
| 34595 | ty.srcLoc(pt.zcu), | |
| 34596 | "union layout depends on it having runtime bits", | |
| 34597 | .{}, | |
| 34598 | ); | |
| 34599 | return sema.failWithOwnedErrorMsg(null, msg); | |
| 34600 | } | |
| 34601 | ||
| 34602 | if (union_type.flagsUnordered(ip).assumed_pointer_aligned and | |
| 34603 | alignment.compareStrict(.neq, Alignment.fromByteUnits(@divExact(pt.zcu.getTarget().ptrBitWidth(), 8)))) | |
| 34604 | { | |
| 34605 | const msg = try sema.errMsg( | |
| 34606 | ty.srcLoc(pt.zcu), | |
| 34607 | "union layout depends on being pointer aligned", | |
| 34608 | .{}, | |
| 34609 | ); | |
| 34610 | return sema.failWithOwnedErrorMsg(null, msg); | |
| 34611 | } | |
| 34612 | _ = try ty.comptimeOnlySema(pt); | |
| 34613 | } | |
| 34614 | ||
| 34615 | /// Returns `error.AnalysisFail` if any of the types (recursively) failed to | |
| 34616 | /// be resolved. | |
| 34617 | pub fn resolveStructFully(sema: *Sema, ty: Type) SemaError!void { | |
| 34618 | try sema.resolveStructLayout(ty); | |
| 34619 | try sema.resolveStructFieldInits(ty); | |
| 34620 | ||
| 34621 | const pt = sema.pt; | |
| 34622 | const zcu = pt.zcu; | |
| 34623 | const io = zcu.comp.io; | |
| 34624 | const ip = &zcu.intern_pool; | |
| 34625 | const struct_type = zcu.typeToStruct(ty).?; | |
| 34626 | ||
| 34627 | assert(sema.owner.unwrap().type == ty.toIntern()); | |
| 34628 | ||
| 34629 | if (struct_type.setFullyResolved(ip, io)) return; | |
| 34630 | errdefer struct_type.clearFullyResolved(ip, io); | |
| 34631 | ||
| 34632 | // No `zcu.trackUnitSema` calls, since this phase isn't really doing any semantic analysis. | |
| 34633 | // It's just triggering *other* analysis, alongside a simple loop over already-resolved info. | |
| 34634 | ||
| 34635 | // After we have resolve struct layout we have to go over the fields again to | |
| 34636 | // make sure pointer fields get their child types resolved as well. | |
| 34637 | // See also similar code for unions. | |
| 34638 | ||
| 34639 | for (0..struct_type.field_types.len) |i| { | |
| 34640 | const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[i]); | |
| 34641 | try field_ty.resolveFully(pt); | |
| 34642 | } | |
| 34643 | } | |
| 34644 | ||
| 34645 | pub fn resolveUnionFully(sema: *Sema, ty: Type) SemaError!void { | |
| 34646 | try sema.resolveUnionLayout(ty); | |
| 34647 | ||
| 34648 | const pt = sema.pt; | |
| 34649 | const zcu = pt.zcu; | |
| 34650 | const io = zcu.comp.io; | |
| 34651 | const ip = &zcu.intern_pool; | |
| 34652 | const union_obj = zcu.typeToUnion(ty).?; | |
| 34653 | ||
| 34654 | assert(sema.owner.unwrap().type == ty.toIntern()); | |
| 34655 | ||
| 34656 | switch (union_obj.flagsUnordered(ip).status) { | |
| 34657 | .none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {}, | |
| 34658 | .fully_resolved_wip, .fully_resolved => return, | |
| 34659 | } | |
| 34660 | ||
| 34661 | // No `zcu.trackUnitSema` calls, since this phase isn't really doing any semantic analysis. | |
| 34662 | // It's just triggering *other* analysis, alongside a simple loop over already-resolved info. | |
| 34663 | ||
| 34664 | { | |
| 34665 | // After we have resolve union layout we have to go over the fields again to | |
| 34666 | // make sure pointer fields get their child types resolved as well. | |
| 34667 | // See also similar code for structs. | |
| 34668 | const prev_status = union_obj.flagsUnordered(ip).status; | |
| 34669 | errdefer union_obj.setStatus(ip, io, prev_status); | |
| 34670 | ||
| 34671 | union_obj.setStatus(ip, io, .fully_resolved_wip); | |
| 34672 | for (0..union_obj.field_types.len) |field_index| { | |
| 34673 | const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]); | |
| 34674 | try field_ty.resolveFully(pt); | |
| 34675 | } | |
| 34676 | union_obj.setStatus(ip, io, .fully_resolved); | |
| 34677 | } | |
| 34678 | ||
| 34679 | // And let's not forget comptime-only status. | |
| 34680 | _ = try ty.comptimeOnlySema(pt); | |
| 34681 | } | |
| 34682 | ||
| 34683 | pub fn resolveStructFieldTypes( | |
| 34684 | sema: *Sema, | |
| 34685 | ty: InternPool.Index, | |
| 34686 | struct_type: InternPool.LoadedStructType, | |
| 34687 | ) SemaError!void { | |
| 34688 | const pt = sema.pt; | |
| 34689 | const zcu = pt.zcu; | |
| 34690 | const io = zcu.comp.io; | |
| 34691 | const ip = &zcu.intern_pool; | |
| 34692 | ||
| 34693 | assert(sema.owner.unwrap().type == ty); | |
| 34694 | ||
| 34695 | if (struct_type.haveFieldTypes(ip)) return; | |
| 34696 | ||
| 34697 | if (struct_type.setFieldTypesWip(ip, io)) { | |
| 34698 | const msg = try sema.errMsg( | |
| 34699 | Type.fromInterned(ty).srcLoc(zcu), | |
| 34700 | "struct '{f}' depends on itself", | |
| 34701 | .{Type.fromInterned(ty).fmt(pt)}, | |
| 34702 | ); | |
| 34703 | return sema.failWithOwnedErrorMsg(null, msg); | |
| 34704 | } | |
| 34705 | defer struct_type.clearFieldTypesWip(ip, io); | |
| 34706 | ||
| 34707 | // can't happen earlier than this because we only want the progress node if not already resolved | |
| 34708 | const tracked_unit = zcu.trackUnitSema(struct_type.name.toSlice(ip), null); | |
| 34709 | defer tracked_unit.end(zcu); | |
| 34710 | ||
| 34711 | sema.structFields(struct_type) catch |err| switch (err) { | |
| 34712 | error.AnalysisFail, error.OutOfMemory, error.Canceled => |e| return e, | |
| 34713 | error.ComptimeBreak, error.ComptimeReturn => unreachable, | |
| 34714 | }; | |
| 34715 | } | |
| 34716 | ||
| 34717 | pub fn resolveStructFieldInits(sema: *Sema, ty: Type) SemaError!void { | |
| 34718 | const pt = sema.pt; | |
| 34719 | const zcu = pt.zcu; | |
| 34720 | const io = zcu.comp.io; | |
| 34721 | const ip = &zcu.intern_pool; | |
| 34722 | const struct_type = zcu.typeToStruct(ty) orelse return; | |
| 34723 | ||
| 34724 | assert(sema.owner.unwrap().type == ty.toIntern()); | |
| 34725 | ||
| 34726 | // Inits can start as resolved | |
| 34727 | if (struct_type.haveFieldInits(ip)) return; | |
| 34728 | ||
| 34729 | try sema.resolveStructLayout(ty); | |
| 34730 | ||
| 34731 | if (struct_type.setInitsWip(ip, io)) { | |
| 34732 | const msg = try sema.errMsg( | |
| 34733 | ty.srcLoc(zcu), | |
| 34734 | "struct '{f}' depends on itself", | |
| 34735 | .{ty.fmt(pt)}, | |
| 34736 | ); | |
| 34737 | return sema.failWithOwnedErrorMsg(null, msg); | |
| 34738 | } | |
| 34739 | defer struct_type.clearInitsWip(ip, io); | |
| 34740 | ||
| 34741 | // can't happen earlier than this because we only want the progress node if not already resolved | |
| 34742 | const tracked_unit = zcu.trackUnitSema(struct_type.name.toSlice(ip), null); | |
| 34743 | defer tracked_unit.end(zcu); | |
| 34744 | ||
| 34745 | sema.structFieldInits(struct_type) catch |err| switch (err) { | |
| 34746 | error.AnalysisFail, error.OutOfMemory, error.Canceled => |e| return e, | |
| 34747 | error.ComptimeBreak, error.ComptimeReturn => unreachable, | |
| 34748 | }; | |
| 34749 | struct_type.setHaveFieldInits(ip, io); | |
| 34750 | } | |
| 34751 | ||
| 34752 | pub fn resolveUnionFieldTypes(sema: *Sema, ty: Type, union_type: InternPool.LoadedUnionType) SemaError!void { | |
| 34753 | const pt = sema.pt; | |
| 34754 | const zcu = pt.zcu; | |
| 34755 | const io = zcu.comp.io; | |
| 34756 | const ip = &zcu.intern_pool; | |
| 34757 | ||
| 34758 | assert(sema.owner.unwrap().type == ty.toIntern()); | |
| 34759 | ||
| 34760 | switch (union_type.flagsUnordered(ip).status) { | |
| 34761 | .none => {}, | |
| 34762 | .field_types_wip => { | |
| 34763 | const msg = try sema.errMsg(ty.srcLoc(zcu), "union '{f}' depends on itself", .{ty.fmt(pt)}); | |
| 34764 | return sema.failWithOwnedErrorMsg(null, msg); | |
| 34765 | }, | |
| 34766 | .have_field_types, | |
| 34767 | .have_layout, | |
| 34768 | .layout_wip, | |
| 34769 | .fully_resolved_wip, | |
| 34770 | .fully_resolved, | |
| 34771 | => return, | |
| 34772 | } | |
| 34773 | ||
| 34774 | // can't happen earlier than this because we only want the progress node if not already resolved | |
| 34775 | const tracked_unit = zcu.trackUnitSema(union_type.name.toSlice(ip), null); | |
| 34776 | defer tracked_unit.end(zcu); | |
| 34777 | ||
| 34778 | union_type.setStatus(ip, io, .field_types_wip); | |
| 34779 | errdefer union_type.setStatus(ip, io, .none); | |
| 34780 | sema.unionFields(ty.toIntern(), union_type) catch |err| switch (err) { | |
| 34781 | error.AnalysisFail, error.OutOfMemory, error.Canceled => |e| return e, | |
| 34782 | error.ComptimeBreak, error.ComptimeReturn => unreachable, | |
| 34783 | }; | |
| 34784 | union_type.setStatus(ip, io, .have_field_types); | |
| 34785 | } | |
| 34786 | ||
| 34787 | 33355 | /// Returns a normal error set corresponding to the fully populated inferred |
| 34788 | 33356 | /// error set. |
| 34789 | 33357 | fn resolveInferredErrorSet( |
| ... | ... | @@ -34798,8 +33366,9 @@ fn resolveInferredErrorSet( |
| 34798 | 33366 | const func_index = ip.iesFuncIndex(ies_index); |
| 34799 | 33367 | const func = zcu.funcInfo(func_index); |
| 34800 | 33368 | |
| 34801 | try sema.declareDependency(.{ .interned = func_index }); // resolved IES | |
| 33369 | try sema.declareDependency(.{ .func_ies = func_index }); | |
| 34802 | 33370 | |
| 33371 | // MLUGG TODO: this feels kinda bad now... instead check for outdated whenver we grab this? | |
| 34803 | 33372 | try zcu.maybeUnresolveIes(func_index); |
| 34804 | 33373 | const resolved_ty = func.resolvedErrorSetUnordered(ip); |
| 34805 | 33374 | if (resolved_ty != .none) return resolved_ty; |
| ... | ... | @@ -34820,7 +33389,7 @@ fn resolveInferredErrorSet( |
| 34820 | 33389 | if (ies_func_info.return_type == .generic_poison_type) { |
| 34821 | 33390 | assert(ies_func_info.cc == .@"inline"); |
| 34822 | 33391 | } else if (ip.errorUnionSet(ies_func_info.return_type) == ies_index) { |
| 34823 | if (ies_func_info.is_generic) { | |
| 33392 | if (!Type.fromInterned(func.ty).fnHasRuntimeBits(zcu)) { | |
| 34824 | 33393 | return sema.failWithOwnedErrorMsg(block, msg: { |
| 34825 | 33394 | const msg = try sema.errMsg(src, "unable to resolve inferred error set of generic function", .{}); |
| 34826 | 33395 | errdefer msg.destroy(sema.gpa); |
| ... | ... | @@ -34935,1248 +33504,6 @@ fn resolveInferredErrorSetTy( |
| 34935 | 33504 | } |
| 34936 | 33505 | } |
| 34937 | 33506 | |
| 34938 | fn structZirInfo(zir: Zir, zir_index: Zir.Inst.Index) struct { | |
| 34939 | /// fields_len | |
| 34940 | usize, | |
| 34941 | Zir.Inst.StructDecl.Small, | |
| 34942 | /// extra_index | |
| 34943 | usize, | |
| 34944 | } { | |
| 34945 | const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended; | |
| 34946 | assert(extended.opcode == .struct_decl); | |
| 34947 | const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small); | |
| 34948 | var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).@"struct".fields.len; | |
| 34949 | ||
| 34950 | const captures_len = if (small.has_captures_len) blk: { | |
| 34951 | const captures_len = zir.extra[extra_index]; | |
| 34952 | extra_index += 1; | |
| 34953 | break :blk captures_len; | |
| 34954 | } else 0; | |
| 34955 | ||
| 34956 | const fields_len = if (small.has_fields_len) blk: { | |
| 34957 | const fields_len = zir.extra[extra_index]; | |
| 34958 | extra_index += 1; | |
| 34959 | break :blk fields_len; | |
| 34960 | } else 0; | |
| 34961 | ||
| 34962 | const decls_len = if (small.has_decls_len) decls_len: { | |
| 34963 | const decls_len = zir.extra[extra_index]; | |
| 34964 | extra_index += 1; | |
| 34965 | break :decls_len decls_len; | |
| 34966 | } else 0; | |
| 34967 | ||
| 34968 | extra_index += captures_len * 2; | |
| 34969 | ||
| 34970 | // The backing integer cannot be handled until `resolveStructLayout()`. | |
| 34971 | if (small.has_backing_int) { | |
| 34972 | const backing_int_body_len = zir.extra[extra_index]; | |
| 34973 | extra_index += 1; // backing_int_body_len | |
| 34974 | if (backing_int_body_len == 0) { | |
| 34975 | extra_index += 1; // backing_int_ref | |
| 34976 | } else { | |
| 34977 | extra_index += backing_int_body_len; // backing_int_body_inst | |
| 34978 | } | |
| 34979 | } | |
| 34980 | ||
| 34981 | // Skip over decls. | |
| 34982 | extra_index += decls_len; | |
| 34983 | ||
| 34984 | return .{ fields_len, small, extra_index }; | |
| 34985 | } | |
| 34986 | ||
| 34987 | fn structFields( | |
| 34988 | sema: *Sema, | |
| 34989 | struct_type: InternPool.LoadedStructType, | |
| 34990 | ) CompileError!void { | |
| 34991 | const pt = sema.pt; | |
| 34992 | const zcu = pt.zcu; | |
| 34993 | const comp = zcu.comp; | |
| 34994 | const gpa = comp.gpa; | |
| 34995 | const io = comp.io; | |
| 34996 | const ip = &zcu.intern_pool; | |
| 34997 | ||
| 34998 | const namespace_index = struct_type.namespace; | |
| 34999 | const zir = zcu.namespacePtr(namespace_index).fileScope(zcu).zir.?; | |
| 35000 | const zir_index = struct_type.zir_index.resolve(ip) orelse return error.AnalysisFail; | |
| 35001 | ||
| 35002 | const fields_len, _, var extra_index = structZirInfo(zir, zir_index); | |
| 35003 | ||
| 35004 | if (fields_len == 0) switch (struct_type.layout) { | |
| 35005 | .@"packed" => { | |
| 35006 | try sema.backingIntType(struct_type); | |
| 35007 | return; | |
| 35008 | }, | |
| 35009 | .auto, .@"extern" => { | |
| 35010 | struct_type.setLayoutResolved(ip, io, 0, .none); | |
| 35011 | return; | |
| 35012 | }, | |
| 35013 | }; | |
| 35014 | ||
| 35015 | var block_scope: Block = .{ | |
| 35016 | .parent = null, | |
| 35017 | .sema = sema, | |
| 35018 | .namespace = namespace_index, | |
| 35019 | .instructions = .{}, | |
| 35020 | .inlining = null, | |
| 35021 | .comptime_reason = .{ .reason = .{ | |
| 35022 | .src = .{ | |
| 35023 | .base_node_inst = struct_type.zir_index, | |
| 35024 | .offset = .nodeOffset(.zero), | |
| 35025 | }, | |
| 35026 | .r = .{ .simple = .type }, | |
| 35027 | } }, | |
| 35028 | .src_base_inst = struct_type.zir_index, | |
| 35029 | .type_name_ctx = struct_type.name, | |
| 35030 | }; | |
| 35031 | defer assert(block_scope.instructions.items.len == 0); | |
| 35032 | ||
| 35033 | const Field = struct { | |
| 35034 | type_body_len: u32 = 0, | |
| 35035 | align_body_len: u32 = 0, | |
| 35036 | init_body_len: u32 = 0, | |
| 35037 | type_ref: Zir.Inst.Ref = .none, | |
| 35038 | }; | |
| 35039 | const fields = try sema.arena.alloc(Field, fields_len); | |
| 35040 | ||
| 35041 | var any_inits = false; | |
| 35042 | var any_aligned = false; | |
| 35043 | ||
| 35044 | { | |
| 35045 | const bits_per_field = 4; | |
| 35046 | const fields_per_u32 = 32 / bits_per_field; | |
| 35047 | const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable; | |
| 35048 | const flags_index = extra_index; | |
| 35049 | var bit_bag_index: usize = flags_index; | |
| 35050 | extra_index += bit_bags_count; | |
| 35051 | var cur_bit_bag: u32 = undefined; | |
| 35052 | var field_i: u32 = 0; | |
| 35053 | while (field_i < fields_len) : (field_i += 1) { | |
| 35054 | if (field_i % fields_per_u32 == 0) { | |
| 35055 | cur_bit_bag = zir.extra[bit_bag_index]; | |
| 35056 | bit_bag_index += 1; | |
| 35057 | } | |
| 35058 | const has_align = @as(u1, @truncate(cur_bit_bag)) != 0; | |
| 35059 | cur_bit_bag >>= 1; | |
| 35060 | const has_init = @as(u1, @truncate(cur_bit_bag)) != 0; | |
| 35061 | cur_bit_bag >>= 1; | |
| 35062 | const is_comptime = @as(u1, @truncate(cur_bit_bag)) != 0; | |
| 35063 | cur_bit_bag >>= 1; | |
| 35064 | const has_type_body = @as(u1, @truncate(cur_bit_bag)) != 0; | |
| 35065 | cur_bit_bag >>= 1; | |
| 35066 | ||
| 35067 | if (is_comptime) struct_type.setFieldComptime(ip, field_i); | |
| 35068 | ||
| 35069 | const field_name_zir: [:0]const u8 = zir.nullTerminatedString(@enumFromInt(zir.extra[extra_index])); | |
| 35070 | extra_index += 1; // field_name | |
| 35071 | ||
| 35072 | fields[field_i] = .{}; | |
| 35073 | ||
| 35074 | if (has_type_body) { | |
| 35075 | fields[field_i].type_body_len = zir.extra[extra_index]; | |
| 35076 | } else { | |
| 35077 | fields[field_i].type_ref = @enumFromInt(zir.extra[extra_index]); | |
| 35078 | } | |
| 35079 | extra_index += 1; | |
| 35080 | ||
| 35081 | // This string needs to outlive the ZIR code. | |
| 35082 | const field_name = try ip.getOrPutString(gpa, io, pt.tid, field_name_zir, .no_embedded_nulls); | |
| 35083 | assert(struct_type.addFieldName(ip, field_name) == null); | |
| 35084 | ||
| 35085 | if (has_align) { | |
| 35086 | fields[field_i].align_body_len = zir.extra[extra_index]; | |
| 35087 | extra_index += 1; | |
| 35088 | any_aligned = true; | |
| 35089 | } | |
| 35090 | if (has_init) { | |
| 35091 | fields[field_i].init_body_len = zir.extra[extra_index]; | |
| 35092 | extra_index += 1; | |
| 35093 | any_inits = true; | |
| 35094 | } | |
| 35095 | } | |
| 35096 | } | |
| 35097 | ||
| 35098 | // Next we do only types and alignments, saving the inits for a second pass, | |
| 35099 | // so that init values may depend on type layout. | |
| 35100 | ||
| 35101 | for (fields, 0..) |zir_field, field_i| { | |
| 35102 | const ty_src: LazySrcLoc = .{ | |
| 35103 | .base_node_inst = struct_type.zir_index, | |
| 35104 | .offset = .{ .container_field_type = @intCast(field_i) }, | |
| 35105 | }; | |
| 35106 | const field_ty: Type = ty: { | |
| 35107 | if (zir_field.type_ref != .none) { | |
| 35108 | break :ty try sema.resolveType(&block_scope, ty_src, zir_field.type_ref); | |
| 35109 | } | |
| 35110 | assert(zir_field.type_body_len != 0); | |
| 35111 | const body = zir.bodySlice(extra_index, zir_field.type_body_len); | |
| 35112 | extra_index += body.len; | |
| 35113 | const ty_ref = try sema.resolveInlineBody(&block_scope, body, zir_index); | |
| 35114 | break :ty try sema.analyzeAsType(&block_scope, ty_src, ty_ref); | |
| 35115 | }; | |
| 35116 | ||
| 35117 | struct_type.field_types.get(ip)[field_i] = field_ty.toIntern(); | |
| 35118 | ||
| 35119 | if (field_ty.zigTypeTag(zcu) == .@"opaque") { | |
| 35120 | const msg = msg: { | |
| 35121 | const msg = try sema.errMsg(ty_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{}); | |
| 35122 | errdefer msg.destroy(sema.gpa); | |
| 35123 | ||
| 35124 | try sema.addDeclaredHereNote(msg, field_ty); | |
| 35125 | break :msg msg; | |
| 35126 | }; | |
| 35127 | return sema.failWithOwnedErrorMsg(&block_scope, msg); | |
| 35128 | } | |
| 35129 | if (field_ty.zigTypeTag(zcu) == .noreturn) { | |
| 35130 | const msg = msg: { | |
| 35131 | const msg = try sema.errMsg(ty_src, "struct fields cannot be 'noreturn'", .{}); | |
| 35132 | errdefer msg.destroy(sema.gpa); | |
| 35133 | ||
| 35134 | try sema.addDeclaredHereNote(msg, field_ty); | |
| 35135 | break :msg msg; | |
| 35136 | }; | |
| 35137 | return sema.failWithOwnedErrorMsg(&block_scope, msg); | |
| 35138 | } | |
| 35139 | switch (struct_type.layout) { | |
| 35140 | .@"extern" => if (!try sema.validateExternType(field_ty, .struct_field)) { | |
| 35141 | const msg = msg: { | |
| 35142 | const msg = try sema.errMsg(ty_src, "extern structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); | |
| 35143 | errdefer msg.destroy(sema.gpa); | |
| 35144 | ||
| 35145 | try sema.explainWhyTypeIsNotExtern(msg, ty_src, field_ty, .struct_field); | |
| 35146 | ||
| 35147 | try sema.addDeclaredHereNote(msg, field_ty); | |
| 35148 | break :msg msg; | |
| 35149 | }; | |
| 35150 | return sema.failWithOwnedErrorMsg(&block_scope, msg); | |
| 35151 | }, | |
| 35152 | .@"packed" => if (!try sema.validatePackedType(field_ty)) { | |
| 35153 | const msg = msg: { | |
| 35154 | const msg = try sema.errMsg(ty_src, "packed structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); | |
| 35155 | errdefer msg.destroy(sema.gpa); | |
| 35156 | ||
| 35157 | try sema.explainWhyTypeIsNotPacked(msg, ty_src, field_ty); | |
| 35158 | ||
| 35159 | try sema.addDeclaredHereNote(msg, field_ty); | |
| 35160 | break :msg msg; | |
| 35161 | }; | |
| 35162 | return sema.failWithOwnedErrorMsg(&block_scope, msg); | |
| 35163 | }, | |
| 35164 | else => {}, | |
| 35165 | } | |
| 35166 | ||
| 35167 | if (zir_field.align_body_len > 0) { | |
| 35168 | const body = zir.bodySlice(extra_index, zir_field.align_body_len); | |
| 35169 | extra_index += body.len; | |
| 35170 | const align_ref = try sema.resolveInlineBody(&block_scope, body, zir_index); | |
| 35171 | const align_src: LazySrcLoc = .{ | |
| 35172 | .base_node_inst = struct_type.zir_index, | |
| 35173 | .offset = .{ .container_field_align = @intCast(field_i) }, | |
| 35174 | }; | |
| 35175 | const field_align = try sema.analyzeAsAlign(&block_scope, align_src, align_ref); | |
| 35176 | struct_type.field_aligns.get(ip)[field_i] = field_align; | |
| 35177 | } | |
| 35178 | ||
| 35179 | extra_index += zir_field.init_body_len; | |
| 35180 | } | |
| 35181 | ||
| 35182 | struct_type.clearFieldTypesWip(ip, io); | |
| 35183 | if (!any_inits) struct_type.setHaveFieldInits(ip, io); | |
| 35184 | ||
| 35185 | try sema.flushExports(); | |
| 35186 | } | |
| 35187 | ||
| 35188 | // This logic must be kept in sync with `structFields` | |
| 35189 | fn structFieldInits( | |
| 35190 | sema: *Sema, | |
| 35191 | struct_type: InternPool.LoadedStructType, | |
| 35192 | ) CompileError!void { | |
| 35193 | const pt = sema.pt; | |
| 35194 | const zcu = pt.zcu; | |
| 35195 | const ip = &zcu.intern_pool; | |
| 35196 | ||
| 35197 | assert(!struct_type.haveFieldInits(ip)); | |
| 35198 | ||
| 35199 | const namespace_index = struct_type.namespace; | |
| 35200 | const zir = zcu.namespacePtr(namespace_index).fileScope(zcu).zir.?; | |
| 35201 | const zir_index = struct_type.zir_index.resolve(ip) orelse return error.AnalysisFail; | |
| 35202 | const fields_len, _, var extra_index = structZirInfo(zir, zir_index); | |
| 35203 | ||
| 35204 | var block_scope: Block = .{ | |
| 35205 | .parent = null, | |
| 35206 | .sema = sema, | |
| 35207 | .namespace = namespace_index, | |
| 35208 | .instructions = .{}, | |
| 35209 | .inlining = null, | |
| 35210 | .comptime_reason = undefined, // set when `block_scope` is used | |
| 35211 | .src_base_inst = struct_type.zir_index, | |
| 35212 | .type_name_ctx = struct_type.name, | |
| 35213 | }; | |
| 35214 | defer assert(block_scope.instructions.items.len == 0); | |
| 35215 | ||
| 35216 | const Field = struct { | |
| 35217 | type_body_len: u32 = 0, | |
| 35218 | align_body_len: u32 = 0, | |
| 35219 | init_body_len: u32 = 0, | |
| 35220 | }; | |
| 35221 | const fields = try sema.arena.alloc(Field, fields_len); | |
| 35222 | ||
| 35223 | var any_inits = false; | |
| 35224 | ||
| 35225 | { | |
| 35226 | const bits_per_field = 4; | |
| 35227 | const fields_per_u32 = 32 / bits_per_field; | |
| 35228 | const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable; | |
| 35229 | const flags_index = extra_index; | |
| 35230 | var bit_bag_index: usize = flags_index; | |
| 35231 | extra_index += bit_bags_count; | |
| 35232 | var cur_bit_bag: u32 = undefined; | |
| 35233 | var field_i: u32 = 0; | |
| 35234 | while (field_i < fields_len) : (field_i += 1) { | |
| 35235 | if (field_i % fields_per_u32 == 0) { | |
| 35236 | cur_bit_bag = zir.extra[bit_bag_index]; | |
| 35237 | bit_bag_index += 1; | |
| 35238 | } | |
| 35239 | const has_align = @as(u1, @truncate(cur_bit_bag)) != 0; | |
| 35240 | cur_bit_bag >>= 1; | |
| 35241 | const has_init = @as(u1, @truncate(cur_bit_bag)) != 0; | |
| 35242 | cur_bit_bag >>= 2; | |
| 35243 | const has_type_body = @as(u1, @truncate(cur_bit_bag)) != 0; | |
| 35244 | cur_bit_bag >>= 1; | |
| 35245 | ||
| 35246 | extra_index += 1; // field_name | |
| 35247 | ||
| 35248 | fields[field_i] = .{}; | |
| 35249 | ||
| 35250 | if (has_type_body) fields[field_i].type_body_len = zir.extra[extra_index]; | |
| 35251 | extra_index += 1; | |
| 35252 | ||
| 35253 | if (has_align) { | |
| 35254 | fields[field_i].align_body_len = zir.extra[extra_index]; | |
| 35255 | extra_index += 1; | |
| 35256 | } | |
| 35257 | if (has_init) { | |
| 35258 | fields[field_i].init_body_len = zir.extra[extra_index]; | |
| 35259 | extra_index += 1; | |
| 35260 | any_inits = true; | |
| 35261 | } | |
| 35262 | } | |
| 35263 | } | |
| 35264 | ||
| 35265 | if (any_inits) { | |
| 35266 | for (fields, 0..) |zir_field, field_i| { | |
| 35267 | extra_index += zir_field.type_body_len; | |
| 35268 | extra_index += zir_field.align_body_len; | |
| 35269 | const body = zir.bodySlice(extra_index, zir_field.init_body_len); | |
| 35270 | extra_index += zir_field.init_body_len; | |
| 35271 | ||
| 35272 | if (body.len == 0) continue; | |
| 35273 | ||
| 35274 | // Pre-populate the type mapping the body expects to be there. | |
| 35275 | // In init bodies, the zir index of the struct itself is used | |
| 35276 | // to refer to the current field type. | |
| 35277 | ||
| 35278 | const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_i]); | |
| 35279 | const type_ref = Air.internedToRef(field_ty.toIntern()); | |
| 35280 | try sema.inst_map.ensureSpaceForInstructions(sema.gpa, &.{zir_index}); | |
| 35281 | sema.inst_map.putAssumeCapacity(zir_index, type_ref); | |
| 35282 | ||
| 35283 | const init_src: LazySrcLoc = .{ | |
| 35284 | .base_node_inst = struct_type.zir_index, | |
| 35285 | .offset = .{ .container_field_value = @intCast(field_i) }, | |
| 35286 | }; | |
| 35287 | ||
| 35288 | block_scope.comptime_reason = .{ .reason = .{ | |
| 35289 | .src = init_src, | |
| 35290 | .r = .{ .simple = .struct_field_default_value }, | |
| 35291 | } }; | |
| 35292 | const init = try sema.resolveInlineBody(&block_scope, body, zir_index); | |
| 35293 | const coerced = try sema.coerce(&block_scope, field_ty, init, init_src); | |
| 35294 | const default_val = try sema.resolveConstValue(&block_scope, init_src, coerced, null); | |
| 35295 | ||
| 35296 | if (default_val.canMutateComptimeVarState(zcu)) { | |
| 35297 | return sema.failWithContainsReferenceToComptimeVar( | |
| 35298 | &block_scope, | |
| 35299 | init_src, | |
| 35300 | struct_type.fieldName(ip, field_i), | |
| 35301 | "field default value", | |
| 35302 | default_val, | |
| 35303 | ); | |
| 35304 | } | |
| 35305 | struct_type.field_inits.get(ip)[field_i] = default_val.toIntern(); | |
| 35306 | } | |
| 35307 | } | |
| 35308 | ||
| 35309 | try sema.flushExports(); | |
| 35310 | } | |
| 35311 | ||
| 35312 | fn unionFields( | |
| 35313 | sema: *Sema, | |
| 35314 | union_ty: InternPool.Index, | |
| 35315 | union_type: InternPool.LoadedUnionType, | |
| 35316 | ) CompileError!void { | |
| 35317 | const tracy = trace(@src()); | |
| 35318 | defer tracy.end(); | |
| 35319 | ||
| 35320 | const pt = sema.pt; | |
| 35321 | const zcu = pt.zcu; | |
| 35322 | const comp = zcu.comp; | |
| 35323 | const gpa = comp.gpa; | |
| 35324 | const io = comp.io; | |
| 35325 | const ip = &zcu.intern_pool; | |
| 35326 | ||
| 35327 | const zir = zcu.namespacePtr(union_type.namespace).fileScope(zcu).zir.?; | |
| 35328 | const zir_index = union_type.zir_index.resolve(ip) orelse return error.AnalysisFail; | |
| 35329 | const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended; | |
| 35330 | assert(extended.opcode == .union_decl); | |
| 35331 | const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small); | |
| 35332 | const extra = zir.extraData(Zir.Inst.UnionDecl, extended.operand); | |
| 35333 | var extra_index: usize = extra.end; | |
| 35334 | ||
| 35335 | const tag_type_ref: Zir.Inst.Ref = if (small.has_tag_type) blk: { | |
| 35336 | const ty_ref: Zir.Inst.Ref = @enumFromInt(zir.extra[extra_index]); | |
| 35337 | extra_index += 1; | |
| 35338 | break :blk ty_ref; | |
| 35339 | } else .none; | |
| 35340 | ||
| 35341 | const captures_len = if (small.has_captures_len) blk: { | |
| 35342 | const captures_len = zir.extra[extra_index]; | |
| 35343 | extra_index += 1; | |
| 35344 | break :blk captures_len; | |
| 35345 | } else 0; | |
| 35346 | ||
| 35347 | const body_len = if (small.has_body_len) blk: { | |
| 35348 | const body_len = zir.extra[extra_index]; | |
| 35349 | extra_index += 1; | |
| 35350 | break :blk body_len; | |
| 35351 | } else 0; | |
| 35352 | ||
| 35353 | const fields_len = if (small.has_fields_len) blk: { | |
| 35354 | const fields_len = zir.extra[extra_index]; | |
| 35355 | extra_index += 1; | |
| 35356 | break :blk fields_len; | |
| 35357 | } else 0; | |
| 35358 | ||
| 35359 | const decls_len = if (small.has_decls_len) decls_len: { | |
| 35360 | const decls_len = zir.extra[extra_index]; | |
| 35361 | extra_index += 1; | |
| 35362 | break :decls_len decls_len; | |
| 35363 | } else 0; | |
| 35364 | ||
| 35365 | // Skip over captures and decls. | |
| 35366 | extra_index += captures_len * 2 + decls_len; | |
| 35367 | ||
| 35368 | const body = zir.bodySlice(extra_index, body_len); | |
| 35369 | extra_index += body.len; | |
| 35370 | ||
| 35371 | const src: LazySrcLoc = .{ | |
| 35372 | .base_node_inst = union_type.zir_index, | |
| 35373 | .offset = .nodeOffset(.zero), | |
| 35374 | }; | |
| 35375 | ||
| 35376 | var block_scope: Block = .{ | |
| 35377 | .parent = null, | |
| 35378 | .sema = sema, | |
| 35379 | .namespace = union_type.namespace, | |
| 35380 | .instructions = .{}, | |
| 35381 | .inlining = null, | |
| 35382 | .comptime_reason = .{ .reason = .{ | |
| 35383 | .src = src, | |
| 35384 | .r = .{ .simple = .type }, | |
| 35385 | } }, | |
| 35386 | .src_base_inst = union_type.zir_index, | |
| 35387 | .type_name_ctx = union_type.name, | |
| 35388 | }; | |
| 35389 | defer assert(block_scope.instructions.items.len == 0); | |
| 35390 | ||
| 35391 | if (body.len != 0) { | |
| 35392 | _ = try sema.analyzeInlineBody(&block_scope, body, zir_index); | |
| 35393 | } | |
| 35394 | ||
| 35395 | var int_tag_ty: Type = undefined; | |
| 35396 | var enum_field_names: []InternPool.NullTerminatedString = &.{}; | |
| 35397 | var enum_field_vals: std.AutoArrayHashMapUnmanaged(InternPool.Index, void) = .empty; | |
| 35398 | var explicit_tags_seen: []bool = &.{}; | |
| 35399 | if (tag_type_ref != .none) { | |
| 35400 | const tag_ty_src: LazySrcLoc = .{ | |
| 35401 | .base_node_inst = union_type.zir_index, | |
| 35402 | .offset = .{ .node_offset_container_tag = .zero }, | |
| 35403 | }; | |
| 35404 | const provided_ty = try sema.resolveType(&block_scope, tag_ty_src, tag_type_ref); | |
| 35405 | if (small.auto_enum_tag) { | |
| 35406 | // The provided type is an integer type and we must construct the enum tag type here. | |
| 35407 | int_tag_ty = provided_ty; | |
| 35408 | if (int_tag_ty.zigTypeTag(zcu) != .int and int_tag_ty.zigTypeTag(zcu) != .comptime_int) { | |
| 35409 | return sema.fail(&block_scope, tag_ty_src, "expected integer tag type, found '{f}'", .{int_tag_ty.fmt(pt)}); | |
| 35410 | } | |
| 35411 | ||
| 35412 | if (fields_len > 0) { | |
| 35413 | const field_count_val = try pt.intValue(.comptime_int, fields_len - 1); | |
| 35414 | if (!(try sema.intFitsInType(field_count_val, int_tag_ty, null))) { | |
| 35415 | const msg = msg: { | |
| 35416 | const msg = try sema.errMsg(tag_ty_src, "specified integer tag type cannot represent every field", .{}); | |
| 35417 | errdefer msg.destroy(sema.gpa); | |
| 35418 | try sema.errNote(tag_ty_src, msg, "type '{f}' cannot fit values in range 0...{d}", .{ | |
| 35419 | int_tag_ty.fmt(pt), | |
| 35420 | fields_len - 1, | |
| 35421 | }); | |
| 35422 | break :msg msg; | |
| 35423 | }; | |
| 35424 | return sema.failWithOwnedErrorMsg(&block_scope, msg); | |
| 35425 | } | |
| 35426 | enum_field_names = try sema.arena.alloc(InternPool.NullTerminatedString, fields_len); | |
| 35427 | try enum_field_vals.ensureTotalCapacity(sema.arena, fields_len); | |
| 35428 | } | |
| 35429 | } else { | |
| 35430 | // The provided type is the enum tag type. | |
| 35431 | const enum_type = switch (ip.indexToKey(provided_ty.toIntern())) { | |
| 35432 | .enum_type => ip.loadEnumType(provided_ty.toIntern()), | |
| 35433 | else => return sema.fail(&block_scope, tag_ty_src, "expected enum tag type, found '{f}'", .{provided_ty.fmt(pt)}), | |
| 35434 | }; | |
| 35435 | union_type.setTagType(ip, io, provided_ty.toIntern()); | |
| 35436 | // The fields of the union must match the enum exactly. | |
| 35437 | // A flag per field is used to check for missing and extraneous fields. | |
| 35438 | explicit_tags_seen = try sema.arena.alloc(bool, enum_type.names.len); | |
| 35439 | @memset(explicit_tags_seen, false); | |
| 35440 | } | |
| 35441 | } else { | |
| 35442 | // If auto_enum_tag is false, this is an untagged union. However, for semantic analysis | |
| 35443 | // purposes, we still auto-generate an enum tag type the same way. That the union is | |
| 35444 | // untagged is represented by the Type tag (union vs union_tagged). | |
| 35445 | enum_field_names = try sema.arena.alloc(InternPool.NullTerminatedString, fields_len); | |
| 35446 | } | |
| 35447 | ||
| 35448 | var field_types: std.ArrayList(InternPool.Index) = .empty; | |
| 35449 | var field_aligns: std.ArrayList(InternPool.Alignment) = .empty; | |
| 35450 | ||
| 35451 | try field_types.ensureTotalCapacityPrecise(sema.arena, fields_len); | |
| 35452 | if (small.any_aligned_fields) | |
| 35453 | try field_aligns.ensureTotalCapacityPrecise(sema.arena, fields_len); | |
| 35454 | ||
| 35455 | var max_bits: u64 = 0; | |
| 35456 | var min_bits: u64 = std.math.maxInt(u64); | |
| 35457 | var max_bits_src: LazySrcLoc = undefined; | |
| 35458 | var min_bits_src: LazySrcLoc = undefined; | |
| 35459 | var max_bits_ty: Type = undefined; | |
| 35460 | var min_bits_ty: Type = undefined; | |
| 35461 | const bits_per_field = 4; | |
| 35462 | const fields_per_u32 = 32 / bits_per_field; | |
| 35463 | const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable; | |
| 35464 | var bit_bag_index: usize = extra_index; | |
| 35465 | extra_index += bit_bags_count; | |
| 35466 | var cur_bit_bag: u32 = undefined; | |
| 35467 | var field_i: u32 = 0; | |
| 35468 | var last_tag_val: ?Value = null; | |
| 35469 | const layout = union_type.flagsUnordered(ip).layout; | |
| 35470 | while (field_i < fields_len) : (field_i += 1) { | |
| 35471 | if (field_i % fields_per_u32 == 0) { | |
| 35472 | cur_bit_bag = zir.extra[bit_bag_index]; | |
| 35473 | bit_bag_index += 1; | |
| 35474 | } | |
| 35475 | const has_type = @as(u1, @truncate(cur_bit_bag)) != 0; | |
| 35476 | cur_bit_bag >>= 1; | |
| 35477 | const has_align = @as(u1, @truncate(cur_bit_bag)) != 0; | |
| 35478 | cur_bit_bag >>= 1; | |
| 35479 | const has_tag = @as(u1, @truncate(cur_bit_bag)) != 0; | |
| 35480 | cur_bit_bag >>= 1; | |
| 35481 | const unused = @as(u1, @truncate(cur_bit_bag)) != 0; | |
| 35482 | cur_bit_bag >>= 1; | |
| 35483 | _ = unused; | |
| 35484 | ||
| 35485 | const field_name_index: Zir.NullTerminatedString = @enumFromInt(zir.extra[extra_index]); | |
| 35486 | const field_name_zir = zir.nullTerminatedString(field_name_index); | |
| 35487 | extra_index += 1; | |
| 35488 | ||
| 35489 | const field_type_ref: Zir.Inst.Ref = if (has_type) blk: { | |
| 35490 | const field_type_ref: Zir.Inst.Ref = @enumFromInt(zir.extra[extra_index]); | |
| 35491 | extra_index += 1; | |
| 35492 | break :blk field_type_ref; | |
| 35493 | } else .none; | |
| 35494 | ||
| 35495 | const align_ref: Zir.Inst.Ref = if (has_align) blk: { | |
| 35496 | const align_ref: Zir.Inst.Ref = @enumFromInt(zir.extra[extra_index]); | |
| 35497 | extra_index += 1; | |
| 35498 | break :blk align_ref; | |
| 35499 | } else .none; | |
| 35500 | ||
| 35501 | const tag_ref: Air.Inst.Ref = if (has_tag) blk: { | |
| 35502 | const tag_ref: Zir.Inst.Ref = @enumFromInt(zir.extra[extra_index]); | |
| 35503 | extra_index += 1; | |
| 35504 | break :blk try sema.resolveInst(tag_ref); | |
| 35505 | } else .none; | |
| 35506 | ||
| 35507 | const name_src: LazySrcLoc = .{ | |
| 35508 | .base_node_inst = union_type.zir_index, | |
| 35509 | .offset = .{ .container_field_name = field_i }, | |
| 35510 | }; | |
| 35511 | const value_src: LazySrcLoc = .{ | |
| 35512 | .base_node_inst = union_type.zir_index, | |
| 35513 | .offset = .{ .container_field_value = field_i }, | |
| 35514 | }; | |
| 35515 | const align_src: LazySrcLoc = .{ | |
| 35516 | .base_node_inst = union_type.zir_index, | |
| 35517 | .offset = .{ .container_field_align = field_i }, | |
| 35518 | }; | |
| 35519 | const type_src: LazySrcLoc = .{ | |
| 35520 | .base_node_inst = union_type.zir_index, | |
| 35521 | .offset = .{ .container_field_type = field_i }, | |
| 35522 | }; | |
| 35523 | ||
| 35524 | if (enum_field_vals.capacity() > 0) { | |
| 35525 | const enum_tag_val = if (tag_ref != .none) blk: { | |
| 35526 | const coerced = try sema.coerce(&block_scope, int_tag_ty, tag_ref, value_src); | |
| 35527 | const val = try sema.resolveConstDefinedValue(&block_scope, value_src, coerced, .{ .simple = .enum_field_tag_value }); | |
| 35528 | last_tag_val = val; | |
| 35529 | ||
| 35530 | break :blk val; | |
| 35531 | } else blk: { | |
| 35532 | if (last_tag_val) |last_tag| { | |
| 35533 | const result = try arith.incrementDefinedInt(sema, int_tag_ty, last_tag); | |
| 35534 | if (result.overflow) return sema.fail( | |
| 35535 | &block_scope, | |
| 35536 | value_src, | |
| 35537 | "enumeration value '{f}' too large for type '{f}'", | |
| 35538 | .{ result.val.fmtValueSema(pt, sema), int_tag_ty.fmt(pt) }, | |
| 35539 | ); | |
| 35540 | last_tag_val = result.val; | |
| 35541 | } else { | |
| 35542 | last_tag_val = try pt.intValue(int_tag_ty, 0); | |
| 35543 | } | |
| 35544 | break :blk last_tag_val.?; | |
| 35545 | }; | |
| 35546 | const gop = enum_field_vals.getOrPutAssumeCapacity(enum_tag_val.toIntern()); | |
| 35547 | if (gop.found_existing) { | |
| 35548 | const other_value_src: LazySrcLoc = .{ | |
| 35549 | .base_node_inst = union_type.zir_index, | |
| 35550 | .offset = .{ .container_field_value = @intCast(gop.index) }, | |
| 35551 | }; | |
| 35552 | const msg = msg: { | |
| 35553 | const msg = try sema.errMsg( | |
| 35554 | value_src, | |
| 35555 | "enum tag value {f} already taken", | |
| 35556 | .{enum_tag_val.fmtValueSema(pt, sema)}, | |
| 35557 | ); | |
| 35558 | errdefer msg.destroy(gpa); | |
| 35559 | try sema.errNote(other_value_src, msg, "other occurrence here", .{}); | |
| 35560 | break :msg msg; | |
| 35561 | }; | |
| 35562 | return sema.failWithOwnedErrorMsg(&block_scope, msg); | |
| 35563 | } | |
| 35564 | } | |
| 35565 | ||
| 35566 | // This string needs to outlive the ZIR code. | |
| 35567 | const field_name = try ip.getOrPutString(gpa, io, pt.tid, field_name_zir, .no_embedded_nulls); | |
| 35568 | if (enum_field_names.len != 0) { | |
| 35569 | enum_field_names[field_i] = field_name; | |
| 35570 | } | |
| 35571 | ||
| 35572 | const field_ty: Type = if (!has_type) | |
| 35573 | .void | |
| 35574 | else if (field_type_ref == .none) | |
| 35575 | .noreturn | |
| 35576 | else | |
| 35577 | try sema.resolveType(&block_scope, type_src, field_type_ref); | |
| 35578 | ||
| 35579 | if (explicit_tags_seen.len > 0) { | |
| 35580 | const tag_ty = union_type.tagTypeUnordered(ip); | |
| 35581 | const tag_info = ip.loadEnumType(tag_ty); | |
| 35582 | const enum_index = tag_info.nameIndex(ip, field_name) orelse { | |
| 35583 | return sema.fail(&block_scope, name_src, "no field named '{f}' in enum '{f}'", .{ | |
| 35584 | field_name.fmt(ip), Type.fromInterned(tag_ty).fmt(pt), | |
| 35585 | }); | |
| 35586 | }; | |
| 35587 | ||
| 35588 | // No check for duplicate because the check already happened in order | |
| 35589 | // to create the enum type in the first place. | |
| 35590 | assert(!explicit_tags_seen[enum_index]); | |
| 35591 | explicit_tags_seen[enum_index] = true; | |
| 35592 | ||
| 35593 | // Enforce the enum fields and the union fields being in the same order. | |
| 35594 | if (enum_index != field_i) { | |
| 35595 | const msg = msg: { | |
| 35596 | const enum_field_src: LazySrcLoc = .{ | |
| 35597 | .base_node_inst = Type.fromInterned(tag_ty).typeDeclInstAllowGeneratedTag(zcu).?, | |
| 35598 | .offset = .{ .container_field_name = enum_index }, | |
| 35599 | }; | |
| 35600 | const msg = try sema.errMsg(name_src, "union field '{f}' ordered differently than corresponding enum field", .{ | |
| 35601 | field_name.fmt(ip), | |
| 35602 | }); | |
| 35603 | errdefer msg.destroy(sema.gpa); | |
| 35604 | try sema.errNote(enum_field_src, msg, "enum field here", .{}); | |
| 35605 | break :msg msg; | |
| 35606 | }; | |
| 35607 | return sema.failWithOwnedErrorMsg(&block_scope, msg); | |
| 35608 | } | |
| 35609 | } | |
| 35610 | ||
| 35611 | if (field_ty.zigTypeTag(zcu) == .@"opaque") { | |
| 35612 | const msg = msg: { | |
| 35613 | const msg = try sema.errMsg(type_src, "opaque types have unknown size and therefore cannot be directly embedded in unions", .{}); | |
| 35614 | errdefer msg.destroy(sema.gpa); | |
| 35615 | ||
| 35616 | try sema.addDeclaredHereNote(msg, field_ty); | |
| 35617 | break :msg msg; | |
| 35618 | }; | |
| 35619 | return sema.failWithOwnedErrorMsg(&block_scope, msg); | |
| 35620 | } | |
| 35621 | switch (layout) { | |
| 35622 | .@"extern" => if (!try sema.validateExternType(field_ty, .union_field)) { | |
| 35623 | const msg = msg: { | |
| 35624 | const msg = try sema.errMsg(type_src, "extern unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); | |
| 35625 | errdefer msg.destroy(sema.gpa); | |
| 35626 | ||
| 35627 | try sema.explainWhyTypeIsNotExtern(msg, type_src, field_ty, .union_field); | |
| 35628 | ||
| 35629 | try sema.addDeclaredHereNote(msg, field_ty); | |
| 35630 | break :msg msg; | |
| 35631 | }; | |
| 35632 | return sema.failWithOwnedErrorMsg(&block_scope, msg); | |
| 35633 | }, | |
| 35634 | .@"packed" => { | |
| 35635 | if (!try sema.validatePackedType(field_ty)) { | |
| 35636 | const msg = msg: { | |
| 35637 | const msg = try sema.errMsg(type_src, "packed unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); | |
| 35638 | errdefer msg.destroy(sema.gpa); | |
| 35639 | ||
| 35640 | try sema.explainWhyTypeIsNotPacked(msg, type_src, field_ty); | |
| 35641 | ||
| 35642 | try sema.addDeclaredHereNote(msg, field_ty); | |
| 35643 | break :msg msg; | |
| 35644 | }; | |
| 35645 | return sema.failWithOwnedErrorMsg(&block_scope, msg); | |
| 35646 | } | |
| 35647 | const field_bits = try field_ty.bitSizeSema(pt); | |
| 35648 | if (field_bits >= max_bits) { | |
| 35649 | max_bits = field_bits; | |
| 35650 | max_bits_src = type_src; | |
| 35651 | max_bits_ty = field_ty; | |
| 35652 | } | |
| 35653 | if (field_bits <= min_bits) { | |
| 35654 | min_bits = field_bits; | |
| 35655 | min_bits_src = type_src; | |
| 35656 | min_bits_ty = field_ty; | |
| 35657 | } | |
| 35658 | }, | |
| 35659 | .auto => {}, | |
| 35660 | } | |
| 35661 | ||
| 35662 | field_types.appendAssumeCapacity(field_ty.toIntern()); | |
| 35663 | ||
| 35664 | if (small.any_aligned_fields) { | |
| 35665 | field_aligns.appendAssumeCapacity(if (align_ref != .none) | |
| 35666 | try sema.resolveAlign(&block_scope, align_src, align_ref) | |
| 35667 | else | |
| 35668 | .none); | |
| 35669 | } else { | |
| 35670 | assert(align_ref == .none); | |
| 35671 | } | |
| 35672 | } | |
| 35673 | ||
| 35674 | union_type.setFieldTypes(ip, field_types.items); | |
| 35675 | union_type.setFieldAligns(ip, field_aligns.items); | |
| 35676 | ||
| 35677 | if (layout == .@"packed" and fields_len != 0 and min_bits != max_bits) { | |
| 35678 | const msg = msg: { | |
| 35679 | const msg = try sema.errMsg(src, "packed union has fields with mismatching bit sizes", .{}); | |
| 35680 | errdefer msg.destroy(sema.gpa); | |
| 35681 | try sema.errNote(min_bits_src, msg, "{d} bits here", .{min_bits}); | |
| 35682 | try sema.addDeclaredHereNote(msg, min_bits_ty); | |
| 35683 | try sema.errNote(max_bits_src, msg, "{d} bits here", .{max_bits}); | |
| 35684 | try sema.addDeclaredHereNote(msg, max_bits_ty); | |
| 35685 | break :msg msg; | |
| 35686 | }; | |
| 35687 | return sema.failWithOwnedErrorMsg(&block_scope, msg); | |
| 35688 | } | |
| 35689 | ||
| 35690 | if (explicit_tags_seen.len > 0) { | |
| 35691 | const tag_ty = union_type.tagTypeUnordered(ip); | |
| 35692 | const tag_info = ip.loadEnumType(tag_ty); | |
| 35693 | if (tag_info.names.len > fields_len) { | |
| 35694 | const msg = msg: { | |
| 35695 | const msg = try sema.errMsg(src, "enum field(s) missing in union", .{}); | |
| 35696 | errdefer msg.destroy(sema.gpa); | |
| 35697 | ||
| 35698 | for (tag_info.names.get(ip), 0..) |field_name, field_index| { | |
| 35699 | if (explicit_tags_seen[field_index]) continue; | |
| 35700 | try sema.addFieldErrNote(.fromInterned(tag_ty), field_index, msg, "field '{f}' missing, declared here", .{ | |
| 35701 | field_name.fmt(ip), | |
| 35702 | }); | |
| 35703 | } | |
| 35704 | try sema.addDeclaredHereNote(msg, .fromInterned(tag_ty)); | |
| 35705 | break :msg msg; | |
| 35706 | }; | |
| 35707 | return sema.failWithOwnedErrorMsg(&block_scope, msg); | |
| 35708 | } | |
| 35709 | } else if (enum_field_vals.count() > 0) { | |
| 35710 | const enum_ty = try sema.generateUnionTagTypeNumbered(&block_scope, enum_field_names, enum_field_vals.keys(), union_ty, union_type.name); | |
| 35711 | union_type.setTagType(ip, io, enum_ty); | |
| 35712 | } else { | |
| 35713 | const enum_ty = try sema.generateUnionTagTypeSimple(&block_scope, enum_field_names, union_ty, union_type.name); | |
| 35714 | union_type.setTagType(ip, io, enum_ty); | |
| 35715 | } | |
| 35716 | ||
| 35717 | try sema.flushExports(); | |
| 35718 | } | |
| 35719 | ||
| 35720 | fn generateUnionTagTypeNumbered( | |
| 35721 | sema: *Sema, | |
| 35722 | block: *Block, | |
| 35723 | enum_field_names: []const InternPool.NullTerminatedString, | |
| 35724 | enum_field_vals: []const InternPool.Index, | |
| 35725 | union_type: InternPool.Index, | |
| 35726 | union_name: InternPool.NullTerminatedString, | |
| 35727 | ) !InternPool.Index { | |
| 35728 | const pt = sema.pt; | |
| 35729 | const zcu = pt.zcu; | |
| 35730 | const comp = zcu.comp; | |
| 35731 | const gpa = comp.gpa; | |
| 35732 | const io = comp.io; | |
| 35733 | const ip = &zcu.intern_pool; | |
| 35734 | ||
| 35735 | const name = try ip.getOrPutStringFmt( | |
| 35736 | gpa, | |
| 35737 | io, | |
| 35738 | pt.tid, | |
| 35739 | "@typeInfo({f}).@\"union\".tag_type.?", | |
| 35740 | .{union_name.fmt(ip)}, | |
| 35741 | .no_embedded_nulls, | |
| 35742 | ); | |
| 35743 | ||
| 35744 | const enum_ty = try ip.getGeneratedTagEnumType(gpa, io, pt.tid, .{ | |
| 35745 | .name = name, | |
| 35746 | .owner_union_ty = union_type, | |
| 35747 | .tag_ty = if (enum_field_vals.len == 0) | |
| 35748 | (try pt.intType(.unsigned, 0)).toIntern() | |
| 35749 | else | |
| 35750 | ip.typeOf(enum_field_vals[0]), | |
| 35751 | .names = enum_field_names, | |
| 35752 | .values = enum_field_vals, | |
| 35753 | .tag_mode = .explicit, | |
| 35754 | .parent_namespace = block.namespace, | |
| 35755 | }); | |
| 35756 | ||
| 35757 | return enum_ty; | |
| 35758 | } | |
| 35759 | ||
| 35760 | fn generateUnionTagTypeSimple( | |
| 35761 | sema: *Sema, | |
| 35762 | block: *Block, | |
| 35763 | enum_field_names: []const InternPool.NullTerminatedString, | |
| 35764 | union_type: InternPool.Index, | |
| 35765 | union_name: InternPool.NullTerminatedString, | |
| 35766 | ) !InternPool.Index { | |
| 35767 | const pt = sema.pt; | |
| 35768 | const zcu = pt.zcu; | |
| 35769 | const comp = zcu.comp; | |
| 35770 | const gpa = comp.gpa; | |
| 35771 | const io = comp.io; | |
| 35772 | const ip = &zcu.intern_pool; | |
| 35773 | ||
| 35774 | const name = try ip.getOrPutStringFmt( | |
| 35775 | gpa, | |
| 35776 | io, | |
| 35777 | pt.tid, | |
| 35778 | "@typeInfo({f}).@\"union\".tag_type.?", | |
| 35779 | .{union_name.fmt(ip)}, | |
| 35780 | .no_embedded_nulls, | |
| 35781 | ); | |
| 35782 | ||
| 35783 | const enum_ty = try ip.getGeneratedTagEnumType(gpa, io, pt.tid, .{ | |
| 35784 | .name = name, | |
| 35785 | .owner_union_ty = union_type, | |
| 35786 | .tag_ty = (try pt.smallestUnsignedInt(enum_field_names.len -| 1)).toIntern(), | |
| 35787 | .names = enum_field_names, | |
| 35788 | .values = &.{}, | |
| 35789 | .tag_mode = .auto, | |
| 35790 | .parent_namespace = block.namespace, | |
| 35791 | }); | |
| 35792 | ||
| 35793 | return enum_ty; | |
| 35794 | } | |
| 35795 | ||
| 35796 | /// There is another implementation of this in `Type.onePossibleValue`. This one | |
| 35797 | /// in `Sema` is for calling during semantic analysis, and performs field resolution | |
| 35798 | /// to get the answer. The one in `Type` is for calling during codegen and asserts | |
| 35799 | /// that the types are already resolved. | |
| 35800 | /// TODO assert the return value matches `ty.onePossibleValue` | |
| 35801 | pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { | |
| 35802 | const pt = sema.pt; | |
| 35803 | const zcu = pt.zcu; | |
| 35804 | const comp = zcu.comp; | |
| 35805 | const gpa = comp.gpa; | |
| 35806 | const io = comp.io; | |
| 35807 | const ip = &zcu.intern_pool; | |
| 35808 | ||
| 35809 | return switch (ty.toIntern()) { | |
| 35810 | .u0_type, | |
| 35811 | .i0_type, | |
| 35812 | => try pt.intValue(ty, 0), | |
| 35813 | .u1_type, | |
| 35814 | .u8_type, | |
| 35815 | .i8_type, | |
| 35816 | .u16_type, | |
| 35817 | .i16_type, | |
| 35818 | .u29_type, | |
| 35819 | .u32_type, | |
| 35820 | .i32_type, | |
| 35821 | .u64_type, | |
| 35822 | .i64_type, | |
| 35823 | .u80_type, | |
| 35824 | .u128_type, | |
| 35825 | .i128_type, | |
| 35826 | .u256_type, | |
| 35827 | .usize_type, | |
| 35828 | .isize_type, | |
| 35829 | .c_char_type, | |
| 35830 | .c_short_type, | |
| 35831 | .c_ushort_type, | |
| 35832 | .c_int_type, | |
| 35833 | .c_uint_type, | |
| 35834 | .c_long_type, | |
| 35835 | .c_ulong_type, | |
| 35836 | .c_longlong_type, | |
| 35837 | .c_ulonglong_type, | |
| 35838 | .c_longdouble_type, | |
| 35839 | .f16_type, | |
| 35840 | .f32_type, | |
| 35841 | .f64_type, | |
| 35842 | .f80_type, | |
| 35843 | .f128_type, | |
| 35844 | .anyopaque_type, | |
| 35845 | .bool_type, | |
| 35846 | .type_type, | |
| 35847 | .anyerror_type, | |
| 35848 | .adhoc_inferred_error_set_type, | |
| 35849 | .comptime_int_type, | |
| 35850 | .comptime_float_type, | |
| 35851 | .enum_literal_type, | |
| 35852 | .ptr_usize_type, | |
| 35853 | .ptr_const_comptime_int_type, | |
| 35854 | .manyptr_u8_type, | |
| 35855 | .manyptr_const_u8_type, | |
| 35856 | .manyptr_const_u8_sentinel_0_type, | |
| 35857 | .manyptr_const_slice_const_u8_type, | |
| 35858 | .slice_const_u8_type, | |
| 35859 | .slice_const_u8_sentinel_0_type, | |
| 35860 | .slice_const_slice_const_u8_type, | |
| 35861 | .optional_type_type, | |
| 35862 | .manyptr_const_type_type, | |
| 35863 | .slice_const_type_type, | |
| 35864 | .vector_8_i8_type, | |
| 35865 | .vector_16_i8_type, | |
| 35866 | .vector_32_i8_type, | |
| 35867 | .vector_64_i8_type, | |
| 35868 | .vector_1_u8_type, | |
| 35869 | .vector_2_u8_type, | |
| 35870 | .vector_4_u8_type, | |
| 35871 | .vector_8_u8_type, | |
| 35872 | .vector_16_u8_type, | |
| 35873 | .vector_32_u8_type, | |
| 35874 | .vector_64_u8_type, | |
| 35875 | .vector_2_i16_type, | |
| 35876 | .vector_4_i16_type, | |
| 35877 | .vector_8_i16_type, | |
| 35878 | .vector_16_i16_type, | |
| 35879 | .vector_32_i16_type, | |
| 35880 | .vector_4_u16_type, | |
| 35881 | .vector_8_u16_type, | |
| 35882 | .vector_16_u16_type, | |
| 35883 | .vector_32_u16_type, | |
| 35884 | .vector_2_i32_type, | |
| 35885 | .vector_4_i32_type, | |
| 35886 | .vector_8_i32_type, | |
| 35887 | .vector_16_i32_type, | |
| 35888 | .vector_4_u32_type, | |
| 35889 | .vector_8_u32_type, | |
| 35890 | .vector_16_u32_type, | |
| 35891 | .vector_2_i64_type, | |
| 35892 | .vector_4_i64_type, | |
| 35893 | .vector_8_i64_type, | |
| 35894 | .vector_2_u64_type, | |
| 35895 | .vector_4_u64_type, | |
| 35896 | .vector_8_u64_type, | |
| 35897 | .vector_1_u128_type, | |
| 35898 | .vector_2_u128_type, | |
| 35899 | .vector_1_u256_type, | |
| 35900 | .vector_4_f16_type, | |
| 35901 | .vector_8_f16_type, | |
| 35902 | .vector_16_f16_type, | |
| 35903 | .vector_32_f16_type, | |
| 35904 | .vector_2_f32_type, | |
| 35905 | .vector_4_f32_type, | |
| 35906 | .vector_8_f32_type, | |
| 35907 | .vector_16_f32_type, | |
| 35908 | .vector_2_f64_type, | |
| 35909 | .vector_4_f64_type, | |
| 35910 | .vector_8_f64_type, | |
| 35911 | .anyerror_void_error_union_type, | |
| 35912 | => null, | |
| 35913 | .void_type => Value.void, | |
| 35914 | .noreturn_type => Value.@"unreachable", | |
| 35915 | .anyframe_type => unreachable, | |
| 35916 | .null_type => Value.null, | |
| 35917 | .undefined_type => Value.undef, | |
| 35918 | .optional_noreturn_type => try pt.nullValue(ty), | |
| 35919 | .generic_poison_type => unreachable, | |
| 35920 | .empty_tuple_type => Value.empty_tuple, | |
| 35921 | // values, not types | |
| 35922 | .undef, | |
| 35923 | .undef_bool, | |
| 35924 | .undef_usize, | |
| 35925 | .undef_u1, | |
| 35926 | .zero, | |
| 35927 | .zero_usize, | |
| 35928 | .zero_u1, | |
| 35929 | .zero_u8, | |
| 35930 | .one, | |
| 35931 | .one_usize, | |
| 35932 | .one_u1, | |
| 35933 | .one_u8, | |
| 35934 | .four_u8, | |
| 35935 | .negative_one, | |
| 35936 | .void_value, | |
| 35937 | .unreachable_value, | |
| 35938 | .null_value, | |
| 35939 | .bool_true, | |
| 35940 | .bool_false, | |
| 35941 | .empty_tuple, | |
| 35942 | // invalid | |
| 35943 | .none, | |
| 35944 | => unreachable, | |
| 35945 | ||
| 35946 | _ => switch (ty.toIntern().unwrap(ip).getTag(ip)) { | |
| 35947 | .removed => unreachable, | |
| 35948 | ||
| 35949 | .type_int_signed, // i0 handled above | |
| 35950 | .type_int_unsigned, // u0 handled above | |
| 35951 | .type_pointer, | |
| 35952 | .type_slice, | |
| 35953 | .type_anyframe, | |
| 35954 | .type_error_union, | |
| 35955 | .type_anyerror_union, | |
| 35956 | .type_error_set, | |
| 35957 | .type_inferred_error_set, | |
| 35958 | .type_opaque, | |
| 35959 | .type_function, | |
| 35960 | => null, | |
| 35961 | ||
| 35962 | .simple_type, // handled above | |
| 35963 | // values, not types | |
| 35964 | .undef, | |
| 35965 | .simple_value, | |
| 35966 | .ptr_nav, | |
| 35967 | .ptr_uav, | |
| 35968 | .ptr_uav_aligned, | |
| 35969 | .ptr_comptime_alloc, | |
| 35970 | .ptr_comptime_field, | |
| 35971 | .ptr_int, | |
| 35972 | .ptr_eu_payload, | |
| 35973 | .ptr_opt_payload, | |
| 35974 | .ptr_elem, | |
| 35975 | .ptr_field, | |
| 35976 | .ptr_slice, | |
| 35977 | .opt_payload, | |
| 35978 | .opt_null, | |
| 35979 | .int_u8, | |
| 35980 | .int_u16, | |
| 35981 | .int_u32, | |
| 35982 | .int_i32, | |
| 35983 | .int_usize, | |
| 35984 | .int_comptime_int_u32, | |
| 35985 | .int_comptime_int_i32, | |
| 35986 | .int_small, | |
| 35987 | .int_positive, | |
| 35988 | .int_negative, | |
| 35989 | .int_lazy_align, | |
| 35990 | .int_lazy_size, | |
| 35991 | .error_set_error, | |
| 35992 | .error_union_error, | |
| 35993 | .error_union_payload, | |
| 35994 | .enum_literal, | |
| 35995 | .enum_tag, | |
| 35996 | .float_f16, | |
| 35997 | .float_f32, | |
| 35998 | .float_f64, | |
| 35999 | .float_f80, | |
| 36000 | .float_f128, | |
| 36001 | .float_c_longdouble_f80, | |
| 36002 | .float_c_longdouble_f128, | |
| 36003 | .float_comptime_float, | |
| 36004 | .variable, | |
| 36005 | .threadlocal_variable, | |
| 36006 | .@"extern", | |
| 36007 | .func_decl, | |
| 36008 | .func_instance, | |
| 36009 | .func_coerced, | |
| 36010 | .only_possible_value, | |
| 36011 | .union_value, | |
| 36012 | .bytes, | |
| 36013 | .aggregate, | |
| 36014 | .repeated, | |
| 36015 | // memoized value, not types | |
| 36016 | .memoized_call, | |
| 36017 | => unreachable, | |
| 36018 | ||
| 36019 | .type_array_big, | |
| 36020 | .type_array_small, | |
| 36021 | .type_vector, | |
| 36022 | .type_enum_auto, | |
| 36023 | .type_enum_explicit, | |
| 36024 | .type_enum_nonexhaustive, | |
| 36025 | .type_struct, | |
| 36026 | .type_struct_packed, | |
| 36027 | .type_struct_packed_inits, | |
| 36028 | .type_tuple, | |
| 36029 | .type_union, | |
| 36030 | => switch (ip.indexToKey(ty.toIntern())) { | |
| 36031 | inline .array_type, .vector_type => |seq_type, seq_tag| { | |
| 36032 | const has_sentinel = seq_tag == .array_type and seq_type.sentinel != .none; | |
| 36033 | if (seq_type.len + @intFromBool(has_sentinel) == 0) return try pt.aggregateValue(ty, &.{}); | |
| 36034 | if (try sema.typeHasOnePossibleValue(.fromInterned(seq_type.child))) |opv| { | |
| 36035 | return try pt.aggregateSplatValue(ty, opv); | |
| 36036 | } | |
| 36037 | return null; | |
| 36038 | }, | |
| 36039 | ||
| 36040 | .struct_type => { | |
| 36041 | // Resolving the layout first helps to avoid loops. | |
| 36042 | // If the type has a coherent layout, we can recurse through fields safely. | |
| 36043 | try ty.resolveLayout(pt); | |
| 36044 | ||
| 36045 | const struct_type = ip.loadStructType(ty.toIntern()); | |
| 36046 | ||
| 36047 | if (struct_type.field_types.len == 0) { | |
| 36048 | // In this case the struct has no fields at all and | |
| 36049 | // therefore has one possible value. | |
| 36050 | return try pt.aggregateValue(ty, &.{}); | |
| 36051 | } | |
| 36052 | ||
| 36053 | const field_vals = try sema.arena.alloc( | |
| 36054 | InternPool.Index, | |
| 36055 | struct_type.field_types.len, | |
| 36056 | ); | |
| 36057 | for (field_vals, 0..) |*field_val, i| { | |
| 36058 | if (struct_type.fieldIsComptime(ip, i)) { | |
| 36059 | try ty.resolveStructFieldInits(pt); | |
| 36060 | field_val.* = struct_type.field_inits.get(ip)[i]; | |
| 36061 | continue; | |
| 36062 | } | |
| 36063 | const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[i]); | |
| 36064 | if (try sema.typeHasOnePossibleValue(field_ty)) |field_opv| { | |
| 36065 | field_val.* = field_opv.toIntern(); | |
| 36066 | } else return null; | |
| 36067 | } | |
| 36068 | ||
| 36069 | // In this case the struct has no runtime-known fields and | |
| 36070 | // therefore has one possible value. | |
| 36071 | return try pt.aggregateValue(ty, field_vals); | |
| 36072 | }, | |
| 36073 | ||
| 36074 | .tuple_type => |tuple| { | |
| 36075 | try ty.resolveLayout(pt); | |
| 36076 | ||
| 36077 | if (tuple.types.len == 0) { | |
| 36078 | return try pt.aggregateValue(ty, &.{}); | |
| 36079 | } | |
| 36080 | ||
| 36081 | const field_vals = try sema.arena.alloc( | |
| 36082 | InternPool.Index, | |
| 36083 | tuple.types.len, | |
| 36084 | ); | |
| 36085 | for ( | |
| 36086 | field_vals, | |
| 36087 | tuple.types.get(ip), | |
| 36088 | tuple.values.get(ip), | |
| 36089 | ) |*field_val, field_ty, field_comptime_val| { | |
| 36090 | if (field_comptime_val != .none) { | |
| 36091 | field_val.* = field_comptime_val; | |
| 36092 | continue; | |
| 36093 | } | |
| 36094 | if (try sema.typeHasOnePossibleValue(.fromInterned(field_ty))) |opv| { | |
| 36095 | field_val.* = opv.toIntern(); | |
| 36096 | } else return null; | |
| 36097 | } | |
| 36098 | ||
| 36099 | return try pt.aggregateValue(ty, field_vals); | |
| 36100 | }, | |
| 36101 | ||
| 36102 | .union_type => { | |
| 36103 | // Resolving the layout first helps to avoid loops. | |
| 36104 | // If the type has a coherent layout, we can recurse through fields safely. | |
| 36105 | try ty.resolveLayout(pt); | |
| 36106 | ||
| 36107 | const union_obj = ip.loadUnionType(ty.toIntern()); | |
| 36108 | const tag_val = (try sema.typeHasOnePossibleValue(.fromInterned(union_obj.tagTypeUnordered(ip)))) orelse | |
| 36109 | return null; | |
| 36110 | if (union_obj.field_types.len == 0) { | |
| 36111 | const only = try pt.intern(.{ .empty_enum_value = ty.toIntern() }); | |
| 36112 | return Value.fromInterned(only); | |
| 36113 | } | |
| 36114 | const only_field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[0]); | |
| 36115 | const val_val = (try sema.typeHasOnePossibleValue(only_field_ty)) orelse | |
| 36116 | return null; | |
| 36117 | const only = try pt.internUnion(.{ | |
| 36118 | .ty = ty.toIntern(), | |
| 36119 | .tag = tag_val.toIntern(), | |
| 36120 | .val = val_val.toIntern(), | |
| 36121 | }); | |
| 36122 | return Value.fromInterned(only); | |
| 36123 | }, | |
| 36124 | ||
| 36125 | .enum_type => { | |
| 36126 | const enum_type = ip.loadEnumType(ty.toIntern()); | |
| 36127 | switch (enum_type.tag_mode) { | |
| 36128 | .nonexhaustive => { | |
| 36129 | if (enum_type.tag_ty == .comptime_int_type) return null; | |
| 36130 | ||
| 36131 | if (try sema.typeHasOnePossibleValue(.fromInterned(enum_type.tag_ty))) |int_opv| { | |
| 36132 | const only = try pt.intern(.{ .enum_tag = .{ | |
| 36133 | .ty = ty.toIntern(), | |
| 36134 | .int = int_opv.toIntern(), | |
| 36135 | } }); | |
| 36136 | return Value.fromInterned(only); | |
| 36137 | } | |
| 36138 | ||
| 36139 | return null; | |
| 36140 | }, | |
| 36141 | .auto, .explicit => { | |
| 36142 | if (Type.fromInterned(enum_type.tag_ty).hasRuntimeBits(zcu)) return null; | |
| 36143 | ||
| 36144 | return Value.fromInterned(switch (enum_type.names.len) { | |
| 36145 | 0 => try pt.intern(.{ .empty_enum_value = ty.toIntern() }), | |
| 36146 | 1 => try pt.intern(.{ .enum_tag = .{ | |
| 36147 | .ty = ty.toIntern(), | |
| 36148 | .int = if (enum_type.values.len == 0) | |
| 36149 | (try pt.intValue(.fromInterned(enum_type.tag_ty), 0)).toIntern() | |
| 36150 | else | |
| 36151 | try ip.getCoercedInts( | |
| 36152 | gpa, | |
| 36153 | io, | |
| 36154 | pt.tid, | |
| 36155 | ip.indexToKey(enum_type.values.get(ip)[0]).int, | |
| 36156 | enum_type.tag_ty, | |
| 36157 | ), | |
| 36158 | } }), | |
| 36159 | else => return null, | |
| 36160 | }); | |
| 36161 | }, | |
| 36162 | } | |
| 36163 | }, | |
| 36164 | ||
| 36165 | else => unreachable, | |
| 36166 | }, | |
| 36167 | ||
| 36168 | .type_optional => { | |
| 36169 | const payload_ip = ip.indexToKey(ty.toIntern()).opt_type; | |
| 36170 | // Although ?noreturn is handled above, the element type | |
| 36171 | // can be effectively noreturn for example via an empty | |
| 36172 | // enum or error set. | |
| 36173 | if (ip.isNoReturn(payload_ip)) return try pt.nullValue(ty); | |
| 36174 | return null; | |
| 36175 | }, | |
| 36176 | }, | |
| 36177 | }; | |
| 36178 | } | |
| 36179 | ||
| 36180 | 33507 | /// Returns the type of the AIR instruction. |
| 36181 | 33508 | fn typeOf(sema: *Sema, inst: Air.Inst.Ref) Type { |
| 36182 | 33509 | return sema.getTmpAir().typeOf(inst, &sema.pt.zcu.intern_pool); |
| ... | ... | @@ -36235,6 +33562,7 @@ fn isComptimeKnown( |
| 36235 | 33562 | return (try sema.resolveValue(inst)) != null; |
| 36236 | 33563 | } |
| 36237 | 33564 | |
| 33565 | /// Asserts that the layout of `var_type` has already been resolved. | |
| 36238 | 33566 | fn analyzeComptimeAlloc( |
| 36239 | 33567 | sema: *Sema, |
| 36240 | 33568 | block: *Block, |
| ... | ... | @@ -36245,10 +33573,9 @@ fn analyzeComptimeAlloc( |
| 36245 | 33573 | const pt = sema.pt; |
| 36246 | 33574 | const zcu = pt.zcu; |
| 36247 | 33575 | |
| 36248 | // Needed to make an anon decl with type `var_type` (the `finish()` call below). | |
| 36249 | _ = try sema.typeHasOnePossibleValue(var_type); | |
| 33576 | var_type.assertHasLayout(zcu); | |
| 36250 | 33577 | |
| 36251 | const ptr_type = try pt.ptrTypeSema(.{ | |
| 33578 | const ptr_type = try pt.ptrType(.{ | |
| 36252 | 33579 | .child = var_type.toIntern(), |
| 36253 | 33580 | .flags = .{ |
| 36254 | 33581 | .alignment = alignment, |
| ... | ... | @@ -36256,13 +33583,23 @@ fn analyzeComptimeAlloc( |
| 36256 | 33583 | }, |
| 36257 | 33584 | }); |
| 36258 | 33585 | |
| 36259 | const alloc = try sema.newComptimeAlloc(block, src, var_type, alignment); | |
| 36260 | ||
| 36261 | return Air.internedToRef((try pt.intern(.{ .ptr = .{ | |
| 36262 | .ty = ptr_type.toIntern(), | |
| 36263 | .base_addr = .{ .comptime_alloc = alloc }, | |
| 36264 | .byte_offset = 0, | |
| 36265 | } }))); | |
| 33586 | if (try var_type.onePossibleValue(pt)) |opv| { | |
| 33587 | return .fromIntern(try pt.intern(.{ .ptr = .{ | |
| 33588 | .ty = ptr_type.toIntern(), | |
| 33589 | .base_addr = .{ .uav = .{ | |
| 33590 | .val = opv.toIntern(), | |
| 33591 | .orig_ty = ptr_type.toIntern(), | |
| 33592 | } }, | |
| 33593 | .byte_offset = 0, | |
| 33594 | } })); | |
| 33595 | } else { | |
| 33596 | const alloc = try sema.newComptimeAlloc(block, src, var_type, alignment); | |
| 33597 | return .fromIntern(try pt.intern(.{ .ptr = .{ | |
| 33598 | .ty = ptr_type.toIntern(), | |
| 33599 | .base_addr = .{ .comptime_alloc = alloc }, | |
| 33600 | .byte_offset = 0, | |
| 33601 | } })); | |
| 33602 | } | |
| 36266 | 33603 | } |
| 36267 | 33604 | |
| 36268 | 33605 | fn resolveAddressSpace( |
| ... | ... | @@ -36363,40 +33700,6 @@ fn usizeCast(sema: *Sema, block: *Block, src: LazySrcLoc, int: u64) CompileError |
| 36363 | 33700 | return std.math.cast(usize, int) orelse return sema.fail(block, src, "expression produces integer value '{d}' which is too big for this compiler implementation to handle", .{int}); |
| 36364 | 33701 | } |
| 36365 | 33702 | |
| 36366 | /// For pointer-like optionals, it returns the pointer type. For pointers, | |
| 36367 | /// the type is returned unmodified. | |
| 36368 | /// This can return `error.AnalysisFail` because it sometimes requires resolving whether | |
| 36369 | /// a type has zero bits, which can cause a "foo depends on itself" compile error. | |
| 36370 | /// This logic must be kept in sync with `Type.isPtrLikeOptional`. | |
| 36371 | fn typePtrOrOptionalPtrTy(sema: *Sema, ty: Type) !?Type { | |
| 36372 | const pt = sema.pt; | |
| 36373 | const zcu = pt.zcu; | |
| 36374 | return switch (zcu.intern_pool.indexToKey(ty.toIntern())) { | |
| 36375 | .ptr_type => |ptr_type| switch (ptr_type.flags.size) { | |
| 36376 | .one, .many, .c => ty, | |
| 36377 | .slice => null, | |
| 36378 | }, | |
| 36379 | .opt_type => |opt_child| switch (zcu.intern_pool.indexToKey(opt_child)) { | |
| 36380 | .ptr_type => |ptr_type| switch (ptr_type.flags.size) { | |
| 36381 | .slice, .c => null, | |
| 36382 | .many, .one => { | |
| 36383 | if (ptr_type.flags.is_allowzero) return null; | |
| 36384 | ||
| 36385 | // optionals of zero sized types behave like bools, not pointers | |
| 36386 | const payload_ty: Type = .fromInterned(opt_child); | |
| 36387 | if ((try sema.typeHasOnePossibleValue(payload_ty)) != null) { | |
| 36388 | return null; | |
| 36389 | } | |
| 36390 | ||
| 36391 | return payload_ty; | |
| 36392 | }, | |
| 36393 | }, | |
| 36394 | else => null, | |
| 36395 | }, | |
| 36396 | else => null, | |
| 36397 | }; | |
| 36398 | } | |
| 36399 | ||
| 36400 | 33703 | fn unionFieldIndex( |
| 36401 | 33704 | sema: *Sema, |
| 36402 | 33705 | block: *Block, |
| ... | ... | @@ -36407,9 +33710,9 @@ fn unionFieldIndex( |
| 36407 | 33710 | const pt = sema.pt; |
| 36408 | 33711 | const zcu = pt.zcu; |
| 36409 | 33712 | const ip = &zcu.intern_pool; |
| 36410 | try union_ty.resolveFields(pt); | |
| 36411 | 33713 | const union_obj = zcu.typeToUnion(union_ty).?; |
| 36412 | const field_index = union_obj.loadTagType(ip).nameIndex(ip, field_name) orelse | |
| 33714 | const enum_obj = ip.loadEnumType(union_obj.enum_tag_type); | |
| 33715 | const field_index = enum_obj.nameIndex(ip, field_name) orelse | |
| 36413 | 33716 | return sema.failWithBadUnionFieldAccess(block, union_ty, union_obj, field_src, field_name); |
| 36414 | 33717 | return @intCast(field_index); |
| 36415 | 33718 | } |
| ... | ... | @@ -36424,7 +33727,6 @@ fn structFieldIndex( |
| 36424 | 33727 | const pt = sema.pt; |
| 36425 | 33728 | const zcu = pt.zcu; |
| 36426 | 33729 | const ip = &zcu.intern_pool; |
| 36427 | try struct_ty.resolveFields(pt); | |
| 36428 | 33730 | const struct_type = zcu.typeToStruct(struct_ty).?; |
| 36429 | 33731 | return struct_type.nameIndex(ip, field_name) orelse |
| 36430 | 33732 | return sema.failWithBadStructFieldAccess(block, struct_ty, struct_type, field_src, field_name); |
| ... | ... | @@ -36513,6 +33815,7 @@ fn intFromFloatScalar( |
| 36513 | 33815 | /// Vectors are also accepted. Vector results are reduced with AND. |
| 36514 | 33816 | /// |
| 36515 | 33817 | /// If provided, `vector_index` reports the first element that failed the range check. |
| 33818 | /// MLUGG TODO: move to `Value` or `Type`? | |
| 36516 | 33819 | fn intFitsInType( |
| 36517 | 33820 | sema: *Sema, |
| 36518 | 33821 | val: Value, |
| ... | ... | @@ -36535,30 +33838,10 @@ fn intFitsInType( |
| 36535 | 33838 | .unsigned => info.bits >= ptr_bits, |
| 36536 | 33839 | }; |
| 36537 | 33840 | }, |
| 36538 | .int => |int| switch (int.storage) { | |
| 36539 | .u64, .i64, .big_int => { | |
| 36540 | var buffer: InternPool.Key.Int.Storage.BigIntSpace = undefined; | |
| 36541 | const big_int = int.storage.toBigInt(&buffer); | |
| 36542 | return big_int.fitsInTwosComp(info.signedness, info.bits); | |
| 36543 | }, | |
| 36544 | .lazy_align => |lazy_ty| { | |
| 36545 | const max_needed_bits = @as(u16, 16) + @intFromBool(info.signedness == .signed); | |
| 36546 | // If it is u16 or bigger we know the alignment fits without resolving it. | |
| 36547 | if (info.bits >= max_needed_bits) return true; | |
| 36548 | const x = try Type.fromInterned(lazy_ty).abiAlignmentSema(pt); | |
| 36549 | if (x == .none) return true; | |
| 36550 | const actual_needed_bits = @as(usize, x.toLog2Units()) + 1 + @intFromBool(info.signedness == .signed); | |
| 36551 | return info.bits >= actual_needed_bits; | |
| 36552 | }, | |
| 36553 | .lazy_size => |lazy_ty| { | |
| 36554 | const max_needed_bits = @as(u16, 64) + @intFromBool(info.signedness == .signed); | |
| 36555 | // If it is u64 or bigger we know the size fits without resolving it. | |
| 36556 | if (info.bits >= max_needed_bits) return true; | |
| 36557 | const x = try Type.fromInterned(lazy_ty).abiSizeSema(pt); | |
| 36558 | if (x == 0) return true; | |
| 36559 | const actual_needed_bits = std.math.log2(x) + 1 + @intFromBool(info.signedness == .signed); | |
| 36560 | return info.bits >= actual_needed_bits; | |
| 36561 | }, | |
| 33841 | .int => |int| { | |
| 33842 | var buffer: InternPool.Key.Int.Storage.BigIntSpace = undefined; | |
| 33843 | const big_int = int.storage.toBigInt(&buffer); | |
| 33844 | return big_int.fitsInTwosComp(info.signedness, info.bits); | |
| 36562 | 33845 | }, |
| 36563 | 33846 | .aggregate => |aggregate| { |
| 36564 | 33847 | assert(ty.zigTypeTag(zcu) == .vector); |
| ... | ... | @@ -36588,23 +33871,23 @@ fn intFitsInType( |
| 36588 | 33871 | |
| 36589 | 33872 | fn intInRange(sema: *Sema, tag_ty: Type, int_val: Value, end: usize) !bool { |
| 36590 | 33873 | const pt = sema.pt; |
| 36591 | if (!(try int_val.compareAllWithZeroSema(.gte, pt))) return false; | |
| 33874 | if (!int_val.compareAllWithZero(.gte, pt.zcu)) return false; | |
| 36592 | 33875 | const end_val = try pt.intValue(tag_ty, end); |
| 36593 | 33876 | if (!(try sema.compareAll(int_val, .lt, end_val, tag_ty))) return false; |
| 36594 | 33877 | return true; |
| 36595 | 33878 | } |
| 36596 | 33879 | |
| 36597 | /// Asserts the type is an enum. | |
| 33880 | /// Asserts the type is an exhaustive enum. | |
| 36598 | 33881 | fn enumHasInt(sema: *Sema, ty: Type, int: Value) CompileError!bool { |
| 36599 | 33882 | const pt = sema.pt; |
| 36600 | 33883 | const zcu = pt.zcu; |
| 36601 | 33884 | const enum_type = zcu.intern_pool.loadEnumType(ty.toIntern()); |
| 36602 | assert(enum_type.tag_mode != .nonexhaustive); | |
| 33885 | assert(!enum_type.nonexhaustive); | |
| 36603 | 33886 | // The `tagValueIndex` function call below relies on the type being the integer tag type. |
| 36604 | 33887 | // `getCoerced` assumes the value will fit the new type. |
| 36605 | if (!(try sema.intFitsInType(int, .fromInterned(enum_type.tag_ty), null))) return false; | |
| 36606 | const int_coerced = try pt.getCoerced(int, .fromInterned(enum_type.tag_ty)); | |
| 36607 | ||
| 33888 | const int_tag_ty: Type = .fromInterned(enum_type.int_tag_type); | |
| 33889 | if (!try sema.intFitsInType(int, int_tag_ty, null)) return false; | |
| 33890 | const int_coerced = try pt.getCoerced(int, int_tag_ty); | |
| 36608 | 33891 | return enum_type.tagValueIndex(&zcu.intern_pool, int_coerced.toIntern()) != null; |
| 36609 | 33892 | } |
| 36610 | 33893 | |
| ... | ... | @@ -36636,6 +33919,7 @@ fn compareAll( |
| 36636 | 33919 | } |
| 36637 | 33920 | |
| 36638 | 33921 | /// Asserts the values are comparable. Both operands have type `ty`. |
| 33922 | /// MLUGG TODO: move to `Value`? | |
| 36639 | 33923 | fn compareScalar( |
| 36640 | 33924 | sema: *Sema, |
| 36641 | 33925 | lhs: Value, |
| ... | ... | @@ -36644,17 +33928,19 @@ fn compareScalar( |
| 36644 | 33928 | ty: Type, |
| 36645 | 33929 | ) CompileError!bool { |
| 36646 | 33930 | const pt = sema.pt; |
| 33931 | const zcu = pt.zcu; | |
| 33932 | ||
| 36647 | 33933 | const coerced_lhs = try pt.getCoerced(lhs, ty); |
| 36648 | 33934 | const coerced_rhs = try pt.getCoerced(rhs, ty); |
| 36649 | 33935 | |
| 36650 | 33936 | // Equality comparisons of signed zero and NaN need to use floating point semantics |
| 36651 | if (coerced_lhs.isFloat(pt.zcu) or coerced_rhs.isFloat(pt.zcu)) | |
| 36652 | return Value.compareHeteroSema(coerced_lhs, op, coerced_rhs, pt); | |
| 33937 | if (coerced_lhs.isFloat(zcu) or coerced_rhs.isFloat(zcu)) | |
| 33938 | return Value.compareHetero(coerced_lhs, op, coerced_rhs, zcu); | |
| 36653 | 33939 | |
| 36654 | 33940 | switch (op) { |
| 36655 | .eq => return sema.valuesEqual(coerced_lhs, coerced_rhs, ty), | |
| 36656 | .neq => return !(try sema.valuesEqual(coerced_lhs, coerced_rhs, ty)), | |
| 36657 | else => return Value.compareHeteroSema(coerced_lhs, op, coerced_rhs, pt), | |
| 33941 | .eq => return Value.eql(coerced_lhs, coerced_rhs, ty, zcu), | |
| 33942 | .neq => return !Value.eql(coerced_lhs, coerced_rhs, ty, zcu), | |
| 33943 | else => return Value.compareHetero(coerced_lhs, op, coerced_rhs, zcu), | |
| 36658 | 33944 | } |
| 36659 | 33945 | } |
| 36660 | 33946 | |
| ... | ... | @@ -36799,7 +34085,7 @@ fn validateRuntimeValue(sema: *Sema, block: *Block, val_src: LazySrcLoc, val: Ai |
| 36799 | 34085 | }); |
| 36800 | 34086 | } |
| 36801 | 34087 | |
| 36802 | fn failWithContainsReferenceToComptimeVar(sema: *Sema, block: *Block, src: LazySrcLoc, value_name: InternPool.NullTerminatedString, kind_of_value: []const u8, val: ?Value) CompileError { | |
| 34088 | pub fn failWithContainsReferenceToComptimeVar(sema: *Sema, block: *Block, src: LazySrcLoc, value_name: InternPool.NullTerminatedString, kind_of_value: []const u8, val: ?Value) CompileError { | |
| 36803 | 34089 | return sema.failWithOwnedErrorMsg(block, msg: { |
| 36804 | 34090 | const msg = try sema.errMsg(src, "{s} contains reference to comptime var", .{kind_of_value}); |
| 36805 | 34091 | errdefer msg.destroy(sema.gpa); |
| ... | ... | @@ -36867,11 +34153,7 @@ fn notePathToComptimeAllocPtr( |
| 36867 | 34153 | else => {}, // there will be another stage |
| 36868 | 34154 | } |
| 36869 | 34155 | |
| 36870 | const derivation = comptime_ptr.pointerDerivationAdvanced(arena, pt, false, sema) catch |err| switch (err) { | |
| 36871 | error.OutOfMemory => |e| return e, | |
| 36872 | error.Canceled => @panic("TODO"), // pls don't be cancelable mlugg | |
| 36873 | error.AnalysisFail => unreachable, | |
| 36874 | }; | |
| 34156 | const derivation = try comptime_ptr.pointerDerivationAdvanced(arena, pt, false, sema); | |
| 36875 | 34157 | |
| 36876 | 34158 | var second_path_aw: std.Io.Writer.Allocating = .init(arena); |
| 36877 | 34159 | defer second_path_aw.deinit(); |
| ... | ... | @@ -37058,12 +34340,12 @@ fn maybeDerefSliceAsArray( |
| 37058 | 34340 | else => unreachable, |
| 37059 | 34341 | }; |
| 37060 | 34342 | const elem_ty = Type.fromInterned(slice.ty).childType(zcu); |
| 37061 | const len = try Value.fromInterned(slice.len).toUnsignedIntSema(pt); | |
| 34343 | const len = Value.fromInterned(slice.len).toUnsignedInt(zcu); | |
| 37062 | 34344 | const array_ty = try pt.arrayType(.{ |
| 37063 | 34345 | .child = elem_ty.toIntern(), |
| 37064 | 34346 | .len = len, |
| 37065 | 34347 | }); |
| 37066 | const ptr_ty = try pt.ptrTypeSema(p: { | |
| 34348 | const ptr_ty = try pt.ptrType(p: { | |
| 37067 | 34349 | var p = Type.fromInterned(slice.ty).ptrInfo(zcu); |
| 37068 | 34350 | p.flags.size = .one; |
| 37069 | 34351 | p.child = array_ty.toIntern(); |
| ... | ... | @@ -37129,238 +34411,6 @@ pub fn flushExports(sema: *Sema) !void { |
| 37129 | 34411 | } |
| 37130 | 34412 | } |
| 37131 | 34413 | |
| 37132 | /// Called as soon as a `declared` enum type is created. | |
| 37133 | /// Resolves the tag type and field inits. | |
| 37134 | /// Marks the `src_inst` dependency on the enum's declaration, so call sites need not do this. | |
| 37135 | pub fn resolveDeclaredEnum( | |
| 37136 | pt: Zcu.PerThread, | |
| 37137 | wip_ty: InternPool.WipEnumType, | |
| 37138 | inst: Zir.Inst.Index, | |
| 37139 | tracked_inst: InternPool.TrackedInst.Index, | |
| 37140 | namespace: InternPool.NamespaceIndex, | |
| 37141 | type_name: InternPool.NullTerminatedString, | |
| 37142 | small: Zir.Inst.EnumDecl.Small, | |
| 37143 | body: []const Zir.Inst.Index, | |
| 37144 | tag_type_ref: Zir.Inst.Ref, | |
| 37145 | any_values: bool, | |
| 37146 | fields_len: u32, | |
| 37147 | zir: Zir, | |
| 37148 | body_end: usize, | |
| 37149 | ) Zcu.SemaError!void { | |
| 37150 | const zcu = pt.zcu; | |
| 37151 | const gpa = zcu.gpa; | |
| 37152 | ||
| 37153 | const src: LazySrcLoc = .{ .base_node_inst = tracked_inst, .offset = LazySrcLoc.Offset.nodeOffset(.zero) }; | |
| 37154 | ||
| 37155 | var arena: std.heap.ArenaAllocator = .init(gpa); | |
| 37156 | defer arena.deinit(); | |
| 37157 | ||
| 37158 | var comptime_err_ret_trace: std.array_list.Managed(Zcu.LazySrcLoc) = .init(gpa); | |
| 37159 | defer comptime_err_ret_trace.deinit(); | |
| 37160 | ||
| 37161 | var sema: Sema = .{ | |
| 37162 | .pt = pt, | |
| 37163 | .gpa = gpa, | |
| 37164 | .arena = arena.allocator(), | |
| 37165 | .code = zir, | |
| 37166 | .owner = .wrap(.{ .type = wip_ty.index }), | |
| 37167 | .func_index = .none, | |
| 37168 | .func_is_naked = false, | |
| 37169 | .fn_ret_ty = .void, | |
| 37170 | .fn_ret_ty_ies = null, | |
| 37171 | .comptime_err_ret_trace = &comptime_err_ret_trace, | |
| 37172 | }; | |
| 37173 | defer sema.deinit(); | |
| 37174 | ||
| 37175 | if (zcu.comp.debugIncremental()) { | |
| 37176 | const info = try zcu.incremental_debug_state.getUnitInfo(gpa, sema.owner); | |
| 37177 | info.last_update_gen = zcu.generation; | |
| 37178 | } | |
| 37179 | ||
| 37180 | try sema.declareDependency(.{ .src_hash = tracked_inst }); | |
| 37181 | ||
| 37182 | var block: Block = .{ | |
| 37183 | .parent = null, | |
| 37184 | .sema = &sema, | |
| 37185 | .namespace = namespace, | |
| 37186 | .instructions = .{}, | |
| 37187 | .inlining = null, | |
| 37188 | .comptime_reason = .{ .reason = .{ | |
| 37189 | .src = src, | |
| 37190 | .r = .{ .simple = .enum_field_values }, | |
| 37191 | } }, | |
| 37192 | .src_base_inst = tracked_inst, | |
| 37193 | .type_name_ctx = type_name, | |
| 37194 | }; | |
| 37195 | defer block.instructions.deinit(gpa); | |
| 37196 | ||
| 37197 | sema.resolveDeclaredEnumInner( | |
| 37198 | &block, | |
| 37199 | wip_ty, | |
| 37200 | inst, | |
| 37201 | tracked_inst, | |
| 37202 | src, | |
| 37203 | small, | |
| 37204 | body, | |
| 37205 | tag_type_ref, | |
| 37206 | any_values, | |
| 37207 | fields_len, | |
| 37208 | zir, | |
| 37209 | body_end, | |
| 37210 | ) catch |err| switch (err) { | |
| 37211 | error.ComptimeBreak => unreachable, | |
| 37212 | error.ComptimeReturn => unreachable, | |
| 37213 | error.OutOfMemory, error.Canceled => |e| return e, | |
| 37214 | error.AnalysisFail => { | |
| 37215 | if (!zcu.failed_analysis.contains(sema.owner)) { | |
| 37216 | try zcu.transitive_failed_analysis.put(gpa, sema.owner, {}); | |
| 37217 | } | |
| 37218 | return error.AnalysisFail; | |
| 37219 | }, | |
| 37220 | }; | |
| 37221 | } | |
| 37222 | ||
| 37223 | fn resolveDeclaredEnumInner( | |
| 37224 | sema: *Sema, | |
| 37225 | block: *Block, | |
| 37226 | wip_ty: InternPool.WipEnumType, | |
| 37227 | inst: Zir.Inst.Index, | |
| 37228 | tracked_inst: InternPool.TrackedInst.Index, | |
| 37229 | src: LazySrcLoc, | |
| 37230 | small: Zir.Inst.EnumDecl.Small, | |
| 37231 | body: []const Zir.Inst.Index, | |
| 37232 | tag_type_ref: Zir.Inst.Ref, | |
| 37233 | any_values: bool, | |
| 37234 | fields_len: u32, | |
| 37235 | zir: Zir, | |
| 37236 | body_end: usize, | |
| 37237 | ) Zcu.CompileError!void { | |
| 37238 | const pt = sema.pt; | |
| 37239 | const zcu = pt.zcu; | |
| 37240 | const comp = zcu.comp; | |
| 37241 | const gpa = comp.gpa; | |
| 37242 | const io = comp.io; | |
| 37243 | const ip = &zcu.intern_pool; | |
| 37244 | ||
| 37245 | const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable; | |
| 37246 | ||
| 37247 | const tag_ty_src: LazySrcLoc = .{ .base_node_inst = tracked_inst, .offset = .{ .node_offset_container_tag = .zero } }; | |
| 37248 | ||
| 37249 | const int_tag_ty = ty: { | |
| 37250 | if (body.len != 0) { | |
| 37251 | _ = try sema.analyzeInlineBody(block, body, inst); | |
| 37252 | } | |
| 37253 | ||
| 37254 | if (tag_type_ref != .none) { | |
| 37255 | const ty = try sema.resolveType(block, tag_ty_src, tag_type_ref); | |
| 37256 | if (ty.zigTypeTag(zcu) != .int and ty.zigTypeTag(zcu) != .comptime_int) { | |
| 37257 | return sema.fail(block, tag_ty_src, "expected integer tag type, found '{f}'", .{ty.fmt(pt)}); | |
| 37258 | } | |
| 37259 | break :ty ty; | |
| 37260 | } else if (fields_len == 0) { | |
| 37261 | break :ty try pt.intType(.unsigned, 0); | |
| 37262 | } else { | |
| 37263 | const bits = std.math.log2_int_ceil(usize, fields_len); | |
| 37264 | break :ty try pt.intType(.unsigned, bits); | |
| 37265 | } | |
| 37266 | }; | |
| 37267 | ||
| 37268 | wip_ty.setTagTy(ip, int_tag_ty.toIntern()); | |
| 37269 | ||
| 37270 | var extra_index = body_end + bit_bags_count; | |
| 37271 | var bit_bag_index: usize = body_end; | |
| 37272 | var cur_bit_bag: u32 = undefined; | |
| 37273 | var last_tag_val: ?Value = null; | |
| 37274 | for (0..fields_len) |field_i_usize| { | |
| 37275 | const field_i: u32 = @intCast(field_i_usize); | |
| 37276 | if (field_i % 32 == 0) { | |
| 37277 | cur_bit_bag = zir.extra[bit_bag_index]; | |
| 37278 | bit_bag_index += 1; | |
| 37279 | } | |
| 37280 | const has_tag_value = @as(u1, @truncate(cur_bit_bag)) != 0; | |
| 37281 | cur_bit_bag >>= 1; | |
| 37282 | ||
| 37283 | const field_name_index: Zir.NullTerminatedString = @enumFromInt(zir.extra[extra_index]); | |
| 37284 | const field_name_zir = zir.nullTerminatedString(field_name_index); | |
| 37285 | extra_index += 1; // field name | |
| 37286 | ||
| 37287 | const field_name = try ip.getOrPutString(gpa, io, pt.tid, field_name_zir, .no_embedded_nulls); | |
| 37288 | ||
| 37289 | const value_src: LazySrcLoc = .{ | |
| 37290 | .base_node_inst = tracked_inst, | |
| 37291 | .offset = .{ .container_field_value = field_i }, | |
| 37292 | }; | |
| 37293 | ||
| 37294 | const tag_overflow = if (has_tag_value) overflow: { | |
| 37295 | const tag_val_ref: Zir.Inst.Ref = @enumFromInt(zir.extra[extra_index]); | |
| 37296 | extra_index += 1; | |
| 37297 | const tag_inst = try sema.resolveInst(tag_val_ref); | |
| 37298 | last_tag_val = try sema.resolveConstDefinedValue(block, .{ | |
| 37299 | .base_node_inst = tracked_inst, | |
| 37300 | .offset = .{ .container_field_name = field_i }, | |
| 37301 | }, tag_inst, .{ .simple = .enum_field_tag_value }); | |
| 37302 | if (!(try sema.intFitsInType(last_tag_val.?, int_tag_ty, null))) break :overflow true; | |
| 37303 | last_tag_val = try pt.getCoerced(last_tag_val.?, int_tag_ty); | |
| 37304 | if (wip_ty.nextField(ip, field_name, last_tag_val.?.toIntern())) |conflict| { | |
| 37305 | assert(conflict.kind == .value); // AstGen validated names are unique | |
| 37306 | const other_field_src: LazySrcLoc = .{ | |
| 37307 | .base_node_inst = tracked_inst, | |
| 37308 | .offset = .{ .container_field_value = conflict.prev_field_idx }, | |
| 37309 | }; | |
| 37310 | const msg = msg: { | |
| 37311 | const msg = try sema.errMsg(value_src, "enum tag value {f} already taken", .{last_tag_val.?.fmtValueSema(pt, sema)}); | |
| 37312 | errdefer msg.destroy(gpa); | |
| 37313 | try sema.errNote(other_field_src, msg, "other occurrence here", .{}); | |
| 37314 | break :msg msg; | |
| 37315 | }; | |
| 37316 | return sema.failWithOwnedErrorMsg(block, msg); | |
| 37317 | } | |
| 37318 | break :overflow false; | |
| 37319 | } else if (any_values) overflow: { | |
| 37320 | if (last_tag_val) |last_tag| { | |
| 37321 | const result = try arith.incrementDefinedInt(sema, int_tag_ty, last_tag); | |
| 37322 | last_tag_val = result.val; | |
| 37323 | if (result.overflow) break :overflow true; | |
| 37324 | } else { | |
| 37325 | last_tag_val = try pt.intValue(int_tag_ty, 0); | |
| 37326 | } | |
| 37327 | if (wip_ty.nextField(ip, field_name, last_tag_val.?.toIntern())) |conflict| { | |
| 37328 | assert(conflict.kind == .value); // AstGen validated names are unique | |
| 37329 | const other_field_src: LazySrcLoc = .{ | |
| 37330 | .base_node_inst = tracked_inst, | |
| 37331 | .offset = .{ .container_field_value = conflict.prev_field_idx }, | |
| 37332 | }; | |
| 37333 | const msg = msg: { | |
| 37334 | const msg = try sema.errMsg(value_src, "enum tag value {f} already taken", .{last_tag_val.?.fmtValueSema(pt, sema)}); | |
| 37335 | errdefer msg.destroy(gpa); | |
| 37336 | try sema.errNote(other_field_src, msg, "other occurrence here", .{}); | |
| 37337 | break :msg msg; | |
| 37338 | }; | |
| 37339 | return sema.failWithOwnedErrorMsg(block, msg); | |
| 37340 | } | |
| 37341 | break :overflow false; | |
| 37342 | } else overflow: { | |
| 37343 | assert(wip_ty.nextField(ip, field_name, .none) == null); | |
| 37344 | last_tag_val = try pt.intValue(.comptime_int, field_i); | |
| 37345 | if (!try sema.intFitsInType(last_tag_val.?, int_tag_ty, null)) break :overflow true; | |
| 37346 | last_tag_val = try pt.getCoerced(last_tag_val.?, int_tag_ty); | |
| 37347 | break :overflow false; | |
| 37348 | }; | |
| 37349 | ||
| 37350 | if (tag_overflow) { | |
| 37351 | const msg = try sema.errMsg(value_src, "enumeration value '{f}' too large for type '{f}'", .{ | |
| 37352 | last_tag_val.?.fmtValueSema(pt, sema), int_tag_ty.fmt(pt), | |
| 37353 | }); | |
| 37354 | return sema.failWithOwnedErrorMsg(block, msg); | |
| 37355 | } | |
| 37356 | } | |
| 37357 | if (small.nonexhaustive and int_tag_ty.toIntern() != .comptime_int_type) { | |
| 37358 | if (fields_len >= 1 and std.math.log2_int(u64, fields_len) == int_tag_ty.bitSize(zcu)) { | |
| 37359 | return sema.fail(block, src, "non-exhaustive enum specifies every value", .{}); | |
| 37360 | } | |
| 37361 | } | |
| 37362 | } | |
| 37363 | ||
| 37364 | 34414 | pub const bitCastVal = @import("Sema/bitcast.zig").bitCast; |
| 37365 | 34415 | pub const bitCastSpliceVal = @import("Sema/bitcast.zig").bitCastSplice; |
| 37366 | 34416 | |
| ... | ... | @@ -37369,6 +34419,11 @@ const ComptimeLoadResult = @import("Sema/comptime_ptr_access.zig").ComptimeLoadR |
| 37369 | 34419 | const storeComptimePtr = @import("Sema/comptime_ptr_access.zig").storeComptimePtr; |
| 37370 | 34420 | const ComptimeStoreResult = @import("Sema/comptime_ptr_access.zig").ComptimeStoreResult; |
| 37371 | 34421 | |
| 34422 | // MLUGG TODO: decide how to do the namespacing here | |
| 34423 | pub const type_resolution = @import("Sema/type_resolution.zig"); | |
| 34424 | pub const ensureLayoutResolved = type_resolution.ensureLayoutResolved; | |
| 34425 | pub const ensureFieldInitsResolved = type_resolution.ensureFieldInitsResolved; | |
| 34426 | ||
| 37372 | 34427 | pub fn getBuiltinType(sema: *Sema, src: LazySrcLoc, decl: Zcu.BuiltinDecl) SemaError!Type { |
| 37373 | 34428 | assert(decl.kind() == .type); |
| 37374 | 34429 | try sema.ensureMemoizedStateResolved(src, decl.stage()); |
| ... | ... | @@ -37483,11 +34538,11 @@ pub fn analyzeMemoizedState(sema: *Sema, block: *Block, simple_src: LazySrcLoc, |
| 37483 | 34538 | const result = try sema.analyzeNavVal(block, src, nav); |
| 37484 | 34539 | |
| 37485 | 34540 | const uncoerced_val = try sema.resolveConstDefinedValue(block, src, result, null); |
| 37486 | const maybe_lazy_val: Value = switch (builtin_decl.kind()) { | |
| 34541 | const val: Value = switch (builtin_decl.kind()) { | |
| 37487 | 34542 | .type => if (uncoerced_val.typeOf(zcu).zigTypeTag(zcu) != .type) { |
| 37488 | 34543 | return sema.fail(block, src, "{s}.{s} is not a type", .{ parent_name, name }); |
| 37489 | 34544 | } else val: { |
| 37490 | try uncoerced_val.toType().resolveFully(pt); | |
| 34545 | try sema.ensureLayoutResolved(uncoerced_val.toType()); | |
| 37491 | 34546 | break :val uncoerced_val; |
| 37492 | 34547 | }, |
| 37493 | 34548 | .func => val: { |
| ... | ... | @@ -37500,7 +34555,6 @@ pub fn analyzeMemoizedState(sema: *Sema, block: *Block, simple_src: LazySrcLoc, |
| 37500 | 34555 | break :val .fromInterned(coerced.toInterned().?); |
| 37501 | 34556 | }, |
| 37502 | 34557 | }; |
| 37503 | const val = try sema.resolveLazyValue(maybe_lazy_val); | |
| 37504 | 34558 | |
| 37505 | 34559 | const prev = zcu.builtin_decl_values.get(builtin_decl); |
| 37506 | 34560 | if (val.toIntern() != prev) { |
| ... | ... | @@ -37539,7 +34593,6 @@ fn getExpectedBuiltinFnType(sema: *Sema, decl: Zcu.BuiltinDecl) CompileError!Typ |
| 37539 | 34593 | => try pt.funcType(.{ |
| 37540 | 34594 | .param_types = &.{ .generic_poison_type, .generic_poison_type }, |
| 37541 | 34595 | .return_type = .noreturn_type, |
| 37542 | .is_generic = true, | |
| 37543 | 34596 | }), |
| 37544 | 34597 | |
| 37545 | 34598 | // `fn (anyerror) noreturn` |
| ... | ... | @@ -37590,3 +34643,823 @@ fn getExpectedBuiltinFnType(sema: *Sema, decl: Zcu.BuiltinDecl) CompileError!Typ |
| 37590 | 34643 | else => unreachable, |
| 37591 | 34644 | }; |
| 37592 | 34645 | } |
| 34646 | ||
| 34647 | /// TODO MLUGG: this is a gnarly hack | |
| 34648 | const PartialTypeName = union(enum) { | |
| 34649 | exact: struct { | |
| 34650 | name: InternPool.NullTerminatedString, | |
| 34651 | nav: InternPool.Nav.Index.Optional, | |
| 34652 | }, | |
| 34653 | anon_prefix: []const u8, | |
| 34654 | fn apply( | |
| 34655 | name: PartialTypeName, | |
| 34656 | wip: *const InternPool.WipContainerType, | |
| 34657 | pt: Zcu.PerThread, | |
| 34658 | ) (Allocator.Error || std.Io.Cancelable)!InternPool.NullTerminatedString { | |
| 34659 | const zcu = pt.zcu; | |
| 34660 | const comp = zcu.comp; | |
| 34661 | const ip = &zcu.intern_pool; | |
| 34662 | switch (name) { | |
| 34663 | .exact => |e| { | |
| 34664 | wip.setName(ip, e.name, e.nav); | |
| 34665 | return e.name; | |
| 34666 | }, | |
| 34667 | .anon_prefix => |prefix| { | |
| 34668 | const resolved_name = try ip.getOrPutStringFmt( | |
| 34669 | comp.gpa, | |
| 34670 | comp.io, | |
| 34671 | pt.tid, | |
| 34672 | "{s}_{d}", | |
| 34673 | .{ prefix, @intFromEnum(wip.index) }, | |
| 34674 | .no_embedded_nulls, | |
| 34675 | ); | |
| 34676 | wip.setName(ip, resolved_name, .none); | |
| 34677 | return resolved_name; | |
| 34678 | }, | |
| 34679 | } | |
| 34680 | } | |
| 34681 | }; | |
| 34682 | pub fn createTypeName( | |
| 34683 | sema: *Sema, | |
| 34684 | block: *Block, | |
| 34685 | name_strategy: Zir.Inst.NameStrategy, | |
| 34686 | anon_prefix: []const u8, | |
| 34687 | inst: Zir.Inst.Index, | |
| 34688 | ) CompileError!PartialTypeName { | |
| 34689 | const pt = sema.pt; | |
| 34690 | const zcu = pt.zcu; | |
| 34691 | const comp = zcu.comp; | |
| 34692 | const gpa = comp.gpa; | |
| 34693 | const io = comp.io; | |
| 34694 | const ip = &zcu.intern_pool; | |
| 34695 | ||
| 34696 | switch (name_strategy) { | |
| 34697 | .anon => {}, // handled after switch | |
| 34698 | .parent => return .{ .exact = .{ | |
| 34699 | .name = block.type_name_ctx, | |
| 34700 | .nav = sema.owner.unwrap().nav_val.toOptional(), | |
| 34701 | } }, | |
| 34702 | .func => func_strat: { | |
| 34703 | const fn_info = sema.code.getFnInfo(ip.funcZirBodyInst(sema.func_index).resolve(ip) orelse return error.AnalysisFail); | |
| 34704 | const zir_tags = sema.code.instructions.items(.tag); | |
| 34705 | ||
| 34706 | var aw: std.Io.Writer.Allocating = .init(gpa); | |
| 34707 | defer aw.deinit(); | |
| 34708 | const w = &aw.writer; | |
| 34709 | w.print("{f}(", .{block.type_name_ctx.fmt(ip)}) catch return error.OutOfMemory; | |
| 34710 | ||
| 34711 | var arg_i: usize = 0; | |
| 34712 | for (fn_info.param_body) |zir_inst| switch (zir_tags[@intFromEnum(zir_inst)]) { | |
| 34713 | .param, .param_comptime, .param_anytype, .param_anytype_comptime => { | |
| 34714 | const arg = sema.inst_map.get(zir_inst).?; | |
| 34715 | // If this is being called in a generic function then analyzeCall will | |
| 34716 | // have already resolved the args and this will work. | |
| 34717 | // If not then this is a struct type being returned from a non-generic | |
| 34718 | // function and the name doesn't matter since it will later | |
| 34719 | // result in a compile error. | |
| 34720 | const arg_val = try sema.resolveValue(arg) orelse break :func_strat; // fall through to anon strat | |
| 34721 | ||
| 34722 | if (arg_i != 0) w.writeByte(',') catch return error.OutOfMemory; | |
| 34723 | ||
| 34724 | // Limiting the depth here helps avoid type names getting too long, which | |
| 34725 | // in turn helps to avoid unreasonably long symbol names for namespaced | |
| 34726 | // symbols. Such names should ideally be human-readable, and additionally, | |
| 34727 | // some tooling may not support very long symbol names. | |
| 34728 | w.print("{f}", .{Value.fmtValueSemaFull(.{ | |
| 34729 | .val = arg_val, | |
| 34730 | .pt = pt, | |
| 34731 | .opt_sema = sema, | |
| 34732 | .depth = 1, | |
| 34733 | })}) catch return error.OutOfMemory; | |
| 34734 | ||
| 34735 | arg_i += 1; | |
| 34736 | continue; | |
| 34737 | }, | |
| 34738 | else => continue, | |
| 34739 | }; | |
| 34740 | ||
| 34741 | w.writeByte(')') catch return error.OutOfMemory; | |
| 34742 | return .{ .exact = .{ | |
| 34743 | .name = try ip.getOrPutString(gpa, io, pt.tid, aw.written(), .no_embedded_nulls), | |
| 34744 | .nav = .none, | |
| 34745 | } }; | |
| 34746 | }, | |
| 34747 | .dbg_var => { | |
| 34748 | // TODO: this logic is questionable. We ideally should be traversing the `Block` rather than relying on the order of AstGen instructions. | |
| 34749 | const ref = inst.toRef(); | |
| 34750 | const zir_tags = sema.code.instructions.items(.tag); | |
| 34751 | const zir_data = sema.code.instructions.items(.data); | |
| 34752 | for (@intFromEnum(inst)..zir_tags.len) |i| switch (zir_tags[i]) { | |
| 34753 | .dbg_var_ptr, .dbg_var_val => if (zir_data[i].str_op.operand == ref) { | |
| 34754 | return .{ .exact = .{ | |
| 34755 | .name = try ip.getOrPutStringFmt(gpa, io, pt.tid, "{f}.{s}", .{ | |
| 34756 | block.type_name_ctx.fmt(ip), zir_data[i].str_op.getStr(sema.code), | |
| 34757 | }, .no_embedded_nulls), | |
| 34758 | .nav = .none, | |
| 34759 | } }; | |
| 34760 | }, | |
| 34761 | else => {}, | |
| 34762 | }; | |
| 34763 | // fall through to anon strat | |
| 34764 | }, | |
| 34765 | } | |
| 34766 | ||
| 34767 | // anon strat handling | |
| 34768 | ||
| 34769 | // It would be neat to have "struct:line:column" but this name has | |
| 34770 | // to survive incremental updates, where it may have been shifted down | |
| 34771 | // or up to a different line, but unchanged, and thus not unnecessarily | |
| 34772 | // semantically analyzed. | |
| 34773 | // TODO: that would be possible, by detecting line number changes and renaming | |
| 34774 | // types appropriately. However, `@typeName` becomes a problem then. If we remove | |
| 34775 | // that builtin from the language, we can consider this. | |
| 34776 | ||
| 34777 | return .{ .anon_prefix = try std.fmt.allocPrint( | |
| 34778 | sema.arena, | |
| 34779 | "{f}__{s}", | |
| 34780 | .{ block.type_name_ctx.fmt(ip), anon_prefix }, | |
| 34781 | ) }; | |
| 34782 | } | |
| 34783 | ||
| 34784 | pub fn analyzeStructDecl( | |
| 34785 | pt: Zcu.PerThread, | |
| 34786 | file_index: Zcu.File.Index, | |
| 34787 | zir: *const Zir, | |
| 34788 | parent_namespace: InternPool.OptionalNamespaceIndex, | |
| 34789 | tracked_inst: InternPool.TrackedInst.Index, | |
| 34790 | struct_decl: *const Zir.UnwrappedStructDecl, | |
| 34791 | explicit_backing_type: ?Type, | |
| 34792 | captures: []const InternPool.CaptureValue, | |
| 34793 | type_name: PartialTypeName, | |
| 34794 | ) (Allocator.Error || std.Io.Cancelable)!Type { | |
| 34795 | const zcu = pt.zcu; | |
| 34796 | const comp = zcu.comp; | |
| 34797 | const gpa = comp.gpa; | |
| 34798 | const io = comp.io; | |
| 34799 | const ip = &zcu.intern_pool; | |
| 34800 | ||
| 34801 | const wip = switch (try ip.getStructType(gpa, io, pt.tid, .{ | |
| 34802 | .fields_len = @intCast(struct_decl.field_names.len), | |
| 34803 | .layout = struct_decl.layout, | |
| 34804 | .explicit_packed_backing_type = if (explicit_backing_type) |ty| ty.toIntern() else .none, | |
| 34805 | .any_comptime_fields = struct_decl.field_comptime_bits != null, | |
| 34806 | .any_field_defaults = struct_decl.field_default_body_lens != null, | |
| 34807 | .any_field_aligns = struct_decl.field_align_body_lens != null, | |
| 34808 | .key = .{ .declared = .{ | |
| 34809 | .zir_index = tracked_inst, | |
| 34810 | .captures = captures, | |
| 34811 | } }, | |
| 34812 | })) { | |
| 34813 | .existing => |ty| return .fromInterned(ty), | |
| 34814 | .wip => |wip| wip, | |
| 34815 | }; | |
| 34816 | errdefer wip.cancel(ip, pt.tid); | |
| 34817 | ||
| 34818 | _ = try type_name.apply(&wip, pt); | |
| 34819 | ||
| 34820 | var field_it = struct_decl.iterateFields(); | |
| 34821 | while (field_it.next()) |field| { | |
| 34822 | const name_slice = zir.nullTerminatedString(field.name); | |
| 34823 | const name = try ip.getOrPutString(gpa, io, pt.tid, name_slice, .no_embedded_nulls); | |
| 34824 | assert(wip.nextField(ip, name, field.is_comptime) == null); // AstGen validated this for us | |
| 34825 | } | |
| 34826 | ||
| 34827 | const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{ | |
| 34828 | .parent = parent_namespace, | |
| 34829 | .owner_type = wip.index, | |
| 34830 | .file_scope = file_index, | |
| 34831 | .generation = zcu.generation, | |
| 34832 | }); | |
| 34833 | errdefer pt.destroyNamespace(new_namespace_index); | |
| 34834 | ||
| 34835 | try pt.scanNamespace(new_namespace_index, struct_decl.decls); | |
| 34836 | ||
| 34837 | // MLUGG TODO: we could potentially revert this language change if we wanted? don't mind | |
| 34838 | try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .type_layout = wip.index }) }); | |
| 34839 | try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .type_inits = wip.index }) }); | |
| 34840 | ||
| 34841 | if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index); | |
| 34842 | ||
| 34843 | try zcu.outdated.ensureUnusedCapacity(gpa, 2); | |
| 34844 | try zcu.outdated_ready.ensureUnusedCapacity(gpa, 2); | |
| 34845 | errdefer comptime unreachable; // because we don't remove the `outdated` entries | |
| 34846 | zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), 0); | |
| 34847 | zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_inits = wip.index }), 0); | |
| 34848 | zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), {}); | |
| 34849 | zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_inits = wip.index }), {}); | |
| 34850 | ||
| 34851 | return .fromInterned(wip.finish(ip, new_namespace_index)); | |
| 34852 | } | |
| 34853 | const AnalyzeUnionDeclError = error{ | |
| 34854 | OutOfMemory, | |
| 34855 | Canceled, | |
| 34856 | /// `packed union(T)` syntax was used, but `T` was not an integer type. | |
| 34857 | ExplicitBackingNotInt, | |
| 34858 | /// `union(enum(T))` syntax was used, but `T` was not an integer type. | |
| 34859 | ExplicitTagNotInt, | |
| 34860 | /// `union(T)` syntax was used, but `T` was not an enum type. | |
| 34861 | ExplicitTagNotEnum, | |
| 34862 | /// `union(T)` syntax was used, but the fields of the union do not exactly | |
| 34863 | /// correspond to the fields of the enum `T`. | |
| 34864 | ExplicitTagFieldMismatch, | |
| 34865 | }; | |
| 34866 | fn analyzeUnionDecl( | |
| 34867 | pt: Zcu.PerThread, | |
| 34868 | file_index: Zcu.File.Index, | |
| 34869 | zir: *const Zir, | |
| 34870 | parent_namespace: InternPool.OptionalNamespaceIndex, | |
| 34871 | want_safe_types: bool, | |
| 34872 | tracked_inst: InternPool.TrackedInst.Index, | |
| 34873 | union_decl: *const Zir.UnwrappedUnionDecl, | |
| 34874 | arg_type: ?Type, | |
| 34875 | captures: []const InternPool.CaptureValue, | |
| 34876 | type_name: PartialTypeName, | |
| 34877 | ) AnalyzeUnionDeclError!Type { | |
| 34878 | const zcu = pt.zcu; | |
| 34879 | const comp = zcu.comp; | |
| 34880 | const gpa = comp.gpa; | |
| 34881 | const io = comp.io; | |
| 34882 | const ip = &zcu.intern_pool; | |
| 34883 | ||
| 34884 | switch (union_decl.kind) { | |
| 34885 | .tagged_explicit => if (arg_type.?.zigTypeTag(zcu) != .@"enum") { | |
| 34886 | return error.ExplicitTagNotEnum; | |
| 34887 | }, | |
| 34888 | .tagged_enum_explicit => if (arg_type.?.zigTypeTag(zcu) != .int) { | |
| 34889 | return error.ExplicitTagNotInt; | |
| 34890 | }, | |
| 34891 | .packed_explicit => if (arg_type.?.zigTypeTag(zcu) != .int) { | |
| 34892 | return error.ExplicitBackingNotInt; | |
| 34893 | }, | |
| 34894 | .auto, | |
| 34895 | .tagged_enum, | |
| 34896 | .@"extern", | |
| 34897 | .@"packed", | |
| 34898 | => assert(arg_type == null), | |
| 34899 | } | |
| 34900 | ||
| 34901 | const wip = switch (try ip.getUnionType(gpa, io, pt.tid, .{ | |
| 34902 | .fields_len = @intCast(union_decl.field_names.len), | |
| 34903 | .layout = union_decl.kind.layout(), | |
| 34904 | .explicit_packed_backing_type = switch (union_decl.kind) { | |
| 34905 | .packed_explicit => arg_type.?.toIntern(), | |
| 34906 | else => .none, | |
| 34907 | }, | |
| 34908 | .runtime_tag = switch (union_decl.kind) { | |
| 34909 | .auto => if (want_safe_types) .safety else .none, | |
| 34910 | ||
| 34911 | .tagged_explicit, | |
| 34912 | .tagged_enum, | |
| 34913 | .tagged_enum_explicit, | |
| 34914 | => .tagged, | |
| 34915 | ||
| 34916 | .@"extern", | |
| 34917 | .@"packed", | |
| 34918 | .packed_explicit, | |
| 34919 | => .none, | |
| 34920 | }, | |
| 34921 | .have_explicit_enum_tag = union_decl.kind == .tagged_explicit, | |
| 34922 | .any_field_aligns = union_decl.field_align_body_lens != null, | |
| 34923 | .key = .{ .declared = .{ | |
| 34924 | .zir_index = tracked_inst, | |
| 34925 | .captures = captures, | |
| 34926 | .arg_ty = if (arg_type) |t| t.toIntern() else .none, | |
| 34927 | } }, | |
| 34928 | })) { | |
| 34929 | .existing => |ty| return .fromInterned(ty), | |
| 34930 | .wip => |wip| wip, | |
| 34931 | }; | |
| 34932 | errdefer wip.cancel(ip, pt.tid); | |
| 34933 | ||
| 34934 | const resolved_type_name = try type_name.apply(&wip, pt); | |
| 34935 | ||
| 34936 | const generated_tag_ty: InternPool.Index = if (union_decl.kind == .tagged_explicit) generated_tag_ty: { | |
| 34937 | const tag_type = arg_type.?; | |
| 34938 | const enum_field_names = ip.loadEnumType(tag_type.toIntern()).field_names; | |
| 34939 | // Check that the enum field names match the union field names | |
| 34940 | if (union_decl.field_names.len != enum_field_names.len) { | |
| 34941 | return error.ExplicitTagFieldMismatch; | |
| 34942 | } | |
| 34943 | for (union_decl.field_names, enum_field_names.get(ip)) |union_field_zir, enum_field_ip| { | |
| 34944 | const union_field_name = zir.nullTerminatedString(union_field_zir); | |
| 34945 | const enum_field_name = enum_field_ip.toSlice(ip); | |
| 34946 | if (!std.mem.eql(u8, union_field_name, enum_field_name)) { | |
| 34947 | return error.ExplicitTagFieldMismatch; | |
| 34948 | } | |
| 34949 | } | |
| 34950 | wip.setTagType(ip, tag_type.toIntern()); | |
| 34951 | break :generated_tag_ty .none; | |
| 34952 | } else generated_tag_ty: { | |
| 34953 | // Generate a tag type. Even if the union is untagged (`.none`), we still generate a | |
| 34954 | // hypothetical tag type. | |
| 34955 | const wip_tag_ty = switch (try ip.getEnumType(gpa, io, pt.tid, .{ | |
| 34956 | .fields_len = @intCast(union_decl.field_names.len), | |
| 34957 | .explicit_int_tag_type = switch (union_decl.kind) { | |
| 34958 | .tagged_enum_explicit => arg_type.?.toIntern(), | |
| 34959 | else => .none, | |
| 34960 | }, | |
| 34961 | .nonexhaustive = false, | |
| 34962 | .key = .{ .generated_union_tag = wip.index }, | |
| 34963 | })) { | |
| 34964 | .existing => unreachable, // enum type is keyed on this union type which we're only just creating | |
| 34965 | .wip => |wip_tag_ty| wip_tag_ty, | |
| 34966 | }; | |
| 34967 | errdefer wip_tag_ty.cancel(ip, pt.tid); | |
| 34968 | // Populate the generated tag type's name | |
| 34969 | const tag_type_name = try ip.getOrPutStringFmt( | |
| 34970 | gpa, | |
| 34971 | io, | |
| 34972 | pt.tid, | |
| 34973 | "@typeInfo({f}).@\"union\".tag_type.?", | |
| 34974 | .{resolved_type_name.fmt(ip)}, | |
| 34975 | .no_embedded_nulls, | |
| 34976 | ); | |
| 34977 | wip_tag_ty.setName(ip, tag_type_name, .none); | |
| 34978 | // Populate the generated tag type's field names | |
| 34979 | for (union_decl.field_names) |zir_name| { | |
| 34980 | const name_slice = zir.nullTerminatedString(zir_name); | |
| 34981 | const name = try ip.getOrPutString(gpa, io, pt.tid, name_slice, .no_embedded_nulls); | |
| 34982 | assert(wip_tag_ty.nextField(ip, name, false) == null); // AstGen validated this for us | |
| 34983 | } | |
| 34984 | // If not explicitly given, populate the generated tag type's *integer* tag type | |
| 34985 | switch (union_decl.kind) { | |
| 34986 | .tagged_enum_explicit => {}, // already set by `getEnumType` | |
| 34987 | else => { | |
| 34988 | // Infer the int tag type from the field count | |
| 34989 | const bits = Type.smallestUnsignedBits(union_decl.field_names.len -| 1); | |
| 34990 | const int_tag_type = try pt.intType(.unsigned, bits); | |
| 34991 | wip_tag_ty.setTagType(ip, int_tag_type.toIntern()); | |
| 34992 | }, | |
| 34993 | } | |
| 34994 | // Create a dummy namespace for the generated tag type | |
| 34995 | const new_namespace_index = try pt.createNamespace(.{ | |
| 34996 | .parent = parent_namespace, | |
| 34997 | .owner_type = wip_tag_ty.index, | |
| 34998 | .file_scope = file_index, | |
| 34999 | .generation = zcu.generation, | |
| 35000 | }); | |
| 35001 | errdefer pt.destroyNamespace(new_namespace_index); | |
| 35002 | wip.setTagType(ip, wip_tag_ty.index); | |
| 35003 | break :generated_tag_ty wip_tag_ty.finish(ip, new_namespace_index); | |
| 35004 | }; | |
| 35005 | // If we fail to create the union type, we must delete the generated enum tag type, since it | |
| 35006 | // would hold a reference to the deleted union. | |
| 35007 | errdefer if (generated_tag_ty != .none) ip.remove(pt.tid, generated_tag_ty); | |
| 35008 | ||
| 35009 | const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{ | |
| 35010 | .parent = parent_namespace, | |
| 35011 | .owner_type = wip.index, | |
| 35012 | .file_scope = file_index, | |
| 35013 | .generation = zcu.generation, | |
| 35014 | }); | |
| 35015 | errdefer pt.destroyNamespace(new_namespace_index); | |
| 35016 | ||
| 35017 | try pt.scanNamespace(new_namespace_index, union_decl.decls); | |
| 35018 | ||
| 35019 | // MLUGG TODO: we could potentially revert this language change if we wanted? don't mind | |
| 35020 | try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .type_layout = wip.index }) }); | |
| 35021 | if (generated_tag_ty != .none) { | |
| 35022 | try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .type_inits = generated_tag_ty }) }); | |
| 35023 | } | |
| 35024 | ||
| 35025 | if (zcu.comp.debugIncremental()) { | |
| 35026 | try zcu.incremental_debug_state.newType(zcu, wip.index); | |
| 35027 | if (generated_tag_ty != .none) { | |
| 35028 | try zcu.incremental_debug_state.newType(zcu, generated_tag_ty); | |
| 35029 | } | |
| 35030 | } | |
| 35031 | ||
| 35032 | try zcu.outdated.ensureUnusedCapacity(gpa, 2); | |
| 35033 | try zcu.outdated_ready.ensureUnusedCapacity(gpa, 2); | |
| 35034 | errdefer comptime unreachable; // because we don't remove the `outdated` entry | |
| 35035 | zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), 0); | |
| 35036 | zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), {}); | |
| 35037 | if (generated_tag_ty != .none) { | |
| 35038 | zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_inits = generated_tag_ty }), 0); | |
| 35039 | zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_inits = generated_tag_ty }), {}); | |
| 35040 | } | |
| 35041 | ||
| 35042 | return .fromInterned(wip.finish(ip, new_namespace_index)); | |
| 35043 | } | |
| 35044 | const AnalyzeEnumDeclError = error{ | |
| 35045 | OutOfMemory, | |
| 35046 | Canceled, | |
| 35047 | /// `enum(T)` syntax was used, but `T` was not an integer type. | |
| 35048 | ExplicitTagNotInt, | |
| 35049 | }; | |
| 35050 | fn analyzeEnumDecl( | |
| 35051 | pt: Zcu.PerThread, | |
| 35052 | file_index: Zcu.File.Index, | |
| 35053 | zir: *const Zir, | |
| 35054 | parent_namespace: InternPool.OptionalNamespaceIndex, | |
| 35055 | tracked_inst: InternPool.TrackedInst.Index, | |
| 35056 | enum_decl: *const Zir.UnwrappedEnumDecl, | |
| 35057 | explicit_tag_type: ?Type, | |
| 35058 | captures: []const InternPool.CaptureValue, | |
| 35059 | type_name: PartialTypeName, | |
| 35060 | ) AnalyzeEnumDeclError!Type { | |
| 35061 | const zcu = pt.zcu; | |
| 35062 | const comp = zcu.comp; | |
| 35063 | const gpa = comp.gpa; | |
| 35064 | const io = comp.io; | |
| 35065 | const ip = &zcu.intern_pool; | |
| 35066 | ||
| 35067 | if (explicit_tag_type) |ty| { | |
| 35068 | // MLUGG TODO: make a final call on whether comptime_int is a valid int tag type, and follow it everywhere. | |
| 35069 | // i think not in the name of simplicity, but my opinion might depend on whether it's broken in practice today | |
| 35070 | switch (ty.zigTypeTag(zcu)) { | |
| 35071 | .int, .comptime_int => {}, | |
| 35072 | else => return error.ExplicitTagNotInt, | |
| 35073 | } | |
| 35074 | } | |
| 35075 | ||
| 35076 | const wip = switch (try ip.getEnumType(gpa, io, pt.tid, .{ | |
| 35077 | .fields_len = @intCast(enum_decl.field_names.len), | |
| 35078 | .explicit_int_tag_type = if (explicit_tag_type) |ty| ty.toIntern() else .none, | |
| 35079 | .nonexhaustive = enum_decl.nonexhaustive, | |
| 35080 | .key = .{ .declared = .{ | |
| 35081 | .zir_index = tracked_inst, | |
| 35082 | .captures = captures, | |
| 35083 | } }, | |
| 35084 | })) { | |
| 35085 | .existing => |ty| return .fromInterned(ty), | |
| 35086 | .wip => |wip| wip, | |
| 35087 | }; | |
| 35088 | errdefer wip.cancel(ip, pt.tid); | |
| 35089 | ||
| 35090 | _ = try type_name.apply(&wip, pt); | |
| 35091 | ||
| 35092 | var field_it = enum_decl.iterateFields(); | |
| 35093 | while (field_it.next()) |field| { | |
| 35094 | const name_slice = zir.nullTerminatedString(field.name); | |
| 35095 | const name = try ip.getOrPutString(gpa, io, pt.tid, name_slice, .no_embedded_nulls); | |
| 35096 | assert(wip.nextField(ip, name, false) == null); // AstGen validated this for us | |
| 35097 | } | |
| 35098 | ||
| 35099 | if (explicit_tag_type == null) { | |
| 35100 | // Infer the int tag type from the field count | |
| 35101 | const bits = Type.smallestUnsignedBits(enum_decl.field_names.len -| 1); | |
| 35102 | const int_tag_ty = try pt.intType(.unsigned, bits); | |
| 35103 | wip.setTagType(ip, int_tag_ty.toIntern()); | |
| 35104 | } | |
| 35105 | ||
| 35106 | const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{ | |
| 35107 | .parent = parent_namespace, | |
| 35108 | .owner_type = wip.index, | |
| 35109 | .file_scope = file_index, | |
| 35110 | .generation = zcu.generation, | |
| 35111 | }); | |
| 35112 | errdefer pt.destroyNamespace(new_namespace_index); | |
| 35113 | ||
| 35114 | try pt.scanNamespace(new_namespace_index, enum_decl.decls); | |
| 35115 | ||
| 35116 | // MLUGG TODO: we could potentially revert this language change if we wanted? don't mind | |
| 35117 | try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .type_inits = wip.index }) }); | |
| 35118 | ||
| 35119 | if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index); | |
| 35120 | ||
| 35121 | try zcu.outdated.ensureUnusedCapacity(gpa, 1); | |
| 35122 | try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1); | |
| 35123 | errdefer comptime unreachable; // because we don't remove the `outdated` entry | |
| 35124 | zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_inits = wip.index }), 0); | |
| 35125 | zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_inits = wip.index }), {}); | |
| 35126 | ||
| 35127 | return .fromInterned(wip.finish(ip, new_namespace_index)); | |
| 35128 | } | |
| 35129 | fn analyzeOpaqueDecl( | |
| 35130 | pt: Zcu.PerThread, | |
| 35131 | file_index: Zcu.File.Index, | |
| 35132 | parent_namespace: InternPool.OptionalNamespaceIndex, | |
| 35133 | tracked_inst: InternPool.TrackedInst.Index, | |
| 35134 | opaque_decl: *const Zir.UnwrappedOpaqueDecl, | |
| 35135 | captures: []const InternPool.CaptureValue, | |
| 35136 | type_name: PartialTypeName, | |
| 35137 | ) (Allocator.Error || std.Io.Cancelable)!Type { | |
| 35138 | const zcu = pt.zcu; | |
| 35139 | const comp = zcu.comp; | |
| 35140 | const gpa = comp.gpa; | |
| 35141 | const io = comp.io; | |
| 35142 | const ip = &zcu.intern_pool; | |
| 35143 | ||
| 35144 | const wip = switch (try ip.getOpaqueType(gpa, io, pt.tid, .{ | |
| 35145 | .zir_index = tracked_inst, | |
| 35146 | .captures = captures, | |
| 35147 | })) { | |
| 35148 | .existing => |ty| return .fromInterned(ty), | |
| 35149 | .wip => |wip| wip, | |
| 35150 | }; | |
| 35151 | errdefer wip.cancel(ip, pt.tid); | |
| 35152 | ||
| 35153 | _ = try type_name.apply(&wip, pt); | |
| 35154 | ||
| 35155 | const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{ | |
| 35156 | .parent = parent_namespace, | |
| 35157 | .owner_type = wip.index, | |
| 35158 | .file_scope = file_index, | |
| 35159 | .generation = zcu.generation, | |
| 35160 | }); | |
| 35161 | errdefer pt.destroyNamespace(new_namespace_index); | |
| 35162 | ||
| 35163 | try pt.scanNamespace(new_namespace_index, opaque_decl.decls); | |
| 35164 | ||
| 35165 | if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index); | |
| 35166 | return .fromInterned(wip.finish(ip, new_namespace_index)); | |
| 35167 | } | |
| 35168 | ||
| 35169 | fn zirStructDecl( | |
| 35170 | sema: *Sema, | |
| 35171 | block: *Block, | |
| 35172 | inst: Zir.Inst.Index, | |
| 35173 | ) CompileError!Air.Inst.Ref { | |
| 35174 | const pt = sema.pt; | |
| 35175 | const zcu = pt.zcu; | |
| 35176 | ||
| 35177 | const tracked_inst = try block.trackZir(inst); | |
| 35178 | ||
| 35179 | const src: LazySrcLoc = .{ | |
| 35180 | .base_node_inst = tracked_inst, | |
| 35181 | .offset = .nodeOffset(.zero), | |
| 35182 | }; | |
| 35183 | const backing_ty_src: LazySrcLoc = .{ | |
| 35184 | .base_node_inst = tracked_inst, | |
| 35185 | .offset = .{ .node_offset_container_tag = .zero }, | |
| 35186 | }; | |
| 35187 | ||
| 35188 | const struct_decl = sema.code.getStructDecl(inst); | |
| 35189 | ||
| 35190 | const captures = try sema.getCaptures(block, src, struct_decl.captures, struct_decl.capture_names); | |
| 35191 | ||
| 35192 | const backing_int_type: ?Type = ty: { | |
| 35193 | if (struct_decl.backing_int_type == .none) break :ty null; | |
| 35194 | break :ty try sema.resolveType(block, backing_ty_src, struct_decl.backing_int_type); | |
| 35195 | // MLUGG TODO validate it's an int! | |
| 35196 | }; | |
| 35197 | ||
| 35198 | const ty = try analyzeStructDecl( | |
| 35199 | pt, | |
| 35200 | block.getFileScopeIndex(zcu), | |
| 35201 | &sema.code, | |
| 35202 | block.namespace.toOptional(), | |
| 35203 | tracked_inst, | |
| 35204 | &struct_decl, | |
| 35205 | backing_int_type, | |
| 35206 | captures, | |
| 35207 | try sema.createTypeName(block, struct_decl.name_strategy, "struct", inst), | |
| 35208 | ); | |
| 35209 | ||
| 35210 | try sema.addTypeReferenceEntry(src, ty); | |
| 35211 | ||
| 35212 | // Make sure we update the namespace if the declaration is re-analyzed, to pick | |
| 35213 | // up on e.g. changed comptime decls. | |
| 35214 | // TODO MLUGG: me no likey, maybe model namespaces less badly idk | |
| 35215 | try pt.ensureNamespaceUpToDate(ty.getNamespaceIndex(zcu)); | |
| 35216 | ||
| 35217 | return .fromIntern(ty.toIntern()); | |
| 35218 | } | |
| 35219 | fn zirUnionDecl( | |
| 35220 | sema: *Sema, | |
| 35221 | block: *Block, | |
| 35222 | inst: Zir.Inst.Index, | |
| 35223 | ) CompileError!Air.Inst.Ref { | |
| 35224 | const pt = sema.pt; | |
| 35225 | const zcu = pt.zcu; | |
| 35226 | const comp = zcu.comp; | |
| 35227 | const gpa = comp.gpa; | |
| 35228 | const io = comp.io; | |
| 35229 | const ip = &zcu.intern_pool; | |
| 35230 | ||
| 35231 | const tracked_inst = try block.trackZir(inst); | |
| 35232 | ||
| 35233 | const src: LazySrcLoc = .{ | |
| 35234 | .base_node_inst = tracked_inst, | |
| 35235 | .offset = .nodeOffset(.zero), | |
| 35236 | }; | |
| 35237 | const arg_ty_src: LazySrcLoc = .{ | |
| 35238 | .base_node_inst = tracked_inst, | |
| 35239 | .offset = .{ .node_offset_container_tag = .zero }, | |
| 35240 | }; | |
| 35241 | ||
| 35242 | const union_decl = sema.code.getUnionDecl(inst); | |
| 35243 | ||
| 35244 | const captures = try sema.getCaptures(block, src, union_decl.captures, union_decl.capture_names); | |
| 35245 | ||
| 35246 | const arg_type: ?Type = ty: { | |
| 35247 | if (union_decl.arg_type == .none) break :ty null; | |
| 35248 | break :ty try sema.resolveType(block, arg_ty_src, union_decl.arg_type); | |
| 35249 | }; | |
| 35250 | ||
| 35251 | const ty = analyzeUnionDecl( | |
| 35252 | pt, | |
| 35253 | block.getFileScopeIndex(zcu), | |
| 35254 | &sema.code, | |
| 35255 | block.namespace.toOptional(), | |
| 35256 | block.wantSafeTypes(), | |
| 35257 | tracked_inst, | |
| 35258 | &union_decl, | |
| 35259 | arg_type, | |
| 35260 | captures, | |
| 35261 | try sema.createTypeName(block, union_decl.name_strategy, "union", inst), | |
| 35262 | ) catch |err| switch (err) { | |
| 35263 | error.OutOfMemory, | |
| 35264 | error.Canceled, | |
| 35265 | => |e| return e, | |
| 35266 | ||
| 35267 | error.ExplicitBackingNotInt => return sema.fail( | |
| 35268 | block, | |
| 35269 | arg_ty_src, | |
| 35270 | "expected integer backing type, found '{f}'", | |
| 35271 | .{arg_type.?.fmt(pt)}, | |
| 35272 | ), | |
| 35273 | error.ExplicitTagNotInt => return sema.fail( | |
| 35274 | block, | |
| 35275 | arg_ty_src, | |
| 35276 | "expected integer tag type, found '{f}'", | |
| 35277 | .{arg_type.?.fmt(pt)}, | |
| 35278 | ), | |
| 35279 | error.ExplicitTagNotEnum => return sema.fail( | |
| 35280 | block, | |
| 35281 | arg_ty_src, | |
| 35282 | "expected enum tag type, found '{f}'", | |
| 35283 | .{arg_type.?.fmt(pt)}, | |
| 35284 | ), | |
| 35285 | error.ExplicitTagFieldMismatch => { | |
| 35286 | const enum_obj = ip.loadEnumType(arg_type.?.toIntern()); | |
| 35287 | const enum_to_union_map = try sema.arena.alloc(?u32, enum_obj.field_names.len); | |
| 35288 | @memset(enum_to_union_map, null); | |
| 35289 | for (union_decl.field_names, 0..) |field_name_zir, union_field_idx| { | |
| 35290 | const field_name_ip = try ip.getOrPutString(gpa, io, pt.tid, sema.code.nullTerminatedString(field_name_zir), .no_embedded_nulls); | |
| 35291 | if (enum_obj.nameIndex(ip, field_name_ip)) |enum_field_idx| { | |
| 35292 | enum_to_union_map[enum_field_idx] = @intCast(union_field_idx); | |
| 35293 | continue; | |
| 35294 | } | |
| 35295 | const union_field_src: LazySrcLoc = .{ | |
| 35296 | .base_node_inst = tracked_inst, | |
| 35297 | .offset = .{ .container_field_name = @intCast(union_field_idx) }, | |
| 35298 | }; | |
| 35299 | return sema.failWithOwnedErrorMsg(block, msg: { | |
| 35300 | const msg = try sema.errMsg(union_field_src, "no field named '{f}' in enum '{f}'", .{ field_name_ip.fmt(ip), arg_type.?.fmt(pt) }); | |
| 35301 | errdefer msg.destroy(gpa); | |
| 35302 | try sema.addDeclaredHereNote(msg, arg_type.?); | |
| 35303 | break :msg msg; | |
| 35304 | }); | |
| 35305 | } | |
| 35306 | for (enum_to_union_map, 0..) |union_field_idx, enum_field_idx| { | |
| 35307 | if (union_field_idx != null) continue; | |
| 35308 | const field_name_ip = enum_obj.field_names.get(ip)[enum_field_idx]; | |
| 35309 | const enum_field_src: LazySrcLoc = .{ | |
| 35310 | .base_node_inst = arg_type.?.typeDeclInstAllowGeneratedTag(zcu).?, | |
| 35311 | .offset = .{ .container_field_name = @intCast(enum_field_idx) }, | |
| 35312 | }; | |
| 35313 | return sema.failWithOwnedErrorMsg(block, msg: { | |
| 35314 | const msg = try sema.errMsg(src, "enum field '{f}' missing from union", .{field_name_ip.fmt(ip)}); | |
| 35315 | errdefer msg.destroy(gpa); | |
| 35316 | try sema.errNote(enum_field_src, msg, "enum field here", .{}); | |
| 35317 | break :msg msg; | |
| 35318 | }); | |
| 35319 | } | |
| 35320 | for (enum_to_union_map, 0..) |union_field_idx, enum_field_idx| { | |
| 35321 | if (union_field_idx.? == enum_field_idx) continue; | |
| 35322 | const field_name = sema.code.nullTerminatedString( | |
| 35323 | union_decl.field_names[union_field_idx.?], | |
| 35324 | ); | |
| 35325 | const union_field_src: LazySrcLoc = .{ | |
| 35326 | .base_node_inst = tracked_inst, | |
| 35327 | .offset = .{ .container_field_name = union_field_idx.? }, | |
| 35328 | }; | |
| 35329 | const enum_field_src: LazySrcLoc = .{ | |
| 35330 | .base_node_inst = arg_type.?.typeDeclInstAllowGeneratedTag(zcu).?, | |
| 35331 | .offset = .{ .container_field_name = @intCast(enum_field_idx) }, | |
| 35332 | }; | |
| 35333 | return sema.failWithOwnedErrorMsg(block, msg: { | |
| 35334 | const msg = try sema.errMsg(src, "union field order does not match tag enum field order", .{}); | |
| 35335 | errdefer msg.destroy(gpa); | |
| 35336 | try sema.errNote(union_field_src, msg, "union field '{s}' is index {d}", .{ field_name, union_field_idx.? }); | |
| 35337 | try sema.errNote(enum_field_src, msg, "enum field '{s}' is index {d}", .{ field_name, enum_field_idx }); | |
| 35338 | break :msg msg; | |
| 35339 | }); | |
| 35340 | } | |
| 35341 | unreachable; | |
| 35342 | }, | |
| 35343 | }; | |
| 35344 | ||
| 35345 | const enum_tag_ty = ty.unionTagTypeHypothetical(zcu); | |
| 35346 | switch (ip.indexToKey(enum_tag_ty.toIntern()).enum_type) { | |
| 35347 | .declared, .reified => {}, | |
| 35348 | .generated_union_tag => |owner_union_ty| { | |
| 35349 | assert(owner_union_ty == ty.toIntern()); | |
| 35350 | // generated tag type [MLUGG] | |
| 35351 | // Enum inits are resolved eagerly. TODO MLUGG: honestly i don't think they SHOULD be lol | |
| 35352 | try sema.ensureFieldInitsResolved(.fromInterned(ip.loadUnionType(ty.toIntern()).enum_tag_type)); | |
| 35353 | }, | |
| 35354 | } | |
| 35355 | ||
| 35356 | try sema.addTypeReferenceEntry(src, ty); | |
| 35357 | ||
| 35358 | // Make sure we update the namespace if the declaration is re-analyzed, to pick | |
| 35359 | // up on e.g. changed comptime decls. | |
| 35360 | // TODO MLUGG: me no likey, maybe model namespaces less badly idk | |
| 35361 | try pt.ensureNamespaceUpToDate(ty.getNamespaceIndex(zcu)); | |
| 35362 | ||
| 35363 | return .fromIntern(ty.toIntern()); | |
| 35364 | } | |
| 35365 | fn zirEnumDecl( | |
| 35366 | sema: *Sema, | |
| 35367 | block: *Block, | |
| 35368 | inst: Zir.Inst.Index, | |
| 35369 | ) CompileError!Air.Inst.Ref { | |
| 35370 | const pt = sema.pt; | |
| 35371 | const zcu = pt.zcu; | |
| 35372 | ||
| 35373 | const tracked_inst = try block.trackZir(inst); | |
| 35374 | ||
| 35375 | const src: LazySrcLoc = .{ | |
| 35376 | .base_node_inst = tracked_inst, | |
| 35377 | .offset = .nodeOffset(.zero), | |
| 35378 | }; | |
| 35379 | const tag_ty_src: LazySrcLoc = .{ | |
| 35380 | .base_node_inst = tracked_inst, | |
| 35381 | .offset = .{ .node_offset_container_tag = .zero }, | |
| 35382 | }; | |
| 35383 | ||
| 35384 | const enum_decl = sema.code.getEnumDecl(inst); | |
| 35385 | ||
| 35386 | const captures = try sema.getCaptures(block, src, enum_decl.captures, enum_decl.capture_names); | |
| 35387 | ||
| 35388 | const tag_type: ?Type = ty: { | |
| 35389 | if (enum_decl.tag_type == .none) break :ty null; | |
| 35390 | break :ty try sema.resolveType(block, tag_ty_src, enum_decl.tag_type); | |
| 35391 | }; | |
| 35392 | ||
| 35393 | const ty = analyzeEnumDecl( | |
| 35394 | pt, | |
| 35395 | block.getFileScopeIndex(zcu), | |
| 35396 | &sema.code, | |
| 35397 | block.namespace.toOptional(), | |
| 35398 | tracked_inst, | |
| 35399 | &enum_decl, | |
| 35400 | tag_type, | |
| 35401 | captures, | |
| 35402 | try sema.createTypeName(block, enum_decl.name_strategy, "enum", inst), | |
| 35403 | ) catch |err| switch (err) { | |
| 35404 | error.OutOfMemory, | |
| 35405 | error.Canceled, | |
| 35406 | => |e| return e, | |
| 35407 | ||
| 35408 | error.ExplicitTagNotInt => return sema.fail( | |
| 35409 | block, | |
| 35410 | tag_ty_src, | |
| 35411 | "expected integer tag type, found '{f}'", | |
| 35412 | .{tag_type.?.fmt(pt)}, | |
| 35413 | ), | |
| 35414 | }; | |
| 35415 | ||
| 35416 | // Enum inits are resolved eagerly. TODO MLUGG: honestly i don't think they SHOULD be lol | |
| 35417 | try sema.ensureFieldInitsResolved(ty); | |
| 35418 | ||
| 35419 | try sema.addTypeReferenceEntry(src, ty); | |
| 35420 | ||
| 35421 | // Make sure we update the namespace if the declaration is re-analyzed, to pick | |
| 35422 | // up on e.g. changed comptime decls. | |
| 35423 | // TODO MLUGG: me no likey, maybe model namespaces less badly idk | |
| 35424 | try pt.ensureNamespaceUpToDate(ty.getNamespaceIndex(zcu)); | |
| 35425 | ||
| 35426 | return .fromIntern(ty.toIntern()); | |
| 35427 | } | |
| 35428 | fn zirOpaqueDecl( | |
| 35429 | sema: *Sema, | |
| 35430 | block: *Block, | |
| 35431 | inst: Zir.Inst.Index, | |
| 35432 | ) CompileError!Air.Inst.Ref { | |
| 35433 | const pt = sema.pt; | |
| 35434 | const zcu = pt.zcu; | |
| 35435 | ||
| 35436 | const tracked_inst = try block.trackZir(inst); | |
| 35437 | ||
| 35438 | const src: LazySrcLoc = .{ | |
| 35439 | .base_node_inst = tracked_inst, | |
| 35440 | .offset = .nodeOffset(.zero), | |
| 35441 | }; | |
| 35442 | ||
| 35443 | const opaque_decl = sema.code.getOpaqueDecl(inst); | |
| 35444 | ||
| 35445 | const captures = try sema.getCaptures(block, src, opaque_decl.captures, opaque_decl.capture_names); | |
| 35446 | ||
| 35447 | const ty = try analyzeOpaqueDecl( | |
| 35448 | pt, | |
| 35449 | block.getFileScopeIndex(zcu), | |
| 35450 | block.namespace.toOptional(), | |
| 35451 | tracked_inst, | |
| 35452 | &opaque_decl, | |
| 35453 | captures, | |
| 35454 | try sema.createTypeName(block, opaque_decl.name_strategy, "opaque", inst), | |
| 35455 | ); | |
| 35456 | ||
| 35457 | try sema.addTypeReferenceEntry(src, ty); | |
| 35458 | ||
| 35459 | // Make sure we update the namespace if the declaration is re-analyzed, to pick | |
| 35460 | // up on e.g. changed comptime decls. | |
| 35461 | // TODO MLUGG: me no likey, maybe model namespaces less badly idk | |
| 35462 | try pt.ensureNamespaceUpToDate(ty.getNamespaceIndex(zcu)); | |
| 35463 | ||
| 35464 | return .fromIntern(ty.toIntern()); | |
| 35465 | } |
src/Sema/LowerZon.zig+11-10| ... | ... | @@ -125,6 +125,7 @@ fn lowerExprAnonResTy(self: *LowerZon, node: Zoir.Node.Index) CompileError!Inter |
| 125 | 125 | return (try pt.aggregateValue(.fromInterned(ty), values)).toIntern(); |
| 126 | 126 | }, |
| 127 | 127 | .struct_literal => |init| { |
| 128 | if (true) @panic("MLUGG TODO"); | |
| 128 | 129 | const elems = try self.sema.arena.alloc(InternPool.Index, init.names.len); |
| 129 | 130 | for (0..init.names.len) |i| { |
| 130 | 131 | elems[i] = try self.lowerExprAnonResTy(init.vals.at(@intCast(i))); |
| ... | ... | @@ -299,7 +300,7 @@ fn checkTypeInner( |
| 299 | 300 | } else { |
| 300 | 301 | const gop = try visited.getOrPut(sema.arena, ty.toIntern()); |
| 301 | 302 | if (gop.found_existing) return; |
| 302 | try ty.resolveFields(pt); | |
| 303 | try sema.ensureLayoutResolved(ty); | |
| 303 | 304 | const struct_info = zcu.typeToStruct(ty).?; |
| 304 | 305 | for (struct_info.field_types.get(ip)) |field_type| { |
| 305 | 306 | try self.checkTypeInner(.fromInterned(field_type), null, visited); |
| ... | ... | @@ -308,7 +309,7 @@ fn checkTypeInner( |
| 308 | 309 | .@"union" => { |
| 309 | 310 | const gop = try visited.getOrPut(sema.arena, ty.toIntern()); |
| 310 | 311 | if (gop.found_existing) return; |
| 311 | try ty.resolveFields(pt); | |
| 312 | try sema.ensureLayoutResolved(ty); | |
| 312 | 313 | const union_info = zcu.typeToUnion(ty).?; |
| 313 | 314 | for (union_info.field_types.get(ip)) |field_type| { |
| 314 | 315 | if (field_type != .void_type) { |
| ... | ... | @@ -767,8 +768,8 @@ fn lowerStruct(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool |
| 767 | 768 | const io = comp.io; |
| 768 | 769 | const ip = &pt.zcu.intern_pool; |
| 769 | 770 | |
| 770 | try res_ty.resolveFields(self.sema.pt); | |
| 771 | try res_ty.resolveStructFieldInits(self.sema.pt); | |
| 771 | try self.sema.ensureLayoutResolved(res_ty); | |
| 772 | try self.sema.ensureFieldInitsResolved(res_ty); | |
| 772 | 773 | const struct_info = self.sema.pt.zcu.typeToStruct(res_ty).?; |
| 773 | 774 | |
| 774 | 775 | const fields: @FieldType(Zoir.Node, "struct_literal") = switch (node.get(self.file.zoir.?)) { |
| ... | ... | @@ -779,7 +780,7 @@ fn lowerStruct(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool |
| 779 | 780 | |
| 780 | 781 | const field_values = try self.sema.arena.alloc(InternPool.Index, struct_info.field_names.len); |
| 781 | 782 | |
| 782 | const field_defaults = struct_info.field_inits.get(ip); | |
| 783 | const field_defaults = struct_info.field_defaults.get(ip); | |
| 783 | 784 | if (field_defaults.len > 0) { |
| 784 | 785 | @memcpy(field_values, field_defaults); |
| 785 | 786 | } else { |
| ... | ... | @@ -803,7 +804,7 @@ fn lowerStruct(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool |
| 803 | 804 | const field_type: Type = .fromInterned(struct_info.field_types.get(ip)[name_index]); |
| 804 | 805 | field_values[name_index] = try self.lowerExprKnownResTy(field_node, field_type); |
| 805 | 806 | |
| 806 | if (struct_info.comptime_bits.getBit(ip, name_index)) { | |
| 807 | if (struct_info.field_is_comptime_bits.get(ip, name_index)) { | |
| 807 | 808 | const val = ip.indexToKey(field_values[name_index]); |
| 808 | 809 | const default = ip.indexToKey(field_defaults[name_index]); |
| 809 | 810 | if (!val.eql(default, ip)) { |
| ... | ... | @@ -918,9 +919,9 @@ fn lowerUnion(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool. |
| 918 | 919 | const gpa = comp.gpa; |
| 919 | 920 | const io = comp.io; |
| 920 | 921 | const ip = &pt.zcu.intern_pool; |
| 921 | try res_ty.resolveFields(self.sema.pt); | |
| 922 | const union_info = self.sema.pt.zcu.typeToUnion(res_ty).?; | |
| 923 | const enum_tag_info = union_info.loadTagType(ip); | |
| 922 | try self.sema.ensureLayoutResolved(res_ty); | |
| 923 | const union_info = pt.zcu.typeToUnion(res_ty).?; | |
| 924 | const enum_tag_info = ip.loadEnumType(union_info.enum_tag_type); | |
| 924 | 925 | |
| 925 | 926 | const field_name, const maybe_field_node = switch (node.get(self.file.zoir.?)) { |
| 926 | 927 | .enum_literal => |name| b: { |
| ... | ... | @@ -956,7 +957,7 @@ fn lowerUnion(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool. |
| 956 | 957 | const name_index = enum_tag_info.nameIndex(ip, field_name) orelse { |
| 957 | 958 | return error.WrongType; |
| 958 | 959 | }; |
| 959 | const tag = try self.sema.pt.enumValueFieldIndex(.fromInterned(union_info.enum_tag_ty), name_index); | |
| 960 | const tag = try self.sema.pt.enumValueFieldIndex(.fromInterned(union_info.enum_tag_type), name_index); | |
| 960 | 961 | const field_type: Type = .fromInterned(union_info.field_types.get(ip)[name_index]); |
| 961 | 962 | const val = if (maybe_field_node) |field_node| b: { |
| 962 | 963 | if (field_type.toIntern() == .void_type) { |
src/Sema/arith.zig+20-19| ... | ... | @@ -1053,7 +1053,7 @@ fn shlScalar( |
| 1053 | 1053 | if (rhs_val.isUndef(zcu)) return rhs_val; |
| 1054 | 1054 | }, |
| 1055 | 1055 | } |
| 1056 | switch (try rhs_val.orderAgainstZeroSema(pt)) { | |
| 1056 | switch (Value.order(rhs_val, .zero_comptime_int, zcu)) { | |
| 1057 | 1057 | .gt => {}, |
| 1058 | 1058 | .eq => return lhs_val, |
| 1059 | 1059 | .lt => return sema.failWithNegativeShiftAmount(block, rhs_src, rhs_val, vec_idx), |
| ... | ... | @@ -1090,7 +1090,7 @@ fn shlWithOverflowScalar( |
| 1090 | 1090 | if (lhs_val.isUndef(zcu)) return sema.failWithUseOfUndef(block, lhs_src, vec_idx); |
| 1091 | 1091 | if (rhs_val.isUndef(zcu)) return sema.failWithUseOfUndef(block, rhs_src, vec_idx); |
| 1092 | 1092 | |
| 1093 | switch (try rhs_val.orderAgainstZeroSema(pt)) { | |
| 1093 | switch (Value.order(rhs_val, .zero_comptime_int, zcu)) { | |
| 1094 | 1094 | .gt => {}, |
| 1095 | 1095 | .eq => return .{ .overflow_bit = .zero_u1, .wrapped_result = lhs_val }, |
| 1096 | 1096 | .lt => return sema.failWithNegativeShiftAmount(block, rhs_src, rhs_val, vec_idx), |
| ... | ... | @@ -1169,7 +1169,7 @@ fn shrScalar( |
| 1169 | 1169 | if (lhs_val.isUndef(zcu)) return sema.failWithUseOfUndef(block, lhs_src, vec_idx); |
| 1170 | 1170 | if (rhs_val.isUndef(zcu)) return sema.failWithUseOfUndef(block, rhs_src, vec_idx); |
| 1171 | 1171 | |
| 1172 | switch (try rhs_val.orderAgainstZeroSema(pt)) { | |
| 1172 | switch (Value.order(rhs_val, .zero_comptime_int, zcu)) { | |
| 1173 | 1173 | .gt => {}, |
| 1174 | 1174 | .eq => return lhs_val, |
| 1175 | 1175 | .lt => return sema.failWithNegativeShiftAmount(block, rhs_src, rhs_val, vec_idx), |
| ... | ... | @@ -1430,8 +1430,8 @@ fn intAddWithOverflowInner(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value |
| 1430 | 1430 | const info = ty.intInfo(zcu); |
| 1431 | 1431 | var lhs_space: Value.BigIntSpace = undefined; |
| 1432 | 1432 | var rhs_space: Value.BigIntSpace = undefined; |
| 1433 | const lhs_bigint = try lhs.toBigIntSema(&lhs_space, pt); | |
| 1434 | const rhs_bigint = try rhs.toBigIntSema(&rhs_space, pt); | |
| 1433 | const lhs_bigint = lhs.toBigInt(&lhs_space, zcu); | |
| 1434 | const rhs_bigint = rhs.toBigInt(&rhs_space, zcu); | |
| 1435 | 1435 | const limbs = try sema.arena.alloc( |
| 1436 | 1436 | std.math.big.Limb, |
| 1437 | 1437 | std.math.big.int.calcTwosCompLimbCount(info.bits), |
| ... | ... | @@ -1512,8 +1512,8 @@ fn intSubWithOverflowInner(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value |
| 1512 | 1512 | const info = ty.intInfo(zcu); |
| 1513 | 1513 | var lhs_space: Value.BigIntSpace = undefined; |
| 1514 | 1514 | var rhs_space: Value.BigIntSpace = undefined; |
| 1515 | const lhs_bigint = try lhs.toBigIntSema(&lhs_space, pt); | |
| 1516 | const rhs_bigint = try rhs.toBigIntSema(&rhs_space, pt); | |
| 1515 | const lhs_bigint = lhs.toBigInt(&lhs_space, zcu); | |
| 1516 | const rhs_bigint = rhs.toBigInt(&rhs_space, zcu); | |
| 1517 | 1517 | const limbs = try sema.arena.alloc( |
| 1518 | 1518 | std.math.big.Limb, |
| 1519 | 1519 | std.math.big.int.calcTwosCompLimbCount(info.bits), |
| ... | ... | @@ -1597,8 +1597,8 @@ fn intMulWithOverflowInner(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value |
| 1597 | 1597 | const info = ty.intInfo(zcu); |
| 1598 | 1598 | var lhs_space: Value.BigIntSpace = undefined; |
| 1599 | 1599 | var rhs_space: Value.BigIntSpace = undefined; |
| 1600 | const lhs_bigint = try lhs.toBigIntSema(&lhs_space, pt); | |
| 1601 | const rhs_bigint = try rhs.toBigIntSema(&rhs_space, pt); | |
| 1600 | const lhs_bigint = lhs.toBigInt(&lhs_space, zcu); | |
| 1601 | const rhs_bigint = rhs.toBigInt(&rhs_space, zcu); | |
| 1602 | 1602 | const limbs = try sema.arena.alloc( |
| 1603 | 1603 | std.math.big.Limb, |
| 1604 | 1604 | lhs_bigint.limbs.len + rhs_bigint.limbs.len, |
| ... | ... | @@ -1840,7 +1840,7 @@ fn intShl( |
| 1840 | 1840 | var lhs_space: Value.BigIntSpace = undefined; |
| 1841 | 1841 | const lhs_bigint = lhs.toBigInt(&lhs_space, zcu); |
| 1842 | 1842 | |
| 1843 | const shift_amt: usize = @intCast(try rhs.toUnsignedIntSema(pt)); | |
| 1843 | const shift_amt: usize = @intCast(rhs.toUnsignedInt(zcu)); | |
| 1844 | 1844 | if (shift_amt >= info.bits) { |
| 1845 | 1845 | return sema.failWithTooLargeShiftAmount(block, lhs_ty, rhs, rhs_src, vec_idx); |
| 1846 | 1846 | } |
| ... | ... | @@ -1862,7 +1862,7 @@ fn intShlSat( |
| 1862 | 1862 | const lhs_bigint = lhs.toBigInt(&lhs_space, zcu); |
| 1863 | 1863 | |
| 1864 | 1864 | const shift_amt: usize = amt: { |
| 1865 | if (try rhs.getUnsignedIntSema(pt)) |shift_amt_u64| { | |
| 1865 | if (rhs.getUnsignedInt(zcu)) |shift_amt_u64| { | |
| 1866 | 1866 | if (std.math.cast(usize, shift_amt_u64)) |shift_amt| break :amt shift_amt; |
| 1867 | 1867 | } |
| 1868 | 1868 | // We only support ints with up to 2^16 - 1 bits, so this |
| ... | ... | @@ -1895,9 +1895,9 @@ fn intShlWithOverflow( |
| 1895 | 1895 | const info = lhs_ty.intInfo(zcu); |
| 1896 | 1896 | |
| 1897 | 1897 | var lhs_space: Value.BigIntSpace = undefined; |
| 1898 | const lhs_bigint = try lhs.toBigIntSema(&lhs_space, pt); | |
| 1898 | const lhs_bigint = lhs.toBigInt(&lhs_space, zcu); | |
| 1899 | 1899 | |
| 1900 | const shift_amt: usize = @intCast(try rhs.toUnsignedIntSema(pt)); | |
| 1900 | const shift_amt: usize = @intCast(rhs.toUnsignedInt(zcu)); | |
| 1901 | 1901 | if (shift_amt >= info.bits) { |
| 1902 | 1902 | return sema.failWithTooLargeShiftAmount(block, lhs_ty, rhs, rhs_src, vec_idx); |
| 1903 | 1903 | } |
| ... | ... | @@ -1924,9 +1924,10 @@ fn comptimeIntShl( |
| 1924 | 1924 | vec_idx: ?usize, |
| 1925 | 1925 | ) !Value { |
| 1926 | 1926 | const pt = sema.pt; |
| 1927 | const zcu = pt.zcu; | |
| 1927 | 1928 | var lhs_space: Value.BigIntSpace = undefined; |
| 1928 | const lhs_bigint = try lhs.toBigIntSema(&lhs_space, pt); | |
| 1929 | if (try rhs.getUnsignedIntSema(pt)) |shift_amt_u64| { | |
| 1929 | const lhs_bigint = lhs.toBigInt(&lhs_space, zcu); | |
| 1930 | if (rhs.getUnsignedInt(zcu)) |shift_amt_u64| { | |
| 1930 | 1931 | if (std.math.cast(usize, shift_amt_u64)) |shift_amt| { |
| 1931 | 1932 | const result_bigint = try intShlInner(sema, lhs_bigint, shift_amt); |
| 1932 | 1933 | return pt.intValue_big(.comptime_int, result_bigint.toConst()); |
| ... | ... | @@ -1963,15 +1964,15 @@ fn intShr( |
| 1963 | 1964 | const lhs_bigint = lhs.toBigInt(&lhs_space, zcu); |
| 1964 | 1965 | |
| 1965 | 1966 | const shift_amt: usize = if (rhs_ty.toIntern() == .comptime_int_type) amt: { |
| 1966 | if (try rhs.getUnsignedIntSema(pt)) |shift_amt_u64| { | |
| 1967 | if (rhs.getUnsignedInt(zcu)) |shift_amt_u64| { | |
| 1967 | 1968 | if (std.math.cast(usize, shift_amt_u64)) |shift_amt| break :amt shift_amt; |
| 1968 | 1969 | } |
| 1969 | if (try rhs.compareAllWithZeroSema(.lt, pt)) { | |
| 1970 | if (rhs.compareAllWithZero(.lt, zcu)) { | |
| 1970 | 1971 | return sema.failWithNegativeShiftAmount(block, rhs_src, rhs, vec_idx); |
| 1971 | 1972 | } else { |
| 1972 | 1973 | return sema.failWithUnsupportedComptimeShiftAmount(block, rhs_src, vec_idx); |
| 1973 | 1974 | } |
| 1974 | } else @intCast(try rhs.toUnsignedIntSema(pt)); | |
| 1975 | } else @intCast(rhs.toUnsignedInt(zcu)); | |
| 1975 | 1976 | |
| 1976 | 1977 | if (lhs_ty.toIntern() != .comptime_int_type and shift_amt >= lhs_ty.intInfo(zcu).bits) { |
| 1977 | 1978 | return sema.failWithTooLargeShiftAmount(block, lhs_ty, rhs, rhs_src, vec_idx); |
| ... | ... | @@ -2006,7 +2007,7 @@ fn intBitReverse(sema: *Sema, val: Value, ty: Type) !Value { |
| 2006 | 2007 | const info = ty.intInfo(zcu); |
| 2007 | 2008 | |
| 2008 | 2009 | var val_space: Value.BigIntSpace = undefined; |
| 2009 | const val_bigint = try val.toBigIntSema(&val_space, pt); | |
| 2010 | const val_bigint = val.toBigInt(&val_space, zcu); | |
| 2010 | 2011 | |
| 2011 | 2012 | const limbs = try sema.arena.alloc( |
| 2012 | 2013 | std.math.big.Limb, |
src/Sema/bitcast.zig+7-4| ... | ... | @@ -79,8 +79,8 @@ fn bitCastInner( |
| 79 | 79 | |
| 80 | 80 | const val_ty = val.typeOf(zcu); |
| 81 | 81 | |
| 82 | try val_ty.resolveLayout(pt); | |
| 83 | try dest_ty.resolveLayout(pt); | |
| 82 | val_ty.assertHasLayout(zcu); | |
| 83 | try sema.ensureLayoutResolved(dest_ty); | |
| 84 | 84 | |
| 85 | 85 | assert(val_ty.hasWellDefinedLayout(zcu)); |
| 86 | 86 | |
| ... | ... | @@ -138,8 +138,8 @@ fn bitCastSpliceInner( |
| 138 | 138 | const val_ty = val.typeOf(zcu); |
| 139 | 139 | const splice_val_ty = splice_val.typeOf(zcu); |
| 140 | 140 | |
| 141 | try val_ty.resolveLayout(pt); | |
| 142 | try splice_val_ty.resolveLayout(pt); | |
| 141 | try sema.ensureLayoutResolved(val_ty); | |
| 142 | try sema.ensureLayoutResolved(splice_val_ty); | |
| 143 | 143 | |
| 144 | 144 | const splice_bits = splice_val_ty.bitSize(zcu); |
| 145 | 145 | |
| ... | ... | @@ -673,6 +673,9 @@ const PackValueBits = struct { |
| 673 | 673 | fn primitive(pack: *PackValueBits, want_ty: Type) BitCastError!Value { |
| 674 | 674 | const pt = pack.pt; |
| 675 | 675 | const zcu = pt.zcu; |
| 676 | ||
| 677 | if (try want_ty.onePossibleValue(pt)) |opv| return opv; | |
| 678 | ||
| 676 | 679 | const vals, const bit_offset = pack.prepareBits(want_ty.bitSize(zcu)); |
| 677 | 680 | |
| 678 | 681 | for (vals) |val| { |
src/Sema/comptime_ptr_access.zig+19-19| ... | ... | @@ -67,7 +67,7 @@ pub fn storeComptimePtr( |
| 67 | 67 | |
| 68 | 68 | { |
| 69 | 69 | const store_ty: Type = .fromInterned(ptr_info.child); |
| 70 | if (!try store_ty.comptimeOnlySema(pt) and !try store_ty.hasRuntimeBitsIgnoreComptimeSema(pt)) { | |
| 70 | if (!store_ty.comptimeOnly(zcu) and !store_ty.hasRuntimeBits(zcu)) { | |
| 71 | 71 | // zero-bit store; nothing to do |
| 72 | 72 | return .success; |
| 73 | 73 | } |
| ... | ... | @@ -354,8 +354,8 @@ fn loadComptimePtrInner( |
| 354 | 354 | const load_one_ty, const load_count = load_ty.arrayBase(zcu); |
| 355 | 355 | |
| 356 | 356 | const extra_base_index: u64 = if (ptr.byte_offset == 0) 0 else idx: { |
| 357 | if (try load_one_ty.comptimeOnlySema(pt)) break :restructure_array; | |
| 358 | const elem_len = try load_one_ty.abiSizeSema(pt); | |
| 357 | if (load_one_ty.comptimeOnly(zcu)) break :restructure_array; | |
| 358 | const elem_len = load_one_ty.abiSize(zcu); | |
| 359 | 359 | if (ptr.byte_offset % elem_len != 0) break :restructure_array; |
| 360 | 360 | break :idx @divExact(ptr.byte_offset, elem_len); |
| 361 | 361 | }; |
| ... | ... | @@ -401,12 +401,12 @@ fn loadComptimePtrInner( |
| 401 | 401 | var cur_offset = ptr.byte_offset; |
| 402 | 402 | |
| 403 | 403 | if (load_ty.zigTypeTag(zcu) == .array and array_offset > 0) { |
| 404 | cur_offset += try load_ty.childType(zcu).abiSizeSema(pt) * array_offset; | |
| 404 | cur_offset += load_ty.childType(zcu).abiSize(zcu) * array_offset; | |
| 405 | 405 | } |
| 406 | 406 | |
| 407 | const need_bytes = if (host_bits > 0) (host_bits + 7) / 8 else try load_ty.abiSizeSema(pt); | |
| 407 | const need_bytes = if (host_bits > 0) (host_bits + 7) / 8 else load_ty.abiSize(zcu); | |
| 408 | 408 | |
| 409 | if (cur_offset + need_bytes > try cur_val.typeOf(zcu).abiSizeSema(pt)) { | |
| 409 | if (cur_offset + need_bytes > cur_val.typeOf(zcu).abiSize(zcu)) { | |
| 410 | 410 | return .{ .out_of_bounds = cur_val.typeOf(zcu) }; |
| 411 | 411 | } |
| 412 | 412 | |
| ... | ... | @@ -441,7 +441,7 @@ fn loadComptimePtrInner( |
| 441 | 441 | .optional => break, // this can only be a pointer-like optional so is terminal |
| 442 | 442 | .array => { |
| 443 | 443 | const elem_ty = cur_ty.childType(zcu); |
| 444 | const elem_size = try elem_ty.abiSizeSema(pt); | |
| 444 | const elem_size = elem_ty.abiSize(zcu); | |
| 445 | 445 | const elem_idx = cur_offset / elem_size; |
| 446 | 446 | const next_elem_off = elem_size * (elem_idx + 1); |
| 447 | 447 | if (cur_offset + need_bytes <= next_elem_off) { |
| ... | ... | @@ -457,7 +457,7 @@ fn loadComptimePtrInner( |
| 457 | 457 | .@"packed" => break, // let the bitcast logic handle this |
| 458 | 458 | .@"extern" => for (0..cur_ty.structFieldCount(zcu)) |field_idx| { |
| 459 | 459 | const start_off = cur_ty.structFieldOffset(field_idx, zcu); |
| 460 | const end_off = start_off + try cur_ty.fieldType(field_idx, zcu).abiSizeSema(pt); | |
| 460 | const end_off = start_off + cur_ty.fieldType(field_idx, zcu).abiSize(zcu); | |
| 461 | 461 | if (cur_offset >= start_off and cur_offset + need_bytes <= end_off) { |
| 462 | 462 | cur_val = try cur_val.getElem(sema.pt, field_idx); |
| 463 | 463 | cur_offset -= start_off; |
| ... | ... | @@ -484,7 +484,7 @@ fn loadComptimePtrInner( |
| 484 | 484 | }; |
| 485 | 485 | // The payload always has offset 0. If it's big enough |
| 486 | 486 | // to represent the whole load type, we can use it. |
| 487 | if (try payload.typeOf(zcu).abiSizeSema(pt) >= need_bytes) { | |
| 487 | if (payload.typeOf(zcu).abiSize(zcu) >= need_bytes) { | |
| 488 | 488 | cur_val = payload; |
| 489 | 489 | } else { |
| 490 | 490 | break; |
| ... | ... | @@ -753,8 +753,8 @@ fn prepareComptimePtrStore( |
| 753 | 753 | |
| 754 | 754 | const store_one_ty, const store_count = store_ty.arrayBase(zcu); |
| 755 | 755 | const extra_base_index: u64 = if (ptr.byte_offset == 0) 0 else idx: { |
| 756 | if (try store_one_ty.comptimeOnlySema(pt)) break :restructure_array; | |
| 757 | const elem_len = try store_one_ty.abiSizeSema(pt); | |
| 756 | if (store_one_ty.comptimeOnly(zcu)) break :restructure_array; | |
| 757 | const elem_len = store_one_ty.abiSize(zcu); | |
| 758 | 758 | if (ptr.byte_offset % elem_len != 0) break :restructure_array; |
| 759 | 759 | break :idx @divExact(ptr.byte_offset, elem_len); |
| 760 | 760 | }; |
| ... | ... | @@ -807,11 +807,11 @@ fn prepareComptimePtrStore( |
| 807 | 807 | var cur_val: *MutableValue, var cur_offset: u64 = switch (base_strat) { |
| 808 | 808 | .direct => |direct| .{ direct.val, 0 }, |
| 809 | 809 | // It's okay to do `abiSize` - the comptime-only case will be caught below. |
| 810 | .index => |index| .{ index.val, index.elem_index * try index.val.typeOf(zcu).childType(zcu).abiSizeSema(pt) }, | |
| 810 | .index => |index| .{ index.val, index.elem_index * index.val.typeOf(zcu).childType(zcu).abiSize(zcu) }, | |
| 811 | 811 | .flat_index => |flat_index| .{ |
| 812 | 812 | flat_index.val, |
| 813 | 813 | // It's okay to do `abiSize` - the comptime-only case will be caught below. |
| 814 | flat_index.flat_elem_index * try flat_index.val.typeOf(zcu).arrayBase(zcu)[0].abiSizeSema(pt), | |
| 814 | flat_index.flat_elem_index * flat_index.val.typeOf(zcu).arrayBase(zcu)[0].abiSize(zcu), | |
| 815 | 815 | }, |
| 816 | 816 | .reinterpret => |r| .{ r.val, r.byte_offset }, |
| 817 | 817 | else => unreachable, |
| ... | ... | @@ -823,12 +823,12 @@ fn prepareComptimePtrStore( |
| 823 | 823 | } |
| 824 | 824 | |
| 825 | 825 | if (store_ty.zigTypeTag(zcu) == .array and array_offset > 0) { |
| 826 | cur_offset += try store_ty.childType(zcu).abiSizeSema(pt) * array_offset; | |
| 826 | cur_offset += store_ty.childType(zcu).abiSize(zcu) * array_offset; | |
| 827 | 827 | } |
| 828 | 828 | |
| 829 | const need_bytes = try store_ty.abiSizeSema(pt); | |
| 829 | const need_bytes = store_ty.abiSize(zcu); | |
| 830 | 830 | |
| 831 | if (cur_offset + need_bytes > try cur_val.typeOf(zcu).abiSizeSema(pt)) { | |
| 831 | if (cur_offset + need_bytes > cur_val.typeOf(zcu).abiSize(zcu)) { | |
| 832 | 832 | return .{ .out_of_bounds = cur_val.typeOf(zcu) }; |
| 833 | 833 | } |
| 834 | 834 | |
| ... | ... | @@ -863,7 +863,7 @@ fn prepareComptimePtrStore( |
| 863 | 863 | .optional => break, // this can only be a pointer-like optional so is terminal |
| 864 | 864 | .array => { |
| 865 | 865 | const elem_ty = cur_ty.childType(zcu); |
| 866 | const elem_size = try elem_ty.abiSizeSema(pt); | |
| 866 | const elem_size = elem_ty.abiSize(zcu); | |
| 867 | 867 | const elem_idx = cur_offset / elem_size; |
| 868 | 868 | const next_elem_off = elem_size * (elem_idx + 1); |
| 869 | 869 | if (cur_offset + need_bytes <= next_elem_off) { |
| ... | ... | @@ -879,7 +879,7 @@ fn prepareComptimePtrStore( |
| 879 | 879 | .@"packed" => break, // let the bitcast logic handle this |
| 880 | 880 | .@"extern" => for (0..cur_ty.structFieldCount(zcu)) |field_idx| { |
| 881 | 881 | const start_off = cur_ty.structFieldOffset(field_idx, zcu); |
| 882 | const end_off = start_off + try cur_ty.fieldType(field_idx, zcu).abiSizeSema(pt); | |
| 882 | const end_off = start_off + cur_ty.fieldType(field_idx, zcu).abiSize(zcu); | |
| 883 | 883 | if (cur_offset >= start_off and cur_offset + need_bytes <= end_off) { |
| 884 | 884 | cur_val = try cur_val.elem(pt, sema.arena, field_idx); |
| 885 | 885 | cur_offset -= start_off; |
| ... | ... | @@ -902,7 +902,7 @@ fn prepareComptimePtrStore( |
| 902 | 902 | }; |
| 903 | 903 | // The payload always has offset 0. If it's big enough |
| 904 | 904 | // to represent the whole load type, we can use it. |
| 905 | if (try payload.typeOf(zcu).abiSizeSema(pt) >= need_bytes) { | |
| 905 | if (payload.typeOf(zcu).abiSize(zcu) >= need_bytes) { | |
| 906 | 906 | cur_val = payload; |
| 907 | 907 | } else { |
| 908 | 908 | break; |
src/Sema/type_resolution.zig created+993| ... | ... | @@ -0,0 +1,993 @@ |
| 1 | const std = @import("std"); | |
| 2 | const assert = std.debug.assert; | |
| 3 | const mem = std.mem; | |
| 4 | ||
| 5 | const Sema = @import("../Sema.zig"); | |
| 6 | const Block = Sema.Block; | |
| 7 | const Type = @import("../Type.zig"); | |
| 8 | const Value = @import("../Value.zig"); | |
| 9 | const Zcu = @import("../Zcu.zig"); | |
| 10 | const CompileError = Zcu.CompileError; | |
| 11 | const SemaError = Zcu.SemaError; | |
| 12 | const LazySrcLoc = Zcu.LazySrcLoc; | |
| 13 | const InternPool = @import("../InternPool.zig"); | |
| 14 | const Alignment = InternPool.Alignment; | |
| 15 | const arith = @import("arith.zig"); | |
| 16 | ||
| 17 | /// Ensures that `ty` has known layout, including alignment, size, and (where relevant) field offsets. | |
| 18 | /// `ty` may be any type; its layout is resolved *recursively* if necessary. | |
| 19 | /// Adds incremental dependencies tracking any required type resolution. | |
| 20 | /// MLUGG TODO: to make the langspec non-stupid, we need to call this from WAY fewer places (the conditions need to be less specific). | |
| 21 | /// e.g. I think creating the type `fn (A, B) C` should force layout resolution of `A`,`B`,`C`, which will simplify some `analyzeCall` logic. | |
| 22 | /// wait i just realised that's probably a terrible idea, fns are a common cause of dep loops rn... so maybe not lol idk... | |
| 23 | /// perhaps "layout resolution" for a function should resolve layout of ret ty and stuff, idk. justification: the "layout" of a function is whether | |
| 24 | /// fnHasRuntimeBits, which depends whether the ret ty is comptime-only, i.e. the ret ty layout | |
| 25 | /// MLUGG TODO: to be clear, i should audit EVERY use of this before PRing | |
| 26 | pub fn ensureLayoutResolved(sema: *Sema, ty: Type) SemaError!void { | |
| 27 | const pt = sema.pt; | |
| 28 | const zcu = pt.zcu; | |
| 29 | const ip = &zcu.intern_pool; | |
| 30 | switch (ip.indexToKey(ty.toIntern())) { | |
| 31 | .int_type, | |
| 32 | .ptr_type, | |
| 33 | .anyframe_type, | |
| 34 | .simple_type, | |
| 35 | .opaque_type, | |
| 36 | .enum_type, | |
| 37 | .error_set_type, | |
| 38 | .inferred_error_set_type, | |
| 39 | => {}, | |
| 40 | ||
| 41 | .func_type => |func_type| { | |
| 42 | for (func_type.param_types.get(ip)) |param_ty| { | |
| 43 | try ensureLayoutResolved(sema, .fromInterned(param_ty)); | |
| 44 | } | |
| 45 | try ensureLayoutResolved(sema, .fromInterned(func_type.return_type)); | |
| 46 | }, | |
| 47 | ||
| 48 | .array_type => |arr| return ensureLayoutResolved(sema, .fromInterned(arr.child)), | |
| 49 | .vector_type => |vec| return ensureLayoutResolved(sema, .fromInterned(vec.child)), | |
| 50 | .opt_type => |child| return ensureLayoutResolved(sema, .fromInterned(child)), | |
| 51 | .error_union_type => |eu| return ensureLayoutResolved(sema, .fromInterned(eu.payload_type)), | |
| 52 | .tuple_type => |tuple| for (tuple.types.get(ip)) |field_ty| { | |
| 53 | try ensureLayoutResolved(sema, .fromInterned(field_ty)); | |
| 54 | }, | |
| 55 | .struct_type, .union_type => { | |
| 56 | try sema.declareDependency(.{ .type_layout = ty.toIntern() }); | |
| 57 | if (zcu.analysis_in_progress.contains(.wrap(.{ .type_layout = ty.toIntern() }))) { | |
| 58 | // TODO: better error message | |
| 59 | return sema.failWithOwnedErrorMsg(null, try sema.errMsg( | |
| 60 | ty.srcLoc(zcu), | |
| 61 | "{s} '{f}' depends on itself", | |
| 62 | .{ @tagName(ty.zigTypeTag(zcu)), ty.fmt(pt) }, | |
| 63 | )); | |
| 64 | } | |
| 65 | try pt.ensureTypeLayoutUpToDate(ty); | |
| 66 | }, | |
| 67 | ||
| 68 | // values, not types | |
| 69 | .undef, | |
| 70 | .simple_value, | |
| 71 | .variable, | |
| 72 | .@"extern", | |
| 73 | .func, | |
| 74 | .int, | |
| 75 | .err, | |
| 76 | .error_union, | |
| 77 | .enum_literal, | |
| 78 | .enum_tag, | |
| 79 | .empty_enum_value, | |
| 80 | .float, | |
| 81 | .ptr, | |
| 82 | .slice, | |
| 83 | .opt, | |
| 84 | .aggregate, | |
| 85 | .un, | |
| 86 | // memoization, not types | |
| 87 | .memoized_call, | |
| 88 | => unreachable, | |
| 89 | } | |
| 90 | } | |
| 91 | ||
| 92 | /// Asserts that `ty` is either a `struct` type, or an `enum` type. | |
| 93 | /// If `ty` is a struct, ensures that fields' default values are resolved. | |
| 94 | /// If `ty` is an enum, ensures that fields' integer tag valus are resolved. | |
| 95 | /// Adds incremental dependencies tracking the required type resolution. | |
| 96 | pub fn ensureFieldInitsResolved(sema: *Sema, ty: Type) SemaError!void { | |
| 97 | const pt = sema.pt; | |
| 98 | const zcu = pt.zcu; | |
| 99 | const ip = &zcu.intern_pool; | |
| 100 | switch (ip.indexToKey(ty.toIntern())) { | |
| 101 | .struct_type, .enum_type => {}, | |
| 102 | else => unreachable, // assertion failure | |
| 103 | } | |
| 104 | ||
| 105 | try sema.declareDependency(.{ .type_inits = ty.toIntern() }); | |
| 106 | if (zcu.analysis_in_progress.contains(.wrap(.{ .type_inits = ty.toIntern() }))) { | |
| 107 | // TODO: better error message | |
| 108 | return sema.failWithOwnedErrorMsg(null, try sema.errMsg( | |
| 109 | ty.srcLoc(zcu), | |
| 110 | "{s} '{f}' depends on itself", | |
| 111 | .{ @tagName(ty.zigTypeTag(zcu)), ty.fmt(pt) }, | |
| 112 | )); | |
| 113 | } | |
| 114 | try pt.ensureTypeInitsUpToDate(ty); | |
| 115 | } | |
| 116 | /// Asserts that `struct_ty` is a non-packed non-tuple struct, and that `sema.owner` is that type. | |
| 117 | /// This function *does* register the `src_hash` dependency on the struct. | |
| 118 | pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void { | |
| 119 | const pt = sema.pt; | |
| 120 | const zcu = pt.zcu; | |
| 121 | const comp = zcu.comp; | |
| 122 | const gpa = comp.gpa; | |
| 123 | const ip = &zcu.intern_pool; | |
| 124 | ||
| 125 | assert(sema.owner.unwrap().type_layout == struct_ty.toIntern()); | |
| 126 | ||
| 127 | const struct_obj = ip.loadStructType(struct_ty.toIntern()); | |
| 128 | const zir_index = struct_obj.zir_index.resolve(ip).?; | |
| 129 | ||
| 130 | assert(struct_obj.layout != .@"packed"); | |
| 131 | ||
| 132 | try sema.declareDependency(.{ .src_hash = struct_obj.zir_index }); | |
| 133 | ||
| 134 | var block: Block = .{ | |
| 135 | .parent = null, | |
| 136 | .sema = sema, | |
| 137 | .namespace = struct_obj.namespace, | |
| 138 | .instructions = .{}, | |
| 139 | .inlining = null, | |
| 140 | .comptime_reason = undefined, // always set before using `block` | |
| 141 | .src_base_inst = struct_obj.zir_index, | |
| 142 | .type_name_ctx = struct_obj.name, | |
| 143 | }; | |
| 144 | defer assert(block.instructions.items.len == 0); | |
| 145 | ||
| 146 | const zir_struct = sema.code.getStructDecl(zir_index); | |
| 147 | var field_it = zir_struct.iterateFields(); | |
| 148 | while (field_it.next()) |zir_field| { | |
| 149 | const field_ty_src: LazySrcLoc = .{ | |
| 150 | .base_node_inst = struct_obj.zir_index, | |
| 151 | .offset = .{ .container_field_type = zir_field.idx }, | |
| 152 | }; | |
| 153 | const field_align_src: LazySrcLoc = .{ | |
| 154 | .base_node_inst = struct_obj.zir_index, | |
| 155 | .offset = .{ .container_field_align = zir_field.idx }, | |
| 156 | }; | |
| 157 | ||
| 158 | const field_ty: Type = field_ty: { | |
| 159 | block.comptime_reason = .{ .reason = .{ | |
| 160 | .src = field_ty_src, | |
| 161 | .r = .{ .simple = .struct_field_types }, | |
| 162 | } }; | |
| 163 | const type_ref = try sema.resolveInlineBody(&block, zir_field.type_body, zir_index); | |
| 164 | break :field_ty try sema.analyzeAsType(&block, field_ty_src, type_ref); | |
| 165 | }; | |
| 166 | assert(!field_ty.isGenericPoison()); | |
| 167 | ||
| 168 | try sema.ensureLayoutResolved(field_ty); | |
| 169 | ||
| 170 | const explicit_field_align: Alignment = a: { | |
| 171 | block.comptime_reason = .{ .reason = .{ | |
| 172 | .src = field_align_src, | |
| 173 | .r = .{ .simple = .struct_field_attrs }, | |
| 174 | } }; | |
| 175 | const align_body = zir_field.align_body orelse break :a .none; | |
| 176 | const align_ref = try sema.resolveInlineBody(&block, align_body, zir_index); | |
| 177 | break :a try sema.analyzeAsAlign(&block, field_align_src, align_ref); | |
| 178 | }; | |
| 179 | ||
| 180 | if (field_ty.zigTypeTag(zcu) == .@"opaque") { | |
| 181 | return sema.failWithOwnedErrorMsg(&block, msg: { | |
| 182 | const msg = try sema.errMsg(field_ty_src, "cannot directly embed opaque type '{f}' in struct", .{field_ty.fmt(pt)}); | |
| 183 | errdefer msg.destroy(gpa); | |
| 184 | try sema.errNote(field_ty_src, msg, "opaque types have unknown size", .{}); | |
| 185 | try sema.addDeclaredHereNote(msg, field_ty); | |
| 186 | break :msg msg; | |
| 187 | }); | |
| 188 | } | |
| 189 | if (struct_obj.layout == .@"extern" and !try sema.validateExternType(field_ty, .struct_field)) { | |
| 190 | return sema.failWithOwnedErrorMsg(&block, msg: { | |
| 191 | const msg = try sema.errMsg(field_ty_src, "extern structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); | |
| 192 | errdefer msg.destroy(gpa); | |
| 193 | try sema.explainWhyTypeIsNotExtern(msg, field_ty_src, field_ty, .struct_field); | |
| 194 | try sema.addDeclaredHereNote(msg, field_ty); | |
| 195 | break :msg msg; | |
| 196 | }); | |
| 197 | } | |
| 198 | ||
| 199 | struct_obj.field_types.get(ip)[zir_field.idx] = field_ty.toIntern(); | |
| 200 | if (struct_obj.field_aligns.len != 0) { | |
| 201 | struct_obj.field_aligns.get(ip)[zir_field.idx] = explicit_field_align; | |
| 202 | } else { | |
| 203 | assert(explicit_field_align == .none); | |
| 204 | } | |
| 205 | } | |
| 206 | ||
| 207 | try finishStructLayout(sema, &block, struct_ty.srcLoc(zcu), struct_ty.toIntern(), &struct_obj); | |
| 208 | } | |
| 209 | ||
| 210 | /// Called after populating field types and alignments; populates field offsets, runtime order, and | |
| 211 | /// overall struct layout information (size, alignment, comptime-only state, etc). | |
| 212 | pub fn finishStructLayout( | |
| 213 | sema: *Sema, | |
| 214 | /// Only used to report compile errors. | |
| 215 | block: *Block, | |
| 216 | struct_src: LazySrcLoc, | |
| 217 | struct_ty: InternPool.Index, | |
| 218 | struct_obj: *const InternPool.LoadedStructType, | |
| 219 | ) SemaError!void { | |
| 220 | const pt = sema.pt; | |
| 221 | const zcu = pt.zcu; | |
| 222 | const comp = zcu.comp; | |
| 223 | const io = comp.io; | |
| 224 | const ip = &zcu.intern_pool; | |
| 225 | var comptime_only = false; | |
| 226 | var one_possible_value = true; | |
| 227 | var struct_align: Alignment = .@"1"; | |
| 228 | // Unlike `struct_obj.field_aligns`, these are not `.none`. | |
| 229 | const resolved_field_aligns = try sema.arena.alloc(Alignment, struct_obj.field_names.len); | |
| 230 | for (resolved_field_aligns, 0..) |*align_out, field_idx| { | |
| 231 | const field_ty: Type = .fromInterned(struct_obj.field_types.get(ip)[field_idx]); | |
| 232 | const field_align: Alignment = a: { | |
| 233 | if (struct_obj.field_aligns.len != 0) { | |
| 234 | const a = struct_obj.field_aligns.get(ip)[field_idx]; | |
| 235 | if (a != .none) break :a a; | |
| 236 | } | |
| 237 | break :a field_ty.defaultStructFieldAlignment(struct_obj.layout, zcu); | |
| 238 | }; | |
| 239 | if (!struct_obj.field_is_comptime_bits.get(ip, field_idx)) { | |
| 240 | // Non-`comptime` fields contribute to the struct's layout. | |
| 241 | struct_align = struct_align.maxStrict(field_align); | |
| 242 | if (field_ty.comptimeOnly(zcu)) comptime_only = true; | |
| 243 | if (try field_ty.onePossibleValue(pt) == null) one_possible_value = false; | |
| 244 | if (struct_obj.layout == .auto) { | |
| 245 | struct_obj.field_runtime_order.get(ip)[field_idx] = @enumFromInt(field_idx); | |
| 246 | } | |
| 247 | } else if (struct_obj.layout == .auto) { | |
| 248 | struct_obj.field_runtime_order.get(ip)[field_idx] = .omitted; // comptime fields are not in the runtime order | |
| 249 | } | |
| 250 | align_out.* = field_align; | |
| 251 | } | |
| 252 | if (struct_obj.layout == .auto) { | |
| 253 | const runtime_order = struct_obj.field_runtime_order.get(ip); | |
| 254 | // This logic does not reorder fields; it only moves the omitted ones to the end so that logic | |
| 255 | // elsewhere does not need to special-case. TODO: support field reordering in all the backends! | |
| 256 | if (!zcu.backendSupportsFeature(.field_reordering)) { | |
| 257 | var i: usize = 0; | |
| 258 | var off: usize = 0; | |
| 259 | while (i + off < runtime_order.len) { | |
| 260 | if (runtime_order[i + off] == .omitted) { | |
| 261 | off += 1; | |
| 262 | } else { | |
| 263 | runtime_order[i] = runtime_order[i + off]; | |
| 264 | i += 1; | |
| 265 | } | |
| 266 | } | |
| 267 | } else { | |
| 268 | // Sort by descending alignment to minimize padding. | |
| 269 | const RuntimeOrder = InternPool.LoadedStructType.RuntimeOrder; | |
| 270 | const AlignSortCtx = struct { | |
| 271 | aligns: []const Alignment, | |
| 272 | fn lessThan(ctx: @This(), a: RuntimeOrder, b: RuntimeOrder) bool { | |
| 273 | assert(a != .unresolved); | |
| 274 | assert(b != .unresolved); | |
| 275 | if (a == .omitted) return false; | |
| 276 | if (b == .omitted) return true; | |
| 277 | const a_align = ctx.aligns[@intFromEnum(a)]; | |
| 278 | const b_align = ctx.aligns[@intFromEnum(b)]; | |
| 279 | return a_align.compare(.gt, b_align); | |
| 280 | } | |
| 281 | }; | |
| 282 | mem.sortUnstable( | |
| 283 | RuntimeOrder, | |
| 284 | runtime_order, | |
| 285 | @as(AlignSortCtx, .{ .aligns = resolved_field_aligns }), | |
| 286 | AlignSortCtx.lessThan, | |
| 287 | ); | |
| 288 | } | |
| 289 | } | |
| 290 | ||
| 291 | var runtime_order_it = struct_obj.iterateRuntimeOrder(ip); | |
| 292 | var cur_offset: u64 = 0; | |
| 293 | while (runtime_order_it.next()) |field_idx| { | |
| 294 | const field_ty: Type = .fromInterned(struct_obj.field_types.get(ip)[field_idx]); | |
| 295 | const offset = resolved_field_aligns[field_idx].forward(cur_offset); | |
| 296 | struct_obj.field_offsets.get(ip)[field_idx] = @truncate(offset); // truncate because the overflow is handled below | |
| 297 | cur_offset = offset + field_ty.abiSize(zcu); | |
| 298 | } | |
| 299 | const struct_size = std.math.cast(u32, struct_align.forward(cur_offset)) orelse return sema.fail( | |
| 300 | block, | |
| 301 | struct_src, | |
| 302 | "struct layout requires size {d}, this compiler implementation supports up to {d}", | |
| 303 | .{ struct_align.forward(cur_offset), std.math.maxInt(u32) }, | |
| 304 | ); | |
| 305 | ip.resolveStructLayout( | |
| 306 | io, | |
| 307 | struct_ty, | |
| 308 | struct_size, | |
| 309 | struct_align, | |
| 310 | false, // MLUGG TODO XXX NPV | |
| 311 | one_possible_value, | |
| 312 | comptime_only, | |
| 313 | ); | |
| 314 | } | |
| 315 | ||
| 316 | /// Asserts that `struct_ty` is a packed struct, and that `sema.owner` is that type. | |
| 317 | /// This function *does* register the `src_hash` dependency on the struct. | |
| 318 | pub fn resolvePackedStructLayout(sema: *Sema, struct_ty: Type) CompileError!void { | |
| 319 | const pt = sema.pt; | |
| 320 | const zcu = pt.zcu; | |
| 321 | const comp = zcu.comp; | |
| 322 | const gpa = comp.gpa; | |
| 323 | const ip = &zcu.intern_pool; | |
| 324 | ||
| 325 | assert(sema.owner.unwrap().type_layout == struct_ty.toIntern()); | |
| 326 | ||
| 327 | const struct_obj = ip.loadStructType(struct_ty.toIntern()); | |
| 328 | const zir_index = struct_obj.zir_index.resolve(ip).?; | |
| 329 | ||
| 330 | assert(struct_obj.layout == .@"packed"); | |
| 331 | ||
| 332 | try sema.declareDependency(.{ .src_hash = struct_obj.zir_index }); | |
| 333 | ||
| 334 | var block: Block = .{ | |
| 335 | .parent = null, | |
| 336 | .sema = sema, | |
| 337 | .namespace = struct_obj.namespace, | |
| 338 | .instructions = .{}, | |
| 339 | .inlining = null, | |
| 340 | .comptime_reason = undefined, // always set before using `block` | |
| 341 | .src_base_inst = struct_obj.zir_index, | |
| 342 | .type_name_ctx = struct_obj.name, | |
| 343 | }; | |
| 344 | defer assert(block.instructions.items.len == 0); | |
| 345 | ||
| 346 | var field_bits: u64 = 0; | |
| 347 | const zir_struct = sema.code.getStructDecl(zir_index); | |
| 348 | var field_it = zir_struct.iterateFields(); | |
| 349 | while (field_it.next()) |zir_field| { | |
| 350 | const field_ty_src: LazySrcLoc = .{ | |
| 351 | .base_node_inst = struct_obj.zir_index, | |
| 352 | .offset = .{ .container_field_type = zir_field.idx }, | |
| 353 | }; | |
| 354 | const field_ty: Type = field_ty: { | |
| 355 | block.comptime_reason = .{ .reason = .{ | |
| 356 | .src = field_ty_src, | |
| 357 | .r = .{ .simple = .struct_field_types }, | |
| 358 | } }; | |
| 359 | const type_ref = try sema.resolveInlineBody(&block, zir_field.type_body, zir_index); | |
| 360 | break :field_ty try sema.analyzeAsType(&block, field_ty_src, type_ref); | |
| 361 | }; | |
| 362 | assert(!field_ty.isGenericPoison()); | |
| 363 | struct_obj.field_types.get(ip)[zir_field.idx] = field_ty.toIntern(); | |
| 364 | ||
| 365 | try sema.ensureLayoutResolved(field_ty); | |
| 366 | ||
| 367 | if (field_ty.zigTypeTag(zcu) == .@"opaque") { | |
| 368 | return sema.failWithOwnedErrorMsg(&block, msg: { | |
| 369 | const msg = try sema.errMsg(field_ty_src, "cannot directly embed opaque type '{f}' in struct", .{field_ty.fmt(pt)}); | |
| 370 | errdefer msg.destroy(gpa); | |
| 371 | try sema.errNote(field_ty_src, msg, "opaque types have unknown size", .{}); | |
| 372 | try sema.addDeclaredHereNote(msg, field_ty); | |
| 373 | break :msg msg; | |
| 374 | }); | |
| 375 | } | |
| 376 | if (!field_ty.packable(zcu)) { | |
| 377 | return sema.failWithOwnedErrorMsg(&block, msg: { | |
| 378 | const msg = try sema.errMsg(field_ty_src, "packed structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); | |
| 379 | errdefer msg.destroy(gpa); | |
| 380 | try sema.explainWhyTypeIsNotPackable(msg, field_ty_src, field_ty); | |
| 381 | try sema.addDeclaredHereNote(msg, field_ty); | |
| 382 | break :msg msg; | |
| 383 | }); | |
| 384 | } | |
| 385 | assert(!field_ty.comptimeOnly(zcu)); // packable types are not comptime-only | |
| 386 | field_bits += field_ty.bitSize(zcu); | |
| 387 | } | |
| 388 | ||
| 389 | try resolvePackedStructBackingInt(sema, &block, field_bits, struct_ty, &struct_obj); | |
| 390 | } | |
| 391 | ||
| 392 | pub fn resolvePackedStructBackingInt( | |
| 393 | sema: *Sema, | |
| 394 | block: *Block, | |
| 395 | field_bits: u64, | |
| 396 | struct_ty: Type, | |
| 397 | struct_obj: *const InternPool.LoadedStructType, | |
| 398 | ) SemaError!void { | |
| 399 | const pt = sema.pt; | |
| 400 | const zcu = pt.zcu; | |
| 401 | const comp = zcu.comp; | |
| 402 | const gpa = comp.gpa; | |
| 403 | const io = comp.io; | |
| 404 | const ip = &zcu.intern_pool; | |
| 405 | ||
| 406 | switch (struct_obj.packed_backing_mode) { | |
| 407 | .explicit => { | |
| 408 | // We only need to validate the type. | |
| 409 | const backing_ty: Type = .fromInterned(struct_obj.packed_backing_int_type); | |
| 410 | assert(backing_ty.zigTypeTag(zcu) == .int); | |
| 411 | if (field_bits != backing_ty.intInfo(zcu).bits) return sema.failWithOwnedErrorMsg(block, msg: { | |
| 412 | const src = struct_ty.srcLoc(zcu); | |
| 413 | const msg = try sema.errMsg(src, "backing integer bit width does not match total bit width of fields", .{}); | |
| 414 | errdefer msg.destroy(gpa); | |
| 415 | try sema.errNote(src, msg, "backing integer '{f}' has bit width '{d}'", .{ backing_ty.fmt(pt), backing_ty.bitSize(zcu) }); | |
| 416 | try sema.errNote(src, msg, "struct fields have total bit width '{d}'", .{field_bits}); | |
| 417 | break :msg msg; | |
| 418 | }); | |
| 419 | }, | |
| 420 | .auto => { | |
| 421 | // We need to generate the inferred tag. | |
| 422 | const want_bits = std.math.cast(u16, field_bits) orelse return sema.fail( | |
| 423 | block, | |
| 424 | struct_ty.srcLoc(zcu), | |
| 425 | "packed struct bit width '{d}' exceeds maximum bit width of 65535", | |
| 426 | .{field_bits}, | |
| 427 | ); | |
| 428 | const backing_int = try pt.intType(.unsigned, want_bits); | |
| 429 | ip.resolvePackedStructBackingInt(io, struct_ty.toIntern(), backing_int.toIntern()); | |
| 430 | }, | |
| 431 | } | |
| 432 | } | |
| 433 | ||
| 434 | /// Asserts that `struct_ty` is a non-tuple struct, and that `sema.owner` is that type. | |
| 435 | /// This function *does* register the `src_hash` dependency on the struct. | |
| 436 | pub fn resolveStructDefaults(sema: *Sema, struct_ty: Type) CompileError!void { | |
| 437 | const pt = sema.pt; | |
| 438 | const zcu = pt.zcu; | |
| 439 | const comp = zcu.comp; | |
| 440 | const gpa = comp.gpa; | |
| 441 | const ip = &zcu.intern_pool; | |
| 442 | ||
| 443 | assert(sema.owner.unwrap().type_inits == struct_ty.toIntern()); | |
| 444 | ||
| 445 | try sema.ensureLayoutResolved(struct_ty); | |
| 446 | ||
| 447 | const struct_obj = ip.loadStructType(struct_ty.toIntern()); | |
| 448 | const zir_index = struct_obj.zir_index.resolve(ip).?; | |
| 449 | ||
| 450 | try sema.declareDependency(.{ .src_hash = struct_obj.zir_index }); | |
| 451 | ||
| 452 | if (struct_obj.field_defaults.len == 0) { | |
| 453 | // The struct has no default field values, so the slice has been omitted. | |
| 454 | return; | |
| 455 | } | |
| 456 | ||
| 457 | const field_types = struct_obj.field_types.get(ip); | |
| 458 | ||
| 459 | var block: Block = .{ | |
| 460 | .parent = null, | |
| 461 | .sema = sema, | |
| 462 | .namespace = struct_obj.namespace, | |
| 463 | .instructions = .{}, | |
| 464 | .inlining = null, | |
| 465 | .comptime_reason = undefined, // always set before using `block` | |
| 466 | .src_base_inst = struct_obj.zir_index, | |
| 467 | .type_name_ctx = struct_obj.name, | |
| 468 | }; | |
| 469 | defer assert(block.instructions.items.len == 0); | |
| 470 | ||
| 471 | // We'll need to map the struct decl instruction to provide result types | |
| 472 | try sema.inst_map.ensureSpaceForInstructions(gpa, &.{zir_index}); | |
| 473 | ||
| 474 | const zir_struct = sema.code.getStructDecl(zir_index); | |
| 475 | var field_it = zir_struct.iterateFields(); | |
| 476 | while (field_it.next()) |zir_field| { | |
| 477 | const default_val_src: LazySrcLoc = .{ | |
| 478 | .base_node_inst = struct_obj.zir_index, | |
| 479 | .offset = .{ .container_field_value = zir_field.idx }, | |
| 480 | }; | |
| 481 | block.comptime_reason = .{ .reason = .{ | |
| 482 | .src = default_val_src, | |
| 483 | .r = .{ .simple = .struct_field_default_value }, | |
| 484 | } }; | |
| 485 | const default_body = zir_field.default_body orelse { | |
| 486 | struct_obj.field_defaults.get(ip)[zir_field.idx] = .none; | |
| 487 | continue; | |
| 488 | }; | |
| 489 | const field_ty: Type = .fromInterned(field_types[zir_field.idx]); | |
| 490 | const uncoerced = ref: { | |
| 491 | // Provide the result type | |
| 492 | sema.inst_map.putAssumeCapacity(zir_index, .fromIntern(field_ty.toIntern())); | |
| 493 | defer assert(sema.inst_map.remove(zir_index)); | |
| 494 | break :ref try sema.resolveInlineBody(&block, default_body, zir_index); | |
| 495 | }; | |
| 496 | const coerced = try sema.coerce(&block, field_ty, uncoerced, default_val_src); | |
| 497 | const default_val = try sema.resolveConstValue(&block, default_val_src, coerced, null); | |
| 498 | if (default_val.canMutateComptimeVarState(zcu)) { | |
| 499 | const field_name = struct_obj.field_names.get(ip)[zir_field.idx]; | |
| 500 | return sema.failWithContainsReferenceToComptimeVar(&block, default_val_src, field_name, "field default value", default_val); | |
| 501 | } | |
| 502 | struct_obj.field_defaults.get(ip)[zir_field.idx] = default_val.toIntern(); | |
| 503 | } | |
| 504 | } | |
| 505 | ||
| 506 | /// This logic must be kept in sync with `Type.getUnionLayout`. | |
| 507 | pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void { | |
| 508 | const pt = sema.pt; | |
| 509 | const zcu = pt.zcu; | |
| 510 | const comp = zcu.comp; | |
| 511 | const gpa = comp.gpa; | |
| 512 | const ip = &zcu.intern_pool; | |
| 513 | ||
| 514 | assert(sema.owner.unwrap().type_layout == union_ty.toIntern()); | |
| 515 | ||
| 516 | const union_obj = ip.loadUnionType(union_ty.toIntern()); | |
| 517 | const zir_index = union_obj.zir_index.resolve(ip).?; | |
| 518 | ||
| 519 | assert(union_obj.layout != .@"packed"); | |
| 520 | ||
| 521 | try sema.declareDependency(.{ .src_hash = union_obj.zir_index }); | |
| 522 | ||
| 523 | var block: Block = .{ | |
| 524 | .parent = null, | |
| 525 | .sema = sema, | |
| 526 | .namespace = union_obj.namespace, | |
| 527 | .instructions = .{}, | |
| 528 | .inlining = null, | |
| 529 | .comptime_reason = undefined, // always set before using `block` | |
| 530 | .src_base_inst = union_obj.zir_index, | |
| 531 | .type_name_ctx = union_obj.name, | |
| 532 | }; | |
| 533 | defer assert(block.instructions.items.len == 0); | |
| 534 | ||
| 535 | const zir_union = sema.code.getUnionDecl(zir_index); | |
| 536 | var field_it = zir_union.iterateFields(); | |
| 537 | while (field_it.next()) |zir_field| { | |
| 538 | const field_ty_src: LazySrcLoc = .{ | |
| 539 | .base_node_inst = union_obj.zir_index, | |
| 540 | .offset = .{ .container_field_type = zir_field.idx }, | |
| 541 | }; | |
| 542 | const field_align_src: LazySrcLoc = .{ | |
| 543 | .base_node_inst = union_obj.zir_index, | |
| 544 | .offset = .{ .container_field_align = zir_field.idx }, | |
| 545 | }; | |
| 546 | ||
| 547 | const field_ty: Type = field_ty: { | |
| 548 | block.comptime_reason = .{ .reason = .{ | |
| 549 | .src = field_ty_src, | |
| 550 | .r = .{ .simple = .union_field_types }, | |
| 551 | } }; | |
| 552 | const type_body = zir_field.type_body orelse break :field_ty .void; | |
| 553 | const type_ref = try sema.resolveInlineBody(&block, type_body, zir_index); | |
| 554 | break :field_ty try sema.analyzeAsType(&block, field_ty_src, type_ref); | |
| 555 | }; | |
| 556 | assert(!field_ty.isGenericPoison()); | |
| 557 | union_obj.field_types.get(ip)[zir_field.idx] = field_ty.toIntern(); | |
| 558 | ||
| 559 | try sema.ensureLayoutResolved(field_ty); | |
| 560 | ||
| 561 | const explicit_field_align: Alignment = a: { | |
| 562 | block.comptime_reason = .{ .reason = .{ | |
| 563 | .src = field_align_src, | |
| 564 | .r = .{ .simple = .union_field_attrs }, | |
| 565 | } }; | |
| 566 | const align_body = zir_field.align_body orelse break :a .none; | |
| 567 | const align_ref = try sema.resolveInlineBody(&block, align_body, zir_index); | |
| 568 | break :a try sema.analyzeAsAlign(&block, field_align_src, align_ref); | |
| 569 | }; | |
| 570 | ||
| 571 | if (union_obj.field_aligns.len != 0) { | |
| 572 | union_obj.field_aligns.get(ip)[zir_field.idx] = explicit_field_align; | |
| 573 | } else { | |
| 574 | assert(explicit_field_align == .none); | |
| 575 | } | |
| 576 | ||
| 577 | if (field_ty.zigTypeTag(zcu) == .@"opaque") { | |
| 578 | return sema.failWithOwnedErrorMsg(&block, msg: { | |
| 579 | const msg = try sema.errMsg(field_ty_src, "cannot directly embed opaque type '{f}' in union", .{field_ty.fmt(pt)}); | |
| 580 | errdefer msg.destroy(gpa); | |
| 581 | try sema.errNote(field_ty_src, msg, "opaque types have unknown size", .{}); | |
| 582 | try sema.addDeclaredHereNote(msg, field_ty); | |
| 583 | break :msg msg; | |
| 584 | }); | |
| 585 | } | |
| 586 | if (union_obj.layout == .@"extern" and !try sema.validateExternType(field_ty, .union_field)) { | |
| 587 | return sema.failWithOwnedErrorMsg(&block, msg: { | |
| 588 | const msg = try sema.errMsg(field_ty_src, "extern unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); | |
| 589 | errdefer msg.destroy(gpa); | |
| 590 | try sema.explainWhyTypeIsNotExtern(msg, field_ty_src, field_ty, .union_field); | |
| 591 | try sema.addDeclaredHereNote(msg, field_ty); | |
| 592 | break :msg msg; | |
| 593 | }); | |
| 594 | } | |
| 595 | } | |
| 596 | ||
| 597 | try finishUnionLayout( | |
| 598 | sema, | |
| 599 | &block, | |
| 600 | union_ty.srcLoc(zcu), | |
| 601 | union_ty.toIntern(), | |
| 602 | &union_obj, | |
| 603 | .fromInterned(union_obj.enum_tag_type), | |
| 604 | ); | |
| 605 | } | |
| 606 | ||
| 607 | /// Called after populating field types and alignments; populates overall union layout | |
| 608 | /// information (size, alignment, comptime-only state, etc). | |
| 609 | pub fn finishUnionLayout( | |
| 610 | sema: *Sema, | |
| 611 | /// Only used to report compile errors. | |
| 612 | block: *Block, | |
| 613 | union_src: LazySrcLoc, | |
| 614 | union_ty: InternPool.Index, | |
| 615 | union_obj: *const InternPool.LoadedUnionType, | |
| 616 | enum_tag_ty: Type, | |
| 617 | ) SemaError!void { | |
| 618 | const pt = sema.pt; | |
| 619 | const zcu = pt.zcu; | |
| 620 | const comp = zcu.comp; | |
| 621 | const io = comp.io; | |
| 622 | const ip = &zcu.intern_pool; | |
| 623 | ||
| 624 | var payload_align: Alignment = .@"1"; | |
| 625 | var payload_size: u64 = 0; | |
| 626 | var comptime_only = false; | |
| 627 | var possible_values: enum { none, one, many } = .none; | |
| 628 | for (0..union_obj.field_types.len) |field_idx| { | |
| 629 | const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_idx]); | |
| 630 | const field_align: Alignment = a: { | |
| 631 | if (union_obj.field_aligns.len != 0) { | |
| 632 | const a = union_obj.field_aligns.get(ip)[field_idx]; | |
| 633 | if (a != .none) break :a a; | |
| 634 | } | |
| 635 | break :a field_ty.abiAlignment(zcu); | |
| 636 | }; | |
| 637 | payload_align = payload_align.maxStrict(field_align); | |
| 638 | payload_size = @max(payload_size, field_ty.abiSize(zcu)); | |
| 639 | if (field_ty.comptimeOnly(zcu)) comptime_only = true; | |
| 640 | if (!field_ty.isNoReturn(zcu)) { | |
| 641 | if (try field_ty.onePossibleValue(pt) != null) { | |
| 642 | possible_values = .many; // this field alone has many possible values | |
| 643 | } else switch (possible_values) { | |
| 644 | .none => possible_values = .one, // there were none, now there is this field's OPV | |
| 645 | .one => possible_values = .many, // there was one, now there are two | |
| 646 | .many => {}, | |
| 647 | } | |
| 648 | } | |
| 649 | } | |
| 650 | ||
| 651 | const size: u64, const padding: u64, const alignment: Alignment = layout: { | |
| 652 | if (union_obj.runtime_tag == .none) { | |
| 653 | break :layout .{ payload_align.forward(payload_size), 0, payload_align }; | |
| 654 | } | |
| 655 | const tag_align = enum_tag_ty.abiAlignment(zcu); | |
| 656 | const tag_size = enum_tag_ty.abiSize(zcu); | |
| 657 | // The layout will either be (tag, payload, padding) or (payload, tag, padding) depending on | |
| 658 | // which has larger alignment. So the overall size is just the tag and payload sizes, added, | |
| 659 | // and padded to the larger alignment. | |
| 660 | const alignment = tag_align.maxStrict(payload_align); | |
| 661 | const unpadded_size = tag_size + payload_size; | |
| 662 | const size = alignment.forward(unpadded_size); | |
| 663 | break :layout .{ size, size - unpadded_size, alignment }; | |
| 664 | }; | |
| 665 | ||
| 666 | const casted_size = std.math.cast(u32, size) orelse return sema.fail( | |
| 667 | block, | |
| 668 | union_src, | |
| 669 | "union layout requires size {d}, this compiler implementation supports up to {d}", | |
| 670 | .{ size, std.math.maxInt(u32) }, | |
| 671 | ); | |
| 672 | ip.resolveUnionLayout( | |
| 673 | io, | |
| 674 | union_ty, | |
| 675 | casted_size, | |
| 676 | @intCast(padding), // okay because padding is no greater than size | |
| 677 | alignment, | |
| 678 | possible_values == .none, // MLUGG TODO: make sure queries use `LoadedUnionType.has_no_possible_value`! | |
| 679 | possible_values == .one, | |
| 680 | comptime_only, | |
| 681 | ); | |
| 682 | } | |
| 683 | ||
| 684 | pub fn resolvePackedUnionLayout(sema: *Sema, union_ty: Type) CompileError!void { | |
| 685 | const pt = sema.pt; | |
| 686 | const zcu = pt.zcu; | |
| 687 | const comp = zcu.comp; | |
| 688 | const gpa = comp.gpa; | |
| 689 | const ip = &zcu.intern_pool; | |
| 690 | ||
| 691 | assert(sema.owner.unwrap().type_layout == union_ty.toIntern()); | |
| 692 | ||
| 693 | const union_obj = ip.loadUnionType(union_ty.toIntern()); | |
| 694 | const zir_index = union_obj.zir_index.resolve(ip).?; | |
| 695 | ||
| 696 | assert(union_obj.layout == .@"packed"); | |
| 697 | ||
| 698 | try sema.declareDependency(.{ .src_hash = union_obj.zir_index }); | |
| 699 | ||
| 700 | var block: Block = .{ | |
| 701 | .parent = null, | |
| 702 | .sema = sema, | |
| 703 | .namespace = union_obj.namespace, | |
| 704 | .instructions = .{}, | |
| 705 | .inlining = null, | |
| 706 | .comptime_reason = undefined, // always set before using `block` | |
| 707 | .src_base_inst = union_obj.zir_index, | |
| 708 | .type_name_ctx = union_obj.name, | |
| 709 | }; | |
| 710 | defer assert(block.instructions.items.len == 0); | |
| 711 | ||
| 712 | const zir_union = sema.code.getUnionDecl(zir_index); | |
| 713 | var field_it = zir_union.iterateFields(); | |
| 714 | while (field_it.next()) |zir_field| { | |
| 715 | const field_ty_src: LazySrcLoc = .{ | |
| 716 | .base_node_inst = union_obj.zir_index, | |
| 717 | .offset = .{ .container_field_type = zir_field.idx }, | |
| 718 | }; | |
| 719 | const field_ty: Type = field_ty: { | |
| 720 | block.comptime_reason = .{ .reason = .{ | |
| 721 | .src = field_ty_src, | |
| 722 | .r = .{ .simple = .union_field_types }, | |
| 723 | } }; | |
| 724 | // MLUGG TODO: i think this should probably be a compile error? (if so, it's an astgen one, right?) | |
| 725 | const type_body = zir_field.type_body orelse break :field_ty .void; | |
| 726 | const type_ref = try sema.resolveInlineBody(&block, type_body, zir_index); | |
| 727 | break :field_ty try sema.analyzeAsType(&block, field_ty_src, type_ref); | |
| 728 | }; | |
| 729 | assert(!field_ty.isGenericPoison()); | |
| 730 | union_obj.field_types.get(ip)[zir_field.idx] = field_ty.toIntern(); | |
| 731 | ||
| 732 | assert(zir_field.align_body == null); // packed union fields cannot be aligned | |
| 733 | assert(zir_field.value_body == null); // packed union fields cannot have tag values | |
| 734 | ||
| 735 | try sema.ensureLayoutResolved(field_ty); | |
| 736 | ||
| 737 | if (field_ty.zigTypeTag(zcu) == .@"opaque") { | |
| 738 | return sema.failWithOwnedErrorMsg(&block, msg: { | |
| 739 | const msg = try sema.errMsg(field_ty_src, "cannot directly embed opaque type '{f}' in union", .{field_ty.fmt(pt)}); | |
| 740 | errdefer msg.destroy(gpa); | |
| 741 | try sema.errNote(field_ty_src, msg, "opaque types have unknown size", .{}); | |
| 742 | try sema.addDeclaredHereNote(msg, field_ty); | |
| 743 | break :msg msg; | |
| 744 | }); | |
| 745 | } | |
| 746 | if (!field_ty.packable(zcu)) { | |
| 747 | return sema.failWithOwnedErrorMsg(&block, msg: { | |
| 748 | const msg = try sema.errMsg(field_ty_src, "packed unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)}); | |
| 749 | errdefer msg.destroy(gpa); | |
| 750 | try sema.explainWhyTypeIsNotPackable(msg, field_ty_src, field_ty); | |
| 751 | try sema.addDeclaredHereNote(msg, field_ty); | |
| 752 | break :msg msg; | |
| 753 | }); | |
| 754 | } | |
| 755 | assert(!field_ty.comptimeOnly(zcu)); // packable types are not comptime-only | |
| 756 | } | |
| 757 | ||
| 758 | try resolvePackedUnionBackingInt(sema, &block, union_ty, &union_obj, false); | |
| 759 | } | |
| 760 | ||
| 761 | /// MLUGG TODO doc comment; asserts all fields are resolved or whatever | |
| 762 | pub fn resolvePackedUnionBackingInt( | |
| 763 | sema: *Sema, | |
| 764 | block: *Block, | |
| 765 | union_ty: Type, | |
| 766 | union_obj: *const InternPool.LoadedUnionType, | |
| 767 | is_reified: bool, | |
| 768 | ) SemaError!void { | |
| 769 | const pt = sema.pt; | |
| 770 | const zcu = pt.zcu; | |
| 771 | const comp = zcu.comp; | |
| 772 | const gpa = comp.gpa; | |
| 773 | const io = comp.io; | |
| 774 | const ip = &zcu.intern_pool; | |
| 775 | switch (union_obj.packed_backing_mode) { | |
| 776 | .explicit => { | |
| 777 | const backing_int_type: Type = .fromInterned(union_obj.packed_backing_int_type); | |
| 778 | const backing_int_bits = backing_int_type.intInfo(zcu).bits; | |
| 779 | for (union_obj.field_types.get(ip), 0..) |field_type_ip, field_idx| { | |
| 780 | const field_type: Type = .fromInterned(field_type_ip); | |
| 781 | const field_bits = field_type.bitSize(zcu); | |
| 782 | if (field_bits != backing_int_bits) return sema.failWithOwnedErrorMsg(block, msg: { | |
| 783 | const field_ty_src: LazySrcLoc = .{ | |
| 784 | .base_node_inst = union_obj.zir_index, | |
| 785 | .offset = if (is_reified) | |
| 786 | .nodeOffset(.zero) | |
| 787 | else | |
| 788 | .{ .container_field_type = @intCast(field_idx) }, | |
| 789 | }; | |
| 790 | const msg = try sema.errMsg(field_ty_src, "field bit width does not match backing integer", .{}); | |
| 791 | errdefer msg.destroy(gpa); | |
| 792 | try sema.errNote(field_ty_src, msg, "field type '{f}' has bit width '{d}'", .{ field_type.fmt(pt), field_bits }); | |
| 793 | try sema.errNote(field_ty_src, msg, "backing integer '{f}' has bit width '{d}'", .{ backing_int_type.fmt(pt), backing_int_bits }); | |
| 794 | try sema.errNote(field_ty_src, msg, "all fields in a packed union must have the same bit width", .{}); | |
| 795 | break :msg msg; | |
| 796 | }); | |
| 797 | } | |
| 798 | }, | |
| 799 | .auto => switch (union_obj.field_types.len) { | |
| 800 | 0 => ip.resolvePackedUnionBackingInt(io, union_ty.toIntern(), .u0_type), | |
| 801 | else => { | |
| 802 | const field_types = union_obj.field_types.get(ip); | |
| 803 | const first_field_type: Type = .fromInterned(field_types[0]); | |
| 804 | const first_field_bits = first_field_type.bitSize(zcu); | |
| 805 | for (field_types[1..], 1..) |field_type_ip, field_idx| { | |
| 806 | const field_type: Type = .fromInterned(field_type_ip); | |
| 807 | const field_bits = field_type.bitSize(zcu); | |
| 808 | if (field_bits != first_field_bits) return sema.failWithOwnedErrorMsg(block, msg: { | |
| 809 | const first_field_ty_src: LazySrcLoc = .{ | |
| 810 | .base_node_inst = union_obj.zir_index, | |
| 811 | .offset = if (is_reified) | |
| 812 | .nodeOffset(.zero) | |
| 813 | else | |
| 814 | .{ .container_field_type = 0 }, | |
| 815 | }; | |
| 816 | const field_ty_src: LazySrcLoc = .{ | |
| 817 | .base_node_inst = union_obj.zir_index, | |
| 818 | .offset = if (is_reified) | |
| 819 | .nodeOffset(.zero) | |
| 820 | else | |
| 821 | .{ .container_field_type = @intCast(field_idx) }, | |
| 822 | }; | |
| 823 | const msg = try sema.errMsg(field_ty_src, "field bit width does not match earlier field", .{}); | |
| 824 | errdefer msg.destroy(gpa); | |
| 825 | try sema.errNote(field_ty_src, msg, "field type '{f}' has bit width '{d}'", .{ field_type.fmt(pt), field_bits }); | |
| 826 | try sema.errNote(first_field_ty_src, msg, "other field type '{f}' has bit width '{d}'", .{ first_field_type.fmt(pt), first_field_bits }); | |
| 827 | try sema.errNote(field_ty_src, msg, "all fields in a packed union must have the same bit width", .{}); | |
| 828 | break :msg msg; | |
| 829 | }); | |
| 830 | } | |
| 831 | const backing_int_bits = std.math.cast(u16, first_field_bits) orelse return sema.fail( | |
| 832 | block, | |
| 833 | block.nodeOffset(.zero), | |
| 834 | "packed union bit width '{d}' exceeds maximum bit width of 65535", | |
| 835 | .{first_field_bits}, | |
| 836 | ); | |
| 837 | const backing_int_type = try pt.intType(.unsigned, backing_int_bits); | |
| 838 | ip.resolvePackedUnionBackingInt(io, union_ty.toIntern(), backing_int_type.toIntern()); | |
| 839 | }, | |
| 840 | }, | |
| 841 | } | |
| 842 | } | |
| 843 | ||
| 844 | /// Asserts that `enum_ty` is an enum and that `sema.owner` is that type. | |
| 845 | /// This function *does* register the `src_hash` dependency on the enum. | |
| 846 | pub fn resolveEnumValues(sema: *Sema, enum_ty: Type) CompileError!void { | |
| 847 | const pt = sema.pt; | |
| 848 | const zcu = pt.zcu; | |
| 849 | const comp = zcu.comp; | |
| 850 | const gpa = comp.gpa; | |
| 851 | const ip = &zcu.intern_pool; | |
| 852 | ||
| 853 | assert(sema.owner.unwrap().type_inits == enum_ty.toIntern()); | |
| 854 | ||
| 855 | const enum_obj = ip.loadEnumType(enum_ty.toIntern()); | |
| 856 | ||
| 857 | // We'll populate this map. | |
| 858 | const field_value_map = enum_obj.field_value_map.unwrap() orelse { | |
| 859 | // The enum has an automatically generated tag and is auto-numbered. We know that we have | |
| 860 | // generated a suitably large type in `analyzeEnumDecl`, so we have no work to do. | |
| 861 | return; | |
| 862 | }; | |
| 863 | ||
| 864 | const maybe_parent_union_obj: ?InternPool.LoadedUnionType = un: { | |
| 865 | if (enum_obj.owner_union == .none) break :un null; | |
| 866 | break :un ip.loadUnionType(enum_obj.owner_union); | |
| 867 | }; | |
| 868 | const tracked_inst = enum_obj.zir_index.unwrap() orelse maybe_parent_union_obj.?.zir_index; | |
| 869 | const zir_index = tracked_inst.resolve(ip).?; | |
| 870 | ||
| 871 | try sema.declareDependency(.{ .src_hash = tracked_inst }); | |
| 872 | ||
| 873 | var block: Block = .{ | |
| 874 | .parent = null, | |
| 875 | .sema = sema, | |
| 876 | .namespace = enum_obj.namespace, | |
| 877 | .instructions = .{}, | |
| 878 | .inlining = null, | |
| 879 | .comptime_reason = undefined, // always set before using `block` | |
| 880 | .src_base_inst = tracked_inst, | |
| 881 | .type_name_ctx = enum_obj.name, | |
| 882 | }; | |
| 883 | defer assert(block.instructions.items.len == 0); | |
| 884 | ||
| 885 | const int_tag_ty: Type = .fromInterned(enum_obj.int_tag_type); | |
| 886 | ||
| 887 | // Map the enum (or union) decl instruction to provide the tag type as the result type | |
| 888 | try sema.inst_map.ensureSpaceForInstructions(gpa, &.{zir_index}); | |
| 889 | sema.inst_map.putAssumeCapacity(zir_index, .fromIntern(int_tag_ty.toIntern())); | |
| 890 | defer assert(sema.inst_map.remove(zir_index)); | |
| 891 | ||
| 892 | // First, populate any explicitly provided values. This is the part that actually depends on | |
| 893 | // the ZIR, and hence depends on whether this is a declared or generated enum. If any explicit | |
| 894 | // value is invalid, we'll emit an error here. | |
| 895 | if (maybe_parent_union_obj) |union_obj| { | |
| 896 | const zir_union = sema.code.getUnionDecl(zir_index); | |
| 897 | var field_it = zir_union.iterateFields(); | |
| 898 | while (field_it.next()) |zir_field| { | |
| 899 | const field_val_src: LazySrcLoc = .{ | |
| 900 | .base_node_inst = union_obj.zir_index, | |
| 901 | .offset = .{ .container_field_value = zir_field.idx }, | |
| 902 | }; | |
| 903 | block.comptime_reason = .{ .reason = .{ | |
| 904 | .src = field_val_src, | |
| 905 | .r = .{ .simple = .enum_field_values }, | |
| 906 | } }; | |
| 907 | const value_body = zir_field.value_body orelse { | |
| 908 | enum_obj.field_values.get(ip)[zir_field.idx] = .none; | |
| 909 | continue; | |
| 910 | }; | |
| 911 | const uncoerced = try sema.resolveInlineBody(&block, value_body, zir_index); | |
| 912 | const coerced = try sema.coerce(&block, int_tag_ty, uncoerced, field_val_src); | |
| 913 | const val = try sema.resolveConstValue(&block, field_val_src, coerced, null); | |
| 914 | enum_obj.field_values.get(ip)[zir_field.idx] = val.toIntern(); | |
| 915 | } | |
| 916 | } else { | |
| 917 | const zir_enum = sema.code.getEnumDecl(zir_index); | |
| 918 | var field_it = zir_enum.iterateFields(); | |
| 919 | while (field_it.next()) |zir_field| { | |
| 920 | const field_val_src: LazySrcLoc = .{ | |
| 921 | .base_node_inst = enum_obj.zir_index.unwrap().?, | |
| 922 | .offset = .{ .container_field_value = zir_field.idx }, | |
| 923 | }; | |
| 924 | block.comptime_reason = .{ .reason = .{ | |
| 925 | .src = field_val_src, | |
| 926 | .r = .{ .simple = .enum_field_values }, | |
| 927 | } }; | |
| 928 | const value_body = zir_field.value_body orelse { | |
| 929 | enum_obj.field_values.get(ip)[zir_field.idx] = .none; | |
| 930 | continue; | |
| 931 | }; | |
| 932 | const uncoerced = try sema.resolveInlineBody(&block, value_body, zir_index); | |
| 933 | const coerced = try sema.coerce(&block, int_tag_ty, uncoerced, field_val_src); | |
| 934 | const val = try sema.resolveConstDefinedValue(&block, field_val_src, coerced, null); | |
| 935 | enum_obj.field_values.get(ip)[zir_field.idx] = val.toIntern(); | |
| 936 | } | |
| 937 | } | |
| 938 | ||
| 939 | // Explicit values are set. Now we'll go through the whole array and figure out the final | |
| 940 | // field values. This is also where we'll detect duplicates. | |
| 941 | ||
| 942 | for (0..enum_obj.field_names.len) |field_idx| { | |
| 943 | const field_val_src: LazySrcLoc = .{ | |
| 944 | .base_node_inst = tracked_inst, | |
| 945 | .offset = .{ .container_field_value = @intCast(field_idx) }, | |
| 946 | }; | |
| 947 | // If the field value was not specified, compute the implicit value. | |
| 948 | const field_val = val: { | |
| 949 | const explicit_val = enum_obj.field_values.get(ip)[field_idx]; | |
| 950 | if (explicit_val != .none) break :val explicit_val; | |
| 951 | if (field_idx == 0) { | |
| 952 | // Implicit value is 0, which is valid for every integer type. | |
| 953 | const val = (try pt.intValue(int_tag_ty, 0)).toIntern(); | |
| 954 | enum_obj.field_values.get(ip)[field_idx] = val; | |
| 955 | break :val val; | |
| 956 | } | |
| 957 | // Implicit non-initial value: take the previous field value and add one. | |
| 958 | const prev_field_val: Value = .fromInterned(enum_obj.field_values.get(ip)[field_idx - 1]); | |
| 959 | const result = try arith.incrementDefinedInt(sema, int_tag_ty, prev_field_val); | |
| 960 | if (result.overflow) return sema.fail( | |
| 961 | &block, | |
| 962 | field_val_src, | |
| 963 | "enum tag value '{f}' too large for type '{f}'", | |
| 964 | .{ result.val.fmtValueSema(pt, sema), int_tag_ty.fmt(pt) }, | |
| 965 | ); | |
| 966 | const val = result.val.toIntern(); | |
| 967 | enum_obj.field_values.get(ip)[field_idx] = val; | |
| 968 | break :val val; | |
| 969 | }; | |
| 970 | const adapter: InternPool.Index.Adapter = .{ .indexes = enum_obj.field_values.get(ip)[0..field_idx] }; | |
| 971 | const gop = field_value_map.get(ip).getOrPutAssumeCapacityAdapted(field_val, adapter); | |
| 972 | if (!gop.found_existing) continue; | |
| 973 | const prev_field_val_src: LazySrcLoc = .{ | |
| 974 | .base_node_inst = tracked_inst, | |
| 975 | .offset = .{ .container_field_value = @intCast(gop.index) }, | |
| 976 | }; | |
| 977 | return sema.failWithOwnedErrorMsg(&block, msg: { | |
| 978 | const msg = try sema.errMsg(field_val_src, "enum tag value '{f}' already taken", .{ | |
| 979 | Value.fromInterned(field_val).fmtValueSema(pt, sema), | |
| 980 | }); | |
| 981 | errdefer msg.destroy(gpa); | |
| 982 | try sema.errNote(prev_field_val_src, msg, "previous occurrence here", .{}); | |
| 983 | break :msg msg; | |
| 984 | }); | |
| 985 | } | |
| 986 | ||
| 987 | if (enum_obj.nonexhaustive and int_tag_ty.toIntern() != .comptime_int_type) { | |
| 988 | const fields_len = enum_obj.field_names.len; | |
| 989 | if (fields_len >= 1 and std.math.log2_int(u64, fields_len) == int_tag_ty.bitSize(zcu)) { | |
| 990 | return sema.fail(&block, block.nodeOffset(.zero), "non-exhaustive enum specifies every value", .{}); | |
| 991 | } | |
| 992 | } | |
| 993 | } |
src/Type.zig+883-2010| ... | ... | @@ -12,12 +12,10 @@ const Target = std.Target; |
| 12 | 12 | const Zcu = @import("Zcu.zig"); |
| 13 | 13 | const log = std.log.scoped(.Type); |
| 14 | 14 | const target_util = @import("target.zig"); |
| 15 | const Sema = @import("Sema.zig"); | |
| 16 | 15 | const InternPool = @import("InternPool.zig"); |
| 17 | 16 | const Alignment = InternPool.Alignment; |
| 18 | 17 | const Zir = std.zig.Zir; |
| 19 | 18 | const Type = @This(); |
| 20 | const SemaError = Zcu.SemaError; | |
| 21 | 19 | |
| 22 | 20 | ip_index: InternPool.Index, |
| 23 | 21 | |
| ... | ... | @@ -25,16 +23,6 @@ pub fn zigTypeTag(ty: Type, zcu: *const Zcu) std.builtin.TypeId { |
| 25 | 23 | return zcu.intern_pool.zigTypeTag(ty.toIntern()); |
| 26 | 24 | } |
| 27 | 25 | |
| 28 | pub fn baseZigTypeTag(self: Type, mod: *Zcu) std.builtin.TypeId { | |
| 29 | return switch (self.zigTypeTag(mod)) { | |
| 30 | .error_union => self.errorUnionPayload(mod).baseZigTypeTag(mod), | |
| 31 | .optional => { | |
| 32 | return self.optionalChild(mod).baseZigTypeTag(mod); | |
| 33 | }, | |
| 34 | else => |t| t, | |
| 35 | }; | |
| 36 | } | |
| 37 | ||
| 38 | 26 | /// Asserts the type is resolved. |
| 39 | 27 | pub fn isSelfComparable(ty: Type, zcu: *const Zcu, is_equality_cmp: bool) bool { |
| 40 | 28 | return switch (ty.zigTypeTag(zcu)) { |
| ... | ... | @@ -44,7 +32,7 @@ pub fn isSelfComparable(ty: Type, zcu: *const Zcu, is_equality_cmp: bool) bool { |
| 44 | 32 | .comptime_int, |
| 45 | 33 | => true, |
| 46 | 34 | |
| 47 | .vector => ty.elemType2(zcu).isSelfComparable(zcu, is_equality_cmp), | |
| 35 | .vector => ty.childType(zcu).isSelfComparable(zcu, is_equality_cmp), | |
| 48 | 36 | |
| 49 | 37 | .bool, |
| 50 | 38 | .type, |
| ... | ... | @@ -121,11 +109,7 @@ pub fn eql(a: Type, b: Type, zcu: *const Zcu) bool { |
| 121 | 109 | return a.toIntern() == b.toIntern(); |
| 122 | 110 | } |
| 123 | 111 | |
| 124 | pub fn format(ty: Type, writer: *std.Io.Writer) !void { | |
| 125 | _ = ty; | |
| 126 | _ = writer; | |
| 127 | @compileError("do not format types directly; use either ty.fmtDebug() or ty.fmt()"); | |
| 128 | } | |
| 112 | pub const format = @compileError("do not format types directly; use either ty.fmtDebug() or ty.fmt()"); | |
| 129 | 113 | |
| 130 | 114 | pub const Formatter = std.fmt.Alt(Format, Format.default); |
| 131 | 115 | |
| ... | ... | @@ -440,31 +424,7 @@ pub fn toIntern(ty: Type) InternPool.Index { |
| 440 | 424 | } |
| 441 | 425 | |
| 442 | 426 | pub fn toValue(self: Type) Value { |
| 443 | return Value.fromInterned(self.toIntern()); | |
| 444 | } | |
| 445 | ||
| 446 | const RuntimeBitsError = SemaError || error{NeedLazy}; | |
| 447 | ||
| 448 | pub fn hasRuntimeBits(ty: Type, zcu: *const Zcu) bool { | |
| 449 | return hasRuntimeBitsInner(ty, false, .eager, zcu, {}) catch unreachable; | |
| 450 | } | |
| 451 | ||
| 452 | pub fn hasRuntimeBitsSema(ty: Type, pt: Zcu.PerThread) SemaError!bool { | |
| 453 | return hasRuntimeBitsInner(ty, false, .sema, pt.zcu, pt.tid) catch |err| switch (err) { | |
| 454 | error.NeedLazy => unreachable, // this would require a resolve strat of lazy | |
| 455 | else => |e| return e, | |
| 456 | }; | |
| 457 | } | |
| 458 | ||
| 459 | pub fn hasRuntimeBitsIgnoreComptime(ty: Type, zcu: *const Zcu) bool { | |
| 460 | return hasRuntimeBitsInner(ty, true, .eager, zcu, {}) catch unreachable; | |
| 461 | } | |
| 462 | ||
| 463 | pub fn hasRuntimeBitsIgnoreComptimeSema(ty: Type, pt: Zcu.PerThread) SemaError!bool { | |
| 464 | return hasRuntimeBitsInner(ty, true, .sema, pt.zcu, pt.tid) catch |err| switch (err) { | |
| 465 | error.NeedLazy => unreachable, // this would require a resolve strat of lazy | |
| 466 | else => |e| return e, | |
| 467 | }; | |
| 427 | return .fromInterned(self.toIntern()); | |
| 468 | 428 | } |
| 469 | 429 | |
| 470 | 430 | /// true if and only if the type takes up space in memory at runtime. |
| ... | ... | @@ -476,205 +436,126 @@ pub fn hasRuntimeBitsIgnoreComptimeSema(ty: Type, pt: Zcu.PerThread) SemaError!b |
| 476 | 436 | /// * the type has only one possible value, making its ABI size 0. |
| 477 | 437 | /// - an enum with an explicit tag type has the ABI size of the integer tag type, |
| 478 | 438 | /// making it one-possible-value only if the integer tag type has 0 bits. |
| 479 | /// When `ignore_comptime_only` is true, then types that are comptime-only | |
| 480 | /// may return false positives. | |
| 481 | pub fn hasRuntimeBitsInner( | |
| 482 | ty: Type, | |
| 483 | ignore_comptime_only: bool, | |
| 484 | comptime strat: ResolveStratLazy, | |
| 485 | zcu: strat.ZcuPtr(), | |
| 486 | tid: strat.Tid(), | |
| 487 | ) RuntimeBitsError!bool { | |
| 439 | pub fn hasRuntimeBits(ty: Type, zcu: *const Zcu) bool { | |
| 488 | 440 | const ip = &zcu.intern_pool; |
| 489 | const io = zcu.comp.io; | |
| 490 | return switch (ty.toIntern()) { | |
| 491 | .empty_tuple_type => false, | |
| 492 | else => switch (ip.indexToKey(ty.toIntern())) { | |
| 493 | .int_type => |int_type| int_type.bits != 0, | |
| 494 | .ptr_type => { | |
| 495 | // Pointers to zero-bit types still have a runtime address; however, pointers | |
| 496 | // to comptime-only types do not, with the exception of function pointers. | |
| 497 | if (ignore_comptime_only) return true; | |
| 498 | return switch (strat) { | |
| 499 | .sema => { | |
| 500 | const pt = strat.pt(zcu, tid); | |
| 501 | return !try ty.comptimeOnlySema(pt); | |
| 502 | }, | |
| 503 | .eager => !ty.comptimeOnly(zcu), | |
| 504 | .lazy => error.NeedLazy, | |
| 505 | }; | |
| 506 | }, | |
| 507 | .anyframe_type => true, | |
| 508 | .array_type => |array_type| return array_type.lenIncludingSentinel() > 0 and | |
| 509 | try Type.fromInterned(array_type.child).hasRuntimeBitsInner(ignore_comptime_only, strat, zcu, tid), | |
| 510 | .vector_type => |vector_type| return vector_type.len > 0 and | |
| 511 | try Type.fromInterned(vector_type.child).hasRuntimeBitsInner(ignore_comptime_only, strat, zcu, tid), | |
| 512 | .opt_type => |child| { | |
| 513 | const child_ty = Type.fromInterned(child); | |
| 514 | if (child_ty.isNoReturn(zcu)) { | |
| 515 | // Then the optional is comptime-known to be null. | |
| 516 | return false; | |
| 517 | } | |
| 518 | if (ignore_comptime_only) return true; | |
| 519 | return switch (strat) { | |
| 520 | .sema => !try child_ty.comptimeOnlyInner(.sema, zcu, tid), | |
| 521 | .eager => !child_ty.comptimeOnly(zcu), | |
| 522 | .lazy => error.NeedLazy, | |
| 523 | }; | |
| 524 | }, | |
| 525 | .error_union_type, | |
| 526 | .error_set_type, | |
| 527 | .inferred_error_set_type, | |
| 528 | => true, | |
| 529 | ||
| 530 | // These are function *bodies*, not pointers. | |
| 531 | // They return false here because they are comptime-only types. | |
| 532 | // Special exceptions have to be made when emitting functions due to | |
| 533 | // this returning false. | |
| 534 | .func_type => false, | |
| 535 | ||
| 536 | .simple_type => |t| switch (t) { | |
| 537 | .f16, | |
| 538 | .f32, | |
| 539 | .f64, | |
| 540 | .f80, | |
| 541 | .f128, | |
| 542 | .usize, | |
| 543 | .isize, | |
| 544 | .c_char, | |
| 545 | .c_short, | |
| 546 | .c_ushort, | |
| 547 | .c_int, | |
| 548 | .c_uint, | |
| 549 | .c_long, | |
| 550 | .c_ulong, | |
| 551 | .c_longlong, | |
| 552 | .c_ulonglong, | |
| 553 | .c_longdouble, | |
| 554 | .bool, | |
| 555 | .anyerror, | |
| 556 | .adhoc_inferred_error_set, | |
| 557 | .anyopaque, | |
| 558 | => true, | |
| 441 | return switch (ip.indexToKey(ty.toIntern())) { | |
| 442 | .int_type => |int_type| int_type.bits != 0, | |
| 443 | .ptr_type => true, | |
| 444 | .anyframe_type => true, | |
| 445 | .array_type => |array_type| array_type.lenIncludingSentinel() > 0 and | |
| 446 | Type.fromInterned(array_type.child).hasRuntimeBits(zcu), | |
| 447 | .vector_type => |vector_type| vector_type.len > 0 and | |
| 448 | Type.fromInterned(vector_type.child).hasRuntimeBits(zcu), | |
| 449 | .opt_type => |child| !Type.fromInterned(child).isNoReturn(zcu), | |
| 559 | 450 | |
| 560 | // These are false because they are comptime-only types. | |
| 561 | .void, | |
| 562 | .type, | |
| 563 | .comptime_int, | |
| 564 | .comptime_float, | |
| 565 | .noreturn, | |
| 566 | .null, | |
| 567 | .undefined, | |
| 568 | .enum_literal, | |
| 569 | => false, | |
| 451 | .error_union_type, | |
| 452 | .error_set_type, | |
| 453 | .inferred_error_set_type, | |
| 454 | => true, | |
| 570 | 455 | |
| 571 | .generic_poison => unreachable, | |
| 572 | }, | |
| 573 | .struct_type => { | |
| 574 | const struct_type = ip.loadStructType(ty.toIntern()); | |
| 575 | if (strat != .eager and struct_type.assumeRuntimeBitsIfFieldTypesWip(ip, io)) { | |
| 576 | // In this case, we guess that hasRuntimeBits() for this type is true, | |
| 577 | // and then later if our guess was incorrect, we emit a compile error. | |
| 578 | return true; | |
| 579 | } | |
| 580 | switch (strat) { | |
| 581 | .sema => try ty.resolveFields(strat.pt(zcu, tid)), | |
| 582 | .eager => assert(struct_type.haveFieldTypes(ip)), | |
| 583 | .lazy => if (!struct_type.haveFieldTypes(ip)) return error.NeedLazy, | |
| 584 | } | |
| 585 | for (0..struct_type.field_types.len) |i| { | |
| 586 | if (struct_type.comptime_bits.getBit(ip, i)) continue; | |
| 587 | const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]); | |
| 588 | if (try field_ty.hasRuntimeBitsInner(ignore_comptime_only, strat, zcu, tid)) | |
| 589 | return true; | |
| 590 | } else { | |
| 591 | return false; | |
| 592 | } | |
| 593 | }, | |
| 594 | .tuple_type => |tuple| { | |
| 595 | for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| { | |
| 596 | if (val != .none) continue; // comptime field | |
| 597 | if (try Type.fromInterned(field_ty).hasRuntimeBitsInner( | |
| 598 | ignore_comptime_only, | |
| 599 | strat, | |
| 600 | zcu, | |
| 601 | tid, | |
| 602 | )) return true; | |
| 603 | } | |
| 604 | return false; | |
| 605 | }, | |
| 456 | // These are function *bodies*, not pointers. | |
| 457 | // They return false here because they are comptime-only types. | |
| 458 | // Special exceptions have to be made when emitting functions due to | |
| 459 | // this returning false. | |
| 460 | .func_type => false, | |
| 606 | 461 | |
| 607 | .union_type => { | |
| 608 | const union_type = ip.loadUnionType(ty.toIntern()); | |
| 609 | const union_flags = union_type.flagsUnordered(ip); | |
| 610 | switch (union_flags.runtime_tag) { | |
| 611 | .none => if (strat != .eager) { | |
| 612 | // In this case, we guess that hasRuntimeBits() for this type is true, | |
| 613 | // and then later if our guess was incorrect, we emit a compile error. | |
| 614 | if (union_type.assumeRuntimeBitsIfFieldTypesWip(ip, io)) return true; | |
| 615 | }, | |
| 616 | .safety, .tagged => {}, | |
| 617 | } | |
| 618 | switch (strat) { | |
| 619 | .sema => try ty.resolveFields(strat.pt(zcu, tid)), | |
| 620 | .eager => assert(union_flags.status.haveFieldTypes()), | |
| 621 | .lazy => if (!union_flags.status.haveFieldTypes()) | |
| 622 | return error.NeedLazy, | |
| 623 | } | |
| 624 | switch (union_flags.runtime_tag) { | |
| 625 | .none => {}, | |
| 626 | .safety, .tagged => { | |
| 627 | const tag_ty = union_type.tagTypeUnordered(ip); | |
| 628 | assert(tag_ty != .none); // tag_ty should have been resolved above | |
| 629 | if (try Type.fromInterned(tag_ty).hasRuntimeBitsInner( | |
| 630 | ignore_comptime_only, | |
| 631 | strat, | |
| 632 | zcu, | |
| 633 | tid, | |
| 634 | )) { | |
| 635 | return true; | |
| 636 | } | |
| 637 | }, | |
| 638 | } | |
| 639 | for (0..union_type.field_types.len) |field_index| { | |
| 640 | const field_ty = Type.fromInterned(union_type.field_types.get(ip)[field_index]); | |
| 641 | if (try field_ty.hasRuntimeBitsInner(ignore_comptime_only, strat, zcu, tid)) | |
| 642 | return true; | |
| 643 | } else { | |
| 644 | return false; | |
| 645 | } | |
| 646 | }, | |
| 462 | .simple_type => |t| switch (t) { | |
| 463 | .f16, | |
| 464 | .f32, | |
| 465 | .f64, | |
| 466 | .f80, | |
| 467 | .f128, | |
| 468 | .usize, | |
| 469 | .isize, | |
| 470 | .c_char, | |
| 471 | .c_short, | |
| 472 | .c_ushort, | |
| 473 | .c_int, | |
| 474 | .c_uint, | |
| 475 | .c_long, | |
| 476 | .c_ulong, | |
| 477 | .c_longlong, | |
| 478 | .c_ulonglong, | |
| 479 | .c_longdouble, | |
| 480 | .bool, | |
| 481 | .anyerror, | |
| 482 | .adhoc_inferred_error_set, | |
| 483 | .anyopaque, | |
| 484 | => true, | |
| 647 | 485 | |
| 648 | .opaque_type => true, | |
| 649 | .enum_type => Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty).hasRuntimeBitsInner( | |
| 650 | ignore_comptime_only, | |
| 651 | strat, | |
| 652 | zcu, | |
| 653 | tid, | |
| 654 | ), | |
| 486 | .void, | |
| 487 | .noreturn, | |
| 488 | => false, | |
| 655 | 489 | |
| 656 | // values, not types | |
| 657 | .undef, | |
| 658 | .simple_value, | |
| 659 | .variable, | |
| 660 | .@"extern", | |
| 661 | .func, | |
| 662 | .int, | |
| 663 | .err, | |
| 664 | .error_union, | |
| 490 | // primitive comptime-only types | |
| 491 | .type, | |
| 492 | .comptime_int, | |
| 493 | .comptime_float, | |
| 494 | .null, | |
| 495 | .undefined, | |
| 665 | 496 | .enum_literal, |
| 666 | .enum_tag, | |
| 667 | .empty_enum_value, | |
| 668 | .float, | |
| 669 | .ptr, | |
| 670 | .slice, | |
| 671 | .opt, | |
| 672 | .aggregate, | |
| 673 | .un, | |
| 674 | // memoization, not types | |
| 675 | .memoized_call, | |
| 676 | => unreachable, | |
| 497 | => false, | |
| 498 | ||
| 499 | .generic_poison => unreachable, | |
| 677 | 500 | }, |
| 501 | .struct_type => { | |
| 502 | // TODO MLUGG: memoize this state when resolving struct? | |
| 503 | const struct_obj = ip.loadStructType(ty.toIntern()); | |
| 504 | for (struct_obj.field_types.get(ip), 0..) |field_ty_ip, field_idx| { | |
| 505 | if (struct_obj.field_is_comptime_bits.get(ip, field_idx)) continue; | |
| 506 | const field_ty: Type = .fromInterned(field_ty_ip); | |
| 507 | if (field_ty.hasRuntimeBits(zcu)) return true; | |
| 508 | } | |
| 509 | return false; | |
| 510 | }, | |
| 511 | .tuple_type => |tuple| { | |
| 512 | for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| { | |
| 513 | if (val != .none) continue; // comptime field | |
| 514 | if (Type.fromInterned(field_ty).hasRuntimeBits(zcu)) return true; | |
| 515 | } | |
| 516 | return false; | |
| 517 | }, | |
| 518 | .union_type => { | |
| 519 | // TODO MLUGG: memoize this state when resolving union? | |
| 520 | const union_obj = ip.loadUnionType(ty.toIntern()); | |
| 521 | switch (union_obj.runtime_tag) { | |
| 522 | .none => {}, | |
| 523 | .safety, .tagged => { | |
| 524 | if (Type.fromInterned(union_obj.enum_tag_type).hasRuntimeBits(zcu)) return true; | |
| 525 | }, | |
| 526 | } | |
| 527 | for (union_obj.field_types.get(ip)) |field_ty_ip| { | |
| 528 | const field_ty: Type = .fromInterned(field_ty_ip); | |
| 529 | if (field_ty.hasRuntimeBits(zcu)) return true; | |
| 530 | } | |
| 531 | return false; | |
| 532 | }, | |
| 533 | ||
| 534 | // MLUGG TODO: i think this can go away and the assert move to the defer? | |
| 535 | .opaque_type => true, | |
| 536 | .enum_type => Type.fromInterned(ip.loadEnumType(ty.toIntern()).int_tag_type).hasRuntimeBits(zcu), | |
| 537 | ||
| 538 | // values, not types | |
| 539 | .undef, | |
| 540 | .simple_value, | |
| 541 | .variable, | |
| 542 | .@"extern", | |
| 543 | .func, | |
| 544 | .int, | |
| 545 | .err, | |
| 546 | .error_union, | |
| 547 | .enum_literal, | |
| 548 | .enum_tag, | |
| 549 | .empty_enum_value, | |
| 550 | .float, | |
| 551 | .ptr, | |
| 552 | .slice, | |
| 553 | .opt, | |
| 554 | .aggregate, | |
| 555 | .un, | |
| 556 | // memoization, not types | |
| 557 | .memoized_call, | |
| 558 | => unreachable, | |
| 678 | 559 | }; |
| 679 | 560 | } |
| 680 | 561 | |
| ... | ... | @@ -739,16 +620,15 @@ pub fn hasWellDefinedLayout(ty: Type, zcu: *const Zcu) bool { |
| 739 | 620 | }, |
| 740 | 621 | .struct_type => ip.loadStructType(ty.toIntern()).layout != .auto, |
| 741 | 622 | .union_type => { |
| 742 | const union_type = ip.loadUnionType(ty.toIntern()); | |
| 743 | return switch (union_type.flagsUnordered(ip).runtime_tag) { | |
| 744 | .none, .safety => union_type.flagsUnordered(ip).layout != .auto, | |
| 623 | const union_obj = ip.loadUnionType(ty.toIntern()); | |
| 624 | if (union_obj.layout == .auto) return false; | |
| 625 | return switch (union_obj.runtime_tag) { | |
| 626 | .none => true, | |
| 745 | 627 | .tagged => false, |
| 628 | .safety => unreachable, // well-defined layout can't have a safety tag | |
| 746 | 629 | }; |
| 747 | 630 | }, |
| 748 | .enum_type => switch (ip.loadEnumType(ty.toIntern()).tag_mode) { | |
| 749 | .auto => false, | |
| 750 | .explicit, .nonexhaustive => true, | |
| 751 | }, | |
| 631 | .enum_type => ip.loadEnumType(ty.toIntern()).int_tag_is_explicit, | |
| 752 | 632 | |
| 753 | 633 | // values, not types |
| 754 | 634 | .undef, |
| ... | ... | @@ -774,28 +654,20 @@ pub fn hasWellDefinedLayout(ty: Type, zcu: *const Zcu) bool { |
| 774 | 654 | }; |
| 775 | 655 | } |
| 776 | 656 | |
| 777 | pub fn fnHasRuntimeBits(ty: Type, zcu: *Zcu) bool { | |
| 778 | return ty.fnHasRuntimeBitsInner(.normal, zcu, {}) catch unreachable; | |
| 779 | } | |
| 780 | ||
| 781 | pub fn fnHasRuntimeBitsSema(ty: Type, pt: Zcu.PerThread) SemaError!bool { | |
| 782 | return try ty.fnHasRuntimeBitsInner(.sema, pt.zcu, pt.tid); | |
| 783 | } | |
| 784 | ||
| 785 | 657 | /// Determines whether a function type has runtime bits, i.e. whether a |
| 786 | 658 | /// function with this type can exist at runtime. |
| 787 | 659 | /// Asserts that `ty` is a function type. |
| 788 | pub fn fnHasRuntimeBitsInner( | |
| 789 | ty: Type, | |
| 790 | comptime strat: ResolveStrat, | |
| 791 | zcu: strat.ZcuPtr(), | |
| 792 | tid: strat.Tid(), | |
| 793 | ) SemaError!bool { | |
| 794 | const fn_info = zcu.typeToFunc(ty).?; | |
| 795 | if (fn_info.is_generic) return false; | |
| 796 | if (fn_info.is_var_args) return true; | |
| 660 | pub fn fnHasRuntimeBits(fn_ty: Type, zcu: *Zcu) bool { | |
| 661 | const fn_info = zcu.typeToFunc(fn_ty).?; | |
| 662 | if (fn_info.comptime_bits != 0) return false; | |
| 663 | for (fn_info.param_types.get(&zcu.intern_pool)) |param_ty| { | |
| 664 | if (param_ty == .generic_poison_type) return false; | |
| 665 | if (Type.fromInterned(param_ty).comptimeOnly(zcu)) return false; | |
| 666 | } | |
| 667 | if (fn_info.return_type == .generic_poison_type) return false; | |
| 668 | if (Type.fromInterned(fn_info.return_type).comptimeOnly(zcu)) return false; | |
| 797 | 669 | if (fn_info.cc == .@"inline") return false; |
| 798 | return !try Type.fromInterned(fn_info.return_type).comptimeOnlyInner(strat, zcu, tid); | |
| 670 | return true; | |
| 799 | 671 | } |
| 800 | 672 | |
| 801 | 673 | pub fn isFnOrHasRuntimeBits(ty: Type, zcu: *Zcu) bool { |
| ... | ... | @@ -806,10 +678,11 @@ pub fn isFnOrHasRuntimeBits(ty: Type, zcu: *Zcu) bool { |
| 806 | 678 | } |
| 807 | 679 | |
| 808 | 680 | /// Same as `isFnOrHasRuntimeBits` but comptime-only types may return a false positive. |
| 681 | /// MLUGG TODO: this function is a bit silly now... | |
| 809 | 682 | pub fn isFnOrHasRuntimeBitsIgnoreComptime(ty: Type, zcu: *Zcu) bool { |
| 810 | 683 | return switch (ty.zigTypeTag(zcu)) { |
| 811 | 684 | .@"fn" => true, |
| 812 | else => return ty.hasRuntimeBitsIgnoreComptime(zcu), | |
| 685 | else => return ty.hasRuntimeBits(zcu), | |
| 813 | 686 | }; |
| 814 | 687 | } |
| 815 | 688 | |
| ... | ... | @@ -818,29 +691,15 @@ pub fn isNoReturn(ty: Type, zcu: *const Zcu) bool { |
| 818 | 691 | } |
| 819 | 692 | |
| 820 | 693 | /// Never returns `none`. Asserts that all necessary type resolution is already done. |
| 821 | pub fn ptrAlignment(ty: Type, zcu: *Zcu) Alignment { | |
| 822 | return ptrAlignmentInner(ty, .normal, zcu, {}) catch unreachable; | |
| 823 | } | |
| 824 | ||
| 825 | pub fn ptrAlignmentSema(ty: Type, pt: Zcu.PerThread) SemaError!Alignment { | |
| 826 | return try ty.ptrAlignmentInner(.sema, pt.zcu, pt.tid); | |
| 827 | } | |
| 828 | ||
| 829 | pub fn ptrAlignmentInner( | |
| 830 | ty: Type, | |
| 831 | comptime strat: ResolveStrat, | |
| 832 | zcu: strat.ZcuPtr(), | |
| 833 | tid: strat.Tid(), | |
| 834 | ) !Alignment { | |
| 835 | return switch (zcu.intern_pool.indexToKey(ty.toIntern())) { | |
| 836 | .ptr_type => |ptr_type| { | |
| 837 | if (ptr_type.flags.alignment != .none) return ptr_type.flags.alignment; | |
| 838 | const res = try Type.fromInterned(ptr_type.child).abiAlignmentInner(strat.toLazy(), zcu, tid); | |
| 839 | return res.scalar; | |
| 840 | }, | |
| 841 | .opt_type => |child| Type.fromInterned(child).ptrAlignmentInner(strat, zcu, tid), | |
| 694 | pub fn ptrAlignment(ptr_ty: Type, zcu: *Zcu) Alignment { | |
| 695 | const ip = &zcu.intern_pool; | |
| 696 | const ptr_key: InternPool.Key.PtrType = switch (ip.indexToKey(ptr_ty.toIntern())) { | |
| 697 | .ptr_type => |key| key, | |
| 698 | .opt_type => |child| ip.indexToKey(child).ptr_type, | |
| 842 | 699 | else => unreachable, |
| 843 | 700 | }; |
| 701 | if (ptr_key.flags.alignment != .none) return ptr_key.flags.alignment; | |
| 702 | return Type.fromInterned(ptr_key.child).abiAlignment(zcu); | |
| 844 | 703 | } |
| 845 | 704 | |
| 846 | 705 | pub fn ptrAddressSpace(ty: Type, zcu: *const Zcu) std.builtin.AddressSpace { |
| ... | ... | @@ -851,861 +710,347 @@ pub fn ptrAddressSpace(ty: Type, zcu: *const Zcu) std.builtin.AddressSpace { |
| 851 | 710 | }; |
| 852 | 711 | } |
| 853 | 712 | |
| 854 | /// May capture a reference to `ty`. | |
| 855 | /// Returned value has type `comptime_int`. | |
| 856 | pub fn lazyAbiAlignment(ty: Type, pt: Zcu.PerThread) !Value { | |
| 857 | switch (try ty.abiAlignmentInner(.lazy, pt.zcu, pt.tid)) { | |
| 858 | .val => |val| return val, | |
| 859 | .scalar => |x| return pt.intValue(Type.comptime_int, x.toByteUnits() orelse 0), | |
| 860 | } | |
| 861 | } | |
| 862 | ||
| 863 | pub const AbiAlignmentInner = union(enum) { | |
| 864 | scalar: Alignment, | |
| 865 | val: Value, | |
| 866 | }; | |
| 867 | ||
| 868 | pub const ResolveStratLazy = enum { | |
| 869 | /// Return a `lazy_size` or `lazy_align` value if necessary. | |
| 870 | /// This value can be resolved later using `Value.resolveLazy`. | |
| 871 | lazy, | |
| 872 | /// Return a scalar result, expecting all necessary type resolution to be completed. | |
| 873 | /// Backends should typically use this, since they must not perform type resolution. | |
| 874 | eager, | |
| 875 | /// Return a scalar result, performing type resolution as necessary. | |
| 876 | /// This should typically be used from semantic analysis. | |
| 877 | sema, | |
| 878 | ||
| 879 | pub fn Tid(strat: ResolveStratLazy) type { | |
| 880 | return switch (strat) { | |
| 881 | .lazy, .sema => Zcu.PerThread.Id, | |
| 882 | .eager => void, | |
| 883 | }; | |
| 884 | } | |
| 885 | ||
| 886 | pub fn ZcuPtr(strat: ResolveStratLazy) type { | |
| 887 | return switch (strat) { | |
| 888 | .eager => *const Zcu, | |
| 889 | .sema, .lazy => *Zcu, | |
| 890 | }; | |
| 891 | } | |
| 892 | ||
| 893 | pub fn pt( | |
| 894 | comptime strat: ResolveStratLazy, | |
| 895 | zcu: strat.ZcuPtr(), | |
| 896 | tid: strat.Tid(), | |
| 897 | ) switch (strat) { | |
| 898 | .lazy, .sema => Zcu.PerThread, | |
| 899 | .eager => void, | |
| 900 | } { | |
| 901 | return switch (strat) { | |
| 902 | .lazy, .sema => .{ .tid = tid, .zcu = zcu }, | |
| 903 | else => {}, | |
| 904 | }; | |
| 905 | } | |
| 906 | }; | |
| 907 | ||
| 908 | /// The chosen strategy can be easily optimized away in release builds. | |
| 909 | /// However, in debug builds, it helps to avoid accidentally resolving types in backends. | |
| 910 | pub const ResolveStrat = enum { | |
| 911 | /// Assert that all necessary resolution is completed. | |
| 912 | /// Backends should typically use this, since they must not perform type resolution. | |
| 913 | normal, | |
| 914 | /// Perform type resolution as necessary using `Zcu`. | |
| 915 | /// This should typically be used from semantic analysis. | |
| 916 | sema, | |
| 917 | ||
| 918 | pub fn Tid(strat: ResolveStrat) type { | |
| 919 | return switch (strat) { | |
| 920 | .sema => Zcu.PerThread.Id, | |
| 921 | .normal => void, | |
| 922 | }; | |
| 923 | } | |
| 924 | ||
| 925 | pub fn ZcuPtr(strat: ResolveStrat) type { | |
| 926 | return switch (strat) { | |
| 927 | .normal => *const Zcu, | |
| 928 | .sema => *Zcu, | |
| 929 | }; | |
| 930 | } | |
| 931 | ||
| 932 | pub fn pt(comptime strat: ResolveStrat, zcu: strat.ZcuPtr(), tid: strat.Tid()) switch (strat) { | |
| 933 | .sema => Zcu.PerThread, | |
| 934 | .normal => void, | |
| 935 | } { | |
| 936 | return switch (strat) { | |
| 937 | .sema => .{ .tid = tid, .zcu = zcu }, | |
| 938 | .normal => {}, | |
| 939 | }; | |
| 940 | } | |
| 941 | ||
| 942 | pub inline fn toLazy(strat: ResolveStrat) ResolveStratLazy { | |
| 943 | return switch (strat) { | |
| 944 | .normal => .eager, | |
| 945 | .sema => .sema, | |
| 946 | }; | |
| 947 | } | |
| 948 | }; | |
| 949 | ||
| 950 | 713 | /// Never returns `none`. Asserts that all necessary type resolution is already done. |
| 714 | /// MLUGG TODO: check that it really does never return `.none` | |
| 951 | 715 | pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment { |
| 952 | return (ty.abiAlignmentInner(.eager, zcu, {}) catch unreachable).scalar; | |
| 953 | } | |
| 954 | ||
| 955 | pub fn abiAlignmentSema(ty: Type, pt: Zcu.PerThread) SemaError!Alignment { | |
| 956 | return (try ty.abiAlignmentInner(.sema, pt.zcu, pt.tid)).scalar; | |
| 957 | } | |
| 958 | ||
| 959 | /// If you pass `eager` you will get back `scalar` and assert the type is resolved. | |
| 960 | /// In this case there will be no error, guaranteed. | |
| 961 | /// If you pass `lazy` you may get back `scalar` or `val`. | |
| 962 | /// If `val` is returned, a reference to `ty` has been captured. | |
| 963 | /// If you pass `sema` you will get back `scalar` and resolve the type if | |
| 964 | /// necessary, possibly returning a CompileError. | |
| 965 | pub fn abiAlignmentInner( | |
| 966 | ty: Type, | |
| 967 | comptime strat: ResolveStratLazy, | |
| 968 | zcu: strat.ZcuPtr(), | |
| 969 | tid: strat.Tid(), | |
| 970 | ) SemaError!AbiAlignmentInner { | |
| 971 | const pt = strat.pt(zcu, tid); | |
| 972 | const target = zcu.getTarget(); | |
| 973 | 716 | const ip = &zcu.intern_pool; |
| 974 | ||
| 975 | switch (ty.toIntern()) { | |
| 976 | .empty_tuple_type => return .{ .scalar = .@"1" }, | |
| 977 | else => switch (ip.indexToKey(ty.toIntern())) { | |
| 978 | .int_type => |int_type| { | |
| 979 | if (int_type.bits == 0) return .{ .scalar = .@"1" }; | |
| 980 | return .{ .scalar = .fromByteUnits(std.zig.target.intAlignment(target, int_type.bits)) }; | |
| 981 | }, | |
| 982 | .ptr_type, .anyframe_type => { | |
| 983 | return .{ .scalar = ptrAbiAlignment(target) }; | |
| 984 | }, | |
| 985 | .array_type => |array_type| { | |
| 986 | return Type.fromInterned(array_type.child).abiAlignmentInner(strat, zcu, tid); | |
| 987 | }, | |
| 988 | .vector_type => |vector_type| { | |
| 989 | if (vector_type.len == 0) return .{ .scalar = .@"1" }; | |
| 990 | switch (zcu.comp.getZigBackend()) { | |
| 991 | else => { | |
| 992 | // This is fine because the child type of a vector always has a bit-size known | |
| 993 | // without needing any type resolution. | |
| 994 | const elem_bits: u32 = @intCast(Type.fromInterned(vector_type.child).bitSize(zcu)); | |
| 995 | if (elem_bits == 0) return .{ .scalar = .@"1" }; | |
| 996 | const bytes = ((elem_bits * vector_type.len) + 7) / 8; | |
| 997 | const alignment = std.math.ceilPowerOfTwoAssert(u32, bytes); | |
| 998 | return .{ .scalar = Alignment.fromByteUnits(alignment) }; | |
| 999 | }, | |
| 1000 | .stage2_c => { | |
| 1001 | return Type.fromInterned(vector_type.child).abiAlignmentInner(strat, zcu, tid); | |
| 1002 | }, | |
| 1003 | .stage2_x86_64 => { | |
| 1004 | if (vector_type.child == .bool_type) { | |
| 1005 | if (vector_type.len > 256 and target.cpu.has(.x86, .avx512f)) return .{ .scalar = .@"64" }; | |
| 1006 | if (vector_type.len > 128 and target.cpu.has(.x86, .avx)) return .{ .scalar = .@"32" }; | |
| 1007 | if (vector_type.len > 64) return .{ .scalar = .@"16" }; | |
| 1008 | const bytes = std.math.divCeil(u32, vector_type.len, 8) catch unreachable; | |
| 1009 | const alignment = std.math.ceilPowerOfTwoAssert(u32, bytes); | |
| 1010 | return .{ .scalar = Alignment.fromByteUnits(alignment) }; | |
| 1011 | } | |
| 1012 | const elem_bytes: u32 = @intCast((try Type.fromInterned(vector_type.child).abiSizeInner(strat, zcu, tid)).scalar); | |
| 1013 | if (elem_bytes == 0) return .{ .scalar = .@"1" }; | |
| 1014 | const bytes = elem_bytes * vector_type.len; | |
| 1015 | if (bytes > 32 and target.cpu.has(.x86, .avx512f)) return .{ .scalar = .@"64" }; | |
| 1016 | if (bytes > 16 and target.cpu.has(.x86, .avx)) return .{ .scalar = .@"32" }; | |
| 1017 | return .{ .scalar = .@"16" }; | |
| 1018 | }, | |
| 1019 | } | |
| 1020 | }, | |
| 1021 | ||
| 1022 | .opt_type => return ty.abiAlignmentInnerOptional(strat, zcu, tid), | |
| 1023 | .error_union_type => |info| return ty.abiAlignmentInnerErrorUnion( | |
| 1024 | strat, | |
| 1025 | zcu, | |
| 1026 | tid, | |
| 1027 | Type.fromInterned(info.payload_type), | |
| 1028 | ), | |
| 1029 | ||
| 1030 | .error_set_type, .inferred_error_set_type => { | |
| 1031 | const bits = zcu.errorSetBits(); | |
| 1032 | if (bits == 0) return .{ .scalar = .@"1" }; | |
| 1033 | return .{ .scalar = .fromByteUnits(std.zig.target.intAlignment(target, bits)) }; | |
| 1034 | }, | |
| 1035 | ||
| 1036 | // represents machine code; not a pointer | |
| 1037 | .func_type => return .{ .scalar = target_util.minFunctionAlignment(target) }, | |
| 1038 | ||
| 1039 | .simple_type => |t| switch (t) { | |
| 1040 | .bool, | |
| 1041 | .anyopaque, | |
| 1042 | => return .{ .scalar = .@"1" }, | |
| 1043 | ||
| 1044 | .usize, | |
| 1045 | .isize, | |
| 1046 | => return .{ .scalar = .fromByteUnits(std.zig.target.intAlignment(target, target.ptrBitWidth())) }, | |
| 1047 | ||
| 1048 | .c_char => return .{ .scalar = cTypeAlign(target, .char) }, | |
| 1049 | .c_short => return .{ .scalar = cTypeAlign(target, .short) }, | |
| 1050 | .c_ushort => return .{ .scalar = cTypeAlign(target, .ushort) }, | |
| 1051 | .c_int => return .{ .scalar = cTypeAlign(target, .int) }, | |
| 1052 | .c_uint => return .{ .scalar = cTypeAlign(target, .uint) }, | |
| 1053 | .c_long => return .{ .scalar = cTypeAlign(target, .long) }, | |
| 1054 | .c_ulong => return .{ .scalar = cTypeAlign(target, .ulong) }, | |
| 1055 | .c_longlong => return .{ .scalar = cTypeAlign(target, .longlong) }, | |
| 1056 | .c_ulonglong => return .{ .scalar = cTypeAlign(target, .ulonglong) }, | |
| 1057 | .c_longdouble => return .{ .scalar = cTypeAlign(target, .longdouble) }, | |
| 1058 | ||
| 1059 | .f16 => return .{ .scalar = .@"2" }, | |
| 1060 | .f32 => return .{ .scalar = cTypeAlign(target, .float) }, | |
| 1061 | .f64 => switch (target.cTypeBitSize(.double)) { | |
| 1062 | 64 => return .{ .scalar = cTypeAlign(target, .double) }, | |
| 1063 | else => return .{ .scalar = .@"8" }, | |
| 1064 | }, | |
| 1065 | .f80 => switch (target.cTypeBitSize(.longdouble)) { | |
| 1066 | 80 => return .{ .scalar = cTypeAlign(target, .longdouble) }, | |
| 1067 | else => return .{ .scalar = Type.u80.abiAlignment(zcu) }, | |
| 1068 | }, | |
| 1069 | .f128 => switch (target.cTypeBitSize(.longdouble)) { | |
| 1070 | 128 => return .{ .scalar = cTypeAlign(target, .longdouble) }, | |
| 1071 | else => return .{ .scalar = .@"16" }, | |
| 717 | const target = zcu.getTarget(); | |
| 718 | assertHasLayout(ty, zcu); | |
| 719 | return switch (ip.indexToKey(ty.toIntern())) { | |
| 720 | .int_type => |int_type| { | |
| 721 | if (int_type.bits == 0) return .@"1"; | |
| 722 | return .fromByteUnits(std.zig.target.intAlignment(target, int_type.bits)); | |
| 723 | }, | |
| 724 | .ptr_type, .anyframe_type => ptrAbiAlignment(target), | |
| 725 | .array_type => |array_type| Type.fromInterned(array_type.child).abiAlignment(zcu), | |
| 726 | .vector_type => |vector_type| { | |
| 727 | if (vector_type.len == 0) return .@"1"; | |
| 728 | switch (zcu.comp.getZigBackend()) { | |
| 729 | else => { | |
| 730 | const elem_bits: u32 = @intCast(Type.fromInterned(vector_type.child).bitSize(zcu)); | |
| 731 | if (elem_bits == 0) return .@"1"; | |
| 732 | const bytes = ((elem_bits * vector_type.len) + 7) / 8; | |
| 733 | return .fromByteUnits(std.math.ceilPowerOfTwoAssert(u32, bytes)); | |
| 1072 | 734 | }, |
| 1073 | ||
| 1074 | .anyerror, .adhoc_inferred_error_set => { | |
| 1075 | const bits = zcu.errorSetBits(); | |
| 1076 | if (bits == 0) return .{ .scalar = .@"1" }; | |
| 1077 | return .{ .scalar = .fromByteUnits(std.zig.target.intAlignment(target, bits)) }; | |
| 735 | .stage2_c => return Type.fromInterned(vector_type.child).abiAlignment(zcu), | |
| 736 | .stage2_x86_64 => { | |
| 737 | if (vector_type.child == .bool_type) { | |
| 738 | if (vector_type.len > 256 and target.cpu.has(.x86, .avx512f)) return .@"64"; | |
| 739 | if (vector_type.len > 128 and target.cpu.has(.x86, .avx)) return .@"32"; | |
| 740 | if (vector_type.len > 64) return .@"16"; | |
| 741 | const bytes = std.math.divCeil(u32, vector_type.len, 8) catch unreachable; | |
| 742 | return .fromByteUnits(std.math.ceilPowerOfTwoAssert(u32, bytes)); | |
| 743 | } | |
| 744 | const elem_bytes: u32 = @intCast(Type.fromInterned(vector_type.child).abiSize(zcu)); | |
| 745 | if (elem_bytes == 0) return .@"1"; | |
| 746 | const bytes = elem_bytes * vector_type.len; | |
| 747 | if (bytes > 32 and target.cpu.has(.x86, .avx512f)) return .@"64"; | |
| 748 | if (bytes > 16 and target.cpu.has(.x86, .avx)) return .@"32"; | |
| 749 | return .@"16"; | |
| 1078 | 750 | }, |
| 751 | } | |
| 752 | }, | |
| 1079 | 753 | |
| 1080 | .void, | |
| 1081 | .type, | |
| 1082 | .comptime_int, | |
| 1083 | .comptime_float, | |
| 1084 | .null, | |
| 1085 | .undefined, | |
| 1086 | .enum_literal, | |
| 1087 | => return .{ .scalar = .@"1" }, | |
| 754 | .opt_type => |child| Type.fromInterned(child).abiAlignment(zcu), | |
| 755 | .error_union_type => |eu| Alignment.maxStrict( | |
| 756 | Type.fromInterned(eu.payload_type).abiAlignment(zcu), | |
| 757 | errorAbiAlignment(zcu), | |
| 758 | ), | |
| 1088 | 759 | |
| 1089 | .noreturn => unreachable, | |
| 1090 | .generic_poison => unreachable, | |
| 1091 | }, | |
| 1092 | .struct_type => { | |
| 1093 | const struct_type = ip.loadStructType(ty.toIntern()); | |
| 1094 | if (struct_type.layout == .@"packed") { | |
| 1095 | switch (strat) { | |
| 1096 | .sema => try ty.resolveLayout(pt), | |
| 1097 | .lazy => if (struct_type.backingIntTypeUnordered(ip) == .none) return .{ | |
| 1098 | .val = Value.fromInterned(try pt.intern(.{ .int = .{ | |
| 1099 | .ty = .comptime_int_type, | |
| 1100 | .storage = .{ .lazy_align = ty.toIntern() }, | |
| 1101 | } })), | |
| 1102 | }, | |
| 1103 | .eager => {}, | |
| 1104 | } | |
| 1105 | return .{ .scalar = Type.fromInterned(struct_type.backingIntTypeUnordered(ip)).abiAlignment(zcu) }; | |
| 1106 | } | |
| 760 | .error_set_type, .inferred_error_set_type => errorAbiAlignment(zcu), | |
| 1107 | 761 | |
| 1108 | if (struct_type.flagsUnordered(ip).alignment == .none) switch (strat) { | |
| 1109 | .eager => unreachable, // struct alignment not resolved | |
| 1110 | .sema => try ty.resolveStructAlignment(pt), | |
| 1111 | .lazy => return .{ .val = Value.fromInterned(try pt.intern(.{ .int = .{ | |
| 1112 | .ty = .comptime_int_type, | |
| 1113 | .storage = .{ .lazy_align = ty.toIntern() }, | |
| 1114 | } })) }, | |
| 1115 | }; | |
| 762 | .func_type => target_util.minFunctionAlignment(target), | |
| 1116 | 763 | |
| 1117 | return .{ .scalar = struct_type.flagsUnordered(ip).alignment }; | |
| 1118 | }, | |
| 1119 | .tuple_type => |tuple| { | |
| 1120 | var big_align: Alignment = .@"1"; | |
| 1121 | for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| { | |
| 1122 | if (val != .none) continue; // comptime field | |
| 1123 | switch (try Type.fromInterned(field_ty).abiAlignmentInner(strat, zcu, tid)) { | |
| 1124 | .scalar => |field_align| big_align = big_align.max(field_align), | |
| 1125 | .val => switch (strat) { | |
| 1126 | .eager => unreachable, // field type alignment not resolved | |
| 1127 | .sema => unreachable, // passed to abiAlignmentInner above | |
| 1128 | .lazy => return .{ .val = Value.fromInterned(try pt.intern(.{ .int = .{ | |
| 1129 | .ty = .comptime_int_type, | |
| 1130 | .storage = .{ .lazy_align = ty.toIntern() }, | |
| 1131 | } })) }, | |
| 1132 | }, | |
| 1133 | } | |
| 1134 | } | |
| 1135 | return .{ .scalar = big_align }; | |
| 764 | .simple_type => |t| switch (t) { | |
| 765 | .bool, | |
| 766 | .void, | |
| 767 | .noreturn, | |
| 768 | .anyopaque, | |
| 769 | .type, | |
| 770 | .comptime_int, | |
| 771 | .comptime_float, | |
| 772 | .null, | |
| 773 | .undefined, | |
| 774 | .enum_literal, | |
| 775 | => .@"1", | |
| 776 | ||
| 777 | .anyerror, .adhoc_inferred_error_set => errorAbiAlignment(zcu), | |
| 778 | .usize, .isize => .fromByteUnits(std.zig.target.intAlignment(target, target.ptrBitWidth())), | |
| 779 | ||
| 780 | .c_char => cTypeAlign(target, .char), | |
| 781 | .c_short => cTypeAlign(target, .short), | |
| 782 | .c_ushort => cTypeAlign(target, .ushort), | |
| 783 | .c_int => cTypeAlign(target, .int), | |
| 784 | .c_uint => cTypeAlign(target, .uint), | |
| 785 | .c_long => cTypeAlign(target, .long), | |
| 786 | .c_ulong => cTypeAlign(target, .ulong), | |
| 787 | .c_longlong => cTypeAlign(target, .longlong), | |
| 788 | .c_ulonglong => cTypeAlign(target, .ulonglong), | |
| 789 | .c_longdouble => cTypeAlign(target, .longdouble), | |
| 790 | ||
| 791 | .f16 => .@"2", | |
| 792 | .f32 => cTypeAlign(target, .float), | |
| 793 | .f64 => switch (target.cTypeBitSize(.double)) { | |
| 794 | 64 => cTypeAlign(target, .double), | |
| 795 | else => .@"8", | |
| 1136 | 796 | }, |
| 1137 | .union_type => { | |
| 1138 | const union_type = ip.loadUnionType(ty.toIntern()); | |
| 1139 | ||
| 1140 | if (union_type.flagsUnordered(ip).alignment == .none) switch (strat) { | |
| 1141 | .eager => unreachable, // union layout not resolved | |
| 1142 | .sema => try ty.resolveUnionAlignment(pt), | |
| 1143 | .lazy => return .{ .val = Value.fromInterned(try pt.intern(.{ .int = .{ | |
| 1144 | .ty = .comptime_int_type, | |
| 1145 | .storage = .{ .lazy_align = ty.toIntern() }, | |
| 1146 | } })) }, | |
| 1147 | }; | |
| 1148 | ||
| 1149 | return .{ .scalar = union_type.flagsUnordered(ip).alignment }; | |
| 797 | .f80 => switch (target.cTypeBitSize(.longdouble)) { | |
| 798 | 80 => cTypeAlign(target, .longdouble), | |
| 799 | else => Type.u80.abiAlignment(zcu), | |
| 1150 | 800 | }, |
| 1151 | .opaque_type => return .{ .scalar = .@"1" }, | |
| 1152 | .enum_type => return .{ | |
| 1153 | .scalar = Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty).abiAlignment(zcu), | |
| 801 | .f128 => switch (target.cTypeBitSize(.longdouble)) { | |
| 802 | 128 => cTypeAlign(target, .longdouble), | |
| 803 | else => .@"16", | |
| 1154 | 804 | }, |
| 1155 | 805 | |
| 1156 | // values, not types | |
| 1157 | .undef, | |
| 1158 | .simple_value, | |
| 1159 | .variable, | |
| 1160 | .@"extern", | |
| 1161 | .func, | |
| 1162 | .int, | |
| 1163 | .err, | |
| 1164 | .error_union, | |
| 1165 | .enum_literal, | |
| 1166 | .enum_tag, | |
| 1167 | .empty_enum_value, | |
| 1168 | .float, | |
| 1169 | .ptr, | |
| 1170 | .slice, | |
| 1171 | .opt, | |
| 1172 | .aggregate, | |
| 1173 | .un, | |
| 1174 | // memoization, not types | |
| 1175 | .memoized_call, | |
| 1176 | => unreachable, | |
| 806 | .generic_poison => unreachable, | |
| 1177 | 807 | }, |
| 1178 | } | |
| 1179 | } | |
| 1180 | ||
| 1181 | fn abiAlignmentInnerErrorUnion( | |
| 1182 | ty: Type, | |
| 1183 | comptime strat: ResolveStratLazy, | |
| 1184 | zcu: strat.ZcuPtr(), | |
| 1185 | tid: strat.Tid(), | |
| 1186 | payload_ty: Type, | |
| 1187 | ) SemaError!AbiAlignmentInner { | |
| 1188 | // This code needs to be kept in sync with the equivalent switch prong | |
| 1189 | // in abiSizeInner. | |
| 1190 | const code_align = Type.anyerror.abiAlignment(zcu); | |
| 1191 | switch (strat) { | |
| 1192 | .eager, .sema => { | |
| 1193 | if (!(payload_ty.hasRuntimeBitsInner(false, strat, zcu, tid) catch |err| switch (err) { | |
| 1194 | error.NeedLazy => if (strat == .lazy) { | |
| 1195 | const pt = strat.pt(zcu, tid); | |
| 1196 | return .{ .val = Value.fromInterned(try pt.intern(.{ .int = .{ | |
| 1197 | .ty = .comptime_int_type, | |
| 1198 | .storage = .{ .lazy_align = ty.toIntern() }, | |
| 1199 | } })) }; | |
| 1200 | } else unreachable, | |
| 1201 | else => |e| return e, | |
| 1202 | })) { | |
| 1203 | return .{ .scalar = code_align }; | |
| 808 | .tuple_type => |tuple| { | |
| 809 | var big_align: Alignment = .@"1"; | |
| 810 | for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| { | |
| 811 | if (val != .none) continue; // comptime field | |
| 812 | const field_align = Type.fromInterned(field_ty).abiAlignment(zcu); | |
| 813 | big_align = big_align.max(field_align); | |
| 1204 | 814 | } |
| 1205 | return .{ .scalar = code_align.max( | |
| 1206 | (try payload_ty.abiAlignmentInner(strat, zcu, tid)).scalar, | |
| 1207 | ) }; | |
| 815 | return big_align; | |
| 1208 | 816 | }, |
| 1209 | .lazy => { | |
| 1210 | const pt = strat.pt(zcu, tid); | |
| 1211 | switch (try payload_ty.abiAlignmentInner(strat, zcu, tid)) { | |
| 1212 | .scalar => |payload_align| return .{ .scalar = code_align.max(payload_align) }, | |
| 1213 | .val => {}, | |
| 817 | .struct_type => { | |
| 818 | const struct_obj = ip.loadStructType(ty.toIntern()); | |
| 819 | switch (struct_obj.layout) { | |
| 820 | .@"packed" => return Type.fromInterned(struct_obj.packed_backing_int_type).abiAlignment(zcu), | |
| 821 | .auto, .@"extern" => return struct_obj.alignment, | |
| 1214 | 822 | } |
| 1215 | return .{ .val = Value.fromInterned(try pt.intern(.{ .int = .{ | |
| 1216 | .ty = .comptime_int_type, | |
| 1217 | .storage = .{ .lazy_align = ty.toIntern() }, | |
| 1218 | } })) }; | |
| 1219 | 823 | }, |
| 1220 | } | |
| 1221 | } | |
| 1222 | ||
| 1223 | fn abiAlignmentInnerOptional( | |
| 1224 | ty: Type, | |
| 1225 | comptime strat: ResolveStratLazy, | |
| 1226 | zcu: strat.ZcuPtr(), | |
| 1227 | tid: strat.Tid(), | |
| 1228 | ) SemaError!AbiAlignmentInner { | |
| 1229 | const pt = strat.pt(zcu, tid); | |
| 1230 | const target = zcu.getTarget(); | |
| 1231 | const child_type = ty.optionalChild(zcu); | |
| 1232 | ||
| 1233 | switch (child_type.zigTypeTag(zcu)) { | |
| 1234 | .pointer => return .{ .scalar = ptrAbiAlignment(target) }, | |
| 1235 | .error_set => return Type.anyerror.abiAlignmentInner(strat, zcu, tid), | |
| 1236 | .noreturn => return .{ .scalar = .@"1" }, | |
| 1237 | else => {}, | |
| 1238 | } | |
| 1239 | ||
| 1240 | switch (strat) { | |
| 1241 | .eager, .sema => { | |
| 1242 | if (!(child_type.hasRuntimeBitsInner(false, strat, zcu, tid) catch |err| switch (err) { | |
| 1243 | error.NeedLazy => if (strat == .lazy) { | |
| 1244 | return .{ .val = Value.fromInterned(try pt.intern(.{ .int = .{ | |
| 1245 | .ty = .comptime_int_type, | |
| 1246 | .storage = .{ .lazy_align = ty.toIntern() }, | |
| 1247 | } })) }; | |
| 1248 | } else unreachable, | |
| 1249 | else => |e| return e, | |
| 1250 | })) { | |
| 1251 | return .{ .scalar = .@"1" }; | |
| 824 | .union_type => { | |
| 825 | const union_obj = ip.loadUnionType(ty.toIntern()); | |
| 826 | switch (union_obj.layout) { | |
| 827 | .@"packed" => return Type.fromInterned(union_obj.packed_backing_int_type).abiAlignment(zcu), | |
| 828 | .auto, .@"extern" => return getUnionLayout(union_obj, zcu).abi_align, | |
| 1252 | 829 | } |
| 1253 | return child_type.abiAlignmentInner(strat, zcu, tid); | |
| 1254 | }, | |
| 1255 | .lazy => switch (try child_type.abiAlignmentInner(strat, zcu, tid)) { | |
| 1256 | .scalar => |x| return .{ .scalar = x.max(.@"1") }, | |
| 1257 | .val => return .{ .val = Value.fromInterned(try pt.intern(.{ .int = .{ | |
| 1258 | .ty = .comptime_int_type, | |
| 1259 | .storage = .{ .lazy_align = ty.toIntern() }, | |
| 1260 | } })) }, | |
| 1261 | 830 | }, |
| 1262 | } | |
| 1263 | } | |
| 1264 | ||
| 1265 | const AbiSizeInner = union(enum) { | |
| 1266 | scalar: u64, | |
| 1267 | val: Value, | |
| 1268 | }; | |
| 1269 | ||
| 1270 | /// Asserts the type has the ABI size already resolved. | |
| 1271 | /// Types that return false for hasRuntimeBits() return 0. | |
| 1272 | pub fn abiSize(ty: Type, zcu: *const Zcu) u64 { | |
| 1273 | return (abiSizeInner(ty, .eager, zcu, {}) catch unreachable).scalar; | |
| 1274 | } | |
| 1275 | ||
| 1276 | /// May capture a reference to `ty`. | |
| 1277 | pub fn abiSizeLazy(ty: Type, pt: Zcu.PerThread) !Value { | |
| 1278 | switch (try ty.abiSizeInner(.lazy, pt.zcu, pt.tid)) { | |
| 1279 | .val => |val| return val, | |
| 1280 | .scalar => |x| return pt.intValue(Type.comptime_int, x), | |
| 1281 | } | |
| 1282 | } | |
| 831 | .enum_type => Type.fromInterned(ip.loadEnumType(ty.toIntern()).int_tag_type).abiAlignment(zcu), | |
| 832 | .opaque_type => .@"1", | |
| 1283 | 833 | |
| 1284 | pub fn abiSizeSema(ty: Type, pt: Zcu.PerThread) SemaError!u64 { | |
| 1285 | return (try abiSizeInner(ty, .sema, pt.zcu, pt.tid)).scalar; | |
| 834 | // values, not types | |
| 835 | .undef, | |
| 836 | .simple_value, | |
| 837 | .variable, | |
| 838 | .@"extern", | |
| 839 | .func, | |
| 840 | .int, | |
| 841 | .err, | |
| 842 | .error_union, | |
| 843 | .enum_literal, | |
| 844 | .enum_tag, | |
| 845 | .empty_enum_value, | |
| 846 | .float, | |
| 847 | .ptr, | |
| 848 | .slice, | |
| 849 | .opt, | |
| 850 | .aggregate, | |
| 851 | .un, | |
| 852 | // memoization, not types | |
| 853 | .memoized_call, | |
| 854 | => unreachable, | |
| 855 | }; | |
| 1286 | 856 | } |
| 1287 | 857 | |
| 1288 | /// If you pass `eager` you will get back `scalar` and assert the type is resolved. | |
| 1289 | /// In this case there will be no error, guaranteed. | |
| 1290 | /// If you pass `lazy` you may get back `scalar` or `val`. | |
| 1291 | /// If `val` is returned, a reference to `ty` has been captured. | |
| 1292 | /// If you pass `sema` you will get back `scalar` and resolve the type if | |
| 1293 | /// necessary, possibly returning a CompileError. | |
| 1294 | pub fn abiSizeInner( | |
| 1295 | ty: Type, | |
| 1296 | comptime strat: ResolveStratLazy, | |
| 1297 | zcu: strat.ZcuPtr(), | |
| 1298 | tid: strat.Tid(), | |
| 1299 | ) SemaError!AbiSizeInner { | |
| 1300 | const target = zcu.getTarget(); | |
| 858 | /// Asserts that `ty` is not an opaque type. | |
| 859 | pub fn abiSize(ty: Type, zcu: *const Zcu) u64 { | |
| 1301 | 860 | const ip = &zcu.intern_pool; |
| 1302 | ||
| 1303 | switch (ty.toIntern()) { | |
| 1304 | .empty_tuple_type => return .{ .scalar = 0 }, | |
| 1305 | ||
| 1306 | else => switch (ip.indexToKey(ty.toIntern())) { | |
| 1307 | .int_type => |int_type| { | |
| 1308 | if (int_type.bits == 0) return .{ .scalar = 0 }; | |
| 1309 | return .{ .scalar = std.zig.target.intByteSize(target, int_type.bits) }; | |
| 1310 | }, | |
| 1311 | .ptr_type => |ptr_type| switch (ptr_type.flags.size) { | |
| 1312 | .slice => return .{ .scalar = @divExact(target.ptrBitWidth(), 8) * 2 }, | |
| 1313 | else => return .{ .scalar = @divExact(target.ptrBitWidth(), 8) }, | |
| 1314 | }, | |
| 1315 | .anyframe_type => return .{ .scalar = @divExact(target.ptrBitWidth(), 8) }, | |
| 1316 | ||
| 1317 | .array_type => |array_type| { | |
| 1318 | const len = array_type.lenIncludingSentinel(); | |
| 1319 | if (len == 0) return .{ .scalar = 0 }; | |
| 1320 | switch (try Type.fromInterned(array_type.child).abiSizeInner(strat, zcu, tid)) { | |
| 1321 | .scalar => |elem_size| return .{ .scalar = len * elem_size }, | |
| 1322 | .val => switch (strat) { | |
| 1323 | .sema, .eager => unreachable, | |
| 1324 | .lazy => { | |
| 1325 | const pt = strat.pt(zcu, tid); | |
| 1326 | return .{ .val = Value.fromInterned(try pt.intern(.{ .int = .{ | |
| 1327 | .ty = .comptime_int_type, | |
| 1328 | .storage = .{ .lazy_size = ty.toIntern() }, | |
| 1329 | } })) }; | |
| 1330 | }, | |
| 1331 | }, | |
| 1332 | } | |
| 1333 | }, | |
| 1334 | .vector_type => |vector_type| { | |
| 1335 | const sub_strat: ResolveStrat = switch (strat) { | |
| 1336 | .sema => .sema, | |
| 1337 | .eager => .normal, | |
| 1338 | .lazy => { | |
| 1339 | const pt = strat.pt(zcu, tid); | |
| 1340 | return .{ .val = Value.fromInterned(try pt.intern(.{ .int = .{ | |
| 1341 | .ty = .comptime_int_type, | |
| 1342 | .storage = .{ .lazy_size = ty.toIntern() }, | |
| 1343 | } })) }; | |
| 1344 | }, | |
| 1345 | }; | |
| 1346 | const alignment = (try ty.abiAlignmentInner(strat, zcu, tid)).scalar; | |
| 1347 | const total_bytes = switch (zcu.comp.getZigBackend()) { | |
| 1348 | else => total_bytes: { | |
| 1349 | const elem_bits = try Type.fromInterned(vector_type.child).bitSizeInner(sub_strat, zcu, tid); | |
| 1350 | const total_bits = elem_bits * vector_type.len; | |
| 1351 | break :total_bytes (total_bits + 7) / 8; | |
| 1352 | }, | |
| 1353 | .stage2_c => total_bytes: { | |
| 1354 | const elem_bytes: u32 = @intCast((try Type.fromInterned(vector_type.child).abiSizeInner(strat, zcu, tid)).scalar); | |
| 1355 | break :total_bytes elem_bytes * vector_type.len; | |
| 1356 | }, | |
| 1357 | .stage2_x86_64 => total_bytes: { | |
| 1358 | if (vector_type.child == .bool_type) break :total_bytes std.math.divCeil(u32, vector_type.len, 8) catch unreachable; | |
| 1359 | const elem_bytes: u32 = @intCast((try Type.fromInterned(vector_type.child).abiSizeInner(strat, zcu, tid)).scalar); | |
| 1360 | break :total_bytes elem_bytes * vector_type.len; | |
| 1361 | }, | |
| 1362 | }; | |
| 1363 | return .{ .scalar = alignment.forward(total_bytes) }; | |
| 1364 | }, | |
| 1365 | ||
| 1366 | .opt_type => return ty.abiSizeInnerOptional(strat, zcu, tid), | |
| 1367 | ||
| 1368 | .error_set_type, .inferred_error_set_type => { | |
| 1369 | const bits = zcu.errorSetBits(); | |
| 1370 | if (bits == 0) return .{ .scalar = 0 }; | |
| 1371 | return .{ .scalar = std.zig.target.intByteSize(target, bits) }; | |
| 1372 | }, | |
| 1373 | ||
| 1374 | .error_union_type => |error_union_type| { | |
| 1375 | const payload_ty = Type.fromInterned(error_union_type.payload_type); | |
| 1376 | // This code needs to be kept in sync with the equivalent switch prong | |
| 1377 | // in abiAlignmentInner. | |
| 1378 | const code_size = Type.anyerror.abiSize(zcu); | |
| 1379 | if (!(payload_ty.hasRuntimeBitsInner(false, strat, zcu, tid) catch |err| switch (err) { | |
| 1380 | error.NeedLazy => if (strat == .lazy) { | |
| 1381 | const pt = strat.pt(zcu, tid); | |
| 1382 | return .{ .val = Value.fromInterned(try pt.intern(.{ .int = .{ | |
| 1383 | .ty = .comptime_int_type, | |
| 1384 | .storage = .{ .lazy_size = ty.toIntern() }, | |
| 1385 | } })) }; | |
| 1386 | } else unreachable, | |
| 1387 | else => |e| return e, | |
| 1388 | })) { | |
| 1389 | // Same as anyerror. | |
| 1390 | return .{ .scalar = code_size }; | |
| 1391 | } | |
| 1392 | const code_align = Type.anyerror.abiAlignment(zcu); | |
| 1393 | const payload_align = (try payload_ty.abiAlignmentInner(strat, zcu, tid)).scalar; | |
| 1394 | const payload_size = switch (try payload_ty.abiSizeInner(strat, zcu, tid)) { | |
| 1395 | .scalar => |elem_size| elem_size, | |
| 1396 | .val => switch (strat) { | |
| 1397 | .sema => unreachable, | |
| 1398 | .eager => unreachable, | |
| 1399 | .lazy => { | |
| 1400 | const pt = strat.pt(zcu, tid); | |
| 1401 | return .{ .val = Value.fromInterned(try pt.intern(.{ .int = .{ | |
| 1402 | .ty = .comptime_int_type, | |
| 1403 | .storage = .{ .lazy_size = ty.toIntern() }, | |
| 1404 | } })) }; | |
| 1405 | }, | |
| 1406 | }, | |
| 1407 | }; | |
| 1408 | ||
| 1409 | var size: u64 = 0; | |
| 1410 | if (code_align.compare(.gt, payload_align)) { | |
| 1411 | size += code_size; | |
| 1412 | size = payload_align.forward(size); | |
| 1413 | size += payload_size; | |
| 1414 | size = code_align.forward(size); | |
| 1415 | } else { | |
| 1416 | size += payload_size; | |
| 1417 | size = code_align.forward(size); | |
| 1418 | size += code_size; | |
| 1419 | size = payload_align.forward(size); | |
| 1420 | } | |
| 1421 | return .{ .scalar = size }; | |
| 1422 | }, | |
| 1423 | .func_type => unreachable, // represents machine code; not a pointer | |
| 1424 | .simple_type => |t| switch (t) { | |
| 1425 | .bool => return .{ .scalar = 1 }, | |
| 1426 | ||
| 1427 | .f16 => return .{ .scalar = 2 }, | |
| 1428 | .f32 => return .{ .scalar = 4 }, | |
| 1429 | .f64 => return .{ .scalar = 8 }, | |
| 1430 | .f128 => return .{ .scalar = 16 }, | |
| 1431 | .f80 => switch (target.cTypeBitSize(.longdouble)) { | |
| 1432 | 80 => return .{ .scalar = target.cTypeByteSize(.longdouble) }, | |
| 1433 | else => return .{ .scalar = Type.u80.abiSize(zcu) }, | |
| 1434 | }, | |
| 1435 | ||
| 1436 | .usize, | |
| 1437 | .isize, | |
| 1438 | => return .{ .scalar = @divExact(target.ptrBitWidth(), 8) }, | |
| 1439 | ||
| 1440 | .c_char => return .{ .scalar = target.cTypeByteSize(.char) }, | |
| 1441 | .c_short => return .{ .scalar = target.cTypeByteSize(.short) }, | |
| 1442 | .c_ushort => return .{ .scalar = target.cTypeByteSize(.ushort) }, | |
| 1443 | .c_int => return .{ .scalar = target.cTypeByteSize(.int) }, | |
| 1444 | .c_uint => return .{ .scalar = target.cTypeByteSize(.uint) }, | |
| 1445 | .c_long => return .{ .scalar = target.cTypeByteSize(.long) }, | |
| 1446 | .c_ulong => return .{ .scalar = target.cTypeByteSize(.ulong) }, | |
| 1447 | .c_longlong => return .{ .scalar = target.cTypeByteSize(.longlong) }, | |
| 1448 | .c_ulonglong => return .{ .scalar = target.cTypeByteSize(.ulonglong) }, | |
| 1449 | .c_longdouble => return .{ .scalar = target.cTypeByteSize(.longdouble) }, | |
| 1450 | ||
| 1451 | .anyopaque, | |
| 1452 | .void, | |
| 1453 | .type, | |
| 1454 | .comptime_int, | |
| 1455 | .comptime_float, | |
| 1456 | .null, | |
| 1457 | .undefined, | |
| 1458 | .enum_literal, | |
| 1459 | => return .{ .scalar = 0 }, | |
| 1460 | ||
| 1461 | .anyerror, .adhoc_inferred_error_set => { | |
| 1462 | const bits = zcu.errorSetBits(); | |
| 1463 | if (bits == 0) return .{ .scalar = 0 }; | |
| 1464 | return .{ .scalar = std.zig.target.intByteSize(target, bits) }; | |
| 861 | const target = zcu.getTarget(); | |
| 862 | assertHasLayout(ty, zcu); | |
| 863 | return switch (ip.indexToKey(ty.toIntern())) { | |
| 864 | .int_type => |int_type| std.zig.target.intByteSize(target, int_type.bits), | |
| 865 | .ptr_type => |ptr_type| switch (ptr_type.flags.size) { | |
| 866 | .slice => ptrAbiSize(target) * 2, | |
| 867 | .one, .many, .c => ptrAbiSize(target), | |
| 868 | }, | |
| 869 | .anyframe_type => ptrAbiSize(target), | |
| 870 | .array_type => |arr| arr.lenIncludingSentinel() * Type.fromInterned(arr.child).abiSize(zcu), | |
| 871 | .vector_type => |vec| { | |
| 872 | const elem_ty: Type = .fromInterned(vec.child); | |
| 873 | const bytes = switch (zcu.comp.getZigBackend()) { | |
| 874 | else => std.math.divCeil(u64, vec.len * elem_ty.bitSize(zcu), 8) catch unreachable, | |
| 875 | .stage2_c => vec.len * elem_ty.abiSize(zcu), | |
| 876 | .stage2_x86_64 => switch (elem_ty.toIntern()) { | |
| 877 | .bool_type => std.math.divCeil(u64, vec.len, 8) catch unreachable, | |
| 878 | else => vec.len * elem_ty.abiSize(zcu), | |
| 1465 | 879 | }, |
| 1466 | ||
| 1467 | .noreturn => unreachable, | |
| 1468 | .generic_poison => unreachable, | |
| 1469 | }, | |
| 1470 | .struct_type => { | |
| 1471 | const struct_type = ip.loadStructType(ty.toIntern()); | |
| 1472 | switch (strat) { | |
| 1473 | .sema => try ty.resolveLayout(strat.pt(zcu, tid)), | |
| 1474 | .lazy => { | |
| 1475 | const pt = strat.pt(zcu, tid); | |
| 1476 | switch (struct_type.layout) { | |
| 1477 | .@"packed" => { | |
| 1478 | if (struct_type.backingIntTypeUnordered(ip) == .none) return .{ | |
| 1479 | .val = Value.fromInterned(try pt.intern(.{ .int = .{ | |
| 1480 | .ty = .comptime_int_type, | |
| 1481 | .storage = .{ .lazy_size = ty.toIntern() }, | |
| 1482 | } })), | |
| 1483 | }; | |
| 1484 | }, | |
| 1485 | .auto, .@"extern" => { | |
| 1486 | if (!struct_type.haveLayout(ip)) return .{ | |
| 1487 | .val = Value.fromInterned(try pt.intern(.{ .int = .{ | |
| 1488 | .ty = .comptime_int_type, | |
| 1489 | .storage = .{ .lazy_size = ty.toIntern() }, | |
| 1490 | } })), | |
| 1491 | }; | |
| 1492 | }, | |
| 1493 | } | |
| 1494 | }, | |
| 1495 | .eager => {}, | |
| 1496 | } | |
| 1497 | switch (struct_type.layout) { | |
| 1498 | .@"packed" => return .{ | |
| 1499 | .scalar = Type.fromInterned(struct_type.backingIntTypeUnordered(ip)).abiSize(zcu), | |
| 1500 | }, | |
| 1501 | .auto, .@"extern" => { | |
| 1502 | assert(struct_type.haveLayout(ip)); | |
| 1503 | return .{ .scalar = struct_type.sizeUnordered(ip) }; | |
| 1504 | }, | |
| 1505 | } | |
| 1506 | }, | |
| 1507 | .tuple_type => |tuple| { | |
| 1508 | switch (strat) { | |
| 1509 | .sema => try ty.resolveLayout(strat.pt(zcu, tid)), | |
| 1510 | .lazy, .eager => {}, | |
| 1511 | } | |
| 1512 | const field_count = tuple.types.len; | |
| 1513 | if (field_count == 0) { | |
| 1514 | return .{ .scalar = 0 }; | |
| 1515 | } | |
| 1516 | return .{ .scalar = ty.structFieldOffset(field_count, zcu) }; | |
| 1517 | }, | |
| 1518 | ||
| 1519 | .union_type => { | |
| 1520 | const union_type = ip.loadUnionType(ty.toIntern()); | |
| 1521 | switch (strat) { | |
| 1522 | .sema => try ty.resolveLayout(strat.pt(zcu, tid)), | |
| 1523 | .lazy => { | |
| 1524 | const pt = strat.pt(zcu, tid); | |
| 1525 | if (!union_type.flagsUnordered(ip).status.haveLayout()) return .{ | |
| 1526 | .val = Value.fromInterned(try pt.intern(.{ .int = .{ | |
| 1527 | .ty = .comptime_int_type, | |
| 1528 | .storage = .{ .lazy_size = ty.toIntern() }, | |
| 1529 | } })), | |
| 1530 | }; | |
| 1531 | }, | |
| 1532 | .eager => {}, | |
| 1533 | } | |
| 1534 | ||
| 1535 | assert(union_type.haveLayout(ip)); | |
| 1536 | return .{ .scalar = union_type.sizeUnordered(ip) }; | |
| 880 | }; | |
| 881 | return ty.abiAlignment(zcu).forward(bytes); | |
| 882 | }, | |
| 883 | .opt_type => |child_ty_ip| { | |
| 884 | const child_ty: Type = .fromInterned(child_ty_ip); | |
| 885 | if (child_ty.isNoReturn(zcu)) return 0; | |
| 886 | const child_size = child_ty.abiSize(zcu); | |
| 887 | if (ty.optionalReprIsPayload(zcu)) return child_size; | |
| 888 | // Optional types are represented as a struct with the child type as the first | |
| 889 | // field and a boolean as the second. Since the child type's abi alignment is | |
| 890 | // guaranteed to be >= that of bool's (1 byte) the added size is exactly equal | |
| 891 | // to the child type's ABI alignment. | |
| 892 | return child_size + child_ty.abiAlignment(zcu).toByteUnits().?; | |
| 893 | }, | |
| 894 | .error_set_type, .inferred_error_set_type => errorAbiSize(zcu), | |
| 895 | .error_union_type => |error_union| { | |
| 896 | const payload_ty: Type = .fromInterned(error_union.payload_type); | |
| 897 | // This code needs to be kept in sync with the equivalent switch prong | |
| 898 | // in abiAlignmentInner. | |
| 899 | const code_size = errorAbiSize(zcu); | |
| 900 | const code_align = errorAbiAlignment(zcu); | |
| 901 | const payload_size = payload_ty.abiSize(zcu); | |
| 902 | const payload_align = payload_ty.abiAlignment(zcu); | |
| 903 | // The layout will either be (code, payload, padding) or (payload, code, padding) | |
| 904 | // depending on which has larger alignment. So the overall size is just the code | |
| 905 | // and payload sizes added and padded to the larger alignment. | |
| 906 | const big_align = code_align.maxStrict(payload_align); | |
| 907 | return big_align.forward(payload_size + code_size); | |
| 908 | }, | |
| 909 | .func_type => 0, | |
| 910 | .simple_type => |t| switch (t) { | |
| 911 | .void, | |
| 912 | .noreturn, | |
| 913 | .type, | |
| 914 | .comptime_int, | |
| 915 | .comptime_float, | |
| 916 | .null, | |
| 917 | .undefined, | |
| 918 | .enum_literal, | |
| 919 | => 0, | |
| 920 | ||
| 921 | .bool => 1, | |
| 922 | .anyerror, .adhoc_inferred_error_set => errorAbiSize(zcu), | |
| 923 | .usize, .isize => ptrAbiSize(target), | |
| 924 | ||
| 925 | .c_char => target.cTypeByteSize(.char), | |
| 926 | .c_short => target.cTypeByteSize(.short), | |
| 927 | .c_ushort => target.cTypeByteSize(.ushort), | |
| 928 | .c_int => target.cTypeByteSize(.int), | |
| 929 | .c_uint => target.cTypeByteSize(.uint), | |
| 930 | .c_long => target.cTypeByteSize(.long), | |
| 931 | .c_ulong => target.cTypeByteSize(.ulong), | |
| 932 | .c_longlong => target.cTypeByteSize(.longlong), | |
| 933 | .c_ulonglong => target.cTypeByteSize(.ulonglong), | |
| 934 | .c_longdouble => target.cTypeByteSize(.longdouble), | |
| 935 | ||
| 936 | .f16 => 2, | |
| 937 | .f32 => 4, | |
| 938 | .f64 => 8, | |
| 939 | .f80 => switch (target.cTypeBitSize(.longdouble)) { | |
| 940 | 80 => target.cTypeByteSize(.longdouble), | |
| 941 | else => Type.u80.abiSize(zcu), | |
| 1537 | 942 | }, |
| 1538 | .opaque_type => unreachable, // no size available | |
| 1539 | .enum_type => return .{ .scalar = Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty).abiSize(zcu) }, | |
| 943 | .f128 => 16, | |
| 1540 | 944 | |
| 1541 | // values, not types | |
| 1542 | .undef, | |
| 1543 | .simple_value, | |
| 1544 | .variable, | |
| 1545 | .@"extern", | |
| 1546 | .func, | |
| 1547 | .int, | |
| 1548 | .err, | |
| 1549 | .error_union, | |
| 1550 | .enum_literal, | |
| 1551 | .enum_tag, | |
| 1552 | .empty_enum_value, | |
| 1553 | .float, | |
| 1554 | .ptr, | |
| 1555 | .slice, | |
| 1556 | .opt, | |
| 1557 | .aggregate, | |
| 1558 | .un, | |
| 1559 | // memoization, not types | |
| 1560 | .memoized_call, | |
| 1561 | => unreachable, | |
| 945 | .anyopaque => unreachable, | |
| 946 | .generic_poison => unreachable, | |
| 1562 | 947 | }, |
| 1563 | } | |
| 1564 | } | |
| 1565 | ||
| 1566 | fn abiSizeInnerOptional( | |
| 1567 | ty: Type, | |
| 1568 | comptime strat: ResolveStratLazy, | |
| 1569 | zcu: strat.ZcuPtr(), | |
| 1570 | tid: strat.Tid(), | |
| 1571 | ) SemaError!AbiSizeInner { | |
| 1572 | const child_ty = ty.optionalChild(zcu); | |
| 1573 | ||
| 1574 | if (child_ty.isNoReturn(zcu)) { | |
| 1575 | return .{ .scalar = 0 }; | |
| 1576 | } | |
| 1577 | ||
| 1578 | if (!(child_ty.hasRuntimeBitsInner(false, strat, zcu, tid) catch |err| switch (err) { | |
| 1579 | error.NeedLazy => if (strat == .lazy) { | |
| 1580 | const pt = strat.pt(zcu, tid); | |
| 1581 | return .{ .val = Value.fromInterned(try pt.intern(.{ .int = .{ | |
| 1582 | .ty = .comptime_int_type, | |
| 1583 | .storage = .{ .lazy_size = ty.toIntern() }, | |
| 1584 | } })) }; | |
| 1585 | } else unreachable, | |
| 1586 | else => |e| return e, | |
| 1587 | })) return .{ .scalar = 1 }; | |
| 1588 | ||
| 1589 | if (ty.optionalReprIsPayload(zcu)) { | |
| 1590 | return child_ty.abiSizeInner(strat, zcu, tid); | |
| 1591 | } | |
| 1592 | ||
| 1593 | const payload_size = switch (try child_ty.abiSizeInner(strat, zcu, tid)) { | |
| 1594 | .scalar => |elem_size| elem_size, | |
| 1595 | .val => switch (strat) { | |
| 1596 | .sema => unreachable, | |
| 1597 | .eager => unreachable, | |
| 1598 | .lazy => return .{ .val = Value.fromInterned(try strat.pt(zcu, tid).intern(.{ .int = .{ | |
| 1599 | .ty = .comptime_int_type, | |
| 1600 | .storage = .{ .lazy_size = ty.toIntern() }, | |
| 1601 | } })) }, | |
| 948 | .tuple_type => |tuple| ty.structFieldOffset(tuple.types.len, zcu), | |
| 949 | .struct_type => { | |
| 950 | const struct_obj = ip.loadStructType(ty.toIntern()); | |
| 951 | switch (struct_obj.layout) { | |
| 952 | .@"packed" => return Type.fromInterned(struct_obj.packed_backing_int_type).abiSize(zcu), | |
| 953 | .auto, .@"extern" => return struct_obj.size, | |
| 954 | } | |
| 1602 | 955 | }, |
| 1603 | }; | |
| 956 | .union_type => { | |
| 957 | const union_obj = ip.loadUnionType(ty.toIntern()); | |
| 958 | switch (union_obj.layout) { | |
| 959 | .@"packed" => return Type.fromInterned(union_obj.packed_backing_int_type).abiSize(zcu), | |
| 960 | .auto, .@"extern" => return union_obj.size, | |
| 961 | } | |
| 962 | }, | |
| 963 | .enum_type => Type.fromInterned(ip.loadEnumType(ty.toIntern()).int_tag_type).abiSize(zcu), | |
| 964 | .opaque_type => unreachable, | |
| 1604 | 965 | |
| 1605 | // Optional types are represented as a struct with the child type as the first | |
| 1606 | // field and a boolean as the second. Since the child type's abi alignment is | |
| 1607 | // guaranteed to be >= that of bool's (1 byte) the added size is exactly equal | |
| 1608 | // to the child type's ABI alignment. | |
| 1609 | return .{ | |
| 1610 | .scalar = (child_ty.abiAlignment(zcu).toByteUnits() orelse 0) + payload_size, | |
| 966 | // values, not types | |
| 967 | .undef, | |
| 968 | .simple_value, | |
| 969 | .variable, | |
| 970 | .@"extern", | |
| 971 | .func, | |
| 972 | .int, | |
| 973 | .err, | |
| 974 | .error_union, | |
| 975 | .enum_literal, | |
| 976 | .enum_tag, | |
| 977 | .empty_enum_value, | |
| 978 | .float, | |
| 979 | .ptr, | |
| 980 | .slice, | |
| 981 | .opt, | |
| 982 | .aggregate, | |
| 983 | .un, | |
| 984 | // memoization, not types | |
| 985 | .memoized_call, | |
| 986 | => unreachable, | |
| 1611 | 987 | }; |
| 1612 | 988 | } |
| 1613 | 989 | |
| 1614 | 990 | pub fn ptrAbiAlignment(target: *const Target) Alignment { |
| 1615 | return Alignment.fromNonzeroByteUnits(@divExact(target.ptrBitWidth(), 8)); | |
| 991 | return .fromNonzeroByteUnits(@divExact(target.ptrBitWidth(), 8)); | |
| 1616 | 992 | } |
| 1617 | ||
| 1618 | pub fn bitSize(ty: Type, zcu: *const Zcu) u64 { | |
| 1619 | return bitSizeInner(ty, .normal, zcu, {}) catch unreachable; | |
| 993 | pub fn ptrAbiSize(target: *const Target) u64 { | |
| 994 | return @divExact(target.ptrBitWidth(), 8); | |
| 1620 | 995 | } |
| 1621 | ||
| 1622 | pub fn bitSizeSema(ty: Type, pt: Zcu.PerThread) SemaError!u64 { | |
| 1623 | return bitSizeInner(ty, .sema, pt.zcu, pt.tid); | |
| 996 | pub fn errorAbiAlignment(zcu: *const Zcu) Alignment { | |
| 997 | return .fromNonzeroByteUnits(std.zig.target.intAlignment(zcu.getTarget(), zcu.errorSetBits())); | |
| 998 | } | |
| 999 | pub fn errorAbiSize(zcu: *const Zcu) u64 { | |
| 1000 | return std.zig.target.intByteSize(zcu.getTarget(), zcu.errorSetBits()); | |
| 1624 | 1001 | } |
| 1625 | 1002 | |
| 1626 | pub fn bitSizeInner( | |
| 1627 | ty: Type, | |
| 1628 | comptime strat: ResolveStrat, | |
| 1629 | zcu: strat.ZcuPtr(), | |
| 1630 | tid: strat.Tid(), | |
| 1631 | ) SemaError!u64 { | |
| 1003 | /// Asserts that `ty` is not an opaque or comptime-only type. | |
| 1004 | /// Once #19755 is implemented, this query will only work on types with a defined bit-level representation. | |
| 1005 | pub fn bitSize(ty: Type, zcu: *const Zcu) u64 { | |
| 1632 | 1006 | const target = zcu.getTarget(); |
| 1633 | 1007 | const ip = &zcu.intern_pool; |
| 1634 | ||
| 1635 | const strat_lazy: ResolveStratLazy = strat.toLazy(); | |
| 1636 | ||
| 1637 | switch (ip.indexToKey(ty.toIntern())) { | |
| 1638 | .int_type => |int_type| return int_type.bits, | |
| 1008 | assertHasLayout(ty, zcu); | |
| 1009 | return switch (ip.indexToKey(ty.toIntern())) { | |
| 1010 | .int_type => |int_type| int_type.bits, | |
| 1639 | 1011 | .ptr_type => |ptr_type| switch (ptr_type.flags.size) { |
| 1640 | .slice => return target.ptrBitWidth() * 2, | |
| 1641 | else => return target.ptrBitWidth(), | |
| 1012 | .slice => target.ptrBitWidth() * 2, | |
| 1013 | else => target.ptrBitWidth(), | |
| 1642 | 1014 | }, |
| 1643 | .anyframe_type => return target.ptrBitWidth(), | |
| 1644 | ||
| 1015 | .anyframe_type => target.ptrBitWidth(), | |
| 1645 | 1016 | .array_type => |array_type| { |
| 1646 | const len = array_type.lenIncludingSentinel(); | |
| 1647 | if (len == 0) return 0; | |
| 1648 | 1017 | const elem_ty: Type = .fromInterned(array_type.child); |
| 1649 | switch (zcu.comp.getZigBackend()) { | |
| 1650 | else => { | |
| 1651 | const elem_size = (try elem_ty.abiSizeInner(strat_lazy, zcu, tid)).scalar; | |
| 1652 | if (elem_size == 0) return 0; | |
| 1653 | const elem_bit_size = try elem_ty.bitSizeInner(strat, zcu, tid); | |
| 1654 | return (len - 1) * 8 * elem_size + elem_bit_size; | |
| 1655 | }, | |
| 1656 | .stage2_x86_64 => { | |
| 1657 | const elem_bit_size = try elem_ty.bitSizeInner(strat, zcu, tid); | |
| 1658 | return elem_bit_size * len; | |
| 1018 | const len = array_type.lenIncludingSentinel(); | |
| 1019 | return switch (zcu.comp.getZigBackend()) { | |
| 1020 | .stage2_x86_64 => len * elem_ty.bitSize(zcu), | |
| 1021 | // this case will be removed under #19755 | |
| 1022 | else => switch (len) { | |
| 1023 | 0 => 0, | |
| 1024 | else => (len - 1) * 8 * elem_ty.abiSize(zcu) + elem_ty.bitSize(zcu), | |
| 1659 | 1025 | }, |
| 1660 | } | |
| 1661 | }, | |
| 1662 | .vector_type => |vector_type| { | |
| 1663 | const child_ty: Type = .fromInterned(vector_type.child); | |
| 1664 | const elem_bit_size = try child_ty.bitSizeInner(strat, zcu, tid); | |
| 1665 | return elem_bit_size * vector_type.len; | |
| 1666 | }, | |
| 1667 | .opt_type => { | |
| 1668 | // Optionals and error unions are not packed so their bitsize | |
| 1669 | // includes padding bits. | |
| 1670 | return (try ty.abiSizeInner(strat_lazy, zcu, tid)).scalar * 8; | |
| 1026 | }; | |
| 1671 | 1027 | }, |
| 1028 | .vector_type => |vec| vec.len * Type.fromInterned(vec.child).bitSize(zcu), | |
| 1029 | .error_set_type, .inferred_error_set_type => zcu.errorSetBits(), | |
| 1030 | .func_type => unreachable, | |
| 1672 | 1031 | |
| 1673 | .error_set_type, .inferred_error_set_type => return zcu.errorSetBits(), | |
| 1674 | ||
| 1675 | .error_union_type => { | |
| 1676 | // Optionals and error unions are not packed so their bitsize | |
| 1677 | // includes padding bits. | |
| 1678 | return (try ty.abiSizeInner(strat_lazy, zcu, tid)).scalar * 8; | |
| 1679 | }, | |
| 1680 | .func_type => unreachable, // represents machine code; not a pointer | |
| 1681 | 1032 | .simple_type => |t| switch (t) { |
| 1682 | .f16 => return 16, | |
| 1683 | .f32 => return 32, | |
| 1684 | .f64 => return 64, | |
| 1685 | .f80 => return 80, | |
| 1686 | .f128 => return 128, | |
| 1687 | ||
| 1688 | .usize, | |
| 1689 | .isize, | |
| 1690 | => return target.ptrBitWidth(), | |
| 1691 | ||
| 1692 | .c_char => return target.cTypeBitSize(.char), | |
| 1693 | .c_short => return target.cTypeBitSize(.short), | |
| 1694 | .c_ushort => return target.cTypeBitSize(.ushort), | |
| 1695 | .c_int => return target.cTypeBitSize(.int), | |
| 1696 | .c_uint => return target.cTypeBitSize(.uint), | |
| 1697 | .c_long => return target.cTypeBitSize(.long), | |
| 1698 | .c_ulong => return target.cTypeBitSize(.ulong), | |
| 1699 | .c_longlong => return target.cTypeBitSize(.longlong), | |
| 1700 | .c_ulonglong => return target.cTypeBitSize(.ulonglong), | |
| 1701 | .c_longdouble => return target.cTypeBitSize(.longdouble), | |
| 1702 | ||
| 1703 | .bool => return 1, | |
| 1704 | .void => return 0, | |
| 1705 | ||
| 1706 | .anyerror, | |
| 1707 | .adhoc_inferred_error_set, | |
| 1708 | => return zcu.errorSetBits(), | |
| 1033 | .void => 0, | |
| 1034 | .bool => 1, | |
| 1035 | .anyerror, .adhoc_inferred_error_set => zcu.errorSetBits(), | |
| 1036 | .usize, .isize => target.ptrBitWidth(), | |
| 1037 | ||
| 1038 | .c_char => target.cTypeBitSize(.char), | |
| 1039 | .c_short => target.cTypeBitSize(.short), | |
| 1040 | .c_ushort => target.cTypeBitSize(.ushort), | |
| 1041 | .c_int => target.cTypeBitSize(.int), | |
| 1042 | .c_uint => target.cTypeBitSize(.uint), | |
| 1043 | .c_long => target.cTypeBitSize(.long), | |
| 1044 | .c_ulong => target.cTypeBitSize(.ulong), | |
| 1045 | .c_longlong => target.cTypeBitSize(.longlong), | |
| 1046 | .c_ulonglong => target.cTypeBitSize(.ulonglong), | |
| 1047 | .c_longdouble => target.cTypeBitSize(.longdouble), | |
| 1048 | ||
| 1049 | .f16 => 16, | |
| 1050 | .f32 => 32, | |
| 1051 | .f64 => 64, | |
| 1052 | .f80 => 80, | |
| 1053 | .f128 => 128, | |
| 1709 | 1054 | |
| 1710 | 1055 | .anyopaque => unreachable, |
| 1711 | 1056 | .type => unreachable, |
| ... | ... | @@ -1717,49 +1062,30 @@ pub fn bitSizeInner( |
| 1717 | 1062 | .enum_literal => unreachable, |
| 1718 | 1063 | .generic_poison => unreachable, |
| 1719 | 1064 | }, |
| 1065 | ||
| 1720 | 1066 | .struct_type => { |
| 1721 | const struct_type = ip.loadStructType(ty.toIntern()); | |
| 1722 | const is_packed = struct_type.layout == .@"packed"; | |
| 1723 | if (strat == .sema) { | |
| 1724 | const pt = strat.pt(zcu, tid); | |
| 1725 | try ty.resolveFields(pt); | |
| 1726 | if (is_packed) try ty.resolveLayout(pt); | |
| 1727 | } | |
| 1728 | if (is_packed) { | |
| 1729 | return try Type.fromInterned(struct_type.backingIntTypeUnordered(ip)) | |
| 1730 | .bitSizeInner(strat, zcu, tid); | |
| 1067 | const struct_obj = ip.loadStructType(ty.toIntern()); | |
| 1068 | switch (struct_obj.layout) { | |
| 1069 | .@"packed" => return Type.fromInterned(struct_obj.packed_backing_int_type).bitSize(zcu), | |
| 1070 | .auto, .@"extern" => return struct_obj.size * 8, // will be `unreachable` under #19755 | |
| 1731 | 1071 | } |
| 1732 | return (try ty.abiSizeInner(strat_lazy, zcu, tid)).scalar * 8; | |
| 1733 | }, | |
| 1734 | ||
| 1735 | .tuple_type => { | |
| 1736 | return (try ty.abiSizeInner(strat_lazy, zcu, tid)).scalar * 8; | |
| 1737 | 1072 | }, |
| 1738 | ||
| 1739 | 1073 | .union_type => { |
| 1740 | const union_type = ip.loadUnionType(ty.toIntern()); | |
| 1741 | const is_packed = ty.containerLayout(zcu) == .@"packed"; | |
| 1742 | if (strat == .sema) { | |
| 1743 | const pt = strat.pt(zcu, tid); | |
| 1744 | try ty.resolveFields(pt); | |
| 1745 | if (is_packed) try ty.resolveLayout(pt); | |
| 1746 | } | |
| 1747 | if (!is_packed) { | |
| 1748 | return (try ty.abiSizeInner(strat_lazy, zcu, tid)).scalar * 8; | |
| 1074 | const union_obj = ip.loadUnionType(ty.toIntern()); | |
| 1075 | switch (union_obj.layout) { | |
| 1076 | .@"packed" => return Type.fromInterned(union_obj.packed_backing_int_type).bitSize(zcu), | |
| 1077 | .auto, .@"extern" => return union_obj.size * 8, // will be `unreachable` under #19755 | |
| 1749 | 1078 | } |
| 1750 | assert(union_type.flagsUnordered(ip).status.haveFieldTypes()); | |
| 1079 | }, | |
| 1080 | .enum_type => Type.fromInterned(ip.loadEnumType(ty.toIntern()).int_tag_type).bitSize(zcu), | |
| 1751 | 1081 | |
| 1752 | var size: u64 = 0; | |
| 1753 | for (0..union_type.field_types.len) |field_index| { | |
| 1754 | const field_ty = union_type.field_types.get(ip)[field_index]; | |
| 1755 | size = @max(size, try Type.fromInterned(field_ty).bitSizeInner(strat, zcu, tid)); | |
| 1756 | } | |
| 1082 | // will be `unreachable` under #19755 | |
| 1083 | .opt_type, | |
| 1084 | .error_union_type, | |
| 1085 | .tuple_type, | |
| 1086 | => ty.abiSize(zcu) * 8, | |
| 1757 | 1087 | |
| 1758 | return size; | |
| 1759 | }, | |
| 1760 | 1088 | .opaque_type => unreachable, |
| 1761 | .enum_type => return Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty) | |
| 1762 | .bitSizeInner(strat, zcu, tid), | |
| 1763 | 1089 | |
| 1764 | 1090 | // values, not types |
| 1765 | 1091 | .undef, |
| ... | ... | @@ -1782,23 +1108,6 @@ pub fn bitSizeInner( |
| 1782 | 1108 | // memoization, not types |
| 1783 | 1109 | .memoized_call, |
| 1784 | 1110 | => unreachable, |
| 1785 | } | |
| 1786 | } | |
| 1787 | ||
| 1788 | /// Returns true if the type's layout is already resolved and it is safe | |
| 1789 | /// to use `abiSize`, `abiAlignment` and `bitSize` on it. | |
| 1790 | pub fn layoutIsResolved(ty: Type, zcu: *const Zcu) bool { | |
| 1791 | const ip = &zcu.intern_pool; | |
| 1792 | return switch (ip.indexToKey(ty.toIntern())) { | |
| 1793 | .struct_type => ip.loadStructType(ty.toIntern()).haveLayout(ip), | |
| 1794 | .union_type => ip.loadUnionType(ty.toIntern()).haveLayout(ip), | |
| 1795 | .array_type => |array_type| { | |
| 1796 | if (array_type.lenIncludingSentinel() == 0) return true; | |
| 1797 | return Type.fromInterned(array_type.child).layoutIsResolved(zcu); | |
| 1798 | }, | |
| 1799 | .opt_type => |child| Type.fromInterned(child).layoutIsResolved(zcu), | |
| 1800 | .error_union_type => |k| Type.fromInterned(k.payload_type).layoutIsResolved(zcu), | |
| 1801 | else => true, | |
| 1802 | 1111 | }; |
| 1803 | 1112 | } |
| 1804 | 1113 | |
| ... | ... | @@ -1841,7 +1150,7 @@ pub fn isSliceAtRuntime(ty: Type, zcu: *const Zcu) bool { |
| 1841 | 1150 | } |
| 1842 | 1151 | |
| 1843 | 1152 | pub fn slicePtrFieldType(ty: Type, zcu: *const Zcu) Type { |
| 1844 | return Type.fromInterned(zcu.intern_pool.slicePtrType(ty.toIntern())); | |
| 1153 | return .fromInterned(zcu.intern_pool.slicePtrType(ty.toIntern())); | |
| 1845 | 1154 | } |
| 1846 | 1155 | |
| 1847 | 1156 | pub fn isConstPtr(ty: Type, zcu: *const Zcu) bool { |
| ... | ... | @@ -1897,10 +1206,7 @@ pub fn isPtrAtRuntime(ty: Type, zcu: *const Zcu) bool { |
| 1897 | 1206 | /// For pointer-like optionals, returns true, otherwise returns the allowzero property |
| 1898 | 1207 | /// of pointers. |
| 1899 | 1208 | pub fn ptrAllowsZero(ty: Type, zcu: *const Zcu) bool { |
| 1900 | if (ty.isPtrLikeOptional(zcu)) { | |
| 1901 | return true; | |
| 1902 | } | |
| 1903 | return ty.ptrInfo(zcu).flags.is_allowzero; | |
| 1209 | return ty.isPtrLikeOptional(zcu) or ty.ptrInfo(zcu).flags.is_allowzero; | |
| 1904 | 1210 | } |
| 1905 | 1211 | |
| 1906 | 1212 | /// See also `isPtrLikeOptional`. |
| ... | ... | @@ -1918,7 +1224,6 @@ pub fn optionalReprIsPayload(ty: Type, zcu: *const Zcu) bool { |
| 1918 | 1224 | |
| 1919 | 1225 | /// Returns true if the type is optional and would be lowered to a single pointer |
| 1920 | 1226 | /// address value, using 0 for null. Note that this returns true for C pointers. |
| 1921 | /// This function must be kept in sync with `Sema.typePtrOrOptionalPtrTy`. | |
| 1922 | 1227 | pub fn isPtrLikeOptional(ty: Type, zcu: *const Zcu) bool { |
| 1923 | 1228 | return switch (zcu.intern_pool.indexToKey(ty.toIntern())) { |
| 1924 | 1229 | .ptr_type => |ptr_type| ptr_type.flags.size == .c, |
| ... | ... | @@ -1947,52 +1252,75 @@ pub fn childTypeIp(ty: Type, ip: *const InternPool) Type { |
| 1947 | 1252 | return Type.fromInterned(ip.childType(ty.toIntern())); |
| 1948 | 1253 | } |
| 1949 | 1254 | |
| 1950 | /// For `*[N]T`, returns `T`. | |
| 1951 | /// For `?*T`, returns `T`. | |
| 1952 | /// For `?*[N]T`, returns `T`. | |
| 1953 | /// For `?[*]T`, returns `T`. | |
| 1954 | /// For `*T`, returns `T`. | |
| 1955 | /// For `[*]T`, returns `T`. | |
| 1956 | /// For `[N]T`, returns `T`. | |
| 1957 | /// For `[]T`, returns `T`. | |
| 1958 | /// For `anyframe->T`, returns `T`. | |
| 1959 | pub fn elemType2(ty: Type, zcu: *const Zcu) Type { | |
| 1960 | return switch (zcu.intern_pool.indexToKey(ty.toIntern())) { | |
| 1961 | .ptr_type => |ptr_type| switch (ptr_type.flags.size) { | |
| 1962 | .one => Type.fromInterned(ptr_type.child).shallowElemType(zcu), | |
| 1963 | .many, .c, .slice => Type.fromInterned(ptr_type.child), | |
| 1964 | }, | |
| 1965 | .anyframe_type => |child| { | |
| 1966 | assert(child != .none); | |
| 1967 | return Type.fromInterned(child); | |
| 1255 | /// Similar to `childType`, but for pointer-like (or slice-like) optionals, gets the child type | |
| 1256 | /// of the *pointer* type. Asserts that `ty` is either a pointer or a pointer-like optional. | |
| 1257 | /// | |
| 1258 | /// Essentially, unwraps any one of the following into `T`: | |
| 1259 | /// ``` | |
| 1260 | /// *T ?*T *allowzero T | |
| 1261 | /// [*]T ?[*]T [*]allowzero T | |
| 1262 | /// []T ?[]T []allowzero T | |
| 1263 | /// [*c]T | |
| 1264 | /// ``` | |
| 1265 | /// This is primarily useful in Sema to implement operations which can act on optional pointers. | |
| 1266 | pub fn nullablePtrElem(ty: Type, zcu: *const Zcu) Type { | |
| 1267 | switch (ty.zigTypeTag(zcu)) { | |
| 1268 | .pointer => return ty.childType(zcu), | |
| 1269 | .optional => { | |
| 1270 | const ptr_ty = ty.childType(zcu); | |
| 1271 | const ptr_info = zcu.intern_pool.indexToKey(ptr_ty.toIntern()).ptr_type; | |
| 1272 | assert(ptr_info.flags.size != .c); | |
| 1273 | assert(!ptr_info.flags.is_allowzero); | |
| 1274 | return .fromInterned(ptr_info.child); | |
| 1968 | 1275 | }, |
| 1969 | .vector_type => |vector_type| Type.fromInterned(vector_type.child), | |
| 1970 | .array_type => |array_type| Type.fromInterned(array_type.child), | |
| 1971 | .opt_type => |child| Type.fromInterned(zcu.intern_pool.childType(child)), | |
| 1972 | 1276 | else => unreachable, |
| 1973 | }; | |
| 1277 | } | |
| 1974 | 1278 | } |
| 1975 | 1279 | |
| 1976 | 1280 | /// Given that `ty` is an indexable pointer, returns its element type. Specifically: |
| 1977 | 1281 | /// * for `*[n]T`, returns `T` |
| 1282 | /// * for `*@Vector(n, T)`, returns `T` | |
| 1978 | 1283 | /// * for `[]T`, returns `T` |
| 1979 | 1284 | /// * for `[*]T`, returns `T` |
| 1980 | 1285 | /// * for `[*c]T`, returns `T` |
| 1286 | /// | |
| 1287 | /// Tuples are not supported because they do not have a single element type. | |
| 1288 | /// | |
| 1289 | /// MLUGG TODO: should i even have this one? it's a subset of indexableElem | |
| 1981 | 1290 | pub fn indexablePtrElem(ty: Type, zcu: *const Zcu) Type { |
| 1982 | 1291 | const ip = &zcu.intern_pool; |
| 1983 | 1292 | const ptr_type = ip.indexToKey(ty.toIntern()).ptr_type; |
| 1984 | switch (ptr_type.flags.size) { | |
| 1293 | return switch (ptr_type.flags.size) { | |
| 1985 | 1294 | .many, .slice, .c => return .fromInterned(ptr_type.child), |
| 1986 | .one => {}, | |
| 1987 | } | |
| 1988 | const array_type = ip.indexToKey(ptr_type.child).array_type; | |
| 1989 | return .fromInterned(array_type.child); | |
| 1295 | .one => switch (ip.indexToKey(ptr_type.child)) { | |
| 1296 | inline .array_type, .vector_type => |arr| return .fromInterned(arr.child), | |
| 1297 | else => unreachable, | |
| 1298 | }, | |
| 1299 | }; | |
| 1990 | 1300 | } |
| 1991 | 1301 | |
| 1992 | fn shallowElemType(child_ty: Type, zcu: *const Zcu) Type { | |
| 1993 | return switch (child_ty.zigTypeTag(zcu)) { | |
| 1994 | .array, .vector => child_ty.childType(zcu), | |
| 1995 | else => child_ty, | |
| 1302 | /// Given that `ty` is an indexable type, returns its element type. Specifically: | |
| 1303 | /// * for `[n]T`, returns `T` | |
| 1304 | /// * for `@Vector(n, T)`, returns `T` | |
| 1305 | /// * for `*[n]T`, returns `T` | |
| 1306 | /// * for `*@Vector(n, T)`, returns `T` | |
| 1307 | /// * for `[]T`, returns `T` | |
| 1308 | /// * for `[*]T`, returns `T` | |
| 1309 | /// * for `[*c]T`, returns `T` | |
| 1310 | /// | |
| 1311 | /// Tuples are not supported because they do not have a single element type. | |
| 1312 | pub fn indexableElem(ty: Type, zcu: *const Zcu) Type { | |
| 1313 | const ip = &zcu.intern_pool; | |
| 1314 | return switch (ip.indexToKey(ty.toIntern())) { | |
| 1315 | inline .array_type, .vector_type => |arr| .fromInterned(arr.child), | |
| 1316 | .ptr_type => |ptr_type| switch (ptr_type.flags.size) { | |
| 1317 | .many, .slice, .c => .fromInterned(ptr_type.child), | |
| 1318 | .one => switch (ip.indexToKey(ptr_type.child)) { | |
| 1319 | inline .array_type, .vector_type => |arr| .fromInterned(arr.child), | |
| 1320 | else => unreachable, | |
| 1321 | }, | |
| 1322 | }, | |
| 1323 | else => unreachable, | |
| 1996 | 1324 | }; |
| 1997 | 1325 | } |
| 1998 | 1326 | |
| ... | ... | @@ -2004,17 +1332,17 @@ pub fn scalarType(ty: Type, zcu: *const Zcu) Type { |
| 2004 | 1332 | }; |
| 2005 | 1333 | } |
| 2006 | 1334 | |
| 2007 | /// Asserts that the type is an optional. | |
| 2008 | /// Note that for C pointers this returns the type unmodified. | |
| 1335 | /// Asserts that the type is an optional, or a C pointer. | |
| 1336 | /// For C pointers this returns the type unmodified. | |
| 2009 | 1337 | pub fn optionalChild(ty: Type, zcu: *const Zcu) Type { |
| 2010 | return switch (zcu.intern_pool.indexToKey(ty.toIntern())) { | |
| 2011 | .opt_type => |child| Type.fromInterned(child), | |
| 2012 | .ptr_type => |ptr_type| b: { | |
| 1338 | switch (zcu.intern_pool.indexToKey(ty.toIntern())) { | |
| 1339 | .opt_type => |child| return .fromInterned(child), | |
| 1340 | .ptr_type => |ptr_type| { | |
| 2013 | 1341 | assert(ptr_type.flags.size == .c); |
| 2014 | break :b ty; | |
| 1342 | return ty; | |
| 2015 | 1343 | }, |
| 2016 | 1344 | else => unreachable, |
| 2017 | }; | |
| 1345 | } | |
| 2018 | 1346 | } |
| 2019 | 1347 | |
| 2020 | 1348 | /// Returns the tag type of a union, if the type is a union and it has a tag type. |
| ... | ... | @@ -2025,15 +1353,11 @@ pub fn unionTagType(ty: Type, zcu: *const Zcu) ?Type { |
| 2025 | 1353 | .union_type => {}, |
| 2026 | 1354 | else => return null, |
| 2027 | 1355 | } |
| 2028 | const union_type = ip.loadUnionType(ty.toIntern()); | |
| 2029 | const union_flags = union_type.flagsUnordered(ip); | |
| 2030 | switch (union_flags.runtime_tag) { | |
| 2031 | .tagged => { | |
| 2032 | assert(union_flags.status.haveFieldTypes()); | |
| 2033 | return Type.fromInterned(union_type.enum_tag_ty); | |
| 2034 | }, | |
| 2035 | else => return null, | |
| 2036 | } | |
| 1356 | const union_obj = ip.loadUnionType(ty.toIntern()); | |
| 1357 | return switch (union_obj.runtime_tag) { | |
| 1358 | .tagged => .fromInterned(union_obj.enum_tag_type), | |
| 1359 | .none, .safety => null, | |
| 1360 | }; | |
| 2037 | 1361 | } |
| 2038 | 1362 | |
| 2039 | 1363 | /// Same as `unionTagType` but includes safety tag. |
| ... | ... | @@ -2043,9 +1367,8 @@ pub fn unionTagTypeSafety(ty: Type, zcu: *const Zcu) ?Type { |
| 2043 | 1367 | return switch (ip.indexToKey(ty.toIntern())) { |
| 2044 | 1368 | .union_type => { |
| 2045 | 1369 | const union_type = ip.loadUnionType(ty.toIntern()); |
| 2046 | if (!union_type.hasTag(ip)) return null; | |
| 2047 | assert(union_type.haveFieldTypes(ip)); | |
| 2048 | return Type.fromInterned(union_type.enum_tag_ty); | |
| 1370 | if (union_type.runtime_tag == .none) return null; | |
| 1371 | return Type.fromInterned(union_type.enum_tag_type); | |
| 2049 | 1372 | }, |
| 2050 | 1373 | else => null, |
| 2051 | 1374 | }; |
| ... | ... | @@ -2055,7 +1378,7 @@ pub fn unionTagTypeSafety(ty: Type, zcu: *const Zcu) ?Type { |
| 2055 | 1378 | /// not be stored at runtime. |
| 2056 | 1379 | pub fn unionTagTypeHypothetical(ty: Type, zcu: *const Zcu) Type { |
| 2057 | 1380 | const union_obj = zcu.typeToUnion(ty).?; |
| 2058 | return Type.fromInterned(union_obj.enum_tag_ty); | |
| 1381 | return Type.fromInterned(union_obj.enum_tag_type); | |
| 2059 | 1382 | } |
| 2060 | 1383 | |
| 2061 | 1384 | pub fn unionFieldType(ty: Type, enum_tag: Value, zcu: *const Zcu) ?Type { |
| ... | ... | @@ -2105,9 +1428,9 @@ pub fn unionGetLayout(ty: Type, zcu: *const Zcu) Zcu.UnionLayout { |
| 2105 | 1428 | pub fn containerLayout(ty: Type, zcu: *const Zcu) std.builtin.Type.ContainerLayout { |
| 2106 | 1429 | const ip = &zcu.intern_pool; |
| 2107 | 1430 | return switch (ip.indexToKey(ty.toIntern())) { |
| 2108 | .struct_type => ip.loadStructType(ty.toIntern()).layout, | |
| 2109 | 1431 | .tuple_type => .auto, |
| 2110 | .union_type => ip.loadUnionType(ty.toIntern()).flagsUnordered(ip).layout, | |
| 1432 | .struct_type => ip.loadStructType(ty.toIntern()).layout, | |
| 1433 | .union_type => ip.loadUnionType(ty.toIntern()).layout, | |
| 2111 | 1434 | else => unreachable, |
| 2112 | 1435 | }; |
| 2113 | 1436 | } |
| ... | ... | @@ -2182,33 +1505,6 @@ pub fn errorSetHasFieldIp( |
| 2182 | 1505 | }; |
| 2183 | 1506 | } |
| 2184 | 1507 | |
| 2185 | /// Returns whether ty, which must be an error set, includes an error `name`. | |
| 2186 | /// Might return a false negative if `ty` is an inferred error set and not fully | |
| 2187 | /// resolved yet. | |
| 2188 | pub fn errorSetHasField(ty: Type, name: []const u8, zcu: *const Zcu) bool { | |
| 2189 | const ip = &zcu.intern_pool; | |
| 2190 | return switch (ty.toIntern()) { | |
| 2191 | .anyerror_type => true, | |
| 2192 | else => switch (ip.indexToKey(ty.toIntern())) { | |
| 2193 | .error_set_type => |error_set_type| { | |
| 2194 | // If the string is not interned, then the field certainly is not present. | |
| 2195 | const field_name_interned = ip.getString(name).unwrap() orelse return false; | |
| 2196 | return error_set_type.nameIndex(ip, field_name_interned) != null; | |
| 2197 | }, | |
| 2198 | .inferred_error_set_type => |i| switch (ip.funcIesResolvedUnordered(i)) { | |
| 2199 | .anyerror_type => true, | |
| 2200 | .none => false, | |
| 2201 | else => |t| { | |
| 2202 | // If the string is not interned, then the field certainly is not present. | |
| 2203 | const field_name_interned = ip.getString(name).unwrap() orelse return false; | |
| 2204 | return ip.indexToKey(t).error_set_type.nameIndex(ip, field_name_interned) != null; | |
| 2205 | }, | |
| 2206 | }, | |
| 2207 | else => unreachable, | |
| 2208 | }, | |
| 2209 | }; | |
| 2210 | } | |
| 2211 | ||
| 2212 | 1508 | /// Asserts the type is an array or vector or struct. |
| 2213 | 1509 | pub fn arrayLen(ty: Type, zcu: *const Zcu) u64 { |
| 2214 | 1510 | return ty.arrayLenIp(&zcu.intern_pool); |
| ... | ... | @@ -2308,8 +1604,12 @@ pub fn intInfo(starting_ty: Type, zcu: *const Zcu) InternPool.Key.IntType { |
| 2308 | 1604 | .c_ulonglong_type => return .{ .signedness = .unsigned, .bits = target.cTypeBitSize(.ulonglong) }, |
| 2309 | 1605 | else => switch (ip.indexToKey(ty.toIntern())) { |
| 2310 | 1606 | .int_type => |int_type| return int_type, |
| 2311 | .struct_type => ty = Type.fromInterned(ip.loadStructType(ty.toIntern()).backingIntTypeUnordered(ip)), | |
| 2312 | .enum_type => ty = Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty), | |
| 1607 | .struct_type => { | |
| 1608 | const struct_obj = ip.loadStructType(ty.toIntern()); | |
| 1609 | assert(struct_obj.layout == .@"packed"); | |
| 1610 | ty = .fromInterned(struct_obj.packed_backing_int_type); | |
| 1611 | }, | |
| 1612 | .enum_type => ty = .fromInterned(ip.loadEnumType(ty.toIntern()).int_tag_type), | |
| 2313 | 1613 | .vector_type => |vector_type| ty = Type.fromInterned(vector_type.child), |
| 2314 | 1614 | |
| 2315 | 1615 | .error_set_type, .inferred_error_set_type => { |
| ... | ... | @@ -2355,25 +1655,6 @@ pub fn intInfo(starting_ty: Type, zcu: *const Zcu) InternPool.Key.IntType { |
| 2355 | 1655 | }; |
| 2356 | 1656 | } |
| 2357 | 1657 | |
| 2358 | pub fn isNamedInt(ty: Type) bool { | |
| 2359 | return switch (ty.toIntern()) { | |
| 2360 | .usize_type, | |
| 2361 | .isize_type, | |
| 2362 | .c_char_type, | |
| 2363 | .c_short_type, | |
| 2364 | .c_ushort_type, | |
| 2365 | .c_int_type, | |
| 2366 | .c_uint_type, | |
| 2367 | .c_long_type, | |
| 2368 | .c_ulong_type, | |
| 2369 | .c_longlong_type, | |
| 2370 | .c_ulonglong_type, | |
| 2371 | => true, | |
| 2372 | ||
| 2373 | else => false, | |
| 2374 | }; | |
| 2375 | } | |
| 2376 | ||
| 2377 | 1658 | /// Returns `false` for `comptime_float`. |
| 2378 | 1659 | pub fn isRuntimeFloat(ty: Type) bool { |
| 2379 | 1660 | return switch (ty.toIntern()) { |
| ... | ... | @@ -2488,17 +1769,16 @@ pub fn isNumeric(ty: Type, zcu: *const Zcu) bool { |
| 2488 | 1769 | }; |
| 2489 | 1770 | } |
| 2490 | 1771 | |
| 2491 | /// During semantic analysis, instead call `Sema.typeHasOnePossibleValue` which | |
| 2492 | /// resolves field types rather than asserting they are already resolved. | |
| 1772 | /// MLUGG TODO: deal with our friends structs and unions | |
| 2493 | 1773 | pub fn onePossibleValue(starting_type: Type, pt: Zcu.PerThread) !?Value { |
| 2494 | 1774 | const zcu = pt.zcu; |
| 2495 | 1775 | const comp = zcu.comp; |
| 2496 | 1776 | const gpa = comp.gpa; |
| 2497 | const io = comp.io; | |
| 2498 | 1777 | const ip = &zcu.intern_pool; |
| 1778 | assertHasLayout(starting_type, zcu); | |
| 2499 | 1779 | var ty = starting_type; |
| 2500 | 1780 | while (true) switch (ty.toIntern()) { |
| 2501 | .empty_tuple_type => return Value.empty_tuple, | |
| 1781 | .empty_tuple_type => return .empty_tuple, | |
| 2502 | 1782 | |
| 2503 | 1783 | else => switch (ip.indexToKey(ty.toIntern())) { |
| 2504 | 1784 | .int_type => |int_type| { |
| ... | ... | @@ -2563,31 +1843,37 @@ pub fn onePossibleValue(starting_type: Type, pt: Zcu.PerThread) !?Value { |
| 2563 | 1843 | .adhoc_inferred_error_set, |
| 2564 | 1844 | => return null, |
| 2565 | 1845 | |
| 2566 | .void => return Value.void, | |
| 2567 | .noreturn => return Value.@"unreachable", | |
| 2568 | .null => return Value.null, | |
| 2569 | .undefined => return Value.undef, | |
| 1846 | .void => return .void, | |
| 1847 | .noreturn => return .@"unreachable", | |
| 1848 | .null => return .null, | |
| 1849 | .undefined => return .undef, | |
| 2570 | 1850 | |
| 2571 | 1851 | .generic_poison => unreachable, |
| 2572 | 1852 | }, |
| 2573 | 1853 | .struct_type => { |
| 2574 | const struct_type = ip.loadStructType(ty.toIntern()); | |
| 2575 | assert(struct_type.haveFieldTypes(ip)); | |
| 2576 | if (struct_type.knownNonOpv(ip)) | |
| 2577 | return null; | |
| 2578 | const field_vals = try zcu.gpa.alloc(InternPool.Index, struct_type.field_types.len); | |
| 2579 | defer zcu.gpa.free(field_vals); | |
| 1854 | const struct_obj = ip.loadStructType(ty.toIntern()); | |
| 1855 | if (struct_obj.layout == .@"packed") { | |
| 1856 | const backing_ty: Type = .fromInterned(struct_obj.packed_backing_int_type); | |
| 1857 | const backing_val = try backing_ty.onePossibleValue(pt) orelse return null; | |
| 1858 | _ = backing_val; // MLUGG TODO: represent unions as their bits! | |
| 1859 | } else { | |
| 1860 | if (!struct_obj.has_one_possible_value) return null; | |
| 1861 | } | |
| 1862 | // There is an OPV. | |
| 1863 | const field_vals = try gpa.alloc(InternPool.Index, struct_obj.field_types.len); | |
| 1864 | defer gpa.free(field_vals); | |
| 2580 | 1865 | for (field_vals, 0..) |*field_val, i_usize| { |
| 2581 | 1866 | const i: u32 = @intCast(i_usize); |
| 2582 | if (struct_type.fieldIsComptime(ip, i)) { | |
| 2583 | assert(struct_type.haveFieldInits(ip)); | |
| 2584 | field_val.* = struct_type.field_inits.get(ip)[i]; | |
| 1867 | if (struct_obj.field_is_comptime_bits.get(ip, i)) { | |
| 1868 | // MLUGG TODO: this is kinda a problem... we don't necessarily know the opv field vals! | |
| 1869 | // for now i'm just not letting structs with comptime fields be opv :) | |
| 1870 | if (true) return null; | |
| 1871 | assertHasInits(ty, zcu); | |
| 1872 | field_val.* = struct_obj.field_defaults.get(ip)[i]; | |
| 2585 | 1873 | continue; |
| 2586 | 1874 | } |
| 2587 | const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]); | |
| 2588 | if (try field_ty.onePossibleValue(pt)) |field_opv| { | |
| 2589 | field_val.* = field_opv.toIntern(); | |
| 2590 | } else return null; | |
| 1875 | const field_ty = Type.fromInterned(struct_obj.field_types.get(ip)[i]); | |
| 1876 | field_val.* = (try field_ty.onePossibleValue(pt)).?.toIntern(); | |
| 2591 | 1877 | } |
| 2592 | 1878 | |
| 2593 | 1879 | // In this case the struct has no runtime-known fields and |
| ... | ... | @@ -2623,12 +1909,13 @@ pub fn onePossibleValue(starting_type: Type, pt: Zcu.PerThread) !?Value { |
| 2623 | 1909 | }, |
| 2624 | 1910 | |
| 2625 | 1911 | .union_type => { |
| 1912 | // MLUGG TODO: is this nonsensical or what!!!!!! | |
| 2626 | 1913 | const union_obj = ip.loadUnionType(ty.toIntern()); |
| 2627 | const tag_val = (try Type.fromInterned(union_obj.enum_tag_ty).onePossibleValue(pt)) orelse | |
| 1914 | const tag_val = (try Type.fromInterned(union_obj.enum_tag_type).onePossibleValue(pt)) orelse | |
| 2628 | 1915 | return null; |
| 2629 | 1916 | if (union_obj.field_types.len == 0) { |
| 2630 | 1917 | const only = try pt.intern(.{ .empty_enum_value = ty.toIntern() }); |
| 2631 | return Value.fromInterned(only); | |
| 1918 | return .fromInterned(only); | |
| 2632 | 1919 | } |
| 2633 | 1920 | const only_field_ty = union_obj.field_types.get(ip)[0]; |
| 2634 | 1921 | const val_val = (try Type.fromInterned(only_field_ty).onePossibleValue(pt)) orelse |
| ... | ... | @@ -2638,47 +1925,34 @@ pub fn onePossibleValue(starting_type: Type, pt: Zcu.PerThread) !?Value { |
| 2638 | 1925 | .tag = tag_val.toIntern(), |
| 2639 | 1926 | .val = val_val.toIntern(), |
| 2640 | 1927 | }); |
| 2641 | return Value.fromInterned(only); | |
| 1928 | return .fromInterned(only); | |
| 2642 | 1929 | }, |
| 2643 | 1930 | .opaque_type => return null, |
| 2644 | 1931 | .enum_type => { |
| 2645 | const enum_type = ip.loadEnumType(ty.toIntern()); | |
| 2646 | switch (enum_type.tag_mode) { | |
| 2647 | .nonexhaustive => { | |
| 2648 | if (enum_type.tag_ty == .comptime_int_type) return null; | |
| 2649 | ||
| 2650 | if (try Type.fromInterned(enum_type.tag_ty).onePossibleValue(pt)) |int_opv| { | |
| 2651 | const only = try pt.intern(.{ .enum_tag = .{ | |
| 2652 | .ty = ty.toIntern(), | |
| 2653 | .int = int_opv.toIntern(), | |
| 2654 | } }); | |
| 2655 | return Value.fromInterned(only); | |
| 2656 | } | |
| 2657 | ||
| 2658 | return null; | |
| 2659 | }, | |
| 2660 | .auto, .explicit => { | |
| 2661 | if (Type.fromInterned(enum_type.tag_ty).hasRuntimeBits(zcu)) return null; | |
| 2662 | ||
| 2663 | return Value.fromInterned(switch (enum_type.names.len) { | |
| 2664 | 0 => try pt.intern(.{ .empty_enum_value = ty.toIntern() }), | |
| 2665 | 1 => try pt.intern(.{ .enum_tag = .{ | |
| 2666 | .ty = ty.toIntern(), | |
| 2667 | .int = if (enum_type.values.len == 0) | |
| 2668 | (try pt.intValue(.fromInterned(enum_type.tag_ty), 0)).toIntern() | |
| 2669 | else | |
| 2670 | try ip.getCoercedInts( | |
| 2671 | gpa, | |
| 2672 | io, | |
| 2673 | pt.tid, | |
| 2674 | ip.indexToKey(enum_type.values.get(ip)[0]).int, | |
| 2675 | enum_type.tag_ty, | |
| 2676 | ), | |
| 2677 | } }), | |
| 2678 | else => return null, | |
| 2679 | }); | |
| 2680 | }, | |
| 1932 | const enum_obj = ip.loadEnumType(ty.toIntern()); | |
| 1933 | if (enum_obj.nonexhaustive) { | |
| 1934 | const int_opv = try Type.fromInterned(enum_obj.int_tag_type).onePossibleValue(pt) orelse return null; | |
| 1935 | return .fromInterned(try pt.intern(.{ .enum_tag = .{ | |
| 1936 | .ty = ty.toIntern(), | |
| 1937 | .int = int_opv.toIntern(), | |
| 1938 | } })); | |
| 1939 | } | |
| 1940 | // MLUGG TODO: this is to preserve existing semantics, i REALLY don't fuck with it... | |
| 1941 | if (enum_obj.int_tag_type == .comptime_int_type) { | |
| 1942 | return switch (enum_obj.field_names.len) { | |
| 1943 | 0 => .fromInterned(try pt.intern(.{ .empty_enum_value = ty.toIntern() })), | |
| 1944 | 1 => try pt.enumValueFieldIndex(ty, 0), | |
| 1945 | else => null, | |
| 1946 | }; | |
| 2681 | 1947 | } |
| 1948 | const int_tag_opv = try Type.fromInterned(enum_obj.int_tag_type).onePossibleValue(pt) orelse return null; | |
| 1949 | if (enum_obj.field_names.len == 0) { | |
| 1950 | return .fromInterned(try pt.intern(.{ .empty_enum_value = ty.toIntern() })); | |
| 1951 | } | |
| 1952 | return .fromInterned(try pt.intern(.{ .enum_tag = .{ | |
| 1953 | .ty = ty.toIntern(), | |
| 1954 | .int = int_tag_opv.toIntern(), | |
| 1955 | } })); | |
| 2682 | 1956 | }, |
| 2683 | 1957 | |
| 2684 | 1958 | // values, not types |
| ... | ... | @@ -2706,211 +1980,106 @@ pub fn onePossibleValue(starting_type: Type, pt: Zcu.PerThread) !?Value { |
| 2706 | 1980 | }; |
| 2707 | 1981 | } |
| 2708 | 1982 | |
| 2709 | /// During semantic analysis, instead call `ty.comptimeOnlySema` which | |
| 2710 | /// resolves field types rather than asserting they are already resolved. | |
| 1983 | /// Asserts that `ty` has its layout resolved. `generic_poison` will return `false`. | |
| 2711 | 1984 | pub fn comptimeOnly(ty: Type, zcu: *const Zcu) bool { |
| 2712 | return ty.comptimeOnlyInner(.normal, zcu, {}) catch unreachable; | |
| 2713 | } | |
| 2714 | ||
| 2715 | pub fn comptimeOnlySema(ty: Type, pt: Zcu.PerThread) SemaError!bool { | |
| 2716 | return try ty.comptimeOnlyInner(.sema, pt.zcu, pt.tid); | |
| 2717 | } | |
| 2718 | ||
| 2719 | /// `generic_poison` will return false. | |
| 2720 | /// May return false negatives when structs and unions are having their field types resolved. | |
| 2721 | pub fn comptimeOnlyInner( | |
| 2722 | ty: Type, | |
| 2723 | comptime strat: ResolveStrat, | |
| 2724 | zcu: strat.ZcuPtr(), | |
| 2725 | tid: strat.Tid(), | |
| 2726 | ) SemaError!bool { | |
| 2727 | 1985 | const ip = &zcu.intern_pool; |
| 2728 | const io = zcu.comp.io; | |
| 2729 | return switch (ty.toIntern()) { | |
| 2730 | .empty_tuple_type => false, | |
| 2731 | ||
| 2732 | else => switch (ip.indexToKey(ty.toIntern())) { | |
| 2733 | .int_type => false, | |
| 2734 | .ptr_type => |ptr_type| { | |
| 2735 | const child_ty = Type.fromInterned(ptr_type.child); | |
| 2736 | switch (child_ty.zigTypeTag(zcu)) { | |
| 2737 | .@"fn" => return !try child_ty.fnHasRuntimeBitsInner(strat, zcu, tid), | |
| 2738 | .@"opaque" => return false, | |
| 2739 | else => return child_ty.comptimeOnlyInner(strat, zcu, tid), | |
| 2740 | } | |
| 2741 | }, | |
| 2742 | .anyframe_type => |child| { | |
| 2743 | if (child == .none) return false; | |
| 2744 | return Type.fromInterned(child).comptimeOnlyInner(strat, zcu, tid); | |
| 2745 | }, | |
| 2746 | .array_type => |array_type| return Type.fromInterned(array_type.child).comptimeOnlyInner(strat, zcu, tid), | |
| 2747 | .vector_type => |vector_type| return Type.fromInterned(vector_type.child).comptimeOnlyInner(strat, zcu, tid), | |
| 2748 | .opt_type => |child| return Type.fromInterned(child).comptimeOnlyInner(strat, zcu, tid), | |
| 2749 | .error_union_type => |error_union_type| return Type.fromInterned(error_union_type.payload_type).comptimeOnlyInner(strat, zcu, tid), | |
| 2750 | ||
| 2751 | .error_set_type, | |
| 2752 | .inferred_error_set_type, | |
| 2753 | => false, | |
| 2754 | ||
| 2755 | // These are function bodies, not function pointers. | |
| 2756 | .func_type => true, | |
| 2757 | ||
| 2758 | .simple_type => |t| switch (t) { | |
| 2759 | .f16, | |
| 2760 | .f32, | |
| 2761 | .f64, | |
| 2762 | .f80, | |
| 2763 | .f128, | |
| 2764 | .usize, | |
| 2765 | .isize, | |
| 2766 | .c_char, | |
| 2767 | .c_short, | |
| 2768 | .c_ushort, | |
| 2769 | .c_int, | |
| 2770 | .c_uint, | |
| 2771 | .c_long, | |
| 2772 | .c_ulong, | |
| 2773 | .c_longlong, | |
| 2774 | .c_ulonglong, | |
| 2775 | .c_longdouble, | |
| 2776 | .anyopaque, | |
| 2777 | .bool, | |
| 2778 | .void, | |
| 2779 | .anyerror, | |
| 2780 | .adhoc_inferred_error_set, | |
| 2781 | .noreturn, | |
| 2782 | .generic_poison, | |
| 2783 | => false, | |
| 2784 | ||
| 2785 | .type, | |
| 2786 | .comptime_int, | |
| 2787 | .comptime_float, | |
| 2788 | .null, | |
| 2789 | .undefined, | |
| 2790 | .enum_literal, | |
| 2791 | => true, | |
| 2792 | }, | |
| 2793 | .struct_type => { | |
| 2794 | const struct_type = ip.loadStructType(ty.toIntern()); | |
| 2795 | // packed structs cannot be comptime-only because they have a well-defined | |
| 2796 | // memory layout and every field has a well-defined bit pattern. | |
| 2797 | if (struct_type.layout == .@"packed") | |
| 2798 | return false; | |
| 2799 | ||
| 2800 | return switch (strat) { | |
| 2801 | .normal => switch (struct_type.requiresComptime(ip)) { | |
| 2802 | .wip => unreachable, | |
| 2803 | .no => false, | |
| 2804 | .yes => true, | |
| 2805 | .unknown => unreachable, | |
| 2806 | }, | |
| 2807 | .sema => switch (struct_type.setRequiresComptimeWip(ip, io)) { | |
| 2808 | .no, .wip => false, | |
| 2809 | .yes => true, | |
| 2810 | .unknown => { | |
| 2811 | if (struct_type.flagsUnordered(ip).field_types_wip) { | |
| 2812 | struct_type.setRequiresComptime(ip, io, .unknown); | |
| 2813 | return false; | |
| 2814 | } | |
| 2815 | ||
| 2816 | errdefer struct_type.setRequiresComptime(ip, io, .unknown); | |
| 2817 | ||
| 2818 | const pt = strat.pt(zcu, tid); | |
| 2819 | try ty.resolveFields(pt); | |
| 2820 | ||
| 2821 | for (0..struct_type.field_types.len) |i_usize| { | |
| 2822 | const i: u32 = @intCast(i_usize); | |
| 2823 | if (struct_type.fieldIsComptime(ip, i)) continue; | |
| 2824 | const field_ty = struct_type.field_types.get(ip)[i]; | |
| 2825 | if (try Type.fromInterned(field_ty).comptimeOnlyInner(strat, zcu, tid)) { | |
| 2826 | // Note that this does not cause the layout to | |
| 2827 | // be considered resolved. Comptime-only types | |
| 2828 | // still maintain a layout of their | |
| 2829 | // runtime-known fields. | |
| 2830 | struct_type.setRequiresComptime(ip, io, .yes); | |
| 2831 | return true; | |
| 2832 | } | |
| 2833 | } | |
| 2834 | ||
| 2835 | struct_type.setRequiresComptime(ip, io, .no); | |
| 2836 | return false; | |
| 2837 | }, | |
| 2838 | }, | |
| 2839 | }; | |
| 2840 | }, | |
| 2841 | ||
| 2842 | .tuple_type => |tuple| { | |
| 2843 | for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| { | |
| 2844 | const have_comptime_val = val != .none; | |
| 2845 | if (!have_comptime_val and try Type.fromInterned(field_ty).comptimeOnlyInner(strat, zcu, tid)) return true; | |
| 2846 | } | |
| 2847 | return false; | |
| 2848 | }, | |
| 1986 | return switch (ip.indexToKey(ty.toIntern())) { | |
| 1987 | .array_type => |array_type| return Type.fromInterned(array_type.child).comptimeOnly(zcu), | |
| 1988 | .vector_type => |vector_type| return Type.fromInterned(vector_type.child).comptimeOnly(zcu), | |
| 1989 | .opt_type => |child| return Type.fromInterned(child).comptimeOnly(zcu), | |
| 1990 | .error_union_type => |error_union_type| return Type.fromInterned(error_union_type.payload_type).comptimeOnly(zcu), | |
| 1991 | .enum_type => return Type.fromInterned(ip.loadEnumType(ty.toIntern()).int_tag_type).comptimeOnly(zcu), | |
| 2849 | 1992 | |
| 2850 | .union_type => { | |
| 2851 | const union_type = ip.loadUnionType(ty.toIntern()); | |
| 2852 | return switch (strat) { | |
| 2853 | .normal => switch (union_type.requiresComptime(ip)) { | |
| 2854 | .wip => unreachable, | |
| 2855 | .no => false, | |
| 2856 | .yes => true, | |
| 2857 | .unknown => unreachable, | |
| 2858 | }, | |
| 2859 | .sema => switch (union_type.setRequiresComptimeWip(ip, io)) { | |
| 2860 | .no, .wip => return false, | |
| 2861 | .yes => return true, | |
| 2862 | .unknown => { | |
| 2863 | if (union_type.flagsUnordered(ip).status == .field_types_wip) { | |
| 2864 | union_type.setRequiresComptime(ip, io, .unknown); | |
| 2865 | return false; | |
| 2866 | } | |
| 2867 | ||
| 2868 | errdefer union_type.setRequiresComptime(ip, io, .unknown); | |
| 2869 | ||
| 2870 | const pt = strat.pt(zcu, tid); | |
| 2871 | try ty.resolveFields(pt); | |
| 2872 | ||
| 2873 | for (0..union_type.field_types.len) |field_idx| { | |
| 2874 | const field_ty = union_type.field_types.get(ip)[field_idx]; | |
| 2875 | if (try Type.fromInterned(field_ty).comptimeOnlyInner(strat, zcu, tid)) { | |
| 2876 | union_type.setRequiresComptime(ip, io, .yes); | |
| 2877 | return true; | |
| 2878 | } | |
| 2879 | } | |
| 2880 | ||
| 2881 | union_type.setRequiresComptime(ip, io, .no); | |
| 2882 | return false; | |
| 2883 | }, | |
| 2884 | }, | |
| 2885 | }; | |
| 2886 | }, | |
| 1993 | .int_type, | |
| 1994 | .ptr_type, | |
| 1995 | .anyframe_type, | |
| 1996 | .error_set_type, | |
| 1997 | .inferred_error_set_type, | |
| 1998 | .opaque_type, | |
| 1999 | => false, | |
| 2887 | 2000 | |
| 2888 | .opaque_type => false, | |
| 2001 | // These are function bodies, not function pointers. | |
| 2002 | .func_type => true, | |
| 2889 | 2003 | |
| 2890 | .enum_type => return Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty).comptimeOnlyInner(strat, zcu, tid), | |
| 2004 | .simple_type => |t| switch (t) { | |
| 2005 | .f16, | |
| 2006 | .f32, | |
| 2007 | .f64, | |
| 2008 | .f80, | |
| 2009 | .f128, | |
| 2010 | .usize, | |
| 2011 | .isize, | |
| 2012 | .c_char, | |
| 2013 | .c_short, | |
| 2014 | .c_ushort, | |
| 2015 | .c_int, | |
| 2016 | .c_uint, | |
| 2017 | .c_long, | |
| 2018 | .c_ulong, | |
| 2019 | .c_longlong, | |
| 2020 | .c_ulonglong, | |
| 2021 | .c_longdouble, | |
| 2022 | .anyopaque, | |
| 2023 | .bool, | |
| 2024 | .void, | |
| 2025 | .anyerror, | |
| 2026 | .adhoc_inferred_error_set, | |
| 2027 | .noreturn, | |
| 2028 | .generic_poison, | |
| 2029 | => false, | |
| 2891 | 2030 | |
| 2892 | // values, not types | |
| 2893 | .undef, | |
| 2894 | .simple_value, | |
| 2895 | .variable, | |
| 2896 | .@"extern", | |
| 2897 | .func, | |
| 2898 | .int, | |
| 2899 | .err, | |
| 2900 | .error_union, | |
| 2031 | .type, | |
| 2032 | .comptime_int, | |
| 2033 | .comptime_float, | |
| 2034 | .null, | |
| 2035 | .undefined, | |
| 2901 | 2036 | .enum_literal, |
| 2902 | .enum_tag, | |
| 2903 | .empty_enum_value, | |
| 2904 | .float, | |
| 2905 | .ptr, | |
| 2906 | .slice, | |
| 2907 | .opt, | |
| 2908 | .aggregate, | |
| 2909 | .un, | |
| 2910 | // memoization, not types | |
| 2911 | .memoized_call, | |
| 2912 | => unreachable, | |
| 2037 | => true, | |
| 2038 | }, | |
| 2039 | .struct_type => { | |
| 2040 | const struct_obj = ip.loadStructType(ty.toIntern()); | |
| 2041 | return switch (struct_obj.layout) { | |
| 2042 | .@"packed" => false, | |
| 2043 | .auto, .@"extern" => struct_obj.comptime_only, | |
| 2044 | }; | |
| 2045 | }, | |
| 2046 | .union_type => { | |
| 2047 | const union_obj = ip.loadUnionType(ty.toIntern()); | |
| 2048 | return switch (union_obj.layout) { | |
| 2049 | .@"packed" => false, | |
| 2050 | .auto, .@"extern" => union_obj.comptime_only, | |
| 2051 | }; | |
| 2913 | 2052 | }, |
| 2053 | .tuple_type => |tuple| { | |
| 2054 | for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| { | |
| 2055 | if (val != .none) continue; | |
| 2056 | if (!Type.fromInterned(field_ty).comptimeOnly(zcu)) continue; | |
| 2057 | return true; | |
| 2058 | } | |
| 2059 | return false; | |
| 2060 | }, | |
| 2061 | ||
| 2062 | // values, not types | |
| 2063 | .undef, | |
| 2064 | .simple_value, | |
| 2065 | .variable, | |
| 2066 | .@"extern", | |
| 2067 | .func, | |
| 2068 | .int, | |
| 2069 | .err, | |
| 2070 | .error_union, | |
| 2071 | .enum_literal, | |
| 2072 | .enum_tag, | |
| 2073 | .empty_enum_value, | |
| 2074 | .float, | |
| 2075 | .ptr, | |
| 2076 | .slice, | |
| 2077 | .opt, | |
| 2078 | .aggregate, | |
| 2079 | .un, | |
| 2080 | // memoization, not types | |
| 2081 | .memoized_call, | |
| 2082 | => unreachable, | |
| 2914 | 2083 | }; |
| 2915 | 2084 | } |
| 2916 | 2085 | |
| ... | ... | @@ -3056,20 +2225,18 @@ pub fn maxIntScalar(ty: Type, pt: Zcu.PerThread, dest_ty: Type) !Value { |
| 3056 | 2225 | /// Asserts the type is an enum or a union. |
| 3057 | 2226 | pub fn intTagType(ty: Type, zcu: *const Zcu) Type { |
| 3058 | 2227 | const ip = &zcu.intern_pool; |
| 3059 | return switch (ip.indexToKey(ty.toIntern())) { | |
| 3060 | .union_type => Type.fromInterned(ip.loadUnionType(ty.toIntern()).enum_tag_ty).intTagType(zcu), | |
| 3061 | .enum_type => Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty), | |
| 2228 | const enum_ty: Type = switch (ip.indexToKey(ty.toIntern())) { | |
| 2229 | .union_type => .fromInterned(ip.loadUnionType(ty.toIntern()).enum_tag_type), | |
| 2230 | .enum_type => ty, | |
| 3062 | 2231 | else => unreachable, |
| 3063 | 2232 | }; |
| 2233 | return .fromInterned(ip.loadEnumType(enum_ty.toIntern()).int_tag_type); | |
| 3064 | 2234 | } |
| 3065 | 2235 | |
| 3066 | 2236 | pub fn isNonexhaustiveEnum(ty: Type, zcu: *const Zcu) bool { |
| 3067 | 2237 | const ip = &zcu.intern_pool; |
| 3068 | 2238 | return switch (ip.indexToKey(ty.toIntern())) { |
| 3069 | .enum_type => switch (ip.loadEnumType(ty.toIntern()).tag_mode) { | |
| 3070 | .nonexhaustive => true, | |
| 3071 | .auto, .explicit => false, | |
| 3072 | }, | |
| 2239 | .enum_type => ip.loadEnumType(ty.toIntern()).nonexhaustive, | |
| 3073 | 2240 | else => false, |
| 3074 | 2241 | }; |
| 3075 | 2242 | } |
| ... | ... | @@ -3090,16 +2257,16 @@ pub fn errorSetNames(ty: Type, zcu: *const Zcu) InternPool.NullTerminatedString. |
| 3090 | 2257 | } |
| 3091 | 2258 | |
| 3092 | 2259 | pub fn enumFields(ty: Type, zcu: *const Zcu) InternPool.NullTerminatedString.Slice { |
| 3093 | return zcu.intern_pool.loadEnumType(ty.toIntern()).names; | |
| 2260 | return zcu.intern_pool.loadEnumType(ty.toIntern()).field_names; | |
| 3094 | 2261 | } |
| 3095 | 2262 | |
| 3096 | 2263 | pub fn enumFieldCount(ty: Type, zcu: *const Zcu) usize { |
| 3097 | return zcu.intern_pool.loadEnumType(ty.toIntern()).names.len; | |
| 2264 | return zcu.intern_pool.loadEnumType(ty.toIntern()).field_names.len; | |
| 3098 | 2265 | } |
| 3099 | 2266 | |
| 3100 | 2267 | pub fn enumFieldName(ty: Type, field_index: usize, zcu: *const Zcu) InternPool.NullTerminatedString { |
| 3101 | 2268 | const ip = &zcu.intern_pool; |
| 3102 | return ip.loadEnumType(ty.toIntern()).names.get(ip)[field_index]; | |
| 2269 | return ip.loadEnumType(ty.toIntern()).field_names.get(ip)[field_index]; | |
| 3103 | 2270 | } |
| 3104 | 2271 | |
| 3105 | 2272 | pub fn enumFieldIndex(ty: Type, field_name: InternPool.NullTerminatedString, zcu: *const Zcu) ?u32 { |
| ... | ... | @@ -3119,7 +2286,7 @@ pub fn enumTagFieldIndex(ty: Type, enum_tag: Value, zcu: *const Zcu) ?u32 { |
| 3119 | 2286 | .enum_tag => |info| info.int, |
| 3120 | 2287 | else => unreachable, |
| 3121 | 2288 | }; |
| 3122 | assert(ip.typeOf(int_tag) == enum_type.tag_ty); | |
| 2289 | assert(ip.typeOf(int_tag) == enum_type.int_tag_type); | |
| 3123 | 2290 | return enum_type.tagValueIndex(ip, int_tag); |
| 3124 | 2291 | } |
| 3125 | 2292 | |
| ... | ... | @@ -3127,7 +2294,7 @@ pub fn enumTagFieldIndex(ty: Type, enum_tag: Value, zcu: *const Zcu) ?u32 { |
| 3127 | 2294 | pub fn structFieldName(ty: Type, index: usize, zcu: *const Zcu) InternPool.OptionalNullTerminatedString { |
| 3128 | 2295 | const ip = &zcu.intern_pool; |
| 3129 | 2296 | return switch (ip.indexToKey(ty.toIntern())) { |
| 3130 | .struct_type => ip.loadStructType(ty.toIntern()).fieldName(ip, index).toOptional(), | |
| 2297 | .struct_type => ip.loadStructType(ty.toIntern()).field_names.get(ip)[index].toOptional(), | |
| 3131 | 2298 | .tuple_type => .none, |
| 3132 | 2299 | else => unreachable, |
| 3133 | 2300 | }; |
| ... | ... | @@ -3144,175 +2311,96 @@ pub fn structFieldCount(ty: Type, zcu: *const Zcu) u32 { |
| 3144 | 2311 | |
| 3145 | 2312 | /// Returns the field type. Supports structs and unions. |
| 3146 | 2313 | pub fn fieldType(ty: Type, index: usize, zcu: *const Zcu) Type { |
| 2314 | const ip = &zcu.intern_pool; | |
| 2315 | const types = switch (ip.indexToKey(ty.toIntern())) { | |
| 2316 | .struct_type => ip.loadStructType(ty.toIntern()).field_types, | |
| 2317 | .union_type => ip.loadUnionType(ty.toIntern()).field_types, | |
| 2318 | .tuple_type => |tuple| tuple.types, | |
| 2319 | else => unreachable, | |
| 2320 | }; | |
| 2321 | return .fromInterned(types.get(ip)[index]); | |
| 2322 | } | |
| 2323 | ||
| 2324 | // TODO MLUGG: clean up doc comments and usages of `{resolved,explicit}FieldAlignment` | |
| 2325 | ||
| 2326 | /// Returns the alignment of the given struct, tuple, or union field. | |
| 2327 | /// Asserts that the layout of `ty` is resolved. Asserts that `ty` is not packed. | |
| 2328 | /// Never returns `.none`, even if the field's alignment was not specified. | |
| 2329 | pub fn resolvedFieldAlignment(ty: Type, index: usize, zcu: *const Zcu) Alignment { | |
| 2330 | switch (ty.explicitFieldAlignment(index, zcu)) { | |
| 2331 | .none => {}, | |
| 2332 | else => |explicit| return explicit, | |
| 2333 | } | |
| 3147 | 2334 | const ip = &zcu.intern_pool; |
| 3148 | 2335 | return switch (ip.indexToKey(ty.toIntern())) { |
| 3149 | .struct_type => Type.fromInterned(ip.loadStructType(ty.toIntern()).field_types.get(ip)[index]), | |
| 2336 | .tuple_type => |tuple| Type.fromInterned(tuple.types.get(ip)[index]).abiAlignment(zcu), | |
| 2337 | .struct_type => { | |
| 2338 | const struct_obj = ip.loadStructType(ty.toIntern()); | |
| 2339 | const field_ty: Type = .fromInterned(struct_obj.field_types.get(ip)[index]); | |
| 2340 | return field_ty.defaultStructFieldAlignment(struct_obj.layout, zcu); | |
| 2341 | }, | |
| 3150 | 2342 | .union_type => { |
| 3151 | 2343 | const union_obj = ip.loadUnionType(ty.toIntern()); |
| 3152 | return Type.fromInterned(union_obj.field_types.get(ip)[index]); | |
| 2344 | const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[index]); | |
| 2345 | return field_ty.abiAlignment(zcu); | |
| 3153 | 2346 | }, |
| 3154 | .tuple_type => |tuple| Type.fromInterned(tuple.types.get(ip)[index]), | |
| 3155 | 2347 | else => unreachable, |
| 3156 | 2348 | }; |
| 3157 | 2349 | } |
| 3158 | 2350 | |
| 3159 | pub fn fieldAlignment(ty: Type, index: usize, zcu: *Zcu) Alignment { | |
| 3160 | return ty.fieldAlignmentInner(index, .normal, zcu, {}) catch unreachable; | |
| 3161 | } | |
| 3162 | ||
| 3163 | pub fn fieldAlignmentSema(ty: Type, index: usize, pt: Zcu.PerThread) SemaError!Alignment { | |
| 3164 | return try ty.fieldAlignmentInner(index, .sema, pt.zcu, pt.tid); | |
| 3165 | } | |
| 3166 | ||
| 3167 | /// Returns the field alignment. Supports structs and unions. | |
| 3168 | /// If `strat` is `.sema`, may perform type resolution. | |
| 3169 | /// Asserts the layout is not packed. | |
| 3170 | /// | |
| 3171 | /// Provide the struct field as the `ty`. | |
| 3172 | pub fn fieldAlignmentInner( | |
| 3173 | ty: Type, | |
| 3174 | index: usize, | |
| 3175 | comptime strat: ResolveStrat, | |
| 3176 | zcu: strat.ZcuPtr(), | |
| 3177 | tid: strat.Tid(), | |
| 3178 | ) SemaError!Alignment { | |
| 2351 | pub fn explicitFieldAlignment(ty: Type, index: usize, zcu: *const Zcu) Alignment { | |
| 3179 | 2352 | const ip = &zcu.intern_pool; |
| 3180 | switch (ip.indexToKey(ty.toIntern())) { | |
| 2353 | return switch (ip.indexToKey(ty.toIntern())) { | |
| 2354 | .tuple_type => .none, | |
| 3181 | 2355 | .struct_type => { |
| 3182 | const struct_type = ip.loadStructType(ty.toIntern()); | |
| 3183 | assert(struct_type.layout != .@"packed"); | |
| 3184 | const explicit_align = struct_type.fieldAlign(ip, index); | |
| 3185 | const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[index]); | |
| 3186 | return field_ty.structFieldAlignmentInner(explicit_align, struct_type.layout, strat, zcu, tid); | |
| 3187 | }, | |
| 3188 | .tuple_type => |tuple| { | |
| 3189 | return (try Type.fromInterned(tuple.types.get(ip)[index]).abiAlignmentInner( | |
| 3190 | strat.toLazy(), | |
| 3191 | zcu, | |
| 3192 | tid, | |
| 3193 | )).scalar; | |
| 2356 | const struct_obj = ip.loadStructType(ty.toIntern()); | |
| 2357 | assert(struct_obj.layout != .@"packed"); | |
| 2358 | if (struct_obj.field_aligns.len == 0) return .none; | |
| 2359 | return struct_obj.field_aligns.get(ip)[index]; | |
| 3194 | 2360 | }, |
| 3195 | 2361 | .union_type => { |
| 3196 | 2362 | const union_obj = ip.loadUnionType(ty.toIntern()); |
| 3197 | const layout = union_obj.flagsUnordered(ip).layout; | |
| 3198 | assert(layout != .@"packed"); | |
| 3199 | const explicit_align = union_obj.fieldAlign(ip, index); | |
| 3200 | const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[index]); | |
| 3201 | return field_ty.unionFieldAlignmentInner(explicit_align, layout, strat, zcu, tid); | |
| 2363 | assert(union_obj.layout != .@"packed"); | |
| 2364 | if (union_obj.field_aligns.len == 0) return .none; | |
| 2365 | return union_obj.field_aligns.get(ip)[index]; | |
| 3202 | 2366 | }, |
| 3203 | 2367 | else => unreachable, |
| 3204 | } | |
| 2368 | }; | |
| 3205 | 2369 | } |
| 3206 | 2370 | |
| 3207 | /// Returns the alignment of a non-packed struct field. Assert the layout is not packed. | |
| 3208 | /// | |
| 3209 | /// Asserts that all resolution needed was done. | |
| 3210 | pub fn structFieldAlignment( | |
| 2371 | /// Returns the alignment a struct field will have if not explicitly specified. | |
| 2372 | /// Asserts that the layout of `field_ty` is resolved. Asserts that `layout` is not `.@"packed"`. | |
| 2373 | pub fn defaultStructFieldAlignment( | |
| 3211 | 2374 | field_ty: Type, |
| 3212 | explicit_alignment: InternPool.Alignment, | |
| 3213 | 2375 | layout: std.builtin.Type.ContainerLayout, |
| 3214 | zcu: *Zcu, | |
| 2376 | zcu: *const Zcu, | |
| 3215 | 2377 | ) Alignment { |
| 3216 | return field_ty.structFieldAlignmentInner( | |
| 3217 | explicit_alignment, | |
| 3218 | layout, | |
| 3219 | .normal, | |
| 3220 | zcu, | |
| 3221 | {}, | |
| 3222 | ) catch unreachable; | |
| 3223 | } | |
| 3224 | ||
| 3225 | /// Returns the alignment of a non-packed struct field. Assert the layout is not packed. | |
| 3226 | /// May do type resolution when needed. | |
| 3227 | /// Asserts that all resolution needed was done. | |
| 3228 | pub fn structFieldAlignmentSema( | |
| 3229 | field_ty: Type, | |
| 3230 | explicit_alignment: InternPool.Alignment, | |
| 3231 | layout: std.builtin.Type.ContainerLayout, | |
| 3232 | pt: Zcu.PerThread, | |
| 3233 | ) SemaError!Alignment { | |
| 3234 | return try field_ty.structFieldAlignmentInner( | |
| 3235 | explicit_alignment, | |
| 3236 | layout, | |
| 3237 | .sema, | |
| 3238 | pt.zcu, | |
| 3239 | pt.tid, | |
| 3240 | ); | |
| 3241 | } | |
| 3242 | ||
| 3243 | /// Returns the alignment of a non-packed struct field. Asserts the layout is not packed. | |
| 3244 | /// If `strat` is `.sema`, may perform type resolution. | |
| 3245 | pub fn structFieldAlignmentInner( | |
| 3246 | field_ty: Type, | |
| 3247 | explicit_alignment: Alignment, | |
| 3248 | layout: std.builtin.Type.ContainerLayout, | |
| 3249 | comptime strat: Type.ResolveStrat, | |
| 3250 | zcu: strat.ZcuPtr(), | |
| 3251 | tid: strat.Tid(), | |
| 3252 | ) SemaError!Alignment { | |
| 3253 | assert(layout != .@"packed"); | |
| 3254 | if (explicit_alignment != .none) return explicit_alignment; | |
| 3255 | const ty_abi_align = (try field_ty.abiAlignmentInner( | |
| 3256 | strat.toLazy(), | |
| 3257 | zcu, | |
| 3258 | tid, | |
| 3259 | )).scalar; | |
| 3260 | switch (layout) { | |
| 2378 | const overalign_big_int = switch (layout) { | |
| 3261 | 2379 | .@"packed" => unreachable, |
| 3262 | .auto => if (zcu.getTarget().ofmt != .c) return ty_abi_align, | |
| 3263 | .@"extern" => {}, | |
| 3264 | } | |
| 3265 | // extern | |
| 3266 | if (field_ty.isAbiInt(zcu) and field_ty.intInfo(zcu).bits >= 128) { | |
| 3267 | return ty_abi_align.maxStrict(.@"16"); | |
| 2380 | .auto => zcu.getTarget().ofmt == .c, | |
| 2381 | .@"extern" => true, | |
| 2382 | }; | |
| 2383 | const abi_align = field_ty.abiAlignment(zcu); | |
| 2384 | assert(abi_align != .none); | |
| 2385 | if (overalign_big_int and field_ty.isAbiInt(zcu) and field_ty.intInfo(zcu).bits >= 128) { | |
| 2386 | return abi_align.maxStrict(.@"16"); | |
| 3268 | 2387 | } |
| 3269 | return ty_abi_align; | |
| 3270 | } | |
| 3271 | ||
| 3272 | pub fn unionFieldAlignmentSema( | |
| 3273 | field_ty: Type, | |
| 3274 | explicit_alignment: Alignment, | |
| 3275 | layout: std.builtin.Type.ContainerLayout, | |
| 3276 | pt: Zcu.PerThread, | |
| 3277 | ) SemaError!Alignment { | |
| 3278 | return field_ty.unionFieldAlignmentInner( | |
| 3279 | explicit_alignment, | |
| 3280 | layout, | |
| 3281 | .sema, | |
| 3282 | pt.zcu, | |
| 3283 | pt.tid, | |
| 3284 | ); | |
| 2388 | return abi_align; | |
| 3285 | 2389 | } |
| 3286 | 2390 | |
| 3287 | pub fn unionFieldAlignmentInner( | |
| 3288 | field_ty: Type, | |
| 3289 | explicit_alignment: Alignment, | |
| 3290 | layout: std.builtin.Type.ContainerLayout, | |
| 3291 | comptime strat: Type.ResolveStrat, | |
| 3292 | zcu: strat.ZcuPtr(), | |
| 3293 | tid: strat.Tid(), | |
| 3294 | ) SemaError!Alignment { | |
| 3295 | assert(layout != .@"packed"); | |
| 3296 | if (explicit_alignment != .none) return explicit_alignment; | |
| 3297 | if (field_ty.isNoReturn(zcu)) return .none; | |
| 3298 | return (try field_ty.abiAlignmentInner(strat.toLazy(), zcu, tid)).scalar; | |
| 3299 | } | |
| 3300 | ||
| 3301 | pub fn structFieldDefaultValue(ty: Type, index: usize, zcu: *const Zcu) Value { | |
| 2391 | pub fn structFieldDefaultValue(ty: Type, index: usize, zcu: *const Zcu) ?Value { | |
| 3302 | 2392 | const ip = &zcu.intern_pool; |
| 3303 | 2393 | switch (ip.indexToKey(ty.toIntern())) { |
| 3304 | 2394 | .struct_type => { |
| 3305 | const struct_type = ip.loadStructType(ty.toIntern()); | |
| 3306 | const val = struct_type.fieldInit(ip, index); | |
| 3307 | // TODO: avoid using `unreachable` to indicate this. | |
| 3308 | if (val == .none) return Value.@"unreachable"; | |
| 3309 | return Value.fromInterned(val); | |
| 2395 | const field_defaults = ip.loadStructType(ty.toIntern()).field_defaults.get(ip); | |
| 2396 | if (field_defaults.len == 0) return null; | |
| 2397 | if (field_defaults[index] == .none) return null; | |
| 2398 | return .fromInterned(field_defaults[index]); | |
| 3310 | 2399 | }, |
| 3311 | 2400 | .tuple_type => |tuple| { |
| 3312 | 2401 | const val = tuple.values.get(ip)[index]; |
| 3313 | // TODO: avoid using `unreachable` to indicate this. | |
| 3314 | if (val == .none) return Value.@"unreachable"; | |
| 3315 | return Value.fromInterned(val); | |
| 2402 | if (val == .none) return null; | |
| 2403 | return .fromInterned(val); | |
| 3316 | 2404 | }, |
| 3317 | 2405 | else => unreachable, |
| 3318 | 2406 | } |
| ... | ... | @@ -3324,9 +2412,9 @@ pub fn structFieldValueComptime(ty: Type, pt: Zcu.PerThread, index: usize) !?Val |
| 3324 | 2412 | switch (ip.indexToKey(ty.toIntern())) { |
| 3325 | 2413 | .struct_type => { |
| 3326 | 2414 | const struct_type = ip.loadStructType(ty.toIntern()); |
| 3327 | if (struct_type.fieldIsComptime(ip, index)) { | |
| 3328 | assert(struct_type.haveFieldInits(ip)); | |
| 3329 | return Value.fromInterned(struct_type.field_inits.get(ip)[index]); | |
| 2415 | if (struct_type.field_is_comptime_bits.get(ip, index)) { | |
| 2416 | assertHasInits(ty, zcu); | |
| 2417 | return .fromInterned(struct_type.field_defaults.get(ip)[index]); | |
| 3330 | 2418 | } else { |
| 3331 | 2419 | return Type.fromInterned(struct_type.field_types.get(ip)[index]).onePossibleValue(pt); |
| 3332 | 2420 | } |
| ... | ... | @@ -3336,7 +2424,7 @@ pub fn structFieldValueComptime(ty: Type, pt: Zcu.PerThread, index: usize) !?Val |
| 3336 | 2424 | if (val == .none) { |
| 3337 | 2425 | return Type.fromInterned(tuple.types.get(ip)[index]).onePossibleValue(pt); |
| 3338 | 2426 | } else { |
| 3339 | return Value.fromInterned(val); | |
| 2427 | return .fromInterned(val); | |
| 3340 | 2428 | } |
| 3341 | 2429 | }, |
| 3342 | 2430 | else => unreachable, |
| ... | ... | @@ -3346,7 +2434,7 @@ pub fn structFieldValueComptime(ty: Type, pt: Zcu.PerThread, index: usize) !?Val |
| 3346 | 2434 | pub fn structFieldIsComptime(ty: Type, index: usize, zcu: *const Zcu) bool { |
| 3347 | 2435 | const ip = &zcu.intern_pool; |
| 3348 | 2436 | return switch (ip.indexToKey(ty.toIntern())) { |
| 3349 | .struct_type => ip.loadStructType(ty.toIntern()).fieldIsComptime(ip, index), | |
| 2437 | .struct_type => ip.loadStructType(ty.toIntern()).field_is_comptime_bits.get(ip, index), | |
| 3350 | 2438 | .tuple_type => |tuple| tuple.values.get(ip)[index] != .none, |
| 3351 | 2439 | else => unreachable, |
| 3352 | 2440 | }; |
| ... | ... | @@ -3357,15 +2445,15 @@ pub const FieldOffset = struct { |
| 3357 | 2445 | offset: u64, |
| 3358 | 2446 | }; |
| 3359 | 2447 | |
| 3360 | /// Supports structs and unions. | |
| 2448 | /// Supports structs, tuples, and unions. | |
| 3361 | 2449 | pub fn structFieldOffset(ty: Type, index: usize, zcu: *const Zcu) u64 { |
| 2450 | assertHasLayout(ty, zcu); | |
| 3362 | 2451 | const ip = &zcu.intern_pool; |
| 3363 | 2452 | switch (ip.indexToKey(ty.toIntern())) { |
| 3364 | 2453 | .struct_type => { |
| 3365 | 2454 | const struct_type = ip.loadStructType(ty.toIntern()); |
| 3366 | assert(struct_type.haveLayout(ip)); | |
| 3367 | 2455 | assert(struct_type.layout != .@"packed"); |
| 3368 | return struct_type.offsets.get(ip)[index]; | |
| 2456 | return struct_type.field_offsets.get(ip)[index]; | |
| 3369 | 2457 | }, |
| 3370 | 2458 | |
| 3371 | 2459 | .tuple_type => |tuple| { |
| ... | ... | @@ -3391,7 +2479,7 @@ pub fn structFieldOffset(ty: Type, index: usize, zcu: *const Zcu) u64 { |
| 3391 | 2479 | |
| 3392 | 2480 | .union_type => { |
| 3393 | 2481 | const union_type = ip.loadUnionType(ty.toIntern()); |
| 3394 | if (!union_type.hasTag(ip)) | |
| 2482 | if (union_type.runtime_tag == .none) | |
| 3395 | 2483 | return 0; |
| 3396 | 2484 | const layout = Type.getUnionLayout(union_type, zcu); |
| 3397 | 2485 | if (layout.tag_align.compare(.gte, layout.payload_align)) { |
| ... | ... | @@ -3414,7 +2502,7 @@ pub fn srcLocOrNull(ty: Type, zcu: *Zcu) ?Zcu.LazySrcLoc { |
| 3414 | 2502 | .struct_type, .union_type, .opaque_type, .enum_type => |info| switch (info) { |
| 3415 | 2503 | .declared => |d| d.zir_index, |
| 3416 | 2504 | .reified => |r| r.zir_index, |
| 3417 | .generated_tag => |gt| ip.loadUnionType(gt.union_type).zir_index, | |
| 2505 | .generated_union_tag => |union_ty| ip.loadUnionType(union_ty).zir_index, | |
| 3418 | 2506 | }, |
| 3419 | 2507 | else => return null, |
| 3420 | 2508 | }, |
| ... | ... | @@ -3438,8 +2526,8 @@ pub fn isTuple(ty: Type, zcu: *const Zcu) bool { |
| 3438 | 2526 | }; |
| 3439 | 2527 | } |
| 3440 | 2528 | |
| 3441 | /// Traverses optional child types and error union payloads until the type | |
| 3442 | /// is not a pointer. For `E!?u32`, returns `u32`; for `*u8`, returns `*u8`. | |
| 2529 | /// Traverses optional child types and error union payloads until the type is neither of those. | |
| 2530 | /// For `E!?u32`, returns `u32`; for `*u8`, returns `*u8`. | |
| 3443 | 2531 | pub fn optEuBaseType(ty: Type, zcu: *const Zcu) Type { |
| 3444 | 2532 | var cur = ty; |
| 3445 | 2533 | while (true) switch (cur.zigTypeTag(zcu)) { |
| ... | ... | @@ -3488,7 +2576,7 @@ pub fn typeDeclInstAllowGeneratedTag(ty: Type, zcu: *const Zcu) ?InternPool.Trac |
| 3488 | 2576 | .union_type => ip.loadUnionType(ty.toIntern()).zir_index, |
| 3489 | 2577 | .enum_type => |e| switch (e) { |
| 3490 | 2578 | .declared, .reified => ip.loadEnumType(ty.toIntern()).zir_index.unwrap().?, |
| 3491 | .generated_tag => |gt| ip.loadUnionType(gt.union_type).zir_index, | |
| 2579 | .generated_union_tag => |union_ty| ip.loadUnionType(union_ty).zir_index, | |
| 3492 | 2580 | }, |
| 3493 | 2581 | .opaque_type => ip.loadOpaqueType(ty.toIntern()).zir_index, |
| 3494 | 2582 | else => null, |
| ... | ... | @@ -3505,7 +2593,7 @@ pub fn typeDeclSrcLine(ty: Type, zcu: *Zcu) ?u32 { |
| 3505 | 2593 | .struct_type, .union_type, .opaque_type, .enum_type => |info| switch (info) { |
| 3506 | 2594 | .declared => |d| d.zir_index, |
| 3507 | 2595 | .reified => |r| r.zir_index, |
| 3508 | .generated_tag => |gt| ip.loadUnionType(gt.union_type).zir_index, | |
| 2596 | .generated_union_tag => |union_ty| ip.loadUnionType(union_ty).zir_index, | |
| 3509 | 2597 | }, |
| 3510 | 2598 | else => return null, |
| 3511 | 2599 | }; |
| ... | ... | @@ -3520,10 +2608,10 @@ pub fn typeDeclSrcLine(ty: Type, zcu: *Zcu) ?u32 { |
| 3520 | 2608 | .struct_init, .struct_init_ref => zir.extraData(Zir.Inst.StructInit, inst.data.pl_node.payload_index).data.abs_line, |
| 3521 | 2609 | .struct_init_anon => zir.extraData(Zir.Inst.StructInitAnon, inst.data.pl_node.payload_index).data.abs_line, |
| 3522 | 2610 | .extended => switch (inst.data.extended.opcode) { |
| 3523 | .struct_decl => zir.extraData(Zir.Inst.StructDecl, inst.data.extended.operand).data.src_line, | |
| 3524 | .union_decl => zir.extraData(Zir.Inst.UnionDecl, inst.data.extended.operand).data.src_line, | |
| 3525 | .enum_decl => zir.extraData(Zir.Inst.EnumDecl, inst.data.extended.operand).data.src_line, | |
| 3526 | .opaque_decl => zir.extraData(Zir.Inst.OpaqueDecl, inst.data.extended.operand).data.src_line, | |
| 2611 | .struct_decl => zir.getStructDecl(info.inst).src_line, | |
| 2612 | .union_decl => zir.getUnionDecl(info.inst).src_line, | |
| 2613 | .enum_decl => zir.getEnumDecl(info.inst).src_line, | |
| 2614 | .opaque_decl => zir.getOpaqueDecl(info.inst).src_line, | |
| 3527 | 2615 | .reify_enum => zir.extraData(Zir.Inst.ReifyEnum, inst.data.extended.operand).data.src_line, |
| 3528 | 2616 | .reify_struct => zir.extraData(Zir.Inst.ReifyStruct, inst.data.extended.operand).data.src_line, |
| 3529 | 2617 | .reify_union => zir.extraData(Zir.Inst.ReifyUnion, inst.data.extended.operand).data.src_line, |
| ... | ... | @@ -3594,330 +2682,8 @@ pub fn packedStructFieldPtrInfo( |
| 3594 | 2682 | }; |
| 3595 | 2683 | } |
| 3596 | 2684 | |
| 3597 | pub fn resolveLayout(ty: Type, pt: Zcu.PerThread) SemaError!void { | |
| 3598 | const zcu = pt.zcu; | |
| 3599 | const ip = &zcu.intern_pool; | |
| 3600 | switch (ty.zigTypeTag(zcu)) { | |
| 3601 | .@"struct" => switch (ip.indexToKey(ty.toIntern())) { | |
| 3602 | .tuple_type => |tuple_type| for (0..tuple_type.types.len) |i| { | |
| 3603 | const field_ty = Type.fromInterned(tuple_type.types.get(ip)[i]); | |
| 3604 | try field_ty.resolveLayout(pt); | |
| 3605 | }, | |
| 3606 | .struct_type => return ty.resolveStructInner(pt, .layout), | |
| 3607 | else => unreachable, | |
| 3608 | }, | |
| 3609 | .@"union" => return ty.resolveUnionInner(pt, .layout), | |
| 3610 | .array => { | |
| 3611 | if (ty.arrayLenIncludingSentinel(zcu) == 0) return; | |
| 3612 | const elem_ty = ty.childType(zcu); | |
| 3613 | return elem_ty.resolveLayout(pt); | |
| 3614 | }, | |
| 3615 | .optional => { | |
| 3616 | const payload_ty = ty.optionalChild(zcu); | |
| 3617 | return payload_ty.resolveLayout(pt); | |
| 3618 | }, | |
| 3619 | .error_union => { | |
| 3620 | const payload_ty = ty.errorUnionPayload(zcu); | |
| 3621 | return payload_ty.resolveLayout(pt); | |
| 3622 | }, | |
| 3623 | .@"fn" => { | |
| 3624 | const info = zcu.typeToFunc(ty).?; | |
| 3625 | if (info.is_generic) { | |
| 3626 | // Resolving of generic function types is deferred to when | |
| 3627 | // the function is instantiated. | |
| 3628 | return; | |
| 3629 | } | |
| 3630 | for (0..info.param_types.len) |i| { | |
| 3631 | const param_ty = info.param_types.get(ip)[i]; | |
| 3632 | try Type.fromInterned(param_ty).resolveLayout(pt); | |
| 3633 | } | |
| 3634 | try Type.fromInterned(info.return_type).resolveLayout(pt); | |
| 3635 | }, | |
| 3636 | else => {}, | |
| 3637 | } | |
| 3638 | } | |
| 3639 | ||
| 3640 | pub fn resolveFields(ty: Type, pt: Zcu.PerThread) SemaError!void { | |
| 3641 | const ip = &pt.zcu.intern_pool; | |
| 3642 | const ty_ip = ty.toIntern(); | |
| 3643 | ||
| 3644 | switch (ty_ip) { | |
| 3645 | .none => unreachable, | |
| 3646 | ||
| 3647 | .u0_type, | |
| 3648 | .i0_type, | |
| 3649 | .u1_type, | |
| 3650 | .u8_type, | |
| 3651 | .i8_type, | |
| 3652 | .u16_type, | |
| 3653 | .i16_type, | |
| 3654 | .u29_type, | |
| 3655 | .u32_type, | |
| 3656 | .i32_type, | |
| 3657 | .u64_type, | |
| 3658 | .i64_type, | |
| 3659 | .u80_type, | |
| 3660 | .u128_type, | |
| 3661 | .i128_type, | |
| 3662 | .usize_type, | |
| 3663 | .isize_type, | |
| 3664 | .c_char_type, | |
| 3665 | .c_short_type, | |
| 3666 | .c_ushort_type, | |
| 3667 | .c_int_type, | |
| 3668 | .c_uint_type, | |
| 3669 | .c_long_type, | |
| 3670 | .c_ulong_type, | |
| 3671 | .c_longlong_type, | |
| 3672 | .c_ulonglong_type, | |
| 3673 | .c_longdouble_type, | |
| 3674 | .f16_type, | |
| 3675 | .f32_type, | |
| 3676 | .f64_type, | |
| 3677 | .f80_type, | |
| 3678 | .f128_type, | |
| 3679 | .anyopaque_type, | |
| 3680 | .bool_type, | |
| 3681 | .void_type, | |
| 3682 | .type_type, | |
| 3683 | .anyerror_type, | |
| 3684 | .adhoc_inferred_error_set_type, | |
| 3685 | .comptime_int_type, | |
| 3686 | .comptime_float_type, | |
| 3687 | .noreturn_type, | |
| 3688 | .anyframe_type, | |
| 3689 | .null_type, | |
| 3690 | .undefined_type, | |
| 3691 | .enum_literal_type, | |
| 3692 | .ptr_usize_type, | |
| 3693 | .ptr_const_comptime_int_type, | |
| 3694 | .manyptr_u8_type, | |
| 3695 | .manyptr_const_u8_type, | |
| 3696 | .manyptr_const_u8_sentinel_0_type, | |
| 3697 | .slice_const_u8_type, | |
| 3698 | .slice_const_u8_sentinel_0_type, | |
| 3699 | .optional_noreturn_type, | |
| 3700 | .anyerror_void_error_union_type, | |
| 3701 | .generic_poison_type, | |
| 3702 | .empty_tuple_type, | |
| 3703 | => {}, | |
| 3704 | ||
| 3705 | .undef => unreachable, | |
| 3706 | .zero => unreachable, | |
| 3707 | .zero_usize => unreachable, | |
| 3708 | .zero_u1 => unreachable, | |
| 3709 | .zero_u8 => unreachable, | |
| 3710 | .one => unreachable, | |
| 3711 | .one_usize => unreachable, | |
| 3712 | .one_u1 => unreachable, | |
| 3713 | .one_u8 => unreachable, | |
| 3714 | .four_u8 => unreachable, | |
| 3715 | .negative_one => unreachable, | |
| 3716 | .void_value => unreachable, | |
| 3717 | .unreachable_value => unreachable, | |
| 3718 | .null_value => unreachable, | |
| 3719 | .bool_true => unreachable, | |
| 3720 | .bool_false => unreachable, | |
| 3721 | .empty_tuple => unreachable, | |
| 3722 | ||
| 3723 | else => switch (ty_ip.unwrap(ip).getTag(ip)) { | |
| 3724 | .type_struct, | |
| 3725 | .type_struct_packed, | |
| 3726 | .type_struct_packed_inits, | |
| 3727 | => return ty.resolveStructInner(pt, .fields), | |
| 3728 | ||
| 3729 | .type_union => return ty.resolveUnionInner(pt, .fields), | |
| 3730 | ||
| 3731 | else => {}, | |
| 3732 | }, | |
| 3733 | } | |
| 3734 | } | |
| 3735 | ||
| 3736 | pub fn resolveFully(ty: Type, pt: Zcu.PerThread) SemaError!void { | |
| 3737 | const zcu = pt.zcu; | |
| 3738 | const ip = &zcu.intern_pool; | |
| 3739 | ||
| 3740 | switch (ty.zigTypeTag(zcu)) { | |
| 3741 | .type, | |
| 3742 | .void, | |
| 3743 | .bool, | |
| 3744 | .noreturn, | |
| 3745 | .int, | |
| 3746 | .float, | |
| 3747 | .comptime_float, | |
| 3748 | .comptime_int, | |
| 3749 | .undefined, | |
| 3750 | .null, | |
| 3751 | .error_set, | |
| 3752 | .@"enum", | |
| 3753 | .@"opaque", | |
| 3754 | .frame, | |
| 3755 | .@"anyframe", | |
| 3756 | .vector, | |
| 3757 | .enum_literal, | |
| 3758 | => {}, | |
| 3759 | ||
| 3760 | .pointer => return ty.childType(zcu).resolveFully(pt), | |
| 3761 | .array => return ty.childType(zcu).resolveFully(pt), | |
| 3762 | .optional => return ty.optionalChild(zcu).resolveFully(pt), | |
| 3763 | .error_union => return ty.errorUnionPayload(zcu).resolveFully(pt), | |
| 3764 | .@"fn" => { | |
| 3765 | const info = zcu.typeToFunc(ty).?; | |
| 3766 | if (info.is_generic) return; | |
| 3767 | for (0..info.param_types.len) |i| { | |
| 3768 | const param_ty = info.param_types.get(ip)[i]; | |
| 3769 | try Type.fromInterned(param_ty).resolveFully(pt); | |
| 3770 | } | |
| 3771 | try Type.fromInterned(info.return_type).resolveFully(pt); | |
| 3772 | }, | |
| 3773 | ||
| 3774 | .@"struct" => switch (ip.indexToKey(ty.toIntern())) { | |
| 3775 | .tuple_type => |tuple_type| for (0..tuple_type.types.len) |i| { | |
| 3776 | const field_ty = Type.fromInterned(tuple_type.types.get(ip)[i]); | |
| 3777 | try field_ty.resolveFully(pt); | |
| 3778 | }, | |
| 3779 | .struct_type => return ty.resolveStructInner(pt, .full), | |
| 3780 | else => unreachable, | |
| 3781 | }, | |
| 3782 | .@"union" => return ty.resolveUnionInner(pt, .full), | |
| 3783 | } | |
| 3784 | } | |
| 3785 | ||
| 3786 | pub fn resolveStructFieldInits(ty: Type, pt: Zcu.PerThread) SemaError!void { | |
| 3787 | // TODO: stop calling this for tuples! | |
| 3788 | _ = pt.zcu.typeToStruct(ty) orelse return; | |
| 3789 | return ty.resolveStructInner(pt, .inits); | |
| 3790 | } | |
| 3791 | ||
| 3792 | pub fn resolveStructAlignment(ty: Type, pt: Zcu.PerThread) SemaError!void { | |
| 3793 | return ty.resolveStructInner(pt, .alignment); | |
| 3794 | } | |
| 3795 | ||
| 3796 | pub fn resolveUnionAlignment(ty: Type, pt: Zcu.PerThread) SemaError!void { | |
| 3797 | return ty.resolveUnionInner(pt, .alignment); | |
| 3798 | } | |
| 3799 | ||
| 3800 | /// `ty` must be a struct. | |
| 3801 | fn resolveStructInner( | |
| 3802 | ty: Type, | |
| 3803 | pt: Zcu.PerThread, | |
| 3804 | resolution: enum { fields, inits, alignment, layout, full }, | |
| 3805 | ) SemaError!void { | |
| 3806 | const zcu = pt.zcu; | |
| 3807 | const gpa = zcu.gpa; | |
| 3808 | ||
| 3809 | const struct_obj = zcu.typeToStruct(ty).?; | |
| 3810 | const owner: InternPool.AnalUnit = .wrap(.{ .type = ty.toIntern() }); | |
| 3811 | ||
| 3812 | if (zcu.failed_analysis.contains(owner) or zcu.transitive_failed_analysis.contains(owner)) { | |
| 3813 | return error.AnalysisFail; | |
| 3814 | } | |
| 3815 | ||
| 3816 | if (zcu.comp.debugIncremental()) { | |
| 3817 | const info = try zcu.incremental_debug_state.getUnitInfo(gpa, owner); | |
| 3818 | info.last_update_gen = zcu.generation; | |
| 3819 | } | |
| 3820 | ||
| 3821 | var analysis_arena = std.heap.ArenaAllocator.init(gpa); | |
| 3822 | defer analysis_arena.deinit(); | |
| 3823 | ||
| 3824 | var comptime_err_ret_trace = std.array_list.Managed(Zcu.LazySrcLoc).init(gpa); | |
| 3825 | defer comptime_err_ret_trace.deinit(); | |
| 3826 | ||
| 3827 | const zir = zcu.namespacePtr(struct_obj.namespace).fileScope(zcu).zir.?; | |
| 3828 | var sema: Sema = .{ | |
| 3829 | .pt = pt, | |
| 3830 | .gpa = gpa, | |
| 3831 | .arena = analysis_arena.allocator(), | |
| 3832 | .code = zir, | |
| 3833 | .owner = owner, | |
| 3834 | .func_index = .none, | |
| 3835 | .func_is_naked = false, | |
| 3836 | .fn_ret_ty = Type.void, | |
| 3837 | .fn_ret_ty_ies = null, | |
| 3838 | .comptime_err_ret_trace = &comptime_err_ret_trace, | |
| 3839 | }; | |
| 3840 | defer sema.deinit(); | |
| 3841 | ||
| 3842 | (switch (resolution) { | |
| 3843 | .fields => sema.resolveStructFieldTypes(ty.toIntern(), struct_obj), | |
| 3844 | .inits => sema.resolveStructFieldInits(ty), | |
| 3845 | .alignment => sema.resolveStructAlignment(ty.toIntern(), struct_obj), | |
| 3846 | .layout => sema.resolveStructLayout(ty), | |
| 3847 | .full => sema.resolveStructFully(ty), | |
| 3848 | }) catch |err| switch (err) { | |
| 3849 | error.AnalysisFail => { | |
| 3850 | if (!zcu.failed_analysis.contains(owner)) { | |
| 3851 | try zcu.transitive_failed_analysis.put(gpa, owner, {}); | |
| 3852 | } | |
| 3853 | return error.AnalysisFail; | |
| 3854 | }, | |
| 3855 | error.OutOfMemory, error.Canceled => |e| return e, | |
| 3856 | }; | |
| 3857 | } | |
| 3858 | ||
| 3859 | /// `ty` must be a union. | |
| 3860 | fn resolveUnionInner( | |
| 3861 | ty: Type, | |
| 3862 | pt: Zcu.PerThread, | |
| 3863 | resolution: enum { fields, alignment, layout, full }, | |
| 3864 | ) SemaError!void { | |
| 3865 | const zcu = pt.zcu; | |
| 3866 | const gpa = zcu.gpa; | |
| 3867 | ||
| 3868 | const union_obj = zcu.typeToUnion(ty).?; | |
| 3869 | const owner: InternPool.AnalUnit = .wrap(.{ .type = ty.toIntern() }); | |
| 3870 | ||
| 3871 | if (zcu.failed_analysis.contains(owner) or zcu.transitive_failed_analysis.contains(owner)) { | |
| 3872 | return error.AnalysisFail; | |
| 3873 | } | |
| 3874 | ||
| 3875 | if (zcu.comp.debugIncremental()) { | |
| 3876 | const info = try zcu.incremental_debug_state.getUnitInfo(gpa, owner); | |
| 3877 | info.last_update_gen = zcu.generation; | |
| 3878 | } | |
| 3879 | ||
| 3880 | var analysis_arena = std.heap.ArenaAllocator.init(gpa); | |
| 3881 | defer analysis_arena.deinit(); | |
| 3882 | ||
| 3883 | var comptime_err_ret_trace = std.array_list.Managed(Zcu.LazySrcLoc).init(gpa); | |
| 3884 | defer comptime_err_ret_trace.deinit(); | |
| 3885 | ||
| 3886 | const zir = zcu.namespacePtr(union_obj.namespace).fileScope(zcu).zir.?; | |
| 3887 | var sema: Sema = .{ | |
| 3888 | .pt = pt, | |
| 3889 | .gpa = gpa, | |
| 3890 | .arena = analysis_arena.allocator(), | |
| 3891 | .code = zir, | |
| 3892 | .owner = owner, | |
| 3893 | .func_index = .none, | |
| 3894 | .func_is_naked = false, | |
| 3895 | .fn_ret_ty = Type.void, | |
| 3896 | .fn_ret_ty_ies = null, | |
| 3897 | .comptime_err_ret_trace = &comptime_err_ret_trace, | |
| 3898 | }; | |
| 3899 | defer sema.deinit(); | |
| 3900 | ||
| 3901 | (switch (resolution) { | |
| 3902 | .fields => sema.resolveUnionFieldTypes(ty, union_obj), | |
| 3903 | .alignment => sema.resolveUnionAlignment(ty, union_obj), | |
| 3904 | .layout => sema.resolveUnionLayout(ty), | |
| 3905 | .full => sema.resolveUnionFully(ty), | |
| 3906 | }) catch |err| switch (err) { | |
| 3907 | error.AnalysisFail => { | |
| 3908 | if (!zcu.failed_analysis.contains(owner)) { | |
| 3909 | try zcu.transitive_failed_analysis.put(gpa, owner, {}); | |
| 3910 | } | |
| 3911 | return error.AnalysisFail; | |
| 3912 | }, | |
| 3913 | error.OutOfMemory => |e| return e, | |
| 3914 | error.Canceled => |e| return e, | |
| 3915 | }; | |
| 3916 | } | |
| 3917 | ||
| 3918 | 2685 | pub fn getUnionLayout(loaded_union: InternPool.LoadedUnionType, zcu: *const Zcu) Zcu.UnionLayout { |
| 3919 | 2686 | const ip = &zcu.intern_pool; |
| 3920 | assert(loaded_union.haveLayout(ip)); | |
| 3921 | 2687 | var most_aligned_field: u32 = 0; |
| 3922 | 2688 | var most_aligned_field_align: InternPool.Alignment = .@"1"; |
| 3923 | 2689 | var most_aligned_field_size: u64 = 0; |
| ... | ... | @@ -3928,11 +2694,14 @@ pub fn getUnionLayout(loaded_union: InternPool.LoadedUnionType, zcu: *const Zcu) |
| 3928 | 2694 | const field_ty: Type = .fromInterned(field_ty_ip_index); |
| 3929 | 2695 | if (field_ty.isNoReturn(zcu)) continue; |
| 3930 | 2696 | |
| 3931 | const explicit_align = loaded_union.fieldAlign(ip, field_index); | |
| 3932 | const field_align = if (explicit_align != .none) | |
| 3933 | explicit_align | |
| 3934 | else | |
| 3935 | field_ty.abiAlignment(zcu); | |
| 2697 | const field_align: InternPool.Alignment = a: { | |
| 2698 | const explicit_aligns = loaded_union.field_aligns.get(ip); | |
| 2699 | if (explicit_aligns.len > 0) { | |
| 2700 | const a = explicit_aligns[field_index]; | |
| 2701 | if (a != .none) break :a a; | |
| 2702 | } | |
| 2703 | break :a field_ty.abiAlignment(zcu); | |
| 2704 | }; | |
| 3936 | 2705 | if (field_ty.hasRuntimeBits(zcu)) { |
| 3937 | 2706 | const field_size = field_ty.abiSize(zcu); |
| 3938 | 2707 | if (field_size > payload_size) { |
| ... | ... | @@ -3947,8 +2716,9 @@ pub fn getUnionLayout(loaded_union: InternPool.LoadedUnionType, zcu: *const Zcu) |
| 3947 | 2716 | } |
| 3948 | 2717 | payload_align = payload_align.max(field_align); |
| 3949 | 2718 | } |
| 3950 | const have_tag = loaded_union.flagsUnordered(ip).runtime_tag.hasTag(); | |
| 3951 | if (!have_tag or !Type.fromInterned(loaded_union.enum_tag_ty).hasRuntimeBits(zcu)) { | |
| 2719 | if (loaded_union.runtime_tag == .none or | |
| 2720 | !Type.fromInterned(loaded_union.enum_tag_type).hasRuntimeBits(zcu)) | |
| 2721 | { | |
| 3952 | 2722 | return .{ |
| 3953 | 2723 | .abi_size = payload_align.forward(payload_size), |
| 3954 | 2724 | .abi_align = payload_align, |
| ... | ... | @@ -3963,10 +2733,10 @@ pub fn getUnionLayout(loaded_union: InternPool.LoadedUnionType, zcu: *const Zcu) |
| 3963 | 2733 | }; |
| 3964 | 2734 | } |
| 3965 | 2735 | |
| 3966 | const tag_size = Type.fromInterned(loaded_union.enum_tag_ty).abiSize(zcu); | |
| 3967 | const tag_align = Type.fromInterned(loaded_union.enum_tag_ty).abiAlignment(zcu).max(.@"1"); | |
| 2736 | const tag_size = Type.fromInterned(loaded_union.enum_tag_type).abiSize(zcu); | |
| 2737 | const tag_align = Type.fromInterned(loaded_union.enum_tag_type).abiAlignment(zcu).max(.@"1"); | |
| 3968 | 2738 | return .{ |
| 3969 | .abi_size = loaded_union.sizeUnordered(ip), | |
| 2739 | .abi_size = loaded_union.size, | |
| 3970 | 2740 | .abi_align = tag_align.max(payload_align), |
| 3971 | 2741 | .most_aligned_field = most_aligned_field, |
| 3972 | 2742 | .most_aligned_field_size = most_aligned_field_size, |
| ... | ... | @@ -3975,7 +2745,7 @@ pub fn getUnionLayout(loaded_union: InternPool.LoadedUnionType, zcu: *const Zcu) |
| 3975 | 2745 | .payload_align = payload_align, |
| 3976 | 2746 | .tag_align = tag_align, |
| 3977 | 2747 | .tag_size = tag_size, |
| 3978 | .padding = loaded_union.paddingUnordered(ip), | |
| 2748 | .padding = loaded_union.padding, | |
| 3979 | 2749 | }; |
| 3980 | 2750 | } |
| 3981 | 2751 | |
| ... | ... | @@ -3989,10 +2759,17 @@ pub fn getUnionLayout(loaded_union: InternPool.LoadedUnionType, zcu: *const Zcu) |
| 3989 | 2759 | /// Handles const-ness and address spaces in particular. |
| 3990 | 2760 | /// This code is duplicated in `Sema.analyzePtrArithmetic`. |
| 3991 | 2761 | /// May perform type resolution and return a transitive `error.AnalysisFail`. |
| 2762 | /// MLUGG TODO audit this shit | |
| 3992 | 2763 | pub fn elemPtrType(ptr_ty: Type, offset: ?usize, pt: Zcu.PerThread) !Type { |
| 3993 | 2764 | const zcu = pt.zcu; |
| 3994 | 2765 | const ptr_info = ptr_ty.ptrInfo(zcu); |
| 3995 | const elem_ty = ptr_ty.elemType2(zcu); | |
| 2766 | const elem_ty: Type = switch (ptr_info.flags.size) { | |
| 2767 | .one => switch (Type.fromInterned(ptr_info.child).zigTypeTag(zcu)) { | |
| 2768 | .array, .vector => Type.fromInterned(ptr_info.child).childType(zcu), | |
| 2769 | else => .fromInterned(ptr_info.child), | |
| 2770 | }, | |
| 2771 | .many, .c, .slice => .fromInterned(ptr_info.child), | |
| 2772 | }; | |
| 3996 | 2773 | const is_allowzero = ptr_info.flags.is_allowzero and (offset orelse 0) == 0; |
| 3997 | 2774 | const parent_ty = ptr_ty.childType(zcu); |
| 3998 | 2775 | |
| ... | ... | @@ -4024,7 +2801,7 @@ pub fn elemPtrType(ptr_ty: Type, offset: ?usize, pt: Zcu.PerThread) !Type { |
| 4024 | 2801 | } |
| 4025 | 2802 | // If the addend is not a comptime-known value we can still count on |
| 4026 | 2803 | // it being a multiple of the type size. |
| 4027 | const elem_size = (try elem_ty.abiSizeInner(.sema, zcu, pt.tid)).scalar; | |
| 2804 | const elem_size = elem_ty.abiSize(zcu); | |
| 4028 | 2805 | const addend = if (offset) |off| elem_size * off else elem_size; |
| 4029 | 2806 | |
| 4030 | 2807 | // The resulting pointer is aligned to the lcd between the offset (an |
| ... | ... | @@ -4037,7 +2814,7 @@ pub fn elemPtrType(ptr_ty: Type, offset: ?usize, pt: Zcu.PerThread) !Type { |
| 4037 | 2814 | assert(new_align != .none); |
| 4038 | 2815 | break :a new_align; |
| 4039 | 2816 | }; |
| 4040 | return pt.ptrTypeSema(.{ | |
| 2817 | return pt.ptrType(.{ | |
| 4041 | 2818 | .child = elem_ty.toIntern(), |
| 4042 | 2819 | .flags = .{ |
| 4043 | 2820 | .alignment = alignment, |
| ... | ... | @@ -4069,11 +2846,107 @@ pub fn containerTypeName(ty: Type, ip: *const InternPool) InternPool.NullTermina |
| 4069 | 2846 | /// Returns `null` otherwise. |
| 4070 | 2847 | pub fn isNullFromType(ty: Type, zcu: *const Zcu) ?bool { |
| 4071 | 2848 | if (ty.zigTypeTag(zcu) != .optional and !ty.isCPtr(zcu)) return false; |
| 4072 | const child = ty.optionalChild(zcu); | |
| 4073 | if (child.zigTypeTag(zcu) == .noreturn) return true; // `?noreturn` is always null | |
| 2849 | if (ty.optionalChild(zcu).isNoReturn(zcu)) return true; // `?noreturn` is always null | |
| 4074 | 2850 | return null; |
| 4075 | 2851 | } |
| 4076 | 2852 | |
| 2853 | /// Returns true if `ty` is allowed in packed types. | |
| 2854 | pub fn packable(ty: Type, zcu: *const Zcu) bool { | |
| 2855 | return switch (ty.zigTypeTag(zcu)) { | |
| 2856 | .type, | |
| 2857 | .comptime_float, | |
| 2858 | .comptime_int, | |
| 2859 | .enum_literal, | |
| 2860 | .undefined, | |
| 2861 | .null, | |
| 2862 | .error_union, | |
| 2863 | .error_set, | |
| 2864 | .frame, | |
| 2865 | .noreturn, | |
| 2866 | .@"opaque", | |
| 2867 | .@"anyframe", | |
| 2868 | .@"fn", | |
| 2869 | .array, | |
| 2870 | => false, | |
| 2871 | .optional => return ty.isPtrLikeOptional(zcu), | |
| 2872 | .void, | |
| 2873 | .bool, | |
| 2874 | .float, | |
| 2875 | .int, | |
| 2876 | .vector, | |
| 2877 | => true, | |
| 2878 | .@"enum" => zcu.intern_pool.loadEnumType(ty.toIntern()).int_tag_is_explicit, | |
| 2879 | .pointer => !ty.isSlice(zcu), | |
| 2880 | .@"struct", .@"union" => ty.containerLayout(zcu) == .@"packed", | |
| 2881 | }; | |
| 2882 | } | |
| 2883 | ||
| 2884 | /// Asserts that `ty` has resolved layout. | |
| 2885 | pub fn assertHasLayout(ty: Type, zcu: *const Zcu) void { | |
| 2886 | switch (zcu.intern_pool.indexToKey(ty.toIntern())) { | |
| 2887 | .int_type, | |
| 2888 | .ptr_type, | |
| 2889 | .anyframe_type, | |
| 2890 | .simple_type, | |
| 2891 | .opaque_type, | |
| 2892 | .enum_type, | |
| 2893 | .error_set_type, | |
| 2894 | .inferred_error_set_type, | |
| 2895 | => {}, | |
| 2896 | .func_type => |func_type| { | |
| 2897 | for (func_type.param_types.get(&zcu.intern_pool)) |param_ty| { | |
| 2898 | assertHasLayout(.fromInterned(param_ty), zcu); | |
| 2899 | } | |
| 2900 | assertHasLayout(.fromInterned(func_type.return_type), zcu); | |
| 2901 | }, | |
| 2902 | .array_type => |arr| assertHasLayout(.fromInterned(arr.child), zcu), | |
| 2903 | .vector_type => |vec| assertHasLayout(.fromInterned(vec.child), zcu), | |
| 2904 | .opt_type => |child| assertHasLayout(.fromInterned(child), zcu), | |
| 2905 | .error_union_type => |eu| assertHasLayout(.fromInterned(eu.payload_type), zcu), | |
| 2906 | .tuple_type => |tuple| for (tuple.types.get(&zcu.intern_pool)) |field_ty| { | |
| 2907 | assertHasLayout(.fromInterned(field_ty), zcu); | |
| 2908 | }, | |
| 2909 | .struct_type, .union_type => { | |
| 2910 | const unit: InternPool.AnalUnit = .wrap(.{ .type_layout = ty.toIntern() }); | |
| 2911 | assert(!zcu.outdated.contains(unit)); | |
| 2912 | assert(!zcu.potentially_outdated.contains(unit)); | |
| 2913 | }, | |
| 2914 | else => unreachable, // assertion failure; not a struct or union | |
| 2915 | ||
| 2916 | // values, not types | |
| 2917 | .simple_value, | |
| 2918 | .variable, | |
| 2919 | .@"extern", | |
| 2920 | .func, | |
| 2921 | .int, | |
| 2922 | .err, | |
| 2923 | .error_union, | |
| 2924 | .enum_literal, | |
| 2925 | .enum_tag, | |
| 2926 | .empty_enum_value, | |
| 2927 | .float, | |
| 2928 | .ptr, | |
| 2929 | .slice, | |
| 2930 | .opt, | |
| 2931 | .aggregate, | |
| 2932 | .un, | |
| 2933 | // memoization, not types | |
| 2934 | .memoized_call, | |
| 2935 | => unreachable, | |
| 2936 | } | |
| 2937 | } | |
| 2938 | ||
| 2939 | /// Asserts that `ty` is an enum or struct type whose field values/defaults are resolved. | |
| 2940 | pub fn assertHasInits(ty: Type, zcu: *const Zcu) void { | |
| 2941 | switch (zcu.intern_pool.indexToKey(ty.toIntern())) { | |
| 2942 | .struct_type, .enum_type => {}, | |
| 2943 | else => unreachable, | |
| 2944 | } | |
| 2945 | const unit: InternPool.AnalUnit = .wrap(.{ .type_inits = ty.toIntern() }); | |
| 2946 | assert(!zcu.outdated.contains(unit)); | |
| 2947 | assert(!zcu.potentially_outdated.contains(unit)); | |
| 2948 | } | |
| 2949 | ||
| 4077 | 2950 | /// Recursively walks the type and marks for each subtype how many times it has been seen |
| 4078 | 2951 | fn collectSubtypes(ty: Type, pt: Zcu.PerThread, visited: *std.AutoArrayHashMapUnmanaged(Type, u16)) error{OutOfMemory}!void { |
| 4079 | 2952 | const zcu = pt.zcu; |
src/Value.zig+145-642| ... | ... | @@ -146,80 +146,22 @@ pub fn toType(self: Value) Type { |
| 146 | 146 | return Type.fromInterned(self.toIntern()); |
| 147 | 147 | } |
| 148 | 148 | |
| 149 | pub fn intFromEnum(val: Value, ty: Type, pt: Zcu.PerThread) Allocator.Error!Value { | |
| 150 | const ip = &pt.zcu.intern_pool; | |
| 151 | const enum_ty = ip.typeOf(val.toIntern()); | |
| 152 | return switch (ip.indexToKey(enum_ty)) { | |
| 153 | // Assume it is already an integer and return it directly. | |
| 154 | .simple_type, .int_type => val, | |
| 155 | .enum_literal => |enum_literal| { | |
| 156 | const field_index = ty.enumFieldIndex(enum_literal, pt.zcu).?; | |
| 157 | switch (ip.indexToKey(ty.toIntern())) { | |
| 158 | // Assume it is already an integer and return it directly. | |
| 159 | .simple_type, .int_type => return val, | |
| 160 | .enum_type => { | |
| 161 | const enum_type = ip.loadEnumType(ty.toIntern()); | |
| 162 | if (enum_type.values.len != 0) { | |
| 163 | return Value.fromInterned(enum_type.values.get(ip)[field_index]); | |
| 164 | } else { | |
| 165 | // Field index and integer values are the same. | |
| 166 | return pt.intValue(Type.fromInterned(enum_type.tag_ty), field_index); | |
| 167 | } | |
| 168 | }, | |
| 169 | else => unreachable, | |
| 170 | } | |
| 171 | }, | |
| 172 | .enum_type => try pt.getCoerced(val, Type.fromInterned(ip.loadEnumType(enum_ty).tag_ty)), | |
| 173 | else => unreachable, | |
| 174 | }; | |
| 149 | pub fn intFromEnum(val: Value, zcu: *const Zcu) Value { | |
| 150 | return .fromInterned(zcu.intern_pool.indexToKey(val.toIntern()).enum_tag.int); | |
| 175 | 151 | } |
| 176 | 152 | |
| 177 | pub const ResolveStrat = Type.ResolveStrat; | |
| 178 | ||
| 179 | /// Asserts the value is an integer. | |
| 153 | /// Asserts that `val` is an integer. | |
| 180 | 154 | pub fn toBigInt(val: Value, space: *BigIntSpace, zcu: *Zcu) BigIntConst { |
| 181 | return val.toBigIntAdvanced(space, .normal, zcu, {}) catch unreachable; | |
| 182 | } | |
| 183 | ||
| 184 | pub fn toBigIntSema(val: Value, space: *BigIntSpace, pt: Zcu.PerThread) !BigIntConst { | |
| 185 | return try val.toBigIntAdvanced(space, .sema, pt.zcu, pt.tid); | |
| 186 | } | |
| 187 | ||
| 188 | /// Asserts the value is an integer. | |
| 189 | pub fn toBigIntAdvanced( | |
| 190 | val: Value, | |
| 191 | space: *BigIntSpace, | |
| 192 | comptime strat: ResolveStrat, | |
| 193 | zcu: *Zcu, | |
| 194 | tid: strat.Tid(), | |
| 195 | ) Zcu.SemaError!BigIntConst { | |
| 155 | if (val.getUnsignedInt(zcu)) |x| { | |
| 156 | return BigIntMutable.init(&space.limbs, x).toConst(); | |
| 157 | } | |
| 196 | 158 | const ip = &zcu.intern_pool; |
| 197 | return switch (val.toIntern()) { | |
| 198 | .bool_false => BigIntMutable.init(&space.limbs, 0).toConst(), | |
| 199 | .bool_true => BigIntMutable.init(&space.limbs, 1).toConst(), | |
| 200 | .null_value => BigIntMutable.init(&space.limbs, 0).toConst(), | |
| 201 | else => switch (ip.indexToKey(val.toIntern())) { | |
| 202 | .int => |int| switch (int.storage) { | |
| 203 | .u64, .i64, .big_int => int.storage.toBigInt(space), | |
| 204 | .lazy_align, .lazy_size => |ty| { | |
| 205 | if (strat == .sema) try Type.fromInterned(ty).resolveLayout(strat.pt(zcu, tid)); | |
| 206 | const x = switch (int.storage) { | |
| 207 | else => unreachable, | |
| 208 | .lazy_align => Type.fromInterned(ty).abiAlignment(zcu).toByteUnits() orelse 0, | |
| 209 | .lazy_size => Type.fromInterned(ty).abiSize(zcu), | |
| 210 | }; | |
| 211 | return BigIntMutable.init(&space.limbs, x).toConst(); | |
| 212 | }, | |
| 213 | }, | |
| 214 | .enum_tag => |enum_tag| Value.fromInterned(enum_tag.int).toBigIntAdvanced(space, strat, zcu, tid), | |
| 215 | .opt, .ptr => BigIntMutable.init( | |
| 216 | &space.limbs, | |
| 217 | (try val.getUnsignedIntInner(strat, zcu, tid)).?, | |
| 218 | ).toConst(), | |
| 219 | .err => |err| BigIntMutable.init(&space.limbs, ip.getErrorValueIfExists(err.name).?).toConst(), | |
| 220 | else => unreachable, | |
| 221 | }, | |
| 159 | const int_key = switch (ip.indexToKey(val.toIntern())) { | |
| 160 | .enum_tag => |enum_tag| ip.indexToKey(enum_tag.int).int, | |
| 161 | .int => |int| int, | |
| 162 | else => unreachable, | |
| 222 | 163 | }; |
| 164 | return int_key.storage.toBigInt(space); | |
| 223 | 165 | } |
| 224 | 166 | |
| 225 | 167 | pub fn isFuncBody(val: Value, zcu: *Zcu) bool { |
| ... | ... | @@ -240,31 +182,17 @@ pub fn getVariable(val: Value, mod: *Zcu) ?InternPool.Key.Variable { |
| 240 | 182 | }; |
| 241 | 183 | } |
| 242 | 184 | |
| 243 | /// If the value fits in a u64, return it, otherwise null. | |
| 244 | /// Asserts not undefined. | |
| 245 | pub fn getUnsignedInt(val: Value, zcu: *const Zcu) ?u64 { | |
| 246 | return getUnsignedIntInner(val, .normal, zcu, {}) catch unreachable; | |
| 247 | } | |
| 248 | ||
| 249 | /// Asserts the value is an integer and it fits in a u64 | |
| 185 | /// Asserts the value is a (defined) integer and it fits in a u64. | |
| 250 | 186 | pub fn toUnsignedInt(val: Value, zcu: *const Zcu) u64 { |
| 251 | 187 | return getUnsignedInt(val, zcu).?; |
| 252 | 188 | } |
| 253 | 189 | |
| 254 | pub fn getUnsignedIntSema(val: Value, pt: Zcu.PerThread) !?u64 { | |
| 255 | return try val.getUnsignedIntInner(.sema, pt.zcu, pt.tid); | |
| 256 | } | |
| 257 | ||
| 258 | 190 | /// If the value fits in a u64, return it, otherwise null. |
| 259 | 191 | /// Asserts not undefined. |
| 260 | pub fn getUnsignedIntInner( | |
| 261 | val: Value, | |
| 262 | comptime strat: ResolveStrat, | |
| 263 | zcu: strat.ZcuPtr(), | |
| 264 | tid: strat.Tid(), | |
| 265 | ) !?u64 { | |
| 192 | pub fn getUnsignedInt(val: Value, zcu: *const Zcu) ?u64 { | |
| 266 | 193 | return switch (val.toIntern()) { |
| 267 | 194 | .undef => unreachable, |
| 195 | .null_value => 0, | |
| 268 | 196 | .bool_false => 0, |
| 269 | 197 | .bool_true => 1, |
| 270 | 198 | else => switch (zcu.intern_pool.indexToKey(val.toIntern())) { |
| ... | ... | @@ -273,37 +201,27 @@ pub fn getUnsignedIntInner( |
| 273 | 201 | .big_int => |big_int| big_int.toInt(u64) catch null, |
| 274 | 202 | .u64 => |x| x, |
| 275 | 203 | .i64 => |x| std.math.cast(u64, x), |
| 276 | .lazy_align => |ty| (try Type.fromInterned(ty).abiAlignmentInner(strat.toLazy(), zcu, tid)).scalar.toByteUnits() orelse 0, | |
| 277 | .lazy_size => |ty| (try Type.fromInterned(ty).abiSizeInner(strat.toLazy(), zcu, tid)).scalar, | |
| 278 | 204 | }, |
| 279 | 205 | .ptr => |ptr| switch (ptr.base_addr) { |
| 280 | 206 | .int => ptr.byte_offset, |
| 281 | 207 | .field => |field| { |
| 282 | const base_addr = (try Value.fromInterned(field.base).getUnsignedIntInner(strat, zcu, tid)) orelse return null; | |
| 208 | const base_addr = Value.fromInterned(field.base).getUnsignedInt(zcu) orelse return null; | |
| 283 | 209 | const struct_ty = Value.fromInterned(field.base).typeOf(zcu).childType(zcu); |
| 284 | if (strat == .sema) { | |
| 285 | const pt = strat.pt(zcu, tid); | |
| 286 | try struct_ty.resolveLayout(pt); | |
| 287 | } | |
| 288 | 210 | return base_addr + struct_ty.structFieldOffset(@intCast(field.index), zcu) + ptr.byte_offset; |
| 289 | 211 | }, |
| 290 | 212 | else => null, |
| 291 | 213 | }, |
| 292 | 214 | .opt => |opt| switch (opt.val) { |
| 293 | 215 | .none => 0, |
| 294 | else => |payload| Value.fromInterned(payload).getUnsignedIntInner(strat, zcu, tid), | |
| 216 | else => |payload| Value.fromInterned(payload).getUnsignedInt(zcu), | |
| 295 | 217 | }, |
| 296 | .enum_tag => |enum_tag| return Value.fromInterned(enum_tag.int).getUnsignedIntInner(strat, zcu, tid), | |
| 218 | .enum_tag => |enum_tag| Value.fromInterned(enum_tag.int).getUnsignedInt(zcu), | |
| 219 | .err => |err| zcu.intern_pool.getErrorValueIfExists(err.name).?, | |
| 297 | 220 | else => null, |
| 298 | 221 | }, |
| 299 | 222 | }; |
| 300 | 223 | } |
| 301 | 224 | |
| 302 | /// Asserts the value is an integer and it fits in a u64 | |
| 303 | pub fn toUnsignedIntSema(val: Value, pt: Zcu.PerThread) !u64 { | |
| 304 | return (try getUnsignedIntInner(val, .sema, pt.zcu, pt.tid)).?; | |
| 305 | } | |
| 306 | ||
| 307 | 225 | /// Asserts the value is an integer and it fits in a i64 |
| 308 | 226 | pub fn toSignedInt(val: Value, zcu: *const Zcu) i64 { |
| 309 | 227 | return switch (val.toIntern()) { |
| ... | ... | @@ -314,8 +232,6 @@ pub fn toSignedInt(val: Value, zcu: *const Zcu) i64 { |
| 314 | 232 | .big_int => |big_int| big_int.toInt(i64) catch unreachable, |
| 315 | 233 | .i64 => |x| x, |
| 316 | 234 | .u64 => |x| @intCast(x), |
| 317 | .lazy_align => |ty| @intCast(Type.fromInterned(ty).abiAlignment(zcu).toByteUnits() orelse 0), | |
| 318 | .lazy_size => |ty| @intCast(Type.fromInterned(ty).abiSize(zcu)), | |
| 319 | 235 | }, |
| 320 | 236 | else => unreachable, |
| 321 | 237 | }, |
| ... | ... | @@ -487,22 +403,16 @@ pub fn writeToPackedMemory( |
| 487 | 403 | buffer[byte_index] &= ~(@as(u8, 1) << @as(u3, @intCast(bit_offset % 8))); |
| 488 | 404 | } |
| 489 | 405 | }, |
| 490 | .int, .@"enum" => { | |
| 491 | if (buffer.len == 0) return; | |
| 406 | .@"enum" => { | |
| 407 | const int_val = val.intFromEnum(zcu); | |
| 408 | return int_val.writeToPackedMemory(int_val.typeOf(zcu), pt, buffer, bit_offset); | |
| 409 | }, | |
| 410 | .int => { | |
| 492 | 411 | const bits = ty.intInfo(zcu).bits; |
| 493 | if (bits == 0) return; | |
| 494 | ||
| 495 | switch (ip.indexToKey((try val.intFromEnum(ty, pt)).toIntern()).int.storage) { | |
| 412 | if (bits == 0 or buffer.len == 0) return; | |
| 413 | switch (ip.indexToKey(val.toIntern()).int.storage) { | |
| 496 | 414 | inline .u64, .i64 => |int| std.mem.writeVarPackedInt(buffer, bit_offset, bits, int, endian), |
| 497 | 415 | .big_int => |bigint| bigint.writePackedTwosComplement(buffer, bit_offset, bits, endian), |
| 498 | .lazy_align => |lazy_align| { | |
| 499 | const num = Type.fromInterned(lazy_align).abiAlignment(zcu).toByteUnits() orelse 0; | |
| 500 | std.mem.writeVarPackedInt(buffer, bit_offset, bits, num, endian); | |
| 501 | }, | |
| 502 | .lazy_size => |lazy_size| { | |
| 503 | const num = Type.fromInterned(lazy_size).abiSize(zcu); | |
| 504 | std.mem.writeVarPackedInt(buffer, bit_offset, bits, num, endian); | |
| 505 | }, | |
| 506 | 416 | } |
| 507 | 417 | }, |
| 508 | 418 | .float => switch (ty.floatBits(target)) { |
| ... | ... | @@ -548,19 +458,15 @@ pub fn writeToPackedMemory( |
| 548 | 458 | }, |
| 549 | 459 | .@"union" => { |
| 550 | 460 | const union_obj = zcu.typeToUnion(ty).?; |
| 551 | switch (union_obj.flagsUnordered(ip).layout) { | |
| 552 | .auto, .@"extern" => unreachable, // Handled in non-packed writeToMemory | |
| 553 | .@"packed" => { | |
| 554 | if (val.unionTag(zcu)) |union_tag| { | |
| 555 | const field_index = zcu.unionTagFieldIndex(union_obj, union_tag).?; | |
| 556 | const field_type = Type.fromInterned(union_obj.field_types.get(ip)[field_index]); | |
| 557 | const field_val = try val.fieldValue(pt, field_index); | |
| 558 | return field_val.writeToPackedMemory(field_type, pt, buffer, bit_offset); | |
| 559 | } else { | |
| 560 | const backing_ty = try ty.unionBackingType(pt); | |
| 561 | return val.unionValue(zcu).writeToPackedMemory(backing_ty, pt, buffer, bit_offset); | |
| 562 | } | |
| 563 | }, | |
| 461 | assert(union_obj.layout == .@"packed"); | |
| 462 | if (val.unionTag(zcu)) |union_tag| { | |
| 463 | const field_index = zcu.unionTagFieldIndex(union_obj, union_tag).?; | |
| 464 | const field_type = Type.fromInterned(union_obj.field_types.get(ip)[field_index]); | |
| 465 | const field_val = try val.fieldValue(pt, field_index); | |
| 466 | return field_val.writeToPackedMemory(field_type, pt, buffer, bit_offset); | |
| 467 | } else { | |
| 468 | const backing_ty = try ty.unionBackingType(pt); | |
| 469 | return val.unionValue(zcu).writeToPackedMemory(backing_ty, pt, buffer, bit_offset); | |
| 564 | 470 | } |
| 565 | 471 | }, |
| 566 | 472 | .pointer => { |
| ... | ... | @@ -729,24 +635,15 @@ pub fn readFromPackedMemory( |
| 729 | 635 | }, |
| 730 | 636 | .pointer => { |
| 731 | 637 | assert(!ty.isSlice(zcu)); // No well defined layout. |
| 732 | const int_val = try readFromPackedMemory(Type.usize, pt, buffer, bit_offset, arena); | |
| 733 | return Value.fromInterned(try pt.intern(.{ .ptr = .{ | |
| 734 | .ty = ty.toIntern(), | |
| 735 | .base_addr = .int, | |
| 736 | .byte_offset = int_val.toUnsignedInt(zcu), | |
| 737 | } })); | |
| 638 | const addr = (try readFromPackedMemory(Type.usize, pt, buffer, bit_offset, arena)).toUnsignedInt(zcu); | |
| 639 | return pt.ptrIntValue(ty, addr); | |
| 738 | 640 | }, |
| 739 | 641 | .optional => { |
| 740 | 642 | assert(ty.isPtrLikeOptional(zcu)); |
| 741 | const child_ty = ty.optionalChild(zcu); | |
| 742 | const child_val = try readFromPackedMemory(child_ty, pt, buffer, bit_offset, arena); | |
| 643 | const addr = (try readFromPackedMemory(Type.usize, pt, buffer, bit_offset, arena)).toUnsignedInt(zcu); | |
| 743 | 644 | return Value.fromInterned(try pt.intern(.{ .opt = .{ |
| 744 | 645 | .ty = ty.toIntern(), |
| 745 | .val = switch (child_val.orderAgainstZero(zcu)) { | |
| 746 | .lt => unreachable, | |
| 747 | .eq => .none, | |
| 748 | .gt => child_val.toIntern(), | |
| 749 | }, | |
| 646 | .val = (try pt.ptrIntValue(ty.childType(zcu), addr)).toIntern(), | |
| 750 | 647 | } })); |
| 751 | 648 | }, |
| 752 | 649 | else => @panic("TODO implement readFromPackedMemory for more types"), |
| ... | ... | @@ -764,8 +661,6 @@ pub fn toFloat(val: Value, comptime T: type, zcu: *const Zcu) T { |
| 764 | 661 | } |
| 765 | 662 | return @floatFromInt(x); |
| 766 | 663 | }, |
| 767 | .lazy_align => |ty| @floatFromInt(Type.fromInterned(ty).abiAlignment(zcu).toByteUnits() orelse 0), | |
| 768 | .lazy_size => |ty| @floatFromInt(Type.fromInterned(ty).abiSize(zcu)), | |
| 769 | 664 | }, |
| 770 | 665 | .float => |float| switch (float.storage) { |
| 771 | 666 | inline else => |x| @floatCast(x), |
| ... | ... | @@ -819,110 +714,8 @@ pub fn floatCast(val: Value, dest_ty: Type, pt: Zcu.PerThread) !Value { |
| 819 | 714 | } })); |
| 820 | 715 | } |
| 821 | 716 | |
| 822 | pub fn orderAgainstZero(lhs: Value, zcu: *Zcu) std.math.Order { | |
| 823 | return orderAgainstZeroInner(lhs, .normal, zcu, {}) catch unreachable; | |
| 824 | } | |
| 825 | ||
| 826 | pub fn orderAgainstZeroSema(lhs: Value, pt: Zcu.PerThread) !std.math.Order { | |
| 827 | return try orderAgainstZeroInner(lhs, .sema, pt.zcu, pt.tid); | |
| 828 | } | |
| 829 | ||
| 830 | pub fn orderAgainstZeroInner( | |
| 831 | lhs: Value, | |
| 832 | comptime strat: ResolveStrat, | |
| 833 | zcu: *Zcu, | |
| 834 | tid: strat.Tid(), | |
| 835 | ) Zcu.SemaError!std.math.Order { | |
| 836 | return switch (lhs.toIntern()) { | |
| 837 | .bool_false => .eq, | |
| 838 | .bool_true => .gt, | |
| 839 | else => switch (zcu.intern_pool.indexToKey(lhs.toIntern())) { | |
| 840 | .ptr => |ptr| if (ptr.byte_offset > 0) .gt else switch (ptr.base_addr) { | |
| 841 | .nav, .comptime_alloc, .comptime_field => .gt, | |
| 842 | .int => .eq, | |
| 843 | else => unreachable, | |
| 844 | }, | |
| 845 | .int => |int| switch (int.storage) { | |
| 846 | .big_int => |big_int| big_int.orderAgainstScalar(0), | |
| 847 | inline .u64, .i64 => |x| std.math.order(x, 0), | |
| 848 | .lazy_align => .gt, // alignment is never 0 | |
| 849 | .lazy_size => |ty| return if (Type.fromInterned(ty).hasRuntimeBitsInner( | |
| 850 | false, | |
| 851 | strat.toLazy(), | |
| 852 | zcu, | |
| 853 | tid, | |
| 854 | ) catch |err| switch (err) { | |
| 855 | error.NeedLazy => unreachable, | |
| 856 | else => |e| return e, | |
| 857 | }) .gt else .eq, | |
| 858 | }, | |
| 859 | .enum_tag => |enum_tag| Value.fromInterned(enum_tag.int).orderAgainstZeroInner(strat, zcu, tid), | |
| 860 | .float => |float| switch (float.storage) { | |
| 861 | inline else => |x| std.math.order(x, 0), | |
| 862 | }, | |
| 863 | .err => .gt, // error values cannot be 0 | |
| 864 | else => unreachable, | |
| 865 | }, | |
| 866 | }; | |
| 867 | } | |
| 868 | ||
| 869 | /// Asserts the value is comparable. | |
| 870 | pub fn order(lhs: Value, rhs: Value, zcu: *Zcu) std.math.Order { | |
| 871 | return orderAdvanced(lhs, rhs, .normal, zcu, {}) catch unreachable; | |
| 872 | } | |
| 873 | ||
| 874 | /// Asserts the value is comparable. | |
| 875 | pub fn orderAdvanced( | |
| 876 | lhs: Value, | |
| 877 | rhs: Value, | |
| 878 | comptime strat: ResolveStrat, | |
| 879 | zcu: *Zcu, | |
| 880 | tid: strat.Tid(), | |
| 881 | ) !std.math.Order { | |
| 882 | const lhs_against_zero = try lhs.orderAgainstZeroInner(strat, zcu, tid); | |
| 883 | const rhs_against_zero = try rhs.orderAgainstZeroInner(strat, zcu, tid); | |
| 884 | switch (lhs_against_zero) { | |
| 885 | .lt => if (rhs_against_zero != .lt) return .lt, | |
| 886 | .eq => return rhs_against_zero.invert(), | |
| 887 | .gt => {}, | |
| 888 | } | |
| 889 | switch (rhs_against_zero) { | |
| 890 | .lt => if (lhs_against_zero != .lt) return .gt, | |
| 891 | .eq => return lhs_against_zero, | |
| 892 | .gt => {}, | |
| 893 | } | |
| 894 | ||
| 895 | if (lhs.isFloat(zcu) or rhs.isFloat(zcu)) { | |
| 896 | const lhs_f128 = lhs.toFloat(f128, zcu); | |
| 897 | const rhs_f128 = rhs.toFloat(f128, zcu); | |
| 898 | return std.math.order(lhs_f128, rhs_f128); | |
| 899 | } | |
| 900 | ||
| 901 | var lhs_bigint_space: BigIntSpace = undefined; | |
| 902 | var rhs_bigint_space: BigIntSpace = undefined; | |
| 903 | const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_bigint_space, strat, zcu, tid); | |
| 904 | const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_bigint_space, strat, zcu, tid); | |
| 905 | return lhs_bigint.order(rhs_bigint); | |
| 906 | } | |
| 907 | ||
| 908 | /// Asserts the value is comparable. Does not take a type parameter because it supports | |
| 909 | /// comparisons between heterogeneous types. | |
| 717 | /// Asserts the value is comparable. Supports comparisons between heterogeneous types. | |
| 910 | 718 | pub fn compareHetero(lhs: Value, op: std.math.CompareOperator, rhs: Value, zcu: *Zcu) bool { |
| 911 | return compareHeteroAdvanced(lhs, op, rhs, .normal, zcu, {}) catch unreachable; | |
| 912 | } | |
| 913 | ||
| 914 | pub fn compareHeteroSema(lhs: Value, op: std.math.CompareOperator, rhs: Value, pt: Zcu.PerThread) !bool { | |
| 915 | return try compareHeteroAdvanced(lhs, op, rhs, .sema, pt.zcu, pt.tid); | |
| 916 | } | |
| 917 | ||
| 918 | pub fn compareHeteroAdvanced( | |
| 919 | lhs: Value, | |
| 920 | op: std.math.CompareOperator, | |
| 921 | rhs: Value, | |
| 922 | comptime strat: ResolveStrat, | |
| 923 | zcu: *Zcu, | |
| 924 | tid: strat.Tid(), | |
| 925 | ) !bool { | |
| 926 | 719 | if (lhs.pointerNav(zcu)) |lhs_nav| { |
| 927 | 720 | if (rhs.pointerNav(zcu)) |rhs_nav| { |
| 928 | 721 | switch (op) { |
| ... | ... | @@ -944,9 +737,21 @@ pub fn compareHeteroAdvanced( |
| 944 | 737 | else => {}, |
| 945 | 738 | } |
| 946 | 739 | } |
| 947 | ||
| 948 | 740 | if (lhs.isNan(zcu) or rhs.isNan(zcu)) return op == .neq; |
| 949 | return (try orderAdvanced(lhs, rhs, strat, zcu, tid)).compare(op); | |
| 741 | return order(lhs, rhs, zcu).compare(op); | |
| 742 | } | |
| 743 | ||
| 744 | pub fn order(lhs: Value, rhs: Value, zcu: *Zcu) std.math.Order { | |
| 745 | if (lhs.isFloat(zcu) or rhs.isFloat(zcu)) { | |
| 746 | const lhs_f128 = lhs.toFloat(f128, zcu); | |
| 747 | const rhs_f128 = rhs.toFloat(f128, zcu); | |
| 748 | return std.math.order(lhs_f128, rhs_f128); | |
| 749 | } | |
| 750 | var lhs_bigint_space: BigIntSpace = undefined; | |
| 751 | var rhs_bigint_space: BigIntSpace = undefined; | |
| 752 | const lhs_bigint = lhs.toBigInt(&lhs_bigint_space, zcu); | |
| 753 | const rhs_bigint = rhs.toBigInt(&rhs_bigint_space, zcu); | |
| 754 | return lhs_bigint.order(rhs_bigint); | |
| 950 | 755 | } |
| 951 | 756 | |
| 952 | 757 | /// Asserts the values are comparable. Both operands have type `ty`. |
| ... | ... | @@ -987,56 +792,32 @@ pub fn compareScalar( |
| 987 | 792 | /// Returns `false` if the value or any vector element is undefined. |
| 988 | 793 | /// |
| 989 | 794 | /// Note that `!compareAllWithZero(.eq, ...) != compareAllWithZero(.neq, ...)` |
| 795 | /// TODO MLUGG: lowkey wanna delete this | |
| 990 | 796 | pub fn compareAllWithZero(lhs: Value, op: std.math.CompareOperator, zcu: *Zcu) bool { |
| 991 | return compareAllWithZeroAdvancedExtra(lhs, op, .normal, zcu, {}) catch unreachable; | |
| 992 | } | |
| 993 | ||
| 994 | pub fn compareAllWithZeroSema( | |
| 995 | lhs: Value, | |
| 996 | op: std.math.CompareOperator, | |
| 997 | pt: Zcu.PerThread, | |
| 998 | ) Zcu.CompileError!bool { | |
| 999 | return compareAllWithZeroAdvancedExtra(lhs, op, .sema, pt.zcu, pt.tid); | |
| 1000 | } | |
| 1001 | ||
| 1002 | pub fn compareAllWithZeroAdvancedExtra( | |
| 1003 | lhs: Value, | |
| 1004 | op: std.math.CompareOperator, | |
| 1005 | comptime strat: ResolveStrat, | |
| 1006 | zcu: *Zcu, | |
| 1007 | tid: strat.Tid(), | |
| 1008 | ) Zcu.CompileError!bool { | |
| 1009 | if (lhs.isInf(zcu)) { | |
| 1010 | switch (op) { | |
| 1011 | .neq => return true, | |
| 1012 | .eq => return false, | |
| 1013 | .gt, .gte => return !lhs.isNegativeInf(zcu), | |
| 1014 | .lt, .lte => return lhs.isNegativeInf(zcu), | |
| 1015 | } | |
| 1016 | } | |
| 1017 | ||
| 1018 | switch (zcu.intern_pool.indexToKey(lhs.toIntern())) { | |
| 797 | return switch (zcu.intern_pool.indexToKey(lhs.toIntern())) { | |
| 1019 | 798 | .float => |float| switch (float.storage) { |
| 1020 | inline else => |x| if (std.math.isNan(x)) return op == .neq, | |
| 799 | inline else => |x| std.math.compare(x, op, 0), | |
| 1021 | 800 | }, |
| 1022 | .aggregate => |aggregate| return switch (aggregate.storage) { | |
| 1023 | .bytes => |bytes| for (bytes.toSlice(lhs.typeOf(zcu).arrayLenIncludingSentinel(zcu), &zcu.intern_pool)) |byte| { | |
| 1024 | if (!std.math.order(byte, 0).compare(op)) break false; | |
| 801 | .aggregate => |aggregate| switch (aggregate.storage) { | |
| 802 | .bytes => |bytes| for (bytes.toSlice( | |
| 803 | lhs.typeOf(zcu).arrayLenIncludingSentinel(zcu), | |
| 804 | &zcu.intern_pool, | |
| 805 | )) |byte| { | |
| 806 | if (!std.math.compare(byte, op, 0)) break false; | |
| 1025 | 807 | } else true, |
| 1026 | 808 | .elems => |elems| for (elems) |elem| { |
| 1027 | if (!try Value.fromInterned(elem).compareAllWithZeroAdvancedExtra(op, strat, zcu, tid)) break false; | |
| 809 | if (!Value.fromInterned(elem).compareAllWithZero(op, zcu)) break false; | |
| 1028 | 810 | } else true, |
| 1029 | .repeated_elem => |elem| Value.fromInterned(elem).compareAllWithZeroAdvancedExtra(op, strat, zcu, tid), | |
| 811 | .repeated_elem => |elem| Value.fromInterned(elem).compareAllWithZero(op, zcu), | |
| 1030 | 812 | }, |
| 1031 | .undef => return false, | |
| 1032 | else => {}, | |
| 1033 | } | |
| 1034 | return (try orderAgainstZeroInner(lhs, strat, zcu, tid)).compare(op); | |
| 813 | .undef => false, | |
| 814 | else => order(lhs, .zero_comptime_int, zcu).compare(op), | |
| 815 | }; | |
| 1035 | 816 | } |
| 1036 | 817 | |
| 1037 | 818 | pub fn eql(a: Value, b: Value, ty: Type, zcu: *Zcu) bool { |
| 1038 | assert(zcu.intern_pool.typeOf(a.toIntern()) == ty.toIntern()); | |
| 1039 | assert(zcu.intern_pool.typeOf(b.toIntern()) == ty.toIntern()); | |
| 819 | assert(a.typeOf(zcu).toIntern() == ty.toIntern()); | |
| 820 | assert(b.typeOf(zcu).toIntern() == ty.toIntern()); | |
| 1040 | 821 | return a.toIntern() == b.toIntern(); |
| 1041 | 822 | } |
| 1042 | 823 | |
| ... | ... | @@ -1088,16 +869,13 @@ pub fn pointerNav(val: Value, zcu: *Zcu) ?InternPool.Nav.Index { |
| 1088 | 869 | pub const slice_ptr_index = 0; |
| 1089 | 870 | pub const slice_len_index = 1; |
| 1090 | 871 | |
| 872 | pub fn sliceLen(val: Value, zcu: *Zcu) u64 { | |
| 873 | return Value.fromInterned(zcu.intern_pool.sliceLen(val.toIntern())).toUnsignedInt(zcu); | |
| 874 | } | |
| 1091 | 875 | pub fn slicePtr(val: Value, zcu: *Zcu) Value { |
| 1092 | 876 | return Value.fromInterned(zcu.intern_pool.slicePtr(val.toIntern())); |
| 1093 | 877 | } |
| 1094 | 878 | |
| 1095 | /// Gets the `len` field of a slice value as a `u64`. | |
| 1096 | /// Resolves the length using `Sema` if necessary. | |
| 1097 | pub fn sliceLen(val: Value, pt: Zcu.PerThread) !u64 { | |
| 1098 | return Value.fromInterned(pt.zcu.intern_pool.sliceLen(val.toIntern())).toUnsignedIntSema(pt); | |
| 1099 | } | |
| 1100 | ||
| 1101 | 879 | /// Asserts the value is an aggregate, and returns the element value at the given index. |
| 1102 | 880 | pub fn elemValue(val: Value, pt: Zcu.PerThread, index: usize) Allocator.Error!Value { |
| 1103 | 881 | const zcu = pt.zcu; |
| ... | ... | @@ -1123,62 +901,6 @@ pub fn elemValue(val: Value, pt: Zcu.PerThread, index: usize) Allocator.Error!Va |
| 1123 | 901 | } |
| 1124 | 902 | } |
| 1125 | 903 | |
| 1126 | pub fn isLazyAlign(val: Value, zcu: *Zcu) bool { | |
| 1127 | return switch (zcu.intern_pool.indexToKey(val.toIntern())) { | |
| 1128 | .int => |int| int.storage == .lazy_align, | |
| 1129 | else => false, | |
| 1130 | }; | |
| 1131 | } | |
| 1132 | ||
| 1133 | pub fn isLazySize(val: Value, zcu: *Zcu) bool { | |
| 1134 | return switch (zcu.intern_pool.indexToKey(val.toIntern())) { | |
| 1135 | .int => |int| int.storage == .lazy_size, | |
| 1136 | else => false, | |
| 1137 | }; | |
| 1138 | } | |
| 1139 | ||
| 1140 | // Asserts that the provided start/end are in-bounds. | |
| 1141 | pub fn sliceArray( | |
| 1142 | val: Value, | |
| 1143 | sema: *Sema, | |
| 1144 | start: usize, | |
| 1145 | end: usize, | |
| 1146 | ) error{OutOfMemory}!Value { | |
| 1147 | const pt = sema.pt; | |
| 1148 | const ip = &pt.zcu.intern_pool; | |
| 1149 | const io = pt.zcu.comp.io; | |
| 1150 | return Value.fromInterned(try pt.intern(.{ | |
| 1151 | .aggregate = .{ | |
| 1152 | .ty = switch (pt.zcu.intern_pool.indexToKey(pt.zcu.intern_pool.typeOf(val.toIntern()))) { | |
| 1153 | .array_type => |array_type| try pt.arrayType(.{ | |
| 1154 | .len = @intCast(end - start), | |
| 1155 | .child = array_type.child, | |
| 1156 | .sentinel = if (end == array_type.len) array_type.sentinel else .none, | |
| 1157 | }), | |
| 1158 | .vector_type => |vector_type| try pt.vectorType(.{ | |
| 1159 | .len = @intCast(end - start), | |
| 1160 | .child = vector_type.child, | |
| 1161 | }), | |
| 1162 | else => unreachable, | |
| 1163 | }.toIntern(), | |
| 1164 | .storage = switch (ip.indexToKey(val.toIntern()).aggregate.storage) { | |
| 1165 | .bytes => |bytes| storage: { | |
| 1166 | try ip.string_bytes.ensureUnusedCapacity(sema.gpa, end - start + 1); | |
| 1167 | break :storage .{ .bytes = try ip.getOrPutString( | |
| 1168 | sema.gpa, | |
| 1169 | io, | |
| 1170 | bytes.toSlice(end, ip)[start..], | |
| 1171 | .maybe_embedded_nulls, | |
| 1172 | ) }; | |
| 1173 | }, | |
| 1174 | // TODO: write something like getCoercedInts to avoid needing to dupe | |
| 1175 | .elems => |elems| .{ .elems = try sema.arena.dupe(InternPool.Index, elems[start..end]) }, | |
| 1176 | .repeated_elem => |elem| .{ .repeated_elem = elem }, | |
| 1177 | }, | |
| 1178 | }, | |
| 1179 | })); | |
| 1180 | } | |
| 1181 | ||
| 1182 | 904 | pub fn fieldValue(val: Value, pt: Zcu.PerThread, index: usize) !Value { |
| 1183 | 905 | const zcu = pt.zcu; |
| 1184 | 906 | return switch (zcu.intern_pool.indexToKey(val.toIntern())) { |
| ... | ... | @@ -1334,63 +1056,6 @@ pub fn isFloat(self: Value, zcu: *const Zcu) bool { |
| 1334 | 1056 | }; |
| 1335 | 1057 | } |
| 1336 | 1058 | |
| 1337 | pub fn floatFromInt(val: Value, arena: Allocator, int_ty: Type, float_ty: Type, zcu: *Zcu) !Value { | |
| 1338 | return floatFromIntAdvanced(val, arena, int_ty, float_ty, zcu, .normal) catch |err| switch (err) { | |
| 1339 | error.OutOfMemory => return error.OutOfMemory, | |
| 1340 | else => unreachable, | |
| 1341 | }; | |
| 1342 | } | |
| 1343 | ||
| 1344 | pub fn floatFromIntAdvanced( | |
| 1345 | val: Value, | |
| 1346 | arena: Allocator, | |
| 1347 | int_ty: Type, | |
| 1348 | float_ty: Type, | |
| 1349 | pt: Zcu.PerThread, | |
| 1350 | comptime strat: ResolveStrat, | |
| 1351 | ) !Value { | |
| 1352 | const zcu = pt.zcu; | |
| 1353 | if (int_ty.zigTypeTag(zcu) == .vector) { | |
| 1354 | const result_data = try arena.alloc(InternPool.Index, int_ty.vectorLen(zcu)); | |
| 1355 | const scalar_ty = float_ty.scalarType(zcu); | |
| 1356 | for (result_data, 0..) |*scalar, i| { | |
| 1357 | const elem_val = try val.elemValue(pt, i); | |
| 1358 | scalar.* = (try floatFromIntScalar(elem_val, scalar_ty, pt, strat)).toIntern(); | |
| 1359 | } | |
| 1360 | return pt.aggregateValue(float_ty, result_data); | |
| 1361 | } | |
| 1362 | return floatFromIntScalar(val, float_ty, pt, strat); | |
| 1363 | } | |
| 1364 | ||
| 1365 | pub fn floatFromIntScalar(val: Value, float_ty: Type, pt: Zcu.PerThread, comptime strat: ResolveStrat) !Value { | |
| 1366 | return switch (pt.zcu.intern_pool.indexToKey(val.toIntern())) { | |
| 1367 | .undef => try pt.undefValue(float_ty), | |
| 1368 | .int => |int| switch (int.storage) { | |
| 1369 | .big_int => |big_int| pt.floatValue(float_ty, big_int.toFloat(f128, .nearest_even)[0]), | |
| 1370 | inline .u64, .i64 => |x| floatFromIntInner(x, float_ty, pt), | |
| 1371 | .lazy_align => |ty| floatFromIntInner((try Type.fromInterned(ty).abiAlignmentInner(strat.toLazy(), pt.zcu, pt.tid)).scalar.toByteUnits() orelse 0, float_ty, pt), | |
| 1372 | .lazy_size => |ty| floatFromIntInner((try Type.fromInterned(ty).abiSizeInner(strat.toLazy(), pt.zcu, pt.tid)).scalar, float_ty, pt), | |
| 1373 | }, | |
| 1374 | else => unreachable, | |
| 1375 | }; | |
| 1376 | } | |
| 1377 | ||
| 1378 | fn floatFromIntInner(x: anytype, dest_ty: Type, pt: Zcu.PerThread) !Value { | |
| 1379 | const target = pt.zcu.getTarget(); | |
| 1380 | const storage: InternPool.Key.Float.Storage = switch (dest_ty.floatBits(target)) { | |
| 1381 | 16 => .{ .f16 = @floatFromInt(x) }, | |
| 1382 | 32 => .{ .f32 = @floatFromInt(x) }, | |
| 1383 | 64 => .{ .f64 = @floatFromInt(x) }, | |
| 1384 | 80 => .{ .f80 = @floatFromInt(x) }, | |
| 1385 | 128 => .{ .f128 = @floatFromInt(x) }, | |
| 1386 | else => unreachable, | |
| 1387 | }; | |
| 1388 | return Value.fromInterned(try pt.intern(.{ .float = .{ | |
| 1389 | .ty = dest_ty.toIntern(), | |
| 1390 | .storage = storage, | |
| 1391 | } })); | |
| 1392 | } | |
| 1393 | ||
| 1394 | 1059 | fn calcLimbLenFloat(scalar: anytype) usize { |
| 1395 | 1060 | if (scalar == 0) { |
| 1396 | 1061 | return 1; |
| ... | ... | @@ -1410,11 +1075,11 @@ pub fn numberMax(lhs: Value, rhs: Value, zcu: *Zcu) Value { |
| 1410 | 1075 | if (lhs.isUndef(zcu) or rhs.isUndef(zcu)) return undef; |
| 1411 | 1076 | if (lhs.isNan(zcu)) return rhs; |
| 1412 | 1077 | if (rhs.isNan(zcu)) return lhs; |
| 1413 | ||
| 1414 | return switch (order(lhs, rhs, zcu)) { | |
| 1415 | .lt => rhs, | |
| 1416 | .gt, .eq => lhs, | |
| 1417 | }; | |
| 1078 | if (compareHetero(lhs, .gt, rhs, zcu)) { | |
| 1079 | return lhs; | |
| 1080 | } else { | |
| 1081 | return rhs; | |
| 1082 | } | |
| 1418 | 1083 | } |
| 1419 | 1084 | |
| 1420 | 1085 | /// Supports both floats and ints; handles undefined. |
| ... | ... | @@ -1422,11 +1087,11 @@ pub fn numberMin(lhs: Value, rhs: Value, zcu: *Zcu) Value { |
| 1422 | 1087 | if (lhs.isUndef(zcu) or rhs.isUndef(zcu)) return undef; |
| 1423 | 1088 | if (lhs.isNan(zcu)) return rhs; |
| 1424 | 1089 | if (rhs.isNan(zcu)) return lhs; |
| 1425 | ||
| 1426 | return switch (order(lhs, rhs, zcu)) { | |
| 1427 | .lt => lhs, | |
| 1428 | .gt, .eq => rhs, | |
| 1429 | }; | |
| 1090 | if (compareHetero(lhs, .lt, rhs, zcu)) { | |
| 1091 | return lhs; | |
| 1092 | } else { | |
| 1093 | return rhs; | |
| 1094 | } | |
| 1430 | 1095 | } |
| 1431 | 1096 | |
| 1432 | 1097 | /// Returns true if the value is a floating point type and is NaN. Returns false otherwise. |
| ... | ... | @@ -2035,6 +1700,7 @@ pub fn makeBool(x: bool) Value { |
| 2035 | 1700 | /// Returns a pointer to the payload of the optional. |
| 2036 | 1701 | /// |
| 2037 | 1702 | /// May perform type resolution. |
| 1703 | /// MLUGG TODO audit | |
| 2038 | 1704 | pub fn ptrOptPayload(parent_ptr: Value, pt: Zcu.PerThread) !Value { |
| 2039 | 1705 | const zcu = pt.zcu; |
| 2040 | 1706 | const parent_ptr_ty = parent_ptr.typeOf(zcu); |
| ... | ... | @@ -2044,7 +1710,7 @@ pub fn ptrOptPayload(parent_ptr: Value, pt: Zcu.PerThread) !Value { |
| 2044 | 1710 | assert(ptr_size == .one or ptr_size == .c); |
| 2045 | 1711 | assert(opt_ty.zigTypeTag(zcu) == .optional); |
| 2046 | 1712 | |
| 2047 | const result_ty = try pt.ptrTypeSema(info: { | |
| 1713 | const result_ty = try pt.ptrType(info: { | |
| 2048 | 1714 | var new = parent_ptr_ty.ptrInfo(zcu); |
| 2049 | 1715 | // We can correctly preserve alignment `.none`, since an optional has the same |
| 2050 | 1716 | // natural alignment as its child type. |
| ... | ... | @@ -2070,6 +1736,7 @@ pub fn ptrOptPayload(parent_ptr: Value, pt: Zcu.PerThread) !Value { |
| 2070 | 1736 | /// `parent_ptr` must be a single-pointer to some error union. |
| 2071 | 1737 | /// Returns a pointer to the payload of the error union. |
| 2072 | 1738 | /// May perform type resolution. |
| 1739 | /// MLUGG TODO audit | |
| 2073 | 1740 | pub fn ptrEuPayload(parent_ptr: Value, pt: Zcu.PerThread) !Value { |
| 2074 | 1741 | const zcu = pt.zcu; |
| 2075 | 1742 | const parent_ptr_ty = parent_ptr.typeOf(zcu); |
| ... | ... | @@ -2078,7 +1745,7 @@ pub fn ptrEuPayload(parent_ptr: Value, pt: Zcu.PerThread) !Value { |
| 2078 | 1745 | assert(parent_ptr_ty.ptrSize(zcu) == .one); |
| 2079 | 1746 | assert(eu_ty.zigTypeTag(zcu) == .error_union); |
| 2080 | 1747 | |
| 2081 | const result_ty = try pt.ptrTypeSema(info: { | |
| 1748 | const result_ty = try pt.ptrType(info: { | |
| 2082 | 1749 | var new = parent_ptr_ty.ptrInfo(zcu); |
| 2083 | 1750 | // We can correctly preserve alignment `.none`, since an error union has a |
| 2084 | 1751 | // natural alignment greater than or equal to that of its payload type. |
| ... | ... | @@ -2096,6 +1763,8 @@ pub fn ptrEuPayload(parent_ptr: Value, pt: Zcu.PerThread) !Value { |
| 2096 | 1763 | } })); |
| 2097 | 1764 | } |
| 2098 | 1765 | |
| 1766 | // MLUGG TODO: audit ptrField etc in terms of resolution, and probably move them under sema | |
| 1767 | ||
| 2099 | 1768 | /// `parent_ptr` must be a single-pointer or c pointer to a struct, union, or slice. |
| 2100 | 1769 | /// |
| 2101 | 1770 | /// Returns a pointer to the aggregate field at the specified index. |
| ... | ... | @@ -2112,23 +1781,34 @@ pub fn ptrField(parent_ptr: Value, field_idx: u32, pt: Zcu.PerThread) !Value { |
| 2112 | 1781 | assert(parent_ptr_info.flags.size == .one or parent_ptr_info.flags.size == .c); |
| 2113 | 1782 | |
| 2114 | 1783 | // Exiting this `switch` indicates that the `field` pointer representation should be used. |
| 2115 | // `field_align` may be `.none` to represent the natural alignment of `field_ty`, but is not necessarily. | |
| 2116 | const field_ty: Type, const field_align: InternPool.Alignment = switch (aggregate_ty.zigTypeTag(zcu)) { | |
| 1784 | const field_ty: Type, const new_align: InternPool.Alignment = switch (aggregate_ty.zigTypeTag(zcu)) { | |
| 2117 | 1785 | .@"struct" => field: { |
| 2118 | 1786 | const field_ty = aggregate_ty.fieldType(field_idx, zcu); |
| 2119 | 1787 | switch (aggregate_ty.containerLayout(zcu)) { |
| 2120 | .auto => break :field .{ field_ty, try aggregate_ty.fieldAlignmentSema(field_idx, pt) }, | |
| 1788 | .auto => break :field .{ field_ty, a: { | |
| 1789 | if (parent_ptr_info.flags.alignment == .none) { | |
| 1790 | break :a aggregate_ty.explicitFieldAlignment(field_idx, zcu); | |
| 1791 | } | |
| 1792 | const field_align = aggregate_ty.resolvedFieldAlignment(field_idx, zcu); | |
| 1793 | break :a field_align.min(parent_ptr_info.flags.alignment); | |
| 1794 | } }, | |
| 2121 | 1795 | .@"extern" => { |
| 2122 | 1796 | // Well-defined layout, so just offset the pointer appropriately. |
| 2123 | try aggregate_ty.resolveLayout(pt); | |
| 2124 | 1797 | const byte_off = aggregate_ty.structFieldOffset(field_idx, zcu); |
| 2125 | const field_align = a: { | |
| 1798 | const field_align: InternPool.Alignment = a: { | |
| 1799 | if (byte_off == 0) break :a parent_ptr_info.flags.alignment; | |
| 1800 | const true_field_align: InternPool.Alignment = .fromLog2Units(@ctz(byte_off)); | |
| 1801 | if (parent_ptr_info.flags.alignment == .none and | |
| 1802 | true_field_align == field_ty.abiAlignment(zcu)) | |
| 1803 | { | |
| 1804 | break :a .none; | |
| 1805 | } | |
| 2126 | 1806 | const parent_align = if (parent_ptr_info.flags.alignment == .none) pa: { |
| 2127 | break :pa try aggregate_ty.abiAlignmentSema(pt); | |
| 1807 | break :pa aggregate_ty.abiAlignment(zcu); | |
| 2128 | 1808 | } else parent_ptr_info.flags.alignment; |
| 2129 | break :a InternPool.Alignment.fromLog2Units(@min(parent_align.toLog2Units(), @ctz(byte_off))); | |
| 1809 | break :a .minStrict(true_field_align, parent_align); | |
| 2130 | 1810 | }; |
| 2131 | const result_ty = try pt.ptrTypeSema(info: { | |
| 1811 | const result_ty = try pt.ptrType(info: { | |
| 2132 | 1812 | var new = parent_ptr_info; |
| 2133 | 1813 | new.child = field_ty.toIntern(); |
| 2134 | 1814 | new.flags.alignment = field_align; |
| ... | ... | @@ -2143,7 +1823,7 @@ pub fn ptrField(parent_ptr: Value, field_idx: u32, pt: Zcu.PerThread) !Value { |
| 2143 | 1823 | new.packed_offset = packed_offset; |
| 2144 | 1824 | new.child = field_ty.toIntern(); |
| 2145 | 1825 | if (new.flags.alignment == .none) { |
| 2146 | new.flags.alignment = try aggregate_ty.abiAlignmentSema(pt); | |
| 1826 | new.flags.alignment = aggregate_ty.abiAlignment(zcu); | |
| 2147 | 1827 | } |
| 2148 | 1828 | break :info new; |
| 2149 | 1829 | }); |
| ... | ... | @@ -2155,10 +1835,16 @@ pub fn ptrField(parent_ptr: Value, field_idx: u32, pt: Zcu.PerThread) !Value { |
| 2155 | 1835 | const union_obj = zcu.typeToUnion(aggregate_ty).?; |
| 2156 | 1836 | const field_ty = Type.fromInterned(union_obj.field_types.get(&zcu.intern_pool)[field_idx]); |
| 2157 | 1837 | switch (aggregate_ty.containerLayout(zcu)) { |
| 2158 | .auto => break :field .{ field_ty, try aggregate_ty.fieldAlignmentSema(field_idx, pt) }, | |
| 1838 | .auto => break :field .{ field_ty, a: { | |
| 1839 | if (parent_ptr_info.flags.alignment == .none) { | |
| 1840 | break :a aggregate_ty.explicitFieldAlignment(field_idx, zcu); | |
| 1841 | } | |
| 1842 | const field_align = aggregate_ty.resolvedFieldAlignment(field_idx, zcu); | |
| 1843 | break :a field_align.min(parent_ptr_info.flags.alignment); | |
| 1844 | } }, | |
| 2159 | 1845 | .@"extern" => { |
| 2160 | 1846 | // Point to the same address. |
| 2161 | const result_ty = try pt.ptrTypeSema(info: { | |
| 1847 | const result_ty = try pt.ptrType(info: { | |
| 2162 | 1848 | var new = parent_ptr_info; |
| 2163 | 1849 | new.child = field_ty.toIntern(); |
| 2164 | 1850 | break :info new; |
| ... | ... | @@ -2166,59 +1852,30 @@ pub fn ptrField(parent_ptr: Value, field_idx: u32, pt: Zcu.PerThread) !Value { |
| 2166 | 1852 | return pt.getCoerced(parent_ptr, result_ty); |
| 2167 | 1853 | }, |
| 2168 | 1854 | .@"packed" => { |
| 2169 | // If the field has an ABI size matching its bit size, then we can continue to use a | |
| 2170 | // non-bit pointer if the parent pointer is also a non-bit pointer. | |
| 2171 | if (parent_ptr_info.packed_offset.host_size == 0 and (try field_ty.abiSizeInner(.sema, zcu, pt.tid)).scalar * 8 == try field_ty.bitSizeSema(pt)) { | |
| 2172 | // We must offset the pointer on big-endian targets, since the bits of packed memory don't align nicely. | |
| 2173 | const byte_offset = switch (zcu.getTarget().cpu.arch.endian()) { | |
| 2174 | .little => 0, | |
| 2175 | .big => (try aggregate_ty.abiSizeInner(.sema, zcu, pt.tid)).scalar - (try field_ty.abiSizeInner(.sema, zcu, pt.tid)).scalar, | |
| 2176 | }; | |
| 2177 | const result_ty = try pt.ptrTypeSema(info: { | |
| 2178 | var new = parent_ptr_info; | |
| 2179 | new.child = field_ty.toIntern(); | |
| 2180 | new.flags.alignment = InternPool.Alignment.fromLog2Units( | |
| 2181 | @ctz(byte_offset | (try parent_ptr_ty.ptrAlignmentSema(pt)).toByteUnits().?), | |
| 2182 | ); | |
| 2183 | break :info new; | |
| 2184 | }); | |
| 2185 | return parent_ptr.getOffsetPtr(byte_offset, result_ty, pt); | |
| 2186 | } else { | |
| 2187 | // The result must be a bit-pointer if it is not already. | |
| 2188 | const result_ty = try pt.ptrTypeSema(info: { | |
| 2189 | var new = parent_ptr_info; | |
| 2190 | new.child = field_ty.toIntern(); | |
| 2191 | if (new.packed_offset.host_size == 0) { | |
| 2192 | new.packed_offset.host_size = @intCast(((try aggregate_ty.bitSizeSema(pt)) + 7) / 8); | |
| 2193 | assert(new.packed_offset.bit_offset == 0); | |
| 2194 | } | |
| 2195 | break :info new; | |
| 2196 | }); | |
| 2197 | return pt.getCoerced(parent_ptr, result_ty); | |
| 2198 | } | |
| 1855 | const result_ty = try pt.ptrType(info: { | |
| 1856 | var new = parent_ptr_info; | |
| 1857 | new.child = field_ty.toIntern(); | |
| 1858 | break :info new; | |
| 1859 | }); | |
| 1860 | return pt.getCoerced(parent_ptr, result_ty); | |
| 2199 | 1861 | }, |
| 2200 | 1862 | } |
| 2201 | 1863 | }, |
| 2202 | 1864 | .pointer => field_ty: { |
| 2203 | 1865 | assert(aggregate_ty.isSlice(zcu)); |
| 2204 | break :field_ty switch (field_idx) { | |
| 2205 | Value.slice_ptr_index => .{ aggregate_ty.slicePtrFieldType(zcu), Type.usize.abiAlignment(zcu) }, | |
| 2206 | Value.slice_len_index => .{ Type.usize, Type.usize.abiAlignment(zcu) }, | |
| 1866 | break :field_ty .{ switch (field_idx) { | |
| 1867 | Value.slice_ptr_index => aggregate_ty.slicePtrFieldType(zcu), | |
| 1868 | Value.slice_len_index => Type.usize, | |
| 2207 | 1869 | else => unreachable, |
| 2208 | }; | |
| 1870 | }, switch (parent_ptr_info.flags.alignment) { | |
| 1871 | .none => .none, | |
| 1872 | else => Type.usize.abiAlignment(zcu).min(parent_ptr_info.flags.alignment), | |
| 1873 | } }; | |
| 2209 | 1874 | }, |
| 2210 | 1875 | else => unreachable, |
| 2211 | 1876 | }; |
| 2212 | 1877 | |
| 2213 | const new_align: InternPool.Alignment = if (parent_ptr_info.flags.alignment != .none) a: { | |
| 2214 | const ty_align = (try field_ty.abiAlignmentInner(.sema, zcu, pt.tid)).scalar; | |
| 2215 | const true_field_align = if (field_align == .none) ty_align else field_align; | |
| 2216 | const new_align = true_field_align.min(parent_ptr_info.flags.alignment); | |
| 2217 | if (new_align == ty_align) break :a .none; | |
| 2218 | break :a new_align; | |
| 2219 | } else field_align; | |
| 2220 | ||
| 2221 | const result_ty = try pt.ptrTypeSema(info: { | |
| 1878 | const result_ty = try pt.ptrType(info: { | |
| 2222 | 1879 | var new = parent_ptr_info; |
| 2223 | 1880 | new.child = field_ty.toIntern(); |
| 2224 | 1881 | new.flags.alignment = new_align; |
| ... | ... | @@ -2241,6 +1898,7 @@ pub fn ptrField(parent_ptr: Value, field_idx: u32, pt: Zcu.PerThread) !Value { |
| 2241 | 1898 | /// `orig_parent_ptr` must be either a single-pointer to an array or vector, or a many-pointer or C-pointer or slice. |
| 2242 | 1899 | /// Returns a pointer to the element at the specified index. |
| 2243 | 1900 | /// May perform type resolution. |
| 1901 | /// MLUGG TODO AUDIT | |
| 2244 | 1902 | pub fn ptrElem(orig_parent_ptr: Value, field_idx: u64, pt: Zcu.PerThread) !Value { |
| 2245 | 1903 | const zcu = pt.zcu; |
| 2246 | 1904 | const parent_ptr = switch (orig_parent_ptr.typeOf(zcu).ptrSize(zcu)) { |
| ... | ... | @@ -2267,21 +1925,19 @@ pub fn ptrElem(orig_parent_ptr: Value, field_idx: u64, pt: Zcu.PerThread) !Value |
| 2267 | 1925 | |
| 2268 | 1926 | const strat: PtrStrat = switch (parent_ptr_ty.ptrSize(zcu)) { |
| 2269 | 1927 | .one => switch (elem_ty.zigTypeTag(zcu)) { |
| 2270 | .vector => .{ .offset = field_idx * @divExact(try elem_ty.childType(zcu).bitSizeSema(pt), 8) }, | |
| 1928 | .vector => .{ .offset = field_idx * @divExact(elem_ty.childType(zcu).bitSize(zcu), 8) }, | |
| 2271 | 1929 | .array => strat: { |
| 2272 | 1930 | const arr_elem_ty = elem_ty.childType(zcu); |
| 2273 | if (try arr_elem_ty.comptimeOnlySema(pt)) { | |
| 2274 | break :strat .{ .elem_ptr = arr_elem_ty }; | |
| 2275 | } | |
| 2276 | break :strat .{ .offset = field_idx * (try arr_elem_ty.abiSizeInner(.sema, zcu, pt.tid)).scalar }; | |
| 1931 | if (arr_elem_ty.comptimeOnly(zcu)) break :strat .{ .elem_ptr = arr_elem_ty }; | |
| 1932 | break :strat .{ .offset = field_idx * arr_elem_ty.abiSize(zcu) }; | |
| 2277 | 1933 | }, |
| 2278 | 1934 | else => unreachable, |
| 2279 | 1935 | }, |
| 2280 | 1936 | |
| 2281 | .many, .c => if (try elem_ty.comptimeOnlySema(pt)) | |
| 1937 | .many, .c => if (elem_ty.comptimeOnly(zcu)) | |
| 2282 | 1938 | .{ .elem_ptr = elem_ty } |
| 2283 | 1939 | else |
| 2284 | .{ .offset = field_idx * (try elem_ty.abiSizeInner(.sema, zcu, pt.tid)).scalar }, | |
| 1940 | .{ .offset = field_idx * elem_ty.abiSize(zcu) }, | |
| 2285 | 1941 | |
| 2286 | 1942 | .slice => unreachable, |
| 2287 | 1943 | }; |
| ... | ... | @@ -2430,6 +2086,7 @@ pub fn pointerDerivation(ptr_val: Value, arena: Allocator, pt: Zcu.PerThread) Al |
| 2430 | 2086 | /// which prefer field/elem accesses when lowering constant pointer values. |
| 2431 | 2087 | /// It is also used by the Value printing logic for pointers. |
| 2432 | 2088 | pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerThread, comptime resolve_types: bool, opt_sema: ?*Sema) !PointerDeriveStep { |
| 2089 | // MLUGG TODO: audit tf outta this code | |
| 2433 | 2090 | const zcu = pt.zcu; |
| 2434 | 2091 | const ptr = zcu.intern_pool.indexToKey(ptr_val.toIntern()).ptr; |
| 2435 | 2092 | const base_derive: PointerDeriveStep = switch (ptr.base_addr) { |
| ... | ... | @@ -2454,7 +2111,7 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh |
| 2454 | 2111 | .comptime_alloc => |idx| base: { |
| 2455 | 2112 | const sema = opt_sema.?; |
| 2456 | 2113 | const alloc = sema.getComptimeAlloc(idx); |
| 2457 | const val = try alloc.val.intern(pt, sema.arena); | |
| 2114 | const val = try alloc.val.intern(pt, arena); | |
| 2458 | 2115 | const ty = val.typeOf(zcu); |
| 2459 | 2116 | break :base .{ .comptime_alloc_ptr = .{ |
| 2460 | 2117 | .idx = idx, |
| ... | ... | @@ -2492,24 +2149,14 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh |
| 2492 | 2149 | const base_ptr = Value.fromInterned(field.base); |
| 2493 | 2150 | const base_ptr_ty = base_ptr.typeOf(zcu); |
| 2494 | 2151 | const agg_ty = base_ptr_ty.childType(zcu); |
| 2495 | const field_ty, const field_align = switch (agg_ty.zigTypeTag(zcu)) { | |
| 2496 | .@"struct" => .{ agg_ty.fieldType(@intCast(field.index), zcu), try agg_ty.fieldAlignmentInner( | |
| 2497 | @intCast(field.index), | |
| 2498 | if (resolve_types) .sema else .normal, | |
| 2499 | pt.zcu, | |
| 2500 | if (resolve_types) pt.tid else {}, | |
| 2501 | ) }, | |
| 2502 | .@"union" => .{ agg_ty.unionFieldTypeByIndex(@intCast(field.index), zcu), try agg_ty.fieldAlignmentInner( | |
| 2503 | @intCast(field.index), | |
| 2504 | if (resolve_types) .sema else .normal, | |
| 2505 | pt.zcu, | |
| 2506 | if (resolve_types) pt.tid else {}, | |
| 2507 | ) }, | |
| 2508 | .pointer => .{ switch (field.index) { | |
| 2509 | Value.slice_ptr_index => agg_ty.slicePtrFieldType(zcu), | |
| 2510 | Value.slice_len_index => Type.usize, | |
| 2152 | if (resolve_types) try opt_sema.?.ensureLayoutResolved(agg_ty); | |
| 2153 | const field_ty: Type, const field_align: InternPool.Alignment = switch (agg_ty.zigTypeTag(zcu)) { | |
| 2154 | .@"struct", .@"union" => .{ agg_ty.fieldType(@intCast(field.index), zcu), agg_ty.resolvedFieldAlignment(@intCast(field.index), pt.zcu) }, | |
| 2155 | .pointer => switch (field.index) { | |
| 2156 | Value.slice_ptr_index => .{ agg_ty.slicePtrFieldType(zcu), Type.ptrAbiAlignment(zcu.getTarget()) }, | |
| 2157 | Value.slice_len_index => .{ .usize, Type.abiAlignment(.usize, zcu) }, | |
| 2511 | 2158 | else => unreachable, |
| 2512 | }, Type.usize.abiAlignment(zcu) }, | |
| 2159 | }, | |
| 2513 | 2160 | else => unreachable, |
| 2514 | 2161 | }; |
| 2515 | 2162 | const base_align = base_ptr_ty.ptrAlignment(zcu); |
| ... | ... | @@ -2720,148 +2367,6 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh |
| 2720 | 2367 | } }; |
| 2721 | 2368 | } |
| 2722 | 2369 | |
| 2723 | pub fn resolveLazy( | |
| 2724 | val: Value, | |
| 2725 | arena: Allocator, | |
| 2726 | pt: Zcu.PerThread, | |
| 2727 | ) Zcu.SemaError!Value { | |
| 2728 | switch (pt.zcu.intern_pool.indexToKey(val.toIntern())) { | |
| 2729 | .int => |int| switch (int.storage) { | |
| 2730 | .u64, .i64, .big_int => return val, | |
| 2731 | .lazy_align, .lazy_size => return pt.intValue( | |
| 2732 | Type.fromInterned(int.ty), | |
| 2733 | try val.toUnsignedIntSema(pt), | |
| 2734 | ), | |
| 2735 | }, | |
| 2736 | .slice => |slice| { | |
| 2737 | const ptr = try Value.fromInterned(slice.ptr).resolveLazy(arena, pt); | |
| 2738 | const len = try Value.fromInterned(slice.len).resolveLazy(arena, pt); | |
| 2739 | if (ptr.toIntern() == slice.ptr and len.toIntern() == slice.len) return val; | |
| 2740 | return Value.fromInterned(try pt.intern(.{ .slice = .{ | |
| 2741 | .ty = slice.ty, | |
| 2742 | .ptr = ptr.toIntern(), | |
| 2743 | .len = len.toIntern(), | |
| 2744 | } })); | |
| 2745 | }, | |
| 2746 | .ptr => |ptr| { | |
| 2747 | switch (ptr.base_addr) { | |
| 2748 | .nav, .comptime_alloc, .uav, .int => return val, | |
| 2749 | .comptime_field => |field_val| { | |
| 2750 | const resolved_field_val = (try Value.fromInterned(field_val).resolveLazy(arena, pt)).toIntern(); | |
| 2751 | return if (resolved_field_val == field_val) | |
| 2752 | val | |
| 2753 | else | |
| 2754 | Value.fromInterned(try pt.intern(.{ .ptr = .{ | |
| 2755 | .ty = ptr.ty, | |
| 2756 | .base_addr = .{ .comptime_field = resolved_field_val }, | |
| 2757 | .byte_offset = ptr.byte_offset, | |
| 2758 | } })); | |
| 2759 | }, | |
| 2760 | .eu_payload, .opt_payload => |base| { | |
| 2761 | const resolved_base = (try Value.fromInterned(base).resolveLazy(arena, pt)).toIntern(); | |
| 2762 | return if (resolved_base == base) | |
| 2763 | val | |
| 2764 | else | |
| 2765 | Value.fromInterned(try pt.intern(.{ .ptr = .{ | |
| 2766 | .ty = ptr.ty, | |
| 2767 | .base_addr = switch (ptr.base_addr) { | |
| 2768 | .eu_payload => .{ .eu_payload = resolved_base }, | |
| 2769 | .opt_payload => .{ .opt_payload = resolved_base }, | |
| 2770 | else => unreachable, | |
| 2771 | }, | |
| 2772 | .byte_offset = ptr.byte_offset, | |
| 2773 | } })); | |
| 2774 | }, | |
| 2775 | .arr_elem, .field => |base_index| { | |
| 2776 | const resolved_base = (try Value.fromInterned(base_index.base).resolveLazy(arena, pt)).toIntern(); | |
| 2777 | return if (resolved_base == base_index.base) | |
| 2778 | val | |
| 2779 | else | |
| 2780 | Value.fromInterned(try pt.intern(.{ .ptr = .{ | |
| 2781 | .ty = ptr.ty, | |
| 2782 | .base_addr = switch (ptr.base_addr) { | |
| 2783 | .arr_elem => .{ .arr_elem = .{ | |
| 2784 | .base = resolved_base, | |
| 2785 | .index = base_index.index, | |
| 2786 | } }, | |
| 2787 | .field => .{ .field = .{ | |
| 2788 | .base = resolved_base, | |
| 2789 | .index = base_index.index, | |
| 2790 | } }, | |
| 2791 | else => unreachable, | |
| 2792 | }, | |
| 2793 | .byte_offset = ptr.byte_offset, | |
| 2794 | } })); | |
| 2795 | }, | |
| 2796 | } | |
| 2797 | }, | |
| 2798 | .aggregate => |aggregate| switch (aggregate.storage) { | |
| 2799 | .bytes => return val, | |
| 2800 | .elems => |elems| { | |
| 2801 | var resolved_elems: []InternPool.Index = &.{}; | |
| 2802 | for (elems, 0..) |elem, i| { | |
| 2803 | const resolved_elem = (try Value.fromInterned(elem).resolveLazy(arena, pt)).toIntern(); | |
| 2804 | if (resolved_elems.len == 0 and resolved_elem != elem) { | |
| 2805 | resolved_elems = try arena.alloc(InternPool.Index, elems.len); | |
| 2806 | @memcpy(resolved_elems[0..i], elems[0..i]); | |
| 2807 | } | |
| 2808 | if (resolved_elems.len > 0) resolved_elems[i] = resolved_elem; | |
| 2809 | } | |
| 2810 | return if (resolved_elems.len == 0) | |
| 2811 | val | |
| 2812 | else | |
| 2813 | pt.aggregateValue(.fromInterned(aggregate.ty), resolved_elems); | |
| 2814 | }, | |
| 2815 | .repeated_elem => |elem| { | |
| 2816 | const resolved_elem = try Value.fromInterned(elem).resolveLazy(arena, pt); | |
| 2817 | return if (resolved_elem.toIntern() == elem) | |
| 2818 | val | |
| 2819 | else | |
| 2820 | pt.aggregateSplatValue(.fromInterned(aggregate.ty), resolved_elem); | |
| 2821 | }, | |
| 2822 | }, | |
| 2823 | .un => |un| { | |
| 2824 | const resolved_tag = if (un.tag == .none) | |
| 2825 | .none | |
| 2826 | else | |
| 2827 | (try Value.fromInterned(un.tag).resolveLazy(arena, pt)).toIntern(); | |
| 2828 | const resolved_val = (try Value.fromInterned(un.val).resolveLazy(arena, pt)).toIntern(); | |
| 2829 | return if (resolved_tag == un.tag and resolved_val == un.val) | |
| 2830 | val | |
| 2831 | else | |
| 2832 | Value.fromInterned(try pt.internUnion(.{ | |
| 2833 | .ty = un.ty, | |
| 2834 | .tag = resolved_tag, | |
| 2835 | .val = resolved_val, | |
| 2836 | })); | |
| 2837 | }, | |
| 2838 | .error_union => |eu| switch (eu.val) { | |
| 2839 | .err_name => return val, | |
| 2840 | .payload => |payload| { | |
| 2841 | const resolved_payload = try Value.fromInterned(payload).resolveLazy(arena, pt); | |
| 2842 | if (resolved_payload.toIntern() == payload) return val; | |
| 2843 | return .fromInterned(try pt.intern(.{ .error_union = .{ | |
| 2844 | .ty = eu.ty, | |
| 2845 | .val = .{ .payload = resolved_payload.toIntern() }, | |
| 2846 | } })); | |
| 2847 | }, | |
| 2848 | }, | |
| 2849 | .opt => |opt| switch (opt.val) { | |
| 2850 | .none => return val, | |
| 2851 | else => |payload| { | |
| 2852 | const resolved_payload = try Value.fromInterned(payload).resolveLazy(arena, pt); | |
| 2853 | if (resolved_payload.toIntern() == payload) return val; | |
| 2854 | return .fromInterned(try pt.intern(.{ .opt = .{ | |
| 2855 | .ty = opt.ty, | |
| 2856 | .val = resolved_payload.toIntern(), | |
| 2857 | } })); | |
| 2858 | }, | |
| 2859 | }, | |
| 2860 | ||
| 2861 | else => return val, | |
| 2862 | } | |
| 2863 | } | |
| 2864 | ||
| 2865 | 2370 | const InterpretMode = enum { |
| 2866 | 2371 | /// In this mode, types are assumed to match what the compiler was built with in terms of field |
| 2867 | 2372 | /// order, field types, etc. This improves compiler performance. However, it means that certain |
| ... | ... | @@ -2878,7 +2383,6 @@ const interpret_mode: InterpretMode = @field(InterpretMode, @tagName(build_optio |
| 2878 | 2383 | |
| 2879 | 2384 | /// Given a `Value` representing a comptime-known value of type `T`, unwrap it into an actual `T` known to the compiler. |
| 2880 | 2385 | /// This is useful for accessing `std.builtin` structures received from comptime logic. |
| 2881 | /// `val` must be fully resolved. | |
| 2882 | 2386 | pub fn interpret(val: Value, comptime T: type, pt: Zcu.PerThread) error{ OutOfMemory, UndefinedValue, TypeMismatch }!T { |
| 2883 | 2387 | const zcu = pt.zcu; |
| 2884 | 2388 | const io = zcu.comp.io; |
| ... | ... | @@ -2917,7 +2421,6 @@ pub fn interpret(val: Value, comptime T: type, pt: Zcu.PerThread) error{ OutOfMe |
| 2917 | 2421 | }, |
| 2918 | 2422 | |
| 2919 | 2423 | .int => switch (ip.indexToKey(val.toIntern()).int.storage) { |
| 2920 | .lazy_align, .lazy_size => unreachable, // `val` is fully resolved | |
| 2921 | 2424 | inline .u64, .i64 => |x| std.math.cast(T, x) orelse return error.TypeMismatch, |
| 2922 | 2425 | .big_int => |big| big.toInt(T) catch return error.TypeMismatch, |
| 2923 | 2426 | }, |
src/Zcu.zig+84-79| ... | ... | @@ -14,6 +14,8 @@ const mem = std.mem; |
| 14 | 14 | const Allocator = std.mem.Allocator; |
| 15 | 15 | const assert = std.debug.assert; |
| 16 | 16 | const log = std.log.scoped(.zcu); |
| 17 | const deps_log = std.log.scoped(.zcu_deps); | |
| 18 | const refs_log = std.log.scoped(.zcu_refs); | |
| 17 | 19 | const BigIntConst = std.math.big.int.Const; |
| 18 | 20 | const BigIntMutable = std.math.big.int.Mutable; |
| 19 | 21 | const Target = std.Target; |
| ... | ... | @@ -2685,10 +2687,10 @@ pub const LazySrcLoc = struct { |
| 2685 | 2687 | .struct_init, .struct_init_ref => zir.extraData(Zir.Inst.StructInit, inst.data.pl_node.payload_index).data.abs_node, |
| 2686 | 2688 | .struct_init_anon => zir.extraData(Zir.Inst.StructInitAnon, inst.data.pl_node.payload_index).data.abs_node, |
| 2687 | 2689 | .extended => switch (inst.data.extended.opcode) { |
| 2688 | .struct_decl => zir.extraData(Zir.Inst.StructDecl, inst.data.extended.operand).data.src_node, | |
| 2689 | .union_decl => zir.extraData(Zir.Inst.UnionDecl, inst.data.extended.operand).data.src_node, | |
| 2690 | .enum_decl => zir.extraData(Zir.Inst.EnumDecl, inst.data.extended.operand).data.src_node, | |
| 2691 | .opaque_decl => zir.extraData(Zir.Inst.OpaqueDecl, inst.data.extended.operand).data.src_node, | |
| 2690 | .struct_decl => zir.getStructDecl(zir_inst).src_node, | |
| 2691 | .union_decl => zir.getUnionDecl(zir_inst).src_node, | |
| 2692 | .enum_decl => zir.getEnumDecl(zir_inst).src_node, | |
| 2693 | .opaque_decl => zir.getOpaqueDecl(zir_inst).src_node, | |
| 2692 | 2694 | .reify_enum => zir.extraData(Zir.Inst.ReifyEnum, inst.data.extended.operand).data.node, |
| 2693 | 2695 | .reify_struct => zir.extraData(Zir.Inst.ReifyStruct, inst.data.extended.operand).data.node, |
| 2694 | 2696 | .reify_union => zir.extraData(Zir.Inst.ReifyUnion, inst.data.extended.operand).data.node, |
| ... | ... | @@ -3063,7 +3065,7 @@ pub fn markDependeeOutdated( |
| 3063 | 3065 | marked_po: enum { not_marked_po, marked_po }, |
| 3064 | 3066 | dependee: InternPool.Dependee, |
| 3065 | 3067 | ) !void { |
| 3066 | log.debug("outdated dependee: {f}", .{zcu.fmtDependee(dependee)}); | |
| 3068 | deps_log.debug("outdated dependee: {f}", .{zcu.fmtDependee(dependee)}); | |
| 3067 | 3069 | var it = zcu.intern_pool.dependencyIterator(dependee); |
| 3068 | 3070 | while (it.next()) |depender| { |
| 3069 | 3071 | if (zcu.outdated.getPtr(depender)) |po_dep_count| { |
| ... | ... | @@ -3071,9 +3073,9 @@ pub fn markDependeeOutdated( |
| 3071 | 3073 | .not_marked_po => {}, |
| 3072 | 3074 | .marked_po => { |
| 3073 | 3075 | po_dep_count.* -= 1; |
| 3074 | log.debug("outdated {f} => already outdated {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), po_dep_count.* }); | |
| 3076 | deps_log.debug("outdated {f} => already outdated {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), po_dep_count.* }); | |
| 3075 | 3077 | if (po_dep_count.* == 0) { |
| 3076 | log.debug("outdated ready: {f}", .{zcu.fmtAnalUnit(depender)}); | |
| 3078 | deps_log.debug("outdated ready: {f}", .{zcu.fmtAnalUnit(depender)}); | |
| 3077 | 3079 | try zcu.outdated_ready.put(zcu.gpa, depender, {}); |
| 3078 | 3080 | } |
| 3079 | 3081 | }, |
| ... | ... | @@ -3094,9 +3096,9 @@ pub fn markDependeeOutdated( |
| 3094 | 3096 | depender, |
| 3095 | 3097 | new_po_dep_count, |
| 3096 | 3098 | ); |
| 3097 | log.debug("outdated {f} => new outdated {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), new_po_dep_count }); | |
| 3099 | deps_log.debug("outdated {f} => new outdated {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), new_po_dep_count }); | |
| 3098 | 3100 | if (new_po_dep_count == 0) { |
| 3099 | log.debug("outdated ready: {f}", .{zcu.fmtAnalUnit(depender)}); | |
| 3101 | deps_log.debug("outdated ready: {f}", .{zcu.fmtAnalUnit(depender)}); | |
| 3100 | 3102 | try zcu.outdated_ready.put(zcu.gpa, depender, {}); |
| 3101 | 3103 | } |
| 3102 | 3104 | // If this is a Decl and was not previously PO, we must recursively |
| ... | ... | @@ -3109,16 +3111,16 @@ pub fn markDependeeOutdated( |
| 3109 | 3111 | } |
| 3110 | 3112 | |
| 3111 | 3113 | pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void { |
| 3112 | log.debug("up-to-date dependee: {f}", .{zcu.fmtDependee(dependee)}); | |
| 3114 | deps_log.debug("up-to-date dependee: {f}", .{zcu.fmtDependee(dependee)}); | |
| 3113 | 3115 | var it = zcu.intern_pool.dependencyIterator(dependee); |
| 3114 | 3116 | while (it.next()) |depender| { |
| 3115 | 3117 | if (zcu.outdated.getPtr(depender)) |po_dep_count| { |
| 3116 | 3118 | // This depender is already outdated, but it now has one |
| 3117 | 3119 | // less PO dependency! |
| 3118 | 3120 | po_dep_count.* -= 1; |
| 3119 | log.debug("up-to-date {f} => {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), po_dep_count.* }); | |
| 3121 | deps_log.debug("up-to-date {f} => {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), po_dep_count.* }); | |
| 3120 | 3122 | if (po_dep_count.* == 0) { |
| 3121 | log.debug("outdated ready: {f}", .{zcu.fmtAnalUnit(depender)}); | |
| 3123 | deps_log.debug("outdated ready: {f}", .{zcu.fmtAnalUnit(depender)}); | |
| 3122 | 3124 | try zcu.outdated_ready.put(zcu.gpa, depender, {}); |
| 3123 | 3125 | } |
| 3124 | 3126 | continue; |
| ... | ... | @@ -3132,11 +3134,11 @@ pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void { |
| 3132 | 3134 | }; |
| 3133 | 3135 | if (ptr.* > 1) { |
| 3134 | 3136 | ptr.* -= 1; |
| 3135 | log.debug("up-to-date {f} => {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), ptr.* }); | |
| 3137 | deps_log.debug("up-to-date {f} => {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), ptr.* }); | |
| 3136 | 3138 | continue; |
| 3137 | 3139 | } |
| 3138 | 3140 | |
| 3139 | log.debug("up-to-date {f} => {f} po_deps=0 (up-to-date)", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender) }); | |
| 3141 | deps_log.debug("up-to-date {f} => {f} po_deps=0 (up-to-date)", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender) }); | |
| 3140 | 3142 | |
| 3141 | 3143 | // This dependency is no longer PO, i.e. is known to be up-to-date. |
| 3142 | 3144 | assert(zcu.potentially_outdated.swapRemove(depender)); |
| ... | ... | @@ -3146,8 +3148,9 @@ pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void { |
| 3146 | 3148 | .@"comptime" => {}, |
| 3147 | 3149 | .nav_val => |nav| try zcu.markPoDependeeUpToDate(.{ .nav_val = nav }), |
| 3148 | 3150 | .nav_ty => |nav| try zcu.markPoDependeeUpToDate(.{ .nav_ty = nav }), |
| 3149 | .type => |ty| try zcu.markPoDependeeUpToDate(.{ .interned = ty }), | |
| 3150 | .func => |func| try zcu.markPoDependeeUpToDate(.{ .interned = func }), | |
| 3151 | .type_layout => |ty| try zcu.markPoDependeeUpToDate(.{ .type_layout = ty }), | |
| 3152 | .type_inits => |ty| try zcu.markPoDependeeUpToDate(.{ .type_inits = ty }), | |
| 3153 | .func => |func| try zcu.markPoDependeeUpToDate(.{ .func_ies = func }), | |
| 3151 | 3154 | .memoized_state => |stage| try zcu.markPoDependeeUpToDate(.{ .memoized_state = stage }), |
| 3152 | 3155 | } |
| 3153 | 3156 | } |
| ... | ... | @@ -3161,11 +3164,12 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUni |
| 3161 | 3164 | .@"comptime" => return, // analysis of a comptime decl can't outdate any dependencies |
| 3162 | 3165 | .nav_val => |nav| .{ .nav_val = nav }, |
| 3163 | 3166 | .nav_ty => |nav| .{ .nav_ty = nav }, |
| 3164 | .type => |ty| .{ .interned = ty }, | |
| 3165 | .func => |func_index| .{ .interned = func_index }, // IES | |
| 3167 | .type_layout => |ty| .{ .type_layout = ty }, | |
| 3168 | .type_inits => |ty| .{ .type_inits = ty }, | |
| 3169 | .func => |func_index| .{ .func_ies = func_index }, | |
| 3166 | 3170 | .memoized_state => |stage| .{ .memoized_state = stage }, |
| 3167 | 3171 | }; |
| 3168 | log.debug("potentially outdated dependee: {f}", .{zcu.fmtDependee(dependee)}); | |
| 3172 | deps_log.debug("potentially outdated dependee: {f}", .{zcu.fmtDependee(dependee)}); | |
| 3169 | 3173 | var it = ip.dependencyIterator(dependee); |
| 3170 | 3174 | while (it.next()) |po| { |
| 3171 | 3175 | if (zcu.outdated.getPtr(po)) |po_dep_count| { |
| ... | ... | @@ -3175,17 +3179,17 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUni |
| 3175 | 3179 | _ = zcu.outdated_ready.swapRemove(po); |
| 3176 | 3180 | } |
| 3177 | 3181 | po_dep_count.* += 1; |
| 3178 | log.debug("po {f} => {f} [outdated] po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(po), po_dep_count.* }); | |
| 3182 | deps_log.debug("po {f} => {f} [outdated] po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(po), po_dep_count.* }); | |
| 3179 | 3183 | continue; |
| 3180 | 3184 | } |
| 3181 | 3185 | if (zcu.potentially_outdated.getPtr(po)) |n| { |
| 3182 | 3186 | // There is now one more PO dependency. |
| 3183 | 3187 | n.* += 1; |
| 3184 | log.debug("po {f} => {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(po), n.* }); | |
| 3188 | deps_log.debug("po {f} => {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(po), n.* }); | |
| 3185 | 3189 | continue; |
| 3186 | 3190 | } |
| 3187 | 3191 | try zcu.potentially_outdated.putNoClobber(zcu.gpa, po, 1); |
| 3188 | log.debug("po {f} => {f} po_deps=1", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(po) }); | |
| 3192 | deps_log.debug("po {f} => {f} po_deps=1", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(po) }); | |
| 3189 | 3193 | // This AnalUnit was not already PO, so we must recursively mark its dependers as also PO. |
| 3190 | 3194 | try zcu.markTransitiveDependersPotentiallyOutdated(po); |
| 3191 | 3195 | } |
| ... | ... | @@ -3240,13 +3244,15 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit { |
| 3240 | 3244 | var chosen_unit: ?AnalUnit = null; |
| 3241 | 3245 | var chosen_unit_dependers: u32 = undefined; |
| 3242 | 3246 | |
| 3247 | // MLUGG TODO: i'm 99% sure this is now impossible. check!!! | |
| 3243 | 3248 | inline for (.{ zcu.outdated.keys(), zcu.potentially_outdated.keys() }) |outdated_units| { |
| 3244 | 3249 | for (outdated_units) |unit| { |
| 3245 | 3250 | var n: u32 = 0; |
| 3246 | 3251 | var it = ip.dependencyIterator(switch (unit.unwrap()) { |
| 3247 | 3252 | .func => continue, // a `func` definitely can't be causing the loop so it is a bad choice |
| 3248 | 3253 | .@"comptime" => continue, // a `comptime` block can't even be depended on so it is a terrible choice |
| 3249 | .type => |ty| .{ .interned = ty }, | |
| 3254 | .type_layout => |ty| .{ .type_layout = ty }, | |
| 3255 | .type_inits => |ty| .{ .type_inits = ty }, | |
| 3250 | 3256 | .nav_val => |nav| .{ .nav_val = nav }, |
| 3251 | 3257 | .nav_ty => |nav| .{ .nav_ty = nav }, |
| 3252 | 3258 | .memoized_state => { |
| ... | ... | @@ -3377,25 +3383,21 @@ pub fn mapOldZirToNew( |
| 3377 | 3383 | var comptime_decls: std.ArrayList(Zir.Inst.Index) = .empty; |
| 3378 | 3384 | defer comptime_decls.deinit(gpa); |
| 3379 | 3385 | |
| 3380 | { | |
| 3381 | var old_decl_it = old_zir.declIterator(match_item.old_inst); | |
| 3382 | while (old_decl_it.next()) |old_decl_inst| { | |
| 3383 | const old_decl = old_zir.getDeclaration(old_decl_inst); | |
| 3384 | switch (old_decl.kind) { | |
| 3385 | .@"comptime" => try comptime_decls.append(gpa, old_decl_inst), | |
| 3386 | .unnamed_test => try unnamed_tests.append(gpa, old_decl_inst), | |
| 3387 | .@"test" => try named_tests.put(gpa, old_zir.nullTerminatedString(old_decl.name), old_decl_inst), | |
| 3388 | .decltest => try named_decltests.put(gpa, old_zir.nullTerminatedString(old_decl.name), old_decl_inst), | |
| 3389 | .@"const", .@"var" => try named_decls.put(gpa, old_zir.nullTerminatedString(old_decl.name), old_decl_inst), | |
| 3390 | } | |
| 3386 | for (old_zir.typeDecls(match_item.old_inst)) |old_decl_inst| { | |
| 3387 | const old_decl = old_zir.getDeclaration(old_decl_inst); | |
| 3388 | switch (old_decl.kind) { | |
| 3389 | .@"comptime" => try comptime_decls.append(gpa, old_decl_inst), | |
| 3390 | .unnamed_test => try unnamed_tests.append(gpa, old_decl_inst), | |
| 3391 | .@"test" => try named_tests.put(gpa, old_zir.nullTerminatedString(old_decl.name), old_decl_inst), | |
| 3392 | .decltest => try named_decltests.put(gpa, old_zir.nullTerminatedString(old_decl.name), old_decl_inst), | |
| 3393 | .@"const", .@"var" => try named_decls.put(gpa, old_zir.nullTerminatedString(old_decl.name), old_decl_inst), | |
| 3391 | 3394 | } |
| 3392 | 3395 | } |
| 3393 | 3396 | |
| 3394 | 3397 | var unnamed_test_idx: u32 = 0; |
| 3395 | 3398 | var comptime_decl_idx: u32 = 0; |
| 3396 | 3399 | |
| 3397 | var new_decl_it = new_zir.declIterator(match_item.new_inst); | |
| 3398 | while (new_decl_it.next()) |new_decl_inst| { | |
| 3400 | for (new_zir.typeDecls(match_item.new_inst)) |new_decl_inst| { | |
| 3399 | 3401 | const new_decl = new_zir.getDeclaration(new_decl_inst); |
| 3400 | 3402 | // Attempt to match this to a declaration in the old ZIR: |
| 3401 | 3403 | // * For named declarations (`const`/`var`/`fn`), we match based on name. |
| ... | ... | @@ -3494,7 +3496,7 @@ pub fn ensureFuncBodyAnalysisQueued(zcu: *Zcu, func_index: InternPool.Index) !vo |
| 3494 | 3496 | } |
| 3495 | 3497 | |
| 3496 | 3498 | try zcu.func_body_analysis_queued.ensureUnusedCapacity(zcu.gpa, 1); |
| 3497 | try zcu.comp.queueJob(.{ .analyze_func = func_index }); | |
| 3499 | try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .func = func_index }) }); | |
| 3498 | 3500 | zcu.func_body_analysis_queued.putAssumeCapacityNoClobber(func_index, {}); |
| 3499 | 3501 | } |
| 3500 | 3502 | |
| ... | ... | @@ -3513,7 +3515,7 @@ pub fn ensureNavValAnalysisQueued(zcu: *Zcu, nav_id: InternPool.Nav.Index) !void |
| 3513 | 3515 | } |
| 3514 | 3516 | |
| 3515 | 3517 | try zcu.nav_val_analysis_queued.ensureUnusedCapacity(zcu.gpa, 1); |
| 3516 | try zcu.comp.queueJob(.{ .analyze_comptime_unit = .wrap(.{ .nav_val = nav_id }) }); | |
| 3518 | try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .nav_val = nav_id }) }); | |
| 3517 | 3519 | zcu.nav_val_analysis_queued.putAssumeCapacityNoClobber(nav_id, {}); |
| 3518 | 3520 | } |
| 3519 | 3521 | |
| ... | ... | @@ -3908,8 +3910,7 @@ pub fn atomicPtrAlignment( |
| 3908 | 3910 | return error.BadType; |
| 3909 | 3911 | } |
| 3910 | 3912 | |
| 3911 | /// Returns null in the following cases: | |
| 3912 | /// * Not a struct. | |
| 3913 | /// Returns null if `ty` is not a struct. | |
| 3913 | 3914 | pub fn typeToStruct(zcu: *const Zcu, ty: Type) ?InternPool.LoadedStructType { |
| 3914 | 3915 | if (ty.ip_index == .none) return null; |
| 3915 | 3916 | const ip = &zcu.intern_pool; |
| ... | ... | @@ -3936,7 +3937,6 @@ pub fn structPackedFieldBitOffset( |
| 3936 | 3937 | ) u16 { |
| 3937 | 3938 | const ip = &zcu.intern_pool; |
| 3938 | 3939 | assert(struct_type.layout == .@"packed"); |
| 3939 | assert(struct_type.haveLayout(ip)); | |
| 3940 | 3940 | var bit_sum: u64 = 0; |
| 3941 | 3941 | for (0..struct_type.field_types.len) |i| { |
| 3942 | 3942 | if (i == field_index) { |
| ... | ... | @@ -3995,8 +3995,10 @@ pub const UnionLayout = struct { |
| 3995 | 3995 | pub fn unionTagFieldIndex(zcu: *const Zcu, loaded_union: InternPool.LoadedUnionType, enum_tag: Value) ?u32 { |
| 3996 | 3996 | const ip = &zcu.intern_pool; |
| 3997 | 3997 | if (enum_tag.toIntern() == .none) return null; |
| 3998 | assert(ip.typeOf(enum_tag.toIntern()) == loaded_union.enum_tag_ty); | |
| 3999 | return loaded_union.loadTagType(ip).tagValueIndex(ip, enum_tag.toIntern()); | |
| 3998 | const enum_tag_key = ip.indexToKey(enum_tag.toIntern()).enum_tag; | |
| 3999 | assert(enum_tag_key.ty == loaded_union.enum_tag_type); | |
| 4000 | const loaded_enum = ip.loadEnumType(loaded_union.enum_tag_type); | |
| 4001 | return loaded_enum.tagValueIndex(ip, enum_tag_key.int); | |
| 4000 | 4002 | } |
| 4001 | 4003 | |
| 4002 | 4004 | pub const ResolvedReference = struct { |
| ... | ... | @@ -4049,31 +4051,36 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R |
| 4049 | 4051 | const referencer = types.values()[type_idx]; |
| 4050 | 4052 | type_idx += 1; |
| 4051 | 4053 | |
| 4052 | log.debug("handle type '{f}'", .{Type.fromInterned(ty).containerTypeName(ip).fmt(ip)}); | |
| 4054 | refs_log.debug("handle type '{f}'", .{Type.fromInterned(ty).containerTypeName(ip).fmt(ip)}); | |
| 4053 | 4055 | |
| 4054 | // If this type undergoes type resolution, the corresponding `AnalUnit` is automatically referenced. | |
| 4055 | const has_resolution: bool = switch (ip.indexToKey(ty)) { | |
| 4056 | .struct_type, .union_type => true, | |
| 4057 | .enum_type => |k| k != .generated_tag, | |
| 4058 | .opaque_type => false, | |
| 4056 | // If this type undergoes type resolution, the corresponding `AnalUnit`s are automatically referenced. | |
| 4057 | const has_layout: bool, const has_inits: bool = switch (ip.indexToKey(ty)) { | |
| 4058 | .struct_type => .{ true, true }, | |
| 4059 | .union_type => .{ true, false }, | |
| 4060 | .enum_type => .{ false, true }, | |
| 4061 | .opaque_type => .{ false, false }, | |
| 4059 | 4062 | else => unreachable, |
| 4060 | 4063 | }; |
| 4061 | if (has_resolution) { | |
| 4064 | if (has_layout) { | |
| 4065 | // this should only be referenced by the type | |
| 4066 | const unit: AnalUnit = .wrap(.{ .type_layout = ty }); | |
| 4067 | try units.putNoClobber(gpa, unit, referencer); | |
| 4068 | } | |
| 4069 | if (has_inits) { | |
| 4062 | 4070 | // this should only be referenced by the type |
| 4063 | const unit: AnalUnit = .wrap(.{ .type = ty }); | |
| 4071 | const unit: AnalUnit = .wrap(.{ .type_inits = ty }); | |
| 4064 | 4072 | try units.putNoClobber(gpa, unit, referencer); |
| 4065 | 4073 | } |
| 4066 | 4074 | |
| 4067 | 4075 | // If this is a union with a generated tag, its tag type is automatically referenced. |
| 4068 | 4076 | // We don't add this reference for non-generated tags, as those will already be referenced via the union's type resolution, with a better source location. |
| 4069 | if (zcu.typeToUnion(Type.fromInterned(ty))) |union_obj| { | |
| 4070 | const tag_ty = union_obj.enum_tag_ty; | |
| 4071 | if (tag_ty != .none) { | |
| 4072 | if (ip.indexToKey(tag_ty).enum_type == .generated_tag) { | |
| 4073 | const gop = try types.getOrPut(gpa, tag_ty); | |
| 4074 | if (!gop.found_existing) gop.value_ptr.* = referencer; | |
| 4075 | } | |
| 4076 | } | |
| 4077 | implicit_tag: { | |
| 4078 | const loaded_union = zcu.typeToUnion(.fromInterned(ty)) orelse break :implicit_tag; | |
| 4079 | const tag_ty = loaded_union.enum_tag_type; | |
| 4080 | if (ip.indexToKey(tag_ty).enum_type != .generated_union_tag) break :implicit_tag; | |
| 4081 | const gop = try types.getOrPut(gpa, tag_ty); | |
| 4082 | if (gop.found_existing) break :implicit_tag; | |
| 4083 | gop.value_ptr.* = referencer; | |
| 4077 | 4084 | } |
| 4078 | 4085 | |
| 4079 | 4086 | // Queue any decls within this type which would be automatically analyzed. |
| ... | ... | @@ -4084,7 +4091,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R |
| 4084 | 4091 | const unit: AnalUnit = .wrap(.{ .@"comptime" = cu }); |
| 4085 | 4092 | const gop = try units.getOrPut(gpa, unit); |
| 4086 | 4093 | if (!gop.found_existing) { |
| 4087 | log.debug("type '{f}': ref comptime %{}", .{ | |
| 4094 | refs_log.debug("type '{f}': ref comptime %{}", .{ | |
| 4088 | 4095 | Type.fromInterned(ty).containerTypeName(ip).fmt(ip), |
| 4089 | 4096 | @intFromEnum(ip.getComptimeUnit(cu).zir_index.resolve(ip) orelse continue), |
| 4090 | 4097 | }); |
| ... | ... | @@ -4118,7 +4125,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R |
| 4118 | 4125 | { |
| 4119 | 4126 | const gop = try units.getOrPut(gpa, .wrap(.{ .nav_val = nav_id })); |
| 4120 | 4127 | if (!gop.found_existing) { |
| 4121 | log.debug("type '{f}': ref test %{}", .{ | |
| 4128 | refs_log.debug("type '{f}': ref test %{}", .{ | |
| 4122 | 4129 | Type.fromInterned(ty).containerTypeName(ip).fmt(ip), |
| 4123 | 4130 | @intFromEnum(inst_info.inst), |
| 4124 | 4131 | }); |
| ... | ... | @@ -4141,7 +4148,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R |
| 4141 | 4148 | const unit: AnalUnit = .wrap(.{ .nav_val = nav }); |
| 4142 | 4149 | const gop = try units.getOrPut(gpa, unit); |
| 4143 | 4150 | if (!gop.found_existing) { |
| 4144 | log.debug("type '{f}': ref named %{}", .{ | |
| 4151 | refs_log.debug("type '{f}': ref named %{}", .{ | |
| 4145 | 4152 | Type.fromInterned(ty).containerTypeName(ip).fmt(ip), |
| 4146 | 4153 | @intFromEnum(inst_info.inst), |
| 4147 | 4154 | }); |
| ... | ... | @@ -4158,7 +4165,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R |
| 4158 | 4165 | const unit: AnalUnit = .wrap(.{ .nav_val = nav }); |
| 4159 | 4166 | const gop = try units.getOrPut(gpa, unit); |
| 4160 | 4167 | if (!gop.found_existing) { |
| 4161 | log.debug("type '{f}': ref named %{}", .{ | |
| 4168 | refs_log.debug("type '{f}': ref named %{}", .{ | |
| 4162 | 4169 | Type.fromInterned(ty).containerTypeName(ip).fmt(ip), |
| 4163 | 4170 | @intFromEnum(inst_info.inst), |
| 4164 | 4171 | }); |
| ... | ... | @@ -4177,14 +4184,14 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R |
| 4177 | 4184 | const other: AnalUnit = .wrap(switch (unit.unwrap()) { |
| 4178 | 4185 | .nav_val => |n| .{ .nav_ty = n }, |
| 4179 | 4186 | .nav_ty => |n| .{ .nav_val = n }, |
| 4180 | .@"comptime", .type, .func, .memoized_state => break :queue_paired, | |
| 4187 | .@"comptime", .type_layout, .type_inits, .func, .memoized_state => break :queue_paired, | |
| 4181 | 4188 | }); |
| 4182 | 4189 | const gop = try units.getOrPut(gpa, other); |
| 4183 | 4190 | if (gop.found_existing) break :queue_paired; |
| 4184 | 4191 | gop.value_ptr.* = units.values()[unit_idx]; // same reference location |
| 4185 | 4192 | } |
| 4186 | 4193 | |
| 4187 | log.debug("handle unit '{f}'", .{zcu.fmtAnalUnit(unit)}); | |
| 4194 | refs_log.debug("handle unit '{f}'", .{zcu.fmtAnalUnit(unit)}); | |
| 4188 | 4195 | |
| 4189 | 4196 | if (zcu.reference_table.get(unit)) |first_ref_idx| { |
| 4190 | 4197 | assert(first_ref_idx != std.math.maxInt(u32)); |
| ... | ... | @@ -4193,7 +4200,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R |
| 4193 | 4200 | const ref = zcu.all_references.items[ref_idx]; |
| 4194 | 4201 | const gop = try units.getOrPut(gpa, ref.referenced); |
| 4195 | 4202 | if (!gop.found_existing) { |
| 4196 | log.debug("unit '{f}': ref unit '{f}'", .{ | |
| 4203 | refs_log.debug("unit '{f}': ref unit '{f}'", .{ | |
| 4197 | 4204 | zcu.fmtAnalUnit(unit), |
| 4198 | 4205 | zcu.fmtAnalUnit(ref.referenced), |
| 4199 | 4206 | }); |
| ... | ... | @@ -4213,7 +4220,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R |
| 4213 | 4220 | const ref = zcu.all_type_references.items[ref_idx]; |
| 4214 | 4221 | const gop = try types.getOrPut(gpa, ref.referenced); |
| 4215 | 4222 | if (!gop.found_existing) { |
| 4216 | log.debug("unit '{f}': ref type '{f}'", .{ | |
| 4223 | refs_log.debug("unit '{f}': ref type '{f}'", .{ | |
| 4217 | 4224 | zcu.fmtAnalUnit(unit), |
| 4218 | 4225 | Type.fromInterned(ref.referenced).containerTypeName(ip).fmt(ip), |
| 4219 | 4226 | }); |
| ... | ... | @@ -4323,9 +4330,8 @@ fn formatAnalUnit(data: FormatAnalUnit, writer: *Io.Writer) Io.Writer.Error!void |
| 4323 | 4330 | return writer.print("comptime(inst=<lost> [{}])", .{@intFromEnum(cu_id)}); |
| 4324 | 4331 | } |
| 4325 | 4332 | }, |
| 4326 | .nav_val => |nav| return writer.print("nav_val('{f}' [{}])", .{ ip.getNav(nav).fqn.fmt(ip), @intFromEnum(nav) }), | |
| 4327 | .nav_ty => |nav| return writer.print("nav_ty('{f}' [{}])", .{ ip.getNav(nav).fqn.fmt(ip), @intFromEnum(nav) }), | |
| 4328 | .type => |ty| return writer.print("ty('{f}' [{}])", .{ Type.fromInterned(ty).containerTypeName(ip).fmt(ip), @intFromEnum(ty) }), | |
| 4333 | .nav_val, .nav_ty => |nav, tag| return writer.print("{t}('{f}' [{}])", .{ tag, ip.getNav(nav).fqn.fmt(ip), @intFromEnum(nav) }), | |
| 4334 | .type_layout, .type_inits => |ty, tag| return writer.print("{t}('{f}' [{}])", .{ tag, Type.fromInterned(ty).containerTypeName(ip).fmt(ip), @intFromEnum(ty) }), | |
| 4329 | 4335 | .func => |func| { |
| 4330 | 4336 | const nav = zcu.funcInfo(func).owner_nav; |
| 4331 | 4337 | return writer.print("func('{f}' [{}])", .{ ip.getNav(nav).fqn.fmt(ip), @intFromEnum(func) }); |
| ... | ... | @@ -4347,18 +4353,17 @@ fn formatDependee(data: FormatDependee, writer: *Io.Writer) Io.Writer.Error!void |
| 4347 | 4353 | const file_path = zcu.fileByIndex(info.file).path; |
| 4348 | 4354 | return writer.print("inst('{f}', %{d})", .{ file_path.fmt(zcu.comp), @intFromEnum(info.inst) }); |
| 4349 | 4355 | }, |
| 4350 | .nav_val => |nav| { | |
| 4356 | .nav_val, .nav_ty => |nav, tag| { | |
| 4351 | 4357 | const fqn = ip.getNav(nav).fqn; |
| 4352 | return writer.print("nav_val('{f}')", .{fqn.fmt(ip)}); | |
| 4358 | return writer.print("{t}('{f}')", .{ tag, fqn.fmt(ip) }); | |
| 4353 | 4359 | }, |
| 4354 | .nav_ty => |nav| { | |
| 4355 | const fqn = ip.getNav(nav).fqn; | |
| 4356 | return writer.print("nav_ty('{f}')", .{fqn.fmt(ip)}); | |
| 4360 | .type_layout, .type_inits => |ip_index, tag| { | |
| 4361 | const name = Type.fromInterned(ip_index).containerTypeName(ip); | |
| 4362 | return writer.print("{t}('{f}')", .{ tag, name.fmt(ip) }); | |
| 4357 | 4363 | }, |
| 4358 | .interned => |ip_index| switch (ip.indexToKey(ip_index)) { | |
| 4359 | .struct_type, .union_type, .enum_type => return writer.print("type('{f}')", .{Type.fromInterned(ip_index).containerTypeName(ip).fmt(ip)}), | |
| 4360 | .func => |f| return writer.print("ies('{f}')", .{ip.getNav(f.owner_nav).fqn.fmt(ip)}), | |
| 4361 | else => unreachable, | |
| 4364 | .func_ies => |ip_index| { | |
| 4365 | const fqn = ip.getNav(ip.indexToKey(ip_index).func.owner_nav).fqn; | |
| 4366 | return writer.print("func_ies('{f}')", .{fqn.fmt(ip)}); | |
| 4362 | 4367 | }, |
| 4363 | 4368 | .zon_file => |file| { |
| 4364 | 4369 | const file_path = zcu.fileByIndex(file).path; |
src/Zcu/PerThread.zig+807-697| ... | ... | @@ -598,44 +598,38 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void { |
| 598 | 598 | // Value is whether the declaration is `pub`. |
| 599 | 599 | var old_names: std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, bool) = .empty; |
| 600 | 600 | defer old_names.deinit(zcu.gpa); |
| 601 | { | |
| 602 | var it = old_zir.declIterator(old_inst); | |
| 603 | while (it.next()) |decl_inst| { | |
| 604 | const old_decl = old_zir.getDeclaration(decl_inst); | |
| 605 | if (old_decl.name == .empty) continue; | |
| 606 | const name_ip = try zcu.intern_pool.getOrPutString( | |
| 607 | zcu.gpa, | |
| 608 | io, | |
| 609 | pt.tid, | |
| 610 | old_zir.nullTerminatedString(old_decl.name), | |
| 611 | .no_embedded_nulls, | |
| 612 | ); | |
| 613 | try old_names.put(zcu.gpa, name_ip, old_decl.is_pub); | |
| 614 | } | |
| 601 | for (old_zir.typeDecls(old_inst)) |decl_inst| { | |
| 602 | const old_decl = old_zir.getDeclaration(decl_inst); | |
| 603 | if (old_decl.name == .empty) continue; | |
| 604 | const name_ip = try zcu.intern_pool.getOrPutString( | |
| 605 | zcu.gpa, | |
| 606 | io, | |
| 607 | pt.tid, | |
| 608 | old_zir.nullTerminatedString(old_decl.name), | |
| 609 | .no_embedded_nulls, | |
| 610 | ); | |
| 611 | try old_names.put(zcu.gpa, name_ip, old_decl.is_pub); | |
| 615 | 612 | } |
| 616 | 613 | var any_change = false; |
| 617 | { | |
| 618 | var it = new_zir.declIterator(new_inst); | |
| 619 | while (it.next()) |decl_inst| { | |
| 620 | const new_decl = new_zir.getDeclaration(decl_inst); | |
| 621 | if (new_decl.name == .empty) continue; | |
| 622 | const name_ip = try zcu.intern_pool.getOrPutString( | |
| 623 | zcu.gpa, | |
| 624 | io, | |
| 625 | pt.tid, | |
| 626 | new_zir.nullTerminatedString(new_decl.name), | |
| 627 | .no_embedded_nulls, | |
| 628 | ); | |
| 629 | if (old_names.fetchSwapRemove(name_ip)) |kv| { | |
| 630 | if (kv.value == new_decl.is_pub) continue; | |
| 631 | } | |
| 632 | // Name added, or changed whether it's pub | |
| 633 | any_change = true; | |
| 634 | try zcu.markDependeeOutdated(.not_marked_po, .{ .namespace_name = .{ | |
| 635 | .namespace = tracked_inst_index, | |
| 636 | .name = name_ip, | |
| 637 | } }); | |
| 614 | for (new_zir.typeDecls(new_inst)) |decl_inst| { | |
| 615 | const new_decl = new_zir.getDeclaration(decl_inst); | |
| 616 | if (new_decl.name == .empty) continue; | |
| 617 | const name_ip = try zcu.intern_pool.getOrPutString( | |
| 618 | zcu.gpa, | |
| 619 | io, | |
| 620 | pt.tid, | |
| 621 | new_zir.nullTerminatedString(new_decl.name), | |
| 622 | .no_embedded_nulls, | |
| 623 | ); | |
| 624 | if (old_names.fetchSwapRemove(name_ip)) |kv| { | |
| 625 | if (kv.value == new_decl.is_pub) continue; | |
| 638 | 626 | } |
| 627 | // Name added, or changed whether it's pub | |
| 628 | any_change = true; | |
| 629 | try zcu.markDependeeOutdated(.not_marked_po, .{ .namespace_name = .{ | |
| 630 | .namespace = tracked_inst_index, | |
| 631 | .name = name_ip, | |
| 632 | } }); | |
| 639 | 633 | } |
| 640 | 634 | // The only elements remaining in `old_names` now are any names which were removed. |
| 641 | 635 | for (old_names.keys()) |name_ip| { |
| ... | ... | @@ -674,24 +668,49 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void { |
| 674 | 668 | } |
| 675 | 669 | } |
| 676 | 670 | |
| 677 | /// Ensures that `zcu.fileRootType` on this `file_index` gives an up-to-date answer. | |
| 678 | /// Returns `error.AnalysisFail` if the file has an error. | |
| 679 | pub fn ensureFileAnalyzed(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void { | |
| 680 | const file_root_type = pt.zcu.fileRootType(file_index); | |
| 681 | if (file_root_type != .none) { | |
| 682 | if (pt.ensureTypeUpToDate(file_root_type)) |_| { | |
| 683 | return; | |
| 684 | } else |err| switch (err) { | |
| 685 | error.AnalysisFail => { | |
| 686 | // The file's root `struct_decl` has, at some point, been lost, because the file failed AstGen. | |
| 687 | // Clear `file_root_type`, and try the `semaFile` call below, in case the instruction has since | |
| 688 | // been discovered under a new `TrackedInst.Index`. | |
| 689 | pt.zcu.setFileRootType(file_index, .none); | |
| 690 | }, | |
| 691 | else => |e| return e, | |
| 692 | } | |
| 693 | } | |
| 694 | return pt.semaFile(file_index); | |
| 671 | /// Ensures that `zcu.fileRootType` on this `file_index` is populated (not `.none`). This implies | |
| 672 | /// that the file's namespace is scanned, discovering declarations. | |
| 673 | /// | |
| 674 | /// Typical Zig compilations begin by claling this function on the root source file of the standard | |
| 675 | /// library, `lib/std/std.zig`. The resulting namespace scan discovers a `comptime` declaration in | |
| 676 | /// that file, which is queued for analysis, and everything goes from there. | |
| 677 | pub fn ensureFileAnalyzed(pt: Zcu.PerThread, file_index: Zcu.File.Index) (Allocator.Error || Io.Cancelable)!void { | |
| 678 | dev.check(.sema); | |
| 679 | ||
| 680 | const tracy = trace(@src()); | |
| 681 | defer tracy.end(); | |
| 682 | ||
| 683 | const zcu = pt.zcu; | |
| 684 | const comp = zcu.comp; | |
| 685 | const io = comp.io; | |
| 686 | const gpa = comp.gpa; | |
| 687 | const ip = &zcu.intern_pool; | |
| 688 | ||
| 689 | if (zcu.fileRootType(file_index) != .none) return; // already good | |
| 690 | ||
| 691 | const file = zcu.fileByIndex(file_index); | |
| 692 | assert(file.getMode() == .zig); | |
| 693 | const struct_decl = file.zir.?.getStructDecl(.main_struct_inst); | |
| 694 | const tracked_inst = try ip.trackZir(gpa, io, pt.tid, .{ | |
| 695 | .file = file_index, | |
| 696 | .inst = .main_struct_inst, | |
| 697 | }); | |
| 698 | const file_root_type = try Sema.analyzeStructDecl( | |
| 699 | pt, | |
| 700 | file_index, | |
| 701 | &file.zir.?, | |
| 702 | .none, | |
| 703 | tracked_inst, | |
| 704 | &struct_decl, | |
| 705 | null, | |
| 706 | &.{}, | |
| 707 | .{ .exact = .{ | |
| 708 | .name = try file.internFullyQualifiedName(pt), | |
| 709 | .nav = .none, | |
| 710 | } }, | |
| 711 | ); | |
| 712 | zcu.setFileRootType(file_index, file_root_type.toIntern()); | |
| 713 | if (zcu.comp.time_report) |*tr| tr.stats.n_imported_files += 1; | |
| 695 | 714 | } |
| 696 | 715 | |
| 697 | 716 | /// Ensures that all memoized state on `Zcu` is up-to-date, performing re-analysis if necessary. |
| ... | ... | @@ -1012,6 +1031,238 @@ fn analyzeComptimeUnit(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu |
| 1012 | 1031 | try sema.flushExports(); |
| 1013 | 1032 | } |
| 1014 | 1033 | |
| 1034 | /// Ensures that the layout of the given `struct` or `union` type is fully up-to-date, performing | |
| 1035 | /// re-analysis if necessary. Asserts that `ty` is a struct (not a tuple!) or union. Returns | |
| 1036 | /// `error.AnalysisFail` if an analysis error is encountered during type resolution; the caller is | |
| 1037 | /// free to ignore this, since the error is already registered. | |
| 1038 | pub fn ensureTypeLayoutUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void { | |
| 1039 | const tracy = trace(@src()); | |
| 1040 | defer tracy.end(); | |
| 1041 | ||
| 1042 | const zcu = pt.zcu; | |
| 1043 | const gpa = zcu.gpa; | |
| 1044 | ||
| 1045 | const anal_unit: AnalUnit = .wrap(.{ .type_layout = ty.toIntern() }); | |
| 1046 | ||
| 1047 | log.debug("ensureTypeLayoutUpToDate {f}", .{zcu.fmtAnalUnit(anal_unit)}); | |
| 1048 | ||
| 1049 | assert(!zcu.analysis_in_progress.contains(anal_unit)); | |
| 1050 | ||
| 1051 | // Determine whether or not this type is outdated. For this kind of `AnalUnit`, that's | |
| 1052 | // the only indicator as to whether or not analysis is required; when a struct/union is | |
| 1053 | // first created, it's marked as outdated. | |
| 1054 | // MLUGG TODO: make that actually true, it's a good strategy here! | |
| 1055 | ||
| 1056 | const was_outdated = zcu.outdated.swapRemove(anal_unit) or | |
| 1057 | zcu.potentially_outdated.swapRemove(anal_unit); | |
| 1058 | ||
| 1059 | if (was_outdated) { | |
| 1060 | _ = zcu.outdated_ready.swapRemove(anal_unit); | |
| 1061 | // `was_outdated` can be true in the initial update for comptime units, so this isn't a `dev.check`. | |
| 1062 | if (dev.env.supports(.incremental)) { | |
| 1063 | zcu.deleteUnitExports(anal_unit); | |
| 1064 | zcu.deleteUnitReferences(anal_unit); | |
| 1065 | zcu.deleteUnitCompileLogs(anal_unit); | |
| 1066 | if (zcu.failed_analysis.fetchSwapRemove(anal_unit)) |kv| { | |
| 1067 | kv.value.destroy(gpa); | |
| 1068 | } | |
| 1069 | _ = zcu.transitive_failed_analysis.swapRemove(anal_unit); | |
| 1070 | zcu.intern_pool.removeDependenciesForDepender(gpa, anal_unit); | |
| 1071 | } | |
| 1072 | // For types, we already know that we have to invalidate all dependees. | |
| 1073 | // TODO: we actually *could* detect whether everything was the same. should we bother? | |
| 1074 | try zcu.markDependeeOutdated(.marked_po, .{ .type_layout = ty.toIntern() }); | |
| 1075 | } else { | |
| 1076 | // We can trust the current information about this unit. | |
| 1077 | if (zcu.failed_analysis.contains(anal_unit)) return error.AnalysisFail; | |
| 1078 | if (zcu.transitive_failed_analysis.contains(anal_unit)) return error.AnalysisFail; | |
| 1079 | return; | |
| 1080 | } | |
| 1081 | ||
| 1082 | if (zcu.comp.debugIncremental()) { | |
| 1083 | const info = try zcu.incremental_debug_state.getUnitInfo(gpa, anal_unit); | |
| 1084 | info.last_update_gen = zcu.generation; | |
| 1085 | info.deps.clearRetainingCapacity(); | |
| 1086 | } | |
| 1087 | ||
| 1088 | const unit_tracking = zcu.trackUnitSema(ty.containerTypeName(&zcu.intern_pool).toSlice(&zcu.intern_pool), null); | |
| 1089 | defer unit_tracking.end(zcu); | |
| 1090 | ||
| 1091 | try zcu.analysis_in_progress.put(gpa, anal_unit, {}); | |
| 1092 | defer assert(zcu.analysis_in_progress.swapRemove(anal_unit)); | |
| 1093 | ||
| 1094 | var analysis_arena: std.heap.ArenaAllocator = .init(gpa); | |
| 1095 | defer analysis_arena.deinit(); | |
| 1096 | ||
| 1097 | var comptime_err_ret_trace: std.array_list.Managed(Zcu.LazySrcLoc) = .init(gpa); | |
| 1098 | defer comptime_err_ret_trace.deinit(); | |
| 1099 | ||
| 1100 | const file = zcu.namespacePtr(ty.getNamespaceIndex(zcu)).fileScope(zcu); | |
| 1101 | ||
| 1102 | var sema: Sema = .{ | |
| 1103 | .pt = pt, | |
| 1104 | .gpa = gpa, | |
| 1105 | .arena = analysis_arena.allocator(), | |
| 1106 | .code = file.zir.?, | |
| 1107 | .owner = anal_unit, | |
| 1108 | .func_index = .none, | |
| 1109 | .func_is_naked = false, | |
| 1110 | .fn_ret_ty = .void, | |
| 1111 | .fn_ret_ty_ies = null, | |
| 1112 | .comptime_err_ret_trace = &comptime_err_ret_trace, | |
| 1113 | }; | |
| 1114 | defer sema.deinit(); | |
| 1115 | ||
| 1116 | const result = switch (ty.containerLayout(zcu)) { | |
| 1117 | .auto, .@"extern" => switch (ty.zigTypeTag(zcu)) { | |
| 1118 | .@"struct" => Sema.type_resolution.resolveStructLayout(&sema, ty), | |
| 1119 | .@"union" => Sema.type_resolution.resolveUnionLayout(&sema, ty), | |
| 1120 | else => unreachable, | |
| 1121 | }, | |
| 1122 | .@"packed" => switch (ty.zigTypeTag(zcu)) { | |
| 1123 | .@"struct" => Sema.type_resolution.resolvePackedStructLayout(&sema, ty), | |
| 1124 | .@"union" => Sema.type_resolution.resolvePackedUnionLayout(&sema, ty), | |
| 1125 | else => unreachable, | |
| 1126 | }, | |
| 1127 | }; | |
| 1128 | result catch |err| switch (err) { | |
| 1129 | error.AnalysisFail => { | |
| 1130 | if (!zcu.failed_analysis.contains(anal_unit)) { | |
| 1131 | // If this unit caused the error, it would have an entry in `failed_analysis`. | |
| 1132 | // Since it does not, this must be a transitive failure. | |
| 1133 | try zcu.transitive_failed_analysis.put(gpa, anal_unit, {}); | |
| 1134 | log.debug("mark transitive analysis failure for {f}", .{zcu.fmtAnalUnit(anal_unit)}); | |
| 1135 | } | |
| 1136 | return error.AnalysisFail; | |
| 1137 | }, | |
| 1138 | error.OutOfMemory, | |
| 1139 | error.Canceled, | |
| 1140 | => |e| return e, | |
| 1141 | error.ComptimeReturn => unreachable, | |
| 1142 | error.ComptimeBreak => unreachable, | |
| 1143 | }; | |
| 1144 | ||
| 1145 | sema.flushExports() catch |err| switch (err) { | |
| 1146 | error.OutOfMemory => |e| return e, | |
| 1147 | }; | |
| 1148 | ||
| 1149 | codegen_type: { | |
| 1150 | if (zcu.comp.config.use_llvm) break :codegen_type; | |
| 1151 | if (file.mod.?.strip) break :codegen_type; | |
| 1152 | zcu.comp.link_prog_node.increaseEstimatedTotalItems(1); | |
| 1153 | try zcu.comp.queueJob(.{ .link_type = ty.toIntern() }); | |
| 1154 | } | |
| 1155 | } | |
| 1156 | ||
| 1157 | /// Ensures that the default/tag values of the given `struct` or `enum` type are fully up-to-date, | |
| 1158 | /// performing re-analysis if necessary. Asserts that `ty` is a struct (not a tuple!) or an enum. | |
| 1159 | /// Returns `error.AnalysisFail` if an analysis error is encountered during resolution; the caller | |
| 1160 | /// is free to ignore this, since the error is already registered. | |
| 1161 | pub fn ensureTypeInitsUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void { | |
| 1162 | const tracy = trace(@src()); | |
| 1163 | defer tracy.end(); | |
| 1164 | ||
| 1165 | const zcu = pt.zcu; | |
| 1166 | const gpa = zcu.gpa; | |
| 1167 | ||
| 1168 | const anal_unit: AnalUnit = .wrap(.{ .type_inits = ty.toIntern() }); | |
| 1169 | ||
| 1170 | log.debug("ensureTypeInitsUpToDate {f}", .{zcu.fmtAnalUnit(anal_unit)}); | |
| 1171 | ||
| 1172 | assert(!zcu.analysis_in_progress.contains(anal_unit)); | |
| 1173 | ||
| 1174 | // Determine whether or not this type is outdated. For this kind of `AnalUnit`, that's | |
| 1175 | // the only indicator as to whether or not analysis is required; when a struct/enum is | |
| 1176 | // first created, it's marked as outdated. | |
| 1177 | // MLUGG TODO: make that actually true, it's a good strategy here! | |
| 1178 | ||
| 1179 | const was_outdated = zcu.outdated.swapRemove(anal_unit) or | |
| 1180 | zcu.potentially_outdated.swapRemove(anal_unit); | |
| 1181 | ||
| 1182 | if (was_outdated) { | |
| 1183 | _ = zcu.outdated_ready.swapRemove(anal_unit); | |
| 1184 | // `was_outdated` can be true in the initial update for comptime units, so this isn't a `dev.check`. | |
| 1185 | if (dev.env.supports(.incremental)) { | |
| 1186 | zcu.deleteUnitExports(anal_unit); | |
| 1187 | zcu.deleteUnitReferences(anal_unit); | |
| 1188 | zcu.deleteUnitCompileLogs(anal_unit); | |
| 1189 | if (zcu.failed_analysis.fetchSwapRemove(anal_unit)) |kv| { | |
| 1190 | kv.value.destroy(gpa); | |
| 1191 | } | |
| 1192 | _ = zcu.transitive_failed_analysis.swapRemove(anal_unit); | |
| 1193 | zcu.intern_pool.removeDependenciesForDepender(gpa, anal_unit); | |
| 1194 | } | |
| 1195 | // For types, we already know that we have to invalidate all dependees. | |
| 1196 | // TODO: we actually *could* detect whether everything was the same. should we bother? | |
| 1197 | try zcu.markDependeeOutdated(.marked_po, .{ .type_inits = ty.toIntern() }); | |
| 1198 | } else { | |
| 1199 | // We can trust the current information about this unit. | |
| 1200 | if (zcu.failed_analysis.contains(anal_unit)) return error.AnalysisFail; | |
| 1201 | if (zcu.transitive_failed_analysis.contains(anal_unit)) return error.AnalysisFail; | |
| 1202 | return; | |
| 1203 | } | |
| 1204 | ||
| 1205 | if (zcu.comp.debugIncremental()) { | |
| 1206 | const info = try zcu.incremental_debug_state.getUnitInfo(gpa, anal_unit); | |
| 1207 | info.last_update_gen = zcu.generation; | |
| 1208 | info.deps.clearRetainingCapacity(); | |
| 1209 | } | |
| 1210 | ||
| 1211 | const unit_tracking = zcu.trackUnitSema(ty.containerTypeName(&zcu.intern_pool).toSlice(&zcu.intern_pool), null); | |
| 1212 | defer unit_tracking.end(zcu); | |
| 1213 | ||
| 1214 | try zcu.analysis_in_progress.put(gpa, anal_unit, {}); | |
| 1215 | defer assert(zcu.analysis_in_progress.swapRemove(anal_unit)); | |
| 1216 | ||
| 1217 | var analysis_arena: std.heap.ArenaAllocator = .init(gpa); | |
| 1218 | defer analysis_arena.deinit(); | |
| 1219 | ||
| 1220 | var comptime_err_ret_trace: std.array_list.Managed(Zcu.LazySrcLoc) = .init(gpa); | |
| 1221 | defer comptime_err_ret_trace.deinit(); | |
| 1222 | ||
| 1223 | const zir = zcu.namespacePtr(ty.getNamespaceIndex(zcu)).fileScope(zcu).zir.?; | |
| 1224 | ||
| 1225 | var sema: Sema = .{ | |
| 1226 | .pt = pt, | |
| 1227 | .gpa = gpa, | |
| 1228 | .arena = analysis_arena.allocator(), | |
| 1229 | .code = zir, | |
| 1230 | .owner = anal_unit, | |
| 1231 | .func_index = .none, | |
| 1232 | .func_is_naked = false, | |
| 1233 | .fn_ret_ty = .void, | |
| 1234 | .fn_ret_ty_ies = null, | |
| 1235 | .comptime_err_ret_trace = &comptime_err_ret_trace, | |
| 1236 | }; | |
| 1237 | defer sema.deinit(); | |
| 1238 | ||
| 1239 | const result = switch (ty.zigTypeTag(zcu)) { | |
| 1240 | .@"struct" => Sema.type_resolution.resolveStructDefaults(&sema, ty), | |
| 1241 | .@"enum" => Sema.type_resolution.resolveEnumValues(&sema, ty), | |
| 1242 | else => unreachable, | |
| 1243 | }; | |
| 1244 | result catch |err| switch (err) { | |
| 1245 | error.AnalysisFail => { | |
| 1246 | if (!zcu.failed_analysis.contains(anal_unit)) { | |
| 1247 | // If this unit caused the error, it would have an entry in `failed_analysis`. | |
| 1248 | // Since it does not, this must be a transitive failure. | |
| 1249 | try zcu.transitive_failed_analysis.put(gpa, anal_unit, {}); | |
| 1250 | log.debug("mark transitive analysis failure for {f}", .{zcu.fmtAnalUnit(anal_unit)}); | |
| 1251 | } | |
| 1252 | return error.AnalysisFail; | |
| 1253 | }, | |
| 1254 | error.OutOfMemory, | |
| 1255 | error.Canceled, | |
| 1256 | => |e| return e, | |
| 1257 | error.ComptimeReturn => unreachable, | |
| 1258 | error.ComptimeBreak => unreachable, | |
| 1259 | }; | |
| 1260 | ||
| 1261 | sema.flushExports() catch |err| switch (err) { | |
| 1262 | error.OutOfMemory => |e| return e, | |
| 1263 | }; | |
| 1264 | } | |
| 1265 | ||
| 1015 | 1266 | /// Ensures that the resolved value of the given `Nav` is fully up-to-date, performing re-analysis |
| 1016 | 1267 | /// if necessary. Returns `error.AnalysisFail` if an analysis error is encountered; the caller is |
| 1017 | 1268 | /// free to ignore this, since the error is already registered. |
| ... | ... | @@ -1360,7 +1611,7 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr |
| 1360 | 1611 | |
| 1361 | 1612 | // This resolves the type of the resolved value, not that value itself. If `nav_val` is a struct type, |
| 1362 | 1613 | // this resolves the type `type` (which needs no resolution), not the struct itself. |
| 1363 | try nav_ty.resolveLayout(pt); | |
| 1614 | try sema.ensureLayoutResolved(nav_ty); | |
| 1364 | 1615 | |
| 1365 | 1616 | const queue_linker_work, const is_owned_fn = switch (ip.indexToKey(nav_val.toIntern())) { |
| 1366 | 1617 | .func => |f| .{ true, f.owner_nav == nav_id }, // note that this lets function aliases reach codegen |
| ... | ... | @@ -1377,7 +1628,7 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr |
| 1377 | 1628 | if (zir_decl.align_body != null and !target_util.supportsFunctionAlignment(zcu.getTarget())) { |
| 1378 | 1629 | return sema.fail(&block, align_src, "target does not support function alignment", .{}); |
| 1379 | 1630 | } |
| 1380 | } else if (try nav_ty.comptimeOnlySema(pt)) { | |
| 1631 | } else if (nav_ty.comptimeOnly(zcu)) { | |
| 1381 | 1632 | // alignment, linksection, addrspace annotations are not allowed for comptime-only types. |
| 1382 | 1633 | const reason: []const u8 = switch (ip.indexToKey(nav_val.toIntern())) { |
| 1383 | 1634 | .func => "function alias", // slightly clearer message, since you *can* specify these on function *declarations* |
| ... | ... | @@ -1420,12 +1671,11 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr |
| 1420 | 1671 | queue_codegen: { |
| 1421 | 1672 | if (!queue_linker_work) break :queue_codegen; |
| 1422 | 1673 | |
| 1423 | if (!try nav_ty.hasRuntimeBitsSema(pt)) { | |
| 1674 | if (!nav_ty.hasRuntimeBits(zcu)) { | |
| 1424 | 1675 | if (zcu.comp.config.use_llvm) break :queue_codegen; |
| 1425 | 1676 | if (file.mod.?.strip) break :queue_codegen; |
| 1426 | 1677 | } |
| 1427 | 1678 | |
| 1428 | // This job depends on any resolve_type_fully jobs queued up before it. | |
| 1429 | 1679 | zcu.comp.link_prog_node.increaseEstimatedTotalItems(1); |
| 1430 | 1680 | try zcu.comp.queueJob(.{ .link_nav = nav_id }); |
| 1431 | 1681 | } |
| ... | ... | @@ -1628,7 +1878,7 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr |
| 1628 | 1878 | break :ty .fromInterned(type_ref.toInterned().?); |
| 1629 | 1879 | }; |
| 1630 | 1880 | |
| 1631 | try resolved_ty.resolveLayout(pt); | |
| 1881 | try sema.ensureLayoutResolved(resolved_ty); | |
| 1632 | 1882 | |
| 1633 | 1883 | // In the case where the type is specified, this function is also responsible for resolving |
| 1634 | 1884 | // the pointer modifiers, i.e. alignment, linksection, addrspace. |
| ... | ... | @@ -1765,9 +2015,9 @@ pub fn ensureFuncBodyUpToDate(pt: Zcu.PerThread, func_index: InternPool.Index) Z |
| 1765 | 2015 | |
| 1766 | 2016 | if (was_outdated) { |
| 1767 | 2017 | if (ies_outdated) { |
| 1768 | try zcu.markDependeeOutdated(.marked_po, .{ .interned = func_index }); | |
| 2018 | try zcu.markDependeeOutdated(.marked_po, .{ .func_ies = func_index }); | |
| 1769 | 2019 | } else { |
| 1770 | try zcu.markPoDependeeUpToDate(.{ .interned = func_index }); | |
| 2020 | try zcu.markPoDependeeUpToDate(.{ .func_ies = func_index }); | |
| 1771 | 2021 | } |
| 1772 | 2022 | } |
| 1773 | 2023 | |
| ... | ... | @@ -1817,7 +2067,7 @@ fn analyzeFuncBody( |
| 1817 | 2067 | |
| 1818 | 2068 | log.debug("analyze and generate fn body {f}", .{zcu.fmtAnalUnit(anal_unit)}); |
| 1819 | 2069 | |
| 1820 | var air = try pt.analyzeFnBodyInner(func_index); | |
| 2070 | var air = try pt.analyzeFuncBodyInner(func_index); | |
| 1821 | 2071 | errdefer air.deinit(gpa); |
| 1822 | 2072 | |
| 1823 | 2073 | const ies_outdated = !func.analysisUnordered(ip).inferred_error_set or |
| ... | ... | @@ -1833,7 +2083,6 @@ fn analyzeFuncBody( |
| 1833 | 2083 | return .{ .ies_outdated = ies_outdated }; |
| 1834 | 2084 | } |
| 1835 | 2085 | |
| 1836 | // This job depends on any resolve_type_fully jobs queued up before it. | |
| 1837 | 2086 | zcu.codegen_prog_node.increaseEstimatedTotalItems(1); |
| 1838 | 2087 | comp.link_prog_node.increaseEstimatedTotalItems(1); |
| 1839 | 2088 | try comp.queueJob(.{ .codegen_func = .{ |
| ... | ... | @@ -1844,94 +2093,12 @@ fn analyzeFuncBody( |
| 1844 | 2093 | return .{ .ies_outdated = ies_outdated }; |
| 1845 | 2094 | } |
| 1846 | 2095 | |
| 1847 | pub fn semaMod(pt: Zcu.PerThread, mod: *Module) !void { | |
| 1848 | dev.check(.sema); | |
| 1849 | const file_index = pt.zcu.module_roots.get(mod).?.unwrap().?; | |
| 1850 | const root_type = pt.zcu.fileRootType(file_index); | |
| 1851 | if (root_type == .none) { | |
| 1852 | return pt.semaFile(file_index); | |
| 1853 | } | |
| 1854 | } | |
| 1855 | ||
| 1856 | fn createFileRootStruct( | |
| 1857 | pt: Zcu.PerThread, | |
| 1858 | file_index: Zcu.File.Index, | |
| 1859 | namespace_index: Zcu.Namespace.Index, | |
| 1860 | replace_existing: bool, | |
| 1861 | ) Allocator.Error!InternPool.Index { | |
| 1862 | const zcu = pt.zcu; | |
| 1863 | const gpa = zcu.gpa; | |
| 1864 | const io = zcu.comp.io; | |
| 1865 | const ip = &zcu.intern_pool; | |
| 1866 | const file = zcu.fileByIndex(file_index); | |
| 1867 | const extended = file.zir.?.instructions.items(.data)[@intFromEnum(Zir.Inst.Index.main_struct_inst)].extended; | |
| 1868 | assert(extended.opcode == .struct_decl); | |
| 1869 | const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small); | |
| 1870 | assert(!small.has_captures_len); | |
| 1871 | assert(!small.has_backing_int); | |
| 1872 | assert(small.layout == .auto); | |
| 1873 | var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).@"struct".fields.len; | |
| 1874 | const fields_len = if (small.has_fields_len) blk: { | |
| 1875 | const fields_len = file.zir.?.extra[extra_index]; | |
| 1876 | extra_index += 1; | |
| 1877 | break :blk fields_len; | |
| 1878 | } else 0; | |
| 1879 | const decls_len = if (small.has_decls_len) blk: { | |
| 1880 | const decls_len = file.zir.?.extra[extra_index]; | |
| 1881 | extra_index += 1; | |
| 1882 | break :blk decls_len; | |
| 1883 | } else 0; | |
| 1884 | const decls = file.zir.?.bodySlice(extra_index, decls_len); | |
| 1885 | extra_index += decls_len; | |
| 1886 | ||
| 1887 | const tracked_inst = try ip.trackZir(gpa, io, pt.tid, .{ | |
| 1888 | .file = file_index, | |
| 1889 | .inst = .main_struct_inst, | |
| 1890 | }); | |
| 1891 | const wip_ty = switch (try ip.getStructType(gpa, io, pt.tid, .{ | |
| 1892 | .layout = .auto, | |
| 1893 | .fields_len = fields_len, | |
| 1894 | .known_non_opv = small.known_non_opv, | |
| 1895 | .requires_comptime = if (small.known_comptime_only) .yes else .unknown, | |
| 1896 | .any_comptime_fields = small.any_comptime_fields, | |
| 1897 | .any_default_inits = small.any_default_inits, | |
| 1898 | .inits_resolved = false, | |
| 1899 | .any_aligned_fields = small.any_aligned_fields, | |
| 1900 | .key = .{ .declared = .{ | |
| 1901 | .zir_index = tracked_inst, | |
| 1902 | .captures = &.{}, | |
| 1903 | } }, | |
| 1904 | }, replace_existing)) { | |
| 1905 | .existing => unreachable, // we wouldn't be analysing the file root if this type existed | |
| 1906 | .wip => |wip| wip, | |
| 1907 | }; | |
| 1908 | errdefer wip_ty.cancel(ip, pt.tid); | |
| 1909 | ||
| 1910 | wip_ty.setName(ip, try file.internFullyQualifiedName(pt), .none); | |
| 1911 | ip.namespacePtr(namespace_index).owner_type = wip_ty.index; | |
| 1912 | ||
| 1913 | if (zcu.comp.config.incremental) { | |
| 1914 | try pt.addDependency(.wrap(.{ .type = wip_ty.index }), .{ .src_hash = tracked_inst }); | |
| 1915 | } | |
| 1916 | ||
| 1917 | try pt.scanNamespace(namespace_index, decls); | |
| 1918 | try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index }); | |
| 1919 | codegen_type: { | |
| 1920 | if (file.mod.?.strip) break :codegen_type; | |
| 1921 | // This job depends on any resolve_type_fully jobs queued up before it. | |
| 1922 | zcu.comp.link_prog_node.increaseEstimatedTotalItems(1); | |
| 1923 | try zcu.comp.queueJob(.{ .link_type = wip_ty.index }); | |
| 1924 | } | |
| 1925 | zcu.setFileRootType(file_index, wip_ty.index); | |
| 1926 | if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index); | |
| 1927 | return wip_ty.finish(ip, namespace_index); | |
| 1928 | } | |
| 1929 | ||
| 1930 | 2096 | /// Re-scan the namespace of a file's root struct type on an incremental update. |
| 1931 | 2097 | /// The file must have successfully populated ZIR. |
| 1932 | 2098 | /// If the file's root struct type is not populated (the file is unreferenced), nothing is done. |
| 1933 | 2099 | /// This is called by `updateZirRefs` for all updated files before the main work loop. |
| 1934 | 2100 | /// This function does not perform any semantic analysis. |
| 2101 | /// MLUGG TODO: mmmmm i have no idea if this makes sense... tbhwy i just want to update all *changed* namespaces at the start of an update or something lol | |
| 1935 | 2102 | fn updateFileNamespace(pt: Zcu.PerThread, file_index: Zcu.File.Index) Allocator.Error!void { |
| 1936 | 2103 | const zcu = pt.zcu; |
| 1937 | 2104 | |
| ... | ... | @@ -1945,48 +2112,11 @@ fn updateFileNamespace(pt: Zcu.PerThread, file_index: Zcu.File.Index) Allocator. |
| 1945 | 2112 | }); |
| 1946 | 2113 | |
| 1947 | 2114 | const namespace_index = Type.fromInterned(file_root_type).getNamespaceIndex(zcu); |
| 1948 | const decls = decls: { | |
| 1949 | const extended = file.zir.?.instructions.items(.data)[@intFromEnum(Zir.Inst.Index.main_struct_inst)].extended; | |
| 1950 | const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small); | |
| 1951 | ||
| 1952 | var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).@"struct".fields.len; | |
| 1953 | extra_index += @intFromBool(small.has_fields_len); | |
| 1954 | const decls_len = if (small.has_decls_len) blk: { | |
| 1955 | const decls_len = file.zir.?.extra[extra_index]; | |
| 1956 | extra_index += 1; | |
| 1957 | break :blk decls_len; | |
| 1958 | } else 0; | |
| 1959 | break :decls file.zir.?.bodySlice(extra_index, decls_len); | |
| 1960 | }; | |
| 2115 | const decls = file.zir.?.getStructDecl(.main_struct_inst).decls; | |
| 1961 | 2116 | try pt.scanNamespace(namespace_index, decls); |
| 1962 | 2117 | zcu.namespacePtr(namespace_index).generation = zcu.generation; |
| 1963 | 2118 | } |
| 1964 | 2119 | |
| 1965 | fn semaFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void { | |
| 1966 | const tracy = trace(@src()); | |
| 1967 | defer tracy.end(); | |
| 1968 | ||
| 1969 | const zcu = pt.zcu; | |
| 1970 | const file = zcu.fileByIndex(file_index); | |
| 1971 | assert(file.getMode() == .zig); | |
| 1972 | assert(zcu.fileRootType(file_index) == .none); | |
| 1973 | ||
| 1974 | assert(file.zir != null); | |
| 1975 | ||
| 1976 | const new_namespace_index = try pt.createNamespace(.{ | |
| 1977 | .parent = .none, | |
| 1978 | .owner_type = undefined, // set in `createFileRootStruct` | |
| 1979 | .file_scope = file_index, | |
| 1980 | .generation = zcu.generation, | |
| 1981 | }); | |
| 1982 | const struct_ty = try pt.createFileRootStruct(file_index, new_namespace_index, false); | |
| 1983 | errdefer zcu.intern_pool.remove(pt.tid, struct_ty); | |
| 1984 | ||
| 1985 | if (zcu.comp.time_report) |*tr| { | |
| 1986 | tr.stats.n_imported_files += 1; | |
| 1987 | } | |
| 1988 | } | |
| 1989 | ||
| 1990 | 2120 | /// Called by AstGen worker threads when an import is seen. If `new_file` is returned, the caller is |
| 1991 | 2121 | /// then responsible for queueing a new AstGen job for the new file. |
| 1992 | 2122 | /// Assumes that `comp.mutex` is NOT locked. It will be locked by this function where necessary. |
| ... | ... | @@ -2878,15 +3008,15 @@ const ScanDeclIter = struct { |
| 2878 | 3008 | |
| 2879 | 3009 | if (existing_unit == null and (want_analysis or decl.linkage == .@"export")) { |
| 2880 | 3010 | log.debug( |
| 2881 | "scanDecl queue analyze_comptime_unit file='{s}' unit={f}", | |
| 3011 | "scanDecl queue analyze_unit file='{s}' unit={f}", | |
| 2882 | 3012 | .{ namespace.fileScope(zcu).sub_file_path, zcu.fmtAnalUnit(unit) }, |
| 2883 | 3013 | ); |
| 2884 | try comp.queueJob(.{ .analyze_comptime_unit = unit }); | |
| 3014 | try comp.queueJob(.{ .analyze_unit = unit }); | |
| 2885 | 3015 | } |
| 2886 | 3016 | } |
| 2887 | 3017 | }; |
| 2888 | 3018 | |
| 2889 | fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError!Air { | |
| 3019 | fn analyzeFuncBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError!Air { | |
| 2890 | 3020 | const tracy = trace(@src()); |
| 2891 | 3021 | defer tracy.end(); |
| 2892 | 3022 | |
| ... | ... | @@ -3020,16 +3150,12 @@ fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaE |
| 3020 | 3150 | const gop = sema.inst_map.getOrPutAssumeCapacity(inst); |
| 3021 | 3151 | if (gop.found_existing) continue; // provided above by comptime arg |
| 3022 | 3152 | |
| 3023 | const param_ty = fn_ty_info.param_types.get(ip)[runtime_param_index]; | |
| 3153 | const param_ty: Type = .fromInterned(fn_ty_info.param_types.get(ip)[runtime_param_index]); | |
| 3024 | 3154 | runtime_param_index += 1; |
| 3025 | 3155 | |
| 3026 | const opt_opv = sema.typeHasOnePossibleValue(Type.fromInterned(param_ty)) catch |err| switch (err) { | |
| 3027 | error.ComptimeReturn => unreachable, | |
| 3028 | error.ComptimeBreak => unreachable, | |
| 3029 | else => |e| return e, | |
| 3030 | }; | |
| 3031 | if (opt_opv) |opv| { | |
| 3032 | gop.value_ptr.* = Air.internedToRef(opv.toIntern()); | |
| 3156 | try sema.ensureLayoutResolved(param_ty); | |
| 3157 | if (try param_ty.onePossibleValue(pt)) |opv| { | |
| 3158 | gop.value_ptr.* = .fromValue(opv); | |
| 3033 | 3159 | continue; |
| 3034 | 3160 | } |
| 3035 | 3161 | const arg_index: Air.Inst.Index = @enumFromInt(sema.air_instructions.len); |
| ... | ... | @@ -3038,12 +3164,14 @@ fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaE |
| 3038 | 3164 | sema.air_instructions.appendAssumeCapacity(.{ |
| 3039 | 3165 | .tag = .arg, |
| 3040 | 3166 | .data = .{ .arg = .{ |
| 3041 | .ty = Air.internedToRef(param_ty), | |
| 3167 | .ty = .fromIntern(param_ty.toIntern()), | |
| 3042 | 3168 | .zir_param_index = @intCast(zir_param_index), |
| 3043 | 3169 | } }, |
| 3044 | 3170 | }); |
| 3045 | 3171 | } |
| 3046 | 3172 | |
| 3173 | try sema.ensureLayoutResolved(sema.fn_ret_ty); | |
| 3174 | ||
| 3047 | 3175 | const last_arg_index = inner_block.instructions.items.len; |
| 3048 | 3176 | |
| 3049 | 3177 | // Save the error trace as our first action in the function. |
| ... | ... | @@ -3103,21 +3231,9 @@ fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaE |
| 3103 | 3231 | func.setResolvedErrorSet(ip, io, ies.resolved); |
| 3104 | 3232 | } |
| 3105 | 3233 | |
| 3234 | // MLUGG TODO: i think this can go away and the assert move to the defer? | |
| 3106 | 3235 | assert(zcu.analysis_in_progress.swapRemove(anal_unit)); |
| 3107 | 3236 | |
| 3108 | // Finally we must resolve the return type and parameter types so that backends | |
| 3109 | // have full access to type information. | |
| 3110 | // Crucially, this happens *after* we set the function state to success above, | |
| 3111 | // so that dependencies on the function body will now be satisfied rather than | |
| 3112 | // result in circular dependency errors. | |
| 3113 | // TODO: this can go away once we fix backends having to resolve `StackTrace`. | |
| 3114 | // The codegen timing guarantees that the parameter types will be populated. | |
| 3115 | sema.resolveFnTypes(fn_ty, inner_block.nodeOffset(.zero)) catch |err| switch (err) { | |
| 3116 | error.ComptimeReturn => unreachable, | |
| 3117 | error.ComptimeBreak => unreachable, | |
| 3118 | else => |e| return e, | |
| 3119 | }; | |
| 3120 | ||
| 3121 | 3237 | try sema.flushExports(); |
| 3122 | 3238 | |
| 3123 | 3239 | defer { |
| ... | ... | @@ -3605,16 +3721,6 @@ pub fn ptrType(pt: Zcu.PerThread, info: InternPool.Key.PtrType) Allocator.Error! |
| 3605 | 3721 | |
| 3606 | 3722 | if (info.flags.size == .c) canon_info.flags.is_allowzero = true; |
| 3607 | 3723 | |
| 3608 | // Canonicalize non-zero alignment. If it matches the ABI alignment of the pointee | |
| 3609 | // type, we change it to 0 here. If this causes an assertion trip because the | |
| 3610 | // pointee type needs to be resolved more, that needs to be done before calling | |
| 3611 | // this ptr() function. | |
| 3612 | if (info.flags.alignment != .none and | |
| 3613 | info.flags.alignment == Type.fromInterned(info.child).abiAlignment(pt.zcu)) | |
| 3614 | { | |
| 3615 | canon_info.flags.alignment = .none; | |
| 3616 | } | |
| 3617 | ||
| 3618 | 3724 | switch (info.flags.vector_index) { |
| 3619 | 3725 | // Canonicalize host_size. If it matches the bit size of the pointee type, |
| 3620 | 3726 | // we change it to 0 here. If this causes an assertion trip, the pointee type |
| ... | ... | @@ -3632,16 +3738,6 @@ pub fn ptrType(pt: Zcu.PerThread, info: InternPool.Key.PtrType) Allocator.Error! |
| 3632 | 3738 | return Type.fromInterned(try pt.intern(.{ .ptr_type = canon_info })); |
| 3633 | 3739 | } |
| 3634 | 3740 | |
| 3635 | /// Like `ptrType`, but if `info` specifies an `alignment`, first ensures the pointer | |
| 3636 | /// child type's alignment is resolved so that an invalid alignment is not used. | |
| 3637 | /// In general, prefer this function during semantic analysis. | |
| 3638 | pub fn ptrTypeSema(pt: Zcu.PerThread, info: InternPool.Key.PtrType) Zcu.SemaError!Type { | |
| 3639 | if (info.flags.alignment != .none) { | |
| 3640 | _ = try Type.fromInterned(info.child).abiAlignmentSema(pt); | |
| 3641 | } | |
| 3642 | return pt.ptrType(info); | |
| 3643 | } | |
| 3644 | ||
| 3645 | 3741 | pub fn singleMutPtrType(pt: Zcu.PerThread, child_type: Type) Allocator.Error!Type { |
| 3646 | 3742 | return pt.ptrType(.{ .child = child_type.toIntern() }); |
| 3647 | 3743 | } |
| ... | ... | @@ -3739,31 +3835,37 @@ pub fn enumValue(pt: Zcu.PerThread, ty: Type, tag_int: InternPool.Index) Allocat |
| 3739 | 3835 | /// declaration order. |
| 3740 | 3836 | pub fn enumValueFieldIndex(pt: Zcu.PerThread, ty: Type, field_index: u32) Allocator.Error!Value { |
| 3741 | 3837 | const ip = &pt.zcu.intern_pool; |
| 3838 | ty.assertHasInits(pt.zcu); | |
| 3742 | 3839 | const enum_type = ip.loadEnumType(ty.toIntern()); |
| 3743 | 3840 | |
| 3744 | if (enum_type.values.len == 0) { | |
| 3841 | assert(field_index < enum_type.field_names.len); | |
| 3842 | ||
| 3843 | if (enum_type.field_values.len == 0) { | |
| 3745 | 3844 | // Auto-numbered fields. |
| 3746 | 3845 | return Value.fromInterned(try pt.intern(.{ .enum_tag = .{ |
| 3747 | 3846 | .ty = ty.toIntern(), |
| 3748 | 3847 | .int = try pt.intern(.{ .int = .{ |
| 3749 | .ty = enum_type.tag_ty, | |
| 3848 | .ty = enum_type.int_tag_type, | |
| 3750 | 3849 | .storage = .{ .u64 = field_index }, |
| 3751 | 3850 | } }), |
| 3752 | 3851 | } })); |
| 3753 | 3852 | } |
| 3754 | 3853 | |
| 3755 | return Value.fromInterned(try pt.intern(.{ .enum_tag = .{ | |
| 3854 | return .fromInterned(try pt.intern(.{ .enum_tag = .{ | |
| 3756 | 3855 | .ty = ty.toIntern(), |
| 3757 | .int = enum_type.values.get(ip)[field_index], | |
| 3856 | .int = enum_type.field_values.get(ip)[field_index], | |
| 3758 | 3857 | } })); |
| 3759 | 3858 | } |
| 3760 | 3859 | |
| 3761 | 3860 | pub fn undefValue(pt: Zcu.PerThread, ty: Type) Allocator.Error!Value { |
| 3762 | return Value.fromInterned(try pt.intern(.{ .undef = ty.toIntern() })); | |
| 3861 | if (std.debug.runtime_safety) { | |
| 3862 | assert(try ty.onePossibleValue(pt) == null); | |
| 3863 | } | |
| 3864 | return .fromInterned(try pt.intern(.{ .undef = ty.toIntern() })); | |
| 3763 | 3865 | } |
| 3764 | 3866 | |
| 3765 | 3867 | pub fn undefRef(pt: Zcu.PerThread, ty: Type) Allocator.Error!Air.Inst.Ref { |
| 3766 | return Air.internedToRef((try pt.undefValue(ty)).toIntern()); | |
| 3868 | return .fromValue(try pt.undefValue(ty)); | |
| 3767 | 3869 | } |
| 3768 | 3870 | |
| 3769 | 3871 | pub fn intValue(pt: Zcu.PerThread, ty: Type, x: anytype) Allocator.Error!Value { |
| ... | ... | @@ -3916,7 +4018,7 @@ pub fn intFittingRange(pt: Zcu.PerThread, min: Value, max: Value) !Type { |
| 3916 | 4018 | assert(Value.order(min, max, zcu).compare(.lte)); |
| 3917 | 4019 | } |
| 3918 | 4020 | |
| 3919 | const sign = min.orderAgainstZero(zcu) == .lt; | |
| 4021 | const sign = min.compareHetero(.lt, .zero_comptime_int, zcu); | |
| 3920 | 4022 | |
| 3921 | 4023 | const min_val_bits = pt.intBitsForValue(min, sign); |
| 3922 | 4024 | const max_val_bits = pt.intBitsForValue(max, sign); |
| ... | ... | @@ -3955,12 +4057,6 @@ pub fn intBitsForValue(pt: Zcu.PerThread, val: Value, sign: bool) u16 { |
| 3955 | 4057 | |
| 3956 | 4058 | return @as(u16, @intCast(big.bitCountTwosComp())); |
| 3957 | 4059 | }, |
| 3958 | .lazy_align => |lazy_ty| { | |
| 3959 | return Type.smallestUnsignedBits(Type.fromInterned(lazy_ty).abiAlignment(pt.zcu).toByteUnits() orelse 0) + @intFromBool(sign); | |
| 3960 | }, | |
| 3961 | .lazy_size => |lazy_ty| { | |
| 3962 | return Type.smallestUnsignedBits(Type.fromInterned(lazy_ty).abiSize(pt.zcu)) + @intFromBool(sign); | |
| 3963 | }, | |
| 3964 | 4060 | } |
| 3965 | 4061 | } |
| 3966 | 4062 | |
| ... | ... | @@ -3993,7 +4089,6 @@ pub fn getExtern(pt: Zcu.PerThread, key: InternPool.Key.Extern) Allocator.Error! |
| 3993 | 4089 | const comp = zcu.comp; |
| 3994 | 4090 | const result = try zcu.intern_pool.getExtern(comp.gpa, comp.io, pt.tid, key); |
| 3995 | 4091 | if (result.new_nav.unwrap()) |nav| { |
| 3996 | // This job depends on any resolve_type_fully jobs queued up before it. | |
| 3997 | 4092 | comp.link_prog_node.increaseEstimatedTotalItems(1); |
| 3998 | 4093 | try comp.queueJob(.{ .link_nav = nav }); |
| 3999 | 4094 | if (comp.debugIncremental()) try zcu.incremental_debug_state.newNav(zcu, nav); |
| ... | ... | @@ -4013,367 +4108,6 @@ pub fn navAlignment(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) InternPo |
| 4013 | 4108 | return ty.abiAlignment(zcu); |
| 4014 | 4109 | } |
| 4015 | 4110 | |
| 4016 | /// `ty` is a container type requiring resolution (struct, union, or enum). | |
| 4017 | /// If `ty` is outdated, it is recreated at a new `InternPool.Index`, which is returned. | |
| 4018 | /// If the type cannot be recreated because it has been lost, `error.AnalysisFail` is returned. | |
| 4019 | /// If `ty` is not outdated, that same `InternPool.Index` is returned. | |
| 4020 | /// If `ty` has already been replaced by this function, the new index will not be returned again. | |
| 4021 | /// Also, if `ty` is an enum, this function will resolve the new type if needed, and the call site | |
| 4022 | /// is responsible for checking `[transitive_]failed_analysis` to detect resolution failures. | |
| 4023 | pub fn ensureTypeUpToDate(pt: Zcu.PerThread, ty: InternPool.Index) Zcu.SemaError!InternPool.Index { | |
| 4024 | const zcu = pt.zcu; | |
| 4025 | const gpa = zcu.gpa; | |
| 4026 | const ip = &zcu.intern_pool; | |
| 4027 | ||
| 4028 | const anal_unit: AnalUnit = .wrap(.{ .type = ty }); | |
| 4029 | const outdated = zcu.outdated.swapRemove(anal_unit) or | |
| 4030 | zcu.potentially_outdated.swapRemove(anal_unit); | |
| 4031 | ||
| 4032 | if (outdated) { | |
| 4033 | _ = zcu.outdated_ready.swapRemove(anal_unit); | |
| 4034 | try zcu.markDependeeOutdated(.marked_po, .{ .interned = ty }); | |
| 4035 | } | |
| 4036 | ||
| 4037 | const ty_key = switch (ip.indexToKey(ty)) { | |
| 4038 | .struct_type, .union_type, .enum_type => |key| key, | |
| 4039 | else => unreachable, | |
| 4040 | }; | |
| 4041 | const declared_ty_key = switch (ty_key) { | |
| 4042 | .reified => unreachable, // never outdated | |
| 4043 | .generated_tag => unreachable, // never outdated | |
| 4044 | .declared => |d| d, | |
| 4045 | }; | |
| 4046 | ||
| 4047 | if (declared_ty_key.zir_index.resolve(ip) == null) { | |
| 4048 | // The instruction has been lost -- this type is dead. | |
| 4049 | return error.AnalysisFail; | |
| 4050 | } | |
| 4051 | ||
| 4052 | if (!outdated) return ty; | |
| 4053 | ||
| 4054 | // We will recreate the type at a new `InternPool.Index`. | |
| 4055 | ||
| 4056 | // Delete old state which is no longer in use. Technically, this is not necessary: these exports, | |
| 4057 | // references, etc, will be ignored because the type itself is unreferenced. However, it allows | |
| 4058 | // reusing the memory which is currently being used to track this state. | |
| 4059 | zcu.deleteUnitExports(anal_unit); | |
| 4060 | zcu.deleteUnitReferences(anal_unit); | |
| 4061 | zcu.deleteUnitCompileLogs(anal_unit); | |
| 4062 | if (zcu.failed_analysis.fetchSwapRemove(anal_unit)) |kv| { | |
| 4063 | kv.value.destroy(gpa); | |
| 4064 | } | |
| 4065 | _ = zcu.transitive_failed_analysis.swapRemove(anal_unit); | |
| 4066 | zcu.intern_pool.removeDependenciesForDepender(gpa, anal_unit); | |
| 4067 | ||
| 4068 | if (zcu.comp.debugIncremental()) { | |
| 4069 | const info = try zcu.incremental_debug_state.getUnitInfo(gpa, anal_unit); | |
| 4070 | info.last_update_gen = zcu.generation; | |
| 4071 | info.deps.clearRetainingCapacity(); | |
| 4072 | } | |
| 4073 | ||
| 4074 | switch (ip.indexToKey(ty)) { | |
| 4075 | .struct_type => return pt.recreateStructType(ty, declared_ty_key), | |
| 4076 | .union_type => return pt.recreateUnionType(ty, declared_ty_key), | |
| 4077 | .enum_type => return pt.recreateEnumType(ty, declared_ty_key), | |
| 4078 | else => unreachable, | |
| 4079 | } | |
| 4080 | } | |
| 4081 | ||
| 4082 | fn recreateStructType( | |
| 4083 | pt: Zcu.PerThread, | |
| 4084 | old_ty: InternPool.Index, | |
| 4085 | key: InternPool.Key.NamespaceType.Declared, | |
| 4086 | ) Allocator.Error!InternPool.Index { | |
| 4087 | const zcu = pt.zcu; | |
| 4088 | const comp = zcu.comp; | |
| 4089 | const gpa = comp.gpa; | |
| 4090 | const io = comp.io; | |
| 4091 | const ip = &zcu.intern_pool; | |
| 4092 | ||
| 4093 | const inst_info = key.zir_index.resolveFull(ip).?; | |
| 4094 | const file = zcu.fileByIndex(inst_info.file); | |
| 4095 | const zir = file.zir.?; | |
| 4096 | ||
| 4097 | assert(zir.instructions.items(.tag)[@intFromEnum(inst_info.inst)] == .extended); | |
| 4098 | const extended = zir.instructions.items(.data)[@intFromEnum(inst_info.inst)].extended; | |
| 4099 | assert(extended.opcode == .struct_decl); | |
| 4100 | const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small); | |
| 4101 | const extra = zir.extraData(Zir.Inst.StructDecl, extended.operand); | |
| 4102 | var extra_index = extra.end; | |
| 4103 | ||
| 4104 | const captures_len = if (small.has_captures_len) blk: { | |
| 4105 | const captures_len = zir.extra[extra_index]; | |
| 4106 | extra_index += 1; | |
| 4107 | break :blk captures_len; | |
| 4108 | } else 0; | |
| 4109 | const fields_len = if (small.has_fields_len) blk: { | |
| 4110 | const fields_len = zir.extra[extra_index]; | |
| 4111 | extra_index += 1; | |
| 4112 | break :blk fields_len; | |
| 4113 | } else 0; | |
| 4114 | ||
| 4115 | assert(captures_len == key.captures.owned.len); // synchronises with logic in `Zcu.mapOldZirToNew` | |
| 4116 | ||
| 4117 | const struct_obj = ip.loadStructType(old_ty); | |
| 4118 | ||
| 4119 | const wip_ty = switch (try ip.getStructType(gpa, io, pt.tid, .{ | |
| 4120 | .layout = small.layout, | |
| 4121 | .fields_len = fields_len, | |
| 4122 | .known_non_opv = small.known_non_opv, | |
| 4123 | .requires_comptime = if (small.known_comptime_only) .yes else .unknown, | |
| 4124 | .any_comptime_fields = small.any_comptime_fields, | |
| 4125 | .any_default_inits = small.any_default_inits, | |
| 4126 | .inits_resolved = false, | |
| 4127 | .any_aligned_fields = small.any_aligned_fields, | |
| 4128 | .key = .{ .declared_owned_captures = .{ | |
| 4129 | .zir_index = key.zir_index, | |
| 4130 | .captures = key.captures.owned, | |
| 4131 | } }, | |
| 4132 | }, true)) { | |
| 4133 | .wip => |wip| wip, | |
| 4134 | .existing => unreachable, // we passed `replace_existing` | |
| 4135 | }; | |
| 4136 | errdefer wip_ty.cancel(ip, pt.tid); | |
| 4137 | ||
| 4138 | wip_ty.setName(ip, struct_obj.name, struct_obj.name_nav); | |
| 4139 | try pt.addDependency(.wrap(.{ .type = wip_ty.index }), .{ .src_hash = key.zir_index }); | |
| 4140 | zcu.namespacePtr(struct_obj.namespace).owner_type = wip_ty.index; | |
| 4141 | // No need to re-scan the namespace -- `zirStructDecl` will ultimately do that if the type is still alive. | |
| 4142 | try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index }); | |
| 4143 | ||
| 4144 | codegen_type: { | |
| 4145 | if (file.mod.?.strip) break :codegen_type; | |
| 4146 | // This job depends on any resolve_type_fully jobs queued up before it. | |
| 4147 | zcu.comp.link_prog_node.increaseEstimatedTotalItems(1); | |
| 4148 | try zcu.comp.queueJob(.{ .link_type = wip_ty.index }); | |
| 4149 | } | |
| 4150 | ||
| 4151 | if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index); | |
| 4152 | const new_ty = wip_ty.finish(ip, struct_obj.namespace); | |
| 4153 | if (inst_info.inst == .main_struct_inst) { | |
| 4154 | // This is the root type of a file! Update the reference. | |
| 4155 | zcu.setFileRootType(inst_info.file, new_ty); | |
| 4156 | } | |
| 4157 | return new_ty; | |
| 4158 | } | |
| 4159 | ||
| 4160 | fn recreateUnionType( | |
| 4161 | pt: Zcu.PerThread, | |
| 4162 | old_ty: InternPool.Index, | |
| 4163 | key: InternPool.Key.NamespaceType.Declared, | |
| 4164 | ) Allocator.Error!InternPool.Index { | |
| 4165 | const zcu = pt.zcu; | |
| 4166 | const comp = zcu.comp; | |
| 4167 | const gpa = comp.gpa; | |
| 4168 | const io = comp.io; | |
| 4169 | const ip = &zcu.intern_pool; | |
| 4170 | ||
| 4171 | const inst_info = key.zir_index.resolveFull(ip).?; | |
| 4172 | const file = zcu.fileByIndex(inst_info.file); | |
| 4173 | const zir = file.zir.?; | |
| 4174 | ||
| 4175 | assert(zir.instructions.items(.tag)[@intFromEnum(inst_info.inst)] == .extended); | |
| 4176 | const extended = zir.instructions.items(.data)[@intFromEnum(inst_info.inst)].extended; | |
| 4177 | assert(extended.opcode == .union_decl); | |
| 4178 | const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small); | |
| 4179 | const extra = zir.extraData(Zir.Inst.UnionDecl, extended.operand); | |
| 4180 | var extra_index = extra.end; | |
| 4181 | ||
| 4182 | extra_index += @intFromBool(small.has_tag_type); | |
| 4183 | const captures_len = if (small.has_captures_len) blk: { | |
| 4184 | const captures_len = zir.extra[extra_index]; | |
| 4185 | extra_index += 1; | |
| 4186 | break :blk captures_len; | |
| 4187 | } else 0; | |
| 4188 | extra_index += @intFromBool(small.has_body_len); | |
| 4189 | const fields_len = if (small.has_fields_len) blk: { | |
| 4190 | const fields_len = zir.extra[extra_index]; | |
| 4191 | extra_index += 1; | |
| 4192 | break :blk fields_len; | |
| 4193 | } else 0; | |
| 4194 | ||
| 4195 | assert(captures_len == key.captures.owned.len); // synchronises with logic in `Zcu.mapOldZirToNew` | |
| 4196 | ||
| 4197 | const union_obj = ip.loadUnionType(old_ty); | |
| 4198 | ||
| 4199 | const namespace_index = union_obj.namespace; | |
| 4200 | ||
| 4201 | const wip_ty = switch (try ip.getUnionType(gpa, io, pt.tid, .{ | |
| 4202 | .flags = .{ | |
| 4203 | .layout = small.layout, | |
| 4204 | .status = .none, | |
| 4205 | .runtime_tag = if (small.has_tag_type or small.auto_enum_tag) | |
| 4206 | .tagged | |
| 4207 | else if (small.layout != .auto) | |
| 4208 | .none | |
| 4209 | else switch (true) { // TODO | |
| 4210 | true => .safety, | |
| 4211 | false => .none, | |
| 4212 | }, | |
| 4213 | .any_aligned_fields = small.any_aligned_fields, | |
| 4214 | .requires_comptime = .unknown, | |
| 4215 | .assumed_runtime_bits = false, | |
| 4216 | .assumed_pointer_aligned = false, | |
| 4217 | .alignment = .none, | |
| 4218 | }, | |
| 4219 | .fields_len = fields_len, | |
| 4220 | .enum_tag_ty = .none, // set later | |
| 4221 | .field_types = &.{}, // set later | |
| 4222 | .field_aligns = &.{}, // set later | |
| 4223 | .key = .{ .declared_owned_captures = .{ | |
| 4224 | .zir_index = key.zir_index, | |
| 4225 | .captures = key.captures.owned, | |
| 4226 | } }, | |
| 4227 | }, true)) { | |
| 4228 | .wip => |wip| wip, | |
| 4229 | .existing => unreachable, // we passed `replace_existing` | |
| 4230 | }; | |
| 4231 | errdefer wip_ty.cancel(ip, pt.tid); | |
| 4232 | ||
| 4233 | wip_ty.setName(ip, union_obj.name, union_obj.name_nav); | |
| 4234 | try pt.addDependency(.wrap(.{ .type = wip_ty.index }), .{ .src_hash = key.zir_index }); | |
| 4235 | zcu.namespacePtr(namespace_index).owner_type = wip_ty.index; | |
| 4236 | // No need to re-scan the namespace -- `zirUnionDecl` will ultimately do that if the type is still alive. | |
| 4237 | try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index }); | |
| 4238 | ||
| 4239 | codegen_type: { | |
| 4240 | if (file.mod.?.strip) break :codegen_type; | |
| 4241 | // This job depends on any resolve_type_fully jobs queued up before it. | |
| 4242 | zcu.comp.link_prog_node.increaseEstimatedTotalItems(1); | |
| 4243 | try zcu.comp.queueJob(.{ .link_type = wip_ty.index }); | |
| 4244 | } | |
| 4245 | ||
| 4246 | if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index); | |
| 4247 | return wip_ty.finish(ip, namespace_index); | |
| 4248 | } | |
| 4249 | ||
| 4250 | /// This *does* call `Sema.resolveDeclaredEnum`, but errors from it are not propagated. | |
| 4251 | /// Call sites are resposible for checking `[transitive_]failed_analysis` after `ensureTypeUpToDate` | |
| 4252 | /// returns in order to detect resolution failures. | |
| 4253 | fn recreateEnumType( | |
| 4254 | pt: Zcu.PerThread, | |
| 4255 | old_ty: InternPool.Index, | |
| 4256 | key: InternPool.Key.NamespaceType.Declared, | |
| 4257 | ) (Allocator.Error || Io.Cancelable)!InternPool.Index { | |
| 4258 | const zcu = pt.zcu; | |
| 4259 | const comp = zcu.comp; | |
| 4260 | const gpa = comp.gpa; | |
| 4261 | const io = comp.io; | |
| 4262 | const ip = &zcu.intern_pool; | |
| 4263 | ||
| 4264 | const inst_info = key.zir_index.resolveFull(ip).?; | |
| 4265 | const file = zcu.fileByIndex(inst_info.file); | |
| 4266 | const zir = file.zir.?; | |
| 4267 | ||
| 4268 | assert(zir.instructions.items(.tag)[@intFromEnum(inst_info.inst)] == .extended); | |
| 4269 | const extended = zir.instructions.items(.data)[@intFromEnum(inst_info.inst)].extended; | |
| 4270 | assert(extended.opcode == .enum_decl); | |
| 4271 | const small: Zir.Inst.EnumDecl.Small = @bitCast(extended.small); | |
| 4272 | const extra = zir.extraData(Zir.Inst.EnumDecl, extended.operand); | |
| 4273 | var extra_index = extra.end; | |
| 4274 | ||
| 4275 | const tag_type_ref = if (small.has_tag_type) blk: { | |
| 4276 | const tag_type_ref: Zir.Inst.Ref = @enumFromInt(zir.extra[extra_index]); | |
| 4277 | extra_index += 1; | |
| 4278 | break :blk tag_type_ref; | |
| 4279 | } else .none; | |
| 4280 | ||
| 4281 | const captures_len = if (small.has_captures_len) blk: { | |
| 4282 | const captures_len = zir.extra[extra_index]; | |
| 4283 | extra_index += 1; | |
| 4284 | break :blk captures_len; | |
| 4285 | } else 0; | |
| 4286 | ||
| 4287 | const body_len = if (small.has_body_len) blk: { | |
| 4288 | const body_len = zir.extra[extra_index]; | |
| 4289 | extra_index += 1; | |
| 4290 | break :blk body_len; | |
| 4291 | } else 0; | |
| 4292 | ||
| 4293 | const fields_len = if (small.has_fields_len) blk: { | |
| 4294 | const fields_len = zir.extra[extra_index]; | |
| 4295 | extra_index += 1; | |
| 4296 | break :blk fields_len; | |
| 4297 | } else 0; | |
| 4298 | ||
| 4299 | const decls_len = if (small.has_decls_len) blk: { | |
| 4300 | const decls_len = zir.extra[extra_index]; | |
| 4301 | extra_index += 1; | |
| 4302 | break :blk decls_len; | |
| 4303 | } else 0; | |
| 4304 | ||
| 4305 | assert(captures_len == key.captures.owned.len); // synchronises with logic in `Zcu.mapOldZirToNew` | |
| 4306 | ||
| 4307 | extra_index += captures_len * 2; | |
| 4308 | extra_index += decls_len; | |
| 4309 | ||
| 4310 | const body = zir.bodySlice(extra_index, body_len); | |
| 4311 | extra_index += body.len; | |
| 4312 | ||
| 4313 | const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable; | |
| 4314 | const body_end = extra_index; | |
| 4315 | extra_index += bit_bags_count; | |
| 4316 | ||
| 4317 | const any_values = for (zir.extra[body_end..][0..bit_bags_count]) |bag| { | |
| 4318 | if (bag != 0) break true; | |
| 4319 | } else false; | |
| 4320 | ||
| 4321 | const enum_obj = ip.loadEnumType(old_ty); | |
| 4322 | ||
| 4323 | const namespace_index = enum_obj.namespace; | |
| 4324 | ||
| 4325 | const wip_ty = switch (try ip.getEnumType(gpa, io, pt.tid, .{ | |
| 4326 | .has_values = any_values, | |
| 4327 | .tag_mode = if (small.nonexhaustive) | |
| 4328 | .nonexhaustive | |
| 4329 | else if (tag_type_ref == .none) | |
| 4330 | .auto | |
| 4331 | else | |
| 4332 | .explicit, | |
| 4333 | .fields_len = fields_len, | |
| 4334 | .key = .{ .declared_owned_captures = .{ | |
| 4335 | .zir_index = key.zir_index, | |
| 4336 | .captures = key.captures.owned, | |
| 4337 | } }, | |
| 4338 | }, true)) { | |
| 4339 | .wip => |wip| wip, | |
| 4340 | .existing => unreachable, // we passed `replace_existing` | |
| 4341 | }; | |
| 4342 | var done = true; | |
| 4343 | errdefer if (!done) wip_ty.cancel(ip, pt.tid); | |
| 4344 | ||
| 4345 | wip_ty.setName(ip, enum_obj.name, enum_obj.name_nav); | |
| 4346 | ||
| 4347 | zcu.namespacePtr(namespace_index).owner_type = wip_ty.index; | |
| 4348 | // No need to re-scan the namespace -- `zirEnumDecl` will ultimately do that if the type is still alive. | |
| 4349 | ||
| 4350 | if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index); | |
| 4351 | wip_ty.prepare(ip, namespace_index); | |
| 4352 | done = true; | |
| 4353 | ||
| 4354 | Sema.resolveDeclaredEnum( | |
| 4355 | pt, | |
| 4356 | wip_ty, | |
| 4357 | inst_info.inst, | |
| 4358 | key.zir_index, | |
| 4359 | namespace_index, | |
| 4360 | enum_obj.name, | |
| 4361 | small, | |
| 4362 | body, | |
| 4363 | tag_type_ref, | |
| 4364 | any_values, | |
| 4365 | fields_len, | |
| 4366 | zir, | |
| 4367 | body_end, | |
| 4368 | ) catch |err| switch (err) { | |
| 4369 | error.OutOfMemory => |e| return e, | |
| 4370 | error.Canceled => |e| return e, | |
| 4371 | error.AnalysisFail => {}, // call sites are responsible for checking `[transitive_]failed_analysis` to detect this | |
| 4372 | }; | |
| 4373 | ||
| 4374 | return wip_ty.index; | |
| 4375 | } | |
| 4376 | ||
| 4377 | 4111 | /// Given a namespace, re-scan its declarations from the type definition if they have not |
| 4378 | 4112 | /// yet been re-scanned on this update. |
| 4379 | 4113 | /// If the type declaration instruction has been lost, returns `error.AnalysisFail`. |
| ... | ... | @@ -4396,7 +4130,7 @@ pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace |
| 4396 | 4130 | }; |
| 4397 | 4131 | |
| 4398 | 4132 | const key = switch (full_key) { |
| 4399 | .reified, .generated_tag => { | |
| 4133 | .reified, .generated_union_tag => { | |
| 4400 | 4134 | // Namespace always empty, so up-to-date. |
| 4401 | 4135 | namespace.generation = zcu.generation; |
| 4402 | 4136 | return; |
| ... | ... | @@ -4408,100 +4142,13 @@ pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace |
| 4408 | 4142 | |
| 4409 | 4143 | const inst_info = key.zir_index.resolveFull(ip) orelse return error.AnalysisFail; |
| 4410 | 4144 | const file = zcu.fileByIndex(inst_info.file); |
| 4411 | const zir = file.zir.?; | |
| 4412 | ||
| 4413 | assert(zir.instructions.items(.tag)[@intFromEnum(inst_info.inst)] == .extended); | |
| 4414 | const extended = zir.instructions.items(.data)[@intFromEnum(inst_info.inst)].extended; | |
| 4145 | const zir = &file.zir.?; | |
| 4415 | 4146 | |
| 4416 | 4147 | const decls = switch (container) { |
| 4417 | .@"struct" => decls: { | |
| 4418 | assert(extended.opcode == .struct_decl); | |
| 4419 | const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small); | |
| 4420 | const extra = zir.extraData(Zir.Inst.StructDecl, extended.operand); | |
| 4421 | var extra_index = extra.end; | |
| 4422 | const captures_len = if (small.has_captures_len) blk: { | |
| 4423 | const captures_len = zir.extra[extra_index]; | |
| 4424 | extra_index += 1; | |
| 4425 | break :blk captures_len; | |
| 4426 | } else 0; | |
| 4427 | extra_index += @intFromBool(small.has_fields_len); | |
| 4428 | const decls_len = if (small.has_decls_len) blk: { | |
| 4429 | const decls_len = zir.extra[extra_index]; | |
| 4430 | extra_index += 1; | |
| 4431 | break :blk decls_len; | |
| 4432 | } else 0; | |
| 4433 | extra_index += captures_len * 2; | |
| 4434 | if (small.has_backing_int) { | |
| 4435 | const backing_int_body_len = zir.extra[extra_index]; | |
| 4436 | extra_index += 1; // backing_int_body_len | |
| 4437 | if (backing_int_body_len == 0) { | |
| 4438 | extra_index += 1; // backing_int_ref | |
| 4439 | } else { | |
| 4440 | extra_index += backing_int_body_len; // backing_int_body_inst | |
| 4441 | } | |
| 4442 | } | |
| 4443 | break :decls zir.bodySlice(extra_index, decls_len); | |
| 4444 | }, | |
| 4445 | .@"union" => decls: { | |
| 4446 | assert(extended.opcode == .union_decl); | |
| 4447 | const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small); | |
| 4448 | const extra = zir.extraData(Zir.Inst.UnionDecl, extended.operand); | |
| 4449 | var extra_index = extra.end; | |
| 4450 | extra_index += @intFromBool(small.has_tag_type); | |
| 4451 | const captures_len = if (small.has_captures_len) blk: { | |
| 4452 | const captures_len = zir.extra[extra_index]; | |
| 4453 | extra_index += 1; | |
| 4454 | break :blk captures_len; | |
| 4455 | } else 0; | |
| 4456 | extra_index += @intFromBool(small.has_body_len); | |
| 4457 | extra_index += @intFromBool(small.has_fields_len); | |
| 4458 | const decls_len = if (small.has_decls_len) blk: { | |
| 4459 | const decls_len = zir.extra[extra_index]; | |
| 4460 | extra_index += 1; | |
| 4461 | break :blk decls_len; | |
| 4462 | } else 0; | |
| 4463 | extra_index += captures_len * 2; | |
| 4464 | break :decls zir.bodySlice(extra_index, decls_len); | |
| 4465 | }, | |
| 4466 | .@"enum" => decls: { | |
| 4467 | assert(extended.opcode == .enum_decl); | |
| 4468 | const small: Zir.Inst.EnumDecl.Small = @bitCast(extended.small); | |
| 4469 | const extra = zir.extraData(Zir.Inst.EnumDecl, extended.operand); | |
| 4470 | var extra_index = extra.end; | |
| 4471 | extra_index += @intFromBool(small.has_tag_type); | |
| 4472 | const captures_len = if (small.has_captures_len) blk: { | |
| 4473 | const captures_len = zir.extra[extra_index]; | |
| 4474 | extra_index += 1; | |
| 4475 | break :blk captures_len; | |
| 4476 | } else 0; | |
| 4477 | extra_index += @intFromBool(small.has_body_len); | |
| 4478 | extra_index += @intFromBool(small.has_fields_len); | |
| 4479 | const decls_len = if (small.has_decls_len) blk: { | |
| 4480 | const decls_len = zir.extra[extra_index]; | |
| 4481 | extra_index += 1; | |
| 4482 | break :blk decls_len; | |
| 4483 | } else 0; | |
| 4484 | extra_index += captures_len * 2; | |
| 4485 | break :decls zir.bodySlice(extra_index, decls_len); | |
| 4486 | }, | |
| 4487 | .@"opaque" => decls: { | |
| 4488 | assert(extended.opcode == .opaque_decl); | |
| 4489 | const small: Zir.Inst.OpaqueDecl.Small = @bitCast(extended.small); | |
| 4490 | const extra = zir.extraData(Zir.Inst.OpaqueDecl, extended.operand); | |
| 4491 | var extra_index = extra.end; | |
| 4492 | const captures_len = if (small.has_captures_len) blk: { | |
| 4493 | const captures_len = zir.extra[extra_index]; | |
| 4494 | extra_index += 1; | |
| 4495 | break :blk captures_len; | |
| 4496 | } else 0; | |
| 4497 | const decls_len = if (small.has_decls_len) blk: { | |
| 4498 | const decls_len = zir.extra[extra_index]; | |
| 4499 | extra_index += 1; | |
| 4500 | break :blk decls_len; | |
| 4501 | } else 0; | |
| 4502 | extra_index += captures_len * 2; | |
| 4503 | break :decls zir.bodySlice(extra_index, decls_len); | |
| 4504 | }, | |
| 4148 | .@"struct" => zir.getStructDecl(inst_info.inst).decls, | |
| 4149 | .@"union" => zir.getUnionDecl(inst_info.inst).decls, | |
| 4150 | .@"enum" => zir.getEnumDecl(inst_info.inst).decls, | |
| 4151 | .@"opaque" => zir.getOpaqueDecl(inst_info.inst).decls, | |
| 4505 | 4152 | }; |
| 4506 | 4153 | |
| 4507 | 4154 | try pt.scanNamespace(namespace_index, decls); |
| ... | ... | @@ -4509,7 +4156,7 @@ pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace |
| 4509 | 4156 | } |
| 4510 | 4157 | |
| 4511 | 4158 | pub fn refValue(pt: Zcu.PerThread, val: InternPool.Index) Zcu.SemaError!InternPool.Index { |
| 4512 | const ptr_ty = (try pt.ptrTypeSema(.{ | |
| 4159 | const ptr_ty = (try pt.ptrType(.{ | |
| 4513 | 4160 | .child = pt.zcu.intern_pool.typeOf(val), |
| 4514 | 4161 | .flags = .{ |
| 4515 | 4162 | .alignment = .none, |
| ... | ... | @@ -4703,3 +4350,466 @@ fn printVerboseAir( |
| 4703 | 4350 | try air.write(w, pt, liveness); |
| 4704 | 4351 | try w.print("# End Function AIR: {f}\n\n", .{fqn.fmt(ip)}); |
| 4705 | 4352 | } |
| 4353 | ||
| 4354 | // MLUGG TODO: these functions are all blatant hacks. See if I can remove them! | |
| 4355 | pub fn resolveTypeForCodegen(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void { | |
| 4356 | const zcu = pt.zcu; | |
| 4357 | const ip = &zcu.intern_pool; | |
| 4358 | if (ty.isGenericPoison()) return; | |
| 4359 | switch (ty.zigTypeTag(zcu)) { | |
| 4360 | .type, | |
| 4361 | .void, | |
| 4362 | .bool, | |
| 4363 | .noreturn, | |
| 4364 | .int, | |
| 4365 | .float, | |
| 4366 | .error_set, | |
| 4367 | .@"opaque", | |
| 4368 | .comptime_float, | |
| 4369 | .comptime_int, | |
| 4370 | .undefined, | |
| 4371 | .null, | |
| 4372 | .enum_literal, | |
| 4373 | => {}, | |
| 4374 | ||
| 4375 | .frame, .@"anyframe" => @panic("TODO resolveTypeForCodegen async frames"), | |
| 4376 | ||
| 4377 | .optional => try pt.resolveTypeForCodegen(ty.childType(zcu)), | |
| 4378 | .error_union => try pt.resolveTypeForCodegen(ty.errorUnionPayload(zcu)), | |
| 4379 | .pointer => try pt.resolveTypeForCodegen(ty.childType(zcu)), | |
| 4380 | .array => try pt.resolveTypeForCodegen(ty.childType(zcu)), | |
| 4381 | .vector => try pt.resolveTypeForCodegen(ty.childType(zcu)), | |
| 4382 | ||
| 4383 | .@"fn" => { | |
| 4384 | const info = zcu.typeToFunc(ty).?; | |
| 4385 | for (0..info.param_types.len) |i| { | |
| 4386 | const param_ty = info.param_types.get(ip)[i]; | |
| 4387 | try pt.resolveTypeForCodegen(.fromInterned(param_ty)); | |
| 4388 | } | |
| 4389 | try pt.resolveTypeForCodegen(.fromInterned(info.return_type)); | |
| 4390 | }, | |
| 4391 | ||
| 4392 | .@"struct" => switch (ip.indexToKey(ty.toIntern())) { | |
| 4393 | .struct_type => { | |
| 4394 | try pt.ensureTypeLayoutUpToDate(ty); | |
| 4395 | try pt.ensureTypeInitsUpToDate(ty); | |
| 4396 | }, | |
| 4397 | .tuple_type => |tuple| for (0..tuple.types.len) |i| { | |
| 4398 | const field_is_comptime = tuple.values.get(ip)[i] != .none; | |
| 4399 | if (field_is_comptime) continue; | |
| 4400 | const field_ty = tuple.types.get(ip)[i]; | |
| 4401 | try pt.resolveTypeForCodegen(.fromInterned(field_ty)); | |
| 4402 | }, | |
| 4403 | else => unreachable, | |
| 4404 | }, | |
| 4405 | ||
| 4406 | .@"union" => try pt.ensureTypeLayoutUpToDate(ty), | |
| 4407 | .@"enum" => try pt.ensureTypeInitsUpToDate(ty), | |
| 4408 | } | |
| 4409 | } | |
| 4410 | pub fn resolveValueTypesForCodegen(pt: Zcu.PerThread, val: Value) Zcu.SemaError!void { | |
| 4411 | const zcu = pt.zcu; | |
| 4412 | const ty: Type = switch (val.typeOf(zcu).toIntern()) { | |
| 4413 | .type_type => if (val.isUndef(zcu)) { | |
| 4414 | return; | |
| 4415 | } else val.toType(), | |
| 4416 | else => |ty| .fromInterned(ty), | |
| 4417 | }; | |
| 4418 | return pt.resolveTypeForCodegen(ty); | |
| 4419 | } | |
| 4420 | pub fn resolveAirTypesForCodegen(pt: Zcu.PerThread, air: *const Air) Zcu.SemaError!void { | |
| 4421 | return pt.resolveBodyTypesForCodegen(air, air.getMainBody()); | |
| 4422 | } | |
| 4423 | fn resolveBodyTypesForCodegen(pt: Zcu.PerThread, air: *const Air, body: []const Air.Inst.Index) Zcu.SemaError!void { | |
| 4424 | const zcu = pt.zcu; | |
| 4425 | const tags = air.instructions.items(.tag); | |
| 4426 | const datas = air.instructions.items(.data); | |
| 4427 | for (body) |inst| { | |
| 4428 | const data = datas[@intFromEnum(inst)]; | |
| 4429 | switch (tags[@intFromEnum(inst)]) { | |
| 4430 | .inferred_alloc, .inferred_alloc_comptime => unreachable, | |
| 4431 | ||
| 4432 | .arg => try pt.resolveTypeForCodegen(data.arg.ty.toType()), | |
| 4433 | ||
| 4434 | .add, | |
| 4435 | .add_safe, | |
| 4436 | .add_optimized, | |
| 4437 | .add_wrap, | |
| 4438 | .add_sat, | |
| 4439 | .sub, | |
| 4440 | .sub_safe, | |
| 4441 | .sub_optimized, | |
| 4442 | .sub_wrap, | |
| 4443 | .sub_sat, | |
| 4444 | .mul, | |
| 4445 | .mul_safe, | |
| 4446 | .mul_optimized, | |
| 4447 | .mul_wrap, | |
| 4448 | .mul_sat, | |
| 4449 | .div_float, | |
| 4450 | .div_float_optimized, | |
| 4451 | .div_trunc, | |
| 4452 | .div_trunc_optimized, | |
| 4453 | .div_floor, | |
| 4454 | .div_floor_optimized, | |
| 4455 | .div_exact, | |
| 4456 | .div_exact_optimized, | |
| 4457 | .rem, | |
| 4458 | .rem_optimized, | |
| 4459 | .mod, | |
| 4460 | .mod_optimized, | |
| 4461 | .max, | |
| 4462 | .min, | |
| 4463 | .bit_and, | |
| 4464 | .bit_or, | |
| 4465 | .shr, | |
| 4466 | .shr_exact, | |
| 4467 | .shl, | |
| 4468 | .shl_exact, | |
| 4469 | .shl_sat, | |
| 4470 | .xor, | |
| 4471 | .cmp_lt, | |
| 4472 | .cmp_lt_optimized, | |
| 4473 | .cmp_lte, | |
| 4474 | .cmp_lte_optimized, | |
| 4475 | .cmp_eq, | |
| 4476 | .cmp_eq_optimized, | |
| 4477 | .cmp_gte, | |
| 4478 | .cmp_gte_optimized, | |
| 4479 | .cmp_gt, | |
| 4480 | .cmp_gt_optimized, | |
| 4481 | .cmp_neq, | |
| 4482 | .cmp_neq_optimized, | |
| 4483 | .bool_and, | |
| 4484 | .bool_or, | |
| 4485 | .store, | |
| 4486 | .store_safe, | |
| 4487 | .set_union_tag, | |
| 4488 | .array_elem_val, | |
| 4489 | .slice_elem_val, | |
| 4490 | .ptr_elem_val, | |
| 4491 | .memset, | |
| 4492 | .memset_safe, | |
| 4493 | .memcpy, | |
| 4494 | .memmove, | |
| 4495 | .atomic_store_unordered, | |
| 4496 | .atomic_store_monotonic, | |
| 4497 | .atomic_store_release, | |
| 4498 | .atomic_store_seq_cst, | |
| 4499 | .legalize_vec_elem_val, | |
| 4500 | => { | |
| 4501 | try pt.resolveRefTypesForCodegen(data.bin_op.lhs); | |
| 4502 | try pt.resolveRefTypesForCodegen(data.bin_op.rhs); | |
| 4503 | }, | |
| 4504 | ||
| 4505 | .not, | |
| 4506 | .bitcast, | |
| 4507 | .clz, | |
| 4508 | .ctz, | |
| 4509 | .popcount, | |
| 4510 | .byte_swap, | |
| 4511 | .bit_reverse, | |
| 4512 | .abs, | |
| 4513 | .load, | |
| 4514 | .fptrunc, | |
| 4515 | .fpext, | |
| 4516 | .intcast, | |
| 4517 | .intcast_safe, | |
| 4518 | .trunc, | |
| 4519 | .optional_payload, | |
| 4520 | .optional_payload_ptr, | |
| 4521 | .optional_payload_ptr_set, | |
| 4522 | .wrap_optional, | |
| 4523 | .unwrap_errunion_payload, | |
| 4524 | .unwrap_errunion_err, | |
| 4525 | .unwrap_errunion_payload_ptr, | |
| 4526 | .unwrap_errunion_err_ptr, | |
| 4527 | .errunion_payload_ptr_set, | |
| 4528 | .wrap_errunion_payload, | |
| 4529 | .wrap_errunion_err, | |
| 4530 | .struct_field_ptr_index_0, | |
| 4531 | .struct_field_ptr_index_1, | |
| 4532 | .struct_field_ptr_index_2, | |
| 4533 | .struct_field_ptr_index_3, | |
| 4534 | .get_union_tag, | |
| 4535 | .slice_len, | |
| 4536 | .slice_ptr, | |
| 4537 | .ptr_slice_len_ptr, | |
| 4538 | .ptr_slice_ptr_ptr, | |
| 4539 | .array_to_slice, | |
| 4540 | .int_from_float, | |
| 4541 | .int_from_float_optimized, | |
| 4542 | .int_from_float_safe, | |
| 4543 | .int_from_float_optimized_safe, | |
| 4544 | .float_from_int, | |
| 4545 | .splat, | |
| 4546 | .error_set_has_value, | |
| 4547 | .addrspace_cast, | |
| 4548 | .c_va_arg, | |
| 4549 | .c_va_copy, | |
| 4550 | => { | |
| 4551 | try pt.resolveTypeForCodegen(data.ty_op.ty.toType()); | |
| 4552 | try pt.resolveRefTypesForCodegen(data.ty_op.operand); | |
| 4553 | }, | |
| 4554 | ||
| 4555 | .alloc, | |
| 4556 | .ret_ptr, | |
| 4557 | .c_va_start, | |
| 4558 | => try pt.resolveTypeForCodegen(data.ty), | |
| 4559 | ||
| 4560 | .ptr_add, | |
| 4561 | .ptr_sub, | |
| 4562 | .add_with_overflow, | |
| 4563 | .sub_with_overflow, | |
| 4564 | .mul_with_overflow, | |
| 4565 | .shl_with_overflow, | |
| 4566 | .slice, | |
| 4567 | .slice_elem_ptr, | |
| 4568 | .ptr_elem_ptr, | |
| 4569 | => { | |
| 4570 | const bin = air.extraData(Air.Bin, data.ty_pl.payload).data; | |
| 4571 | try pt.resolveTypeForCodegen(data.ty_pl.ty.toType()); | |
| 4572 | try pt.resolveRefTypesForCodegen(bin.lhs); | |
| 4573 | try pt.resolveRefTypesForCodegen(bin.rhs); | |
| 4574 | }, | |
| 4575 | ||
| 4576 | .block, | |
| 4577 | .loop, | |
| 4578 | => { | |
| 4579 | const block = air.unwrapBlock(inst); | |
| 4580 | try pt.resolveTypeForCodegen(block.ty); | |
| 4581 | try pt.resolveBodyTypesForCodegen(air, block.body); | |
| 4582 | }, | |
| 4583 | ||
| 4584 | .dbg_inline_block => { | |
| 4585 | const block = air.unwrapDbgBlock(inst); | |
| 4586 | try pt.resolveTypeForCodegen(block.ty); | |
| 4587 | try pt.resolveBodyTypesForCodegen(air, block.body); | |
| 4588 | }, | |
| 4589 | ||
| 4590 | .sqrt, | |
| 4591 | .sin, | |
| 4592 | .cos, | |
| 4593 | .tan, | |
| 4594 | .exp, | |
| 4595 | .exp2, | |
| 4596 | .log, | |
| 4597 | .log2, | |
| 4598 | .log10, | |
| 4599 | .floor, | |
| 4600 | .ceil, | |
| 4601 | .round, | |
| 4602 | .trunc_float, | |
| 4603 | .neg, | |
| 4604 | .neg_optimized, | |
| 4605 | .is_null, | |
| 4606 | .is_non_null, | |
| 4607 | .is_null_ptr, | |
| 4608 | .is_non_null_ptr, | |
| 4609 | .is_err, | |
| 4610 | .is_non_err, | |
| 4611 | .is_err_ptr, | |
| 4612 | .is_non_err_ptr, | |
| 4613 | .ret, | |
| 4614 | .ret_safe, | |
| 4615 | .ret_load, | |
| 4616 | .is_named_enum_value, | |
| 4617 | .tag_name, | |
| 4618 | .error_name, | |
| 4619 | .cmp_lt_errors_len, | |
| 4620 | .c_va_end, | |
| 4621 | .set_err_return_trace, | |
| 4622 | => try pt.resolveRefTypesForCodegen(data.un_op), | |
| 4623 | ||
| 4624 | .br, .switch_dispatch => try pt.resolveRefTypesForCodegen(data.br.operand), | |
| 4625 | ||
| 4626 | .cmp_vector, | |
| 4627 | .cmp_vector_optimized, | |
| 4628 | => { | |
| 4629 | const extra = air.extraData(Air.VectorCmp, data.ty_pl.payload).data; | |
| 4630 | try pt.resolveTypeForCodegen(data.ty_pl.ty.toType()); | |
| 4631 | try pt.resolveRefTypesForCodegen(extra.lhs); | |
| 4632 | try pt.resolveRefTypesForCodegen(extra.rhs); | |
| 4633 | }, | |
| 4634 | ||
| 4635 | .reduce, | |
| 4636 | .reduce_optimized, | |
| 4637 | => try pt.resolveRefTypesForCodegen(data.reduce.operand), | |
| 4638 | ||
| 4639 | .struct_field_ptr, | |
| 4640 | .struct_field_val, | |
| 4641 | => { | |
| 4642 | const extra = air.extraData(Air.StructField, data.ty_pl.payload).data; | |
| 4643 | try pt.resolveTypeForCodegen(data.ty_pl.ty.toType()); | |
| 4644 | try pt.resolveRefTypesForCodegen(extra.struct_operand); | |
| 4645 | }, | |
| 4646 | ||
| 4647 | .shuffle_one => { | |
| 4648 | const unwrapped = air.unwrapShuffleOne(zcu, inst); | |
| 4649 | try pt.resolveTypeForCodegen(unwrapped.result_ty); | |
| 4650 | try pt.resolveRefTypesForCodegen(unwrapped.operand); | |
| 4651 | for (unwrapped.mask) |m| switch (m.unwrap()) { | |
| 4652 | .elem => {}, | |
| 4653 | .value => |val| try pt.resolveValueTypesForCodegen(.fromInterned(val)), | |
| 4654 | }; | |
| 4655 | }, | |
| 4656 | ||
| 4657 | .shuffle_two => { | |
| 4658 | const unwrapped = air.unwrapShuffleTwo(zcu, inst); | |
| 4659 | try pt.resolveTypeForCodegen(unwrapped.result_ty); | |
| 4660 | try pt.resolveRefTypesForCodegen(unwrapped.operand_a); | |
| 4661 | try pt.resolveRefTypesForCodegen(unwrapped.operand_b); | |
| 4662 | // No values to check because there are no comptime-known values other than undef | |
| 4663 | }, | |
| 4664 | ||
| 4665 | .cmpxchg_weak, | |
| 4666 | .cmpxchg_strong, | |
| 4667 | => { | |
| 4668 | const extra = air.extraData(Air.Cmpxchg, data.ty_pl.payload).data; | |
| 4669 | try pt.resolveTypeForCodegen(data.ty_pl.ty.toType()); | |
| 4670 | try pt.resolveRefTypesForCodegen(extra.ptr); | |
| 4671 | try pt.resolveRefTypesForCodegen(extra.expected_value); | |
| 4672 | try pt.resolveRefTypesForCodegen(extra.new_value); | |
| 4673 | }, | |
| 4674 | ||
| 4675 | .aggregate_init => { | |
| 4676 | const ty = data.ty_pl.ty.toType(); | |
| 4677 | const elems_len: usize = @intCast(ty.arrayLen(zcu)); | |
| 4678 | const elems: []const Air.Inst.Ref = @ptrCast(air.extra.items[data.ty_pl.payload..][0..elems_len]); | |
| 4679 | try pt.resolveTypeForCodegen(ty); | |
| 4680 | if (ty.zigTypeTag(zcu) == .@"struct") { | |
| 4681 | for (elems, 0..) |elem, elem_idx| { | |
| 4682 | if (ty.structFieldIsComptime(elem_idx, zcu)) continue; | |
| 4683 | try pt.resolveRefTypesForCodegen(elem); | |
| 4684 | } | |
| 4685 | } else { | |
| 4686 | for (elems) |elem| { | |
| 4687 | try pt.resolveRefTypesForCodegen(elem); | |
| 4688 | } | |
| 4689 | } | |
| 4690 | }, | |
| 4691 | ||
| 4692 | .union_init => { | |
| 4693 | const extra = air.extraData(Air.UnionInit, data.ty_pl.payload).data; | |
| 4694 | try pt.resolveTypeForCodegen(data.ty_pl.ty.toType()); | |
| 4695 | try pt.resolveRefTypesForCodegen(extra.init); | |
| 4696 | }, | |
| 4697 | ||
| 4698 | .field_parent_ptr => { | |
| 4699 | const extra = air.extraData(Air.FieldParentPtr, data.ty_pl.payload).data; | |
| 4700 | try pt.resolveTypeForCodegen(data.ty_pl.ty.toType()); | |
| 4701 | try pt.resolveRefTypesForCodegen(extra.field_ptr); | |
| 4702 | }, | |
| 4703 | ||
| 4704 | .atomic_load => try pt.resolveRefTypesForCodegen(data.atomic_load.ptr), | |
| 4705 | ||
| 4706 | .prefetch => try pt.resolveRefTypesForCodegen(data.prefetch.ptr), | |
| 4707 | ||
| 4708 | .runtime_nav_ptr => try pt.resolveTypeForCodegen(.fromInterned(data.ty_nav.ty)), | |
| 4709 | ||
| 4710 | .select, | |
| 4711 | .mul_add, | |
| 4712 | .legalize_vec_store_elem, | |
| 4713 | => { | |
| 4714 | const bin = air.extraData(Air.Bin, data.pl_op.payload).data; | |
| 4715 | try pt.resolveRefTypesForCodegen(data.pl_op.operand); | |
| 4716 | try pt.resolveRefTypesForCodegen(bin.lhs); | |
| 4717 | try pt.resolveRefTypesForCodegen(bin.rhs); | |
| 4718 | }, | |
| 4719 | ||
| 4720 | .atomic_rmw => { | |
| 4721 | const extra = air.extraData(Air.AtomicRmw, data.pl_op.payload).data; | |
| 4722 | try pt.resolveRefTypesForCodegen(data.pl_op.operand); | |
| 4723 | try pt.resolveRefTypesForCodegen(extra.operand); | |
| 4724 | }, | |
| 4725 | ||
| 4726 | .call, | |
| 4727 | .call_always_tail, | |
| 4728 | .call_never_tail, | |
| 4729 | .call_never_inline, | |
| 4730 | => { | |
| 4731 | const call = air.unwrapCall(inst); | |
| 4732 | try pt.resolveRefTypesForCodegen(call.callee); | |
| 4733 | for (call.args) |arg| try pt.resolveRefTypesForCodegen(arg); | |
| 4734 | }, | |
| 4735 | ||
| 4736 | .dbg_var_ptr, | |
| 4737 | .dbg_var_val, | |
| 4738 | .dbg_arg_inline, | |
| 4739 | => try pt.resolveRefTypesForCodegen(data.pl_op.operand), | |
| 4740 | ||
| 4741 | .@"try", .try_cold => { | |
| 4742 | const @"try" = air.unwrapTry(inst); | |
| 4743 | try pt.resolveRefTypesForCodegen(@"try".error_union); | |
| 4744 | try pt.resolveBodyTypesForCodegen(air, @"try".else_body); | |
| 4745 | }, | |
| 4746 | ||
| 4747 | .try_ptr, .try_ptr_cold => { | |
| 4748 | const try_ptr = air.unwrapTryPtr(inst); | |
| 4749 | try pt.resolveTypeForCodegen(try_ptr.error_union_payload_ptr_ty.toType()); | |
| 4750 | try pt.resolveRefTypesForCodegen(try_ptr.error_union_ptr); | |
| 4751 | try pt.resolveBodyTypesForCodegen(air, try_ptr.else_body); | |
| 4752 | }, | |
| 4753 | ||
| 4754 | .cond_br => { | |
| 4755 | const cond_br = air.unwrapCondBr(inst); | |
| 4756 | try pt.resolveRefTypesForCodegen(cond_br.condition); | |
| 4757 | try pt.resolveBodyTypesForCodegen(air, cond_br.then_body); | |
| 4758 | try pt.resolveBodyTypesForCodegen(air, cond_br.else_body); | |
| 4759 | }, | |
| 4760 | ||
| 4761 | .switch_br, .loop_switch_br => { | |
| 4762 | const switch_br = air.unwrapSwitch(inst); | |
| 4763 | try pt.resolveRefTypesForCodegen(switch_br.operand); | |
| 4764 | var it = switch_br.iterateCases(); | |
| 4765 | while (it.next()) |case| { | |
| 4766 | for (case.items) |item| { | |
| 4767 | try pt.resolveRefTypesForCodegen(item); | |
| 4768 | } | |
| 4769 | for (case.ranges) |range| { | |
| 4770 | try pt.resolveRefTypesForCodegen(range[0]); | |
| 4771 | try pt.resolveRefTypesForCodegen(range[1]); | |
| 4772 | } | |
| 4773 | try pt.resolveBodyTypesForCodegen(air, case.body); | |
| 4774 | } | |
| 4775 | try pt.resolveBodyTypesForCodegen(air, it.elseBody()); | |
| 4776 | }, | |
| 4777 | ||
| 4778 | .assembly => { | |
| 4779 | const @"asm" = air.unwrapAsm(inst); | |
| 4780 | try pt.resolveTypeForCodegen(data.ty_pl.ty.toType()); | |
| 4781 | for (@"asm".outputs) |output| if (output != .none) try pt.resolveRefTypesForCodegen(output); | |
| 4782 | for (@"asm".inputs) |input| if (input != .none) try pt.resolveRefTypesForCodegen(input); | |
| 4783 | }, | |
| 4784 | ||
| 4785 | .legalize_compiler_rt_call => { | |
| 4786 | const compiler_rt_call = air.unwrapCompilerRtCall(inst); | |
| 4787 | for (compiler_rt_call.args) |arg| try pt.resolveRefTypesForCodegen(arg); | |
| 4788 | }, | |
| 4789 | ||
| 4790 | .trap, | |
| 4791 | .breakpoint, | |
| 4792 | .ret_addr, | |
| 4793 | .frame_addr, | |
| 4794 | .unreach, | |
| 4795 | .wasm_memory_size, | |
| 4796 | .wasm_memory_grow, | |
| 4797 | .work_item_id, | |
| 4798 | .work_group_size, | |
| 4799 | .work_group_id, | |
| 4800 | .dbg_stmt, | |
| 4801 | .dbg_empty_stmt, | |
| 4802 | .err_return_trace, | |
| 4803 | .save_err_return_trace_index, | |
| 4804 | .repeat, | |
| 4805 | => {}, | |
| 4806 | } | |
| 4807 | } | |
| 4808 | } | |
| 4809 | fn resolveRefTypesForCodegen(pt: Zcu.PerThread, ref: Air.Inst.Ref) Zcu.SemaError!void { | |
| 4810 | const ip_index = ref.toInterned() orelse { | |
| 4811 | // `ref` refers to a prior instruction, which we already did the resolution for. | |
| 4812 | return; | |
| 4813 | }; | |
| 4814 | return pt.resolveValueTypesForCodegen(.fromInterned(ip_index)); | |
| 4815 | } |
src/codegen.zig+1-1| ... | ... | @@ -1088,7 +1088,7 @@ pub fn lowerValue(pt: Zcu.PerThread, val: Value, target: *const std.Target) Allo |
| 1088 | 1088 | return .{ .immediate = fn_ty.abiAlignment(zcu).toByteUnits().? }; |
| 1089 | 1089 | } |
| 1090 | 1090 | } else if (ty.zigTypeTag(zcu) == .pointer) { |
| 1091 | const elem_ty = ty.elemType2(zcu); | |
| 1091 | const elem_ty = ty.childType(zcu); | |
| 1092 | 1092 | if (!elem_ty.hasRuntimeBits(zcu)) { |
| 1093 | 1093 | return .{ .immediate = elem_ty.abiAlignment(zcu).toByteUnits().? }; |
| 1094 | 1094 | } |
src/codegen/aarch64/Select.zig+4-4| ... | ... | @@ -2464,7 +2464,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, |
| 2464 | 2464 | |
| 2465 | 2465 | const ty_pl = air.data(air.inst_index).ty_pl; |
| 2466 | 2466 | const bin_op = isel.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2467 | const elem_size = ty_pl.ty.toType().elemType2(zcu).abiSize(zcu); | |
| 2467 | const elem_size = ty_pl.ty.toType().childType(zcu).abiSize(zcu); | |
| 2468 | 2468 | |
| 2469 | 2469 | const base_vi = try isel.use(bin_op.lhs); |
| 2470 | 2470 | var base_part_it = base_vi.field(ty_pl.ty.toType(), 0, 8); |
| ... | ... | @@ -6145,7 +6145,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, |
| 6145 | 6145 | } else { |
| 6146 | 6146 | const elem_ptr_ra = try isel.allocIntReg(); |
| 6147 | 6147 | defer isel.freeReg(elem_ptr_ra); |
| 6148 | if (!try elem_vi.value.load(isel, slice_ty.elemType2(zcu), elem_ptr_ra, .{ | |
| 6148 | if (!try elem_vi.value.load(isel, slice_ty.childType(zcu), elem_ptr_ra, .{ | |
| 6149 | 6149 | .@"volatile" = ptr_info.flags.is_volatile, |
| 6150 | 6150 | })) break :unused; |
| 6151 | 6151 | const slice_vi = try isel.use(bin_op.lhs); |
| ... | ... | @@ -6253,7 +6253,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, |
| 6253 | 6253 | } else { |
| 6254 | 6254 | const elem_ptr_ra = try isel.allocIntReg(); |
| 6255 | 6255 | defer isel.freeReg(elem_ptr_ra); |
| 6256 | if (!try elem_vi.value.load(isel, ptr_ty.elemType2(zcu), elem_ptr_ra, .{ | |
| 6256 | if (!try elem_vi.value.load(isel, ptr_ty.childType(zcu), elem_ptr_ra, .{ | |
| 6257 | 6257 | .@"volatile" = ptr_info.flags.is_volatile, |
| 6258 | 6258 | })) break :unused; |
| 6259 | 6259 | const base_vi = try isel.use(bin_op.lhs); |
| ... | ... | @@ -6594,7 +6594,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory, |
| 6594 | 6594 | if (try isel.hasRepeatedByteRepr(.fromInterned(fill_val))) |fill_byte| |
| 6595 | 6595 | break :fill_byte .{ .constant = fill_byte }; |
| 6596 | 6596 | } |
| 6597 | switch (dst_ty.elemType2(zcu).abiSize(zcu)) { | |
| 6597 | switch (dst_ty.indexablePtrElem(zcu).abiSize(zcu)) { | |
| 6598 | 6598 | 0 => unreachable, |
| 6599 | 6599 | 1 => break :fill_byte .{ .value = bin_op.rhs }, |
| 6600 | 6600 | 2, 4, 8 => |size| { |
src/codegen/c.zig+4-4| ... | ... | @@ -3676,7 +3676,7 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3676 | 3676 | |
| 3677 | 3677 | const inst_ty = f.typeOfIndex(inst); |
| 3678 | 3678 | const ptr_ty = f.typeOf(bin_op.lhs); |
| 3679 | const elem_has_bits = ptr_ty.elemType2(zcu).hasRuntimeBitsIgnoreComptime(zcu); | |
| 3679 | const elem_has_bits = ptr_ty.indexablePtrElem(zcu).hasRuntimeBitsIgnoreComptime(zcu); | |
| 3680 | 3680 | |
| 3681 | 3681 | const ptr = try f.resolveInst(bin_op.lhs); |
| 3682 | 3682 | const index = try f.resolveInst(bin_op.rhs); |
| ... | ... | @@ -3738,7 +3738,7 @@ fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3738 | 3738 | |
| 3739 | 3739 | const inst_ty = f.typeOfIndex(inst); |
| 3740 | 3740 | const slice_ty = f.typeOf(bin_op.lhs); |
| 3741 | const elem_ty = slice_ty.elemType2(zcu); | |
| 3741 | const elem_ty = slice_ty.childType(zcu); | |
| 3742 | 3742 | const elem_has_bits = elem_ty.hasRuntimeBitsIgnoreComptime(zcu); |
| 3743 | 3743 | |
| 3744 | 3744 | const slice = try f.resolveInst(bin_op.lhs); |
| ... | ... | @@ -4502,7 +4502,7 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue { |
| 4502 | 4502 | |
| 4503 | 4503 | const inst_ty = f.typeOfIndex(inst); |
| 4504 | 4504 | const inst_scalar_ty = inst_ty.scalarType(zcu); |
| 4505 | const elem_ty = inst_scalar_ty.elemType2(zcu); | |
| 4505 | const elem_ty = inst_scalar_ty.indexablePtrElem(zcu); | |
| 4506 | 4506 | if (!elem_ty.hasRuntimeBitsIgnoreComptime(zcu)) return f.moveCValue(inst, inst_ty, lhs); |
| 4507 | 4507 | const inst_scalar_ctype = try f.ctypeFromType(inst_scalar_ty, .complete); |
| 4508 | 4508 | |
| ... | ... | @@ -7037,7 +7037,7 @@ fn airMemcpy(f: *Function, inst: Air.Inst.Index, function_paren: []const u8) !CV |
| 7037 | 7037 | try w.writeAll(", "); |
| 7038 | 7038 | try writeArrayLen(f, dest_ptr, dest_ty); |
| 7039 | 7039 | try w.writeAll(" * sizeof("); |
| 7040 | try f.renderType(w, dest_ty.elemType2(zcu)); | |
| 7040 | try f.renderType(w, dest_ty.indexablePtrElem(zcu)); | |
| 7041 | 7041 | try w.writeAll("));"); |
| 7042 | 7042 | try f.object.newline(); |
| 7043 | 7043 |
src/codegen/llvm.zig+1-1| ... | ... | @@ -2112,7 +2112,7 @@ pub const Object = struct { |
| 2112 | 2112 | return debug_array_type; |
| 2113 | 2113 | }, |
| 2114 | 2114 | .vector => { |
| 2115 | const elem_ty = ty.elemType2(zcu); | |
| 2115 | const elem_ty = ty.childType(zcu); | |
| 2116 | 2116 | // Vector elements cannot be padded since that would make |
| 2117 | 2117 | // @bitSizOf(elem) * len > @bitSizOf(vec). |
| 2118 | 2118 | // Neither gdb nor lldb seem to be able to display non-byte sized |
src/codegen/mips/abi.zig+1-1| ... | ... | @@ -44,7 +44,7 @@ pub fn classifyType(ty: Type, zcu: *Zcu, ctx: Context) Class { |
| 44 | 44 | return .byval; |
| 45 | 45 | }, |
| 46 | 46 | .vector => { |
| 47 | const elem_type = ty.elemType2(zcu); | |
| 47 | const elem_type = ty.childType(zcu); | |
| 48 | 48 | switch (elem_type.zigTypeTag(zcu)) { |
| 49 | 49 | .bool, .int => { |
| 50 | 50 | const bit_size = ty.bitSize(zcu); |
src/codegen/riscv64/CodeGen.zig+2-3| ... | ... | @@ -2673,7 +2673,7 @@ fn genBinOp( |
| 2673 | 2673 | defer func.register_manager.unlockReg(tmp_lock); |
| 2674 | 2674 | |
| 2675 | 2675 | // RISC-V has no immediate mul, so we copy the size to a temporary register |
| 2676 | const elem_size = lhs_ty.elemType2(zcu).abiSize(zcu); | |
| 2676 | const elem_size = lhs_ty.indexablePtrElem(zcu).abiSize(zcu); | |
| 2677 | 2677 | const elem_size_reg = try func.copyToTmpRegister(Type.u64, .{ .immediate = elem_size }); |
| 2678 | 2678 | |
| 2679 | 2679 | try func.genBinOp( |
| ... | ... | @@ -3913,9 +3913,8 @@ fn airPtrElemVal(func: *Func, inst: Air.Inst.Index) !void { |
| 3913 | 3913 | const base_ptr_ty = func.typeOf(bin_op.lhs); |
| 3914 | 3914 | |
| 3915 | 3915 | const result: MCValue = if (!is_volatile and func.liveness.isUnused(inst)) .unreach else result: { |
| 3916 | const elem_ty = base_ptr_ty.elemType2(zcu); | |
| 3916 | const elem_ty = base_ptr_ty.indexablePtrElem(zcu); | |
| 3917 | 3917 | if (!elem_ty.hasRuntimeBitsIgnoreComptime(zcu)) break :result .none; |
| 3918 | ||
| 3919 | 3918 | const base_ptr_mcv = try func.resolveInst(bin_op.lhs); |
| 3920 | 3919 | const base_ptr_lock: ?RegisterLock = switch (base_ptr_mcv) { |
| 3921 | 3920 | .register => |reg| func.register_manager.lockRegAssumeUnused(reg), |
src/codegen/spirv/CodeGen.zig+1-1| ... | ... | @@ -4381,7 +4381,7 @@ fn airSliceElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 4381 | 4381 | fn ptrElemPtr(cg: *CodeGen, ptr_ty: Type, ptr_id: Id, index_id: Id) !Id { |
| 4382 | 4382 | const zcu = cg.module.zcu; |
| 4383 | 4383 | // Construct new pointer type for the resulting pointer |
| 4384 | const elem_ty = ptr_ty.elemType2(zcu); // use elemType() so that we get T for *[N]T. | |
| 4384 | const elem_ty = ptr_ty.indexablePtrElem(zcu); | |
| 4385 | 4385 | const elem_ty_id = try cg.resolveType(elem_ty, .indirect); |
| 4386 | 4386 | const elem_ptr_ty_id = try cg.module.ptrType(elem_ty_id, cg.module.storageClass(ptr_ty.ptrAddressSpace(zcu))); |
| 4387 | 4387 | if (ptr_ty.isSinglePointer(zcu)) { |
src/codegen/x86_64/CodeGen.zig+16-21| ... | ... | @@ -43261,7 +43261,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 43261 | 43261 | var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs }); |
| 43262 | 43262 | try ops[0].toSlicePtr(cg); |
| 43263 | 43263 | var res: [1]Temp = undefined; |
| 43264 | if (!hack_around_sema_opv_bugs or ty_pl.ty.toType().elemType2(zcu).hasRuntimeBitsIgnoreComptime(zcu)) cg.select(&res, &.{ty_pl.ty.toType()}, &ops, comptime &.{ .{ | |
| 43264 | if (!hack_around_sema_opv_bugs or ty_pl.ty.toType().childType(zcu).hasRuntimeBitsIgnoreComptime(zcu)) cg.select(&res, &.{ty_pl.ty.toType()}, &ops, comptime &.{ .{ | |
| 43265 | 43265 | .patterns = &.{ |
| 43266 | 43266 | .{ .src = .{ .to_gpr, .simm32, .none } }, |
| 43267 | 43267 | }, |
| ... | ... | @@ -43375,7 +43375,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 43375 | 43375 | var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs }); |
| 43376 | 43376 | try ops[0].toSlicePtr(cg); |
| 43377 | 43377 | var res: [1]Temp = undefined; |
| 43378 | if (!hack_around_sema_opv_bugs or ty_pl.ty.toType().elemType2(zcu).hasRuntimeBitsIgnoreComptime(zcu)) cg.select(&res, &.{ty_pl.ty.toType()}, &ops, comptime &.{ .{ | |
| 43378 | if (!hack_around_sema_opv_bugs or ty_pl.ty.toType().childType(zcu).hasRuntimeBitsIgnoreComptime(zcu)) cg.select(&res, &.{ty_pl.ty.toType()}, &ops, comptime &.{ .{ | |
| 43379 | 43379 | .patterns = &.{ |
| 43380 | 43380 | .{ .src = .{ .to_gpr, .simm32, .none } }, |
| 43381 | 43381 | }, |
| ... | ... | @@ -103926,7 +103926,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 103926 | 103926 | .array_elem_val, .legalize_vec_elem_val => { |
| 103927 | 103927 | const bin_op = air_datas[@intFromEnum(inst)].bin_op; |
| 103928 | 103928 | const array_ty = cg.typeOf(bin_op.lhs); |
| 103929 | const res_ty = array_ty.elemType2(zcu); | |
| 103929 | const res_ty = array_ty.childType(zcu); | |
| 103930 | 103930 | var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs }); |
| 103931 | 103931 | var res: [1]Temp = undefined; |
| 103932 | 103932 | cg.select(&res, &.{res_ty}, &ops, comptime &.{ .{ |
| ... | ... | @@ -104121,7 +104121,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 104121 | 104121 | }, |
| 104122 | 104122 | .slice_elem_val, .ptr_elem_val => { |
| 104123 | 104123 | const bin_op = air_datas[@intFromEnum(inst)].bin_op; |
| 104124 | const res_ty = cg.typeOf(bin_op.lhs).elemType2(zcu); | |
| 104124 | const res_ty = cg.typeOf(bin_op.lhs).indexablePtrElem(zcu); | |
| 104125 | 104125 | var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs }); |
| 104126 | 104126 | try ops[0].toSlicePtr(cg); |
| 104127 | 104127 | var res: [1]Temp = undefined; |
| ... | ... | @@ -187919,7 +187919,6 @@ const Select = struct { |
| 187919 | 187919 | unsigned_int: Memory.Size, |
| 187920 | 187920 | elem_size_is: u8, |
| 187921 | 187921 | po2_elem_size, |
| 187922 | elem_int: Memory.Size, | |
| 187923 | 187922 | |
| 187924 | 187923 | const OfIsSizes = struct { of: Memory.Size, is: Memory.Size }; |
| 187925 | 187924 | |
| ... | ... | @@ -188178,12 +188177,8 @@ const Select = struct { |
| 188178 | 188177 | .signed => false, |
| 188179 | 188178 | .unsigned => size.bitSize(cg.target) >= int_info.bits, |
| 188180 | 188179 | } else false, |
| 188181 | .elem_size_is => |size| size == ty.elemType2(zcu).abiSize(zcu), | |
| 188182 | .po2_elem_size => std.math.isPowerOfTwo(ty.elemType2(zcu).abiSize(zcu)), | |
| 188183 | .elem_int => |size| if (cg.intInfo(ty.elemType2(zcu))) |elem_int_info| | |
| 188184 | size.bitSize(cg.target) >= elem_int_info.bits | |
| 188185 | else | |
| 188186 | false, | |
| 188180 | .elem_size_is => |size| size == ty.indexablePtrElem(zcu).abiSize(zcu), | |
| 188181 | .po2_elem_size => std.math.isPowerOfTwo(ty.indexablePtrElem(zcu).abiSize(zcu)), | |
| 188187 | 188182 | }; |
| 188188 | 188183 | } |
| 188189 | 188184 | }; |
| ... | ... | @@ -189918,20 +189913,20 @@ const Select = struct { |
| 189918 | 189913 | .dst0_size => @intCast(Select.Operand.Ref.dst0.typeOf(s).abiSize(s.cg.pt.zcu)), |
| 189919 | 189914 | .delta_size => @intCast(@as(SignedImm, @intCast(op.flags.base.ref.typeOf(s).abiSize(s.cg.pt.zcu))) - |
| 189920 | 189915 | @as(SignedImm, @intCast(op.flags.index.ref.typeOf(s).abiSize(s.cg.pt.zcu)))), |
| 189921 | .delta_elem_size => @intCast(@as(SignedImm, @intCast(op.flags.base.ref.typeOf(s).elemType2(s.cg.pt.zcu).abiSize(s.cg.pt.zcu))) - | |
| 189922 | @as(SignedImm, @intCast(op.flags.index.ref.typeOf(s).elemType2(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)))), | |
| 189916 | .delta_elem_size => @intCast(@as(SignedImm, @intCast(op.flags.base.ref.typeOf(s).scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu))) - | |
| 189917 | @as(SignedImm, @intCast(op.flags.index.ref.typeOf(s).scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)))), | |
| 189923 | 189918 | .unaligned_size => @intCast(s.cg.unalignedSize(op.flags.base.ref.typeOf(s))), |
| 189924 | 189919 | .unaligned_size_add_elem_size => { |
| 189925 | 189920 | const ty = op.flags.base.ref.typeOf(s); |
| 189926 | break :lhs @intCast(s.cg.unalignedSize(ty) + ty.elemType2(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)); | |
| 189921 | break :lhs @intCast(s.cg.unalignedSize(ty) + ty.scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)); | |
| 189927 | 189922 | }, |
| 189928 | 189923 | .unaligned_size_sub_elem_size => { |
| 189929 | 189924 | const ty = op.flags.base.ref.typeOf(s); |
| 189930 | break :lhs @intCast(s.cg.unalignedSize(ty) - ty.elemType2(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)); | |
| 189925 | break :lhs @intCast(s.cg.unalignedSize(ty) - ty.scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)); | |
| 189931 | 189926 | }, |
| 189932 | 189927 | .unaligned_size_sub_2_elem_size => { |
| 189933 | 189928 | const ty = op.flags.base.ref.typeOf(s); |
| 189934 | break :lhs @intCast(s.cg.unalignedSize(ty) - ty.elemType2(s.cg.pt.zcu).abiSize(s.cg.pt.zcu) * 2); | |
| 189929 | break :lhs @intCast(s.cg.unalignedSize(ty) - ty.scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu) * 2); | |
| 189935 | 189930 | }, |
| 189936 | 189931 | .bit_size => @intCast(s.cg.nonBoolScalarBitSize(op.flags.base.ref.typeOf(s))), |
| 189937 | 189932 | .src0_bit_size => @intCast(s.cg.nonBoolScalarBitSize(Select.Operand.Ref.src0.typeOf(s))), |
| ... | ... | @@ -189944,10 +189939,10 @@ const Select = struct { |
| 189944 | 189939 | op.flags.base.ref.typeOf(s).scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu), |
| 189945 | 189940 | @divExact(op.flags.base.size.bitSize(s.cg.target), 8), |
| 189946 | 189941 | )), |
| 189947 | .elem_size => @intCast(op.flags.base.ref.typeOf(s).elemType2(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)), | |
| 189948 | .src0_elem_size => @intCast(Select.Operand.Ref.src0.typeOf(s).elemType2(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)), | |
| 189949 | .dst0_elem_size => @intCast(Select.Operand.Ref.dst0.typeOf(s).elemType2(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)), | |
| 189950 | .src0_elem_size_mul_src1 => @intCast(Select.Operand.Ref.src0.typeOf(s).elemType2(s.cg.pt.zcu).abiSize(s.cg.pt.zcu) * | |
| 189942 | .elem_size => @intCast(op.flags.base.ref.typeOf(s).scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)), | |
| 189943 | .src0_elem_size => @intCast(Select.Operand.Ref.src0.typeOf(s).scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)), | |
| 189944 | .dst0_elem_size => @intCast(Select.Operand.Ref.dst0.typeOf(s).scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)), | |
| 189945 | .src0_elem_size_mul_src1 => @intCast(Select.Operand.Ref.src0.typeOf(s).indexableElem(s.cg.pt.zcu).abiSize(s.cg.pt.zcu) * | |
| 189951 | 189946 | Select.Operand.Ref.src1.valueOf(s).immediate), |
| 189952 | 189947 | .vector_index => switch (op.flags.base.ref.typeOf(s).ptrInfo(s.cg.pt.zcu).flags.vector_index) { |
| 189953 | 189948 | .none => unreachable, |
| ... | ... | @@ -189956,7 +189951,7 @@ const Select = struct { |
| 189956 | 189951 | .src1 => @intCast(Select.Operand.Ref.src1.valueOf(s).immediate), |
| 189957 | 189952 | .src1_sub_bit_size => @as(SignedImm, @intCast(Select.Operand.Ref.src1.valueOf(s).immediate)) - |
| 189958 | 189953 | @as(SignedImm, @intCast(s.cg.nonBoolScalarBitSize(op.flags.base.ref.typeOf(s)))), |
| 189959 | .log2_src0_elem_size => @intCast(std.math.log2(Select.Operand.Ref.src0.typeOf(s).elemType2(s.cg.pt.zcu).abiSize(s.cg.pt.zcu))), | |
| 189954 | .log2_src0_elem_size => @intCast(std.math.log2(Select.Operand.Ref.src0.typeOf(s).scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu))), | |
| 189960 | 189955 | .elem_mask => @as(u8, std.math.maxInt(u8)) >> @intCast( |
| 189961 | 189956 | 8 - ((s.cg.unalignedSize(op.flags.base.ref.typeOf(s)) - 1) % |
| 189962 | 189957 | @divExact(op.flags.base.size.bitSize(s.cg.target), 8) + 1 >> |
src/link/Dwarf.zig+4-4| ... | ... | @@ -4575,10 +4575,10 @@ fn updateContainerTypeWriterError( |
| 4575 | 4575 | const name_strat: Zir.Inst.NameStrategy = switch (decl_inst.tag) { |
| 4576 | 4576 | .struct_init, .struct_init_ref, .struct_init_anon => .anon, |
| 4577 | 4577 | .extended => switch (decl_inst.data.extended.opcode) { |
| 4578 | .struct_decl => @as(Zir.Inst.StructDecl.Small, @bitCast(decl_inst.data.extended.small)).name_strategy, | |
| 4579 | .enum_decl => @as(Zir.Inst.EnumDecl.Small, @bitCast(decl_inst.data.extended.small)).name_strategy, | |
| 4580 | .union_decl => @as(Zir.Inst.UnionDecl.Small, @bitCast(decl_inst.data.extended.small)).name_strategy, | |
| 4581 | .opaque_decl => @as(Zir.Inst.OpaqueDecl.Small, @bitCast(decl_inst.data.extended.small)).name_strategy, | |
| 4578 | .struct_decl => file.zir.?.getStructDecl(inst_info.inst).name_strategy, | |
| 4579 | .union_decl => file.zir.?.getUnionDecl(inst_info.inst).name_strategy, | |
| 4580 | .enum_decl => file.zir.?.getEnumDecl(inst_info.inst).name_strategy, | |
| 4581 | .opaque_decl => file.zir.?.getOpaqueDecl(inst_info.inst).name_strategy, | |
| 4582 | 4582 | |
| 4583 | 4583 | .reify_enum, |
| 4584 | 4584 | .reify_struct, |
src/mutable_value.zig+3-15| ... | ... | @@ -18,7 +18,7 @@ pub const MutableValue = union(enum) { |
| 18 | 18 | opt_payload: SubValue, |
| 19 | 19 | /// An aggregate consisting of a single repeated value. |
| 20 | 20 | repeated: SubValue, |
| 21 | /// An aggregate of `u8` consisting of "plain" bytes (no lazy or undefined elements). | |
| 21 | /// An aggregate of `u8` consisting of "plain" bytes (no undefined elements). | |
| 22 | 22 | bytes: Bytes, |
| 23 | 23 | /// An aggregate with arbitrary sub-values. |
| 24 | 24 | aggregate: Aggregate, |
| ... | ... | @@ -415,16 +415,7 @@ pub const MutableValue = union(enum) { |
| 415 | 415 | } else if (!is_struct and is_trivial_int and Type.fromInterned(a.ty).childType(zcu).toIntern() == .u8_type) { |
| 416 | 416 | // See if we can switch to `bytes` repr |
| 417 | 417 | for (a.elems) |e| { |
| 418 | switch (e) { | |
| 419 | else => break, | |
| 420 | .interned => |ip_index| switch (ip.indexToKey(ip_index)) { | |
| 421 | else => break, | |
| 422 | .int => |int| switch (int.storage) { | |
| 423 | .u64, .i64, .big_int => {}, | |
| 424 | .lazy_align, .lazy_size => break, | |
| 425 | }, | |
| 426 | }, | |
| 427 | } | |
| 418 | if (!e.isTrivialInt(zcu)) break; | |
| 428 | 419 | } else { |
| 429 | 420 | const bytes = try arena.alloc(u8, a.elems.len); |
| 430 | 421 | for (a.elems, bytes) |elem_val, *b| { |
| ... | ... | @@ -494,10 +485,7 @@ pub const MutableValue = union(enum) { |
| 494 | 485 | else => false, |
| 495 | 486 | .interned => |ip_index| switch (zcu.intern_pool.indexToKey(ip_index)) { |
| 496 | 487 | else => false, |
| 497 | .int => |int| switch (int.storage) { | |
| 498 | .u64, .i64, .big_int => true, | |
| 499 | .lazy_align, .lazy_size => false, | |
| 500 | }, | |
| 488 | .int => true, | |
| 501 | 489 | }, |
| 502 | 490 | }; |
| 503 | 491 | } |
src/print_value.zig+2-10| ... | ... | @@ -81,14 +81,6 @@ pub fn print( |
| 81 | 81 | .int => |int| switch (int.storage) { |
| 82 | 82 | inline .u64, .i64 => |x| try writer.print("{d}", .{x}), |
| 83 | 83 | .big_int => |x| try writer.print("{d}", .{x}), |
| 84 | .lazy_align => |ty| if (opt_sema != null) { | |
| 85 | const a = try Type.fromInterned(ty).abiAlignmentSema(pt); | |
| 86 | try writer.print("{d}", .{a.toByteUnits() orelse 0}); | |
| 87 | } else try writer.print("@alignOf({f})", .{Type.fromInterned(ty).fmt(pt)}), | |
| 88 | .lazy_size => |ty| if (opt_sema != null) { | |
| 89 | const s = try Type.fromInterned(ty).abiSizeSema(pt); | |
| 90 | try writer.print("{d}", .{s}); | |
| 91 | } else try writer.print("@sizeOf({f})", .{Type.fromInterned(ty).fmt(pt)}), | |
| 92 | 84 | }, |
| 93 | 85 | .err => |err| try writer.print("error.{f}", .{ |
| 94 | 86 | err.name.fmt(ip), |
| ... | ... | @@ -104,8 +96,8 @@ pub fn print( |
| 104 | 96 | }), |
| 105 | 97 | .enum_tag => |enum_tag| { |
| 106 | 98 | const enum_type = ip.loadEnumType(val.typeOf(zcu).toIntern()); |
| 107 | if (enum_type.tagValueIndex(ip, val.toIntern())) |tag_index| { | |
| 108 | return writer.print(".{f}", .{enum_type.names.get(ip)[tag_index].fmt(ip)}); | |
| 99 | if (enum_type.tagValueIndex(ip, enum_tag.int)) |tag_index| { | |
| 100 | return writer.print(".{f}", .{enum_type.field_names.get(ip)[tag_index].fmt(ip)}); | |
| 109 | 101 | } |
| 110 | 102 | if (level == 0) { |
| 111 | 103 | return writer.writeAll("@enumFromInt(...)"); |