Commit cbdea959 authored by Matthías Páll Gissurarson's avatar Matthías Páll Gissurarson Committed by Ben Gamari

Sort valid substitutions for typed holes by "relevance"

This is an initial attempt at tackling the issue of how to order the
suggestions provided by the valid substitutions checker, by sorting
them by creating a graph of how they subsume each other. We'd like to
order them in such a manner that the most "relevant" suggestions are
displayed first, so that the suggestion that the user might be looking
for is displayed before more far-fetched suggestions (and thus also
displayed when they'd otherwise be cut-off by the
`-fmax-valid-substitutions` limit). The previous ordering was based on
the order in which the elements appear in the list of imports, which I
believe is less correlated with relevance than this ordering.

A drawback of this approach is that, since we now want to sort the
elements, we can no longer "bail out early" when we've hit the
`-fmax-valid-substitutions` limit.

Reviewers: bgamari, dfeuer

Reviewed By: dfeuer

Subscribers: dfeuer, rwbarton, thomie, carter

Differential Revision: https://phabricator.haskell.org/D4326
parent 31c260f3
......@@ -553,6 +553,8 @@ data GeneralFlag
| Opt_PprCaseAsLet
| Opt_PprShowTicks
| Opt_ShowHoleConstraints
| Opt_NoShowValidSubstitutions
| Opt_NoSortValidSubstitutions
| Opt_ShowLoadedModules
-- Suppress all coercions, them replacing with '...'
......@@ -800,8 +802,8 @@ data DynFlags = DynFlags {
maxRelevantBinds :: Maybe Int, -- ^ Maximum number of bindings from the type envt
-- to show in type error messages
maxValidSubstitutions :: Maybe Int, -- ^ Maximum number of substitutions
-- to show in type error messages
maxValidSubstitutions :: Maybe Int, -- ^ Maximum number of substitutions to
-- show in typed hole error messages
maxUncoveredPatterns :: Int, -- ^ Maximum number of unmatched patterns to show
-- in non-exhaustiveness warnings
simplTickFactor :: Int, -- ^ Multiplier for simplifier ticks
......@@ -3897,6 +3899,8 @@ fFlagsDeps = [
flagSpec "show-warning-groups" Opt_ShowWarnGroups,
flagSpec "hide-source-paths" Opt_HideSourcePaths,
flagSpec "show-hole-constraints" Opt_ShowHoleConstraints,
flagSpec "no-show-valid-substitutions" Opt_NoShowValidSubstitutions,
flagSpec "no-sort-valid-substitutions" Opt_NoSortValidSubstitutions,
flagSpec "show-loaded-modules" Opt_ShowLoadedModules,
flagSpec "whole-archive-hs-libs" Opt_WholeArchiveHsLibs
]
......
......@@ -50,7 +50,7 @@ import BasicTypes
import ConLike ( ConLike(..))
import Util
import TcEnv (tcLookup)
import {-# SOURCE #-} TcSimplify ( tcCheckHoleFit )
import {-# SOURCE #-} TcSimplify ( tcCheckHoleFit, tcSubsumes )
import FastString
import Outputable
import SrcLoc
......@@ -61,10 +61,13 @@ import Pair
import qualified GHC.LanguageExtensions as LangExt
import FV ( fvVarList, fvVarSet, unionFV )
import Control.Monad ( when )
import Control.Monad ( when, filterM )
import Data.Foldable ( toList )
import Data.List ( partition, mapAccumL, nub, sortBy, unfoldr, foldl')
import Data.List ( partition, mapAccumL, nub
, sortBy, sort, unfoldr, foldl' )
import qualified Data.Set as Set
import Data.Graph ( graphFromEdges, topSort )
import Data.Function ( on )
import Data.Semigroup ( Semigroup )
import qualified Data.Semigroup as Semigroup
......@@ -1085,7 +1088,9 @@ mkHoleError tidy_simples ctxt ct@(CHoleCan { cc_hole = hole })
= givenConstraintsMsg ctxt
| otherwise = empty
; sub_msg <- validSubstitutions tidy_simples ctxt ct
; no_show_valid_substitutions <- goptM Opt_NoShowValidSubstitutions
; sub_msg <- if no_show_valid_substitutions then return empty
else validSubstitutions tidy_simples ctxt ct
; mkErrorMsgFromCt ctxt ct $
important hole_msg `mappend`
relevant_bindings (binds_msg $$ constraints_msg) `mappend`
......@@ -1146,22 +1151,52 @@ mkHoleError tidy_simples ctxt ct@(CHoleCan { cc_hole = hole })
mkHoleError _ _ ct = pprPanic "mkHoleError" (ppr ct)
-- HoleFit is the type we use for a fit in valid substitutions. It contains the
-- element that was checked and the elements Id.
data HoleFit = HoleFit { hfEl :: GlobalRdrElt , hfId :: Id }
-- We define an Eq and Ord instance to be able to build a graph.
instance Eq HoleFit where
(==) = (==) `on` hfId
-- We compare HoleFits by their gre_name instead of their Id, since we don't
-- want our tests to be affected by the non-determinism of `nonDetCmpVar`,
-- which is used to compare Ids.
instance Ord HoleFit where
compare = compare `on` (gre_name . hfEl)
-- See Note [Valid substitutions include ...]
validSubstitutions :: [Ct] -> ReportErrCtxt -> Ct -> TcM SDoc
validSubstitutions simples (CEC {cec_encl = implics}) ct | isExprHoleCt ct =
do { rdr_env <- getGlobalRdrEnv
; dflags <- getDynFlags
; traceTc "findingValidSubstitutionsFor {" $ ppr wrapped_hole_ty
; (discards, substitutions) <-
setTcLevel hole_lvl $
go (maxValidSubstitutions dflags) $
localsFirst $ globalRdrEnvElts rdr_env
; traceTc "}" empty
; return $ ppUnless (null substitutions) $
hang (text "Valid substitutions include")
2 (vcat (map ppr_sub substitutions)
$$ ppWhen discards subsDiscardMsg) }
; maxSubs <- maxValidSubstitutions <$> getDynFlags
; sortSubs <- not <$> goptM Opt_NoSortValidSubstitutions
-- If we're not supposed to output any substitutions, we don't want to do
-- any work.
; if maxSubs == Just 0
then return empty
else do { traceTc "findingValidSubstitutionsFor {" $ ppr wrapped_hole_ty
; let limit = if sortSubs then Nothing else maxSubs
; (discards, subs) <-
setTcLevel hole_lvl $ go limit $ globalRdrEnvElts rdr_env
-- We split the fits into localFits and globalFits and show
-- local fit before global fits, since they are probably more
-- relevant to the user.
; let (lclFits, gblFits) = partition (gre_lcl . hfEl) subs
; (discards, sortedSubs) <-
-- We sort the fits first, to prevent the order of
-- suggestions being effected when identifiers are moved
-- around in modules. We use (<*>) to expose the
-- parallelism, in case it becomes useful later.
if sortSubs then possiblyDiscard maxSubs <$>
((++) <$> sortByGraph (sort lclFits)
<*> sortByGraph (sort gblFits))
else return (discards, lclFits ++ gblFits)
; traceTc "}" empty
; return $ ppUnless (null sortedSubs) $
hang (text "Valid substitutions include")
2 (vcat (map ppr_sub sortedSubs)
$$ ppWhen discards subsDiscardMsg) } }
where
-- We extract the type of the hole from the constraint.
hole_ty :: TcPredType
......@@ -1175,16 +1210,18 @@ validSubstitutions simples (CEC {cec_encl = implics}) ct | isExprHoleCt ct =
wrapped_hole_ty :: TcSigmaType
wrapped_hole_ty = foldl' wrapTypeWithImplication hole_ty implics
-- We rearrange the elements to make locals appear at the top of the list,
-- since they're most likely to be relevant to the user
localsFirst :: [GlobalRdrElt] -> [GlobalRdrElt]
-- We rearrange the elements to make locals appear at the top of the list
-- since they're most likely to be relevant to the user.
localsFirst :: [HoleFit] -> [HoleFit]
localsFirst elts = lcl ++ gbl
where (lcl, gbl) = partition gre_lcl elts
where (lcl, gbl) = partition (gre_lcl . hfEl) elts
-- For pretty printing, we look up the name and type of the substitution
-- we found.
ppr_sub :: (GlobalRdrElt, Id) -> SDoc
ppr_sub (elt, id) = sep [ idAndTy , nest 2 (parens $ pprNameProvenance elt)]
ppr_sub :: HoleFit -> SDoc
ppr_sub (HoleFit elt id) = sep [ idAndTy
, nest 2 (parens $ pprNameProvenance elt)]
where name = gre_name elt
ty = varType id
idAndTy = (pprPrefixOcc name <+> dcolon <+> pprType ty)
......@@ -1242,19 +1279,43 @@ validSubstitutions simples (CEC {cec_encl = implics}) ct | isExprHoleCt ct =
; traceTc "}" empty
; return fits}
-- Kickoff the checking of the elements. The first argument
-- is a counter, so that we stop after finding functions up to
-- the limit the user gives us.
go :: Maybe Int -> [GlobalRdrElt] -> TcM (Bool, [(GlobalRdrElt, Id)])
-- Based on the flags, we might possibly discard some or all the
-- fits we've found.
possiblyDiscard :: Maybe Int -> [HoleFit] -> (Bool, [HoleFit])
possiblyDiscard (Just max) fits = (fits `lengthExceeds` max, take max fits)
possiblyDiscard Nothing fits = (False, fits)
-- Based on a suggestion by phadej on #ghc, we can sort the found fits
-- by constructing a subsumption graph, and then do a topological sort of
-- the graph. This makes the most specific types appear first, which are
-- probably those most relevant. This takes a lot of work (but results in
-- much more useful output), and can be disabled by
-- '-fno-sort-valid-substitutions'.
sortByGraph :: [HoleFit] -> TcM [HoleFit]
sortByGraph fits = go [] fits
where hfType :: HoleFit -> TcSigmaType
hfType = varType . hfId
go :: [(HoleFit, [HoleFit])] -> [HoleFit] -> TcM [HoleFit]
go sofar [] = return $ localsFirst topSorted
where toV (hf, adjs) = (hf, hfId hf, map hfId adjs)
(graph, fromV, _) = graphFromEdges $ map toV sofar
topSorted = map ((\(h,_,_) -> h) . fromV) $ topSort graph
go sofar (id:ids) =
do { adjs <- filterM (tcSubsumes (hfType id) . hfType) fits
; go ((id, adjs):sofar) ids }
-- Kickoff the checking of the elements.
go :: Maybe Int -> [GlobalRdrElt] -> TcM (Bool, [HoleFit])
go = go_ []
-- We iterate over the elements, checking each one in turn. If
-- we've already found -fmax-valid-substitutions=n elements, we
-- look no further.
go_ :: [(GlobalRdrElt,Id)] -- What we've found so far.
-> Maybe Int -- How many we're allowed to find, if limited.
-> [GlobalRdrElt] -- The elements we've yet to check.
-> TcM (Bool, [(GlobalRdrElt, Id)])
-- We iterate over the elements, checking each one in turn for whether it
-- fits, and adding it to the results if it does.
go_ :: [HoleFit] -- What we've found so far.
-> Maybe Int -- How many we're allowed to find, if limited
-> [GlobalRdrElt] -- The elements we've yet to check.
-> TcM (Bool, [HoleFit])
go_ subs _ [] = return (False, reverse subs)
go_ subs (Just 0) _ = return (True, reverse subs)
go_ subs maxleft (el:elts) =
......@@ -1266,7 +1327,7 @@ validSubstitutions simples (CEC {cec_encl = implics}) ct | isExprHoleCt ct =
_ -> discard_it
}
where discard_it = go_ subs maxleft elts
keep_it id = go_ ((el,id):subs) ((\n -> n - 1) <$> maxleft) elts
keep_it id = go_ ((HoleFit el id):subs) ((\n->n-1) <$> maxleft) elts
lookup name =
do { thing <- tcLookup name
; case thing of
......@@ -1338,30 +1399,33 @@ The hole in `f` would generate the message:
In an equation for ‘f’: f = _ "hello, world"
• Relevant bindings include f :: [String] (bound at test.hs:6:1)
Valid substitutions include
lines :: String -> [String]
(imported from ‘Prelude’ at test.hs:1:8-11
(and originally defined in ‘base-4.11.0.0:Data.OldList’))
words :: String -> [String]
(imported from ‘Prelude’ at test.hs:1:8-11
(and originally defined in ‘base-4.11.0.0:Data.OldList’))
read :: forall a. Read a => String -> a
(imported from ‘Prelude’ at test.hs:1:8-11
(and originally defined in ‘Text.Read’))
inits :: forall a. [a] -> [[a]]
(imported from ‘Data.List’ at test.hs:3:19-23
(and originally defined in ‘base-4.11.0.0:Data.OldList’))
return :: forall (m :: * -> *). Monad m => forall a. a -> m a
repeat :: forall a. a -> [a]
(imported from ‘Prelude’ at test.hs:1:8-11
(and originally defined in ‘GHC.Base’))
fail :: forall (m :: * -> *). Monad m => forall a. String -> m a
(and originally defined in ‘GHC.List’))
mempty :: forall a. Monoid a => a
(imported from ‘Prelude’ at test.hs:1:8-11
(and originally defined in ‘GHC.Base’))
mempty :: forall a. Monoid a => a
return :: forall (m :: * -> *). Monad m => forall a. a -> m a
(imported from ‘Prelude’ at test.hs:1:8-11
(and originally defined in ‘GHC.Base’))
pure :: forall (f :: * -> *). Applicative f => forall a. a -> f a
(imported from ‘Prelude’ at test.hs:1:8-11
(and originally defined in ‘GHC.Base’))
read :: forall a. Read a => String -> a
(imported from ‘Prelude’ at test.hs:1:8-11
(and originally defined in ‘Text.Read’))
lines :: String -> [String]
(imported from ‘Prelude’ at test.hs:1:8-11
(and originally defined in ‘base-4.11.0.0:Data.OldList’))
words :: String -> [String]
fail :: forall (m :: * -> *). Monad m => forall a. String -> m a
(imported from ‘Prelude’ at test.hs:1:8-11
(and originally defined in ‘base-4.11.0.0:Data.OldList’))
(and originally defined in ‘GHC.Base’))
error :: forall (a :: TYPE r). GHC.Stack.Types.HasCallStack => [Char] -> a
(imported from ‘Prelude’ at test.hs:1:8-11
(and originally defined in ‘GHC.Err’))
......@@ -1371,9 +1435,7 @@ The hole in `f` would generate the message:
undefined :: forall (a :: TYPE r). GHC.Stack.Types.HasCallStack => a
(imported from ‘Prelude’ at test.hs:1:8-11
(and originally defined in ‘GHC.Err’))
repeat :: forall a. a -> [a]
(imported from ‘Prelude’ at test.hs:1:8-11
(and originally defined in ‘GHC.List’))
Valid substitutions are found by checking top level identifiers in scope for
whether their type is subsumed by the type of the hole. Additionally, as
......@@ -1386,7 +1448,13 @@ variables are all mentioned by the type of the hole. Since checking for
subsumption results in the side effect of type variables being unified by the
simplifier, we need to take care to clone the variables in the hole and relevant
constraints before checking whether an identifier fits into the hole, to avoid
affecting the hole and later checks.
affecting the hole and later checks. When outputting, take the fits found for
the hole and build a subsumption graph, where fit a and fit b are connected if
a subsumes b. We then sort the graph topologically, and output the suggestions
in that order. This is done in order to display "more relevant" suggestions
first where the most specific suggestions (i.e. the ones that are subsumed by
the other suggestions) appear first. This puts suggestions such as `error` and
`undefined` last, as seen in the example above.
Note [Constraints include ...]
......
......@@ -494,13 +494,14 @@ tcSubsumes = tcCheckHoleFit emptyBag
-- | A tcSubsumes which takes into account relevant constraints, to fix trac
-- #14273. Make sure that the constraints are cloned, since the simplifier may
-- perform unification
-- perform unification.
tcCheckHoleFit :: Cts -> TcSigmaType -> TcSigmaType -> TcM Bool
tcCheckHoleFit _ hole_ty ty | hole_ty `eqType` ty = return True
tcCheckHoleFit relevantCts hole_ty ty = discardErrs $
do { (_, wanted, _) <- pushLevelAndCaptureConstraints $
do { (_, wanted, _) <- pushLevelAndCaptureConstraints $
tcSubType_NC ExprSigCtxt ty hole_ty
; (rem, _) <- runTcS (simpl_top $ addSimples wanted relevantCts)
; rem <- runTcSDeriveds $
simpl_top $ addSimples wanted relevantCts
-- We don't want any insoluble or simple constraints left,
-- but solved implications are ok (and neccessary for e.g. undefined)
; return (isEmptyBag (wc_simple rem)
......
......@@ -4,6 +4,8 @@ import GhcPrelude
import TcRnTypes ( TcM, Cts )
import TcType ( TcSigmaType )
-- This boot file exists solely to make tcCheckHoleFit avaialble in TcErrors
-- This boot file exists solely to make tcCheckHoleFit and tcSubsumes avaialble
-- in TcErrors
tcSubsumes :: TcSigmaType -> TcSigmaType -> TcM Bool
tcCheckHoleFit :: Cts -> TcSigmaType -> TcSigmaType -> TcM Bool
......@@ -10669,7 +10669,8 @@ written with a leading underscore (e.g., "``_``", "``_foo``",
will generate an error message that describes which type is expected at
the hole's location, information about the origin of any free type
variables, and a list of local bindings that might help fill the hole
with actual code. Typed holes are always enabled in GHC.
and bindings in scope that fit the type of the hole that might help fill
the hole with actual code. Typed holes are always enabled in GHC.
The goal of typed holes is to help with writing Haskell code rather than
to change the type system. Typed holes can be used to obtain extra
......@@ -10691,11 +10692,15 @@ will fail with the following error: ::
Found hole `_' with type: a
Where: `a' is a rigid type variable bound by
the type signature for f :: a -> a at hole.hs:1:6
Relevant bindings include
f :: a -> a (bound at hole.hs:2:1)
x :: a (bound at hole.hs:2:3)
In the expression: _
In an equation for `f': f x = _
Relevant bindings include
x :: a (bound at hole.hs:2:3)
f :: a -> a (bound at hole.hs:2:1)
Valid substitutions include
undefined :: forall (a :: TYPE r). GHC.Stack.Types.HasCallStack => a
(imported from ‘Prelude’ at hole.hs:1:1
(and originally defined in ‘GHC.Err’))
Here are some more details:
......@@ -10732,13 +10737,36 @@ Here are some more details:
.. code-block:: none
Foo.hs:5:15: error:
Found hole: _x :: Bool
Relevant bindings include
p :: Bool (bound at Foo.hs:3:6)
cons :: Bool -> [Bool] (bound at Foo.hs:3:1)
Foo.hs:5:20: error:
Foo.hs:3:21: error:
Found hole: _x :: Bool
Or perhaps ‘_x’ is mis-spelled, or not in scope
In the first argument of ‘(:)’, namely ‘_x’
In the second argument of ‘(:)’, namely ‘_x : y’
In the second argument of ‘(:)’, namely ‘True : _x : y’
Relevant bindings include
z :: Bool (bound at Foo.hs:3:6)
cons :: Bool -> [Bool] (bound at Foo.hs:3:1)
Valid substitutions include
otherwise :: Bool
(imported from ‘Prelude’ at Foo.hs:1:8-10
(and originally defined in ‘GHC.Base’))
False :: Bool
(imported from ‘Prelude’ at Foo.hs:1:8-10
(and originally defined in ‘GHC.Types’))
True :: Bool
(imported from ‘Prelude’ at Foo.hs:1:8-10
(and originally defined in ‘GHC.Types’))
maxBound :: forall a. Bounded a => a
(imported from ‘Prelude’ at Foo.hs:1:8-10
(and originally defined in ‘GHC.Enum’))
minBound :: forall a. Bounded a => a
(imported from ‘Prelude’ at Foo.hs:1:8-10
(and originally defined in ‘GHC.Enum’))
undefined :: forall (a :: TYPE r). GHC.Stack.Types.HasCallStack => a
(imported from ‘Prelude’ at Foo.hs:1:8-10
(and originally defined in ‘GHC.Err’))
Foo.hs:3:26: error:
Variable not in scope: y :: [Bool]
More information is given for explicit holes (i.e. ones that start
......@@ -10756,24 +10784,38 @@ Here are some more details:
.. code-block:: none
unbound.hs:1:8:
Found hole '_x' with type: a
Where: `a' is a rigid type variable bound by
the inferred type of cons :: [a] at unbound.hs:1:1
Relevant bindings include cons :: [a] (bound at unbound.hs:1:1)
In the first argument of `(:)', namely `_x'
In the expression: _x : _x
In an equation for `cons': cons = _x : _x
unbound.hs:1:13:
Found hole '_x' with type: [a]
Arising from: an undeclared identifier `_x' at unbound.hs:1:13-14
Where: `a' is a rigid type variable bound by
the inferred type of cons :: [a] at unbound.hs:1:1
Relevant bindings include cons :: [a] (bound at unbound.hs:1:1)
In the second argument of `(:)', namely `_x'
In the expression: _x : _x
In an equation for `cons': cons = _x : _x
unbound.hs:1:8:
Found hole '_x' with type: a
Where: `a' is a rigid type variable bound by
the inferred type of cons :: [a] at unbound.hs:1:1
In the first argument of `(:)', namely `_x'
In the expression: _x : _x
In an equation for `cons': cons = _x : _x
Relevant bindings include cons :: [a] (bound at unbound.hs:1:1)
Valid substitutions include
undefined :: forall (a :: TYPE r). GHC.Stack.Types.HasCallStack => a
(imported from ‘Prelude’ at unbound.hs:1:8-11
(and originally defined in ‘GHC.Err’))
unbound.hs:1:13:
Found hole: _x :: [a]
Where: ‘a’ is a rigid type variable bound by
the inferred type of cons :: [a]
at unbound.hs:3:1-12
Or perhaps ‘_x’ is mis-spelled, or not in scope
In the second argument of ‘(:)’, namely ‘_x’
In the expression: _x : _x
In an equation for ‘cons’: cons = _x : _x
Relevant bindings include cons :: [a] (bound at unbound.hs:3:1)
Valid substitutions include
cons :: forall a. [a] (defined at unbound.hs:3:1)
mempty :: forall a. Monoid a => a
(imported from ‘Prelude’ at unbound.hs:1:8-11
(and originally defined in ‘GHC.Base’))
undefined :: forall (a :: TYPE r). GHC.Stack.Types.HasCallStack => a
(imported from ‘Prelude’ at unbound.hs:1:8-11
(and originally defined in ‘GHC.Err’))
Notice the two different types reported for the two different
occurrences of ``_x``.
......@@ -10797,11 +10839,68 @@ Here are some more details:
implementation terms, they are reported by the renamer rather than
the type checker.)
There's a flag for controlling the amount of context information shown for
typed holes:
- The list of valid substitutions is found by checking which bindings in scope
would fit into the hole. As an example, compiling the following module with
GHC: ::
import Data.List (inits)
g :: [String]
g = _ "hello, world"
yields the errors:
.. code-block:: none
• Found hole: _ :: [Char] -> [String]
• In the expression: _
In the expression: _ "hello, world"
In an equation for ‘f’: f = _ "hello, world"
• Relevant bindings include f :: [String] (bound at test.hs:6:1)
Valid substitutions include
lines :: String -> [String]
(imported from ‘Prelude’ at test.hs:1:8-11
(and originally defined in ‘base-4.11.0.0:Data.OldList’))
words :: String -> [String]
(imported from ‘Prelude’ at test.hs:1:8-11
(and originally defined in ‘base-4.11.0.0:Data.OldList’))
read :: forall a. Read a => String -> a
(imported from ‘Prelude’ at test.hs:1:8-11
(and originally defined in ‘Text.Read’))
inits :: forall a. [a] -> [[a]]
(imported from ‘Data.List’ at test.hs:3:19-23
(and originally defined in ‘base-4.11.0.0:Data.OldList’))
repeat :: forall a. a -> [a]
(imported from ‘Prelude’ at test.hs:1:8-11
(and originally defined in ‘GHC.List’))
mempty :: forall a. Monoid a => a
(imported from ‘Prelude’ at test.hs:1:8-11
(and originally defined in ‘GHC.Base’))
return :: forall (m :: * -> *). Monad m => forall a. a -> m a
(imported from ‘Prelude’ at test.hs:1:8-11
(and originally defined in ‘GHC.Base’))
pure :: forall (f :: * -> *). Applicative f => forall a. a -> f a
(imported from ‘Prelude’ at test.hs:1:8-11
(and originally defined in ‘GHC.Base’))
fail :: forall (m :: * -> *). Monad m => forall a. String -> m a
(imported from ‘Prelude’ at test.hs:1:8-11
(and originally defined in ‘GHC.Base’))
error :: forall (a :: TYPE r). GHC.Stack.Types.HasCallStack => [Char] -> a
(imported from ‘Prelude’ at test.hs:1:8-11
(and originally defined in ‘GHC.Err’))
errorWithoutStackTrace :: forall (a :: TYPE r). [Char] -> a
(imported from ‘Prelude’ at test.hs:1:8-11
(and originally defined in ‘GHC.Err’))
undefined :: forall (a :: TYPE r). GHC.Stack.Types.HasCallStack => a
(imported from ‘Prelude’ at test.hs:1:8-11
(and originally defined in ‘GHC.Err’))
There are a few flags for controlling the amount of context information shown
for typed holes:
.. ghc-flag:: -fshow-hole-constraints
:shortdesc: Show constraints when reporting typed holes
:shortdesc: Show constraints when reporting typed holes.
:type: dynamic
:category: verbosity
......@@ -10815,17 +10914,131 @@ typed holes:
.. code-block:: none
show_constraints.hs:4:7: error:
• Found hole: _ :: Bool
• In the expression: _
In an equation for ‘f’: f x = _
• Relevant bindings include
x :: a (bound at show_constraints.hs:4:3)
f :: a -> Bool (bound at show_constraints.hs:4:1)
Constraints include
Eq a (from the type signature for:
f :: Eq a => a -> Bool
at show_constraints.hs:3:1-22)
show_constraints.hs:4:7: error:
• Found hole: _ :: Bool
• In the expression: _
In an equation for ‘f’: f x = _
• Relevant bindings include
x :: a (bound at show_constraints.hs:4:3)
f :: a -> Bool (bound at show_constraints.hs:4:1)
Constraints include Eq a (from show_constraints.hs:3:1-22)
Valid substitutions include
otherwise :: Bool
(imported from ‘Prelude’ at show_constraints.hs:1:8-11
(and originally defined in ‘GHC.Base’))
False :: Bool
(imported from ‘Prelude’ at show_constraints.hs:1:8-11
(and originally defined in ‘GHC.Types’))
True :: Bool
(imported from ‘Prelude’ at show_constraints.hs:1:8-11
(and originally defined in ‘GHC.Types’))
maxBound :: forall a. Bounded a => a
(imported from ‘Prelude’ at show_constraints.hs:1:8-11
(and originally defined in ‘GHC.Enum’))
minBound :: forall a. Bounded a => a
(imported from ‘Prelude’ at show_constraints.hs:1:8-11
(and originally defined in ‘GHC.Enum’))
undefined :: forall (a :: TYPE r). GHC.Stack.Types.HasCallStack => a
(imported from ‘Prelude’ at show_constraints.hs:1:8-11
(and originally defined in ‘GHC.Err’))
.. ghc-flag:: -fno-show-valid-substitutions
:shortdesc: Disables showing a list of valid substitutions for typed holes
in type error messages.
:type: dynamic
:category: verbosity
:default: off
This flag can be toggled to turn off the display of valid substitutions
entirely.
.. ghc-flag:: -fno-sort-valid-substitutions
:shortdesc: Disables the sorting of the list of valid substitutions for typed holes
in type error messages.
:type: dynamic
:category: verbosity
:default: off
By default the valid substitutions are sorted by a topological sort on the
subsumption graph of the identified substitutions. However, this requires
checking relations between the found substitutions, which can be expensive
if there are many valid substitutions. Sorting can be toggled off with this
flag.
When sorting is off, the hole in ``g`` in the following as before ::
import Data.List (inits)
g :: [String]
g = _ "hello, world"
will yield an error:
.. code-block:: none
test.hs:6:5: error:
• Found hole: _ :: [Char] -> [String]
• In the expression: _
In the expression: _ "hello, world"
In an equation for ‘g’: g = _ "hello, world"
• Relevant bindings include f :: [String] (bound at test.hs:6:1)
Valid substitutions include
inits :: forall a. [a] -> [[a]]
(imported from ‘Data.List’ at test.hs:3:19-23
(and originally defined in ‘base-4.11.0.0:Data.OldList’))
return :: forall (m :: * -> *). Monad m => forall a. a -> m a
(imported from ‘Prelude’ at test.hs:1:8-11
(and originally defined in ‘GHC.Base’))
fail :: forall (m :: * -> *). Monad m => forall a. String -> m a
(imported from ‘Prelude’ at test.hs:1:8-11
(and originally defined in ‘GHC.Base’))
mempty :: forall a. Monoid a => a
(imported from ‘Prelude’ at test.hs:1:8-11
(and originally defined in ‘GHC.Base’))
pure :: forall (f :: * -> *). Applicative f => forall a. a -> f a
(imported from ‘Prelude’ at test.hs:1:8-11
(and originally defined in ‘GHC.Base’))
read :: forall a. Read a => String -> a
(imported from ‘Prelude’ at test.hs:1:8-11
(and originally defined in ‘Text.Read’))
lines :: String -> [String]
(imported from ‘Prelude’ at test.hs:1:8-11
(and originally defined in ‘base-4.11.0.0:Data.OldList’))
words :: String -> [String]
(imported from ‘Prelude’ at test.hs:1:8-11
(and originally defined in ‘base-4.11.0.0:Data.OldList’))
error :: forall (a :: TYPE r). GHC.Stack.Types.HasCallStack => [Char] -> a
(imported from ‘Prelude’ at test.hs:1:8-11
(and originally defined in ‘GHC.Err’))
errorWithoutStackTrace :: forall (a :: TYPE r). [Char] -> a
(imported from ‘Prelude’ at test.hs:1:8-11
(and originally defined in ‘GHC.Err’))
undefined :: forall (a :: TYPE r). GHC.Stack.Types.HasCallStack => a
(imported from ‘Prelude’ at test.hs:1:8-11
(and originally defined in ‘GHC.Err’))