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.
This commit is contained in:
metagn
2024-10-07 12:40:44 +03:00
committed by GitHub
parent 911cef1621
commit c73eedfe6e
3 changed files with 39 additions and 3 deletions

View File

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

View File

@@ -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
View 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]