GHC.Tc.Deriv.Utils

ghc-9.14.0.20251028: The GHC API

Safe Haskell | None
Language | GHC2021

GHC.Tc.Deriv.Utils

Description

Error-checking and other utilities for `deriving` clauses or declarations.

Synopsis

- type DerivM = ReaderT DerivEnv TcRn
- data DerivEnv = DerivEnv {
  - denv_overlap_mode :: Maybe OverlapMode
  - denv_tvs :: [TyVar]
  - denv_cls :: Class
  - denv_inst_tys :: [Type]
  - denv_ctxt :: DerivContext
  - denv_skol_info :: SkolemInfo
  - denv_strat :: Maybe (DerivStrategy GhcTc)
  - denv_warn :: Maybe (WarningTxt GhcRn)
  }
- data DerivSpec theta = DS {
  - ds_loc :: SrcSpan
  - ds_name :: Name
  - ds_tvs :: [TyVar]
  - ds_theta :: theta
  - ds_cls :: Class
  - ds_tys :: [Type]
  - ds_skol_info :: SkolemInfo
  - ds_user_ctxt :: UserTypeCtxt
  - ds_overlap :: Maybe OverlapMode
  - ds_standalone_wildcard :: Maybe SrcSpan
  - ds_mechanism :: DerivSpecMechanism
  - ds_warn :: Maybe (WarningTxt GhcRn)
  }
- pprDerivSpec :: Outputable theta => DerivSpec theta -> SDoc
- setDerivSpecTheta :: theta' -> DerivSpec theta -> DerivSpec theta'
- zonkDerivSpec :: DerivSpec ThetaType -> ZonkTcM (DerivSpec ThetaType)
- data DerivSpecMechanism
  - = DerivSpecStock {
    - dsm_stock_dit :: DerivInstTys
    - dsm_stock_gen_fns :: StockGenFns
    }
  - | DerivSpecNewtype {
    - dsm_newtype_dit :: DerivInstTys
    - dsm_newtype_rep_ty :: Type
    }
  - | DerivSpecAnyClass
  - | DerivSpecVia {
    - dsm_via_cls_tys :: [Type]
    - dsm_via_inst_ty :: Type
    - dsm_via_ty :: Type
    }
- derivSpecMechanismToStrategy :: DerivSpecMechanism -> DerivStrategy GhcTc
- isDerivSpecStock :: DerivSpecMechanism -> Bool
- isDerivSpecNewtype :: DerivSpecMechanism -> Bool
- isDerivSpecAnyClass :: DerivSpecMechanism -> Bool
- isDerivSpecVia :: DerivSpecMechanism -> Bool
- zonkDerivSpecMechanism :: DerivSpecMechanism -> ZonkTcM DerivSpecMechanism
- data DerivContext
  - = InferContext (Maybe SrcSpan)
  - | SupplyContext ThetaType
- data OriginativeDerivStatus
  - = CanDeriveStock StockGenFns
  - | StockClassError !DeriveInstanceErrReason
  - | CanDeriveAnyClass
  - | NonDerivableClass
- data StockGenFns = StockGenFns {
  - stock_gen_binds :: SrcSpan -> DerivInstTys -> TcM (LHsBinds GhcPs, [LSig GhcPs], Bag AuxBindSpec, [Name])
  - stock_gen_fam_insts :: SrcSpan -> DerivInstTys -> TcM [FamInst]
  }
- isStandaloneDeriv :: DerivM Bool
- isStandaloneWildcardDeriv :: DerivContext -> Bool
- askDerivUserTypeCtxt :: DerivM UserTypeCtxt
- mkDerivOrigin :: Bool -> CtOrigin
- data PredSpec
  - = SimplePredSpec {
    - sps_pred :: TcPredType
    - sps_origin :: CtOrigin
    - sps_type_or_kind :: TypeOrKind
    }
  - | SubTypePredSpec {
    - stps_ty_actual :: TcSigmaType
    - stps_ty_expected :: TcSigmaType
    - stps_origin :: CtOrigin
    }
