Opened 3 years ago

Last modified 11 months ago

#12643 new bug

class declaration works in ghci, but not in a file

Reported by: dmwit Owned by:
Priority: normal Milestone:
Component: Compiler Version: 8.0.1
Keywords: Cc: RyanGlScott
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: None/Unknown Test Case:
Blocked By: Blocking:
Related Tickets: #12088, #14668, #15561, #15987 Differential Rev(s):
Wiki Page:

Description

The following ghci session prints no errors:

> :set -XStandaloneDeriving -XDeriveGeneric
> import GHC.Generics
> import Control.Monad.Except
> deriving instance Generic (ExceptT e m a)
> class F a where f :: Rep (Except String a) x

However, when I transfer this to a file:

{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE DeriveGeneric #-}
import GHC.Generics
import Control.Monad.Except
deriving instance Generic (ExceptT e m a)
class F a where f :: Rep (Except String a) x

I get a mysterious error:

test.hs:6:17: error:
    • Couldn't match type ‘Rep (Except String a0)’
                     with ‘Rep (Except String a)’
      Expected type: Rep (Except String a) x
        Actual type: Rep (Except String a0) x
      NB: ‘Rep’ is a type function, and may not be injective
      The type variable ‘a0’ is ambiguous
    • In the ambiguity check for ‘f’
      To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
      When checking the class method:
        f :: forall a. F a => forall x. Rep (Except String a) x
      In the class declaration for ‘F’

If I turn on -fdefer-type-errors, I can verify that the type family indeed reduces far enough for a and x to be arguments to injective types, so I believe GHC should not consider this an error:

> :set -XRankNTypes
> :kind! forall a x. Rep (Except String a) x
forall a x. Rep (Except String a) x :: *
= D1
    ('MetaData
       "ExceptT"
       "Control.Monad.Trans.Except"
       "transformers-0.5.2.0"
       'True)
    (C1
       ('MetaCons "ExceptT" 'PrefixI 'False)
       (S1
          ('MetaSel
             'Nothing 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy)
          (Rec0 (Data.Functor.Identity.Identity (Either [Char] a)))))
    x

Change History (3)

comment:1 Changed 3 years ago by simonpj

Crumbs. This is another variation of #11348, and its as-yet-unsolved cousin #12088.

In this case, we must type check in this order:

  1. deriving instance Generic (ExceptT e m a). This generates a type instance Rep (Except e m a) = ... declaration, for Generic's associated type Rep.
  1. class F a where .... We must do this second because f's type can be seen to be unambiguous only after expanding the call to Rep.

However the fix to #11348 arranges to interleave type instance declarations with type/class decls; but deriving instance declarations are still left to the end. The fix is, I think, to include deriving instance decls in the interleaving.

Workaround for now: make the staging explicit with a degenerate Template Haskell splice, thus:

deriving instance Generic (ExceptT e m a)

$( return [] )    -- Degenerate splice

class F a where f :: Rep (Except String a) x

comment:2 Changed 2 years ago by RyanGlScott

Cc: RyanGlScott added

comment:3 Changed 11 months ago by RyanGlScott

Note: See TracTickets for help on using tickets.