mirror of
https://github.com/odin-lang/Odin.git
synced 2026-01-02 11:12:31 +00:00
Correct union type checking for constants
This commit is contained in:
@@ -821,9 +821,11 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand
|
||||
}
|
||||
}
|
||||
|
||||
if (is_type_enum(dst) && are_types_identical(dst->Enum.base_type, operand->type)) {
|
||||
if (c->in_enum_type) {
|
||||
return 3;
|
||||
if (c != nullptr) {
|
||||
if (is_type_enum(dst) && are_types_identical(dst->Enum.base_type, operand->type)) {
|
||||
if (c->in_enum_type) {
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3590,11 +3592,7 @@ gb_internal void check_cast(CheckerContext *c, Operand *x, Type *type, bool forb
|
||||
Type *final_type = type;
|
||||
if (is_const_expr && !is_type_constant_type(type)) {
|
||||
if (is_type_union(type)) {
|
||||
if (is_type_union_constantable(type)) {
|
||||
|
||||
} else {
|
||||
convert_to_typed(c, x, type);
|
||||
}
|
||||
convert_to_typed(c, x, type);
|
||||
}
|
||||
final_type = default_type(x->type);
|
||||
}
|
||||
@@ -8033,6 +8031,106 @@ gb_internal bool check_call_parameter_mixture(Slice<Ast *> const &args, char con
|
||||
return Expr_Stmt; \
|
||||
}
|
||||
|
||||
gb_internal ExprKind check_call_expr_as_type_cast(CheckerContext *c, Operand *operand, Ast *call, Slice<Ast *> const &args, Type *type_hint) {
|
||||
GB_ASSERT(operand->mode == Addressing_Type);
|
||||
Type *t = operand->type;
|
||||
if (is_type_polymorphic_record(t)) {
|
||||
CHECK_CALL_PARAMETER_MIXTURE_OR_RETURN("polymorphic type construction");
|
||||
|
||||
if (!is_type_named(t)) {
|
||||
gbString s = expr_to_string(operand->expr);
|
||||
error(call, "Illegal use of an unnamed polymorphic record, %s", s);
|
||||
gb_string_free(s);
|
||||
operand->mode = Addressing_Invalid;
|
||||
operand->type = t_invalid;;
|
||||
return Expr_Expr;
|
||||
}
|
||||
auto err = check_polymorphic_record_type(c, operand, call);
|
||||
if (err == 0) {
|
||||
Ast *ident = operand->expr;
|
||||
while (ident->kind == Ast_SelectorExpr) {
|
||||
Ast *s = ident->SelectorExpr.selector;
|
||||
ident = s;
|
||||
}
|
||||
Type *ot = operand->type;
|
||||
GB_ASSERT(ot->kind == Type_Named);
|
||||
Entity *e = ot->Named.type_name;
|
||||
add_entity_use(c, ident, e);
|
||||
add_type_and_value(c, call, Addressing_Type, ot, empty_exact_value);
|
||||
} else {
|
||||
operand->mode = Addressing_Invalid;
|
||||
operand->type = t_invalid;
|
||||
}
|
||||
} else {
|
||||
CHECK_CALL_PARAMETER_MIXTURE_OR_RETURN("type conversion");
|
||||
|
||||
operand->mode = Addressing_Invalid;
|
||||
isize arg_count = args.count;
|
||||
switch (arg_count) {
|
||||
case 0:
|
||||
{
|
||||
gbString str = type_to_string(t);
|
||||
error(call, "Missing argument in conversion to '%s'", str);
|
||||
gb_string_free(str);
|
||||
} break;
|
||||
default:
|
||||
{
|
||||
gbString str = type_to_string(t);
|
||||
if (t->kind == Type_Basic) {
|
||||
ERROR_BLOCK();
|
||||
switch (t->Basic.kind) {
|
||||
case Basic_complex32:
|
||||
case Basic_complex64:
|
||||
case Basic_complex128:
|
||||
error(call, "Too many arguments in conversion to '%s'", str);
|
||||
error_line("\tSuggestion: %s(1+2i) or construct with 'complex'\n", str);
|
||||
break;
|
||||
case Basic_quaternion64:
|
||||
case Basic_quaternion128:
|
||||
case Basic_quaternion256:
|
||||
error(call, "Too many arguments in conversion to '%s'", str);
|
||||
error_line("\tSuggestion: %s(1+2i+3j+4k) or construct with 'quaternion'\n", str);
|
||||
break;
|
||||
default:
|
||||
error(call, "Too many arguments in conversion to '%s'", str);
|
||||
}
|
||||
} else {
|
||||
error(call, "Too many arguments in conversion to '%s'", str);
|
||||
}
|
||||
gb_string_free(str);
|
||||
} break;
|
||||
case 1: {
|
||||
Ast *arg = args[0];
|
||||
if (arg->kind == Ast_FieldValue) {
|
||||
error(call, "'field = value' cannot be used in a type conversion");
|
||||
arg = arg->FieldValue.value;
|
||||
// NOTE(bill): Carry on the cast regardless
|
||||
}
|
||||
check_expr_with_type_hint(c, operand, arg, t);
|
||||
if (operand->mode != Addressing_Invalid) {
|
||||
if (is_type_polymorphic(t)) {
|
||||
error(call, "A polymorphic type cannot be used in a type conversion");
|
||||
} else {
|
||||
// NOTE(bill): Otherwise the compiler can override the polymorphic type
|
||||
// as it assumes it is determining the type
|
||||
check_cast(c, operand, t);
|
||||
}
|
||||
}
|
||||
operand->type = t;
|
||||
operand->expr = call;
|
||||
|
||||
|
||||
if (operand->mode != Addressing_Invalid) {
|
||||
update_untyped_expr_type(c, arg, t, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Expr_Expr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call, Ast *proc, Slice<Ast *> const &args, ProcInlining inlining, Type *type_hint) {
|
||||
if (proc != nullptr &&
|
||||
@@ -8089,99 +8187,7 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c
|
||||
}
|
||||
|
||||
if (operand->mode == Addressing_Type) {
|
||||
Type *t = operand->type;
|
||||
if (is_type_polymorphic_record(t)) {
|
||||
CHECK_CALL_PARAMETER_MIXTURE_OR_RETURN("polymorphic type construction");
|
||||
|
||||
if (!is_type_named(t)) {
|
||||
gbString s = expr_to_string(operand->expr);
|
||||
error(call, "Illegal use of an unnamed polymorphic record, %s", s);
|
||||
gb_string_free(s);
|
||||
operand->mode = Addressing_Invalid;
|
||||
operand->type = t_invalid;;
|
||||
return Expr_Expr;
|
||||
}
|
||||
auto err = check_polymorphic_record_type(c, operand, call);
|
||||
if (err == 0) {
|
||||
Ast *ident = operand->expr;
|
||||
while (ident->kind == Ast_SelectorExpr) {
|
||||
Ast *s = ident->SelectorExpr.selector;
|
||||
ident = s;
|
||||
}
|
||||
Type *ot = operand->type;
|
||||
GB_ASSERT(ot->kind == Type_Named);
|
||||
Entity *e = ot->Named.type_name;
|
||||
add_entity_use(c, ident, e);
|
||||
add_type_and_value(c, call, Addressing_Type, ot, empty_exact_value);
|
||||
} else {
|
||||
operand->mode = Addressing_Invalid;
|
||||
operand->type = t_invalid;
|
||||
}
|
||||
} else {
|
||||
CHECK_CALL_PARAMETER_MIXTURE_OR_RETURN("type conversion");
|
||||
|
||||
operand->mode = Addressing_Invalid;
|
||||
isize arg_count = args.count;
|
||||
switch (arg_count) {
|
||||
case 0:
|
||||
{
|
||||
gbString str = type_to_string(t);
|
||||
error(call, "Missing argument in conversion to '%s'", str);
|
||||
gb_string_free(str);
|
||||
} break;
|
||||
default:
|
||||
{
|
||||
gbString str = type_to_string(t);
|
||||
if (t->kind == Type_Basic) {
|
||||
ERROR_BLOCK();
|
||||
switch (t->Basic.kind) {
|
||||
case Basic_complex32:
|
||||
case Basic_complex64:
|
||||
case Basic_complex128:
|
||||
error(call, "Too many arguments in conversion to '%s'", str);
|
||||
error_line("\tSuggestion: %s(1+2i) or construct with 'complex'\n", str);
|
||||
break;
|
||||
case Basic_quaternion64:
|
||||
case Basic_quaternion128:
|
||||
case Basic_quaternion256:
|
||||
error(call, "Too many arguments in conversion to '%s'", str);
|
||||
error_line("\tSuggestion: %s(1+2i+3j+4k) or construct with 'quaternion'\n", str);
|
||||
break;
|
||||
default:
|
||||
error(call, "Too many arguments in conversion to '%s'", str);
|
||||
}
|
||||
} else {
|
||||
error(call, "Too many arguments in conversion to '%s'", str);
|
||||
}
|
||||
gb_string_free(str);
|
||||
} break;
|
||||
case 1: {
|
||||
Ast *arg = args[0];
|
||||
if (arg->kind == Ast_FieldValue) {
|
||||
error(call, "'field = value' cannot be used in a type conversion");
|
||||
arg = arg->FieldValue.value;
|
||||
// NOTE(bill): Carry on the cast regardless
|
||||
}
|
||||
check_expr_with_type_hint(c, operand, arg, t);
|
||||
if (operand->mode != Addressing_Invalid) {
|
||||
if (is_type_polymorphic(t)) {
|
||||
error(call, "A polymorphic type cannot be used in a type conversion");
|
||||
} else {
|
||||
// NOTE(bill): Otherwise the compiler can override the polymorphic type
|
||||
// as it assumes it is determining the type
|
||||
check_cast(c, operand, t);
|
||||
}
|
||||
}
|
||||
operand->type = t;
|
||||
operand->expr = call;
|
||||
if (operand->mode != Addressing_Invalid) {
|
||||
update_untyped_expr_type(c, arg, t, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Expr_Expr;
|
||||
return check_call_expr_as_type_cast(c, operand, call, args, type_hint);
|
||||
}
|
||||
|
||||
if (operand->mode == Addressing_Builtin) {
|
||||
|
||||
Reference in New Issue
Block a user