|
@@ -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, Array<Operand> const &named_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> positional_operands, Array<Operand> const &named_operands, CallArgumentErrorMode show_error_mode, CallArgumentData *data)
|
|
typedef CALL_ARGUMENT_CHECKER(CallArgumentCheckerType);
|
|
typedef CALL_ARGUMENT_CHECKER(CallArgumentCheckerType);
|
|
|
|
|
|
|
|
|
|
@@ -5351,77 +5351,280 @@ gb_internal CALL_ARGUMENT_CHECKER(check_call_arguments_internal) {
|
|
i64 score = 0;
|
|
i64 score = 0;
|
|
bool show_error = show_error_mode == CallArgumentMode_ShowErrors;
|
|
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);
|
|
|
|
|
|
+ Type *final_proc_type = proc_type;
|
|
|
|
+ Entity *gen_entity = nullptr;
|
|
|
|
+
|
|
|
|
+ if (vari_expand && !variadic) {
|
|
|
|
+ if (show_error) {
|
|
|
|
+ error(ce->ellipsis,
|
|
|
|
+ "Cannot use '..' in call to a non-variadic procedure: '%.*s'",
|
|
|
|
+ LIT(ce->proc->Ident.token.string));
|
|
|
|
+ }
|
|
|
|
+ err = CallArgumentError_NonVariadicExpand;
|
|
|
|
+ } else if (vari_expand && pt->c_vararg) {
|
|
|
|
+ if (show_error) {
|
|
|
|
+ error(ce->ellipsis,
|
|
|
|
+ "Cannot use '..' in call to a '#c_vararg' variadic procedure: '%.*s'",
|
|
|
|
+ LIT(ce->proc->Ident.token.string));
|
|
|
|
+ }
|
|
|
|
+ err = CallArgumentError_NonVariadicExpand;
|
|
|
|
+ }
|
|
|
|
|
|
if (ce->split_args) {
|
|
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];
|
|
|
|
|
|
+ auto ordered_operands = array_make<Operand>(temporary_allocator(), pt->param_count);
|
|
|
|
+ auto visited = slice_make<bool>(temporary_allocator(), pt->param_count);
|
|
|
|
|
|
- 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);
|
|
|
|
|
|
+ isize positional_operand_count = positional_operands.count;
|
|
|
|
+ if (variadic) {
|
|
|
|
+ positional_operand_count = gb_min(positional_operands.count, pt->variadic_index);
|
|
|
|
+ } else if (positional_operand_count > pt->param_count) {
|
|
|
|
+ err = CallArgumentError_TooManyArguments;
|
|
|
|
+ char const *err_fmt = "Too many arguments for '%s', expected %td arguments, got %td";
|
|
|
|
+ if (show_error) {
|
|
|
|
+ gbString proc_str = expr_to_string(ce->proc);
|
|
|
|
+ defer (gb_string_free(proc_str));
|
|
|
|
+ error(call, err_fmt, proc_str, param_count_excluding_defaults, positional_operands.count);
|
|
|
|
+ }
|
|
|
|
+ return err;
|
|
|
|
+ }
|
|
|
|
+ positional_operand_count = gb_min(positional_operand_count, pt->param_count);
|
|
|
|
+
|
|
|
|
+ for (isize i = 0; i < positional_operand_count; i++) {
|
|
|
|
+ ordered_operands[i] = positional_operands[i];
|
|
|
|
+ visited[i] = true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ auto variadic_operands = slice(slice_from_array(positional_operands), positional_operand_count, positional_operands.count);
|
|
|
|
+
|
|
|
|
+ if (named_operands.count != 0) {
|
|
|
|
+ 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;
|
|
}
|
|
}
|
|
- 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;
|
|
|
|
+ }
|
|
|
|
+ Entity *e = pt->params->Tuple.variables[param_index];
|
|
|
|
+
|
|
|
|
+ check_assignment(c, &operand, e->type, str_lit("named argument"));
|
|
|
|
+
|
|
|
|
+ visited[param_index] = true;
|
|
|
|
+ ordered_operands[param_index] = operand;
|
|
|
|
+
|
|
|
|
+ err = CallArgumentError_DuplicateParameter;
|
|
}
|
|
}
|
|
- String name = fv->field->Ident.token.string;
|
|
|
|
- isize param_index = lookup_procedure_parameter(pt, name);
|
|
|
|
- if (param_index < 0) {
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (variadic) {
|
|
|
|
+ if (visited[pt->variadic_index] &&
|
|
|
|
+ positional_operand_count < positional_operands.count) {
|
|
if (show_error) {
|
|
if (show_error) {
|
|
- error(arg, "No parameter named '%.*s' for this procedure type", LIT(name));
|
|
|
|
|
|
+ String name = pt->params->Tuple.variables[pt->variadic_index]->token.string;
|
|
|
|
+ error(call, "Variadic parameters already handled with a named argument '%.*s' in procedure call", LIT(name));
|
|
}
|
|
}
|
|
- err = CallArgumentError_ParameterNotFound;
|
|
|
|
- continue;
|
|
|
|
|
|
+ err = CallArgumentError_DuplicateParameter;
|
|
|
|
+ } else {
|
|
|
|
+ visited[pt->variadic_index] = true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ for (Operand const &o : ordered_operands) {
|
|
|
|
+ if (o.mode != Addressing_Invalid) {
|
|
|
|
+ check_no_copy_assignment(o, str_lit("procedure call expression"));
|
|
}
|
|
}
|
|
- if (visited[param_index]) {
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for (isize i = 0; i < pt->param_count; i++) {
|
|
|
|
+ if (!visited[i]) {
|
|
|
|
+ Entity *e = pt->params->Tuple.variables[i];
|
|
|
|
+ if (is_blank_ident(e->token)) {
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ if (e->kind == Entity_Variable) {
|
|
|
|
+ if (e->Variable.param_value.kind != ParameterValue_Invalid) {
|
|
|
|
+ score += assign_score_function(1);
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
if (show_error) {
|
|
if (show_error) {
|
|
- error(arg, "Duplicate parameter '%.*s' in procedure call", LIT(name));
|
|
|
|
|
|
+ if (e->kind == Entity_TypeName) {
|
|
|
|
+ error(call, "Type parameter '%.*s' is missing in procedure call",
|
|
|
|
+ LIT(e->token.string));
|
|
|
|
+ } else if (e->kind == Entity_Constant && e->Constant.value.kind != ExactValue_Invalid) {
|
|
|
|
+ // Ignore
|
|
|
|
+ } else {
|
|
|
|
+ gbString str = type_to_string(e->type);
|
|
|
|
+ error(call, "Parameter '%.*s' of type '%s' is missing in procedure call",
|
|
|
|
+ LIT(e->token.string), str);
|
|
|
|
+ gb_string_free(str);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
- err = CallArgumentError_DuplicateParameter;
|
|
|
|
- continue;
|
|
|
|
|
|
+ err = CallArgumentError_ParameterMissing;
|
|
}
|
|
}
|
|
|
|
+ }
|
|
|
|
|
|
- visited[param_index] = true;
|
|
|
|
- ordered_operands[param_index] = operand;
|
|
|
|
|
|
+ if (ordered_operands.count == 0 && param_count_excluding_defaults == 0) {
|
|
|
|
+ err = CallArgumentError_None;
|
|
|
|
|
|
- err = CallArgumentError_DuplicateParameter;
|
|
|
|
|
|
+ if (variadic) {
|
|
|
|
+ GB_ASSERT(pt->params != nullptr && pt->params->Tuple.variables.count > 0);
|
|
|
|
+ Type *t = pt->params->Tuple.variables[0]->type;
|
|
|
|
+ if (is_type_polymorphic(t)) {
|
|
|
|
+ error(call, "Ambiguous call to a polymorphic variadic procedure with no variadic input");
|
|
|
|
+ err = CallArgumentError_AmbiguousPolymorphicVariadic;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ if (pt->is_polymorphic && !pt->is_poly_specialized && err == CallArgumentError_None) {
|
|
|
|
+ PolyProcData poly_proc_data = {};
|
|
|
|
+ if (find_or_generate_polymorphic_procedure_from_parameters(c, entity, &ordered_operands, call, &poly_proc_data)) {
|
|
|
|
+ gen_entity = poly_proc_data.gen_entity;
|
|
|
|
+ Type *gept = base_type(gen_entity->type);
|
|
|
|
+ GB_ASSERT(is_type_proc(gept));
|
|
|
|
+ proc_type = gept;
|
|
|
|
+ pt = &gept->Proc;
|
|
|
|
+ } else {
|
|
|
|
+ err = CallArgumentError_WrongTypes;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for (isize i = 0; i < pt->param_count; i++) {
|
|
|
|
+ Entity *e = pt->params->Tuple.variables[i];
|
|
|
|
+ Operand *o = &ordered_operands[i];
|
|
|
|
+ bool param_is_variadic = pt->variadic && pt->variadic_index == i;
|
|
|
|
+
|
|
|
|
+ if (o->mode == Addressing_Invalid) {
|
|
|
|
+ if (param_is_variadic) {
|
|
|
|
+ Type *slice = e->type;
|
|
|
|
+ GB_ASSERT(is_type_slice(slice));
|
|
|
|
+ Type *elem = base_type(slice)->Slice.elem;
|
|
|
|
+
|
|
|
|
+ if (variadic_operands.count == 0) {
|
|
|
|
+ if (is_type_polymorphic(elem)) {
|
|
|
|
+ error(call, "Ambiguous call to a polymorphic variadic procedure with no variadic input");
|
|
|
|
+ err = CallArgumentError_AmbiguousPolymorphicVariadic;
|
|
|
|
+ return err;
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ if (vari_expand) {
|
|
|
|
+ GB_ASSERT(variadic_operands.count == 1);
|
|
|
|
+ check_assignment(c, &variadic_operands[0], slice, str_lit("variadic expanded argument"));
|
|
|
|
+ } else {
|
|
|
|
+ for (Operand &vo : variadic_operands) {
|
|
|
|
+ check_assignment(c, &vo, elem, str_lit("variadic argument"));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (e->kind == Entity_TypeName) {
|
|
|
|
+ GB_ASSERT(pt->is_polymorphic);
|
|
|
|
+ if (o->mode != Addressing_Type) {
|
|
|
|
+ if (show_error) {
|
|
|
|
+ error(o->expr, "Expected a type for the argument '%.*s'", LIT(e->token.string));
|
|
|
|
+ }
|
|
|
|
+ err = CallArgumentError_WrongTypes;
|
|
|
|
+ }
|
|
|
|
+ if (are_types_identical(e->type, o->type)) {
|
|
|
|
+ score += assign_score_function(1);
|
|
|
|
+ } else {
|
|
|
|
+ score += assign_score_function(MAXIMUM_TYPE_DISTANCE);
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ i64 s = 0;
|
|
|
|
+ if (!check_is_assignable_to_with_score(c, o, e->type, &s, param_is_variadic)) {
|
|
|
|
+ bool ok = false;
|
|
|
|
+ if (ok) {
|
|
|
|
+ s = assign_score_function(MAXIMUM_TYPE_DISTANCE);
|
|
|
|
+ } else {
|
|
|
|
+ if (show_error) {
|
|
|
|
+ check_assignment(c, o, e->type, str_lit("procedure argument"));
|
|
|
|
+ }
|
|
|
|
+ err = CallArgumentError_WrongTypes;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (e->flags & EntityFlag_ConstInput) {
|
|
|
|
+ if (o->mode != Addressing_Constant) {
|
|
|
|
+ if (show_error) {
|
|
|
|
+ error(o->expr, "Expected a constant value for the argument '%.*s'", LIT(e->token.string));
|
|
|
|
+ }
|
|
|
|
+ err = CallArgumentError_NoneConstantParameter;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ } else if (show_error) {
|
|
|
|
+ check_assignment(c, o, e->type, str_lit("procedure argument"));
|
|
|
|
+ }
|
|
|
|
+ score += s;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (o->mode == Addressing_Type && is_type_typeid(e->type)) {
|
|
|
|
+ add_type_info_type(c, o->type);
|
|
|
|
+ add_type_and_value(c, o->expr, Addressing_Value, e->type, exact_value_typeid(o->type));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
- if (err) {
|
|
|
|
- return err;
|
|
|
|
|
|
+
|
|
|
|
+ if (data) {
|
|
|
|
+ data->score = score;
|
|
|
|
+ data->result_type = final_proc_type->Proc.results;
|
|
|
|
+ data->gen_entity = gen_entity;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ Ast *proc_lit = nullptr;
|
|
|
|
+ if (ce->proc->tav.value.kind == ExactValue_Procedure) {
|
|
|
|
+ Ast *vp = unparen_expr(ce->proc->tav.value.value_procedure);
|
|
|
|
+ if (vp && vp->kind == Ast_ProcLit) {
|
|
|
|
+ proc_lit = vp;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (proc_lit == nullptr) {
|
|
|
|
+ add_type_and_value(c, ce->proc, Addressing_Value, final_proc_type, {});
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ return err;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (err) {
|
|
|
|
+ return err;
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+ auto operands = positional_operands;
|
|
TypeTuple *param_tuple = nullptr;
|
|
TypeTuple *param_tuple = nullptr;
|
|
if (pt->params != nullptr) {
|
|
if (pt->params != nullptr) {
|
|
param_tuple = &pt->params->Tuple;
|
|
param_tuple = &pt->params->Tuple;
|
|
}
|
|
}
|
|
|
|
|
|
-
|
|
|
|
- Type *final_proc_type = proc_type;
|
|
|
|
- Entity *gen_entity = nullptr;
|
|
|
|
-
|
|
|
|
- if (vari_expand && !variadic) {
|
|
|
|
- if (show_error) {
|
|
|
|
- error(ce->ellipsis,
|
|
|
|
- "Cannot use '..' in call to a non-variadic procedure: '%.*s'",
|
|
|
|
- LIT(ce->proc->Ident.token.string));
|
|
|
|
- }
|
|
|
|
- err = CallArgumentError_NonVariadicExpand;
|
|
|
|
- } else if (vari_expand && pt->c_vararg) {
|
|
|
|
- if (show_error) {
|
|
|
|
- error(ce->ellipsis,
|
|
|
|
- "Cannot use '..' in call to a '#c_vararg' variadic procedure: '%.*s'",
|
|
|
|
- LIT(ce->proc->Ident.token.string));
|
|
|
|
- }
|
|
|
|
- err = CallArgumentError_NonVariadicExpand;
|
|
|
|
- } else if (operands.count == 0 && param_count_excluding_defaults == 0) {
|
|
|
|
|
|
+ if (operands.count == 0 && param_count_excluding_defaults == 0) {
|
|
err = CallArgumentError_None;
|
|
err = CallArgumentError_None;
|
|
|
|
|
|
if (variadic) {
|
|
if (variadic) {
|
|
@@ -5641,6 +5844,7 @@ gb_internal bool is_call_expr_field_value(AstCallExpr *ce) {
|
|
}
|
|
}
|
|
|
|
|
|
gb_internal CALL_ARGUMENT_CHECKER(check_named_call_arguments) {
|
|
gb_internal CALL_ARGUMENT_CHECKER(check_named_call_arguments) {
|
|
|
|
+ auto operands = positional_operands;
|
|
ast_node(ce, CallExpr, call);
|
|
ast_node(ce, CallExpr, call);
|
|
GB_ASSERT(is_type_proc(proc_type));
|
|
GB_ASSERT(is_type_proc(proc_type));
|
|
proc_type = base_type(proc_type);
|
|
proc_type = base_type(proc_type);
|
|
@@ -6705,37 +6909,26 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved(CheckerContex
|
|
return data;
|
|
return data;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ // if (pt->variadic) {
|
|
|
|
+ // isize param_index = pt->variadic_index;
|
|
|
|
|
|
- for_array(i, positional_operands) {
|
|
|
|
- Operand &o = positional_operands[i];
|
|
|
|
- isize param_index = i;
|
|
|
|
|
|
+ // Entity *e = pt->params->Tuple.variables[param_index];
|
|
|
|
+ // GB_ASSERT(e->kind == Entity_Variable);
|
|
|
|
+ // GB_ASSERT(e->flags & EntityFlag_Ellipsis);
|
|
|
|
+ // GB_ASSERT(is_type_slice(e->type));
|
|
|
|
|
|
- Entity *e = pt->params->Tuple.variables[param_index];
|
|
|
|
- GB_ASSERT(e->kind == Entity_Variable);
|
|
|
|
-
|
|
|
|
- check_assignment(c, &o, e->type, str_lit("procedure call expression"));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (pt->variadic) {
|
|
|
|
- isize param_index = pt->variadic_index;
|
|
|
|
-
|
|
|
|
- Entity *e = pt->params->Tuple.variables[param_index];
|
|
|
|
- GB_ASSERT(e->kind == Entity_Variable);
|
|
|
|
- GB_ASSERT(e->flags & EntityFlag_Ellipsis);
|
|
|
|
- GB_ASSERT(is_type_slice(e->type));
|
|
|
|
-
|
|
|
|
- if (vari_expand) {
|
|
|
|
- if (variadic_operands.count != 0) {
|
|
|
|
- GB_ASSERT(variadic_operands.count == 1);
|
|
|
|
- check_assignment(c, &variadic_operands[0], e->type, str_lit("procedure call expression"));
|
|
|
|
- }
|
|
|
|
- } else {
|
|
|
|
- Type *elem = e->type->Slice.elem;
|
|
|
|
- for (Operand &o : variadic_operands) {
|
|
|
|
- check_assignment(c, &o, elem, str_lit("procedure call expression"));
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ // if (vari_expand) {
|
|
|
|
+ // if (variadic_operands.count != 0) {
|
|
|
|
+ // GB_ASSERT(variadic_operands.count == 1);
|
|
|
|
+ // check_assignment(c, &variadic_operands[0], e->type, str_lit("procedure call expression"));
|
|
|
|
+ // }
|
|
|
|
+ // } else {
|
|
|
|
+ // Type *elem = e->type->Slice.elem;
|
|
|
|
+ // for (Operand &o : variadic_operands) {
|
|
|
|
+ // check_assignment(c, &o, elem, str_lit("procedure call expression"));
|
|
|
|
+ // }
|
|
|
|
+ // }
|
|
|
|
+ // }
|
|
|
|
|
|
array_resize(&positional_operands, pt->param_count);
|
|
array_resize(&positional_operands, pt->param_count);
|
|
|
|
|
|
@@ -6770,68 +6963,6 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved(CheckerContex
|
|
array_add(&named_parameters, NamedParameter{name, fv->value});
|
|
array_add(&named_parameters, NamedParameter{name, fv->value});
|
|
}
|
|
}
|
|
|
|
|
|
- StringMap<Type *> type_hint_map = {}; // Key: String
|
|
|
|
- string_map_init(&type_hint_map, 2*named_args.count);
|
|
|
|
- defer (string_map_destroy(&type_hint_map));
|
|
|
|
-
|
|
|
|
- if (pt != nullptr) {
|
|
|
|
- TypeTuple *param_tuple = &pt->params->Tuple;
|
|
|
|
- for (Entity *e : param_tuple->variables) {
|
|
|
|
- if (is_blank_ident(e->token)) {
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
- string_map_set(&type_hint_map, e->token.string, e->type);
|
|
|
|
- }
|
|
|
|
- } else if (operand->mode == Addressing_ProcGroup) {
|
|
|
|
- Array<Entity *> procs = proc_group_entities(c, *operand);
|
|
|
|
- for (Entity *proc : procs) {
|
|
|
|
- Type *proc_type = base_type(proc->type);
|
|
|
|
- if (is_type_proc(proc_type)) {
|
|
|
|
- TypeProc *pt = &proc_type->Proc;
|
|
|
|
- TypeTuple *param_tuple = nullptr;
|
|
|
|
- if (pt->params != nullptr) {
|
|
|
|
- param_tuple = &pt->params->Tuple;
|
|
|
|
- }
|
|
|
|
- if (param_tuple == nullptr) {
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
- for (Entity *e : param_tuple->variables) {
|
|
|
|
- if (is_blank_ident(e->token)) {
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
- StringHashKey key = string_hash_string(e->token.string);
|
|
|
|
- Type **found = string_map_get(&type_hint_map, key);
|
|
|
|
- if (found) {
|
|
|
|
- Type *t = *found;
|
|
|
|
- if (t == nullptr) {
|
|
|
|
- // NOTE(bill): Ambiguous named parameter across all types
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
- if (are_types_identical(t, e->type)) {
|
|
|
|
- // NOTE(bill): No need to set again
|
|
|
|
- } else {
|
|
|
|
- // NOTE(bill): Ambiguous named parameter across all types so set it to a nullptr
|
|
|
|
- string_map_set(&type_hint_map, key, cast(Type *)nullptr);
|
|
|
|
- }
|
|
|
|
- } else {
|
|
|
|
- string_map_set(&type_hint_map, key, e->type);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- for (NamedParameter ¶m : named_parameters) {
|
|
|
|
- Type *type_hint = nullptr;
|
|
|
|
- if (Type **found = string_map_get(&type_hint_map, param.key)) {
|
|
|
|
- type_hint = *found;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- Operand operand = {};
|
|
|
|
- check_expr_or_type(c, &operand, param.value, type_hint);
|
|
|
|
- array_add(&named_operands, operand);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
for (NamedParameter const ¶m : named_parameters) {
|
|
for (NamedParameter const ¶m : named_parameters) {
|
|
isize param_index = lookup_procedure_parameter(pt, param.key);
|
|
isize param_index = lookup_procedure_parameter(pt, param.key);
|
|
if (param_index < 0) {
|
|
if (param_index < 0) {
|
|
@@ -6856,11 +6987,10 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved(CheckerContex
|
|
any_failure = true;
|
|
any_failure = true;
|
|
}
|
|
}
|
|
|
|
|
|
- check_assignment(c, &o, e->type, str_lit("procedure call expression"));
|
|
|
|
-
|
|
|
|
if (!prev_visited) {
|
|
if (!prev_visited) {
|
|
positional_operands[param_index] = o;
|
|
positional_operands[param_index] = o;
|
|
}
|
|
}
|
|
|
|
+ array_add(&named_operands, o);
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
@@ -6891,17 +7021,6 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved(CheckerContex
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- for (Operand const &o : positional_operands) {
|
|
|
|
- check_no_copy_assignment(o, str_lit("procedure call expression"));
|
|
|
|
- }
|
|
|
|
- for (Operand const &o : variadic_operands) {
|
|
|
|
- check_no_copy_assignment(o, str_lit("procedure call expression"));
|
|
|
|
- }
|
|
|
|
- for (Operand const &o : named_operands) {
|
|
|
|
- check_no_copy_assignment(o, str_lit("procedure call expression"));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-
|
|
|
|
if (any_failure) {
|
|
if (any_failure) {
|
|
return data;
|
|
return data;
|
|
}
|
|
}
|
|
@@ -6917,7 +7036,7 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved(CheckerContex
|
|
|
|
|
|
Array<Operand> operands = array_clone(heap_allocator(), positional_operands);
|
|
Array<Operand> operands = array_clone(heap_allocator(), positional_operands);
|
|
|
|
|
|
- CallArgumentError err = check_call_arguments_internal(c, call, proc_type, e, operands, named_operands, CallArgumentMode_ShowErrors, &data);
|
|
|
|
|
|
+ CallArgumentError err = check_call_arguments_internal(c, call, proc_type, e, operands, {}, CallArgumentMode_ShowErrors, &data);
|
|
gb_unused(err);
|
|
gb_unused(err);
|
|
Entity *entity_to_use = data.gen_entity != nullptr ? data.gen_entity : e;
|
|
Entity *entity_to_use = data.gen_entity != nullptr ? data.gen_entity : e;
|
|
add_entity_use(c, ident, entity_to_use);
|
|
add_entity_use(c, ident, entity_to_use);
|
|
@@ -6948,127 +7067,6 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved(CheckerContex
|
|
data.result_type = pt->results;
|
|
data.result_type = pt->results;
|
|
}
|
|
}
|
|
return data;
|
|
return data;
|
|
-#if 0
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- auto visited = slice_make<bool>(temporary_allocator(), pt->param_count);
|
|
|
|
- auto ordered_values = slice_make<ParameterValue>(temporary_allocator(), pt->param_count);
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- for_array(i, ce->args) {
|
|
|
|
- Ast *arg = ce->args[i];
|
|
|
|
-
|
|
|
|
- isize param_index = i;
|
|
|
|
- String param_name = {};
|
|
|
|
-
|
|
|
|
- if (arg->kind == Ast_FieldValue) {
|
|
|
|
- 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);
|
|
|
|
- any_failure = true;
|
|
|
|
- gb_string_free(expr_str);
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
- param_name = fv->field->Ident.token.string;
|
|
|
|
- param_index = lookup_procedure_parameter(pt, param_name);
|
|
|
|
- if (param_index < 0) {
|
|
|
|
- error(arg, "No parameter named '%.*s' for this procedure type", LIT(param_name));
|
|
|
|
- any_failure = true;
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
- arg = fv->value;
|
|
|
|
- } else {
|
|
|
|
- if (param_index >= pt->param_count) {
|
|
|
|
- error(arg, "Too many parameters in procedure call, expected a maximum of %td, got %td", pt->param_count, ce->args.count);
|
|
|
|
- any_failure = true;
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- param_name = pt->params->Tuple.variables[param_index]->token.string;
|
|
|
|
- }
|
|
|
|
- if (visited[param_index]) {
|
|
|
|
- error(arg, "Duplicate parameter '%.*s' in procedure call", LIT(param_name));
|
|
|
|
- any_failure = true;
|
|
|
|
- } else {
|
|
|
|
- ParameterValue value = {};
|
|
|
|
- value.kind = ParameterValue_Value;
|
|
|
|
- value.original_ast_expr = arg;
|
|
|
|
- value.ast_value = arg;
|
|
|
|
- ordered_values[param_index] = value;
|
|
|
|
- }
|
|
|
|
- visited[param_index] = true;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- for (isize i = 0; i < pt->param_count; i++) {
|
|
|
|
- if (!visited[i]) {
|
|
|
|
- Entity *e = pt->params->Tuple.variables[i];
|
|
|
|
- if (e->kind == Entity_Variable &&
|
|
|
|
- has_parameter_value(e->Variable.param_value)) {
|
|
|
|
- ordered_values[i] = e->Variable.param_value;
|
|
|
|
- visited[i] = true;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- for (isize i = 0; i < visited.count; i++) {
|
|
|
|
- if (!visited[i]) {
|
|
|
|
- Entity *e = pt->params->Tuple.variables[i];
|
|
|
|
- gbString t = type_to_string(e->type);
|
|
|
|
- defer (gb_string_free(t));
|
|
|
|
- if (is_blank_ident(e->token)) {
|
|
|
|
- error(call, "Missing parameter of type '%s' at index %td", t, i);
|
|
|
|
- } else {
|
|
|
|
- error(call, "Missing parameter '%.*s' of type '%s'", LIT(e->token.string), t, i);
|
|
|
|
- }
|
|
|
|
- return data;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- */
|
|
|
|
- if (any_failure) {
|
|
|
|
- return data;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- Array<Operand> operands = {};
|
|
|
|
- defer (array_free(&operands));
|
|
|
|
-
|
|
|
|
- Ast *ident = unparen_expr(operand->expr);
|
|
|
|
- while (ident->kind == Ast_SelectorExpr) {
|
|
|
|
- Ast *s = ident->SelectorExpr.selector;
|
|
|
|
- ident = unparen_expr(s);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- Entity *e = entity_of_node(ident);
|
|
|
|
-
|
|
|
|
- CallArgumentError err = check_call_arguments_internal(c, call, proc_type, e, 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;
|
|
|
|
-#endif
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|