Opened 2 years ago

Closed 23 months ago

Last modified 15 months ago

#13285 closed bug (fixed)

Bug in GHC.Stack.callStack when used with sections

Reported by: SimonHengel Owned by: simonpj
Priority: normal Milestone: 8.2.1
Component: Compiler Version: 8.0.1
Keywords: Cc: saurabhnanda
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: Incorrect result at runtime Test Case: deSigar/should_run/T13285
Blocked By: Blocking:
Related Tickets: Differential Rev(s):
Wiki Page:

Description

Since GHC 8.0.1 call stacks are not constructed consistently anymore. Specifically, no stack frames are added for call sites that use section syntax.

This used to work with GHC 7.10.2. I haven't tried with 7.10.3.

Call stacks are used in hspec and HUnit to attach location information to failing test cases. Moreover, it is somewhat common to use section syntax with hspec. This is why I describe the bug in the context of hspec. But first, I give minimal steps on how to reproduce without the need of any additional dependencies.

TL;DR Minimal steps to reproduce

-- Main.hs
import GHC.Stack

main :: IO ()
main = do
  foo 23 42
  (`foo` 23) 42

foo :: HasCallStack => Int -> Int -> IO ()
foo _ _ = print (length . getCallStack $ callStack)
$ runhaskell Main.hs

expected output:

1
1

actual output:

1
0

Description of the bug from a users perspective (in the context of Hspec)

This section describes the bug in the context of hspec. If you already understand how this bug affects users and why this is problematic you may choose to skip this section.

A working example

Looking at the following example

-- Spec.hs
import Test.Hspec
           
main :: IO ()
main = hspec $ do
  it "works for my use case" $ do
    23 `shouldBe` 42

call stacks work as expected:

$ runhaskell Spec.hs
...
Failures:

  Spec.hs:6: 
  1) works for my use case
       expected: 42
        but got: 23
...

The users sees a source locations that points him to the failing test case.

A slightly modified and broken example

If we rephrase the above example using section syntax we get

-- Spec.hs
import Test.Hspec

main :: IO ()
main = hspec $ do
  it "works for my use case" $ do
    (`shouldBe` 42) 23

and things suddenly go bad:

$ runhaskell Spec.hs
...
Failures:

  src/Test/Hspec/Expectations.hs:91: 
  1) works for my use case
       expected: 42
        but got: 23
...

The user expects to see the call site of shouldBe, that points him to the failing test case. But instead he gets an unhelpful location that points somewhere at the implementation of hspec-expectations.

Change History (7)

comment:1 Changed 2 years ago by simonpj

Owner: set to simonpj

I'm on this.

comment:2 Changed 2 years ago by Simon Peyton Jones <simonpj@…>

In b8c29bc9/ghc:

Use the correct origin in SectionL and Section R

This fixes Trac #13285.

The CallStack stuff is all driven by a CtOrigin of (OccurenceOf f),
and we were instead using SectionOrigin.  Boo!

Easily fixed; and I did a little refactoring as usual.

comment:3 Changed 2 years ago by simonpj

Milestone: 8.0.3
Status: newmerge
Test Case: deSigar/should_run/T13285

comment:4 Changed 23 months ago by bgamari

Milestone: 8.0.38.2.1

At this point it is rather unlikely that there will be an 8.0.3. Re-milestoning.

comment:5 Changed 23 months ago by bgamari

Resolution: fixed
Status: mergeclosed

comment:6 Changed 15 months ago by saurabhnanda

Commenting to be notified of future discussion. (is there a better way of doing this?)

comment:7 Changed 15 months ago by saurabhnanda

Cc: saurabhnanda added
Note: See TracTickets for help on using tickets.