From c73eedfe6ef39cfe74ae3071be09e9cb018a3d66 Mon Sep 17 00:00:00 2001 From: metagn Date: Mon, 7 Oct 2024 12:40:44 +0300 Subject: [PATCH] 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](https://github.com/nim-lang/Nim/blob/7dfadb8b4e95d09981fbeb01d85b12f23946c3e7/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. --- compiler/sigmatch.nim | 10 ++++++++-- tests/generics/t14193.nim | 2 +- tests/js/tint64litgen.nim | 30 ++++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 tests/js/tint64litgen.nim diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index e50b50331c..9643f37655 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -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: diff --git a/tests/generics/t14193.nim b/tests/generics/t14193.nim index 213b1a8e6e..8dab666e42 100644 --- a/tests/generics/t14193.nim +++ b/tests/generics/t14193.nim @@ -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] diff --git a/tests/js/tint64litgen.nim b/tests/js/tint64litgen.nim new file mode 100644 index 0000000000..240bbc6a02 --- /dev/null +++ b/tests/js/tint64litgen.nim @@ -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]