Opened 3 years ago

Closed 3 years ago

Last modified 2 years ago

#12399 closed bug (fixed)

DeriveFunctor fail

Reported by: osa1 Owned by:
Priority: normal Milestone: 8.0.2
Component: Compiler (Type checker) Version: 8.0.1
Keywords: deriving Cc: RyanGlScott
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: None/Unknown Test Case: deriving/should_compile/T12399
Blocked By: Blocking:
Related Tickets: Differential Rev(s): Phab:D2404
Wiki Page:

Description

{-# LANGUAGE DeriveFunctor, MagicHash, UnboxedTuples #-}

module Lib where

import GHC.Exts

newtype RmLoopsM a = RmLoopsM { runRmLoops :: Int# -> (# Int#, a #) }

Functor instance for this can be derived like this:

instance Functor RmLoopsM where
  fmap f (RmLoopsM m) = RmLoopsM $ \i -> case m i of
                                           (# i', r #) -> (# i', f r #)

DeriveFunctor instead generates something like this:

instance Functor RmLoopsM where
  fmap f_a2Oh (Lib.RmLoopsM a1_a2Oi)
    = RmLoopsM
        ((\ b6_a2Oj b7_a2Ok
            -> (\ b5_a2Ol
                  -> case b5_a2Ol of {
                       ((#,#) a1_a2Om a2_a2On a3_a2Oo a4_a2Op)
                         -> (#,#)
                              ((\ b2_a2Oq -> b2_a2Oq) a1_a2Om)
                              ((\ b3_a2Or -> b3_a2Or) a2_a2On)
                              ((\ b4_a2Os -> b4_a2Os) a3_a2Oo)
                              (f_a2Oh a4_a2Op) })
                 (b6_a2Oj ((\ b1_a2Ot -> b1_a2Ot) b7_a2Ok)))
           a1_a2Oi)

which fails with

Main.hs:17:25: error:
    • The constructor ‘(#,#)’ should have 2 arguments, but has been given 4
    • In the pattern: (#,#) a1_a2Om a2_a2On a3_a2Oo a4_a2Op
      In a case alternative:
          ((#,#) a1_a2Om a2_a2On a3_a2Oo a4_a2Op)
            -> (#,#)
                 ((\ b2_a2Oq -> b2_a2Oq) a1_a2Om)
                 ((\ b3_a2Or -> b3_a2Or) a2_a2On)
                 ((\ b4_a2Os -> b4_a2Os) a3_a2Oo)
                 (f_a2Oh a4_a2Op)
      In the expression:
        case b5_a2Ol of {
          ((#,#) a1_a2Om a2_a2On a3_a2Oo a4_a2Op)
            -> (#,#)
                 ((\ b2_a2Oq -> b2_a2Oq) a1_a2Om)
                 ((\ b3_a2Or -> b3_a2Or) a2_a2On)
                 ((\ b4_a2Os -> b4_a2Os) a3_a2Oo)
                 (f_a2Oh a4_a2Op) }

I think it's supposed to ignore RuntimeRep args during the fold (TcGenDeriv.functorLikeTraverse).

Tried with: HEAD, 8.0.1.

Change History (10)

comment:1 Changed 3 years ago by bgamari

Cc: RyanGlScott added
Milestone: 8.2.1

Adding RyanGlScott who has done a fair bit of work in this area.

comment:2 Changed 3 years ago by RyanGlScott

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

Nice catch! I had no idea that RuntimeRep-kinded type parameters were also represented as actual arguments to a constructor... in any case, your intuition that we need to drop the RuntimeRep args was spot on.

(Hopefully, this would also fix derived Functor instances for datatypes that contain unboxed sums, but I'm not 100% sure on that.)

comment:3 Changed 3 years ago by Ryan Scott <ryan.gl.scott@…>

In 3fa3fe8/ghc:

Make DeriveFunctor work with unboxed tuples

Summary:
Unboxed tuples have `RuntimeRep` arguments which `-XDeriveFunctor` was
mistaking for actual data constructor arguments. As a result, a derived
`Functor` instance for a datatype that contained an unboxed tuple would
generate twice as many arguments as it needed for an unboxed tuple pattern
match or expression. The solution is to simply put `dropRuntimeRepArgs` in the
right place.

Fixes #12399.

Test Plan: ./validate

Reviewers: austin, hvr, bgamari

Reviewed By: bgamari

Subscribers: thomie, osa1

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

GHC Trac Issues: #12399

comment:4 Changed 3 years ago by RyanGlScott

Milestone: 8.2.18.0.2
Resolution: fixed
Status: patchclosed

I think this deserves to go into 8.0.2, if possible.

comment:5 Changed 3 years ago by RyanGlScott

Status: closedmerge

comment:6 Changed 3 years ago by simonpj

Test Case: deriving/should_compile/T12399

comment:7 Changed 3 years ago by Ben Gamari <ben@…>

In 1f862acb/ghc:

Make DeriveFunctor work with unboxed tuples

Summary:
Unboxed tuples have `RuntimeRep` arguments which `-XDeriveFunctor` was
mistaking for actual data constructor arguments. As a result, a derived
`Functor` instance for a datatype that contained an unboxed tuple would
generate twice as many arguments as it needed for an unboxed tuple pattern
match or expression. The solution is to simply put `dropRuntimeRepArgs` in the
right place.

Fixes #12399.

Test Plan: ./validate

Reviewers: austin, hvr, bgamari

Reviewed By: bgamari

Subscribers: thomie, osa1

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

GHC Trac Issues: #12399

(cherry picked from commit 3fa3fe8a9a8afa67829e12efa5d25b76e58a185a)

comment:8 Changed 3 years ago by bgamari

Status: mergeclosed

comment:9 Changed 3 years ago by bgamari

Version: 8.18.0.1

comment:10 Changed 2 years ago by RyanGlScott

Keywords: deriving added
Note: See TracTickets for help on using tickets.