Fix polymorphic record types with constant value parameters

This commit is contained in:
gingerBill
2018-12-14 18:36:06 +00:00
parent 57d4333ed3
commit b7eebe5d00
5 changed files with 82 additions and 26 deletions

View File

@@ -775,6 +775,7 @@ void check_assignment(CheckerContext *c, Operand *operand, Type *type, String co
}
}
bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, Type *source, bool compound, bool modify_type) {
Operand o = {Addressing_Value};
o.type = source;
@@ -985,6 +986,7 @@ Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *named_type, Typ
o->expr = n;
String name = n->Ident.token.string;
Entity *e = scope_lookup(c->scope, name);
if (e == nullptr) {
if (is_blank_ident(name)) {
@@ -5007,9 +5009,9 @@ CallArgumentError check_polymorphic_record_type(CheckerContext *c, Operand *oper
}
} else {
i64 s = 0;
if (is_type_generic(o->type)) {
if (o->type->kind == Type_Generic) {
// Polymorphic name!
score += assign_score_function(0);
score += assign_score_function(1);
continue;
} else if (!check_is_assignable_to_with_score(c, o, e->type, &s)) {
if (show_error) {
@@ -5028,18 +5030,6 @@ CallArgumentError check_polymorphic_record_type(CheckerContext *c, Operand *oper
}
}
if (param_count < ordered_operands.count) {
error(call, "Too many polymorphic type arguments, expected %td, got %td", param_count, ordered_operands.count);
err = CallArgumentError_TooManyArguments;
} else if (param_count > ordered_operands.count) {
error(call, "Too few polymorphic type arguments, expected %td, got %td", param_count, ordered_operands.count);
err = CallArgumentError_TooFewArguments;
}
if (err != 0) {
return err;
}
{
gbAllocator a = c->allocator;

View File

@@ -627,7 +627,7 @@ void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, Array<Op
e = alloc_entity_type_name(scope, token, operand.type);
e->TypeName.is_type_alias = true;
} else {
GB_ASSERT(operand.mode == Addressing_Constant);
// GB_ASSERT(operand.mode == Addressing_Constant);
e = alloc_entity_constant(scope, token, operand.type, operand.value);
}
} else {
@@ -1117,9 +1117,8 @@ bool check_type_specialization_to(CheckerContext *ctx, Type *specialization, Typ
if (t->kind != s->kind) {
return false;
}
// gb_printf_err("#1 %s %s\n", type_to_string(type), type_to_string(specialization));
if (t->kind == Type_Struct) {
if (t->kind == Type_Struct) {
if (t->Struct.polymorphic_parent == specialization) {
return true;
}
@@ -1136,7 +1135,58 @@ bool check_type_specialization_to(CheckerContext *ctx, Type *specialization, Typ
Entity *t_e = t_tuple->variables[i];
Type *st = s_e->type;
Type *tt = t_e->type;
bool ok = is_polymorphic_type_assignable(ctx, st, tt, true, modify_type);
// NOTE(bill, 2018-12-14): This is needed to override polymorphic named constants in types
if (st->kind == Type_Generic && t_e->kind == Entity_Constant) {
Entity *e = scope_lookup(st->Generic.scope, st->Generic.name);
GB_ASSERT(e != nullptr);
if (modify_type) {
e->kind = Entity_Constant;
e->Constant.value = t_e->Constant.value;
e->type = t_e->type;
}
} else {
bool ok = is_polymorphic_type_assignable(ctx, st, tt, true, modify_type);
}
}
if (modify_type) {
// NOTE(bill): This is needed in order to change the actual type but still have the types defined within it
gb_memmove(specialization, type, gb_size_of(Type));
}
return true;
}
} else if (t->kind == Type_Union) {
if (t->Union.polymorphic_parent == specialization) {
return true;
}
if (t->Union.polymorphic_parent == s->Union.polymorphic_parent &&
s->Union.polymorphic_params != nullptr &&
t->Union.polymorphic_params != nullptr) {
TypeTuple *s_tuple = &s->Union.polymorphic_params->Tuple;
TypeTuple *t_tuple = &t->Union.polymorphic_params->Tuple;
GB_ASSERT(t_tuple->variables.count == s_tuple->variables.count);
for_array(i, s_tuple->variables) {
Entity *s_e = s_tuple->variables[i];
Entity *t_e = t_tuple->variables[i];
Type *st = s_e->type;
Type *tt = t_e->type;
// NOTE(bill, 2018-12-14): This is needed to override polymorphic named constants in types
if (st->kind == Type_Generic && t_e->kind == Entity_Constant) {
Entity *e = scope_lookup(st->Generic.scope, st->Generic.name);
GB_ASSERT(e != nullptr);
if (modify_type) {
e->kind = Entity_Constant;
e->Constant.value = t_e->Constant.value;
e->type = t_e->type;
}
} else {
bool ok = is_polymorphic_type_assignable(ctx, st, tt, true, modify_type);
}
}
if (modify_type) {
@@ -1168,6 +1218,7 @@ Type *determine_type_from_polymorphic(CheckerContext *ctx, Type *poly_type, Oper
}
return t_invalid;
}
if (is_polymorphic_type_assignable(ctx, poly_type, operand.type, false, modify_type)) {
return poly_type;
}
@@ -2290,6 +2341,7 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t
entity_scope = ps;
}
Entity *e = alloc_entity_type_name(entity_scope, token, t);
t->Generic.entity = e;
e->TypeName.is_type_alias = true;
e->state = EntityState_Resolved;
add_entity(ctx->checker, ps, ident, e);

View File

@@ -606,12 +606,14 @@ struct irDebugInfo {
} LexicalBlock;
struct {
Type * type;
String name;
i32 size;
i32 align;
irDebugEncoding encoding;
} BasicType;
struct {
Type * type;
irDebugEncoding tag;
irDebugInfo * base_type;
String name;
@@ -1766,6 +1768,7 @@ irDebugInfo *ir_add_debug_info_field_internal(irModule *module, String name, Typ
// "scope", if set, should be inserted into map prior to calling to ensure no cyclical dependency issues.
irDebugInfo *di = ir_alloc_debug_info(irDebugInfo_DerivedType);
// GB_ASSERT_MSG(name.len > 0, "%s", type_to_string(type));
di->DerivedType.name = name;
di->DerivedType.tag = irDebugBasicEncoding_member;
di->DerivedType.size = ir_debug_size_bits(type);
@@ -2350,9 +2353,9 @@ irDebugInfo *ir_add_debug_info_type(irModule *module, Type *type, Entity *e, irD
di->CompositeType.file = file;
di->CompositeType.pos = base->Union.node->UnionType.token.pos;
for_array(field_index, base->Union.variants) {
array_add(&di->CompositeType.elements->DebugInfoArray.elements,
ir_add_debug_info_field(module, di, nullptr, type, cast(i32)field_index,
base->Union.variants[field_index], file));
// TODO(bill): Union pseudo-"fields"
// irDebugInfo *di = ir_add_debug_info_field(module, di, nullptr, type, cast(i32)field_index, base->Union.variants[field_index], file);
// array_add(&di->CompositeType.elements->DebugInfoArray.elements, di);
}
} else if (is_type_enum(type)) {
GB_ASSERT(base->kind == Type_Enum);

View File

@@ -2437,7 +2437,8 @@ void print_llvm_ir(irGen *ir) {
case irDebugInfo_DerivedType: {
if (di->DerivedType.tag == irDebugBasicEncoding_member) {
// NOTE(lachsinc): We crash llvm super hard if we don't specify a name :)
GB_ASSERT(di->DerivedType.name.len > 0);
Type *t = di->DerivedType.type;
GB_ASSERT_MSG(di->DerivedType.name.len > 0, "%s", type_to_string(di->DerivedType.type));
}
ir_write_str_lit(f, "!DIDerivedType(tag: ");
ir_print_debug_encoding(f, irDebugInfo_DerivedType, di->DerivedType.tag);

View File

@@ -140,10 +140,11 @@ struct TypeUnion {
Entity *type_name; /* Entity_TypeName */ \
}) \
TYPE_KIND(Generic, struct { \
i64 id; \
String name; \
Type * specialized; \
Scope *scope; \
i64 id; \
String name; \
Type * specialized; \
Scope * scope; \
Entity *entity; \
}) \
TYPE_KIND(Pointer, struct { Type *elem; }) \
TYPE_KIND(Opaque, struct { Type *elem; }) \
@@ -1988,6 +1989,15 @@ Selection lookup_field_with_selection(Type *type_, String field_name, bool is_ty
return sel;
}
}
} else if (type->kind == Type_Union) {
Scope *s = type->Union.scope;
if (s != nullptr) {
Entity *found = scope_lookup_current(s, field_name);
if (found != nullptr && found->kind != Entity_Variable) {
sel.entity = found;
return sel;
}
}
} else if (type->kind == Type_BitSet) {
return lookup_field_with_selection(type->BitSet.elem, field_name, true, sel, allow_blank_ident);
}