Skip to content
This repository has been archived by the owner on Apr 25, 2020. It is now read-only.

[WIP] New cabal helper used in hie #947

Open
wants to merge 53 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
d3d920a
Update for newer cabal-hel
alanz Jan 6, 2018
b62c558
Switch to 8.2.2 image for gitlab ci
alanz Jan 7, 2018
6b04d9b
Explicitly turn off -Wmissing-home-modules
alanz Jan 20, 2018
2638227
Add runV to run tests with vomit logging
alanz Jan 20, 2018
1128096
Move the core functionality into new package ghc-mod-core
alanz Sep 25, 2017
5ebd13b
Move the core functionality into new package ghc-mod-core
alanz Sep 25, 2017
a7406d4
Squash branch hie-integration-rebased-split-up-3
alanz Sep 25, 2017
47e200a
Remove stale dependencies
alanz Jan 27, 2018
9cc7498
Initial preparation for cabal new-build
alanz Mar 14, 2018
e3427d1
Support GHC 8.4
alanz Feb 11, 2018
9e07bc0
Add ModuleLoader
alanz Apr 15, 2018
fd02f84
Update for GHC 8.4.2, removing auto command
alanz Apr 24, 2018
90c7c0f
Implement splits' to return a structured restult for case splitting
txsmith Apr 21, 2018
9ea60d5
Use canonicalizePath in FileMapping
wz1000 May 9, 2018
214fe1b
Match code style to the existing code
alanz Jun 17, 2018
66fc098
Only load mapped files from the current component
wz1000 Jul 8, 2017
55f6eea
Update for GHC 8.6
alanz Jul 2, 2018
52752f9
Update ghc-mod part for GHC 8.6
alanz Jul 14, 2018
973e46c
Return parsed module in getTypecheckedModuleGhc
lukel97 Aug 28, 2018
30f31ad
Rename getTypecheckedModule to getModules
lukel97 Sep 9, 2018
84067de
Merge remote-tracking branch 'bubba/parse-module' into ghc-8.6-parse-…
alanz Sep 12, 2018
3be79fe
Satisfies deps and configures with GHC 8.6.1
alanz Sep 22, 2018
65bc41d
Update for Monad Fail Proposal
alanz Sep 22, 2018
6f97275
Merge remote-tracking branch 'origin/new-build' into HEAD
dsturnbull Oct 12, 2018
4461caf
use new dist-dir command
dsturnbull Oct 25, 2018
5dc532b
remove hardcoded .
dsturnbull Oct 26, 2018
9844e57
use proper dir
dsturnbull Oct 26, 2018
40da7b7
cabal-helper-1.0.0.0
dsturnbull Oct 26, 2018
97a3a4e
also tell ghc-mod-core to use cabal-helper-1.0.0.0
dsturnbull Oct 26, 2018
3c96147
Merge branch 'cabal-new-rebased' into cabal-new-merged
alanz Nov 6, 2018
8da1255
Fix compilation
alanz Nov 6, 2018
f4a7c89
Delete some dead code
alanz Nov 8, 2018
f321acd
Can build tests too
alanz Nov 8, 2018
b51eff3
Use cabal-helper 0.9.0.0
alanz Nov 8, 2018
a2b695d
Remove unused compatibility flag, add Compat.hs_h to dist
alanz Nov 9, 2018
03739d5
Ignore .ghc.environment.* files
alanz Nov 10, 2018
b83dbb9
Use flag for disabling loading of .ghc.environment files
alanz Nov 10, 2018
82b5fca
Introduce LoadGhcEnvironment type
alanz Nov 10, 2018
33f01a0
Trying to bring in cabal-helper-wrapper exe for GHC 8.6.1
alanz Nov 10, 2018
8383b8c
Fill in missing constructor for Pretty Text for GHC 8.6
alanz Nov 11, 2018
bd0867f
Add RStr case in DebugLogger for GHC 8.6
alanz Nov 11, 2018
e5b7daf
Remove spurious up cabal-helper-wrapper dep
alanz Nov 26, 2018
8df7fa3
WIP on integrating new-gen cabal-helper
alanz Dec 23, 2018
502a2e9
WIP
alanz Dec 24, 2018
338469f
HaRe UtilsSpec tests pass with old build
alanz Dec 26, 2018
be26c61
getComponents returns all components info
alanz Dec 26, 2018
b872904
WIP. pausing now, need to wait for stack release
alanz Dec 27, 2018
c450f34
Revert to checking stack cradle first.
alanz Dec 30, 2018
98c4122
Get ghc-mod compiling too, commenting out stuff
alanz Jan 3, 2019
9f4e9b6
Works with alanz cabalhelper at wip/new-build
alanz Feb 16, 2019
7fb6291
Move the entire currently used (by hie) API into GhcModCore
alanz Feb 17, 2019
c488f3a
Include the API used by HaRe
alanz Feb 17, 2019
1046813
Starting to move things around
alanz Feb 24, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ elisp/*.elc
/.cabal-sandbox/
/.stack-work/
/test/data/**/stack.yaml
/test/data/**/.stack-work
/test/data/**/.cabal-sandbox
add-source-timestamps
package.cache
cabal.sandbox.config
Expand All @@ -20,3 +22,6 @@ cabal.sandbox.config
cabal-dev
/TAGS
/tags
/.bash_history
/.travis.yml.orig
/cabal.project.az
8 changes: 7 additions & 1 deletion GhcMod.hs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ module GhcMod (
, splits
, sig
, refine
, auto
-- , auto
, modules
, languages
, flags
Expand All @@ -67,6 +67,9 @@ module GhcMod (
, loadMappedFile
, loadMappedFileSource
, unloadMappedFile
-- * API moving around stuff, temporary for now
, pretty
, collectAllSpansTypes
) where

import GhcMod.Exe.Boot
Expand All @@ -90,3 +93,6 @@ import GhcMod.Monad
import GhcMod.Output
import GhcMod.Target
import GhcMod.Types


import GhcMod.SrcUtils (pretty,collectAllSpansTypes)
156 changes: 102 additions & 54 deletions GhcMod/Exe/CaseSplit.hs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

module GhcMod.Exe.CaseSplit (
splits
, splits'
, SplitResult(..)
) where

import Data.List (find, intercalate)
Expand All @@ -12,7 +14,6 @@ import System.FilePath
import Prelude

import qualified DataCon as Ty
import GHC (GhcMonad, LPat, Id, ParsedModule(..), TypecheckedModule(..), DynFlags, SrcSpan, Type, GenLocated(L))
import qualified GHC as G
import Outputable (PprStyle)
import qualified TyCon as Ty
Expand All @@ -35,15 +36,22 @@ import Control.DeepSeq
-- CASE SPLITTING
----------------------------------------------------------------

data SplitInfo = SplitInfo G.Name SrcSpan (SrcSpan, Type) [SrcSpan]
| TySplitInfo G.Name SrcSpan (SrcSpan, Ty.Kind)
data SplitInfo = SplitInfo G.Name G.SrcSpan (G.SrcSpan, G.Type) [G.SrcSpan]
| TySplitInfo G.Name G.SrcSpan (G.SrcSpan, Ty.Kind)
data SplitToTextInfo = SplitToTextInfo { sVarName :: String
, sBindingSpan :: SrcSpan
, sVarSpan :: SrcSpan
, sBindingSpan :: G.SrcSpan
, sVarSpan :: G.SrcSpan
, sTycons :: [String]
}
data SplitResult = SplitResult { sStartLine :: Int
, sStartCol :: Int
, sEndLine :: Int
, sEndCol :: Int
, sNewText :: T.Text }

-- | Splitting a variable in a equation.
-- Unlike splits', this performs parsing an type checking on every invocation.
-- This is meant for consumption by tools that call ghc-mod as a binary.
splits :: IOish m
=> FilePath -- ^ A target file.
-> Int -- ^ Line number.
Expand All @@ -53,84 +61,122 @@ splits file lineNo colNo =
ghandle handler $ runGmlT' [Left file] deferErrors $ do
oopts <- outputOpts
crdl <- cradle
style <- getStyle
dflag <- G.getSessionDynFlags
modSum <- fileModSummaryWithMapping (cradleCurrentDir crdl </> file)
whenFound' oopts (getSrcSpanTypeForSplit modSum lineNo colNo) $ \x -> do
let (varName, bndLoc, (varLoc,varT))
| (SplitInfo vn bl vlvt _matches) <- x
= (vn, bl, vlvt)
| (TySplitInfo vn bl vlvt) <- x
= (vn, bl, vlvt)
varName' = showName dflag style varName -- Convert name to string
t <- withMappedFile file $ \file' ->
genCaseSplitTextFile file' (SplitToTextInfo varName' bndLoc varLoc $
getTyCons dflag style varName varT)
return $!! (fourInts bndLoc, t)
p <- G.parseModule modSum
tcm <- G.typecheckModule p
whenFound' oopts (performSplit file tcm lineNo colNo) $
\(SplitResult sLine sCol eLine eCol newText) ->
return $!! ((sLine, sCol, eLine, eCol), T.unpack newText)
where
handler (SomeException ex) = do
gmLog GmException "splits" $
text "" $$ nest 4 (showToDoc ex)
emptyResult =<< outputOpts

