[project @ 1996-01-08 20:28:12 by partain]
[ghc-hetmet.git] / ghc / compiler / typecheck / GenSpecEtc.lhs
diff --git a/ghc/compiler/typecheck/GenSpecEtc.lhs b/ghc/compiler/typecheck/GenSpecEtc.lhs
new file mode 100644 (file)
index 0000000..c607157
--- /dev/null
@@ -0,0 +1,506 @@
+%
+% (c) The GRASP/AQUA Project, Glasgow University, 1992-1995
+%
+\section[GenSpecEtc]{Code for GEN, SPEC, PRED, and REL}
+
+\begin{code}
+#include "HsVersions.h"
+
+module GenSpecEtc (
+       genBinds, SignatureInfo(..),
+       checkSigTyVars,
+
+       -- and to make the interface self-sufficient...
+       Bag, E, Bind, Binds, TypecheckedPat, Id, Inst,
+       LIE, TcResult, Name, SrcLoc, Subst, TyVar, UniType,
+       UniqueSupply, Error(..), Pretty(..), PprStyle,
+       PrettyRep
+    ) where
+
+import TcMonad         -- typechecker monadery
+import TcMonadFns      ( applyTcSubstAndCollectTyVars,
+                         mkIdsWithGivenTys
+                       )
+import AbsSyn
+
+import AbsUniType
+import E               ( tvOfE, E, LVE(..), TCE(..), UniqFM, CE(..) )
+                       -- TCE and CE for pragmas only
+import Errors
+import Id              ( getIdUniType, mkInstId, Id, DictVar(..) )
+import IdInfo
+import Inst
+import LIE             ( mkLIE, unMkLIE, LIE )
+import ListSetOps      ( minusList, unionLists, intersectLists )
+import Maybes          ( assocMaybe, Maybe(..) )
+import Name            ( Name(..) )    -- ToDo: a HACK
+import TcSimplify      ( tcSimplify, tcSimplifyAndCheck )
+import Util
+
+IMPORT_Trace           -- ToDo: rm (debugging)
+import Pretty          -- 
+\end{code}
+
+%************************************************************************
+%*                                                                     *
+\subsection[Gen-SignatureInfo]{The @SignatureInfo@ type}
+%*                                                                     *
+%************************************************************************
+
+A type signature (or user-pragma) is typechecked to produce a
+@SignatureInfo@.
+
+\begin{code}
+data SignatureInfo
+  = TySigInfo      Id  -- for this value...
+                   [TyVar] [Inst] TauType
+                   SrcLoc
+
+  | ValSpecInfo            Name        -- we'd rather have the Name than Id...
+                   UniType
+                   (Maybe Name)
+                   SrcLoc
+
+  | ValInlineInfo   Name
+                   UnfoldingGuidance
+                   SrcLoc
+
+  | ValDeforestInfo Name
+                    SrcLoc
+
+  | ValMagicUnfoldingInfo
+                   Name
+                   FAST_STRING
+                   SrcLoc
+
+  -- ToDo: perhaps add more (for other user pragmas)
+\end{code}
+
+
+%************************************************************************
+%*                                                                     *
+\subsection[Gen-GEN]{Generalising bindings}
+%*                                                                     *
+%************************************************************************
+
+\begin{code}
+genBinds :: Bool                               -- True <=> top level
+        -> E 
+        -> TypecheckedBind 
+        -> LIE                                 -- LIE from typecheck of binds
+        -> LVE                                 -- Local types
+        -> [SignatureInfo]                     -- Signatures, if any
+        -> TcM (TypecheckedBinds, LIE, LVE)    -- Generalised binds, reduced LIE,
+                                               --      polymorphic LVE
+                                               -- The LVE and LIE are fixed points
+                                               -- of the substitution
+\end{code}
+
+In the call $(@genBinds@~env~bind~lie~lve)$, $(bind,lie,lve)$
+is the result of typechecking a @Bind@.  @genBinds@ implements the BIND-GEN
+and BIND-PRED rules.
+$lie$ and $lve$ may or may not be
+fixed points of the current substitution.
+
+It returns
+\begin{itemize}
+\item
+An @AbsBind@ which wraps up $bind$ in a suitable abstraction.
+\item
+an LIE, which is the part of the input LIE which isn't discharged by
+the AbsBind.  This means the parts which predicate type variables
+free in $env$.
+\item
+An LVE whose domain is identical to that passed in.
+Its range is a new set of locals to that passed in,
+because they have been gen'd.
+\end{itemize}
+
+@genBinds@ takes the
+following steps:
+\begin{itemize}
+\item
+find $constrained$, the free variables of $env$.
+First we must apply the current substitution to the environment, so that the
+correct set of constrained type vars are extracted!
+\item
+find $free$, the free variables of $lve$ which are not in $constrained$.
+We need to apply the current subsitution to $lve$ first, of course.
+\item
+minimise $lie$ to give $lie'$; all the constraints in $lie'$ are on
+single type variables.
+\item
+split $lie'$ into three: those predicating type variables in $constrained$,
+those on type variables in $free$, and the rest.
+\item
+complain about ``the rest'' part of $lie'$.  These type variables are
+ambiguous.
+\item
+generate new locals for each member of the domain of $lve$, with appropriately
+gen'd types.
+\item
+generate a suitable AbsBinds to enclose the bindings.
+\end{itemize}
+
+\begin{code}
+genBinds top_level e bind lie lve sigs
+  = getSrcLocTc                                        `thenNF_Tc` \ locn ->
+
+       -- GET TYPE VARIABLES FREE IN ENV
+    applyTcSubstAndCollectTyVars (tvOfE e)     `thenNF_Tc` \ free_tyvars ->
+
+       -- CHECK THAT THE SIGNATURES MATCH
+       -- Doesn't affect substitution
+    mapTc (checkSigMatch free_tyvars) sigs     `thenTc_`
+
+        -- UNPACK THE LVE
+    let
+       (bound_var_names, bound_var_locals) = unzip lve
+       bound_var_types = map getIdUniType bound_var_locals
+    in
+    applyTcSubstToTys bound_var_types `thenNF_Tc`      \ bound_var_types' ->
+    let
+       mentioned_tyvars' = extractTyVarsFromTys bound_var_types'
+
+        -- COMPUTE VARIABLES OVER WHICH TO QUANTIFY, namely tyvars_to_gen
+       tyvars_to_gen = mentioned_tyvars' `minusList` free_tyvars
+
+       -- UNSCRAMBLE "sigs" INTO VARIOUS FLAVOURS
+       -- AND SNAFFLE ANY "IdInfos" FOR VARS HERE
+
+       (ty_sigs, upragmas) = partition is_tysig_info sigs
+       inline_sigs         = filter is_inline_info   upragmas
+       deforest_sigs       = filter is_deforest_info upragmas
+       magic_uf_sigs       = filter is_magic_uf_info upragmas
+       spec_sigs           = filter is_spec_info     upragmas
+
+       unfold_me_fn n
+         = case [ x | x@(ValInlineInfo v _ _) <- inline_sigs, v == n ] of
+             (ValInlineInfo _ guide _ :_) -> iWantToBeINLINEd guide
+             [] ->
+               case [ x | x@(ValMagicUnfoldingInfo v _ _) <- magic_uf_sigs, v == n ] of
+                 (ValMagicUnfoldingInfo _ str _:_) -> mkMagicUnfolding str
+                 []                            -> noInfo_UF
+
+        deforest_me_fn n
+          = case [ x | x@(ValDeforestInfo v _) <- deforest_sigs, v == n ] of
+            (ValDeforestInfo _ _ : _) -> DoDeforest
+            [] -> Don'tDeforest
+
+       id_info_for n
+         = noIdInfo
+             `addInfo_UF` (unfold_me_fn   n)
+              `addInfo`    (deforest_me_fn n)
+
+       id_infos = [ id_info_for n | n <- bound_var_names ]
+    in
+    resolveOverloading top_level e free_tyvars tyvars_to_gen lie bind ty_sigs
+                `thenTc` \ (lie', reduced_tyvars_to_gen, dict_binds, dicts_bound) ->
+
+        -- BUILD THE NEW LOCALS
+    let
+       dict_tys = map getInstUniType dicts_bound
+
+       envs_and_new_locals_types
+         = map (quantifyTy reduced_tyvars_to_gen . glueTyArgs dict_tys) bound_var_types'
+
+       (_, new_locals_types) = unzip envs_and_new_locals_types
+    in
+        -- The new_locals function is passed into genBinds
+        -- so it can generate top-level or non-top-level locals
+    let
+       lve_of_new_ids = mkIdsWithGivenTys bound_var_names new_locals_types id_infos
+       new_ids = map snd lve_of_new_ids
+    in
+        -- BUILD RESULTS
+    returnTc (
+--     pprTrace "Gen: " (ppSep [ppr PprDebug new_ids, 
+--                              ppStr "; to gen ", ppr PprDebug tyvars_to_gen,
+--                              ppStr "; reduced ", ppr PprDebug reduced_tyvars_to_gen
+--             ]) $
+        AbsBinds reduced_tyvars_to_gen (map mkInstId dicts_bound)
+                (bound_var_locals `zip` new_ids)
+                dict_binds bind,
+        lie',
+        lve_of_new_ids
+    )
+  where
+    is_tysig_info (TySigInfo _ _ _ _ _) = True
+    is_tysig_info _                    = False
+
+    is_inline_info (ValInlineInfo _ _ _) = True
+    is_inline_info _ = False
+
+    is_deforest_info (ValDeforestInfo _ _) = True
+    is_deforest_info _ = False
+    is_magic_uf_info (ValMagicUnfoldingInfo _ _ _) = True
+    is_magic_uf_info _ = False
+
+    is_spec_info (ValSpecInfo _ _ _ _) = True
+    is_spec_info _ = False
+\end{code}
+
+
+\begin{code}
+resolveOverloading 
+       :: Bool                 -- True <=> top level
+       -> E
+       -> [TyVar]              -- Tyvars free in E
+       -> [TyVar]              -- Tyvars over which we are going to generalise
+       -> LIE                  -- The LIE to deal with
+       -> TypecheckedBind      -- The binding group
+       -> [SignatureInfo]      -- And its real type-signature information
+       -> TcM (LIE,                    -- LIE to pass up the way; a fixed point of
+                                       -- the current substitution
+               [TyVar],                -- Revised tyvars to generalise
+               [(Inst, TypecheckedExpr)],-- Dict bindings
+               [Inst])                 -- List of dicts to bind here
+                      
+resolveOverloading top_level e free_tyvars tyvars_to_gen lie bind ty_sigs
+  = let
+       dicts = unMkLIE lie
+    in
+        -- DEAL WITH MONOMORPHISM RESTRICTION
+    if (not (isUnRestrictedGroup tysig_vars bind)) then 
+
+       -- Restricted group, so bind no dictionaries, and
+       -- remove from tyvars_to_gen any constrained type variables
+
+       -- *Don't* simplify dicts at this point, because we aren't going
+       -- to generalise over these dicts.  By the time we do simplify them
+       -- we may well know more.  For example (this actually came up)
+       --      f :: Array Int Int
+       --      f x = array ... xs where xs = [1,2,3,4,5]
+       -- We don't want to generate lots of (fromInt Int 1), (fromInt Int 2)
+       -- stuff.  If we simplify only at the f-binding (not the xs-binding)
+       -- we'll know that the literals are all Ints, and we can just produce
+       -- Int literals!
+
+       -- Find all the type variables involved in overloading 
+       -- These are the ones we *aren't* going to generalise.
+       -- We must be careful about doing this:
+       --  (a) If we fail to generalise a tyvar which is not actually
+       --      constrained, then it will never, ever get bound, and lands 
+       --      up printed out in interface files!  Notorious example:
+       --              instance Eq a => Eq (Foo a b) where ..
+       --      Here, b is not constrained, even though it looks as if it is.
+       --      Another, more common, example is when there's a Method inst in
+       --      the LIE, whose type might very well involve non-overloaded
+       --      type variables.
+       --  (b) On the other hand, we mustn't generalise tyvars which are constrained,
+       --      because we are going to pass on out the unmodified LIE, with those 
+       --      tyvars in it.  They won't be in scope if we've generalised them.
+       --
+       -- So we are careful, and do a complete simplification just to find the
+       -- constrained tyvars. We don't use any of the results, except to
+       -- find which tyvars are constrained.
+
+       tcSimplify top_level free_tyvars tyvars_to_gen dicts
+                                   `thenTc` \ (_, _, dicts_sig) ->
+
+-- ASSERT: tcSimplify has already applied subst to its results
+-- (WDP/SLPJ 95/07)
+--     applyTcSubstToInsts dicts_sig   `thenNF_Tc`     \ dicts_sig' ->
+       let
+         constrained_tyvars
+           = foldr (unionLists . extractTyVarsFromInst) [] dicts_sig
+
+         reduced_tyvars_to_gen = tyvars_to_gen `minusList` constrained_tyvars
+
+         increased_free_tyvars = free_tyvars `unionLists` constrained_tyvars
+       in
+
+       -- Do it again, but with increased_free_tyvars/reduced_tyvars_to_gen:
+
+       tcSimplify top_level increased_free_tyvars reduced_tyvars_to_gen dicts
+                                   `thenTc` \ (dicts_free, dicts_binds, dicts_sig2) ->
+--NB: still no applyTcSubstToInsts
+
+--     pprTrace "resolve:" (ppCat [ppr PprDebug free_tyvars, ppr PprDebug tyvars_to_gen, ppr PprDebug constrained_tyvars, ppr PprDebug reduced_tyvars_to_gen, ppr PprDebug bind]) $
+       returnTc (mkLIE (dicts_free++dicts_sig2), -- All these are left unbound
+                 reduced_tyvars_to_gen, 
+                 dicts_binds,                  -- Local dict binds
+                 [])                           -- No lambda-bound dicts
+
+               -- The returned LIE should be a fixed point of the substitution
+
+    else -- Unrestricted group
+       case ty_sigs of
+        [] ->  -- NO TYPE SIGNATURES
+
+           tcSimplify top_level free_tyvars tyvars_to_gen dicts
+                                   `thenTc` \ (dicts_free, dict_binds, dicts_sig) ->
+           returnTc (mkLIE dicts_free, tyvars_to_gen, dict_binds, dicts_sig)
+
+        other -> -- TYPE SIGNATURES PRESENT!
+
+               -- Check that all the signature contexts are identical
+               -- "tysig_dicts_s" is a list (one for each id declared
+               -- in this group) of lists of dicts (the list
+               -- corresponds to the context in the sig).
+               -- "dicts_sig" is just the first such list; we match
+               -- it against all the others.
+
+           mapNF_Tc applyTcSubstToInsts tysig_dicts_s
+                               `thenNF_Tc` \ (dicts_sig : other_dicts_s) ->
+
+           checkTc (not (all (same_dicts dicts_sig) other_dicts_s))
+               -- The type signatures on a mutually-recursive group of definitions
+               -- must all have the same context (or none).  See Errors.lhs.
+               (sigContextsErr ty_sigs) `thenTc_`
+
+                   -- Check that the needed dicts can be expressed in
+                   -- terms of the signature ones
+           tcSimplifyAndCheck
+               top_level
+               free_tyvars     -- Vars free in the environment
+               tyvars_to_gen   -- Type vars over which we will quantify
+               dicts_sig       -- Available dicts
+               dicts           -- Want bindings for these dicts
+               (BindSigCtxt tysig_vars)
+
+                                   `thenTc` \ (dicts_free, dict_binds) ->
+
+           returnTc (mkLIE dicts_free, tyvars_to_gen, dict_binds, dicts_sig)
+  where
+    tysig_dicts_s = [dicts   | (TySigInfo _       _ dicts _ _) <- ty_sigs]
+    tysig_vars    = [sig_var | (TySigInfo sig_var _ _     _ _) <- ty_sigs] 
+
+       -- same_dicts checks that (post substitution) all the type signatures
+       -- constrain the same type variables in the same way
+    same_dicts []      []       = True
+    same_dicts []      _        = False
+    same_dicts _       []       = False
+    same_dicts (d1:d1s) (d2:d2s) = matchesInst d1 d2 && same_dicts d1s d2s
+
+    -- don't use the old version, because zipWith will truncate
+    -- the longer one!
+    --OLD: same_dicts dicts1 dicts2 = and (zipWith matchesInst dicts1 dicts2)
+\end{code}
+
+@checkSigMatch@ does the next step in checking signature matching.
+The tau-type part has already been unified.  What we do here is to
+check that this unification has not over-constrained the (polymorphic)
+type variables of the original signature type.
+
+The error message here is somewhat unsatisfactory, but it'll do for
+now (ToDo).
+
+\begin{code}
+checkSigMatch :: [TyVar]       -- Free in environment
+             -> SignatureInfo
+             -> TcM [TyVar]
+
+checkSigMatch env_tyvars (TySigInfo name sig_tyvars _ tau_ty src_loc)
+  = let
+       inferred_ty = getIdUniType name
+    in
+    addSrcLocTc src_loc        (
+    checkSigTyVars env_tyvars sig_tyvars tau_ty inferred_ty
+                  (SigCtxt name tau_ty)
+    )
+
+checkSigMatch _ other_not_really_a_sig = returnTc []
+\end{code}
+
+
+%************************************************************************
+%*                                                                     *
+\subsection[GenEtc-monomorphism]{The monomorphism restriction}
+%*                                                                     *
+%************************************************************************
+
+Not exported:
+
+\begin{code}
+isUnRestrictedGroup :: [Id]            -- Signatures given for these
+                    -> TypecheckedBind
+                    -> Bool
+
+isUnRestrictedGroup sigs EmptyBind              = True
+isUnRestrictedGroup sigs (NonRecBind monobinds) = isUnResMono sigs monobinds
+isUnRestrictedGroup sigs (RecBind monobinds)    = isUnResMono sigs monobinds
+
+is_elem = isIn "isUnResMono"
+
+isUnResMono sigs EmptyMonoBinds = True
+isUnResMono sigs (AndMonoBinds mb1 mb2) = isUnResMono sigs mb1 && isUnResMono sigs mb2
+isUnResMono sigs (PatMonoBind (VarPat v) _ _)  = v `is_elem` sigs
+isUnResMono sigs (PatMonoBind other      _ _)  = False
+isUnResMono sigs (VarMonoBind v _)             = v `is_elem` sigs
+isUnResMono sigs (FunMonoBind _ _ _)           = True
+\end{code}
+
+
+%************************************************************************
+%*                                                                     *
+\subsection[GenEtc-sig]{Matching a type signature}
+%*                                                                     *
+%************************************************************************
+
+@checkSigTyVars@ is used after the type in a type signature has been unified with
+the actual type found.  It then checks that the type variables of the type signature
+are 
+       (a) still all type variables
+               eg matching signature [a] against inferred type [(p,q)]
+               [then a will be unified to a non-type variable]
+
+       (b) still all distinct
+               eg matching signature [(a,b)] against inferred type [(p,p)]
+               [then a and b will be unified together]
+
+       (c) not mentioned in the environment
+               eg the signature for f in this:
+
+                       g x = ... where
+                                       f :: a->[a]
+                                       f y = [x,y]
+       
+               Here, f is forced to be monorphic by the free occurence of x.
+
+Before doing this, the substitution is applied to the signature type variable.
+
+It's {\em assumed} that the substitution has already been applied to the 
+environment type variables.
+
+\begin{code}
+checkSigTyVars :: [TyVar]      -- Tyvars free in environment; 
+                               -- fixed points of substitution
+              -> [TyVar]       -- The original signature type variables
+              -> UniType       -- signature type (for err msg)
+              -> UniType       -- inferred type (for err msg)
+              -> UnifyErrContext -- also for error msg
+              -> TcM [TyVar]   -- Post-substitution signature type variables
+
+checkSigTyVars env_tyvars sig_tyvars sig_tau inferred_tau err_ctxt
+  = getSrcLocTc                                        `thenNF_Tc` \ locn ->
+    applyTcSubstToTy inferred_tau              `thenNF_Tc` \ inferred_tau' ->
+    let
+       match_err = badMatchErr sig_tau inferred_tau' err_ctxt locn
+    in
+    applyTcSubstToTyVars sig_tyvars    `thenNF_Tc` \ sig_tys ->
+
+        -- Check point (a) above
+    checkMaybesTc (map getTyVarMaybe sig_tys) match_err        `thenTc` \ sig_tyvars' ->
+
+        -- Check point (b)
+    checkTc (not (hasNoDups sig_tyvars')) match_err    `thenTc_`
+
+       -- Check point (c)
+       -- We want to report errors in terms of the original signature tyvars, 
+       -- ie sig_tyvars, NOT sig_tyvars'.  sig_tys and sig_tyvars' correspond
+       -- 1-1 with sig_tyvars, so we can just map back.
+    let
+       is_elem = isIn "checkSigTyVars"
+
+       mono_tyvars = [ sig_tyvar 
+                     | (sig_tyvar,sig_tyvar') <- zipEqual sig_tyvars sig_tyvars',
+                       sig_tyvar' `is_elem` env_tyvars
+                     ]
+    in
+    checkTc (not (null mono_tyvars))
+           (notAsPolyAsSigErr sig_tau mono_tyvars err_ctxt locn) `thenTc_`
+
+    returnTc sig_tyvars'
+\end{code}