diff options
author | Matthías Páll Gissurarson <mpg@mpg.is> | 2018-07-12 09:57:00 -0400 |
---|---|---|
committer | Ben Gamari <ben@smart-cactus.org> | 2018-07-12 11:39:46 -0400 |
commit | c4d983412dc8128ac85d3bce0c8e91718af38ed2 (patch) | |
tree | 994b90a5ae3df4f852e163545ad53fe3d00e3c7f /compiler/iface/LoadIface.hs | |
parent | 101e90472b5536fffce1c19324db45451faf5246 (diff) | |
download | haskell-c4d983412dc8128ac85d3bce0c8e91718af38ed2.tar.gz |
Add flag to show docs of valid hole fits
One issue with valid hole fits is that the function names can often be
opaque for the uninitiated, such as `($)`. This diff adds a new flag,
`-fshow-docs-of-hole-fits` that adds the documentation of the identifier
in question to the message, using the same mechanism as the `:doc`
command.
As an example, with this flag enabled, the valid hole fits for `_ ::
[Int] -> Int` will include:
```
Valid hole fits include
head :: forall a. [a] -> a
{-^ Extract the first element of a list, which must be non-empty.-}
with head @Int
(imported from ‘Prelude’ (and originally defined in ‘GHC.List’))
```
And one of the refinement hole fits, `($) _`, will read:
```
Valid refinement hole fits include
...
($) (_ :: [Int] -> Int)
where ($) :: forall a b. (a -> b) -> a -> b
{-^ Application operator. This operator is redundant, since ordinary
application @(f x)@ means the same as @(f '$' x)@. However, '$' has
low, right-associative binding precedence, so it sometimes allows
parentheses to be omitted; for example:
> f $ g $ h x = f (g (h x))
It is also useful in higher-order situations, such as @'map' ('$' 0) xs@,
or @'Data.List.zipWith' ('$') fs xs@.
Note that @($)@ is levity-polymorphic in its result type, so that
foo $ True where foo :: Bool -> Int#
is well-typed-}
with ($) @'GHC.Types.LiftedRep @[Int] @Int
(imported from ‘Prelude’ (and originally defined in ‘GHC.Base’))
```
Another example of where documentation can come in very handy, is when
working with the `lens` library.
When you compile
```
{-# OPTIONS_GHC -fno-show-provenance-of-hole-fits -fshow-docs-of-hole-fits #-}
module LensDemo where
import Control.Lens
import Control.Monad.State
newtype Test = Test { _value :: Int } deriving (Show)
value :: Lens' Test Int
value f (Test i) = Test <$> f i
updTest :: Test -> Test
updTest t = t &~ do
_ value (1 :: Int)
```
You get:
```
Valid hole fits include
(#=) :: forall s (m :: * -> *) a b.
MonadState s m =>
ALens s s a b -> b -> m ()
{-^ A version of ('Control.Lens.Setter..=') that works on 'ALens'.-}
with (#=) @Test @(StateT Test Identity) @Int @Int
(<#=) :: forall s (m :: * -> *) a b.
MonadState s m =>
ALens s s a b -> b -> m b
{-^ A version of ('Control.Lens.Setter.<.=') that works on 'ALens'.-}
with (<#=) @Test @(StateT Test Identity) @Int @Int
(<*=) :: forall s (m :: * -> *) a.
(MonadState s m, Num a) =>
LensLike' ((,) a) s a -> a -> m a
{-^ Multiply the target of a numerically valued 'Lens' into your 'Monad''s
state and return the result.
When you do not need the result of the multiplication,
('Control.Lens.Setter.*=') is more flexible.
@
('<*=') :: ('MonadState' s m, 'Num' a) => 'Lens'' s a -> a -> m a
('<*=') :: ('MonadState' s m, 'Num' a) => 'Control.Lens.Iso.Iso'' s a -> a -> m a
@-}
with (<*=) @Test @(StateT Test Identity) @Int
(<+=) :: forall s (m :: * -> *) a.
(MonadState s m, Num a) =>
LensLike' ((,) a) s a -> a -> m a
{-^ Add to the target of a numerically valued 'Lens' into your 'Monad''s state
and return the result.
When you do not need the result of the addition,
('Control.Lens.Setter.+=') is more flexible.
@
('<+=') :: ('MonadState' s m, 'Num' a) => 'Lens'' s a -> a -> m a
('<+=') :: ('MonadState' s m, 'Num' a) => 'Control.Lens.Iso.Iso'' s a -> a -> m a
@-}
with (<+=) @Test @(StateT Test Identity) @Int
(<-=) :: forall s (m :: * -> *) a.
(MonadState s m, Num a) =>
LensLike' ((,) a) s a -> a -> m a
{-^ Subtract from the target of a numerically valued 'Lens' into your 'Monad''s
state and return the result.
When you do not need the result of the subtraction,
('Control.Lens.Setter.-=') is more flexible.
@
('<-=') :: ('MonadState' s m, 'Num' a) => 'Lens'' s a -> a -> m a
('<-=') :: ('MonadState' s m, 'Num' a) => 'Control.Lens.Iso.Iso'' s a -> a -> m a
@-}
with (<-=) @Test @(StateT Test Identity) @Int
(<<*=) :: forall s (m :: * -> *) a.
(MonadState s m, Num a) =>
LensLike' ((,) a) s a -> a -> m a
{-^ Modify the target of a 'Lens' into your 'Monad''s state by multipling a value
and return the /old/ value that was replaced.
When you do not need the result of the operation,
('Control.Lens.Setter.*=') is more flexible.
@
('<<*=') :: ('MonadState' s m, 'Num' a) => 'Lens'' s a -> a -> m a
('<<*=') :: ('MonadState' s m, 'Num' a) => 'Iso'' s a -> a -> m a
@-}
with (<<*=) @Test @(StateT Test Identity) @Int
(Some hole fits suppressed; use -fmax-valid-hole-fits=N or -fno-max-valid-hole-fits)
```
Which allows you to see at a glance what opaque operators like `(<<*=)`
and `(<#=)` do.
Reviewers: bgamari, sjakobi
Reviewed By: sjakobi
Subscribers: sjakobi, alexbiehl, rwbarton, thomie, carter
Differential Revision: https://phabricator.haskell.org/D4848
Diffstat (limited to 'compiler/iface/LoadIface.hs')
-rw-r--r-- | compiler/iface/LoadIface.hs | 11 |
1 files changed, 10 insertions, 1 deletions
diff --git a/compiler/iface/LoadIface.hs b/compiler/iface/LoadIface.hs index 20928d6ba5..4524402985 100644 --- a/compiler/iface/LoadIface.hs +++ b/compiler/iface/LoadIface.hs @@ -16,7 +16,7 @@ module LoadIface ( -- RnM/TcM functions loadModuleInterface, loadModuleInterfaces, loadSrcInterface, loadSrcInterface_maybe, - loadInterfaceForName, loadInterfaceForModule, + loadInterfaceForName, loadInterfaceForNameMaybe, loadInterfaceForModule, -- IfM functions loadInterface, @@ -313,6 +313,15 @@ loadInterfaceForName doc name ; ASSERT2( isExternalName name, ppr name ) initIfaceTcRn $ loadSysInterface doc (nameModule name) } +-- | Only loads the interface for external non-local names. +loadInterfaceForNameMaybe :: SDoc -> Name -> TcRn (Maybe ModIface) +loadInterfaceForNameMaybe doc name + = do { this_mod <- getModule + ; if nameIsLocalOrFrom this_mod name || not (isExternalName name) + then return Nothing + else Just <$> (initIfaceTcRn $ loadSysInterface doc (nameModule name)) + } + -- | Loads the interface for a given Module. loadInterfaceForModule :: SDoc -> Module -> TcRn ModIface loadInterfaceForModule doc m |