From a90e3c440bed666624c5fd65031ce7456552ca92 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Fri, 2 Aug 2024 11:37:38 +0200 Subject: [PATCH] Distinct inline would not implement protocol if the inlined implemented it. This closes #1292 --- releasenotes.md | 1 + src/compiler/sema_casts.c | 29 ++++++++++++++---- test/test_suite/dynamic/inline_protocol.c3 | 35 ++++++++++++++++++++++ 3 files changed, 60 insertions(+), 5 deletions(-) create mode 100644 test/test_suite/dynamic/inline_protocol.c3 diff --git a/releasenotes.md b/releasenotes.md index 1bc510a52..aeb135668 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -33,6 +33,7 @@ - Incorrect justify formatting of integers. - Assertion with duplicate function pointer signatures #1286 - Distinct func type would not accept direct function address assign. #1287 +- Distinct inline would not implement protocol if the inlined implemented it. #1292 ### Stdlib changes diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index 9ff2345ce..c452dbee1 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -1035,6 +1035,29 @@ static bool rule_vecarr_to_infer(CastContext *cc, bool is_explicit, bool is_sile return cast_is_allowed(cc, is_explicit, is_silent); } +static inline bool type_implements_interface(CastContext *cc, Decl *decl, Type *interface) +{ +RETRY:; + FOREACH(TypeInfo *, interface_type, decl->interfaces) + { + if (!sema_resolve_type_info(cc->context, interface_type, RESOLVE_TYPE_DEFAULT)) return false; + if (interface_type->type == interface) return true; + } + if (!decl->is_substruct) return false; + Type *inner; + if (decl->decl_kind == DECL_DISTINCT) + { + inner = decl->distinct->type->canonical; + } + else + { + assert(decl->decl_kind == DECL_STRUCT); + inner = decl->strukt.members[0]->type->canonical; + } + if (!type_may_implement_interface(inner)) return false; + decl = inner->decl; + goto RETRY; +} static bool rule_ptr_to_interface(CastContext *cc, bool is_explicit, bool is_silent) { if (is_explicit) return true; @@ -1044,11 +1067,7 @@ static bool rule_ptr_to_interface(CastContext *cc, bool is_explicit, bool is_sil { Type *interface = cc->to; Decl *pointee_decl = pointee->decl; - FOREACH(TypeInfo *, interface_type, pointee_decl->interfaces) - { - if (!sema_resolve_type_info(cc->context, interface_type, RESOLVE_TYPE_DEFAULT)) return false; - if (interface_type->type == interface) return true; - } + if (type_implements_interface(cc, pointee->decl, interface)) return true; } if (is_silent) return false; RETURN_CAST_ERROR(cc->expr, "%s cannot be implicitly cast to %s, but you can use an explicit " diff --git a/test/test_suite/dynamic/inline_protocol.c3 b/test/test_suite/dynamic/inline_protocol.c3 new file mode 100644 index 000000000..76494b27b --- /dev/null +++ b/test/test_suite/dynamic/inline_protocol.c3 @@ -0,0 +1,35 @@ +interface Foo +{ + fn int foo(); +} + +struct Abc (Foo) +{ + int a; +} + +struct Bcd +{ + inline Abc a; +} + +struct Def +{ + Abc a; +} + +fn int Abc.foo(&self) @dynamic => 1; + +distinct Foob = inline Abc; + +fn void test1() +{ + Foob b; + Abc x; + Bcd y; + Def d; + Foo f = &x; + f = &b; + f = &y; + f = &d; // #error: assume the interface is implemented +} \ No newline at end of file