Not possible to alias or take reference for extension methods on non-user defined types. #1637

This commit is contained in:
Christoffer Lerno
2024-11-21 14:48:13 +01:00
parent 22f7faf60e
commit ae1b39eb60
5 changed files with 63 additions and 22 deletions

View File

@@ -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.

View File

@@ -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)
{

View File

@@ -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()

View File

@@ -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()

View 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));
}