Compare commits

...

1 Commits

Author SHA1 Message Date
Christoffer Lerno
3348f4dc7d Test of overloading. 2022-09-15 22:31:31 +02:00
5 changed files with 174 additions and 11 deletions

View File

@@ -636,7 +636,7 @@ typedef struct Decl_
bool obfuscate : 1;
bool is_dynamic : 1;
bool is_synthetic : 1;
OperatorOverload operator : 4;
OperatorOverload operator : 5;
union
{
void *backend_ref;
@@ -1781,7 +1781,7 @@ extern const char *kw_max;
extern const char *kw_min;
extern const char *kw_elements;
extern const char *kw_align;
extern const char *kw_add;
extern const char *kw_nameof;
extern const char *kw_names;
extern const char *kw_sizeof;
@@ -1790,6 +1790,7 @@ extern const char *kw_out;
extern const char *kw_inout;
extern const char *kw_deprecated;
extern const char *kw_distinct;
extern const char *kw_div;
extern const char *kw_intvec;
extern const char *kw_floatvec;
extern const char *kw_inline;
@@ -1800,17 +1801,21 @@ extern const char *kw_elementat;
extern const char *kw_elementref;
extern const char *kw_elementset;
extern const char *kw_len;
extern const char *kw_nan;
extern const char *kw_noinline;
extern const char *kw_main;
extern const char *kw_max;
extern const char *kw_min;
extern const char *kw_mult;
extern const char *kw_nan;
extern const char *kw_neg;
extern const char *kw_noinline;
extern const char *kw_ordinal;
extern const char *kw_pure;
extern const char *kw_ptr;
extern const char *kw_values;
extern const char *kw_rem;
extern const char *kw_return;
extern const char *kw_sub;
extern const char *kw_type;
extern const char *kw_values;
extern const char *kw_FILE;
extern const char *kw_FUNC;
extern const char *kw_LINE;

View File

@@ -722,6 +722,12 @@ typedef enum
OVERLOAD_ELEMENT_REF,
OVERLOAD_ELEMENT_SET,
OVERLOAD_LEN,
OVERLOAD_ADD,
OVERLOAD_SUB,
OVERLOAD_MULT,
OVERLOAD_DIV,
OVERLOAD_REM,
OVERLOAD_NEG,
} OperatorOverload;
typedef enum

View File

