From eaf691f6ce3dc04022a6565fc547874dc1ac7106 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Fri, 3 Aug 2018 19:08:44 -0700 Subject: [PATCH 1/2] add extractGeneric: extractGeneric(Foo2[float, string], 0) is float --- doc/manual.rst | 3 ++- lib/pure/sugar.nim | 30 ++++++++++++++++++++++++++++++ tests/stdlib/tsugar.nim | 16 ++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/doc/manual.rst b/doc/manual.rst index a646b79632356..177c46e4ffd77 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -4437,7 +4437,7 @@ type classes are called `bind many`:idx: types. Procs written with the implicitly generic style will often need to refer to the type parameters of the matched generic type. They can be easily accessed using -the dot syntax: +``sugar.extractGeneric`` or the dot syntax: .. code-block:: nim type Matrix[T, Rows, Columns] = object @@ -4445,6 +4445,7 @@ the dot syntax: proc `[]`(m: Matrix, row, col: int): Matrix.T = m.data[col * high(Matrix.Columns) + row] + # we could've also used ``extractGeneric(Matrix, 0)`` Alternatively, the `type` operator can be used over the proc params for similar effect when anonymous or distinct type classes are used. diff --git a/lib/pure/sugar.nim b/lib/pure/sugar.nim index 53c31e8c90640..9586066e7e3e6 100644 --- a/lib/pure/sugar.nim +++ b/lib/pure/sugar.nim @@ -237,3 +237,33 @@ macro distinctBase*(T: typedesc): untyped = while typeSym.typeKind == ntyDistinct: typeSym = getTypeImpl(typeSym)[0] typeSym.freshIdentNodes + +macro extractGeneric*(T: typedesc, index:static[int]): untyped = + ## extract generic type numbered ``index`` used to construct ``T``. Note: + ## ``-1`` returns ``Foo`` in ``Foo[T]`` + runnableExamples: + type Foo[T1, T2]=object + doAssert extractGeneric(Foo[float, string], 0) is float + doAssert extractGeneric(Foo[float, string], 1) is string + doAssert extractGeneric(Foo[float, string], -1) is Foo + + 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: + if index == -1: + impl=impl[0] #return `Foo` in `Foo[T]` + else: + impl=impl[1+index] #return `T` in `Foo[T]` (when index = 0) + break + else: + error "internal error: impl.kind: " & $impl.kind + impl diff --git a/tests/stdlib/tsugar.nim b/tests/stdlib/tsugar.nim index a870bf6fed27a..f8935cc33c8b3 100644 --- a/tests/stdlib/tsugar.nim +++ b/tests/stdlib/tsugar.nim @@ -2,6 +2,7 @@ discard """ file: "tsugar.nim" output: "" """ + import sugar import macros @@ -27,3 +28,18 @@ block distinctBase: Uint[bits: static[int]] = distinct uintImpl(bits) doAssert Uint[128].distinctBase is UintImpl[uint64] + +block extractGeneric: + type Foo[T1, T2]=object + type Foo2=Foo[float, string] + doAssert extractGeneric(Foo[float, string], 1) is string + doAssert extractGeneric(Foo2, 1) is string + # workaround for seq[int].T not working, + # see https://github.com/nim-lang/Nim/issues/8433 + doAssert extractGeneric(seq[int], 0) is int + doAssert extractGeneric(seq[seq[string]], 0) is seq[string] + doAssert: not compiles(extractGeneric(seq[int], 1)) + doAssert extractGeneric(seq[int], -1) is seq + + type Foo3[T] = T + doAssert extractGeneric(Foo3[int], 0) is int From 3ed1b6e6c7bdeca3177e443e17e06ae8cd60a112 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 3 Dec 2018 22:56:41 -0800 Subject: [PATCH 2/2] disabled some tests pending regression #9855 --- lib/pure/sugar.nim | 3 ++- tests/stdlib/tsugar.nim | 9 +++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/pure/sugar.nim b/lib/pure/sugar.nim index 9586066e7e3e6..8e512af1b98ea 100644 --- a/lib/pure/sugar.nim +++ b/lib/pure/sugar.nim @@ -245,7 +245,8 @@ macro extractGeneric*(T: typedesc, index:static[int]): untyped = type Foo[T1, T2]=object doAssert extractGeneric(Foo[float, string], 0) is float doAssert extractGeneric(Foo[float, string], 1) is string - doAssert extractGeneric(Foo[float, string], -1) is Foo + # pending https://github.com/nim-lang/Nim/issues/9855 + # doAssert extractGeneric(Foo[float, string], -1) is Foo var impl = getTypeImpl(T) expectKind(impl, nnkBracketExpr) diff --git a/tests/stdlib/tsugar.nim b/tests/stdlib/tsugar.nim index f8935cc33c8b3..4e1d101803a14 100644 --- a/tests/stdlib/tsugar.nim +++ b/tests/stdlib/tsugar.nim @@ -32,13 +32,18 @@ block distinctBase: block extractGeneric: type Foo[T1, T2]=object type Foo2=Foo[float, string] - doAssert extractGeneric(Foo[float, string], 1) is string + # pending https://github.com/nim-lang/Nim/issues/9855 + # doAssert extractGeneric(Foo2, -1) is Foo + doAssert extractGeneric(Foo2, 0) is float doAssert extractGeneric(Foo2, 1) is string + doAssert extractGeneric(Foo[float, string], 1) is string + # pending https://github.com/nim-lang/Nim/issues/9855 + # doAssert extractGeneric(Foo[float, string], -1) is Foo # workaround for seq[int].T not working, # see https://github.com/nim-lang/Nim/issues/8433 doAssert extractGeneric(seq[int], 0) is int doAssert extractGeneric(seq[seq[string]], 0) is seq[string] - doAssert: not compiles(extractGeneric(seq[int], 1)) + doAssert not compiles(extractGeneric(seq[int], 1)) doAssert extractGeneric(seq[int], -1) is seq type Foo3[T] = T