diff --git a/results.nim b/results.nim index 5d41448..4be4c54 100644 --- a/results.nim +++ b/results.nim @@ -340,6 +340,20 @@ type Opt*[T] = Result[T, void] +const + resultsGenericBindingWorkaround* {.booldefine.} = true + ## Enable a workaround for the template injection problem in the issue + ## linked below where injected templates get bound differently depending + ## on whether we're in a generic context or not - this leads to surprising + ## errors where random symbols from outer scopes get bound to the name + ## instead of the intended value. + ## However, this ugly hack might introduce more damage than it's worth so + ## it can be disabled at compile-time - hopefully an upstream solution + ## can be found. + # TODO https://github.com/nim-lang/Nim/issues/22605 + # TODO https://github.com/arnetheduck/nim-results/issues/34 + + func raiseResultOk[T, E](self: Result[T, E]) {.noreturn, noinline.} = # noinline because raising should take as little space as possible at call # site @@ -955,6 +969,67 @@ func get*[T, E](self: Result[T, E], otherwise: T): T {.inline.} = of false: otherwise +when resultsGenericBindingWorkaround: + import macros + + proc containsHack(n: NimNode): bool = + if n.len == 0: + n.eqIdent("isOkOr") or n.eqIdent("isErrOr") or n.eqIdent("valueOr") or + n.eqIdent("errorOr") + else: + for child in n: + if containsHack(child): + return true + false + + proc replace(n: NimNode, what: string, with: NimNode): NimNode = + if n.eqIdent(what): + result = with + else: + case n.kind + of nnkCallKinds: + # `error(...)` - replace args but not function name + if n[0].containsHack(): + result = n + else: + result = copyNimNode(n) + result.add n[0] + for i in 1..