mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 15:48:51 +00:00
Fix nil assignment to unions
This commit is contained in:
+67
-73
@@ -4362,99 +4362,93 @@ void convert_to_typed(Checker *c, Operand *operand, Type *target_type, i32 level
|
|||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Type_Union:
|
case Type_Union:
|
||||||
{
|
if (!is_operand_nil(*operand) && !is_operand_undef(*operand)) {
|
||||||
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
|
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
|
||||||
defer (gb_temp_arena_memory_end(tmp));
|
defer (gb_temp_arena_memory_end(tmp));
|
||||||
isize count = t->Union.variants.count;
|
isize count = t->Union.variants.count;
|
||||||
i64 *scores = gb_alloc_array(c->tmp_allocator, i64, count);
|
i64 *scores = gb_alloc_array(c->tmp_allocator, i64, count);
|
||||||
i32 success_count = 0;
|
i32 success_count = 0;
|
||||||
i32 first_success_index = -1;
|
i32 first_success_index = -1;
|
||||||
for_array(i, t->Union.variants) {
|
for_array(i, t->Union.variants) {
|
||||||
Type *vt = t->Union.variants[i];
|
Type *vt = t->Union.variants[i];
|
||||||
i64 score = 0;
|
i64 score = 0;
|
||||||
if (check_is_assignable_to_with_score(c, operand, vt, &score)) {
|
if (check_is_assignable_to_with_score(c, operand, vt, &score)) {
|
||||||
scores[i] = score;
|
scores[i] = score;
|
||||||
success_count += 1;
|
success_count += 1;
|
||||||
if (first_success_index < 0) {
|
if (first_success_index < 0) {
|
||||||
first_success_index = i;
|
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;
|
gbString type_str = type_to_string(target_type);
|
||||||
} else if (is_type_untyped_undef(operand->type) && type_has_undef(target_type)) {
|
defer (gb_string_free(type_str));
|
||||||
target_type = t_untyped_undef;
|
|
||||||
} else if (!is_type_untyped_nil(operand->type) || !type_has_nil(target_type)) {
|
if (success_count == 1) {
|
||||||
operand->mode = Addressing_Invalid;
|
operand->mode = Addressing_Value;
|
||||||
convert_untyped_error(c, operand, target_type);
|
operand->type = t->Union.variants[first_success_index];
|
||||||
if (count > 0) {
|
target_type = t->Union.variants[first_success_index];
|
||||||
gb_printf_err("`%s` is a union which only excepts the following types:\n", type_str);
|
break;
|
||||||
gb_printf_err("\t");
|
} else if (success_count > 1) {
|
||||||
for (i32 i = 0; i < count; i++) {
|
GB_ASSERT(first_success_index >= 0);
|
||||||
Type *v = t->Union.variants[i];
|
operand->mode = Addressing_Invalid;
|
||||||
if (i > 0 && count > 2) gb_printf_err(", ");
|
convert_untyped_error(c, operand, target_type);
|
||||||
if (i == count-1) {
|
|
||||||
if (count == 2) {
|
gb_printf_err("Ambiguous type conversion to `%s`, which variant did you mean:\n\t", type_str);
|
||||||
gb_printf_err(" or ");
|
i32 j = 0;
|
||||||
} else {
|
for (i32 i = first_success_index; i < count; i++) {
|
||||||
gb_printf_err("or ");
|
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(" ");
|
||||||
|
gb_printf_err("or ");
|
||||||
}
|
}
|
||||||
gbString str = type_to_string(v);
|
gbString str = type_to_string(t->Union.variants[i]);
|
||||||
gb_printf_err("`%s`", str);
|
gb_printf_err("`%s`", str);
|
||||||
gb_string_free(str);
|
gb_string_free(str);
|
||||||
|
j++;
|
||||||
}
|
}
|
||||||
gb_printf_err("\n\n");
|
gb_printf_err("\n\n");
|
||||||
|
|
||||||
}
|
return;
|
||||||
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 > 0) {
|
||||||
|
gb_printf_err("`%s` is a union which only excepts the following types:\n", type_str);
|
||||||
|
gb_printf_err("\t");
|
||||||
|
for (i32 i = 0; i < count; i++) {
|
||||||
|
Type *v = t->Union.variants[i];
|
||||||
|
if (i > 0 && count > 2) gb_printf_err(", ");
|
||||||
|
if (i == count-1) {
|
||||||
|
if (count == 2) gb_printf_err(" ");
|
||||||
|
gb_printf_err("or ");
|
||||||
|
}
|
||||||
|
gbString str = type_to_string(v);
|
||||||
|
gb_printf_err("`%s`", str);
|
||||||
|
gb_string_free(str);
|
||||||
|
}
|
||||||
|
gb_printf_err("\n\n");
|
||||||
|
|
||||||
}
|
}
|
||||||
/* fallthrough */
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* fallthrough */
|
||||||
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (is_type_untyped_undef(operand->type) && type_has_undef(target_type)) {
|
if (is_type_untyped_undef(operand->type) && type_has_undef(target_type)) {
|
||||||
target_type = t_untyped_undef;
|
target_type = t_untyped_undef;
|
||||||
} else if (!is_type_untyped_nil(operand->type) || !type_has_nil(target_type)) {
|
} else if (is_type_untyped_nil(operand->type) && type_has_nil(target_type)) {
|
||||||
|
target_type = t_untyped_nil;
|
||||||
|
} else {
|
||||||
operand->mode = Addressing_Invalid;
|
operand->mode = Addressing_Invalid;
|
||||||
convert_untyped_error(c, operand, target_type);
|
convert_untyped_error(c, operand, target_type);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
target_type = t_untyped_nil;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user