@@ -18,6 +18,8 @@ module Type.Unify ( Unify, UnifyError(..), runUnify, runUnifyEx
1818 , matchArguments
1919 , matchShape , pureMatchShape
2020 , extractNormalizeEffect
21+ , unexpectedEffectLabels
22+ , missingEffectLabels
2123 ) where
2224
2325import Control.Applicative
@@ -75,7 +77,7 @@ overlaps range free tp1 tp2
7577 fo1 = take hi (map snd fixed1 ++ map (unOptional . snd ) optional1 ++ map snd implicit1)
7678 fo2 = take hi (map snd fixed2 ++ map (unOptional . snd ) optional2 ++ map snd implicit2)
7779 in if (length fo1 /= length fo2)
78- then unifyError NoMatch -- one has more fixed arguments than the other can ever get
80+ then unifyError noMatchTypes -- one has more fixed arguments than the other can ever get
7981 else do unifies fo1 fo2
8082 return ()
8183
@@ -87,10 +89,10 @@ matchNamed matchSome range free tp n {- given args -} named mbExpResTp
8789 = do rho1 <- instantiate range tp
8890 case splitFunType rho1 of
8991 Nothing
90- -> unifyError NoMatch
92+ -> unifyError noMatchTypes
9193 Just (pars,_,resTp)
9294 -> if (n + length named > length pars)
93- then unifyError NoMatch
95+ then unifyError noMatchTypes
9496 else let npars = drop n pars
9597 names = map fst npars
9698 in if (all (\ name -> name `elem` names) named)
@@ -102,8 +104,8 @@ matchNamed matchSome range free tp n {- given args -} named mbExpResTp
102104 let rest = [(nm,tp) | (nm,tp) <- npars, not (nm `elem` named)]
103105 if (matchSome || all isOptionalOrImplicit rest)
104106 then subst rho1
105- else unifyError NoMatch
106- else unifyError NoMatch
107+ else unifyError noMatchTypes
108+ else unifyError noMatchTypes
107109
108110
109111-- | Does a function type match the given arguments? if the first argument 'matchSome' is true,
@@ -124,15 +126,15 @@ matchArguments matchSome range free tp fixed named mbExpResTp
124126
125127 Just (pars,_,resTp)
126128 -> if (length fixed + length named > length pars)
127- then unifyError NoMatch
129+ then unifyError noMatchTypes
128130 else do -- trace (" matchArguments: " ++ show (map pretty pars, map pretty fixed, map pretty named)) $ return ()
129131 -- subsume fixed parameters
130132 let parsNotNamedArg = filter (\ (nm,tp) -> nm `notElem` map fst named) pars
131133 let (fpars,rest) = splitAt (length fixed) parsNotNamedArg
132134 mapM_ (\ (tpar,targ) -> subsumeSubst range free (unOptional tpar) targ) (zip (map snd fpars) fixed)
133135 -- subsume named parameters
134136 mapM_ (\ (name,targ) -> case lookup name pars of
135- Nothing -> unifyError NoMatch
137+ Nothing -> unifyError noMatchTypes
136138 Just tpar -> subsumeSubst range free (unOptional tpar) targ
137139 ) named
138140 -- check if the result type matches
@@ -143,7 +145,7 @@ matchArguments matchSome range free tp fixed named mbExpResTp
143145 -- check the rest is optional or implicit
144146 if (matchSome || all isOptionalOrImplicit rest)
145147 then do subst rho1
146- else unifyError NoMatch
148+ else unifyError noMatchTypes
147149
148150subsumeSubst :: Range -> Tvs -> Type -> Type -> Unify (Type ,Rho , Core. Expr -> Core. Expr )
149151subsumeSubst range free tp1 tp2
@@ -160,9 +162,9 @@ matchShape tp1 tp2
160162 codom <- nub <$>
161163 mapM (\ (_,t) -> case t of
162164 TVar tv -> return tv
163- _ -> unifyError NoMatch ) (subList sub)
165+ _ -> unifyError noMatchTypes ) (subList sub)
164166 let oneToOne = (length dom == length codom)
165- if oneToOne then return () else unifyError NoMatch
167+ if oneToOne then return () else unifyError noMatchTypes
166168
167169pureMatchShape :: Type -> Type -> Bool
168170pureMatchShape tp1 tp2
@@ -272,8 +274,9 @@ unify f1@(TFun args1 eff1 res1) f2@(TFun args2 eff2 res2) | length args1 == leng
272274 withError (effErr) (unify eff1 eff2)
273275 where
274276 -- specialize to sub-part of the type for effect unification errors
275- effErr NoMatch = NoMatchEffect eff1 eff2
276- effErr (NoMatchEffect _ _) = NoMatchEffect eff1 eff2
277+ effErr (NoMatch diff) = NoMatchEffect eff1 eff2 (maybeEffectMismatch diff)
278+
279+ effErr (NoMatchEffect _ _ diff) = NoMatchEffect eff1 eff2 diff
277280 effErr err = err
278281
279282-- quantified types
@@ -321,9 +324,19 @@ unify tp1 (TSyn _ _ tp2)
321324unify (TVar (TypeVar _ kind Skolem )) (TVar (TypeVar _ _ Skolem ))
322325 = unifyError (NoMatchSkolem kind)
323326
327+ -- expected a skolem, got some other effect type
328+ unify (TVar (TypeVar _ kind Skolem )) tp2 | isKindEffect kind
329+ = -- trace ("no match (left is skolem): " ++ show (pretty tp2)) $
330+ unifyError $ NoMatch (Just $ effectMismatchMissing tp2)
331+
332+ -- expected `total`, got tp2
333+ unify tp1 tp2 | isEffectEmpty tp1
334+ = -- trace ("no match (left is total): " ++ show (pretty tp2)) $
335+ unifyError $ NoMatch (Just $ effectMismatchUnexpected tp2)
336+
324337unify tp1 tp2
325338 = -- trace ("no match: " ++ show (pretty tp1, pretty tp2)) $
326- unifyError NoMatch
339+ unifyError noMatchTypes
327340
328341
329342-- | Unify a type variable with a type
@@ -337,7 +350,7 @@ unifyTVar tv@(TypeVar id kind Meta) tp
337350 _ -> unifyError Infinite
338351 else case etp of
339352 TVar (TypeVar _ _ Bound )
340- -> unifyError NoMatch -- can't unify with bound variables
353+ -> unifyError noMatchTypes -- can't unify with bound variables
341354 TVar tv2@ (TypeVar id2 _ Meta ) | id <= id2
342355 -> if (id < id2)
343356 then unifyTVar tv2 (TVar tv)
@@ -477,11 +490,34 @@ data Res a = Ok !a !St
477490 | Err UnifyError ! St
478491data St = St { uniq :: ! Int , sub :: ! Sub }
479492
493+ data EffectMismatch = EffectMismatch
494+ { unexpectedEffectLabels :: [Type ]
495+ , missingEffectLabels :: [Type ]
496+ } deriving Show
497+
498+ maybeEffectMismatch (Just diff) = diff
499+ maybeEffectMismatch Nothing = EffectMismatch [] []
500+
501+ concreteEffectLabels typ = head ++ tailList
502+ where
503+ (head , tail ) = extractOrderedEffect typ
504+ tailList =
505+ if isEffectEmpty tail || isMeta tail then [] else [tail ]
506+
507+ isMeta (TVar (TypeVar _ kind Meta )) = True
508+ isMeta _ = False
509+
510+ effectMismatchUnexpected unexpected = EffectMismatch (concreteEffectLabels unexpected) []
511+
512+ effectMismatchMissing missing = EffectMismatch [] (concreteEffectLabels missing)
513+
514+ noMatchTypes = NoMatch Nothing
515+
480516data UnifyError
481- = NoMatch
517+ = NoMatch ( Maybe EffectMismatch )
482518 | NoMatchKind
483519 | NoMatchSkolem Kind
484- | NoMatchEffect Type Type
520+ | NoMatchEffect Type Type EffectMismatch
485521 | NoSubsume
486522 | Infinite
487523 | NoArgMatch Int Int
0 commit comments