From 4967084d22522d351a7071a98646d500b814a3fd Mon Sep 17 00:00:00 2001 From: Mark Spanbroek Date: Mon, 30 Aug 2021 15:58:29 +0200 Subject: [PATCH] Better errors when using a proc without a return type in a .? chain --- questionable/chaining.nim | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/questionable/chaining.nim b/questionable/chaining.nim index a281f82..d42aa28 100644 --- a/questionable/chaining.nim +++ b/questionable/chaining.nim @@ -1,5 +1,6 @@ import std/options import std/macros +import std/strformat func isSym(node: NimNode): bool = node.kind in {nnkSym, nnkOpenSymChoice, nnkClosedSymChoice} @@ -7,14 +8,20 @@ func isSym(node: NimNode): bool = func expectSym(node: NimNode) = node.expectKind({nnkSym, nnkOpenSymChoice, nnkClosedSymChoice}) +macro expectReturnType(identifier: untyped, expression: untyped): untyped = + let message = + fmt"'{identifier}' doesn't have a return type, it can't be in a .? chain" + quote do: + when compiles(`expression`) and not compiles(typeof `expression`): + {.error: `message`.} + template `.?`*(option: typed, identifier: untyped{nkIdent}): untyped = ## The `.?` chaining operator is used to safely access fields and call procs ## on Options or Results. The expression is only evaluated when the preceding ## Option or Result has a value. # chain is of shape: option.?identifier - when not compiles(typeof(option.unsafeGet.identifier)): - {.error: ".? chain cannot return void".} + expectReturnType(identifier, option.unsafeGet.identifier) option ->? option.unsafeGet.identifier macro `.?`*(option: typed, infix: untyped{nkInfix}): untyped = @@ -70,7 +77,9 @@ macro `.?`*(option: typed, call: untyped{nkCall}): untyped = else: # chain is of shape: option.?procedure(arguments) call.insert(1, quote do: `option`.unsafeGet) - quote do: `option` ->? `call` + quote do: + expectReturnType(`procedure`, `call`) + `option` ->? `call` macro `.?`*(option: typed, symbol: untyped): untyped = ## The `.?` chaining operator is used to safely access fields and call procs