aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGinger Bill <bill@gingerbill.org>2017-07-19 12:15:21 +0100
committerGinger Bill <bill@gingerbill.org>2017-07-19 12:15:21 +0100
commit6113164211d5bd010ea324594d69668e5732817d (patch)
treee31315edbdaefdc698dae9d5f78b1555207d97f4 /src
parent4db462a703d506f2ef23a16921a23a10115feacb (diff)
Change union layout to store type info rather than an integer; ternary expression for types with constant condition
Diffstat (limited to 'src')
-rw-r--r--src/check_expr.cpp149
-rw-r--r--src/ir.cpp82
-rw-r--r--src/ir_print.cpp3
-rw-r--r--src/parser.cpp2
-rw-r--r--src/types.cpp15
5 files changed, 169 insertions, 82 deletions
diff --git a/src/check_expr.cpp b/src/check_expr.cpp
index 7a730629a..2a4d60872 100644
--- a/src/check_expr.cpp
+++ b/src/check_expr.cpp
@@ -1326,10 +1326,6 @@ void check_union_type(Checker *c, Type *named_type, Type *union_type, AstNode *n
array_add(&variants, t_invalid);
union_type->Union.scope = c->context.scope;
- {
- Entity *__tag = make_entity_field(c->allocator, nullptr, make_token_ident(str_lit("__tag")), t_int, false, -1);
- union_type->Union.union__tag = __tag;
- }
for_array(i, ut->variants) {
AstNode *node = ut->variants[i];
@@ -1353,7 +1349,10 @@ void check_union_type(Checker *c, Type *named_type, Type *union_type, AstNode *n
}
}
}
- if (ok) array_add(&variants, t);
+ if (ok) {
+ add_type_info_type(c, t);
+ array_add(&variants, t);
+ }
}
}
@@ -2044,8 +2043,10 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
success = false;
type = t_invalid;
}
- if (is_type_polymorphic_struct(type)) {
- error(o.expr, "Cannot pass polymorphic struct as a parameter");
+ if (is_type_polymorphic(type)) {
+ gbString str = type_to_string(type);
+ error(o.expr, "Cannot pass polymorphic type as a parameter, got `%s`", str);
+ gb_string_free(str);
success = false;
type = t_invalid;
}
@@ -3079,6 +3080,15 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
return true;
}
case_end;
+
+ case_ast_node(te, TernaryExpr, e);
+ Operand o = {};
+ check_expr_or_type(c, &o, e);
+ if (o.mode == Addressing_Type) {
+ *type = o.type;
+ return true;
+ }
+ case_end;
}
*type = t_invalid;
@@ -4290,6 +4300,90 @@ void convert_to_typed(Checker *c, Operand *operand, Type *target_type, i32 level
}
} break;
+ case Type_Union:
+ {
+ gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
+ defer (gb_temp_arena_memory_end(tmp));
+ i32 count = t->Union.variant_count;
+ i64 *scores = gb_alloc_array(c->tmp_allocator, i64, count);
+ i32 success_count = 0;
+ i32 first_success_index = -1;
+ for (i32 i = 1; i < count; i++) {
+ Type *vt = t->Union.variants[i];
+ i64 score = 0;
+ if (check_is_assignable_to_with_score(c, operand, vt, &score)) {
+ scores[i] = score;
+ success_count += 1;
+ if (first_success_index < 0) {
+ first_success_index = i;
+ }
+ }
+ }
+
+ gbString type_str = type_to_string(target_type);
+ defer (gb_string_free(type_str));
+
+ if (success_count == 1) {
+ operand->mode = Addressing_Value;
+ operand->type = t->Union.variants[first_success_index];
+ target_type = t->Union.variants[first_success_index];
+ break;
+ } else if (success_count > 1) {
+ GB_ASSERT(first_success_index >= 0);
+ operand->mode = Addressing_Invalid;
+ convert_untyped_error(c, operand, target_type);
+
+ gb_printf_err("Ambiguous type conversion to `%s`, which variant did you mean:\n\t", type_str);
+ i32 j = 0;
+ for (i32 i = first_success_index; i < count; i++) {
+ if (scores[i] == 0) continue;
+ if (j > 0 && success_count > 2) gb_printf_err(", ");
+ if (j == success_count-1) {
+ if (success_count == 2) {
+ gb_printf_err(" or ");
+ } else {
+ gb_printf_err(" or ");
+ }
+ }
+ gbString str = type_to_string(t->Union.variants[i]);
+ gb_printf_err("`%s`", str);
+ gb_string_free(str);
+ j++;
+ }
+ gb_printf_err("\n\n");
+
+ return;
+ } else if (is_type_untyped_undef(operand->type) && type_has_undef(target_type)) {
+ target_type = t_untyped_undef;
+ } else if (!is_type_untyped_nil(operand->type) || !type_has_nil(target_type)) {
+ operand->mode = Addressing_Invalid;
+ convert_untyped_error(c, operand, target_type);
+ if (count > 1) {
+ gb_printf_err("`%s` is a union which only excepts the following types:\n", type_str);
+ gb_printf_err("\t");
+ for (i32 i = 1; i < count; i++) {
+ Type *v = t->Union.variants[i];
+ if (i > 1 && count > 3) gb_printf_err(", ");
+ if (i == count-1) {
+ if (count == 3) {
+ gb_printf_err(" or ");
+ } else {
+ gb_printf_err("or ");
+ }
+ }
+ gbString str = type_to_string(v);
+ gb_printf_err("`%s`", str);
+ gb_string_free(str);
+ }
+ gb_printf_err("\n\n");
+
+ }
+ return;
+ }
+
+ }
+ /* fallthrough */
+
default:
if (is_type_untyped_undef(operand->type) && type_has_undef(target_type)) {
@@ -6894,16 +6988,6 @@ ExprKind check_call_expr(Checker *c, Operand *operand, AstNode *call) {
}
-ExprKind Ov(Checker *c, Operand *operand, AstNode *call) {
- GB_ASSERT(call->kind == AstNode_MacroCallExpr);
- ast_node(mce, MacroCallExpr, call);
-
- error(call, "Macro call expressions are not yet supported");
- operand->mode = Addressing_Invalid;
- operand->expr = call;
- return Expr_Stmt;
-}
-
void check_expr_with_type_hint(Checker *c, Operand *o, AstNode *e, Type *t) {
check_expr_base(c, o, e, t);
check_not_tuple(c, o);
@@ -7139,10 +7223,10 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
Operand x = {Addressing_Invalid};
Operand y = {Addressing_Invalid};
- check_expr_with_type_hint(c, &x, te->x, type_hint);
+ check_expr_or_type(c, &x, te->x, type_hint);
if (te->y != nullptr) {
- check_expr_with_type_hint(c, &y, te->y, type_hint);
+ check_expr_or_type(c, &y, te->y, type_hint);
} else {
error(node, "A ternary expression must have an else clause");
return kind;
@@ -7153,6 +7237,19 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
return kind;
}
+ if (x.mode == Addressing_Type && y.mode == Addressing_Type &&
+ cond.mode == Addressing_Constant && is_type_boolean(cond.type)) {
+ o->mode = Addressing_Type;
+ if (cond.value.value_bool) {
+ o->type = x.type;
+ o->expr = x.expr;
+ } else {
+ o->type = y.type;
+ o->expr = y.expr;
+ }
+ return Expr_Expr;
+ }
+
convert_to_typed(c, &x, y.type, 0);
if (x.mode == Addressing_Invalid) {
return kind;
@@ -7218,7 +7315,18 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
return kind;
}
+
Type *t = base_type(type);
+ if (is_type_polymorphic(t)) {
+ gbString str = type_to_string(type);
+ error(node, "Cannot use a polymorphic type for a compound literal, got `%s`", str);
+ o->expr = node;
+ o->type = type;
+ gb_string_free(str);
+ return kind;
+ }
+
+
switch (t->kind) {
case Type_Record: {
if (is_type_union(t)) {
@@ -7909,7 +8017,8 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
case_end;
case_ast_node(ce, MacroCallExpr, node);
- return Ov(c, o, node);
+ error(node, "Macro calls are not yet supported");
+ return kind;
case_end;
case_ast_node(de, DerefExpr, node);
diff --git a/src/ir.cpp b/src/ir.cpp
index 85eef66c4..833edb0e2 100644
--- a/src/ir.cpp
+++ b/src/ir.cpp
@@ -954,7 +954,7 @@ irValue *ir_instr_union_tag_ptr(irProcedure *p, irValue *address) {
irValue *v = ir_alloc_instr(p, irInstr_UnionTagPtr);
irInstr *i = &v->Instr;
i->UnionTagPtr.address = address;
- i->UnionTagPtr.type = t_int_ptr;
+ i->UnionTagPtr.type = make_type_pointer(p->module->allocator, t_type_info_ptr);
return v;
}
@@ -962,7 +962,7 @@ irValue *ir_instr_union_tag_value(irProcedure *p, irValue *address) {
irValue *v = ir_alloc_instr(p, irInstr_UnionTagValue);
irInstr *i = &v->Instr;
i->UnionTagValue.address = address;
- i->UnionTagValue.type = t_int;
+ i->UnionTagValue.type = t_type_info_ptr;
return v;
}
@@ -2218,7 +2218,7 @@ irValue *ir_emit_union_tag_ptr(irProcedure *proc, irValue *u) {
Type *tpt = ir_type(tag_ptr);
GB_ASSERT(is_type_pointer(tpt));
tpt = base_type(type_deref(tpt));
- GB_ASSERT(tpt == t_int);
+ GB_ASSERT(tpt == t_type_info_ptr);
return tag_ptr;
}
@@ -2379,15 +2379,8 @@ irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index) {
GB_ASSERT_MSG(gb_is_between(index, 0, t->Record.field_count-1), "0..%d..%d", index, t->Record.field_count);
result_type = make_type_pointer(a, t->Record.fields[index]->type);
} else if (is_type_union(t)) {
- type_set_offsets(a, t);
- GB_ASSERT(t->Record.field_count > 0);
- 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);
- }
+ GB_ASSERT(index == -1);
+ return ir_emit_union_tag_ptr(proc, s);
} 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));
@@ -2449,14 +2442,8 @@ irValue *ir_emit_struct_ev(irProcedure *proc, irValue *s, i32 index) {
GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1));
result_type = t->Record.fields[index]->type;
} else if (is_type_union(t)) {
- type_set_offsets(a, t);
- 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;
+ GB_ASSERT(index == -1);
+ return ir_emit_union_tag_value(proc, s);
} 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));
@@ -2523,12 +2510,12 @@ irValue *ir_emit_deep_field_gep(irProcedure *proc, irValue *e, Selection sel) {
if (is_type_raw_union(type)) {
type = type->Record.fields[index]->type;
e = ir_emit_conv(proc, e, make_type_pointer(proc->module->allocator, type));
+ } else if (type->kind == Type_Union) {
+ GB_ASSERT(index == -1);
+ type = t_type_info_ptr;
+ e = ir_emit_struct_ep(proc, e, index);
} else if (type->kind == Type_Record) {
- if (index == -1) {
- type = t_int;
- } else {
- type = type->Record.fields[index]->type;
- }
+ 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;
@@ -2983,7 +2970,7 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) {
ir_emit_store(proc, underlying, value);
irValue *tag_ptr = ir_emit_union_tag_ptr(proc, parent);
- ir_emit_store(proc, tag_ptr, ir_const_int(a, i));
+ ir_emit_store(proc, tag_ptr, ir_type_info(proc, vt));
return ir_emit_load(proc, parent);
}
@@ -3308,20 +3295,11 @@ irValue *ir_emit_union_cast(irProcedure *proc, irValue *value, Type *type, Token
Type *src = base_type(type_deref(src_type));
GB_ASSERT(is_type_union(src));
Type *dst = tuple->Tuple.variables[0]->type;
- Type *dst_ptr = make_type_pointer(a, dst);
irValue *value_ = ir_address_from_load_or_generate_local(proc, value);
irValue *tag = ir_emit_load(proc, ir_emit_union_tag_ptr(proc, value_));
- irValue *dst_tag = nullptr;
- for (isize i = 1; i < src->Union.variant_count; i++) {
- Type *vt = src->Union.variants[i];
- if (are_types_identical(vt, dst)) {
- dst_tag = ir_const_int(a, i);
- break;
- }
- }
- GB_ASSERT(dst_tag != nullptr);
+ irValue *dst_tag = ir_type_info(proc, dst);
irBlock *ok_block = ir_new_block(proc, nullptr, "union_cast.ok");
irBlock *end_block = ir_new_block(proc, nullptr, "union_cast.end");
@@ -6943,18 +6921,18 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
irValue *cond = nullptr;
if (match_type_kind == MatchType_Union) {
Type *bt = type_deref(case_type);
- irValue *index = nullptr;
+ irValue *variant_tag = nullptr;
Type *ut = base_type(type_deref(parent_type));
GB_ASSERT(ut->kind == Type_Union);
for (isize variant_index = 1; variant_index < ut->Union.variant_count; variant_index++) {
Type *vt = ut->Union.variants[variant_index];
if (are_types_identical(vt, bt)) {
- index = ir_const_int(allocator, variant_index);
+ variant_tag = ir_type_info(proc, vt);
break;
}
}
- GB_ASSERT(index != nullptr);
- cond = ir_emit_comp(proc, Token_CmpEq, tag_index, index);
+ GB_ASSERT(variant_tag != nullptr);
+ cond = ir_emit_comp(proc, Token_CmpEq, tag_index, variant_tag);
} else if (match_type_kind == MatchType_Any) {
irValue *any_ti = ir_emit_load(proc, ir_emit_struct_ep(proc, parent_ptr, 1));
irValue *case_ti = ir_type_info(proc, case_type);
@@ -8166,7 +8144,8 @@ void ir_gen_tree(irGen *s) {
tag = ir_emit_conv(proc, variant_ptr, t_type_info_union_ptr);
{
- irValue *variant_types = ir_emit_struct_ep(proc, tag, 0);
+ irValue *variant_types = ir_emit_struct_ep(proc, tag, 0);
+ irValue *tag_offset_ptr = ir_emit_struct_ep(proc, tag, 1);
isize variant_count = gb_max(0, t->Union.variant_count-1);
irValue *memory_types = ir_type_info_member_types_offset(proc, variant_count);
@@ -8183,6 +8162,9 @@ void ir_gen_tree(irGen *s) {
irValue *count = ir_const_int(a, variant_count);
ir_fill_slice(proc, variant_types, memory_types, count, count);
+
+ i64 tag_offset = align_formula(t->Union.variant_block_size, build_context.word_size);
+ ir_emit_store(proc, tag_offset_ptr, ir_const_int(a, tag_offset));
}
} break;
@@ -8323,21 +8305,9 @@ void ir_gen_tree(irGen *s) {
if (tag != nullptr) {
Type *tag_type = type_deref(ir_type(tag));
GB_ASSERT(is_type_named(tag_type));
- Type *ti = base_type(t_type_info);
- Type *tiv = base_type(ti->Record.fields_in_src_order[2]->type);
- GB_ASSERT(is_type_union(tiv));
- bool found = false;
- for (isize i = 1; i < tiv->Union.variant_count; i++) {
- Type *vt = tiv->Union.variants[i];
- if (are_types_identical(vt, tag_type)) {
- found = true;
- irValue *tag_val = ir_const_int(a, i);
- irValue *ptr = ir_emit_union_tag_ptr(proc, variant_ptr);
- ir_emit_store(proc, ptr, tag_val);
- break;
- }
- }
- GB_ASSERT_MSG(found, "Tag type not found: %s", type_to_string(tag_type));
+ irValue *ti = ir_type_info(proc, tag_type);
+ irValue *ptr = ir_emit_union_tag_ptr(proc, variant_ptr);
+ ir_emit_store(proc, ptr, ti);
} else {
GB_PANIC("Unhandled TypeInfo type: %s", type_to_string(t));
}
diff --git a/src/ir_print.cpp b/src/ir_print.cpp
index e2d33054b..deb5b9e34 100644
--- a/src/ir_print.cpp
+++ b/src/ir_print.cpp
@@ -292,7 +292,8 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
ir_fprintf(f, "{[0 x <%lld x i8>], ", align);
ir_fprintf(f, "[%lld x i8], ", block_size);
- ir_fprintf(f, "i%lld}", word_bits);
+ ir_print_type(f, m, t_type_info_ptr);
+ ir_fprintf(f, "}");
#else
i64 block_size = total_size - build_context.word_size;
ir_fprintf(f, "{[0 x <%lld x i8>], [%lld x i8], i%lld}", align, block_size, word_bits);
diff --git a/src/parser.cpp b/src/parser.cpp
index 651bed859..a7da2ee9e 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -4942,7 +4942,7 @@ ParseFileError parse_files(Parser *p, String init_filename) {
GB_ASSERT(init_filename.text[init_filename.len] == 0);
char *fullpath_str = gb_path_get_full_name(heap_allocator(), cast(char *)&init_filename[0]);
- String init_fullpath = make_string_c(fullpath_str);
+ String init_fullpath = string_trim_whitespace(make_string_c(fullpath_str));
TokenPos init_pos = {};
ImportedFile init_imported_file = {init_fullpath, init_fullpath, init_pos};
diff --git a/src/types.cpp b/src/types.cpp
index 3fe9029d8..29a06528d 100644
--- a/src/types.cpp
+++ b/src/types.cpp
@@ -123,7 +123,7 @@ struct TypeRecord {
i32 variant_count; \
AstNode *node; \
Scope * scope; \
- Entity * union__tag; \
+ Entity * union__type_info; \
i64 variant_block_size; \
i64 custom_align; \
}) \
@@ -1596,11 +1596,18 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
}
} else if (type->kind == Type_Union) {
- if (field_name == "__tag") {
- Entity *e = type->Union.union__tag;
+ if (field_name == "__type_info") {
+ Entity *e = type->Union.union__type_info;
+ if (e == nullptr) {
+ Entity *__type_info = make_entity_field(a, nullptr, make_token_ident(str_lit("__type_info")), t_type_info_ptr, false, -1);
+ type->Union.union__type_info = __type_info;
+ e = __type_info;
+ }
+
GB_ASSERT(e != nullptr);
selection_add_index(&sel, -1); // HACK(bill): Leaky memory
sel.entity = e;
+
return sel;
}
} else if (type->kind == Type_Record) {
@@ -2067,9 +2074,9 @@ i64 type_size_of_internal(gbAllocator allocator, Type *t, TypePath *path) {
}
i64 max = 0;
+ i64 field_size = 0;
isize variant_count = t->Union.variant_count;
- i64 field_size = max;
for (isize i = 1; i < variant_count; i++) {
Type *variant_type = t->Union.variants[i];