+{-
+ This helper computes the difference between a base type t and the
+ improved rtti_t computed by RTTI
+ The main difference between RTTI types and their normal counterparts
+ is that the former are _not_ polymorphic, thus polymorphism must
+ be stripped. Syntactically, forall's must be stripped.
+ We also remove predicates.
+-}
+unifyRTTI :: Type -> Type -> TvSubst
+unifyRTTI ty rtti_ty =
+ case mb_subst of
+ Just subst -> subst
+ Nothing -> pprPanic "Failed to compute a RTTI substitution"
+ (ppr (ty, rtti_ty))
+ -- In addition, we strip newtypes too, since the reconstructed type might
+ -- not have recovered them all
+ -- TODO stripping newtypes shouldn't be necessary, test
+ where mb_subst = tcUnifyTys (const BindMe)
+ [rttiView ty]
+ [rttiView rtti_ty]
+
+-- Dealing with newtypes
+{-
+ congruenceNewtypes does a parallel fold over two Type values,
+ compensating for missing newtypes on both sides.
+ This is necessary because newtypes are not present
+ in runtime, but sometimes there is evidence available.
+ Evidence can come from DataCon signatures or
+ from compile-time type inference.
+ What we are doing here is an approximation
+ of unification modulo a set of equations derived
+ from newtype definitions. These equations should be the
+ same as the equality coercions generated for newtypes
+ in System Fc. The idea is to perform a sort of rewriting,
+ taking those equations as rules, before launching unification.
+
+ The caller must ensure the following.
+ The 1st type (lhs) comes from the heap structure of ptrs,nptrs.
+ The 2nd type (rhs) comes from a DataCon type signature.
+ Rewriting (i.e. adding/removing a newtype wrapper) can happen
+ in both types, but in the rhs it is restricted to the result type.
+
+ Note that it is very tricky to make this 'rewriting'
+ work with the unification implemented by TcM, where
+ substitutions are operationally inlined. The order in which
+ constraints are unified is vital as we cannot modify
+ anything that has been touched by a previous unification step.
+Therefore, congruenceNewtypes is sound only if the types
+recovered by the RTTI mechanism are unified Top-Down.
+-}
+congruenceNewtypes :: TcType -> TcType -> TR (TcType,TcType)
+congruenceNewtypes lhs rhs
+ -- TyVar lhs inductive case
+ | Just tv <- getTyVar_maybe lhs
+ = recoverTc (return (lhs,rhs)) $ do
+ Indirect ty_v <- readMetaTyVar tv
+ (_lhs1, rhs1) <- congruenceNewtypes ty_v rhs
+ return (lhs, rhs1)
+-- FunTy inductive case
+ | Just (l1,l2) <- splitFunTy_maybe lhs
+ , Just (r1,r2) <- splitFunTy_maybe rhs
+ = do (l2',r2') <- congruenceNewtypes l2 r2
+ (l1',r1') <- congruenceNewtypes l1 r1
+ return (mkFunTy l1' l2', mkFunTy r1' r2')
+-- TyconApp Inductive case; this is the interesting bit.
+ | Just (tycon_l, _) <- splitNewTyConApp_maybe lhs
+ , Just (tycon_r, _) <- splitNewTyConApp_maybe rhs
+ , tycon_l /= tycon_r
+ = do rhs' <- upgrade tycon_l rhs
+ return (lhs, rhs')
+
+ | otherwise = return (lhs,rhs)
+
+ where upgrade :: TyCon -> Type -> TR Type
+ upgrade new_tycon ty
+ | not (isNewTyCon new_tycon) = return ty
+ | otherwise = do
+ vars <- mapM (newVar . tyVarKind) (tyConTyVars new_tycon)
+ let ty' = mkTyConApp new_tycon vars
+ liftTcM (unifyType ty (repType ty'))
+ -- assumes that reptype doesn't ^^^^ touch tyconApp args
+ return ty'
+
+
+--------------------------------------------------------------------------------
+-- Semantically different to recoverM in TcRnMonad
+-- recoverM retains the errors in the first action,
+-- whereas recoverTc here does not
+recoverTc :: TcM a -> TcM a -> TcM a
+recoverTc recover thing = do
+ (_,mb_res) <- tryTcErrs thing
+ case mb_res of
+ Nothing -> recover
+ Just res -> return res
+
+isMonomorphic :: Type -> Bool
+isMonomorphic ty | (tvs, ty') <- splitForAllTys ty
+ = null tvs && (isEmptyVarSet . tyVarsOfType) ty'
+
+mapMif :: Monad m => (a -> Bool) -> (a -> m a) -> [a] -> m [a]
+mapMif pred f xx = sequence $ mapMif_ pred f xx
+ where
+ mapMif_ _ _ [] = []
+ mapMif_ pred f (x:xx) = (if pred x then f x else return x) : mapMif_ pred f xx
+
+unlessM :: Monad m => m Bool -> m () -> m ()
+unlessM condM acc = condM >>= \c -> unless c acc
+
+-- Strict application of f at index i
+appArr :: Ix i => (e -> a) -> Array i e -> Int -> a
+appArr f a@(Array _ _ _ ptrs#) i@(I# i#)
+ = ASSERT (i < length(elems a))
+ case indexArray# ptrs# i# of
+ (# e #) -> f e