constraints-0.14: src/Data/Constraint/Unsafe.hs
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE Unsafe #-}
{-# LANGUAGE CPP #-}
{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}
-- |
-- Copyright : (C) 2011-2021 Edward Kmett
-- License : BSD-style (see the file LICENSE)
-- Maintainer : Edward Kmett <ekmett@gmail.com>
-- Stability : experimental
-- Portability : non-portable
--
-- Unsafe utilities used throughout @constraints@. As the names suggest, these
-- functions are unsafe in general and can cause your program to segfault if
-- used improperly. Handle with care.
module Data.Constraint.Unsafe
( Coercible
, unsafeAxiom
, unsafeCoerceConstraint
, unsafeDerive
, unsafeUnderive
#if MIN_VERSION_base(4,18,0)
-- * Unsafely creating @GHC.TypeLits@ singleton values
, unsafeSChar
, unsafeSNat
, unsafeSSymbol
#endif
) where
import Data.Coerce
import Data.Constraint
import Unsafe.Coerce
#if MIN_VERSION_base(4,18,0)
import GHC.TypeLits (SChar, SNat, SSymbol)
import Numeric.Natural (Natural)
#endif
-- | Unsafely create a dictionary for any constraint.
unsafeAxiom :: Dict c
unsafeAxiom = unsafeCoerce (Dict :: Dict ())
-- | Coerce a dictionary unsafely from one type to another
unsafeCoerceConstraint :: a :- b
unsafeCoerceConstraint = unsafeCoerce refl
-- | Coerce a dictionary unsafely from one type to a newtype of that type
unsafeDerive :: Coercible n o => (o -> n) -> t o :- t n
unsafeDerive _ = unsafeCoerceConstraint
-- | Coerce a dictionary unsafely from a newtype of a type to the base type
unsafeUnderive :: Coercible n o => (o -> n) -> t n :- t o
unsafeUnderive _ = unsafeCoerceConstraint
#if MIN_VERSION_base(4,18,0)
-- NB: if https://gitlab.haskell.org/ghc/ghc/-/issues/23478 were implemented,
-- then we could avoid using 'unsafeCoerce' in the definitions below.
-- | Unsafely create an 'SChar' value directly from a 'Char'. Use this function
-- with care:
--
-- * The 'Char' value must match the 'Char' @c@ encoded in the return type
-- @'SChar' c@.
--
-- * Be wary of using this function to create multiple values of type
-- @'SChar' T@, where @T@ is a type family that does not reduce (e.g.,
-- @Any@ from "GHC.Exts"). If you do, GHC is liable to optimize away one of
-- the values and replace it with the other during a common subexpression
-- elimination pass. If the two values have different underlying 'Char'
-- values, this could be disastrous.
unsafeSChar :: Char -> SChar c
unsafeSChar = unsafeCoerce
-- | Unsafely create an 'SNat' value directly from a 'Natural'. Use this
-- function with care:
--
-- * The 'Natural' value must match the 'Nat' @n@ encoded in the return type
-- @'SNat' n@.
--
-- * Be wary of using this function to create multiple values of type
-- @'SNat' T@, where @T@ is a type family that does not reduce (e.g.,
-- @Any@ from "GHC.Exts"). If you do, GHC is liable to optimize away one of
-- the values and replace it with the other during a common subexpression
-- elimination pass. If the two values have different underlying 'Natural'
-- values, this could be disastrous.
unsafeSNat :: Natural -> SNat n
unsafeSNat = unsafeCoerce
-- | Unsafely create an 'SSymbol' value directly from a 'String'. Use this
-- function with care:
--
-- * The 'String' value must match the 'Symbol' @s@ encoded in the return type
-- @'SSymbol' s@.
--
-- * Be wary of using this function to create multiple values of type
-- @'SSymbol' T@, where @T@ is a type family that does not reduce (e.g.,
-- @Any@ from "GHC.Exts"). If you do, GHC is liable to optimize away one of
-- the values and replace it with the other during a common subexpression
-- elimination pass. If the two values have different underlying 'String'
-- values, this could be disastrous.
unsafeSSymbol :: String -> SSymbol s
unsafeSSymbol = unsafeCoerce
#endif