mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 15:48:51 +00:00
Correct purely named argument handling
This commit is contained in:
+97
-84
@@ -676,6 +676,11 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case Basic_UntypedString:
|
||||||
|
if (is_type_string(dst)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case Basic_UntypedFloat:
|
case Basic_UntypedFloat:
|
||||||
if (is_type_float(dst)) {
|
if (is_type_float(dst)) {
|
||||||
return 1;
|
return 1;
|
||||||
@@ -701,33 +706,48 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (src->kind == Type_Basic) {
|
if (src->kind == Type_Basic) {
|
||||||
|
i64 score = -1;
|
||||||
switch (src->Basic.kind) {
|
switch (src->Basic.kind) {
|
||||||
case Basic_UntypedRune:
|
case Basic_UntypedRune:
|
||||||
if (is_type_integer(dst) || is_type_rune(dst)) {
|
if (is_type_integer(dst) || is_type_rune(dst)) {
|
||||||
if (is_type_typed(type)) {
|
score = 1;
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
return -1;
|
break;
|
||||||
case Basic_UntypedBool:
|
case Basic_UntypedInteger:
|
||||||
if (is_type_boolean(dst)) {
|
if (is_type_integer(dst) || is_type_rune(dst)) {
|
||||||
if (is_type_typed(type)) {
|
score = 1;
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
return -1;
|
break;
|
||||||
case Basic_UntypedString:
|
case Basic_UntypedString:
|
||||||
if (is_type_string(dst) || is_type_cstring(dst)) {
|
if (is_type_string(dst)) {
|
||||||
if (is_type_typed(type)) {
|
score = 1;
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
return -1;
|
break;
|
||||||
|
case Basic_UntypedFloat:
|
||||||
|
if (is_type_float(dst)) {
|
||||||
|
score = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Basic_UntypedComplex:
|
||||||
|
if (is_type_complex(dst)) {
|
||||||
|
score = 1;
|
||||||
|
}
|
||||||
|
if (is_type_quaternion(dst)) {
|
||||||
|
score = 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Basic_UntypedQuaternion:
|
||||||
|
if (is_type_quaternion(dst)) {
|
||||||
|
score = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
if (score > 0) {
|
||||||
|
if (is_type_typed(dst)) {
|
||||||
|
score += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return score;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5447,14 +5467,9 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A
|
|||||||
err = CallArgumentError_DuplicateParameter;
|
err = CallArgumentError_DuplicateParameter;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Entity *e = pt->params->Tuple.variables[param_index];
|
|
||||||
|
|
||||||
check_assignment(c, &operand, e->type, str_lit("named argument"));
|
|
||||||
|
|
||||||
visited[param_index] = true;
|
visited[param_index] = true;
|
||||||
ordered_operands[param_index] = operand;
|
ordered_operands[param_index] = operand;
|
||||||
|
|
||||||
err = CallArgumentError_DuplicateParameter;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5469,7 +5484,7 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A
|
|||||||
error(call, "Variadic parameters already handled with a named argument '%.*s' in procedure call", LIT(name));
|
error(call, "Variadic parameters already handled with a named argument '%.*s' in procedure call", LIT(name));
|
||||||
}
|
}
|
||||||
err = CallArgumentError_DuplicateParameter;
|
err = CallArgumentError_DuplicateParameter;
|
||||||
} else {
|
} else if (!visited[pt->variadic_index]) {
|
||||||
visited[pt->variadic_index] = true;
|
visited[pt->variadic_index] = true;
|
||||||
|
|
||||||
Operand *variadic_operand = &ordered_operands[pt->variadic_index];
|
Operand *variadic_operand = &ordered_operands[pt->variadic_index];
|
||||||
@@ -5548,6 +5563,52 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto eval_param_and_score = [](CheckerContext *c, Operand *o, Type *param_type, CallArgumentError &err, bool param_is_variadic, Entity *e, bool show_error) -> i64 {
|
||||||
|
i64 s = 0;
|
||||||
|
if (!check_is_assignable_to_with_score(c, o, param_type, &s, param_is_variadic)) {
|
||||||
|
bool ok = false;
|
||||||
|
if (e && e->flags & EntityFlag_AnyInt) {
|
||||||
|
if (is_type_integer(param_type)) {
|
||||||
|
ok = check_is_castable_to(c, o, param_type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ok) {
|
||||||
|
s = assign_score_function(MAXIMUM_TYPE_DISTANCE);
|
||||||
|
} else {
|
||||||
|
if (show_error) {
|
||||||
|
check_assignment(c, o, param_type, str_lit("procedure argument"));
|
||||||
|
}
|
||||||
|
err = CallArgumentError_WrongTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (show_error) {
|
||||||
|
check_assignment(c, o, param_type, str_lit("procedure argument"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e && 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!err && is_type_any(param_type)) {
|
||||||
|
add_type_info_type(c, o->type);
|
||||||
|
}
|
||||||
|
if (o->mode == Addressing_Type && is_type_typeid(param_type)) {
|
||||||
|
add_type_info_type(c, o->type);
|
||||||
|
add_type_and_value(c, o->expr, Addressing_Value, param_type, exact_value_typeid(o->type));
|
||||||
|
} else if (show_error && is_type_untyped(o->type)) {
|
||||||
|
update_untyped_expr_type(c, o->expr, param_type, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
if (ordered_operands.count == 0 && param_count_excluding_defaults == 0) {
|
if (ordered_operands.count == 0 && param_count_excluding_defaults == 0) {
|
||||||
err = CallArgumentError_None;
|
err = CallArgumentError_None;
|
||||||
|
|
||||||
@@ -5555,7 +5616,9 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A
|
|||||||
GB_ASSERT(pt->params != nullptr && pt->params->Tuple.variables.count > 0);
|
GB_ASSERT(pt->params != nullptr && pt->params->Tuple.variables.count > 0);
|
||||||
Type *t = pt->params->Tuple.variables[0]->type;
|
Type *t = pt->params->Tuple.variables[0]->type;
|
||||||
if (is_type_polymorphic(t)) {
|
if (is_type_polymorphic(t)) {
|
||||||
error(call, "Ambiguous call to a polymorphic variadic procedure with no variadic input");
|
if (show_error) {
|
||||||
|
error(call, "Ambiguous call to a polymorphic variadic procedure with no variadic input");
|
||||||
|
}
|
||||||
err = CallArgumentError_AmbiguousPolymorphicVariadic;
|
err = CallArgumentError_AmbiguousPolymorphicVariadic;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5596,46 +5659,14 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A
|
|||||||
} else {
|
} else {
|
||||||
score += assign_score_function(MAXIMUM_TYPE_DISTANCE);
|
score += assign_score_function(MAXIMUM_TYPE_DISTANCE);
|
||||||
}
|
}
|
||||||
} else {
|
continue;
|
||||||
i64 s = 0;
|
|
||||||
if (!check_is_assignable_to_with_score(c, o, e->type, &s, param_is_variadic)) {
|
|
||||||
bool ok = false;
|
|
||||||
if (e->flags & EntityFlag_AnyInt) {
|
|
||||||
if (is_type_integer(e->type)) {
|
|
||||||
ok = check_is_castable_to(c, o, e->type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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"));
|
|
||||||
}
|
|
||||||
if (!param_is_variadic) {
|
|
||||||
score += s;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (o->mode == Addressing_Type && is_type_typeid(e->type)) {
|
if (param_is_variadic) {
|
||||||
add_type_info_type(c, o->type);
|
continue;
|
||||||
add_type_and_value(c, o->expr, Addressing_Value, e->type, exact_value_typeid(o->type));
|
|
||||||
} else if (show_error && is_type_untyped(o->type)) {
|
|
||||||
update_untyped_expr_type(c, o->expr, e->type, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
score += eval_param_and_score(c, o, e->type, err, param_is_variadic, e, show_error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5651,12 +5682,12 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A
|
|||||||
}
|
}
|
||||||
|
|
||||||
for_array(operand_index, variadic_operands) {
|
for_array(operand_index, variadic_operands) {
|
||||||
Operand &o = variadic_operands[operand_index];
|
Operand *o = &variadic_operands[operand_index];
|
||||||
if (vari_expand) {
|
if (vari_expand) {
|
||||||
t = slice;
|
t = slice;
|
||||||
if (operand_index > 0) {
|
if (operand_index > 0) {
|
||||||
if (show_error) {
|
if (show_error) {
|
||||||
error(o.expr, "'..' in a variadic procedure can only have one variadic argument at the end");
|
error(o->expr, "'..' in a variadic procedure can only have one variadic argument at the end");
|
||||||
}
|
}
|
||||||
if (data) {
|
if (data) {
|
||||||
data->score = score;
|
data->score = score;
|
||||||
@@ -5666,25 +5697,7 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A
|
|||||||
return CallArgumentError_MultipleVariadicExpand;
|
return CallArgumentError_MultipleVariadicExpand;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
i64 s = 0;
|
score += eval_param_and_score(c, o, t, err, true, nullptr, show_error);
|
||||||
if (!check_is_assignable_to_with_score(c, &o, t, &s, true)) {
|
|
||||||
if (show_error) {
|
|
||||||
check_assignment(c, &o, t, str_lit("variadic argument"));
|
|
||||||
}
|
|
||||||
err = CallArgumentError_WrongTypes;
|
|
||||||
} else if (show_error) {
|
|
||||||
check_assignment(c, &o, t, str_lit("variadic argument"));
|
|
||||||
}
|
|
||||||
score += s;
|
|
||||||
if (is_type_any(elem)) {
|
|
||||||
add_type_info_type(c, o.type);
|
|
||||||
}
|
|
||||||
if (o.mode == Addressing_Type && is_type_typeid(t)) {
|
|
||||||
add_type_info_type(c, o.type);
|
|
||||||
add_type_and_value(c, o.expr, Addressing_Value, t, exact_value_typeid(o.type));
|
|
||||||
} else if (show_error && is_type_untyped(o.type)) {
|
|
||||||
update_untyped_expr_type(c, o.expr, t, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-248
@@ -3336,253 +3336,7 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) {
|
|||||||
GB_ASSERT(proc_type_->kind == Type_Proc);
|
GB_ASSERT(proc_type_->kind == Type_Proc);
|
||||||
TypeProc *pt = &proc_type_->Proc;
|
TypeProc *pt = &proc_type_->Proc;
|
||||||
|
|
||||||
if (ce->split_args) {
|
GB_ASSERT(ce->split_args != nullptr);
|
||||||
return lb_build_call_expr_internal_with_arg_split_args(p, value, pt, expr, ce->split_args);
|
return lb_build_call_expr_internal_with_arg_split_args(p, value, pt, expr, ce->split_args);
|
||||||
}
|
|
||||||
|
|
||||||
if (is_call_expr_field_value(ce)) {
|
|
||||||
auto args = array_make<lbValue>(permanent_allocator(), pt->param_count);
|
|
||||||
|
|
||||||
for_array(arg_index, ce->args) {
|
|
||||||
Ast *arg = ce->args[arg_index];
|
|
||||||
ast_node(fv, FieldValue, arg);
|
|
||||||
GB_ASSERT(fv->field->kind == Ast_Ident);
|
|
||||||
String name = fv->field->Ident.token.string;
|
|
||||||
isize index = lookup_procedure_parameter(pt, name);
|
|
||||||
GB_ASSERT(index >= 0);
|
|
||||||
TypeAndValue tav = type_and_value_of_expr(fv->value);
|
|
||||||
if (tav.mode == Addressing_Type) {
|
|
||||||
args[index] = lb_const_nil(m, tav.type);
|
|
||||||
} else {
|
|
||||||
args[index] = lb_build_expr(p, fv->value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TypeTuple *params = &pt->params->Tuple;
|
|
||||||
for (isize i = 0; i < args.count; i++) {
|
|
||||||
Entity *e = params->variables[i];
|
|
||||||
if (e->kind == Entity_TypeName) {
|
|
||||||
args[i] = lb_const_nil(m, e->type);
|
|
||||||
} else if (e->kind == Entity_Constant) {
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
GB_ASSERT(e->kind == Entity_Variable);
|
|
||||||
if (args[i].value == nullptr) {
|
|
||||||
args[i] = lb_handle_param_value(p, e->type, e->Variable.param_value, ast_token(expr).pos);
|
|
||||||
} else if (is_type_typeid(e->type) && !is_type_typeid(args[i].type)) {
|
|
||||||
args[i] = lb_typeid(p->module, args[i].type);
|
|
||||||
} else {
|
|
||||||
args[i] = lb_emit_conv(p, args[i], e->type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (isize i = 0; i < args.count; i++) {
|
|
||||||
Entity *e = params->variables[i];
|
|
||||||
if (args[i].type == nullptr) {
|
|
||||||
continue;
|
|
||||||
} else if (is_type_untyped_uninit(args[i].type)) {
|
|
||||||
args[i] = lb_const_undef(m, e->type);
|
|
||||||
} else if (is_type_untyped_nil(args[i].type)) {
|
|
||||||
args[i] = lb_const_nil(m, e->type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return lb_emit_call(p, value, args, ce->inlining);
|
|
||||||
}
|
|
||||||
|
|
||||||
isize arg_index = 0;
|
|
||||||
|
|
||||||
isize arg_count = 0;
|
|
||||||
for_array(i, ce->args) {
|
|
||||||
Ast *arg = ce->args[i];
|
|
||||||
if (arg->kind == Ast_FieldValue) {
|
|
||||||
arg = arg->FieldValue.value;
|
|
||||||
}
|
|
||||||
TypeAndValue tav = type_and_value_of_expr(arg);
|
|
||||||
GB_ASSERT_MSG(tav.mode != Addressing_Invalid, "%s %s %d", expr_to_string(arg), expr_to_string(expr), tav.mode);
|
|
||||||
GB_ASSERT_MSG(tav.mode != Addressing_ProcGroup, "%s", expr_to_string(arg));
|
|
||||||
Type *at = tav.type;
|
|
||||||
if (is_type_tuple(at)) {
|
|
||||||
arg_count += at->Tuple.variables.count;
|
|
||||||
} else {
|
|
||||||
arg_count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
isize param_count = 0;
|
|
||||||
if (pt->params) {
|
|
||||||
GB_ASSERT(pt->params->kind == Type_Tuple);
|
|
||||||
param_count = pt->params->Tuple.variables.count;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto args = array_make<lbValue>(permanent_allocator(), cast(isize)gb_max(param_count, arg_count));
|
|
||||||
isize variadic_index = pt->variadic_index;
|
|
||||||
bool variadic = pt->variadic && variadic_index >= 0;
|
|
||||||
bool vari_expand = ce->ellipsis.pos.line != 0;
|
|
||||||
bool is_c_vararg = pt->c_vararg;
|
|
||||||
|
|
||||||
String proc_name = {};
|
|
||||||
if (p->entity != nullptr) {
|
|
||||||
proc_name = p->entity->token.string;
|
|
||||||
}
|
|
||||||
TokenPos pos = ast_token(ce->proc).pos;
|
|
||||||
|
|
||||||
TypeTuple *param_tuple = nullptr;
|
|
||||||
if (pt->params) {
|
|
||||||
GB_ASSERT(pt->params->kind == Type_Tuple);
|
|
||||||
param_tuple = &pt->params->Tuple;
|
|
||||||
}
|
|
||||||
|
|
||||||
for_array(i, ce->args) {
|
|
||||||
Ast *arg = ce->args[i];
|
|
||||||
TypeAndValue arg_tv = type_and_value_of_expr(arg);
|
|
||||||
if (arg_tv.mode == Addressing_Type) {
|
|
||||||
args[arg_index++] = lb_const_nil(m, arg_tv.type);
|
|
||||||
} else {
|
|
||||||
lbValue a = lb_build_expr(p, arg);
|
|
||||||
Type *at = a.type;
|
|
||||||
if (at->kind == Type_Tuple) {
|
|
||||||
lbTupleFix *tf = map_get(&p->tuple_fix_map, a.value);
|
|
||||||
if (tf) {
|
|
||||||
for_array(j, tf->values) {
|
|
||||||
args[arg_index++] = tf->values[j];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for_array(j, at->Tuple.variables) {
|
|
||||||
lbValue v = lb_emit_struct_ev(p, a, cast(i32)j);
|
|
||||||
args[arg_index++] = v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
args[arg_index++] = a;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (param_count > 0) {
|
|
||||||
GB_ASSERT_MSG(pt->params != nullptr, "%s %td", expr_to_string(expr), pt->param_count);
|
|
||||||
GB_ASSERT(param_count < 1000000);
|
|
||||||
|
|
||||||
if (arg_count < param_count) {
|
|
||||||
isize end = cast(isize)param_count;
|
|
||||||
if (variadic) {
|
|
||||||
end = variadic_index;
|
|
||||||
}
|
|
||||||
while (arg_index < end) {
|
|
||||||
Entity *e = param_tuple->variables[arg_index];
|
|
||||||
GB_ASSERT(e->kind == Entity_Variable);
|
|
||||||
args[arg_index++] = lb_handle_param_value(p, e->type, e->Variable.param_value, ast_token(expr).pos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_c_vararg) {
|
|
||||||
GB_ASSERT(variadic);
|
|
||||||
GB_ASSERT(!vari_expand);
|
|
||||||
isize i = 0;
|
|
||||||
for (; i < variadic_index; i++) {
|
|
||||||
Entity *e = param_tuple->variables[i];
|
|
||||||
if (e->kind == Entity_Variable) {
|
|
||||||
args[i] = lb_emit_conv(p, args[i], e->type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Type *variadic_type = param_tuple->variables[i]->type;
|
|
||||||
GB_ASSERT(is_type_slice(variadic_type));
|
|
||||||
variadic_type = base_type(variadic_type)->Slice.elem;
|
|
||||||
if (!is_type_any(variadic_type)) {
|
|
||||||
for (; i < arg_count; i++) {
|
|
||||||
args[i] = lb_emit_conv(p, args[i], variadic_type);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (; i < arg_count; i++) {
|
|
||||||
args[i] = lb_emit_conv(p, args[i], default_type(args[i].type));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (variadic) {
|
|
||||||
isize i = 0;
|
|
||||||
for (; i < variadic_index; i++) {
|
|
||||||
Entity *e = param_tuple->variables[i];
|
|
||||||
if (e->kind == Entity_Variable) {
|
|
||||||
args[i] = lb_emit_conv(p, args[i], e->type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!vari_expand) {
|
|
||||||
Type *variadic_type = param_tuple->variables[i]->type;
|
|
||||||
GB_ASSERT(is_type_slice(variadic_type));
|
|
||||||
variadic_type = base_type(variadic_type)->Slice.elem;
|
|
||||||
for (; i < arg_count; i++) {
|
|
||||||
args[i] = lb_emit_conv(p, args[i], variadic_type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (isize i = 0; i < param_count; i++) {
|
|
||||||
Entity *e = param_tuple->variables[i];
|
|
||||||
if (e->kind == Entity_Variable) {
|
|
||||||
if (args[i].value == nullptr) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
GB_ASSERT_MSG(args[i].value != nullptr, "%.*s", LIT(e->token.string));
|
|
||||||
if (is_type_typeid(e->type) && !is_type_typeid(args[i].type)) {
|
|
||||||
GB_ASSERT(LLVMIsNull(args[i].value));
|
|
||||||
args[i] = lb_typeid(p->module, args[i].type);
|
|
||||||
} else {
|
|
||||||
args[i] = lb_emit_conv(p, args[i], e->type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (variadic && !vari_expand && !is_c_vararg) {
|
|
||||||
// variadic call argument generation
|
|
||||||
Type *slice_type = param_tuple->variables[variadic_index]->type;
|
|
||||||
Type *elem_type = base_type(slice_type)->Slice.elem;
|
|
||||||
lbAddr slice = lb_add_local_generated(p, slice_type, true);
|
|
||||||
isize slice_len = arg_count+1 - (variadic_index+1);
|
|
||||||
|
|
||||||
if (slice_len > 0) {
|
|
||||||
lbAddr base_array = lb_add_local_generated(p, alloc_type_array(elem_type, slice_len), true);
|
|
||||||
|
|
||||||
for (isize i = variadic_index, j = 0; i < arg_count; i++, j++) {
|
|
||||||
lbValue addr = lb_emit_array_epi(p, base_array.addr, cast(i32)j);
|
|
||||||
lb_emit_store(p, addr, args[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
lbValue base_elem = lb_emit_array_epi(p, base_array.addr, 0);
|
|
||||||
lbValue len = lb_const_int(m, t_int, slice_len);
|
|
||||||
lb_fill_slice(p, slice, base_elem, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
arg_count = param_count;
|
|
||||||
args[variadic_index] = lb_addr_load(p, slice);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (variadic && variadic_index+1 < param_count) {
|
|
||||||
for (isize i = variadic_index+1; i < param_count; i++) {
|
|
||||||
Entity *e = param_tuple->variables[i];
|
|
||||||
args[i] = lb_handle_param_value(p, e->type, e->Variable.param_value, ast_token(expr).pos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
isize final_count = param_count;
|
|
||||||
if (is_c_vararg) {
|
|
||||||
final_count = arg_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (param_tuple != nullptr) {
|
|
||||||
for (isize i = 0; i < gb_min(args.count, param_tuple->variables.count); i++) {
|
|
||||||
Entity *e = param_tuple->variables[i];
|
|
||||||
if (args[i].type == nullptr) {
|
|
||||||
continue;
|
|
||||||
} else if (is_type_untyped_uninit(args[i].type)) {
|
|
||||||
args[i] = lb_const_undef(m, e->type);
|
|
||||||
} else if (is_type_untyped_nil(args[i].type)) {
|
|
||||||
args[i] = lb_const_nil(m, e->type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto call_args = array_slice(args, 0, final_count);
|
|
||||||
return lb_emit_call(p, value, call_args, ce->inlining);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user