mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
- Support untyped second argument for operator overloading.
- Distinct versions of builtin types ignore @operator overloads #2204. - @operator macro using untyped parameter causes compiler segfault #2200. - Add comparison with `==` for ZString types.
This commit is contained in:
@@ -19,7 +19,7 @@ static inline bool unit_add_base_extension_method(SemaContext *context, Compilat
|
||||
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 Decl *operator_in_module_typed(SemaContext *c, Module *module, OperatorOverload operator_overload,
|
||||
static inline bool 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, 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 sema_analyse_operator_element_at(SemaContext *context, Decl *method);
|
||||
@@ -48,7 +48,7 @@ static bool sema_analyse_attributes(SemaContext *context, Decl *decl, Attr **att
|
||||
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 Decl *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, Decl **ambiguous_ref);
|
||||
static bool 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, 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);
|
||||
@@ -1709,16 +1709,15 @@ INLINE bool decl_matches_overload(Decl *method, Type *type, OperatorOverload ove
|
||||
return method->func_decl.operator == overload && typeget(method->func_decl.type_parent)->canonical == type;
|
||||
}
|
||||
|
||||
static inline Decl *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, Decl **ambiguous_ref)
|
||||
static inline bool 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, Decl **ambiguous_ref)
|
||||
{
|
||||
if (module->is_generic) return NULL;
|
||||
Decl *found = sema_find_typed_operator_in_list(c, module->private_method_extensions, operator_overload, OVERLOAD_TYPE_SYMMETRIC, method_type, binary_arg, binary_type, candidate_ref, ambiguous_ref);
|
||||
if (found) return found;
|
||||
if (!sema_find_typed_operator_in_list(c, module->private_method_extensions, operator_overload, OVERLOAD_TYPE_SYMMETRIC, method_type, binary_arg, binary_type, candidate_ref, ambiguous_ref)) return false;
|
||||
FOREACH(Module *, sub_module, module->sub_modules)
|
||||
{
|
||||
return operator_in_module_typed(c, sub_module, operator_overload, overload_type, method_type, binary_arg, binary_type, candidate_ref, ambiguous_ref);
|
||||
if (!operator_in_module_typed(c, sub_module, operator_overload, overload_type, method_type, binary_arg, binary_type, candidate_ref, ambiguous_ref)) return false;
|
||||
}
|
||||
return NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline Decl *operator_in_module_exact_typed(Module *module, OperatorOverload operator_overload, OverloadType overload_type, Type *method_type, Type *param_type, Decl *skipped)
|
||||
@@ -1779,6 +1778,7 @@ Decl *sema_find_untyped_operator(SemaContext *context, Type *type, OperatorOverl
|
||||
|
||||
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;
|
||||
@@ -1786,39 +1786,46 @@ static Decl *sema_find_exact_typed_operator_in_list(Decl **methods, OperatorOver
|
||||
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;
|
||||
Type *first_arg = func->func_decl.signature.params[1]->type->canonical;
|
||||
if (first_arg != binary_type) 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 NULL;
|
||||
return wildcard;
|
||||
}
|
||||
|
||||
static Decl *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, Decl **ambiguous_ref)
|
||||
static bool 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, Decl **ambiguous_ref)
|
||||
{
|
||||
|
||||
Decl *candidate = *candidate_ref;
|
||||
FOREACH(Decl *, func, methods)
|
||||
{
|
||||
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;
|
||||
Type *first_arg = func->func_decl.signature.params[1]->type->canonical;
|
||||
if (first_arg != binary_type)
|
||||
if (!func->func_decl.is_wildcard_overload)
|
||||
{
|
||||
if (!binary_arg) continue;
|
||||
if (may_cast(context, binary_arg, first_arg, false, true))
|
||||
Type *first_arg = func->func_decl.signature.params[1]->type->canonical;
|
||||
if (first_arg != binary_type)
|
||||
{
|
||||
if (*candidate_ref)
|
||||
{
|
||||
*ambiguous_ref = func;
|
||||
continue;
|
||||
}
|
||||
*candidate_ref = func;
|
||||
if (!binary_arg) continue;
|
||||
if (!may_cast(context, binary_arg, first_arg, false, true)) continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
unit_register_external_symbol(context, func);
|
||||
return func;
|
||||
if (candidate && !candidate->func_decl.is_wildcard_overload)
|
||||
{
|
||||
*ambiguous_ref = func;
|
||||
*candidate_ref = candidate;
|
||||
return false;
|
||||
}
|
||||
candidate = func;
|
||||
}
|
||||
return NULL;
|
||||
*candidate_ref = candidate;
|
||||
return true;
|
||||
}
|
||||
|
||||
static Decl *sema_find_exact_typed_operator(SemaContext *context, Type *type, OperatorOverload operator_overload, OverloadType overload_type, Type *param_type, Decl *skipped)
|
||||
@@ -1848,67 +1855,69 @@ static Decl *sema_find_exact_typed_operator(SemaContext *context, Type *type, Op
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static Decl *sema_find_typed_operator_type(SemaContext *context, OperatorOverload operator_overload, OverloadType overloat_type, Type *lhs_type, Type *rhs_type, Expr *rhs, Decl **candidate_ref, Decl **ambiguous_ref)
|
||||
static bool sema_find_typed_operator_type(SemaContext *context, OperatorOverload operator_overload, OverloadType overloat_type, Type *lhs_type, Type *rhs_type, Expr *rhs, Decl **candidate_ref, Decl **ambiguous_ref)
|
||||
{
|
||||
// Can we find the overload directly on the method?
|
||||
Decl *func = sema_find_typed_operator_in_list(context, lhs_type->decl->methods, operator_overload, overloat_type, lhs_type,
|
||||
rhs, rhs_type, candidate_ref, ambiguous_ref);
|
||||
if (func) return func;
|
||||
if (!sema_find_typed_operator_in_list(context, lhs_type->decl->methods,
|
||||
operator_overload, overloat_type, lhs_type,
|
||||
rhs, rhs_type, candidate_ref, ambiguous_ref)) return false;
|
||||
// Can we find it as a local extension?
|
||||
Decl *extension = sema_find_typed_operator_in_list(context, context->unit->local_method_extensions,
|
||||
operator_overload, overloat_type, lhs_type, rhs, rhs_type, candidate_ref, ambiguous_ref);
|
||||
if (!sema_find_typed_operator_in_list(context, context->unit->local_method_extensions,
|
||||
operator_overload, overloat_type, lhs_type, rhs, rhs_type, candidate_ref, ambiguous_ref)) return false;
|
||||
|
||||
// Can we find it in the current module?
|
||||
if (extension) return extension;
|
||||
extension = operator_in_module_typed(context, context->compilation_unit->module, operator_overload, overloat_type,
|
||||
lhs_type, rhs, rhs_type, candidate_ref, ambiguous_ref);
|
||||
if (extension) return extension;
|
||||
// TODO incorrect, doesn't recurse
|
||||
// Look through our public imports
|
||||
if (!operator_in_module_typed(context, context->compilation_unit->module, operator_overload, overloat_type,
|
||||
lhs_type, rhs, rhs_type, candidate_ref, ambiguous_ref)) return false;
|
||||
FOREACH(Decl *, import, context->unit->public_imports)
|
||||
{
|
||||
extension = operator_in_module_typed(context, import->import.module, operator_overload, overloat_type,
|
||||
lhs_type, rhs, rhs_type, candidate_ref, ambiguous_ref);
|
||||
if (extension) return extension;
|
||||
if (!operator_in_module_typed(context, import->import.module, operator_overload, overloat_type,
|
||||
lhs_type, rhs, rhs_type, candidate_ref, ambiguous_ref)) return false;
|
||||
}
|
||||
return NULL;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
Decl *sema_find_typed_operator(SemaContext *context, OperatorOverload operator_overload, Expr *lhs, Expr *rhs, Decl **ambiguous_ref, bool *reverse)
|
||||
{
|
||||
assert(operator_overload >= OVERLOAD_TYPED_START);
|
||||
assert(lhs && rhs && ambiguous_ref);
|
||||
Type *left_type = type_no_optional(lhs->type)->canonical;
|
||||
Type *right_type = type_no_optional(rhs->type)->canonical;
|
||||
|
||||
Decl *candidate = NULL;
|
||||
Decl *ambiguous = NULL;
|
||||
Decl *left_candidate = NULL;
|
||||
*reverse = false;
|
||||
if (type_is_user_defined(left_type))
|
||||
{
|
||||
Decl *found = sema_find_typed_operator_type(context, operator_overload, OVERLOAD_TYPE_LEFT, left_type, right_type, rhs, &candidate, &ambiguous);
|
||||
if (found) return found;
|
||||
if (!sema_find_typed_operator_type(context, operator_overload, OVERLOAD_TYPE_LEFT, left_type, right_type, rhs, &candidate, &ambiguous)) return NULL;
|
||||
left_candidate = candidate;
|
||||
}
|
||||
candidate = NULL;
|
||||
if (type_is_user_defined(right_type))
|
||||
{
|
||||
Decl *found = sema_find_typed_operator_type(context, operator_overload, OVERLOAD_TYPE_RIGHT, right_type, left_type, lhs, &candidate, &ambiguous);
|
||||
if (found)
|
||||
{
|
||||
*reverse = true;
|
||||
return found;
|
||||
}
|
||||
if (!sema_find_typed_operator_type(context, operator_overload, OVERLOAD_TYPE_RIGHT, right_type, left_type, lhs, &candidate, &ambiguous)) return NULL;
|
||||
}
|
||||
if (ambiguous)
|
||||
|
||||
// If one or the other is missing, pick the right one.
|
||||
if (!left_candidate)
|
||||
{
|
||||
*ambiguous_ref = ambiguous;
|
||||
return NULL;
|
||||
}
|
||||
if (candidate)
|
||||
{
|
||||
*reverse = candidate != left_candidate;
|
||||
*reverse = true;
|
||||
return candidate;
|
||||
}
|
||||
if (!candidate) return left_candidate;
|
||||
|
||||
// Both exist, prefer non-wildcard
|
||||
if (left_candidate->func_decl.is_wildcard_overload && !candidate->func_decl.is_wildcard_overload)
|
||||
{
|
||||
*reverse = true;
|
||||
return candidate;
|
||||
}
|
||||
if (candidate->func_decl.is_wildcard_overload && !left_candidate->func_decl.is_wildcard_overload)
|
||||
{
|
||||
return left_candidate;
|
||||
}
|
||||
*ambiguous_ref = candidate;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -2193,7 +2202,22 @@ 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 = vec_size(method->func_decl.signature.params) > 1 ? method->func_decl.signature.params[1]->type->canonical : NULL;
|
||||
|
||||
Type *second_param = NULL;
|
||||
if (vec_size(method->func_decl.signature.params) > 1)
|
||||
{
|
||||
second_param = method->func_decl.signature.params[1]->type;
|
||||
if (!second_param)
|
||||
{
|
||||
if (method->func_decl.overload_type & OVERLOAD_TYPE_RIGHT)
|
||||
{
|
||||
RETURN_SEMA_ERROR(method, "Only regular overloads can have untyped right hand parameters");
|
||||
}
|
||||
method->func_decl.is_wildcard_overload = true;
|
||||
second_param = type_void;
|
||||
}
|
||||
second_param = second_param->canonical;
|
||||
}
|
||||
|
||||
if (!type_is_user_defined(parent_type))
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user