mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Implicit casting from struct to interface failure for inheriting interfaces #2151. Fix second bug in #2148
This commit is contained in:
@@ -40,6 +40,7 @@
|
||||
- Missing error on default values for body with default arguments #2148.
|
||||
- `--path` does not interact correctly with relative path arguments #2149.
|
||||
- Add missing `@noreturn` to `os::exit`.
|
||||
- Implicit casting from struct to interface failure for inheriting interfaces #2151.
|
||||
|
||||
### Stdlib changes
|
||||
- Added `String.quick_ztr` and `String.is_zstr`
|
||||
|
||||
@@ -1143,14 +1143,23 @@ 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 BoolErr type_implements_interface_ignore_substruct(CastContext *cc, Decl *decl, Type *interface)
|
||||
{
|
||||
FOREACH(TypeInfo *, interface_type, decl->interfaces)
|
||||
{
|
||||
if (!sema_resolve_type_info(cc->context, interface_type, RESOLVE_TYPE_DEFAULT)) return BOOL_ERR;
|
||||
if (interface_type->type == interface) return BOOL_TRUE;
|
||||
BoolErr res = type_implements_interface_ignore_substruct(cc, interface_type->type->decl, interface);
|
||||
if (res != BOOL_FALSE) return res;
|
||||
}
|
||||
|
||||
return BOOL_FALSE;
|
||||
}
|
||||
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;
|
||||
}
|
||||
BoolErr result = type_implements_interface_ignore_substruct(cc, decl, interface);
|
||||
if (result != BOOL_FALSE) return result == BOOL_TRUE;
|
||||
if (!decl->is_substruct) return false;
|
||||
Type *inner;
|
||||
if (decl->decl_kind == DECL_DISTINCT)
|
||||
|
||||
@@ -2381,6 +2381,10 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
if (body_arg->var.init_expr)
|
||||
{
|
||||
RETURN_SEMA_ERROR(body_arg->var.init_expr, "Macro body parameters should never have default values.");
|
||||
}
|
||||
TypeInfo *expected_type_info = vartype(body_param);
|
||||
TypeInfo *type_info = vartype(body_arg);
|
||||
if (type_info && !sema_resolve_type_info(context, type_info, RESOLVE_TYPE_DEFAULT)) return false;
|
||||
|
||||
@@ -680,40 +680,55 @@ void sema_analysis_pass_lambda(Module *module)
|
||||
DEBUG_LOG("Pass finished with %d error(s).", compiler.context.errors_found);
|
||||
}
|
||||
|
||||
static bool sema_check_interface(SemaContext *context, Decl *decl, TypeInfo *interface_type, TypeInfo *original_type)
|
||||
{
|
||||
Decl *interface = interface_type->type->decl;
|
||||
FOREACH(Decl *, method, interface->interface_methods)
|
||||
{
|
||||
Decl *matching_method = sema_decl_stack_resolve_symbol(method->name);
|
||||
if (!matching_method)
|
||||
{
|
||||
if (method->func_decl.attr_optional) continue;
|
||||
if (interface_type != original_type)
|
||||
{
|
||||
RETURN_SEMA_ERROR(original_type,
|
||||
"'%s' was not fully implemented, the required method '%s' of interface '%s' needs to be implemented, did you forget it?",
|
||||
original_type->type->decl->name, method->name, interface->name);
|
||||
}
|
||||
RETURN_SEMA_ERROR(original_type,
|
||||
"'%s' was not fully implemented, the required method '%s' needs to be implemented, did you forget it?",
|
||||
interface->name, method->name);
|
||||
}
|
||||
if (matching_method->decl_kind != DECL_FUNC)
|
||||
{
|
||||
if (method->func_decl.attr_optional) continue;
|
||||
RETURN_SEMA_ERROR(matching_method, "'%s' was not fully implemented, it requires '%s' to be a function marked '@dynamic'.",
|
||||
interface->name, method->name);
|
||||
}
|
||||
if (!matching_method->func_decl.attr_dynamic)
|
||||
{
|
||||
SEMA_ERROR(matching_method, "'%s(...)' must be marked '@dynamic' as it matches the method '%s' in interface '%s'.",
|
||||
method->name, method->name, interface->name);
|
||||
SEMA_NOTE(method, "Here is the interface method to implement.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
FOREACH(TypeInfo *, parent_interface, interface->interfaces)
|
||||
{
|
||||
if (!sema_check_interface(context, decl, parent_interface, original_type)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
static inline bool sema_check_interfaces(SemaContext *context, Decl *decl)
|
||||
{
|
||||
Decl **store = sema_decl_stack_store();
|
||||
FOREACH(Decl *, method, decl->methods) sema_decl_stack_push(method);
|
||||
FOREACH(TypeInfo *, interface_type, decl->interfaces)
|
||||
{
|
||||
Decl *interface = interface_type->type->decl;
|
||||
FOREACH(Decl *, method, interface->interface_methods)
|
||||
if (!sema_check_interface(context, decl, interface_type, interface_type))
|
||||
{
|
||||
Decl *matching_method = sema_decl_stack_resolve_symbol(method->name);
|
||||
if (!matching_method)
|
||||
{
|
||||
if (method->func_decl.attr_optional) continue;
|
||||
SEMA_ERROR(interface_type, "'%s' was not fully implemented, required method '%s' needs to be implemented, did you forget it?",
|
||||
interface->name, method->name);
|
||||
sema_decl_stack_restore(store);
|
||||
return false;
|
||||
}
|
||||
if (matching_method->decl_kind != DECL_FUNC)
|
||||
{
|
||||
if (method->func_decl.attr_optional) continue;
|
||||
SEMA_ERROR(matching_method, "'%s' was not fully implemented, it requires '%s' to be a function marked '@dynamic'.",
|
||||
interface->name, method->name);
|
||||
sema_decl_stack_restore(store);
|
||||
return false;
|
||||
}
|
||||
if (!matching_method->func_decl.attr_dynamic)
|
||||
{
|
||||
SEMA_ERROR(matching_method, "'%s(...)' must be marked '@dynamic' as it matches the method '%s' in interface '%s'.",
|
||||
method->name, method->name, interface->name);
|
||||
SEMA_NOTE(method, "Here is the interface method to implement.");
|
||||
sema_decl_stack_restore(store);
|
||||
return false;
|
||||
}
|
||||
sema_decl_stack_restore(store);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
sema_decl_stack_restore(store);
|
||||
|
||||
13
test/test_suite/any/interface_inheritance_fail.c3
Normal file
13
test/test_suite/any/interface_inheritance_fail.c3
Normal file
@@ -0,0 +1,13 @@
|
||||
import std;
|
||||
|
||||
interface IFoo { fn void a(); }
|
||||
interface IBar { fn void b(); }
|
||||
|
||||
interface IFooBar: IFoo, IBar {}
|
||||
|
||||
struct Foo (IFooBar) { int _a; } // #error: was not fully implemented
|
||||
struct Foo2 (IFoo, IBar) { int _a; }
|
||||
|
||||
fn void Foo2.a(&s) @dynamic {}
|
||||
fn void Foo2.b(&s) @dynamic {}
|
||||
|
||||
29
test/test_suite/interface_multi.c3
Normal file
29
test/test_suite/interface_multi.c3
Normal file
@@ -0,0 +1,29 @@
|
||||
import std;
|
||||
|
||||
interface IFoo { fn void a(); }
|
||||
interface IBar { fn void b(); }
|
||||
|
||||
interface IFooBar: IFoo, IBar {}
|
||||
|
||||
struct Foo (IFooBar) { int _a; }
|
||||
|
||||
fn void Foo.a(&s) @dynamic {}
|
||||
fn void Foo.b(&s) @dynamic {}
|
||||
|
||||
fn void foo(IFoo o) => o.a();
|
||||
fn void bar(IBar o) => o.b();
|
||||
|
||||
fn void foobar(IFooBar o)
|
||||
{
|
||||
o.a();
|
||||
o.b();
|
||||
}
|
||||
|
||||
fn void main()
|
||||
{
|
||||
Foo f;
|
||||
|
||||
foo(&f);
|
||||
bar(&f);
|
||||
foobar(&f);
|
||||
}
|
||||
13
test/test_suite/macros/macro_body_error_2148_2.c3
Normal file
13
test/test_suite/macros/macro_body_error_2148_2.c3
Normal file
@@ -0,0 +1,13 @@
|
||||
fn int main()
|
||||
{
|
||||
@foo(;int x = 2) // #error: Macro body parameters should
|
||||
{
|
||||
|
||||
};
|
||||
return 0;
|
||||
}
|
||||
|
||||
macro @foo(; @body(int x))
|
||||
{
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user