From 39287d7346436a87ce785866befa77351bf2fc85 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 11 Feb 2017 13:13:45 -0500 Subject: [PATCH] rework compile-time known pointer values See #257 --- src/all_types.hpp | 77 ++++-- src/analyze.cpp | 142 ++++++++--- src/analyze.hpp | 9 +- src/codegen.cpp | 131 ++++++++--- src/ir.cpp | 556 +++++++++++++++++++++++++++----------------- test/cases/eval.zig | 20 ++ 6 files changed, 633 insertions(+), 302 deletions(-) diff --git a/src/all_types.hpp b/src/all_types.hpp index fd8523102f..dee4b3c4d6 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -67,6 +67,27 @@ enum OutType { OutTypeObj, }; +enum ConstParentId { + ConstParentIdNone, + ConstParentIdStruct, + ConstParentIdArray, +}; + +struct ConstParent { + ConstParentId id; + + union { + struct { + ConstExprValue *array_val; + size_t elem_index; + } p_array; + struct { + ConstExprValue *struct_val; + size_t field_index; + } p_struct; + } data; +}; + struct ConstEnumValue { uint64_t tag; ConstExprValue *payload; @@ -74,43 +95,55 @@ struct ConstEnumValue { struct ConstStructValue { ConstExprValue *fields; + ConstParent parent; }; struct ConstArrayValue { ConstExprValue *elements; - // This will be the same as `len` from the type, but we duplicate the information - // in the constant value so that pointers pointing to arrays can see this size. - // TODO now that ConstExprValue has the type field we can use that instead of this. - size_t size; - // If the data for this array is supposed to be contained in a different constant - // value, we link to the parent here. This way getting a pointer to this constant - // value can return a pointer into the parent data structure. - ConstExprValue *parent_array; - size_t parent_array_index; + ConstParent parent; }; enum ConstPtrSpecial { - ConstPtrSpecialNone, - // This helps us preserve the null byte when performing compile-time - // concatenation on C strings. - ConstPtrSpecialCStr, - // This means that the pointer points to inline memory, so attempting - // to write a non-compile-time known value is an error - ConstPtrSpecialInline, + // Enforce explicitly setting this ID by making the zero value invalid. + ConstPtrSpecialInvalid, + // The pointer is a reference to a single object. + ConstPtrSpecialRef, + // The pointer points to an element in an underlying array. + ConstPtrSpecialBaseArray, + // The pointer points to a field in an underlying struct. + ConstPtrSpecialBaseStruct, // This means that we did a compile-time pointer reinterpret and we cannot // understand the value of pointee at compile time. However, we will still // emit a binary with a compile time known address. // In this case index is the numeric address value. - ConstPtrSpecialRuntime, + ConstPtrSpecialHardCodedAddr, }; struct ConstPtrValue { - ConstExprValue *base_ptr; - // If index is SIZE_MAX, then base_ptr points directly to child type. - // Otherwise base_ptr points to an array const val and index is offset - // in object units from base_ptr into the block of memory pointed to - size_t index; ConstPtrSpecial special; + // This means that the pointer points to memory used by a comptime variable, + // so attempting to write a non-compile-time known value is an error + bool comptime_var_mem; + + union { + struct { + ConstExprValue *pointee; + } ref; + struct { + ConstExprValue *array_val; + size_t elem_index; + // This helps us preserve the null byte when performing compile-time + // concatenation on C strings. + bool is_cstr; + } base_array; + struct { + ConstExprValue *struct_val; + size_t field_index; + } base_struct; + struct { + uint64_t addr; + } hard_coded_addr; + } data; }; struct ConstErrValue { diff --git a/src/analyze.cpp b/src/analyze.cpp index 232fae69e1..efa3cde333 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -2832,7 +2832,33 @@ static uint32_t hash_const_val(ConstExprValue *const_val) { return const_val->data.x_arg_tuple.start_index * 281907309 + const_val->data.x_arg_tuple.end_index * 2290442768; case TypeTableEntryIdPointer: - return hash_ptr(const_val->data.x_ptr.base_ptr) + hash_size(const_val->data.x_ptr.index); + { + uint32_t hash_val = const_val->data.x_ptr.comptime_var_mem ? 2216297012 : 170810250; + switch (const_val->data.x_ptr.special) { + case ConstPtrSpecialInvalid: + zig_unreachable(); + case ConstPtrSpecialRef: + hash_val += 2478261866; + hash_val += hash_ptr(const_val->data.x_ptr.data.ref.pointee); + return hash_val; + case ConstPtrSpecialBaseArray: + hash_val += 1764906839; + hash_val += hash_ptr(const_val->data.x_ptr.data.base_array.array_val); + hash_val += hash_size(const_val->data.x_ptr.data.base_array.elem_index); + hash_val += const_val->data.x_ptr.data.base_array.is_cstr ? 1297263887 : 200363492; + return hash_val; + case ConstPtrSpecialBaseStruct: + hash_val += 3518317043; + hash_val += hash_ptr(const_val->data.x_ptr.data.base_struct.struct_val); + hash_val += hash_size(const_val->data.x_ptr.data.base_struct.field_index); + return hash_val; + case ConstPtrSpecialHardCodedAddr: + hash_val += 4048518294; + hash_val += hash_size(const_val->data.x_ptr.data.hard_coded_addr.addr); + return hash_val; + } + zig_unreachable(); + } case TypeTableEntryIdUndefLit: return 162837799; case TypeTableEntryIdNullLit: @@ -3007,7 +3033,6 @@ void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str) { const_val->special = ConstValSpecialStatic; const_val->type = get_array_type(g, g->builtin_types.entry_u8, buf_len(str)); const_val->data.x_array.elements = allocate(buf_len(str)); - const_val->data.x_array.size = buf_len(str); for (size_t i = 0; i < buf_len(str); i += 1) { ConstExprValue *this_char = &const_val->data.x_array.elements[i]; @@ -3030,7 +3055,6 @@ void init_const_c_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str) { array_val->special = ConstValSpecialStatic; array_val->type = get_array_type(g, g->builtin_types.entry_u8, len_with_null); array_val->data.x_array.elements = allocate(len_with_null); - array_val->data.x_array.size = len_with_null; for (size_t i = 0; i < buf_len(str); i += 1) { ConstExprValue *this_char = &array_val->data.x_array.elements[i]; this_char->special = ConstValSpecialStatic; @@ -3045,9 +3069,10 @@ void init_const_c_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str) { // then make the pointer point to it const_val->special = ConstValSpecialStatic; const_val->type = get_pointer_to_type(g, g->builtin_types.entry_u8, true); - const_val->data.x_ptr.base_ptr = array_val; - const_val->data.x_ptr.index = 0; - const_val->data.x_ptr.special = ConstPtrSpecialCStr; + const_val->data.x_ptr.special = ConstPtrSpecialBaseArray; + const_val->data.x_ptr.data.base_array.array_val = array_val; + const_val->data.x_ptr.data.base_array.elem_index = 0; + const_val->data.x_ptr.data.base_array.is_cstr = true; } ConstExprValue *create_const_c_str_lit(CodeGen *g, Buf *str) { ConstExprValue *const_val = allocate(1); @@ -3156,7 +3181,7 @@ void init_const_slice(CodeGen *g, ConstExprValue *const_val, ConstExprValue *arr const_val->type = get_slice_type(g, array_val->type->data.array.child_type, is_const); const_val->data.x_struct.fields = allocate(2); - init_const_ptr(g, &const_val->data.x_struct.fields[slice_ptr_index], array_val, start, is_const); + init_const_ptr_array(g, &const_val->data.x_struct.fields[slice_ptr_index], array_val, start, is_const); init_const_usize(g, &const_val->data.x_struct.fields[slice_len_index], len); } @@ -3166,24 +3191,35 @@ ConstExprValue *create_const_slice(CodeGen *g, ConstExprValue *array_val, size_t return const_val; } -void init_const_ptr(CodeGen *g, ConstExprValue *const_val, ConstExprValue *base_ptr, size_t index, bool is_const) { - TypeTableEntry *child_type; - if (index == SIZE_MAX) { - child_type = base_ptr->type; - } else { - assert(base_ptr->type->id == TypeTableEntryIdArray); - child_type = base_ptr->type->data.array.child_type; - } +void init_const_ptr_array(CodeGen *g, ConstExprValue *const_val, ConstExprValue *array_val, + size_t elem_index, bool is_const) +{ + assert(array_val->type->id == TypeTableEntryIdArray); + TypeTableEntry *child_type = array_val->type->data.array.child_type; const_val->special = ConstValSpecialStatic; const_val->type = get_pointer_to_type(g, child_type, is_const); - const_val->data.x_ptr.base_ptr = base_ptr; - const_val->data.x_ptr.index = index; + const_val->data.x_ptr.special = ConstPtrSpecialBaseArray; + const_val->data.x_ptr.data.base_array.array_val = array_val; + const_val->data.x_ptr.data.base_array.elem_index = elem_index; } -ConstExprValue *create_const_ptr(CodeGen *g, ConstExprValue *base_ptr, size_t index, bool is_const) { +ConstExprValue *create_const_ptr_array(CodeGen *g, ConstExprValue *array_val, size_t elem_index, bool is_const) { ConstExprValue *const_val = allocate(1); - init_const_ptr(g, const_val, base_ptr, index, is_const); + init_const_ptr_array(g, const_val, array_val, elem_index, is_const); + return const_val; +} + +void init_const_ptr_ref(CodeGen *g, ConstExprValue *const_val, ConstExprValue *pointee_val, bool is_const) { + const_val->special = ConstValSpecialStatic; + const_val->type = get_pointer_to_type(g, pointee_val->type, is_const); + const_val->data.x_ptr.special = ConstPtrSpecialRef; + const_val->data.x_ptr.data.ref.pointee = pointee_val; +} + +ConstExprValue *create_const_ptr_ref(CodeGen *g, ConstExprValue *pointee_val, bool is_const) { + ConstExprValue *const_val = allocate(1); + init_const_ptr_ref(g, const_val, pointee_val, is_const); return const_val; } @@ -3207,14 +3243,14 @@ void init_const_undefined(CodeGen *g, ConstExprValue *const_val) { const_val->special = ConstValSpecialStatic; size_t elem_count = canon_wanted_type->data.array.len; const_val->data.x_array.elements = allocate(elem_count); - const_val->data.x_array.size = elem_count; for (size_t i = 0; i < elem_count; i += 1) { ConstExprValue *element_val = &const_val->data.x_array.elements[i]; element_val->type = canon_wanted_type->data.array.child_type; init_const_undefined(g, element_val); if (get_underlying_type(element_val->type)->id == TypeTableEntryIdArray) { - element_val->data.x_array.parent_array = const_val; - element_val->data.x_array.parent_array_index = i; + element_val->data.x_array.parent.id = ConstParentIdArray; + element_val->data.x_array.parent.data.p_array.array_val = const_val; + element_val->data.x_array.parent.data.p_array.elem_index = i; } } } else if (canon_wanted_type->id == TypeTableEntryIdStruct) { @@ -3301,9 +3337,37 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) { case TypeTableEntryIdEnumTag: return bignum_cmp_eq(&a->data.x_bignum, &b->data.x_bignum); case TypeTableEntryIdPointer: - if (a->data.x_ptr.index != b->data.x_ptr.index) + if (a->data.x_ptr.special != b->data.x_ptr.special) return false; - return a->data.x_ptr.base_ptr == b->data.x_ptr.base_ptr; + if (a->data.x_ptr.comptime_var_mem != b->data.x_ptr.comptime_var_mem) + return false; + switch (a->data.x_ptr.special) { + case ConstPtrSpecialInvalid: + zig_unreachable(); + case ConstPtrSpecialRef: + if (a->data.x_ptr.data.ref.pointee != b->data.x_ptr.data.ref.pointee) + return false; + return true; + case ConstPtrSpecialBaseArray: + if (a->data.x_ptr.data.base_array.array_val != b->data.x_ptr.data.base_array.array_val) + return false; + if (a->data.x_ptr.data.base_array.elem_index != b->data.x_ptr.data.base_array.elem_index) + return false; + if (a->data.x_ptr.data.base_array.is_cstr != b->data.x_ptr.data.base_array.is_cstr) + return false; + return true; + case ConstPtrSpecialBaseStruct: + if (a->data.x_ptr.data.base_struct.struct_val != b->data.x_ptr.data.base_struct.struct_val) + return false; + if (a->data.x_ptr.data.base_struct.field_index != b->data.x_ptr.data.base_struct.field_index) + return false; + return true; + case ConstPtrSpecialHardCodedAddr: + if (a->data.x_ptr.data.hard_coded_addr.addr != b->data.x_ptr.data.hard_coded_addr.addr) + return false; + return true; + } + zig_unreachable(); case TypeTableEntryIdArray: zig_panic("TODO"); case TypeTableEntryIdStruct: @@ -3482,15 +3546,29 @@ void render_const_value(Buf *buf, ConstExprValue *const_val) { return; } case TypeTableEntryIdPointer: - buf_appendf(buf, "&"); - if (const_val->data.x_ptr.special == ConstPtrSpecialRuntime) { - buf_appendf(buf, "(runtime pointer value)"); - } else if (const_val->data.x_ptr.special == ConstPtrSpecialCStr) { - buf_appendf(buf, "(c str lit)"); - } else { - render_const_value(buf, const_ptr_pointee(const_val)); + switch (const_val->data.x_ptr.special) { + case ConstPtrSpecialInvalid: + zig_unreachable(); + case ConstPtrSpecialRef: + case ConstPtrSpecialBaseStruct: + buf_appendf(buf, "&"); + render_const_value(buf, const_ptr_pointee(const_val)); + return; + case ConstPtrSpecialBaseArray: + if (const_val->data.x_ptr.data.base_array.is_cstr) { + buf_appendf(buf, "&(c str lit)"); + return; + } else { + buf_appendf(buf, "&"); + render_const_value(buf, const_ptr_pointee(const_val)); + return; + } + case ConstPtrSpecialHardCodedAddr: + buf_appendf(buf, "(&%s)(%" PRIx64 ")", buf_ptr(&canon_type->data.pointer.child_type->name), + const_val->data.x_ptr.data.hard_coded_addr.addr); + return; } - return; + zig_unreachable(); case TypeTableEntryIdFn: { FnTableEntry *fn_entry = const_val->data.x_fn; diff --git a/src/analyze.hpp b/src/analyze.hpp index 19ff3756dd..012e6d19e7 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -126,9 +126,12 @@ ConstExprValue *create_const_type(CodeGen *g, TypeTableEntry *type_value); void init_const_runtime(ConstExprValue *const_val, TypeTableEntry *type); ConstExprValue *create_const_runtime(TypeTableEntry *type); -void init_const_ptr(CodeGen *g, ConstExprValue *const_val, ConstExprValue *base_ptr, size_t index, bool is_const); -ConstExprValue *create_const_ptr(CodeGen *g, ConstExprValue *const_val, ConstExprValue *base_ptr, - size_t index, bool is_const); +void init_const_ptr_ref(CodeGen *g, ConstExprValue *const_val, ConstExprValue *pointee_val, bool is_const); +ConstExprValue *create_const_ptr_ref(CodeGen *g, ConstExprValue *pointee_val, bool is_const); + +void init_const_ptr_array(CodeGen *g, ConstExprValue *const_val, ConstExprValue *array_val, + size_t elem_index, bool is_const); +ConstExprValue *create_const_ptr_array(CodeGen *g, ConstExprValue *array_val, size_t elem_index, bool is_const); void init_const_slice(CodeGen *g, ConstExprValue *const_val, ConstExprValue *array_val, size_t start, size_t len, bool is_const); diff --git a/src/codegen.cpp b/src/codegen.cpp index 828dba3b64..e56c3b7de2 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2527,17 +2527,29 @@ static void ir_render(CodeGen *g, FnTableEntry *fn_entry) { } } -static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *array_const_val, size_t index) { - ConstExprValue *parent_array = array_const_val->data.x_array.parent_array; - LLVMValueRef base_ptr; - if (parent_array) { - size_t parent_array_index = array_const_val->data.x_array.parent_array_index; - base_ptr = gen_const_ptr_array_recursive(g, parent_array, parent_array_index); - } else { - render_const_val(g, array_const_val); - render_const_val_global(g, array_const_val, ""); - base_ptr = array_const_val->llvm_global; +static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *struct_const_val, size_t field_index); +static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *array_const_val, size_t index); + +static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent *parent) { + switch (parent->id) { + case ConstParentIdNone: + render_const_val(g, val); + render_const_val_global(g, val, ""); + return val->llvm_global; + case ConstParentIdStruct: + return gen_const_ptr_struct_recursive(g, parent->data.p_struct.struct_val, + parent->data.p_struct.field_index); + case ConstParentIdArray: + return gen_const_ptr_array_recursive(g, parent->data.p_array.array_val, + parent->data.p_array.elem_index); } + zig_unreachable(); +} + +static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *array_const_val, size_t index) { + ConstParent *parent = &array_const_val->data.x_array.parent; + LLVMValueRef base_ptr = gen_parent_ptr(g, array_const_val, parent); + TypeTableEntry *usize = g->builtin_types.entry_usize; LLVMValueRef indices[] = { LLVMConstNull(usize->type_ref), @@ -2546,6 +2558,19 @@ static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *ar return LLVMConstInBoundsGEP(base_ptr, indices, 2); } +static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *struct_const_val, size_t field_index) { + ConstParent *parent = &struct_const_val->data.x_struct.parent; + LLVMValueRef base_ptr = gen_parent_ptr(g, struct_const_val, parent); + + TypeTableEntry *u32 = g->builtin_types.entry_u32; + LLVMValueRef indices[] = { + LLVMConstNull(u32->type_ref), + LLVMConstInt(u32->type_ref, field_index, false), + }; + return LLVMConstInBoundsGEP(base_ptr, indices, 2); +} + + static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { TypeTableEntry *canon_type = get_underlying_type(const_val->type); assert(!canon_type->zero_bits); @@ -2684,38 +2709,70 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { case TypeTableEntryIdPointer: { render_const_val_global(g, const_val, ""); - size_t index = const_val->data.x_ptr.index; - ConstExprValue *base_ptr = const_val->data.x_ptr.base_ptr; - if (base_ptr) { - if (index == SIZE_MAX) { - render_const_val(g, base_ptr); - render_const_val_global(g, base_ptr, ""); - ConstExprValue *other_val = base_ptr; - const_val->llvm_value = LLVMConstBitCast(other_val->llvm_global, const_val->type->type_ref); - render_const_val_global(g, const_val, ""); - return const_val->llvm_value; - } else { - ConstExprValue *array_const_val = base_ptr; - assert(array_const_val->type->id == TypeTableEntryIdArray); - if (array_const_val->type->zero_bits) { - // make this a null pointer + switch (const_val->data.x_ptr.special) { + case ConstPtrSpecialInvalid: + zig_unreachable(); + case ConstPtrSpecialRef: + { + ConstExprValue *pointee = const_val->data.x_ptr.data.ref.pointee; + render_const_val(g, pointee); + render_const_val_global(g, pointee, ""); + ConstExprValue *other_val = pointee; + const_val->llvm_value = LLVMConstBitCast(other_val->llvm_global, const_val->type->type_ref); + render_const_val_global(g, const_val, ""); + return const_val->llvm_value; + } + case ConstPtrSpecialBaseArray: + { + ConstExprValue *array_const_val = const_val->data.x_ptr.data.base_array.array_val; + size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index; + assert(array_const_val->type->id == TypeTableEntryIdArray); + if (array_const_val->type->zero_bits) { + // make this a null pointer + TypeTableEntry *usize = g->builtin_types.entry_usize; + const_val->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref), + const_val->type->type_ref); + render_const_val_global(g, const_val, ""); + return const_val->llvm_value; + } + LLVMValueRef uncasted_ptr_val = gen_const_ptr_array_recursive(g, array_const_val, + elem_index); + LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref); + const_val->llvm_value = ptr_val; + render_const_val_global(g, const_val, ""); + return ptr_val; + } + case ConstPtrSpecialBaseStruct: + { + ConstExprValue *struct_const_val = const_val->data.x_ptr.data.base_struct.struct_val; + assert(struct_const_val->type->id == TypeTableEntryIdStruct); + if (struct_const_val->type->zero_bits) { + // make this a null pointer + TypeTableEntry *usize = g->builtin_types.entry_usize; + const_val->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref), + const_val->type->type_ref); + render_const_val_global(g, const_val, ""); + return const_val->llvm_value; + } + size_t src_field_index = const_val->data.x_ptr.data.base_struct.field_index; + size_t gen_field_index = + struct_const_val->type->data.structure.fields[src_field_index].gen_index; + LLVMValueRef uncasted_ptr_val = gen_const_ptr_struct_recursive(g, struct_const_val, + gen_field_index); + LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref); + const_val->llvm_value = ptr_val; + render_const_val_global(g, const_val, ""); + return ptr_val; + } + case ConstPtrSpecialHardCodedAddr: + { + uint64_t addr_value = const_val->data.x_ptr.data.hard_coded_addr.addr; TypeTableEntry *usize = g->builtin_types.entry_usize; - const_val->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref), + const_val->llvm_value = LLVMConstIntToPtr(LLVMConstInt(usize->type_ref, addr_value, false), const_val->type->type_ref); render_const_val_global(g, const_val, ""); return const_val->llvm_value; } - LLVMValueRef uncasted_ptr_val = gen_const_ptr_array_recursive(g, array_const_val, index); - LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref); - const_val->llvm_value = ptr_val; - render_const_val_global(g, const_val, ""); - return ptr_val; - } - } else { - TypeTableEntry *usize = g->builtin_types.entry_usize; - const_val->llvm_value = LLVMConstIntToPtr(LLVMConstInt(usize->type_ref, index, false), const_val->type->type_ref); - render_const_val_global(g, const_val, ""); - return const_val->llvm_value; } } case TypeTableEntryIdErrorUnion: diff --git a/src/ir.cpp b/src/ir.cpp index 30bfdca7ce..b0a9c14108 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -64,16 +64,21 @@ static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, Typ ConstExprValue *const_ptr_pointee(ConstExprValue *const_val) { assert(const_val->special == ConstValSpecialStatic); - assert(const_val->data.x_ptr.special != ConstPtrSpecialRuntime); - ConstExprValue *base_ptr = const_val->data.x_ptr.base_ptr; - size_t index = const_val->data.x_ptr.index; - - if (index == SIZE_MAX) { - return base_ptr; - } else { - assert(index < base_ptr->data.x_array.size); - return &base_ptr->data.x_array.elements[index]; + switch (const_val->data.x_ptr.special) { + case ConstPtrSpecialInvalid: + zig_unreachable(); + case ConstPtrSpecialRef: + return const_val->data.x_ptr.data.ref.pointee; + case ConstPtrSpecialBaseArray: + return &const_val->data.x_ptr.data.base_array.array_val->data.x_array.elements[ + const_val->data.x_ptr.data.base_array.elem_index]; + case ConstPtrSpecialBaseStruct: + return &const_val->data.x_ptr.data.base_struct.struct_val->data.x_struct.fields[ + const_val->data.x_ptr.data.base_struct.field_index]; + case ConstPtrSpecialHardCodedAddr: + zig_unreachable(); } + zig_unreachable(); } static bool ir_should_inline(IrExecutable *exec, Scope *scope) { @@ -6209,7 +6214,7 @@ static TypeTableEntry *ir_analyze_void(IrAnalyze *ira, IrInstruction *instructio static TypeTableEntry *ir_analyze_const_ptr(IrAnalyze *ira, IrInstruction *instruction, ConstExprValue *pointee, TypeTableEntry *pointee_type, - ConstPtrSpecial special, bool ptr_is_const, bool ptr_is_volatile) + bool comptime_var_mem, bool ptr_is_const, bool ptr_is_volatile) { if (pointee_type->id == TypeTableEntryIdMetaType) { TypeTableEntry *type_entry = pointee->data.x_type; @@ -6227,9 +6232,9 @@ static TypeTableEntry *ir_analyze_const_ptr(IrAnalyze *ira, IrInstruction *instr TypeTableEntry *ptr_type = get_pointer_to_type_volatile(ira->codegen, pointee_type, ptr_is_const, ptr_is_volatile); ConstExprValue *const_val = ir_build_const_from(ira, instruction); - const_val->data.x_ptr.base_ptr = pointee; - const_val->data.x_ptr.index = SIZE_MAX; - const_val->data.x_ptr.special = special; + const_val->data.x_ptr.special = ConstPtrSpecialRef; + const_val->data.x_ptr.comptime_var_mem = comptime_var_mem; + const_val->data.x_ptr.data.ref.pointee = pointee; return ptr_type; } } @@ -6471,8 +6476,8 @@ static IrInstruction *ir_analyze_cast_ref(IrAnalyze *ira, IrInstruction *source_ source_instr->scope, source_instr->source_node); const_instruction->base.value.type = wanted_type; const_instruction->base.value.special = ConstValSpecialStatic; - const_instruction->base.value.data.x_ptr.base_ptr = val; - const_instruction->base.value.data.x_ptr.index = SIZE_MAX; + const_instruction->base.value.data.x_ptr.special = ConstPtrSpecialRef; + const_instruction->base.value.data.x_ptr.data.ref.pointee = val; return &const_instruction->base; } @@ -6608,10 +6613,10 @@ static IrInstruction *ir_analyze_ptr_to_int(IrAnalyze *ira, IrInstruction *sourc ConstExprValue *val = ir_resolve_const(ira, target, UndefBad); if (!val) return ira->codegen->invalid_instruction; - if (val->data.x_ptr.special == ConstPtrSpecialRuntime) { + if (val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) { IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, source_instr->source_node, wanted_type); - bignum_init_unsigned(&result->value.data.x_bignum, val->data.x_ptr.index); + bignum_init_unsigned(&result->value.data.x_bignum, val->data.x_ptr.data.hard_coded_addr.addr); return result; } } @@ -6633,9 +6638,8 @@ static IrInstruction *ir_analyze_int_to_ptr(IrAnalyze *ira, IrInstruction *sourc return ira->codegen->invalid_instruction; IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, source_instr->source_node, wanted_type); - result->value.data.x_ptr.base_ptr = nullptr; - result->value.data.x_ptr.index = bignum_to_twos_complement(&val->data.x_bignum); - result->value.data.x_ptr.special = ConstPtrSpecialRuntime; + result->value.data.x_ptr.special = ConstPtrSpecialHardCodedAddr; + result->value.data.x_ptr.data.hard_coded_addr.addr = bignum_to_twos_complement(&val->data.x_bignum); return result; } @@ -6660,9 +6664,8 @@ static IrInstruction *ir_analyze_int_lit_to_ptr(IrAnalyze *ira, IrInstruction *s IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, source_instr->source_node, wanted_type); - result->value.data.x_ptr.base_ptr = nullptr; - result->value.data.x_ptr.index = bignum_to_twos_complement(&val->data.x_bignum); - result->value.data.x_ptr.special = ConstPtrSpecialRuntime; + result->value.data.x_ptr.special = ConstPtrSpecialHardCodedAddr; + result->value.data.x_ptr.data.hard_coded_addr.addr = bignum_to_twos_complement(&val->data.x_bignum); return result; } @@ -7006,17 +7009,22 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc return ira->codegen->invalid_instruction; } else if (type_entry->id == TypeTableEntryIdPointer) { TypeTableEntry *child_type = type_entry->data.pointer.child_type; - if (ptr->value.special != ConstValSpecialRuntime) { - ConstExprValue *pointee = const_ptr_pointee(&ptr->value); - if (pointee->special != ConstValSpecialRuntime) { - IrInstruction *result = ir_create_const(&ira->new_irb, source_instruction->scope, - source_instruction->source_node, child_type); - result->value = *pointee; - return result; + if (instr_is_comptime(ptr)) { + // Dereferencing a mutable pointer at compile time is not allowed + // unless that pointer is from a comptime variable + if (type_entry->data.pointer.is_const || ptr->value.data.x_ptr.comptime_var_mem) { + ConstExprValue *pointee = const_ptr_pointee(&ptr->value); + if (pointee->special != ConstValSpecialRuntime) { + IrInstruction *result = ir_create_const(&ira->new_irb, source_instruction->scope, + source_instruction->source_node, child_type); + result->value = *pointee; + return result; + } } } - // TODO if the instruction is a get pointer instruction we can skip it - IrInstruction *load_ptr_instruction = ir_build_load_ptr(&ira->new_irb, source_instruction->scope, source_instruction->source_node, ptr); + // TODO if the instruction is a const ref instruction we can skip it + IrInstruction *load_ptr_instruction = ir_build_load_ptr(&ira->new_irb, source_instruction->scope, + source_instruction->source_node, ptr); load_ptr_instruction->value.type = child_type; return load_ptr_instruction; } else if (type_entry->id == TypeTableEntryIdMetaType) { @@ -7052,8 +7060,7 @@ static TypeTableEntry *ir_analyze_ref(IrAnalyze *ira, IrInstruction *source_inst ConstExprValue *val = ir_resolve_const(ira, value, UndefBad); if (!val) return ira->codegen->builtin_types.entry_invalid; - return ir_analyze_const_ptr(ira, source_instruction, val, value->value.type, - ConstPtrSpecialNone, is_const, is_volatile); + return ir_analyze_const_ptr(ira, source_instruction, val, value->value.type, false, is_const, is_volatile); } TypeTableEntry *ptr_type = get_pointer_to_type_volatile(ira->codegen, value->value.type, is_const, is_volatile); @@ -7136,13 +7143,14 @@ static Buf *ir_resolve_str(IrAnalyze *ira, IrInstruction *value) { ConstExprValue *ptr_field = &const_val->data.x_struct.fields[slice_ptr_index]; ConstExprValue *len_field = &const_val->data.x_struct.fields[slice_len_index]; - ConstExprValue *array_val = ptr_field->data.x_ptr.base_ptr; - assert(ptr_field->data.x_ptr.index != SIZE_MAX); + + assert(ptr_field->data.x_ptr.special == ConstPtrSpecialBaseArray); + ConstExprValue *array_val = ptr_field->data.x_ptr.data.base_array.array_val; size_t len = len_field->data.x_bignum.data.x_uint; Buf *result = buf_alloc(); buf_resize(result, len); for (size_t i = 0; i < len; i += 1) { - size_t new_index = ptr_field->data.x_ptr.index + i; + size_t new_index = ptr_field->data.x_ptr.data.base_array.elem_index + i; ConstExprValue *char_val = &array_val->data.x_array.elements[new_index]; uint64_t big_c = char_val->data.x_bignum.data.x_uint; assert(big_c <= UINT8_MAX); @@ -7591,22 +7599,24 @@ static TypeTableEntry *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp * child_type = op1_canon_type->data.array.child_type; op1_array_val = op1_val; op1_array_index = 0; - op1_array_end = op1_val->data.x_array.size; + op1_array_end = op1_canon_type->data.array.len; } else if (op1_canon_type->id == TypeTableEntryIdPointer && op1_canon_type->data.pointer.child_type == ira->codegen->builtin_types.entry_u8 && - op1_val->data.x_ptr.special == ConstPtrSpecialCStr) + op1_val->data.x_ptr.special == ConstPtrSpecialBaseArray && + op1_val->data.x_ptr.data.base_array.is_cstr) { child_type = op1_canon_type->data.pointer.child_type; - op1_array_val = op1_val->data.x_ptr.base_ptr; - op1_array_index = op1_val->data.x_ptr.index; - op1_array_end = op1_array_val->data.x_array.size - 1; + op1_array_val = op1_val->data.x_ptr.data.base_array.array_val; + op1_array_index = op1_val->data.x_ptr.data.base_array.elem_index; + op1_array_end = op1_array_val->type->data.array.len - 1; } else if (is_slice(op1_canon_type)) { TypeTableEntry *ptr_type = op1_canon_type->data.structure.fields[slice_ptr_index].type_entry; child_type = ptr_type->data.pointer.child_type; ConstExprValue *ptr_val = &op1_val->data.x_struct.fields[slice_ptr_index]; - op1_array_val = ptr_val->data.x_ptr.base_ptr; - op1_array_index = ptr_val->data.x_ptr.index; - op1_array_end = op1_array_val->data.x_array.size; + assert(ptr_val->data.x_ptr.special == ConstPtrSpecialBaseArray); + op1_array_val = ptr_val->data.x_ptr.data.base_array.array_val; + op1_array_index = ptr_val->data.x_ptr.data.base_array.elem_index; + op1_array_end = op1_array_val->type->data.array.len; } else { ir_add_error(ira, op1, buf_sprintf("expected array or C string literal, found '%s'", buf_ptr(&op1->value.type->name))); @@ -7626,10 +7636,11 @@ static TypeTableEntry *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp * } op2_array_val = op2_val; op2_array_index = 0; - op2_array_end = op2_array_val->data.x_array.size; + op2_array_end = op2_array_val->type->data.array.len; } else if (op2_canon_type->id == TypeTableEntryIdPointer && op2_canon_type->data.pointer.child_type == ira->codegen->builtin_types.entry_u8 && - op2_val->data.x_ptr.special == ConstPtrSpecialCStr) + op2_val->data.x_ptr.special == ConstPtrSpecialBaseArray && + op2_val->data.x_ptr.data.base_array.is_cstr) { if (child_type != ira->codegen->builtin_types.entry_u8) { ir_add_error(ira, op2, buf_sprintf("expected array of type '%s', found '%s'", @@ -7637,9 +7648,9 @@ static TypeTableEntry *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp * buf_ptr(&op2->value.type->name))); return ira->codegen->builtin_types.entry_invalid; } - op2_array_val = op2_val->data.x_ptr.base_ptr; - op2_array_index = op2_val->data.x_ptr.index; - op2_array_end = op2_array_val->data.x_array.size - 1; + op2_array_val = op2_val->data.x_ptr.data.base_array.array_val; + op2_array_index = op2_val->data.x_ptr.data.base_array.elem_index; + op2_array_end = op2_array_val->type->data.array.len - 1; } else if (is_slice(op2_canon_type)) { TypeTableEntry *ptr_type = op2_canon_type->data.structure.fields[slice_ptr_index].type_entry; if (ptr_type->data.pointer.child_type != child_type) { @@ -7649,9 +7660,10 @@ static TypeTableEntry *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp * return ira->codegen->builtin_types.entry_invalid; } ConstExprValue *ptr_val = &op2_val->data.x_struct.fields[slice_ptr_index]; - op2_array_val = ptr_val->data.x_ptr.base_ptr; - op2_array_index = ptr_val->data.x_ptr.index; - op2_array_end = op2_array_val->data.x_array.size; + assert(ptr_val->data.x_ptr.special == ConstPtrSpecialBaseArray); + op2_array_val = ptr_val->data.x_ptr.data.base_array.array_val; + op2_array_index = ptr_val->data.x_ptr.data.base_array.elem_index; + op2_array_end = op2_array_val->type->data.array.len; } else { ir_add_error(ira, op2, buf_sprintf("expected array or C string literal, found '%s'", buf_ptr(&op2->value.type->name))); @@ -7676,12 +7688,12 @@ static TypeTableEntry *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp * out_array_val = allocate(1); out_array_val->special = ConstValSpecialStatic; out_array_val->type = get_array_type(ira->codegen, child_type, new_len); - out_val->data.x_ptr.base_ptr = out_array_val; - out_val->data.x_ptr.index = 0; - out_val->data.x_ptr.special = ConstPtrSpecialCStr; + out_val->data.x_ptr.special = ConstPtrSpecialBaseArray; + out_val->data.x_ptr.data.base_array.is_cstr = true; + out_val->data.x_ptr.data.base_array.array_val = out_array_val; + out_val->data.x_ptr.data.base_array.elem_index = 0; } out_array_val->data.x_array.elements = allocate(new_len); - out_array_val->data.x_array.size = new_len; size_t next_index = 0; for (size_t i = op1_array_index; i < op1_array_end; i += 1, next_index += 1) { @@ -7736,7 +7748,6 @@ static TypeTableEntry *ir_analyze_array_mult(IrAnalyze *ira, IrInstructionBinOp ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); uint64_t new_array_len = array_len.data.x_uint; - out_val->data.x_array.size = new_array_len; out_val->data.x_array.elements = allocate(new_array_len); uint64_t i = 0; @@ -8721,24 +8732,23 @@ static TypeTableEntry *ir_analyze_var_ptr(IrAnalyze *ira, IrInstruction *instruc if (var->value.type->id == TypeTableEntryIdInvalid) return var->value.type; - bool is_comptime = ir_get_var_is_comptime(var); + bool comptime_var_mem = ir_get_var_is_comptime(var); ConstExprValue *mem_slot = nullptr; FnTableEntry *fn_entry = scope_fn_entry(var->parent_scope); - if (var->src_is_const && var->value.special == ConstValSpecialStatic) { + if (var->value.special == ConstValSpecialStatic) { mem_slot = &var->value; - assert(mem_slot->special != ConstValSpecialRuntime); } else if (fn_entry) { // TODO once the analyze code is fully ported over to IR we won't need this SIZE_MAX thing. - if (var->mem_slot_index != SIZE_MAX && (is_comptime || var->gen_is_const)) + if (var->mem_slot_index != SIZE_MAX && (comptime_var_mem || var->gen_is_const)) mem_slot = &ira->exec_context.mem_slot_list[var->mem_slot_index]; } bool is_const = (var->value.type->id == TypeTableEntryIdMetaType) ? is_const_ptr : var->src_is_const; bool is_volatile = (var->value.type->id == TypeTableEntryIdMetaType) ? is_volatile_ptr : false; if (mem_slot && mem_slot->special != ConstValSpecialRuntime) { - ConstPtrSpecial ptr_special = is_comptime ? ConstPtrSpecialInline : ConstPtrSpecialNone; - return ir_analyze_const_ptr(ira, instruction, mem_slot, var->value.type, ptr_special, is_const, is_volatile); + return ir_analyze_const_ptr(ira, instruction, mem_slot, var->value.type, + comptime_var_mem, is_const, is_volatile); } else { ir_build_var_ptr_from(&ira->new_irb, instruction, var, is_const, is_volatile); type_ensure_zero_bits_known(ira->codegen, var->value.type); @@ -8793,7 +8803,8 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc buf_sprintf("index 0 outside array of size 0")); } TypeTableEntry *child_type = array_type->data.array.child_type; - return_type = get_pointer_to_type(ira->codegen, child_type, false); + return_type = get_pointer_to_type_volatile(ira->codegen, child_type, + ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile); } else if (array_type->id == TypeTableEntryIdPointer) { return_type = array_type; } else if (is_slice(array_type)) { @@ -8826,8 +8837,7 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc is_const, is_volatile); } else { return ir_analyze_const_ptr(ira, &elem_ptr_instruction->base, &ira->codegen->const_void_val, - ira->codegen->builtin_types.entry_void, ConstPtrSpecialNone, - is_const, is_volatile); + ira->codegen->builtin_types.entry_void, false, is_const, is_volatile); } } else { ir_add_error_node(ira, elem_ptr_instruction->base.source_node, @@ -8858,30 +8868,54 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc if (array_ptr->value.special != ConstValSpecialRuntime && (array_ptr_val = const_ptr_pointee(&array_ptr->value)) && array_ptr_val->special != ConstValSpecialRuntime && - (array_type->id != TypeTableEntryIdPointer || array_ptr_val->data.x_ptr.special != ConstPtrSpecialRuntime)) + (array_type->id != TypeTableEntryIdPointer || + array_ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr)) { ConstExprValue *out_val = ir_build_const_from(ira, &elem_ptr_instruction->base); + out_val->data.x_ptr.comptime_var_mem = array_ptr->value.data.x_ptr.comptime_var_mem; if (array_type->id == TypeTableEntryIdPointer) { - size_t offset = array_ptr_val->data.x_ptr.index; size_t new_index; size_t mem_size; size_t old_size; - if (offset == SIZE_MAX) { - new_index = SIZE_MAX; - mem_size = 1; - old_size = 1; - } else { - new_index = offset + index; - mem_size = array_ptr_val->data.x_ptr.base_ptr->data.x_array.size; - old_size = mem_size - offset; + switch (array_ptr_val->data.x_ptr.special) { + case ConstPtrSpecialInvalid: + zig_unreachable(); + case ConstPtrSpecialRef: + mem_size = 1; + old_size = 1; + new_index = index; + + out_val->data.x_ptr.special = ConstPtrSpecialRef; + out_val->data.x_ptr.data.ref.pointee = array_ptr_val->data.x_ptr.data.ref.pointee; + break; + case ConstPtrSpecialBaseArray: + { + size_t offset = array_ptr_val->data.x_ptr.data.base_array.elem_index; + new_index = offset + index; + mem_size = array_ptr_val->data.x_ptr.data.base_array.array_val->type->data.array.len; + old_size = mem_size - offset; + + assert(array_ptr_val->data.x_ptr.data.base_array.array_val); + + out_val->data.x_ptr.special = ConstPtrSpecialBaseArray; + out_val->data.x_ptr.data.base_array.array_val = + array_ptr_val->data.x_ptr.data.base_array.array_val; + out_val->data.x_ptr.data.base_array.elem_index = new_index; + out_val->data.x_ptr.data.base_array.is_cstr = + array_ptr_val->data.x_ptr.data.base_array.is_cstr; + + break; + } + case ConstPtrSpecialBaseStruct: + zig_panic("TODO elem ptr on a const inner struct"); + case ConstPtrSpecialHardCodedAddr: + zig_unreachable(); } if (new_index >= mem_size) { ir_add_error_node(ira, elem_ptr_instruction->base.source_node, buf_sprintf("index %" PRIu64 " outside pointer of size %" PRIu64, index, old_size)); return ira->codegen->builtin_types.entry_invalid; } - out_val->data.x_ptr.base_ptr = array_ptr_val->data.x_ptr.base_ptr; - out_val->data.x_ptr.index = new_index; } else if (is_slice(array_type)) { ConstExprValue *ptr_field = &array_ptr_val->data.x_struct.fields[slice_ptr_index]; ConstExprValue *len_field = &array_ptr_val->data.x_struct.fields[slice_len_index]; @@ -8892,18 +8926,35 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc index, slice_len)); return ira->codegen->builtin_types.entry_invalid; } - out_val->data.x_ptr.base_ptr = ptr_field->data.x_ptr.base_ptr; - size_t offset = ptr_field->data.x_ptr.index; - if (offset == SIZE_MAX) { - out_val->data.x_ptr.index = SIZE_MAX; - } else { - uint64_t new_index = offset + index; - assert(new_index < ptr_field->data.x_ptr.base_ptr->data.x_array.size); - out_val->data.x_ptr.index = new_index; + switch (ptr_field->data.x_ptr.special) { + case ConstPtrSpecialInvalid: + zig_unreachable(); + case ConstPtrSpecialRef: + out_val->data.x_ptr.special = ConstPtrSpecialRef; + out_val->data.x_ptr.data.ref.pointee = ptr_field->data.x_ptr.data.ref.pointee; + break; + case ConstPtrSpecialBaseArray: + { + size_t offset = ptr_field->data.x_ptr.data.base_array.elem_index; + uint64_t new_index = offset + index; + assert(new_index < ptr_field->data.x_ptr.data.base_array.array_val->type->data.array.len); + out_val->data.x_ptr.special = ConstPtrSpecialBaseArray; + out_val->data.x_ptr.data.base_array.array_val = + ptr_field->data.x_ptr.data.base_array.array_val; + out_val->data.x_ptr.data.base_array.elem_index = new_index; + out_val->data.x_ptr.data.base_array.is_cstr = + ptr_field->data.x_ptr.data.base_array.is_cstr; + break; + } + case ConstPtrSpecialBaseStruct: + zig_panic("TODO elem ptr on a slice backed by const inner struct"); + case ConstPtrSpecialHardCodedAddr: + zig_unreachable(); } } else if (array_type->id == TypeTableEntryIdArray) { - out_val->data.x_ptr.base_ptr = array_ptr_val; - out_val->data.x_ptr.index = index; + out_val->data.x_ptr.special = ConstPtrSpecialBaseArray; + out_val->data.x_ptr.data.base_array.array_val = array_ptr_val; + out_val->data.x_ptr.data.base_array.elem_index = index; } else { zig_unreachable(); } @@ -8931,6 +8982,9 @@ static TypeTableEntry *ir_analyze_container_member_access_inner(IrAnalyze *ira, return ira->codegen->builtin_types.entry_invalid; TldFn *tld_fn = (TldFn *)tld; FnTableEntry *fn_entry = tld_fn->fn_entry; + if (fn_entry->type_entry->id == TypeTableEntryIdInvalid) + return ira->codegen->builtin_types.entry_invalid; + IrInstruction *bound_fn_value = ir_build_const_bound_fn(&ira->new_irb, field_ptr_instruction->base.scope, field_ptr_instruction->base.source_node, fn_entry, container_ptr); return ir_analyze_ref(ira, &field_ptr_instruction->base, bound_fn_value, true, false); @@ -8962,15 +9016,17 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field if (!ptr_val) return ira->codegen->builtin_types.entry_invalid; - if (ptr_val->data.x_ptr.special != ConstPtrSpecialRuntime) { + if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { ConstExprValue *struct_val = const_ptr_pointee(ptr_val); - if (value_is_comptime(struct_val)) { - ConstExprValue *field_val = &struct_val->data.x_struct.fields[field->src_index]; - if (value_is_comptime(field_val)) { - return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, field_val, - field_val->type, ConstPtrSpecialNone, is_const, is_volatile); - } - } + ConstExprValue *field_val = &struct_val->data.x_struct.fields[field->src_index]; + TypeTableEntry *ptr_type = get_pointer_to_type_volatile(ira->codegen, field_val->type, + is_const, is_volatile); + ConstExprValue *const_val = ir_build_const_from(ira, &field_ptr_instruction->base); + const_val->data.x_ptr.special = ConstPtrSpecialBaseStruct; + const_val->data.x_ptr.comptime_var_mem = container_ptr->value.data.x_ptr.comptime_var_mem; + const_val->data.x_ptr.data.base_struct.struct_val = struct_val; + const_val->data.x_ptr.data.base_struct.field_index = field->src_index; + return ptr_type; } } ir_build_struct_field_ptr_from(&ira->new_irb, &field_ptr_instruction->base, container_ptr, field); @@ -9032,7 +9088,7 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source bool ptr_is_const = true; bool ptr_is_volatile = false; return ir_analyze_const_ptr(ira, source_instruction, const_val, fn_entry->type_entry, - ConstPtrSpecialNone, ptr_is_const, ptr_is_volatile); + false, ptr_is_const, ptr_is_volatile); } case TldIdTypeDef: { @@ -9049,7 +9105,7 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source bool ptr_is_const = true; bool ptr_is_volatile = false; return ir_analyze_const_ptr(ira, source_instruction, const_val, ira->codegen->builtin_types.entry_type, - ConstPtrSpecialNone, ptr_is_const, ptr_is_volatile); + false, ptr_is_const, ptr_is_volatile); } } zig_unreachable(); @@ -9092,7 +9148,7 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru bool ptr_is_const = true; bool ptr_is_volatile = false; return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, len_val, - usize, ConstPtrSpecialNone, ptr_is_const, ptr_is_volatile); + usize, false, ptr_is_const, ptr_is_volatile); } else { ir_add_error_node(ira, source_node, buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name), @@ -9116,7 +9172,7 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru bool ptr_is_const = true; bool ptr_is_volatile = false; return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, len_val, - usize, ConstPtrSpecialNone, ptr_is_const, ptr_is_volatile); + usize, false, ptr_is_const, ptr_is_volatile); } else { ir_add_error_node(ira, source_node, buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name), @@ -9155,14 +9211,14 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru bool ptr_is_volatile = false; return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, create_const_enum_tag(child_type, field->value), child_type, - ConstPtrSpecialNone, ptr_is_const, ptr_is_volatile); + false, ptr_is_const, ptr_is_volatile); } else { bool ptr_is_const = true; bool ptr_is_volatile = false; return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, create_const_unsigned_negative(child_type->data.enumeration.tag_type, field->value, false), child_type->data.enumeration.tag_type, - ConstPtrSpecialNone, ptr_is_const, ptr_is_volatile); + false, ptr_is_const, ptr_is_volatile); } } } @@ -9187,7 +9243,7 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru bool ptr_is_const = true; bool ptr_is_volatile = false; return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, const_val, - child_type, ConstPtrSpecialNone, ptr_is_const, ptr_is_volatile); + child_type, false, ptr_is_const, ptr_is_volatile); } ir_add_error(ira, &field_ptr_instruction->base, @@ -9201,14 +9257,14 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru create_const_unsigned_negative(ira->codegen->builtin_types.entry_num_lit_int, child_type->data.integral.bit_count, false), ira->codegen->builtin_types.entry_num_lit_int, - ConstPtrSpecialNone, ptr_is_const, ptr_is_volatile); + false, ptr_is_const, ptr_is_volatile); } else if (buf_eql_str(field_name, "is_signed")) { bool ptr_is_const = true; bool ptr_is_volatile = false; return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, create_const_bool(ira->codegen, child_type->data.integral.is_signed), ira->codegen->builtin_types.entry_bool, - ConstPtrSpecialNone, ptr_is_const, ptr_is_volatile); + false, ptr_is_const, ptr_is_volatile); } else { ir_add_error(ira, &field_ptr_instruction->base, buf_sprintf("type '%s' has no member called '%s'", @@ -9295,16 +9351,16 @@ static TypeTableEntry *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstru if (casted_value == ira->codegen->invalid_instruction) return ira->codegen->builtin_types.entry_invalid; - if (ptr->value.special != ConstValSpecialRuntime && ptr->value.data.x_ptr.special != ConstPtrSpecialRuntime) { - bool is_inline = (ptr->value.data.x_ptr.special == ConstPtrSpecialInline); - if (casted_value->value.special != ConstValSpecialRuntime) { - ConstExprValue *dest_val = const_ptr_pointee(&ptr->value); - if (dest_val->special != ConstValSpecialRuntime) { - *dest_val = casted_value->value; - return ir_analyze_void(ira, &store_ptr_instruction->base); + if (instr_is_comptime(ptr) && ptr->value.data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { + bool comptime_var_mem = ptr->value.data.x_ptr.comptime_var_mem; + if (comptime_var_mem) { + if (instr_is_comptime(casted_value)) { + ConstExprValue *dest_val = const_ptr_pointee(&ptr->value); + if (dest_val->special != ConstValSpecialRuntime) { + *dest_val = casted_value->value; + return ir_analyze_void(ira, &store_ptr_instruction->base); + } } - } - if (is_inline) { ir_add_error(ira, &store_ptr_instruction->base, buf_sprintf("cannot store runtime value in compile time variable")); return ira->codegen->builtin_types.entry_invalid; @@ -9906,14 +9962,15 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira, return ira->codegen->builtin_types.entry_invalid; } TypeTableEntry *child_type = type_entry->data.maybe.child_type; - TypeTableEntry *result_type = get_pointer_to_type(ira->codegen, child_type, false); + TypeTableEntry *result_type = get_pointer_to_type_volatile(ira->codegen, child_type, + ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile); if (instr_is_comptime(value)) { ConstExprValue *val = ir_resolve_const(ira, value, UndefBad); if (!val) return ira->codegen->builtin_types.entry_invalid; - ConstExprValue *maybe_val = val->data.x_ptr.base_ptr; - assert(val->data.x_ptr.index == SIZE_MAX); + assert(val->data.x_ptr.special == ConstPtrSpecialRef); + ConstExprValue *maybe_val = val->data.x_ptr.data.ref.pointee; if (maybe_val->special != ConstValSpecialRuntime) { if (!maybe_val->data.x_maybe) { @@ -9921,8 +9978,8 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira, return ira->codegen->builtin_types.entry_invalid; } ConstExprValue *out_val = ir_build_const_from(ira, &unwrap_maybe_instruction->base); - out_val->data.x_ptr.base_ptr = maybe_val->data.x_maybe; - out_val->data.x_ptr.index = SIZE_MAX; + out_val->data.x_ptr.special = ConstPtrSpecialRef; + out_val->data.x_ptr.data.ref.pointee = maybe_val->data.x_maybe; return result_type; } } @@ -10215,9 +10272,10 @@ static TypeTableEntry *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstr ConstExprValue *pointee_val = const_ptr_pointee(target_val_ptr); if (pointee_val->type->id == TypeTableEntryIdEnum) { ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); - out_val->data.x_ptr.base_ptr = pointee_val->data.x_enum.payload; - out_val->data.x_ptr.index = SIZE_MAX; - return get_pointer_to_type(ira->codegen, pointee_val->type, target_value_ptr->value.type->data.pointer.is_const); + out_val->data.x_ptr.special = ConstPtrSpecialRef; + out_val->data.x_ptr.data.ref.pointee = pointee_val->data.x_enum.payload; + return get_pointer_to_type(ira->codegen, pointee_val->type, + target_value_ptr->value.type->data.pointer.is_const); } else { zig_panic("TODO comptime switch var"); } @@ -10501,7 +10559,6 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira const_val.special = ConstValSpecialStatic; const_val.type = fixed_size_array_type; const_val.data.x_array.elements = allocate(elem_count); - const_val.data.x_array.size = elem_count; bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->base.scope); @@ -10540,8 +10597,9 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira for (size_t i = 0; i < elem_count; i += 1) { ConstExprValue *elem_val = &out_val->data.x_array.elements[i]; if (elem_val->type->id == TypeTableEntryIdArray) { - elem_val->data.x_array.parent_array = out_val; - elem_val->data.x_array.parent_array_index = i; + elem_val->data.x_array.parent.id = ConstParentIdArray; + elem_val->data.x_array.parent.data.p_array.array_val = out_val; + elem_val->data.x_array.parent.data.p_array.elem_index = i; } } return fixed_size_array_type; @@ -11227,22 +11285,34 @@ static TypeTableEntry *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstructi if (casted_dest_ptr->value.special == ConstValSpecialStatic && casted_byte->value.special == ConstValSpecialStatic && - casted_count->value.special == ConstValSpecialStatic) + casted_count->value.special == ConstValSpecialStatic && + casted_dest_ptr->value.data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { ConstExprValue *dest_ptr_val = &casted_dest_ptr->value; ConstExprValue *dest_elements; size_t start; size_t bound_end; - if (dest_ptr_val->data.x_ptr.index == SIZE_MAX) { - dest_elements = dest_ptr_val->data.x_ptr.base_ptr; - start = 0; - bound_end = 1; - } else { - ConstExprValue *array_val = dest_ptr_val->data.x_ptr.base_ptr; - dest_elements = array_val->data.x_array.elements; - start = dest_ptr_val->data.x_ptr.index; - bound_end = array_val->data.x_array.size; + switch (dest_ptr_val->data.x_ptr.special) { + case ConstPtrSpecialInvalid: + zig_unreachable(); + case ConstPtrSpecialRef: + dest_elements = dest_ptr_val->data.x_ptr.data.ref.pointee; + start = 0; + bound_end = 1; + break; + case ConstPtrSpecialBaseArray: + { + ConstExprValue *array_val = dest_ptr_val->data.x_ptr.data.base_array.array_val; + dest_elements = array_val->data.x_array.elements; + start = dest_ptr_val->data.x_ptr.data.base_array.elem_index; + bound_end = array_val->type->data.array.len; + break; + } + case ConstPtrSpecialBaseStruct: + zig_panic("TODO memset on const inner struct"); + case ConstPtrSpecialHardCodedAddr: + zig_unreachable(); } size_t count = casted_count->value.data.x_bignum.data.x_uint; @@ -11304,7 +11374,8 @@ static TypeTableEntry *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructi if (casted_dest_ptr->value.special == ConstValSpecialStatic && casted_src_ptr->value.special == ConstValSpecialStatic && - casted_count->value.special == ConstValSpecialStatic) + casted_count->value.special == ConstValSpecialStatic && + casted_dest_ptr->value.data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { size_t count = casted_count->value.data.x_bignum.data.x_uint; @@ -11312,15 +11383,26 @@ static TypeTableEntry *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructi ConstExprValue *dest_elements; size_t dest_start; size_t dest_end; - if (dest_ptr_val->data.x_ptr.index == SIZE_MAX) { - dest_elements = dest_ptr_val->data.x_ptr.base_ptr; - dest_start = 0; - dest_end = 1; - } else { - ConstExprValue *array_val = dest_ptr_val->data.x_ptr.base_ptr; - dest_elements = array_val->data.x_array.elements; - dest_start = dest_ptr_val->data.x_ptr.index; - dest_end = array_val->data.x_array.size; + switch (dest_ptr_val->data.x_ptr.special) { + case ConstPtrSpecialInvalid: + zig_unreachable(); + case ConstPtrSpecialRef: + dest_elements = dest_ptr_val->data.x_ptr.data.ref.pointee; + dest_start = 0; + dest_end = 1; + break; + case ConstPtrSpecialBaseArray: + { + ConstExprValue *array_val = dest_ptr_val->data.x_ptr.data.base_array.array_val; + dest_elements = array_val->data.x_array.elements; + dest_start = dest_ptr_val->data.x_ptr.data.base_array.elem_index; + dest_end = array_val->type->data.array.len; + break; + } + case ConstPtrSpecialBaseStruct: + zig_panic("TODO memcpy on const inner struct"); + case ConstPtrSpecialHardCodedAddr: + zig_unreachable(); } if (dest_start + count > dest_end) { @@ -11332,15 +11414,27 @@ static TypeTableEntry *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructi ConstExprValue *src_elements; size_t src_start; size_t src_end; - if (src_ptr_val->data.x_ptr.index == SIZE_MAX) { - src_elements = src_ptr_val->data.x_ptr.base_ptr; - src_start = 0; - src_end = 1; - } else { - ConstExprValue *array_val = src_ptr_val->data.x_ptr.base_ptr; - src_elements = array_val->data.x_array.elements; - src_start = src_ptr_val->data.x_ptr.index; - src_end = array_val->data.x_array.size; + + switch (src_ptr_val->data.x_ptr.special) { + case ConstPtrSpecialInvalid: + zig_unreachable(); + case ConstPtrSpecialRef: + src_elements = src_ptr_val->data.x_ptr.data.ref.pointee; + src_start = 0; + src_end = 1; + break; + case ConstPtrSpecialBaseArray: + { + ConstExprValue *array_val = src_ptr_val->data.x_ptr.data.base_array.array_val; + src_elements = array_val->data.x_array.elements; + src_start = src_ptr_val->data.x_ptr.data.base_array.elem_index; + src_end = array_val->type->data.array.len; + break; + } + case ConstPtrSpecialBaseStruct: + zig_panic("TODO memcpy on const inner struct"); + case ConstPtrSpecialHardCodedAddr: + zig_unreachable(); } if (src_start + count > src_end) { @@ -11415,68 +11509,115 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio casted_start->value.special == ConstValSpecialStatic && (!end || end->value.special == ConstValSpecialStatic)) { - ConstExprValue *base_ptr; + ConstExprValue *array_val; + ConstExprValue *parent_ptr; size_t abs_offset; size_t rel_end; if (array_type->id == TypeTableEntryIdArray) { - base_ptr = &ptr->value; + array_val = &ptr->value; abs_offset = 0; rel_end = array_type->data.array.len; + parent_ptr = nullptr; } else if (array_type->id == TypeTableEntryIdPointer) { - base_ptr = ptr->value.data.x_ptr.base_ptr; - abs_offset = ptr->value.data.x_ptr.index; - if (abs_offset == SIZE_MAX) { - rel_end = 1; - } else { - rel_end = base_ptr->data.x_array.size - abs_offset; + parent_ptr = &ptr->value; + switch (parent_ptr->data.x_ptr.special) { + case ConstPtrSpecialInvalid: + zig_unreachable(); + case ConstPtrSpecialRef: + array_val = nullptr; + abs_offset = SIZE_MAX; + rel_end = 1; + break; + case ConstPtrSpecialBaseArray: + array_val = parent_ptr->data.x_ptr.data.base_array.array_val; + abs_offset = parent_ptr->data.x_ptr.data.base_array.elem_index; + rel_end = array_val->type->data.array.len - abs_offset; + break; + case ConstPtrSpecialBaseStruct: + zig_panic("TODO slice const inner struct"); + case ConstPtrSpecialHardCodedAddr: + array_val = nullptr; + break; } } else if (is_slice(array_type)) { - ConstExprValue *ptr_val = &ptr->value.data.x_struct.fields[slice_ptr_index]; + parent_ptr = &ptr->value.data.x_struct.fields[slice_ptr_index]; ConstExprValue *len_val = &ptr->value.data.x_struct.fields[slice_len_index]; - base_ptr = ptr_val->data.x_ptr.base_ptr; - abs_offset = ptr_val->data.x_ptr.index; - if (ptr_val->data.x_ptr.index == SIZE_MAX) { - rel_end = 1; - } else { - rel_end = len_val->data.x_bignum.data.x_uint; + switch (parent_ptr->data.x_ptr.special) { + case ConstPtrSpecialInvalid: + zig_unreachable(); + case ConstPtrSpecialRef: + array_val = nullptr; + abs_offset = SIZE_MAX; + rel_end = 1; + break; + case ConstPtrSpecialBaseArray: + array_val = parent_ptr->data.x_ptr.data.base_array.array_val; + abs_offset = parent_ptr->data.x_ptr.data.base_array.elem_index; + rel_end = len_val->data.x_bignum.data.x_uint; + break; + case ConstPtrSpecialBaseStruct: + zig_panic("TODO slice const inner struct"); + case ConstPtrSpecialHardCodedAddr: + array_val = nullptr; + break; } } else { zig_unreachable(); } - uint64_t start_scalar = casted_start->value.data.x_bignum.data.x_uint; - if (start_scalar > rel_end) { - ir_add_error(ira, &instruction->base, buf_sprintf("out of bounds slice")); - return ira->codegen->builtin_types.entry_invalid; + if (array_val || parent_ptr->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { + uint64_t start_scalar = casted_start->value.data.x_bignum.data.x_uint; + if (start_scalar > rel_end) { + ir_add_error(ira, &instruction->base, buf_sprintf("out of bounds slice")); + return ira->codegen->builtin_types.entry_invalid; + } + + uint64_t end_scalar; + if (end) { + end_scalar = end->value.data.x_bignum.data.x_uint; + } else { + end_scalar = rel_end; + } + if (end_scalar > rel_end) { + ir_add_error(ira, &instruction->base, buf_sprintf("out of bounds slice")); + return ira->codegen->builtin_types.entry_invalid; + } + if (start_scalar > end_scalar) { + ir_add_error(ira, &instruction->base, buf_sprintf("slice start is greater than end")); + return ira->codegen->builtin_types.entry_invalid; + } + + ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); + out_val->data.x_struct.fields = allocate(2); + + ConstExprValue *ptr_val = &out_val->data.x_struct.fields[slice_ptr_index]; + + if (array_val) { + size_t index = abs_offset + start_scalar; + init_const_ptr_array(ira->codegen, ptr_val, array_val, index, instruction->is_const); + } else { + switch (parent_ptr->data.x_ptr.special) { + case ConstPtrSpecialInvalid: + zig_unreachable(); + case ConstPtrSpecialRef: + init_const_ptr_ref(ira->codegen, ptr_val, + parent_ptr->data.x_ptr.data.ref.pointee, instruction->is_const); + break; + case ConstPtrSpecialBaseArray: + zig_unreachable(); + case ConstPtrSpecialBaseStruct: + zig_panic("TODO"); + case ConstPtrSpecialHardCodedAddr: + zig_unreachable(); + } + } + + ConstExprValue *len_val = &out_val->data.x_struct.fields[slice_len_index]; + init_const_usize(ira->codegen, len_val, end_scalar - start_scalar); + + return return_type; } - - uint64_t end_scalar; - if (end) { - end_scalar = end->value.data.x_bignum.data.x_uint; - } else { - end_scalar = rel_end; - } - if (end_scalar > rel_end) { - ir_add_error(ira, &instruction->base, buf_sprintf("out of bounds slice")); - return ira->codegen->builtin_types.entry_invalid; - } - if (start_scalar > end_scalar) { - ir_add_error(ira, &instruction->base, buf_sprintf("slice start is greater than end")); - return ira->codegen->builtin_types.entry_invalid; - } - - ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); - out_val->data.x_struct.fields = allocate(2); - - ConstExprValue *ptr_val = &out_val->data.x_struct.fields[slice_ptr_index]; - size_t index = (abs_offset != SIZE_MAX) ? (abs_offset + start_scalar) : SIZE_MAX; - init_const_ptr(ira->codegen, ptr_val, base_ptr, index, instruction->is_const); - - ConstExprValue *len_val = &out_val->data.x_struct.fields[slice_len_index]; - init_const_usize(ira->codegen, len_val, end_scalar - start_scalar); - - return return_type; } IrInstruction *new_instruction = ir_build_slice_from(&ira->new_irb, &instruction->base, ptr, @@ -11688,8 +11829,7 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira, ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad); if (!ptr_val) return ira->codegen->builtin_types.entry_invalid; - ConstExprValue *err_union_val = ptr_val->data.x_ptr.base_ptr; - assert(ptr_val->data.x_ptr.index == SIZE_MAX); + ConstExprValue *err_union_val = const_ptr_pointee(ptr_val); if (err_union_val->special != ConstValSpecialRuntime) { ErrorTableEntry *err = err_union_val->data.x_err_union.err; assert(err); @@ -11728,13 +11868,13 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira, return ira->codegen->builtin_types.entry_invalid; } else if (canon_type->id == TypeTableEntryIdErrorUnion) { TypeTableEntry *child_type = canon_type->data.error.child_type; - TypeTableEntry *result_type = get_pointer_to_type(ira->codegen, child_type, false); + TypeTableEntry *result_type = get_pointer_to_type_volatile(ira->codegen, child_type, + ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile); if (instr_is_comptime(value)) { ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad); if (!ptr_val) return ira->codegen->builtin_types.entry_invalid; - ConstExprValue *err_union_val = ptr_val->data.x_ptr.base_ptr; - assert(ptr_val->data.x_ptr.index == SIZE_MAX); + ConstExprValue *err_union_val = const_ptr_pointee(ptr_val); if (err_union_val->special != ConstValSpecialRuntime) { ErrorTableEntry *err = err_union_val->data.x_err_union.err; if (err != nullptr) { @@ -11744,8 +11884,8 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira, } ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); - out_val->data.x_ptr.base_ptr = err_union_val->data.x_err_union.payload; - out_val->data.x_ptr.index = SIZE_MAX; + out_val->data.x_ptr.special = ConstPtrSpecialRef; + out_val->data.x_ptr.data.ref.pointee = err_union_val->data.x_err_union.payload; return result_type; } } diff --git a/test/cases/eval.zig b/test/cases/eval.zig index 027bb643b6..00906488c0 100644 --- a/test/cases/eval.zig +++ b/test/cases/eval.zig @@ -263,3 +263,23 @@ fn fnWithSetDebugSafety() -> i32{ @setDebugSafety(this, true); return 1234; } + + + +const SimpleStruct = struct { + field: i32, + + fn method(self: &const SimpleStruct) -> i32 { + return self.field + 3; + } +}; + +var simple_struct = SimpleStruct{ .field = 1234, }; + +const bound_fn = simple_struct.method; + +fn callMethodOnBoundFnReferringToVarInstance() { + @setFnTest(this); + + assert(bound_fn() == 1237); +}