From 62ce23f785fc735fa80f563d66db65e48bb0610d Mon Sep 17 00:00:00 2001
From: Jan Stolarek <jan.stolarek@p.lodz.pl>
Date: Sat, 9 Jan 2016 20:58:52 +0100
Subject: [PATCH] Add InjectiveTypeFamilies language extension

Previously injective type families were part of TypeFamilies.
Now they are in a separate language extension.

Test Plan: ./validate

Reviewers: austin, bgamari, goldfire

Reviewed By: bgamari

Subscribers: goldfire, thomie

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

GHC Trac Issues: #11381

(cherry picked from commit fbd6de2f0761b63a5f0a88ce0590f515d63790a4)
---
 compiler/main/DynFlags.hs                                | 4 +++-
 compiler/typecheck/TcTyClsDecls.hs                       | 6 +++++-
 compiler/typecheck/TcValidity.hs                         | 2 +-
 docs/users_guide/glasgow_exts.rst                        | 3 +++
 libraries/ghc-boot/GHC/LanguageExtensions.hs             | 1 +
 testsuite/tests/driver/T11381.hs                         | 9 +++++++++
 testsuite/tests/driver/T11381.stderr                     | 5 +++++
 testsuite/tests/driver/T4437.hs                          | 3 ++-
 testsuite/tests/driver/all.T                             | 1 +
 testsuite/tests/ghci/scripts/T6018ghci.script            | 2 +-
 testsuite/tests/ghci/scripts/T6018ghcifail.script        | 2 +-
 testsuite/tests/ghci/scripts/T6018ghcirnfail.script      | 2 +-
 testsuite/tests/th/T6018th.hs                            | 4 ++--
 testsuite/tests/th/T8884.hs                              | 2 +-
 testsuite/tests/typecheck/should_compile/T6018.hs        | 2 +-
 testsuite/tests/typecheck/should_compile/T6018.hs-boot   | 2 +-
 testsuite/tests/typecheck/should_compile/T6018a.hs       | 2 +-
 testsuite/tests/typecheck/should_fail/T10836.hs          | 2 +-
 testsuite/tests/typecheck/should_fail/T6018Afail.hs      | 2 +-
 testsuite/tests/typecheck/should_fail/T6018Bfail.hs      | 2 +-
 testsuite/tests/typecheck/should_fail/T6018fail.hs       | 2 +-
 testsuite/tests/typecheck/should_fail/T6018failclosed.hs | 4 ++--
 .../tests/typecheck/should_fail/T6018failclosed2.hs      | 2 +-
 utils/mkUserGuidePart/Options/Language.hs                | 8 ++++++++
 24 files changed, 54 insertions(+), 20 deletions(-)
 create mode 100644 testsuite/tests/driver/T11381.hs
 create mode 100644 testsuite/tests/driver/T11381.stderr

diff --git a/compiler/main/DynFlags.hs b/compiler/main/DynFlags.hs
index 3caff6355351..fea441cf21c6 100644
--- a/compiler/main/DynFlags.hs
+++ b/compiler/main/DynFlags.hs
@@ -243,7 +243,7 @@ import qualified GHC.LanguageExtensions as LangExt
 --
 --  * Adding the extension to GHC.LanguageExtensions
 --
---    The LangExt type in libraries/ghc-boot/GHC/LanguageExtensions.hs is
+--    The Extension type in libraries/ghc-boot/GHC/LanguageExtensions.hs is
 --    the canonical list of language extensions known by GHC.
 --
 --  * Adding a flag to DynFlags.xFlags
