aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compile.c38
1 files changed, 23 insertions, 15 deletions
diff --git a/compile.c b/compile.c
index daed549c..cc59dc0f 100644
--- a/compile.c
+++ b/compile.c
@@ -15,6 +15,7 @@
#include "builtins/util.h"
static CORD compile_to_pointer_depth(env_t *env, ast_t *ast, int64_t target_depth, bool allow_optional);
+static env_t *arg_scope(env_t *env, type_t *t);
CORD compile_type_ast(env_t *env, type_ast_t *t)
{
@@ -572,15 +573,7 @@ CORD compile_statement(env_t *env, ast_t *ast)
auto ret = Match(ast, Return)->value;
assert(env->fn_ctx->return_type);
if (ret) {
- if (env->fn_ctx->return_type->tag == EnumType) {
- env = fresh_scope(env);
- env_t *ns_env = Match(env->fn_ctx->return_type, EnumType)->env;
- for (tag_t *tag = Match(env->fn_ctx->return_type, EnumType)->tags; tag; tag = tag->next) {
- if (get_binding(env, tag->name))
- continue;
- set_binding(env, tag->name, get_binding(ns_env, tag->name));
- }
- }
+ env = arg_scope(env, env->fn_ctx->return_type);
type_t *ret_t = get_type(env, ret);
CORD value = compile(env, ret);
if (!promote(env, &value, ret_t, env->fn_ctx->return_type))
@@ -912,6 +905,19 @@ CORD compile_to_pointer_depth(env_t *env, ast_t *ast, int64_t target_depth, bool
return val;
}
+env_t *arg_scope(env_t *env, type_t *t)
+{
+ if (t->tag != EnumType) return env;
+ env = fresh_scope(env);
+ env_t *ns_env = Match(t, EnumType)->env;
+ for (tag_t *tag = Match(t, EnumType)->tags; tag; tag = tag->next) {
+ if (get_binding(env, tag->name))
+ continue;
+ set_binding(env, tag->name, get_binding(ns_env, tag->name));
+ }
+ return env;
+}
+
static CORD compile_arguments(env_t *env, ast_t *call_ast, arg_t *spec_args, arg_ast_t *call_args)
{
table_t used_args = {};
@@ -922,9 +928,10 @@ static CORD compile_arguments(env_t *env, ast_t *call_ast, arg_t *spec_args, arg
if (spec_arg->name) {
for (arg_ast_t *call_arg = call_args; call_arg; call_arg = call_arg->next) {
if (call_arg->name && streq(call_arg->name, spec_arg->name)) {
- type_t *actual_t = get_type(env, call_arg->value);
- CORD value = compile(env, call_arg->value);
- if (!promote(env, &value, actual_t, spec_arg->type))
+ env_t *arg_env = arg_scope(env, spec_arg->type);
+ type_t *actual_t = get_type(arg_env, call_arg->value);
+ CORD value = compile(arg_env, call_arg->value);
+ if (!promote(arg_env, &value, actual_t, spec_arg->type))
code_err(call_arg->value, "This argument is supposed to be a %T, but this value is a %T", spec_arg->type, actual_t);
Table$str_set(&used_args, call_arg->name, call_arg);
if (code) code = CORD_cat(code, ", ");
@@ -939,9 +946,10 @@ static CORD compile_arguments(env_t *env, ast_t *call_ast, arg_t *spec_args, arg
if (call_arg->name) continue;
const char *pseudoname = heap_strf("%ld", i++);
if (!Table$str_get(used_args, pseudoname)) {
- type_t *actual_t = get_type(env, call_arg->value);
- CORD value = compile(env, call_arg->value);
- if (!promote(env, &value, actual_t, spec_arg->type))
+ env_t *arg_env = arg_scope(env, spec_arg->type);
+ type_t *actual_t = get_type(arg_env, call_arg->value);
+ CORD value = compile(arg_env, call_arg->value);
+ if (!promote(arg_env, &value, actual_t, spec_arg->type))
code_err(call_arg->value, "This argument is supposed to be a %T, but this value is a %T", spec_arg->type, actual_t);
Table$str_set(&used_args, pseudoname, call_arg);
if (code) code = CORD_cat(code, ", ");