Fix #5962
During the instantiation of a generic type A, some other generic type B may be instantiated multiple times with different parameters. We can think about each instantiation as a function call that should temporary bind the parameter names to concrete types. The problem with the existing implementation in semtypinst was that it was performing this binding within a shared global table. In this sense, it was executing the code as a programming language featuring only global variables. In such a language, re-entrant functions cannot be defined properly and hence this was leading to problems with similar types. The solution is simple - just like we need to introduce stack frames to handle re-entrant functions, we introduce a stack of type bindings that are pushed and popped during the generic instantiations.
This commit is contained in:
parent
cd02561368
commit
f0999de9dc
3 changed files with 133 additions and 16 deletions
81
tests/generics/treentranttypes.nim
Normal file
81
tests/generics/treentranttypes.nim
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
discard """
|
||||
output: '''
|
||||
(Field0: 10, Field1: (Field0: test, Field1: 1.2))
|
||||
3x3 Matrix [[0.0, 2.0, 3.0], [2.0, 0.0, 5.0], [2.0, 0.0, 5.0]]
|
||||
|
||||
2x3 Matrix [[0.0, 2.0, 3.0], [2.0, 0.0, 5.0]]
|
||||
|
||||
2x3 Literal [[0.0, 2.0, 3.0], [2.0, 0.0, 5.0]]
|
||||
|
||||
2x3 Matrix [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]
|
||||
|
||||
2x2 ArrayArray[[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]
|
||||
|
||||
2x3 ArrayVector[[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]
|
||||
|
||||
2x3 VectorVector [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]
|
||||
|
||||
2x3 VectorArray [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]
|
||||
'''
|
||||
"""
|
||||
|
||||
# https://github.com/nim-lang/Nim/issues/5962
|
||||
|
||||
type
|
||||
ArrayLike[A, B] = (A, B)
|
||||
VectorLike*[SIZE, T] = ArrayLike[SIZE, T]
|
||||
MatrixLike*[M, N, T] = VectorLike[M, VectorLike[N, T]]
|
||||
|
||||
proc tupleTest =
|
||||
let m: MatrixLike[int, string, float] = (10, ("test", 1.2))
|
||||
echo m
|
||||
|
||||
tupleTest()
|
||||
|
||||
type
|
||||
Vector*[K: static[int], T] =
|
||||
array[K, T]
|
||||
|
||||
Matrix*[M: static[int]; N: static[int]; T] =
|
||||
Vector[M, Vector[N, T]]
|
||||
|
||||
proc arrayTest =
|
||||
# every kind of square matrix works just fine
|
||||
let mat_good: Matrix[3, 3, float] = [[0.0, 2.0, 3.0],
|
||||
[2.0, 0.0, 5.0],
|
||||
[2.0, 0.0, 5.0]]
|
||||
echo "3x3 Matrix ", repr(mat_good)
|
||||
|
||||
# this does not work with explicit type signature (the matrix seems to always think it is NxN instead)
|
||||
let mat_fail: Matrix[2, 3, float] = [[0.0, 2.0, 3.0],
|
||||
[2.0, 0.0, 5.0]]
|
||||
echo "2x3 Matrix ", repr(mat_fail)
|
||||
|
||||
# this literal seems to work just fine
|
||||
let mat_also_good = [[0.0, 2.0, 3.0],
|
||||
[2.0, 0.0, 5.0]]
|
||||
|
||||
echo "2x3 Literal ", repr(mat_also_good)
|
||||
|
||||
# but making a named type out of this leads to pretty nasty runtime behavior
|
||||
var mat_fail_runtime: Matrix[2, 3, float]
|
||||
echo "2x3 Matrix ", repr(mat_fail_runtime)
|
||||
|
||||
# cutting out the matrix type middle man seems to solve our problem
|
||||
var mat_ok_runtime: array[2, array[3, float]]
|
||||
echo "2x2 ArrayArray", repr(mat_ok_runtime)
|
||||
|
||||
# this is fine too
|
||||
var mat_ok_runtime_2: array[2, Vector[3, float]]
|
||||
echo "2x3 ArrayVector", repr(mat_ok_runtime_2)
|
||||
|
||||
# here we are in trouble again
|
||||
var mat_fail_runtime_2: Vector[2, Vector[3, float]]
|
||||
echo "2x3 VectorVector ", repr(mat_fail_runtime_2)
|
||||
|
||||
# and here we are fine again
|
||||
var mat_ok_runtime_3: Vector[2, array[3, float]]
|
||||
echo "2x3 VectorArray ", repr(mat_ok_runtime_3)
|
||||
|
||||
arrayTest()
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue