{-+ This module defines type checking functions for generalizing inferred types and applying context reduction (#generalise'#). -} module TiGeneralize where import TiMonad import TiTypes import TiUtil import TiSolve(solve,TypeConstraint(..)) import Unification(isVar) import TiNames(ValueId,TypeVar,dictName,dictName') import TiClasses hiding (isVar) import TiKinds --import TiPrelude import TiContextReduction import TiDefault import TiFunDeps(predDeps,closure,improvement) import TiFresh import HasBaseStruct import HsConstants(mod_Prelude,tuple) import BaseSyntax(srcLoc,TI(..)) import TypedIds(NameSpace(..)) import PrettyPrint hiding (var) import List((\\),partition,nub)--,intersect import MUtils --import Debug.Trace(trace) -- debug {-+ If there were polymorphic kinds, #kgeneralise# would produce kind schemes, but currently it just instantiates any remaining kind variables after kind inference to *, in accordance with the Haskell 98 report, section 4.6. -} kgeneralise m = do (kbs,s) <- getKSubst m return $ (map.fmap) (fixkvars . ksubst s) kbs {-+ As #kgeneralise#, but treat Pred as equal to *. Useful for kind checking after the dictionary translation. -} kgeneraliseSloppy m = do (kbs,s) <- getKSubstSloppy m return $ (map.fmap) (apFst (fixkvars . ksubst s)) kbs --generalise1 u = generalise' u id --generalise u = generalise' u fmap {-+ At the moment, #checkKinds# only keeps track of the kinds of type variables that remain after type inference. It could be improved to also check that all subsitutions performed were kind preserving. -} checkKinds kpreds = return (tyvars kpreds) where --tyvars :: Unifiable i => [Kinded (Type i)] -> [Kinded i] tyvars kpreds = nub [v:>:k|t:>:k<-kpreds,Just v<-[isVar t]] -- hmm {- catchAmbiguity dicts = if null dicts then done else fail $ pp ("Unresolved overloading: "<+>ppDicts dicts) -} {-+ Iterate context reduction and improvement until nothing changes -} reduceAndImprove dicts0 = do (dicts1,r1) <- contextReduction dicts0 subst1@(S s) <- errorContext "Applying functional dependencies" $ improvement [ p | d:>:p<-dicts1] if null s then return (dicts1,r1,subst1) else do --trace (pp $ "Improvement:"<+>vcat [ppi s,"of"<+>ppi dicts1]) $ done (dicts2,r2,subst2) <- reduceAndImprove (apply subst1 dicts1) return (dicts2,r2 . r1,compS subst2 subst1) {-+ Generalize inferred types: -} generalise' keepambig unrestricted fmap' m = do env <- getTEnv (x:>:t0,res@(dicts0,kpreds0,subst0)) <- getSubst m --trace (pp (t0,res)) $ return () ((dicts,r,subst1),([],kpreds1,S [])) <- getSubst $ reduceAndImprove dicts0 let subst@(S s) = compS subst1 subst0 kpreds <- checkKinds (kpreds1++[apply subst1 t:>:k|t:>:k<-kpreds0]) --trace (pp kpreds) $ return () mono <- monomorphism # getEnv -- The monomorphism restriction is optional! fdeps <- predDeps [ p | d:>:p<-dicts] let t = apply subst t0 ngvs0 = tv env -- could probably be made more efficient... s' = [s1|s1@(v,_)<-s,v `elem` ngvs0] -- Non-generic variables by the usual Hindley-Milner rules: hmngvs0 = ngvs0++tv (map snd s') -- Non-generic vars when taking functional dependencies into account: hmngvs = closure fdeps hmngvs0 -- (deferred,retained) predicates: (ngdicts,gdicts0) = if not mono || unrestricted then partition ng dicts else (dicts,[]) -- monomorphism restriction applies where ng = all (`elem` hmngvs) . tv mrngvs = tv ngdicts ngvs = hmngvs++ -- the usual Hindley-Milner restriction mrngvs -- from the monomorphism restriction (ngkpreds,gkpreds0) = partition ng kpreds where ng (v:>:k) = v `elem` ngvs -- mrngvs is not enough! --(avs,(ambigdicts,gdicts)) = ambiguities ngvs gdicts0 t --catchAmbiguity ambigdicts; let subst' = idS; r' = id (gdicts,(subst',r')) <- let known = (if keepambig then tdom gkpreds0 else [])++{-hm-}ngvs in resolveAmbiguities fdeps known gdicts0 t gkpreds <- checkKinds [varSubst subst' v:>:k|v:>:k<-gkpreds0] let ds:>:ctx = unzipTyped gdicts gvs = tdom gkpreds ks = map (emap HsVar) gkpreds gen t = Forall ags (kinded ks gs) qt where ags = filter (\ (v:>:_)->v `notElem` gs) gkpreds qt = ctx:=>t gs = tv qt \\ ngvs -- normal type scheme --gs = gvs \\ ngvs -- keep "ambiguous" type variables sc = fmap' gen t mapM_ constrain [tyvar v:=:t|(v,t)<-s'] -- deferred equality constraints mapM_ addinst ngdicts -- deferred predicates --trace (pp $ "ngkpreds:"<+>ngkpreds) $ return () mapM_ addkinst [tyvar v:>:k|v:>:k<-ngkpreds] -- what to propagate? --abstract ds (r (apply subst x))>:fmap' gen t (ds,r' $ apply subst' $ r $ apply subst x)>:sc getSubst m = do env <- getKEnv ; getSubst' (solve env) m getKSubst = getSubst' ksolve getKSubstSloppy = getSubst' ksolveSloppy getSubst' solve m = do (ans,cs) <- getConstraints m subst <- solve cs return (ans,subst)