From d90d0bade05fa63b81fe68d42c4242dd97c46e77 Mon Sep 17 00:00:00 2001
From: Ben Gamari <ben@smart-cactus.org>
Date: Mon, 16 Sep 2019 10:51:08 -0400
Subject: [PATCH] base: Move Ix typeclass to GHC.Ix

The `Ix` class seems rather orthogonal to its original home in
`GHC.Arr`.
---
 compiler/prelude/PrelNames.hs                 |  16 +-
 libraries/base/Data/Functor/Const.hs          |   2 +-
 libraries/base/Data/Functor/Identity.hs       |   2 +-
 libraries/base/Data/Ix.hs                     |   2 +-
 libraries/base/Data/Ord.hs                    |   2 +-
 libraries/base/GHC/Arr.hs                     | 326 +---------------
 libraries/base/GHC/Generics.hs                |   2 +-
 libraries/base/GHC/Ix.hs                      | 348 ++++++++++++++++++
 libraries/base/GHC/Unicode.hs                 |   2 +-
 libraries/base/GHC/Word.hs                    |   2 +-
 libraries/base/base.cabal                     |   1 +
 .../deriving/should_compile/T14682.stderr     |  34 +-
 testsuite/tests/ghci/scripts/ghci064.stdout   |   2 +-
 13 files changed, 383 insertions(+), 358 deletions(-)
 create mode 100644 libraries/base/GHC/Ix.hs

diff --git a/compiler/prelude/PrelNames.hs b/compiler/prelude/PrelNames.hs
index a889f703631..2acb2a00191 100644
--- a/compiler/prelude/PrelNames.hs
+++ b/compiler/prelude/PrelNames.hs
@@ -504,7 +504,7 @@ gHC_PRIM, gHC_TYPES, gHC_GENERICS, gHC_MAGIC,
     gHC_LIST, gHC_TUPLE, dATA_TUPLE, dATA_EITHER, dATA_STRING,
     dATA_FOLDABLE, dATA_TRAVERSABLE,
     gHC_CONC, gHC_IO, gHC_IO_Exception,
-    gHC_ST, gHC_ARR, gHC_STABLE, gHC_PTR, gHC_ERR, gHC_REAL,
+    gHC_ST, gHC_IX, gHC_STABLE, gHC_PTR, gHC_ERR, gHC_REAL,
     gHC_FLOAT, gHC_TOP_HANDLER, sYSTEM_IO, dYNAMIC,
     tYPEABLE, tYPEABLE_INTERNAL, gENERICS,
     rEAD_PREC, lEX, gHC_INT, gHC_WORD, mONAD, mONAD_FIX, mONAD_ZIP, mONAD_FAIL,
@@ -540,7 +540,7 @@ gHC_CONC        = mkBaseModule (fsLit "GHC.Conc")
 gHC_IO          = mkBaseModule (fsLit "GHC.IO")
 gHC_IO_Exception = mkBaseModule (fsLit "GHC.IO.Exception")
 gHC_ST          = mkBaseModule (fsLit "GHC.ST")
-gHC_ARR         = mkBaseModule (fsLit "GHC.Arr")
+gHC_IX          = mkBaseModule (fsLit "GHC.Ix")
 gHC_STABLE      = mkBaseModule (fsLit "GHC.Stable")
 gHC_PTR         = mkBaseModule (fsLit "GHC.Ptr")
 gHC_ERR         = mkBaseModule (fsLit "GHC.Err")
@@ -750,11 +750,11 @@ succ_RDR                = varQual_RDR gHC_ENUM (fsLit "succ")
 pred_RDR                = varQual_RDR gHC_ENUM (fsLit "pred")
 minBound_RDR            = varQual_RDR gHC_ENUM (fsLit "minBound")
 maxBound_RDR            = varQual_RDR gHC_ENUM (fsLit "maxBound")
-range_RDR               = varQual_RDR gHC_ARR (fsLit "range")
-inRange_RDR             = varQual_RDR gHC_ARR (fsLit "inRange")
-index_RDR               = varQual_RDR gHC_ARR (fsLit "index")
-unsafeIndex_RDR         = varQual_RDR gHC_ARR (fsLit "unsafeIndex")
-unsafeRangeSize_RDR     = varQual_RDR gHC_ARR (fsLit "unsafeRangeSize")
+range_RDR               = varQual_RDR gHC_IX (fsLit "range")
+inRange_RDR             = varQual_RDR gHC_IX (fsLit "inRange")
+index_RDR               = varQual_RDR gHC_IX (fsLit "index")
+unsafeIndex_RDR         = varQual_RDR gHC_IX (fsLit "unsafeIndex")
+unsafeRangeSize_RDR     = varQual_RDR gHC_IX (fsLit "unsafeRangeSize")
 
 readList_RDR, readListDefault_RDR, readListPrec_RDR, readListPrecDefault_RDR,
     readPrec_RDR, parens_RDR, choose_RDR, lexP_RDR, expectP_RDR :: RdrName
@@ -1214,7 +1214,7 @@ rationalToDoubleName = varQual gHC_FLOAT (fsLit "rationalToDouble") rationalToDo
 
 -- Class Ix
 ixClassName :: Name
-ixClassName = clsQual gHC_ARR (fsLit "Ix") ixClassKey
+ixClassName = clsQual gHC_IX (fsLit "Ix") ixClassKey
 
 -- Typeable representation types
 trModuleTyConName
diff --git a/libraries/base/Data/Functor/Const.hs b/libraries/base/Data/Functor/Const.hs
index 4e4992dcf6c..651041f15b6 100644
--- a/libraries/base/Data/Functor/Const.hs
+++ b/libraries/base/Data/Functor/Const.hs
@@ -25,7 +25,7 @@ import Data.Bits (Bits, FiniteBits)
 import Data.Foldable (Foldable(foldMap))
 import Foreign.Storable (Storable)
 
