aboutsummaryrefslogtreecommitdiff
path: root/src/check_expr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/check_expr.cpp')
-rw-r--r--src/check_expr.cpp100
1 files changed, 94 insertions, 6 deletions
diff --git a/src/check_expr.cpp b/src/check_expr.cpp
index 06d0a8b12..f0c33d9d8 100644
--- a/src/check_expr.cpp
+++ b/src/check_expr.cpp
@@ -102,6 +102,7 @@ gb_internal Type * check_init_variable (CheckerContext *c, Entity *
gb_internal void check_assignment_error_suggestion(CheckerContext *c, Operand *o, Type *type, i64 max_bit_size=0);
gb_internal void add_map_key_type_dependencies(CheckerContext *ctx, Type *key);
+gb_internal Type *make_soa_struct_fixed(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_expr, Type *elem, i64 count, Type *generic_type);
gb_internal Type *make_soa_struct_slice(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_expr, Type *elem);
gb_internal Type *make_soa_struct_dynamic_array(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_expr, Type *elem);
@@ -1409,11 +1410,16 @@ gb_internal bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, T
poly->Struct.soa_kind != StructSoa_None) {
bool ok = is_polymorphic_type_assignable(c, poly->Struct.soa_elem, source->Struct.soa_elem, true, modify_type);
if (ok) switch (source->Struct.soa_kind) {
- case StructSoa_Fixed:
+ case StructSoa_None:
default:
GB_PANIC("Unhandled SOA Kind");
break;
-
+ case StructSoa_Fixed:
+ if (modify_type) {
+ Type *type = make_soa_struct_fixed(c, nullptr, poly->Struct.node, poly->Struct.soa_elem, poly->Struct.soa_count, nullptr);
+ gb_memmove(poly, type, gb_size_of(*type));
+ }
+ break;
case StructSoa_Slice:
if (modify_type) {
Type *type = make_soa_struct_slice(c, nullptr, poly->Struct.node, poly->Struct.soa_elem);
@@ -1802,11 +1808,13 @@ gb_internal bool check_unary_op(CheckerContext *c, Operand *o, Token op) {
case Token_Not:
if (!is_type_boolean(type) || is_type_array_like(o->type)) {
ERROR_BLOCK();
- str = expr_to_string(o->expr);
error(op, "Operator '%.*s' is only allowed on boolean expressions", LIT(op.string));
- gb_string_free(str);
if (is_type_integer(type)) {
- error_line("\tSuggestion: Did you mean to use the bitwise not operator '~'?\n");
+ str = expr_to_string(o->expr);
+ error_line("\tSuggestion: Did you mean to do one of the following?\n");
+ error_line("\t\t'%s == 0'?\n", str);
+ error_line("\t\tUse of the bitwise not operator '~'?\n");
+ gb_string_free(str);
}
} else {
o->type = t_untyped_bool;
@@ -6185,6 +6193,20 @@ gb_internal bool evaluate_where_clauses(CheckerContext *ctx, Ast *call_expr, Sco
}
return false;
}
+
+ if (ast_file_vet_style(ctx->file)) {
+ Ast *c = unparen_expr(clause);
+ if (c->kind == Ast_BinaryExpr && c->BinaryExpr.op.kind == Token_CmpAnd) {
+ ERROR_BLOCK();
+ error(c, "Prefer to separate 'where' clauses with a comma rather than '&&'");
+ gbString x = expr_to_string(c->BinaryExpr.left);
+ gbString y = expr_to_string(c->BinaryExpr.right);
+ error_line("\tSuggestion: '%s, %s'\n", x, y);
+ gb_string_free(y);
+ gb_string_free(x);
+ }
+ }
+
}
}
@@ -6526,12 +6548,17 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c,
array_add(&proc_entities, proc);
}
+ int max_matched_features = 0;
gbString expr_name = expr_to_string(operand->expr);
defer (gb_string_free(expr_name));
for_array(i, procs) {
Entity *p = procs[i];
+ if (p->flags & EntityFlag_Disabled) {
+ continue;
+ }
+
Type *pt = base_type(p->type);
if (pt != nullptr && is_type_proc(pt)) {
CallArgumentData data = {};
@@ -6562,11 +6589,24 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c,
item.score += assign_score_function(1);
}
+ max_matched_features = gb_max(max_matched_features, matched_target_features(&pt->Proc));
+
item.index = index;
array_add(&valids, item);
}
}
+ if (max_matched_features > 0) {
+ for_array(i, valids) {
+ Entity *p = procs[valids[i].index];
+ Type *t = base_type(p->type);
+ GB_ASSERT(t->kind == Type_Proc);
+
+ int matched = matched_target_features(&t->Proc);
+ valids[i].score += assign_score_function(max_matched_features-matched);
+ }
+ }
+
if (valids.count > 1) {
array_sort(valids, valid_index_and_score_cmp);
i64 best_score = valids[0].score;
@@ -6708,7 +6748,11 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c,
ERROR_BLOCK();
error(operand->expr, "Ambiguous procedure group call '%s' that match with the given arguments", expr_name);
- print_argument_types();
+ if (positional_operands.count == 0 && named_operands.count == 0) {
+ error_line("\tNo given arguments\n");
+ } else {
+ print_argument_types();
+ }
for (auto const &valid : valids) {
Entity *proc = proc_entities[valid.index];
@@ -7553,8 +7597,11 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c
}
}
+ bool is_call_inlined = false;
+
switch (inlining) {
case ProcInlining_inline:
+ is_call_inlined = true;
if (proc != nullptr) {
Entity *e = entity_from_expr(proc);
if (e != nullptr && e->kind == Entity_Procedure) {
@@ -7570,6 +7617,47 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c
break;
case ProcInlining_no_inline:
break;
+ case ProcInlining_none:
+ if (proc != nullptr) {
+ Entity *e = entity_from_expr(proc);
+ if (e != nullptr && e->kind == Entity_Procedure) {
+ DeclInfo *decl = e->decl_info;
+ if (decl->proc_lit) {
+ ast_node(pl, ProcLit, decl->proc_lit);
+ if (pl->inlining == ProcInlining_inline) {
+ is_call_inlined = true;
+ }
+ }
+ }
+ }
+ }
+
+ {
+ String invalid;
+ if (pt->kind == Type_Proc && pt->Proc.require_target_feature.len != 0) {
+ if (!check_target_feature_is_valid_for_target_arch(pt->Proc.require_target_feature, &invalid)) {
+ error(call, "Called procedure requires target feature '%.*s' which is invalid for the build target", LIT(invalid));
+ } else if (!check_target_feature_is_enabled(pt->Proc.require_target_feature, &invalid)) {
+ error(call, "Calling this procedure requires target feature '%.*s' to be enabled", LIT(invalid));
+ }
+ }
+
+ if (pt->kind == Type_Proc && pt->Proc.enable_target_feature.len != 0) {
+ if (!check_target_feature_is_valid_for_target_arch(pt->Proc.enable_target_feature, &invalid)) {
+ error(call, "Called procedure enables target feature '%.*s' which is invalid for the build target", LIT(invalid));
+ }
+
+ // NOTE: Due to restrictions in LLVM you can not inline calls with a superset of features.
+ if (is_call_inlined) {
+ GB_ASSERT(c->curr_proc_decl);
+ GB_ASSERT(c->curr_proc_decl->entity);
+ GB_ASSERT(c->curr_proc_decl->entity->type->kind == Type_Proc);
+ String scope_features = c->curr_proc_decl->entity->type->Proc.enable_target_feature;
+ if (!check_target_feature_is_superset_of(scope_features, pt->Proc.enable_target_feature, &invalid)) {
+ error(call, "Inlined procedure enables target feature '%.*s', this requires the calling procedure to at least enable the same feature", LIT(invalid));
+ }
+ }
+ }
}
operand->expr = call;