summaryrefslogtreecommitdiff
path: root/compiler/GHC/Tc/Deriv/Utils.hs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/GHC/Tc/Deriv/Utils.hs')
-rw-r--r--compiler/GHC/Tc/Deriv/Utils.hs178
1 files changed, 110 insertions, 68 deletions
diff --git a/compiler/GHC/Tc/Deriv/Utils.hs b/compiler/GHC/Tc/Deriv/Utils.hs
index 8a5b376767..5fe1f6b185 100644
--- a/compiler/GHC/Tc/Deriv/Utils.hs
+++ b/compiler/GHC/Tc/Deriv/Utils.hs
@@ -10,10 +10,10 @@
-- | Error-checking and other utilities for @deriving@ clauses or declarations.
module GHC.Tc.Deriv.Utils (
DerivM, DerivEnv(..),
- DerivSpec(..), pprDerivSpec,
+ DerivSpec(..), pprDerivSpec, setDerivSpecTheta,
DerivSpecMechanism(..), derivSpecMechanismToStrategy, isDerivSpecStock,
isDerivSpecNewtype, isDerivSpecAnyClass, isDerivSpecVia,
- DerivContext(..), OriginativeDerivStatus(..),
+ DerivContext(..), OriginativeDerivStatus(..), StockGenFns(..),
isStandaloneDeriv, isStandaloneWildcardDeriv, mkDerivOrigin,
PredOrigin(..), ThetaOrigin(..), mkPredOrigin,
mkThetaOrigin, mkThetaOriginFromPreds, substPredOrigin,
@@ -28,6 +28,7 @@ import GHC.Data.Bag
import GHC.Types.Basic
import GHC.Core.Class
import GHC.Core.DataCon
+import GHC.Core.FamInstEnv
import GHC.Driver.Session
import GHC.Utils.Error
import GHC.Types.Fixity.Env (lookupFixity)
@@ -179,6 +180,10 @@ pprDerivSpec (DS { ds_loc = l, ds_name = n, ds_tvs = tvs, ds_cls = c,
instance Outputable theta => Outputable (DerivSpec theta) where
ppr = pprDerivSpec
+-- | Set the 'ds_theta' in a 'DerivSpec'.
+setDerivSpecTheta :: theta' -> DerivSpec theta -> DerivSpec theta'
+setDerivSpecTheta theta ds = ds{ds_theta = theta}
+
-- | What action to take in order to derive a class instance.
-- See @Note [DerivEnv and DerivSpecMechanism]@, as well as
-- @Note [Deriving strategies]@ in "GHC.Tc.Deriv".
@@ -189,28 +194,9 @@ data DerivSpecMechanism
-- ^ Information about the arguments to the class in the derived
-- instance, including what type constructor the last argument is
-- headed by. See @Note [DerivEnv and DerivSpecMechanism]@.
- , dsm_stock_gen_fn ::
- SrcSpan -> [Type] -- inst_tys
- -> DerivInstTys -- dsm_stock_dit
- -> TcM (LHsBinds GhcPs, [LSig GhcPs], BagDerivStuff, [Name])
- -- ^ This function returns four things:
- --
- -- 1. @LHsBinds GhcPs@: The derived instance's function bindings
- -- (e.g., @compare (T x) (T y) = compare x y@)
- --
- -- 2. @[LSig GhcPs]@: A list of instance specific signatures/pragmas.
- -- Most likely INLINE pragmas for class methods.
- --
- -- 3. @BagDerivStuff@: Auxiliary bindings needed to support the derived
- -- instance. As examples, derived 'Generic' instances require
- -- associated type family instances, and derived 'Eq' and 'Ord'
- -- instances require top-level @con2tag@ functions.
- -- See @Note [Auxiliary binders]@ in "GHC.Tc.Deriv.Generate".
- --
- -- 4. @[Name]@: A list of Names for which @-Wunused-binds@ should be
- -- suppressed. This is used to suppress unused warnings for record
- -- selectors when deriving 'Read', 'Show', or 'Generic'.
- -- See @Note [Deriving and unused record selectors]@.
+ , dsm_stock_gen_fns :: StockGenFns
+ -- ^ How to generate the instance bindings and associated type family
+ -- instances.
}
-- | @GeneralizedNewtypeDeriving@
@@ -401,13 +387,61 @@ instance Outputable DerivContext where
--
-- See @Note [Deriving strategies]@ in "GHC.Tc.Deriv".
data OriginativeDerivStatus
- = CanDeriveStock -- Stock class, can derive
- (SrcSpan -> [Type] -> DerivInstTys
- -> TcM (LHsBinds GhcPs, [LSig GhcPs], BagDerivStuff, [Name]))
+ = CanDeriveStock StockGenFns -- Stock class, can derive
| StockClassError !DeriveInstanceErrReason -- Stock class, but can't do it
| CanDeriveAnyClass -- See Note [Deriving any class]
| NonDerivableClass -- Cannot derive with either stock or anyclass
+-- | Describes how to generate instance bindings ('stock_gen_binds') and
+-- associated type family instances ('stock_gen_fam_insts') for a particular
+-- stock-derived instance.
+data StockGenFns = StockGenFns
+ { stock_gen_binds ::
+ SrcSpan -> DerivInstTys
+ -> TcM (LHsBinds GhcPs, [LSig GhcPs], Bag AuxBindSpec, [Name])
+ -- ^ Describes how to generate instance bindings for a stock-derived
+ -- instance.
+ --
+ -- This function takes two arguments:
+ --
+ -- 1. 'SrcSpan': the source location where the instance is being derived.
+ -- This will eventually be instantiated with the 'ds_loc' field of a
+ -- 'DerivSpec'.
+ --
+ -- 2. 'DerivInstTys': information about the argument types to which a
+ -- class is applied in a derived instance. This will eventually be
+ -- instantiated with the 'dsm_stock_dit' field of a
+ -- 'DerivSpecMechanism'.
+ --
+ -- This function returns four things:
+ --
+ -- 1. @'LHsBinds' 'GhcPs'@: The derived instance's function bindings
+ -- (e.g., @compare (T x) (T y) = compare x y@)
+ --
+ -- 2. @['LSig' 'GhcPs']@: A list of instance specific signatures/pragmas.
+ -- Most likely @INLINE@ pragmas for class methods.
+ --
+ -- 3. @'Bag' 'AuxBindSpec'@: Auxiliary bindings needed to support the
+ -- derived instance. As examples, derived 'Eq' and 'Ord' instances
+ -- sometimes require top-level @con2tag@ functions.
+ -- See @Note [Auxiliary binders]@ in "GHC.Tc.Deriv.Generate".
+ --
+ -- 4. @['Name']@: A list of Names for which @-Wunused-binds@ should be
+ -- suppressed. This is used to suppress unused warnings for record
+ -- selectors when deriving 'Read', 'Show', or 'Generic'.
+ -- See @Note [Deriving and unused record selectors]@.
+ , stock_gen_fam_insts ::
+ SrcSpan -> DerivInstTys
+ -> TcM [FamInst]
+ -- ^ Describes how to generate associated type family instances for a
+ -- stock-derived instance. This function takes the same arguments as the
+ -- 'stock_gen_binds' function but returns a list of 'FamInst's instead.
+ -- Generating type family instances is done separately from
+ -- 'stock_gen_binds' since the type family instances must be generated
+ -- before the instance bindings can be typechecked. See
+ -- @Note [Staging of tcDeriving]@ in "GHC.Tc.Deriv".
+ }
+
-- A stock class is one either defined in the Haskell report or for which GHC
-- otherwise knows how to generate code for (possibly requiring the use of a
-- language extension), such as Eq, Ord, Ix, Data, Generic, etc.)
@@ -542,58 +576,65 @@ is willing to support it.
-}
hasStockDeriving
- :: Class -> Maybe (SrcSpan
- -> [Type]
- -> DerivInstTys
- -> TcM (LHsBinds GhcPs, [LSig GhcPs], BagDerivStuff, [Name]))
+ :: Class -> Maybe StockGenFns
hasStockDeriving clas
= assocMaybe gen_list (getUnique clas)
where
- gen_list
- :: [(Unique, SrcSpan
- -> [Type]
- -> DerivInstTys
- -> TcM (LHsBinds GhcPs, [LSig GhcPs], BagDerivStuff, [Name]))]
- gen_list = [ (eqClassKey, simpleM gen_Eq_binds)
- , (ordClassKey, simpleM gen_Ord_binds)
- , (enumClassKey, simpleM gen_Enum_binds)
- , (boundedClassKey, simple gen_Bounded_binds)
- , (ixClassKey, simpleM gen_Ix_binds)
- , (showClassKey, read_or_show gen_Show_binds)
- , (readClassKey, read_or_show gen_Read_binds)
- , (dataClassKey, simpleM gen_Data_binds)
- , (functorClassKey, simple gen_Functor_binds)
- , (foldableClassKey, simple gen_Foldable_binds)
- , (traversableClassKey, simple gen_Traversable_binds)
- , (liftClassKey, simple gen_Lift_binds)
- , (genClassKey, generic (gen_Generic_binds Gen0))
- , (gen1ClassKey, generic (gen_Generic_binds Gen1)) ]
-
- simple gen_fn loc _ dit
- = let (binds, deriv_stuff) = gen_fn loc dit
- in return (binds, [], deriv_stuff, [])
+ gen_list :: [(Unique, StockGenFns)]
+ gen_list =
+ [ (eqClassKey, mk (simple_bindsM gen_Eq_binds) no_fam_insts)
+ , (ordClassKey, mk (simple_bindsM gen_Ord_binds) no_fam_insts)
+ , (enumClassKey, mk (simple_bindsM gen_Enum_binds) no_fam_insts)
+ , (boundedClassKey, mk (simple_binds gen_Bounded_binds) no_fam_insts)
+ , (ixClassKey, mk (simple_bindsM gen_Ix_binds) no_fam_insts)
+ , (showClassKey, mk (read_or_show_binds gen_Show_binds) no_fam_insts)
+ , (readClassKey, mk (read_or_show_binds gen_Read_binds) no_fam_insts)
+ , (dataClassKey, mk (simple_bindsM gen_Data_binds) no_fam_insts)
+ , (functorClassKey, mk (simple_binds gen_Functor_binds) no_fam_insts)
+ , (foldableClassKey, mk (simple_binds gen_Foldable_binds) no_fam_insts)
+ , (traversableClassKey, mk (simple_binds gen_Traversable_binds) no_fam_insts)
+ , (liftClassKey, mk (simple_binds gen_Lift_binds) no_fam_insts)
+ , (genClassKey, mk (generic_binds Gen0) (generic_fam_inst Gen0))
+ , (gen1ClassKey, mk (generic_binds Gen1) (generic_fam_inst Gen1))
+ ]
+
+ mk gen_binds_fn gen_fam_insts_fn = StockGenFns
+ { stock_gen_binds = gen_binds_fn
+ , stock_gen_fam_insts = gen_fam_insts_fn
+ }
+
+ simple_binds gen_fn loc dit
+ = let (binds, aux_specs) = gen_fn loc dit
+ in return (binds, [], aux_specs, [])
-- Like `simple`, but monadic. The only monadic thing that these functions
-- do is allocate new Uniques, which are used for generating the names of
-- auxiliary bindings.
-- See Note [Auxiliary binders] in GHC.Tc.Deriv.Generate.
- simpleM gen_fn loc _ dit
- = do { (binds, deriv_stuff) <- gen_fn loc dit
- ; return (binds, [], deriv_stuff, []) }
+ simple_bindsM gen_fn loc dit
+ = do { (binds, aux_specs) <- gen_fn loc dit
+ ; return (binds, [], aux_specs, []) }
- read_or_show gen_fn loc _ dit
+ read_or_show_binds gen_fn loc dit
= do { let tc = dit_rep_tc dit
; fix_env <- getDataConFixityFun tc
- ; let (binds, deriv_stuff) = gen_fn fix_env loc dit
- field_names = all_field_names tc
- ; return (binds, [], deriv_stuff, field_names) }
+ ; let (binds, aux_specs) = gen_fn fix_env loc dit
+ field_names = all_field_names tc
+ ; return (binds, [], aux_specs, field_names) }
- generic gen_fn _ inst_tys dit
+ generic_binds gk loc dit
= do { let tc = dit_rep_tc dit
- ; fix_env <- getDataConFixityFun tc
- ; (binds, sigs, faminst) <- gen_fn fix_env inst_tys dit
+ ; (binds, sigs) <- gen_Generic_binds gk loc dit
; let field_names = all_field_names tc
- ; return (binds, sigs, unitBag (DerivFamInst faminst), field_names) }
+ ; return (binds, sigs, emptyBag, field_names) }
+
+ generic_fam_inst gk loc dit
+ = do { let tc = dit_rep_tc dit
+ ; fix_env <- getDataConFixityFun tc
+ ; faminst <- gen_Generic_fam_inst gk fix_env loc dit
+ ; return [faminst] }
+
+ no_fam_insts _ _ = pure []
-- See Note [Deriving and unused record selectors]
all_field_names = map flSelector . concatMap dataConFieldLabels
@@ -983,9 +1024,10 @@ non_coercible_class cls
------------------------------------------------------------------
-newDerivClsInst :: ThetaType -> DerivSpec theta -> TcM ClsInst
-newDerivClsInst theta (DS { ds_name = dfun_name, ds_overlap = overlap_mode
- , ds_tvs = tvs, ds_cls = clas, ds_tys = tys })
+newDerivClsInst :: DerivSpec ThetaType -> TcM ClsInst
+newDerivClsInst (DS { ds_name = dfun_name, ds_overlap = overlap_mode
+ , ds_tvs = tvs, ds_theta = theta
+ , ds_cls = clas, ds_tys = tys })
= newClsInst overlap_mode dfun_name tvs theta clas tys
extendLocalInstEnv :: [ClsInst] -> TcM a -> TcM a