mirror of
https://github.com/odin-lang/Odin.git
synced 2026-01-04 12:07:45 +00:00
Fix polymorphic record types with constant value parameters
This commit is contained in:
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user