Skip to content

hasX might hide exceptions other than XException #2450

Description

@DigitalBrains1

If the value evaluated with hasX contains multiple exceptions, only the first one encountered will determine the outcome of hasX.

>>> let a = errorX "XException" :> error "ErrorCall" :> Nil
>>> let b = error "ErrorCall" :> errorX "XException" :> Nil
>>> hasX a
Left "X: XException\nCallStack (from HasCallStack):\n  errorX, called at <interactive>:1:9 in interactive:Ghci2"
>>> hasX b
*** Exception: ErrorCall
CallStack (from HasCallStack):
  error, called at <interactive>:2:9 in interactive:Ghci3

In my opinion, both should have thrown an ErrorCall. The documentation for hasX describes it as fully evaluate a value. It is currently not evaluating anything beyond the XException.

Currently, hasX reduces its argument to normal form using NFData, and catches XExceptions. This checks only one of the exceptions the argument might throw. Instead, we probably need to first check for exceptions other than XException and only after that check for all exceptions (which boils down to just the XExceptions of course):

hasX :: (NFDataX a, NFData a) => a -> Either String a
hasX a =
  unsafeDupablePerformIO
    (catch
      (evaluate (rnfX a `seq` rnf a) >> return (Right a))
      (\(XException msg) -> return (Left msg)))

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions