aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2025-11-23 13:52:15 -0500
committerBruce Hill <bruce@bruce-hill.com>2025-11-23 13:52:15 -0500
commit80505a7eb147422226d1b86da17f516982d0f4c8 (patch)
tree9265fd867d115711192705e6688a29df573fd057
parent0fa9a52090eb5d9ce88220c0134a8d2af6eb8d94 (diff)
Better error messages and bugfix for compile_to_type logic
-rw-r--r--src/compile/functions.c12
-rw-r--r--src/typecheck.c25
-rw-r--r--src/types.c21
-rw-r--r--src/types.h1
4 files changed, 33 insertions, 26 deletions
diff --git a/src/compile/functions.c b/src/compile/functions.c
index 4a2812ba..cce93e3d 100644
--- a/src/compile/functions.c
+++ b/src/compile/functions.c
@@ -163,12 +163,12 @@ Text_t compile_function_call(env_t *env, ast_t *ast) {
args = new (arg_t, .name = a->name, .type = get_type(env, a->value), .next = args);
REVERSE_LIST(args);
code_err(ast,
- "This function's signature doesn't match this call site.\n"
- "The signature is: ",
- type_to_text(fn_t),
- "\n"
- "But it's being called with: ",
- type_to_text(Type(FunctionType, .args = args)));
+ "This function's signature doesn't match this call site. \n"
+ " The function takes these args: (",
+ arg_types_to_text(Match(fn_t, FunctionType)->args, ", "),
+ ") \n"
+ " But it's being called with: (",
+ arg_types_to_text(args, ", "), ")");
}
}
return Texts(fn, "(", compile_arguments(env, ast, Match(fn_t, FunctionType)->args, call->args), ")");
diff --git a/src/typecheck.c b/src/typecheck.c
index 27bb62c6..98fbf6da 100644
--- a/src/typecheck.c
+++ b/src/typecheck.c
@@ -1588,8 +1588,9 @@ bool is_valid_call(env_t *env, arg_t *spec_args, arg_ast_t *call_args, call_opts
for (; unused_args; unused_args = unused_args->next) {
if (unused_args->name) continue; // Already handled the keyword args
if (options.promotion) {
- if (!can_compile_to_type(arg_scope, unused_args->value, spec_type))
+ if (!can_compile_to_type(arg_scope, unused_args->value, spec_type)) {
return false; // Positional arg trying to fill in
+ }
} else {
type_t *call_type = get_arg_ast_type(arg_scope, unused_args);
type_t *complete_call_type =
@@ -1701,16 +1702,16 @@ PUREFUNC bool can_compile_to_type(env_t *env, ast_t *ast, type_t *needed) {
if (is_numeric_type(needed) && ast->tag == Int) return true;
if (needed->tag == NumType && ast->tag == Num) return true;
- needed = non_optional(needed);
- if (needed->tag == ListType && ast->tag == List) {
- type_t *item_type = Match(needed, ListType)->item_type;
+ type_t *non_optional_needed = non_optional(needed);
+ if (non_optional_needed->tag == ListType && ast->tag == List) {
+ type_t *item_type = Match(non_optional_needed, ListType)->item_type;
for (ast_list_t *item = Match(ast, List)->items; item; item = item->next) {
if (!can_compile_to_type(env, item->ast, item_type)) return false;
}
return true;
- } else if (needed->tag == TableType && ast->tag == Table) {
- type_t *key_type = Match(needed, TableType)->key_type;
- type_t *value_type = Match(needed, TableType)->value_type;
+ } else if (non_optional_needed->tag == TableType && ast->tag == Table) {
+ type_t *key_type = Match(non_optional_needed, TableType)->key_type;
+ type_t *value_type = Match(non_optional_needed, TableType)->value_type;
for (ast_list_t *entry = Match(ast, Table)->entries; entry; entry = entry->next) {
if (entry->ast->tag != TableEntry) continue; // TODO: fix this
DeclareMatch(e, entry->ast, TableEntry);
@@ -1725,16 +1726,16 @@ PUREFUNC bool can_compile_to_type(env_t *env, ast_t *ast, type_t *needed) {
if (type_eq(actual, needed)) return true;
if (actual->tag == OptionalType && needed->tag == OptionalType) return can_promote(actual, needed);
- if (needed->tag == PointerType) {
- DeclareMatch(ptr, needed, PointerType);
+ if (non_optional_needed->tag == PointerType) {
+ DeclareMatch(ptr, non_optional_needed, PointerType);
if (ast->tag == HeapAllocate)
return !ptr->is_stack && can_compile_to_type(env, Match(ast, HeapAllocate)->value, ptr->pointed);
else if (ast->tag == StackReference)
return ptr->is_stack && can_compile_to_type(env, Match(ast, StackReference)->value, ptr->pointed);
- else return can_promote(actual, needed);
- } else if (actual->tag == OptionalType && needed->tag != OptionalType) {
+ else return can_promote(actual, non_optional_needed);
+ } else if (actual->tag == OptionalType && non_optional_needed->tag != OptionalType) {
return false;
} else {
- return can_promote(actual, needed);
+ return can_promote(actual, non_optional_needed);
}
}
diff --git a/src/types.c b/src/types.c
index 51555560..edfee27d 100644
--- a/src/types.c
+++ b/src/types.c
@@ -12,6 +12,15 @@
#include "stdlib/util.h"
#include "types.h"
+Text_t arg_types_to_text(arg_t *args, const char *separator) {
+ Text_t text = EMPTY_TEXT;
+ for (arg_t *arg = args; arg; arg = arg->next) {
+ text = Texts(text, type_to_text(arg->type));
+ if (arg->next) text = Texts(text, separator);
+ }
+ return text;
+}
+
Text_t type_to_text(type_t *t) {
if (!t) return Text("(Unknown type)");
@@ -45,15 +54,11 @@ Text_t type_to_text(type_t *t) {
return type_to_text(Match(t, ClosureType)->fn);
}
case FunctionType: {
- Text_t c = Text("func(");
DeclareMatch(fn, t, FunctionType);
- for (arg_t *arg = fn->args; arg; arg = arg->next) {
- c = Texts(c, type_to_text(arg->type));
- if (arg->next) c = Texts(c, ",");
- }
- if (fn->ret && fn->ret->tag != VoidType) c = Texts(c, fn->args ? " -> " : "-> ", type_to_text(fn->ret));
- c = Texts(c, ")");
- return c;
+ Text_t text = Texts("func(", arg_types_to_text(fn->args, ","));
+ if (fn->ret && fn->ret->tag != VoidType) text = Texts(text, fn->args ? " -> " : "-> ", type_to_text(fn->ret));
+ text = Texts(text, ")");
+ return text;
}
case StructType: {
DeclareMatch(struct_, t, StructType);
diff --git a/src/types.h b/src/types.h
index 2a94a512..b8f9a42f 100644
--- a/src/types.h
+++ b/src/types.h
@@ -136,6 +136,7 @@ struct type_s {
_make_function_type(ret, sizeof((arg_t[]){__VA_ARGS__}) / sizeof(arg_t), (arg_t[]){__VA_ARGS__})
Text_t type_to_text(type_t *t);
+Text_t arg_types_to_text(arg_t *args, const char *separator);
const char *get_type_name(type_t *t);
PUREFUNC bool type_eq(type_t *a, type_t *b);
PUREFUNC bool type_is_a(type_t *t, type_t *req);