Fix subtype polymorphism implicit conversion

This commit is contained in:
Ginger Bill
2017-04-30 16:22:24 +01:00
parent e63393e394
commit 1430ca30a3
4 changed files with 72 additions and 45 deletions
+29 -21
View File
@@ -79,32 +79,37 @@ void check_scope_decls(Checker *c, AstNodeArray nodes, isize reserve_size) {
} }
bool check_is_assignable_to_using_subtype(Type *dst, Type *src) { bool check_is_assignable_to_using_subtype(Type *src, Type *dst) {
bool src_is_ptr; bool src_is_ptr = false;
Type *prev_src = src; Type *prev_src = src;
src = type_deref(src); src = type_deref(src);
src_is_ptr = src != prev_src; src_is_ptr = src != prev_src;
src = base_type(src); src = base_type(src);
if (is_type_struct(src) || is_type_union(src)) { if (!is_type_struct(src) && !is_type_union(src)) {
for (isize i = 0; i < src->Record.field_count; i++) { return false;
Entity *f = src->Record.fields[i]; }
if (f->kind == Entity_Variable && (f->flags & EntityFlag_Using) != 0) {
if (are_types_identical(dst, f->type)) { for (isize i = 0; i < src->Record.field_count; i++) {
return true; Entity *f = src->Record.fields[i];
} if (f->kind != Entity_Variable || (f->flags&EntityFlag_Using) == 0) {
if (src_is_ptr && is_type_pointer(dst)) { continue;
if (are_types_identical(type_deref(dst), f->type)) { }
return true;
} if (are_types_identical(f->type, dst)) {
} return true;
bool ok = check_is_assignable_to_using_subtype(dst, f->type); }
if (ok) { if (src_is_ptr && is_type_pointer(dst)) {
return true; if (are_types_identical(f->type, type_deref(dst))) {
} return true;
} }
} }
bool ok = check_is_assignable_to_using_subtype(f->type, dst);
if (ok) {
return true;
}
} }
return false; return false;
} }
@@ -113,6 +118,7 @@ bool check_is_assignable_to_using_subtype(Type *dst, Type *src) {
// -1 is not convertable // -1 is not convertable
// 0 is exact // 0 is exact
// >0 is convertable // >0 is convertable
i64 check_distance_between_types(Checker *c, Operand *operand, Type *type) { i64 check_distance_between_types(Checker *c, Operand *operand, Type *type) {
if (operand->mode == Addressing_Invalid || if (operand->mode == Addressing_Invalid ||
type == t_invalid) { type == t_invalid) {
@@ -383,10 +389,12 @@ isize check_fields(Checker *c, AstNode *node, AstNodeArray decls,
ast_node(f, Field, decl); ast_node(f, Field, decl);
Type *type = check_type(c, f->type); Type *type = check_type(c, f->type);
bool is_using = (f->flags&FieldFlag_using) != 0;
if (f->flags&FieldFlag_using) { if (is_using) {
if (f->names.count > 1) { if (f->names.count > 1) {
error_node(f->names.e[0], "Cannot apply `using` to more than one of the same type"); error_node(f->names.e[0], "Cannot apply `using` to more than one of the same type");
is_using = false;
} }
} }
@@ -398,7 +406,7 @@ isize check_fields(Checker *c, AstNode *node, AstNodeArray decls,
Token name_token = name->Ident; Token name_token = name->Ident;
Entity *e = make_entity_field(c->allocator, c->context.scope, name_token, type, f->flags&FieldFlag_using, cast(i32)field_index); Entity *e = make_entity_field(c->allocator, c->context.scope, name_token, type, is_using, cast(i32)field_index);
e->identifier = name; e->identifier = name;
if (str_eq(name_token.string, str_lit("_"))) { if (str_eq(name_token.string, str_lit("_"))) {
fields[field_index++] = e; fields[field_index++] = e;
@@ -421,7 +429,7 @@ isize check_fields(Checker *c, AstNode *node, AstNodeArray decls,
} }
if (f->flags&FieldFlag_using) { if (is_using) {
Type *t = base_type(type_deref(type)); Type *t = base_type(type_deref(type));
if (!is_type_struct(t) && !is_type_raw_union(t) && if (!is_type_struct(t) && !is_type_raw_union(t) &&
f->names.count >= 1 && f->names.count >= 1 &&
+4 -4
View File
@@ -185,20 +185,20 @@ Entity *make_entity_type_name(gbAllocator a, Scope *scope, Token token, Type *ty
return entity; return entity;
} }
Entity *make_entity_param(gbAllocator a, Scope *scope, Token token, Type *type, bool anonymous, bool is_immutable) { Entity *make_entity_param(gbAllocator a, Scope *scope, Token token, Type *type, bool is_using, bool is_immutable) {
Entity *entity = make_entity_variable(a, scope, token, type, is_immutable); Entity *entity = make_entity_variable(a, scope, token, type, is_immutable);
entity->flags |= EntityFlag_Used; entity->flags |= EntityFlag_Used;
if (anonymous) entity->flags |= EntityFlag_Using; if (is_using) entity->flags |= EntityFlag_Using;
entity->flags |= EntityFlag_Param; entity->flags |= EntityFlag_Param;
return entity; return entity;
} }
Entity *make_entity_field(gbAllocator a, Scope *scope, Token token, Type *type, bool anonymous, i32 field_src_index) { Entity *make_entity_field(gbAllocator a, Scope *scope, Token token, Type *type, bool is_using, i32 field_src_index) {
Entity *entity = make_entity_variable(a, scope, token, type, false); Entity *entity = make_entity_variable(a, scope, token, type, false);
entity->Variable.field_src_index = field_src_index; entity->Variable.field_src_index = field_src_index;
entity->Variable.field_index = field_src_index; entity->Variable.field_index = field_src_index;
if (is_using) entity->flags |= EntityFlag_Using;
entity->flags |= EntityFlag_Field; entity->flags |= EntityFlag_Field;
entity->flags |= EntityFlag_Using*(anonymous != 0);
return entity; return entity;
} }
+39 -17
View File
@@ -2613,7 +2613,7 @@ irValue *ir_add_local_slice(irProcedure *proc, Type *slice_type, irValue *base,
String lookup_polymorphic_field(CheckerInfo *info, Type *dst, Type *src) { String ir_lookup_polymorphic_field(CheckerInfo *info, Type *dst, Type *src) {
Type *prev_src = src; Type *prev_src = src;
// Type *prev_dst = dst; // Type *prev_dst = dst;
src = base_type(type_deref(src)); src = base_type(type_deref(src));
@@ -2621,7 +2621,7 @@ String lookup_polymorphic_field(CheckerInfo *info, Type *dst, Type *src) {
bool src_is_ptr = src != prev_src; bool src_is_ptr = src != prev_src;
// bool dst_is_ptr = dst != prev_dst; // bool dst_is_ptr = dst != prev_dst;
GB_ASSERT(is_type_struct(src)); GB_ASSERT(is_type_struct(src) || is_type_union(src));
for (isize i = 0; i < src->Record.field_count; i++) { for (isize i = 0; i < src->Record.field_count; i++) {
Entity *f = src->Record.fields[i]; Entity *f = src->Record.fields[i];
if (f->kind == Entity_Variable && f->flags & EntityFlag_Using) { if (f->kind == Entity_Variable && f->flags & EntityFlag_Using) {
@@ -2634,7 +2634,7 @@ String lookup_polymorphic_field(CheckerInfo *info, Type *dst, Type *src) {
} }
} }
if (is_type_struct(f->type)) { if (is_type_struct(f->type)) {
String name = lookup_polymorphic_field(info, dst, f->type); String name = ir_lookup_polymorphic_field(info, dst, f->type);
if (name.len > 0) { if (name.len > 0) {
return name; return name;
} }
@@ -2805,23 +2805,45 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) {
} }
} }
// NOTE(bill): This has to be done beofre `Pointer <-> Pointer` as it's // NOTE(bill): This has to be done before `Pointer <-> Pointer` as it's
// subtype polymorphism casting // subtype polymorphism casting
{ if (check_is_assignable_to_using_subtype(src_type, t)) {
Type *sb = base_type(type_deref(src)); Type *st = type_deref(src_type);
bool src_is_ptr = src != sb; Type *pst = st;
if (is_type_struct(sb)) { st = type_deref(st);
String field_name = lookup_polymorphic_field(proc->module->info, t, src);
// gb_printf("field_name: %.*s\n", LIT(field_name)); bool st_is_ptr = st != pst;
if (field_name.len > 0) { st = base_type(st);
// NOTE(bill): It can be casted
Selection sel = lookup_field(proc->module->allocator, sb, field_name, false); Type *dt = t;
if (sel.entity != NULL) { bool dt_is_ptr = is_type_pointer(dt);
ir_emit_comment(proc, str_lit("cast - polymorphism"));
if (src_is_ptr) { GB_ASSERT(is_type_struct(st) || is_type_union(st));
value = ir_emit_load(proc, value); String field_name = ir_lookup_polymorphic_field(proc->module->info, t, st);
// gb_printf("field_name: %.*s\n", LIT(field_name));
if (field_name.len > 0) {
// NOTE(bill): It can be casted
Selection sel = lookup_field(proc->module->allocator, st, field_name, false);
if (sel.entity != NULL) {
ir_emit_comment(proc, str_lit("cast - polymorphism"));
if (st_is_ptr) {
irValue *res = ir_emit_deep_field_gep(proc, value, sel);
if (!dt_is_ptr) {
res = ir_emit_load(proc, res);
} }
return res;
} else {
if (is_type_pointer(ir_type(value))) {
if (!dt_is_ptr) {
value = ir_emit_load(proc, value);
} else {
value = ir_emit_deep_field_gep(proc, value, sel);
return ir_emit_load(proc, value);
}
}
return ir_emit_deep_field_ev(proc, value, sel); return ir_emit_deep_field_ev(proc, value, sel);
} }
} }
} }
-3
View File
@@ -107,9 +107,6 @@ TOKEN_KIND(Token__KeywordBegin, "_KeywordBegin"), \
TOKEN_KIND(Token_using, "using"), \ TOKEN_KIND(Token_using, "using"), \
TOKEN_KIND(Token_no_alias, "no_alias"), \ TOKEN_KIND(Token_no_alias, "no_alias"), \
TOKEN_KIND(Token_immutable, "immutable"), \ TOKEN_KIND(Token_immutable, "immutable"), \
/* TOKEN_KIND(Token_cast, "cast"), */ \
/* TOKEN_KIND(Token_transmute, "transmute"), */ \
/* TOKEN_KIND(Token_union_cast, "union_cast"), */ \
TOKEN_KIND(Token_context, "context"), \ TOKEN_KIND(Token_context, "context"), \
TOKEN_KIND(Token_push_context, "push_context"), \ TOKEN_KIND(Token_push_context, "push_context"), \
TOKEN_KIND(Token_push_allocator, "push_allocator"), \ TOKEN_KIND(Token_push_allocator, "push_allocator"), \