Merge tag 'dev-2024-07'

This commit is contained in:
2024-07-01 13:32:04 -04:00
160 changed files with 13729 additions and 7588 deletions
+168 -25
View File
@@ -1435,6 +1435,16 @@ gb_internal bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, T
if (!is_polymorphic_type_assignable(c, poly->BitSet.elem, source->BitSet.elem, true, modify_type)) {
return false;
}
// For generic types like bit_set[$T] the upper and lower of the poly type will be zeroes since
// it could not figure that stuff out when the poly type was created.
if (poly->BitSet.upper == 0 && modify_type) {
poly->BitSet.upper = source->BitSet.upper;
}
if (poly->BitSet.lower == 0 && modify_type) {
poly->BitSet.lower = source->BitSet.lower;
}
if (poly->BitSet.underlying == nullptr) {
if (modify_type) {
poly->BitSet.underlying = source->BitSet.underlying;
@@ -3310,7 +3320,7 @@ gb_internal bool check_cast_internal(CheckerContext *c, Operand *x, Type *type)
}
gb_internal void check_cast(CheckerContext *c, Operand *x, Type *type) {
gb_internal void check_cast(CheckerContext *c, Operand *x, Type *type, bool forbid_identical = false) {
if (!is_operand_value(*x)) {
error(x->expr, "Only values can be casted");
x->mode = Addressing_Invalid;
@@ -3382,27 +3392,37 @@ gb_internal void check_cast(CheckerContext *c, Operand *x, Type *type) {
add_package_dependency(c, "runtime", "gnu_f2h_ieee", REQUIRE);
}
}
// If we check polymorphic procedures, we risk erring on
// identical casts that cannot be foreseen or otherwise
// forbidden, so just skip them.
if (forbid_identical && check_vet_flags(c) & VetFlag_Cast &&
(c->curr_proc_sig == nullptr || !is_type_polymorphic(c->curr_proc_sig))) {
Type *src_exact = x->type;
Type *dst_exact = type;
if (src_exact != nullptr &&
dst_exact != nullptr &&
are_types_identical(src_exact, dst_exact)
) {
gbString oper_str = expr_to_string(x->expr);
gbString to_type = type_to_string(dst_exact);
error(x->expr, "Unneeded cast of '%s' to identical type '%s'", oper_str, to_type);
gb_string_free(oper_str);
gb_string_free(to_type);
}
}
}
x->type = type;
}
gb_internal bool check_transmute(CheckerContext *c, Ast *node, Operand *o, Type *t) {
gb_internal bool check_transmute(CheckerContext *c, Ast *node, Operand *o, Type *t, bool forbid_identical = false) {
if (!is_operand_value(*o)) {
error(o->expr, "'transmute' can only be applied to values");
o->mode = Addressing_Invalid;
return false;
}
// if (o->mode == Addressing_Constant) {
// gbString expr_str = expr_to_string(o->expr);
// error(o->expr, "Cannot transmute a constant expression: '%s'", expr_str);
// gb_string_free(expr_str);
// o->mode = Addressing_Invalid;
// o->expr = node;
// return false;
// }
Type *src_t = o->type;
Type *dst_t = t;
Type *src_bt = base_type(src_t);
@@ -3485,6 +3505,36 @@ gb_internal bool check_transmute(CheckerContext *c, Ast *node, Operand *o, Type
return true;
}
}
} else {
// If we check polymorphic procedures, we risk erring on
// identical casts that cannot be foreseen or otherwise
// forbidden, so just skip them.
if (forbid_identical && check_vet_flags(c) & VetFlag_Cast &&
(c->curr_proc_sig == nullptr || !is_type_polymorphic(c->curr_proc_sig))) {
if (are_types_identical(src_t, dst_t)) {
gbString oper_str = expr_to_string(o->expr);
gbString to_type = type_to_string(dst_t);
error(o->expr, "Unneeded transmute of '%s' to identical type '%s'", oper_str, to_type);
gb_string_free(oper_str);
gb_string_free(to_type);
} else if (is_type_internally_pointer_like(src_t) &&
is_type_internally_pointer_like(dst_t)) {
error(o->expr, "Use of 'transmute' where 'cast' would be preferred since the types are pointer-like");
} else if (are_types_identical(src_bt, dst_bt)) {
gbString oper_str = expr_to_string(o->expr);
gbString to_type = type_to_string(dst_t);
error(o->expr, "Unneeded transmute of '%s' to identical type '%s'", oper_str, to_type);
gb_string_free(oper_str);
gb_string_free(to_type);
} else if (is_type_integer(src_t) && is_type_integer(dst_t) &&
types_have_same_internal_endian(src_t, dst_t)) {
gbString oper_type = type_to_string(src_t);
gbString to_type = type_to_string(dst_t);
error(o->expr, "Use of 'transmute' where 'cast' would be preferred since both are integers of the same endianness, from '%s' to '%s'", oper_type, to_type);
gb_string_free(to_type);
gb_string_free(oper_type);
}
}
}
o->mode = Addressing_Value;
@@ -4431,9 +4481,14 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar
defer (gb_string_free(type_str));
if (valid_count == 1) {
Type *new_type = t->Union.variants[first_success_index];
target_type = new_type;
if (is_type_union(new_type)) {
convert_to_typed(c, operand, new_type);
break;
}
operand->type = new_type;
operand->mode = Addressing_Value;
operand->type = t->Union.variants[first_success_index];
target_type = t->Union.variants[first_success_index];
break;
} else if (valid_count > 1) {
ERROR_BLOCK();
@@ -6113,7 +6168,9 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A
Type *t = elem;
if (is_type_polymorphic(t)) {
error(call, "Ambiguous call to a polymorphic variadic procedure with no variadic input %s", type_to_string(final_proc_type));
if (show_error) {
error(call, "Ambiguous call to a polymorphic variadic procedure with no variadic input %s", type_to_string(final_proc_type));
}
err = CallArgumentError_AmbiguousPolymorphicVariadic;
}
@@ -6745,9 +6802,73 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c,
if (procs.count > 0) {
error_line("Did you mean to use one of the following:\n");
}
// Try to reduce the list further for `$T: typeid` like parameters
bool *possibly_ignore = gb_alloc_array(temporary_allocator(), bool, procs.count);
isize possibly_ignore_set = 0;
if (true) {
// NOTE(bill): This currently only checks for #soa types
for_array(i, procs) {
Entity *proc = procs[i];
Type *t = base_type(proc->type);
if (t == nullptr || t->kind != Type_Proc) {
continue;
}
TypeProc *pt = &t->Proc;
if (pt->param_count == 0) {
continue;
}
for_array(j, pt->params->Tuple.variables) {
Entity *v = pt->params->Tuple.variables[j];
if (v->kind != Entity_TypeName) {
continue;
}
Type *dst_t = base_type(v->type);
while (dst_t->kind == Type_Generic && dst_t->Generic.specialized) {
dst_t = dst_t->Generic.specialized;
}
if (j >= positional_operands.count) {
continue;
}
Operand const &o = positional_operands[j];
if (o.mode != Addressing_Type) {
continue;
}
Type *t = base_type(o.type);
if (t->kind == dst_t->kind) {
continue;
}
Type *st = base_type(type_deref(o.type));
Type *dt = base_type(type_deref(dst_t));
if (st->kind == dt->kind) {
continue;
}
if (is_type_soa_struct(st)) {
possibly_ignore[i] = true;
possibly_ignore_set += 1;
continue;
}
}
}
}
if (possibly_ignore_set == procs.count) {
possibly_ignore_set = 0;
}
isize max_name_length = 0;
isize max_type_length = 0;
for (Entity *proc : procs) {
for_array(i, procs) {
if (possibly_ignore_set != 0 && possibly_ignore[i]) {
continue;
}
Entity *proc = procs[i];
Type *t = base_type(proc->type);
if (t == t_invalid) continue;
String prefix = {};
@@ -6777,7 +6898,11 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c,
}
spaces[max_spaces] = 0;
for (Entity *proc : procs) {
for_array(i, procs) {
if (possibly_ignore_set != 0 && possibly_ignore[i]) {
continue;
}
Entity *proc = procs[i];
TokenPos pos = proc->token.pos;
Type *t = base_type(proc->type);
if (t == t_invalid) continue;
@@ -9002,12 +9127,16 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
type = nullptr;
// [?]Type
if (type_expr->kind == Ast_ArrayType && type_expr->ArrayType.count != nullptr) {
if (type_expr->kind == Ast_ArrayType) {
Ast *count = type_expr->ArrayType.count;
if (count->kind == Ast_UnaryExpr &&
count->UnaryExpr.op.kind == Token_Question) {
type = alloc_type_array(check_type(c, type_expr->ArrayType.elem), -1);
is_to_be_determined_array_count = true;
if (count != nullptr) {
if (count->kind == Ast_UnaryExpr &&
count->UnaryExpr.op.kind == Token_Question) {
type = alloc_type_array(check_type(c, type_expr->ArrayType.elem), -1);
is_to_be_determined_array_count = true;
}
} else {
type = alloc_type_slice(check_type(c, type_expr->ArrayType.elem));
}
if (cl->elems.count > 0) {
if (type_expr->ArrayType.tag != nullptr) {
@@ -9020,8 +9149,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
}
}
}
}
if (type_expr->kind == Ast_DynamicArrayType && type_expr->DynamicArrayType.tag != nullptr) {
} else if (type_expr->kind == Ast_DynamicArrayType && type_expr->DynamicArrayType.tag != nullptr) {
if (cl->elems.count > 0) {
Ast *tag = type_expr->DynamicArrayType.tag;
GB_ASSERT(tag->kind == Ast_BasicDirective);
@@ -9060,6 +9188,12 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
if (cl->elems.count == 0) {
break; // NOTE(bill): No need to init
}
if (t->Struct.soa_kind != StructSoa_None) {
error(node, "#soa arrays are not supported for compound literals");
break;
}
if (t->Struct.is_raw_union) {
if (cl->elems.count > 0) {
// NOTE: unions cannot be constant
@@ -10712,10 +10846,10 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast
if (o->mode != Addressing_Invalid) {
switch (tc->token.kind) {
case Token_transmute:
check_transmute(c, node, o, type);
check_transmute(c, node, o, type, true);
break;
case Token_cast:
check_cast(c, o, type);
check_cast(c, o, type, true);
break;
default:
error(node, "Invalid AST: Invalid casting expression");
@@ -11361,6 +11495,9 @@ gb_internal gbString write_expr_to_string(gbString str, Ast *node, bool shorthan
case_end;
case_ast_node(pt, PointerType, node);
if (pt->tag) {
str = write_expr_to_string(str, pt->tag, false);
}
str = gb_string_append_rune(str, '^');
str = write_expr_to_string(str, pt->type, shorthand);
case_end;
@@ -11371,6 +11508,9 @@ gb_internal gbString write_expr_to_string(gbString str, Ast *node, bool shorthan
case_end;
case_ast_node(at, ArrayType, node);
if (at->tag) {
str = write_expr_to_string(str, at->tag, false);
}
str = gb_string_append_rune(str, '[');
if (at->count != nullptr &&
at->count->kind == Ast_UnaryExpr &&
@@ -11384,6 +11524,9 @@ gb_internal gbString write_expr_to_string(gbString str, Ast *node, bool shorthan
case_end;
case_ast_node(at, DynamicArrayType, node);
if (at->tag) {
str = write_expr_to_string(str, at->tag, false);
}
str = gb_string_appendc(str, "[dynamic]");
str = write_expr_to_string(str, at->elem, shorthand);
case_end;