[GHC] #10270: inconsistent semantics of type class instance visibility outside recursive modules

GHC ghc-devs at haskell.org
Wed Apr 8 18:12:01 UTC 2015


#10270: inconsistent semantics of type class instance visibility outside recursive
modules
-------------------------------------+-------------------------------------
              Reporter:  skilpat     |             Owner:
                  Type:  bug         |            Status:  new
              Priority:  normal      |         Milestone:
             Component:  Compiler    |           Version:  7.10.1
              Keywords:              |  Operating System:  MacOS X
          Architecture:  x86_64      |   Type of failure:  GHC rejects
  (amd64)                            |  valid program
             Test Case:              |        Blocked By:
              Blocking:              |   Related Tickets:
Differential Revisions:              |
-------------------------------------+-------------------------------------
 When you have an instance defined in a module that's part of a recursive
 module loop, when should modules outside the loop see it? Right now, GHC
 behaves differently depending on whether it's in batch or in single-shot
 compilation mode. Which one is correct? Dunno!

 Here's the example (code at the bottom). The gist is that you have two
 modules A and B that define data types T and U, respectively, which depend
 on each other, so A and B are recursive modules and we need a boot file --
 say, for A.

 Now suppose we define an instance Eq T in the implementation of A but not
 in the boot file. B imports the boot file, so it doesn't know about this
 instance. And then I have some third module, Main, outside the loop, which
 imports only B. And now the central question: ''Does Main know about the
 Eq T defined in A?''

 We can test how GHC answers this question by defining an (orphan) instance
 for Eq T in Main. In batch compilation mode, Main is rejected for defining
 a duplicate instance. In single-shot compilation mode, however, Main is
 accepted and any equality test in Main uses the locally defined instance;
 i.e., B doesn't know about A's Eq T and so neither does Main.

 So which is correct? If you ask me, the latter semantics is correct, but I
 can see why the former might be argued as well (e.g., according to the
 fixed-point semantics of import/export described in (1)). In any case, the
 semantics between the two compilation modes should probably agree, right?

 {{{#!hs
 -- A.hs-boot
 module A where
   data T -- a mutually recursive data type, along with B.U
   t :: T -- some value to test for Eq in Main


 -- B.hs
 module B(module A, module B) where
   -- export A.{T,t} since Main doesn't import A

   import {-# SOURCE #-} A

   -- mutually recursive data type across modules
   data U = U | UT T


 -- A.hs
 module A where
   import B

   -- mutually recursive data type across modules
   data T = T | TU U

   -- the true instance
   instance Eq T where
     _ == _ = True

   -- some value to test Eq instance in Main
   t :: T
   t = T


 -- Main.hs
 module Main where
   import B -- no import of A

   -- an orphan instance for Eq T.
   -- okay in one-shot mode; not okay in batch (--make) mode
   instance Eq T where
     _ == _ = False

   -- in one-shot mode, this prints False
   main = putStrLn $ show $ t == t
 }}}

 Commands and output for batch mode:
 {{{
 $ ghc --make Main
 [1 of 4] Compiling A[boot]          ( A.hs-boot, A.o-boot )
 [2 of 4] Compiling B                ( B.hs, B.o )
 [3 of 4] Compiling A                ( A.hs, A.o )
 [4 of 4] Compiling Main             ( Main.hs, Main.o )

 A.hs:8:10:
     Duplicate instance declarations:
       instance Eq T -- Defined at A.hs:8:10
       instance Eq T -- Defined at Main.hs:7:10
 }}}

 Commands and output for single-shot mode:
 {{{
 $ ghc -c A.hs-boot
 $ ghc -c B.hs
 $ ghc -c A.hs
 $ ghc -c Main.hs
 $ ghc A.o B.o Main.o -o main
 $ ./main
 False
 }}}

 Tested on GHC 7.6.3, 7.8.3, and 7.10.1.

 (1) ''A Formal Specification for the Haskell 98 Module System''. Iavor S.
 Diatchki, Mark P. Jones, and Thomas Hallgren. Haskell '02.
 http://web.cecs.pdx.edu/~mpj/pubs/hsmods.pdf

--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/10270>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler


More information about the ghc-tickets mailing list