Skip to content

Confusing error when hs-boot abstract data implemented using synonym

This example is a little goofy (that's why I've marked it low priority), but here goes:

-- A.hs-boot
module A where
data T
f :: T -> T

-- B.hs
module B(f) where
import {-# SOURCE #-} A

-- A.hs
module A(T, f) where
    import qualified B
    type T = Int
    f :: T -> T
    f x = B.f x

When compiled, we get a very interesting error:

ezyang@sabre:~$ ghc-head --make A.hs -fforce-recomp
[1 of 3] Compiling A[boot]          ( A.hs-boot, A.o-boot )
[2 of 3] Compiling B                ( B.hs, B.o )
[3 of 3] Compiling A                ( A.hs, A.o )

A.hs-boot:2:1: error:
    Type constructor ‘T’ has conflicting definitions in the module
    and its hs-boot file
    Main module: type T = Int
    Boot file:   abstract T
  |
2 | data T
  | ^^^^^^

A.hs-boot:3:1: error:
    Identifier ‘f’ has conflicting definitions in the module
    and its hs-boot file
    Main module: f :: T -> T
    Boot file:   f :: T -> T
    The two types are different
  |
3 | f :: T -> T
  | ^^^^^^^^^^^

The first error is legitimate, but the second is puzzling. I believe the problem has to do with the fact that when we load the hs-boot file for checking, we knot-tie it against itself. Thus, the T referenced in "Boot file" is the one WITHOUT the type synonym unfolding, while the main module *does* have the type synonym unfolding.

Pretty-printing is horribly confusing in these situations, so it would be nice if we could give some better guidance here.

Trac metadata
Trac field Value
Version 8.1
Type Bug
TypeOfFailure OtherFailure
Priority low
Resolution Unresolved
Component Compiler (Type checker)
Test case
Differential revisions
BlockedBy
Related
Blocking
CC
Operating system
Architecture
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information