mirror of
https://github.com/nim-lang/Nim.git
synced 2026-02-19 01:18:32 +00:00
give int literals matched type on generic match (#24234)
fixes #24233 Integer literals with type `int` can match `int64` with a generic match. Normally this would generate an conversion via `isFromIntLit`, but when it matches with a generic match (`isGeneric`) the node is left alone and continues to have type `int` (related to #4858, but separate; since `isFromIntLit > isGeneric` it doesn't propagate). This did not cause problems on the C backend up to this point because either the compiler generated a cast when generating the C code or it was implicitly casted in the C code itself. On the JS backend however, we need to generate `int64` and `int` values differently, so we copy the integer literal and give it the matched type now instead. This is somewhat risky even if CI passes but it's required to make the times module work without [this workaround](7dfadb8b4e/lib/pure/times.nim (L219-L238)) on `--jsbigint64:on` (the default). CI exposed an issue: When matching an int literal to a generic parameter in a generic instantiation, the literal is only treated like a value if it has `int literal` type, but if it has the type `int`, it gets transformed into literally the type `int` (#12664, #13906), which breaks the tests t14193 and t12938. To deal with this, we don't give it the type `int` if we are in a generic instantiation and preserve the `int literal` type. (cherry picked from commitc73eedfe6e)
This commit is contained in:
@@ -2523,9 +2523,15 @@ proc paramTypesMatchAux(m: var TCandidate, f, a: PType,
|
||||
result = arg
|
||||
elif skipTypes(arg.typ, abstractVar-{tyTypeDesc}).kind == tyTuple or cmpInheritancePenalty(oldInheritancePenalty, m.inheritancePenalty) > 0:
|
||||
result = implicitConv(nkHiddenSubConv, f, arg, m, c)
|
||||
elif arg.typ.isEmptyContainer:
|
||||
elif arg.typ.isEmptyContainer or
|
||||
# XXX `and not m.isNoCall` is a workaround
|
||||
# passing an int to generic types converts it to the type `int`
|
||||
# but this isn't done for int literal types, so we preserve the type
|
||||
# i.e. works: `type Foo[T] = array[T, int]; var x: Foo[3]` (see t12938, t14193)
|
||||
# doesn't work: `proc foo[T](): array[T, int] = ...; foo[3]()` (see #23204)
|
||||
(arg.typ.isIntLit and not m.isNoCall):
|
||||
result = arg.copyTree
|
||||
result.typ = getInstantiatedType(c, arg, m, f)
|
||||
result.typ = getInstantiatedType(c, arg, m, f).skipTypes({tySink})
|
||||
else:
|
||||
result = arg
|
||||
of isBothMetaConvertible:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
type
|
||||
Task*[N: int] = object
|
||||
Task*[N: int] = object # XXX this shouldn't work, should be `static int`
|
||||
env*: array[N, byte]
|
||||
|
||||
var task14193: Task[20]
|
||||
|
||||
30
tests/js/tint64litgen.nim
Normal file
30
tests/js/tint64litgen.nim
Normal file
@@ -0,0 +1,30 @@
|
||||
discard """
|
||||
matrix: "--jsbigint64:on; --jsbigint64:off"
|
||||
"""
|
||||
|
||||
block: # issue #24233
|
||||
proc foo[T: SomeInteger](a, b: T) =
|
||||
let x = a div b
|
||||
|
||||
const bar = 123
|
||||
|
||||
let x: int64 = 456
|
||||
foo(x, bar)
|
||||
|
||||
block: # issue #24233, modified
|
||||
proc f(a, b: int64) =
|
||||
let x = a div b
|
||||
|
||||
proc foo[T: SomeInteger](a, b: T) =
|
||||
f(a, b)
|
||||
|
||||
const bar = 123
|
||||
|
||||
let x: int64 = 456
|
||||
foo(x, bar)
|
||||
|
||||
block:
|
||||
proc foo[I: Ordinal](x: I) = discard
|
||||
foo(123)
|
||||
let x = [0, 1, 2]
|
||||
discard x[0]
|
||||
Reference in New Issue
Block a user