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:
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; };"