diff options
author | Bad Diode <bd@badd10de.dev> | 2024-06-24 11:46:43 +0200 |
---|---|---|
committer | Bad Diode <bd@badd10de.dev> | 2024-06-24 11:46:43 +0200 |
commit | 9c73b54a747e5489b2d6f27947cd8216f5311d5e (patch) | |
tree | 1a6aa027e80336cd3418305bcb8402ef47bbedf2 /src/main.c | |
parent | 15e24115a2a117407157c993fe17b2d414dc0bf4 (diff) | |
download | bdl-9c73b54a747e5489b2d6f27947cd8216f5311d5e.tar.gz bdl-9c73b54a747e5489b2d6f27947cd8216f5311d5e.zip |
Typecheck return values in the entire function body
Diffstat (limited to 'src/main.c')
-rw-r--r-- | src/main.c | 89 |
1 files changed, 81 insertions, 8 deletions
@@ -201,6 +201,70 @@ emit_semantic_error(Analyzer *a, Node *n, Str msg) { | |||
201 | eprintln("%s:%d:%d: error: %s", a->file_name, n->line, n->col, msg); | 201 | eprintln("%s:%d:%d: error: %s", a->file_name, n->line, n->col, msg); |
202 | } | 202 | } |
203 | 203 | ||
204 | bool | ||
205 | typecheck_returns(Node *node, Str expected) { | ||
206 | if (!node) { | ||
207 | return true; | ||
208 | } | ||
209 | |||
210 | // Traverse the tree again. | ||
211 | switch (node->kind) { | ||
212 | case NODE_COND: | ||
213 | case NODE_MATCH: { | ||
214 | for (sz i = 0; i < array_size(node->match_cases); i++) { | ||
215 | Node *next = node->match_cases[i]; | ||
216 | if (!typecheck_returns(next, expected)) { | ||
217 | return false; | ||
218 | } | ||
219 | } | ||
220 | } break; | ||
221 | case NODE_RETURN: { | ||
222 | return str_eq(node->type, expected); | ||
223 | } break; | ||
224 | case NODE_BLOCK: { | ||
225 | for (sz i = 0; i < array_size(node->elements); i++) { | ||
226 | Node *next = node->elements[i]; | ||
227 | if (!typecheck_returns(next, expected)) { | ||
228 | return false; | ||
229 | } | ||
230 | } | ||
231 | } break; | ||
232 | case NODE_IF: { | ||
233 | if (node->cond_expr) { | ||
234 | if (!typecheck_returns(node->cond_expr, expected)) { | ||
235 | return false; | ||
236 | } | ||
237 | } | ||
238 | if (node->cond_else) { | ||
239 | if (!typecheck_returns(node->cond_else, expected)) { | ||
240 | return false; | ||
241 | } | ||
242 | } | ||
243 | } break; | ||
244 | case NODE_SET: | ||
245 | case NODE_LET: { | ||
246 | if (node->var_val) { | ||
247 | if (!typecheck_returns(node->var_val, expected)) { | ||
248 | return false; | ||
249 | } | ||
250 | } | ||
251 | } break; | ||
252 | default: { | ||
253 | if (node->left) { | ||
254 | if (!typecheck_returns(node->left, expected)) { | ||
255 | return false; | ||
256 | } | ||
257 | } | ||
258 | if (node->right) { | ||
259 | if (!typecheck_returns(node->right, expected)) { | ||
260 | return false; | ||
261 | } | ||
262 | } | ||
263 | } break; | ||
264 | } | ||
265 | return true; | ||
266 | } | ||
267 | |||
204 | Type | 268 | Type |
205 | type_inference(Analyzer *a, Node *node, TypeScope *scope) { | 269 | type_inference(Analyzer *a, Node *node, TypeScope *scope) { |
206 | assert(a); | 270 | assert(a); |
@@ -554,21 +618,30 @@ type_inference(Analyzer *a, Node *node, TypeScope *scope) { | |||
554 | ret_type = str_concat(ret_type, cstr(")"), a->storage); | 618 | ret_type = str_concat(ret_type, cstr(")"), a->storage); |
555 | node->fun_return = ret_type; | 619 | node->fun_return = ret_type; |
556 | 620 | ||
557 | node->type = cstr("nil"); | ||
558 | if (node->func_body->kind == NODE_BLOCK) { | 621 | if (node->func_body->kind == NODE_BLOCK) { |
559 | node = node->func_body; | ||
560 | Type type; | 622 | Type type; |
561 | for (sz i = 0; i < array_size(node->elements); i++) { | 623 | for (sz i = 0; i < array_size(node->func_body->elements); i++) { |
562 | Node *expr = node->elements[i]; | 624 | Node *expr = node->func_body->elements[i]; |
563 | type = type_inference(a, expr, scope); | 625 | type = type_inference(a, expr, scope); |
564 | } | 626 | } |
565 | node->type = type; | 627 | node->func_body->type = type; |
566 | // TODO: ensure ALL return statements match the function | ||
567 | // prototype. | ||
568 | } else { | 628 | } else { |
569 | type_inference(a, node->func_body, scope); | 629 | type_inference(a, node->func_body, scope); |
570 | } | 630 | } |
571 | return cstr("nil"); | 631 | |
632 | // Ensure main body return matches the prototype. | ||
633 | if (!str_eq(node->func_body->type, ret_type)) { | ||
634 | emit_semantic_error(a, node, cstr("mismatched return types")); | ||
635 | } | ||
636 | |||
637 | // Ensure ALL return statements match the function prototype. | ||
638 | if (!typecheck_returns(node->func_body, ret_type)) { | ||
639 | emit_semantic_error(a, node, cstr("mismatched return types")); | ||
640 | } | ||
641 | |||
642 | // TODO: insert this into a functions map in the current scope? need | ||
643 | // the arity and return parameters for funcalls. | ||
644 | return node->type; | ||
572 | } break; | 645 | } break; |
573 | default: { | 646 | default: { |
574 | emit_semantic_error(a, node, | 647 | emit_semantic_error(a, node, |