-- | Split an identifier in a function definition.
-- Meant for library-usage.
splits' :: IOish m => FilePath -> G.TypecheckedModule -> Int -> Int -> GhcModT m (Maybe SplitResult)
splits' file tcm lineNo colNo =
ghandle handler $ runGmlT' [Left file] deferErrors $ performSplit file tcm lineNo colNo
where
handler (SomeException ex) = do
gmLog GmException "splits'" $
text "" $$ nest 4 (showToDoc ex)
return Nothing

performSplit :: IOish m => FilePath -> G.TypecheckedModule -> Int -> Int -> GmlT m (Maybe SplitResult)
performSplit file tcm lineNo colNo = do
style <- getStyle
dflag <- G.getSessionDynFlags
maybeSplitInfo <- getSrcSpanTypeForSplit tcm lineNo colNo
sequenceA $ constructSplitResult file maybeSplitInfo dflag style

constructSplitResult :: (IOish m) => FilePath -> Maybe SplitInfo -> G.DynFlags -> PprStyle -> Maybe (GmlT m SplitResult)
constructSplitResult file maybeSplitInfo dflag style = do
splitInfo <- maybeSplitInfo
let splitToTextInfo = constructSplitToTextInfo splitInfo dflag style
startLoc <- maybeSrcSpanStart $ sBindingSpan splitToTextInfo
endLoc <- maybeSrcSpanEnd $ sBindingSpan splitToTextInfo
let startLine = G.srcLocLine startLoc
startCol = G.srcLocCol startLoc
endLine = G.srcLocLine endLoc
endCol = G.srcLocCol endLoc
newText = genCaseSplitTextFile file splitToTextInfo
return $ SplitResult startLine startCol endLine endCol . T.pack <$> newText

