From ce296cbe2ca652169f714dd7b3dfd9ddbb70864f Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 6 Jan 2020 10:14:10 -0800 Subject: [PATCH] add `deref` that wraps original `system.[] --- lib/std/wrapnils.nim | 18 ++++++++++++++++-- tests/stdlib/twrapnils.nim | 9 +++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/lib/std/wrapnils.nim b/lib/std/wrapnils.nim index f0c1944394340..92d37e93f4c59 100644 --- a/lib/std/wrapnils.nim +++ b/lib/std/wrapnils.nim @@ -25,17 +25,18 @@ proc wrapnil*[T](a: T): Wrapnil[T] = template `.`*(a: Wrapnil, b): untyped = let a1 = a # to avoid double evaluations let a2 = a1.valueImpl + type T = Wrapnil[type(a2.b)] if a1.validImpl: when type(a2) is ref|ptr: if a2 == nil: - default(Wrapnil[type(a2.b)]) + default(T) else: wrapnil(a2.b) else: wrapnil(a2.b) else: # nil is "sticky"; this is needed, see tests - default(Wrapnil[type(a2.b)]) + default(T) {.pop.} @@ -51,3 +52,16 @@ template `[]`*[I](a: Wrapnil, i: I): untyped = wrapnil(a1.valueImpl[i]) else: default(Wrapnil[type(a1.valueImpl[i])]) + +template deref*(a: Wrapnil): untyped = + ## Since `[]` is hijacked, we can use `deref` that wraps original `system.[]` + let a1 = a # to avoid double evaluations + let a2 = a1.valueImpl + type T = Wrapnil[type(a2[])] + if a1.validImpl: + if a2 == nil: + default(T) + else: + wrapnil(a2[]) + else: + default(T) diff --git a/tests/stdlib/twrapnils.nim b/tests/stdlib/twrapnils.nim index 13030b03fe1cb..8b191ca8d5d5a 100644 --- a/tests/stdlib/twrapnils.nim +++ b/tests/stdlib/twrapnils.nim @@ -10,6 +10,8 @@ var witness = 0 proc main() = type Bar = object b1: int + b2: ptr string + type Foo = ref object x1: float x2: Foo @@ -19,6 +21,9 @@ proc main() = x6: ptr Bar x7: array[2, string] x8: seq[int] + x9: ref Bar + + proc fun(a: Bar): auto = a.b2 var a: Foo var x6 = create(Bar) @@ -57,4 +62,8 @@ proc main() = doAssert initFoo(1.3).wrapnil.x1[] == 1.3 doAssert witness == 1 + # since `[]` is hijacked, we can use `deref` that wraps original `system.[]` + # here, it's used twice, to deref `ref Bar` and then `ptr string` + doAssert a.wrapnil.x9.deref.fun.deref[] == "" + main()