diff options
author | Simon Jakobi <simon.jakobi@gmail.com> | 2018-07-19 13:36:45 +0200 |
---|---|---|
committer | Alexander Biehl <alexbiehl@gmail.com> | 2018-07-19 13:36:45 +0200 |
commit | c3eb3f0581f69e816f9453b1747a9f2a3ba02bb9 (patch) | |
tree | b6fa12d003a70349acd90f974cbb4005a6749357 | |
parent | 657b1b3d519545f8d4ca048c06210d6cbf0f0da0 (diff) |
tyThingToLHsDecl: Preserve type synonyms that contain a forall (#880)
* tyThingToLHsDecls: Preserve type synonyms that contain a forall
Fixes #879.
* Add Note [Invariant: Never expand type synonyms]
* Clarify Note [Invariant: Never expand type synonyms]
-rw-r--r-- | haddock-api/src/Haddock/Convert.hs | 48 |
1 files changed, 46 insertions, 2 deletions
diff --git a/haddock-api/src/Haddock/Convert.hs b/haddock-api/src/Haddock/Convert.hs index 8b227c50..7595f798 100644 --- a/haddock-api/src/Haddock/Convert.hs +++ b/haddock-api/src/Haddock/Convert.hs @@ -31,7 +31,7 @@ import NameSet ( emptyNameSet ) import RdrName ( mkVarUnqual ) import PatSyn import SrcLoc ( Located, noLoc, unLoc, GenLocated(..), srcLocSpan ) -import TcType ( tcSplitSigmaTy ) +import TcType import TyCon import Type import TyCoRep @@ -515,7 +515,7 @@ synifyType _ (FunTy t1 t2) = let s2 = synifyType WithinType t2 in noLoc $ HsFunTy s1 s2 synifyType s forallty@(ForAllTy _tv _ty) = - let (tvs, ctx, tau) = tcSplitSigmaTy forallty + let (tvs, ctx, tau) = tcSplitSigmaTyPreserveSynonyms forallty sPhi = HsQualTy { hst_ctxt = synifyCtx ctx , hst_body = synifyType WithinType tau } in case s of @@ -610,3 +610,47 @@ synifyFamInst fi opaque = do ts' = synifyTypes ts annot_ts = zipWith3 annotHsType is_poly_tvs ts ts' is_poly_tvs = mkIsPolyTvs (tyConVisibleTyVars fam_tc) + +{- +Note [Invariant: Never expand type synonyms] + +In haddock, we never want to expand a type synonym that may be presented to the +user, as we want to keep the link to the abstraction captured in the synonym. + +All code in Haddock.Convert must make sure that this invariant holds. + +See https://github.com/haskell/haddock/issues/879 for a bug where this +invariant didn't hold. +-} + +-- | A version of 'TcType.tcSplitSigmaTy' that preserves type synonyms. +-- +-- See Note [Invariant: Never expand type synonyms] +tcSplitSigmaTyPreserveSynonyms :: Type -> ([TyVar], ThetaType, Type) +tcSplitSigmaTyPreserveSynonyms ty = + case tcSplitForAllTysPreserveSynonyms ty of + (tvs, rho) -> case tcSplitPhiTyPreserveSynonyms rho of + (theta, tau) -> (tvs, theta, tau) + +-- | See Note [Invariant: Never expand type synonyms] +tcSplitForAllTysPreserveSynonyms :: Type -> ([TyVar], Type) +tcSplitForAllTysPreserveSynonyms ty = split ty ty [] + where + split _ (ForAllTy (TvBndr tv _) ty') tvs = split ty' ty' (tv:tvs) + split orig_ty _ tvs = (reverse tvs, orig_ty) + +-- | See Note [Invariant: Never expand type synonyms] +tcSplitPhiTyPreserveSynonyms :: Type -> (ThetaType, Type) +tcSplitPhiTyPreserveSynonyms ty0 = split ty0 [] + where + split ty ts + = case tcSplitPredFunTyPreserveSynonyms_maybe ty of + Just (pred_, ty') -> split ty' (pred_:ts) + Nothing -> (reverse ts, ty) + +-- | See Note [Invariant: Never expand type synonyms] +tcSplitPredFunTyPreserveSynonyms_maybe :: Type -> Maybe (PredType, Type) +tcSplitPredFunTyPreserveSynonyms_maybe (FunTy arg res) + | isPredTy arg = Just (arg, res) +tcSplitPredFunTyPreserveSynonyms_maybe _ + = Nothing |