harec

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit 39599274468de63e4e8ee484e616fb8c695d5f11
parent 422f2db26233f1649c30b4579650852e0c955179
Author: Drew DeVault <sir@cmpwn.com>
Date:   Sun, 31 Jan 2021 09:45:25 -0500

types: implement tagged_subset_compat

Diffstat:
Msrc/types.c | 29+++++++++++++++++++++++++++--
Mtests/13-tagged.ha | 14+++++++-------
2 files changed, 34 insertions(+), 9 deletions(-)

diff --git a/src/types.c b/src/types.c @@ -375,6 +375,31 @@ tagged_select_subtype(const struct type *tagged, const struct type *subtype) return NULL; } +static bool +tagged_subset_compat(const struct type *to, const struct type *from) +{ + // Note: this implementation depends on the invariant that tagged union + // member types are sorted by their type ID. + to = type_dealias(to), from = type_dealias(from); + if (to->storage != TYPE_STORAGE_TAGGED || from->storage != TYPE_STORAGE_TAGGED) { + return false; + } + const struct type_tagged_union *to_tu = &to->tagged, + *from_tu = &from->tagged; + while (from_tu && to_tu) { + while (to_tu) { + if (to_tu->type->id == from_tu->type->id) { + from_tu = from_tu->next; + to_tu = to_tu->next; + break; + } + to_tu = to_tu->next; + } + } + + return !from_tu; +} + bool type_is_assignable(const struct type *to, const struct type *from) { @@ -464,8 +489,8 @@ type_is_assignable(const struct type *to, const struct type *from) && to->array.length == SIZE_UNDEFINED && from->array.length != SIZE_UNDEFINED; case TYPE_STORAGE_TAGGED: - // XXX: Needs work! - return tagged_select_subtype(to, from) != NULL || true; + return tagged_select_subtype(to, from) != NULL + || tagged_subset_compat(to, from); // The following types are only assignable from themselves, and are // handled above: case TYPE_STORAGE_BOOL: diff --git a/tests/13-tagged.ha b/tests/13-tagged.ha @@ -55,13 +55,13 @@ fn reduction() void = { const a: (i8 | i16) = 42i8; const b: (i16 | i8) = a; const c: (i8 | i16 | i32) = a; - //assert(rt::compile( - // // Cannot assign from more general type - // "fn test() void = { - // let a: (i8 | i16 | i32) = 42i8; - // let b: (i8 | i16) = a; - // };" - //) != 0); + assert(rt::compile( + // Cannot assign from more general type + "fn test() void = { + let a: (i8 | i16 | i32) = 42i8; + let b: (i8 | i16) = a; + };" + ) != 0); assert(a is i8 && b is i8 && c is i8); assert(size((i8 | i16 | i32)) == size((i8 | (i16 | i32)))); assert(size(integer) == size(signed));