@@ -3213,6 +3213,7 @@ xFlags = [
   flagSpec "ImpredicativeTypes"               LangExt.ImpredicativeTypes,
   flagSpec' "IncoherentInstances"             LangExt.IncoherentInstances
                                               setIncoherentInsts,
+  flagSpec "InjectiveTypeFamilies"            LangExt.InjectiveTypeFamilies,
   flagSpec "InstanceSigs"                     LangExt.InstanceSigs,
   flagSpec "ApplicativeDo"                    LangExt.ApplicativeDo,
   flagSpec "InterruptibleFFI"                 LangExt.InterruptibleFFI,
@@ -3352,6 +3353,7 @@ impliedXFlags
     , (LangExt.FlexibleInstances,         turnOn, LangExt.TypeSynonymInstances)
     , (LangExt.FunctionalDependencies,    turnOn, LangExt.MultiParamTypeClasses)
     , (LangExt.MultiParamTypeClasses,     turnOn, LangExt.ConstrainedClassMethods)  -- c.f. Trac #7854
+    , (LangExt.InjectiveTypeFamilies,     turnOn, LangExt.TypeFamilies)
 
     , (LangExt.RebindableSyntax, turnOff, LangExt.ImplicitPrelude)      -- NB: turn off!
 
diff --git a/compiler/typecheck/TcTyClsDecls.hs b/compiler/typecheck/TcTyClsDecls.hs
index 4424304a431c..40501a3443a3 100644
--- a/compiler/typecheck/TcTyClsDecls.hs
+++ b/compiler/typecheck/TcTyClsDecls.hs
@@ -834,7 +834,11 @@ tcInjectivity _ Nothing
   -- reason is that the implementation would not be straightforward.)
 tcInjectivity tvs (Just (L loc (InjectivityAnn _ lInjNames)))
   = setSrcSpan loc $
