Nim icon indicating copy to clipboard operation
Nim copied to clipboard

Generic overload ambiguous call for int literal; Regression in 2.0/2.2/devel

Open nitely opened this issue 3 months ago • 5 comments

Nim Version

Nim Compiler Version 2.3.1 [Linux: amd64] Compiled at 2025-09-13 Copyright (c) 2006-2025 by Andreas Rumpf

git hash: ff9cae896ce900ac8e77ec9a51e09192653a1a49 active boot switches: -d:release

Description

proc foo[T: int](x: T) =
  echo "int"
proc foo[T: uint](x: T) =
  echo "uint"

foo(0'u) # ok
foo(0'u8) # ok
foo(0'i8) # ok
foo(0.int)  # ok
foo(0)  # fails

Current Output

ambiguous call error

Expected Output

uint
uint
int
int
int

Known Workarounds

No response

Additional Information

Works in Nim 1.6.20 and 2.0.8, fails in 2.0.10 to 2.0.16, 2.2.0 to 2.2.4 and devel.

nitely avatar Sep 15 '25 14:09 nitely

!nim c

proc foo[T: int](x: T) =
  echo "int"
proc foo[T: uint](x: T) =
  echo "uint"

foo(0)  # fails

ringabout avatar Sep 17 '25 13:09 ringabout

:penguin: Linux bisect by @ringabout (member)
devel :-1: FAIL

Output


Filesize 0 (0 bytes) Duration

stable :-1: FAIL

Output


Filesize 0 (0 bytes) Duration

2.2.2 :-1: FAIL

Output


Filesize 0 (0 bytes) Duration

2.0.0 :+1: OK

Output


Filesize 91.02 Kb (93,208 bytes) Duration

1.6.20 :+1: OK

Output


Filesize 96.09 Kb (98,400 bytes) Duration

1.4.8 :+1: OK

Output


Filesize 92.19 Kb (94,400 bytes) Duration

1.2.18 :+1: OK

Output


Filesize 91.91 Kb (94,112 bytes) Duration

1.0.10 :+1: OK

Output


Filesize 87.03 Kb (89,120 bytes) Duration

??? :arrow_right: :bug:

Diagnostics

The commit that introduced the bug can not be found, but the bug is in the commits:

(Can not find the commit because Nim can not be re-built commit-by-commit to bisect).

Stats
  • GCC 13.3.0
  • Clang 18.1.3
  • NodeJS 19.5
  • Created 2025-09-17T13:27:20Z
  • Comments 1
  • Commands nim c --run -d:nimDebug -d:nimDebugDlOpen -d:ssl -d:nimDisableCertificateValidation --forceBuild:on --colors:off --verbosity:0 --hints:off --lineTrace:off --nimcache:/home/runner/work/Nim/Nim --out:/home/runner/work/Nim/Nim/temp /home/runner/work/Nim/Nim/temp.nim

:robot: Bug found in 27 mins bisecting 1372 commits at 50 commits per second

github-actions[bot] avatar Sep 17 '25 14:09 github-actions[bot]

Not that it's impossible to make this work, but the spec doesn't have any kind of rule that would make int match stronger then uint generically. I'm not sure this is a bug since 0.int works.

Graveflo avatar Sep 17 '25 15:09 Graveflo

I was expecting the constrained generic to match the same as the concrete type proc version, as it seems to be the case for every other type. It also seems to work for generic [T: int] and [T: float] as I'd expect.

proc foo(x: int) =
  echo "int"
proc foo(x: uint) =
  echo "uint"
foo(0)
# output: int

proc bar[T: int](x: T) =
  echo "int"
proc bar[T: float](x: T) =
  echo "float"
bar(0)
# output: int

proc baz[T: float](x: T) =
  echo "float"
baz(0)
# output: float

Also, the issue also exists for SomeUnsignedInt and SomeSignedInt:

proc foo[T: SomeSignedInt](x: T): string =
  "SomeSignedInt"
proc foo[T: SomeUnsignedInt](x: T): string =
  "SomeUnsignedInt"
doAssert foo(0'u) == "SomeUnsignedInt"
doAssert foo(0'u8) == "SomeUnsignedInt"
doAssert foo(0'i8) == "SomeSignedInt" 
doAssert foo(0.int) == "SomeSignedInt"
doAssert foo(0) == "SomeSignedInt"  # ambiguous call error

nitely avatar Sep 17 '25 19:09 nitely

@nitely The substitution would be equivalent if both were a generic match. When you make int the generic constraint you are still matching generically with T. I guess var x = 0 is implicitly int but if you use an int literal as an argument to a uint parameter I don't think that is an implicit type conversion from int -> uint. So if an integer literal's type is dependent on the formal parameter's type then it should have no preference to be either signed or unsigned. Of course, I do understand what you are saying though. I could be wrong.

Graveflo avatar Sep 18 '25 01:09 Graveflo