Skip to content

Closed type family declaration accepts any name in LHS

Summary

Closed type family declaration will accept (almost) any name instead of family's name left of =.

Steps to reproduce

{-# LANGUAGE TypeFamilies #-}

module WTF where

type family Bar (a :: *) :: * where
  Bar Int = ()


type family Foo (a :: *) :: * where
  Bar Int = Bool
  Bar Bool = Int
  Bar a = a

When loaded to ghci, this file not only compiles, but works as if Foo were defined the normal way:

λ> :kind! Bar Int
Bar Int :: *
= ()
λ> :kind! Bar Bool
Bar Bool :: *
= Bar Bool
λ> :kind! Foo Int
Foo Int :: *
= Bool
λ> :kind! Foo Bool
Foo Bool :: *
= Int
λ> :kind! Foo Char
Foo Char :: *
= Char

It's clear that Foo is defined as it should be and that Bar is not broken by this definition.

Expected behavior

GHC should emit an error in this case, as this code seems very strange.

Curiously, if Bar is not in scope GHC detects an error at Foo's definition:

<interactive>:5:3: error:
    Not in scope: type constructor or class ‘Bar’

Moreover, if I try to use some family from another module, it fails as well:

> import GHC.Generics
> :{
| type family Foo (a :: *) where
|   Rep Bool = Maybe
| :}
<interactive>:6:3: error:
    • Mismatched type name in type family instance.
        Expected: Foo
          Actual: Rep

Environment

  • GHC version used:
$ stack exec -- ghc -V
The Glorious Glasgow Haskell Compilation System, version 8.6.3
  • Operating System: macOS
Edited by Ben Gamari
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information