aboutsummaryrefslogtreecommitdiff
path: root/src/compile.c
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2025-08-24 14:18:22 -0400
committerBruce Hill <bruce@bruce-hill.com>2025-08-24 14:18:22 -0400
commitbe534f5e511a1d3836254b827cdaa2b8c309f5c4 (patch)
tree478fc9ede3a1c61220d3b02a2524fb32d53e7300 /src/compile.c
parent788922fa2437c5b680b57d8adaaac9012fd5aba4 (diff)
Constructors and functions with underscore arguments should be allowed to be called, but
only if the underscore arguments are not provided but are implicit from the default values. Same for constructing structs with private fields.
Diffstat (limited to 'src/compile.c')
-rw-r--r--src/compile.c50
1 files changed, 33 insertions, 17 deletions
diff --git a/src/compile.c b/src/compile.c
index 6bb528a0..262608c5 100644
--- a/src/compile.c
+++ b/src/compile.c
@@ -579,7 +579,7 @@ static Text_t compile_binary_op(env_t *env, ast_t *ast) {
DeclareMatch(fn, b->type, FunctionType);
if (type_eq(fn->ret, rhs_t)) {
arg_ast_t *args = new (arg_ast_t, .value = binop.rhs, .next = new (arg_ast_t, .value = binop.lhs));
- if (is_valid_call(env, fn->args, args, true))
+ if (is_valid_call(env, fn->args, args, (call_opts_t){.promotion = true}))
return Texts(b->code, "(", compile_arguments(env, ast, fn->args, args), ")");
}
}
@@ -589,7 +589,7 @@ static Text_t compile_binary_op(env_t *env, ast_t *ast) {
DeclareMatch(fn, b->type, FunctionType);
if (type_eq(fn->ret, lhs_t)) {
arg_ast_t *args = new (arg_ast_t, .value = binop.lhs, .next = new (arg_ast_t, .value = binop.rhs));
- if (is_valid_call(env, fn->args, args, true))
+ if (is_valid_call(env, fn->args, args, (call_opts_t){.promotion = true}))
return Texts(b->code, "(", compile_arguments(env, ast, fn->args, args), ")");
}
}
@@ -599,7 +599,7 @@ static Text_t compile_binary_op(env_t *env, ast_t *ast) {
DeclareMatch(fn, b->type, FunctionType);
if (type_eq(fn->ret, lhs_t)) {
arg_ast_t *args = new (arg_ast_t, .value = binop.lhs, .next = new (arg_ast_t, .value = binop.rhs));
- if (is_valid_call(env, fn->args, args, true))
+ if (is_valid_call(env, fn->args, args, (call_opts_t){.promotion = true}))
return Texts(b->code, "(", compile_arguments(env, ast, fn->args, args), ")");
}
}
@@ -609,7 +609,7 @@ static Text_t compile_binary_op(env_t *env, ast_t *ast) {
DeclareMatch(fn, b->type, FunctionType);
if (type_eq(fn->ret, lhs_t)) {
arg_ast_t *args = new (arg_ast_t, .value = binop.lhs, .next = new (arg_ast_t, .value = binop.rhs));
- if (is_valid_call(env, fn->args, args, true))
+ if (is_valid_call(env, fn->args, args, (call_opts_t){.promotion = true}))
return Texts(b->code, "(", compile_arguments(env, ast, fn->args, args), ")");
}
}
@@ -3466,6 +3466,24 @@ Text_t compile(env_t *env, ast_t *ast) {
type_t *fn_t = get_type(env, call->fn);
if (fn_t->tag == FunctionType) {
Text_t fn = compile(env, call->fn);
+ if (!is_valid_call(env, Match(fn_t, FunctionType)->args, call->args, (call_opts_t){.promotion = true})) {
+ if (is_valid_call(env, Match(fn_t, FunctionType)->args, call->args,
+ (call_opts_t){.promotion = true, .underscores = true})) {
+ code_err(ast, "You can't pass underscore arguments to this function (those are private)");
+ } else {
+ arg_t *args = NULL;
+ for (arg_ast_t *a = call->args; a; a = a->next)
+ args = new (arg_t, .name = a->name, .type = get_type(env, a->value), .next = args);
+ REVERSE_LIST(args);
+ code_err(ast,
+ "This function's public 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)));
+ }
+ }
return Texts(fn, "(", compile_arguments(env, ast, Match(fn_t, FunctionType)->args, call->args), ")");
} else if (fn_t->tag == TypeInfoType) {
type_t *t = Match(fn_t, TypeInfoType)->type;
@@ -3509,21 +3527,19 @@ Text_t compile(env_t *env, ast_t *ast) {
")");
} else if (t->tag == StructType) {
DeclareMatch(struct_, t, StructType);
- if (!struct_->opaque && is_valid_call(env, struct_->fields, call->args, true)) {
- if (env->current_type == NULL || !type_eq(env->current_type, t)) {
- for (arg_t *field = struct_->fields; field; field = field->next) {
- if (field->name[0] == '_')
- code_err(ast, "This struct can't be "
- "initialized directly because it "
- "has private fields (starting "
- "with underscore).\n"
- "Use a `convert` or `func` to "
- "instantiate the type "
- "instead.");
- }
- }
+ if (struct_->opaque) code_err(ast, "This struct is opaque, so I don't know what's inside it!");
+
+ call_opts_t constructor_opts = {
+ .promotion = true,
+ .underscores = (env->current_type != NULL && type_eq(env->current_type, t)),
+ };
+ if (is_valid_call(env, struct_->fields, call->args, constructor_opts)) {
return Texts("((", compile_type(t), "){", compile_arguments(env, ast, struct_->fields, call->args),
"})");
+ } else if (!constructor_opts.underscores
+ && is_valid_call(env, struct_->fields, call->args,
+ (call_opts_t){.promotion = true, .underscores = true})) {
+ code_err(ast, "This constructor uses private fields that are not exposed.");
}
}
code_err(ast,