New method resolution.

This commit is contained in:
Christoffer Lerno
2025-08-15 19:00:44 +02:00
committed by Christoffer Lerno
parent 34b0b6f8f9
commit 4b95d6be4c
19 changed files with 440 additions and 482 deletions

View File

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

View File

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

View File

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

View File

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

View File

@@ -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(&copy->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:

View File

@@ -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;
}
}

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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;
}

View File

@@ -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;
}

View File

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