Commit 12fcbecbf8
Changed files (8)
src/all_types.hpp
@@ -115,14 +115,26 @@ enum ConstValSpecial {
ConstValSpecialZeroes,
};
+enum RuntimeHintErrorUnion {
+ RuntimeHintErrorUnionUnknown,
+ RuntimeHintErrorUnionError,
+ RuntimeHintErrorUnionNonError,
+};
+
+enum RuntimeHintMaybe {
+ RuntimeHintMaybeUnknown,
+ RuntimeHintMaybeNull, // TODO is this value even possible? if this is the case it might mean the const value is compile time known.
+ RuntimeHintMaybeNonNull,
+};
+
struct ConstExprValue {
ConstValSpecial special;
bool depends_on_compile_var;
LLVMValueRef llvm_value;
LLVMValueRef llvm_global;
- // populated if val_type == ConstValTypeOk
union {
+ // populated if special == ConstValSpecialStatic
BigNum x_bignum;
bool x_bool;
FnTableEntry *x_fn;
@@ -137,6 +149,10 @@ struct ConstExprValue {
ConstPtrValue x_ptr;
ImportTableEntry *x_import;
Scope *x_block;
+
+ // populated if special == ConstValSpecialRuntime
+ RuntimeHintErrorUnion rh_error_union;
+ RuntimeHintMaybe rh_maybe;
} data;
};
@@ -412,10 +428,6 @@ enum CastOp {
CastOpIntToPtr,
CastOpWidenOrShorten,
CastOpToUnknownSizeArray,
- CastOpMaybeWrap,
- CastOpNullToMaybe,
- CastOpErrorWrap,
- CastOpPureErrorWrap,
CastOpPointerReinterpret,
CastOpErrToInt,
CastOpIntToFloat,
@@ -1394,6 +1406,7 @@ enum IrInstructionId {
IrInstructionIdSizeOf,
IrInstructionIdTestNull,
IrInstructionIdUnwrapMaybe,
+ IrInstructionIdMaybeWrap,
IrInstructionIdEnumTag,
IrInstructionIdClz,
IrInstructionIdCtz,
@@ -1426,6 +1439,12 @@ enum IrInstructionId {
IrInstructionIdFrameAddress,
IrInstructionIdAlignOf,
IrInstructionIdOverflowOp,
+ IrInstructionIdTestErr,
+ IrInstructionIdUnwrapErrCode,
+ IrInstructionIdUnwrapErrPayload,
+ IrInstructionIdErrUnionTypeChild,
+ IrInstructionIdErrWrapCode,
+ IrInstructionIdErrWrapPayload,
};
struct IrInstruction {
@@ -1439,7 +1458,6 @@ struct IrInstruction {
// if ref_count is zero, instruction can be omitted in codegen
size_t ref_count;
IrInstruction *other;
- ReturnKnowledge return_knowledge;
};
struct IrInstructionCondBr {
@@ -1504,10 +1522,6 @@ enum IrUnOp {
IrUnOpDereference,
IrUnOpError,
IrUnOpMaybe,
- IrUnOpUnwrapError,
- IrUnOpUnwrapMaybe,
- IrUnOpErrorReturn,
- IrUnOpMaybeReturn,
};
struct IrInstructionUnOp {
@@ -2004,6 +2018,53 @@ struct IrInstructionAlignOf {
IrInstruction *type_value;
};
+// returns true if error, returns false if not error
+struct IrInstructionTestErr {
+ IrInstruction base;
+
+ IrInstruction *value;
+};
+
+struct IrInstructionUnwrapErrCode {
+ IrInstruction base;
+
+ IrInstruction *value;
+};
+
+struct IrInstructionUnwrapErrPayload {
+ IrInstruction base;
+
+ IrInstruction *value;
+ bool safety_check_on;
+};
+
+struct IrInstructionErrUnionTypeChild {
+ IrInstruction base;
+
+ IrInstruction *type_value;
+};
+
+struct IrInstructionMaybeWrap {
+ IrInstruction base;
+
+ IrInstruction *value;
+ LLVMValueRef tmp_ptr;
+};
+
+struct IrInstructionErrWrapPayload {
+ IrInstruction base;
+
+ IrInstruction *value;
+ LLVMValueRef tmp_ptr;
+};
+
+struct IrInstructionErrWrapCode {
+ IrInstruction base;
+
+ IrInstruction *value;
+ LLVMValueRef tmp_ptr;
+};
+
enum LValPurpose {
LValPurposeNone,
LValPurposeAssign,
@@ -2019,4 +2080,7 @@ static const size_t maybe_null_index = 1;
static const size_t enum_gen_tag_index = 0;
static const size_t enum_gen_union_index = 1;
+static const size_t err_union_err_index = 0;
+static const size_t err_union_payload_index = 1;
+
#endif
src/ast_render.cpp
@@ -862,10 +862,20 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
fprintf(ar->f, "const");
break;
}
+ case NodeTypeUnwrapErrorExpr:
+ {
+ render_node_ungrouped(ar, node->data.unwrap_err_expr.op1);
+ fprintf(ar->f, " %%%% ");
+ if (node->data.unwrap_err_expr.symbol) {
+ Buf *var_name = node->data.unwrap_err_expr.symbol->data.symbol_expr.symbol;
+ fprintf(ar->f, "|%s| ", buf_ptr(var_name));
+ }
+ render_node_ungrouped(ar, node->data.unwrap_err_expr.op2);
+ break;
+ }
case NodeTypeFnDecl:
case NodeTypeParamDecl:
case NodeTypeErrorValueDecl:
- case NodeTypeUnwrapErrorExpr:
case NodeTypeStructField:
case NodeTypeUse:
case NodeTypeZeroesLiteral:
src/codegen.cpp
@@ -969,63 +969,6 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
} else {
zig_panic("TODO");
}
- case CastOpMaybeWrap:
- {
- assert(cast_instruction->tmp_ptr);
- assert(wanted_type->id == TypeTableEntryIdMaybe);
- assert(actual_type);
-
- TypeTableEntry *child_type = wanted_type->data.maybe.child_type;
-
- if (child_type->id == TypeTableEntryIdPointer ||
- child_type->id == TypeTableEntryIdFn)
- {
- return expr_val;
- } else {
- LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr, 0, "");
- gen_assign_raw(g, cast_instruction->base.source_node,
- val_ptr, expr_val, child_type, actual_type);
-
- LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr, 1, "");
- LLVMBuildStore(g->builder, LLVMConstAllOnes(LLVMInt1Type()), maybe_ptr);
- }
-
- return cast_instruction->tmp_ptr;
- }
- case CastOpNullToMaybe:
- // handled by constant expression evaluator
- zig_unreachable();
- case CastOpErrorWrap:
- {
- assert(wanted_type->id == TypeTableEntryIdErrorUnion);
- TypeTableEntry *child_type = wanted_type->data.error.child_type;
- LLVMValueRef ok_err_val = LLVMConstNull(g->err_tag_type->type_ref);
-
- if (!type_has_bits(child_type)) {
- return ok_err_val;
- } else {
- assert(cast_instruction->tmp_ptr);
- assert(wanted_type->id == TypeTableEntryIdErrorUnion);
- assert(actual_type);
-
- LLVMValueRef err_tag_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr, 0, "");
- LLVMBuildStore(g->builder, ok_err_val, err_tag_ptr);
-
- LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr, 1, "");
- gen_assign_raw(g, cast_instruction->base.source_node,
- payload_ptr, expr_val, child_type, actual_type);
-
- return cast_instruction->tmp_ptr;
- }
- }
- case CastOpPureErrorWrap:
- assert(wanted_type->id == TypeTableEntryIdErrorUnion);
-
- if (!type_has_bits(wanted_type->data.error.child_type)) {
- return expr_val;
- } else {
- zig_panic("TODO");
- }
case CastOpPtrToInt:
return LLVMBuildPtrToInt(g->builder, expr_val, wanted_type->type_ref, "");
case CastOpIntToPtr:
@@ -1257,78 +1200,6 @@ static LLVMValueRef ir_render_un_op(CodeGen *g, IrExecutable *executable, IrInst
{
zig_panic("TODO codegen PrefixOpMaybe");
}
- case IrUnOpUnwrapError:
- {
- assert(expr_type->id == TypeTableEntryIdErrorUnion);
- TypeTableEntry *child_type = expr_type->data.error.child_type;
-
- if (ir_want_debug_safety(g, &un_op_instruction->base)) {
- LLVMValueRef err_val;
- if (type_has_bits(child_type)) {
- LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, expr, 0, "");
- err_val = LLVMBuildLoad(g->builder, err_val_ptr, "");
- } else {
- err_val = expr;
- }
- LLVMValueRef zero = LLVMConstNull(g->err_tag_type->type_ref);
- LLVMValueRef cond_val = LLVMBuildICmp(g->builder, LLVMIntEQ, err_val, zero, "");
- LLVMBasicBlockRef err_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapErrError");
- LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapErrOk");
- LLVMBuildCondBr(g->builder, cond_val, ok_block, err_block);
-
- LLVMPositionBuilderAtEnd(g->builder, err_block);
- gen_debug_safety_crash(g);
-
- LLVMPositionBuilderAtEnd(g->builder, ok_block);
- }
-
- if (type_has_bits(child_type)) {
- LLVMValueRef child_val_ptr = LLVMBuildStructGEP(g->builder, expr, 1, "");
- return get_handle_value(g, child_val_ptr, child_type);
- } else {
- return nullptr;
- }
- }
- case IrUnOpUnwrapMaybe:
- {
- assert(expr_type->id == TypeTableEntryIdMaybe);
- TypeTableEntry *child_type = expr_type->data.maybe.child_type;
-
- if (ir_want_debug_safety(g, &un_op_instruction->base)) {
- LLVMValueRef cond_val;
- if (child_type->id == TypeTableEntryIdPointer ||
- child_type->id == TypeTableEntryIdFn)
- {
- cond_val = LLVMBuildICmp(g->builder, LLVMIntNE, expr,
- LLVMConstNull(child_type->type_ref), "");
- } else {
- LLVMValueRef maybe_null_ptr = LLVMBuildStructGEP(g->builder, expr, 1, "");
- cond_val = LLVMBuildLoad(g->builder, maybe_null_ptr, "");
- }
-
- LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapMaybeOk");
- LLVMBasicBlockRef null_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapMaybeNull");
- LLVMBuildCondBr(g->builder, cond_val, ok_block, null_block);
-
- LLVMPositionBuilderAtEnd(g->builder, null_block);
- gen_debug_safety_crash(g);
-
- LLVMPositionBuilderAtEnd(g->builder, ok_block);
- }
-
-
- if (child_type->id == TypeTableEntryIdPointer ||
- child_type->id == TypeTableEntryIdFn)
- {
- return expr;
- } else {
- LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, expr, 0, "");
- return get_handle_value(g, maybe_field_ptr, child_type);
- }
- }
- case IrUnOpErrorReturn:
- case IrUnOpMaybeReturn:
- zig_panic("TODO codegen more un ops");
}
zig_unreachable();
@@ -2132,6 +2003,143 @@ static LLVMValueRef ir_render_overflow_op(CodeGen *g, IrExecutable *executable,
return overflow_bit;
}
+static LLVMValueRef ir_render_test_err(CodeGen *g, IrExecutable *executable, IrInstructionTestErr *instruction) {
+ TypeTableEntry *ptr_type = get_underlying_type(instruction->value->type_entry);
+ TypeTableEntry *err_union_type = get_underlying_type(ptr_type->data.pointer.child_type);
+ TypeTableEntry *child_type = get_underlying_type(err_union_type->data.error.child_type);
+ LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->value);
+ LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type);
+
+ LLVMValueRef err_val;
+ if (type_has_bits(child_type)) {
+ LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, "");
+ err_val = LLVMBuildLoad(g->builder, err_val_ptr, "");
+ } else {
+ err_val = err_union_handle;
+ }
+
+ LLVMValueRef zero = LLVMConstNull(g->err_tag_type->type_ref);
+ return LLVMBuildICmp(g->builder, LLVMIntNE, err_val, zero, "");
+}
+
+static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executable, IrInstructionUnwrapErrCode *instruction) {
+ TypeTableEntry *ptr_type = get_underlying_type(instruction->value->type_entry);
+ TypeTableEntry *err_union_type = get_underlying_type(ptr_type->data.pointer.child_type);
+ TypeTableEntry *child_type = get_underlying_type(err_union_type->data.error.child_type);
+ LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->value);
+ LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type);
+
+ if (type_has_bits(child_type)) {
+ LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, "");
+ return LLVMBuildLoad(g->builder, err_val_ptr, "");
+ } else {
+ return err_union_handle;
+ }
+}
+
+static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *executable, IrInstructionUnwrapErrPayload *instruction) {
+ TypeTableEntry *ptr_type = get_underlying_type(instruction->value->type_entry);
+ TypeTableEntry *err_union_type = get_underlying_type(ptr_type->data.pointer.child_type);
+ TypeTableEntry *child_type = get_underlying_type(err_union_type->data.error.child_type);
+ LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->value);
+ LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type);
+
+ if (ir_want_debug_safety(g, &instruction->base) && instruction->safety_check_on) {
+ LLVMValueRef err_val;
+ if (type_has_bits(child_type)) {
+ LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, "");
+ err_val = LLVMBuildLoad(g->builder, err_val_ptr, "");
+ } else {
+ err_val = err_union_handle;
+ }
+ LLVMValueRef zero = LLVMConstNull(g->err_tag_type->type_ref);
+ LLVMValueRef cond_val = LLVMBuildICmp(g->builder, LLVMIntEQ, err_val, zero, "");
+ LLVMBasicBlockRef err_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapErrError");
+ LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapErrOk");
+ LLVMBuildCondBr(g->builder, cond_val, ok_block, err_block);
+
+ LLVMPositionBuilderAtEnd(g->builder, err_block);
+ gen_debug_safety_crash(g);
+
+ LLVMPositionBuilderAtEnd(g->builder, ok_block);
+ }
+
+ if (type_has_bits(child_type)) {
+ return LLVMBuildStructGEP(g->builder, err_union_handle, err_union_payload_index, "");
+ } else {
+ return nullptr;
+ }
+}
+
+static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, IrInstructionMaybeWrap *instruction) {
+ TypeTableEntry *wanted_type = instruction->base.type_entry;
+
+ assert(wanted_type->id == TypeTableEntryIdMaybe);
+
+ TypeTableEntry *child_type = wanted_type->data.maybe.child_type;
+
+ LLVMValueRef payload_val = ir_llvm_value(g, instruction->value);
+ if (child_type->id == TypeTableEntryIdPointer ||
+ child_type->id == TypeTableEntryIdFn)
+ {
+ return payload_val;
+ }
+
+ assert(instruction->tmp_ptr);
+
+ LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_child_index, "");
+ gen_assign_raw(g, instruction->base.source_node, val_ptr, payload_val, child_type, instruction->value->type_entry);
+
+ LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_null_index, "");
+ LLVMBuildStore(g->builder, LLVMConstAllOnes(LLVMInt1Type()), maybe_ptr);
+
+ return instruction->tmp_ptr;
+}
+
+static LLVMValueRef ir_render_err_wrap_code(CodeGen *g, IrExecutable *executable, IrInstructionErrWrapCode *instruction) {
+ TypeTableEntry *wanted_type = instruction->base.type_entry;
+
+ assert(wanted_type->id == TypeTableEntryIdErrorUnion);
+
+ TypeTableEntry *child_type = wanted_type->data.error.child_type;
+ LLVMValueRef err_val = ir_llvm_value(g, instruction->value);
+
+ if (!type_has_bits(child_type))
+ return err_val;
+
+ assert(instruction->tmp_ptr);
+
+ LLVMValueRef err_tag_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_err_index, "");
+ LLVMBuildStore(g->builder, err_val, err_tag_ptr);
+
+ return instruction->tmp_ptr;
+}
+
+static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executable, IrInstructionErrWrapPayload *instruction) {
+ TypeTableEntry *wanted_type = instruction->base.type_entry;
+
+ assert(wanted_type->id == TypeTableEntryIdErrorUnion);
+
+ TypeTableEntry *child_type = wanted_type->data.error.child_type;
+
+ LLVMValueRef ok_err_val = LLVMConstNull(g->err_tag_type->type_ref);
+
+ if (!type_has_bits(child_type))
+ return ok_err_val;
+
+ assert(instruction->tmp_ptr);
+
+ LLVMValueRef payload_val = ir_llvm_value(g, instruction->value);
+
+ LLVMValueRef err_tag_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_err_index, "");
+ LLVMBuildStore(g->builder, ok_err_val, err_tag_ptr);
+
+ LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_payload_index, "");
+ gen_assign_raw(g, instruction->base.source_node, payload_ptr, payload_val, child_type, instruction->value->type_entry);
+
+ return instruction->tmp_ptr;
+}
+
static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
AstNode *source_node = instruction->source_node;
Scope *scope = instruction->scope;
@@ -2175,6 +2183,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
case IrInstructionIdIntType:
case IrInstructionIdMemberCount:
case IrInstructionIdAlignOf:
+ case IrInstructionIdErrUnionTypeChild:
zig_unreachable();
case IrInstructionIdReturn:
return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
@@ -2250,6 +2259,18 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_frame_address(g, executable, (IrInstructionFrameAddress *)instruction);
case IrInstructionIdOverflowOp:
return ir_render_overflow_op(g, executable, (IrInstructionOverflowOp *)instruction);
+ case IrInstructionIdTestErr:
+ return ir_render_test_err(g, executable, (IrInstructionTestErr *)instruction);
+ case IrInstructionIdUnwrapErrCode:
+ return ir_render_unwrap_err_code(g, executable, (IrInstructionUnwrapErrCode *)instruction);
+ case IrInstructionIdUnwrapErrPayload:
+ return ir_render_unwrap_err_payload(g, executable, (IrInstructionUnwrapErrPayload *)instruction);
+ case IrInstructionIdMaybeWrap:
+ return ir_render_maybe_wrap(g, executable, (IrInstructionMaybeWrap *)instruction);
+ case IrInstructionIdErrWrapCode:
+ return ir_render_err_wrap_code(g, executable, (IrInstructionErrWrapCode *)instruction);
+ case IrInstructionIdErrWrapPayload:
+ return ir_render_err_wrap_payload(g, executable, (IrInstructionErrWrapPayload *)instruction);
case IrInstructionIdSwitchVar:
case IrInstructionIdContainerInitList:
case IrInstructionIdStructInit:
@@ -2835,6 +2856,15 @@ static void do_code_gen(CodeGen *g) {
} else if (instruction->id == IrInstructionIdSlice) {
IrInstructionSlice *slice_instruction = (IrInstructionSlice *)instruction;
slot = &slice_instruction->tmp_ptr;
+ } else if (instruction->id == IrInstructionIdMaybeWrap) {
+ IrInstructionMaybeWrap *maybe_wrap_instruction = (IrInstructionMaybeWrap *)instruction;
+ slot = &maybe_wrap_instruction->tmp_ptr;
+ } else if (instruction->id == IrInstructionIdErrWrapPayload) {
+ IrInstructionErrWrapPayload *err_wrap_payload_instruction = (IrInstructionErrWrapPayload *)instruction;
+ slot = &err_wrap_payload_instruction->tmp_ptr;
+ } else if (instruction->id == IrInstructionIdErrWrapCode) {
+ IrInstructionErrWrapCode *err_wrap_code_instruction = (IrInstructionErrWrapCode *)instruction;
+ slot = &err_wrap_code_instruction->tmp_ptr;
} else {
zig_unreachable();
}
src/eval.cpp
@@ -342,23 +342,6 @@ void eval_const_expr_implicit_cast(CastOp cast_op,
const_val->special = ConstValSpecialStatic;
break;
}
- case CastOpMaybeWrap:
- const_val->data.x_maybe = other_val;
- const_val->special = ConstValSpecialStatic;
- break;
- case CastOpNullToMaybe:
- const_val->data.x_maybe = nullptr;
- const_val->special = ConstValSpecialStatic;
- break;
- case CastOpErrorWrap:
- const_val->data.x_err_union.err = nullptr;
- const_val->data.x_err_union.payload = other_val;
- const_val->special = ConstValSpecialStatic;
- break;
- case CastOpPureErrorWrap:
- const_val->data.x_err_union.err = other_val->data.x_pure_err;
- const_val->special = ConstValSpecialStatic;
- break;
case CastOpErrToInt:
{
uint64_t value;
src/ir.cpp
@@ -93,6 +93,10 @@ static Buf *exec_c_import_buf(IrExecutable *exec) {
return exec->c_import_buf;
}
+static bool instr_is_comptime(IrInstruction *instruction) {
+ return instruction->static_value.special != ConstValSpecialRuntime;
+}
+
static void ir_link_new_instruction(IrInstruction *new_instruction, IrInstruction *old_instruction) {
new_instruction->other = old_instruction;
old_instruction->other = new_instruction;
@@ -411,6 +415,34 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionOverflowOp *) {
return IrInstructionIdOverflowOp;
}
+static constexpr IrInstructionId ir_instruction_id(IrInstructionTestErr *) {
+ return IrInstructionIdTestErr;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionUnwrapErrCode *) {
+ return IrInstructionIdUnwrapErrCode;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionUnwrapErrPayload *) {
+ return IrInstructionIdUnwrapErrPayload;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionErrUnionTypeChild *) {
+ return IrInstructionIdErrUnionTypeChild;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionMaybeWrap *) {
+ return IrInstructionIdMaybeWrap;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionErrWrapPayload *) {
+ return IrInstructionIdErrWrapPayload;
+}
+
+static constexpr IrInstructionId ir_instruction_id(IrInstructionErrWrapCode *) {
+ return IrInstructionIdErrWrapCode;
+}
+
template<typename T>
static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) {
T *special_instruction = allocate<T>(1);
@@ -1037,8 +1069,11 @@ static IrInstruction *ir_build_to_ptr_type(IrBuilder *irb, Scope *scope, AstNode
return &instruction->base;
}
-static IrInstruction *ir_build_ptr_type_child(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) {
- IrInstructionPtrTypeChild *instruction = ir_build_instruction<IrInstructionPtrTypeChild>(irb, scope, source_node);
+static IrInstruction *ir_build_ptr_type_child(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *value)
+{
+ IrInstructionPtrTypeChild *instruction = ir_build_instruction<IrInstructionPtrTypeChild>(
+ irb, scope, source_node);
instruction->value = value;
ir_ref_instruction(value);
@@ -1198,6 +1233,33 @@ static IrInstruction *ir_build_unwrap_maybe_from(IrBuilder *irb, IrInstruction *
return new_instruction;
}
+static IrInstruction *ir_build_maybe_wrap(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) {
+ IrInstructionMaybeWrap *instruction = ir_build_instruction<IrInstructionMaybeWrap>(irb, scope, source_node);
+ instruction->value = value;
+
+ ir_ref_instruction(value);
+
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_err_wrap_payload(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) {
+ IrInstructionErrWrapPayload *instruction = ir_build_instruction<IrInstructionErrWrapPayload>(irb, scope, source_node);
+ instruction->value = value;
+
+ ir_ref_instruction(value);
+
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_err_wrap_code(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) {
+ IrInstructionErrWrapCode *instruction = ir_build_instruction<IrInstructionErrWrapCode>(irb, scope, source_node);
+ instruction->value = value;
+
+ ir_ref_instruction(value);
+
+ return &instruction->base;
+}
+
static IrInstruction *ir_build_clz(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) {
IrInstructionClz *instruction = ir_build_instruction<IrInstructionClz>(irb, scope, source_node);
instruction->value = value;
@@ -1709,6 +1771,76 @@ static IrInstruction *ir_build_alignof(IrBuilder *irb, Scope *scope, AstNode *so
return &instruction->base;
}
+static IrInstruction *ir_build_test_err(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *value)
+{
+ IrInstructionTestErr *instruction = ir_build_instruction<IrInstructionTestErr>(irb, scope, source_node);
+ instruction->value = value;
+
+ ir_ref_instruction(value);
+
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_test_err_from(IrBuilder *irb, IrInstruction *old_instruction, IrInstruction *value) {
+ IrInstruction *new_instruction = ir_build_test_err(irb, old_instruction->scope, old_instruction->source_node,
+ value);
+ ir_link_new_instruction(new_instruction, old_instruction);
+ return new_instruction;
+}
+
+static IrInstruction *ir_build_unwrap_err_code(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *value)
+{
+ IrInstructionUnwrapErrCode *instruction = ir_build_instruction<IrInstructionUnwrapErrCode>(irb, scope, source_node);
+ instruction->value = value;
+
+ ir_ref_instruction(value);
+
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_unwrap_err_code_from(IrBuilder *irb, IrInstruction *old_instruction,
+ IrInstruction *value)
+{
+ IrInstruction *new_instruction = ir_build_unwrap_err_code(irb, old_instruction->scope,
+ old_instruction->source_node, value);
+ ir_link_new_instruction(new_instruction, old_instruction);
+ return new_instruction;
+}
+
+static IrInstruction *ir_build_unwrap_err_payload(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *value, bool safety_check_on)
+{
+ IrInstructionUnwrapErrPayload *instruction = ir_build_instruction<IrInstructionUnwrapErrPayload>(irb, scope, source_node);
+ instruction->value = value;
+ instruction->safety_check_on = safety_check_on;
+
+ ir_ref_instruction(value);
+
+ return &instruction->base;
+}
+
+static IrInstruction *ir_build_unwrap_err_payload_from(IrBuilder *irb, IrInstruction *old_instruction,
+ IrInstruction *value, bool safety_check_on)
+{
+ IrInstruction *new_instruction = ir_build_unwrap_err_payload(irb, old_instruction->scope,
+ old_instruction->source_node, value, safety_check_on);
+ ir_link_new_instruction(new_instruction, old_instruction);
+ return new_instruction;
+}
+
+static IrInstruction *ir_build_err_union_type_child(IrBuilder *irb, Scope *scope, AstNode *source_node,
+ IrInstruction *type_value)
+{
+ IrInstructionErrUnionTypeChild *instruction = ir_build_instruction<IrInstructionErrUnionTypeChild>(irb, scope, source_node);
+ instruction->type_value = type_value;
+
+ ir_ref_instruction(type_value);
+
+ return &instruction->base;
+}
+
static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
results[ReturnKindUnconditional] = 0;
results[ReturnKindError] = 0;
@@ -1799,7 +1931,29 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
return ir_build_return(irb, scope, node, return_value);
}
case ReturnKindError:
- zig_panic("TODO gen IR for %%return");
+ {
+ assert(expr_node);
+ IrInstruction *err_union_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPurposeAddressOf);
+ if (err_union_ptr == irb->codegen->invalid_instruction)
+ return irb->codegen->invalid_instruction;
+ IrInstruction *is_err_val = ir_build_test_err(irb, scope, node, err_union_ptr);
+
+ IrBasicBlock *return_block = ir_build_basic_block(irb, scope, "ErrRetReturn");
+ IrBasicBlock *continue_block = ir_build_basic_block(irb, scope, "ErrRetContinue");
+ ir_build_cond_br(irb, scope, node, is_err_val, return_block, continue_block, is_inline);
+
+ ir_set_cursor_at_end(irb, return_block);
+ ir_gen_defers_for_block(irb, scope, outer_scope, true, false);
+ IrInstruction *err_val = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr);
+ ir_build_return(irb, scope, node, err_val);
+
+ ir_set_cursor_at_end(irb, continue_block);
+ IrInstruction *unwrapped_ptr = ir_build_unwrap_err_payload(irb, scope, node, err_union_ptr, false);
+ if (lval != LValPurposeNone)
+ return unwrapped_ptr;
+ else
+ return ir_build_load_ptr(irb, scope, node, unwrapped_ptr);
+ }
case ReturnKindMaybe:
{
assert(expr_node);
@@ -2798,13 +2952,33 @@ static IrInstruction *ir_gen_prefix_op_id(IrBuilder *irb, Scope *scope, AstNode
return ir_gen_prefix_op_id_lval(irb, scope, node, op_id, LValPurposeNone);
}
-static IrInstruction *ir_gen_prefix_op_unwrap_maybe(IrBuilder *irb, Scope *scope, AstNode *node, LValPurpose lval) {
- AstNode *expr = node->data.prefix_op_expr.primary_expr;
- IrInstruction *value = ir_gen_node_extra(irb, expr, scope, LValPurposeAddressOf);
- if (value == irb->codegen->invalid_instruction)
- return value;
+static IrInstruction *ir_gen_err_assert_ok(IrBuilder *irb, Scope *scope, AstNode *node, LValPurpose lval) {
+ assert(node->type == NodeTypePrefixOpExpr);
+ AstNode *expr_node = node->data.prefix_op_expr.primary_expr;
+
+ IrInstruction *err_union_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPurposeAddressOf);
+ if (err_union_ptr == irb->codegen->invalid_instruction)
+ return irb->codegen->invalid_instruction;
+
+ IrInstruction *payload_ptr = ir_build_unwrap_err_payload(irb, scope, node, err_union_ptr, true);
+ if (payload_ptr == irb->codegen->invalid_instruction)
+ return irb->codegen->invalid_instruction;
- IrInstruction *unwrapped_ptr = ir_build_unwrap_maybe(irb, scope, node, value, true);
+ if (lval == LValPurposeNone)
+ return ir_build_load_ptr(irb, scope, node, payload_ptr);
+ else
+ return payload_ptr;
+}
+
+static IrInstruction *ir_gen_maybe_assert_ok(IrBuilder *irb, Scope *scope, AstNode *node, LValPurpose lval) {
+ assert(node->type == NodeTypePrefixOpExpr);
+ AstNode *expr_node = node->data.prefix_op_expr.primary_expr;
+
+ IrInstruction *maybe_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPurposeAddressOf);
+ if (maybe_ptr == irb->codegen->invalid_instruction)
+ return irb->codegen->invalid_instruction;
+
+ IrInstruction *unwrapped_ptr = ir_build_unwrap_maybe(irb, scope, node, maybe_ptr, true);
if (lval == LValPurposeNone)
return ir_build_load_ptr(irb, scope, node, unwrapped_ptr);
else
@@ -2860,9 +3034,9 @@ static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNod
case PrefixOpError:
return ir_gen_prefix_op_id(irb, scope, node, IrUnOpError);
case PrefixOpUnwrapError:
- return ir_gen_prefix_op_id(irb, scope, node, IrUnOpUnwrapError);
+ return ir_gen_err_assert_ok(irb, scope, node, lval);
case PrefixOpUnwrapMaybe:
- return ir_gen_prefix_op_unwrap_maybe(irb, scope, node, lval);
+ return ir_gen_maybe_assert_ok(irb, scope, node, lval);
}
zig_unreachable();
}
@@ -3626,6 +3800,66 @@ static IrInstruction *ir_gen_slice(IrBuilder *irb, Scope *scope, AstNode *node)
return ir_build_slice(irb, scope, node, ptr_value, start_value, end_value, slice_expr->is_const);
}
+static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
+ assert(node->type == NodeTypeUnwrapErrorExpr);
+
+ AstNode *op1_node = node->data.unwrap_err_expr.op1;
+ AstNode *op2_node = node->data.unwrap_err_expr.op2;
+ AstNode *var_node = node->data.unwrap_err_expr.symbol;
+
+ bool is_inline = ir_should_inline(irb);
+
+ IrInstruction *err_union_ptr = ir_gen_node_extra(irb, op1_node, parent_scope, LValPurposeAddressOf);
+ if (err_union_ptr == irb->codegen->invalid_instruction)
+ return irb->codegen->invalid_instruction;
+
+ IrInstruction *is_err = ir_build_test_err(irb, parent_scope, node, err_union_ptr);
+
+ IrBasicBlock *ok_block = ir_build_basic_block(irb, parent_scope, "UnwrapErrOk");
+ IrBasicBlock *err_block = ir_build_basic_block(irb, parent_scope, "UnwrapErrError");
+ IrBasicBlock *end_block = ir_build_basic_block(irb, parent_scope, "UnwrapErrEnd");
+ ir_build_cond_br(irb, parent_scope, node, is_err, err_block, ok_block, is_inline);
+
+ ir_set_cursor_at_end(irb, err_block);
+ Scope *err_scope;
+ if (var_node) {
+ assert(var_node->type == NodeTypeSymbol);
+ IrInstruction *err_union_ptr_type = ir_build_typeof(irb, parent_scope, var_node, err_union_ptr);
+ IrInstruction *err_union_type = ir_build_ptr_type_child(irb, parent_scope, var_node, err_union_ptr_type);
+ IrInstruction *var_type = ir_build_err_union_type_child(irb, parent_scope, var_node, err_union_type);
+ Buf *var_name = var_node->data.symbol_expr.symbol;
+ bool is_const = true;
+ bool is_shadowable = false;
+ VariableTableEntry *var = ir_create_var(irb, node, parent_scope, var_name,
+ is_const, is_const, is_shadowable, is_inline);
+ err_scope = var->child_scope;
+ IrInstruction *err_val = ir_build_unwrap_err_code(irb, err_scope, node, err_union_ptr);
+ ir_build_var_decl(irb, err_scope, var_node, var, var_type, err_val);
+ } else {
+ err_scope = parent_scope;
+ }
+ IrInstruction *err_result = ir_gen_node(irb, op2_node, err_scope);
+ if (err_result == irb->codegen->invalid_instruction)
+ return irb->codegen->invalid_instruction;
+ IrBasicBlock *after_err_block = irb->current_basic_block;
+ ir_build_br(irb, err_scope, node, end_block, is_inline);
+
+ ir_set_cursor_at_end(irb, ok_block);
+ IrInstruction *unwrapped_ptr = ir_build_unwrap_err_payload(irb, parent_scope, node, err_union_ptr, false);
+ IrInstruction *unwrapped_payload = ir_build_load_ptr(irb, parent_scope, node, unwrapped_ptr);
+ IrBasicBlock *after_ok_block = irb->current_basic_block;
+ ir_build_br(irb, parent_scope, node, end_block, is_inline);
+
+ ir_set_cursor_at_end(irb, end_block);
+ IrInstruction **incoming_values = allocate<IrInstruction *>(2);
+ incoming_values[0] = err_result;
+ incoming_values[1] = unwrapped_payload;
+ IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2);
+ incoming_blocks[0] = after_err_block;
+ incoming_blocks[1] = after_ok_block;
+ return ir_build_phi(irb, parent_scope, node, 2, incoming_blocks, incoming_values);
+}
+
static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scope,
LValPurpose lval)
{
@@ -3703,6 +3937,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
case NodeTypeSliceExpr:
return ir_lval_wrap(irb, scope, ir_gen_slice(irb, scope, node), lval);
case NodeTypeUnwrapErrorExpr:
+ return ir_lval_wrap(irb, scope, ir_gen_err_ok_or(irb, scope, node), lval);
case NodeTypeZeroesLiteral:
case NodeTypeVarLiteral:
case NodeTypeFnProto:
@@ -4279,11 +4514,20 @@ static TypeTableEntry *ir_analyze_const_usize(IrAnalyze *ira, IrInstruction *ins
}
static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value) {
- if (value->static_value.special != ConstValSpecialStatic) {
- ir_add_error(ira, value, buf_sprintf("unable to evaluate constant expression"));
- return nullptr;
+ switch (value->static_value.special) {
+ case ConstValSpecialStatic:
+ return &value->static_value;
+ case ConstValSpecialRuntime:
+ ir_add_error(ira, value, buf_sprintf("unable to evaluate constant expression"));
+ return nullptr;
+ case ConstValSpecialUndef:
+ ir_add_error(ira, value, buf_sprintf("use of undefined value"));
+ return nullptr;
+ case ConstValSpecialZeroes:
+ ir_add_error(ira, value, buf_sprintf("zeroes is deprecated"));
+ return nullptr;
}
- return &value->static_value;
+ zig_unreachable();
}
IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node,
@@ -4375,6 +4619,95 @@ static FnTableEntry *ir_resolve_fn(IrAnalyze *ira, IrInstruction *fn_value) {
return const_val->data.x_fn;
}
+static IrInstruction *ir_analyze_maybe_wrap(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, TypeTableEntry *wanted_type) {
+ assert(wanted_type->id == TypeTableEntryIdMaybe);
+
+ if (instr_is_comptime(value)) {
+ ConstExprValue *val = ir_resolve_const(ira, value);
+ if (!val)
+ return ira->codegen->invalid_instruction;
+
+ IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(ira->new_irb.exec,
+ source_instr->scope, source_instr->source_node);
+ const_instruction->base.type_entry = wanted_type;
+ const_instruction->base.static_value.special = ConstValSpecialStatic;
+ const_instruction->base.static_value.depends_on_compile_var = val->depends_on_compile_var;
+ const_instruction->base.static_value.data.x_maybe = &value->static_value;
+ return &const_instruction->base;
+ }
+
+ IrInstruction *result = ir_build_maybe_wrap(&ira->new_irb, source_instr->scope, source_instr->source_node, value);
+ result->type_entry = wanted_type;
+ result->static_value.data.rh_maybe = RuntimeHintMaybeNonNull;
+ ir_add_alloca(ira, result, wanted_type);
+ return result;
+}
+
+static IrInstruction *ir_analyze_err_wrap_payload(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, TypeTableEntry *wanted_type) {
+ assert(wanted_type->id == TypeTableEntryIdErrorUnion);
+
+ if (instr_is_comptime(value)) {
+ ConstExprValue *val = ir_resolve_const(ira, value);
+ if (!val)
+ return ira->codegen->invalid_instruction;
+
+ IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(ira->new_irb.exec,
+ source_instr->scope, source_instr->source_node);
+ const_instruction->base.type_entry = wanted_type;
+ const_instruction->base.static_value.special = ConstValSpecialStatic;
+ const_instruction->base.static_value.depends_on_compile_var = val->depends_on_compile_var;
+ const_instruction->base.static_value.data.x_err_union.err = nullptr;
+ const_instruction->base.static_value.data.x_err_union.payload = val;
+ return &const_instruction->base;
+ }
+
+ IrInstruction *result = ir_build_err_wrap_payload(&ira->new_irb, source_instr->scope, source_instr->source_node, value);
+ result->type_entry = wanted_type;
+ result->static_value.data.rh_error_union = RuntimeHintErrorUnionNonError;
+ ir_add_alloca(ira, result, wanted_type);
+ return result;
+}
+
+static IrInstruction *ir_analyze_err_wrap_code(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, TypeTableEntry *wanted_type) {
+ assert(wanted_type->id == TypeTableEntryIdErrorUnion);
+
+ if (instr_is_comptime(value)) {
+ ConstExprValue *val = ir_resolve_const(ira, value);
+ if (!val)
+ return ira->codegen->invalid_instruction;
+
+ IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(ira->new_irb.exec,
+ source_instr->scope, source_instr->source_node);
+ const_instruction->base.type_entry = wanted_type;
+ const_instruction->base.static_value.special = ConstValSpecialStatic;
+ const_instruction->base.static_value.depends_on_compile_var = val->depends_on_compile_var;
+ const_instruction->base.static_value.data.x_err_union.err = val->data.x_pure_err;
+ const_instruction->base.static_value.data.x_err_union.payload = nullptr;
+ return &const_instruction->base;
+ }
+
+ IrInstruction *result = ir_build_err_wrap_code(&ira->new_irb, source_instr->scope, source_instr->source_node, value);
+ result->type_entry = wanted_type;
+ result->static_value.data.rh_error_union = RuntimeHintErrorUnionError;
+ ir_add_alloca(ira, result, wanted_type);
+ return result;
+}
+
+static IrInstruction *ir_analyze_null_to_maybe(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, TypeTableEntry *wanted_type) {
+ assert(wanted_type->id == TypeTableEntryIdMaybe);
+ assert(instr_is_comptime(value));
+
+ ConstExprValue *val = ir_resolve_const(ira, value);
+ assert(val);
+
+ IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(ira->new_irb.exec, source_instr->scope, source_instr->source_node);
+ const_instruction->base.type_entry = wanted_type;
+ const_instruction->base.static_value.special = ConstValSpecialStatic;
+ const_instruction->base.static_value.depends_on_compile_var = val->depends_on_compile_var;
+ const_instruction->base.static_value.data.x_maybe = nullptr;
+ return &const_instruction->base;
+}
+
static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr,
TypeTableEntry *wanted_type, IrInstruction *value)
{
@@ -4503,18 +4836,12 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
// explicit cast from child type of maybe type to maybe type
if (wanted_type->id == TypeTableEntryIdMaybe) {
if (types_match_const_cast_only(wanted_type->data.maybe.child_type, actual_type)) {
- IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, wanted_type,
- CastOpMaybeWrap, true);
- cast_instruction->return_knowledge = ReturnKnowledgeKnownNonNull;
- return cast_instruction;
+ return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type);
} else if (actual_type->id == TypeTableEntryIdNumLitInt ||
actual_type->id == TypeTableEntryIdNumLitFloat)
{
if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.maybe.child_type)) {
- IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, wanted_type,
- CastOpMaybeWrap, true);
- cast_instruction->return_knowledge = ReturnKnowledgeKnownNonNull;
- return cast_instruction;
+ return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type);
} else {
return ira->codegen->invalid_instruction;
}
@@ -4525,27 +4852,18 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
if (wanted_type->id == TypeTableEntryIdMaybe &&
actual_type->id == TypeTableEntryIdNullLit)
{
- IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, wanted_type,
- CastOpNullToMaybe, true);
- cast_instruction->return_knowledge = ReturnKnowledgeKnownNull;
- return cast_instruction;
+ return ir_analyze_null_to_maybe(ira, source_instr, value, wanted_type);
}
// explicit cast from child type of error type to error type
if (wanted_type->id == TypeTableEntryIdErrorUnion) {
if (types_match_const_cast_only(wanted_type->data.error.child_type, actual_type)) {
- IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, wanted_type,
- CastOpErrorWrap, true);
- cast_instruction->return_knowledge = ReturnKnowledgeKnownNonError;
- return cast_instruction;
+ return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type);
} else if (actual_type->id == TypeTableEntryIdNumLitInt ||
actual_type->id == TypeTableEntryIdNumLitFloat)
{
if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.error.child_type)) {
- IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, wanted_type,
- CastOpErrorWrap, true);
- cast_instruction->return_knowledge = ReturnKnowledgeKnownNonError;
- return cast_instruction;
+ return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type);
} else {
return ira->codegen->invalid_instruction;
}
@@ -4556,10 +4874,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
if (wanted_type->id == TypeTableEntryIdErrorUnion &&
actual_type->id == TypeTableEntryIdPureError)
{
- IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, wanted_type,
- CastOpPureErrorWrap, false);
- cast_instruction->return_knowledge = ReturnKnowledgeKnownError;
- return cast_instruction;
+ return ir_analyze_err_wrap_code(ira, source_instr, value, wanted_type);
}
// explicit cast from number literal to another type
@@ -5997,33 +6312,6 @@ static TypeTableEntry *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op
zig_unreachable();
}
-static TypeTableEntry *ir_analyze_unwrap_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) {
- IrInstruction *value = un_op_instruction->value->other;
- TypeTableEntry *type_entry = value->type_entry;
- if (type_entry->id == TypeTableEntryIdInvalid) {
- return type_entry;
- } else if (type_entry->id == TypeTableEntryIdMaybe) {
- if (value->static_value.special != ConstValSpecialRuntime) {
- bool depends_on_compile_var = value->static_value.depends_on_compile_var;
- ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base, depends_on_compile_var);
- ConstExprValue *child_val = value->static_value.data.x_maybe;
- if (!child_val) {
- ir_add_error(ira, &un_op_instruction->base,
- buf_sprintf("unable to unwrap null"));
- return ira->codegen->builtin_types.entry_invalid;
- }
- *out_val = *child_val;
- return type_entry->data.maybe.child_type;
- }
- ir_build_un_op_from(&ira->new_irb, &un_op_instruction->base, IrUnOpUnwrapMaybe, value);
- return type_entry->data.maybe.child_type;
- } else {
- add_node_error(ira->codegen, un_op_instruction->base.source_node,
- buf_sprintf("expected maybe type, found '%s'", buf_ptr(&type_entry->name)));
- return ira->codegen->builtin_types.entry_invalid;
- }
-}
-
static TypeTableEntry *ir_analyze_negation(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) {
IrInstruction *value = un_op_instruction->value->other;
TypeTableEntry *expr_type = value->type_entry;
@@ -6099,27 +6387,6 @@ static TypeTableEntry *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstructio
return ir_analyze_maybe(ira, un_op_instruction);
case IrUnOpError:
return ir_analyze_unary_prefix_op_err(ira, un_op_instruction);
- case IrUnOpUnwrapError:
- zig_panic("TODO analyze PrefixOpUnwrapError");
- //{
- // TypeTableEntry *type_entry = analyze_expression(g, import, context, nullptr, *expr_node);
-
- // if (type_entry->id == TypeTableEntryIdInvalid) {
- // return type_entry;
- // } else if (type_entry->id == TypeTableEntryIdErrorUnion) {
- // return type_entry->data.error.child_type;
- // } else {
- // add_node_error(g, *expr_node,
- // buf_sprintf("expected error type, found '%s'", buf_ptr(&type_entry->name)));
- // return g->builtin_types.entry_invalid;
- // }
- //}
- case IrUnOpUnwrapMaybe:
- return ir_analyze_unwrap_maybe(ira, un_op_instruction);
- case IrUnOpErrorReturn:
- zig_panic("TODO analyze IrUnOpErrorReturn");
- case IrUnOpMaybeReturn:
- zig_panic("TODO analyze IrUnOpMaybeReturn");
}
zig_unreachable();
}
@@ -6835,6 +7102,7 @@ static TypeTableEntry *ir_analyze_instruction_ptr_type_child(IrAnalyze *ira,
if (type_entry->id == TypeTableEntryIdInvalid)
return type_entry;
+ // TODO handle typedefs
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)));
@@ -7243,6 +7511,7 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira,
assert(ptr_type->id == TypeTableEntryIdPointer);
TypeTableEntry *type_entry = ptr_type->data.pointer.child_type;
+ // TODO handle typedef
if (type_entry->id == TypeTableEntryIdInvalid) {
return ira->codegen->builtin_types.entry_invalid;
} else if (type_entry->id != TypeTableEntryIdMaybe) {
@@ -7253,9 +7522,12 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira,
TypeTableEntry *child_type = type_entry->data.maybe.child_type;
TypeTableEntry *result_type = get_pointer_to_type(ira->codegen, child_type, false);
- if (value->static_value.special != ConstValSpecialRuntime) {
- ConstExprValue *maybe_val = value->static_value.data.x_ptr.base_ptr;
- assert(value->static_value.data.x_ptr.index == SIZE_MAX);
+ if (instr_is_comptime(value)) {
+ ConstExprValue *val = ir_resolve_const(ira, value);
+ if (!val)
+ return ira->codegen->builtin_types.entry_invalid;
+ ConstExprValue *maybe_val = val->data.x_ptr.base_ptr;
+ assert(val->data.x_ptr.index == SIZE_MAX);
if (maybe_val->special != ConstValSpecialRuntime) {
if (!maybe_val->data.x_maybe) {
@@ -8837,6 +9109,161 @@ static TypeTableEntry *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInst
return ira->codegen->builtin_types.entry_bool;
}
+static TypeTableEntry *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstructionTestErr *instruction) {
+ IrInstruction *value = instruction->value->other;
+ if (value->type_entry->id == TypeTableEntryIdInvalid)
+ return ira->codegen->builtin_types.entry_invalid;
+
+ TypeTableEntry *ptr_type = value->type_entry;
+
+ // This will be a pointer type because unwrap err payload IR instruction operates on a pointer to a thing.
+ assert(ptr_type->id == TypeTableEntryIdPointer);
+
+ TypeTableEntry *non_canon_type = ptr_type->data.pointer.child_type;
+ TypeTableEntry *canon_type = get_underlying_type(non_canon_type);
+ if (canon_type->id == TypeTableEntryIdInvalid) {
+ return ira->codegen->builtin_types.entry_invalid;
+ } else if (canon_type->id == TypeTableEntryIdErrorUnion) {
+ if (instr_is_comptime(value)) {
+ ConstExprValue *ptr_val = ir_resolve_const(ira, value);
+ if (!ptr_val)
+ return ira->codegen->builtin_types.entry_invalid;
+ ConstExprValue *err_union_val = ptr_val->data.x_ptr.base_ptr;
+ assert(ptr_val->data.x_ptr.index == SIZE_MAX);
+
+ if (err_union_val->special != ConstValSpecialRuntime) {
+ bool depends_on_compile_var = ptr_val->depends_on_compile_var || err_union_val->depends_on_compile_var;
+ ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, depends_on_compile_var);
+ out_val->data.x_bool = (err_union_val->data.x_err_union.err != nullptr);
+ return ira->codegen->builtin_types.entry_bool;
+ }
+ }
+
+ ir_build_test_err_from(&ira->new_irb, &instruction->base, value);
+ return ira->codegen->builtin_types.entry_bool;
+ } else {
+ ir_add_error(ira, value,
+ buf_sprintf("expected error union type, found '%s'", buf_ptr(&non_canon_type->name)));
+ // TODO if this is a typedecl, add error note showing the declaration of the type decl
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+}
+
+static TypeTableEntry *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira,
+ IrInstructionUnwrapErrCode *instruction)
+{
+ IrInstruction *value = instruction->value->other;
+ if (value->type_entry->id == TypeTableEntryIdInvalid)
+ return ira->codegen->builtin_types.entry_invalid;
+ TypeTableEntry *ptr_type = value->type_entry;
+
+ // This will be a pointer type because unwrap err payload IR instruction operates on a pointer to a thing.
+ assert(ptr_type->id == TypeTableEntryIdPointer);
+
+ TypeTableEntry *non_canon_type = ptr_type->data.pointer.child_type;
+ TypeTableEntry *canon_type = get_underlying_type(non_canon_type);
+ if (canon_type->id == TypeTableEntryIdInvalid) {
+ return ira->codegen->builtin_types.entry_invalid;
+ } else if (canon_type->id == TypeTableEntryIdErrorUnion) {
+ if (instr_is_comptime(value)) {
+ ConstExprValue *ptr_val = ir_resolve_const(ira, value);
+ if (!ptr_val)
+ return ira->codegen->builtin_types.entry_invalid;
+ ConstExprValue *err_union_val = ptr_val->data.x_ptr.base_ptr;
+ assert(ptr_val->data.x_ptr.index == SIZE_MAX);
+ if (err_union_val->special != ConstValSpecialRuntime) {
+ ErrorTableEntry *err = err_union_val->data.x_err_union.err;
+ assert(err);
+
+ bool depends_on_compile_var = ptr_val->depends_on_compile_var || err_union_val->depends_on_compile_var;
+ ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, depends_on_compile_var);
+ out_val->data.x_pure_err = err;
+ return ira->codegen->builtin_types.entry_pure_error;
+ }
+ }
+
+ ir_build_unwrap_err_code_from(&ira->new_irb, &instruction->base, value);
+ return ira->codegen->builtin_types.entry_pure_error;
+ } else {
+ ir_add_error(ira, value,
+ buf_sprintf("expected error union type, found '%s'", buf_ptr(&non_canon_type->name)));
+ // TODO if this is a typedecl, add error note showing the declaration of the type decl
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+}
+
+static TypeTableEntry *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira,
+ IrInstructionUnwrapErrPayload *instruction)
+{
+ IrInstruction *value = instruction->value->other;
+ if (value->type_entry->id == TypeTableEntryIdInvalid)
+ return ira->codegen->builtin_types.entry_invalid;
+ TypeTableEntry *ptr_type = value->type_entry;
+
+ // This will be a pointer type because unwrap err payload IR instruction operates on a pointer to a thing.
+ assert(ptr_type->id == TypeTableEntryIdPointer);
+
+ TypeTableEntry *non_canon_type = ptr_type->data.pointer.child_type;
+ TypeTableEntry *canon_type = get_underlying_type(non_canon_type);
+ if (canon_type->id == TypeTableEntryIdInvalid) {
+ return ira->codegen->builtin_types.entry_invalid;
+ } else if (canon_type->id == TypeTableEntryIdErrorUnion) {
+ TypeTableEntry *child_type = canon_type->data.error.child_type;
+ TypeTableEntry *result_type = get_pointer_to_type(ira->codegen, child_type, false);
+ if (instr_is_comptime(value)) {
+ ConstExprValue *ptr_val = ir_resolve_const(ira, value);
+ if (!ptr_val)
+ return ira->codegen->builtin_types.entry_invalid;
+ ConstExprValue *err_union_val = ptr_val->data.x_ptr.base_ptr;
+ assert(ptr_val->data.x_ptr.index == SIZE_MAX);
+ if (err_union_val->special != ConstValSpecialRuntime) {
+ ErrorTableEntry *err = err_union_val->data.x_err_union.err;
+ if (err != nullptr) {
+ ir_add_error(ira, &instruction->base,
+ buf_sprintf("unable to unwrap error '%s'", buf_ptr(&err->name)));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+
+ bool depends_on_compile_var = ptr_val->depends_on_compile_var || err_union_val->depends_on_compile_var;
+ ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, depends_on_compile_var);
+ out_val->data.x_ptr.base_ptr = err_union_val->data.x_err_union.payload;
+ out_val->data.x_ptr.index = SIZE_MAX;
+ return result_type;
+ }
+ }
+
+ ir_build_unwrap_err_payload_from(&ira->new_irb, &instruction->base, value, instruction->safety_check_on);
+ return result_type;
+ } else {
+ ir_add_error(ira, value,
+ buf_sprintf("expected error union type, found '%s'", buf_ptr(&non_canon_type->name)));
+ // TODO if this is a typedecl, add error note showing the declaration of the type decl
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+
+}
+
+static TypeTableEntry *ir_analyze_instruction_err_union_type_child(IrAnalyze *ira,
+ IrInstructionErrUnionTypeChild *instruction)
+{
+ IrInstruction *type_value = instruction->type_value->other;
+ TypeTableEntry *type_entry = ir_resolve_type(ira, type_value);
+ if (type_entry->id == TypeTableEntryIdInvalid)
+ return type_entry;
+
+ // TODO handle typedefs
+ if (type_entry->id != TypeTableEntryIdErrorUnion) {
+ add_node_error(ira->codegen, instruction->base.source_node,
+ buf_sprintf("expected error type, found '%s'", buf_ptr(&type_entry->name)));
+ return ira->codegen->builtin_types.entry_invalid;
+ }
+
+ ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base,
+ type_value->static_value.depends_on_compile_var);
+ out_val->data.x_type = type_entry->data.error.child_type;
+ return ira->codegen->builtin_types.entry_type;
+}
+
static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
switch (instruction->id) {
case IrInstructionIdInvalid:
@@ -8971,6 +9398,17 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
return ir_analyze_instruction_alignof(ira, (IrInstructionAlignOf *)instruction);
case IrInstructionIdOverflowOp:
return ir_analyze_instruction_overflow_op(ira, (IrInstructionOverflowOp *)instruction);
+ case IrInstructionIdTestErr:
+ return ir_analyze_instruction_test_err(ira, (IrInstructionTestErr *)instruction);
+ case IrInstructionIdUnwrapErrCode:
+ return ir_analyze_instruction_unwrap_err_code(ira, (IrInstructionUnwrapErrCode *)instruction);
+ case IrInstructionIdUnwrapErrPayload:
+ return ir_analyze_instruction_unwrap_err_payload(ira, (IrInstructionUnwrapErrPayload *)instruction);
+ case IrInstructionIdErrUnionTypeChild:
+ return ir_analyze_instruction_err_union_type_child(ira, (IrInstructionErrUnionTypeChild *)instruction);
+ case IrInstructionIdMaybeWrap:
+ case IrInstructionIdErrWrapCode:
+ case IrInstructionIdErrWrapPayload:
case IrInstructionIdCast:
case IrInstructionIdStructFieldPtr:
case IrInstructionIdEnumFieldPtr:
@@ -9122,6 +9560,13 @@ bool ir_has_side_effects(IrInstruction *instruction) {
case IrInstructionIdAlignOf:
case IrInstructionIdReturnAddress:
case IrInstructionIdFrameAddress:
+ case IrInstructionIdTestErr:
+ case IrInstructionIdUnwrapErrCode:
+ case IrInstructionIdUnwrapErrPayload:
+ case IrInstructionIdErrUnionTypeChild:
+ case IrInstructionIdMaybeWrap:
+ case IrInstructionIdErrWrapCode:
+ case IrInstructionIdErrWrapPayload:
return false;
case IrInstructionIdAsm:
{
@@ -9131,268 +9576,3 @@ bool ir_has_side_effects(IrInstruction *instruction) {
}
zig_unreachable();
}
-
-// TODO port over all this commented out code into new IR way of doing things
-
-//static TypeTableEntry *analyze_return_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
-// TypeTableEntry *expected_type, AstNode *node)
-//{
-// TypeTableEntry *expected_return_type = get_return_type(context);
-//
-// switch (node->data.return_expr.kind) {
-// 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, found '%s'", buf_ptr(&resolved_type->name)));
-// return g->builtin_types.entry_invalid;
-// }
-// }
-// }
-// zig_unreachable();
-//}
-//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, found '%s'", buf_ptr(&lhs_type->name)));
-// return g->builtin_types.entry_invalid;
-// }
-//}
-//
-//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"));
-// }
-//}
-//
-//static LLVMValueRef gen_enum_value_expr(CodeGen *g, AstNode *node, TypeTableEntry *enum_type,
-// AstNode *arg_node)
-//{
-// assert(node->type == NodeTypeFieldAccessExpr);
-//
-// uint64_t value = node->data.field_access_expr.type_enum_field->value;
-// LLVMTypeRef tag_type_ref = enum_type->data.enumeration.tag_type->type_ref;
-// LLVMValueRef tag_value = LLVMConstInt(tag_type_ref, value, false);
-//
-// if (enum_type->data.enumeration.gen_field_count == 0) {
-// return tag_value;
-// } else {
-// TypeTableEntry *arg_node_type = nullptr;
-// LLVMValueRef new_union_val = gen_expr(g, arg_node);
-// if (arg_node) {
-// arg_node_type = get_expr_type(arg_node);
-// } else {
-// arg_node_type = g->builtin_types.entry_void;
-// }
-//
-// LLVMValueRef tmp_struct_ptr = node->data.field_access_expr.resolved_struct_val_expr.ptr;
-//
-// // populate the new tag value
-// LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, 0, "");
-// LLVMBuildStore(g->builder, tag_value, tag_field_ptr);
-//
-// if (arg_node_type->id != TypeTableEntryIdVoid) {
-// // populate the union value
-// TypeTableEntry *union_val_type = get_expr_type(arg_node);
-// LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, 1, "");
-// LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr,
-// LLVMPointerType(union_val_type->type_ref, 0), "");
-//
-// gen_assign_raw(g, arg_node, BinOpTypeAssign, bitcasted_union_field_ptr, new_union_val,
-// union_val_type, union_val_type);
-//
-// }
-//
-// return tmp_struct_ptr;
-// }
-//}
-//
-//static LLVMValueRef gen_unwrap_err_expr(CodeGen *g, AstNode *node) {
-// assert(node->type == NodeTypeUnwrapErrorExpr);
-//
-// AstNode *op1 = node->data.unwrap_err_expr.op1;
-// AstNode *op2 = node->data.unwrap_err_expr.op2;
-// VariableTableEntry *var = node->data.unwrap_err_expr.var;
-//
-// LLVMValueRef expr_val = gen_expr(g, op1);
-// TypeTableEntry *expr_type = get_expr_type(op1);
-// TypeTableEntry *op2_type = get_expr_type(op2);
-// assert(expr_type->id == TypeTableEntryIdErrorUnion);
-// TypeTableEntry *child_type = expr_type->data.error.child_type;
-// LLVMValueRef err_val;
-// if (handle_is_ptr(expr_type)) {
-// LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, expr_val, 0, "");
-// err_val = LLVMBuildLoad(g->builder, err_val_ptr, "");
-// } else {
-// err_val = expr_val;
-// }
-// LLVMValueRef zero = LLVMConstNull(g->err_tag_type->type_ref);
-// LLVMValueRef cond_val = LLVMBuildICmp(g->builder, LLVMIntEQ, err_val, zero, "");
-//
-// LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapErrOk");
-// LLVMBasicBlockRef err_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapErrError");
-// LLVMBasicBlockRef end_block;
-// bool err_reachable = op2_type->id != TypeTableEntryIdUnreachable;
-// bool have_end_block = err_reachable && type_has_bits(child_type);
-// if (have_end_block) {
-// end_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapErrEnd");
-// }
-//
-// LLVMBuildCondBr(g->builder, cond_val, ok_block, err_block);
-//
-// LLVMPositionBuilderAtEnd(g->builder, err_block);
-// if (var) {
-// LLVMBuildStore(g->builder, err_val, var->value_ref);
-// }
-// LLVMValueRef err_result = gen_expr(g, op2);
-// if (have_end_block) {
-// LLVMBuildBr(g->builder, end_block);
-// } else if (err_reachable) {
-// LLVMBuildBr(g->builder, ok_block);
-// }
-//
-// LLVMPositionBuilderAtEnd(g->builder, ok_block);
-// if (!type_has_bits(child_type)) {
-// return nullptr;
-// }
-// LLVMValueRef child_val_ptr = LLVMBuildStructGEP(g->builder, expr_val, 1, "");
-// LLVMValueRef child_val = get_handle_value(g, child_val_ptr, child_type);
-//
-// if (!have_end_block) {
-// return child_val;
-// }
-//
-// LLVMBuildBr(g->builder, end_block);
-//
-// LLVMPositionBuilderAtEnd(g->builder, end_block);
-// LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMTypeOf(err_result), "");
-// LLVMValueRef incoming_values[2] = {child_val, err_result};
-// LLVMBasicBlockRef incoming_blocks[2] = {ok_block, err_block};
-// LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2);
-// return phi;
-//}
-//
-//static LLVMValueRef gen_return_expr(CodeGen *g, AstNode *node) {
-// assert(node->type == NodeTypeReturnExpr);
-// AstNode *param_node = node->data.return_expr.expr;
-// assert(param_node);
-// LLVMValueRef value = gen_expr(g, param_node);
-// TypeTableEntry *value_type = get_expr_type(param_node);
-//
-// switch (node->data.return_expr.kind) {
-// case ReturnKindUnconditional:
-// {
-// Expr *expr = get_resolved_expr(param_node);
-// if (expr->const_val.ok) {
-// if (value_type->id == TypeTableEntryIdErrorUnion) {
-// if (expr->const_val.data.x_err.err) {
-// expr->return_knowledge = ReturnKnowledgeKnownError;
-// } else {
-// expr->return_knowledge = ReturnKnowledgeKnownNonError;
-// }
-// } else if (value_type->id == TypeTableEntryIdMaybe) {
-// if (expr->const_val.data.x_maybe) {
-// expr->return_knowledge = ReturnKnowledgeKnownNonNull;
-// } else {
-// expr->return_knowledge = ReturnKnowledgeKnownNull;
-// }
-// }
-// }
-// return gen_return(g, node, value, expr->return_knowledge);
-// }
-// case ReturnKindError:
-// {
-// assert(value_type->id == TypeTableEntryIdErrorUnion);
-// TypeTableEntry *child_type = value_type->data.error.child_type;
-//
-// LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "ErrRetReturn");
-// LLVMBasicBlockRef continue_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "ErrRetContinue");
-//
-// LLVMValueRef err_val;
-// if (type_has_bits(child_type)) {
-// LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, value, 0, "");
-// err_val = LLVMBuildLoad(g->builder, err_val_ptr, "");
-// } else {
-// err_val = value;
-// }
-// LLVMValueRef zero = LLVMConstNull(g->err_tag_type->type_ref);
-// LLVMValueRef cond_val = LLVMBuildICmp(g->builder, LLVMIntEQ, err_val, zero, "");
-// LLVMBuildCondBr(g->builder, cond_val, continue_block, return_block);
-//
-// LLVMPositionBuilderAtEnd(g->builder, return_block);
-// TypeTableEntry *return_type = g->cur_fn->type_entry->data.fn.fn_type_id.return_type;
-// if (return_type->id == TypeTableEntryIdPureError) {
-// gen_return(g, node, err_val, ReturnKnowledgeKnownError);
-// } else if (return_type->id == TypeTableEntryIdErrorUnion) {
-// if (type_has_bits(return_type->data.error.child_type)) {
-// assert(g->cur_ret_ptr);
-//
-// LLVMValueRef tag_ptr = LLVMBuildStructGEP(g->builder, g->cur_ret_ptr, 0, "");
-// LLVMBuildStore(g->builder, err_val, tag_ptr);
-// LLVMBuildRetVoid(g->builder);
-// } else {
-// gen_return(g, node, err_val, ReturnKnowledgeKnownError);
-// }
-// } else {
-// zig_unreachable();
-// }
-//
-// LLVMPositionBuilderAtEnd(g->builder, continue_block);
-// if (type_has_bits(child_type)) {
-// LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, value, 1, "");
-// return get_handle_value(g, val_ptr, child_type);
-// } else {
-// return nullptr;
-// }
-// }
-// }
-// zig_unreachable();
-//}
src/ir_print.cpp
@@ -295,14 +295,6 @@ static const char *ir_un_op_id_str(IrUnOp op_id) {
return "?";
case IrUnOpError:
return "%";
- case IrUnOpUnwrapError:
- return "%%";
- case IrUnOpUnwrapMaybe:
- return "??";
- case IrUnOpMaybeReturn:
- return "?return";
- case IrUnOpErrorReturn:
- return "%return";
}
zig_unreachable();
}
@@ -855,6 +847,51 @@ static void ir_print_overflow_op(IrPrint *irp, IrInstructionOverflowOp *instruct
fprintf(irp->f, ")");
}
+static void ir_print_test_err(IrPrint *irp, IrInstructionTestErr *instruction) {
+ fprintf(irp->f, "@testError(");
+ ir_print_other_instruction(irp, instruction->value);
+ fprintf(irp->f, ")");
+}
+
+static void ir_print_err_union_type_child(IrPrint *irp, IrInstructionErrUnionTypeChild *instruction) {
+ fprintf(irp->f, "@errorUnionTypeChild(");
+ ir_print_other_instruction(irp, instruction->type_value);
+ fprintf(irp->f, ")");
+}
+
+static void ir_print_unwrap_err_code(IrPrint *irp, IrInstructionUnwrapErrCode *instruction) {
+ fprintf(irp->f, "@unwrapErrorCode(");
+ ir_print_other_instruction(irp, instruction->value);
+ fprintf(irp->f, ")");
+}
+
+static void ir_print_unwrap_err_payload(IrPrint *irp, IrInstructionUnwrapErrPayload *instruction) {
+ fprintf(irp->f, "@unwrapErrorPayload(");
+ ir_print_other_instruction(irp, instruction->value);
+ fprintf(irp->f, ")");
+ if (!instruction->safety_check_on) {
+ fprintf(irp->f, " // no safety");
+ }
+}
+
+static void ir_print_maybe_wrap(IrPrint *irp, IrInstructionMaybeWrap *instruction) {
+ fprintf(irp->f, "@maybeWrap(");
+ ir_print_other_instruction(irp, instruction->value);
+ fprintf(irp->f, ")");
+}
+
+static void ir_print_err_wrap_code(IrPrint *irp, IrInstructionErrWrapCode *instruction) {
+ fprintf(irp->f, "@errWrapCode(");
+ ir_print_other_instruction(irp, instruction->value);
+ fprintf(irp->f, ")");
+}
+
+static void ir_print_err_wrap_payload(IrPrint *irp, IrInstructionErrWrapPayload *instruction) {
+ fprintf(irp->f, "@errWrapPayload(");
+ ir_print_other_instruction(irp, instruction->value);
+ fprintf(irp->f, ")");
+}
+
static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
ir_print_prefix(irp, instruction);
switch (instruction->id) {
@@ -1067,6 +1104,27 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdOverflowOp:
ir_print_overflow_op(irp, (IrInstructionOverflowOp *)instruction);
break;
+ case IrInstructionIdTestErr:
+ ir_print_test_err(irp, (IrInstructionTestErr *)instruction);
+ break;
+ case IrInstructionIdUnwrapErrCode:
+ ir_print_unwrap_err_code(irp, (IrInstructionUnwrapErrCode *)instruction);
+ break;
+ case IrInstructionIdUnwrapErrPayload:
+ ir_print_unwrap_err_payload(irp, (IrInstructionUnwrapErrPayload *)instruction);
+ break;
+ case IrInstructionIdErrUnionTypeChild:
+ ir_print_err_union_type_child(irp, (IrInstructionErrUnionTypeChild *)instruction);
+ break;
+ case IrInstructionIdMaybeWrap:
+ ir_print_maybe_wrap(irp, (IrInstructionMaybeWrap *)instruction);
+ break;
+ case IrInstructionIdErrWrapCode:
+ ir_print_err_wrap_code(irp, (IrInstructionErrWrapCode *)instruction);
+ break;
+ case IrInstructionIdErrWrapPayload:
+ ir_print_err_wrap_payload(irp, (IrInstructionErrWrapPayload *)instruction);
+ break;
}
fprintf(irp->f, "\n");
}
test/cases/err_wrapping.zig
@@ -0,0 +1,13 @@
+pub fn foo() -> %i32 {
+ const x = %return bar();
+ return x + 1
+}
+
+pub fn bar() -> %i32 {
+ return 13;
+}
+
+pub fn baz() -> %i32 {
+ const y = foo() %% 1234;
+ return y + 1;
+}
test/self_hosted2.zig
@@ -1,4 +1,5 @@
const case_namespace_fn_call = @import("cases/namespace_fn_call.zig");
+const case_err_wrapping = @import("cases/err_wrapping.zig");
pub const SYS_write = 1;
pub const SYS_exit = 60;
@@ -354,6 +355,9 @@ fn assignToIfVarPtr() {
assert(??maybe_bool == false);
}
+fn errorWrapping() {
+ assert(%%case_err_wrapping.baz() == 15);
+}
fn assert(ok: bool) {
if (!ok)
@@ -390,6 +394,7 @@ fn runAllTests() {
overflowIntrinsics();
shlWithOverflow();
assignToIfVarPtr();
+ errorWrapping();
}
export nakedcc fn _start() -> unreachable {