aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGinger Bill <bill@gingerbill.org>2017-04-30 15:29:46 +0100
committerGinger Bill <bill@gingerbill.org>2017-04-30 15:29:46 +0100
commite63393e3941f43aca0976367d36f22207758e4a1 (patch)
treec8e69d0a0cf816cdc0ea625e77b6c68508abfdca
parent784f3ecf7e427c1d948541f62253d6d2eab9e70d (diff)
Add type assertion for `any`
-rw-r--r--src/check_expr.c56
-rw-r--r--src/ir.c72
2 files changed, 101 insertions, 27 deletions
diff --git a/src/check_expr.c b/src/check_expr.c
index c700e7d25..3722652b6 100644
--- a/src/check_expr.c
+++ b/src/check_expr.c
@@ -5583,38 +5583,44 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
return kind;
}
- if (!is_type_union(src)) {
- error_node(o->expr, "Type assertions can only operate on unions");
- o->mode = Addressing_Invalid;
- o->expr = node;
- return kind;
- }
+ if (is_type_union(src)) {
+ bool ok = false;
+ for (isize i = 1; i < bsrc->Record.variant_count; i++) {
+ Entity *f = bsrc->Record.variants[i];
+ if (are_types_identical(f->type, dst)) {
+ ok = true;
+ break;
+ }
+ }
- bool ok = false;
- for (isize i = 1; i < bsrc->Record.variant_count; i++) {
- Entity *f = bsrc->Record.variants[i];
- if (are_types_identical(f->type, dst)) {
- ok = true;
- break;
+ if (!ok) {
+ gbString expr_str = expr_to_string(o->expr);
+ gbString dst_type_str = type_to_string(t);
+ error_node(o->expr, "Cannot type assert `%s` to `%s`", expr_str, dst_type_str);
+ gb_string_free(dst_type_str);
+ gb_string_free(expr_str);
+ o->mode = Addressing_Invalid;
+ o->expr = node;
+ return kind;
}
- }
- if (!ok) {
- gbString expr_str = expr_to_string(o->expr);
- gbString dst_type_str = type_to_string(t);
- error_node(o->expr, "Cannot type assert `%s` to `%s`", expr_str, dst_type_str);
- gb_string_free(dst_type_str);
- gb_string_free(expr_str);
+ add_type_info_type(c, o->type);
+ add_type_info_type(c, t);
+
+ o->type = t;
+ o->mode = Addressing_OptionalOk;
+ } else if (is_type_any(o->type)) {
+ o->type = t;
+ o->mode = Addressing_OptionalOk;
+
+ add_type_info_type(c, o->type);
+ add_type_info_type(c, t);
+ } else {
+ error_node(o->expr, "Type assertions can only operate on unions");
o->mode = Addressing_Invalid;
o->expr = node;
return kind;
}
-
- add_type_info_type(c, o->type);
- add_type_info_type(c, t);
-
- o->type = t;
- o->mode = Addressing_OptionalOk;
case_end;
case_ast_node(ue, UnaryExpr, node);
diff --git a/src/ir.c b/src/ir.c
index 12bb07826..0b8319333 100644
--- a/src/ir.c
+++ b/src/ir.c
@@ -3112,6 +3112,64 @@ irValue *ir_emit_union_cast(irProcedure *proc, irValue *value, Type *type, Token
return ir_emit_load(proc, v);
}
+irAddr ir_emit_any_cast_addr(irProcedure *proc, irValue *value, Type *type, TokenPos pos) {
+ gbAllocator a = proc->module->allocator;
+ Type *src_type = ir_type(value);
+ bool is_tuple = true;
+ Type *tuple = type;
+ if (type->kind != Type_Tuple) {
+ is_tuple = false;
+ tuple = make_optional_ok_type(a, type);
+ }
+ Type *dst_type = tuple->Tuple.variables[0]->type;
+
+ irValue *v = ir_add_local_generated(proc, tuple);
+
+ irValue *ti_ptr = ir_type_info(proc, dst_type);
+ irValue *any_ti = ir_emit_struct_ev(proc, value, 1);
+
+
+ irBlock *ok_block = ir_new_block(proc, NULL, "any_cast.ok");
+ irBlock *end_block = ir_new_block(proc, NULL, "any_cast.end");
+ irValue *cond = ir_emit_comp(proc, Token_CmpEq, any_ti, ti_ptr);
+ ir_emit_if(proc, cond, ok_block, end_block);
+ ir_start_block(proc, ok_block);
+
+ irValue *gep0 = ir_emit_struct_ep(proc, v, 0);
+ irValue *gep1 = ir_emit_struct_ep(proc, v, 1);
+
+ irValue *any_data = ir_emit_struct_ev(proc, value, 0);
+ irValue *ptr = ir_emit_conv(proc, any_data, make_type_pointer(a, dst_type));
+ ir_emit_store(proc, gep0, ir_emit_load(proc, ptr));
+ ir_emit_store(proc, gep1, v_true);
+
+ ir_emit_jump(proc, end_block);
+ ir_start_block(proc, end_block);
+
+ if (!is_tuple) {
+ // NOTE(bill): Panic on invalid conversion
+
+ irValue *ok = ir_emit_load(proc, ir_emit_struct_ep(proc, v, 1));
+ irValue **args = gb_alloc_array(a, irValue *, 6);
+ args[0] = ok;
+
+ args[1] = ir_const_string(a, pos.file);
+ args[2] = ir_const_int(a, pos.line);
+ args[3] = ir_const_int(a, pos.column);
+
+ args[4] = any_ti;
+ args[5] = ti_ptr;
+ ir_emit_global_call(proc, "__type_assertion_check", args, 6);
+
+ return ir_addr(ir_emit_struct_ep(proc, v, 0));
+ }
+ return ir_addr(v);
+}
+irValue *ir_emit_any_cast(irProcedure *proc, irValue *value, Type *type, TokenPos pos) {
+ return ir_addr_load(proc, ir_emit_any_cast_addr(proc, value, type, pos));
+}
+
+
isize ir_type_info_index(CheckerInfo *info, Type *type) {
type = default_type(type);
@@ -3607,12 +3665,16 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
#endif
case_ast_node(ta, TypeAssertion, expr);
+ TokenPos pos = ast_node_token(expr).pos;
Type *type = tv->type;
irValue *e = ir_build_expr(proc, ta->expr);
Type *t = type_deref(ir_type(e));
if (is_type_union(t)) {
ir_emit_comment(proc, str_lit("cast - union_cast"));
- return ir_emit_union_cast(proc, e, type, ast_node_token(expr).pos);
+ return ir_emit_union_cast(proc, e, type, pos);
+ } else if (is_type_any(t)) {
+ ir_emit_comment(proc, str_lit("cast - any_cast"));
+ return ir_emit_any_cast(proc, e, type, pos);
} else {
GB_PANIC("TODO(bill): type assertion %s", type_to_string(ir_type(e)));
}
@@ -4727,14 +4789,20 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
case_end;
case_ast_node(ta, TypeAssertion, expr);
+ gbAllocator a = proc->module->allocator;
+ TokenPos pos = ast_node_token(expr).pos;
irValue *e = ir_build_expr(proc, ta->expr);
Type *t = type_deref(ir_type(e));
if (is_type_union(t)) {
Type *type = type_of_expr(proc->module->info, expr);
irValue *v = ir_add_local_generated(proc, type);
ir_emit_comment(proc, str_lit("cast - union_cast"));
- ir_emit_store(proc, v, ir_emit_union_cast(proc, ir_build_expr(proc, ta->expr), type, ast_node_token(expr).pos));
+ ir_emit_store(proc, v, ir_emit_union_cast(proc, ir_build_expr(proc, ta->expr), type, pos));
return ir_addr(v);
+ } else if (is_type_any(t)) {
+ ir_emit_comment(proc, str_lit("cast - any_cast"));
+ Type *type = type_of_expr(proc->module->info, expr);
+ return ir_emit_any_cast_addr(proc, ir_build_expr(proc, ta->expr), type, pos);
} else {
GB_PANIC("TODO(bill): type assertion %s", type_to_string(ir_type(e)));
}