Skip to content

Commit

Permalink
typetraits: fix nim-lang#6454; genericParams; tuple len; tuple type get
Browse files Browse the repository at this point in the history
  • Loading branch information
timotheecour committed Jan 7, 2020
1 parent 8bcc7e8 commit e2de229
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 0 deletions.
38 changes: 38 additions & 0 deletions lib/pure/typetraits.nim
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,44 @@ proc isNamedTuple*(T: typedesc): bool =
# see https://github.com/nim-lang/Nim/issues/8861#issue-356631191
return false

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..<impl.len:
result.add impl[i]
break
else:
error "wrong kind: " & $impl.kind

when isMainModule:
static:
Expand Down
14 changes: 14 additions & 0 deletions tests/metatype/ttypetraits.nim
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,17 @@ 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 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).len == 2
static: doAssert (1, ).len == 1
static: doAssert ().len == 0

0 comments on commit e2de229

Please sign in to comment.