Skip to content

Commit b440621

Browse files
committed
Merge branch 'master' into new-import-no-exactprint
2 parents 1f84e79 + 988c498 commit b440621

27 files changed

+335
-59
lines changed

ghcide/src/Development/IDE/Core/Debouncer.hs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ module Development.IDE.Core.Debouncer
1111
import Control.Concurrent.Async
1212
import Control.Concurrent.Extra
1313
import Control.Exception
14-
import Control.Monad.Extra
14+
import Control.Monad (join)
15+
import Data.Foldable (traverse_)
1516
import Data.HashMap.Strict (HashMap)
1617
import qualified Data.HashMap.Strict as Map
1718
import Data.Hashable
@@ -40,17 +41,18 @@ newAsyncDebouncer = Debouncer . asyncRegisterEvent <$> newVar Map.empty
4041
-- to mask if required.
4142
asyncRegisterEvent :: (Eq k, Hashable k) => Var (HashMap k (Async ())) -> Seconds -> k -> IO () -> IO ()
4243
asyncRegisterEvent d 0 k fire = do
43-
modifyVar_ d $ \m -> mask_ $ do
44-
whenJust (Map.lookup k m) cancel
45-
pure $ Map.delete k m
44+
join $ modifyVar d $ \m -> do
45+
(cancel, !m') <- evaluate $ Map.alterF (\prev -> (traverse_ cancel prev, Nothing)) k m
46+
return (m', cancel)
4647
fire
47-
asyncRegisterEvent d delay k fire = modifyVar_ d $ \m -> mask_ $ do
48-
whenJust (Map.lookup k m) cancel
48+
asyncRegisterEvent d delay k fire = mask_ $ do
4949
a <- asyncWithUnmask $ \unmask -> unmask $ do
5050
sleep delay
5151
fire
52-
modifyVar_ d (pure . Map.delete k)
53-
pure $ Map.insert k a m
52+
modifyVar_ d (evaluate . Map.delete k)
53+
join $ modifyVar d $ \m -> do
54+
(cancel, !m') <- evaluate $ Map.alterF (\prev -> (traverse_ cancel prev, Just a)) k m
55+
return (m', cancel)
5456

5557
-- | Debouncer used in the DAML CLI compiler that emits events immediately.
5658
noopDebouncer :: Debouncer k

ghcide/src/Development/IDE/Core/Shake.hs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1100,15 +1100,16 @@ updateFileDiagnostics fp k ShakeExtras{logger, diagnostics, hiddenDiagnostics, p
11001100
let uri = filePathToUri' fp
11011101
let delay = if null newDiags then 0.1 else 0
11021102
registerEvent debouncer delay uri $ do
1103-
mask_ $ modifyVar_ publishedDiagnostics $ \published -> do
1103+
join $ mask_ $ modifyVar publishedDiagnostics $ \published -> do
11041104
let lastPublish = HMap.lookupDefault [] uri published
1105-
when (lastPublish /= newDiags) $ case lspEnv of
1106-
Nothing -> -- Print an LSP event.
1107-
logInfo logger $ showDiagnosticsColored $ map (fp,ShowDiag,) newDiags
1108-
Just env -> LSP.runLspT env $
1109-
LSP.sendNotification LSP.STextDocumentPublishDiagnostics $
1110-
LSP.PublishDiagnosticsParams (fromNormalizedUri uri) ver (List newDiags)
1111-
pure $! HMap.insert uri newDiags published
1105+
!published' = HMap.insert uri newDiags published
1106+
action = when (lastPublish /= newDiags) $ case lspEnv of
1107+
Nothing -> -- Print an LSP event.
1108+
logInfo logger $ showDiagnosticsColored $ map (fp,ShowDiag,) newDiags
1109+
Just env -> LSP.runLspT env $
1110+
LSP.sendNotification LSP.STextDocumentPublishDiagnostics $
1111+
LSP.PublishDiagnosticsParams (fromNormalizedUri uri) ver (List newDiags)
1112+
return (published', action)
11121113

11131114
newtype Priority = Priority Double
11141115

ghcide/src/Development/IDE/Main.hs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ import Data.Maybe (catMaybes, fromMaybe,
1515
import qualified Data.Text as T
1616
import qualified Data.Text.IO as T
1717
import Development.IDE (Action, Rules)
18-
import Development.IDE.Core.Debouncer (newAsyncDebouncer)
18+
import Development.IDE.Core.Debouncer (Debouncer,
19+
newAsyncDebouncer)
1920
import Development.IDE.Core.FileStore (makeVFSHandle)
2021
import Development.IDE.Core.IdeConfiguration (IdeConfiguration (..),
2122
registerIdeConfiguration)
@@ -43,7 +44,8 @@ import Development.IDE.Session (SessionLoadingOptions,
4344
loadSessionWithOptions,
4445
runWithDb,
4546
setInitialDynFlags)
46-
import Development.IDE.Types.Location (toNormalizedFilePath')
47+
import Development.IDE.Types.Location (NormalizedUri,
48+
toNormalizedFilePath')
4749
import Development.IDE.Types.Logger (Logger (Logger))
4850
import Development.IDE.Types.Options (IdeGhcSession,
4951
IdeOptions (optCheckParents, optCheckProject, optReportProgress),
@@ -86,6 +88,7 @@ data Arguments = Arguments
8688
, argsLspOptions :: LSP.Options
8789
, argsDefaultHlsConfig :: Config
8890
, argsGetHieDbLoc :: FilePath -> IO FilePath -- ^ Map project roots to the location of the hiedb for the project
91+
, argsDebouncer :: IO (Debouncer NormalizedUri) -- ^ Debouncer used for diagnostics
8992
}
9093

9194
instance Default Arguments where
@@ -101,6 +104,7 @@ instance Default Arguments where
101104
, argsLspOptions = def {LSP.completionTriggerCharacters = Just "."}
102105
, argsDefaultHlsConfig = def
103106
, argsGetHieDbLoc = getHieDbLoc
107+
, argsDebouncer = newAsyncDebouncer
104108
}
105109

106110
-- | Cheap stderr logger that relies on LineBuffering
@@ -123,6 +127,8 @@ defaultMain Arguments{..} = do
123127
argsOnConfigChange _ide = pure . getConfigFromNotification argsDefaultHlsConfig
124128
rules = argsRules >> pluginRules plugins
125129

130+
debouncer <- argsDebouncer
131+
126132
case argFiles of
127133
Nothing -> do
128134
t <- offsetTime
@@ -148,7 +154,6 @@ defaultMain Arguments{..} = do
148154
{ optReportProgress = clientSupportsProgress caps
149155
}
150156
caps = LSP.resClientCapabilities env
151-
debouncer <- newAsyncDebouncer
152157
initialise
153158
argsDefaultHlsConfig
154159
rules
@@ -184,7 +189,6 @@ defaultMain Arguments{..} = do
184189
when (n > 0) $ putStrLn $ " (" ++ intercalate ", " (catMaybes ucradles) ++ ")"
185190
putStrLn "\nStep 3/4: Initializing the IDE"
186191
vfs <- makeVFSHandle
187-
debouncer <- newAsyncDebouncer
188192
sessionLoader <- loadSessionWithOptions argsSessionLoadingOptions dir
189193
let options = (argsIdeOptions Nothing sessionLoader)
190194
{ optCheckParents = pure NeverCheck

plugins/hls-tactics-plugin/src/Wingman/CodeGen.hs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,11 @@ module Wingman.CodeGen
1111

1212
import Control.Lens ((%~), (<>~), (&))
1313
import Control.Monad.Except
14+
import Control.Monad.State
1415
import Data.Generics.Labels ()
1516
import Data.List
17+
import Data.Maybe (mapMaybe)
18+
import Data.Monoid (Endo(..))
1619
import qualified Data.Set as S
1720
import Data.Traversable
1821
import DataCon
@@ -26,6 +29,7 @@ import Type hiding (Var)
2629
import Wingman.CodeGen.Utils
2730
import Wingman.GHC
2831
import Wingman.Judgements
32+
import Wingman.Judgements.Theta
2933
import Wingman.Machinery
3034
import Wingman.Naming
3135
import Wingman.Types
@@ -50,12 +54,20 @@ destructMatches f scrut t jdg = do
5054
case dcs of
5155
[] -> throwError $ GoalMismatch "destruct" g
5256
_ -> fmap unzipTrace $ for dcs $ \dc -> do
53-
let args = dataConInstOrigArgTys' dc apps
57+
let ev = mapMaybe mkEvidence $ dataConInstArgTys dc apps
58+
-- We explicitly do not need to add the method hypothesis to
59+
-- #syn_scoped
60+
method_hy = foldMap evidenceToHypothesis ev
61+
args = dataConInstOrigArgTys' dc apps
62+
modify $ appEndo $ foldMap (Endo . evidenceToSubst) ev
63+
subst <- gets ts_unifier
5464
names <- mkManyGoodNames (hyNamesInScope hy) args
5565
let hy' = patternHypothesis scrut dc jdg
5666
$ zip names
5767
$ coerce args
58-
j = introduce hy'
68+
j = fmap (CType . substTyAddInScope subst . unCType)
69+
$ introduce hy'
70+
$ introduce method_hy
5971
$ withNewGoal g jdg
6072
ext <- f dc j
6173
pure $ ext

plugins/hls-tactics-plugin/src/Wingman/Judgements.hs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,13 @@ isTopLevel TopLevelArgPrv{} = True
369369
isTopLevel _ = False
370370

371371

372+
------------------------------------------------------------------------------
373+
-- | Was this term defined by the user?
374+
isUserProv :: Provenance -> Bool
375+
isUserProv UserPrv{} = True
376+
isUserProv _ = False
377+
378+
372379
------------------------------------------------------------------------------
373380
-- | Is this a local function argument, pattern match or user val?
374381
isLocalHypothesis :: Provenance -> Bool
Lines changed: 123 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,100 @@
1+
{-# LANGUAGE CPP #-}
12
{-# LANGUAGE ViewPatterns #-}
23

34
module Wingman.Judgements.Theta
4-
( getMethodHypothesisAtHole
5+
( Evidence
6+
, getEvidenceAtHole
7+
, mkEvidence
8+
, evidenceToSubst
9+
, evidenceToHypothesis
510
) where
611

7-
import Data.Maybe (fromMaybe)
12+
import Data.Maybe (fromMaybe, mapMaybe)
813
import Data.Set (Set)
914
import qualified Data.Set as S
1015
import Development.IDE.GHC.Compat
11-
import Generics.SYB
12-
import GhcPlugins (EvVar, mkVarOcc)
16+
import Generics.SYB hiding (tyConName)
17+
import GhcPlugins (mkVarOcc, splitTyConApp_maybe, getTyVar_maybe)
18+
#if __GLASGOW_HASKELL__ > 806
19+
import GhcPlugins (eqTyCon)
20+
#else
21+
import GhcPlugins (nameRdrName, tyConName)
22+
import PrelNames (eqTyCon_RDR)
23+
#endif
24+
import TcEvidence
25+
import TcType (tcTyConAppTyCon_maybe)
26+
import TysPrim (eqPrimTyCon)
1327
import Wingman.Machinery
1428
import Wingman.Types
1529

1630

1731
------------------------------------------------------------------------------
18-
-- | Create a 'Hypothesis' containing 'ClassMethodPrv' provenance. For every
19-
-- dictionary that is in scope at the given 'SrcSpan', find every method and
20-
-- superclass method available.
21-
getMethodHypothesisAtHole :: SrcSpan -> LHsBinds GhcTc -> Hypothesis CType
22-
getMethodHypothesisAtHole dst
23-
= Hypothesis
24-
. excludeForbiddenMethods
25-
. fromMaybe []
26-
. foldMap methodHypothesis
27-
. (everything (<>) $ mkQ mempty $ evbinds dst)
32+
-- | Something we've learned about the type environment.
33+
data Evidence
34+
-- | The two types are equal, via a @a ~ b@ relationship
35+
= EqualityOfTypes Type Type
36+
-- | We have an instance in scope
37+
| HasInstance PredType
38+
deriving (Show)
39+
40+
41+
------------------------------------------------------------------------------
42+
-- | Given a 'PredType', pull an 'Evidence' out of it.
43+
mkEvidence :: PredType -> Maybe Evidence
44+
mkEvidence (getEqualityTheta -> Just (a, b))
45+
= Just $ EqualityOfTypes a b
46+
mkEvidence inst@(tcTyConAppTyCon_maybe -> Just (isClassTyCon -> True))
47+
= Just $ HasInstance inst
48+
mkEvidence _ = Nothing
49+
50+
51+
------------------------------------------------------------------------------
52+
-- | Compute all the 'Evidence' implicitly bound at the given 'SrcSpan'.
53+
getEvidenceAtHole :: SrcSpan -> LHsBinds GhcTc -> [Evidence]
54+
getEvidenceAtHole dst
55+
= mapMaybe mkEvidence
56+
. (everything (<>) $
57+
mkQ mempty (absBinds dst) `extQ` wrapperBinds dst `extQ` matchBinds dst)
58+
59+
60+
------------------------------------------------------------------------------
61+
-- | Update our knowledge of which types are equal.
62+
evidenceToSubst :: Evidence -> TacticState -> TacticState
63+
evidenceToSubst (EqualityOfTypes a b) ts =
64+
let tyvars = S.fromList $ mapMaybe getTyVar_maybe [a, b]
65+
-- If we can unify our skolems, at least one is no longer a skolem.
66+
-- Removing them from this set ensures we can get a subtitution between
67+
-- the two. But it's okay to leave them in 'ts_skolems' in general, since
68+
-- they won't exist after running this substitution.
69+
skolems = ts_skolems ts S.\\ tyvars
70+
in
71+
case tryUnifyUnivarsButNotSkolems skolems (CType a) (CType b) of
72+
Just subst -> updateSubst subst ts
73+
Nothing -> ts
74+
evidenceToSubst HasInstance{} ts = ts
75+
76+
77+
------------------------------------------------------------------------------
78+
-- | Get all of the methods that are in scope from this piece of 'Evidence'.
79+
evidenceToHypothesis :: Evidence -> Hypothesis CType
80+
evidenceToHypothesis EqualityOfTypes{} = mempty
81+
evidenceToHypothesis (HasInstance t) =
82+
Hypothesis . excludeForbiddenMethods . fromMaybe [] $ methodHypothesis t
83+
84+
85+
------------------------------------------------------------------------------
86+
-- | Given @a ~ b@ or @a ~# b@, returns @Just (a, b)@, otherwise @Nothing@.
87+
getEqualityTheta :: PredType -> Maybe (Type, Type)
88+
getEqualityTheta (splitTyConApp_maybe -> Just (tc, [_k, a, b]))
89+
#if __GLASGOW_HASKELL__ > 806
90+
| tc == eqTyCon
91+
#else
92+
| nameRdrName (tyConName tc) == eqTyCon_RDR
93+
#endif
94+
= Just (a, b)
95+
getEqualityTheta (splitTyConApp_maybe -> Just (tc, [_k1, _k2, a, b]))
96+
| tc == eqPrimTyCon = Just (a, b)
97+
getEqualityTheta _ = Nothing
2898

2999

30100
------------------------------------------------------------------------------
@@ -38,13 +108,48 @@ excludeForbiddenMethods = filter (not . flip S.member forbiddenMethods . hi_name
38108
forbiddenMethods = S.map mkVarOcc $ S.fromList
39109
[ -- monadfail
40110
"fail"
111+
-- show
112+
, "showsPrec"
113+
, "showList"
41114
]
42115

43116

44117
------------------------------------------------------------------------------
45-
-- | Extract the types of the evidence bindings in scope.
46-
evbinds :: SrcSpan -> LHsBindLR GhcTc GhcTc -> [PredType]
47-
evbinds dst (L src (AbsBinds _ _ h _ _ _ _))
118+
-- | Extract evidence from 'AbsBinds' in scope.
119+
absBinds :: SrcSpan -> LHsBindLR GhcTc GhcTc -> [PredType]
120+
absBinds dst (L src (AbsBinds _ _ h _ _ _ _))
48121
| dst `isSubspanOf` src = fmap idType h
49-
evbinds _ _ = []
122+
absBinds _ _ = []
123+
124+
125+
------------------------------------------------------------------------------
126+
-- | Extract evidence from 'HsWrapper's in scope
127+
wrapperBinds :: SrcSpan -> LHsExpr GhcTc -> [PredType]
128+
wrapperBinds dst (L src (HsWrap _ h _))
129+
| dst `isSubspanOf` src = wrapper h
130+
wrapperBinds _ _ = []
131+
132+
133+
------------------------------------------------------------------------------
134+
-- | Extract evidence from the 'ConPatOut's bound in this 'Match'.
135+
matchBinds :: SrcSpan -> LMatch GhcTc (LHsExpr GhcTc) -> [PredType]
136+
matchBinds dst (L src (Match _ _ pats _))
137+
| dst `isSubspanOf` src = everything (<>) (mkQ mempty patBinds) pats
138+
matchBinds _ _ = []
139+
140+
141+
------------------------------------------------------------------------------
142+
-- | Extract evidence from a 'ConPatOut'.
143+
patBinds :: Pat GhcTc -> [PredType]
144+
patBinds (ConPatOut { pat_dicts = dicts })
145+
= fmap idType dicts
146+
patBinds _ = []
147+
148+
149+
------------------------------------------------------------------------------
150+
-- | Extract the types of the evidence bindings in scope.
151+
wrapper :: HsWrapper -> [PredType]
152+
wrapper (WpCompose h h2) = wrapper h <> wrapper h2
153+
wrapper (WpEvLam v) = [idType v]
154+
wrapper _ = []
50155

plugins/hls-tactics-plugin/src/Wingman/LanguageServer.hs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import Development.IDE.Spans.LocalBindings (Bindings, getDefiningBindi
3131
import Development.Shake (Action, RuleResult)
3232
import Development.Shake.Classes (Typeable, Binary, Hashable, NFData)
3333
import qualified FastString
34-
import GhcPlugins (mkAppTys, tupleDataCon, consDataCon)
34+
import GhcPlugins (mkAppTys, tupleDataCon, consDataCon, substTyAddInScope)
3535
import Ide.Plugin.Config (PluginConfig (plcConfig))
3636
import qualified Ide.Plugin.Config as Plugin
3737
import Language.LSP.Server (MonadLsp, sendNotification)
@@ -44,7 +44,7 @@ import Wingman.Context
4444
import Wingman.FeatureSet
4545
import Wingman.GHC
4646
import Wingman.Judgements
47-
import Wingman.Judgements.Theta (getMethodHypothesisAtHole)
47+
import Wingman.Judgements.Theta
4848
import Wingman.Range
4949
import Wingman.Types
5050

@@ -143,8 +143,10 @@ mkJudgementAndContext features g binds rss tcmod = do
143143
top_provs = getRhsPosVals rss tcs
144144
local_hy = spliceProvenance top_provs
145145
$ hypothesisFromBindings rss binds
146-
cls_hy = getMethodHypothesisAtHole (RealSrcSpan rss) tcs
147-
in ( mkFirstJudgement
146+
evidence = getEvidenceAtHole (RealSrcSpan rss) tcs
147+
cls_hy = foldMap evidenceToHypothesis evidence
148+
subst = ts_unifier $ appEndo (foldMap (Endo . evidenceToSubst) evidence) defaultTacticState
149+
in ( fmap (CType . substTyAddInScope subst . unCType) $ mkFirstJudgement
148150
(local_hy <> cls_hy)
149151
(isRhsHole rss tcs)
150152
g

0 commit comments

Comments
 (0)