diff options
Diffstat (limited to 'src/ir.cpp')
| -rw-r--r-- | src/ir.cpp | 3913 |
1 files changed, 3092 insertions, 821 deletions
diff --git a/src/ir.cpp b/src/ir.cpp index 52a016185d..96bf78bdf5 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -149,10 +149,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCall *) { return IrInstructionIdCall; } -static constexpr IrInstructionId ir_instruction_id(IrInstructionBuiltinCall *) { - return IrInstructionIdBuiltinCall; -} - static constexpr IrInstructionId ir_instruction_id(IrInstructionConst *) { return IrInstructionIdConst; } @@ -189,6 +185,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrTypeChild *) return IrInstructionIdPtrTypeChild; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionSetFnTest *) { + return IrInstructionIdSetFnTest; +} + template<typename T> static T *ir_create_instruction(IrExecutable *exec, AstNode *source_node) { T *special_instruction = allocate<T>(1); @@ -353,7 +353,7 @@ static IrInstruction *ir_build_const_scope(IrBuilder *irb, AstNode *source_node, static IrInstruction *ir_build_const_bool(IrBuilder *irb, AstNode *source_node, bool value) { IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, source_node); - const_instruction->base.type_entry = irb->codegen->builtin_types.entry_block; + const_instruction->base.type_entry = irb->codegen->builtin_types.entry_bool; const_instruction->base.static_value.ok = true; const_instruction->base.static_value.data.x_bool = value; return &const_instruction->base; @@ -505,20 +505,6 @@ static IrInstruction *ir_build_call_from(IrBuilder *irb, IrInstruction *old_inst return new_instruction; } -static IrInstruction *ir_build_builtin_call(IrBuilder *irb, AstNode *source_node, - BuiltinFnEntry *fn, IrInstruction **args) -{ - IrInstructionBuiltinCall *call_instruction = ir_build_instruction<IrInstructionBuiltinCall>(irb, source_node); - call_instruction->fn = fn; - call_instruction->args = args; - - for (size_t i = 0; i < fn->param_count; i += 1) { - ir_ref_instruction(args[i]); - } - - return &call_instruction->base; -} - static IrInstruction *ir_build_phi(IrBuilder *irb, AstNode *source_node, size_t incoming_count, IrBasicBlock **incoming_blocks, IrInstruction **incoming_values) { @@ -717,6 +703,19 @@ static IrInstruction *ir_build_ptr_type_child(IrBuilder *irb, AstNode *source_no return &instruction->base; } +static IrInstruction *ir_build_set_fn_test(IrBuilder *irb, AstNode *source_node, IrInstruction *fn_value, + IrInstruction *is_test) +{ + IrInstructionSetFnTest *instruction = ir_build_instruction<IrInstructionSetFnTest>(irb, source_node); + instruction->fn_value = fn_value; + instruction->is_test = is_test; + + ir_ref_instruction(fn_value); + ir_ref_instruction(is_test); + + return &instruction->base; +} + //static size_t get_conditional_defer_count(BlockContext *inner_block, BlockContext *outer_block) { // size_t result = 0; // while (inner_block != outer_block) { @@ -1066,10 +1065,6 @@ static IrInstruction *ir_gen_decl_ref(IrBuilder *irb, AstNode *source_node, AstN static IrInstruction *ir_gen_symbol(IrBuilder *irb, AstNode *node, LValPurpose lval) { assert(node->type == NodeTypeSymbol); - if (node->data.symbol_expr.override_type_entry) { - zig_panic("TODO have parseh directly generate IR"); - } - Buf *variable_name = node->data.symbol_expr.symbol; auto primitive_table_entry = irb->codegen->primitive_type_table.maybe_get(variable_name); @@ -1163,26 +1158,71 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, AstNode *node) { builtin_fn->ref_count += 1; - if (builtin_fn->id == BuiltinFnIdUnreachable) { - return ir_build_unreachable(irb, node); - } else if (builtin_fn->id == BuiltinFnIdTypeof) { - AstNode *arg_node = node->data.fn_call_expr.params.at(0); - IrInstruction *arg = ir_gen_node(irb, arg_node, node->block_context); - if (arg == irb->codegen->invalid_instruction) - return arg; - return ir_build_typeof(irb, node, arg); - } + switch (builtin_fn->id) { + case BuiltinFnIdInvalid: + zig_unreachable(); + case BuiltinFnIdUnreachable: + return ir_build_unreachable(irb, node); + case BuiltinFnIdTypeof: + { + AstNode *arg_node = node->data.fn_call_expr.params.at(0); + IrInstruction *arg = ir_gen_node(irb, arg_node, node->block_context); + if (arg == irb->codegen->invalid_instruction) + return arg; + return ir_build_typeof(irb, node, arg); + } + case BuiltinFnIdSetFnTest: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, node->block_context); + if (arg0_value == irb->codegen->invalid_instruction) + return arg0_value; - IrInstruction **args = allocate<IrInstruction *>(actual_param_count); - for (size_t i = 0; i < actual_param_count; i += 1) { - AstNode *arg_node = node->data.fn_call_expr.params.at(i); - IrInstruction *arg = ir_gen_node(irb, arg_node, node->block_context); - if (arg == irb->codegen->invalid_instruction) - return arg; - args[i] = arg; - } + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, node->block_context); + if (arg1_value == irb->codegen->invalid_instruction) + return arg1_value; - return ir_build_builtin_call(irb, node, builtin_fn, args); + return ir_build_set_fn_test(irb, node, arg0_value, arg1_value); + } + case BuiltinFnIdMemcpy: + case BuiltinFnIdMemset: + case BuiltinFnIdSizeof: + case BuiltinFnIdAlignof: + case BuiltinFnIdMaxValue: + case BuiltinFnIdMinValue: + case BuiltinFnIdMemberCount: + case BuiltinFnIdAddWithOverflow: + case BuiltinFnIdSubWithOverflow: + case BuiltinFnIdMulWithOverflow: + case BuiltinFnIdShlWithOverflow: + case BuiltinFnIdCInclude: + case BuiltinFnIdCDefine: + case BuiltinFnIdCUndef: + case BuiltinFnIdCompileVar: + case BuiltinFnIdCompileErr: + case BuiltinFnIdConstEval: + case BuiltinFnIdCtz: + case BuiltinFnIdClz: + case BuiltinFnIdImport: + case BuiltinFnIdCImport: + case BuiltinFnIdErrName: + case BuiltinFnIdBreakpoint: + case BuiltinFnIdReturnAddress: + case BuiltinFnIdFrameAddress: + case BuiltinFnIdEmbedFile: + case BuiltinFnIdCmpExchange: + case BuiltinFnIdFence: + case BuiltinFnIdDivExact: + case BuiltinFnIdTruncate: + case BuiltinFnIdIntType: + case BuiltinFnIdSetFnVisible: + case BuiltinFnIdSetFnStaticEval: + case BuiltinFnIdSetFnNoInline: + case BuiltinFnIdSetDebugSafety: + zig_panic("TODO IR gen more builtin functions"); + } + zig_unreachable(); } static IrInstruction *ir_gen_fn_call(IrBuilder *irb, AstNode *node) { @@ -2044,6 +2084,53 @@ static TypeTableEntry *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value return const_val->data.x_type; } +static bool ir_resolve_bool(IrAnalyze *ira, IrInstruction *bool_value, bool *out) { + if (bool_value == ira->codegen->invalid_instruction) + return false; + + if (bool_value->type_entry->id == TypeTableEntryIdInvalid) + return false; + + if (bool_value->type_entry->id != TypeTableEntryIdBool) { + add_node_error(ira->codegen, bool_value->source_node, + buf_sprintf("expected type 'bool', found '%s'", buf_ptr(&bool_value->type_entry->name))); + return false; + } + + ConstExprValue *const_val = &bool_value->static_value; + if (!const_val->ok) { + add_node_error(ira->codegen, bool_value->source_node, + buf_sprintf("unable to evaluate constant expression")); + return false; + } + + *out = const_val->data.x_bool; + return true; +} + +static FnTableEntry *ir_resolve_fn(IrAnalyze *ira, IrInstruction *fn_value) { + if (fn_value == ira->codegen->invalid_instruction) + return nullptr; + + if (fn_value->type_entry->id == TypeTableEntryIdInvalid) + return nullptr; + + if (fn_value->type_entry->id != TypeTableEntryIdFn) { + add_node_error(ira->codegen, fn_value->source_node, + buf_sprintf("expected function type, found '%s'", buf_ptr(&fn_value->type_entry->name))); + return nullptr; + } + + ConstExprValue *const_val = &fn_value->static_value; + if (!const_val->ok) { + add_node_error(ira->codegen, fn_value->source_node, + buf_sprintf("unable to evaluate constant expression")); + return nullptr; + } + + return const_val->data.x_fn; +} + static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *dest_type, IrInstruction *value) { @@ -2837,11 +2924,18 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction } 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; + casted_args[i] = ir_get_casted_value(ira, old_arg, param_type); + } ir_build_call_from(&ira->new_irb, &call_instruction->base, - call_instruction->fn, call_instruction->arg_count, call_instruction->args); + call_instruction->fn, call_instruction->arg_count, casted_args); - TypeTableEntry *fn_type = fn_table_entry->type_entry; TypeTableEntry *return_type = fn_type->data.fn.fn_type_id.return_type; return return_type; } else { @@ -3075,6 +3169,696 @@ static TypeTableEntry *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstructio zig_unreachable(); } +static TypeTableEntry *ir_analyze_instruction_br(IrAnalyze *ira, IrInstructionBr *br_instruction) { + IrBasicBlock *old_dest_block = br_instruction->dest_block; + + // TODO detect backward jumps + + if (br_instruction->is_inline || old_dest_block->ref_count == 1) { + ir_inline_bb(ira, old_dest_block); + return ira->codegen->builtin_types.entry_unreachable; + } + + IrBasicBlock *new_bb = ir_get_new_bb(ira, old_dest_block); + ir_build_br_from(&ira->new_irb, &br_instruction->base, new_bb); + ir_finish_bb(ira); + return ira->codegen->builtin_types.entry_unreachable; +} + +static TypeTableEntry *ir_analyze_instruction_cond_br(IrAnalyze *ira, IrInstructionCondBr *cond_br_instruction) { + TypeTableEntry *bool_type = ira->codegen->builtin_types.entry_bool; + IrInstruction *condition = ir_get_casted_value(ira, cond_br_instruction->condition->other, bool_type); + if (condition == ira->codegen->invalid_instruction) { + ir_finish_bb(ira); + return ira->codegen->builtin_types.entry_unreachable; + } + + // TODO detect backward jumps + if (condition->static_value.ok) { + IrBasicBlock *old_dest_block = condition->static_value.data.x_bool ? + cond_br_instruction->then_block : cond_br_instruction->else_block; + + if (cond_br_instruction->is_inline || old_dest_block->ref_count == 1) { + ir_inline_bb(ira, old_dest_block); + return ira->codegen->builtin_types.entry_unreachable; + } + } else if (cond_br_instruction->is_inline) { + add_node_error(ira->codegen, condition->source_node, + buf_sprintf("unable to evaluate constant expression")); + ir_finish_bb(ira); + return ira->codegen->builtin_types.entry_unreachable; + } + + IrBasicBlock *new_then_block = ir_get_new_bb(ira, cond_br_instruction->then_block); + IrBasicBlock *new_else_block = ir_get_new_bb(ira, cond_br_instruction->else_block); + ir_build_cond_br_from(&ira->new_irb, &cond_br_instruction->base, condition, new_then_block, new_else_block, false); + ir_finish_bb(ira); + return ira->codegen->builtin_types.entry_unreachable; +} + +static TypeTableEntry *ir_analyze_instruction_unreachable(IrAnalyze *ira, + IrInstructionUnreachable *unreachable_instruction) +{ + ir_build_unreachable_from(&ira->new_irb, &unreachable_instruction->base); + ir_finish_bb(ira); + return ira->codegen->builtin_types.entry_unreachable; +} + +static TypeTableEntry *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionPhi *phi_instruction) { + if (ira->const_predecessor_bb) { + for (size_t i = 0; i < phi_instruction->incoming_count; i += 1) { + IrBasicBlock *predecessor = phi_instruction->incoming_blocks[i]; + if (predecessor != ira->const_predecessor_bb) + continue; + IrInstruction *value = phi_instruction->incoming_values[i]->other; + assert(value->type_entry); + if (value->static_value.ok) { + ConstExprValue *out_val = ir_build_const_from(ira, &phi_instruction->base, + value->static_value.depends_on_compile_var); + *out_val = value->static_value; + } else { + phi_instruction->base.other = value; + } + return value->type_entry; + } + zig_unreachable(); + } + + ZigList<IrBasicBlock*> new_incoming_blocks = {0}; + ZigList<IrInstruction*> new_incoming_values = {0}; + + for (size_t i = 0; i < phi_instruction->incoming_count; i += 1) { + IrBasicBlock *predecessor = phi_instruction->incoming_blocks[i]; + if (predecessor->ref_count == 0) + continue; + + assert(predecessor->other); + new_incoming_blocks.append(predecessor->other); + + IrInstruction *old_value = phi_instruction->incoming_values[i]; + assert(old_value); + new_incoming_values.append(old_value->other); + } + assert(new_incoming_blocks.length != 0); + + if (new_incoming_blocks.length == 1) { + IrInstruction *first_value = new_incoming_values.at(0); + phi_instruction->base.other = first_value; + return first_value->type_entry; + } + + TypeTableEntry *resolved_type = ir_resolve_peer_types(ira, phi_instruction->base.source_node, + new_incoming_values.items, new_incoming_values.length); + if (resolved_type->id == TypeTableEntryIdInvalid) + return resolved_type; + + ir_build_phi_from(&ira->new_irb, &phi_instruction->base, new_incoming_blocks.length, + new_incoming_blocks.items, new_incoming_values.items); + return resolved_type; +} + +static TypeTableEntry *ir_analyze_instruction_var_ptr(IrAnalyze *ira, IrInstructionVarPtr *var_ptr_instruction) { + VariableTableEntry *var = var_ptr_instruction->var; + if (var->type->id == TypeTableEntryIdInvalid) + return var->type; + + TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, var->type, false); + // TODO once the anlayze code is fully ported over to IR we won't need this SIZE_MAX thing. + if (var->mem_slot_index != SIZE_MAX) { + ConstExprValue *mem_slot = &ira->exec_context.mem_slot_list[var->mem_slot_index]; + if (mem_slot->ok) { + ConstExprValue *out_val = ir_build_const_from(ira, &var_ptr_instruction->base, + mem_slot->depends_on_compile_var); + + out_val->data.x_ptr.len = 1; + out_val->data.x_ptr.is_c_str = false; + out_val->data.x_ptr.ptr = allocate<ConstExprValue *>(1); + out_val->data.x_ptr.ptr[0] = mem_slot; + return ptr_type; + } + } + + ir_build_var_ptr_from(&ira->new_irb, &var_ptr_instruction->base, var); + return ptr_type; +} + +static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstructionElemPtr *elem_ptr_instruction) { + IrInstruction *array_ptr = elem_ptr_instruction->array_ptr->other; + IrInstruction *elem_index = elem_ptr_instruction->elem_index->other; + + TypeTableEntry *array_type = array_ptr->type_entry; + TypeTableEntry *return_type; + + if (array_type->id == TypeTableEntryIdInvalid) { + return array_type; + } else if (array_type->id == TypeTableEntryIdArray) { + if (array_type->data.array.len == 0) { + add_node_error(ira->codegen, elem_ptr_instruction->base.source_node, + buf_sprintf("out of bounds array access")); + } + TypeTableEntry *child_type = array_type->data.array.child_type; + return_type = get_pointer_to_type(ira->codegen, child_type, false); + } else if (array_type->id == TypeTableEntryIdPointer) { + return_type = array_type; + } else if (is_slice(array_type)) { + return_type = array_type->data.structure.fields[0].type_entry; + } else { + add_node_error(ira->codegen, elem_ptr_instruction->base.source_node, + buf_sprintf("array access of non-array type '%s'", buf_ptr(&array_type->name))); + return ira->codegen->builtin_types.entry_invalid; + } + + TypeTableEntry *usize = ira->codegen->builtin_types.entry_usize; + IrInstruction *casted_elem_index = ir_get_casted_value(ira, elem_index, usize); + if (casted_elem_index == ira->codegen->invalid_instruction) + return ira->codegen->builtin_types.entry_invalid; + + if (array_ptr->static_value.ok && casted_elem_index->static_value.ok) { + zig_panic("TODO compile time array access"); + } + + ir_build_elem_ptr_from(&ira->new_irb, &elem_ptr_instruction->base, array_ptr, casted_elem_index); + + return return_type; +} + +static TypeTableEntry *ir_analyze_container_member_access_inner(IrAnalyze *ira, + TypeTableEntry *bare_struct_type, Buf *field_name, IrInstructionFieldPtr *field_ptr_instruction, + TypeTableEntry *container_type) +{ + 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) { + zig_panic("TODO member function call"); + } + } + add_node_error(ira->codegen, field_ptr_instruction->base.source_node, + buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name), buf_ptr(&bare_struct_type->name))); + return ira->codegen->builtin_types.entry_invalid; +} + + +static TypeTableEntry *ir_analyze_container_member_access(IrAnalyze *ira, Buf *field_name, + IrInstructionFieldPtr *field_ptr_instruction, 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)) { + resolve_container_type(ira->codegen, bare_type); + } + + if (bare_type->id == TypeTableEntryIdStruct) { + TypeStructField *field = find_struct_type_field(bare_type, field_name); + if (field) { + ir_build_struct_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_type); + } + } else if (bare_type->id == TypeTableEntryIdEnum) { + zig_panic("TODO enum field ptr"); + } else if (bare_type->id == TypeTableEntryIdUnion) { + zig_panic("TODO"); + } else { + zig_unreachable(); + } +} + +static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstructionFieldPtr *field_ptr_instruction) { + IrInstruction *container_ptr = field_ptr_instruction->container_ptr->other; + Buf *field_name = field_ptr_instruction->field_name; + + TypeTableEntry *container_type = container_ptr->type_entry; + 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); + } else if (container_type->id == TypeTableEntryIdArray) { + if (buf_eql_str(field_name, "len")) { + add_node_error(ira->codegen, field_ptr_instruction->base.source_node, + buf_sprintf("pointer to array length not available")); + return ira->codegen->builtin_types.entry_invalid; + } else { + add_node_error(ira->codegen, field_ptr_instruction->base.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; + } + } else if (container_type->id == TypeTableEntryIdMetaType) { + 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, field_ptr_instruction->base.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) { + zig_panic("TODO namespace field access"); + } else { + add_node_error(ira->codegen, field_ptr_instruction->base.source_node, + buf_sprintf("type '%s' does not support field access", buf_ptr(&container_type->name))); + return ira->codegen->builtin_types.entry_invalid; + } +} + +static TypeTableEntry *ir_analyze_read_field_as_ptr_load(IrAnalyze *ira, + IrInstructionReadField *read_field_instruction) +{ + IrInstruction *old_field_ptr_inst = ir_build_field_ptr(&ira->old_irb, read_field_instruction->base.source_node, + read_field_instruction->container_ptr, read_field_instruction->field_name); + IrInstruction *old_load_ptr_inst = ir_build_load_ptr(&ira->old_irb, read_field_instruction->base.source_node, + old_field_ptr_inst); + ir_analyze_instruction(ira, old_field_ptr_inst); + TypeTableEntry *result_type = ir_analyze_instruction(ira, old_load_ptr_inst); + read_field_instruction->base.other = old_load_ptr_inst->other; + return result_type; +} + +static TypeTableEntry *ir_analyze_instruction_read_field(IrAnalyze *ira, + IrInstructionReadField *read_field_instruction) +{ + IrInstruction *container_ptr = read_field_instruction->container_ptr->other; + Buf *field_name = read_field_instruction->field_name; + + TypeTableEntry *container_type = container_ptr->type_entry; + if (container_type->id == TypeTableEntryIdInvalid) { + return container_type; + } else if (is_container_ref(container_type)) { + return ir_analyze_read_field_as_ptr_load(ira, read_field_instruction); + } else if (container_type->id == TypeTableEntryIdArray) { + if (buf_eql_str(field_name, "len")) { + return ir_analyze_const_usize(ira, &read_field_instruction->base, container_type->data.array.len, false); + } else { + add_node_error(ira->codegen, read_field_instruction->base.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; + } + } else if (container_type->id == TypeTableEntryIdMetaType) { + 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, read_field_instruction->base.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) { + zig_panic("TODO namespace field access"); + } else { + add_node_error(ira->codegen, read_field_instruction->base.source_node, + buf_sprintf("type '%s' does not support field access", buf_ptr(&container_type->name))); + return ira->codegen->builtin_types.entry_invalid; + } +} + +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.ok) { + ConstExprValue *pointee = ptr->static_value.data.x_ptr.ptr[0]; + if (pointee->ok) { + 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("indirection requires pointer operand ('%s' invalid)", + buf_ptr(&type_entry->name))); + return ira->codegen->builtin_types.entry_invalid; + } +} + +static TypeTableEntry *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstructionStorePtr *store_ptr_instruction) { + IrInstruction *ptr = store_ptr_instruction->ptr->other; + if (ptr->type_entry->id == TypeTableEntryIdInvalid) + return ptr->type_entry; + + IrInstruction *value = store_ptr_instruction->value->other; + if (value->type_entry->id == TypeTableEntryIdInvalid) + return value->type_entry; + + TypeTableEntry *child_type = ptr->type_entry->data.pointer.child_type; + IrInstruction *casted_value = ir_get_casted_value(ira, value, child_type); + if (casted_value == ira->codegen->invalid_instruction) + return ira->codegen->builtin_types.entry_invalid; + + if (ptr->static_value.ok && casted_value->static_value.ok) { + ConstExprValue *dest_val = ptr->static_value.data.x_ptr.ptr[0]; + if (dest_val->ok) { + *dest_val = casted_value->static_value; + return ir_analyze_void(ira, &store_ptr_instruction->base); + } + } + + if (ptr->static_value.ok) { + // This memory location is transforming from known at compile time to known at runtime. + // We must emit our own var ptr instruction. + ptr->static_value.ok = false; + IrInstruction *new_ptr_inst; + if (ptr->id == IrInstructionIdVarPtr) { + IrInstructionVarPtr *var_ptr_inst = (IrInstructionVarPtr *)ptr; + VariableTableEntry *var = var_ptr_inst->var; + new_ptr_inst = ir_build_var_ptr(&ira->new_irb, store_ptr_instruction->base.source_node, var); + assert(var->mem_slot_index != SIZE_MAX); + ConstExprValue *mem_slot = &ira->exec_context.mem_slot_list[var->mem_slot_index]; + mem_slot->ok = false; + } else if (ptr->id == IrInstructionIdFieldPtr) { + zig_panic("TODO"); + } else if (ptr->id == IrInstructionIdElemPtr) { + zig_panic("TODO"); + } else { + zig_unreachable(); + } + new_ptr_inst->type_entry = ptr->type_entry; + ir_build_store_ptr(&ira->new_irb, store_ptr_instruction->base.source_node, new_ptr_inst, casted_value); + return ir_analyze_void(ira, &store_ptr_instruction->base); + } + + ir_build_store_ptr_from(&ira->new_irb, &store_ptr_instruction->base, ptr, casted_value); + return ira->codegen->builtin_types.entry_void; +} + +static TypeTableEntry *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructionTypeOf *typeof_instruction) { + IrInstruction *expr_value = typeof_instruction->value->other; + TypeTableEntry *type_entry = expr_value->type_entry; + switch (type_entry->id) { + case TypeTableEntryIdInvalid: + return type_entry; + case TypeTableEntryIdVar: + add_node_error(ira->codegen, expr_value->source_node, + buf_sprintf("type '%s' not eligible for @typeOf", buf_ptr(&type_entry->name))); + return ira->codegen->builtin_types.entry_invalid; + case TypeTableEntryIdNumLitFloat: + case TypeTableEntryIdNumLitInt: + case TypeTableEntryIdUndefLit: + case TypeTableEntryIdNullLit: + case TypeTableEntryIdNamespace: + case TypeTableEntryIdBlock: + case TypeTableEntryIdGenericFn: + case TypeTableEntryIdMetaType: + case TypeTableEntryIdVoid: + case TypeTableEntryIdBool: + case TypeTableEntryIdUnreachable: + case TypeTableEntryIdInt: + case TypeTableEntryIdFloat: + case TypeTableEntryIdPointer: + case TypeTableEntryIdArray: + case TypeTableEntryIdStruct: + case TypeTableEntryIdMaybe: + case TypeTableEntryIdErrorUnion: + case TypeTableEntryIdPureError: + case TypeTableEntryIdEnum: + case TypeTableEntryIdUnion: + case TypeTableEntryIdFn: + case TypeTableEntryIdTypeDecl: + { + ConstExprValue *out_val = ir_build_const_from(ira, &typeof_instruction->base, false); + // TODO depends_on_compile_var should be set based on whether the type of the expression + // depends_on_compile_var. but we currently don't have a thing to tell us if the type of + // something depends on a compile var + out_val->data.x_type = type_entry; + + return ira->codegen->builtin_types.entry_type; + } + } + + zig_unreachable(); +} + +static TypeTableEntry *ir_analyze_instruction_to_ptr_type(IrAnalyze *ira, + IrInstructionToPtrType *to_ptr_type_instruction) +{ + IrInstruction *type_value = to_ptr_type_instruction->value->other; + TypeTableEntry *type_entry = ir_resolve_type(ira, type_value); + if (type_entry->id == TypeTableEntryIdInvalid) + return type_entry; + + TypeTableEntry *ptr_type; + if (type_entry->id == TypeTableEntryIdArray) { + ptr_type = get_pointer_to_type(ira->codegen, type_entry->data.array.child_type, false); + } else if (is_slice(type_entry)) { + ptr_type = type_entry->data.structure.fields[0].type_entry; + } else { + add_node_error(ira->codegen, to_ptr_type_instruction->base.source_node, + buf_sprintf("expected array type, found '%s'", buf_ptr(&type_entry->name))); + return ira->codegen->builtin_types.entry_invalid; + } + + ConstExprValue *out_val = ir_build_const_from(ira, &to_ptr_type_instruction->base, + type_value->static_value.depends_on_compile_var); + out_val->data.x_type = ptr_type; + return ira->codegen->builtin_types.entry_type; +} + +static TypeTableEntry *ir_analyze_instruction_ptr_type_child(IrAnalyze *ira, + IrInstructionPtrTypeChild *ptr_type_child_instruction) +{ + IrInstruction *type_value = ptr_type_child_instruction->value->other; + TypeTableEntry *type_entry = ir_resolve_type(ira, type_value); + if (type_entry->id == TypeTableEntryIdInvalid) + return type_entry; + + if (type_entry->id != TypeTableEntryIdPointer) { + add_node_error(ira->codegen, ptr_type_child_instruction->base.source_node, + buf_sprintf("expected pointer type, found '%s'", buf_ptr(&type_entry->name))); + return ira->codegen->builtin_types.entry_invalid; + } + + ConstExprValue *out_val = ir_build_const_from(ira, &ptr_type_child_instruction->base, + type_value->static_value.depends_on_compile_var); + out_val->data.x_type = type_entry->data.pointer.child_type; + return ira->codegen->builtin_types.entry_type; +} + +static TypeTableEntry *ir_analyze_instruction_set_fn_test(IrAnalyze *ira, + IrInstructionSetFnTest *set_fn_test_instruction) +{ + IrInstruction *fn_value = set_fn_test_instruction->fn_value->other; + IrInstruction *is_test_value = set_fn_test_instruction->is_test->other; + + FnTableEntry *fn_entry = ir_resolve_fn(ira, fn_value); + if (!fn_entry) + return ira->codegen->builtin_types.entry_invalid; + + if (!ir_resolve_bool(ira, is_test_value, &fn_entry->is_test)) + return ira->codegen->builtin_types.entry_invalid; + + AstNode *source_node = set_fn_test_instruction->base.source_node; + if (fn_entry->fn_test_set_node) { + ErrorMsg *msg = add_node_error(ira->codegen, source_node, + buf_sprintf("function test attribute set twice")); + add_error_note(ira->codegen, msg, fn_entry->fn_test_set_node, buf_sprintf("first set here")); + return ira->codegen->builtin_types.entry_invalid; + } + fn_entry->fn_test_set_node = source_node; + + ira->codegen->test_fn_count += 1; + + ir_build_const_from(ira, &set_fn_test_instruction->base, false); + return ira->codegen->builtin_types.entry_void; +} + +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 IrInstructionIdReadField: + return ir_analyze_instruction_read_field(ira, (IrInstructionReadField *)instruction); + case IrInstructionIdCall: + return ir_analyze_instruction_call(ira, (IrInstructionCall *)instruction); + case IrInstructionIdBr: + return ir_analyze_instruction_br(ira, (IrInstructionBr *)instruction); + case IrInstructionIdCondBr: + return ir_analyze_instruction_cond_br(ira, (IrInstructionCondBr *)instruction); + case IrInstructionIdUnreachable: + return ir_analyze_instruction_unreachable(ira, (IrInstructionUnreachable *)instruction); + case IrInstructionIdPhi: + return ir_analyze_instruction_phi(ira, (IrInstructionPhi *)instruction); + case IrInstructionIdTypeOf: + return ir_analyze_instruction_typeof(ira, (IrInstructionTypeOf *)instruction); + case IrInstructionIdToPtrType: + return ir_analyze_instruction_to_ptr_type(ira, (IrInstructionToPtrType *)instruction); + case IrInstructionIdPtrTypeChild: + return ir_analyze_instruction_ptr_type_child(ira, (IrInstructionPtrTypeChild *)instruction); + case IrInstructionIdSetFnTest: + return ir_analyze_instruction_set_fn_test(ira, (IrInstructionSetFnTest *)instruction); + case IrInstructionIdSwitchBr: + case IrInstructionIdCast: + case IrInstructionIdContainerInitList: + case IrInstructionIdContainerInitFields: + case IrInstructionIdStructFieldPtr: + zig_panic("TODO analyze more instructions"); + } + zig_unreachable(); +} + +static TypeTableEntry *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction) { + TypeTableEntry *instruction_type = ir_analyze_instruction_nocast(ira, instruction); + instruction->type_entry = instruction_type; + if (instruction->other) { + instruction->other->type_entry = instruction_type; + } else { + assert(instruction_type->id == TypeTableEntryIdInvalid || + instruction_type->id == TypeTableEntryIdUnreachable); + instruction->other = instruction; + } + return instruction_type; +} + +// This function attempts to evaluate IR code while doing type checking and other analysis. +// It emits a new IrExecutable which is partially evaluated IR code. +TypeTableEntry *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_exec, + TypeTableEntry *expected_type, AstNode *expected_type_source_node) +{ + IrAnalyze ir_analyze_data = {}; + IrAnalyze *ira = &ir_analyze_data; + ira->codegen = codegen; + ira->explicit_return_type = expected_type; + + ira->old_irb.codegen = codegen; + ira->old_irb.exec = old_exec; + + ira->new_irb.codegen = codegen; + ira->new_irb.exec = new_exec; + + ira->exec_context.mem_slot_count = ira->old_irb.exec->mem_slot_count; + ira->exec_context.mem_slot_list = allocate<ConstExprValue>(ira->exec_context.mem_slot_count); + + IrBasicBlock *old_entry_bb = ira->old_irb.exec->basic_block_list.at(0); + IrBasicBlock *new_entry_bb = ir_get_new_bb(ira, old_entry_bb); + ir_ref_bb(new_entry_bb); + ira->old_irb.current_basic_block = old_entry_bb; + ira->new_irb.current_basic_block = new_entry_bb; + ira->block_queue_index = 0; + ira->instruction_index = 0; + + while (ira->block_queue_index < ira->old_bb_queue.length) { + IrInstruction *old_instruction = ira->old_irb.current_basic_block->instruction_list.at(ira->instruction_index); + + if (old_instruction->ref_count == 0 && !ir_has_side_effects(old_instruction)) { + ira->instruction_index += 1; + continue; + } + + TypeTableEntry *return_type = ir_analyze_instruction(ira, old_instruction); + + // unreachable instructions do their own control flow. + if (return_type->id == TypeTableEntryIdUnreachable) + continue; + + ira->instruction_index += 1; + } + + return ir_resolve_peer_types(ira, expected_type_source_node, ira->implicit_return_type_list.items, + ira->implicit_return_type_list.length); +} + +bool ir_has_side_effects(IrInstruction *instruction) { + switch (instruction->id) { + case IrInstructionIdInvalid: + zig_unreachable(); + case IrInstructionIdBr: + case IrInstructionIdCondBr: + case IrInstructionIdSwitchBr: + case IrInstructionIdDeclVar: + case IrInstructionIdStorePtr: + case IrInstructionIdCall: + case IrInstructionIdReturn: + case IrInstructionIdUnreachable: + case IrInstructionIdSetFnTest: + return true; + case IrInstructionIdPhi: + case IrInstructionIdUnOp: + case IrInstructionIdBinOp: + case IrInstructionIdLoadPtr: + case IrInstructionIdConst: + case IrInstructionIdCast: + case IrInstructionIdContainerInitList: + case IrInstructionIdContainerInitFields: + case IrInstructionIdFieldPtr: + case IrInstructionIdElemPtr: + case IrInstructionIdVarPtr: + case IrInstructionIdTypeOf: + case IrInstructionIdToPtrType: + case IrInstructionIdPtrTypeChild: + case IrInstructionIdReadField: + case IrInstructionIdStructFieldPtr: + return false; + } + zig_unreachable(); +} + +IrInstruction *ir_exec_const_result(IrExecutable *exec) { + if (exec->basic_block_list.length != 1) + return nullptr; + + IrBasicBlock *bb = exec->basic_block_list.at(0); + if (bb->instruction_list.length != 1) + return nullptr; + + IrInstruction *only_inst = bb->instruction_list.at(0); + if (only_inst->id != IrInstructionIdReturn) + return nullptr; + + IrInstructionReturn *ret_inst = (IrInstructionReturn *)only_inst; + IrInstruction *value = ret_inst->value; + assert(value->static_value.ok); + return value; +} + //static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *import, BlockContext *context, // AstNode *node, const char *err_format, bool is_max) //{ @@ -3510,33 +4294,6 @@ static TypeTableEntry *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstructio // //} // -//static TypeTableEntry *analyze_set_fn_test(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 ok = resolve_const_expr_bool(g, import, context, value_node, &fn_entry->is_test); -// if (!ok) { -// return g->builtin_types.entry_invalid; -// } -// -// if (fn_entry->fn_test_set_node) { -// ErrorMsg *msg = add_node_error(g, node, buf_sprintf("function test attribute set twice")); -// add_error_note(g, msg, fn_entry->fn_test_set_node, buf_sprintf("first set here")); -// return g->builtin_types.entry_invalid; -// } -// fn_entry->fn_test_set_node = node; -// -// g->test_fn_count += 1; -// return g->builtin_types.entry_void; -//} -// //static TypeTableEntry *analyze_set_fn_no_inline(CodeGen *g, ImportTableEntry *import, // BlockContext *context, AstNode *node) //{ @@ -4188,762 +4945,2276 @@ static TypeTableEntry *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstructio // } //} -static TypeTableEntry *ir_analyze_instruction_br(IrAnalyze *ira, IrInstructionBr *br_instruction) { - IrBasicBlock *old_dest_block = br_instruction->dest_block; - - // TODO detect backward jumps - - if (br_instruction->is_inline || old_dest_block->ref_count == 1) { - ir_inline_bb(ira, old_dest_block); - return ira->codegen->builtin_types.entry_unreachable; - } - - IrBasicBlock *new_bb = ir_get_new_bb(ira, old_dest_block); - ir_build_br_from(&ira->new_irb, &br_instruction->base, new_bb); - ir_finish_bb(ira); - return ira->codegen->builtin_types.entry_unreachable; -} - -static TypeTableEntry *ir_analyze_instruction_cond_br(IrAnalyze *ira, IrInstructionCondBr *cond_br_instruction) { - TypeTableEntry *bool_type = ira->codegen->builtin_types.entry_bool; - IrInstruction *condition = ir_get_casted_value(ira, cond_br_instruction->condition->other, bool_type); - if (condition == ira->codegen->invalid_instruction) { - ir_finish_bb(ira); - return ira->codegen->builtin_types.entry_unreachable; - } - - // TODO detect backward jumps - if (condition->static_value.ok) { - IrBasicBlock *old_dest_block = condition->static_value.data.x_bool ? - cond_br_instruction->then_block : cond_br_instruction->else_block; - - if (cond_br_instruction->is_inline || old_dest_block->ref_count == 1) { - ir_inline_bb(ira, old_dest_block); - return ira->codegen->builtin_types.entry_unreachable; - } - } else if (cond_br_instruction->is_inline) { - add_node_error(ira->codegen, condition->source_node, - buf_sprintf("unable to evaluate constant expression")); - ir_finish_bb(ira); - return ira->codegen->builtin_types.entry_unreachable; - } - - IrBasicBlock *new_then_block = ir_get_new_bb(ira, cond_br_instruction->then_block); - IrBasicBlock *new_else_block = ir_get_new_bb(ira, cond_br_instruction->else_block); - ir_build_cond_br_from(&ira->new_irb, &cond_br_instruction->base, condition, new_then_block, new_else_block, false); - ir_finish_bb(ira); - return ira->codegen->builtin_types.entry_unreachable; -} - -static TypeTableEntry *ir_analyze_instruction_builtin_call(IrAnalyze *ira, - IrInstructionBuiltinCall *builtin_call_instruction) -{ - switch (builtin_call_instruction->fn->id) { - case BuiltinFnIdInvalid: - case BuiltinFnIdUnreachable: - case BuiltinFnIdTypeof: - zig_unreachable(); - case BuiltinFnIdMemcpy: - case BuiltinFnIdMemset: - case BuiltinFnIdSizeof: - case BuiltinFnIdAlignof: - case BuiltinFnIdMaxValue: - case BuiltinFnIdMinValue: - case BuiltinFnIdMemberCount: - case BuiltinFnIdAddWithOverflow: - case BuiltinFnIdSubWithOverflow: - case BuiltinFnIdMulWithOverflow: - case BuiltinFnIdShlWithOverflow: - case BuiltinFnIdCInclude: - case BuiltinFnIdCDefine: - case BuiltinFnIdCUndef: - case BuiltinFnIdCompileVar: - case BuiltinFnIdCompileErr: - case BuiltinFnIdConstEval: - case BuiltinFnIdCtz: - case BuiltinFnIdClz: - case BuiltinFnIdImport: - case BuiltinFnIdCImport: - case BuiltinFnIdErrName: - case BuiltinFnIdBreakpoint: - case BuiltinFnIdReturnAddress: - case BuiltinFnIdFrameAddress: - case BuiltinFnIdEmbedFile: - case BuiltinFnIdCmpExchange: - case BuiltinFnIdFence: - case BuiltinFnIdDivExact: - case BuiltinFnIdTruncate: - case BuiltinFnIdIntType: - case BuiltinFnIdSetFnTest: - case BuiltinFnIdSetFnVisible: - case BuiltinFnIdSetFnStaticEval: - case BuiltinFnIdSetFnNoInline: - case BuiltinFnIdSetDebugSafety: - zig_panic("TODO analyze more builtin functions"); - } - zig_unreachable(); -} - -static TypeTableEntry *ir_analyze_instruction_unreachable(IrAnalyze *ira, - IrInstructionUnreachable *unreachable_instruction) -{ - ir_build_unreachable_from(&ira->new_irb, &unreachable_instruction->base); - ir_finish_bb(ira); - return ira->codegen->builtin_types.entry_unreachable; -} - -static TypeTableEntry *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionPhi *phi_instruction) { - if (ira->const_predecessor_bb) { - for (size_t i = 0; i < phi_instruction->incoming_count; i += 1) { - IrBasicBlock *predecessor = phi_instruction->incoming_blocks[i]; - if (predecessor != ira->const_predecessor_bb) - continue; - IrInstruction *value = phi_instruction->incoming_values[i]->other; - assert(value->type_entry); - if (value->static_value.ok) { - ConstExprValue *out_val = ir_build_const_from(ira, &phi_instruction->base, - value->static_value.depends_on_compile_var); - *out_val = value->static_value; - } else { - phi_instruction->base.other = value; - } - return value->type_entry; - } - zig_unreachable(); - } - - ZigList<IrBasicBlock*> new_incoming_blocks = {0}; - ZigList<IrInstruction*> new_incoming_values = {0}; - - for (size_t i = 0; i < phi_instruction->incoming_count; i += 1) { - IrBasicBlock *predecessor = phi_instruction->incoming_blocks[i]; - if (predecessor->ref_count == 0) - continue; - - assert(predecessor->other); - new_incoming_blocks.append(predecessor->other); - - IrInstruction *old_value = phi_instruction->incoming_values[i]; - assert(old_value); - new_incoming_values.append(old_value->other); - } - assert(new_incoming_blocks.length != 0); - - if (new_incoming_blocks.length == 1) { - IrInstruction *first_value = new_incoming_values.at(0); - phi_instruction->base.other = first_value; - return first_value->type_entry; - } - - TypeTableEntry *resolved_type = ir_resolve_peer_types(ira, phi_instruction->base.source_node, - new_incoming_values.items, new_incoming_values.length); - if (resolved_type->id == TypeTableEntryIdInvalid) - return resolved_type; - - ir_build_phi_from(&ira->new_irb, &phi_instruction->base, new_incoming_blocks.length, - new_incoming_blocks.items, new_incoming_values.items); - return resolved_type; -} - -static TypeTableEntry *ir_analyze_instruction_var_ptr(IrAnalyze *ira, IrInstructionVarPtr *var_ptr_instruction) { - VariableTableEntry *var = var_ptr_instruction->var; - if (var->type->id == TypeTableEntryIdInvalid) - return var->type; - - TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, var->type, false); - // TODO once the anlayze code is fully ported over to IR we won't need this SIZE_MAX thing. - if (var->mem_slot_index != SIZE_MAX) { - ConstExprValue *mem_slot = &ira->exec_context.mem_slot_list[var->mem_slot_index]; - if (mem_slot->ok) { - ConstExprValue *out_val = ir_build_const_from(ira, &var_ptr_instruction->base, - mem_slot->depends_on_compile_var); - - out_val->data.x_ptr.len = 1; - out_val->data.x_ptr.is_c_str = false; - out_val->data.x_ptr.ptr = allocate<ConstExprValue *>(1); - out_val->data.x_ptr.ptr[0] = mem_slot; - return ptr_type; - } - } - - ir_build_var_ptr_from(&ira->new_irb, &var_ptr_instruction->base, var); - return ptr_type; -} - -static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstructionElemPtr *elem_ptr_instruction) { - IrInstruction *array_ptr = elem_ptr_instruction->array_ptr->other; - IrInstruction *elem_index = elem_ptr_instruction->elem_index->other; - - TypeTableEntry *array_type = array_ptr->type_entry; - TypeTableEntry *return_type; - - if (array_type->id == TypeTableEntryIdInvalid) { - return array_type; - } else if (array_type->id == TypeTableEntryIdArray) { - if (array_type->data.array.len == 0) { - add_node_error(ira->codegen, elem_ptr_instruction->base.source_node, - buf_sprintf("out of bounds array access")); - } - TypeTableEntry *child_type = array_type->data.array.child_type; - return_type = get_pointer_to_type(ira->codegen, child_type, false); - } else if (array_type->id == TypeTableEntryIdPointer) { - return_type = array_type; - } else if (is_slice(array_type)) { - return_type = array_type->data.structure.fields[0].type_entry; - } else { - add_node_error(ira->codegen, elem_ptr_instruction->base.source_node, - buf_sprintf("array access of non-array type '%s'", buf_ptr(&array_type->name))); - return ira->codegen->builtin_types.entry_invalid; - } - - TypeTableEntry *usize = ira->codegen->builtin_types.entry_usize; - IrInstruction *casted_elem_index = ir_get_casted_value(ira, elem_index, usize); - if (casted_elem_index == ira->codegen->invalid_instruction) - return ira->codegen->builtin_types.entry_invalid; - - if (array_ptr->static_value.ok && casted_elem_index->static_value.ok) { - zig_panic("TODO compile time array access"); - } - - ir_build_elem_ptr_from(&ira->new_irb, &elem_ptr_instruction->base, array_ptr, casted_elem_index); - - return return_type; -} - -static TypeTableEntry *ir_analyze_container_member_access_inner(IrAnalyze *ira, - TypeTableEntry *bare_struct_type, Buf *field_name, IrInstructionFieldPtr *field_ptr_instruction, - TypeTableEntry *container_type) -{ - 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) { - zig_panic("TODO member function call"); - } - } - add_node_error(ira->codegen, field_ptr_instruction->base.source_node, - buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name), buf_ptr(&bare_struct_type->name))); - return ira->codegen->builtin_types.entry_invalid; -} - - -static TypeTableEntry *ir_analyze_container_member_access(IrAnalyze *ira, Buf *field_name, - IrInstructionFieldPtr *field_ptr_instruction, 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)) { - resolve_container_type(ira->codegen, bare_type); - } - - if (bare_type->id == TypeTableEntryIdStruct) { - TypeStructField *field = find_struct_type_field(bare_type, field_name); - if (field) { - ir_build_struct_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_type); - } - } else if (bare_type->id == TypeTableEntryIdEnum) { - zig_panic("TODO enum field ptr"); - } else if (bare_type->id == TypeTableEntryIdUnion) { - zig_panic("TODO"); - } else { - zig_unreachable(); - } -} - -static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstructionFieldPtr *field_ptr_instruction) { - IrInstruction *container_ptr = field_ptr_instruction->container_ptr->other; - Buf *field_name = field_ptr_instruction->field_name; - - TypeTableEntry *container_type = container_ptr->type_entry; - 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); - } else if (container_type->id == TypeTableEntryIdArray) { - if (buf_eql_str(field_name, "len")) { - add_node_error(ira->codegen, field_ptr_instruction->base.source_node, - buf_sprintf("pointer to array length not available")); - return ira->codegen->builtin_types.entry_invalid; - } else { - add_node_error(ira->codegen, field_ptr_instruction->base.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; - } - } else if (container_type->id == TypeTableEntryIdMetaType) { - 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, field_ptr_instruction->base.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) { - zig_panic("TODO namespace field access"); - } else { - add_node_error(ira->codegen, field_ptr_instruction->base.source_node, - buf_sprintf("type '%s' does not support field access", buf_ptr(&container_type->name))); - return ira->codegen->builtin_types.entry_invalid; - } -} - -static TypeTableEntry *ir_analyze_read_field_as_ptr_load(IrAnalyze *ira, - IrInstructionReadField *read_field_instruction) -{ - IrInstruction *old_field_ptr_inst = ir_build_field_ptr(&ira->old_irb, read_field_instruction->base.source_node, - read_field_instruction->container_ptr, read_field_instruction->field_name); - IrInstruction *old_load_ptr_inst = ir_build_load_ptr(&ira->old_irb, read_field_instruction->base.source_node, - old_field_ptr_inst); - ir_analyze_instruction(ira, old_field_ptr_inst); - TypeTableEntry *result_type = ir_analyze_instruction(ira, old_load_ptr_inst); - read_field_instruction->base.other = old_load_ptr_inst->other; - return result_type; -} - -static TypeTableEntry *ir_analyze_instruction_read_field(IrAnalyze *ira, - IrInstructionReadField *read_field_instruction) -{ - IrInstruction *container_ptr = read_field_instruction->container_ptr->other; - Buf *field_name = read_field_instruction->field_name; - - TypeTableEntry *container_type = container_ptr->type_entry; - if (container_type->id == TypeTableEntryIdInvalid) { - return container_type; - } else if (is_container_ref(container_type)) { - return ir_analyze_read_field_as_ptr_load(ira, read_field_instruction); - } else if (container_type->id == TypeTableEntryIdArray) { - if (buf_eql_str(field_name, "len")) { - return ir_analyze_const_usize(ira, &read_field_instruction->base, container_type->data.array.len, false); - } else { - add_node_error(ira->codegen, read_field_instruction->base.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; - } - } else if (container_type->id == TypeTableEntryIdMetaType) { - 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, read_field_instruction->base.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) { - zig_panic("TODO namespace field access"); - } else { - add_node_error(ira->codegen, read_field_instruction->base.source_node, - buf_sprintf("type '%s' does not support field access", buf_ptr(&container_type->name))); - return ira->codegen->builtin_types.entry_invalid; - } -} - -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.ok) { - ConstExprValue *pointee = ptr->static_value.data.x_ptr.ptr[0]; - if (pointee->ok) { - 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("indirection requires pointer operand ('%s' invalid)", - buf_ptr(&type_entry->name))); - return ira->codegen->builtin_types.entry_invalid; - } -} - -static TypeTableEntry *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstructionStorePtr *store_ptr_instruction) { - IrInstruction *ptr = store_ptr_instruction->ptr->other; - if (ptr->type_entry->id == TypeTableEntryIdInvalid) - return ptr->type_entry; - - IrInstruction *value = store_ptr_instruction->value->other; - if (value->type_entry->id == TypeTableEntryIdInvalid) - return value->type_entry; - - TypeTableEntry *child_type = ptr->type_entry->data.pointer.child_type; - IrInstruction *casted_value = ir_get_casted_value(ira, value, child_type); - if (casted_value == ira->codegen->invalid_instruction) - return ira->codegen->builtin_types.entry_invalid; - - if (ptr->static_value.ok && casted_value->static_value.ok) { - ConstExprValue *dest_val = ptr->static_value.data.x_ptr.ptr[0]; - if (dest_val->ok) { - *dest_val = casted_value->static_value; - return ir_analyze_void(ira, &store_ptr_instruction->base); - } - } - - if (ptr->static_value.ok) { - // This memory location is transforming from known at compile time to known at runtime. - // We must emit our own var ptr instruction. - ptr->static_value.ok = false; - IrInstruction *new_ptr_inst; - if (ptr->id == IrInstructionIdVarPtr) { - IrInstructionVarPtr *var_ptr_inst = (IrInstructionVarPtr *)ptr; - VariableTableEntry *var = var_ptr_inst->var; - new_ptr_inst = ir_build_var_ptr(&ira->new_irb, store_ptr_instruction->base.source_node, var); - assert(var->mem_slot_index != SIZE_MAX); - ConstExprValue *mem_slot = &ira->exec_context.mem_slot_list[var->mem_slot_index]; - mem_slot->ok = false; - } else if (ptr->id == IrInstructionIdFieldPtr) { - zig_panic("TODO"); - } else if (ptr->id == IrInstructionIdElemPtr) { - zig_panic("TODO"); - } else { - zig_unreachable(); - } - new_ptr_inst->type_entry = ptr->type_entry; - ir_build_store_ptr(&ira->new_irb, store_ptr_instruction->base.source_node, new_ptr_inst, casted_value); - return ir_analyze_void(ira, &store_ptr_instruction->base); - } - ir_build_store_ptr_from(&ira->new_irb, &store_ptr_instruction->base, ptr, casted_value); - return ira->codegen->builtin_types.entry_void; -} -static TypeTableEntry *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructionTypeOf *typeof_instruction) { - IrInstruction *expr_value = typeof_instruction->value->other; - TypeTableEntry *type_entry = expr_value->type_entry; - switch (type_entry->id) { - case TypeTableEntryIdInvalid: - return type_entry; - case TypeTableEntryIdVar: - add_node_error(ira->codegen, expr_value->source_node, - buf_sprintf("type '%s' not eligible for @typeOf", buf_ptr(&type_entry->name))); - return ira->codegen->builtin_types.entry_invalid; - case TypeTableEntryIdNumLitFloat: - case TypeTableEntryIdNumLitInt: - case TypeTableEntryIdUndefLit: - case TypeTableEntryIdNullLit: - case TypeTableEntryIdNamespace: - case TypeTableEntryIdBlock: - case TypeTableEntryIdGenericFn: - case TypeTableEntryIdMetaType: - case TypeTableEntryIdVoid: - case TypeTableEntryIdBool: - case TypeTableEntryIdUnreachable: - case TypeTableEntryIdInt: - case TypeTableEntryIdFloat: - case TypeTableEntryIdPointer: - case TypeTableEntryIdArray: - case TypeTableEntryIdStruct: - case TypeTableEntryIdMaybe: - case TypeTableEntryIdErrorUnion: - case TypeTableEntryIdPureError: - case TypeTableEntryIdEnum: - case TypeTableEntryIdUnion: - case TypeTableEntryIdFn: - case TypeTableEntryIdTypeDecl: - { - ConstExprValue *out_val = ir_build_const_from(ira, &typeof_instruction->base, false); - // TODO depends_on_compile_var should be set based on whether the type of the expression - // depends_on_compile_var. but we currently don't have a thing to tell us if the type of - // something depends on a compile var - out_val->data.x_type = type_entry; - - return ira->codegen->builtin_types.entry_type; - } - } - - zig_unreachable(); -} - -static TypeTableEntry *ir_analyze_instruction_to_ptr_type(IrAnalyze *ira, - IrInstructionToPtrType *to_ptr_type_instruction) -{ - IrInstruction *type_value = to_ptr_type_instruction->value->other; - TypeTableEntry *type_entry = ir_resolve_type(ira, type_value); - if (type_entry->id == TypeTableEntryIdInvalid) - return type_entry; - - TypeTableEntry *ptr_type; - if (type_entry->id == TypeTableEntryIdArray) { - ptr_type = get_pointer_to_type(ira->codegen, type_entry->data.array.child_type, false); - } else if (is_slice(type_entry)) { - ptr_type = type_entry->data.structure.fields[0].type_entry; - } else { - add_node_error(ira->codegen, to_ptr_type_instruction->base.source_node, - buf_sprintf("expected array type, found '%s'", buf_ptr(&type_entry->name))); - return ira->codegen->builtin_types.entry_invalid; - } - - ConstExprValue *out_val = ir_build_const_from(ira, &to_ptr_type_instruction->base, - type_value->static_value.depends_on_compile_var); - out_val->data.x_type = ptr_type; - return ira->codegen->builtin_types.entry_type; -} - -static TypeTableEntry *ir_analyze_instruction_ptr_type_child(IrAnalyze *ira, - IrInstructionPtrTypeChild *ptr_type_child_instruction) -{ - IrInstruction *type_value = ptr_type_child_instruction->value->other; - TypeTableEntry *type_entry = ir_resolve_type(ira, type_value); - if (type_entry->id == TypeTableEntryIdInvalid) - return type_entry; - - if (type_entry->id != TypeTableEntryIdPointer) { - add_node_error(ira->codegen, ptr_type_child_instruction->base.source_node, - buf_sprintf("expected pointer type, found '%s'", buf_ptr(&type_entry->name))); - return ira->codegen->builtin_types.entry_invalid; - } - - ConstExprValue *out_val = ir_build_const_from(ira, &ptr_type_child_instruction->base, - type_value->static_value.depends_on_compile_var); - out_val->data.x_type = type_entry->data.pointer.child_type; - return ira->codegen->builtin_types.entry_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); - case IrInstructionIdFieldPtr: - return ir_analyze_instruction_field_ptr(ira, (IrInstructionFieldPtr *)instruction); - case IrInstructionIdReadField: - return ir_analyze_instruction_read_field(ira, (IrInstructionReadField *)instruction); - case IrInstructionIdCall: - return ir_analyze_instruction_call(ira, (IrInstructionCall *)instruction); - case IrInstructionIdBr: - return ir_analyze_instruction_br(ira, (IrInstructionBr *)instruction); - case IrInstructionIdCondBr: - return ir_analyze_instruction_cond_br(ira, (IrInstructionCondBr *)instruction); - case IrInstructionIdBuiltinCall: - return ir_analyze_instruction_builtin_call(ira, (IrInstructionBuiltinCall *)instruction); - case IrInstructionIdUnreachable: - return ir_analyze_instruction_unreachable(ira, (IrInstructionUnreachable *)instruction); - case IrInstructionIdPhi: - return ir_analyze_instruction_phi(ira, (IrInstructionPhi *)instruction); - case IrInstructionIdTypeOf: - return ir_analyze_instruction_typeof(ira, (IrInstructionTypeOf *)instruction); - case IrInstructionIdToPtrType: - return ir_analyze_instruction_to_ptr_type(ira, (IrInstructionToPtrType *)instruction); - case IrInstructionIdPtrTypeChild: - return ir_analyze_instruction_ptr_type_child(ira, (IrInstructionPtrTypeChild *)instruction); - case IrInstructionIdSwitchBr: - case IrInstructionIdCast: - case IrInstructionIdContainerInitList: - case IrInstructionIdContainerInitFields: - case IrInstructionIdStructFieldPtr: - zig_panic("TODO analyze more instructions"); - } - zig_unreachable(); -} - -static TypeTableEntry *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction) { - TypeTableEntry *instruction_type = ir_analyze_instruction_nocast(ira, instruction); - instruction->type_entry = instruction_type; - if (instruction->other) { - instruction->other->type_entry = instruction_type; - } else { - assert(instruction_type->id == TypeTableEntryIdInvalid || - instruction_type->id == TypeTableEntryIdUnreachable); - instruction->other = instruction; - } - return instruction_type; -} - -// This function attempts to evaluate IR code while doing type checking and other analysis. -// It emits a new IrExecutable which is partially evaluated IR code. -TypeTableEntry *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_exec, - TypeTableEntry *expected_type, AstNode *expected_type_source_node) -{ - IrAnalyze ir_analyze_data = {}; - IrAnalyze *ira = &ir_analyze_data; - ira->codegen = codegen; - ira->explicit_return_type = expected_type; - - ira->old_irb.codegen = codegen; - ira->old_irb.exec = old_exec; - - ira->new_irb.codegen = codegen; - ira->new_irb.exec = new_exec; - - ira->exec_context.mem_slot_count = ira->old_irb.exec->mem_slot_count; - ira->exec_context.mem_slot_list = allocate<ConstExprValue>(ira->exec_context.mem_slot_count); - - IrBasicBlock *old_entry_bb = ira->old_irb.exec->basic_block_list.at(0); - IrBasicBlock *new_entry_bb = ir_get_new_bb(ira, old_entry_bb); - ir_ref_bb(new_entry_bb); - ira->old_irb.current_basic_block = old_entry_bb; - ira->new_irb.current_basic_block = new_entry_bb; - ira->block_queue_index = 0; - ira->instruction_index = 0; - - while (ira->block_queue_index < ira->old_bb_queue.length) { - IrInstruction *old_instruction = ira->old_irb.current_basic_block->instruction_list.at(ira->instruction_index); - - if (old_instruction->ref_count == 0 && !ir_has_side_effects(old_instruction)) { - ira->instruction_index += 1; - continue; - } - - TypeTableEntry *return_type = ir_analyze_instruction(ira, old_instruction); - - // unreachable instructions do their own control flow. - if (return_type->id == TypeTableEntryIdUnreachable) - continue; - - ira->instruction_index += 1; - } - - return ir_resolve_peer_types(ira, expected_type_source_node, ira->implicit_return_type_list.items, - ira->implicit_return_type_list.length); -} +//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 if (struct_type->id == TypeTableEntryIdNamespace) { +// ConstExprValue *const_val = &get_resolved_expr(*struct_expr_node)->const_val; +// assert(const_val->ok); +// ImportTableEntry *namespace_import = const_val->data.x_import; +// AstNode *decl_node = find_decl(namespace_import->block_context, field_name); +// if (!decl_node) { +// // we must now resolve all the use decls +// for (size_t i = 0; i < namespace_import->use_decls.length; i += 1) { +// AstNode *use_decl_node = namespace_import->use_decls.at(i); +// if (!get_resolved_expr(use_decl_node->data.use.expr)->type_entry) { +// preview_use_decl(g, use_decl_node); +// } +// resolve_use_decl(g, use_decl_node); +// } +// decl_node = find_decl(namespace_import->block_context, field_name); +// } +// if (decl_node) { +// TopLevelDecl *tld = get_as_top_level_decl(decl_node); +// if (tld->visib_mod == VisibModPrivate && decl_node->owner != import) { +// ErrorMsg *msg = add_node_error(g, node, +// buf_sprintf("'%s' is private", buf_ptr(field_name))); +// add_error_note(g, msg, decl_node, buf_sprintf("declared here")); +// } +// bool pointer_only = false; +// return analyze_decl_ref(g, node, decl_node, pointer_only, context, +// const_val->depends_on_compile_var); +// } else { +// const char *import_name = namespace_import->path ? buf_ptr(namespace_import->path) : "(C import)"; +// add_node_error(g, node, +// buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name), import_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 bool ir_builtin_call_has_side_effects(IrInstructionBuiltinCall *call_instruction) { - switch (call_instruction->fn->id) { - case BuiltinFnIdInvalid: - zig_unreachable(); - case BuiltinFnIdMemcpy: - case BuiltinFnIdMemset: - case BuiltinFnIdAddWithOverflow: - case BuiltinFnIdSubWithOverflow: - case BuiltinFnIdMulWithOverflow: - case BuiltinFnIdShlWithOverflow: - case BuiltinFnIdCInclude: - case BuiltinFnIdCDefine: - case BuiltinFnIdCUndef: - case BuiltinFnIdImport: - case BuiltinFnIdCImport: - case BuiltinFnIdBreakpoint: - case BuiltinFnIdEmbedFile: - case BuiltinFnIdCmpExchange: - case BuiltinFnIdFence: - case BuiltinFnIdUnreachable: - case BuiltinFnIdSetFnTest: - case BuiltinFnIdSetFnVisible: - case BuiltinFnIdSetFnStaticEval: - case BuiltinFnIdSetFnNoInline: - case BuiltinFnIdSetDebugSafety: - return true; - case BuiltinFnIdSizeof: - case BuiltinFnIdAlignof: - case BuiltinFnIdMaxValue: - case BuiltinFnIdMinValue: - case BuiltinFnIdMemberCount: - case BuiltinFnIdTypeof: - case BuiltinFnIdCompileVar: - case BuiltinFnIdCompileErr: - case BuiltinFnIdConstEval: - case BuiltinFnIdCtz: - case BuiltinFnIdClz: - case BuiltinFnIdErrName: - case BuiltinFnIdReturnAddress: - case BuiltinFnIdFrameAddress: - case BuiltinFnIdDivExact: - case BuiltinFnIdTruncate: - case BuiltinFnIdIntType: - return false; - } - zig_unreachable(); -} +//static TypeTableEntry *analyze_lvalue(CodeGen *g, ImportTableEntry *import, BlockContext *block_context, +// AstNode *lhs_node, LValPurpose purpose, bool is_ptr_const) +//{ +// TypeTableEntry *expected_rhs_type = nullptr; +// lhs_node->block_context = block_context; +// if (lhs_node->type == NodeTypeSymbol) { +// bool pointer_only = purpose == LValPurposeAddressOf; +// expected_rhs_type = analyze_symbol_expr(g, import, block_context, nullptr, lhs_node, pointer_only); +// if (expected_rhs_type->id == TypeTableEntryIdInvalid) { +// return g->builtin_types.entry_invalid; +// } +// if (purpose != LValPurposeAddressOf) { +// Buf *name = lhs_node->data.symbol_expr.symbol; +// VariableTableEntry *var = find_variable(g, block_context, name); +// if (var) { +// if (var->src_is_const) { +// add_node_error(g, lhs_node, buf_sprintf("cannot assign to constant")); +// expected_rhs_type = g->builtin_types.entry_invalid; +// } else { +// expected_rhs_type = var->type; +// get_resolved_expr(lhs_node)->variable = var; +// } +// } else { +// add_node_error(g, lhs_node, +// buf_sprintf("use of undeclared identifier '%s'", buf_ptr(name))); +// expected_rhs_type = g->builtin_types.entry_invalid; +// } +// } +// } else if (lhs_node->type == NodeTypeArrayAccessExpr) { +// expected_rhs_type = analyze_array_access_expr(g, import, block_context, lhs_node, purpose); +// } else if (lhs_node->type == NodeTypeFieldAccessExpr) { +// expected_rhs_type = analyze_field_access_expr(g, import, block_context, nullptr, lhs_node); +// } else if (lhs_node->type == NodeTypePrefixOpExpr && +// lhs_node->data.prefix_op_expr.prefix_op == PrefixOpDereference) +// { +// assert(purpose == LValPurposeAssign); +// AstNode *target_node = lhs_node->data.prefix_op_expr.primary_expr; +// TypeTableEntry *type_entry = analyze_expression(g, import, block_context, nullptr, target_node); +// if (type_entry->id == TypeTableEntryIdInvalid) { +// expected_rhs_type = type_entry; +// } else if (type_entry->id == TypeTableEntryIdPointer) { +// expected_rhs_type = type_entry->data.pointer.child_type; +// } else { +// add_node_error(g, target_node, +// buf_sprintf("indirection requires pointer operand ('%s' invalid)", +// buf_ptr(&type_entry->name))); +// expected_rhs_type = g->builtin_types.entry_invalid; +// } +// } else { +// if (purpose == LValPurposeAssign) { +// add_node_error(g, lhs_node, buf_sprintf("invalid assignment target")); +// expected_rhs_type = g->builtin_types.entry_invalid; +// } else if (purpose == LValPurposeAddressOf) { +// TypeTableEntry *type_entry = analyze_expression(g, import, block_context, nullptr, lhs_node); +// if (type_entry->id == TypeTableEntryIdInvalid) { +// expected_rhs_type = g->builtin_types.entry_invalid; +// } else if (type_entry->id == TypeTableEntryIdMetaType) { +// expected_rhs_type = type_entry; +// } else { +// add_node_error(g, lhs_node, buf_sprintf("invalid addressof target")); +// expected_rhs_type = g->builtin_types.entry_invalid; +// } +// } +// } +// assert(expected_rhs_type); +// return expected_rhs_type; +//} -bool ir_has_side_effects(IrInstruction *instruction) { - switch (instruction->id) { - case IrInstructionIdInvalid: - zig_unreachable(); - case IrInstructionIdBr: - case IrInstructionIdCondBr: - case IrInstructionIdSwitchBr: - case IrInstructionIdDeclVar: - case IrInstructionIdStorePtr: - case IrInstructionIdCall: - case IrInstructionIdReturn: - case IrInstructionIdUnreachable: - return true; - case IrInstructionIdPhi: - case IrInstructionIdUnOp: - case IrInstructionIdBinOp: - case IrInstructionIdLoadPtr: - case IrInstructionIdConst: - case IrInstructionIdCast: - case IrInstructionIdContainerInitList: - case IrInstructionIdContainerInitFields: - case IrInstructionIdFieldPtr: - case IrInstructionIdElemPtr: - case IrInstructionIdVarPtr: - case IrInstructionIdTypeOf: - case IrInstructionIdToPtrType: - case IrInstructionIdPtrTypeChild: - case IrInstructionIdReadField: - case IrInstructionIdStructFieldPtr: - return false; - case IrInstructionIdBuiltinCall: - return ir_builtin_call_has_side_effects((IrInstructionBuiltinCall *)instruction); - } - zig_unreachable(); -} -IrInstruction *ir_exec_const_result(IrExecutable *exec) { - if (exec->basic_block_list.length != 1) - return nullptr; - IrBasicBlock *bb = exec->basic_block_list.at(0); - if (bb->instruction_list.length != 1) - return nullptr; +//static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, +// TypeTableEntry *expected_type, AstNode *node) +//{ +// assert(node->type == NodeTypeBinOpExpr); +// BinOpType bin_op_type = node->data.bin_op_expr.bin_op; +// switch (bin_op_type) { +// case BinOpTypeAssign: +// case BinOpTypeAssignTimes: +// case BinOpTypeAssignTimesWrap: +// case BinOpTypeAssignDiv: +// case BinOpTypeAssignMod: +// case BinOpTypeAssignPlus: +// case BinOpTypeAssignPlusWrap: +// case BinOpTypeAssignMinus: +// case BinOpTypeAssignMinusWrap: +// case BinOpTypeAssignBitShiftLeft: +// case BinOpTypeAssignBitShiftLeftWrap: +// case BinOpTypeAssignBitShiftRight: +// case BinOpTypeAssignBitAnd: +// case BinOpTypeAssignBitXor: +// case BinOpTypeAssignBitOr: +// case BinOpTypeAssignBoolAnd: +// case BinOpTypeAssignBoolOr: +// { +// AstNode *lhs_node = node->data.bin_op_expr.op1; +// +// TypeTableEntry *expected_rhs_type = analyze_lvalue(g, import, context, lhs_node, +// LValPurposeAssign, false); +// if (expected_rhs_type->id == TypeTableEntryIdInvalid) { +// return g->builtin_types.entry_invalid; +// } else if (!is_op_allowed(expected_rhs_type, node->data.bin_op_expr.bin_op)) { +// if (expected_rhs_type->id != TypeTableEntryIdInvalid) { +// add_node_error(g, lhs_node, +// buf_sprintf("operator not allowed for type '%s'", +// buf_ptr(&expected_rhs_type->name))); +// } +// } +// +// analyze_expression(g, import, context, expected_rhs_type, node->data.bin_op_expr.op2); +// // not const ok because expression has side effects +// return g->builtin_types.entry_void; +// } +// case BinOpTypeBoolOr: +// case BinOpTypeBoolAnd: +// return analyze_logic_bin_op_expr(g, import, context, node); +// case BinOpTypeCmpEq: +// case BinOpTypeCmpNotEq: +// case BinOpTypeCmpLessThan: +// case BinOpTypeCmpGreaterThan: +// case BinOpTypeCmpLessOrEq: +// case BinOpTypeCmpGreaterOrEq: +// return analyze_bool_bin_op_expr(g, import, context, node); +// case BinOpTypeBinOr: +// case BinOpTypeBinXor: +// case BinOpTypeBinAnd: +// case BinOpTypeBitShiftLeft: +// case BinOpTypeBitShiftLeftWrap: +// case BinOpTypeBitShiftRight: +// case BinOpTypeAdd: +// case BinOpTypeAddWrap: +// case BinOpTypeSub: +// case BinOpTypeSubWrap: +// case BinOpTypeMult: +// case BinOpTypeMultWrap: +// case BinOpTypeDiv: +// case BinOpTypeMod: +// { +// AstNode **op1 = node->data.bin_op_expr.op1->parent_field; +// AstNode **op2 = node->data.bin_op_expr.op2->parent_field; +// TypeTableEntry *lhs_type = analyze_expression(g, import, context, nullptr, *op1); +// TypeTableEntry *rhs_type = analyze_expression(g, import, context, nullptr, *op2); +// +// AstNode *op_nodes[] = {*op1, *op2}; +// TypeTableEntry *op_types[] = {lhs_type, rhs_type}; +// +// TypeTableEntry *resolved_type = resolve_peer_type_compatibility(g, import, context, node, +// op_nodes, op_types, 2); +// +// if (resolved_type->id == TypeTableEntryIdInvalid) { +// return resolved_type; +// } +// +// if (resolved_type->id == TypeTableEntryIdInt || +// resolved_type->id == TypeTableEntryIdNumLitInt) +// { +// // int +// } else if ((resolved_type->id == TypeTableEntryIdFloat || +// resolved_type->id == TypeTableEntryIdNumLitFloat) && +// (bin_op_type == BinOpTypeAdd || +// bin_op_type == BinOpTypeSub || +// bin_op_type == BinOpTypeMult || +// bin_op_type == BinOpTypeDiv || +// bin_op_type == BinOpTypeMod)) +// { +// // float +// } else { +// add_node_error(g, node, buf_sprintf("invalid operands to binary expression: '%s' and '%s'", +// buf_ptr(&lhs_type->name), buf_ptr(&rhs_type->name))); +// return g->builtin_types.entry_invalid; +// } +// +// ConstExprValue *op1_val = &get_resolved_expr(*op1)->const_val; +// ConstExprValue *op2_val = &get_resolved_expr(*op2)->const_val; +// if (!op1_val->ok || !op2_val->ok) { +// return resolved_type; +// } +// +// ConstExprValue *out_val = &get_resolved_expr(node)->const_val; +// int err; +// if ((err = eval_const_expr_bin_op(op1_val, resolved_type, bin_op_type, +// op2_val, resolved_type, out_val))) +// { +// if (err == ErrorDivByZero) { +// add_node_error(g, node, buf_sprintf("division by zero is undefined")); +// return g->builtin_types.entry_invalid; +// } else if (err == ErrorOverflow) { +// add_node_error(g, node, buf_sprintf("value cannot be represented in any integer type")); +// return g->builtin_types.entry_invalid; +// } +// return g->builtin_types.entry_invalid; +// } +// +// num_lit_fits_in_other_type(g, node, resolved_type); +// return resolved_type; +// } +// case BinOpTypeUnwrapMaybe: +// { +// AstNode *op1 = node->data.bin_op_expr.op1; +// AstNode *op2 = node->data.bin_op_expr.op2; +// TypeTableEntry *lhs_type = analyze_expression(g, import, context, nullptr, op1); +// +// if (lhs_type->id == TypeTableEntryIdInvalid) { +// return lhs_type; +// } else if (lhs_type->id == TypeTableEntryIdMaybe) { +// TypeTableEntry *child_type = lhs_type->data.maybe.child_type; +// analyze_expression(g, import, context, child_type, op2); +// return child_type; +// } else { +// add_node_error(g, op1, +// buf_sprintf("expected maybe type, got '%s'", +// buf_ptr(&lhs_type->name))); +// return g->builtin_types.entry_invalid; +// } +// } +// case BinOpTypeArrayCat: +// { +// AstNode **op1 = node->data.bin_op_expr.op1->parent_field; +// AstNode **op2 = node->data.bin_op_expr.op2->parent_field; +// +// TypeTableEntry *op1_type = analyze_expression(g, import, context, nullptr, *op1); +// TypeTableEntry *child_type; +// if (op1_type->id == TypeTableEntryIdInvalid) { +// return g->builtin_types.entry_invalid; +// } else if (op1_type->id == TypeTableEntryIdArray) { +// child_type = op1_type->data.array.child_type; +// } else if (op1_type->id == TypeTableEntryIdPointer && +// op1_type->data.pointer.child_type == g->builtin_types.entry_u8) { +// child_type = op1_type->data.pointer.child_type; +// } else { +// add_node_error(g, *op1, buf_sprintf("expected array or C string literal, got '%s'", +// buf_ptr(&op1_type->name))); +// return g->builtin_types.entry_invalid; +// } +// +// TypeTableEntry *op2_type = analyze_expression(g, import, context, nullptr, *op2); +// +// if (op2_type->id == TypeTableEntryIdInvalid) { +// return g->builtin_types.entry_invalid; +// } else if (op2_type->id == TypeTableEntryIdArray) { +// if (op2_type->data.array.child_type != child_type) { +// add_node_error(g, *op2, buf_sprintf("expected array of type '%s', got '%s'", +// buf_ptr(&child_type->name), +// buf_ptr(&op2_type->name))); +// return g->builtin_types.entry_invalid; +// } +// } else if (op2_type->id == TypeTableEntryIdPointer && +// op2_type->data.pointer.child_type == g->builtin_types.entry_u8) { +// } else { +// add_node_error(g, *op2, buf_sprintf("expected array or C string literal, got '%s'", +// buf_ptr(&op2_type->name))); +// return g->builtin_types.entry_invalid; +// } +// +// ConstExprValue *op1_val = &get_resolved_expr(*op1)->const_val; +// ConstExprValue *op2_val = &get_resolved_expr(*op2)->const_val; +// +// AstNode *bad_node; +// if (!op1_val->ok) { +// bad_node = *op1; +// } else if (!op2_val->ok) { +// bad_node = *op2; +// } else { +// bad_node = nullptr; +// } +// if (bad_node) { +// add_node_error(g, bad_node, buf_sprintf("array concatenation requires constant expression")); +// return g->builtin_types.entry_invalid; +// } +// +// ConstExprValue *const_val = &get_resolved_expr(node)->const_val; +// const_val->ok = true; +// const_val->depends_on_compile_var = op1_val->depends_on_compile_var || +// op2_val->depends_on_compile_var; +// +// if (op1_type->id == TypeTableEntryIdArray) { +// uint64_t new_len = op1_type->data.array.len + op2_type->data.array.len; +// const_val->data.x_array.fields = allocate<ConstExprValue*>(new_len); +// uint64_t next_index = 0; +// for (uint64_t i = 0; i < op1_type->data.array.len; i += 1, next_index += 1) { +// const_val->data.x_array.fields[next_index] = op1_val->data.x_array.fields[i]; +// } +// for (uint64_t i = 0; i < op2_type->data.array.len; i += 1, next_index += 1) { +// const_val->data.x_array.fields[next_index] = op2_val->data.x_array.fields[i]; +// } +// return get_array_type(g, child_type, new_len); +// } else if (op1_type->id == TypeTableEntryIdPointer) { +// if (!op1_val->data.x_ptr.is_c_str) { +// add_node_error(g, *op1, +// buf_sprintf("expected array or C string literal, got '%s'", +// buf_ptr(&op1_type->name))); +// return g->builtin_types.entry_invalid; +// } else if (!op2_val->data.x_ptr.is_c_str) { +// add_node_error(g, *op2, +// buf_sprintf("expected array or C string literal, got '%s'", +// buf_ptr(&op2_type->name))); +// return g->builtin_types.entry_invalid; +// } +// const_val->data.x_ptr.is_c_str = true; +// const_val->data.x_ptr.len = op1_val->data.x_ptr.len + op2_val->data.x_ptr.len - 1; +// const_val->data.x_ptr.ptr = allocate<ConstExprValue*>(const_val->data.x_ptr.len); +// uint64_t next_index = 0; +// for (uint64_t i = 0; i < op1_val->data.x_ptr.len - 1; i += 1, next_index += 1) { +// const_val->data.x_ptr.ptr[next_index] = op1_val->data.x_ptr.ptr[i]; +// } +// for (uint64_t i = 0; i < op2_val->data.x_ptr.len; i += 1, next_index += 1) { +// const_val->data.x_ptr.ptr[next_index] = op2_val->data.x_ptr.ptr[i]; +// } +// return op1_type; +// } else { +// zig_unreachable(); +// } +// } +// case BinOpTypeArrayMult: +// return analyze_array_mult(g, import, context, expected_type, node); +// case BinOpTypeInvalid: +// zig_unreachable(); +// } +// zig_unreachable(); +//} - IrInstruction *only_inst = bb->instruction_list.at(0); - if (only_inst->id != IrInstructionIdReturn) - return nullptr; - IrInstructionReturn *ret_inst = (IrInstructionReturn *)only_inst; - IrInstruction *value = ret_inst->value; - assert(value->static_value.ok); - return value; -} +//static TypeTableEntry *analyze_bool_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, +// AstNode *node) +//{ +// assert(node->type == NodeTypeBinOpExpr); +// BinOpType bin_op_type = node->data.bin_op_expr.bin_op; +// +// AstNode **op1 = &node->data.bin_op_expr.op1; +// AstNode **op2 = &node->data.bin_op_expr.op2; +// TypeTableEntry *op1_type = analyze_expression(g, import, context, nullptr, *op1); +// TypeTableEntry *op2_type = analyze_expression(g, import, context, nullptr, *op2); +// +// AstNode *op_nodes[] = {*op1, *op2}; +// TypeTableEntry *op_types[] = {op1_type, op2_type}; +// +// TypeTableEntry *resolved_type = resolve_peer_type_compatibility(g, import, context, node, +// op_nodes, op_types, 2); +// +// bool is_equality_cmp = (bin_op_type == BinOpTypeCmpEq || bin_op_type == BinOpTypeCmpNotEq); +// +// switch (resolved_type->id) { +// case TypeTableEntryIdInvalid: +// return g->builtin_types.entry_invalid; +// +// case TypeTableEntryIdNumLitFloat: +// case TypeTableEntryIdNumLitInt: +// case TypeTableEntryIdInt: +// case TypeTableEntryIdFloat: +// break; +// +// case TypeTableEntryIdBool: +// case TypeTableEntryIdMetaType: +// case TypeTableEntryIdVoid: +// case TypeTableEntryIdPointer: +// case TypeTableEntryIdPureError: +// case TypeTableEntryIdFn: +// case TypeTableEntryIdTypeDecl: +// case TypeTableEntryIdNamespace: +// case TypeTableEntryIdBlock: +// case TypeTableEntryIdGenericFn: +// if (!is_equality_cmp) { +// add_node_error(g, node, +// buf_sprintf("operator not allowed for type '%s'", buf_ptr(&resolved_type->name))); +// return g->builtin_types.entry_invalid; +// } +// break; +// +// case TypeTableEntryIdEnum: +// if (!is_equality_cmp || resolved_type->data.enumeration.gen_field_count != 0) { +// add_node_error(g, node, +// buf_sprintf("operator not allowed for type '%s'", buf_ptr(&resolved_type->name))); +// return g->builtin_types.entry_invalid; +// } +// break; +// +// case TypeTableEntryIdUnreachable: +// case TypeTableEntryIdArray: +// case TypeTableEntryIdStruct: +// case TypeTableEntryIdUndefLit: +// case TypeTableEntryIdNullLit: +// case TypeTableEntryIdMaybe: +// case TypeTableEntryIdErrorUnion: +// case TypeTableEntryIdUnion: +// add_node_error(g, node, +// buf_sprintf("operator not allowed for type '%s'", buf_ptr(&resolved_type->name))); +// return g->builtin_types.entry_invalid; +// +// case TypeTableEntryIdVar: +// zig_unreachable(); +// } +// +// ConstExprValue *op1_val = &get_resolved_expr(*op1)->const_val; +// ConstExprValue *op2_val = &get_resolved_expr(*op2)->const_val; +// if (!op1_val->ok || !op2_val->ok) { +// return g->builtin_types.entry_bool; +// } +// +// +// ConstExprValue *out_val = &get_resolved_expr(node)->const_val; +// eval_const_expr_bin_op(op1_val, op1_type, bin_op_type, op2_val, op2_type, out_val); +// return g->builtin_types.entry_bool; +// +//} +// +//// +//static TypeTableEntry *analyze_if(CodeGen *g, ImportTableEntry *import, BlockContext *parent_context, +// TypeTableEntry *expected_type, AstNode *node, +// AstNode **then_node, AstNode **else_node, bool cond_is_const, bool cond_bool_val) +//{ +// if (!*else_node) { +// *else_node = create_ast_void_node(g, import, node); +// normalize_parent_ptrs(node); +// } +// +// BlockContext *then_context; +// BlockContext *else_context; +// if (cond_is_const) { +// if (cond_bool_val) { +// then_context = parent_context; +// else_context = new_block_context(node, parent_context); +// +// else_context->codegen_excluded = true; +// } else { +// then_context = new_block_context(node, parent_context); +// else_context = parent_context; +// +// then_context->codegen_excluded = true; +// } +// } else { +// then_context = parent_context; +// else_context = parent_context; +// } +// +// TypeTableEntry *then_type = nullptr; +// TypeTableEntry *else_type = nullptr; +// +// if (!then_context->codegen_excluded) { +// then_type = analyze_expression(g, import, then_context, expected_type, *then_node); +// if (then_type->id == TypeTableEntryIdInvalid) { +// return g->builtin_types.entry_invalid; +// } +// } +// if (!else_context->codegen_excluded) { +// else_type = analyze_expression(g, import, else_context, expected_type, *else_node); +// if (else_type->id == TypeTableEntryIdInvalid) { +// return g->builtin_types.entry_invalid; +// } +// } +// +// TypeTableEntry *result_type; +// if (then_context->codegen_excluded) { +// result_type = else_type; +// } else if (else_context->codegen_excluded) { +// result_type = then_type; +// } else if (expected_type) { +// result_type = (then_type->id == TypeTableEntryIdUnreachable) ? else_type : then_type; +// } else { +// AstNode *op_nodes[] = {*then_node, *else_node}; +// TypeTableEntry *op_types[] = {then_type, else_type}; +// result_type = resolve_peer_type_compatibility(g, import, parent_context, node, op_nodes, op_types, 2); +// } +// +// if (!cond_is_const) { +// return add_error_if_type_is_num_lit(g, result_type, node); +// } +// +// ConstExprValue *other_const_val; +// if (cond_bool_val) { +// other_const_val = &get_resolved_expr(*then_node)->const_val; +// } else { +// other_const_val = &get_resolved_expr(*else_node)->const_val; +// } +// if (!other_const_val->ok) { +// return add_error_if_type_is_num_lit(g, result_type, node); +// } +// +// ConstExprValue *const_val = &get_resolved_expr(node)->const_val; +// *const_val = *other_const_val; +// // the condition depends on a compile var, so the entire if statement does too +// const_val->depends_on_compile_var = true; +// return result_type; +//} +// +//static TypeTableEntry *analyze_if_var_expr(CodeGen *g, ImportTableEntry *import, BlockContext *parent_context, +// TypeTableEntry *expected_type, AstNode *node) +//{ +// assert(node->type == NodeTypeIfVarExpr); +// +// BlockContext *child_context = new_block_context(node, parent_context); +// +// analyze_variable_declaration_raw(g, import, child_context, node, &node->data.if_var_expr.var_decl, true, +// nullptr, node->data.if_var_expr.var_is_ptr); +// VariableTableEntry *var = node->data.if_var_expr.var_decl.variable; +// if (var->type->id == TypeTableEntryIdInvalid) { +// return g->builtin_types.entry_invalid; +// } +// AstNode *var_expr_node = node->data.if_var_expr.var_decl.expr; +// ConstExprValue *var_const_val = &get_resolved_expr(var_expr_node)->const_val; +// bool cond_is_const = var_const_val->ok; +// bool cond_bool_val = cond_is_const ? (var_const_val->data.x_maybe != nullptr) : false; +// +// +// AstNode **then_node = &node->data.if_var_expr.then_block; +// AstNode **else_node = &node->data.if_var_expr.else_node; +// +// return analyze_if(g, import, child_context, expected_type, +// node, then_node, else_node, cond_is_const, cond_bool_val); +//} +// +//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, got %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, got %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, got %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, got %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_switch_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, +// TypeTableEntry *expected_type, AstNode *node) +//{ +// AstNode **expr_node = &node->data.switch_expr.expr; +// TypeTableEntry *expr_type = analyze_expression(g, import, context, nullptr, *expr_node); +// ConstExprValue *expr_val = &get_resolved_expr(*expr_node)->const_val; +// if (expr_val->ok && !expr_val->depends_on_compile_var) { +// add_node_error(g, first_executing_node(*expr_node), +// buf_sprintf("value is constant; unnecessary switch statement")); +// } +// ConstExprValue *const_val = &get_resolved_expr(node)->const_val; +// +// +// size_t prong_count = node->data.switch_expr.prongs.length; +// AstNode **peer_nodes = allocate<AstNode*>(prong_count); +// TypeTableEntry **peer_types = allocate<TypeTableEntry*>(prong_count); +// +// bool any_errors = false; +// if (expr_type->id == TypeTableEntryIdInvalid) { +// return expr_type; +// } else if (expr_type->id == TypeTableEntryIdUnreachable) { +// add_node_error(g, first_executing_node(*expr_node), +// buf_sprintf("switch on unreachable expression not allowed")); +// return g->builtin_types.entry_invalid; +// } +// +// +// size_t *field_use_counts = nullptr; +// HashMap<int, AstNode *, int_hash, int_eq> err_use_nodes = {}; +// if (expr_type->id == TypeTableEntryIdEnum) { +// field_use_counts = allocate<size_t>(expr_type->data.enumeration.src_field_count); +// } else if (expr_type->id == TypeTableEntryIdErrorUnion) { +// err_use_nodes.init(10); +// } +// +// size_t *const_chosen_prong_index = &node->data.switch_expr.const_chosen_prong_index; +// *const_chosen_prong_index = SIZE_MAX; +// AstNode *else_prong = nullptr; +// for (size_t prong_i = 0; prong_i < prong_count; prong_i += 1) { +// AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i); +// +// TypeTableEntry *var_type; +// bool var_is_target_expr; +// if (prong_node->data.switch_prong.items.length == 0) { +// if (else_prong) { +// add_node_error(g, prong_node, buf_sprintf("multiple else prongs in switch expression")); +// any_errors = true; +// } else { +// else_prong = prong_node; +// } +// var_type = expr_type; +// var_is_target_expr = true; +// if (*const_chosen_prong_index == SIZE_MAX && expr_val->ok) { +// *const_chosen_prong_index = prong_i; +// } +// } else { +// bool all_agree_on_var_type = true; +// var_type = nullptr; +// +// for (size_t item_i = 0; item_i < prong_node->data.switch_prong.items.length; item_i += 1) { +// AstNode *item_node = prong_node->data.switch_prong.items.at(item_i); +// if (item_node->type == NodeTypeSwitchRange) { +// zig_panic("TODO range in switch statement"); +// } +// +// if (expr_type->id == TypeTableEntryIdEnum) { +// if (item_node->type == NodeTypeSymbol) { +// Buf *field_name = item_node->data.symbol_expr.symbol; +// TypeEnumField *type_enum_field = find_enum_type_field(expr_type, field_name); +// if (type_enum_field) { +// item_node->data.symbol_expr.enum_field = type_enum_field; +// if (!var_type) { +// var_type = type_enum_field->type_entry; +// } +// if (type_enum_field->type_entry != var_type) { +// all_agree_on_var_type = false; +// } +// uint32_t field_index = type_enum_field->value; +// assert(field_use_counts); +// field_use_counts[field_index] += 1; +// if (field_use_counts[field_index] > 1) { +// add_node_error(g, item_node, +// buf_sprintf("duplicate switch value: '%s'", +// buf_ptr(type_enum_field->name))); +// any_errors = true; +// } +// if (!any_errors && expr_val->ok) { +// if (expr_val->data.x_enum.tag == type_enum_field->value) { +// *const_chosen_prong_index = prong_i; +// } +// } +// } else { +// add_node_error(g, item_node, +// buf_sprintf("enum '%s' has no field '%s'", +// buf_ptr(&expr_type->name), buf_ptr(field_name))); +// any_errors = true; +// } +// } else { +// add_node_error(g, item_node, buf_sprintf("expected enum tag name")); +// any_errors = true; +// } +// } else if (expr_type->id == TypeTableEntryIdErrorUnion) { +// if (item_node->type == NodeTypeSymbol) { +// Buf *err_name = item_node->data.symbol_expr.symbol; +// bool is_ok_case = buf_eql_str(err_name, "Ok"); +// auto err_table_entry = is_ok_case ? nullptr: g->error_table.maybe_get(err_name); +// if (is_ok_case || err_table_entry) { +// uint32_t err_value = is_ok_case ? 0 : err_table_entry->value->value; +// item_node->data.symbol_expr.err_value = err_value; +// TypeTableEntry *this_var_type; +// if (is_ok_case) { +// this_var_type = expr_type->data.error.child_type; +// } else { +// this_var_type = g->builtin_types.entry_pure_error; +// } +// if (!var_type) { +// var_type = this_var_type; +// } +// if (this_var_type != var_type) { +// all_agree_on_var_type = false; +// } +// +// // detect duplicate switch values +// auto existing_entry = err_use_nodes.maybe_get(err_value); +// if (existing_entry) { +// add_node_error(g, existing_entry->value, +// buf_sprintf("duplicate switch value: '%s'", buf_ptr(err_name))); +// any_errors = true; +// } else { +// err_use_nodes.put(err_value, item_node); +// } +// +// if (!any_errors && expr_val->ok) { +// if (expr_val->data.x_err.err->value == err_value) { +// *const_chosen_prong_index = prong_i; +// } +// } +// } else { +// add_node_error(g, item_node, +// buf_sprintf("use of undeclared error value '%s'", buf_ptr(err_name))); +// any_errors = true; +// } +// } else { +// add_node_error(g, item_node, buf_sprintf("expected error value name")); +// any_errors = true; +// } +// } else { +// if (!any_errors && expr_val->ok) { +// // note: there is now a function in eval.cpp for doing const expr comparison +// zig_panic("TODO determine if const exprs are equal"); +// } +// TypeTableEntry *item_type = analyze_expression(g, import, context, expr_type, item_node); +// if (item_type->id != TypeTableEntryIdInvalid) { +// ConstExprValue *const_val = &get_resolved_expr(item_node)->const_val; +// if (!const_val->ok) { +// add_node_error(g, item_node, +// buf_sprintf("unable to evaluate constant expression")); +// any_errors = true; +// } +// } +// } +// } +// if (!var_type || !all_agree_on_var_type) { +// var_type = expr_type; +// var_is_target_expr = true; +// } else { +// var_is_target_expr = false; +// } +// } +// +// BlockContext *child_context = new_block_context(node, context); +// prong_node->data.switch_prong.block_context = child_context; +// AstNode *var_node = prong_node->data.switch_prong.var_symbol; +// if (var_node) { +// assert(var_node->type == NodeTypeSymbol); +// Buf *var_name = var_node->data.symbol_expr.symbol; +// var_node->block_context = child_context; +// prong_node->data.switch_prong.var = add_local_var(g, var_node, import, +// child_context, var_name, var_type, true, nullptr); +// prong_node->data.switch_prong.var_is_target_expr = var_is_target_expr; +// } +// } +// +// for (size_t prong_i = 0; prong_i < prong_count; prong_i += 1) { +// AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i); +// BlockContext *child_context = prong_node->data.switch_prong.block_context; +// child_context->codegen_excluded = expr_val->ok && (*const_chosen_prong_index != prong_i); +// +// if (child_context->codegen_excluded) { +// peer_types[prong_i] = g->builtin_types.entry_unreachable; +// } else { +// peer_types[prong_i] = analyze_expression(g, import, child_context, expected_type, +// prong_node->data.switch_prong.expr); +// } +// // This must go after the analyze_expression for +// // prong_node->data.switch_prong.expr because of AST rewriting. +// peer_nodes[prong_i] = prong_node->data.switch_prong.expr; +// } +// +// if (expr_type->id == TypeTableEntryIdEnum && !else_prong) { +// for (uint32_t i = 0; i < expr_type->data.enumeration.src_field_count; i += 1) { +// if (field_use_counts[i] == 0) { +// add_node_error(g, node, +// buf_sprintf("enumeration value '%s' not handled in switch", +// buf_ptr(expr_type->data.enumeration.fields[i].name))); +// any_errors = true; +// } +// } +// } +// +// if (any_errors) { +// return g->builtin_types.entry_invalid; +// } +// +// if (prong_count == 0) { +// add_node_error(g, node, buf_sprintf("switch statement has no prongs")); +// return g->builtin_types.entry_invalid; +// } +// +// TypeTableEntry *result_type = resolve_peer_type_compatibility(g, import, context, node, +// peer_nodes, peer_types, prong_count); +// +// if (expr_val->ok) { +// assert(*const_chosen_prong_index != SIZE_MAX); +// +// *const_val = get_resolved_expr(peer_nodes[*const_chosen_prong_index])->const_val; +// // the target expr depends on a compile var because we have an error on unnecessary +// // switch statement, so the entire switch statement does too +// const_val->depends_on_compile_var = true; +// +// if (!const_val->ok) { +// return add_error_if_type_is_num_lit(g, result_type, node); +// } +// } else { +// return add_error_if_type_is_num_lit(g, result_type, node); +// } +// +// return result_type; +//} +// +//static TypeTableEntry *analyze_return_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, +// TypeTableEntry *expected_type, AstNode *node) +//{ +// if (!node->data.return_expr.expr) { +// node->data.return_expr.expr = create_ast_void_node(g, import, node); +// normalize_parent_ptrs(node); +// } +// +// TypeTableEntry *expected_return_type = get_return_type(context); +// +// switch (node->data.return_expr.kind) { +// case ReturnKindUnconditional: +// zig_panic("TODO moved to ir.cpp"); +// case ReturnKindError: +// { +// TypeTableEntry *expected_err_type; +// if (expected_type) { +// expected_err_type = get_error_type(g, expected_type); +// } else { +// expected_err_type = nullptr; +// } +// TypeTableEntry *resolved_type = analyze_expression(g, import, context, expected_err_type, +// node->data.return_expr.expr); +// if (resolved_type->id == TypeTableEntryIdInvalid) { +// return resolved_type; +// } else if (resolved_type->id == TypeTableEntryIdErrorUnion) { +// if (expected_return_type->id != TypeTableEntryIdErrorUnion && +// expected_return_type->id != TypeTableEntryIdPureError) +// { +// ErrorMsg *msg = add_node_error(g, node, +// buf_sprintf("%%return statement in function with return type '%s'", +// buf_ptr(&expected_return_type->name))); +// AstNode *return_type_node = context->fn_entry->fn_def_node->data.fn_def.fn_proto->data.fn_proto.return_type; +// add_error_note(g, msg, return_type_node, buf_sprintf("function return type here")); +// } +// +// return resolved_type->data.error.child_type; +// } else { +// add_node_error(g, node->data.return_expr.expr, +// buf_sprintf("expected error type, got '%s'", buf_ptr(&resolved_type->name))); +// return g->builtin_types.entry_invalid; +// } +// } +// case ReturnKindMaybe: +// { +// TypeTableEntry *expected_maybe_type; +// if (expected_type) { +// expected_maybe_type = get_maybe_type(g, expected_type); +// } else { +// expected_maybe_type = nullptr; +// } +// TypeTableEntry *resolved_type = analyze_expression(g, import, context, expected_maybe_type, +// node->data.return_expr.expr); +// if (resolved_type->id == TypeTableEntryIdInvalid) { +// return resolved_type; +// } else if (resolved_type->id == TypeTableEntryIdMaybe) { +// if (expected_return_type->id != TypeTableEntryIdMaybe) { +// ErrorMsg *msg = add_node_error(g, node, +// buf_sprintf("?return statement in function with return type '%s'", +// buf_ptr(&expected_return_type->name))); +// AstNode *return_type_node = context->fn_entry->fn_def_node->data.fn_def.fn_proto->data.fn_proto.return_type; +// add_error_note(g, msg, return_type_node, buf_sprintf("function return type here")); +// } +// +// return resolved_type->data.maybe.child_type; +// } else { +// add_node_error(g, node->data.return_expr.expr, +// buf_sprintf("expected maybe type, got '%s'", buf_ptr(&resolved_type->name))); +// return g->builtin_types.entry_invalid; +// } +// } +// } +// zig_unreachable(); +//} +//static TypeTableEntry *analyze_goto_pass1(CodeGen *g, ImportTableEntry *import, BlockContext *context, +// TypeTableEntry *expected_type, AstNode *node) +//{ +// assert(node->type == NodeTypeGoto); +// +// FnTableEntry *fn_table_entry = context->fn_entry; +// assert(fn_table_entry); +// +// fn_table_entry->goto_list.append(node); +// +// return g->builtin_types.entry_unreachable; +//} +// +//static TypeTableEntry *analyze_enum_value_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, +// AstNode *field_access_node, AstNode *value_node, TypeTableEntry *enum_type, Buf *field_name, +// AstNode *out_node) +//{ +// assert(field_access_node->type == NodeTypeFieldAccessExpr); +// +// TypeEnumField *type_enum_field = find_enum_type_field(enum_type, field_name); +// if (type_enum_field->type_entry->id == TypeTableEntryIdInvalid) { +// return g->builtin_types.entry_invalid; +// } +// +// field_access_node->data.field_access_expr.type_enum_field = type_enum_field; +// +// if (type_enum_field) { +// if (value_node) { +// AstNode **value_node_ptr = value_node->parent_field; +// TypeTableEntry *value_type = analyze_expression(g, import, context, +// type_enum_field->type_entry, value_node); +// +// if (value_type->id == TypeTableEntryIdInvalid) { +// return g->builtin_types.entry_invalid; +// } +// +// StructValExprCodeGen *codegen = &field_access_node->data.field_access_expr.resolved_struct_val_expr; +// codegen->type_entry = enum_type; +// codegen->source_node = field_access_node; +// +// ConstExprValue *value_const_val = &get_resolved_expr(*value_node_ptr)->const_val; +// if (value_const_val->ok) { +// ConstExprValue *const_val = &get_resolved_expr(out_node)->const_val; +// const_val->ok = true; +// const_val->data.x_enum.tag = type_enum_field->value; +// const_val->data.x_enum.payload = value_const_val; +// } else { +// if (context->fn_entry) { +// context->fn_entry->struct_val_expr_alloca_list.append(codegen); +// } else { +// add_node_error(g, *value_node_ptr, buf_sprintf("unable to evaluate constant expression")); +// return g->builtin_types.entry_invalid; +// } +// } +// } else if (type_enum_field->type_entry->id != TypeTableEntryIdVoid) { +// add_node_error(g, field_access_node, +// buf_sprintf("enum value '%s.%s' requires parameter of type '%s'", +// buf_ptr(&enum_type->name), +// buf_ptr(field_name), +// buf_ptr(&type_enum_field->type_entry->name))); +// } else { +// Expr *expr = get_resolved_expr(out_node); +// expr->const_val.ok = true; +// expr->const_val.data.x_enum.tag = type_enum_field->value; +// expr->const_val.data.x_enum.payload = nullptr; +// } +// } else { +// add_node_error(g, field_access_node, +// buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name), +// buf_ptr(&enum_type->name))); +// } +// 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) +//{ +// assert(node->type == NodeTypeSliceExpr); +// +// TypeTableEntry *array_type = analyze_expression(g, import, context, nullptr, +// node->data.slice_expr.array_ref_expr); +// +// TypeTableEntry *return_type; +// +// if (array_type->id == TypeTableEntryIdInvalid) { +// return_type = g->builtin_types.entry_invalid; +// } else if (array_type->id == TypeTableEntryIdArray) { +// return_type = get_slice_type(g, array_type->data.array.child_type, +// node->data.slice_expr.is_const); +// } else if (array_type->id == TypeTableEntryIdPointer) { +// return_type = get_slice_type(g, array_type->data.pointer.child_type, +// node->data.slice_expr.is_const); +// } else if (array_type->id == TypeTableEntryIdStruct && +// array_type->data.structure.is_slice) +// { +// return_type = get_slice_type(g, +// array_type->data.structure.fields[0].type_entry->data.pointer.child_type, +// node->data.slice_expr.is_const); +// } else { +// add_node_error(g, node, +// buf_sprintf("slice of non-array type '%s'", buf_ptr(&array_type->name))); +// return_type = g->builtin_types.entry_invalid; +// } +// +// if (return_type->id != TypeTableEntryIdInvalid) { +// node->data.slice_expr.resolved_struct_val_expr.type_entry = return_type; +// node->data.slice_expr.resolved_struct_val_expr.source_node = node; +// context->fn_entry->struct_val_expr_alloca_list.append(&node->data.slice_expr.resolved_struct_val_expr); +// } +// +// analyze_expression(g, import, context, g->builtin_types.entry_usize, node->data.slice_expr.start); +// +// if (node->data.slice_expr.end) { +// analyze_expression(g, import, context, g->builtin_types.entry_usize, node->data.slice_expr.end); +// } +// +// return return_type; +//} +// +//static TypeTableEntry *analyze_array_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, +// AstNode *node, LValPurpose purpose) +//{ +// TypeTableEntry *array_type = analyze_expression(g, import, context, nullptr, +// node->data.array_access_expr.array_ref_expr); +// +// TypeTableEntry *return_type; +// +// if (array_type->id == TypeTableEntryIdInvalid) { +// return_type = g->builtin_types.entry_invalid; +// } else if (array_type->id == TypeTableEntryIdArray) { +// if (array_type->data.array.len == 0) { +// add_node_error(g, node, buf_sprintf("out of bounds array access")); +// } +// return_type = array_type->data.array.child_type; +// } else if (array_type->id == TypeTableEntryIdPointer) { +// if (array_type->data.pointer.is_const && purpose == LValPurposeAssign) { +// add_node_error(g, node, buf_sprintf("cannot assign to constant")); +// return g->builtin_types.entry_invalid; +// } +// return_type = array_type->data.pointer.child_type; +// } else if (array_type->id == TypeTableEntryIdStruct && +// array_type->data.structure.is_slice) +// { +// TypeTableEntry *pointer_type = array_type->data.structure.fields[0].type_entry; +// if (pointer_type->data.pointer.is_const && purpose == LValPurposeAssign) { +// add_node_error(g, node, buf_sprintf("cannot assign to constant")); +// return g->builtin_types.entry_invalid; +// } +// return_type = pointer_type->data.pointer.child_type; +// } else { +// add_node_error(g, node, +// buf_sprintf("array access of non-array type '%s'", buf_ptr(&array_type->name))); +// return_type = g->builtin_types.entry_invalid; +// } +// +// analyze_expression(g, import, context, g->builtin_types.entry_usize, node->data.array_access_expr.subscript); +// +// return return_type; +//} +// +//static TypeTableEntry *analyze_logic_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, +// AstNode *node) +//{ +// assert(node->type == NodeTypeBinOpExpr); +// BinOpType bin_op_type = node->data.bin_op_expr.bin_op; +// +// AstNode *op1 = node->data.bin_op_expr.op1; +// AstNode *op2 = node->data.bin_op_expr.op2; +// TypeTableEntry *op1_type = analyze_expression(g, import, context, g->builtin_types.entry_bool, op1); +// TypeTableEntry *op2_type = analyze_expression(g, import, context, g->builtin_types.entry_bool, op2); +// +// if (op1_type->id == TypeTableEntryIdInvalid || +// op2_type->id == TypeTableEntryIdInvalid) +// { +// return g->builtin_types.entry_invalid; +// } +// +// ConstExprValue *op1_val = &get_resolved_expr(op1)->const_val; +// ConstExprValue *op2_val = &get_resolved_expr(op2)->const_val; +// if (!op1_val->ok || !op2_val->ok) { +// return g->builtin_types.entry_bool; +// } +// +// ConstExprValue *out_val = &get_resolved_expr(node)->const_val; +// eval_const_expr_bin_op(op1_val, op1_type, bin_op_type, op2_val, op2_type, out_val); +// return g->builtin_types.entry_bool; +//} +// +//static TypeTableEntry *analyze_array_mult(CodeGen *g, ImportTableEntry *import, BlockContext *context, +// TypeTableEntry *expected_type, AstNode *node) +//{ +// assert(node->type == NodeTypeBinOpExpr); +// assert(node->data.bin_op_expr.bin_op == BinOpTypeArrayMult); +// +// AstNode **op1 = node->data.bin_op_expr.op1->parent_field; +// AstNode **op2 = node->data.bin_op_expr.op2->parent_field; +// +// TypeTableEntry *op1_type = analyze_expression(g, import, context, nullptr, *op1); +// TypeTableEntry *op2_type = analyze_expression(g, import, context, nullptr, *op2); +// +// if (op1_type->id == TypeTableEntryIdInvalid || +// op2_type->id == TypeTableEntryIdInvalid) +// { +// return g->builtin_types.entry_invalid; +// } +// +// ConstExprValue *op1_val = &get_resolved_expr(*op1)->const_val; +// ConstExprValue *op2_val = &get_resolved_expr(*op2)->const_val; +// +// AstNode *bad_node; +// if (!op1_val->ok) { +// bad_node = *op1; +// } else if (!op2_val->ok) { +// bad_node = *op2; +// } else { +// bad_node = nullptr; +// } +// if (bad_node) { +// add_node_error(g, bad_node, buf_sprintf("array multiplication requires constant expression")); +// return g->builtin_types.entry_invalid; +// } +// +// if (op1_type->id != TypeTableEntryIdArray) { +// add_node_error(g, *op1, +// buf_sprintf("expected array type, got '%s'", buf_ptr(&op1_type->name))); +// return g->builtin_types.entry_invalid; +// } +// +// if (op2_type->id != TypeTableEntryIdNumLitInt && +// op2_type->id != TypeTableEntryIdInt) +// { +// add_node_error(g, *op2, buf_sprintf("expected integer type, got '%s'", buf_ptr(&op2_type->name))); +// return g->builtin_types.entry_invalid; +// } +// +// if (op2_val->data.x_bignum.is_negative) { +// add_node_error(g, *op2, buf_sprintf("expected positive number")); +// return g->builtin_types.entry_invalid; +// } +// +// ConstExprValue *const_val = &get_resolved_expr(node)->const_val; +// const_val->ok = true; +// const_val->depends_on_compile_var = op1_val->depends_on_compile_var || op2_val->depends_on_compile_var; +// +// TypeTableEntry *child_type = op1_type->data.array.child_type; +// BigNum old_array_len; +// bignum_init_unsigned(&old_array_len, op1_type->data.array.len); +// +// BigNum new_array_len; +// if (bignum_mul(&new_array_len, &old_array_len, &op2_val->data.x_bignum)) { +// add_node_error(g, node, buf_sprintf("operation results in overflow")); +// return g->builtin_types.entry_invalid; +// } +// +// uint64_t old_array_len_bare = op1_type->data.array.len; +// uint64_t operand_amt = op2_val->data.x_bignum.data.x_uint; +// +// uint64_t new_array_len_bare = new_array_len.data.x_uint; +// const_val->data.x_array.fields = allocate<ConstExprValue*>(new_array_len_bare); +// +// uint64_t i = 0; +// for (uint64_t x = 0; x < operand_amt; x += 1) { +// for (uint64_t y = 0; y < old_array_len_bare; y += 1) { +// const_val->data.x_array.fields[i] = op1_val->data.x_array.fields[y]; +// i += 1; +// } +// } +// +// return get_array_type(g, child_type, new_array_len_bare); +//} +// +//static TypeTableEntry *analyze_unwrap_error_expr(CodeGen *g, ImportTableEntry *import, +// BlockContext *parent_context, TypeTableEntry *expected_type, AstNode *node) +//{ +// AstNode *op1 = node->data.unwrap_err_expr.op1; +// AstNode *op2 = node->data.unwrap_err_expr.op2; +// AstNode *var_node = node->data.unwrap_err_expr.symbol; +// +// TypeTableEntry *lhs_type = analyze_expression(g, import, parent_context, nullptr, op1); +// if (lhs_type->id == TypeTableEntryIdInvalid) { +// return lhs_type; +// } else if (lhs_type->id == TypeTableEntryIdErrorUnion) { +// TypeTableEntry *child_type = lhs_type->data.error.child_type; +// BlockContext *child_context; +// if (var_node) { +// child_context = new_block_context(node, parent_context); +// var_node->block_context = child_context; +// Buf *var_name = var_node->data.symbol_expr.symbol; +// node->data.unwrap_err_expr.var = add_local_var(g, var_node, import, child_context, var_name, +// g->builtin_types.entry_pure_error, true, nullptr); +// } else { +// child_context = parent_context; +// } +// +// analyze_expression(g, import, child_context, child_type, op2); +// return child_type; +// } else { +// add_node_error(g, op1, +// buf_sprintf("expected error type, got '%s'", buf_ptr(&lhs_type->name))); +// return g->builtin_types.entry_invalid; +// } +//} +// +// +//static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTableEntry *import, +// BlockContext *context, AstNode *source_node, +// AstNodeVariableDeclaration *variable_declaration, +// bool expr_is_maybe, AstNode *decl_node, bool var_is_ptr) +//{ +// bool is_const = variable_declaration->is_const; +// bool is_export = (variable_declaration->top_level_decl.visib_mod == VisibModExport); +// bool is_extern = variable_declaration->is_extern; +// +// TypeTableEntry *explicit_type = nullptr; +// if (variable_declaration->type != nullptr) { +// explicit_type = analyze_type_expr(g, import, context, variable_declaration->type); +// if (explicit_type->id == TypeTableEntryIdUnreachable) { +// add_node_error(g, variable_declaration->type, +// buf_sprintf("variable of type 'unreachable' not allowed")); +// explicit_type = g->builtin_types.entry_invalid; +// } +// } +// +// TypeTableEntry *implicit_type = nullptr; +// if (explicit_type && explicit_type->id == TypeTableEntryIdInvalid) { +// implicit_type = explicit_type; +// } else if (variable_declaration->expr) { +// implicit_type = analyze_expression(g, import, context, explicit_type, variable_declaration->expr); +// if (implicit_type->id == TypeTableEntryIdInvalid) { +// // ignore the poison value +// } else if (expr_is_maybe) { +// if (implicit_type->id == TypeTableEntryIdMaybe) { +// if (var_is_ptr) { +// // TODO if the expression is constant, can't get pointer to it +// implicit_type = get_pointer_to_type(g, implicit_type->data.maybe.child_type, false); +// } else { +// implicit_type = implicit_type->data.maybe.child_type; +// } +// } else { +// add_node_error(g, variable_declaration->expr, buf_sprintf("expected maybe type")); +// implicit_type = g->builtin_types.entry_invalid; +// } +// } else if (implicit_type->id == TypeTableEntryIdUnreachable) { +// add_node_error(g, source_node, +// buf_sprintf("variable initialization is unreachable")); +// implicit_type = g->builtin_types.entry_invalid; +// } else if ((!is_const || is_export) && +// (implicit_type->id == TypeTableEntryIdNumLitFloat || +// implicit_type->id == TypeTableEntryIdNumLitInt)) +// { +// add_node_error(g, source_node, buf_sprintf("unable to infer variable type")); +// implicit_type = g->builtin_types.entry_invalid; +// } else if (implicit_type->id == TypeTableEntryIdMetaType && !is_const) { +// add_node_error(g, source_node, buf_sprintf("variable of type 'type' must be constant")); +// implicit_type = g->builtin_types.entry_invalid; +// } +// if (implicit_type->id != TypeTableEntryIdInvalid && !context->fn_entry) { +// ConstExprValue *const_val = &get_resolved_expr(variable_declaration->expr)->const_val; +// if (!const_val->ok) { +// add_node_error(g, first_executing_node(variable_declaration->expr), +// buf_sprintf("global variable initializer requires constant expression")); +// } +// } +// } else if (!is_extern) { +// add_node_error(g, source_node, buf_sprintf("variables must be initialized")); +// implicit_type = g->builtin_types.entry_invalid; +// } +// +// TypeTableEntry *type = explicit_type != nullptr ? explicit_type : implicit_type; +// assert(type != nullptr); // should have been caught by the parser +// +// VariableTableEntry *var = add_local_var(g, source_node, import, context, +// variable_declaration->symbol, type, is_const, +// expr_is_maybe ? nullptr : variable_declaration->expr); +// +// variable_declaration->variable = var; +// +// return var; +//} +// +//static VariableTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableEntry *import, +// BlockContext *context, TypeTableEntry *expected_type, AstNode *node) +//{ +// AstNodeVariableDeclaration *variable_declaration = &node->data.variable_declaration; +// return analyze_variable_declaration_raw(g, import, context, node, variable_declaration, +// false, nullptr, false); +//} +// +//static TypeTableEntry *analyze_array_type(CodeGen *g, ImportTableEntry *import, BlockContext *context, +// TypeTableEntry *expected_type, AstNode *node) +//{ +// AstNode *size_node = node->data.array_type.size; +// +// TypeTableEntry *child_type = analyze_type_expr_pointer_only(g, import, context, +// node->data.array_type.child_type, true); +// +// if (child_type->id == TypeTableEntryIdUnreachable) { +// add_node_error(g, node, buf_create_from_str("array of unreachable not allowed")); +// return g->builtin_types.entry_invalid; +// } else if (child_type->id == TypeTableEntryIdInvalid) { +// return g->builtin_types.entry_invalid; +// } +// +// if (size_node) { +// child_type = analyze_type_expr(g, import, context, node->data.array_type.child_type); +// TypeTableEntry *size_type = analyze_expression(g, import, context, +// g->builtin_types.entry_usize, size_node); +// if (size_type->id == TypeTableEntryIdInvalid) { +// return g->builtin_types.entry_invalid; +// } +// +// ConstExprValue *const_val = &get_resolved_expr(size_node)->const_val; +// if (const_val->ok) { +// if (const_val->data.x_bignum.is_negative) { +// add_node_error(g, size_node, +// buf_sprintf("array size %s is negative", +// buf_ptr(bignum_to_buf(&const_val->data.x_bignum)))); +// return g->builtin_types.entry_invalid; +// } else { +// return resolve_expr_const_val_as_type(g, node, +// get_array_type(g, child_type, const_val->data.x_bignum.data.x_uint), false); +// } +// } else if (context->fn_entry) { +// return resolve_expr_const_val_as_type(g, node, +// get_slice_type(g, child_type, node->data.array_type.is_const), false); +// } else { +// add_node_error(g, first_executing_node(size_node), +// buf_sprintf("unable to evaluate constant expression")); +// return g->builtin_types.entry_invalid; +// } +// } else { +// TypeTableEntry *slice_type = get_slice_type(g, child_type, node->data.array_type.is_const); +// return resolve_expr_const_val_as_type(g, node, slice_type, false); +// } +//} +// +//static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, +// TypeTableEntry *expected_type, AstNode *node) +//{ +// assert(node->type == NodeTypeWhileExpr); +// +// AstNode **condition_node = &node->data.while_expr.condition; +// AstNode *while_body_node = node->data.while_expr.body; +// AstNode **continue_expr_node = &node->data.while_expr.continue_expr; +// +// TypeTableEntry *condition_type = analyze_expression(g, import, context, +// g->builtin_types.entry_bool, *condition_node); +// +// if (*continue_expr_node) { +// analyze_expression(g, import, context, g->builtin_types.entry_void, *continue_expr_node); +// } +// +// BlockContext *child_context = new_block_context(node, context); +// child_context->parent_loop_node = node; +// +// analyze_expression(g, import, child_context, g->builtin_types.entry_void, while_body_node); +// +// +// TypeTableEntry *expr_return_type = g->builtin_types.entry_void; +// +// if (condition_type->id == TypeTableEntryIdInvalid) { +// expr_return_type = g->builtin_types.entry_invalid; +// } else { +// // if the condition is a simple constant expression and there are no break statements +// // then the return type is unreachable +// ConstExprValue *const_val = &get_resolved_expr(*condition_node)->const_val; +// if (const_val->ok) { +// if (const_val->data.x_bool) { +// node->data.while_expr.condition_always_true = true; +// if (!node->data.while_expr.contains_break) { +// expr_return_type = g->builtin_types.entry_unreachable; +// } +// } +// } +// } +// +// return expr_return_type; +//} +// +//static TypeTableEntry *analyze_break_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, +// TypeTableEntry *expected_type, AstNode *node) +//{ +// assert(node->type == NodeTypeBreak); +// +// AstNode *loop_node = context->parent_loop_node; +// if (loop_node) { +// if (loop_node->type == NodeTypeWhileExpr) { +// loop_node->data.while_expr.contains_break = true; +// } else if (loop_node->type == NodeTypeForExpr) { +// loop_node->data.for_expr.contains_break = true; +// } else { +// zig_unreachable(); +// } +// } else { +// add_node_error(g, node, buf_sprintf("'break' expression outside loop")); +// } +// return g->builtin_types.entry_unreachable; +//} +// +//static TypeTableEntry *analyze_continue_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, +// TypeTableEntry *expected_type, AstNode *node) +//{ +// AstNode *loop_node = context->parent_loop_node; +// if (loop_node) { +// if (loop_node->type == NodeTypeWhileExpr) { +// loop_node->data.while_expr.contains_continue = true; +// } else if (loop_node->type == NodeTypeForExpr) { +// loop_node->data.for_expr.contains_continue = true; +// } else { +// zig_unreachable(); +// } +// } else { +// add_node_error(g, node, buf_sprintf("'continue' expression outside loop")); +// } +// return g->builtin_types.entry_unreachable; +//} +// +//static TypeTableEntry *analyze_defer(CodeGen *g, ImportTableEntry *import, BlockContext *parent_context, +// TypeTableEntry *expected_type, AstNode *node) +//{ +// if (!parent_context->fn_entry) { +// add_node_error(g, node, buf_sprintf("defer expression outside function definition")); +// return g->builtin_types.entry_invalid; +// } +// +// if (!node->data.defer.expr) { +// add_node_error(g, node, buf_sprintf("defer expects an expression")); +// return g->builtin_types.entry_void; +// } +// +// node->data.defer.child_block = new_block_context(node, parent_context); +// +// TypeTableEntry *resolved_type = analyze_expression(g, import, parent_context, nullptr, +// node->data.defer.expr); +// validate_voided_expr(g, node->data.defer.expr, resolved_type); +// +// return g->builtin_types.entry_void; +//} +// +//static TypeTableEntry *analyze_string_literal_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, +// TypeTableEntry *expected_type, AstNode *node) +//{ +// if (node->data.string_literal.c) { +// return resolve_expr_const_val_as_c_string_lit(g, node, node->data.string_literal.buf); +// } else { +// return resolve_expr_const_val_as_string_lit(g, node, node->data.string_literal.buf); +// } +//} +// +//static TypeTableEntry *analyze_block_expr(CodeGen *g, ImportTableEntry *import, BlockContext *parent_context, +// TypeTableEntry *expected_type, AstNode *node) +//{ +// BlockContext *child_context = new_block_context(node, parent_context); +// node->data.block.child_block = child_context; +// TypeTableEntry *return_type = g->builtin_types.entry_void; +// +// for (size_t i = 0; i < node->data.block.statements.length; i += 1) { +// AstNode *child = node->data.block.statements.at(i); +// if (child->type == NodeTypeLabel) { +// FnTableEntry *fn_table_entry = child_context->fn_entry; +// assert(fn_table_entry); +// +// LabelTableEntry *label = allocate<LabelTableEntry>(1); +// label->decl_node = child; +// label->entered_from_fallthrough = (return_type->id != TypeTableEntryIdUnreachable); +// +// child->block_context = child_context; +// child->data.label.label_entry = label; +// fn_table_entry->all_labels.append(label); +// +// child_context->label_table.put(child->data.label.name, label); +// +// return_type = g->builtin_types.entry_void; +// continue; +// } +// if (return_type->id == TypeTableEntryIdUnreachable) { +// if (is_node_void_expr(child)) { +// // {unreachable;void;void} is allowed. +// // ignore void statements once we enter unreachable land. +// analyze_expression(g, import, child_context, g->builtin_types.entry_void, child); +// continue; +// } +// add_node_error(g, first_executing_node(child), buf_sprintf("unreachable code")); +// break; +// } +// bool is_last = (i == node->data.block.statements.length - 1); +// TypeTableEntry *passed_expected_type = is_last ? expected_type : nullptr; +// return_type = analyze_expression(g, import, child_context, passed_expected_type, child); +// if (child->type == NodeTypeDefer && return_type->id != TypeTableEntryIdInvalid) { +// // defer starts a new block context +// child_context = child->data.defer.child_block; +// assert(child_context); +// } +// if (!is_last) { +// validate_voided_expr(g, child, return_type); +// } +// } +// node->data.block.nested_block = child_context; +// +// ConstExprValue *const_val = &node->data.block.resolved_expr.const_val; +// if (node->data.block.statements.length == 0) { +// const_val->ok = true; +// } else if (node->data.block.statements.length == 1) { +// AstNode *only_node = node->data.block.statements.at(0); +// ConstExprValue *other_const_val = &get_resolved_expr(only_node)->const_val; +// if (other_const_val->ok) { +// *const_val = *other_const_val; +// } +// } +// +// return return_type; +//} +// +//static TypeTableEntry *analyze_asm_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, +// TypeTableEntry *expected_type, AstNode *node) +//{ +// mark_impure_fn(g, context, node); +// +// node->data.asm_expr.return_count = 0; +// TypeTableEntry *return_type = g->builtin_types.entry_void; +// for (size_t i = 0; i < node->data.asm_expr.output_list.length; i += 1) { +// AsmOutput *asm_output = node->data.asm_expr.output_list.at(i); +// if (asm_output->return_type) { +// node->data.asm_expr.return_count += 1; +// return_type = analyze_type_expr(g, import, context, asm_output->return_type); +// if (node->data.asm_expr.return_count > 1) { +// add_node_error(g, node, +// buf_sprintf("inline assembly allows up to one output value")); +// break; +// } +// } else { +// Buf *variable_name = asm_output->variable_name; +// VariableTableEntry *var = find_variable(g, context, variable_name); +// if (var) { +// asm_output->variable = var; +// return var->type; +// } else { +// add_node_error(g, node, +// buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name))); +// return g->builtin_types.entry_invalid; +// } +// } +// } +// for (size_t i = 0; i < node->data.asm_expr.input_list.length; i += 1) { +// AsmInput *asm_input = node->data.asm_expr.input_list.at(i); +// analyze_expression(g, import, context, nullptr, asm_input->expr); +// } +// +// return return_type; +//} +// +//static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *import, +// BlockContext *context, AstNode *node, Buf *err_name) +//{ +// auto err_table_entry = g->error_table.maybe_get(err_name); +// +// if (err_table_entry) { +// return resolve_expr_const_val_as_err(g, node, err_table_entry->value); +// } +// +// add_node_error(g, node, +// buf_sprintf("use of undeclared error value '%s'", buf_ptr(err_name))); +// +// return g->builtin_types.entry_invalid; +//} +// +//static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, +// TypeTableEntry *expected_type, AstNode *node, bool pointer_only) +//{ +// Buf *variable_name = node->data.symbol_expr.symbol; +// +// auto primitive_table_entry = g->primitive_type_table.maybe_get(variable_name); +// if (primitive_table_entry) { +// return resolve_expr_const_val_as_type(g, node, primitive_table_entry->value, false); +// } +// +// VariableTableEntry *var = find_variable(g, context, variable_name); +// if (var) { +// TypeTableEntry *var_type = analyze_var_ref(g, node, var, context, false); +// return var_type; +// } +// +// AstNode *decl_node = find_decl(context, variable_name); +// if (decl_node) { +// return analyze_decl_ref(g, node, decl_node, pointer_only, context, false); +// } +// +// if (import->any_imports_failed) { +// // skip the error message since we had a failing import in this file +// // if an import breaks we don't need 9999 undeclared identifier errors +// return g->builtin_types.entry_invalid; +// } +// +// mark_impure_fn(g, context, node); +// add_node_error(g, node, buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name))); +// return g->builtin_types.entry_invalid; +//} +// +//static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNode *decl_node, +// bool pointer_only, BlockContext *block_context, bool depends_on_compile_var) +//{ +// resolve_top_level_decl(g, decl_node, pointer_only); +// TopLevelDecl *tld = get_as_top_level_decl(decl_node); +// if (tld->resolution == TldResolutionInvalid) { +// return g->builtin_types.entry_invalid; +// } +// +// if (decl_node->type == NodeTypeVariableDeclaration) { +// VariableTableEntry *var = decl_node->data.variable_declaration.variable; +// return analyze_var_ref(g, source_node, var, block_context, depends_on_compile_var); +// } else if (decl_node->type == NodeTypeFnProto) { +// FnTableEntry *fn_entry = decl_node->data.fn_proto.fn_table_entry; +// assert(fn_entry->type_entry); +// if (fn_entry->type_entry->id == TypeTableEntryIdGenericFn) { +// return resolve_expr_const_val_as_generic_fn(g, source_node, fn_entry->type_entry, depends_on_compile_var); +// } else { +// return resolve_expr_const_val_as_fn(g, source_node, fn_entry, depends_on_compile_var); +// } +// } else if (decl_node->type == NodeTypeContainerDecl) { +// if (decl_node->data.struct_decl.generic_params.length > 0) { +// TypeTableEntry *type_entry = decl_node->data.struct_decl.generic_fn_type; +// assert(type_entry); +// return resolve_expr_const_val_as_generic_fn(g, source_node, type_entry, depends_on_compile_var); +// } else { +// return resolve_expr_const_val_as_type(g, source_node, decl_node->data.struct_decl.type_entry, +// depends_on_compile_var); +// } +// } else if (decl_node->type == NodeTypeTypeDecl) { +// return resolve_expr_const_val_as_type(g, source_node, decl_node->data.type_decl.child_type_entry, +// depends_on_compile_var); +// } else { +// zig_unreachable(); +// } +//} +// +//static TypeTableEntry *analyze_var_ref(CodeGen *g, AstNode *source_node, VariableTableEntry *var, +// BlockContext *context, bool depends_on_compile_var) +//{ +// get_resolved_expr(source_node)->variable = var; +// if (!var_is_pure(var, context)) { +// mark_impure_fn(g, context, source_node); +// } +// if (var->src_is_const && var->val_node) { +// ConstExprValue *other_const_val = &get_resolved_expr(var->val_node)->const_val; +// if (other_const_val->ok) { +// return resolve_expr_const_val_as_other_expr(g, source_node, var->val_node, +// depends_on_compile_var || var->force_depends_on_compile_var); +// } +// } +// return var->type; +//} +// +//static TypeTableEntry *analyze_null_literal_expr(CodeGen *g, ImportTableEntry *import, +// BlockContext *block_context, TypeTableEntry *expected_type, AstNode *node) +//{ +// assert(node->type == NodeTypeNullLiteral); +// +// ConstExprValue *const_val = &get_resolved_expr(node)->const_val; +// const_val->ok = true; +// +// return g->builtin_types.entry_null; +//} +// +//static TypeTableEntry *analyze_undefined_literal_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, +// TypeTableEntry *expected_type, AstNode *node) +//{ +// assert(node->type == NodeTypeUndefinedLiteral); +// +// Expr *expr = get_resolved_expr(node); +// ConstExprValue *const_val = &expr->const_val; +// +// const_val->ok = true; +// const_val->special = ConstValSpecialUndef; +// +// return expected_type ? expected_type : g->builtin_types.entry_undef; +//} +// +//static TypeTableEntry *analyze_zeroes_literal_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, +// TypeTableEntry *expected_type, AstNode *node) +//{ +// Expr *expr = get_resolved_expr(node); +// ConstExprValue *const_val = &expr->const_val; +// +// const_val->ok = true; +// const_val->special = ConstValSpecialZeroes; +// +// return expected_type ? expected_type : g->builtin_types.entry_undef; +//} +// +//static TypeTableEntry *analyze_number_literal_expr(CodeGen *g, ImportTableEntry *import, +// BlockContext *block_context, TypeTableEntry *expected_type, AstNode *node) +//{ +// return resolve_expr_const_val_as_bignum(g, node, expected_type, node->data.number_literal.bignum, false); +//} +// +//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 bool var_is_pure(VariableTableEntry *var, BlockContext *context) { +// if (var->block_context->fn_entry == context->fn_entry) { +// // variable was declared in the current function, so it's OK. +// return true; +// } +// return var->src_is_const && var->type->deep_const; +//} +// +//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")); +// } else if (type_entry->id == TypeTableEntryIdErrorUnion) { +// add_node_error(g, first_executing_node(source_node), buf_sprintf("statement ignores error value")); +// } +//} +// |
