diff options
author | Timothee Cour <timothee.cour2@gmail.com> | 2020-01-09 23:51:37 -0800 |
---|---|---|
committer | Andreas Rumpf <rumpf_a@web.de> | 2020-01-10 08:51:37 +0100 |
commit | 4cd86c08427205d2e26510a07a3c6980c14e1608 (patch) | |
tree | efab63d6385cfe3f9368f390ececb06793eb30b9 | |
parent | fcd2f305ad5ad2af37284caf7b33907afb8ad834 (diff) | |
download | Nim-4cd86c08427205d2e26510a07a3c6980c14e1608.tar.gz |
typetraits: fixes #6454; genericParams; added lenTuple; added tuple type get (#13064)
-rw-r--r-- | changelog.md | 4 | ||||
-rw-r--r-- | lib/pure/typetraits.nim | 40 | ||||
-rw-r--r-- | lib/system/inclrtl.nim | 2 | ||||
-rw-r--r-- | tests/metatype/ttypetraits.nim | 18 |
4 files changed, 60 insertions, 4 deletions
diff --git a/changelog.md b/changelog.md index aeb6987c4..17eedb3a1 100644 --- a/changelog.md +++ b/changelog.md @@ -47,6 +47,10 @@ - Added `sugar.capture` for capturing some local loop variables when creating a closure. This is an enhanced version of `closureScope`. +- Added `typetraits.lenTuple` to get number of elements of a tuple/type tuple, + and `typetraits.get` to get the ith element of a type tuple. +- Added `typetraits.genericParams` to return a tuple of generic params from a generic instantiation + ## Library changes - `asyncdispatch.drain` now properly takes into account `selector.hasPendingOperations` diff --git a/lib/pure/typetraits.nim b/lib/pure/typetraits.nim index 7a493cb6c..26cbce4d1 100644 --- a/lib/pure/typetraits.nim +++ b/lib/pure/typetraits.nim @@ -14,6 +14,7 @@ export system.`$` # for backward compatibility +include "system/inclrtl" proc name*(t: typedesc): string {.magic: "TypeTrait".} ## Returns the name of the given type. @@ -70,6 +71,45 @@ 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).} = + ## Return number of elements of `T` + newLit t.len + +when (NimMajor, NimMinor) >= (1, 1): + template get*(T: typedesc[tuple], i: static int): untyped = + ## Return `i`th element of `T` + # Note: `[]` currently gives: `Error: no generic parameters allowed for ...` + type(default(T)[i]) + +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) + result = newNimNode(nnkTupleConstr) + var impl = getTypeImpl(T) + expectKind(impl, nnkBracketExpr) + impl = impl[1] + while true: + case impl.kind + of nnkSym: + impl = impl.getImpl + continue + of nnkTypeDef: + impl = impl[2] + continue + of nnkBracketExpr: + for i in 1..<impl.len: + result.add impl[i] + break + else: + error "wrong kind: " & $impl.kind when isMainModule: static: diff --git a/lib/system/inclrtl.nim b/lib/system/inclrtl.nim index 6bff819e6..33b8545c4 100644 --- a/lib/system/inclrtl.nim +++ b/lib/system/inclrtl.nim @@ -50,5 +50,7 @@ else: {.pragma: benign, gcsafe.} template since(version, body: untyped) {.dirty.} = + ## limitation: can't be used to annotate a template (eg typetraits.get), would + ## error: cannot attach a custom pragma. when version <= (NimMajor, NimMinor): body diff --git a/tests/metatype/ttypetraits.nim b/tests/metatype/ttypetraits.nim index 3215a21b0..8ae41f1e6 100644 --- a/tests/metatype/ttypetraits.nim +++ b/tests/metatype/ttypetraits.nim @@ -44,9 +44,6 @@ block: # typeToString doAssert (tuple[a: C2b[MyInt, C4[cstring]], b: cint, c: float]).name3 == "tuple[a: C2b{C}[MyInt{int}, C4[cstring]], b: cint{int32}, c: float]" - -#---------------------------------------------------- - block distinctBase: block: type @@ -90,4 +87,17 @@ block distinctBase: doAssert($distinctBase(typeof(b2)) == "string") doAssert($distinctBase(typeof(c2)) == "int") - +block genericParams: + type Foo[T1, T2]=object + doAssert genericParams(Foo[float, string]) is (float, string) + type Foo1 = Foo[float, int] + doAssert genericParams(Foo1) is (float, int) + type Foo2 = Foo[float, Foo1] + doAssert genericParams(Foo2) is (float, Foo[float, int]) + doAssert genericParams(Foo2) is (float, Foo1) + 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 |