From 9b80b2e868252d439453aedf0790422e6cb607ec Mon Sep 17 00:00:00 2001 From: Tomohiro Date: Mon, 8 Jun 2026 16:00:00 +0900 Subject: [PATCH] fixes-25655; defining `>=` operator generates compile error (#25787) Fixes https://github.com/nim-lang/Nim/issues/25655 --------- Co-authored-by: Andreas Rumpf --- compiler/lineinfos.nim | 2 ++ compiler/nilcheck.nim | 6 ------ compiler/semstmts.nim | 5 +++++ tests/proc/tinvalid_cmp_op1.nim | 12 ++++++++++++ tests/proc/tinvalid_cmp_op2.nim | 12 ++++++++++++ tests/proc/tinvalid_cmp_op3.nim | 12 ++++++++++++ 6 files changed, 43 insertions(+), 6 deletions(-) create mode 100644 tests/proc/tinvalid_cmp_op1.nim create mode 100644 tests/proc/tinvalid_cmp_op2.nim create mode 100644 tests/proc/tinvalid_cmp_op3.nim diff --git a/compiler/lineinfos.nim b/compiler/lineinfos.nim index bb3f519535..2ac5cec7aa 100644 --- a/compiler/lineinfos.nim +++ b/compiler/lineinfos.nim @@ -100,6 +100,7 @@ type warnGlobalVarConstructorTemporary = "GlobalVarConstructorTemporary", warnImplicitRangeConversion = "ImplicitRangeConversion", warnSystemRangeConversion = "SystemRangeConversion", + warnInvalidCmpOp = "InvalidCmpOp", # hints hintSuccess = "Success", hintSuccessX = "SuccessX", hintCC = "CC", @@ -210,6 +211,7 @@ const warnGlobalVarConstructorTemporary: "global variable '$1' initialization requires a temporary variable", warnImplicitRangeConversion: "implicit range conversion $1", warnSystemRangeConversion: "implicit range conversion $1", + warnInvalidCmpOp: "$1", hintSuccess: "operation successful: $#", # keep in sync with `testament.isSuccess` hintSuccessX: "$build\n$loc lines; ${sec}s; $mem; proj: $project; out: $output", diff --git a/compiler/nilcheck.nim b/compiler/nilcheck.nim index 7e0efc34bb..fad9bd5b8a 100644 --- a/compiler/nilcheck.nim +++ b/compiler/nilcheck.nim @@ -183,12 +183,6 @@ func `<`*(a: ExprIndex, b: ExprIndex): bool = func `<=`*(a: ExprIndex, b: ExprIndex): bool = a.int16 <= b.int16 -func `>`*(a: ExprIndex, b: ExprIndex): bool = - a.int16 > b.int16 - -func `>=`*(a: ExprIndex, b: ExprIndex): bool = - a.int16 >= b.int16 - func `==`*(a: ExprIndex, b: ExprIndex): bool = a.int16 == b.int16 diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 465276ffc2..8b9ce24efa 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -2642,6 +2642,11 @@ proc semProcAux(c: PContext, n: PNode, kind: TSymKind, elif s.name.s == "()" and callOperator notin c.features: localError(c.config, n.info, "the overloaded " & s.name.s & " operator has to be enabled with {.experimental: \"callOperator\".}") + elif sfImportc notin s.flags and (s.name.s == ">" or s.name.s == ">=" or s.name.s == "!="): + # ignore imported procs as these operators in backend language might have different semantics + let op1 = if s.name.s == "!=": "==" elif s.name.s == ">": "<" else: "<=" + message(c.config, n.info, warnInvalidCmpOp, "define `" & op1 & "` instead of `" & s.name.s & "` to implement user defined comparison operator. " & + "it allows you to use `" & s.name.s & "` automatically.") if sfBorrow in s.flags and c.config.cmd notin cmdDocLike: result[bodyPos] = c.graph.emptyNode diff --git a/tests/proc/tinvalid_cmp_op1.nim b/tests/proc/tinvalid_cmp_op1.nim new file mode 100644 index 0000000000..3b223c8348 --- /dev/null +++ b/tests/proc/tinvalid_cmp_op1.nim @@ -0,0 +1,12 @@ +discard """ + cmd: "nim check $file" + action: compile + nimout: ''' +tinvalid_cmp_op1.nim(12, 1) Warning: define `<=` instead of `>=` to implement user defined comparison operator. it allows you to use `>=` automatically. [InvalidCmpOp] +''' +""" + +# issue #25655 + +type Foo = distinct int +func `>=`(a, b: Foo): bool = int(a) >= int(b) diff --git a/tests/proc/tinvalid_cmp_op2.nim b/tests/proc/tinvalid_cmp_op2.nim new file mode 100644 index 0000000000..861e6959cf --- /dev/null +++ b/tests/proc/tinvalid_cmp_op2.nim @@ -0,0 +1,12 @@ +discard """ + cmd: "nim check $file" + action: compile + nimout: ''' +tinvalid_cmp_op2.nim(12, 1) Warning: define `<` instead of `>` to implement user defined comparison operator. it allows you to use `>` automatically. [InvalidCmpOp] +''' +""" + +# issue #25655 + +type Foo = distinct int +func `>`(a, b: Foo): bool = int(a) > int(b) diff --git a/tests/proc/tinvalid_cmp_op3.nim b/tests/proc/tinvalid_cmp_op3.nim new file mode 100644 index 0000000000..f543edd3f0 --- /dev/null +++ b/tests/proc/tinvalid_cmp_op3.nim @@ -0,0 +1,12 @@ +discard """ + cmd: "nim check $file" + action: compile + nimout: ''' +tinvalid_cmp_op3.nim(12, 1) Warning: define `==` instead of `!=` to implement user defined comparison operator. it allows you to use `!=` automatically. [InvalidCmpOp] +''' +""" + +# issue #25655 + +type Foo = distinct int +func `!=`(a, b: Foo): bool = int(a) != int(b)