aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2024-05-15 13:39:35 -0400
committerBruce Hill <bruce@bruce-hill.com>2024-05-15 13:39:35 -0400
commit88094358671af5e2a1bd3b3b3a7e50a8426b6943 (patch)
treee6222df7c5162c322f7901b0d23e5498b5a2716e
parentaf0c285d9643f6073df9ea83efd9b92a90dc74b9 (diff)
Bugfix for assignment not properly promoting (and checking) values, plus
adding support for unqualified enums in assignment
-rw-r--r--compile.c31
1 files changed, 23 insertions, 8 deletions
diff --git a/compile.c b/compile.c
index cc59dc0f..545c43a1 100644
--- a/compile.c
+++ b/compile.c
@@ -266,11 +266,12 @@ CORD compile_statement(env_t *env, ast_t *ast)
auto assign = Match(test->expr, Assign);
if (!assign->targets->next && assign->targets->ast->tag == Var) {
// Common case: assigning to one variable:
+ type_t *t = get_type(env, assign->targets->ast);
return CORD_asprintf(
"test(({ %r; &%r; }), %r, %r, %r, %ld, %ld);",
- compile_assignment(env, assign->targets->ast, compile(env, assign->values->ast)),
+ compile_assignment(env, assign->targets->ast, compile(arg_scope(env, t), assign->values->ast)),
compile(env, assign->targets->ast),
- compile_type_info(env, get_type(env, assign->targets->ast)),
+ compile_type_info(env, t),
compile(env, WrapAST(test->expr, TextLiteral, .cord=test->output)),
compile(env, WrapAST(test->expr, TextLiteral, .cord=test->expr->file->filename)),
(int64_t)(test->expr->start - test->expr->file->text),
@@ -285,7 +286,7 @@ CORD compile_statement(env_t *env, ast_t *ast)
for (ast_list_t *target = assign->targets, *value = assign->values; target && value; target = target->next, value = value->next) {
type_t *target_type = get_type(env, target->ast);
type_t *value_type = get_type(env, value->ast);
- CORD val_code = compile(env, value->ast);
+ CORD val_code = compile(arg_scope(env, target_type), value->ast);
if (!promote(env, &val_code, value_type, target_type))
code_err(value->ast, "This %T value cannot be converted to a %T type", value_type, target_type);
CORD_appendf(&code, "%r $%ld = %r;\n", compile_type(env, target_type), i++, val_code);
@@ -334,14 +335,28 @@ CORD compile_statement(env_t *env, ast_t *ast)
}
case Assign: {
auto assign = Match(ast, Assign);
- // Single assignment:
- if (assign->targets && !assign->targets->next)
- return compile_assignment(env, assign->targets->ast, compile(env, assign->values->ast));
+ // Single assignment, no temp vars needed:
+ if (assign->targets && !assign->targets->next) {
+ type_t *lhs_t = get_type(env, assign->targets->ast);
+ env_t *val_env = arg_scope(env, lhs_t);
+ type_t *rhs_t = get_type(val_env, assign->values->ast);
+ CORD val = compile(val_env, assign->values->ast);
+ if (!promote(env, &val, rhs_t, lhs_t))
+ code_err(assign->values->ast, "You cannot assign a %T value to a %T operand", rhs_t, lhs_t);
+ return compile_assignment(env, assign->targets->ast, val);
+ }
CORD code = "{ // Assignment\n";
int64_t i = 1;
- for (ast_list_t *value = assign->values; value; value = value->next)
- CORD_appendf(&code, "%r $%ld = %r;\n", compile_type(env, get_type(env, value->ast)), i++, compile(env, value->ast));
+ for (ast_list_t *value = assign->values, *target = assign->targets; value && target; value = value->next, target = target->next) {
+ type_t *lhs_t = get_type(env, target->ast);
+ env_t *val_env = arg_scope(env, lhs_t);
+ type_t *rhs_t = get_type(val_env, value->ast);
+ CORD val = compile(val_env, value->ast);
+ if (!promote(env, &val, rhs_t, lhs_t))
+ code_err(value->ast, "You cannot assign a %T value to a %T operand", rhs_t, lhs_t);
+ CORD_appendf(&code, "%r $%ld = %r;\n", compile_type(env, lhs_t), i++, val);
+ }
i = 1;
for (ast_list_t *target = assign->targets; target; target = target->next) {
code = CORD_cat(code, compile_assignment(env, target->ast, CORD_asprintf("$%ld", i++)));