diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 2e5b23e78..5b1f1a73c 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -676,6 +676,11 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand return 1; } break; + case Basic_UntypedString: + if (is_type_string(dst)) { + return 1; + } + break; case Basic_UntypedFloat: if (is_type_float(dst)) { return 1; @@ -701,33 +706,48 @@ gb_internal i64 check_distance_between_types(CheckerContext *c, Operand *operand return -1; } if (src->kind == Type_Basic) { + i64 score = -1; switch (src->Basic.kind) { case Basic_UntypedRune: if (is_type_integer(dst) || is_type_rune(dst)) { - if (is_type_typed(type)) { - return 2; - } - return 1; + score = 1; } - return -1; - case Basic_UntypedBool: - if (is_type_boolean(dst)) { - if (is_type_typed(type)) { - return 2; - } - return 1; + break; + case Basic_UntypedInteger: + if (is_type_integer(dst) || is_type_rune(dst)) { + score = 1; } - return -1; + break; case Basic_UntypedString: - if (is_type_string(dst) || is_type_cstring(dst)) { - if (is_type_typed(type)) { - return 2; - } - return 1; + if (is_type_string(dst)) { + score = 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; 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; } } @@ -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)); } err = CallArgumentError_DuplicateParameter; - } else { + } else if (!visited[pt->variadic_index]) { visited[pt->variadic_index] = true; 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) { 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); 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"); + if (show_error) { + error(call, "Ambiguous call to a polymorphic variadic procedure with no variadic input"); + } err = CallArgumentError_AmbiguousPolymorphicVariadic; } } @@ -5596,46 +5659,14 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A } 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 (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; - } + continue; } - 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)); - } else if (show_error && is_type_untyped(o->type)) { - update_untyped_expr_type(c, o->expr, e->type, true); + if (param_is_variadic) { + continue; } + + 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) { - Operand &o = variadic_operands[operand_index]; + Operand *o = &variadic_operands[operand_index]; if (vari_expand) { t = slice; if (operand_index > 0) { 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) { data->score = score; @@ -5666,25 +5697,7 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A return CallArgumentError_MultipleVariadicExpand; } } - i64 s = 0; - 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); - } + score += eval_param_and_score(c, o, t, err, true, nullptr, show_error); } } diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index b7ee88804..fc58d584e 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -3336,253 +3336,7 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) { GB_ASSERT(proc_type_->kind == Type_Proc); TypeProc *pt = &proc_type_->Proc; - if (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(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(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); + GB_ASSERT(ce->split_args != nullptr); + return lb_build_call_expr_internal_with_arg_split_args(p, value, pt, expr, ce->split_args); }