Skip to content

Incorrect callstack trace when function is used multiple times in different branches #838

Open
@SeungheonOh

Description

@SeungheonOh

Consider

foo :: forall s. HasCallStack => Term s (PInteger :--> PInteger)
foo = plam $ \(_x :: Term s PInteger) -> (pthrow "nope") :: Term s PInteger
bob :: forall s. HasCallStack => Term s (PInteger :--> PInteger)
bob = plam $ \(x :: Term s PInteger) -> foo # x

rob :: forall s. HasCallStack => Term s (PInteger :--> PInteger)
rob = plam $ \(x :: Term s PInteger) -> foo # x

mine :: forall s. HasCallStack => Term s (PInteger :--> PInteger)
mine = plam $ \(x :: Term s PInteger) ->
  pif
    (x #== 10)
    (bob # x)
    (rob # x)

-- and execute below

λ let Left a = evalTerm mempty (mine # pconstant @PInteger 11) in putStrLn $ unpack a
CallStack (from HasCallStack):
  pthrow', called at ./Plutarch/Internal/Term.hs:632:24 in plutarch-1.10.1-inplace:Plutarch.Internal.Term
  pthrow, called at <interactive>:52:43 in interactive:Ghci20
  foo, called at <interactive>:54:41 in interactive:Ghci20
  bob, called at <interactive>:60:58 in interactive:Ghci20
  mine, called at <interactive>:66:31 in interactive:Ghci25

nope

λ let Left a = evalTerm mempty (mine # pconstant @PInteger 10) in putStrLn $ unpack a
CallStack (from HasCallStack):
  pthrow', called at ./Plutarch/Internal/Term.hs:632:24 in plutarch-1.10.1-inplace:Plutarch.Internal.Term
  pthrow, called at <interactive>:52:43 in interactive:Ghci20
  foo, called at <interactive>:54:41 in interactive:Ghci20
  bob, called at <interactive>:60:58 in interactive:Ghci20
  mine, called at <interactive>:67:31 in interactive:Ghci26

nope

Notice how they have exactly same callstack trace where first must show foo -> rob -> mine. This is not particularly unexpected and I think it will consistently take the first branch to generate callstack. It will be difficult to make it generate correct callstack since that means we need a different copies of foo for each "branches." Generating "correct" callstack would also mean duplicating a ton of code obviously.

So, I don't think we should necessarily fix this by making correct behavior default. We should at least

  • Make note of current shortcoming clearly
  • (if we have time and passion) Add new compilation option that will generate correct callstack trace with note that will severely bloat amount of generated code.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions