implement literal error values

See #23
This commit is contained in:
Andrew Kelley 2016-01-23 00:34:47 -07:00
parent 1543043bf5
commit a922d5d42a
4 changed files with 60 additions and 5 deletions

View File

@ -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 {

View File

@ -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 (;;) {

View File

@ -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();
}

View File

@ -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");
}