+-- -----------------------------------------------------------------------------
+-- After stopping at a breakpoint, add free variables to the environment
+
+-- Todo: turn this into a primop, and provide special version(s) for unboxed things
+foreign import ccall unsafe "rts_getApStackVal"
+ getApStackVal :: StablePtr a -> Int -> IO (StablePtr b)
+
+getIdValFromApStack :: a -> Int -> IO HValue
+getIdValFromApStack apStack stackDepth = do
+ apSptr <- newStablePtr apStack
+ resultSptr <- getApStackVal apSptr (stackDepth - 1)
+ result <- deRefStablePtr resultSptr
+ freeStablePtr apSptr
+ freeStablePtr resultSptr
+ return (unsafeCoerce# result)
+
+extendEnvironment
+ :: HscEnv
+ -> a -- the AP_STACK object built by the interpreter
+ -> SrcSpan
+ -> [(Id, Int)] -- free variables and offsets into the AP_STACK
+ -> Type
+ -> [OccName] -- names for the variables (from the source code)
+ -> IO (HscEnv, [Name])
+extendEnvironment hsc_env apStack span idsOffsets result_ty occs = do
+
+ -- filter out any unboxed ids; we can't bind these at the prompt
+ let pointers = filter (\(id,_) -> isPointer id) idsOffsets
+ isPointer id | PtrRep <- idPrimRep id = True
+ | otherwise = False
+
+ let (ids, offsets) = unzip pointers
+ hValues <- mapM (getIdValFromApStack apStack) offsets
+ new_ids <- zipWithM mkNewId occs ids
+ let names = map idName ids
+
+ -- make an Id for _result. We use the Unique of the FastString "_result";
+ -- we don't care about uniqueness here, because there will only be one
+ -- _result in scope at any time.
+ let result_fs = FSLIT("_result")
+ result_name = mkInternalName (getUnique result_fs)
+ (mkVarOccFS result_fs) (srcSpanStart span)
+ result_id = Id.mkLocalId result_name result_ty
+
+ -- for each Id we're about to bind in the local envt:
+ -- - skolemise the type variables in its type, so they can't
+ -- be randomly unified with other types. These type variables
+ -- can only be resolved by type reconstruction in RtClosureInspect
+ -- - tidy the type variables
+ -- - globalise the Id (Ids are supposed to be Global, apparently).
+ --
+ let all_ids | isPointer result_id = result_id : ids
+ | otherwise = ids
+ (id_tys, tyvarss) = mapAndUnzip (skolemiseTy.idType) all_ids
+ (_,tidy_tys) = tidyOpenTypes emptyTidyEnv id_tys
+ new_tyvars = unionVarSets tyvarss
+ new_ids = zipWith setIdType all_ids tidy_tys
+ global_ids = map (globaliseId VanillaGlobal) new_ids
+
+ let ictxt = extendInteractiveContext (hsc_IC hsc_env)
+ global_ids new_tyvars
+
+ Linker.extendLinkEnv (zip names hValues)
+ Linker.extendLinkEnv [(result_name, unsafeCoerce# apStack)]
+ return (hsc_env{hsc_IC = ictxt}, result_name:names)
+ where
+ mkNewId :: OccName -> Id -> IO Id
+ mkNewId occ id = do
+ let uniq = idUnique id
+ loc = nameSrcLoc (idName id)
+ name = mkInternalName uniq occ loc
+ ty = tidyTopType (idType id)
+ new_id = Id.mkGlobalId VanillaGlobal name ty (idInfo id)
+ return new_id
+
+skolemiseTy :: Type -> (Type, TyVarSet)
+skolemiseTy ty = (substTy subst ty, mkVarSet new_tyvars)
+ where env = mkVarEnv (zip tyvars new_tyvar_tys)
+ subst = mkTvSubst emptyInScopeSet env
+ tyvars = varSetElems (tyVarsOfType ty)
+ new_tyvars = map skolemiseTyVar tyvars
+ new_tyvar_tys = map mkTyVarTy new_tyvars
+
+skolemiseTyVar :: TyVar -> TyVar
+skolemiseTyVar tyvar = mkTcTyVar (tyVarName tyvar) (tyVarKind tyvar)
+ (SkolemTv RuntimeUnkSkol)
+