From fee875770cb8c9363219b736f6c03e15cff39b92 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 8 Feb 2018 11:09:18 -0500 Subject: [PATCH] error set casting building --- TODO | 1 + src/all_types.hpp | 1 + src/codegen.cpp | 3 +++ src/ir.cpp | 63 ++++++++++++++++++----------------------------- 4 files changed, 29 insertions(+), 39 deletions(-) diff --git a/TODO b/TODO index f470ebaaf..567d31e39 100644 --- a/TODO +++ b/TODO @@ -19,6 +19,7 @@ foo() catch |err| switch (err) {}; // TODO this is an explicit cast and should actually coerce the type erorr set casting + // add a runtime safety check test err should be comptime if error set has 0 members diff --git a/src/all_types.hpp b/src/all_types.hpp index 869d17f0b..04b781a59 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -560,6 +560,7 @@ enum CastOp { CastOpResizeSlice, CastOpBytesToSlice, CastOpNumLitToConcrete, + CastOpErrSet, }; struct AstNodeFnCallExpr { diff --git a/src/codegen.cpp b/src/codegen.cpp index e3f182e17..69460d723 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2081,6 +2081,9 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable, assert(wanted_type->id == TypeTableEntryIdInt); assert(actual_type->id == TypeTableEntryIdBool); return LLVMBuildZExt(g->builder, expr_val, wanted_type->type_ref, ""); + case CastOpErrSet: + // TODO runtime safety for error casting + return expr_val; } zig_unreachable(); } diff --git a/src/ir.cpp b/src/ir.cpp index 0c30f49d3..25723535d 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -7584,6 +7584,8 @@ static void eval_const_expr_implicit_cast(CastOp cast_op, switch (cast_op) { case CastOpNoCast: zig_unreachable(); + case CastOpErrSet: + zig_panic("TODO"); case CastOpNoop: { copy_const_val(const_val, other_val, other_val->special == ConstValSpecialStatic); @@ -8039,53 +8041,36 @@ static IrInstruction *ir_analyze_err_wrap_payload(IrAnalyze *ira, IrInstruction return result; } -// TODO this is an explicit cast and should actually coerce the type static IrInstruction *ir_analyze_err_set_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, TypeTableEntry *wanted_type) { - TypeTableEntry *contained_set = value->value.type; - TypeTableEntry *container_set = wanted_type; - - assert(contained_set->id == TypeTableEntryIdErrorSet); - assert(container_set->id == TypeTableEntryIdErrorSet); - - zig_panic("TODO explicit error set cast"); - - if (container_set->data.error_set.infer_fn == nullptr && - !type_is_global_error_set(container_set)) - { - ErrorTableEntry **errors = allocate(ira->codegen->errors_by_index.length); - for (uint32_t i = 0; i < container_set->data.error_set.err_count; i += 1) { - ErrorTableEntry *error_entry = container_set->data.error_set.errors[i]; - assert(errors[error_entry->value] == nullptr); - errors[error_entry->value] = error_entry; - } - ErrorMsg *err_msg = nullptr; - for (uint32_t i = 0; i < contained_set->data.error_set.err_count; i += 1) { - ErrorTableEntry *contained_error_entry = contained_set->data.error_set.errors[i]; - ErrorTableEntry *error_entry = errors[contained_error_entry->value]; - if (error_entry == nullptr) { - if (err_msg == nullptr) { - err_msg = ir_add_error(ira, source_instr, - buf_sprintf("invalid cast of error set '%s' to error set '%s'", - buf_ptr(&contained_set->name), buf_ptr(&container_set->name))); - } - add_error_note(ira->codegen, err_msg, contained_error_entry->decl_node, - buf_sprintf("'%s.%s' not present in '%s'", buf_ptr(&contained_set->name), - buf_ptr(&contained_error_entry->name), buf_ptr(&container_set->name))); - } - } - free(errors); - if (err_msg != nullptr) { - return ira->codegen->invalid_instruction; - } - } + assert(value->value.type->id == TypeTableEntryIdErrorSet); + assert(wanted_type->id == TypeTableEntryIdErrorSet); if (instr_is_comptime(value)) { ConstExprValue *val = ir_resolve_const(ira, value, UndefBad); if (!val) return ira->codegen->invalid_instruction; + if (!resolve_inferred_error_set(ira, wanted_type, source_instr->source_node)) { + return ira->codegen->invalid_instruction; + } + if (!type_is_global_error_set(wanted_type)) { + bool subset = false; + for (uint32_t i = 0, count = wanted_type->data.error_set.err_count; i < count; i += 1) { + if (wanted_type->data.error_set.errors[i]->value == val->data.x_err_set->value) { + subset = true; + break; + } + } + if (!subset) { + ir_add_error(ira, source_instr, + buf_sprintf("error.%s not a member of error set '%s'", + buf_ptr(&val->data.x_err_set->name), buf_ptr(&wanted_type->name))); + return ira->codegen->invalid_instruction; + } + } + IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb, source_instr->scope, source_instr->source_node); const_instruction->base.value.type = wanted_type; @@ -8094,7 +8079,7 @@ static IrInstruction *ir_analyze_err_set_cast(IrAnalyze *ira, IrInstruction *sou return &const_instruction->base; } - IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->scope, source_instr->source_node, wanted_type, value, CastOpNoop); + IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->scope, source_instr->source_node, wanted_type, value, CastOpErrSet); result->value.type = wanted_type; return result; }