Overload resolution fixes to inline typedef #2226.

This commit is contained in:
Christoffer Lerno
2025-06-21 13:03:16 +02:00
parent b4a6e3704f
commit fa730e7ec2
6 changed files with 118 additions and 7 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

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