- type ThetaSpec = [PredSpec]
- mkDirectThetaSpec :: CtOrigin -> TypeOrKind -> ThetaType -> ThetaSpec
- substPredSpec :: HasDebugCallStack => Subst -> PredSpec -> PredSpec
- captureThetaSpecConstraints :: UserTypeCtxt -> ThetaSpec -> TcM (TcLevel, WantedConstraints)
- checkOriginativeSideConditions :: DerivInstTys -> DerivM OriginativeDerivStatus
- hasStockDeriving :: Class -> Maybe StockGenFns
- std_class_via_coercible :: Class -> Bool
- non_coercible_class :: Class -> Bool
- newDerivClsInst :: DerivSpec ThetaType -> TcM ClsInst
- extendLocalInstEnv :: [ClsInst] -> TcM a -> TcM a

# Documentation

type DerivM = ReaderT DerivEnv TcRn Source #

To avoid having to manually plumb everything in `DerivEnv` throughout various functions in GHC.Tc.Deriv and GHC.Tc.Deriv.Infer, we use `DerivM`, which is a simple reader around `TcRn`.

data DerivEnv Source #

Contains all of the information known about a derived instance when determining what its `EarlyDerivSpec` should be. See `Note [DerivEnv and DerivSpecMechanism]`.

Constructors

DerivEnv |
Fields denv_overlap_mode :: Maybe OverlapMode Is this an overlapping instance? denv_tvs :: [TyVar] Universally quantified type variables in the instance. If the `denv_ctxt` is `InferContext`, these will be `TcTyVar` skolems. If the `denv_ctxt` is `SupplyContext`, these will be ordinary `TyVar`s. See `Note [Overlap and deriving]` in GHC.Tc.Deriv.Infer. All type variables that appear in the `denv_inst_tys`, `denv_ctxt`, `denv_skol_info`, and `denv_strat` should come from `denv_tvs`. denv_cls :: Class Class for which we need to derive an instance denv_inst_tys :: [Type] All arguments to `denv_cls` in the derived instance. denv_ctxt :: DerivContext ``SupplyContext` theta` for standalone deriving (where `theta` is the context of the instance). `InferContext` for `deriving` clauses, or for standalone deriving that uses a wildcard constraint. See `Note [Inferring the instance context]`. denv_skol_info :: SkolemInfo The `SkolemInfo` used to skolemise the `denv_tvs` in the case where the `denv_ctxt` is `InferContext`. denv_strat :: Maybe (DerivStrategy GhcTc) `Just` if user requests a particular deriving strategy. Otherwise, `Nothing`. denv_warn :: Maybe (WarningTxt GhcRn) A warning to emit whenever the derived instance is used

#### Instances

Instances details

Outputable DerivEnv Source # |
Instance details Defined in GHC.Tc.Deriv.Utils Methods ppr :: DerivEnv -> SDoc Source #

data DerivSpec theta Source #

Constructors

DS |
Fields ds_loc :: SrcSpan ds_name :: Name ds_tvs :: [TyVar] ds_theta :: theta ds_cls :: Class ds_tys :: [Type] ds_skol_info :: SkolemInfo ds_user_ctxt :: UserTypeCtxt ds_overlap :: Maybe OverlapMode ds_standalone_wildcard :: Maybe SrcSpan ds_mechanism :: DerivSpecMechanism ds_warn :: Maybe (WarningTxt GhcRn)

#### Instances

Instances details

Outputable theta => Outputable (DerivSpec theta) Source # |
Instance details Defined in GHC.Tc.Deriv.Utils Methods ppr :: DerivSpec theta -> SDoc Source #

pprDerivSpec :: Outputable theta => DerivSpec theta -> SDoc Source #

setDerivSpecTheta :: theta' -> DerivSpec theta -> DerivSpec theta' Source #

Set the `ds_theta` in a `DerivSpec`.

zonkDerivSpec :: DerivSpec ThetaType -> ZonkTcM (DerivSpec ThetaType) Source #

Zonk the `TcTyVar`s in a `DerivSpec` to `TyVar`s. See `Note [What is zonking?]` in GHC.Tc.Zonk.Type.

This is only used in the final zonking step when inferring the context for a derived instance. See `Note [Overlap and deriving]` in GHC.Tc.Deriv.Infer.

data DerivSpecMechanism Source #

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.

Constructors

DerivSpecStock | "Standard" classes
Fields dsm_stock_dit :: DerivInstTys 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_fns :: StockGenFns How to generate the instance bindings and associated type family instances.
DerivSpecNewtype |
    GeneralizedNewtypeDeriving
