mirror of
https://github.com/odin-lang/Odin.git
synced 2025-12-29 09:24:33 +00:00
Refactor record polymorphic params code for unification
This commit is contained in:
@@ -5915,7 +5915,8 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
i32 i = id - cast(i32)BuiltinProc__type_simple_boolean_begin;
|
||||
auto procedure = builtin_type_is_procs[i];
|
||||
GB_ASSERT_MSG(procedure != nullptr, "%.*s", LIT(builtin_name));
|
||||
operand->value = exact_value_bool(procedure(operand->type));
|
||||
bool ok = procedure(operand->type);
|
||||
operand->value = exact_value_bool(ok);
|
||||
}
|
||||
operand->mode = Addressing_Constant;
|
||||
operand->type = t_untyped_bool;
|
||||
|
||||
@@ -338,12 +338,17 @@ void add_polymorphic_record_entity(CheckerContext *ctx, Ast *node, Type *named_t
|
||||
}
|
||||
|
||||
Type *check_record_polymorphic_params(CheckerContext *ctx, Ast *polymorphic_params,
|
||||
bool *is_polymorphic_, bool *can_check_fields_,
|
||||
bool *is_polymorphic_,
|
||||
Ast *node, Array<Operand> *poly_operands,
|
||||
Type *named_type, Type *original_type_for_poly) {
|
||||
Type *polymorphic_params_type = nullptr;
|
||||
bool can_check_fields = true;
|
||||
GB_ASSERT(is_polymorphic_ != nullptr);
|
||||
|
||||
if (polymorphic_params == nullptr) {
|
||||
if (!*is_polymorphic_) {
|
||||
*is_polymorphic_ = polymorphic_params != nullptr && poly_operands == nullptr;
|
||||
}
|
||||
return polymorphic_params_type;
|
||||
}
|
||||
|
||||
@@ -463,7 +468,7 @@ Type *check_record_polymorphic_params(CheckerContext *ctx, Ast *polymorphic_para
|
||||
if (is_type_param) {
|
||||
if (is_type_polymorphic(base_type(operand.type))) {
|
||||
*is_polymorphic_ = true;
|
||||
*can_check_fields_ = false;
|
||||
can_check_fields = false;
|
||||
}
|
||||
e = alloc_entity_type_name(scope, token, operand.type);
|
||||
e->TypeName.is_type_alias = true;
|
||||
@@ -471,7 +476,7 @@ Type *check_record_polymorphic_params(CheckerContext *ctx, Ast *polymorphic_para
|
||||
} else {
|
||||
if (is_type_polymorphic(base_type(operand.type))) {
|
||||
*is_polymorphic_ = true;
|
||||
*can_check_fields_ = false;
|
||||
can_check_fields = false;
|
||||
}
|
||||
if (e == nullptr) {
|
||||
e = alloc_entity_constant(scope, token, operand.type, operand.value);
|
||||
@@ -507,9 +512,42 @@ Type *check_record_polymorphic_params(CheckerContext *ctx, Ast *polymorphic_para
|
||||
add_polymorphic_record_entity(ctx, node, named_type, original_type_for_poly);
|
||||
}
|
||||
|
||||
if (!*is_polymorphic_) {
|
||||
*is_polymorphic_ = polymorphic_params != nullptr && poly_operands == nullptr;
|
||||
}
|
||||
|
||||
return polymorphic_params_type;
|
||||
}
|
||||
|
||||
bool check_record_poly_operand_specialization(CheckerContext *ctx, Type *record_type, Array<Operand> *poly_operands, bool *is_polymorphic_) {
|
||||
if (poly_operands == nullptr) {
|
||||
return false;
|
||||
}
|
||||
for (isize i = 0; i < poly_operands->count; i++) {
|
||||
Operand o = (*poly_operands)[i];
|
||||
if (is_type_polymorphic(o.type)) {
|
||||
return false;
|
||||
}
|
||||
if (record_type == o.type) {
|
||||
// NOTE(bill): Cycle
|
||||
return false;
|
||||
}
|
||||
if (o.mode == Addressing_Type) {
|
||||
// NOTE(bill): ANNOYING EDGE CASE FOR `where` clauses
|
||||
// TODO(bill, 2021-03-27): Is this even a valid HACK?!
|
||||
Entity *entity = entity_of_node(o.expr);
|
||||
if (entity != nullptr &&
|
||||
entity->kind == Entity_TypeName &&
|
||||
entity->type == t_typeid) {
|
||||
*is_polymorphic_ = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array<Operand> *poly_operands, Type *named_type, Type *original_type_for_poly) {
|
||||
GB_ASSERT(is_type_struct(struct_type));
|
||||
ast_node(st, StructType, node);
|
||||
@@ -541,39 +579,18 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array<
|
||||
bool &is_polymorphic = struct_type->Struct.is_polymorphic;
|
||||
|
||||
Type *polymorphic_params = nullptr;
|
||||
bool can_check_fields = true;
|
||||
bool is_poly_specialized = false;
|
||||
|
||||
polymorphic_params = check_record_polymorphic_params(
|
||||
ctx, st->polymorphic_params,
|
||||
&is_polymorphic, &can_check_fields,
|
||||
&is_polymorphic,
|
||||
node, poly_operands,
|
||||
named_type, original_type_for_poly
|
||||
);
|
||||
|
||||
if (!is_polymorphic) {
|
||||
is_polymorphic = polymorphic_params != nullptr && poly_operands == nullptr;
|
||||
}
|
||||
if (poly_operands != nullptr) {
|
||||
is_poly_specialized = true;
|
||||
for (isize i = 0; i < poly_operands->count; i++) {
|
||||
Operand o = (*poly_operands)[i];
|
||||
if (is_type_polymorphic(o.type)) {
|
||||
is_poly_specialized = false;
|
||||
break;
|
||||
}
|
||||
if (struct_type == o.type) {
|
||||
// NOTE(bill): Cycle
|
||||
is_poly_specialized = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct_type->Struct.scope = ctx->scope;
|
||||
struct_type->Struct.is_packed = st->is_packed;
|
||||
struct_type->Struct.polymorphic_params = polymorphic_params;
|
||||
struct_type->Struct.is_poly_specialized = is_poly_specialized;
|
||||
struct_type->Struct.scope = ctx->scope;
|
||||
struct_type->Struct.is_packed = st->is_packed;
|
||||
struct_type->Struct.polymorphic_params = polymorphic_params;
|
||||
struct_type->Struct.is_poly_specialized = check_record_poly_operand_specialization(ctx, struct_type, poly_operands, &is_polymorphic);
|
||||
|
||||
if (!is_polymorphic) {
|
||||
if (st->where_clauses.count > 0 && st->polymorphic_params == nullptr) {
|
||||
@@ -611,46 +628,26 @@ void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, Array<Op
|
||||
bool &is_polymorphic = union_type->Union.is_polymorphic;
|
||||
|
||||
Type *polymorphic_params = nullptr;
|
||||
bool can_check_fields = true;
|
||||
bool is_poly_specialized = false;
|
||||
|
||||
polymorphic_params = check_record_polymorphic_params(
|
||||
ctx, ut->polymorphic_params,
|
||||
&is_polymorphic, &can_check_fields,
|
||||
&is_polymorphic,
|
||||
node, poly_operands,
|
||||
named_type, original_type_for_poly
|
||||
);
|
||||
|
||||
union_type->Union.scope = ctx->scope;
|
||||
union_type->Union.polymorphic_params = polymorphic_params;
|
||||
union_type->Union.is_polymorphic = is_polymorphic;
|
||||
union_type->Union.is_poly_specialized = check_record_poly_operand_specialization(ctx, union_type, poly_operands, &is_polymorphic);
|
||||
|
||||
if (!is_polymorphic) {
|
||||
is_polymorphic = polymorphic_params != nullptr && poly_operands == nullptr;
|
||||
}
|
||||
if (poly_operands != nullptr) {
|
||||
is_poly_specialized = true;
|
||||
for (isize i = 0; i < poly_operands->count; i++) {
|
||||
Operand o = (*poly_operands)[i];
|
||||
if (is_type_polymorphic(o.type)) {
|
||||
is_poly_specialized = false;
|
||||
break;
|
||||
}
|
||||
if (union_type == o.type) {
|
||||
// NOTE(bill): Cycle
|
||||
is_poly_specialized = false;
|
||||
break;
|
||||
}
|
||||
if (ut->where_clauses.count > 0 && ut->polymorphic_params == nullptr) {
|
||||
error(ut->where_clauses[0], "'where' clauses can only be used on unions with polymorphic parameters");
|
||||
} else {
|
||||
bool where_clause_ok = evaluate_where_clauses(ctx, node, ctx->scope, &ut->where_clauses, true);
|
||||
}
|
||||
}
|
||||
|
||||
union_type->Union.scope = ctx->scope;
|
||||
union_type->Union.polymorphic_params = polymorphic_params;
|
||||
union_type->Union.is_polymorphic = is_polymorphic;
|
||||
union_type->Union.is_poly_specialized = is_poly_specialized;
|
||||
|
||||
if (ut->where_clauses.count > 0 && ut->polymorphic_params == nullptr) {
|
||||
error(ut->where_clauses[0], "'where' clauses can only be used on unions with polymorphic parameters");
|
||||
} else {
|
||||
bool where_clause_ok = evaluate_where_clauses(ctx, node, ctx->scope, &ut->where_clauses, true);
|
||||
}
|
||||
|
||||
|
||||
for_array(i, ut->variants) {
|
||||
Ast *node = ut->variants[i];
|
||||
|
||||
Reference in New Issue
Block a user