Accept only optional and reference types as RHS of `=?`
The fact that `option(x)` works for non-reference types (being an alias for `some`) is an stdlib's design mistake that bites us here.
This commit is contained in:
parent
c2a08bd703
commit
440debc7c3
|
@ -2,15 +2,20 @@ import std/options
|
|||
import std/macros
|
||||
import ./private/binderror
|
||||
|
||||
proc option[T](option: Option[T]): Option[T] =
|
||||
template toOption[T](option: Option[T]): Option[T] =
|
||||
option
|
||||
|
||||
template toOption[T: ref | ptr | pointer | proc](value: T): Option[T] =
|
||||
# `std/options` don't consider closure iterators to be pointer types
|
||||
# (probably a bug) so we don't list them here.
|
||||
value.option
|
||||
|
||||
proc placeholder(T: type): T =
|
||||
discard
|
||||
|
||||
template bindLet(name, expression): untyped =
|
||||
let evaluated = expression
|
||||
let option = evaluated.option
|
||||
let option = evaluated.toOption
|
||||
type T = typeof(option.unsafeGet())
|
||||
let name {.used.} = if option.isSome:
|
||||
option.unsafeGet()
|
||||
|
@ -21,7 +26,7 @@ template bindLet(name, expression): untyped =
|
|||
|
||||
template bindVar(name, expression): untyped =
|
||||
let evaluated = expression
|
||||
let option = evaluated.option
|
||||
let option = evaluated.toOption
|
||||
type T = typeof(option.unsafeGet())
|
||||
var name {.used.} = if option.isSome:
|
||||
option.unsafeGet()
|
||||
|
@ -55,7 +60,7 @@ macro bindTuple(names, expression): bool =
|
|||
|
||||
quote do:
|
||||
let `evaluated` = `expression`
|
||||
let `opt` = `evaluated`.option
|
||||
let `opt` = `evaluated`.toOption
|
||||
type `T` = typeof(`opt`.unsafeGet())
|
||||
`letsection`
|
||||
`opt`.isSome
|
||||
|
|
|
@ -165,6 +165,53 @@ suite "optionals":
|
|||
else:
|
||||
fail()
|
||||
|
||||
test "=? works with reference types":
|
||||
var x = new int
|
||||
x[] = 42
|
||||
if a =? x:
|
||||
check a[] == 42
|
||||
else:
|
||||
fail
|
||||
|
||||
x = nil
|
||||
if a =? x:
|
||||
fail
|
||||
|
||||
var p = proc = discard
|
||||
if a =? p:
|
||||
a()
|
||||
else:
|
||||
fail
|
||||
|
||||
p = nil
|
||||
if a =? p:
|
||||
fail
|
||||
|
||||
test "=? rejects non-reference types":
|
||||
check `not` compiles do:
|
||||
if a =? 0:
|
||||
discard
|
||||
check `not` compiles do:
|
||||
if var a =? 0:
|
||||
discard
|
||||
check `not` compiles do:
|
||||
if (a,) =? (0,):
|
||||
discard
|
||||
|
||||
test "=? works with custom optional types":
|
||||
type MyOption = distinct int
|
||||
proc isSome(x: MyOption): bool = x.int >= 0
|
||||
proc unsafeGet(x: MyOption): int = x.int
|
||||
template toOption(x: MyOption): MyOption = x
|
||||
|
||||
if a =? MyOption 42:
|
||||
check a == 42
|
||||
else:
|
||||
fail
|
||||
|
||||
if a =? MyOption -1:
|
||||
fail
|
||||
|
||||
test "=? binds and unpacks tuples":
|
||||
if (a, b) =? (some ("test", 1)):
|
||||
check a == "test"
|
||||
|
|
Loading…
Reference in New Issue