summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--lib/pure/typetraits.nim34
-rw-r--r--tests/metatype/ttypetraits.nim45
2 files changed, 72 insertions, 7 deletions
diff --git a/lib/pure/typetraits.nim b/lib/pure/typetraits.nim
index 04231db09..0335d5488 100644
--- a/lib/pure/typetraits.nim
+++ b/lib/pure/typetraits.nim
@@ -86,13 +86,13 @@ since (1, 1):
     # Note: `[]` currently gives: `Error: no generic parameters allowed for ...`
     type(default(T)[i])
 
+  type StaticParam*[value] = object
+    ## used to wrap a static value in `genericParams`
+
 import std/macros
 
-macro genericParams*(T: typedesc): untyped {.since: (1, 1).} =
-  ## return tuple of generic params for generic `T`
-  runnableExamples:
-    type Foo[T1, T2]=object
-    doAssert genericParams(Foo[float, string]) is (float, string)
+macro genericParamsImpl(T: typedesc): untyped =
+  # auxiliary macro needed, can't do it directly in `genericParams`
   result = newNimNode(nnkTupleConstr)
   var impl = getTypeImpl(T)
   expectKind(impl, nnkBracketExpr)
@@ -107,11 +107,33 @@ macro genericParams*(T: typedesc): untyped {.since: (1, 1).} =
         continue
       of nnkBracketExpr:
         for i in 1..<impl.len:
-          result.add impl[i]
+          let ai = impl[i]
+          var ret: NimNode
+          case ai.typeKind
+          of ntyStatic:
+            ret = newTree(nnkBracketExpr, @[bindSym"StaticParam", ai])
+          of ntyTypeDesc:
+            ret = ai
+          else:
+            assert false, $(ai.typeKind, ai.kind)
+          result.add ret
         break
       else:
         error "wrong kind: " & $impl.kind
 
+since (1, 1):
+  template genericParams*(T: typedesc): untyped =
+    ## return tuple of generic params for generic `T`
+    runnableExamples:
+      type Foo[T1, T2]=object
+      doAssert genericParams(Foo[float, string]) is (float, string)
+      type Bar[N: static float, T] = object
+      doAssert genericParams(Bar[1.0, string]) is (StaticParam[1.0], string)
+      doAssert genericParams(Bar[1.0, string]).get(0).value == 1.0
+
+    type T2 = T
+    genericParamsImpl(T2)
+
 when isMainModule:
   static:
     doAssert $type(42) == "int"
diff --git a/tests/metatype/ttypetraits.nim b/tests/metatype/ttypetraits.nim
index a6813ed00..7badf8317 100644
--- a/tests/metatype/ttypetraits.nim
+++ b/tests/metatype/ttypetraits.nim
@@ -128,7 +128,6 @@ block: # lenTuple
   doAssert T2.lenTuple == 2
 
 block genericParams:
-
   type Foo[T1, T2]=object
   doAssert genericParams(Foo[float, string]) is (float, string)
   type Foo1 = Foo[float, int]
@@ -140,6 +139,50 @@ block genericParams:
   doAssert (int,).get(0) is int
   doAssert (int, float).get(1) is float
 
+  type Bar[N: static int, T] = object
+  type Bar3 = Bar[3, float]
+  doAssert genericParams(Bar3) is (StaticParam[3], float)
+  doAssert genericParams(Bar3).get(0) is StaticParam
+  doAssert genericParams(Bar3).get(0).value == 3
+  doAssert genericParams(Bar[3, float]).get(0).value == 3
+
+  type
+    VectorElementType = SomeNumber | bool
+    Vec[N: static[int], T: VectorElementType] = object
+      arr: array[N, T]
+    Vec4[T: VectorElementType] = Vec[4,T]
+    Vec4f = Vec4[float32]
+
+    MyTupleType = (int,float,string)
+    MyGenericTuple[T] = (T,int,float)
+    MyGenericAlias = MyGenericTuple[string]
+    MyGenericTuple2[T,U] = (T,U,string)
+    MyGenericTuple2Alias[T] =  MyGenericTuple2[T,int]
+    MyGenericTuple2Alias2 =   MyGenericTuple2Alias[float]
+
+  doAssert genericParams(MyGenericAlias) is (string,)
+  doAssert genericHead(MyGenericAlias) is MyGenericTuple
+  doAssert genericParams(MyGenericTuple2Alias2) is (float,)
+  doAssert genericParams(MyGenericTuple2[float, int]) is (float, int)
+  doAssert genericParams(MyGenericAlias) is (string,)
+  doAssert genericParams(Vec4f) is (float32,)
+  doAssert genericParams(Vec[4, bool]) is (StaticParam[4], bool)
+
+  block:
+    type Foo[T1, T2]=object
+    doAssert genericParams(Foo[float, string]) is (float, string)
+    type Bar[N: static float, T] = object
+    doAssert genericParams(Bar[1.0, string]) is (StaticParam[1.0], string)
+    type Bar2 = Bar[2.0, string]
+    doAssert genericParams(Bar2) is (StaticParam[2.0], string)
+    type Bar3 = Bar[1.0 + 2.0, string]
+    doAssert genericParams(Bar3) is (StaticParam[3.0], string)
+
+    const F = 5.0
+    type Bar4 = Bar[F, string]
+    doAssert genericParams(Bar4) is (StaticParam[5.0], string)
+    doAssert genericParams(Bar[F, string]) is (StaticParam[5.0], string)
+
 ##############################################
 # bug 13095