From 78eeed6834acdc5839f6e80dd5c037d1a27fe000 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Wed, 25 Mar 2026 16:42:20 +0300 Subject: [PATCH] checker: fix referenced operator overloading not working (fixes #15551) --- vlib/v/checker/infix.v | 22 ++++++++++--------- ...overloading_with_reference_operands_test.v | 21 ++++++++++++++++++ 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/vlib/v/checker/infix.v b/vlib/v/checker/infix.v index 60424a3ee..a3d1b7dd6 100644 --- a/vlib/v/checker/infix.v +++ b/vlib/v/checker/infix.v @@ -15,6 +15,12 @@ fn infix_expr_is_nil_like(expr ast.Expr) bool { return expr.is_nil() || (expr is ast.UnsafeExpr && expr.expr.is_nil()) } +fn has_matching_reference_operator_overload(sym &ast.TypeSymbol, op string, receiver_type ast.Type, operand_type ast.Type) bool { + method := sym.find_method_with_generic_parent(op) or { return false } + return method.params.len == 2 && method.params[0].typ == receiver_type + && method.params[1].typ == operand_type +} + fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type { former_expected_type := c.expected_type defer { @@ -188,17 +194,13 @@ fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type { if left_type.is_any_kind_of_pointer() && !left_type.has_flag(.shared_f) && !node.left.is_auto_deref_var() && node.op in [.plus, .minus, .mul, .div, .mod, .xor, .amp, .pipe] { - if !c.pref.translated && ((right_type.is_any_kind_of_pointer() && node.op != .minus) + if has_matching_reference_operator_overload(left_sym, node.op.str(), left_type, + right_type) + { + // allow explicit operator overloads like `fn (x &Type) OP (y &Type) ReturnType {` + } else if !c.pref.translated && ((right_type.is_any_kind_of_pointer() && node.op != .minus) || (!right_type.is_any_kind_of_pointer() && node.op !in [.plus, .minus])) { - if _ := left_sym.find_method(node.op.str()) { - if left_sym.kind == .alias && right_sym.kind == .alias { - // allow an explicit operator override `fn (x &AliasType) OP (y &AliasType) &AliasType {` - } else { - c.invalid_operator_error(node.op, left_type, right_type, left_right_pos) - } - } else { - c.invalid_operator_error(node.op, left_type, right_type, left_right_pos) - } + c.invalid_operator_error(node.op, left_type, right_type, left_right_pos) } else if node.op in [.plus, .minus] { if !c.inside_unsafe && !node.left.is_auto_deref_var() && !node.right.is_auto_deref_var() { if !c.pref.translated && !c.file.is_translated { diff --git a/vlib/v/tests/structs/operator_overloading_with_reference_operands_test.v b/vlib/v/tests/structs/operator_overloading_with_reference_operands_test.v index 6c5db2a87..9c43aab6b 100644 --- a/vlib/v/tests/structs/operator_overloading_with_reference_operands_test.v +++ b/vlib/v/tests/structs/operator_overloading_with_reference_operands_test.v @@ -45,3 +45,24 @@ fn test_eq_operator_with_reference_operands() { } assert false } + +struct Sum { + value int +} + +fn (a &Sum) + (b &Sum) &Sum { + return &Sum{ + value: a.value + b.value + } +} + +fn test_plus_operator_with_reference_operands() { + a := &Sum{ + value: 2 + } + b := &Sum{ + value: 3 + } + c := a + b + assert c.value == 5 +} -- 2.39.5