commit b315aba134db251d9df47c75392ecf2e12531e80
parent 2a6711b038d44577cd1aca66ea666260cbecc34b
Author: Drew DeVault <sir@cmpwn.com>
Date: Sun, 31 Jan 2021 11:06:37 -0500
check: fix issue with type assertions
Diffstat:
2 files changed, 18 insertions(+), 3 deletions(-)
diff --git a/src/check.c b/src/check.c
@@ -544,15 +544,15 @@ check_expr_cast(struct context *ctx,
const struct type *secondary = expr->cast.secondary =
type_store_lookup_atype(ctx->store, aexpr->cast.type);
check_expression(ctx, aexpr->cast.value, value, secondary);
- expect(&aexpr->cast.type->loc,
- type_is_castable(secondary, value->result),
- "Invalid cast");
if (aexpr->cast.kind == C_ASSERTION || aexpr->cast.kind == C_TEST) {
const struct type *primary = type_dealias(expr->cast.value->result);
expect(&aexpr->cast.value->loc,
primary->storage == TYPE_STORAGE_TAGGED,
"Expected a tagged union type");
+ expect(&aexpr->cast.type->loc,
+ type_is_castable(value->result, secondary),
+ "Invalid cast");
bool found = false;
for (const struct type_tagged_union *t = &primary->tagged;
t; t = t->next) {
@@ -567,6 +567,10 @@ check_expr_cast(struct context *ctx,
switch (aexpr->cast.kind) {
case C_CAST:
+ expect(&aexpr->cast.type->loc,
+ type_is_castable(secondary, value->result),
+ "Invalid cast");
+ // Fallthrough
case C_ASSERTION:
expr->result = secondary;
break;
diff --git a/tests/18-match.ha b/tests/18-match.ha
@@ -79,6 +79,16 @@ fn tagged_result() void = {
assert(y is uint);
};
+fn implicit_cast() void = {
+ let x: foobar = foo;
+ let y: nullable *int = null;
+ let a: (int | foobar) = match (y) {
+ null => foo: foobar,
+ z: *int => *z,
+ };
+ assert(a is foobar);
+};
+
export fn main() void = {
tagged();
termination();
@@ -86,5 +96,6 @@ export fn main() void = {
pointer();
alias();
tagged_result();
+ implicit_cast();
// TODO: Test exhaustiveness and dupe detection
};