packages feed

monadic-bang 0.1.1.0 → 0.2.1.0

raw patch · 20 files changed

+380/−293 lines, 20 filesdep −exceptionsdep ~basedep ~containersdep ~ghcPVP ok

version bump matches the API change (PVP)

Dependencies removed: exceptions

Dependency ranges changed: base, containers, ghc, ghc-boot

API changes (from Hackage documentation)

- MonadicBang.Effect.Offer: OfferC :: StateC (Map k v) m a -> OfferC k v m a
- MonadicBang.Effect.Offer: [Yoink] :: k -> Offer k v m (Maybe v)
- MonadicBang.Effect.Offer: [getOfferState] :: OfferC k v m a -> StateC (Map k v) m a
- MonadicBang.Effect.Offer: data Offer k v m a
- MonadicBang.Effect.Offer: instance (Control.Algebra.Algebra sig m, GHC.Classes.Ord k) => Control.Algebra.Algebra (MonadicBang.Effect.Offer.Offer k v Control.Effect.Sum.:+: sig) (MonadicBang.Effect.Offer.OfferC k v m)
- MonadicBang.Effect.Offer: instance GHC.Base.Functor m => GHC.Base.Functor (MonadicBang.Effect.Offer.OfferC k v m)
- MonadicBang.Effect.Offer: instance GHC.Base.Monad m => GHC.Base.Applicative (MonadicBang.Effect.Offer.OfferC k v m)
- MonadicBang.Effect.Offer: instance GHC.Base.Monad m => GHC.Base.Monad (MonadicBang.Effect.Offer.OfferC k v m)
- MonadicBang.Effect.Offer: newtype OfferC k v m a
- MonadicBang.Effect.Offer: runOffer :: Map k v -> OfferC k v m a -> m (Map k v, a)
- MonadicBang.Effect.Offer: yoink :: Has (Offer k v) sig m => k -> m (Maybe v)
- MonadicBang.Effect.Uniques: UniquesC :: StateC UniqSupply m a -> UniquesC m a
- MonadicBang.Effect.Uniques: [FreshUnique] :: Uniques m Unique
- MonadicBang.Effect.Uniques: [getUniquesState] :: UniquesC m a -> StateC UniqSupply m a
- MonadicBang.Effect.Uniques: data Uniques m a
- MonadicBang.Effect.Uniques: freshUnique :: Has Uniques sig m => m Unique
- MonadicBang.Effect.Uniques: instance Control.Algebra.Algebra sig m => Control.Algebra.Algebra (MonadicBang.Effect.Uniques.Uniques Control.Effect.Sum.:+: sig) (MonadicBang.Effect.Uniques.UniquesC m)
- MonadicBang.Effect.Uniques: instance GHC.Base.Functor m => GHC.Base.Functor (MonadicBang.Effect.Uniques.UniquesC m)
- MonadicBang.Effect.Uniques: instance GHC.Base.Monad m => GHC.Base.Applicative (MonadicBang.Effect.Uniques.UniquesC m)
- MonadicBang.Effect.Uniques: instance GHC.Base.Monad m => GHC.Base.Monad (MonadicBang.Effect.Uniques.UniquesC m)
- MonadicBang.Effect.Uniques: newtype UniquesC m a
- MonadicBang.Effect.Uniques: runUniques :: Functor m => UniqSupply -> UniquesC m a -> m a
- MonadicBang.Effect.Uniques: runUniquesIO :: MonadIO m => Char -> UniquesC m a -> m a
- MonadicBang.Effect.Writer.Discard: DiscardC :: m a -> DiscardC w m a
- MonadicBang.Effect.Writer.Discard: [evalDiscardC] :: DiscardC w m a -> m a
- MonadicBang.Effect.Writer.Discard: evalWriter :: (Monoid w, Algebra sig m) => DiscardC w m a -> m a
- MonadicBang.Effect.Writer.Discard: instance (GHC.Base.Monoid w, Control.Algebra.Algebra sig m) => Control.Algebra.Algebra (Control.Effect.Writer.Internal.Writer w Control.Effect.Sum.:+: sig) (MonadicBang.Effect.Writer.Discard.DiscardC w m)
- MonadicBang.Effect.Writer.Discard: instance forall k (w :: k) (m :: * -> *). GHC.Base.Applicative m => GHC.Base.Applicative (MonadicBang.Effect.Writer.Discard.DiscardC w m)
- MonadicBang.Effect.Writer.Discard: instance forall k (w :: k) (m :: * -> *). GHC.Base.Functor m => GHC.Base.Functor (MonadicBang.Effect.Writer.Discard.DiscardC w m)
- MonadicBang.Effect.Writer.Discard: instance forall k (w :: k) (m :: * -> *). GHC.Base.Monad m => GHC.Base.Monad (MonadicBang.Effect.Writer.Discard.DiscardC w m)
- MonadicBang.Effect.Writer.Discard: newtype DiscardC w m a
- MonadicBang.Error: ErrBangOutsideOfDo :: Error
- MonadicBang.Error: ErrOutOfScopeVariable :: OccName -> Error
- MonadicBang.Error: customError :: Error -> PsError
- MonadicBang.Error: data Error
- MonadicBang.Error: tellPsError :: Has PsErrors sig m => PsError -> SrcSpan -> m ()
- MonadicBang.Error: type PsErrors = Writer (Messages PsError)
- MonadicBang.Internal: [$sel:col:MkLoc] :: Loc -> Int
- MonadicBang.Internal: [$sel:invalid:MkInScope] :: InScope -> OccSet
- MonadicBang.Internal: [$sel:line:MkLoc] :: Loc -> Int
- MonadicBang.Internal: [$sel:valid:MkInScope] :: InScope -> OccSet
- MonadicBang.Options: Don'tPreserve :: PreserveErrors
- MonadicBang.Options: DumpTransformed :: Verbosity
- MonadicBang.Options: MkOptions :: Verbosity -> PreserveErrors -> Options
- MonadicBang.Options: Preserve :: PreserveErrors
- MonadicBang.Options: Quiet :: Verbosity
- MonadicBang.Options: [preserveErrors] :: Options -> PreserveErrors
- MonadicBang.Options: [verbosity] :: Options -> Verbosity
- MonadicBang.Options: data Options
- MonadicBang.Options: data PreserveErrors
- MonadicBang.Options: data Verbosity
- MonadicBang.Options: parseOptions :: Has (Throw ErrorCall) sig m => Located (HsModule GhcPs) -> [CommandLineOption] -> m Options
- MonadicBang.Utils: (??) :: Functor f => f (a -> b) -> a -> f b
- MonadicBang.Utils: fromDList :: DList a -> [a]
- MonadicBang.Utils: panic :: HasCallStack => String -> a
- MonadicBang.Utils: type DList a = Endo [a]
- MonadicBang.Utils: type Handler m a = a -> m a
- MonadicBang.Utils: type Try m a = Handler (MaybeT m) a
+ MonadicBang.Internal: [col] :: Loc -> Int
+ MonadicBang.Internal: [invalid] :: InScope -> OccSet
+ MonadicBang.Internal: [line] :: Loc -> Int
+ MonadicBang.Internal: [valid] :: InScope -> OccSet
+ MonadicBang.Internal.Effect.Offer: OfferC :: StateC (Map k v) m a -> OfferC k v (m :: Type -> Type) a
+ MonadicBang.Internal.Effect.Offer: [Yoink] :: forall {k} k1 v (m :: k). k1 -> Offer k1 v m (Maybe v)
+ MonadicBang.Internal.Effect.Offer: [getOfferState] :: OfferC k v (m :: Type -> Type) a -> StateC (Map k v) m a
+ MonadicBang.Internal.Effect.Offer: data Offer k1 v (m :: k) a
+ MonadicBang.Internal.Effect.Offer: instance (Control.Algebra.Algebra sig m, GHC.Classes.Ord k) => Control.Algebra.Algebra (MonadicBang.Internal.Effect.Offer.Offer k v Control.Effect.Sum.:+: sig) (MonadicBang.Internal.Effect.Offer.OfferC k v m)
+ MonadicBang.Internal.Effect.Offer: instance GHC.Base.Functor m => GHC.Base.Functor (MonadicBang.Internal.Effect.Offer.OfferC k v m)
+ MonadicBang.Internal.Effect.Offer: instance GHC.Base.Monad m => GHC.Base.Applicative (MonadicBang.Internal.Effect.Offer.OfferC k v m)
+ MonadicBang.Internal.Effect.Offer: instance GHC.Base.Monad m => GHC.Base.Monad (MonadicBang.Internal.Effect.Offer.OfferC k v m)
+ MonadicBang.Internal.Effect.Offer: newtype OfferC k v (m :: Type -> Type) a
+ MonadicBang.Internal.Effect.Offer: runOffer :: Map k v -> OfferC k v m a -> m (Map k v, a)
+ MonadicBang.Internal.Effect.Offer: yoink :: forall k v (sig :: (Type -> Type) -> Type -> Type) m. Has (Offer k v :: (Type -> Type) -> Type -> Type) sig m => k -> m (Maybe v)
+ MonadicBang.Internal.Effect.Uniques: UniquesC :: StateC UniqSupply m a -> UniquesC (m :: Type -> Type) a
+ MonadicBang.Internal.Effect.Uniques: [FreshUnique] :: forall {k} (m :: k). Uniques m Unique
+ MonadicBang.Internal.Effect.Uniques: [getUniquesState] :: UniquesC (m :: Type -> Type) a -> StateC UniqSupply m a
+ MonadicBang.Internal.Effect.Uniques: data Uniques (m :: k) a
+ MonadicBang.Internal.Effect.Uniques: freshUnique :: forall (sig :: (Type -> Type) -> Type -> Type) m. Has (Uniques :: (Type -> Type) -> Type -> Type) sig m => m Unique
+ MonadicBang.Internal.Effect.Uniques: instance Control.Algebra.Algebra sig m => Control.Algebra.Algebra (MonadicBang.Internal.Effect.Uniques.Uniques Control.Effect.Sum.:+: sig) (MonadicBang.Internal.Effect.Uniques.UniquesC m)
+ MonadicBang.Internal.Effect.Uniques: instance GHC.Base.Functor m => GHC.Base.Functor (MonadicBang.Internal.Effect.Uniques.UniquesC m)
+ MonadicBang.Internal.Effect.Uniques: instance GHC.Base.Monad m => GHC.Base.Applicative (MonadicBang.Internal.Effect.Uniques.UniquesC m)
+ MonadicBang.Internal.Effect.Uniques: instance GHC.Base.Monad m => GHC.Base.Monad (MonadicBang.Internal.Effect.Uniques.UniquesC m)
+ MonadicBang.Internal.Effect.Uniques: newtype UniquesC (m :: Type -> Type) a
+ MonadicBang.Internal.Effect.Uniques: runUniques :: Functor m => UniqSupply -> UniquesC m a -> m a
+ MonadicBang.Internal.Effect.Uniques: runUniquesIO :: MonadIO m => Char -> UniquesC m a -> m a
+ MonadicBang.Internal.Effect.Writer.Discard: DiscardC :: m a -> DiscardC (w :: k) (m :: k1 -> Type) (a :: k1)
+ MonadicBang.Internal.Effect.Writer.Discard: [evalDiscardC] :: DiscardC (w :: k) (m :: k1 -> Type) (a :: k1) -> m a
+ MonadicBang.Internal.Effect.Writer.Discard: evalWriter :: forall w (sig :: (Type -> Type) -> Type -> Type) m a. (Monoid w, Algebra sig m) => DiscardC w m a -> m a
+ MonadicBang.Internal.Effect.Writer.Discard: instance (GHC.Base.Monoid w, Control.Algebra.Algebra sig m) => Control.Algebra.Algebra (Control.Effect.Writer.Internal.Writer w Control.Effect.Sum.:+: sig) (MonadicBang.Internal.Effect.Writer.Discard.DiscardC w m)
+ MonadicBang.Internal.Effect.Writer.Discard: instance forall k (w :: k) (m :: * -> *). GHC.Base.Applicative m => GHC.Base.Applicative (MonadicBang.Internal.Effect.Writer.Discard.DiscardC w m)
+ MonadicBang.Internal.Effect.Writer.Discard: instance forall k (w :: k) (m :: * -> *). GHC.Base.Functor m => GHC.Base.Functor (MonadicBang.Internal.Effect.Writer.Discard.DiscardC w m)
+ MonadicBang.Internal.Effect.Writer.Discard: instance forall k (w :: k) (m :: * -> *). GHC.Base.Monad m => GHC.Base.Monad (MonadicBang.Internal.Effect.Writer.Discard.DiscardC w m)
+ MonadicBang.Internal.Effect.Writer.Discard: newtype DiscardC (w :: k) (m :: k1 -> Type) (a :: k1)
+ MonadicBang.Internal.Error: ErrBangOutsideOfDo :: Error
+ MonadicBang.Internal.Error: ErrOutOfScopeVariable :: OccName -> Error
+ MonadicBang.Internal.Error: customError :: Error -> PsError
+ MonadicBang.Internal.Error: data Error
+ MonadicBang.Internal.Error: tellPsError :: forall (sig :: (Type -> Type) -> Type -> Type) m. Has PsErrors sig m => PsError -> SrcSpan -> m ()
+ MonadicBang.Internal.Error: type PsErrors = Writer Messages PsError
+ MonadicBang.Internal.Options: Don'tPreserve :: PreserveErrors
+ MonadicBang.Internal.Options: DumpTransformed :: Verbosity
+ MonadicBang.Internal.Options: MkOptions :: Verbosity -> PreserveErrors -> Options
+ MonadicBang.Internal.Options: Preserve :: PreserveErrors
+ MonadicBang.Internal.Options: Quiet :: Verbosity
+ MonadicBang.Internal.Options: [preserveErrors] :: Options -> PreserveErrors
+ MonadicBang.Internal.Options: [verbosity] :: Options -> Verbosity
+ MonadicBang.Internal.Options: data Options
+ MonadicBang.Internal.Options: data PreserveErrors
+ MonadicBang.Internal.Options: data Verbosity
+ MonadicBang.Internal.Options: parseOptions :: forall (sig :: (Type -> Type) -> Type -> Type) m. Has (Throw ErrorCall) sig m => Located (HsModule GhcPs) -> [CommandLineOption] -> m Options
+ MonadicBang.Internal.Utils: (??) :: Functor f => f (a -> b) -> a -> f b
+ MonadicBang.Internal.Utils: fromDList :: DList a -> [a]
+ MonadicBang.Internal.Utils: panic :: HasCallStack => String -> a
+ MonadicBang.Internal.Utils: type DList a = Endo [a]
+ MonadicBang.Internal.Utils: type Handler (m :: Type -> Type) a = a -> m a
+ MonadicBang.Internal.Utils: type Try (m :: Type -> Type) a = Handler MaybeT m a
- MonadicBang.Internal: addStmts :: forall sig m. Has (PsErrors :+: (HoleFills :+: (Uniques :+: (LocalVars :+: Reader DynFlags)))) sig m => Handler m [ExprLStmt GhcPs]
+ MonadicBang.Internal: addStmts :: forall (sig :: (Type -> Type) -> Type -> Type) m. Has (PsErrors :+: ((HoleFills :: (Type -> Type) -> Type -> Type) :+: ((Uniques :: (Type -> Type) -> Type -> Type) :+: (LocalVars :+: Reader DynFlags)))) sig m => Handler m [ExprLStmt GhcPs]
- MonadicBang.Internal: bangVar :: Has (Uniques :+: Reader DynFlags) sig m => LExpr -> Loc -> m RdrName
+ MonadicBang.Internal: bangVar :: forall (sig :: (Type -> Type) -> Type -> Type) m. Has ((Uniques :: (Type -> Type) -> Type -> Type) :+: Reader DynFlags) sig m => LExpr -> Loc -> m RdrName
- MonadicBang.Internal: class Typeable (AstType a) => Handle a where {
+ MonadicBang.Internal: class Typeable AstType a => Handle (a :: k) where {
- MonadicBang.Internal: class MonadTrans t => HandlingMonadTrans t
+ MonadicBang.Internal: class MonadTrans t => HandlingMonadTrans (t :: Type -> Type -> Type -> Type)
- MonadicBang.Internal: evac :: forall a sig m. (Has Fill sig m, Data a) => Handler m a
+ MonadicBang.Internal: evac :: forall a (sig :: (Type -> Type) -> Type -> Type) m. (Has Fill sig m, Data a) => Handler m a
- MonadicBang.Internal: evacPats :: forall a m sig. (Has (Fill :+: State InScope) sig m, Data a) => Handler m a
+ MonadicBang.Internal: evacPats :: forall a m (sig :: (Type -> Type) -> Type -> Type). (Has (Fill :+: State InScope) sig m, Data a) => Handler m a
- MonadicBang.Internal: fillHoles :: (Data a, Has (PsErrors :+: (Reader Options :+: (Uniques :+: (LocalVars :+: Reader DynFlags)))) sig m) => Map Loc LExpr -> Handler m a
+ MonadicBang.Internal: fillHoles :: forall a (sig :: (Type -> Type) -> Type -> Type) m. (Data a, Has (PsErrors :+: (Reader Options :+: ((Uniques :: (Type -> Type) -> Type -> Type) :+: (LocalVars :+: Reader DynFlags)))) sig m) => Map Loc LExpr -> Handler m a
- MonadicBang.Internal: handle :: forall a sig m. (Handle a, CanFail a ~ False) => Has (Effects a) sig m => Handler m (AstType a)
+ MonadicBang.Internal: handle :: forall {k} (a :: k) (sig :: (Type -> Type) -> Type -> Type) m. (Handle a, CanFail a ~ 'False, Has (Effects a) sig m) => Handler m (AstType a)
- MonadicBang.Internal: handle' :: forall sig m m'. (Handle a, m ~ HandleFailure (CanFail a) m') => Has (Effects a) sig m' => Handler m (AstType a)
+ MonadicBang.Internal: handle' :: forall (sig :: (Type -> Type) -> Type -> Type) m (m' :: Type -> Type). (Handle a, m ~ HandleFailure (CanFail a) m', Has (Effects a) sig m') => Handler m (AstType a)
- MonadicBang.Internal: ignore :: forall (e :: Type) m a. (Monad m, Typeable a, Typeable e) => Try m a
+ MonadicBang.Internal: ignore :: forall e (m :: Type -> Type) a. (Monad m, Typeable a, Typeable e) => Try m a
- MonadicBang.Internal: isInvalid :: Has (Reader InScope) sig m => OccName -> m Bool
+ MonadicBang.Internal: isInvalid :: forall (sig :: (Type -> Type) -> Type -> Type) m. Has (Reader InScope) sig m => OccName -> m Bool
- MonadicBang.Internal: locVar :: Has Uniques sig m => String -> SrcSpan -> Loc -> m RdrName
+ MonadicBang.Internal: locVar :: forall (sig :: (Type -> Type) -> Type -> Type) m. Has (Uniques :: (Type -> Type) -> Type -> Type) sig m => String -> SrcSpan -> Loc -> m RdrName
- MonadicBang.Internal: tellLocalVar :: Has (Writer OccSet) sig m => OccName -> m ()
+ MonadicBang.Internal: tellLocalVar :: forall (sig :: (Type -> Type) -> Type -> Type) m. Has (Writer OccSet) sig m => OccName -> m ()
- MonadicBang.Internal: tellOne :: Has (Writer (DList w)) sig m => w -> m ()
+ MonadicBang.Internal: tellOne :: forall w (sig :: (Type -> Type) -> Type -> Type) m. Has (Writer (DList w)) sig m => w -> m ()
- MonadicBang.Internal: toMaybeT :: (HandlingMonadTrans t, Monad m) => t m a -> MaybeT m a
+ MonadicBang.Internal: toMaybeT :: forall (m :: Type -> Type) a. (HandlingMonadTrans t, Monad m) => t m a -> MaybeT m a
- MonadicBang.Internal: try :: forall e sig m a. (HandlingMonadTrans (HandleFailure (CanFail e)), Typeable a, Handle e, Monad m, Has (Effects e) sig m) => Try m a
+ MonadicBang.Internal: try :: forall {k} (e :: k) (sig :: (Type -> Type) -> Type -> Type) (m :: Type -> Type) a. (HandlingMonadTrans (HandleFailure (CanFail e)), Typeable a, Handle e, Monad m, Has (Effects e) sig m) => Try m a
- MonadicBang.Internal: tryEvac :: Monad m => [Try m a] -> Try m a
+ MonadicBang.Internal: tryEvac :: forall (m :: Type -> Type) a. Monad m => [Try m a] -> Try m a
- MonadicBang.Internal: type AstType a = (r :: Type) | r -> a;
+ MonadicBang.Internal: type AstType (a :: k) = (r :: Type) | r -> k a;
- MonadicBang.Internal: type CanFail a :: Bool;
+ MonadicBang.Internal: type CanFail (a :: k) :: Bool;
- MonadicBang.Internal: type Effects a :: (Type -> Type) -> Type -> Type;
+ MonadicBang.Internal: type Effects (a :: k) :: Type -> Type -> Type -> Type;
- MonadicBang.Internal: type Fill = PsErrors :+: Writer (DList BindStmt) :+: HoleFills :+: Uniques :+: LocalVars :+: Reader DynFlags
+ MonadicBang.Internal: type Fill = PsErrors :+: Writer DList BindStmt :+: HoleFills :: Type -> Type -> Type -> Type :+: Uniques :: Type -> Type -> Type -> Type :+: LocalVars :+: Reader DynFlags
- MonadicBang.Internal: type HoleFills = Offer Loc LExpr
+ MonadicBang.Internal: type HoleFills = Offer Loc LExpr :: k -> Type -> Type
- MonadicBang.Internal: type family HandleFailure canFail = t | t -> canFail
+ MonadicBang.Internal: type family HandleFailure (canFail :: Bool) = (t :: Type -> Type -> Type -> Type) | t -> canFail
- MonadicBang.Internal: usualTries :: (Has Fill sig m, Data a) => [Try m a]
+ MonadicBang.Internal: usualTries :: forall (sig :: (Type -> Type) -> Type -> Type) (m :: Type -> Type) a. (Has Fill sig m, Data a) => [Try m a]

Files

CHANGELOG.md view
@@ -1,5 +1,10 @@ # Revision history for monadic-bang +## 0.2.0.0 -- 2023-10-16++* Added support for GHC 9.8+* Prefix internal modules with `Internal`+ ## 0.1.1.0 -- 2023-07-10  * Removed debug log message (thanks evincarofautumn!)
README.md view
@@ -1,5 +1,7 @@ # Monadic Bang +[![Run Tests](https://github.com/JakobBruenker/monadic-bang/actions/workflows/haskell.yml/badge.svg?branch=main&event=push)](https://github.com/JakobBruenker/monadic-bang/actions/workflows/haskell.yml)+ This is a GHC Parser plugin for GHC 9.4 and above, intended to make monadic code within `do`-blocks more concise and nicer to work with. Works with HLS.  This is heavily inspired by [Idris's !-notation](https://idris2.readthedocs.io/en/latest/tutorial/interfaces.html#notation), but with some [important differences](#comparison-with-idriss--notation).
monadic-bang.cabal view
@@ -14,7 +14,7 @@ -- PVP summary:      +-+------- breaking API changes --                   | | +----- non-breaking API additions --                   | | | +--- code changes with no API change-version:            0.1.1.0+version:            0.2.1.0  -- A short (one-line) description of the package. synopsis:           GHC plugin to desugar ! into do-notation@@ -49,8 +49,9 @@     CHANGELOG.md     README.md -tested-with:        GHC == 9.4.5-                    GHC == 9.6.2+tested-with:        GHC == 9.4.7+                    GHC == 9.6.3+                    GHC == 9.8.1  source-repository head     type:           git@@ -60,12 +61,12 @@     -- Modules exported by the library.     exposed-modules:  MonadicBang                       MonadicBang.Internal-                      MonadicBang.Effect.Offer-                      MonadicBang.Effect.Uniques-                      MonadicBang.Effect.Writer.Discard-                      MonadicBang.Options-                      MonadicBang.Utils-                      MonadicBang.Error+                      MonadicBang.Internal.Effect.Offer+                      MonadicBang.Internal.Effect.Uniques+                      MonadicBang.Internal.Effect.Writer.Discard+                      MonadicBang.Internal.Options+                      MonadicBang.Internal.Utils+                      MonadicBang.Internal.Error      -- Modules included in this library but not exported.     -- other-modules:@@ -83,11 +84,11 @@                       PatternSynonyms      -- Other library packages from which modules are imported.-    build-depends:    base >=4.17.0.0 && < 5,-                      ghc >= 9.4 && < 9.7,-                      containers ^>= 0.6.4.1,-                      transformers >= 0.5.6.2 && < 0.7,-                      fused-effects ^>= 1.1.1.2,+    build-depends:    base >=4.17.0.0 && <4.20,+                      ghc >=9.4 && <9.9,+                      containers ^>=0.6.4.1 || ^>=0.7,+                      transformers >=0.5.6.2 && <0.7,+                      fused-effects ^>=1.1.1.2      -- Directories containing source files.     hs-source-dirs:   src@@ -119,10 +120,9 @@     -- Test dependencies.     build-depends:    base,                       ghc,-                      ghc-boot >= 9.4 && < 9.7,-                      ghc-paths ^>= 0.1.0.12,+                      ghc-boot >=9.4 && <9.9,+                      ghc-paths ^>=0.1.0.12,                       transformers,-                      exceptions ^>= 0.10,                       monadic-bang      ghc-options:      -Wall -Wcompat -plugin-package=monadic-bang
− src/MonadicBang/Effect/Offer.hs
@@ -1,35 +0,0 @@-{-# LANGUAGE BlockArguments #-}-{-# LANGUAGE DerivingStrategies #-}-{-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE MonoLocalBinds #-}-{-# LANGUAGE OverloadedRecordDot #-}--module MonadicBang.Effect.Offer where--import Control.Algebra-import Control.Carrier.State.Strict-import Data.Map.Strict (Map)-import Data.Map.Strict qualified as M---- | Offers a number of things that can be yoinked, but only once-data Offer k v m a where-  Yoink :: k -> Offer k v m (Maybe v)--yoink :: Has (Offer k v) sig m => k -> m (Maybe v)-yoink = send . Yoink--newtype OfferC k v m a = OfferC {getOfferState :: StateC (Map k v) m a}-  deriving newtype (Functor, Applicative, Monad)---- Returns the result of the computation, along with the remaining offers-runOffer :: Map k v -> OfferC k v m a -> m (Map k v, a)-runOffer o (OfferC s) = runState o s--instance (Algebra sig m, Ord k) => Algebra (Offer k v :+: sig) (OfferC k v m) where-  alg hdl sig ctx = case sig of-    L (Yoink k) -> OfferC do-      (mv, remaining) <- M.updateLookupWithKey (\_ _ -> Nothing) k <$> get-      put remaining-      pure (mv <$ ctx)-    R other -> OfferC (alg ((.getOfferState) . hdl) (R other) ctx)-  {-# INLINE alg #-}
− src/MonadicBang/Effect/Uniques.hs
@@ -1,41 +0,0 @@-{-# LANGUAGE BlockArguments #-}-{-# LANGUAGE DerivingStrategies #-}-{-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE MonoLocalBinds #-}-{-# LANGUAGE OverloadedRecordDot #-}--module MonadicBang.Effect.Uniques where--import Control.Algebra-import Control.Carrier.State.Strict-import Control.Monad.IO.Class-import Data.Functor-import Data.Tuple--import GHC.Types.Unique-import GHC.Types.Unique.Supply---- | Uniques provides arbitrarily many unique GHC Uniques-data Uniques m a where-  FreshUnique :: Uniques m Unique--freshUnique :: Has Uniques sig m => m Unique-freshUnique = send FreshUnique--newtype UniquesC m a = UniquesC {getUniquesState :: StateC UniqSupply m a}-  deriving newtype (Functor, Applicative, Monad)---- | The "mask" (Char) supplied is purely cosmetic, making it easier to figure out where a Unique was born.------ See Note [Uniques for wired-in prelude things and known masks] in GHC.Builtin.Uniques-runUniquesIO :: MonadIO m => Char -> UniquesC m a -> m a-runUniquesIO mask (UniquesC s) = flip evalState s =<< liftIO (mkSplitUniqSupply mask)--runUniques :: Functor m => UniqSupply -> UniquesC m a -> m a-runUniques uniqSupply (UniquesC s) = evalState uniqSupply s--instance Algebra sig m => Algebra (Uniques :+: sig) (UniquesC m) where-  alg hdl sig ctx = case sig of-    L FreshUnique -> UniquesC . state $ fmap (ctx $>) . swap . takeUniqFromSupply-    R other -> UniquesC (alg ((.getUniquesState) . hdl) (R other) ctx)-  {-# INLINE alg #-} 
− src/MonadicBang/Effect/Writer/Discard.hs
@@ -1,24 +0,0 @@-{-# LANGUAGE DerivingStrategies #-}-{-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE BlockArguments #-}-{-# LANGUAGE GADTs #-}---- | A Writer carrier that discards any values it is told-module MonadicBang.Effect.Writer.Discard where--import Control.Algebra-import Control.Effect.Writer--newtype DiscardC w m a = DiscardC { evalDiscardC :: m a }-  deriving newtype (Functor, Applicative, Monad)--evalWriter :: (Monoid w, Algebra sig m) => DiscardC w m a -> m a-evalWriter = evalDiscardC--instance (Monoid w, Algebra sig m) => Algebra (Writer w :+: sig) (DiscardC w m) where-  alg hdl sig ctx = DiscardC $ case sig of-    L writer -> case writer of-      Tell _ -> pure ctx-      Listen m -> fmap (mempty,) <$> evalWriter (hdl (m <$ ctx))-      Censor _ m -> evalWriter (hdl (m <$ ctx))-    R other -> alg (evalDiscardC . hdl) other ctx
− src/MonadicBang/Error.hs
@@ -1,39 +0,0 @@-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE CPP #-}--module MonadicBang.Error where--import Prelude hiding ((<>))--import Control.Effect.Writer--import GHC-import GHC.Types.Error-import GHC.Types.Name.Occurrence-import GHC.Parser.Errors.Types-import GHC.Utils.Outputable--data Error = ErrOutOfScopeVariable OccName-           | ErrBangOutsideOfDo--type PsErrors = Writer (Messages PsError)--customError :: Error -> PsError-#if MIN_VERSION_ghc(9,6,0)-customError = PsUnknownMessage . UnknownDiagnostic . \cases-#else-customError = PsUnknownMessage . \cases-#endif-  ErrBangOutsideOfDo -> DiagnosticMessage-    { diagMessage = mkDecorated [text "Monadic ! outside of a 'do'-block is not allowed"]-    , diagReason = ErrorWithoutFlag-    , diagHints = [SuggestMissingDo]-    }-  (ErrOutOfScopeVariable name) -> DiagnosticMessage-    { diagMessage = mkDecorated [text "The variable " <> quotes (ppr name) <> text " cannot be used inside of ! here, since its desugaring would escape its scope"]-    , diagReason = ErrorWithoutFlag-    , diagHints = [UnknownHint $ text "Maybe you meant to open a new 'do'-block after " <> ppr name <> text " has been bound?"]-    }--tellPsError :: Has PsErrors sig m => PsError -> SrcSpan -> m ()-tellPsError err srcSpan = tell . singleMessage $ MsgEnvelope srcSpan neverQualify err SevError
src/MonadicBang/Internal.hs view
@@ -44,14 +44,14 @@  import GHC.Utils.Logger -import MonadicBang.Effect.Offer-import MonadicBang.Effect.Uniques-import MonadicBang.Options-import MonadicBang.Utils-import MonadicBang.Error+import MonadicBang.Internal.Effect.Offer+import MonadicBang.Internal.Effect.Uniques+import MonadicBang.Internal.Options+import MonadicBang.Internal.Utils+import MonadicBang.Internal.Error+import MonadicBang.Internal.Effect.Writer.Discard  import Data.Kind-import MonadicBang.Effect.Writer.Discard  -- We don't care about which file things are from, because the entire AST comes -- from the same module
+ src/MonadicBang/Internal/Effect/Offer.hs view
@@ -0,0 +1,35 @@+{-# LANGUAGE BlockArguments #-}+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE MonoLocalBinds #-}+{-# LANGUAGE OverloadedRecordDot #-}++module MonadicBang.Internal.Effect.Offer where++import Control.Algebra+import Control.Carrier.State.Strict+import Data.Map.Strict (Map)+import Data.Map.Strict qualified as M++-- | Offers a number of things that can be yoinked, but only once+data Offer k v m a where+  Yoink :: k -> Offer k v m (Maybe v)++yoink :: Has (Offer k v) sig m => k -> m (Maybe v)+yoink = send . Yoink++newtype OfferC k v m a = OfferC {getOfferState :: StateC (Map k v) m a}+  deriving newtype (Functor, Applicative, Monad)++-- Returns the result of the computation, along with the remaining offers+runOffer :: Map k v -> OfferC k v m a -> m (Map k v, a)+runOffer o (OfferC s) = runState o s++instance (Algebra sig m, Ord k) => Algebra (Offer k v :+: sig) (OfferC k v m) where+  alg hdl sig ctx = case sig of+    L (Yoink k) -> OfferC do+      (mv, remaining) <- M.updateLookupWithKey (\_ _ -> Nothing) k <$> get+      put remaining+      pure (mv <$ ctx)+    R other -> OfferC (alg ((.getOfferState) . hdl) (R other) ctx)+  {-# INLINE alg #-}
+ src/MonadicBang/Internal/Effect/Uniques.hs view
@@ -0,0 +1,41 @@+{-# LANGUAGE BlockArguments #-}+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE MonoLocalBinds #-}+{-# LANGUAGE OverloadedRecordDot #-}++module MonadicBang.Internal.Effect.Uniques where++import Control.Algebra+import Control.Carrier.State.Strict+import Control.Monad.IO.Class+import Data.Functor+import Data.Tuple++import GHC.Types.Unique+import GHC.Types.Unique.Supply++-- | Uniques provides arbitrarily many unique GHC Uniques+data Uniques m a where+  FreshUnique :: Uniques m Unique++freshUnique :: Has Uniques sig m => m Unique+freshUnique = send FreshUnique++newtype UniquesC m a = UniquesC {getUniquesState :: StateC UniqSupply m a}+  deriving newtype (Functor, Applicative, Monad)++-- | The "mask" (Char) supplied is purely cosmetic, making it easier to figure out where a Unique was born.+--+-- See Note [Uniques for wired-in prelude things and known masks] in GHC.Builtin.Uniques+runUniquesIO :: MonadIO m => Char -> UniquesC m a -> m a+runUniquesIO mask (UniquesC s) = flip evalState s =<< liftIO (mkSplitUniqSupply mask)++runUniques :: Functor m => UniqSupply -> UniquesC m a -> m a+runUniques uniqSupply (UniquesC s) = evalState uniqSupply s++instance Algebra sig m => Algebra (Uniques :+: sig) (UniquesC m) where+  alg hdl sig ctx = case sig of+    L FreshUnique -> UniquesC . state $ fmap (ctx $>) . swap . takeUniqFromSupply+    R other -> UniquesC (alg ((.getUniquesState) . hdl) (R other) ctx)+  {-# INLINE alg #-} 
+ src/MonadicBang/Internal/Effect/Writer/Discard.hs view
@@ -0,0 +1,24 @@+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE BlockArguments #-}+{-# LANGUAGE GADTs #-}++-- | A Writer carrier that discards any values it is told+module MonadicBang.Internal.Effect.Writer.Discard where++import Control.Algebra+import Control.Effect.Writer++newtype DiscardC w m a = DiscardC { evalDiscardC :: m a }+  deriving newtype (Functor, Applicative, Monad)++evalWriter :: (Monoid w, Algebra sig m) => DiscardC w m a -> m a+evalWriter = evalDiscardC++instance (Monoid w, Algebra sig m) => Algebra (Writer w :+: sig) (DiscardC w m) where+  alg hdl sig ctx = DiscardC $ case sig of+    L writer -> case writer of+      Tell _ -> pure ctx+      Listen m -> fmap (mempty,) <$> evalWriter (hdl (m <$ ctx))+      Censor _ m -> evalWriter (hdl (m <$ ctx))+    R other -> alg (evalDiscardC . hdl) other ctx
+ src/MonadicBang/Internal/Error.hs view
@@ -0,0 +1,49 @@+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE CPP #-}++module MonadicBang.Internal.Error where++import Prelude hiding ((<>))++import Control.Effect.Writer++import GHC+#if MIN_VERSION_ghc(9,8,0)+import GHC.Utils.Error+#endif+import GHC.Types.Error+import GHC.Types.Name.Occurrence+import GHC.Parser.Errors.Types+import GHC.Utils.Outputable++data Error = ErrOutOfScopeVariable OccName+           | ErrBangOutsideOfDo++type PsErrors = Writer (Messages PsError)++customError :: Error -> PsError+#if MIN_VERSION_ghc(9,8,0)+customError = PsUnknownMessage . mkUnknownDiagnostic . \cases+#elif MIN_VERSION_ghc(9,6,0)+customError = PsUnknownMessage . UnknownDiagnostic . \cases+#else+customError = PsUnknownMessage . \cases+#endif+  ErrBangOutsideOfDo -> DiagnosticMessage+    { diagMessage = mkDecorated [text "Monadic ! outside of a 'do'-block is not allowed"]+    , diagReason = ErrorWithoutFlag+    , diagHints = [SuggestMissingDo]+    }+  (ErrOutOfScopeVariable name) -> DiagnosticMessage+    { diagMessage = mkDecorated [text "The variable " <> quotes (ppr name) <> text " cannot be used inside of ! here, since its desugaring would escape its scope"]+    , diagReason = ErrorWithoutFlag+    , diagHints = [UnknownHint $ text "Maybe you meant to open a new 'do'-block after " <> ppr name <> text " has been bound?"]+    }++tellPsError :: Has PsErrors sig m => PsError -> SrcSpan -> m ()+tellPsError err srcSpan = tell . singleMessage $+#if MIN_VERSION_ghc(9,8,0)+  mkErrorMsgEnvelope srcSpan neverQualify err+#else+  MsgEnvelope srcSpan neverQualify err SevError+#endif
+ src/MonadicBang/Internal/Options.hs view
@@ -0,0 +1,61 @@+{-# LANGUAGE BlockArguments #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedRecordDot #-}+{-# LANGUAGE CPP #-}++module MonadicBang.Internal.Options where++import Control.Exception+import Control.Algebra+import Control.Carrier.State.Strict+import Control.Effect.Throw+import Control.Monad+import Data.Bifunctor+import Data.Bool+import Data.List (intercalate, partition)++import GHC+import GHC.Plugins++data Verbosity = DumpTransformed | Quiet++data PreserveErrors = Preserve | Don'tPreserve++data Options = MkOptions {verbosity :: Verbosity, preserveErrors :: PreserveErrors}++#if MIN_VERSION_ghc(9,6,0)+parseOptions :: Has (Throw ErrorCall) sig m => Located (HsModule GhcPs) -> [CommandLineOption] -> m Options+#else+parseOptions :: Has (Throw ErrorCall) sig m => Located HsModule -> [CommandLineOption] -> m Options+#endif+parseOptions mod' cmdLineOpts = do+  (remaining, options) <- runState cmdLineOpts do+    verbosity <- bool Quiet DumpTransformed <$> extractOpts verboseOpts+    preserveErrors <- bool Don'tPreserve Preserve <$> extractOpts preserveErrorsOpts+    pure $ MkOptions verbosity preserveErrors+  unless (null remaining) . throwError . ErrorCall $+    "Incorrect command line options for plugin MonadicBang, encountered in " ++ modName ++ modFile +++    "\n\tOptions that were supplied (via -fplugin-opt) are: " ++ intercalate ", " (map show cmdLineOpts) +++    "\n\tUnrecognized options: " ++ showOpts remaining +++    "\n\n\tUsage: [-ddump] [-preserve-errors]" +++    "\n" +++    "\n\t\t-ddump            Print the altered AST" +++    "\n\t\t-preserve-errors  Keep parse errors about ! outside of 'do' in their original form, rather then a more relevant explanation." +++    "\n\t\t                  This is mainly useful if another plugin expects those errors."+  pure options++  where+    verboseOpts = ["-ddump"]+    preserveErrorsOpts = ["-preserve-errors"]+    extractOpts opt = do+      (isOpt, opts') <- gets $ first (not . null) . partition (`elem` opt)+      put opts'+      pure isOpt++    showOpts = intercalate ", " . map show++    modFile = maybe "" ((" in file " ++) . unpackFS . srcSpanFile) $ toRealSrcSpan (getLoc mod')+    modName = maybe "an unnamed module" (("module " ++) . moduleNameString . unLoc) $ (unLoc mod').hsmodName+    toRealSrcSpan = \cases+      (RealSrcSpan rss _) -> Just rss+      (UnhelpfulSpan _) -> Nothing
+ src/MonadicBang/Internal/Utils.hs view
@@ -0,0 +1,38 @@+{-# LANGUAGE MonoLocalBinds #-}+{-# LANGUAGE CPP #-}++module MonadicBang.Internal.Utils where++import Control.Monad.Trans.Maybe+import Data.Monoid+import GHC.Stack (withFrozenCallStack, HasCallStack)++type DList a = Endo [a]++-- | Handle a specific AST node+type Handler m a = a -> m a++-- | Try handling an AST node, but may fail (usually because the handler is not+-- applicable)+type Try m a = Handler (MaybeT m) a++{-# INLINE fromDList #-}+fromDList :: DList a -> [a]+fromDList = appEndo ?? []++{-# INLINE (??) #-}+(??) :: Functor f => f (a -> b) -> a -> f b+fs ?? x = ($ x) <$> fs++#if MIN_VERSION_transformers(0,6,0)+#else+{-# INLINE hoistMaybe #-}+hoistMaybe :: Applicative m => Maybe a -> MaybeT m a+hoistMaybe = MaybeT . pure+#endif++panic :: HasCallStack => String -> a+panic message = withFrozenCallStack $ error $+  unlines ["MonadicBang panic:", message, "", submitReport]+  where+    submitReport = "This is likely a bug. Please submit a bug report at https://github.com/JakobBruenker/monadic-bang/issues"
− src/MonadicBang/Options.hs
@@ -1,61 +0,0 @@-{-# LANGUAGE BlockArguments #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE OverloadedRecordDot #-}-{-# LANGUAGE CPP #-}--module MonadicBang.Options where--import Control.Exception-import Control.Algebra-import Control.Carrier.State.Strict-import Control.Effect.Throw-import Control.Monad-import Data.Bifunctor-import Data.Bool-import Data.List (intercalate, partition)--import GHC-import GHC.Plugins--data Verbosity = DumpTransformed | Quiet--data PreserveErrors = Preserve | Don'tPreserve--data Options = MkOptions {verbosity :: Verbosity, preserveErrors :: PreserveErrors}--#if MIN_VERSION_ghc(9,6,0)-parseOptions :: Has (Throw ErrorCall) sig m => Located (HsModule GhcPs) -> [CommandLineOption] -> m Options-#else-parseOptions :: Has (Throw ErrorCall) sig m => Located HsModule -> [CommandLineOption] -> m Options-#endif-parseOptions mod' cmdLineOpts = do-  (remaining, options) <- runState cmdLineOpts do-    verbosity <- bool Quiet DumpTransformed <$> extractOpts verboseOpts-    preserveErrors <- bool Don'tPreserve Preserve <$> extractOpts preserveErrorsOpts-    pure $ MkOptions verbosity preserveErrors-  unless (null remaining) . throwError . ErrorCall $-    "Incorrect command line options for plugin MonadicBang, encountered in " ++ modName ++ modFile ++-    "\n\tOptions that were supplied (via -fplugin-opt) are: " ++ intercalate ", " (map show cmdLineOpts) ++-    "\n\tUnrecognized options: " ++ showOpts remaining ++-    "\n\n\tUsage: [-ddump] [-preserve-errors]" ++-    "\n" ++-    "\n\t\t-ddump            Print the altered AST" ++-    "\n\t\t-preserve-errors  Keep parse errors about ! outside of 'do' in their original form, rather then a more relevant explanation." ++-    "\n\t\t                  This is mainly useful if another plugin expects those errors."-  pure options--  where-    verboseOpts = ["-ddump"]-    preserveErrorsOpts = ["-preserve-errors"]-    extractOpts opt = do-      (isOpt, opts') <- gets $ first (not . null) . partition (`elem` opt)-      put opts'-      pure isOpt--    showOpts = intercalate ", " . map show--    modFile = maybe "" ((" in file " ++) . unpackFS . srcSpanFile) $ toRealSrcSpan (getLoc mod')-    modName = maybe "an unnamed module" (("module " ++) . moduleNameString . unLoc) $ (unLoc mod').hsmodName-    toRealSrcSpan = \cases-      (RealSrcSpan rss _) -> Just rss-      (UnhelpfulSpan _) -> Nothing
− src/MonadicBang/Utils.hs
@@ -1,39 +0,0 @@-{-# LANGUAGE MonoLocalBinds #-}-{-# LANGUAGE CPP #-}--module MonadicBang.Utils where--import Control.Monad.Trans.Maybe-import Data.Monoid-import GHC.Stack (withFrozenCallStack, HasCallStack)--type DList a = Endo [a]---- | Handle a specific AST node-type Handler m a = a -> m a---- | Try handling an AST node, but may fail (usually because the handler is not--- applicable)-type Try m a = Handler (MaybeT m) a--{-# INLINE fromDList #-}-fromDList :: DList a -> [a]-fromDList = appEndo ?? []--{-# INLINE (??) #-}-(??) :: Functor f => f (a -> b) -> a -> f b-fs ?? x = ($ x) <$> fs--#if MIN_VERSION_ghc(9,6,0)-#else--- This is included in transformers 0.6, but that can't be used together with ghc 9.4-{-# INLINE hoistMaybe #-}-hoistMaybe :: Applicative m => Maybe a -> MaybeT m a-hoistMaybe = MaybeT . pure-#endif--panic :: HasCallStack => String -> a-panic message = withFrozenCallStack $ error $-  unlines ["MonadicBang panic:", message, "", submitReport]-  where-    submitReport = "This is likely a bug. Please submit a bug report at https://github.com/JakobBruenker/monadic-bang/issues"
test/MonadicBang/Test.hs view
@@ -1,13 +1,51 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE BlockArguments #-} {-# LANGUAGE LexicalNegation #-} {-# LANGUAGE MonadComprehensions #-}+{-# LANGUAGE ViewPatterns #-}  module Main (main) where +import Prelude hiding ((<>))+#if MIN_VERSION_ghc(9,6,0)+#else+import Control.Applicative (liftA2)+#endif+import Data.Foldable+import Data.Traversable+import System.IO++import MonadicBang.Test.Utils import MonadicBang.Test.ShouldPass import MonadicBang.Test.ShouldFail +import GHC.Utils.Outputable+import GHC.Utils.Ppr (Mode(PageMode))+import System.Exit (exitFailure)+ main :: IO () main = do-  shouldPass-  shouldFail+  (numFailures, numFailedSuites) <- liftA2 (,) sum (length . filter (> 0)) <$> for suites \suite -> do+    failures <- runSuite suite+    for_ failures \failure -> putSDoc stderr $ vcat [space, prettyFail failure]+    pure $ length failures+  if numFailures == 0+    then putStrLn "All tests passed!"+    else do+      putSDoc stdout $+        space $+$ plural' numFailures "test" <+> text "in" <+> int numFailedSuites <> char '/' <> plural' (length suites) "suite" <+> text "failed."+      exitFailure+  where+    plural' :: Int -> String -> SDoc+    plural' n (text -> s) = int n <+> case n of+      1 -> s+      _ -> s <> char 's'++putSDoc :: Handle -> SDoc -> IO ()+putSDoc = printSDocLn defaultSDocContext (PageMode True)++suites :: [TestType]+suites =+  [ shouldPass+  , shouldFail+  ]
test/MonadicBang/Test/ShouldFail.hs view
@@ -3,7 +3,7 @@ module MonadicBang.Test.ShouldFail (shouldFail) where  import MonadicBang.Test.Utils-import MonadicBang.Error+import MonadicBang.Internal.Error  import GHC.Types.Name.Occurrence 
test/MonadicBang/Test/ShouldPass.hs view
@@ -16,6 +16,7 @@  import MonadicBang.Test.Utils import MonadicBang.Test.Utils.QualifiedDo qualified as QualifiedDo+import Control.Monad.IO.Class  shouldPass :: Test shouldPass = do@@ -39,7 +40,7 @@   confusing   qualifiedDo -getA, getB, getC :: IO String+getA, getB, getC :: MonadIO m => m String getA = pure "a" getB = pure "b" getC = pure "c"
test/MonadicBang/Test/Utils.hs view
@@ -4,6 +4,9 @@ #if MIN_VERSION_ghc(9,6,0) {-# LANGUAGE ScopedTypeVariables #-} #endif+{-# LANGUAGE NoFieldSelectors #-}+{-# LANGUAGE OverloadedRecordDot #-}+{-# LANGUAGE ViewPatterns #-}  module MonadicBang.Test.Utils where @@ -11,6 +14,8 @@ import Data.Foldable import Data.Function +import Control.Monad.Trans.Writer.CPS+ import GHC.Stack  import GHC@@ -20,49 +25,76 @@ import GHC.Utils.Outputable hiding ((<>))  import MonadicBang.Test.Utils.RunGhcParser+import MonadicBang.Internal.Utils+import Data.Monoid --- TODO: This should use a Writer to collect all errors-type Test = HasCallStack => IO ()+data FailType+  = forall a . Show a => IncorrectResult { expectedValue :: a, actualValue :: a }+  | forall a . Outputable a => Didn'tFail { expectedFails :: [PsMessage], actualValue :: a }+  | FailedIncorrectly { expectedFails :: [PsMessage], actualFails :: [GhcMessage] } -assertEq :: (HasCallStack, Show a, Eq a) => a -> a -> IO ()--- We don't care about seeing where the `error` call itself happens in the--- call stack, so we freeze it-assertEq expected actual = when (expected /= actual) $ withFrozenCallStack do-  error $ "Expected " <> show expected <> ", but got " <> show actual+data Fail = MkFail { error :: FailType, callStack :: CallStack } +type TestType = WriterT (DList Fail) IO ()++type Test = HasCallStack => TestType++runSuite :: TestType -> IO [Fail]+runSuite test = fromDList <$> execWriterT test++prettyFail :: Fail -> SDoc+prettyFail failure = vcat+  [ case failure.error of+      IncorrectResult{ expectedValue, actualValue } -> vcat+        [ text "Expected: " <+> text (show expectedValue)+        , text "but got:  " <+> text (show actualValue)+        ]+      Didn'tFail{ expectedFails } -> vcat+        [ text "Expected failure with"+        , nest 2 $ diagnosticsSDoc expectedFails+        , text "but execution succeeded"+        ]+      FailedIncorrectly{ expectedFails, actualFails } -> vcat+        [ text "Expected failure with"+        , nest 2 $ diagnosticsSDoc expectedFails+        , text "but execution failed with these errors instead:"+        , nest 2 $ diagnosticsSDoc actualFails+        ]+  , text "at" <+> text (prettyCallStack failure.callStack)+  ]+  where+    diagnosticsSDoc diags = vcat (map (vcat . unDecorated . diagMsg) diags)++recordFail :: HasCallStack => FailType -> TestType+recordFail err = tell . Endo . (:) $ MkFail err callStack++assertEq :: (HasCallStack, Show a, Eq a) => a -> a -> TestType+assertEq expected actual = when (expected /= actual) $+  withFrozenCallStack $ recordFail $ IncorrectResult expected actual+ sdocEq :: SDoc -> SDoc -> Bool sdocEq = (==) `on` showSDocUnsafe -assertFailWith :: (HasCallStack, Outputable a) => [PsMessage] -> Either SourceError a -> IO ()+assertFailWith :: (HasCallStack, Outputable a) => [PsMessage] -> Either SourceError a -> TestType assertFailWith expected = \case-  Right result -> withFrozenCallStack $ error . showSDocUnsafe $-    text "\n    Expected failure with" $$-    diagnosticsSDoc expected $$-    text "    but execution succeeded with this result:" $$-    ppr result-  Left err -> unless sameErrors do-    error . showSDocUnsafe $-      text "\n    Expected failure with" $$-      diagnosticsSDoc expected $$-      text "    but execution failed with these errors instead:" $$-      diagnosticsSDoc errMsgs+  Right result -> withFrozenCallStack $ recordFail $ Didn'tFail expected result+  Left err -> unless sameFails do+    withFrozenCallStack $ recordFail $ FailedIncorrectly expected errMsgs     where       errMsgs = toList (srcErrorMessages err)       toPsMessage = \case         GhcPsMessage m -> Just m         _ -> Nothing       listEq eq xs ys = and $ zipWith eq xs ys-      sameErrors = maybe False (((listEq . listEq) sdocEq `on` map (unDecorated . diagMsg)) expected) $ traverse toPsMessage errMsgs-  where-    diagnosticsSDoc diags = vcat (map (vcat . unDecorated . diagMsg) diags)+      sameFails = maybe False (((listEq . listEq) sdocEq `on` map (unDecorated . diagMsg)) expected) $ traverse toPsMessage errMsgs -    diagMsg :: forall a . Diagnostic a => a -> DecoratedSDoc+diagMsg :: forall a . Diagnostic a => a -> DecoratedSDoc #if MIN_VERSION_ghc(9,6,0)-    diagMsg = diagnosticMessage (defaultDiagnosticOpts @a)+diagMsg = diagnosticMessage (defaultDiagnosticOpts @a) #else-    diagMsg = diagnosticMessage+diagMsg = diagnosticMessage #endif -assertParseFailWith :: HasCallStack => [PsMessage] -> String -> IO ()-assertParseFailWith expected source = withFrozenCallStack do+assertParseFailWith :: HasCallStack => [PsMessage] -> String -> TestType+assertParseFailWith expected source = withFrozenCallStack $   assertFailWith expected . fmap pm_parsed_source =<< parseGhc source