mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Overload resolution fixes to inline typedef #2226.
This commit is contained in:
@@ -57,6 +57,7 @@
|
||||
- Linking fails on operator method imported as `@public` #2224.
|
||||
- Lambda C-style vaargs were not properly rejected, leading to crash #2229.
|
||||
- Incorrect handling of constant null fault causing compiler crash #2232.
|
||||
- Overload resolution fixes to inline typedef #2226.
|
||||
|
||||
### Stdlib changes
|
||||
- Deprecate `String.is_zstr` and `String.quick_zstr` #2188.
|
||||
|
||||
@@ -291,6 +291,7 @@ static inline ConstInitializer *expr_const_initializer_from_expr(Expr *expr)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The following valid cases exist:
|
||||
*
|
||||
@@ -303,14 +304,11 @@ static inline ConstInitializer *expr_const_initializer_from_expr(Expr *expr)
|
||||
*/
|
||||
bool sema_expr_analyse_ct_concat(SemaContext *context, Expr *concat_expr, Expr *left, Expr *right, bool *failed_ref)
|
||||
{
|
||||
ASSERT(concat_expr->resolve_status == RESOLVE_RUNNING);
|
||||
ASSERT_SPAN(concat_expr, concat_expr->resolve_status == RESOLVE_RUNNING);
|
||||
if (!sema_check_left_right_const(context, left, right)) return false;
|
||||
ArraySize len = 0;
|
||||
bool use_array = true;
|
||||
Type *indexed_type = NULL;
|
||||
if (!sema_analyse_expr(context, left)) return false;
|
||||
if (!sema_cast_const(left)) RETURN_SEMA_ERROR(left, "Expected this to evaluate to a constant value.");
|
||||
if (!sema_analyse_expr(context, right)) return false;
|
||||
if (!sema_cast_const(right)) RETURN_SEMA_ERROR(right, "Expected this to evaluate to a constant value.");
|
||||
Type *element_type = left->type->canonical;
|
||||
Type *right_type = right->type->canonical;
|
||||
switch (left->const_expr.const_kind)
|
||||
|
||||
@@ -1802,27 +1802,37 @@ static bool sema_find_typed_operator_in_list(SemaContext *context, Decl **method
|
||||
{
|
||||
|
||||
Decl *candidate = *candidate_ref;
|
||||
Type *candidate_type = candidate ? candidate->func_decl.signature.params[1]->type : NULL;
|
||||
bool last_first_arg_exact_match = candidate_type ? candidate_type->canonical == binary_type : false;
|
||||
|
||||
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;
|
||||
bool is_exact_match = true;
|
||||
if (!func->func_decl.is_wildcard_overload)
|
||||
{
|
||||
Type *first_arg = func->func_decl.signature.params[1]->type->canonical;
|
||||
if (first_arg != binary_type)
|
||||
{
|
||||
is_exact_match = false;
|
||||
if (!binary_arg) continue;
|
||||
if (!may_cast(context, binary_arg, first_arg, false, true)) continue;
|
||||
}
|
||||
}
|
||||
if (candidate && !candidate->func_decl.is_wildcard_overload)
|
||||
{
|
||||
if (last_first_arg_exact_match && !is_exact_match) continue;
|
||||
if (!last_first_arg_exact_match && is_exact_match) goto MATCH;
|
||||
assert(!last_first_arg_exact_match);
|
||||
*ambiguous_ref = func;
|
||||
*candidate_ref = candidate;
|
||||
return false;
|
||||
}
|
||||
MATCH:
|
||||
candidate = func;
|
||||
last_first_arg_exact_match = is_exact_match;
|
||||
}
|
||||
*candidate_ref = candidate;
|
||||
return true;
|
||||
|
||||
@@ -1224,6 +1224,50 @@ static inline bool sema_expr_analyse_ct_identifier(SemaContext *context, Expr *e
|
||||
}
|
||||
|
||||
|
||||
static inline bool sema_binary_analyse_with_inference(SemaContext *context, Expr *left, Expr *right, BinaryOp op)
|
||||
{
|
||||
const static int op_table[BINARYOP_LAST + 1] = {
|
||||
[BINARYOP_AND] = 1, [BINARYOP_OR] = 1, [BINARYOP_CT_AND] = 1, [BINARYOP_CT_OR] = 1,
|
||||
[BINARYOP_EQ] = 2, [BINARYOP_NE] = 2 };
|
||||
int op_result = op_table[op];
|
||||
if (op_result == 1) return true;
|
||||
// If lhs or rhs is an initializer list, infer
|
||||
bool is_init_rhs = right->expr_kind == EXPR_INITIALIZER_LIST;
|
||||
bool is_init_lhs = left->expr_kind == EXPR_INITIALIZER_LIST;
|
||||
if (is_init_rhs && is_init_lhs) goto EVAL_BOTH;
|
||||
|
||||
if (is_init_rhs)
|
||||
{
|
||||
if (!sema_analyse_expr(context, left)) return false;
|
||||
if (type_kind_is_any_vector(type_flatten(left->type)->type_kind))
|
||||
{
|
||||
return sema_analyse_inferred_expr(context, left->type, right);
|
||||
}
|
||||
return sema_analyse_expr(context, right);
|
||||
}
|
||||
if (is_init_lhs)
|
||||
{
|
||||
if (!sema_analyse_expr(context, right)) return false;
|
||||
if (type_kind_is_any_vector(type_flatten(right->type)->type_kind))
|
||||
{
|
||||
return sema_analyse_inferred_expr(context, right->type, left);
|
||||
}
|
||||
return sema_analyse_expr(context, left);
|
||||
}
|
||||
|
||||
if (op_result != 2) goto EVAL_BOTH;
|
||||
|
||||
if (!sema_analyse_expr(context, left)) return false;
|
||||
if (left->type->canonical->type_kind == TYPE_ENUM)
|
||||
{
|
||||
return sema_analyse_inferred_expr(context, left->type, right);
|
||||
}
|
||||
return sema_analyse_expr(context, right);
|
||||
|
||||
EVAL_BOTH:
|
||||
return sema_analyse_expr(context, left) && sema_analyse_expr(context, right);
|
||||
}
|
||||
|
||||
static inline bool sema_binary_analyse_subexpr(SemaContext *context, Expr *left, Expr *right)
|
||||
{
|
||||
// Special handling of f = FOO_BAR
|
||||
@@ -1273,7 +1317,8 @@ static inline bool sema_binary_analyse_arithmetic_subexpr(SemaContext *context,
|
||||
Expr *right = exprptr(expr->binary_expr.right);
|
||||
|
||||
// 1. Analyse both sides.
|
||||
if (!sema_binary_analyse_subexpr(context, left, right)) return false;
|
||||
ASSERT_SPAN(expr, left->resolve_status == RESOLVE_DONE);
|
||||
ASSERT_SPAN(expr, right->resolve_status == RESOLVE_DONE);
|
||||
|
||||
Type *left_type = type_no_optional(left->type)->canonical;
|
||||
Type *right_type = type_no_optional(right->type)->canonical;
|
||||
@@ -8656,10 +8701,22 @@ static inline bool sema_expr_analyse_binary(SemaContext *context, Type *infer_ty
|
||||
RETURN_SEMA_ERROR(expr, "You need to add explicit parentheses to clarify precedence.");
|
||||
}
|
||||
BinaryOp operator = expr->binary_expr.operator;
|
||||
if (operator >= BINARYOP_ASSIGN)
|
||||
{
|
||||
if (left->expr_kind != EXPR_TYPEINFO)
|
||||
{
|
||||
if (!sema_analyse_expr_lvalue(context, left, NULL)) return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (operator == BINARYOP_ELSE) return sema_expr_analyse_or_error(context, expr, left, right, infer_type, failed_ref);
|
||||
if (!sema_binary_analyse_with_inference(context, left, right, operator)) return false;
|
||||
}
|
||||
switch (operator)
|
||||
{
|
||||
case BINARYOP_ELSE:
|
||||
return sema_expr_analyse_or_error(context, expr, left, right, infer_type, failed_ref);
|
||||
UNREACHABLE
|
||||
case BINARYOP_CT_CONCAT:
|
||||
return sema_expr_analyse_ct_concat(context, expr, left, right, failed_ref);
|
||||
case BINARYOP_CT_OR:
|
||||
|
||||
@@ -130,6 +130,12 @@ INLINE bool sema_set_alloca_alignment(SemaContext *context, Type *type, AlignSiz
|
||||
INLINE void sema_display_deprecated_warning_on_use(Decl *decl, SourceSpan span);
|
||||
bool sema_expr_analyse_ct_concat(SemaContext *context, Expr *concat_expr, Expr *left, Expr *right, bool *failed_ref);
|
||||
|
||||
INLINE bool sema_check_left_right_const(SemaContext *context, Expr *left, Expr *right)
|
||||
{
|
||||
if (!sema_cast_const(left)) RETURN_SEMA_ERROR(left, "Expected this to evaluate to a constant value.");
|
||||
if (!sema_cast_const(right)) RETURN_SEMA_ERROR(right, "Expected this to evaluate to a constant value.");
|
||||
return true;
|
||||
}
|
||||
|
||||
INLINE bool sema_set_abi_alignment(SemaContext *context, Type *type, AlignSize *result)
|
||||
{
|
||||
|
||||
39
test/test_suite/methods/overload_method_example.c3t
Normal file
39
test/test_suite/methods/overload_method_example.c3t
Normal file
@@ -0,0 +1,39 @@
|
||||
// #target: macos-x64
|
||||
module test;
|
||||
struct Word {int x;}
|
||||
typedef Byte = inline ushort;
|
||||
|
||||
macro Word Word.add0(self, int other) @operator(+) => { self.x + (int)other };
|
||||
macro Word Word.add1(self, Byte other) @operator(+) => { self.x + (int)other };
|
||||
|
||||
fn int main()
|
||||
{
|
||||
Word a = {1};
|
||||
Byte b = 2;
|
||||
Word c = a + b;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* #expect: test.ll
|
||||
|
||||
define i32 @main() #0 {
|
||||
entry:
|
||||
%a = alloca %Word, align 4
|
||||
%b = alloca i16, align 2
|
||||
%c = alloca %Word, align 4
|
||||
%self = alloca %Word, align 4
|
||||
%other = alloca i16, align 2
|
||||
%literal = alloca %Word, align 4
|
||||
call void @llvm.memcpy.p0.p0.i32(ptr align 4 %a, ptr align 4 @.__const, i32 4, i1 false)
|
||||
store i16 2, ptr %b, align 2
|
||||
call void @llvm.memcpy.p0.p0.i32(ptr align 4 %self, ptr align 4 %a, i32 4, i1 false)
|
||||
%0 = load i16, ptr %b, align 2
|
||||
store i16 %0, ptr %other, align 2
|
||||
%1 = load i32, ptr %self, align 4
|
||||
%2 = load i16, ptr %other, align 2
|
||||
%zext = zext i16 %2 to i32
|
||||
%add = add i32 %1, %zext
|
||||
store i32 %add, ptr %literal, align 4
|
||||
call void @llvm.memcpy.p0.p0.i32(ptr align 4 %c, ptr align 4 %literal, i32 4, i1 false)
|
||||
ret i32 0
|
||||
}
|
||||
Reference in New Issue
Block a user