[project @ 1996-01-08 20:28:12 by partain]
[ghc-hetmet.git] / ghc / compiler / envs / InstEnv.lhs
diff --git a/ghc/compiler/envs/InstEnv.lhs b/ghc/compiler/envs/InstEnv.lhs
new file mode 100644 (file)
index 0000000..edc3e2f
--- /dev/null
@@ -0,0 +1,549 @@
+%
+% (c) The GRASP/AQUA Project, Glasgow University, 1993-1995
+%
+\section[InstEnv]{Instance environments}
+
+\begin{code}
+#include "HsVersions.h"
+
+module InstEnv (
+       -- these types could use some abstractification (??? ToDo)
+       ClassInstEnv(..), -- OLD: IdInstEnv(..),
+       InstTemplate, InstTy,
+       MethodInstInfo(..),     -- needs to be exported? (ToDo)
+       InstanceMapper(..),     -- widely-used synonym
+
+--     instMethod, instTemplate, -- no need to export
+       addClassInst, {- NOT USED addConstMethInst, -}
+       lookupInst,
+       lookupClassInstAtSimpleType,
+       lookupNoBindInst,
+
+       MatchEnv(..),   -- mk more abstract (??? ToDo)
+       nullMEnv,
+--     mkMEnv, lookupMEnv, insertMEnv, -- no need to export
+
+       -- and to make the interface self-sufficient...
+       Class, ClassOp, CoreExpr, Expr, TypecheckedPat, Id,
+       Inst, InstOrigin, Maybe, MaybeErr, TyVarTemplate, TyCon,
+       UniType, SplitUniqSupply, SpecInfo
+    ) where
+
+IMPORT_Trace           -- ToDo: rm (debugging)
+
+import AbsPrel         ( intTyCon, --wordTyCon, addrTyCon,
+                         floatTyCon, doubleTyCon, charDataCon, intDataCon,
+                         wordDataCon, addrDataCon, floatDataCon,
+                         doubleDataCon,
+                         intPrimTyCon, doublePrimTyCon
+                       )
+import AbsSyn          -- TypecheckedExpr, etc.
+import AbsUniType
+import Id
+import IdInfo
+import Inst
+import Maybes          -- most of it
+import Outputable      ( isExported )
+import PlainCore       -- PlainCoreExpr, etc.
+import Pretty
+import PrimKind                -- rather grubby import (ToDo?)
+import SplitUniq
+import Util
+\end{code}
+
+%************************************************************************
+%*                                                                     *
+\subsection[InstEnv-types]{Type declarations}
+%*                                                                     *
+%************************************************************************
+
+\begin{code}
+type InstanceMapper
+  = Class -> (ClassInstEnv, ClassOp -> SpecEnv)
+
+type ClassInstEnv = MatchEnv UniType   InstTemplate -- Instances of dicts
+--OLD: type IdInstEnv = MatchEnv [UniType] InstTemplate -- Instances of ids
+
+data InstTemplate
+  = MkInstTemplate
+       Id              -- A fully polymorphic Id; it is the function
+                       -- which produces the Id instance or dict from
+                       -- the pieces specified by the rest of the
+                       -- template.  Its SrcLoc tells where the
+                       -- instance was defined.
+       [UniType]       -- Apply it to these types, suitably instantiated
+       [InstTy]        -- and instances of these things
+
+type MethodInstInfo = (Id, [UniType], InstTemplate) -- Specifies a method instance
+\end{code}
+
+There is an important consistency constraint between the @MatchEnv@s
+in and the @InstTemplate@s inside them: the @UniType@(s) which is/are
+the key for the @MatchEnv@ must contain only @TyVarTemplates@, and
+these must be a superset of the @TyVarTemplates@ mentioned in the
+corresponding @InstTemplate@.
+
+Reason: the lookup process matches the key against the desired value,
+returning a substitution which is used to instantiate the template.
+
+\begin{code}
+data InstTy
+  = DictTy     Class UniType
+  | MethodTy   Id    [UniType]
+\end{code}
+
+       MkInstTemplate f tvs insts
+
+says that, given a particular mapping of type variables tvs to some
+types tys, the value which is the required instance is
+
+       f tys (insts [tys/tvs])
+
+
+@instMethod@ is used if there is no instance for a method; then it is
+expressed in terms of the corresponding dictionary (or possibly, in a
+wired-in case only, dictionaries).
+
+\begin{code}
+instMethod :: SplitUniqSupply
+          -> InstOrigin
+          -> Id -> [UniType]
+          -> (TypecheckedExpr, [Inst])
+
+instMethod uniqs orig id tys
+  = (mkDictApp (mkTyApp (Var id) tys) dicts,
+     insts)
+  where
+   (tyvars, theta, tau_ty) = splitType (getIdUniType id)
+   tenv                           = tyvars `zipEqual` tys
+   insts                  = mk_dict_insts uniqs theta
+   dicts                  = map mkInstId insts
+
+   mk_dict_insts us [] = []
+   mk_dict_insts us ((clas, ty) : rest)
+      = case splitUniqSupply us of { (s1, s2) ->
+        (Dict (getSUnique s1) clas (instantiateTauTy tenv ty) orig)
+       : mk_dict_insts s2 rest
+       }
+\end{code}
+
+@instTemplate@ is used if there is an instance for a method or dictionary.
+
+\begin{code}
+instTemplate :: SplitUniqSupply
+            -> InstOrigin
+            -> [(TyVarTemplate, UniType)]
+            -> InstTemplate
+            -> (TypecheckedExpr, [Inst])
+
+instTemplate uniqs orig tenv (MkInstTemplate id ty_tmpls inst_tys)
+  = (mkDictApp (mkTyApp (Var id) ty_args) ids, -- ToDo: not strictly a dict app
+                                               -- for Method inst_tys
+     insts)
+  where
+    ty_args        = map (instantiateTy tenv) ty_tmpls
+    insts          = mk_insts uniqs inst_tys
+    ids                    = map mkInstId insts
+
+    mk_insts us [] = []
+    mk_insts us (inst_ty : rest)
+      = case splitUniqSupply us of { (s1, s2) ->
+       let
+           uniq = getSUnique s1
+       in
+        (case inst_ty of
+          DictTy clas ty  -> Dict uniq clas (instantiateTy tenv ty) orig
+          MethodTy id tys -> Method uniq id (map (instantiateTy tenv) tys) orig
+       ) : mk_insts s2 rest
+       }
+\end{code}
+
+
+%************************************************************************
+%*                                                                     *
+\subsection[InstEnv-adding]{Adding new class instances}
+%*                                                                     *
+%************************************************************************
+
+@addClassInstance@ adds the appropriate stuff to the @ClassInstEnv@ based on
+information from a single instance declaration.         It complains about
+any overlap with an existing instance.
+
+Notice that we manufacture the @DictFunId@ and @ConstMethodId@s from
+scratch here, rather than passing them in.  This means a small amount
+of duplication (no big deal) and that we can't attach a single
+canonical unfolding; but they don't have a slot for unfoldings
+anyway...  This could be improved.  (We do, however, snaffle in the
+pragma info from the interface...)
+
+{\em Random notes}
+
+\begin{verbatim}
+class Foo a where
+  fop :: Ord b => a -> b -> b -> a
+
+instance Foo Int where
+  fop x y z = if y<z then x else fop x z y
+
+instance Foo a => Foo [a] where
+  fop []     y z = []
+  fop (x:xs) y z = [fop x y z]
+\end{verbatim}
+
+
+For the Int instance we add to the ??? envt
+\begin{verbatim}
+  (ClassOpId Foo fop) |--> [Int,b] |--> InstTemplate (ConstMethodId Foo fop Int) [b] [Ord b]
+\end{verbatim}
+
+If there are no type variables, @addClassInstance@ adds constant
+instances for those class ops not mentioned in the class-op details
+(possibly using the pragma info that was passed in).  This MUST
+be the same decision as that by @tcInstDecls2@ about whether to
+generate constant methods.  NB: A slightly more permissive version
+would base the decision on the context being empty, but there is
+slightly more admin associated and the benefits are very slight; the
+context is seldom empty unless there are no tyvars involved.
+
+Note: the way of specifying class-op instance details is INADEQUATE
+for polymorphic class ops.  That just means you can't specify clever
+instances for them via this function.
+
+\begin{code}
+addClassInst
+    :: Class                   -- class in question (for err msg only)         
+    -> ClassInstEnv            -- Incoming envt
+    -> UniType                 -- The instance type
+    -> Id                      -- Dict fun id to apply
+    -> [TyVarTemplate]         -- Types to which (after instantiation) to apply the dfun
+    -> ThetaType               -- Dicts to which to apply the dfun
+    -> SrcLoc                  -- associated SrcLoc (for err msg only)
+    -> MaybeErr
+         ClassInstEnv          -- Success
+         (Class, (UniType, SrcLoc),  -- Failure: the overlapping pair
+                 (UniType, SrcLoc))
+
+addClassInst clas inst_env inst_ty dfun_id inst_tyvars dfun_theta locn
+  = case (insertMEnv matchTy inst_env inst_ty dict_template) of
+      Succeeded inst_env' -> Succeeded inst_env'
+      Failed (ty', MkInstTemplate id' _ _)
+       -> Failed (clas, (inst_ty, locn), (ty', getSrcLoc id'))
+  where
+    dict_template = MkInstTemplate dfun_id 
+                                  (map mkTyVarTemplateTy inst_tyvars) 
+                                  (unzipWith DictTy dfun_theta)
+\end{code}
+
+============ NOT USED =============
+@addConstMethInst@ panics on overlap, because @addClassInst@ has already found
+any overlap.
+
+\begin{pseudocode}
+addConstMethInst :: IdInstEnv
+                -> UniType             -- The instance type
+                -> Id                  -- The constant method
+                -> [TyVarTemplate]     -- Apply method to these (as above)
+                -> IdInstEnv
+
+addConstMethInst inst_env inst_ty meth_id inst_tyvars
+  = case (insertMEnv matchTys inst_env [inst_ty] template) of
+      Succeeded inst_env' -> inst_env'
+      Failed (tys', MkInstTemplate id' _ _) ->
+       pprPanic "addConstMethInst:"
+               (ppSep [ppr PprDebug meth_id,
+                       ppr PprDebug inst_ty,
+                       ppr PprDebug id'])
+  where
+     template = MkInstTemplate meth_id (map mkTyVarTemplateTy inst_tyvars) []
+       -- Constant method just needs to be applied to tyvars
+       -- (which are usually empty)
+\end{pseudocode}
+
+@mkIdInstEnv@ is useful in the simple case where we've a list of
+@(types, id)@ pairs; the \tr{id} is the \tr{types} specialisation of
+some other Id (in which the resulting IdInstEnv will doubtless be
+embedded.  There's no messing about with type variables or
+dictionaries here.
+
+\begin{code}
+{- OLD:
+mkIdInstEnv :: [([TauType],Id)] -> IdInstEnv
+
+mkIdInstEnv [] = nullMEnv
+mkIdInstEnv ((tys,id) : rest) 
+  = let
+       inst_env = mkIdInstEnv rest
+    in
+    case (insertMEnv matchTys inst_env tys template) of
+      Succeeded inst_env' -> inst_env'
+      Failed _ -> panic "Failed in mkIdInstEnv"
+  where
+    template = MkInstTemplate id [] []
+-}
+\end{code}
+
+%************************************************************************
+%*                                                                     *
+\subsection[InstEnv-lookup]{Performing lookup}
+%*                                                                     *
+%************************************************************************
+
+\begin{code}
+lookupInst :: SplitUniqSupply
+          -> Inst
+          -> Maybe (TypecheckedExpr,
+                    [Inst])
+
+lookupInst uniqs (Dict _ clas ty orig)
+  = if isTyVarTy ty then
+       Nothing -- No instances of a class at a type variable
+    else
+      case (lookupMEnv matchTy inst_env ty) of
+       Nothing             -> Nothing
+       Just (_,tenv,templ) -> Just (instTemplate uniqs orig tenv templ)
+  where
+    inst_env
+      = case orig of
+
+         -- During deriving and instance specialisation operations
+         -- we can't get the instances of the class from inside the
+         -- class, because the latter ain't ready yet.  Instead we
+         -- find a mapping from classes to envts inside the dict origin.
+         -- (A Simon hack [WDP])
+
+         DerivingOrigin inst_mapper _ _ _ _ -> fst (inst_mapper clas)
+
+         InstanceSpecOrigin inst_mapper _ _ _ -> fst (inst_mapper clas)
+
+         -- Usually we just get the instances of the class from
+         -- inside the class itself.
+
+         other -> getClassInstEnv clas
+
+lookupInst uniqs (Method _ id tys orig)
+  = if (all isTyVarTy tys) then
+       general_case    -- Instance types are all type variables, so there can't be
+                       -- a special instance for this method
+
+    else       -- Get the inst env from the Id, and look up in it
+      case (lookupSpecEnv (getIdSpecialisation id) tys) of
+       Nothing             -> general_case
+       Just (spec_id, types_left, num_dicts_to_toss)
+         -> Just (instMethod uniqs orig spec_id types_left)
+  where
+    general_case = Just (instMethod uniqs orig id tys)
+\end{code}
+
+Now "overloaded" literals: the plain truth is that the compiler
+is intimately familiar w/ the types Int, Integer, Float, and Double;
+for everything else, we actually conjure up an appropriately-applied
+fromInteger/fromRational, as the Haskell report suggests.
+
+\begin{code}
+lookupInst uniqs (LitInst u (OverloadedIntegral i from_int from_integer) ty orig)
+  = Just (
+    case (getUniDataTyCon_maybe ty) of -- this way is *unflummoxed* by synonyms
+      Just (tycon, [], _)
+        | tycon == intPrimTyCon                -> (intprim_lit,    [])
+       | tycon == doublePrimTyCon      -> (doubleprim_lit, [])
+        | tycon == intTyCon            -> (int_lit,        [])
+       | tycon == doubleTyCon          -> (double_lit,     [])
+       | tycon == floatTyCon           -> (float_lit,      [])
+--     | tycon == wordTyCon            -> (word_lit,       [])
+--     | tycon == addrTyCon            -> (addr_lit,       [])
+
+      _{-otherwise-} ->
+
+       if (i >= toInteger minInt && i <= toInteger maxInt) then
+           -- It's overloaded but small enough to fit into an Int
+
+           let u2              = getSUnique uniqs
+               method  = Method u2 from_int [ty] orig
+           in
+           (App (Var (mkInstId method)) int_lit, [method])
+
+       else
+           -- Alas, it is overloaded and a big literal!
+
+           let u2         = getSUnique uniqs
+               method = Method u2 from_integer [ty] orig
+           in
+           (App (Var (mkInstId method)) (Lit (IntLit i)), [method])
+    )
+  where
+#if __GLASGOW_HASKELL__ <= 22
+    iD = ((fromInteger i) :: Double)
+#else
+    iD = ((fromInteger i) :: Rational)
+#endif
+    intprim_lit    = Lit (IntPrimLit i)
+    doubleprim_lit = Lit (DoublePrimLit iD)
+    int_lit        = App (Var intDataCon)    intprim_lit
+    double_lit     = App (Var doubleDataCon) doubleprim_lit
+    float_lit      = App (Var floatDataCon)  (Lit (FloatPrimLit iD))
+--  word_lit       = App (Var wordDataCon)   intprim_lit
+--  addr_lit       = App (Var addrDataCon)   intprim_lit
+
+lookupInst uniqs (LitInst u (OverloadedFractional f from_rational) ty orig)
+  = Just (
+    case (getUniDataTyCon_maybe ty) of -- this way is *unflummoxed* by synonyms
+      Just (tycon, [], _)
+       | tycon == doublePrimTyCon -> (doubleprim_lit, [])
+       | tycon == doubleTyCon     -> (double_lit, [])
+       | tycon == floatTyCon      -> (float_lit,  [])
+
+      _ {-otherwise-} ->    -- gotta fromRational it...
+       --pprTrace "lookupInst:fractional lit ty?:" (ppr PprDebug ty) (
+       let
+           u2     = getSUnique uniqs
+           method = Method u2 from_rational [ty] orig
+       in
+       (App (Var (mkInstId method)) (Lit (FracLit f)), [method])
+       --)
+    )
+  where
+#if __GLASGOW_HASKELL__ <= 22
+    fD = ((fromRational f) :: Double)
+#else
+    fD = f
+#endif
+    doubleprim_lit = Lit (DoublePrimLit fD)
+    double_lit     = App (Var doubleDataCon) doubleprim_lit
+    float_lit      = App (Var floatDataCon)  (Lit (FloatPrimLit  fD))
+\end{code}
+
+There is a second, simpler interface, when you want an instance
+of a class at a given nullary type constructor.         It just returns
+the appropriate dictionary if it exists.  It is used only when resolving
+ambiguous dictionaries.
+
+\begin{code}
+lookupClassInstAtSimpleType :: Class -> UniType -> Maybe Id
+
+lookupClassInstAtSimpleType clas ty
+  = case (lookupMEnv matchTy (getClassInstEnv clas) ty) of
+      Nothing                             -> Nothing
+      Just (_,_,MkInstTemplate dict [] []) -> Just dict
+\end{code}
+
+Notice in the above that the type constructors in the default list
+should all have arity zero, so there should be no type variables
+or thetas in the instance declaration.
+
+There's yet a third interface for Insts which need no binding.
+They are used to record constraints on type variables, notably
+for CCall arguments and results.
+
+\begin{code}
+lookupNoBindInst :: SplitUniqSupply
+                -> Inst
+                -> Maybe [Inst]
+
+lookupNoBindInst uniqs (Dict _ clas ty orig)
+  = if isTyVarTy ty then
+       Nothing -- No instances of a class at a type variable
+    else
+      case (lookupMEnv matchTy inst_env ty) of
+       Nothing             -> Nothing
+       Just (_,tenv,templ) ->
+         case (instTemplate uniqs orig tenv templ) of
+           (bottom_rhs, insts)
+             -> Just insts
+               -- The idea here is that the expression built by
+               -- instTemplate isn't relevant; indeed, it might well
+               -- be a place-holder bottom value.
+  where
+    inst_env = getClassInstEnv clas
+\end{code}
+
+%************************************************************************
+%*                                                                     *
+\subsection[MatchEnv]{Matching environments}
+%*                                                                     *
+%************************************************************************
+
+``Matching'' environments allow you to bind a template to a value;
+when you look up in it, you supply a value which is matched against
+the template.
+
+\begin{code}
+type MatchEnv key value = [(key, value)]
+\end{code}
+
+For now we just use association lists. The list is maintained sorted
+in order of {\em decreasing specificness} of @key@, so that the first
+match will be the most specific.
+
+\begin{code}
+nullMEnv :: MatchEnv a b
+nullMEnv = []
+
+mkMEnv :: [(key, value)] -> MatchEnv key value
+mkMEnv stuff = stuff
+\end{code}
+
+@lookupMEnv@ looks up in a @MatchEnv@.
+It
+simply takes the first match, should be the most specific.
+
+\begin{code}
+lookupMEnv :: (key {- template -} ->   -- Matching function
+              key {- instance -} ->
+              Maybe match_info)
+          -> MatchEnv key value        -- The envt
+          -> key                       -- Key
+          -> Maybe (key,               -- Template
+                    match_info,        -- Match info returned by matching fn
+                    value)             -- Value
+
+lookupMEnv key_match alist key
+  = find alist
+  where
+    find [] = Nothing
+    find ((tpl, val) : rest)
+      = case key_match tpl key of
+         Nothing         -> find rest
+         Just match_info -> Just (tpl, match_info, val)
+\end{code}
+
+@insertMEnv@ extends a match environment, checking for overlaps.
+
+\begin{code}
+insertMEnv :: (key {- template -} ->           -- Matching function
+              key {- instance -} ->
+              Maybe match_info)
+          -> MatchEnv key value                -- Envt
+          -> key -> value                      -- New item
+          -> MaybeErr (MatchEnv key value)     -- Success...
+                      (key, value)             -- Failure: Offending overlap
+
+insertMEnv match_fn alist key value
+  = insert alist
+  where
+    -- insert has to put the new item in BEFORE any keys which are
+    -- LESS SPECIFIC than the new key, and AFTER any keys which are
+    -- MORE SPECIFIC The list is maintained in specific-ness order, so
+    -- we just stick it in either last, or just before the first key
+    -- of which the new key is an instance.  We check for overlap at
+    -- that point.
+
+    insert [] = returnMaB [(key, value)]
+    insert ((t,v) : rest)
+      = case (match_fn t key) of
+         Nothing ->
+           -- New key is not an instance of this existing one, so
+           -- continue down the list.
+           insert rest                 `thenMaB` (\ rest' ->
+           returnMaB ((t,v):rest') )
+
+         Just match_info ->
+           -- New key *is* an instance of the old one, so check the
+           -- other way round in case of identity.
+
+           case (match_fn key t) of
+             Just _  -> failMaB (t,v)
+                        -- Oops; overlap
+
+             Nothing -> returnMaB ((key,value):(t,v):rest)
+                        -- All ok; insert here
+\end{code}