Fields dsm_newtype_dit :: DerivInstTys 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_newtype_rep_ty :: Type The newtype rep type.
DerivSpecAnyClass |
    DeriveAnyClass
DerivSpecVia |
    DerivingVia
Fields dsm_via_cls_tys :: [Type] All arguments to the class besides the last one. dsm_via_inst_ty :: Type The last argument to the class. dsm_via_ty :: Type The `via` type

#### Instances

Instances details

Outputable DerivSpecMechanism Source # |
Instance details Defined in GHC.Tc.Deriv.Utils Methods ppr :: DerivSpecMechanism -> SDoc Source #

derivSpecMechanismToStrategy :: DerivSpecMechanism -> DerivStrategy GhcTc Source #

Convert a `DerivSpecMechanism` to its corresponding `DerivStrategy`.

isDerivSpecStock :: DerivSpecMechanism -> Bool Source #

isDerivSpecNewtype :: DerivSpecMechanism -> Bool Source #

isDerivSpecAnyClass :: DerivSpecMechanism -> Bool Source #

isDerivSpecVia :: DerivSpecMechanism -> Bool Source #

zonkDerivSpecMechanism :: DerivSpecMechanism -> ZonkTcM DerivSpecMechanism Source #

Zonk the `TcTyVar`s in a `DerivSpecMechanism` to `TyVar`s. See `Note [What is zonking?]` in GHC.Tc.Zonk.Type.

This is only used in the final zonking step when inferring the context for a derived instance. See `Note [Overlap and deriving]` in GHC.Tc.Deriv.Infer.

data DerivContext Source #

Whether GHC is processing a `deriving` clause or a standalone deriving declaration.

Constructors

