-- Hoogle documentation, generated by Haddock
-- See Hoogle, http://www.haskell.org/hoogle/


-- | GHC plugin to do inspection testing
--   
--   Some carefully crafted libraries make promises to their users beyond
--   functionality and performance.
--   
--   Examples are: Fusion libraries promise intermediate data structures to
--   be eliminated. Generic programming libraries promise that the generic
--   implementation is identical to the hand-written one. Some libraries
--   may promise allocation-free or branch-free code.
--   
--   Conventionally, the modus operandi in all these cases is that the
--   library author manually inspects the (intermediate or final) code
--   produced by the compiler. This is not only tedious, but makes it very
--   likely that some change, either in the library itself or the
--   surrounding eco-system, breaks the library’s promised without anyone
--   noticing.
--   
--   This package provides a disciplined way of specifying such properties,
--   and have them checked by the compiler. This way, this checking can be
--   part of the ususal development cycle and regressions caught early.
--   
--   See the documentation in <a>Test.Inspection</a> or the project webpage
--   for more examples and more information.
@package inspection-testing
@version 0.2.0.1


-- | This module implements some of analyses of Core expressions necessary
--   for <a>Test.Inspection</a>. Normally, users of this pacakge can ignore
--   this module.
module Test.Inspection.Core

-- | Selects those bindings that define the given variable
slice :: [(Var, CoreExpr)] -> Var -> Slice

-- | Pretty-print a slice
pprSlice :: Slice -> SDoc

-- | Pretty-print two slices, after removing variables occurring in both
pprSliceDifference :: Slice -> Slice -> SDoc

-- | This is a heuristic, which only works if both slices have auxillary
--   variables in the right order. (This is mostly to work-around the buggy
--   CSE in GHC-8.0) It also breaks if there is shadowing.
eqSlice :: Bool -> Slice -> Slice -> Bool

-- | Returns <tt>True</tt> if the given core expression mentions no type
--   constructor anywhere that has the given name.
freeOfType :: Slice -> Name -> Maybe (Var, CoreExpr)

-- | True if the given variable binding does not allocate, if called fully
--   satisfied.
--   
--   It currently does not look through function calls, which of course
--   could allocate. It should probably at least look through local
--   function calls.
--   
--   The variable is important to know the arity of the function.
doesNotAllocate :: Slice -> Maybe (Var, CoreExpr)


module Test.Inspection.Internal

-- | An annotation to keep names alive
data KeepAlive
KeepAlive :: KeepAlive
instance Data.Data.Data Test.Inspection.Internal.KeepAlive


-- | This module supports the accompanying GHC plugin
--   <a>Test.Inspection.Plugin</a> and adds to GHC the ability to do
--   inspection testing.
module Test.Inspection

-- | As seen in the example above, the entry point to inspection testing is
--   the <a>inspect</a> function, to which you pass an <a>Obligation</a>.
--   It will report test failures at compile time.
inspect :: Obligation -> Q [Dec]

-- | This is a variant that allows compilation to succeed in any case, and
--   instead indicates the result as a value of type <a>Result</a>, which
--   allows seamless integration into test frameworks.
--   
--   This variant ignores the <a>expectFail</a> field of the obligation.
--   Instead, it is expected that you use the corresponding functionality
--   in your test framework (e.g. tasty-expected-failure)
inspectTest :: Obligation -> Q Exp

-- | The result of <a>inspectTest</a>, which a more or less helpful text
--   message
data Result
Failure :: String -> Result
Success :: String -> Result

-- | This data type describes an inspection testing obligation.
--   
--   It is recommended to build it using <a>mkObligation</a>, for backwards
--   compatibility when new fields are added. You can also use the more
--   memonic convenience functions like '(===)' or <a>hasNoType</a>.
--   
--   The obligation needs to be passed to <a>inspect</a>.
data Obligation
Obligation :: Name -> Property -> Maybe String -> Bool -> Maybe Loc -> Maybe String -> Obligation

-- | The target of a test obligation; invariably the name of a local
--   definition. To get the name of a function <tt>foo</tt>, write
--   <tt>'foo</tt>. This requires <tt>{-# LANGAUGE TemplateHaskell
--   #-}</tt>.
[target] :: Obligation -> Name

-- | The property of the target to be checked.
[property] :: Obligation -> Property

-- | An optional name for the test
[testName] :: Obligation -> Maybe String

-- | Do we expect this property to fail? (Only used by <a>inspect</a>, not
--   by <a>inspectTest</a>)
[expectFail] :: Obligation -> Bool

-- | The source location where this obligation is defined. This is filled
--   in by <a>inspect</a>.
[srcLoc] :: Obligation -> Maybe Loc

-- | If this is <a>Nothing</a>, then report errors during compilation.
--   Otherwise, update the top-level definition with this name.
[storeResult] :: Obligation -> Maybe String

-- | Creates an inspection obligation for the given function name with
--   default values for the optional fields.
mkObligation :: Name -> Property -> Obligation

-- | Properties of the obligation target to be checked.
data Property

-- | Are the two functions equal?
--   
--   More precisely: <tt>f</tt> is equal to <tt>g</tt> if either the
--   definition of <tt>f</tt> is <tt>f = g</tt>, or the definition of
--   <tt>g</tt> is <tt>g = f</tt>, or if the definitions are <tt>f = e</tt>
--   and <tt>g = e</tt>.
--   
--   If the boolean flag is true, then ignore types during the comparison.
EqualTo :: Name -> Bool -> Property

-- | Does this type not occur anywhere in the definition of the function
--   (neither locally bound nor passed as arguments)
NoType :: Name -> Property

-- | Does this function perform no heap allocations.
NoAllocation :: Property

-- | Convenience function to declare two functions to be equal
(===) :: Name -> Name -> Obligation
infix 9 ===

-- | Convenience function to declare two functions to be equal, but
--   ignoring type lambdas, type arguments and type casts
(==-) :: Name -> Name -> Obligation
infix 9 ==-

-- | Convenience function to declare two functions to be equal, but expect
--   the test to fail (This is useful for documentation purposes, or as a
--   TODO list.)
(=/=) :: Name -> Name -> Obligation
infix 9 =/=

-- | Convenience function to declare that a function’s implementation does
--   not mention a type
--   
--   <pre>
--   inspect $ fusedFunction <a>hasNoType</a> ''[]
--   </pre>
hasNoType :: Name -> Name -> Obligation
instance GHC.Show.Show Test.Inspection.Result
instance Data.Data.Data Test.Inspection.Obligation
instance Data.Data.Data Test.Inspection.Property


-- | See <a>Test.Inspection</a>.
module Test.Inspection.Plugin

-- | The plugin. It supports the option
--   <tt>-fplugin-opt=Test.Inspection.Plugin:keep-going</tt> to ignore a
--   failing build.
plugin :: Plugin
instance GHC.Enum.Bounded Test.Inspection.Plugin.Stat
instance GHC.Classes.Ord Test.Inspection.Plugin.Stat
instance GHC.Classes.Eq Test.Inspection.Plugin.Stat
instance GHC.Enum.Enum Test.Inspection.Plugin.Stat
instance GHC.Classes.Eq Test.Inspection.Plugin.UponFailure
