th-desugar v1.12 Release Notes

    • ๐Ÿ‘Œ Support GHC 9.0.
    • โž• Add support for explicit specificity. As part of this change, the way th-desugar represents type variable binders has been overhauled:

      • The DTyVarBndr data type is now parameterized by a flag type parameter:
      data DTyVarBndr flag
        = DPlainTV Name flag
        | DKindedTV Name flag DKind

      This can be instantiated to Specificity (for type variable binders that can be specified or inferred) or () (for type variable binders where specificity is irrelevant). DTyVarBndrSpec and DTyVarBndrUnit are also provided as type synonyms for DTyVarBndr Specificity and DTyVarBndr (), respectively.

      • In order to interface with TyVarBndr (the TH counterpart to DTyVarBndr) in a backwards-compatible way, th-desugar now depends on the th-abstraction library.
      • The ForallVisFlag has been removed in favor of the new DForallTelescope data type, which not only distinguishes between invisible and visible foralls but also uses the correct type variable flag for invisible type variables (Specificity) and visible type variables (()).
      • The type of the dsTvb is now different on pre-9.0 versions of GHC:
      #if __GLASGOW_HASKELL__ >= 900
      dsTvb :: DsMonad q => TyVarBndr flag -> q (DTyVarBndr flag)
      dsTvb :: DsMonad q => flag -> TyVarBndr -> q (DTyVarBndr flag)

      This is unfortunately required by the fact that prior to GHC 9.0, there is no flag information stored anywhere in a TyVarBndr. If you need to use dsTvb in a backward-compatible way, L.H.TH.Desugar now provides dsTvbSpec and dsTvbUnit functions which specialise dsTvb to particular flag types:

      dsTvbSpec :: DsMonad q => TyVarBndrSpec -> q DTyVarBndrSpec
      dsTvbUnit :: DsMonad q => TyVarBndrUnit -> q DTyVarBndrUnit
    • The type of the getRecordSelectors function has changed:

      -getRecordSelectors :: DsMonad q => DType -> [DCon] -> q [DLetDec]
      +getRecordSelectors :: DsMonad q =>          [DCon] -> q [DLetDec]

    The old type signature had a DType argument whose sole purpose was to help determine which type variables were existential, as this information was used to filter out "naughty" record selectors, like the example below:

      data Some :: (Type -> Type) -> Type where
        MkSome :: { getSome :: f a } -> Some f

    The old implementation of getRecordSelectors would not include getSome in the returned list, as its type f a mentions an existential type variable, a, that is not mentioned in the return type Some f. The new implementation of getRecordSelectors, on the other hand, makes no attempt to filter out naughty record selectors, so it would include getSome.

    This reason for this change is ultimately because determining which type variables are existentially quantified in the context of Template Haskell is rather challenging in the general case. There are heuristics we could employ to guess which variables are existential, but we have found these heuristics difficult to predict (let alone specify). As a result, we take the slightly less correct (but much easier to explain) approach of returning all record selectors, regardless of whether they are naughty or not.

    • ๐Ÿšš The conExistentialTvbs function has been removed. It was horribly buggy, especially in the presence of GADT constructors. Moreover, this function was used in the implementation of getRecordSelectors function, so bugs in conExistentialTvbs often affected the results of getRecordSelectors.
    • The types of decToTH, letDecToTH, and pragmaToTH have changed:
      -decToTH :: DDec -> [Dec]
      +decToTH :: DDec -> Dec
      -letDecToTH :: DLetDec -> Maybe Dec
      +letDecToTH :: DLetDec -> Dec
      -pragmaToTH :: DPragma -> Maybe Pragma
      +pragmaToTH :: DPragma -> Pragma

    The semantics of pragmaToTH have changed accordingly. Previously, pragmaToTH would return Nothing when the argument is a DPragma that is not supported on an old version of GHC, but now an error will be thrown instead. decToTH and letDecToTH, which transitively invoke pragmaToTH, have had their types updated to accommodate pragmaToTH's type change.

    • The type of the substTyVarBndrs function has been simplified to avoid the needless use of continuation-passing style:
      -substTyVarBndrs :: Quasi q => DSubst -> [DTyVarBndr flag] -> (DSubst -> [DTyVarBndr flag] -> q a) -> q a
      +substTyVarBndrs :: Quasi q => DSubst -> [DTyVarBndr flag] -> q (DSubst, [DTyVarBndr flag])