    {-|
    Copyright  :  (C) 2024, Google LLC
    License    :  BSD2 (see the file LICENSE)
    Maintainer :  QBayLogic B.V. <devops@qbaylogic.com>

    Tooling to safely work around @incomplete-uni-patterns@ and @incomplete-patterns@
    warnings. See 'vecToTuple' for more information and examples.

    Note: This module has been added to make upgrading to GHC 9.2 easier. As of GHC
          9.2, the @incomplete-uni-patterns@ has been added to the @-Wall@, making
          previously warning-free code now produce warnings.
    -}

    {-# LANGUAGE CPP #-}
    {-# LANGUAGE FlexibleInstances #-}
    {-# LANGUAGE TemplateHaskell #-}
    {-# LANGUAGE TypeFamilyDependencies #-}

    -- Purpose of this module
    {-# OPTIONS_GHC -Wno-incomplete-patterns #-}

    -- For debugging:
    -- {-# OPTIONS_GHC -ddump-splices #-}

    module Clash.Sized.Vector.ToTuple (VecToTuple(..)) where

    import Clash.CPP
    import Clash.Sized.Vector
    import Clash.Sized.Vector.ToTuple.TH (vecToTupleInstances)

    import Data.Tagged (Tagged(..))

    #if MIN_VERSION_base(4,18,0)
    import Data.Tuple (Solo(MkSolo))
    #elif MIN_VERSION_base(4,16,0)
    import Data.Tuple (Solo(Solo))
    #endif

    {- $setup
    >>> :set -XMonoLocalBinds -XGADTs
    >>> import Clash.Sized.Vector
    -}

    class VecToTuple a where
      type TupType a = r | r -> a

      -- | Given a vector with three elements:
      --
      -- >>> myVec = (1 :> 2 :> 3 :> Nil) :: Vec 3 Int
      --
      -- The following would produce a warning even though we can be sure
      -- no other pattern can ever apply:
      --
      -- >>> (a :> b :> c :> Nil) = myVec
      --
      -- 'vecToTuple' can be used to work around the warning:
      --
      -- >>> (a, b, c) = vecToTuple myVec
      --
      -- Of course, you will still get an error if you try to match a vector of the
      -- wrong length:
      --
      -- >>> (a, b, c, d) = vecToTuple myVec
      -- ...
    #if __GLASGOW_HASKELL__ > 900
      --     • Couldn't match type: (a, b, c, d)
      --                      with: (Int, Int, Int)
    #else
      --     • Couldn't match type: (Int, Int, Int)
      --                             ^
      --                      with: (a, b, c, d)
    #endif
      -- ...
      vecToTuple ::  a -> TupType a

    instance VecToTuple (Vec 0 a) where
      type TupType (Vec 0 a) = Tagged a ()
      vecToTuple :: Vec 0 a -> TupType (Vec 0 a)
    vecToTuple Vec 0 a
    _ = () -> Tagged a ()
    forall {k} (s :: k) b. b -> Tagged s b
    Tagged ()

    #if MIN_VERSION_base(4,18,0)
    -- | Instead of using 'vecToTuple' for @Vec 1 _@, you could also consider using 'head'
    instance VecToTuple (Vec 1 a) where
      type TupType (Vec 1 a) = Solo a
      vecToTuple :: Vec 1 a -> TupType (Vec 1 a)
    vecToTuple (a
    a1 :> Vec 0 a
    _) = a -> Solo a
    forall a. a -> Solo a
    MkSolo a
    a1
    #elif MIN_VERSION_base(4,16,0)
    -- | Instead of using 'vecToTuple' for @Vec 1 _@, you could also consider using 'head'
    instance VecToTuple (Vec 1 a) where
      type TupType (Vec 1 a) = Solo a
      vecToTuple (a1 :> _) = Solo a1
    #endif

    -- | __NB__: The documentation only shows instances up to /3/-tuples. By
    -- default, instances up to and including /12/-tuples will exist. If the flag
    -- @large-tuples@ is set instances up to the GHC imposed limit will exist. The
    -- GHC imposed limit is either 62 or 64 depending on the GHC version.
    instance VecToTuple (Vec 2 a) where
      type TupType (Vec 2 a) = (a, a)
      vecToTuple :: Vec 2 a -> TupType (Vec 2 a)
    vecToTuple (a
    a1 :> a
    a2 :> Vec 0 a
    _) = (a
    a1, a
    a2)

    vecToTupleInstances maxTupleSize