mirror of
https://github.com/odin-lang/Odin.git
synced 2026-01-08 14:03:14 +00:00
Change union layout to store type info rather than an integer; ternary expression for types with constant condition
This commit is contained in:
@@ -1326,10 +1326,6 @@ void check_union_type(Checker *c, Type *named_type, Type *union_type, AstNode *n
|
||||
array_add(&variants, t_invalid);
|
||||
|
||||
union_type->Union.scope = c->context.scope;
|
||||
{
|
||||
Entity *__tag = make_entity_field(c->allocator, nullptr, make_token_ident(str_lit("__tag")), t_int, false, -1);
|
||||
union_type->Union.union__tag = __tag;
|
||||
}
|
||||
|
||||
for_array(i, ut->variants) {
|
||||
AstNode *node = ut->variants[i];
|
||||
@@ -1353,7 +1349,10 @@ void check_union_type(Checker *c, Type *named_type, Type *union_type, AstNode *n
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ok) array_add(&variants, t);
|
||||
if (ok) {
|
||||
add_type_info_type(c, t);
|
||||
array_add(&variants, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2044,8 +2043,10 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
|
||||
success = false;
|
||||
type = t_invalid;
|
||||
}
|
||||
if (is_type_polymorphic_struct(type)) {
|
||||
error(o.expr, "Cannot pass polymorphic struct as a parameter");
|
||||
if (is_type_polymorphic(type)) {
|
||||
gbString str = type_to_string(type);
|
||||
error(o.expr, "Cannot pass polymorphic type as a parameter, got `%s`", str);
|
||||
gb_string_free(str);
|
||||
success = false;
|
||||
type = t_invalid;
|
||||
}
|
||||
@@ -3079,6 +3080,15 @@ bool check_type_internal(Checker *c, AstNode *e, Type **type, Type *named_type)
|
||||
return true;
|
||||
}
|
||||
case_end;
|
||||
|
||||
case_ast_node(te, TernaryExpr, e);
|
||||
Operand o = {};
|
||||
check_expr_or_type(c, &o, e);
|
||||
if (o.mode == Addressing_Type) {
|
||||
*type = o.type;
|
||||
return true;
|
||||
}
|
||||
case_end;
|
||||
}
|
||||
|
||||
*type = t_invalid;
|
||||
@@ -4290,6 +4300,90 @@ void convert_to_typed(Checker *c, Operand *operand, Type *target_type, i32 level
|
||||
}
|
||||
} break;
|
||||
|
||||
case Type_Union:
|
||||
{
|
||||
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
|
||||
defer (gb_temp_arena_memory_end(tmp));
|
||||
i32 count = t->Union.variant_count;
|
||||
i64 *scores = gb_alloc_array(c->tmp_allocator, i64, count);
|
||||
i32 success_count = 0;
|
||||
i32 first_success_index = -1;
|
||||
for (i32 i = 1; i < count; i++) {
|
||||
Type *vt = t->Union.variants[i];
|
||||
i64 score = 0;
|
||||
if (check_is_assignable_to_with_score(c, operand, vt, &score)) {
|
||||
scores[i] = score;
|
||||
success_count += 1;
|
||||
if (first_success_index < 0) {
|
||||
first_success_index = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gbString type_str = type_to_string(target_type);
|
||||
defer (gb_string_free(type_str));
|
||||
|
||||
if (success_count == 1) {
|
||||
operand->mode = Addressing_Value;
|
||||
operand->type = t->Union.variants[first_success_index];
|
||||
target_type = t->Union.variants[first_success_index];
|
||||
break;
|
||||
} else if (success_count > 1) {
|
||||
GB_ASSERT(first_success_index >= 0);
|
||||
operand->mode = Addressing_Invalid;
|
||||
convert_untyped_error(c, operand, target_type);
|
||||
|
||||
gb_printf_err("Ambiguous type conversion to `%s`, which variant did you mean:\n\t", type_str);
|
||||
i32 j = 0;
|
||||
for (i32 i = first_success_index; i < count; i++) {
|
||||
if (scores[i] == 0) continue;
|
||||
if (j > 0 && success_count > 2) gb_printf_err(", ");
|
||||
if (j == success_count-1) {
|
||||
if (success_count == 2) {
|
||||
gb_printf_err(" or ");
|
||||
} else {
|
||||
gb_printf_err(" or ");
|
||||
}
|
||||
}
|
||||
gbString str = type_to_string(t->Union.variants[i]);
|
||||
gb_printf_err("`%s`", str);
|
||||
gb_string_free(str);
|
||||
j++;
|
||||
}
|
||||
gb_printf_err("\n\n");
|
||||
|
||||
return;
|
||||
} else if (is_type_untyped_undef(operand->type) && type_has_undef(target_type)) {
|
||||
target_type = t_untyped_undef;
|
||||
} else if (!is_type_untyped_nil(operand->type) || !type_has_nil(target_type)) {
|
||||
operand->mode = Addressing_Invalid;
|
||||
convert_untyped_error(c, operand, target_type);
|
||||
if (count > 1) {
|
||||
gb_printf_err("`%s` is a union which only excepts the following types:\n", type_str);
|
||||
gb_printf_err("\t");
|
||||
for (i32 i = 1; i < count; i++) {
|
||||
Type *v = t->Union.variants[i];
|
||||
if (i > 1 && count > 3) gb_printf_err(", ");
|
||||
if (i == count-1) {
|
||||
if (count == 3) {
|
||||
gb_printf_err(" or ");
|
||||
} else {
|
||||
gb_printf_err("or ");
|
||||
}
|
||||
}
|
||||
gbString str = type_to_string(v);
|
||||
gb_printf_err("`%s`", str);
|
||||
gb_string_free(str);
|
||||
}
|
||||
gb_printf_err("\n\n");
|
||||
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
/* fallthrough */
|
||||
|
||||
|
||||
default:
|
||||
if (is_type_untyped_undef(operand->type) && type_has_undef(target_type)) {
|
||||
@@ -6894,16 +6988,6 @@ ExprKind check_call_expr(Checker *c, Operand *operand, AstNode *call) {
|
||||
}
|
||||
|
||||
|
||||
ExprKind Ov(Checker *c, Operand *operand, AstNode *call) {
|
||||
GB_ASSERT(call->kind == AstNode_MacroCallExpr);
|
||||
ast_node(mce, MacroCallExpr, call);
|
||||
|
||||
error(call, "Macro call expressions are not yet supported");
|
||||
operand->mode = Addressing_Invalid;
|
||||
operand->expr = call;
|
||||
return Expr_Stmt;
|
||||
}
|
||||
|
||||
void check_expr_with_type_hint(Checker *c, Operand *o, AstNode *e, Type *t) {
|
||||
check_expr_base(c, o, e, t);
|
||||
check_not_tuple(c, o);
|
||||
@@ -7139,10 +7223,10 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
|
||||
|
||||
Operand x = {Addressing_Invalid};
|
||||
Operand y = {Addressing_Invalid};
|
||||
check_expr_with_type_hint(c, &x, te->x, type_hint);
|
||||
check_expr_or_type(c, &x, te->x, type_hint);
|
||||
|
||||
if (te->y != nullptr) {
|
||||
check_expr_with_type_hint(c, &y, te->y, type_hint);
|
||||
check_expr_or_type(c, &y, te->y, type_hint);
|
||||
} else {
|
||||
error(node, "A ternary expression must have an else clause");
|
||||
return kind;
|
||||
@@ -7153,6 +7237,19 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
|
||||
return kind;
|
||||
}
|
||||
|
||||
if (x.mode == Addressing_Type && y.mode == Addressing_Type &&
|
||||
cond.mode == Addressing_Constant && is_type_boolean(cond.type)) {
|
||||
o->mode = Addressing_Type;
|
||||
if (cond.value.value_bool) {
|
||||
o->type = x.type;
|
||||
o->expr = x.expr;
|
||||
} else {
|
||||
o->type = y.type;
|
||||
o->expr = y.expr;
|
||||
}
|
||||
return Expr_Expr;
|
||||
}
|
||||
|
||||
convert_to_typed(c, &x, y.type, 0);
|
||||
if (x.mode == Addressing_Invalid) {
|
||||
return kind;
|
||||
@@ -7218,7 +7315,18 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
|
||||
return kind;
|
||||
}
|
||||
|
||||
|
||||
Type *t = base_type(type);
|
||||
if (is_type_polymorphic(t)) {
|
||||
gbString str = type_to_string(type);
|
||||
error(node, "Cannot use a polymorphic type for a compound literal, got `%s`", str);
|
||||
o->expr = node;
|
||||
o->type = type;
|
||||
gb_string_free(str);
|
||||
return kind;
|
||||
}
|
||||
|
||||
|
||||
switch (t->kind) {
|
||||
case Type_Record: {
|
||||
if (is_type_union(t)) {
|
||||
@@ -7909,7 +8017,8 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t
|
||||
case_end;
|
||||
|
||||
case_ast_node(ce, MacroCallExpr, node);
|
||||
return Ov(c, o, node);
|
||||
error(node, "Macro calls are not yet supported");
|
||||
return kind;
|
||||
case_end;
|
||||
|
||||
case_ast_node(de, DerefExpr, node);
|
||||
|
||||
Reference in New Issue
Block a user