Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Agda-style case splitting for tactics #1379

Merged
merged 32 commits into from
Feb 17, 2021
Merged
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
4552fb8
Agda splitting machinery
isovector Feb 12, 2021
81c7411
Expand decls!
isovector Feb 12, 2021
bf4e670
Only very top-level lambda to args
isovector Feb 12, 2021
ee2094e
Preserve top-level args (but it doesnt work very well)
isovector Feb 12, 2021
cf75b1e
Preserve existing patterns and matches when agdasplitting
isovector Feb 14, 2021
14fa9f6
Add traceFX debug function
isovector Feb 14, 2021
f3ea83f
Force a few iterations of splitAgda
isovector Feb 14, 2021
0e120de
Merge branch 'master' into agda-case-split
isovector Feb 14, 2021
d573e7a
Cleanup imports
isovector Feb 14, 2021
de541c2
Put wildcard patterns in for unused variables
isovector Feb 14, 2021
af02f05
Update tests
isovector Feb 14, 2021
6a5f2e4
Agda-unfold on instance deps
isovector Feb 15, 2021
5a38557
wildify at the very end of simplifying
isovector Feb 15, 2021
e78549c
Haddock for top-level functions
isovector Feb 15, 2021
cca1f34
Move case splitting stuff into its own module
isovector Feb 15, 2021
8fcb936
Exactprint comments
isovector Feb 15, 2021
41c7461
Haddock for casesplit
isovector Feb 15, 2021
c6112c4
Use PatCompat
isovector Feb 15, 2021
57c2da2
Remove HsDumpAst
isovector Feb 15, 2021
0d698aa
Use Pat, not LPat
isovector Feb 16, 2021
5c1f3e0
More massaging Pats
isovector Feb 16, 2021
96f566b
Only unXPat on 8.0.8
isovector Feb 16, 2021
57e906f
Haddock and cleanup -Wall
isovector Feb 16, 2021
b857ca7
Cleanup sus errors
isovector Feb 16, 2021
3ea09c3
Fix parse errors in GHC > 8.8
isovector Feb 16, 2021
5348c61
Merge branch 'master' into agda-case-split
isovector Feb 16, 2021
b2236b8
Update comment around unXPat
isovector Feb 16, 2021
1261489
Cleanup ExactPrint to split FunBind matches
isovector Feb 16, 2021
d8a8198
Minor haddock tweak
isovector Feb 16, 2021
529e4dd
Bad suggest, hlint
isovector Feb 16, 2021
cffba27
I hate hlint with so much passion
isovector Feb 16, 2021
054e59d
Merge branch 'master' into agda-case-split
pepeiborra Feb 17, 2021
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
86 changes: 81 additions & 5 deletions ghcide/src/Development/IDE/GHC/ExactPrint.hs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
{-# LANGUAGE CPP #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeFamilies #-}

{- HLINT ignore "Use zipFrom" -}

module Development.IDE.GHC.ExactPrint
( Graft(..),
Expand All @@ -15,6 +17,8 @@ module Development.IDE.GHC.ExactPrint
hoistGraft,
graftWithM,
graftWithSmallestM,
graftSmallestDecls,
graftSmallestDeclsWithM,
transform,
transformM,
useAnnotatedSource,
Expand Down Expand Up @@ -60,9 +64,17 @@ import Language.LSP.Types.Capabilities (ClientCapabilities)
import Outputable (Outputable, ppr, showSDoc)
import Retrie.ExactPrint hiding (parseDecl, parseExpr, parsePattern, parseType)
import Parser (parseIdentifier)
import Data.Traversable (for)
import Data.Foldable (Foldable(fold))
import Data.Bool (bool)
#if __GLASGOW_HASKELL__ == 808
import Control.Arrow
#endif
#if __GLASGOW_HASKELL__ > 808
import Bag (listToBag)
import ErrUtils (mkErrMsg)
import Outputable (text, neverQualify)
#endif


------------------------------------------------------------------------------
Expand Down Expand Up @@ -202,6 +214,7 @@ graftWithoutParentheses dst val = Graft $ \dflags a -> do
)
a


------------------------------------------------------------------------------

graftWithM ::
Expand Down Expand Up @@ -271,6 +284,44 @@ graftDecls dst decs0 = Graft $ \dflags a -> do
| otherwise = DL.singleton (L src e) <> go rest
modifyDeclsT (pure . DL.toList . go) a

graftSmallestDecls ::
forall a.
(HasDecls a) =>
SrcSpan ->
[LHsDecl GhcPs] ->
Graft (Either String) a
graftSmallestDecls dst decs0 = Graft $ \dflags a -> do
decs <- forM decs0 $ \decl -> do
(anns, decl') <- annotateDecl dflags decl
modifyAnnsT $ mappend anns
pure decl'
let go [] = DL.empty
go (L src e : rest)
| dst `isSubspanOf` src = DL.fromList decs <> DL.fromList rest
| otherwise = DL.singleton (L src e) <> go rest
modifyDeclsT (pure . DL.toList . go) a
isovector marked this conversation as resolved.
Show resolved Hide resolved

graftSmallestDeclsWithM ::
forall a.
(HasDecls a) =>
SrcSpan ->
(LHsDecl GhcPs -> TransformT (Either String) (Maybe [LHsDecl GhcPs])) ->
Graft (Either String) a
graftSmallestDeclsWithM dst toDecls = Graft $ \dflags a -> do
let go [] = pure DL.empty
go (e@(L src _) : rest)
| dst `isSubspanOf` src = toDecls e >>= \case
Just decs0 -> do
decs <- forM decs0 $ \decl -> do
(anns, decl') <-
annotateDecl dflags decl
modifyAnnsT $ mappend anns
pure decl'
pure $ DL.fromList decs <> DL.fromList rest
Nothing -> (DL.singleton e <>) <$> go rest
| otherwise = (DL.singleton e <>) <$> go rest
isovector marked this conversation as resolved.
Show resolved Hide resolved
modifyDeclsT (fmap DL.toList . go) a

graftDeclsWithM ::
forall a m.
(HasDecls a, Fail.MonadFail m) =>
Expand Down Expand Up @@ -355,12 +406,37 @@ annotate dflags ast = do

-- | Given an 'LHsDecl', compute its exactprint annotations.
annotateDecl :: DynFlags -> LHsDecl GhcPs -> TransformT (Either String) (Anns, LHsDecl GhcPs)
-- The 'parseDecl' function fails to parse 'FunBind' 'ValD's which contain
-- multiple matches. To work around this, we split the single
-- 'FunBind'-of-multiple-'Match'es into multiple 'FunBind's-of-one-'Match',
-- and then merge them all back together.
annotateDecl dflags
(L src (
ValD ext fb@FunBind
{ fun_matches = mg@MG { mg_alts = L alt_src alts@(_:_)}
})) = do
let set_matches matches =
ValD ext fb { fun_matches = mg { mg_alts = L alt_src matches }}

(anns', alts') <- fmap unzip $ for (zip [0..] alts) $ \(ix :: Int, alt) -> do
uniq <- show <$> uniqueSrcSpanT
let rendered = render dflags $ set_matches [alt]
lift (mapLeft show $ parseDecl dflags uniq rendered) >>= \case
(ann, L _ (ValD _ FunBind { fun_matches = MG { mg_alts = L _ [alt']}}))
-> pure (bool id (setPrecedingLines alt' 1 0) (ix /= 0) ann, alt')
_ -> lift $ Left "annotateDecl: didn't parse a single FunBind match"

let expr' = L src $ set_matches alts'
anns'' = setPrecedingLines expr' 1 0 $ fold anns'

pure (anns'', expr')
annotateDecl dflags ast = do
uniq <- show <$> uniqueSrcSpanT
let rendered = render dflags ast
(anns, expr') <- lift $ mapLeft show $ parseDecl dflags uniq rendered
let anns' = setPrecedingLines expr' 1 0 anns
pure (anns', expr')

------------------------------------------------------------------------------

-- | Print out something 'Outputable'.
Expand Down
1 change: 1 addition & 0 deletions plugins/hls-tactics-plugin/hls-tactics-plugin.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ library
exposed-modules:
Ide.Plugin.Tactic
Ide.Plugin.Tactic.Auto
Ide.Plugin.Tactic.CaseSplit
Ide.Plugin.Tactic.CodeGen
Ide.Plugin.Tactic.CodeGen.Utils
Ide.Plugin.Tactic.Context
Expand Down
Loading