diff options
author | Richard Eisenberg <eir@cis.upenn.edu> | 2012-12-21 20:54:15 -0500 |
---|---|---|
committer | Richard Eisenberg <eir@cis.upenn.edu> | 2012-12-21 20:54:15 -0500 |
commit | 8366792eede3c8eb486ff15d8c8e62e9363f1959 (patch) | |
tree | b8ac6d4c9f13a3a8631dac12d3fe75b630f502d1 /compiler/deSugar | |
parent | d3e2912ac2048346828539e0dfef6c0cefef0d38 (diff) | |
download | haskell-8366792eede3c8eb486ff15d8c8e62e9363f1959.tar.gz |
Implement overlapping type family instances.
An ordered, overlapping type family instance is introduced by 'type
instance
where', followed by equations. See the new section in the user manual
(7.7.2.2) for details. The canonical example is Boolean equality at the
type
level:
type family Equals (a :: k) (b :: k) :: Bool
type instance where
Equals a a = True
Equals a b = False
A branched family instance, such as this one, checks its equations in
order
and applies only the first the matches. As explained in the note
[Instance
checking within groups] in FamInstEnv.lhs, we must be careful not to
simplify,
say, (Equals Int b) to False, because b might later unify with Int.
This commit includes all of the commits on the overlapping-tyfams
branch. SPJ
requested that I combine all my commits over the past several months
into one
monolithic commit. The following GHC repos are affected: ghc, testsuite,
utils/haddock, libraries/template-haskell, and libraries/dph.
Here are some details for the interested:
- The definition of CoAxiom has been moved from TyCon.lhs to a
new file CoAxiom.lhs. I made this decision because of the
number of definitions necessary to support BranchList.
- BranchList is a GADT whose type tracks whether it is a
singleton list or not-necessarily-a-singleton-list. The reason
I introduced this type is to increase static checking of places
where GHC code assumes that a FamInst or CoAxiom is indeed a
singleton. This assumption takes place roughly 10 times
throughout the code. I was worried that a future change to GHC
would invalidate the assumption, and GHC might subtly fail to
do the right thing. By explicitly labeling CoAxioms and
FamInsts as being Unbranched (singleton) or
Branched (not-necessarily-singleton), we make this assumption
explicit and checkable. Furthermore, to enforce the accuracy of
this label, the list of branches of a CoAxiom or FamInst is
stored using a BranchList, whose constructors constrain its
type index appropriately.
I think that the decision to use BranchList is probably the most
controversial decision I made from a code design point of view.
Although I provide conversions to/from ordinary lists, it is more
efficient to use the brList... functions provided in CoAxiom than
always to convert. The use of these functions does not wander far
from the core CoAxiom/FamInst logic.
BranchLists are motivated and explained in the note [Branched axioms] in
CoAxiom.lhs.
- The CoAxiom type has changed significantly. You can see the new
type in CoAxiom.lhs. It uses a CoAxBranch type to track
branches of the CoAxiom. Correspondingly various functions
producing and consuming CoAxioms had to change, including the
binary layout of interface files.
- To get branched axioms to work correctly, it is important to have a
notion
of type "apartness": two types are apart if they cannot unify, and no
substitution of variables can ever get them to unify, even after type
family
simplification. (This is different than the normal failure to unify
because
of the type family bit.) This notion in encoded in tcApartTys, in
Unify.lhs.
Because apartness is finer-grained than unification, the tcUnifyTys
now
calls tcApartTys.
- CoreLinting axioms has been updated, both to reflect the new
form of CoAxiom and to enforce the apartness rules of branch
application. The formalization of the new rules is in
docs/core-spec/core-spec.pdf.
- The FamInst type (in types/FamInstEnv.lhs) has changed
significantly, paralleling the changes to CoAxiom. Of course,
this forced minor changes in many files.
- There are several new Notes in FamInstEnv.lhs, including one
discussing confluent overlap and why we're not doing it.
- lookupFamInstEnv, lookupFamInstEnvConflicts, and
lookup_fam_inst_env' (the function that actually does the work)
have all been more-or-less completely rewritten. There is a
Note [lookup_fam_inst_env' implementation] describing the
implementation. One of the changes that affects other files is
to change the type of matches from a pair of (FamInst, [Type])
to a new datatype (which now includes the index of the matching
branch). This seemed a better design.
- The TySynInstD constructor in Template Haskell was updated to
use the new datatype TySynEqn. I also bumped the TH version
number, requiring changes to DPH cabal files. (That's why the
DPH repo has an overlapping-tyfams branch.)
- As SPJ requested, I refactored some of the code in HsDecls:
* splitting up TyDecl into SynDecl and DataDecl, correspondingly
changing HsTyDefn to HsDataDefn (with only one constructor)
* splitting FamInstD into TyFamInstD and DataFamInstD and
splitting FamInstDecl into DataFamInstDecl and TyFamInstDecl
* making the ClsInstD take a ClsInstDecl, for parallelism with
InstDecl's other constructors
* changing constructor TyFamily into FamDecl
* creating a FamilyDecl type that stores the details for a family
declaration; this is useful because FamilyDecls can appear in classes
but
other decls cannot
* restricting the associated types and associated type defaults for a
* class
to be the new, more restrictive types
* splitting cid_fam_insts into cid_tyfam_insts and cid_datafam_insts,
according to the new types
* perhaps one or two more that I'm overlooking
None of these changes has far-reaching implications.
- The user manual, section 7.7.2.2, is updated to describe the new type
family
instances.
Diffstat (limited to 'compiler/deSugar')
-rw-r--r-- | compiler/deSugar/DsBinds.lhs | 3 | ||||
-rw-r--r-- | compiler/deSugar/DsMeta.hs | 165 |
2 files changed, 112 insertions, 56 deletions
diff --git a/compiler/deSugar/DsBinds.lhs b/compiler/deSugar/DsBinds.lhs index 4b7f8c0dd4..78d8569091 100644 --- a/compiler/deSugar/DsBinds.lhs +++ b/compiler/deSugar/DsBinds.lhs @@ -830,7 +830,8 @@ ds_tc_coercion subst tc_co go (TcForAllCo tv co) = mkForAllCo tv' (ds_tc_coercion subst' co) where (subst', tv') = Coercion.substTyVarBndr subst tv - go (TcAxiomInstCo ax tys) = mkAxInstCo ax (map (Coercion.substTy subst) tys) + go (TcAxiomInstCo ax ind tys) + = mkAxInstCo ax ind (map (Coercion.substTy subst) tys) go (TcSymCo co) = mkSymCo (go co) go (TcTransCo co1 co2) = mkTransCo (go co1) (go co2) go (TcNthCo n co) = mkNthCo n (go co) diff --git a/compiler/deSugar/DsMeta.hs b/compiler/deSugar/DsMeta.hs index f25039c8a9..fcaff4bd9a 100644 --- a/compiler/deSugar/DsMeta.hs +++ b/compiler/deSugar/DsMeta.hs @@ -65,7 +65,6 @@ import Bag import DynFlags import FastString import ForeignCall -import MonadUtils import Util import Data.Maybe @@ -203,31 +202,21 @@ in repTyClD and repC. -- represent associated family instances -- -repTyClDs :: [LTyClDecl Name] -> DsM [Core TH.DecQ] -repTyClDs ds = liftM de_loc (mapMaybeM repTyClD ds) - - repTyClD :: LTyClDecl Name -> DsM (Maybe (SrcSpan, Core TH.DecQ)) -repTyClD (L loc (TyFamily { tcdFlavour = flavour, - tcdLName = tc, tcdTyVars = tvs, - tcdKindSig = opt_kind })) - = do { tc1 <- lookupLOcc tc -- See note [Binders and occurrences] - ; dec <- addTyClTyVarBinds tvs $ \bndrs -> - do { flav <- repFamilyFlavour flavour - ; case opt_kind of - Nothing -> repFamilyNoKind flav tc1 bndrs - Just ki -> do { ki1 <- repLKind ki - ; repFamilyKind flav tc1 bndrs ki1 } - } - ; return $ Just (loc, dec) - } +repTyClD (L loc (FamDecl { tcdFam = fam })) = liftM Just $ repFamilyDecl (L loc fam) + +repTyClD (L loc (SynDecl { tcdLName = tc, tcdTyVars = tvs, tcdRhs = rhs })) + = do { tc1 <- lookupLOcc tc -- See note [Binders and occurrences] + ; dec <- addTyClTyVarBinds tvs $ \bndrs -> + repSynDecl tc1 bndrs rhs + ; return (Just (loc, dec)) } -repTyClD (L loc (TyDecl { tcdLName = tc, tcdTyVars = tvs, tcdTyDefn = defn })) +repTyClD (L loc (DataDecl { tcdLName = tc, tcdTyVars = tvs, tcdDataDefn = defn })) = do { tc1 <- lookupLOcc tc -- See note [Binders and occurrences] ; tc_tvs <- mk_extra_tvs tc tvs defn ; dec <- addTyClTyVarBinds tc_tvs $ \bndrs -> - repTyDefn tc1 bndrs Nothing (hsLTyVarNames tc_tvs) defn + repDataDefn tc1 bndrs Nothing (hsLTyVarNames tc_tvs) defn ; return (Just (loc, dec)) } repTyClD (L loc (ClassDecl { tcdCtxt = cxt, tcdLName = cls, @@ -240,7 +229,7 @@ repTyClD (L loc (ClassDecl { tcdCtxt = cxt, tcdLName = cls, ; sigs1 <- rep_sigs sigs ; binds1 <- rep_binds meth_binds ; fds1 <- repLFunDeps fds - ; ats1 <- repTyClDs ats + ; ats1 <- repFamilyDecls ats ; decls1 <- coreList decQTyConName (ats1 ++ sigs1 ++ binds1) ; repClass cxt1 cls1 bndrs fds1 decls1 } @@ -253,13 +242,13 @@ repTyClD (L loc d) = putSrcSpanDs loc $ ; return Nothing } ------------------------- -repTyDefn :: Core TH.Name -> Core [TH.TyVarBndr] - -> Maybe (Core [TH.TypeQ]) - -> [Name] -> HsTyDefn Name - -> DsM (Core TH.DecQ) -repTyDefn tc bndrs opt_tys tv_names - (TyData { td_ND = new_or_data, td_ctxt = cxt - , td_cons = cons, td_derivs = mb_derivs }) +repDataDefn :: Core TH.Name -> Core [TH.TyVarBndr] + -> Maybe (Core [TH.TypeQ]) + -> [Name] -> HsDataDefn Name + -> DsM (Core TH.DecQ) +repDataDefn tc bndrs opt_tys tv_names + (HsDataDefn { dd_ND = new_or_data, dd_ctxt = cxt + , dd_cons = cons, dd_derivs = mb_derivs }) = do { cxt1 <- repLContext cxt ; derivs1 <- repDerivs mb_derivs ; case new_or_data of @@ -268,18 +257,40 @@ repTyDefn tc bndrs opt_tys tv_names DataType -> do { cons1 <- repList conQTyConName (repC tv_names) cons ; repData cxt1 tc bndrs opt_tys cons1 derivs1 } } -repTyDefn tc bndrs opt_tys _ (TySynonym { td_synRhs = ty }) +repSynDecl :: Core TH.Name -> Core [TH.TyVarBndr] + -> LHsType Name + -> DsM (Core TH.DecQ) +repSynDecl tc bndrs ty = do { ty1 <- repLTy ty - ; repTySyn tc bndrs opt_tys ty1 } + ; repTySyn tc bndrs ty1 } + +repFamilyDecl :: LFamilyDecl Name -> DsM (SrcSpan, Core TH.DecQ) +repFamilyDecl (L loc (FamilyDecl { fdFlavour = flavour, + fdLName = tc, + fdTyVars = tvs, + fdKindSig = opt_kind })) + = do { tc1 <- lookupLOcc tc -- See note [Binders and occurrences] + ; dec <- addTyClTyVarBinds tvs $ \bndrs -> + do { flav <- repFamilyFlavour flavour + ; case opt_kind of + Nothing -> repFamilyNoKind flav tc1 bndrs + Just ki -> do { ki1 <- repLKind ki + ; repFamilyKind flav tc1 bndrs ki1 } + } + ; return (loc, dec) + } + +repFamilyDecls :: [LFamilyDecl Name] -> DsM [Core TH.DecQ] +repFamilyDecls fds = liftM de_loc (mapM repFamilyDecl fds) ------------------------- mk_extra_tvs :: Located Name -> LHsTyVarBndrs Name - -> HsTyDefn Name -> DsM (LHsTyVarBndrs Name) + -> HsDataDefn Name -> DsM (LHsTyVarBndrs Name) -- If there is a kind signature it must be of form -- k1 -> .. -> kn -> * -- Return type variables [tv1:k1, tv2:k2, .., tvn:kn] mk_extra_tvs tc tvs defn - | TyData { td_kindSig = Just hs_kind } <- defn + | HsDataDefn { dd_kindSig = Just hs_kind } <- defn = do { extra_tvs <- go hs_kind ; return (tvs { hsq_tvs = hsq_tvs tvs ++ extra_tvs }) } | otherwise @@ -320,13 +331,21 @@ repFamilyFlavour DataFamily = rep2 dataFamName [] -- Represent instance declarations -- repInstD :: LInstDecl Name -> DsM (SrcSpan, Core TH.DecQ) -repInstD (L loc (FamInstD { lid_inst = fi_decl })) - = do { dec <- repFamInstD fi_decl +repInstD (L loc (TyFamInstD { tfid_inst = fi_decl })) + = do { dec <- repTyFamInstD fi_decl + ; return (loc, dec) } +repInstD (L loc (DataFamInstD { dfid_inst = fi_decl })) + = do { dec <- repDataFamInstD fi_decl + ; return (loc, dec) } +repInstD (L loc (ClsInstD { cid_inst = cls_decl })) + = do { dec <- repClsInstD cls_decl ; return (loc, dec) } -repInstD (L loc (ClsInstD { cid_poly_ty = ty, cid_binds = binds - , cid_sigs = prags, cid_fam_insts = ats })) - = do { dec <- addTyVarBinds tvs $ \_ -> +repClsInstD :: ClsInstDecl Name -> DsM (Core TH.DecQ) +repClsInstD (ClsInstDecl { cid_poly_ty = ty, cid_binds = binds + , cid_sigs = prags, cid_tyfam_insts = ats + , cid_datafam_insts = adts }) + = addTyVarBinds tvs $ \_ -> -- We must bring the type variables into scope, so their -- occurrences don't fail, even though the binders don't -- appear in the resulting data structure @@ -342,25 +361,44 @@ repInstD (L loc (ClsInstD { cid_poly_ty = ty, cid_binds = binds ; inst_ty1 <- repTapps cls_tcon cls_tys ; binds1 <- rep_binds binds ; prags1 <- rep_sigs prags - ; ats1 <- mapM (repFamInstD . unLoc) ats - ; decls <- coreList decQTyConName (ats1 ++ binds1 ++ prags1) + ; ats1 <- mapM (repTyFamInstD . unLoc) ats + ; adts1 <- mapM (repDataFamInstD . unLoc) adts + ; decls <- coreList decQTyConName (ats1 ++ adts1 ++ binds1 ++ prags1) ; repInst cxt1 inst_ty1 decls } - ; return (loc, dec) } where Just (tvs, cxt, cls, tys) = splitLHsInstDeclTy_maybe ty -repFamInstD :: FamInstDecl Name -> DsM (Core TH.DecQ) -repFamInstD (FamInstDecl { fid_tycon = tc_name - , fid_pats = HsWB { hswb_cts = tys, hswb_kvs = kv_names, hswb_tvs = tv_names } - , fid_defn = defn }) - = WARN( not (null kv_names), ppr kv_names ) -- We have not yet dealt with kind - -- polymorphism in Template Haskell (sigh) - do { tc <- lookupLOcc tc_name -- See note [Binders and occurrences] +repTyFamInstD :: TyFamInstDecl Name -> DsM (Core TH.DecQ) +repTyFamInstD decl@(TyFamInstDecl { tfid_eqns = eqns }) + = do { let tc_name = tyFamInstDeclLName decl + ; tc <- lookupLOcc tc_name -- See note [Binders and occurrences] + ; eqns1 <- mapM repTyFamEqn eqns + ; eqns2 <- coreList tySynEqnQTyConName eqns1 + ; repTySynInst tc eqns2 } + +repTyFamEqn :: LTyFamInstEqn Name -> DsM (Core TH.TySynEqnQ) +repTyFamEqn (L loc (TyFamInstEqn { tfie_pats = HsWB { hswb_cts = tys + , hswb_kvs = kv_names + , hswb_tvs = tv_names } + , tfie_rhs = rhs })) + = do { let hs_tvs = HsQTvs { hsq_kvs = kv_names + , hsq_tvs = userHsTyVarBndrs loc tv_names } -- Yuk + ; addTyClTyVarBinds hs_tvs $ \ _ -> + do { tys1 <- repLTys tys + ; tys2 <- coreList typeQTyConName tys1 + ; rhs1 <- repLTy rhs + ; repTySynEqn tys2 rhs1 } } + +repDataFamInstD :: DataFamInstDecl Name -> DsM (Core TH.DecQ) +repDataFamInstD (DataFamInstDecl { dfid_tycon = tc_name + , dfid_pats = HsWB { hswb_cts = tys, hswb_kvs = kv_names, hswb_tvs = tv_names } + , dfid_defn = defn }) + = do { tc <- lookupLOcc tc_name -- See note [Binders and occurrences] ; let loc = getLoc tc_name hs_tvs = HsQTvs { hsq_kvs = kv_names, hsq_tvs = userHsTyVarBndrs loc tv_names } -- Yuk ; addTyClTyVarBinds hs_tvs $ \ bndrs -> do { tys1 <- repList typeQTyConName repLTy tys - ; repTyDefn tc bndrs (Just tys1) tv_names defn } } + ; repDataDefn tc bndrs (Just tys1) tv_names defn } } repForD :: Located (ForeignDecl Name) -> DsM (SrcSpan, Core TH.DecQ) repForD (L loc (ForeignImport name typ _ (CImport cc s mch cis))) @@ -1607,12 +1645,9 @@ repNewtype (MkC cxt) (MkC nm) (MkC _) (Just (MkC tys)) (MkC con) (MkC derivs) = rep2 newtypeInstDName [cxt, nm, tys, con, derivs] repTySyn :: Core TH.Name -> Core [TH.TyVarBndr] - -> Maybe (Core [TH.TypeQ]) -> Core TH.TypeQ -> DsM (Core TH.DecQ) -repTySyn (MkC nm) (MkC tvs) Nothing (MkC rhs) +repTySyn (MkC nm) (MkC tvs) (MkC rhs) = rep2 tySynDName [nm, tvs, rhs] -repTySyn (MkC nm) (MkC _) (Just (MkC tys)) (MkC rhs) - = rep2 tySynInstDName [nm, tys, rhs] repInst :: Core TH.CxtQ -> Core TH.TypeQ -> Core [TH.DecQ] -> DsM (Core TH.DecQ) repInst (MkC cxt) (MkC ty) (MkC ds) = rep2 instanceDName [cxt, ty, ds] @@ -1657,6 +1692,14 @@ repFamilyKind :: Core TH.FamFlavour -> Core TH.Name -> Core [TH.TyVarBndr] repFamilyKind (MkC flav) (MkC nm) (MkC tvs) (MkC ki) = rep2 familyKindDName [flav, nm, tvs, ki] +repTySynInst :: Core TH.Name -> Core [TH.TySynEqnQ] -> DsM (Core TH.DecQ) +repTySynInst (MkC nm) (MkC eqns) + = rep2 tySynInstDName [nm, eqns] + +repTySynEqn :: Core [TH.TypeQ] -> Core TH.TypeQ -> DsM (Core TH.TySynEqnQ) +repTySynEqn (MkC lhs) (MkC rhs) + = rep2 tySynEqnName [lhs, rhs] + repFunDep :: Core [TH.Name] -> Core [TH.Name] -> DsM (Core TH.FunDep) repFunDep (MkC xs) (MkC ys) = rep2 funDepName [xs, ys] @@ -1997,6 +2040,8 @@ templateHaskellNames = [ funDepName, -- FamFlavour typeFamName, dataFamName, + -- TySynEqn + tySynEqnName, -- And the tycons qTyConName, nameTyConName, patTyConName, fieldPatTyConName, matchQTyConName, @@ -2005,7 +2050,7 @@ templateHaskellNames = [ varStrictTypeQTyConName, typeQTyConName, expTyConName, decTyConName, typeTyConName, tyVarBndrTyConName, matchTyConName, clauseTyConName, patQTyConName, fieldPatQTyConName, fieldExpQTyConName, funDepTyConName, - predQTyConName, decsQTyConName, ruleBndrQTyConName, + predQTyConName, decsQTyConName, ruleBndrQTyConName, tySynEqnQTyConName, -- Quasiquoting quoteDecName, quoteTypeName, quoteExpName, quotePatName] @@ -2304,11 +2349,15 @@ typeFamName, dataFamName :: Name typeFamName = libFun (fsLit "typeFam") typeFamIdKey dataFamName = libFun (fsLit "dataFam") dataFamIdKey +-- data TySynEqn = ... +tySynEqnName :: Name +tySynEqnName = libFun (fsLit "tySynEqn") tySynEqnIdKey + matchQTyConName, clauseQTyConName, expQTyConName, stmtQTyConName, decQTyConName, conQTyConName, strictTypeQTyConName, varStrictTypeQTyConName, typeQTyConName, fieldExpQTyConName, patQTyConName, fieldPatQTyConName, predQTyConName, decsQTyConName, - ruleBndrQTyConName :: Name + ruleBndrQTyConName, tySynEqnQTyConName :: Name matchQTyConName = libTc (fsLit "MatchQ") matchQTyConKey clauseQTyConName = libTc (fsLit "ClauseQ") clauseQTyConKey expQTyConName = libTc (fsLit "ExpQ") expQTyConKey @@ -2324,6 +2373,7 @@ patQTyConName = libTc (fsLit "PatQ") patQTyConKey fieldPatQTyConName = libTc (fsLit "FieldPatQ") fieldPatQTyConKey predQTyConName = libTc (fsLit "PredQ") predQTyConKey ruleBndrQTyConName = libTc (fsLit "RuleBndrQ") ruleBndrQTyConKey +tySynEqnQTyConName = libTc (fsLit "TySynEqnQ") tySynEqnQTyConKey -- quasiquoting quoteExpName, quotePatName, quoteDecName, quoteTypeName :: Name @@ -2341,7 +2391,7 @@ expTyConKey, matchTyConKey, clauseTyConKey, qTyConKey, expQTyConKey, decTyConKey, varStrictTypeQTyConKey, strictTypeQTyConKey, fieldExpTyConKey, fieldPatTyConKey, nameTyConKey, patQTyConKey, fieldPatQTyConKey, fieldExpQTyConKey, funDepTyConKey, predTyConKey, - predQTyConKey, decsQTyConKey, ruleBndrQTyConKey :: Unique + predQTyConKey, decsQTyConKey, ruleBndrQTyConKey, tySynEqnQTyConKey :: Unique expTyConKey = mkPreludeTyConUnique 200 matchTyConKey = mkPreludeTyConUnique 201 clauseTyConKey = mkPreludeTyConUnique 202 @@ -2370,6 +2420,7 @@ predQTyConKey = mkPreludeTyConUnique 224 tyVarBndrTyConKey = mkPreludeTyConUnique 225 decsQTyConKey = mkPreludeTyConUnique 226 ruleBndrQTyConKey = mkPreludeTyConUnique 227 +tySynEqnQTyConKey = mkPreludeTyConUnique 228 -- IdUniques available: 200-499 -- If you want to change this, make sure you check in PrelNames @@ -2629,6 +2680,10 @@ typeFamIdKey, dataFamIdKey :: Unique typeFamIdKey = mkPreludeMiscIdUnique 415 dataFamIdKey = mkPreludeMiscIdUnique 416 +-- data TySynEqn = ... +tySynEqnIdKey :: Unique +tySynEqnIdKey = mkPreludeMiscIdUnique 417 + -- quasiquoting quoteExpKey, quotePatKey, quoteDecKey, quoteTypeKey :: Unique quoteExpKey = mkPreludeMiscIdUnique 418 |