Add hidden __tag for union variables.

This commit is contained in:
Ginger Bill
2017-05-04 20:34:50 +01:00
parent 3b25f924cb
commit 789b297f32
10 changed files with 205 additions and 134 deletions
+6
View File
@@ -422,6 +422,8 @@ isize check_fields(Checker *c, AstNode *node, AstNodeArray decls,
e->identifier = name;
if (str_eq(name_token.string, str_lit("_"))) {
fields[field_index++] = e;
} else if (str_eq(name_token.string, str_lit("__tag"))) {
error_node(name, "`__tag` is a reserved identifier for fields");
} else {
HashKey key = hash_string(name_token.string);
Entity **found = map_entity_get(&entity_map, key);
@@ -660,6 +662,10 @@ void check_union_type(Checker *c, Type *union_type, AstNode *node) {
union_type->Record.field_count = field_count;
union_type->Record.are_offsets_set = false;
union_type->Record.is_ordered = true;
{
Entity *__tag = make_entity_field(c->allocator, NULL, make_token_ident(str_lit("__tag")), t_int, false, -1);
union_type->Record.union__tag = __tag;
}
for_array(i, ut->variants) {
AstNode *variant = ut->variants.e[i];
+18 -5
View File
@@ -2244,8 +2244,13 @@ irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index) {
} else if (is_type_union(t)) {
type_set_offsets(a, t);
GB_ASSERT(t->Record.field_count > 0);
GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1));
result_type = make_type_pointer(a, t->Record.fields[index]->type);
if (index == -1) {
index = t->Record.field_count+1;
result_type = t_int_ptr;
} else {
GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1));
result_type = make_type_pointer(a, t->Record.fields[index]->type);
}
} else if (is_type_tuple(t)) {
GB_ASSERT(t->Tuple.variable_count > 0);
GB_ASSERT(gb_is_between(index, 0, t->Tuple.variable_count-1));
@@ -2316,8 +2321,12 @@ irValue *ir_emit_struct_ev(irProcedure *proc, irValue *s, i32 index) {
result_type = t->Record.fields[index]->type;
} else if (is_type_union(t)) {
type_set_offsets(a, t);
GB_ASSERT(t->Record.field_count > 0);
GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1));
if (index == -1) {
index = t->Record.field_count+1;
result_type = t_int_ptr;
} else {
GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1));
}
result_type = t->Record.fields[index]->type;
} else if (is_type_tuple(t)) {
GB_ASSERT(t->Tuple.variable_count > 0);
@@ -2394,7 +2403,11 @@ irValue *ir_emit_deep_field_gep(irProcedure *proc, irValue *e, Selection sel) {
type = type->Record.fields[index]->type;
e = ir_emit_conv(proc, e, make_type_pointer(proc->module->allocator, type));
} else if (type->kind == Type_Record) {
type = type->Record.fields[index]->type;
if (index == -1) {
type = t_int;
} else {
type = type->Record.fields[index]->type;
}
e = ir_emit_struct_ep(proc, e, index);
} else if (type->kind == Type_Tuple) {
type = type->Tuple.variables[index]->type;
+1 -1
View File
@@ -1844,7 +1844,7 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
return ast_proc_lit(f, type, NULL, tags, foreign_library, foreign_name, link_name);
}
if (tags != 0) {
syntax_error(token, "A procedure type cannot have tags");
// syntax_error(token, "A procedure type cannot have tags");
}
return type;
+11
View File
@@ -92,6 +92,8 @@ typedef struct TypeRecord {
// Entity_TypeName - union
Entity **variants;
i32 variant_count;
Entity * union__tag;
i64 * offsets;
bool are_offsets_set;
@@ -1415,6 +1417,15 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
sel.index.count = prev_count;
}
}
if (type->Record.kind == TypeRecord_Union) {
if (str_eq(field_name, str_lit("__tag"))) {
Entity *e = type->Record.union__tag;
GB_ASSERT(e != NULL);
selection_add_index(&sel, -1); // HACK(bill): Leaky memory
sel.entity = e;
return sel;
}
}
}
return sel;