constructSplitToTextInfo :: SplitInfo -> G.DynFlags -> PprStyle -> SplitToTextInfo
constructSplitToTextInfo splitInfo dflag style =
SplitToTextInfo varName' bndLoc varLoc typeCons
where
typeCons = getTyCons dflag style varName varT
varName' = showName dflag style varName -- Convert name to string
(varName, bndLoc, varLoc, varT) = case splitInfo of
(SplitInfo vn bl (vl, vt) _matches) -> (vn, bl, vl, vt)
(TySplitInfo vn bl (vl, vt)) -> (vn, bl, vl, vt)

maybeSrcSpanStart :: G.SrcSpan -> Maybe G.RealSrcLoc
maybeSrcSpanStart s = case G.srcSpanStart s of
(G.RealSrcLoc startLoc) -> Just startLoc
_ -> Nothing

maybeSrcSpanEnd :: G.SrcSpan -> Maybe G.RealSrcLoc
maybeSrcSpanEnd s = case G.srcSpanEnd s of
(G.RealSrcLoc endLoc) -> Just endLoc
_ -> Nothing
----------------------------------------------------------------
-- a. Code for getting the information of the variable

getSrcSpanTypeForSplit :: GhcMonad m => G.ModSummary -> Int -> Int -> m (Maybe SplitInfo)
getSrcSpanTypeForSplit modSum lineNo colNo = do
fn <- getSrcSpanTypeForFnSplit modSum lineNo colNo
getSrcSpanTypeForSplit :: G.GhcMonad m => G.TypecheckedModule -> Int -> Int -> m (Maybe SplitInfo)
getSrcSpanTypeForSplit tcm lineNo colNo = do
fn <- getSrcSpanTypeForFnSplit tcm lineNo colNo
if isJust fn
then return fn
else getSrcSpanTypeForTypeSplit modSum lineNo colNo
else getSrcSpanTypeForTypeSplit tcm lineNo colNo

