Browse Source

switch on typeid with type cases

gingerBill 6 years ago
parent
commit
73e9dbbf8c
4 changed files with 43 additions and 26 deletions
  1. 2 4
      core/fmt/fmt.odin
  2. 2 4
      core/runtime/internal.odin
  3. 31 17
      src/check_stmt.cpp
  4. 8 1
      src/ir.cpp

+ 2 - 4
core/fmt/fmt.odin

@@ -239,8 +239,7 @@ write_type :: proc(buf: ^String_Buffer, ti: ^runtime.Type_Info) {
 	case runtime.Type_Info_Named:
 		write_string(buf, info.name);
 	case runtime.Type_Info_Integer:
-		a := any{id = ti.id};
-		switch in a {
+		switch ti.id {
 		case int:     write_string(buf, "int");
 		case uint:    write_string(buf, "uint");
 		case uintptr: write_string(buf, "uintptr");
@@ -263,8 +262,7 @@ write_type :: proc(buf: ^String_Buffer, ti: ^runtime.Type_Info) {
 			write_string(buf, "string");
 		}
 	case runtime.Type_Info_Boolean:
-		a := any{id = ti.id};
-		switch in a {
+		switch ti.id {
 		case bool: write_string(buf, "bool");
 		case:
 			write_byte(buf, 'b');

+ 2 - 4
core/runtime/internal.odin

@@ -63,8 +63,7 @@ print_type :: proc(fd: os.Handle, ti: ^Type_Info) {
 	case Type_Info_Named:
 		os.write_string(fd, info.name);
 	case Type_Info_Integer:
-		a := any{id = ti.id};
-		switch _ in a {
+		switch ti.id {
 		case int:     os.write_string(fd, "int");
 		case uint:    os.write_string(fd, "uint");
 		case uintptr: os.write_string(fd, "uintptr");
@@ -83,8 +82,7 @@ print_type :: proc(fd: os.Handle, ti: ^Type_Info) {
 	case Type_Info_String:
 		os.write_string(fd, "string");
 	case Type_Info_Boolean:
-		a := any{id = ti.id};
-		switch _ in a {
+		switch ti.id {
 		case bool: os.write_string(fd, "bool");
 		case:
 			os.write_byte(fd, 'b');

+ 31 - 17
src/check_stmt.cpp

@@ -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;
-				}
+				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;
+					}
 
-				// 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");
+					// 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;
 					}
-					continue;
-				}
 
-				add_constant_switch_case(ctx, &seen, y);
+					add_constant_switch_case(ctx, &seen, y);
+				}
 			}
 		}
 

+ 8 - 1
src/ir.cpp

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