#14682 closed bug (fixed)

Atrocious parenthesization in -ddump-deriv output

Reported by: RyanGlScott Owned by:
Priority: normal Milestone: 8.4.1
Component: Compiler Version: 8.2.2
Keywords: deriving Cc:
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: Debugging information is incorrect Test Case:
Blocked By: Blocking:
Related Tickets: #14681 Differential Rev(s): Phab:D4323
Wiki Page:

Description

The next installment in "RyanGlScott finds parenthesization bugs". This time, we're featuring -ddump-deriv. Just look at this garbage:

$ /opt/ghc/8.2.2/bin/ghci
GHCi, version 8.2.2: http://www.haskell.org/ghc/  :? for help
Loaded GHCi configuration from /home/rgscott/.ghci
λ> import Data.Ix
λ> import Language.Haskell.TH.Syntax
λ> import Data.Data
λ> :set -ddump-deriv -XDeriveLift -XDeriveDataTypeable 
λ> data Foo = Foo Int Int deriving (Show, Lift, Data, Eq, Ord, Ix)

==================== Derived instances ====================
Derived class instances:
  instance GHC.Show.Show Ghci1.Foo where
    GHC.Show.showsPrec a_a6me Ghci1.Foo b1_a6mf b2_a6mg
      = GHC.Show.showParen
          (a_a6me GHC.Classes.>= 11)
          ((GHC.Base..)
             (GHC.Show.showString "Foo ")
             ((GHC.Base..)
                (GHC.Show.showsPrec 11 b1_a6mf)
                ((GHC.Base..) GHC.Show.showSpace (GHC.Show.showsPrec 11 b2_a6mg))))
    GHC.Show.showList = GHC.Show.showList__ (GHC.Show.showsPrec 0)
  
  instance Language.Haskell.TH.Syntax.Lift Ghci1.Foo where
    Language.Haskell.TH.Syntax.lift Ghci1.Foo a1_a6mh a2_a6mi
      = Language.Haskell.TH.Lib.appE
          (Language.Haskell.TH.Lib.appE
             (Language.Haskell.TH.Lib.conE
                (Language.Haskell.TH.Syntax.mkNameG_d "interactive" "Ghci1" "Foo"))
             (Language.Haskell.TH.Syntax.lift a1_a6mh))
          (Language.Haskell.TH.Syntax.lift a2_a6mi)
  
  instance Data.Data.Data Ghci1.Foo where
    Data.Data.gfoldl k_a6mj z_a6mk Ghci1.Foo a1_a6ml a2_a6mm
      = ((z_a6mk Ghci1.Foo `k_a6mj` a1_a6ml) `k_a6mj` a2_a6mm)
    Data.Data.gunfold k_a6mn z_a6mo _
      = k_a6mn (k_a6mn (z_a6mo Ghci1.Foo))
    Data.Data.toConstr Ghci1.Foo _ _ = Ghci1.$cFoo
    Data.Data.dataTypeOf _ = Ghci1.$tFoo
  
  instance GHC.Classes.Eq Ghci1.Foo where
    (GHC.Classes.==)
      (Ghci1.Foo a1_a6mp a2_a6mq)
      (Ghci1.Foo b1_a6mr b2_a6ms)
      = (((a1_a6mp GHC.Classes.== b1_a6mr))
           GHC.Classes.&& ((a2_a6mq GHC.Classes.== b2_a6ms)))
    (GHC.Classes./=) a_a6mt b_a6mu
      = GHC.Classes.not ((GHC.Classes.==) a_a6mt b_a6mu)
  
  instance GHC.Classes.Ord Ghci1.Foo where
    GHC.Classes.compare a_a6mv b_a6mw
      = case a_a6mv of {
          Ghci1.Foo a1_a6mx a2_a6my
            -> case b_a6mw of {
                 Ghci1.Foo b1_a6mz b2_a6mA
                   -> case (GHC.Classes.compare a1_a6mx b1_a6mz) of
                        GHC.Types.LT -> GHC.Types.LT
                        GHC.Types.EQ -> (a2_a6my `GHC.Classes.compare` b2_a6mA)
                        GHC.Types.GT -> GHC.Types.GT } }
    (GHC.Classes.<) a_a6mB b_a6mC
      = case a_a6mB of {
          Ghci1.Foo a1_a6mD a2_a6mE
            -> case b_a6mC of {
                 Ghci1.Foo b1_a6mF b2_a6mG
                   -> case (GHC.Classes.compare a1_a6mD b1_a6mF) of
                        GHC.Types.LT -> GHC.Types.True
                        GHC.Types.EQ -> (a2_a6mE GHC.Classes.< b2_a6mG)
                        GHC.Types.GT -> GHC.Types.False } }
    (GHC.Classes.<=) a_a6mH b_a6mI
      = GHC.Classes.not ((GHC.Classes.<) b_a6mI a_a6mH)
    (GHC.Classes.>) a_a6mJ b_a6mK = (GHC.Classes.<) b_a6mK a_a6mJ
    (GHC.Classes.>=) a_a6mL b_a6mM
      = GHC.Classes.not ((GHC.Classes.<) a_a6mL b_a6mM)
  
  instance GHC.Arr.Ix Ghci1.Foo where
    GHC.Arr.range
      (Ghci1.Foo a1_a6mN a2_a6mO, Ghci1.Foo b1_a6mP b2_a6mQ)
      = [Ghci1.Foo c1_a6mR c2_a6mS |
           c1_a6mR <- GHC.Arr.range (a1_a6mN, b1_a6mP),
           c2_a6mS <- GHC.Arr.range (a2_a6mO, b2_a6mQ)]
    GHC.Arr.unsafeIndex
      (Ghci1.Foo a1_a6mT a2_a6mU, Ghci1.Foo b1_a6mV b2_a6mW)
      Ghci1.Foo c1_a6mX c2_a6mY
      = (GHC.Arr.unsafeIndex (a2_a6mU, b2_a6mW) c2_a6mY
           GHC.Num.+
             (GHC.Arr.unsafeRangeSize (a2_a6mU, b2_a6mW)
                GHC.Num.* GHC.Arr.unsafeIndex (a1_a6mT, b1_a6mV) c1_a6mX))
    GHC.Arr.inRange
      (Ghci1.Foo a1_a6oj a2_a6ok, Ghci1.Foo b1_a6ol b2_a6om)
      Ghci1.Foo c1_a6on c2_a6oo
      = (GHC.Arr.inRange (a1_a6oj, b1_a6ol) c1_a6on
           GHC.Classes.&& GHC.Arr.inRange (a2_a6ok, b2_a6om) c2_a6oo)
  
  Ghci1.$con2tag_Hv18APskVh1Gg9kT3PCwD2 :: Ghci1.Foo -> GHC.Prim.Int#
  Ghci1.$con2tag_Hv18APskVh1Gg9kT3PCwD2 Ghci1.Foo _ _ = 0#
  Ghci1.$tFoo :: Data.Data.DataType
  Ghci1.$cFoo :: Data.Data.Constr
  Ghci1.$tFoo = Data.Data.mkDataType "Foo" [Ghci1.$cFoo]
  Ghci1.$cFoo
    = Data.Data.mkConstr Ghci1.$tFoo "Foo" [] Data.Data.Prefix

