summaryrefslogtreecommitdiff
path: root/compiler/GHC/Core/TyCon.hs
diff options
context:
space:
mode:
authorSebastian Graf <sebastian.graf@kit.edu>2020-11-30 17:08:40 +0100
committerMarge Bot <ben+marge-bot@smart-cactus.org>2020-12-23 10:21:56 -0500
commitf0ec06c76ccd6797d42736fd423adbbb238723b4 (patch)
treec6eade36b2649f83df8172ac319f716c5f30ebe0 /compiler/GHC/Core/TyCon.hs
parent56841432ae4e38dabdada1a280ef0e0878e895f1 (diff)
downloadhaskell-f0ec06c76ccd6797d42736fd423adbbb238723b4.tar.gz
WorkWrap: Unbox constructors with existentials (#18982)
Consider ```hs data Ex where Ex :: e -> Int -> Ex f :: Ex -> Int f (Ex e n) = e `seq` n + 1 ``` Worker/wrapper should build the following worker for `f`: ```hs $wf :: forall e. e -> Int# -> Int# $wf e n = e `seq` n +# 1# ``` But previously it didn't, because `Ex` binds an existential. This patch lifts that condition. That entailed having to instantiate existential binders in `GHC.Core.Opt.WorkWrap.Utils.mkWWstr` via `GHC.Core.Utils.dataConRepFSInstPat`, requiring a bit of a refactoring around what is now `DataConPatContext`. CPR W/W still won't unbox DataCons with existentials. See `Note [Which types are unboxed?]` for details. I also refactored the various `tyCon*DataCon(s)_maybe` functions in `GHC.Core.TyCon`, deleting some of them which are no longer needed (`isDataProductType_maybe` and `isDataSumType_maybe`). I cleaned up a couple of call sites, some of which weren't very explicit about whether they cared for existentials or not. The test output of `T18013` changed, because we now unbox the `Rule` data type. Its constructor carries existential state and will be w/w'd now. In the particular example, the worker functions inlines right back into the wrapper, which then unnecessarily has a (quite big) stable unfolding. I think this kind of fallout is inevitable; see also Note [Don't w/w inline small non-loop-breaker things]. There's a new regression test case `T18982`. Fixes #18982.
Diffstat (limited to 'compiler/GHC/Core/TyCon.hs')
-rw-r--r--compiler/GHC/Core/TyCon.hs99
1 files changed, 20 insertions, 79 deletions
diff --git a/compiler/GHC/Core/TyCon.hs b/compiler/GHC/Core/TyCon.hs
index a038fd646c..0cd1463b46 100644
--- a/compiler/GHC/Core/TyCon.hs
+++ b/compiler/GHC/Core/TyCon.hs
@@ -58,8 +58,7 @@ module GHC.Core.TyCon(
isKindTyCon, isLiftedTypeKindTyConName,
isTauTyCon, isFamFreeTyCon, isForgetfulSynTyCon,
- isDataTyCon, isProductTyCon, isDataProductTyCon_maybe,
- isDataSumTyCon_maybe,
+ isDataTyCon,
isEnumerationTyCon,
isNewTyCon, isAbstractTyCon,
isFamilyTyCon, isOpenFamilyTyCon,
@@ -84,6 +83,7 @@ module GHC.Core.TyCon(
tyConCType, tyConCType_maybe,
tyConDataCons, tyConDataCons_maybe,
tyConSingleDataCon_maybe, tyConSingleDataCon,
+ tyConAlgDataCons_maybe,
tyConSingleAlgDataCon_maybe,
tyConFamilySize,
tyConStupidTheta,
@@ -143,7 +143,7 @@ import {-# SOURCE #-} GHC.Builtin.Types
, multiplicityTyCon
, vecCountTyCon, vecElemTyCon, liftedTypeKind )
import {-# SOURCE #-} GHC.Core.DataCon
- ( DataCon, dataConExTyCoVars, dataConFieldLabels
+ ( DataCon, dataConFieldLabels
, dataConTyCon, dataConFullSig
, isUnboxedSumDataCon )
import GHC.Builtin.Uniques
@@ -1976,72 +1976,6 @@ unwrapNewTyConEtad_maybe (AlgTyCon { algTcRhs = NewTyCon { nt_co = co,
= Just (tvs, rhs, co)
unwrapNewTyConEtad_maybe _ = Nothing
-isProductTyCon :: TyCon -> Bool
--- True of datatypes or newtypes that have
--- one, non-existential, data constructor
--- See Note [Product types]
-isProductTyCon tc@(AlgTyCon {})
- = case algTcRhs tc of
- TupleTyCon {} -> True
- DataTyCon{ data_cons = [data_con] }
- -> null (dataConExTyCoVars data_con)
- NewTyCon {} -> True
- _ -> False
-isProductTyCon _ = False
-
-isDataProductTyCon_maybe :: TyCon -> Maybe DataCon
--- True of datatypes (not newtypes) with
--- one, vanilla, data constructor
--- See Note [Product types]
-isDataProductTyCon_maybe (AlgTyCon { algTcRhs = rhs })
- = case rhs of
- DataTyCon { data_cons = [con] }
- | null (dataConExTyCoVars con) -- non-existential
- -> Just con
- TupleTyCon { data_con = con }
- -> Just con
- _ -> Nothing
-isDataProductTyCon_maybe _ = Nothing
-
-isDataSumTyCon_maybe :: TyCon -> Maybe [DataCon]
-isDataSumTyCon_maybe (AlgTyCon { algTcRhs = rhs })
- = case rhs of
- DataTyCon { data_cons = cons }
- | cons `lengthExceeds` 1
- , all (null . dataConExTyCoVars) cons -- FIXME(osa): Why do we need this?
- -> Just cons
- SumTyCon { data_cons = cons }
- | all (null . dataConExTyCoVars) cons -- FIXME(osa): Why do we need this?
- -> Just cons
- _ -> Nothing
-isDataSumTyCon_maybe _ = Nothing
-
-{- Note [Product types]
-~~~~~~~~~~~~~~~~~~~~~~~
-A product type is
- * A data type (not a newtype)
- * With one, boxed data constructor
- * That binds no existential type variables
-
-The main point is that product types are amenable to unboxing for
- * Strict function calls; we can transform
- f (D a b) = e
- to
- fw a b = e
- via the worker/wrapper transformation. (Question: couldn't this
- work for existentials too?)
-
- * CPR for function results; we can transform
- f x y = let ... in D a b
- to
- fw x y = let ... in (# a, b #)
-
-Note that the data constructor /can/ have evidence arguments: equality
-constraints, type classes etc. So it can be GADT. These evidence
-arguments are simply value arguments, and should not get in the way.
--}
-
-
-- | Is this a 'TyCon' representing a regular H98 type synonym (@type@)?
{-# INLINE isTypeSynonymTyCon #-} -- See Note [Inlining coreView] in GHC.Core.Type
isTypeSynonymTyCon :: TyCon -> Bool
@@ -2382,8 +2316,7 @@ tyConDataCons_maybe _ = Nothing
-- | If the given 'TyCon' has a /single/ data constructor, i.e. it is a @data@
-- type with one alternative, a tuple type or a @newtype@ then that constructor
-- is returned. If the 'TyCon' has more than one constructor, or represents a
--- primitive or function type constructor then @Nothing@ is returned. In any
--- other case, the function panics
+-- primitive or function type constructor then @Nothing@ is returned.
tyConSingleDataCon_maybe :: TyCon -> Maybe DataCon
tyConSingleDataCon_maybe (AlgTyCon { algTcRhs = rhs })
= case rhs of
@@ -2393,21 +2326,29 @@ tyConSingleDataCon_maybe (AlgTyCon { algTcRhs = rhs })
_ -> Nothing
tyConSingleDataCon_maybe _ = Nothing
+-- | Like 'tyConSingleDataCon_maybe', but panics if 'Nothing'.
tyConSingleDataCon :: TyCon -> DataCon
tyConSingleDataCon tc
= case tyConSingleDataCon_maybe tc of
Just c -> c
Nothing -> pprPanic "tyConDataCon" (ppr tc)
+-- | Like 'tyConSingleDataCon_maybe', but returns 'Nothing' for newtypes.
tyConSingleAlgDataCon_maybe :: TyCon -> Maybe DataCon
--- Returns (Just con) for single-constructor
--- *algebraic* data types *not* newtypes
-tyConSingleAlgDataCon_maybe (AlgTyCon { algTcRhs = rhs })
- = case rhs of
- DataTyCon { data_cons = [c] } -> Just c
- TupleTyCon { data_con = c } -> Just c
- _ -> Nothing
-tyConSingleAlgDataCon_maybe _ = Nothing
+tyConSingleAlgDataCon_maybe tycon
+ | isNewTyCon tycon = Nothing
+ | otherwise = tyConSingleDataCon_maybe tycon
+
+-- | Returns @Just dcs@ if the given 'TyCon' is a @data@ type, a tuple type
+-- or a sum type with data constructors dcs. If the 'TyCon' has more than one
+-- constructor, or represents a primitive or function type constructor then
+-- @Nothing@ is returned.
+--
+-- Like 'tyConDataCons_maybe', but returns 'Nothing' for newtypes.
+tyConAlgDataCons_maybe :: TyCon -> Maybe [DataCon]
+tyConAlgDataCons_maybe tycon
+ | isNewTyCon tycon = Nothing
+ | otherwise = tyConDataCons_maybe tycon
-- | Determine the number of value constructors a 'TyCon' has. Panics if the
-- 'TyCon' is not algebraic or a tuple