Commit eb5693d91f
Changed files (8)
src/all_types.hpp
@@ -41,6 +41,7 @@ struct IrExecutable {
bool invalid;
ZigList<LabelTableEntry *> all_labels;
ZigList<AstNode *> goto_list;
+ bool is_inline;
};
enum OutType {
@@ -82,6 +83,11 @@ struct ConstErrValue {
ConstExprValue *payload;
};
+struct ConstBoundFnValue {
+ FnTableEntry *fn;
+ IrInstruction *first_arg;
+};
+
enum ConstValSpecial {
ConstValSpecialRuntime,
ConstValSpecialStatic,
@@ -100,6 +106,7 @@ struct ConstExprValue {
BigNum x_bignum;
bool x_bool;
FnTableEntry *x_fn;
+ ConstBoundFnValue x_bound_fn;
TypeTableEntry *x_type;
ConstExprValue *x_maybe;
ConstErrValue x_err;
@@ -494,6 +501,7 @@ struct AstNodeIfBoolExpr {
AstNode *condition;
AstNode *then_block;
AstNode *else_node; // null, block node, or other if expr node
+ bool is_inline; // TODO
// populated by semantic analyzer
};
@@ -503,6 +511,7 @@ struct AstNodeIfVarExpr {
AstNode *then_block;
AstNode *else_node; // null, block node, or other if expr node
bool var_is_ptr;
+ bool is_inline; // TODO
// populated by semantic analyzer
TypeTableEntry *type;
@@ -941,12 +950,18 @@ struct TypeTableEntryFn {
LLVMTypeRef raw_type_ref;
LLVMCallConv calling_convention;
+
+ TypeTableEntry *bound_fn_parent;
};
struct TypeTableEntryGenericFn {
AstNode *decl_node;
};
+struct TypeTableEntryBoundFn {
+ TypeTableEntry *fn_type;
+};
+
struct TypeTableEntryTypeDecl {
TypeTableEntry *child_type;
TypeTableEntry *canonical_type;
@@ -978,6 +993,7 @@ enum TypeTableEntryId {
TypeTableEntryIdNamespace,
TypeTableEntryIdBlock,
TypeTableEntryIdGenericFn,
+ TypeTableEntryIdBoundFn,
};
struct TypeTableEntry {
@@ -988,7 +1004,6 @@ struct TypeTableEntry {
ZigLLVMDIType *di_type;
bool zero_bits;
- bool deep_const;
union {
TypeTableEntryPointer pointer;
@@ -1003,6 +1018,7 @@ struct TypeTableEntry {
TypeTableEntryFn fn;
TypeTableEntryTypeDecl type_decl;
TypeTableEntryGenericFn generic_fn;
+ TypeTableEntryBoundFn bound_fn;
} data;
// use these fields to make sure we don't duplicate type table entries for the same type
@@ -1043,12 +1059,6 @@ enum FnAnalState {
};
-enum WantPure {
- WantPureAuto,
- WantPureFalse,
- WantPureTrue,
-};
-
enum FnInline {
FnInlineAuto,
FnInlineAlways,
@@ -1067,10 +1077,6 @@ struct FnTableEntry {
bool internal_linkage;
bool is_extern;
bool is_test;
- bool is_pure;
- WantPure want_pure;
- AstNode *want_pure_attr_node;
- AstNode *want_pure_return_type;
FnInline fn_inline;
FnAnalState anal_state;
IrExecutable ir_executable;
@@ -1085,6 +1091,9 @@ struct FnTableEntry {
ZigList<VariableTableEntry *> variable_list;
};
+uint32_t fn_table_entry_hash(FnTableEntry*);
+bool fn_table_entry_eql(FnTableEntry *a, FnTableEntry *b);
+
enum BuiltinFnId {
BuiltinFnIdInvalid,
BuiltinFnIdMemcpy,
@@ -1122,7 +1131,6 @@ enum BuiltinFnId {
BuiltinFnIdUnreachable,
BuiltinFnIdSetFnTest,
BuiltinFnIdSetFnVisible,
- BuiltinFnIdSetFnStaticEval,
BuiltinFnIdSetFnNoInline,
BuiltinFnIdSetDebugSafety,
};
@@ -1385,6 +1393,7 @@ enum IrInstructionId {
IrInstructionIdStorePtr,
IrInstructionIdFieldPtr,
IrInstructionIdStructFieldPtr,
+ IrInstructionIdEnumFieldPtr,
IrInstructionIdElemPtr,
IrInstructionIdVarPtr,
IrInstructionIdCall,
@@ -1393,6 +1402,7 @@ enum IrInstructionId {
IrInstructionIdCast,
IrInstructionIdContainerInitList,
IrInstructionIdContainerInitFields,
+ IrInstructionIdStructInit,
IrInstructionIdUnreachable,
IrInstructionIdTypeOf,
IrInstructionIdToPtrType,
@@ -1578,6 +1588,14 @@ struct IrInstructionStructFieldPtr {
bool is_const;
};
+struct IrInstructionEnumFieldPtr {
+ IrInstruction base;
+
+ IrInstruction *enum_ptr;
+ TypeEnumField *field;
+ bool is_const;
+};
+
struct IrInstructionElemPtr {
IrInstruction base;
@@ -1597,9 +1615,12 @@ struct IrInstructionVarPtr {
struct IrInstructionCall {
IrInstruction base;
- IrInstruction *fn;
+ IrInstruction *fn_ref;
+ FnTableEntry *fn_entry;
size_t arg_count;
IrInstruction **args;
+ bool is_inline;
+ LLVMValueRef tmp_ptr;
};
struct IrInstructionConst {
@@ -1615,11 +1636,12 @@ struct IrInstructionReturn {
IrInstruction *value;
};
+// TODO get rid of this instruction, replace with instructions for each op code
struct IrInstructionCast {
IrInstruction base;
IrInstruction *value;
- IrInstruction *dest_type;
+ TypeTableEntry *dest_type;
CastOp cast_op;
LLVMValueRef tmp_ptr;
};
@@ -1630,6 +1652,14 @@ struct IrInstructionContainerInitList {
IrInstruction *container_type;
size_t item_count;
IrInstruction **items;
+ LLVMValueRef tmp_ptr;
+};
+
+struct IrInstructionContainerInitFieldsField {
+ Buf *name;
+ IrInstruction *value;
+ AstNode *source_node;
+ TypeStructField *type_struct_field;
};
struct IrInstructionContainerInitFields {
@@ -1637,8 +1667,21 @@ struct IrInstructionContainerInitFields {
IrInstruction *container_type;
size_t field_count;
- Buf **field_names;
- IrInstruction **field_values;
+ IrInstructionContainerInitFieldsField *fields;
+};
+
+struct IrInstructionStructInitField {
+ IrInstruction *value;
+ TypeStructField *type_struct_field;
+};
+
+struct IrInstructionStructInit {
+ IrInstruction base;
+
+ TypeTableEntry *struct_type;
+ size_t field_count;
+ IrInstructionStructInitField *fields;
+ LLVMValueRef tmp_ptr;
};
struct IrInstructionUnreachable {
@@ -1790,4 +1833,7 @@ static const size_t slice_len_index = 1;
static const size_t maybe_child_index = 0;
static const size_t maybe_null_index = 1;
+static const size_t enum_gen_tag_index = 0;
+static const size_t enum_gen_union_index = 1;
+
#endif
src/analyze.cpp
@@ -84,46 +84,11 @@ AstNode *first_executing_node(AstNode *node) {
zig_unreachable();
}
-void mark_impure_fn(CodeGen *g, BlockContext *context, AstNode *node) {
- if (!context->fn_entry) return;
- if (!context->fn_entry->is_pure) return;
-
- context->fn_entry->is_pure = false;
- if (context->fn_entry->want_pure == WantPureTrue) {
- context->fn_entry->proto_node->data.fn_proto.skip = true;
-
- ErrorMsg *msg = add_node_error(g, context->fn_entry->proto_node,
- buf_sprintf("failed to evaluate function at compile time"));
-
- add_error_note(g, msg, node,
- buf_sprintf("unable to evaluate this expression at compile time"));
-
- if (context->fn_entry->want_pure_attr_node) {
- add_error_note(g, msg, context->fn_entry->want_pure_attr_node,
- buf_sprintf("required to be compile-time function here"));
- }
-
- if (context->fn_entry->want_pure_return_type) {
- add_error_note(g, msg, context->fn_entry->want_pure_return_type,
- buf_sprintf("required to be compile-time function because of return type '%s'",
- buf_ptr(&context->fn_entry->type_entry->data.fn.fn_type_id.return_type->name)));
- }
- }
-}
-
ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) {
// if this assert fails, then parseh generated code that
// failed semantic analysis, which isn't supposed to happen
assert(!node->owner->c_import_node);
- // if an error occurs in a function then it becomes impure
- if (node->block_context) {
- FnTableEntry *fn_entry = node->block_context->fn_entry;
- if (fn_entry) {
- fn_entry->is_pure = false;
- }
- }
-
ErrorMsg *err = err_msg_create_with_line(node->owner->path, node->line, node->column,
node->owner->source_code, node->owner->line_offsets, msg);
@@ -217,6 +182,7 @@ bool type_is_complete(TypeTableEntry *type_entry) {
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
case TypeTableEntryIdGenericFn:
+ case TypeTableEntryIdBoundFn:
return true;
}
zig_unreachable();
@@ -241,7 +207,6 @@ TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x) {
static TypeTableEntry *get_generic_fn_type(CodeGen *g, AstNode *decl_node) {
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdGenericFn);
buf_init_from_str(&entry->name, "(generic function)");
- entry->deep_const = true;
entry->zero_bits = true;
entry->data.generic_fn.decl_node = decl_node;
return entry;
@@ -255,8 +220,6 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool
} else {
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdPointer);
- entry->deep_const = is_const && child_type->deep_const;
-
const char *const_str = is_const ? "const " : "";
buf_resize(&entry->name, 0);
buf_appendf(&entry->name, "&%s%s", const_str, buf_ptr(&child_type->name));
@@ -298,8 +261,6 @@ TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {
assert(child_type->type_ref);
assert(child_type->di_type);
- entry->deep_const = child_type->deep_const;
-
buf_resize(&entry->name, 0);
buf_appendf(&entry->name, "?%s", buf_ptr(&child_type->name));
@@ -383,8 +344,6 @@ TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) {
entry->data.error.child_type = child_type;
- entry->deep_const = child_type->deep_const;
-
if (!type_has_bits(child_type)) {
entry->type_ref = g->err_tag_type->type_ref;
entry->di_type = g->err_tag_type->di_type;
@@ -456,7 +415,6 @@ TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdArray);
entry->type_ref = child_type->type_ref ? LLVMArrayType(child_type->type_ref, array_size) : nullptr;
entry->zero_bits = (array_size == 0) || child_type->zero_bits;
- entry->deep_const = child_type->deep_const;
buf_resize(&entry->name, 0);
buf_appendf(&entry->name, "[%" PRIu64 "]%s", array_size, buf_ptr(&child_type->name));
@@ -507,8 +465,6 @@ TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *child_type, bool is_c
TypeTableEntry *var_peer = get_slice_type(g, child_type, false);
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdStruct);
- entry->deep_const = child_type->deep_const;
-
buf_resize(&entry->name, 0);
buf_appendf(&entry->name, "[]const %s", buf_ptr(&child_type->name));
@@ -657,7 +613,6 @@ TypeTableEntry *get_typedecl_type(CodeGen *g, const char *name, TypeTableEntry *
buf_init_from_str(&entry->name, name);
- entry->deep_const = child_type->deep_const;
entry->type_ref = child_type->type_ref;
entry->di_type = child_type->di_type;
entry->zero_bits = child_type->zero_bits;
@@ -673,6 +628,23 @@ TypeTableEntry *get_typedecl_type(CodeGen *g, const char *name, TypeTableEntry *
return entry;
}
+TypeTableEntry *get_bound_fn_type(CodeGen *g, FnTableEntry *fn_entry) {
+ TypeTableEntry *fn_type = fn_entry->type_entry;
+ assert(fn_type->id == TypeTableEntryIdFn);
+ if (fn_type->data.fn.bound_fn_parent)
+ return fn_type->data.fn.bound_fn_parent;
+
+ TypeTableEntry *bound_fn_type = new_type_table_entry(TypeTableEntryIdBoundFn);
+ bound_fn_type->data.bound_fn.fn_type = fn_type;
+ bound_fn_type->zero_bits = true;
+
+ buf_resize(&bound_fn_type->name, 0);
+ buf_appendf(&bound_fn_type->name, "(bound %s)", buf_ptr(&fn_type->name));
+
+ fn_type->data.fn.bound_fn_parent = bound_fn_type;
+ return bound_fn_type;
+}
+
// accepts ownership of fn_type_id memory
TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id, bool gen_debug_info) {
auto table_entry = g->fn_type_table.maybe_get(fn_type_id);
@@ -681,7 +653,6 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id, bool gen_debug_inf
}
TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn);
- fn_type->deep_const = true;
fn_type->data.fn.fn_type_id = *fn_type_id;
if (fn_type_id->is_cold) {
@@ -838,6 +809,7 @@ static IrInstruction *analyze_const_value(CodeGen *g, BlockContext *scope, AstNo
TypeTableEntry *expected_type)
{
IrExecutable ir_executable = {0};
+ ir_executable.is_inline = true;
ir_gen(g, node, scope, &ir_executable);
if (ir_executable.invalid)
@@ -851,6 +823,7 @@ static IrInstruction *analyze_const_value(CodeGen *g, BlockContext *scope, AstNo
fprintf(stderr, "}\n");
}
IrExecutable analyzed_executable = {0};
+ analyzed_executable.is_inline = true;
analyzed_executable.backward_branch_quota = default_backward_branch_quota;
TypeTableEntry *result_type = ir_analyze(g, &ir_executable, &analyzed_executable, expected_type, node);
if (result_type->id == TypeTableEntryIdInvalid)
@@ -884,8 +857,7 @@ static TypeTableEntry *analyze_type_expr(CodeGen *g, ImportTableEntry *import, B
static bool fn_wants_full_static_eval(FnTableEntry *fn_table_entry) {
assert(fn_table_entry);
- AstNodeFnProto *fn_proto = &fn_table_entry->proto_node->data.fn_proto;
- return fn_proto->inline_arg_count == fn_proto->params.length && fn_table_entry->want_pure == WantPureTrue;
+ return false;
}
// fn_table_entry is populated if and only if there is a function definition for this prototype
@@ -931,6 +903,7 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
case TypeTableEntryIdGenericFn:
+ case TypeTableEntryIdBoundFn:
if (!fn_proto->skip) {
fn_proto->skip = true;
add_node_error(g, child->data.param_decl.type,
@@ -991,6 +964,7 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
case TypeTableEntryIdGenericFn:
+ case TypeTableEntryIdBoundFn:
case TypeTableEntryIdVar:
if (!fn_proto->skip) {
fn_proto->skip = true;
@@ -1023,9 +997,6 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor
}
if (fn_table_entry && fn_type_id.return_type->id == TypeTableEntryIdMetaType) {
- fn_table_entry->want_pure = WantPureTrue;
- fn_table_entry->want_pure_return_type = fn_proto->return_type;
-
ErrorMsg *err_msg = nullptr;
for (size_t i = 0; i < fn_proto->params.length; i += 1) {
AstNode *param_decl_node = fn_proto->params.at(i);
@@ -1046,8 +1017,7 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor
}
}
-
- bool gen_debug_info = !(fn_table_entry && fn_wants_full_static_eval(fn_table_entry));
+ bool gen_debug_info = fn_table_entry && !fn_wants_full_static_eval(fn_table_entry);
return get_fn_type(g, &fn_type_id, gen_debug_info);
}
@@ -1167,8 +1137,6 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt
assert(decl_node->type == NodeTypeContainerDecl);
assert(enum_type->di_type);
- enum_type->deep_const = true;
-
uint32_t field_count = decl_node->data.struct_decl.fields.length;
enum_type->data.enumeration.src_field_count = field_count;
@@ -1198,11 +1166,6 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt
type_enum_field->type_entry = field_type;
type_enum_field->value = i;
- if (!field_type->deep_const) {
- enum_type->deep_const = false;
- }
-
-
di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(type_enum_field->name), i);
if (field_type->id == TypeTableEntryIdStruct) {
@@ -1362,8 +1325,6 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE
assert(decl_node->type == NodeTypeContainerDecl);
assert(struct_type->di_type);
- struct_type->deep_const = true;
-
size_t field_count = decl_node->data.struct_decl.fields.length;
struct_type->data.structure.src_field_count = field_count;
@@ -1389,10 +1350,6 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE
type_struct_field->src_index = i;
type_struct_field->gen_index = SIZE_MAX;
- if (!field_type->deep_const) {
- struct_type->deep_const = false;
- }
-
if (field_type->id == TypeTableEntryIdStruct) {
resolve_struct_type(g, import, field_type);
} else if (field_type->id == TypeTableEntryIdEnum) {
@@ -1537,7 +1494,6 @@ static void preview_fn_proto_instance(CodeGen *g, ImportTableEntry *import, AstN
fn_table_entry->proto_node = proto_node;
fn_table_entry->fn_def_node = fn_def_node;
fn_table_entry->is_extern = is_extern;
- fn_table_entry->is_pure = fn_def_node != nullptr;
get_fully_qualified_decl_name(&fn_table_entry->symbol_name, proto_node, '_');
@@ -1852,6 +1808,7 @@ TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEnt
case TypeTableEntryIdUnion:
case TypeTableEntryIdFn:
case TypeTableEntryIdGenericFn:
+ case TypeTableEntryIdBoundFn:
return type_entry;
}
zig_unreachable();
@@ -2100,6 +2057,7 @@ static bool type_has_codegen_value(TypeTableEntry *type_entry) {
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
case TypeTableEntryIdGenericFn:
+ case TypeTableEntryIdBoundFn:
return false;
case TypeTableEntryIdBool:
@@ -2314,6 +2272,7 @@ static bool is_container(TypeTableEntry *type_entry) {
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
case TypeTableEntryIdGenericFn:
+ case TypeTableEntryIdBoundFn:
return false;
}
zig_unreachable();
@@ -2361,6 +2320,7 @@ void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry) {
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
case TypeTableEntryIdGenericFn:
+ case TypeTableEntryIdBoundFn:
case TypeTableEntryIdInvalid:
case TypeTableEntryIdVar:
zig_unreachable();
@@ -2429,10 +2389,6 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) {
if (fn_type->data.fn.gen_param_info) {
var->gen_arg_index = fn_type->data.fn.gen_param_info[i].gen_index;
}
-
- if (!type->deep_const) {
- fn_table_entry->is_pure = false;
- }
}
TypeTableEntry *expected_type = fn_type->data.fn.fn_type_id.return_type;
@@ -2768,6 +2724,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
case TypeTableEntryIdGenericFn:
+ case TypeTableEntryIdBoundFn:
case TypeTableEntryIdVar:
zig_unreachable();
case TypeTableEntryIdUnreachable:
@@ -2820,6 +2777,14 @@ static uint32_t hash_size(size_t x) {
return x % UINT32_MAX;
}
+uint32_t fn_table_entry_hash(FnTableEntry* value) {
+ return ptr_hash(value);
+}
+
+bool fn_table_entry_eql(FnTableEntry *a, FnTableEntry *b) {
+ return ptr_eq(a, b);
+}
+
uint32_t fn_type_id_hash(FnTypeId *id) {
uint32_t result = 0;
result += id->is_extern ? 3349388391 : 0;
@@ -2912,6 +2877,7 @@ static uint32_t hash_const_val(TypeTableEntry *type, ConstExprValue *const_val)
case TypeTableEntryIdBlock:
return hash_ptr(const_val->data.x_block);
case TypeTableEntryIdGenericFn:
+ case TypeTableEntryIdBoundFn:
case TypeTableEntryIdInvalid:
case TypeTableEntryIdUnreachable:
case TypeTableEntryIdVar:
@@ -2990,6 +2956,7 @@ static TypeTableEntry *type_of_first_thing_in_memory(TypeTableEntry *type_entry)
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
case TypeTableEntryIdGenericFn:
+ case TypeTableEntryIdBoundFn:
case TypeTableEntryIdVar:
zig_unreachable();
case TypeTableEntryIdArray:
src/analyze.hpp
@@ -31,6 +31,7 @@ TypeTableEntry *get_partial_container_type(CodeGen *g, ImportTableEntry *import,
ContainerKind kind, AstNode *decl_node, const char *name);
TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x);
TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type);
+TypeTableEntry *get_bound_fn_type(CodeGen *g, FnTableEntry *fn_entry);
bool handle_is_ptr(TypeTableEntry *type_entry);
void find_libc_include_path(CodeGen *g);
void find_libc_lib_path(CodeGen *g);
@@ -52,7 +53,6 @@ VariableTableEntry *find_variable(CodeGen *g, BlockContext *orig_context, Buf *n
AstNode *find_decl(BlockContext *context, Buf *name);
void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only);
TopLevelDecl *get_as_top_level_decl(AstNode *node);
-void mark_impure_fn(CodeGen *g, BlockContext *context, AstNode *node);
bool type_is_codegen_pointer(TypeTableEntry *type);
TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEntry *type_entry);
TypeTableEntry *container_ref_type(TypeTableEntry *type_entry);
src/codegen.cpp
@@ -1368,27 +1368,34 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrI
}
static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstructionCall *instruction) {
- LLVMValueRef fn_val = ir_llvm_value(g, instruction->fn);
- TypeTableEntry *fn_type = instruction->fn->type_entry;
+ LLVMValueRef fn_val;
+ TypeTableEntry *fn_type;
+ if (instruction->fn_entry) {
+ fn_val = instruction->fn_entry->fn_value;
+ fn_type = instruction->fn_entry->type_entry;
+ } else {
+ assert(instruction->fn_ref);
+ fn_val = ir_llvm_value(g, instruction->fn_ref);
+ fn_type = instruction->fn_ref->type_entry;
+ }
+
TypeTableEntry *src_return_type = fn_type->data.fn.fn_type_id.return_type;
bool ret_has_bits = type_has_bits(src_return_type);
- size_t fn_call_param_count = instruction->arg_count;
bool first_arg_ret = ret_has_bits && handle_is_ptr(src_return_type);
- size_t actual_param_count = fn_call_param_count + (first_arg_ret ? 1 : 0);
+ size_t actual_param_count = instruction->arg_count + (first_arg_ret ? 1 : 0);
bool is_var_args = fn_type->data.fn.fn_type_id.is_var_args;
LLVMValueRef *gen_param_values = allocate<LLVMValueRef>(actual_param_count);
size_t gen_param_index = 0;
if (first_arg_ret) {
- zig_panic("TODO");
- //gen_param_values[gen_param_index] = node->data.fn_call_expr.tmp_ptr;
- //gen_param_index += 1;
+ gen_param_values[gen_param_index] = instruction->tmp_ptr;
+ gen_param_index += 1;
}
- for (size_t call_i = 0; call_i < fn_call_param_count; call_i += 1) {
+ for (size_t call_i = 0; call_i < instruction->arg_count; call_i += 1) {
IrInstruction *param_instruction = instruction->args[call_i];
- LLVMValueRef param_value = ir_llvm_value(g, param_instruction);
- assert(param_value);
TypeTableEntry *param_type = param_instruction->type_entry;
if (is_var_args || type_has_bits(param_type)) {
+ LLVMValueRef param_value = ir_llvm_value(g, param_instruction);
+ assert(param_value);
gen_param_values[gen_param_index] = param_value;
gen_param_index += 1;
}
@@ -1402,8 +1409,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
} else if (!ret_has_bits) {
return nullptr;
} else if (first_arg_ret) {
- zig_panic("TODO");
- //return node->data.fn_call_expr.tmp_ptr;
+ return instruction->tmp_ptr;
} else {
return result;
}
@@ -1422,6 +1428,22 @@ static LLVMValueRef ir_render_struct_field_ptr(CodeGen *g, IrExecutable *executa
return LLVMBuildStructGEP(g->builder, struct_ptr, field->gen_index, "");
}
+static LLVMValueRef ir_render_enum_field_ptr(CodeGen *g, IrExecutable *executable,
+ IrInstructionEnumFieldPtr *instruction)
+{
+ LLVMValueRef enum_ptr = ir_llvm_value(g, instruction->enum_ptr);
+ TypeEnumField *field = instruction->field;
+
+ if (!type_has_bits(field->type_entry))
+ return nullptr;
+
+ LLVMTypeRef field_type_ref = LLVMPointerType(field->type_entry->type_ref, 0);
+ LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, enum_ptr, enum_gen_union_index, "");
+ LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr, field_type_ref, "");
+
+ return bitcasted_union_field_ptr;
+}
+
static size_t find_asm_index(CodeGen *g, AstNode *node, AsmToken *tok) {
const char *ptr = buf_ptr(node->data.asm_expr.asm_template) + tok->start + 2;
size_t len = tok->end - tok->start - 2;
@@ -1691,6 +1713,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
case IrInstructionIdSwitchTarget:
case IrInstructionIdStaticEval:
case IrInstructionIdImport:
+ case IrInstructionIdContainerInitFields:
zig_unreachable();
case IrInstructionIdReturn:
return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
@@ -1720,6 +1743,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_call(g, executable, (IrInstructionCall *)instruction);
case IrInstructionIdStructFieldPtr:
return ir_render_struct_field_ptr(g, executable, (IrInstructionStructFieldPtr *)instruction);
+ case IrInstructionIdEnumFieldPtr:
+ return ir_render_enum_field_ptr(g, executable, (IrInstructionEnumFieldPtr *)instruction);
case IrInstructionIdAsm:
return ir_render_asm(g, executable, (IrInstructionAsm *)instruction);
case IrInstructionIdTestNull:
@@ -1738,7 +1763,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_ref(g, executable, (IrInstructionRef *)instruction);
case IrInstructionIdSwitchVar:
case IrInstructionIdContainerInitList:
- case IrInstructionIdContainerInitFields:
+ case IrInstructionIdStructInit:
case IrInstructionIdEnumTag:
case IrInstructionIdArrayLen:
zig_panic("TODO render more IR instructions to LLVM");
@@ -1960,6 +1985,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
case TypeTableEntryIdGenericFn:
+ case TypeTableEntryIdBoundFn:
case TypeTableEntryIdVar:
zig_unreachable();
@@ -2197,7 +2223,6 @@ static void do_code_gen(CodeGen *g) {
TypeTableEntry *fn_type = fn_table_entry->type_entry;
- bool is_sret = false;
if (!type_has_bits(fn_type->data.fn.fn_type_id.return_type)) {
// nothing to do
} else if (fn_type->data.fn.fn_type_id.return_type->id == TypeTableEntryIdPointer) {
@@ -2208,10 +2233,6 @@ static void do_code_gen(CodeGen *g) {
LLVMValueRef first_arg = LLVMGetParam(fn_table_entry->fn_value, 0);
LLVMAddAttribute(first_arg, LLVMStructRetAttribute);
ZigLLVMAddNonNullAttr(fn_table_entry->fn_value, 1);
- is_sret = true;
- }
- if (fn_table_entry->is_pure && !is_sret && g->is_release_build) {
- LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMReadOnlyAttribute);
}
@@ -2234,9 +2255,7 @@ static void do_code_gen(CodeGen *g) {
if (param_is_noalias) {
LLVMAddAttribute(argument_val, LLVMNoAliasAttribute);
}
- if ((param_type->id == TypeTableEntryIdPointer && (param_type->data.pointer.is_const || fn_table_entry->is_pure)) ||
- is_byval)
- {
+ if ((param_type->id == TypeTableEntryIdPointer && param_type->data.pointer.is_const) || is_byval) {
LLVMAddAttribute(argument_val, LLVMReadOnlyAttribute);
}
if (param_type->id == TypeTableEntryIdPointer) {
@@ -2339,6 +2358,15 @@ static void do_code_gen(CodeGen *g) {
} else if (instruction->id == IrInstructionIdRef) {
IrInstructionRef *ref_instruction = (IrInstructionRef *)instruction;
slot = &ref_instruction->tmp_ptr;
+ } else if (instruction->id == IrInstructionIdContainerInitList) {
+ IrInstructionContainerInitList *container_init_list_instruction = (IrInstructionContainerInitList *)instruction;
+ slot = &container_init_list_instruction->tmp_ptr;
+ } else if (instruction->id == IrInstructionIdStructInit) {
+ IrInstructionStructInit *struct_init_instruction = (IrInstructionStructInit *)instruction;
+ slot = &struct_init_instruction->tmp_ptr;
+ } else if (instruction->id == IrInstructionIdCall) {
+ IrInstructionCall *call_instruction = (IrInstructionCall *)instruction;
+ slot = &call_instruction->tmp_ptr;
} else {
zig_unreachable();
}
@@ -2464,46 +2492,39 @@ static void define_builtin_types(CodeGen *g) {
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdNamespace);
buf_init_from_str(&entry->name, "(namespace)");
entry->zero_bits = true;
- entry->deep_const = true;
g->builtin_types.entry_namespace = entry;
}
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdBlock);
buf_init_from_str(&entry->name, "(block)");
entry->zero_bits = true;
- entry->deep_const = true;
g->builtin_types.entry_block = entry;
}
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdNumLitFloat);
buf_init_from_str(&entry->name, "(float literal)");
entry->zero_bits = true;
- entry->deep_const = true;
g->builtin_types.entry_num_lit_float = entry;
}
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdNumLitInt);
buf_init_from_str(&entry->name, "(integer literal)");
entry->zero_bits = true;
- entry->deep_const = true;
g->builtin_types.entry_num_lit_int = entry;
}
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdUndefLit);
buf_init_from_str(&entry->name, "(undefined)");
- entry->deep_const = true;
g->builtin_types.entry_undef = entry;
}
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdNullLit);
buf_init_from_str(&entry->name, "(null)");
- entry->deep_const = true;
g->builtin_types.entry_null = entry;
}
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdVar);
buf_init_from_str(&entry->name, "(var)");
- entry->deep_const = true;
g->builtin_types.entry_var = entry;
}
@@ -2514,7 +2535,6 @@ static void define_builtin_types(CodeGen *g) {
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
entry->type_ref = LLVMIntType(size_in_bits);
- entry->deep_const = true;
const char u_or_i = is_signed ? 'i' : 'u';
buf_resize(&entry->name, 0);
@@ -2554,7 +2574,6 @@ static void define_builtin_types(CodeGen *g) {
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
entry->type_ref = LLVMIntType(size_in_bits);
- entry->deep_const = true;
buf_init_from_str(&entry->name, info->name);
@@ -2574,7 +2593,6 @@ static void define_builtin_types(CodeGen *g) {
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdBool);
entry->type_ref = LLVMInt1Type();
- entry->deep_const = true;
buf_init_from_str(&entry->name, "bool");
uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref);
uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, entry->type_ref);
@@ -2590,7 +2608,6 @@ static void define_builtin_types(CodeGen *g) {
bool is_signed = is_signed_list[sign_i];
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
- entry->deep_const = true;
entry->type_ref = LLVMIntType(g->pointer_size_bytes * 8);
const char u_or_i = is_signed ? 'i' : 'u';
@@ -2616,7 +2633,6 @@ static void define_builtin_types(CodeGen *g) {
}
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat);
- entry->deep_const = true;
entry->type_ref = LLVMFloatType();
buf_init_from_str(&entry->name, "f32");
entry->data.floating.bit_count = 32;
@@ -2632,7 +2648,6 @@ static void define_builtin_types(CodeGen *g) {
}
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat);
- entry->deep_const = true;
entry->type_ref = LLVMDoubleType();
buf_init_from_str(&entry->name, "f64");
entry->data.floating.bit_count = 64;
@@ -2648,7 +2663,6 @@ static void define_builtin_types(CodeGen *g) {
}
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat);
- entry->deep_const = true;
entry->type_ref = LLVMX86FP80Type();
buf_init_from_str(&entry->name, "c_long_double");
entry->data.floating.bit_count = 80;
@@ -2664,7 +2678,6 @@ static void define_builtin_types(CodeGen *g) {
}
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdVoid);
- entry->deep_const = true;
entry->type_ref = LLVMVoidType();
entry->zero_bits = true;
buf_init_from_str(&entry->name, "void");
@@ -2677,7 +2690,6 @@ static void define_builtin_types(CodeGen *g) {
}
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdUnreachable);
- entry->deep_const = true;
entry->type_ref = LLVMVoidType();
entry->zero_bits = true;
buf_init_from_str(&entry->name, "unreachable");
@@ -2687,7 +2699,6 @@ static void define_builtin_types(CodeGen *g) {
}
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdMetaType);
- entry->deep_const = true;
buf_init_from_str(&entry->name, "type");
entry->zero_bits = true;
g->builtin_types.entry_type = entry;
@@ -2710,7 +2721,6 @@ static void define_builtin_types(CodeGen *g) {
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdPureError);
- entry->deep_const = true;
buf_init_from_str(&entry->name, "error");
// TODO allow overriding this type and keep track of max value and emit an
@@ -2726,7 +2736,6 @@ static void define_builtin_types(CodeGen *g) {
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);
- entry->deep_const = true;
entry->zero_bits = true; // only allowed at compile time
buf_init_from_str(&entry->name, "@OS");
uint32_t field_count = target_os_count();
@@ -2752,7 +2761,6 @@ static void define_builtin_types(CodeGen *g) {
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);
- entry->deep_const = true;
entry->zero_bits = true; // only allowed at compile time
buf_init_from_str(&entry->name, "@Arch");
uint32_t field_count = target_arch_count();
@@ -2784,7 +2792,6 @@ static void define_builtin_types(CodeGen *g) {
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);
- entry->deep_const = true;
entry->zero_bits = true; // only allowed at compile time
buf_init_from_str(&entry->name, "@Environ");
uint32_t field_count = target_environ_count();
@@ -2811,7 +2818,6 @@ static void define_builtin_types(CodeGen *g) {
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);
- entry->deep_const = true;
entry->zero_bits = true; // only allowed at compile time
buf_init_from_str(&entry->name, "@ObjectFormat");
uint32_t field_count = target_oformat_count();
@@ -2838,7 +2844,6 @@ static void define_builtin_types(CodeGen *g) {
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);
- entry->deep_const = true;
buf_init_from_str(&entry->name, "AtomicOrder");
uint32_t field_count = 6;
entry->data.enumeration.src_field_count = field_count;
@@ -2998,7 +3003,6 @@ static void define_builtin_fns(CodeGen *g) {
create_builtin_fn_with_arg_count(g, BuiltinFnIdUnreachable, "unreachable", 0);
create_builtin_fn_with_arg_count(g, BuiltinFnIdSetFnTest, "setFnTest", 2);
create_builtin_fn_with_arg_count(g, BuiltinFnIdSetFnVisible, "setFnVisible", 2);
- create_builtin_fn_with_arg_count(g, BuiltinFnIdSetFnStaticEval, "setFnStaticEval", 2);
create_builtin_fn_with_arg_count(g, BuiltinFnIdSetFnNoInline, "setFnNoInline", 2);
create_builtin_fn_with_arg_count(g, BuiltinFnIdSetDebugSafety, "setDebugSafety", 2);
}
@@ -3287,6 +3291,7 @@ static void get_c_type(CodeGen *g, TypeTableEntry *type_entry, Buf *out_buf) {
case TypeTableEntryIdInvalid:
case TypeTableEntryIdMetaType:
case TypeTableEntryIdGenericFn:
+ case TypeTableEntryIdBoundFn:
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
case TypeTableEntryIdNumLitFloat:
src/eval.cpp
@@ -56,6 +56,7 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b, TypeTableEntry *ty
case TypeTableEntryIdBlock:
zig_panic("TODO");
case TypeTableEntryIdGenericFn:
+ case TypeTableEntryIdBoundFn:
case TypeTableEntryIdInvalid:
case TypeTableEntryIdUnreachable:
case TypeTableEntryIdVar:
src/ir.cpp
@@ -49,6 +49,10 @@ ConstExprValue *const_ptr_pointee(ConstExprValue *const_val) {
}
}
+static bool ir_should_inline(IrBuilder *irb) {
+ return irb->exec->is_inline;
+}
+
static void ir_instruction_append(IrBasicBlock *basic_block, IrInstruction *instruction) {
assert(basic_block);
assert(instruction);
@@ -160,6 +164,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionStructFieldPtr *
return IrInstructionIdStructFieldPtr;
}
+static constexpr IrInstructionId ir_instruction_id(IrInstructionEnumFieldPtr *) {
+ return IrInstructionIdEnumFieldPtr;
+}
+
static constexpr IrInstructionId ir_instruction_id(IrInstructionElemPtr *) {
return IrInstructionIdElemPtr;
}
@@ -276,6 +284,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionRef *) {
return IrInstructionIdRef;
}
+static constexpr IrInstructionId ir_instruction_id(IrInstructionStructInit *) {
+ return IrInstructionIdStructInit;
+}
+
template<typename T>
static T *ir_create_instruction(IrExecutable *exec, AstNode *source_node) {
T *special_instruction = allocate<T>(1);
@@ -293,15 +305,14 @@ static T *ir_build_instruction(IrBuilder *irb, AstNode *source_node) {
return special_instruction;
}
-static IrInstruction *ir_build_cast(IrBuilder *irb, AstNode *source_node, IrInstruction *dest_type,
- IrInstruction *value, CastOp cast_op)
+static IrInstruction *ir_build_cast(IrBuilder *irb, AstNode *source_node, TypeTableEntry *dest_type,
+ IrInstruction *value, CastOp cast_op)
{
IrInstructionCast *cast_instruction = ir_build_instruction<IrInstructionCast>(irb, source_node);
cast_instruction->dest_type = dest_type;
cast_instruction->value = value;
cast_instruction->cast_op = cast_op;
- ir_ref_instruction(dest_type);
ir_ref_instruction(value);
return &cast_instruction->base;
@@ -353,10 +364,14 @@ static IrInstruction *ir_build_return_from(IrBuilder *irb, IrInstruction *old_in
return new_instruction;
}
-static IrInstruction *ir_create_const(IrBuilder *irb, AstNode *source_node, TypeTableEntry *type_entry) {
+static IrInstruction *ir_create_const(IrBuilder *irb, AstNode *source_node,
+ TypeTableEntry *type_entry, bool depends_on_compile_var)
+{
+ assert(type_entry);
IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(irb->exec, source_node);
const_instruction->base.type_entry = type_entry;
const_instruction->base.static_value.special = ConstValSpecialStatic;
+ const_instruction->base.static_value.depends_on_compile_var = depends_on_compile_var;
return &const_instruction->base;
}
@@ -452,6 +467,18 @@ static IrInstruction *ir_build_const_bool(IrBuilder *irb, AstNode *source_node,
return &const_instruction->base;
}
+static IrInstruction *ir_build_const_bound_fn(IrBuilder *irb, AstNode *source_node,
+ FnTableEntry *fn_entry, IrInstruction *first_arg, bool depends_on_compile_var)
+{
+ IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, source_node);
+ const_instruction->base.type_entry = get_bound_fn_type(irb->codegen, fn_entry);
+ const_instruction->base.static_value.special = ConstValSpecialStatic;
+ const_instruction->base.static_value.depends_on_compile_var = depends_on_compile_var;
+ const_instruction->base.static_value.data.x_bound_fn.fn = fn_entry;
+ const_instruction->base.static_value.data.x_bound_fn.first_arg = first_arg;
+ return &const_instruction->base;
+}
+
static IrInstruction *ir_build_const_str_lit(IrBuilder *irb, AstNode *source_node, Buf *str) {
IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, source_node);
TypeTableEntry *u8_type = irb->codegen->builtin_types.entry_u8;
@@ -595,26 +622,48 @@ static IrInstruction *ir_build_struct_field_ptr_from(IrBuilder *irb, IrInstructi
return new_instruction;
}
+static IrInstruction *ir_build_enum_field_ptr(IrBuilder *irb, AstNode *source_node,
+ IrInstruction *enum_ptr, TypeEnumField *field)
+{
+ IrInstructionEnumFieldPtr *instruction = ir_build_instruction<IrInstructionEnumFieldPtr>(irb, source_node);
+ instruction->enum_ptr = enum_ptr;
+ instruction->field = field;
+
+ ir_ref_instruction(enum_ptr);
+
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_enum_field_ptr_from(IrBuilder *irb, IrInstruction *old_instruction,
+ IrInstruction *enum_ptr, TypeEnumField *type_enum_field)
+{
+ IrInstruction *new_instruction = ir_build_enum_field_ptr(irb, old_instruction->source_node,
+ enum_ptr, type_enum_field);
+ ir_link_new_instruction(new_instruction, old_instruction);
+ return new_instruction;
+}
+
static IrInstruction *ir_build_call(IrBuilder *irb, AstNode *source_node,
- IrInstruction *fn, size_t arg_count, IrInstruction **args)
+ FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args)
{
IrInstructionCall *call_instruction = ir_build_instruction<IrInstructionCall>(irb, source_node);
- call_instruction->fn = fn;
+ call_instruction->fn_entry = fn_entry;
+ call_instruction->fn_ref = fn_ref;
call_instruction->arg_count = arg_count;
call_instruction->args = args;
- ir_ref_instruction(fn);
- for (size_t i = 0; i < arg_count; i += 1) {
+ if (fn_ref)
+ ir_ref_instruction(fn_ref);
+ for (size_t i = 0; i < arg_count; i += 1)
ir_ref_instruction(args[i]);
- }
return &call_instruction->base;
}
static IrInstruction *ir_build_call_from(IrBuilder *irb, IrInstruction *old_instruction,
- IrInstruction *fn, size_t arg_count, IrInstruction **args)
+ FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args)
{
- IrInstruction *new_instruction = ir_build_call(irb, old_instruction->source_node, fn, arg_count, args);
+ IrInstruction *new_instruction = ir_build_call(irb, old_instruction->source_node, fn_entry, fn_ref, arg_count, args);
ir_link_new_instruction(new_instruction, old_instruction);
return new_instruction;
}
@@ -706,24 +755,55 @@ static IrInstruction *ir_build_container_init_list(IrBuilder *irb, AstNode *sour
return &container_init_list_instruction->base;
}
+static IrInstruction *ir_build_container_init_list_from(IrBuilder *irb, IrInstruction *old_instruction,
+ IrInstruction *container_type, size_t item_count, IrInstruction **items)
+{
+ IrInstruction *new_instruction = ir_build_container_init_list(irb, old_instruction->source_node,
+ container_type, item_count, items);
+ ir_link_new_instruction(new_instruction, old_instruction);
+ return new_instruction;
+}
+
static IrInstruction *ir_build_container_init_fields(IrBuilder *irb, AstNode *source_node,
- IrInstruction *container_type, size_t field_count, Buf **field_names, IrInstruction **field_values)
+ IrInstruction *container_type, size_t field_count, IrInstructionContainerInitFieldsField *fields)
{
IrInstructionContainerInitFields *container_init_fields_instruction =
ir_build_instruction<IrInstructionContainerInitFields>(irb, source_node);
container_init_fields_instruction->container_type = container_type;
container_init_fields_instruction->field_count = field_count;
- container_init_fields_instruction->field_names = field_names;
- container_init_fields_instruction->field_values = field_values;
+ container_init_fields_instruction->fields = fields;
ir_ref_instruction(container_type);
for (size_t i = 0; i < field_count; i += 1) {
- ir_ref_instruction(field_values[i]);
+ ir_ref_instruction(fields[i].value);
}
return &container_init_fields_instruction->base;
}
+static IrInstruction *ir_build_struct_init(IrBuilder *irb, AstNode *source_node,
+ TypeTableEntry *struct_type, size_t field_count, IrInstructionStructInitField *fields)
+{
+ IrInstructionStructInit *struct_init_instruction = ir_build_instruction<IrInstructionStructInit>(irb, source_node);
+ struct_init_instruction->struct_type = struct_type;
+ struct_init_instruction->field_count = field_count;
+ struct_init_instruction->fields = fields;
+
+ for (size_t i = 0; i < field_count; i += 1)
+ ir_ref_instruction(fields[i].value);
+
+ return &struct_init_instruction->base;
+}
+
+static IrInstruction *ir_build_struct_init_from(IrBuilder *irb, IrInstruction *old_instruction,
+ TypeTableEntry *struct_type, size_t field_count, IrInstructionStructInitField *fields)
+{
+ IrInstruction *new_instruction = ir_build_struct_init(irb, old_instruction->source_node,
+ struct_type, field_count, fields);
+ ir_link_new_instruction(new_instruction, old_instruction);
+ return new_instruction;
+}
+
static IrInstruction *ir_build_unreachable(IrBuilder *irb, AstNode *source_node) {
IrInstructionUnreachable *unreachable_instruction =
ir_build_instruction<IrInstructionUnreachable>(irb, source_node);
@@ -1442,7 +1522,7 @@ static IrInstruction *ir_gen_decl_ref(IrBuilder *irb, AstNode *source_node, AstN
ref_instruction = ir_build_const_fn(irb, source_node, fn_entry);
}
if (lval != LValPurposeNone)
- return ir_build_un_op(irb, source_node, IrUnOpAddressOf, ref_instruction);
+ return ir_build_ref(irb, source_node, ref_instruction);
else
return ref_instruction;
} else if (decl_node->type == NodeTypeContainerDecl) {
@@ -1455,14 +1535,14 @@ static IrInstruction *ir_gen_decl_ref(IrBuilder *irb, AstNode *source_node, AstN
ref_instruction = ir_build_const_type(irb, source_node, decl_node->data.struct_decl.type_entry);
}
if (lval != LValPurposeNone)
- return ir_build_un_op(irb, source_node, IrUnOpAddressOf, ref_instruction);
+ return ir_build_ref(irb, source_node, ref_instruction);
else
return ref_instruction;
} else if (decl_node->type == NodeTypeTypeDecl) {
TypeTableEntry *child_type = decl_node->data.type_decl.child_type_entry;
IrInstruction *ref_instruction = ir_build_const_type(irb, source_node, child_type);
if (lval != LValPurposeNone)
- return ir_build_un_op(irb, source_node, IrUnOpAddressOf, ref_instruction);
+ return ir_build_ref(irb, source_node, ref_instruction);
else
return ref_instruction;
} else {
@@ -1712,7 +1792,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, AstNode *node) {
case BuiltinFnIdDivExact:
case BuiltinFnIdTruncate:
case BuiltinFnIdIntType:
- case BuiltinFnIdSetFnStaticEval:
case BuiltinFnIdSetFnNoInline:
zig_panic("TODO IR gen more builtin functions");
}
@@ -1726,9 +1805,9 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, AstNode *node) {
return ir_gen_builtin_fn_call(irb, node);
AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr;
- IrInstruction *fn = ir_gen_node(irb, fn_ref_node, node->block_context);
- if (fn == irb->codegen->invalid_instruction)
- return fn;
+ IrInstruction *fn_ref = ir_gen_node(irb, fn_ref_node, node->block_context);
+ if (fn_ref == irb->codegen->invalid_instruction)
+ return fn_ref;
size_t arg_count = node->data.fn_call_expr.params.length;
IrInstruction **args = allocate<IrInstruction*>(arg_count);
@@ -1737,7 +1816,7 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, AstNode *node) {
args[i] = ir_gen_node(irb, arg_node, node->block_context);
}
- return ir_build_call(irb, node, fn, arg_count, args);
+ return ir_build_call(irb, node, nullptr, fn_ref, arg_count, args);
}
static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, AstNode *node) {
@@ -1754,7 +1833,7 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, AstNode *node) {
IrBasicBlock *else_block = ir_build_basic_block(irb, "Else");
IrBasicBlock *endif_block = ir_build_basic_block(irb, "EndIf");
- bool is_inline = (node->block_context->fn_entry == nullptr);
+ bool is_inline = ir_should_inline(irb) || node->data.if_bool_expr.is_inline;
ir_build_cond_br(irb, condition->source_node, condition, then_block, else_block, is_inline);
ir_set_cursor_at_end(irb, then_block);
@@ -1865,8 +1944,7 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, AstNode *node)
if (kind == ContainerInitKindStruct) {
size_t field_count = container_init_expr->entries.length;
- IrInstruction **values = allocate<IrInstruction *>(field_count);
- Buf **names = allocate<Buf *>(field_count);
+ IrInstructionContainerInitFieldsField *fields = allocate<IrInstructionContainerInitFieldsField>(field_count);
for (size_t i = 0; i < field_count; i += 1) {
AstNode *entry_node = container_init_expr->entries.at(i);
assert(entry_node->type == NodeTypeStructValueField);
@@ -1877,10 +1955,11 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, AstNode *node)
if (expr_value == irb->codegen->invalid_instruction)
return expr_value;
- names[i] = name;
- values[i] = expr_value;
+ fields[i].name = name;
+ fields[i].value = expr_value;
+ fields[i].source_node = entry_node;
}
- return ir_build_container_init_fields(irb, node, container_type, field_count, names, values);
+ return ir_build_container_init_fields(irb, node, container_type, field_count, fields);
} else if (kind == ContainerInitKindArray) {
size_t item_count = container_init_expr->entries.length;
IrInstruction **values = allocate<IrInstruction *>(item_count);
@@ -1919,7 +1998,7 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, AstNode *node) {
bool is_shadowable = false;
bool is_const = variable_declaration->is_const;
bool is_extern = variable_declaration->is_extern;
- bool is_inline = variable_declaration->is_inline;
+ bool is_inline = ir_should_inline(irb) || variable_declaration->is_inline;
VariableTableEntry *var = ir_add_local_var(irb, node, node->block_context,
variable_declaration->symbol, is_const, is_const, is_shadowable, is_inline);
@@ -1943,7 +2022,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, AstNode *node) {
ir_build_basic_block(irb, "WhileContinue") : cond_block;
IrBasicBlock *end_block = ir_build_basic_block(irb, "WhileEnd");
- bool is_inline = node->data.while_expr.is_inline;
+ bool is_inline = ir_should_inline(irb) || node->data.while_expr.is_inline;
ir_build_br(irb, node, cond_block, is_inline);
if (continue_expr_node) {
@@ -1998,7 +2077,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, AstNode *node) {
} else {
elem_var_type = ir_build_ptr_type_child(irb, elem_node, pointer_type);
}
- bool is_inline = node->data.for_expr.is_inline;
+ bool is_inline = ir_should_inline(irb) || node->data.for_expr.is_inline;
BlockContext *child_scope = new_block_context(node, parent_scope);
child_scope->parent_loop_node = node;
@@ -2219,7 +2298,7 @@ static IrInstruction *ir_gen_if_var_expr(IrBuilder *irb, AstNode *node) {
IrBasicBlock *else_block = ir_build_basic_block(irb, "MaybeElse");
IrBasicBlock *endif_block = ir_build_basic_block(irb, "MaybeEndIf");
- bool is_inline = (node->block_context->fn_entry == nullptr);
+ bool is_inline = ir_should_inline(irb) || node->data.if_var_expr.is_inline;
ir_build_cond_br(irb, node, is_nonnull_value, then_block, else_block, is_inline);
ir_set_cursor_at_end(irb, then_block);
@@ -2322,7 +2401,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, AstNode *node) {
size_t prong_count = node->data.switch_expr.prongs.length;
ZigList<IrInstructionSwitchBrCase> cases = {0};
- bool is_inline = node->data.switch_expr.is_inline || (node->block_context->fn_entry == nullptr);
+ bool is_inline = ir_should_inline(irb) || node->data.switch_expr.is_inline;
ZigList<IrInstruction *> incoming_values = {0};
ZigList<IrBasicBlock *> incoming_blocks = {0};
@@ -2495,7 +2574,7 @@ static IrInstruction *ir_gen_label(IrBuilder *irb, AstNode *node) {
node->block_context->label_table.put(label_name, label);
}
- bool is_inline = (node->block_context->fn_entry == nullptr);
+ bool is_inline = ir_should_inline(irb);
ir_build_br(irb, node, label_block, is_inline);
ir_set_cursor_at_end(irb, label_block);
return ir_build_const_void(irb, node);
@@ -2535,56 +2614,58 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, BlockContex
node->block_context = block_context;
switch (node->type) {
+ case NodeTypeStructValueField:
+ zig_unreachable();
case NodeTypeBlock:
- return ir_gen_block(irb, node);
+ return ir_lval_wrap(irb, ir_gen_block(irb, node), lval);
case NodeTypeBinOpExpr:
- return ir_gen_bin_op(irb, node);
+ return ir_lval_wrap(irb, ir_gen_bin_op(irb, node), lval);
case NodeTypeNumberLiteral:
- return ir_gen_num_lit(irb, node);
+ return ir_lval_wrap(irb, ir_gen_num_lit(irb, node), lval);
case NodeTypeSymbol:
return ir_gen_symbol(irb, node, lval);
case NodeTypeFnCallExpr:
return ir_lval_wrap(irb, ir_gen_fn_call(irb, node), lval);
case NodeTypeIfBoolExpr:
- return ir_gen_if_bool_expr(irb, node);
+ return ir_lval_wrap(irb, ir_gen_if_bool_expr(irb, node), lval);
case NodeTypePrefixOpExpr:
return ir_gen_prefix_op_expr(irb, node, lval);
case NodeTypeContainerInitExpr:
- return ir_gen_container_init_expr(irb, node);
+ return ir_lval_wrap(irb, ir_gen_container_init_expr(irb, node), lval);
case NodeTypeVariableDeclaration:
- return ir_gen_var_decl(irb, node);
+ return ir_lval_wrap(irb, ir_gen_var_decl(irb, node), lval);
case NodeTypeWhileExpr:
- return ir_gen_while_expr(irb, node);
+ return ir_lval_wrap(irb, ir_gen_while_expr(irb, node), lval);
case NodeTypeForExpr:
- return ir_gen_for_expr(irb, node);
+ return ir_lval_wrap(irb, ir_gen_for_expr(irb, node), lval);
case NodeTypeArrayAccessExpr:
return ir_gen_array_access(irb, node, lval);
case NodeTypeReturnExpr:
- return ir_gen_return(irb, node);
+ return ir_lval_wrap(irb, ir_gen_return(irb, node), lval);
case NodeTypeFieldAccessExpr:
return ir_gen_field_access(irb, node, lval);
case NodeTypeThisLiteral:
- return ir_gen_this_literal(irb, node);
+ return ir_lval_wrap(irb, ir_gen_this_literal(irb, node), lval);
case NodeTypeBoolLiteral:
- return ir_gen_bool_literal(irb, node);
+ return ir_lval_wrap(irb, ir_gen_bool_literal(irb, node), lval);
case NodeTypeArrayType:
- return ir_gen_array_type(irb, node);
+ return ir_lval_wrap(irb, ir_gen_array_type(irb, node), lval);
case NodeTypeStringLiteral:
- return ir_gen_string_literal(irb, node);
+ return ir_lval_wrap(irb, ir_gen_string_literal(irb, node), lval);
case NodeTypeUndefinedLiteral:
- return ir_gen_undefined_literal(irb, node);
+ return ir_lval_wrap(irb, ir_gen_undefined_literal(irb, node), lval);
case NodeTypeAsmExpr:
- return ir_gen_asm_expr(irb, node);
+ return ir_lval_wrap(irb, ir_gen_asm_expr(irb, node), lval);
case NodeTypeNullLiteral:
- return ir_gen_null_literal(irb, node);
+ return ir_lval_wrap(irb, ir_gen_null_literal(irb, node), lval);
case NodeTypeIfVarExpr:
- return ir_gen_if_var_expr(irb, node);
+ return ir_lval_wrap(irb, ir_gen_if_var_expr(irb, node), lval);
case NodeTypeSwitchExpr:
- return ir_gen_switch_expr(irb, node);
+ return ir_lval_wrap(irb, ir_gen_switch_expr(irb, node), lval);
case NodeTypeLabel:
- return ir_gen_label(irb, node);
+ return ir_lval_wrap(irb, ir_gen_label(irb, node), lval);
case NodeTypeGoto:
- return ir_gen_goto(irb, node);
+ return ir_lval_wrap(irb, ir_gen_goto(irb, node), lval);
case NodeTypeTypeLiteral:
return ir_lval_wrap(irb, ir_gen_type_literal(irb, node), lval);
case NodeTypeUnwrapErrorExpr:
@@ -2604,7 +2685,6 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, BlockContex
case NodeTypeUse:
case NodeTypeContainerDecl:
case NodeTypeStructField:
- case NodeTypeStructValueField:
case NodeTypeSwitchProng:
case NodeTypeSwitchRange:
case NodeTypeErrorValueDecl:
@@ -2642,7 +2722,7 @@ static bool ir_goto_pass2(IrBuilder *irb) {
}
label->used = true;
- bool is_inline = goto_node->data.goto_expr.is_inline || (goto_node->block_context->fn_entry == nullptr);
+ bool is_inline = ir_should_inline(irb) || goto_node->data.goto_expr.is_inline;
IrInstruction *new_instruction = ir_create_br(irb, goto_node, label->bb, is_inline);
new_instruction->ref_count = old_instruction->ref_count;
*slot = new_instruction;
@@ -2703,6 +2783,21 @@ IrInstruction *ir_gen_fn(CodeGen *codegn, FnTableEntry *fn_entry) {
return ir_gen(codegn, body_node, scope, ir_executable);
}
+static IrInstruction *ir_eval_fn(IrAnalyze *ira, IrInstruction *source_instruction,
+ size_t arg_count, IrInstruction **args)
+{
+ zig_panic("TODO ir_eval_fn");
+}
+
+static bool ir_emit_global_runtime_side_effect(IrAnalyze *ira, IrInstruction *source_instruction) {
+ if (ir_should_inline(&ira->new_irb)) {
+ add_node_error(ira->codegen, source_instruction->source_node,
+ buf_sprintf("unable to evaluate constant expression"));
+ return false;
+ }
+ return true;
+}
+
static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruction, TypeTableEntry *other_type) {
TypeTableEntry *other_type_underlying = get_underlying_type(other_type);
@@ -2918,20 +3013,15 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod
}
static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value,
- IrInstruction *dest_type, CastOp cast_op, bool need_alloca)
+ TypeTableEntry *wanted_type, CastOp cast_op, bool need_alloca)
{
- assert(dest_type->type_entry->id == TypeTableEntryIdMetaType);
- assert(dest_type->static_value.special != ConstValSpecialRuntime);
- TypeTableEntry *wanted_type = dest_type->static_value.data.x_type;
-
if (value->static_value.special != ConstValSpecialRuntime) {
- IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->source_node, wanted_type);
+ IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->source_node, wanted_type, false);
eval_const_expr_implicit_cast(cast_op, &value->static_value, value->type_entry,
&result->static_value, wanted_type);
return result;
} else {
- IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->source_node,
- dest_type, value, cast_op);
+ IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->source_node, wanted_type, value, cast_op);
result->type_entry = wanted_type;
if (need_alloca && source_instr->source_node->block_context->fn_entry) {
source_instr->source_node->block_context->fn_entry->alloca_list.append(result);
@@ -3126,12 +3216,8 @@ static FnTableEntry *ir_resolve_fn(IrAnalyze *ira, IrInstruction *fn_value) {
}
static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr,
- IrInstruction *dest_type, IrInstruction *value)
+ TypeTableEntry *wanted_type, IrInstruction *value)
{
- assert(dest_type->type_entry->id == TypeTableEntryIdMetaType);
- assert(dest_type->static_value.special != ConstValSpecialRuntime);
-
- TypeTableEntry *wanted_type = dest_type->static_value.data.x_type;
TypeTableEntry *actual_type = value->type_entry;
TypeTableEntry *wanted_type_canon = get_underlying_type(wanted_type);
TypeTableEntry *actual_type_canon = get_underlying_type(actual_type);
@@ -3147,21 +3233,21 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
// explicit match or non-const to const
if (types_match_const_cast_only(wanted_type, actual_type)) {
- return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpNoop, false);
+ return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpNoop, false);
}
// explicit cast from bool to int
if (wanted_type_canon->id == TypeTableEntryIdInt &&
actual_type_canon->id == TypeTableEntryIdBool)
{
- return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpBoolToInt, false);
+ return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpBoolToInt, false);
}
// explicit cast from pointer to isize or usize
if ((wanted_type_canon == isize_type || wanted_type_canon == usize_type) &&
type_is_codegen_pointer(actual_type_canon))
{
- return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpPtrToInt, false);
+ return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpPtrToInt, false);
}
@@ -3169,7 +3255,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
if (wanted_type_canon->id == TypeTableEntryIdPointer &&
(actual_type_canon == isize_type || actual_type_canon == usize_type))
{
- return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpIntToPtr, false);
+ return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpIntToPtr, false);
}
// explicit widening or shortening cast
@@ -3178,21 +3264,21 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
(wanted_type_canon->id == TypeTableEntryIdFloat &&
actual_type_canon->id == TypeTableEntryIdFloat))
{
- return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpWidenOrShorten, false);
+ return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpWidenOrShorten, false);
}
// explicit cast from int to float
if (wanted_type_canon->id == TypeTableEntryIdFloat &&
actual_type_canon->id == TypeTableEntryIdInt)
{
- return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpIntToFloat, false);
+ return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpIntToFloat, false);
}
// explicit cast from float to int
if (wanted_type_canon->id == TypeTableEntryIdInt &&
actual_type_canon->id == TypeTableEntryIdFloat)
{
- return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpFloatToInt, false);
+ return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpFloatToInt, false);
}
// explicit cast from array to slice
@@ -3202,7 +3288,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
wanted_type->data.structure.fields[0].type_entry->data.pointer.child_type,
actual_type->data.array.child_type))
{
- return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpToUnknownSizeArray, true);
+ return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpToUnknownSizeArray, true);
}
// explicit cast from []T to []u8 or []u8 to []T
@@ -3212,8 +3298,9 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
(wanted_type->data.structure.fields[0].type_entry->data.pointer.is_const ||
!actual_type->data.structure.fields[0].type_entry->data.pointer.is_const))
{
- mark_impure_fn(ira->codegen, source_instr->source_node->block_context, source_instr->source_node);
- return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpResizeSlice, true);
+ if (!ir_emit_global_runtime_side_effect(ira, source_instr))
+ return ira->codegen->invalid_instruction;
+ return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpResizeSlice, true);
}
// explicit cast from [N]u8 to []T
@@ -3221,11 +3308,12 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
actual_type->id == TypeTableEntryIdArray &&
is_u8(actual_type->data.array.child_type))
{
- mark_impure_fn(ira->codegen, source_instr->source_node->block_context, source_instr->source_node);
+ if (!ir_emit_global_runtime_side_effect(ira, source_instr))
+ return ira->codegen->invalid_instruction;
uint64_t child_type_size = type_size(ira->codegen,
wanted_type->data.structure.fields[0].type_entry->data.pointer.child_type);
if (actual_type->data.array.len % child_type_size == 0) {
- return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpBytesToSlice, true);
+ return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpBytesToSlice, true);
} else {
add_node_error(ira->codegen, source_instr->source_node,
buf_sprintf("unable to convert %s to %s: size mismatch",
@@ -3238,7 +3326,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
if ((actual_type->id == TypeTableEntryIdPointer || actual_type->id == TypeTableEntryIdFn) &&
(wanted_type->id == TypeTableEntryIdPointer || wanted_type->id == TypeTableEntryIdFn))
{
- return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpPointerReinterpret, false);
+ return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpPointerReinterpret, false);
}
// explicit cast from maybe pointer to another maybe pointer
@@ -3249,13 +3337,13 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
(wanted_type->data.maybe.child_type->id == TypeTableEntryIdPointer ||
wanted_type->data.maybe.child_type->id == TypeTableEntryIdFn))
{
- return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpPointerReinterpret, false);
+ return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpPointerReinterpret, false);
}
// explicit cast from child type of maybe type to maybe type
if (wanted_type->id == TypeTableEntryIdMaybe) {
if (types_match_const_cast_only(wanted_type->data.maybe.child_type, actual_type)) {
- IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, dest_type,
+ IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, wanted_type,
CastOpMaybeWrap, true);
cast_instruction->return_knowledge = ReturnKnowledgeKnownNonNull;
return cast_instruction;
@@ -3263,7 +3351,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
actual_type->id == TypeTableEntryIdNumLitFloat)
{
if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.maybe.child_type)) {
- IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, dest_type,
+ IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, wanted_type,
CastOpMaybeWrap, true);
cast_instruction->return_knowledge = ReturnKnowledgeKnownNonNull;
return cast_instruction;
@@ -3277,7 +3365,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
if (wanted_type->id == TypeTableEntryIdMaybe &&
actual_type->id == TypeTableEntryIdNullLit)
{
- IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, dest_type,
+ IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, wanted_type,
CastOpNullToMaybe, true);
cast_instruction->return_knowledge = ReturnKnowledgeKnownNull;
return cast_instruction;
@@ -3286,7 +3374,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
// explicit cast from child type of error type to error type
if (wanted_type->id == TypeTableEntryIdErrorUnion) {
if (types_match_const_cast_only(wanted_type->data.error.child_type, actual_type)) {
- IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, dest_type,
+ IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, wanted_type,
CastOpErrorWrap, true);
cast_instruction->return_knowledge = ReturnKnowledgeKnownNonError;
return cast_instruction;
@@ -3294,7 +3382,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
actual_type->id == TypeTableEntryIdNumLitFloat)
{
if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.error.child_type)) {
- IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, dest_type,
+ IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, wanted_type,
CastOpErrorWrap, true);
cast_instruction->return_knowledge = ReturnKnowledgeKnownNonError;
return cast_instruction;
@@ -3308,7 +3396,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
if (wanted_type->id == TypeTableEntryIdErrorUnion &&
actual_type->id == TypeTableEntryIdPureError)
{
- IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, dest_type,
+ IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, wanted_type,
CastOpPureErrorWrap, false);
cast_instruction->return_knowledge = ReturnKnowledgeKnownError;
return cast_instruction;
@@ -3333,7 +3421,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
} else {
zig_unreachable();
}
- return ir_resolve_cast(ira, source_instr, value, dest_type, op, false);
+ return ir_resolve_cast(ira, source_instr, value, wanted_type, op, false);
} else {
return ira->codegen->invalid_instruction;
}
@@ -3351,7 +3439,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
if (bignum_fits_in_bits(&bn, wanted_type->data.integral.bit_count,
wanted_type->data.integral.is_signed))
{
- return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpErrToInt, false);
+ return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpErrToInt, false);
} else {
add_node_error(ira->codegen, source_instr->source_node,
buf_sprintf("too many error values to fit in '%s'", buf_ptr(&wanted_type->name)));
@@ -3364,7 +3452,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
wanted_type->id == TypeTableEntryIdEnum &&
wanted_type->data.enumeration.gen_field_count == 0)
{
- return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpIntToEnum, false);
+ return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpIntToEnum, false);
}
// explicit cast from enum type with no payload to integer
@@ -3372,12 +3460,12 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
actual_type->id == TypeTableEntryIdEnum &&
actual_type->data.enumeration.gen_field_count == 0)
{
- return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpEnumToInt, false);
+ return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpEnumToInt, false);
}
// explicit cast from undefined to anything
if (actual_type->id == TypeTableEntryIdUndefLit) {
- return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpNoop, false);
+ return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpNoop, false);
}
add_node_error(ira->codegen, source_instr->source_node,
@@ -3410,11 +3498,7 @@ static IrInstruction *ir_get_casted_value(IrAnalyze *ira, IrInstruction *value,
return ira->codegen->invalid_instruction;
case ImplicitCastMatchResultYes:
- {
- IrInstruction *dest_type = ir_create_const_type(&ira->new_irb, value->source_node, expected_type);
- IrInstruction *cast_instruction = ir_analyze_cast(ira, value, dest_type, value);
- return cast_instruction;
- }
+ return ir_analyze_cast(ira, value, expected_type, value);
case ImplicitCastMatchResultReportedError:
return ira->codegen->invalid_instruction;
}
@@ -3422,6 +3506,58 @@ static IrInstruction *ir_get_casted_value(IrAnalyze *ira, IrInstruction *value,
zig_unreachable();
}
+static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr) {
+ TypeTableEntry *type_entry = ptr->type_entry;
+ if (type_entry->id == TypeTableEntryIdInvalid) {
+ return ira->codegen->invalid_instruction;
+ } else if (type_entry->id == TypeTableEntryIdPointer) {
+ TypeTableEntry *child_type = type_entry->data.pointer.child_type;
+ if (ptr->static_value.special != ConstValSpecialRuntime) {
+ ConstExprValue *pointee = const_ptr_pointee(&ptr->static_value);
+ if (pointee->special != ConstValSpecialRuntime) {
+ IrInstruction *result = ir_create_const(&ira->new_irb, source_instruction->source_node,
+ child_type, pointee->depends_on_compile_var);
+ result->static_value = *pointee;
+ return result;
+ }
+ }
+ IrInstruction *load_ptr_instruction = ir_build_load_ptr(&ira->new_irb, source_instruction->source_node, ptr);
+ load_ptr_instruction->type_entry = child_type;
+ return load_ptr_instruction;
+ } else {
+ add_node_error(ira->codegen, source_instruction->source_node,
+ buf_sprintf("attempt to dereference non pointer type '%s'",
+ buf_ptr(&type_entry->name)));
+ return ira->codegen->invalid_instruction;
+ }
+}
+
+static TypeTableEntry *ir_analyze_ref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *value) {
+ if (value->type_entry->id == TypeTableEntryIdInvalid)
+ return ira->codegen->builtin_types.entry_invalid;
+
+ bool is_inline = ir_should_inline(&ira->new_irb);
+ if (is_inline || value->static_value.special != ConstValSpecialRuntime) {
+ ConstExprValue *val = ir_resolve_const(ira, value);
+ if (!val)
+ return ira->codegen->builtin_types.entry_invalid;
+ return ir_analyze_const_ptr(ira, source_instruction, val, value->type_entry, false);
+ }
+
+ TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, value->type_entry, true);
+ if (handle_is_ptr(value->type_entry)) {
+ // this instruction is a noop - codegen can pass the pointer we already have as the result
+ ir_link_new_instruction(value, source_instruction);
+ return ptr_type;
+ } else {
+ FnTableEntry *fn_entry = source_instruction->source_node->block_context->fn_entry;
+ IrInstruction *new_instruction = ir_build_ref_from(&ira->new_irb, source_instruction, value);
+ fn_entry->alloca_list.append(new_instruction);
+ return ptr_type;
+ }
+}
+
+
static bool ir_resolve_usize(IrAnalyze *ira, IrInstruction *value, uint64_t *out) {
if (value->type_entry->id == TypeTableEntryIdInvalid)
return false;
@@ -3580,6 +3716,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
case TypeTableEntryIdGenericFn:
+ case TypeTableEntryIdBoundFn:
if (!is_equality_cmp) {
add_node_error(ira->codegen, source_node,
buf_sprintf("operator not allowed for type '%s'", buf_ptr(&resolved_type->name)));
@@ -3944,6 +4081,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
case TypeTableEntryIdUnion:
case TypeTableEntryIdFn:
case TypeTableEntryIdGenericFn:
+ case TypeTableEntryIdBoundFn:
// OK
break;
}
@@ -3966,13 +4104,121 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
return ira->codegen->builtin_types.entry_void;
}
+static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call_instruction,
+ FnTableEntry *fn_entry, TypeTableEntry *fn_type, IrInstruction *fn_ref,
+ IrInstruction *first_arg_ptr, bool is_inline)
+{
+ FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
+ size_t first_arg_1_or_0 = first_arg_ptr ? 1 : 0;
+ size_t src_param_count = fn_type_id->param_count;
+ size_t call_param_count = call_instruction->arg_count + first_arg_1_or_0;
+ AstNode *source_node = call_instruction->base.source_node;
+
+ AstNode *fn_proto_node = fn_entry ? fn_entry->proto_node : nullptr;;
+
+ if (fn_type_id->is_var_args) {
+ if (call_param_count < src_param_count) {
+ ErrorMsg *msg = add_node_error(ira->codegen, source_node,
+ buf_sprintf("expected at least %zu arguments, found %zu", src_param_count, call_param_count));
+ if (fn_proto_node) {
+ add_error_note(ira->codegen, msg, fn_proto_node,
+ buf_sprintf("declared here"));
+ }
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+ } else if (src_param_count != call_param_count) {
+ ErrorMsg *msg = add_node_error(ira->codegen, source_node,
+ buf_sprintf("expected %zu arguments, found %zu", src_param_count, call_param_count));
+ if (fn_proto_node) {
+ add_error_note(ira->codegen, msg, fn_proto_node,
+ buf_sprintf("declared here"));
+ }
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+
+ IrInstruction **casted_args = allocate<IrInstruction *>(call_param_count);
+ size_t next_arg_index = 0;
+ if (first_arg_ptr) {
+ IrInstruction *first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr);
+ if (first_arg->type_entry->id == TypeTableEntryIdInvalid)
+ return ira->codegen->builtin_types.entry_invalid;
+
+ TypeTableEntry *param_type = fn_type_id->param_info[next_arg_index].type;
+ if (param_type->id == TypeTableEntryIdInvalid)
+ return ira->codegen->builtin_types.entry_invalid;
+
+ IrInstruction *casted_arg = ir_get_casted_value(ira, first_arg, param_type);
+ if (casted_arg->type_entry->id == TypeTableEntryIdInvalid)
+ return ira->codegen->builtin_types.entry_invalid;
+
+ if (is_inline && !ir_resolve_const(ira, casted_arg))
+ return ira->codegen->builtin_types.entry_invalid;
+
+ casted_args[next_arg_index] = casted_arg;
+ next_arg_index += 1;
+ }
+ for (size_t call_i = 0; call_i < call_instruction->arg_count; call_i += 1) {
+ IrInstruction *old_arg = call_instruction->args[call_i]->other;
+ if (old_arg->type_entry->id == TypeTableEntryIdInvalid)
+ return ira->codegen->builtin_types.entry_invalid;
+ IrInstruction *casted_arg;
+ if (next_arg_index < src_param_count) {
+ TypeTableEntry *param_type = fn_type_id->param_info[next_arg_index].type;
+ if (param_type->id == TypeTableEntryIdInvalid)
+ return ira->codegen->builtin_types.entry_invalid;
+ casted_arg = ir_get_casted_value(ira, old_arg, param_type);
+ if (casted_arg->type_entry->id == TypeTableEntryIdInvalid)
+ return ira->codegen->builtin_types.entry_invalid;
+ } else {
+ casted_arg = old_arg;
+ }
+
+ if (is_inline && !ir_resolve_const(ira, casted_arg))
+ return ira->codegen->builtin_types.entry_invalid;
+
+ casted_args[next_arg_index] = casted_arg;
+ next_arg_index += 1;
+ }
+
+ assert(next_arg_index == call_param_count);
+
+ TypeTableEntry *return_type = fn_type_id->return_type;
+ if (return_type->id == TypeTableEntryIdInvalid)
+ return ira->codegen->builtin_types.entry_invalid;
+
+ if (is_inline) {
+ IrInstruction *result = ir_eval_fn(ira, &call_instruction->base, call_param_count, casted_args);
+ if (result->type_entry->id == TypeTableEntryIdInvalid)
+ return ira->codegen->builtin_types.entry_invalid;
+
+ ConstExprValue *out_val = ir_build_const_from(ira, &call_instruction->base,
+ result->static_value.depends_on_compile_var);
+ *out_val = result->static_value;
+ return ir_finish_anal(ira, return_type);
+ }
+
+ IrInstruction *new_call_instruction = ir_build_call_from(&ira->new_irb, &call_instruction->base,
+ fn_entry, fn_ref, call_param_count, casted_args);
+
+ if (type_has_bits(return_type) && handle_is_ptr(return_type))
+ call_instruction->base.source_node->block_context->fn_entry->alloca_list.append(new_call_instruction);
+
+ return ir_finish_anal(ira, return_type);
+}
+
static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstructionCall *call_instruction) {
- IrInstruction *fn_ref = call_instruction->fn->other;
+ IrInstruction *fn_ref = call_instruction->fn_ref->other;
if (fn_ref->type_entry->id == TypeTableEntryIdInvalid)
return ira->codegen->builtin_types.entry_invalid;
- if (fn_ref->static_value.special != ConstValSpecialRuntime) {
+ bool is_inline = call_instruction->is_inline || ir_should_inline(&ira->new_irb);
+
+ if (is_inline || fn_ref->static_value.special != ConstValSpecialRuntime) {
if (fn_ref->type_entry->id == TypeTableEntryIdMetaType) {
+ TypeTableEntry *dest_type = ir_resolve_type(ira, fn_ref);
+ if (!dest_type)
+ return ira->codegen->builtin_types.entry_invalid;
+
size_t actual_param_count = call_instruction->arg_count;
if (actual_param_count != 1) {
@@ -3982,38 +4228,39 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction
}
IrInstruction *arg = call_instruction->args[0]->other;
- IrInstruction *cast_instruction = ir_analyze_cast(ira, &call_instruction->base, fn_ref, arg);
- if (cast_instruction == ira->codegen->invalid_instruction)
+
+ IrInstruction *cast_instruction = ir_analyze_cast(ira, &call_instruction->base, dest_type, arg);
+ if (cast_instruction->type_entry->id == TypeTableEntryIdInvalid)
return ira->codegen->builtin_types.entry_invalid;
ir_link_new_instruction(cast_instruction, &call_instruction->base);
return ir_finish_anal(ira, cast_instruction->type_entry);
} else if (fn_ref->type_entry->id == TypeTableEntryIdFn) {
- // TODO fully port over the fn call analyze code to IR
- FnTableEntry *fn_table_entry = fn_ref->static_value.data.x_fn;
- TypeTableEntry *fn_type = fn_table_entry->type_entry;
-
- IrInstruction **casted_args = allocate<IrInstruction *>(call_instruction->arg_count);
- for (size_t i = 0; i < call_instruction->arg_count; i += 1) {
- TypeTableEntry *param_type = fn_type->data.fn.fn_type_id.param_info[i].type;
- IrInstruction *old_arg = call_instruction->args[i]->other;
- if (old_arg->type_entry->id == TypeTableEntryIdInvalid)
- return ira->codegen->builtin_types.entry_invalid;
- casted_args[i] = ir_get_casted_value(ira, old_arg, param_type);
- }
-
- ir_build_call_from(&ira->new_irb, &call_instruction->base,
- fn_ref, call_instruction->arg_count, casted_args);
-
- return ir_finish_anal(ira, fn_type->data.fn.fn_type_id.return_type);
+ FnTableEntry *fn_table_entry = ir_resolve_fn(ira, fn_ref);
+ return ir_analyze_fn_call(ira, call_instruction, fn_table_entry, fn_table_entry->type_entry,
+ fn_ref, nullptr, is_inline);
+ } else if (fn_ref->type_entry->id == TypeTableEntryIdBoundFn) {
+ assert(fn_ref->static_value.special == ConstValSpecialStatic);
+ FnTableEntry *fn_table_entry = fn_ref->static_value.data.x_bound_fn.fn;
+ IrInstruction *first_arg_ptr = fn_ref->static_value.data.x_bound_fn.first_arg;
+ return ir_analyze_fn_call(ira, call_instruction, fn_table_entry, fn_table_entry->type_entry,
+ nullptr, first_arg_ptr, is_inline);
+ } else if (fn_ref->type_entry->id == TypeTableEntryIdGenericFn) {
+ zig_panic("TODO generic fn call");
} else {
- zig_panic("TODO analyze more fn call types");
+ add_node_error(ira->codegen, fn_ref->source_node,
+ buf_sprintf("type '%s' not a function", buf_ptr(&fn_ref->type_entry->name)));
+ return ira->codegen->builtin_types.entry_invalid;
}
- } else {
- //ir_build_call_from(&ira->new_irb, &call_instruction->base,
- // call_instruction->fn, call_instruction->arg_count, call_instruction->args);
+ }
- zig_panic("TODO analyze fn call");
+ if (fn_ref->type_entry->id == TypeTableEntryIdFn) {
+ return ir_analyze_fn_call(ira, call_instruction, nullptr, fn_ref->type_entry,
+ fn_ref, nullptr, false);
+ } else {
+ add_node_error(ira->codegen, fn_ref->source_node,
+ buf_sprintf("type '%s' not a function", buf_ptr(&fn_ref->type_entry->name)));
+ return ira->codegen->builtin_types.entry_invalid;
}
}
@@ -4071,6 +4318,7 @@ static TypeTableEntry *ir_analyze_unary_prefix_op_err(IrAnalyze *ira, IrInstruct
case TypeTableEntryIdUnion:
case TypeTableEntryIdFn:
case TypeTableEntryIdGenericFn:
+ case TypeTableEntryIdBoundFn:
{
ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base,
value->static_value.depends_on_compile_var);
@@ -4119,6 +4367,7 @@ static TypeTableEntry *ir_analyze_unary_address_of(IrAnalyze *ira, IrInstruction
case TypeTableEntryIdUnreachable:
case TypeTableEntryIdVar:
case TypeTableEntryIdGenericFn:
+ case TypeTableEntryIdBoundFn:
add_node_error(ira->codegen, un_op_instruction->base.source_node,
buf_sprintf("unable to get address of type '%s'", buf_ptr(&target_type->name)));
// TODO if type decl, add note pointing to type decl declaration
@@ -4217,6 +4466,7 @@ static TypeTableEntry *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
case TypeTableEntryIdGenericFn:
+ case TypeTableEntryIdBoundFn:
{
ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base,
value->static_value.depends_on_compile_var);
@@ -4626,7 +4876,7 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
static TypeTableEntry *ir_analyze_container_member_access_inner(IrAnalyze *ira,
TypeTableEntry *bare_struct_type, Buf *field_name, IrInstructionFieldPtr *field_ptr_instruction,
- TypeTableEntry *container_type)
+ IrInstruction *container_ptr, TypeTableEntry *container_type)
{
if (!is_slice(bare_struct_type)) {
BlockContext *container_block_context = get_container_block_context(bare_struct_type);
@@ -4634,7 +4884,15 @@ static TypeTableEntry *ir_analyze_container_member_access_inner(IrAnalyze *ira,
auto entry = container_block_context->decl_table.maybe_get(field_name);
AstNode *fn_decl_node = entry ? entry->value : nullptr;
if (fn_decl_node && fn_decl_node->type == NodeTypeFnProto) {
- zig_panic("TODO member function call");
+ resolve_top_level_decl(ira->codegen, fn_decl_node, false);
+ TopLevelDecl *tld = get_as_top_level_decl(fn_decl_node);
+ if (tld->resolution == TldResolutionInvalid)
+ return ira->codegen->builtin_types.entry_invalid;
+ FnTableEntry *fn_entry = fn_decl_node->data.fn_proto.fn_table_entry;
+ bool depends_on_compile_var = container_ptr->static_value.depends_on_compile_var;
+ IrInstruction *bound_fn_value = ir_build_const_bound_fn(&ira->new_irb,
+ field_ptr_instruction->base.source_node, fn_entry, container_ptr, depends_on_compile_var);
+ return ir_analyze_ref(ira, &field_ptr_instruction->base, bound_fn_value);
}
}
add_node_error(ira->codegen, field_ptr_instruction->base.source_node,
@@ -4643,14 +4901,12 @@ static TypeTableEntry *ir_analyze_container_member_access_inner(IrAnalyze *ira,
}
-static TypeTableEntry *ir_analyze_container_member_access(IrAnalyze *ira, Buf *field_name,
- IrInstructionFieldPtr *field_ptr_instruction, TypeTableEntry *container_type)
+static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name,
+ IrInstructionFieldPtr *field_ptr_instruction, IrInstruction *container_ptr, TypeTableEntry *container_type)
{
- IrInstruction *container_ptr = field_ptr_instruction->container_ptr->other;
TypeTableEntry *bare_type = container_ref_type(container_type);
- if (!type_is_complete(bare_type)) {
+ if (!type_is_complete(bare_type))
resolve_container_type(ira->codegen, bare_type);
- }
if (bare_type->id == TypeTableEntryIdStruct) {
TypeStructField *field = find_struct_type_field(bare_type, field_name);
@@ -4659,10 +4915,17 @@ static TypeTableEntry *ir_analyze_container_member_access(IrAnalyze *ira, Buf *f
return get_pointer_to_type(ira->codegen, field->type_entry, false);
} else {
return ir_analyze_container_member_access_inner(ira, bare_type, field_name,
- field_ptr_instruction, container_type);
+ field_ptr_instruction, container_ptr, container_type);
}
} else if (bare_type->id == TypeTableEntryIdEnum) {
- zig_panic("TODO enum field ptr");
+ TypeEnumField *field = find_enum_type_field(bare_type, field_name);
+ if (field) {
+ ir_build_enum_field_ptr_from(&ira->new_irb, &field_ptr_instruction->base, container_ptr, field);
+ return get_pointer_to_type(ira->codegen, field->type_entry, false);
+ } else {
+ return ir_analyze_container_member_access_inner(ira, bare_type, field_name,
+ field_ptr_instruction, container_ptr, container_type);
+ }
} else if (bare_type->id == TypeTableEntryIdUnion) {
zig_panic("TODO");
} else {
@@ -4733,7 +4996,7 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
if (container_type->id == TypeTableEntryIdInvalid) {
return container_type;
} else if (is_container_ref(container_type)) {
- return ir_analyze_container_member_access(ira, field_name, field_ptr_instruction, container_type);
+ return ir_analyze_container_field_ptr(ira, field_name, field_ptr_instruction, container_ptr, container_type);
} else if (container_type->id == TypeTableEntryIdArray) {
if (buf_eql_str(field_name, "len")) {
ConstExprValue *len_val = allocate<ConstExprValue>(1);
@@ -4749,24 +5012,38 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
return ira->codegen->builtin_types.entry_invalid;
}
} else if (container_type->id == TypeTableEntryIdMetaType) {
- zig_panic("TODO type field access");
- //TypeTableEntry *child_type = ir_resolve_type(ira, container_ptr);
-
- //if (child_type->id == TypeTableEntryIdInvalid) {
- // return ira->codegen->builtin_types.entry_invalid;
- //} else if (child_type->id == TypeTableEntryIdEnum) {
- // zig_panic("TODO enum type field");
- //} else if (child_type->id == TypeTableEntryIdStruct) {
- // zig_panic("TODO struct type field");
- //} else if (child_type->id == TypeTableEntryIdPureError) {
- // zig_panic("TODO error type field");
- //} else if (child_type->id == TypeTableEntryIdInt) {
- // zig_panic("TODO integer type field");
- //} else {
- // add_node_error(ira->codegen, source_node,
- // buf_sprintf("type '%s' does not support field access", buf_ptr(&container_type->name)));
- // return ira->codegen->builtin_types.entry_invalid;
- //}
+ ConstExprValue *container_ptr_val = ir_resolve_const(ira, container_ptr);
+ if (!container_ptr_val)
+ return ira->codegen->builtin_types.entry_invalid;
+ ConstExprValue *child_val = const_ptr_pointee(container_ptr_val);
+ TypeTableEntry *child_type = child_val->data.x_type;
+
+ if (child_type->id == TypeTableEntryIdInvalid) {
+ return ira->codegen->builtin_types.entry_invalid;
+ } else if (child_type->id == TypeTableEntryIdEnum) {
+ zig_panic("TODO enum type field");
+ } else if (child_type->id == TypeTableEntryIdStruct) {
+ BlockContext *container_block_context = get_container_block_context(child_type);
+ auto entry = container_block_context->decl_table.maybe_get(field_name);
+ AstNode *decl_node = entry ? entry->value : nullptr;
+ if (decl_node) {
+ bool depends_on_compile_var = container_ptr->static_value.depends_on_compile_var;
+ return ir_analyze_decl_ref(ira, &field_ptr_instruction->base, decl_node, depends_on_compile_var);
+ } else {
+ add_node_error(ira->codegen, source_node,
+ buf_sprintf("container '%s' has no member called '%s'",
+ buf_ptr(&child_type->name), buf_ptr(field_name)));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+ } else if (child_type->id == TypeTableEntryIdPureError) {
+ zig_panic("TODO error type field");
+ } else if (child_type->id == TypeTableEntryIdInt) {
+ zig_panic("TODO integer type field");
+ } else {
+ add_node_error(ira->codegen, source_node,
+ buf_sprintf("type '%s' does not support field access", buf_ptr(&container_type->name)));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
} else if (container_type->id == TypeTableEntryIdNamespace) {
ConstExprValue *container_ptr_val = ir_resolve_const(ira, container_ptr);
if (!container_ptr_val)
@@ -4817,28 +5094,10 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
static TypeTableEntry *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstructionLoadPtr *load_ptr_instruction) {
IrInstruction *ptr = load_ptr_instruction->ptr->other;
- TypeTableEntry *type_entry = ptr->type_entry;
- if (type_entry->id == TypeTableEntryIdInvalid) {
- return type_entry;
- } else if (type_entry->id == TypeTableEntryIdPointer) {
- TypeTableEntry *child_type = type_entry->data.pointer.child_type;
- if (ptr->static_value.special != ConstValSpecialRuntime) {
- ConstExprValue *pointee = const_ptr_pointee(&ptr->static_value);
- if (pointee->special != ConstValSpecialRuntime) {
- ConstExprValue *out_val = ir_build_const_from(ira, &load_ptr_instruction->base,
- pointee->depends_on_compile_var);
- *out_val = *pointee;
- return child_type;
- }
- }
- ir_build_load_ptr_from(&ira->new_irb, &load_ptr_instruction->base, ptr);
- return child_type;
- } else {
- add_node_error(ira->codegen, load_ptr_instruction->base.source_node,
- buf_sprintf("attempt to dereference non pointer type '%s'",
- buf_ptr(&type_entry->name)));
- return ira->codegen->builtin_types.entry_invalid;
- }
+ IrInstruction *result = ir_get_deref(ira, &load_ptr_instruction->base, ptr);
+ ir_link_new_instruction(result, &load_ptr_instruction->base);
+ assert(result->type_entry);
+ return result->type_entry;
}
static TypeTableEntry *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstructionStorePtr *store_ptr_instruction) {
@@ -4911,6 +5170,7 @@ static TypeTableEntry *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructi
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
case TypeTableEntryIdGenericFn:
+ case TypeTableEntryIdBoundFn:
case TypeTableEntryIdMetaType:
case TypeTableEntryIdVoid:
case TypeTableEntryIdBool:
@@ -5148,6 +5408,7 @@ static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira,
case TypeTableEntryIdFn:
case TypeTableEntryIdNamespace:
case TypeTableEntryIdGenericFn:
+ case TypeTableEntryIdBoundFn:
{
TypeTableEntry *result_type = get_slice_type(ira->codegen, resolved_child_type, is_const);
ConstExprValue *out_val = ir_build_const_from(ira, &slice_type_instruction->base,
@@ -5161,8 +5422,9 @@ static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira,
static TypeTableEntry *ir_analyze_instruction_asm(IrAnalyze *ira, IrInstructionAsm *asm_instruction) {
assert(asm_instruction->base.source_node->type == NodeTypeAsmExpr);
- mark_impure_fn(ira->codegen, asm_instruction->base.source_node->block_context,
- asm_instruction->base.source_node);
+
+ if (!ir_emit_global_runtime_side_effect(ira, &asm_instruction->base))
+ return ira->codegen->builtin_types.entry_invalid;
// TODO validate the output types and variable types
@@ -5236,6 +5498,7 @@ static TypeTableEntry *ir_analyze_instruction_array_type(IrAnalyze *ira,
case TypeTableEntryIdFn:
case TypeTableEntryIdNamespace:
case TypeTableEntryIdGenericFn:
+ case TypeTableEntryIdBoundFn:
{
TypeTableEntry *result_type = get_array_type(ira->codegen, child_type, size);
bool depends_on_compile_var = child_type_value->static_value.depends_on_compile_var ||
@@ -5306,6 +5569,7 @@ static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira,
case TypeTableEntryIdNumLitFloat:
case TypeTableEntryIdNumLitInt:
case TypeTableEntryIdGenericFn:
+ case TypeTableEntryIdBoundFn:
case TypeTableEntryIdMetaType:
case TypeTableEntryIdFn:
case TypeTableEntryIdNamespace:
@@ -5469,7 +5733,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_br(IrAnalyze *ira,
return ir_unreach_error(ira);
size_t case_count = switch_br_instruction->case_count;
- bool is_inline = switch_br_instruction->is_inline;
+ bool is_inline = ir_should_inline(&ira->new_irb) || switch_br_instruction->is_inline;
if (is_inline || target_value->static_value.special != ConstValSpecialRuntime) {
ConstExprValue *target_val = ir_resolve_const(ira, target_value);
@@ -5599,6 +5863,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,
case TypeTableEntryIdUnion:
case TypeTableEntryIdBlock:
case TypeTableEntryIdGenericFn:
+ case TypeTableEntryIdBoundFn:
add_node_error(ira->codegen, switch_target_instruction->base.source_node,
buf_sprintf("invalid switch target type '%s'", buf_ptr(&target_type->name)));
// TODO if this is a typedecl, add error note showing the declaration of the type decl
@@ -5741,51 +6006,222 @@ static TypeTableEntry *ir_analyze_instruction_array_len(IrAnalyze *ira,
static TypeTableEntry *ir_analyze_instruction_ref(IrAnalyze *ira, IrInstructionRef *ref_instruction) {
IrInstruction *value = ref_instruction->value->other;
- if (value->type_entry->id == TypeTableEntryIdInvalid)
- return ira->codegen->builtin_types.entry_invalid;
+ return ir_analyze_ref(ira, &ref_instruction->base, value);
+}
- FnTableEntry *fn_entry = ref_instruction->base.source_node->block_context->fn_entry;
- if (!fn_entry || value->static_value.special != ConstValSpecialRuntime) {
- ConstExprValue *val = ir_resolve_const(ira, value);
- if (!val)
+static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruction *instruction,
+ TypeTableEntry *container_type, size_t instr_field_count, IrInstructionContainerInitFieldsField *fields,
+ bool depends_on_compile_var)
+{
+ size_t actual_field_count = container_type->data.structure.src_field_count;
+
+ IrInstruction *first_non_const_instruction = nullptr;
+
+ AstNode **field_assign_nodes = allocate<AstNode *>(actual_field_count);
+
+ IrInstructionStructInitField *new_fields = allocate<IrInstructionStructInitField>(actual_field_count);
+
+ FnTableEntry *fn_entry = instruction->source_node->block_context->fn_entry;
+ bool outside_fn = (fn_entry == nullptr);
+
+ ConstExprValue const_val = {};
+ const_val.special = ConstValSpecialStatic;
+ const_val.depends_on_compile_var = depends_on_compile_var;
+ const_val.data.x_struct.fields = allocate<ConstExprValue>(actual_field_count);
+ for (size_t i = 0; i < instr_field_count; i += 1) {
+ IrInstructionContainerInitFieldsField *field = &fields[i];
+
+ IrInstruction *field_value = field->value->other;
+ if (field_value->type_entry->id == TypeTableEntryIdInvalid)
+ return ira->codegen->builtin_types.entry_invalid;
+
+ TypeStructField *type_field = find_struct_type_field(container_type, field->name);
+ if (!type_field) {
+ add_node_error(ira->codegen, field->source_node,
+ buf_sprintf("no member named '%s' in '%s'",
+ buf_ptr(field->name), buf_ptr(&container_type->name)));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+
+ if (type_field->type_entry->id == TypeTableEntryIdInvalid)
return ira->codegen->builtin_types.entry_invalid;
- return ir_analyze_const_ptr(ira, &ref_instruction->base, val, value->type_entry, false);
+
+ size_t field_index = type_field->src_index;
+ AstNode *existing_assign_node = field_assign_nodes[field_index];
+ if (existing_assign_node) {
+ ErrorMsg *msg = add_node_error(ira->codegen, field->source_node, buf_sprintf("duplicate field"));
+ add_error_note(ira->codegen, msg, existing_assign_node, buf_sprintf("other field here"));
+ continue;
+ }
+ field_assign_nodes[field_index] = field->source_node;
+
+ new_fields[field_index].value = field_value;
+ new_fields[field_index].type_struct_field = type_field;
+
+ if (const_val.special == ConstValSpecialStatic) {
+ if (outside_fn || field_value->static_value.special != ConstValSpecialRuntime) {
+ ConstExprValue *field_val = ir_resolve_const(ira, field_value);
+ if (!field_val)
+ return ira->codegen->builtin_types.entry_invalid;
+
+ const_val.data.x_struct.fields[field_index] = *field_val;
+ const_val.depends_on_compile_var = const_val.depends_on_compile_var || field_val->depends_on_compile_var;
+ } else {
+ first_non_const_instruction = field_value;
+ const_val.special = ConstValSpecialRuntime;
+ }
+ }
}
- TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, value->type_entry, true);
- if (handle_is_ptr(value->type_entry)) {
- // this instruction is a noop - codegen can pass the pointer we already have as the result
- ir_link_new_instruction(value, &ref_instruction->base);
- return ptr_type;
- } else {
- fn_entry->alloca_list.append(&ref_instruction->base);
- ir_build_ref_from(&ira->new_irb, &ref_instruction->base, value);
- return ptr_type;
+ bool any_missing = false;
+ for (size_t i = 0; i < actual_field_count; i += 1) {
+ if (!field_assign_nodes[i]) {
+ add_node_error(ira->codegen, instruction->source_node,
+ buf_sprintf("missing field: '%s'", buf_ptr(container_type->data.structure.fields[i].name)));
+ any_missing = true;
+ }
+ }
+ if (any_missing)
+ return ira->codegen->builtin_types.entry_invalid;
+
+ if (const_val.special == ConstValSpecialStatic) {
+ ConstExprValue *out_val = ir_build_const_from(ira, instruction, const_val.depends_on_compile_var);
+ *out_val = const_val;
+ return container_type;
+ }
+
+ if (outside_fn) {
+ add_node_error(ira->codegen, first_non_const_instruction->source_node,
+ buf_sprintf("unable to evaluate constant expression"));
+ return ira->codegen->builtin_types.entry_invalid;
}
+
+ IrInstruction *new_instruction = ir_build_struct_init_from(&ira->new_irb, instruction,
+ container_type, actual_field_count, new_fields);
+ fn_entry->alloca_list.append(new_instruction);
+ return container_type;
}
-static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
- switch (instruction->id) {
- case IrInstructionIdInvalid:
- zig_unreachable();
- case IrInstructionIdReturn:
- return ir_analyze_instruction_return(ira, (IrInstructionReturn *)instruction);
- case IrInstructionIdConst:
- return ir_analyze_instruction_const(ira, (IrInstructionConst *)instruction);
- case IrInstructionIdUnOp:
- return ir_analyze_instruction_un_op(ira, (IrInstructionUnOp *)instruction);
- case IrInstructionIdBinOp:
- return ir_analyze_instruction_bin_op(ira, (IrInstructionBinOp *)instruction);
- case IrInstructionIdDeclVar:
- return ir_analyze_instruction_decl_var(ira, (IrInstructionDeclVar *)instruction);
- case IrInstructionIdLoadPtr:
- return ir_analyze_instruction_load_ptr(ira, (IrInstructionLoadPtr *)instruction);
- case IrInstructionIdStorePtr:
- return ir_analyze_instruction_store_ptr(ira, (IrInstructionStorePtr *)instruction);
- case IrInstructionIdElemPtr:
- return ir_analyze_instruction_elem_ptr(ira, (IrInstructionElemPtr *)instruction);
- case IrInstructionIdVarPtr:
- return ir_analyze_instruction_var_ptr(ira, (IrInstructionVarPtr *)instruction);
+static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira, IrInstructionContainerInitList *instruction) {
+ IrInstruction *container_type_value = instruction->container_type->other;
+ TypeTableEntry *container_type = ir_resolve_type(ira, container_type_value);
+ if (!container_type)
+ return ira->codegen->builtin_types.entry_invalid;
+
+ size_t elem_count = instruction->item_count;
+ bool depends_on_compile_var = container_type_value->static_value.depends_on_compile_var;
+
+ if (container_type->id == TypeTableEntryIdStruct && !is_slice(container_type) && elem_count == 0) {
+ return ir_analyze_container_init_fields(ira, &instruction->base, container_type, 0, nullptr, depends_on_compile_var);
+ } else if (is_slice(container_type)) {
+ TypeTableEntry *pointer_type = container_type->data.structure.fields[slice_ptr_index].type_entry;
+ assert(pointer_type->id == TypeTableEntryIdPointer);
+ TypeTableEntry *child_type = pointer_type->data.pointer.child_type;
+
+ ConstExprValue const_val = {};
+ const_val.special = ConstValSpecialStatic;
+ const_val.depends_on_compile_var = depends_on_compile_var;
+ const_val.data.x_array.elements = allocate<ConstExprValue>(elem_count);
+ const_val.data.x_array.size = elem_count;
+
+ FnTableEntry *fn_entry = instruction->base.source_node->block_context->fn_entry;
+ bool outside_fn = (fn_entry == nullptr);
+
+ IrInstruction **new_items = allocate<IrInstruction *>(elem_count);
+
+ IrInstruction *first_non_const_instruction = nullptr;
+
+ for (size_t i = 0; i < elem_count; i += 1) {
+ IrInstruction *arg_value = instruction->items[i]->other;
+ if (arg_value->type_entry->id == TypeTableEntryIdInvalid)
+ return ira->codegen->builtin_types.entry_invalid;
+
+ new_items[i] = arg_value;
+
+ if (const_val.special == ConstValSpecialStatic) {
+ if (outside_fn || arg_value->static_value.special != ConstValSpecialRuntime) {
+ ConstExprValue *elem_val = ir_resolve_const(ira, arg_value);
+ if (!elem_val)
+ return ira->codegen->builtin_types.entry_invalid;
+
+ const_val.data.x_array.elements[i] = *elem_val;
+ const_val.depends_on_compile_var = const_val.depends_on_compile_var || elem_val->depends_on_compile_var;
+ } else {
+ first_non_const_instruction = arg_value;
+ const_val.special = ConstValSpecialRuntime;
+ }
+ }
+ }
+
+ TypeTableEntry *fixed_size_array_type = get_array_type(ira->codegen, child_type, elem_count);
+ if (const_val.special == ConstValSpecialStatic) {
+ ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, const_val.depends_on_compile_var);
+ *out_val = const_val;
+ return fixed_size_array_type;
+ }
+
+ if (outside_fn) {
+ add_node_error(ira->codegen, first_non_const_instruction->source_node,
+ buf_sprintf("unable to evaluate constant expression"));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+
+ IrInstruction *new_instruction = ir_build_container_init_list_from(&ira->new_irb, &instruction->base,
+ container_type_value, elem_count, new_items);
+ fn_entry->alloca_list.append(new_instruction);
+ return fixed_size_array_type;
+ } else if (container_type->id == TypeTableEntryIdArray) {
+ // same as slice init but we make a compile error if the length is wrong
+ zig_panic("TODO array container init");
+ } else if (container_type->id == TypeTableEntryIdVoid) {
+ if (elem_count != 0) {
+ add_node_error(ira->codegen, instruction->base.source_node,
+ buf_sprintf("void expression expects no arguments"));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+ return ir_analyze_void(ira, &instruction->base);
+ } else {
+ add_node_error(ira->codegen, instruction->base.source_node,
+ buf_sprintf("type '%s' does not support array initialization",
+ buf_ptr(&container_type->name)));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+}
+
+static TypeTableEntry *ir_analyze_instruction_container_init_fields(IrAnalyze *ira, IrInstructionContainerInitFields *instruction) {
+ IrInstruction *container_type_value = instruction->container_type->other;
+ TypeTableEntry *container_type = ir_resolve_type(ira, container_type_value);
+ if (!container_type)
+ return ira->codegen->builtin_types.entry_invalid;
+
+ bool depends_on_compile_var = container_type_value->static_value.depends_on_compile_var;
+
+ return ir_analyze_container_init_fields(ira, &instruction->base, container_type,
+ instruction->field_count, instruction->fields, depends_on_compile_var);
+}
+
+static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
+ switch (instruction->id) {
+ case IrInstructionIdInvalid:
+ zig_unreachable();
+ case IrInstructionIdReturn:
+ return ir_analyze_instruction_return(ira, (IrInstructionReturn *)instruction);
+ case IrInstructionIdConst:
+ return ir_analyze_instruction_const(ira, (IrInstructionConst *)instruction);
+ case IrInstructionIdUnOp:
+ return ir_analyze_instruction_un_op(ira, (IrInstructionUnOp *)instruction);
+ case IrInstructionIdBinOp:
+ return ir_analyze_instruction_bin_op(ira, (IrInstructionBinOp *)instruction);
+ case IrInstructionIdDeclVar:
+ return ir_analyze_instruction_decl_var(ira, (IrInstructionDeclVar *)instruction);
+ case IrInstructionIdLoadPtr:
+ return ir_analyze_instruction_load_ptr(ira, (IrInstructionLoadPtr *)instruction);
+ case IrInstructionIdStorePtr:
+ return ir_analyze_instruction_store_ptr(ira, (IrInstructionStorePtr *)instruction);
+ case IrInstructionIdElemPtr:
+ return ir_analyze_instruction_elem_ptr(ira, (IrInstructionElemPtr *)instruction);
+ case IrInstructionIdVarPtr:
+ return ir_analyze_instruction_var_ptr(ira, (IrInstructionVarPtr *)instruction);
case IrInstructionIdFieldPtr:
return ir_analyze_instruction_field_ptr(ira, (IrInstructionFieldPtr *)instruction);
case IrInstructionIdCall:
@@ -5844,10 +6280,14 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
return ir_analyze_instruction_array_len(ira, (IrInstructionArrayLen *)instruction);
case IrInstructionIdRef:
return ir_analyze_instruction_ref(ira, (IrInstructionRef *)instruction);
- case IrInstructionIdCast:
case IrInstructionIdContainerInitList:
+ return ir_analyze_instruction_container_init_list(ira, (IrInstructionContainerInitList *)instruction);
case IrInstructionIdContainerInitFields:
+ return ir_analyze_instruction_container_init_fields(ira, (IrInstructionContainerInitFields *)instruction);
+ case IrInstructionIdCast:
case IrInstructionIdStructFieldPtr:
+ case IrInstructionIdEnumFieldPtr:
+ case IrInstructionIdStructInit:
zig_panic("TODO analyze more instructions");
}
zig_unreachable();
@@ -5947,6 +6387,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdCast:
case IrInstructionIdContainerInitList:
case IrInstructionIdContainerInitFields:
+ case IrInstructionIdStructInit:
case IrInstructionIdFieldPtr:
case IrInstructionIdElemPtr:
case IrInstructionIdVarPtr:
@@ -5955,6 +6396,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdPtrTypeChild:
case IrInstructionIdArrayLen:
case IrInstructionIdStructFieldPtr:
+ case IrInstructionIdEnumFieldPtr:
case IrInstructionIdArrayType:
case IrInstructionIdSliceType:
case IrInstructionIdCompileVar:
@@ -6393,46 +6835,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) {
// return g->builtin_types.entry_void;
//}
//
-//static TypeTableEntry *analyze_set_fn_static_eval(CodeGen *g, ImportTableEntry *import,
-// BlockContext *context, AstNode *node)
-//{
-// AstNode **fn_node = &node->data.fn_call_expr.params.at(0);
-// AstNode **value_node = &node->data.fn_call_expr.params.at(1);
-//
-// FnTableEntry *fn_entry = resolve_const_expr_fn(g, import, context, fn_node);
-// if (!fn_entry) {
-// return g->builtin_types.entry_invalid;
-// }
-//
-// bool want_static_eval;
-// bool ok = resolve_const_expr_bool(g, import, context, value_node, &want_static_eval);
-// if (!ok) {
-// return g->builtin_types.entry_invalid;
-// }
-//
-// if (fn_entry->fn_static_eval_set_node) {
-// ErrorMsg *msg = add_node_error(g, node, buf_sprintf("function static eval attribute set twice"));
-// add_error_note(g, msg, fn_entry->fn_static_eval_set_node, buf_sprintf("first set here"));
-// return g->builtin_types.entry_invalid;
-// }
-// fn_entry->fn_static_eval_set_node = node;
-//
-// if (want_static_eval && !context->fn_entry->is_pure) {
-// add_node_error(g, node, buf_sprintf("attribute appears too late within function"));
-// return g->builtin_types.entry_invalid;
-// }
-//
-// if (want_static_eval) {
-// fn_entry->want_pure = WantPureTrue;
-// fn_entry->want_pure_attr_node = node;
-// } else {
-// fn_entry->want_pure = WantPureFalse;
-// fn_entry->is_pure = false;
-// }
-//
-// return g->builtin_types.entry_void;
-//}
-//
//static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
// TypeTableEntry *expected_type, AstNode *node)
//{
@@ -6634,713 +7036,10 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) {
// return analyze_set_fn_test(g, import, context, node);
// case BuiltinFnIdSetFnNoInline:
// return analyze_set_fn_no_inline(g, import, context, node);
-// case BuiltinFnIdSetFnStaticEval:
-// return analyze_set_fn_static_eval(g, import, context, node);
// }
// zig_unreachable();
//}
-//static TypeTableEntry *analyze_container_init_expr(CodeGen *g, ImportTableEntry *import,
-// BlockContext *context, AstNode *node)
-//{
-// assert(node->type == NodeTypeContainerInitExpr);
-//
-// AstNodeContainerInitExpr *container_init_expr = &node->data.container_init_expr;
-//
-// ContainerInitKind kind = container_init_expr->kind;
-//
-// if (container_init_expr->type->type == NodeTypeFieldAccessExpr) {
-// container_init_expr->type->data.field_access_expr.container_init_expr_node = node;
-// }
-//
-// TypeTableEntry *container_meta_type = analyze_expression(g, import, context, nullptr,
-// container_init_expr->type);
-//
-// if (container_meta_type->id == TypeTableEntryIdInvalid) {
-// return g->builtin_types.entry_invalid;
-// }
-//
-// if (node->data.container_init_expr.enum_type) {
-// get_resolved_expr(node)->const_val = get_resolved_expr(container_init_expr->type)->const_val;
-// return node->data.container_init_expr.enum_type;
-// }
-//
-// TypeTableEntry *container_type = resolve_type(g, container_init_expr->type);
-//
-// if (container_type->id == TypeTableEntryIdInvalid) {
-// return container_type;
-// } else if (container_type->id == TypeTableEntryIdStruct &&
-// !container_type->data.structure.is_slice &&
-// (kind == ContainerInitKindStruct || (kind == ContainerInitKindArray &&
-// container_init_expr->entries.length == 0)))
-// {
-// StructValExprCodeGen *codegen = &container_init_expr->resolved_struct_val_expr;
-// codegen->type_entry = container_type;
-// codegen->source_node = node;
-//
-//
-// size_t expr_field_count = container_init_expr->entries.length;
-// size_t actual_field_count = container_type->data.structure.src_field_count;
-//
-// AstNode *non_const_expr_culprit = nullptr;
-//
-// size_t *field_use_counts = allocate<size_t>(actual_field_count);
-// ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
-// const_val->ok = true;
-// const_val->data.x_struct.fields = allocate<ConstExprValue*>(actual_field_count);
-// for (size_t i = 0; i < expr_field_count; i += 1) {
-// AstNode *val_field_node = container_init_expr->entries.at(i);
-// assert(val_field_node->type == NodeTypeStructValueField);
-//
-// val_field_node->block_context = context;
-//
-// TypeStructField *type_field = find_struct_type_field(container_type,
-// val_field_node->data.struct_val_field.name);
-//
-// if (!type_field) {
-// add_node_error(g, val_field_node,
-// buf_sprintf("no member named '%s' in '%s'",
-// buf_ptr(val_field_node->data.struct_val_field.name), buf_ptr(&container_type->name)));
-// continue;
-// }
-//
-// if (type_field->type_entry->id == TypeTableEntryIdInvalid) {
-// return g->builtin_types.entry_invalid;
-// }
-//
-// size_t field_index = type_field->src_index;
-// field_use_counts[field_index] += 1;
-// if (field_use_counts[field_index] > 1) {
-// add_node_error(g, val_field_node, buf_sprintf("duplicate field"));
-// continue;
-// }
-//
-// val_field_node->data.struct_val_field.type_struct_field = type_field;
-//
-// analyze_expression(g, import, context, type_field->type_entry,
-// val_field_node->data.struct_val_field.expr);
-//
-// if (const_val->ok) {
-// ConstExprValue *field_val =
-// &get_resolved_expr(val_field_node->data.struct_val_field.expr)->const_val;
-// if (field_val->ok) {
-// const_val->data.x_struct.fields[field_index] = field_val;
-// const_val->depends_on_compile_var = const_val->depends_on_compile_var || field_val->depends_on_compile_var;
-// } else {
-// const_val->ok = false;
-// non_const_expr_culprit = val_field_node->data.struct_val_field.expr;
-// }
-// }
-// }
-// if (!const_val->ok) {
-// assert(non_const_expr_culprit);
-// if (context->fn_entry) {
-// context->fn_entry->struct_val_expr_alloca_list.append(codegen);
-// } else {
-// add_node_error(g, non_const_expr_culprit, buf_sprintf("unable to evaluate constant expression"));
-// }
-// }
-//
-// for (size_t i = 0; i < actual_field_count; i += 1) {
-// if (field_use_counts[i] == 0) {
-// add_node_error(g, node,
-// buf_sprintf("missing field: '%s'", buf_ptr(container_type->data.structure.fields[i].name)));
-// }
-// }
-// return container_type;
-// } else if (container_type->id == TypeTableEntryIdStruct &&
-// container_type->data.structure.is_slice &&
-// kind == ContainerInitKindArray)
-// {
-// size_t elem_count = container_init_expr->entries.length;
-//
-// TypeTableEntry *pointer_type = container_type->data.structure.fields[0].type_entry;
-// assert(pointer_type->id == TypeTableEntryIdPointer);
-// TypeTableEntry *child_type = pointer_type->data.pointer.child_type;
-//
-// ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
-// const_val->ok = true;
-// const_val->data.x_array.fields = allocate<ConstExprValue*>(elem_count);
-//
-// for (size_t i = 0; i < elem_count; i += 1) {
-// AstNode **elem_node = &container_init_expr->entries.at(i);
-// analyze_expression(g, import, context, child_type, *elem_node);
-//
-// if (const_val->ok) {
-// ConstExprValue *elem_const_val = &get_resolved_expr(*elem_node)->const_val;
-// if (elem_const_val->ok) {
-// const_val->data.x_array.fields[i] = elem_const_val;
-// const_val->depends_on_compile_var = const_val->depends_on_compile_var ||
-// elem_const_val->depends_on_compile_var;
-// } else {
-// const_val->ok = false;
-// }
-// }
-// }
-//
-// TypeTableEntry *fixed_size_array_type = get_array_type(g, child_type, elem_count);
-//
-// StructValExprCodeGen *codegen = &container_init_expr->resolved_struct_val_expr;
-// codegen->type_entry = fixed_size_array_type;
-// codegen->source_node = node;
-// if (!const_val->ok) {
-// if (!context->fn_entry) {
-// add_node_error(g, node,
-// buf_sprintf("unable to evaluate constant expression"));
-// } else {
-// context->fn_entry->struct_val_expr_alloca_list.append(codegen);
-// }
-// }
-//
-// return fixed_size_array_type;
-// } else if (container_type->id == TypeTableEntryIdArray) {
-// zig_panic("TODO array container init");
-// return container_type;
-// } else if (container_type->id == TypeTableEntryIdVoid) {
-// if (container_init_expr->entries.length != 0) {
-// add_node_error(g, node, buf_sprintf("void expression expects no arguments"));
-// return g->builtin_types.entry_invalid;
-// } else {
-// return resolve_expr_const_val_as_void(g, node);
-// }
-// } else {
-// add_node_error(g, node,
-// buf_sprintf("type '%s' does not support %s initialization syntax",
-// buf_ptr(&container_type->name), err_container_init_syntax_name(kind)));
-// return g->builtin_types.entry_invalid;
-// }
-//}
-
-
-
-//static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
-// TypeTableEntry *expected_type, AstNode *node)
-//{
-// assert(node->type == NodeTypeFieldAccessExpr);
-//
-// AstNode **struct_expr_node = &node->data.field_access_expr.struct_expr;
-// TypeTableEntry *struct_type = analyze_expression(g, import, context, nullptr, *struct_expr_node);
-// Buf *field_name = node->data.field_access_expr.field_name;
-//
-// if (struct_type->id == TypeTableEntryIdInvalid) {
-// return struct_type;
-// } else if (is_container_ref(struct_type)) {
-// return analyze_container_member_access(g, field_name, node, struct_type);
-// } else if (struct_type->id == TypeTableEntryIdArray) {
-// if (buf_eql_str(field_name, "len")) {
-// return resolve_expr_const_val_as_unsigned_num_lit(g, node, expected_type,
-// struct_type->data.array.len, false);
-// } else {
-// add_node_error(g, node,
-// buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name),
-// buf_ptr(&struct_type->name)));
-// return g->builtin_types.entry_invalid;
-// }
-// } else if (struct_type->id == TypeTableEntryIdMetaType) {
-// TypeTableEntry *child_type = resolve_type(g, *struct_expr_node);
-//
-// if (child_type->id == TypeTableEntryIdInvalid) {
-// return g->builtin_types.entry_invalid;
-// } else if (child_type->id == TypeTableEntryIdEnum) {
-// AstNode *container_init_node = node->data.field_access_expr.container_init_expr_node;
-// AstNode *value_node;
-// if (container_init_node) {
-// assert(container_init_node->type == NodeTypeContainerInitExpr);
-// size_t param_count = container_init_node->data.container_init_expr.entries.length;
-// if (param_count > 1) {
-// AstNode *first_invalid_node = container_init_node->data.container_init_expr.entries.at(1);
-// add_node_error(g, first_executing_node(first_invalid_node),
-// buf_sprintf("enum values accept only one parameter"));
-// return child_type;
-// } else {
-// if (param_count == 1) {
-// value_node = container_init_node->data.container_init_expr.entries.at(0);
-// } else {
-// value_node = nullptr;
-// }
-// container_init_node->data.container_init_expr.enum_type = child_type;
-// }
-// } else {
-// value_node = nullptr;
-// }
-// return analyze_enum_value_expr(g, import, context, node, value_node, child_type, field_name, node);
-// } else if (child_type->id == TypeTableEntryIdStruct) {
-// BlockContext *container_block_context = get_container_block_context(child_type);
-// auto entry = container_block_context->decl_table.maybe_get(field_name);
-// AstNode *decl_node = entry ? entry->value : nullptr;
-// if (decl_node) {
-// bool pointer_only = false;
-// return analyze_decl_ref(g, node, decl_node, pointer_only, context, false);
-// } else {
-// add_node_error(g, node,
-// buf_sprintf("container '%s' has no member called '%s'",
-// buf_ptr(&child_type->name), buf_ptr(field_name)));
-// return g->builtin_types.entry_invalid;
-// }
-// } else if (child_type->id == TypeTableEntryIdPureError) {
-// return analyze_error_literal_expr(g, import, context, node, field_name);
-// } else if (child_type->id == TypeTableEntryIdInt) {
-// bool depends_on_compile_var =
-// get_resolved_expr(*struct_expr_node)->const_val.depends_on_compile_var;
-// if (buf_eql_str(field_name, "bit_count")) {
-// return resolve_expr_const_val_as_unsigned_num_lit(g, node, expected_type,
-// child_type->data.integral.bit_count, depends_on_compile_var);
-// } else if (buf_eql_str(field_name, "is_signed")) {
-// return resolve_expr_const_val_as_bool(g, node, child_type->data.integral.is_signed,
-// depends_on_compile_var);
-// } else {
-// add_node_error(g, node,
-// buf_sprintf("type '%s' has no member called '%s'",
-// buf_ptr(&child_type->name), buf_ptr(field_name)));
-// return g->builtin_types.entry_invalid;
-// }
-// } else {
-// add_node_error(g, node,
-// buf_sprintf("type '%s' does not support field access", buf_ptr(&struct_type->name)));
-// return g->builtin_types.entry_invalid;
-// }
-// } else {
-// add_node_error(g, node,
-// buf_sprintf("type '%s' does not support field access", buf_ptr(&struct_type->name)));
-// return g->builtin_types.entry_invalid;
-// }
-//}
-//
-//static TypeTableEntry *bad_method_call(CodeGen *g, AstNode *node, TypeTableEntry *container_type,
-// TypeTableEntry *expected_param_type, FnTableEntry *fn_table_entry)
-//{
-// ErrorMsg *msg = add_node_error(g, node,
-// buf_sprintf("function called as method of '%s', but first parameter is of type '%s'",
-// buf_ptr(&container_type->name),
-// buf_ptr(&expected_param_type->name)));
-// if (fn_table_entry) {
-// add_error_note(g, msg, fn_table_entry->proto_node, buf_sprintf("function declared here"));
-// }
-// return g->builtin_types.entry_invalid;
-//}
-//
-//// Before calling this function, set node->data.fn_call_expr.fn_table_entry if the function is known
-//// at compile time. Otherwise this is a function pointer call.
-//static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
-// TypeTableEntry *expected_type, AstNode *node, TypeTableEntry *fn_type,
-// AstNode *struct_node)
-//{
-// assert(node->type == NodeTypeFnCallExpr);
-//
-// if (fn_type->id == TypeTableEntryIdInvalid) {
-// return fn_type;
-// }
-//
-// // The function call might include inline parameters which we need to ignore according to the
-// // fn_type.
-// FnTableEntry *fn_table_entry = node->data.fn_call_expr.fn_entry;
-// AstNode *generic_proto_node = fn_table_entry ?
-// fn_table_entry->proto_node->data.fn_proto.generic_proto_node : nullptr;
-//
-// // count parameters
-// size_t struct_node_1_or_0 = struct_node ? 1 : 0;
-// size_t src_param_count = fn_type->data.fn.fn_type_id.param_count +
-// (generic_proto_node ? generic_proto_node->data.fn_proto.inline_arg_count : 0);
-// size_t call_param_count = node->data.fn_call_expr.params.length;
-// size_t expect_arg_count = src_param_count - struct_node_1_or_0;
-//
-// bool ok_invocation = true;
-//
-// if (fn_type->data.fn.fn_type_id.is_var_args) {
-// if (call_param_count < expect_arg_count) {
-// ok_invocation = false;
-// add_node_error(g, node,
-// buf_sprintf("expected at least %zu arguments, found %zu", src_param_count, call_param_count));
-// }
-// } else if (expect_arg_count != call_param_count) {
-// ok_invocation = false;
-// add_node_error(g, node,
-// buf_sprintf("expected %zu arguments, found %zu", expect_arg_count, call_param_count));
-// }
-//
-// bool all_args_const_expr = true;
-//
-// if (struct_node) {
-// Expr *struct_expr = get_resolved_expr(struct_node);
-// ConstExprValue *struct_const_val = &struct_expr->const_val;
-// if (!struct_const_val->ok) {
-// all_args_const_expr = false;
-// }
-//
-// FnTypeParamInfo *param_info = &fn_type->data.fn.fn_type_id.param_info[0];
-// TypeTableEntry *expected_param_type = param_info->type;
-// TypeTableEntry *container_bare_type = container_ref_type(struct_expr->type_entry);
-// if (is_container_ref(expected_param_type)) {
-// TypeTableEntry *param_bare_type = container_ref_type(expected_param_type);
-// if (param_bare_type != container_bare_type) {
-// return bad_method_call(g, node, container_bare_type, expected_param_type, fn_table_entry);
-// }
-// } else {
-// return bad_method_call(g, node, container_bare_type, expected_param_type, fn_table_entry);
-// }
-// }
-//
-// // analyze each parameter. in the case of a method, we already analyzed the
-// // first parameter in order to figure out which struct we were calling a method on.
-// size_t next_type_i = struct_node_1_or_0;
-// for (size_t call_i = 0; call_i < call_param_count; call_i += 1) {
-// size_t proto_i = call_i + struct_node_1_or_0;
-// AstNode **param_node = &node->data.fn_call_expr.params.at(call_i);
-// // determine the expected type for each parameter
-// TypeTableEntry *expected_param_type = nullptr;
-// if (proto_i < src_param_count) {
-// if (generic_proto_node &&
-// generic_proto_node->data.fn_proto.params.at(proto_i)->data.param_decl.is_inline)
-// {
-// continue;
-// }
-//
-// FnTypeParamInfo *param_info = &fn_type->data.fn.fn_type_id.param_info[next_type_i];
-// next_type_i += 1;
-//
-// expected_param_type = param_info->type;
-// }
-// TypeTableEntry *param_type = analyze_expression(g, import, context, expected_param_type, *param_node);
-// if (param_type->id == TypeTableEntryIdInvalid) {
-// return param_type;
-// }
-//
-// ConstExprValue *const_arg_val = &get_resolved_expr(*param_node)->const_val;
-// if (!const_arg_val->ok) {
-// all_args_const_expr = false;
-// }
-// }
-//
-// TypeTableEntry *return_type = fn_type->data.fn.fn_type_id.return_type;
-//
-// if (return_type->id == TypeTableEntryIdInvalid) {
-// return return_type;
-// }
-//
-// ConstExprValue *result_val = &get_resolved_expr(node)->const_val;
-// if (ok_invocation && fn_table_entry && fn_table_entry->is_pure && fn_table_entry->want_pure != WantPureFalse) {
-// if (fn_table_entry->anal_state == FnAnalStateReady) {
-// analyze_fn_body(g, fn_table_entry);
-// if (fn_table_entry->proto_node->data.fn_proto.skip) {
-// return g->builtin_types.entry_invalid;
-// }
-// }
-// if (all_args_const_expr) {
-// if (fn_table_entry->is_pure && fn_table_entry->anal_state == FnAnalStateComplete) {
-// if (eval_fn(g, node, fn_table_entry, result_val, 1000, struct_node)) {
-// // function evaluation generated an error
-// return g->builtin_types.entry_invalid;
-// }
-// return return_type;
-// }
-// }
-// }
-// if (!ok_invocation || !fn_table_entry || !fn_table_entry->is_pure || fn_table_entry->want_pure == WantPureFalse) {
-// // calling an impure fn is impure
-// mark_impure_fn(g, context, node);
-// if (fn_table_entry && fn_table_entry->want_pure == WantPureTrue) {
-// return g->builtin_types.entry_invalid;
-// }
-// }
-//
-// // TODO
-// //if (handle_is_ptr(return_type)) {
-// // if (context->fn_entry) {
-// // context->fn_entry->cast_alloca_list.append(node);
-// // } else if (!result_val->ok) {
-// // add_node_error(g, node, buf_sprintf("unable to evaluate constant expression"));
-// // }
-// //}
-//
-// return return_type;
-//}
-//
-//static TypeTableEntry *analyze_fn_call_with_inline_args(CodeGen *g, ImportTableEntry *import,
-// BlockContext *parent_context, TypeTableEntry *expected_type, AstNode *call_node,
-// FnTableEntry *fn_table_entry, AstNode *struct_node)
-//{
-// assert(call_node->type == NodeTypeFnCallExpr);
-// assert(fn_table_entry);
-//
-// AstNode *decl_node = fn_table_entry->proto_node;
-//
-// // count parameters
-// size_t struct_node_1_or_0 = (struct_node ? 1 : 0);
-// size_t src_param_count = decl_node->data.fn_proto.params.length;
-// size_t call_param_count = call_node->data.fn_call_expr.params.length;
-//
-// if (src_param_count != call_param_count + struct_node_1_or_0) {
-// add_node_error(g, call_node,
-// buf_sprintf("expected %zu arguments, found %zu", src_param_count - struct_node_1_or_0, call_param_count));
-// return g->builtin_types.entry_invalid;
-// }
-//
-// size_t inline_or_var_type_arg_count = decl_node->data.fn_proto.inline_or_var_type_arg_count;
-// assert(inline_or_var_type_arg_count > 0);
-//
-// BlockContext *child_context = decl_node->owner->block_context;
-// size_t next_generic_param_index = 0;
-//
-// GenericFnTypeId *generic_fn_type_id = allocate<GenericFnTypeId>(1);
-// generic_fn_type_id->decl_node = decl_node;
-// generic_fn_type_id->generic_param_count = inline_or_var_type_arg_count;
-// generic_fn_type_id->generic_params = allocate<GenericParamValue>(inline_or_var_type_arg_count);
-//
-// size_t next_impl_i = 0;
-// for (size_t call_i = 0; call_i < call_param_count; call_i += 1) {
-// size_t proto_i = call_i + struct_node_1_or_0;
-// AstNode *generic_param_decl_node = decl_node->data.fn_proto.params.at(proto_i);
-// assert(generic_param_decl_node->type == NodeTypeParamDecl);
-//
-// AstNode **generic_param_type_node = &generic_param_decl_node->data.param_decl.type;
-// TypeTableEntry *expected_param_type = analyze_type_expr(g, decl_node->owner, child_context,
-// *generic_param_type_node);
-// if (expected_param_type->id == TypeTableEntryIdInvalid) {
-// return expected_param_type;
-// }
-//
-// bool is_var_type = (expected_param_type->id == TypeTableEntryIdVar);
-// bool is_inline = generic_param_decl_node->data.param_decl.is_inline;
-// if (!is_inline && !is_var_type) {
-// next_impl_i += 1;
-// continue;
-// }
-//
-//
-// AstNode **param_node = &call_node->data.fn_call_expr.params.at(call_i);
-// TypeTableEntry *param_type = analyze_expression(g, import, parent_context,
-// is_var_type ? nullptr : expected_param_type, *param_node);
-// if (param_type->id == TypeTableEntryIdInvalid) {
-// return param_type;
-// }
-//
-// // set child_context so that the previous param is in scope
-// child_context = new_block_context(generic_param_decl_node, child_context);
-//
-// ConstExprValue *const_val = &get_resolved_expr(*param_node)->const_val;
-// if (is_inline && !const_val->ok) {
-// add_node_error(g, *param_node,
-// buf_sprintf("unable to evaluate constant expression for inline parameter"));
-//
-// return g->builtin_types.entry_invalid;
-// }
-//
-// VariableTableEntry *var = add_local_var_shadowable(g, generic_param_decl_node, decl_node->owner, child_context,
-// generic_param_decl_node->data.param_decl.name, param_type, true, *param_node, true);
-// // This generic function instance could be called with anything, so when this variable is read it
-// // needs to know that it depends on compile time variable data.
-// var->force_depends_on_compile_var = true;
-//
-// GenericParamValue *generic_param_value =
-// &generic_fn_type_id->generic_params[next_generic_param_index];
-// generic_param_value->type = param_type;
-// generic_param_value->node = is_inline ? *param_node : nullptr;
-// generic_param_value->impl_index = next_impl_i;
-// next_generic_param_index += 1;
-//
-// if (!is_inline) {
-// next_impl_i += 1;
-// }
-// }
-//
-// assert(next_generic_param_index == inline_or_var_type_arg_count);
-//
-// auto entry = g->generic_table.maybe_get(generic_fn_type_id);
-// FnTableEntry *impl_fn;
-// if (entry) {
-// AstNode *impl_decl_node = entry->value;
-// assert(impl_decl_node->type == NodeTypeFnProto);
-// impl_fn = impl_decl_node->data.fn_proto.fn_table_entry;
-// } else {
-// AstNode *decl_node = generic_fn_type_id->decl_node;
-// AstNode *impl_fn_def_node = ast_clone_subtree_special(decl_node->data.fn_proto.fn_def_node,
-// &g->next_node_index, AstCloneSpecialOmitInlineParams);
-// AstNode *impl_decl_node = impl_fn_def_node->data.fn_def.fn_proto;
-// impl_decl_node->data.fn_proto.inline_arg_count = 0;
-// impl_decl_node->data.fn_proto.inline_or_var_type_arg_count = 0;
-// impl_decl_node->data.fn_proto.generic_proto_node = decl_node;
-//
-// // replace var arg types with actual types
-// for (size_t generic_arg_i = 0; generic_arg_i < inline_or_var_type_arg_count; generic_arg_i += 1) {
-// GenericParamValue *generic_param_value = &generic_fn_type_id->generic_params[generic_arg_i];
-// if (!generic_param_value->node) {
-// size_t impl_i = generic_param_value->impl_index;
-// AstNode *impl_param_decl_node = impl_decl_node->data.fn_proto.params.at(impl_i);
-// assert(impl_param_decl_node->type == NodeTypeParamDecl);
-//
-// impl_param_decl_node->data.param_decl.type = create_ast_type_node(g, import,
-// generic_param_value->type, impl_param_decl_node);
-// normalize_parent_ptrs(impl_param_decl_node);
-// }
-// }
-//
-// preview_fn_proto_instance(g, import, impl_decl_node, child_context);
-// g->generic_table.put(generic_fn_type_id, impl_decl_node);
-// impl_fn = impl_decl_node->data.fn_proto.fn_table_entry;
-// }
-//
-// call_node->data.fn_call_expr.fn_entry = impl_fn;
-// return analyze_fn_call_ptr(g, import, parent_context, expected_type, call_node,
-// impl_fn->type_entry, struct_node);
-//}
-//
-//static TypeTableEntry *analyze_generic_fn_call(CodeGen *g, ImportTableEntry *import, BlockContext *parent_context,
-// TypeTableEntry *expected_type, AstNode *node, TypeTableEntry *generic_fn_type)
-//{
-// assert(node->type == NodeTypeFnCallExpr);
-// assert(generic_fn_type->id == TypeTableEntryIdGenericFn);
-//
-// AstNode *decl_node = generic_fn_type->data.generic_fn.decl_node;
-// assert(decl_node->type == NodeTypeContainerDecl);
-// ZigList<AstNode *> *generic_params = &decl_node->data.struct_decl.generic_params;
-//
-// size_t expected_param_count = generic_params->length;
-// size_t actual_param_count = node->data.fn_call_expr.params.length;
-//
-// if (actual_param_count != expected_param_count) {
-// add_node_error(g, first_executing_node(node),
-// buf_sprintf("expected %zu arguments, found %zu", expected_param_count, actual_param_count));
-// return g->builtin_types.entry_invalid;
-// }
-//
-// GenericFnTypeId *generic_fn_type_id = allocate<GenericFnTypeId>(1);
-// generic_fn_type_id->decl_node = decl_node;
-// generic_fn_type_id->generic_param_count = actual_param_count;
-// generic_fn_type_id->generic_params = allocate<GenericParamValue>(actual_param_count);
-//
-// BlockContext *child_context = decl_node->owner->block_context;
-// for (size_t i = 0; i < actual_param_count; i += 1) {
-// AstNode *generic_param_decl_node = generic_params->at(i);
-// assert(generic_param_decl_node->type == NodeTypeParamDecl);
-//
-// AstNode **generic_param_type_node = &generic_param_decl_node->data.param_decl.type;
-//
-// TypeTableEntry *expected_param_type = analyze_type_expr(g, decl_node->owner,
-// child_context, *generic_param_type_node);
-// if (expected_param_type->id == TypeTableEntryIdInvalid) {
-// return expected_param_type;
-// }
-//
-//
-//
-// AstNode **param_node = &node->data.fn_call_expr.params.at(i);
-//
-// TypeTableEntry *param_type = analyze_expression(g, import, parent_context, expected_param_type,
-// *param_node);
-// if (param_type->id == TypeTableEntryIdInvalid) {
-// return param_type;
-// }
-//
-// // set child_context so that the previous param is in scope
-// child_context = new_block_context(generic_param_decl_node, child_context);
-//
-// ConstExprValue *const_val = &get_resolved_expr(*param_node)->const_val;
-// if (const_val->ok) {
-// VariableTableEntry *var = add_local_var(g, generic_param_decl_node, decl_node->owner, child_context,
-// generic_param_decl_node->data.param_decl.name, param_type, true, *param_node);
-// var->force_depends_on_compile_var = true;
-// } else {
-// add_node_error(g, *param_node, buf_sprintf("unable to evaluate constant expression"));
-//
-// return g->builtin_types.entry_invalid;
-// }
-//
-// GenericParamValue *generic_param_value = &generic_fn_type_id->generic_params[i];
-// generic_param_value->type = param_type;
-// generic_param_value->node = *param_node;
-// }
-//
-// auto entry = g->generic_table.maybe_get(generic_fn_type_id);
-// if (entry) {
-// AstNode *impl_decl_node = entry->value;
-// assert(impl_decl_node->type == NodeTypeContainerDecl);
-// TypeTableEntry *type_entry = impl_decl_node->data.struct_decl.type_entry;
-// return resolve_expr_const_val_as_type(g, node, type_entry, false);
-// }
-//
-// // make a type from the generic parameters supplied
-// assert(decl_node->type == NodeTypeContainerDecl);
-// AstNode *impl_decl_node = ast_clone_subtree(decl_node, &g->next_node_index);
-// g->generic_table.put(generic_fn_type_id, impl_decl_node);
-// scan_struct_decl(g, import, child_context, impl_decl_node);
-// TypeTableEntry *type_entry = impl_decl_node->data.struct_decl.type_entry;
-// resolve_struct_type(g, import, type_entry);
-// return resolve_expr_const_val_as_type(g, node, type_entry, false);
-//}
-//
-//static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
-// TypeTableEntry *expected_type, AstNode *node)
-//{
-// AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr;
-//
-// if (node->data.fn_call_expr.is_builtin) {
-// zig_panic("moved builtin fn call code to ir.cpp");
-// }
-//
-// TypeTableEntry *invoke_type_entry = analyze_expression(g, import, context, nullptr, fn_ref_expr);
-// if (invoke_type_entry->id == TypeTableEntryIdInvalid) {
-// return g->builtin_types.entry_invalid;
-// }
-//
-// // use constant expression evaluator to figure out the function at compile time.
-// // otherwise we treat this as a function pointer.
-// ConstExprValue *const_val = &get_resolved_expr(fn_ref_expr)->const_val;
-//
-// if (const_val->ok) {
-// if (invoke_type_entry->id == TypeTableEntryIdMetaType) {
-// zig_unreachable();
-// } else if (invoke_type_entry->id == TypeTableEntryIdFn) {
-// AstNode *struct_node;
-// if (fn_ref_expr->type == NodeTypeFieldAccessExpr &&
-// fn_ref_expr->data.field_access_expr.is_member_fn)
-// {
-// struct_node = fn_ref_expr->data.field_access_expr.struct_expr;
-// } else {
-// struct_node = nullptr;
-// }
-//
-// FnTableEntry *fn_table_entry = const_val->data.x_fn;
-// node->data.fn_call_expr.fn_entry = fn_table_entry;
-// return analyze_fn_call_ptr(g, import, context, expected_type, node,
-// fn_table_entry->type_entry, struct_node);
-// } else if (invoke_type_entry->id == TypeTableEntryIdGenericFn) {
-// TypeTableEntry *generic_fn_type = const_val->data.x_type;
-// AstNode *decl_node = generic_fn_type->data.generic_fn.decl_node;
-// if (decl_node->type == NodeTypeFnProto) {
-// AstNode *struct_node;
-// if (fn_ref_expr->type == NodeTypeFieldAccessExpr &&
-// fn_ref_expr->data.field_access_expr.is_member_fn)
-// {
-// struct_node = fn_ref_expr->data.field_access_expr.struct_expr;
-// } else {
-// struct_node = nullptr;
-// }
-//
-// FnTableEntry *fn_table_entry = decl_node->data.fn_proto.fn_table_entry;
-// if (fn_table_entry->proto_node->data.fn_proto.skip) {
-// return g->builtin_types.entry_invalid;
-// }
-// return analyze_fn_call_with_inline_args(g, import, context, expected_type, node,
-// fn_table_entry, struct_node);
-// } else {
-// return analyze_generic_fn_call(g, import, context, expected_type, node, const_val->data.x_type);
-// }
-// } else {
-// add_node_error(g, fn_ref_expr,
-// buf_sprintf("type '%s' not a function", buf_ptr(&invoke_type_entry->name)));
-// return g->builtin_types.entry_invalid;
-// }
-// }
-//
-// // function pointer
-// if (invoke_type_entry->id == TypeTableEntryIdFn) {
-// return analyze_fn_call_ptr(g, import, context, expected_type, node, invoke_type_entry, nullptr);
-// } else {
-// add_node_error(g, fn_ref_expr,
-// buf_sprintf("type '%s' not a function", buf_ptr(&invoke_type_entry->name)));
-// return g->builtin_types.entry_invalid;
-// }
-//}
//static TypeTableEntry *analyze_return_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
// TypeTableEntry *expected_type, AstNode *node)
//{
@@ -7476,68 +7175,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) {
// return enum_type;
//}
//
-//static TypeTableEntry *analyze_container_member_access_inner(CodeGen *g,
-// TypeTableEntry *bare_struct_type, Buf *field_name, AstNode *node, TypeTableEntry *struct_type)
-//{
-// assert(node->type == NodeTypeFieldAccessExpr);
-// if (!is_slice(bare_struct_type)) {
-// BlockContext *container_block_context = get_container_block_context(bare_struct_type);
-// assert(container_block_context);
-// auto entry = container_block_context->decl_table.maybe_get(field_name);
-// AstNode *fn_decl_node = entry ? entry->value : nullptr;
-// if (fn_decl_node && fn_decl_node->type == NodeTypeFnProto) {
-// resolve_top_level_decl(g, fn_decl_node, false);
-// TopLevelDecl *tld = get_as_top_level_decl(fn_decl_node);
-// if (tld->resolution == TldResolutionInvalid) {
-// return g->builtin_types.entry_invalid;
-// }
-//
-// node->data.field_access_expr.is_member_fn = true;
-// FnTableEntry *fn_entry = fn_decl_node->data.fn_proto.fn_table_entry;
-// if (fn_entry->type_entry->id == TypeTableEntryIdGenericFn) {
-// return resolve_expr_const_val_as_generic_fn(g, node, fn_entry->type_entry, false);
-// } else {
-// return resolve_expr_const_val_as_fn(g, node, fn_entry, false);
-// }
-// }
-// }
-// add_node_error(g, node,
-// buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name), buf_ptr(&bare_struct_type->name)));
-// return g->builtin_types.entry_invalid;
-//}
-//
-//static TypeTableEntry *analyze_container_member_access(CodeGen *g,
-// Buf *field_name, AstNode *node, TypeTableEntry *struct_type)
-//{
-// TypeTableEntry *bare_type = container_ref_type(struct_type);
-// if (!type_is_complete(bare_type)) {
-// resolve_container_type(g, bare_type);
-// }
-//
-// node->data.field_access_expr.bare_container_type = bare_type;
-//
-// if (bare_type->id == TypeTableEntryIdStruct) {
-// node->data.field_access_expr.type_struct_field = find_struct_type_field(bare_type, field_name);
-// if (node->data.field_access_expr.type_struct_field) {
-// return node->data.field_access_expr.type_struct_field->type_entry;
-// } else {
-// return analyze_container_member_access_inner(g, bare_type, field_name,
-// node, struct_type);
-// }
-// } else if (bare_type->id == TypeTableEntryIdEnum) {
-// node->data.field_access_expr.type_enum_field = find_enum_type_field(bare_type, field_name);
-// if (node->data.field_access_expr.type_enum_field) {
-// return node->data.field_access_expr.type_enum_field->type_entry;
-// } else {
-// return analyze_container_member_access_inner(g, bare_type, field_name,
-// node, struct_type);
-// }
-// } else if (bare_type->id == TypeTableEntryIdUnion) {
-// zig_panic("TODO");
-// } else {
-// zig_unreachable();
-// }
-//}
//
//static TypeTableEntry *analyze_slice_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
// AstNode *node)
@@ -7887,19 +7524,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) {
// return g->builtin_types.entry_invalid;
//}
//
-//static TypeTableEntry *analyze_fn_proto_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
-// TypeTableEntry *expected_type, AstNode *node)
-//{
-// TypeTableEntry *type_entry = analyze_fn_proto_type(g, import, context, expected_type, node,
-// false, false, nullptr);
-//
-// if (type_entry->id == TypeTableEntryIdInvalid) {
-// return type_entry;
-// }
-//
-// return resolve_expr_const_val_as_type(g, node, type_entry, false);
-//}
-//
//static void validate_voided_expr(CodeGen *g, AstNode *source_node, TypeTableEntry *type_entry) {
// if (type_entry->id == TypeTableEntryIdMetaType) {
// add_node_error(g, first_executing_node(source_node), buf_sprintf("expected expression, found type"));
@@ -8239,92 +7863,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) {
// }
//}
//
-//static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
-// assert(node->type == NodeTypeFnCallExpr);
-//
-// if (node->data.fn_call_expr.is_builtin) {
-// return gen_builtin_fn_call_expr(g, node);
-// }
-//
-// FnTableEntry *fn_table_entry = node->data.fn_call_expr.fn_entry;
-// TypeTableEntry *struct_type = nullptr;
-// AstNode *first_param_expr = nullptr;
-//
-// AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr;
-// if (fn_ref_expr->type == NodeTypeFieldAccessExpr &&
-// fn_ref_expr->data.field_access_expr.is_member_fn)
-// {
-// first_param_expr = fn_ref_expr->data.field_access_expr.struct_expr;
-// struct_type = get_expr_type(first_param_expr);
-// }
-//
-// TypeTableEntry *fn_type;
-// LLVMValueRef fn_val;
-// AstNode *generic_proto_node;
-// if (fn_table_entry) {
-// fn_val = fn_table_entry->fn_value;
-// fn_type = fn_table_entry->type_entry;
-// generic_proto_node = fn_table_entry->proto_node->data.fn_proto.generic_proto_node;
-// } else {
-// fn_val = gen_expr(g, fn_ref_expr);
-// fn_type = get_expr_type(fn_ref_expr);
-// generic_proto_node = nullptr;
-// }
-//
-// TypeTableEntry *src_return_type = fn_type->data.fn.fn_type_id.return_type;
-//
-// bool ret_has_bits = type_has_bits(src_return_type);
-//
-// size_t fn_call_param_count = node->data.fn_call_expr.params.length;
-// bool first_arg_ret = ret_has_bits && handle_is_ptr(src_return_type);
-// size_t actual_param_count = fn_call_param_count + (struct_type ? 1 : 0) + (first_arg_ret ? 1 : 0);
-// bool is_var_args = fn_type->data.fn.fn_type_id.is_var_args;
-//
-// // don't really include void values
-// LLVMValueRef *gen_param_values = allocate<LLVMValueRef>(actual_param_count);
-//
-// size_t gen_param_index = 0;
-// if (first_arg_ret) {
-// gen_param_values[gen_param_index] = node->data.fn_call_expr.tmp_ptr;
-// gen_param_index += 1;
-// }
-// if (struct_type && type_has_bits(struct_type)) {
-// gen_param_values[gen_param_index] = gen_expr(g, first_param_expr);
-// assert(gen_param_values[gen_param_index]);
-// gen_param_index += 1;
-// }
-//
-// for (size_t call_i = 0; call_i < fn_call_param_count; call_i += 1) {
-// size_t proto_i = call_i + (struct_type ? 1 : 0);
-// if (generic_proto_node &&
-// generic_proto_node->data.fn_proto.params.at(proto_i)->data.param_decl.is_inline)
-// {
-// continue;
-// }
-// AstNode *expr_node = node->data.fn_call_expr.params.at(call_i);
-// LLVMValueRef param_value = gen_expr(g, expr_node);
-// assert(param_value);
-// TypeTableEntry *param_type = get_expr_type(expr_node);
-// if (is_var_args || type_has_bits(param_type)) {
-// gen_param_values[gen_param_index] = param_value;
-// gen_param_index += 1;
-// }
-// }
-//
-// LLVMValueRef result = ZigLLVMBuildCall(g->builder, fn_val,
-// gen_param_values, gen_param_index, fn_type->data.fn.calling_convention, "");
-//
-// if (src_return_type->id == TypeTableEntryIdUnreachable) {
-// return LLVMBuildUnreachable(g->builder);
-// } else if (!ret_has_bits) {
-// return nullptr;
-// } else if (first_arg_ret) {
-// return node->data.fn_call_expr.tmp_ptr;
-// } else {
-// return result;
-// }
-//}
-//
//static LLVMValueRef gen_array_base_ptr(CodeGen *g, AstNode *node) {
// TypeTableEntry *type_entry = get_expr_type(node);
//
@@ -8356,46 +7894,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) {
// return gen_array_elem_ptr(g, node, array_ptr, array_type, subscript_value);
//}
//
-//static LLVMValueRef gen_field_ptr(CodeGen *g, AstNode *node, TypeTableEntry **out_type_entry) {
-// assert(node->type == NodeTypeFieldAccessExpr);
-//
-// AstNode *struct_expr_node = node->data.field_access_expr.struct_expr;
-//
-// *out_type_entry = node->data.field_access_expr.type_struct_field->type_entry;
-// if (!type_has_bits(*out_type_entry)) {
-// return nullptr;
-// }
-//
-// LLVMValueRef struct_ptr;
-// if (struct_expr_node->type == NodeTypeSymbol) {
-// VariableTableEntry *var = get_resolved_expr(struct_expr_node)->variable;
-// assert(var);
-//
-// if (var->type->id == TypeTableEntryIdPointer) {
-// struct_ptr = LLVMBuildLoad(g->builder, var->value_ref, "");
-// } else {
-// struct_ptr = var->value_ref;
-// }
-// } else if (struct_expr_node->type == NodeTypeFieldAccessExpr) {
-// struct_ptr = gen_field_access_expr(g, struct_expr_node, true);
-// TypeTableEntry *field_type = get_expr_type(struct_expr_node);
-// if (field_type->id == TypeTableEntryIdPointer) {
-// // we have a double pointer so we must dereference it once
-// struct_ptr = LLVMBuildLoad(g->builder, struct_ptr, "");
-// }
-// } else {
-// struct_ptr = gen_expr(g, struct_expr_node);
-// }
-//
-// assert(LLVMGetTypeKind(LLVMTypeOf(struct_ptr)) == LLVMPointerTypeKind);
-// assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(struct_ptr))) == LLVMStructTypeKind);
-//
-// size_t gen_field_index = node->data.field_access_expr.type_struct_field->gen_index;
-// assert(gen_field_index != SIZE_MAX);
-//
-// return LLVMBuildStructGEP(g->builder, struct_ptr, gen_field_index, "");
-//}
-//
//static LLVMValueRef gen_slice_expr(CodeGen *g, AstNode *node) {
// assert(node->type == NodeTypeSliceExpr);
//
@@ -8771,87 +8269,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) {
// zig_unreachable();
//}
//
-//static LLVMValueRef gen_if_bool_expr_raw(CodeGen *g, AstNode *source_node, LLVMValueRef cond_value,
-// AstNode *then_node, AstNode *else_node)
-//{
-// assert(then_node);
-// assert(else_node);
-//
-// TypeTableEntry *then_type = get_expr_type(then_node);
-// TypeTableEntry *else_type = get_expr_type(else_node);
-//
-// bool use_then_value = type_has_bits(then_type);
-// bool use_else_value = type_has_bits(else_type);
-//
-// LLVMBasicBlockRef then_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "Then");
-// LLVMBasicBlockRef else_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "Else");
-//
-// LLVMBasicBlockRef endif_block = nullptr;
-// bool then_endif_reachable = then_type->id != TypeTableEntryIdUnreachable;
-// bool else_endif_reachable = else_type->id != TypeTableEntryIdUnreachable;
-// if (then_endif_reachable || else_endif_reachable) {
-// endif_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "EndIf");
-// }
-//
-// LLVMBuildCondBr(g->builder, cond_value, then_block, else_block);
-//
-// LLVMPositionBuilderAtEnd(g->builder, then_block);
-// LLVMValueRef then_expr_result = gen_expr(g, then_node);
-// if (then_endif_reachable) {
-// clear_debug_source_node(g);
-// LLVMBuildBr(g->builder, endif_block);
-// }
-// LLVMBasicBlockRef after_then_block = LLVMGetInsertBlock(g->builder);
-//
-// LLVMPositionBuilderAtEnd(g->builder, else_block);
-// LLVMValueRef else_expr_result = gen_expr(g, else_node);
-// if (else_endif_reachable) {
-// clear_debug_source_node(g);
-// LLVMBuildBr(g->builder, endif_block);
-// }
-// LLVMBasicBlockRef after_else_block = LLVMGetInsertBlock(g->builder);
-//
-// if (then_endif_reachable || else_endif_reachable) {
-// LLVMPositionBuilderAtEnd(g->builder, endif_block);
-// if (use_then_value && use_else_value) {
-// LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMTypeOf(then_expr_result), "");
-// LLVMValueRef incoming_values[2] = {then_expr_result, else_expr_result};
-// LLVMBasicBlockRef incoming_blocks[2] = {after_then_block, after_else_block};
-// LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2);
-// return phi;
-// } else if (use_then_value) {
-// return then_expr_result;
-// } else if (use_else_value) {
-// return else_expr_result;
-// }
-// }
-//
-// return nullptr;
-//}
-//
-//static LLVMValueRef gen_if_bool_expr(CodeGen *g, AstNode *node) {
-// assert(node->type == NodeTypeIfBoolExpr);
-// assert(node->data.if_bool_expr.condition);
-// assert(node->data.if_bool_expr.then_block);
-//
-// ConstExprValue *const_val = &get_resolved_expr(node->data.if_bool_expr.condition)->const_val;
-// if (const_val->ok) {
-// if (const_val->data.x_bool) {
-// return gen_expr(g, node->data.if_bool_expr.then_block);
-// } else if (node->data.if_bool_expr.else_node) {
-// return gen_expr(g, node->data.if_bool_expr.else_node);
-// } else {
-// return nullptr;
-// }
-// } else {
-// LLVMValueRef cond_value = gen_expr(g, node->data.if_bool_expr.condition);
-//
-// return gen_if_bool_expr_raw(g, node, cond_value,
-// node->data.if_bool_expr.then_block,
-// node->data.if_bool_expr.else_node);
-// }
-//}
-//
//static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *implicit_return_type) {
// assert(block_node->type == NodeTypeBlock);
//
@@ -8876,140 +8293,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) {
// }
//}
//
-//static LLVMValueRef gen_container_init_expr(CodeGen *g, AstNode *node) {
-// assert(node->type == NodeTypeContainerInitExpr);
-//
-// TypeTableEntry *type_entry = get_expr_type(node);
-//
-//
-// if (node->data.container_init_expr.enum_type) {
-// size_t param_count = node->data.container_init_expr.entries.length;
-// AstNode *arg1_node;
-// if (param_count == 1) {
-// arg1_node = node->data.container_init_expr.entries.at(0);
-// } else {
-// assert(param_count == 0);
-// arg1_node = nullptr;
-// }
-// return gen_enum_value_expr(g, node->data.container_init_expr.type,
-// node->data.container_init_expr.enum_type, arg1_node);
-// }
-//
-//
-// if (type_entry->id == TypeTableEntryIdStruct) {
-// assert(node->data.container_init_expr.kind == ContainerInitKindStruct);
-//
-// size_t src_field_count = type_entry->data.structure.src_field_count;
-// assert(src_field_count == node->data.container_init_expr.entries.length);
-//
-// StructValExprCodeGen *struct_val_expr_node = &node->data.container_init_expr.resolved_struct_val_expr;
-// LLVMValueRef tmp_struct_ptr = struct_val_expr_node->ptr;
-//
-// for (size_t i = 0; i < src_field_count; i += 1) {
-// AstNode *field_node = node->data.container_init_expr.entries.at(i);
-// assert(field_node->type == NodeTypeStructValueField);
-// TypeStructField *type_struct_field = field_node->data.struct_val_field.type_struct_field;
-// if (type_struct_field->type_entry->id == TypeTableEntryIdVoid) {
-// continue;
-// }
-// assert(buf_eql_buf(type_struct_field->name, field_node->data.struct_val_field.name));
-//
-// set_debug_source_node(g, field_node);
-// LLVMValueRef field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, type_struct_field->gen_index, "");
-// AstNode *expr_node = field_node->data.struct_val_field.expr;
-// LLVMValueRef value = gen_expr(g, expr_node);
-// gen_assign_raw(g, field_node, BinOpTypeAssign, field_ptr, value,
-// type_struct_field->type_entry, get_expr_type(expr_node));
-// }
-//
-// return tmp_struct_ptr;
-// } else if (type_entry->id == TypeTableEntryIdVoid) {
-// assert(node->data.container_init_expr.entries.length == 0);
-// return nullptr;
-// } else if (type_entry->id == TypeTableEntryIdArray) {
-// StructValExprCodeGen *struct_val_expr_node = &node->data.container_init_expr.resolved_struct_val_expr;
-// LLVMValueRef tmp_array_ptr = struct_val_expr_node->ptr;
-//
-// size_t field_count = type_entry->data.array.len;
-// assert(field_count == node->data.container_init_expr.entries.length);
-//
-// TypeTableEntry *child_type = type_entry->data.array.child_type;
-//
-// for (size_t i = 0; i < field_count; i += 1) {
-// AstNode *field_node = node->data.container_init_expr.entries.at(i);
-// LLVMValueRef elem_val = gen_expr(g, field_node);
-//
-// LLVMValueRef indices[] = {
-// LLVMConstNull(g->builtin_types.entry_usize->type_ref),
-// LLVMConstInt(g->builtin_types.entry_usize->type_ref, i, false),
-// };
-// set_debug_source_node(g, field_node);
-// LLVMValueRef elem_ptr = LLVMBuildInBoundsGEP(g->builder, tmp_array_ptr, indices, 2, "");
-// gen_assign_raw(g, field_node, BinOpTypeAssign, elem_ptr, elem_val,
-// child_type, get_expr_type(field_node));
-// }
-//
-// return tmp_array_ptr;
-// } else {
-// zig_unreachable();
-// }
-//}
-//
-//static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) {
-// assert(node->type == NodeTypeWhileExpr);
-// assert(node->data.while_expr.condition);
-// assert(node->data.while_expr.body);
-//
-// //AstNode *continue_expr_node = node->data.while_expr.continue_expr;
-//
-// bool condition_always_true = node->data.while_expr.condition_always_true;
-// //bool contains_break = node->data.while_expr.contains_break;
-// if (condition_always_true) {
-// // generate a forever loop
-// zig_panic("TODO IR");
-//
-// //LLVMBasicBlockRef body_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileBody");
-// //LLVMBasicBlockRef continue_block = continue_expr_node ?
-// // LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileContinue") : body_block;
-// //LLVMBasicBlockRef end_block = nullptr;
-// //if (contains_break) {
-// // end_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileEnd");
-// //}
-//
-// //set_debug_source_node(g, node);
-// //LLVMBuildBr(g->builder, body_block);
-//
-// //if (continue_expr_node) {
-// // LLVMPositionBuilderAtEnd(g->builder, continue_block);
-//
-// // gen_expr(g, continue_expr_node);
-//
-// // set_debug_source_node(g, node);
-// // LLVMBuildBr(g->builder, body_block);
-// //}
-//
-// //LLVMPositionBuilderAtEnd(g->builder, body_block);
-// //g->break_block_stack.append(end_block);
-// //g->continue_block_stack.append(continue_block);
-// //gen_expr(g, node->data.while_expr.body);
-// //g->break_block_stack.pop();
-// //g->continue_block_stack.pop();
-//
-// //if (get_expr_type(node->data.while_expr.body)->id != TypeTableEntryIdUnreachable) {
-// // set_debug_source_node(g, node);
-// // LLVMBuildBr(g->builder, continue_block);
-// //}
-//
-// //if (contains_break) {
-// // LLVMPositionBuilderAtEnd(g->builder, end_block);
-// //}
-// } else {
-// zig_panic("moved to ir.cpp");
-// }
-//
-// return nullptr;
-//}
-
//static LLVMValueRef gen_break(CodeGen *g, AstNode *node) {
// assert(node->type == NodeTypeBreak);
// LLVMBasicBlockRef dest_block = g->break_block_stack.last();
@@ -9164,44 +8447,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) {
// }
//}
//
-//static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node, bool is_lvalue) {
-// assert(node->type == NodeTypeFieldAccessExpr);
-//
-// AstNode *struct_expr = node->data.field_access_expr.struct_expr;
-// TypeTableEntry *struct_type = get_expr_type(struct_expr);
-//
-// if (struct_type->id == TypeTableEntryIdArray) {
-// Buf *name = node->data.field_access_expr.field_name;
-// assert(buf_eql_str(name, "len"));
-// return LLVMConstInt(g->builtin_types.entry_usize->type_ref,
-// struct_type->data.array.len, false);
-// } else if (struct_type->id == TypeTableEntryIdStruct || (struct_type->id == TypeTableEntryIdPointer &&
-// struct_type->data.pointer.child_type->id == TypeTableEntryIdStruct))
-// {
-// TypeTableEntry *type_entry;
-// LLVMValueRef ptr = gen_field_ptr(g, node, &type_entry);
-// if (is_lvalue || handle_is_ptr(type_entry)) {
-// return ptr;
-// } else {
-// return LLVMBuildLoad(g->builder, ptr, "");
-// }
-// } else if (struct_type->id == TypeTableEntryIdMetaType) {
-// assert(!is_lvalue);
-// TypeTableEntry *child_type = get_type_for_type_node(struct_expr);
-// if (child_type->id == TypeTableEntryIdEnum) {
-// return gen_enum_value_expr(g, node, child_type, nullptr);
-// } else {
-// zig_unreachable();
-// }
-// } else if (struct_type->id == TypeTableEntryIdNamespace) {
-// VariableTableEntry *variable = get_resolved_expr(node)->variable;
-// assert(variable);
-// return gen_variable(g, node, variable);
-// } else {
-// zig_unreachable();
-// }
-//}
-//
//static LLVMValueRef gen_return(CodeGen *g, AstNode *source_node, LLVMValueRef value, ReturnKnowledge rk) {
// BlockContext *defer_inner_block = source_node->block_context;
// BlockContext *defer_outer_block = source_node->block_context->fn_entry->fn_def_node->block_context;
src/ir_print.cpp
@@ -7,6 +7,8 @@ struct IrPrint {
int indent_size;
};
+static void ir_print_other_instruction(IrPrint *irp, IrInstruction *instruction);
+
static void ir_print_indent(IrPrint *irp) {
for (int i = 0; i < irp->indent; i += 1) {
fprintf(irp->f, " ");
@@ -35,25 +37,30 @@ static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, Const
break;
}
switch (type_entry->id) {
+ case TypeTableEntryIdTypeDecl:
+ return ir_print_const_value(irp, type_entry->data.type_decl.canonical_type, const_val);
case TypeTableEntryIdInvalid:
fprintf(irp->f, "(invalid)");
- break;
+ return;
+ case TypeTableEntryIdVar:
+ fprintf(irp->f, "(var)");
+ return;
case TypeTableEntryIdVoid:
fprintf(irp->f, "{}");
- break;
+ return;
case TypeTableEntryIdNumLitFloat:
fprintf(irp->f, "%f", const_val->data.x_bignum.data.x_float);
- break;
+ return;
case TypeTableEntryIdNumLitInt:
{
BigNum *bignum = &const_val->data.x_bignum;
const char *negative_str = bignum->is_negative ? "-" : "";
fprintf(irp->f, "%s%llu", negative_str, bignum->data.x_uint);
- break;
+ return;
}
case TypeTableEntryIdMetaType:
fprintf(irp->f, "%s", buf_ptr(&const_val->data.x_type->name));
- break;
+ return;
case TypeTableEntryIdInt:
{
BigNum *bignum = &const_val->data.x_bignum;
@@ -61,31 +68,38 @@ static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, Const
const char *negative_str = bignum->is_negative ? "-" : "";
fprintf(irp->f, "%s%llu", negative_str, bignum->data.x_uint);
}
- break;
+ return;
+ case TypeTableEntryIdFloat:
+ {
+ BigNum *bignum = &const_val->data.x_bignum;
+ assert(bignum->kind == BigNumKindFloat);
+ fprintf(irp->f, "%f", bignum->data.x_float);
+ }
+ return;
case TypeTableEntryIdUnreachable:
fprintf(irp->f, "@unreachable()");
- break;
+ return;
case TypeTableEntryIdBool:
{
const char *value = const_val->data.x_bool ? "true" : "false";
fprintf(irp->f, "%s", value);
- break;
+ return;
}
case TypeTableEntryIdPointer:
fprintf(irp->f, "&");
ir_print_const_value(irp, type_entry->data.pointer.child_type, const_ptr_pointee(const_val));
- break;
+ return;
case TypeTableEntryIdFn:
{
FnTableEntry *fn_entry = const_val->data.x_fn;
fprintf(irp->f, "%s", buf_ptr(&fn_entry->symbol_name));
- break;
+ return;
}
case TypeTableEntryIdBlock:
{
AstNode *node = const_val->data.x_block->node;
fprintf(irp->f, "(scope:%zu:%zu)", node->line + 1, node->column + 1);
- break;
+ return;
}
case TypeTableEntryIdArray:
{
@@ -99,12 +113,17 @@ static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, Const
ir_print_const_value(irp, child_type, child_value);
}
fprintf(irp->f, "}");
- break;
+ return;
}
case TypeTableEntryIdNullLit:
{
fprintf(irp->f, "null");
- break;
+ return;
+ }
+ case TypeTableEntryIdUndefLit:
+ {
+ fprintf(irp->f, "undefined");
+ return;
}
case TypeTableEntryIdMaybe:
{
@@ -113,26 +132,56 @@ static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, Const
} else {
fprintf(irp->f, "null");
}
- break;
+ return;
}
case TypeTableEntryIdNamespace:
{
ImportTableEntry *import = const_val->data.x_import;
fprintf(irp->f, "(namespace: %s)", buf_ptr(import->path));
- break;
+ return;
+ }
+ case TypeTableEntryIdGenericFn:
+ {
+ TypeTableEntry *type_entry = const_val->data.x_type;
+ AstNode *decl_node = type_entry->data.generic_fn.decl_node;
+ assert(decl_node->type == NodeTypeFnProto);
+ fprintf(irp->f, "%s", buf_ptr(decl_node->data.fn_proto.name));
+ return;
+ }
+ case TypeTableEntryIdBoundFn:
+ {
+ FnTableEntry *fn_entry = const_val->data.x_bound_fn.fn;
+ fprintf(irp->f, "bound %s to ", buf_ptr(&fn_entry->symbol_name));
+ ir_print_other_instruction(irp, const_val->data.x_bound_fn.first_arg);
+ return;
}
- case TypeTableEntryIdVar:
- case TypeTableEntryIdFloat:
case TypeTableEntryIdStruct:
- case TypeTableEntryIdUndefLit:
- case TypeTableEntryIdErrorUnion:
- case TypeTableEntryIdPureError:
+ {
+ fprintf(irp->f, "(struct %s constant)", buf_ptr(&type_entry->name));
+ return;
+ }
case TypeTableEntryIdEnum:
+ {
+ fprintf(irp->f, "(enum %s constant)", buf_ptr(&type_entry->name));
+ return;
+ }
+ case TypeTableEntryIdErrorUnion:
+ {
+ fprintf(irp->f, "(error union %s constant)", buf_ptr(&type_entry->name));
+ return;
+ }
case TypeTableEntryIdUnion:
- case TypeTableEntryIdTypeDecl:
- case TypeTableEntryIdGenericFn:
- zig_panic("TODO render more constant types in IR printer");
+ {
+ fprintf(irp->f, "(union %s constant)", buf_ptr(&type_entry->name));
+ return;
+ }
+ case TypeTableEntryIdPureError:
+ {
+ fprintf(irp->f, "(pure error constant)");
+ return;
+ }
}
+ zig_unreachable();
}
static void ir_print_const_instruction(IrPrint *irp, IrInstruction *instruction) {
@@ -285,12 +334,16 @@ static void ir_print_decl_var(IrPrint *irp, IrInstructionDeclVar *decl_var_instr
static void ir_print_cast(IrPrint *irp, IrInstructionCast *cast_instruction) {
fprintf(irp->f, "cast ");
ir_print_other_instruction(irp, cast_instruction->value);
- fprintf(irp->f, " to ");
- ir_print_other_instruction(irp, cast_instruction->dest_type);
+ fprintf(irp->f, " to %s", buf_ptr(&cast_instruction->dest_type->name));
}
static void ir_print_call(IrPrint *irp, IrInstructionCall *call_instruction) {
- ir_print_other_instruction(irp, call_instruction->fn);
+ if (call_instruction->fn_entry) {
+ fprintf(irp->f, "%s", buf_ptr(&call_instruction->fn_entry->symbol_name));
+ } else {
+ assert(call_instruction->fn_ref);
+ ir_print_other_instruction(irp, call_instruction->fn_ref);
+ }
fprintf(irp->f, "(");
for (size_t i = 0; i < call_instruction->arg_count; i += 1) {
IrInstruction *arg = call_instruction->args[i];
@@ -347,13 +400,24 @@ static void ir_print_container_init_fields(IrPrint *irp, IrInstructionContainerI
ir_print_other_instruction(irp, instruction->container_type);
fprintf(irp->f, "{");
for (size_t i = 0; i < instruction->field_count; i += 1) {
- Buf *name = instruction->field_names[i];
- IrInstruction *field_value = instruction->field_values[i];
+ IrInstructionContainerInitFieldsField *field = &instruction->fields[i];
const char *comma = (i == 0) ? "" : ", ";
- fprintf(irp->f, "%s.%s = ", comma, buf_ptr(name));
- ir_print_other_instruction(irp, field_value);
+ fprintf(irp->f, "%s.%s = ", comma, buf_ptr(field->name));
+ ir_print_other_instruction(irp, field->value);
}
- fprintf(irp->f, "}");
+ fprintf(irp->f, "} // container init");
+}
+
+static void ir_print_struct_init(IrPrint *irp, IrInstructionStructInit *instruction) {
+ fprintf(irp->f, "%s {", buf_ptr(&instruction->struct_type->name));
+ for (size_t i = 0; i < instruction->field_count; i += 1) {
+ IrInstructionStructInitField *field = &instruction->fields[i];
+ Buf *field_name = field->type_struct_field->name;
+ const char *comma = (i == 0) ? "" : ", ";
+ fprintf(irp->f, "%s.%s = ", comma, buf_ptr(field_name));
+ ir_print_other_instruction(irp, field->value);
+ }
+ fprintf(irp->f, "} // struct init");
}
static void ir_print_unreachable(IrPrint *irp, IrInstructionUnreachable *instruction) {
@@ -406,10 +470,9 @@ static void ir_print_ptr_type_child(IrPrint *irp, IrInstructionPtrTypeChild *ins
}
static void ir_print_field_ptr(IrPrint *irp, IrInstructionFieldPtr *instruction) {
- fprintf(irp->f, "@FieldPtr(&");
+ fprintf(irp->f, "fieldptr ");
ir_print_other_instruction(irp, instruction->container_ptr);
fprintf(irp->f, ".%s", buf_ptr(instruction->field_name));
- fprintf(irp->f, ")");
}
static void ir_print_struct_field_ptr(IrPrint *irp, IrInstructionStructFieldPtr *instruction) {
@@ -419,6 +482,13 @@ static void ir_print_struct_field_ptr(IrPrint *irp, IrInstructionStructFieldPtr
fprintf(irp->f, ")");
}
+static void ir_print_enum_field_ptr(IrPrint *irp, IrInstructionEnumFieldPtr *instruction) {
+ fprintf(irp->f, "@EnumFieldPtr(&");
+ ir_print_other_instruction(irp, instruction->enum_ptr);
+ fprintf(irp->f, ".%s", buf_ptr(instruction->field->name));
+ fprintf(irp->f, ")");
+}
+
static void ir_print_set_fn_test(IrPrint *irp, IrInstructionSetFnTest *instruction) {
fprintf(irp->f, "@setFnTest(");
ir_print_other_instruction(irp, instruction->fn_value);
@@ -632,6 +702,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdContainerInitFields:
ir_print_container_init_fields(irp, (IrInstructionContainerInitFields *)instruction);
break;
+ case IrInstructionIdStructInit:
+ ir_print_struct_init(irp, (IrInstructionStructInit *)instruction);
+ break;
case IrInstructionIdUnreachable:
ir_print_unreachable(irp, (IrInstructionUnreachable *)instruction);
break;
@@ -662,6 +735,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdStructFieldPtr:
ir_print_struct_field_ptr(irp, (IrInstructionStructFieldPtr *)instruction);
break;
+ case IrInstructionIdEnumFieldPtr:
+ ir_print_enum_field_ptr(irp, (IrInstructionEnumFieldPtr *)instruction);
+ break;
case IrInstructionIdSetFnTest:
ir_print_set_fn_test(irp, (IrInstructionSetFnTest *)instruction);
break;
test/self_hosted2.zig
@@ -84,6 +84,18 @@ end:
}
var goto_counter: i32 = 0;
+
+
+struct FooA {
+ fn add(a: i32, b: i32) -> i32 { a + b }
+}
+const foo_a = FooA {};
+
+fn testStructStatic() {
+ const result = FooA.add(3, 4);
+ assert(result == 7);
+}
+
fn assert(ok: bool) {
if (!ok)
@unreachable();
@@ -98,6 +110,7 @@ fn runAllTests() {
testInlineSwitch();
testNamespaceFnCall();
gotoAndLabels();
+ testStructStatic();
}
export nakedcc fn _start() -> unreachable {