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;...@@ -9,6 +9,7 @@ const warn = std.debug.warn;
9const Tokenizer = std.zig.Tokenizer;9const Tokenizer = std.zig.Tokenizer;
10const Parser = std.zig.Parser;10const Parser = std.zig.Parser;
11const io = std.io;11const io = std.io;
12const fmtIntSizeBin = std.fmt.fmtIntSizeBin;
1213
13const source = @embedFile("../os.zig");14const source = @embedFile("../os.zig");
14var fixed_buffer_mem: [10 * 1024 * 1024]u8 = undefined;15var fixed_buffer_mem: [10 * 1024 * 1024]u8 = undefined;
...@@ -25,12 +26,15 @@ pub fn main() !void {...@@ -25,12 +26,15 @@ pub fn main() !void {
25 const end = timer.read();26 const end = timer.read();
26 memory_used /= iterations;27 memory_used /= iterations;
27 const elapsed_s = @intToFloat(f64, end - start) / std.time.ns_per_s;28 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 bytes_per_sec_float = @intToFloat(f64, source.len * iterations) / elapsed_s;
29 const mb_per_sec = bytes_per_sec / (1024 * 1024);30 const bytes_per_sec = @floatToInt(u64, @floor(bytes_per_sec_float));
3031
31 var stdout_file = std.io.getStdOut();32 var stdout_file = std.io.getStdOut();
32 const stdout = stdout_file.writer();33 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 });
34}38}
3539
36fn testOnce() usize {40fn testOnce() usize {
src/AstGen.zig+246-57
...@@ -28,8 +28,6 @@ const BuiltinFn = @import("BuiltinFn.zig");...@@ -28,8 +28,6 @@ const BuiltinFn = @import("BuiltinFn.zig");
28instructions: std.MultiArrayList(zir.Inst) = .{},28instructions: std.MultiArrayList(zir.Inst) = .{},
29string_bytes: ArrayListUnmanaged(u8) = .{},29string_bytes: ArrayListUnmanaged(u8) = .{},
30extra: ArrayListUnmanaged(u32) = .{},30extra: ArrayListUnmanaged(u32) = .{},
31decl_map: std.StringArrayHashMapUnmanaged(void) = .{},
32decls: ArrayListUnmanaged(*Decl) = .{},
33/// The end of special indexes. `zir.Inst.Ref` subtracts against this number to convert31/// The end of special indexes. `zir.Inst.Ref` subtracts against this number to convert
34/// to `zir.Inst.Index`. The default here is correct if there are 0 parameters.32/// to `zir.Inst.Index`. The default here is correct if there are 0 parameters.
35ref_start_index: u32 = zir.Inst.Ref.typed_value_map.len,33ref_start_index: u32 = zir.Inst.Ref.typed_value_map.len,
...@@ -110,8 +108,6 @@ pub fn deinit(astgen: *AstGen) void {...@@ -110,8 +108,6 @@ pub fn deinit(astgen: *AstGen) void {
110 astgen.instructions.deinit(gpa);108 astgen.instructions.deinit(gpa);
111 astgen.extra.deinit(gpa);109 astgen.extra.deinit(gpa);
112 astgen.string_bytes.deinit(gpa);110 astgen.string_bytes.deinit(gpa);
113 astgen.decl_map.deinit(gpa);
114 astgen.decls.deinit(gpa);
115}111}
116112
117pub const ResultLoc = union(enum) {113pub const ResultLoc = union(enum) {
...@@ -1183,13 +1179,6 @@ fn blockExprStmts(...@@ -1183,13 +1179,6 @@ fn blockExprStmts(
1183 // in the above while loop.1179 // in the above while loop.
1184 const zir_tags = gz.astgen.instructions.items(.tag);1180 const zir_tags = gz.astgen.instructions.items(.tag);
1185 switch (zir_tags[inst]) {1181 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 },
1193 // For some instructions, swap in a slightly different ZIR tag1182 // For some instructions, swap in a slightly different ZIR tag
1194 // so we can avoid a separate ensure_result_used instruction.1183 // so we can avoid a separate ensure_result_used instruction.
1195 .call_none_chkused => unreachable,1184 .call_none_chkused => unreachable,
...@@ -1257,6 +1246,8 @@ fn blockExprStmts(...@@ -1257,6 +1246,8 @@ fn blockExprStmts(
1257 .fn_type_cc,1246 .fn_type_cc,
1258 .fn_type_cc_var_args,1247 .fn_type_cc_var_args,
1259 .int,1248 .int,
1249 .float,
1250 .float128,
1260 .intcast,1251 .intcast,
1261 .int_type,1252 .int_type,
1262 .is_non_null,1253 .is_non_null,
...@@ -1334,7 +1325,10 @@ fn blockExprStmts(...@@ -1334,7 +1325,10 @@ fn blockExprStmts(
1334 .struct_decl_extern,1325 .struct_decl_extern,
1335 .union_decl,1326 .union_decl,
1336 .enum_decl,1327 .enum_decl,
1328 .enum_decl_nonexhaustive,
1337 .opaque_decl,1329 .opaque_decl,
1330 .int_to_enum,
1331 .enum_to_int,
1338 => break :b false,1332 => break :b false,
13391333
1340 // ZIR instructions that are always either `noreturn` or `void`.1334 // ZIR instructions that are always either `noreturn` or `void`.
...@@ -1490,7 +1484,7 @@ fn varDecl(...@@ -1490,7 +1484,7 @@ fn varDecl(
1490 init_scope.rl_ptr = try init_scope.addUnNode(.alloc, type_inst, node);1484 init_scope.rl_ptr = try init_scope.addUnNode(.alloc, type_inst, node);
1491 init_scope.rl_ty_inst = type_inst;1485 init_scope.rl_ty_inst = type_inst;
1492 } else {1486 } else {
1493 const alloc = try init_scope.addUnNode(.alloc_inferred, undefined, node);1487 const alloc = try init_scope.addNode(.alloc_inferred, node);
1494 resolve_inferred_alloc = alloc;1488 resolve_inferred_alloc = alloc;
1495 init_scope.rl_ptr = alloc;1489 init_scope.rl_ptr = alloc;
1496 }1490 }
...@@ -1565,7 +1559,7 @@ fn varDecl(...@@ -1565,7 +1559,7 @@ fn varDecl(
1565 const alloc = try gz.addUnNode(.alloc_mut, type_inst, node);1559 const alloc = try gz.addUnNode(.alloc_mut, type_inst, node);
1566 break :a .{ .alloc = alloc, .result_loc = .{ .ptr = alloc } };1560 break :a .{ .alloc = alloc, .result_loc = .{ .ptr = alloc } };
1567 } else a: {1561 } else a: {
1568 const alloc = try gz.addUnNode(.alloc_inferred_mut, undefined, node);1562 const alloc = try gz.addNode(.alloc_inferred_mut, node);
1569 resolve_inferred_alloc = alloc;1563 resolve_inferred_alloc = alloc;
1570 break :a .{ .alloc = alloc, .result_loc = .{ .inferred_ptr = alloc } };1564 break :a .{ .alloc = alloc, .result_loc = .{ .inferred_ptr = alloc } };
1571 };1565 };
...@@ -1823,15 +1817,18 @@ fn containerDecl(...@@ -1823,15 +1817,18 @@ fn containerDecl(
1823 defer bit_bag.deinit(gpa);1817 defer bit_bag.deinit(gpa);
18241818
1825 var cur_bit_bag: u32 = 0;1819 var cur_bit_bag: u32 = 0;
1826 var member_index: usize = 0;1820 var field_index: usize = 0;
1827 while (true) {1821 for (container_decl.ast.members) |member_node| {
1828 const member_node = container_decl.ast.members[member_index];
1829 const member = switch (node_tags[member_node]) {1822 const member = switch (node_tags[member_node]) {
1830 .container_field_init => tree.containerFieldInit(member_node),1823 .container_field_init => tree.containerFieldInit(member_node),
1831 .container_field_align => tree.containerFieldAlign(member_node),1824 .container_field_align => tree.containerFieldAlign(member_node),
1832 .container_field => tree.containerField(member_node),1825 .container_field => tree.containerField(member_node),
1833 else => unreachable,1826 else => continue,
1834 };1827 };
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 }
1835 if (member.comptime_token) |comptime_token| {1832 if (member.comptime_token) |comptime_token| {
1836 return mod.failTok(scope, comptime_token, "TODO implement comptime struct fields", .{});1833 return mod.failTok(scope, comptime_token, "TODO implement comptime struct fields", .{});
1837 }1834 }
...@@ -1858,17 +1855,9 @@ fn containerDecl(...@@ -1858,17 +1855,9 @@ fn containerDecl(
1858 fields_data.appendAssumeCapacity(@enumToInt(default_inst));1855 fields_data.appendAssumeCapacity(@enumToInt(default_inst));
1859 }1856 }
18601857
1861 member_index += 1;1858 field_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 }
1870 }1859 }
1871 const empty_slot_count = 16 - ((member_index - 1) % 16);1860 const empty_slot_count = 16 - (field_index % 16);
1872 cur_bit_bag >>= @intCast(u5, empty_slot_count * 2);1861 cur_bit_bag >>= @intCast(u5, empty_slot_count * 2);
18731862
1874 const result = try gz.addPlNode(tag, node, zir.Inst.StructDecl{1863 const result = try gz.addPlNode(tag, node, zir.Inst.StructDecl{
...@@ -1885,7 +1874,172 @@ fn containerDecl(...@@ -1885,7 +1874,172 @@ fn containerDecl(
1885 return mod.failTok(scope, container_decl.ast.main_token, "TODO AstGen for union decl", .{});1874 return mod.failTok(scope, container_decl.ast.main_token, "TODO AstGen for union decl", .{});
1886 },1875 },
1887 .keyword_enum => {1876 .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", .{});
1889 },2043 },
1890 .keyword_opaque => {2044 .keyword_opaque => {
1891 const result = try gz.addNode(.opaque_decl, node);2045 const result = try gz.addNode(.opaque_decl, node);
...@@ -1901,11 +2055,11 @@ fn errorSetDecl(...@@ -1901,11 +2055,11 @@ fn errorSetDecl(
1901 rl: ResultLoc,2055 rl: ResultLoc,
1902 node: ast.Node.Index,2056 node: ast.Node.Index,
1903) InnerError!zir.Inst.Ref {2057) InnerError!zir.Inst.Ref {
1904 const mod = gz.astgen.mod;2058 const astgen = gz.astgen;
2059 const mod = astgen.mod;
1905 const tree = gz.tree();2060 const tree = gz.tree();
1906 const main_tokens = tree.nodes.items(.main_token);2061 const main_tokens = tree.nodes.items(.main_token);
1907 const token_tags = tree.tokens.items(.tag);2062 const token_tags = tree.tokens.items(.tag);
1908 const arena = gz.astgen.arena;
19092063
1910 // Count how many fields there are.2064 // Count how many fields there are.
1911 const error_token = main_tokens[node];2065 const error_token = main_tokens[node];
...@@ -1922,6 +2076,11 @@ fn errorSetDecl(...@@ -1922,6 +2076,11 @@ fn errorSetDecl(
1922 } else unreachable; // TODO should not need else unreachable here2076 } else unreachable; // TODO should not need else unreachable here
1923 };2077 };
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
1925 const fields = try arena.alloc([]const u8, count);2084 const fields = try arena.alloc([]const u8, count);
1926 {2085 {
1927 var tok_i = error_token + 2;2086 var tok_i = error_token + 2;
...@@ -1930,7 +2089,7 @@ fn errorSetDecl(...@@ -1930,7 +2089,7 @@ fn errorSetDecl(
1930 switch (token_tags[tok_i]) {2089 switch (token_tags[tok_i]) {
1931 .doc_comment, .comma => {},2090 .doc_comment, .comma => {},
1932 .identifier => {2091 .identifier => {
1933 fields[field_i] = try mod.identifierTokenString(scope, tok_i);2092 fields[field_i] = try mod.identifierTokenStringTreeArena(scope, tok_i, tree, arena);
1934 field_i += 1;2093 field_i += 1;
1935 },2094 },
1936 .r_brace => break,2095 .r_brace => break,
...@@ -1940,18 +2099,19 @@ fn errorSetDecl(...@@ -1940,18 +2099,19 @@ fn errorSetDecl(
1940 }2099 }
1941 const error_set = try arena.create(Module.ErrorSet);2100 const error_set = try arena.create(Module.ErrorSet);
1942 error_set.* = .{2101 error_set.* = .{
1943 .owner_decl = gz.astgen.decl,2102 .owner_decl = astgen.decl,
1944 .node_offset = gz.astgen.decl.nodeIndexToRelative(node),2103 .node_offset = astgen.decl.nodeIndexToRelative(node),
1945 .names_ptr = fields.ptr,2104 .names_ptr = fields.ptr,
1946 .names_len = @intCast(u32, fields.len),2105 .names_len = @intCast(u32, fields.len),
1947 };2106 };
1948 const error_set_ty = try Type.Tag.error_set.create(arena, error_set);2107 const error_set_ty = try Type.Tag.error_set.create(arena, error_set);
1949 const typed_value = try arena.create(TypedValue);2108 const error_set_val = try Value.Tag.ty.create(arena, error_set_ty);
1950 typed_value.* = .{2109 const new_decl = try mod.createAnonymousDecl(scope, &new_decl_arena, .{
1951 .ty = Type.initTag(.type),2110 .ty = Type.initTag(.type),
1952 .val = try Value.Tag.ty.create(arena, error_set_ty),2111 .val = error_set_val,
1953 };2112 });
1954 const result = try gz.addConst(typed_value);2113 const decl_index = try mod.declareDeclDependency(astgen.decl, new_decl);
2114 const result = try gz.addDecl(.decl_val, decl_index, node);
1955 return rvalue(gz, scope, rl, result, node);2115 return rvalue(gz, scope, rl, result, node);
1956}2116}
19572117
...@@ -3196,8 +3356,13 @@ fn switchExpr(...@@ -3196,8 +3356,13 @@ fn switchExpr(
3196 switch (strat.tag) {3356 switch (strat.tag) {
3197 .break_operand => {3357 .break_operand => {
3198 // Switch expressions return `true` for `nodeMayNeedMemoryLocation` thus3358 // Switch expressions return `true` for `nodeMayNeedMemoryLocation` thus
3199 // this is always true.3359 // `elide_store_to_block_ptr_instructions` will either be true,
3200 assert(strat.elide_store_to_block_ptr_instructions);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
3202 // There will necessarily be a store_to_block_ptr for3367 // There will necessarily be a store_to_block_ptr for
3203 // all prongs, except for prongs that ended with a noreturn instruction.3368 // all prongs, except for prongs that ended with a noreturn instruction.
...@@ -3426,7 +3591,8 @@ fn identifier(...@@ -3426,7 +3591,8 @@ fn identifier(
3426 const tracy = trace(@src());3591 const tracy = trace(@src());
3427 defer tracy.end();3592 defer tracy.end();
34283593
3429 const mod = gz.astgen.mod;3594 const astgen = gz.astgen;
3595 const mod = astgen.mod;
3430 const tree = gz.tree();3596 const tree = gz.tree();
3431 const main_tokens = tree.nodes.items(.main_token);3597 const main_tokens = tree.nodes.items(.main_token);
34323598
...@@ -3459,7 +3625,7 @@ fn identifier(...@@ -3459,7 +3625,7 @@ fn identifier(
3459 const result = try gz.add(.{3625 const result = try gz.add(.{
3460 .tag = .int_type,3626 .tag = .int_type,
3461 .data = .{ .int_type = .{3627 .data = .{ .int_type = .{
3462 .src_node = gz.astgen.decl.nodeIndexToRelative(ident),3628 .src_node = astgen.decl.nodeIndexToRelative(ident),
3463 .signedness = signedness,3629 .signedness = signedness,
3464 .bit_count = bit_count,3630 .bit_count = bit_count,
3465 } },3631 } },
...@@ -3497,13 +3663,13 @@ fn identifier(...@@ -3497,13 +3663,13 @@ fn identifier(
3497 };3663 };
3498 }3664 }
34993665
3500 const gop = try gz.astgen.decl_map.getOrPut(mod.gpa, ident_name);3666 const decl = mod.lookupDeclName(scope, ident_name) orelse {
3501 if (!gop.found_existing) {3667 // TODO insert a "dependency on the non-existence of a decl" here to make this
3502 const decl = mod.lookupDeclName(scope, ident_name) orelse3668 // compile error go away when the decl is introduced. This data should be in a global
3503 return mod.failNode(scope, ident, "use of undeclared identifier '{s}'", .{ident_name});3669 // sparse map since it is only relevant when a compile error occurs.
3504 try gz.astgen.decls.append(mod.gpa, decl);3670 return mod.failNode(scope, ident, "use of undeclared identifier '{s}'", .{ident_name});
3505 }3671 };
3506 const decl_index = @intCast(u32, gop.index);3672 const decl_index = try mod.declareDeclDependency(astgen.decl, decl);
3507 switch (rl) {3673 switch (rl) {
3508 .ref, .none_or_ref => return gz.addDecl(.decl_ref, decl_index, ident),3674 .ref, .none_or_ref => return gz.addDecl(.decl_ref, decl_index, ident),
3509 else => return rvalue(gz, scope, rl, try gz.addDecl(.decl_val, decl_index, ident), ident),3675 else => return rvalue(gz, scope, rl, try gz.addDecl(.decl_val, decl_index, ident), ident),
...@@ -3638,12 +3804,23 @@ fn floatLiteral(...@@ -3638,12 +3804,23 @@ fn floatLiteral(
3638 const float_number = std.fmt.parseFloat(f128, bytes) catch |e| switch (e) {3804 const float_number = std.fmt.parseFloat(f128, bytes) catch |e| switch (e) {
3639 error.InvalidCharacter => unreachable, // validated by tokenizer3805 error.InvalidCharacter => unreachable, // validated by tokenizer
3640 };3806 };
3641 const typed_value = try arena.create(TypedValue);3807 // If the value fits into a f32 without losing any precision, store it that way.
3642 typed_value.* = .{3808 @setFloatMode(.Strict);
3643 .ty = Type.initTag(.comptime_float),3809 const smaller_float = @floatCast(f32, float_number);
3644 .val = try Value.Tag.float_128.create(arena, float_number),3810 const bigger_again: f128 = smaller_float;
3645 };3811 if (bigger_again == float_number) {
3646 const result = try gz.addConst(typed_value);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 });
3647 return rvalue(gz, scope, rl, result, node);3824 return rvalue(gz, scope, rl, result, node);
3648}3825}
36493826
...@@ -3955,6 +4132,20 @@ fn builtinCall(...@@ -3955,6 +4132,20 @@ fn builtinCall(
3955 .bit_cast => return bitCast(gz, scope, rl, node, params[0], params[1]),4132 .bit_cast => return bitCast(gz, scope, rl, node, params[0], params[1]),
3956 .TypeOf => return typeOf(gz, scope, rl, node, params),4133 .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
3958 .add_with_overflow,4149 .add_with_overflow,
3959 .align_cast,4150 .align_cast,
3960 .align_of,4151 .align_of,
...@@ -3981,7 +4172,6 @@ fn builtinCall(...@@ -3981,7 +4172,6 @@ fn builtinCall(
3981 .div_floor,4172 .div_floor,
3982 .div_trunc,4173 .div_trunc,
3983 .embed_file,4174 .embed_file,
3984 .enum_to_int,
3985 .error_name,4175 .error_name,
3986 .error_return_trace,4176 .error_return_trace,
3987 .err_set_cast,4177 .err_set_cast,
...@@ -3991,7 +4181,6 @@ fn builtinCall(...@@ -3991,7 +4181,6 @@ fn builtinCall(
3991 .float_to_int,4181 .float_to_int,
3992 .has_decl,4182 .has_decl,
3993 .has_field,4183 .has_field,
3994 .int_to_enum,
3995 .int_to_float,4184 .int_to_float,
3996 .int_to_ptr,4185 .int_to_ptr,
3997 .memcpy,4186 .memcpy,
src/BuiltinFn.zig+1-1
...@@ -484,7 +484,7 @@ pub const list = list: {...@@ -484,7 +484,7 @@ pub const list = list: {
484 "@intToEnum",484 "@intToEnum",
485 .{485 .{
486 .tag = .int_to_enum,486 .tag = .int_to_enum,
487 .param_count = 1,487 .param_count = 2,
488 },488 },
489 },489 },
490 .{490 .{
src/Compilation.zig+41-14
...@@ -1346,9 +1346,9 @@ pub fn update(self: *Compilation) !void {...@@ -1346,9 +1346,9 @@ pub fn update(self: *Compilation) !void {
1346 module.generation += 1;1346 module.generation += 1;
13471347
1348 // TODO Detect which source files changed.1348 // TODO Detect which source files changed.
1349 // Until then we simulate a full cache miss. Source files could have been loaded for any reason;1349 // Until then we simulate a full cache miss. Source files could have been loaded
1350 // to force a refresh we unload now.1350 // for any reason; to force a refresh we unload now.
1351 module.root_scope.unload(module.gpa);1351 module.unloadFile(module.root_scope);
1352 module.failed_root_src_file = null;1352 module.failed_root_src_file = null;
1353 module.analyzeContainer(&module.root_scope.root_container) catch |err| switch (err) {1353 module.analyzeContainer(&module.root_scope.root_container) catch |err| switch (err) {
1354 error.AnalysisFail => {1354 error.AnalysisFail => {
...@@ -1362,7 +1362,7 @@ pub fn update(self: *Compilation) !void {...@@ -1362,7 +1362,7 @@ pub fn update(self: *Compilation) !void {
13621362
1363 // TODO only analyze imports if they are still referenced1363 // TODO only analyze imports if they are still referenced
1364 for (module.import_table.items()) |entry| {1364 for (module.import_table.items()) |entry| {
1365 entry.value.unload(module.gpa);1365 module.unloadFile(entry.value);
1366 module.analyzeContainer(&entry.value.root_container) catch |err| switch (err) {1366 module.analyzeContainer(&entry.value.root_container) catch |err| switch (err) {
1367 error.AnalysisFail => {1367 error.AnalysisFail => {
1368 assert(self.totalErrorCount() != 0);1368 assert(self.totalErrorCount() != 0);
...@@ -1377,14 +1377,17 @@ pub fn update(self: *Compilation) !void {...@@ -1377,14 +1377,17 @@ pub fn update(self: *Compilation) !void {
13771377
1378 if (!use_stage1) {1378 if (!use_stage1) {
1379 if (self.bin_file.options.module) |module| {1379 if (self.bin_file.options.module) |module| {
1380 // Process the deletion set.1380 // Process the deletion set. We use a while loop here because the
1381 while (module.deletion_set.popOrNull()) |decl| {1381 // deletion set may grow as we call `deleteDecl` within this loop,
1382 if (decl.dependants.items().len != 0) {1382 // and more unreferenced Decls are revealed.
1383 decl.deletion_flag = false;1383 var entry_i: usize = 0;
1384 continue;1384 while (entry_i < module.deletion_set.entries.items.len) : (entry_i += 1) {
1385 }1385 const decl = module.deletion_set.entries.items[entry_i].key;
1386 try module.deleteDecl(decl);1386 assert(decl.deletion_flag);
1387 assert(decl.dependants.items().len == 0);
1388 try module.deleteDecl(decl, null);
1387 }1389 }
1390 module.deletion_set.shrinkRetainingCapacity(0);
1388 }1391 }
1389 }1392 }
13901393
...@@ -1429,11 +1432,25 @@ pub fn totalErrorCount(self: *Compilation) usize {...@@ -1429,11 +1432,25 @@ pub fn totalErrorCount(self: *Compilation) usize {
1429 var total: usize = self.failed_c_objects.items().len;1432 var total: usize = self.failed_c_objects.items().len;
14301433
1431 if (self.bin_file.options.module) |module| {1434 if (self.bin_file.options.module) |module| {
1432 total += module.failed_decls.count() +1435 total += module.failed_exports.items().len +
1433 module.emit_h_failed_decls.count() +
1434 module.failed_exports.items().len +
1435 module.failed_files.items().len +1436 module.failed_files.items().len +
1436 @boolToInt(module.failed_root_src_file != null);1437 @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 }
1437 }1454 }
14381455
1439 // The "no entry point found" error only counts if there are no other errors.1456 // The "no entry point found" error only counts if there are no other errors.
...@@ -1480,9 +1497,19 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {...@@ -1480,9 +1497,19 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
1480 try AllErrors.add(module, &arena, &errors, entry.value.*);1497 try AllErrors.add(module, &arena, &errors, entry.value.*);
1481 }1498 }
1482 for (module.failed_decls.items()) |entry| {1499 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 }
1483 try AllErrors.add(module, &arena, &errors, entry.value.*);1505 try AllErrors.add(module, &arena, &errors, entry.value.*);
1484 }1506 }
1485 for (module.emit_h_failed_decls.items()) |entry| {1507 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 }
1486 try AllErrors.add(module, &arena, &errors, entry.value.*);1513 try AllErrors.add(module, &arena, &errors, entry.value.*);
1487 }1514 }
1488 for (module.failed_exports.items()) |entry| {1515 for (module.failed_exports.items()) |entry| {
src/Module.zig+204-38
...@@ -65,8 +65,8 @@ emit_h_failed_decls: std.AutoArrayHashMapUnmanaged(*Decl, *ErrorMsg) = .{},...@@ -65,8 +65,8 @@ emit_h_failed_decls: std.AutoArrayHashMapUnmanaged(*Decl, *ErrorMsg) = .{},
65/// Keep track of one `@compileLog` callsite per owner Decl.65/// Keep track of one `@compileLog` callsite per owner Decl.
66compile_log_decls: std.AutoArrayHashMapUnmanaged(*Decl, SrcLoc) = .{},66compile_log_decls: std.AutoArrayHashMapUnmanaged(*Decl, SrcLoc) = .{},
67/// Using a map here for consistency with the other fields here.67/// 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.68/// The ErrorMsg memory is owned by the `Scope.File`, using Module's general purpose allocator.
69failed_files: std.AutoArrayHashMapUnmanaged(*Scope, *ErrorMsg) = .{},69failed_files: std.AutoArrayHashMapUnmanaged(*Scope.File, *ErrorMsg) = .{},
70/// Using a map here for consistency with the other fields here.70/// Using a map here for consistency with the other fields here.
71/// The ErrorMsg memory is owned by the `Export`, using Module's general purpose allocator.71/// The ErrorMsg memory is owned by the `Export`, using Module's general purpose allocator.
72failed_exports: std.AutoArrayHashMapUnmanaged(*Export, *ErrorMsg) = .{},72failed_exports: std.AutoArrayHashMapUnmanaged(*Export, *ErrorMsg) = .{},
...@@ -75,7 +75,7 @@ next_anon_name_index: usize = 0,...@@ -75,7 +75,7 @@ next_anon_name_index: usize = 0,
7575
76/// Candidates for deletion. After a semantic analysis update completes, this list76/// Candidates for deletion. After a semantic analysis update completes, this list
77/// contains Decls that need to be deleted if they end up having no references to them.77/// 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
80/// Error tags and their values, tag names are duped with mod.gpa.80/// Error tags and their values, tag names are duped with mod.gpa.
81/// Corresponds with `error_name_list`.81/// Corresponds with `error_name_list`.
...@@ -192,7 +192,7 @@ pub const Decl = struct {...@@ -192,7 +192,7 @@ pub const Decl = struct {
192 /// to require re-analysis.192 /// to require re-analysis.
193 outdated,193 outdated,
194 },194 },
195 /// This flag is set when this Decl is added to a check_for_deletion set, and cleared195 /// This flag is set when this Decl is added to `Module.deletion_set`, and cleared
196 /// when removed.196 /// when removed.
197 deletion_flag: bool,197 deletion_flag: bool,
198 /// Whether the corresponding AST decl has a `pub` keyword.198 /// Whether the corresponding AST decl has a `pub` keyword.
...@@ -290,6 +290,18 @@ pub const Decl = struct {...@@ -290,6 +290,18 @@ pub const Decl = struct {
290 return decl.container.fullyQualifiedNameHash(mem.spanZ(decl.name));290 return decl.container.fullyQualifiedNameHash(mem.spanZ(decl.name));
291 }291 }
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
293 pub fn typedValue(decl: *Decl) error{AnalysisFail}!TypedValue {305 pub fn typedValue(decl: *Decl) error{AnalysisFail}!TypedValue {
294 const tvm = decl.typedValueManaged() orelse return error.AnalysisFail;306 const tvm = decl.typedValueManaged() orelse return error.AnalysisFail;
295 return tvm.typed_value;307 return tvm.typed_value;
...@@ -354,6 +366,13 @@ pub const ErrorSet = struct {...@@ -354,6 +366,13 @@ pub const ErrorSet = struct {
354 /// The string bytes are stored in the owner Decl arena.366 /// The string bytes are stored in the owner Decl arena.
355 /// They are in the same order they appear in the AST.367 /// They are in the same order they appear in the AST.
356 names_ptr: [*]const []const u8,368 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 }
357};376};
358377
359/// Represents the data that a struct declaration provides.378/// Represents the data that a struct declaration provides.
...@@ -375,8 +394,7 @@ pub const Struct = struct {...@@ -375,8 +394,7 @@ pub const Struct = struct {
375 };394 };
376395
377 pub fn getFullyQualifiedName(s: *Struct, gpa: *Allocator) ![]u8 {396 pub fn getFullyQualifiedName(s: *Struct, gpa: *Allocator) ![]u8 {
378 // TODO this should return e.g. "std.fs.Dir.OpenOptions"397 return s.owner_decl.getFullyQualifiedName(gpa);
379 return gpa.dupe(u8, mem.spanZ(s.owner_decl.name));
380 }398 }
381399
382 pub fn srcLoc(s: Struct) SrcLoc {400 pub fn srcLoc(s: Struct) SrcLoc {
...@@ -387,6 +405,53 @@ pub const Struct = struct {...@@ -387,6 +405,53 @@ pub const Struct = struct {
387 }405 }
388};406};
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
390/// Some Fn struct memory is owned by the Decl's TypedValue.Managed arena allocator.455/// Some Fn struct memory is owned by the Decl's TypedValue.Managed arena allocator.
391/// Extern functions do not have this data structure; they are represented by456/// Extern functions do not have this data structure; they are represented by
392/// the `Decl` only, with a `Value` tag of `extern_fn`.457/// the `Decl` only, with a `Value` tag of `extern_fn`.
...@@ -634,6 +699,11 @@ pub const Scope = struct {...@@ -634,6 +699,11 @@ pub const Scope = struct {
634 // TODO container scope qualified names.699 // TODO container scope qualified names.
635 return std.zig.hashSrc(name);700 return std.zig.hashSrc(name);
636 }701 }
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 }
637 };707 };
638708
639 pub const File = struct {709 pub const File = struct {
...@@ -662,10 +732,12 @@ pub const Scope = struct {...@@ -662,10 +732,12 @@ pub const Scope = struct {
662732
663 pub fn unload(file: *File, gpa: *Allocator) void {733 pub fn unload(file: *File, gpa: *Allocator) void {
664 switch (file.status) {734 switch (file.status) {
665 .never_loaded,
666 .unloaded_parse_failure,735 .unloaded_parse_failure,
736 .never_loaded,
667 .unloaded_success,737 .unloaded_success,
668 => {},738 => {
739 file.status = .unloaded_success;
740 },
669741
670 .loaded_success => {742 .loaded_success => {
671 file.tree.deinit(gpa);743 file.tree.deinit(gpa);
...@@ -1030,7 +1102,6 @@ pub const Scope = struct {...@@ -1030,7 +1102,6 @@ pub const Scope = struct {
1030 .instructions = gz.astgen.instructions.toOwnedSlice(),1102 .instructions = gz.astgen.instructions.toOwnedSlice(),
1031 .string_bytes = gz.astgen.string_bytes.toOwnedSlice(gpa),1103 .string_bytes = gz.astgen.string_bytes.toOwnedSlice(gpa),
1032 .extra = gz.astgen.extra.toOwnedSlice(gpa),1104 .extra = gz.astgen.extra.toOwnedSlice(gpa),
1033 .decls = gz.astgen.decls.toOwnedSlice(gpa),
1034 };1105 };
1035 }1106 }
10361107
...@@ -1242,6 +1313,16 @@ pub const Scope = struct {...@@ -1242,6 +1313,16 @@ pub const Scope = struct {
1242 });1313 });
1243 }1314 }
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
1245 pub fn addUnNode(1326 pub fn addUnNode(
1246 gz: *GenZir,1327 gz: *GenZir,
1247 tag: zir.Inst.Tag,1328 tag: zir.Inst.Tag,
...@@ -1450,13 +1531,6 @@ pub const Scope = struct {...@@ -1450,13 +1531,6 @@ pub const Scope = struct {
1450 return new_index;1531 return new_index;
1451 }1532 }
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
1460 pub fn add(gz: *GenZir, inst: zir.Inst) !zir.Inst.Ref {1534 pub fn add(gz: *GenZir, inst: zir.Inst) !zir.Inst.Ref {
1461 return gz.astgen.indexToRef(try gz.addAsIndex(inst));1535 return gz.astgen.indexToRef(try gz.addAsIndex(inst));
1462 }1536 }
...@@ -2321,7 +2395,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl: *Decl) InnerError!void {...@@ -2321,7 +2395,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl: *Decl) InnerError!void {
2321 // We don't perform a deletion here, because this Decl or another one2395 // We don't perform a deletion here, because this Decl or another one
2322 // may end up referencing it before the update is complete.2396 // may end up referencing it before the update is complete.
2323 dep.deletion_flag = true;2397 dep.deletion_flag = true;
2324 try mod.deletion_set.append(mod.gpa, dep);2398 try mod.deletion_set.put(mod.gpa, dep, {});
2325 }2399 }
2326 }2400 }
2327 decl.dependencies.clearRetainingCapacity();2401 decl.dependencies.clearRetainingCapacity();
...@@ -3120,12 +3194,19 @@ fn astgenAndSemaVarDecl(...@@ -3120,12 +3194,19 @@ fn astgenAndSemaVarDecl(
3120 return type_changed;3194 return type_changed;
3121}3195}
31223196
3123pub fn declareDeclDependency(mod: *Module, depender: *Decl, dependee: *Decl) !void {3197/// Returns the depender's index of the dependee.
3124 try depender.dependencies.ensureCapacity(mod.gpa, depender.dependencies.items().len + 1);3198pub fn declareDeclDependency(mod: *Module, depender: *Decl, dependee: *Decl) !u32 {
3125 try dependee.dependants.ensureCapacity(mod.gpa, dependee.dependants.items().len + 1);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, {});
3128 dependee.dependants.putAssumeCapacity(depender, {});3207 dependee.dependants.putAssumeCapacity(depender, {});
3208 const gop = depender.dependencies.getOrPutAssumeCapacity(dependee);
3209 return @intCast(u32, gop.index);
3129}3210}
31303211
3131pub fn getAstTree(mod: *Module, root_scope: *Scope.File) !*const ast.Tree {3212pub 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 {...@@ -3150,17 +3231,19 @@ pub fn getAstTree(mod: *Module, root_scope: *Scope.File) !*const ast.Tree {
3150 var msg = std.ArrayList(u8).init(mod.gpa);3231 var msg = std.ArrayList(u8).init(mod.gpa);
3151 defer msg.deinit();3232 defer msg.deinit();
31523233
3234 const token_starts = tree.tokens.items(.start);
3235
3153 try tree.renderError(parse_err, msg.writer());3236 try tree.renderError(parse_err, msg.writer());
3154 const err_msg = try mod.gpa.create(ErrorMsg);3237 const err_msg = try mod.gpa.create(ErrorMsg);
3155 err_msg.* = .{3238 err_msg.* = .{
3156 .src_loc = .{3239 .src_loc = .{
3157 .container = .{ .file_scope = root_scope },3240 .container = .{ .file_scope = root_scope },
3158 .lazy = .{ .token_abs = parse_err.token },3241 .lazy = .{ .byte_abs = token_starts[parse_err.token] },
3159 },3242 },
3160 .msg = msg.toOwnedSlice(),3243 .msg = msg.toOwnedSlice(),
3161 };3244 };
31623245
3163 mod.failed_files.putAssumeCapacityNoClobber(&root_scope.base, err_msg);3246 mod.failed_files.putAssumeCapacityNoClobber(root_scope, err_msg);
3164 root_scope.status = .unloaded_parse_failure;3247 root_scope.status = .unloaded_parse_failure;
3165 return error.AnalysisFail;3248 return error.AnalysisFail;
3166 }3249 }
...@@ -3200,6 +3283,14 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3200,6 +3283,14 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3200 deleted_decls.putAssumeCapacityNoClobber(entry.key, {});3283 deleted_decls.putAssumeCapacityNoClobber(entry.key, {});
3201 }3284 }
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
3203 for (decls) |decl_node, decl_i| switch (node_tags[decl_node]) {3294 for (decls) |decl_node, decl_i| switch (node_tags[decl_node]) {
3204 .fn_decl => {3295 .fn_decl => {
3205 const fn_proto = node_datas[decl_node].lhs;3296 const fn_proto = node_datas[decl_node].lhs;
...@@ -3210,6 +3301,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3210,6 +3301,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3210 try mod.semaContainerFn(3301 try mod.semaContainerFn(
3211 container_scope,3302 container_scope,
3212 &deleted_decls,3303 &deleted_decls,
3304 &outdated_decls,
3213 decl_node,3305 decl_node,
3214 decl_i,3306 decl_i,
3215 tree.*,3307 tree.*,
...@@ -3220,6 +3312,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3220,6 +3312,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3220 .fn_proto_multi => try mod.semaContainerFn(3312 .fn_proto_multi => try mod.semaContainerFn(
3221 container_scope,3313 container_scope,
3222 &deleted_decls,3314 &deleted_decls,
3315 &outdated_decls,
3223 decl_node,3316 decl_node,
3224 decl_i,3317 decl_i,
3225 tree.*,3318 tree.*,
...@@ -3231,6 +3324,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3231,6 +3324,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3231 try mod.semaContainerFn(3324 try mod.semaContainerFn(
3232 container_scope,3325 container_scope,
3233 &deleted_decls,3326 &deleted_decls,
3327 &outdated_decls,
3234 decl_node,3328 decl_node,
3235 decl_i,3329 decl_i,
3236 tree.*,3330 tree.*,
...@@ -3241,6 +3335,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3241,6 +3335,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3241 .fn_proto => try mod.semaContainerFn(3335 .fn_proto => try mod.semaContainerFn(
3242 container_scope,3336 container_scope,
3243 &deleted_decls,3337 &deleted_decls,
3338 &outdated_decls,
3244 decl_node,3339 decl_node,
3245 decl_i,3340 decl_i,
3246 tree.*,3341 tree.*,
...@@ -3255,6 +3350,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3255,6 +3350,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3255 try mod.semaContainerFn(3350 try mod.semaContainerFn(
3256 container_scope,3351 container_scope,
3257 &deleted_decls,3352 &deleted_decls,
3353 &outdated_decls,
3258 decl_node,3354 decl_node,
3259 decl_i,3355 decl_i,
3260 tree.*,3356 tree.*,
...@@ -3265,6 +3361,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3265,6 +3361,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3265 .fn_proto_multi => try mod.semaContainerFn(3361 .fn_proto_multi => try mod.semaContainerFn(
3266 container_scope,3362 container_scope,
3267 &deleted_decls,3363 &deleted_decls,
3364 &outdated_decls,
3268 decl_node,3365 decl_node,
3269 decl_i,3366 decl_i,
3270 tree.*,3367 tree.*,
...@@ -3276,6 +3373,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3276,6 +3373,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3276 try mod.semaContainerFn(3373 try mod.semaContainerFn(
3277 container_scope,3374 container_scope,
3278 &deleted_decls,3375 &deleted_decls,
3376 &outdated_decls,
3279 decl_node,3377 decl_node,
3280 decl_i,3378 decl_i,
3281 tree.*,3379 tree.*,
...@@ -3286,6 +3384,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3286,6 +3384,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3286 .fn_proto => try mod.semaContainerFn(3384 .fn_proto => try mod.semaContainerFn(
3287 container_scope,3385 container_scope,
3288 &deleted_decls,3386 &deleted_decls,
3387 &outdated_decls,
3289 decl_node,3388 decl_node,
3290 decl_i,3389 decl_i,
3291 tree.*,3390 tree.*,
...@@ -3296,6 +3395,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3296,6 +3395,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3296 .global_var_decl => try mod.semaContainerVar(3395 .global_var_decl => try mod.semaContainerVar(
3297 container_scope,3396 container_scope,
3298 &deleted_decls,3397 &deleted_decls,
3398 &outdated_decls,
3299 decl_node,3399 decl_node,
3300 decl_i,3400 decl_i,
3301 tree.*,3401 tree.*,
...@@ -3304,6 +3404,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3304,6 +3404,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3304 .local_var_decl => try mod.semaContainerVar(3404 .local_var_decl => try mod.semaContainerVar(
3305 container_scope,3405 container_scope,
3306 &deleted_decls,3406 &deleted_decls,
3407 &outdated_decls,
3307 decl_node,3408 decl_node,
3308 decl_i,3409 decl_i,
3309 tree.*,3410 tree.*,
...@@ -3312,6 +3413,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3312,6 +3413,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3312 .simple_var_decl => try mod.semaContainerVar(3413 .simple_var_decl => try mod.semaContainerVar(
3313 container_scope,3414 container_scope,
3314 &deleted_decls,3415 &deleted_decls,
3416 &outdated_decls,
3315 decl_node,3417 decl_node,
3316 decl_i,3418 decl_i,
3317 tree.*,3419 tree.*,
...@@ -3320,6 +3422,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3320,6 +3422,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3320 .aligned_var_decl => try mod.semaContainerVar(3422 .aligned_var_decl => try mod.semaContainerVar(
3321 container_scope,3423 container_scope,
3322 &deleted_decls,3424 &deleted_decls,
3425 &outdated_decls,
3323 decl_node,3426 decl_node,
3324 decl_i,3427 decl_i,
3325 tree.*,3428 tree.*,
...@@ -3372,11 +3475,27 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3372,11 +3475,27 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3372 },3475 },
3373 else => unreachable,3476 else => unreachable,
3374 };3477 };
3375 // Handle explicitly deleted decls from the source code. Not to be confused3478 // Handle explicitly deleted decls from the source code. This is one of two
3376 // with when we delete decls because they are no longer referenced.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.
3377 for (deleted_decls.items()) |entry| {3486 for (deleted_decls.items()) |entry| {
3378 log.debug("noticed '{s}' deleted from source", .{entry.key.name});3487 const decl = entry.key;
3379 try mod.deleteDecl(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);
3380 }3499 }
3381}3500}
33823501
...@@ -3384,6 +3503,7 @@ fn semaContainerFn(...@@ -3384,6 +3503,7 @@ fn semaContainerFn(
3384 mod: *Module,3503 mod: *Module,
3385 container_scope: *Scope.Container,3504 container_scope: *Scope.Container,
3386 deleted_decls: *std.AutoArrayHashMap(*Decl, void),3505 deleted_decls: *std.AutoArrayHashMap(*Decl, void),
3506 outdated_decls: *std.AutoArrayHashMap(*Decl, void),
3387 decl_node: ast.Node.Index,3507 decl_node: ast.Node.Index,
3388 decl_i: usize,3508 decl_i: usize,
3389 tree: ast.Tree,3509 tree: ast.Tree,
...@@ -3415,7 +3535,7 @@ fn semaContainerFn(...@@ -3415,7 +3535,7 @@ fn semaContainerFn(
3415 try mod.failed_decls.putNoClobber(mod.gpa, decl, msg);3535 try mod.failed_decls.putNoClobber(mod.gpa, decl, msg);
3416 } else {3536 } else {
3417 if (!srcHashEql(decl.contents_hash, contents_hash)) {3537 if (!srcHashEql(decl.contents_hash, contents_hash)) {
3418 try mod.markOutdatedDecl(decl);3538 try outdated_decls.put(decl, {});
3419 decl.contents_hash = contents_hash;3539 decl.contents_hash = contents_hash;
3420 } else switch (mod.comp.bin_file.tag) {3540 } else switch (mod.comp.bin_file.tag) {
3421 .coff => {3541 .coff => {
...@@ -3450,6 +3570,7 @@ fn semaContainerVar(...@@ -3450,6 +3570,7 @@ fn semaContainerVar(
3450 mod: *Module,3570 mod: *Module,
3451 container_scope: *Scope.Container,3571 container_scope: *Scope.Container,
3452 deleted_decls: *std.AutoArrayHashMap(*Decl, void),3572 deleted_decls: *std.AutoArrayHashMap(*Decl, void),
3573 outdated_decls: *std.AutoArrayHashMap(*Decl, void),
3453 decl_node: ast.Node.Index,3574 decl_node: ast.Node.Index,
3454 decl_i: usize,3575 decl_i: usize,
3455 tree: ast.Tree,3576 tree: ast.Tree,
...@@ -3475,7 +3596,7 @@ fn semaContainerVar(...@@ -3475,7 +3596,7 @@ fn semaContainerVar(
3475 errdefer err_msg.destroy(mod.gpa);3596 errdefer err_msg.destroy(mod.gpa);
3476 try mod.failed_decls.putNoClobber(mod.gpa, decl, err_msg);3597 try mod.failed_decls.putNoClobber(mod.gpa, decl, err_msg);
3477 } else if (!srcHashEql(decl.contents_hash, contents_hash)) {3598 } else if (!srcHashEql(decl.contents_hash, contents_hash)) {
3478 try mod.markOutdatedDecl(decl);3599 try outdated_decls.put(decl, {});
3479 decl.contents_hash = contents_hash;3600 decl.contents_hash = contents_hash;
3480 }3601 }
3481 } else {3602 } else {
...@@ -3505,17 +3626,27 @@ fn semaContainerField(...@@ -3505,17 +3626,27 @@ fn semaContainerField(
3505 log.err("TODO: analyze container field", .{});3626 log.err("TODO: analyze container field", .{});
3506}3627}
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 {
3509 const tracy = trace(@src());3634 const tracy = trace(@src());
3510 defer tracy.end();3635 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
3514 // Remove from the namespace it resides in. In the case of an anonymous Decl it will3646 // Remove from the namespace it resides in. In the case of an anonymous Decl it will
3515 // not be present in the set, and this does nothing.3647 // not be present in the set, and this does nothing.
3516 decl.container.removeDecl(decl);3648 decl.container.removeDecl(decl);
35173649
3518 log.debug("deleting decl '{s}'", .{decl.name});
3519 const name_hash = decl.fullyQualifiedNameHash();3650 const name_hash = decl.fullyQualifiedNameHash();
3520 mod.decl_table.removeAssertDiscard(name_hash);3651 mod.decl_table.removeAssertDiscard(name_hash);
3521 // Remove itself from its dependencies, because we are about to destroy the decl pointer.3652 // 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 {...@@ -3526,16 +3657,22 @@ pub fn deleteDecl(mod: *Module, decl: *Decl) !void {
3526 // We don't recursively perform a deletion here, because during the update,3657 // We don't recursively perform a deletion here, because during the update,
3527 // another reference to it may turn up.3658 // another reference to it may turn up.
3528 dep.deletion_flag = true;3659 dep.deletion_flag = true;
3529 mod.deletion_set.appendAssumeCapacity(dep);3660 mod.deletion_set.putAssumeCapacity(dep, {});
3530 }3661 }
3531 }3662 }
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.
3533 for (decl.dependants.items()) |entry| {3664 for (decl.dependants.items()) |entry| {
3534 const dep = entry.key;3665 const dep = entry.key;
3535 dep.removeDependency(decl);3666 dep.removeDependency(decl);
3536 if (dep.analysis != .outdated) {3667 if (outdated_decls) |map| {
3537 // TODO Move this failure possibility to the top of the function.3668 map.putAssumeCapacity(dep, {});
3538 try mod.markOutdatedDecl(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));
3539 }3676 }
3540 }3677 }
3541 if (mod.failed_decls.swapRemove(decl)) |entry| {3678 if (mod.failed_decls.swapRemove(decl)) |entry| {
...@@ -4455,7 +4592,29 @@ pub fn identifierTokenString(mod: *Module, scope: *Scope, token: ast.TokenIndex)...@@ -4455,7 +4592,29 @@ pub fn identifierTokenString(mod: *Module, scope: *Scope, token: ast.TokenIndex)
4455 var buf: ArrayListUnmanaged(u8) = .{};4592 var buf: ArrayListUnmanaged(u8) = .{};
4456 defer buf.deinit(mod.gpa);4593 defer buf.deinit(mod.gpa);
4457 try parseStrLit(mod, scope, token, &buf, ident_name, 1);4594 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);
4459}4618}
44604619
4461/// Given an identifier token, obtain the string for it (possibly parsing as a string4620/// Given an identifier token, obtain the string for it (possibly parsing as a string
...@@ -4545,3 +4704,10 @@ pub fn parseStrLit(...@@ -4545,3 +4704,10 @@ pub fn parseStrLit(
4545 },4704 },
4546 }4705 }
4547}4706}
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(...@@ -168,7 +168,6 @@ pub fn analyzeBody(
168 .cmp_lte => try sema.zirCmp(block, inst, .lte),168 .cmp_lte => try sema.zirCmp(block, inst, .lte),
169 .cmp_neq => try sema.zirCmp(block, inst, .neq),169 .cmp_neq => try sema.zirCmp(block, inst, .neq),
170 .coerce_result_ptr => try sema.zirCoerceResultPtr(block, inst),170 .coerce_result_ptr => try sema.zirCoerceResultPtr(block, inst),
171 .@"const" => try sema.zirConst(block, inst),
172 .decl_ref => try sema.zirDeclRef(block, inst),171 .decl_ref => try sema.zirDeclRef(block, inst),
173 .decl_val => try sema.zirDeclVal(block, inst),172 .decl_val => try sema.zirDeclVal(block, inst),
174 .load => try sema.zirLoad(block, inst),173 .load => try sema.zirLoad(block, inst),
...@@ -179,6 +178,8 @@ pub fn analyzeBody(...@@ -179,6 +178,8 @@ pub fn analyzeBody(
179 .elem_val_node => try sema.zirElemValNode(block, inst),178 .elem_val_node => try sema.zirElemValNode(block, inst),
180 .enum_literal => try sema.zirEnumLiteral(block, inst),179 .enum_literal => try sema.zirEnumLiteral(block, inst),
181 .enum_literal_small => try sema.zirEnumLiteralSmall(block, inst),180 .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),
182 .err_union_code => try sema.zirErrUnionCode(block, inst),183 .err_union_code => try sema.zirErrUnionCode(block, inst),
183 .err_union_code_ptr => try sema.zirErrUnionCodePtr(block, inst),184 .err_union_code_ptr => try sema.zirErrUnionCodePtr(block, inst),
184 .err_union_payload_safe => try sema.zirErrUnionPayload(block, inst, true),185 .err_union_payload_safe => try sema.zirErrUnionPayload(block, inst, true),
...@@ -201,6 +202,8 @@ pub fn analyzeBody(...@@ -201,6 +202,8 @@ pub fn analyzeBody(
201 .import => try sema.zirImport(block, inst),202 .import => try sema.zirImport(block, inst),
202 .indexable_ptr_len => try sema.zirIndexablePtrLen(block, inst),203 .indexable_ptr_len => try sema.zirIndexablePtrLen(block, inst),
203 .int => try sema.zirInt(block, inst),204 .int => try sema.zirInt(block, inst),
205 .float => try sema.zirFloat(block, inst),
206 .float128 => try sema.zirFloat128(block, inst),
204 .int_type => try sema.zirIntType(block, inst),207 .int_type => try sema.zirIntType(block, inst),
205 .intcast => try sema.zirIntcast(block, inst),208 .intcast => try sema.zirIntcast(block, inst),
206 .is_err => try sema.zirIsErr(block, inst),209 .is_err => try sema.zirIsErr(block, inst),
...@@ -264,7 +267,8 @@ pub fn analyzeBody(...@@ -264,7 +267,8 @@ pub fn analyzeBody(
264 .struct_decl => try sema.zirStructDecl(block, inst, .Auto),267 .struct_decl => try sema.zirStructDecl(block, inst, .Auto),
265 .struct_decl_packed => try sema.zirStructDecl(block, inst, .Packed),268 .struct_decl_packed => try sema.zirStructDecl(block, inst, .Packed),
266 .struct_decl_extern => try sema.zirStructDecl(block, inst, .Extern),269 .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),
268 .union_decl => try sema.zirUnionDecl(block, inst),272 .union_decl => try sema.zirUnionDecl(block, inst),
269 .opaque_decl => try sema.zirOpaqueDecl(block, inst),273 .opaque_decl => try sema.zirOpaqueDecl(block, inst),
270274
...@@ -498,18 +502,6 @@ fn resolveInstConst(...@@ -498,18 +502,6 @@ fn resolveInstConst(
498 };502 };
499}503}
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
513fn zirBitcastResultPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {505fn zirBitcastResultPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
514 const tracy = trace(@src());506 const tracy = trace(@src());
515 defer tracy.end();507 defer tracy.end();
...@@ -617,7 +609,12 @@ fn zirStructDecl(...@@ -617,7 +609,12 @@ fn zirStructDecl(
617 return sema.analyzeDeclVal(block, src, new_decl);609 return sema.analyzeDeclVal(block, src, new_decl);
618}610}
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 {
621 const tracy = trace(@src());618 const tracy = trace(@src());
622 defer tracy.end();619 defer tracy.end();
623620
...@@ -788,8 +785,8 @@ fn zirAllocInferred(...@@ -788,8 +785,8 @@ fn zirAllocInferred(
788 const tracy = trace(@src());785 const tracy = trace(@src());
789 defer tracy.end();786 defer tracy.end();
790787
791 const inst_data = sema.code.instructions.items(.data)[inst].un_node;788 const src_node = sema.code.instructions.items(.data)[inst].node;
792 const src = inst_data.src();789 const src: LazySrcLoc = .{ .node_offset = src_node };
793790
794 const val_payload = try sema.arena.create(Value.Payload.InferredAlloc);791 const val_payload = try sema.arena.create(Value.Payload.InferredAlloc);
795 val_payload.* = .{792 val_payload.* = .{
...@@ -900,7 +897,7 @@ fn zirValidateStructInitPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Ind...@@ -900,7 +897,7 @@ fn zirValidateStructInitPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Ind
900 try mod.errNoteNonLazy(897 try mod.errNoteNonLazy(
901 struct_obj.srcLoc(),898 struct_obj.srcLoc(),
902 msg,899 msg,
903 "'{s}' declared here",900 "struct '{s}' declared here",
904 .{fqn},901 .{fqn},
905 );902 );
906 return mod.failWithOwnedErrorMsg(&block.base, msg);903 return mod.failWithOwnedErrorMsg(&block.base, msg);
...@@ -928,7 +925,7 @@ fn failWithBadFieldAccess(...@@ -928,7 +925,7 @@ fn failWithBadFieldAccess(
928 .{ field_name, fqn },925 .{ field_name, fqn },
929 );926 );
930 errdefer msg.destroy(gpa);927 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", .{});
932 break :msg msg;929 break :msg msg;
933 };930 };
934 return mod.failWithOwnedErrorMsg(&block.base, msg);931 return mod.failWithOwnedErrorMsg(&block.base, msg);
...@@ -1070,6 +1067,31 @@ fn zirInt(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*In...@@ -1070,6 +1067,31 @@ fn zirInt(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*In
1070 return sema.mod.constIntUnsigned(sema.arena, .unneeded, Type.initTag(.comptime_int), int);1067 return sema.mod.constIntUnsigned(sema.arena, .unneeded, Type.initTag(.comptime_int), int);
1071}1068}
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
1073fn zirCompileError(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!zir.Inst.Index {1095fn zirCompileError(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!zir.Inst.Index {
1074 const tracy = trace(@src());1096 const tracy = trace(@src());
1075 defer tracy.end();1097 defer tracy.end();
...@@ -1385,7 +1407,7 @@ fn zirDeclRef(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError...@@ -1385,7 +1407,7 @@ fn zirDeclRef(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError
13851407
1386 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;1408 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1387 const src = inst_data.src();1409 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;
1389 return sema.analyzeDeclRef(block, src, decl);1411 return sema.analyzeDeclRef(block, src, decl);
1390}1412}
13911413
...@@ -1395,7 +1417,7 @@ fn zirDeclVal(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError...@@ -1395,7 +1417,7 @@ fn zirDeclVal(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError
13951417
1396 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;1418 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1397 const src = inst_data.src();1419 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;
1399 return sema.analyzeDeclVal(block, src, decl);1421 return sema.analyzeDeclVal(block, src, decl);
1400}1422}
14011423
...@@ -1852,6 +1874,143 @@ fn zirEnumLiteralSmall(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) I...@@ -1852,6 +1874,143 @@ fn zirEnumLiteralSmall(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) I
1852 });1874 });
1853}1875}
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
1855/// Pointer in, pointer out.2014/// Pointer in, pointer out.
1856fn zirOptionalPayloadPtr(2015fn zirOptionalPayloadPtr(
1857 sema: *Sema,2016 sema: *Sema,
...@@ -2584,6 +2743,8 @@ fn analyzeSwitch(...@@ -2584,6 +2743,8 @@ fn analyzeSwitch(
2584 src_node_offset: i32,2743 src_node_offset: i32,
2585) InnerError!*Inst {2744) InnerError!*Inst {
2586 const gpa = sema.gpa;2745 const gpa = sema.gpa;
2746 const mod = sema.mod;
2747
2587 const special: struct { body: []const zir.Inst.Index, end: usize } = switch (special_prong) {2748 const special: struct { body: []const zir.Inst.Index, end: usize } = switch (special_prong) {
2588 .none => .{ .body = &.{}, .end = extra_end },2749 .none => .{ .body = &.{}, .end = extra_end },
2589 .under, .@"else" => blk: {2750 .under, .@"else" => blk: {
...@@ -2601,16 +2762,16 @@ fn analyzeSwitch(...@@ -2601,16 +2762,16 @@ fn analyzeSwitch(
2601 const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = src_node_offset };2762 const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = src_node_offset };
26022763
2603 // Validate usage of '_' prongs.2764 // Validate usage of '_' prongs.
2604 if (special_prong == .under and !operand.ty.isExhaustiveEnum()) {2765 if (special_prong == .under and !operand.ty.isNonexhaustiveEnum()) {
2605 const msg = msg: {2766 const msg = msg: {
2606 const msg = try sema.mod.errMsg(2767 const msg = try mod.errMsg(
2607 &block.base,2768 &block.base,
2608 src,2769 src,
2609 "'_' prong only allowed when switching on non-exhaustive enums",2770 "'_' prong only allowed when switching on non-exhaustive enums",
2610 .{},2771 .{},
2611 );2772 );
2612 errdefer msg.destroy(gpa);2773 errdefer msg.destroy(gpa);
2613 try sema.mod.errNote(2774 try mod.errNote(
2614 &block.base,2775 &block.base,
2615 special_prong_src,2776 special_prong_src,
2616 msg,2777 msg,
...@@ -2619,14 +2780,123 @@ fn analyzeSwitch(...@@ -2619,14 +2780,123 @@ fn analyzeSwitch(
2619 );2780 );
2620 break :msg msg;2781 break :msg msg;
2621 };2782 };
2622 return sema.mod.failWithOwnedErrorMsg(&block.base, msg);2783 return mod.failWithOwnedErrorMsg(&block.base, msg);
2623 }2784 }
26242785
2625 // Validate for duplicate items, missing else prong, and invalid range.2786 // Validate for duplicate items, missing else prong, and invalid range.
2626 switch (operand.ty.zigTypeTag()) {2787 switch (operand.ty.zigTypeTag()) {
2627 .Enum => return sema.mod.fail(&block.base, src, "TODO validate switch .Enum", .{}),2788 .Enum => {
2628 .ErrorSet => return sema.mod.fail(&block.base, src, "TODO validate switch .ErrorSet", .{}),2789 var seen_fields = try gpa.alloc(?AstGen.SwitchProngSrc, operand.ty.enumFieldCount());
2629 .Union => return sema.mod.fail(&block.base, src, "TODO validate switch .Union", .{}),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", .{}),
2630 .Int, .ComptimeInt => {2900 .Int, .ComptimeInt => {
2631 var range_set = RangeSet.init(gpa);2901 var range_set = RangeSet.init(gpa);
2632 defer range_set.deinit();2902 defer range_set.deinit();
...@@ -2699,11 +2969,11 @@ fn analyzeSwitch(...@@ -2699,11 +2969,11 @@ fn analyzeSwitch(
2699 var arena = std.heap.ArenaAllocator.init(gpa);2969 var arena = std.heap.ArenaAllocator.init(gpa);
2700 defer arena.deinit();2970 defer arena.deinit();
27012971
2702 const min_int = try operand.ty.minInt(&arena, sema.mod.getTarget());2972 const min_int = try operand.ty.minInt(&arena, mod.getTarget());
2703 const max_int = try operand.ty.maxInt(&arena, sema.mod.getTarget());2973 const max_int = try operand.ty.maxInt(&arena, mod.getTarget());
2704 if (try range_set.spans(min_int, max_int)) {2974 if (try range_set.spans(min_int, max_int)) {
2705 if (special_prong == .@"else") {2975 if (special_prong == .@"else") {
2706 return sema.mod.fail(2976 return mod.fail(
2707 &block.base,2977 &block.base,
2708 special_prong_src,2978 special_prong_src,
2709 "unreachable else prong; all cases already handled",2979 "unreachable else prong; all cases already handled",
...@@ -2714,7 +2984,7 @@ fn analyzeSwitch(...@@ -2714,7 +2984,7 @@ fn analyzeSwitch(
2714 }2984 }
2715 }2985 }
2716 if (special_prong != .@"else") {2986 if (special_prong != .@"else") {
2717 return sema.mod.fail(2987 return mod.fail(
2718 &block.base,2988 &block.base,
2719 src,2989 src,
2720 "switch must handle all possibilities",2990 "switch must handle all possibilities",
...@@ -2777,7 +3047,7 @@ fn analyzeSwitch(...@@ -2777,7 +3047,7 @@ fn analyzeSwitch(
2777 switch (special_prong) {3047 switch (special_prong) {
2778 .@"else" => {3048 .@"else" => {
2779 if (true_count + false_count == 2) {3049 if (true_count + false_count == 2) {
2780 return sema.mod.fail(3050 return mod.fail(
2781 &block.base,3051 &block.base,
2782 src,3052 src,
2783 "unreachable else prong; all cases already handled",3053 "unreachable else prong; all cases already handled",
...@@ -2787,7 +3057,7 @@ fn analyzeSwitch(...@@ -2787,7 +3057,7 @@ fn analyzeSwitch(
2787 },3057 },
2788 .under, .none => {3058 .under, .none => {
2789 if (true_count + false_count < 2) {3059 if (true_count + false_count < 2) {
2790 return sema.mod.fail(3060 return mod.fail(
2791 &block.base,3061 &block.base,
2792 src,3062 src,
2793 "switch must handle all possibilities",3063 "switch must handle all possibilities",
...@@ -2799,7 +3069,7 @@ fn analyzeSwitch(...@@ -2799,7 +3069,7 @@ fn analyzeSwitch(
2799 },3069 },
2800 .EnumLiteral, .Void, .Fn, .Pointer, .Type => {3070 .EnumLiteral, .Void, .Fn, .Pointer, .Type => {
2801 if (special_prong != .@"else") {3071 if (special_prong != .@"else") {
2802 return sema.mod.fail(3072 return mod.fail(
2803 &block.base,3073 &block.base,
2804 src,3074 src,
2805 "else prong required when switching on type '{}'",3075 "else prong required when switching on type '{}'",
...@@ -2871,7 +3141,7 @@ fn analyzeSwitch(...@@ -2871,7 +3141,7 @@ fn analyzeSwitch(
2871 .AnyFrame,3141 .AnyFrame,
2872 .ComptimeFloat,3142 .ComptimeFloat,
2873 .Float,3143 .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 '{}'", .{
2875 operand.ty,3145 operand.ty,
2876 }),3146 }),
2877 }3147 }
...@@ -3146,7 +3416,7 @@ fn resolveSwitchItemVal(...@@ -3146,7 +3416,7 @@ fn resolveSwitchItemVal(
3146 switch_node_offset: i32,3416 switch_node_offset: i32,
3147 switch_prong_src: AstGen.SwitchProngSrc,3417 switch_prong_src: AstGen.SwitchProngSrc,
3148 range_expand: AstGen.SwitchProngSrc.RangeExpand,3418 range_expand: AstGen.SwitchProngSrc.RangeExpand,
3149) InnerError!Value {3419) InnerError!TypedValue {
3150 const item = try sema.resolveInst(item_ref);3420 const item = try sema.resolveInst(item_ref);
3151 // We have to avoid the other helper functions here because we cannot construct a LazySrcLoc3421 // We have to avoid the other helper functions here because we cannot construct a LazySrcLoc
3152 // because we only have the switch AST node. Only if we know for sure we need to report3422 // because we only have the switch AST node. Only if we know for sure we need to report
...@@ -3156,7 +3426,7 @@ fn resolveSwitchItemVal(...@@ -3156,7 +3426,7 @@ fn resolveSwitchItemVal(
3156 const src = switch_prong_src.resolve(block.src_decl, switch_node_offset, range_expand);3426 const src = switch_prong_src.resolve(block.src_decl, switch_node_offset, range_expand);
3157 return sema.failWithUseOfUndef(block, src);3427 return sema.failWithUseOfUndef(block, src);
3158 }3428 }
3159 return val;3429 return TypedValue{ .ty = item.ty, .val = val };
3160 }3430 }
3161 const src = switch_prong_src.resolve(block.src_decl, switch_node_offset, range_expand);3431 const src = switch_prong_src.resolve(block.src_decl, switch_node_offset, range_expand);
3162 return sema.failWithNeededComptime(block, src);3432 return sema.failWithNeededComptime(block, src);
...@@ -3171,8 +3441,8 @@ fn validateSwitchRange(...@@ -3171,8 +3441,8 @@ fn validateSwitchRange(
3171 src_node_offset: i32,3441 src_node_offset: i32,
3172 switch_prong_src: AstGen.SwitchProngSrc,3442 switch_prong_src: AstGen.SwitchProngSrc,
3173) InnerError!void {3443) InnerError!void {
3174 const first_val = try sema.resolveSwitchItemVal(block, first_ref, src_node_offset, switch_prong_src, .first);3444 const first_val = (try sema.resolveSwitchItemVal(block, first_ref, src_node_offset, switch_prong_src, .first)).val;
3175 const last_val = try sema.resolveSwitchItemVal(block, last_ref, src_node_offset, switch_prong_src, .last);3445 const last_val = (try sema.resolveSwitchItemVal(block, last_ref, src_node_offset, switch_prong_src, .last)).val;
3176 const maybe_prev_src = try range_set.add(first_val, last_val, switch_prong_src);3446 const maybe_prev_src = try range_set.add(first_val, last_val, switch_prong_src);
3177 return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);3447 return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
3178}3448}
...@@ -3185,11 +3455,46 @@ fn validateSwitchItem(...@@ -3185,11 +3455,46 @@ fn validateSwitchItem(
3185 src_node_offset: i32,3455 src_node_offset: i32,
3186 switch_prong_src: AstGen.SwitchProngSrc,3456 switch_prong_src: AstGen.SwitchProngSrc,
3187) InnerError!void {3457) 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;
3189 const maybe_prev_src = try range_set.add(item_val, item_val, switch_prong_src);3459 const maybe_prev_src = try range_set.add(item_val, item_val, switch_prong_src);
3190 return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);3460 return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
3191}3461}
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
3193fn validateSwitchDupe(3498fn validateSwitchDupe(
3194 sema: *Sema,3499 sema: *Sema,
3195 block: *Scope.Block,3500 block: *Scope.Block,
...@@ -3198,17 +3503,18 @@ fn validateSwitchDupe(...@@ -3198,17 +3503,18 @@ fn validateSwitchDupe(
3198 src_node_offset: i32,3503 src_node_offset: i32,
3199) InnerError!void {3504) InnerError!void {
3200 const prev_prong_src = maybe_prev_src orelse return;3505 const prev_prong_src = maybe_prev_src orelse return;
3506 const mod = sema.mod;
3201 const src = switch_prong_src.resolve(block.src_decl, src_node_offset, .none);3507 const src = switch_prong_src.resolve(block.src_decl, src_node_offset, .none);
3202 const prev_src = prev_prong_src.resolve(block.src_decl, src_node_offset, .none);3508 const prev_src = prev_prong_src.resolve(block.src_decl, src_node_offset, .none);
3203 const msg = msg: {3509 const msg = msg: {
3204 const msg = try sema.mod.errMsg(3510 const msg = try mod.errMsg(
3205 &block.base,3511 &block.base,
3206 src,3512 src,
3207 "duplicate switch value",3513 "duplicate switch value",
3208 .{},3514 .{},
3209 );3515 );
3210 errdefer msg.destroy(sema.gpa);3516 errdefer msg.destroy(sema.gpa);
3211 try sema.mod.errNote(3517 try mod.errNote(
3212 &block.base,3518 &block.base,
3213 prev_src,3519 prev_src,
3214 msg,3520 msg,
...@@ -3217,7 +3523,7 @@ fn validateSwitchDupe(...@@ -3217,7 +3523,7 @@ fn validateSwitchDupe(
3217 );3523 );
3218 break :msg msg;3524 break :msg msg;
3219 };3525 };
3220 return sema.mod.failWithOwnedErrorMsg(&block.base, msg);3526 return mod.failWithOwnedErrorMsg(&block.base, msg);
3221}3527}
32223528
3223fn validateSwitchItemBool(3529fn validateSwitchItemBool(
...@@ -3229,7 +3535,7 @@ fn validateSwitchItemBool(...@@ -3229,7 +3535,7 @@ fn validateSwitchItemBool(
3229 src_node_offset: i32,3535 src_node_offset: i32,
3230 switch_prong_src: AstGen.SwitchProngSrc,3536 switch_prong_src: AstGen.SwitchProngSrc,
3231) InnerError!void {3537) 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;
3233 if (item_val.toBool()) {3539 if (item_val.toBool()) {
3234 true_count.* += 1;3540 true_count.* += 1;
3235 } else {3541 } else {
...@@ -3251,7 +3557,7 @@ fn validateSwitchItemSparse(...@@ -3251,7 +3557,7 @@ fn validateSwitchItemSparse(
3251 src_node_offset: i32,3557 src_node_offset: i32,
3252 switch_prong_src: AstGen.SwitchProngSrc,3558 switch_prong_src: AstGen.SwitchProngSrc,
3253) InnerError!void {3559) 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;
3255 const entry = (try seen_values.fetchPut(item_val, switch_prong_src)) orelse return;3561 const entry = (try seen_values.fetchPut(item_val, switch_prong_src)) orelse return;
3256 return sema.validateSwitchDupe(block, entry.value, switch_prong_src, src_node_offset);3562 return sema.validateSwitchDupe(block, entry.value, switch_prong_src, src_node_offset);
3257}3563}
...@@ -3631,9 +3937,13 @@ fn zirCmp(...@@ -3631,9 +3937,13 @@ fn zirCmp(
3631 const tracy = trace(@src());3937 const tracy = trace(@src());
3632 defer tracy.end();3938 defer tracy.end();
36333939
3940 const mod = sema.mod;
3941
3634 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;3942 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
3635 const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data;3943 const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data;
3636 const src: LazySrcLoc = inst_data.src();3944 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 };
3637 const lhs = try sema.resolveInst(extra.lhs);3947 const lhs = try sema.resolveInst(extra.lhs);
3638 const rhs = try sema.resolveInst(extra.rhs);3948 const rhs = try sema.resolveInst(extra.rhs);
36393949
...@@ -3645,7 +3955,7 @@ fn zirCmp(...@@ -3645,7 +3955,7 @@ fn zirCmp(
3645 const rhs_ty_tag = rhs.ty.zigTypeTag();3955 const rhs_ty_tag = rhs.ty.zigTypeTag();
3646 if (is_equality_cmp and lhs_ty_tag == .Null and rhs_ty_tag == .Null) {3956 if (is_equality_cmp and lhs_ty_tag == .Null and rhs_ty_tag == .Null) {
3647 // null == null, null != null3957 // null == null, null != null
3648 return sema.mod.constBool(sema.arena, src, op == .eq);3958 return mod.constBool(sema.arena, src, op == .eq);
3649 } else if (is_equality_cmp and3959 } else if (is_equality_cmp and
3650 ((lhs_ty_tag == .Null and rhs_ty_tag == .Optional) or3960 ((lhs_ty_tag == .Null and rhs_ty_tag == .Optional) or
3651 rhs_ty_tag == .Null and lhs_ty_tag == .Optional))3961 rhs_ty_tag == .Null and lhs_ty_tag == .Optional))
...@@ -3656,23 +3966,23 @@ fn zirCmp(...@@ -3656,23 +3966,23 @@ fn zirCmp(
3656 } else if (is_equality_cmp and3966 } else if (is_equality_cmp and
3657 ((lhs_ty_tag == .Null and rhs.ty.isCPtr()) or (rhs_ty_tag == .Null and lhs.ty.isCPtr())))3967 ((lhs_ty_tag == .Null and rhs.ty.isCPtr()) or (rhs_ty_tag == .Null and lhs.ty.isCPtr())))
3658 {3968 {
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", .{});
3660 } else if (lhs_ty_tag == .Null or rhs_ty_tag == .Null) {3970 } else if (lhs_ty_tag == .Null or rhs_ty_tag == .Null) {
3661 const non_null_type = if (lhs_ty_tag == .Null) rhs.ty else lhs.ty;3971 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});
3663 } else if (is_equality_cmp and3973 } else if (is_equality_cmp and
3664 ((lhs_ty_tag == .EnumLiteral and rhs_ty_tag == .Union) or3974 ((lhs_ty_tag == .EnumLiteral and rhs_ty_tag == .Union) or
3665 (rhs_ty_tag == .EnumLiteral and lhs_ty_tag == .Union)))3975 (rhs_ty_tag == .EnumLiteral and lhs_ty_tag == .Union)))
3666 {3976 {
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", .{});
3668 } else if (lhs_ty_tag == .ErrorSet and rhs_ty_tag == .ErrorSet) {3978 } else if (lhs_ty_tag == .ErrorSet and rhs_ty_tag == .ErrorSet) {
3669 if (!is_equality_cmp) {3979 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)});
3671 }3981 }
3672 if (rhs.value()) |rval| {3982 if (rhs.value()) |rval| {
3673 if (lhs.value()) |lval| {3983 if (lhs.value()) |lval| {
3674 // 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 faster3984 // 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));
3676 }3986 }
3677 }3987 }
3678 try sema.requireRuntimeBlock(block, src);3988 try sema.requireRuntimeBlock(block, src);
...@@ -3684,11 +3994,30 @@ fn zirCmp(...@@ -3684,11 +3994,30 @@ fn zirCmp(
3684 return sema.cmpNumeric(block, src, lhs, rhs, op);3994 return sema.cmpNumeric(block, src, lhs, rhs, op);
3685 } else if (lhs_ty_tag == .Type and rhs_ty_tag == .Type) {3995 } else if (lhs_ty_tag == .Type and rhs_ty_tag == .Type) {
3686 if (!is_equality_cmp) {3996 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)});
3688 }3998 }
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});
3690 }4006 }
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);
3692}4021}
36934022
3694fn zirTypeof(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {4023fn zirTypeof(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
...@@ -4215,22 +4544,25 @@ fn namedFieldPtr(...@@ -4215,22 +4544,25 @@ fn namedFieldPtr(
4215 field_name: []const u8,4544 field_name: []const u8,
4216 field_name_src: LazySrcLoc,4545 field_name_src: LazySrcLoc,
4217) InnerError!*Inst {4546) InnerError!*Inst {
4547 const mod = sema.mod;
4548 const arena = sema.arena;
4549
4218 const elem_ty = switch (object_ptr.ty.zigTypeTag()) {4550 const elem_ty = switch (object_ptr.ty.zigTypeTag()) {
4219 .Pointer => object_ptr.ty.elemType(),4551 .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}),
4221 };4553 };
4222 switch (elem_ty.zigTypeTag()) {4554 switch (elem_ty.zigTypeTag()) {
4223 .Array => {4555 .Array => {
4224 if (mem.eql(u8, field_name, "len")) {4556 if (mem.eql(u8, field_name, "len")) {
4225 return sema.mod.constInst(sema.arena, src, .{4557 return mod.constInst(arena, src, .{
4226 .ty = Type.initTag(.single_const_pointer_to_comptime_int),4558 .ty = Type.initTag(.single_const_pointer_to_comptime_int),
4227 .val = try Value.Tag.ref_val.create(4559 .val = try Value.Tag.ref_val.create(
4228 sema.arena,4560 arena,
4229 try Value.Tag.int_u64.create(sema.arena, elem_ty.arrayLen()),4561 try Value.Tag.int_u64.create(arena, elem_ty.arrayLen()),
4230 ),4562 ),
4231 });4563 });
4232 } else {4564 } else {
4233 return sema.mod.fail(4565 return mod.fail(
4234 &block.base,4566 &block.base,
4235 field_name_src,4567 field_name_src,
4236 "no member named '{s}' in '{}'",4568 "no member named '{s}' in '{}'",
...@@ -4243,15 +4575,15 @@ fn namedFieldPtr(...@@ -4243,15 +4575,15 @@ fn namedFieldPtr(
4243 switch (ptr_child.zigTypeTag()) {4575 switch (ptr_child.zigTypeTag()) {
4244 .Array => {4576 .Array => {
4245 if (mem.eql(u8, field_name, "len")) {4577 if (mem.eql(u8, field_name, "len")) {
4246 return sema.mod.constInst(sema.arena, src, .{4578 return mod.constInst(arena, src, .{
4247 .ty = Type.initTag(.single_const_pointer_to_comptime_int),4579 .ty = Type.initTag(.single_const_pointer_to_comptime_int),
4248 .val = try Value.Tag.ref_val.create(4580 .val = try Value.Tag.ref_val.create(
4249 sema.arena,4581 arena,
4250 try Value.Tag.int_u64.create(sema.arena, ptr_child.arrayLen()),4582 try Value.Tag.int_u64.create(arena, ptr_child.arrayLen()),
4251 ),4583 ),
4252 });4584 });
4253 } else {4585 } else {
4254 return sema.mod.fail(4586 return mod.fail(
4255 &block.base,4587 &block.base,
4256 field_name_src,4588 field_name_src,
4257 "no member named '{s}' in '{}'",4589 "no member named '{s}' in '{}'",
...@@ -4266,7 +4598,7 @@ fn namedFieldPtr(...@@ -4266,7 +4598,7 @@ fn namedFieldPtr(
4266 _ = try sema.resolveConstValue(block, object_ptr.src, object_ptr);4598 _ = try sema.resolveConstValue(block, object_ptr.src, object_ptr);
4267 const result = try sema.analyzeLoad(block, src, object_ptr, object_ptr.src);4599 const result = try sema.analyzeLoad(block, src, object_ptr, object_ptr.src);
4268 const val = result.value().?;4600 const val = result.value().?;
4269 const child_type = try val.toType(sema.arena);4601 const child_type = try val.toType(arena);
4270 switch (child_type.zigTypeTag()) {4602 switch (child_type.zigTypeTag()) {
4271 .ErrorSet => {4603 .ErrorSet => {
4272 // TODO resolve inferred error sets4604 // TODO resolve inferred error sets
...@@ -4280,42 +4612,90 @@ fn namedFieldPtr(...@@ -4280,42 +4612,90 @@ fn namedFieldPtr(
4280 break :blk name;4612 break :blk name;
4281 }4613 }
4282 }4614 }
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 '{}'", .{
4284 field_name,4616 field_name,
4285 child_type,4617 child_type,
4286 });4618 });
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, .{4621 return mod.constInst(arena, src, .{
4290 .ty = try sema.mod.simplePtrType(sema.arena, child_type, false, .One),4622 .ty = try mod.simplePtrType(arena, child_type, false, .One),
4291 .val = try Value.Tag.ref_val.create(4623 .val = try Value.Tag.ref_val.create(
4292 sema.arena,4624 arena,
4293 try Value.Tag.@"error".create(sema.arena, .{4625 try Value.Tag.@"error".create(arena, .{
4294 .name = name,4626 .name = name,
4295 }),4627 }),
4296 ),4628 ),
4297 });4629 });
4298 },4630 },
4299 .Struct => {4631 .Struct, .Opaque, .Union => {
4300 const container_scope = child_type.getContainerScope();4632 if (child_type.getContainerScope()) |container_scope| {
4301 if (sema.mod.lookupDeclName(&container_scope.base, field_name)) |decl| {4633 if (mod.lookupDeclName(&container_scope.base, field_name)) |decl| {
4302 // TODO if !decl.is_pub and inDifferentFiles() "{} is private"4634 // TODO if !decl.is_pub and inDifferentFiles() "{} is private"
4303 return sema.analyzeDeclRef(block, src, decl);4635 return sema.analyzeDeclRef(block, src, decl);
4304 }4636 }
43054637
4306 if (container_scope.file_scope == sema.mod.root_scope) {4638 // TODO this will give false positives for structs inside the root file
4307 return sema.mod.fail(&block.base, src, "root source file has no member called '{s}'", .{field_name});4639 if (container_scope.file_scope == mod.root_scope) {
4308 } else {4640 return mod.fail(
4309 return sema.mod.fail(&block.base, src, "container '{}' has no member called '{s}'", .{ child_type, field_name });4641 &block.base,
4642 src,
4643 "root source file has no member named '{s}'",
4644 .{field_name},
4645 );
4646 }
4310 }4647 }
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 });
4311 },4658 },
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}),
4313 }4693 }
4314 },4694 },
4315 .Struct => return sema.analyzeStructFieldPtr(block, src, object_ptr, field_name, field_name_src, elem_ty),4695 .Struct => return sema.analyzeStructFieldPtr(block, src, object_ptr, field_name, field_name_src, elem_ty),
4316 else => {},4696 else => {},
4317 }4697 }
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});
4319}4699}
43204700
4321fn analyzeStructFieldPtr(4701fn analyzeStructFieldPtr(
...@@ -4400,10 +4780,13 @@ fn coerce(...@@ -4400,10 +4780,13 @@ fn coerce(
4400 return sema.bitcast(block, dest_type, inst);4780 return sema.bitcast(block, dest_type, inst);
4401 }4781 }
44024782
4783 const mod = sema.mod;
4784 const arena = sema.arena;
4785
4403 // undefined to anything4786 // undefined to anything
4404 if (inst.value()) |val| {4787 if (inst.value()) |val| {
4405 if (val.isUndef() or inst.ty.zigTypeTag() == .Undefined) {4788 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 });
4407 }4790 }
4408 }4791 }
4409 assert(inst.ty.zigTypeTag() != .Undefined);4792 assert(inst.ty.zigTypeTag() != .Undefined);
...@@ -4417,13 +4800,13 @@ fn coerce(...@@ -4417,13 +4800,13 @@ fn coerce(
4417 if (try sema.coerceNum(block, dest_type, inst)) |some|4800 if (try sema.coerceNum(block, dest_type, inst)) |some|
4418 return some;4801 return some;
44194802
4420 const target = sema.mod.getTarget();4803 const target = mod.getTarget();
44214804
4422 switch (dest_type.zigTypeTag()) {4805 switch (dest_type.zigTypeTag()) {
4423 .Optional => {4806 .Optional => {
4424 // null to ?T4807 // null to ?T
4425 if (inst.ty.zigTypeTag() == .Null) {4808 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) });
4427 }4810 }
44284811
4429 // T to ?T4812 // T to ?T
...@@ -4509,10 +4892,40 @@ fn coerce(...@@ -4509,10 +4892,40 @@ fn coerce(
4509 }4892 }
4510 }4893 }
4511 },4894 },
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 },
4512 else => {},4925 else => {},
4513 }4926 }
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 });
4516}4929}
45174930
4518const InMemoryCoercionResult = enum {4931const InMemoryCoercionResult = enum {
...@@ -4630,7 +5043,7 @@ fn analyzeDeclVal(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, decl: *Decl...@@ -4630,7 +5043,7 @@ fn analyzeDeclVal(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, decl: *Decl
4630}5043}
46315044
4632fn analyzeDeclRef(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, decl: *Decl) InnerError!*Inst {5045fn 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);
4634 sema.mod.ensureDeclAnalyzed(decl) catch |err| {5047 sema.mod.ensureDeclAnalyzed(decl) catch |err| {
4635 if (sema.func) |func| {5048 if (sema.func) |func| {
4636 func.state = .dependency_failure;5049 func.state = .dependency_failure;
src/codegen/c.zig+55-5
...@@ -172,7 +172,10 @@ pub const DeclGen = struct {...@@ -172,7 +172,10 @@ pub const DeclGen = struct {
172 val: Value,172 val: Value,
173 ) error{ OutOfMemory, AnalysisFail }!void {173 ) error{ OutOfMemory, AnalysisFail }!void {
174 if (val.isUndef()) {174 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", .{});
176 }179 }
177 switch (t.zigTypeTag()) {180 switch (t.zigTypeTag()) {
178 .Int => {181 .Int => {
...@@ -288,6 +291,31 @@ pub const DeclGen = struct {...@@ -288,6 +291,31 @@ pub const DeclGen = struct {
288 try writer.writeAll(", .error = 0 }");291 try writer.writeAll(", .error = 0 }");
289 }292 }
290 },293 },
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 },
291 else => |e| return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement value {s}", .{319 else => |e| return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement value {s}", .{
292 @tagName(e),320 @tagName(e),
293 }),321 }),
...@@ -368,6 +396,9 @@ pub const DeclGen = struct {...@@ -368,6 +396,9 @@ pub const DeclGen = struct {
368 else => unreachable,396 else => unreachable,
369 }397 }
370 },398 },
399
400 .Float => return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement type Float", .{}),
401
371 .Pointer => {402 .Pointer => {
372 if (t.isSlice()) {403 if (t.isSlice()) {
373 return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement slices", .{});404 return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement slices", .{});
...@@ -472,10 +503,29 @@ pub const DeclGen = struct {...@@ -472,10 +503,29 @@ pub const DeclGen = struct {
472 try w.writeAll(name);503 try w.writeAll(name);
473 dg.typedefs.putAssumeCapacityNoClobber(t, .{ .name = name, .rendered = rendered });504 dg.typedefs.putAssumeCapacityNoClobber(t, .{ .name = name, .rendered = rendered });
474 },505 },
475 .Null, .Undefined => unreachable, // must be const or comptime506 .Enum => {
476 else => |e| return dg.fail(.{ .node_offset = 0 }, "TODO: C backend: implement type {s}", .{507 // For enums, we simply use the integer tag type.
477 @tagName(e),508 var int_tag_ty_buffer: Type.Payload.Bits = undefined;
478 }),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
479 }529 }
480 }530 }
481531
src/type.zig+623-1742
...@@ -93,14 +93,56 @@ pub const Type = extern union {...@@ -93,14 +93,56 @@ pub const Type = extern union {
9393
94 .anyerror_void_error_union, .error_union => return .ErrorUnion,94 .anyerror_void_error_union, .error_union => return .ErrorUnion,
9595
96 .empty_struct => return .Struct,96 .empty_struct,
97 .empty_struct_literal => return .Struct,97 .empty_struct_literal,
98 .@"struct" => return .Struct,98 .@"struct",
99 => return .Struct,
100
101 .enum_full,
102 .enum_nonexhaustive,
103 .enum_simple,
104 => return .Enum,
99105
100 .var_args_param => unreachable, // can be any type106 .var_args_param => unreachable, // can be any type
101 }107 }
102 }108 }
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
104 pub fn initTag(comptime small_tag: Tag) Type {146 pub fn initTag(comptime small_tag: Tag) Type {
105 comptime assert(@enumToInt(small_tag) < Tag.no_payload_count);147 comptime assert(@enumToInt(small_tag) < Tag.no_payload_count);
106 return .{ .tag_if_small_enough = @enumToInt(small_tag) };148 return .{ .tag_if_small_enough = @enumToInt(small_tag) };
...@@ -614,6 +656,8 @@ pub const Type = extern union {...@@ -614,6 +656,8 @@ pub const Type = extern union {
614 .error_set_single => return self.copyPayloadShallow(allocator, Payload.Name),656 .error_set_single => return self.copyPayloadShallow(allocator, Payload.Name),
615 .empty_struct => return self.copyPayloadShallow(allocator, Payload.ContainerScope),657 .empty_struct => return self.copyPayloadShallow(allocator, Payload.ContainerScope),
616 .@"struct" => return self.copyPayloadShallow(allocator, Payload.Struct),658 .@"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),
617 .@"opaque" => return self.copyPayloadShallow(allocator, Payload.Opaque),661 .@"opaque" => return self.copyPayloadShallow(allocator, Payload.Opaque),
618 }662 }
619 }663 }
...@@ -626,13 +670,13 @@ pub const Type = extern union {...@@ -626,13 +670,13 @@ pub const Type = extern union {
626 }670 }
627671
628 pub fn format(672 pub fn format(
629 self: Type,673 start_type: Type,
630 comptime fmt: []const u8,674 comptime fmt: []const u8,
631 options: std.fmt.FormatOptions,675 options: std.fmt.FormatOptions,
632 out_stream: anytype,676 writer: anytype,
633 ) @TypeOf(out_stream).Error!void {677 ) @TypeOf(writer).Error!void {
634 comptime assert(fmt.len == 0);678 comptime assert(fmt.len == 0);
635 var ty = self;679 var ty = start_type;
636 while (true) {680 while (true) {
637 const t = ty.tag();681 const t = ty.tag();
638 switch (t) {682 switch (t) {
...@@ -670,132 +714,149 @@ pub const Type = extern union {...@@ -670,132 +714,149 @@ pub const Type = extern union {
670 .comptime_float,714 .comptime_float,
671 .noreturn,715 .noreturn,
672 .var_args_param,716 .var_args_param,
673 => return out_stream.writeAll(@tagName(t)),717 => return writer.writeAll(@tagName(t)),
674718
675 .enum_literal => return out_stream.writeAll("@Type(.EnumLiteral)"),719 .enum_literal => return writer.writeAll("@Type(.EnumLiteral)"),
676 .@"null" => return out_stream.writeAll("@Type(.Null)"),720 .@"null" => return writer.writeAll("@Type(.Null)"),
677 .@"undefined" => return out_stream.writeAll("@Type(.Undefined)"),721 .@"undefined" => return writer.writeAll("@Type(.Undefined)"),
678722
679 .empty_struct, .empty_struct_literal => return out_stream.writeAll("struct {}"),723 .empty_struct, .empty_struct_literal => return writer.writeAll("struct {}"),
680 .@"struct" => return out_stream.writeAll("(struct)"),724
681 .anyerror_void_error_union => return out_stream.writeAll("anyerror!void"),725 .@"struct" => {
682 .const_slice_u8 => return out_stream.writeAll("[]const u8"),726 const struct_obj = ty.castTag(.@"struct").?.data;
683 .fn_noreturn_no_args => return out_stream.writeAll("fn() noreturn"),727 return struct_obj.owner_decl.renderFullyQualifiedName(writer);
684 .fn_void_no_args => return out_stream.writeAll("fn() void"),728 },
685 .fn_naked_noreturn_no_args => return out_stream.writeAll("fn() callconv(.Naked) noreturn"),729 .enum_full, .enum_nonexhaustive => {
686 .fn_ccc_void_no_args => return out_stream.writeAll("fn() callconv(.C) void"),730 const enum_full = ty.cast(Payload.EnumFull).?.data;
687 .single_const_pointer_to_comptime_int => return out_stream.writeAll("*const comptime_int"),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"),
688 .function => {749 .function => {
689 const payload = ty.castTag(.function).?.data;750 const payload = ty.castTag(.function).?.data;
690 try out_stream.writeAll("fn(");751 try writer.writeAll("fn(");
691 for (payload.param_types) |param_type, i| {752 for (payload.param_types) |param_type, i| {
692 if (i != 0) try out_stream.writeAll(", ");753 if (i != 0) try writer.writeAll(", ");
693 try param_type.format("", .{}, out_stream);754 try param_type.format("", .{}, writer);
694 }755 }
695 if (payload.is_var_args) {756 if (payload.is_var_args) {
696 if (payload.param_types.len != 0) {757 if (payload.param_types.len != 0) {
697 try out_stream.writeAll(", ");758 try writer.writeAll(", ");
698 }759 }
699 try out_stream.writeAll("...");760 try writer.writeAll("...");
700 }761 }
701 try out_stream.writeAll(") callconv(.");762 try writer.writeAll(") callconv(.");
702 try out_stream.writeAll(@tagName(payload.cc));763 try writer.writeAll(@tagName(payload.cc));
703 try out_stream.writeAll(")");764 try writer.writeAll(")");
704 ty = payload.return_type;765 ty = payload.return_type;
705 continue;766 continue;
706 },767 },
707768
708 .array_u8 => {769 .array_u8 => {
709 const len = ty.castTag(.array_u8).?.data;770 const len = ty.castTag(.array_u8).?.data;
710 return out_stream.print("[{d}]u8", .{len});771 return writer.print("[{d}]u8", .{len});
711 },772 },
712 .array_u8_sentinel_0 => {773 .array_u8_sentinel_0 => {
713 const len = ty.castTag(.array_u8_sentinel_0).?.data;774 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});
715 },776 },
716 .array => {777 .array => {
717 const payload = ty.castTag(.array).?.data;778 const payload = ty.castTag(.array).?.data;
718 try out_stream.print("[{d}]", .{payload.len});779 try writer.print("[{d}]", .{payload.len});
719 ty = payload.elem_type;780 ty = payload.elem_type;
720 continue;781 continue;
721 },782 },
722 .array_sentinel => {783 .array_sentinel => {
723 const payload = ty.castTag(.array_sentinel).?.data;784 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 });
725 ty = payload.elem_type;786 ty = payload.elem_type;
726 continue;787 continue;
727 },788 },
728 .single_const_pointer => {789 .single_const_pointer => {
729 const pointee_type = ty.castTag(.single_const_pointer).?.data;790 const pointee_type = ty.castTag(.single_const_pointer).?.data;
730 try out_stream.writeAll("*const ");791 try writer.writeAll("*const ");
731 ty = pointee_type;792 ty = pointee_type;
732 continue;793 continue;
733 },794 },
734 .single_mut_pointer => {795 .single_mut_pointer => {
735 const pointee_type = ty.castTag(.single_mut_pointer).?.data;796 const pointee_type = ty.castTag(.single_mut_pointer).?.data;
736 try out_stream.writeAll("*");797 try writer.writeAll("*");
737 ty = pointee_type;798 ty = pointee_type;
738 continue;799 continue;
739 },800 },
740 .many_const_pointer => {801 .many_const_pointer => {
741 const pointee_type = ty.castTag(.many_const_pointer).?.data;802 const pointee_type = ty.castTag(.many_const_pointer).?.data;
742 try out_stream.writeAll("[*]const ");803 try writer.writeAll("[*]const ");
743 ty = pointee_type;804 ty = pointee_type;
744 continue;805 continue;
745 },806 },
746 .many_mut_pointer => {807 .many_mut_pointer => {
747 const pointee_type = ty.castTag(.many_mut_pointer).?.data;808 const pointee_type = ty.castTag(.many_mut_pointer).?.data;
748 try out_stream.writeAll("[*]");809 try writer.writeAll("[*]");
749 ty = pointee_type;810 ty = pointee_type;
750 continue;811 continue;
751 },812 },
752 .c_const_pointer => {813 .c_const_pointer => {
753 const pointee_type = ty.castTag(.c_const_pointer).?.data;814 const pointee_type = ty.castTag(.c_const_pointer).?.data;
754 try out_stream.writeAll("[*c]const ");815 try writer.writeAll("[*c]const ");
755 ty = pointee_type;816 ty = pointee_type;
756 continue;817 continue;
757 },818 },
758 .c_mut_pointer => {819 .c_mut_pointer => {
759 const pointee_type = ty.castTag(.c_mut_pointer).?.data;820 const pointee_type = ty.castTag(.c_mut_pointer).?.data;
760 try out_stream.writeAll("[*c]");821 try writer.writeAll("[*c]");
761 ty = pointee_type;822 ty = pointee_type;
762 continue;823 continue;
763 },824 },
764 .const_slice => {825 .const_slice => {
765 const pointee_type = ty.castTag(.const_slice).?.data;826 const pointee_type = ty.castTag(.const_slice).?.data;
766 try out_stream.writeAll("[]const ");827 try writer.writeAll("[]const ");
767 ty = pointee_type;828 ty = pointee_type;
768 continue;829 continue;
769 },830 },
770 .mut_slice => {831 .mut_slice => {
771 const pointee_type = ty.castTag(.mut_slice).?.data;832 const pointee_type = ty.castTag(.mut_slice).?.data;
772 try out_stream.writeAll("[]");833 try writer.writeAll("[]");
773 ty = pointee_type;834 ty = pointee_type;
774 continue;835 continue;
775 },836 },
776 .int_signed => {837 .int_signed => {
777 const bits = ty.castTag(.int_signed).?.data;838 const bits = ty.castTag(.int_signed).?.data;
778 return out_stream.print("i{d}", .{bits});839 return writer.print("i{d}", .{bits});
779 },840 },
780 .int_unsigned => {841 .int_unsigned => {
781 const bits = ty.castTag(.int_unsigned).?.data;842 const bits = ty.castTag(.int_unsigned).?.data;
782 return out_stream.print("u{d}", .{bits});843 return writer.print("u{d}", .{bits});
783 },844 },
784 .optional => {845 .optional => {
785 const child_type = ty.castTag(.optional).?.data;846 const child_type = ty.castTag(.optional).?.data;
786 try out_stream.writeByte('?');847 try writer.writeByte('?');
787 ty = child_type;848 ty = child_type;
788 continue;849 continue;
789 },850 },
790 .optional_single_const_pointer => {851 .optional_single_const_pointer => {
791 const pointee_type = ty.castTag(.optional_single_const_pointer).?.data;852 const pointee_type = ty.castTag(.optional_single_const_pointer).?.data;
792 try out_stream.writeAll("?*const ");853 try writer.writeAll("?*const ");
793 ty = pointee_type;854 ty = pointee_type;
794 continue;855 continue;
795 },856 },
796 .optional_single_mut_pointer => {857 .optional_single_mut_pointer => {
797 const pointee_type = ty.castTag(.optional_single_mut_pointer).?.data;858 const pointee_type = ty.castTag(.optional_single_mut_pointer).?.data;
798 try out_stream.writeAll("?*");859 try writer.writeAll("?*");
799 ty = pointee_type;860 ty = pointee_type;
800 continue;861 continue;
801 },862 },
...@@ -804,48 +865,46 @@ pub const Type = extern union {...@@ -804,48 +865,46 @@ pub const Type = extern union {
804 const payload = ty.castTag(.pointer).?.data;865 const payload = ty.castTag(.pointer).?.data;
805 if (payload.sentinel) |some| switch (payload.size) {866 if (payload.sentinel) |some| switch (payload.size) {
806 .One, .C => unreachable,867 .One, .C => unreachable,
807 .Many => try out_stream.print("[*:{}]", .{some}),868 .Many => try writer.print("[*:{}]", .{some}),
808 .Slice => try out_stream.print("[:{}]", .{some}),869 .Slice => try writer.print("[:{}]", .{some}),
809 } else switch (payload.size) {870 } else switch (payload.size) {
810 .One => try out_stream.writeAll("*"),871 .One => try writer.writeAll("*"),
811 .Many => try out_stream.writeAll("[*]"),872 .Many => try writer.writeAll("[*]"),
812 .C => try out_stream.writeAll("[*c]"),873 .C => try writer.writeAll("[*c]"),
813 .Slice => try out_stream.writeAll("[]"),874 .Slice => try writer.writeAll("[]"),
814 }875 }
815 if (payload.@"align" != 0) {876 if (payload.@"align" != 0) {
816 try out_stream.print("align({d}", .{payload.@"align"});877 try writer.print("align({d}", .{payload.@"align"});
817878
818 if (payload.bit_offset != 0) {879 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 });
820 }881 }
821 try out_stream.writeAll(") ");882 try writer.writeAll(") ");
822 }883 }
823 if (!payload.mutable) try out_stream.writeAll("const ");884 if (!payload.mutable) try writer.writeAll("const ");
824 if (payload.@"volatile") try out_stream.writeAll("volatile ");885 if (payload.@"volatile") try writer.writeAll("volatile ");
825 if (payload.@"allowzero") try out_stream.writeAll("allowzero ");886 if (payload.@"allowzero") try writer.writeAll("allowzero ");
826887
827 ty = payload.pointee_type;888 ty = payload.pointee_type;
828 continue;889 continue;
829 },890 },
830 .error_union => {891 .error_union => {
831 const payload = ty.castTag(.error_union).?.data;892 const payload = ty.castTag(.error_union).?.data;
832 try payload.error_set.format("", .{}, out_stream);893 try payload.error_set.format("", .{}, writer);
833 try out_stream.writeAll("!");894 try writer.writeAll("!");
834 ty = payload.payload;895 ty = payload.payload;
835 continue;896 continue;
836 },897 },
837 .error_set => {898 .error_set => {
838 const error_set = ty.castTag(.error_set).?.data;899 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));
840 },901 },
841 .error_set_single => {902 .error_set_single => {
842 const name = ty.castTag(.error_set_single).?.data;903 const name = ty.castTag(.error_set_single).?.data;
843 return out_stream.print("error{{{s}}}", .{name});904 return writer.print("error{{{s}}}", .{name});
844 },905 },
845 .inferred_alloc_const => return out_stream.writeAll("(inferred_alloc_const)"),906 .inferred_alloc_const => return writer.writeAll("(inferred_alloc_const)"),
846 .inferred_alloc_mut => return out_stream.writeAll("(inferred_alloc_mut)"),907 .inferred_alloc_mut => return writer.writeAll("(inferred_alloc_mut)"),
847 // TODO use declaration name
848 .@"opaque" => return out_stream.writeAll("opaque {}"),
849 }908 }
850 unreachable;909 unreachable;
851 }910 }
...@@ -954,6 +1013,19 @@ pub const Type = extern union {...@@ -954,6 +1013,19 @@ pub const Type = extern union {
954 return false;1013 return false;
955 }1014 }
956 },1015 },
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
958 // TODO lazy types1030 // TODO lazy types
959 .array => self.elemType().hasCodeGenBits() and self.arrayLen() != 0,1031 .array => self.elemType().hasCodeGenBits() and self.arrayLen() != 0,
...@@ -1112,13 +1184,37 @@ pub const Type = extern union {...@@ -1112,13 +1184,37 @@ pub const Type = extern union {
1112 } else if (!payload.payload.hasCodeGenBits()) {1184 } else if (!payload.payload.hasCodeGenBits()) {
1113 return payload.error_set.abiAlignment(target);1185 return payload.error_set.abiAlignment(target);
1114 }1186 }
1115 @panic("TODO abiAlignment error union");1187 return std.math.max(
1188 payload.payload.abiAlignment(target),
1189 payload.error_set.abiAlignment(target),
1190 );
1116 },1191 },
11171192
1118 .@"struct" => {1193 .@"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);
1120 },1217 },
1121
1122 .c_void,1218 .c_void,
1123 .void,1219 .void,
1124 .type,1220 .type,
...@@ -1166,6 +1262,11 @@ pub const Type = extern union {...@@ -1166,6 +1262,11 @@ pub const Type = extern union {
1166 .@"struct" => {1262 .@"struct" => {
1167 @panic("TODO abiSize struct");1263 @panic("TODO abiSize struct");
1168 },1264 },
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
1170 .u8,1271 .u8,
1171 .i8,1272 .i8,
...@@ -1276,76 +1377,25 @@ pub const Type = extern union {...@@ -1276,76 +1377,25 @@ pub const Type = extern union {
1276 };1377 };
1277 }1378 }
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
1279 pub fn isSinglePointer(self: Type) bool {1397 pub fn isSinglePointer(self: Type) bool {
1280 return switch (self.tag()) {1398 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
1349 .single_const_pointer,1399 .single_const_pointer,
1350 .single_mut_pointer,1400 .single_mut_pointer,
1351 .single_const_pointer_to_comptime_int,1401 .single_const_pointer_to_comptime_int,
...@@ -1354,73 +1404,14 @@ pub const Type = extern union {...@@ -1354,73 +1404,14 @@ pub const Type = extern union {
1354 => true,1404 => true,
13551405
1356 .pointer => self.castTag(.pointer).?.data.size == .One,1406 .pointer => self.castTag(.pointer).?.data.size == .One,
1407
1408 else => false,
1357 };1409 };
1358 }1410 }
13591411
1360 /// Asserts the `Type` is a pointer.1412 /// Asserts the `Type` is a pointer.
1361 pub fn ptrSize(self: Type) std.builtin.TypeInfo.Pointer.Size {1413 pub fn ptrSize(self: Type) std.builtin.TypeInfo.Pointer.Size {
1362 return switch (self.tag()) {1414 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
1424 .const_slice,1415 .const_slice,
1425 .mut_slice,1416 .mut_slice,
1426 .const_slice_u8,1417 .const_slice_u8,
...@@ -1442,159 +1433,26 @@ pub const Type = extern union {...@@ -1442,159 +1433,26 @@ pub const Type = extern union {
1442 => .One,1433 => .One,
14431434
1444 .pointer => self.castTag(.pointer).?.data.size,1435 .pointer => self.castTag(.pointer).?.data.size,
1436
1437 else => unreachable,
1445 };1438 };
1446 }1439 }
14471440
1448 pub fn isSlice(self: Type) bool {1441 pub fn isSlice(self: Type) bool {
1449 return switch (self.tag()) {1442 return switch (self.tag()) {
1450 .u8,1443 .const_slice,
1451 .i8,1444 .mut_slice,
1452 .u16,1445 .const_slice_u8,
1453 .i16,1446 => true,
1454 .u32,1447
1455 .i32,1448 .pointer => self.castTag(.pointer).?.data.size == .Slice,
1456 .u64,1449
1457 .i64,1450 else => false,
1458 .u128,1451 };
1459 .i128,1452 }
1460 .usize,1453
1461 .isize,1454 pub fn isConstPtr(self: Type) bool {
1462 .c_short,1455 return switch (self.tag()) {
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
1598 .single_const_pointer,1456 .single_const_pointer,
1599 .many_const_pointer,1457 .many_const_pointer,
1600 .c_const_pointer,1458 .c_const_pointer,
...@@ -1604,181 +1462,51 @@ pub const Type = extern union {...@@ -1604,181 +1462,51 @@ pub const Type = extern union {
1604 => true,1462 => true,
16051463
1606 .pointer => !self.castTag(.pointer).?.data.mutable,1464 .pointer => !self.castTag(.pointer).?.data.mutable,
1465
1466 else => false,
1607 };1467 };
1608 }1468 }
16091469
1610 pub fn isVolatilePtr(self: Type) bool {1470 pub fn isVolatilePtr(self: Type) bool {
1611 return switch (self.tag()) {1471 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
1685 .pointer => {1472 .pointer => {
1686 const payload = self.castTag(.pointer).?.data;1473 const payload = self.castTag(.pointer).?.data;
1687 return payload.@"volatile";1474 return payload.@"volatile";
1688 },1475 },
1476 else => false,
1689 };1477 };
1690 }1478 }
16911479
1692 pub fn isAllowzeroPtr(self: Type) bool {1480 pub fn isAllowzeroPtr(self: Type) bool {
1693 return switch (self.tag()) {1481 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
1767 .pointer => {1482 .pointer => {
1768 const payload = self.castTag(.pointer).?.data;1483 const payload = self.castTag(.pointer).?.data;
1769 return payload.@"allowzero";1484 return payload.@"allowzero";
1770 },1485 },
1486 else => false,
1771 };1487 };
1772 }1488 }
17731489
1774 /// Asserts that the type is an optional1490 pub fn isCPtr(self: Type) bool {
1775 pub fn isPtrLikeOptional(self: Type) bool {1491 return switch (self.tag()) {
1776 switch (self.tag()) {1492 .c_const_pointer,
1777 .optional_single_const_pointer, .optional_single_mut_pointer => return true,1493 .c_mut_pointer,
1778 .optional => {1494 => return true,
1779 var buf: Payload.ElemType = undefined;1495
1780 const child_type = self.optionalChild(&buf);1496 .pointer => self.castTag(.pointer).?.data.size == .C,
1781 // optionals of zero sized pointers behave like bools1497
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
1782 if (!child_type.hasCodeGenBits()) return false;1510 if (!child_type.hasCodeGenBits()) return false;
17831511
1784 return child_type.zigTypeTag() == .Pointer and !child_type.isCPtr();1512 return child_type.zigTypeTag() == .Pointer and !child_type.isCPtr();
...@@ -1833,64 +1561,6 @@ pub const Type = extern union {...@@ -1833,64 +1561,6 @@ pub const Type = extern union {
1833 /// Asserts the type is a pointer or array type.1561 /// Asserts the type is a pointer or array type.
1834 pub fn elemType(self: Type) Type {1562 pub fn elemType(self: Type) Type {
1835 return switch (self.tag()) {1563 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
1894 .array => self.castTag(.array).?.data.elem_type,1564 .array => self.castTag(.array).?.data.elem_type,
1895 .array_sentinel => self.castTag(.array_sentinel).?.data.elem_type,1565 .array_sentinel => self.castTag(.array_sentinel).?.data.elem_type,
1896 .single_const_pointer,1566 .single_const_pointer,
...@@ -1902,9 +1572,12 @@ pub const Type = extern union {...@@ -1902,9 +1572,12 @@ pub const Type = extern union {
1902 .const_slice,1572 .const_slice,
1903 .mut_slice,1573 .mut_slice,
1904 => self.castPointer().?.data,1574 => self.castPointer().?.data,
1575
1905 .array_u8, .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.u8),1576 .array_u8, .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.u8),
1906 .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int),1577 .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int),
1907 .pointer => self.castTag(.pointer).?.data.pointee_type,1578 .pointer => self.castTag(.pointer).?.data.pointee_type,
1579
1580 else => unreachable,
1908 };1581 };
1909 }1582 }
19101583
...@@ -1972,148 +1645,18 @@ pub const Type = extern union {...@@ -1972,148 +1645,18 @@ pub const Type = extern union {
1972 /// Asserts the type is an array or vector.1645 /// Asserts the type is an array or vector.
1973 pub fn arrayLen(self: Type) u64 {1646 pub fn arrayLen(self: Type) u64 {
1974 return switch (self.tag()) {1647 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
2045 .array => self.castTag(.array).?.data.len,1648 .array => self.castTag(.array).?.data.len,
2046 .array_sentinel => self.castTag(.array_sentinel).?.data.len,1649 .array_sentinel => self.castTag(.array_sentinel).?.data.len,
2047 .array_u8 => self.castTag(.array_u8).?.data,1650 .array_u8 => self.castTag(.array_u8).?.data,
2048 .array_u8_sentinel_0 => self.castTag(.array_u8_sentinel_0).?.data,1651 .array_u8_sentinel_0 => self.castTag(.array_u8_sentinel_0).?.data,
1652
1653 else => unreachable,
2049 };1654 };
2050 }1655 }
20511656
2052 /// Asserts the type is an array, pointer or vector.1657 /// Asserts the type is an array, pointer or vector.
2053 pub fn sentinel(self: Type) ?Value {1658 pub fn sentinel(self: Type) ?Value {
2054 return switch (self.tag()) {1659 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
2117 .single_const_pointer,1660 .single_const_pointer,
2118 .single_mut_pointer,1661 .single_mut_pointer,
2119 .many_const_pointer,1662 .many_const_pointer,
...@@ -2128,6 +1671,8 @@ pub const Type = extern union {...@@ -2128,6 +1671,8 @@ pub const Type = extern union {
2128 .pointer => return self.castTag(.pointer).?.data.sentinel,1671 .pointer => return self.castTag(.pointer).?.data.sentinel,
2129 .array_sentinel => return self.castTag(.array_sentinel).?.data.sentinel,1672 .array_sentinel => return self.castTag(.array_sentinel).?.data.sentinel,
2130 .array_u8_sentinel_0 => return Value.initTag(.zero),1673 .array_u8_sentinel_0 => return Value.initTag(.zero),
1674
1675 else => unreachable,
2131 };1676 };
2132 }1677 }
21331678
...@@ -2136,869 +1681,84 @@ pub const Type = extern union {...@@ -2136,869 +1681,84 @@ pub const Type = extern union {
2136 return self.isSignedInt() or self.isUnsignedInt();1681 return self.isSignedInt() or self.isUnsignedInt();
2137 }1682 }
21381683
2139 /// Returns true if and only if the type is a fixed-width, signed integer.1684 /// Returns true if and only if the type is a fixed-width, signed integer.
2140 pub fn isSignedInt(self: Type) bool {1685 pub fn isSignedInt(self: Type) bool {
2141 return switch (self.tag()) {1686 return switch (self.tag()) {
2142 .f16,1687 .int_signed,
2143 .f32,1688 .i8,
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,
2953 .isize,1689 .isize,
2954 .c_short,1690 .c_short,
2955 .c_ushort,
2956 .c_int,1691 .c_int,
2957 .c_uint,
2958 .c_long,1692 .c_long,
2959 .c_ulong,
2960 .c_longlong,1693 .c_longlong,
2961 .c_ulonglong,1694 .i16,
2962 .int_unsigned,1695 .i32,
2963 .int_signed,1696 .i64,
2964 .optional,1697 .i128,
2965 .optional_single_mut_pointer,1698 => true,
2966 .optional_single_const_pointer,1699
2967 .enum_literal,1700 else => false,
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,
2980 };1701 };
2981 }1702 }
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 {
2984 return switch (self.tag()) {1706 return switch (self.tag()) {
2985 .f16,1707 .int_unsigned,
2986 .f32,
2987 .f64,
2988 .f128,
2989 .c_longdouble,
2990 .comptime_int,
2991 .comptime_float,
2992 .u8,1708 .u8,
2993 .i8,1709 .usize,
1710 .c_ushort,
1711 .c_uint,
1712 .c_ulong,
1713 .c_ulonglong,
2994 .u16,1714 .u16,
2995 .i16,
2996 .u32,1715 .u32,
2997 .i32,
2998 .u64,1716 .u64,
2999 .i64,
3000 .u128,1717 .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()) {
3002 .usize,1762 .usize,
3003 .isize,1763 .isize,
3004 .c_short,1764 .c_short,
...@@ -3009,59 +1769,161 @@ pub const Type = extern union {...@@ -3009,59 +1769,161 @@ pub const Type = extern union {
3009 .c_ulong,1769 .c_ulong,
3010 .c_longlong,1770 .c_longlong,
3011 .c_ulonglong,1771 .c_ulonglong,
3012 .int_unsigned,
3013 .int_signed,
3014 => true,1772 => true,
30151773
3016 .c_void,1774 else => false,
3017 .bool,1775 };
3018 .void,1776 }
3019 .type,1777
3020 .anyerror,1778 pub fn isFloat(self: Type) bool {
3021 .noreturn,1779 return switch (self.tag()) {
3022 .@"null",1780 .f16,
3023 .@"undefined",1781 .f32,
3024 .fn_noreturn_no_args,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
3025 .fn_void_no_args,1852 .fn_void_no_args,
3026 .fn_naked_noreturn_no_args,
3027 .fn_ccc_void_no_args,1853 .fn_ccc_void_no_args,
3028 .function,1854 => Type.initTag(.void),
3029 .array,1855
3030 .array_sentinel,1856 .function => self.castTag(.function).?.data.return_type,
3031 .array_u8,1857
3032 .array_u8_sentinel_0,1858 else => unreachable,
3033 .pointer,1859 };
3034 .single_const_pointer,1860 }
3035 .single_mut_pointer,1861
3036 .many_const_pointer,1862 /// Asserts the type is a function.
3037 .many_mut_pointer,1863 pub fn fnCallingConvention(self: Type) std.builtin.CallingConvention {
3038 .c_const_pointer,1864 return switch (self.tag()) {
3039 .c_mut_pointer,1865 .fn_noreturn_no_args => .Unspecified,
3040 .const_slice,1866 .fn_void_no_args => .Unspecified,
3041 .mut_slice,1867 .fn_naked_noreturn_no_args => .Naked,
3042 .single_const_pointer_to_comptime_int,1868 .fn_ccc_void_no_args => .C,
3043 .const_slice_u8,1869 .function => self.castTag(.function).?.data.cc,
3044 .optional,1870
3045 .optional_single_mut_pointer,1871 else => unreachable,
3046 .optional_single_const_pointer,1872 };
3047 .enum_literal,1873 }
3048 .error_union,1874
3049 .anyerror_void_error_union,1875 /// Asserts the type is a function.
3050 .error_set,1876 pub fn fnIsVarArgs(self: Type) bool {
3051 .error_set_single,1877 return switch (self.tag()) {
3052 .@"struct",1878 .fn_noreturn_no_args => false,
3053 .empty_struct,1879 .fn_void_no_args => false,
3054 .empty_struct_literal,1880 .fn_naked_noreturn_no_args => false,
3055 .inferred_alloc_const,1881 .fn_ccc_void_no_args => false,
3056 .inferred_alloc_mut,1882 .function => self.castTag(.function).?.data.is_var_args,
3057 .@"opaque",1883
3058 .var_args_param,1884 else => unreachable,
3059 => false,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,
3060 };1922 };
3061 }1923 }
30621924
3063 pub fn onePossibleValue(self: Type) ?Value {1925 pub fn onePossibleValue(starting_type: Type) ?Value {
3064 var ty = self;1926 var ty = starting_type;
3065 while (true) switch (ty.tag()) {1927 while (true) switch (ty.tag()) {
3066 .f16,1928 .f16,
3067 .f32,1929 .f32,
...@@ -3127,6 +1989,23 @@ pub const Type = extern union {...@@ -3127,6 +1989,23 @@ pub const Type = extern union {
3127 }1989 }
3128 return Value.initTag(.empty_struct_value);1990 return Value.initTag(.empty_struct_value);
3129 },1991 },
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
3131 .empty_struct, .empty_struct_literal => return Value.initTag(.empty_struct_value),2010 .empty_struct, .empty_struct_literal => return Value.initTag(.empty_struct_value),
3132 .void => return Value.initTag(.void_value),2011 .void => return Value.initTag(.void_value),
...@@ -3166,87 +2045,6 @@ pub const Type = extern union {...@@ -3166,87 +2045,6 @@ pub const Type = extern union {
3166 };2045 };
3167 }2046 }
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
3250 pub fn isIndexable(self: Type) bool {2048 pub fn isIndexable(self: Type) bool {
3251 const zig_tag = self.zigTypeTag();2049 const zig_tag = self.zigTypeTag();
3252 // TODO tuples are indexable2050 // TODO tuples are indexable
...@@ -3254,83 +2052,15 @@ pub const Type = extern union {...@@ -3254,83 +2052,15 @@ pub const Type = extern union {
3254 (self.isSinglePointer() and self.elemType().zigTypeTag() == .Array);2052 (self.isSinglePointer() and self.elemType().zigTypeTag() == .Array);
3255 }2053 }
32562054
3257 /// Asserts that the type is a container. (note: ErrorSet is not a container).2055 /// Returns null if the type has no container.
3258 pub fn getContainerScope(self: Type) *Module.Scope.Container {2056 pub fn getContainerScope(self: Type) ?*Module.Scope.Container {
3259 return switch (self.tag()) {2057 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
3331 .@"struct" => &self.castTag(.@"struct").?.data.container,2058 .@"struct" => &self.castTag(.@"struct").?.data.container,
2059 .enum_full => &self.castTag(.enum_full).?.data.container,
3332 .empty_struct => self.castTag(.empty_struct).?.data,2060 .empty_struct => self.castTag(.empty_struct).?.data,
3333 .@"opaque" => &self.castTag(.@"opaque").?.data,2061 .@"opaque" => &self.castTag(.@"opaque").?.data,
2062
2063 else => null,
3334 };2064 };
3335 }2065 }
33362066
...@@ -3389,8 +2119,144 @@ pub const Type = extern union {...@@ -3389,8 +2119,144 @@ pub const Type = extern union {
3389 }2119 }
3390 }2120 }
33912121
3392 pub fn isExhaustiveEnum(ty: Type) bool {2122 pub fn isNonexhaustiveEnum(ty: Type) bool {
3393 return false; // TODO2123 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 }
3394 }2260 }
33952261
3396 /// This enum does not directly correspond to `std.builtin.TypeId` because2262 /// This enum does not directly correspond to `std.builtin.TypeId` because
...@@ -3482,6 +2348,9 @@ pub const Type = extern union {...@@ -3482,6 +2348,9 @@ pub const Type = extern union {
3482 empty_struct,2348 empty_struct,
3483 @"opaque",2349 @"opaque",
3484 @"struct",2350 @"struct",
2351 enum_simple,
2352 enum_full,
2353 enum_nonexhaustive,
34852354
3486 pub const last_no_payload_tag = Tag.inferred_alloc_const;2355 pub const last_no_payload_tag = Tag.inferred_alloc_const;
3487 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;2356 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
...@@ -3568,6 +2437,8 @@ pub const Type = extern union {...@@ -3568,6 +2437,8 @@ pub const Type = extern union {
3568 .error_set_single => Payload.Name,2437 .error_set_single => Payload.Name,
3569 .@"opaque" => Payload.Opaque,2438 .@"opaque" => Payload.Opaque,
3570 .@"struct" => Payload.Struct,2439 .@"struct" => Payload.Struct,
2440 .enum_full, .enum_nonexhaustive => Payload.EnumFull,
2441 .enum_simple => Payload.EnumSimple,
3571 .empty_struct => Payload.ContainerScope,2442 .empty_struct => Payload.ContainerScope,
3572 };2443 };
3573 }2444 }
...@@ -3705,6 +2576,16 @@ pub const Type = extern union {...@@ -3705,6 +2576,16 @@ pub const Type = extern union {
3705 base: Payload = .{ .tag = .@"struct" },2576 base: Payload = .{ .tag = .@"struct" },
3706 data: *Module.Struct,2577 data: *Module.Struct,
3707 };2578 };
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 };
3708 };2589 };
3709};2590};
37102591
src/value.zig+57-780
...@@ -103,6 +103,8 @@ pub const Value = extern union {...@@ -103,6 +103,8 @@ pub const Value = extern union {
103 float_64,103 float_64,
104 float_128,104 float_128,
105 enum_literal,105 enum_literal,
106 /// A specific enum tag, indicated by the field index (declaration order).
107 enum_field_index,
106 @"error",108 @"error",
107 error_union,109 error_union,
108 /// This is a special value that tracks a set of types that have been stored110 /// This is a special value that tracks a set of types that have been stored
...@@ -186,6 +188,8 @@ pub const Value = extern union {...@@ -186,6 +188,8 @@ pub const Value = extern union {
186 .enum_literal,188 .enum_literal,
187 => Payload.Bytes,189 => Payload.Bytes,
188190
191 .enum_field_index => Payload.U32,
192
189 .ty => Payload.Ty,193 .ty => Payload.Ty,
190 .int_type => Payload.IntType,194 .int_type => Payload.IntType,
191 .int_u64 => Payload.U64,195 .int_u64 => Payload.U64,
...@@ -394,6 +398,7 @@ pub const Value = extern union {...@@ -394,6 +398,7 @@ pub const Value = extern union {
394 };398 };
395 return Value{ .ptr_otherwise = &new_payload.base };399 return Value{ .ptr_otherwise = &new_payload.base };
396 },400 },
401 .enum_field_index => return self.copyPayloadShallow(allocator, Payload.U32),
397 .@"error" => return self.copyPayloadShallow(allocator, Payload.Error),402 .@"error" => return self.copyPayloadShallow(allocator, Payload.Error),
398 .error_union => {403 .error_union => {
399 const payload = self.castTag(.error_union).?;404 const payload = self.castTag(.error_union).?;
...@@ -416,6 +421,8 @@ pub const Value = extern union {...@@ -416,6 +421,8 @@ pub const Value = extern union {
416 return Value{ .ptr_otherwise = &new_payload.base };421 return Value{ .ptr_otherwise = &new_payload.base };
417 }422 }
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.
419 pub fn format(426 pub fn format(
420 self: Value,427 self: Value,
421 comptime fmt: []const u8,428 comptime fmt: []const u8,
...@@ -506,6 +513,7 @@ pub const Value = extern union {...@@ -506,6 +513,7 @@ pub const Value = extern union {
506 },513 },
507 .empty_array => return out_stream.writeAll(".{}"),514 .empty_array => return out_stream.writeAll(".{}"),
508 .enum_literal => return out_stream.print(".{}", .{std.zig.fmtId(self.castTag(.enum_literal).?.data)}),515 .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}),
509 .bytes => return out_stream.print("\"{}\"", .{std.zig.fmtEscapes(self.castTag(.bytes).?.data)}),517 .bytes => return out_stream.print("\"{}\"", .{std.zig.fmtEscapes(self.castTag(.bytes).?.data)}),
510 .repeated => {518 .repeated => {
511 try out_stream.writeAll("(repeated) ");519 try out_stream.writeAll("(repeated) ");
...@@ -626,6 +634,7 @@ pub const Value = extern union {...@@ -626,6 +634,7 @@ pub const Value = extern union {
626 .float_64,634 .float_64,
627 .float_128,635 .float_128,
628 .enum_literal,636 .enum_literal,
637 .enum_field_index,
629 .@"error",638 .@"error",
630 .error_union,639 .error_union,
631 .empty_struct_value,640 .empty_struct_value,
...@@ -638,76 +647,6 @@ pub const Value = extern union {...@@ -638,76 +647,6 @@ pub const Value = extern union {
638 /// Asserts the value is an integer.647 /// Asserts the value is an integer.
639 pub fn toBigInt(self: Value, space: *BigIntSpace) BigIntConst {648 pub fn toBigInt(self: Value, space: *BigIntSpace) BigIntConst {
640 switch (self.tag()) {649 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
711 .zero,650 .zero,
712 .bool_false,651 .bool_false,
713 => return BigIntMutable.init(&space.limbs, 0).toConst(),652 => return BigIntMutable.init(&space.limbs, 0).toConst(),
...@@ -720,82 +659,15 @@ pub const Value = extern union {...@@ -720,82 +659,15 @@ pub const Value = extern union {
720 .int_i64 => return BigIntMutable.init(&space.limbs, self.castTag(.int_i64).?.data).toConst(),659 .int_i64 => return BigIntMutable.init(&space.limbs, self.castTag(.int_i64).?.data).toConst(),
721 .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt(),660 .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt(),
722 .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt(),661 .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt(),
662
663 .undef => unreachable,
664 else => unreachable,
723 }665 }
724 }666 }
725667
726 /// Asserts the value is an integer and it fits in a u64668 /// Asserts the value is an integer and it fits in a u64
727 pub fn toUnsignedInt(self: Value) u64 {669 pub fn toUnsignedInt(self: Value) u64 {
728 switch (self.tag()) {670 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
799 .zero,671 .zero,
800 .bool_false,672 .bool_false,
801 => return 0,673 => return 0,
...@@ -808,82 +680,15 @@ pub const Value = extern union {...@@ -808,82 +680,15 @@ pub const Value = extern union {
808 .int_i64 => return @intCast(u64, self.castTag(.int_i64).?.data),680 .int_i64 => return @intCast(u64, self.castTag(.int_i64).?.data),
809 .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().to(u64) catch unreachable,681 .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().to(u64) catch unreachable,
810 .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().to(u64) catch unreachable,682 .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().to(u64) catch unreachable,
683
684 .undef => unreachable,
685 else => unreachable,
811 }686 }
812 }687 }
813688
814 /// Asserts the value is an integer and it fits in a i64689 /// Asserts the value is an integer and it fits in a i64
815 pub fn toSignedInt(self: Value) i64 {690 pub fn toSignedInt(self: Value) i64 {
816 switch (self.tag()) {691 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
887 .zero,692 .zero,
888 .bool_false,693 .bool_false,
889 => return 0,694 => return 0,
...@@ -896,6 +701,9 @@ pub const Value = extern union {...@@ -896,6 +701,9 @@ pub const Value = extern union {
896 .int_i64 => return self.castTag(.int_i64).?.data,701 .int_i64 => return self.castTag(.int_i64).?.data,
897 .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().to(i64) catch unreachable,702 .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().to(i64) catch unreachable,
898 .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().to(i64) catch unreachable,703 .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().to(i64) catch unreachable,
704
705 .undef => unreachable,
706 else => unreachable,
899 }707 }
900 }708 }
901709
...@@ -929,75 +737,6 @@ pub const Value = extern union {...@@ -929,75 +737,6 @@ pub const Value = extern union {
929 /// Returns the number of bits the value requires to represent stored in twos complement form.737 /// Returns the number of bits the value requires to represent stored in twos complement form.
930 pub fn intBitCountTwosComp(self: Value) usize {738 pub fn intBitCountTwosComp(self: Value) usize {
931 switch (self.tag()) {739 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
1001 .zero,740 .zero,
1002 .bool_false,741 .bool_false,
1003 => return 0,742 => return 0,
...@@ -1016,80 +755,14 @@ pub const Value = extern union {...@@ -1016,80 +755,14 @@ pub const Value = extern union {
1016 },755 },
1017 .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().bitCountTwosComp(),756 .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().bitCountTwosComp(),
1018 .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().bitCountTwosComp(),757 .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().bitCountTwosComp(),
758
759 else => unreachable,
1019 }760 }
1020 }761 }
1021762
1022 /// Asserts the value is an integer, and the destination type is ComptimeInt or Int.763 /// Asserts the value is an integer, and the destination type is ComptimeInt or Int.
1023 pub fn intFitsInType(self: Value, ty: Type, target: Target) bool {764 pub fn intFitsInType(self: Value, ty: Type, target: Target) bool {
1024 switch (self.tag()) {765 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
1093 .zero,766 .zero,
1094 .undef,767 .undef,
1095 .bool_false,768 .bool_false,
...@@ -1144,6 +817,8 @@ pub const Value = extern union {...@@ -1144,6 +817,8 @@ pub const Value = extern union {
1144 .ComptimeInt => return true,817 .ComptimeInt => return true,
1145 else => unreachable,818 else => unreachable,
1146 },819 },
820
821 else => unreachable,
1147 }822 }
1148 }823 }
1149824
...@@ -1180,77 +855,6 @@ pub const Value = extern union {...@@ -1180,77 +855,6 @@ pub const Value = extern union {
1180 /// Asserts the value is a float855 /// Asserts the value is a float
1181 pub fn floatHasFraction(self: Value) bool {856 pub fn floatHasFraction(self: Value) bool {
1182 return switch (self.tag()) {857 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
1254 .zero,858 .zero,
1255 .one,859 .one,
1256 => false,860 => false,
...@@ -1260,76 +864,13 @@ pub const Value = extern union {...@@ -1260,76 +864,13 @@ pub const Value = extern union {
1260 .float_64 => @rem(self.castTag(.float_64).?.data, 1) != 0,864 .float_64 => @rem(self.castTag(.float_64).?.data, 1) != 0,
1261 // .float_128 => @rem(self.castTag(.float_128).?.data, 1) != 0,865 // .float_128 => @rem(self.castTag(.float_128).?.data, 1) != 0,
1262 .float_128 => @panic("TODO lld: error: undefined symbol: fmodl"),866 .float_128 => @panic("TODO lld: error: undefined symbol: fmodl"),
867
868 else => unreachable,
1263 };869 };
1264 }870 }
1265871
1266 pub fn orderAgainstZero(lhs: Value) std.math.Order {872 pub fn orderAgainstZero(lhs: Value) std.math.Order {
1267 return switch (lhs.tag()) {873 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
1333 .zero,874 .zero,
1334 .bool_false,875 .bool_false,
1335 => .eq,876 => .eq,
...@@ -1347,6 +888,8 @@ pub const Value = extern union {...@@ -1347,6 +888,8 @@ pub const Value = extern union {
1347 .float_32 => std.math.order(lhs.castTag(.float_32).?.data, 0),888 .float_32 => std.math.order(lhs.castTag(.float_32).?.data, 0),
1348 .float_64 => std.math.order(lhs.castTag(.float_64).?.data, 0),889 .float_64 => std.math.order(lhs.castTag(.float_64).?.data, 0),
1349 .float_128 => std.math.order(lhs.castTag(.float_128).?.data, 0),890 .float_128 => std.math.order(lhs.castTag(.float_128).?.data, 0),
891
892 else => unreachable,
1350 };893 };
1351 }894 }
1352895
...@@ -1396,10 +939,12 @@ pub const Value = extern union {...@@ -1396,10 +939,12 @@ pub const Value = extern union {
1396 }939 }
1397940
1398 pub fn eql(a: Value, b: Value) bool {941 pub fn eql(a: Value, b: Value) bool {
1399 if (a.tag() == b.tag()) {942 const a_tag = a.tag();
1400 if (a.tag() == .void_value or a.tag() == .null_value) {943 const b_tag = b.tag();
944 if (a_tag == b_tag) {
945 if (a_tag == .void_value or a_tag == .null_value) {
1401 return true;946 return true;
1402 } else if (a.tag() == .enum_literal) {947 } else if (a_tag == .enum_literal) {
1403 const a_name = a.castTag(.enum_literal).?.data;948 const a_name = a.castTag(.enum_literal).?.data;
1404 const b_name = b.castTag(.enum_literal).?.data;949 const b_name = b.castTag(.enum_literal).?.data;
1405 return std.mem.eql(u8, a_name, b_name);950 return std.mem.eql(u8, a_name, b_name);
...@@ -1416,6 +961,10 @@ pub const Value = extern union {...@@ -1416,6 +961,10 @@ pub const Value = extern union {
1416 return compare(a, .eq, b);961 return compare(a, .eq, b);
1417 }962 }
1418963
964 pub fn hash_u32(self: Value) u32 {
965 return @truncate(u32, self.hash());
966 }
967
1419 pub fn hash(self: Value) u64 {968 pub fn hash(self: Value) u64 {
1420 var hasher = std.hash.Wyhash.init(0);969 var hasher = std.hash.Wyhash.init(0);
1421970
...@@ -1493,11 +1042,18 @@ pub const Value = extern union {...@@ -1493,11 +1042,18 @@ pub const Value = extern union {
1493 .zero, .bool_false => std.hash.autoHash(&hasher, @as(u64, 0)),1042 .zero, .bool_false => std.hash.autoHash(&hasher, @as(u64, 0)),
1494 .one, .bool_true => std.hash.autoHash(&hasher, @as(u64, 1)),1043 .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
1497 .enum_literal => {1049 .enum_literal => {
1498 const payload = self.castTag(.enum_literal).?;1050 const payload = self.castTag(.enum_literal).?;
1499 hasher.update(payload.data);1051 hasher.update(payload.data);
1500 },1052 },
1053 .enum_field_index => {
1054 const payload = self.castTag(.enum_field_index).?;
1055 std.hash.autoHash(&hasher, payload.data);
1056 },
1501 .bytes => {1057 .bytes => {
1502 const payload = self.castTag(.bytes).?;1058 const payload = self.castTag(.bytes).?;
1503 hasher.update(payload.data);1059 hasher.update(payload.data);
...@@ -1573,80 +1129,6 @@ pub const Value = extern union {...@@ -1573,80 +1129,6 @@ pub const Value = extern union {
1573 /// Returns error.AnalysisFail if the pointer points to a Decl that failed semantic analysis.1129 /// Returns error.AnalysisFail if the pointer points to a Decl that failed semantic analysis.
1574 pub fn pointerDeref(self: Value, allocator: *Allocator) error{ AnalysisFail, OutOfMemory }!Value {1130 pub fn pointerDeref(self: Value, allocator: *Allocator) error{ AnalysisFail, OutOfMemory }!Value {
1575 return switch (self.tag()) {1131 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
1650 .ref_val => self.castTag(.ref_val).?.data,1132 .ref_val => self.castTag(.ref_val).?.data,
1651 .decl_ref => self.castTag(.decl_ref).?.data.value(),1133 .decl_ref => self.castTag(.decl_ref).?.data.value(),
1652 .elem_ptr => {1134 .elem_ptr => {
...@@ -1654,6 +1136,8 @@ pub const Value = extern union {...@@ -1654,6 +1136,8 @@ pub const Value = extern union {
1654 const array_val = try elem_ptr.array_ptr.pointerDeref(allocator);1136 const array_val = try elem_ptr.array_ptr.pointerDeref(allocator);
1655 return array_val.elemValue(allocator, elem_ptr.index);1137 return array_val.elemValue(allocator, elem_ptr.index);
1656 },1138 },
1139
1140 else => unreachable,
1657 };1141 };
1658 }1142 }
16591143
...@@ -1661,86 +1145,14 @@ pub const Value = extern union {...@@ -1661,86 +1145,14 @@ pub const Value = extern union {
1661 /// or an unknown-length pointer, and returns the element value at the index.1145 /// or an unknown-length pointer, and returns the element value at the index.
1662 pub fn elemValue(self: Value, allocator: *Allocator, index: usize) error{OutOfMemory}!Value {1146 pub fn elemValue(self: Value, allocator: *Allocator, index: usize) error{OutOfMemory}!Value {
1663 switch (self.tag()) {1147 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
1738 .empty_array => unreachable, // out of bounds array index1148 .empty_array => unreachable, // out of bounds array index
17391149
1740 .bytes => return Tag.int_u64.create(allocator, self.castTag(.bytes).?.data[index]),1150 .bytes => return Tag.int_u64.create(allocator, self.castTag(.bytes).?.data[index]),
17411151
1742 // No matter the index; all the elements are the same!1152 // No matter the index; all the elements are the same!
1743 .repeated => return self.castTag(.repeated).?.data,1153 .repeated => return self.castTag(.repeated).?.data,
1154
1155 else => unreachable,
1744 }1156 }
1745 }1157 }
17461158
...@@ -1766,161 +1178,18 @@ pub const Value = extern union {...@@ -1766,161 +1178,18 @@ pub const Value = extern union {
1766 /// Valid for all types. Asserts the value is not undefined and not unreachable.1178 /// Valid for all types. Asserts the value is not undefined and not unreachable.
1767 pub fn isNull(self: Value) bool {1179 pub fn isNull(self: Value) bool {
1768 return switch (self.tag()) {1180 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
1842 .undef => unreachable,1181 .undef => unreachable,
1843 .unreachable_value => unreachable,1182 .unreachable_value => unreachable,
1844 .inferred_alloc => unreachable,1183 .inferred_alloc => unreachable,
1845 .null_value => true,1184 .null_value => true,
1185
1186 else => false,
1846 };1187 };
1847 }1188 }
18481189
1849 /// Valid for all types. Asserts the value is not undefined and not unreachable.1190 /// Valid for all types. Asserts the value is not undefined and not unreachable.
1850 pub fn getError(self: Value) ?[]const u8 {1191 pub fn getError(self: Value) ?[]const u8 {
1851 return switch (self.tag()) {1192 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
1924 .error_union => {1193 .error_union => {
1925 const data = self.castTag(.error_union).?.data;1194 const data = self.castTag(.error_union).?.data;
1926 return if (data.tag() == .@"error")1195 return if (data.tag() == .@"error")
...@@ -1932,6 +1201,8 @@ pub const Value = extern union {...@@ -1932,6 +1201,8 @@ pub const Value = extern union {
1932 .undef => unreachable,1201 .undef => unreachable,
1933 .unreachable_value => unreachable,1202 .unreachable_value => unreachable,
1934 .inferred_alloc => unreachable,1203 .inferred_alloc => unreachable,
1204
1205 else => null,
1935 };1206 };
1936 }1207 }
1937 /// Valid for all types. Asserts the value is not undefined.1208 /// Valid for all types. Asserts the value is not undefined.
...@@ -2021,6 +1292,7 @@ pub const Value = extern union {...@@ -2021,6 +1292,7 @@ pub const Value = extern union {
2021 .float_128,1292 .float_128,
2022 .void_value,1293 .void_value,
2023 .enum_literal,1294 .enum_literal,
1295 .enum_field_index,
2024 .@"error",1296 .@"error",
2025 .error_union,1297 .error_union,
2026 .empty_struct_value,1298 .empty_struct_value,
...@@ -2038,6 +1310,11 @@ pub const Value = extern union {...@@ -2038,6 +1310,11 @@ pub const Value = extern union {
2038 pub const Payload = struct {1310 pub const Payload = struct {
2039 tag: Tag,1311 tag: Tag,
20401312
1313 pub const U32 = struct {
1314 base: Payload,
1315 data: u32,
1316 };
1317
2041 pub const U64 = struct {1318 pub const U64 = struct {
2042 base: Payload,1319 base: Payload,
2043 data: u64,1320 data: u64,
src/zir.zig+72-23
...@@ -37,8 +37,6 @@ pub const Code = struct {...@@ -37,8 +37,6 @@ pub const Code = struct {
37 string_bytes: []u8,37 string_bytes: []u8,
38 /// The meaning of this data is determined by `Inst.Tag` value.38 /// The meaning of this data is determined by `Inst.Tag` value.
39 extra: []u32,39 extra: []u32,
40 /// Used for decl_val and decl_ref instructions.
41 decls: []*Module.Decl,
4240
43 /// Returns the requested data, as well as the new index which is at the start of the41 /// Returns the requested data, as well as the new index which is at the start of the
44 /// trailers for the object.42 /// trailers for the object.
...@@ -78,7 +76,6 @@ pub const Code = struct {...@@ -78,7 +76,6 @@ pub const Code = struct {
78 code.instructions.deinit(gpa);76 code.instructions.deinit(gpa);
79 gpa.free(code.string_bytes);77 gpa.free(code.string_bytes);
80 gpa.free(code.extra);78 gpa.free(code.extra);
81 gpa.free(code.decls);
82 code.* = undefined;79 code.* = undefined;
83 }80 }
8481
...@@ -133,7 +130,7 @@ pub const Inst = struct {...@@ -133,7 +130,7 @@ pub const Inst = struct {
133 /// Same as `alloc` except mutable.130 /// Same as `alloc` except mutable.
134 alloc_mut,131 alloc_mut,
135 /// Same as `alloc` except the type is inferred.132 /// Same as `alloc` except the type is inferred.
136 /// The operand is unused.133 /// Uses the `node` union field.
137 alloc_inferred,134 alloc_inferred,
138 /// Same as `alloc_inferred` except mutable.135 /// Same as `alloc_inferred` except mutable.
139 alloc_inferred_mut,136 alloc_inferred_mut,
...@@ -267,9 +264,6 @@ pub const Inst = struct {...@@ -267,9 +264,6 @@ pub const Inst = struct {
267 /// only the taken branch is analyzed. The then block and else block must264 /// only the taken branch is analyzed. The then block and else block must
268 /// terminate with an "inline" variant of a noreturn instruction.265 /// terminate with an "inline" variant of a noreturn instruction.
269 condbr_inline,266 condbr_inline,
270 /// A comptime known value.
271 /// Uses the `const` union field.
272 @"const",
273 /// A struct type definition. Contains references to ZIR instructions for267 /// A struct type definition. Contains references to ZIR instructions for
274 /// the field types, defaults, and alignments.268 /// the field types, defaults, and alignments.
275 /// Uses the `pl_node` union field. Payload is `StructDecl`.269 /// Uses the `pl_node` union field. Payload is `StructDecl`.
...@@ -286,6 +280,8 @@ pub const Inst = struct {...@@ -286,6 +280,8 @@ pub const Inst = struct {
286 /// the field value expressions and optional type tag expression.280 /// the field value expressions and optional type tag expression.
287 /// Uses the `pl_node` union field. Payload is `EnumDecl`.281 /// Uses the `pl_node` union field. Payload is `EnumDecl`.
288 enum_decl,282 enum_decl,
283 /// Same as `enum_decl`, except the enum is non-exhaustive.
284 enum_decl_nonexhaustive,
289 /// An opaque type definition. Provides an AST node only.285 /// An opaque type definition. Provides an AST node only.
290 /// Uses the `node` union field.286 /// Uses the `node` union field.
291 opaque_decl,287 opaque_decl,
...@@ -369,6 +365,11 @@ pub const Inst = struct {...@@ -369,6 +365,11 @@ pub const Inst = struct {
369 import,365 import,
370 /// Integer literal that fits in a u64. Uses the int union value.366 /// Integer literal that fits in a u64. Uses the int union value.
371 int,367 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,
372 /// Convert an integer value to another integer type, asserting that the destination type373 /// Convert an integer value to another integer type, asserting that the destination type
373 /// can hold the same mathematical value.374 /// can hold the same mathematical value.
374 /// Uses the `pl_node` field. AST is the `@intCast` syntax.375 /// Uses the `pl_node` field. AST is the `@intCast` syntax.
...@@ -667,6 +668,12 @@ pub const Inst = struct {...@@ -667,6 +668,12 @@ pub const Inst = struct {
667 /// A struct literal with a specified type, with no fields.668 /// A struct literal with a specified type, with no fields.
668 /// Uses the `un_node` field.669 /// Uses the `un_node` field.
669 struct_init_empty,670 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
671 /// Returns whether the instruction is one of the control flow "noreturn" types.678 /// Returns whether the instruction is one of the control flow "noreturn" types.
672 /// Function calls do not count.679 /// Function calls do not count.
...@@ -712,12 +719,12 @@ pub const Inst = struct {...@@ -712,12 +719,12 @@ pub const Inst = struct {
712 .cmp_gt,719 .cmp_gt,
713 .cmp_neq,720 .cmp_neq,
714 .coerce_result_ptr,721 .coerce_result_ptr,
715 .@"const",
716 .struct_decl,722 .struct_decl,
717 .struct_decl_packed,723 .struct_decl_packed,
718 .struct_decl_extern,724 .struct_decl_extern,
719 .union_decl,725 .union_decl,
720 .enum_decl,726 .enum_decl,
727 .enum_decl_nonexhaustive,
721 .opaque_decl,728 .opaque_decl,
722 .dbg_stmt_node,729 .dbg_stmt_node,
723 .decl_ref,730 .decl_ref,
...@@ -740,6 +747,8 @@ pub const Inst = struct {...@@ -740,6 +747,8 @@ pub const Inst = struct {
740 .fn_type_cc,747 .fn_type_cc,
741 .fn_type_cc_var_args,748 .fn_type_cc_var_args,
742 .int,749 .int,
750 .float,
751 .float128,
743 .intcast,752 .intcast,
744 .int_type,753 .int_type,
745 .is_non_null,754 .is_non_null,
...@@ -822,6 +831,8 @@ pub const Inst = struct {...@@ -822,6 +831,8 @@ pub const Inst = struct {
822 .switch_block_ref_under_multi,831 .switch_block_ref_under_multi,
823 .validate_struct_init_ptr,832 .validate_struct_init_ptr,
824 .struct_init_empty,833 .struct_init_empty,
834 .int_to_enum,
835 .enum_to_int,
825 => false,836 => false,
826837
827 .@"break",838 .@"break",
...@@ -1184,7 +1195,6 @@ pub const Inst = struct {...@@ -1184,7 +1195,6 @@ pub const Inst = struct {
1184 }1195 }
1185 },1196 },
1186 bin: Bin,1197 bin: Bin,
1187 @"const": *TypedValue,
1188 /// For strings which may contain null bytes.1198 /// For strings which may contain null bytes.
1189 str: struct {1199 str: struct {
1190 /// Offset into `string_bytes`.1200 /// Offset into `string_bytes`.
...@@ -1226,6 +1236,16 @@ pub const Inst = struct {...@@ -1226,6 +1236,16 @@ pub const Inst = struct {
1226 /// Offset from Decl AST node index.1236 /// Offset from Decl AST node index.
1227 node: i32,1237 node: i32,
1228 int: u64,1238 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 },
1229 array_type_sentinel: struct {1249 array_type_sentinel: struct {
1230 len: Ref,1250 len: Ref,
1231 /// index into extra, points to an `ArrayTypeSentinel`1251 /// index into extra, points to an `ArrayTypeSentinel`
...@@ -1507,6 +1527,22 @@ pub const Inst = struct {...@@ -1507,6 +1527,22 @@ pub const Inst = struct {
1507 tag_type: Ref,1527 tag_type: Ref,
1508 fields_len: u32,1528 fields_len: u32,
1509 };1529 };
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 };
1510};1546};
15111547
1512pub const SpecialProng = enum { none, @"else", under };1548pub const SpecialProng = enum { none, @"else", under };
...@@ -1536,12 +1572,11 @@ const Writer = struct {...@@ -1536,12 +1572,11 @@ const Writer = struct {
1536 .intcast,1572 .intcast,
1537 .store,1573 .store,
1538 .store_to_block_ptr,1574 .store_to_block_ptr,
1575 .store_to_inferred_ptr,
1539 => try self.writeBin(stream, inst),1576 => try self.writeBin(stream, inst),
15401577
1541 .alloc,1578 .alloc,
1542 .alloc_mut,1579 .alloc_mut,
1543 .alloc_inferred,
1544 .alloc_inferred_mut,
1545 .indexable_ptr_len,1580 .indexable_ptr_len,
1546 .bit_not,1581 .bit_not,
1547 .bool_not,1582 .bool_not,
...@@ -1581,6 +1616,7 @@ const Writer = struct {...@@ -1581,6 +1616,7 @@ const Writer = struct {
1581 .typeof,1616 .typeof,
1582 .typeof_elem,1617 .typeof_elem,
1583 .struct_init_empty,1618 .struct_init_empty,
1619 .enum_to_int,
1584 => try self.writeUnNode(stream, inst),1620 => try self.writeUnNode(stream, inst),
15851621
1586 .ref,1622 .ref,
...@@ -1594,11 +1630,12 @@ const Writer = struct {...@@ -1594,11 +1630,12 @@ const Writer = struct {
1594 => try self.writeBoolBr(stream, inst),1630 => try self.writeBoolBr(stream, inst),
15951631
1596 .array_type_sentinel => try self.writeArrayTypeSentinel(stream, inst),1632 .array_type_sentinel => try self.writeArrayTypeSentinel(stream, inst),
1597 .@"const" => try self.writeConst(stream, inst),
1598 .param_type => try self.writeParamType(stream, inst),1633 .param_type => try self.writeParamType(stream, inst),
1599 .ptr_type_simple => try self.writePtrTypeSimple(stream, inst),1634 .ptr_type_simple => try self.writePtrTypeSimple(stream, inst),
1600 .ptr_type => try self.writePtrType(stream, inst),1635 .ptr_type => try self.writePtrType(stream, inst),
1601 .int => try self.writeInt(stream, inst),1636 .int => try self.writeInt(stream, inst),
1637 .float => try self.writeFloat(stream, inst),
1638 .float128 => try self.writeFloat128(stream, inst),
1602 .str => try self.writeStr(stream, inst),1639 .str => try self.writeStr(stream, inst),
1603 .elided => try stream.writeAll(")"),1640 .elided => try stream.writeAll(")"),
1604 .int_type => try self.writeIntType(stream, inst),1641 .int_type => try self.writeIntType(stream, inst),
...@@ -1619,6 +1656,7 @@ const Writer = struct {...@@ -1619,6 +1656,7 @@ const Writer = struct {
1619 .slice_sentinel,1656 .slice_sentinel,
1620 .union_decl,1657 .union_decl,
1621 .enum_decl,1658 .enum_decl,
1659 .enum_decl_nonexhaustive,
1622 => try self.writePlNode(stream, inst),1660 => try self.writePlNode(stream, inst),
16231661
1624 .add,1662 .add,
...@@ -1647,6 +1685,7 @@ const Writer = struct {...@@ -1647,6 +1685,7 @@ const Writer = struct {
1647 .merge_error_sets,1685 .merge_error_sets,
1648 .bit_and,1686 .bit_and,
1649 .bit_or,1687 .bit_or,
1688 .int_to_enum,
1650 => try self.writePlNodeBin(stream, inst),1689 => try self.writePlNodeBin(stream, inst),
16511690
1652 .call,1691 .call,
...@@ -1704,6 +1743,8 @@ const Writer = struct {...@@ -1704,6 +1743,8 @@ const Writer = struct {
1704 .ret_type,1743 .ret_type,
1705 .repeat,1744 .repeat,
1706 .repeat_inline,1745 .repeat_inline,
1746 .alloc_inferred,
1747 .alloc_inferred_mut,
1707 => try self.writeNode(stream, inst),1748 => try self.writeNode(stream, inst),
17081749
1709 .error_value,1750 .error_value,
...@@ -1729,7 +1770,6 @@ const Writer = struct {...@@ -1729,7 +1770,6 @@ const Writer = struct {
17291770
1730 .bitcast,1771 .bitcast,
1731 .bitcast_result_ptr,1772 .bitcast_result_ptr,
1732 .store_to_inferred_ptr,
1733 => try stream.writeAll("TODO)"),1773 => try stream.writeAll("TODO)"),
1734 }1774 }
1735 }1775 }
...@@ -1773,15 +1813,6 @@ const Writer = struct {...@@ -1773,15 +1813,6 @@ const Writer = struct {
1773 try stream.writeAll("TODO)");1813 try stream.writeAll("TODO)");
1774 }1814 }
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
1785 fn writeParamType(1816 fn writeParamType(
1786 self: *Writer,1817 self: *Writer,
1787 stream: anytype,1818 stream: anytype,
...@@ -1819,6 +1850,23 @@ const Writer = struct {...@@ -1819,6 +1850,23 @@ const Writer = struct {
1819 try stream.print("{d})", .{inst_data});1850 try stream.print("{d})", .{inst_data});
1820 }1851 }
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
1822 fn writeStr(1870 fn writeStr(
1823 self: *Writer,1871 self: *Writer,
1824 stream: anytype,1872 stream: anytype,
...@@ -2136,7 +2184,8 @@ const Writer = struct {...@@ -2136,7 +2184,8 @@ const Writer = struct {
21362184
2137 fn writePlNodeDecl(self: *Writer, stream: anytype, inst: Inst.Index) !void {2185 fn writePlNodeDecl(self: *Writer, stream: anytype, inst: Inst.Index) !void {
2138 const inst_data = self.code.instructions.items(.data)[inst].pl_node;2186 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;
2140 try stream.print("{s}) ", .{decl.name});2189 try stream.print("{s}) ", .{decl.name});
2141 try self.writeSrc(stream, inst_data.src());2190 try self.writeSrc(stream, inst_data.src());
2142 }2191 }
test/stage2/cbe.zig+251-2
...@@ -517,7 +517,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -517,7 +517,7 @@ pub fn addCases(ctx: *TestContext) !void {
517 \\}517 \\}
518 , &.{518 , &.{
519 ":3:21: error: mising struct field: x",519 ":3:21: error: mising struct field: x",
520 ":1:15: note: 'Point' declared here",520 ":1:15: note: struct 'Point' declared here",
521 });521 });
522 case.addError(522 case.addError(
523 \\const Point = struct { x: i32, y: i32 };523 \\const Point = struct { x: i32, y: i32 };
...@@ -531,7 +531,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -531,7 +531,7 @@ pub fn addCases(ctx: *TestContext) !void {
531 \\}531 \\}
532 , &.{532 , &.{
533 ":6:10: error: no field named 'z' in struct 'Point'",533 ":6:10: error: no field named 'z' in struct 'Point'",
534 ":1:15: note: 'Point' declared here",534 ":1:15: note: struct declared here",
535 });535 });
536 case.addCompareOutput(536 case.addCompareOutput(
537 \\const Point = struct { x: i32, y: i32 };537 \\const Point = struct { x: i32, y: i32 };
...@@ -545,6 +545,255 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -545,6 +545,255 @@ pub fn addCases(ctx: *TestContext) !void {
545 , "");545 , "");
546 }546 }
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
548 ctx.c("empty start function", linux_x64,797 ctx.c("empty start function", linux_x64,
549 \\export fn _start() noreturn {798 \\export fn _start() noreturn {
550 \\ unreachable;799 \\ unreachable;