-import GHC.Arr (Ix)
+import GHC.Ix (Ix)
 import GHC.Base
 import GHC.Enum (Bounded, Enum)
 import GHC.Float (Floating, RealFloat)
diff --git a/libraries/base/Data/Functor/Identity.hs b/libraries/base/Data/Functor/Identity.hs
index daaa3a450c8..0709393616a 100644
--- a/libraries/base/Data/Functor/Identity.hs
+++ b/libraries/base/Data/Functor/Identity.hs
@@ -41,7 +41,7 @@ import Data.Coerce
 import Data.Foldable
 import Data.Functor.Utils ((#.))
 import Foreign.Storable (Storable)
-import GHC.Arr (Ix)
+import GHC.Ix (Ix)
 import GHC.Base ( Applicative(..), Eq(..), Functor(..), Monad(..)
                 , Semigroup, Monoid, Ord(..), ($), (.) )
 import GHC.Enum (Bounded, Enum)
diff --git a/libraries/base/Data/Ix.hs b/libraries/base/Data/Ix.hs
index 0171431f453..79f0805b841 100644
--- a/libraries/base/Data/Ix.hs
+++ b/libraries/base/Data/Ix.hs
@@ -61,4 +61,4 @@ module Data.Ix
 
     ) where
 
-import GHC.Arr
+import GHC.Ix
diff --git a/libraries/base/Data/Ord.hs b/libraries/base/Data/Ord.hs
index 4ccfa7c6b48..8703c7bdc0d 100644
--- a/libraries/base/Data/Ord.hs
+++ b/libraries/base/Data/Ord.hs
@@ -25,7 +25,7 @@ module Data.Ord (
 
 import Data.Bits (Bits, FiniteBits)
 import Foreign.Storable (Storable)
-import GHC.Arr (Ix)
+import GHC.Ix (Ix)
 import GHC.Base
 import GHC.Enum (Bounded, Enum)
 import GHC.Float (Floating, RealFloat)
diff --git a/libraries/base/GHC/Arr.hs b/libraries/base/GHC/Arr.hs
index 730f2205b51..06951d38510 100644
--- a/libraries/base/GHC/Arr.hs
+++ b/libraries/base/GHC/Arr.hs
@@ -20,7 +20,6 @@
 module GHC.Arr (
         Ix(..), Array(..), STArray(..),
 
-        indexError, hopelessIndexError,
         arrEleBottom, array, listArray,
         (!), safeRangeSize, negRange, safeIndex, badSafeIndex,
         bounds, numElements, numElementsSTArray, indices, elems,
@@ -42,340 +41,17 @@ module GHC.Arr (
         unsafeFreezeSTArray, unsafeThawSTArray,
     ) where
 
-import GHC.Enum
 import GHC.Num
 import GHC.ST
 import GHC.Base
 import GHC.List
-import GHC.Real( fromIntegral )
+import GHC.Ix
 import GHC.Show
 
 infixl 9  !, //
 
 default ()
 
--- | The 'Ix' class is used to map a contiguous subrange of values in
--- a type onto integers.  It is used primarily for array indexing
--- (see the array package).
---
--- The first argument @(l,u)@ of each of these operations is a pair
--- specifying the lower and upper bounds of a contiguous subrange of values.
---
--- An implementation is entitled to assume the following laws about these
--- operations:
---
--- * @'inRange' (l,u) i == 'elem' i ('range' (l,u))@ @ @
---
--- * @'range' (l,u) '!!' 'index' (l,u) i == i@, when @'inRange' (l,u) i@
---
--- * @'map' ('index' (l,u)) ('range' (l,u))) == [0..'rangeSize' (l,u)-1]@ @ @
---
--- * @'rangeSize' (l,u) == 'length' ('range' (l,u))@ @ @
---
-class (Ord a) => Ix a where
-    {-# MINIMAL range, (index | unsafeIndex), inRange #-}
-
-    -- | The list of values in the subrange defined by a bounding pair.
-    range               :: (a,a) -> [a]
-    -- | The position of a subscript in the subrange.
-    index               :: (a,a) -> a -> Int
-    -- | Like 'index', but without checking that the value is in range.
-    unsafeIndex         :: (a,a) -> a -> Int
-    -- | Returns 'True' the given subscript lies in the range defined
-    -- the bounding pair.
-    inRange             :: (a,a) -> a -> Bool
-    -- | The size of the subrange defined by a bounding pair.
-    rangeSize           :: (a,a) -> Int
-    -- | like 'rangeSize', but without checking that the upper bound is
-    -- in range.
-    unsafeRangeSize     :: (a,a) -> Int
-
-        -- Must specify one of index, unsafeIndex
-
-        -- 'index' is typically over-ridden in instances, with essentially
-        -- the same code, but using indexError instead of hopelessIndexError
-        -- Reason: we have 'Show' at the instances
-    {-# INLINE index #-}  -- See Note [Inlining index]
-    index b i | inRange b i = unsafeIndex b i
-              | otherwise   = hopelessIndexError
-
-    unsafeIndex b i = index b i
-
-    rangeSize b@(_l,h) | inRange b h = unsafeIndex b h + 1
-                       | otherwise   = 0        -- This case is only here to
-                                                -- check for an empty range
-        -- NB: replacing (inRange b h) by (l <= h) fails for
-        --     tuples.  E.g.  (1,2) <= (2,1) but the range is empty
-
-    unsafeRangeSize b@(_l,h) = unsafeIndex b h + 1
-
-{-
-Note that the following is NOT right
-        rangeSize (l,h) | l <= h    = index b h + 1
-                        | otherwise = 0
-
-Because it might be the case that l<h, but the range
-is nevertheless empty.  Consider
-        ((1,2),(2,1))
-Here l<h, but the second index ranges from 2..1 and
-hence is empty
-
-
-Note [Inlining index]
-~~~~~~~~~~~~~~~~~~~~~
-We inline the 'index' operation,
-
- * Partly because it generates much faster code
-   (although bigger); see #1216
-
- * Partly because it exposes the bounds checks to the simplifier which
-   might help a big.
-
-If you make a per-instance index method, you may consider inlining it.
-
-Note [Double bounds-checking of index values]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-When you index an array, a!x, there are two possible bounds checks we might make:
-
-  (A) Check that (inRange (bounds a) x) holds.
-
-      (A) is checked in the method for 'index'
-
-  (B) Check that (index (bounds a) x) lies in the range 0..n,
-      where n is the size of the underlying array
-
-      (B) is checked in the top-level function (!), in safeIndex.
-
-Of course it *should* be the case that (A) holds iff (B) holds, but that
-is a property of the particular instances of index, bounds, and inRange,
-so GHC cannot guarantee it.
-
- * If you do (A) and not (B), then you might get a seg-fault,
-   by indexing at some bizarre location.  #1610
-
- * If you do (B) but not (A), you may get no complaint when you index
-   an array out of its semantic bounds.  #2120
-
-At various times we have had (A) and not (B), or (B) and not (A); both
-led to complaints.  So now we implement *both* checks (#2669).
-
-For 1-d, 2-d, and 3-d arrays of Int we have specialised instances to avoid this.
-
-Note [Out-of-bounds error messages]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-The default method for 'index' generates hoplelessIndexError, because
-Ix doesn't have Show as a superclass.  For particular base types we
-can do better, so we override the default method for index.
--}
-
--- Abstract these errors from the relevant index functions so that
--- the guts of the function will be small enough to inline.
-
-{-# NOINLINE indexError #-}
-indexError :: Show a => (a,a) -> a -> String -> b
-indexError rng i tp
-  = errorWithoutStackTrace (showString "Ix{" . showString tp . showString "}.index: Index " .
-           showParen True (showsPrec 0 i) .
-           showString " out of range " $
-           showParen True (showsPrec 0 rng) "")
-
-hopelessIndexError :: Int -- Try to use 'indexError' instead!
-hopelessIndexError = errorWithoutStackTrace "Error in array index"
-
-----------------------------------------------------------------------
--- | @since 2.01
-instance  Ix Char  where
-    {-# INLINE range #-}
-    range (m,n) = [m..n]
-
-    {-# INLINE unsafeIndex #-}
-    unsafeIndex (m,_n) i = fromEnum i - fromEnum m
-
-    {-# INLINE index #-}  -- See Note [Out-of-bounds error messages]
-                          -- and Note [Inlining index]
-    index b i | inRange b i =  unsafeIndex b i
-              | otherwise   =  indexError b i "Char"
-
-    inRange (m,n) i     =  m <= i && i <= n
-
-----------------------------------------------------------------------
--- | @since 2.01
-instance  Ix Int  where
-    {-# INLINE range #-}
-        -- The INLINE stops the build in the RHS from getting inlined,
-        -- so that callers can fuse with the result of range
-    range (m,n) = [m..n]
-
-    {-# INLINE unsafeIndex #-}
-    unsafeIndex (m,_n) i = i - m
-
-    {-# INLINE index #-}  -- See Note [Out-of-bounds error messages]
-                          -- and Note [Inlining index]
-    index b i | inRange b i =  unsafeIndex b i
-              | otherwise   =  indexError b i "Int"
-
-    {-# INLINE inRange #-}
-    inRange (I# m,I# n) (I# i) =  isTrue# (m <=# i) && isTrue# (i <=# n)
-
--- | @since 4.6.0.0
-instance Ix Word where
-    range (m,n)         = [m..n]
-    unsafeIndex (m,_) i = fromIntegral (i - m)
-    inRange (m,n) i     = m <= i && i <= n
-
-----------------------------------------------------------------------
--- | @since 2.01
-instance  Ix Integer  where
-    {-# INLINE range #-}
-    range (m,n) = [m..n]
-
-    {-# INLINE unsafeIndex #-}
-    unsafeIndex (m,_n) i   = fromInteger (i - m)
-
-    {-# INLINE index #-}  -- See Note [Out-of-bounds error messages]
-                          -- and Note [Inlining index]
-    index b i | inRange b i =  unsafeIndex b i
-              | otherwise   =  indexError b i "Integer"
-
-    inRange (m,n) i     =  m <= i && i <= n
-
-----------------------------------------------------------------------
--- | @since 4.8.0.0
-instance Ix Natural where
-    range (m,n) = [m..n]
-    inRange (m,n) i = m <= i && i <= n
-    unsafeIndex (m,_) i = fromIntegral (i-m)
-    index b i | inRange b i = unsafeIndex b i
-              | otherwise   = indexError b i "Natural"
-
-----------------------------------------------------------------------
--- | @since 2.01
-instance Ix Bool where -- as derived
-    {-# INLINE range #-}
-    range (m,n) = [m..n]
-
-    {-# INLINE unsafeIndex #-}
-    unsafeIndex (l,_) i = fromEnum i - fromEnum l
-
-    {-# INLINE index #-}  -- See Note [Out-of-bounds error messages]
-                          -- and Note [Inlining index]
-    index b i | inRange b i =  unsafeIndex b i
-              | otherwise   =  indexError b i "Bool"
-
-    inRange (l,u) i = fromEnum i >= fromEnum l && fromEnum i <= fromEnum u
-
-----------------------------------------------------------------------
--- | @since 2.01
-instance Ix Ordering where -- as derived
-    {-# INLINE range #-}
-    range (m,n) = [m..n]
-
-    {-# INLINE unsafeIndex #-}
-    unsafeIndex (l,_) i = fromEnum i - fromEnum l
-
-    {-# INLINE index #-}  -- See Note [Out-of-bounds error messages]
-                          -- and Note [Inlining index]
-    index b i | inRange b i =  unsafeIndex b i
-              | otherwise   =  indexError b i "Ordering"
-
-    inRange (l,u) i = fromEnum i >= fromEnum l && fromEnum i <= fromEnum u
-
-----------------------------------------------------------------------
--- | @since 2.01
-instance Ix () where
-    {-# INLINE range #-}
-    range   ((), ())    = [()]
-    {-# INLINE unsafeIndex #-}
-    unsafeIndex   ((), ()) () = 0
-    {-# INLINE inRange #-}
-    inRange ((), ()) () = True
-
-    {-# INLINE index #-}  -- See Note [Inlining index]
-    index b i = unsafeIndex b i
-
-----------------------------------------------------------------------
--- | @since 2.01
-instance (Ix a, Ix b) => Ix (a, b) where -- as derived
-    {-# SPECIALISE instance Ix (Int,Int) #-}
-
-    {-# INLINE range #-}
-    range ((l1,l2),(u1,u2)) =
-      [ (i1,i2) | i1 <- range (l1,u1), i2 <- range (l2,u2) ]
-
-    {-# INLINE unsafeIndex #-}
-    unsafeIndex ((l1,l2),(u1,u2)) (i1,i2) =
-      unsafeIndex (l1,u1) i1 * unsafeRangeSize (l2,u2) + unsafeIndex (l2,u2) i2
-
-    {-# INLINE inRange #-}
-    inRange ((l1,l2),(u1,u2)) (i1,i2) =
-      inRange (l1,u1) i1 && inRange (l2,u2) i2
-
-    -- Default method for index
-
-----------------------------------------------------------------------
--- | @since 2.01
-instance  (Ix a1, Ix a2, Ix a3) => Ix (a1,a2,a3)  where
-    {-# SPECIALISE instance Ix (Int,Int,Int) #-}
-
-    range ((l1,l2,l3),(u1,u2,u3)) =
-        [(i1,i2,i3) | i1 <- range (l1,u1),
-                      i2 <- range (l2,u2),
-                      i3 <- range (l3,u3)]
-
-    unsafeIndex ((l1,l2,l3),(u1,u2,u3)) (i1,i2,i3) =
-      unsafeIndex (l3,u3) i3 + unsafeRangeSize (l3,u3) * (
-      unsafeIndex (l2,u2) i2 + unsafeRangeSize (l2,u2) * (
-      unsafeIndex (l1,u1) i1))
-
-    inRange ((l1,l2,l3),(u1,u2,u3)) (i1,i2,i3) =
-      inRange (l1,u1) i1 && inRange (l2,u2) i2 &&
-      inRange (l3,u3) i3
-
-    -- Default method for index
-
-----------------------------------------------------------------------
--- | @since 2.01
-instance  (Ix a1, Ix a2, Ix a3, Ix a4) => Ix (a1,a2,a3,a4)  where
-    range ((l1,l2,l3,l4),(u1,u2,u3,u4)) =
-      [(i1,i2,i3,i4) | i1 <- range (l1,u1),
-                       i2 <- range (l2,u2),
-                       i3 <- range (l3,u3),
-                       i4 <- range (l4,u4)]
-
-    unsafeIndex ((l1,l2,l3,l4),(u1,u2,u3,u4)) (i1,i2,i3,i4) =
-      unsafeIndex (l4,u4) i4 + unsafeRangeSize (l4,u4) * (
-      unsafeIndex (l3,u3) i3 + unsafeRangeSize (l3,u3) * (
-      unsafeIndex (l2,u2) i2 + unsafeRangeSize (l2,u2) * (
-      unsafeIndex (l1,u1) i1)))
-
-    inRange ((l1,l2,l3,l4),(u1,u2,u3,u4)) (i1,i2,i3,i4) =
-      inRange (l1,u1) i1 && inRange (l2,u2) i2 &&
-      inRange (l3,u3) i3 && inRange (l4,u4) i4
-
-    -- Default method for index
--- | @since 2.01
-instance  (Ix a1, Ix a2, Ix a3, Ix a4, Ix a5) => Ix (a1,a2,a3,a4,a5)  where
-    range ((l1,l2,l3,l4,l5),(u1,u2,u3,u4,u5)) =
-      [(i1,i2,i3,i4,i5) | i1 <- range (l1,u1),
-                          i2 <- range (l2,u2),
-                          i3 <- range (l3,u3),
-                          i4 <- range (l4,u4),
-                          i5 <- range (l5,u5)]
-
-    unsafeIndex ((l1,l2,l3,l4,l5),(u1,u2,u3,u4,u5)) (i1,i2,i3,i4,i5) =
-      unsafeIndex (l5,u5) i5 + unsafeRangeSize (l5,u5) * (
-      unsafeIndex (l4,u4) i4 + unsafeRangeSize (l4,u4) * (
-      unsafeIndex (l3,u3) i3 + unsafeRangeSize (l3,u3) * (
-      unsafeIndex (l2,u2) i2 + unsafeRangeSize (l2,u2) * (
-      unsafeIndex (l1,u1) i1))))
-
-    inRange ((l1,l2,l3,l4,l5),(u1,u2,u3,u4,u5)) (i1,i2,i3,i4,i5) =
-      inRange (l1,u1) i1 && inRange (l2,u2) i2 &&
-      inRange (l3,u3) i3 && inRange (l4,u4) i4 &&
-      inRange (l5,u5) i5
-
-    -- Default method for index
-
 -- | The type of immutable non-strict (boxed) arrays
 -- with indices in @i@ and elements in @e@.
 data Array i e
diff --git a/libraries/base/GHC/Generics.hs b/libraries/base/GHC/Generics.hs
index 0492464d2b7..56fca9b5a25 100644
--- a/libraries/base/GHC/Generics.hs
+++ b/libraries/base/GHC/Generics.hs
@@ -736,7 +736,7 @@ import GHC.Ptr     ( Ptr )
 import GHC.Types
 
 -- Needed for instances
-import GHC.Arr     ( Ix )
+import GHC.Ix      ( Ix )
 import GHC.Base    ( Alternative(..), Applicative(..), Functor(..)
                    , Monad(..), MonadPlus(..), NonEmpty(..), String, coerce
                    , Semigroup(..), Monoid(..) )
diff --git a/libraries/base/GHC/Ix.hs b/libraries/base/GHC/Ix.hs
new file mode 100644
index 00000000000..efd64670bb0
--- /dev/null
+++ b/libraries/base/GHC/Ix.hs
@@ -0,0 +1,348 @@
+{-# LANGUAGE NoImplicitPrelude, MagicHash, UnboxedTuples #-}
+{-# OPTIONS_HADDOCK not-home #-}
+
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  GHC.Ix
+-- Copyright   :  (c) The University of Glasgow, 1994-2000
+-- License     :  see libraries/base/LICENSE
+--
+-- Maintainer  :  cvs-ghc@haskell.org
+-- Stability   :  internal
+-- Portability :  non-portable (GHC extensions)
+--
+-- GHC\'s Ix typeclass implementation.
+--
+-----------------------------------------------------------------------------
+
+module GHC.Ix (
+        Ix(..)
+    ) where
+
+import GHC.Enum
+import GHC.Num
+import GHC.Base
+import GHC.Real( fromIntegral )
+import GHC.Show
+
+-- | The 'Ix' class is used to map a contiguous subrange of values in
+-- a type onto integers.  It is used primarily for array indexing
+-- (see the array package).
+--
+-- The first argument @(l,u)@ of each of these operations is a pair
+-- specifying the lower and upper bounds of a contiguous subrange of values.
+--
+-- An implementation is entitled to assume the following laws about these
+-- operations:
+--
+-- * @'inRange' (l,u) i == 'elem' i ('range' (l,u))@ @ @
+--
+-- * @'range' (l,u) '!!' 'index' (l,u) i == i@, when @'inRange' (l,u) i@
+--
+-- * @'map' ('index' (l,u)) ('range' (l,u))) == [0..'rangeSize' (l,u)-1]@ @ @
+--
+-- * @'rangeSize' (l,u) == 'length' ('range' (l,u))@ @ @
+--
+class (Ord a) => Ix a where
+    {-# MINIMAL range, (index | unsafeIndex), inRange #-}
+
+    -- | The list of values in the subrange defined by a bounding pair.
+    range               :: (a,a) -> [a]
+    -- | The position of a subscript in the subrange.
+    index               :: (a,a) -> a -> Int
+    -- | Like 'index', but without checking that the value is in range.
+    unsafeIndex         :: (a,a) -> a -> Int
+    -- | Returns 'True' the given subscript lies in the range defined
+    -- the bounding pair.
+    inRange             :: (a,a) -> a -> Bool
+    -- | The size of the subrange defined by a bounding pair.
+    rangeSize           :: (a,a) -> Int
+    -- | like 'rangeSize', but without checking that the upper bound is
+    -- in range.
+    unsafeRangeSize     :: (a,a) -> Int
+
+        -- Must specify one of index, unsafeIndex
+
+        -- 'index' is typically over-ridden in instances, with essentially
+        -- the same code, but using indexError instead of hopelessIndexError
+        -- Reason: we have 'Show' at the instances
+    {-# INLINE index #-}  -- See Note [Inlining index]
+    index b i | inRange b i = unsafeIndex b i
+              | otherwise   = hopelessIndexError
+
+    unsafeIndex b i = index b i
+
+    rangeSize b@(_l,h) | inRange b h = unsafeIndex b h + 1
+                       | otherwise   = 0        -- This case is only here to
+                                                -- check for an empty range
+        -- NB: replacing (inRange b h) by (l <= h) fails for
+        --     tuples.  E.g.  (1,2) <= (2,1) but the range is empty
+
+    unsafeRangeSize b@(_l,h) = unsafeIndex b h + 1
+
+{-
+Note that the following is NOT right
+        rangeSize (l,h) | l <= h    = index b h + 1
+                        | otherwise = 0
+
+Because it might be the case that l<h, but the range
+is nevertheless empty.  Consider
+        ((1,2),(2,1))
+Here l<h, but the second index ranges from 2..1 and
+hence is empty
+
+
+Note [Inlining index]
+~~~~~~~~~~~~~~~~~~~~~
+We inline the 'index' operation,
+
+ * Partly because it generates much faster code
+   (although bigger); see #1216
+
+ * Partly because it exposes the bounds checks to the simplifier which
+   might help a big.
+
+If you make a per-instance index method, you may consider inlining it.
+
+Note [Double bounds-checking of index values]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+When you index an array, a!x, there are two possible bounds checks we might make:
+
+  (A) Check that (inRange (bounds a) x) holds.
+
+      (A) is checked in the method for 'index'
+
+  (B) Check that (index (bounds a) x) lies in the range 0..n,
+      where n is the size of the underlying array
+
+      (B) is checked in the top-level function (!), in safeIndex.
+
+Of course it *should* be the case that (A) holds iff (B) holds, but that
+is a property of the particular instances of index, bounds, and inRange,
+so GHC cannot guarantee it.
+
+ * If you do (A) and not (B), then you might get a seg-fault,
+   by indexing at some bizarre location.  #1610
+
+ * If you do (B) but not (A), you may get no complaint when you index
+   an array out of its semantic bounds.  #2120
+
+At various times we have had (A) and not (B), or (B) and not (A); both
+led to complaints.  So now we implement *both* checks (#2669).
+
+For 1-d, 2-d, and 3-d arrays of Int we have specialised instances to avoid this.
+
+Note [Out-of-bounds error messages]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The default method for 'index' generates hoplelessIndexError, because
+Ix doesn't have Show as a superclass.  For particular base types we
+can do better, so we override the default method for index.
+-}
+
+-- Abstract these errors from the relevant index functions so that
+-- the guts of the function will be small enough to inline.
+
+{-# NOINLINE indexError #-}
+indexError :: Show a => (a,a) -> a -> String -> b
+indexError rng i tp
+  = errorWithoutStackTrace (showString "Ix{" . showString tp . showString "}.index: Index " .
+           showParen True (showsPrec 0 i) .
+           showString " out of range " $
+           showParen True (showsPrec 0 rng) "")
+
+hopelessIndexError :: Int -- Try to use 'indexError' instead!
+hopelessIndexError = errorWithoutStackTrace "Error in array index"
+
+----------------------------------------------------------------------
+-- | @since 2.01
+instance  Ix Char  where
+    {-# INLINE range #-}
+    range (m,n) = [m..n]
+
+    {-# INLINE unsafeIndex #-}
+    unsafeIndex (m,_n) i = fromEnum i - fromEnum m
+
+    {-# INLINE index #-}  -- See Note [Out-of-bounds error messages]
+                          -- and Note [Inlining index]
+    index b i | inRange b i =  unsafeIndex b i
+              | otherwise   =  indexError b i "Char"
+
+    inRange (m,n) i     =  m <= i && i <= n
+
+----------------------------------------------------------------------
+-- | @since 2.01
+instance  Ix Int  where
+    {-# INLINE range #-}
+        -- The INLINE stops the build in the RHS from getting inlined,
+        -- so that callers can fuse with the result of range
+    range (m,n) = [m..n]
+
+    {-# INLINE unsafeIndex #-}
+    unsafeIndex (m,_n) i = i - m
+
+    {-# INLINE index #-}  -- See Note [Out-of-bounds error messages]
+                          -- and Note [Inlining index]
+    index b i | inRange b i =  unsafeIndex b i
+              | otherwise   =  indexError b i "Int"
+
+    {-# INLINE inRange #-}
+    inRange (I# m,I# n) (I# i) =  isTrue# (m <=# i) && isTrue# (i <=# n)
+
+-- | @since 4.6.0.0
+instance Ix Word where
+    range (m,n)         = [m..n]
+    unsafeIndex (m,_) i = fromIntegral (i - m)
+    inRange (m,n) i     = m <= i && i <= n
+
+----------------------------------------------------------------------
+-- | @since 2.01
+instance  Ix Integer  where
+    {-# INLINE range #-}
+    range (m,n) = [m..n]
+
+    {-# INLINE unsafeIndex #-}
+    unsafeIndex (m,_n) i   = fromInteger (i - m)
+
+    {-# INLINE index #-}  -- See Note [Out-of-bounds error messages]
+                          -- and Note [Inlining index]
+    index b i | inRange b i =  unsafeIndex b i
+              | otherwise   =  indexError b i "Integer"
+
+    inRange (m,n) i     =  m <= i && i <= n
+
+----------------------------------------------------------------------
+-- | @since 4.8.0.0
+instance Ix Natural where
+    range (m,n) = [m..n]
+    inRange (m,n) i = m <= i && i <= n
+    unsafeIndex (m,_) i = fromIntegral (i-m)
+    index b i | inRange b i = unsafeIndex b i
+              | otherwise   = indexError b i "Natural"
+
+----------------------------------------------------------------------
+-- | @since 2.01
+instance Ix Bool where -- as derived
+    {-# INLINE range #-}
+    range (m,n) = [m..n]
+
+    {-# INLINE unsafeIndex #-}
+    unsafeIndex (l,_) i = fromEnum i - fromEnum l
+
+    {-# INLINE index #-}  -- See Note [Out-of-bounds error messages]
+                          -- and Note [Inlining index]
+    index b i | inRange b i =  unsafeIndex b i
+              | otherwise   =  indexError b i "Bool"
+
+    inRange (l,u) i = fromEnum i >= fromEnum l && fromEnum i <= fromEnum u
+
+----------------------------------------------------------------------
+-- | @since 2.01
+instance Ix Ordering where -- as derived
+    {-# INLINE range #-}
+    range (m,n) = [m..n]
+
+    {-# INLINE unsafeIndex #-}
+    unsafeIndex (l,_) i = fromEnum i - fromEnum l
+
+    {-# INLINE index #-}  -- See Note [Out-of-bounds error messages]
+                          -- and Note [Inlining index]
+    index b i | inRange b i =  unsafeIndex b i
+              | otherwise   =  indexError b i "Ordering"
+
+    inRange (l,u) i = fromEnum i >= fromEnum l && fromEnum i <= fromEnum u
+
+----------------------------------------------------------------------
+-- | @since 2.01
+instance Ix () where
+    {-# INLINE range #-}
+    range   ((), ())    = [()]
+    {-# INLINE unsafeIndex #-}
+    unsafeIndex   ((), ()) () = 0
+    {-# INLINE inRange #-}
+    inRange ((), ()) () = True
+
+    {-# INLINE index #-}  -- See Note [Inlining index]
+    index b i = unsafeIndex b i
+
+----------------------------------------------------------------------
+-- | @since 2.01
+instance (Ix a, Ix b) => Ix (a, b) where -- as derived
+    {-# SPECIALISE instance Ix (Int,Int) #-}
+
+    {-# INLINE range #-}
+    range ((l1,l2),(u1,u2)) =
+      [ (i1,i2) | i1 <- range (l1,u1), i2 <- range (l2,u2) ]
+
+    {-# INLINE unsafeIndex #-}
+    unsafeIndex ((l1,l2),(u1,u2)) (i1,i2) =
+      unsafeIndex (l1,u1) i1 * unsafeRangeSize (l2,u2) + unsafeIndex (l2,u2) i2
+
+    {-# INLINE inRange #-}
+    inRange ((l1,l2),(u1,u2)) (i1,i2) =
+      inRange (l1,u1) i1 && inRange (l2,u2) i2
+
+    -- Default method for index
+
+----------------------------------------------------------------------
+-- | @since 2.01
+instance  (Ix a1, Ix a2, Ix a3) => Ix (a1,a2,a3)  where
+    {-# SPECIALISE instance Ix (Int,Int,Int) #-}
+
+    range ((l1,l2,l3),(u1,u2,u3)) =
+        [(i1,i2,i3) | i1 <- range (l1,u1),
+                      i2 <- range (l2,u2),
+                      i3 <- range (l3,u3)]
+
+    unsafeIndex ((l1,l2,l3),(u1,u2,u3)) (i1,i2,i3) =
+      unsafeIndex (l3,u3) i3 + unsafeRangeSize (l3,u3) * (
+      unsafeIndex (l2,u2) i2 + unsafeRangeSize (l2,u2) * (
+      unsafeIndex (l1,u1) i1))
+
+    inRange ((l1,l2,l3),(u1,u2,u3)) (i1,i2,i3) =
+      inRange (l1,u1) i1 && inRange (l2,u2) i2 &&
+      inRange (l3,u3) i3
+
+    -- Default method for index
+
+----------------------------------------------------------------------
+-- | @since 2.01
+instance  (Ix a1, Ix a2, Ix a3, Ix a4) => Ix (a1,a2,a3,a4)  where
+    range ((l1,l2,l3,l4),(u1,u2,u3,u4)) =
+      [(i1,i2,i3,i4) | i1 <- range (l1,u1),
+                       i2 <- range (l2,u2),
+                       i3 <- range (l3,u3),
+                       i4 <- range (l4,u4)]
+
+    unsafeIndex ((l1,l2,l3,l4),(u1,u2,u3,u4)) (i1,i2,i3,i4) =
+      unsafeIndex (l4,u4) i4 + unsafeRangeSize (l4,u4) * (
+      unsafeIndex (l3,u3) i3 + unsafeRangeSize (l3,u3) * (
+      unsafeIndex (l2,u2) i2 + unsafeRangeSize (l2,u2) * (
+      unsafeIndex (l1,u1) i1)))
+
+    inRange ((l1,l2,l3,l4),(u1,u2,u3,u4)) (i1,i2,i3,i4) =
+      inRange (l1,u1) i1 && inRange (l2,u2) i2 &&
+      inRange (l3,u3) i3 && inRange (l4,u4) i4
+
+    -- Default method for index
+-- | @since 2.01
+instance  (Ix a1, Ix a2, Ix a3, Ix a4, Ix a5) => Ix (a1,a2,a3,a4,a5)  where
+    range ((l1,l2,l3,l4,l5),(u1,u2,u3,u4,u5)) =
+      [(i1,i2,i3,i4,i5) | i1 <- range (l1,u1),
+                          i2 <- range (l2,u2),
+                          i3 <- range (l3,u3),
+                          i4 <- range (l4,u4),
+                          i5 <- range (l5,u5)]
+
+    unsafeIndex ((l1,l2,l3,l4,l5),(u1,u2,u3,u4,u5)) (i1,i2,i3,i4,i5) =
+      unsafeIndex (l5,u5) i5 + unsafeRangeSize (l5,u5) * (
+      unsafeIndex (l4,u4) i4 + unsafeRangeSize (l4,u4) * (
+      unsafeIndex (l3,u3) i3 + unsafeRangeSize (l3,u3) * (
+      unsafeIndex (l2,u2) i2 + unsafeRangeSize (l2,u2) * (
+      unsafeIndex (l1,u1) i1))))
+
+    inRange ((l1,l2,l3,l4,l5),(u1,u2,u3,u4,u5)) (i1,i2,i3,i4,i5) =
+      inRange (l1,u1) i1 && inRange (l2,u2) i2 &&
+      inRange (l3,u3) i3 && inRange (l4,u4) i4 &&
+      inRange (l5,u5) i5
+
+    -- Default method for index
diff --git a/libraries/base/GHC/Unicode.hs b/libraries/base/GHC/Unicode.hs
index d6f3ecc170a..9d11b37d0c6 100644
--- a/libraries/base/GHC/Unicode.hs
+++ b/libraries/base/GHC/Unicode.hs
@@ -34,7 +34,7 @@ import GHC.Base
 import GHC.Char        (chr)
 import GHC.Real
 import GHC.Enum ( Enum (..), Bounded (..) )
-import GHC.Arr ( Ix (..) )
+import GHC.Ix ( Ix (..) )
 import GHC.Num
 
 -- Data.Char.chr already imports this and we need to define a Show instance
diff --git a/libraries/base/GHC/Word.hs b/libraries/base/GHC/Word.hs
index dcd9e162087..b19e6a3bed6 100644
--- a/libraries/base/GHC/Word.hs
+++ b/libraries/base/GHC/Word.hs
@@ -57,7 +57,7 @@ import GHC.Base
 import GHC.Enum
 import GHC.Num
 import GHC.Real
-import GHC.Arr
+import GHC.Ix
 import GHC.Show
 
 ------------------------------------------------------------------------
diff --git a/libraries/base/base.cabal b/libraries/base/base.cabal
index da018d27ce9..d08b625b7f8 100644
--- a/libraries/base/base.cabal
+++ b/libraries/base/base.cabal
@@ -258,6 +258,7 @@ Library
         GHC.IOArray
         GHC.IORef
         GHC.Int
+        GHC.Ix
         GHC.List
         GHC.Maybe
         GHC.MVar
diff --git a/testsuite/tests/deriving/should_compile/T14682.stderr b/testsuite/tests/deriving/should_compile/T14682.stderr
index 7656c9c3b87..59fc405cdb5 100644
--- a/testsuite/tests/deriving/should_compile/T14682.stderr
+++ b/testsuite/tests/deriving/should_compile/T14682.stderr
@@ -18,7 +18,7 @@ Derived class instances:
                      <a1, Language.Haskell.TH.Syntax.lift a1>]
     Language.Haskell.TH.Syntax.liftTyped (T14682.Foo a1 a2)
       = [|| T14682.Foo a1 a2 ||]
-
+  
   instance Data.Data.Data T14682.Foo where
     Data.Data.gfoldl k z (T14682.Foo a1 a2)
       = ((z T14682.Foo `k` a1) `k` a2)
@@ -54,22 +54,22 @@ Derived class instances:
     (GHC.Classes.>) a b = (GHC.Classes.<) b a
     (GHC.Classes.>=) a b = GHC.Classes.not ((GHC.Classes.<) a b)
   
-  instance GHC.Arr.Ix T14682.Foo where
-    GHC.Arr.range (T14682.Foo a1 a2, T14682.Foo b1 b2)
+  instance GHC.Ix.Ix T14682.Foo where
+    GHC.Ix.range (T14682.Foo a1 a2, T14682.Foo b1 b2)
       = [T14682.Foo c1 c2 |
-           c1 <- GHC.Arr.range (a1, b1), c2 <- GHC.Arr.range (a2, b2)]
-    GHC.Arr.unsafeIndex
+           c1 <- GHC.Ix.range (a1, b1), c2 <- GHC.Ix.range (a2, b2)]
+    GHC.Ix.unsafeIndex
       (T14682.Foo a1 a2, T14682.Foo b1 b2)
       (T14682.Foo c1 c2)
-      = (GHC.Arr.unsafeIndex (a2, b2) c2
+      = (GHC.Ix.unsafeIndex (a2, b2) c2
            GHC.Num.+
-             (GHC.Arr.unsafeRangeSize (a2, b2)
-                GHC.Num.* GHC.Arr.unsafeIndex (a1, b1) c1))
-    GHC.Arr.inRange
+             (GHC.Ix.unsafeRangeSize (a2, b2)
+                GHC.Num.* GHC.Ix.unsafeIndex (a1, b1) c1))
+    GHC.Ix.inRange
       (T14682.Foo a1 a2, T14682.Foo b1 b2)
       (T14682.Foo c1 c2)
-      = (GHC.Arr.inRange (a1, b1) c1
-           GHC.Classes.&& GHC.Arr.inRange (a2, b2) c2)
+      = (GHC.Ix.inRange (a1, b1) c1
+           GHC.Classes.&& GHC.Ix.inRange (a2, b2) c2)
   
   T14682.$con2tag_B4iUvrAY4wB3YczpMJQUOX ::
     T14682.Foo -> GHC.Prim.Int#
@@ -175,19 +175,19 @@ GHC.Classes.Ord [T14682.Foo]
 
 
 ==================== Filling in method body ====================
-GHC.Arr.Ix [T14682.Foo]
-  GHC.Arr.index = GHC.Arr.$dmindex @(T14682.Foo)
+GHC.Ix.Ix [T14682.Foo]
+  GHC.Ix.index = GHC.Ix.$dmindex @(T14682.Foo)
 
 
 
 ==================== Filling in method body ====================
-GHC.Arr.Ix [T14682.Foo]
-  GHC.Arr.rangeSize = GHC.Arr.$dmrangeSize @(T14682.Foo)
+GHC.Ix.Ix [T14682.Foo]
+  GHC.Ix.rangeSize = GHC.Ix.$dmrangeSize @(T14682.Foo)
 
 
 
 ==================== Filling in method body ====================
-GHC.Arr.Ix [T14682.Foo]
-  GHC.Arr.unsafeRangeSize = GHC.Arr.$dmunsafeRangeSize @(T14682.Foo)
+GHC.Ix.Ix [T14682.Foo]
+  GHC.Ix.unsafeRangeSize = GHC.Ix.$dmunsafeRangeSize @(T14682.Foo)
 
 
diff --git a/testsuite/tests/ghci/scripts/ghci064.stdout b/testsuite/tests/ghci/scripts/ghci064.stdout
index 91298153fc0..e3fe5a98046 100644
--- a/testsuite/tests/ghci/scripts/ghci064.stdout
+++ b/testsuite/tests/ghci/scripts/ghci064.stdout
@@ -38,7 +38,7 @@ instance Show Bool -- Defined in ‘GHC.Show’
 instance Read Bool -- Defined in ‘GHC.Read’
 instance Bounded Bool -- Defined in ‘GHC.Enum’
 instance GHC.Generics.Generic Bool -- Defined in ‘GHC.Generics’
-instance GHC.Arr.Ix Bool -- Defined in ‘GHC.Arr’
+instance GHC.Ix.Ix Bool -- Defined in ‘GHC.Ix’
 instance GHC.Generics.SingKind Bool -- Defined in ‘GHC.Generics’
 instance Data.Bits.Bits Bool -- Defined in ‘Data.Bits’
 instance Data.Bits.FiniteBits Bool -- Defined in ‘Data.Bits’
-- 
GitLab