There are several lines where Foo must be surrounded with parentheses to typecheck, but aren't. They are:

  • In the Show instance:
    GHC.Show.showsPrec a_a8sa Ghci11.Foo b1_a8sb b2_a8sc
    
  • In the Lift instance:
    Language.Haskell.TH.Syntax.lift Ghci11.Foo a1_a8sd a2_a8se
    
  • In the Data instance:
    Data.Data.gfoldl k_a8sf z_a8sg Ghci11.Foo a1_a8sh a2_a8si
    ...
    Data.Data.toConstr Ghci11.Foo _ _ = Ghci11.$cFoo
    
  • In the auxiliary bindings (technically, these aren't legal definitions in the first place, but it does look jarring):
      Ghci11.$con2tag_GrjBmXmdiewCS4g3vLeGMg :: Ghci11.Foo -> GHC.Prim.Int#
      Ghci11.$con2tag_GrjBmXmdiewCS4g3vLeGMg Ghci11.Foo _ _ = 0#
    

Change History (5)

comment:1 Changed 20 months ago by RyanGlScott

I end up needing the functions I defined in Phab:D4323 to fix this bug. Since the ticket that Phab:D4323 fixes (#14681) is so similar to this one, I think I'll just amend Phab:D4323 to fix this ticket as well.

comment:2 Changed 20 months ago by RyanGlScott

Differential Rev(s): Phab:D4323
Status: newpatch

comment:3 Changed 20 months ago by Ben Gamari <ben@…>

In 575c009d/ghc:

Fix #14681 and #14682 with precision-aimed parentheses

It turns out that `Convert` was recklessly leaving off
parentheses in two places:

* Negative numeric literals
* Patterns in lambda position

This patch fixes it by adding three new functions, `isCompoundHsLit`,
`isCompoundHsOverLit`, and `isCompoundPat`, and using them in the
right places in `Convert`. While I was in town, I also sprinkled
`isCompoundPat` among some `Pat`-constructing functions in `HsUtils`
to help avoid the likelihood of this problem happening in other
places. One of these places is in `TcGenDeriv`, and sprinkling
`isCompountPat` there fixes #14682

Test Plan: make test TEST="T14681 T14682"

Reviewers: alanz, goldfire, bgamari

Reviewed By: bgamari

Subscribers: rwbarton, thomie, carter

GHC Trac Issues: #14681, #14682

Differential Revision: https://phabricator.haskell.org/D4323

comment:4 Changed 20 months ago by bgamari

Milestone: 8.4.1
Status: patchmerge

comment:5 Changed 20 months ago by bgamari

Resolution: fixed
Status: mergeclosed
Note: See TracTickets for help on using tickets.