summaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/ghci/ByteCodeGen.hs4
-rw-r--r--compiler/ghci/ByteCodeTypes.hs6
-rw-r--r--compiler/main/InteractiveEval.hs63
3 files changed, 60 insertions, 13 deletions
diff --git a/compiler/ghci/ByteCodeGen.hs b/compiler/ghci/ByteCodeGen.hs
index 8b23e08003..12331e2d52 100644
--- a/compiler/ghci/ByteCodeGen.hs
+++ b/compiler/ghci/ByteCodeGen.hs
@@ -432,8 +432,8 @@ schemeER_wrk d p rhs
return $ breakInstr `consOL` code
| otherwise = schemeE d 0 p rhs
-getVarOffSets :: DynFlags -> StackDepth -> BCEnv -> [Id] -> [(Id, Word16)]
-getVarOffSets dflags depth env = catMaybes . map getOffSet
+getVarOffSets :: DynFlags -> StackDepth -> BCEnv -> [Id] -> [Maybe (Id, Word16)]
+getVarOffSets dflags depth env = map getOffSet
where
getOffSet id = case lookupBCEnv_maybe id env of
Nothing -> Nothing
diff --git a/compiler/ghci/ByteCodeTypes.hs b/compiler/ghci/ByteCodeTypes.hs
index 628b576ca0..0c0c34ad64 100644
--- a/compiler/ghci/ByteCodeTypes.hs
+++ b/compiler/ghci/ByteCodeTypes.hs
@@ -35,6 +35,7 @@ import Data.Array.Base ( UArray(..) )
import Data.ByteString (ByteString)
import Data.IntMap (IntMap)
import qualified Data.IntMap as IntMap
+import Data.Maybe (catMaybes)
import GHC.Exts.Heap
import GHC.Stack.CCS
@@ -110,14 +111,15 @@ instance NFData BCONPtr where
-- | Information about a breakpoint that we know at code-generation time
data CgBreakInfo
= CgBreakInfo
- { cgb_vars :: [(Id,Word16)]
+ { cgb_vars :: [Maybe (Id,Word16)]
, cgb_resty :: Type
}
+-- See Note [Syncing breakpoint info] in compiler/main/InteractiveEval.hs
-- Not a real NFData instance because we can't rnf Id or Type
seqCgBreakInfo :: CgBreakInfo -> ()
seqCgBreakInfo CgBreakInfo{..} =
- rnf (map snd cgb_vars) `seq`
+ rnf (map snd (catMaybes (cgb_vars))) `seq`
seqType cgb_resty
instance Outputable UnlinkedBCO where
diff --git a/compiler/main/InteractiveEval.hs b/compiler/main/InteractiveEval.hs
index b2c644e65c..ee43aaf675 100644
--- a/compiler/main/InteractiveEval.hs
+++ b/compiler/main/InteractiveEval.hs
@@ -521,20 +521,17 @@ bindLocalsAtBreakpoint hsc_env apStack_fhv (Just BreakInfo{..}) = do
breaks = getModBreaks hmi
info = expectJust "bindLocalsAtBreakpoint2" $
IntMap.lookup breakInfo_number (modBreaks_breakInfo breaks)
- vars = cgb_vars info
+ mbVars = cgb_vars info
result_ty = cgb_resty info
occs = modBreaks_vars breaks ! breakInfo_number
span = modBreaks_locs breaks ! breakInfo_number
decl = intercalate "." $ modBreaks_decls breaks ! breakInfo_number
- -- Filter out any unboxed ids;
+ -- Filter out any unboxed ids by changing them to Nothings;
-- we can't bind these at the prompt
- pointers = filter (\(id,_) -> isPointer id) vars
- isPointer id | [rep] <- typePrimRep (idType id)
- , isGcPtrRep rep = True
- | otherwise = False
+ mbPointers = nullUnboxed <$> mbVars
- (ids, offsets) = unzip pointers
+ (ids, offsets, occs') = syncOccs mbPointers occs
free_tvs = tyCoVarsOfTypesList (result_ty:map idType ids)
@@ -550,11 +547,12 @@ bindLocalsAtBreakpoint hsc_env apStack_fhv (Just BreakInfo{..}) = do
us <- mkSplitUniqSupply 'I' -- Dodgy; will give the same uniques every time
let tv_subst = newTyVars us free_tvs
- filtered_ids = [ id | (id, Just _hv) <- zip ids mb_hValues ]
+ (filtered_ids, occs'') = unzip -- again, sync the occ-names
+ [ (id, occ) | (id, Just _hv, occ) <- zip3 ids mb_hValues occs' ]
(_,tidy_tys) = tidyOpenTypes emptyTidyEnv $
map (substTy tv_subst . idType) filtered_ids
- new_ids <- zipWith3M mkNewId occs tidy_tys filtered_ids
+ new_ids <- zipWith3M mkNewId occs'' tidy_tys filtered_ids
result_name <- newInteractiveBinder hsc_env (mkVarOccFS result_fs) span
let result_id = Id.mkVanillaGlobal result_name
@@ -591,6 +589,24 @@ bindLocalsAtBreakpoint hsc_env apStack_fhv (Just BreakInfo{..}) = do
| (tv, uniq) <- tvs `zip` uniqsFromSupply us
, let name = setNameUnique (tyVarName tv) uniq ]
+ isPointer id | [rep] <- typePrimRep (idType id)
+ , isGcPtrRep rep = True
+ | otherwise = False
+
+ -- Convert unboxed Id's to Nothings
+ nullUnboxed (Just (fv@(id, _)))
+ | isPointer id = Just fv
+ | otherwise = Nothing
+ nullUnboxed Nothing = Nothing
+
+ -- See Note [Syncing breakpoint info]
+ syncOccs :: [Maybe (a,b)] -> [c] -> ([a], [b], [c])
+ syncOccs mbVs ocs = unzip3 $ catMaybes $ joinOccs mbVs ocs
+ where
+ joinOccs :: [Maybe (a,b)] -> [c] -> [Maybe (a,b,c)]
+ joinOccs = zipWith joinOcc
+ joinOcc mbV oc = (\(a,b) c -> (a,b,c)) <$> mbV <*> pure oc
+
rttiEnvironment :: HscEnv -> IO HscEnv
rttiEnvironment hsc_env@HscEnv{hsc_IC=ic} = do
let tmp_ids = [id | AnId id <- ic_tythings ic]
@@ -632,6 +648,35 @@ pushResume hsc_env resume = hsc_env { hsc_IC = ictxt1 }
ictxt0 = hsc_IC hsc_env
ictxt1 = ictxt0 { ic_resume = resume : ic_resume ictxt0 }
+
+ {-
+ Note [Syncing breakpoint info]
+
+ To display the values of the free variables for a single breakpoint, the
+ function `compiler/main/InteractiveEval.hs:bindLocalsAtBreakpoint` pulls
+ out the information from the fields `modBreaks_breakInfo` and
+ `modBreaks_vars` of the `ModBreaks` data structure.
+ For a specific breakpoint this gives 2 lists of type `Id` (or `Var`)
+ and `OccName`.
+ They are used to create the Id's for the free variables and must be kept
+ in sync!
+
+ There are 3 situations where items are removed from the Id list
+ (or replaced with `Nothing`):
+ 1.) If function `compiler/ghci/ByteCodeGen.hs:schemeER_wrk` (which creates
+ the Id list) doesn't find an Id in the ByteCode environement.
+ 2.) If function `compiler/main/InteractiveEval.hs:bindLocalsAtBreakpoint`
+ filters out unboxed elements from the Id list, because GHCi cannot
+ yet handle them.
+ 3.) If the GHCi interpreter doesn't find the reference to a free variable
+ of our breakpoint. This also happens in the function
+ bindLocalsAtBreakpoint.
+
+ If an element is removed from the Id list, then the corresponding element
+ must also be removed from the Occ list. Otherwise GHCi will confuse
+ variable names as in #8487.
+ -}
+
-- -----------------------------------------------------------------------------
-- Abandoning a resume context