mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Not possible to alias or take reference for extension methods on non-user defined types. #1637
This commit is contained in:
@@ -19,6 +19,7 @@
|
||||
- Fix issue with properties in different targets not being respected #1633.
|
||||
- Indexing an Optional slice would crash in codegen #1636.
|
||||
- SimpleHeapAllocator bug when splitting blocks allowed memory overrun.
|
||||
- Not possible to alias or take reference for extension methods on non-user defined types. #1637
|
||||
|
||||
### Stdlib changes
|
||||
- Add `io::MultiReader`, `io::MultiWriter`, and `io::TeeReader` structs.
|
||||
|
||||
@@ -3641,6 +3641,34 @@ static inline bool sema_analyse_macro_func_access(SemaContext *context, Expr *ex
|
||||
return sema_expr_analyse_type_access(context, expr, parent->type, identifier, missing_ref);
|
||||
}
|
||||
|
||||
static inline Decl *sema_check_for_type_method(SemaContext *context, Expr *expr, Type *parent_type, const char *name, bool *missing_ref)
|
||||
{
|
||||
ASSERT0(parent_type == parent_type->canonical);
|
||||
Decl *ambiguous = NULL;
|
||||
Decl *private = NULL;
|
||||
Decl *member = sema_resolve_type_method(context->unit, parent_type, name, &ambiguous, &private);
|
||||
if (private)
|
||||
{
|
||||
if (missing_ref)
|
||||
{
|
||||
*missing_ref = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
SEMA_ERROR(expr, "The method '%s' has private visibility.", name);
|
||||
}
|
||||
return poisoned_decl;
|
||||
}
|
||||
if (ambiguous)
|
||||
{
|
||||
SEMA_ERROR(expr, "'%s' is an ambiguous name and so cannot be resolved, "
|
||||
"it may refer to method defined in '%s' or one in '%s'",
|
||||
name, member->unit->module->name->module, ambiguous->unit->module->name->module);
|
||||
return poisoned_decl;
|
||||
}
|
||||
return member;
|
||||
}
|
||||
|
||||
static inline bool sema_expr_analyse_type_access(SemaContext *context, Expr *expr, Type *parent_type, Expr *identifier, bool *missing_ref)
|
||||
{
|
||||
ASSERT_SPAN(expr, identifier->expr_kind == EXPR_IDENTIFIER);
|
||||
@@ -3659,9 +3687,16 @@ static inline bool sema_expr_analyse_type_access(SemaContext *context, Expr *exp
|
||||
|
||||
if (!type_may_have_sub_elements(canonical))
|
||||
{
|
||||
if (missing_ref) goto MISSING_REF;
|
||||
SEMA_ERROR(expr, "'%s' does not have a property '%s'.", type_to_error_string(parent_type), name);
|
||||
return false;
|
||||
Decl *member = sema_check_for_type_method(context, expr, parent_type->canonical, name, missing_ref);
|
||||
if (!decl_ok(member)) return false;
|
||||
if (!member)
|
||||
{
|
||||
if (missing_ref) goto MISSING_REF;
|
||||
RETURN_SEMA_ERROR(expr, "'%s' does not have a property or method '%s'.", type_to_error_string(parent_type), name);
|
||||
}
|
||||
expr->expr_kind = EXPR_IDENTIFIER;
|
||||
expr_resolve_ident(expr, member);
|
||||
return true;
|
||||
}
|
||||
Decl *decl = canonical->decl;
|
||||
if (!decl_ok(decl)) return false;
|
||||
@@ -3704,26 +3739,12 @@ static inline bool sema_expr_analyse_type_access(SemaContext *context, Expr *exp
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
|
||||
Decl *member = sema_decl_stack_find_decl_member(context, decl, name);
|
||||
if (!decl_ok(member)) return false;
|
||||
if (!member)
|
||||
{
|
||||
Decl *ambiguous = NULL;
|
||||
Decl *private = NULL;
|
||||
member = sema_resolve_type_method(context->unit, decl->type, name, &ambiguous, &private);
|
||||
if (private)
|
||||
{
|
||||
if (missing_ref) goto MISSING_REF;
|
||||
SEMA_ERROR(expr, "The method '%s' has private visibility.", name);
|
||||
return false;
|
||||
}
|
||||
if (ambiguous)
|
||||
{
|
||||
RETURN_SEMA_ERROR(expr, "'%s' is an ambiguous name and so cannot be resolved, "
|
||||
"it may refer to method defined in '%s' or one in '%s'",
|
||||
name, member->unit->module->name->module, ambiguous->unit->module->name->module);
|
||||
}
|
||||
member = sema_check_for_type_method(context, expr, decl->type, name, missing_ref);
|
||||
if (!decl_ok(member)) return false;
|
||||
}
|
||||
if (!member)
|
||||
{
|
||||
|
||||
@@ -11,7 +11,7 @@ fn void main2()
|
||||
|
||||
fn void main3()
|
||||
{
|
||||
$evaltype("int").extnameof; // #error: 'int' does not have a property 'extnameof'
|
||||
$evaltype("int").extnameof; // #error: 'int' does not have a property or method 'extnameof'
|
||||
}
|
||||
|
||||
fn void main4()
|
||||
|
||||
@@ -29,12 +29,12 @@ fn void g()
|
||||
|
||||
fn void k()
|
||||
{
|
||||
int v = $evaltype("int").x.sizeof; // #error: 'int' does not have a property 'x'.
|
||||
int v = $evaltype("int").x.sizeof; // #error: 'x'.
|
||||
}
|
||||
|
||||
fn void l()
|
||||
{
|
||||
int v = $sizeof(int[].len); // #error: 'int[]' does not have a property 'len'
|
||||
int v = $sizeof(int[].len); // #error: 'len'
|
||||
}
|
||||
|
||||
fn void m()
|
||||
|
||||
19
test/test_suite/methods/method_ref_for_extension_method.c3
Normal file
19
test/test_suite/methods/method_ref_for_extension_method.c3
Normal file
@@ -0,0 +1,19 @@
|
||||
module testc3;
|
||||
import std::io;
|
||||
|
||||
struct Foo {
|
||||
int i;
|
||||
}
|
||||
|
||||
fn bool Foo[].is_empty(Foo[] array) {
|
||||
return array.len == 0;
|
||||
}
|
||||
|
||||
def foo_arr_is_empty = Foo[].is_empty;
|
||||
|
||||
fn void main() {
|
||||
Foo[] foos = { Foo { .i = 0 } };
|
||||
void* foo = &Foo[].is_empty;
|
||||
io::printfn("Is empty: %s", foos.is_empty());
|
||||
io::printfn("Is empty: %s", foo_arr_is_empty(foos));
|
||||
}
|
||||
Reference in New Issue
Block a user