mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
New method resolution.
This commit is contained in:
committed by
Christoffer Lerno
parent
34b0b6f8f9
commit
4b95d6be4c
@@ -390,6 +390,7 @@ add_executable(c3c
|
||||
src/utils/unzipper.c
|
||||
src/compiler/c_codegen.c
|
||||
src/compiler/decltable.c
|
||||
src/compiler/methodtable.c
|
||||
src/compiler/mac_support.c
|
||||
src/compiler/windows_support.c
|
||||
src/compiler/codegen_asm.c
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
- Deprecate `@compact` use for comparison. Old behaviour is enabled using `--use-old-compact-eq`.
|
||||
- Switch available for types implementing `@operator(==)`.
|
||||
- `Type.is_eq` is now true for types with `==` overload.
|
||||
- Methods ignore visibility settings.
|
||||
|
||||
### Fixes
|
||||
- List.remove_at would incorrectly trigger ASAN.
|
||||
|
||||
@@ -75,9 +75,10 @@ void compiler_init(BuildOptions *build_options)
|
||||
|
||||
htable_init(&compiler.context.features, 1024);
|
||||
htable_init(&compiler.context.compiler_defines, 16 * 1024);
|
||||
methodtable_init(&compiler.context.method_extensions, 16 * 1024);
|
||||
compiler.context.module_list = NULL;
|
||||
compiler.context.generic_module_list = NULL;
|
||||
compiler.context.method_extensions = NULL;
|
||||
compiler.context.method_extension_list = NULL;
|
||||
|
||||
vmem_init(&ast_arena, START_VMEM_SIZE);
|
||||
ast_calloc();
|
||||
|
||||
@@ -121,6 +121,22 @@ typedef struct
|
||||
TypeKind type;
|
||||
} Float;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t count;
|
||||
uint32_t capacity;
|
||||
uint32_t max_load;
|
||||
DeclId *methods;
|
||||
} MethodTable;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t count;
|
||||
uint32_t capacity;
|
||||
uint32_t max_load;
|
||||
DeclId *entries;
|
||||
} DeclTable;
|
||||
|
||||
struct ConstInitializer_
|
||||
{
|
||||
ConstInitType kind;
|
||||
@@ -619,6 +635,13 @@ typedef struct
|
||||
AstId parent;
|
||||
} LabelDecl;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
DeclId overloads[OVERLOADS_COUNT + 1];
|
||||
DeclTable method_table;
|
||||
Decl **methods;
|
||||
} Methods;
|
||||
|
||||
typedef struct Decl_
|
||||
{
|
||||
const char *name;
|
||||
@@ -678,7 +701,7 @@ typedef struct Decl_
|
||||
struct
|
||||
{
|
||||
TypeInfo **interfaces;
|
||||
Decl **methods;
|
||||
Methods *method_table;
|
||||
union
|
||||
{
|
||||
// Enums and Fault
|
||||
@@ -1570,7 +1593,6 @@ typedef struct Module_
|
||||
AnalysisStage stage : 6;
|
||||
|
||||
AstId contracts;
|
||||
Decl** private_method_extensions;
|
||||
HTable symbols;
|
||||
struct CompilationUnit_ **units;
|
||||
Module *generic_module;
|
||||
@@ -1652,14 +1674,6 @@ typedef struct
|
||||
LexMode mode;
|
||||
} Lexer;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t count;
|
||||
uint32_t capacity;
|
||||
uint32_t max_load;
|
||||
DeclId *entries;
|
||||
} DeclTable;
|
||||
|
||||
struct CompilationUnit_
|
||||
{
|
||||
Module *module;
|
||||
@@ -1697,7 +1711,6 @@ struct CompilationUnit_
|
||||
Decl *main_function;
|
||||
HTable local_symbols;
|
||||
int lambda_count;
|
||||
Decl **local_method_extensions;
|
||||
TypeInfo **check_type_variable_array;
|
||||
struct
|
||||
{
|
||||
@@ -1899,7 +1912,6 @@ typedef struct
|
||||
Module **module_list;
|
||||
Module **generic_module_list;
|
||||
Type **type;
|
||||
Decl **method_extensions;
|
||||
const char *lib_dir;
|
||||
const char **sources;
|
||||
File **loaded_sources;
|
||||
@@ -1911,6 +1923,8 @@ typedef struct
|
||||
HTable compiler_defines;
|
||||
HTable features;
|
||||
Module std_module;
|
||||
MethodTable method_extensions;
|
||||
Decl **method_extension_list;
|
||||
DeclTable symbols;
|
||||
PathTable path_symbols;
|
||||
DeclTable generic_symbols;
|
||||
@@ -2160,6 +2174,7 @@ UNUSED bool i128_get_bit(const Int128 *op, int bit);
|
||||
#define MACRO_COPY_DECL(x) x = copy_decl(c, x)
|
||||
#define MACRO_COPY_DECLID(x) x = declid_copy_deep(c, x)
|
||||
#define MACRO_COPY_DECL_LIST(x) x = copy_decl_list(c, x)
|
||||
#define MACRO_COPY_DECL_METHODS(x) x = copy_decl_methods(c, x)
|
||||
#define MACRO_COPY_EXPR(x) x = copy_expr(c, x)
|
||||
#define MACRO_COPY_EXPRID(x) x = exprid_copy_deep(c, x)
|
||||
#define MACRO_COPY_TYPE(x) x = copy_type_info(c, x)
|
||||
@@ -2370,6 +2385,7 @@ Path *path_create_from_string(const char *string, uint32_t len, SourceSpan span)
|
||||
typedef enum FindMember
|
||||
{
|
||||
METHODS_AND_FIELDS,
|
||||
METHODS_INTERFACES_AND_FIELDS,
|
||||
FIELDS_ONLY
|
||||
} FindMember;
|
||||
|
||||
@@ -2418,8 +2434,9 @@ void sema_expr_convert_enum_to_int(Expr *expr);
|
||||
Decl *sema_decl_stack_resolve_symbol(const char *symbol);
|
||||
Decl *sema_find_decl_in_modules(Module **module_list, Path *path, const char *interned_name);
|
||||
bool unit_resolve_parameterized_symbol(SemaContext *context, NameResolve *name_resolve);
|
||||
Decl *sema_resolve_type_method(CompilationUnit *unit, Type *type, const char *method_name, Decl **ambiguous_ref, Decl **private_ref);
|
||||
Decl *sema_resolve_method(CompilationUnit *unit, Decl *type, const char *method_name, Decl **ambiguous_ref, Decl **private_ref);
|
||||
Decl *sema_resolve_type_method(CanonicalType *type, const char *method_name);
|
||||
Decl *sema_resolve_method(Decl *type, const char *method_name);
|
||||
Decl *sema_resolve_method_only(Decl *type, const char *method_name);
|
||||
Decl *sema_find_extension_method_in_list(Decl **extensions, Type *type, const char *method_name);
|
||||
bool sema_resolve_type_decl(SemaContext *context, Type *type);
|
||||
bool sema_check_type_variable_array(SemaContext *context, TypeInfo *type);
|
||||
@@ -2476,6 +2493,10 @@ void decltable_init(DeclTable *table, uint32_t initial_size);
|
||||
DeclId decltable_get(DeclTable *table, const char *name);
|
||||
void decltable_set(DeclTable *table, Decl *decl);
|
||||
|
||||
void methodtable_init(MethodTable *table, uint32_t initial_size);
|
||||
DeclId methodtable_get(MethodTable *table, Type *type, const char *name);
|
||||
DeclId methodtable_set(MethodTable *table, Decl *method);
|
||||
|
||||
const char *scratch_buffer_interned(void);
|
||||
const char *scratch_buffer_interned_as(TokenType *type);
|
||||
|
||||
@@ -2542,7 +2563,6 @@ bool type_is_abi_aggregate(Type *type);
|
||||
bool type_is_int128(Type *type);
|
||||
|
||||
Type *type_from_token(TokenType type);
|
||||
bool type_is_user_defined(Type *type);
|
||||
bool type_is_structurally_equivalent(Type *type1, Type *type);
|
||||
bool type_flat_is_floatlike(Type *type);
|
||||
bool type_flat_is_intlike(Type *type);
|
||||
@@ -2608,6 +2628,7 @@ INLINE TypeInfo *type_info_new(TypeInfoKind kind, SourceSpan span);
|
||||
INLINE TypeInfo *type_info_new_base(Type *type, SourceSpan span);
|
||||
INLINE bool type_info_ok(TypeInfo *type_info);
|
||||
INLINE bool type_info_poison(TypeInfo *type);
|
||||
INLINE bool type_is_user_defined(Type *type);
|
||||
|
||||
int type_kind_bitsize(TypeKind kind);
|
||||
INLINE bool type_kind_is_signed(TypeKind kind);
|
||||
@@ -3019,6 +3040,46 @@ INLINE Type *type_flatten_for_bitstruct(Type *type)
|
||||
return type;
|
||||
}
|
||||
|
||||
static inline void methods_add(Methods *methods, Decl *method)
|
||||
{
|
||||
vec_add(methods->methods, method);
|
||||
OperatorOverload operator = method->func_decl.operator;
|
||||
if (operator)
|
||||
{
|
||||
unsigned len = vec_size(method->func_decl.signature.params);
|
||||
if (operator == OVERLOAD_MINUS && len == 1)
|
||||
{
|
||||
method->func_decl.operator = operator = OVERLOAD_UNARY_MINUS;
|
||||
}
|
||||
|
||||
if (len > 1 && !method->func_decl.signature.params[1]->var.type_info)
|
||||
{
|
||||
method->func_decl.is_wildcard_overload = true;
|
||||
}
|
||||
DeclId *decl = &methods->overloads[operator];
|
||||
if (!*decl)
|
||||
{
|
||||
*decl = declid(method);
|
||||
}
|
||||
else
|
||||
{
|
||||
Decl *current = declptr(*decl);
|
||||
if (current->decl_kind != DECL_DECLARRAY)
|
||||
{
|
||||
Decl *decl_array = decl_new(DECL_DECLARRAY, NULL, INVALID_SPAN);
|
||||
vec_add(decl_array->decls, declptr(*decl));
|
||||
vec_add(decl_array->decls, method);
|
||||
*decl = declid(decl_array);
|
||||
}
|
||||
else
|
||||
{
|
||||
vec_add(current->decls, method);
|
||||
}
|
||||
}
|
||||
}
|
||||
decltable_set(&methods->method_table, method);
|
||||
}
|
||||
|
||||
static inline Type *type_base(Type *type)
|
||||
{
|
||||
while (1)
|
||||
@@ -3147,6 +3208,21 @@ static inline Type *type_flat_distinct_enum_inline(Type *type)
|
||||
}
|
||||
}
|
||||
|
||||
INLINE bool type_is_user_defined(Type *type)
|
||||
{
|
||||
static const bool user_defined_types[TYPE_LAST + 1] = {
|
||||
[TYPE_ENUM] = true,
|
||||
[TYPE_STRUCT] = true,
|
||||
[TYPE_FUNC_RAW] = true,
|
||||
[TYPE_UNION] = true,
|
||||
[TYPE_DISTINCT] = true,
|
||||
[TYPE_BITSTRUCT] = true,
|
||||
[TYPE_TYPEDEF] = true,
|
||||
[TYPE_INTERFACE] = true,
|
||||
};
|
||||
return user_defined_types[type->type_kind];
|
||||
}
|
||||
|
||||
static inline Type *type_flatten_to_int(Type *type)
|
||||
{
|
||||
while (1)
|
||||
|
||||
@@ -16,6 +16,7 @@ static Ast *ast_copy_deep(CopyStruct *c, Ast *source);
|
||||
static Ast **copy_ast_list(CopyStruct *c, Ast **to_copy);
|
||||
static Decl *copy_decl(CopyStruct *c, Decl *decl);
|
||||
static Decl **copy_decl_list(CopyStruct *c, Decl **decl_list);
|
||||
static Methods *copy_decl_methods(CopyStruct *c, Methods *methods);
|
||||
static TypeInfo *copy_type_info(CopyStruct *c, TypeInfo *source);
|
||||
|
||||
static inline void copy_reg_ref(CopyStruct *c, void *original, void *result)
|
||||
@@ -871,8 +872,6 @@ static ResolvedAttrData *copy_attrs_resolved(CopyStruct *c, ResolvedAttrData *da
|
||||
.section = data->section,
|
||||
.wasm_module = data->wasm_module
|
||||
};
|
||||
const char **new = NULL;
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
@@ -913,6 +912,19 @@ Decl **copy_decl_list(CopyStruct *c, Decl **decl_list)
|
||||
return result;
|
||||
}
|
||||
|
||||
static Methods *copy_decl_methods(CopyStruct *c, Methods *methods)
|
||||
{
|
||||
if (!methods) return NULL;
|
||||
Methods *copy = CALLOCS(Methods);
|
||||
decltable_init(©->method_table, 64);
|
||||
|
||||
FOREACH(Decl *, method, methods->methods)
|
||||
{
|
||||
methods_add(copy, copy_decl(c, method));
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
TypeInfo *copy_type_info(CopyStruct *c, TypeInfo *source)
|
||||
{
|
||||
if (!source) return NULL;
|
||||
@@ -1004,7 +1016,7 @@ Decl *copy_decl(CopyStruct *c, Decl *decl)
|
||||
case DECL_INTERFACE:
|
||||
copy_decl_type(copy);
|
||||
MACRO_COPY_TYPE_LIST(copy->interfaces);
|
||||
MACRO_COPY_DECL_LIST(copy->methods);
|
||||
MACRO_COPY_DECL_METHODS(copy->method_table);
|
||||
MACRO_COPY_DECL_LIST(copy->interface_methods);
|
||||
break;
|
||||
case DECL_CT_EXEC:
|
||||
@@ -1024,7 +1036,7 @@ Decl *copy_decl(CopyStruct *c, Decl *decl)
|
||||
MACRO_COPY_TYPE_LIST(copy->interfaces);
|
||||
MACRO_COPY_DECL_LIST(copy->strukt.members);
|
||||
MACRO_COPY_DECLID(copy->strukt.padded_decl_id);
|
||||
MACRO_COPY_DECL_LIST(copy->methods);
|
||||
MACRO_COPY_DECL_METHODS(copy->method_table);
|
||||
break;
|
||||
case DECL_DECLARRAY:
|
||||
case DECL_GROUP:
|
||||
@@ -1035,21 +1047,21 @@ Decl *copy_decl(CopyStruct *c, Decl *decl)
|
||||
MACRO_COPY_TYPE_LIST(copy->interfaces);
|
||||
MACRO_COPY_DECL_LIST(copy->strukt.members);
|
||||
MACRO_COPY_TYPE(copy->strukt.container_type);
|
||||
MACRO_COPY_DECL_LIST(copy->methods);
|
||||
MACRO_COPY_DECL_METHODS(copy->method_table);
|
||||
break;
|
||||
case DECL_FAULT:
|
||||
break;
|
||||
case DECL_CONST_ENUM:
|
||||
copy_decl_type(copy);
|
||||
MACRO_COPY_TYPE_LIST(copy->interfaces);
|
||||
MACRO_COPY_DECL_LIST(copy->methods);
|
||||
MACRO_COPY_DECL_METHODS(copy->method_table);
|
||||
MACRO_COPY_TYPE(copy->enums.type_info);
|
||||
MACRO_COPY_DECL_LIST(copy->enums.values);
|
||||
break;
|
||||
case DECL_ENUM:
|
||||
copy_decl_type(copy);
|
||||
MACRO_COPY_TYPE_LIST(copy->interfaces);
|
||||
MACRO_COPY_DECL_LIST(copy->methods);
|
||||
MACRO_COPY_DECL_METHODS(copy->method_table);
|
||||
MACRO_COPY_DECL_LIST(copy->enums.parameters);
|
||||
MACRO_COPY_TYPE(copy->enums.type_info);
|
||||
MACRO_COPY_DECL_LIST(copy->enums.values);
|
||||
@@ -1112,7 +1124,7 @@ Decl *copy_decl(CopyStruct *c, Decl *decl)
|
||||
case DECL_DISTINCT:
|
||||
copy_decl_type(copy);
|
||||
MACRO_COPY_TYPE_LIST(copy->interfaces);
|
||||
MACRO_COPY_DECL_LIST(copy->methods);
|
||||
MACRO_COPY_DECL_METHODS(copy->method_table);
|
||||
MACRO_COPY_TYPE(copy->distinct);
|
||||
break;
|
||||
case DECL_CT_ECHO:
|
||||
|
||||
@@ -89,4 +89,4 @@ void decltable_init(DeclTable *table, uint32_t initial_size)
|
||||
table->capacity = initial_size;
|
||||
table->max_load = (uint32_t)(initial_size * TABLE_MAX_LOAD);
|
||||
table->entries = entries;
|
||||
}
|
||||
}
|
||||
|
||||
73
src/compiler/methodtable.c
Normal file
73
src/compiler/methodtable.c
Normal file
@@ -0,0 +1,73 @@
|
||||
#include "compiler_internal.h"
|
||||
|
||||
static inline DeclId *methodentry_find(DeclId *entries, uint32_t capacity, const char *name, Type *type)
|
||||
{
|
||||
uintptr_t hash_key = (uintptr_t)name ^ (uintptr_t)type;
|
||||
uint32_t mask = capacity - 1;
|
||||
hash_key ^= hash_key >> 16;
|
||||
uint32_t index = (uint32_t)hash_key & mask;
|
||||
while (1)
|
||||
{
|
||||
DeclId *entry = &entries[index];
|
||||
DeclId decl_id = *entry;
|
||||
if (!decl_id) return entry;
|
||||
Decl *decl = declptr(*entry);
|
||||
if (decl->name == name && typeget(decl->func_decl.type_parent) == type) return entry;
|
||||
index = (index + 1) & mask;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void methodtable_resize(MethodTable *table)
|
||||
{
|
||||
ASSERT(table->capacity < MAX_HASH_SIZE && "Table size too large, exceeded max hash size");
|
||||
uint32_t new_capacity = table->capacity ? (table->capacity << 2u) : 16u;
|
||||
DeclId *new_data = CALLOC(new_capacity * sizeof(DeclId));
|
||||
table->count = 0;
|
||||
uint32_t len = table->capacity;
|
||||
for (uint32_t i = 0; i < len; i++)
|
||||
{
|
||||
DeclId *entry = &table->methods[i];
|
||||
DeclId id = *entry;
|
||||
if (!id) continue;
|
||||
Decl *decl = declptr(id);
|
||||
table->count++;
|
||||
DeclId *dest = methodentry_find(new_data, new_capacity, decl->name, typeget(decl->func_decl.type_parent));
|
||||
*dest = id;
|
||||
}
|
||||
table->methods = new_data;
|
||||
table->max_load = (uint32_t)(new_capacity * TABLE_MAX_LOAD);
|
||||
table->capacity = new_capacity;
|
||||
}
|
||||
|
||||
DeclId methodtable_set(MethodTable *table, Decl *decl)
|
||||
{
|
||||
ASSERT(decl && "Cannot insert NULL");
|
||||
DeclId *entry = methodentry_find(table->methods, table->capacity, decl->name, typeget(decl->func_decl.type_parent));
|
||||
DeclId decl_id = declid(decl);
|
||||
DeclId old_id = *entry;
|
||||
if (old_id) return old_id;
|
||||
*entry = decl_id;
|
||||
table->count++;
|
||||
if (table->count >= table->max_load) methodtable_resize(table);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
DeclId methodtable_get(MethodTable *table, Type *type, const char *name)
|
||||
{
|
||||
if (!table->methods) return 0;
|
||||
DeclId *entry = methodentry_find(table->methods, table->capacity, name, type);
|
||||
return *entry;
|
||||
}
|
||||
|
||||
void methodtable_init(MethodTable *table, uint32_t initial_size)
|
||||
{
|
||||
ASSERT(initial_size && "Size must be larger than 0");
|
||||
assert (is_power_of_two(initial_size) && "Must be a power of two");
|
||||
|
||||
DeclId *entries = CALLOC(initial_size * sizeof(DeclId));
|
||||
table->count = 0;
|
||||
table->capacity = initial_size;
|
||||
table->max_load = (uint32_t)(initial_size * TABLE_MAX_LOAD);
|
||||
table->methods = entries;
|
||||
}
|
||||
@@ -9,18 +9,13 @@ static inline bool sema_analyse_macro(SemaContext *context, Decl *decl, bool *er
|
||||
static inline bool sema_analyse_signature(SemaContext *context, Signature *sig, TypeInfo *method_parent, Decl *decl);
|
||||
static inline bool sema_analyse_main_function(SemaContext *context, Decl *decl);
|
||||
static inline bool sema_check_param_uniqueness_and_type(SemaContext *context, Decl **decls, Decl *current,
|
||||
unsigned current_index, unsigned count);
|
||||
unsigned current_index);
|
||||
static inline bool sema_analyse_method(SemaContext *context, Decl *decl);
|
||||
static inline bool sema_is_valid_method_param(SemaContext *context, Decl *param, Type *parent_type, bool is_dynamic);
|
||||
static inline bool sema_analyse_macro_method(SemaContext *context, Decl *decl);
|
||||
static inline bool unit_add_base_extension_method(SemaContext *context, CompilationUnit *unit, Type *parent_type,
|
||||
Decl *method);
|
||||
static inline bool unit_add_method(SemaContext *context, Type *parent_type, Decl *method);
|
||||
static bool sema_analyse_operator_common(SemaContext *context, Decl *method, TypeInfo **rtype_ptr, Decl ***params_ptr,
|
||||
uint32_t parameters);
|
||||
static inline OverloadMatch operator_in_module_typed(SemaContext *c, Module *module, OperatorOverload operator_overload,
|
||||
OverloadType overload_type, Type *method_type, Expr *binary_arg, Type *binary_type, Decl **candidate_ref, OverloadMatch last_match, Decl **ambiguous_ref);
|
||||
static inline Decl *operator_in_module_exact_typed(Module *module, OperatorOverload operator_overload, OverloadType overload_type, Type *method_type, Type *param_type, Decl *skipped);
|
||||
static inline bool unit_add_base_extension_method(SemaContext *context, Decl *method);
|
||||
static inline bool type_add_method(SemaContext *context, Type *parent_type, Decl *method);
|
||||
static bool sema_analyse_operator_common(SemaContext *context, Decl *method, TypeInfo **rtype_ptr, Decl ***params_ptr, uint32_t parameters);
|
||||
static inline bool sema_analyse_operator_element_at(SemaContext *context, Decl *method);
|
||||
static inline bool sema_analyse_operator_element_set(SemaContext *context, Decl *method);
|
||||
static inline bool sema_analyse_operator_len(SemaContext *context, Decl *method);
|
||||
@@ -40,13 +35,11 @@ static inline bool sema_analyse_doc_header(SemaContext *context, AstId doc, Decl
|
||||
|
||||
static const char *attribute_domain_to_string(AttributeDomain domain);
|
||||
static bool sema_analyse_attribute(SemaContext *context, ResolvedAttrData *attr_data, Decl *decl, Attr *attr, AttributeDomain domain, bool *erase_decl);
|
||||
static bool sema_analyse_attributes_inner(SemaContext *context, ResolvedAttrData *attr_data, Decl *decl, Attr **attrs, AttributeDomain domain,
|
||||
static bool sema_analyse_attributes_inner(SemaContext *context, ResolvedAttrData *attr_data_ref, Decl *decl, Attr **attrs, AttributeDomain domain,
|
||||
Decl *top, bool *erase_decl);
|
||||
static bool sema_analyse_attributes_for_var(SemaContext *context, Decl *decl, bool *erase_decl);
|
||||
static bool sema_check_section(SemaContext *context, Attr *attr);
|
||||
static inline bool sema_analyse_attribute_decl(SemaContext *context, SemaContext *c, Decl *decl, bool *erase_decl);
|
||||
static OverloadMatch sema_find_typed_operator_in_list(SemaContext *context, Decl **methods, OperatorOverload operator_overload, OverloadType overload_type, Type *parent_type, Expr *binary_arg, Type *binary_type, Decl **candidate_ref, OverloadMatch current_match, Decl **ambiguous_ref);
|
||||
static Decl *sema_find_exact_typed_operator_in_list(Decl **methods, OperatorOverload operator_overload, OverloadType overload_type, Type *parent_type, Type *binary_type, Decl *skipped);
|
||||
|
||||
static inline bool sema_analyse_typedef(SemaContext *context, Decl *decl, bool *erase_decl);
|
||||
static bool sema_analyse_variable_type(SemaContext *context, Type *type, SourceSpan span);
|
||||
@@ -97,7 +90,7 @@ static bool sema_check_section(SemaContext *context, Attr *attr)
|
||||
* Check parameter name uniqueness and that the type is not void.
|
||||
*/
|
||||
static inline bool sema_check_param_uniqueness_and_type(SemaContext *context, Decl **decls, Decl *current,
|
||||
unsigned current_index, unsigned count)
|
||||
unsigned current_index)
|
||||
{
|
||||
|
||||
const char *name = current->name;
|
||||
@@ -1420,7 +1413,7 @@ static inline bool sema_analyse_signature(SemaContext *context, Signature *sig,
|
||||
if (!sema_analyse_expr_rhs(context, param->type, expr, true, NULL, false)) return decl_poison(param);
|
||||
}
|
||||
}
|
||||
if (!sema_check_param_uniqueness_and_type(context, params, param, i, param_count)) return decl_poison(param);
|
||||
if (!sema_check_param_uniqueness_and_type(context, params, param, i)) return decl_poison(param);
|
||||
param->resolve_status = RESOLVE_DONE;
|
||||
}
|
||||
return true;
|
||||
@@ -1855,122 +1848,64 @@ static bool sema_analyse_operator_common(SemaContext *context, Decl *method, Typ
|
||||
return true;
|
||||
}
|
||||
|
||||
INLINE bool decl_matches_overload(Decl *method, Type *type, OperatorOverload overload)
|
||||
{
|
||||
return method->func_decl.operator == overload && typeget(method->func_decl.type_parent)->canonical == type;
|
||||
}
|
||||
|
||||
static inline OverloadMatch operator_in_module_typed(SemaContext *c, Module *module, OperatorOverload operator_overload, OverloadType overload_type, Type *method_type, Expr *binary_arg, Type *binary_type, Decl **candidate_ref, OverloadMatch match, Decl **ambiguous_ref)
|
||||
{
|
||||
if (match == OVERLOAD_MATCH_ERROR) return match;
|
||||
if (module->is_generic) return match;
|
||||
match = sema_find_typed_operator_in_list(c, module->private_method_extensions, operator_overload, OVERLOAD_TYPE_SYMMETRIC, method_type, binary_arg, binary_type, candidate_ref, match, ambiguous_ref);
|
||||
FOREACH(Module *, sub_module, module->sub_modules)
|
||||
{
|
||||
match = operator_in_module_typed(c, sub_module, operator_overload, overload_type, method_type, binary_arg, binary_type, candidate_ref, match, ambiguous_ref);
|
||||
}
|
||||
return match;
|
||||
}
|
||||
|
||||
static inline Decl *operator_in_module_exact_typed(Module *module, OperatorOverload operator_overload, OverloadType overload_type, Type *method_type, Type *param_type, Decl *skipped)
|
||||
{
|
||||
if (module->is_generic) return NULL;
|
||||
Decl *found = sema_find_exact_typed_operator_in_list(module->private_method_extensions, operator_overload, overload_type, method_type, param_type, skipped);
|
||||
if (found) return found;
|
||||
FOREACH(Module *, sub_module, module->sub_modules)
|
||||
{
|
||||
return operator_in_module_exact_typed(sub_module, operator_overload, overload_type, method_type, param_type, skipped);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline Decl *operator_in_module_untyped(Module *module, Type *type, OperatorOverload operator_overload, Decl *skipped)
|
||||
{
|
||||
if (module->is_generic) return NULL;
|
||||
FOREACH(Decl *, extension, module->private_method_extensions)
|
||||
{
|
||||
if (extension == skipped) continue;
|
||||
if (decl_matches_overload(extension, type, operator_overload))
|
||||
{
|
||||
return extension;
|
||||
}
|
||||
}
|
||||
FOREACH(Module *, sub_module, module->sub_modules)
|
||||
{
|
||||
return operator_in_module_untyped(sub_module, type, operator_overload, skipped);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Decl *sema_find_untyped_operator(SemaContext *context, Type *type, OperatorOverload operator_overload, Decl *skipped)
|
||||
Decl *sema_find_untyped_operator(Type *type, OperatorOverload operator_overload, Decl *skipped)
|
||||
{
|
||||
type = type->canonical;
|
||||
assert(operator_overload < OVERLOAD_TYPED_START);
|
||||
if (!type_may_have_sub_elements(type)) return NULL;
|
||||
Decl *def = type->decl;
|
||||
FOREACH(Decl *, func, def->methods)
|
||||
if (!def->method_table) return NULL;
|
||||
Decl *decl = declptrzero(def->method_table->overloads[operator_overload]);
|
||||
if (!decl) return NULL;
|
||||
if (decl->decl_kind != DECL_DECLARRAY)
|
||||
{
|
||||
if (skipped == func) continue;
|
||||
if (func->func_decl.operator == operator_overload) return func;
|
||||
return decl == skipped ? NULL : decl;
|
||||
}
|
||||
FOREACH(Decl *, extension, context->unit->local_method_extensions)
|
||||
FOREACH(Decl *, candidate, decl->decls)
|
||||
{
|
||||
if (skipped == extension) continue;
|
||||
if (decl_matches_overload(extension, type, operator_overload)) return extension;
|
||||
}
|
||||
Decl *extension = operator_in_module_untyped(context->compilation_unit->module, type, operator_overload, skipped);
|
||||
if (extension) return extension;
|
||||
FOREACH(Decl *, import, context->unit->public_imports)
|
||||
{
|
||||
extension = operator_in_module_untyped(import->import.module, type, operator_overload, skipped);
|
||||
if (extension) return extension;
|
||||
return candidate == skipped ? NULL : candidate;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static Decl *sema_find_exact_typed_operator_in_list(Decl **methods, OperatorOverload operator_overload, OverloadType overload_type, Type *parent_type, Type *binary_type, Decl *skipped)
|
||||
{
|
||||
Decl *wildcard = NULL;
|
||||
FOREACH(Decl *, func, methods)
|
||||
{
|
||||
if (func == skipped) continue;
|
||||
if (!decl_ok(func)) continue;
|
||||
if (func->func_decl.operator != operator_overload) continue;
|
||||
if (parent_type && parent_type != typeget(func->func_decl.type_parent)) continue;
|
||||
if ((overload_type & func->func_decl.overload_type) == 0) continue;
|
||||
if (func->func_decl.is_wildcard_overload)
|
||||
{
|
||||
wildcard = func;
|
||||
continue;
|
||||
}
|
||||
Type *first_arg = func->func_decl.signature.params[1]->type;
|
||||
if (first_arg->canonical != binary_type) continue;
|
||||
return func;
|
||||
}
|
||||
return wildcard;
|
||||
}
|
||||
|
||||
static OverloadMatch sema_find_typed_operator_in_list(SemaContext *context, Decl **methods, OperatorOverload operator_overload, OverloadType overload_type, Type *parent_type, Expr *binary_arg, Type *binary_type, Decl **candidate_ref, OverloadMatch last_match, Decl **ambiguous_ref)
|
||||
|
||||
OverloadMatch sema_find_typed_operator_type(SemaContext *context, OperatorOverload operator_overload, OverloadType overload_type, Type *lhs_type, Type *rhs_type, Expr *rhs, Decl **candidate_ref, OverloadMatch last_match, Decl **ambiguous_ref)
|
||||
{
|
||||
if (last_match == OVERLOAD_MATCH_AMBIGUOUS_EXACT || last_match == OVERLOAD_MATCH_ERROR) return last_match;
|
||||
Methods *methods = lhs_type->decl->method_table;
|
||||
if (!methods || last_match == OVERLOAD_MATCH_AMBIGUOUS_EXACT || last_match == OVERLOAD_MATCH_ERROR) return last_match;
|
||||
Decl *decl = declptrzero(methods->overloads[operator_overload]);
|
||||
if (!decl) return last_match;
|
||||
Decl **decls;
|
||||
unsigned count;
|
||||
Decl *candidate = *candidate_ref;
|
||||
FOREACH(Decl *, func, methods)
|
||||
if (decl->decl_kind == DECL_DECLARRAY)
|
||||
{
|
||||
decls = decl->decls;
|
||||
count = vec_size(decls);
|
||||
}
|
||||
else
|
||||
{
|
||||
decls = &decl;
|
||||
count = 1;
|
||||
}
|
||||
for (unsigned i = 0; i < count; i++)
|
||||
{
|
||||
Decl *func = decls[i];
|
||||
if (!sema_analyse_decl(context, func)) return OVERLOAD_MATCH_ERROR;
|
||||
ASSERT_SPAN(func, func->resolve_status == RESOLVE_DONE);
|
||||
if (func->func_decl.operator != operator_overload) continue;
|
||||
if (parent_type && parent_type != typeget(func->func_decl.type_parent)) continue;
|
||||
if ((overload_type & func->func_decl.overload_type) == 0) continue;
|
||||
if (candidate == func) continue;
|
||||
if ((overload_type & func->func_decl.overload_type) == 0) continue;
|
||||
OverloadMatch match = OVERLOAD_MATCH_WILDCARD;
|
||||
if (!func->func_decl.is_wildcard_overload)
|
||||
{
|
||||
Type *first_arg = func->func_decl.signature.params[1]->type->canonical;
|
||||
match = OVERLOAD_MATCH_EXACT;
|
||||
if (first_arg != binary_type)
|
||||
if (first_arg != rhs_type)
|
||||
{
|
||||
if (!binary_arg) continue;
|
||||
if (!may_cast(context, binary_arg, first_arg, false, true)) continue;
|
||||
if (!rhs) continue;
|
||||
if (!may_cast(context, rhs, first_arg, false, true)) continue;
|
||||
match = OVERLOAD_MATCH_CONVERSION;
|
||||
}
|
||||
}
|
||||
@@ -2010,7 +1945,7 @@ static OverloadMatch sema_find_typed_operator_in_list(SemaContext *context, Decl
|
||||
}
|
||||
UNREACHABLE;
|
||||
}
|
||||
MATCH:
|
||||
MATCH:
|
||||
candidate = func;
|
||||
last_match = match;
|
||||
}
|
||||
@@ -2018,54 +1953,6 @@ MATCH:
|
||||
return last_match;
|
||||
}
|
||||
|
||||
static Decl *sema_find_exact_typed_operator(SemaContext *context, Type *type, OperatorOverload operator_overload, OverloadType overload_type, Type *param_type, Decl *skipped)
|
||||
{
|
||||
assert(operator_overload >= OVERLOAD_TYPED_START);
|
||||
type = type->canonical;
|
||||
|
||||
Decl *func = sema_find_exact_typed_operator_in_list(type->decl->methods, operator_overload, overload_type, type,
|
||||
param_type, skipped);
|
||||
if (func) return func;
|
||||
|
||||
Decl *extension = sema_find_exact_typed_operator_in_list(context->unit->local_method_extensions,
|
||||
operator_overload, overload_type, type, param_type, skipped);
|
||||
if (extension) return extension;
|
||||
|
||||
extension = operator_in_module_exact_typed(context->compilation_unit->module, operator_overload, overload_type,
|
||||
type, param_type, skipped);
|
||||
if (extension) return extension;
|
||||
|
||||
FOREACH(Decl *, import, context->unit->imports)
|
||||
{
|
||||
if (!import->import.import_private_as_public) continue;
|
||||
extension = operator_in_module_exact_typed(import->import.module, operator_overload, overload_type,
|
||||
type, param_type, skipped);
|
||||
if (extension) return extension;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
OverloadMatch sema_find_typed_operator_type(SemaContext *context, OperatorOverload operator_overload, OverloadType overloat_type, Type *lhs_type, Type *rhs_type, Expr *rhs, Decl **candidate_ref, OverloadMatch last_match, Decl **ambiguous_ref)
|
||||
{
|
||||
// Can we find the overload directly on the method?
|
||||
last_match = sema_find_typed_operator_in_list(
|
||||
context, lhs_type->decl->methods,
|
||||
operator_overload, overloat_type, lhs_type,
|
||||
rhs, rhs_type, candidate_ref, last_match, ambiguous_ref);
|
||||
last_match = sema_find_typed_operator_in_list(context, context->unit->local_method_extensions,
|
||||
operator_overload, overloat_type, lhs_type, rhs, rhs_type, candidate_ref, last_match, ambiguous_ref);
|
||||
// Can we find it in the current module?
|
||||
last_match = operator_in_module_typed(context, context->compilation_unit->module, operator_overload, overloat_type,
|
||||
lhs_type, rhs, rhs_type, candidate_ref, last_match, ambiguous_ref);
|
||||
|
||||
FOREACH(Decl *, import, context->unit->public_imports)
|
||||
{
|
||||
last_match = operator_in_module_typed(context, import->import.module, operator_overload, overloat_type,
|
||||
lhs_type, rhs, rhs_type, candidate_ref, last_match, ambiguous_ref);
|
||||
}
|
||||
return last_match;
|
||||
}
|
||||
|
||||
const char *operator_overload_to_string(OperatorOverload operator_overload)
|
||||
{
|
||||
switch (operator_overload)
|
||||
@@ -2157,10 +2044,6 @@ static inline bool sema_analyse_operator_unary(SemaContext *context, Decl *metho
|
||||
|
||||
static inline bool sema_analyse_operator_arithmetics(SemaContext *context, Decl *method, OperatorOverload operator_overload)
|
||||
{
|
||||
if (operator_overload == OVERLOAD_MINUS && vec_size(method->func_decl.signature.params) < 2)
|
||||
{
|
||||
return sema_analyse_operator_unary(context, method, method->func_decl.operator = OVERLOAD_UNARY_MINUS);
|
||||
}
|
||||
Signature *signature = &method->func_decl.signature;
|
||||
Decl **params = signature->params;
|
||||
uint32_t param_count = vec_size(params);
|
||||
@@ -2278,9 +2161,8 @@ static bool sema_check_operator_method_validity(SemaContext *context, Decl *meth
|
||||
case OVERLOAD_SHL_ASSIGN:
|
||||
return sema_analyse_operator_arithmetics(context, method, operator);
|
||||
case OVERLOAD_NEGATE:
|
||||
return sema_analyse_operator_unary(context, method, operator);
|
||||
case OVERLOAD_UNARY_MINUS:
|
||||
// Changed in OVERLOAD_MINUS analysis
|
||||
return sema_analyse_operator_unary(context, method, operator);
|
||||
UNREACHABLE
|
||||
}
|
||||
ASSERT_SPANF(method, false, "Method had unexpected operator %d", operator);
|
||||
@@ -2317,22 +2199,17 @@ INLINE SourceSpan method_find_overload_span(Decl *method)
|
||||
return method->attrs_resolved->overload;
|
||||
}
|
||||
|
||||
static inline bool unit_add_base_extension_method(UNUSED SemaContext *context, CompilationUnit *unit, Type *parent_type, Decl *method)
|
||||
static inline bool unit_add_base_extension_method(SemaContext *context, Decl *method)
|
||||
{
|
||||
// Add it to the right list of extensions.
|
||||
switch (method->visibility)
|
||||
Decl *other = declptrzero(methodtable_set(&compiler.context.method_extensions, method));
|
||||
if (other)
|
||||
{
|
||||
case VISIBLE_PUBLIC:
|
||||
vec_add(compiler.context.method_extensions, method);
|
||||
break;
|
||||
case VISIBLE_PRIVATE:
|
||||
vec_add(unit->module->private_method_extensions, method);
|
||||
break;
|
||||
case VISIBLE_LOCAL:
|
||||
vec_add(unit->local_method_extensions, method);
|
||||
break;
|
||||
SEMA_ERROR(method, "This %s is already defined.", method_name_by_decl(method));
|
||||
SEMA_NOTE(other, "The previous definition was here.");
|
||||
return false;
|
||||
}
|
||||
DEBUG_LOG("Method-like '%s.%s' analysed.", parent_type->name, method->name);
|
||||
vec_add(compiler.context.method_extension_list, method);
|
||||
DEBUG_LOG("Builtin type method '%s' analysed.", method->name);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2421,8 +2298,8 @@ INLINE bool sema_analyse_operator_method(SemaContext *context, Type *parent_type
|
||||
// See if the operator has already been defined.
|
||||
OperatorOverload operator = method->func_decl.operator;
|
||||
|
||||
|
||||
Type *second_param = NULL;
|
||||
bool is_wildcard = false;
|
||||
if (vec_size(method->func_decl.signature.params) > 1)
|
||||
{
|
||||
second_param = method->func_decl.signature.params[1]->type;
|
||||
@@ -2432,7 +2309,7 @@ INLINE bool sema_analyse_operator_method(SemaContext *context, Type *parent_type
|
||||
{
|
||||
RETURN_SEMA_ERROR(method, "Only regular overloads can have untyped right hand parameters");
|
||||
}
|
||||
method->func_decl.is_wildcard_overload = true;
|
||||
is_wildcard = method->func_decl.is_wildcard_overload = true;
|
||||
second_param = type_void;
|
||||
}
|
||||
second_param = second_param->canonical;
|
||||
@@ -2446,11 +2323,46 @@ INLINE bool sema_analyse_operator_method(SemaContext *context, Type *parent_type
|
||||
Decl *other = NULL;
|
||||
if (operator >= OVERLOAD_TYPED_START)
|
||||
{
|
||||
other = sema_find_exact_typed_operator(context, parent_type, operator, method->func_decl.overload_type, second_param, method); // NOLINT
|
||||
Methods *methods = parent_type->decl->method_table;
|
||||
if (!methods) goto NONE;
|
||||
Decl *decl = declptrzero(methods->overloads[operator]);
|
||||
if (!decl) goto NONE;
|
||||
Decl **decls;
|
||||
unsigned count;
|
||||
if (decl->decl_kind == DECL_DECLARRAY)
|
||||
{
|
||||
decls = decl->decls;
|
||||
count = vec_size(decls);
|
||||
}
|
||||
else
|
||||
{
|
||||
decls = &decl;
|
||||
count = 1;
|
||||
}
|
||||
OverloadType type = method->func_decl.overload_type;
|
||||
assert(type);
|
||||
for (unsigned i = 0; i < count; i++)
|
||||
{
|
||||
Decl *func = decls[i];
|
||||
if (func == method) continue;
|
||||
assert(func->func_decl.operator);
|
||||
if ((func->func_decl.overload_type & type) == 0) continue;
|
||||
if (!sema_analyse_decl(context, func)) return false;
|
||||
ASSERT_SPAN(func, func->decl_kind == DECL_FUNC || func->decl_kind == DECL_MACRO);
|
||||
if (is_wildcard && func->func_decl.is_wildcard_overload)
|
||||
{
|
||||
other = func;
|
||||
break;
|
||||
}
|
||||
if (is_wildcard || func->func_decl.is_wildcard_overload) continue;
|
||||
if (func->func_decl.signature.params[1]->type->canonical != second_param) continue;
|
||||
other = func;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
other = sema_find_untyped_operator(context, parent_type, operator, method);
|
||||
other = sema_find_untyped_operator(parent_type, operator, method);
|
||||
}
|
||||
if (other)
|
||||
{
|
||||
@@ -2459,7 +2371,7 @@ INLINE bool sema_analyse_operator_method(SemaContext *context, Type *parent_type
|
||||
SEMA_NOTE(other, "The previous definition was here.");
|
||||
return false;
|
||||
}
|
||||
|
||||
NONE:
|
||||
if (parent_type->canonical->type_kind == TYPE_BITSTRUCT)
|
||||
{
|
||||
switch (operator)
|
||||
@@ -2490,48 +2402,54 @@ INLINE bool sema_analyse_operator_method(SemaContext *context, Type *parent_type
|
||||
return true;
|
||||
case OVERLOAD_ELEMENT_AT:
|
||||
// [] compares &[]
|
||||
other = sema_find_untyped_operator(context, parent_type, OVERLOAD_ELEMENT_REF, method);
|
||||
if (other && decl_ok(other))
|
||||
other = sema_find_untyped_operator(parent_type, OVERLOAD_ELEMENT_REF, method);
|
||||
if (other)
|
||||
{
|
||||
if (!sema_analyse_decl(context, other)) return false;
|
||||
sema_get_overload_arguments(other, &value, &index_type);
|
||||
break;
|
||||
}
|
||||
// And []=
|
||||
other = sema_find_untyped_operator(context, parent_type, OVERLOAD_ELEMENT_SET, method);
|
||||
if (other && decl_ok(other))
|
||||
other = sema_find_untyped_operator(parent_type, OVERLOAD_ELEMENT_SET, method);
|
||||
if (other)
|
||||
{
|
||||
if (!sema_analyse_decl(context, other)) return false;
|
||||
sema_get_overload_arguments(other, &value, &index_type);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
case OVERLOAD_ELEMENT_REF:
|
||||
// &[] compares []
|
||||
other = sema_find_untyped_operator(context, parent_type, OVERLOAD_ELEMENT_AT, method);
|
||||
if (other && decl_ok(other))
|
||||
other = sema_find_untyped_operator(parent_type, OVERLOAD_ELEMENT_AT, method);
|
||||
if (other)
|
||||
{
|
||||
if (!sema_analyse_decl(context, other)) return false;
|
||||
sema_get_overload_arguments(other, &value, &index_type);
|
||||
break;
|
||||
}
|
||||
// And []=
|
||||
other = sema_find_untyped_operator(context, parent_type, OVERLOAD_ELEMENT_SET, method);
|
||||
if (other && decl_ok(other))
|
||||
other = sema_find_untyped_operator(parent_type, OVERLOAD_ELEMENT_SET, method);
|
||||
if (other)
|
||||
{
|
||||
if (!sema_analyse_decl(context, other)) return false;
|
||||
sema_get_overload_arguments(other, &value, &index_type);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
case OVERLOAD_ELEMENT_SET:
|
||||
// []= compares &[]
|
||||
other = sema_find_untyped_operator(context, parent_type, OVERLOAD_ELEMENT_REF, method);
|
||||
if (other && decl_ok(other))
|
||||
other = sema_find_untyped_operator(parent_type, OVERLOAD_ELEMENT_REF, method);
|
||||
if (other)
|
||||
{
|
||||
if (!sema_analyse_decl(context, other)) return false;
|
||||
sema_get_overload_arguments(other, &value, &index_type);
|
||||
break;
|
||||
}
|
||||
// And []
|
||||
other = sema_find_untyped_operator(context, parent_type, OVERLOAD_ELEMENT_AT, method);
|
||||
if (other && decl_ok(other))
|
||||
other = sema_find_untyped_operator(parent_type, OVERLOAD_ELEMENT_AT, method);
|
||||
if (other)
|
||||
{
|
||||
if (!sema_analyse_decl(context, other)) return false;
|
||||
sema_get_overload_arguments(other, &value, &index_type);
|
||||
break;
|
||||
}
|
||||
@@ -2607,34 +2525,27 @@ INLINE bool sema_analyse_operator_method(SemaContext *context, Type *parent_type
|
||||
* 5. Register its external name.
|
||||
* 6. Add the module according to visibility.
|
||||
*/
|
||||
static inline bool unit_add_method(SemaContext *context, Type *parent_type, Decl *method)
|
||||
static inline bool type_add_method(SemaContext *context, Type *parent_type, Decl *method)
|
||||
{
|
||||
CompilationUnit *unit = context->unit;
|
||||
ASSERT(parent_type->canonical == parent_type);
|
||||
const char *name = method->name;
|
||||
|
||||
// Did we already define it externally?
|
||||
Decl *other = sema_find_extension_method_in_list(unit->local_method_extensions, parent_type, name);
|
||||
if (!other) other = sema_find_extension_method_in_list(unit->module->private_method_extensions, parent_type, name);
|
||||
if (!other) other = sema_find_extension_method_in_list(compiler.context.method_extensions, parent_type, name);
|
||||
if (other)
|
||||
{
|
||||
SEMA_ERROR(method, "This %s is already defined.", method_name_by_decl(method));
|
||||
SEMA_NOTE(other, "The previous definition was here.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Attributes needs to be resolved early
|
||||
bool erase_decl = false;
|
||||
if (!sema_analyse_attributes(context, method, method->attributes,
|
||||
method->decl_kind == DECL_MACRO ? ATTR_MACRO : ATTR_FUNC, &erase_decl)) return decl_poison(method);
|
||||
if (erase_decl) return true;
|
||||
|
||||
// Is it a base extension?
|
||||
if (!type_is_user_defined(parent_type)) return unit_add_base_extension_method(context, unit, parent_type, method);
|
||||
if (!type_is_user_defined(parent_type)) return unit_add_base_extension_method(context, method);
|
||||
|
||||
// Resolve it as a user-defined type extension.
|
||||
Decl *parent = parent_type->decl;
|
||||
Decl *ambiguous = NULL;
|
||||
Decl *private = NULL;
|
||||
|
||||
// If we found it, issue an error.
|
||||
other = sema_resolve_method(unit, parent, name, &ambiguous, &private);
|
||||
Decl *other = sema_resolve_method(parent, name);
|
||||
if (!decl_ok(other)) return false;
|
||||
if (other)
|
||||
{
|
||||
if (unit->module->generic_module && other->unit->module->generic_module == unit->module->generic_module && other->unit->module != unit->module)
|
||||
@@ -2653,31 +2564,13 @@ static inline bool unit_add_method(SemaContext *context, Type *parent_type, Decl
|
||||
|
||||
DEBUG_LOG("Method-like '%s.%s' analysed.", parent->name, method->name);
|
||||
|
||||
// Add it to the correct place: type methods, private extensions, local method extensions
|
||||
switch (method->visibility)
|
||||
Methods *table = parent->method_table;
|
||||
if (!table)
|
||||
{
|
||||
case VISIBLE_PUBLIC:
|
||||
vec_add(parent->methods, method);
|
||||
break;
|
||||
case VISIBLE_PRIVATE:
|
||||
if (parent->unit->module == unit->module && parent->visibility >= VISIBLE_PRIVATE)
|
||||
{
|
||||
vec_add(parent->methods, method);
|
||||
break;
|
||||
}
|
||||
vec_add(unit->module->private_method_extensions, method);
|
||||
break;
|
||||
case VISIBLE_LOCAL:
|
||||
if (parent->unit == unit && parent->visibility >= VISIBLE_LOCAL)
|
||||
{
|
||||
vec_add(parent->methods, method);
|
||||
break;
|
||||
}
|
||||
vec_add(unit->local_method_extensions, method);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE
|
||||
table = parent->method_table = CALLOCS(Methods);
|
||||
decltable_init(&table->method_table, 64);
|
||||
}
|
||||
methods_add(table, method);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2990,6 +2883,8 @@ static inline bool sema_analyse_method(SemaContext *context, Decl *decl)
|
||||
// Is it an operator?
|
||||
if (decl->func_decl.operator)
|
||||
{
|
||||
// We must resolve it here to avoid recursion.
|
||||
decl->resolve_status = RESOLVE_DONE;
|
||||
if (!sema_analyse_operator_method(context, par_type, decl)) return false;
|
||||
}
|
||||
|
||||
@@ -4355,6 +4250,7 @@ static bool sema_analyse_macro_method(SemaContext *context, Decl *decl)
|
||||
// Is it an operator?
|
||||
if (decl->func_decl.operator)
|
||||
{
|
||||
decl->resolve_status = RESOLVE_DONE;
|
||||
if (!sema_analyse_operator_method(context, parent_type, decl)) return false;
|
||||
}
|
||||
|
||||
@@ -4398,7 +4294,7 @@ INLINE bool sema_analyse_macro_body(SemaContext *context, Decl **body_parameters
|
||||
case VARDECL_ERASE:
|
||||
UNREACHABLE
|
||||
}
|
||||
if (!sema_check_param_uniqueness_and_type(context, body_parameters, param, i, body_param_count)) return false;
|
||||
if (!sema_check_param_uniqueness_and_type(context, body_parameters, param, i)) return false;
|
||||
param->resolve_status = RESOLVE_DONE;
|
||||
}
|
||||
return true;
|
||||
@@ -5090,14 +4986,13 @@ static bool sema_generate_parameterized_name_to_scratch(SemaContext *context, Mo
|
||||
if (fault)
|
||||
{
|
||||
type_mangle_introspect_name_to_buffer(fault->type->canonical);
|
||||
scratch_buffer_append(mangled ? "_" : ":");
|
||||
scratch_buffer_append(fault->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
scratch_buffer_append("null");
|
||||
}
|
||||
|
||||
scratch_buffer_append(mangled ? "_" : ":");
|
||||
scratch_buffer_append(fault->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -5403,7 +5298,7 @@ bool sema_analyse_method_register(SemaContext *context, Decl *method)
|
||||
RETURN_SEMA_ERROR(parent_type_info, "Methods can not be associated with '%s'", type_to_error_string(parent_type));
|
||||
}
|
||||
|
||||
return unit_add_method(context, parent_type->canonical, method);
|
||||
return type_add_method(context, parent_type->canonical, method);
|
||||
}
|
||||
|
||||
bool sema_analyse_decl(SemaContext *context, Decl *decl)
|
||||
|
||||
@@ -3616,7 +3616,7 @@ static Expr *sema_expr_find_subscript_type_or_overload_for_subscript(SemaContext
|
||||
Decl **overload_ptr)
|
||||
{
|
||||
Decl *overload = NULL;
|
||||
overload = sema_find_untyped_operator(context, current_expr->type, overload_type, NULL);
|
||||
overload = sema_find_untyped_operator(current_expr->type, overload_type, NULL);
|
||||
if (overload)
|
||||
{
|
||||
// Overload for []=
|
||||
@@ -3833,7 +3833,7 @@ static inline bool sema_expr_analyse_subscript_lvalue(SemaContext *context, Expr
|
||||
{
|
||||
if (start_from_end)
|
||||
{
|
||||
Decl *len = sema_find_untyped_operator(context, current_expr->type, OVERLOAD_LEN, NULL);
|
||||
Decl *len = sema_find_untyped_operator(current_expr->type, OVERLOAD_LEN, NULL);
|
||||
if (!len)
|
||||
{
|
||||
if (check_valid) goto VALID_FAIL_POISON;
|
||||
@@ -3948,7 +3948,7 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr,
|
||||
{
|
||||
if (start_from_end)
|
||||
{
|
||||
Decl *len = sema_find_untyped_operator(context, current_expr->type, OVERLOAD_LEN, NULL);
|
||||
Decl *len = sema_find_untyped_operator(current_expr->type, OVERLOAD_LEN, NULL);
|
||||
if (!len)
|
||||
{
|
||||
if (check_valid) goto VALID_FAIL_POISON;
|
||||
@@ -4621,35 +4621,6 @@ 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)
|
||||
{
|
||||
ASSERT(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_UNRESOLVED_IDENTIFIER);
|
||||
@@ -4668,7 +4639,7 @@ static inline bool sema_expr_analyse_type_access(SemaContext *context, Expr *exp
|
||||
|
||||
if (!type_may_have_sub_elements(canonical))
|
||||
{
|
||||
Decl *member = sema_check_for_type_method(context, expr, parent_type->canonical, name, missing_ref);
|
||||
Decl *member = sema_resolve_type_method(parent_type->canonical, name);
|
||||
if (!decl_ok(member)) return false;
|
||||
if (!member)
|
||||
{
|
||||
@@ -4706,11 +4677,11 @@ static inline bool sema_expr_analyse_type_access(SemaContext *context, Expr *exp
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
Decl *member = sema_decl_stack_find_decl_member(context, decl, name, METHODS_AND_FIELDS);
|
||||
Decl *member = sema_decl_stack_find_decl_member(context, decl, name, FIELDS_ONLY);
|
||||
if (!decl_ok(member)) return false;
|
||||
if (!member)
|
||||
{
|
||||
member = sema_check_for_type_method(context, expr, decl->type, name, missing_ref);
|
||||
member = sema_resolve_type_method(decl->type, name);
|
||||
if (!decl_ok(member)) return false;
|
||||
}
|
||||
if (!member)
|
||||
@@ -5192,12 +5163,13 @@ CONTINUE:
|
||||
sema_append_interface_methods(decl, &method_exprs, expr->span);
|
||||
}
|
||||
// Look through natively defined methods.
|
||||
append_to_method_list(decl->methods, &method_exprs, expr->span);
|
||||
Methods *methods = decl->method_table;
|
||||
if (methods) append_to_method_list(methods->methods, &method_exprs, expr->span);
|
||||
}
|
||||
else
|
||||
{
|
||||
append_extension_methods(type, compiler.context.method_extension_list, &method_exprs, expr->span);
|
||||
}
|
||||
append_extension_methods(type, context->unit->local_method_extensions, &method_exprs, expr->span);
|
||||
append_extension_methods(type, context->unit->module->private_method_extensions, &method_exprs, expr->span);
|
||||
append_extension_methods(type, compiler.context.method_extensions, &method_exprs, expr->span);
|
||||
|
||||
type = type_find_parent_type(type);
|
||||
if (type) goto CONTINUE;
|
||||
expr_rewrite_const_untyped_list(expr, method_exprs);
|
||||
@@ -6128,20 +6100,7 @@ CHECK_DEEPER:
|
||||
// 9. At this point we may only have distinct, struct, union, error, enum, interface
|
||||
if (!type_may_have_sub_elements(type))
|
||||
{
|
||||
Decl *ambiguous = NULL;
|
||||
Decl *private = NULL;
|
||||
Decl *method = sema_resolve_type_method(context->unit, type, kw, &ambiguous, &private);
|
||||
if (private)
|
||||
{
|
||||
if (missing_ref) goto MISSING_REF;
|
||||
RETURN_SEMA_ERROR(expr, "The method '%s' has private visibility.", kw);
|
||||
}
|
||||
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'",
|
||||
kw, method->unit->module->name->module, ambiguous->unit->module->name->module);
|
||||
}
|
||||
Decl *method = sema_resolve_type_method(type, kw);
|
||||
if (!method)
|
||||
{
|
||||
if (missing_ref) goto MISSING_REF;
|
||||
@@ -6159,7 +6118,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, METHODS_AND_FIELDS);
|
||||
Decl *member = sema_decl_stack_find_decl_member(context, decl, kw, METHODS_INTERFACES_AND_FIELDS);
|
||||
if (!decl_ok(member)) return false;
|
||||
|
||||
if (member && decl->decl_kind == DECL_ENUM && member->decl_kind == DECL_VAR && sema_cast_const(parent))
|
||||
@@ -6174,24 +6133,22 @@ CHECK_DEEPER:
|
||||
return true;
|
||||
}
|
||||
Decl *private = NULL;
|
||||
if (!member)
|
||||
if (!member && decl->decl_kind == DECL_INTERFACE)
|
||||
{
|
||||
Decl *ambiguous = NULL;
|
||||
member = sema_resolve_method(context->unit, decl, kw, &ambiguous, &private);
|
||||
// Look at interface parents
|
||||
if (!member && decl->decl_kind == DECL_INTERFACE)
|
||||
Decl *inf;
|
||||
FOREACH(TypeInfo *, parent_interface, decl->interfaces)
|
||||
{
|
||||
FOREACH(TypeInfo *, parent_interface, decl->interfaces)
|
||||
if (!sema_resolve_type_info(context, parent_interface, RESOLVE_TYPE_NO_CHECK_DISTINCT)) return false;
|
||||
Decl *parent_decl = parent_interface->type->decl;
|
||||
Decl *value = sema_resolve_method(parent_decl, kw);
|
||||
if (value && member)
|
||||
{
|
||||
member = sema_resolve_method(context->unit, parent_interface->type->decl, kw, &ambiguous, &private);
|
||||
if (member) break;
|
||||
RETURN_SEMA_ERROR(expr, "Ambiguous method '%s' on '%s', it was implemented on both '%s' and '%s'.", kw,
|
||||
type_to_error_string(parent->type),
|
||||
inf->name, parent_decl->name);
|
||||
}
|
||||
}
|
||||
if (ambiguous)
|
||||
{
|
||||
ASSERT(member);
|
||||
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'",
|
||||
kw, member->unit->module->name->module, ambiguous->unit->module->name->module);
|
||||
member = value;
|
||||
inf = parent_decl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6875,7 +6832,7 @@ INLINE bool sema_rewrite_op_assign(SemaContext *context, Expr *expr, Expr *left,
|
||||
{
|
||||
Expr *parent = exprptr(left->subscript_assign_expr.expr);
|
||||
Type *parent_type = type_no_optional(parent->type)->canonical;
|
||||
Decl *operator = sema_find_untyped_operator(context, parent_type, OVERLOAD_ELEMENT_REF, NULL);
|
||||
Decl *operator = sema_find_untyped_operator(parent_type, OVERLOAD_ELEMENT_REF, NULL);
|
||||
Expr *index = exprptr(left->subscript_assign_expr.index);
|
||||
if (operator)
|
||||
{
|
||||
@@ -6885,7 +6842,7 @@ INLINE bool sema_rewrite_op_assign(SemaContext *context, Expr *expr, Expr *left,
|
||||
goto AFTER_ADDR;
|
||||
}
|
||||
// If we only have []=, then we need []
|
||||
operator = sema_find_untyped_operator(context, parent_type, OVERLOAD_ELEMENT_AT, NULL);
|
||||
operator = sema_find_untyped_operator(parent_type, OVERLOAD_ELEMENT_AT, NULL);
|
||||
if (!operator)
|
||||
{
|
||||
RETURN_SEMA_ERROR(left, "There is no overload for [] for %s.", type_quoted_error_string(type_no_optional(left->type)));
|
||||
@@ -8528,7 +8485,7 @@ static inline bool sema_expr_analyse_neg_plus(SemaContext *context, Expr *expr)
|
||||
// Check for overload
|
||||
if (type_is_user_defined(canonical))
|
||||
{
|
||||
Decl *overload = sema_find_untyped_operator(context, canonical, OVERLOAD_UNARY_MINUS, NULL);
|
||||
Decl *overload = sema_find_untyped_operator(canonical, OVERLOAD_UNARY_MINUS, NULL);
|
||||
if (overload)
|
||||
{
|
||||
// Plus just returns inner
|
||||
@@ -8604,7 +8561,7 @@ static inline bool sema_expr_analyse_bit_not(SemaContext *context, Expr *expr, b
|
||||
|
||||
if (type_is_user_defined(canonical) && canonical->type_kind != TYPE_BITSTRUCT)
|
||||
{
|
||||
Decl *overload = sema_find_untyped_operator(context, canonical, OVERLOAD_NEGATE, NULL);
|
||||
Decl *overload = sema_find_untyped_operator(canonical, OVERLOAD_NEGATE, NULL);
|
||||
if (overload) return sema_insert_method_call(context, expr, overload, inner, NULL, false);
|
||||
}
|
||||
|
||||
@@ -8780,7 +8737,7 @@ static bool sema_analyse_assign_mutate_overloaded_subscript(SemaContext *context
|
||||
{
|
||||
Expr *increased = exprptr(subscript_expr->subscript_assign_expr.expr);
|
||||
Type *type_check = increased->type->canonical;
|
||||
Decl *operator = sema_find_untyped_operator(context, type_check, OVERLOAD_ELEMENT_REF, NULL);
|
||||
Decl *operator = sema_find_untyped_operator(type_check, OVERLOAD_ELEMENT_REF, NULL);
|
||||
Expr **args = NULL;
|
||||
// The simple case: we have &[] so just replace it by that.
|
||||
if (operator)
|
||||
@@ -8792,7 +8749,7 @@ static bool sema_analyse_assign_mutate_overloaded_subscript(SemaContext *context
|
||||
return true;
|
||||
}
|
||||
// We need []= and [] now.
|
||||
operator = sema_find_untyped_operator(context, type_check, OVERLOAD_ELEMENT_AT, NULL);
|
||||
operator = sema_find_untyped_operator(type_check, OVERLOAD_ELEMENT_AT, NULL);
|
||||
if (!operator)
|
||||
{
|
||||
RETURN_SEMA_ERROR(main, "There is no overload for [] for %s.", type_quoted_error_string(increased->type));
|
||||
@@ -9615,15 +9572,6 @@ static inline bool sema_expr_analyse_decl_element(SemaContext *context, Designat
|
||||
if (!decl_ok(member)) return false;
|
||||
if (!member)
|
||||
{
|
||||
Decl *ambiguous = NULL;
|
||||
Decl *private = NULL;
|
||||
member = sema_resolve_method(context->unit, actual_type->decl, kw, &ambiguous, &private);
|
||||
if (ambiguous)
|
||||
{
|
||||
sema_error_at(context, loc, "'%s' is an ambiguous name and so cannot be resolved, it may refer to method defined in '%s' or one in '%s'",
|
||||
kw, member->unit->module->name->module, ambiguous->unit->module->name->module);
|
||||
return false;
|
||||
}
|
||||
if (is_missing)
|
||||
{
|
||||
*is_missing = true;
|
||||
|
||||
@@ -100,9 +100,10 @@ bool sema_analyse_ct_expr(SemaContext *context, Expr *expr);
|
||||
Decl *sema_find_typed_operator(SemaContext *context, OperatorOverload operator_overload, SourceSpan span, Expr *lhs, Expr *rhs, bool *reverse);
|
||||
OverloadMatch sema_find_typed_operator_type(SemaContext *context, OperatorOverload operator_overload, OverloadType overloat_type, Type *lhs_type, Type *rhs_type, Expr *rhs, Decl **candidate_ref, OverloadMatch last_match, Decl **ambiguous_ref);
|
||||
BoolErr sema_type_has_equality_overload(SemaContext *context, Type *type);
|
||||
Decl *sema_find_untyped_operator(SemaContext *context, Type *type, OperatorOverload operator_overload, Decl *skipped);
|
||||
Decl *sema_find_untyped_operator(Type *type, OperatorOverload operator_overload, Decl *skipped);
|
||||
bool sema_insert_method_call(SemaContext *context, Expr *method_call, Decl *method_decl, Expr *parent, Expr **arguments, bool reverse_overload);
|
||||
bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr);
|
||||
void sema_add_methods_to_decl_stack(SemaContext *context, Decl *decl);
|
||||
|
||||
bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *struct_var, Decl *decl, bool call_var_optional, bool *no_match_ref);
|
||||
Expr *sema_expr_analyse_ct_arg_index(SemaContext *context, Expr *index_expr, unsigned *index_ref);
|
||||
|
||||
@@ -523,7 +523,7 @@ void sema_trace_liveness(void)
|
||||
}
|
||||
bool keep_tests = compiler.build.testing;
|
||||
bool keep_benchmarks = compiler.build.benchmarking;
|
||||
FOREACH(Decl *, function, compiler.context.method_extensions)
|
||||
FOREACH(Decl *, function, compiler.context.method_extension_list)
|
||||
{
|
||||
if (function->func_decl.attr_dynamic) function->no_strip = true;
|
||||
if (function->is_export || function->no_strip) sema_trace_decl_liveness(function);
|
||||
@@ -548,10 +548,6 @@ void sema_trace_liveness(void)
|
||||
{
|
||||
if (var->is_export || var->no_strip) sema_trace_decl_liveness(var);
|
||||
}
|
||||
FOREACH(Decl *, method, unit->local_method_extensions)
|
||||
{
|
||||
if (method->is_export || method->no_strip) sema_trace_decl_liveness(method);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -566,7 +562,9 @@ INLINE void sema_trace_enum_associated(Decl *decl)
|
||||
}
|
||||
INLINE void sema_trace_decl_dynamic_methods(Decl *decl)
|
||||
{
|
||||
Decl **methods = decl->methods;
|
||||
Methods *table = decl->method_table;
|
||||
if (!table) return;
|
||||
Decl **methods = table->methods;
|
||||
unsigned method_count = vec_size(methods);
|
||||
if (!method_count) return;
|
||||
for (unsigned i = 0; i < method_count; i++)
|
||||
|
||||
@@ -82,13 +82,7 @@ static bool add_interface_to_decl_stack(SemaContext *context, Decl *decl)
|
||||
|
||||
static bool add_members_to_decl_stack(SemaContext *context, Decl *decl, FindMember find)
|
||||
{
|
||||
if (find != FIELDS_ONLY)
|
||||
{
|
||||
FOREACH(Decl *, func, decl->methods)
|
||||
{
|
||||
sema_decl_stack_push(func);
|
||||
}
|
||||
}
|
||||
if (find != FIELDS_ONLY) sema_add_methods_to_decl_stack(context, decl);
|
||||
while (decl->decl_kind == DECL_DISTINCT)
|
||||
{
|
||||
Type *type = decl->distinct->type->canonical;
|
||||
@@ -124,7 +118,12 @@ Decl *sema_decl_stack_find_decl_member(SemaContext *context, Decl *decl_owner, c
|
||||
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;
|
||||
if (member || find == FIELDS_ONLY) return member;
|
||||
if (find == METHODS_AND_FIELDS)
|
||||
{
|
||||
return sema_resolve_method_only(decl_owner, symbol);
|
||||
}
|
||||
return sema_resolve_method(decl_owner, symbol);
|
||||
}
|
||||
|
||||
static inline Decl *sema_find_decl_in_module(Module *module, Path *path, const char *symbol, Module **path_found_ref)
|
||||
@@ -839,56 +838,36 @@ Decl *sema_find_extension_method_in_list(Decl **extensions, Type *type, const ch
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Decl *sema_resolve_method_in_module(Module *module, Type *actual_type, const char *method_name,
|
||||
Decl **private_found, Decl **ambiguous, MethodSearchType search_type)
|
||||
Decl *sema_resolve_method_only(Decl *type, const char *method_name)
|
||||
{
|
||||
if (module->is_generic) return NULL;
|
||||
Decl *found = sema_find_extension_method_in_list(module->private_method_extensions, actual_type, method_name);
|
||||
// The found one might not be visible
|
||||
if (found && search_type < METHOD_SEARCH_CURRENT && found->visibility == VISIBLE_PRIVATE)
|
||||
Methods *methods = type->method_table;
|
||||
Decl *found = NULL;
|
||||
if (methods)
|
||||
{
|
||||
*private_found = found;
|
||||
found = NULL;
|
||||
found = declptrzero(decltable_get(&methods->method_table, method_name));
|
||||
}
|
||||
assert(!found || found->visibility != VISIBLE_LOCAL);
|
||||
if (found && search_type == METHOD_SEARCH_CURRENT) return found;
|
||||
// We are now searching submodules, so hide the private ones.
|
||||
if (search_type == METHOD_SEARCH_CURRENT) search_type = METHOD_SEARCH_SUBMODULE_CURRENT;
|
||||
FOREACH(Module *, mod, module->sub_modules)
|
||||
{
|
||||
Decl *new_found = sema_resolve_method_in_module(mod, actual_type, method_name, private_found, ambiguous,
|
||||
search_type);
|
||||
if (!new_found) continue;
|
||||
if (found)
|
||||
{
|
||||
*ambiguous = new_found;
|
||||
return found;
|
||||
}
|
||||
found = new_found;
|
||||
}
|
||||
// We might have it ambiguous due to searching sub modules.
|
||||
return found;
|
||||
}
|
||||
|
||||
Decl *sema_resolve_method(CompilationUnit *unit, Decl *type, const char *method_name, Decl **ambiguous_ref, Decl **private_ref)
|
||||
Decl *sema_resolve_method(Decl *type, const char *method_name)
|
||||
{
|
||||
// Interface, prefer interface methods.
|
||||
if (type->decl_kind == DECL_INTERFACE)
|
||||
bool is_interface = type->decl_kind == DECL_INTERFACE;
|
||||
if (is_interface)
|
||||
{
|
||||
FOREACH(Decl *, method, type->interface_methods)
|
||||
{
|
||||
if (method_name == method->name) return method;
|
||||
}
|
||||
}
|
||||
// Look through natively defined methods.
|
||||
FOREACH(Decl *, method, type->methods)
|
||||
{
|
||||
if (method_name == method->name) return method;
|
||||
}
|
||||
|
||||
return sema_resolve_type_method(unit, type->type, method_name, ambiguous_ref, private_ref);
|
||||
Methods *methods = type->method_table;
|
||||
Decl *found = NULL;
|
||||
if (methods)
|
||||
{
|
||||
found = declptrzero(decltable_get(&methods->method_table, method_name));
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
bool sema_check_type_variable_array(SemaContext *context, TypeInfo *type_info)
|
||||
@@ -975,75 +954,41 @@ bool sema_resolve_type_decl(SemaContext *context, Type *type)
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
Decl *sema_resolve_type_method(CompilationUnit *unit, Type *type, const char *method_name, Decl **ambiguous_ref, Decl **private_ref)
|
||||
Decl *sema_resolve_type_method(CanonicalType *type, const char *method_name)
|
||||
{
|
||||
ASSERT(type == type->canonical);
|
||||
Decl *private = NULL;
|
||||
Decl *ambiguous = NULL;
|
||||
Decl *found = sema_find_extension_method_in_list(unit->local_method_extensions, type, method_name);
|
||||
if (!found) found = sema_resolve_method_in_module(unit->module, type, method_name, &private, &ambiguous, METHOD_SEARCH_CURRENT);
|
||||
if (ambiguous)
|
||||
RETRY:
|
||||
if (!type_is_user_defined(type))
|
||||
{
|
||||
*ambiguous_ref = ambiguous;
|
||||
ASSERT(found);
|
||||
return found;
|
||||
}
|
||||
|
||||
// 2. Lookup in imports
|
||||
FOREACH(Decl *, import, unit->imports)
|
||||
{
|
||||
if (import->import.module->is_generic) continue;
|
||||
|
||||
Decl *new_found = sema_resolve_method_in_module(import->import.module, type, method_name,
|
||||
&private, &ambiguous,
|
||||
import->import.import_private_as_public
|
||||
? METHOD_SEARCH_PRIVATE_IMPORTED
|
||||
: METHOD_SEARCH_IMPORTED);
|
||||
if (!new_found || found == new_found) continue;
|
||||
if (found)
|
||||
Decl *found = declptrzero(methodtable_get(&compiler.context.method_extensions, type, method_name));
|
||||
if (found) return found;
|
||||
switch (type->type_kind)
|
||||
{
|
||||
*ambiguous_ref = new_found;
|
||||
return found;
|
||||
}
|
||||
found = new_found;
|
||||
if (ambiguous)
|
||||
{
|
||||
*ambiguous_ref = ambiguous;
|
||||
return found;
|
||||
case TYPE_ARRAY:
|
||||
return declptrzero(methodtable_get(&compiler.context.method_extensions, type_get_inferred_array(type->array.base), method_name));
|
||||
case TYPE_VECTOR:
|
||||
return declptrzero(methodtable_get(&compiler.context.method_extensions, type_get_inferred_vector(type->array.base), method_name));
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
Decl *type_decl = type->decl;
|
||||
Methods *methods = type_decl->method_table;
|
||||
Decl *found = methods ? declptrzero(decltable_get(&methods->method_table, method_name)) : NULL;
|
||||
if (found || !type_decl->is_substruct) return found;
|
||||
switch (type->type_kind)
|
||||
{
|
||||
found = sema_resolve_method_in_module(compiler.context.core_module, type, method_name,
|
||||
&private, &ambiguous, METHOD_SEARCH_IMPORTED);
|
||||
case TYPE_STRUCT:
|
||||
type = type_decl->strukt.members[0]->type->canonical;
|
||||
goto RETRY;
|
||||
case TYPE_DISTINCT:
|
||||
type = type_decl->distinct->type->canonical;
|
||||
goto RETRY;
|
||||
case TYPE_ENUM:
|
||||
type = type_decl->enums.type_info->type->canonical;
|
||||
goto RETRY;
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
if (found && ambiguous)
|
||||
{
|
||||
*ambiguous_ref = ambiguous;
|
||||
return found;
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
found = sema_find_extension_method_in_list(compiler.context.method_extensions, type, method_name);
|
||||
private = NULL;
|
||||
}
|
||||
if (private) *private_ref = private;
|
||||
if (!found)
|
||||
{
|
||||
if (type->type_kind == TYPE_ARRAY)
|
||||
{
|
||||
Type *inferred_array = type_get_inferred_array(type->array.base);
|
||||
found = sema_resolve_type_method(unit, inferred_array, method_name, ambiguous_ref, private_ref);
|
||||
if (found) *private_ref = NULL;
|
||||
}
|
||||
else if (type->type_kind == TYPE_VECTOR)
|
||||
{
|
||||
Type *inferred_vector = type_get_inferred_vector(type->array.base);
|
||||
found = sema_resolve_type_method(unit, inferred_vector, method_name, ambiguous_ref, private_ref);
|
||||
if (found) *private_ref = NULL;
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
bool unit_resolve_parameterized_symbol(SemaContext *context, NameResolve *name_resolve)
|
||||
|
||||
@@ -749,7 +749,7 @@ static bool sema_check_interface(SemaContext *context, Decl *decl, TypeInfo *int
|
||||
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);
|
||||
sema_add_methods_to_decl_stack(context, decl);
|
||||
FOREACH(TypeInfo *, interface_type, decl->interfaces)
|
||||
{
|
||||
if (!sema_check_interface(context, decl, interface_type, interface_type))
|
||||
|
||||
@@ -1574,11 +1574,11 @@ static inline bool sema_analyse_foreach_stmt(SemaContext *context, Ast *statemen
|
||||
if (!value_type || canonical->type_kind == TYPE_DISTINCT)
|
||||
{
|
||||
// Get the overload for .len
|
||||
len = sema_find_untyped_operator(context, enumerator->type, OVERLOAD_LEN, NULL);
|
||||
len = sema_find_untyped_operator(enumerator->type, OVERLOAD_LEN, NULL);
|
||||
// For foo[]
|
||||
Decl *by_val = sema_find_untyped_operator(context, enumerator->type, OVERLOAD_ELEMENT_AT, NULL);
|
||||
Decl *by_val = sema_find_untyped_operator(enumerator->type, OVERLOAD_ELEMENT_AT, NULL);
|
||||
// For &foo[]
|
||||
Decl *by_ref = sema_find_untyped_operator(context, enumerator->type, OVERLOAD_ELEMENT_REF, NULL);
|
||||
Decl *by_ref = sema_find_untyped_operator(enumerator->type, OVERLOAD_ELEMENT_REF, NULL);
|
||||
|
||||
// If we don't have .len, or there is neither by val nor by ref
|
||||
if (!len || (!by_val && !by_ref))
|
||||
|
||||
@@ -118,6 +118,27 @@ void context_pop_defers(SemaContext *context, AstId *next)
|
||||
context->active_scope.defer_last = defer_start;
|
||||
}
|
||||
|
||||
void sema_add_methods_to_decl_stack(SemaContext *context, Decl *decl)
|
||||
{
|
||||
if (!decl->method_table) return;
|
||||
FOREACH(Decl *, func, decl->method_table->methods)
|
||||
{
|
||||
switch (func->visibility)
|
||||
{
|
||||
case VISIBLE_LOCAL:
|
||||
if (context->unit != func->unit) continue;
|
||||
break;
|
||||
case VISIBLE_PRIVATE:
|
||||
if (context->unit->module != func->unit->module) continue;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
sema_decl_stack_push(func);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void context_pop_defers_and_replace_ast(SemaContext *context, Ast *ast)
|
||||
{
|
||||
|
||||
@@ -1058,23 +1058,6 @@ bool type_is_structurally_equivalent(Type *type1, Type *type2)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool type_is_user_defined(Type *type)
|
||||
{
|
||||
switch (type->type_kind)
|
||||
{
|
||||
case TYPE_ENUM:
|
||||
case TYPE_FUNC_RAW:
|
||||
case TYPE_STRUCT:
|
||||
case TYPE_UNION:
|
||||
case TYPE_DISTINCT:
|
||||
case TYPE_BITSTRUCT:
|
||||
case TYPE_TYPEDEF:
|
||||
case TYPE_INTERFACE:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Type *type_get_indexed_type(Type *type)
|
||||
{
|
||||
|
||||
@@ -27,11 +27,11 @@ Bar y = { 1 };
|
||||
|
||||
fn int test()
|
||||
{
|
||||
x.get1(); // #error: method
|
||||
x.get1();
|
||||
x.get2();
|
||||
x.get3(); // #error: method
|
||||
y.get1(); // #error: method
|
||||
x.get3();
|
||||
y.get1();
|
||||
y.get2();
|
||||
y.get3(); // #error: method
|
||||
y.get3();
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -29,9 +29,9 @@ fn int test()
|
||||
{
|
||||
x.get1();
|
||||
x.get2();
|
||||
x.get3(); // #error: method
|
||||
x.get3();
|
||||
y.get1();
|
||||
y.get2();
|
||||
y.get3(); // #error: method
|
||||
y.get3();
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
struct Foo { int a; }
|
||||
struct Foo2 { int a; }
|
||||
struct Foo3 { int a; }
|
||||
struct Bar { int a; }
|
||||
|
||||
fn int Foo.x(&self, int x) @operator([]) => 1;
|
||||
fn int Foo.y(&self, int x) @operator(&[]) => 1; // #error: The return type must be a pointer
|
||||
fn int Foo2.y(&self, int x) @operator([]) => null;
|
||||
fn int** Foo2.y2(&self, int x) @operator(&[]) => null; // #error: There is a mismatch of the 'value' type
|
||||
fn void Foo.z(&self, uint x, int a) @operator([]=) {} // #error: There is a mismatch of the 'index'
|
||||
|
||||
fn int Foo3.x(&self, int x) @operator([]) => 1;
|
||||
fn void Foo3.z(&self, uint x, int a) @operator([]=) {} // #error: There is a mismatch of the 'index'
|
||||
|
||||
fn double Bar.x(&self, int x) @operator([]) => 0.1;
|
||||
fn void Bar.y(&self, int x, float y) @operator([]=) {} // #error: There is a mismatch of the 'value'
|
||||
|
||||
Reference in New Issue
Block a user