diff options
author | metagn <metagngn@gmail.com> | 2023-09-05 11:30:13 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-09-05 10:30:13 +0200 |
commit | 6000cc8c0f5c71fd0495172b5680ab6b1945428c (patch) | |
tree | 68d4c09822b7318a75a974eb07beaf4841920ab5 /tests | |
parent | 8f7aedb3d1941650e6650c07aa4bcf6a7dee0b90 (diff) | |
download | Nim-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.nim | 39 |
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] |