ban-instance 0.1.0.1 → 0.1.1.0
raw patch · 5 files changed
+53/−20 lines, 5 filesdep ~template-haskellnew-uploaderPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: template-haskell
API changes (from Hackage documentation)
Files
- ChangeLog.md +4/−0
- README.md +7/−3
- ban-instance.cabal +16/−13
- src/Language/Haskell/Instance/Ban.hs +20/−4
- test/Spec.hs +6/−0
ChangeLog.md view
@@ -1,5 +1,9 @@ # Changelog for ban-instance +## 0.1.1.0 - 2026-03-30++* Enable banning instances including type variables.+ ## 0.1.0.1 - 2019-11-08 * Remove broken test.
README.md view
@@ -13,7 +13,7 @@ {-# LANGUAGE DataKinds #-} {-# LANGUAGE UndecideableInstances #-} -import Lanuage.Haskell.Instance.Ban+import Language.Haskell.Instance.Ban data Foo = -- ... @@ -69,7 +69,11 @@ ## Limitations -* There is currently no support for type classes with associated types- or associated data types. * Type quotations `[t|...|]` do not support free variables ([GHC#5616](https://gitlab.haskell.org/ghc/ghc/issues/5616)).+ To overcome this limitation, `banInstance` allows you to use an explicit+ `forall`. For example:++ ```haskell+ $(banInstance [t|forall a. ToJSON (Maybe a)|] "use a newtype wrapper at the API layer")+ ```
ban-instance.cabal view
@@ -1,5 +1,6 @@+cabal-version: 1.18 name: ban-instance-version: 0.1.0.1+version: 0.1.1.0 synopsis: For when a type should never be an instance of a class description: <<https://raw.githubusercontent.com/qfpl/assets/master/data61-transparent-bg.png>>@@ -19,19 +20,21 @@ bug-reports: https://github.com/qfpl/ban-instance/issues author: Jack Kelly, Alex Mason maintainer: jack.kelly@data61.csiro.au-copyright: Copyright (C) 2017 Data61+copyright: (c) 2017, Commonwealth Scientific and Industrial Research Organisation license: BSD3 license-file: LICENSE build-type: Simple-cabal-version: >= 1.10-tested-with: GHC == 8.0.2- || == 8.2.2- || == 8.4.4- || == 8.6.5- || == 8.8.1+tested-with: GHC == 8.10.7+ || == 9.0.1+ || == 9.2.7+ || == 9.4.5+ || == 9.6.5+ || == 9.8.2+ || == 9.10.2+ || == 9.12.2 -extra-source-files: ChangeLog.md- README.md+extra-doc-files: ChangeLog.md+ README.md source-repository head type: git@@ -40,8 +43,8 @@ library hs-source-dirs: src ghc-options: -Wall- build-depends: base >= 4.7 && < 4.14- , template-haskell >= 2.11 && < 2.16+ build-depends: base >= 4.7 && < 4.22+ , template-haskell >= 2.16 && < 2.24 exposed-modules: Language.Haskell.Instance.Ban default-language: Haskell2010 @@ -50,6 +53,6 @@ main-is: Spec.hs hs-source-dirs: test ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N- build-depends: base >= 4.7 && < 4.14+ build-depends: base , ban-instance default-language: Haskell2010
src/Language/Haskell/Instance/Ban.hs view
@@ -6,7 +6,7 @@ {-| Module : Language.Haskell.Instance.Ban-Description : Declare that a typeclass instance+Description : Declare that a typeclass instance should never exist. Copyright : (c) 2017, Commonwealth Scientific and Industrial Research Organisation License : BSD3 Maintainer : jack.kelly@data61.csiro.au@@ -38,6 +38,12 @@ -- @ -- \$(banInstance [t|ToJSON Foo|] "why ToJSON Foo should never be defined") -- @+--+-- To ban instances containing type variables:+--+-- @+-- \$(banInstance [t|forall a. ToJSON (Maybe a)|] "why ToJSON (Maybe a) should never be defined")+-- @ banInstance :: TypeQ -- ^ The instance you want to ban.@@ -53,7 +59,7 @@ ':$$: 'Text "Instance banned at " ':<>: 'Text $(symbol $ formatLocation loc) ':$$: 'Text "" )|]]- pure <$> instanceD context constraintQ (convertClassDecs classDecs)+ pure <$> instanceD context (withoutForall <$> constraintQ) (convertClassDecs classDecs) symbol :: String -> TypeQ symbol = litT . strTyLit@@ -61,10 +67,20 @@ formatLocation :: Loc -> String formatLocation Loc{..} = concat ["[", loc_package, ":", loc_module, "] ", loc_filename, ":", show $ fst loc_start] +withoutForall :: Type -> Type+withoutForall topTy = go topTy where+ go (ForallT _ _ ty) = go ty+ go ty = ty+ className :: Type -> Name className topTy = go topTy where- go (AppT ty _) = className ty- go (ConT name) = name+ go (ForallT _ _ ty) = className ty+ go (ForallVisT _ ty) = className ty+ go (AppT ty _) = className ty+ go (AppKindT ty _) = className ty+ go (SigT ty _) = className ty+ go (ConT name) = name+ go (ParensT ty) = className ty go _ = error $ "Cannot determine class name for type: " ++ pprint topTy convertClassDecs :: [Dec] -> [DecQ]
test/Spec.hs view
@@ -2,6 +2,7 @@ {-# LANGUAGE DataKinds #-} {-# LANGUAGE FunctionalDependencies #-}+{-# LANGUAGE ImpredicativeTypes #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE TemplateHaskell #-}@@ -22,6 +23,11 @@ -- Test that we haven't overlapped other instances by mistake. instance TestClass Int Int where testFunction = const 0++class TestClass2 a where+ testFunction2 :: a++$(banInstance [t|forall a. TestClass2 (Maybe a)|] "no instances allowed") main :: IO () main = pure ()