{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE UndecidableSuperClasses #-}
-- | Type-level metadata
--
-- This module provides datatypes (to be used promoted) that can represent the
-- metadata of Haskell datatypes on the type level.
--
-- We do not reuse the term-level metadata types, because these are GADTs that
-- incorporate additional invariants. We could (at least in GHC 8) impose the
-- same invariants on the type level as well, but some tests have revealed that
-- the resulting type are rather inconvenient to work with.
--
-- So we use simple datatypes to represent the type-level metadata, even if
-- this means that some invariants are not explicitly captured.
--
-- We establish a relation between the term- and type-level versions of the
-- metadata by automatically computing the term-level version from the type-level
-- version.
--
-- As we now have two versions of metadata (term-level and type-level)
-- with very similar, yet slightly different datatype definitions, the names
-- between the modules clash, and this module is recommended to be imported
-- qualified when needed.
--
-- The interface exported by this module is still somewhat experimental.
--
-- @since 0.3.0.0
--
module Generics.SOP.Type.Metadata
  ( module Generics.SOP.Type.Metadata
    -- * re-exports
  , Associativity(..)
  ) where

#if __GLASGOW_HASKELL__ <802
import Data.Kind (Type)
#endif
import Data.Proxy (Proxy (..))
import GHC.Generics
  ( Associativity(..)
  , DecidedStrictness(..)
  , SourceStrictness(..)
  , SourceUnpackedness(..)
  )
import GHC.Types
import GHC.TypeLits

import qualified Generics.SOP.Metadata as M
import Generics.SOP.NP
import Generics.SOP.Sing

-- Regarding the CPP in the datatype definitions below:
--
-- We cannot promote type synonyms in GHC 7, so we
-- use equivalent yet less descriptive definitions
-- for the older GHCs.

-- | Metadata for a datatype (to be used promoted).
--
-- A type of kind @'DatatypeInfo'@ contains meta-information about a datatype
-- that is not contained in its code. This information consists
-- primarily of the names of the datatype, its constructors, and possibly its
-- record selectors.
--
-- The constructor indicates whether the datatype has been declared using @newtype@
-- or not.
--
-- @since 0.3.0.0
--
data DatatypeInfo =
    ADT ModuleName DatatypeName [ConstructorInfo] [[StrictnessInfo]]
    -- ^ Standard algebraic datatype
  | Newtype ModuleName DatatypeName ConstructorInfo
    -- ^ Newtype

-- | Metadata for a single constructors (to be used promoted).
--
-- @since 0.3.0.0
--
data ConstructorInfo =
    Constructor ConstructorName
    -- ^ Normal constructor
  | Infix ConstructorName Associativity Fixity
    -- ^ Infix constructor
  | Record ConstructorName [FieldInfo]
    -- ^ Record constructor

-- | Strictness information for a single field (to be used promoted).
--
-- @since 0.4.0.0
--
data StrictnessInfo =
    StrictnessInfo SourceUnpackedness SourceStrictness DecidedStrictness

-- | Metadata for a single record field (to be used promoted).
--
-- @since 0.3.0.0
--
data FieldInfo =
    FieldInfo FieldName

-- | The name of a datatype.
type DatatypeName    = Symbol

-- | The name of a module.
type ModuleName      = Symbol

-- | The name of a data constructor.
type ConstructorName = Symbol

-- | The name of a field / record selector.
type FieldName       = Symbol

-- | The fixity of an infix constructor.
type Fixity          = Nat

-- Demotion
--
-- The following classes are concerned with computing the
-- term-level metadata from the type-level metadata.

-- | Class for computing term-level datatype information from
-- type-level datatype information.
--
-- @since 0.3.0.0
--
class DemoteDatatypeInfo (x :: DatatypeInfo) (xss :: [[Type]]) where
  -- | Given a proxy of some type-level datatype information,
  -- return the corresponding term-level information.
  --
  -- @since 0.3.0.0
  --
  demoteDatatypeInfo :: proxy x -> M.DatatypeInfo xss

instance
     ( KnownSymbol m
     , KnownSymbol d
     , DemoteConstructorInfos cs xss
     , DemoteStrictnessInfoss sss xss
     )
  => DemoteDatatypeInfo ('ADT m d cs sss) xss where
  demoteDatatypeInfo :: forall (proxy :: DatatypeInfo -> *).
proxy ('ADT m d cs sss) -> DatatypeInfo xss
demoteDatatypeInfo proxy ('ADT m d cs sss)
_ =
    forall (a :: [[*]]).
ModuleName
-> ModuleName
-> NP ConstructorInfo a
-> POP StrictnessInfo a
-> DatatypeInfo a
M.ADT
      (forall (n :: Symbol) (proxy :: Symbol -> *).
KnownSymbol n =>
proxy n -> ModuleName
symbolVal (forall {k} (t :: k). Proxy t
Proxy :: Proxy m))
      (forall (n :: Symbol) (proxy :: Symbol -> *).
KnownSymbol n =>
proxy n -> ModuleName
symbolVal (forall {k} (t :: k). Proxy t
Proxy :: Proxy d))
      (forall (cs :: [ConstructorInfo]) (xss :: [[*]])
       (proxy :: [ConstructorInfo] -> *).
DemoteConstructorInfos cs xss =>
proxy cs -> NP ConstructorInfo xss
demoteConstructorInfos (forall {k} (t :: k). Proxy t
Proxy :: Proxy cs))
      (forall k (f :: k -> *) (xss :: [[k]]). NP (NP f) xss -> POP f xss
POP (forall (sss :: [[StrictnessInfo]]) (xss :: [[*]])
       (proxy :: [[StrictnessInfo]] -> *).
DemoteStrictnessInfoss sss xss =>
proxy sss -> NP (NP StrictnessInfo) xss
demoteStrictnessInfoss (forall {k} (t :: k). Proxy t
Proxy :: Proxy sss)))

instance
     (KnownSymbol m, KnownSymbol d, DemoteConstructorInfo c '[ x ])
  => DemoteDatatypeInfo ('Newtype m d c) '[ '[ x ] ] where
  demoteDatatypeInfo :: forall (proxy :: DatatypeInfo -> *).
proxy ('Newtype m d c) -> DatatypeInfo '[ '[x]]
demoteDatatypeInfo proxy ('Newtype m d c)
_ =
    forall x.
ModuleName
-> ModuleName -> ConstructorInfo '[x] -> DatatypeInfo '[ '[x]]
M.Newtype
      (forall (n :: Symbol) (proxy :: Symbol -> *).
KnownSymbol n =>
proxy n -> ModuleName
symbolVal (forall {k} (t :: k). Proxy t
Proxy :: Proxy m))
      (forall (n :: Symbol) (proxy :: Symbol -> *).
KnownSymbol n =>
proxy n -> ModuleName
symbolVal (forall {k} (t :: k). Proxy t
Proxy :: Proxy d))
      (forall (x :: ConstructorInfo) (xs :: [*])
       (proxy :: ConstructorInfo -> *).
DemoteConstructorInfo x xs =>
proxy x -> ConstructorInfo xs
demoteConstructorInfo (forall {k} (t :: k). Proxy t
Proxy :: Proxy c))

-- | Class for computing term-level constructor information from
-- type-level constructor information.
--
-- @since 0.3.0.0
--
class DemoteConstructorInfos (cs :: [ConstructorInfo]) (xss :: [[Type]]) where
  -- | Given a proxy of some type-level constructor information,
  -- return the corresponding term-level information as a product.
  --
  -- @since 0.3.0.0
  --
  demoteConstructorInfos :: proxy cs -> NP M.ConstructorInfo xss

instance DemoteConstructorInfos '[] '[] where
  demoteConstructorInfos :: forall (proxy :: [ConstructorInfo] -> *).
proxy '[] -> NP ConstructorInfo '[]
demoteConstructorInfos proxy '[]
_ = forall {k} (a :: k -> *). NP a '[]
Nil

instance
     (DemoteConstructorInfo c xs, DemoteConstructorInfos cs xss)
  => DemoteConstructorInfos (c ': cs) (xs ': xss) where
  demoteConstructorInfos :: forall (proxy :: [ConstructorInfo] -> *).
proxy (c : cs) -> NP ConstructorInfo (xs : xss)
demoteConstructorInfos proxy (c : cs)
_ =
    forall (x :: ConstructorInfo) (xs :: [*])
       (proxy :: ConstructorInfo -> *).
DemoteConstructorInfo x xs =>
proxy x -> ConstructorInfo xs
demoteConstructorInfo (forall {k} (t :: k). Proxy t
Proxy :: Proxy c) forall {k} (a :: k -> *) (x :: k) (xs :: [k]).
a x -> NP a xs -> NP a (x : xs)
:* forall (cs :: [ConstructorInfo]) (xss :: [[*]])
       (proxy :: [ConstructorInfo] -> *).
DemoteConstructorInfos cs xss =>
proxy cs -> NP ConstructorInfo xss
demoteConstructorInfos (forall {k} (t :: k). Proxy t
Proxy :: Proxy cs)

-- | Class for computing term-level constructor information from
-- type-level constructor information.
--
-- @since 0.3.0.0
--
class DemoteConstructorInfo (x :: ConstructorInfo) (xs :: [Type]) where
  -- | Given a proxy of some type-level constructor information,
  -- return the corresponding term-level information.
  --
  -- @since 0.3.0.0
  --
  demoteConstructorInfo :: proxy x -> M.ConstructorInfo xs

instance (KnownSymbol s, SListI xs) => DemoteConstructorInfo ('Constructor s) xs where
  demoteConstructorInfo :: forall (proxy :: ConstructorInfo -> *).
proxy ('Constructor s) -> ConstructorInfo xs
demoteConstructorInfo proxy ('Constructor s)
_ = forall (a :: [*]). SListI a => ModuleName -> ConstructorInfo a
M.Constructor (forall (n :: Symbol) (proxy :: Symbol -> *).
KnownSymbol n =>
proxy n -> ModuleName
symbolVal (forall {k} (t :: k). Proxy t
Proxy :: Proxy s))

instance
     (KnownSymbol s, DemoteAssociativity a, KnownNat f)
  => DemoteConstructorInfo ('Infix s a f) [y, z] where
  demoteConstructorInfo :: forall (proxy :: ConstructorInfo -> *).
proxy ('Infix s a f) -> ConstructorInfo '[y, z]
demoteConstructorInfo proxy ('Infix s a f)
_ =
    forall x y.
ModuleName -> Associativity -> Fixity -> ConstructorInfo '[x, y]
M.Infix
      (forall (n :: Symbol) (proxy :: Symbol -> *).
KnownSymbol n =>
proxy n -> ModuleName
symbolVal (forall {k} (t :: k). Proxy t
Proxy :: Proxy s))
      (forall (a :: Associativity) (proxy :: Associativity -> *).
DemoteAssociativity a =>
proxy a -> Associativity
demoteAssociativity (forall {k} (t :: k). Proxy t
Proxy :: Proxy a))
      (forall a. Num a => Integer -> a
fromInteger (forall (n :: Nat) (proxy :: Nat -> *).
KnownNat n =>
proxy n -> Integer
natVal (forall {k} (t :: k). Proxy t
Proxy :: Proxy f)))

instance (KnownSymbol s, DemoteFieldInfos fs xs) => DemoteConstructorInfo ('Record s fs) xs where
  demoteConstructorInfo :: forall (proxy :: ConstructorInfo -> *).
proxy ('Record s fs) -> ConstructorInfo xs
demoteConstructorInfo proxy ('Record s fs)
_ =
    forall (a :: [*]).
SListI a =>
ModuleName -> NP FieldInfo a -> ConstructorInfo a
M.Record (forall (n :: Symbol) (proxy :: Symbol -> *).
KnownSymbol n =>
proxy n -> ModuleName
symbolVal (forall {k} (t :: k). Proxy t
Proxy :: Proxy s)) (forall (fs :: [FieldInfo]) (xs :: [*]) (proxy :: [FieldInfo] -> *).
DemoteFieldInfos fs xs =>
proxy fs -> NP FieldInfo xs
demoteFieldInfos (forall {k} (t :: k). Proxy t
Proxy :: Proxy fs))


class DemoteStrictnessInfoss (sss :: [[StrictnessInfo]]) (xss :: [[Type]]) where
  demoteStrictnessInfoss :: proxy sss -> NP (NP M.StrictnessInfo) xss

instance DemoteStrictnessInfoss '[] '[] where
  demoteStrictnessInfoss :: forall (proxy :: [[StrictnessInfo]] -> *).
proxy '[] -> NP (NP StrictnessInfo) '[]
demoteStrictnessInfoss proxy '[]
_ = forall {k} (a :: k -> *). NP a '[]
Nil

instance
     (DemoteStrictnessInfos ss xs, DemoteStrictnessInfoss sss xss)
  => DemoteStrictnessInfoss (ss ': sss) (xs ': xss) where
  demoteStrictnessInfoss :: forall (proxy :: [[StrictnessInfo]] -> *).
proxy (ss : sss) -> NP (NP StrictnessInfo) (xs : xss)
demoteStrictnessInfoss proxy (ss : sss)
_ =
       forall (ss :: [StrictnessInfo]) (xs :: [*])
       (proxy :: [StrictnessInfo] -> *).
DemoteStrictnessInfos ss xs =>
proxy ss -> NP StrictnessInfo xs
demoteStrictnessInfos  (forall {k} (t :: k). Proxy t
Proxy :: Proxy ss )
    forall {k} (a :: k -> *) (x :: k) (xs :: [k]).
a x -> NP a xs -> NP a (x : xs)
:* forall (sss :: [[StrictnessInfo]]) (xss :: [[*]])
       (proxy :: [[StrictnessInfo]] -> *).
DemoteStrictnessInfoss sss xss =>
proxy sss -> NP (NP StrictnessInfo) xss
demoteStrictnessInfoss (forall {k} (t :: k). Proxy t
Proxy :: Proxy sss)

class DemoteStrictnessInfos (ss :: [StrictnessInfo]) (xs :: [Type]) where
  demoteStrictnessInfos :: proxy ss -> NP M.StrictnessInfo xs

instance DemoteStrictnessInfos '[] '[] where
  demoteStrictnessInfos :: forall (proxy :: [StrictnessInfo] -> *).
proxy '[] -> NP StrictnessInfo '[]
demoteStrictnessInfos proxy '[]
_ = forall {k} (a :: k -> *). NP a '[]
Nil

instance
     (DemoteStrictnessInfo s x, DemoteStrictnessInfos ss xs)
  => DemoteStrictnessInfos (s ': ss) (x ': xs) where
  demoteStrictnessInfos :: forall (proxy :: [StrictnessInfo] -> *).
proxy (s : ss) -> NP StrictnessInfo (x : xs)
demoteStrictnessInfos proxy (s : ss)
_ =
       forall (s :: StrictnessInfo) x (proxy :: StrictnessInfo -> *).
DemoteStrictnessInfo s x =>
proxy s -> StrictnessInfo x
demoteStrictnessInfo  (forall {k} (t :: k). Proxy t
Proxy :: Proxy s )
    forall {k} (a :: k -> *) (x :: k) (xs :: [k]).
a x -> NP a xs -> NP a (x : xs)
:* forall (ss :: [StrictnessInfo]) (xs :: [*])
       (proxy :: [StrictnessInfo] -> *).
DemoteStrictnessInfos ss xs =>
proxy ss -> NP StrictnessInfo xs
demoteStrictnessInfos (forall {k} (t :: k). Proxy t
Proxy :: Proxy ss)

class DemoteStrictnessInfo (s :: StrictnessInfo) (x :: Type) where
  demoteStrictnessInfo :: proxy s -> M.StrictnessInfo x

instance
     ( DemoteSourceUnpackedness su
     , DemoteSourceStrictness   ss
     , DemoteDecidedStrictness  ds
     )
  => DemoteStrictnessInfo ('StrictnessInfo su ss ds) x where
  demoteStrictnessInfo :: forall (proxy :: StrictnessInfo -> *).
proxy ('StrictnessInfo su ss ds) -> StrictnessInfo x
demoteStrictnessInfo proxy ('StrictnessInfo su ss ds)
_ =
    forall a.
SourceUnpackedness
-> SourceStrictness -> DecidedStrictness -> StrictnessInfo a
M.StrictnessInfo
      (forall (a :: SourceUnpackedness)
       (proxy :: SourceUnpackedness -> *).
DemoteSourceUnpackedness a =>
proxy a -> SourceUnpackedness
demoteSourceUnpackedness (forall {k} (t :: k). Proxy t
Proxy :: Proxy su))
      (forall (a :: SourceStrictness) (proxy :: SourceStrictness -> *).
DemoteSourceStrictness a =>
proxy a -> SourceStrictness
demoteSourceStrictness   (forall {k} (t :: k). Proxy t
Proxy :: Proxy ss))
      (forall (a :: DecidedStrictness) (proxy :: DecidedStrictness -> *).
DemoteDecidedStrictness a =>
proxy a -> DecidedStrictness
demoteDecidedStrictness  (forall {k} (t :: k). Proxy t
Proxy :: Proxy ds))

-- | Class for computing term-level field information from
-- type-level field information.
--
-- @since 0.3.0.0
--
class SListI xs => DemoteFieldInfos (fs :: [FieldInfo]) (xs :: [Type]) where
  -- | Given a proxy of some type-level field information,
  -- return the corresponding term-level information as a product.
  --
  -- @since 0.3.0.0
  --
  demoteFieldInfos :: proxy fs -> NP M.FieldInfo xs

instance DemoteFieldInfos '[] '[] where
  demoteFieldInfos :: forall (proxy :: [FieldInfo] -> *). proxy '[] -> NP FieldInfo '[]
demoteFieldInfos proxy '[]
_ = forall {k} (a :: k -> *). NP a '[]
Nil

instance
     (DemoteFieldInfo f x, DemoteFieldInfos fs xs)
  => DemoteFieldInfos (f ': fs) (x ': xs) where
  demoteFieldInfos :: forall (proxy :: [FieldInfo] -> *).
proxy (f : fs) -> NP FieldInfo (x : xs)
demoteFieldInfos proxy (f : fs)
_ = forall (x :: FieldInfo) a (proxy :: FieldInfo -> *).
DemoteFieldInfo x a =>
proxy x -> FieldInfo a
demoteFieldInfo (forall {k} (t :: k). Proxy t
Proxy :: Proxy f) forall {k} (a :: k -> *) (x :: k) (xs :: [k]).
a x -> NP a xs -> NP a (x : xs)
:* forall (fs :: [FieldInfo]) (xs :: [*]) (proxy :: [FieldInfo] -> *).
DemoteFieldInfos fs xs =>
proxy fs -> NP FieldInfo xs
demoteFieldInfos (forall {k} (t :: k). Proxy t
Proxy :: Proxy fs)

-- | Class for computing term-level field information from
-- type-level field information.
--
-- @since 0.3.0.0
--
class DemoteFieldInfo (x :: FieldInfo) (a :: Type) where
  -- | Given a proxy of some type-level field information,
  -- return the corresponding term-level information.
  --
  -- @since 0.3.0.0
  --
  demoteFieldInfo :: proxy x -> M.FieldInfo a

instance KnownSymbol s => DemoteFieldInfo ('FieldInfo s) a where
  demoteFieldInfo :: forall (proxy :: FieldInfo -> *).
proxy ('FieldInfo s) -> FieldInfo a
demoteFieldInfo proxy ('FieldInfo s)
_ = forall a. ModuleName -> FieldInfo a
M.FieldInfo (forall (n :: Symbol) (proxy :: Symbol -> *).
KnownSymbol n =>
proxy n -> ModuleName
symbolVal (forall {k} (t :: k). Proxy t
Proxy :: Proxy s))

-- | Class for computing term-level associativity information
-- from type-level associativity information.
--
-- @since 0.3.0.0
--
class DemoteAssociativity (a :: Associativity) where
  -- | Given a proxy of some type-level associativity information,
  -- return the corresponding term-level information.
  --
  -- @since 0.3.0.0
  --
  demoteAssociativity :: proxy a -> M.Associativity

instance DemoteAssociativity 'LeftAssociative where
  demoteAssociativity :: forall (proxy :: Associativity -> *).
proxy 'LeftAssociative -> Associativity
demoteAssociativity proxy 'LeftAssociative
_ = Associativity
M.LeftAssociative

instance DemoteAssociativity 'RightAssociative where
  demoteAssociativity :: forall (proxy :: Associativity -> *).
proxy 'RightAssociative -> Associativity
demoteAssociativity proxy 'RightAssociative
_ = Associativity
M.RightAssociative

instance DemoteAssociativity 'NotAssociative where
  demoteAssociativity :: forall (proxy :: Associativity -> *).
proxy 'NotAssociative -> Associativity
demoteAssociativity proxy 'NotAssociative
_ = Associativity
M.NotAssociative

-- | Class for computing term-level source unpackedness information
-- from type-level source unpackedness information.
--
-- @since 0.4.0.0
--
class DemoteSourceUnpackedness (a :: SourceUnpackedness) where
  -- | Given a proxy of some type-level source unpackedness information,
  -- return the corresponding term-level information.
  --
  -- @since 0.4.0.0
  --
  demoteSourceUnpackedness :: proxy a -> M.SourceUnpackedness

instance DemoteSourceUnpackedness 'NoSourceUnpackedness where
  demoteSourceUnpackedness :: forall (proxy :: SourceUnpackedness -> *).
proxy 'NoSourceUnpackedness -> SourceUnpackedness
demoteSourceUnpackedness proxy 'NoSourceUnpackedness
_ = SourceUnpackedness
M.NoSourceUnpackedness

instance DemoteSourceUnpackedness 'SourceNoUnpack where
  demoteSourceUnpackedness :: forall (proxy :: SourceUnpackedness -> *).
proxy 'SourceNoUnpack -> SourceUnpackedness
demoteSourceUnpackedness proxy 'SourceNoUnpack
_ = SourceUnpackedness
M.SourceNoUnpack

instance DemoteSourceUnpackedness 'SourceUnpack where
  demoteSourceUnpackedness :: forall (proxy :: SourceUnpackedness -> *).
proxy 'SourceUnpack -> SourceUnpackedness
demoteSourceUnpackedness proxy 'SourceUnpack
_ = SourceUnpackedness
M.SourceUnpack

-- | Class for computing term-level source strictness information
-- from type-level source strictness information.
--
-- @since 0.4.0.0
--
class DemoteSourceStrictness (a :: SourceStrictness) where
  -- | Given a proxy of some type-level source strictness information,
  -- return the corresponding term-level information.
  --
  -- @since 0.4.0.0
  --
  demoteSourceStrictness :: proxy a -> M.SourceStrictness

instance DemoteSourceStrictness 'NoSourceStrictness where
  demoteSourceStrictness :: forall (proxy :: SourceStrictness -> *).
proxy 'NoSourceStrictness -> SourceStrictness
demoteSourceStrictness proxy 'NoSourceStrictness
_ = SourceStrictness
M.NoSourceStrictness

instance DemoteSourceStrictness 'SourceLazy where
  demoteSourceStrictness :: forall (proxy :: SourceStrictness -> *).
proxy 'SourceLazy -> SourceStrictness
demoteSourceStrictness proxy 'SourceLazy
_ = SourceStrictness
M.SourceLazy

instance DemoteSourceStrictness 'SourceStrict where
  demoteSourceStrictness :: forall (proxy :: SourceStrictness -> *).
proxy 'SourceStrict -> SourceStrictness
demoteSourceStrictness proxy 'SourceStrict
_ = SourceStrictness
M.SourceStrict

-- | Class for computing term-level decided strictness information
-- from type-level decided strictness information.
--
-- @since 0.4.0.0
--
class DemoteDecidedStrictness (a :: DecidedStrictness) where
  -- | Given a proxy of some type-level source strictness information,
  -- return the corresponding term-level information.
  --
  -- @since 0.4.0.0
  --
  demoteDecidedStrictness :: proxy a -> M.DecidedStrictness

instance DemoteDecidedStrictness 'DecidedLazy where
  demoteDecidedStrictness :: forall (proxy :: DecidedStrictness -> *).
proxy 'DecidedLazy -> DecidedStrictness
demoteDecidedStrictness proxy 'DecidedLazy
_ = DecidedStrictness
M.DecidedLazy

instance DemoteDecidedStrictness 'DecidedStrict where
  demoteDecidedStrictness :: forall (proxy :: DecidedStrictness -> *).
proxy 'DecidedStrict -> DecidedStrictness
demoteDecidedStrictness proxy 'DecidedStrict
_ = DecidedStrictness
M.DecidedStrict

instance DemoteDecidedStrictness 'DecidedUnpack where
  demoteDecidedStrictness :: forall (proxy :: DecidedStrictness -> *).
proxy 'DecidedUnpack -> DecidedStrictness
demoteDecidedStrictness proxy 'DecidedUnpack
_ = DecidedStrictness
M.DecidedUnpack