summary refs log tree commit diff stats
path: root/tests
diff options
context:
space:
mode:
authormetagn <metagngn@gmail.com>2023-09-05 11:30:13 +0300
committerGitHub <noreply@github.com>2023-09-05 10:30:13 +0200
commit6000cc8c0f5c71fd0495172b5680ab6b1945428c (patch)
tree68d4c09822b7318a75a974eb07beaf4841920ab5 /tests
parent8f7aedb3d1941650e6650c07aa4bcf6a7dee0b90 (diff)
downloadNim-6000cc8c0f5c71fd0495172b5680ab6b1945428c.tar.gz
fix sym of created generic instantiation type (#22642)
fixes #22639

A `tyGenericInst` has its last son as the instantiated body of the
original generic type. However this type keeps its original `sym` field
from the original generic types, which means the sym's type is
uninstantiated. This causes problems in the implementation of `getType`,
where it uses the `sym` fields of types to represent them in AST, the
relevant example for the issue being
[here](https://github.com/nim-lang/Nim/blob/d13aab50cf465a7f2edf9c37a4fa30e128892e72/compiler/vmdeps.nim#L191)
called from
[here](https://github.com/nim-lang/Nim/blob/d13aab50cf465a7f2edf9c37a4fa30e128892e72/compiler/vmdeps.nim#L143).

To fix this, create a new symbol from the original symbol for the
instantiated body during the creation of `tyGenericInst`s with the
appropriate type. Normally `replaceTypeVarsS` would be used for this,
but here it seems to cause some recursion issue (immediately gives an
error like "cannot instantiate HSlice[T, U]"), so we directly set the
symbol's type to the instantiated type.

Avoiding recursion means we also cannot use `replaceTypeVarsN` for the
symbol AST, and the symbol not having any AST crashes the implementation
of `getType` again
[here](https://github.com/nim-lang/Nim/blob/d13aab50cf465a7f2edf9c37a4fa30e128892e72/compiler/vmdeps.nim#L167),
so the symbol AST is set to the original generic type AST for now which
is what it was before anyway.

Not sure about this because not sure why the recursion issue is
happening, putting it at the end of the proc doesn't help either. Also
not sure if the `cl.owner != nil and s.owner != cl.owner` condition from
`replaceTypeVarsS` is relevant here. This might also break some code if
it depended on the original generic type symbol being given.
Diffstat (limited to 'tests')
-rw-r--r--tests/generics/timpl_ast.nim39
1 files changed, 35 insertions, 4 deletions
diff --git a/tests/generics/timpl_ast.nim b/tests/generics/timpl_ast.nim
index 69a59e24d..97fe128cd 100644
--- a/tests/generics/timpl_ast.nim
+++ b/tests/generics/timpl_ast.nim
@@ -1,7 +1,3 @@
-discard """
-  action: compile
-"""
-
 import std/macros
 import std/assertions
 
@@ -47,3 +43,38 @@ block: # issues #9899, ##14708
     macro parse(s: static string) =
       result = parseStmt(s)
     parse("type " & implRepr(Option))
+
+block: # issue #22639
+  type
+    Spectrum[N: static int] = object
+      data: array[N, float]
+    AngleInterpolator = object
+      data: seq[Spectrum[60]]
+  proc initInterpolator(num: int): AngleInterpolator =
+    result = AngleInterpolator()
+    for i in 0 ..< num:
+      result.data.add Spectrum[60]()
+  macro genCompatibleTuple(t: typed): untyped =
+    let typ = t.getType[1].getTypeImpl[2]
+    result = nnkTupleTy.newTree()
+    for i, ch in typ: # is `nnkObjectTy`
+      result.add nnkIdentDefs.newTree(ident(ch[0].strVal), # ch is `nnkIdentDefs`
+                                      ch[1],
+                                      newEmptyNode())
+  proc fullSize[T: object | tuple](x: T): int =
+    var tmp: genCompatibleTuple(T)
+    result = 0
+    for field, val in fieldPairs(x):
+      result += sizeof(val)
+    doAssert result == sizeof(tmp)
+
+  let reflectivity = initInterpolator(1)
+  for el in reflectivity.data:
+    doAssert fullSize(el) == sizeof(el)
+  doAssert fullSize(reflectivity.data[0]) == sizeof(reflectivity.data[0])
+  doAssert genCompatibleTuple(Spectrum[60]) is tuple[data: array[60, float]]
+  doAssert genCompatibleTuple(Spectrum[120]) is tuple[data: array[120, float]]
+  type Foo[T] = object
+    data: T
+  doAssert genCompatibleTuple(Foo[int]) is tuple[data: int]
+  doAssert genCompatibleTuple(Foo[float]) is tuple[data: float]