From b7eebe5d004380dec34a185bca6e5e343589de69 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 14 Dec 2018 18:36:06 +0000 Subject: [PATCH] Fix polymorphic record types with constant value parameters --- src/check_expr.cpp | 18 ++++---------- src/check_type.cpp | 60 ++++++++++++++++++++++++++++++++++++++++++---- src/ir.cpp | 9 ++++--- src/ir_print.cpp | 3 ++- src/types.cpp | 18 ++++++++++---- 5 files changed, 82 insertions(+), 26 deletions(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 6e4bf05e6..37a54854c 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -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; diff --git a/src/check_type.cpp b/src/check_type.cpp index 33797ba27..63835dd76 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -627,7 +627,7 @@ void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, ArrayTypeName.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); diff --git a/src/ir.cpp b/src/ir.cpp index e11d1a054..c2739b387 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -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); diff --git a/src/ir_print.cpp b/src/ir_print.cpp index eadd091bd..457fc57a7 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -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); diff --git a/src/types.cpp b/src/types.cpp index 262e4c228..512505007 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -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); }