summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWormHeamer2025-08-10 05:20:40 -0400
committerWormHeamer2025-08-10 05:20:40 -0400
commita9810c2281a2c4fc2265aa8c59fa9bf101e3a3b5 (patch)
treea9afaee0d6514505ccd35343bca8bb931a196f76
parentc9980711ce42de9cf58db35f41ce1ac42bfea0c7 (diff)
better error reporting around uninitialized values
-rw-r--r--ir.c40
-rw-r--r--main.c39
-rw-r--r--test.lang7
3 files changed, 34 insertions, 52 deletions
diff --git a/ir.c b/ir.c
index b0b90f5..0e8e097 100644
--- a/ir.c
+++ b/ir.c
@@ -359,19 +359,9 @@ static int type_ok(Node *n) {
}
}
-/* TODO: make it so
- * func foo(a, b i64) i64 {
- * let x i64
- * if a < b {
- * return 0
- * } else {
- * x := 3
- * }
- * return x
- * }
- * doesn't throw warnings (e.g. don't generate phi nodes if one scope is
- * guaranteed to return early)
- */
+void type_check(Node *n, Lexer *l) {
+ if (!type_ok(n)) type_err(n, l);
+}
int node_uninit(Node *n) {
return n->op == N_UNINIT;
@@ -386,27 +376,3 @@ int node_maybe_uninit(Node *n) {
}
return 0;
}
-
-void uninit_check(Node *n, Lexer *l) {
- if (NMASK(n->op) & ~NM_PHI) {
- for (int i = 0; i < n->in.len; i++) {
- Node *o = IN(n, i);
- if (!o) continue;
- if (node_uninit(o)) {
- fprintf(stderr, "%s\n", node_type_name(n->op));
- lex_error_at(l, o->src_pos, LE_WARN,
- str_fmt(&l->arena, "uninitialized %S",
- type_desc(&IN(n,i)->type, &l->arena)));
- } else if (node_maybe_uninit(o)) {
- lex_error_at(l, o->src_pos, LE_WARN,
- str_fmt(&l->arena, "possibly uninitialized %S",
- type_desc(&o->type, &l->arena)));
- }
- }
- }
-}
-
-void type_check(Node *n, Lexer *l) {
- uninit_check(n, l);
- if (!type_ok(n)) type_err(n, l);
-}
diff --git a/main.c b/main.c
index fa00bad..1d35ce9 100644
--- a/main.c
+++ b/main.c
@@ -32,7 +32,7 @@ void unit_free(Unit *u) {
/* parsing */
-Node *parse_expr(Lexer *l, Proc *p);
+Node *parse_expr(Lexer *l, Proc *p, Type *twant);
/* TODO: eliminate unused if-else statements at the end of compilation
* they don't get pruned out by peephole optimizations if there are phi
@@ -58,7 +58,7 @@ void parse_return(Lexer *l, Proc *p) {
if (p->ret_type.t == T_NONE) {
n = node_new(p, N_RETURN, p->ctrl);
} else {
- Node *e = parse_expr(l, p);
+ Node *e = parse_expr(l, p, NULL);
if (!type_base_eql(&e->type, &p->ret_type)) {
lex_error_at(l, e->src_pos, LE_ERROR,
str_fmt(&p->arena, "incorrect return type (expected %S, got %S)",
@@ -116,7 +116,7 @@ recurse:
}
if (l->tok == TOK_EQL) {
lex_next(l);
- rhs = parse_expr(l, p);
+ rhs = parse_expr(l, p, t.t == T_NONE ? NULL : &t);
if (t.t != T_NONE) type_expected(&t, rhs, l);
}
NameBinding *b = scope_bind(&p->scope, name, rhs, pos, p);
@@ -154,7 +154,7 @@ void parse_assign(Lexer *l, Proc *p) {
if (!b) {
lex_error_at(l, pos, LE_ERROR, S("undeclared identifier"));
}
- Node *e = parse_expr(l, p);
+ Node *e = parse_expr(l, p, &b->node->type);
if (!type_base_eql(&e->type, &b->node->type)) {
lex_error_at(l, pos, LE_ERROR,
str_fmt(&p->arena, "tried to assign value of type %S to variable of type %S",
@@ -256,7 +256,7 @@ void merge_scope(Lexer *l, Proc *p, Node *region, ScopeNameList *before, ScopeNa
void parse_if(Lexer *l, Proc *p) {
lex_next(l);
- Node *cond = parse_expr(l, p);
+ Node *cond = parse_expr(l, p, &(Type) { .t = T_BOOL });
Node *ctrl_if = NULL, *ctrl_else = NULL;
Node *if_node = node_new(p, N_IF_ELSE, p->ctrl, cond);
if_node->val = (Value) {
@@ -417,7 +417,7 @@ void proc_opt_fwd(Proc *p, Lexer *l, Node *n) {
break;
case N_IF_ELSE:
if (n->out.len < 2) {
- lex_error_at(l, n->src_pos, LE_ERROR, S("not all codepaths return"));
+ //lex_error_at(l, n->src_pos, LE_ERROR, S("not all codepaths return"));
}
for (int i = 0; i < n->out.len; i++) {
Node *r = find_return(n->out.data[i]);
@@ -503,13 +503,26 @@ Proc *parse_proc(Lexer *l, Unit *u) {
return proc;
}
-Node *parse_term(Lexer *l, Proc *p) {
+void uninit_check(Lexer *l, Proc *p, Node *n, LexSpan pos) {
+ if (node_uninit(n)) {
+ lex_error_at(l, pos, LE_ERROR,
+ str_fmt(&p->arena, "uninitialized %S",
+ type_desc(&n->type, &p->arena)));
+ } else if (node_maybe_uninit(n)) {
+ lex_error_at(l, pos, LE_WARN,
+ str_fmt(&p->arena, "possibly uninitialized %S",
+ type_desc(&n->type, &p->arena)));
+ }
+}
+
+Node *parse_term(Lexer *l, Proc *p, Type *twant) {
+ (void)twant; /* to be used for .ENUM_TYPE and stuff */
Node *node = NULL;
NodeType op_after = N_START;
if (TMASK(l->tok) & (TM_MINUS | TM_PLUS | TM_NOT)) {
Token t = l->tok;
lex_next(l);
- node = parse_term(l, p);
+ node = parse_term(l, p, twant);
NodeType post_op = N_START;
switch (t) {
case TOK_MINUS: post_op = N_OP_NEG; break;
@@ -521,7 +534,7 @@ Node *parse_term(Lexer *l, Proc *p) {
}
if (l->tok == TOK_LPAREN) {
lex_next(l);
- node = parse_expr(l, p);
+ node = parse_expr(l, p, NULL);
lex_expected(l, TM_RPAREN);
lex_next(l);
node->src_pos.ofs--;
@@ -533,6 +546,7 @@ Node *parse_term(Lexer *l, Proc *p) {
} else {
lex_error(l, LE_ERROR, S("undeclared identifier"));
}
+ uninit_check(l, p, node, l->pos);
lex_next(l);
} else if (TMASK(l->tok) & (TM_TRUE | TM_FALSE)) {
node = node_new_lit_bool(p, l->tok == TOK_TRUE);
@@ -580,9 +594,9 @@ NodeType tok_to_bin_op(Token t) {
}
/* TODO: operator precedence would be kinda nice actually, sad to say */
-Node *parse_expr(Lexer *l, Proc *p) {
+Node *parse_expr(Lexer *l, Proc *p, Type *twant) {
LexSpan pos = l->pos;
- Node *lhs = parse_term(l, p);
+ Node *lhs = parse_term(l, p, twant);
NodeType nt = tok_to_bin_op(l->tok);;
if (lhs->refs <= 0) lex_error(l, LE_ERROR, S("dead lhs"));
assert(lhs->refs > 0);
@@ -592,11 +606,12 @@ Node *parse_expr(Lexer *l, Proc *p) {
* and therefore culled by peephole optimizations */
Node *rhs;
NODE_KEEP(p, lhs, {
- rhs = parse_expr(l, p);
+ rhs = parse_expr(l, p, &lhs->type);
});
lhs = node_peephole(node_new(p, nt, NULL, lhs, rhs), p, l);
}
lhs->src_pos = (LexSpan) { pos.ofs, l->pos.ofs - pos.ofs };
+ if (twant) type_expected(twant, lhs, l);
return lhs;
}
diff --git a/test.lang b/test.lang
index d461439..4df4f82 100644
--- a/test.lang
+++ b/test.lang
@@ -1,11 +1,12 @@
func main(a, b i64) i64 {
let x i64, y bool
- if a < b {
+ if true {
let t = a
a := b
b := t
+ x := 3
} else {
- x := 2
+ //x := 2
}
- return (a + b) + x
+ return x
}