-- 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 Test.Inspection or the project webpage -- for more examples and more information. @package inspection-testing @version 0.5 -- | This module supports the accompanying GHC plugin -- Test.Inspection.Plugin 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 inspect function, to which you pass an Obligation. -- It will report test failures at compile time. inspect :: Obligation -> Q [Dec] -- | This is a variant of inspect that allows compilation to succeed -- in any case, and instead indicates the result as a value of type -- Result, which allows seamless integration into test frameworks. -- -- This variant ignores the expectFail 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 inspectTest, which has 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 mkObligation, for backwards -- compatibility when new fields are added. You can also use the more -- mnemonic convenience functions like (===) or hasNoType. -- -- The obligation needs to be passed to inspect or -- inspectTest. 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 foo, write -- 'foo. This requires {-# LANGUAGE TemplateHaskell -- #-}. [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 inspect, not -- by inspectTest) [expectFail] :: Obligation -> Bool -- | The source location where this obligation is defined. This is filled -- in by inspect. [srcLoc] :: Obligation -> Maybe Loc -- | If this is Nothing, 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 -- | Equivalence of terms. data Equivalence -- | strict term equality StrictEquiv :: Equivalence -- | ignore types and hpc ticks during the comparison IgnoreTypesAndTicksEquiv :: Equivalence -- | allow permuted let bindings, ignore types and hpc tick during -- comparison UnorderedLetsEquiv :: Equivalence -- | Properties of the obligation target to be checked. data Property -- | Are the two functions equal? -- -- More precisely: f is equal to g if either the -- definition of f is f = g, or the definition of -- g is g = f, or if the definitions are f = e -- and g = e. -- -- In general f and g need to be defined in this -- module, so that their actual defintions can be inspected. -- -- The Equivalence indicates how strict to check for equality EqualTo :: Name -> Equivalence -> Property -- | Do none of these types appear anywhere in the definition of the -- function (neither locally bound nor passed as arguments) NoTypes :: [Name] -> Property -- | Does this function perform no heap allocations. NoAllocation :: Property -- | Does this value contain dictionaries (except of the listed -- classes). NoTypeClasses :: [Name] -> Property -- | Does not contain this value (in terms or patterns) NoUseOf :: [Name] -> Property -- | Always satisfied, but dumps the value in non-quiet mode. CoreOf :: Property -- | Declare two functions to be equal (see EqualTo) (===) :: Name -> Name -> Obligation infix 9 === -- | Declare two functions to be equal, but ignoring type lambdas, type -- arguments, type casts and hpc ticks (see EqualTo). Note that -- -fhpc can prevent some optimizations; build without for more -- reliable analysis. (==-) :: Name -> Name -> Obligation infix 9 ==- -- | Declare two functions to be equal, but expect the test to fail (see -- EqualTo and expectFail) (This is useful for -- documentation purposes, or as a TODO list.) (=/=) :: Name -> Name -> Obligation infix 9 =/= -- | Declare two functions to be equal up to types (see (==-)), but -- expect the test to fail (see expectFail), (=/-) :: Name -> Name -> Obligation infix 9 =/- -- | Declare two functions to be equal as (==-) but also -- ignoring let bindings ordering (see EqualTo). (==~) :: Name -> Name -> Obligation infix 9 ==~ -- | Declare two functions to be equal up to let binding ordering (see -- (==~)), but expect the test to fail (see expectFail), (=/~) :: Name -> Name -> Obligation infix 9 =/~ -- | Declare that in a function’s implementation, the given type does not -- occur. -- -- More precisely: No locally bound variable (let-bound, lambda-bound or -- pattern-bound) has a type that contains the given type constructor. -- --
-- inspect $ fusedFunction `hasNoType` ''[] --hasNoType :: Name -> Name -> Obligation -- | Declare that a function’s implementation does not contain any generic -- types. This is just hasNoType applied to the usual type -- constructors used in GHC.Generics. -- --
-- inspect $ hasNoGenerics genericFunction --hasNoGenerics :: Name -> Obligation -- | Declare that a function's implementation does not include -- dictionaries. -- -- More precisely: No locally bound variable (let-bound, lambda-bound or -- pattern-bound) has a type that contains a type that mentions a type -- class. -- --
-- inspect $ hasNoTypeClasses specializedFunction --hasNoTypeClasses :: Name -> Obligation -- | A variant of hasNoTypeClasses, which white-lists some -- type-classes. -- --
-- inspect $ fieldLens `hasNoTypeClassesExcept` [''Functor] --hasNoTypeClassesExcept :: Name -> [Name] -> Obligation -- | Declare that a function's implementation does not use the given -- variable (either in terms or -- if it is a constructor -- in -- patterns). -- --
-- inspect $ foo `doesNotUse` 'error --doesNotUse :: Name -> Name -> Obligation -- | Dump the Core of the value. -- --
-- inspect $ coreOf 'foo ---- -- This is useful when you need to inspect some values manually. coreOf :: Name -> Obligation instance Data.Data.Data Test.Inspection.Equivalence instance Data.Data.Data Test.Inspection.Property instance Data.Data.Data Test.Inspection.Obligation instance GHC.Show.Show Test.Inspection.Result -- | This module implements some analyses of Core expressions necessary for -- Test.Inspection. Normally, users of this package can ignore -- this module. module Test.Inspection.Core -- | Selects those bindings that define the given variable (with this -- variable first) 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 auxiliary -- 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 :: Equivalence -> Slice -> Slice -> Bool -- | Returns True if the given core expression mentions no type -- constructor anywhere that has the given name. freeOfType :: Slice -> [Name] -> Maybe (Var, CoreExpr) -- | Returns True if the given core expression mentions no term -- variable anywhere that has the given name. freeOfTerm :: 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) doesNotContainTypeClasses :: Slice -> [Name] -> Maybe (Var, CoreExpr, [TyCon]) -- | See Test.Inspection. module Test.Inspection.Plugin -- | The plugin. It supports some options: -- --