mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 07:38:48 +00:00
Multiple type cases for match in
This commit is contained in:
@@ -68,6 +68,21 @@ main :: proc() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
t := type_info(int);
|
||||||
|
using Type_Info;
|
||||||
|
match i in t {
|
||||||
|
case Integer, Float:
|
||||||
|
fmt.println("It's a number");
|
||||||
|
}
|
||||||
|
|
||||||
|
x: any = 123;
|
||||||
|
match i in x {
|
||||||
|
case int, f32:
|
||||||
|
fmt.println("It's an int or f32");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
cond := true;
|
cond := true;
|
||||||
x: int;
|
x: int;
|
||||||
|
|||||||
+47
-50
@@ -942,7 +942,6 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
|||||||
}
|
}
|
||||||
ast_node(cc, CaseClause, stmt);
|
ast_node(cc, CaseClause, stmt);
|
||||||
|
|
||||||
|
|
||||||
for_array(j, cc->list) {
|
for_array(j, cc->list) {
|
||||||
AstNode *expr = cc->list.e[j];
|
AstNode *expr = cc->list.e[j];
|
||||||
Operand y = {0};
|
Operand y = {0};
|
||||||
@@ -1058,7 +1057,6 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// NOTE(bill): Check for multiple defaults
|
// NOTE(bill): Check for multiple defaults
|
||||||
AstNode *first_default = NULL;
|
AstNode *first_default = NULL;
|
||||||
ast_node(bs, BlockStmt, ms->body);
|
ast_node(bs, BlockStmt, ms->body);
|
||||||
@@ -1093,7 +1091,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
MapBool seen = {0};
|
MapBool seen = {0}; // Multimap
|
||||||
map_bool_init(&seen, heap_allocator());
|
map_bool_init(&seen, heap_allocator());
|
||||||
|
|
||||||
for_array(i, bs->stmts) {
|
for_array(i, bs->stmts) {
|
||||||
@@ -1107,69 +1105,68 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
|||||||
// TODO(bill): Make robust
|
// TODO(bill): Make robust
|
||||||
Type *bt = base_type(type_deref(x.type));
|
Type *bt = base_type(type_deref(x.type));
|
||||||
|
|
||||||
AstNode *type_expr = cc->list.count > 0 ? cc->list.e[0] : NULL;
|
|
||||||
Type *case_type = NULL;
|
Type *case_type = NULL;
|
||||||
if (type_expr != NULL) { // Otherwise it's a default expression
|
for_array(type_index, cc->list) {
|
||||||
Operand y = {0};
|
AstNode *type_expr = cc->list.e[type_index];
|
||||||
check_expr_or_type(c, &y, type_expr);
|
if (type_expr != NULL) { // Otherwise it's a default expression
|
||||||
|
Operand y = {0};
|
||||||
|
check_expr_or_type(c, &y, type_expr);
|
||||||
|
|
||||||
if (match_type_kind == MatchType_Union) {
|
if (match_type_kind == MatchType_Union) {
|
||||||
GB_ASSERT(is_type_union(bt));
|
GB_ASSERT(is_type_union(bt));
|
||||||
bool tag_type_found = false;
|
bool tag_type_found = false;
|
||||||
for (isize i = 0; i < bt->Record.variant_count; i++) {
|
for (isize i = 0; i < bt->Record.variant_count; i++) {
|
||||||
Entity *f = bt->Record.variants[i];
|
Entity *f = bt->Record.variants[i];
|
||||||
if (are_types_identical(f->type, y.type)) {
|
if (are_types_identical(f->type, y.type)) {
|
||||||
tag_type_found = true;
|
tag_type_found = true;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (!tag_type_found) {
|
||||||
|
gbString type_str = type_to_string(y.type);
|
||||||
|
error_node(y.expr, "Unknown tag type, got `%s`", type_str);
|
||||||
|
gb_string_free(type_str);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
case_type = y.type;
|
||||||
|
} else if (match_type_kind == MatchType_Any) {
|
||||||
|
case_type = y.type;
|
||||||
|
} else {
|
||||||
|
GB_PANIC("Unknown type to type match statement");
|
||||||
}
|
}
|
||||||
if (!tag_type_found) {
|
|
||||||
gbString type_str = type_to_string(y.type);
|
|
||||||
error_node(y.expr, "Unknown tag type, got `%s`", type_str);
|
|
||||||
gb_string_free(type_str);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
case_type = y.type;
|
|
||||||
} else if (match_type_kind == MatchType_Any) {
|
|
||||||
case_type = y.type;
|
|
||||||
} else {
|
|
||||||
GB_PANIC("Unknown type to type match statement");
|
|
||||||
}
|
|
||||||
|
|
||||||
HashKey key = hash_pointer(y.type);
|
HashKey key = hash_pointer(y.type);
|
||||||
bool *found = map_bool_get(&seen, key);
|
bool *found = map_bool_get(&seen, key);
|
||||||
if (found) {
|
if (found) {
|
||||||
TokenPos pos = cc->token.pos;
|
TokenPos pos = cc->token.pos;
|
||||||
gbString expr_str = expr_to_string(y.expr);
|
gbString expr_str = expr_to_string(y.expr);
|
||||||
error_node(y.expr,
|
error_node(y.expr,
|
||||||
"Duplicate type case `%s`\n"
|
"Duplicate type case `%s`\n"
|
||||||
"\tprevious type case at %.*s(%td:%td)",
|
"\tprevious type case at %.*s(%td:%td)",
|
||||||
expr_str,
|
expr_str,
|
||||||
LIT(pos.file), pos.line, pos.column);
|
LIT(pos.file), pos.line, pos.column);
|
||||||
gb_string_free(expr_str);
|
gb_string_free(expr_str);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
map_bool_set(&seen, key, cast(bool)true);
|
||||||
}
|
}
|
||||||
map_bool_set(&seen, key, cast(bool)true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
check_open_scope(c, stmt);
|
if (cc->list.count > 1) {
|
||||||
|
case_type = NULL;
|
||||||
|
}
|
||||||
if (case_type == NULL) {
|
if (case_type == NULL) {
|
||||||
case_type = type_deref(x.type);
|
case_type = x.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
add_type_info_type(c, case_type);
|
add_type_info_type(c, case_type);
|
||||||
|
|
||||||
|
check_open_scope(c, stmt);
|
||||||
{
|
{
|
||||||
// NOTE(bill): Dummy type
|
Entity *tag_var = make_entity_variable(c->allocator, c->context.scope, lhs->Ident, case_type, true);
|
||||||
Type *tt = case_type;
|
|
||||||
if (is_type_pointer(x.type)) {
|
|
||||||
tt = make_type_pointer(c->allocator, case_type);
|
|
||||||
add_type_info_type(c, tt);
|
|
||||||
}
|
|
||||||
Entity *tag_var = make_entity_variable(c->allocator, c->context.scope, lhs->Ident, tt, true);
|
|
||||||
tag_var->flags |= EntityFlag_Used;
|
tag_var->flags |= EntityFlag_Used;
|
||||||
add_entity(c, c->context.scope, lhs, tag_var);
|
add_entity(c, c->context.scope, lhs, tag_var);
|
||||||
add_entity_use(c, lhs, tag_var);
|
add_entity_use(c, lhs, tag_var);
|
||||||
|
add_implicit_entity(c, stmt, tag_var);
|
||||||
}
|
}
|
||||||
check_stmt_list(c, cc->stmts, mod_flags);
|
check_stmt_list(c, cc->stmts, mod_flags);
|
||||||
check_close_scope(c);
|
check_close_scope(c);
|
||||||
|
|||||||
+10
-1
@@ -165,7 +165,7 @@ bool is_operand_nil(Operand o) {
|
|||||||
|
|
||||||
typedef struct BlockLabel {
|
typedef struct BlockLabel {
|
||||||
String name;
|
String name;
|
||||||
AstNode *label; // AstNode_Label
|
AstNode *label; // AstNode_Label;
|
||||||
} BlockLabel;
|
} BlockLabel;
|
||||||
|
|
||||||
// DeclInfo is used to store information of certain declarations to allow for "any order" usage
|
// DeclInfo is used to store information of certain declarations to allow for "any order" usage
|
||||||
@@ -286,6 +286,7 @@ typedef struct CheckerInfo {
|
|||||||
MapScope scopes; // Key: AstNode * | Node -> Scope
|
MapScope scopes; // Key: AstNode * | Node -> Scope
|
||||||
MapExprInfo untyped; // Key: AstNode * | Expression -> ExprInfo
|
MapExprInfo untyped; // Key: AstNode * | Expression -> ExprInfo
|
||||||
MapDeclInfo entities; // Key: Entity *
|
MapDeclInfo entities; // Key: Entity *
|
||||||
|
MapEntity implicits; // Key: AstNode *
|
||||||
MapEntity foreigns; // Key: String
|
MapEntity foreigns; // Key: String
|
||||||
MapAstFile files; // Key: String (full path)
|
MapAstFile files; // Key: String (full path)
|
||||||
MapIsize type_info_map; // Key: Type *
|
MapIsize type_info_map; // Key: Type *
|
||||||
@@ -674,6 +675,7 @@ void init_checker_info(CheckerInfo *i) {
|
|||||||
map_decl_info_init(&i->entities, a);
|
map_decl_info_init(&i->entities, a);
|
||||||
map_expr_info_init(&i->untyped, a);
|
map_expr_info_init(&i->untyped, a);
|
||||||
map_entity_init(&i->foreigns, a);
|
map_entity_init(&i->foreigns, a);
|
||||||
|
map_entity_init(&i->implicits, a);
|
||||||
map_isize_init(&i->type_info_map, a);
|
map_isize_init(&i->type_info_map, a);
|
||||||
map_ast_file_init(&i->files, a);
|
map_ast_file_init(&i->files, a);
|
||||||
i->type_info_count = 0;
|
i->type_info_count = 0;
|
||||||
@@ -688,6 +690,7 @@ void destroy_checker_info(CheckerInfo *i) {
|
|||||||
map_decl_info_destroy(&i->entities);
|
map_decl_info_destroy(&i->entities);
|
||||||
map_expr_info_destroy(&i->untyped);
|
map_expr_info_destroy(&i->untyped);
|
||||||
map_entity_destroy(&i->foreigns);
|
map_entity_destroy(&i->foreigns);
|
||||||
|
map_entity_destroy(&i->implicits);
|
||||||
map_isize_destroy(&i->type_info_map);
|
map_isize_destroy(&i->type_info_map);
|
||||||
map_ast_file_destroy(&i->files);
|
map_ast_file_destroy(&i->files);
|
||||||
}
|
}
|
||||||
@@ -873,6 +876,12 @@ void add_entity_and_decl_info(Checker *c, AstNode *identifier, Entity *e, DeclIn
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void add_implicit_entity(Checker *c, AstNode *node, Entity *e) {
|
||||||
|
GB_ASSERT(node != NULL);
|
||||||
|
GB_ASSERT(e != NULL);
|
||||||
|
map_entity_set(&c->info.implicits, hash_pointer(node), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void add_type_info_type(Checker *c, Type *t) {
|
void add_type_info_type(Checker *c, Type *t) {
|
||||||
if (t == NULL) {
|
if (t == NULL) {
|
||||||
|
|||||||
@@ -341,8 +341,8 @@ typedef struct irValueTypeName {
|
|||||||
typedef struct irValueGlobal {
|
typedef struct irValueGlobal {
|
||||||
Entity * entity;
|
Entity * entity;
|
||||||
Type * type;
|
Type * type;
|
||||||
irValue * value;
|
irValue * value;
|
||||||
irValueArray referrers;
|
irValueArray referrers;
|
||||||
bool is_constant;
|
bool is_constant;
|
||||||
bool is_private;
|
bool is_private;
|
||||||
bool is_thread_local;
|
bool is_thread_local;
|
||||||
@@ -359,7 +359,8 @@ typedef struct irValueParam {
|
|||||||
|
|
||||||
typedef struct irValue {
|
typedef struct irValue {
|
||||||
irValueKind kind;
|
irValueKind kind;
|
||||||
i32 index;
|
i32 index;
|
||||||
|
bool index_set;
|
||||||
union {
|
union {
|
||||||
irValueConstant Constant;
|
irValueConstant Constant;
|
||||||
irValueConstantSlice ConstantSlice;
|
irValueConstantSlice ConstantSlice;
|
||||||
@@ -1015,6 +1016,8 @@ irValue *ir_emit(irProcedure *proc, irValue *instr) {
|
|||||||
if (!ir_is_instr_terminating(i)) {
|
if (!ir_is_instr_terminating(i)) {
|
||||||
array_add(&b->instrs, instr);
|
array_add(&b->instrs, instr);
|
||||||
}
|
}
|
||||||
|
} else if (instr->Instr.kind != irInstr_Unreachable) {
|
||||||
|
GB_PANIC("ir_emit: Instruction missing parent block");
|
||||||
}
|
}
|
||||||
return instr;
|
return instr;
|
||||||
}
|
}
|
||||||
@@ -1108,7 +1111,9 @@ irBlock *ir_new_block(irProcedure *proc, AstNode *node, char *label) {
|
|||||||
|
|
||||||
void ir_add_block_to_proc(irProcedure *proc, irBlock *b) {
|
void ir_add_block_to_proc(irProcedure *proc, irBlock *b) {
|
||||||
for_array(i, proc->blocks) {
|
for_array(i, proc->blocks) {
|
||||||
GB_ASSERT(proc->blocks.e[i] != b);
|
if (proc->blocks.e[i] == b) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
array_add(&proc->blocks, b);
|
array_add(&proc->blocks, b);
|
||||||
b->index = proc->block_count++;
|
b->index = proc->block_count++;
|
||||||
@@ -4876,7 +4881,25 @@ void ir_build_range_interval(irProcedure *proc, AstNodeIntervalExpr *node, Type
|
|||||||
if (done_) *done_ = done;
|
if (done_) *done_ = done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ir_store_type_case_implicit(irProcedure *proc, AstNode *clause, irValue *value) {
|
||||||
|
Entity **found = map_entity_get(&proc->module->info->implicits, hash_pointer(clause));
|
||||||
|
GB_ASSERT(found != NULL);
|
||||||
|
Entity *e = *found; GB_ASSERT(e != NULL);
|
||||||
|
irValue *x = ir_add_local(proc, e, NULL);
|
||||||
|
ir_emit_store(proc, x, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ir_type_case_body(irProcedure *proc, AstNode *label, AstNode *clause, irBlock *body, irBlock *done) {
|
||||||
|
ast_node(cc, CaseClause, clause);
|
||||||
|
|
||||||
|
ir_push_target_list(proc, label, done, NULL, NULL);
|
||||||
|
ir_open_scope(proc);
|
||||||
|
ir_build_stmt_list(proc, cc->stmts);
|
||||||
|
ir_close_scope(proc, irDeferExit_Default, body);
|
||||||
|
ir_pop_target_list(proc);
|
||||||
|
|
||||||
|
ir_emit_jump(proc, done);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
|
void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
|
||||||
@@ -5504,166 +5527,116 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
|
|||||||
ast_node(as, AssignStmt, ms->tag);
|
ast_node(as, AssignStmt, ms->tag);
|
||||||
GB_ASSERT(as->lhs.count == 1);
|
GB_ASSERT(as->lhs.count == 1);
|
||||||
GB_ASSERT(as->rhs.count == 1);
|
GB_ASSERT(as->rhs.count == 1);
|
||||||
AstNode *lhs = as->lhs.e[0];
|
|
||||||
AstNode *rhs = as->rhs.e[0];
|
|
||||||
|
|
||||||
irValue *parent = ir_build_expr(proc, rhs);
|
irValue *parent = ir_build_expr(proc, as->rhs.e[0]);
|
||||||
|
Type *parent_type = ir_type(parent);
|
||||||
bool is_parent_ptr = is_type_pointer(ir_type(parent));
|
bool is_parent_ptr = is_type_pointer(ir_type(parent));
|
||||||
|
|
||||||
MatchTypeKind match_type_kind = check_valid_type_match_type(ir_type(parent));
|
MatchTypeKind match_type_kind = check_valid_type_match_type(ir_type(parent));
|
||||||
GB_ASSERT(match_type_kind != MatchType_Invalid);
|
GB_ASSERT(match_type_kind != MatchType_Invalid);
|
||||||
|
|
||||||
|
irValue *parent_value = parent;
|
||||||
|
|
||||||
|
irValue *parent_ptr = parent;
|
||||||
|
if (!is_parent_ptr) {
|
||||||
|
parent_ptr = ir_address_from_load_or_generate_local(proc, parent_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
irValue *tag_index = NULL;
|
irValue *tag_index = NULL;
|
||||||
irValue *union_data = NULL;
|
irValue *union_data = NULL;
|
||||||
if (match_type_kind == MatchType_Union) {
|
if (match_type_kind == MatchType_Union) {
|
||||||
if (!is_parent_ptr) {
|
|
||||||
parent = ir_address_from_load_or_generate_local(proc, parent);
|
|
||||||
}
|
|
||||||
ir_emit_comment(proc, str_lit("get union's tag"));
|
ir_emit_comment(proc, str_lit("get union's tag"));
|
||||||
tag_index = ir_emit_load(proc, ir_emit_union_tag_ptr(proc, parent));
|
tag_index = ir_emit_load(proc, ir_emit_union_tag_ptr(proc, parent_ptr));
|
||||||
union_data = ir_emit_conv(proc, parent, t_rawptr);
|
union_data = ir_emit_conv(proc, parent_ptr, t_rawptr);
|
||||||
} else if (match_type_kind == MatchType_Any) {
|
|
||||||
if (!is_parent_ptr) {
|
|
||||||
parent = ir_address_from_load_or_generate_local(proc, parent);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
irBlock *start_block = ir_new_block(proc, node, "type-match.case.first");
|
irBlock *start_block = ir_new_block(proc, node, "typematch.case.first");
|
||||||
ir_emit_jump(proc, start_block);
|
ir_emit_jump(proc, start_block);
|
||||||
ir_start_block(proc, start_block);
|
ir_start_block(proc, start_block);
|
||||||
|
|
||||||
irBlock *done = ir_new_block(proc, node, "type-match.done"); // NOTE(bill): Append later
|
// NOTE(bill): Append this later
|
||||||
|
irBlock *done = ir_new_block(proc, node, "typematch.done");
|
||||||
|
AstNode *default_ = NULL;
|
||||||
|
|
||||||
ast_node(body, BlockStmt, ms->body);
|
ast_node(body, BlockStmt, ms->body);
|
||||||
|
|
||||||
String tag_var_name = lhs->Ident.string;
|
gb_local_persist i32 weird_count = 0;
|
||||||
|
|
||||||
|
|
||||||
AstNodeArray default_stmts = {0};
|
|
||||||
irBlock *default_block = NULL;
|
|
||||||
|
|
||||||
|
|
||||||
isize case_count = body->stmts.count;
|
|
||||||
for_array(i, body->stmts) {
|
for_array(i, body->stmts) {
|
||||||
AstNode *clause = body->stmts.e[i];
|
AstNode *clause = body->stmts.e[i];
|
||||||
ast_node(cc, CaseClause, clause);
|
ast_node(cc, CaseClause, clause);
|
||||||
|
|
||||||
Entity *tag_var_entity = NULL;
|
|
||||||
Type *tag_var_type = NULL;
|
|
||||||
if (str_eq(tag_var_name, str_lit("_"))) {
|
|
||||||
Type *t = type_of_expr(proc->module->info, cc->list.e[0]);
|
|
||||||
if (match_type_kind == MatchType_Union) {
|
|
||||||
t = make_type_pointer(proc->module->allocator, t);
|
|
||||||
}
|
|
||||||
tag_var_type = t;
|
|
||||||
} else {
|
|
||||||
Scope *scope = *map_scope_get(&proc->module->info->scopes, hash_pointer(clause));
|
|
||||||
tag_var_entity = current_scope_lookup_entity(scope, tag_var_name);
|
|
||||||
GB_ASSERT_MSG(tag_var_entity != NULL, "%.*s", LIT(tag_var_name));
|
|
||||||
tag_var_type = tag_var_entity->type;
|
|
||||||
}
|
|
||||||
GB_ASSERT(tag_var_type != NULL);
|
|
||||||
|
|
||||||
irBlock *next_cond = NULL;
|
|
||||||
irValue *cond = NULL;
|
|
||||||
|
|
||||||
if (cc->list.count == 0) {
|
if (cc->list.count == 0) {
|
||||||
// default case
|
default_ = clause;
|
||||||
default_stmts = cc->stmts;
|
|
||||||
default_block = ir_new_block(proc, clause, "type-match.dflt.body");
|
|
||||||
|
|
||||||
|
|
||||||
irValue *tag_var = NULL;
|
|
||||||
if (tag_var_entity != NULL) {
|
|
||||||
tag_var = ir_add_local(proc, tag_var_entity, NULL);
|
|
||||||
} else {
|
|
||||||
tag_var = ir_add_local_generated(proc, tag_var_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is_parent_ptr) {
|
|
||||||
ir_emit_store(proc, tag_var, ir_emit_load(proc, parent));
|
|
||||||
} else {
|
|
||||||
ir_emit_store(proc, tag_var, parent);
|
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
GB_ASSERT(cc->list.count == 1);
|
|
||||||
|
|
||||||
irBlock *body = ir_new_block(proc, clause, "type-match.case.body");
|
irBlock *body = ir_new_block(proc, clause, "typematch.body");
|
||||||
|
irBlock *next = NULL;
|
||||||
|
Type *case_type = NULL;
|
||||||
if (match_type_kind == MatchType_Union) {
|
for_array(type_index, cc->list) {
|
||||||
Type *bt = type_deref(tag_var_type);
|
next = ir_new_block(proc, NULL, "typematch.next");
|
||||||
irValue *index = NULL;
|
case_type = type_of_expr(proc->module->info, cc->list.e[type_index]);
|
||||||
Type *ut = base_type(type_deref(ir_type(parent)));
|
irValue *cond = NULL;
|
||||||
GB_ASSERT(ut->Record.kind == TypeRecord_Union);
|
if (match_type_kind == MatchType_Union) {
|
||||||
for (isize variant_index = 1; variant_index < ut->Record.variant_count; variant_index++) {
|
Type *bt = type_deref(case_type);
|
||||||
Entity *f = ut->Record.variants[variant_index];
|
irValue *index = NULL;
|
||||||
if (are_types_identical(f->type, bt)) {
|
Type *ut = base_type(type_deref(parent_type));
|
||||||
index = ir_const_int(allocator, variant_index);
|
GB_ASSERT(ut->Record.kind == TypeRecord_Union);
|
||||||
break;
|
for (isize variant_index = 1; variant_index < ut->Record.variant_count; variant_index++) {
|
||||||
|
Entity *f = ut->Record.variants[variant_index];
|
||||||
|
if (are_types_identical(f->type, bt)) {
|
||||||
|
index = ir_const_int(allocator, variant_index);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
GB_ASSERT(index != NULL);
|
||||||
|
cond = ir_emit_comp(proc, Token_CmpEq, tag_index, index);
|
||||||
|
} else if (match_type_kind == MatchType_Any) {
|
||||||
|
irValue *any_ti = ir_emit_load(proc, ir_emit_struct_ep(proc, parent_ptr, 0));
|
||||||
|
irValue *case_ti = ir_type_info(proc, case_type);
|
||||||
|
cond = ir_emit_comp(proc, Token_CmpEq, any_ti, case_ti);
|
||||||
}
|
}
|
||||||
GB_ASSERT(index != NULL);
|
GB_ASSERT(cond != NULL);
|
||||||
|
|
||||||
irValue *tag_var = NULL;
|
ir_emit_if(proc, cond, body, next);
|
||||||
if (tag_var_entity != NULL) {
|
ir_start_block(proc, next);
|
||||||
tag_var = ir_add_local(proc, tag_var_entity, NULL);
|
|
||||||
} else {
|
|
||||||
tag_var = ir_add_local_generated(proc, tag_var_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
Type *bt_ptr = make_type_pointer(proc->module->allocator, bt);
|
|
||||||
irValue *data_ptr = ir_emit_conv(proc, union_data, bt_ptr);
|
|
||||||
if (!is_type_pointer(type_deref(ir_type(tag_var)))) {
|
|
||||||
data_ptr = ir_emit_load(proc, data_ptr);
|
|
||||||
}
|
|
||||||
ir_emit_store(proc, tag_var, data_ptr);
|
|
||||||
|
|
||||||
cond = ir_emit_comp(proc, Token_CmpEq, tag_index, index);
|
|
||||||
} else if (match_type_kind == MatchType_Any) {
|
|
||||||
Type *type = tag_var_type;
|
|
||||||
irValue *any_data = ir_emit_load(proc, ir_emit_struct_ep(proc, parent, 1));
|
|
||||||
irValue *data = ir_emit_conv(proc, any_data, make_type_pointer(proc->module->allocator, type));
|
|
||||||
if (tag_var_entity != NULL) {
|
|
||||||
ir_module_add_value(proc->module, tag_var_entity, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
irValue *any_ti = ir_emit_load(proc, ir_emit_struct_ep(proc, parent, 0));
|
|
||||||
irValue *case_ti = ir_type_info(proc, type);
|
|
||||||
cond = ir_emit_comp(proc, Token_CmpEq, any_ti, case_ti);
|
|
||||||
} else {
|
|
||||||
GB_PANIC("Invalid type for type match statement");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
next_cond = ir_new_block(proc, clause, "type-match.case.next");
|
Entity *case_entity = NULL;
|
||||||
ir_emit_if(proc, cond, body, next_cond);
|
{
|
||||||
ir_start_block(proc, next_cond);
|
Entity **found = map_entity_get(&proc->module->info->implicits, hash_pointer(clause));
|
||||||
|
GB_ASSERT(found != NULL);
|
||||||
|
case_entity = *found;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
irValue *value = parent_value;
|
||||||
|
|
||||||
ir_start_block(proc, body);
|
ir_start_block(proc, body);
|
||||||
|
|
||||||
ir_push_target_list(proc, ms->label, done, NULL, NULL);
|
if (cc->list.count == 1) {
|
||||||
ir_open_scope(proc);
|
Type *ct = make_type_pointer(proc->module->allocator, case_entity->type);
|
||||||
ir_build_stmt_list(proc, cc->stmts);
|
irValue *data = NULL;
|
||||||
ir_close_scope(proc, irDeferExit_Default, body);
|
if (match_type_kind == MatchType_Union) {
|
||||||
ir_pop_target_list(proc);
|
data = union_data;
|
||||||
|
} else if (match_type_kind == MatchType_Any) {
|
||||||
|
irValue *any_data = ir_emit_load(proc, ir_emit_struct_ep(proc, parent_ptr, 1));
|
||||||
|
data = any_data;
|
||||||
|
}
|
||||||
|
value = ir_emit_load(proc, ir_emit_conv(proc, data, ct));
|
||||||
|
}
|
||||||
|
|
||||||
|
ir_store_type_case_implicit(proc, clause, value);
|
||||||
|
ir_type_case_body(proc, ms->label, clause, body, done);
|
||||||
|
ir_start_block(proc, next);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (default_ != NULL) {
|
||||||
|
ir_store_type_case_implicit(proc, default_, parent_value);
|
||||||
|
ir_type_case_body(proc, ms->label, default_, proc->curr_block, done);
|
||||||
|
} else {
|
||||||
ir_emit_jump(proc, done);
|
ir_emit_jump(proc, done);
|
||||||
proc->curr_block = next_cond;
|
|
||||||
// ir_start_block(proc, next_cond);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (default_block != NULL) {
|
|
||||||
ir_emit_jump(proc, default_block);
|
|
||||||
ir_start_block(proc, default_block);
|
|
||||||
|
|
||||||
ir_push_target_list(proc, ms->label, done, NULL, NULL);
|
|
||||||
ir_open_scope(proc);
|
|
||||||
ir_build_stmt_list(proc, default_stmts);
|
|
||||||
ir_close_scope(proc, irDeferExit_Default, default_block);
|
|
||||||
ir_pop_target_list(proc);
|
|
||||||
}
|
|
||||||
|
|
||||||
ir_emit_jump(proc, done);
|
|
||||||
ir_start_block(proc, done);
|
ir_start_block(proc, done);
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
@@ -5774,9 +5747,11 @@ void ir_number_proc_registers(irProcedure *proc) {
|
|||||||
GB_ASSERT(value->kind == irValue_Instr);
|
GB_ASSERT(value->kind == irValue_Instr);
|
||||||
irInstr *instr = &value->Instr;
|
irInstr *instr = &value->Instr;
|
||||||
if (ir_instr_type(instr) == NULL) { // NOTE(bill): Ignore non-returning instructions
|
if (ir_instr_type(instr) == NULL) { // NOTE(bill): Ignore non-returning instructions
|
||||||
|
value->index = -1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
value->index = reg_index;
|
value->index = reg_index;
|
||||||
|
value->index_set = true;
|
||||||
reg_index++;
|
reg_index++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5785,10 +5760,10 @@ void ir_number_proc_registers(irProcedure *proc) {
|
|||||||
void ir_begin_procedure_body(irProcedure *proc) {
|
void ir_begin_procedure_body(irProcedure *proc) {
|
||||||
array_add(&proc->module->procs, proc);
|
array_add(&proc->module->procs, proc);
|
||||||
|
|
||||||
array_init(&proc->blocks, heap_allocator());
|
array_init(&proc->blocks, heap_allocator());
|
||||||
array_init(&proc->defer_stmts, heap_allocator());
|
array_init(&proc->defer_stmts, heap_allocator());
|
||||||
array_init(&proc->children, heap_allocator());
|
array_init(&proc->children, heap_allocator());
|
||||||
array_init(&proc->branch_blocks, heap_allocator());
|
array_init(&proc->branch_blocks, heap_allocator());
|
||||||
|
|
||||||
DeclInfo **found = map_decl_info_get(&proc->module->info->entities, hash_pointer(proc->entity));
|
DeclInfo **found = map_decl_info_get(&proc->module->info->entities, hash_pointer(proc->entity));
|
||||||
if (found != NULL) {
|
if (found != NULL) {
|
||||||
@@ -6949,6 +6924,7 @@ void ir_gen_tree(irGen *s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// m->layout = str_lit("e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64");
|
// m->layout = str_lit("e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+13
-5
@@ -2162,7 +2162,7 @@ AstNode *parse_expr(AstFile *f, bool lhs) {
|
|||||||
|
|
||||||
AstNodeArray parse_expr_list(AstFile *f, bool lhs) {
|
AstNodeArray parse_expr_list(AstFile *f, bool lhs) {
|
||||||
AstNodeArray list = make_ast_node_array(f);
|
AstNodeArray list = make_ast_node_array(f);
|
||||||
do {
|
for (;;) {
|
||||||
AstNode *e = parse_expr(f, lhs);
|
AstNode *e = parse_expr(f, lhs);
|
||||||
array_add(&list, e);
|
array_add(&list, e);
|
||||||
if (f->curr_token.kind != Token_Comma ||
|
if (f->curr_token.kind != Token_Comma ||
|
||||||
@@ -2170,7 +2170,7 @@ AstNodeArray parse_expr_list(AstFile *f, bool lhs) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
next_token(f);
|
next_token(f);
|
||||||
} while (true);
|
}
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
@@ -3099,9 +3099,17 @@ AstNode *parse_case_clause(AstFile *f) {
|
|||||||
|
|
||||||
AstNode *parse_type_case_clause(AstFile *f) {
|
AstNode *parse_type_case_clause(AstFile *f) {
|
||||||
Token token = f->curr_token;
|
Token token = f->curr_token;
|
||||||
AstNodeArray clause = make_ast_node_array(f);
|
AstNodeArray list = make_ast_node_array(f);
|
||||||
if (allow_token(f, Token_case)) {
|
if (allow_token(f, Token_case)) {
|
||||||
array_add(&clause, parse_type(f));
|
for (;;) {
|
||||||
|
AstNode *t = parse_type(f);
|
||||||
|
array_add(&list, t);
|
||||||
|
if (f->curr_token.kind != Token_Comma ||
|
||||||
|
f->curr_token.kind == Token_EOF) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
next_token(f);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
expect_token(f, Token_default);
|
expect_token(f, Token_default);
|
||||||
}
|
}
|
||||||
@@ -3109,7 +3117,7 @@ AstNode *parse_type_case_clause(AstFile *f) {
|
|||||||
// expect_token(f, Token_ArrowRight); // TODO(bill): Is this the best syntax?
|
// expect_token(f, Token_ArrowRight); // TODO(bill): Is this the best syntax?
|
||||||
AstNodeArray stmts = parse_stmt_list(f);
|
AstNodeArray stmts = parse_stmt_list(f);
|
||||||
|
|
||||||
return ast_case_clause(f, token, clause, stmts);
|
return ast_case_clause(f, token, list, stmts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user