Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

results valueOr access to error template injected symbol fails with certain generic callers #34

Closed
arnetheduck opened this issue Sep 1, 2023 · 2 comments

Comments

@arnetheduck
Copy link
Owner

import stew/results

proc makeBeaconBlockForHeadAndSlot[T](): Result[int, string] =
  var gps: Result[int, string]

  discard gps.valueOr:
    return err(error)

  return err("")

proc getBlindedBlockParts() =
  discard makeBeaconBlockForHeadAndSlot[int]()

For example, results in an error of:

stew/results.nim(405, 16) Error: type mismatch: got 'proc (self: Result[error.T, error.E]): E{.noSideEffect.}' for 'error' but expected 'string'

but if one makes makeBeaconBlockForHeadAndSlot non-generic, it compiles fine, even though it doesn't use its dummy parameter regardless.

It's the result of conflict between the error func and injected symbol, which is a known Nim issue. Reproduced in

type
  Result[T, E] = object
   case o: bool
   of false:
     e: E
   of true:
     v: T

template err[T, E](R: type Result[T, E], x: untyped): R =
  R(o: false, e: x)

template err(v: auto): auto = err(typeof(result), v)

func error[T, E](self: Result[T, E]): E =
  if self.o:
    raiseAssert("Trying to access error when value is set")
  when E isnot void:
    self.e

template valueOr[T: not void, E](self: Result[T, E], def: untyped): T =
  let s = (self) # TODO avoid copy
  if s.o: s.v
  else:
    when E isnot void:
      template error: E {.used, inject.} = s.e
    def

#proc makeBeaconBlockForHeadAndSlot[T](): Result[int, string] =
proc makeBeaconBlockForHeadAndSlot(): Result[int, string] =
  var gps: Result[int, string]

  discard gps.valueOr:
    return err(error)

  return err("")

proc getBlindedBlockParts() =
  #discard makeBeaconBlockForHeadAndSlot[int]()
  discard makeBeaconBlockForHeadAndSlot()

in a self-contained way.

Ported from status-im/nim-stew#161

@arnetheduck
Copy link
Owner Author

Upstream discussion: nim-lang/Nim#22605

arnetheduck added a commit that referenced this issue Sep 4, 2023
arnetheduck added a commit that referenced this issue Aug 13, 2024
This PR adds a workaround for the case where a global symbol is matched instead of the local `error`/`value` template in `valueOr` and friends, when `valueOr` is being used in a generic context.

Two options are added:
* when using Nim version supporting the experimental `genericsOpenSym` [feature](nim-lang/Nim#23873), we use it
* when not, a macro tries to replace all accesses in the given body with the correct symbol - this matching is done by name and some minimal heuristics which potentially could be wrong - the upstream solution is obviously preferable

Both solutions can be disabled via compile-time options to retain the old behavior of matching the global symbol.

See also nim-lang/Nim#22605

thanks to @Araq for the macro hack and @metagn for the language fix!
@arnetheduck
Copy link
Owner Author

#35

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant