| author | |
| committer | |
| log | eb3726c502e92ec4a3689732a76479c6d561cff5 |
| tree | 91f14deeaffd5e475c11be3ec8572b66a3799b37 |
| parent | d1d3dbc7b5bc986849db476e491300ffd18d4db5 |
| parent | 3268276b58d8b65cb295b738d7c14174005bd84e |
11 files changed, 156 insertions(+), 20 deletions(-)
CMakeLists.txt+1| ... | @@ -425,6 +425,7 @@ set(ZIG_STD_FILES | ... | @@ -425,6 +425,7 @@ set(ZIG_STD_FILES |
| 425 | "math/tan.zig" | 425 | "math/tan.zig" |
| 426 | "math/tanh.zig" | 426 | "math/tanh.zig" |
| 427 | "math/trunc.zig" | 427 | "math/trunc.zig" |
| 428 | "math/x86_64/sqrt.zig" | ||
| 428 | "mem.zig" | 429 | "mem.zig" |
| 429 | "net.zig" | 430 | "net.zig" |
| 430 | "os/child_process.zig" | 431 | "os/child_process.zig" |
src/all_types.hpp+1| ... | @@ -1421,6 +1421,7 @@ struct CodeGen { | ... | @@ -1421,6 +1421,7 @@ struct CodeGen { |
| 1421 | HashMap<ZigLLVMFnKey, LLVMValueRef, zig_llvm_fn_key_hash, zig_llvm_fn_key_eql> llvm_fn_table; | 1421 | HashMap<ZigLLVMFnKey, LLVMValueRef, zig_llvm_fn_key_hash, zig_llvm_fn_key_eql> llvm_fn_table; |
| 1422 | HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> exported_symbol_names; | 1422 | HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> exported_symbol_names; |
| 1423 | HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> external_prototypes; | 1423 | HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> external_prototypes; |
| 1424 | HashMap<Buf *, ConstExprValue *, buf_hash, buf_eql_buf> string_literals_table; | ||
| 1424 | 1425 | ||
| 1425 | 1426 | ||
| 1426 | ZigList<ImportTableEntry *> import_queue; | 1427 | ZigList<ImportTableEntry *> import_queue; |
src/analyze.cpp+8| ... | @@ -4370,6 +4370,12 @@ bool type_requires_comptime(TypeTableEntry *type_entry) { | ... | @@ -4370,6 +4370,12 @@ bool type_requires_comptime(TypeTableEntry *type_entry) { |
| 4370 | } | 4370 | } |
| 4371 | 4371 | ||
| 4372 | void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str) { | 4372 | void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str) { |
| 4373 | auto entry = g->string_literals_table.maybe_get(str); | ||
| 4374 | if (entry != nullptr) { | ||
| 4375 | *const_val = *entry->value; | ||
| 4376 | return; | ||
| 4377 | } | ||
| 4378 | |||
| 4373 | const_val->special = ConstValSpecialStatic; | 4379 | const_val->special = ConstValSpecialStatic; |
| 4374 | const_val->type = get_array_type(g, g->builtin_types.entry_u8, buf_len(str)); | 4380 | const_val->type = get_array_type(g, g->builtin_types.entry_u8, buf_len(str)); |
| 4375 | const_val->data.x_array.s_none.elements = create_const_vals(buf_len(str)); | 4381 | const_val->data.x_array.s_none.elements = create_const_vals(buf_len(str)); |
| ... | @@ -4380,6 +4386,8 @@ void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str) { | ... | @@ -4380,6 +4386,8 @@ void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str) { |
| 4380 | this_char->type = g->builtin_types.entry_u8; | 4386 | this_char->type = g->builtin_types.entry_u8; |
| 4381 | bigint_init_unsigned(&this_char->data.x_bigint, (uint8_t)buf_ptr(str)[i]); | 4387 | bigint_init_unsigned(&this_char->data.x_bigint, (uint8_t)buf_ptr(str)[i]); |
| 4382 | } | 4388 | } |
| 4389 | |||
| 4390 | g->string_literals_table.put(str, const_val); | ||
| 4383 | } | 4391 | } |
| 4384 | 4392 | ||
| 4385 | ConstExprValue *create_const_str_lit(CodeGen *g, Buf *str) { | 4393 | ConstExprValue *create_const_str_lit(CodeGen *g, Buf *str) { |
src/buffer.cpp+4-1| ... | @@ -67,9 +67,12 @@ bool buf_eql_buf(Buf *buf, Buf *other) { | ... | @@ -67,9 +67,12 @@ bool buf_eql_buf(Buf *buf, Buf *other) { |
| 67 | 67 | ||
| 68 | uint32_t buf_hash(Buf *buf) { | 68 | uint32_t buf_hash(Buf *buf) { |
| 69 | assert(buf->list.length); | 69 | assert(buf->list.length); |
| 70 | size_t interval = buf->list.length / 256; | ||
| 71 | if (interval == 0) | ||
| 72 | interval = 1; | ||
| 70 | // FNV 32-bit hash | 73 | // FNV 32-bit hash |
| 71 | uint32_t h = 2166136261; | 74 | uint32_t h = 2166136261; |
| 72 | for (size_t i = 0; i < buf_len(buf); i += 1) { | 75 | for (size_t i = 0; i < buf_len(buf); i += interval) { |
| 73 | h = h ^ ((uint8_t)buf->list.at(i)); | 76 | h = h ^ ((uint8_t)buf->list.at(i)); |
| 74 | h = h * 16777619; | 77 | h = h * 16777619; |
| 75 | } | 78 | } |
src/codegen.cpp+1| ... | @@ -87,6 +87,7 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out | ... | @@ -87,6 +87,7 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out |
| 87 | g->memoized_fn_eval_table.init(16); | 87 | g->memoized_fn_eval_table.init(16); |
| 88 | g->exported_symbol_names.init(8); | 88 | g->exported_symbol_names.init(8); |
| 89 | g->external_prototypes.init(8); | 89 | g->external_prototypes.init(8); |
| 90 | g->string_literals_table.init(16); | ||
| 90 | g->is_test_build = false; | 91 | g->is_test_build = false; |
| 91 | g->want_h_file = (out_type == OutTypeObj || out_type == OutTypeLib); | 92 | g->want_h_file = (out_type == OutTypeObj || out_type == OutTypeLib); |
| 92 | buf_resize(&g->global_asm, 0); | 93 | buf_resize(&g->global_asm, 0); |
src/ir.cpp+4-4| ... | @@ -13224,9 +13224,9 @@ static TypeTableEntry *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstr | ... | @@ -13224,9 +13224,9 @@ static TypeTableEntry *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstr |
| 13224 | os_path_resolve(&source_dir_path, rel_file_path, &file_path); | 13224 | os_path_resolve(&source_dir_path, rel_file_path, &file_path); |
| 13225 | 13225 | ||
| 13226 | // load from file system into const expr | 13226 | // load from file system into const expr |
| 13227 | Buf file_contents = BUF_INIT; | 13227 | Buf *file_contents = buf_alloc(); |
| 13228 | int err; | 13228 | int err; |
| 13229 | if ((err = os_fetch_file_path(&file_path, &file_contents))) { | 13229 | if ((err = os_fetch_file_path(&file_path, file_contents))) { |
| 13230 | if (err == ErrorFileNotFound) { | 13230 | if (err == ErrorFileNotFound) { |
| 13231 | ir_add_error(ira, instruction->name, buf_sprintf("unable to find '%s'", buf_ptr(&file_path))); | 13231 | ir_add_error(ira, instruction->name, buf_sprintf("unable to find '%s'", buf_ptr(&file_path))); |
| 13232 | return ira->codegen->builtin_types.entry_invalid; | 13232 | return ira->codegen->builtin_types.entry_invalid; |
| ... | @@ -13240,9 +13240,9 @@ static TypeTableEntry *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstr | ... | @@ -13240,9 +13240,9 @@ static TypeTableEntry *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstr |
| 13240 | // we'll have to invalidate the cache | 13240 | // we'll have to invalidate the cache |
| 13241 | 13241 | ||
| 13242 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); | 13242 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); |
| 13243 | init_const_str_lit(ira->codegen, out_val, &file_contents); | 13243 | init_const_str_lit(ira->codegen, out_val, file_contents); |
| 13244 | 13244 | ||
| 13245 | return get_array_type(ira->codegen, ira->codegen->builtin_types.entry_u8, buf_len(&file_contents)); | 13245 | return get_array_type(ira->codegen, ira->codegen->builtin_types.entry_u8, buf_len(file_contents)); |
| 13246 | } | 13246 | } |
| 13247 | 13247 | ||
| 13248 | static TypeTableEntry *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructionCmpxchg *instruction) { | 13248 | static TypeTableEntry *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructionCmpxchg *instruction) { |
std/endian.zig+8-3| ... | @@ -2,11 +2,11 @@ const mem = @import("mem.zig"); | ... | @@ -2,11 +2,11 @@ const mem = @import("mem.zig"); |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 3 | 3 | ||
| 4 | pub fn swapIfLe(comptime T: type, x: T) -> T { | 4 | pub fn swapIfLe(comptime T: type, x: T) -> T { |
| 5 | return swapIf(false, T, x); | 5 | return swapIf(builtin.Endian.Little, T, x); |
| 6 | } | 6 | } |
| 7 | 7 | ||
| 8 | pub fn swapIfBe(comptime T: type, x: T) -> T { | 8 | pub fn swapIfBe(comptime T: type, x: T) -> T { |
| 9 | return swapIf(true, T, x); | 9 | return swapIf(builtin.Endian.Big, T, x); |
| 10 | } | 10 | } |
| 11 | 11 | ||
| 12 | pub fn swapIf(endian: builtin.Endian, comptime T: type, x: T) -> T { | 12 | pub fn swapIf(endian: builtin.Endian, comptime T: type, x: T) -> T { |
| ... | @@ -15,6 +15,11 @@ pub fn swapIf(endian: builtin.Endian, comptime T: type, x: T) -> T { | ... | @@ -15,6 +15,11 @@ pub fn swapIf(endian: builtin.Endian, comptime T: type, x: T) -> T { |
| 15 | 15 | ||
| 16 | pub fn swap(comptime T: type, x: T) -> T { | 16 | pub fn swap(comptime T: type, x: T) -> T { |
| 17 | var buf: [@sizeOf(T)]u8 = undefined; | 17 | var buf: [@sizeOf(T)]u8 = undefined; |
| 18 | mem.writeInt(buf[0..], x, false); | 18 | mem.writeInt(buf[0..], x, builtin.Endian.Little); |
| 19 | return mem.readInt(buf, T, builtin.Endian.Big); | 19 | return mem.readInt(buf, T, builtin.Endian.Big); |
| 20 | } | 20 | } |
| 21 | |||
| 22 | test "swap" { | ||
| 23 | const debug = @import("debug/index.zig"); | ||
| 24 | debug.assert(swap(u32, 0xDEADBEEF) == 0xEFBEADDE); | ||
| 25 | } |
std/linked_list.zig+87-8| ... | @@ -4,8 +4,18 @@ const assert = debug.assert; | ... | @@ -4,8 +4,18 @@ const assert = debug.assert; |
| 4 | const mem = std.mem; | 4 | const mem = std.mem; |
| 5 | const Allocator = mem.Allocator; | 5 | const Allocator = mem.Allocator; |
| 6 | 6 | ||
| 7 | /// Generic doubly linked list. | 7 | /// Generic non-intrusive doubly linked list. |
| 8 | pub fn LinkedList(comptime T: type) -> type { | 8 | pub fn LinkedList(comptime T: type) -> type { |
| 9 | return BaseLinkedList(T, void, ""); | ||
| 10 | } | ||
| 11 | |||
| 12 | /// Generic intrusive doubly linked list. | ||
| 13 | pub fn IntrusiveLinkedList(comptime ParentType: type, comptime field_name: []const u8) -> type { | ||
| 14 | return BaseLinkedList(void, ParentType, field_name); | ||
| 15 | } | ||
| 16 | |||
| 17 | /// Generic doubly linked list. | ||
| 18 | fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_name: []const u8) -> type { | ||
| 9 | return struct { | 19 | return struct { |
| 10 | const Self = this; | 20 | const Self = this; |
| 11 | 21 | ||
| ... | @@ -15,13 +25,23 @@ pub fn LinkedList(comptime T: type) -> type { | ... | @@ -15,13 +25,23 @@ pub fn LinkedList(comptime T: type) -> type { |
| 15 | next: ?&Node, | 25 | next: ?&Node, |
| 16 | data: T, | 26 | data: T, |
| 17 | 27 | ||
| 18 | pub fn init(data: &const T) -> Node { | 28 | pub fn init(value: &const T) -> Node { |
| 19 | return Node { | 29 | return Node { |
| 20 | .prev = null, | 30 | .prev = null, |
| 21 | .next = null, | 31 | .next = null, |
| 22 | .data = *data, | 32 | .data = *value, |
| 23 | }; | 33 | }; |
| 24 | } | 34 | } |
| 35 | |||
| 36 | pub fn initIntrusive() -> Node { | ||
| 37 | // TODO: when #678 is solved this can become `init`. | ||
| 38 | return Node.init({}); | ||
| 39 | } | ||
| 40 | |||
| 41 | pub fn toData(node: &Node) -> &ParentType { | ||
| 42 | comptime assert(isIntrusive()); | ||
| 43 | return @fieldParentPtr(ParentType, field_name, node); | ||
| 44 | } | ||
| 25 | }; | 45 | }; |
| 26 | 46 | ||
| 27 | first: ?&Node, | 47 | first: ?&Node, |
| ... | @@ -40,6 +60,10 @@ pub fn LinkedList(comptime T: type) -> type { | ... | @@ -40,6 +60,10 @@ pub fn LinkedList(comptime T: type) -> type { |
| 40 | }; | 60 | }; |
| 41 | } | 61 | } |
| 42 | 62 | ||
| 63 | fn isIntrusive() -> bool { | ||
| 64 | return ParentType != void or field_name.len != 0; | ||
| 65 | } | ||
| 66 | |||
| 43 | /// Insert a new node after an existing one. | 67 | /// Insert a new node after an existing one. |
| 44 | /// | 68 | /// |
| 45 | /// Arguments: | 69 | /// Arguments: |
| ... | @@ -167,6 +191,7 @@ pub fn LinkedList(comptime T: type) -> type { | ... | @@ -167,6 +191,7 @@ pub fn LinkedList(comptime T: type) -> type { |
| 167 | /// Returns: | 191 | /// Returns: |
| 168 | /// A pointer to the new node. | 192 | /// A pointer to the new node. |
| 169 | pub fn allocateNode(list: &Self, allocator: &Allocator) -> %&Node { | 193 | pub fn allocateNode(list: &Self, allocator: &Allocator) -> %&Node { |
| 194 | comptime assert(!isIntrusive()); | ||
| 170 | return allocator.create(Node); | 195 | return allocator.create(Node); |
| 171 | } | 196 | } |
| 172 | 197 | ||
| ... | @@ -176,6 +201,7 @@ pub fn LinkedList(comptime T: type) -> type { | ... | @@ -176,6 +201,7 @@ pub fn LinkedList(comptime T: type) -> type { |
| 176 | /// node: Pointer to the node to deallocate. | 201 | /// node: Pointer to the node to deallocate. |
| 177 | /// allocator: Dynamic memory allocator. | 202 | /// allocator: Dynamic memory allocator. |
| 178 | pub fn destroyNode(list: &Self, node: &Node, allocator: &Allocator) { | 203 | pub fn destroyNode(list: &Self, node: &Node, allocator: &Allocator) { |
| 204 | comptime assert(!isIntrusive()); | ||
| 179 | allocator.destroy(node); | 205 | allocator.destroy(node); |
| 180 | } | 206 | } |
| 181 | 207 | ||
| ... | @@ -188,6 +214,7 @@ pub fn LinkedList(comptime T: type) -> type { | ... | @@ -188,6 +214,7 @@ pub fn LinkedList(comptime T: type) -> type { |
| 188 | /// Returns: | 214 | /// Returns: |
| 189 | /// A pointer to the new node. | 215 | /// A pointer to the new node. |
| 190 | pub fn createNode(list: &Self, data: &const T, allocator: &Allocator) -> %&Node { | 216 | pub fn createNode(list: &Self, data: &const T, allocator: &Allocator) -> %&Node { |
| 217 | comptime assert(!isIntrusive()); | ||
| 191 | var node = try list.allocateNode(allocator); | 218 | var node = try list.allocateNode(allocator); |
| 192 | *node = Node.init(data); | 219 | *node = Node.init(data); |
| 193 | return node; | 220 | return node; |
| ... | @@ -199,11 +226,11 @@ test "basic linked list test" { | ... | @@ -199,11 +226,11 @@ test "basic linked list test" { |
| 199 | const allocator = debug.global_allocator; | 226 | const allocator = debug.global_allocator; |
| 200 | var list = LinkedList(u32).init(); | 227 | var list = LinkedList(u32).init(); |
| 201 | 228 | ||
| 202 | var one = list.createNode(1, allocator) catch unreachable; | 229 | var one = try list.createNode(1, allocator); |
| 203 | var two = list.createNode(2, allocator) catch unreachable; | 230 | var two = try list.createNode(2, allocator); |
| 204 | var three = list.createNode(3, allocator) catch unreachable; | 231 | var three = try list.createNode(3, allocator); |
| 205 | var four = list.createNode(4, allocator) catch unreachable; | 232 | var four = try list.createNode(4, allocator); |
| 206 | var five = list.createNode(5, allocator) catch unreachable; | 233 | var five = try list.createNode(5, allocator); |
| 207 | defer { | 234 | defer { |
| 208 | list.destroyNode(one, allocator); | 235 | list.destroyNode(one, allocator); |
| 209 | list.destroyNode(two, allocator); | 236 | list.destroyNode(two, allocator); |
| ... | @@ -246,3 +273,55 @@ test "basic linked list test" { | ... | @@ -246,3 +273,55 @@ test "basic linked list test" { |
| 246 | assert ((??list.last ).data == 4); | 273 | assert ((??list.last ).data == 4); |
| 247 | assert (list.len == 2); | 274 | assert (list.len == 2); |
| 248 | } | 275 | } |
| 276 | |||
| 277 | const link = "link"; | ||
| 278 | const ElementList = IntrusiveLinkedList(Element, link); | ||
| 279 | const Element = struct { | ||
| 280 | value: u32, | ||
| 281 | link: IntrusiveLinkedList(Element, link).Node, | ||
| 282 | }; | ||
| 283 | |||
| 284 | test "basic intrusive linked list test" { | ||
| 285 | const allocator = debug.global_allocator; | ||
| 286 | var list = ElementList.init(); | ||
| 287 | |||
| 288 | var one = Element { .value = 1, .link = ElementList.Node.initIntrusive() }; | ||
| 289 | var two = Element { .value = 2, .link = ElementList.Node.initIntrusive() }; | ||
| 290 | var three = Element { .value = 3, .link = ElementList.Node.initIntrusive() }; | ||
| 291 | var four = Element { .value = 4, .link = ElementList.Node.initIntrusive() }; | ||
| 292 | var five = Element { .value = 5, .link = ElementList.Node.initIntrusive() }; | ||
| 293 | |||
| 294 | list.append(&two.link); // {2} | ||
| 295 | list.append(&five.link); // {2, 5} | ||
| 296 | list.prepend(&one.link); // {1, 2, 5} | ||
| 297 | list.insertBefore(&five.link, &four.link); // {1, 2, 4, 5} | ||
| 298 | list.insertAfter(&two.link, &three.link); // {1, 2, 3, 4, 5} | ||
| 299 | |||
| 300 | // Traverse forwards. | ||
| 301 | { | ||
| 302 | var it = list.first; | ||
| 303 | var index: u32 = 1; | ||
| 304 | while (it) |node| : (it = node.next) { | ||
| 305 | assert(node.toData().value == index); | ||
| 306 | index += 1; | ||
| 307 | } | ||
| 308 | } | ||
| 309 | |||
| 310 | // Traverse backwards. | ||
| 311 | { | ||
| 312 | var it = list.last; | ||
| 313 | var index: u32 = 1; | ||
| 314 | while (it) |node| : (it = node.prev) { | ||
| 315 | assert(node.toData().value == (6 - index)); | ||
| 316 | index += 1; | ||
| 317 | } | ||
| 318 | } | ||
| 319 | |||
| 320 | var first = list.popFirst(); // {2, 3, 4, 5} | ||
| 321 | var last = list.pop(); // {2, 3, 4} | ||
| 322 | list.remove(&three.link); // {2, 4} | ||
| 323 | |||
| 324 | assert ((??list.first).toData().value == 2); | ||
| 325 | assert ((??list.last ).toData().value == 4); | ||
| 326 | assert (list.len == 2); | ||
| 327 | } |
std/math/sqrt.zig+14-4| ... | @@ -18,11 +18,21 @@ pub fn sqrt(x: var) -> (if (@typeId(@typeOf(x)) == TypeId.Int) @IntType(false, @ | ... | @@ -18,11 +18,21 @@ pub fn sqrt(x: var) -> (if (@typeId(@typeOf(x)) == TypeId.Int) @IntType(false, @ |
| 18 | return T(sqrt64(x)); | 18 | return T(sqrt64(x)); |
| 19 | }, | 19 | }, |
| 20 | TypeId.Float => { | 20 | TypeId.Float => { |
| 21 | return switch (T) { | 21 | switch (T) { |
| 22 | f32 => sqrt32(x), | 22 | f32 => { |
| 23 | f64 => sqrt64(x), | 23 | switch (builtin.arch) { |
| 24 | builtin.Arch.x86_64 => return @import("x86_64/sqrt.zig").sqrt32(x), | ||
| 25 | else => return sqrt32(x), | ||
| 26 | } | ||
| 27 | }, | ||
| 28 | f64 => { | ||
| 29 | switch (builtin.arch) { | ||
| 30 | builtin.Arch.x86_64 => return @import("x86_64/sqrt.zig").sqrt64(x), | ||
| 31 | else => return sqrt64(x), | ||
| 32 | } | ||
| 33 | }, | ||
| 24 | else => @compileError("sqrt not implemented for " ++ @typeName(T)), | 34 | else => @compileError("sqrt not implemented for " ++ @typeName(T)), |
| 25 | }; | 35 | } |
| 26 | }, | 36 | }, |
| 27 | TypeId.IntLiteral => comptime { | 37 | TypeId.IntLiteral => comptime { |
| 28 | if (x > @maxValue(u128)) { | 38 | if (x > @maxValue(u128)) { |
std/math/x86_64/sqrt.zig created+15| ... | @@ -0,0 +1,15 @@ | ||
| 1 | pub fn sqrt32(x: f32) -> f32 { | ||
| 2 | return asm ( | ||
| 3 | \\sqrtss %%xmm0, %%xmm0 | ||
| 4 | : [ret] "={xmm0}" (-> f32) | ||
| 5 | : [x] "{xmm0}" (x) | ||
| 6 | ); | ||
| 7 | } | ||
| 8 | |||
| 9 | pub fn sqrt64(x: f64) -> f64 { | ||
| 10 | return asm ( | ||
| 11 | \\sqrtsd %%xmm0, %%xmm0 | ||
| 12 | : [ret] "={xmm0}" (-> f64) | ||
| 13 | : [x] "{xmm0}" (x) | ||
| 14 | ); | ||
| 15 | } | ||
test/cases/eval.zig+13| ... | @@ -375,3 +375,16 @@ test "f128 at compile time is lossy" { | ... | @@ -375,3 +375,16 @@ test "f128 at compile time is lossy" { |
| 375 | 375 | ||
| 376 | // TODO need a better implementation of bigfloat_init_bigint | 376 | // TODO need a better implementation of bigfloat_init_bigint |
| 377 | // assert(f128(1 << 113) == 10384593717069655257060992658440192); | 377 | // assert(f128(1 << 113) == 10384593717069655257060992658440192); |
| 378 | |||
| 379 | pub fn TypeWithCompTimeSlice(comptime field_name: []const u8) -> type { | ||
| 380 | return struct { | ||
| 381 | pub const Node = struct { }; | ||
| 382 | }; | ||
| 383 | } | ||
| 384 | |||
| 385 | test "string literal used as comptime slice is memoized" { | ||
| 386 | const a = "link"; | ||
| 387 | const b = "link"; | ||
| 388 | comptime assert(TypeWithCompTimeSlice(a).Node == TypeWithCompTimeSlice(b).Node); | ||
| 389 | comptime assert(TypeWithCompTimeSlice("link").Node == TypeWithCompTimeSlice("link").Node); | ||
| 390 | } |