X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=ghc%2Fcompiler%2Ftypecheck%2FTcInstUtil.lhs;h=083ea7977eb074df206703a4d44ce8fc983261e2;hb=1b91b7e5adb10bb9d9c6bfe6112f3ef03ab47e31;hp=c30a90ae9245ca67fe5cac96867ec6618098fd1b;hpb=26741ec416bae2c502ef00a2ba0e79050a32cb67;p=ghc-hetmet.git diff --git a/ghc/compiler/typecheck/TcInstUtil.lhs b/ghc/compiler/typecheck/TcInstUtil.lhs index c30a90a..083ea79 100644 --- a/ghc/compiler/typecheck/TcInstUtil.lhs +++ b/ghc/compiler/typecheck/TcInstUtil.lhs @@ -1,295 +1,388 @@ % -% (c) The GRASP/AQUA Project, Glasgow University, 1992-1996 +% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998 % \section[TcInstUtil]{Utilities for typechecking instance declarations} The bits common to TcInstDcls and TcDeriv. \begin{code} -#include "HsVersions.h" - module TcInstUtil ( - InstInfo(..), - mkInstanceRelatedIds, - buildInstanceEnvs + InstInfo(..), pprInstInfo, + simpleInstInfoTy, simpleInstInfoTyCon, simpleDFunClassTyCon, + + -- Instance environment + InstEnv, emptyInstEnv, extendInstEnv, + lookupInstEnv, InstLookupResult(..), + classInstEnv, classDataCon, + + isLocalInst ) where -IMP_Ubiq() - -import HsSyn ( MonoBinds, Fake, InPat, Sig ) -import RnHsSyn ( RenamedMonoBinds(..), RenamedSig(..), - RenamedInstancePragmas(..) ) - -import TcMonad hiding ( rnMtoTcM ) -import Inst ( InstanceMapper(..) ) - -import Bag ( bagToList ) -import Class ( GenClass, GenClassOp, SYN_IE(ClassInstEnv), - classBigSig, classOps, classOpLocalType ) -import CoreSyn ( GenCoreExpr(..), mkValLam, mkTyApp ) -import Id ( GenId, mkDictFunId, mkConstMethodId, mkSysLocal ) -import MatchEnv ( nullMEnv, insertMEnv ) -import Maybes ( MaybeErr(..), mkLookupFunDef ) -import Name ( getSrcLoc, Name{--O only-} ) -import PprType ( GenClass, GenType, GenTyVar ) -import Pretty -import SpecEnv ( SYN_IE(SpecEnv), nullSpecEnv, addOneToSpecEnv ) +#include "HsVersions.h" + +import RnHsSyn ( RenamedMonoBinds, RenamedSig ) + +import HscTypes ( InstEnv, ClsInstEnv, DFunId ) +import Class ( Class ) +import Var ( TyVar, Id ) +import VarSet ( unionVarSet, mkVarSet ) +import VarEnv ( TyVarSubstEnv ) +import Maybes ( MaybeErr(..), returnMaB, failMaB, thenMaB, maybeToBool ) +import Name ( getSrcLoc ) import SrcLoc ( SrcLoc ) -import Type ( mkSigmaTy, mkForAllTys, mkDictTy, mkTyVarTys, - splitForAllTy, instantiateTy, matchTy, SYN_IE(ThetaType) ) -import TyVar ( GenTyVar ) -import Unique ( Unique ) -import Util ( equivClasses, zipWithEqual, panic ) - -import IdInfo ( noIdInfo ) ---import TcPragmas ( tcDictFunPragmas, tcGenPragmas ) +import Type ( Type, ThetaType, splitTyConApp_maybe, + splitSigmaTy, splitDictTy, + tyVarsOfTypes ) +import PprType ( ) +import Class ( classTyCon ) +import DataCon ( DataCon ) +import TyCon ( TyCon, tyConDataCons ) +import Outputable +import Unify ( matchTys, unifyTyListsX ) +import UniqFM ( lookupWithDefaultUFM, addToUFM, emptyUFM ) +import Id ( idType ) +import ErrUtils ( Message ) +import CmdLineOpts \end{code} - instance c => k (t tvs) where b -\begin{code} -data InstInfo - = InstInfo - Class -- Class, k - [TyVar] -- Type variables, tvs - Type -- The type at which the class is being instantiated - ThetaType -- inst_decl_theta: the original context, c, from the - -- instance declaration. It constrains (some of) - -- the TyVars above - ThetaType -- dfun_theta: the inst_decl_theta, plus one - -- element for each superclass; the "Mark - -- Jones optimisation" - Id -- The dfun id - [Id] -- Constant methods (either all or none) - RenamedMonoBinds -- Bindings, b - Bool -- True <=> local instance decl - Module -- Name of module where this instance defined - SrcLoc -- Source location assoc'd with this instance's defn - [RenamedSig] -- User pragmas recorded for generating specialised instances -\end{code} %************************************************************************ %* * -\subsection{Creating instance related Ids} +\subsection{The InstInfo type} %* * %************************************************************************ +The InstInfo type summarises the information in an instance declaration + + instance c => k (t tvs) where b + \begin{code} -mkInstanceRelatedIds :: Bool - -> SrcLoc - -> Module - -> RenamedInstancePragmas - -> Class - -> [TyVar] - -> Type - -> ThetaType - -> [RenamedSig] - -> TcM s (Id, ThetaType, [Id]) - -mkInstanceRelatedIds from_here src_loc inst_mod inst_pragmas - clas inst_tyvars inst_ty inst_decl_theta uprags - = -- MAKE THE DFUN ID - let - dfun_theta = case inst_decl_theta of - [] -> [] -- If inst_decl_theta is empty, then we don't - -- want to have any dict arguments, so that we can - -- expose the constant methods. - - other -> inst_decl_theta ++ super_class_theta - -- Otherwise we pass the superclass dictionaries to - -- the dictionary function; the Mark Jones optimisation. - - dfun_ty = mkSigmaTy inst_tyvars dfun_theta (mkDictTy clas inst_ty) - in - tcGetUnique `thenNF_Tc` \ dfun_uniq -> - fixTc ( \ rec_dfun_id -> - -{- LATER - tcDictFunPragmas dfun_ty rec_dfun_id inst_pragmas - `thenNF_Tc` \ dfun_pragma_info -> - let - dfun_specenv = mkInstSpecEnv clas inst_ty inst_tyvars dfun_theta - dfun_id_info = dfun_pragma_info `addInfo` dfun_specenv - in --} - let dfun_id_info = noIdInfo in -- For now - - returnTc (mkDictFunId dfun_uniq clas inst_ty dfun_ty from_here src_loc inst_mod dfun_id_info) - ) `thenTc` \ dfun_id -> - - -- MAKE THE CONSTANT-METHOD IDS - -- if there are no type variables involved - (if not (null inst_decl_theta) - then - returnTc [] - else - mapTc mk_const_meth_id class_ops - ) `thenTc` \ const_meth_ids -> - - returnTc (dfun_id, dfun_theta, const_meth_ids) - where - (class_tyvar, super_classes, _, class_ops, _, _) = classBigSig clas - tenv = [(class_tyvar, inst_ty)] - - super_class_theta = super_classes `zip` repeat inst_ty - - mk_const_meth_id op - = tcGetUnique `thenNF_Tc` \ uniq -> - fixTc (\ rec_const_meth_id -> - -{- LATER - -- Figure out the IdInfo from the pragmas - (case assocMaybe opname_prag_pairs (getName op) of - Nothing -> returnTc inline_info - Just prag -> tcGenPragmas (Just meth_ty) rec_const_meth_id prag - ) `thenNF_Tc` \ id_info -> --} - let id_info = noIdInfo -- For now - in - returnTc (mkConstMethodId uniq clas op inst_ty meth_ty - from_here src_loc inst_mod id_info) - ) - where - op_ty = classOpLocalType op - meth_ty = mkForAllTys inst_tyvars (instantiateTy tenv op_ty) -{- LATER - inline_me = isIn "mkInstanceRelatedIds" op ops_to_inline - inline_info = if inline_me - then noIdInfo `addInfo_UF` (iWantToBeINLINEd UnfoldAlways) - else noIdInfo - - opname_prag_pairs = case inst_pragmas of - ConstantInstancePragma _ name_prag_pairs -> name_prag_pairs - other_inst_pragmas -> [] - - ops_to_inline = [op | (InlineSig op _) <- uprags] --} +data InstInfo + = InstInfo { + iClass :: Class, -- Class, k + iTyVars :: [TyVar], -- Type variables, tvs + iTys :: [Type], -- The types at which the class is being instantiated + iTheta :: ThetaType, -- inst_decl_theta: the original context, c, from the + -- instance declaration. It constrains (some of) + -- the TyVars above + iLocal :: Bool, -- True <=> it's defined in this module + iDFunId :: DFunId, -- The dfun id + iBinds :: RenamedMonoBinds, -- Bindings, b + iLoc :: SrcLoc, -- Source location assoc'd with this instance's defn + iPrags :: [RenamedSig] -- User pragmas recorded for generating specialised instances + } + +pprInstInfo info = vcat [ptext SLIT("InstInfo:") <+> ppr (idType (iDFunId info)), + nest 4 (ppr (iBinds info))] + +simpleInstInfoTy :: InstInfo -> Type +simpleInstInfoTy (InstInfo {iTys = [ty]}) = ty + +simpleInstInfoTyCon :: InstInfo -> TyCon + -- Gets the type constructor for a simple instance declaration, + -- i.e. one of the form instance (...) => C (T a b c) where ... +simpleInstInfoTyCon inst + = case splitTyConApp_maybe (simpleInstInfoTy inst) of + Just (tycon, _) -> tycon + +isLocalInst :: InstInfo -> Bool +isLocalInst info = iLocal info \end{code} +A tiny function which doesn't belong anywhere else. +It makes a nasty mutual-recursion knot if you put it in Class. + +\begin{code} +simpleDFunClassTyCon :: DFunId -> (Class, TyCon) +simpleDFunClassTyCon dfun + = (clas, tycon) + where + (_,_,dict_ty) = splitSigmaTy (idType dfun) + (clas, [ty]) = splitDictTy dict_ty + tycon = case splitTyConApp_maybe ty of + Just (tycon,_) -> tycon + +classDataCon :: Class -> DataCon +classDataCon clas = case tyConDataCons (classTyCon clas) of + (dict_constr:no_more) -> ASSERT( null no_more ) dict_constr +\end{code} + %************************************************************************ %* * -\subsection{Converting instance info into suitable InstEnvs} +\subsection{Instance environments: InstEnv and ClsInstEnv} %* * %************************************************************************ -\begin{code} -buildInstanceEnvs :: Bag InstInfo - -> TcM s InstanceMapper - -buildInstanceEnvs info - = let - icmp :: InstInfo -> InstInfo -> TAG_ - (InstInfo c1 _ _ _ _ _ _ _ _ _ _ _) `icmp` (InstInfo c2 _ _ _ _ _ _ _ _ _ _ _) - = c1 `cmp` c2 - - info_by_class = equivClasses icmp (bagToList info) - in - mapTc buildInstanceEnv info_by_class `thenTc` \ inst_env_entries -> - let - class_lookup_fn = mkLookupFunDef (==) inst_env_entries - (nullMEnv, \ o -> nullSpecEnv) - in - returnTc class_lookup_fn -\end{code} +The actual type declarations are in HscTypes. \begin{code} -buildInstanceEnv :: [InstInfo] -- Non-empty, and all for same class - -> TcM s (Class, (ClassInstEnv, (ClassOp -> SpecEnv))) - -buildInstanceEnv inst_infos@((InstInfo clas _ _ _ _ _ _ _ _ _ _ _) : _) - = foldlTc addClassInstance - (nullMEnv, [(op, nullSpecEnv) | op <- classOps clas]) - inst_infos - `thenTc` \ (class_inst_env, op_inst_envs) -> - returnTc (clas, (class_inst_env, - mkLookupFunDef (==) op_inst_envs - (panic "buildInstanceEnv"))) +emptyInstEnv :: InstEnv +emptyInstEnv = emptyUFM + +classInstEnv :: InstEnv -> Class -> ClsInstEnv +classInstEnv env cls = lookupWithDefaultUFM env [] cls \end{code} -@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. +A @ClsInstEnv@ lives inside a class, and identifies all the instances +of that class. The @Id@ inside a ClsInstEnv mapping is the dfun for +that instance. + +If class C maps to a list containing the item ([a,b], [t1,t2,t3], dfun), then + + forall a b, C t1 t2 t3 can be constructed by dfun + +or, to put it another way, we have + + instance (...) => C t1 t2 t3, witnessed by dfun + +There is an important consistency constraint in the elements of a ClsInstEnv: + + * [a,b] must be a superset of the free vars of [t1,t2,t3] + + * The dfun must itself be quantified over [a,b] + +Thus, the @ClassInstEnv@ for @Eq@ might contain the following entry: + [a] ===> dfun_Eq_List :: forall a. Eq a => Eq [a] +The "a" in the pattern must be one of the forall'd variables in +the dfun type. + + + +Notes on overlapping instances +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +In some ClsInstEnvs, overlap is prohibited; that is, no pair of templates unify. + +In others, overlap is permitted, but only in such a way that one can make +a unique choice when looking up. That is, overlap is only permitted if +one template matches the other, or vice versa. So this is ok: + + [a] [Int] + +but this is not + + (Int,a) (b,Int) + +If overlap is permitted, the list is kept most specific first, so that +the first lookup is the right choice. + + +For now we just use association lists. + +\subsection{Avoiding a problem with overlapping} + +Consider this little program: + +\begin{pseudocode} + class C a where c :: a + class C a => D a where d :: a + + instance C Int where c = 17 + instance D Int where d = 13 + + instance C a => C [a] where c = [c] + instance ({- C [a], -} D a) => D [a] where d = c + + instance C [Int] where c = [37] + + main = print (d :: [Int]) +\end{pseudocode} + +What do you think `main' prints (assuming we have overlapping instances, and +all that turned on)? Well, the instance for `D' at type `[a]' is defined to +be `c' at the same type, and we've got an instance of `C' at `[Int]', so the +answer is `[37]', right? (the generic `C [a]' instance shouldn't apply because +the `C [Int]' instance is more specific). + +Ghc-4.04 gives `[37]', while ghc-4.06 gives `[17]', so 4.06 is wrong. That +was easy ;-) Let's just consult hugs for good measure. Wait - if I use old +hugs (pre-September99), I get `[17]', and stranger yet, if I use hugs98, it +doesn't even compile! What's going on!? + +What hugs complains about is the `D [a]' instance decl. + +\begin{pseudocode} + ERROR "mj.hs" (line 10): Cannot build superclass instance + *** Instance : D [a] + *** Context supplied : D a + *** Required superclass : C [a] +\end{pseudocode} + +You might wonder what hugs is complaining about. It's saying that you +need to add `C [a]' to the context of the `D [a]' instance (as appears +in comments). But there's that `C [a]' instance decl one line above +that says that I can reduce the need for a `C [a]' instance to the +need for a `C a' instance, and in this case, I already have the +necessary `C a' instance (since we have `D a' explicitly in the +context, and `C' is a superclass of `D'). + +Unfortunately, the above reasoning indicates a premature commitment to the +generic `C [a]' instance. I.e., it prematurely rules out the more specific +instance `C [Int]'. This is the mistake that ghc-4.06 makes. The fix is to +add the context that hugs suggests (uncomment the `C [a]'), effectively +deferring the decision about which instance to use. + +Now, interestingly enough, 4.04 has this same bug, but it's covered up +in this case by a little known `optimization' that was disabled in +4.06. Ghc-4.04 silently inserts any missing superclass context into +an instance declaration. In this case, it silently inserts the `C +[a]', and everything happens to work out. + +(See `basicTypes/MkId:mkDictFunId' for the code in question. Search for +`Mark Jones', although Mark claims no credit for the `optimization' in +question, and would rather it stopped being called the `Mark Jones +optimization' ;-) + +So, what's the fix? I think hugs has it right. Here's why. Let's try +something else out with ghc-4.04. Let's add the following line: + + d' :: D a => [a] + d' = c + +Everyone raise their hand who thinks that `d :: [Int]' should give a +different answer from `d' :: [Int]'. Well, in ghc-4.04, it does. The +`optimization' only applies to instance decls, not to regular +bindings, giving inconsistent behavior. + +Old hugs had this same bug. Here's how we fixed it: like GHC, the +list of instances for a given class is ordered, so that more specific +instances come before more generic ones. For example, the instance +list for C might contain: + ..., C Int, ..., C a, ... +When we go to look for a `C Int' instance we'll get that one first. +But what if we go looking for a `C b' (`b' is unconstrained)? We'll +pass the `C Int' instance, and keep going. But if `b' is +unconstrained, then we don't know yet if the more specific instance +will eventually apply. GHC keeps going, and matches on the generic `C +a'. The fix is to, at each step, check to see if there's a reverse +match, and if so, abort the search. This prevents hugs from +prematurely chosing a generic instance when a more specific one +exists. + +--Jeff + + +@lookupInstEnv@ looks up in a @InstEnv@, using a one-way match. Since +the env is kept ordered, the first match must be the only one. The +thing we are looking up can have an arbitrary "flexi" part. \begin{code} -addClassInstance - :: (ClassInstEnv, [(ClassOp,SpecEnv)]) - -> InstInfo - -> TcM s (ClassInstEnv, [(ClassOp,SpecEnv)]) - -addClassInstance - (class_inst_env, op_spec_envs) - (InstInfo clas inst_tyvars inst_ty _ _ - dfun_id const_meth_ids _ _ _ src_loc _) - = - --- We only add specialised/overlapped instances --- if we are specialising the overloading --- ToDo ... This causes getConstMethodId errors! --- --- if not (is_plain_instance inst_ty) && not opt_SpecialiseOverloaded --- then --- -- Drop this specialised/overlapped instance --- returnTc (class_inst_env, op_spec_envs) --- else - - -- Add the instance to the class's instance environment - case insertMEnv matchTy class_inst_env inst_ty dfun_id of { - Failed (ty', dfun_id') -> dupInstFailure clas (inst_ty, src_loc) - (ty', getSrcLoc dfun_id'); - Succeeded class_inst_env' -> - - -- If there are any constant methods, then add them to - -- the SpecEnv of each class op (ie selector) - -- - -- Example. class Foo a where { op :: Baz b => a -> b } - -- instance Foo (p,q) where { op (x,y) = ... } - -- - -- The constant method from the instance decl will be: - -- op_Pair :: forall p q b. Baz b => (p,q) -> b - -- - -- What we put in op's SpecEnv is - -- (p,q) b |--> (\d::Foo (p,q) -> op_Pair p q b) - -- - -- Here, [p,q] are the inst_tyvars, and d is a dict whose only - -- purpose is to cancel with the dict to which op is applied. - -- - -- NOTE THAT this correctly deals with the case where there are - -- constant methods even though there are type variables in the - -- instance declaration. - - tcGetUnique `thenNF_Tc` \ uniq -> - let - dict = mkSysLocal SLIT("dict_tpl") uniq (mkDictTy clas inst_ty) src_loc - -- Slightly disgusting, but it's only a placeholder for - -- a dictionary to be chucked away. - - op_spec_envs' | null const_meth_ids = op_spec_envs - | otherwise = zipWithEqual "add_const_meth" add_const_meth op_spec_envs const_meth_ids - - add_const_meth (op,spec_env) meth_id - = (op, case addOneToSpecEnv spec_env (inst_ty : local_tyvar_tys) rhs of - Failed (tys', rhs') -> panic "TcInstDecls:add_const_meth" - Succeeded spec_env' -> spec_env' ) - where - (local_tyvars, _) = splitForAllTy (classOpLocalType op) - local_tyvar_tys = mkTyVarTys local_tyvars - rhs = mkValLam [dict] (mkTyApp (mkTyApp (Var meth_id) - (mkTyVarTys inst_tyvars)) - local_tyvar_tys) - in - returnTc (class_inst_env', op_spec_envs') - } +lookupInstEnv :: InstEnv -- The envt + -> Class -> [Type] -- Key + -> InstLookupResult + +data InstLookupResult + = FoundInst -- There is a (template,substitution) pair + -- that makes the template match the key, + -- and no template is an instance of the key + TyVarSubstEnv Id + + | NoMatch Bool -- Boolean is true iff there is at least one + -- template that matches the key. + -- (but there are other template(s) that are + -- instances of the key, so we don't report + -- FoundInst) + -- The NoMatch True case happens when we look up + -- Foo [a] + -- in an InstEnv that has entries for + -- Foo [Int] + -- Foo [b] + -- Then which we choose would depend on the way in which 'a' + -- is instantiated. So we say there is no match, but identify + -- it as ambiguous case in the hope of giving a better error msg. + -- See the notes above from Jeff Lewis + +lookupInstEnv env key_cls key_tys + = find (classInstEnv env key_cls) + where + key_vars = tyVarsOfTypes key_tys + + find [] = NoMatch False + find ((tpl_tyvars, tpl, val) : rest) + = case matchTys tpl_tyvars tpl key_tys of + Nothing -> + case matchTys key_vars key_tys tpl of + Nothing -> find rest + Just (_, _) -> NoMatch (any_match rest) + Just (subst, leftovers) -> ASSERT( null leftovers ) + FoundInst subst val + + any_match rest = or [ maybeToBool (matchTys tvs tpl key_tys) + | (tvs,tpl,_) <- rest + ] \end{code} +@addToClsInstEnv@ extends a @ClsInstEnv@, checking for overlaps. + +A boolean flag controls overlap reporting. + +True => overlap is permitted, but only if one template matches the other; + not if they unify but neither is + \begin{code} -dupInstFailure clas info1@(ty1, locn1) info2@(ty2, locn2) +extendInstEnv :: DynFlags -> InstEnv -> [DFunId] -> (InstEnv, [Message]) + -- Similar, but all we have is the DFuns +extendInstEnv dflags env infos + = go env [] infos + where + go env msgs [] = (env, msgs) + go env msgs (dfun:dfuns) = case addToInstEnv dflags env dfun of + Succeeded new_env -> go new_env msgs dfuns + Failed dfun' -> go env (msg:msgs) infos + where + msg = dupInstErr dfun dfun' + + +dupInstErr dfun1 dfun2 -- Overlapping/duplicate instances for given class; msg could be more glamourous - = tcAddErrCtxt ctxt $ - failTc (\sty -> ppStr "Duplicate or overlapping instance declarations") + = hang (ptext SLIT("Duplicate or overlapping instance declarations:")) + 2 (ppr_dfun dfun1 $$ ppr_dfun dfun2) + where + ppr_dfun dfun = ppr (getSrcLoc dfun) <> colon <+> ppr tau + where + (_,_,tau) = splitSigmaTy (idType dfun) + +addToInstEnv :: DynFlags + -> InstEnv -> DFunId + -> MaybeErr InstEnv -- Success... + DFunId -- Failure: Offending overlap + +addToInstEnv dflags inst_env dfun_id + = case insert_into (classInstEnv inst_env clas) of + Failed stuff -> Failed stuff + Succeeded new_env -> Succeeded (addToUFM inst_env clas new_env) + where - ctxt sty = ppHang (ppSep [ppBesides[ppStr "Class `", ppr sty clas, ppStr "'"], - ppBesides[ppStr "type `", ppr sty ty1, ppStr "'"]]) - 4 (ppSep [ppBesides [ppStr "at ", ppr sty locn1], - ppBesides [ppStr "and ", ppr sty locn2]]) + (ins_tvs, _, dict_ty) = splitSigmaTy (idType dfun_id) + (clas, ins_tys) = splitDictTy dict_ty + + ins_tv_set = mkVarSet ins_tvs + ins_item = (ins_tv_set, ins_tys, dfun_id) + + insert_into [] = returnMaB [ins_item] + insert_into env@(cur_item@(tpl_tvs, tpl_tys, val) : rest) + + -- FAIL if: + -- (a) they are the same, or + -- (b) they unify, and any sort of overlap is prohibited, + -- (c) they unify but neither is more specific than t'other + | identical + || (unifiable && not (dopt Opt_AllowOverlappingInstances dflags)) + || (unifiable && not (ins_item_more_specific || cur_item_more_specific)) + = failMaB val + + -- New item is an instance of current item, so drop it here + | ins_item_more_specific = returnMaB (ins_item : env) + + -- Otherwise carry on + | otherwise = insert_into rest `thenMaB` \ rest' -> + returnMaB (cur_item : rest') + where + unifiable = maybeToBool (unifyTyListsX (ins_tv_set `unionVarSet` tpl_tvs) tpl_tys ins_tys) + ins_item_more_specific = maybeToBool (matchTys tpl_tvs tpl_tys ins_tys) + cur_item_more_specific = maybeToBool (matchTys ins_tv_set ins_tys tpl_tys) + identical = ins_item_more_specific && cur_item_more_specific \end{code} + +