summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorTimothee Cour <timothee.cour2@gmail.com>2020-02-19 02:07:18 -0800
committerGitHub <noreply@github.com>2020-02-19 11:07:17 +0100
commit273a93581f851d2d16d6891d7dd1d7d9edfbb4ef (patch)
tree1e9e772bb7c839e2469bdd6aed122dca5050d2c8
parentd1f9f11245a29f00bfa8cd86f9b4eb4ab0963a15 (diff)
downloadNim-273a93581f851d2d16d6891d7dd1d7d9edfbb4ef.tar.gz
fix incorrect lenTuple implementation (#13423)
-rw-r--r--compiler/semmagic.nim4
-rw-r--r--lib/pure/typetraits.nim15
-rw-r--r--tests/metatype/ttypetraits.nim40
3 files changed, 48 insertions, 11 deletions
diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim
index 0571032dc..1671a8a26 100644
--- a/compiler/semmagic.nim
+++ b/compiler/semmagic.nim
@@ -187,6 +187,10 @@ proc evalTypeTrait(c: PContext; traitCall: PNode, operand: PType, context: PSym)
     var operand = operand.skipTypes({tyGenericInst})
     let cond = operand.kind == tyTuple and operand.n != nil
     result = newIntNodeT(toInt128(ord(cond)), traitCall, c.graph)
+  of "lenTuple":
+    var operand = operand.skipTypes({tyGenericInst})
+    assert operand.kind == tyTuple, $operand.kind
+    result = newIntNodeT(toInt128(operand.len), traitCall, c.graph)
   of "distinctBase":
     var arg = operand.skipTypes({tyGenericInst})
     if arg.kind == tyDistinct:
diff --git a/lib/pure/typetraits.nim b/lib/pure/typetraits.nim
index fd729b59e..04231db09 100644
--- a/lib/pure/typetraits.nim
+++ b/lib/pure/typetraits.nim
@@ -71,15 +71,14 @@ proc distinctBase*(T: typedesc): typedesc {.magic: "TypeTrait".}
   ## Returns base type for distinct types, works only for distinct types.
   ## compile time error otherwise
 
-import std/macros
-
-macro lenTuple*(t: tuple): int {.since: (1, 1).} =
-  ## Return number of elements of `t`
-  newLit t.len
 
-macro lenTuple*(t: typedesc[tuple]): int {.since: (1, 1).} =
+proc lenTuple*(T: typedesc[tuple]): int {.magic: "TypeTrait", since: (1, 1).}
   ## Return number of elements of `T`
-  newLit t.len
+
+since (1, 1):
+  template lenTuple*(t: tuple): int =
+    ## Return number of elements of `t`
+    lenTuple(type(t))
 
 since (1, 1):
   template get*(T: typedesc[tuple], i: static int): untyped =
@@ -87,6 +86,8 @@ since (1, 1):
     # Note: `[]` currently gives: `Error: no generic parameters allowed for ...`
     type(default(T)[i])
 
+import std/macros
+
 macro genericParams*(T: typedesc): untyped {.since: (1, 1).} =
   ## return tuple of generic params for generic `T`
   runnableExamples:
diff --git a/tests/metatype/ttypetraits.nim b/tests/metatype/ttypetraits.nim
index 218ffadc2..a6813ed00 100644
--- a/tests/metatype/ttypetraits.nim
+++ b/tests/metatype/ttypetraits.nim
@@ -92,7 +92,43 @@ block distinctBase:
         doAssert($distinctBase(typeof(b2)) == "string")
         doAssert($distinctBase(typeof(c2)) == "int")
 
+block: # lenTuple
+  doAssert not compiles(lenTuple(int))
+
+  type
+    MyTupleType = (int,float,string)
+
+  static: doAssert MyTupleType.lenTuple == 3
+
+  type
+    MyGenericTuple[T] = (T,int,float)
+    MyGenericAlias = MyGenericTuple[string]
+  static: doAssert MyGenericAlias.lenTuple == 3
+
+  type
+    MyGenericTuple2[T,U] = (T,U,string)
+    MyGenericTuple2Alias[T] =  MyGenericTuple2[T,int]
+
+    MyGenericTuple2Alias2 =   MyGenericTuple2Alias[float]
+  static: doAssert MyGenericTuple2Alias2.lenTuple == 3
+
+  static: doAssert (int, float).lenTuple == 2
+  static: doAssert (1, ).lenTuple == 1
+  static: doAssert ().lenTuple == 0
+
+  let x = (1,2,)
+  doAssert x.lenTuple == 2
+  doAssert ().lenTuple == 0
+  doAssert (1,).lenTuple == 1
+  doAssert (int,).lenTuple == 1
+  doAssert type(x).lenTuple == 2
+  doAssert type(x).default.lenTuple == 2
+  type T1 = (int,float)
+  type T2 = T1
+  doAssert T2.lenTuple == 2
+
 block genericParams:
+
   type Foo[T1, T2]=object
   doAssert genericParams(Foo[float, string]) is (float, string)
   type Foo1 = Foo[float, int]
@@ -103,10 +139,6 @@ block genericParams:
   doAssert genericParams(Foo2).get(1) is Foo1
   doAssert (int,).get(0) is int
   doAssert (int, float).get(1) is float
-  static: doAssert (int, float).lenTuple == 2
-  static: doAssert (1, ).lenTuple == 1
-  static: doAssert ().lenTuple == 0
-
 
 ##############################################
 # bug 13095