From 2992ca5df122e2f20113d5b357413c7fff606879 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 15 Jun 2023 01:37:55 +0100 Subject: Basic support for new procedure code (non-polymorphic, non-proc-group) --- src/llvm_backend_proc.cpp | 119 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) (limited to 'src/llvm_backend_proc.cpp') diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 8b9f8b249..3c1cfe47c 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -3145,6 +3145,118 @@ gb_internal lbValue lb_build_call_expr(lbProcedure *p, Ast *expr) { } return res; } + +gb_internal void lb_add_values_to_array(lbProcedure *p, Array *args, lbValue value) { + if (is_type_tuple(value.type)) { + for_array(i, value.type->Tuple.variables) { + lbValue sub_value = lb_emit_struct_ev(p, value, cast(i32)i); + array_add(args, sub_value); + } + } else { + array_add(args, value); + } +} +gb_internal lbValue lb_build_call_expr_internal_with_arg_ordered_args(lbProcedure *p, lbValue value, TypeProc *pt, Ast *call, AstOrderedArgs *ordered_args) { + ast_node(ce, CallExpr, call); + + auto args = array_make(permanent_allocator(), 0, pt->param_count); + + bool vari_expand = (ce->ellipsis.pos.line != 0); + + for_array(i, ordered_args->positional) { + Entity *e = pt->params->Tuple.variables[i]; + GB_ASSERT(e->kind == Entity_Variable); + + if (pt->variadic && pt->variadic_index == i) { + lbValue variadic_args = lb_const_nil(p->module, e->type); + auto variadic = slice(ordered_args->positional, pt->variadic_index, ordered_args->positional.count); + if (variadic.count != 0) { + // variadic call argument generation + Type *slice_type = e->type; + GB_ASSERT(slice_type->kind == Type_Slice); + if (vari_expand) { + GB_ASSERT(variadic.count == 1); + variadic_args = lb_build_expr(p, variadic[0]); + variadic_args = lb_emit_conv(p, variadic_args, slice_type); + } else { + Type *elem_type = slice_type->Slice.elem; + + auto var_args = array_make(heap_allocator(), 0, variadic.count); + defer (array_free(&var_args)); + for (Ast *var_arg : variadic) { + lbValue v = lb_build_expr(p, var_arg); + lb_add_values_to_array(p, &var_args, v); + } + isize slice_len = var_args.count; + if (slice_len > 0) { + lbAddr slice = lb_add_local_generated(p, slice_type, true); + lbAddr base_array = lb_add_local_generated(p, alloc_type_array(elem_type, slice_len), true); + + for (isize i = 0; i < var_args.count; i++) { + lbValue addr = lb_emit_array_epi(p, base_array.addr, cast(i32)i); + lbValue var_arg = var_args[i]; + var_arg = lb_emit_conv(p, var_arg, elem_type); + lb_emit_store(p, addr, var_arg); + } + + lbValue base_elem = lb_emit_array_epi(p, base_array.addr, 0); + lbValue len = lb_const_int(p->module, t_int, slice_len); + lb_fill_slice(p, slice, base_elem, len); + + variadic_args = lb_addr_load(p, slice); + } + } + } + array_add(&args, variadic_args); + + break; + } else { + lbValue value = lb_build_expr(p, ordered_args->positional[i]); + lb_add_values_to_array(p, &args, value); + } + } + + array_resize(&args, pt->param_count); + + for (Ast *arg : ordered_args->named) { + ast_node(fv, FieldValue, arg); + GB_ASSERT(fv->field->kind == Ast_Ident); + String name = fv->field->Ident.token.string; + gb_unused(name); + isize param_index = lookup_procedure_parameter(pt, name); + GB_ASSERT(param_index >= 0); + + lbValue value = lb_build_expr(p, fv->value); + GB_ASSERT(!is_type_tuple(value.type)); + args[param_index] = value; + } + + TokenPos pos = ast_token(ce->proc).pos; + + for_array(i, args) { + Entity *e = pt->params->Tuple.variables[i]; + lbValue arg = args[i]; + if (arg.value == nullptr) { + switch (e->kind) { + case Entity_TypeName: + args[i] = lb_const_nil(p->module, e->type); + break; + case Entity_Variable: + args[i] = lb_handle_param_value(p, e->type, e->Variable.param_value, pos); + break; + case Entity_Constant: + GB_PANIC("TODO constant parameter"); + break; + } + } else { + args[i] = lb_emit_conv(p, arg, e->type); + } + } + + + return lb_emit_call(p, value, args, ce->inlining); +} + gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) { lbModule *m = p->module; @@ -3219,6 +3331,10 @@ 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->ordered_args) { + return lb_build_call_expr_internal_with_arg_ordered_args(p, value, pt, expr, ce->ordered_args); + } + if (is_call_expr_field_value(ce)) { auto args = array_make(permanent_allocator(), pt->param_count); @@ -3274,6 +3390,9 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) { 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)); -- cgit v1.2.3 From 6568625dea679b4622024f62fc14725aa49b2106 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 19 Jun 2023 22:12:47 +0100 Subject: Fix line error printing for error messages --- src/array.cpp | 4 +- src/check_expr.cpp | 750 ++++++++++++++++++++++++++++++++++++++++++---- src/error.cpp | 31 +- src/gb/gb.h | 39 ++- src/llvm_backend_proc.cpp | 14 +- src/parser.hpp | 4 +- src/types.cpp | 6 + 7 files changed, 765 insertions(+), 83 deletions(-) (limited to 'src/llvm_backend_proc.cpp') diff --git a/src/array.cpp b/src/array.cpp index f1a1f93e2..d8e25d25d 100644 --- a/src/array.cpp +++ b/src/array.cpp @@ -80,7 +80,9 @@ gb_internal Slice slice_make(gbAllocator const &allocator, isize count) { GB_ASSERT(count >= 0); Slice s = {}; s.data = gb_alloc_array(allocator, T, count); - GB_ASSERT(s.data != nullptr); + if (count > 0) { + GB_ASSERT(s.data != nullptr); + } s.count = count; return s; } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index c3f6002c7..e0c6be1d1 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -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 operands, CallArgumentErrorMode show_error_mode, CallArgumentData *data) +#define CALL_ARGUMENT_CHECKER(name) CallArgumentError name(CheckerContext *c, Ast *call, Type *proc_type, Entity *entity, Array operands, Array 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(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,32 +6016,568 @@ gb_internal CallArgumentError check_order_of_call_arguments(CheckerContext *c, T return err; } +gb_internal bool check_named_arguments(CheckerContext *c, Type *type, Slice const &named_args, Array *named_operands, bool show_error) { + bool success = true; -gb_internal CallArgumentData check_call_arguments_single_procedure(CheckerContext *c, Operand *operand, Ast *call) { - Type *proc_type = nullptr; + 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 const &positional_args = ce->split_args->positional; + Slice const &named_args = ce->split_args->named; CallArgumentData data = {}; data.result_type = t_invalid; - proc_type = base_type(operand->type); + 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; + } + } + } - if (operand->mode == Addressing_ProcGroup) { - Array 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"); + 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(heap_allocator(), 0, 0); + auto named_operands = array_make(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); } - 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); + gb_free(heap_allocator(), lhs); + + auto valids = array_make(heap_allocator(), 0, procs.count); + defer (array_free(&valids)); + + auto proc_entities = array_make(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 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 = {}; + data.result_type = t_invalid; + + proc_type = base_type(operand->type); + 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 positional_args = {}; + Slice 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; + } + + if (operand->mode == Addressing_ProcGroup) { + return check_call_arguments_new_and_improved_proc_group(c, operand, call); } - auto named_args = slice(ce->args, positional_args.count, ce->args.count); + auto positional_operands = array_make(heap_allocator(), 0, positional_args.count); - auto variadic_operands = array_make(heap_allocator(), 0, 0); - auto named_operands = array_make(heap_allocator(), 0, 0); + auto variadic_operands = array_make(heap_allocator(), 0, 0); + auto named_operands = array_make(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(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 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 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 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 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 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); diff --git a/src/error.cpp b/src/error.cpp index defc2593f..eb010eb36 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -265,7 +265,8 @@ gb_internal bool show_error_on_line(TokenPos const &pos, TokenPos end) { defer (gb_string_free(the_line)); if (the_line != nullptr) { - String line = make_string(cast(u8 const *)the_line, gb_string_length(the_line)); + char const *line_text = the_line; + isize line_len = gb_string_length(the_line); // TODO(bill): This assumes ASCII @@ -285,21 +286,27 @@ gb_internal bool show_error_on_line(TokenPos const &pos, TokenPos end) { isize squiggle_extra = 0; - if (line.len > MAX_LINE_LENGTH_PADDED) { + if (line_len > MAX_LINE_LENGTH_PADDED) { i32 left = MAX_TAB_WIDTH; - line.text += offset-left; - line.len -= offset-left; - offset = left+MAX_TAB_WIDTH/2; - if (line.len > MAX_LINE_LENGTH_PADDED) { - line.len = MAX_LINE_LENGTH_PADDED; - if (error_length > line.len-left) { - error_length = cast(i32)line.len - left; + if (offset > 0) { + line_text += offset-left; + line_len -= offset-left; + offset = left+MAX_TAB_WIDTH/2; + } + if (line_len > MAX_LINE_LENGTH_PADDED) { + line_len = MAX_LINE_LENGTH_PADDED; + if (error_length > line_len-left) { + error_length = cast(i32)line_len - left; squiggle_extra = 1; } } - error_out("... %.*s ...", LIT(line)); + if (offset > 0) { + error_out("... %.*s ...", cast(i32)line_len, line_text); + } else { + error_out("%.*s ...", cast(i32)line_len, line_text); + } } else { - error_out("%.*s", LIT(line)); + error_out("%.*s", cast(i32)line_len, line_text); } error_out("\n\t"); @@ -312,7 +319,7 @@ gb_internal bool show_error_on_line(TokenPos const &pos, TokenPos end) { error_out("^"); if (end.file_id == pos.file_id) { if (end.line > pos.line) { - for (i32 i = offset; i < line.len; i++) { + for (i32 i = offset; i < line_len; i++) { error_out("~"); } } else if (end.line == pos.line && end.column > pos.column) { diff --git a/src/gb/gb.h b/src/gb/gb.h index bc4c1f27d..3d4bff9b4 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -3299,12 +3299,39 @@ void const *gb_memrchr(void const *data, u8 c, isize n) { -gb_inline void *gb_alloc_align (gbAllocator a, isize size, isize alignment) { return a.proc(a.data, gbAllocation_Alloc, size, alignment, NULL, 0, GB_DEFAULT_ALLOCATOR_FLAGS); } -gb_inline void *gb_alloc (gbAllocator a, isize size) { return gb_alloc_align(a, size, GB_DEFAULT_MEMORY_ALIGNMENT); } -gb_inline void gb_free (gbAllocator a, void *ptr) { if (ptr != NULL) a.proc(a.data, gbAllocation_Free, 0, 0, ptr, 0, GB_DEFAULT_ALLOCATOR_FLAGS); } -gb_inline void gb_free_all (gbAllocator a) { a.proc(a.data, gbAllocation_FreeAll, 0, 0, NULL, 0, GB_DEFAULT_ALLOCATOR_FLAGS); } -gb_inline void *gb_resize (gbAllocator a, void *ptr, isize old_size, isize new_size) { return gb_resize_align(a, ptr, old_size, new_size, GB_DEFAULT_MEMORY_ALIGNMENT); } -gb_inline void *gb_resize_align(gbAllocator a, void *ptr, isize old_size, isize new_size, isize alignment) { return a.proc(a.data, gbAllocation_Resize, new_size, alignment, ptr, old_size, GB_DEFAULT_ALLOCATOR_FLAGS); } +gb_inline void *gb_alloc_align (gbAllocator a, isize size, isize alignment) { + if (size == 0) { + return NULL; + } + return a.proc(a.data, gbAllocation_Alloc, size, alignment, NULL, 0, GB_DEFAULT_ALLOCATOR_FLAGS); +} +gb_inline void *gb_alloc(gbAllocator a, isize size) { + return gb_alloc_align(a, size, GB_DEFAULT_MEMORY_ALIGNMENT); +} +gb_inline void gb_free(gbAllocator a, void *ptr) { + if (ptr != NULL) { + a.proc(a.data, gbAllocation_Free, 0, 0, ptr, 0, GB_DEFAULT_ALLOCATOR_FLAGS); + } +} +gb_inline void gb_free_all(gbAllocator a) { + a.proc(a.data, gbAllocation_FreeAll, 0, 0, NULL, 0, GB_DEFAULT_ALLOCATOR_FLAGS); +} +gb_inline void *gb_resize(gbAllocator a, void *ptr, isize old_size, isize new_size) { + return gb_resize_align(a, ptr, old_size, new_size, GB_DEFAULT_MEMORY_ALIGNMENT); +} +gb_inline void *gb_resize_align(gbAllocator a, void *ptr, isize old_size, isize new_size, isize alignment) { + if (new_size == 0) { + if (ptr != NULL) { + return a.proc(a.data, gbAllocation_Free, 0, 0, ptr, old_size, GB_DEFAULT_ALLOCATOR_FLAGS); + } + return NULL; + } else if (ptr == NULL) { + return a.proc(a.data, gbAllocation_Alloc, new_size, alignment, NULL, 0, GB_DEFAULT_ALLOCATOR_FLAGS); + } else if (old_size == new_size && ((uintptr)ptr % (uintptr)alignment) == 0) { + return ptr; + } + return a.proc(a.data, gbAllocation_Resize, new_size, alignment, ptr, old_size, GB_DEFAULT_ALLOCATOR_FLAGS); +} gb_inline void *gb_alloc_copy (gbAllocator a, void const *src, isize size) { return gb_memcopy(gb_alloc(a, size), src, size); diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 3c1cfe47c..046016c75 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -3156,20 +3156,20 @@ gb_internal void lb_add_values_to_array(lbProcedure *p, Array *args, lb array_add(args, value); } } -gb_internal lbValue lb_build_call_expr_internal_with_arg_ordered_args(lbProcedure *p, lbValue value, TypeProc *pt, Ast *call, AstOrderedArgs *ordered_args) { +gb_internal lbValue lb_build_call_expr_internal_with_arg_split_args(lbProcedure *p, lbValue value, TypeProc *pt, Ast *call, AstSplitArgs *split_args) { ast_node(ce, CallExpr, call); auto args = array_make(permanent_allocator(), 0, pt->param_count); bool vari_expand = (ce->ellipsis.pos.line != 0); - for_array(i, ordered_args->positional) { + for_array(i, split_args->positional) { Entity *e = pt->params->Tuple.variables[i]; GB_ASSERT(e->kind == Entity_Variable); if (pt->variadic && pt->variadic_index == i) { lbValue variadic_args = lb_const_nil(p->module, e->type); - auto variadic = slice(ordered_args->positional, pt->variadic_index, ordered_args->positional.count); + auto variadic = slice(split_args->positional, pt->variadic_index, split_args->positional.count); if (variadic.count != 0) { // variadic call argument generation Type *slice_type = e->type; @@ -3211,14 +3211,14 @@ gb_internal lbValue lb_build_call_expr_internal_with_arg_ordered_args(lbProcedur break; } else { - lbValue value = lb_build_expr(p, ordered_args->positional[i]); + lbValue value = lb_build_expr(p, split_args->positional[i]); lb_add_values_to_array(p, &args, value); } } array_resize(&args, pt->param_count); - for (Ast *arg : ordered_args->named) { + for (Ast *arg : split_args->named) { ast_node(fv, FieldValue, arg); GB_ASSERT(fv->field->kind == Ast_Ident); String name = fv->field->Ident.token.string; @@ -3331,8 +3331,8 @@ 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->ordered_args) { - return lb_build_call_expr_internal_with_arg_ordered_args(p, value, pt, expr, ce->ordered_args); + 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)) { diff --git a/src/parser.hpp b/src/parser.hpp index e0e78fa1d..900fddbab 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -367,7 +367,7 @@ gb_global char const *union_type_kind_strings[UnionType_COUNT] = { "#shared_nil", }; -struct AstOrderedArgs { +struct AstSplitArgs { Slice positional; Slice named; }; @@ -447,7 +447,7 @@ AST_KIND(_ExprBegin, "", bool) \ ProcInlining inlining; \ bool optional_ok_one; \ bool was_selector; \ - AstOrderedArgs *ordered_args; \ + AstSplitArgs *split_args; \ }) \ AST_KIND(FieldValue, "field value", struct { Token eq; Ast *field, *value; }) \ AST_KIND(EnumFieldValue, "enum field value", struct { \ diff --git a/src/types.cpp b/src/types.cpp index 3cc077f84..f3b7f5bab 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -3326,6 +3326,9 @@ gb_internal bool are_struct_fields_reordered(Type *type) { type = base_type(type); GB_ASSERT(type->kind == Type_Struct); type_set_offsets(type); + if (type->Struct.fields.count == 0) { + return false; + } GB_ASSERT(type->Struct.offsets != nullptr); i64 prev_offset = 0; @@ -3344,6 +3347,9 @@ gb_internal Slice struct_fields_index_by_increasing_offset(gbAllocator allo type = base_type(type); GB_ASSERT(type->kind == Type_Struct); type_set_offsets(type); + if (type->Struct.fields.count == 0) { + return {}; + } GB_ASSERT(type->Struct.offsets != nullptr); auto indices = slice_make(allocator, type->Struct.fields.count); -- cgit v1.2.3 From 9ec927b9e952cb1e82ec543c95547321273a812b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 20 Jun 2023 00:30:29 +0100 Subject: Try to get make everything work with parapoly --- src/check_expr.cpp | 186 ++++++++-------------------------------------- src/llvm_backend_proc.cpp | 7 +- src/types.cpp | 16 ++-- 3 files changed, 48 insertions(+), 161 deletions(-) (limited to 'src/llvm_backend_proc.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 92b572352..8242d38e9 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -6791,11 +6791,6 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved(CheckerContex proc_type = base_type(operand->type); - if (proc_type != nullptr && is_type_polymorphic(proc_type)) { - error(call, "Polymorphic procedures not yet supported"); - return data; - } - TypeProc *pt = nullptr; if (proc_type) { pt = &proc_type->Proc; @@ -6806,7 +6801,7 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved(CheckerContex bool any_failure = false; - bool vari_expand = (ce->ellipsis.pos.line != 0); + // bool vari_expand = (ce->ellipsis.pos.line != 0); // Split positional and named args into separate arrays/slices Slice positional_args = {}; @@ -6838,14 +6833,11 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved(CheckerContex auto positional_operands = array_make(heap_allocator(), 0, positional_args.count); - auto variadic_operands = array_make(heap_allocator(), 0, 0); auto named_operands = array_make(heap_allocator(), 0, 0); defer (array_free(&positional_operands)); - defer (array_free(&variadic_operands)); defer (array_free(&named_operands)); - isize positional_operand_count = 0; Slice visited = {}; @@ -6860,90 +6852,8 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved(CheckerContex } check_unpack_arguments(c, lhs, lhs_count, &positional_operands, positional_args, is_variadic ? UnpackFlag_IsVariadic : UnpackFlag_None); } - positional_operand_count = positional_operands.count; - - if (pt != nullptr) { - visited = slice_make(temporary_allocator(), pt->param_count); - - if (!pt->variadic) { - if (pt->param_count < positional_operands.count) { - char const *err_fmt = "Too many arguments for '%s', expected a maximum of %td arguments, got %td"; - gbString c = expr_to_string(ce->proc); - error(call, err_fmt, c, pt->param_count, positional_operands.count); - gb_string_free(c); - return data; - } - positional_operand_count = positional_operands.count; - } else { - // only state it is visited if it was set later on - visited[pt->variadic_index] = positional_operand_count > pt->variadic_index; - - positional_operand_count = gb_min(pt->variadic_index, positional_operand_count); - } - - - for (isize i = 0; i < positional_operand_count; i++) { - visited[i] = true; - } - - for (isize i = positional_operand_count; i < positional_operands.count; i++) { - array_add(&variadic_operands, positional_operands[i]); - } - array_resize(&positional_operands, positional_operand_count); - - if (vari_expand) { - if (variadic_operands.count > 1) { - error(variadic_operands[1].expr, "Unexpected position arguments after variadic expansion with '..'"); - return data; - } - } - - isize param_count = 0; - isize param_count_excluding_defaults = get_procedure_param_count_excluding_defaults(proc_type, ¶m_count); - - if (named_args.count == 0 && positional_operands.count < param_count_excluding_defaults) { - char const *err_fmt = "Too few arguments for '%s', expected a minimum of %td arguments, got %td"; - gbString c = expr_to_string(ce->proc); - error(call, err_fmt, c, param_count_excluding_defaults, positional_operands.count); - gb_string_free(c); - return data; - } - - // 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")); - // } - // } - // } - - array_resize(&positional_operands, pt->param_count); - - } - if (named_args.count > 0) { - struct NamedParameter { - String key; - Ast * value; - }; - - auto named_parameters = array_make(heap_allocator(), 0, named_args.count); - defer (array_free(&named_parameters)); - for_array(i, named_args) { Ast *arg = named_args[i]; if (arg->kind != Ast_FieldValue) { @@ -6958,74 +6868,27 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved(CheckerContex gb_string_free(expr_str); continue; } - String name = fv->field->Ident.token.string; - - array_add(&named_parameters, NamedParameter{name, fv->value}); - } - - for (NamedParameter const ¶m : named_parameters) { - isize param_index = lookup_procedure_parameter(pt, param.key); - if (param_index < 0) { - error(param.value, "No parameter named '%.*s' for this procedure type", LIT(param.key)); - any_failure = true; - continue; - } - - bool prev_visited = visited[param_index]; - visited[param_index] = true; + String key = fv->field->Ident.token.string; + Ast *value = fv->value; - if (prev_visited) { - error(param.value, "Duplicate parameter named '%.*s' in procedure call", LIT(param.key)); + isize param_index = lookup_procedure_parameter(pt, key); + Type *type_hint = nullptr; + if (param_index >= 0) { + Entity *e = pt->params->Tuple.variables[param_index]; + type_hint = e->type; } - Entity *e = pt->params->Tuple.variables[param_index]; - GB_ASSERT(e->kind == Entity_Variable); - Operand o = {}; - check_expr_with_type_hint(c, &o, param.value, e->type); + check_expr_with_type_hint(c, &o, value, type_hint); if (o.mode == Addressing_Invalid) { any_failure = true; } - - if (!prev_visited) { - positional_operands[param_index] = o; - } array_add(&named_operands, o); } } - if (pt != nullptr) { - if (pt->variadic) { - visited[pt->variadic_index] = true; - } - - for_array(i, visited) { - if (!visited[i]) { - if (pt->variadic && i == pt->variadic_index) { - visited[i] = true; - continue; - } - - Entity *e = pt->params->Tuple.variables[i]; - if (e->kind == Entity_Variable) { - if (has_parameter_value(e->Variable.param_value)) { - visited[i] = true; - continue; - } - } - gbString t = type_to_string(e->type); - error(call, "Missing parameter of type '%s' at index %td", t, i); - gb_string_free(t); - } - } - } - - if (any_failure) { - return data; - } - - { + if (!any_failure) { Ast *ident = operand->expr; while (ident->kind == Ast_SelectorExpr) { Ast *s = ident->SelectorExpr.selector; @@ -7034,9 +6897,12 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved(CheckerContex Entity *e = entity_of_node(ident); - Array operands = array_clone(heap_allocator(), positional_operands); + TokenPos pos = ast_token(call).pos; + if (pos.line == 282 && pos.column == 9 && is_type_polymorphic(proc_type)) { + // GB_PANIC("HERE! %s\n", expr_to_string(call)); + } - CallArgumentError err = check_call_arguments_internal(c, call, proc_type, e, operands, {}, CallArgumentMode_ShowErrors, &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); @@ -7060,12 +6926,17 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved(CheckerContex 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) { + if (is_type_proc(data.gen_entity->type)) { + Type *t = base_type(entity_to_use->type); + // GB_ASSERT_MSG(!is_type_polymorphic(t), "%s", expr_to_string(call)); + data.result_type = t->Proc.results; + } + } + } else if (pt) { data.result_type = pt->results; } + return data; } @@ -7085,8 +6956,15 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op } } - if (operand->mode != Addressing_ProcGroup && is_type_proc(operand->type) && !is_type_polymorphic(operand->type)) { - return check_call_arguments_new_and_improved(c, operand, call); + if (operand->mode != Addressing_ProcGroup) { + bool is_poly = is_type_polymorphic(operand->type); + bool ok = !is_poly; + if (!ok && c->pkg->name == "bug") { + ok = true; + } + if (ok) { + return check_call_arguments_new_and_improved(c, operand, call); + } } ast_node(ce, CallExpr, call); diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 046016c75..c6a9438ea 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -3165,7 +3165,12 @@ gb_internal lbValue lb_build_call_expr_internal_with_arg_split_args(lbProcedure for_array(i, split_args->positional) { Entity *e = pt->params->Tuple.variables[i]; - GB_ASSERT(e->kind == Entity_Variable); + if (e->kind == Entity_TypeName) { + array_add(&args, lb_const_nil(p->module, e->type)); + continue; + } else if (e->kind != Entity_Variable) { + continue; + } if (pt->variadic && pt->variadic_index == i) { lbValue variadic_args = lb_const_nil(p->module, e->type); diff --git a/src/types.cpp b/src/types.cpp index f3b7f5bab..1223132e3 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -2108,8 +2108,12 @@ gb_internal bool is_type_polymorphic(Type *t, bool or_specialized=false) { return is_type_polymorphic(t->Matrix.elem, or_specialized); case Type_Tuple: - for_array(i, t->Tuple.variables) { - if (is_type_polymorphic(t->Tuple.variables[i]->type, or_specialized)) { + for (Entity *e : t->Tuple.variables) { + if (e->kind == Entity_Constant) { + if (e->Constant.value.kind != ExactValue_Invalid) { + return or_specialized; + } + } else if (is_type_polymorphic(e->type, or_specialized)) { return true; } } @@ -4279,6 +4283,10 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha if (var == nullptr) { continue; } + if (comma_index++ > 0) { + str = gb_string_appendc(str, ", "); + } + String name = var->token.string; if (var->kind == Entity_Constant) { str = gb_string_appendc(str, "$"); @@ -4295,10 +4303,6 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha continue; } - if (comma_index++ > 0) { - str = gb_string_appendc(str, ", "); - } - if (var->kind == Entity_Variable) { if (var->flags&EntityFlag_CVarArg) { str = gb_string_appendc(str, "#c_vararg "); -- cgit v1.2.3 From 7c57dde2556b95a0ef206efd93fc23f8fd0bdf89 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 20 Jun 2023 13:47:10 +0100 Subject: Start work on parapoly args for new and improved --- src/check_expr.cpp | 18 ++++-------------- src/llvm_backend_proc.cpp | 2 +- 2 files changed, 5 insertions(+), 15 deletions(-) (limited to 'src/llvm_backend_proc.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 8242d38e9..5574827d5 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -6898,9 +6898,6 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved(CheckerContex Entity *e = entity_of_node(ident); TokenPos pos = ast_token(call).pos; - if (pos.line == 282 && pos.column == 9 && is_type_polymorphic(proc_type)) { - // GB_PANIC("HERE! %s\n", expr_to_string(call)); - } CallArgumentError err = check_call_arguments_internal(c, call, proc_type, e, positional_operands, named_operands, CallArgumentMode_ShowErrors, &data); gb_unused(err); @@ -6908,6 +6905,7 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved(CheckerContex 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); + add_type_and_value(c, operand->expr, operand->mode, entity_to_use->type, operand->value); } if (data.gen_entity != nullptr) { Entity *e = data.gen_entity; @@ -6931,6 +6929,7 @@ gb_internal CallArgumentData check_call_arguments_new_and_improved(CheckerContex Type *t = base_type(entity_to_use->type); // GB_ASSERT_MSG(!is_type_polymorphic(t), "%s", expr_to_string(call)); data.result_type = t->Proc.results; + } } } else if (pt) { @@ -6954,17 +6953,8 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op if (all_non_poly) { return check_call_arguments_new_and_improved(c, operand, call); } - } - - if (operand->mode != Addressing_ProcGroup) { - bool is_poly = is_type_polymorphic(operand->type); - bool ok = !is_poly; - if (!ok && c->pkg->name == "bug") { - ok = true; - } - if (ok) { - return check_call_arguments_new_and_improved(c, operand, call); - } + } else { + return check_call_arguments_new_and_improved(c, operand, call); } ast_node(ce, CallExpr, call); diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index c6a9438ea..b7ee88804 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -3250,7 +3250,7 @@ gb_internal lbValue lb_build_call_expr_internal_with_arg_split_args(lbProcedure args[i] = lb_handle_param_value(p, e->type, e->Variable.param_value, pos); break; case Entity_Constant: - GB_PANIC("TODO constant parameter"); + args[i] = lb_handle_param_value(p, e->type, e->Constant.param_value, pos); break; } } else { -- cgit v1.2.3 From 09f366bec72087fb8ed835cda6d2b8cc115627e4 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 21 Jun 2023 00:03:56 +0100 Subject: Correct purely named argument handling --- src/check_expr.cpp | 181 +++++++++++++++++---------------- src/llvm_backend_proc.cpp | 250 +--------------------------------------------- 2 files changed, 99 insertions(+), 332 deletions(-) (limited to 'src/llvm_backend_proc.cpp') 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); } -- cgit v1.2.3 From 43ba2c6226dc71754c7aa74ed8ecb150231a9624 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 21 Jun 2023 12:10:07 +0100 Subject: Fix constant parameter passing --- src/llvm_backend_proc.cpp | 44 +++++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 17 deletions(-) (limited to 'src/llvm_backend_proc.cpp') diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index fc58d584e..0beaf376b 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -3168,10 +3168,13 @@ gb_internal lbValue lb_build_call_expr_internal_with_arg_split_args(lbProcedure if (e->kind == Entity_TypeName) { array_add(&args, lb_const_nil(p->module, e->type)); continue; - } else if (e->kind != Entity_Variable) { + } else if (e->kind == Entity_Constant) { + array_add(&args, lb_const_value(p->module, e->type, e->Constant.value)); continue; } + GB_ASSERT(e->kind == Entity_Variable); + if (pt->variadic && pt->variadic_index == i) { lbValue variadic_args = lb_const_nil(p->module, e->type); auto variadic = slice(split_args->positional, pt->variadic_index, split_args->positional.count); @@ -3238,23 +3241,30 @@ gb_internal lbValue lb_build_call_expr_internal_with_arg_split_args(lbProcedure TokenPos pos = ast_token(ce->proc).pos; - for_array(i, args) { - Entity *e = pt->params->Tuple.variables[i]; - lbValue arg = args[i]; - if (arg.value == nullptr) { - switch (e->kind) { - case Entity_TypeName: - args[i] = lb_const_nil(p->module, e->type); - break; - case Entity_Variable: - args[i] = lb_handle_param_value(p, e->type, e->Variable.param_value, pos); - break; - case Entity_Constant: - args[i] = lb_handle_param_value(p, e->type, e->Constant.param_value, pos); - break; + + if (pt->params != nullptr) { + for_array(arg_index, pt->params->Tuple.variables) { + Entity *e = pt->params->Tuple.variables[arg_index]; + + lbValue arg = args[arg_index]; + if (arg.value == nullptr) { + switch (e->kind) { + case Entity_TypeName: + args[arg_index] = lb_const_nil(p->module, e->type); + break; + case Entity_Variable: + args[arg_index] = lb_handle_param_value(p, e->type, e->Variable.param_value, pos); + break; + + case Entity_Constant: + args[arg_index] = lb_const_value(p->module, e->type, e->Constant.value); + break; + default: + GB_PANIC("Unknown entity kind %.*s\n", LIT(entity_strings[e->kind])); + } + } else { + args[arg_index] = lb_emit_conv(p, arg, e->type); } - } else { - args[i] = lb_emit_conv(p, arg, e->type); } } -- cgit v1.2.3 From 180003035659d56a898ddf7de59e8630493c2147 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 21 Jun 2023 14:01:46 +0100 Subject: Correct deferred procedures --- src/llvm_backend_proc.cpp | 196 ++++++++++++++++++++++++++-------------------- 1 file changed, 109 insertions(+), 87 deletions(-) (limited to 'src/llvm_backend_proc.cpp') diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 0beaf376b..48b4b9330 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -1160,7 +1160,13 @@ gb_internal lbValue lb_emit_call(lbProcedure *p, lbValue value, Array c } - Entity **found = map_get(&p->module->procedure_values, value.value); + LLVMValueRef the_proc_value = value.value; + + if (LLVMIsAConstantExpr(the_proc_value)) { + // NOTE(bill): it's a bit cast + the_proc_value = LLVMGetOperand(the_proc_value, 0); + } + Entity **found = map_get(&p->module->procedure_values, the_proc_value); if (found != nullptr) { Entity *e = *found; if (e != nullptr && entity_has_deferred_procedure(e)) { @@ -3156,14 +3162,89 @@ gb_internal void lb_add_values_to_array(lbProcedure *p, Array *args, lb array_add(args, value); } } -gb_internal lbValue lb_build_call_expr_internal_with_arg_split_args(lbProcedure *p, lbValue value, TypeProc *pt, Ast *call, AstSplitArgs *split_args) { - ast_node(ce, CallExpr, call); + +gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) { + lbModule *m = p->module; + + TypeAndValue tv = type_and_value_of_expr(expr); + + ast_node(ce, CallExpr, expr); + + TypeAndValue proc_tv = type_and_value_of_expr(ce->proc); + AddressingMode proc_mode = proc_tv.mode; + if (proc_mode == Addressing_Type) { + GB_ASSERT(ce->args.count == 1); + lbValue x = lb_build_expr(p, ce->args[0]); + lbValue y = lb_emit_conv(p, x, tv.type); + return y; + } + + Ast *proc_expr = unparen_expr(ce->proc); + if (proc_mode == Addressing_Builtin) { + Entity *e = entity_of_node(proc_expr); + BuiltinProcId id = BuiltinProc_Invalid; + if (e != nullptr) { + id = cast(BuiltinProcId)e->Builtin.id; + } else { + id = BuiltinProc_DIRECTIVE; + } + return lb_build_builtin_proc(p, expr, tv, id); + } + + // NOTE(bill): Regular call + lbValue value = {}; + + Entity *proc_entity = entity_of_node(proc_expr); + if (proc_entity != nullptr) { + if (proc_entity->flags & EntityFlag_Disabled) { + GB_ASSERT(tv.type == nullptr); + return {}; + } + } + + if (proc_expr->tav.mode == Addressing_Constant) { + ExactValue v = proc_expr->tav.value; + switch (v.kind) { + case ExactValue_Integer: + { + u64 u = big_int_to_u64(&v.value_integer); + lbValue x = {}; + x.value = LLVMConstInt(lb_type(m, t_uintptr), u, false); + x.type = t_uintptr; + x = lb_emit_conv(p, x, t_rawptr); + value = lb_emit_conv(p, x, proc_expr->tav.type); + break; + } + case ExactValue_Pointer: + { + u64 u = cast(u64)v.value_pointer; + lbValue x = {}; + x.value = LLVMConstInt(lb_type(m, t_uintptr), u, false); + x.type = t_uintptr; + x = lb_emit_conv(p, x, t_rawptr); + value = lb_emit_conv(p, x, proc_expr->tav.type); + break; + } + } + } + + if (value.value == nullptr) { + value = lb_build_expr(p, proc_expr); + } + + GB_ASSERT(value.value != nullptr); + Type *proc_type_ = base_type(value.type); + GB_ASSERT(proc_type_->kind == Type_Proc); + TypeProc *pt = &proc_type_->Proc; + + GB_ASSERT(ce->split_args != nullptr); auto args = array_make(permanent_allocator(), 0, pt->param_count); bool vari_expand = (ce->ellipsis.pos.line != 0); + bool is_c_vararg = pt->c_vararg; - for_array(i, split_args->positional) { + for_array(i, ce->split_args->positional) { Entity *e = pt->params->Tuple.variables[i]; if (e->kind == Entity_TypeName) { array_add(&args, lb_const_nil(p->module, e->type)); @@ -3177,12 +3258,28 @@ gb_internal lbValue lb_build_call_expr_internal_with_arg_split_args(lbProcedure if (pt->variadic && pt->variadic_index == i) { lbValue variadic_args = lb_const_nil(p->module, e->type); - auto variadic = slice(split_args->positional, pt->variadic_index, split_args->positional.count); + auto variadic = slice(ce->split_args->positional, pt->variadic_index, ce->split_args->positional.count); if (variadic.count != 0) { // variadic call argument generation Type *slice_type = e->type; GB_ASSERT(slice_type->kind == Type_Slice); - if (vari_expand) { + + if (is_c_vararg) { + GB_PANIC("TODO #c_vararg"); + GB_ASSERT(!vari_expand); + + Type *elem_type = slice_type->Slice.elem; + + for (Ast *var_arg : variadic) { + lbValue arg = lb_build_expr(p, var_arg); + if (!is_type_any(elem_type)) { + array_add(&args, lb_emit_conv(p, arg, elem_type)); + } else { + array_add(&args, lb_emit_conv(p, arg, default_type(arg.type))); + } + } + break; + } else if (vari_expand) { GB_ASSERT(variadic.count == 1); variadic_args = lb_build_expr(p, variadic[0]); variadic_args = lb_emit_conv(p, variadic_args, slice_type); @@ -3219,14 +3316,14 @@ gb_internal lbValue lb_build_call_expr_internal_with_arg_split_args(lbProcedure break; } else { - lbValue value = lb_build_expr(p, split_args->positional[i]); + lbValue value = lb_build_expr(p, ce->split_args->positional[i]); lb_add_values_to_array(p, &args, value); } } array_resize(&args, pt->param_count); - for (Ast *arg : split_args->named) { + for (Ast *arg : ce->split_args->named) { ast_node(fv, FieldValue, arg); GB_ASSERT(fv->field->kind == Ast_Ident); String name = fv->field->Ident.token.string; @@ -3243,6 +3340,7 @@ gb_internal lbValue lb_build_call_expr_internal_with_arg_split_args(lbProcedure if (pt->params != nullptr) { + GB_ASSERT(args.count >= pt->params->Tuple.variables.count); for_array(arg_index, pt->params->Tuple.variables) { Entity *e = pt->params->Tuple.variables[arg_index]; @@ -3269,84 +3367,8 @@ gb_internal lbValue lb_build_call_expr_internal_with_arg_split_args(lbProcedure } - return lb_emit_call(p, value, args, ce->inlining); -} - -gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) { - lbModule *m = p->module; - - TypeAndValue tv = type_and_value_of_expr(expr); - - ast_node(ce, CallExpr, expr); - - TypeAndValue proc_tv = type_and_value_of_expr(ce->proc); - AddressingMode proc_mode = proc_tv.mode; - if (proc_mode == Addressing_Type) { - GB_ASSERT(ce->args.count == 1); - lbValue x = lb_build_expr(p, ce->args[0]); - lbValue y = lb_emit_conv(p, x, tv.type); - return y; - } - - Ast *proc_expr = unparen_expr(ce->proc); - if (proc_mode == Addressing_Builtin) { - Entity *e = entity_of_node(proc_expr); - BuiltinProcId id = BuiltinProc_Invalid; - if (e != nullptr) { - id = cast(BuiltinProcId)e->Builtin.id; - } else { - id = BuiltinProc_DIRECTIVE; - } - return lb_build_builtin_proc(p, expr, tv, id); - } - - // NOTE(bill): Regular call - lbValue value = {}; - - Entity *proc_entity = entity_of_node(proc_expr); - if (proc_entity != nullptr) { - if (proc_entity->flags & EntityFlag_Disabled) { - GB_ASSERT(tv.type == nullptr); - return {}; - } - } - - if (proc_expr->tav.mode == Addressing_Constant) { - ExactValue v = proc_expr->tav.value; - switch (v.kind) { - case ExactValue_Integer: - { - u64 u = big_int_to_u64(&v.value_integer); - lbValue x = {}; - x.value = LLVMConstInt(lb_type(m, t_uintptr), u, false); - x.type = t_uintptr; - x = lb_emit_conv(p, x, t_rawptr); - value = lb_emit_conv(p, x, proc_expr->tav.type); - break; - } - case ExactValue_Pointer: - { - u64 u = cast(u64)v.value_pointer; - lbValue x = {}; - x.value = LLVMConstInt(lb_type(m, t_uintptr), u, false); - x.type = t_uintptr; - x = lb_emit_conv(p, x, t_rawptr); - value = lb_emit_conv(p, x, proc_expr->tav.type); - break; - } - } - } - - if (value.value == nullptr) { - value = lb_build_expr(p, proc_expr); - } - - GB_ASSERT(value.value != nullptr); - Type *proc_type_ = base_type(value.type); - GB_ASSERT(proc_type_->kind == Type_Proc); - TypeProc *pt = &proc_type_->Proc; - - GB_ASSERT(ce->split_args != nullptr); - return lb_build_call_expr_internal_with_arg_split_args(p, value, pt, expr, ce->split_args); + isize final_count = is_c_vararg ? args.count : pt->param_count; + auto call_args = array_slice(args, 0, final_count); + return lb_emit_call(p, value, call_args, ce->inlining); } -- cgit v1.2.3 From c9fb078c0f1e09edcc023dce30dd0ca04f20cc24 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 21 Jun 2023 14:07:14 +0100 Subject: Handle `#c_vararg` --- src/llvm_backend_proc.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'src/llvm_backend_proc.cpp') diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 48b4b9330..7cf82b208 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -3265,17 +3265,16 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) { GB_ASSERT(slice_type->kind == Type_Slice); if (is_c_vararg) { - GB_PANIC("TODO #c_vararg"); GB_ASSERT(!vari_expand); Type *elem_type = slice_type->Slice.elem; for (Ast *var_arg : variadic) { lbValue arg = lb_build_expr(p, var_arg); - if (!is_type_any(elem_type)) { - array_add(&args, lb_emit_conv(p, arg, elem_type)); - } else { + if (is_type_any(elem_type)) { array_add(&args, lb_emit_conv(p, arg, default_type(arg.type))); + } else { + array_add(&args, lb_emit_conv(p, arg, elem_type)); } } break; @@ -3321,7 +3320,9 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) { } } - array_resize(&args, pt->param_count); + if (!is_c_vararg) { + array_resize(&args, pt->param_count); + } for (Ast *arg : ce->split_args->named) { ast_node(fv, FieldValue, arg); @@ -3343,6 +3344,9 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) { GB_ASSERT(args.count >= pt->params->Tuple.variables.count); for_array(arg_index, pt->params->Tuple.variables) { Entity *e = pt->params->Tuple.variables[arg_index]; + if (pt->variadic && arg_index == pt->variadic_index) { + continue; + } lbValue arg = args[arg_index]; if (arg.value == nullptr) { @@ -3366,7 +3370,6 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) { } } - isize final_count = is_c_vararg ? args.count : pt->param_count; auto call_args = array_slice(args, 0, final_count); return lb_emit_call(p, value, call_args, ce->inlining); -- cgit v1.2.3 From ea76e09ea741f0bf090d967cf3aaded59079d001 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 21 Jun 2023 14:30:39 +0100 Subject: Fix empty varargs --- src/llvm_backend_proc.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/llvm_backend_proc.cpp') diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 7cf82b208..47137c540 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -3345,6 +3345,9 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) { for_array(arg_index, pt->params->Tuple.variables) { Entity *e = pt->params->Tuple.variables[arg_index]; if (pt->variadic && arg_index == pt->variadic_index) { + if (!is_c_vararg && args[arg_index].value == 0) { + args[arg_index] = lb_const_nil(p->module, e->type); + } continue; } -- cgit v1.2.3