|
|
|
|
@@ -66,7 +66,7 @@ gb_internal int valid_index_and_score_cmp(void const *a, void const *b) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define CALL_ARGUMENT_CHECKER(name) CallArgumentError name(CheckerContext *c, Ast *call, Type *proc_type, Entity *entity, Array<Operand> operands, CallArgumentErrorMode show_error_mode, CallArgumentData *data)
|
|
|
|
|
#define CALL_ARGUMENT_CHECKER(name) CallArgumentError name(CheckerContext *c, Ast *call, Type *proc_type, Entity *entity, Array<Operand> operands, Array<Operand> const &named_operands, CallArgumentErrorMode show_error_mode, CallArgumentData *data)
|
|
|
|
|
typedef CALL_ARGUMENT_CHECKER(CallArgumentCheckerType);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -5314,7 +5314,24 @@ gb_internal isize get_procedure_param_count_excluding_defaults(Type *pt, isize *
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
gb_internal isize lookup_procedure_parameter(TypeProc *pt, String parameter_name) {
|
|
|
|
|
isize param_count = pt->param_count;
|
|
|
|
|
for (isize i = 0; i < param_count; i++) {
|
|
|
|
|
Entity *e = pt->params->Tuple.variables[i];
|
|
|
|
|
String name = e->token.string;
|
|
|
|
|
if (is_blank_ident(name)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (name == parameter_name) {
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gb_internal CALL_ARGUMENT_CHECKER(check_call_arguments_internal) {
|
|
|
|
|
CallArgumentError err = CallArgumentError_None;
|
|
|
|
|
|
|
|
|
|
ast_node(ce, CallExpr, call);
|
|
|
|
|
GB_ASSERT(is_type_proc(proc_type));
|
|
|
|
|
proc_type = base_type(proc_type);
|
|
|
|
|
@@ -5327,6 +5344,52 @@ gb_internal CALL_ARGUMENT_CHECKER(check_call_arguments_internal) {
|
|
|
|
|
i64 score = 0;
|
|
|
|
|
bool show_error = show_error_mode == CallArgumentMode_ShowErrors;
|
|
|
|
|
|
|
|
|
|
auto ordered_operands = array_make<Operand>(temporary_allocator(), pt->param_count);
|
|
|
|
|
bool *visited = gb_alloc_array(temporary_allocator(), bool, pt->param_count);
|
|
|
|
|
|
|
|
|
|
if (ce->split_args) {
|
|
|
|
|
GB_ASSERT(ce->split_args->named.count == named_operands.count);
|
|
|
|
|
for_array(i, ce->split_args->named) {
|
|
|
|
|
Ast *arg = ce->split_args->named[i];
|
|
|
|
|
Operand operand = named_operands[i];
|
|
|
|
|
|
|
|
|
|
ast_node(fv, FieldValue, arg);
|
|
|
|
|
if (fv->field->kind != Ast_Ident) {
|
|
|
|
|
if (show_error) {
|
|
|
|
|
gbString expr_str = expr_to_string(fv->field);
|
|
|
|
|
error(arg, "Invalid parameter name '%s' in procedure call", expr_str);
|
|
|
|
|
gb_string_free(expr_str);
|
|
|
|
|
}
|
|
|
|
|
err = CallArgumentError_InvalidFieldValue;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
String name = fv->field->Ident.token.string;
|
|
|
|
|
isize param_index = lookup_procedure_parameter(pt, name);
|
|
|
|
|
if (param_index < 0) {
|
|
|
|
|
if (show_error) {
|
|
|
|
|
error(arg, "No parameter named '%.*s' for this procedure type", LIT(name));
|
|
|
|
|
}
|
|
|
|
|
err = CallArgumentError_ParameterNotFound;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (visited[param_index]) {
|
|
|
|
|
if (show_error) {
|
|
|
|
|
error(arg, "Duplicate parameter '%.*s' in procedure call", LIT(name));
|
|
|
|
|
}
|
|
|
|
|
err = CallArgumentError_DuplicateParameter;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
visited[param_index] = true;
|
|
|
|
|
ordered_operands[param_index] = operand;
|
|
|
|
|
|
|
|
|
|
err = CallArgumentError_DuplicateParameter;
|
|
|
|
|
}
|
|
|
|
|
if (err) {
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
TypeTuple *param_tuple = nullptr;
|
|
|
|
|
if (pt->params != nullptr) {
|
|
|
|
|
@@ -5334,7 +5397,6 @@ gb_internal CALL_ARGUMENT_CHECKER(check_call_arguments_internal) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CallArgumentError err = CallArgumentError_None;
|
|
|
|
|
Type *final_proc_type = proc_type;
|
|
|
|
|
Entity *gen_entity = nullptr;
|
|
|
|
|
|
|
|
|
|
@@ -5571,21 +5633,6 @@ gb_internal bool is_call_expr_field_value(AstCallExpr *ce) {
|
|
|
|
|
return ce->args[0]->kind == Ast_FieldValue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gb_internal isize lookup_procedure_parameter(TypeProc *pt, String parameter_name) {
|
|
|
|
|
isize param_count = pt->param_count;
|
|
|
|
|
for (isize i = 0; i < param_count; i++) {
|
|
|
|
|
Entity *e = pt->params->Tuple.variables[i];
|
|
|
|
|
String name = e->token.string;
|
|
|
|
|
if (is_blank_ident(name)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (name == parameter_name) {
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gb_internal CALL_ARGUMENT_CHECKER(check_named_call_arguments) {
|
|
|
|
|
ast_node(ce, CallExpr, call);
|
|
|
|
|
GB_ASSERT(is_type_proc(proc_type));
|
|
|
|
|
@@ -5969,8 +6016,561 @@ gb_internal CallArgumentError check_order_of_call_arguments(CheckerContext *c, T
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gb_internal bool check_named_arguments(CheckerContext *c, Type *type, Slice<Ast *> const &named_args, Array<Operand> *named_operands, bool show_error) {
|
|
|
|
|
bool success = true;
|
|
|
|
|
|
|
|
|
|
gb_internal CallArgumentData check_call_arguments_single_procedure(CheckerContext *c, Operand *operand, Ast *call) {
|
|
|
|
|
type = base_type(type);
|
|
|
|
|
if (named_args.count > 0) {
|
|
|
|
|
TypeProc *pt = nullptr;
|
|
|
|
|
if (is_type_proc(type)) {
|
|
|
|
|
pt = &type->Proc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for_array(i, named_args) {
|
|
|
|
|
Ast *arg = named_args[i];
|
|
|
|
|
if (arg->kind != Ast_FieldValue) {
|
|
|
|
|
if (show_error) {
|
|
|
|
|
error(arg, "Expected a 'field = value'");
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
ast_node(fv, FieldValue, arg);
|
|
|
|
|
if (fv->field->kind != Ast_Ident) {
|
|
|
|
|
if (show_error) {
|
|
|
|
|
gbString expr_str = expr_to_string(fv->field);
|
|
|
|
|
error(arg, "Invalid parameter name '%s' in procedure call", expr_str);
|
|
|
|
|
gb_string_free(expr_str);
|
|
|
|
|
}
|
|
|
|
|
success = false;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
String key = fv->field->Ident.token.string;
|
|
|
|
|
Ast *value = fv->value;
|
|
|
|
|
|
|
|
|
|
Type *type_hint = nullptr;
|
|
|
|
|
if (pt) {
|
|
|
|
|
isize param_index = lookup_procedure_parameter(pt, key);
|
|
|
|
|
if (param_index < 0) {
|
|
|
|
|
if (show_error) {
|
|
|
|
|
error(value, "No parameter named '%.*s' for this procedure type %s", LIT(key), type_to_string(type));
|
|
|
|
|
}
|
|
|
|
|
success = false;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// bool prev_visited = visited[param_index];
|
|
|
|
|
// if (prev_visited) {
|
|
|
|
|
// error(value, "Duplicate parameter named '%.*s' in procedure call", LIT(key));
|
|
|
|
|
// success = false;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
Entity *e = pt->params->Tuple.variables[param_index];
|
|
|
|
|
if (!is_type_polymorphic(e->type)) {
|
|
|
|
|
type_hint = e->type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
Operand o = {};
|
|
|
|
|
check_expr_with_type_hint(c, &o, value, type_hint);
|
|
|
|
|
if (o.mode == Addressing_Invalid) {
|
|
|
|
|
success = false;
|
|
|
|
|
}
|
|
|
|
|
array_add(named_operands, o);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
return success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
gb_internal CallArgumentData check_call_arguments_new_and_improved_proc_group(CheckerContext *c, Operand *operand, Ast *call) {
|
|
|
|
|
ast_node(ce, CallExpr, call);
|
|
|
|
|
GB_ASSERT(ce->split_args != nullptr);
|
|
|
|
|
|
|
|
|
|
Slice<Ast *> const &positional_args = ce->split_args->positional;
|
|
|
|
|
Slice<Ast *> const &named_args = ce->split_args->named;
|
|
|
|
|
|
|
|
|
|
CallArgumentData data = {};
|
|
|
|
|
data.result_type = t_invalid;
|
|
|
|
|
|
|
|
|
|
GB_ASSERT(operand->mode == Addressing_ProcGroup);
|
|
|
|
|
auto procs = proc_group_entities_cloned(c, *operand);
|
|
|
|
|
|
|
|
|
|
if (procs.count > 1) {
|
|
|
|
|
isize max_arg_count = positional_args.count + named_args.count;
|
|
|
|
|
for (Ast *arg : positional_args) {
|
|
|
|
|
// NOTE(bill): The only thing that may have multiple values
|
|
|
|
|
// will be a call expression (assuming `or_return` and `()` will be stripped)
|
|
|
|
|
arg = strip_or_return_expr(arg);
|
|
|
|
|
if (arg && arg->kind == Ast_CallExpr) {
|
|
|
|
|
max_arg_count = ISIZE_MAX;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (max_arg_count != ISIZE_MAX) for (Ast *arg : named_args) {
|
|
|
|
|
// NOTE(bill): The only thing that may have multiple values
|
|
|
|
|
// will be a call expression (assuming `or_return` and `()` will be stripped)
|
|
|
|
|
if (arg->kind == Ast_FieldValue) {
|
|
|
|
|
arg = strip_or_return_expr(arg->FieldValue.value);
|
|
|
|
|
if (arg && arg->kind == Ast_CallExpr) {
|
|
|
|
|
max_arg_count = ISIZE_MAX;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (isize proc_index = 0; proc_index < procs.count; /**/) {
|
|
|
|
|
Entity *proc = procs[proc_index];
|
|
|
|
|
Type *pt = base_type(proc->type);
|
|
|
|
|
if (!(pt != nullptr && is_type_proc(pt))) {
|
|
|
|
|
proc_index++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
isize param_count = 0;
|
|
|
|
|
isize param_count_excluding_defaults = get_procedure_param_count_excluding_defaults(pt, ¶m_count);
|
|
|
|
|
|
|
|
|
|
if (param_count_excluding_defaults > max_arg_count) {
|
|
|
|
|
array_unordered_remove(&procs, proc_index);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// for (Ast *arg : named_args) {
|
|
|
|
|
// if (arg->kind != Ast_FieldValue) {
|
|
|
|
|
// continue;
|
|
|
|
|
// }
|
|
|
|
|
// ast_node(fv, FieldValue, arg);
|
|
|
|
|
// if (fv->field->kind != Ast_Ident) {
|
|
|
|
|
// continue;
|
|
|
|
|
// }
|
|
|
|
|
// bool ok = false;
|
|
|
|
|
// String key = fv->field->Ident.token.string;
|
|
|
|
|
// if (param_count) for (Entity *e : pt->Proc.params->Tuple.variables) {
|
|
|
|
|
// if (e->token.string == key) {
|
|
|
|
|
// ok = true;
|
|
|
|
|
// break;
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// if (!ok) {
|
|
|
|
|
// if (proc_index < procs.count) {
|
|
|
|
|
// array_unordered_remove(&procs, proc_index);
|
|
|
|
|
// continue;
|
|
|
|
|
// } else {
|
|
|
|
|
// break;
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
proc_index++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Entity **lhs = nullptr;
|
|
|
|
|
isize lhs_count = -1;
|
|
|
|
|
bool is_variadic = false;
|
|
|
|
|
|
|
|
|
|
auto positional_operands = array_make<Operand>(heap_allocator(), 0, 0);
|
|
|
|
|
auto named_operands = array_make<Operand>(heap_allocator(), 0, 0);
|
|
|
|
|
defer (array_free(&positional_operands));
|
|
|
|
|
defer (array_free(&named_operands));
|
|
|
|
|
|
|
|
|
|
if (procs.count == 1) {
|
|
|
|
|
Ast *ident = operand->expr;
|
|
|
|
|
while (ident->kind == Ast_SelectorExpr) {
|
|
|
|
|
Ast *s = ident->SelectorExpr.selector;
|
|
|
|
|
ident = s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Entity *e = procs[0];
|
|
|
|
|
|
|
|
|
|
lhs = populate_proc_parameter_list(c, e->type, &lhs_count, &is_variadic);
|
|
|
|
|
check_unpack_arguments(c, lhs, lhs_count, &positional_operands, positional_args, is_variadic ? UnpackFlag_IsVariadic : UnpackFlag_None);
|
|
|
|
|
|
|
|
|
|
if (!check_named_arguments(c, e->type, named_args, &named_operands, true)) {
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CallArgumentError err = check_call_arguments_internal(c, call, e->type, e, positional_operands, named_operands, CallArgumentMode_ShowErrors, &data);
|
|
|
|
|
if (err != CallArgumentError_None) {
|
|
|
|
|
// handle error
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Type *proc_type = base_type(operand->type);
|
|
|
|
|
|
|
|
|
|
Entity *entity_to_use = data.gen_entity != nullptr ? data.gen_entity : e;
|
|
|
|
|
add_entity_use(c, ident, entity_to_use);
|
|
|
|
|
if (entity_to_use != nullptr) {
|
|
|
|
|
update_untyped_expr_type(c, operand->expr, entity_to_use->type, true);
|
|
|
|
|
|
|
|
|
|
proc_type = base_type(entity_to_use->type);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (proc_type && proc_type->kind == Type_Proc) {
|
|
|
|
|
data.result_type = proc_type->Proc.results;
|
|
|
|
|
add_type_and_value(c, operand->expr, operand->mode, proc_type, operand->value);
|
|
|
|
|
} else if (err == CallArgumentError_None) {
|
|
|
|
|
data.result_type = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (data.gen_entity != nullptr) {
|
|
|
|
|
Entity *e = data.gen_entity;
|
|
|
|
|
DeclInfo *decl = data.gen_entity->decl_info;
|
|
|
|
|
CheckerContext ctx = *c;
|
|
|
|
|
ctx.scope = decl->scope;
|
|
|
|
|
ctx.decl = decl;
|
|
|
|
|
ctx.proc_name = e->token.string;
|
|
|
|
|
ctx.curr_proc_decl = decl;
|
|
|
|
|
ctx.curr_proc_sig = e->type;
|
|
|
|
|
|
|
|
|
|
GB_ASSERT(decl->proc_lit->kind == Ast_ProcLit);
|
|
|
|
|
bool ok = evaluate_where_clauses(&ctx, call, decl->scope, &decl->proc_lit->ProcLit.where_clauses, true);
|
|
|
|
|
decl->where_clauses_evaluated = true;
|
|
|
|
|
|
|
|
|
|
if (ok && (data.gen_entity->flags & EntityFlag_ProcBodyChecked) == 0) {
|
|
|
|
|
check_procedure_later(c->checker, e->file, e->token, decl, e->type, decl->proc_lit->ProcLit.body, decl->proc_lit->ProcLit.tags);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
// NOTE(bill, 2019-07-13): This code is used to improve the type inference for procedure groups
|
|
|
|
|
// where the same positional parameter has the same type value (and ellipsis)
|
|
|
|
|
bool proc_arg_count_all_equal = true;
|
|
|
|
|
isize proc_arg_count = -1;
|
|
|
|
|
for (Entity *p : procs) {
|
|
|
|
|
Type *pt = base_type(p->type);
|
|
|
|
|
if (pt != nullptr && is_type_proc(pt)) {
|
|
|
|
|
if (proc_arg_count < 0) {
|
|
|
|
|
proc_arg_count = pt->Proc.param_count;
|
|
|
|
|
} else {
|
|
|
|
|
if (proc_arg_count != pt->Proc.param_count) {
|
|
|
|
|
proc_arg_count_all_equal = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (proc_arg_count >= 0 && proc_arg_count_all_equal) {
|
|
|
|
|
lhs_count = proc_arg_count;
|
|
|
|
|
if (lhs_count > 0) {
|
|
|
|
|
lhs = gb_alloc_array(heap_allocator(), Entity *, lhs_count);
|
|
|
|
|
for (isize param_index = 0; param_index < lhs_count; param_index++) {
|
|
|
|
|
Entity *e = nullptr;
|
|
|
|
|
for (Entity *p : procs) {
|
|
|
|
|
Type *pt = base_type(p->type);
|
|
|
|
|
if (!(pt != nullptr && is_type_proc(pt))) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (e == nullptr) {
|
|
|
|
|
e = pt->Proc.params->Tuple.variables[param_index];
|
|
|
|
|
} else {
|
|
|
|
|
Entity *f = pt->Proc.params->Tuple.variables[param_index];
|
|
|
|
|
if (e == f) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (are_types_identical(e->type, f->type)) {
|
|
|
|
|
bool ee = (e->flags & EntityFlag_Ellipsis) != 0;
|
|
|
|
|
bool fe = (f->flags & EntityFlag_Ellipsis) != 0;
|
|
|
|
|
if (ee == fe) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// NOTE(bill): Entities are not close enough to be used
|
|
|
|
|
e = nullptr;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
lhs[param_index] = e;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
check_unpack_arguments(c, lhs, lhs_count, &positional_operands, positional_args, is_variadic ? UnpackFlag_IsVariadic : UnpackFlag_None);
|
|
|
|
|
|
|
|
|
|
for_array(i, named_args) {
|
|
|
|
|
Ast *arg = named_args[i];
|
|
|
|
|
if (arg->kind != Ast_FieldValue) {
|
|
|
|
|
error(arg, "Expected a 'field = value'");
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
ast_node(fv, FieldValue, arg);
|
|
|
|
|
if (fv->field->kind != Ast_Ident) {
|
|
|
|
|
gbString expr_str = expr_to_string(fv->field);
|
|
|
|
|
error(arg, "Invalid parameter name '%s' in procedure call", expr_str);
|
|
|
|
|
gb_string_free(expr_str);
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
String key = fv->field->Ident.token.string;
|
|
|
|
|
Ast *value = fv->value;
|
|
|
|
|
|
|
|
|
|
Type *type_hint = nullptr;
|
|
|
|
|
|
|
|
|
|
for (isize lhs_idx = 0; lhs_idx < lhs_count; lhs_idx++) {
|
|
|
|
|
Entity *e = lhs[lhs_idx];
|
|
|
|
|
if (e != nullptr && e->token.string == key &&
|
|
|
|
|
!is_type_polymorphic(e->type)) {
|
|
|
|
|
type_hint = e->type;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Operand o = {};
|
|
|
|
|
check_expr_with_type_hint(c, &o, value, type_hint);
|
|
|
|
|
array_add(&named_operands, o);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gb_free(heap_allocator(), lhs);
|
|
|
|
|
|
|
|
|
|
auto valids = array_make<ValidIndexAndScore>(heap_allocator(), 0, procs.count);
|
|
|
|
|
defer (array_free(&valids));
|
|
|
|
|
|
|
|
|
|
auto proc_entities = array_make<Entity *>(heap_allocator(), 0, procs.count*2 + 1);
|
|
|
|
|
defer (array_free(&proc_entities));
|
|
|
|
|
for (Entity *proc : procs) {
|
|
|
|
|
array_add(&proc_entities, proc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
gbString expr_name = expr_to_string(operand->expr);
|
|
|
|
|
defer (gb_string_free(expr_name));
|
|
|
|
|
|
|
|
|
|
for_array(i, procs) {
|
|
|
|
|
Entity *p = procs[i];
|
|
|
|
|
Type *pt = base_type(p->type);
|
|
|
|
|
if (pt != nullptr && is_type_proc(pt)) {
|
|
|
|
|
CallArgumentError err = CallArgumentError_None;
|
|
|
|
|
CallArgumentData data = {};
|
|
|
|
|
CheckerContext ctx = *c;
|
|
|
|
|
|
|
|
|
|
ctx.no_polymorphic_errors = true;
|
|
|
|
|
ctx.allow_polymorphic_types = is_type_polymorphic(pt);
|
|
|
|
|
ctx.hide_polymorphic_errors = true;
|
|
|
|
|
|
|
|
|
|
err = check_call_arguments_internal(&ctx, call, pt, p, positional_operands, named_operands, CallArgumentMode_NoErrors, &data);
|
|
|
|
|
if (err != CallArgumentError_None) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
isize index = i;
|
|
|
|
|
|
|
|
|
|
if (data.gen_entity != nullptr) {
|
|
|
|
|
Entity *e = data.gen_entity;
|
|
|
|
|
DeclInfo *decl = data.gen_entity->decl_info;
|
|
|
|
|
ctx.scope = decl->scope;
|
|
|
|
|
ctx.decl = decl;
|
|
|
|
|
ctx.proc_name = e->token.string;
|
|
|
|
|
ctx.curr_proc_decl = decl;
|
|
|
|
|
ctx.curr_proc_sig = e->type;
|
|
|
|
|
|
|
|
|
|
GB_ASSERT(decl->proc_lit->kind == Ast_ProcLit);
|
|
|
|
|
if (!evaluate_where_clauses(&ctx, call, decl->scope, &decl->proc_lit->ProcLit.where_clauses, false)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
array_add(&proc_entities, data.gen_entity);
|
|
|
|
|
index = proc_entities.count-1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ValidIndexAndScore item = {};
|
|
|
|
|
item.index = index;
|
|
|
|
|
item.score = data.score;
|
|
|
|
|
array_add(&valids, item);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (valids.count > 1) {
|
|
|
|
|
gb_sort_array(valids.data, valids.count, valid_index_and_score_cmp);
|
|
|
|
|
i64 best_score = valids[0].score;
|
|
|
|
|
Entity *best_entity = proc_entities[valids[0].index];
|
|
|
|
|
GB_ASSERT(best_entity != nullptr);
|
|
|
|
|
for (isize i = 1; i < valids.count; i++) {
|
|
|
|
|
if (best_score > valids[i].score) {
|
|
|
|
|
valids.count = i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (best_entity == proc_entities[valids[i].index]) {
|
|
|
|
|
valids.count = i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto print_argument_types = [&]() {
|
|
|
|
|
error_line("\tGiven argument types: (");
|
|
|
|
|
isize i = 0;
|
|
|
|
|
for (Operand const &o : positional_operands) {
|
|
|
|
|
if (i++ > 0) error_line(", ");
|
|
|
|
|
gbString type = type_to_string(o.type);
|
|
|
|
|
defer (gb_string_free(type));
|
|
|
|
|
error_line("%s", type);
|
|
|
|
|
}
|
|
|
|
|
for (Operand const &o : named_operands) {
|
|
|
|
|
if (i++ > 0) error_line(", ");
|
|
|
|
|
|
|
|
|
|
gbString type = type_to_string(o.type);
|
|
|
|
|
defer (gb_string_free(type));
|
|
|
|
|
|
|
|
|
|
if (i < ce->split_args->named.count) {
|
|
|
|
|
Ast *named_field = ce->split_args->named[i];
|
|
|
|
|
ast_node(fv, FieldValue, named_field);
|
|
|
|
|
|
|
|
|
|
gbString field = expr_to_string(fv->field);
|
|
|
|
|
defer (gb_string_free(field));
|
|
|
|
|
|
|
|
|
|
error_line("%s = %s", field, type);
|
|
|
|
|
} else {
|
|
|
|
|
error_line("%s", type);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
error_line(")\n");
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (valids.count == 0) {
|
|
|
|
|
begin_error_block();
|
|
|
|
|
defer (end_error_block());
|
|
|
|
|
|
|
|
|
|
error(operand->expr, "No procedures or ambiguous call for procedure group '%s' that match with the given arguments", expr_name);
|
|
|
|
|
if (positional_operands.count == 0 && named_operands.count == 0) {
|
|
|
|
|
error_line("\tNo given arguments\n");
|
|
|
|
|
} else {
|
|
|
|
|
print_argument_types();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (procs.count > 0) {
|
|
|
|
|
error_line("Did you mean to use one of the following:\n");
|
|
|
|
|
}
|
|
|
|
|
for (Entity *proc : procs) {
|
|
|
|
|
TokenPos pos = proc->token.pos;
|
|
|
|
|
Type *t = base_type(proc->type);
|
|
|
|
|
if (t == t_invalid) continue;
|
|
|
|
|
GB_ASSERT(t->kind == Type_Proc);
|
|
|
|
|
gbString pt;
|
|
|
|
|
defer (gb_string_free(pt));
|
|
|
|
|
if (t->Proc.node != nullptr) {
|
|
|
|
|
pt = expr_to_string(t->Proc.node);
|
|
|
|
|
} else {
|
|
|
|
|
pt = type_to_string(t);
|
|
|
|
|
}
|
|
|
|
|
String prefix = {};
|
|
|
|
|
String prefix_sep = {};
|
|
|
|
|
if (proc->pkg) {
|
|
|
|
|
prefix = proc->pkg->name;
|
|
|
|
|
prefix_sep = str_lit(".");
|
|
|
|
|
}
|
|
|
|
|
String name = proc->token.string;
|
|
|
|
|
|
|
|
|
|
char const *sep = "::";
|
|
|
|
|
if (proc->kind == Entity_Variable) {
|
|
|
|
|
sep = ":=";
|
|
|
|
|
}
|
|
|
|
|
error_line("\t%.*s%.*s%.*s %s %s at %s\n", LIT(prefix), LIT(prefix_sep), LIT(name), sep, pt, token_pos_to_string(pos));
|
|
|
|
|
}
|
|
|
|
|
if (procs.count > 0) {
|
|
|
|
|
error_line("\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
data.result_type = t_invalid;
|
|
|
|
|
} else if (valids.count > 1) {
|
|
|
|
|
begin_error_block();
|
|
|
|
|
defer (end_error_block());
|
|
|
|
|
|
|
|
|
|
error(operand->expr, "Ambiguous procedure group call '%s' that match with the given arguments", expr_name);
|
|
|
|
|
print_argument_types();
|
|
|
|
|
|
|
|
|
|
for (isize i = 0; i < valids.count; i++) {
|
|
|
|
|
Entity *proc = proc_entities[valids[i].index];
|
|
|
|
|
GB_ASSERT(proc != nullptr);
|
|
|
|
|
TokenPos pos = proc->token.pos;
|
|
|
|
|
Type *t = base_type(proc->type); GB_ASSERT(t->kind == Type_Proc);
|
|
|
|
|
gbString pt = nullptr;
|
|
|
|
|
defer (gb_string_free(pt));
|
|
|
|
|
if (t->Proc.node != nullptr) {
|
|
|
|
|
pt = expr_to_string(t->Proc.node);
|
|
|
|
|
} else {
|
|
|
|
|
pt = type_to_string(t);
|
|
|
|
|
}
|
|
|
|
|
String name = proc->token.string;
|
|
|
|
|
char const *sep = "::";
|
|
|
|
|
if (proc->kind == Entity_Variable) {
|
|
|
|
|
sep = ":=";
|
|
|
|
|
}
|
|
|
|
|
error_line("\t%.*s %s %s ", LIT(name), sep, pt);
|
|
|
|
|
if (proc->decl_info->proc_lit != nullptr) {
|
|
|
|
|
GB_ASSERT(proc->decl_info->proc_lit->kind == Ast_ProcLit);
|
|
|
|
|
auto *pl = &proc->decl_info->proc_lit->ProcLit;
|
|
|
|
|
if (pl->where_token.kind != Token_Invalid) {
|
|
|
|
|
error_line("\n\t\twhere ");
|
|
|
|
|
for_array(j, pl->where_clauses) {
|
|
|
|
|
Ast *clause = pl->where_clauses[j];
|
|
|
|
|
if (j != 0) {
|
|
|
|
|
error_line("\t\t ");
|
|
|
|
|
}
|
|
|
|
|
gbString str = expr_to_string(clause);
|
|
|
|
|
error_line("%s", str);
|
|
|
|
|
gb_string_free(str);
|
|
|
|
|
|
|
|
|
|
if (j != pl->where_clauses.count-1) {
|
|
|
|
|
error_line(",");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
error_line("\n\t");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
error_line("at %s\n", token_pos_to_string(pos));
|
|
|
|
|
}
|
|
|
|
|
data.result_type = t_invalid;
|
|
|
|
|
} else {
|
|
|
|
|
GB_ASSERT(valids.count == 1);
|
|
|
|
|
Ast *ident = operand->expr;
|
|
|
|
|
while (ident->kind == Ast_SelectorExpr) {
|
|
|
|
|
Ast *s = ident->SelectorExpr.selector;
|
|
|
|
|
ident = s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Entity *e = proc_entities[valids[0].index];
|
|
|
|
|
GB_ASSERT(e != nullptr);
|
|
|
|
|
|
|
|
|
|
Array<Operand> named_operands = {};
|
|
|
|
|
|
|
|
|
|
Type *proc_type = e->type;
|
|
|
|
|
CallArgumentData data = {};
|
|
|
|
|
CallArgumentError err = check_call_arguments_internal(c, call, proc_type, e, positional_operands, named_operands, CallArgumentMode_ShowErrors, &data);
|
|
|
|
|
gb_unused(err);
|
|
|
|
|
Entity *entity_to_use = data.gen_entity != nullptr ? data.gen_entity : e;
|
|
|
|
|
add_entity_use(c, ident, entity_to_use);
|
|
|
|
|
if (entity_to_use != nullptr) {
|
|
|
|
|
update_untyped_expr_type(c, operand->expr, entity_to_use->type, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (data.gen_entity != nullptr) {
|
|
|
|
|
Entity *e = data.gen_entity;
|
|
|
|
|
DeclInfo *decl = data.gen_entity->decl_info;
|
|
|
|
|
CheckerContext ctx = *c;
|
|
|
|
|
ctx.scope = decl->scope;
|
|
|
|
|
ctx.decl = decl;
|
|
|
|
|
ctx.proc_name = e->token.string;
|
|
|
|
|
ctx.curr_proc_decl = decl;
|
|
|
|
|
ctx.curr_proc_sig = e->type;
|
|
|
|
|
|
|
|
|
|
GB_ASSERT(decl->proc_lit->kind == Ast_ProcLit);
|
|
|
|
|
bool ok = evaluate_where_clauses(&ctx, call, decl->scope, &decl->proc_lit->ProcLit.where_clauses, true);
|
|
|
|
|
decl->where_clauses_evaluated = true;
|
|
|
|
|
|
|
|
|
|
if (ok && (data.gen_entity->flags & EntityFlag_ProcBodyChecked) == 0) {
|
|
|
|
|
check_procedure_later(c->checker, e->file, e->token, decl, e->type, decl->proc_lit->ProcLit.body, decl->proc_lit->ProcLit.tags);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
gb_internal CallArgumentData check_call_arguments_new_and_improved(CheckerContext *c, Operand *operand, Ast *call) {
|
|
|
|
|
Type *proc_type = nullptr;
|
|
|
|
|
|
|
|
|
|
CallArgumentData data = {};
|
|
|
|
|
@@ -5978,23 +6578,6 @@ gb_internal CallArgumentData check_call_arguments_single_procedure(CheckerContex
|
|
|
|
|
|
|
|
|
|
proc_type = base_type(operand->type);
|
|
|
|
|
|
|
|
|
|
if (operand->mode == Addressing_ProcGroup) {
|
|
|
|
|
Array<Entity *> procs = proc_group_entities(c, *operand);
|
|
|
|
|
if (procs.count == 1) {
|
|
|
|
|
proc_type = base_type(procs[0]->type);
|
|
|
|
|
} else {
|
|
|
|
|
error(call, "Procedure groups >1 not yet supported");
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (proc_type == nullptr || proc_type->kind != Type_Proc) {
|
|
|
|
|
gbString s = type_to_string(proc_type);
|
|
|
|
|
error(call, "Expected a procedure to call, got %s", s);
|
|
|
|
|
gb_string_free(s);
|
|
|
|
|
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (proc_type != nullptr && is_type_polymorphic(proc_type)) {
|
|
|
|
|
error(call, "Polymorphic procedures not yet supported");
|
|
|
|
|
return data;
|
|
|
|
|
@@ -6012,19 +6595,38 @@ gb_internal CallArgumentData check_call_arguments_single_procedure(CheckerContex
|
|
|
|
|
|
|
|
|
|
bool vari_expand = (ce->ellipsis.pos.line != 0);
|
|
|
|
|
|
|
|
|
|
auto positional_args = ce->args;
|
|
|
|
|
for (isize i = 0; i < ce->args.count; i++) {
|
|
|
|
|
Ast *arg = ce->args.data[i];
|
|
|
|
|
if (arg->kind == Ast_FieldValue) {
|
|
|
|
|
positional_args.count = i;
|
|
|
|
|
break;
|
|
|
|
|
// Split positional and named args into separate arrays/slices
|
|
|
|
|
Slice<Ast *> positional_args = {};
|
|
|
|
|
Slice<Ast *> named_args = {};
|
|
|
|
|
|
|
|
|
|
if (ce->split_args == nullptr) {
|
|
|
|
|
positional_args = ce->args;
|
|
|
|
|
for (isize i = 0; i < ce->args.count; i++) {
|
|
|
|
|
Ast *arg = ce->args.data[i];
|
|
|
|
|
if (arg->kind == Ast_FieldValue) {
|
|
|
|
|
positional_args.count = i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
named_args = slice(ce->args, positional_args.count, ce->args.count);
|
|
|
|
|
|
|
|
|
|
auto split_args = gb_alloc_item(permanent_allocator(), AstSplitArgs);
|
|
|
|
|
split_args->positional = positional_args;
|
|
|
|
|
split_args->named = named_args;
|
|
|
|
|
ce->split_args = split_args;
|
|
|
|
|
} else {
|
|
|
|
|
positional_args = ce->split_args->positional;
|
|
|
|
|
named_args = ce->split_args->named;
|
|
|
|
|
}
|
|
|
|
|
auto named_args = slice(ce->args, positional_args.count, ce->args.count);
|
|
|
|
|
|
|
|
|
|
if (operand->mode == Addressing_ProcGroup) {
|
|
|
|
|
return check_call_arguments_new_and_improved_proc_group(c, operand, call);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
auto positional_operands = array_make<Operand>(heap_allocator(), 0, positional_args.count);
|
|
|
|
|
auto variadic_operands = array_make<Operand>(heap_allocator(), 0, 0);
|
|
|
|
|
auto named_operands = array_make<Operand>(heap_allocator(), 0, 0);
|
|
|
|
|
auto variadic_operands = array_make<Operand>(heap_allocator(), 0, 0);
|
|
|
|
|
auto named_operands = array_make<Operand>(heap_allocator(), 0, 0);
|
|
|
|
|
|
|
|
|
|
defer (array_free(&positional_operands));
|
|
|
|
|
defer (array_free(&variadic_operands));
|
|
|
|
|
@@ -6038,14 +6640,16 @@ gb_internal CallArgumentData check_call_arguments_single_procedure(CheckerContex
|
|
|
|
|
isize lhs_count = -1;
|
|
|
|
|
bool is_variadic = false;
|
|
|
|
|
Entity **lhs = nullptr;
|
|
|
|
|
if (proc_type != nullptr && is_type_proc(proc_type)) {
|
|
|
|
|
if (pt != nullptr) {
|
|
|
|
|
lhs = populate_proc_parameter_list(c, proc_type, &lhs_count, &is_variadic);
|
|
|
|
|
} else if (operand->mode == Addressing_ProcGroup) {
|
|
|
|
|
// TODO
|
|
|
|
|
}
|
|
|
|
|
check_unpack_arguments(c, lhs, lhs_count, &positional_operands, positional_args, is_variadic ? UnpackFlag_IsVariadic : UnpackFlag_None);
|
|
|
|
|
}
|
|
|
|
|
positional_operand_count = positional_operands.count;
|
|
|
|
|
|
|
|
|
|
if (proc_type != nullptr) {
|
|
|
|
|
if (pt != nullptr) {
|
|
|
|
|
visited = slice_make<bool>(temporary_allocator(), pt->param_count);
|
|
|
|
|
|
|
|
|
|
if (!pt->variadic) {
|
|
|
|
|
@@ -6161,7 +6765,7 @@ gb_internal CallArgumentData check_call_arguments_single_procedure(CheckerContex
|
|
|
|
|
string_map_init(&type_hint_map, 2*named_args.count);
|
|
|
|
|
defer (string_map_destroy(&type_hint_map));
|
|
|
|
|
|
|
|
|
|
if (proc_type != nullptr) {
|
|
|
|
|
if (pt != nullptr) {
|
|
|
|
|
TypeTuple *param_tuple = &pt->params->Tuple;
|
|
|
|
|
for (Entity *e : param_tuple->variables) {
|
|
|
|
|
if (is_blank_ident(e->token)) {
|
|
|
|
|
@@ -6252,7 +6856,7 @@ gb_internal CallArgumentData check_call_arguments_single_procedure(CheckerContex
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (proc_type != nullptr) {
|
|
|
|
|
if (pt != nullptr) {
|
|
|
|
|
if (pt->variadic) {
|
|
|
|
|
visited[pt->variadic_index] = true;
|
|
|
|
|
}
|
|
|
|
|
@@ -6293,14 +6897,45 @@ gb_internal CallArgumentData check_call_arguments_single_procedure(CheckerContex
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
Ast *ident = operand->expr;
|
|
|
|
|
while (ident->kind == Ast_SelectorExpr) {
|
|
|
|
|
Ast *s = ident->SelectorExpr.selector;
|
|
|
|
|
ident = s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto ordered_args = gb_alloc_item(permanent_allocator(), AstOrderedArgs);
|
|
|
|
|
ordered_args->positional = positional_args;
|
|
|
|
|
ordered_args->named = named_args;
|
|
|
|
|
Entity *e = entity_of_node(ident);
|
|
|
|
|
|
|
|
|
|
ce->ordered_args = ordered_args;
|
|
|
|
|
Array<Operand> operands = array_clone(heap_allocator(), positional_operands);
|
|
|
|
|
|
|
|
|
|
if (proc_type != nullptr) {
|
|
|
|
|
CallArgumentError err = check_call_arguments_internal(c, call, proc_type, e, operands, named_operands, CallArgumentMode_ShowErrors, &data);
|
|
|
|
|
gb_unused(err);
|
|
|
|
|
Entity *entity_to_use = data.gen_entity != nullptr ? data.gen_entity : e;
|
|
|
|
|
add_entity_use(c, ident, entity_to_use);
|
|
|
|
|
if (entity_to_use != nullptr) {
|
|
|
|
|
update_untyped_expr_type(c, operand->expr, entity_to_use->type, true);
|
|
|
|
|
}
|
|
|
|
|
if (data.gen_entity != nullptr) {
|
|
|
|
|
Entity *e = data.gen_entity;
|
|
|
|
|
DeclInfo *decl = data.gen_entity->decl_info;
|
|
|
|
|
CheckerContext ctx = *c;
|
|
|
|
|
ctx.scope = decl->scope;
|
|
|
|
|
ctx.decl = decl;
|
|
|
|
|
ctx.proc_name = e->token.string;
|
|
|
|
|
ctx.curr_proc_decl = decl;
|
|
|
|
|
ctx.curr_proc_sig = e->type;
|
|
|
|
|
|
|
|
|
|
GB_ASSERT(decl->proc_lit->kind == Ast_ProcLit);
|
|
|
|
|
bool ok = evaluate_where_clauses(&ctx, call, decl->scope, &decl->proc_lit->ProcLit.where_clauses, true);
|
|
|
|
|
decl->where_clauses_evaluated = true;
|
|
|
|
|
|
|
|
|
|
if (ok && (data.gen_entity->flags & EntityFlag_ProcBodyChecked) == 0) {
|
|
|
|
|
check_procedure_later(c->checker, e->file, e->token, decl, e->type, decl->proc_lit->ProcLit.body, decl->proc_lit->ProcLit.tags);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (pt != nullptr) {
|
|
|
|
|
data.result_type = pt->results;
|
|
|
|
|
}
|
|
|
|
|
return data;
|
|
|
|
|
@@ -6438,13 +7073,13 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (all_non_poly && (procs.count == 1 || c->pkg->name == "bug")) {
|
|
|
|
|
return check_call_arguments_single_procedure(c, operand, call);
|
|
|
|
|
if (all_non_poly) {
|
|
|
|
|
return check_call_arguments_new_and_improved(c, operand, call);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (operand->mode != Addressing_ProcGroup && is_type_proc(operand->type) && !is_type_polymorphic(operand->type)) {
|
|
|
|
|
return check_call_arguments_single_procedure(c, operand, call);
|
|
|
|
|
return check_call_arguments_new_and_improved(c, operand, call);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ast_node(ce, CallExpr, call);
|
|
|
|
|
@@ -6635,8 +7270,9 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op
|
|
|
|
|
lhs = populate_proc_parameter_list(c, e->type, &lhs_count, &is_variadic);
|
|
|
|
|
check_unpack_arguments(c, lhs, lhs_count, &operands, args, is_variadic ? UnpackFlag_IsVariadic : UnpackFlag_None);
|
|
|
|
|
|
|
|
|
|
Array<Operand> named_operands = {};
|
|
|
|
|
CallArgumentData data = {};
|
|
|
|
|
CallArgumentError err = call_checker(c, call, e->type, e, operands, CallArgumentMode_ShowErrors, &data);
|
|
|
|
|
CallArgumentError err = call_checker(c, call, e->type, e, operands, named_operands, CallArgumentMode_ShowErrors, &data);
|
|
|
|
|
if (err != CallArgumentError_None) {
|
|
|
|
|
// handle error
|
|
|
|
|
}
|
|
|
|
|
@@ -6740,7 +7376,8 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op
|
|
|
|
|
ctx.allow_polymorphic_types = is_type_polymorphic(pt);
|
|
|
|
|
ctx.hide_polymorphic_errors = true;
|
|
|
|
|
|
|
|
|
|
err = call_checker(&ctx, call, pt, p, operands, CallArgumentMode_NoErrors, &data);
|
|
|
|
|
Array<Operand> named_operands = {};
|
|
|
|
|
err = call_checker(&ctx, call, pt, p, operands, named_operands, CallArgumentMode_NoErrors, &data);
|
|
|
|
|
if (err != CallArgumentError_None) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
@@ -6910,9 +7547,11 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op
|
|
|
|
|
Entity *e = proc_entities[valids[0].index];
|
|
|
|
|
GB_ASSERT(e != nullptr);
|
|
|
|
|
|
|
|
|
|
Array<Operand> named_operands = {};
|
|
|
|
|
|
|
|
|
|
proc_type = e->type;
|
|
|
|
|
CallArgumentData data = {};
|
|
|
|
|
CallArgumentError err = call_checker(c, call, proc_type, e, operands, CallArgumentMode_ShowErrors, &data);
|
|
|
|
|
CallArgumentError err = call_checker(c, call, proc_type, e, operands, named_operands, CallArgumentMode_ShowErrors, &data);
|
|
|
|
|
gb_unused(err);
|
|
|
|
|
Entity *entity_to_use = data.gen_entity != nullptr ? data.gen_entity : e;
|
|
|
|
|
add_entity_use(c, ident, entity_to_use);
|
|
|
|
|
@@ -6949,9 +7588,10 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op
|
|
|
|
|
|
|
|
|
|
Entity *e = entity_of_node(ident);
|
|
|
|
|
|
|
|
|
|
Array<Operand> named_operands = {};
|
|
|
|
|
|
|
|
|
|
CallArgumentData data = {};
|
|
|
|
|
CallArgumentError err = call_checker(c, call, proc_type, e, operands, CallArgumentMode_ShowErrors, &data);
|
|
|
|
|
CallArgumentError err = call_checker(c, call, proc_type, e, operands, named_operands, CallArgumentMode_ShowErrors, &data);
|
|
|
|
|
gb_unused(err);
|
|
|
|
|
Entity *entity_to_use = data.gen_entity != nullptr ? data.gen_entity : e;
|
|
|
|
|
add_entity_use(c, ident, entity_to_use);
|
|
|
|
|
|