zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

blob eacbd4e9 (55129B) - Raw


      1 const std = @import("std");
      2 const Type = @import("type.zig").Type;
      3 const log2 = std.math.log2;
      4 const assert = std.debug.assert;
      5 const BigIntConst = std.math.big.int.Const;
      6 const BigIntMutable = std.math.big.int.Mutable;
      7 const Target = std.Target;
      8 const Allocator = std.mem.Allocator;
      9 const Module = @import("Module.zig");
     10 
     11 /// This is the raw data, with no bookkeeping, no memory awareness,
     12 /// no de-duplication, and no type system awareness.
     13 /// It's important for this type to be small.
     14 /// This union takes advantage of the fact that the first page of memory
     15 /// is unmapped, giving us 4096 possible enum tags that have no payload.
     16 pub const Value = extern union {
     17     /// If the tag value is less than Tag.no_payload_count, then no pointer
     18     /// dereference is needed.
     19     tag_if_small_enough: usize,
     20     ptr_otherwise: *Payload,
     21 
     22     pub const Tag = enum {
     23         // The first section of this enum are tags that require no payload.
     24         u8_type,
     25         i8_type,
     26         u16_type,
     27         i16_type,
     28         u32_type,
     29         i32_type,
     30         u64_type,
     31         i64_type,
     32         usize_type,
     33         isize_type,
     34         c_short_type,
     35         c_ushort_type,
     36         c_int_type,
     37         c_uint_type,
     38         c_long_type,
     39         c_ulong_type,
     40         c_longlong_type,
     41         c_ulonglong_type,
     42         c_longdouble_type,
     43         f16_type,
     44         f32_type,
     45         f64_type,
     46         f128_type,
     47         c_void_type,
     48         bool_type,
     49         void_type,
     50         type_type,
     51         anyerror_type,
     52         comptime_int_type,
     53         comptime_float_type,
     54         noreturn_type,
     55         null_type,
     56         undefined_type,
     57         fn_noreturn_no_args_type,
     58         fn_void_no_args_type,
     59         fn_naked_noreturn_no_args_type,
     60         fn_ccc_void_no_args_type,
     61         single_const_pointer_to_comptime_int_type,
     62         const_slice_u8_type,
     63         enum_literal_type,
     64         anyframe_type,
     65 
     66         undef,
     67         zero,
     68         void_value,
     69         unreachable_value,
     70         empty_array,
     71         null_value,
     72         bool_true,
     73         bool_false, // See last_no_payload_tag below.
     74         // After this, the tag requires a payload.
     75 
     76         ty,
     77         int_type,
     78         int_u64,
     79         int_i64,
     80         int_big_positive,
     81         int_big_negative,
     82         function,
     83         variable,
     84         ref_val,
     85         decl_ref,
     86         elem_ptr,
     87         bytes,
     88         repeated, // the value is a value repeated some number of times
     89         float_16,
     90         float_32,
     91         float_64,
     92         float_128,
     93         enum_literal,
     94         error_set,
     95         @"error",
     96 
     97         pub const last_no_payload_tag = Tag.bool_false;
     98         pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
     99     };
    100 
    101     pub fn initTag(small_tag: Tag) Value {
    102         assert(@enumToInt(small_tag) < Tag.no_payload_count);
    103         return .{ .tag_if_small_enough = @enumToInt(small_tag) };
    104     }
    105 
    106     pub fn initPayload(payload: *Payload) Value {
    107         assert(@enumToInt(payload.tag) >= Tag.no_payload_count);
    108         return .{ .ptr_otherwise = payload };
    109     }
    110 
    111     pub fn tag(self: Value) Tag {
    112         if (self.tag_if_small_enough < Tag.no_payload_count) {
    113             return @intToEnum(Tag, @intCast(@TagType(Tag), self.tag_if_small_enough));
    114         } else {
    115             return self.ptr_otherwise.tag;
    116         }
    117     }
    118 
    119     pub fn cast(self: Value, comptime T: type) ?*T {
    120         if (self.tag_if_small_enough < Tag.no_payload_count)
    121             return null;
    122 
    123         const expected_tag = std.meta.fieldInfo(T, "base").default_value.?.tag;
    124         if (self.ptr_otherwise.tag != expected_tag)
    125             return null;
    126 
    127         return @fieldParentPtr(T, "base", self.ptr_otherwise);
    128     }
    129 
    130     pub fn copy(self: Value, allocator: *Allocator) error{OutOfMemory}!Value {
    131         if (self.tag_if_small_enough < Tag.no_payload_count) {
    132             return Value{ .tag_if_small_enough = self.tag_if_small_enough };
    133         } else switch (self.ptr_otherwise.tag) {
    134             .u8_type,
    135             .i8_type,
    136             .u16_type,
    137             .i16_type,
    138             .u32_type,
    139             .i32_type,
    140             .u64_type,
    141             .i64_type,
    142             .usize_type,
    143             .isize_type,
    144             .c_short_type,
    145             .c_ushort_type,
    146             .c_int_type,
    147             .c_uint_type,
    148             .c_long_type,
    149             .c_ulong_type,
    150             .c_longlong_type,
    151             .c_ulonglong_type,
    152             .c_longdouble_type,
    153             .f16_type,
    154             .f32_type,
    155             .f64_type,
    156             .f128_type,
    157             .c_void_type,
    158             .bool_type,
    159             .void_type,
    160             .type_type,
    161             .anyerror_type,
    162             .comptime_int_type,
    163             .comptime_float_type,
    164             .noreturn_type,
    165             .null_type,
    166             .undefined_type,
    167             .fn_noreturn_no_args_type,
    168             .fn_void_no_args_type,
    169             .fn_naked_noreturn_no_args_type,
    170             .fn_ccc_void_no_args_type,
    171             .single_const_pointer_to_comptime_int_type,
    172             .const_slice_u8_type,
    173             .enum_literal_type,
    174             .anyframe_type,
    175             .undef,
    176             .zero,
    177             .void_value,
    178             .unreachable_value,
    179             .empty_array,
    180             .null_value,
    181             .bool_true,
    182             .bool_false,
    183             => unreachable,
    184 
    185             .ty => {
    186                 const payload = @fieldParentPtr(Payload.Ty, "base", self.ptr_otherwise);
    187                 const new_payload = try allocator.create(Payload.Ty);
    188                 new_payload.* = .{
    189                     .base = payload.base,
    190                     .ty = try payload.ty.copy(allocator),
    191                 };
    192                 return Value{ .ptr_otherwise = &new_payload.base };
    193             },
    194             .int_type => return self.copyPayloadShallow(allocator, Payload.IntType),
    195             .int_u64 => return self.copyPayloadShallow(allocator, Payload.Int_u64),
    196             .int_i64 => return self.copyPayloadShallow(allocator, Payload.Int_i64),
    197             .int_big_positive => {
    198                 @panic("TODO implement copying of big ints");
    199             },
    200             .int_big_negative => {
    201                 @panic("TODO implement copying of big ints");
    202             },
    203             .function => return self.copyPayloadShallow(allocator, Payload.Function),
    204             .variable => return self.copyPayloadShallow(allocator, Payload.Variable),
    205             .ref_val => {
    206                 const payload = @fieldParentPtr(Payload.RefVal, "base", self.ptr_otherwise);
    207                 const new_payload = try allocator.create(Payload.RefVal);
    208                 new_payload.* = .{
    209                     .base = payload.base,
    210                     .val = try payload.val.copy(allocator),
    211                 };
    212                 return Value{ .ptr_otherwise = &new_payload.base };
    213             },
    214             .decl_ref => return self.copyPayloadShallow(allocator, Payload.DeclRef),
    215             .elem_ptr => {
    216                 const payload = @fieldParentPtr(Payload.ElemPtr, "base", self.ptr_otherwise);
    217                 const new_payload = try allocator.create(Payload.ElemPtr);
    218                 new_payload.* = .{
    219                     .base = payload.base,
    220                     .array_ptr = try payload.array_ptr.copy(allocator),
    221                     .index = payload.index,
    222                 };
    223                 return Value{ .ptr_otherwise = &new_payload.base };
    224             },
    225             .bytes => return self.copyPayloadShallow(allocator, Payload.Bytes),
    226             .repeated => {
    227                 const payload = @fieldParentPtr(Payload.Repeated, "base", self.ptr_otherwise);
    228                 const new_payload = try allocator.create(Payload.Repeated);
    229                 new_payload.* = .{
    230                     .base = payload.base,
    231                     .val = try payload.val.copy(allocator),
    232                 };
    233                 return Value{ .ptr_otherwise = &new_payload.base };
    234             },
    235             .float_16 => return self.copyPayloadShallow(allocator, Payload.Float_16),
    236             .float_32 => return self.copyPayloadShallow(allocator, Payload.Float_32),
    237             .float_64 => return self.copyPayloadShallow(allocator, Payload.Float_64),
    238             .float_128 => return self.copyPayloadShallow(allocator, Payload.Float_128),
    239             .enum_literal => {
    240                 const payload = @fieldParentPtr(Payload.Bytes, "base", self.ptr_otherwise);
    241                 const new_payload = try allocator.create(Payload.Bytes);
    242                 new_payload.* = .{
    243                     .base = payload.base,
    244                     .data = try allocator.dupe(u8, payload.data),
    245                 };
    246                 return Value{ .ptr_otherwise = &new_payload.base };
    247             },
    248             .@"error" => return self.copyPayloadShallow(allocator, Payload.Error),
    249 
    250             // memory is managed by the declaration
    251             .error_set => return self.copyPayloadShallow(allocator, Payload.ErrorSet),
    252         }
    253     }
    254 
    255     fn copyPayloadShallow(self: Value, allocator: *Allocator, comptime T: type) error{OutOfMemory}!Value {
    256         const payload = @fieldParentPtr(T, "base", self.ptr_otherwise);
    257         const new_payload = try allocator.create(T);
    258         new_payload.* = payload.*;
    259         return Value{ .ptr_otherwise = &new_payload.base };
    260     }
    261 
    262     pub fn format(
    263         self: Value,
    264         comptime fmt: []const u8,
    265         options: std.fmt.FormatOptions,
    266         out_stream: anytype,
    267     ) !void {
    268         comptime assert(fmt.len == 0);
    269         var val = self;
    270         while (true) switch (val.tag()) {
    271             .u8_type => return out_stream.writeAll("u8"),
    272             .i8_type => return out_stream.writeAll("i8"),
    273             .u16_type => return out_stream.writeAll("u16"),
    274             .i16_type => return out_stream.writeAll("i16"),
    275             .u32_type => return out_stream.writeAll("u32"),
    276             .i32_type => return out_stream.writeAll("i32"),
    277             .u64_type => return out_stream.writeAll("u64"),
    278             .i64_type => return out_stream.writeAll("i64"),
    279             .isize_type => return out_stream.writeAll("isize"),
    280             .usize_type => return out_stream.writeAll("usize"),
    281             .c_short_type => return out_stream.writeAll("c_short"),
    282             .c_ushort_type => return out_stream.writeAll("c_ushort"),
    283             .c_int_type => return out_stream.writeAll("c_int"),
    284             .c_uint_type => return out_stream.writeAll("c_uint"),
    285             .c_long_type => return out_stream.writeAll("c_long"),
    286             .c_ulong_type => return out_stream.writeAll("c_ulong"),
    287             .c_longlong_type => return out_stream.writeAll("c_longlong"),
    288             .c_ulonglong_type => return out_stream.writeAll("c_ulonglong"),
    289             .c_longdouble_type => return out_stream.writeAll("c_longdouble"),
    290             .f16_type => return out_stream.writeAll("f16"),
    291             .f32_type => return out_stream.writeAll("f32"),
    292             .f64_type => return out_stream.writeAll("f64"),
    293             .f128_type => return out_stream.writeAll("f128"),
    294             .c_void_type => return out_stream.writeAll("c_void"),
    295             .bool_type => return out_stream.writeAll("bool"),
    296             .void_type => return out_stream.writeAll("void"),
    297             .type_type => return out_stream.writeAll("type"),
    298             .anyerror_type => return out_stream.writeAll("anyerror"),
    299             .comptime_int_type => return out_stream.writeAll("comptime_int"),
    300             .comptime_float_type => return out_stream.writeAll("comptime_float"),
    301             .noreturn_type => return out_stream.writeAll("noreturn"),
    302             .null_type => return out_stream.writeAll("@TypeOf(null)"),
    303             .undefined_type => return out_stream.writeAll("@TypeOf(undefined)"),
    304             .fn_noreturn_no_args_type => return out_stream.writeAll("fn() noreturn"),
    305             .fn_void_no_args_type => return out_stream.writeAll("fn() void"),
    306             .fn_naked_noreturn_no_args_type => return out_stream.writeAll("fn() callconv(.Naked) noreturn"),
    307             .fn_ccc_void_no_args_type => return out_stream.writeAll("fn() callconv(.C) void"),
    308             .single_const_pointer_to_comptime_int_type => return out_stream.writeAll("*const comptime_int"),
    309             .const_slice_u8_type => return out_stream.writeAll("[]const u8"),
    310             .enum_literal_type => return out_stream.writeAll("@TypeOf(.EnumLiteral)"),
    311             .anyframe_type => return out_stream.writeAll("anyframe"),
    312 
    313             .null_value => return out_stream.writeAll("null"),
    314             .undef => return out_stream.writeAll("undefined"),
    315             .zero => return out_stream.writeAll("0"),
    316             .void_value => return out_stream.writeAll("{}"),
    317             .unreachable_value => return out_stream.writeAll("unreachable"),
    318             .bool_true => return out_stream.writeAll("true"),
    319             .bool_false => return out_stream.writeAll("false"),
    320             .ty => return val.cast(Payload.Ty).?.ty.format("", options, out_stream),
    321             .int_type => {
    322                 const int_type = val.cast(Payload.IntType).?;
    323                 return out_stream.print("{}{}", .{
    324                     if (int_type.signed) "s" else "u",
    325                     int_type.bits,
    326                 });
    327             },
    328             .int_u64 => return std.fmt.formatIntValue(val.cast(Payload.Int_u64).?.int, "", options, out_stream),
    329             .int_i64 => return std.fmt.formatIntValue(val.cast(Payload.Int_i64).?.int, "", options, out_stream),
    330             .int_big_positive => return out_stream.print("{}", .{val.cast(Payload.IntBigPositive).?.asBigInt()}),
    331             .int_big_negative => return out_stream.print("{}", .{val.cast(Payload.IntBigNegative).?.asBigInt()}),
    332             .function => return out_stream.writeAll("(function)"),
    333             .variable => return out_stream.writeAll("(variable)"),
    334             .ref_val => {
    335                 const ref_val = val.cast(Payload.RefVal).?;
    336                 try out_stream.writeAll("&const ");
    337                 val = ref_val.val;
    338             },
    339             .decl_ref => return out_stream.writeAll("(decl ref)"),
    340             .elem_ptr => {
    341                 const elem_ptr = val.cast(Payload.ElemPtr).?;
    342                 try out_stream.print("&[{}] ", .{elem_ptr.index});
    343                 val = elem_ptr.array_ptr;
    344             },
    345             .empty_array => return out_stream.writeAll(".{}"),
    346             .enum_literal, .bytes => return std.zig.renderStringLiteral(self.cast(Payload.Bytes).?.data, out_stream),
    347             .repeated => {
    348                 try out_stream.writeAll("(repeated) ");
    349                 val = val.cast(Payload.Repeated).?.val;
    350             },
    351             .float_16 => return out_stream.print("{}", .{val.cast(Payload.Float_16).?.val}),
    352             .float_32 => return out_stream.print("{}", .{val.cast(Payload.Float_32).?.val}),
    353             .float_64 => return out_stream.print("{}", .{val.cast(Payload.Float_64).?.val}),
    354             .float_128 => return out_stream.print("{}", .{val.cast(Payload.Float_128).?.val}),
    355             .error_set => {
    356                 const error_set = val.cast(Payload.ErrorSet).?;
    357                 try out_stream.writeAll("error{");
    358                 for (error_set.fields.items()) |entry| {
    359                     try out_stream.print("{},", .{entry.value});
    360                 }
    361                 return out_stream.writeAll("}");
    362             },
    363             .@"error" => return out_stream.print("error.{}", .{val.cast(Payload.Error).?.name}),
    364         };
    365     }
    366 
    367     /// Asserts that the value is representable as an array of bytes.
    368     /// Copies the value into a freshly allocated slice of memory, which is owned by the caller.
    369     pub fn toAllocatedBytes(self: Value, allocator: *Allocator) ![]u8 {
    370         if (self.cast(Payload.Bytes)) |bytes| {
    371             return std.mem.dupe(allocator, u8, bytes.data);
    372         }
    373         if (self.cast(Payload.Repeated)) |repeated| {
    374             @panic("TODO implement toAllocatedBytes for this Value tag");
    375         }
    376         if (self.cast(Payload.DeclRef)) |declref| {
    377             const val = try declref.decl.value();
    378             return val.toAllocatedBytes(allocator);
    379         }
    380         unreachable;
    381     }
    382 
    383     /// Asserts that the value is representable as a type.
    384     pub fn toType(self: Value) Type {
    385         return switch (self.tag()) {
    386             .ty => self.cast(Payload.Ty).?.ty,
    387             .int_type => @panic("TODO int type to type"),
    388 
    389             .u8_type => Type.initTag(.u8),
    390             .i8_type => Type.initTag(.i8),
    391             .u16_type => Type.initTag(.u16),
    392             .i16_type => Type.initTag(.i16),
    393             .u32_type => Type.initTag(.u32),
    394             .i32_type => Type.initTag(.i32),
    395             .u64_type => Type.initTag(.u64),
    396             .i64_type => Type.initTag(.i64),
    397             .usize_type => Type.initTag(.usize),
    398             .isize_type => Type.initTag(.isize),
    399             .c_short_type => Type.initTag(.c_short),
    400             .c_ushort_type => Type.initTag(.c_ushort),
    401             .c_int_type => Type.initTag(.c_int),
    402             .c_uint_type => Type.initTag(.c_uint),
    403             .c_long_type => Type.initTag(.c_long),
    404             .c_ulong_type => Type.initTag(.c_ulong),
    405             .c_longlong_type => Type.initTag(.c_longlong),
    406             .c_ulonglong_type => Type.initTag(.c_ulonglong),
    407             .c_longdouble_type => Type.initTag(.c_longdouble),
    408             .f16_type => Type.initTag(.f16),
    409             .f32_type => Type.initTag(.f32),
    410             .f64_type => Type.initTag(.f64),
    411             .f128_type => Type.initTag(.f128),
    412             .c_void_type => Type.initTag(.c_void),
    413             .bool_type => Type.initTag(.bool),
    414             .void_type => Type.initTag(.void),
    415             .type_type => Type.initTag(.type),
    416             .anyerror_type => Type.initTag(.anyerror),
    417             .comptime_int_type => Type.initTag(.comptime_int),
    418             .comptime_float_type => Type.initTag(.comptime_float),
    419             .noreturn_type => Type.initTag(.noreturn),
    420             .null_type => Type.initTag(.@"null"),
    421             .undefined_type => Type.initTag(.@"undefined"),
    422             .fn_noreturn_no_args_type => Type.initTag(.fn_noreturn_no_args),
    423             .fn_void_no_args_type => Type.initTag(.fn_void_no_args),
    424             .fn_naked_noreturn_no_args_type => Type.initTag(.fn_naked_noreturn_no_args),
    425             .fn_ccc_void_no_args_type => Type.initTag(.fn_ccc_void_no_args),
    426             .single_const_pointer_to_comptime_int_type => Type.initTag(.single_const_pointer_to_comptime_int),
    427             .const_slice_u8_type => Type.initTag(.const_slice_u8),
    428             .enum_literal_type => Type.initTag(.enum_literal),
    429             .anyframe_type => Type.initTag(.@"anyframe"),
    430             .error_set => @panic("TODO error set to type"),
    431 
    432             .undef,
    433             .zero,
    434             .void_value,
    435             .unreachable_value,
    436             .empty_array,
    437             .bool_true,
    438             .bool_false,
    439             .null_value,
    440             .int_u64,
    441             .int_i64,
    442             .int_big_positive,
    443             .int_big_negative,
    444             .function,
    445             .variable,
    446             .ref_val,
    447             .decl_ref,
    448             .elem_ptr,
    449             .bytes,
    450             .repeated,
    451             .float_16,
    452             .float_32,
    453             .float_64,
    454             .float_128,
    455             .enum_literal,
    456             .@"error",
    457             => unreachable,
    458         };
    459     }
    460 
    461     /// Asserts the value is an integer.
    462     pub fn toBigInt(self: Value, space: *BigIntSpace) BigIntConst {
    463         switch (self.tag()) {
    464             .ty,
    465             .int_type,
    466             .u8_type,
    467             .i8_type,
    468             .u16_type,
    469             .i16_type,
    470             .u32_type,
    471             .i32_type,
    472             .u64_type,
    473             .i64_type,
    474             .usize_type,
    475             .isize_type,
    476             .c_short_type,
    477             .c_ushort_type,
    478             .c_int_type,
    479             .c_uint_type,
    480             .c_long_type,
    481             .c_ulong_type,
    482             .c_longlong_type,
    483             .c_ulonglong_type,
    484             .c_longdouble_type,
    485             .f16_type,
    486             .f32_type,
    487             .f64_type,
    488             .f128_type,
    489             .c_void_type,
    490             .bool_type,
    491             .void_type,
    492             .type_type,
    493             .anyerror_type,
    494             .comptime_int_type,
    495             .comptime_float_type,
    496             .noreturn_type,
    497             .null_type,
    498             .undefined_type,
    499             .fn_noreturn_no_args_type,
    500             .fn_void_no_args_type,
    501             .fn_naked_noreturn_no_args_type,
    502             .fn_ccc_void_no_args_type,
    503             .single_const_pointer_to_comptime_int_type,
    504             .const_slice_u8_type,
    505             .enum_literal_type,
    506             .anyframe_type,
    507             .null_value,
    508             .function,
    509             .variable,
    510             .ref_val,
    511             .decl_ref,
    512             .elem_ptr,
    513             .bytes,
    514             .repeated,
    515             .float_16,
    516             .float_32,
    517             .float_64,
    518             .float_128,
    519             .void_value,
    520             .unreachable_value,
    521             .empty_array,
    522             .enum_literal,
    523             .error_set,
    524             .@"error",
    525             => unreachable,
    526 
    527             .undef => unreachable,
    528 
    529             .zero,
    530             .bool_false,
    531             => return BigIntMutable.init(&space.limbs, 0).toConst(),
    532 
    533             .bool_true => return BigIntMutable.init(&space.limbs, 1).toConst(),
    534 
    535             .int_u64 => return BigIntMutable.init(&space.limbs, self.cast(Payload.Int_u64).?.int).toConst(),
    536             .int_i64 => return BigIntMutable.init(&space.limbs, self.cast(Payload.Int_i64).?.int).toConst(),
    537             .int_big_positive => return self.cast(Payload.IntBigPositive).?.asBigInt(),
    538             .int_big_negative => return self.cast(Payload.IntBigPositive).?.asBigInt(),
    539         }
    540     }
    541 
    542     /// Asserts the value is an integer and it fits in a u64
    543     pub fn toUnsignedInt(self: Value) u64 {
    544         switch (self.tag()) {
    545             .ty,
    546             .int_type,
    547             .u8_type,
    548             .i8_type,
    549             .u16_type,
    550             .i16_type,
    551             .u32_type,
    552             .i32_type,
    553             .u64_type,
    554             .i64_type,
    555             .usize_type,
    556             .isize_type,
    557             .c_short_type,
    558             .c_ushort_type,
    559             .c_int_type,
    560             .c_uint_type,
    561             .c_long_type,
    562             .c_ulong_type,
    563             .c_longlong_type,
    564             .c_ulonglong_type,
    565             .c_longdouble_type,
    566             .f16_type,
    567             .f32_type,
    568             .f64_type,
    569             .f128_type,
    570             .c_void_type,
    571             .bool_type,
    572             .void_type,
    573             .type_type,
    574             .anyerror_type,
    575             .comptime_int_type,
    576             .comptime_float_type,
    577             .noreturn_type,
    578             .null_type,
    579             .undefined_type,
    580             .fn_noreturn_no_args_type,
    581             .fn_void_no_args_type,
    582             .fn_naked_noreturn_no_args_type,
    583             .fn_ccc_void_no_args_type,
    584             .single_const_pointer_to_comptime_int_type,
    585             .const_slice_u8_type,
    586             .enum_literal_type,
    587             .anyframe_type,
    588             .null_value,
    589             .function,
    590             .variable,
    591             .ref_val,
    592             .decl_ref,
    593             .elem_ptr,
    594             .bytes,
    595             .repeated,
    596             .float_16,
    597             .float_32,
    598             .float_64,
    599             .float_128,
    600             .void_value,
    601             .unreachable_value,
    602             .empty_array,
    603             .enum_literal,
    604             .error_set,
    605             .@"error",
    606             => unreachable,
    607 
    608             .undef => unreachable,
    609 
    610             .zero,
    611             .bool_false,
    612             => return 0,
    613 
    614             .bool_true => return 1,
    615 
    616             .int_u64 => return self.cast(Payload.Int_u64).?.int,
    617             .int_i64 => return @intCast(u64, self.cast(Payload.Int_i64).?.int),
    618             .int_big_positive => return self.cast(Payload.IntBigPositive).?.asBigInt().to(u64) catch unreachable,
    619             .int_big_negative => return self.cast(Payload.IntBigNegative).?.asBigInt().to(u64) catch unreachable,
    620         }
    621     }
    622 
    623     /// Asserts the value is an integer and it fits in a i64
    624     pub fn toSignedInt(self: Value) i64 {
    625         switch (self.tag()) {
    626             .ty,
    627             .int_type,
    628             .u8_type,
    629             .i8_type,
    630             .u16_type,
    631             .i16_type,
    632             .u32_type,
    633             .i32_type,
    634             .u64_type,
    635             .i64_type,
    636             .usize_type,
    637             .isize_type,
    638             .c_short_type,
    639             .c_ushort_type,
    640             .c_int_type,
    641             .c_uint_type,
    642             .c_long_type,
    643             .c_ulong_type,
    644             .c_longlong_type,
    645             .c_ulonglong_type,
    646             .c_longdouble_type,
    647             .f16_type,
    648             .f32_type,
    649             .f64_type,
    650             .f128_type,
    651             .c_void_type,
    652             .bool_type,
    653             .void_type,
    654             .type_type,
    655             .anyerror_type,
    656             .comptime_int_type,
    657             .comptime_float_type,
    658             .noreturn_type,
    659             .null_type,
    660             .undefined_type,
    661             .fn_noreturn_no_args_type,
    662             .fn_void_no_args_type,
    663             .fn_naked_noreturn_no_args_type,
    664             .fn_ccc_void_no_args_type,
    665             .single_const_pointer_to_comptime_int_type,
    666             .const_slice_u8_type,
    667             .enum_literal_type,
    668             .anyframe_type,
    669             .null_value,
    670             .function,
    671             .variable,
    672             .ref_val,
    673             .decl_ref,
    674             .elem_ptr,
    675             .bytes,
    676             .repeated,
    677             .float_16,
    678             .float_32,
    679             .float_64,
    680             .float_128,
    681             .void_value,
    682             .unreachable_value,
    683             .empty_array,
    684             .enum_literal,
    685             .error_set,
    686             .@"error",
    687             => unreachable,
    688 
    689             .undef => unreachable,
    690 
    691             .zero,
    692             .bool_false,
    693             => return 0,
    694 
    695             .bool_true => return 1,
    696 
    697             .int_u64 => return @intCast(i64, self.cast(Payload.Int_u64).?.int),
    698             .int_i64 => return self.cast(Payload.Int_i64).?.int,
    699             .int_big_positive => return self.cast(Payload.IntBigPositive).?.asBigInt().to(i64) catch unreachable,
    700             .int_big_negative => return self.cast(Payload.IntBigNegative).?.asBigInt().to(i64) catch unreachable,
    701         }
    702     }
    703 
    704     pub fn toBool(self: Value) bool {
    705         return switch (self.tag()) {
    706             .bool_true => true,
    707             .bool_false, .zero => false,
    708             else => unreachable,
    709         };
    710     }
    711 
    712     /// Asserts that the value is a float or an integer.
    713     pub fn toFloat(self: Value, comptime T: type) T {
    714         return switch (self.tag()) {
    715             .float_16 => @panic("TODO soft float"),
    716             .float_32 => @floatCast(T, self.cast(Payload.Float_32).?.val),
    717             .float_64 => @floatCast(T, self.cast(Payload.Float_64).?.val),
    718             .float_128 => @floatCast(T, self.cast(Payload.Float_128).?.val),
    719 
    720             .zero => 0,
    721             .int_u64 => @intToFloat(T, self.cast(Payload.Int_u64).?.int),
    722             .int_i64 => @intToFloat(T, self.cast(Payload.Int_i64).?.int),
    723 
    724             .int_big_positive, .int_big_negative => @panic("big int to f128"),
    725             else => unreachable,
    726         };
    727     }
    728 
    729     /// Asserts the value is an integer and not undefined.
    730     /// Returns the number of bits the value requires to represent stored in twos complement form.
    731     pub fn intBitCountTwosComp(self: Value) usize {
    732         switch (self.tag()) {
    733             .ty,
    734             .int_type,
    735             .u8_type,
    736             .i8_type,
    737             .u16_type,
    738             .i16_type,
    739             .u32_type,
    740             .i32_type,
    741             .u64_type,
    742             .i64_type,
    743             .usize_type,
    744             .isize_type,
    745             .c_short_type,
    746             .c_ushort_type,
    747             .c_int_type,
    748             .c_uint_type,
    749             .c_long_type,
    750             .c_ulong_type,
    751             .c_longlong_type,
    752             .c_ulonglong_type,
    753             .c_longdouble_type,
    754             .f16_type,
    755             .f32_type,
    756             .f64_type,
    757             .f128_type,
    758             .c_void_type,
    759             .bool_type,
    760             .void_type,
    761             .type_type,
    762             .anyerror_type,
    763             .comptime_int_type,
    764             .comptime_float_type,
    765             .noreturn_type,
    766             .null_type,
    767             .undefined_type,
    768             .fn_noreturn_no_args_type,
    769             .fn_void_no_args_type,
    770             .fn_naked_noreturn_no_args_type,
    771             .fn_ccc_void_no_args_type,
    772             .single_const_pointer_to_comptime_int_type,
    773             .const_slice_u8_type,
    774             .enum_literal_type,
    775             .anyframe_type,
    776             .null_value,
    777             .function,
    778             .variable,
    779             .ref_val,
    780             .decl_ref,
    781             .elem_ptr,
    782             .bytes,
    783             .undef,
    784             .repeated,
    785             .float_16,
    786             .float_32,
    787             .float_64,
    788             .float_128,
    789             .void_value,
    790             .unreachable_value,
    791             .empty_array,
    792             .enum_literal,
    793             .error_set,
    794             .@"error",
    795             => unreachable,
    796 
    797             .zero,
    798             .bool_false,
    799             => return 0,
    800 
    801             .bool_true => return 1,
    802 
    803             .int_u64 => {
    804                 const x = self.cast(Payload.Int_u64).?.int;
    805                 if (x == 0) return 0;
    806                 return std.math.log2(x) + 1;
    807             },
    808             .int_i64 => {
    809                 @panic("TODO implement i64 intBitCountTwosComp");
    810             },
    811             .int_big_positive => return self.cast(Payload.IntBigPositive).?.asBigInt().bitCountTwosComp(),
    812             .int_big_negative => return self.cast(Payload.IntBigNegative).?.asBigInt().bitCountTwosComp(),
    813         }
    814     }
    815 
    816     /// Asserts the value is an integer, and the destination type is ComptimeInt or Int.
    817     pub fn intFitsInType(self: Value, ty: Type, target: Target) bool {
    818         switch (self.tag()) {
    819             .ty,
    820             .int_type,
    821             .u8_type,
    822             .i8_type,
    823             .u16_type,
    824             .i16_type,
    825             .u32_type,
    826             .i32_type,
    827             .u64_type,
    828             .i64_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             .anyframe_type,
    862             .null_value,
    863             .function,
    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_set,
    879             .@"error",
    880             => unreachable,
    881 
    882             .zero,
    883             .undef,
    884             .bool_false,
    885             => return true,
    886 
    887             .bool_true => {
    888                 const info = ty.intInfo(target);
    889                 if (info.signed) {
    890                     return info.bits >= 2;
    891                 } else {
    892                     return info.bits >= 1;
    893                 }
    894             },
    895 
    896             .int_u64 => switch (ty.zigTypeTag()) {
    897                 .Int => {
    898                     const x = self.cast(Payload.Int_u64).?.int;
    899                     if (x == 0) return true;
    900                     const info = ty.intInfo(target);
    901                     const needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signed);
    902                     return info.bits >= needed_bits;
    903                 },
    904                 .ComptimeInt => return true,
    905                 else => unreachable,
    906             },
    907             .int_i64 => switch (ty.zigTypeTag()) {
    908                 .Int => {
    909                     const x = self.cast(Payload.Int_i64).?.int;
    910                     if (x == 0) return true;
    911                     const info = ty.intInfo(target);
    912                     if (!info.signed and x < 0)
    913                         return false;
    914                     @panic("TODO implement i64 intFitsInType");
    915                 },
    916                 .ComptimeInt => return true,
    917                 else => unreachable,
    918             },
    919             .int_big_positive => switch (ty.zigTypeTag()) {
    920                 .Int => {
    921                     const info = ty.intInfo(target);
    922                     return self.cast(Payload.IntBigPositive).?.asBigInt().fitsInTwosComp(info.signed, info.bits);
    923                 },
    924                 .ComptimeInt => return true,
    925                 else => unreachable,
    926             },
    927             .int_big_negative => switch (ty.zigTypeTag()) {
    928                 .Int => {
    929                     const info = ty.intInfo(target);
    930                     return self.cast(Payload.IntBigNegative).?.asBigInt().fitsInTwosComp(info.signed, info.bits);
    931                 },
    932                 .ComptimeInt => return true,
    933                 else => unreachable,
    934             },
    935         }
    936     }
    937 
    938     /// Converts an integer or a float to a float.
    939     /// Returns `error.Overflow` if the value does not fit in the new type.
    940     pub fn floatCast(self: Value, allocator: *Allocator, ty: Type, target: Target) !Value {
    941         const dest_bit_count = switch (ty.tag()) {
    942             .comptime_float => 128,
    943             else => ty.floatBits(target),
    944         };
    945         switch (dest_bit_count) {
    946             16, 32, 64, 128 => {},
    947             else => std.debug.panic("TODO float cast bit count {}\n", .{dest_bit_count}),
    948         }
    949         if (ty.isInt()) {
    950             @panic("TODO int to float");
    951         }
    952 
    953         switch (dest_bit_count) {
    954             16 => {
    955                 @panic("TODO soft float");
    956                 // var res_payload = Value.Payload.Float_16{.val = self.toFloat(f16)};
    957                 // if (!self.eql(Value.initPayload(&res_payload.base)))
    958                 //     return error.Overflow;
    959                 // return Value.initPayload(&res_payload.base).copy(allocator);
    960             },
    961             32 => {
    962                 var res_payload = Value.Payload.Float_32{ .val = self.toFloat(f32) };
    963                 if (!self.eql(Value.initPayload(&res_payload.base)))
    964                     return error.Overflow;
    965                 return Value.initPayload(&res_payload.base).copy(allocator);
    966             },
    967             64 => {
    968                 var res_payload = Value.Payload.Float_64{ .val = self.toFloat(f64) };
    969                 if (!self.eql(Value.initPayload(&res_payload.base)))
    970                     return error.Overflow;
    971                 return Value.initPayload(&res_payload.base).copy(allocator);
    972             },
    973             128 => {
    974                 const float_payload = try allocator.create(Value.Payload.Float_128);
    975                 float_payload.* = .{ .val = self.toFloat(f128) };
    976                 return Value.initPayload(&float_payload.base);
    977             },
    978             else => unreachable,
    979         }
    980     }
    981 
    982     /// Asserts the value is a float
    983     pub fn floatHasFraction(self: Value) bool {
    984         return switch (self.tag()) {
    985             .ty,
    986             .int_type,
    987             .u8_type,
    988             .i8_type,
    989             .u16_type,
    990             .i16_type,
    991             .u32_type,
    992             .i32_type,
    993             .u64_type,
    994             .i64_type,
    995             .usize_type,
    996             .isize_type,
    997             .c_short_type,
    998             .c_ushort_type,
    999             .c_int_type,
   1000             .c_uint_type,
   1001             .c_long_type,
   1002             .c_ulong_type,
   1003             .c_longlong_type,
   1004             .c_ulonglong_type,
   1005             .c_longdouble_type,
   1006             .f16_type,
   1007             .f32_type,
   1008             .f64_type,
   1009             .f128_type,
   1010             .c_void_type,
   1011             .bool_type,
   1012             .void_type,
   1013             .type_type,
   1014             .anyerror_type,
   1015             .comptime_int_type,
   1016             .comptime_float_type,
   1017             .noreturn_type,
   1018             .null_type,
   1019             .undefined_type,
   1020             .fn_noreturn_no_args_type,
   1021             .fn_void_no_args_type,
   1022             .fn_naked_noreturn_no_args_type,
   1023             .fn_ccc_void_no_args_type,
   1024             .single_const_pointer_to_comptime_int_type,
   1025             .const_slice_u8_type,
   1026             .enum_literal_type,
   1027             .anyframe_type,
   1028             .bool_true,
   1029             .bool_false,
   1030             .null_value,
   1031             .function,
   1032             .variable,
   1033             .ref_val,
   1034             .decl_ref,
   1035             .elem_ptr,
   1036             .bytes,
   1037             .repeated,
   1038             .undef,
   1039             .int_u64,
   1040             .int_i64,
   1041             .int_big_positive,
   1042             .int_big_negative,
   1043             .empty_array,
   1044             .void_value,
   1045             .unreachable_value,
   1046             .enum_literal,
   1047             .error_set,
   1048             .@"error",
   1049             => unreachable,
   1050 
   1051             .zero => false,
   1052 
   1053             .float_16 => @rem(self.cast(Payload.Float_16).?.val, 1) != 0,
   1054             .float_32 => @rem(self.cast(Payload.Float_32).?.val, 1) != 0,
   1055             .float_64 => @rem(self.cast(Payload.Float_64).?.val, 1) != 0,
   1056             // .float_128 => @rem(self.cast(Payload.Float_128).?.val, 1) != 0,
   1057             .float_128 => @panic("TODO lld: error: undefined symbol: fmodl"),
   1058         };
   1059     }
   1060 
   1061     pub fn orderAgainstZero(lhs: Value) std.math.Order {
   1062         return switch (lhs.tag()) {
   1063             .ty,
   1064             .int_type,
   1065             .u8_type,
   1066             .i8_type,
   1067             .u16_type,
   1068             .i16_type,
   1069             .u32_type,
   1070             .i32_type,
   1071             .u64_type,
   1072             .i64_type,
   1073             .usize_type,
   1074             .isize_type,
   1075             .c_short_type,
   1076             .c_ushort_type,
   1077             .c_int_type,
   1078             .c_uint_type,
   1079             .c_long_type,
   1080             .c_ulong_type,
   1081             .c_longlong_type,
   1082             .c_ulonglong_type,
   1083             .c_longdouble_type,
   1084             .f16_type,
   1085             .f32_type,
   1086             .f64_type,
   1087             .f128_type,
   1088             .c_void_type,
   1089             .bool_type,
   1090             .void_type,
   1091             .type_type,
   1092             .anyerror_type,
   1093             .comptime_int_type,
   1094             .comptime_float_type,
   1095             .noreturn_type,
   1096             .null_type,
   1097             .undefined_type,
   1098             .fn_noreturn_no_args_type,
   1099             .fn_void_no_args_type,
   1100             .fn_naked_noreturn_no_args_type,
   1101             .fn_ccc_void_no_args_type,
   1102             .single_const_pointer_to_comptime_int_type,
   1103             .const_slice_u8_type,
   1104             .enum_literal_type,
   1105             .anyframe_type,
   1106             .null_value,
   1107             .function,
   1108             .variable,
   1109             .ref_val,
   1110             .decl_ref,
   1111             .elem_ptr,
   1112             .bytes,
   1113             .repeated,
   1114             .undef,
   1115             .void_value,
   1116             .unreachable_value,
   1117             .empty_array,
   1118             .enum_literal,
   1119             .error_set,
   1120             .@"error",
   1121             => unreachable,
   1122 
   1123             .zero,
   1124             .bool_false,
   1125             => .eq,
   1126 
   1127             .bool_true => .gt,
   1128 
   1129             .int_u64 => std.math.order(lhs.cast(Payload.Int_u64).?.int, 0),
   1130             .int_i64 => std.math.order(lhs.cast(Payload.Int_i64).?.int, 0),
   1131             .int_big_positive => lhs.cast(Payload.IntBigPositive).?.asBigInt().orderAgainstScalar(0),
   1132             .int_big_negative => lhs.cast(Payload.IntBigNegative).?.asBigInt().orderAgainstScalar(0),
   1133 
   1134             .float_16 => std.math.order(lhs.cast(Payload.Float_16).?.val, 0),
   1135             .float_32 => std.math.order(lhs.cast(Payload.Float_32).?.val, 0),
   1136             .float_64 => std.math.order(lhs.cast(Payload.Float_64).?.val, 0),
   1137             .float_128 => std.math.order(lhs.cast(Payload.Float_128).?.val, 0),
   1138         };
   1139     }
   1140 
   1141     /// Asserts the value is comparable.
   1142     pub fn order(lhs: Value, rhs: Value) std.math.Order {
   1143         const lhs_tag = lhs.tag();
   1144         const rhs_tag = rhs.tag();
   1145         const lhs_is_zero = lhs_tag == .zero;
   1146         const rhs_is_zero = rhs_tag == .zero;
   1147         if (lhs_is_zero) return rhs.orderAgainstZero().invert();
   1148         if (rhs_is_zero) return lhs.orderAgainstZero();
   1149 
   1150         const lhs_float = lhs.isFloat();
   1151         const rhs_float = rhs.isFloat();
   1152         if (lhs_float and rhs_float) {
   1153             if (lhs_tag == rhs_tag) {
   1154                 return switch (lhs.tag()) {
   1155                     .float_16 => return std.math.order(lhs.cast(Payload.Float_16).?.val, rhs.cast(Payload.Float_16).?.val),
   1156                     .float_32 => return std.math.order(lhs.cast(Payload.Float_32).?.val, rhs.cast(Payload.Float_32).?.val),
   1157                     .float_64 => return std.math.order(lhs.cast(Payload.Float_64).?.val, rhs.cast(Payload.Float_64).?.val),
   1158                     .float_128 => return std.math.order(lhs.cast(Payload.Float_128).?.val, rhs.cast(Payload.Float_128).?.val),
   1159                     else => unreachable,
   1160                 };
   1161             }
   1162         }
   1163         if (lhs_float or rhs_float) {
   1164             const lhs_f128 = lhs.toFloat(f128);
   1165             const rhs_f128 = rhs.toFloat(f128);
   1166             return std.math.order(lhs_f128, rhs_f128);
   1167         }
   1168 
   1169         var lhs_bigint_space: BigIntSpace = undefined;
   1170         var rhs_bigint_space: BigIntSpace = undefined;
   1171         const lhs_bigint = lhs.toBigInt(&lhs_bigint_space);
   1172         const rhs_bigint = rhs.toBigInt(&rhs_bigint_space);
   1173         return lhs_bigint.order(rhs_bigint);
   1174     }
   1175 
   1176     /// Asserts the value is comparable.
   1177     pub fn compare(lhs: Value, op: std.math.CompareOperator, rhs: Value) bool {
   1178         return order(lhs, rhs).compare(op);
   1179     }
   1180 
   1181     /// Asserts the value is comparable.
   1182     pub fn compareWithZero(lhs: Value, op: std.math.CompareOperator) bool {
   1183         return orderAgainstZero(lhs).compare(op);
   1184     }
   1185 
   1186     pub fn eql(a: Value, b: Value) bool {
   1187         if (a.tag() == b.tag() and a.tag() == .enum_literal) {
   1188             const a_name = @fieldParentPtr(Payload.Bytes, "base", a.ptr_otherwise).data;
   1189             const b_name = @fieldParentPtr(Payload.Bytes, "base", b.ptr_otherwise).data;
   1190             return std.mem.eql(u8, a_name, b_name);
   1191         }
   1192         // TODO non numerical comparisons
   1193         return compare(a, .eq, b);
   1194     }
   1195 
   1196     /// Asserts the value is a pointer and dereferences it.
   1197     /// Returns error.AnalysisFail if the pointer points to a Decl that failed semantic analysis.
   1198     pub fn pointerDeref(self: Value, allocator: *Allocator) error{ AnalysisFail, OutOfMemory }!Value {
   1199         return switch (self.tag()) {
   1200             .ty,
   1201             .int_type,
   1202             .u8_type,
   1203             .i8_type,
   1204             .u16_type,
   1205             .i16_type,
   1206             .u32_type,
   1207             .i32_type,
   1208             .u64_type,
   1209             .i64_type,
   1210             .usize_type,
   1211             .isize_type,
   1212             .c_short_type,
   1213             .c_ushort_type,
   1214             .c_int_type,
   1215             .c_uint_type,
   1216             .c_long_type,
   1217             .c_ulong_type,
   1218             .c_longlong_type,
   1219             .c_ulonglong_type,
   1220             .c_longdouble_type,
   1221             .f16_type,
   1222             .f32_type,
   1223             .f64_type,
   1224             .f128_type,
   1225             .c_void_type,
   1226             .bool_type,
   1227             .void_type,
   1228             .type_type,
   1229             .anyerror_type,
   1230             .comptime_int_type,
   1231             .comptime_float_type,
   1232             .noreturn_type,
   1233             .null_type,
   1234             .undefined_type,
   1235             .fn_noreturn_no_args_type,
   1236             .fn_void_no_args_type,
   1237             .fn_naked_noreturn_no_args_type,
   1238             .fn_ccc_void_no_args_type,
   1239             .single_const_pointer_to_comptime_int_type,
   1240             .const_slice_u8_type,
   1241             .enum_literal_type,
   1242             .anyframe_type,
   1243             .zero,
   1244             .bool_true,
   1245             .bool_false,
   1246             .null_value,
   1247             .function,
   1248             .variable,
   1249             .int_u64,
   1250             .int_i64,
   1251             .int_big_positive,
   1252             .int_big_negative,
   1253             .bytes,
   1254             .undef,
   1255             .repeated,
   1256             .float_16,
   1257             .float_32,
   1258             .float_64,
   1259             .float_128,
   1260             .void_value,
   1261             .unreachable_value,
   1262             .empty_array,
   1263             .enum_literal,
   1264             .error_set,
   1265             .@"error",
   1266             => unreachable,
   1267 
   1268             .ref_val => self.cast(Payload.RefVal).?.val,
   1269             .decl_ref => self.cast(Payload.DeclRef).?.decl.value(),
   1270             .elem_ptr => {
   1271                 const elem_ptr = self.cast(Payload.ElemPtr).?;
   1272                 const array_val = try elem_ptr.array_ptr.pointerDeref(allocator);
   1273                 return array_val.elemValue(allocator, elem_ptr.index);
   1274             },
   1275         };
   1276     }
   1277 
   1278     /// Asserts the value is a single-item pointer to an array, or an array,
   1279     /// or an unknown-length pointer, and returns the element value at the index.
   1280     pub fn elemValue(self: Value, allocator: *Allocator, index: usize) error{OutOfMemory}!Value {
   1281         switch (self.tag()) {
   1282             .ty,
   1283             .int_type,
   1284             .u8_type,
   1285             .i8_type,
   1286             .u16_type,
   1287             .i16_type,
   1288             .u32_type,
   1289             .i32_type,
   1290             .u64_type,
   1291             .i64_type,
   1292             .usize_type,
   1293             .isize_type,
   1294             .c_short_type,
   1295             .c_ushort_type,
   1296             .c_int_type,
   1297             .c_uint_type,
   1298             .c_long_type,
   1299             .c_ulong_type,
   1300             .c_longlong_type,
   1301             .c_ulonglong_type,
   1302             .c_longdouble_type,
   1303             .f16_type,
   1304             .f32_type,
   1305             .f64_type,
   1306             .f128_type,
   1307             .c_void_type,
   1308             .bool_type,
   1309             .void_type,
   1310             .type_type,
   1311             .anyerror_type,
   1312             .comptime_int_type,
   1313             .comptime_float_type,
   1314             .noreturn_type,
   1315             .null_type,
   1316             .undefined_type,
   1317             .fn_noreturn_no_args_type,
   1318             .fn_void_no_args_type,
   1319             .fn_naked_noreturn_no_args_type,
   1320             .fn_ccc_void_no_args_type,
   1321             .single_const_pointer_to_comptime_int_type,
   1322             .const_slice_u8_type,
   1323             .enum_literal_type,
   1324             .anyframe_type,
   1325             .zero,
   1326             .bool_true,
   1327             .bool_false,
   1328             .null_value,
   1329             .function,
   1330             .variable,
   1331             .int_u64,
   1332             .int_i64,
   1333             .int_big_positive,
   1334             .int_big_negative,
   1335             .undef,
   1336             .elem_ptr,
   1337             .ref_val,
   1338             .decl_ref,
   1339             .float_16,
   1340             .float_32,
   1341             .float_64,
   1342             .float_128,
   1343             .void_value,
   1344             .unreachable_value,
   1345             .enum_literal,
   1346             .error_set,
   1347             .@"error",
   1348             => unreachable,
   1349 
   1350             .empty_array => unreachable, // out of bounds array index
   1351 
   1352             .bytes => {
   1353                 const int_payload = try allocator.create(Payload.Int_u64);
   1354                 int_payload.* = .{ .int = self.cast(Payload.Bytes).?.data[index] };
   1355                 return Value.initPayload(&int_payload.base);
   1356             },
   1357 
   1358             // No matter the index; all the elements are the same!
   1359             .repeated => return self.cast(Payload.Repeated).?.val,
   1360         }
   1361     }
   1362 
   1363     /// Returns a pointer to the element value at the index.
   1364     pub fn elemPtr(self: Value, allocator: *Allocator, index: usize) !Value {
   1365         const payload = try allocator.create(Payload.ElemPtr);
   1366         if (self.cast(Payload.ElemPtr)) |elem_ptr| {
   1367             payload.* = .{ .array_ptr = elem_ptr.array_ptr, .index = elem_ptr.index + index };
   1368         } else {
   1369             payload.* = .{ .array_ptr = self, .index = index };
   1370         }
   1371         return Value.initPayload(&payload.base);
   1372     }
   1373 
   1374     pub fn isUndef(self: Value) bool {
   1375         return self.tag() == .undef;
   1376     }
   1377 
   1378     /// Valid for all types. Asserts the value is not undefined and not unreachable.
   1379     pub fn isNull(self: Value) bool {
   1380         return switch (self.tag()) {
   1381             .ty,
   1382             .int_type,
   1383             .u8_type,
   1384             .i8_type,
   1385             .u16_type,
   1386             .i16_type,
   1387             .u32_type,
   1388             .i32_type,
   1389             .u64_type,
   1390             .i64_type,
   1391             .usize_type,
   1392             .isize_type,
   1393             .c_short_type,
   1394             .c_ushort_type,
   1395             .c_int_type,
   1396             .c_uint_type,
   1397             .c_long_type,
   1398             .c_ulong_type,
   1399             .c_longlong_type,
   1400             .c_ulonglong_type,
   1401             .c_longdouble_type,
   1402             .f16_type,
   1403             .f32_type,
   1404             .f64_type,
   1405             .f128_type,
   1406             .c_void_type,
   1407             .bool_type,
   1408             .void_type,
   1409             .type_type,
   1410             .anyerror_type,
   1411             .comptime_int_type,
   1412             .comptime_float_type,
   1413             .noreturn_type,
   1414             .null_type,
   1415             .undefined_type,
   1416             .fn_noreturn_no_args_type,
   1417             .fn_void_no_args_type,
   1418             .fn_naked_noreturn_no_args_type,
   1419             .fn_ccc_void_no_args_type,
   1420             .single_const_pointer_to_comptime_int_type,
   1421             .const_slice_u8_type,
   1422             .enum_literal_type,
   1423             .anyframe_type,
   1424             .zero,
   1425             .empty_array,
   1426             .bool_true,
   1427             .bool_false,
   1428             .function,
   1429             .variable,
   1430             .int_u64,
   1431             .int_i64,
   1432             .int_big_positive,
   1433             .int_big_negative,
   1434             .ref_val,
   1435             .decl_ref,
   1436             .elem_ptr,
   1437             .bytes,
   1438             .repeated,
   1439             .float_16,
   1440             .float_32,
   1441             .float_64,
   1442             .float_128,
   1443             .void_value,
   1444             .enum_literal,
   1445             .error_set,
   1446             .@"error",
   1447             => false,
   1448 
   1449             .undef => unreachable,
   1450             .unreachable_value => unreachable,
   1451             .null_value => true,
   1452         };
   1453     }
   1454 
   1455     /// Valid for all types. Asserts the value is not undefined.
   1456     pub fn isFloat(self: Value) bool {
   1457         return switch (self.tag()) {
   1458             .undef => unreachable,
   1459 
   1460             .float_16,
   1461             .float_32,
   1462             .float_64,
   1463             .float_128,
   1464             => true,
   1465             else => false,
   1466         };
   1467     }
   1468 
   1469     /// This type is not copyable since it may contain pointers to its inner data.
   1470     pub const Payload = struct {
   1471         tag: Tag,
   1472 
   1473         pub const Int_u64 = struct {
   1474             base: Payload = Payload{ .tag = .int_u64 },
   1475             int: u64,
   1476         };
   1477 
   1478         pub const Int_i64 = struct {
   1479             base: Payload = Payload{ .tag = .int_i64 },
   1480             int: i64,
   1481         };
   1482 
   1483         pub const IntBigPositive = struct {
   1484             base: Payload = Payload{ .tag = .int_big_positive },
   1485             limbs: []const std.math.big.Limb,
   1486 
   1487             pub fn asBigInt(self: IntBigPositive) BigIntConst {
   1488                 return BigIntConst{ .limbs = self.limbs, .positive = true };
   1489             }
   1490         };
   1491 
   1492         pub const IntBigNegative = struct {
   1493             base: Payload = Payload{ .tag = .int_big_negative },
   1494             limbs: []const std.math.big.Limb,
   1495 
   1496             pub fn asBigInt(self: IntBigNegative) BigIntConst {
   1497                 return BigIntConst{ .limbs = self.limbs, .positive = false };
   1498             }
   1499         };
   1500 
   1501         pub const Function = struct {
   1502             base: Payload = Payload{ .tag = .function },
   1503             func: *Module.Fn,
   1504         };
   1505 
   1506         pub const Variable = struct {
   1507             base: Payload = Payload{ .tag = .variable },
   1508             variable: *Module.Var,
   1509         };
   1510 
   1511         pub const ArraySentinel0_u8_Type = struct {
   1512             base: Payload = Payload{ .tag = .array_sentinel_0_u8_type },
   1513             len: u64,
   1514         };
   1515 
   1516         /// Represents a pointer to another immutable value.
   1517         pub const RefVal = struct {
   1518             base: Payload = Payload{ .tag = .ref_val },
   1519             val: Value,
   1520         };
   1521 
   1522         /// Represents a pointer to a decl, not the value of the decl.
   1523         pub const DeclRef = struct {
   1524             base: Payload = Payload{ .tag = .decl_ref },
   1525             decl: *Module.Decl,
   1526         };
   1527 
   1528         pub const ElemPtr = struct {
   1529             base: Payload = Payload{ .tag = .elem_ptr },
   1530             array_ptr: Value,
   1531             index: usize,
   1532         };
   1533 
   1534         pub const Bytes = struct {
   1535             base: Payload = Payload{ .tag = .bytes },
   1536             data: []const u8,
   1537         };
   1538 
   1539         pub const Ty = struct {
   1540             base: Payload = Payload{ .tag = .ty },
   1541             ty: Type,
   1542         };
   1543 
   1544         pub const IntType = struct {
   1545             base: Payload = Payload{ .tag = .int_type },
   1546             bits: u16,
   1547             signed: bool,
   1548         };
   1549 
   1550         pub const Repeated = struct {
   1551             base: Payload = Payload{ .tag = .ty },
   1552             /// This value is repeated some number of times. The amount of times to repeat
   1553             /// is stored externally.
   1554             val: Value,
   1555         };
   1556 
   1557         pub const Float_16 = struct {
   1558             base: Payload = .{ .tag = .float_16 },
   1559             val: f16,
   1560         };
   1561 
   1562         pub const Float_32 = struct {
   1563             base: Payload = .{ .tag = .float_32 },
   1564             val: f32,
   1565         };
   1566 
   1567         pub const Float_64 = struct {
   1568             base: Payload = .{ .tag = .float_64 },
   1569             val: f64,
   1570         };
   1571 
   1572         pub const Float_128 = struct {
   1573             base: Payload = .{ .tag = .float_128 },
   1574             val: f128,
   1575         };
   1576 
   1577         pub const ErrorSet = struct {
   1578             base: Payload = .{ .tag = .error_set },
   1579 
   1580             // TODO revisit this when we have the concept of the error tag type
   1581             fields: std.StringHashMapUnmanaged(u16),
   1582         };
   1583 
   1584         pub const Error = struct {
   1585             base: Payload = .{ .tag = .@"error" },
   1586 
   1587             // TODO revisit this when we have the concept of the error tag type
   1588             /// `name` is owned by `Module` and will be valid for the entire
   1589             /// duration of the compilation.
   1590             name: []const u8,
   1591             value: u16,
   1592         };
   1593     };
   1594 
   1595     /// Big enough to fit any non-BigInt value
   1596     pub const BigIntSpace = struct {
   1597         /// The +1 is headroom so that operations such as incrementing once or decrementing once
   1598         /// are possible without using an allocator.
   1599         limbs: [(@sizeOf(u64) / @sizeOf(std.math.big.Limb)) + 1]std.math.big.Limb,
   1600     };
   1601 };