-    do { inj_tvs <- mapM (tcLookupTyVar . unLoc) lInjNames
+    do { dflags <- getDynFlags
+       ; checkTc (xopt LangExt.InjectiveTypeFamilies dflags)
+                 (text "Illegal injectivity annotation" $$
+                  text "Use InjectiveTypeFamilies to allow this")
+       ; inj_tvs <- mapM (tcLookupTyVar . unLoc) lInjNames
        ; let inj_ktvs = filterVarSet isTyVar $  -- no injective coercion vars
                         closeOverKinds (mkVarSet inj_tvs)
        ; let inj_bools = map (`elemVarSet` inj_ktvs) tvs
diff --git a/compiler/typecheck/TcValidity.hs b/compiler/typecheck/TcValidity.hs
index 98b78db4501f..2df092bd4455 100644
--- a/compiler/typecheck/TcValidity.hs
+++ b/compiler/typecheck/TcValidity.hs
@@ -1328,7 +1328,7 @@ checkValidCoAxiom ax@(CoAxiom { co_ax_tc = fam_tc, co_ax_branches = branches })
                         -> CoAxBranch      -- current branch
                         -> TcM [CoAxBranch]-- current branch : previous branches
     -- Check for
-    --   (a) this banch is dominated by previous ones
+    --   (a) this branch is dominated by previous ones
     --   (b) failure of injectivity
     check_branch_compat prev_branches cur_branch
       | cur_branch `isDominatedBy` prev_branches
diff --git a/docs/users_guide/glasgow_exts.rst b/docs/users_guide/glasgow_exts.rst
index 93686602442f..7d37c6386ad6 100644
--- a/docs/users_guide/glasgow_exts.rst
+++ b/docs/users_guide/glasgow_exts.rst
@@ -6764,6 +6764,9 @@ will be possible to infer ``t`` at call sites from the type of the argument: ::
 
     type family Id a = r | r -> a
 
+Injective type families are enabled with ``-XInjectiveTypeFamilies`` language
+extension.  This extension implies ``-XTypeFamilies``.
+
 For full details on injective type families refer to Haskell Symposium
 2015 paper `Injective type families for
 Haskell <http://ics.p.lodz.pl/~stolarek/_media/pl:research:stolarek_peyton-jones_eisenberg_injectivity_extended.pdf>`__.
diff --git a/libraries/ghc-boot/GHC/LanguageExtensions.hs b/libraries/ghc-boot/GHC/LanguageExtensions.hs
index 68455194e651..0ccd59cbb07c 100644
--- a/libraries/ghc-boot/GHC/LanguageExtensions.hs
+++ b/libraries/ghc-boot/GHC/LanguageExtensions.hs
@@ -45,6 +45,7 @@ data Extension
    | UnboxedTuples
    | BangPatterns
    | TypeFamilies
+   | InjectiveTypeFamilies
    | TypeInType
    | OverloadedStrings
    | OverloadedLists
diff --git a/testsuite/tests/driver/T11381.hs b/testsuite/tests/driver/T11381.hs
new file mode 100644
index 000000000000..8dc94dd8a798
--- /dev/null
+++ b/testsuite/tests/driver/T11381.hs
@@ -0,0 +1,9 @@
+{-# LANGUAGE TypeFamilies #-}
+
+module T11381 where
+
+-- ensure that this code does not compile without InjectiveTypeFamilies and that
+-- injectivity error is not reported.
+type family F a = r | r -> a
+type instance F Int = Bool
+type instance F Int = Char
diff --git a/testsuite/tests/driver/T11381.stderr b/testsuite/tests/driver/T11381.stderr
new file mode 100644
index 000000000000..afe652d38e4b
--- /dev/null
+++ b/testsuite/tests/driver/T11381.stderr
@@ -0,0 +1,5 @@
+
+T11381.hs:7:23:
+     Illegal injectivity annotation
+      Use InjectiveTypeFamilies to allow this
+     In the type family declaration for ‘F’
diff --git a/testsuite/tests/driver/T4437.hs b/testsuite/tests/driver/T4437.hs
index 5f14da1a9a0d..cbf71868bdc3 100644
--- a/testsuite/tests/driver/T4437.hs
+++ b/testsuite/tests/driver/T4437.hs
@@ -38,7 +38,8 @@ check title expected got
 expectedGhcOnlyExtensions :: [String]
 expectedGhcOnlyExtensions = ["RelaxedLayout",
                              "AlternativeLayoutRule",
-                             "AlternativeLayoutRuleTransitional"]
+                             "AlternativeLayoutRuleTransitional",
+                             "InjectiveTypeFamilies"]
 
 expectedCabalOnlyExtensions :: [String]
 expectedCabalOnlyExtensions = ["Generics",
diff --git a/testsuite/tests/driver/all.T b/testsuite/tests/driver/all.T
index 8493aa4c5770..e0022d7d6092 100644
--- a/testsuite/tests/driver/all.T
+++ b/testsuite/tests/driver/all.T
@@ -466,3 +466,4 @@ test('T10970', normal, compile_and_run, ['-hide-all-packages -package base -pack
 test('T10970a', normal, compile_and_run, [''])
 test('T4931', normal, compile_and_run, [''])
 test('T11182', normal, compile_and_run, [''])
+test('T11381', normal, compile_fail, [''])
diff --git a/testsuite/tests/ghci/scripts/T6018ghci.script b/testsuite/tests/ghci/scripts/T6018ghci.script
index 4615be2d041e..3b14bd346747 100644
--- a/testsuite/tests/ghci/scripts/T6018ghci.script
+++ b/testsuite/tests/ghci/scripts/T6018ghci.script
@@ -1,4 +1,4 @@
-:set -XTypeFamilies
+:set -XInjectiveTypeFamilies
 :set -XDataKinds
 :set -XUndecidableInstances
 :set -XPolyKinds
diff --git a/testsuite/tests/ghci/scripts/T6018ghcifail.script b/testsuite/tests/ghci/scripts/T6018ghcifail.script
index c0e073457f7a..0e6fe6503335 100644
--- a/testsuite/tests/ghci/scripts/T6018ghcifail.script
+++ b/testsuite/tests/ghci/scripts/T6018ghcifail.script
@@ -1,4 +1,4 @@
-:set -XTypeFamilies
+:set -XInjectiveTypeFamilies
 :set -XDataKinds
 :set -XUndecidableInstances
 :set -XPolyKinds
diff --git a/testsuite/tests/ghci/scripts/T6018ghcirnfail.script b/testsuite/tests/ghci/scripts/T6018ghcirnfail.script
index f1a5fa469a3c..1f3372ebaca6 100644
--- a/testsuite/tests/ghci/scripts/T6018ghcirnfail.script
+++ b/testsuite/tests/ghci/scripts/T6018ghcirnfail.script
@@ -1,4 +1,4 @@
-:set -XTypeFamilies
+:set -XInjectiveTypeFamilies
 :set -XDataKinds
 :set -XUndecidableInstances
 :set -XPolyKinds
diff --git a/testsuite/tests/th/T6018th.hs b/testsuite/tests/th/T6018th.hs
index 62af74383563..1643e9aea5f3 100644
--- a/testsuite/tests/th/T6018th.hs
+++ b/testsuite/tests/th/T6018th.hs
@@ -1,5 +1,5 @@
-{-# LANGUAGE TypeFamilies, DataKinds, UndecidableInstances, PolyKinds #-}
-
+{-# LANGUAGE InjectiveTypeFamilies, DataKinds, UndecidableInstances,
+             PolyKinds #-}
 module T6018th where
 
 import Language.Haskell.TH
diff --git a/testsuite/tests/th/T8884.hs b/testsuite/tests/th/T8884.hs
index 4255f76a4d2f..cad38f9de18b 100644
--- a/testsuite/tests/th/T8884.hs
+++ b/testsuite/tests/th/T8884.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE TemplateHaskell, TypeFamilies, PolyKinds #-}
+{-# LANGUAGE TemplateHaskell, InjectiveTypeFamilies, PolyKinds #-}
 
 module T8884 where
 
diff --git a/testsuite/tests/typecheck/should_compile/T6018.hs b/testsuite/tests/typecheck/should_compile/T6018.hs
index 523bc968d00a..62894c791a03 100644
--- a/testsuite/tests/typecheck/should_compile/T6018.hs
+++ b/testsuite/tests/typecheck/should_compile/T6018.hs
@@ -1,7 +1,7 @@
 {-# LANGUAGE DataKinds                 #-}
 {-# LANGUAGE MultiParamTypeClasses     #-}
 {-# LANGUAGE PolyKinds                 #-}
-{-# LANGUAGE TypeFamilies              #-}
+{-# LANGUAGE InjectiveTypeFamilies     #-}
 {-# LANGUAGE UndecidableInstances      #-}
 {-# LANGUAGE ScopedTypeVariables       #-}
 {-# LANGUAGE NoMonomorphismRestriction #-}
diff --git a/testsuite/tests/typecheck/should_compile/T6018.hs-boot b/testsuite/tests/typecheck/should_compile/T6018.hs-boot
index e31903a3121e..d1cb0687cc2f 100644
--- a/testsuite/tests/typecheck/should_compile/T6018.hs-boot
+++ b/testsuite/tests/typecheck/should_compile/T6018.hs-boot
@@ -1,4 +1,4 @@
-{-# LANGUAGE TypeFamilies, PolyKinds #-}
+{-# LANGUAGE InjectiveTypeFamilies, PolyKinds #-}
 
 module T6018 where
 
diff --git a/testsuite/tests/typecheck/should_compile/T6018a.hs b/testsuite/tests/typecheck/should_compile/T6018a.hs
index beecb57c6588..e1e40bb790f8 100644
--- a/testsuite/tests/typecheck/should_compile/T6018a.hs
+++ b/testsuite/tests/typecheck/should_compile/T6018a.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE InjectiveTypeFamilies #-}
 
 module T6018a where
 
diff --git a/testsuite/tests/typecheck/should_fail/T10836.hs b/testsuite/tests/typecheck/should_fail/T10836.hs
index 00c5c6a650f0..3ad2093c924a 100644
--- a/testsuite/tests/typecheck/should_fail/T10836.hs
+++ b/testsuite/tests/typecheck/should_fail/T10836.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE InjectiveTypeFamilies #-}
 module T10836 where
 
 type family Foo a = r | r -> a where
diff --git a/testsuite/tests/typecheck/should_fail/T6018Afail.hs b/testsuite/tests/typecheck/should_fail/T6018Afail.hs
index 95184a177c08..d0cc076ac691 100644
--- a/testsuite/tests/typecheck/should_fail/T6018Afail.hs
+++ b/testsuite/tests/typecheck/should_fail/T6018Afail.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE InjectiveTypeFamilies #-}
 
 module T6018Afail where
 
diff --git a/testsuite/tests/typecheck/should_fail/T6018Bfail.hs b/testsuite/tests/typecheck/should_fail/T6018Bfail.hs
index ef2460187ff3..2b7b4427693d 100644
--- a/testsuite/tests/typecheck/should_fail/T6018Bfail.hs
+++ b/testsuite/tests/typecheck/should_fail/T6018Bfail.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE InjectiveTypeFamilies #-}
 
 module T6018Bfail where
 
diff --git a/testsuite/tests/typecheck/should_fail/T6018fail.hs b/testsuite/tests/typecheck/should_fail/T6018fail.hs
index ead4dd354fc3..8531c13d9ad7 100644
--- a/testsuite/tests/typecheck/should_fail/T6018fail.hs
+++ b/testsuite/tests/typecheck/should_fail/T6018fail.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE TypeFamilies, DataKinds, UndecidableInstances, PolyKinds,
+{-# LANGUAGE InjectiveTypeFamilies, DataKinds, UndecidableInstances, PolyKinds,
              MultiParamTypeClasses, FlexibleInstances #-}
 
 module T6018fail where
diff --git a/testsuite/tests/typecheck/should_fail/T6018failclosed.hs b/testsuite/tests/typecheck/should_fail/T6018failclosed.hs
index a69c63f7e5c1..eed5d033fb5d 100644
--- a/testsuite/tests/typecheck/should_fail/T6018failclosed.hs
+++ b/testsuite/tests/typecheck/should_fail/T6018failclosed.hs
@@ -1,5 +1,5 @@
-{-# LANGUAGE TypeFamilies, DataKinds, PolyKinds, UndecidableInstances #-}
-
+{-# LANGUAGE InjectiveTypeFamilies, DataKinds, PolyKinds,
+             UndecidableInstances #-}
 module T6018failclosed where
 
 -- Id is injective...
diff --git a/testsuite/tests/typecheck/should_fail/T6018failclosed2.hs b/testsuite/tests/typecheck/should_fail/T6018failclosed2.hs
index d90b9decfc0f..323b16fde34c 100644
--- a/testsuite/tests/typecheck/should_fail/T6018failclosed2.hs
+++ b/testsuite/tests/typecheck/should_fail/T6018failclosed2.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE TypeFamilies  #-}
+{-# LANGUAGE InjectiveTypeFamilies  #-}
 
 module T6018failclosed2 where
 
diff --git a/utils/mkUserGuidePart/Options/Language.hs b/utils/mkUserGuidePart/Options/Language.hs
index 0fc3ea5f2520..ddd05ea13f1f 100644
--- a/utils/mkUserGuidePart/Options/Language.hs
+++ b/utils/mkUserGuidePart/Options/Language.hs
@@ -340,6 +340,14 @@ languageOptions =
          , flagReverse = "-XNoIncoherentInstances"
          , flagSince = "6.8.1"
          }
+  , flag { flagName = "-XInjectiveTypeFamilies"
+         , flagDescription =
+           "Enable :ref:`injective type families <injective-ty-fams>`. "++
+           "Implies ``-XTypeFamilies``."
+         , flagType = DynamicFlag
+         , flagReverse = "-XNoInjectiveTypeFamilies"
+         , flagSince = "8.0.1"
+         }
   , flag { flagName = "-XInstanceSigs"
          , flagDescription =
            "Enable :ref:`instance signatures <instance-sigs>`."
-- 
GitLab