Commit a922d5d42a

Andrew Kelley <superjoe30@gmail.com>
2016-01-23 08:34:47
implement literal error values
See #23
1 parent 1543043
src/all_types.hpp
@@ -310,6 +310,7 @@ enum CastOp {
     CastOpToUnknownSizeArray,
     CastOpMaybeWrap,
     CastOpPointerReinterpret,
+    CastOpErrToInt,
 };
 
 struct AstNodeFnCallExpr {
@@ -999,6 +1000,7 @@ struct CodeGen {
     bool error_during_imports;
     uint32_t next_node_index;
     uint32_t next_error_index;
+    TypeTableEntry *err_tag_type;
 };
 
 struct VariableTableEntry {
src/analyze.cpp
@@ -233,11 +233,10 @@ static TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) {
         entry->data.error.child_type = child_type;
 
         if (child_type->size_in_bits == 0) {
-            TypeTableEntry *tag_type = get_smallest_unsigned_int_type(g, g->next_error_index);
-            entry->type_ref = tag_type->type_ref;
-            entry->size_in_bits = tag_type->size_in_bits;
-            entry->align_in_bits = tag_type->align_in_bits;
-            entry->di_type = tag_type->di_type;
+            entry->type_ref = g->err_tag_type->type_ref;
+            entry->size_in_bits = g->err_tag_type->size_in_bits;
+            entry->align_in_bits = g->err_tag_type->align_in_bits;
+            entry->di_type = g->err_tag_type->di_type;
 
         } else {
             zig_panic("TODO get_error_type non-void");
@@ -2869,6 +2868,10 @@ static void eval_const_expr_implicit_cast(CodeGen *g, AstNode *node, AstNode *ex
             const_val->data.x_maybe = other_val;
             const_val->ok = true;
             break;
+        case CastOpErrToInt:
+            bignum_init_unsigned(&const_val->data.x_bignum, other_val->data.x_err->value);
+            const_val->ok = true;
+            break;
     }
 }
 
@@ -2975,6 +2978,24 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B
         }
     }
 
+    // explicit cast from %void to integer type which can fit it
+    if (actual_type->id == TypeTableEntryIdError &&
+        actual_type->data.error.child_type->size_in_bits == 0 &&
+        wanted_type->id == TypeTableEntryIdInt)
+    {
+        BigNum bn;
+        bignum_init_unsigned(&bn, g->next_error_index);
+        if (bignum_fits_in_bits(&bn, wanted_type->size_in_bits, wanted_type->data.integral.is_signed)) {
+            node->data.fn_call_expr.cast_op = CastOpErrToInt;
+            eval_const_expr_implicit_cast(g, node, expr_node);
+            return wanted_type;
+        } else {
+            add_node_error(g, node,
+                    buf_sprintf("too many error values to fit in '%s'", buf_ptr(&wanted_type->name)));
+            return g->builtin_types.entry_invalid;
+        }
+    }
+
     add_node_error(g, node,
         buf_sprintf("invalid cast from type '%s' to '%s'",
             buf_ptr(&actual_type->name),
@@ -4353,6 +4374,9 @@ void semantic_analyze(CodeGen *g) {
             }
         }
     }
+
+    g->err_tag_type = get_smallest_unsigned_int_type(g, g->next_error_index);
+
     {
         auto it = g->import_table.entry_iterator();
         for (;;) {
src/codegen.cpp
@@ -284,6 +284,13 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {
             zig_unreachable();
         case CastOpNoop:
             return expr_val;
+        case CastOpErrToInt:
+            assert(actual_type->id == TypeTableEntryIdError);
+            if (actual_type->data.error.child_type->size_in_bits == 0) {
+                return expr_val;
+            } else {
+                zig_panic("TODO");
+            }
         case CastOpMaybeWrap:
             {
                 assert(cast_expr->tmp_ptr);
@@ -2122,6 +2129,12 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
         } else {
             return global_value;
         }
+    } else if (type_entry->id == TypeTableEntryIdError) {
+        if (type_entry->data.error.child_type->size_in_bits == 0) {
+            return LLVMConstInt(g->err_tag_type->type_ref, const_val->data.x_err->value, false);
+        } else {
+            zig_panic("TODO");
+        }
     } else {
         zig_unreachable();
     }
test/run_tests.cpp
@@ -1258,6 +1258,22 @@ pub fn main(args: [][]u8) i32 => {
 }
     )SOURCE", "OK\n");
 
+    add_simple_case("error values", R"SOURCE(
+import "std.zig";
+%.err1;
+%.err2;
+pub fn main(args: [][]u8) i32 => {
+    const a = i32(%.err1);
+    const b = i32(%.err2);
+    if (a == b) {
+        print_str("BAD\n");
+    }
+
+    print_str("OK\n");
+    return 0;
+}
+    )SOURCE", "OK\n");
+
 }