+ solve_with xi_unflat coi -- coi : xi_unflat ~ xi
+ = do { traceTcS "Sneaky unification:" $
+ vcat [text "Coercion variable: " <+> ppr gw,
+ text "Coercion: " <+> pprEq (mkTyVarTy tv) xi,
+ text "Left Kind is : " <+> ppr (typeKind (mkTyVarTy tv)),
+ text "Right Kind is : " <+> ppr (typeKind xi)
+ ]
+ ; setWantedTyBind tv xi_unflat -- Set tv := xi_unflat
+ ; cv_given <- newGivOrDerCoVar (mkTyVarTy tv) xi_unflat xi_unflat
+ ; let flav = mkGivenFlavor gw UnkSkol
+ ; (cts, co) <- case coi of
+ ACo co -> do { can_eqs <- canEq flav cv_given (mkTyVarTy tv) xi_unflat
+ ; return (can_eqs, co) }
+ IdCo co -> return $
+ (singleCCan (CTyEqCan { cc_id = cv_given
+ , cc_flavor = mkGivenFlavor gw UnkSkol
+ , cc_tyvar = tv, cc_rhs = xi }
+ -- xi, *not* xi_unflat because
+ -- xi_unflat may require flattening!
+ ), co)
+ ; case gw of
+ Wanted {} -> setWantedCoBind cv co
+ Derived {} -> setDerivedCoBind cv co
+ _ -> pprPanic "Can't spontaneously solve *given*" empty
+ -- See Note [Avoid double unifications]
+ ; return (Just cts) }
+
+occurCheck :: Bag (TcTyVar, TcType) -> InertSet
+ -> TcTyVar -> TcType -> Maybe (TcType,CoercionI)
+-- Traverse @ty@ to make sure that @tv@ does not appear under some flatten skolem.
+-- If it appears under some flatten skolem look in that flatten skolem equivalence class
+-- (see Note [InertSet FlattenSkolemEqClass], [Loopy Spontaneous Solving]) to see if you
+-- can find a different flatten skolem to use, that is, one that does not mention @tv@.
+--
+-- Postcondition: Just (ty', coi) = occurCheck binds inerts tv ty
+-- coi :: ty' ~ ty
+-- NB: The returned type ty' may not be flat!
+
+occurCheck ty_binds_bag inerts tv ty
+ = ok emptyVarSet ty
+ where
+ ok bad this_ty@(TyConApp tc tys)
+ | Just tys_cois <- allMaybes (map (ok bad) tys)
+ , (tys',cois') <- unzip tys_cois
+ = Just (TyConApp tc tys', mkTyConAppCoI tc cois')
+ | isSynTyCon tc, Just ty_expanded <- tcView this_ty
+ = ok bad ty_expanded -- See Note [Type synonyms and the occur check] in TcUnify
+ ok bad (PredTy sty)
+ | Just (sty',coi) <- ok_pred bad sty
+ = Just (PredTy sty', coi)
+ ok bad (FunTy arg res)
+ | Just (arg', coiarg) <- ok bad arg, Just (res', coires) <- ok bad res
+ = Just (FunTy arg' res', mkFunTyCoI coiarg coires)
+ ok bad (AppTy fun arg)
+ | Just (fun', coifun) <- ok bad fun, Just (arg', coiarg) <- ok bad arg
+ = Just (AppTy fun' arg', mkAppTyCoI coifun coiarg)
+ ok bad (ForAllTy tv1 ty1)
+ -- WARNING: What if it is a (t1 ~ t2) => t3? It's not handled properly at the moment.
+ | Just (ty1', coi) <- ok bad ty1
+ = Just (ForAllTy tv1 ty1', mkForAllTyCoI tv1 coi)
+
+ -- Variable cases
+ ok _bad this_ty@(TyVarTy tv')
+ | not $ isTcTyVar tv' = Just (this_ty, IdCo this_ty) -- Bound variable
+ | tv == tv' = Nothing -- Occurs check error
+
+ ok bad (TyVarTy fsk)
+ | FlatSkol zty <- tcTyVarDetails fsk
+ = if fsk `elemVarSet` bad then
+ -- its type has been checked
+ go_down_eq_class bad $ getFskEqClass inerts fsk
+ else
+ -- its type is not yet checked
+ case ok bad zty of
+ Nothing -> go_down_eq_class (bad `extendVarSet` fsk) $
+ getFskEqClass inerts fsk
+ Just (zty',ico) -> Just (zty',ico)
+
+ -- Check if there exists a ty bind already, as a result of sneaky unification.
+ ok bad this_ty@(TyVarTy tv0)
+ = case Bag.foldlBag find_bind Nothing ty_binds_bag of
+ Nothing -> Just (this_ty, IdCo this_ty)
+ Just ty0 -> ok bad ty0
+ where find_bind Nothing (tvx,tyx) | tv0 == tvx = Just tyx
+ find_bind m _ = m
+ -- Fall through
+ ok _bad _ty = Nothing
+
+ ok_pred bad (ClassP cn tys)
+ | Just tys_cois <- allMaybes $ map (ok bad) tys
+ = let (tys', cois') = unzip tys_cois
+ in Just (ClassP cn tys', mkClassPPredCoI cn cois')
+ ok_pred bad (IParam nm ty)
+ | Just (ty',co') <- ok bad ty
+ = Just (IParam nm ty', mkIParamPredCoI nm co')
+ ok_pred bad (EqPred ty1 ty2)
+ | Just (ty1',coi1) <- ok bad ty1, Just (ty2',coi2) <- ok bad ty2
+ = Just (EqPred ty1' ty2', mkEqPredCoI coi1 coi2)
+ ok_pred _ _ = Nothing
+
+ go_down_eq_class _bad_tvs [] = Nothing
+ go_down_eq_class bad_tvs ((fsk1,co1):rest)
+ | fsk1 `elemVarSet` bad_tvs = go_down_eq_class bad_tvs rest
+ | otherwise
+ = case ok bad_tvs (TyVarTy fsk1) of
+ Nothing -> go_down_eq_class (bad_tvs `extendVarSet` fsk1) rest
+ Just (ty1,co1i') -> Just (ty1, mkTransCoI co1i' (ACo co1))