packages feed

ghc-typelits-natnormalise 0.3.1 → 0.4

raw patch · 9 files changed

+274/−69 lines, 9 filesdep ~basedep ~ghcdep ~ghc-tcplugins-extraPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: base, ghc, ghc-tcplugins-extra, ghc-typelits-natnormalise

API changes (from Hackage documentation)

- GHC.TypeLits.Normalise.Unify: Draw :: CoreUnify -> UnifyResult
+ GHC.TypeLits.Normalise.Unify: Draw :: (CoreUnify Ct) -> UnifyResult
- GHC.TypeLits.Normalise.Unify: type CoreUnify = TyUnify TyVar Type Ct
+ GHC.TypeLits.Normalise.Unify: type CoreUnify a = TyUnify TyVar Type a
- GHC.TypeLits.Normalise.Unify: unifiers :: Ct -> CoreSOP -> CoreSOP -> CoreUnify
+ GHC.TypeLits.Normalise.Unify: unifiers :: Ct -> CoreSOP -> CoreSOP -> CoreUnify Ct

Files

CHANGELOG.md view
@@ -1,5 +1,15 @@ # Changelog for the [`ghc-typelits-natnormalise`](http://hackage.haskell.org/package/ghc-typelits-natnormalise) package +## 0.4 *January 19th 2016*+* Stop using 'provenance' hack to create conditional evidence (GHC 8.0+ only)+* Find more unifications:+  * `F x + 2 - 1 - 1 ~ F x` ==> [F x := F x], where `F` can be any type function with result `Nat`.++## 0.3.2+* Find more unifications:+  * `(z ^ a) ~ (z ^ b) ==> [a := b]`+  * `(i ^ a) ~ j ==> [a := round (logBase i j)]`, when `i` and `j` are integers, and `ceiling (logBase i j) == floor (logBase i j)`.+ ## 0.3.1 *October 19th 2015* * Find more unifications:   * `(i * a) ~ j ==> [a := div j i]`, when `i` and `j` are integers, and `mod j i == 0`.
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2015, University of Twente+Copyright (c) 2015-2016, University of Twente All rights reserved.  Redistribution and use in source and binary forms, with or without
ghc-typelits-natnormalise.cabal view
@@ -1,5 +1,5 @@ name:                ghc-typelits-natnormalise-version:             0.3.1+version:             0.4 synopsis:            GHC typechecker plugin for types of kind GHC.TypeLits.Nat description:   A type checker plugin for GHC that can solve /equalities/ of types of kind@@ -41,7 +41,7 @@ license-file:        LICENSE author:              Christiaan Baaij maintainer:          christiaan.baaij@gmail.com-copyright:           Copyright © 2015 University of Twente+copyright:           Copyright © 2015-2016 University of Twente category:            Type System build-type:          Simple extra-source-files:  README.md@@ -64,10 +64,14 @@                        GHC.TypeLits.Normalise.Unify   Other-Modules:       GHC.Extra.Instances   build-depends:       base >=4.8  && <5,-                       ghc  >=7.10 && <7.12,-                       ghc-tcplugins-extra >= 0.1+                       ghc  >=7.10 && <8.2,+                       ghc-tcplugins-extra >= 0.2   hs-source-dirs:      src   default-language:    Haskell2010+  other-extensions:    CPP+                       LambdaCase+                       RecordWildCards+                       TupleSections   if flag(deverror)     ghc-options:         -Wall -Werror   else@@ -77,11 +81,18 @@   type:                exitcode-stdio-1.0   main-is:             Tests.hs   Other-Modules:       ErrorTests-  build-depends:       base >=4.8 && <4.9,-                       ghc-typelits-natnormalise >= 0.1,+  build-depends:       base >=4.8 && <5,+                       ghc-typelits-natnormalise >= 0.4,                        tasty >= 0.10,                        tasty-hunit >= 0.9   hs-source-dirs:      tests   default-language:    Haskell2010+  other-extensions:    DataKinds+                       GADTs+                       KindSignatures+                       NoImplicitPrelude+                       TypeFamilies+                       TypeOperators+                       ScopedTypeVariables   if flag(deverror)     ghc-options:       -O0 -dcore-lint
src/GHC/Extra/Instances.hs view
@@ -1,6 +1,5 @@-{-# OPTIONS_GHC -fno-warn-orphans #-} {-|-Copyright  :  (C) 2015, University of Twente+Copyright  :  (C) 2015-2016, University of Twente License    :  BSD2 (see the file LICENSE) Maintainer :  Christiaan Baaij <christiaan.baaij@gmail.com> @@ -8,9 +7,21 @@  * 'Ord' instance for 'Type' and 'Ct' -}++{-# LANGUAGE CPP #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}+ module GHC.Extra.Instances where -import Type          (Type,cmpType)+import Type (Type,cmpType)+#if __GLASGOW_HASKELL__ >= 711+import Type (eqType)+#endif++#if __GLASGOW_HASKELL__ >= 711+instance Eq Type where+  (==) = eqType+#endif  instance Ord Type where   compare = cmpType
src/GHC/TypeLits/Normalise.hs view
@@ -1,12 +1,5 @@-{-# LANGUAGE CPP             #-}-{-# LANGUAGE LambdaCase      #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE TupleSections   #-}--{-# OPTIONS_HADDOCK show-extensions #-}- {-|-Copyright  :  (C) 2015, University of Twente+Copyright  :  (C) 2015-2016, University of Twente License    :  BSD2 (see the file LICENSE) Maintainer :  Christiaan Baaij <christiaan.baaij@gmail.com> @@ -44,6 +37,18 @@  To the header of your file. -}++{-# LANGUAGE CPP             #-}+{-# LANGUAGE LambdaCase      #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE TupleSections   #-}++{-# OPTIONS_HADDOCK show-extensions #-}++#if __GLASGOW_HASKELL__ < 711+{-# OPTIONS_GHC -fno-warn-deprecations #-}+#endif+ module GHC.TypeLits.Normalise   ( plugin ) where@@ -51,21 +56,33 @@ -- external import Data.IORef          (IORef, newIORef,readIORef, modifyIORef) import Data.Maybe          (catMaybes, mapMaybe)-import GHC.TcPluginM.Extra (evByFiat, failWithProvenace, newGiven,-                            newWantedWithProvenance, tracePlugin)+import GHC.TcPluginM.Extra (evByFiat, newGiven, tracePlugin)  -- GHC API import Outputable (Outputable (..), (<+>), ($$), text) import Plugins    (Plugin (..), defaultPlugin)-import TcEvidence (EvTerm)+import TcEvidence (EvTerm (..)) import TcPluginM  (TcPluginM, tcPluginIO, tcPluginTrace, zonkCt) import TcRnTypes  (Ct, TcPlugin (..), TcPluginResult(..), ctEvidence, ctEvPred,                    ctPred, ctLoc, isGiven, isWanted, mkNonCanonical)-import TcType     (mkEqPred, typeKind)-import Type       (EqRel (NomEq), Kind, PredTree (EqPred), Type, TyVar,-                   classifyPredType, mkTyVarTy)+import Type       (EqRel (NomEq), Kind, PredTree (EqPred), PredType, Type, TyVar,+                   classifyPredType, getEqPredTys, mkTyVarTy) import TysWiredIn (typeNatKind) +#if __GLASGOW_HASKELL__ >= 711+import Coercion   (CoercionHole, Role (..), mkForAllCos, mkHoleCo, mkInstCo,+                   mkNomReflCo, mkUnivCo)+import TcPluginM  (newCoercionHole, newFlexiTyVar)+import TcRnTypes  (CtEvidence (..), TcEvDest (..))+import TyCoRep    (UnivCoProvenance (..))+import Type       (mkPrimEqPred)+import TcType     (typeKind)+#else+import TcType              (mkEqPred, typeKind)+import GHC.TcPluginM.Extra (newWantedWithProvenance, failWithProvenace)+#endif++ -- internal import GHC.Extra.Instances () -- Ord instance for Ct import GHC.TypeLits.Normalise.Unify@@ -104,7 +121,11 @@           Simplified subst evs -> do             let solved     = filter (isWanted . ctEvidence . snd) evs             -- Create new wanted constraints+#if __GLASGOW_HASKELL__ >= 711+            let newWanteds = filter (isWanted . ctEvidence . snd . siNote) subst+#else             let newWanteds = filter (isWanted . ctEvidence . siNote) subst+#endif             discharedWanteds <- tcPluginIO (readIORef discharged)             let existingWanteds = wanteds' ++ discharedWanteds             newWantedConstraints <- catMaybes <$>@@ -114,10 +135,14 @@             tcPluginIO (modifyIORef discharged (++ newWantedConstraints))             -- return             return (TcPluginOk solved newWantedConstraints)-          Impossible eq -> failWithProvenace $ fromNatEquality eq+#if __GLASGOW_HASKELL__ >= 711+          Impossible eq -> return (TcPluginContradiction [fromNatEquality eq])+#else+          Impossible eq -> failWithProvenace (fromNatEquality eq)+#endif  substItemToCt :: [Ct] -- ^ Existing wanteds wanted-              -> UnifyItem TyVar Type Ct+              -> UnifyItem TyVar Type CoreNote               -> TcPluginM (Maybe Ct) substItemToCt existingWanteds si   | isGiven (ctEvidence ct)@@ -126,32 +151,57 @@   -- Only create new wanteds   | predicate  `notElem` wantedPreds   , predicateS `notElem` wantedPreds+#if __GLASGOW_HASKELL__ >= 711+  = return (Just (mkNonCanonical (CtWanted predicate (HoleDest ev) loc)))+#else   = Just <$> mkNonCanonical <$> newWantedWithProvenance (ctEvidence ct) predicate+#endif    | otherwise   = return Nothing   where-    predicate   = mkEqPred ty1 ty2+    predicate   = unifyItemToPredType si+    (ty1,ty2)   = getEqPredTys predicate+#if __GLASGOW_HASKELL__ >= 711+    predicateS    = mkPrimEqPred ty2 ty1+    ((ev,_,_),ct) = siNote si+#else     predicateS  = mkEqPred ty2 ty1+    ct          = siNote si+#endif     wantedPreds = map ctPred existingWanteds -    ty1       = case si of-                  (SubstItem {..}) -> mkTyVarTy siVar-                  (UnifyItem {..}) -> reifySOP siLHS-    ty2       = case si of-                  (SubstItem {..}) -> reifySOP siSOP-                  (UnifyItem {..}) -> reifySOP siRHS-    ct        = siNote si     loc       = ctLoc ct     evTm      = evByFiat "ghc-typelits-natnormalise" ty1 ty2 +unifyItemToPredType :: UnifyItem TyVar Type a -> PredType+unifyItemToPredType ui =+#if __GLASGOW_HASKELL__ >= 711+    mkPrimEqPred ty1 ty2+#else+    mkEqPred ty1 ty2+#endif+  where+    ty1 = case ui of+            SubstItem {..} -> mkTyVarTy siVar+            UnifyItem {..} -> reifySOP siLHS+    ty2 = case ui of+            SubstItem {..} -> reifySOP siSOP+            UnifyItem {..} -> reifySOP siRHS+ type NatEquality = (Ct,CoreSOP,CoreSOP)  fromNatEquality :: NatEquality -> Ct fromNatEquality (ct, _, _) = ct +#if __GLASGOW_HASKELL__ >= 711+type CoreNote = ((CoercionHole,TyVar,PredType), Ct)+#else+type CoreNote = Ct+#endif+ data SimplifyResult-  = Simplified CoreUnify [(EvTerm,Ct)]+  = Simplified (CoreUnify CoreNote) [(EvTerm,Ct)]   | Impossible NatEquality  instance Outputable SimplifyResult where@@ -163,20 +213,38 @@ simplifyNats eqs =     tcPluginTrace "simplifyNats" (ppr eqs) >> simples [] [] [] eqs   where-    simples :: CoreUnify -> [Maybe (EvTerm, Ct)] -> [NatEquality]+    simples :: CoreUnify CoreNote -> [Maybe (EvTerm, Ct)] -> [NatEquality]             -> [NatEquality] -> TcPluginM SimplifyResult     simples subst evs _xs [] = return (Simplified subst (catMaybes evs))     simples subst evs xs (eq@(ct,u,v):eqs') = do       ur <- unifyNats ct (substsSOP subst u) (substsSOP subst v)       tcPluginTrace "unifyNats result" (ppr ur)       case ur of+#if __GLASGOW_HASKELL__ >= 711+        Win         -> simples subst (((,) <$> evMagic ct [] <*> pure ct):evs) []+                               (xs ++ eqs')+        Lose        -> return (Impossible eq)+        Draw []     -> simples subst evs (eq:xs) eqs'+        Draw subst' -> do+          newEvs <- mapM (\si -> (,,) <$> newCoercionHole+                                      <*> newFlexiTyVar typeNatKind+                                      <*> pure (unifyItemToPredType si))+                         subst'+          let subst'' = zipWith (\si ev -> si {siNote = (ev,siNote si)})+                                subst' newEvs+          simples (substsSubst subst'' subst ++ subst'')+            (((,) <$> evMagic ct newEvs <*> pure ct):evs)+            [] (xs ++ eqs')+#else         Win         -> simples subst (((,) <$> evMagic ct <*> pure ct):evs) []                                (xs ++ eqs')         Lose        -> return (Impossible eq)         Draw []     -> simples subst evs (eq:xs) eqs'-        Draw subst' -> simples (substsSubst subst' subst ++ subst')-                               (((,) <$> evMagic ct <*> pure ct):evs)-                               [] (xs ++ eqs')+        Draw subst' -> do+          simples (substsSubst subst' subst ++ subst')+                  (((,) <$> evMagic ct <*> pure ct):evs)+                  [] (xs ++ eqs')+#endif  -- Extract the Nat equality constraints toNatEquality :: Ct -> Maybe NatEquality@@ -189,7 +257,22 @@     isNatKind :: Kind -> Bool     isNatKind = (== typeNatKind) +#if __GLASGOW_HASKELL__ >= 711+evMagic :: Ct -> [(CoercionHole, TyVar, PredType)] -> Maybe EvTerm+evMagic ct evs = case classifyPredType $ ctEvPred $ ctEvidence ct of+  EqPred NomEq t1 t2 ->+    let ctEv = mkUnivCo (PluginProv "ghc-typelits-natnormalise") Nominal t1 t2+        (holes,tvs,preds) = unzip3 evs+        holeEvs = zipWith (\h p -> uncurry (mkHoleCo h Nominal) (getEqPredTys p))+                          holes preds+        natReflCo = mkNomReflCo typeNatKind+        forallEv = mkForAllCos (map (,natReflCo) tvs) ctEv+        finalEv = foldl mkInstCo forallEv holeEvs+    in  Just (EvCoercion finalEv)+  _ -> Nothing+#else evMagic :: Ct -> Maybe EvTerm evMagic ct = case classifyPredType $ ctEvPred $ ctEvidence ct of   EqPred NomEq t1 t2 -> Just (evByFiat "ghc-typelits-natnormalise" t1 t2)   _                  -> Nothing+#endif
src/GHC/TypeLits/Normalise/SOP.hs view
@@ -1,5 +1,5 @@ {-|-Copyright  :  (C) 2015, University of Twente+Copyright  :  (C) 2015-2016, University of Twente License    :  BSD2 (see the file LICENSE) Maintainer :  Christiaan Baaij <christiaan.baaij@gmail.com> @@ -284,10 +284,12 @@   . mergeWith mergeP   . map (P . sort . map reduceExp . mergeWith mergeS . unP)   . unS+{-# INLINEABLE simplifySOP #-}  -- | Merge two SOP terms by additions mergeSOPAdd :: (Ord v, Ord c) => SOP v c -> SOP v c -> SOP v c mergeSOPAdd (S sop1) (S sop2) = simplifySOP $ S (sop1 ++ sop2)+{-# INLINEABLE mergeSOPAdd #-}  -- | Merge two SOP terms by multiplication mergeSOPMul :: (Ord v, Ord c) => SOP v c -> SOP v c -> SOP v c@@ -295,3 +297,4 @@   = simplifySOP   . S   $ concatMap (zipWith (\p1 p2 -> P (unP p1 ++ unP p2)) sop1 . repeat) sop2+{-# INLINEABLE mergeSOPMul #-}
src/GHC/TypeLits/Normalise/Unify.hs view
@@ -1,11 +1,13 @@-{-# LANGUAGE RecordWildCards #-}-{-# OPTIONS_GHC -fno-warn-unused-imports #-}- {-|-Copyright  :  (C) 2015, University of Twente+Copyright  :  (C) 2015-2016, University of Twente License    :  BSD2 (see the file LICENSE) Maintainer :  Christiaan Baaij <christiaan.baaij@gmail.com> -}++{-# LANGUAGE CPP             #-}+{-# LANGUAGE RecordWildCards #-}+{-# OPTIONS_GHC -fno-warn-unused-imports #-}+ module GHC.TypeLits.Normalise.Unify   ( -- * 'Nat' expressions \<-\> 'SOP' terms     CoreSOP@@ -34,10 +36,16 @@ import Outputable    (Outputable (..), (<+>), ($$), text) import TcPluginM     (TcPluginM, tcPluginTrace) import TcRnMonad     (Ct, ctEvidence, isGiven)+import TcRnTypes     (ctEvPred) import TcTypeNats    (typeNatAddTyCon, typeNatExpTyCon, typeNatMulTyCon,                       typeNatSubTyCon)-import Type          (TyVar, mkNumLitTy, mkTyConApp, mkTyVarTy, tcView)+import Type          (EqRel (NomEq), PredTree (EqPred), TyVar, classifyPredType,+                      coreView, mkNumLitTy, mkTyConApp, mkTyVarTy)+#if __GLASGOW_HASKELL__ >= 711+import TyCoRep       (Type (..), TyLit (..))+#else import TypeRep       (Type (..), TyLit (..))+#endif import UniqSet       (UniqSet, unionManyUniqSets, emptyUniqSet, unionUniqSets,                       unitUniqSet) @@ -60,7 +68,7 @@ -- * type variables -- * Applications of the arithmetic operators @(+,-,*,^)@ normaliseNat :: Type -> CoreSOP-normaliseNat ty | Just ty1 <- tcView ty = normaliseNat ty1+normaliseNat ty | Just ty1 <- coreView ty = normaliseNat ty1 normaliseNat (TyVarTy v)          = S [P [V v]] normaliseNat (LitTy (NumTyLit i)) = S [P [I i]] normaliseNat (TyConApp tc [x,y])@@ -105,7 +113,8 @@ -- | A substitution is essentially a list of (variable, 'SOP') pairs, -- but we keep the original 'Ct' that lead to the substitution being -- made, for use when turning the substitution back into constraints.-type CoreUnify     = TyUnify TyVar Type Ct+type CoreUnify a = TyUnify TyVar Type a+ type TyUnify v c n = [UnifyItem v c n]  data UnifyItem v c n = SubstItem { siVar  :: v@@ -147,13 +156,14 @@   where     subt si@(SubstItem {..}) = si {siSOP = substsSOP s siSOP}     subt si@(UnifyItem {..}) = si {siLHS = substsSOP s siLHS, siRHS = substsSOP s siRHS}+{-# INLINEABLE substsSubst #-}  -- | Result of comparing two 'SOP' terms, returning a potential substitution -- list under which the two terms are equal. data UnifyResult   = Win            -- ^ Two terms are equal   | Lose           -- ^ Two terms are /not/ equal-  | Draw CoreUnify -- ^ Two terms are only equal if the given substitution holds+  | Draw (CoreUnify Ct) -- ^ Two terms are only equal if the given substitution holds  instance Outputable UnifyResult where   ppr Win          = text "Win"@@ -172,12 +182,15 @@  unifyNats' :: Ct -> CoreSOP -> CoreSOP -> UnifyResult unifyNats' ct u v-  | eqFV u v-  , not (containsConstants u)-  , not (containsConstants v)-  = if u == v then Win else Lose-  | otherwise-  = Draw (unifiers ct u v)+  = if eqFV u v+       then if containsConstants u || containsConstants v+               then if u == v+                       then Win+                       else Draw (unifiers ct u v)+               else if u == v+                       then Win+                       else Lose+       else Draw (unifiers ct u v)  -- | Find unifiers for two SOP terms --@@ -212,18 +225,30 @@ -- @ -- [a := b] -- @-unifiers :: Ct -> CoreSOP -> CoreSOP -> CoreUnify-unifiers ct (S [P [V x]]) s-  | isGiven (ctEvidence ct) = [SubstItem x s ct]-  | otherwise               = []-unifiers ct s (S [P [V x]])-  | isGiven (ctEvidence ct) = [SubstItem x s ct]-  | otherwise               = []-unifiers _ (S [P [C _]]) _  = []-unifiers _ _ (S [P [C _]])  = []+unifiers :: Ct -> CoreSOP -> CoreSOP -> CoreUnify Ct+unifiers ct u@(S [P [V x]]) v+  = case classifyPredType $ ctEvPred $ ctEvidence ct of+      EqPred NomEq t1 _+        | reifySOP u /= t1 || isGiven (ctEvidence ct) -> [SubstItem x v ct]+      _ -> []+unifiers ct u v@(S [P [V x]])+  = case classifyPredType $ ctEvPred $ ctEvidence ct of+      EqPred NomEq _ t2+        | reifySOP v /= t2 || isGiven (ctEvidence ct) -> [SubstItem x u ct]+      _ -> []+unifiers ct u@(S [P [C _]]) v+  = case classifyPredType $ ctEvPred $ ctEvidence ct of+      EqPred NomEq t1 t2+        | reifySOP u /= t1 || reifySOP v /= t2 -> [UnifyItem u v ct]+      _ -> []+unifiers ct u v@(S [P [C _]])+  = case classifyPredType $ ctEvPred $ ctEvidence ct of+      EqPred NomEq t1 t2+        | reifySOP u /= t1 || reifySOP v /= t2 -> [UnifyItem u v ct]+      _ -> [] unifiers ct u v             = unifiers' ct u v -unifiers' :: Ct -> CoreSOP -> CoreSOP -> CoreUnify+unifiers' :: Ct -> CoreSOP -> CoreSOP -> CoreUnify Ct unifiers' ct (S [P [V x]]) (S [])        = [SubstItem x (S [P [I 0]]) ct] unifiers' ct (S [])        (S [P [V x]]) = [SubstItem x (S [P [I 0]]) ct] @@ -232,6 +257,31 @@  unifiers' ct s1@(S [P [C _]]) s2               = [UnifyItem s1 s2 ct] unifiers' ct s1               s2@(S [P [C _]]) = [UnifyItem s1 s2 ct]+++-- (z ^ a) ~ (z ^ b) ==> [a := b]+unifiers' ct (S [P [E s1 p1]]) (S [P [E s2 p2]])+  | s1 == s2 = unifiers' ct (S [p1]) (S [p2])++-- (i ^ a) ~ j ==> [a := round (logBase i j)], when `i` and `j` are integers,+-- and `ceiling (logBase i j) == floor (logBase i j)`+unifiers' ct (S [P [E (S [P [I i]]) p]]) (S [P [I j]])+    = if kC == kF+         then unifiers' ct (S [p]) (S [P [I kC]])+         else []+  where+    k  = logBase (fromInteger i :: Double) (fromInteger j)+    kC = ceiling k :: Integer+    kF = floor k :: Integer++unifiers' ct (S [P [I j]]) (S [P [E (S [P [I i]]) p]])+    = if kC == kF+         then unifiers' ct (S [p]) (S [P [I kC]])+         else []+  where+    k  = logBase (fromInteger i :: Double) (fromInteger j)+    kC = ceiling k :: Integer+    kF = floor k :: Integer  -- (i * a) ~ j ==> [a := div j i] -- Where 'a' is a variable, 'i' and 'j' are integer literals, and j `mod` i == 0
tests/ErrorTests.hs view
@@ -56,3 +56,25 @@   ["Expected type: Proxy 7 -> ()"   ,"Actual type: Proxy ((2 * y1) + 4) -> ()"   ]++proxyFun6 :: Proxy (2^k) -> Proxy (2^k)+proxyFun6 = const Proxy++testProxy6 :: Proxy 7+testProxy6 = proxyFun6 (Proxy :: Proxy 7)++testProxy6Errors =+  ["Expected type: Proxy (2 ^ k0)"+  ,"Actual type: Proxy 7"+  ]++proxyFun7 :: Proxy (2^k) -> Proxy k+proxyFun7 = const Proxy++testProxy8 :: Proxy x -> Proxy (y + x)+testProxy8 = id++testProxy8Errors =+  ["Expected type: Proxy x -> Proxy (y + x)"+  ,"Actual type: Proxy x -> Proxy x"+  ]
tests/Tests.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP                 #-} {-# LANGUAGE DataKinds           #-} {-# LANGUAGE GADTs               #-} {-# LANGUAGE KindSignatures      #-}@@ -7,13 +8,13 @@  {-# OPTIONS_GHC -fplugin GHC.TypeLits.Normalise #-} -import Data.Proxy import GHC.TypeLits import Unsafe.Coerce import Prelude hiding (head,tail,init,(++),splitAt,concat,drop) import qualified Prelude as P  import Data.List (isInfixOf)+import Data.Proxy import Control.Exception import Test.Tasty import Test.Tasty.HUnit@@ -27,7 +28,7 @@ instance Show a => Show (Vec n a) where   show vs = "<" P.++ punc vs P.++ ">"     where-      punc :: Show a => Vec m a -> String+      punc :: Vec m a -> String       punc Nil        = ""       punc (x :> Nil) = show x       punc (x :> xs)  = show x P.++ "," P.++ punc xs@@ -266,6 +267,9 @@     , testCase "show (proxyFun4 (Proxy :: Proxy 8))" $       show (proxyFun4 (Proxy :: Proxy 8)) @?=       "()"+    , testCase "show (proxyFun7 (Proxy :: Proxy 8) :: Proxy 3)" $+      show (proxyFun7 (Proxy :: Proxy 8) :: Proxy 3) @?=+      "Proxy"     ]   , testGroup "errors"     [ testCase "x + 2 ~ 3 + x" $ testProxy1 `throws` testProxy1Errors@@ -273,6 +277,8 @@     , testCase "Unify \"x + x + x\" with \"8\"" $ testProxy3 `throws` testProxy3Errors     , testCase "Unify \"(2*x)+4\" with \"2\"" $ testProxy4 `throws` testProxy4Errors     , testCase "Unify \"(2*x)+4\" with \"7\"" $ testProxy5 `throws` testProxy5Errors+    , testCase "Unify \"2^k\" with \"7\"" $ testProxy6 `throws` testProxy6Errors+    , testCase "x ~ y + x" $ testProxy8 `throws` testProxy8Errors     ]   ] @@ -280,6 +286,15 @@ -- an exception whose string representation contains the given -- substrings. throws :: a -> [String] -> Assertion-throws v xs =-  (evaluate v >> assertFailure "No exception!")-  `catch` \ (e :: SomeException) -> if all (`isInfixOf` show e) xs then return () else throw e+throws v xs = do+  result <- try (evaluate v)+  case result of+    Right _ -> assertFailure "No exception!"+#if MIN_VERSION_base(4,9,0)+    Left (TypeError msg) ->+#else+    Left (ErrorCall msg) ->+#endif+      if all (`isInfixOf` msg) xs+         then return ()+         else assertFailure msg