TiDerivedInstances.hs

module TiDerivedInstances(derivedInstances) where
import HasBaseStruct
import HsDecl
import TI
import TiSolve(expandSynonyms)
import TiContextReduction(contextReduction'')
import TiInstanceDB(addInstKind)
import TiSCC(sccD)
import SrcLoc

import Deriving(derive)
import FreeNamesBase()

import Maybe(mapMaybe)
import List(nub,partition)
import MUtils
import PrettyPrint

--import IOExts(trace) -- debugging

-- Figuring out what the derived instances are, without generating the
-- derived code.

derivedInstances ks stdnames modmap env ds =
     reduceInsts .
     map inst0 .
     concatMap (collectByFst.concatMap drv.mapMaybe basestruct) .
     sccD . filter isBaseTypeDec $ ds
  where
    inst0 (cn,is) = [(n,((c t,map c ts),(s,code t)))|(n,(t,ts))<-is]
      where c=app cn
	    s=srcLoc cn
	    code t=derive stdnames cn (definedTypeName t)
    drv d =
	case d of
	  HsNewTypeDecl s ctx t c  cls -> drv' cls t [c]
	  HsDataDecl    s ctx t cs cls -> drv' cls t cs
	  HsTypeDecl    {}             -> []
      where
	drv' cls t cons =
            [(cl,(derivedInstName' modmap cl tn,(t,syn (conArgTypes=<<cons))))
             |cl<-cls]
	  where tn=definedTypeName t

	conArgTypes con =
	  case con of
	    HsConDecl s _ _ c bangts -> map unbang bangts -- !!!
	    HsRecDecl s _ _ c fields -> map (unbang.snd) fields -- !!!

    app c t = hsTyCon c `hsTyApp` t
    syn = tmap (expandSynonyms env)

    isBaseTypeDec = maybe False isTypeDec . basestruct
    isTypeDec d =
	case d of
	  HsNewTypeDecl {} -> True
	  HsDataDecl    {} -> True
	  HsTypeDecl    {} -> True
	  _ -> False

     -- TODO: need fixed point interation for mutually recursive types!!
    reduceInsts [] = return []
    reduceInsts ([i]:is) =
      do i' <- reduce1 i
	 is' <- extendIEnv' [(fst i')] $ reduceInsts is
	 return (i':is')
    reduceInsts (is1:is) =
      do is1' <- mapM declare =<< instContext (instContext0 is1)
	 is' <- extendIEnv' (map fst is1') $ reduceInsts is
	 return (is1'++is')

{- old:
    reduceInsts (is1:is) =
      if all (null.freeTyvars.fst.fst.snd) is1
      then reduceInsts ([[i]|i<-is1]++is)
      else
      fail.pp$
        sep [ppi "Deriving for mutually recursive types with parameters not implemented yet:",
	     nest 4 $ ppiFSeq (map (fst.fst.snd) is1)]
-}
    reduce1 (n,((p,ps),(s,mcode))) =
      do _:>:ps' <- extendIEnv' [(p,(n,[]))] $ simplify s ps
	 --trace (pp (ps$$ps')) $ do
	 declare ((p,(n,ps')),(ps,(s,mcode)))

    declare (i@(p,(n,ps')),(_,(s,mcode))) =
      do methods <- posContext s mcode
	 let d = hsInstDecl s (Just n) ps' p (toDefs methods)
	 return (i,d)

    simplify s ps =
      do ns <- map (flip dictName' (Just s)) # freshlist (length ps)
         unzipTyped # contextReduction'' (zipTyped (ns:>:ps))

   --In progress: fix point iteration for mutually recursive types:
    instContext is =
       do is' <- mapM (instContext1 (map fst is)) is
	  if and (zipWith eqinst is is')
            then return is
	    else instContext is'

    instContext1 is (i@(p,(n,ctx)),j@(ps,(s,c))) =
       do _:>:ctx' <- extendIEnv' is $ simplify s ps
	  return ((p,(n,ctx')),j)

    instContext0 is = [((p,(n,[])),(ps,c))|(n,((p,ps),c))<-is]

    extendIEnv' = extendIEnv . map (addInstKind ks)

    

If there was an Ord instance for predicates, we could just nub and sort and compare for equality. Since we only have Eq, it's a bit more clumpsy...

eqinst i1 i2 = eqctx (ctx i1) (ctx i2)
      where
        ctx ((_,(_,c)),_) = nub c
	
	eqctx [] ps2 = null ps2
	eqctx (p1:ps1) ps2 =
          case partition (==p1) ps2 of
            ([p2],ps2') -> eqctx ps1 ps2'
	    _ -> False

Plain-text version of TiDerivedInstances.hs | Valid HTML?