From f23920fb34c8cda7a9e9614d24ebd82b33583353 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Tue, 7 Jan 2020 14:53:47 -0800 Subject: [PATCH 1/3] typetraits: fix #6454; genericParams; tuple len; tuple type get --- lib/pure/typetraits.nim | 38 ++++++++++++++++++++++++++++++++++ tests/metatype/ttypetraits.nim | 18 ++++++++++++---- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/lib/pure/typetraits.nim b/lib/pure/typetraits.nim index 7a493cb6cbd75..618c11010cc7b 100644 --- a/lib/pure/typetraits.nim +++ b/lib/pure/typetraits.nim @@ -70,6 +70,44 @@ 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 len*(t: tuple): int = + ## Return number of elements of `t` + newLit t.len + +template len*(T: typedesc[tuple]): untyped = + ## Return number of elements of `T` + len(default(T)) + +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 = + ## 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.. Date: Thu, 9 Jan 2020 12:20:32 -0800 Subject: [PATCH 2/3] len => lenTuple --- lib/pure/typetraits.nim | 6 +++--- tests/metatype/ttypetraits.nim | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/pure/typetraits.nim b/lib/pure/typetraits.nim index 618c11010cc7b..eb5c192a526ef 100644 --- a/lib/pure/typetraits.nim +++ b/lib/pure/typetraits.nim @@ -72,13 +72,13 @@ proc distinctBase*(T: typedesc): typedesc {.magic: "TypeTrait".} import std/macros -macro len*(t: tuple): int = +macro lenTuple*(t: tuple): int = ## Return number of elements of `t` newLit t.len -template len*(T: typedesc[tuple]): untyped = +macro lenTuple*(t: typedesc[tuple]): int = ## Return number of elements of `T` - len(default(T)) + newLit t.len template get*(T: typedesc[tuple], i: static int): untyped = ## Return `i`th element of `T` diff --git a/tests/metatype/ttypetraits.nim b/tests/metatype/ttypetraits.nim index 3daee1e33b991..8ae41f1e6e484 100644 --- a/tests/metatype/ttypetraits.nim +++ b/tests/metatype/ttypetraits.nim @@ -98,6 +98,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).len == 2 - static: doAssert (1, ).len == 1 - static: doAssert ().len == 0 + static: doAssert (int, float).lenTuple == 2 + static: doAssert (1, ).lenTuple == 1 + static: doAssert ().lenTuple == 0 From b17794cb68174e9966d7cb835d2238ba75c51d7f Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 9 Jan 2020 18:15:29 -0800 Subject: [PATCH 3/3] fixup --- changelog.md | 4 ++++ lib/pure/typetraits.nim | 16 +++++++++------- lib/system/inclrtl.nim | 2 ++ 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/changelog.md b/changelog.md index aeb6987c47a31..17eedb3a104d9 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 eb5c192a526ef..26cbce4d127ba 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. @@ -72,20 +73,21 @@ proc distinctBase*(T: typedesc): typedesc {.magic: "TypeTrait".} import std/macros -macro lenTuple*(t: tuple): int = +macro lenTuple*(t: tuple): int {.since: (1, 1).} = ## Return number of elements of `t` newLit t.len -macro lenTuple*(t: typedesc[tuple]): int = +macro lenTuple*(t: typedesc[tuple]): int {.since: (1, 1).} = ## Return number of elements of `T` newLit t.len -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]) +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 = +macro genericParams*(T: typedesc): untyped {.since: (1, 1).} = ## return tuple of generic params for generic `T` runnableExamples: type Foo[T1, T2]=object diff --git a/lib/system/inclrtl.nim b/lib/system/inclrtl.nim index 6bff819e677d9..33b8545c42040 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