--
normaliseDicts :: Bool -> [Inst] -> TcM EqConfig
normaliseDicts isWanted insts
- = do { traceTc $ ptext (sLit "Entering normaliseDicts") <+>
- ptext (if isWanted then sLit "[Wanted]" else sLit "[Local]")
+ = do { traceTc $ hang (ptext (sLit "Entering normaliseDicts") <+>
+ ptext (if isWanted then sLit "[Wanted] for"
+ else sLit "[Local] for"))
+ 4 (ppr insts)
; (insts', eqss, bindss, skolemss) <- mapAndUnzip4M (normDict isWanted)
insts
+
+ ; traceTc $ hang (ptext (sLit "normaliseDicts returns"))
+ 4 (ppr insts' $$ ppr eqss)
; return $ emptyEqConfig { eqs = concat eqss
, locals = if isWanted then [] else insts'
, wanteds = if isWanted then insts' else []
-- Normalise one equality.
normEqInst inst
= ASSERT( isEqInst inst )
- go ty1 ty2 (eqInstCoercion inst)
+ do { traceTc $ ptext (sLit "normEqInst of ") <+>
+ pprEqInstCo co <+> text "::" <+>
+ ppr ty1 <+> text "~" <+> ppr ty2
+ ; res <- go ty1 ty2 co
+ ; traceTc $ ptext (sLit "normEqInst returns") <+> ppr res
+ ; return res
+ }
where
(ty1, ty2) = eqInstTys inst
+ co = eqInstCoercion inst
-- look through synonyms
go ty1 ty2 co | Just ty1' <- tcView ty1 = go ty1' ty2 co
go ty1 ty2 co | Just ty2' <- tcView ty2 = go ty1 ty2' co
-- left-to-right rule with type family head
- go (TyConApp con args) ty2 co
- | isOpenSynTyCon con
+ go ty1@(TyConApp con args) ty2 co
+ | isOpenSynTyConApp ty1 -- only if not oversaturated
= mkRewriteFam False con args ty2 co
-- right-to-left rule with type family head
go ty1 ty2@(TyConApp con args) co
- | isOpenSynTyCon con
+ | isOpenSynTyConApp ty2 -- only if not oversaturated
= do { co' <- mkSymEqInstCo co (ty2, ty1)
; mkRewriteFam True con args ty1 co'
}
-- NB: We cannot assume that the two types already have outermost type
-- synonyms expanded due to the recursion in the case of type applications.
checkOrientation ty1 ty2 co inst
- = do { traceTc $ ptext (sLit "checkOrientation of ") <+>
- pprEqInstCo co <+> text "::" <+>
- ppr ty1 <+> text "~" <+> ppr ty2
- ; eqs <- go ty1 ty2
- ; traceTc $ ptext (sLit "checkOrientation returns") <+> ppr eqs
- ; return eqs
- }
+ = go ty1 ty2
where
-- look through synonyms
go ty1 ty2 | Just ty1' <- tcView ty1 = go ty1' ty2
go ty@(TyVarTy _)
= return (ty, ty, [] , emptyVarSet)
- -- type family application
+ -- type family application & family arity matches number of args
-- => flatten to "gamma :: F t1'..tn' ~ alpha" (alpha & gamma fresh)
go ty@(TyConApp con args)
- | isOpenSynTyCon con
+ | isOpenSynTyConApp ty -- only if not oversaturated
= do { (args', cargs, args_eqss, args_skolemss) <- mapAndUnzip4M go args
; alpha <- newFlexiTyVar (typeKind ty)
; let alphaTy = mkTyVarTy alpha
-- data constructor application => flatten subtypes
-- NB: Special cased for efficiency - could be handled as type application
go ty@(TyConApp con args)
+ | not (isOpenSynTyCon con) -- don't match oversaturated family apps
= do { (args', cargs, args_eqss, args_skolemss) <- mapAndUnzip4M go args
; if null args_eqss
then -- unchanged, keep the old type with folded synonyms
}
-- type application => flatten subtypes
- go ty@(AppTy ty_l ty_r)
+ go ty
+ | Just (ty_l, ty_r) <- repSplitAppTy_maybe ty
+ -- need to use the smart split as ty may be an
+ -- oversaturated family application
= do { (ty_l', co_l, eqs_l, skolems_l) <- go ty_l
; (ty_r', co_r, eqs_r, skolems_r) <- go ty_r
; if null eqs_l && null eqs_r
go (PredTy _)
= panic "TcTyFuns.flattenType: unexpected PredType"
+ go _ = panic "TcTyFuns: suppress bogus warning"
+
adjustCoercions :: EqInstCo -- coercion of original equality
-> Coercion -- coercion witnessing the left rewrite
-> Coercion -- coercion witnessing the right rewrite
where
loc = tci_loc dict
--- gamma :: Fam args ~ alpha
--- => alpha :: Fam args ~ alpha, with alpha := Fam args
+-- gamma ::^l Fam args ~ alpha
+-- => gamma ::^w Fam args ~ alpha, with alpha := Fam args & gamma := Fam args
-- (the update of alpha will not be apparent during propagation, as we
-- never follow the indirections of meta variables; it will be revealed
-- when the equality is zonked)
+--
+-- NB: It's crucial to update *both* alpha and gamma, as gamma may already
+-- have escaped into some other coercions during normalisation.
+--
wantedToLocal :: RewriteInst -> TcM RewriteInst
wantedToLocal eq@(RewriteFam {rwi_fam = fam,
rwi_args = args,
- rwi_right = alphaTy@(TyVarTy alpha)})
+ rwi_right = TyVarTy alpha,
+ rwi_co = Left gamma})
= do { writeMetaTyVar alpha (mkTyConApp fam args)
- ; return $ eq {rwi_co = mkGivenCo alphaTy}
+ ; writeMetaTyVar gamma (mkTyConApp fam args)
+ ; return $ eq {rwi_co = mkGivenCo $ mkTyVarTy gamma}
}
wantedToLocal _ = panic "TcTyFuns.wantedToLocal"
\end{code}
}
where
substRules eq1 eq2
- = do { -- try the SubstFam rule
- optEqs <- applySubstFam eq1 eq2
+ = do {traceTc $ hang (ptext (sLit "Trying subst rules with"))
+ 4 (ppr eq1 $$ ppr eq2)
+
+ -- try the SubstFam rule
+ ; optEqs <- applySubstFam eq1 eq2
; case optEqs of
Just (eqs, skolems) -> return (eqs, [], skolems)
Nothing -> do
-> TcM (Maybe ([RewriteInst], TyVarSet))
applySubstFam eq1@(RewriteFam {rwi_fam = fam1, rwi_args = args1})
eq2@(RewriteFam {rwi_fam = fam2, rwi_args = args2})
+
+ -- rule matches => rewrite
| fam1 == fam2 && tcEqTypes args1 args2 &&
(isWantedRewriteInst eq2 || not (isWantedRewriteInst eq1))
-- !!!TODO: tcEqTypes is insufficient as it does not look through type synonyms
; eq2' <- deriveEqInst eq2 lhs rhs co2'
; liftM Just $ normEqInst eq2'
}
+
+ -- rule would match with eq1 and eq2 swapped => put eq2 into todo list
+ | fam1 == fam2 && tcEqTypes args1 args2 &&
+ (isWantedRewriteInst eq1 || not (isWantedRewriteInst eq2))
+ = return $ Just ([eq2], emptyVarSet)
+
where
lhs = rwi_right eq1
rhs = rwi_right eq2
co1 = eqInstCoType (rwi_co eq1)
co2 = rwi_co eq2
+
applySubstFam _ _ = return Nothing
\end{code}
-> TcM (Maybe ([RewriteInst], TyVarSet))
applySubstVarVar eq1@(RewriteVar {rwi_var = tv1})
eq2@(RewriteVar {rwi_var = tv2})
+
+ -- rule matches => rewrite
| tv1 == tv2 &&
(isWantedRewriteInst eq2 || not (isWantedRewriteInst eq1))
= do { co2' <- mkRightTransEqInstCo co2 co1 (lhs, rhs)
; eq2' <- deriveEqInst eq2 lhs rhs co2'
; liftM Just $ normEqInst eq2'
}
+
+ -- rule would match with eq1 and eq2 swapped => put eq2 into todo list
+ | tv1 == tv2 &&
+ (isWantedRewriteInst eq1 || not (isWantedRewriteInst eq2))
+ = return $ Just ([eq2], emptyVarSet)
+
where
lhs = rwi_right eq1
rhs = rwi_right eq2
co1 = eqInstCoType (rwi_co eq1)
co2 = rwi_co eq2
+
applySubstVarVar _ _ = return Nothing
\end{code}
\begin{code}
applySubstVarFam :: RewriteInst -> RewriteInst -> TcM (Maybe RewriteInst)
+
+ -- rule matches => rewrite
applySubstVarFam eq1@(RewriteVar {rwi_var = tv1})
eq2@(RewriteFam {rwi_fam = fam2, rwi_args = args2})
| tv1 `elemVarSet` tyVarsOfTypes args2
rhs2 = rwi_right eq2
co1 = eqInstCoType (rwi_co eq1)
co2 = rwi_co eq2
+
+ -- rule would match with eq1 and eq2 swapped => put eq2 into todo list
+applySubstVarFam (RewriteFam {rwi_args = args1})
+ eq2@(RewriteVar {rwi_var = tv2})
+ | tv2 `elemVarSet` tyVarsOfTypes args1
+ = return $ Just eq2
+
applySubstVarFam _ _ = return Nothing
\end{code}
\begin{code}
instantiateAndExtract :: [RewriteInst] -> Bool -> TyVarSet -> TcM ([Inst], Bool)
instantiateAndExtract eqs localsEmpty skolems
- = do { results <- mapM inst wanteds
+ = do { traceTc $ hang (ptext (sLit "instantiateAndExtract:"))
+ 4 (ppr eqs $$ ppr skolems)
+ ; results <- mapM inst wanteds
; let residuals = [eq | Left eq <- results]
only_skolems = and [tv `elemVarSet` skolems | Right tv <- results]
; residuals' <- mapM rewriteInstToInst residuals
checkingMode = length eqs > length wanteds || not localsEmpty
-- no local equalities or dicts => checking mode
+ -- co :: alpha ~ t or co :: a ~ alpha
inst eq@(RewriteVar {rwi_var = tv1, rwi_right = ty2, rwi_co = co})
-
- -- co :: alpha ~ t
- | isMetaTyVar tv1
- = doInst (rwi_swapped eq) tv1 ty2 co eq
-
- -- co :: a ~ alpha
- | Just tv2 <- tcGetTyVar_maybe ty2
- , isMetaTyVar tv2
- = doInst (not $ rwi_swapped eq) tv2 (mkTyVarTy tv1) co eq
+ = do { flexi_tv1 <- isFlexible tv1
+ ; maybe_flexi_tv2 <- isFlexibleTy ty2
+ ; case (flexi_tv1, maybe_flexi_tv2) of
+ (True, _)
+ -> -- co :: alpha ~ t
+ doInst (rwi_swapped eq) tv1 ty2 co eq
+ (False, Just tv2)
+ -> -- co :: a ~ alpha
+ doInst (not $ rwi_swapped eq) tv2 (mkTyVarTy tv1) co eq
+ _ -> return $ Left eq
+ }
-- co :: F args ~ alpha, and we are in checking mode (ie, no locals)
inst eq@(RewriteFam {rwi_fam = fam, rwi_args = args, rwi_right = ty2,
inst eq = return $ Left eq
+ -- tv is a meta var and not filled
+ isFlexible tv
+ | isMetaTyVar tv = liftM isFlexi $ readMetaTyVar tv
+ | otherwise = return False
+
+ -- type is a tv that is a meta var and not filled
+ isFlexibleTy ty
+ | Just tv <- tcGetTyVar_maybe ty = do {flexi <- isFlexible tv
+ ; if flexi then return $ Just tv
+ else return Nothing
+ }
+ | otherwise = return Nothing
+
doInst _swapped _tv _ty (Right ty) _eq
= pprPanic "TcTyFuns.doInst: local eq: " (ppr ty)
doInst swapped tv ty (Left cotv) eq