mirror of
https://github.com/odin-lang/Odin.git
synced 2026-04-19 13:00:28 +00:00
Correct implicit union cast
This commit is contained in:
@@ -508,6 +508,10 @@ bool check_cast_internal(CheckerContext *c, Operand *x, Type *type);
|
||||
#define MAXIMUM_TYPE_DISTANCE 10
|
||||
|
||||
i64 check_distance_between_types(CheckerContext *c, Operand *operand, Type *type) {
|
||||
if (c == nullptr) {
|
||||
GB_ASSERT(operand->mode == Addressing_Value);
|
||||
GB_ASSERT(is_type_typed(operand->type));
|
||||
}
|
||||
if (operand->mode == Addressing_Invalid ||
|
||||
type == t_invalid) {
|
||||
return -1;
|
||||
@@ -818,6 +822,13 @@ bool check_is_assignable_to(CheckerContext *c, Operand *operand, Type *type) {
|
||||
return check_is_assignable_to_with_score(c, operand, type, &score);
|
||||
}
|
||||
|
||||
bool internal_check_is_assignable_to(Type *src, Type *dst) {
|
||||
Operand x = {};
|
||||
x.type = src;
|
||||
x.mode = Addressing_Value;
|
||||
return check_is_assignable_to(nullptr, &x, dst);
|
||||
}
|
||||
|
||||
AstPackage *get_package_of_type(Type *type) {
|
||||
for (;;) {
|
||||
if (type == nullptr) {
|
||||
|
||||
@@ -1834,6 +1834,15 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
|
||||
return lb_addr_load(p, parent);
|
||||
}
|
||||
}
|
||||
if (dst->Union.variants.count == 1) {
|
||||
Type *vt = dst->Union.variants[0];
|
||||
if (internal_check_is_assignable_to(src, vt)) {
|
||||
value = lb_emit_conv(p, value, vt);
|
||||
lbAddr parent = lb_add_local_generated(p, t, true);
|
||||
lb_emit_store_union_variant(p, parent.addr, value, vt);
|
||||
return lb_addr_load(p, parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE(bill): This has to be done before 'Pointer <-> Pointer' as it's
|
||||
|
||||
Reference in New Issue
Block a user