diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2024-05-24 00:03:46 -0400 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2024-05-24 00:03:46 -0400 |
| commit | 308946e794f05da9f7010797f5911bcf4e131c3e (patch) | |
| tree | 8ab109d49a2b0314faacc577e21de1c60e227788 /typecheck.c | |
| parent | bf3cdc3dfa4dcd0d17f182fe875d718cb4a4272f (diff) | |
Switch optional detection to use 'when .. is @..' instead of 'if .. :=
..'; also fixed a bug with stack memory in doctests
Diffstat (limited to 'typecheck.c')
| -rw-r--r-- | typecheck.c | 39 |
1 files changed, 22 insertions, 17 deletions
diff --git a/typecheck.c b/typecheck.c index 9964c9d9..16841e8f 100644 --- a/typecheck.c +++ b/typecheck.c @@ -845,22 +845,7 @@ type_t *get_type(env_t *env, ast_t *ast) case If: { auto if_ = Match(ast, If); - type_t *true_t; - if (if_->condition->tag == Declare) { - auto decl = Match(if_->condition, Declare); - env_t *scope = fresh_scope(env); - type_t *var_t = get_type(env, decl->value); - if (var_t->tag == PointerType) { - auto ptr = Match(var_t, PointerType); - var_t = Type(PointerType, .pointed=ptr->pointed, .is_optional=false, .is_stack=ptr->is_stack, .is_readonly=ptr->is_readonly); - } - CORD var = Match(decl->var, Var)->name; - set_binding(scope, CORD_to_const_char_star(var), new(binding_t, .type=var_t)); - true_t = get_type(scope, if_->body); - } else { - true_t = get_type(env, if_->body); - } - + type_t *true_t = get_type(env, if_->body); if (if_->else_body) { type_t *false_t = get_type(env, if_->else_body); type_t *t_either = type_or_type(true_t, false_t); @@ -877,8 +862,28 @@ type_t *get_type(env_t *env, ast_t *ast) case When: { auto when = Match(ast, When); type_t *subject_t = get_type(env, when->subject); + if (subject_t->tag == PointerType) { + if (!Match(subject_t, PointerType)->is_optional) + code_err(when->subject, "This %T pointer type is not optional, so this 'when' statement is tautological", subject_t); + + bool handled_at = false; + for (when_clause_t *clause = when->clauses; clause; clause = clause->next) { + const char *tag_name = Match(clause->tag_name, Var)->name; + if (!streq(tag_name, "@")) + code_err(clause->tag_name, "'when' clauses on optional pointers only support @var, not tags like '%s'", tag_name); + if (handled_at) + code_err(clause->tag_name, "This 'when' statement has already handled the case of non-null pointers!"); + handled_at = true; + } + if (!handled_at) + code_err(ast, "This 'when' statement doesn't handle non-null pointers"); + if (!when->else_body) + code_err(ast, "This 'when' statement doesn't handle null pointers"); + return Type(VoidType); + } + if (subject_t->tag != EnumType) - code_err(when->subject, "'when' statements are only for enum types, not %T", subject_t); + code_err(when->subject, "'when' statements are only for enum types and optional pointers, not %T", subject_t); tag_t * const tags = Match(subject_t, EnumType)->tags; |
