summary refs log tree commit diff stats
path: root/lib/pure
diff options
context:
space:
mode:
authoralaviss <leorize+oss@disroot.org>2020-06-30 13:25:53 +0000
committerGitHub <noreply@github.com>2020-06-30 15:25:53 +0200
commit56b3d422b014b42c6367fa56916cfd9851884506 (patch)
treebbd32fac6a407c47bea5552a63f3904ad58effe6 /lib/pure
parent36fa79a5242d2e39a83083cd66cf3af9f8931f3b (diff)
downloadNim-56b3d422b014b42c6367fa56916cfd9851884506.tar.gz
typetraits: features and fixes (#14791)
* typetraits: add support for nnkTypeOfExpr

* typetraits: don't wrap typedesc symbols in StaticParam

* typetraits: add nested generics support to genericParams

* typetraits: make genericParams understand array[I, T] whackiness

Also moved tests to ttypetraits

* typetraits: clarify comment on genericParams
Diffstat (limited to 'lib/pure')
-rw-r--r--lib/pure/typetraits.nim42
1 files changed, 39 insertions, 3 deletions
diff --git a/lib/pure/typetraits.nim b/lib/pure/typetraits.nim
index c289f6c84..0e23077ac 100644
--- a/lib/pure/typetraits.nim
+++ b/lib/pure/typetraits.nim
@@ -121,6 +121,9 @@ macro genericParamsImpl(T: typedesc): untyped =
       of nnkTypeDef:
         impl = impl[2]
         continue
+      of nnkTypeOfExpr:
+        impl = getTypeInst(impl[0])
+        continue
       of nnkBracketExpr:
         for i in 1..<impl.len:
           let ai = impl[i]
@@ -130,8 +133,32 @@ macro genericParamsImpl(T: typedesc): untyped =
             ret = ai
           of ntyStatic: doAssert false
           else:
-            since (1, 1):
-              ret = newTree(nnkBracketExpr, @[bindSym"StaticParam", ai])
+            # getType from a resolved symbol might return a typedesc symbol.
+            # If so, use it directly instead of wrapping it in StaticParam.
+            if (ai.kind == nnkSym and ai.symKind == nskType) or
+               (ai.kind == nnkBracketExpr and ai[0].kind == nnkSym and
+                ai[0].symKind == nskType):
+              ret = ai
+            elif ai.kind == nnkInfix and ai[0].kind == nnkIdent and
+                 ai[0].strVal == "..":
+              # For built-in array types, the "2" is translated to "0..1" then
+              # automagically translated to "range[0..1]". However this is not
+              # reflected in the AST, thus requiring manual transformation here.
+              #
+              # We will also be losing some context here:
+              #   var a: array[10, int]
+              # will be translated to:
+              #   var a: array[0..9, int]
+              # after typecheck. This means that we can't get the exact
+              # definition as typed by the user, which will cause confusion for
+              # users expecting:
+              #   genericParams(typeof(a)) is (StaticParam(10), int)
+              # to be true while in fact the result will be:
+              #   genericParams(typeof(a)) is (range[0..9], int)
+              ret = newTree(nnkBracketExpr, @[bindSym"range", ai])
+            else:
+              since (1, 1):
+                ret = newTree(nnkBracketExpr, @[bindSym"StaticParam", ai])
           result.add ret
         break
       else:
@@ -141,11 +168,20 @@ since (1, 1):
   template genericParams*(T: typedesc): untyped =
     ## return tuple of generic params for generic `T`
     runnableExamples:
-      type Foo[T1, T2]=object
+      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
+      doAssert genericParams(seq[Bar[2.0, string]]).get(0) is Bar[2.0, string]
+      var s: seq[Bar[3.0, string]]
+      doAssert genericParams(typeof(s)) is (Bar[3.0, string],)
+
+      # NOTE: For the builtin array type, the index generic param will
+      #       **always** become a range type after it's bound to a variable.
+      doAssert genericParams(array[10, int]) is (StaticParam[10], int)
+      var a: array[10, int]
+      doAssert genericParams(typeof(a)) is (range[0..9], int)
 
     type T2 = T
     genericParamsImpl(T2)