large-records 0.2.1.0 → 0.3
raw patch · 26 files changed
+503/−195 lines, 26 filesdep ~ghcPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: ghc
API changes (from Hackage documentation)
- Data.Record.Plugin.Options: [allFieldsStrict] :: LargeRecordOptions -> Bool
- Data.Record.Plugin.Options: largeRecordLazy :: LargeRecordOptions
- Data.Record.Plugin.Options: largeRecordStrict :: LargeRecordOptions
+ Data.Record.Plugin.Options: largeRecord :: LargeRecordOptions
- Data.Record.Plugin.Options: LargeRecordOptions :: Bool -> Bool -> LargeRecordOptions
+ Data.Record.Plugin.Options: LargeRecordOptions :: Bool -> LargeRecordOptions
Files
- CHANGELOG.md +5/−0
- large-records.cabal +3/−2
- src/Data/Record/Internal/GHC/Shim.hs +145/−49
- src/Data/Record/Internal/GHC/TemplateHaskellStyle.hs +137/−54
- src/Data/Record/Internal/Plugin/CodeGen.hs +32/−16
- src/Data/Record/Internal/Plugin/Exception.hs +4/−3
- src/Data/Record/Internal/Plugin/Options.hs +9/−25
- src/Data/Record/Internal/Plugin/Record.hs +9/−7
- src/Data/Record/Plugin.hs +22/−3
- src/Data/Record/Plugin/Options.hs +1/−2
- test/Test/Record/Sanity/CodeGen.hs +2/−1
- test/Test/Record/Sanity/Derive.hs +6/−6
- test/Test/Record/Sanity/EqualFieldTypes.hs +1/−1
- test/Test/Record/Sanity/GhcGenerics.hs +1/−1
- test/Test/Record/Sanity/HKD.hs +2/−1
- test/Test/Record/Sanity/HigherKinded.hs +2/−1
- test/Test/Record/Sanity/OverloadingNoDRF.hs +2/−2
- test/Test/Record/Sanity/PatternMatch.hs +3/−3
- test/Test/Record/Sanity/QualifiedImports/A.hs +1/−1
- test/Test/Record/Sanity/QualifiedImports/B.hs +1/−1
- test/Test/Record/Sanity/RDP/SingleModule.hs +5/−5
- test/Test/Record/Sanity/RDP/SplitModule/RecordDef.hs +5/−5
- test/Test/Record/Sanity/RecordConstruction.hs +4/−3
- test/Test/Record/Sanity/Strictness.hs +3/−3
- test/Test/Record/Sanity/StrictnessStrictData.hs +96/−0
- test/TestLargeRecords.hs +2/−0
CHANGELOG.md view
@@ -1,5 +1,10 @@ # Revision history for large-records +## 0.3 -- 2022-07-22++* Support ghc 9.2 (#117)+* Support for field strictness annotations (#107)+ ## 0.2.1.0 -- 2022-04-06 * Update for `large-generics` 0.2
large-records.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.4 name: large-records-version: 0.2.1.0+version: 0.3 synopsis: Efficient compilation for large records, linear in the size of the record description: For many reasons, the internal code generated for modules that contain records is quadratic in the number of record@@ -16,7 +16,7 @@ maintainer: edsko@well-typed.com category: Generics extra-source-files: CHANGELOG.md-tested-with: GHC ==8.8.4 || ==8.10.7 || ==9.0.2+tested-with: GHC ==8.8.4 || ==8.10.7 || ==9.0.2 || ==9.2.2 source-repository head type: git@@ -99,6 +99,7 @@ Test.Record.Sanity.RDP.SplitModule.RecordDef Test.Record.Sanity.RecordConstruction Test.Record.Sanity.Strictness+ Test.Record.Sanity.StrictnessStrictData Test.Record.Sanity.GhcGenerics Test.Record.Util
src/Data/Record/Internal/GHC/Shim.hs view
@@ -7,6 +7,7 @@ {-# LANGUAGE RankNTypes #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE ViewPatterns #-} -- | Thin compatibility layer around GHC --@@ -21,10 +22,17 @@ , LHsModule , LRdrName , pattern GHC.HsModule- , putLogMsg + -- * Annotations+#if __GLASGOW_HASKELL__ < 902+ , reLoc+ , reLocA+ , noLocA+#endif+ -- * Extensions , HasDefaultExt(..)+ , withDefExt -- * Generalized @forall@ #if __GLASGOW_HASKELL__ >= 900@@ -39,7 +47,9 @@ -- * New functionality , compareHs- , InheritLoc(..)+ , inheritLoc+ , inheritLoc'+ , inheritLocPat -- * Re-exports @@ -60,10 +70,13 @@ , module GHC.Hs , module GHC.Plugins , module GHC.Tc.Types.Evidence- , module GHC.Types.Basic , module GHC.Types.Name.Cache , module GHC.Utils.Error+#if __GLASGOW_HASKELL__ >= 902+ , module GHC.Types.SourceText+ , module GHC.Types.Fixity #endif+#endif ) where import Data.List.NonEmpty (NonEmpty(..))@@ -73,12 +86,12 @@ #if __GLASGOW_HASKELL__ < 900 +import BasicTypes (SourceText (NoSourceText)) import Bag (listToBag, emptyBag)-import BasicTypes (SourceText(NoSourceText)) import ConLike (ConLike) import ErrUtils (mkErrMsg, mkWarnMsg) import GHC hiding (AnnKeywordId(..), HsModule, exprType, typeKind, mkFunBind)-import GhcPlugins hiding ((<>), getHscEnv, putLogMsg)+import GhcPlugins hiding ((<>), getHscEnv,) import HscMain (getHscEnv) import NameCache (NameCache(nsUniqs)) import PatSyn (PatSyn)@@ -89,21 +102,33 @@ #else +import GHC.Hs hiding (LHsTyVarBndr, HsTyVarBndr, HsModule, mkFunBind)+ import GHC.Core.Class (Class) import GHC.Core.ConLike (ConLike) import GHC.Core.PatSyn (PatSyn) import GHC.Data.Bag (listToBag, emptyBag) import GHC.Driver.Main (getHscEnv)-import GHC.Hs hiding (LHsTyVarBndr, HsTyVarBndr, HsModule, mkFunBind)-import GHC.Parser.Annotation (IsUnicodeSyntax(NormalSyntax))-import GHC.Plugins hiding ((<>), getHscEnv, putLogMsg) import GHC.Tc.Types.Evidence (HsWrapper(WpHole))-import GHC.Types.Basic (SourceText(NoSourceText)) import GHC.Types.Name.Cache (NameCache(nsUniqs))-import GHC.Utils.Error (Severity(SevError, SevWarning), mkErrMsg, mkWarnMsg)+import GHC.Utils.Error (Severity(SevError, SevWarning)) +import GHC.Plugins hiding ((<>), getHscEnv+#if __GLASGOW_HASKELL__ >=902+ , AnnType, AnnLet, AnnRec, AnnLam, AnnCase+ , Exception+#endif+ )++#if __GLASGOW_HASKELL__ < 902+import GHC.Utils.Error (mkErrMsg, mkWarnMsg)+import GHC.Parser.Annotation (IsUnicodeSyntax(NormalSyntax))+#else+import GHC.Types.SourceText (SourceText(NoSourceText), mkIntegralLit)+import GHC.Types.Fixity+#endif+ import qualified GHC.Hs as GHC-import qualified GHC.Plugins as GHC #endif @@ -113,10 +138,10 @@ -- | Optionally @qualified@ import declaration importDecl :: ModuleName -> Bool -> LImportDecl GhcPs-importDecl name qualified = noLoc $ ImportDecl {+importDecl name qualified = noLocA $ ImportDecl { ideclExt = defExt , ideclSourceSrc = NoSourceText- , ideclName = noLoc name+ , ideclName = noLocA name , ideclPkgQual = Nothing , ideclSafe = False , ideclImplicit = False@@ -138,14 +163,14 @@ #if __GLASGOW_HASKELL__ < 900 conPat x y = ConPatIn x y #else-conPat x y = ConPat noExtField x y+conPat x y = ConPat defExt (reLocA x) y #endif mkFunBind :: Located RdrName -> [LMatch GhcPs (LHsExpr GhcPs)] -> HsBind GhcPs #if __GLASGOW_HASKELL__ < 810 mkFunBind = GHC.mkFunBind #else-mkFunBind = GHC.mkFunBind Generated+mkFunBind (reLocA -> n) = GHC.mkFunBind Generated n #endif #if __GLASGOW_HASKELL__ < 900@@ -157,13 +182,25 @@ type LHsModule = Located HsModule type LRdrName = Located RdrName -putLogMsg :: DynFlags -> WarnReason -> Severity -> SrcSpan -> SDoc -> IO ()-#if __GLASGOW_HASKELL__ < 900-putLogMsg flags reason sev srcspan =- GHC.putLogMsg flags reason sev srcspan (defaultErrStyle flags)-#else-putLogMsg = GHC.putLogMsg+{-------------------------------------------------------------------------------+ Exact-print annotations+-------------------------------------------------------------------------------}++#if __GLASGOW_HASKELL__ < 902+reLoc :: Located a -> Located a+reLoc = id++reLocA :: Located a -> Located a+reLocA = id++noLocA :: e -> Located e+noLocA = noLoc++#if __GLASGOW_HASKELL__ >= 900+mapXRec :: forall pass f g l. (f pass -> g pass) -> GenLocated l (f pass) -> GenLocated l (g pass)+mapXRec = fmap #endif+#endif {------------------------------------------------------------------------------- Extensions@@ -185,6 +222,32 @@ defExt = NoLayoutInfo #endif +instance (HasDefaultExt a, HasDefaultExt b) => HasDefaultExt (a, b) where+ defExt = (defExt, defExt)++instance (HasDefaultExt a, HasDefaultExt b, HasDefaultExt c) => HasDefaultExt (a, b, c) where+ defExt = (defExt, defExt, defExt)++#if __GLASGOW_HASKELL__ >= 902+instance HasDefaultExt (EpAnn ann) where+ defExt = noAnn++instance HasDefaultExt AnnSortKey where+ defExt = NoAnnSortKey++instance HasDefaultExt EpAnnComments where+ defExt = epAnnComments noAnn+#endif++-- In GHC-9.2 some things have extension fields.+#if __GLASGOW_HASKELL__ >= 902+withDefExt :: HasDefaultExt a => (a -> b) -> b+withDefExt f = f defExt +#else+withDefExt :: a -> a+withDefExt a = a+#endif+ {------------------------------------------------------------------------------- Generalized @forall@ in 9.0 -------------------------------------------------------------------------------}@@ -202,24 +265,24 @@ #endif userTyVar ::- XUserTyVar pass- -> Located (IdP pass)- -> HsTyVarBndr pass+ XUserTyVar GhcPs+ -> Located (IdP GhcPs)+ -> HsTyVarBndr GhcPs #if __GLASGOW_HASKELL__ < 900 userTyVar = UserTyVar #else-userTyVar ext = UserTyVar ext ()+userTyVar ext x = UserTyVar ext () (reLocA x) #endif kindedTyVar ::- XKindedTyVar pass- -> Located (IdP pass)- -> LHsKind pass- -> HsTyVarBndr pass+ XKindedTyVar GhcPs+ -> Located (IdP GhcPs)+ -> LHsKind GhcPs+ -> HsTyVarBndr GhcPs #if __GLASGOW_HASKELL__ < 900 kindedTyVar = KindedTyVar #else-kindedTyVar ext = KindedTyVar ext ()+kindedTyVar ext k = KindedTyVar ext () (reLocA k) #endif -- | Like 'hsTyVarName', but don't throw away the location information@@ -229,20 +292,22 @@ hsTyVarLName (KindedTyVar _ n _) = n hsTyVarLName _ = panic "hsTyVarLName" #else-hsTyVarLName (UserTyVar _ _ n ) = n-hsTyVarLName (KindedTyVar _ _ n _) = n+hsTyVarLName (UserTyVar _ _ n ) = reLoc n+hsTyVarLName (KindedTyVar _ _ n _) = reLoc n #endif #if __GLASGOW_HASKELL__ < 900 setDefaultSpecificity :: LHsTyVarBndr pass -> GHC.LHsTyVarBndr pass setDefaultSpecificity = id #else-setDefaultSpecificity :: LHsTyVarBndr pass -> GHC.LHsTyVarBndr Specificity pass-setDefaultSpecificity (L l v) = L l $ case v of+setDefaultSpecificity :: LHsTyVarBndr GhcPs -> GHC.LHsTyVarBndr Specificity GhcPs+setDefaultSpecificity = mapXRec @GhcPs $ \v -> case v of UserTyVar ext () name -> UserTyVar ext SpecifiedSpec name KindedTyVar ext () name kind -> KindedTyVar ext SpecifiedSpec name kind+#if __GLASGOW_HASKELL__ < 900 XTyVarBndr ext -> XTyVarBndr ext #endif+#endif {------------------------------------------------------------------------------- New functionality@@ -294,26 +359,57 @@ Working with locations -------------------------------------------------------------------------------} -class InheritLoc a b lb | lb -> b where- inheritLoc :: a -> b -> lb+class FromSrcSpan l where+ fromSrcSpan :: SrcSpan -> l -instance InheritLoc (Located a) b (Located b) where- inheritLoc (L l _) = L l+instance FromSrcSpan SrcSpan where+ fromSrcSpan = id -instance InheritLoc a b lb => InheritLoc (NonEmpty a) b lb where+#if __GLASGOW_HASKELL__ >= 902+instance HasDefaultExt ann => FromSrcSpan (SrcSpanAnn' ann) where+ fromSrcSpan = SrcSpanAnn defExt+#endif++class InheritLoc a where+ inheritLoc :: FromSrcSpan l => a -> b -> GenLocated l b++#if __GLASGOW_HASKELL__ >= 902+-- GHC-9.2 may not require annotation+inheritLoc' :: a -> b -> b+inheritLoc' _ = id+#else+inheritLoc' :: InheritLoc a => a -> b -> Located b+inheritLoc' = inheritLoc+#endif++instance InheritLoc a => InheritLoc (NonEmpty a) where inheritLoc = inheritLoc . NE.head --- | The instance for @[]@ is not ideal: we use 'noLoc' if the list is empty+instance InheritLoc l => InheritLoc (GenLocated l a) where+ inheritLoc (L l _) = inheritLoc l++instance InheritLoc SrcSpan where+ inheritLoc l x = L (fromSrcSpan l) x++#if __GLASGOW_HASKELL__ >= 902+instance InheritLoc (SrcSpanAnn' ann) where+ inheritLoc (SrcSpanAnn _ l) = inheritLoc l+#endif+ ----- For the use cases in this library, this is acceptable: typically these are--- lists with elements for the record fields, and having slightly poorer error--- messages for highly unusual "empty large" records is fine.-instance InheritLoc a b (Located b) => InheritLoc [a] b (Located b) where- inheritLoc (a:_) = inheritLoc a- inheritLoc [] = noLoc+-- -- | The instance for @[]@ is not ideal: we use 'noLoc' if the list is empty+-- --+-- -- For the use cases in this library, this is acceptable: typically these are+-- -- lists with elements for the record fields, and having slightly poorer error+-- -- messages for highly unusual "empty large" records is fine.+instance InheritLoc a => InheritLoc [a] where+ inheritLoc (a:_) = inheritLoc a+ inheritLoc [] = inheritLoc noSrcSpan #if __GLASGOW_HASKELL__ < 810--- In 8.8, 'LPat' is a synonym for 'Pat'-instance InheritLoc a (Pat p) (LPat p) where- inheritLoc _ = id+inheritLocPat :: a -> Pat p -> LPat p+inheritLocPat _ = id -- In 8.8, 'LPat' is a synonym for 'Pat'+#else+inheritLocPat :: InheritLoc a => a -> Pat (GhcPass p) -> LPat (GhcPass p)+inheritLocPat = inheritLoc #endif
src/Data/Record/Internal/GHC/TemplateHaskellStyle.hs view
@@ -179,13 +179,13 @@ -- | Equivalent of 'Language.Haskell.TH.Lib.varE' varE :: HasCallStack => LRdrName -> LHsExpr GhcPs varE name- | isTermVar name = inheritLoc name $ HsVar defExt name+ | isTermVar name = inheritLoc name $ HsVar defExt (reLocA name) | otherwise = error "varE: incorrect name type" -- | Inverse to 'varE' viewVarE :: LHsExpr GhcPs -> Maybe LRdrName-viewVarE (L _ (HsVar _ name)) | isTermVar name = Just name-viewVarE _ = Nothing+viewVarE (reLoc -> L _ (HsVar _ (reLoc -> name))) | isTermVar name = Just name+viewVarE _ = Nothing pattern VarE :: HasCallStack => () => LRdrName -> LHsExpr GhcPs pattern VarE name <- (viewVarE -> Just name)@@ -195,12 +195,12 @@ -- | Equivalent of 'Language.Haskell.TH.Lib.conE' conE :: HasCallStack => LRdrName -> LHsExpr GhcPs conE name- | isTermCon name = inheritLoc name $ HsVar defExt name+ | isTermCon name = inheritLoc name $ HsVar defExt (reLocA name) | otherwise = error "conE: incorrect name type" -- | Inverse to 'conE' viewConE :: LHsExpr GhcPs -> Maybe LRdrName-viewConE (L _ (HsVar _ name)) | isTermCon name = Just name+viewConE (reLoc -> L _ (HsVar _ (reLoc -> name))) | isTermCon name = Just name viewConE _ = Nothing pattern ConE :: HasCallStack => () => LRdrName -> LHsExpr GhcPs@@ -210,7 +210,7 @@ -- | Equivalent of 'Language.Haskell.TH.Lib.litE' litE :: HsLit GhcPs -> LHsExpr GhcPs-litE = noLoc . HsLit defExt+litE = noLocA . HsLit defExt -- | Equivalent of 'Language.Haskell.TH.Lib.stringE' stringE :: String -> LHsExpr GhcPs@@ -222,11 +222,15 @@ where mkRec :: LRdrName -> [LHsRecField GhcPs (LHsExpr GhcPs)] -> LHsExpr GhcPs mkRec name fields = inheritLoc name $- RecordCon defExt name (HsRecFields fields Nothing)+ RecordCon defExt (reLocA name) (HsRecFields fields Nothing) mkFld :: LRdrName -> LHsExpr GhcPs -> LHsRecField GhcPs (LHsExpr GhcPs) mkFld name val = inheritLoc name $- HsRecField (inheritLoc name (mkFieldOcc name)) val False+ HsRecField+#if __GLASGOW_HASKELL__ >= 902+ defExt+#endif+ (reLoc (inheritLoc name (mkFieldOcc (reLocA name)))) val False -- | Equivalent of 'Language.Haskell.TH.Lib.recUpdE' recUpdE :: LHsExpr GhcPs -> [(LRdrName, LHsExpr GhcPs)] -> LHsExpr GhcPs@@ -234,21 +238,33 @@ where updRec :: LHsExpr GhcPs -> [LHsRecUpdField GhcPs] -> LHsExpr GhcPs updRec expr fields = inheritLoc expr $- RecordUpd defExt expr fields+ RecordUpd defExt expr+#if __GLASGOW_HASKELL__ >= 902+ $ Left+#endif+ fields updFld :: LRdrName -> LHsExpr GhcPs -> LHsRecUpdField GhcPs updFld name val = inheritLoc name $- HsRecField (inheritLoc name (mkAmbiguousFieldOcc name)) val False+ HsRecField+#if __GLASGOW_HASKELL__ >= 902+ defExt+#endif+ (reLoc (inheritLoc name (mkAmbiguousFieldOcc (reLocA name)))) val False viewRecUpdE :: LHsExpr GhcPs -> Maybe (LHsExpr GhcPs, [(LRdrName, LHsExpr GhcPs)])+#if __GLASGOW_HASKELL__ >= 902+viewRecUpdE (L _ (RecordUpd _ recExpr (Left fields))) =+#else viewRecUpdE (L _ (RecordUpd _ recExpr fields)) =+#endif (recExpr,) <$> mapM viewFieldUpd fields where viewFieldUpd :: LHsRecUpdField GhcPs -> Maybe (LRdrName, LHsExpr GhcPs)- viewFieldUpd (L _ (HsRecField (L _ (Unambiguous _ name)) val False)) =- Just (name, val)+ viewFieldUpd (L _ (HsRecField { hsRecFieldLbl = L _ (Unambiguous _ name), hsRecFieldArg = val, hsRecPun = False })) =+ Just (reLoc name, val) viewFieldUpd _otherwise = Nothing viewRecUpdE _otherwise = Nothing@@ -264,7 +280,11 @@ -- | Equivalent of 'Language.Haskell.TH.Lib.listE' listE :: [LHsExpr GhcPs] -> LHsExpr GhcPs-listE es = inheritLoc es $ ExplicitList defExt Nothing es+listE es = inheritLoc es $ ExplicitList defExt+#if __GLASGOW_HASKELL__ < 902+ Nothing+#endif+ es -- | Equivalent of 'Language.Haskell.TH.Lib.lamE' lamE :: NonEmpty (LPat GhcPs) -> LHsExpr GhcPs -> LHsExpr GhcPs@@ -297,7 +317,7 @@ tupE xs = inheritLoc xs $ ExplicitTuple defExt- [inheritLoc xs (Present defExt x) | x <- NE.toList xs]+ [inheritLoc' xs (Present defExt x) | x <- NE.toList xs] Boxed -- | Equivalent of 'Language.Haskell.TH.Lib.sigE'@@ -319,18 +339,18 @@ -- | Equivalent of 'Language.Haskell.TH.Lib.litT' litT :: HsTyLit -> LHsType GhcPs-litT = noLoc . HsTyLit defExt+litT = noLocA . HsTyLit defExt -- | Equivalent of 'Language.Haskell.TH.Lib.varT' varT :: HasCallStack => LRdrName -> LHsType GhcPs varT name- | isTypeVar name = inheritLoc name (HsTyVar defExt NotPromoted name)+ | isTypeVar name = inheritLoc name (HsTyVar defExt NotPromoted (reLocA name)) | otherwise = error "varT: incorrect name type" -- | Inverse to 'varT' viewVarT :: LHsType GhcPs -> Maybe LRdrName-viewVarT (L _ (HsTyVar _ _ name)) | isTypeVar name = Just name-viewVarT _otherwise = Nothing+viewVarT (reLoc -> L _ (HsTyVar _ _ (reLoc -> name))) | isTypeVar name = Just name+viewVarT _otherwise = Nothing pattern VarT :: HasCallStack => () => LRdrName -> LHsType GhcPs pattern VarT name <- (viewVarT -> Just name)@@ -340,13 +360,13 @@ -- | Equivalent of 'Language.Haskell.TH.Lib.conT' conT :: HasCallStack => LRdrName -> LHsType GhcPs conT name- | isTypeCon name = inheritLoc name (HsTyVar defExt NotPromoted name)+ | isTypeCon name = inheritLoc name (HsTyVar defExt NotPromoted (reLocA name)) | otherwise = error "varT: incorrect name type" -- | Inverse to 'conT' viewConT :: LHsType GhcPs -> Maybe LRdrName-viewConT (L _ (HsTyVar _ _ name)) | isTypeCon name = Just name-viewConT _otherwise = Nothing+viewConT (reLoc -> L _ (HsTyVar _ _ (reLoc -> name))) | isTypeCon name = Just name+viewConT _otherwise = Nothing pattern ConT :: HasCallStack => () => LRdrName -> LHsType GhcPs pattern ConT name <- (viewConT -> Just name)@@ -394,23 +414,27 @@ -- | Equivalent of 'Language.Haskell.TH.Lib.varP' varP :: LRdrName -> LPat GhcPs-varP name = inheritLoc name (VarPat defExt name)+varP name = inheritLocPat name (VarPat defExt (reLocA name)) -- | Equivalent of 'Language.Haskell.TH.Lib.conP' conP :: LRdrName -> [LPat GhcPs] -> LPat GhcPs-conP con args = inheritLoc con (conPat con (PrefixCon args))+#if __GLASGOW_HASKELL__ >= 902+conP con args = inheritLocPat con (conPat con (PrefixCon [] args))+#else+conP con args = inheritLocPat con (conPat con (PrefixCon args))+#endif -- | Equivalent of 'Language.Haskell.TH.Lib.bangP' bangP :: LPat GhcPs -> LPat GhcPs-bangP p = inheritLoc p $ BangPat defExt p+bangP p = inheritLocPat p $ BangPat defExt p -- | Equivalent of 'Language.Haskell.TH.Lib.listP' listP :: [LPat GhcPs] -> LPat GhcPs-listP xs = inheritLoc xs $ ListPat defExt xs+listP xs = inheritLocPat xs $ ListPat defExt xs -- | Equivalent of 'Language.Haskell.TH.Lib.wildP' wildP :: LPat GhcPs-wildP = noLoc (WildPat defExt)+wildP = inheritLocPat noSrcSpan (WildPat defExt) {------------------------------------------------------------------------------- Strictness@@ -448,12 +472,16 @@ (L _ ConDeclH98 { con_name = conName+#if __GLASGOW_HASKELL__ >= 902+ , con_forall = False+#else , con_forall = L _ False+#endif , con_ex_tvs = [] , con_mb_cxt = Nothing , con_args = RecCon (L _ fields) }- ) = (conName,) <$> mapM viewRecField fields+ ) = (reLoc conName ,) <$> mapM viewRecField fields where viewRecField :: LConDeclField GhcPs -> Maybe (LRdrName, LHsType GhcPs) viewRecField@@ -466,7 +494,7 @@ viewRecField _otherwise = Nothing viewFieldOcc :: FieldOcc GhcPs -> LRdrName- viewFieldOcc (FieldOcc _ name) = name+ viewFieldOcc (FieldOcc _ (reLoc -> name)) = name #if __GLASGOW_HASKELL__ < 900 viewFieldOcc _ = panic "viewFieldOcc" #endif@@ -487,8 +515,8 @@ -> LConDecl GhcPs forallRecC vars ctxt conName args = inheritLoc conName $ ConDeclH98 { con_ext = defExt- , con_name = conName- , con_forall = inheritLoc conName True+ , con_name = reLocA conName+ , con_forall = inheritLoc' conName True , con_ex_tvs = map (setDefaultSpecificity . mkBndr) vars , con_mb_cxt = Just (inheritLoc conName ctxt) , con_args = RecCon (inheritLoc conName $ map (uncurry mkRecField) args)@@ -501,7 +529,7 @@ mkRecField :: LRdrName -> LHsType GhcPs -> LConDeclField GhcPs mkRecField name ty = inheritLoc name $ ConDeclField { cd_fld_ext = defExt- , cd_fld_names = [inheritLoc name $ mkFieldOcc name]+ , cd_fld_names = [inheritLoc name $ mkFieldOcc $ reLocA name] , cd_fld_type = ty , cd_fld_doc = Nothing }@@ -530,7 +558,7 @@ sigD name ty = inheritLoc name $ SigD defExt sig where sig :: Sig GhcPs- sig = TypeSig defExt [name] $ HsWC defExt (implicitBndrs ty)+ sig = TypeSig defExt [reLocA name] $ HsWC defExt (implicitBndrs ty) -- | Equivalent of 'Language.Haskell.TH.Lib.valD' --@@ -549,17 +577,21 @@ dataD typeName tyVars cons derivs = inheritLoc typeName $ TyClD defExt $ DataDecl { tcdDExt = defExt- , tcdLName = typeName+ , tcdLName = reLocA typeName , tcdTyVars = mkHsQTvs tyVars , tcdFixity = Prefix , tcdDataDefn = HsDataDefn { dd_ext = defExt , dd_ND = DataType+#if __GLASGOW_HASKELL__ >= 902+ , dd_ctxt = Nothing+#else , dd_ctxt = inheritLoc typeName []+#endif , dd_cType = Nothing , dd_kindSig = Nothing , dd_cons = cons- , dd_derivs = inheritLoc typeName derivs+ , dd_derivs = inheritLoc' typeName derivs } } @@ -582,15 +614,23 @@ , tcdFixity = Prefix , tcdDataDefn = HsDataDefn { dd_ND = DataType+#if __GLASGOW_HASKELL__ >= 902+ , dd_ctxt = Nothing+#else , dd_ctxt = L _ []+#endif , dd_cType = Nothing , dd_kindSig = Nothing , dd_cons = cons+#if __GLASGOW_HASKELL__ >= 902+ , dd_derivs = derivs+#else , dd_derivs = L _ derivs+#endif } } )- ) = Just (typeName, tyVars, cons, derivs)+ ) = Just (reLoc typeName, tyVars, cons, derivs) viewDataD _otherwise = Nothing pattern DataD ::@@ -610,15 +650,25 @@ -> NonEmpty (LHsType GhcPs) -> LHsDerivingClause GhcPs derivClause strat tys = inheritLoc tys $- HsDerivingClause defExt strat $- inheritLoc tys $ map implicitBndrs (NE.toList tys)+ HsDerivingClause defExt strat $ inheritLoc tys $+#if __GLASGOW_HASKELL__ >= 902+ DctMulti defExt $+#endif+ map implicitBndrs (NE.toList tys) -- | Inverse of 'derivClause' viewDerivClause :: LHsDerivingClause GhcPs -> (Maybe (LDerivStrategy GhcPs), [LHsType GhcPs])+#if __GLASGOW_HASKELL__ >= 902+viewDerivClause (L _ (HsDerivingClause _ mStrat (L _ (DctMulti _ tys)))) =+ (mStrat, map viewImplicitBndrs tys)+viewDerivClause (L _ (HsDerivingClause _ mStrat (L _ (DctSingle _ ty)))) =+ (mStrat, map viewImplicitBndrs [ty])+#else viewDerivClause (L _ (HsDerivingClause _ mStrat (L _ tys))) = (mStrat, map viewImplicitBndrs tys)+#endif #if __GLASGOW_HASKELL__ < 900 viewDerivClause _ = panic "viewDerivClause" #endif@@ -654,8 +704,13 @@ where qualT :: [LHsType GhcPs] -> LHsType GhcPs -> LHsType GhcPs qualT [] a = a- qualT ctx@(c:_) a = inheritLoc c $- HsQualTy defExt (inheritLoc c ctx) a+ qualT ctx@(c:_) a = inheritLoc c $ HsQualTy defExt+#if __GLASGOW_HASKELL__ >= 902+ (Just (inheritLoc c ctx))+#else+ (inheritLoc c ctx)+#endif+ a -- | Equivalent of 'Language.Haskell.TH.Lib.classD' classD ::@@ -667,8 +722,12 @@ classD = \ctx name clsVars sigs -> inheritLoc name $ TyClD defExt $ ClassDecl { tcdCExt = defExt+#if __GLASGOW_HASKELL__ >= 902+ , tcdCtxt = Just (inheritLoc name ctx)+#else , tcdCtxt = inheritLoc name ctx- , tcdLName = name+#endif+ , tcdLName = reLocA name , tcdTyVars = mkHsQTvs clsVars , tcdFixity = Prefix , tcdFDs = []@@ -681,7 +740,7 @@ where classOpSig :: LRdrName -> LHsType GhcPs -> LSig GhcPs classOpSig name ty = inheritLoc name $- ClassOpSig defExt False [name] (implicitBndrs ty)+ ClassOpSig defExt False [reLocA name] (implicitBndrs ty) -- | Approximate equivalent of 'Language.Haskell.TH.Lib.tySynEqn' tySynEqn ::@@ -690,11 +749,19 @@ -> LHsType GhcPs -- ^ Equation RHS -> LTyFamInstDecl GhcPs tySynEqn name pats val = inheritLoc val $- TyFamInstDecl $- implicitBndrs $+ TyFamInstDecl+#if __GLASGOW_HASKELL__ >= 902+ defExt $+#else+ $ implicitBndrs $+#endif FamEqn defExt- name+ (reLocA name)+#if __GLASGOW_HASKELL__ >= 902+ (HsOuterImplicit defExt)+#else Nothing+#endif (map HsValArg pats) Prefix val@@ -706,22 +773,29 @@ the @name@ type in @Located@. -------------------------------------------------------------------------------} +type AnnProvenancePs = AnnProvenance+#if __GLASGOW_HASKELL__ >= 902+ GhcPs+#else+ RdrName+#endif+ -- | Equivalent of 'Language.Haskell.TH.Lib.typeAnnotation'-typeAnnotation :: LRdrName -> AnnProvenance RdrName-typeAnnotation name = TypeAnnProvenance name+typeAnnotation :: LRdrName -> AnnProvenancePs+typeAnnotation name = TypeAnnProvenance (reLocA name) -- | Inverse to 'typeAnnotation'-viewTypeAnnotation :: AnnProvenance RdrName -> Maybe LRdrName-viewTypeAnnotation (TypeAnnProvenance name) = Just name+viewTypeAnnotation :: AnnProvenancePs -> Maybe LRdrName+viewTypeAnnotation (TypeAnnProvenance name) = Just (reLoc name) viewTypeAnnotation _otherwise = Nothing -pattern TypeAnnotation :: LRdrName -> AnnProvenance RdrName+pattern TypeAnnotation :: LRdrName -> AnnProvenancePs pattern TypeAnnotation name <- (viewTypeAnnotation -> Just name) where TypeAnnotation = typeAnnotation -- | Equivalent of 'Language.Haskell.TH.Lib.pragAnnD'-pragAnnD :: AnnProvenance RdrName -> LHsExpr GhcPs -> AnnDecl GhcPs+pragAnnD :: AnnProvenancePs -> LHsExpr GhcPs -> AnnDecl GhcPs pragAnnD prov value = HsAnnotation defExt@@ -729,13 +803,13 @@ prov value -viewPragAnnD :: AnnDecl GhcPs -> (AnnProvenance RdrName, LHsExpr GhcPs)+viewPragAnnD :: AnnDecl GhcPs -> (AnnProvenancePs, LHsExpr GhcPs) viewPragAnnD (HsAnnotation _ _ prov value) = (prov, value) #if __GLASGOW_HASKELL__ < 900 viewPragAnnD _ = panic "viewPragAnnD" #endif -pattern PragAnnD :: AnnProvenance RdrName -> LHsExpr GhcPs -> AnnDecl GhcPs+pattern PragAnnD :: AnnProvenancePs -> LHsExpr GhcPs -> AnnDecl GhcPs pattern PragAnnD prov value <- (viewPragAnnD -> (prov, value)) where PragAnnD = pragAnnD@@ -744,6 +818,14 @@ Internal auxiliary -------------------------------------------------------------------------------} +#if __GLASGOW_HASKELL__ >= 902+implicitBndrs :: LHsType GhcPs -> LHsSigType GhcPs+implicitBndrs t = inheritLoc t (HsSig defExt (HsOuterImplicit defExt) t)++viewImplicitBndrs :: LHsSigType GhcPs -> LHsType GhcPs+viewImplicitBndrs (L _ (HsSig _ _ ty)) = ty++#else implicitBndrs :: a -> HsImplicitBndrs GhcPs a implicitBndrs a = HsIB defExt a @@ -752,6 +834,7 @@ #if __GLASGOW_HASKELL__ < 900 viewImplicitBndrs _ = panic "viewImplicitBndrs" #endif+#endif -- | Simple binding (without patterns) simpleBinding :: LRdrName -> LHsExpr GhcPs -> LHsBind GhcPs@@ -764,7 +847,7 @@ match :: LMatch GhcPs (LHsExpr GhcPs) match = inheritLoc fnName $ Match defExt- (FunRhs fnName Prefix NoSrcStrict)+ (FunRhs (reLocA fnName) Prefix NoSrcStrict) [] grhs @@ -773,6 +856,6 @@ simpleGHRSs body = GRHSs defExt [inheritLoc body $ GRHS defExt [] body]- (inheritLoc body $ EmptyLocalBinds defExt)+ (inheritLoc' body $ EmptyLocalBinds defExt)
src/Data/Record/Internal/Plugin/CodeGen.hs view
@@ -8,12 +8,13 @@ import Data.List (nubBy) import Data.List.NonEmpty (NonEmpty(..)) +import Language.Haskell.TH (Extension(StrictData))+ import qualified Data.Generics as SYB import Data.Record.Internal.GHC.Fresh import Data.Record.Internal.GHC.Shim hiding (mkTyVar) import Data.Record.Internal.GHC.TemplateHaskellStyle-import Data.Record.Internal.Plugin.Options import Data.Record.Internal.Plugin.Record import qualified Data.Record.Internal.Plugin.Names.GhcGenerics as GHC@@ -24,8 +25,8 @@ -------------------------------------------------------------------------------} -- | Generate all large-records definitions for a record.-genLargeRecord :: MonadFresh m => Record -> m [LHsDecl GhcPs]-genLargeRecord r@Record{..} = concatM [+genLargeRecord :: MonadFresh m => Record -> DynFlags -> m [LHsDecl GhcPs]+genLargeRecord r@Record{..} dynFlags = concatM [ (:[]) <$> genDatatype r , genVectorConversions r , genIndexedAccessor r@@ -35,7 +36,7 @@ , sequence [ genConstraintsClass r , genConstraintsInstance r- , genGenericInstance r+ , genGenericInstance r dynFlags , genGHCGeneric r ] ]@@ -101,7 +102,7 @@ (zipWith fieldExistentialType vars recordFields) ]- [ DerivClause (Just (noLoc AnyclassStrategy)) (c :| [])+ [ DerivClause (Just (noLoc (withDefExt AnyclassStrategy))) (c :| []) | DeriveAnyClass c <- recordDerivings ] where@@ -113,14 +114,14 @@ | (i, _) <- zip [1 :: Int ..] recordFields ] - optionalBang :: LHsType GhcPs -> LHsType GhcPs- optionalBang = if allFieldsStrict recordOptions then bangType else id+ optionalBang :: HsSrcBang -> LHsType GhcPs -> LHsType GhcPs+ optionalBang bang = noLocA . HsBangTy defExt bang fieldContext :: LRdrName -> Field -> LHsType GhcPs fieldContext var fld = equalP (VarT var) (fieldType fld) fieldExistentialType :: LRdrName -> Field -> (LRdrName, LHsType GhcPs)- fieldExistentialType var fld = (fieldName fld, optionalBang $ VarT var)+ fieldExistentialType var fld = (fieldName fld, optionalBang (fieldStrictness fld) $ VarT var) -- | Generate conversion to and from an array --@@ -467,8 +468,8 @@ -- > , FieldMetadata (Proxy :: Proxy "tListB")) FieldLazy -- > ] -- > }-genMetadata :: MonadFresh m => Record -> m (LHsExpr GhcPs)-genMetadata r@Record{..} = do+genMetadata :: MonadFresh m => Record -> DynFlags -> m (LHsExpr GhcPs)+genMetadata r@Record{..} dynFlags = do p <- freshName $ mkExpVar recordAnnLoc "p" return $ lamE1 (varP p) $@@ -498,11 +499,26 @@ appsE (ConE RT.con_FieldMetadata) [ proxyE (stringT (nameBase fieldName))- , ConE $ if allFieldsStrict recordOptions- then RT.con_FieldStrict- else RT.con_FieldLazy+ , ConE $ case decideStrictness dynFlags fieldStrictness of+ HsStrict -> RT.con_FieldStrict+ HsLazy -> RT.con_FieldLazy+ HsUnpack _ -> RT.con_FieldStrict ] +-- | Implementation of https://hackage.haskell.org/package/base-4.16.1.0/docs/GHC-Generics.html#t:DecidedStrictness+decideStrictness :: DynFlags -> HsSrcBang -> HsImplBang+decideStrictness dynFlags (HsSrcBang _ unpackedness strictness) =+ case (unpackedness, srcToImpl strictness) of+ (SrcUnpack, HsStrict) | optimizations -> HsUnpack Nothing+ (_, strictness') -> strictness'+ where+ strictData = xopt StrictData dynFlags+ optimizations = optLevel dynFlags >= 1+ srcToImpl = \case+ SrcStrict -> HsStrict+ SrcLazy -> HsLazy+ NoSrcStrict -> if strictData then HsStrict else HsLazy+ -- | Generate definition for `from` in the `Generic` instance -- -- Generates something like@@ -545,9 +561,9 @@ -- > to = .. -- > dict = dictConstraints_T -- > metadata = ..-genGenericInstance :: MonadFresh m => Record -> m (LHsDecl GhcPs)-genGenericInstance r@Record{..} = do- metadata <- genMetadata r+genGenericInstance :: MonadFresh m => Record -> DynFlags -> m (LHsDecl GhcPs)+genGenericInstance r@Record{..} dynFlags = do+ metadata <- genMetadata r dynFlags from <- genFrom r to <- genTo r return $
src/Data/Record/Internal/Plugin/Exception.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ViewPatterns #-} -- | Exceptions that may be thrown by the large-records plugin. module Data.Record.Internal.Plugin.Exception (@@ -17,9 +18,9 @@ exceptionLoc :: Exception -> SrcSpan exceptionLoc = \case- UnsupportedStockDeriving (L l _) -> l- UnsupportedStrategy (L l _) -> l- InvalidDeclaration (L l _) -> l+ UnsupportedStockDeriving (reLoc -> L l _) -> l+ UnsupportedStrategy (id -> L l _) -> l+ InvalidDeclaration (reLoc -> L l _) -> l exceptionToSDoc :: Exception -> SDoc exceptionToSDoc = hsep . \case
src/Data/Record/Internal/Plugin/Options.hs view
@@ -7,8 +7,7 @@ module Data.Record.Internal.Plugin.Options ( -- * Definition LargeRecordOptions(..)- , largeRecordStrict- , largeRecordLazy+ , largeRecord -- * Extract options from source module , getLargeRecordOptions ) where@@ -32,34 +31,21 @@ -- -- The default for Haskell code should probably be: ----- > {-# ANN type T largeRecordLazy #-}--- > data T = ..------ For records with strict fields, you can use:------ > {-# ANN type T largeRecordStrict #-}+-- > {-# ANN type T largeRecord #-} -- > data T = .. -- -- To see the definitions generated by @large-records@: ----- > {-# ANN type T largeRecordLazy {debugLargeRecords = True} #-}+-- > {-# ANN type T largeRecord {debugLargeRecords = True} #-} -- > data T = .. data LargeRecordOptions = LargeRecordOptions {- allFieldsStrict :: Bool- , debugLargeRecords :: Bool+ debugLargeRecords :: Bool } deriving stock (Data) -largeRecordStrict :: LargeRecordOptions-largeRecordStrict = LargeRecordOptions {- allFieldsStrict = True- , debugLargeRecords = False- }--largeRecordLazy :: LargeRecordOptions-largeRecordLazy = LargeRecordOptions {- allFieldsStrict = False- , debugLargeRecords = False+largeRecord :: LargeRecordOptions+largeRecord = LargeRecordOptions {+ debugLargeRecords = False } {-------------------------------------------------------------------------------@@ -94,10 +80,8 @@ -------------------------------------------------------------------------------} intOptions :: LHsExpr GhcPs -> Maybe LargeRecordOptions-intOptions (VarE (nameBase -> "largeRecordStrict")) =- Just largeRecordStrict-intOptions (VarE (nameBase -> "largeRecordLazy")) =- Just largeRecordLazy+intOptions (VarE (nameBase -> "largeRecord")) =+ Just largeRecord intOptions (RecUpdE expr fields) = do opts <- intOptions expr updates <- mapM intUpdate fields
src/Data/Record/Internal/Plugin/Record.hs view
@@ -43,9 +43,10 @@ } data Field = Field {- fieldName :: LRdrName- , fieldType :: LHsType GhcPs- , fieldIndex :: Int+ fieldName :: LRdrName+ , fieldType :: LHsType GhcPs+ , fieldStrictness :: HsSrcBang+ , fieldIndex :: Int } -- | Derived classes that we can support.@@ -97,8 +98,9 @@ viewField :: MonadError Exception m- => (LRdrName, LHsType GhcPs) -> m (Int -> Field)-viewField (name, typ) = return $ Field name typ+ => (LRdrName, LHsType GhcPs) -> m (Int -> Field) +viewField (name, typ) =+ return $ Field name (getBangType typ) (getBangStrictness typ) viewRecordDerivings :: MonadError Exception m@@ -111,9 +113,9 @@ viewRecordDeriving = \case DerivClause Nothing tys -> goStock tys- DerivClause (Just (L _ StockStrategy)) tys ->+ DerivClause (Just (L _ StockStrategy {})) tys -> goStock tys- DerivClause (Just (L _ AnyclassStrategy)) tys ->+ DerivClause (Just (L _ AnyclassStrategy {})) tys -> pure $ fmap DeriveAnyClass (NE.toList tys) DerivClause (Just strategy) _ -> throwError (UnsupportedStrategy strategy)
src/Data/Record/Plugin.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE ViewPatterns #-} @@ -7,7 +8,7 @@ -- -- > {-# OPTIONS_GHC -fplugin=Data.Record.Plugin #-} -- >--- > {-# ANN type B LargeRecordStrict #-}+-- > {-# ANN type B largeRecord #-} -- > data B a = B {a :: a, b :: String} -- > deriving stock (Show, Eq, Ord) --@@ -43,6 +44,12 @@ import Data.Record.Internal.Plugin.Options import Data.Record.Internal.Plugin.Record +#if __GLASGOW_HASKELL__ >= 902+import GHC.Driver.Errors+import GHC.Types.Error (mkWarnMsg, mkErr, mkDecorated)+import GHC.Utils.Logger (getLogger)+#endif+ {------------------------------------------------------------------------------- Top-level: the plugin proper -------------------------------------------------------------------------------}@@ -103,7 +110,7 @@ Map String [(SrcSpan, LargeRecordOptions)] -> LHsDecl GhcPs -> WriterT (Set String) Hsc [LHsDecl GhcPs]-transformDecl largeRecords decl@(L l _) =+transformDecl largeRecords decl@(reLoc -> L l _) = case decl of DataD (nameBase -> name) _ _ _ -> case Map.findWithDefault [] name largeRecords of@@ -121,7 +128,8 @@ -- Return the declaration unchanged if we cannot parse it return [decl] Right r -> do- newDecls <- lift $ runFreshHsc $ genLargeRecord r+ dynFlags <- lift getDynFlags+ newDecls <- lift $ runFreshHsc $ genLargeRecord r dynFlags when (debugLargeRecords opts) $ lift $ issueWarning l (debugMsg newDecls) pure newDecls@@ -185,12 +193,23 @@ issueError :: SrcSpan -> SDoc -> Hsc () issueError l errMsg = do+#if __GLASGOW_HASKELL__ >= 902+ throwOneError $+ mkErr l neverQualify (mkDecorated [errMsg])+#else dynFlags <- getDynFlags throwOneError $ mkErrMsg dynFlags l neverQualify errMsg+#endif issueWarning :: SrcSpan -> SDoc -> Hsc () issueWarning l errMsg = do dynFlags <- getDynFlags+#if __GLASGOW_HASKELL__ >= 902+ logger <- getLogger+ liftIO $ printOrThrowWarnings logger dynFlags . listToBag . (:[]) $+ mkWarnMsg l neverQualify errMsg+#else liftIO $ printOrThrowWarnings dynFlags . listToBag . (:[]) $ mkWarnMsg dynFlags l neverQualify errMsg+#endif
src/Data/Record/Plugin/Options.hs view
@@ -3,8 +3,7 @@ -- This module is added as an export to user code by the plugin. module Data.Record.Plugin.Options ( LargeRecordOptions(..)- , largeRecordStrict- , largeRecordLazy+ , largeRecord ) where import Data.Record.Internal.Plugin.Options
test/Test/Record/Sanity/CodeGen.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE RecordWildCards #-}@@ -24,7 +25,7 @@ This is the example record we use throughout the comments in TH codegen. -------------------------------------------------------------------------------} -{-# ANN type T largeRecordStrict #-}+{-# ANN type T largeRecord #-} data T a b = MkT { tInt :: Word , tBool :: Bool
test/Test/Record/Sanity/Derive.hs view
@@ -33,7 +33,7 @@ -- Type of kind @Type@ -{-# ANN type LA1 largeRecordStrict #-}+{-# ANN type LA1 largeRecord #-} data LA1 = MkLA1 { la1_f1 :: Int } deriving anyclass C1 @@ -42,7 +42,7 @@ data RA2 a = MkRA1 { ra2_f1 :: a } deriving anyclass C1 -{-# ANN type LA2 largeRecordStrict #-}+{-# ANN type LA2 largeRecord #-} data LA2 a = MkLA2 { la2_f1 :: a } deriving anyclass C1 @@ -59,7 +59,7 @@ really is a newtype around a record). -------------------------------------------------------------------------------} -{-# ANN type LB largeRecordStrict #-}+{-# ANN type LB largeRecord #-} data LB = MkLB { lb1 :: Int, lb2 :: Int } deriving anyclass (Newtype LB) @@ -80,7 +80,7 @@ data RC a = MkRC { rc1 :: a, rc2 :: Int } deriving anyclass C3 -{-# ANN type LC largeRecordStrict #-}+{-# ANN type LC largeRecord #-} data LC (a :: Type) = MkLC { lc1 :: a, lc2 :: Int } deriving anyclass C3 @@ -96,7 +96,7 @@ data RD f = MkRD { rd1 :: f Int, rd2 :: Int } deriving anyclass C4 -{-# ANN type LD largeRecordStrict #-}+{-# ANN type LD largeRecord #-} data LD (f :: Type -> Type) = MkLD { ld1 :: f Int, ld2 :: Int } deriving anyclass C4 @@ -113,7 +113,7 @@ deriving stock Show deriving anyclass C5 -{-# ANN type LE largeRecordStrict #-}+{-# ANN type LE largeRecord #-} data LE = MkLE { le1 :: Int, le2 :: Bool } deriving stock Show deriving anyclass C5
test/Test/Record/Sanity/EqualFieldTypes.hs view
@@ -20,7 +20,7 @@ import Test.Tasty import Test.Tasty.HUnit -{-# ANN type R largeRecordStrict #-}+{-# ANN type R largeRecord #-} data R a = MkR { field1 :: a , field2 :: a
test/Test/Record/Sanity/GhcGenerics.hs view
@@ -21,7 +21,7 @@ import Test.Tasty import Test.Tasty.HUnit -{-# ANN type R largeRecordStrict #-}+{-# ANN type R largeRecord #-} data R = MkR { a :: Int } deriving (Show)
test/Test/Record/Sanity/HKD.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE MultiParamTypeClasses #-}@@ -29,7 +30,7 @@ HKD (Const b) a = b -- | Test record with fields whose types are given by type families-{-# ANN type T largeRecordStrict #-}+{-# ANN type T largeRecord #-} data T (f :: Type -> Type) = MkT { field1 :: HKD f Int , field2 :: HKD f Bool
test/Test/Record/Sanity/HigherKinded.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE MultiParamTypeClasses #-}@@ -35,7 +36,7 @@ -- We need an explicit kind annotation on @f@ for @large-records@ to generate -- correct code (either that, or use @PolyKinds@).-{-# ANN type MyRecord largeRecordStrict #-}+{-# ANN type MyRecord largeRecord #-} data MyRecord (f :: Type -> Type) = MyRecord { field0 :: T 0 f , field1 :: T 1 f
test/Test/Record/Sanity/OverloadingNoDRF.hs view
@@ -29,10 +29,10 @@ through DRF. --------------------------------------s-----------------------------------------} -{-# ANN type X largeRecordStrict #-}+{-# ANN type X largeRecord #-} data X = MkX { a :: Int } -{-# ANN type Y largeRecordStrict #-}+{-# ANN type Y largeRecord #-} data Y = MkY { a :: String } testOverloading :: Assertion
test/Test/Record/Sanity/PatternMatch.hs view
@@ -28,10 +28,10 @@ Basic pattern matching tests -------------------------------------------------------------------------------} -{-# ANN type T largeRecordStrict #-}+{-# ANN type T largeRecord #-} data T a = MkT { x :: Int, y :: [a], z :: Double } -{-# ANN type S largeRecordStrict #-}+{-# ANN type S largeRecord #-} data S a = MkS { x :: Char, y :: T a } projectOne :: T Bool -> Int@@ -75,7 +75,7 @@ type errors iff 'noSigEmpty' and 'noSigNonEmpty' are suffciently monomorphic. -------------------------------------------------------------------------------} -{-# ANN type T2 largeRecordStrict #-}+{-# ANN type T2 largeRecord #-} data T2 = MkT2 { x :: Int } noSigEmpty MkT {} = ()
test/Test/Record/Sanity/QualifiedImports/A.hs view
@@ -11,5 +11,5 @@ module Test.Record.Sanity.QualifiedImports.A (T(..)) where -{-# ANN type T largeRecordStrict #-}+{-# ANN type T largeRecord #-} data T a = MkT { x :: Int, y :: [a] }
test/Test/Record/Sanity/QualifiedImports/B.hs view
@@ -14,5 +14,5 @@ import qualified Test.Record.Sanity.QualifiedImports.A as A -{-# ANN type T largeRecordStrict #-}+{-# ANN type T largeRecord #-} data T a = MkT { x :: Char, y :: A.T a }
test/Test/Record/Sanity/RDP/SingleModule.hs view
@@ -22,7 +22,7 @@ Simple field selection and override -------------------------------------------------------------------------------} -{-# ANN type R1 largeRecordStrict #-}+{-# ANN type R1 largeRecord #-} data R1 = MkR1 { r1_x :: Int, r1_y :: Bool } deriving (Show, Eq) @@ -44,11 +44,11 @@ Field selection and override when there are overloaded fields -------------------------------------------------------------------------------} -{-# ANN type R2 largeRecordStrict #-}+{-# ANN type R2 largeRecord #-} data R2 = MkR2 { a :: Int, b :: Bool } deriving (Show, Eq) -{-# ANN type R3 largeRecordStrict #-}+{-# ANN type R3 largeRecord #-} data R3 = MkR3 { a :: Int, b :: Char } deriving (Show, Eq) @@ -81,11 +81,11 @@ data R5_WOutLR = MkR5_WOutLR { r5_woutLR_x :: Char, r5_woutLR_y :: Double } deriving (Show, Eq) -{-# ANN type R4_WithLR largeRecordStrict #-}+{-# ANN type R4_WithLR largeRecord #-} data R4_WithLR = MkR4_WithLR { r4_withLR_x :: Int, r4_withLR_y :: R5_WithLR } deriving (Show, Eq) -{-# ANN type R5_WithLR largeRecordStrict #-}+{-# ANN type R5_WithLR largeRecord #-} data R5_WithLR = MkR5_WithLR { r5_withLR_x :: Char, r5_withLR_y :: Double } deriving (Show, Eq)
test/Test/Record/Sanity/RDP/SplitModule/RecordDef.hs view
@@ -22,23 +22,23 @@ , R5_WithLR(..) ) where -{-# ANN type R1 largeRecordStrict #-}+{-# ANN type R1 largeRecord #-} data R1 = MkR1 { r1_x :: Int, r1_y :: Bool } deriving (Show, Eq) -{-# ANN type R2 largeRecordStrict #-}+{-# ANN type R2 largeRecord #-} data R2 = MkR2 { a :: Int, b :: Bool } deriving (Show, Eq) -{-# ANN type R3 largeRecordStrict #-}+{-# ANN type R3 largeRecord #-} data R3 = MkR3 { a :: Int, b :: Char } deriving (Show, Eq) -{-# ANN type R4_WithLR largeRecordStrict #-}+{-# ANN type R4_WithLR largeRecord #-} data R4_WithLR = MkR4_WithLR { r4_withLR_x :: Int, r4_withLR_y :: R5_WithLR } deriving (Show, Eq) -{-# ANN type R5_WithLR largeRecordStrict #-}+{-# ANN type R5_WithLR largeRecord #-} data R5_WithLR = MkR5_WithLR { r5_withLR_x :: Char, r5_withLR_y :: Double } deriving (Show, Eq)
test/Test/Record/Sanity/RecordConstruction.hs view
@@ -2,6 +2,7 @@ {-# LANGUAGE DataKinds #-} {-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE MultiParamTypeClasses #-}@@ -27,10 +28,10 @@ -- Test both the case where the name of the type and the name of the constructor -- are the same and where they are different. -{-# ANN type R largeRecordLazy #-}+{-# ANN type R largeRecord #-} data R a = MkR { x :: Int, y :: [a] } deriving (Eq, Show) -{-# ANN type S largeRecordLazy #-}+{-# ANN type S largeRecord #-} data S a = S { x :: Int, y :: [a] } deriving (Eq, Show) inOrder :: R Bool@@ -56,7 +57,7 @@ data RegularRecord = RR { a :: Int } deriving (Show, Eq) -{-# ANN type T largeRecordStrict #-}+{-# ANN type T largeRecord #-} data T = T { x :: Int, y :: S Bool, z :: RegularRecord } valueOfT :: T
test/Test/Record/Sanity/Strictness.hs view
@@ -27,11 +27,11 @@ import Test.Tasty import Test.Tasty.HUnit -{-# ANN type Lazy largeRecordLazy #-}+{-# ANN type Lazy largeRecord #-} data Lazy = MkLazy { lazyField :: Word } -{-# ANN type Strict largeRecordStrict #-}-data Strict = MkStrict { strictField :: Word }+{-# ANN type Strict largeRecord #-}+data Strict = MkStrict { strictField :: !Word } _silenceWarnings :: Lazy -> Strict -> () _silenceWarnings MkLazy{..} MkStrict{..} = const () $ (
+ test/Test/Record/Sanity/StrictnessStrictData.hs view
@@ -0,0 +1,96 @@+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE StrictData #-}++{-# OPTIONS_GHC -fplugin=Data.Record.Plugin #-}++module Test.Record.Sanity.StrictnessStrictData (tests) where++import Control.Exception+import GHC.Records.Compat++import Data.Record.Generic+import Data.Record.Generic.LowerBound++import qualified Data.Record.Generic.Rep as Rep++import Test.Tasty+import Test.Tasty.HUnit++{-# ANN type Lazy largeRecord #-}+data Lazy = MkLazy { lazyField :: ~Word }++{-# ANN type Strict largeRecord #-}+data Strict = MkStrict { strictField :: Word }++_silenceWarnings :: Lazy -> Strict -> ()+_silenceWarnings MkLazy{..} MkStrict{..} = const () $ (+ lazyField+ , strictField+ )++tests :: TestTree+tests = testGroup "Test.Record.Sanity.Strictness" [+ testCase "initValueLazy" test_initValueLazy+ , testCase "initValueStrict" test_initValueStrict+ , testCase "setValueLazy" test_setValueLazy+ , testCase "setValueStrict" test_setValueStrict+ ]++test_initValueLazy :: Assertion+test_initValueLazy =+ initValue `seq` return ()+ where+ initValue :: Lazy+ initValue = to $ Rep.pure undefined++test_initValueStrict :: Assertion+test_initValueStrict =+ expectBoom (initValue `seq` return ())+ where+ initValue :: Strict+ initValue = to $ Rep.pure boom++test_setValueLazy :: Assertion+test_setValueLazy =+ setField @"lazyField" initValue boom `seq` return ()+ where+ initValue :: Lazy+ initValue = glowerBound++test_setValueStrict :: Assertion+test_setValueStrict =+ expectBoom (setField @"strictField" initValue boom `seq` return ())+ where+ initValue :: Strict+ initValue = glowerBound++{-------------------------------------------------------------------------------+ Auxiliary+-------------------------------------------------------------------------------}++data Boom = Boom+ deriving (Show)++boom :: a+boom = throw Boom++instance Exception Boom++expectBoom :: IO () -> Assertion+expectBoom act = do+ mErr <- try act+ case mErr of+ Left Boom -> return ()+ Right () -> assertFailure "Expected boom"
test/TestLargeRecords.hs view
@@ -14,6 +14,7 @@ import qualified Test.Record.Sanity.RDP.SingleModule import qualified Test.Record.Sanity.RecordConstruction import qualified Test.Record.Sanity.Strictness+import qualified Test.Record.Sanity.StrictnessStrictData import qualified Test.Record.Sanity.GhcGenerics main :: IO ()@@ -34,6 +35,7 @@ , Test.Record.Sanity.RDP.SingleModule.tests , Test.Record.Sanity.RecordConstruction.tests , Test.Record.Sanity.Strictness.tests+ , Test.Record.Sanity.StrictnessStrictData.tests , Test.Record.Sanity.GhcGenerics.tests ] ]