Commit fee875770c

Andrew Kelley <superjoe30@gmail.com>
2018-02-08 17:09:18
error set casting building
1 parent 76239f2
src/all_types.hpp
@@ -560,6 +560,7 @@ enum CastOp {
     CastOpResizeSlice,
     CastOpBytesToSlice,
     CastOpNumLitToConcrete,
+    CastOpErrSet,
 };
 
 struct AstNodeFnCallExpr {
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();
 }
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,52 +8041,35 @@ 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);
+    assert(value->value.type->id == TypeTableEntryIdErrorSet);
+    assert(wanted_type->id == TypeTableEntryIdErrorSet);
 
-    zig_panic("TODO explicit error set cast");
+    if (instr_is_comptime(value)) {
+        ConstExprValue *val = ir_resolve_const(ira, value, UndefBad);
+        if (!val)
+            return ira->codegen->invalid_instruction;
 
-    if (container_set->data.error_set.infer_fn == nullptr &&
-        !type_is_global_error_set(container_set))
-    {
-        ErrorTableEntry **errors = allocate<ErrorTableEntry *>(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;
+        if (!resolve_inferred_error_set(ira, wanted_type, source_instr->source_node)) {
+            return ira->codegen->invalid_instruction;
         }
-        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)));
+        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;
                 }
-                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)));
+            }
+            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;
             }
         }
-        free(errors);
-        if (err_msg != nullptr) {
-            return ira->codegen->invalid_instruction;
-        }
-    }
-
-    if (instr_is_comptime(value)) {
-        ConstExprValue *val = ir_resolve_const(ira, value, UndefBad);
-        if (!val)
-            return ira->codegen->invalid_instruction;
 
         IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb,
                 source_instr->scope, source_instr->source_node);
@@ -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;
 }
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