diff options
author | Timothee Cour <timothee.cour2@gmail.com> | 2021-07-06 21:04:36 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-07-07 06:04:36 +0200 |
commit | d1447fe25d40e35d4746d570701d23333ff480a0 (patch) | |
tree | 76214c3c494ad5494598dda535a9a7efbb288e8a /tests/stdlib/twrapnils.nim | |
parent | b72ecaf639ca7b2edf5a762cfea3a11f7cc5da9a (diff) | |
download | Nim-d1447fe25d40e35d4746d570701d23333ff480a0.tar.gz |
major improvements to `std/wrapnils`: optimal codegen, case objects, lvalue semantics (#18435)
* wrapnils now generates optimal code; also handles case objects * changelog * unsafeAddr => addr
Diffstat (limited to 'tests/stdlib/twrapnils.nim')
-rw-r--r-- | tests/stdlib/twrapnils.nim | 281 |
1 files changed, 207 insertions, 74 deletions
diff --git a/tests/stdlib/twrapnils.nim b/tests/stdlib/twrapnils.nim index 956204355..1a66f4cd9 100644 --- a/tests/stdlib/twrapnils.nim +++ b/tests/stdlib/twrapnils.nim @@ -7,80 +7,213 @@ proc checkNotZero(x: float): float = proc main() = var witness = 0 - type Bar = object - b1: int - b2: ptr string - - type Foo = ref object - x1: float - x2: Foo - x3: string - x4: Bar - x5: seq[int] - x6: ptr Bar - x7: array[2, string] - x8: seq[int] - x9: ref Bar - - type Gook = ref object - foo: Foo - - proc fun(a: Bar): auto = a.b2 - - var a: Foo - - var x6: ptr Bar - when nimvm: discard # pending https://github.com/timotheecour/Nim/issues/568 - else: - x6 = create(Bar) - x6.b1 = 42 - var a2 = Foo(x1: 1.0, x5: @[10, 11], x6: x6) - var a3 = Foo(x1: 1.2, x3: "abc") - a3.x2 = a3 - - var gook = Gook(foo: a) - - proc initFoo(x1: float): auto = - witness.inc - result = Foo(x1: x1) - - doAssert ?.a.x2.x2.x1 == 0.0 - doAssert ?.a3.x2.x2.x1 == 1.2 - doAssert ?.a3.x2.x2.x3[1] == 'b' - - doAssert ?.a3.x2.x2.x5.len == 0 - doAssert a3.x2.x2.x3.len == 3 - - doAssert ?.a.x2.x2.x3[1] == default(char) - # here we only apply wrapnil around gook.foo, not gook (and assume gook is not nil) - doAssert ?.(gook.foo).x2.x2.x1 == 0.0 - - when nimvm: discard - else: - doAssert ?.a2.x6[] == Bar(b1: 42) # deref for ptr Bar - - doAssert ?.a2.x1.checkNotZero == 1.0 - doAssert a == nil - # shows that checkNotZero won't be called if a nil is found earlier in chain - doAssert ?.a.x1.checkNotZero == 0.0 - - when nimvm: discard - else: - # checks that a chain without nil but with an empty seq still raises - doAssertRaises(IndexDefect): discard ?.a2.x8[3] - - # make sure no double evaluation bug - doAssert witness == 0 - doAssert ?.initFoo(1.3).x1 == 1.3 - doAssert witness == 1 - - # here, it's used twice, to deref `ref Bar` and then `ptr string` - doAssert ?.a.x9[].fun[] == "" - - block: # `??.` - doAssert (??.a3.x2.x2.x3.len).get == 3 - doAssert (??.a2.x4).isSome - doAssert not (??.a.x4).isSome + block: + type Bar = object + b1: int + b2: ptr string + + type Foo = ref object + x1: float + x2: Foo + x3: string + x4: Bar + x5: seq[int] + x6: ptr Bar + x7: array[2, string] + x8: seq[int] + x9: ref Bar + + type Gook = ref object + foo: Foo + + proc fun(a: Bar): auto = a.b2 + + var a: Foo + + var x6: ptr Bar + when nimvm: discard # pending https://github.com/timotheecour/Nim/issues/568 + else: + x6 = create(Bar) + x6.b1 = 42 + var a2 = Foo(x1: 1.0, x5: @[10, 11], x6: x6) + var a3 = Foo(x1: 1.2, x3: "abc") + a3.x2 = a3 + + var gook = Gook(foo: a) + + proc initFoo(x1: float): auto = + witness.inc + result = Foo(x1: x1) + + doAssert ?.a.x2.x2.x1 == 0.0 + doAssert ?.a3.x2.x2.x1 == 1.2 + doAssert ?.a3.x2.x2.x3[1] == 'b' + + doAssert ?.a3.x2.x2.x5.len == 0 + doAssert a3.x2.x2.x3.len == 3 + + doAssert ?.a.x2.x2.x3[1] == default(char) + # here we only apply wrapnil around gook.foo, not gook (and assume gook is not nil) + doAssert ?.(gook.foo).x2.x2.x1 == 0.0 + + when nimvm: discard + else: + doAssert ?.a2.x6[] == Bar(b1: 42) # deref for ptr Bar + + doAssert ?.a2.x1.checkNotZero == 1.0 + doAssert a == nil + # shows that checkNotZero won't be called if a nil is found earlier in chain + doAssert ?.a.x1.checkNotZero == 0.0 + + when nimvm: discard + else: + # checks that a chain without nil but with an empty seq still raises + doAssertRaises(IndexDefect): discard ?.a2.x8[3] + + # make sure no double evaluation bug + doAssert witness == 0 + doAssert ?.initFoo(1.3).x1 == 1.3 + doAssert witness == 1 + + # here, it's used twice, to deref `ref Bar` and then `ptr string` + doAssert ?.a.x9[].fun[] == "" + + block: # `??.` + doAssert (??.a3.x2.x2.x3.len).get == 3 + doAssert (??.a2.x4).isSome + doAssert not (??.a.x4).isSome + + block: + type + A = object + b: B + B = object + c: C + C = object + d: D + D = ref object + e: E + e2: array[2, E] + e3: seq[E] + d3: D + i4: int + E = object + f: int + d2: D + proc identity[T](a: T): T = a + proc identity2[T](a: T, ignore: int): T = a + var a: A + doAssert ?.a.b.c.d.e.f == 0 + doAssert ?.a.b.c.d.e.d2.d3[].d3.e.d2.e.f == 0 + doAssert ?.a.b.c.d.d3[].e.f == 0 + doAssert ?.a.b.c.d.e2[0].d2.e3[0].f == 0 + doAssert ?.a == A.default + doAssert ?.a.b.c.d.e == E.default + doAssert ?.a.b.c.d.e.d2 == nil + + doAssert ?.a.identity.b.c.identity2(12).d.d3.e.f == 0 + doAssert ?.a.b.c.d.d3.e2[0].f == 0 + a.b.c.d = D() + a.b.c.d.d3 = a.b.c.d + a.b.c.d.e2[0].f = 5 + doAssert ?.a.b.c.d.d3.e2[0].f == 5 + + var d: D = nil + doAssert ?.d.identity.i4 == 0 + doAssert ?.d.i4.identity == 0 + + block: # case objects + type + Kind = enum k0, k1, k2 + V = object + case kind: Kind + of k0: + x0: int + of k1: + x1: int + of k2: + x2: int + A = object + v0: V + + block: + var a = V(kind: k0, x0: 3) + doAssert ?.a.x0 == 3 + doAssert ?.a.x1 == 0 + a = V(kind: k1, x1: 5) + doAssert ?.a.x0 == 0 + doAssert ?.a.x1 == 5 + + block: + var a = A(v0: V(kind: k0, x0: 10)) + doAssert ?.a.v0.x0 == 10 + doAssert ?.a.v0.x1 == 0 + a.v0 = V(kind: k2, x2: 8) + doAssert ?.a.v0.x0 == 0 + doAssert ?.a.v0.x1 == 0 + doAssert ?.a.v0.x2 == 8 + + block: # `nnkCall` + type + A = object + a0: int + d: D + D = ref object + i4: int + + proc identity[T](a: T): T = a + var d: D = nil + doAssert ?.d.i4.identity == 0 + doAssert ?.identity(?.d.i4) == 0 + doAssert ?.identity(d.i4) == 0 + doAssert ?.identity(d) == nil + doAssert ?.identity(d[]) == default(typeof(d[])) + doAssert ?.identity(d[]).i4 == 0 + var a: A + doAssert ?.identity(a) == default(A) + doAssert ?.identity(a.a0) == 0 + doAssert ?.identity(a.d) == nil + doAssert ?.identity(a.d.i4) == 0 + + block: # lvalue semantic propagation + type + A = ref object + a0: A + a1: seq[A] + a2: int + + B = object + b0: int + case cond: bool + of false: discard + of true: + b1: float + + block: + var a: A + doAssert ?.a.a0.a1[0].a2.addr == nil + a = A(a2: 3) + doAssert ?.a.a0.a1[0].a2.addr == nil + a.a0 = a + a.a1 = @[a] + let p = ?.a.a0.a1[0].a2.addr + doAssert p != nil + p[] = 5 + doAssert a.a2 == 5 + + block: + var b = B(cond: false, b0: 3) + let p = ?.b.b1.addr + doAssert p == nil + b = B(cond: true, b1: 4.5) + let p2 = ?.b.b1.addr + doAssert p2 != nil + p2[] = 4.6 + doAssert b.b1 == 4.6 + # useful pattern, impossible with Options + if (let p3 = ?.b.b1.addr; p3 != nil): + p3[] = 4.7 + doAssert b.b1 == 4.7 main() static: main() |