mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Prevent methods from using names of properties or fields. #1638
This commit is contained in:
@@ -21,6 +21,7 @@
|
||||
- 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
|
||||
- Prevent methods from using names of properties or fields. #1638
|
||||
|
||||
### Stdlib changes
|
||||
- Add `io::MultiReader`, `io::MultiWriter`, and `io::TeeReader` structs.
|
||||
|
||||
@@ -2255,9 +2255,15 @@ bool parse_stdin(void);
|
||||
Path *path_create_from_string(const char *string, uint32_t len, SourceSpan span);
|
||||
|
||||
|
||||
typedef enum FindMember
|
||||
{
|
||||
METHODS_AND_FIELDS,
|
||||
FIELDS_ONLY
|
||||
} FindMember;
|
||||
|
||||
void sema_analysis_run(void);
|
||||
Decl **sema_decl_stack_store(void);
|
||||
Decl *sema_decl_stack_find_decl_member(SemaContext *context, Decl *decl_owner, const char *symbol);
|
||||
Decl *sema_decl_stack_find_decl_member(SemaContext *context, Decl *decl_owner, const char *symbol, FindMember find);
|
||||
Decl *sema_decl_stack_resolve_symbol(const char *symbol);
|
||||
void sema_decl_stack_restore(Decl **state);
|
||||
void sema_decl_stack_push(Decl *decl);
|
||||
|
||||
@@ -2212,6 +2212,103 @@ static inline bool sema_analyse_method(SemaContext *context, Decl *decl)
|
||||
|
||||
// Resolve declaration of parent as needed.
|
||||
if (!sema_resolve_type_decl(context, par_type)) return false;
|
||||
const char *kw = decl->name;
|
||||
const char *errname = NULL;
|
||||
switch (par_type->canonical->type_kind)
|
||||
{
|
||||
case TYPE_ENUM:
|
||||
if (kw == kw_ordinal || kw == kw_nameof)
|
||||
{
|
||||
errname = "an enum";
|
||||
goto NOT_VALID_NAME;
|
||||
}
|
||||
FALLTHROUGH;
|
||||
case TYPE_STRUCT:
|
||||
case TYPE_UNION:
|
||||
{
|
||||
Decl *d = sema_decl_stack_find_decl_member(context, par_type->canonical->decl, kw, FIELDS_ONLY);
|
||||
if (!decl_ok(d)) return false;
|
||||
if (d) RETURN_SEMA_ERROR(decl, "%s already has a field with the same name.", type_quoted_error_string(par_type));
|
||||
break;
|
||||
}
|
||||
case TYPE_FAULTTYPE:
|
||||
if (kw == kw_ordinal || kw == kw_nameof)
|
||||
{
|
||||
errname = "a fault";
|
||||
goto NOT_VALID_NAME;
|
||||
}
|
||||
break;
|
||||
case TYPE_ANYFAULT:
|
||||
if (kw == kw_type || kw == kw_nameof)
|
||||
{
|
||||
errname = "'anyfault'";
|
||||
goto NOT_VALID_NAME;
|
||||
}
|
||||
break;
|
||||
case TYPE_ANY:
|
||||
case TYPE_INTERFACE:
|
||||
if (kw == kw_ptr || kw == kw_type)
|
||||
{
|
||||
errname = "an interface or 'any'";
|
||||
goto NOT_VALID_NAME;
|
||||
}
|
||||
break;
|
||||
case TYPE_SLICE:
|
||||
if (kw == kw_ptr || kw == kw_len)
|
||||
{
|
||||
errname = "a slice";
|
||||
goto NOT_VALID_NAME;
|
||||
}
|
||||
break;
|
||||
case TYPE_VECTOR:
|
||||
case TYPE_INFERRED_VECTOR:
|
||||
{
|
||||
unsigned len = strlen(decl->name);
|
||||
if (len <= 4)
|
||||
{
|
||||
for (unsigned i = 0; i < len; i++)
|
||||
{
|
||||
if (!swizzle[(int) decl->name[i]]) goto NEXT;
|
||||
}
|
||||
RETURN_SEMA_ERROR(decl, "\"%s\" is not a valid method name for a vector, since it matches a swizzle combination.", kw);
|
||||
}
|
||||
}
|
||||
NEXT:;
|
||||
FALLTHROUGH;
|
||||
case TYPE_ARRAY:
|
||||
case TYPE_INFERRED_ARRAY:
|
||||
case TYPE_FLEXIBLE_ARRAY:
|
||||
if (kw == kw_len)
|
||||
{
|
||||
errname = "a vector or array";
|
||||
goto NOT_VALID_NAME;
|
||||
}
|
||||
break;
|
||||
case TYPE_POISONED:
|
||||
case TYPE_VOID:
|
||||
case ALL_FLOATS:
|
||||
case ALL_INTS:
|
||||
case TYPE_BOOL:
|
||||
case TYPE_FUNC_PTR:
|
||||
case TYPE_POINTER:
|
||||
case TYPE_FUNC_RAW:
|
||||
case TYPE_UNTYPED_LIST:
|
||||
case TYPE_BITSTRUCT:
|
||||
case TYPE_DISTINCT:
|
||||
break;
|
||||
case TYPE_TYPEID:
|
||||
if (type_property_by_name(kw) != TYPE_PROPERTY_NONE)
|
||||
{
|
||||
RETURN_SEMA_ERROR(decl, "\"%s\" is not a valid method name for a typeid as this is the name of a type property.", decl->name);
|
||||
}
|
||||
break;
|
||||
case TYPE_TYPEDEF:
|
||||
case TYPE_OPTIONAL:
|
||||
case TYPE_WILDCARD:
|
||||
case TYPE_TYPEINFO:
|
||||
case TYPE_MEMBER:
|
||||
UNREACHABLE
|
||||
}
|
||||
Decl **params = decl->func_decl.signature.params;
|
||||
bool is_dynamic = decl->func_decl.attr_dynamic;
|
||||
|
||||
@@ -2257,6 +2354,8 @@ static inline bool sema_analyse_method(SemaContext *context, Decl *decl)
|
||||
}
|
||||
|
||||
return true;
|
||||
NOT_VALID_NAME:
|
||||
RETURN_SEMA_ERROR(decl, "\"%s\" is not a valid method name for %s, as this would shadow the built-in property '.%s'.", kw, errname, kw);
|
||||
}
|
||||
|
||||
static const char *attribute_domain_to_string(AttributeDomain domain)
|
||||
|
||||
@@ -3739,7 +3739,7 @@ static inline bool sema_expr_analyse_type_access(SemaContext *context, Expr *exp
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
Decl *member = sema_decl_stack_find_decl_member(context, decl, name);
|
||||
Decl *member = sema_decl_stack_find_decl_member(context, decl, name, METHODS_AND_FIELDS);
|
||||
if (!decl_ok(member)) return false;
|
||||
if (!member)
|
||||
{
|
||||
@@ -3859,7 +3859,7 @@ static inline bool sema_expr_analyse_member_access(SemaContext *context, Expr *e
|
||||
}
|
||||
|
||||
Decl *underlying_type_decl = underlying_type->decl;
|
||||
Decl *member = sema_decl_stack_find_decl_member(context, underlying_type_decl, name);
|
||||
Decl *member = sema_decl_stack_find_decl_member(context, underlying_type_decl, name, METHODS_AND_FIELDS);
|
||||
if (!decl_ok(member)) return false;
|
||||
if (!member || !(decl_is_struct_type(member) || member->decl_kind == DECL_VAR || member->decl_kind == DECL_BITSTRUCT))
|
||||
{
|
||||
@@ -5012,7 +5012,7 @@ CHECK_DEEPER:
|
||||
// 10. Dump all members and methods into a decl stack.
|
||||
Decl *decl = type->decl;
|
||||
|
||||
Decl *member = sema_decl_stack_find_decl_member(context, decl, kw);
|
||||
Decl *member = sema_decl_stack_find_decl_member(context, decl, kw, METHODS_AND_FIELDS);
|
||||
if (!decl_ok(member)) return false;
|
||||
if (member && decl_is_enum_kind(decl) && member->decl_kind == DECL_VAR && sema_cast_const(parent))
|
||||
{
|
||||
@@ -7982,7 +7982,7 @@ static inline bool sema_expr_analyse_decl_element(SemaContext *context, Designat
|
||||
}
|
||||
return false;
|
||||
}
|
||||
Decl *member = sema_decl_stack_find_decl_member(context, actual_type->decl, kw);
|
||||
Decl *member = sema_decl_stack_find_decl_member(context, actual_type->decl, kw, METHODS_AND_FIELDS);
|
||||
if (!decl_ok(member)) return false;
|
||||
if (!member)
|
||||
{
|
||||
@@ -9134,14 +9134,6 @@ static inline BuiltinFunction builtin_by_name(const char *name)
|
||||
return BUILTIN_NONE;
|
||||
}
|
||||
|
||||
static inline TypeProperty type_property_by_name(const char *name)
|
||||
{
|
||||
for (unsigned i = 0; i < NUMBER_OF_TYPE_PROPERTIES; i++)
|
||||
{
|
||||
if (type_property_list[i] == name) return (TypeProperty)i;
|
||||
}
|
||||
return TYPE_PROPERTY_NONE;
|
||||
}
|
||||
|
||||
static inline bool sema_expr_analyse_retval(SemaContext *context, Expr *expr)
|
||||
{
|
||||
|
||||
@@ -242,4 +242,13 @@ static inline StorageType sema_resolve_storage_type(SemaContext *context, Type *
|
||||
default:
|
||||
return STORAGE_NORMAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline TypeProperty type_property_by_name(const char *name)
|
||||
{
|
||||
for (unsigned i = 0; i < NUMBER_OF_TYPE_PROPERTIES; i++)
|
||||
{
|
||||
if (type_property_list[i] == name) return (TypeProperty)i;
|
||||
}
|
||||
return TYPE_PROPERTY_NONE;
|
||||
}
|
||||
|
||||
@@ -80,11 +80,14 @@ static bool add_interface_to_decl_stack(SemaContext *context, Decl *decl)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool add_members_to_decl_stack(SemaContext *context, Decl *decl)
|
||||
static bool add_members_to_decl_stack(SemaContext *context, Decl *decl, FindMember find)
|
||||
{
|
||||
FOREACH(Decl *, func, decl->methods)
|
||||
if (find != FIELDS_ONLY)
|
||||
{
|
||||
sema_decl_stack_push(func);
|
||||
FOREACH(Decl *, func, decl->methods)
|
||||
{
|
||||
sema_decl_stack_push(func);
|
||||
}
|
||||
}
|
||||
while (decl->decl_kind == DECL_DISTINCT)
|
||||
{
|
||||
@@ -96,7 +99,7 @@ static bool add_members_to_decl_stack(SemaContext *context, Decl *decl)
|
||||
{
|
||||
FOREACH(Decl *, member, decl->enums.parameters) sema_decl_stack_push(member);
|
||||
}
|
||||
if (decl->decl_kind == DECL_INTERFACE)
|
||||
if (decl->decl_kind == DECL_INTERFACE && find != FIELDS_ONLY)
|
||||
{
|
||||
if (!add_interface_to_decl_stack(context, decl)) return false;
|
||||
}
|
||||
@@ -106,7 +109,7 @@ static bool add_members_to_decl_stack(SemaContext *context, Decl *decl)
|
||||
{
|
||||
if (member->name == NULL)
|
||||
{
|
||||
if (!add_members_to_decl_stack(context, member)) return false;
|
||||
if (!add_members_to_decl_stack(context, member, find)) return false;
|
||||
continue;
|
||||
}
|
||||
sema_decl_stack_push(member);
|
||||
@@ -115,10 +118,10 @@ static bool add_members_to_decl_stack(SemaContext *context, Decl *decl)
|
||||
return true;
|
||||
}
|
||||
|
||||
Decl *sema_decl_stack_find_decl_member(SemaContext *context, Decl *decl_owner, const char *symbol)
|
||||
Decl *sema_decl_stack_find_decl_member(SemaContext *context, Decl *decl_owner, const char *symbol, FindMember find)
|
||||
{
|
||||
Decl **state = sema_decl_stack_store();
|
||||
if (!add_members_to_decl_stack(context, decl_owner)) return poisoned_decl;
|
||||
if (!add_members_to_decl_stack(context, decl_owner, find)) return poisoned_decl;
|
||||
Decl *member = sema_decl_stack_resolve_symbol(symbol);
|
||||
sema_decl_stack_restore(state);
|
||||
return member;
|
||||
|
||||
7
test/test_suite/methods/method_name_collision.c3
Normal file
7
test/test_suite/methods/method_name_collision.c3
Normal file
@@ -0,0 +1,7 @@
|
||||
module testc3;
|
||||
|
||||
fn bool any.type(self) { // #error: is not a valid method name
|
||||
return true;
|
||||
}
|
||||
|
||||
fn void main() {}
|
||||
Reference in New Issue
Block a user