X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=compiler%2Ftypecheck%2FTcTyFuns.lhs;h=0066d2fd03e03f4fe6f71dbc0b8128bb8f4c5479;hb=27759873a8bd45c487a6e636f7a12c37e87f616f;hp=bed053d2d654e4f1ec1949f47f6ba96cc55d8040;hpb=654d07dd0fb679d014ac363e13c004b0086d0d6e;p=ghc-hetmet.git diff --git a/compiler/typecheck/TcTyFuns.lhs b/compiler/typecheck/TcTyFuns.lhs index bed053d..0066d2f 100644 --- a/compiler/typecheck/TcTyFuns.lhs +++ b/compiler/typecheck/TcTyFuns.lhs @@ -69,21 +69,16 @@ tcUnfoldSynFamInst (TyConApp tycon tys) | not (isOpenSynTyCon tycon) -- unfold *only* _synonym_ family instances = return Nothing | otherwise - = do { -- we only use the indexing arguments for matching, - -- not the additional ones - ; maybeFamInst <- tcLookupFamInst tycon idxTys + = do { -- The TyCon might be over-saturated, but that's ok for tcLookupFamInst + ; maybeFamInst <- tcLookupFamInst tycon tys ; case maybeFamInst of Nothing -> return Nothing - Just (rep_tc, rep_tys) -> return $ Just (mkTyConApp rep_tc tys', - mkTyConApp coe_tc tys') + Just (rep_tc, rep_tys) -> return $ Just (mkTyConApp rep_tc rep_tys, + mkTyConApp coe_tc rep_tys) where - tys' = rep_tys ++ restTys coe_tc = expectJust "TcTyFuns.tcUnfoldSynFamInst" (tyConFamilyCoercion_maybe rep_tc) } - where - n = tyConArity tycon - (idxTys, restTys) = splitAt n tys tcUnfoldSynFamInst _other = return Nothing \end{code} @@ -231,9 +226,6 @@ tcReduceEqs locals wanteds We maintain normalised equalities together with the skolems introduced as intermediates during flattening of equalities as well as -!!!TODO: We probably now can do without the skolem set. It's not used during -finalisation in the current code. - \begin{code} -- |Configuration of normalised equalities used during solving. -- @@ -286,7 +278,7 @@ no further propoagation is possible. -- normaliseEqs :: [Inst] -> TcM EqConfig normaliseEqs eqs - = do { ASSERTM2( allM isValidWantedEqInst eqs, ppr eqs ) + = do { ASSERTM2( allM wantedEqInstIsUnsolved eqs, ppr eqs ) ; traceTc $ ptext (sLit "Entering normaliseEqs") ; (eqss, skolemss) <- mapAndUnzipM normEqInst eqs @@ -303,10 +295,15 @@ normaliseEqs eqs -- 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 [] @@ -347,7 +344,7 @@ finaliseEqsAndDicts (EqConfig { eqs = eqs -- Assert that all cotvs of wanted equalities are still unfilled, and -- zonk all final insts, to make any improvement visible - ; ASSERTM2( allM isValidWantedEqInst eqs'', ppr eqs'' ) + ; ASSERTM2( allM wantedEqInstIsUnsolved eqs'', ppr eqs'' ) ; zonked_locals <- zonkInsts locals' ; zonked_wanteds <- zonkInsts (eqs'' ++ wanteds') ; return (zonked_locals, zonked_wanteds, final_binds, improved) @@ -379,9 +376,6 @@ families. Moreover, in Forms (2) & (3), the left-hand side may not occur in the right-hand side, and the relation x > y is an arbitrary, but total order on type variables -!!!TODO: We may need to keep track of swapping for error messages (and to -re-orient on finilisation). - \begin{code} data RewriteInst = RewriteVar -- Form (2) above @@ -809,17 +803,23 @@ mkDictBind dict isWanted rewriteCo pred 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} @@ -873,8 +873,11 @@ mapSubstRules eq eqs } 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 @@ -942,20 +945,26 @@ applySubstFam :: RewriteInst -> 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 --- !!!Check whether anything breaks by making tcEqTypes look through synonyms. --- !!!Should be ok and we don't want three type equalities. = 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 + | 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} @@ -977,17 +986,26 @@ applySubstVarVar :: RewriteInst -> 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} @@ -1005,6 +1023,8 @@ co2' is returned. (The equality co1 is not returned as it remain unaltered.) \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 @@ -1019,6 +1039,13 @@ applySubstVarFam eq1@(RewriteVar {rwi_var = tv1}) 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} @@ -1153,44 +1180,72 @@ Return all remaining wanted equalities. The Boolean result component is True if at least one instantiation of a flexible that is *not* a skolem from flattening was performed. +We need to instantiate all flexibles that arose as skolems during flattening +of wanteds before we instantiate any other flexibles. Consider F delta ~ +alpha, F alpha ~ delta, where alpha is a skolem and delta a free flexible. We +need to produce F (F delta) ~ delta (and not F (F alpha) ~ alpha). Otherwise, +we may wrongly claim to having performed an improvement, which can lead to +non-termination of the combined class-family solver. + \begin{code} instantiateAndExtract :: [RewriteInst] -> Bool -> TyVarSet -> TcM ([Inst], Bool) instantiateAndExtract eqs localsEmpty skolems - = do { results <- mapM inst wanteds - ; let residuals = [eq | Left eq <- results] - only_skolems = and [tv `elemVarSet` skolems | Right tv <- results] + = do { traceTc $ hang (ptext (sLit "instantiateAndExtract:")) + 4 (ppr eqs $$ ppr skolems) + -- start by *only* instantiating skolem flexibles from flattening + ; unflat_wanteds <- liftM catMaybes $ + mapM (inst (`elemVarSet` skolems)) wanteds + -- only afterwards instantiate free flexibles + ; residuals <- liftM catMaybes $ mapM (inst (const True)) unflat_wanteds + ; let improvement = length residuals < length unflat_wanteds ; residuals' <- mapM rewriteInstToInst residuals - ; return (residuals', not only_skolems) + ; return (residuals', improvement) } where wanteds = filter (isWantedCo . rwi_co) eqs checkingMode = length eqs > length wanteds || not localsEmpty -- no local equalities or dicts => checking mode - 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 + -- co :: alpha ~ t or co :: a ~ alpha + inst mayInst eq@(RewriteVar {rwi_var = tv1, rwi_right = ty2, rwi_co = co}) + = do { flexi_tv1 <- isFlexible mayInst tv1 + ; maybe_flexi_tv2 <- isFlexibleTy mayInst 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 $ Just 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, - rwi_co = co}) + inst mayInst eq@(RewriteFam {rwi_fam = fam, rwi_args = args, + rwi_right = ty2, rwi_co = co}) | Just tv2 <- tcGetTyVar_maybe ty2 , isMetaTyVar tv2 - , checkingMode || tv2 `elemVarSet` skolems - -- !!!TODO: this is too liberal, even if tv2 is in + , mayInst tv2 && (checkingMode || tv2 `elemVarSet` skolems) + -- !!!FIXME: this is too liberal, even if tv2 is in -- skolems we shouldn't instantiate if tvs occurs -- in other equalities that may propagate it into the -- environment = doInst (not $ rwi_swapped eq) tv2 (mkTyConApp fam args) co eq - inst eq = return $ Left eq + inst _mayInst eq = return $ Just eq + + -- tv is a meta var and not filled + isFlexible mayInst tv + | isMetaTyVar tv && mayInst tv = liftM isFlexi $ readMetaTyVar tv + | otherwise = return False + + -- type is a tv that is a meta var and not filled + isFlexibleTy mayInst ty + | Just tv <- tcGetTyVar_maybe ty = do {flexi <- isFlexible mayInst 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) @@ -1206,7 +1261,7 @@ instantiateAndExtract eqs localsEmpty skolems ptext (sLit "flexible") <+> ppr tv <+> ptext (sLit "already filled with") <+> ppr fill_ty <+> ptext (sLit "meant to fill with") <+> ppr ty - ; return $ Left eq + ; return $ Just eq } -- type variable meets type variable @@ -1229,7 +1284,7 @@ instantiateAndExtract eqs localsEmpty skolems -- signature skolem meets non-variable type -- => cannot update (retain the equality)! uMeta _swapped _tv (DoneTv (MetaTv (SigTv _) _)) _non_tv_ty _cotv - = return $ Left eq + = return $ Just eq -- updatable meta variable meets non-variable type -- => occurs check, monotype check, and kinds match check, then update @@ -1239,12 +1294,13 @@ instantiateAndExtract eqs localsEmpty skolems ; case mb_ty' of Nothing -> - -- normalisation shouldn't leave families in non_tv_ty - panic "TcTyFuns.uMeta: unexpected synonym family" + -- there may be a family in non_tv_ty due to an unzonked, + -- but updated skolem for a local equality + return $ Just eq Just ty' -> do { checkUpdateMeta swapped tv ref ty' -- update meta var ; writeMetaTyVar cotv ty' -- update co var - ; return $ Right tv + ; return Nothing } } @@ -1256,38 +1312,36 @@ instantiateAndExtract eqs localsEmpty skolems uMetaVar swapped tv1 (MetaTv _ ref) tv2 (SkolemTv _) cotv = do { checkUpdateMeta swapped tv1 ref (mkTyVarTy tv2) ; writeMetaTyVar cotv (mkTyVarTy tv2) - ; return $ Right tv1 + ; return Nothing } -- meta variable meets meta variable -- => be clever about which of the two to update -- (from TcUnify.uUnfilledVars minus boxy stuff) uMetaVar swapped tv1 (MetaTv info1 ref1) tv2 (MetaTv info2 ref2) cotv - = do { tv <- case (info1, info2) of - -- Avoid SigTvs if poss - (SigTv _, _ ) | k1_sub_k2 -> update_tv2 - (_, SigTv _) | k2_sub_k1 -> update_tv1 - - (_, _) | k1_sub_k2 -> if k2_sub_k1 && - nicer_to_update_tv1 - then update_tv1 -- Same kinds - else update_tv2 - | k2_sub_k1 -> update_tv1 - | otherwise -> kind_err >> return tv1 + = do { case (info1, info2) of + -- Avoid SigTvs if poss + (SigTv _, _ ) | k1_sub_k2 -> update_tv2 + (_, SigTv _) | k2_sub_k1 -> update_tv1 + + (_, _) | k1_sub_k2 -> if k2_sub_k1 && + nicer_to_update_tv1 + then update_tv1 -- Same kinds + else update_tv2 + | k2_sub_k1 -> update_tv1 + | otherwise -> kind_err -- Update the variable with least kind info -- See notes on type inference in Kind.lhs -- The "nicer to" part only applies if the two kinds are the same, -- so we can choose which to do. ; writeMetaTyVar cotv (mkTyVarTy tv2) - ; return $ Right tv + ; return Nothing } where -- Kinds should be guaranteed ok at this point update_tv1 = updateMeta tv1 ref1 (mkTyVarTy tv2) - >> return tv1 update_tv2 = updateMeta tv2 ref2 (mkTyVarTy tv1) - >> return tv2 kind_err = addErrCtxtM (unifyKindCtxt swapped tv1 (mkTyVarTy tv2)) $ unifyKindMisMatch k1 k2