module Type.Check.Soundness ( --checkUpdateSoundness dangerousCidsT) where import Util import qualified Shared.Var as Var import qualified Shared.VarBind as Var import Shared.VarPrim import Type.Exp import Type.Error import Type.Util import Type.Plate.Collect import Type.State import Type.Class import Shared.Error import qualified Data.Set as Set import Data.Set (Set) import qualified Data.Map as Map import Data.Map (Map) ----- stage = "Type.Soundness" debug = True trace s = when debug $ traceM s -- checkUpdateSoundness -- Check for update soudness problems in an already generalised scheme. -- -- The type inferencer might find out that some scheme has mutable components -- after it's already generalised and instantiated it several times. It's -- too late to apply monomorphism restrictions, but we can at least report -- an error. -- -- If you want the monomorphism restriction, and not the error, then supply -- a type sig for the scheme including an appropriate mutability constraint. -- {- checkUpdateSoundness :: Var -> Type -> SquidM () checkUpdateSoundness varT t = do let ?fsMutable = nub $ [f | f@(FClass v _) <- collectFetters t , Var.bind v == Var.FMutable] let dangerTs = nub $ [t | t@(TVar v) <- dangerT [] t] trace $ "* CheckUpdate.checkUpdate " % t % "\n" % " fsMutable = " % ?fsMutable % "\n" % " dangerTs = " % dangerTs % "\n" % "\n" when (not $ isNil dangerTs) $ do addErrors [ErrorUpdateSoundness { eVar = varT , eType = t , eTypeDanger = dangerTs }] return () ----- -} dangerousCidsT :: Type -> [ClassId] dangerousCidsT tt = let tsDanger = dangerT Set.empty Map.empty tt in [ cid | TClass k cid <- Set.toList tsDanger , elem k [KData, KEffect, KClosure] ] dangerT :: Set Type -> Map Type Type -> Type -> Set Type dangerT rsMutable fsClosure tt = case tt of TVar{} -> Set.empty TClass{} -> Set.empty TForall vks t -> dangerT rsMutable fsClosure t -- fetters TFetters fs t1 -> -- remember any regions flagged as mutable let rsMoreMutable = Set.fromList $ [r | FConstraint v [r] <- fs , Var.bind v == Var.FMutable ] rsMutable' = Set.union rsMutable rsMoreMutable -- collect up more closure bindings fsClosure' = Map.union fsClosure (Map.fromList [(u1, u2) | FLet u1 u2 <- fs , kindOfType u1 == KClosure]) -- decend into type and fetters t1Danger = dangerT rsMutable' fsClosure' t1 fsDanger = Set.unions $ map (dangerT rsMutable' fsClosure') [ u2 | FLet u1 u2 <- fs , kindOfType u1 == KClosure] in Set.union t1Danger fsDanger -- functions TFun t1 t2 eff clo -> let cloDanger | TBot KClosure <- clo = Set.empty | otherwise = case Map.lookup clo fsClosure of Just c -> dangerT rsMutable fsClosure c Nothing -> Set.empty in Set.unions -- [ dangerT rsMutable fsClosure t1 -- , dangerT rsMutable fsClosure t2 [ cloDanger ] -- data constructors TData v ts -- if this ctor has any mutable regions then all vars from this point down are dangerous | or $ map (\t -> case t of TVar{} -> Set.member t rsMutable TClass{} -> Set.member t rsMutable _ -> False) ts -> Set.unions $ map (Set.fromList . collectTClassVars) ts -- check for dangerous vars in subterms | otherwise -> Set.unions $ map (dangerT rsMutable fsClosure) ts -- closures TFree v t -> dangerT rsMutable fsClosure t TSum KClosure ts -> Set.unions $ map (dangerT rsMutable fsClosure) ts TMask KClosure t v -> dangerT rsMutable fsClosure t -- skip over errors TError{} -> Set.empty _ -> panic stage $ "dangerT: no match for " % tt