-- Information for a function case split
getSrcSpanTypeForFnSplit :: GhcMonad m => G.ModSummary -> Int -> Int -> m (Maybe SplitInfo)
getSrcSpanTypeForFnSplit modSum lineNo colNo = do
p@ParsedModule{pm_parsed_source = _pms} <- G.parseModule modSum
tcm@TypecheckedModule{tm_typechecked_source = tcs} <- G.typecheckModule p
let varPat = find isPatternVar $ listifySpans tcs (lineNo, colNo) :: Maybe (LPat Id)
match = last $ listifySpans tcs (lineNo, colNo) :: Gap.GLMatchI
getSrcSpanTypeForFnSplit :: G.GhcMonad m => G.TypecheckedModule -> Int -> Int -> m (Maybe SplitInfo)
getSrcSpanTypeForFnSplit [email protected]{G.tm_typechecked_source = tcs} lineNo colNo = do
let varPat = find isPatternVar $ listifySpans tcs (lineNo, colNo) :: Maybe (G.LPat Gap.GhcTc)
match = last $ listifySpans tcs (lineNo, colNo) :: G.LMatch Gap.GhcTc (G.LHsExpr Gap.GhcTc)
case varPat of
Nothing -> return Nothing
Just varPat' -> do
varT <- Gap.getType tcm varPat' -- Finally we get the type of the var
case varT of
Just varT' ->
#if __GLASGOW_HASKELL__ >= 710
let (L matchL (G.Match _ _ _ (G.GRHSs rhsLs _))) = match
#else
let (L matchL (G.Match _ _ (G.GRHSs rhsLs _))) = match
#endif
let (G.L matchL (G.Match { G.m_grhss = G.GRHSs { G.grhssGRHSs = rhsLs }})) = match
in return $ Just (SplitInfo (getPatternVarName varPat') matchL varT' (map G.getLoc rhsLs) )
_ -> return Nothing

isPatternVar :: LPat Id -> Bool
isPatternVar (L _ (G.VarPat _)) = True
isPatternVar _ = False
isPatternVar :: G.LPat Gap.GhcTc -> Bool
isPatternVar (G.L _ (G.VarPat {})) = True
isPatternVar _ = False

getPatternVarName :: LPat Id -> G.Name
#if __GLASGOW_HASKELL__ >= 800
getPatternVarName (L _ (G.VarPat (L _ vName))) = G.getName vName
getPatternVarName :: G.LPat Gap.GhcTc -> G.Name
#if __GLASGOW_HASKELL__ >= 806
getPatternVarName (G.L _ (G.VarPat _ (G.L _ vName))) = G.getName vName
#elif __GLASGOW_HASKELL__ >= 800
getPatternVarName (G.L _ (G.VarPat (G.L _ vName))) = G.getName vName
#else
getPatternVarName (L _ (G.VarPat vName)) = G.getName vName
getPatternVarName (G.L _ (G.VarPat vName)) = G.getName vName
#endif
getPatternVarName _ = error "This should never happened"

-- TODO: Information for a type family case split
getSrcSpanTypeForTypeSplit :: GhcMonad m => G.ModSummary -> Int -> Int -> m (Maybe SplitInfo)
getSrcSpanTypeForTypeSplit _modSum _lineNo _colNo = return Nothing
getSrcSpanTypeForTypeSplit :: G.GhcMonad m => G.TypecheckedModule -> Int -> Int -> m (Maybe SplitInfo)
getSrcSpanTypeForTypeSplit _tcm _lineNo _colNo = return Nothing

----------------------------------------------------------------
-- b. Code for getting the possible constructors

getTyCons :: DynFlags -> PprStyle -> G.Name -> G.Type -> [String]
getTyCons :: G.DynFlags -> PprStyle -> G.Name -> G.Type -> [String]
getTyCons dflag style name ty | Just (tyCon, _) <- Ty.splitTyConApp_maybe ty =
let name' = showName dflag style name -- Convert name to string
in getTyCon dflag style name' tyCon
getTyCons dflag style name _ = [showName dflag style name]

-- Write cases for one type
getTyCon :: DynFlags -> PprStyle -> String -> Ty.TyCon -> [String]
getTyCon :: G.DynFlags -> PprStyle -> String -> Ty.TyCon -> [String]
-- 1. Non-matcheable type constructors
getTyCon _ _ name tyCon | isNotMatcheableTyCon tyCon = [name]
-- 2. Special cases
Expand All @@ -152,7 +198,7 @@ isNotMatcheableTyCon ty = Ty.isPrimTyCon ty -- Primitive types, such as Int#
|| Ty.isFunTyCon ty -- Function types

-- Write case for one constructor
getDataCon :: DynFlags -> PprStyle -> String -> Ty.DataCon -> String
getDataCon :: G.DynFlags -> PprStyle -> String -> Ty.DataCon -> String
-- 1. Infix constructors
getDataCon dflag style vName dcon | Ty.dataConIsInfix dcon =
let dName = showName dflag style $ Ty.dataConName dcon
Expand Down Expand Up @@ -196,7 +242,7 @@ newVarsSpecialSingleton :: String -> Int -> Int -> String
newVarsSpecialSingleton v _ 1 = v
newVarsSpecialSingleton v start n = newVars v start n

showFieldNames :: DynFlags -> PprStyle -> String -> [G.Name] -> String
showFieldNames :: G.DynFlags -> PprStyle -> String -> [G.Name] -> String
showFieldNames _ _ _ [] = "" -- This should never happen
showFieldNames dflag style v (x:xs) = let fName = showName dflag style x
fAcc = fName ++ " = " ++ v ++ "_" ++ fName
Expand All @@ -207,11 +253,13 @@ showFieldNames dflag style v (x:xs) = let fName = showName dflag style x
----------------------------------------------------------------
-- c. Code for performing the case splitting

genCaseSplitTextFile :: (MonadIO m, GhcMonad m) =>
FilePath -> SplitToTextInfo -> m String
genCaseSplitTextFile file info = liftIO $ do
t <- T.readFile file
return $ getCaseSplitText (T.lines t) info

genCaseSplitTextFile :: IOish m =>
FilePath -> SplitToTextInfo -> GmlT m String
genCaseSplitTextFile file info =
withMappedFile file $ \file' -> liftIO $ do
t <- T.readFile file'
return $ getCaseSplitText (T.lines t) info

getCaseSplitText :: [T.Text] -> SplitToTextInfo -> String
getCaseSplitText t SplitToTextInfo{ sVarName = sVN, sBindingSpan = sBS
Expand All @@ -224,7 +272,7 @@ getCaseSplitText t SplitToTextInfo{ sVarName = sVN, sBindingSpan = sBS
replaced' = head replaced : map (indentBindingTo sBS) (tail replaced)
in T.unpack $ T.intercalate (T.pack "\n") (concat replaced')

getBindingText :: [T.Text] -> SrcSpan -> [T.Text]
getBindingText :: [T.Text] -> G.SrcSpan -> [T.Text]
getBindingText t srcSpan =
let Just (sl,sc,el,ec) = Gap.getSrcSpan srcSpan
lines_ = drop (sl - 1) $ take el t
Expand All @@ -235,7 +283,7 @@ getBindingText t srcSpan =
let (first,rest,last_) = (head lines_, tail $ init lines_, last lines_)
in T.drop (sc - 1) first : rest ++ [T.take ec last_]

srcSpanDifference :: SrcSpan -> SrcSpan -> (Int,Int,Int,Int)
srcSpanDifference :: G.SrcSpan -> G.SrcSpan -> (Int,Int,Int,Int)
srcSpanDifference b v =
let Just (bsl,bsc,_ ,_) = Gap.getSrcSpan b
Just (vsl,vsc,vel,vec) = Gap.getSrcSpan v
Expand All @@ -254,7 +302,7 @@ replaceVarWithTyCon t (vsl,vsc,_,vec) varname tycon =
else T.replicate spacesToAdd (T.pack " ") `T.append` line)
[0 ..] t

indentBindingTo :: SrcSpan -> [T.Text] -> [T.Text]
indentBindingTo :: G.SrcSpan -> [T.Text] -> [T.Text]
indentBindingTo bndLoc binds =
let Just (_,sl,_,_) = Gap.getSrcSpan bndLoc
indent = (T.replicate (sl - 1) (T.pack " ") `T.append`)
Expand Down
24 changes: 15 additions & 9 deletions GhcMod/Exe/Debug.hs
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,15 @@ debugInfo = do
Options {..} <- options
Cradle {..} <- cradle

[ghcPath, ghcPkgPath] <- liftIO $
mpaths <- liftIO $
case cradleProject of
StackProject se ->
catMaybes <$> sequence [getStackGhcPath se, getStackGhcPkgPath se]
_ ->
return ["ghc", "ghc-pkg"]
(ghcPath, ghcPkgPath) <- case mpaths of
[ghc,ghcp] -> return (ghc,ghcp)
_ -> error "pattern match fail"

cabal <-
case cradleProject of
Expand Down Expand Up @@ -67,13 +70,16 @@ debugInfo = do

stackPaths :: IOish m => GhcModT m [String]
stackPaths = do
Cradle { cradleProject = StackProject senv } <- cradle
ghc <- getStackGhcPath senv
ghcPkg <- getStackGhcPkgPath senv
return $
[ "Stack ghc executable: " ++ show ghc
, "Stack ghc-pkg executable:" ++ show ghcPkg
]
Cradle { cradleProject = menv } <- cradle
case menv of
StackProject senv -> do
ghc <- getStackGhcPath senv
ghcPkg <- getStackGhcPkgPath senv
return $
[ "Stack ghc executable: " ++ show ghc
, "Stack ghc-pkg executable:" ++ show ghcPkg
]
_ -> error "stackPaths:expected a stack project"

cabalDebug :: IOish m => FilePath -> GhcModT m [String]
cabalDebug ghcPkgPath = do
Expand Down Expand Up @@ -123,7 +129,7 @@ componentInfo ts = do
mdlcs = moduleComponents mcs `zipMap` Set.toList sefnmn
candidates = findCandidates $ map snd mdlcs
cn = pickComponent candidates
opts <- targetGhcOptions crdl sefnmn
opts <- fst <$> targetGhcOptions crdl sefnmn

return $ unlines $
[ "Matching Components:\n" ++ renderGm (nest 4 $
Expand Down
Loading