InferContext (Maybe SrcSpan) | `'InferContext mb_wildcard` is either: A `deriving` clause (in which case `mb_wildcard` is `Nothing`). A standalone deriving declaration with an extra-constraints wildcard as the context (in which case `mb_wildcard` is ``Just` loc`, where `loc` is the location of the wildcard. GHC should infer the context.
SupplyContext ThetaType | ``SupplyContext` theta` is a standalone deriving declaration, where `theta` is the context supplied by the user.

#### Instances

Instances details

Outputable DerivContext Source # |
Instance details Defined in GHC.Tc.Deriv.Utils Methods ppr :: DerivContext -> SDoc Source #

data OriginativeDerivStatus Source #

Records whether a particular class can be derived by way of an originative deriving strategy (i.e., `stock` or `anyclass`).

See `Note [Deriving strategies]` in GHC.Tc.Deriv.

Constructors

CanDeriveStock StockGenFns |
StockClassError !DeriveInstanceErrReason |
CanDeriveAnyClass |
NonDerivableClass |

data StockGenFns Source #

Describes how to generate instance bindings (`stock_gen_binds`) and associated type family instances (`stock_gen_fam_insts`) for a particular stock-derived instance.

Constructors

StockGenFns |
Fields 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: `SrcSpan`: the source location where the instance is being derived. This will eventually be instantiated with the `ds_loc` field of a `DerivSpec`. `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: ``LHsBinds` `GhcPs``: The derived instance's function bindings (e.g., `compare (T x) (T y) = compare x y`) `[`LSig` `GhcPs`]`: A list of instance specific signatures/pragmas. Most likely `INLINE` pragmas for class methods. ``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. `[`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.

isStandaloneDeriv :: DerivM Bool Source #

Is GHC processing a standalone deriving declaration?

isStandaloneWildcardDeriv :: DerivContext -> Bool Source #

Is GHC processing a standalone deriving declaration with an extra-constraints wildcard as the context? (e.g., `deriving instance _ => Eq (Foo a)`)

askDerivUserTypeCtxt :: DerivM UserTypeCtxt Source #

Return `InstDeclCtxt` if processing with a standalone `deriving` declaration or `DerivClauseCtxt` if processing a `deriving` clause.

mkDerivOrigin :: Bool -> CtOrigin Source #

data PredSpec Source #

A `PredSpec` specifies a constraint to emitted when inferring the instance context for a derived instance in `simplifyInfer`.

Constructors

SimplePredSpec | An ordinary `PredSpec` that directly stores a `PredType`, which will be emitted as a wanted constraint in the constraint solving machinery. This is the simple case, as there are no skolems, metavariables, or given constraints involved.
Fields sps_pred :: TcPredType The constraint to emit as a wanted Usually just a simple predicate like (Eq a) or (ki ~# Type), but can be a forall-constraint: * in the case of GHC.Tc.Deriv.Infer.inferConstraintsCoerceBased * if a class has quantified-constraint superclasses, via `mkDirectThetaSpec` in `inferConstraints` sps_origin :: CtOrigin The origin of the constraint sps_type_or_kind :: TypeOrKind Whether the constraint is a type or kind
SubTypePredSpec | A special `PredSpec` that is only used by `DeriveAnyClass`. This will check if `stps_ty_actual` is a subtype of (i.e., more polymorphic than) `stps_ty_expected` in the constraint solving machinery, emitting an implication constraint as a side effect. For more details on how this works, see `Note [Gathering and simplifying constraints for DeriveAnyClass]` in GHC.Tc.Deriv.Infer.
Fields stps_ty_actual :: TcSigmaType The actual type. In the context of `DeriveAnyClass`, this is the default method type signature. stps_ty_expected :: TcSigmaType The expected type. In the context of `DeriveAnyClass`, this is the original method type signature. stps_origin :: CtOrigin The origin of the constraint

#### Instances

Instances details

Outputable PredSpec Source # |
Instance details Defined in GHC.Tc.Deriv.Utils Methods ppr :: PredSpec -> SDoc Source #

type ThetaSpec = [PredSpec] Source #

A list of `PredSpec` constraints to simplify when inferring a derived instance's context. For the `stock`, `newtype`, and `via` deriving strategies, these will consist of `SimplePredSpec`s, and for `DeriveAnyClass`, these will consist of `SubTypePredSpec`s. Here is an example to illustrate the latter:

    class Foo a where
      bar :: forall b. Ix b => a -> b -> String
      default bar :: forall y. (Show a, Ix y) => a -> y -> String
      bar x y = show x ++ show (range (y, y))

      baz :: Eq a => a -> a -> Bool
      default baz :: Ord a => a -> a -> Bool
      baz x y = compare x y == EQ

    data Quux q = Quux deriving anyclass Foo

Then it would generate two `SubTypePredSpec`s, one for each method:

    [ SubTypePredSpec
        { stps_ty_actual   = forall y. (Show (Quux q), Ix y) => Quux q -> y -> String
        , stps_ty_expected = forall b.                (Ix b) => Quux q -> b -> String
        , stps_ty_origin   = DerivClauseCtxt
        }
    , SubTypePredSpec
        { stps_ty_actual   = Ord (Quux q) => Quux q -> Quux q -> Bool
        , stps_ty_expected = Eq  (Quux q) => Quux q -> Quux q -> Bool
        , stps_ty_origin   = DerivClauseCtxt
        }
    ]

(Note that the type variable `q` is bound by the data type `Quux`, and thus appears free in the `stps_ty_actual`s and `stps_ty_expected`s.)

See `Note [Gathering and simplifying constraints for DeriveAnyClass]` in GHC.Tc.Deriv.Infer for an explanation of how these `SubTypePredSpec`s are used to compute implication constraints.

mkDirectThetaSpec :: CtOrigin -> TypeOrKind -> ThetaType -> ThetaSpec Source #

Build a list of `SimplePredSpec`s, using the supplied `CtOrigin` and `TypeOrKind` values for each `PredType`.

substPredSpec :: HasDebugCallStack => Subst -> PredSpec -> PredSpec Source #

captureThetaSpecConstraints Source #

Arguments

:: UserTypeCtxt | Used to inform error messages as to whether we are in a `deriving` clause or a standalone `deriving` declaration
-> ThetaSpec | The specs from which constraints will be created
-> TcM (TcLevel, WantedConstraints) |

Capture wanted constraints from a `ThetaSpec`.

checkOriginativeSideConditions :: DerivInstTys -> DerivM OriginativeDerivStatus Source #

hasStockDeriving :: Class -> Maybe StockGenFns Source #

std_class_via_coercible :: Class -> Bool Source #

non_coercible_class :: Class -> Bool Source #

newDerivClsInst :: DerivSpec ThetaType -> TcM ClsInst Source #

extendLocalInstEnv :: [ClsInst] -> TcM a -> TcM a Source #