Skip to content

Commit 1c669ab

Browse files
committed
add extractGeneric: extractGeneric(Foo2[float, string], 0) is float
1 parent bbc404d commit 1c669ab

File tree

3 files changed

+54
-1
lines changed

3 files changed

+54
-1
lines changed

doc/manual.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4351,14 +4351,15 @@ type classes are called `bind many`:idx: types.
43514351

43524352
Procs written with the implicitly generic style will often need to refer to the
43534353
type parameters of the matched generic type. They can be easily accessed using
4354-
the dot syntax:
4354+
``sugar.extractGeneric`` or the dot syntax:
43554355

43564356
.. code-block:: nim
43574357
type Matrix[T, Rows, Columns] = object
43584358
...
43594359
43604360
proc `[]`(m: Matrix, row, col: int): Matrix.T =
43614361
m.data[col * high(Matrix.Columns) + row]
4362+
# we could've also used ``extractGeneric(Matrix, 0)``
43624363
43634364
Alternatively, the `type` operator can be used over the proc params for similar
43644365
effect when anonymous or distinct type classes are used.

lib/pure/sugar.nim

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,3 +198,34 @@ macro dump*(x: typed): untyped =
198198
let r = quote do:
199199
debugEcho `s`, " = ", `x`
200200
return r
201+
202+
macro extractGeneric*(T: typedesc, index:static[int]): untyped =
203+
## extract generic type numbered ``index`` used to construct ``T``. Note:
204+
## ``-1`` returns ``Foo`` in ``Foo[T]``
205+
runnableExamples:
206+
type Foo[T1, T2]=object
207+
doAssert extractGeneric(Foo[float, string], 0) is float
208+
doAssert extractGeneric(Foo[float, string], 1) is string
209+
doAssert extractGeneric(Foo[float, string], -1) is Foo
210+
211+
var impl = getTypeImpl(T)
212+
expectKind(impl, nnkBracketExpr)
213+
impl = impl[1]
214+
while true:
215+
case impl.kind
216+
of nnkSym:
217+
impl = impl.getImpl
218+
continue
219+
of nnkTypeDef:
220+
impl = impl[2]
221+
continue
222+
of nnkBracketExpr:
223+
if index == -1:
224+
impl=impl[0] #return `Foo` in `Foo[T]`
225+
else:
226+
impl=impl[1+index] #return `T` in `Foo[T]` (when index = 0)
227+
break
228+
else:
229+
error "internal error: impl.kind: " & $impl.kind
230+
impl
231+

tests/stdlib/tsugar.nim

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
discard """
2+
file: "tsugar.nim"
3+
output: ""
4+
"""
5+
import sugar
6+
import macros
7+
8+
block extractGeneric:
9+
type Foo[T1, T2]=object
10+
type Foo2=Foo[float, string]
11+
doAssert extractGeneric(Foo[float, string], 1) is string
12+
doAssert extractGeneric(Foo2, 1) is string
13+
# workaround for seq[int].T not working,
14+
# see https://github.com/nim-lang/Nim/issues/8433
15+
doAssert extractGeneric(seq[int], 0) is int
16+
doAssert extractGeneric(seq[seq[string]], 0) is seq[string]
17+
doAssert: not compiles(extractGeneric(seq[int], 1))
18+
doAssert extractGeneric(seq[int], -1) is seq
19+
20+
type Foo3[T] = T
21+
doAssert extractGeneric(Foo3[int], 0) is int

0 commit comments

Comments
 (0)