@@ -1274,6 +1274,34 @@ static inline bool sema_analyse_operator_len(Decl *method)
return true;
}
static inline bool sema_analyse_operator_binary_arithmetics(Decl *method)
{
TypeInfo *rtype;
Signature *signature = &method->func_decl.signature;
Decl **params = signature->params;
uint32_t param_count = vec_size(params);
if (param_count != 2)
{
SEMA_ERROR(method, "Expected two elements for this operation.");
return false;
}
return true;
}
static inline bool sema_analyse_operator_unary_arithmetics(Decl *method)
{
TypeInfo *rtype;
Signature *signature = &method->func_decl.signature;
Decl **params = signature->params;
uint32_t param_count = vec_size(params);
if (param_count != 1)
{
SEMA_ERROR(method, "Too many parameters for this operation.");
return false;
}
return true;
}
static bool sema_check_operator_method_validity(Decl *method)
{
switch (method->operator)
@@ -1285,6 +1313,14 @@ static bool sema_check_operator_method_validity(Decl *method)
return sema_analyse_operator_element_at(method);
case OVERLOAD_LEN:
return sema_analyse_operator_len(method);
case OVERLOAD_ADD:
case OVERLOAD_DIV:
case OVERLOAD_MULT:
case OVERLOAD_REM:
case OVERLOAD_SUB:
return sema_analyse_operator_binary_arithmetics(method);
case OVERLOAD_NEG:
return sema_analyse_operator_unary_arithmetics(method);
}
UNREACHABLE
}
@@ -1402,6 +1438,21 @@ static const char *attribute_domain_to_string(AttributeDomain domain)
UNREACHABLE
}
INLINE bool check_operator_overload(Expr *expr, Decl *decl, const char *kw)
{
if (decl->decl_kind != DECL_MACRO)
{
SEMA_ERROR(expr, "@operator(%s) can only be used with macros.", kw);
return false;
}
if (!decl->func_decl.type_parent)
{
SEMA_ERROR(expr, "@operator(%s) can only be used with method-like macros.", kw);
return false;
}
return true;
}
static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr, AttributeDomain domain)
{
AttributeType type = attr->attr_kind;
@@ -1538,6 +1589,36 @@ static bool sema_analyse_attribute(SemaContext *context, Decl *decl, Attr *attr,
}
decl->operator = OVERLOAD_LEN;
}
else if (kw == kw_add)
{
if (!check_operator_overload(expr, decl, kw)) return false;
decl->operator = OVERLOAD_ADD;
}
else if (kw == kw_sub)
{
if (!check_operator_overload(expr, decl, kw)) return false;
decl->operator = OVERLOAD_SUB;
}
else if (kw == kw_mult)
{
if (!check_operator_overload(expr, decl, kw)) return false;
decl->operator = OVERLOAD_MULT;
}
else if (kw == kw_div)
{
if (!check_operator_overload(expr, decl, kw)) return false;
decl->operator = OVERLOAD_DIV;
}
else if (kw == kw_rem)
{
if (!check_operator_overload(expr, decl, kw)) return false;
decl->operator = OVERLOAD_REM;
}
else if (kw == kw_neg)
{
if (!check_operator_overload(expr, decl, kw)) return false;
decl->operator = OVERLOAD_NEG;
}
else if (kw == kw_floatvec)
{
if (decl->decl_kind != DECL_MACRO)

View File

@@ -838,6 +838,31 @@ bool sema_expr_check_assign(SemaContext *c, Expr *expr)
return false;
}
static Decl *sema_type_get_overload_method(Type *a, OperatorOverload overload)
{
if (!overload) return NULL;
assert(a->canonical == a);
if (!type_may_have_sub_elements(a))
{
return NULL;
}
FOREACH_BEGIN(Decl *method, a->decl->methods)
if (method->operator == overload) return method;
FOREACH_END();
return NULL;
}
INLINE bool sema_rewrite_analyze_overload(SemaContext *context, Expr *expr, Decl *decl, Expr *left, Expr *right)
{
expr->expr_kind = EXPR_CALL;
Expr **args = VECNEW(Expr*, 2);
vec_add(args, right);
expr->call_expr = (ExprCall){ .arguments = args, .func_ref = declid(decl) };
return sema_expr_analyse_general_call(context, expr, decl, left, false);
}
static inline bool sema_cast_ident_rvalue(SemaContext *context, Expr *expr)
{
Decl *decl = expr->identifier_expr.decl;
@@ -1325,7 +1350,7 @@ static inline bool sema_expr_analyse_binary_subexpr(SemaContext *context, Expr *
return (int)sema_analyse_expr(context, left) & (int)sema_analyse_expr(context, right);
}
static inline bool sema_expr_analyse_binary_arithmetic_subexpr(SemaContext *context, Expr *expr, const char *error, bool bool_is_allowed)
static inline bool sema_expr_analyse_binary_arithmetic_subexpr(SemaContext *context, Expr *expr, const char *error, bool bool_is_allowed, OperatorOverload *overload)
{
Expr *left = exprptr(expr->binary_expr.left);
Expr *right = exprptr(expr->binary_expr.right);
@@ -1338,6 +1363,14 @@ static inline bool sema_expr_analyse_binary_arithmetic_subexpr(SemaContext *cont
Type *left_type = type_no_optional(left->type)->canonical;
Type *right_type = type_no_optional(right->type)->canonical;
Decl *possible_overload = sema_type_get_overload_method(left_type, *overload);
if (possible_overload)
{
if (!sema_rewrite_analyze_overload(context, expr, possible_overload, left, right)) return false;
return true;
}
*overload = 0;
if (bool_is_allowed && left_type == type_bool && right_type == type_bool) return true;
// 2. Perform promotion to a common type.
return binary_arithmetic_promotion(context, left, right, left_type, right_type, expr, error);
@@ -5879,6 +5912,12 @@ static bool sema_expr_analyse_sub(SemaContext *context, Expr *expr, Expr *left,
left_type = type_no_optional(left->type)->canonical;
right_type = type_no_optional(right->type)->canonical;
Decl *possible_overload = sema_type_get_overload_method(left_type, OVERLOAD_SUB);
if (possible_overload)
{
return sema_rewrite_analyze_overload(context, expr, possible_overload, left, right);
}
// 7. Attempt arithmetic promotion, to promote both to a common type.
if (!binary_arithmetic_promotion(context, left, right, left_type, right_type, expr, "The subtraction %s - %s is not possible."))
{
@@ -5910,6 +5949,7 @@ static bool sema_expr_analyse_sub(SemaContext *context, Expr *expr, Expr *left,
}
/**
* Analyse a + b
* @return true if it succeeds.
@@ -6003,6 +6043,12 @@ static bool sema_expr_analyse_add(SemaContext *context, Expr *expr, Expr *left,
left_type = type_no_optional(left->type)->canonical;
right_type = type_no_optional(right->type)->canonical;
Decl *possible_overload = sema_type_get_overload_method(left_type, OVERLOAD_ADD);
if (possible_overload)
{
return sema_rewrite_analyze_overload(context, expr, possible_overload, left, right);
}
assert(!cast_to_iptr);
// 4. Do a binary arithmetic promotion
if (!binary_arithmetic_promotion(context, left, right, left_type, right_type, expr, "Cannot do the addition %s + %s."))
@@ -6046,8 +6092,9 @@ static bool sema_expr_analyse_mult(SemaContext *context, Expr *expr, Expr *left,
{
// 1. Analyse the sub expressions and promote to a common type
if (!sema_expr_analyse_binary_arithmetic_subexpr(context, expr, "It is not possible to multiply %s by %s.", false)) return false;
OperatorOverload overload = OVERLOAD_MULT;
if (!sema_expr_analyse_binary_arithmetic_subexpr(context, expr, "It is not possible to multiply %s by %s.", false, &overload)) return false;
if (overload) return true;
// 2. Handle constant folding.
if (expr_both_const(left, right))
@@ -6079,7 +6126,9 @@ static bool sema_expr_analyse_mult(SemaContext *context, Expr *expr, Expr *left,
static bool sema_expr_analyse_div(SemaContext *context, Expr *expr, Expr *left, Expr *right)
{
// 1. Analyse sub expressions and promote to a common type
if (!sema_expr_analyse_binary_arithmetic_subexpr(context, expr, "Cannot divide %s by %s.", false)) return false;
OperatorOverload overload = OVERLOAD_DIV;
if (!sema_expr_analyse_binary_arithmetic_subexpr(context, expr, "Cannot divide %s by %s.", false, &overload)) return false;
if (overload) return true;
// 2. Check for a constant 0 on the rhs.
if (IS_CONST(right))
@@ -6131,7 +6180,9 @@ static bool sema_expr_analyse_div(SemaContext *context, Expr *expr, Expr *left,
static bool sema_expr_analyse_mod(SemaContext *context, Expr *expr, Expr *left, Expr *right)
{
// 1. Analyse both sides and promote to a common type
if (!sema_expr_analyse_binary_arithmetic_subexpr(context, expr, NULL, false)) return false;
OperatorOverload overload = OVERLOAD_REM;
if (!sema_expr_analyse_binary_arithmetic_subexpr(context, expr, NULL, false, &overload)) return false;
if (overload) return true;
// 3. a % 0 is not valid, so detect it.
if (IS_CONST(right) && int_is_zero(right->const_expr.ixx))
@@ -6160,7 +6211,8 @@ static bool sema_expr_analyse_bit(SemaContext *context, Expr *expr, Expr *left,
{
// 1. Convert to common type if possible.
if (!sema_expr_analyse_binary_arithmetic_subexpr(context, expr, NULL, true)) return false;
OperatorOverload overload = 0;
if (!sema_expr_analyse_binary_arithmetic_subexpr(context, expr, NULL, true, &overload)) return false;
// 2. Check that both are integers or bools.
bool is_bool = left->type->canonical == type_bool;
@@ -6730,6 +6782,13 @@ static bool sema_expr_analyse_neg(SemaContext *context, Expr *expr)
Type *no_fail = type_no_optional(inner->type);
if (!type_may_negate(no_fail))
{
Decl *decl = sema_type_get_overload_method(no_fail->canonical, OVERLOAD_NEG);
if (decl)
{
expr->expr_kind = EXPR_CALL;
expr->call_expr = (ExprCall){ .func_ref = declid(decl) };
return sema_expr_analyse_general_call(context, expr, decl, inner, false);
}
SEMA_ERROR(expr, "Cannot negate an expression of type %s.", type_quoted_error_string(no_fail));
return false;
}

View File

@@ -43,6 +43,7 @@ const char *kw_FILE;
const char *kw_FUNC;
const char *kw_LINEREAL;
const char *kw_LINE;
const char *kw_add;
const char *kw_align;
const char *kw_argc;
const char *kw_argv;
@@ -56,6 +57,7 @@ const char *kw_at_return;
const char *kw_check_assign;
const char *kw_deprecated;
const char *kw_distinct;
const char *kw_div;
const char *kw_elementat;
const char *kw_elementref;
const char *kw_elementset;
@@ -74,19 +76,23 @@ const char *kw_mainstub;
const char *kw_main;
const char *kw_max;
const char *kw_min;
const char *kw_mult;
const char *kw_nameof;
const char *kw_names;
const char *kw_nan;
const char *kw_neg;
const char *kw_noinline;
const char *kw_ordinal;
const char *kw_out;
const char *kw_ptr;
const char *kw_pure;
const char *kw_rem;
const char *kw_return;
const char *kw_sizeof;
const char *kw_std;
const char *kw_std__core;
const char *kw_std__core__types;
const char *kw_sub;
const char *kw_typekind;
const char *kw_type;
const char *kw_values;
@@ -140,11 +146,13 @@ void symtab_init(uint32_t capacity)
type = TOKEN_IDENT;
kw_add = KW_DEF("add");
kw_align = KW_DEF("align");
kw_argc = KW_DEF("_$argc");
kw_argv = KW_DEF("_$argv");
kw_check_assign = KW_DEF("check_assign");
kw_deprecated = KW_DEF("deprecated");
kw_div = KW_DEF("div");
kw_distinct = KW_DEF("distinct");
kw_elementat = KW_DEF("elementat");
kw_elementref = KW_DEF("elementref");
@@ -164,18 +172,22 @@ void symtab_init(uint32_t capacity)
kw_main = KW_DEF("main");
kw_max = KW_DEF("max");
kw_min = KW_DEF("min");
kw_mult = KW_DEF("mult");
kw_nameof = KW_DEF("nameof");
kw_names = KW_DEF("names");
kw_nan = KW_DEF("nan");
kw_neg = KW_DEF("neg");
kw_noinline = KW_DEF("noinline");
kw_ordinal = KW_DEF("ordinal");
kw_out = KW_DEF("out");
kw_ptr = KW_DEF("ptr");
kw_pure = KW_DEF("pure");
kw_rem = KW_DEF("rem");
kw_sizeof = KW_DEF("sizeof");
kw_std = KW_DEF("std");
kw_std__core = KW_DEF("std::core");
kw_std__core__types = KW_DEF("std::core::types");
kw_sub = KW_DEF("sub");
kw_type = KW_DEF("type");
kw_values = KW_DEF("values");