harec

[hare] Hare compiler, written in C11 for POSIX OSs
Log | Files | Refs | README | LICENSE

commit b6cb76a4dcaba027ca45436106978e35dd6f568a
parent d70b91ef8f36c60eb179d932cf520dd11d5b9a87
Author: Ember Sawady <ecs@d2evs.net>
Date:   Mon, 23 Jan 2023 16:18:48 +0000

Fix tagged unions containing t and !t

Or more broadly, any types which are identical besides type flags

Signed-off-by: Ember Sawady <ecs@d2evs.net>

Diffstat:
Minclude/types.h | 2+-
Msrc/check.c | 4++--
Msrc/eval.c | 2+-
Msrc/gen.c | 14+++++++-------
Msrc/types.c | 26++++++++++++++++++--------
Mtests/26-regression.ha | 5+++++
6 files changed, 34 insertions(+), 19 deletions(-)

diff --git a/include/types.h b/include/types.h @@ -175,7 +175,7 @@ const struct type_tuple *type_get_value( const struct type *type, uintmax_t index); const struct type *tagged_select_subtype( - const struct type *tagged, const struct type *subtype); + const struct type *tagged, const struct type *subtype, bool strip); bool tagged_subset_compat(const struct type *to, const struct type *from); const char *type_storage_unparse(enum type_storage storage); diff --git a/src/check.c b/src/check.c @@ -127,7 +127,7 @@ lower_implicit_cast(const struct type *to, struct expression *expr) if (type_dealias(to)->storage == STORAGE_TAGGED) { const struct type *interim = - tagged_select_subtype(to, expr->result); + tagged_select_subtype(to, expr->result, true); if (interim) { expr = lower_implicit_cast(interim, expr); } @@ -1467,7 +1467,7 @@ check_expr_cast(struct context *ctx, // secondary type must be a strict subset or a // member of the primary type if (!((tagged_subset_compat(primary, secondary) - || tagged_select_subtype(primary, secondary)) + || tagged_select_subtype(primary, secondary, true)) && !tagged_subset_compat(secondary, primary))) { error(ctx, aexpr->cast.type->loc, expr, "Type is not a valid member of " diff --git a/src/eval.c b/src/eval.c @@ -624,7 +624,7 @@ eval_cast(struct context *ctx, struct expression *in, struct expression *out) } return EVAL_OK; case STORAGE_TAGGED: - subtype = tagged_select_subtype(to, val.result); + subtype = tagged_select_subtype(to, val.result, true); out->constant.tagged.value = xcalloc(1, sizeof(struct expression)); if (subtype) { diff --git a/src/gen.c b/src/gen.c @@ -1285,7 +1285,7 @@ gen_type_assertion_or_test(struct gen_context *ctx, const struct expression *exp bfailed = bpassed; } struct gen_value result = {0}; - if (tagged_select_subtype(expr->cast.value->result, want)) { + if (tagged_select_subtype(expr->cast.value->result, want, true)) { result = gen_nested_match_tests(ctx, base, bpassed, bfailed, tag, want); } else if (tagged_subset_compat(expr->cast.value->result, want)) { @@ -1351,7 +1351,7 @@ gen_expr_cast_tagged_at(struct gen_context *ctx, { assert(expr->type == EXPR_CAST); const struct type *to = expr->result, *from = expr->cast.value->result; - const struct type *subtype = tagged_select_subtype(to, from); + const struct type *subtype = tagged_select_subtype(to, from, true); if (!subtype && tagged_align_compat(from, to)) { // Case 1: from is a union whose members are a subset of to, and @@ -1425,7 +1425,7 @@ cast_prefers_at(const struct expression *expr) } // tagged => *; subtype compatible if (type_dealias(from)->storage == STORAGE_TAGGED - && tagged_select_subtype(from, to)) { + && tagged_select_subtype(from, to, true)) { return false; } // * => tagged @@ -1540,7 +1540,7 @@ gen_expr_cast(struct gen_context *ctx, const struct expression *expr) if (expr->cast.kind != C_CAST) { bool is_valid_tagged, is_valid_pointer; is_valid_tagged = type_dealias(from)->storage == STORAGE_TAGGED - && (tagged_select_subtype(from, to) + && (tagged_select_subtype(from, to, true) || tagged_subset_compat(from, to)); is_valid_pointer = type_dealias(from)->storage == STORAGE_POINTER && (type_dealias(to)->storage == STORAGE_POINTER @@ -2404,7 +2404,7 @@ nested_tagged_offset(const struct type *tu, const struct type *target) const struct type *test = tu; struct qbe_value offset = constl(tu->align); do { - test = tagged_select_subtype(tu, target); + test = tagged_select_subtype(tu, target, false); if (!test) { break; } @@ -2451,7 +2451,7 @@ gen_nested_match_tests(struct gen_context *ctx, struct gen_value object, if (type_dealias(subtype)->storage != STORAGE_TAGGED) { break; } - test = tagged_select_subtype(subtype, type); + test = tagged_select_subtype(subtype, type, false); if (!test) { break; } @@ -2540,7 +2540,7 @@ gen_match_with_tagged(struct gen_context *ctx, struct qbe_value bmatch = mklabel(ctx, &lmatch, "matches.%d"); struct qbe_value bnext = mklabel(ctx, &lnext, "next.%d"); const struct type *subtype = - tagged_select_subtype(objtype, _case->type); + tagged_select_subtype(objtype, _case->type, false); enum match_compat compat = COMPAT_SUBTYPE; if (subtype) { gen_nested_match_tests(ctx, object, diff --git a/src/types.c b/src/types.c @@ -462,7 +462,8 @@ strip_flags(const struct type *t, struct type *secondary) } const struct type * -tagged_select_subtype(const struct type *tagged, const struct type *subtype) +tagged_select_subtype(const struct type *tagged, const struct type *subtype, + bool strip) { tagged = type_dealias(tagged); assert(tagged->storage == STORAGE_TAGGED); @@ -474,10 +475,7 @@ tagged_select_subtype(const struct type *tagged, const struct type *subtype) const struct type *selected = NULL; for (const struct type_tagged_union *tu = &tagged->tagged; tu; tu = tu->next) { - struct type _tustripped; - const struct type *tustripped = - strip_flags(tu->type, &_tustripped); - if (tustripped->id == stripped->id) { + if (tu->type->id == subtype->id) { return tu->type; } @@ -490,6 +488,18 @@ tagged_select_subtype(const struct type *tagged, const struct type *subtype) } } + if (strip) { + for (const struct type_tagged_union *tu = &tagged->tagged; + tu; tu = tu->next) { + struct type _tustripped; + const struct type *tustripped = + strip_flags(tu->type, &_tustripped); + if (tustripped->id == stripped->id) { + return tu->type; + } + } + } + if (nassign == 1) { return selected; } @@ -858,7 +868,7 @@ type_is_assignable(const struct type *to, const struct type *from) && to->array.members == from->array.members; } case STORAGE_TAGGED: - return tagged_select_subtype(to, from_orig) != NULL + return tagged_select_subtype(to, from_orig, true) != NULL || tagged_subset_compat(to, from); // The following types are only assignable from themselves, and are // handled above: @@ -891,13 +901,13 @@ is_castable_with_tagged(const struct type *to, const struct type *from) } } if (type_dealias(to)->storage == STORAGE_TAGGED) { - const struct type *subtype = tagged_select_subtype(to, from); + const struct type *subtype = tagged_select_subtype(to, from, true); if (subtype != NULL) { return subtype; } } if (type_dealias(from)->storage == STORAGE_TAGGED) { - const struct type *subtype = tagged_select_subtype(from, to); + const struct type *subtype = tagged_select_subtype(from, to, true); if (subtype != NULL) { return subtype; } diff --git a/tests/26-regression.ha b/tests/26-regression.ha @@ -69,4 +69,9 @@ export fn main() void = { case &global => void; case => abort(); }; + + match (void: (void | !void)) { + case void => void; + case !void => abort(); + }; };