aboutsummaryrefslogtreecommitdiff
path: root/src/compile
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2025-09-06 13:51:18 -0400
committerBruce Hill <bruce@bruce-hill.com>2025-09-06 13:51:18 -0400
commitaa15f0f78214cefa9fabace61c119e01812a3050 (patch)
treec6df00685eca8ca2f9626ea8777b0ecee3828e15 /src/compile
parent94ff047dd74cd3ad793f68503729a0fe004c10f4 (diff)
Refactor a bit in order to catch issue with ConvertDefs creating
infinite loops
Diffstat (limited to 'src/compile')
-rw-r--r--src/compile/files.c6
-rw-r--r--src/compile/functions.c20
-rw-r--r--src/compile/statements.c22
3 files changed, 22 insertions, 26 deletions
diff --git a/src/compile/files.c b/src/compile/files.c
index a6af2300..c250e6cc 100644
--- a/src/compile/files.c
+++ b/src/compile/files.c
@@ -95,13 +95,13 @@ static Text_t compile_top_level_code(env_t *env, ast_t *ast) {
return compile_function(env, name_code, ast, &env->code->staticdefs);
}
case ConvertDef: {
- type_t *type = get_function_def_type(env, ast);
- const char *name = get_type_name(Match(type, FunctionType)->ret);
+ type_t *type = get_function_return_type(env, ast);
+ const char *name = get_type_name(type);
if (!name)
code_err(ast,
"Conversions are only supported for text, struct, and enum "
"types, not ",
- type_to_str(Match(type, FunctionType)->ret));
+ type_to_str(type));
Text_t name_code =
namespace_name(env, env->namespace, Texts(name, "$", get_line_number(ast->file, ast->start)));
return compile_function(env, name_code, ast, &env->code->staticdefs);
diff --git a/src/compile/functions.c b/src/compile/functions.c
index 6caefa8b..f04a3b59 100644
--- a/src/compile/functions.c
+++ b/src/compile/functions.c
@@ -256,18 +256,7 @@ Text_t compile_lambda(env_t *env, ast_t *ast) {
set_binding(body_scope, arg->name, arg_type, Texts("_$", arg->name));
}
- type_t *ret_t = get_type(body_scope, lambda->body);
- if (ret_t->tag == ReturnType) ret_t = Match(ret_t, ReturnType)->ret;
-
- if (lambda->ret_type) {
- type_t *declared = parse_type_ast(env, lambda->ret_type);
- if (can_promote(ret_t, declared)) ret_t = declared;
- else
- code_err(ast, "This function was declared to return a value of type ", type_to_str(declared),
- ", but actually returns a value of type ", type_to_str(ret_t));
- }
-
- body_scope->fn_ret = ret_t;
+ body_scope->fn = ast;
Table_t closed_vars = get_closed_vars(env, lambda->args, ast);
if (Table$length(closed_vars) > 0) { // Create a typedef for the lambda's closure userdata
@@ -289,6 +278,7 @@ Text_t compile_lambda(env_t *env, ast_t *ast) {
env->code->local_typedefs = Texts(env->code->local_typedefs, def);
}
+ type_t *ret_t = get_function_return_type(env, ast);
Text_t code = Texts("static ", compile_type(ret_t), " ", name, "(");
for (arg_ast_t *arg = lambda->args; arg; arg = arg->next) {
type_t *arg_type = get_arg_ast_type(env, arg);
@@ -623,7 +613,7 @@ Text_t compile_function(env_t *env, Text_t name_code, ast_t *ast, Text_t *static
bool is_private = false;
const char *function_name;
arg_ast_t *args;
- type_t *ret_t;
+ type_t *ret_t = get_function_return_type(env, ast);
ast_t *body;
ast_t *cache;
bool is_inline;
@@ -632,14 +622,12 @@ Text_t compile_function(env_t *env, Text_t name_code, ast_t *ast, Text_t *static
function_name = Match(fndef->name, Var)->name;
is_private = function_name[0] == '_';
args = fndef->args;
- ret_t = fndef->ret_type ? parse_type_ast(env, fndef->ret_type) : Type(VoidType);
body = fndef->body;
cache = fndef->cache;
is_inline = fndef->is_inline;
} else {
DeclareMatch(convertdef, ast, ConvertDef);
args = convertdef->args;
- ret_t = convertdef->ret_type ? parse_type_ast(env, convertdef->ret_type) : Type(VoidType);
function_name = get_type_name(ret_t);
if (!function_name)
code_err(ast,
@@ -689,7 +677,7 @@ Text_t compile_function(env_t *env, Text_t name_code, ast_t *ast, Text_t *static
set_binding(body_scope, arg->name, arg_type, Texts("_$", arg->name));
}
- body_scope->fn_ret = ret_t;
+ body_scope->fn = ast;
type_t *body_type = get_type(body_scope, body);
if (ret_t->tag == AbortType) {
diff --git a/src/compile/statements.c b/src/compile/statements.c
index a7c5214a..4e37838c 100644
--- a/src/compile/statements.c
+++ b/src/compile/statements.c
@@ -131,7 +131,7 @@ static Text_t _compile_statement(env_t *env, ast_t *ast) {
return code;
}
case Return: {
- if (!env->fn_ret) code_err(ast, "This return statement is not inside any function");
+ if (!env->fn) code_err(ast, "This return statement is not inside any function");
ast_t *ret = Match(ast, Return)->value;
Text_t code = EMPTY_TEXT;
@@ -139,22 +139,30 @@ static Text_t _compile_statement(env_t *env, ast_t *ast) {
code = Texts(code, compile_statement(deferred->defer_env, deferred->block));
}
+ type_t *ret_type = get_function_return_type(env, env->fn);
if (ret) {
- if (env->fn_ret->tag == VoidType || env->fn_ret->tag == AbortType)
+ if (ret_type->tag == VoidType || ret_type->tag == AbortType)
code_err(ast, "This function is not supposed to return any values, "
"according to its type signature");
- env = with_enum_scope(env, env->fn_ret);
- Text_t value = compile_to_type(env, ret, env->fn_ret);
+ env = with_enum_scope(env, ret_type);
+ if (env->fn->tag == ConvertDef) {
+ type_t *value_type = get_type(env, ret);
+ if (!type_eq(value_type, ret_type)) {
+ code_err(ret, "This value is a ", type_to_text(value_type),
+ " but this conversion needs an explicit ", type_to_text(ret_type));
+ }
+ }
+ Text_t value = compile_to_type(env, ret, ret_type);
if (env->deferred) {
- code = Texts(compile_declaration(env->fn_ret, Text("ret")), " = ", value, ";\n", code);
+ code = Texts(compile_declaration(ret_type, Text("ret")), " = ", value, ";\n", code);
value = Text("ret");
}
return Texts(code, "return ", value, ";");
} else {
- if (env->fn_ret->tag != VoidType)
- code_err(ast, "This function expects you to return a ", type_to_str(env->fn_ret), " value");
+ if (ret_type->tag != VoidType)
+ code_err(ast, "This function expects you to return a ", type_to_text(ret_type), " value");
return Texts(code, "return;");
}
}