mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 08:54:53 +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.
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