| ... | ... | @@ -34,8 +34,51 @@ pub const Type = struct { |
| 34 | 34 | } |
| 35 | 35 | |
| 36 | 36 | pub fn zigTypeTagOrPoison(ty: Type, mod: *const Module) error{GenericPoison}!std.builtin.TypeId { |
| 37 | | if (ty.ip_index != .none) { |
| 38 | | switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 37 | switch (ty.ip_index) { |
| 38 | .none => switch (ty.tag()) { |
| 39 | .error_set, |
| 40 | .error_set_single, |
| 41 | .error_set_inferred, |
| 42 | .error_set_merged, |
| 43 | => return .ErrorSet, |
| 44 | |
| 45 | .@"opaque" => return .Opaque, |
| 46 | |
| 47 | .function => return .Fn, |
| 48 | |
| 49 | .array, |
| 50 | .array_sentinel, |
| 51 | => return .Array, |
| 52 | |
| 53 | .pointer, |
| 54 | .inferred_alloc_const, |
| 55 | .inferred_alloc_mut, |
| 56 | => return .Pointer, |
| 57 | |
| 58 | .optional => return .Optional, |
| 59 | |
| 60 | .error_union => return .ErrorUnion, |
| 61 | |
| 62 | .anyframe_T => return .AnyFrame, |
| 63 | |
| 64 | .empty_struct, |
| 65 | .@"struct", |
| 66 | .tuple, |
| 67 | .anon_struct, |
| 68 | => return .Struct, |
| 69 | |
| 70 | .enum_full, |
| 71 | .enum_nonexhaustive, |
| 72 | .enum_simple, |
| 73 | .enum_numbered, |
| 74 | => return .Enum, |
| 75 | |
| 76 | .@"union", |
| 77 | .union_safety_tagged, |
| 78 | .union_tagged, |
| 79 | => return .Union, |
| 80 | }, |
| 81 | else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 39 | 82 | .int_type => return .Int, |
| 40 | 83 | .ptr_type => return .Pointer, |
| 41 | 84 | .array_type => return .Array, |
| ... | ... | @@ -104,51 +147,7 @@ pub const Type = struct { |
| 104 | 147 | .enum_tag, |
| 105 | 148 | .simple_value, |
| 106 | 149 | => unreachable, // it's a value, not a type |
| 107 | | } |
| 108 | | } |
| 109 | | switch (ty.tag()) { |
| 110 | | .error_set, |
| 111 | | .error_set_single, |
| 112 | | .error_set_inferred, |
| 113 | | .error_set_merged, |
| 114 | | => return .ErrorSet, |
| 115 | | |
| 116 | | .@"opaque" => return .Opaque, |
| 117 | | |
| 118 | | .function => return .Fn, |
| 119 | | |
| 120 | | .array, |
| 121 | | .array_sentinel, |
| 122 | | => return .Array, |
| 123 | | |
| 124 | | .pointer, |
| 125 | | .inferred_alloc_const, |
| 126 | | .inferred_alloc_mut, |
| 127 | | => return .Pointer, |
| 128 | | |
| 129 | | .optional => return .Optional, |
| 130 | | |
| 131 | | .error_union => return .ErrorUnion, |
| 132 | | |
| 133 | | .anyframe_T => return .AnyFrame, |
| 134 | | |
| 135 | | .empty_struct, |
| 136 | | .empty_struct_literal, |
| 137 | | .@"struct", |
| 138 | | .tuple, |
| 139 | | .anon_struct, |
| 140 | | => return .Struct, |
| 141 | | |
| 142 | | .enum_full, |
| 143 | | .enum_nonexhaustive, |
| 144 | | .enum_simple, |
| 145 | | .enum_numbered, |
| 146 | | => return .Enum, |
| 147 | | |
| 148 | | .@"union", |
| 149 | | .union_safety_tagged, |
| 150 | | .union_tagged, |
| 151 | | => return .Union, |
| 150 | }, |
| 152 | 151 | } |
| 153 | 152 | } |
| 154 | 153 | |
| ... | ... | @@ -517,7 +516,7 @@ pub const Type = struct { |
| 517 | 516 | const b_struct_obj = (b.castTag(.@"struct") orelse return false).data; |
| 518 | 517 | return a_struct_obj == b_struct_obj; |
| 519 | 518 | }, |
| 520 | | .tuple, .empty_struct_literal => { |
| 519 | .tuple => { |
| 521 | 520 | if (!b.isSimpleTuple()) return false; |
| 522 | 521 | |
| 523 | 522 | const a_tuple = a.tupleFields(); |
| ... | ... | @@ -741,7 +740,7 @@ pub const Type = struct { |
| 741 | 740 | const struct_obj: *const Module.Struct = ty.castTag(.@"struct").?.data; |
| 742 | 741 | std.hash.autoHash(hasher, struct_obj); |
| 743 | 742 | }, |
| 744 | | .tuple, .empty_struct_literal => { |
| 743 | .tuple => { |
| 745 | 744 | std.hash.autoHash(hasher, std.builtin.TypeId.Struct); |
| 746 | 745 | |
| 747 | 746 | const tuple = ty.tupleFields(); |
| ... | ... | @@ -837,7 +836,6 @@ pub const Type = struct { |
| 837 | 836 | } else switch (self.legacy.ptr_otherwise.tag) { |
| 838 | 837 | .inferred_alloc_const, |
| 839 | 838 | .inferred_alloc_mut, |
| 840 | | .empty_struct_literal, |
| 841 | 839 | => unreachable, |
| 842 | 840 | |
| 843 | 841 | .optional, |
| ... | ... | @@ -1047,7 +1045,7 @@ pub const Type = struct { |
| 1047 | 1045 | while (true) { |
| 1048 | 1046 | const t = ty.tag(); |
| 1049 | 1047 | switch (t) { |
| 1050 | | .empty_struct, .empty_struct_literal => return writer.writeAll("struct {}"), |
| 1048 | .empty_struct => return writer.writeAll("struct {}"), |
| 1051 | 1049 | |
| 1052 | 1050 | .@"struct" => { |
| 1053 | 1051 | const struct_obj = ty.castTag(.@"struct").?.data; |
| ... | ... | @@ -1266,327 +1264,328 @@ pub const Type = struct { |
| 1266 | 1264 | |
| 1267 | 1265 | /// Prints a name suitable for `@typeName`. |
| 1268 | 1266 | pub fn print(ty: Type, writer: anytype, mod: *Module) @TypeOf(writer).Error!void { |
| 1269 | | if (ty.ip_index != .none) switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 1270 | | .int_type => |int_type| { |
| 1271 | | const sign_char: u8 = switch (int_type.signedness) { |
| 1272 | | .signed => 'i', |
| 1273 | | .unsigned => 'u', |
| 1274 | | }; |
| 1275 | | return writer.print("{c}{d}", .{ sign_char, int_type.bits }); |
| 1276 | | }, |
| 1277 | | .ptr_type => { |
| 1278 | | const info = ty.ptrInfo(mod); |
| 1279 | | |
| 1280 | | if (info.sentinel) |s| switch (info.size) { |
| 1281 | | .One, .C => unreachable, |
| 1282 | | .Many => try writer.print("[*:{}]", .{s.fmtValue(info.pointee_type, mod)}), |
| 1283 | | .Slice => try writer.print("[:{}]", .{s.fmtValue(info.pointee_type, mod)}), |
| 1284 | | } else switch (info.size) { |
| 1285 | | .One => try writer.writeAll("*"), |
| 1286 | | .Many => try writer.writeAll("[*]"), |
| 1287 | | .C => try writer.writeAll("[*c]"), |
| 1288 | | .Slice => try writer.writeAll("[]"), |
| 1289 | | } |
| 1290 | | if (info.@"align" != 0 or info.host_size != 0 or info.vector_index != .none) { |
| 1291 | | if (info.@"align" != 0) { |
| 1292 | | try writer.print("align({d}", .{info.@"align"}); |
| 1293 | | } else { |
| 1294 | | const alignment = info.pointee_type.abiAlignment(mod); |
| 1295 | | try writer.print("align({d}", .{alignment}); |
| 1296 | | } |
| 1297 | | |
| 1298 | | if (info.bit_offset != 0 or info.host_size != 0) { |
| 1299 | | try writer.print(":{d}:{d}", .{ info.bit_offset, info.host_size }); |
| 1300 | | } |
| 1301 | | if (info.vector_index == .runtime) { |
| 1302 | | try writer.writeAll(":?"); |
| 1303 | | } else if (info.vector_index != .none) { |
| 1304 | | try writer.print(":{d}", .{@enumToInt(info.vector_index)}); |
| 1305 | | } |
| 1306 | | try writer.writeAll(") "); |
| 1307 | | } |
| 1308 | | if (info.@"addrspace" != .generic) { |
| 1309 | | try writer.print("addrspace(.{s}) ", .{@tagName(info.@"addrspace")}); |
| 1310 | | } |
| 1311 | | if (!info.mutable) try writer.writeAll("const "); |
| 1312 | | if (info.@"volatile") try writer.writeAll("volatile "); |
| 1313 | | if (info.@"allowzero" and info.size != .C) try writer.writeAll("allowzero "); |
| 1314 | | |
| 1315 | | try print(info.pointee_type, writer, mod); |
| 1316 | | return; |
| 1317 | | }, |
| 1318 | | .array_type => |array_type| { |
| 1319 | | if (array_type.sentinel == .none) { |
| 1320 | | try writer.print("[{d}]", .{array_type.len}); |
| 1321 | | try print(array_type.child.toType(), writer, mod); |
| 1322 | | } else { |
| 1323 | | try writer.print("[{d}:{}]", .{ |
| 1324 | | array_type.len, |
| 1325 | | array_type.sentinel.toValue().fmtValue(array_type.child.toType(), mod), |
| 1326 | | }); |
| 1327 | | try print(array_type.child.toType(), writer, mod); |
| 1328 | | } |
| 1329 | | return; |
| 1330 | | }, |
| 1331 | | .vector_type => |vector_type| { |
| 1332 | | try writer.print("@Vector({d}, ", .{vector_type.len}); |
| 1333 | | try print(vector_type.child.toType(), writer, mod); |
| 1334 | | try writer.writeAll(")"); |
| 1335 | | return; |
| 1336 | | }, |
| 1337 | | .opt_type => |child| { |
| 1338 | | try writer.writeByte('?'); |
| 1339 | | try print(child.toType(), writer, mod); |
| 1340 | | return; |
| 1341 | | }, |
| 1342 | | .error_union_type => |error_union_type| { |
| 1343 | | try print(error_union_type.error_set_type.toType(), writer, mod); |
| 1344 | | try writer.writeByte('!'); |
| 1345 | | try print(error_union_type.payload_type.toType(), writer, mod); |
| 1346 | | return; |
| 1347 | | }, |
| 1348 | | .simple_type => |s| return writer.writeAll(@tagName(s)), |
| 1349 | | .struct_type => @panic("TODO"), |
| 1350 | | .union_type => @panic("TODO"), |
| 1351 | | .simple_value => unreachable, |
| 1352 | | .extern_func => unreachable, |
| 1353 | | .int => unreachable, |
| 1354 | | .enum_tag => unreachable, |
| 1355 | | }; |
| 1356 | | const t = ty.tag(); |
| 1357 | | switch (t) { |
| 1358 | | .inferred_alloc_const => unreachable, |
| 1359 | | .inferred_alloc_mut => unreachable, |
| 1267 | switch (ty.ip_index) { |
| 1268 | .empty_struct_type => try writer.writeAll("@TypeOf(.{})"), |
| 1360 | 1269 | |
| 1361 | | .empty_struct_literal => try writer.writeAll("@TypeOf(.{})"), |
| 1270 | .none => switch (ty.tag()) { |
| 1271 | .inferred_alloc_const => unreachable, |
| 1272 | .inferred_alloc_mut => unreachable, |
| 1362 | 1273 | |
| 1363 | | .empty_struct => { |
| 1364 | | const namespace = ty.castTag(.empty_struct).?.data; |
| 1365 | | try namespace.renderFullyQualifiedName(mod, "", writer); |
| 1366 | | }, |
| 1274 | .empty_struct => { |
| 1275 | const namespace = ty.castTag(.empty_struct).?.data; |
| 1276 | try namespace.renderFullyQualifiedName(mod, "", writer); |
| 1277 | }, |
| 1367 | 1278 | |
| 1368 | | .@"struct" => { |
| 1369 | | const struct_obj = ty.castTag(.@"struct").?.data; |
| 1370 | | const decl = mod.declPtr(struct_obj.owner_decl); |
| 1371 | | try decl.renderFullyQualifiedName(mod, writer); |
| 1372 | | }, |
| 1373 | | .@"union", .union_safety_tagged, .union_tagged => { |
| 1374 | | const union_obj = ty.cast(Payload.Union).?.data; |
| 1375 | | const decl = mod.declPtr(union_obj.owner_decl); |
| 1376 | | try decl.renderFullyQualifiedName(mod, writer); |
| 1377 | | }, |
| 1378 | | .enum_full, .enum_nonexhaustive => { |
| 1379 | | const enum_full = ty.cast(Payload.EnumFull).?.data; |
| 1380 | | const decl = mod.declPtr(enum_full.owner_decl); |
| 1381 | | try decl.renderFullyQualifiedName(mod, writer); |
| 1382 | | }, |
| 1383 | | .enum_simple => { |
| 1384 | | const enum_simple = ty.castTag(.enum_simple).?.data; |
| 1385 | | const decl = mod.declPtr(enum_simple.owner_decl); |
| 1386 | | try decl.renderFullyQualifiedName(mod, writer); |
| 1387 | | }, |
| 1388 | | .enum_numbered => { |
| 1389 | | const enum_numbered = ty.castTag(.enum_numbered).?.data; |
| 1390 | | const decl = mod.declPtr(enum_numbered.owner_decl); |
| 1391 | | try decl.renderFullyQualifiedName(mod, writer); |
| 1392 | | }, |
| 1393 | | .@"opaque" => { |
| 1394 | | const opaque_obj = ty.cast(Payload.Opaque).?.data; |
| 1395 | | const decl = mod.declPtr(opaque_obj.owner_decl); |
| 1396 | | try decl.renderFullyQualifiedName(mod, writer); |
| 1397 | | }, |
| 1279 | .@"struct" => { |
| 1280 | const struct_obj = ty.castTag(.@"struct").?.data; |
| 1281 | const decl = mod.declPtr(struct_obj.owner_decl); |
| 1282 | try decl.renderFullyQualifiedName(mod, writer); |
| 1283 | }, |
| 1284 | .@"union", .union_safety_tagged, .union_tagged => { |
| 1285 | const union_obj = ty.cast(Payload.Union).?.data; |
| 1286 | const decl = mod.declPtr(union_obj.owner_decl); |
| 1287 | try decl.renderFullyQualifiedName(mod, writer); |
| 1288 | }, |
| 1289 | .enum_full, .enum_nonexhaustive => { |
| 1290 | const enum_full = ty.cast(Payload.EnumFull).?.data; |
| 1291 | const decl = mod.declPtr(enum_full.owner_decl); |
| 1292 | try decl.renderFullyQualifiedName(mod, writer); |
| 1293 | }, |
| 1294 | .enum_simple => { |
| 1295 | const enum_simple = ty.castTag(.enum_simple).?.data; |
| 1296 | const decl = mod.declPtr(enum_simple.owner_decl); |
| 1297 | try decl.renderFullyQualifiedName(mod, writer); |
| 1298 | }, |
| 1299 | .enum_numbered => { |
| 1300 | const enum_numbered = ty.castTag(.enum_numbered).?.data; |
| 1301 | const decl = mod.declPtr(enum_numbered.owner_decl); |
| 1302 | try decl.renderFullyQualifiedName(mod, writer); |
| 1303 | }, |
| 1304 | .@"opaque" => { |
| 1305 | const opaque_obj = ty.cast(Payload.Opaque).?.data; |
| 1306 | const decl = mod.declPtr(opaque_obj.owner_decl); |
| 1307 | try decl.renderFullyQualifiedName(mod, writer); |
| 1308 | }, |
| 1398 | 1309 | |
| 1399 | | .error_set_inferred => { |
| 1400 | | const func = ty.castTag(.error_set_inferred).?.data.func; |
| 1310 | .error_set_inferred => { |
| 1311 | const func = ty.castTag(.error_set_inferred).?.data.func; |
| 1401 | 1312 | |
| 1402 | | try writer.writeAll("@typeInfo(@typeInfo(@TypeOf("); |
| 1403 | | const owner_decl = mod.declPtr(func.owner_decl); |
| 1404 | | try owner_decl.renderFullyQualifiedName(mod, writer); |
| 1405 | | try writer.writeAll(")).Fn.return_type.?).ErrorUnion.error_set"); |
| 1406 | | }, |
| 1313 | try writer.writeAll("@typeInfo(@typeInfo(@TypeOf("); |
| 1314 | const owner_decl = mod.declPtr(func.owner_decl); |
| 1315 | try owner_decl.renderFullyQualifiedName(mod, writer); |
| 1316 | try writer.writeAll(")).Fn.return_type.?).ErrorUnion.error_set"); |
| 1317 | }, |
| 1407 | 1318 | |
| 1408 | | .function => { |
| 1409 | | const fn_info = ty.fnInfo(); |
| 1410 | | if (fn_info.is_noinline) { |
| 1411 | | try writer.writeAll("noinline "); |
| 1412 | | } |
| 1413 | | try writer.writeAll("fn("); |
| 1414 | | for (fn_info.param_types, 0..) |param_ty, i| { |
| 1415 | | if (i != 0) try writer.writeAll(", "); |
| 1416 | | if (fn_info.paramIsComptime(i)) { |
| 1417 | | try writer.writeAll("comptime "); |
| 1319 | .function => { |
| 1320 | const fn_info = ty.fnInfo(); |
| 1321 | if (fn_info.is_noinline) { |
| 1322 | try writer.writeAll("noinline "); |
| 1418 | 1323 | } |
| 1419 | | if (std.math.cast(u5, i)) |index| if (@truncate(u1, fn_info.noalias_bits >> index) != 0) { |
| 1420 | | try writer.writeAll("noalias "); |
| 1421 | | }; |
| 1422 | | if (param_ty.isGenericPoison()) { |
| 1423 | | try writer.writeAll("anytype"); |
| 1424 | | } else { |
| 1425 | | try print(param_ty, writer, mod); |
| 1324 | try writer.writeAll("fn("); |
| 1325 | for (fn_info.param_types, 0..) |param_ty, i| { |
| 1326 | if (i != 0) try writer.writeAll(", "); |
| 1327 | if (fn_info.paramIsComptime(i)) { |
| 1328 | try writer.writeAll("comptime "); |
| 1329 | } |
| 1330 | if (std.math.cast(u5, i)) |index| if (@truncate(u1, fn_info.noalias_bits >> index) != 0) { |
| 1331 | try writer.writeAll("noalias "); |
| 1332 | }; |
| 1333 | if (param_ty.isGenericPoison()) { |
| 1334 | try writer.writeAll("anytype"); |
| 1335 | } else { |
| 1336 | try print(param_ty, writer, mod); |
| 1337 | } |
| 1426 | 1338 | } |
| 1427 | | } |
| 1428 | | if (fn_info.is_var_args) { |
| 1429 | | if (fn_info.param_types.len != 0) { |
| 1430 | | try writer.writeAll(", "); |
| 1339 | if (fn_info.is_var_args) { |
| 1340 | if (fn_info.param_types.len != 0) { |
| 1341 | try writer.writeAll(", "); |
| 1342 | } |
| 1343 | try writer.writeAll("..."); |
| 1431 | 1344 | } |
| 1432 | | try writer.writeAll("..."); |
| 1433 | | } |
| 1434 | | try writer.writeAll(") "); |
| 1435 | | if (fn_info.alignment != 0) { |
| 1436 | | try writer.print("align({d}) ", .{fn_info.alignment}); |
| 1437 | | } |
| 1438 | | if (fn_info.cc != .Unspecified) { |
| 1439 | | try writer.writeAll("callconv(."); |
| 1440 | | try writer.writeAll(@tagName(fn_info.cc)); |
| 1441 | 1345 | try writer.writeAll(") "); |
| 1442 | | } |
| 1443 | | if (fn_info.return_type.isGenericPoison()) { |
| 1444 | | try writer.writeAll("anytype"); |
| 1445 | | } else { |
| 1446 | | try print(fn_info.return_type, writer, mod); |
| 1447 | | } |
| 1448 | | }, |
| 1346 | if (fn_info.alignment != 0) { |
| 1347 | try writer.print("align({d}) ", .{fn_info.alignment}); |
| 1348 | } |
| 1349 | if (fn_info.cc != .Unspecified) { |
| 1350 | try writer.writeAll("callconv(."); |
| 1351 | try writer.writeAll(@tagName(fn_info.cc)); |
| 1352 | try writer.writeAll(") "); |
| 1353 | } |
| 1354 | if (fn_info.return_type.isGenericPoison()) { |
| 1355 | try writer.writeAll("anytype"); |
| 1356 | } else { |
| 1357 | try print(fn_info.return_type, writer, mod); |
| 1358 | } |
| 1359 | }, |
| 1449 | 1360 | |
| 1450 | | .error_union => { |
| 1451 | | const error_union = ty.castTag(.error_union).?.data; |
| 1452 | | try print(error_union.error_set, writer, mod); |
| 1453 | | try writer.writeAll("!"); |
| 1454 | | try print(error_union.payload, writer, mod); |
| 1455 | | }, |
| 1361 | .error_union => { |
| 1362 | const error_union = ty.castTag(.error_union).?.data; |
| 1363 | try print(error_union.error_set, writer, mod); |
| 1364 | try writer.writeAll("!"); |
| 1365 | try print(error_union.payload, writer, mod); |
| 1366 | }, |
| 1456 | 1367 | |
| 1457 | | .array => { |
| 1458 | | const payload = ty.castTag(.array).?.data; |
| 1459 | | try writer.print("[{d}]", .{payload.len}); |
| 1460 | | try print(payload.elem_type, writer, mod); |
| 1461 | | }, |
| 1462 | | .array_sentinel => { |
| 1463 | | const payload = ty.castTag(.array_sentinel).?.data; |
| 1464 | | try writer.print("[{d}:{}]", .{ |
| 1465 | | payload.len, |
| 1466 | | payload.sentinel.fmtValue(payload.elem_type, mod), |
| 1467 | | }); |
| 1468 | | try print(payload.elem_type, writer, mod); |
| 1469 | | }, |
| 1470 | | .tuple => { |
| 1471 | | const tuple = ty.castTag(.tuple).?.data; |
| 1368 | .array => { |
| 1369 | const payload = ty.castTag(.array).?.data; |
| 1370 | try writer.print("[{d}]", .{payload.len}); |
| 1371 | try print(payload.elem_type, writer, mod); |
| 1372 | }, |
| 1373 | .array_sentinel => { |
| 1374 | const payload = ty.castTag(.array_sentinel).?.data; |
| 1375 | try writer.print("[{d}:{}]", .{ |
| 1376 | payload.len, |
| 1377 | payload.sentinel.fmtValue(payload.elem_type, mod), |
| 1378 | }); |
| 1379 | try print(payload.elem_type, writer, mod); |
| 1380 | }, |
| 1381 | .tuple => { |
| 1382 | const tuple = ty.castTag(.tuple).?.data; |
| 1472 | 1383 | |
| 1473 | | try writer.writeAll("tuple{"); |
| 1474 | | for (tuple.types, 0..) |field_ty, i| { |
| 1475 | | if (i != 0) try writer.writeAll(", "); |
| 1476 | | const val = tuple.values[i]; |
| 1477 | | if (val.ip_index != .unreachable_value) { |
| 1478 | | try writer.writeAll("comptime "); |
| 1479 | | } |
| 1480 | | try print(field_ty, writer, mod); |
| 1481 | | if (val.ip_index != .unreachable_value) { |
| 1482 | | try writer.print(" = {}", .{val.fmtValue(field_ty, mod)}); |
| 1384 | try writer.writeAll("tuple{"); |
| 1385 | for (tuple.types, 0..) |field_ty, i| { |
| 1386 | if (i != 0) try writer.writeAll(", "); |
| 1387 | const val = tuple.values[i]; |
| 1388 | if (val.ip_index != .unreachable_value) { |
| 1389 | try writer.writeAll("comptime "); |
| 1390 | } |
| 1391 | try print(field_ty, writer, mod); |
| 1392 | if (val.ip_index != .unreachable_value) { |
| 1393 | try writer.print(" = {}", .{val.fmtValue(field_ty, mod)}); |
| 1394 | } |
| 1483 | 1395 | } |
| 1484 | | } |
| 1485 | | try writer.writeAll("}"); |
| 1486 | | }, |
| 1487 | | .anon_struct => { |
| 1488 | | const anon_struct = ty.castTag(.anon_struct).?.data; |
| 1396 | try writer.writeAll("}"); |
| 1397 | }, |
| 1398 | .anon_struct => { |
| 1399 | const anon_struct = ty.castTag(.anon_struct).?.data; |
| 1489 | 1400 | |
| 1490 | | try writer.writeAll("struct{"); |
| 1491 | | for (anon_struct.types, 0..) |field_ty, i| { |
| 1492 | | if (i != 0) try writer.writeAll(", "); |
| 1493 | | const val = anon_struct.values[i]; |
| 1494 | | if (val.ip_index != .unreachable_value) { |
| 1495 | | try writer.writeAll("comptime "); |
| 1496 | | } |
| 1497 | | try writer.writeAll(anon_struct.names[i]); |
| 1498 | | try writer.writeAll(": "); |
| 1401 | try writer.writeAll("struct{"); |
| 1402 | for (anon_struct.types, 0..) |field_ty, i| { |
| 1403 | if (i != 0) try writer.writeAll(", "); |
| 1404 | const val = anon_struct.values[i]; |
| 1405 | if (val.ip_index != .unreachable_value) { |
| 1406 | try writer.writeAll("comptime "); |
| 1407 | } |
| 1408 | try writer.writeAll(anon_struct.names[i]); |
| 1409 | try writer.writeAll(": "); |
| 1499 | 1410 | |
| 1500 | | try print(field_ty, writer, mod); |
| 1411 | try print(field_ty, writer, mod); |
| 1501 | 1412 | |
| 1502 | | if (val.ip_index != .unreachable_value) { |
| 1503 | | try writer.print(" = {}", .{val.fmtValue(field_ty, mod)}); |
| 1413 | if (val.ip_index != .unreachable_value) { |
| 1414 | try writer.print(" = {}", .{val.fmtValue(field_ty, mod)}); |
| 1415 | } |
| 1504 | 1416 | } |
| 1505 | | } |
| 1506 | | try writer.writeAll("}"); |
| 1507 | | }, |
| 1417 | try writer.writeAll("}"); |
| 1418 | }, |
| 1508 | 1419 | |
| 1509 | | .pointer => { |
| 1510 | | const info = ty.ptrInfo(mod); |
| 1420 | .pointer => { |
| 1421 | const info = ty.ptrInfo(mod); |
| 1511 | 1422 | |
| 1512 | | if (info.sentinel) |s| switch (info.size) { |
| 1513 | | .One, .C => unreachable, |
| 1514 | | .Many => try writer.print("[*:{}]", .{s.fmtValue(info.pointee_type, mod)}), |
| 1515 | | .Slice => try writer.print("[:{}]", .{s.fmtValue(info.pointee_type, mod)}), |
| 1516 | | } else switch (info.size) { |
| 1517 | | .One => try writer.writeAll("*"), |
| 1518 | | .Many => try writer.writeAll("[*]"), |
| 1519 | | .C => try writer.writeAll("[*c]"), |
| 1520 | | .Slice => try writer.writeAll("[]"), |
| 1521 | | } |
| 1522 | | if (info.@"align" != 0 or info.host_size != 0 or info.vector_index != .none) { |
| 1523 | | if (info.@"align" != 0) { |
| 1524 | | try writer.print("align({d}", .{info.@"align"}); |
| 1525 | | } else { |
| 1526 | | const alignment = info.pointee_type.abiAlignment(mod); |
| 1527 | | try writer.print("align({d}", .{alignment}); |
| 1423 | if (info.sentinel) |s| switch (info.size) { |
| 1424 | .One, .C => unreachable, |
| 1425 | .Many => try writer.print("[*:{}]", .{s.fmtValue(info.pointee_type, mod)}), |
| 1426 | .Slice => try writer.print("[:{}]", .{s.fmtValue(info.pointee_type, mod)}), |
| 1427 | } else switch (info.size) { |
| 1428 | .One => try writer.writeAll("*"), |
| 1429 | .Many => try writer.writeAll("[*]"), |
| 1430 | .C => try writer.writeAll("[*c]"), |
| 1431 | .Slice => try writer.writeAll("[]"), |
| 1528 | 1432 | } |
| 1433 | if (info.@"align" != 0 or info.host_size != 0 or info.vector_index != .none) { |
| 1434 | if (info.@"align" != 0) { |
| 1435 | try writer.print("align({d}", .{info.@"align"}); |
| 1436 | } else { |
| 1437 | const alignment = info.pointee_type.abiAlignment(mod); |
| 1438 | try writer.print("align({d}", .{alignment}); |
| 1439 | } |
| 1529 | 1440 | |
| 1530 | | if (info.bit_offset != 0 or info.host_size != 0) { |
| 1531 | | try writer.print(":{d}:{d}", .{ info.bit_offset, info.host_size }); |
| 1441 | if (info.bit_offset != 0 or info.host_size != 0) { |
| 1442 | try writer.print(":{d}:{d}", .{ info.bit_offset, info.host_size }); |
| 1443 | } |
| 1444 | if (info.vector_index == .runtime) { |
| 1445 | try writer.writeAll(":?"); |
| 1446 | } else if (info.vector_index != .none) { |
| 1447 | try writer.print(":{d}", .{@enumToInt(info.vector_index)}); |
| 1448 | } |
| 1449 | try writer.writeAll(") "); |
| 1532 | 1450 | } |
| 1533 | | if (info.vector_index == .runtime) { |
| 1534 | | try writer.writeAll(":?"); |
| 1535 | | } else if (info.vector_index != .none) { |
| 1536 | | try writer.print(":{d}", .{@enumToInt(info.vector_index)}); |
| 1451 | if (info.@"addrspace" != .generic) { |
| 1452 | try writer.print("addrspace(.{s}) ", .{@tagName(info.@"addrspace")}); |
| 1537 | 1453 | } |
| 1538 | | try writer.writeAll(") "); |
| 1539 | | } |
| 1540 | | if (info.@"addrspace" != .generic) { |
| 1541 | | try writer.print("addrspace(.{s}) ", .{@tagName(info.@"addrspace")}); |
| 1542 | | } |
| 1543 | | if (!info.mutable) try writer.writeAll("const "); |
| 1544 | | if (info.@"volatile") try writer.writeAll("volatile "); |
| 1545 | | if (info.@"allowzero" and info.size != .C) try writer.writeAll("allowzero "); |
| 1546 | | |
| 1547 | | try print(info.pointee_type, writer, mod); |
| 1548 | | }, |
| 1454 | if (!info.mutable) try writer.writeAll("const "); |
| 1455 | if (info.@"volatile") try writer.writeAll("volatile "); |
| 1456 | if (info.@"allowzero" and info.size != .C) try writer.writeAll("allowzero "); |
| 1549 | 1457 | |
| 1550 | | .optional => { |
| 1551 | | const child_type = ty.castTag(.optional).?.data; |
| 1552 | | try writer.writeByte('?'); |
| 1553 | | try print(child_type, writer, mod); |
| 1554 | | }, |
| 1555 | | .anyframe_T => { |
| 1556 | | const return_type = ty.castTag(.anyframe_T).?.data; |
| 1557 | | try writer.print("anyframe->", .{}); |
| 1558 | | try print(return_type, writer, mod); |
| 1559 | | }, |
| 1560 | | .error_set => { |
| 1561 | | const names = ty.castTag(.error_set).?.data.names.keys(); |
| 1562 | | try writer.writeAll("error{"); |
| 1563 | | for (names, 0..) |name, i| { |
| 1564 | | if (i != 0) try writer.writeByte(','); |
| 1565 | | try writer.writeAll(name); |
| 1566 | | } |
| 1567 | | try writer.writeAll("}"); |
| 1568 | | }, |
| 1569 | | .error_set_single => { |
| 1570 | | const name = ty.castTag(.error_set_single).?.data; |
| 1571 | | return writer.print("error{{{s}}}", .{name}); |
| 1572 | | }, |
| 1573 | | .error_set_merged => { |
| 1574 | | const names = ty.castTag(.error_set_merged).?.data.keys(); |
| 1575 | | try writer.writeAll("error{"); |
| 1576 | | for (names, 0..) |name, i| { |
| 1577 | | if (i != 0) try writer.writeByte(','); |
| 1578 | | try writer.writeAll(name); |
| 1579 | | } |
| 1580 | | try writer.writeAll("}"); |
| 1581 | | }, |
| 1582 | | } |
| 1583 | | } |
| 1458 | try print(info.pointee_type, writer, mod); |
| 1459 | }, |
| 1584 | 1460 | |
| 1585 | | pub fn toValue(self: Type, allocator: Allocator) Allocator.Error!Value { |
| 1586 | | if (self.ip_index != .none) return self.ip_index.toValue(); |
| 1587 | | switch (self.tag()) { |
| 1588 | | .inferred_alloc_const => unreachable, |
| 1589 | | .inferred_alloc_mut => unreachable, |
| 1461 | .optional => { |
| 1462 | const child_type = ty.castTag(.optional).?.data; |
| 1463 | try writer.writeByte('?'); |
| 1464 | try print(child_type, writer, mod); |
| 1465 | }, |
| 1466 | .anyframe_T => { |
| 1467 | const return_type = ty.castTag(.anyframe_T).?.data; |
| 1468 | try writer.print("anyframe->", .{}); |
| 1469 | try print(return_type, writer, mod); |
| 1470 | }, |
| 1471 | .error_set => { |
| 1472 | const names = ty.castTag(.error_set).?.data.names.keys(); |
| 1473 | try writer.writeAll("error{"); |
| 1474 | for (names, 0..) |name, i| { |
| 1475 | if (i != 0) try writer.writeByte(','); |
| 1476 | try writer.writeAll(name); |
| 1477 | } |
| 1478 | try writer.writeAll("}"); |
| 1479 | }, |
| 1480 | .error_set_single => { |
| 1481 | const name = ty.castTag(.error_set_single).?.data; |
| 1482 | return writer.print("error{{{s}}}", .{name}); |
| 1483 | }, |
| 1484 | .error_set_merged => { |
| 1485 | const names = ty.castTag(.error_set_merged).?.data.keys(); |
| 1486 | try writer.writeAll("error{"); |
| 1487 | for (names, 0..) |name, i| { |
| 1488 | if (i != 0) try writer.writeByte(','); |
| 1489 | try writer.writeAll(name); |
| 1490 | } |
| 1491 | try writer.writeAll("}"); |
| 1492 | }, |
| 1493 | }, |
| 1494 | else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 1495 | .int_type => |int_type| { |
| 1496 | const sign_char: u8 = switch (int_type.signedness) { |
| 1497 | .signed => 'i', |
| 1498 | .unsigned => 'u', |
| 1499 | }; |
| 1500 | return writer.print("{c}{d}", .{ sign_char, int_type.bits }); |
| 1501 | }, |
| 1502 | .ptr_type => { |
| 1503 | const info = ty.ptrInfo(mod); |
| 1504 | |
| 1505 | if (info.sentinel) |s| switch (info.size) { |
| 1506 | .One, .C => unreachable, |
| 1507 | .Many => try writer.print("[*:{}]", .{s.fmtValue(info.pointee_type, mod)}), |
| 1508 | .Slice => try writer.print("[:{}]", .{s.fmtValue(info.pointee_type, mod)}), |
| 1509 | } else switch (info.size) { |
| 1510 | .One => try writer.writeAll("*"), |
| 1511 | .Many => try writer.writeAll("[*]"), |
| 1512 | .C => try writer.writeAll("[*c]"), |
| 1513 | .Slice => try writer.writeAll("[]"), |
| 1514 | } |
| 1515 | if (info.@"align" != 0 or info.host_size != 0 or info.vector_index != .none) { |
| 1516 | if (info.@"align" != 0) { |
| 1517 | try writer.print("align({d}", .{info.@"align"}); |
| 1518 | } else { |
| 1519 | const alignment = info.pointee_type.abiAlignment(mod); |
| 1520 | try writer.print("align({d}", .{alignment}); |
| 1521 | } |
| 1522 | |
| 1523 | if (info.bit_offset != 0 or info.host_size != 0) { |
| 1524 | try writer.print(":{d}:{d}", .{ info.bit_offset, info.host_size }); |
| 1525 | } |
| 1526 | if (info.vector_index == .runtime) { |
| 1527 | try writer.writeAll(":?"); |
| 1528 | } else if (info.vector_index != .none) { |
| 1529 | try writer.print(":{d}", .{@enumToInt(info.vector_index)}); |
| 1530 | } |
| 1531 | try writer.writeAll(") "); |
| 1532 | } |
| 1533 | if (info.@"addrspace" != .generic) { |
| 1534 | try writer.print("addrspace(.{s}) ", .{@tagName(info.@"addrspace")}); |
| 1535 | } |
| 1536 | if (!info.mutable) try writer.writeAll("const "); |
| 1537 | if (info.@"volatile") try writer.writeAll("volatile "); |
| 1538 | if (info.@"allowzero" and info.size != .C) try writer.writeAll("allowzero "); |
| 1539 | |
| 1540 | try print(info.pointee_type, writer, mod); |
| 1541 | return; |
| 1542 | }, |
| 1543 | .array_type => |array_type| { |
| 1544 | if (array_type.sentinel == .none) { |
| 1545 | try writer.print("[{d}]", .{array_type.len}); |
| 1546 | try print(array_type.child.toType(), writer, mod); |
| 1547 | } else { |
| 1548 | try writer.print("[{d}:{}]", .{ |
| 1549 | array_type.len, |
| 1550 | array_type.sentinel.toValue().fmtValue(array_type.child.toType(), mod), |
| 1551 | }); |
| 1552 | try print(array_type.child.toType(), writer, mod); |
| 1553 | } |
| 1554 | return; |
| 1555 | }, |
| 1556 | .vector_type => |vector_type| { |
| 1557 | try writer.print("@Vector({d}, ", .{vector_type.len}); |
| 1558 | try print(vector_type.child.toType(), writer, mod); |
| 1559 | try writer.writeAll(")"); |
| 1560 | return; |
| 1561 | }, |
| 1562 | .opt_type => |child| { |
| 1563 | try writer.writeByte('?'); |
| 1564 | try print(child.toType(), writer, mod); |
| 1565 | return; |
| 1566 | }, |
| 1567 | .error_union_type => |error_union_type| { |
| 1568 | try print(error_union_type.error_set_type.toType(), writer, mod); |
| 1569 | try writer.writeByte('!'); |
| 1570 | try print(error_union_type.payload_type.toType(), writer, mod); |
| 1571 | return; |
| 1572 | }, |
| 1573 | .simple_type => |s| return writer.writeAll(@tagName(s)), |
| 1574 | .struct_type => @panic("TODO"), |
| 1575 | .union_type => @panic("TODO"), |
| 1576 | .simple_value => unreachable, |
| 1577 | .extern_func => unreachable, |
| 1578 | .int => unreachable, |
| 1579 | .enum_tag => unreachable, |
| 1580 | }, |
| 1581 | } |
| 1582 | } |
| 1583 | |
| 1584 | pub fn toValue(self: Type, allocator: Allocator) Allocator.Error!Value { |
| 1585 | if (self.ip_index != .none) return self.ip_index.toValue(); |
| 1586 | switch (self.tag()) { |
| 1587 | .inferred_alloc_const => unreachable, |
| 1588 | .inferred_alloc_mut => unreachable, |
| 1590 | 1589 | else => return Value.Tag.ty.create(allocator, self), |
| 1591 | 1590 | } |
| 1592 | 1591 | } |
| ... | ... | @@ -1610,240 +1609,244 @@ pub const Type = struct { |
| 1610 | 1609 | ignore_comptime_only: bool, |
| 1611 | 1610 | strat: AbiAlignmentAdvancedStrat, |
| 1612 | 1611 | ) RuntimeBitsError!bool { |
| 1613 | | if (ty.ip_index != .none) switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 1614 | | .int_type => |int_type| return int_type.bits != 0, |
| 1615 | | .ptr_type => |ptr_type| { |
| 1612 | switch (ty.ip_index) { |
| 1613 | // False because it is a comptime-only type. |
| 1614 | .empty_struct_type => return false, |
| 1615 | |
| 1616 | .none => switch (ty.tag()) { |
| 1617 | .error_set_inferred, |
| 1618 | |
| 1619 | .@"opaque", |
| 1620 | .error_set_single, |
| 1621 | .error_union, |
| 1622 | .error_set, |
| 1623 | .error_set_merged, |
| 1624 | => return true, |
| 1625 | |
| 1616 | 1626 | // Pointers to zero-bit types still have a runtime address; however, pointers |
| 1617 | 1627 | // to comptime-only types do not, with the exception of function pointers. |
| 1618 | | if (ignore_comptime_only) return true; |
| 1619 | | const child_ty = ptr_type.elem_type.toType(); |
| 1620 | | if (child_ty.zigTypeTag(mod) == .Fn) return !child_ty.fnInfo().is_generic; |
| 1621 | | if (strat == .sema) return !(try strat.sema.typeRequiresComptime(ty)); |
| 1622 | | return !comptimeOnly(ty, mod); |
| 1623 | | }, |
| 1624 | | .array_type => |array_type| { |
| 1625 | | if (array_type.sentinel != .none) { |
| 1626 | | return array_type.child.toType().hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat); |
| 1627 | | } else { |
| 1628 | | return array_type.len > 0 and |
| 1629 | | try array_type.child.toType().hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat); |
| 1630 | | } |
| 1631 | | }, |
| 1632 | | .vector_type => |vector_type| { |
| 1633 | | return vector_type.len > 0 and |
| 1634 | | try vector_type.child.toType().hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat); |
| 1635 | | }, |
| 1636 | | .opt_type => |child| { |
| 1637 | | const child_ty = child.toType(); |
| 1638 | | if (child_ty.isNoReturn()) { |
| 1639 | | // Then the optional is comptime-known to be null. |
| 1640 | | return false; |
| 1641 | | } |
| 1642 | | if (ignore_comptime_only) { |
| 1643 | | return true; |
| 1644 | | } else if (strat == .sema) { |
| 1645 | | return !(try strat.sema.typeRequiresComptime(child_ty)); |
| 1646 | | } else { |
| 1647 | | return !comptimeOnly(child_ty, mod); |
| 1648 | | } |
| 1649 | | }, |
| 1650 | | .error_union_type => @panic("TODO"), |
| 1651 | | .simple_type => |t| return switch (t) { |
| 1652 | | .f16, |
| 1653 | | .f32, |
| 1654 | | .f64, |
| 1655 | | .f80, |
| 1656 | | .f128, |
| 1657 | | .usize, |
| 1658 | | .isize, |
| 1659 | | .c_char, |
| 1660 | | .c_short, |
| 1661 | | .c_ushort, |
| 1662 | | .c_int, |
| 1663 | | .c_uint, |
| 1664 | | .c_long, |
| 1665 | | .c_ulong, |
| 1666 | | .c_longlong, |
| 1667 | | .c_ulonglong, |
| 1668 | | .c_longdouble, |
| 1669 | | .bool, |
| 1670 | | .anyerror, |
| 1671 | | .@"anyframe", |
| 1672 | | .anyopaque, |
| 1673 | | .atomic_order, |
| 1674 | | .atomic_rmw_op, |
| 1675 | | .calling_convention, |
| 1676 | | .address_space, |
| 1677 | | .float_mode, |
| 1678 | | .reduce_op, |
| 1679 | | .call_modifier, |
| 1680 | | .prefetch_options, |
| 1681 | | .export_options, |
| 1682 | | .extern_options, |
| 1683 | | => true, |
| 1628 | .anyframe_T, |
| 1629 | .pointer, |
| 1630 | => { |
| 1631 | if (ignore_comptime_only) { |
| 1632 | return true; |
| 1633 | } else if (ty.childType(mod).zigTypeTag(mod) == .Fn) { |
| 1634 | return !ty.childType(mod).fnInfo().is_generic; |
| 1635 | } else if (strat == .sema) { |
| 1636 | return !(try strat.sema.typeRequiresComptime(ty)); |
| 1637 | } else { |
| 1638 | return !comptimeOnly(ty, mod); |
| 1639 | } |
| 1640 | }, |
| 1684 | 1641 | |
| 1685 | 1642 | // These are false because they are comptime-only types. |
| 1686 | | .void, |
| 1687 | | .type, |
| 1688 | | .comptime_int, |
| 1689 | | .comptime_float, |
| 1690 | | .noreturn, |
| 1691 | | .null, |
| 1692 | | .undefined, |
| 1693 | | .enum_literal, |
| 1694 | | .type_info, |
| 1695 | | => false, |
| 1643 | .empty_struct, |
| 1644 | // These are function *bodies*, not pointers. |
| 1645 | // Special exceptions have to be made when emitting functions due to |
| 1646 | // this returning false. |
| 1647 | .function, |
| 1648 | => return false, |
| 1696 | 1649 | |
| 1697 | | .generic_poison => unreachable, |
| 1698 | | .var_args_param => unreachable, |
| 1699 | | }, |
| 1700 | | .struct_type => @panic("TODO"), |
| 1701 | | .union_type => @panic("TODO"), |
| 1702 | | .simple_value => unreachable, |
| 1703 | | .extern_func => unreachable, |
| 1704 | | .int => unreachable, |
| 1705 | | .enum_tag => unreachable, // it's a value, not a type |
| 1706 | | }; |
| 1707 | | switch (ty.tag()) { |
| 1708 | | .error_set_inferred, |
| 1709 | | |
| 1710 | | .@"opaque", |
| 1711 | | .error_set_single, |
| 1712 | | .error_union, |
| 1713 | | .error_set, |
| 1714 | | .error_set_merged, |
| 1715 | | => return true, |
| 1716 | | |
| 1717 | | // Pointers to zero-bit types still have a runtime address; however, pointers |
| 1718 | | // to comptime-only types do not, with the exception of function pointers. |
| 1719 | | .anyframe_T, |
| 1720 | | .pointer, |
| 1721 | | => { |
| 1722 | | if (ignore_comptime_only) { |
| 1723 | | return true; |
| 1724 | | } else if (ty.childType(mod).zigTypeTag(mod) == .Fn) { |
| 1725 | | return !ty.childType(mod).fnInfo().is_generic; |
| 1726 | | } else if (strat == .sema) { |
| 1727 | | return !(try strat.sema.typeRequiresComptime(ty)); |
| 1728 | | } else { |
| 1729 | | return !comptimeOnly(ty, mod); |
| 1730 | | } |
| 1731 | | }, |
| 1650 | .optional => { |
| 1651 | const child_ty = ty.optionalChild(mod); |
| 1652 | if (child_ty.isNoReturn()) { |
| 1653 | // Then the optional is comptime-known to be null. |
| 1654 | return false; |
| 1655 | } |
| 1656 | if (ignore_comptime_only) { |
| 1657 | return true; |
| 1658 | } else if (strat == .sema) { |
| 1659 | return !(try strat.sema.typeRequiresComptime(child_ty)); |
| 1660 | } else { |
| 1661 | return !comptimeOnly(child_ty, mod); |
| 1662 | } |
| 1663 | }, |
| 1732 | 1664 | |
| 1733 | | // These are false because they are comptime-only types. |
| 1734 | | .empty_struct, |
| 1735 | | .empty_struct_literal, |
| 1736 | | // These are function *bodies*, not pointers. |
| 1737 | | // Special exceptions have to be made when emitting functions due to |
| 1738 | | // this returning false. |
| 1739 | | .function, |
| 1740 | | => return false, |
| 1665 | .@"struct" => { |
| 1666 | const struct_obj = ty.castTag(.@"struct").?.data; |
| 1667 | if (struct_obj.status == .field_types_wip) { |
| 1668 | // In this case, we guess that hasRuntimeBits() for this type is true, |
| 1669 | // and then later if our guess was incorrect, we emit a compile error. |
| 1670 | struct_obj.assumed_runtime_bits = true; |
| 1671 | return true; |
| 1672 | } |
| 1673 | switch (strat) { |
| 1674 | .sema => |sema| _ = try sema.resolveTypeFields(ty), |
| 1675 | .eager => assert(struct_obj.haveFieldTypes()), |
| 1676 | .lazy => if (!struct_obj.haveFieldTypes()) return error.NeedLazy, |
| 1677 | } |
| 1678 | for (struct_obj.fields.values()) |field| { |
| 1679 | if (field.is_comptime) continue; |
| 1680 | if (try field.ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat)) |
| 1681 | return true; |
| 1682 | } else { |
| 1683 | return false; |
| 1684 | } |
| 1685 | }, |
| 1741 | 1686 | |
| 1742 | | .optional => { |
| 1743 | | const child_ty = ty.optionalChild(mod); |
| 1744 | | if (child_ty.isNoReturn()) { |
| 1745 | | // Then the optional is comptime-known to be null. |
| 1746 | | return false; |
| 1747 | | } |
| 1748 | | if (ignore_comptime_only) { |
| 1749 | | return true; |
| 1750 | | } else if (strat == .sema) { |
| 1751 | | return !(try strat.sema.typeRequiresComptime(child_ty)); |
| 1752 | | } else { |
| 1753 | | return !comptimeOnly(child_ty, mod); |
| 1754 | | } |
| 1755 | | }, |
| 1687 | .enum_full => { |
| 1688 | const enum_full = ty.castTag(.enum_full).?.data; |
| 1689 | return enum_full.tag_ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat); |
| 1690 | }, |
| 1691 | .enum_simple => { |
| 1692 | const enum_simple = ty.castTag(.enum_simple).?.data; |
| 1693 | return enum_simple.fields.count() >= 2; |
| 1694 | }, |
| 1695 | .enum_numbered, .enum_nonexhaustive => { |
| 1696 | const int_tag_ty = try ty.intTagType(mod); |
| 1697 | return int_tag_ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat); |
| 1698 | }, |
| 1756 | 1699 | |
| 1757 | | .@"struct" => { |
| 1758 | | const struct_obj = ty.castTag(.@"struct").?.data; |
| 1759 | | if (struct_obj.status == .field_types_wip) { |
| 1760 | | // In this case, we guess that hasRuntimeBits() for this type is true, |
| 1761 | | // and then later if our guess was incorrect, we emit a compile error. |
| 1762 | | struct_obj.assumed_runtime_bits = true; |
| 1763 | | return true; |
| 1764 | | } |
| 1765 | | switch (strat) { |
| 1766 | | .sema => |sema| _ = try sema.resolveTypeFields(ty), |
| 1767 | | .eager => assert(struct_obj.haveFieldTypes()), |
| 1768 | | .lazy => if (!struct_obj.haveFieldTypes()) return error.NeedLazy, |
| 1769 | | } |
| 1770 | | for (struct_obj.fields.values()) |field| { |
| 1771 | | if (field.is_comptime) continue; |
| 1772 | | if (try field.ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat)) |
| 1700 | .@"union" => { |
| 1701 | const union_obj = ty.castTag(.@"union").?.data; |
| 1702 | if (union_obj.status == .field_types_wip) { |
| 1703 | // In this case, we guess that hasRuntimeBits() for this type is true, |
| 1704 | // and then later if our guess was incorrect, we emit a compile error. |
| 1705 | union_obj.assumed_runtime_bits = true; |
| 1773 | 1706 | return true; |
| 1774 | | } else { |
| 1775 | | return false; |
| 1776 | | } |
| 1777 | | }, |
| 1707 | } |
| 1708 | switch (strat) { |
| 1709 | .sema => |sema| _ = try sema.resolveTypeFields(ty), |
| 1710 | .eager => assert(union_obj.haveFieldTypes()), |
| 1711 | .lazy => if (!union_obj.haveFieldTypes()) return error.NeedLazy, |
| 1712 | } |
| 1713 | for (union_obj.fields.values()) |value| { |
| 1714 | if (try value.ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat)) |
| 1715 | return true; |
| 1716 | } else { |
| 1717 | return false; |
| 1718 | } |
| 1719 | }, |
| 1720 | .union_safety_tagged, .union_tagged => { |
| 1721 | const union_obj = ty.cast(Payload.Union).?.data; |
| 1722 | if (try union_obj.tag_ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat)) { |
| 1723 | return true; |
| 1724 | } |
| 1778 | 1725 | |
| 1779 | | .enum_full => { |
| 1780 | | const enum_full = ty.castTag(.enum_full).?.data; |
| 1781 | | return enum_full.tag_ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat); |
| 1782 | | }, |
| 1783 | | .enum_simple => { |
| 1784 | | const enum_simple = ty.castTag(.enum_simple).?.data; |
| 1785 | | return enum_simple.fields.count() >= 2; |
| 1786 | | }, |
| 1787 | | .enum_numbered, .enum_nonexhaustive => { |
| 1788 | | const int_tag_ty = try ty.intTagType(mod); |
| 1789 | | return int_tag_ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat); |
| 1790 | | }, |
| 1726 | switch (strat) { |
| 1727 | .sema => |sema| _ = try sema.resolveTypeFields(ty), |
| 1728 | .eager => assert(union_obj.haveFieldTypes()), |
| 1729 | .lazy => if (!union_obj.haveFieldTypes()) return error.NeedLazy, |
| 1730 | } |
| 1731 | for (union_obj.fields.values()) |value| { |
| 1732 | if (try value.ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat)) |
| 1733 | return true; |
| 1734 | } else { |
| 1735 | return false; |
| 1736 | } |
| 1737 | }, |
| 1791 | 1738 | |
| 1792 | | .@"union" => { |
| 1793 | | const union_obj = ty.castTag(.@"union").?.data; |
| 1794 | | if (union_obj.status == .field_types_wip) { |
| 1795 | | // In this case, we guess that hasRuntimeBits() for this type is true, |
| 1796 | | // and then later if our guess was incorrect, we emit a compile error. |
| 1797 | | union_obj.assumed_runtime_bits = true; |
| 1798 | | return true; |
| 1799 | | } |
| 1800 | | switch (strat) { |
| 1801 | | .sema => |sema| _ = try sema.resolveTypeFields(ty), |
| 1802 | | .eager => assert(union_obj.haveFieldTypes()), |
| 1803 | | .lazy => if (!union_obj.haveFieldTypes()) return error.NeedLazy, |
| 1804 | | } |
| 1805 | | for (union_obj.fields.values()) |value| { |
| 1806 | | if (try value.ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat)) |
| 1807 | | return true; |
| 1808 | | } else { |
| 1809 | | return false; |
| 1810 | | } |
| 1811 | | }, |
| 1812 | | .union_safety_tagged, .union_tagged => { |
| 1813 | | const union_obj = ty.cast(Payload.Union).?.data; |
| 1814 | | if (try union_obj.tag_ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat)) { |
| 1815 | | return true; |
| 1816 | | } |
| 1739 | .array => return ty.arrayLen(mod) != 0 and |
| 1740 | try ty.childType(mod).hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat), |
| 1741 | .array_sentinel => return ty.childType(mod).hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat), |
| 1817 | 1742 | |
| 1818 | | switch (strat) { |
| 1819 | | .sema => |sema| _ = try sema.resolveTypeFields(ty), |
| 1820 | | .eager => assert(union_obj.haveFieldTypes()), |
| 1821 | | .lazy => if (!union_obj.haveFieldTypes()) return error.NeedLazy, |
| 1822 | | } |
| 1823 | | for (union_obj.fields.values()) |value| { |
| 1824 | | if (try value.ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat)) |
| 1825 | | return true; |
| 1826 | | } else { |
| 1743 | .tuple, .anon_struct => { |
| 1744 | const tuple = ty.tupleFields(); |
| 1745 | for (tuple.types, 0..) |field_ty, i| { |
| 1746 | const val = tuple.values[i]; |
| 1747 | if (val.ip_index != .unreachable_value) continue; // comptime field |
| 1748 | if (try field_ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat)) return true; |
| 1749 | } |
| 1827 | 1750 | return false; |
| 1828 | | } |
| 1829 | | }, |
| 1830 | | |
| 1831 | | .array => return ty.arrayLen(mod) != 0 and |
| 1832 | | try ty.childType(mod).hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat), |
| 1833 | | .array_sentinel => return ty.childType(mod).hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat), |
| 1751 | }, |
| 1834 | 1752 | |
| 1835 | | .tuple, .anon_struct => { |
| 1836 | | const tuple = ty.tupleFields(); |
| 1837 | | for (tuple.types, 0..) |field_ty, i| { |
| 1838 | | const val = tuple.values[i]; |
| 1839 | | if (val.ip_index != .unreachable_value) continue; // comptime field |
| 1840 | | if (try field_ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat)) return true; |
| 1841 | | } |
| 1842 | | return false; |
| 1753 | .inferred_alloc_const => unreachable, |
| 1754 | .inferred_alloc_mut => unreachable, |
| 1755 | }, |
| 1756 | else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 1757 | .int_type => |int_type| return int_type.bits != 0, |
| 1758 | .ptr_type => |ptr_type| { |
| 1759 | // Pointers to zero-bit types still have a runtime address; however, pointers |
| 1760 | // to comptime-only types do not, with the exception of function pointers. |
| 1761 | if (ignore_comptime_only) return true; |
| 1762 | const child_ty = ptr_type.elem_type.toType(); |
| 1763 | if (child_ty.zigTypeTag(mod) == .Fn) return !child_ty.fnInfo().is_generic; |
| 1764 | if (strat == .sema) return !(try strat.sema.typeRequiresComptime(ty)); |
| 1765 | return !comptimeOnly(ty, mod); |
| 1766 | }, |
| 1767 | .array_type => |array_type| { |
| 1768 | if (array_type.sentinel != .none) { |
| 1769 | return array_type.child.toType().hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat); |
| 1770 | } else { |
| 1771 | return array_type.len > 0 and |
| 1772 | try array_type.child.toType().hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat); |
| 1773 | } |
| 1774 | }, |
| 1775 | .vector_type => |vector_type| { |
| 1776 | return vector_type.len > 0 and |
| 1777 | try vector_type.child.toType().hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat); |
| 1778 | }, |
| 1779 | .opt_type => |child| { |
| 1780 | const child_ty = child.toType(); |
| 1781 | if (child_ty.isNoReturn()) { |
| 1782 | // Then the optional is comptime-known to be null. |
| 1783 | return false; |
| 1784 | } |
| 1785 | if (ignore_comptime_only) { |
| 1786 | return true; |
| 1787 | } else if (strat == .sema) { |
| 1788 | return !(try strat.sema.typeRequiresComptime(child_ty)); |
| 1789 | } else { |
| 1790 | return !comptimeOnly(child_ty, mod); |
| 1791 | } |
| 1792 | }, |
| 1793 | .error_union_type => @panic("TODO"), |
| 1794 | .simple_type => |t| return switch (t) { |
| 1795 | .f16, |
| 1796 | .f32, |
| 1797 | .f64, |
| 1798 | .f80, |
| 1799 | .f128, |
| 1800 | .usize, |
| 1801 | .isize, |
| 1802 | .c_char, |
| 1803 | .c_short, |
| 1804 | .c_ushort, |
| 1805 | .c_int, |
| 1806 | .c_uint, |
| 1807 | .c_long, |
| 1808 | .c_ulong, |
| 1809 | .c_longlong, |
| 1810 | .c_ulonglong, |
| 1811 | .c_longdouble, |
| 1812 | .bool, |
| 1813 | .anyerror, |
| 1814 | .@"anyframe", |
| 1815 | .anyopaque, |
| 1816 | .atomic_order, |
| 1817 | .atomic_rmw_op, |
| 1818 | .calling_convention, |
| 1819 | .address_space, |
| 1820 | .float_mode, |
| 1821 | .reduce_op, |
| 1822 | .call_modifier, |
| 1823 | .prefetch_options, |
| 1824 | .export_options, |
| 1825 | .extern_options, |
| 1826 | => true, |
| 1827 | |
| 1828 | // These are false because they are comptime-only types. |
| 1829 | .void, |
| 1830 | .type, |
| 1831 | .comptime_int, |
| 1832 | .comptime_float, |
| 1833 | .noreturn, |
| 1834 | .null, |
| 1835 | .undefined, |
| 1836 | .enum_literal, |
| 1837 | .type_info, |
| 1838 | => false, |
| 1839 | |
| 1840 | .generic_poison => unreachable, |
| 1841 | .var_args_param => unreachable, |
| 1842 | }, |
| 1843 | .struct_type => @panic("TODO"), |
| 1844 | .union_type => @panic("TODO"), |
| 1845 | .simple_value => unreachable, |
| 1846 | .extern_func => unreachable, |
| 1847 | .int => unreachable, |
| 1848 | .enum_tag => unreachable, // it's a value, not a type |
| 1843 | 1849 | }, |
| 1844 | | |
| 1845 | | .inferred_alloc_const => unreachable, |
| 1846 | | .inferred_alloc_mut => unreachable, |
| 1847 | 1850 | } |
| 1848 | 1851 | } |
| 1849 | 1852 | |
| ... | ... | @@ -1851,104 +1854,107 @@ pub const Type = struct { |
| 1851 | 1854 | /// readFrom/writeToMemory are supported only for types with a well- |
| 1852 | 1855 | /// defined memory layout |
| 1853 | 1856 | pub fn hasWellDefinedLayout(ty: Type, mod: *Module) bool { |
| 1854 | | if (ty.ip_index != .none) return switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 1855 | | .int_type => true, |
| 1856 | | .ptr_type => true, |
| 1857 | | .array_type => |array_type| array_type.child.toType().hasWellDefinedLayout(mod), |
| 1858 | | .vector_type => true, |
| 1859 | | .opt_type => |child| child.toType().isPtrLikeOptional(mod), |
| 1860 | | .error_union_type => false, |
| 1861 | | .simple_type => |t| switch (t) { |
| 1862 | | .f16, |
| 1863 | | .f32, |
| 1864 | | .f64, |
| 1865 | | .f80, |
| 1866 | | .f128, |
| 1867 | | .usize, |
| 1868 | | .isize, |
| 1869 | | .c_char, |
| 1870 | | .c_short, |
| 1871 | | .c_ushort, |
| 1872 | | .c_int, |
| 1873 | | .c_uint, |
| 1874 | | .c_long, |
| 1875 | | .c_ulong, |
| 1876 | | .c_longlong, |
| 1877 | | .c_ulonglong, |
| 1878 | | .c_longdouble, |
| 1879 | | .bool, |
| 1880 | | .void, |
| 1857 | return switch (ty.ip_index) { |
| 1858 | .empty_struct_type => false, |
| 1859 | |
| 1860 | .none => switch (ty.tag()) { |
| 1861 | .pointer, |
| 1862 | .enum_numbered, |
| 1881 | 1863 | => true, |
| 1882 | 1864 | |
| 1883 | | .anyerror, |
| 1884 | | .@"anyframe", |
| 1885 | | .anyopaque, |
| 1886 | | .atomic_order, |
| 1887 | | .atomic_rmw_op, |
| 1888 | | .calling_convention, |
| 1889 | | .address_space, |
| 1890 | | .float_mode, |
| 1891 | | .reduce_op, |
| 1892 | | .call_modifier, |
| 1893 | | .prefetch_options, |
| 1894 | | .export_options, |
| 1895 | | .extern_options, |
| 1896 | | .type, |
| 1897 | | .comptime_int, |
| 1898 | | .comptime_float, |
| 1899 | | .noreturn, |
| 1900 | | .null, |
| 1901 | | .undefined, |
| 1902 | | .enum_literal, |
| 1903 | | .type_info, |
| 1904 | | .generic_poison, |
| 1865 | .error_set, |
| 1866 | .error_set_single, |
| 1867 | .error_set_inferred, |
| 1868 | .error_set_merged, |
| 1869 | .@"opaque", |
| 1870 | // These are function bodies, not function pointers. |
| 1871 | .function, |
| 1872 | .enum_simple, |
| 1873 | .error_union, |
| 1874 | .anyframe_T, |
| 1875 | .tuple, |
| 1876 | .anon_struct, |
| 1877 | .empty_struct, |
| 1905 | 1878 | => false, |
| 1906 | 1879 | |
| 1907 | | .var_args_param => unreachable, |
| 1908 | | }, |
| 1909 | | .struct_type => @panic("TODO"), |
| 1910 | | .union_type => @panic("TODO"), |
| 1911 | | .simple_value => unreachable, |
| 1912 | | .extern_func => unreachable, |
| 1913 | | .int => unreachable, |
| 1914 | | .enum_tag => unreachable, // it's a value, not a type |
| 1915 | | }; |
| 1916 | | return switch (ty.tag()) { |
| 1917 | | .pointer, |
| 1918 | | .enum_numbered, |
| 1919 | | => true, |
| 1880 | .enum_full, |
| 1881 | .enum_nonexhaustive, |
| 1882 | => !ty.cast(Payload.EnumFull).?.data.tag_ty_inferred, |
| 1920 | 1883 | |
| 1921 | | .error_set, |
| 1922 | | .error_set_single, |
| 1923 | | .error_set_inferred, |
| 1924 | | .error_set_merged, |
| 1925 | | .@"opaque", |
| 1926 | | // These are function bodies, not function pointers. |
| 1927 | | .function, |
| 1928 | | .enum_simple, |
| 1929 | | .error_union, |
| 1930 | | .anyframe_T, |
| 1931 | | .tuple, |
| 1932 | | .anon_struct, |
| 1933 | | .empty_struct_literal, |
| 1934 | | .empty_struct, |
| 1935 | | => false, |
| 1884 | .inferred_alloc_mut => unreachable, |
| 1885 | .inferred_alloc_const => unreachable, |
| 1936 | 1886 | |
| 1937 | | .enum_full, |
| 1938 | | .enum_nonexhaustive, |
| 1939 | | => !ty.cast(Payload.EnumFull).?.data.tag_ty_inferred, |
| 1887 | .array, |
| 1888 | .array_sentinel, |
| 1889 | => ty.childType(mod).hasWellDefinedLayout(mod), |
| 1940 | 1890 | |
| 1941 | | .inferred_alloc_mut => unreachable, |
| 1942 | | .inferred_alloc_const => unreachable, |
| 1891 | .optional => ty.isPtrLikeOptional(mod), |
| 1892 | .@"struct" => ty.castTag(.@"struct").?.data.layout != .Auto, |
| 1893 | .@"union", .union_safety_tagged => ty.cast(Payload.Union).?.data.layout != .Auto, |
| 1894 | .union_tagged => false, |
| 1895 | }, |
| 1896 | else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 1897 | .int_type => true, |
| 1898 | .ptr_type => true, |
| 1899 | .array_type => |array_type| array_type.child.toType().hasWellDefinedLayout(mod), |
| 1900 | .vector_type => true, |
| 1901 | .opt_type => |child| child.toType().isPtrLikeOptional(mod), |
| 1902 | .error_union_type => false, |
| 1903 | .simple_type => |t| switch (t) { |
| 1904 | .f16, |
| 1905 | .f32, |
| 1906 | .f64, |
| 1907 | .f80, |
| 1908 | .f128, |
| 1909 | .usize, |
| 1910 | .isize, |
| 1911 | .c_char, |
| 1912 | .c_short, |
| 1913 | .c_ushort, |
| 1914 | .c_int, |
| 1915 | .c_uint, |
| 1916 | .c_long, |
| 1917 | .c_ulong, |
| 1918 | .c_longlong, |
| 1919 | .c_ulonglong, |
| 1920 | .c_longdouble, |
| 1921 | .bool, |
| 1922 | .void, |
| 1923 | => true, |
| 1943 | 1924 | |
| 1944 | | .array, |
| 1945 | | .array_sentinel, |
| 1946 | | => ty.childType(mod).hasWellDefinedLayout(mod), |
| 1925 | .anyerror, |
| 1926 | .@"anyframe", |
| 1927 | .anyopaque, |
| 1928 | .atomic_order, |
| 1929 | .atomic_rmw_op, |
| 1930 | .calling_convention, |
| 1931 | .address_space, |
| 1932 | .float_mode, |
| 1933 | .reduce_op, |
| 1934 | .call_modifier, |
| 1935 | .prefetch_options, |
| 1936 | .export_options, |
| 1937 | .extern_options, |
| 1938 | .type, |
| 1939 | .comptime_int, |
| 1940 | .comptime_float, |
| 1941 | .noreturn, |
| 1942 | .null, |
| 1943 | .undefined, |
| 1944 | .enum_literal, |
| 1945 | .type_info, |
| 1946 | .generic_poison, |
| 1947 | => false, |
| 1947 | 1948 | |
| 1948 | | .optional => ty.isPtrLikeOptional(mod), |
| 1949 | | .@"struct" => ty.castTag(.@"struct").?.data.layout != .Auto, |
| 1950 | | .@"union", .union_safety_tagged => ty.cast(Payload.Union).?.data.layout != .Auto, |
| 1951 | | .union_tagged => false, |
| 1949 | .var_args_param => unreachable, |
| 1950 | }, |
| 1951 | .struct_type => @panic("TODO"), |
| 1952 | .union_type => @panic("TODO"), |
| 1953 | .simple_value => unreachable, |
| 1954 | .extern_func => unreachable, |
| 1955 | .int => unreachable, |
| 1956 | .enum_tag => unreachable, // it's a value, not a type |
| 1957 | }, |
| 1952 | 1958 | }; |
| 1953 | 1959 | } |
| 1954 | 1960 | |
| ... | ... | @@ -2120,232 +2126,232 @@ pub const Type = struct { |
| 2120 | 2126 | else => null, |
| 2121 | 2127 | }; |
| 2122 | 2128 | |
| 2123 | | if (ty.ip_index != .none) switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 2124 | | .int_type => |int_type| { |
| 2125 | | if (int_type.bits == 0) return AbiAlignmentAdvanced{ .scalar = 0 }; |
| 2126 | | return AbiAlignmentAdvanced{ .scalar = intAbiAlignment(int_type.bits, target) }; |
| 2127 | | }, |
| 2128 | | .ptr_type => { |
| 2129 | | return AbiAlignmentAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) }; |
| 2130 | | }, |
| 2131 | | .array_type => |array_type| { |
| 2132 | | return array_type.child.toType().abiAlignmentAdvanced(mod, strat); |
| 2133 | | }, |
| 2134 | | .vector_type => |vector_type| { |
| 2135 | | const bits_u64 = try bitSizeAdvanced(vector_type.child.toType(), mod, opt_sema); |
| 2136 | | const bits = @intCast(u32, bits_u64); |
| 2137 | | const bytes = ((bits * vector_type.len) + 7) / 8; |
| 2138 | | const alignment = std.math.ceilPowerOfTwoAssert(u32, bytes); |
| 2139 | | return AbiAlignmentAdvanced{ .scalar = alignment }; |
| 2140 | | }, |
| 2129 | switch (ty.ip_index) { |
| 2130 | .empty_struct_type => return AbiAlignmentAdvanced{ .scalar = 0 }, |
| 2131 | .none => switch (ty.tag()) { |
| 2132 | .@"opaque" => return AbiAlignmentAdvanced{ .scalar = 1 }, |
| 2141 | 2133 | |
| 2142 | | .opt_type => return abiAlignmentAdvancedOptional(ty, mod, strat), |
| 2143 | | .error_union_type => return abiAlignmentAdvancedErrorUnion(ty, mod, strat), |
| 2144 | | .simple_type => |t| switch (t) { |
| 2145 | | .bool, |
| 2146 | | .atomic_order, |
| 2147 | | .atomic_rmw_op, |
| 2148 | | .calling_convention, |
| 2149 | | .address_space, |
| 2150 | | .float_mode, |
| 2151 | | .reduce_op, |
| 2152 | | .call_modifier, |
| 2153 | | .prefetch_options, |
| 2154 | | .anyopaque, |
| 2155 | | => return AbiAlignmentAdvanced{ .scalar = 1 }, |
| 2134 | // represents machine code; not a pointer |
| 2135 | .function => { |
| 2136 | const alignment = ty.castTag(.function).?.data.alignment; |
| 2137 | if (alignment != 0) return AbiAlignmentAdvanced{ .scalar = alignment }; |
| 2138 | return AbiAlignmentAdvanced{ .scalar = target_util.defaultFunctionAlignment(target) }; |
| 2139 | }, |
| 2156 | 2140 | |
| 2157 | | .usize, |
| 2158 | | .isize, |
| 2159 | | .export_options, |
| 2160 | | .extern_options, |
| 2161 | | .@"anyframe", |
| 2141 | .pointer, |
| 2142 | .anyframe_T, |
| 2162 | 2143 | => return AbiAlignmentAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) }, |
| 2163 | 2144 | |
| 2164 | | .c_char => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.char) }, |
| 2165 | | .c_short => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.short) }, |
| 2166 | | .c_ushort => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.ushort) }, |
| 2167 | | .c_int => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.int) }, |
| 2168 | | .c_uint => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.uint) }, |
| 2169 | | .c_long => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.long) }, |
| 2170 | | .c_ulong => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.ulong) }, |
| 2171 | | .c_longlong => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.longlong) }, |
| 2172 | | .c_ulonglong => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.ulonglong) }, |
| 2173 | | .c_longdouble => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.longdouble) }, |
| 2174 | | |
| 2175 | | .f16 => return AbiAlignmentAdvanced{ .scalar = 2 }, |
| 2176 | | .f32 => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.float) }, |
| 2177 | | .f64 => switch (target.c_type_bit_size(.double)) { |
| 2178 | | 64 => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.double) }, |
| 2179 | | else => return AbiAlignmentAdvanced{ .scalar = 8 }, |
| 2180 | | }, |
| 2181 | | .f80 => switch (target.c_type_bit_size(.longdouble)) { |
| 2182 | | 80 => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.longdouble) }, |
| 2183 | | else => { |
| 2184 | | const u80_ty: Type = .{ |
| 2185 | | .ip_index = .u80_type, |
| 2186 | | .legacy = undefined, |
| 2187 | | }; |
| 2188 | | return AbiAlignmentAdvanced{ .scalar = abiAlignment(u80_ty, mod) }; |
| 2189 | | }, |
| 2190 | | }, |
| 2191 | | .f128 => switch (target.c_type_bit_size(.longdouble)) { |
| 2192 | | 128 => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.longdouble) }, |
| 2193 | | else => return AbiAlignmentAdvanced{ .scalar = 16 }, |
| 2194 | | }, |
| 2195 | | |
| 2196 | 2145 | // TODO revisit this when we have the concept of the error tag type |
| 2197 | | .anyerror => return AbiAlignmentAdvanced{ .scalar = 2 }, |
| 2198 | | |
| 2199 | | .void, |
| 2200 | | .type, |
| 2201 | | .comptime_int, |
| 2202 | | .comptime_float, |
| 2203 | | .null, |
| 2204 | | .undefined, |
| 2205 | | .enum_literal, |
| 2206 | | .type_info, |
| 2207 | | => return AbiAlignmentAdvanced{ .scalar = 0 }, |
| 2208 | | |
| 2209 | | .noreturn => unreachable, |
| 2210 | | .generic_poison => unreachable, |
| 2211 | | .var_args_param => unreachable, |
| 2212 | | }, |
| 2213 | | .struct_type => @panic("TODO"), |
| 2214 | | .union_type => @panic("TODO"), |
| 2215 | | .simple_value => unreachable, |
| 2216 | | .extern_func => unreachable, |
| 2217 | | .int => unreachable, |
| 2218 | | .enum_tag => unreachable, // it's a value, not a type |
| 2219 | | }; |
| 2220 | | |
| 2221 | | switch (ty.tag()) { |
| 2222 | | .@"opaque" => return AbiAlignmentAdvanced{ .scalar = 1 }, |
| 2223 | | |
| 2224 | | // represents machine code; not a pointer |
| 2225 | | .function => { |
| 2226 | | const alignment = ty.castTag(.function).?.data.alignment; |
| 2227 | | if (alignment != 0) return AbiAlignmentAdvanced{ .scalar = alignment }; |
| 2228 | | return AbiAlignmentAdvanced{ .scalar = target_util.defaultFunctionAlignment(target) }; |
| 2229 | | }, |
| 2230 | | |
| 2231 | | .pointer, |
| 2232 | | .anyframe_T, |
| 2233 | | => return AbiAlignmentAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) }, |
| 2146 | .error_set_inferred, |
| 2147 | .error_set_single, |
| 2148 | .error_set, |
| 2149 | .error_set_merged, |
| 2150 | => return AbiAlignmentAdvanced{ .scalar = 2 }, |
| 2234 | 2151 | |
| 2235 | | // TODO revisit this when we have the concept of the error tag type |
| 2236 | | .error_set_inferred, |
| 2237 | | .error_set_single, |
| 2238 | | .error_set, |
| 2239 | | .error_set_merged, |
| 2240 | | => return AbiAlignmentAdvanced{ .scalar = 2 }, |
| 2241 | | |
| 2242 | | .array, .array_sentinel => return ty.childType(mod).abiAlignmentAdvanced(mod, strat), |
| 2152 | .array, .array_sentinel => return ty.childType(mod).abiAlignmentAdvanced(mod, strat), |
| 2243 | 2153 | |
| 2244 | | .optional => return abiAlignmentAdvancedOptional(ty, mod, strat), |
| 2245 | | .error_union => return abiAlignmentAdvancedErrorUnion(ty, mod, strat), |
| 2154 | .optional => return abiAlignmentAdvancedOptional(ty, mod, strat), |
| 2155 | .error_union => return abiAlignmentAdvancedErrorUnion(ty, mod, strat), |
| 2246 | 2156 | |
| 2247 | | .@"struct" => { |
| 2248 | | const struct_obj = ty.castTag(.@"struct").?.data; |
| 2249 | | if (opt_sema) |sema| { |
| 2250 | | if (struct_obj.status == .field_types_wip) { |
| 2251 | | // We'll guess "pointer-aligned", if the struct has an |
| 2252 | | // underaligned pointer field then some allocations |
| 2253 | | // might require explicit alignment. |
| 2254 | | return AbiAlignmentAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) }; |
| 2157 | .@"struct" => { |
| 2158 | const struct_obj = ty.castTag(.@"struct").?.data; |
| 2159 | if (opt_sema) |sema| { |
| 2160 | if (struct_obj.status == .field_types_wip) { |
| 2161 | // We'll guess "pointer-aligned", if the struct has an |
| 2162 | // underaligned pointer field then some allocations |
| 2163 | // might require explicit alignment. |
| 2164 | return AbiAlignmentAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) }; |
| 2165 | } |
| 2166 | _ = try sema.resolveTypeFields(ty); |
| 2255 | 2167 | } |
| 2256 | | _ = try sema.resolveTypeFields(ty); |
| 2257 | | } |
| 2258 | | if (!struct_obj.haveFieldTypes()) switch (strat) { |
| 2259 | | .eager => unreachable, // struct layout not resolved |
| 2260 | | .sema => unreachable, // handled above |
| 2261 | | .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }, |
| 2262 | | }; |
| 2263 | | if (struct_obj.layout == .Packed) { |
| 2264 | | switch (strat) { |
| 2265 | | .sema => |sema| try sema.resolveTypeLayout(ty), |
| 2266 | | .lazy => |arena| { |
| 2267 | | if (!struct_obj.haveLayout()) { |
| 2268 | | return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }; |
| 2269 | | } |
| 2270 | | }, |
| 2271 | | .eager => {}, |
| 2168 | if (!struct_obj.haveFieldTypes()) switch (strat) { |
| 2169 | .eager => unreachable, // struct layout not resolved |
| 2170 | .sema => unreachable, // handled above |
| 2171 | .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }, |
| 2172 | }; |
| 2173 | if (struct_obj.layout == .Packed) { |
| 2174 | switch (strat) { |
| 2175 | .sema => |sema| try sema.resolveTypeLayout(ty), |
| 2176 | .lazy => |arena| { |
| 2177 | if (!struct_obj.haveLayout()) { |
| 2178 | return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }; |
| 2179 | } |
| 2180 | }, |
| 2181 | .eager => {}, |
| 2182 | } |
| 2183 | assert(struct_obj.haveLayout()); |
| 2184 | return AbiAlignmentAdvanced{ .scalar = struct_obj.backing_int_ty.abiAlignment(mod) }; |
| 2272 | 2185 | } |
| 2273 | | assert(struct_obj.haveLayout()); |
| 2274 | | return AbiAlignmentAdvanced{ .scalar = struct_obj.backing_int_ty.abiAlignment(mod) }; |
| 2275 | | } |
| 2276 | | |
| 2277 | | const fields = ty.structFields(); |
| 2278 | | var big_align: u32 = 0; |
| 2279 | | for (fields.values()) |field| { |
| 2280 | | if (!(field.ty.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) { |
| 2281 | | error.NeedLazy => return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(strat.lazy, ty) }, |
| 2282 | | else => |e| return e, |
| 2283 | | })) continue; |
| 2284 | 2186 | |
| 2285 | | const field_align = if (field.abi_align != 0) |
| 2286 | | field.abi_align |
| 2287 | | else switch (try field.ty.abiAlignmentAdvanced(mod, strat)) { |
| 2288 | | .scalar => |a| a, |
| 2289 | | .val => switch (strat) { |
| 2290 | | .eager => unreachable, // struct layout not resolved |
| 2291 | | .sema => unreachable, // handled above |
| 2292 | | .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }, |
| 2293 | | }, |
| 2294 | | }; |
| 2295 | | big_align = @max(big_align, field_align); |
| 2187 | const fields = ty.structFields(); |
| 2188 | var big_align: u32 = 0; |
| 2189 | for (fields.values()) |field| { |
| 2190 | if (!(field.ty.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) { |
| 2191 | error.NeedLazy => return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(strat.lazy, ty) }, |
| 2192 | else => |e| return e, |
| 2193 | })) continue; |
| 2194 | |
| 2195 | const field_align = if (field.abi_align != 0) |
| 2196 | field.abi_align |
| 2197 | else switch (try field.ty.abiAlignmentAdvanced(mod, strat)) { |
| 2198 | .scalar => |a| a, |
| 2199 | .val => switch (strat) { |
| 2200 | .eager => unreachable, // struct layout not resolved |
| 2201 | .sema => unreachable, // handled above |
| 2202 | .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }, |
| 2203 | }, |
| 2204 | }; |
| 2205 | big_align = @max(big_align, field_align); |
| 2206 | |
| 2207 | // This logic is duplicated in Module.Struct.Field.alignment. |
| 2208 | if (struct_obj.layout == .Extern or target.ofmt == .c) { |
| 2209 | if (field.ty.isAbiInt(mod) and field.ty.intInfo(mod).bits >= 128) { |
| 2210 | // The C ABI requires 128 bit integer fields of structs |
| 2211 | // to be 16-bytes aligned. |
| 2212 | big_align = @max(big_align, 16); |
| 2213 | } |
| 2214 | } |
| 2215 | } |
| 2216 | return AbiAlignmentAdvanced{ .scalar = big_align }; |
| 2217 | }, |
| 2296 | 2218 | |
| 2297 | | // This logic is duplicated in Module.Struct.Field.alignment. |
| 2298 | | if (struct_obj.layout == .Extern or target.ofmt == .c) { |
| 2299 | | if (field.ty.isAbiInt(mod) and field.ty.intInfo(mod).bits >= 128) { |
| 2300 | | // The C ABI requires 128 bit integer fields of structs |
| 2301 | | // to be 16-bytes aligned. |
| 2302 | | big_align = @max(big_align, 16); |
| 2219 | .tuple, .anon_struct => { |
| 2220 | const tuple = ty.tupleFields(); |
| 2221 | var big_align: u32 = 0; |
| 2222 | for (tuple.types, 0..) |field_ty, i| { |
| 2223 | const val = tuple.values[i]; |
| 2224 | if (val.ip_index != .unreachable_value) continue; // comptime field |
| 2225 | if (!(field_ty.hasRuntimeBits(mod))) continue; |
| 2226 | |
| 2227 | switch (try field_ty.abiAlignmentAdvanced(mod, strat)) { |
| 2228 | .scalar => |field_align| big_align = @max(big_align, field_align), |
| 2229 | .val => switch (strat) { |
| 2230 | .eager => unreachable, // field type alignment not resolved |
| 2231 | .sema => unreachable, // passed to abiAlignmentAdvanced above |
| 2232 | .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }, |
| 2233 | }, |
| 2303 | 2234 | } |
| 2304 | 2235 | } |
| 2305 | | } |
| 2306 | | return AbiAlignmentAdvanced{ .scalar = big_align }; |
| 2307 | | }, |
| 2236 | return AbiAlignmentAdvanced{ .scalar = big_align }; |
| 2237 | }, |
| 2308 | 2238 | |
| 2309 | | .tuple, .anon_struct => { |
| 2310 | | const tuple = ty.tupleFields(); |
| 2311 | | var big_align: u32 = 0; |
| 2312 | | for (tuple.types, 0..) |field_ty, i| { |
| 2313 | | const val = tuple.values[i]; |
| 2314 | | if (val.ip_index != .unreachable_value) continue; // comptime field |
| 2315 | | if (!(field_ty.hasRuntimeBits(mod))) continue; |
| 2239 | .enum_full, .enum_nonexhaustive, .enum_simple, .enum_numbered => { |
| 2240 | const int_tag_ty = try ty.intTagType(mod); |
| 2241 | return AbiAlignmentAdvanced{ .scalar = int_tag_ty.abiAlignment(mod) }; |
| 2242 | }, |
| 2243 | .@"union" => { |
| 2244 | const union_obj = ty.castTag(.@"union").?.data; |
| 2245 | return abiAlignmentAdvancedUnion(ty, mod, strat, union_obj, false); |
| 2246 | }, |
| 2247 | .union_safety_tagged, .union_tagged => { |
| 2248 | const union_obj = ty.cast(Payload.Union).?.data; |
| 2249 | return abiAlignmentAdvancedUnion(ty, mod, strat, union_obj, true); |
| 2250 | }, |
| 2251 | |
| 2252 | .empty_struct => return AbiAlignmentAdvanced{ .scalar = 0 }, |
| 2316 | 2253 | |
| 2317 | | switch (try field_ty.abiAlignmentAdvanced(mod, strat)) { |
| 2318 | | .scalar => |field_align| big_align = @max(big_align, field_align), |
| 2319 | | .val => switch (strat) { |
| 2320 | | .eager => unreachable, // field type alignment not resolved |
| 2321 | | .sema => unreachable, // passed to abiAlignmentAdvanced above |
| 2322 | | .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) }, |
| 2323 | | }, |
| 2324 | | } |
| 2325 | | } |
| 2326 | | return AbiAlignmentAdvanced{ .scalar = big_align }; |
| 2254 | .inferred_alloc_const, |
| 2255 | .inferred_alloc_mut, |
| 2256 | => unreachable, |
| 2327 | 2257 | }, |
| 2258 | else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 2259 | .int_type => |int_type| { |
| 2260 | if (int_type.bits == 0) return AbiAlignmentAdvanced{ .scalar = 0 }; |
| 2261 | return AbiAlignmentAdvanced{ .scalar = intAbiAlignment(int_type.bits, target) }; |
| 2262 | }, |
| 2263 | .ptr_type => { |
| 2264 | return AbiAlignmentAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) }; |
| 2265 | }, |
| 2266 | .array_type => |array_type| { |
| 2267 | return array_type.child.toType().abiAlignmentAdvanced(mod, strat); |
| 2268 | }, |
| 2269 | .vector_type => |vector_type| { |
| 2270 | const bits_u64 = try bitSizeAdvanced(vector_type.child.toType(), mod, opt_sema); |
| 2271 | const bits = @intCast(u32, bits_u64); |
| 2272 | const bytes = ((bits * vector_type.len) + 7) / 8; |
| 2273 | const alignment = std.math.ceilPowerOfTwoAssert(u32, bytes); |
| 2274 | return AbiAlignmentAdvanced{ .scalar = alignment }; |
| 2275 | }, |
| 2328 | 2276 | |
| 2329 | | .enum_full, .enum_nonexhaustive, .enum_simple, .enum_numbered => { |
| 2330 | | const int_tag_ty = try ty.intTagType(mod); |
| 2331 | | return AbiAlignmentAdvanced{ .scalar = int_tag_ty.abiAlignment(mod) }; |
| 2332 | | }, |
| 2333 | | .@"union" => { |
| 2334 | | const union_obj = ty.castTag(.@"union").?.data; |
| 2335 | | return abiAlignmentAdvancedUnion(ty, mod, strat, union_obj, false); |
| 2336 | | }, |
| 2337 | | .union_safety_tagged, .union_tagged => { |
| 2338 | | const union_obj = ty.cast(Payload.Union).?.data; |
| 2339 | | return abiAlignmentAdvancedUnion(ty, mod, strat, union_obj, true); |
| 2340 | | }, |
| 2277 | .opt_type => return abiAlignmentAdvancedOptional(ty, mod, strat), |
| 2278 | .error_union_type => return abiAlignmentAdvancedErrorUnion(ty, mod, strat), |
| 2279 | .simple_type => |t| switch (t) { |
| 2280 | .bool, |
| 2281 | .atomic_order, |
| 2282 | .atomic_rmw_op, |
| 2283 | .calling_convention, |
| 2284 | .address_space, |
| 2285 | .float_mode, |
| 2286 | .reduce_op, |
| 2287 | .call_modifier, |
| 2288 | .prefetch_options, |
| 2289 | .anyopaque, |
| 2290 | => return AbiAlignmentAdvanced{ .scalar = 1 }, |
| 2341 | 2291 | |
| 2342 | | .empty_struct, |
| 2343 | | .empty_struct_literal, |
| 2344 | | => return AbiAlignmentAdvanced{ .scalar = 0 }, |
| 2292 | .usize, |
| 2293 | .isize, |
| 2294 | .export_options, |
| 2295 | .extern_options, |
| 2296 | .@"anyframe", |
| 2297 | => return AbiAlignmentAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) }, |
| 2298 | |
| 2299 | .c_char => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.char) }, |
| 2300 | .c_short => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.short) }, |
| 2301 | .c_ushort => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.ushort) }, |
| 2302 | .c_int => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.int) }, |
| 2303 | .c_uint => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.uint) }, |
| 2304 | .c_long => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.long) }, |
| 2305 | .c_ulong => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.ulong) }, |
| 2306 | .c_longlong => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.longlong) }, |
| 2307 | .c_ulonglong => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.ulonglong) }, |
| 2308 | .c_longdouble => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.longdouble) }, |
| 2309 | |
| 2310 | .f16 => return AbiAlignmentAdvanced{ .scalar = 2 }, |
| 2311 | .f32 => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.float) }, |
| 2312 | .f64 => switch (target.c_type_bit_size(.double)) { |
| 2313 | 64 => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.double) }, |
| 2314 | else => return AbiAlignmentAdvanced{ .scalar = 8 }, |
| 2315 | }, |
| 2316 | .f80 => switch (target.c_type_bit_size(.longdouble)) { |
| 2317 | 80 => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.longdouble) }, |
| 2318 | else => { |
| 2319 | const u80_ty: Type = .{ |
| 2320 | .ip_index = .u80_type, |
| 2321 | .legacy = undefined, |
| 2322 | }; |
| 2323 | return AbiAlignmentAdvanced{ .scalar = abiAlignment(u80_ty, mod) }; |
| 2324 | }, |
| 2325 | }, |
| 2326 | .f128 => switch (target.c_type_bit_size(.longdouble)) { |
| 2327 | 128 => return AbiAlignmentAdvanced{ .scalar = target.c_type_alignment(.longdouble) }, |
| 2328 | else => return AbiAlignmentAdvanced{ .scalar = 16 }, |
| 2329 | }, |
| 2345 | 2330 | |
| 2346 | | .inferred_alloc_const, |
| 2347 | | .inferred_alloc_mut, |
| 2348 | | => unreachable, |
| 2331 | // TODO revisit this when we have the concept of the error tag type |
| 2332 | .anyerror => return AbiAlignmentAdvanced{ .scalar = 2 }, |
| 2333 | |
| 2334 | .void, |
| 2335 | .type, |
| 2336 | .comptime_int, |
| 2337 | .comptime_float, |
| 2338 | .null, |
| 2339 | .undefined, |
| 2340 | .enum_literal, |
| 2341 | .type_info, |
| 2342 | => return AbiAlignmentAdvanced{ .scalar = 0 }, |
| 2343 | |
| 2344 | .noreturn => unreachable, |
| 2345 | .generic_poison => unreachable, |
| 2346 | .var_args_param => unreachable, |
| 2347 | }, |
| 2348 | .struct_type => @panic("TODO"), |
| 2349 | .union_type => @panic("TODO"), |
| 2350 | .simple_value => unreachable, |
| 2351 | .extern_func => unreachable, |
| 2352 | .int => unreachable, |
| 2353 | .enum_tag => unreachable, // it's a value, not a type |
| 2354 | }, |
| 2349 | 2355 | } |
| 2350 | 2356 | } |
| 2351 | 2357 | |
| ... | ... | @@ -2506,255 +2512,256 @@ pub const Type = struct { |
| 2506 | 2512 | ) Module.CompileError!AbiSizeAdvanced { |
| 2507 | 2513 | const target = mod.getTarget(); |
| 2508 | 2514 | |
| 2509 | | if (ty.ip_index != .none) switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 2510 | | .int_type => |int_type| { |
| 2511 | | if (int_type.bits == 0) return AbiSizeAdvanced{ .scalar = 0 }; |
| 2512 | | return AbiSizeAdvanced{ .scalar = intAbiSize(int_type.bits, target) }; |
| 2513 | | }, |
| 2514 | | .ptr_type => |ptr_type| switch (ptr_type.size) { |
| 2515 | | .Slice => return .{ .scalar = @divExact(target.ptrBitWidth(), 8) * 2 }, |
| 2516 | | else => return .{ .scalar = @divExact(target.ptrBitWidth(), 8) }, |
| 2517 | | }, |
| 2518 | | .array_type => |array_type| { |
| 2519 | | const len = array_type.len + @boolToInt(array_type.sentinel != .none); |
| 2520 | | switch (try array_type.child.toType().abiSizeAdvanced(mod, strat)) { |
| 2521 | | .scalar => |elem_size| return .{ .scalar = len * elem_size }, |
| 2522 | | .val => switch (strat) { |
| 2523 | | .sema, .eager => unreachable, |
| 2524 | | .lazy => |arena| return .{ .val = try Value.Tag.lazy_size.create(arena, ty) }, |
| 2525 | | }, |
| 2526 | | } |
| 2527 | | }, |
| 2528 | | .vector_type => |vector_type| { |
| 2529 | | const opt_sema = switch (strat) { |
| 2530 | | .sema => |sema| sema, |
| 2531 | | .eager => null, |
| 2532 | | .lazy => |arena| return AbiSizeAdvanced{ |
| 2533 | | .val = try Value.Tag.lazy_size.create(arena, ty), |
| 2534 | | }, |
| 2535 | | }; |
| 2536 | | const elem_bits_u64 = try vector_type.child.toType().bitSizeAdvanced(mod, opt_sema); |
| 2537 | | const elem_bits = @intCast(u32, elem_bits_u64); |
| 2538 | | const total_bits = elem_bits * vector_type.len; |
| 2539 | | const total_bytes = (total_bits + 7) / 8; |
| 2540 | | const alignment = switch (try ty.abiAlignmentAdvanced(mod, strat)) { |
| 2541 | | .scalar => |x| x, |
| 2542 | | .val => return AbiSizeAdvanced{ |
| 2543 | | .val = try Value.Tag.lazy_size.create(strat.lazy, ty), |
| 2544 | | }, |
| 2545 | | }; |
| 2546 | | const result = std.mem.alignForwardGeneric(u32, total_bytes, alignment); |
| 2547 | | return AbiSizeAdvanced{ .scalar = result }; |
| 2548 | | }, |
| 2515 | switch (ty.ip_index) { |
| 2516 | .empty_struct_type => return AbiSizeAdvanced{ .scalar = 0 }, |
| 2549 | 2517 | |
| 2550 | | .opt_type => return ty.abiSizeAdvancedOptional(mod, strat), |
| 2551 | | .error_union_type => @panic("TODO"), |
| 2552 | | .simple_type => |t| switch (t) { |
| 2553 | | .bool, |
| 2554 | | .atomic_order, |
| 2555 | | .atomic_rmw_op, |
| 2556 | | .calling_convention, |
| 2557 | | .address_space, |
| 2558 | | .float_mode, |
| 2559 | | .reduce_op, |
| 2560 | | .call_modifier, |
| 2561 | | => return AbiSizeAdvanced{ .scalar = 1 }, |
| 2562 | | |
| 2563 | | .f16 => return AbiSizeAdvanced{ .scalar = 2 }, |
| 2564 | | .f32 => return AbiSizeAdvanced{ .scalar = 4 }, |
| 2565 | | .f64 => return AbiSizeAdvanced{ .scalar = 8 }, |
| 2566 | | .f128 => return AbiSizeAdvanced{ .scalar = 16 }, |
| 2567 | | .f80 => switch (target.c_type_bit_size(.longdouble)) { |
| 2568 | | 80 => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.longdouble) }, |
| 2518 | .none => switch (ty.tag()) { |
| 2519 | .function => unreachable, // represents machine code; not a pointer |
| 2520 | .@"opaque" => unreachable, // no size available |
| 2521 | .inferred_alloc_const => unreachable, |
| 2522 | .inferred_alloc_mut => unreachable, |
| 2523 | |
| 2524 | .empty_struct => return AbiSizeAdvanced{ .scalar = 0 }, |
| 2525 | |
| 2526 | .@"struct", .tuple, .anon_struct => switch (ty.containerLayout()) { |
| 2527 | .Packed => { |
| 2528 | const struct_obj = ty.castTag(.@"struct").?.data; |
| 2529 | switch (strat) { |
| 2530 | .sema => |sema| try sema.resolveTypeLayout(ty), |
| 2531 | .lazy => |arena| { |
| 2532 | if (!struct_obj.haveLayout()) { |
| 2533 | return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(arena, ty) }; |
| 2534 | } |
| 2535 | }, |
| 2536 | .eager => {}, |
| 2537 | } |
| 2538 | assert(struct_obj.haveLayout()); |
| 2539 | return AbiSizeAdvanced{ .scalar = struct_obj.backing_int_ty.abiSize(mod) }; |
| 2540 | }, |
| 2569 | 2541 | else => { |
| 2570 | | const u80_ty: Type = .{ |
| 2571 | | .ip_index = .u80_type, |
| 2572 | | .legacy = undefined, |
| 2573 | | }; |
| 2574 | | return AbiSizeAdvanced{ .scalar = abiSize(u80_ty, mod) }; |
| 2542 | switch (strat) { |
| 2543 | .sema => |sema| try sema.resolveTypeLayout(ty), |
| 2544 | .lazy => |arena| { |
| 2545 | if (ty.castTag(.@"struct")) |payload| { |
| 2546 | const struct_obj = payload.data; |
| 2547 | if (!struct_obj.haveLayout()) { |
| 2548 | return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(arena, ty) }; |
| 2549 | } |
| 2550 | } |
| 2551 | }, |
| 2552 | .eager => {}, |
| 2553 | } |
| 2554 | const field_count = ty.structFieldCount(); |
| 2555 | if (field_count == 0) { |
| 2556 | return AbiSizeAdvanced{ .scalar = 0 }; |
| 2557 | } |
| 2558 | return AbiSizeAdvanced{ .scalar = ty.structFieldOffset(field_count, mod) }; |
| 2575 | 2559 | }, |
| 2576 | 2560 | }, |
| 2577 | 2561 | |
| 2578 | | .usize, |
| 2579 | | .isize, |
| 2580 | | .@"anyframe", |
| 2581 | | => return AbiSizeAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) }, |
| 2582 | | |
| 2583 | | .c_char => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.char) }, |
| 2584 | | .c_short => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.short) }, |
| 2585 | | .c_ushort => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.ushort) }, |
| 2586 | | .c_int => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.int) }, |
| 2587 | | .c_uint => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.uint) }, |
| 2588 | | .c_long => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.long) }, |
| 2589 | | .c_ulong => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.ulong) }, |
| 2590 | | .c_longlong => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.longlong) }, |
| 2591 | | .c_ulonglong => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.ulonglong) }, |
| 2592 | | .c_longdouble => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.longdouble) }, |
| 2593 | | |
| 2594 | | .anyopaque, |
| 2595 | | .void, |
| 2596 | | .type, |
| 2597 | | .comptime_int, |
| 2598 | | .comptime_float, |
| 2599 | | .null, |
| 2600 | | .undefined, |
| 2601 | | .enum_literal, |
| 2602 | | => return AbiSizeAdvanced{ .scalar = 0 }, |
| 2603 | | |
| 2604 | | // TODO revisit this when we have the concept of the error tag type |
| 2605 | | .anyerror => return AbiSizeAdvanced{ .scalar = 2 }, |
| 2606 | | |
| 2607 | | .prefetch_options => unreachable, // missing call to resolveTypeFields |
| 2608 | | .export_options => unreachable, // missing call to resolveTypeFields |
| 2609 | | .extern_options => unreachable, // missing call to resolveTypeFields |
| 2610 | | |
| 2611 | | .type_info => unreachable, |
| 2612 | | .noreturn => unreachable, |
| 2613 | | .generic_poison => unreachable, |
| 2614 | | .var_args_param => unreachable, |
| 2615 | | }, |
| 2616 | | .struct_type => @panic("TODO"), |
| 2617 | | .union_type => @panic("TODO"), |
| 2618 | | .simple_value => unreachable, |
| 2619 | | .extern_func => unreachable, |
| 2620 | | .int => unreachable, |
| 2621 | | .enum_tag => unreachable, // it's a value, not a type |
| 2622 | | }; |
| 2623 | | |
| 2624 | | switch (ty.tag()) { |
| 2625 | | .function => unreachable, // represents machine code; not a pointer |
| 2626 | | .@"opaque" => unreachable, // no size available |
| 2627 | | .inferred_alloc_const => unreachable, |
| 2628 | | .inferred_alloc_mut => unreachable, |
| 2629 | | |
| 2630 | | .empty_struct_literal, |
| 2631 | | .empty_struct, |
| 2632 | | => return AbiSizeAdvanced{ .scalar = 0 }, |
| 2562 | .enum_simple, .enum_full, .enum_nonexhaustive, .enum_numbered => { |
| 2563 | const int_tag_ty = try ty.intTagType(mod); |
| 2564 | return AbiSizeAdvanced{ .scalar = int_tag_ty.abiSize(mod) }; |
| 2565 | }, |
| 2566 | .@"union" => { |
| 2567 | const union_obj = ty.castTag(.@"union").?.data; |
| 2568 | return abiSizeAdvancedUnion(ty, mod, strat, union_obj, false); |
| 2569 | }, |
| 2570 | .union_safety_tagged, .union_tagged => { |
| 2571 | const union_obj = ty.cast(Payload.Union).?.data; |
| 2572 | return abiSizeAdvancedUnion(ty, mod, strat, union_obj, true); |
| 2573 | }, |
| 2633 | 2574 | |
| 2634 | | .@"struct", .tuple, .anon_struct => switch (ty.containerLayout()) { |
| 2635 | | .Packed => { |
| 2636 | | const struct_obj = ty.castTag(.@"struct").?.data; |
| 2637 | | switch (strat) { |
| 2638 | | .sema => |sema| try sema.resolveTypeLayout(ty), |
| 2639 | | .lazy => |arena| { |
| 2640 | | if (!struct_obj.haveLayout()) { |
| 2641 | | return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(arena, ty) }; |
| 2642 | | } |
| 2575 | .array => { |
| 2576 | const payload = ty.castTag(.array).?.data; |
| 2577 | switch (try payload.elem_type.abiSizeAdvanced(mod, strat)) { |
| 2578 | .scalar => |elem_size| return AbiSizeAdvanced{ .scalar = payload.len * elem_size }, |
| 2579 | .val => switch (strat) { |
| 2580 | .sema => unreachable, |
| 2581 | .eager => unreachable, |
| 2582 | .lazy => |arena| return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(arena, ty) }, |
| 2643 | 2583 | }, |
| 2644 | | .eager => {}, |
| 2645 | 2584 | } |
| 2646 | | assert(struct_obj.haveLayout()); |
| 2647 | | return AbiSizeAdvanced{ .scalar = struct_obj.backing_int_ty.abiSize(mod) }; |
| 2648 | 2585 | }, |
| 2649 | | else => { |
| 2650 | | switch (strat) { |
| 2651 | | .sema => |sema| try sema.resolveTypeLayout(ty), |
| 2652 | | .lazy => |arena| { |
| 2653 | | if (ty.castTag(.@"struct")) |payload| { |
| 2654 | | const struct_obj = payload.data; |
| 2655 | | if (!struct_obj.haveLayout()) { |
| 2656 | | return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(arena, ty) }; |
| 2657 | | } |
| 2658 | | } |
| 2586 | .array_sentinel => { |
| 2587 | const payload = ty.castTag(.array_sentinel).?.data; |
| 2588 | switch (try payload.elem_type.abiSizeAdvanced(mod, strat)) { |
| 2589 | .scalar => |elem_size| return AbiSizeAdvanced{ .scalar = (payload.len + 1) * elem_size }, |
| 2590 | .val => switch (strat) { |
| 2591 | .sema => unreachable, |
| 2592 | .eager => unreachable, |
| 2593 | .lazy => |arena| return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(arena, ty) }, |
| 2659 | 2594 | }, |
| 2660 | | .eager => {}, |
| 2661 | 2595 | } |
| 2662 | | const field_count = ty.structFieldCount(); |
| 2663 | | if (field_count == 0) { |
| 2664 | | return AbiSizeAdvanced{ .scalar = 0 }; |
| 2665 | | } |
| 2666 | | return AbiSizeAdvanced{ .scalar = ty.structFieldOffset(field_count, mod) }; |
| 2667 | 2596 | }, |
| 2668 | | }, |
| 2669 | 2597 | |
| 2670 | | .enum_simple, .enum_full, .enum_nonexhaustive, .enum_numbered => { |
| 2671 | | const int_tag_ty = try ty.intTagType(mod); |
| 2672 | | return AbiSizeAdvanced{ .scalar = int_tag_ty.abiSize(mod) }; |
| 2673 | | }, |
| 2674 | | .@"union" => { |
| 2675 | | const union_obj = ty.castTag(.@"union").?.data; |
| 2676 | | return abiSizeAdvancedUnion(ty, mod, strat, union_obj, false); |
| 2677 | | }, |
| 2678 | | .union_safety_tagged, .union_tagged => { |
| 2679 | | const union_obj = ty.cast(Payload.Union).?.data; |
| 2680 | | return abiSizeAdvancedUnion(ty, mod, strat, union_obj, true); |
| 2681 | | }, |
| 2598 | .anyframe_T => return AbiSizeAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) }, |
| 2682 | 2599 | |
| 2683 | | .array => { |
| 2684 | | const payload = ty.castTag(.array).?.data; |
| 2685 | | switch (try payload.elem_type.abiSizeAdvanced(mod, strat)) { |
| 2686 | | .scalar => |elem_size| return AbiSizeAdvanced{ .scalar = payload.len * elem_size }, |
| 2687 | | .val => switch (strat) { |
| 2688 | | .sema => unreachable, |
| 2689 | | .eager => unreachable, |
| 2690 | | .lazy => |arena| return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(arena, ty) }, |
| 2691 | | }, |
| 2692 | | } |
| 2693 | | }, |
| 2694 | | .array_sentinel => { |
| 2695 | | const payload = ty.castTag(.array_sentinel).?.data; |
| 2696 | | switch (try payload.elem_type.abiSizeAdvanced(mod, strat)) { |
| 2697 | | .scalar => |elem_size| return AbiSizeAdvanced{ .scalar = (payload.len + 1) * elem_size }, |
| 2698 | | .val => switch (strat) { |
| 2699 | | .sema => unreachable, |
| 2700 | | .eager => unreachable, |
| 2701 | | .lazy => |arena| return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(arena, ty) }, |
| 2702 | | }, |
| 2703 | | } |
| 2704 | | }, |
| 2600 | .pointer => switch (ty.castTag(.pointer).?.data.size) { |
| 2601 | .Slice => return AbiSizeAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) * 2 }, |
| 2602 | else => return AbiSizeAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) }, |
| 2603 | }, |
| 2705 | 2604 | |
| 2706 | | .anyframe_T => return AbiSizeAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) }, |
| 2605 | // TODO revisit this when we have the concept of the error tag type |
| 2606 | .error_set_inferred, |
| 2607 | .error_set, |
| 2608 | .error_set_merged, |
| 2609 | .error_set_single, |
| 2610 | => return AbiSizeAdvanced{ .scalar = 2 }, |
| 2707 | 2611 | |
| 2708 | | .pointer => switch (ty.castTag(.pointer).?.data.size) { |
| 2709 | | .Slice => return AbiSizeAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) * 2 }, |
| 2710 | | else => return AbiSizeAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) }, |
| 2711 | | }, |
| 2612 | .optional => return ty.abiSizeAdvancedOptional(mod, strat), |
| 2712 | 2613 | |
| 2713 | | // TODO revisit this when we have the concept of the error tag type |
| 2714 | | .error_set_inferred, |
| 2715 | | .error_set, |
| 2716 | | .error_set_merged, |
| 2717 | | .error_set_single, |
| 2718 | | => return AbiSizeAdvanced{ .scalar = 2 }, |
| 2614 | .error_union => { |
| 2615 | // This code needs to be kept in sync with the equivalent switch prong |
| 2616 | // in abiAlignmentAdvanced. |
| 2617 | const data = ty.castTag(.error_union).?.data; |
| 2618 | const code_size = abiSize(Type.anyerror, mod); |
| 2619 | if (!(data.payload.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) { |
| 2620 | error.NeedLazy => return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(strat.lazy, ty) }, |
| 2621 | else => |e| return e, |
| 2622 | })) { |
| 2623 | // Same as anyerror. |
| 2624 | return AbiSizeAdvanced{ .scalar = code_size }; |
| 2625 | } |
| 2626 | const code_align = abiAlignment(Type.anyerror, mod); |
| 2627 | const payload_align = abiAlignment(data.payload, mod); |
| 2628 | const payload_size = switch (try data.payload.abiSizeAdvanced(mod, strat)) { |
| 2629 | .scalar => |elem_size| elem_size, |
| 2630 | .val => switch (strat) { |
| 2631 | .sema => unreachable, |
| 2632 | .eager => unreachable, |
| 2633 | .lazy => |arena| return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(arena, ty) }, |
| 2634 | }, |
| 2635 | }; |
| 2719 | 2636 | |
| 2720 | | .optional => return ty.abiSizeAdvancedOptional(mod, strat), |
| 2637 | var size: u64 = 0; |
| 2638 | if (code_align > payload_align) { |
| 2639 | size += code_size; |
| 2640 | size = std.mem.alignForwardGeneric(u64, size, payload_align); |
| 2641 | size += payload_size; |
| 2642 | size = std.mem.alignForwardGeneric(u64, size, code_align); |
| 2643 | } else { |
| 2644 | size += payload_size; |
| 2645 | size = std.mem.alignForwardGeneric(u64, size, code_align); |
| 2646 | size += code_size; |
| 2647 | size = std.mem.alignForwardGeneric(u64, size, payload_align); |
| 2648 | } |
| 2649 | return AbiSizeAdvanced{ .scalar = size }; |
| 2650 | }, |
| 2651 | }, |
| 2652 | else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 2653 | .int_type => |int_type| { |
| 2654 | if (int_type.bits == 0) return AbiSizeAdvanced{ .scalar = 0 }; |
| 2655 | return AbiSizeAdvanced{ .scalar = intAbiSize(int_type.bits, target) }; |
| 2656 | }, |
| 2657 | .ptr_type => |ptr_type| switch (ptr_type.size) { |
| 2658 | .Slice => return .{ .scalar = @divExact(target.ptrBitWidth(), 8) * 2 }, |
| 2659 | else => return .{ .scalar = @divExact(target.ptrBitWidth(), 8) }, |
| 2660 | }, |
| 2661 | .array_type => |array_type| { |
| 2662 | const len = array_type.len + @boolToInt(array_type.sentinel != .none); |
| 2663 | switch (try array_type.child.toType().abiSizeAdvanced(mod, strat)) { |
| 2664 | .scalar => |elem_size| return .{ .scalar = len * elem_size }, |
| 2665 | .val => switch (strat) { |
| 2666 | .sema, .eager => unreachable, |
| 2667 | .lazy => |arena| return .{ .val = try Value.Tag.lazy_size.create(arena, ty) }, |
| 2668 | }, |
| 2669 | } |
| 2670 | }, |
| 2671 | .vector_type => |vector_type| { |
| 2672 | const opt_sema = switch (strat) { |
| 2673 | .sema => |sema| sema, |
| 2674 | .eager => null, |
| 2675 | .lazy => |arena| return AbiSizeAdvanced{ |
| 2676 | .val = try Value.Tag.lazy_size.create(arena, ty), |
| 2677 | }, |
| 2678 | }; |
| 2679 | const elem_bits_u64 = try vector_type.child.toType().bitSizeAdvanced(mod, opt_sema); |
| 2680 | const elem_bits = @intCast(u32, elem_bits_u64); |
| 2681 | const total_bits = elem_bits * vector_type.len; |
| 2682 | const total_bytes = (total_bits + 7) / 8; |
| 2683 | const alignment = switch (try ty.abiAlignmentAdvanced(mod, strat)) { |
| 2684 | .scalar => |x| x, |
| 2685 | .val => return AbiSizeAdvanced{ |
| 2686 | .val = try Value.Tag.lazy_size.create(strat.lazy, ty), |
| 2687 | }, |
| 2688 | }; |
| 2689 | const result = std.mem.alignForwardGeneric(u32, total_bytes, alignment); |
| 2690 | return AbiSizeAdvanced{ .scalar = result }; |
| 2691 | }, |
| 2721 | 2692 | |
| 2722 | | .error_union => { |
| 2723 | | // This code needs to be kept in sync with the equivalent switch prong |
| 2724 | | // in abiAlignmentAdvanced. |
| 2725 | | const data = ty.castTag(.error_union).?.data; |
| 2726 | | const code_size = abiSize(Type.anyerror, mod); |
| 2727 | | if (!(data.payload.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) { |
| 2728 | | error.NeedLazy => return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(strat.lazy, ty) }, |
| 2729 | | else => |e| return e, |
| 2730 | | })) { |
| 2731 | | // Same as anyerror. |
| 2732 | | return AbiSizeAdvanced{ .scalar = code_size }; |
| 2733 | | } |
| 2734 | | const code_align = abiAlignment(Type.anyerror, mod); |
| 2735 | | const payload_align = abiAlignment(data.payload, mod); |
| 2736 | | const payload_size = switch (try data.payload.abiSizeAdvanced(mod, strat)) { |
| 2737 | | .scalar => |elem_size| elem_size, |
| 2738 | | .val => switch (strat) { |
| 2739 | | .sema => unreachable, |
| 2740 | | .eager => unreachable, |
| 2741 | | .lazy => |arena| return AbiSizeAdvanced{ .val = try Value.Tag.lazy_size.create(arena, ty) }, |
| 2693 | .opt_type => return ty.abiSizeAdvancedOptional(mod, strat), |
| 2694 | .error_union_type => @panic("TODO"), |
| 2695 | .simple_type => |t| switch (t) { |
| 2696 | .bool, |
| 2697 | .atomic_order, |
| 2698 | .atomic_rmw_op, |
| 2699 | .calling_convention, |
| 2700 | .address_space, |
| 2701 | .float_mode, |
| 2702 | .reduce_op, |
| 2703 | .call_modifier, |
| 2704 | => return AbiSizeAdvanced{ .scalar = 1 }, |
| 2705 | |
| 2706 | .f16 => return AbiSizeAdvanced{ .scalar = 2 }, |
| 2707 | .f32 => return AbiSizeAdvanced{ .scalar = 4 }, |
| 2708 | .f64 => return AbiSizeAdvanced{ .scalar = 8 }, |
| 2709 | .f128 => return AbiSizeAdvanced{ .scalar = 16 }, |
| 2710 | .f80 => switch (target.c_type_bit_size(.longdouble)) { |
| 2711 | 80 => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.longdouble) }, |
| 2712 | else => { |
| 2713 | const u80_ty: Type = .{ |
| 2714 | .ip_index = .u80_type, |
| 2715 | .legacy = undefined, |
| 2716 | }; |
| 2717 | return AbiSizeAdvanced{ .scalar = abiSize(u80_ty, mod) }; |
| 2718 | }, |
| 2742 | 2719 | }, |
| 2743 | | }; |
| 2744 | 2720 | |
| 2745 | | var size: u64 = 0; |
| 2746 | | if (code_align > payload_align) { |
| 2747 | | size += code_size; |
| 2748 | | size = std.mem.alignForwardGeneric(u64, size, payload_align); |
| 2749 | | size += payload_size; |
| 2750 | | size = std.mem.alignForwardGeneric(u64, size, code_align); |
| 2751 | | } else { |
| 2752 | | size += payload_size; |
| 2753 | | size = std.mem.alignForwardGeneric(u64, size, code_align); |
| 2754 | | size += code_size; |
| 2755 | | size = std.mem.alignForwardGeneric(u64, size, payload_align); |
| 2756 | | } |
| 2757 | | return AbiSizeAdvanced{ .scalar = size }; |
| 2721 | .usize, |
| 2722 | .isize, |
| 2723 | .@"anyframe", |
| 2724 | => return AbiSizeAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) }, |
| 2725 | |
| 2726 | .c_char => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.char) }, |
| 2727 | .c_short => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.short) }, |
| 2728 | .c_ushort => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.ushort) }, |
| 2729 | .c_int => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.int) }, |
| 2730 | .c_uint => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.uint) }, |
| 2731 | .c_long => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.long) }, |
| 2732 | .c_ulong => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.ulong) }, |
| 2733 | .c_longlong => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.longlong) }, |
| 2734 | .c_ulonglong => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.ulonglong) }, |
| 2735 | .c_longdouble => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.longdouble) }, |
| 2736 | |
| 2737 | .anyopaque, |
| 2738 | .void, |
| 2739 | .type, |
| 2740 | .comptime_int, |
| 2741 | .comptime_float, |
| 2742 | .null, |
| 2743 | .undefined, |
| 2744 | .enum_literal, |
| 2745 | => return AbiSizeAdvanced{ .scalar = 0 }, |
| 2746 | |
| 2747 | // TODO revisit this when we have the concept of the error tag type |
| 2748 | .anyerror => return AbiSizeAdvanced{ .scalar = 2 }, |
| 2749 | |
| 2750 | .prefetch_options => unreachable, // missing call to resolveTypeFields |
| 2751 | .export_options => unreachable, // missing call to resolveTypeFields |
| 2752 | .extern_options => unreachable, // missing call to resolveTypeFields |
| 2753 | |
| 2754 | .type_info => unreachable, |
| 2755 | .noreturn => unreachable, |
| 2756 | .generic_poison => unreachable, |
| 2757 | .var_args_param => unreachable, |
| 2758 | }, |
| 2759 | .struct_type => @panic("TODO"), |
| 2760 | .union_type => @panic("TODO"), |
| 2761 | .simple_value => unreachable, |
| 2762 | .extern_func => unreachable, |
| 2763 | .int => unreachable, |
| 2764 | .enum_tag => unreachable, // it's a value, not a type |
| 2758 | 2765 | }, |
| 2759 | 2766 | } |
| 2760 | 2767 | } |
| ... | ... | @@ -2929,7 +2936,6 @@ pub const Type = struct { |
| 2929 | 2936 | switch (ty.tag()) { |
| 2930 | 2937 | .function => unreachable, // represents machine code; not a pointer |
| 2931 | 2938 | .empty_struct => unreachable, |
| 2932 | | .empty_struct_literal => unreachable, |
| 2933 | 2939 | .inferred_alloc_const => unreachable, |
| 2934 | 2940 | .inferred_alloc_mut => unreachable, |
| 2935 | 2941 | .@"opaque" => unreachable, |
| ... | ... | @@ -3490,12 +3496,16 @@ pub const Type = struct { |
| 3490 | 3496 | } |
| 3491 | 3497 | |
| 3492 | 3498 | pub fn containerLayout(ty: Type) std.builtin.Type.ContainerLayout { |
| 3493 | | return switch (ty.tag()) { |
| 3494 | | .tuple, .empty_struct_literal, .anon_struct => .Auto, |
| 3495 | | .@"struct" => ty.castTag(.@"struct").?.data.layout, |
| 3496 | | .@"union" => ty.castTag(.@"union").?.data.layout, |
| 3497 | | .union_safety_tagged => ty.castTag(.union_safety_tagged).?.data.layout, |
| 3498 | | .union_tagged => ty.castTag(.union_tagged).?.data.layout, |
| 3499 | return switch (ty.ip_index) { |
| 3500 | .empty_struct_type => .Auto, |
| 3501 | .none => switch (ty.tag()) { |
| 3502 | .tuple, .anon_struct => .Auto, |
| 3503 | .@"struct" => ty.castTag(.@"struct").?.data.layout, |
| 3504 | .@"union" => ty.castTag(.@"union").?.data.layout, |
| 3505 | .union_safety_tagged => ty.castTag(.union_safety_tagged).?.data.layout, |
| 3506 | .union_tagged => ty.castTag(.union_tagged).?.data.layout, |
| 3507 | else => unreachable, |
| 3508 | }, |
| 3499 | 3509 | else => unreachable, |
| 3500 | 3510 | }; |
| 3501 | 3511 | } |
| ... | ... | @@ -3610,13 +3620,14 @@ pub const Type = struct { |
| 3610 | 3620 | |
| 3611 | 3621 | pub fn arrayLenIp(ty: Type, ip: InternPool) u64 { |
| 3612 | 3622 | return switch (ty.ip_index) { |
| 3623 | .empty_struct_type => 0, |
| 3613 | 3624 | .none => switch (ty.tag()) { |
| 3614 | 3625 | .array => ty.castTag(.array).?.data.len, |
| 3615 | 3626 | .array_sentinel => ty.castTag(.array_sentinel).?.data.len, |
| 3616 | 3627 | .tuple => ty.castTag(.tuple).?.data.types.len, |
| 3617 | 3628 | .anon_struct => ty.castTag(.anon_struct).?.data.types.len, |
| 3618 | 3629 | .@"struct" => ty.castTag(.@"struct").?.data.fields.count(), |
| 3619 | | .empty_struct, .empty_struct_literal => 0, |
| 3630 | .empty_struct => 0, |
| 3620 | 3631 | |
| 3621 | 3632 | else => unreachable, |
| 3622 | 3633 | }, |
| ... | ... | @@ -3649,10 +3660,10 @@ pub const Type = struct { |
| 3649 | 3660 | /// Asserts the type is an array, pointer or vector. |
| 3650 | 3661 | pub fn sentinel(ty: Type, mod: *const Module) ?Value { |
| 3651 | 3662 | return switch (ty.ip_index) { |
| 3663 | .empty_struct_type => null, |
| 3652 | 3664 | .none => switch (ty.tag()) { |
| 3653 | 3665 | .array, |
| 3654 | 3666 | .tuple, |
| 3655 | | .empty_struct_literal, |
| 3656 | 3667 | .@"struct", |
| 3657 | 3668 | => null, |
| 3658 | 3669 | |
| ... | ... | @@ -3951,197 +3962,200 @@ pub const Type = struct { |
| 3951 | 3962 | pub fn onePossibleValue(starting_type: Type, mod: *Module) !?Value { |
| 3952 | 3963 | var ty = starting_type; |
| 3953 | 3964 | |
| 3954 | | if (ty.ip_index != .none) switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 3955 | | .int_type => |int_type| { |
| 3956 | | if (int_type.bits == 0) { |
| 3957 | | return try mod.intValue(ty, 0); |
| 3958 | | } else { |
| 3959 | | return null; |
| 3960 | | } |
| 3961 | | }, |
| 3962 | | .ptr_type => return null, |
| 3963 | | .array_type => |array_type| { |
| 3964 | | if (array_type.len == 0) |
| 3965 | | return Value.initTag(.empty_array); |
| 3966 | | if ((try array_type.child.toType().onePossibleValue(mod)) != null) |
| 3967 | | return Value.initTag(.the_only_possible_value); |
| 3968 | | return null; |
| 3969 | | }, |
| 3970 | | .vector_type => |vector_type| { |
| 3971 | | if (vector_type.len == 0) return Value.initTag(.empty_array); |
| 3972 | | if (try vector_type.child.toType().onePossibleValue(mod)) |v| return v; |
| 3973 | | return null; |
| 3974 | | }, |
| 3975 | | .opt_type => |child| { |
| 3976 | | if (child.toType().isNoReturn()) { |
| 3977 | | return Value.null; |
| 3978 | | } else { |
| 3979 | | return null; |
| 3980 | | } |
| 3981 | | }, |
| 3982 | | .error_union_type => return null, |
| 3983 | | .simple_type => |t| switch (t) { |
| 3984 | | .f16, |
| 3985 | | .f32, |
| 3986 | | .f64, |
| 3987 | | .f80, |
| 3988 | | .f128, |
| 3989 | | .usize, |
| 3990 | | .isize, |
| 3991 | | .c_char, |
| 3992 | | .c_short, |
| 3993 | | .c_ushort, |
| 3994 | | .c_int, |
| 3995 | | .c_uint, |
| 3996 | | .c_long, |
| 3997 | | .c_ulong, |
| 3998 | | .c_longlong, |
| 3999 | | .c_ulonglong, |
| 4000 | | .c_longdouble, |
| 4001 | | .anyopaque, |
| 4002 | | .bool, |
| 4003 | | .type, |
| 4004 | | .anyerror, |
| 4005 | | .comptime_int, |
| 4006 | | .comptime_float, |
| 4007 | | .@"anyframe", |
| 4008 | | .enum_literal, |
| 4009 | | .atomic_order, |
| 4010 | | .atomic_rmw_op, |
| 4011 | | .calling_convention, |
| 4012 | | .address_space, |
| 4013 | | .float_mode, |
| 4014 | | .reduce_op, |
| 4015 | | .call_modifier, |
| 4016 | | .prefetch_options, |
| 4017 | | .export_options, |
| 4018 | | .extern_options, |
| 4019 | | .type_info, |
| 3965 | while (true) switch (ty.ip_index) { |
| 3966 | .empty_struct_type => return Value.empty_struct, |
| 3967 | |
| 3968 | .none => switch (ty.tag()) { |
| 3969 | .error_union, |
| 3970 | .error_set_single, |
| 3971 | .error_set, |
| 3972 | .error_set_merged, |
| 3973 | .function, |
| 3974 | .array_sentinel, |
| 3975 | .error_set_inferred, |
| 3976 | .@"opaque", |
| 3977 | .anyframe_T, |
| 3978 | .pointer, |
| 4020 | 3979 | => return null, |
| 4021 | 3980 | |
| 4022 | | .void => return Value.void, |
| 4023 | | .noreturn => return Value.@"unreachable", |
| 4024 | | .null => return Value.null, |
| 4025 | | .undefined => return Value.undef, |
| 3981 | .optional => { |
| 3982 | const child_ty = ty.optionalChild(mod); |
| 3983 | if (child_ty.isNoReturn()) { |
| 3984 | return Value.null; |
| 3985 | } else { |
| 3986 | return null; |
| 3987 | } |
| 3988 | }, |
| 4026 | 3989 | |
| 4027 | | .generic_poison => unreachable, |
| 4028 | | .var_args_param => unreachable, |
| 4029 | | }, |
| 4030 | | .struct_type => @panic("TODO"), |
| 4031 | | .union_type => @panic("TODO"), |
| 4032 | | .simple_value => unreachable, |
| 4033 | | .extern_func => unreachable, |
| 4034 | | .int => unreachable, |
| 4035 | | .enum_tag => unreachable, // it's a value, not a type |
| 4036 | | }; |
| 3990 | .@"struct" => { |
| 3991 | const s = ty.castTag(.@"struct").?.data; |
| 3992 | assert(s.haveFieldTypes()); |
| 3993 | for (s.fields.values()) |field| { |
| 3994 | if (field.is_comptime) continue; |
| 3995 | if ((try field.ty.onePossibleValue(mod)) != null) continue; |
| 3996 | return null; |
| 3997 | } |
| 3998 | return Value.empty_struct; |
| 3999 | }, |
| 4037 | 4000 | |
| 4038 | | while (true) switch (ty.tag()) { |
| 4039 | | .error_union, |
| 4040 | | .error_set_single, |
| 4041 | | .error_set, |
| 4042 | | .error_set_merged, |
| 4043 | | .function, |
| 4044 | | .array_sentinel, |
| 4045 | | .error_set_inferred, |
| 4046 | | .@"opaque", |
| 4047 | | .anyframe_T, |
| 4048 | | .pointer, |
| 4049 | | => return null, |
| 4001 | .tuple, .anon_struct => { |
| 4002 | const tuple = ty.tupleFields(); |
| 4003 | for (tuple.values, 0..) |val, i| { |
| 4004 | const is_comptime = val.ip_index != .unreachable_value; |
| 4005 | if (is_comptime) continue; |
| 4006 | if ((try tuple.types[i].onePossibleValue(mod)) != null) continue; |
| 4007 | return null; |
| 4008 | } |
| 4009 | return Value.empty_struct; |
| 4010 | }, |
| 4011 | |
| 4012 | .enum_numbered => { |
| 4013 | const enum_numbered = ty.castTag(.enum_numbered).?.data; |
| 4014 | // An explicit tag type is always provided for enum_numbered. |
| 4015 | if (enum_numbered.tag_ty.hasRuntimeBits(mod)) { |
| 4016 | return null; |
| 4017 | } |
| 4018 | assert(enum_numbered.fields.count() == 1); |
| 4019 | return enum_numbered.values.keys()[0]; |
| 4020 | }, |
| 4021 | .enum_full => { |
| 4022 | const enum_full = ty.castTag(.enum_full).?.data; |
| 4023 | if (enum_full.tag_ty.hasRuntimeBits(mod)) { |
| 4024 | return null; |
| 4025 | } |
| 4026 | switch (enum_full.fields.count()) { |
| 4027 | 0 => return Value.@"unreachable", |
| 4028 | 1 => if (enum_full.values.count() == 0) { |
| 4029 | return try mod.intValue(ty, 0); // auto-numbered |
| 4030 | } else { |
| 4031 | return enum_full.values.keys()[0]; |
| 4032 | }, |
| 4033 | else => return null, |
| 4034 | } |
| 4035 | }, |
| 4036 | .enum_simple => { |
| 4037 | const enum_simple = ty.castTag(.enum_simple).?.data; |
| 4038 | switch (enum_simple.fields.count()) { |
| 4039 | 0 => return Value.@"unreachable", |
| 4040 | 1 => return try mod.intValue(ty, 0), |
| 4041 | else => return null, |
| 4042 | } |
| 4043 | }, |
| 4044 | .enum_nonexhaustive => { |
| 4045 | const tag_ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty; |
| 4046 | if (!tag_ty.hasRuntimeBits(mod)) { |
| 4047 | return try mod.intValue(ty, 0); |
| 4048 | } else { |
| 4049 | return null; |
| 4050 | } |
| 4051 | }, |
| 4052 | .@"union", .union_safety_tagged, .union_tagged => { |
| 4053 | const union_obj = ty.cast(Payload.Union).?.data; |
| 4054 | const tag_val = (try union_obj.tag_ty.onePossibleValue(mod)) orelse return null; |
| 4055 | if (union_obj.fields.count() == 0) return Value.@"unreachable"; |
| 4056 | const only_field = union_obj.fields.values()[0]; |
| 4057 | const val_val = (try only_field.ty.onePossibleValue(mod)) orelse return null; |
| 4058 | _ = tag_val; |
| 4059 | _ = val_val; |
| 4060 | return Value.empty_struct; |
| 4061 | }, |
| 4050 | 4062 | |
| 4051 | | .optional => { |
| 4052 | | const child_ty = ty.optionalChild(mod); |
| 4053 | | if (child_ty.isNoReturn()) { |
| 4054 | | return Value.null; |
| 4055 | | } else { |
| 4056 | | return null; |
| 4057 | | } |
| 4058 | | }, |
| 4063 | .empty_struct => return Value.empty_struct, |
| 4059 | 4064 | |
| 4060 | | .@"struct" => { |
| 4061 | | const s = ty.castTag(.@"struct").?.data; |
| 4062 | | assert(s.haveFieldTypes()); |
| 4063 | | for (s.fields.values()) |field| { |
| 4064 | | if (field.is_comptime) continue; |
| 4065 | | if ((try field.ty.onePossibleValue(mod)) != null) continue; |
| 4065 | .array => { |
| 4066 | if (ty.arrayLen(mod) == 0) |
| 4067 | return Value.initTag(.empty_array); |
| 4068 | if ((try ty.childType(mod).onePossibleValue(mod)) != null) |
| 4069 | return Value.initTag(.the_only_possible_value); |
| 4066 | 4070 | return null; |
| 4067 | | } |
| 4068 | | return Value.initTag(.empty_struct_value); |
| 4069 | | }, |
| 4071 | }, |
| 4070 | 4072 | |
| 4071 | | .tuple, .anon_struct => { |
| 4072 | | const tuple = ty.tupleFields(); |
| 4073 | | for (tuple.values, 0..) |val, i| { |
| 4074 | | const is_comptime = val.ip_index != .unreachable_value; |
| 4075 | | if (is_comptime) continue; |
| 4076 | | if ((try tuple.types[i].onePossibleValue(mod)) != null) continue; |
| 4077 | | return null; |
| 4078 | | } |
| 4079 | | return Value.initTag(.empty_struct_value); |
| 4073 | .inferred_alloc_const => unreachable, |
| 4074 | .inferred_alloc_mut => unreachable, |
| 4080 | 4075 | }, |
| 4081 | | |
| 4082 | | .enum_numbered => { |
| 4083 | | const enum_numbered = ty.castTag(.enum_numbered).?.data; |
| 4084 | | // An explicit tag type is always provided for enum_numbered. |
| 4085 | | if (enum_numbered.tag_ty.hasRuntimeBits(mod)) { |
| 4076 | else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 4077 | .int_type => |int_type| { |
| 4078 | if (int_type.bits == 0) { |
| 4079 | return try mod.intValue(ty, 0); |
| 4080 | } else { |
| 4081 | return null; |
| 4082 | } |
| 4083 | }, |
| 4084 | .ptr_type => return null, |
| 4085 | .array_type => |array_type| { |
| 4086 | if (array_type.len == 0) |
| 4087 | return Value.initTag(.empty_array); |
| 4088 | if ((try array_type.child.toType().onePossibleValue(mod)) != null) |
| 4089 | return Value.initTag(.the_only_possible_value); |
| 4086 | 4090 | return null; |
| 4087 | | } |
| 4088 | | assert(enum_numbered.fields.count() == 1); |
| 4089 | | return enum_numbered.values.keys()[0]; |
| 4090 | | }, |
| 4091 | | .enum_full => { |
| 4092 | | const enum_full = ty.castTag(.enum_full).?.data; |
| 4093 | | if (enum_full.tag_ty.hasRuntimeBits(mod)) { |
| 4091 | }, |
| 4092 | .vector_type => |vector_type| { |
| 4093 | if (vector_type.len == 0) return Value.initTag(.empty_array); |
| 4094 | if (try vector_type.child.toType().onePossibleValue(mod)) |v| return v; |
| 4094 | 4095 | return null; |
| 4095 | | } |
| 4096 | | switch (enum_full.fields.count()) { |
| 4097 | | 0 => return Value.@"unreachable", |
| 4098 | | 1 => if (enum_full.values.count() == 0) { |
| 4099 | | return try mod.intValue(ty, 0); // auto-numbered |
| 4096 | }, |
| 4097 | .opt_type => |child| { |
| 4098 | if (child.toType().isNoReturn()) { |
| 4099 | return Value.null; |
| 4100 | 4100 | } else { |
| 4101 | | return enum_full.values.keys()[0]; |
| 4102 | | }, |
| 4103 | | else => return null, |
| 4104 | | } |
| 4105 | | }, |
| 4106 | | .enum_simple => { |
| 4107 | | const enum_simple = ty.castTag(.enum_simple).?.data; |
| 4108 | | switch (enum_simple.fields.count()) { |
| 4109 | | 0 => return Value.@"unreachable", |
| 4110 | | 1 => return try mod.intValue(ty, 0), |
| 4111 | | else => return null, |
| 4112 | | } |
| 4113 | | }, |
| 4114 | | .enum_nonexhaustive => { |
| 4115 | | const tag_ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty; |
| 4116 | | if (!tag_ty.hasRuntimeBits(mod)) { |
| 4117 | | return try mod.intValue(ty, 0); |
| 4118 | | } else { |
| 4119 | | return null; |
| 4120 | | } |
| 4121 | | }, |
| 4122 | | .@"union", .union_safety_tagged, .union_tagged => { |
| 4123 | | const union_obj = ty.cast(Payload.Union).?.data; |
| 4124 | | const tag_val = (try union_obj.tag_ty.onePossibleValue(mod)) orelse return null; |
| 4125 | | if (union_obj.fields.count() == 0) return Value.@"unreachable"; |
| 4126 | | const only_field = union_obj.fields.values()[0]; |
| 4127 | | const val_val = (try only_field.ty.onePossibleValue(mod)) orelse return null; |
| 4128 | | _ = tag_val; |
| 4129 | | _ = val_val; |
| 4130 | | return Value.initTag(.empty_struct_value); |
| 4131 | | }, |
| 4101 | return null; |
| 4102 | } |
| 4103 | }, |
| 4104 | .error_union_type => return null, |
| 4105 | .simple_type => |t| switch (t) { |
| 4106 | .f16, |
| 4107 | .f32, |
| 4108 | .f64, |
| 4109 | .f80, |
| 4110 | .f128, |
| 4111 | .usize, |
| 4112 | .isize, |
| 4113 | .c_char, |
| 4114 | .c_short, |
| 4115 | .c_ushort, |
| 4116 | .c_int, |
| 4117 | .c_uint, |
| 4118 | .c_long, |
| 4119 | .c_ulong, |
| 4120 | .c_longlong, |
| 4121 | .c_ulonglong, |
| 4122 | .c_longdouble, |
| 4123 | .anyopaque, |
| 4124 | .bool, |
| 4125 | .type, |
| 4126 | .anyerror, |
| 4127 | .comptime_int, |
| 4128 | .comptime_float, |
| 4129 | .@"anyframe", |
| 4130 | .enum_literal, |
| 4131 | .atomic_order, |
| 4132 | .atomic_rmw_op, |
| 4133 | .calling_convention, |
| 4134 | .address_space, |
| 4135 | .float_mode, |
| 4136 | .reduce_op, |
| 4137 | .call_modifier, |
| 4138 | .prefetch_options, |
| 4139 | .export_options, |
| 4140 | .extern_options, |
| 4141 | .type_info, |
| 4142 | => return null, |
| 4132 | 4143 | |
| 4133 | | .empty_struct, .empty_struct_literal => return Value.initTag(.empty_struct_value), |
| 4144 | .void => return Value.void, |
| 4145 | .noreturn => return Value.@"unreachable", |
| 4146 | .null => return Value.null, |
| 4147 | .undefined => return Value.undef, |
| 4134 | 4148 | |
| 4135 | | .array => { |
| 4136 | | if (ty.arrayLen(mod) == 0) |
| 4137 | | return Value.initTag(.empty_array); |
| 4138 | | if ((try ty.childType(mod).onePossibleValue(mod)) != null) |
| 4139 | | return Value.initTag(.the_only_possible_value); |
| 4140 | | return null; |
| 4149 | .generic_poison => unreachable, |
| 4150 | .var_args_param => unreachable, |
| 4151 | }, |
| 4152 | .struct_type => @panic("TODO"), |
| 4153 | .union_type => @panic("TODO"), |
| 4154 | .simple_value => unreachable, |
| 4155 | .extern_func => unreachable, |
| 4156 | .int => unreachable, |
| 4157 | .enum_tag => unreachable, // it's a value, not a type |
| 4141 | 4158 | }, |
| 4142 | | |
| 4143 | | .inferred_alloc_const => unreachable, |
| 4144 | | .inferred_alloc_mut => unreachable, |
| 4145 | 4159 | }; |
| 4146 | 4160 | } |
| 4147 | 4161 | |
| ... | ... | @@ -4150,159 +4164,161 @@ pub const Type = struct { |
| 4150 | 4164 | /// TODO merge these implementations together with the "advanced" pattern seen |
| 4151 | 4165 | /// elsewhere in this file. |
| 4152 | 4166 | pub fn comptimeOnly(ty: Type, mod: *const Module) bool { |
| 4153 | | if (ty.ip_index != .none) return switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 4154 | | .int_type => false, |
| 4155 | | .ptr_type => |ptr_type| { |
| 4156 | | const child_ty = ptr_type.elem_type.toType(); |
| 4157 | | if (child_ty.zigTypeTag(mod) == .Fn) { |
| 4158 | | return false; |
| 4159 | | } else { |
| 4160 | | return child_ty.comptimeOnly(mod); |
| 4161 | | } |
| 4162 | | }, |
| 4163 | | .array_type => |array_type| array_type.child.toType().comptimeOnly(mod), |
| 4164 | | .vector_type => |vector_type| vector_type.child.toType().comptimeOnly(mod), |
| 4165 | | .opt_type => |child| child.toType().comptimeOnly(mod), |
| 4166 | | .error_union_type => |error_union_type| error_union_type.payload_type.toType().comptimeOnly(mod), |
| 4167 | | .simple_type => |t| switch (t) { |
| 4168 | | .f16, |
| 4169 | | .f32, |
| 4170 | | .f64, |
| 4171 | | .f80, |
| 4172 | | .f128, |
| 4173 | | .usize, |
| 4174 | | .isize, |
| 4175 | | .c_char, |
| 4176 | | .c_short, |
| 4177 | | .c_ushort, |
| 4178 | | .c_int, |
| 4179 | | .c_uint, |
| 4180 | | .c_long, |
| 4181 | | .c_ulong, |
| 4182 | | .c_longlong, |
| 4183 | | .c_ulonglong, |
| 4184 | | .c_longdouble, |
| 4185 | | .anyopaque, |
| 4186 | | .bool, |
| 4187 | | .void, |
| 4188 | | .anyerror, |
| 4189 | | .@"anyframe", |
| 4190 | | .noreturn, |
| 4191 | | .generic_poison, |
| 4192 | | .atomic_order, |
| 4193 | | .atomic_rmw_op, |
| 4194 | | .calling_convention, |
| 4195 | | .address_space, |
| 4196 | | .float_mode, |
| 4197 | | .reduce_op, |
| 4198 | | .call_modifier, |
| 4199 | | .prefetch_options, |
| 4200 | | .export_options, |
| 4201 | | .extern_options, |
| 4202 | | => false, |
| 4167 | return switch (ty.ip_index) { |
| 4168 | .empty_struct_type => false, |
| 4203 | 4169 | |
| 4204 | | .type, |
| 4205 | | .comptime_int, |
| 4206 | | .comptime_float, |
| 4207 | | .null, |
| 4208 | | .undefined, |
| 4209 | | .enum_literal, |
| 4210 | | .type_info, |
| 4211 | | => true, |
| 4170 | .none => switch (ty.tag()) { |
| 4171 | .empty_struct, |
| 4172 | .error_set, |
| 4173 | .error_set_single, |
| 4174 | .error_set_inferred, |
| 4175 | .error_set_merged, |
| 4176 | .@"opaque", |
| 4177 | .enum_simple, |
| 4178 | => false, |
| 4212 | 4179 | |
| 4213 | | .var_args_param => unreachable, |
| 4214 | | }, |
| 4215 | | .struct_type => @panic("TODO"), |
| 4216 | | .union_type => @panic("TODO"), |
| 4217 | | .simple_value => unreachable, |
| 4218 | | .extern_func => unreachable, |
| 4219 | | .int => unreachable, |
| 4220 | | .enum_tag => unreachable, // it's a value, not a type |
| 4221 | | }; |
| 4180 | // These are function bodies, not function pointers. |
| 4181 | .function => true, |
| 4222 | 4182 | |
| 4223 | | return switch (ty.tag()) { |
| 4224 | | .empty_struct_literal, |
| 4225 | | .empty_struct, |
| 4226 | | .error_set, |
| 4227 | | .error_set_single, |
| 4228 | | .error_set_inferred, |
| 4229 | | .error_set_merged, |
| 4230 | | .@"opaque", |
| 4231 | | .enum_simple, |
| 4232 | | => false, |
| 4183 | .inferred_alloc_mut => unreachable, |
| 4184 | .inferred_alloc_const => unreachable, |
| 4233 | 4185 | |
| 4234 | | // These are function bodies, not function pointers. |
| 4235 | | .function => true, |
| 4186 | .array, |
| 4187 | .array_sentinel, |
| 4188 | => return ty.childType(mod).comptimeOnly(mod), |
| 4236 | 4189 | |
| 4237 | | .inferred_alloc_mut => unreachable, |
| 4238 | | .inferred_alloc_const => unreachable, |
| 4190 | .pointer => { |
| 4191 | const child_ty = ty.childType(mod); |
| 4192 | if (child_ty.zigTypeTag(mod) == .Fn) { |
| 4193 | return false; |
| 4194 | } else { |
| 4195 | return child_ty.comptimeOnly(mod); |
| 4196 | } |
| 4197 | }, |
| 4239 | 4198 | |
| 4240 | | .array, |
| 4241 | | .array_sentinel, |
| 4242 | | => return ty.childType(mod).comptimeOnly(mod), |
| 4199 | .optional => { |
| 4200 | return ty.optionalChild(mod).comptimeOnly(mod); |
| 4201 | }, |
| 4243 | 4202 | |
| 4244 | | .pointer => { |
| 4245 | | const child_ty = ty.childType(mod); |
| 4246 | | if (child_ty.zigTypeTag(mod) == .Fn) { |
| 4203 | .tuple, .anon_struct => { |
| 4204 | const tuple = ty.tupleFields(); |
| 4205 | for (tuple.types, 0..) |field_ty, i| { |
| 4206 | const have_comptime_val = tuple.values[i].ip_index != .unreachable_value; |
| 4207 | if (!have_comptime_val and field_ty.comptimeOnly(mod)) return true; |
| 4208 | } |
| 4247 | 4209 | return false; |
| 4248 | | } else { |
| 4249 | | return child_ty.comptimeOnly(mod); |
| 4250 | | } |
| 4251 | | }, |
| 4210 | }, |
| 4252 | 4211 | |
| 4253 | | .optional => { |
| 4254 | | return ty.optionalChild(mod).comptimeOnly(mod); |
| 4255 | | }, |
| 4212 | .@"struct" => { |
| 4213 | const struct_obj = ty.castTag(.@"struct").?.data; |
| 4214 | switch (struct_obj.requires_comptime) { |
| 4215 | .wip, .unknown => { |
| 4216 | // Return false to avoid incorrect dependency loops. |
| 4217 | // This will be handled correctly once merged with |
| 4218 | // `Sema.typeRequiresComptime`. |
| 4219 | return false; |
| 4220 | }, |
| 4221 | .no => return false, |
| 4222 | .yes => return true, |
| 4223 | } |
| 4224 | }, |
| 4256 | 4225 | |
| 4257 | | .tuple, .anon_struct => { |
| 4258 | | const tuple = ty.tupleFields(); |
| 4259 | | for (tuple.types, 0..) |field_ty, i| { |
| 4260 | | const have_comptime_val = tuple.values[i].ip_index != .unreachable_value; |
| 4261 | | if (!have_comptime_val and field_ty.comptimeOnly(mod)) return true; |
| 4262 | | } |
| 4263 | | return false; |
| 4264 | | }, |
| 4226 | .@"union", .union_safety_tagged, .union_tagged => { |
| 4227 | const union_obj = ty.cast(Type.Payload.Union).?.data; |
| 4228 | switch (union_obj.requires_comptime) { |
| 4229 | .wip, .unknown => { |
| 4230 | // Return false to avoid incorrect dependency loops. |
| 4231 | // This will be handled correctly once merged with |
| 4232 | // `Sema.typeRequiresComptime`. |
| 4233 | return false; |
| 4234 | }, |
| 4235 | .no => return false, |
| 4236 | .yes => return true, |
| 4237 | } |
| 4238 | }, |
| 4265 | 4239 | |
| 4266 | | .@"struct" => { |
| 4267 | | const struct_obj = ty.castTag(.@"struct").?.data; |
| 4268 | | switch (struct_obj.requires_comptime) { |
| 4269 | | .wip, .unknown => { |
| 4270 | | // Return false to avoid incorrect dependency loops. |
| 4271 | | // This will be handled correctly once merged with |
| 4272 | | // `Sema.typeRequiresComptime`. |
| 4273 | | return false; |
| 4274 | | }, |
| 4275 | | .no => return false, |
| 4276 | | .yes => return true, |
| 4277 | | } |
| 4240 | .error_union => return ty.errorUnionPayload().comptimeOnly(mod), |
| 4241 | .anyframe_T => { |
| 4242 | const child_ty = ty.castTag(.anyframe_T).?.data; |
| 4243 | return child_ty.comptimeOnly(mod); |
| 4244 | }, |
| 4245 | .enum_numbered => { |
| 4246 | const tag_ty = ty.castTag(.enum_numbered).?.data.tag_ty; |
| 4247 | return tag_ty.comptimeOnly(mod); |
| 4248 | }, |
| 4249 | .enum_full, .enum_nonexhaustive => { |
| 4250 | const tag_ty = ty.cast(Type.Payload.EnumFull).?.data.tag_ty; |
| 4251 | return tag_ty.comptimeOnly(mod); |
| 4252 | }, |
| 4278 | 4253 | }, |
| 4279 | | |
| 4280 | | .@"union", .union_safety_tagged, .union_tagged => { |
| 4281 | | const union_obj = ty.cast(Type.Payload.Union).?.data; |
| 4282 | | switch (union_obj.requires_comptime) { |
| 4283 | | .wip, .unknown => { |
| 4284 | | // Return false to avoid incorrect dependency loops. |
| 4285 | | // This will be handled correctly once merged with |
| 4286 | | // `Sema.typeRequiresComptime`. |
| 4254 | else => switch (mod.intern_pool.indexToKey(ty.ip_index)) { |
| 4255 | .int_type => false, |
| 4256 | .ptr_type => |ptr_type| { |
| 4257 | const child_ty = ptr_type.elem_type.toType(); |
| 4258 | if (child_ty.zigTypeTag(mod) == .Fn) { |
| 4287 | 4259 | return false; |
| 4288 | | }, |
| 4289 | | .no => return false, |
| 4290 | | .yes => return true, |
| 4291 | | } |
| 4292 | | }, |
| 4260 | } else { |
| 4261 | return child_ty.comptimeOnly(mod); |
| 4262 | } |
| 4263 | }, |
| 4264 | .array_type => |array_type| array_type.child.toType().comptimeOnly(mod), |
| 4265 | .vector_type => |vector_type| vector_type.child.toType().comptimeOnly(mod), |
| 4266 | .opt_type => |child| child.toType().comptimeOnly(mod), |
| 4267 | .error_union_type => |error_union_type| error_union_type.payload_type.toType().comptimeOnly(mod), |
| 4268 | .simple_type => |t| switch (t) { |
| 4269 | .f16, |
| 4270 | .f32, |
| 4271 | .f64, |
| 4272 | .f80, |
| 4273 | .f128, |
| 4274 | .usize, |
| 4275 | .isize, |
| 4276 | .c_char, |
| 4277 | .c_short, |
| 4278 | .c_ushort, |
| 4279 | .c_int, |
| 4280 | .c_uint, |
| 4281 | .c_long, |
| 4282 | .c_ulong, |
| 4283 | .c_longlong, |
| 4284 | .c_ulonglong, |
| 4285 | .c_longdouble, |
| 4286 | .anyopaque, |
| 4287 | .bool, |
| 4288 | .void, |
| 4289 | .anyerror, |
| 4290 | .@"anyframe", |
| 4291 | .noreturn, |
| 4292 | .generic_poison, |
| 4293 | .atomic_order, |
| 4294 | .atomic_rmw_op, |
| 4295 | .calling_convention, |
| 4296 | .address_space, |
| 4297 | .float_mode, |
| 4298 | .reduce_op, |
| 4299 | .call_modifier, |
| 4300 | .prefetch_options, |
| 4301 | .export_options, |
| 4302 | .extern_options, |
| 4303 | => false, |
| 4293 | 4304 | |
| 4294 | | .error_union => return ty.errorUnionPayload().comptimeOnly(mod), |
| 4295 | | .anyframe_T => { |
| 4296 | | const child_ty = ty.castTag(.anyframe_T).?.data; |
| 4297 | | return child_ty.comptimeOnly(mod); |
| 4298 | | }, |
| 4299 | | .enum_numbered => { |
| 4300 | | const tag_ty = ty.castTag(.enum_numbered).?.data.tag_ty; |
| 4301 | | return tag_ty.comptimeOnly(mod); |
| 4302 | | }, |
| 4303 | | .enum_full, .enum_nonexhaustive => { |
| 4304 | | const tag_ty = ty.cast(Type.Payload.EnumFull).?.data.tag_ty; |
| 4305 | | return tag_ty.comptimeOnly(mod); |
| 4305 | .type, |
| 4306 | .comptime_int, |
| 4307 | .comptime_float, |
| 4308 | .null, |
| 4309 | .undefined, |
| 4310 | .enum_literal, |
| 4311 | .type_info, |
| 4312 | => true, |
| 4313 | |
| 4314 | .var_args_param => unreachable, |
| 4315 | }, |
| 4316 | .struct_type => @panic("TODO"), |
| 4317 | .union_type => @panic("TODO"), |
| 4318 | .simple_value => unreachable, |
| 4319 | .extern_func => unreachable, |
| 4320 | .int => unreachable, |
| 4321 | .enum_tag => unreachable, // it's a value, not a type |
| 4306 | 4322 | }, |
| 4307 | 4323 | }; |
| 4308 | 4324 | } |
| ... | ... | @@ -4575,15 +4591,19 @@ pub const Type = struct { |
| 4575 | 4591 | } |
| 4576 | 4592 | |
| 4577 | 4593 | pub fn structFields(ty: Type) Module.Struct.Fields { |
| 4578 | | switch (ty.tag()) { |
| 4579 | | .empty_struct, .empty_struct_literal => return .{}, |
| 4580 | | .@"struct" => { |
| 4581 | | const struct_obj = ty.castTag(.@"struct").?.data; |
| 4582 | | assert(struct_obj.haveFieldTypes()); |
| 4583 | | return struct_obj.fields; |
| 4594 | return switch (ty.ip_index) { |
| 4595 | .empty_struct_type => .{}, |
| 4596 | .none => switch (ty.tag()) { |
| 4597 | .empty_struct => .{}, |
| 4598 | .@"struct" => { |
| 4599 | const struct_obj = ty.castTag(.@"struct").?.data; |
| 4600 | assert(struct_obj.haveFieldTypes()); |
| 4601 | return struct_obj.fields; |
| 4602 | }, |
| 4603 | else => unreachable, |
| 4584 | 4604 | }, |
| 4585 | 4605 | else => unreachable, |
| 4586 | | } |
| 4606 | }; |
| 4587 | 4607 | } |
| 4588 | 4608 | |
| 4589 | 4609 | pub fn structFieldName(ty: Type, field_index: usize) []const u8 { |
| ... | ... | @@ -4599,17 +4619,21 @@ pub const Type = struct { |
| 4599 | 4619 | } |
| 4600 | 4620 | |
| 4601 | 4621 | pub fn structFieldCount(ty: Type) usize { |
| 4602 | | switch (ty.tag()) { |
| 4603 | | .@"struct" => { |
| 4604 | | const struct_obj = ty.castTag(.@"struct").?.data; |
| 4605 | | assert(struct_obj.haveFieldTypes()); |
| 4606 | | return struct_obj.fields.count(); |
| 4622 | return switch (ty.ip_index) { |
| 4623 | .empty_struct_type => 0, |
| 4624 | .none => switch (ty.tag()) { |
| 4625 | .@"struct" => { |
| 4626 | const struct_obj = ty.castTag(.@"struct").?.data; |
| 4627 | assert(struct_obj.haveFieldTypes()); |
| 4628 | return struct_obj.fields.count(); |
| 4629 | }, |
| 4630 | .empty_struct => 0, |
| 4631 | .tuple => ty.castTag(.tuple).?.data.types.len, |
| 4632 | .anon_struct => ty.castTag(.anon_struct).?.data.types.len, |
| 4633 | else => unreachable, |
| 4607 | 4634 | }, |
| 4608 | | .empty_struct, .empty_struct_literal => return 0, |
| 4609 | | .tuple => return ty.castTag(.tuple).?.data.types.len, |
| 4610 | | .anon_struct => return ty.castTag(.anon_struct).?.data.types.len, |
| 4611 | 4635 | else => unreachable, |
| 4612 | | } |
| 4636 | }; |
| 4613 | 4637 | } |
| 4614 | 4638 | |
| 4615 | 4639 | /// Supports structs and unions. |
| ... | ... | @@ -4927,10 +4951,6 @@ pub const Type = struct { |
| 4927 | 4951 | return ty.ip_index == .generic_poison_type; |
| 4928 | 4952 | } |
| 4929 | 4953 | |
| 4930 | | pub fn isVarArgsParam(ty: Type) bool { |
| 4931 | | return ty.ip_index == .none and ty.tag() == .var_args_param; |
| 4932 | | } |
| 4933 | | |
| 4934 | 4954 | /// This enum does not directly correspond to `std.builtin.TypeId` because |
| 4935 | 4955 | /// it has extra enum tags in it, as a way of using less memory. For example, |
| 4936 | 4956 | /// even though Zig recognizes `*align(10) i32` and `*i32` both as Pointer types |
| ... | ... | @@ -4938,8 +4958,6 @@ pub const Type = struct { |
| 4938 | 4958 | /// with different enum tags, because the the former requires more payload data than the latter. |
| 4939 | 4959 | /// See `zigTypeTag` for the function that corresponds to `std.builtin.TypeId`. |
| 4940 | 4960 | pub const Tag = enum(usize) { |
| 4941 | | /// Same as `empty_struct` except it has an empty namespace. |
| 4942 | | empty_struct_literal, |
| 4943 | 4961 | /// This is a special value that tracks a set of types that have been stored |
| 4944 | 4962 | /// to an inferred allocation. It does not support most of the normal type queries. |
| 4945 | 4963 | /// However it does respond to `isConstPtr`, `ptrSize`, `zigTypeTag`, etc. |
| ... | ... | @@ -4982,7 +5000,6 @@ pub const Type = struct { |
| 4982 | 5000 | return switch (t) { |
| 4983 | 5001 | .inferred_alloc_const, |
| 4984 | 5002 | .inferred_alloc_mut, |
| 4985 | | .empty_struct_literal, |
| 4986 | 5003 | => @compileError("Type Tag " ++ @tagName(t) ++ " has no payload"), |
| 4987 | 5004 | |
| 4988 | 5005 | .optional, |
| ... | ... | @@ -5038,33 +5055,36 @@ pub const Type = struct { |
| 5038 | 5055 | |
| 5039 | 5056 | pub fn isTuple(ty: Type) bool { |
| 5040 | 5057 | return switch (ty.ip_index) { |
| 5058 | .empty_struct_type => true, |
| 5041 | 5059 | .none => switch (ty.tag()) { |
| 5042 | | .tuple, .empty_struct_literal => true, |
| 5060 | .tuple => true, |
| 5043 | 5061 | .@"struct" => ty.castTag(.@"struct").?.data.is_tuple, |
| 5044 | 5062 | else => false, |
| 5045 | 5063 | }, |
| 5046 | | else => false, // TODO |
| 5064 | else => false, // TODO struct |
| 5047 | 5065 | }; |
| 5048 | 5066 | } |
| 5049 | 5067 | |
| 5050 | 5068 | pub fn isAnonStruct(ty: Type) bool { |
| 5051 | 5069 | return switch (ty.ip_index) { |
| 5070 | .empty_struct_type => true, |
| 5052 | 5071 | .none => switch (ty.tag()) { |
| 5053 | | .anon_struct, .empty_struct_literal => true, |
| 5072 | .anon_struct => true, |
| 5054 | 5073 | else => false, |
| 5055 | 5074 | }, |
| 5056 | | else => false, // TODO |
| 5075 | else => false, // TODO struct |
| 5057 | 5076 | }; |
| 5058 | 5077 | } |
| 5059 | 5078 | |
| 5060 | 5079 | pub fn isTupleOrAnonStruct(ty: Type) bool { |
| 5061 | 5080 | return switch (ty.ip_index) { |
| 5081 | .empty_struct_type => true, |
| 5062 | 5082 | .none => switch (ty.tag()) { |
| 5063 | | .tuple, .empty_struct_literal, .anon_struct => true, |
| 5083 | .tuple, .anon_struct => true, |
| 5064 | 5084 | .@"struct" => ty.castTag(.@"struct").?.data.is_tuple, |
| 5065 | 5085 | else => false, |
| 5066 | 5086 | }, |
| 5067 | | else => false, // TODO |
| 5087 | else => false, // TODO struct |
| 5068 | 5088 | }; |
| 5069 | 5089 | } |
| 5070 | 5090 | |
| ... | ... | @@ -5072,7 +5092,7 @@ pub const Type = struct { |
| 5072 | 5092 | return switch (ty.ip_index) { |
| 5073 | 5093 | .empty_struct => true, |
| 5074 | 5094 | .none => switch (ty.tag()) { |
| 5075 | | .tuple, .empty_struct_literal => true, |
| 5095 | .tuple => true, |
| 5076 | 5096 | else => false, |
| 5077 | 5097 | }, |
| 5078 | 5098 | else => false, // TODO |
| ... | ... | @@ -5083,7 +5103,7 @@ pub const Type = struct { |
| 5083 | 5103 | return switch (ty.ip_index) { |
| 5084 | 5104 | .empty_struct => true, |
| 5085 | 5105 | .none => switch (ty.tag()) { |
| 5086 | | .tuple, .empty_struct_literal, .anon_struct => true, |
| 5106 | .tuple, .anon_struct => true, |
| 5087 | 5107 | else => false, |
| 5088 | 5108 | }, |
| 5089 | 5109 | else => false, |
| ... | ... | @@ -5100,7 +5120,6 @@ pub const Type = struct { |
| 5100 | 5120 | .types = ty.castTag(.anon_struct).?.data.types, |
| 5101 | 5121 | .values = ty.castTag(.anon_struct).?.data.values, |
| 5102 | 5122 | }, |
| 5103 | | .empty_struct_literal => .{ .types = &.{}, .values = &.{} }, |
| 5104 | 5123 | else => unreachable, |
| 5105 | 5124 | }, |
| 5106 | 5125 | else => unreachable, |
| ... | ... | @@ -5387,6 +5406,7 @@ pub const Type = struct { |
| 5387 | 5406 | .ip_index = .const_slice_u8_sentinel_0_type, |
| 5388 | 5407 | .legacy = undefined, |
| 5389 | 5408 | }; |
| 5409 | pub const empty_struct_literal: Type = .{ .ip_index = .empty_struct_type, .legacy = undefined }; |
| 5390 | 5410 | |
| 5391 | 5411 | pub const generic_poison: Type = .{ .ip_index = .generic_poison_type, .legacy = undefined }; |
| 5392 | 5412 | |