TiDs.hs

-- Type checking sequences of declarations
module TiDs where
import List(nub,(\\),intersect,partition)
import Maybe(mapMaybe,fromMaybe)

import HasBaseStruct(HasBaseStruct(..),GetBaseStruct(..))
import SrcLoc(SrcLoc,HasSrcLoc(..))
import HsLiteral(HsLiteral)
import HsDeclStruct
import HsPatStruct(PI)
import TI hiding (Subst)
import TiNameMaps
import TiDkc(Dinst,Einst)
import TiSolve
import TiSCC(sccD)
import TiContextReduction(contextReduction,entails)
import TiInstanceDB(instType,addInstKind)
import TiDerivedInstances
import TiFunDeps(checkInstances)
import Substitute
import SubstituteBaseStruct
--import QualNames

import MUtils(( # ))
import PrettyPrint(Printable,pp,vcat)

instance DeclInfo i d => DeclInfo i [d] where
  explicitlyTyped ks kinfo ctx ds = (concat kss,concat tss)
    where (kss,tss) = unzip $ map (explicitlyTyped ks kinfo ctx) ds

---
instance (
 TypeId i,ValueId i,Printable i, Fresh i,HasSrcLoc i,
 TypedId PId i,CheckRecursion i d,
 DeclInfo i d, FreeNames i d, TypeCheckDecl i d ds2,HasSrcLoc d,
 HasCoreSyntax i p,HasCoreSyntax i e,HasDef ds d,
 --HasLit e,HasLit p,
 HasBaseStruct e (Einst i e p ds),HasBaseStruct p (PI i p),
 DefinedNames i d,AccNames i d,
 HasBaseStruct d (Dinst i e p ds), GetBaseStruct d (Dinst i e p ds),
 HasDef ds2 d2,  HasLocalDef i e2 d2,  Types i d2,
 HasAbstr i ds2, HasLocalDef i e2 ds2, Types i ds2, AddDeclsType i ds2,
 HasCoreSyntax i e2,
 MapExp e2 ds2,Subst i e2,HasTypeApp i e2, -- for dicts in mono rec calls
 KindCheck i d ()) => TypeCheckDecls i [d] ds2
  where
    tcTopDecls rewrite ds = decorate # tcDs rewrite True ds
    tcInstDecls mts ds = do ds':>:bs <- tcExplDs mts ds
			    return (addDeclsType ([],bs) ds')

--}

decorate (ds:>:(insts,dt)) = addDeclsType dt ds:>:(insts,dt)

--sccD ds = [ds] -- dummy

-- How to type check a (possibly recursive) group of declarations:
tcDs rewrite rec ds0 =
    do -- Recursive type synonyms and suprtclass relations can cause the type
       -- checker to loop, so start by checking...
       checkRecursion ds0
       -- Infer the kinds of all class/type identifers, including
       -- type variables.
       -- (Names are assumed to have been made unique in an earlier pass.)
       ks <- errorContext "Kind inference" $
             kgeneralise $ do kbs <- kintro (allTypeNames ds0)
			      let kbs' = map (fmap (flip (,) undefined)) kbs
                              extendkts kbs' (kc ds0>>return kbs)
       -- Find additional info about classes and types
       -- and the types of all explicitly typed value identifiers...
       let (kinfo,expls) = explicitlyTyped ks (map (fmap snd) kinfo) [] ds0
	   vkinfo = [v:>:(k,Tyvar)|v@(HsVar _):>:k<-ks]
       expl <- mapM checkTypeSigClash (collectTyped expls)
       -- ...and add them to the environment (if in a recursive group).
       extendkts (kinfo++vkinfo) $ opt rec (extendts expl) $
	do -- Extend the instance database with the declared instances
           (insts,ds) <- getInstances ks ds0
	   checkInstances insts
	   extendIEnv insts $
	    do -- Infer the types of the implicitly typed declarations,
	       -- one strongly connected component (scc) at a time...
	       let (dsImpl,dsExpl) = partition (isImplicit ns) ds
		   dsccs = sccD dsImpl
		   ns:>:_=unzipTyped expl
	       ds1:>:bs1 <- tcImplBGs rec expl dsccs
	       -- ...and add them to the environment (if in a recursive group)
	       opt rec (extendts bs1) $
		do -- Infer the types of the explicitly typed declarations
		   -- and check that they agree with their explicit types
		   ds2:>:bs2 <- tcExplDs expl dsExpl
		   let env = (kinfo,its++filter noDup bs0++expl)
		       its=map instType insts
		       bs0 = bs1++bs2
		       noDup (x:>:_) = x `notElem` ns
		   -- Finally, return the translated declarations, the
		   -- instances, and the resulting environment
		   ((ds1 `appendDef` ds2)>:(insts,env))
  where	
    getInstances ks ds =
        do modmap <- getModule
           kenv <- getKEnv
           let insts1 = map (addInstKind ks) (instDecls ds modmap kenv)
	   extendIEnv insts1 $
	    do stdnames <- getStdNames
	       (insts2,ds2) <- unzip # derivedInstances ks stdnames modmap kenv ds
	       let insts = insts1++map (addInstKind ks) insts2
	       return (insts,ds++rewrite ds2)

    instDecls ds modmap env =
         [instDecl s optn ctx tp|HsInstDecl s optn ctx tp _<-mapMaybe basestruct ds]
       where
        instDecl s optn ctx tp = (syn tp,(n,map syn ctx))
	  where n = fromMaybe (instName' modmap s tp) optn
        syn = expandSynonyms env

    isImplicit ns d = any (`notElem` ns) (definedValueNames d)

-- Type check a sequence of implicitly typed binding groups:
tcImplBGs rec expl [] = noDef>:[]
tcImplBGs rec expl (ds:dss) =
  do ds1:>:bs1 <- tcImplBG rec expl ds
     ds2:>:bs2 <- extendts bs1 $ tcImplBGs rec expl dss
     ds1 `appendDef` ds2>:bs1++bs2

tcImplBG rec expl ds =
    checkExplicit rec (srcLoc ds) expl =<< tcBG expl rec False ds

-- Type check declarations with explicit type signatures
-- pre: the explicitly given types have already been added to the environment
tcExplDs expl ds =conc . unzipTyped # mapM (tcExplD expl) ds
  where conc (dss:>:bss) = concatDefs dss:>:concat bss

tcExplD expl d =
  checkExplicit False (srcLoc d) expl =<< tcBG expl False True [d]

-- Typecheck one (mutually recursive) binding group:
tcBG all_ebs rec isExpl ds =
  addErrorContext $
  do (dns,ds'):>:bs' <-
       generalise' keepambig unr mapTs $
       do bs1 <- tintro (values\\ens)
	  bs2 <- tintro ens
	  let bs=bs1++bs2
	      lbs = (map.fmap) mono bs1
	  (:>:bs) # opt rec (extendts lbs) (mapM (tcDecl bs) ds)
     (dns,concatDefs ds')>:bs'
  where
    ens=values `intersect` all_ens where all_ens:>:_=unzipTyped all_ebs
    (types,values) = definedNamesSplit ds
    unr = all (isUnrestricted isExpl) ds
    keepambig = all keepAmbigTypes ds

    mapTs = map . fmap
      --where mapTM f (x:>:t) = (x:>:) # f t
    --typed = uncurry (:>:)

    addErrorContext =
      if null types && null values
      then posContext' (srcLoc ds) "in declaration"
      else posContext (srcLoc ds) .
           declContext (types++values)
           {-errorContext (render
	    (sep [(if unr then "In an un" else "In a ")
		   <>"restricted definition of",
		  nest 4 (fsep types $$ fsep values)]))-}

opt b f = if b then f else id

checkExplicit rec loc explicit ((dns,d):>:inferred) =
    posContext' loc "type signature vs inferred type" $
    do let xs:>:_ = unzipTyped inferred
	   ixs = xs \\ exs
           (exs,eqscs) =
	       unzip [ (x,(it,et)) |x:>:it<-inferred,y:>:et<-explicit,y==x]
           pick x = if x `elem` exs
		    then head [ t |t@(y:>:_)<-explicit,x==y]
		    else head [ t |t@(y:>:_)<-inferred,x==y]
           -- abstract' adjusts monomorphic recurive calls:
	   abstract' ixs dns d =
	       if rec
	       then abstract dns (esubst addDicts d)
	       else abstract dns d
	     where
	       addDicts x = if HsVar x `elem` ixs
			    then foldl1 app (x':map var dns)
			    else if HsVar x `elem` exs
			         then x' 
				 else var x -- Grr!! Type info is lost
		 where
		   x' = spec (HsVar x) sc (map tyvar (tdom gs))
		   _:>:sc@(Forall ags gs qt) = pick (HsVar x)
       if null eqscs then abstract' ixs dns d>:map pick xs
	 else do (ids,eds,eqts) <- freshInsts dns eqscs
		 s0 <- matchEqns eqts =<< getKEnv
		 let ids' = apply s0 ids
		 id {-errorContext (eds,ids',apply s0 eqts)-} $ do
		  -- Although the context ids should already be reduced,
		  -- the instance ids' may still not be in normal form,
		  -- so we have to apply context reduction again.
		  (ids'',r1,s1) <- do reduceAndImprove ids'
		  (is,r2) <-
                    do env <- getKEnv
		       let eds' = (map.fmap) (expandSynonyms env) (apply s1 eds)
		       (eds' `entails` ids'') env
		  let edns:>:_ = unzipTyped eds
		      r = r2 . r1
		      s@(S su) = is `compS` s1 `compS` s0
		  ngvs <- tv # getTEnv
		  mapM_ constrain [tyvar v:=:t|(v,t)<-su,v `elem` ngvs]
		  abstract' ixs edns (r (apply s d))>:apply s (map pick xs)
  where
    freshInsts dns eqscs =
       do ((ctx,eds):_,eqts) <- unzip # mapM freshInst' eqscs
	  return (zipTyped (dns:>:ctx),eds,eqts)

    freshInst' (isc,esc) =
       do -- Don't freshen the inferred type, the quantified tvars can appear in the body:
          --(ids,it) <- freshInst isc
          --let _:>:ctx = unzipTyped ids
          let Forall _ _ (ictx:=>it) = isc
	      Forall _ _ (ectx:=>et) = esc
          --(eds,et) <- freshInst esc
          ds <- map dictName # freshlist (length ectx)
	  let eds = zipTyped (ds:>:ectx)
          return ((ictx,eds),(it,et))

We allow more than one type signature for the same identifier, but we check that they are syntactically equal. In Haskell 98, its invalid to give more then one type signature for the same identifier, even if they are identical (H98 report, section 4.4.1).

checkTypeSigClash (x:>:ts0) =
    case nub ts0 of -- Equality of type schemes. Hmm...
      [t] -> x>:t
      ts -> declContext [x] $
              errorContext "Conflicting type signatures" $
                fail $ pp (vcat ts)

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