switch on typeid with type cases

This commit is contained in:
gingerBill
2018-10-13 11:07:56 +01:00
parent 0971a59493
commit 73e9dbbf8c
4 changed files with 44 additions and 27 deletions
+32 -18
View File
@@ -729,32 +729,46 @@ void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) {
add_constant_switch_case(ctx, &seen, rhs);
} else {
Operand y = {};
check_expr(ctx, &y, expr);
if (is_type_typeid(x.type)) {
check_expr_or_type(ctx, &y, expr, x.type);
} else {
check_expr(ctx, &y, expr);
}
if (x.mode == Addressing_Invalid ||
y.mode == Addressing_Invalid) {
continue;
}
convert_to_typed(ctx, &y, x.type);
if (y.mode == Addressing_Invalid) {
continue;
}
// NOTE(bill): the ordering here matters
Operand z = y;
check_comparison(ctx, &z, &x, Token_CmpEq);
if (z.mode == Addressing_Invalid) {
continue;
}
if (y.mode != Addressing_Constant) {
if (complete) {
error(y.expr, "#complete switch statement only allows constant case clauses");
if (y.mode == Addressing_Type) {
Type *t = y.type;
if (t == nullptr || t == t_invalid || is_type_polymorphic(t)) {
error(y.expr, "Invalid type for case clause");
continue;
}
t = default_type(t);
add_type_info_type(ctx, t);
} else {
convert_to_typed(ctx, &y, x.type);
if (y.mode == Addressing_Invalid) {
continue;
}
continue;
}
add_constant_switch_case(ctx, &seen, y);
// NOTE(bill): the ordering here matters
Operand z = y;
check_comparison(ctx, &z, &x, Token_CmpEq);
if (z.mode == Addressing_Invalid) {
continue;
}
if (y.mode != Addressing_Constant) {
if (complete) {
error(y.expr, "#complete switch statement only allows constant case clauses");
}
continue;
}
add_constant_switch_case(ctx, &seen, y);
}
}
}
+8 -1
View File
@@ -7145,7 +7145,14 @@ void ir_build_stmt_internal(irProcedure *proc, Ast *node) {
irValue *cond_rhs = ir_emit_comp(proc, op, tag, rhs);
cond = ir_emit_arith(proc, Token_And, cond_lhs, cond_rhs, t_bool);
} else {
cond = ir_emit_comp(proc, Token_CmpEq, tag, ir_build_expr(proc, expr));
if (expr->tav.mode == Addressing_Type) {
GB_ASSERT(is_type_typeid(ir_type(tag)));
irValue *e = ir_typeid(proc->module, expr->tav.type);
e = ir_emit_conv(proc, e, ir_type(tag));
cond = ir_emit_comp(proc, Token_CmpEq, tag, e);
} else {
cond = ir_emit_comp(proc, Token_CmpEq, tag, ir_build_expr(proc, expr));
}
}
ir_emit_if(proc, cond, body, next_cond);
ir_start_block(proc, next_cond);