-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Runtime type assertions for testing -- -- This package provides a way to make runtime assertions about types -- that cooperate with the typechecker, intended for use in testing. For -- more information, see the module documentation for -- Test.TypeAssertions. @package type-assertions @version 0.1.0.0 -- | This module provides a set of runtime assertions about types that -- propogates information back to the type system, using Typeable -- and :~:. These are intended to be used in a test suite (and -- exclusively in a test suite) to create monomorphic implementations of -- polymorphic functions. Specifically, this is intended to be used with -- a package like test-fixture to stub out polymorphic typeclass -- methods with monomorphic implementations. -- -- For example, consider the following typeclass: -- --
-- class Monad m => MonadDB m where -- get :: DBRecord r => Id r -> m [r] -- ... ---- -- The get method might be used in another function to retrieve -- a record of a specific type, such as a User. In a test, it -- might be useful to stub out the get method to provide a -- well-known user: -- --
-- let fixture = def { _get = \_ -> User { ... } }
--
--
-- However, this will not typecheck, since the type of record should be
-- chosen by the caller of get. We might know that the
-- type is guaranteed to be User in this particular case, but
-- GHC cannot prove that, and it will reject attempts to write a stubbed
-- implementation.
--
-- To work around this issue, we can effectively defer the type error to
-- runtime by using the functions in this module. For example, we can use
-- withAssertEqT to assert that the types are the same:
--
--
-- {-# LANGUAGE ScopedTypeVariables, TypeApplications #-}
--
-- let fixture = def { _get = \(_ :: Id r) ->
-- withAssertEqT @r @User $
-- User { ... } }
--
--
-- This will properly convince GHC that the User value will only
-- be returned when the argument is actually an Id User. If it
-- isn’t, withAssertEqT will throw.
module Test.TypeAssertions
-- | Asserts that a value has a particular type, and raises an exception if
-- it does not.
--
-- -- >>> assertHasT @Bool True -- Refl -- -- >>> assertHasT @Bool "hello" -- *** Exception: expected value of type ‘Bool’, but got ‘"hello"’, which is of type ‘[Char]’ --assertHasT :: forall b a. (HasCallStack, Show a, Typeable a, Typeable b) => a -> (a :~: b) -- | Like assertHasT, but instead of returning a witness upon -- success, withAssertHasT returns its second argument. The second -- argument can be an expression that typechecks under the assumption -- that a ~ b. -- --
-- foo :: (Show a, Typeable a) => a -> a -- foo x = withAssertHasT @String x $ map toUpper x ---- --
-- >>> foo "hello" -- "HELLO" -- -- >>> foo True -- *** Exception: expected value of type ‘[Char]’, but got ‘True’, which is of type ‘Bool’ -- CallStack (from HasCallStack): -- withAssertHasT, called at <interactive>:17:13 in interactive:Ghci1 --withAssertHasT :: forall b a c. (HasCallStack, Show a, Typeable a, Typeable b) => a -> ((a ~ b) => c) -> c -- | Like assertHasT, but asserts that two types are the same -- instead of asserting that a value has a type. Generally, prefer -- assertHasT when possible, since it will produce better error -- messages, but assertEqT can be necessary when the type does not -- have a runtime representation (such as if it is phantom). -- --
-- >>> assertEqT @Bool @Bool -- Refl -- -- >>> assertEqT @Bool @Int -- *** Exception: expected type ‘Int’, but got type ‘Bool’ --assertEqT :: forall a b. (HasCallStack, Typeable a, Typeable b) => (a :~: b) -- | Like assertEqT but with the type propogation behavior of -- withAssertHasT. Generally, prefer withAssertHasT when -- possible, since it will produce better error messages, but -- withAssertEqT can be necessary when the type does not have a -- runtime representation (such as if it is phantom). -- --
-- foo :: forall a proxy. (Show a, Typeable a) => proxy a -> a -- foo _ = withAssertEqT @Bool @a True ---- --
-- >>> foo (Proxy @Bool) -- True -- -- >>> foo (Proxy @Int) -- *** Exception: expected type ‘Int’, but got type ‘Bool’ --withAssertEqT :: forall a b c. (HasCallStack, Typeable a, Typeable b) => ((a ~ b) => c) -> c -- | Propositional equality. If a :~: b is inhabited by some -- terminating value, then the type a is the same as the type -- b. To use this equality in practice, pattern-match on the -- a :~: b to get out the Refl constructor; in the body -- of the pattern-match, the compiler knows that a ~ b. data (:~:) k (a :: k) (b :: k) :: forall k. k -> k -> * [Refl] :: (:~:) k a a