status-im / nim-stew

stew is collection of utilities, std library extensions and budding libraries that are frequently used at Status, but are too small to deserve their own git repository.
135 stars 18 forks source link

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

Closed tersec closed 10 months ago

tersec commented 1 year ago
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.

arnetheduck commented 1 year ago

Workaround: qualify the error access inside valueOr:


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

  discard gps.valueOr:
    return err(gps.error)

  return err("")
arnetheduck commented 10 months ago

moved to https://github.com/arnetheduck/nim-results/issues/34