harec

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

commit 9823d8cae6542d9ff805c089395ba19511537f10
parent 7a9448df40e2927eb8ae01b408d5eac57ab1aa15
Author: Eyal Sawady <ecs@d2evs.net>
Date:   Fri,  3 Sep 2021 10:35:07 +0000

type_is_assignable: implement struct subtyping

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

Diffstat:
Msrc/types.c | 16++++++++++++++++
Mtests/05-implicit-casts.ha | 24++++++++++++++++++++++++
2 files changed, 40 insertions(+), 0 deletions(-)

diff --git a/src/types.c b/src/types.c @@ -527,6 +527,19 @@ tagged_subset_compat(const struct type *to, const struct type *from) return !from_tu; } +static bool +struct_subtype(const struct type *to, const struct type *from) { + if (from->storage != STORAGE_STRUCT) { + return false; + } + for (struct struct_field *f = from->struct_union.fields; f; + f = f->next) { + if (f->offset == 0) { + return f->type == to; + } + } + return false; +} bool type_is_assignable(const struct type *to, const struct type *from) { @@ -580,6 +593,9 @@ type_is_assignable(const struct type *to, const struct type *from) case STORAGE_POINTER: from_secondary = type_dealias(from->pointer.referent); from_secondary = strip_flags(from_secondary, &_from_secondary); + if (struct_subtype(to->pointer.referent, from_secondary)) { + return true; + } switch (to_secondary->storage) { case STORAGE_VOID: break; diff --git a/tests/05-implicit-casts.ha b/tests/05-implicit-casts.ha @@ -1,5 +1,24 @@ use rt; +type subtype = struct { + foo: int, +}; + +type super1 = struct { + foo: subtype, + bar: int, +}; + +type super2 = struct { + subtype, + bar: int, +}; + +type super3 = struct { + struct { foo: int }, + bar: int, +}; + fn rules() void = { // Fixed precision ints let _i64: i64 = 0i64; @@ -62,6 +81,11 @@ fn rules() void = { nptr = &i; let vptr: nullable *void = nptr; + // Struct subtyping + let sptr: *subtype = &super1 { ... }; + let sptr: *subtype = &super2 { ... }; + let sptr: *struct { foo: int } = &super3 { ... }; + // Invalid pointer conversions assert(rt::compile( "fn test() void = { let x: nullable *int = null; let y: *int = x; };"