-- | Functions for reducing the context of a type. module Type.Context ( reduceContextT ) where ------ import Type.Exp import Type.Plate import Type.Util import Shared.VarPrim import Shared.Error import Util import qualified Data.Set as Set import Data.Set (Set) import qualified Data.Map as Map import Data.Map (Map) import Debug.Trace ----- stage = "Type.Context" -- | Reduce the context of this type using the provided map of instance definitions. reduceContextT :: Map Var [Fetter] -- (class var -> instances) for this class -> Type -- the type to reduce -> Type reduceContextT classInst tt = case tt of TFetters fs t -> let vsFreeT = freeVars t fs' = concat $ map (reduceContextF vsFreeT classInst) fs in case fs' of [] -> t _ -> TFetters fs' t _ -> tt reduceContextF :: Set Var -- vars that are free in the shape of the type -> Map Var [Fetter] -- (class var -> instances) for each class -> Fetter -- the constraint being used -> [Fetter] -- maybe some new constraints reduceContextF vsShape classInstances ff -- = trace (pprStr $ "reduceContextF: " % ff % "\n") = reduceContextF' vsShape classInstances ff reduceContextF' vsShape classInstances ff -- If there is a Const, Lazy, Mutable, Direct fetter on a region that isn't in the shape of the -- type then we can safely ditch it | FConstraint v [TVar KRegion r] <- ff , v == primConst -- elem v [primConst, primMutable, primMutable, primDirect] , not $ Set.member r vsShape = [] -- If there is a matching instance for this class then we can remove the constraint. | FConstraint v ts <- ff , Just instances <- Map.lookup v classInstances , Just inst' <- find (matchInstance ff) instances = [] -- Purity constraints on bottom effects can be removed. | FConstraint v [TBot KEffect] <- ff , v == primPure = [] -- Purity constraints on read effects can be dischared by -- making the region constant | FConstraint v effs <- ff , v == primPure , effsFlat <- catMap flattenTSum effs , (effs', fsMore) <- unzip $ map purifyEff effsFlat -- build the effs we couldn't purify back into a sum , remainingEff <- makeTSum KEffect $ catMaybes effs' -- this produces constraints (like Const) that might be able to be further reduced, -- so make sure to call ourselves recursively.. = case remainingEff of TBot KEffect -> catMap (reduceContextF vsShape classInstances) $ catMaybes fsMore _ -> FConstraint primPure [remainingEff] : ( catMap (reduceContextF vsShape classInstances) $ catMaybes fsMore) | otherwise = [ff] purifyEff eff | TEffect v [tR@(TVar KRegion r)] <- eff , v == primRead = (Nothing, Just (FConstraint primConst [tR])) | otherwise = (Just eff, Nothing) -- Checks if an class instance supports a certain type. -- The class instance has to be more polymorphic than the type we want to support. -- -- This is duplicated in Core.Dictionary for Core.Type -- matchInstance :: Fetter -- the class we want to support -> Fetter -- the class of the instance -> Bool matchInstance cType cInst | FConstraint v1 ts1 <- cType , FConstraint v2 ts2 <- cInst -- check the class is the same , v1 == v2 , length ts1 == length ts2 -- all the type arguments of the class must unify , Just constrs <- sequence $ zipWith unifyT2 ts1 ts2 -- any extra constraint from the unification must have -- a var or wildcard for the RHS , and $ map (\(ta, tb) -> case tb of TVar k v | kindOfType ta == k -> True TWild k | kindOfType ta == k -> True _ -> False) $ concat $ constrs = True | otherwise = False