authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-07 22:29:28-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-04-07 22:29:28-07:00
logd4f61f9842da9025a4eb57e7a0fbb3298a4c01f6
treecf9bdfa6cf51b7446df1da43bb37b76728ced769
parent341dc03b638bc75bb8215dd2ad22231ebe106139
parent759591577518fcaf03fb90efca67d896d0806458
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #8449 from ziglang/stage2-enums

stage2: implement simple enums

11 files changed, 2058 insertions(+), 2753 deletions(-)

lib/std/zig/perf_test.zig+7-3
......@@ -9,6 +9,7 @@ const warn = std.debug.warn;
99const Tokenizer = std.zig.Tokenizer;
1010const Parser = std.zig.Parser;
1111const io = std.io;
12const fmtIntSizeBin = std.fmt.fmtIntSizeBin;
1213
1314const source = @embedFile("../os.zig");
1415var fixed_buffer_mem: [10 * 1024 * 1024]u8 = undefined;
......@@ -25,12 +26,15 @@ pub fn main() !void {
2526 const end = timer.read();
2627 memory_used /= iterations;
2728 const elapsed_s = @intToFloat(f64, end - start) / std.time.ns_per_s;
28 const bytes_per_sec = @intToFloat(f64, source.len * iterations) / elapsed_s;
29 const mb_per_sec = bytes_per_sec / (1024 * 1024);
29 const bytes_per_sec_float = @intToFloat(f64, source.len * iterations) / elapsed_s;
30 const bytes_per_sec = @floatToInt(u64, @floor(bytes_per_sec_float));
3031
3132 var stdout_file = std.io.getStdOut();
3233 const stdout = stdout_file.writer();
33 try stdout.print("{:.3} MiB/s, {} KiB used \n", .{ mb_per_sec, memory_used / 1024 });
34 try stdout.print("parsing speed: {:.2}/s, {:.2} used \n", .{
35 fmtIntSizeBin(bytes_per_sec),
36 fmtIntSizeBin(memory_used),
37 });
3438}
3539
3640fn testOnce() usize {
src/AstGen.zig+246-57
......@@ -28,8 +28,6 @@ const BuiltinFn = @import("BuiltinFn.zig");
2828instructions: std.MultiArrayList(zir.Inst) = .{},
2929string_bytes: ArrayListUnmanaged(u8) = .{},
3030extra: ArrayListUnmanaged(u32) = .{},
31decl_map: std.StringArrayHashMapUnmanaged(void) = .{},
32decls: ArrayListUnmanaged(*Decl) = .{},
3331/// The end of special indexes. `zir.Inst.Ref` subtracts against this number to convert
3432/// to `zir.Inst.Index`. The default here is correct if there are 0 parameters.
3533ref_start_index: u32 = zir.Inst.Ref.typed_value_map.len,
......@@ -110,8 +108,6 @@ pub fn deinit(astgen: *AstGen) void {
110108 astgen.instructions.deinit(gpa);
111109 astgen.extra.deinit(gpa);
112110 astgen.string_bytes.deinit(gpa);
113 astgen.decl_map.deinit(gpa);
114 astgen.decls.deinit(gpa);
115111}
116112
117113pub const ResultLoc = union(enum) {
......@@ -1183,13 +1179,6 @@ fn blockExprStmts(
11831179 // in the above while loop.
11841180 const zir_tags = gz.astgen.instructions.items(.tag);
11851181 switch (zir_tags[inst]) {
1186 .@"const" => {
1187 const tv = gz.astgen.instructions.items(.data)[inst].@"const";
1188 break :b switch (tv.ty.zigTypeTag()) {
1189 .NoReturn, .Void => true,
1190 else => false,
1191 };
1192 },
11931182 // For some instructions, swap in a slightly different ZIR tag
11941183 // so we can avoid a separate ensure_result_used instruction.
11951184 .call_none_chkused => unreachable,
......@@ -1257,6 +1246,8 @@ fn blockExprStmts(
12571246 .fn_type_cc,
12581247 .fn_type_cc_var_args,
12591248 .int,
1249 .float,
1250 .float128,
12601251 .intcast,
12611252 .int_type,
12621253 .is_non_null,
......@@ -1334,7 +1325,10 @@ fn blockExprStmts(
13341325 .struct_decl_extern,
13351326 .union_decl,
13361327 .enum_decl,
1328 .enum_decl_nonexhaustive,
13371329 .opaque_decl,
1330 .int_to_enum,
1331 .enum_to_int,
13381332 => break :b false,
13391333
13401334 // ZIR instructions that are always either `noreturn` or `void`.
......@@ -1490,7 +1484,7 @@ fn varDecl(
14901484 init_scope.rl_ptr = try init_scope.addUnNode(.alloc, type_inst, node);
14911485 init_scope.rl_ty_inst = type_inst;
14921486 } else {
1493 const alloc = try init_scope.addUnNode(.alloc_inferred, undefined, node);
1487 const alloc = try init_scope.addNode(.alloc_inferred, node);
14941488 resolve_inferred_alloc = alloc;
14951489 init_scope.rl_ptr = alloc;
14961490 }
......@@ -1565,7 +1559,7 @@ fn varDecl(
15651559 const alloc = try gz.addUnNode(.alloc_mut, type_inst, node);
15661560 break :a .{ .alloc = alloc, .result_loc = .{ .ptr = alloc } };
15671561 } else a: {
1568 const alloc = try gz.addUnNode(.alloc_inferred_mut, undefined, node);
1562 const alloc = try gz.addNode(.alloc_inferred_mut, node);
15691563 resolve_inferred_alloc = alloc;
15701564 break :a .{ .alloc = alloc, .result_loc = .{ .inferred_ptr = alloc } };
15711565 };
......@@ -1823,15 +1817,18 @@ fn containerDecl(
18231817 defer bit_bag.deinit(gpa);
18241818
18251819 var cur_bit_bag: u32 = 0;
1826 var member_index: usize = 0;
1827 while (true) {
1828 const member_node = container_decl.ast.members[member_index];
1820 var field_index: usize = 0;
1821 for (container_decl.ast.members) |member_node| {
18291822 const member = switch (node_tags[member_node]) {
18301823 .container_field_init => tree.containerFieldInit(member_node),
18311824 .container_field_align => tree.containerFieldAlign(member_node),
18321825 .container_field => tree.containerField(member_node),
1833 else => unreachable,
1826 else => continue,
18341827 };
1828 if (field_index % 16 == 0 and field_index != 0) {
1829 try bit_bag.append(gpa, cur_bit_bag);
1830 cur_bit_bag = 0;
1831 }
18351832 if (member.comptime_token) |comptime_token| {
18361833 return mod.failTok(scope, comptime_token, "TODO implement comptime struct fields", .{});
18371834 }
......@@ -1858,17 +1855,9 @@ fn containerDecl(
18581855 fields_data.appendAssumeCapacity(@enumToInt(default_inst));
18591856 }
18601857
1861 member_index += 1;
1862 if (member_index < container_decl.ast.members.len) {
1863 if (member_index % 16 == 0) {
1864 try bit_bag.append(gpa, cur_bit_bag);
1865 cur_bit_bag = 0;
1866 }
1867 } else {
1868 break;
1869 }
1858 field_index += 1;
18701859 }
1871 const empty_slot_count = 16 - ((member_index - 1) % 16);
1860 const empty_slot_count = 16 - (field_index % 16);
18721861 cur_bit_bag >>= @intCast(u5, empty_slot_count * 2);
18731862
18741863 const result = try gz.addPlNode(tag, node, zir.Inst.StructDecl{
......@@ -1885,7 +1874,172 @@ fn containerDecl(
18851874 return mod.failTok(scope, container_decl.ast.main_token, "TODO AstGen for union decl", .{});
18861875 },
18871876 .keyword_enum => {
1888 return mod.failTok(scope, container_decl.ast.main_token, "TODO AstGen for enum decl", .{});
1877 if (container_decl.layout_token) |t| {
1878 return mod.failTok(scope, t, "enums do not support 'packed' or 'extern'; instead provide an explicit integer tag type", .{});
1879 }
1880 // Count total fields as well as how many have explicitly provided tag values.
1881 const counts = blk: {
1882 var values: usize = 0;
1883 var total_fields: usize = 0;
1884 var decls: usize = 0;
1885 var nonexhaustive_node: ast.Node.Index = 0;
1886 for (container_decl.ast.members) |member_node| {
1887 const member = switch (node_tags[member_node]) {
1888 .container_field_init => tree.containerFieldInit(member_node),
1889 .container_field_align => tree.containerFieldAlign(member_node),
1890 .container_field => tree.containerField(member_node),
1891 else => {
1892 decls += 1;
1893 continue;
1894 },
1895 };
1896 if (member.comptime_token) |comptime_token| {
1897 return mod.failTok(scope, comptime_token, "enum fields cannot be marked comptime", .{});
1898 }
1899 if (member.ast.type_expr != 0) {
1900 return mod.failNode(scope, member.ast.type_expr, "enum fields do not have types", .{});
1901 }
1902 // Alignment expressions in enums are caught by the parser.
1903 assert(member.ast.align_expr == 0);
1904
1905 const name_token = member.ast.name_token;
1906 if (mem.eql(u8, tree.tokenSlice(name_token), "_")) {
1907 if (nonexhaustive_node != 0) {
1908 const msg = msg: {
1909 const msg = try mod.errMsg(
1910 scope,
1911 gz.nodeSrcLoc(member_node),
1912 "redundant non-exhaustive enum mark",
1913 .{},
1914 );
1915 errdefer msg.destroy(gpa);
1916 const other_src = gz.nodeSrcLoc(nonexhaustive_node);
1917 try mod.errNote(scope, other_src, msg, "other mark here", .{});
1918 break :msg msg;
1919 };
1920 return mod.failWithOwnedErrorMsg(scope, msg);
1921 }
1922 nonexhaustive_node = member_node;
1923 if (member.ast.value_expr != 0) {
1924 return mod.failNode(scope, member.ast.value_expr, "'_' is used to mark an enum as non-exhaustive and cannot be assigned a value", .{});
1925 }
1926 continue;
1927 }
1928 total_fields += 1;
1929 if (member.ast.value_expr != 0) {
1930 values += 1;
1931 }
1932 }
1933 break :blk .{
1934 .total_fields = total_fields,
1935 .values = values,
1936 .decls = decls,
1937 .nonexhaustive_node = nonexhaustive_node,
1938 };
1939 };
1940 if (counts.total_fields == 0) {
1941 // One can construct an enum with no tags, and it functions the same as `noreturn`. But
1942 // this is only useful for generic code; when explicitly using `enum {}` syntax, there
1943 // must be at least one tag.
1944 return mod.failNode(scope, node, "enum declarations must have at least one tag", .{});
1945 }
1946 if (counts.nonexhaustive_node != 0 and arg_inst == .none) {
1947 const msg = msg: {
1948 const msg = try mod.errMsg(
1949 scope,
1950 gz.nodeSrcLoc(node),
1951 "non-exhaustive enum missing integer tag type",
1952 .{},
1953 );
1954 errdefer msg.destroy(gpa);
1955 const other_src = gz.nodeSrcLoc(counts.nonexhaustive_node);
1956 try mod.errNote(scope, other_src, msg, "marked non-exhaustive here", .{});
1957 break :msg msg;
1958 };
1959 return mod.failWithOwnedErrorMsg(scope, msg);
1960 }
1961 if (counts.values == 0 and counts.decls == 0 and arg_inst == .none) {
1962 // No explicitly provided tag values and no top level declarations! In this case,
1963 // we can construct the enum type in AstGen and it will be correctly shared by all
1964 // generic function instantiations and comptime function calls.
1965 var new_decl_arena = std.heap.ArenaAllocator.init(gpa);
1966 errdefer new_decl_arena.deinit();
1967 const arena = &new_decl_arena.allocator;
1968
1969 var fields_map: std.StringArrayHashMapUnmanaged(void) = .{};
1970 try fields_map.ensureCapacity(arena, counts.total_fields);
1971 for (container_decl.ast.members) |member_node| {
1972 if (member_node == counts.nonexhaustive_node)
1973 continue;
1974 const member = switch (node_tags[member_node]) {
1975 .container_field_init => tree.containerFieldInit(member_node),
1976 .container_field_align => tree.containerFieldAlign(member_node),
1977 .container_field => tree.containerField(member_node),
1978 else => unreachable, // We checked earlier.
1979 };
1980 const name_token = member.ast.name_token;
1981 const tag_name = try mod.identifierTokenStringTreeArena(
1982 scope,
1983 name_token,
1984 tree,
1985 arena,
1986 );
1987 const gop = fields_map.getOrPutAssumeCapacity(tag_name);
1988 if (gop.found_existing) {
1989 const msg = msg: {
1990 const msg = try mod.errMsg(
1991 scope,
1992 gz.tokSrcLoc(name_token),
1993 "duplicate enum tag",
1994 .{},
1995 );
1996 errdefer msg.destroy(gpa);
1997 // Iterate to find the other tag. We don't eagerly store it in a hash
1998 // map because in the hot path there will be no compile error and we
1999 // don't need to waste time with a hash map.
2000 const bad_node = for (container_decl.ast.members) |other_member_node| {
2001 const other_member = switch (node_tags[other_member_node]) {
2002 .container_field_init => tree.containerFieldInit(other_member_node),
2003 .container_field_align => tree.containerFieldAlign(other_member_node),
2004 .container_field => tree.containerField(other_member_node),
2005 else => unreachable, // We checked earlier.
2006 };
2007 const other_tag_name = try mod.identifierTokenStringTreeArena(
2008 scope,
2009 other_member.ast.name_token,
2010 tree,
2011 arena,
2012 );
2013 if (mem.eql(u8, tag_name, other_tag_name))
2014 break other_member_node;
2015 } else unreachable;
2016 const other_src = gz.nodeSrcLoc(bad_node);
2017 try mod.errNote(scope, other_src, msg, "other tag here", .{});
2018 break :msg msg;
2019 };
2020 return mod.failWithOwnedErrorMsg(scope, msg);
2021 }
2022 }
2023 const enum_simple = try arena.create(Module.EnumSimple);
2024 enum_simple.* = .{
2025 .owner_decl = astgen.decl,
2026 .node_offset = astgen.decl.nodeIndexToRelative(node),
2027 .fields = fields_map,
2028 };
2029 const enum_ty = try Type.Tag.enum_simple.create(arena, enum_simple);
2030 const enum_val = try Value.Tag.ty.create(arena, enum_ty);
2031 const new_decl = try mod.createAnonymousDecl(scope, &new_decl_arena, .{
2032 .ty = Type.initTag(.type),
2033 .val = enum_val,
2034 });
2035 const decl_index = try mod.declareDeclDependency(astgen.decl, new_decl);
2036 const result = try gz.addDecl(.decl_val, decl_index, node);
2037 return rvalue(gz, scope, rl, result, node);
2038 }
2039 // In this case we must generate ZIR code for the tag values, similar to
2040 // how structs are handled above. The new anonymous Decl will be created in
2041 // Sema, not AstGen.
2042 return mod.failNode(scope, node, "TODO AstGen for enum decl with decls or explicitly provided field values", .{});
18892043 },
18902044 .keyword_opaque => {
18912045 const result = try gz.addNode(.opaque_decl, node);
......@@ -1901,11 +2055,11 @@ fn errorSetDecl(
19012055 rl: ResultLoc,
19022056 node: ast.Node.Index,
19032057) InnerError!zir.Inst.Ref {
1904 const mod = gz.astgen.mod;
2058 const astgen = gz.astgen;
2059 const mod = astgen.mod;
19052060 const tree = gz.tree();
19062061 const main_tokens = tree.nodes.items(.main_token);
19072062 const token_tags = tree.tokens.items(.tag);
1908 const arena = gz.astgen.arena;
19092063
19102064 // Count how many fields there are.
19112065 const error_token = main_tokens[node];
......@@ -1922,6 +2076,11 @@ fn errorSetDecl(
19222076 } else unreachable; // TODO should not need else unreachable here
19232077 };
19242078
2079 const gpa = mod.gpa;
2080 var new_decl_arena = std.heap.ArenaAllocator.init(gpa);
2081 errdefer new_decl_arena.deinit();
2082 const arena = &new_decl_arena.allocator;
2083
19252084 const fields = try arena.alloc([]const u8, count);
19262085 {
19272086 var tok_i = error_token + 2;
......@@ -1930,7 +2089,7 @@ fn errorSetDecl(
19302089 switch (token_tags[tok_i]) {
19312090 .doc_comment, .comma => {},
19322091 .identifier => {
1933 fields[field_i] = try mod.identifierTokenString(scope, tok_i);
2092 fields[field_i] = try mod.identifierTokenStringTreeArena(scope, tok_i, tree, arena);
19342093 field_i += 1;
19352094 },
19362095 .r_brace => break,
......@@ -1940,18 +2099,19 @@ fn errorSetDecl(
19402099 }
19412100 const error_set = try arena.create(Module.ErrorSet);
19422101 error_set.* = .{
1943 .owner_decl = gz.astgen.decl,
1944 .node_offset = gz.astgen.decl.nodeIndexToRelative(node),
2102 .owner_decl = astgen.decl,
2103 .node_offset = astgen.decl.nodeIndexToRelative(node),
19452104 .names_ptr = fields.ptr,
19462105 .names_len = @intCast(u32, fields.len),
19472106 };
19482107 const error_set_ty = try Type.Tag.error_set.create(arena, error_set);
1949 const typed_value = try arena.create(TypedValue);
1950 typed_value.* = .{
2108 const error_set_val = try Value.Tag.ty.create(arena, error_set_ty);
2109 const new_decl = try mod.createAnonymousDecl(scope, &new_decl_arena, .{
19512110 .ty = Type.initTag(.type),
1952 .val = try Value.Tag.ty.create(arena, error_set_ty),
1953 };
1954 const result = try gz.addConst(typed_value);
2111 .val = error_set_val,
2112 });
2113 const decl_index = try mod.declareDeclDependency(astgen.decl, new_decl);
2114 const result = try gz.addDecl(.decl_val, decl_index, node);
19552115 return rvalue(gz, scope, rl, result, node);
19562116}
19572117
......@@ -3196,8 +3356,13 @@ fn switchExpr(
31963356 switch (strat.tag) {
31973357 .break_operand => {
31983358 // Switch expressions return `true` for `nodeMayNeedMemoryLocation` thus
3199 // this is always true.
3200 assert(strat.elide_store_to_block_ptr_instructions);
3359 // `elide_store_to_block_ptr_instructions` will either be true,
3360 // or all prongs are noreturn.
3361 if (!strat.elide_store_to_block_ptr_instructions) {
3362 astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items);
3363 astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items);
3364 return astgen.indexToRef(switch_block);
3365 }
32013366
32023367 // There will necessarily be a store_to_block_ptr for
32033368 // all prongs, except for prongs that ended with a noreturn instruction.
......@@ -3426,7 +3591,8 @@ fn identifier(
34263591 const tracy = trace(@src());
34273592 defer tracy.end();
34283593
3429 const mod = gz.astgen.mod;
3594 const astgen = gz.astgen;
3595 const mod = astgen.mod;
34303596 const tree = gz.tree();
34313597 const main_tokens = tree.nodes.items(.main_token);
34323598
......@@ -3459,7 +3625,7 @@ fn identifier(
34593625 const result = try gz.add(.{
34603626 .tag = .int_type,
34613627 .data = .{ .int_type = .{
3462 .src_node = gz.astgen.decl.nodeIndexToRelative(ident),
3628 .src_node = astgen.decl.nodeIndexToRelative(ident),
34633629 .signedness = signedness,
34643630 .bit_count = bit_count,
34653631 } },
......@@ -3497,13 +3663,13 @@ fn identifier(
34973663 };
34983664 }
34993665
3500 const gop = try gz.astgen.decl_map.getOrPut(mod.gpa, ident_name);
3501 if (!gop.found_existing) {
3502 const decl = mod.lookupDeclName(scope, ident_name) orelse
3503 return mod.failNode(scope, ident, "use of undeclared identifier '{s}'", .{ident_name});
3504 try gz.astgen.decls.append(mod.gpa, decl);
3505 }
3506 const decl_index = @intCast(u32, gop.index);
3666 const decl = mod.lookupDeclName(scope, ident_name) orelse {
3667 // TODO insert a "dependency on the non-existence of a decl" here to make this
3668 // compile error go away when the decl is introduced. This data should be in a global
3669 // sparse map since it is only relevant when a compile error occurs.
3670 return mod.failNode(scope, ident, "use of undeclared identifier '{s}'", .{ident_name});
3671 };
3672 const decl_index = try mod.declareDeclDependency(astgen.decl, decl);
35073673 switch (rl) {
35083674 .ref, .none_or_ref => return gz.addDecl(.decl_ref, decl_index, ident),
35093675 else => return rvalue(gz, scope, rl, try gz.addDecl(.decl_val, decl_index, ident), ident),
......@@ -3638,12 +3804,23 @@ fn floatLiteral(
36383804 const float_number = std.fmt.parseFloat(f128, bytes) catch |e| switch (e) {
36393805 error.InvalidCharacter => unreachable, // validated by tokenizer
36403806 };
3641 const typed_value = try arena.create(TypedValue);
3642 typed_value.* = .{
3643 .ty = Type.initTag(.comptime_float),
3644 .val = try Value.Tag.float_128.create(arena, float_number),
3645 };
3646 const result = try gz.addConst(typed_value);
3807 // If the value fits into a f32 without losing any precision, store it that way.
3808 @setFloatMode(.Strict);
3809 const smaller_float = @floatCast(f32, float_number);
3810 const bigger_again: f128 = smaller_float;
3811 if (bigger_again == float_number) {
3812 const result = try gz.addFloat(smaller_float, node);
3813 return rvalue(gz, scope, rl, result, node);
3814 }
3815 // We need to use 128 bits. Break the float into 4 u32 values so we can
3816 // put it into the `extra` array.
3817 const int_bits = @bitCast(u128, float_number);
3818 const result = try gz.addPlNode(.float128, node, zir.Inst.Float128{
3819 .piece0 = @truncate(u32, int_bits),
3820 .piece1 = @truncate(u32, int_bits >> 32),
3821 .piece2 = @truncate(u32, int_bits >> 64),
3822 .piece3 = @truncate(u32, int_bits >> 96),
3823 });
36473824 return rvalue(gz, scope, rl, result, node);
36483825}
36493826
......@@ -3955,6 +4132,20 @@ fn builtinCall(
39554132 .bit_cast => return bitCast(gz, scope, rl, node, params[0], params[1]),
39564133 .TypeOf => return typeOf(gz, scope, rl, node, params),
39574134
4135 .int_to_enum => {
4136 const result = try gz.addPlNode(.int_to_enum, node, zir.Inst.Bin{
4137 .lhs = try typeExpr(gz, scope, params[0]),
4138 .rhs = try expr(gz, scope, .none, params[1]),
4139 });
4140 return rvalue(gz, scope, rl, result, node);
4141 },
4142
4143 .enum_to_int => {
4144 const operand = try expr(gz, scope, .none, params[0]);
4145 const result = try gz.addUnNode(.enum_to_int, operand, node);
4146 return rvalue(gz, scope, rl, result, node);
4147 },
4148
39584149 .add_with_overflow,
39594150 .align_cast,
39604151 .align_of,
......@@ -3981,7 +4172,6 @@ fn builtinCall(
39814172 .div_floor,
39824173 .div_trunc,
39834174 .embed_file,
3984 .enum_to_int,
39854175 .error_name,
39864176 .error_return_trace,
39874177 .err_set_cast,
......@@ -3991,7 +4181,6 @@ fn builtinCall(
39914181 .float_to_int,
39924182 .has_decl,
39934183 .has_field,
3994 .int_to_enum,
39954184 .int_to_float,
39964185 .int_to_ptr,
39974186 .memcpy,
src/BuiltinFn.zig+1-1
......@@ -484,7 +484,7 @@ pub const list = list: {
484484 "@intToEnum",
485485 .{
486486 .tag = .int_to_enum,
487 .param_count = 1,
487 .param_count = 2,
488488 },
489489 },
490490 .{
src/Compilation.zig+41-14
......@@ -1346,9 +1346,9 @@ pub fn update(self: *Compilation) !void {
13461346 module.generation += 1;
13471347
13481348 // TODO Detect which source files changed.
1349 // Until then we simulate a full cache miss. Source files could have been loaded for any reason;
1350 // to force a refresh we unload now.
1351 module.root_scope.unload(module.gpa);
1349 // Until then we simulate a full cache miss. Source files could have been loaded
1350 // for any reason; to force a refresh we unload now.
1351 module.unloadFile(module.root_scope);
13521352 module.failed_root_src_file = null;
13531353 module.analyzeContainer(&module.root_scope.root_container) catch |err| switch (err) {
13541354 error.AnalysisFail => {
......@@ -1362,7 +1362,7 @@ pub fn update(self: *Compilation) !void {
13621362
13631363 // TODO only analyze imports if they are still referenced
13641364 for (module.import_table.items()) |entry| {
1365 entry.value.unload(module.gpa);
1365 module.unloadFile(entry.value);
13661366 module.analyzeContainer(&entry.value.root_container) catch |err| switch (err) {
13671367 error.AnalysisFail => {
13681368 assert(self.totalErrorCount() != 0);
......@@ -1377,14 +1377,17 @@ pub fn update(self: *Compilation) !void {
13771377
13781378 if (!use_stage1) {
13791379 if (self.bin_file.options.module) |module| {
1380 // Process the deletion set.
1381 while (module.deletion_set.popOrNull()) |decl| {
1382 if (decl.dependants.items().len != 0) {
1383 decl.deletion_flag = false;
1384 continue;
1385 }
1386 try module.deleteDecl(decl);
1380 // Process the deletion set. We use a while loop here because the
1381 // deletion set may grow as we call `deleteDecl` within this loop,
1382 // and more unreferenced Decls are revealed.
1383 var entry_i: usize = 0;
1384 while (entry_i < module.deletion_set.entries.items.len) : (entry_i += 1) {
1385 const decl = module.deletion_set.entries.items[entry_i].key;
1386 assert(decl.deletion_flag);
1387 assert(decl.dependants.items().len == 0);
1388 try module.deleteDecl(decl, null);
13871389 }
1390 module.deletion_set.shrinkRetainingCapacity(0);
13881391 }
13891392 }
13901393
......@@ -1429,11 +1432,25 @@ pub fn totalErrorCount(self: *Compilation) usize {
14291432 var total: usize = self.failed_c_objects.items().len;
14301433
14311434 if (self.bin_file.options.module) |module| {
1432 total += module.failed_decls.count() +
1433 module.emit_h_failed_decls.count() +
1434 module.failed_exports.items().len +
1435 total += module.failed_exports.items().len +
14351436 module.failed_files.items().len +
14361437 @boolToInt(module.failed_root_src_file != null);
1438 // Skip errors for Decls within files that failed parsing.
1439 // When a parse error is introduced, we keep all the semantic analysis for
1440 // the previous parse success, including compile errors, but we cannot
1441 // emit them until the file succeeds parsing.
1442 for (module.failed_decls.items()) |entry| {
1443 if (entry.key.container.file_scope.status == .unloaded_parse_failure) {
1444 continue;
1445 }
1446 total += 1;
1447 }
1448 for (module.emit_h_failed_decls.items()) |entry| {
1449 if (entry.key.container.file_scope.status == .unloaded_parse_failure) {
1450 continue;
1451 }
1452 total += 1;
1453 }
14371454 }
14381455
14391456 // The "no entry point found" error only counts if there are no other errors.
......@@ -1480,9 +1497,19 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
14801497 try AllErrors.add(module, &arena, &errors, entry.value.*);
14811498 }
14821499 for (module.failed_decls.items()) |entry| {
1500 if (entry.key.container.file_scope.status == .unloaded_parse_failure) {
1501 // Skip errors for Decls within files that had a parse failure.
1502 // We'll try again once parsing succeeds.
1503 continue;
1504 }
14831505 try AllErrors.add(module, &arena, &errors, entry.value.*);
14841506 }
14851507 for (module.emit_h_failed_decls.items()) |entry| {
1508 if (entry.key.container.file_scope.status == .unloaded_parse_failure) {
1509 // Skip errors for Decls within files that had a parse failure.
1510 // We'll try again once parsing succeeds.
1511 continue;
1512 }
14861513 try AllErrors.add(module, &arena, &errors, entry.value.*);
14871514 }
14881515 for (module.failed_exports.items()) |entry| {
src/Module.zig+204-38
......@@ -65,8 +65,8 @@ emit_h_failed_decls: std.AutoArrayHashMapUnmanaged(*Decl, *ErrorMsg) = .{},
6565/// Keep track of one `@compileLog` callsite per owner Decl.
6666compile_log_decls: std.AutoArrayHashMapUnmanaged(*Decl, SrcLoc) = .{},
6767/// Using a map here for consistency with the other fields here.
68/// The ErrorMsg memory is owned by the `Scope`, using Module's general purpose allocator.
69failed_files: std.AutoArrayHashMapUnmanaged(*Scope, *ErrorMsg) = .{},
68/// The ErrorMsg memory is owned by the `Scope.File`, using Module's general purpose allocator.
69failed_files: std.AutoArrayHashMapUnmanaged(*Scope.File, *ErrorMsg) = .{},
7070/// Using a map here for consistency with the other fields here.
7171/// The ErrorMsg memory is owned by the `Export`, using Module's general purpose allocator.
7272failed_exports: std.AutoArrayHashMapUnmanaged(*Export, *ErrorMsg) = .{},
......@@ -75,7 +75,7 @@ next_anon_name_index: usize = 0,
7575
7676/// Candidates for deletion. After a semantic analysis update completes, this list
7777/// contains Decls that need to be deleted if they end up having no references to them.
78deletion_set: ArrayListUnmanaged(*Decl) = .{},
78deletion_set: std.AutoArrayHashMapUnmanaged(*Decl, void) = .{},
7979
8080/// Error tags and their values, tag names are duped with mod.gpa.
8181/// Corresponds with `error_name_list`.
......@@ -192,7 +192,7 @@ pub const Decl = struct {
192192 /// to require re-analysis.
193193 outdated,
194194 },
195 /// This flag is set when this Decl is added to a check_for_deletion set, and cleared
195 /// This flag is set when this Decl is added to `Module.deletion_set`, and cleared
196196 /// when removed.
197197 deletion_flag: bool,
198198 /// Whether the corresponding AST decl has a `pub` keyword.
......@@ -290,6 +290,18 @@ pub const Decl = struct {
290290 return decl.container.fullyQualifiedNameHash(mem.spanZ(decl.name));
291291 }
292292
293 pub fn renderFullyQualifiedName(decl: Decl, writer: anytype) !void {
294 const unqualified_name = mem.spanZ(decl.name);
295 return decl.container.renderFullyQualifiedName(unqualified_name, writer);
296 }
297
298 pub fn getFullyQualifiedName(decl: Decl, gpa: *Allocator) ![]u8 {
299 var buffer = std.ArrayList(u8).init(gpa);
300 defer buffer.deinit();
301 try decl.renderFullyQualifiedName(buffer.writer());
302 return buffer.toOwnedSlice();
303 }
304
293305 pub fn typedValue(decl: *Decl) error{AnalysisFail}!TypedValue {
294306 const tvm = decl.typedValueManaged() orelse return error.AnalysisFail;
295307 return tvm.typed_value;
......@@ -354,6 +366,13 @@ pub const ErrorSet = struct {
354366 /// The string bytes are stored in the owner Decl arena.
355367 /// They are in the same order they appear in the AST.
356368 names_ptr: [*]const []const u8,
369
370 pub fn srcLoc(self: ErrorSet) SrcLoc {
371 return .{
372 .container = .{ .decl = self.owner_decl },
373 .lazy = .{ .node_offset = self.node_offset },
374 };
375 }
357376};
358377
359378/// Represents the data that a struct declaration provides.
......@@ -375,8 +394,7 @@ pub const Struct = struct {
375394 };
376395
377396 pub fn getFullyQualifiedName(s: *Struct, gpa: *Allocator) ![]u8 {
378 // TODO this should return e.g. "std.fs.Dir.OpenOptions"
379 return gpa.dupe(u8, mem.spanZ(s.owner_decl.name));
397 return s.owner_decl.getFullyQualifiedName(gpa);
380398 }
381399
382400 pub fn srcLoc(s: Struct) SrcLoc {
......@@ -387,6 +405,53 @@ pub const Struct = struct {
387405 }
388406};
389407
408/// Represents the data that an enum declaration provides, when the fields
409/// are auto-numbered, and there are no declarations. The integer tag type
410/// is inferred to be the smallest power of two unsigned int that fits
411/// the number of fields.
412pub const EnumSimple = struct {
413 owner_decl: *Decl,
414 /// Set of field names in declaration order.
415 fields: std.StringArrayHashMapUnmanaged(void),
416 /// Offset from `owner_decl`, points to the enum decl AST node.
417 node_offset: i32,
418
419 pub fn srcLoc(self: EnumSimple) SrcLoc {
420 return .{
421 .container = .{ .decl = self.owner_decl },
422 .lazy = .{ .node_offset = self.node_offset },
423 };
424 }
425};
426
427/// Represents the data that an enum declaration provides, when there is
428/// at least one tag value explicitly specified, or at least one declaration.
429pub const EnumFull = struct {
430 owner_decl: *Decl,
431 /// An integer type which is used for the numerical value of the enum.
432 /// Whether zig chooses this type or the user specifies it, it is stored here.
433 tag_ty: Type,
434 /// Set of field names in declaration order.
435 fields: std.StringArrayHashMapUnmanaged(void),
436 /// Maps integer tag value to field index.
437 /// Entries are in declaration order, same as `fields`.
438 /// If this hash map is empty, it means the enum tags are auto-numbered.
439 values: ValueMap,
440 /// Represents the declarations inside this struct.
441 container: Scope.Container,
442 /// Offset from `owner_decl`, points to the enum decl AST node.
443 node_offset: i32,
444
445 pub const ValueMap = std.ArrayHashMapUnmanaged(Value, void, Value.hash_u32, Value.eql, false);
446
447 pub fn srcLoc(self: EnumFull) SrcLoc {
448 return .{
449 .container = .{ .decl = self.owner_decl },
450 .lazy = .{ .node_offset = self.node_offset },
451 };
452 }
453};
454
390455/// Some Fn struct memory is owned by the Decl's TypedValue.Managed arena allocator.
391456/// Extern functions do not have this data structure; they are represented by
392457/// the `Decl` only, with a `Value` tag of `extern_fn`.
......@@ -634,6 +699,11 @@ pub const Scope = struct {
634699 // TODO container scope qualified names.
635700 return std.zig.hashSrc(name);
636701 }
702
703 pub fn renderFullyQualifiedName(cont: Container, name: []const u8, writer: anytype) !void {
704 // TODO this should render e.g. "std.fs.Dir.OpenOptions"
705 return writer.writeAll(name);
706 }
637707 };
638708
639709 pub const File = struct {
......@@ -662,10 +732,12 @@ pub const Scope = struct {
662732
663733 pub fn unload(file: *File, gpa: *Allocator) void {
664734 switch (file.status) {
665 .never_loaded,
666735 .unloaded_parse_failure,
736 .never_loaded,
667737 .unloaded_success,
668 => {},
738 => {
739 file.status = .unloaded_success;
740 },
669741
670742 .loaded_success => {
671743 file.tree.deinit(gpa);
......@@ -1030,7 +1102,6 @@ pub const Scope = struct {
10301102 .instructions = gz.astgen.instructions.toOwnedSlice(),
10311103 .string_bytes = gz.astgen.string_bytes.toOwnedSlice(gpa),
10321104 .extra = gz.astgen.extra.toOwnedSlice(gpa),
1033 .decls = gz.astgen.decls.toOwnedSlice(gpa),
10341105 };
10351106 }
10361107
......@@ -1242,6 +1313,16 @@ pub const Scope = struct {
12421313 });
12431314 }
12441315
1316 pub fn addFloat(gz: *GenZir, number: f32, src_node: ast.Node.Index) !zir.Inst.Ref {
1317 return gz.add(.{
1318 .tag = .float,
1319 .data = .{ .float = .{
1320 .src_node = gz.astgen.decl.nodeIndexToRelative(src_node),
1321 .number = number,
1322 } },
1323 });
1324 }
1325
12451326 pub fn addUnNode(
12461327 gz: *GenZir,
12471328 tag: zir.Inst.Tag,
......@@ -1450,13 +1531,6 @@ pub const Scope = struct {
14501531 return new_index;
14511532 }
14521533
1453 pub fn addConst(gz: *GenZir, typed_value: *TypedValue) !zir.Inst.Ref {
1454 return gz.add(.{
1455 .tag = .@"const",
1456 .data = .{ .@"const" = typed_value },
1457 });
1458 }
1459
14601534 pub fn add(gz: *GenZir, inst: zir.Inst) !zir.Inst.Ref {
14611535 return gz.astgen.indexToRef(try gz.addAsIndex(inst));
14621536 }
......@@ -2321,7 +2395,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl: *Decl) InnerError!void {
23212395 // We don't perform a deletion here, because this Decl or another one
23222396 // may end up referencing it before the update is complete.
23232397 dep.deletion_flag = true;
2324 try mod.deletion_set.append(mod.gpa, dep);
2398 try mod.deletion_set.put(mod.gpa, dep, {});
23252399 }
23262400 }
23272401 decl.dependencies.clearRetainingCapacity();
......@@ -3120,12 +3194,19 @@ fn astgenAndSemaVarDecl(
31203194 return type_changed;
31213195}
31223196
3123pub fn declareDeclDependency(mod: *Module, depender: *Decl, dependee: *Decl) !void {
3124 try depender.dependencies.ensureCapacity(mod.gpa, depender.dependencies.items().len + 1);
3125 try dependee.dependants.ensureCapacity(mod.gpa, dependee.dependants.items().len + 1);
3197/// Returns the depender's index of the dependee.
3198pub fn declareDeclDependency(mod: *Module, depender: *Decl, dependee: *Decl) !u32 {
3199 try depender.dependencies.ensureCapacity(mod.gpa, depender.dependencies.count() + 1);
3200 try dependee.dependants.ensureCapacity(mod.gpa, dependee.dependants.count() + 1);
3201
3202 if (dependee.deletion_flag) {
3203 dependee.deletion_flag = false;
3204 mod.deletion_set.removeAssertDiscard(dependee);
3205 }
31263206
3127 depender.dependencies.putAssumeCapacity(dependee, {});
31283207 dependee.dependants.putAssumeCapacity(depender, {});
3208 const gop = depender.dependencies.getOrPutAssumeCapacity(dependee);
3209 return @intCast(u32, gop.index);
31293210}
31303211
31313212pub fn getAstTree(mod: *Module, root_scope: *Scope.File) !*const ast.Tree {
......@@ -3150,17 +3231,19 @@ pub fn getAstTree(mod: *Module, root_scope: *Scope.File) !*const ast.Tree {
31503231 var msg = std.ArrayList(u8).init(mod.gpa);
31513232 defer msg.deinit();
31523233
3234 const token_starts = tree.tokens.items(.start);
3235
31533236 try tree.renderError(parse_err, msg.writer());
31543237 const err_msg = try mod.gpa.create(ErrorMsg);
31553238 err_msg.* = .{
31563239 .src_loc = .{
31573240 .container = .{ .file_scope = root_scope },
3158 .lazy = .{ .token_abs = parse_err.token },
3241 .lazy = .{ .byte_abs = token_starts[parse_err.token] },
31593242 },
31603243 .msg = msg.toOwnedSlice(),
31613244 };
31623245
3163 mod.failed_files.putAssumeCapacityNoClobber(&root_scope.base, err_msg);
3246 mod.failed_files.putAssumeCapacityNoClobber(root_scope, err_msg);
31643247 root_scope.status = .unloaded_parse_failure;
31653248 return error.AnalysisFail;
31663249 }
......@@ -3200,6 +3283,14 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
32003283 deleted_decls.putAssumeCapacityNoClobber(entry.key, {});
32013284 }
32023285
3286 // Keep track of decls that are invalidated from the update. Ultimately,
3287 // the goal is to queue up `analyze_decl` tasks in the work queue for
3288 // the outdated decls, but we cannot queue up the tasks until after
3289 // we find out which ones have been deleted, otherwise there would be
3290 // deleted Decl pointers in the work queue.
3291 var outdated_decls = std.AutoArrayHashMap(*Decl, void).init(mod.gpa);
3292 defer outdated_decls.deinit();
3293
32033294 for (decls) |decl_node, decl_i| switch (node_tags[decl_node]) {
32043295 .fn_decl => {
32053296 const fn_proto = node_datas[decl_node].lhs;
......@@ -3210,6 +3301,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
32103301 try mod.semaContainerFn(
32113302 container_scope,
32123303 &deleted_decls,
3304 &outdated_decls,
32133305 decl_node,
32143306 decl_i,
32153307 tree.*,
......@@ -3220,6 +3312,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
32203312 .fn_proto_multi => try mod.semaContainerFn(
32213313 container_scope,
32223314 &deleted_decls,
3315 &outdated_decls,
32233316 decl_node,
32243317 decl_i,
32253318 tree.*,
......@@ -3231,6 +3324,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
32313324 try mod.semaContainerFn(
32323325 container_scope,
32333326 &deleted_decls,
3327 &outdated_decls,
32343328 decl_node,
32353329 decl_i,
32363330 tree.*,
......@@ -3241,6 +3335,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
32413335 .fn_proto => try mod.semaContainerFn(
32423336 container_scope,
32433337 &deleted_decls,
3338 &outdated_decls,
32443339 decl_node,
32453340 decl_i,
32463341 tree.*,
......@@ -3255,6 +3350,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
32553350 try mod.semaContainerFn(
32563351 container_scope,
32573352 &deleted_decls,
3353 &outdated_decls,
32583354 decl_node,
32593355 decl_i,
32603356 tree.*,
......@@ -3265,6 +3361,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
32653361 .fn_proto_multi => try mod.semaContainerFn(
32663362 container_scope,
32673363 &deleted_decls,
3364 &outdated_decls,
32683365 decl_node,
32693366 decl_i,
32703367 tree.*,
......@@ -3276,6 +3373,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
32763373 try mod.semaContainerFn(
32773374 container_scope,
32783375 &deleted_decls,
3376 &outdated_decls,
32793377 decl_node,
32803378 decl_i,
32813379 tree.*,
......@@ -3286,6 +3384,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
32863384 .fn_proto => try mod.semaContainerFn(
32873385 container_scope,
32883386 &deleted_decls,
3387 &outdated_decls,
32893388 decl_node,
32903389 decl_i,
32913390 tree.*,
......@@ -3296,6 +3395,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
32963395 .global_var_decl => try mod.semaContainerVar(
32973396 container_scope,
32983397 &deleted_decls,
3398 &outdated_decls,
32993399 decl_node,
33003400 decl_i,
33013401 tree.*,
......@@ -3304,6 +3404,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
33043404 .local_var_decl => try mod.semaContainerVar(
33053405 container_scope,
33063406 &deleted_decls,
3407 &outdated_decls,
33073408 decl_node,
33083409 decl_i,
33093410 tree.*,
......@@ -3312,6 +3413,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
33123413 .simple_var_decl => try mod.semaContainerVar(
33133414 container_scope,
33143415 &deleted_decls,
3416 &outdated_decls,
33153417 decl_node,
33163418 decl_i,
33173419 tree.*,
......@@ -3320,6 +3422,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
33203422 .aligned_var_decl => try mod.semaContainerVar(
33213423 container_scope,
33223424 &deleted_decls,
3425 &outdated_decls,
33233426 decl_node,
33243427 decl_i,
33253428 tree.*,
......@@ -3372,11 +3475,27 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
33723475 },
33733476 else => unreachable,
33743477 };
3375 // Handle explicitly deleted decls from the source code. Not to be confused
3376 // with when we delete decls because they are no longer referenced.
3478 // Handle explicitly deleted decls from the source code. This is one of two
3479 // places that Decl deletions happen. The other is in `Compilation`, after
3480 // `performAllTheWork`, where we iterate over `Module.deletion_set` and
3481 // delete Decls which are no longer referenced.
3482 // If a Decl is explicitly deleted from source, and also no longer referenced,
3483 // it may be both in this `deleted_decls` set, as well as in the
3484 // `Module.deletion_set`. To avoid deleting it twice, we remove it from the
3485 // deletion set at this time.
33773486 for (deleted_decls.items()) |entry| {
3378 log.debug("noticed '{s}' deleted from source", .{entry.key.name});
3379 try mod.deleteDecl(entry.key);
3487 const decl = entry.key;
3488 log.debug("'{s}' deleted from source", .{decl.name});
3489 if (decl.deletion_flag) {
3490 log.debug("'{s}' redundantly in deletion set; removing", .{decl.name});
3491 mod.deletion_set.removeAssertDiscard(decl);
3492 }
3493 try mod.deleteDecl(decl, &outdated_decls);
3494 }
3495 // Finally we can queue up re-analysis tasks after we have processed
3496 // the deleted decls.
3497 for (outdated_decls.items()) |entry| {
3498 try mod.markOutdatedDecl(entry.key);
33803499 }
33813500}
33823501
......@@ -3384,6 +3503,7 @@ fn semaContainerFn(
33843503 mod: *Module,
33853504 container_scope: *Scope.Container,
33863505 deleted_decls: *std.AutoArrayHashMap(*Decl, void),
3506 outdated_decls: *std.AutoArrayHashMap(*Decl, void),
33873507 decl_node: ast.Node.Index,
33883508 decl_i: usize,
33893509 tree: ast.Tree,
......@@ -3415,7 +3535,7 @@ fn semaContainerFn(
34153535 try mod.failed_decls.putNoClobber(mod.gpa, decl, msg);
34163536 } else {
34173537 if (!srcHashEql(decl.contents_hash, contents_hash)) {
3418 try mod.markOutdatedDecl(decl);
3538 try outdated_decls.put(decl, {});
34193539 decl.contents_hash = contents_hash;
34203540 } else switch (mod.comp.bin_file.tag) {
34213541 .coff => {
......@@ -3450,6 +3570,7 @@ fn semaContainerVar(
34503570 mod: *Module,
34513571 container_scope: *Scope.Container,
34523572 deleted_decls: *std.AutoArrayHashMap(*Decl, void),
3573 outdated_decls: *std.AutoArrayHashMap(*Decl, void),
34533574 decl_node: ast.Node.Index,
34543575 decl_i: usize,
34553576 tree: ast.Tree,
......@@ -3475,7 +3596,7 @@ fn semaContainerVar(
34753596 errdefer err_msg.destroy(mod.gpa);
34763597 try mod.failed_decls.putNoClobber(mod.gpa, decl, err_msg);
34773598 } else if (!srcHashEql(decl.contents_hash, contents_hash)) {
3478 try mod.markOutdatedDecl(decl);
3599 try outdated_decls.put(decl, {});
34793600 decl.contents_hash = contents_hash;
34803601 }
34813602 } else {
......@@ -3505,17 +3626,27 @@ fn semaContainerField(
35053626 log.err("TODO: analyze container field", .{});
35063627}
35073628
3508pub fn deleteDecl(mod: *Module, decl: *Decl) !void {
3629pub fn deleteDecl(
3630 mod: *Module,
3631 decl: *Decl,
3632 outdated_decls: ?*std.AutoArrayHashMap(*Decl, void),
3633) !void {
35093634 const tracy = trace(@src());
35103635 defer tracy.end();
35113636
3512 try mod.deletion_set.ensureCapacity(mod.gpa, mod.deletion_set.items.len + decl.dependencies.items().len);
3637 log.debug("deleting decl '{s}'", .{decl.name});
3638
3639 if (outdated_decls) |map| {
3640 _ = map.swapRemove(decl);
3641 try map.ensureCapacity(map.count() + decl.dependants.count());
3642 }
3643 try mod.deletion_set.ensureCapacity(mod.gpa, mod.deletion_set.count() +
3644 decl.dependencies.count());
35133645
35143646 // Remove from the namespace it resides in. In the case of an anonymous Decl it will
35153647 // not be present in the set, and this does nothing.
35163648 decl.container.removeDecl(decl);
35173649
3518 log.debug("deleting decl '{s}'", .{decl.name});
35193650 const name_hash = decl.fullyQualifiedNameHash();
35203651 mod.decl_table.removeAssertDiscard(name_hash);
35213652 // Remove itself from its dependencies, because we are about to destroy the decl pointer.
......@@ -3526,16 +3657,22 @@ pub fn deleteDecl(mod: *Module, decl: *Decl) !void {
35263657 // We don't recursively perform a deletion here, because during the update,
35273658 // another reference to it may turn up.
35283659 dep.deletion_flag = true;
3529 mod.deletion_set.appendAssumeCapacity(dep);
3660 mod.deletion_set.putAssumeCapacity(dep, {});
35303661 }
35313662 }
3532 // Anything that depends on this deleted decl certainly needs to be re-analyzed.
3663 // Anything that depends on this deleted decl needs to be re-analyzed.
35333664 for (decl.dependants.items()) |entry| {
35343665 const dep = entry.key;
35353666 dep.removeDependency(decl);
3536 if (dep.analysis != .outdated) {
3537 // TODO Move this failure possibility to the top of the function.
3538 try mod.markOutdatedDecl(dep);
3667 if (outdated_decls) |map| {
3668 map.putAssumeCapacity(dep, {});
3669 } else if (std.debug.runtime_safety) {
3670 // If `outdated_decls` is `null`, it means we're being called from
3671 // `Compilation` after `performAllTheWork` and we cannot queue up any
3672 // more work. `dep` must necessarily be another Decl that is no longer
3673 // being referenced, and will be in the `deletion_set`. Otherwise,
3674 // something has gone wrong.
3675 assert(mod.deletion_set.contains(dep));
35393676 }
35403677 }
35413678 if (mod.failed_decls.swapRemove(decl)) |entry| {
......@@ -4455,7 +4592,29 @@ pub fn identifierTokenString(mod: *Module, scope: *Scope, token: ast.TokenIndex)
44554592 var buf: ArrayListUnmanaged(u8) = .{};
44564593 defer buf.deinit(mod.gpa);
44574594 try parseStrLit(mod, scope, token, &buf, ident_name, 1);
4458 return buf.toOwnedSlice(mod.gpa);
4595 const duped = try scope.arena().dupe(u8, buf.items);
4596 return duped;
4597}
4598
4599/// `scope` is only used for error reporting.
4600/// The string is stored in `arena` regardless of whether it uses @"" syntax.
4601pub fn identifierTokenStringTreeArena(
4602 mod: *Module,
4603 scope: *Scope,
4604 token: ast.TokenIndex,
4605 tree: *const ast.Tree,
4606 arena: *Allocator,
4607) InnerError![]u8 {
4608 const token_tags = tree.tokens.items(.tag);
4609 assert(token_tags[token] == .identifier);
4610 const ident_name = tree.tokenSlice(token);
4611 if (!mem.startsWith(u8, ident_name, "@")) {
4612 return arena.dupe(u8, ident_name);
4613 }
4614 var buf: ArrayListUnmanaged(u8) = .{};
4615 defer buf.deinit(mod.gpa);
4616 try parseStrLit(mod, scope, token, &buf, ident_name, 1);
4617 return arena.dupe(u8, buf.items);
44594618}
44604619
44614620/// Given an identifier token, obtain the string for it (possibly parsing as a string
......@@ -4545,3 +4704,10 @@ pub fn parseStrLit(
45454704 },
45464705 }
45474706}
4707
4708pub fn unloadFile(mod: *Module, file_scope: *Scope.File) void {
4709 if (file_scope.status == .unloaded_parse_failure) {
4710 mod.failed_files.swapRemove(file_scope).?.value.destroy(mod.gpa);
4711 }
4712 file_scope.unload(mod.gpa);
4713}
src/Sema.zig+501-88
......@@ -168,7 +168,6 @@ pub fn analyzeBody(
168168 .cmp_lte => try sema.zirCmp(block, inst, .lte),
169169 .cmp_neq => try sema.zirCmp(block, inst, .neq),
170170 .coerce_result_ptr => try sema.zirCoerceResultPtr(block, inst),
171 .@"const" => try sema.zirConst(block, inst),
172171 .decl_ref => try sema.zirDeclRef(block, inst),
173172 .decl_val => try sema.zirDeclVal(block, inst),
174173 .load => try sema.zirLoad(block, inst),
......@@ -179,6 +178,8 @@ pub fn analyzeBody(
179178 .elem_val_node => try sema.zirElemValNode(block, inst),
180179 .enum_literal => try sema.zirEnumLiteral(block, inst),
181180 .enum_literal_small => try sema.zirEnumLiteralSmall(block, inst),
181 .enum_to_int => try sema.zirEnumToInt(block, inst),
182 .int_to_enum => try sema.zirIntToEnum(block, inst),
182183 .err_union_code => try sema.zirErrUnionCode(block, inst),
183184 .err_union_code_ptr => try sema.zirErrUnionCodePtr(block, inst),
184185 .err_union_payload_safe => try sema.zirErrUnionPayload(block, inst, true),
......@@ -201,6 +202,8 @@ pub fn analyzeBody(
201202 .import => try sema.zirImport(block, inst),
202203 .indexable_ptr_len => try sema.zirIndexablePtrLen(block, inst),
203204 .int => try sema.zirInt(block, inst),
205 .float => try sema.zirFloat(block, inst),
206 .float128 => try sema.zirFloat128(block, inst),
204207 .int_type => try sema.zirIntType(block, inst),
205208 .intcast => try sema.zirIntcast(block, inst),
206209 .is_err => try sema.zirIsErr(block, inst),
......@@ -264,7 +267,8 @@ pub fn analyzeBody(
264267 .struct_decl => try sema.zirStructDecl(block, inst, .Auto),
265268 .struct_decl_packed => try sema.zirStructDecl(block, inst, .Packed),
266269 .struct_decl_extern => try sema.zirStructDecl(block, inst, .Extern),
267 .enum_decl => try sema.zirEnumDecl(block, inst),
270 .enum_decl => try sema.zirEnumDecl(block, inst, false),
271 .enum_decl_nonexhaustive => try sema.zirEnumDecl(block, inst, true),
268272 .union_decl => try sema.zirUnionDecl(block, inst),
269273 .opaque_decl => try sema.zirOpaqueDecl(block, inst),
270274
......@@ -498,18 +502,6 @@ fn resolveInstConst(
498502 };
499503}
500504
501fn zirConst(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
502 const tracy = trace(@src());
503 defer tracy.end();
504
505 const tv_ptr = sema.code.instructions.items(.data)[inst].@"const";
506 // Move the TypedValue from old memory to new memory. This allows freeing the ZIR instructions
507 // after analysis. This happens, for example, with variable declaration initialization
508 // expressions.
509 const typed_value_copy = try tv_ptr.copy(sema.arena);
510 return sema.mod.constInst(sema.arena, .unneeded, typed_value_copy);
511}
512
513505fn zirBitcastResultPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
514506 const tracy = trace(@src());
515507 defer tracy.end();
......@@ -617,7 +609,12 @@ fn zirStructDecl(
617609 return sema.analyzeDeclVal(block, src, new_decl);
618610}
619611
620fn zirEnumDecl(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
612fn zirEnumDecl(
613 sema: *Sema,
614 block: *Scope.Block,
615 inst: zir.Inst.Index,
616 nonexhaustive: bool,
617) InnerError!*Inst {
621618 const tracy = trace(@src());
622619 defer tracy.end();
623620
......@@ -788,8 +785,8 @@ fn zirAllocInferred(
788785 const tracy = trace(@src());
789786 defer tracy.end();
790787
791 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
792 const src = inst_data.src();
788 const src_node = sema.code.instructions.items(.data)[inst].node;
789 const src: LazySrcLoc = .{ .node_offset = src_node };
793790
794791 const val_payload = try sema.arena.create(Value.Payload.InferredAlloc);
795792 val_payload.* = .{
......@@ -900,7 +897,7 @@ fn zirValidateStructInitPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Ind
900897 try mod.errNoteNonLazy(
901898 struct_obj.srcLoc(),
902899 msg,
903 "'{s}' declared here",
900 "struct '{s}' declared here",
904901 .{fqn},
905902 );
906903 return mod.failWithOwnedErrorMsg(&block.base, msg);
......@@ -928,7 +925,7 @@ fn failWithBadFieldAccess(
928925 .{ field_name, fqn },
929926 );
930927 errdefer msg.destroy(gpa);
931 try mod.errNoteNonLazy(struct_obj.srcLoc(), msg, "'{s}' declared here", .{fqn});
928 try mod.errNoteNonLazy(struct_obj.srcLoc(), msg, "struct declared here", .{});
932929 break :msg msg;
933930 };
934931 return mod.failWithOwnedErrorMsg(&block.base, msg);
......@@ -1070,6 +1067,31 @@ fn zirInt(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*In
10701067 return sema.mod.constIntUnsigned(sema.arena, .unneeded, Type.initTag(.comptime_int), int);
10711068}
10721069
1070fn zirFloat(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1071 const arena = sema.arena;
1072 const inst_data = sema.code.instructions.items(.data)[inst].float;
1073 const src = inst_data.src();
1074 const number = inst_data.number;
1075
1076 return sema.mod.constInst(arena, src, .{
1077 .ty = Type.initTag(.comptime_float),
1078 .val = try Value.Tag.float_32.create(arena, number),
1079 });
1080}
1081
1082fn zirFloat128(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1083 const arena = sema.arena;
1084 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1085 const extra = sema.code.extraData(zir.Inst.Float128, inst_data.payload_index).data;
1086 const src = inst_data.src();
1087 const number = extra.get();
1088
1089 return sema.mod.constInst(arena, src, .{
1090 .ty = Type.initTag(.comptime_float),
1091 .val = try Value.Tag.float_128.create(arena, number),
1092 });
1093}
1094
10731095fn zirCompileError(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!zir.Inst.Index {
10741096 const tracy = trace(@src());
10751097 defer tracy.end();
......@@ -1385,7 +1407,7 @@ fn zirDeclRef(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError
13851407
13861408 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
13871409 const src = inst_data.src();
1388 const decl = sema.code.decls[inst_data.payload_index];
1410 const decl = sema.owner_decl.dependencies.entries.items[inst_data.payload_index].key;
13891411 return sema.analyzeDeclRef(block, src, decl);
13901412}
13911413
......@@ -1395,7 +1417,7 @@ fn zirDeclVal(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError
13951417
13961418 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
13971419 const src = inst_data.src();
1398 const decl = sema.code.decls[inst_data.payload_index];
1420 const decl = sema.owner_decl.dependencies.entries.items[inst_data.payload_index].key;
13991421 return sema.analyzeDeclVal(block, src, decl);
14001422}
14011423
......@@ -1852,6 +1874,143 @@ fn zirEnumLiteralSmall(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) I
18521874 });
18531875}
18541876
1877fn zirEnumToInt(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1878 const mod = sema.mod;
1879 const arena = sema.arena;
1880 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
1881 const src = inst_data.src();
1882 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
1883 const operand = try sema.resolveInst(inst_data.operand);
1884
1885 const enum_tag: *Inst = switch (operand.ty.zigTypeTag()) {
1886 .Enum => operand,
1887 .Union => {
1888 //if (!operand.ty.unionHasTag()) {
1889 // return mod.fail(
1890 // &block.base,
1891 // operand_src,
1892 // "untagged union '{}' cannot be converted to integer",
1893 // .{dest_ty_src},
1894 // );
1895 //}
1896 return mod.fail(&block.base, operand_src, "TODO zirEnumToInt for tagged unions", .{});
1897 },
1898 else => {
1899 return mod.fail(&block.base, operand_src, "expected enum or tagged union, found {}", .{
1900 operand.ty,
1901 });
1902 },
1903 };
1904
1905 var int_tag_type_buffer: Type.Payload.Bits = undefined;
1906 const int_tag_ty = try enum_tag.ty.intTagType(&int_tag_type_buffer).copy(arena);
1907
1908 if (enum_tag.ty.onePossibleValue()) |opv| {
1909 return mod.constInst(arena, src, .{
1910 .ty = int_tag_ty,
1911 .val = opv,
1912 });
1913 }
1914
1915 if (enum_tag.value()) |enum_tag_val| {
1916 if (enum_tag_val.castTag(.enum_field_index)) |enum_field_payload| {
1917 const field_index = enum_field_payload.data;
1918 switch (enum_tag.ty.tag()) {
1919 .enum_full => {
1920 const enum_full = enum_tag.ty.castTag(.enum_full).?.data;
1921 if (enum_full.values.count() != 0) {
1922 const val = enum_full.values.entries.items[field_index].key;
1923 return mod.constInst(arena, src, .{
1924 .ty = int_tag_ty,
1925 .val = val,
1926 });
1927 } else {
1928 // Field index and integer values are the same.
1929 const val = try Value.Tag.int_u64.create(arena, field_index);
1930 return mod.constInst(arena, src, .{
1931 .ty = int_tag_ty,
1932 .val = val,
1933 });
1934 }
1935 },
1936 .enum_simple => {
1937 // Field index and integer values are the same.
1938 const val = try Value.Tag.int_u64.create(arena, field_index);
1939 return mod.constInst(arena, src, .{
1940 .ty = int_tag_ty,
1941 .val = val,
1942 });
1943 },
1944 else => unreachable,
1945 }
1946 } else {
1947 // Assume it is already an integer and return it directly.
1948 return mod.constInst(arena, src, .{
1949 .ty = int_tag_ty,
1950 .val = enum_tag_val,
1951 });
1952 }
1953 }
1954
1955 try sema.requireRuntimeBlock(block, src);
1956 return block.addUnOp(src, int_tag_ty, .bitcast, enum_tag);
1957}
1958
1959fn zirIntToEnum(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1960 const mod = sema.mod;
1961 const target = mod.getTarget();
1962 const arena = sema.arena;
1963 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1964 const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data;
1965 const src = inst_data.src();
1966 const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
1967 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
1968 const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);
1969 const operand = try sema.resolveInst(extra.rhs);
1970
1971 if (dest_ty.zigTypeTag() != .Enum) {
1972 return mod.fail(&block.base, dest_ty_src, "expected enum, found {}", .{dest_ty});
1973 }
1974
1975 if (dest_ty.isNonexhaustiveEnum()) {
1976 if (operand.value()) |int_val| {
1977 return mod.constInst(arena, src, .{
1978 .ty = dest_ty,
1979 .val = int_val,
1980 });
1981 }
1982 }
1983
1984 if (try sema.resolveDefinedValue(block, operand_src, operand)) |int_val| {
1985 if (!dest_ty.enumHasInt(int_val, target)) {
1986 const msg = msg: {
1987 const msg = try mod.errMsg(
1988 &block.base,
1989 src,
1990 "enum '{}' has no tag with value {}",
1991 .{ dest_ty, int_val },
1992 );
1993 errdefer msg.destroy(sema.gpa);
1994 try mod.errNoteNonLazy(
1995 dest_ty.declSrcLoc(),
1996 msg,
1997 "enum declared here",
1998 .{},
1999 );
2000 break :msg msg;
2001 };
2002 return mod.failWithOwnedErrorMsg(&block.base, msg);
2003 }
2004 return mod.constInst(arena, src, .{
2005 .ty = dest_ty,
2006 .val = int_val,
2007 });
2008 }
2009
2010 try sema.requireRuntimeBlock(block, src);
2011 return block.addUnOp(src, dest_ty, .bitcast, operand);
2012}
2013
18552014/// Pointer in, pointer out.
18562015fn zirOptionalPayloadPtr(
18572016 sema: *Sema,
......@@ -2584,6 +2743,8 @@ fn analyzeSwitch(
25842743 src_node_offset: i32,
25852744) InnerError!*Inst {
25862745 const gpa = sema.gpa;
2746 const mod = sema.mod;
2747
25872748 const special: struct { body: []const zir.Inst.Index, end: usize } = switch (special_prong) {
25882749 .none => .{ .body = &.{}, .end = extra_end },
25892750 .under, .@"else" => blk: {
......@@ -2601,16 +2762,16 @@ fn analyzeSwitch(
26012762 const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = src_node_offset };
26022763
26032764 // Validate usage of '_' prongs.
2604 if (special_prong == .under and !operand.ty.isExhaustiveEnum()) {
2765 if (special_prong == .under and !operand.ty.isNonexhaustiveEnum()) {
26052766 const msg = msg: {
2606 const msg = try sema.mod.errMsg(
2767 const msg = try mod.errMsg(
26072768 &block.base,
26082769 src,
26092770 "'_' prong only allowed when switching on non-exhaustive enums",
26102771 .{},
26112772 );
26122773 errdefer msg.destroy(gpa);
2613 try sema.mod.errNote(
2774 try mod.errNote(
26142775 &block.base,
26152776 special_prong_src,
26162777 msg,
......@@ -2619,14 +2780,123 @@ fn analyzeSwitch(
26192780 );
26202781 break :msg msg;
26212782 };
2622 return sema.mod.failWithOwnedErrorMsg(&block.base, msg);
2783 return mod.failWithOwnedErrorMsg(&block.base, msg);
26232784 }
26242785
26252786 // Validate for duplicate items, missing else prong, and invalid range.
26262787 switch (operand.ty.zigTypeTag()) {
2627 .Enum => return sema.mod.fail(&block.base, src, "TODO validate switch .Enum", .{}),
2628 .ErrorSet => return sema.mod.fail(&block.base, src, "TODO validate switch .ErrorSet", .{}),
2629 .Union => return sema.mod.fail(&block.base, src, "TODO validate switch .Union", .{}),
2788 .Enum => {
2789 var seen_fields = try gpa.alloc(?AstGen.SwitchProngSrc, operand.ty.enumFieldCount());
2790 defer gpa.free(seen_fields);
2791
2792 mem.set(?AstGen.SwitchProngSrc, seen_fields, null);
2793
2794 var extra_index: usize = special.end;
2795 {
2796 var scalar_i: u32 = 0;
2797 while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
2798 const item_ref = @intToEnum(zir.Inst.Ref, sema.code.extra[extra_index]);
2799 extra_index += 1;
2800 const body_len = sema.code.extra[extra_index];
2801 extra_index += 1;
2802 const body = sema.code.extra[extra_index..][0..body_len];
2803 extra_index += body_len;
2804
2805 try sema.validateSwitchItemEnum(
2806 block,
2807 seen_fields,
2808 item_ref,
2809 src_node_offset,
2810 .{ .scalar = scalar_i },
2811 );
2812 }
2813 }
2814 {
2815 var multi_i: u32 = 0;
2816 while (multi_i < multi_cases_len) : (multi_i += 1) {
2817 const items_len = sema.code.extra[extra_index];
2818 extra_index += 1;
2819 const ranges_len = sema.code.extra[extra_index];
2820 extra_index += 1;
2821 const body_len = sema.code.extra[extra_index];
2822 extra_index += 1;
2823 const items = sema.code.refSlice(extra_index, items_len);
2824 extra_index += items_len + body_len;
2825
2826 for (items) |item_ref, item_i| {
2827 try sema.validateSwitchItemEnum(
2828 block,
2829 seen_fields,
2830 item_ref,
2831 src_node_offset,
2832 .{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },
2833 );
2834 }
2835
2836 try sema.validateSwitchNoRange(block, ranges_len, operand.ty, src_node_offset);
2837 }
2838 }
2839 const all_tags_handled = for (seen_fields) |seen_src| {
2840 if (seen_src == null) break false;
2841 } else true;
2842
2843 switch (special_prong) {
2844 .none => {
2845 if (!all_tags_handled) {
2846 const msg = msg: {
2847 const msg = try mod.errMsg(
2848 &block.base,
2849 src,
2850 "switch must handle all possibilities",
2851 .{},
2852 );
2853 errdefer msg.destroy(sema.gpa);
2854 for (seen_fields) |seen_src, i| {
2855 if (seen_src != null) continue;
2856
2857 const field_name = operand.ty.enumFieldName(i);
2858
2859 // TODO have this point to the tag decl instead of here
2860 try mod.errNote(
2861 &block.base,
2862 src,
2863 msg,
2864 "unhandled enumeration value: '{s}'",
2865 .{field_name},
2866 );
2867 }
2868 try mod.errNoteNonLazy(
2869 operand.ty.declSrcLoc(),
2870 msg,
2871 "enum '{}' declared here",
2872 .{operand.ty},
2873 );
2874 break :msg msg;
2875 };
2876 return mod.failWithOwnedErrorMsg(&block.base, msg);
2877 }
2878 },
2879 .under => {
2880 if (all_tags_handled) return mod.fail(
2881 &block.base,
2882 special_prong_src,
2883 "unreachable '_' prong; all cases already handled",
2884 .{},
2885 );
2886 },
2887 .@"else" => {
2888 if (all_tags_handled) return mod.fail(
2889 &block.base,
2890 special_prong_src,
2891 "unreachable else prong; all cases already handled",
2892 .{},
2893 );
2894 },
2895 }
2896 },
2897
2898 .ErrorSet => return mod.fail(&block.base, src, "TODO validate switch .ErrorSet", .{}),
2899 .Union => return mod.fail(&block.base, src, "TODO validate switch .Union", .{}),
26302900 .Int, .ComptimeInt => {
26312901 var range_set = RangeSet.init(gpa);
26322902 defer range_set.deinit();
......@@ -2699,11 +2969,11 @@ fn analyzeSwitch(
26992969 var arena = std.heap.ArenaAllocator.init(gpa);
27002970 defer arena.deinit();
27012971
2702 const min_int = try operand.ty.minInt(&arena, sema.mod.getTarget());
2703 const max_int = try operand.ty.maxInt(&arena, sema.mod.getTarget());
2972 const min_int = try operand.ty.minInt(&arena, mod.getTarget());
2973 const max_int = try operand.ty.maxInt(&arena, mod.getTarget());
27042974 if (try range_set.spans(min_int, max_int)) {
27052975 if (special_prong == .@"else") {
2706 return sema.mod.fail(
2976 return mod.fail(
27072977 &block.base,
27082978 special_prong_src,
27092979 "unreachable else prong; all cases already handled",
......@@ -2714,7 +2984,7 @@ fn analyzeSwitch(
27142984 }
27152985 }
27162986 if (special_prong != .@"else") {
2717 return sema.mod.fail(
2987 return mod.fail(
27182988 &block.base,
27192989 src,
27202990 "switch must handle all possibilities",
......@@ -2777,7 +3047,7 @@ fn analyzeSwitch(
27773047 switch (special_prong) {
27783048 .@"else" => {
27793049 if (true_count + false_count == 2) {
2780 return sema.mod.fail(
3050 return mod.fail(
27813051 &block.base,
27823052 src,
27833053 "unreachable else prong; all cases already handled",
......@@ -2787,7 +3057,7 @@ fn analyzeSwitch(
27873057 },
27883058 .under, .none => {
27893059 if (true_count + false_count < 2) {
2790 return sema.mod.fail(
3060 return mod.fail(
27913061 &block.base,
27923062 src,
27933063 "switch must handle all possibilities",
......@@ -2799,7 +3069,7 @@ fn analyzeSwitch(
27993069 },
28003070 .EnumLiteral, .Void, .Fn, .Pointer, .Type => {
28013071 if (special_prong != .@"else") {
2802 return sema.mod.fail(
3072 return mod.fail(
28033073 &block.base,
28043074 src,
28053075 "else prong required when switching on type '{}'",
......@@ -2871,7 +3141,7 @@ fn analyzeSwitch(
28713141 .AnyFrame,
28723142 .ComptimeFloat,
28733143 .Float,
2874 => return sema.mod.fail(&block.base, operand_src, "invalid switch operand type '{}'", .{
3144 => return mod.fail(&block.base, operand_src, "invalid switch operand type '{}'", .{
28753145 operand.ty,
28763146 }),
28773147 }
......@@ -3146,7 +3416,7 @@ fn resolveSwitchItemVal(
31463416 switch_node_offset: i32,
31473417 switch_prong_src: AstGen.SwitchProngSrc,
31483418 range_expand: AstGen.SwitchProngSrc.RangeExpand,
3149) InnerError!Value {
3419) InnerError!TypedValue {
31503420 const item = try sema.resolveInst(item_ref);
31513421 // We have to avoid the other helper functions here because we cannot construct a LazySrcLoc
31523422 // because we only have the switch AST node. Only if we know for sure we need to report
......@@ -3156,7 +3426,7 @@ fn resolveSwitchItemVal(
31563426 const src = switch_prong_src.resolve(block.src_decl, switch_node_offset, range_expand);
31573427 return sema.failWithUseOfUndef(block, src);
31583428 }
3159 return val;
3429 return TypedValue{ .ty = item.ty, .val = val };
31603430 }
31613431 const src = switch_prong_src.resolve(block.src_decl, switch_node_offset, range_expand);
31623432 return sema.failWithNeededComptime(block, src);
......@@ -3171,8 +3441,8 @@ fn validateSwitchRange(
31713441 src_node_offset: i32,
31723442 switch_prong_src: AstGen.SwitchProngSrc,
31733443) InnerError!void {
3174 const first_val = try sema.resolveSwitchItemVal(block, first_ref, src_node_offset, switch_prong_src, .first);
3175 const last_val = try sema.resolveSwitchItemVal(block, last_ref, src_node_offset, switch_prong_src, .last);
3444 const first_val = (try sema.resolveSwitchItemVal(block, first_ref, src_node_offset, switch_prong_src, .first)).val;
3445 const last_val = (try sema.resolveSwitchItemVal(block, last_ref, src_node_offset, switch_prong_src, .last)).val;
31763446 const maybe_prev_src = try range_set.add(first_val, last_val, switch_prong_src);
31773447 return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
31783448}
......@@ -3185,11 +3455,46 @@ fn validateSwitchItem(
31853455 src_node_offset: i32,
31863456 switch_prong_src: AstGen.SwitchProngSrc,
31873457) InnerError!void {
3188 const item_val = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);
3458 const item_val = (try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none)).val;
31893459 const maybe_prev_src = try range_set.add(item_val, item_val, switch_prong_src);
31903460 return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
31913461}
31923462
3463fn validateSwitchItemEnum(
3464 sema: *Sema,
3465 block: *Scope.Block,
3466 seen_fields: []?AstGen.SwitchProngSrc,
3467 item_ref: zir.Inst.Ref,
3468 src_node_offset: i32,
3469 switch_prong_src: AstGen.SwitchProngSrc,
3470) InnerError!void {
3471 const mod = sema.mod;
3472 const item_tv = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);
3473 const field_index = item_tv.ty.enumTagFieldIndex(item_tv.val) orelse {
3474 const msg = msg: {
3475 const src = switch_prong_src.resolve(block.src_decl, src_node_offset, .none);
3476 const msg = try mod.errMsg(
3477 &block.base,
3478 src,
3479 "enum '{}' has no tag with value '{}'",
3480 .{ item_tv.ty, item_tv.val },
3481 );
3482 errdefer msg.destroy(sema.gpa);
3483 try mod.errNoteNonLazy(
3484 item_tv.ty.declSrcLoc(),
3485 msg,
3486 "enum declared here",
3487 .{},
3488 );
3489 break :msg msg;
3490 };
3491 return mod.failWithOwnedErrorMsg(&block.base, msg);
3492 };
3493 const maybe_prev_src = seen_fields[field_index];
3494 seen_fields[field_index] = switch_prong_src;
3495 return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
3496}
3497
31933498fn validateSwitchDupe(
31943499 sema: *Sema,
31953500 block: *Scope.Block,
......@@ -3198,17 +3503,18 @@ fn validateSwitchDupe(
31983503 src_node_offset: i32,
31993504) InnerError!void {
32003505 const prev_prong_src = maybe_prev_src orelse return;
3506 const mod = sema.mod;
32013507 const src = switch_prong_src.resolve(block.src_decl, src_node_offset, .none);
32023508 const prev_src = prev_prong_src.resolve(block.src_decl, src_node_offset, .none);
32033509 const msg = msg: {
3204 const msg = try sema.mod.errMsg(
3510 const msg = try mod.errMsg(
32053511 &block.base,
32063512 src,
32073513 "duplicate switch value",
32083514 .{},
32093515 );
32103516 errdefer msg.destroy(sema.gpa);
3211 try sema.mod.errNote(
3517 try mod.errNote(
32123518 &block.base,
32133519 prev_src,
32143520 msg,
......@@ -3217,7 +3523,7 @@ fn validateSwitchDupe(
32173523 );
32183524 break :msg msg;
32193525 };
3220 return sema.mod.failWithOwnedErrorMsg(&block.base, msg);
3526 return mod.failWithOwnedErrorMsg(&block.base, msg);
32213527}
32223528
32233529fn validateSwitchItemBool(
......@@ -3229,7 +3535,7 @@ fn validateSwitchItemBool(
32293535 src_node_offset: i32,
32303536 switch_prong_src: AstGen.SwitchProngSrc,
32313537) InnerError!void {
3232 const item_val = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);
3538 const item_val = (try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none)).val;
32333539 if (item_val.toBool()) {
32343540 true_count.* += 1;
32353541 } else {
......@@ -3251,7 +3557,7 @@ fn validateSwitchItemSparse(
32513557 src_node_offset: i32,
32523558 switch_prong_src: AstGen.SwitchProngSrc,
32533559) InnerError!void {
3254 const item_val = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);
3560 const item_val = (try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none)).val;
32553561 const entry = (try seen_values.fetchPut(item_val, switch_prong_src)) orelse return;
32563562 return sema.validateSwitchDupe(block, entry.value, switch_prong_src, src_node_offset);
32573563}
......@@ -3631,9 +3937,13 @@ fn zirCmp(
36313937 const tracy = trace(@src());
36323938 defer tracy.end();
36333939
3940 const mod = sema.mod;
3941
36343942 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
36353943 const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data;
36363944 const src: LazySrcLoc = inst_data.src();
3945 const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
3946 const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
36373947 const lhs = try sema.resolveInst(extra.lhs);
36383948 const rhs = try sema.resolveInst(extra.rhs);
36393949
......@@ -3645,7 +3955,7 @@ fn zirCmp(
36453955 const rhs_ty_tag = rhs.ty.zigTypeTag();
36463956 if (is_equality_cmp and lhs_ty_tag == .Null and rhs_ty_tag == .Null) {
36473957 // null == null, null != null
3648 return sema.mod.constBool(sema.arena, src, op == .eq);
3958 return mod.constBool(sema.arena, src, op == .eq);
36493959 } else if (is_equality_cmp and
36503960 ((lhs_ty_tag == .Null and rhs_ty_tag == .Optional) or
36513961 rhs_ty_tag == .Null and lhs_ty_tag == .Optional))
......@@ -3656,23 +3966,23 @@ fn zirCmp(
36563966 } else if (is_equality_cmp and
36573967 ((lhs_ty_tag == .Null and rhs.ty.isCPtr()) or (rhs_ty_tag == .Null and lhs.ty.isCPtr())))
36583968 {
3659 return sema.mod.fail(&block.base, src, "TODO implement C pointer cmp", .{});
3969 return mod.fail(&block.base, src, "TODO implement C pointer cmp", .{});
36603970 } else if (lhs_ty_tag == .Null or rhs_ty_tag == .Null) {
36613971 const non_null_type = if (lhs_ty_tag == .Null) rhs.ty else lhs.ty;
3662 return sema.mod.fail(&block.base, src, "comparison of '{}' with null", .{non_null_type});
3972 return mod.fail(&block.base, src, "comparison of '{}' with null", .{non_null_type});
36633973 } else if (is_equality_cmp and
36643974 ((lhs_ty_tag == .EnumLiteral and rhs_ty_tag == .Union) or
36653975 (rhs_ty_tag == .EnumLiteral and lhs_ty_tag == .Union)))
36663976 {
3667 return sema.mod.fail(&block.base, src, "TODO implement equality comparison between a union's tag value and an enum literal", .{});
3977 return mod.fail(&block.base, src, "TODO implement equality comparison between a union's tag value and an enum literal", .{});
36683978 } else if (lhs_ty_tag == .ErrorSet and rhs_ty_tag == .ErrorSet) {
36693979 if (!is_equality_cmp) {
3670 return sema.mod.fail(&block.base, src, "{s} operator not allowed for errors", .{@tagName(op)});
3980 return mod.fail(&block.base, src, "{s} operator not allowed for errors", .{@tagName(op)});
36713981 }
36723982 if (rhs.value()) |rval| {
36733983 if (lhs.value()) |lval| {
36743984 // TODO optimisation oppurtunity: evaluate if std.mem.eql is faster with the names, or calling to Module.getErrorValue to get the values and then compare them is faster
3675 return sema.mod.constBool(sema.arena, src, std.mem.eql(u8, lval.castTag(.@"error").?.data.name, rval.castTag(.@"error").?.data.name) == (op == .eq));
3985 return mod.constBool(sema.arena, src, std.mem.eql(u8, lval.castTag(.@"error").?.data.name, rval.castTag(.@"error").?.data.name) == (op == .eq));
36763986 }
36773987 }
36783988 try sema.requireRuntimeBlock(block, src);
......@@ -3684,11 +3994,30 @@ fn zirCmp(
36843994 return sema.cmpNumeric(block, src, lhs, rhs, op);
36853995 } else if (lhs_ty_tag == .Type and rhs_ty_tag == .Type) {
36863996 if (!is_equality_cmp) {
3687 return sema.mod.fail(&block.base, src, "{s} operator not allowed for types", .{@tagName(op)});
3997 return mod.fail(&block.base, src, "{s} operator not allowed for types", .{@tagName(op)});
36883998 }
3689 return sema.mod.constBool(sema.arena, src, lhs.value().?.eql(rhs.value().?) == (op == .eq));
3999 return mod.constBool(sema.arena, src, lhs.value().?.eql(rhs.value().?) == (op == .eq));
4000 }
4001
4002 const instructions = &[_]*Inst{ lhs, rhs };
4003 const resolved_type = try sema.resolvePeerTypes(block, src, instructions);
4004 if (!resolved_type.isSelfComparable(is_equality_cmp)) {
4005 return mod.fail(&block.base, src, "operator not allowed for type '{}'", .{resolved_type});
36904006 }
3691 return sema.mod.fail(&block.base, src, "TODO implement more cmp analysis", .{});
4007
4008 const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
4009 const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
4010 try sema.requireRuntimeBlock(block, src); // TODO try to do it at comptime
4011 const bool_type = Type.initTag(.bool); // TODO handle vectors
4012 const tag: Inst.Tag = switch (op) {
4013 .lt => .cmp_lt,
4014 .lte => .cmp_lte,
4015 .eq => .cmp_eq,
4016 .gte => .cmp_gte,
4017 .gt => .cmp_gt,
4018 .neq => .cmp_neq,
4019 };
4020 return block.addBinOp(src, bool_type, tag, casted_lhs, casted_rhs);
36924021}
36934022
36944023fn zirTypeof(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
......@@ -4215,22 +4544,25 @@ fn namedFieldPtr(
42154544 field_name: []const u8,
42164545 field_name_src: LazySrcLoc,
42174546) InnerError!*Inst {
4547 const mod = sema.mod;
4548 const arena = sema.arena;
4549
42184550 const elem_ty = switch (object_ptr.ty.zigTypeTag()) {
42194551 .Pointer => object_ptr.ty.elemType(),
4220 else => return sema.mod.fail(&block.base, object_ptr.src, "expected pointer, found '{}'", .{object_ptr.ty}),
4552 else => return mod.fail(&block.base, object_ptr.src, "expected pointer, found '{}'", .{object_ptr.ty}),
42214553 };
42224554 switch (elem_ty.zigTypeTag()) {
42234555 .Array => {
42244556 if (mem.eql(u8, field_name, "len")) {
4225 return sema.mod.constInst(sema.arena, src, .{
4557 return mod.constInst(arena, src, .{
42264558 .ty = Type.initTag(.single_const_pointer_to_comptime_int),
42274559 .val = try Value.Tag.ref_val.create(
4228 sema.arena,
4229 try Value.Tag.int_u64.create(sema.arena, elem_ty.arrayLen()),
4560 arena,
4561 try Value.Tag.int_u64.create(arena, elem_ty.arrayLen()),
42304562 ),
42314563 });
42324564 } else {
4233 return sema.mod.fail(
4565 return mod.fail(
42344566 &block.base,
42354567 field_name_src,
42364568 "no member named '{s}' in '{}'",
......@@ -4243,15 +4575,15 @@ fn namedFieldPtr(
42434575 switch (ptr_child.zigTypeTag()) {
42444576 .Array => {
42454577 if (mem.eql(u8, field_name, "len")) {
4246 return sema.mod.constInst(sema.arena, src, .{
4578 return mod.constInst(arena, src, .{
42474579 .ty = Type.initTag(.single_const_pointer_to_comptime_int),
42484580 .val = try Value.Tag.ref_val.create(
4249 sema.arena,
4250 try Value.Tag.int_u64.create(sema.arena, ptr_child.arrayLen()),
4581 arena,
4582 try Value.Tag.int_u64.create(arena, ptr_child.arrayLen()),
42514583 ),
42524584 });
42534585 } else {
4254 return sema.mod.fail(
4586 return mod.fail(
42554587 &block.base,
42564588 field_name_src,
42574589 "no member named '{s}' in '{}'",
......@@ -4266,7 +4598,7 @@ fn namedFieldPtr(
42664598 _ = try sema.resolveConstValue(block, object_ptr.src, object_ptr);
42674599 const result = try sema.analyzeLoad(block, src, object_ptr, object_ptr.src);
42684600 const val = result.value().?;
4269 const child_type = try val.toType(sema.arena);
4601 const child_type = try val.toType(arena);
42704602 switch (child_type.zigTypeTag()) {
42714603 .ErrorSet => {
42724604 // TODO resolve inferred error sets
......@@ -4280,42 +4612,90 @@ fn namedFieldPtr(
42804612 break :blk name;
42814613 }
42824614 }
4283 return sema.mod.fail(&block.base, src, "no error named '{s}' in '{}'", .{
4615 return mod.fail(&block.base, src, "no error named '{s}' in '{}'", .{
42844616 field_name,
42854617 child_type,
42864618 });
4287 } else (try sema.mod.getErrorValue(field_name)).key;
4619 } else (try mod.getErrorValue(field_name)).key;
42884620
4289 return sema.mod.constInst(sema.arena, src, .{
4290 .ty = try sema.mod.simplePtrType(sema.arena, child_type, false, .One),
4621 return mod.constInst(arena, src, .{
4622 .ty = try mod.simplePtrType(arena, child_type, false, .One),
42914623 .val = try Value.Tag.ref_val.create(
4292 sema.arena,
4293 try Value.Tag.@"error".create(sema.arena, .{
4624 arena,
4625 try Value.Tag.@"error".create(arena, .{
42944626 .name = name,
42954627 }),
42964628 ),
42974629 });
42984630 },
4299 .Struct => {
4300 const container_scope = child_type.getContainerScope();
4301 if (sema.mod.lookupDeclName(&container_scope.base, field_name)) |decl| {
4302 // TODO if !decl.is_pub and inDifferentFiles() "{} is private"
4303 return sema.analyzeDeclRef(block, src, decl);
4304 }
4631 .Struct, .Opaque, .Union => {
4632 if (child_type.getContainerScope()) |container_scope| {
4633 if (mod.lookupDeclName(&container_scope.base, field_name)) |decl| {
4634 // TODO if !decl.is_pub and inDifferentFiles() "{} is private"
4635 return sema.analyzeDeclRef(block, src, decl);
4636 }
43054637
4306 if (container_scope.file_scope == sema.mod.root_scope) {
4307 return sema.mod.fail(&block.base, src, "root source file has no member called '{s}'", .{field_name});
4308 } else {
4309 return sema.mod.fail(&block.base, src, "container '{}' has no member called '{s}'", .{ child_type, field_name });
4638 // TODO this will give false positives for structs inside the root file
4639 if (container_scope.file_scope == mod.root_scope) {
4640 return mod.fail(
4641 &block.base,
4642 src,
4643 "root source file has no member named '{s}'",
4644 .{field_name},
4645 );
4646 }
43104647 }
4648 // TODO add note: declared here
4649 const kw_name = switch (child_type.zigTypeTag()) {
4650 .Struct => "struct",
4651 .Opaque => "opaque",
4652 .Union => "union",
4653 else => unreachable,
4654 };
4655 return mod.fail(&block.base, src, "{s} '{}' has no member named '{s}'", .{
4656 kw_name, child_type, field_name,
4657 });
43114658 },
4312 else => return sema.mod.fail(&block.base, src, "type '{}' does not support field access", .{child_type}),
4659 .Enum => {
4660 if (child_type.getContainerScope()) |container_scope| {
4661 if (mod.lookupDeclName(&container_scope.base, field_name)) |decl| {
4662 // TODO if !decl.is_pub and inDifferentFiles() "{} is private"
4663 return sema.analyzeDeclRef(block, src, decl);
4664 }
4665 }
4666 const field_index = child_type.enumFieldIndex(field_name) orelse {
4667 const msg = msg: {
4668 const msg = try mod.errMsg(
4669 &block.base,
4670 src,
4671 "enum '{}' has no member named '{s}'",
4672 .{ child_type, field_name },
4673 );
4674 errdefer msg.destroy(sema.gpa);
4675 try mod.errNoteNonLazy(
4676 child_type.declSrcLoc(),
4677 msg,
4678 "enum declared here",
4679 .{},
4680 );
4681 break :msg msg;
4682 };
4683 return mod.failWithOwnedErrorMsg(&block.base, msg);
4684 };
4685 const field_index_u32 = @intCast(u32, field_index);
4686 const enum_val = try Value.Tag.enum_field_index.create(arena, field_index_u32);
4687 return mod.constInst(arena, src, .{
4688 .ty = try mod.simplePtrType(arena, child_type, false, .One),
4689 .val = try Value.Tag.ref_val.create(arena, enum_val),
4690 });
4691 },
4692 else => return mod.fail(&block.base, src, "type '{}' has no members", .{child_type}),
43134693 }
43144694 },
43154695 .Struct => return sema.analyzeStructFieldPtr(block, src, object_ptr, field_name, field_name_src, elem_ty),
43164696 else => {},
43174697 }
4318 return sema.mod.fail(&block.base, src, "type '{}' does not support field access", .{elem_ty});
4698 return mod.fail(&block.base, src, "type '{}' does not support field access", .{elem_ty});
43194699}
43204700
43214701fn analyzeStructFieldPtr(
......@@ -4400,10 +4780,13 @@ fn coerce(
44004780 return sema.bitcast(block, dest_type, inst);
44014781 }
44024782
4783 const mod = sema.mod;
4784 const arena = sema.arena;
4785
44034786 // undefined to anything
44044787 if (inst.value()) |val| {
44054788 if (val.isUndef() or inst.ty.zigTypeTag() == .Undefined) {
4406 return sema.mod.constInst(sema.arena, inst_src, .{ .ty = dest_type, .val = val });
4789 return mod.constInst(arena, inst_src, .{ .ty = dest_type, .val = val });
44074790 }
44084791 }
44094792 assert(inst.ty.zigTypeTag() != .Undefined);
......@@ -4417,13 +4800,13 @@ fn coerce(
44174800 if (try sema.coerceNum(block, dest_type, inst)) |some|
44184801 return some;
44194802
4420 const target = sema.mod.getTarget();
4803 const target = mod.getTarget();
44214804
44224805 switch (dest_type.zigTypeTag()) {
44234806 .Optional => {
44244807 // null to ?T
44254808 if (inst.ty.zigTypeTag() == .Null) {
4426 return sema.mod.constInst(sema.arena, inst_src, .{ .ty = dest_type, .val = Value.initTag(.null_value) });
4809 return mod.constInst(arena, inst_src, .{ .ty = dest_type, .val = Value.initTag(.null_value) });
44274810 }
44284811
44294812 // T to ?T
......@@ -4509,10 +4892,40 @@ fn coerce(
45094892 }
45104893 }
45114894 },
4895 .Enum => {
4896 // enum literal to enum
4897 if (inst.ty.zigTypeTag() == .EnumLiteral) {
4898 const val = try sema.resolveConstValue(block, inst_src, inst);
4899 const bytes = val.castTag(.enum_literal).?.data;
4900 const field_index = dest_type.enumFieldIndex(bytes) orelse {
4901 const msg = msg: {
4902 const msg = try mod.errMsg(
4903 &block.base,
4904 inst_src,
4905 "enum '{}' has no field named '{s}'",
4906 .{ dest_type, bytes },
4907 );
4908 errdefer msg.destroy(sema.gpa);
4909 try mod.errNoteNonLazy(
4910 dest_type.declSrcLoc(),
4911 msg,
4912 "enum declared here",
4913 .{},
4914 );
4915 break :msg msg;
4916 };
4917 return mod.failWithOwnedErrorMsg(&block.base, msg);
4918 };
4919 return mod.constInst(arena, inst_src, .{
4920 .ty = dest_type,
4921 .val = try Value.Tag.enum_field_index.create(arena, @intCast(u32, field_index)),
4922 });
4923 }
4924 },
45124925 else => {},
45134926 }
45144927
4515 return sema.mod.fail(&block.base, inst_src, "expected {}, found {}", .{ dest_type, inst.ty });
4928 return mod.fail(&block.base, inst_src, "expected {}, found {}", .{ dest_type, inst.ty });
45164929}
45174930
45184931const InMemoryCoercionResult = enum {
......@@ -4630,7 +5043,7 @@ fn analyzeDeclVal(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, decl: *Decl
46305043}
46315044
46325045fn analyzeDeclRef(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, decl: *Decl) InnerError!*Inst {
4633 try sema.mod.declareDeclDependency(sema.owner_decl, decl);
5046 _ = try sema.mod.declareDeclDependency(sema.owner_decl, decl);
46345047 sema.mod.ensureDeclAnalyzed(decl) catch |err| {
46355048 if (sema.func) |func| {
46365049 func.state = .dependency_failure;
src/codegen/c.zig+55-5
......@@ -172,7 +172,10 @@ pub const DeclGen = struct {
172172 val: Value,
173173 ) error{ OutOfMemory, AnalysisFail }!void {
174174 if (val.isUndef()) {
175 return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: properly handle undefined in all cases (with debug safety?)", .{});
175 // This should lower to 0xaa bytes in safe modes, and for unsafe modes should
176 // lower to leaving variables uninitialized (that might need to be implemented
177 // outside of this function).
178 return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement renderValue undef", .{});
176179 }
177180 switch (t.zigTypeTag()) {
178181 .Int => {
......@@ -288,6 +291,31 @@ pub const DeclGen = struct {
288291 try writer.writeAll(", .error = 0 }");
289292 }
290293 },
294 .Enum => {
295 switch (val.tag()) {
296 .enum_field_index => {
297 const field_index = val.castTag(.enum_field_index).?.data;
298 switch (t.tag()) {
299 .enum_simple => return writer.print("{d}", .{field_index}),
300 .enum_full, .enum_nonexhaustive => {
301 const enum_full = t.cast(Type.Payload.EnumFull).?.data;
302 if (enum_full.values.count() != 0) {
303 const tag_val = enum_full.values.entries.items[field_index].key;
304 return dg.renderValue(writer, enum_full.tag_ty, tag_val);
305 } else {
306 return writer.print("{d}", .{field_index});
307 }
308 },
309 else => unreachable,
310 }
311 },
312 else => {
313 var int_tag_ty_buffer: Type.Payload.Bits = undefined;
314 const int_tag_ty = t.intTagType(&int_tag_ty_buffer);
315 return dg.renderValue(writer, int_tag_ty, val);
316 },
317 }
318 },
291319 else => |e| return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement value {s}", .{
292320 @tagName(e),
293321 }),
......@@ -368,6 +396,9 @@ pub const DeclGen = struct {
368396 else => unreachable,
369397 }
370398 },
399
400 .Float => return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement type Float", .{}),
401
371402 .Pointer => {
372403 if (t.isSlice()) {
373404 return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement slices", .{});
......@@ -472,10 +503,29 @@ pub const DeclGen = struct {
472503 try w.writeAll(name);
473504 dg.typedefs.putAssumeCapacityNoClobber(t, .{ .name = name, .rendered = rendered });
474505 },
475 .Null, .Undefined => unreachable, // must be const or comptime
476 else => |e| return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement type {s}", .{
477 @tagName(e),
478 }),
506 .Enum => {
507 // For enums, we simply use the integer tag type.
508 var int_tag_ty_buffer: Type.Payload.Bits = undefined;
509 const int_tag_ty = t.intTagType(&int_tag_ty_buffer);
510
511 try dg.renderType(w, int_tag_ty);
512 },
513 .Union => return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement type Union", .{}),
514 .Fn => return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement type Fn", .{}),
515 .Opaque => return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement type Opaque", .{}),
516 .Frame => return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement type Frame", .{}),
517 .AnyFrame => return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement type AnyFrame", .{}),
518 .Vector => return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement type Vector", .{}),
519
520 .Null,
521 .Undefined,
522 .EnumLiteral,
523 .ComptimeFloat,
524 .ComptimeInt,
525 .Type,
526 => unreachable, // must be const or comptime
527
528 .BoundFn => unreachable, // this type will be deleted from the language
479529 }
480530 }
481531
src/type.zig+623-1742
......@@ -93,14 +93,56 @@ pub const Type = extern union {
9393
9494 .anyerror_void_error_union, .error_union => return .ErrorUnion,
9595
96 .empty_struct => return .Struct,
97 .empty_struct_literal => return .Struct,
98 .@"struct" => return .Struct,
96 .empty_struct,
97 .empty_struct_literal,
98 .@"struct",
99 => return .Struct,
100
101 .enum_full,
102 .enum_nonexhaustive,
103 .enum_simple,
104 => return .Enum,
99105
100106 .var_args_param => unreachable, // can be any type
101107 }
102108 }
103109
110 pub fn isSelfComparable(ty: Type, is_equality_cmp: bool) bool {
111 return switch (ty.zigTypeTag()) {
112 .Int,
113 .Float,
114 .ComptimeFloat,
115 .ComptimeInt,
116 .Vector, // TODO some vectors require is_equality_cmp==true
117 => true,
118
119 .Bool,
120 .Type,
121 .Void,
122 .ErrorSet,
123 .Fn,
124 .BoundFn,
125 .Opaque,
126 .AnyFrame,
127 .Enum,
128 .EnumLiteral,
129 => is_equality_cmp,
130
131 .NoReturn,
132 .Array,
133 .Struct,
134 .Undefined,
135 .Null,
136 .ErrorUnion,
137 .Union,
138 .Frame,
139 => false,
140
141 .Pointer => is_equality_cmp or ty.isCPtr(),
142 .Optional => is_equality_cmp and ty.isPtrLikeOptional(),
143 };
144 }
145
104146 pub fn initTag(comptime small_tag: Tag) Type {
105147 comptime assert(@enumToInt(small_tag) < Tag.no_payload_count);
106148 return .{ .tag_if_small_enough = @enumToInt(small_tag) };
......@@ -614,6 +656,8 @@ pub const Type = extern union {
614656 .error_set_single => return self.copyPayloadShallow(allocator, Payload.Name),
615657 .empty_struct => return self.copyPayloadShallow(allocator, Payload.ContainerScope),
616658 .@"struct" => return self.copyPayloadShallow(allocator, Payload.Struct),
659 .enum_simple => return self.copyPayloadShallow(allocator, Payload.EnumSimple),
660 .enum_full, .enum_nonexhaustive => return self.copyPayloadShallow(allocator, Payload.EnumFull),
617661 .@"opaque" => return self.copyPayloadShallow(allocator, Payload.Opaque),
618662 }
619663 }
......@@ -626,13 +670,13 @@ pub const Type = extern union {
626670 }
627671
628672 pub fn format(
629 self: Type,
673 start_type: Type,
630674 comptime fmt: []const u8,
631675 options: std.fmt.FormatOptions,
632 out_stream: anytype,
633 ) @TypeOf(out_stream).Error!void {
676 writer: anytype,
677 ) @TypeOf(writer).Error!void {
634678 comptime assert(fmt.len == 0);
635 var ty = self;
679 var ty = start_type;
636680 while (true) {
637681 const t = ty.tag();
638682 switch (t) {
......@@ -670,132 +714,149 @@ pub const Type = extern union {
670714 .comptime_float,
671715 .noreturn,
672716 .var_args_param,
673 => return out_stream.writeAll(@tagName(t)),
674
675 .enum_literal => return out_stream.writeAll("@Type(.EnumLiteral)"),
676 .@"null" => return out_stream.writeAll("@Type(.Null)"),
677 .@"undefined" => return out_stream.writeAll("@Type(.Undefined)"),
678
679 .empty_struct, .empty_struct_literal => return out_stream.writeAll("struct {}"),
680 .@"struct" => return out_stream.writeAll("(struct)"),
681 .anyerror_void_error_union => return out_stream.writeAll("anyerror!void"),
682 .const_slice_u8 => return out_stream.writeAll("[]const u8"),
683 .fn_noreturn_no_args => return out_stream.writeAll("fn() noreturn"),
684 .fn_void_no_args => return out_stream.writeAll("fn() void"),
685 .fn_naked_noreturn_no_args => return out_stream.writeAll("fn() callconv(.Naked) noreturn"),
686 .fn_ccc_void_no_args => return out_stream.writeAll("fn() callconv(.C) void"),
687 .single_const_pointer_to_comptime_int => return out_stream.writeAll("*const comptime_int"),
717 => return writer.writeAll(@tagName(t)),
718
719 .enum_literal => return writer.writeAll("@Type(.EnumLiteral)"),
720 .@"null" => return writer.writeAll("@Type(.Null)"),
721 .@"undefined" => return writer.writeAll("@Type(.Undefined)"),
722
723 .empty_struct, .empty_struct_literal => return writer.writeAll("struct {}"),
724
725 .@"struct" => {
726 const struct_obj = ty.castTag(.@"struct").?.data;
727 return struct_obj.owner_decl.renderFullyQualifiedName(writer);
728 },
729 .enum_full, .enum_nonexhaustive => {
730 const enum_full = ty.cast(Payload.EnumFull).?.data;
731 return enum_full.owner_decl.renderFullyQualifiedName(writer);
732 },
733 .enum_simple => {
734 const enum_simple = ty.castTag(.enum_simple).?.data;
735 return enum_simple.owner_decl.renderFullyQualifiedName(writer);
736 },
737 .@"opaque" => {
738 // TODO use declaration name
739 return writer.writeAll("opaque {}");
740 },
741
742 .anyerror_void_error_union => return writer.writeAll("anyerror!void"),
743 .const_slice_u8 => return writer.writeAll("[]const u8"),
744 .fn_noreturn_no_args => return writer.writeAll("fn() noreturn"),
745 .fn_void_no_args => return writer.writeAll("fn() void"),
746 .fn_naked_noreturn_no_args => return writer.writeAll("fn() callconv(.Naked) noreturn"),
747 .fn_ccc_void_no_args => return writer.writeAll("fn() callconv(.C) void"),
748 .single_const_pointer_to_comptime_int => return writer.writeAll("*const comptime_int"),
688749 .function => {
689750 const payload = ty.castTag(.function).?.data;
690 try out_stream.writeAll("fn(");
751 try writer.writeAll("fn(");
691752 for (payload.param_types) |param_type, i| {
692 if (i != 0) try out_stream.writeAll(", ");
693 try param_type.format("", .{}, out_stream);
753 if (i != 0) try writer.writeAll(", ");
754 try param_type.format("", .{}, writer);
694755 }
695756 if (payload.is_var_args) {
696757 if (payload.param_types.len != 0) {
697 try out_stream.writeAll(", ");
758 try writer.writeAll(", ");
698759 }
699 try out_stream.writeAll("...");
760 try writer.writeAll("...");
700761 }
701 try out_stream.writeAll(") callconv(.");
702 try out_stream.writeAll(@tagName(payload.cc));
703 try out_stream.writeAll(")");
762 try writer.writeAll(") callconv(.");
763 try writer.writeAll(@tagName(payload.cc));
764 try writer.writeAll(")");
704765 ty = payload.return_type;
705766 continue;
706767 },
707768
708769 .array_u8 => {
709770 const len = ty.castTag(.array_u8).?.data;
710 return out_stream.print("[{d}]u8", .{len});
771 return writer.print("[{d}]u8", .{len});
711772 },
712773 .array_u8_sentinel_0 => {
713774 const len = ty.castTag(.array_u8_sentinel_0).?.data;
714 return out_stream.print("[{d}:0]u8", .{len});
775 return writer.print("[{d}:0]u8", .{len});
715776 },
716777 .array => {
717778 const payload = ty.castTag(.array).?.data;
718 try out_stream.print("[{d}]", .{payload.len});
779 try writer.print("[{d}]", .{payload.len});
719780 ty = payload.elem_type;
720781 continue;
721782 },
722783 .array_sentinel => {
723784 const payload = ty.castTag(.array_sentinel).?.data;
724 try out_stream.print("[{d}:{}]", .{ payload.len, payload.sentinel });
785 try writer.print("[{d}:{}]", .{ payload.len, payload.sentinel });
725786 ty = payload.elem_type;
726787 continue;
727788 },
728789 .single_const_pointer => {
729790 const pointee_type = ty.castTag(.single_const_pointer).?.data;
730 try out_stream.writeAll("*const ");
791 try writer.writeAll("*const ");
731792 ty = pointee_type;
732793 continue;
733794 },
734795 .single_mut_pointer => {
735796 const pointee_type = ty.castTag(.single_mut_pointer).?.data;
736 try out_stream.writeAll("*");
797 try writer.writeAll("*");
737798 ty = pointee_type;
738799 continue;
739800 },
740801 .many_const_pointer => {
741802 const pointee_type = ty.castTag(.many_const_pointer).?.data;
742 try out_stream.writeAll("[*]const ");
803 try writer.writeAll("[*]const ");
743804 ty = pointee_type;
744805 continue;
745806 },
746807 .many_mut_pointer => {
747808 const pointee_type = ty.castTag(.many_mut_pointer).?.data;
748 try out_stream.writeAll("[*]");
809 try writer.writeAll("[*]");
749810 ty = pointee_type;
750811 continue;
751812 },
752813 .c_const_pointer => {
753814 const pointee_type = ty.castTag(.c_const_pointer).?.data;
754 try out_stream.writeAll("[*c]const ");
815 try writer.writeAll("[*c]const ");
755816 ty = pointee_type;
756817 continue;
757818 },
758819 .c_mut_pointer => {
759820 const pointee_type = ty.castTag(.c_mut_pointer).?.data;
760 try out_stream.writeAll("[*c]");
821 try writer.writeAll("[*c]");
761822 ty = pointee_type;
762823 continue;
763824 },
764825 .const_slice => {
765826 const pointee_type = ty.castTag(.const_slice).?.data;
766 try out_stream.writeAll("[]const ");
827 try writer.writeAll("[]const ");
767828 ty = pointee_type;
768829 continue;
769830 },
770831 .mut_slice => {
771832 const pointee_type = ty.castTag(.mut_slice).?.data;
772 try out_stream.writeAll("[]");
833 try writer.writeAll("[]");
773834 ty = pointee_type;
774835 continue;
775836 },
776837 .int_signed => {
777838 const bits = ty.castTag(.int_signed).?.data;
778 return out_stream.print("i{d}", .{bits});
839 return writer.print("i{d}", .{bits});
779840 },
780841 .int_unsigned => {
781842 const bits = ty.castTag(.int_unsigned).?.data;
782 return out_stream.print("u{d}", .{bits});
843 return writer.print("u{d}", .{bits});
783844 },
784845 .optional => {
785846 const child_type = ty.castTag(.optional).?.data;
786 try out_stream.writeByte('?');
847 try writer.writeByte('?');
787848 ty = child_type;
788849 continue;
789850 },
790851 .optional_single_const_pointer => {
791852 const pointee_type = ty.castTag(.optional_single_const_pointer).?.data;
792 try out_stream.writeAll("?*const ");
853 try writer.writeAll("?*const ");
793854 ty = pointee_type;
794855 continue;
795856 },
796857 .optional_single_mut_pointer => {
797858 const pointee_type = ty.castTag(.optional_single_mut_pointer).?.data;
798 try out_stream.writeAll("?*");
859 try writer.writeAll("?*");
799860 ty = pointee_type;
800861 continue;
801862 },
......@@ -804,48 +865,46 @@ pub const Type = extern union {
804865 const payload = ty.castTag(.pointer).?.data;
805866 if (payload.sentinel) |some| switch (payload.size) {
806867 .One, .C => unreachable,
807 .Many => try out_stream.print("[*:{}]", .{some}),
808 .Slice => try out_stream.print("[:{}]", .{some}),
868 .Many => try writer.print("[*:{}]", .{some}),
869 .Slice => try writer.print("[:{}]", .{some}),
809870 } else switch (payload.size) {
810 .One => try out_stream.writeAll("*"),
811 .Many => try out_stream.writeAll("[*]"),
812 .C => try out_stream.writeAll("[*c]"),
813 .Slice => try out_stream.writeAll("[]"),
871 .One => try writer.writeAll("*"),
872 .Many => try writer.writeAll("[*]"),
873 .C => try writer.writeAll("[*c]"),
874 .Slice => try writer.writeAll("[]"),
814875 }
815876 if (payload.@"align" != 0) {
816 try out_stream.print("align({d}", .{payload.@"align"});
877 try writer.print("align({d}", .{payload.@"align"});
817878
818879 if (payload.bit_offset != 0) {
819 try out_stream.print(":{d}:{d}", .{ payload.bit_offset, payload.host_size });
880 try writer.print(":{d}:{d}", .{ payload.bit_offset, payload.host_size });
820881 }
821 try out_stream.writeAll(") ");
882 try writer.writeAll(") ");
822883 }
823 if (!payload.mutable) try out_stream.writeAll("const ");
824 if (payload.@"volatile") try out_stream.writeAll("volatile ");
825 if (payload.@"allowzero") try out_stream.writeAll("allowzero ");
884 if (!payload.mutable) try writer.writeAll("const ");
885 if (payload.@"volatile") try writer.writeAll("volatile ");
886 if (payload.@"allowzero") try writer.writeAll("allowzero ");
826887
827888 ty = payload.pointee_type;
828889 continue;
829890 },
830891 .error_union => {
831892 const payload = ty.castTag(.error_union).?.data;
832 try payload.error_set.format("", .{}, out_stream);
833 try out_stream.writeAll("!");
893 try payload.error_set.format("", .{}, writer);
894 try writer.writeAll("!");
834895 ty = payload.payload;
835896 continue;
836897 },
837898 .error_set => {
838899 const error_set = ty.castTag(.error_set).?.data;
839 return out_stream.writeAll(std.mem.spanZ(error_set.owner_decl.name));
900 return writer.writeAll(std.mem.spanZ(error_set.owner_decl.name));
840901 },
841902 .error_set_single => {
842903 const name = ty.castTag(.error_set_single).?.data;
843 return out_stream.print("error{{{s}}}", .{name});
904 return writer.print("error{{{s}}}", .{name});
844905 },
845 .inferred_alloc_const => return out_stream.writeAll("(inferred_alloc_const)"),
846 .inferred_alloc_mut => return out_stream.writeAll("(inferred_alloc_mut)"),
847 // TODO use declaration name
848 .@"opaque" => return out_stream.writeAll("opaque {}"),
906 .inferred_alloc_const => return writer.writeAll("(inferred_alloc_const)"),
907 .inferred_alloc_mut => return writer.writeAll("(inferred_alloc_mut)"),
849908 }
850909 unreachable;
851910 }
......@@ -954,6 +1013,19 @@ pub const Type = extern union {
9541013 return false;
9551014 }
9561015 },
1016 .enum_full => {
1017 const enum_full = self.castTag(.enum_full).?.data;
1018 return enum_full.fields.count() >= 2;
1019 },
1020 .enum_simple => {
1021 const enum_simple = self.castTag(.enum_simple).?.data;
1022 return enum_simple.fields.count() >= 2;
1023 },
1024 .enum_nonexhaustive => {
1025 var buffer: Payload.Bits = undefined;
1026 const int_tag_ty = self.intTagType(&buffer);
1027 return int_tag_ty.hasCodeGenBits();
1028 },
9571029
9581030 // TODO lazy types
9591031 .array => self.elemType().hasCodeGenBits() and self.arrayLen() != 0,
......@@ -1112,13 +1184,37 @@ pub const Type = extern union {
11121184 } else if (!payload.payload.hasCodeGenBits()) {
11131185 return payload.error_set.abiAlignment(target);
11141186 }
1115 @panic("TODO abiAlignment error union");
1187 return std.math.max(
1188 payload.payload.abiAlignment(target),
1189 payload.error_set.abiAlignment(target),
1190 );
11161191 },
11171192
11181193 .@"struct" => {
1119 @panic("TODO abiAlignment struct");
1194 // TODO take into account field alignment
1195 // also make this possible to fail, and lazy
1196 // I think we need to move all the functions from type.zig which can
1197 // fail into Sema.
1198 // Probably will need to introduce multi-stage struct resolution just
1199 // like we have in stage1.
1200 const struct_obj = self.castTag(.@"struct").?.data;
1201 var biggest: u32 = 0;
1202 for (struct_obj.fields.entries.items) |entry| {
1203 const field_ty = entry.value.ty;
1204 if (!field_ty.hasCodeGenBits()) continue;
1205 const field_align = field_ty.abiAlignment(target);
1206 if (field_align > biggest) {
1207 return field_align;
1208 }
1209 }
1210 assert(biggest != 0);
1211 return biggest;
1212 },
1213 .enum_full, .enum_nonexhaustive, .enum_simple => {
1214 var buffer: Payload.Bits = undefined;
1215 const int_tag_ty = self.intTagType(&buffer);
1216 return int_tag_ty.abiAlignment(target);
11201217 },
1121
11221218 .c_void,
11231219 .void,
11241220 .type,
......@@ -1166,6 +1262,11 @@ pub const Type = extern union {
11661262 .@"struct" => {
11671263 @panic("TODO abiSize struct");
11681264 },
1265 .enum_simple, .enum_full, .enum_nonexhaustive => {
1266 var buffer: Payload.Bits = undefined;
1267 const int_tag_ty = self.intTagType(&buffer);
1268 return int_tag_ty.abiSize(target);
1269 },
11691270
11701271 .u8,
11711272 .i8,
......@@ -1276,76 +1377,25 @@ pub const Type = extern union {
12761377 };
12771378 }
12781379
1380 /// Asserts the type is an enum.
1381 pub fn intTagType(self: Type, buffer: *Payload.Bits) Type {
1382 switch (self.tag()) {
1383 .enum_full, .enum_nonexhaustive => return self.cast(Payload.EnumFull).?.data.tag_ty,
1384 .enum_simple => {
1385 const enum_simple = self.castTag(.enum_simple).?.data;
1386 const bits = std.math.log2_int_ceil(usize, enum_simple.fields.count());
1387 buffer.* = .{
1388 .base = .{ .tag = .int_unsigned },
1389 .data = bits,
1390 };
1391 return Type.initPayload(&buffer.base);
1392 },
1393 else => unreachable,
1394 }
1395 }
1396
12791397 pub fn isSinglePointer(self: Type) bool {
12801398 return switch (self.tag()) {
1281 .u8,
1282 .i8,
1283 .u16,
1284 .i16,
1285 .u32,
1286 .i32,
1287 .u64,
1288 .i64,
1289 .u128,
1290 .i128,
1291 .usize,
1292 .isize,
1293 .c_short,
1294 .c_ushort,
1295 .c_int,
1296 .c_uint,
1297 .c_long,
1298 .c_ulong,
1299 .c_longlong,
1300 .c_ulonglong,
1301 .c_longdouble,
1302 .f16,
1303 .f32,
1304 .f64,
1305 .f128,
1306 .c_void,
1307 .bool,
1308 .void,
1309 .type,
1310 .anyerror,
1311 .comptime_int,
1312 .comptime_float,
1313 .noreturn,
1314 .@"null",
1315 .@"undefined",
1316 .array,
1317 .array_sentinel,
1318 .array_u8,
1319 .array_u8_sentinel_0,
1320 .const_slice_u8,
1321 .fn_noreturn_no_args,
1322 .fn_void_no_args,
1323 .fn_naked_noreturn_no_args,
1324 .fn_ccc_void_no_args,
1325 .function,
1326 .int_unsigned,
1327 .int_signed,
1328 .optional,
1329 .optional_single_mut_pointer,
1330 .optional_single_const_pointer,
1331 .enum_literal,
1332 .many_const_pointer,
1333 .many_mut_pointer,
1334 .c_const_pointer,
1335 .c_mut_pointer,
1336 .const_slice,
1337 .mut_slice,
1338 .error_union,
1339 .anyerror_void_error_union,
1340 .error_set,
1341 .error_set_single,
1342 .@"struct",
1343 .empty_struct,
1344 .empty_struct_literal,
1345 .@"opaque",
1346 .var_args_param,
1347 => false,
1348
13491399 .single_const_pointer,
13501400 .single_mut_pointer,
13511401 .single_const_pointer_to_comptime_int,
......@@ -1354,73 +1404,14 @@ pub const Type = extern union {
13541404 => true,
13551405
13561406 .pointer => self.castTag(.pointer).?.data.size == .One,
1407
1408 else => false,
13571409 };
13581410 }
13591411
13601412 /// Asserts the `Type` is a pointer.
13611413 pub fn ptrSize(self: Type) std.builtin.TypeInfo.Pointer.Size {
13621414 return switch (self.tag()) {
1363 .u8,
1364 .i8,
1365 .u16,
1366 .i16,
1367 .u32,
1368 .i32,
1369 .u64,
1370 .i64,
1371 .u128,
1372 .i128,
1373 .usize,
1374 .isize,
1375 .c_short,
1376 .c_ushort,
1377 .c_int,
1378 .c_uint,
1379 .c_long,
1380 .c_ulong,
1381 .c_longlong,
1382 .c_ulonglong,
1383 .c_longdouble,
1384 .f16,
1385 .f32,
1386 .f64,
1387 .f128,
1388 .c_void,
1389 .bool,
1390 .void,
1391 .type,
1392 .anyerror,
1393 .comptime_int,
1394 .comptime_float,
1395 .noreturn,
1396 .@"null",
1397 .@"undefined",
1398 .array,
1399 .array_sentinel,
1400 .array_u8,
1401 .array_u8_sentinel_0,
1402 .fn_noreturn_no_args,
1403 .fn_void_no_args,
1404 .fn_naked_noreturn_no_args,
1405 .fn_ccc_void_no_args,
1406 .function,
1407 .int_unsigned,
1408 .int_signed,
1409 .optional,
1410 .optional_single_mut_pointer,
1411 .optional_single_const_pointer,
1412 .enum_literal,
1413 .error_union,
1414 .anyerror_void_error_union,
1415 .error_set,
1416 .error_set_single,
1417 .empty_struct,
1418 .empty_struct_literal,
1419 .@"opaque",
1420 .@"struct",
1421 .var_args_param,
1422 => unreachable,
1423
14241415 .const_slice,
14251416 .mut_slice,
14261417 .const_slice_u8,
......@@ -1442,159 +1433,26 @@ pub const Type = extern union {
14421433 => .One,
14431434
14441435 .pointer => self.castTag(.pointer).?.data.size,
1436
1437 else => unreachable,
14451438 };
14461439 }
14471440
14481441 pub fn isSlice(self: Type) bool {
14491442 return switch (self.tag()) {
1450 .u8,
1451 .i8,
1452 .u16,
1453 .i16,
1454 .u32,
1455 .i32,
1456 .u64,
1457 .i64,
1458 .u128,
1459 .i128,
1460 .usize,
1461 .isize,
1462 .c_short,
1463 .c_ushort,
1464 .c_int,
1465 .c_uint,
1466 .c_long,
1467 .c_ulong,
1468 .c_longlong,
1469 .c_ulonglong,
1470 .c_longdouble,
1471 .f16,
1472 .f32,
1473 .f64,
1474 .f128,
1475 .c_void,
1476 .bool,
1477 .void,
1478 .type,
1479 .anyerror,
1480 .comptime_int,
1481 .comptime_float,
1482 .noreturn,
1483 .@"null",
1484 .@"undefined",
1485 .array,
1486 .array_sentinel,
1487 .array_u8,
1488 .array_u8_sentinel_0,
1489 .single_const_pointer,
1490 .single_mut_pointer,
1491 .many_const_pointer,
1492 .many_mut_pointer,
1493 .c_const_pointer,
1494 .c_mut_pointer,
1495 .single_const_pointer_to_comptime_int,
1496 .fn_noreturn_no_args,
1497 .fn_void_no_args,
1498 .fn_naked_noreturn_no_args,
1499 .fn_ccc_void_no_args,
1500 .function,
1501 .int_unsigned,
1502 .int_signed,
1503 .optional,
1504 .optional_single_mut_pointer,
1505 .optional_single_const_pointer,
1506 .enum_literal,
1507 .error_union,
1508 .anyerror_void_error_union,
1509 .error_set,
1510 .error_set_single,
1511 .empty_struct,
1512 .empty_struct_literal,
1513 .inferred_alloc_const,
1514 .inferred_alloc_mut,
1515 .@"struct",
1516 .@"opaque",
1517 .var_args_param,
1518 => false,
1519
1520 .const_slice,
1521 .mut_slice,
1522 .const_slice_u8,
1523 => true,
1524
1525 .pointer => self.castTag(.pointer).?.data.size == .Slice,
1526 };
1527 }
1528
1529 pub fn isConstPtr(self: Type) bool {
1530 return switch (self.tag()) {
1531 .u8,
1532 .i8,
1533 .u16,
1534 .i16,
1535 .u32,
1536 .i32,
1537 .u64,
1538 .i64,
1539 .u128,
1540 .i128,
1541 .usize,
1542 .isize,
1543 .c_short,
1544 .c_ushort,
1545 .c_int,
1546 .c_uint,
1547 .c_long,
1548 .c_ulong,
1549 .c_longlong,
1550 .c_ulonglong,
1551 .c_longdouble,
1552 .f16,
1553 .f32,
1554 .f64,
1555 .f128,
1556 .c_void,
1557 .bool,
1558 .void,
1559 .type,
1560 .anyerror,
1561 .comptime_int,
1562 .comptime_float,
1563 .noreturn,
1564 .@"null",
1565 .@"undefined",
1566 .array,
1567 .array_sentinel,
1568 .array_u8,
1569 .array_u8_sentinel_0,
1570 .fn_noreturn_no_args,
1571 .fn_void_no_args,
1572 .fn_naked_noreturn_no_args,
1573 .fn_ccc_void_no_args,
1574 .function,
1575 .int_unsigned,
1576 .int_signed,
1577 .single_mut_pointer,
1578 .many_mut_pointer,
1579 .c_mut_pointer,
1580 .optional,
1581 .optional_single_mut_pointer,
1582 .optional_single_const_pointer,
1583 .enum_literal,
1584 .mut_slice,
1585 .error_union,
1586 .anyerror_void_error_union,
1587 .error_set,
1588 .error_set_single,
1589 .empty_struct,
1590 .empty_struct_literal,
1591 .inferred_alloc_const,
1592 .inferred_alloc_mut,
1593 .@"struct",
1594 .@"opaque",
1595 .var_args_param,
1596 => false,
1597
1443 .const_slice,
1444 .mut_slice,
1445 .const_slice_u8,
1446 => true,
1447
1448 .pointer => self.castTag(.pointer).?.data.size == .Slice,
1449
1450 else => false,
1451 };
1452 }
1453
1454 pub fn isConstPtr(self: Type) bool {
1455 return switch (self.tag()) {
15981456 .single_const_pointer,
15991457 .many_const_pointer,
16001458 .c_const_pointer,
......@@ -1604,181 +1462,51 @@ pub const Type = extern union {
16041462 => true,
16051463
16061464 .pointer => !self.castTag(.pointer).?.data.mutable,
1465
1466 else => false,
16071467 };
16081468 }
16091469
16101470 pub fn isVolatilePtr(self: Type) bool {
16111471 return switch (self.tag()) {
1612 .u8,
1613 .i8,
1614 .u16,
1615 .i16,
1616 .u32,
1617 .i32,
1618 .u64,
1619 .i64,
1620 .u128,
1621 .i128,
1622 .usize,
1623 .isize,
1624 .c_short,
1625 .c_ushort,
1626 .c_int,
1627 .c_uint,
1628 .c_long,
1629 .c_ulong,
1630 .c_longlong,
1631 .c_ulonglong,
1632 .c_longdouble,
1633 .f16,
1634 .f32,
1635 .f64,
1636 .f128,
1637 .c_void,
1638 .bool,
1639 .void,
1640 .type,
1641 .anyerror,
1642 .comptime_int,
1643 .comptime_float,
1644 .noreturn,
1645 .@"null",
1646 .@"undefined",
1647 .array,
1648 .array_sentinel,
1649 .array_u8,
1650 .array_u8_sentinel_0,
1651 .fn_noreturn_no_args,
1652 .fn_void_no_args,
1653 .fn_naked_noreturn_no_args,
1654 .fn_ccc_void_no_args,
1655 .function,
1656 .int_unsigned,
1657 .int_signed,
1658 .single_mut_pointer,
1659 .single_const_pointer,
1660 .many_const_pointer,
1661 .many_mut_pointer,
1662 .c_const_pointer,
1663 .c_mut_pointer,
1664 .const_slice,
1665 .mut_slice,
1666 .single_const_pointer_to_comptime_int,
1667 .const_slice_u8,
1668 .optional,
1669 .optional_single_mut_pointer,
1670 .optional_single_const_pointer,
1671 .enum_literal,
1672 .error_union,
1673 .anyerror_void_error_union,
1674 .error_set,
1675 .error_set_single,
1676 .empty_struct,
1677 .empty_struct_literal,
1678 .inferred_alloc_const,
1679 .inferred_alloc_mut,
1680 .@"struct",
1681 .@"opaque",
1682 .var_args_param,
1683 => false,
1684
16851472 .pointer => {
16861473 const payload = self.castTag(.pointer).?.data;
16871474 return payload.@"volatile";
16881475 },
1476 else => false,
16891477 };
16901478 }
16911479
16921480 pub fn isAllowzeroPtr(self: Type) bool {
16931481 return switch (self.tag()) {
1694 .u8,
1695 .i8,
1696 .u16,
1697 .i16,
1698 .u32,
1699 .i32,
1700 .u64,
1701 .i64,
1702 .u128,
1703 .i128,
1704 .usize,
1705 .isize,
1706 .c_short,
1707 .c_ushort,
1708 .c_int,
1709 .c_uint,
1710 .c_long,
1711 .c_ulong,
1712 .c_longlong,
1713 .c_ulonglong,
1714 .c_longdouble,
1715 .f16,
1716 .f32,
1717 .f64,
1718 .f128,
1719 .c_void,
1720 .bool,
1721 .void,
1722 .type,
1723 .anyerror,
1724 .comptime_int,
1725 .comptime_float,
1726 .noreturn,
1727 .@"null",
1728 .@"undefined",
1729 .array,
1730 .array_sentinel,
1731 .array_u8,
1732 .array_u8_sentinel_0,
1733 .fn_noreturn_no_args,
1734 .fn_void_no_args,
1735 .fn_naked_noreturn_no_args,
1736 .fn_ccc_void_no_args,
1737 .function,
1738 .int_unsigned,
1739 .int_signed,
1740 .single_mut_pointer,
1741 .single_const_pointer,
1742 .many_const_pointer,
1743 .many_mut_pointer,
1744 .c_const_pointer,
1745 .c_mut_pointer,
1746 .const_slice,
1747 .mut_slice,
1748 .single_const_pointer_to_comptime_int,
1749 .const_slice_u8,
1750 .optional,
1751 .optional_single_mut_pointer,
1752 .optional_single_const_pointer,
1753 .enum_literal,
1754 .error_union,
1755 .anyerror_void_error_union,
1756 .error_set,
1757 .error_set_single,
1758 .empty_struct,
1759 .empty_struct_literal,
1760 .inferred_alloc_const,
1761 .inferred_alloc_mut,
1762 .@"struct",
1763 .@"opaque",
1764 .var_args_param,
1765 => false,
1766
17671482 .pointer => {
17681483 const payload = self.castTag(.pointer).?.data;
17691484 return payload.@"allowzero";
17701485 },
1486 else => false,
17711487 };
17721488 }
17731489
1774 /// Asserts that the type is an optional
1775 pub fn isPtrLikeOptional(self: Type) bool {
1776 switch (self.tag()) {
1777 .optional_single_const_pointer, .optional_single_mut_pointer => return true,
1778 .optional => {
1779 var buf: Payload.ElemType = undefined;
1780 const child_type = self.optionalChild(&buf);
1781 // optionals of zero sized pointers behave like bools
1490 pub fn isCPtr(self: Type) bool {
1491 return switch (self.tag()) {
1492 .c_const_pointer,
1493 .c_mut_pointer,
1494 => return true,
1495
1496 .pointer => self.castTag(.pointer).?.data.size == .C,
1497
1498 else => return false,
1499 };
1500 }
1501
1502 /// Asserts that the type is an optional
1503 pub fn isPtrLikeOptional(self: Type) bool {
1504 switch (self.tag()) {
1505 .optional_single_const_pointer, .optional_single_mut_pointer => return true,
1506 .optional => {
1507 var buf: Payload.ElemType = undefined;
1508 const child_type = self.optionalChild(&buf);
1509 // optionals of zero sized pointers behave like bools
17821510 if (!child_type.hasCodeGenBits()) return false;
17831511
17841512 return child_type.zigTypeTag() == .Pointer and !child_type.isCPtr();
......@@ -1833,64 +1561,6 @@ pub const Type = extern union {
18331561 /// Asserts the type is a pointer or array type.
18341562 pub fn elemType(self: Type) Type {
18351563 return switch (self.tag()) {
1836 .u8 => unreachable,
1837 .i8 => unreachable,
1838 .u16 => unreachable,
1839 .i16 => unreachable,
1840 .u32 => unreachable,
1841 .i32 => unreachable,
1842 .u64 => unreachable,
1843 .i64 => unreachable,
1844 .u128 => unreachable,
1845 .i128 => unreachable,
1846 .usize => unreachable,
1847 .isize => unreachable,
1848 .c_short => unreachable,
1849 .c_ushort => unreachable,
1850 .c_int => unreachable,
1851 .c_uint => unreachable,
1852 .c_long => unreachable,
1853 .c_ulong => unreachable,
1854 .c_longlong => unreachable,
1855 .c_ulonglong => unreachable,
1856 .c_longdouble => unreachable,
1857 .f16 => unreachable,
1858 .f32 => unreachable,
1859 .f64 => unreachable,
1860 .f128 => unreachable,
1861 .c_void => unreachable,
1862 .bool => unreachable,
1863 .void => unreachable,
1864 .type => unreachable,
1865 .anyerror => unreachable,
1866 .comptime_int => unreachable,
1867 .comptime_float => unreachable,
1868 .noreturn => unreachable,
1869 .@"null" => unreachable,
1870 .@"undefined" => unreachable,
1871 .fn_noreturn_no_args => unreachable,
1872 .fn_void_no_args => unreachable,
1873 .fn_naked_noreturn_no_args => unreachable,
1874 .fn_ccc_void_no_args => unreachable,
1875 .function => unreachable,
1876 .int_unsigned => unreachable,
1877 .int_signed => unreachable,
1878 .optional => unreachable,
1879 .optional_single_const_pointer => unreachable,
1880 .optional_single_mut_pointer => unreachable,
1881 .enum_literal => unreachable,
1882 .error_union => unreachable,
1883 .anyerror_void_error_union => unreachable,
1884 .error_set => unreachable,
1885 .error_set_single => unreachable,
1886 .@"struct" => unreachable,
1887 .empty_struct => unreachable,
1888 .empty_struct_literal => unreachable,
1889 .inferred_alloc_const => unreachable,
1890 .inferred_alloc_mut => unreachable,
1891 .@"opaque" => unreachable,
1892 .var_args_param => unreachable,
1893
18941564 .array => self.castTag(.array).?.data.elem_type,
18951565 .array_sentinel => self.castTag(.array_sentinel).?.data.elem_type,
18961566 .single_const_pointer,
......@@ -1902,9 +1572,12 @@ pub const Type = extern union {
19021572 .const_slice,
19031573 .mut_slice,
19041574 => self.castPointer().?.data,
1575
19051576 .array_u8, .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.u8),
19061577 .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int),
19071578 .pointer => self.castTag(.pointer).?.data.pointee_type,
1579
1580 else => unreachable,
19081581 };
19091582 }
19101583
......@@ -1972,148 +1645,18 @@ pub const Type = extern union {
19721645 /// Asserts the type is an array or vector.
19731646 pub fn arrayLen(self: Type) u64 {
19741647 return switch (self.tag()) {
1975 .u8,
1976 .i8,
1977 .u16,
1978 .i16,
1979 .u32,
1980 .i32,
1981 .u64,
1982 .i64,
1983 .u128,
1984 .i128,
1985 .usize,
1986 .isize,
1987 .c_short,
1988 .c_ushort,
1989 .c_int,
1990 .c_uint,
1991 .c_long,
1992 .c_ulong,
1993 .c_longlong,
1994 .c_ulonglong,
1995 .c_longdouble,
1996 .f16,
1997 .f32,
1998 .f64,
1999 .f128,
2000 .c_void,
2001 .bool,
2002 .void,
2003 .type,
2004 .anyerror,
2005 .comptime_int,
2006 .comptime_float,
2007 .noreturn,
2008 .@"null",
2009 .@"undefined",
2010 .fn_noreturn_no_args,
2011 .fn_void_no_args,
2012 .fn_naked_noreturn_no_args,
2013 .fn_ccc_void_no_args,
2014 .function,
2015 .pointer,
2016 .single_const_pointer,
2017 .single_mut_pointer,
2018 .many_const_pointer,
2019 .many_mut_pointer,
2020 .c_const_pointer,
2021 .c_mut_pointer,
2022 .const_slice,
2023 .mut_slice,
2024 .single_const_pointer_to_comptime_int,
2025 .const_slice_u8,
2026 .int_unsigned,
2027 .int_signed,
2028 .optional,
2029 .optional_single_mut_pointer,
2030 .optional_single_const_pointer,
2031 .enum_literal,
2032 .error_union,
2033 .anyerror_void_error_union,
2034 .error_set,
2035 .error_set_single,
2036 .@"struct",
2037 .empty_struct,
2038 .empty_struct_literal,
2039 .inferred_alloc_const,
2040 .inferred_alloc_mut,
2041 .@"opaque",
2042 .var_args_param,
2043 => unreachable,
2044
20451648 .array => self.castTag(.array).?.data.len,
20461649 .array_sentinel => self.castTag(.array_sentinel).?.data.len,
20471650 .array_u8 => self.castTag(.array_u8).?.data,
20481651 .array_u8_sentinel_0 => self.castTag(.array_u8_sentinel_0).?.data,
1652
1653 else => unreachable,
20491654 };
20501655 }
20511656
20521657 /// Asserts the type is an array, pointer or vector.
20531658 pub fn sentinel(self: Type) ?Value {
20541659 return switch (self.tag()) {
2055 .u8,
2056 .i8,
2057 .u16,
2058 .i16,
2059 .u32,
2060 .i32,
2061 .u64,
2062 .i64,
2063 .u128,
2064 .i128,
2065 .usize,
2066 .isize,
2067 .c_short,
2068 .c_ushort,
2069 .c_int,
2070 .c_uint,
2071 .c_long,
2072 .c_ulong,
2073 .c_longlong,
2074 .c_ulonglong,
2075 .c_longdouble,
2076 .f16,
2077 .f32,
2078 .f64,
2079 .f128,
2080 .c_void,
2081 .bool,
2082 .void,
2083 .type,
2084 .anyerror,
2085 .comptime_int,
2086 .comptime_float,
2087 .noreturn,
2088 .@"null",
2089 .@"undefined",
2090 .fn_noreturn_no_args,
2091 .fn_void_no_args,
2092 .fn_naked_noreturn_no_args,
2093 .fn_ccc_void_no_args,
2094 .function,
2095 .const_slice,
2096 .mut_slice,
2097 .const_slice_u8,
2098 .int_unsigned,
2099 .int_signed,
2100 .optional,
2101 .optional_single_mut_pointer,
2102 .optional_single_const_pointer,
2103 .enum_literal,
2104 .error_union,
2105 .anyerror_void_error_union,
2106 .error_set,
2107 .error_set_single,
2108 .@"struct",
2109 .empty_struct,
2110 .empty_struct_literal,
2111 .inferred_alloc_const,
2112 .inferred_alloc_mut,
2113 .@"opaque",
2114 .var_args_param,
2115 => unreachable,
2116
21171660 .single_const_pointer,
21181661 .single_mut_pointer,
21191662 .many_const_pointer,
......@@ -2128,6 +1671,8 @@ pub const Type = extern union {
21281671 .pointer => return self.castTag(.pointer).?.data.sentinel,
21291672 .array_sentinel => return self.castTag(.array_sentinel).?.data.sentinel,
21301673 .array_u8_sentinel_0 => return Value.initTag(.zero),
1674
1675 else => unreachable,
21311676 };
21321677 }
21331678
......@@ -2136,869 +1681,84 @@ pub const Type = extern union {
21361681 return self.isSignedInt() or self.isUnsignedInt();
21371682 }
21381683
2139 /// Returns true if and only if the type is a fixed-width, signed integer.
2140 pub fn isSignedInt(self: Type) bool {
2141 return switch (self.tag()) {
2142 .f16,
2143 .f32,
2144 .f64,
2145 .f128,
2146 .c_longdouble,
2147 .c_void,
2148 .bool,
2149 .void,
2150 .type,
2151 .anyerror,
2152 .comptime_int,
2153 .comptime_float,
2154 .noreturn,
2155 .@"null",
2156 .@"undefined",
2157 .fn_noreturn_no_args,
2158 .fn_void_no_args,
2159 .fn_naked_noreturn_no_args,
2160 .fn_ccc_void_no_args,
2161 .function,
2162 .array,
2163 .array_sentinel,
2164 .array_u8,
2165 .array_u8_sentinel_0,
2166 .pointer,
2167 .single_const_pointer,
2168 .single_mut_pointer,
2169 .many_const_pointer,
2170 .many_mut_pointer,
2171 .c_const_pointer,
2172 .c_mut_pointer,
2173 .const_slice,
2174 .mut_slice,
2175 .single_const_pointer_to_comptime_int,
2176 .const_slice_u8,
2177 .int_unsigned,
2178 .u8,
2179 .usize,
2180 .c_ushort,
2181 .c_uint,
2182 .c_ulong,
2183 .c_ulonglong,
2184 .u16,
2185 .u32,
2186 .u64,
2187 .optional,
2188 .optional_single_mut_pointer,
2189 .optional_single_const_pointer,
2190 .enum_literal,
2191 .error_union,
2192 .anyerror_void_error_union,
2193 .error_set,
2194 .error_set_single,
2195 .@"struct",
2196 .empty_struct,
2197 .empty_struct_literal,
2198 .inferred_alloc_const,
2199 .inferred_alloc_mut,
2200 .@"opaque",
2201 .var_args_param,
2202 => false,
2203
2204 .int_signed,
2205 .i8,
2206 .isize,
2207 .c_short,
2208 .c_int,
2209 .c_long,
2210 .c_longlong,
2211 .i16,
2212 .i32,
2213 .i64,
2214 .u128,
2215 .i128,
2216 => true,
2217 };
2218 }
2219
2220 /// Returns true if and only if the type is a fixed-width, unsigned integer.
2221 pub fn isUnsignedInt(self: Type) bool {
2222 return switch (self.tag()) {
2223 .f16,
2224 .f32,
2225 .f64,
2226 .f128,
2227 .c_longdouble,
2228 .c_void,
2229 .bool,
2230 .void,
2231 .type,
2232 .anyerror,
2233 .comptime_int,
2234 .comptime_float,
2235 .noreturn,
2236 .@"null",
2237 .@"undefined",
2238 .fn_noreturn_no_args,
2239 .fn_void_no_args,
2240 .fn_naked_noreturn_no_args,
2241 .fn_ccc_void_no_args,
2242 .function,
2243 .array,
2244 .array_sentinel,
2245 .array_u8,
2246 .array_u8_sentinel_0,
2247 .pointer,
2248 .single_const_pointer,
2249 .single_mut_pointer,
2250 .many_const_pointer,
2251 .many_mut_pointer,
2252 .c_const_pointer,
2253 .c_mut_pointer,
2254 .const_slice,
2255 .mut_slice,
2256 .single_const_pointer_to_comptime_int,
2257 .const_slice_u8,
2258 .int_signed,
2259 .i8,
2260 .isize,
2261 .c_short,
2262 .c_int,
2263 .c_long,
2264 .c_longlong,
2265 .i16,
2266 .i32,
2267 .i64,
2268 .u128,
2269 .i128,
2270 .optional,
2271 .optional_single_mut_pointer,
2272 .optional_single_const_pointer,
2273 .enum_literal,
2274 .error_union,
2275 .anyerror_void_error_union,
2276 .error_set,
2277 .error_set_single,
2278 .@"struct",
2279 .empty_struct,
2280 .empty_struct_literal,
2281 .inferred_alloc_const,
2282 .inferred_alloc_mut,
2283 .@"opaque",
2284 .var_args_param,
2285 => false,
2286
2287 .int_unsigned,
2288 .u8,
2289 .usize,
2290 .c_ushort,
2291 .c_uint,
2292 .c_ulong,
2293 .c_ulonglong,
2294 .u16,
2295 .u32,
2296 .u64,
2297 => true,
2298 };
2299 }
2300
2301 /// Asserts the type is an integer.
2302 pub fn intInfo(self: Type, target: Target) struct { signedness: std.builtin.Signedness, bits: u16 } {
2303 return switch (self.tag()) {
2304 .f16,
2305 .f32,
2306 .f64,
2307 .f128,
2308 .c_longdouble,
2309 .c_void,
2310 .bool,
2311 .void,
2312 .type,
2313 .anyerror,
2314 .comptime_int,
2315 .comptime_float,
2316 .noreturn,
2317 .@"null",
2318 .@"undefined",
2319 .fn_noreturn_no_args,
2320 .fn_void_no_args,
2321 .fn_naked_noreturn_no_args,
2322 .fn_ccc_void_no_args,
2323 .function,
2324 .array,
2325 .array_sentinel,
2326 .array_u8,
2327 .array_u8_sentinel_0,
2328 .pointer,
2329 .single_const_pointer,
2330 .single_mut_pointer,
2331 .many_const_pointer,
2332 .many_mut_pointer,
2333 .c_const_pointer,
2334 .c_mut_pointer,
2335 .const_slice,
2336 .mut_slice,
2337 .single_const_pointer_to_comptime_int,
2338 .const_slice_u8,
2339 .optional,
2340 .optional_single_mut_pointer,
2341 .optional_single_const_pointer,
2342 .enum_literal,
2343 .error_union,
2344 .anyerror_void_error_union,
2345 .error_set,
2346 .error_set_single,
2347 .@"struct",
2348 .empty_struct,
2349 .empty_struct_literal,
2350 .inferred_alloc_const,
2351 .inferred_alloc_mut,
2352 .@"opaque",
2353 .var_args_param,
2354 => unreachable,
2355
2356 .int_unsigned => .{
2357 .signedness = .unsigned,
2358 .bits = self.castTag(.int_unsigned).?.data,
2359 },
2360 .int_signed => .{
2361 .signedness = .signed,
2362 .bits = self.castTag(.int_signed).?.data,
2363 },
2364 .u8 => .{ .signedness = .unsigned, .bits = 8 },
2365 .i8 => .{ .signedness = .signed, .bits = 8 },
2366 .u16 => .{ .signedness = .unsigned, .bits = 16 },
2367 .i16 => .{ .signedness = .signed, .bits = 16 },
2368 .u32 => .{ .signedness = .unsigned, .bits = 32 },
2369 .i32 => .{ .signedness = .signed, .bits = 32 },
2370 .u64 => .{ .signedness = .unsigned, .bits = 64 },
2371 .i64 => .{ .signedness = .signed, .bits = 64 },
2372 .u128 => .{ .signedness = .unsigned, .bits = 128 },
2373 .i128 => .{ .signedness = .signed, .bits = 128 },
2374 .usize => .{ .signedness = .unsigned, .bits = target.cpu.arch.ptrBitWidth() },
2375 .isize => .{ .signedness = .signed, .bits = target.cpu.arch.ptrBitWidth() },
2376 .c_short => .{ .signedness = .signed, .bits = CType.short.sizeInBits(target) },
2377 .c_ushort => .{ .signedness = .unsigned, .bits = CType.ushort.sizeInBits(target) },
2378 .c_int => .{ .signedness = .signed, .bits = CType.int.sizeInBits(target) },
2379 .c_uint => .{ .signedness = .unsigned, .bits = CType.uint.sizeInBits(target) },
2380 .c_long => .{ .signedness = .signed, .bits = CType.long.sizeInBits(target) },
2381 .c_ulong => .{ .signedness = .unsigned, .bits = CType.ulong.sizeInBits(target) },
2382 .c_longlong => .{ .signedness = .signed, .bits = CType.longlong.sizeInBits(target) },
2383 .c_ulonglong => .{ .signedness = .unsigned, .bits = CType.ulonglong.sizeInBits(target) },
2384 };
2385 }
2386
2387 pub fn isNamedInt(self: Type) bool {
2388 return switch (self.tag()) {
2389 .f16,
2390 .f32,
2391 .f64,
2392 .f128,
2393 .c_longdouble,
2394 .c_void,
2395 .bool,
2396 .void,
2397 .type,
2398 .anyerror,
2399 .comptime_int,
2400 .comptime_float,
2401 .noreturn,
2402 .@"null",
2403 .@"undefined",
2404 .fn_noreturn_no_args,
2405 .fn_void_no_args,
2406 .fn_naked_noreturn_no_args,
2407 .fn_ccc_void_no_args,
2408 .function,
2409 .array,
2410 .array_sentinel,
2411 .array_u8,
2412 .array_u8_sentinel_0,
2413 .pointer,
2414 .single_const_pointer,
2415 .single_mut_pointer,
2416 .many_const_pointer,
2417 .many_mut_pointer,
2418 .c_const_pointer,
2419 .c_mut_pointer,
2420 .const_slice,
2421 .mut_slice,
2422 .single_const_pointer_to_comptime_int,
2423 .const_slice_u8,
2424 .int_unsigned,
2425 .int_signed,
2426 .u8,
2427 .i8,
2428 .u16,
2429 .i16,
2430 .u32,
2431 .i32,
2432 .u64,
2433 .i64,
2434 .u128,
2435 .i128,
2436 .optional,
2437 .optional_single_mut_pointer,
2438 .optional_single_const_pointer,
2439 .enum_literal,
2440 .error_union,
2441 .anyerror_void_error_union,
2442 .error_set,
2443 .error_set_single,
2444 .@"struct",
2445 .empty_struct,
2446 .empty_struct_literal,
2447 .inferred_alloc_const,
2448 .inferred_alloc_mut,
2449 .@"opaque",
2450 .var_args_param,
2451 => false,
2452
2453 .usize,
2454 .isize,
2455 .c_short,
2456 .c_ushort,
2457 .c_int,
2458 .c_uint,
2459 .c_long,
2460 .c_ulong,
2461 .c_longlong,
2462 .c_ulonglong,
2463 => true,
2464 };
2465 }
2466
2467 pub fn isFloat(self: Type) bool {
2468 return switch (self.tag()) {
2469 .f16,
2470 .f32,
2471 .f64,
2472 .f128,
2473 .c_longdouble,
2474 => true,
2475
2476 else => false,
2477 };
2478 }
2479
2480 /// Asserts the type is a fixed-size float.
2481 pub fn floatBits(self: Type, target: Target) u16 {
2482 return switch (self.tag()) {
2483 .f16 => 16,
2484 .f32 => 32,
2485 .f64 => 64,
2486 .f128 => 128,
2487 .c_longdouble => CType.longdouble.sizeInBits(target),
2488
2489 else => unreachable,
2490 };
2491 }
2492
2493 /// Asserts the type is a function.
2494 pub fn fnParamLen(self: Type) usize {
2495 return switch (self.tag()) {
2496 .fn_noreturn_no_args => 0,
2497 .fn_void_no_args => 0,
2498 .fn_naked_noreturn_no_args => 0,
2499 .fn_ccc_void_no_args => 0,
2500 .function => self.castTag(.function).?.data.param_types.len,
2501
2502 .f16,
2503 .f32,
2504 .f64,
2505 .f128,
2506 .c_longdouble,
2507 .c_void,
2508 .bool,
2509 .void,
2510 .type,
2511 .anyerror,
2512 .comptime_int,
2513 .comptime_float,
2514 .noreturn,
2515 .@"null",
2516 .@"undefined",
2517 .array,
2518 .array_sentinel,
2519 .array_u8,
2520 .array_u8_sentinel_0,
2521 .pointer,
2522 .single_const_pointer,
2523 .single_mut_pointer,
2524 .many_const_pointer,
2525 .many_mut_pointer,
2526 .c_const_pointer,
2527 .c_mut_pointer,
2528 .const_slice,
2529 .mut_slice,
2530 .single_const_pointer_to_comptime_int,
2531 .const_slice_u8,
2532 .u8,
2533 .i8,
2534 .u16,
2535 .i16,
2536 .u32,
2537 .i32,
2538 .u64,
2539 .i64,
2540 .u128,
2541 .i128,
2542 .usize,
2543 .isize,
2544 .c_short,
2545 .c_ushort,
2546 .c_int,
2547 .c_uint,
2548 .c_long,
2549 .c_ulong,
2550 .c_longlong,
2551 .c_ulonglong,
2552 .int_unsigned,
2553 .int_signed,
2554 .optional,
2555 .optional_single_mut_pointer,
2556 .optional_single_const_pointer,
2557 .enum_literal,
2558 .error_union,
2559 .anyerror_void_error_union,
2560 .error_set,
2561 .error_set_single,
2562 .@"struct",
2563 .empty_struct,
2564 .empty_struct_literal,
2565 .inferred_alloc_const,
2566 .inferred_alloc_mut,
2567 .@"opaque",
2568 .var_args_param,
2569 => unreachable,
2570 };
2571 }
2572
2573 /// Asserts the type is a function. The length of the slice must be at least the length
2574 /// given by `fnParamLen`.
2575 pub fn fnParamTypes(self: Type, types: []Type) void {
2576 switch (self.tag()) {
2577 .fn_noreturn_no_args => return,
2578 .fn_void_no_args => return,
2579 .fn_naked_noreturn_no_args => return,
2580 .fn_ccc_void_no_args => return,
2581 .function => {
2582 const payload = self.castTag(.function).?.data;
2583 std.mem.copy(Type, types, payload.param_types);
2584 },
2585
2586 .f16,
2587 .f32,
2588 .f64,
2589 .f128,
2590 .c_longdouble,
2591 .c_void,
2592 .bool,
2593 .void,
2594 .type,
2595 .anyerror,
2596 .comptime_int,
2597 .comptime_float,
2598 .noreturn,
2599 .@"null",
2600 .@"undefined",
2601 .array,
2602 .array_sentinel,
2603 .array_u8,
2604 .array_u8_sentinel_0,
2605 .pointer,
2606 .single_const_pointer,
2607 .single_mut_pointer,
2608 .many_const_pointer,
2609 .many_mut_pointer,
2610 .c_const_pointer,
2611 .c_mut_pointer,
2612 .const_slice,
2613 .mut_slice,
2614 .single_const_pointer_to_comptime_int,
2615 .const_slice_u8,
2616 .u8,
2617 .i8,
2618 .u16,
2619 .i16,
2620 .u32,
2621 .i32,
2622 .u64,
2623 .i64,
2624 .u128,
2625 .i128,
2626 .usize,
2627 .isize,
2628 .c_short,
2629 .c_ushort,
2630 .c_int,
2631 .c_uint,
2632 .c_long,
2633 .c_ulong,
2634 .c_longlong,
2635 .c_ulonglong,
2636 .int_unsigned,
2637 .int_signed,
2638 .optional,
2639 .optional_single_mut_pointer,
2640 .optional_single_const_pointer,
2641 .enum_literal,
2642 .error_union,
2643 .anyerror_void_error_union,
2644 .error_set,
2645 .error_set_single,
2646 .@"struct",
2647 .empty_struct,
2648 .empty_struct_literal,
2649 .inferred_alloc_const,
2650 .inferred_alloc_mut,
2651 .@"opaque",
2652 .var_args_param,
2653 => unreachable,
2654 }
2655 }
2656
2657 /// Asserts the type is a function.
2658 pub fn fnParamType(self: Type, index: usize) Type {
2659 switch (self.tag()) {
2660 .function => {
2661 const payload = self.castTag(.function).?.data;
2662 return payload.param_types[index];
2663 },
2664
2665 .fn_noreturn_no_args,
2666 .fn_void_no_args,
2667 .fn_naked_noreturn_no_args,
2668 .fn_ccc_void_no_args,
2669 .f16,
2670 .f32,
2671 .f64,
2672 .f128,
2673 .c_longdouble,
2674 .c_void,
2675 .bool,
2676 .void,
2677 .type,
2678 .anyerror,
2679 .comptime_int,
2680 .comptime_float,
2681 .noreturn,
2682 .@"null",
2683 .@"undefined",
2684 .array,
2685 .array_sentinel,
2686 .array_u8,
2687 .array_u8_sentinel_0,
2688 .pointer,
2689 .single_const_pointer,
2690 .single_mut_pointer,
2691 .many_const_pointer,
2692 .many_mut_pointer,
2693 .c_const_pointer,
2694 .c_mut_pointer,
2695 .const_slice,
2696 .mut_slice,
2697 .single_const_pointer_to_comptime_int,
2698 .const_slice_u8,
2699 .u8,
2700 .i8,
2701 .u16,
2702 .i16,
2703 .u32,
2704 .i32,
2705 .u64,
2706 .i64,
2707 .u128,
2708 .i128,
2709 .usize,
2710 .isize,
2711 .c_short,
2712 .c_ushort,
2713 .c_int,
2714 .c_uint,
2715 .c_long,
2716 .c_ulong,
2717 .c_longlong,
2718 .c_ulonglong,
2719 .int_unsigned,
2720 .int_signed,
2721 .optional,
2722 .optional_single_mut_pointer,
2723 .optional_single_const_pointer,
2724 .enum_literal,
2725 .error_union,
2726 .anyerror_void_error_union,
2727 .error_set,
2728 .error_set_single,
2729 .@"struct",
2730 .empty_struct,
2731 .empty_struct_literal,
2732 .inferred_alloc_const,
2733 .inferred_alloc_mut,
2734 .@"opaque",
2735 .var_args_param,
2736 => unreachable,
2737 }
2738 }
2739
2740 /// Asserts the type is a function.
2741 pub fn fnReturnType(self: Type) Type {
2742 return switch (self.tag()) {
2743 .fn_noreturn_no_args => Type.initTag(.noreturn),
2744 .fn_naked_noreturn_no_args => Type.initTag(.noreturn),
2745
2746 .fn_void_no_args,
2747 .fn_ccc_void_no_args,
2748 => Type.initTag(.void),
2749
2750 .function => self.castTag(.function).?.data.return_type,
2751
2752 .f16,
2753 .f32,
2754 .f64,
2755 .f128,
2756 .c_longdouble,
2757 .c_void,
2758 .bool,
2759 .void,
2760 .type,
2761 .anyerror,
2762 .comptime_int,
2763 .comptime_float,
2764 .noreturn,
2765 .@"null",
2766 .@"undefined",
2767 .array,
2768 .array_sentinel,
2769 .array_u8,
2770 .array_u8_sentinel_0,
2771 .pointer,
2772 .single_const_pointer,
2773 .single_mut_pointer,
2774 .many_const_pointer,
2775 .many_mut_pointer,
2776 .c_const_pointer,
2777 .c_mut_pointer,
2778 .const_slice,
2779 .mut_slice,
2780 .single_const_pointer_to_comptime_int,
2781 .const_slice_u8,
2782 .u8,
2783 .i8,
2784 .u16,
2785 .i16,
2786 .u32,
2787 .i32,
2788 .u64,
2789 .i64,
2790 .u128,
2791 .i128,
2792 .usize,
2793 .isize,
2794 .c_short,
2795 .c_ushort,
2796 .c_int,
2797 .c_uint,
2798 .c_long,
2799 .c_ulong,
2800 .c_longlong,
2801 .c_ulonglong,
2802 .int_unsigned,
2803 .int_signed,
2804 .optional,
2805 .optional_single_mut_pointer,
2806 .optional_single_const_pointer,
2807 .enum_literal,
2808 .error_union,
2809 .anyerror_void_error_union,
2810 .error_set,
2811 .error_set_single,
2812 .@"struct",
2813 .empty_struct,
2814 .empty_struct_literal,
2815 .inferred_alloc_const,
2816 .inferred_alloc_mut,
2817 .@"opaque",
2818 .var_args_param,
2819 => unreachable,
2820 };
2821 }
2822
2823 /// Asserts the type is a function.
2824 pub fn fnCallingConvention(self: Type) std.builtin.CallingConvention {
2825 return switch (self.tag()) {
2826 .fn_noreturn_no_args => .Unspecified,
2827 .fn_void_no_args => .Unspecified,
2828 .fn_naked_noreturn_no_args => .Naked,
2829 .fn_ccc_void_no_args => .C,
2830 .function => self.castTag(.function).?.data.cc,
2831
2832 .f16,
2833 .f32,
2834 .f64,
2835 .f128,
2836 .c_longdouble,
2837 .c_void,
2838 .bool,
2839 .void,
2840 .type,
2841 .anyerror,
2842 .comptime_int,
2843 .comptime_float,
2844 .noreturn,
2845 .@"null",
2846 .@"undefined",
2847 .array,
2848 .array_sentinel,
2849 .array_u8,
2850 .array_u8_sentinel_0,
2851 .pointer,
2852 .single_const_pointer,
2853 .single_mut_pointer,
2854 .many_const_pointer,
2855 .many_mut_pointer,
2856 .c_const_pointer,
2857 .c_mut_pointer,
2858 .const_slice,
2859 .mut_slice,
2860 .single_const_pointer_to_comptime_int,
2861 .const_slice_u8,
2862 .u8,
2863 .i8,
2864 .u16,
2865 .i16,
2866 .u32,
2867 .i32,
2868 .u64,
2869 .i64,
2870 .u128,
2871 .i128,
2872 .usize,
2873 .isize,
2874 .c_short,
2875 .c_ushort,
2876 .c_int,
2877 .c_uint,
2878 .c_long,
2879 .c_ulong,
2880 .c_longlong,
2881 .c_ulonglong,
2882 .int_unsigned,
2883 .int_signed,
2884 .optional,
2885 .optional_single_mut_pointer,
2886 .optional_single_const_pointer,
2887 .enum_literal,
2888 .error_union,
2889 .anyerror_void_error_union,
2890 .error_set,
2891 .error_set_single,
2892 .@"struct",
2893 .empty_struct,
2894 .empty_struct_literal,
2895 .inferred_alloc_const,
2896 .inferred_alloc_mut,
2897 .@"opaque",
2898 .var_args_param,
2899 => unreachable,
2900 };
2901 }
2902
2903 /// Asserts the type is a function.
2904 pub fn fnIsVarArgs(self: Type) bool {
2905 return switch (self.tag()) {
2906 .fn_noreturn_no_args => false,
2907 .fn_void_no_args => false,
2908 .fn_naked_noreturn_no_args => false,
2909 .fn_ccc_void_no_args => false,
2910 .function => self.castTag(.function).?.data.is_var_args,
2911
2912 .f16,
2913 .f32,
2914 .f64,
2915 .f128,
2916 .c_longdouble,
2917 .c_void,
2918 .bool,
2919 .void,
2920 .type,
2921 .anyerror,
2922 .comptime_int,
2923 .comptime_float,
2924 .noreturn,
2925 .@"null",
2926 .@"undefined",
2927 .array,
2928 .array_sentinel,
2929 .array_u8,
2930 .array_u8_sentinel_0,
2931 .pointer,
2932 .single_const_pointer,
2933 .single_mut_pointer,
2934 .many_const_pointer,
2935 .many_mut_pointer,
2936 .c_const_pointer,
2937 .c_mut_pointer,
2938 .const_slice,
2939 .mut_slice,
2940 .single_const_pointer_to_comptime_int,
2941 .const_slice_u8,
2942 .u8,
2943 .i8,
2944 .u16,
2945 .i16,
2946 .u32,
2947 .i32,
2948 .u64,
2949 .i64,
2950 .u128,
2951 .i128,
2952 .usize,
1684 /// Returns true if and only if the type is a fixed-width, signed integer.
1685 pub fn isSignedInt(self: Type) bool {
1686 return switch (self.tag()) {
1687 .int_signed,
1688 .i8,
29531689 .isize,
29541690 .c_short,
2955 .c_ushort,
29561691 .c_int,
2957 .c_uint,
29581692 .c_long,
2959 .c_ulong,
29601693 .c_longlong,
2961 .c_ulonglong,
2962 .int_unsigned,
2963 .int_signed,
2964 .optional,
2965 .optional_single_mut_pointer,
2966 .optional_single_const_pointer,
2967 .enum_literal,
2968 .error_union,
2969 .anyerror_void_error_union,
2970 .error_set,
2971 .error_set_single,
2972 .@"struct",
2973 .empty_struct,
2974 .empty_struct_literal,
2975 .inferred_alloc_const,
2976 .inferred_alloc_mut,
2977 .@"opaque",
2978 .var_args_param,
2979 => unreachable,
1694 .i16,
1695 .i32,
1696 .i64,
1697 .i128,
1698 => true,
1699
1700 else => false,
29801701 };
29811702 }
29821703
2983 pub fn isNumeric(self: Type) bool {
1704 /// Returns true if and only if the type is a fixed-width, unsigned integer.
1705 pub fn isUnsignedInt(self: Type) bool {
29841706 return switch (self.tag()) {
2985 .f16,
2986 .f32,
2987 .f64,
2988 .f128,
2989 .c_longdouble,
2990 .comptime_int,
2991 .comptime_float,
1707 .int_unsigned,
29921708 .u8,
2993 .i8,
1709 .usize,
1710 .c_ushort,
1711 .c_uint,
1712 .c_ulong,
1713 .c_ulonglong,
29941714 .u16,
2995 .i16,
29961715 .u32,
2997 .i32,
29981716 .u64,
2999 .i64,
30001717 .u128,
3001 .i128,
1718 => true,
1719
1720 else => false,
1721 };
1722 }
1723
1724 /// Asserts the type is an integer.
1725 pub fn intInfo(self: Type, target: Target) struct { signedness: std.builtin.Signedness, bits: u16 } {
1726 return switch (self.tag()) {
1727 .int_unsigned => .{
1728 .signedness = .unsigned,
1729 .bits = self.castTag(.int_unsigned).?.data,
1730 },
1731 .int_signed => .{
1732 .signedness = .signed,
1733 .bits = self.castTag(.int_signed).?.data,
1734 },
1735 .u8 => .{ .signedness = .unsigned, .bits = 8 },
1736 .i8 => .{ .signedness = .signed, .bits = 8 },
1737 .u16 => .{ .signedness = .unsigned, .bits = 16 },
1738 .i16 => .{ .signedness = .signed, .bits = 16 },
1739 .u32 => .{ .signedness = .unsigned, .bits = 32 },
1740 .i32 => .{ .signedness = .signed, .bits = 32 },
1741 .u64 => .{ .signedness = .unsigned, .bits = 64 },
1742 .i64 => .{ .signedness = .signed, .bits = 64 },
1743 .u128 => .{ .signedness = .unsigned, .bits = 128 },
1744 .i128 => .{ .signedness = .signed, .bits = 128 },
1745 .usize => .{ .signedness = .unsigned, .bits = target.cpu.arch.ptrBitWidth() },
1746 .isize => .{ .signedness = .signed, .bits = target.cpu.arch.ptrBitWidth() },
1747 .c_short => .{ .signedness = .signed, .bits = CType.short.sizeInBits(target) },
1748 .c_ushort => .{ .signedness = .unsigned, .bits = CType.ushort.sizeInBits(target) },
1749 .c_int => .{ .signedness = .signed, .bits = CType.int.sizeInBits(target) },
1750 .c_uint => .{ .signedness = .unsigned, .bits = CType.uint.sizeInBits(target) },
1751 .c_long => .{ .signedness = .signed, .bits = CType.long.sizeInBits(target) },
1752 .c_ulong => .{ .signedness = .unsigned, .bits = CType.ulong.sizeInBits(target) },
1753 .c_longlong => .{ .signedness = .signed, .bits = CType.longlong.sizeInBits(target) },
1754 .c_ulonglong => .{ .signedness = .unsigned, .bits = CType.ulonglong.sizeInBits(target) },
1755
1756 else => unreachable,
1757 };
1758 }
1759
1760 pub fn isNamedInt(self: Type) bool {
1761 return switch (self.tag()) {
30021762 .usize,
30031763 .isize,
30041764 .c_short,
......@@ -3009,59 +1769,161 @@ pub const Type = extern union {
30091769 .c_ulong,
30101770 .c_longlong,
30111771 .c_ulonglong,
3012 .int_unsigned,
3013 .int_signed,
30141772 => true,
30151773
3016 .c_void,
3017 .bool,
3018 .void,
3019 .type,
3020 .anyerror,
3021 .noreturn,
3022 .@"null",
3023 .@"undefined",
3024 .fn_noreturn_no_args,
1774 else => false,
1775 };
1776 }
1777
1778 pub fn isFloat(self: Type) bool {
1779 return switch (self.tag()) {
1780 .f16,
1781 .f32,
1782 .f64,
1783 .f128,
1784 .c_longdouble,
1785 => true,
1786
1787 else => false,
1788 };
1789 }
1790
1791 /// Asserts the type is a fixed-size float.
1792 pub fn floatBits(self: Type, target: Target) u16 {
1793 return switch (self.tag()) {
1794 .f16 => 16,
1795 .f32 => 32,
1796 .f64 => 64,
1797 .f128 => 128,
1798 .c_longdouble => CType.longdouble.sizeInBits(target),
1799
1800 else => unreachable,
1801 };
1802 }
1803
1804 /// Asserts the type is a function.
1805 pub fn fnParamLen(self: Type) usize {
1806 return switch (self.tag()) {
1807 .fn_noreturn_no_args => 0,
1808 .fn_void_no_args => 0,
1809 .fn_naked_noreturn_no_args => 0,
1810 .fn_ccc_void_no_args => 0,
1811 .function => self.castTag(.function).?.data.param_types.len,
1812
1813 else => unreachable,
1814 };
1815 }
1816
1817 /// Asserts the type is a function. The length of the slice must be at least the length
1818 /// given by `fnParamLen`.
1819 pub fn fnParamTypes(self: Type, types: []Type) void {
1820 switch (self.tag()) {
1821 .fn_noreturn_no_args => return,
1822 .fn_void_no_args => return,
1823 .fn_naked_noreturn_no_args => return,
1824 .fn_ccc_void_no_args => return,
1825 .function => {
1826 const payload = self.castTag(.function).?.data;
1827 std.mem.copy(Type, types, payload.param_types);
1828 },
1829
1830 else => unreachable,
1831 }
1832 }
1833
1834 /// Asserts the type is a function.
1835 pub fn fnParamType(self: Type, index: usize) Type {
1836 switch (self.tag()) {
1837 .function => {
1838 const payload = self.castTag(.function).?.data;
1839 return payload.param_types[index];
1840 },
1841
1842 else => unreachable,
1843 }
1844 }
1845
1846 /// Asserts the type is a function.
1847 pub fn fnReturnType(self: Type) Type {
1848 return switch (self.tag()) {
1849 .fn_noreturn_no_args => Type.initTag(.noreturn),
1850 .fn_naked_noreturn_no_args => Type.initTag(.noreturn),
1851
30251852 .fn_void_no_args,
3026 .fn_naked_noreturn_no_args,
30271853 .fn_ccc_void_no_args,
3028 .function,
3029 .array,
3030 .array_sentinel,
3031 .array_u8,
3032 .array_u8_sentinel_0,
3033 .pointer,
3034 .single_const_pointer,
3035 .single_mut_pointer,
3036 .many_const_pointer,
3037 .many_mut_pointer,
3038 .c_const_pointer,
3039 .c_mut_pointer,
3040 .const_slice,
3041 .mut_slice,
3042 .single_const_pointer_to_comptime_int,
3043 .const_slice_u8,
3044 .optional,
3045 .optional_single_mut_pointer,
3046 .optional_single_const_pointer,
3047 .enum_literal,
3048 .error_union,
3049 .anyerror_void_error_union,
3050 .error_set,
3051 .error_set_single,
3052 .@"struct",
3053 .empty_struct,
3054 .empty_struct_literal,
3055 .inferred_alloc_const,
3056 .inferred_alloc_mut,
3057 .@"opaque",
3058 .var_args_param,
3059 => false,
1854 => Type.initTag(.void),
1855
1856 .function => self.castTag(.function).?.data.return_type,
1857
1858 else => unreachable,
1859 };
1860 }
1861
1862 /// Asserts the type is a function.
1863 pub fn fnCallingConvention(self: Type) std.builtin.CallingConvention {
1864 return switch (self.tag()) {
1865 .fn_noreturn_no_args => .Unspecified,
1866 .fn_void_no_args => .Unspecified,
1867 .fn_naked_noreturn_no_args => .Naked,
1868 .fn_ccc_void_no_args => .C,
1869 .function => self.castTag(.function).?.data.cc,
1870
1871 else => unreachable,
1872 };
1873 }
1874
1875 /// Asserts the type is a function.
1876 pub fn fnIsVarArgs(self: Type) bool {
1877 return switch (self.tag()) {
1878 .fn_noreturn_no_args => false,
1879 .fn_void_no_args => false,
1880 .fn_naked_noreturn_no_args => false,
1881 .fn_ccc_void_no_args => false,
1882 .function => self.castTag(.function).?.data.is_var_args,
1883
1884 else => unreachable,
1885 };
1886 }
1887
1888 pub fn isNumeric(self: Type) bool {
1889 return switch (self.tag()) {
1890 .f16,
1891 .f32,
1892 .f64,
1893 .f128,
1894 .c_longdouble,
1895 .comptime_int,
1896 .comptime_float,
1897 .u8,
1898 .i8,
1899 .u16,
1900 .i16,
1901 .u32,
1902 .i32,
1903 .u64,
1904 .i64,
1905 .u128,
1906 .i128,
1907 .usize,
1908 .isize,
1909 .c_short,
1910 .c_ushort,
1911 .c_int,
1912 .c_uint,
1913 .c_long,
1914 .c_ulong,
1915 .c_longlong,
1916 .c_ulonglong,
1917 .int_unsigned,
1918 .int_signed,
1919 => true,
1920
1921 else => false,
30601922 };
30611923 }
30621924
3063 pub fn onePossibleValue(self: Type) ?Value {
3064 var ty = self;
1925 pub fn onePossibleValue(starting_type: Type) ?Value {
1926 var ty = starting_type;
30651927 while (true) switch (ty.tag()) {
30661928 .f16,
30671929 .f32,
......@@ -3127,6 +1989,23 @@ pub const Type = extern union {
31271989 }
31281990 return Value.initTag(.empty_struct_value);
31291991 },
1992 .enum_full => {
1993 const enum_full = ty.castTag(.enum_full).?.data;
1994 if (enum_full.fields.count() == 1) {
1995 return enum_full.values.entries.items[0].key;
1996 } else {
1997 return null;
1998 }
1999 },
2000 .enum_simple => {
2001 const enum_simple = ty.castTag(.enum_simple).?.data;
2002 if (enum_simple.fields.count() == 1) {
2003 return Value.initTag(.zero);
2004 } else {
2005 return null;
2006 }
2007 },
2008 .enum_nonexhaustive => ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty,
31302009
31312010 .empty_struct, .empty_struct_literal => return Value.initTag(.empty_struct_value),
31322011 .void => return Value.initTag(.void_value),
......@@ -3166,87 +2045,6 @@ pub const Type = extern union {
31662045 };
31672046 }
31682047
3169 pub fn isCPtr(self: Type) bool {
3170 return switch (self.tag()) {
3171 .f16,
3172 .f32,
3173 .f64,
3174 .f128,
3175 .c_longdouble,
3176 .comptime_int,
3177 .comptime_float,
3178 .u8,
3179 .i8,
3180 .u16,
3181 .i16,
3182 .u32,
3183 .i32,
3184 .u64,
3185 .i64,
3186 .u128,
3187 .i128,
3188 .usize,
3189 .isize,
3190 .c_short,
3191 .c_ushort,
3192 .c_int,
3193 .c_uint,
3194 .c_long,
3195 .c_ulong,
3196 .c_longlong,
3197 .c_ulonglong,
3198 .bool,
3199 .type,
3200 .anyerror,
3201 .fn_noreturn_no_args,
3202 .fn_void_no_args,
3203 .fn_naked_noreturn_no_args,
3204 .fn_ccc_void_no_args,
3205 .function,
3206 .single_const_pointer_to_comptime_int,
3207 .const_slice_u8,
3208 .c_void,
3209 .void,
3210 .noreturn,
3211 .@"null",
3212 .@"undefined",
3213 .int_unsigned,
3214 .int_signed,
3215 .array,
3216 .array_sentinel,
3217 .array_u8,
3218 .array_u8_sentinel_0,
3219 .single_const_pointer,
3220 .single_mut_pointer,
3221 .many_const_pointer,
3222 .many_mut_pointer,
3223 .const_slice,
3224 .mut_slice,
3225 .optional,
3226 .optional_single_mut_pointer,
3227 .optional_single_const_pointer,
3228 .enum_literal,
3229 .error_union,
3230 .anyerror_void_error_union,
3231 .error_set,
3232 .error_set_single,
3233 .@"struct",
3234 .empty_struct,
3235 .empty_struct_literal,
3236 .inferred_alloc_const,
3237 .inferred_alloc_mut,
3238 .@"opaque",
3239 .var_args_param,
3240 => return false,
3241
3242 .c_const_pointer,
3243 .c_mut_pointer,
3244 => return true,
3245
3246 .pointer => self.castTag(.pointer).?.data.size == .C,
3247 };
3248 }
3249
32502048 pub fn isIndexable(self: Type) bool {
32512049 const zig_tag = self.zigTypeTag();
32522050 // TODO tuples are indexable
......@@ -3254,83 +2052,15 @@ pub const Type = extern union {
32542052 (self.isSinglePointer() and self.elemType().zigTypeTag() == .Array);
32552053 }
32562054
3257 /// Asserts that the type is a container. (note: ErrorSet is not a container).
3258 pub fn getContainerScope(self: Type) *Module.Scope.Container {
2055 /// Returns null if the type has no container.
2056 pub fn getContainerScope(self: Type) ?*Module.Scope.Container {
32592057 return switch (self.tag()) {
3260 .f16,
3261 .f32,
3262 .f64,
3263 .f128,
3264 .c_longdouble,
3265 .comptime_int,
3266 .comptime_float,
3267 .u8,
3268 .i8,
3269 .u16,
3270 .i16,
3271 .u32,
3272 .i32,
3273 .u64,
3274 .i64,
3275 .u128,
3276 .i128,
3277 .usize,
3278 .isize,
3279 .c_short,
3280 .c_ushort,
3281 .c_int,
3282 .c_uint,
3283 .c_long,
3284 .c_ulong,
3285 .c_longlong,
3286 .c_ulonglong,
3287 .bool,
3288 .type,
3289 .anyerror,
3290 .fn_noreturn_no_args,
3291 .fn_void_no_args,
3292 .fn_naked_noreturn_no_args,
3293 .fn_ccc_void_no_args,
3294 .function,
3295 .single_const_pointer_to_comptime_int,
3296 .const_slice_u8,
3297 .c_void,
3298 .void,
3299 .noreturn,
3300 .@"null",
3301 .@"undefined",
3302 .int_unsigned,
3303 .int_signed,
3304 .array,
3305 .array_sentinel,
3306 .array_u8,
3307 .array_u8_sentinel_0,
3308 .single_const_pointer,
3309 .single_mut_pointer,
3310 .many_const_pointer,
3311 .many_mut_pointer,
3312 .const_slice,
3313 .mut_slice,
3314 .optional,
3315 .optional_single_mut_pointer,
3316 .optional_single_const_pointer,
3317 .enum_literal,
3318 .error_union,
3319 .anyerror_void_error_union,
3320 .error_set,
3321 .error_set_single,
3322 .c_const_pointer,
3323 .c_mut_pointer,
3324 .pointer,
3325 .inferred_alloc_const,
3326 .inferred_alloc_mut,
3327 .var_args_param,
3328 .empty_struct_literal,
3329 => unreachable,
3330
33312058 .@"struct" => &self.castTag(.@"struct").?.data.container,
2059 .enum_full => &self.castTag(.enum_full).?.data.container,
33322060 .empty_struct => self.castTag(.empty_struct).?.data,
33332061 .@"opaque" => &self.castTag(.@"opaque").?.data,
2062
2063 else => null,
33342064 };
33352065 }
33362066
......@@ -3389,8 +2119,144 @@ pub const Type = extern union {
33892119 }
33902120 }
33912121
3392 pub fn isExhaustiveEnum(ty: Type) bool {
3393 return false; // TODO
2122 pub fn isNonexhaustiveEnum(ty: Type) bool {
2123 return switch (ty.tag()) {
2124 .enum_nonexhaustive => true,
2125 else => false,
2126 };
2127 }
2128
2129 pub fn enumFieldCount(ty: Type) usize {
2130 switch (ty.tag()) {
2131 .enum_full, .enum_nonexhaustive => {
2132 const enum_full = ty.cast(Payload.EnumFull).?.data;
2133 return enum_full.fields.count();
2134 },
2135 .enum_simple => {
2136 const enum_simple = ty.castTag(.enum_simple).?.data;
2137 return enum_simple.fields.count();
2138 },
2139 else => unreachable,
2140 }
2141 }
2142
2143 pub fn enumFieldName(ty: Type, field_index: usize) []const u8 {
2144 switch (ty.tag()) {
2145 .enum_full, .enum_nonexhaustive => {
2146 const enum_full = ty.cast(Payload.EnumFull).?.data;
2147 return enum_full.fields.entries.items[field_index].key;
2148 },
2149 .enum_simple => {
2150 const enum_simple = ty.castTag(.enum_simple).?.data;
2151 return enum_simple.fields.entries.items[field_index].key;
2152 },
2153 else => unreachable,
2154 }
2155 }
2156
2157 pub fn enumFieldIndex(ty: Type, field_name: []const u8) ?usize {
2158 switch (ty.tag()) {
2159 .enum_full, .enum_nonexhaustive => {
2160 const enum_full = ty.cast(Payload.EnumFull).?.data;
2161 return enum_full.fields.getIndex(field_name);
2162 },
2163 .enum_simple => {
2164 const enum_simple = ty.castTag(.enum_simple).?.data;
2165 return enum_simple.fields.getIndex(field_name);
2166 },
2167 else => unreachable,
2168 }
2169 }
2170
2171 /// Asserts `ty` is an enum. `enum_tag` can either be `enum_field_index` or
2172 /// an integer which represents the enum value. Returns the field index in
2173 /// declaration order, or `null` if `enum_tag` does not match any field.
2174 pub fn enumTagFieldIndex(ty: Type, enum_tag: Value) ?usize {
2175 if (enum_tag.castTag(.enum_field_index)) |payload| {
2176 return @as(usize, payload.data);
2177 }
2178 const S = struct {
2179 fn fieldWithRange(int_val: Value, end: usize) ?usize {
2180 if (int_val.compareWithZero(.lt)) return null;
2181 var end_payload: Value.Payload.U64 = .{
2182 .base = .{ .tag = .int_u64 },
2183 .data = end,
2184 };
2185 const end_val = Value.initPayload(&end_payload.base);
2186 if (int_val.compare(.gte, end_val)) return null;
2187 return int_val.toUnsignedInt();
2188 }
2189 };
2190 switch (ty.tag()) {
2191 .enum_full, .enum_nonexhaustive => {
2192 const enum_full = ty.cast(Payload.EnumFull).?.data;
2193 if (enum_full.values.count() == 0) {
2194 return S.fieldWithRange(enum_tag, enum_full.fields.count());
2195 } else {
2196 return enum_full.values.getIndex(enum_tag);
2197 }
2198 },
2199 .enum_simple => {
2200 const enum_simple = ty.castTag(.enum_simple).?.data;
2201 return S.fieldWithRange(enum_tag, enum_simple.fields.count());
2202 },
2203 else => unreachable,
2204 }
2205 }
2206
2207 pub fn declSrcLoc(ty: Type) Module.SrcLoc {
2208 switch (ty.tag()) {
2209 .enum_full, .enum_nonexhaustive => {
2210 const enum_full = ty.cast(Payload.EnumFull).?.data;
2211 return enum_full.srcLoc();
2212 },
2213 .enum_simple => {
2214 const enum_simple = ty.castTag(.enum_simple).?.data;
2215 return enum_simple.srcLoc();
2216 },
2217 .@"struct" => {
2218 const struct_obj = ty.castTag(.@"struct").?.data;
2219 return struct_obj.srcLoc();
2220 },
2221 .error_set => {
2222 const error_set = ty.castTag(.error_set).?.data;
2223 return error_set.srcLoc();
2224 },
2225 else => unreachable,
2226 }
2227 }
2228
2229 /// Asserts the type is an enum.
2230 pub fn enumHasInt(ty: Type, int: Value, target: Target) bool {
2231 const S = struct {
2232 fn intInRange(int_val: Value, end: usize) bool {
2233 if (int_val.compareWithZero(.lt)) return false;
2234 var end_payload: Value.Payload.U64 = .{
2235 .base = .{ .tag = .int_u64 },
2236 .data = end,
2237 };
2238 const end_val = Value.initPayload(&end_payload.base);
2239 if (int_val.compare(.gte, end_val)) return false;
2240 return true;
2241 }
2242 };
2243 switch (ty.tag()) {
2244 .enum_nonexhaustive => return int.intFitsInType(ty, target),
2245 .enum_full => {
2246 const enum_full = ty.castTag(.enum_full).?.data;
2247 if (enum_full.values.count() == 0) {
2248 return S.intInRange(int, enum_full.fields.count());
2249 } else {
2250 return enum_full.values.contains(int);
2251 }
2252 },
2253 .enum_simple => {
2254 const enum_simple = ty.castTag(.enum_simple).?.data;
2255 return S.intInRange(int, enum_simple.fields.count());
2256 },
2257
2258 else => unreachable,
2259 }
33942260 }
33952261
33962262 /// This enum does not directly correspond to `std.builtin.TypeId` because
......@@ -3482,6 +2348,9 @@ pub const Type = extern union {
34822348 empty_struct,
34832349 @"opaque",
34842350 @"struct",
2351 enum_simple,
2352 enum_full,
2353 enum_nonexhaustive,
34852354
34862355 pub const last_no_payload_tag = Tag.inferred_alloc_const;
34872356 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
......@@ -3568,6 +2437,8 @@ pub const Type = extern union {
35682437 .error_set_single => Payload.Name,
35692438 .@"opaque" => Payload.Opaque,
35702439 .@"struct" => Payload.Struct,
2440 .enum_full, .enum_nonexhaustive => Payload.EnumFull,
2441 .enum_simple => Payload.EnumSimple,
35712442 .empty_struct => Payload.ContainerScope,
35722443 };
35732444 }
......@@ -3705,6 +2576,16 @@ pub const Type = extern union {
37052576 base: Payload = .{ .tag = .@"struct" },
37062577 data: *Module.Struct,
37072578 };
2579
2580 pub const EnumFull = struct {
2581 base: Payload,
2582 data: *Module.EnumFull,
2583 };
2584
2585 pub const EnumSimple = struct {
2586 base: Payload = .{ .tag = .enum_simple },
2587 data: *Module.EnumSimple,
2588 };
37082589 };
37092590};
37102591
src/value.zig+57-780
......@@ -103,6 +103,8 @@ pub const Value = extern union {
103103 float_64,
104104 float_128,
105105 enum_literal,
106 /// A specific enum tag, indicated by the field index (declaration order).
107 enum_field_index,
106108 @"error",
107109 error_union,
108110 /// This is a special value that tracks a set of types that have been stored
......@@ -186,6 +188,8 @@ pub const Value = extern union {
186188 .enum_literal,
187189 => Payload.Bytes,
188190
191 .enum_field_index => Payload.U32,
192
189193 .ty => Payload.Ty,
190194 .int_type => Payload.IntType,
191195 .int_u64 => Payload.U64,
......@@ -394,6 +398,7 @@ pub const Value = extern union {
394398 };
395399 return Value{ .ptr_otherwise = &new_payload.base };
396400 },
401 .enum_field_index => return self.copyPayloadShallow(allocator, Payload.U32),
397402 .@"error" => return self.copyPayloadShallow(allocator, Payload.Error),
398403 .error_union => {
399404 const payload = self.castTag(.error_union).?;
......@@ -416,6 +421,8 @@ pub const Value = extern union {
416421 return Value{ .ptr_otherwise = &new_payload.base };
417422 }
418423
424 /// TODO this should become a debug dump() function. In order to print values in a meaningful way
425 /// we also need access to the type.
419426 pub fn format(
420427 self: Value,
421428 comptime fmt: []const u8,
......@@ -506,6 +513,7 @@ pub const Value = extern union {
506513 },
507514 .empty_array => return out_stream.writeAll(".{}"),
508515 .enum_literal => return out_stream.print(".{}", .{std.zig.fmtId(self.castTag(.enum_literal).?.data)}),
516 .enum_field_index => return out_stream.print("(enum field {d})", .{self.castTag(.enum_field_index).?.data}),
509517 .bytes => return out_stream.print("\"{}\"", .{std.zig.fmtEscapes(self.castTag(.bytes).?.data)}),
510518 .repeated => {
511519 try out_stream.writeAll("(repeated) ");
......@@ -626,6 +634,7 @@ pub const Value = extern union {
626634 .float_64,
627635 .float_128,
628636 .enum_literal,
637 .enum_field_index,
629638 .@"error",
630639 .error_union,
631640 .empty_struct_value,
......@@ -638,76 +647,6 @@ pub const Value = extern union {
638647 /// Asserts the value is an integer.
639648 pub fn toBigInt(self: Value, space: *BigIntSpace) BigIntConst {
640649 switch (self.tag()) {
641 .ty,
642 .int_type,
643 .u8_type,
644 .i8_type,
645 .u16_type,
646 .i16_type,
647 .u32_type,
648 .i32_type,
649 .u64_type,
650 .i64_type,
651 .u128_type,
652 .i128_type,
653 .usize_type,
654 .isize_type,
655 .c_short_type,
656 .c_ushort_type,
657 .c_int_type,
658 .c_uint_type,
659 .c_long_type,
660 .c_ulong_type,
661 .c_longlong_type,
662 .c_ulonglong_type,
663 .c_longdouble_type,
664 .f16_type,
665 .f32_type,
666 .f64_type,
667 .f128_type,
668 .c_void_type,
669 .bool_type,
670 .void_type,
671 .type_type,
672 .anyerror_type,
673 .comptime_int_type,
674 .comptime_float_type,
675 .noreturn_type,
676 .null_type,
677 .undefined_type,
678 .fn_noreturn_no_args_type,
679 .fn_void_no_args_type,
680 .fn_naked_noreturn_no_args_type,
681 .fn_ccc_void_no_args_type,
682 .single_const_pointer_to_comptime_int_type,
683 .const_slice_u8_type,
684 .enum_literal_type,
685 .null_value,
686 .function,
687 .extern_fn,
688 .variable,
689 .ref_val,
690 .decl_ref,
691 .elem_ptr,
692 .bytes,
693 .repeated,
694 .float_16,
695 .float_32,
696 .float_64,
697 .float_128,
698 .void_value,
699 .unreachable_value,
700 .empty_array,
701 .enum_literal,
702 .error_union,
703 .@"error",
704 .empty_struct_value,
705 .inferred_alloc,
706 .abi_align_default,
707 => unreachable,
708
709 .undef => unreachable,
710
711650 .zero,
712651 .bool_false,
713652 => return BigIntMutable.init(&space.limbs, 0).toConst(),
......@@ -720,82 +659,15 @@ pub const Value = extern union {
720659 .int_i64 => return BigIntMutable.init(&space.limbs, self.castTag(.int_i64).?.data).toConst(),
721660 .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt(),
722661 .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt(),
662
663 .undef => unreachable,
664 else => unreachable,
723665 }
724666 }
725667
726668 /// Asserts the value is an integer and it fits in a u64
727669 pub fn toUnsignedInt(self: Value) u64 {
728670 switch (self.tag()) {
729 .ty,
730 .int_type,
731 .u8_type,
732 .i8_type,
733 .u16_type,
734 .i16_type,
735 .u32_type,
736 .i32_type,
737 .u64_type,
738 .i64_type,
739 .u128_type,
740 .i128_type,
741 .usize_type,
742 .isize_type,
743 .c_short_type,
744 .c_ushort_type,
745 .c_int_type,
746 .c_uint_type,
747 .c_long_type,
748 .c_ulong_type,
749 .c_longlong_type,
750 .c_ulonglong_type,
751 .c_longdouble_type,
752 .f16_type,
753 .f32_type,
754 .f64_type,
755 .f128_type,
756 .c_void_type,
757 .bool_type,
758 .void_type,
759 .type_type,
760 .anyerror_type,
761 .comptime_int_type,
762 .comptime_float_type,
763 .noreturn_type,
764 .null_type,
765 .undefined_type,
766 .fn_noreturn_no_args_type,
767 .fn_void_no_args_type,
768 .fn_naked_noreturn_no_args_type,
769 .fn_ccc_void_no_args_type,
770 .single_const_pointer_to_comptime_int_type,
771 .const_slice_u8_type,
772 .enum_literal_type,
773 .null_value,
774 .function,
775 .extern_fn,
776 .variable,
777 .ref_val,
778 .decl_ref,
779 .elem_ptr,
780 .bytes,
781 .repeated,
782 .float_16,
783 .float_32,
784 .float_64,
785 .float_128,
786 .void_value,
787 .unreachable_value,
788 .empty_array,
789 .enum_literal,
790 .@"error",
791 .error_union,
792 .empty_struct_value,
793 .inferred_alloc,
794 .abi_align_default,
795 => unreachable,
796
797 .undef => unreachable,
798
799671 .zero,
800672 .bool_false,
801673 => return 0,
......@@ -808,82 +680,15 @@ pub const Value = extern union {
808680 .int_i64 => return @intCast(u64, self.castTag(.int_i64).?.data),
809681 .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().to(u64) catch unreachable,
810682 .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().to(u64) catch unreachable,
683
684 .undef => unreachable,
685 else => unreachable,
811686 }
812687 }
813688
814689 /// Asserts the value is an integer and it fits in a i64
815690 pub fn toSignedInt(self: Value) i64 {
816691 switch (self.tag()) {
817 .ty,
818 .int_type,
819 .u8_type,
820 .i8_type,
821 .u16_type,
822 .i16_type,
823 .u32_type,
824 .i32_type,
825 .u64_type,
826 .i64_type,
827 .u128_type,
828 .i128_type,
829 .usize_type,
830 .isize_type,
831 .c_short_type,
832 .c_ushort_type,
833 .c_int_type,
834 .c_uint_type,
835 .c_long_type,
836 .c_ulong_type,
837 .c_longlong_type,
838 .c_ulonglong_type,
839 .c_longdouble_type,
840 .f16_type,
841 .f32_type,
842 .f64_type,
843 .f128_type,
844 .c_void_type,
845 .bool_type,
846 .void_type,
847 .type_type,
848 .anyerror_type,
849 .comptime_int_type,
850 .comptime_float_type,
851 .noreturn_type,
852 .null_type,
853 .undefined_type,
854 .fn_noreturn_no_args_type,
855 .fn_void_no_args_type,
856 .fn_naked_noreturn_no_args_type,
857 .fn_ccc_void_no_args_type,
858 .single_const_pointer_to_comptime_int_type,
859 .const_slice_u8_type,
860 .enum_literal_type,
861 .null_value,
862 .function,
863 .extern_fn,
864 .variable,
865 .ref_val,
866 .decl_ref,
867 .elem_ptr,
868 .bytes,
869 .repeated,
870 .float_16,
871 .float_32,
872 .float_64,
873 .float_128,
874 .void_value,
875 .unreachable_value,
876 .empty_array,
877 .enum_literal,
878 .@"error",
879 .error_union,
880 .empty_struct_value,
881 .inferred_alloc,
882 .abi_align_default,
883 => unreachable,
884
885 .undef => unreachable,
886
887692 .zero,
888693 .bool_false,
889694 => return 0,
......@@ -896,6 +701,9 @@ pub const Value = extern union {
896701 .int_i64 => return self.castTag(.int_i64).?.data,
897702 .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().to(i64) catch unreachable,
898703 .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().to(i64) catch unreachable,
704
705 .undef => unreachable,
706 else => unreachable,
899707 }
900708 }
901709
......@@ -929,75 +737,6 @@ pub const Value = extern union {
929737 /// Returns the number of bits the value requires to represent stored in twos complement form.
930738 pub fn intBitCountTwosComp(self: Value) usize {
931739 switch (self.tag()) {
932 .ty,
933 .int_type,
934 .u8_type,
935 .i8_type,
936 .u16_type,
937 .i16_type,
938 .u32_type,
939 .i32_type,
940 .u64_type,
941 .i64_type,
942 .u128_type,
943 .i128_type,
944 .usize_type,
945 .isize_type,
946 .c_short_type,
947 .c_ushort_type,
948 .c_int_type,
949 .c_uint_type,
950 .c_long_type,
951 .c_ulong_type,
952 .c_longlong_type,
953 .c_ulonglong_type,
954 .c_longdouble_type,
955 .f16_type,
956 .f32_type,
957 .f64_type,
958 .f128_type,
959 .c_void_type,
960 .bool_type,
961 .void_type,
962 .type_type,
963 .anyerror_type,
964 .comptime_int_type,
965 .comptime_float_type,
966 .noreturn_type,
967 .null_type,
968 .undefined_type,
969 .fn_noreturn_no_args_type,
970 .fn_void_no_args_type,
971 .fn_naked_noreturn_no_args_type,
972 .fn_ccc_void_no_args_type,
973 .single_const_pointer_to_comptime_int_type,
974 .const_slice_u8_type,
975 .enum_literal_type,
976 .null_value,
977 .function,
978 .extern_fn,
979 .variable,
980 .ref_val,
981 .decl_ref,
982 .elem_ptr,
983 .bytes,
984 .undef,
985 .repeated,
986 .float_16,
987 .float_32,
988 .float_64,
989 .float_128,
990 .void_value,
991 .unreachable_value,
992 .empty_array,
993 .enum_literal,
994 .@"error",
995 .error_union,
996 .empty_struct_value,
997 .inferred_alloc,
998 .abi_align_default,
999 => unreachable,
1000
1001740 .zero,
1002741 .bool_false,
1003742 => return 0,
......@@ -1016,80 +755,14 @@ pub const Value = extern union {
1016755 },
1017756 .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().bitCountTwosComp(),
1018757 .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().bitCountTwosComp(),
758
759 else => unreachable,
1019760 }
1020761 }
1021762
1022763 /// Asserts the value is an integer, and the destination type is ComptimeInt or Int.
1023764 pub fn intFitsInType(self: Value, ty: Type, target: Target) bool {
1024765 switch (self.tag()) {
1025 .ty,
1026 .int_type,
1027 .u8_type,
1028 .i8_type,
1029 .u16_type,
1030 .i16_type,
1031 .u32_type,
1032 .i32_type,
1033 .u64_type,
1034 .i64_type,
1035 .u128_type,
1036 .i128_type,
1037 .usize_type,
1038 .isize_type,
1039 .c_short_type,
1040 .c_ushort_type,
1041 .c_int_type,
1042 .c_uint_type,
1043 .c_long_type,
1044 .c_ulong_type,
1045 .c_longlong_type,
1046 .c_ulonglong_type,
1047 .c_longdouble_type,
1048 .f16_type,
1049 .f32_type,
1050 .f64_type,
1051 .f128_type,
1052 .c_void_type,
1053 .bool_type,
1054 .void_type,
1055 .type_type,
1056 .anyerror_type,
1057 .comptime_int_type,
1058 .comptime_float_type,
1059 .noreturn_type,
1060 .null_type,
1061 .undefined_type,
1062 .fn_noreturn_no_args_type,
1063 .fn_void_no_args_type,
1064 .fn_naked_noreturn_no_args_type,
1065 .fn_ccc_void_no_args_type,
1066 .single_const_pointer_to_comptime_int_type,
1067 .const_slice_u8_type,
1068 .enum_literal_type,
1069 .null_value,
1070 .function,
1071 .extern_fn,
1072 .variable,
1073 .ref_val,
1074 .decl_ref,
1075 .elem_ptr,
1076 .bytes,
1077 .repeated,
1078 .float_16,
1079 .float_32,
1080 .float_64,
1081 .float_128,
1082 .void_value,
1083 .unreachable_value,
1084 .empty_array,
1085 .enum_literal,
1086 .@"error",
1087 .error_union,
1088 .empty_struct_value,
1089 .inferred_alloc,
1090 .abi_align_default,
1091 => unreachable,
1092
1093766 .zero,
1094767 .undef,
1095768 .bool_false,
......@@ -1144,6 +817,8 @@ pub const Value = extern union {
1144817 .ComptimeInt => return true,
1145818 else => unreachable,
1146819 },
820
821 else => unreachable,
1147822 }
1148823 }
1149824
......@@ -1180,77 +855,6 @@ pub const Value = extern union {
1180855 /// Asserts the value is a float
1181856 pub fn floatHasFraction(self: Value) bool {
1182857 return switch (self.tag()) {
1183 .ty,
1184 .int_type,
1185 .u8_type,
1186 .i8_type,
1187 .u16_type,
1188 .i16_type,
1189 .u32_type,
1190 .i32_type,
1191 .u64_type,
1192 .i64_type,
1193 .u128_type,
1194 .i128_type,
1195 .usize_type,
1196 .isize_type,
1197 .c_short_type,
1198 .c_ushort_type,
1199 .c_int_type,
1200 .c_uint_type,
1201 .c_long_type,
1202 .c_ulong_type,
1203 .c_longlong_type,
1204 .c_ulonglong_type,
1205 .c_longdouble_type,
1206 .f16_type,
1207 .f32_type,
1208 .f64_type,
1209 .f128_type,
1210 .c_void_type,
1211 .bool_type,
1212 .void_type,
1213 .type_type,
1214 .anyerror_type,
1215 .comptime_int_type,
1216 .comptime_float_type,
1217 .noreturn_type,
1218 .null_type,
1219 .undefined_type,
1220 .fn_noreturn_no_args_type,
1221 .fn_void_no_args_type,
1222 .fn_naked_noreturn_no_args_type,
1223 .fn_ccc_void_no_args_type,
1224 .single_const_pointer_to_comptime_int_type,
1225 .const_slice_u8_type,
1226 .enum_literal_type,
1227 .bool_true,
1228 .bool_false,
1229 .null_value,
1230 .function,
1231 .extern_fn,
1232 .variable,
1233 .ref_val,
1234 .decl_ref,
1235 .elem_ptr,
1236 .bytes,
1237 .repeated,
1238 .undef,
1239 .int_u64,
1240 .int_i64,
1241 .int_big_positive,
1242 .int_big_negative,
1243 .empty_array,
1244 .void_value,
1245 .unreachable_value,
1246 .enum_literal,
1247 .@"error",
1248 .error_union,
1249 .empty_struct_value,
1250 .inferred_alloc,
1251 .abi_align_default,
1252 => unreachable,
1253
1254858 .zero,
1255859 .one,
1256860 => false,
......@@ -1260,76 +864,13 @@ pub const Value = extern union {
1260864 .float_64 => @rem(self.castTag(.float_64).?.data, 1) != 0,
1261865 // .float_128 => @rem(self.castTag(.float_128).?.data, 1) != 0,
1262866 .float_128 => @panic("TODO lld: error: undefined symbol: fmodl"),
867
868 else => unreachable,
1263869 };
1264870 }
1265871
1266872 pub fn orderAgainstZero(lhs: Value) std.math.Order {
1267873 return switch (lhs.tag()) {
1268 .ty,
1269 .int_type,
1270 .u8_type,
1271 .i8_type,
1272 .u16_type,
1273 .i16_type,
1274 .u32_type,
1275 .i32_type,
1276 .u64_type,
1277 .i64_type,
1278 .u128_type,
1279 .i128_type,
1280 .usize_type,
1281 .isize_type,
1282 .c_short_type,
1283 .c_ushort_type,
1284 .c_int_type,
1285 .c_uint_type,
1286 .c_long_type,
1287 .c_ulong_type,
1288 .c_longlong_type,
1289 .c_ulonglong_type,
1290 .c_longdouble_type,
1291 .f16_type,
1292 .f32_type,
1293 .f64_type,
1294 .f128_type,
1295 .c_void_type,
1296 .bool_type,
1297 .void_type,
1298 .type_type,
1299 .anyerror_type,
1300 .comptime_int_type,
1301 .comptime_float_type,
1302 .noreturn_type,
1303 .null_type,
1304 .undefined_type,
1305 .fn_noreturn_no_args_type,
1306 .fn_void_no_args_type,
1307 .fn_naked_noreturn_no_args_type,
1308 .fn_ccc_void_no_args_type,
1309 .single_const_pointer_to_comptime_int_type,
1310 .const_slice_u8_type,
1311 .enum_literal_type,
1312 .null_value,
1313 .function,
1314 .extern_fn,
1315 .variable,
1316 .ref_val,
1317 .decl_ref,
1318 .elem_ptr,
1319 .bytes,
1320 .repeated,
1321 .undef,
1322 .void_value,
1323 .unreachable_value,
1324 .empty_array,
1325 .enum_literal,
1326 .@"error",
1327 .error_union,
1328 .empty_struct_value,
1329 .inferred_alloc,
1330 .abi_align_default,
1331 => unreachable,
1332
1333874 .zero,
1334875 .bool_false,
1335876 => .eq,
......@@ -1347,6 +888,8 @@ pub const Value = extern union {
1347888 .float_32 => std.math.order(lhs.castTag(.float_32).?.data, 0),
1348889 .float_64 => std.math.order(lhs.castTag(.float_64).?.data, 0),
1349890 .float_128 => std.math.order(lhs.castTag(.float_128).?.data, 0),
891
892 else => unreachable,
1350893 };
1351894 }
1352895
......@@ -1396,10 +939,12 @@ pub const Value = extern union {
1396939 }
1397940
1398941 pub fn eql(a: Value, b: Value) bool {
1399 if (a.tag() == b.tag()) {
1400 if (a.tag() == .void_value or a.tag() == .null_value) {
942 const a_tag = a.tag();
943 const b_tag = b.tag();
944 if (a_tag == b_tag) {
945 if (a_tag == .void_value or a_tag == .null_value) {
1401946 return true;
1402 } else if (a.tag() == .enum_literal) {
947 } else if (a_tag == .enum_literal) {
1403948 const a_name = a.castTag(.enum_literal).?.data;
1404949 const b_name = b.castTag(.enum_literal).?.data;
1405950 return std.mem.eql(u8, a_name, b_name);
......@@ -1416,6 +961,10 @@ pub const Value = extern union {
1416961 return compare(a, .eq, b);
1417962 }
1418963
964 pub fn hash_u32(self: Value) u32 {
965 return @truncate(u32, self.hash());
966 }
967
1419968 pub fn hash(self: Value) u64 {
1420969 var hasher = std.hash.Wyhash.init(0);
1421970
......@@ -1493,11 +1042,18 @@ pub const Value = extern union {
14931042 .zero, .bool_false => std.hash.autoHash(&hasher, @as(u64, 0)),
14941043 .one, .bool_true => std.hash.autoHash(&hasher, @as(u64, 1)),
14951044
1496 .float_16, .float_32, .float_64, .float_128 => {},
1045 .float_16, .float_32, .float_64, .float_128 => {
1046 @panic("TODO implement Value.hash for floats");
1047 },
1048
14971049 .enum_literal => {
14981050 const payload = self.castTag(.enum_literal).?;
14991051 hasher.update(payload.data);
15001052 },
1053 .enum_field_index => {
1054 const payload = self.castTag(.enum_field_index).?;
1055 std.hash.autoHash(&hasher, payload.data);
1056 },
15011057 .bytes => {
15021058 const payload = self.castTag(.bytes).?;
15031059 hasher.update(payload.data);
......@@ -1573,80 +1129,6 @@ pub const Value = extern union {
15731129 /// Returns error.AnalysisFail if the pointer points to a Decl that failed semantic analysis.
15741130 pub fn pointerDeref(self: Value, allocator: *Allocator) error{ AnalysisFail, OutOfMemory }!Value {
15751131 return switch (self.tag()) {
1576 .ty,
1577 .int_type,
1578 .u8_type,
1579 .i8_type,
1580 .u16_type,
1581 .i16_type,
1582 .u32_type,
1583 .i32_type,
1584 .u64_type,
1585 .i64_type,
1586 .u128_type,
1587 .i128_type,
1588 .usize_type,
1589 .isize_type,
1590 .c_short_type,
1591 .c_ushort_type,
1592 .c_int_type,
1593 .c_uint_type,
1594 .c_long_type,
1595 .c_ulong_type,
1596 .c_longlong_type,
1597 .c_ulonglong_type,
1598 .c_longdouble_type,
1599 .f16_type,
1600 .f32_type,
1601 .f64_type,
1602 .f128_type,
1603 .c_void_type,
1604 .bool_type,
1605 .void_type,
1606 .type_type,
1607 .anyerror_type,
1608 .comptime_int_type,
1609 .comptime_float_type,
1610 .noreturn_type,
1611 .null_type,
1612 .undefined_type,
1613 .fn_noreturn_no_args_type,
1614 .fn_void_no_args_type,
1615 .fn_naked_noreturn_no_args_type,
1616 .fn_ccc_void_no_args_type,
1617 .single_const_pointer_to_comptime_int_type,
1618 .const_slice_u8_type,
1619 .enum_literal_type,
1620 .zero,
1621 .one,
1622 .bool_true,
1623 .bool_false,
1624 .null_value,
1625 .function,
1626 .extern_fn,
1627 .variable,
1628 .int_u64,
1629 .int_i64,
1630 .int_big_positive,
1631 .int_big_negative,
1632 .bytes,
1633 .undef,
1634 .repeated,
1635 .float_16,
1636 .float_32,
1637 .float_64,
1638 .float_128,
1639 .void_value,
1640 .unreachable_value,
1641 .empty_array,
1642 .enum_literal,
1643 .@"error",
1644 .error_union,
1645 .empty_struct_value,
1646 .inferred_alloc,
1647 .abi_align_default,
1648 => unreachable,
1649
16501132 .ref_val => self.castTag(.ref_val).?.data,
16511133 .decl_ref => self.castTag(.decl_ref).?.data.value(),
16521134 .elem_ptr => {
......@@ -1654,6 +1136,8 @@ pub const Value = extern union {
16541136 const array_val = try elem_ptr.array_ptr.pointerDeref(allocator);
16551137 return array_val.elemValue(allocator, elem_ptr.index);
16561138 },
1139
1140 else => unreachable,
16571141 };
16581142 }
16591143
......@@ -1661,86 +1145,14 @@ pub const Value = extern union {
16611145 /// or an unknown-length pointer, and returns the element value at the index.
16621146 pub fn elemValue(self: Value, allocator: *Allocator, index: usize) error{OutOfMemory}!Value {
16631147 switch (self.tag()) {
1664 .ty,
1665 .int_type,
1666 .u8_type,
1667 .i8_type,
1668 .u16_type,
1669 .i16_type,
1670 .u32_type,
1671 .i32_type,
1672 .u64_type,
1673 .i64_type,
1674 .u128_type,
1675 .i128_type,
1676 .usize_type,
1677 .isize_type,
1678 .c_short_type,
1679 .c_ushort_type,
1680 .c_int_type,
1681 .c_uint_type,
1682 .c_long_type,
1683 .c_ulong_type,
1684 .c_longlong_type,
1685 .c_ulonglong_type,
1686 .c_longdouble_type,
1687 .f16_type,
1688 .f32_type,
1689 .f64_type,
1690 .f128_type,
1691 .c_void_type,
1692 .bool_type,
1693 .void_type,
1694 .type_type,
1695 .anyerror_type,
1696 .comptime_int_type,
1697 .comptime_float_type,
1698 .noreturn_type,
1699 .null_type,
1700 .undefined_type,
1701 .fn_noreturn_no_args_type,
1702 .fn_void_no_args_type,
1703 .fn_naked_noreturn_no_args_type,
1704 .fn_ccc_void_no_args_type,
1705 .single_const_pointer_to_comptime_int_type,
1706 .const_slice_u8_type,
1707 .enum_literal_type,
1708 .zero,
1709 .one,
1710 .bool_true,
1711 .bool_false,
1712 .null_value,
1713 .function,
1714 .extern_fn,
1715 .variable,
1716 .int_u64,
1717 .int_i64,
1718 .int_big_positive,
1719 .int_big_negative,
1720 .undef,
1721 .elem_ptr,
1722 .ref_val,
1723 .decl_ref,
1724 .float_16,
1725 .float_32,
1726 .float_64,
1727 .float_128,
1728 .void_value,
1729 .unreachable_value,
1730 .enum_literal,
1731 .@"error",
1732 .error_union,
1733 .empty_struct_value,
1734 .inferred_alloc,
1735 .abi_align_default,
1736 => unreachable,
1737
17381148 .empty_array => unreachable, // out of bounds array index
17391149
17401150 .bytes => return Tag.int_u64.create(allocator, self.castTag(.bytes).?.data[index]),
17411151
17421152 // No matter the index; all the elements are the same!
17431153 .repeated => return self.castTag(.repeated).?.data,
1154
1155 else => unreachable,
17441156 }
17451157 }
17461158
......@@ -1766,161 +1178,18 @@ pub const Value = extern union {
17661178 /// Valid for all types. Asserts the value is not undefined and not unreachable.
17671179 pub fn isNull(self: Value) bool {
17681180 return switch (self.tag()) {
1769 .ty,
1770 .int_type,
1771 .u8_type,
1772 .i8_type,
1773 .u16_type,
1774 .i16_type,
1775 .u32_type,
1776 .i32_type,
1777 .u64_type,
1778 .i64_type,
1779 .u128_type,
1780 .i128_type,
1781 .usize_type,
1782 .isize_type,
1783 .c_short_type,
1784 .c_ushort_type,
1785 .c_int_type,
1786 .c_uint_type,
1787 .c_long_type,
1788 .c_ulong_type,
1789 .c_longlong_type,
1790 .c_ulonglong_type,
1791 .c_longdouble_type,
1792 .f16_type,
1793 .f32_type,
1794 .f64_type,
1795 .f128_type,
1796 .c_void_type,
1797 .bool_type,
1798 .void_type,
1799 .type_type,
1800 .anyerror_type,
1801 .comptime_int_type,
1802 .comptime_float_type,
1803 .noreturn_type,
1804 .null_type,
1805 .undefined_type,
1806 .fn_noreturn_no_args_type,
1807 .fn_void_no_args_type,
1808 .fn_naked_noreturn_no_args_type,
1809 .fn_ccc_void_no_args_type,
1810 .single_const_pointer_to_comptime_int_type,
1811 .const_slice_u8_type,
1812 .enum_literal_type,
1813 .zero,
1814 .one,
1815 .empty_array,
1816 .bool_true,
1817 .bool_false,
1818 .function,
1819 .extern_fn,
1820 .variable,
1821 .int_u64,
1822 .int_i64,
1823 .int_big_positive,
1824 .int_big_negative,
1825 .ref_val,
1826 .decl_ref,
1827 .elem_ptr,
1828 .bytes,
1829 .repeated,
1830 .float_16,
1831 .float_32,
1832 .float_64,
1833 .float_128,
1834 .void_value,
1835 .enum_literal,
1836 .@"error",
1837 .error_union,
1838 .empty_struct_value,
1839 .abi_align_default,
1840 => false,
1841
18421181 .undef => unreachable,
18431182 .unreachable_value => unreachable,
18441183 .inferred_alloc => unreachable,
18451184 .null_value => true,
1185
1186 else => false,
18461187 };
18471188 }
18481189
18491190 /// Valid for all types. Asserts the value is not undefined and not unreachable.
18501191 pub fn getError(self: Value) ?[]const u8 {
18511192 return switch (self.tag()) {
1852 .ty,
1853 .int_type,
1854 .u8_type,
1855 .i8_type,
1856 .u16_type,
1857 .i16_type,
1858 .u32_type,
1859 .i32_type,
1860 .u64_type,
1861 .i64_type,
1862 .u128_type,
1863 .i128_type,
1864 .usize_type,
1865 .isize_type,
1866 .c_short_type,
1867 .c_ushort_type,
1868 .c_int_type,
1869 .c_uint_type,
1870 .c_long_type,
1871 .c_ulong_type,
1872 .c_longlong_type,
1873 .c_ulonglong_type,
1874 .c_longdouble_type,
1875 .f16_type,
1876 .f32_type,
1877 .f64_type,
1878 .f128_type,
1879 .c_void_type,
1880 .bool_type,
1881 .void_type,
1882 .type_type,
1883 .anyerror_type,
1884 .comptime_int_type,
1885 .comptime_float_type,
1886 .noreturn_type,
1887 .null_type,
1888 .undefined_type,
1889 .fn_noreturn_no_args_type,
1890 .fn_void_no_args_type,
1891 .fn_naked_noreturn_no_args_type,
1892 .fn_ccc_void_no_args_type,
1893 .single_const_pointer_to_comptime_int_type,
1894 .const_slice_u8_type,
1895 .enum_literal_type,
1896 .zero,
1897 .one,
1898 .null_value,
1899 .empty_array,
1900 .bool_true,
1901 .bool_false,
1902 .function,
1903 .extern_fn,
1904 .variable,
1905 .int_u64,
1906 .int_i64,
1907 .int_big_positive,
1908 .int_big_negative,
1909 .ref_val,
1910 .decl_ref,
1911 .elem_ptr,
1912 .bytes,
1913 .repeated,
1914 .float_16,
1915 .float_32,
1916 .float_64,
1917 .float_128,
1918 .void_value,
1919 .enum_literal,
1920 .empty_struct_value,
1921 .abi_align_default,
1922 => null,
1923
19241193 .error_union => {
19251194 const data = self.castTag(.error_union).?.data;
19261195 return if (data.tag() == .@"error")
......@@ -1932,6 +1201,8 @@ pub const Value = extern union {
19321201 .undef => unreachable,
19331202 .unreachable_value => unreachable,
19341203 .inferred_alloc => unreachable,
1204
1205 else => null,
19351206 };
19361207 }
19371208 /// Valid for all types. Asserts the value is not undefined.
......@@ -2021,6 +1292,7 @@ pub const Value = extern union {
20211292 .float_128,
20221293 .void_value,
20231294 .enum_literal,
1295 .enum_field_index,
20241296 .@"error",
20251297 .error_union,
20261298 .empty_struct_value,
......@@ -2038,6 +1310,11 @@ pub const Value = extern union {
20381310 pub const Payload = struct {
20391311 tag: Tag,
20401312
1313 pub const U32 = struct {
1314 base: Payload,
1315 data: u32,
1316 };
1317
20411318 pub const U64 = struct {
20421319 base: Payload,
20431320 data: u64,
src/zir.zig+72-23
......@@ -37,8 +37,6 @@ pub const Code = struct {
3737 string_bytes: []u8,
3838 /// The meaning of this data is determined by `Inst.Tag` value.
3939 extra: []u32,
40 /// Used for decl_val and decl_ref instructions.
41 decls: []*Module.Decl,
4240
4341 /// Returns the requested data, as well as the new index which is at the start of the
4442 /// trailers for the object.
......@@ -78,7 +76,6 @@ pub const Code = struct {
7876 code.instructions.deinit(gpa);
7977 gpa.free(code.string_bytes);
8078 gpa.free(code.extra);
81 gpa.free(code.decls);
8279 code.* = undefined;
8380 }
8481
......@@ -133,7 +130,7 @@ pub const Inst = struct {
133130 /// Same as `alloc` except mutable.
134131 alloc_mut,
135132 /// Same as `alloc` except the type is inferred.
136 /// The operand is unused.
133 /// Uses the `node` union field.
137134 alloc_inferred,
138135 /// Same as `alloc_inferred` except mutable.
139136 alloc_inferred_mut,
......@@ -267,9 +264,6 @@ pub const Inst = struct {
267264 /// only the taken branch is analyzed. The then block and else block must
268265 /// terminate with an "inline" variant of a noreturn instruction.
269266 condbr_inline,
270 /// A comptime known value.
271 /// Uses the `const` union field.
272 @"const",
273267 /// A struct type definition. Contains references to ZIR instructions for
274268 /// the field types, defaults, and alignments.
275269 /// Uses the `pl_node` union field. Payload is `StructDecl`.
......@@ -286,6 +280,8 @@ pub const Inst = struct {
286280 /// the field value expressions and optional type tag expression.
287281 /// Uses the `pl_node` union field. Payload is `EnumDecl`.
288282 enum_decl,
283 /// Same as `enum_decl`, except the enum is non-exhaustive.
284 enum_decl_nonexhaustive,
289285 /// An opaque type definition. Provides an AST node only.
290286 /// Uses the `node` union field.
291287 opaque_decl,
......@@ -369,6 +365,11 @@ pub const Inst = struct {
369365 import,
370366 /// Integer literal that fits in a u64. Uses the int union value.
371367 int,
368 /// A float literal that fits in a f32. Uses the float union value.
369 float,
370 /// A float literal that fits in a f128. Uses the `pl_node` union value.
371 /// Payload is `Float128`.
372 float128,
372373 /// Convert an integer value to another integer type, asserting that the destination type
373374 /// can hold the same mathematical value.
374375 /// Uses the `pl_node` field. AST is the `@intCast` syntax.
......@@ -667,6 +668,12 @@ pub const Inst = struct {
667668 /// A struct literal with a specified type, with no fields.
668669 /// Uses the `un_node` field.
669670 struct_init_empty,
671 /// Converts an integer into an enum value.
672 /// Uses `pl_node` with payload `Bin`. `lhs` is enum type, `rhs` is operand.
673 int_to_enum,
674 /// Converts an enum value into an integer. Resulting type will be the tag type
675 /// of the enum. Uses `un_node`.
676 enum_to_int,
670677
671678 /// Returns whether the instruction is one of the control flow "noreturn" types.
672679 /// Function calls do not count.
......@@ -712,12 +719,12 @@ pub const Inst = struct {
712719 .cmp_gt,
713720 .cmp_neq,
714721 .coerce_result_ptr,
715 .@"const",
716722 .struct_decl,
717723 .struct_decl_packed,
718724 .struct_decl_extern,
719725 .union_decl,
720726 .enum_decl,
727 .enum_decl_nonexhaustive,
721728 .opaque_decl,
722729 .dbg_stmt_node,
723730 .decl_ref,
......@@ -740,6 +747,8 @@ pub const Inst = struct {
740747 .fn_type_cc,
741748 .fn_type_cc_var_args,
742749 .int,
750 .float,
751 .float128,
743752 .intcast,
744753 .int_type,
745754 .is_non_null,
......@@ -822,6 +831,8 @@ pub const Inst = struct {
822831 .switch_block_ref_under_multi,
823832 .validate_struct_init_ptr,
824833 .struct_init_empty,
834 .int_to_enum,
835 .enum_to_int,
825836 => false,
826837
827838 .@"break",
......@@ -1184,7 +1195,6 @@ pub const Inst = struct {
11841195 }
11851196 },
11861197 bin: Bin,
1187 @"const": *TypedValue,
11881198 /// For strings which may contain null bytes.
11891199 str: struct {
11901200 /// Offset into `string_bytes`.
......@@ -1226,6 +1236,16 @@ pub const Inst = struct {
12261236 /// Offset from Decl AST node index.
12271237 node: i32,
12281238 int: u64,
1239 float: struct {
1240 /// Offset from Decl AST node index.
1241 /// `Tag` determines which kind of AST node this points to.
1242 src_node: i32,
1243 number: f32,
1244
1245 pub fn src(self: @This()) LazySrcLoc {
1246 return .{ .node_offset = self.src_node };
1247 }
1248 },
12291249 array_type_sentinel: struct {
12301250 len: Ref,
12311251 /// index into extra, points to an `ArrayTypeSentinel`
......@@ -1507,6 +1527,22 @@ pub const Inst = struct {
15071527 tag_type: Ref,
15081528 fields_len: u32,
15091529 };
1530
1531 /// A f128 value, broken up into 4 u32 parts.
1532 pub const Float128 = struct {
1533 piece0: u32,
1534 piece1: u32,
1535 piece2: u32,
1536 piece3: u32,
1537
1538 pub fn get(self: Float128) f128 {
1539 const int_bits = @as(u128, self.piece0) |
1540 (@as(u128, self.piece1) << 32) |
1541 (@as(u128, self.piece2) << 64) |
1542 (@as(u128, self.piece3) << 96);
1543 return @bitCast(f128, int_bits);
1544 }
1545 };
15101546};
15111547
15121548pub const SpecialProng = enum { none, @"else", under };
......@@ -1536,12 +1572,11 @@ const Writer = struct {
15361572 .intcast,
15371573 .store,
15381574 .store_to_block_ptr,
1575 .store_to_inferred_ptr,
15391576 => try self.writeBin(stream, inst),
15401577
15411578 .alloc,
15421579 .alloc_mut,
1543 .alloc_inferred,
1544 .alloc_inferred_mut,
15451580 .indexable_ptr_len,
15461581 .bit_not,
15471582 .bool_not,
......@@ -1581,6 +1616,7 @@ const Writer = struct {
15811616 .typeof,
15821617 .typeof_elem,
15831618 .struct_init_empty,
1619 .enum_to_int,
15841620 => try self.writeUnNode(stream, inst),
15851621
15861622 .ref,
......@@ -1594,11 +1630,12 @@ const Writer = struct {
15941630 => try self.writeBoolBr(stream, inst),
15951631
15961632 .array_type_sentinel => try self.writeArrayTypeSentinel(stream, inst),
1597 .@"const" => try self.writeConst(stream, inst),
15981633 .param_type => try self.writeParamType(stream, inst),
15991634 .ptr_type_simple => try self.writePtrTypeSimple(stream, inst),
16001635 .ptr_type => try self.writePtrType(stream, inst),
16011636 .int => try self.writeInt(stream, inst),
1637 .float => try self.writeFloat(stream, inst),
1638 .float128 => try self.writeFloat128(stream, inst),
16021639 .str => try self.writeStr(stream, inst),
16031640 .elided => try stream.writeAll(")"),
16041641 .int_type => try self.writeIntType(stream, inst),
......@@ -1619,6 +1656,7 @@ const Writer = struct {
16191656 .slice_sentinel,
16201657 .union_decl,
16211658 .enum_decl,
1659 .enum_decl_nonexhaustive,
16221660 => try self.writePlNode(stream, inst),
16231661
16241662 .add,
......@@ -1647,6 +1685,7 @@ const Writer = struct {
16471685 .merge_error_sets,
16481686 .bit_and,
16491687 .bit_or,
1688 .int_to_enum,
16501689 => try self.writePlNodeBin(stream, inst),
16511690
16521691 .call,
......@@ -1704,6 +1743,8 @@ const Writer = struct {
17041743 .ret_type,
17051744 .repeat,
17061745 .repeat_inline,
1746 .alloc_inferred,
1747 .alloc_inferred_mut,
17071748 => try self.writeNode(stream, inst),
17081749
17091750 .error_value,
......@@ -1729,7 +1770,6 @@ const Writer = struct {
17291770
17301771 .bitcast,
17311772 .bitcast_result_ptr,
1732 .store_to_inferred_ptr,
17331773 => try stream.writeAll("TODO)"),
17341774 }
17351775 }
......@@ -1773,15 +1813,6 @@ const Writer = struct {
17731813 try stream.writeAll("TODO)");
17741814 }
17751815
1776 fn writeConst(
1777 self: *Writer,
1778 stream: anytype,
1779 inst: Inst.Index,
1780 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
1781 const inst_data = self.code.instructions.items(.data)[inst].@"const";
1782 try stream.writeAll("TODO)");
1783 }
1784
17851816 fn writeParamType(
17861817 self: *Writer,
17871818 stream: anytype,
......@@ -1819,6 +1850,23 @@ const Writer = struct {
18191850 try stream.print("{d})", .{inst_data});
18201851 }
18211852
1853 fn writeFloat(self: *Writer, stream: anytype, inst: Inst.Index) !void {
1854 const inst_data = self.code.instructions.items(.data)[inst].float;
1855 const src = inst_data.src();
1856 try stream.print("{d}) ", .{inst_data.number});
1857 try self.writeSrc(stream, src);
1858 }
1859
1860 fn writeFloat128(self: *Writer, stream: anytype, inst: Inst.Index) !void {
1861 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
1862 const extra = self.code.extraData(Inst.Float128, inst_data.payload_index).data;
1863 const src = inst_data.src();
1864 const number = extra.get();
1865 // TODO improve std.format to be able to print f128 values
1866 try stream.print("{d}) ", .{@floatCast(f64, number)});
1867 try self.writeSrc(stream, src);
1868 }
1869
18221870 fn writeStr(
18231871 self: *Writer,
18241872 stream: anytype,
......@@ -2136,7 +2184,8 @@ const Writer = struct {
21362184
21372185 fn writePlNodeDecl(self: *Writer, stream: anytype, inst: Inst.Index) !void {
21382186 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
2139 const decl = self.code.decls[inst_data.payload_index];
2187 const owner_decl = self.scope.ownerDecl().?;
2188 const decl = owner_decl.dependencies.entries.items[inst_data.payload_index].key;
21402189 try stream.print("{s}) ", .{decl.name});
21412190 try self.writeSrc(stream, inst_data.src());
21422191 }
test/stage2/cbe.zig+251-2
......@@ -517,7 +517,7 @@ pub fn addCases(ctx: *TestContext) !void {
517517 \\}
518518 , &.{
519519 ":3:21: error: mising struct field: x",
520 ":1:15: note: 'Point' declared here",
520 ":1:15: note: struct 'Point' declared here",
521521 });
522522 case.addError(
523523 \\const Point = struct { x: i32, y: i32 };
......@@ -531,7 +531,7 @@ pub fn addCases(ctx: *TestContext) !void {
531531 \\}
532532 , &.{
533533 ":6:10: error: no field named 'z' in struct 'Point'",
534 ":1:15: note: 'Point' declared here",
534 ":1:15: note: struct declared here",
535535 });
536536 case.addCompareOutput(
537537 \\const Point = struct { x: i32, y: i32 };
......@@ -545,6 +545,255 @@ pub fn addCases(ctx: *TestContext) !void {
545545 , "");
546546 }
547547
548 {
549 var case = ctx.exeFromCompiledC("enums", .{});
550
551 case.addError(
552 \\const E1 = packed enum { a, b, c };
553 \\const E2 = extern enum { a, b, c };
554 \\export fn foo() void {
555 \\ const x = E1.a;
556 \\}
557 \\export fn bar() void {
558 \\ const x = E2.a;
559 \\}
560 , &.{
561 ":1:12: error: enums do not support 'packed' or 'extern'; instead provide an explicit integer tag type",
562 ":2:12: error: enums do not support 'packed' or 'extern'; instead provide an explicit integer tag type",
563 });
564
565 // comptime and types are caught in AstGen.
566 case.addError(
567 \\const E1 = enum {
568 \\ a,
569 \\ comptime b,
570 \\ c,
571 \\};
572 \\const E2 = enum {
573 \\ a,
574 \\ b: i32,
575 \\ c,
576 \\};
577 \\export fn foo() void {
578 \\ const x = E1.a;
579 \\}
580 \\export fn bar() void {
581 \\ const x = E2.a;
582 \\}
583 , &.{
584 ":3:5: error: enum fields cannot be marked comptime",
585 ":8:8: error: enum fields do not have types",
586 });
587
588 // @enumToInt, @intToEnum, enum literal coercion, field access syntax, comparison, switch
589 case.addCompareOutput(
590 \\const Number = enum { One, Two, Three };
591 \\
592 \\export fn main() c_int {
593 \\ var number1 = Number.One;
594 \\ var number2: Number = .Two;
595 \\ const number3 = @intToEnum(Number, 2);
596 \\ if (number1 == number2) return 1;
597 \\ if (number2 == number3) return 1;
598 \\ if (@enumToInt(number1) != 0) return 1;
599 \\ if (@enumToInt(number2) != 1) return 1;
600 \\ if (@enumToInt(number3) != 2) return 1;
601 \\ var x: Number = .Two;
602 \\ if (number2 != x) return 1;
603 \\ switch (x) {
604 \\ .One => return 1,
605 \\ .Two => return 0,
606 \\ number3 => return 2,
607 \\ }
608 \\}
609 , "");
610
611 // Specifying alignment is a parse error.
612 // This also tests going from a successful build to a parse error.
613 case.addError(
614 \\const E1 = enum {
615 \\ a,
616 \\ b align(4),
617 \\ c,
618 \\};
619 \\export fn foo() void {
620 \\ const x = E1.a;
621 \\}
622 , &.{
623 ":3:7: error: expected ',', found 'align'",
624 });
625
626 // Redundant non-exhaustive enum mark.
627 // This also tests going from a parse error to an AstGen error.
628 case.addError(
629 \\const E1 = enum {
630 \\ a,
631 \\ _,
632 \\ b,
633 \\ c,
634 \\ _,
635 \\};
636 \\export fn foo() void {
637 \\ const x = E1.a;
638 \\}
639 , &.{
640 ":6:5: error: redundant non-exhaustive enum mark",
641 ":3:5: note: other mark here",
642 });
643
644 case.addError(
645 \\const E1 = enum {
646 \\ a,
647 \\ b,
648 \\ c,
649 \\ _ = 10,
650 \\};
651 \\export fn foo() void {
652 \\ const x = E1.a;
653 \\}
654 , &.{
655 ":5:9: error: '_' is used to mark an enum as non-exhaustive and cannot be assigned a value",
656 });
657
658 case.addError(
659 \\const E1 = enum {};
660 \\export fn foo() void {
661 \\ const x = E1.a;
662 \\}
663 , &.{
664 ":1:12: error: enum declarations must have at least one tag",
665 });
666
667 case.addError(
668 \\const E1 = enum { a, b, _ };
669 \\export fn foo() void {
670 \\ const x = E1.a;
671 \\}
672 , &.{
673 ":1:12: error: non-exhaustive enum missing integer tag type",
674 ":1:25: note: marked non-exhaustive here",
675 });
676
677 case.addError(
678 \\const E1 = enum { a, b, c, b, d };
679 \\export fn foo() void {
680 \\ const x = E1.a;
681 \\}
682 , &.{
683 ":1:28: error: duplicate enum tag",
684 ":1:22: note: other tag here",
685 });
686
687 case.addError(
688 \\export fn foo() void {
689 \\ const a = true;
690 \\ const b = @enumToInt(a);
691 \\}
692 , &.{
693 ":3:26: error: expected enum or tagged union, found bool",
694 });
695
696 case.addError(
697 \\export fn foo() void {
698 \\ const a = 1;
699 \\ const b = @intToEnum(bool, a);
700 \\}
701 , &.{
702 ":3:26: error: expected enum, found bool",
703 });
704
705 case.addError(
706 \\const E = enum { a, b, c };
707 \\export fn foo() void {
708 \\ const b = @intToEnum(E, 3);
709 \\}
710 , &.{
711 ":3:15: error: enum 'E' has no tag with value 3",
712 ":1:11: note: enum declared here",
713 });
714
715 case.addError(
716 \\const E = enum { a, b, c };
717 \\export fn foo() void {
718 \\ var x: E = .a;
719 \\ switch (x) {
720 \\ .a => {},
721 \\ .c => {},
722 \\ }
723 \\}
724 , &.{
725 ":4:5: error: switch must handle all possibilities",
726 ":4:5: note: unhandled enumeration value: 'b'",
727 ":1:11: note: enum 'E' declared here",
728 });
729
730 case.addError(
731 \\const E = enum { a, b, c };
732 \\export fn foo() void {
733 \\ var x: E = .a;
734 \\ switch (x) {
735 \\ .a => {},
736 \\ .b => {},
737 \\ .b => {},
738 \\ .c => {},
739 \\ }
740 \\}
741 , &.{
742 ":7:10: error: duplicate switch value",
743 ":6:10: note: previous value here",
744 });
745
746 case.addError(
747 \\const E = enum { a, b, c };
748 \\export fn foo() void {
749 \\ var x: E = .a;
750 \\ switch (x) {
751 \\ .a => {},
752 \\ .b => {},
753 \\ .c => {},
754 \\ else => {},
755 \\ }
756 \\}
757 , &.{
758 ":8:14: error: unreachable else prong; all cases already handled",
759 });
760
761 case.addError(
762 \\const E = enum { a, b, c };
763 \\export fn foo() void {
764 \\ var x: E = .a;
765 \\ switch (x) {
766 \\ .a => {},
767 \\ .b => {},
768 \\ _ => {},
769 \\ }
770 \\}
771 , &.{
772 ":4:5: error: '_' prong only allowed when switching on non-exhaustive enums",
773 ":7:11: note: '_' prong here",
774 });
775
776 case.addError(
777 \\const E = enum { a, b, c };
778 \\export fn foo() void {
779 \\ var x = E.d;
780 \\}
781 , &.{
782 ":3:14: error: enum 'E' has no member named 'd'",
783 ":1:11: note: enum declared here",
784 });
785
786 case.addError(
787 \\const E = enum { a, b, c };
788 \\export fn foo() void {
789 \\ var x: E = .d;
790 \\}
791 , &.{
792 ":3:17: error: enum 'E' has no field named 'd'",
793 ":1:11: note: enum declared here",
794 });
795 }
796
548797 ctx.c("empty start function", linux_x64,
549798 \\export fn _start() noreturn {
550799 \\ unreachable;