aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2025-09-21 18:46:28 -0400
committerBruce Hill <bruce@bruce-hill.com>2025-09-21 18:46:28 -0400
commitb84e7c69ae52155c4902cf24b4f9bb86d65d5f9e (patch)
treea5b782209c29e6b2938b060d96596f47ec4f783a
parent0d489659597f9d3e6b69f92d2ca001a8dd5bf6cd (diff)
Be more lenient with underscore fields and arguments.
-rw-r--r--CHANGES.md3
-rw-r--r--src/compile/functions.c3
-rw-r--r--src/compile/structs.c4
-rw-r--r--src/typecheck.c16
4 files changed, 9 insertions, 17 deletions
diff --git a/CHANGES.md b/CHANGES.md
index 10283b0e..8f5704e0 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -21,6 +21,9 @@
- Deprecated `>> ... = ...` form of doctests. They are now called "debug logs"
and you can specify multiple values: `>> a, b, c`
- Deprecated `defer` statement
+- Struct fields that start with underscores can be accessed again and function
+ arguments that start with underscore can be passed (but only as keyword
+ arguments).
- Added a `--format` flag to the `tomo` binary that autoformats your code
(currently unstable, do not rely on it just yet).
- Standardized text methods for Unicode encodings:
diff --git a/src/compile/functions.c b/src/compile/functions.c
index abe0a588..e3dbc2e7 100644
--- a/src/compile/functions.c
+++ b/src/compile/functions.c
@@ -155,7 +155,8 @@ Text_t compile_function_call(env_t *env, ast_t *ast) {
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)");
+ code_err(ast, "You can't pass underscore arguments to this function as positional arguments. You must "
+ "use keyword arguments.");
} else {
arg_t *args = NULL;
for (arg_ast_t *a = call->args; a; a = a->next)
diff --git a/src/compile/structs.c b/src/compile/structs.c
index aaebef22..2e7217f6 100644
--- a/src/compile/structs.c
+++ b/src/compile/structs.c
@@ -127,7 +127,9 @@ Text_t compile_struct_literal(env_t *env, ast_t *ast, type_t *t, arg_ast_t *args
return Texts("((", compile_type(t), "){", compile_arguments(env, ast, struct_->fields, args), "})");
} else if (!constructor_opts.underscores
&& is_valid_call(env, struct_->fields, args, (call_opts_t){.promotion = true, .underscores = true})) {
- code_err(ast, "This constructor uses private fields that are not exposed.");
+ code_err(ast, "This constructor is passing private fields (those starting with underscores) as positional "
+ "arguments, which is not allowed. \n"
+ " If you need to pass these fields, use a keyword argument.");
}
code_err(ast, "I could not find a constructor matching these arguments for the struct ", type_to_text(t));
}
diff --git a/src/typecheck.c b/src/typecheck.c
index 9d33e119..6cd87289 100644
--- a/src/typecheck.c
+++ b/src/typecheck.c
@@ -905,16 +905,6 @@ type_t *get_type(env_t *env, ast_t *ast) {
case FieldAccess: {
DeclareMatch(access, ast, FieldAccess);
type_t *fielded_t = get_type(env, access->fielded);
- if (access->field[0] == '_') {
- if (!env->current_type
- || !type_eq(env->current_type, fielded_t->tag == TypeInfoType ? Match(fielded_t, TypeInfoType)->type
- : value_type(fielded_t)))
- code_err(ast, "Fields beginning with underscores like '", access->field,
- "' can't be accessed outside the scope where the type (",
- type_to_text(fielded_t->tag == TypeInfoType ? Match(fielded_t, TypeInfoType)->type
- : value_type(fielded_t)),
- ") is defined.");
- }
if (fielded_t->tag == ModuleType) {
const char *name = Match(fielded_t, ModuleType)->name;
env_t *module_env = Table$str_get(*env->imports, name);
@@ -1049,9 +1039,7 @@ type_t *get_type(env_t *env, ast_t *ast) {
if (call->name[0] == '_') {
if (env->current_type == NULL || !type_eq(env->current_type, self_value_t))
code_err(ast, "You can't call private methods starting with underscore (like '", call->name,
- "') "
- "outside of the place where the type (",
- type_to_text(self_value_t), ") is defined.");
+ "') outside of the place where the type (", type_to_text(self_value_t), ") is defined.");
}
type_t *field_type = get_field_type(self_value_t, call->name);
if (field_type && field_type->tag == ClosureType) field_type = Match(field_type, ClosureType)->fn;
@@ -1625,10 +1613,8 @@ bool is_valid_call(env_t *env, arg_t *spec_args, arg_ast_t *call_args, call_opts
// Populate keyword args:
for (arg_ast_t *call_arg = call_args; call_arg; call_arg = call_arg->next) {
if (!call_arg->name) continue;
- if (!options.underscores && call_arg->name[0] == '_') return false;
for (arg_t *spec_arg = spec_args; spec_arg; spec_arg = spec_arg->next) {
- if (!options.underscores && spec_arg->name[0] == '_') continue;
if (!(streq(call_arg->name, spec_arg->name) || (spec_arg->alias && streq(call_arg->name, spec_arg->alias))))
continue;
type_t *spec_type = get_arg_type(env, spec_arg);