summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthías Páll Gissurarson <mpg@mpg.is>2017-03-29 17:30:28 -0400
committerBen Gamari <ben@smart-cactus.org>2017-03-29 18:06:21 -0400
commit26c95f46e679fb73e1ec2bec2be0801c72fd1449 (patch)
treeeeedf7a400c80f07a8295c333875576d1b7b5800
parent924a65fc27bb2a3e24489f7baea7ad5fb8a556ac (diff)
downloadhaskell-26c95f46e679fb73e1ec2bec2be0801c72fd1449.tar.gz
Show valid substitutions for typed holes
The idea is to implement a mechanism similar to PureScript, where they suggest which identifiers in scope would fit the given hole. In PureScript, they use subsumption (which is what we would like here as well). For subsumption, we would have to check each type in scope whether the hole is a subtype of the given type, but that would require `tcSubType` and constraint satisfiability checking. Currently, `TcSimplify` uses a lot of functions from `TcErrors`, so that would require more of a rewrite, I will hold on with that for now, and submit the more simpler type equality version. As an example, consider ``` ps :: String -> IO () ps = putStrLn ps2 :: a -> IO () ps2 _ = putStrLn "hello, world" main :: IO () main = _ "hello, world" ``` The results would be something like ``` • Found hole: _ :: [Char] -> IO () • In the expression: _ In a stmt of a 'do' block: _ "hello, world" In the expression: do _ "hello, world" • Relevant bindings include main :: IO () (bound at test.hs:13:1) ps :: String -> IO () (bound at test.hs:7:1) ps2 :: forall a. a -> IO () (bound at test.hs:10:1) Valid substitutions include putStrLn :: String -> IO () (imported from ‘Prelude’ at test.hs:1:1-14 (and originally defined in ‘System.IO’)) putStr :: String -> IO () (imported from ‘Prelude’ at test.hs:1:1-14 (and originally defined in ‘System.IO’)) ``` We'd like here for ps2 to be suggested as well, but for that we require subsumption. Reviewers: austin, bgamari, dfeuer, mpickering Reviewed By: dfeuer, mpickering Subscribers: mpickering, Wizek, dfeuer, rwbarton, thomie Differential Revision: https://phabricator.haskell.org/D3361
-rw-r--r--compiler/main/DynFlags.hs7
-rw-r--r--compiler/typecheck/TcErrors.hs170
-rw-r--r--docs/users_guide/using-optimisation.rst10
-rw-r--r--testsuite/tests/ghci/scripts/T8353.stderr5
-rw-r--r--testsuite/tests/typecheck/should_compile/T13050.stderr5
-rw-r--r--testsuite/tests/typecheck/should_compile/ValidSubs.hs4
-rw-r--r--testsuite/tests/typecheck/should_compile/all.T2
-rw-r--r--testsuite/tests/typecheck/should_compile/valid_substitutions.hs19
-rw-r--r--testsuite/tests/typecheck/should_compile/valid_substitutions.stderr37
-rw-r--r--utils/mkUserGuidePart/Options/Optimizations.hs7
10 files changed, 256 insertions, 10 deletions
diff --git a/compiler/main/DynFlags.hs b/compiler/main/DynFlags.hs
index 927d3c46a0..2750ca6aa8 100644
--- a/compiler/main/DynFlags.hs
+++ b/compiler/main/DynFlags.hs
@@ -708,6 +708,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
maxUncoveredPatterns :: Int, -- ^ Maximum number of unmatched patterns to show
-- in non-exhaustiveness warnings
simplTickFactor :: Int, -- ^ Multiplier for simplifier ticks
@@ -1539,6 +1541,7 @@ defaultDynFlags mySettings =
maxPmCheckIterations = 2000000,
ruleCheck = Nothing,
maxRelevantBinds = Just 6,
+ maxValidSubstitutions = Just 6,
maxUncoveredPatterns = 4,
simplTickFactor = 100,
specConstrThreshold = Just 2000,
@@ -3134,6 +3137,10 @@ dynamic_flags_deps = [
(intSuffix (\n d -> d { maxRelevantBinds = Just n }))
, make_ord_flag defFlag "fno-max-relevant-binds"
(noArg (\d -> d { maxRelevantBinds = Nothing }))
+ , make_ord_flag defFlag "fmax-valid-substitutions"
+ (intSuffix (\n d -> d { maxValidSubstitutions = Just n }))
+ , make_ord_flag defFlag "fno-max-valid-substitutions"
+ (noArg (\d -> d { maxValidSubstitutions = Nothing }))
, make_ord_flag defFlag "fmax-uncovered-patterns"
(intSuffix (\n d -> d { maxUncoveredPatterns = n }))
, make_ord_flag defFlag "fsimplifier-phases"
diff --git a/compiler/typecheck/TcErrors.hs b/compiler/typecheck/TcErrors.hs
index 9701637729..290da2f63d 100644
--- a/compiler/typecheck/TcErrors.hs
+++ b/compiler/typecheck/TcErrors.hs
@@ -32,7 +32,8 @@ import HsExpr ( UnboundVar(..) )
import HsBinds ( PatSynBind(..) )
import Name
import RdrName ( lookupGlobalRdrEnv, lookupGRE_Name, GlobalRdrEnv
- , mkRdrUnqual, isLocalGRE, greSrcSpan )
+ , mkRdrUnqual, isLocalGRE, greSrcSpan, pprNameProvenance
+ , GlobalRdrElt (..), globalRdrEnvElts )
import PrelNames ( typeableClassName, hasKey, liftedRepDataConKey )
import Id
import Var
@@ -42,8 +43,10 @@ import NameSet
import Bag
import ErrUtils ( ErrMsg, errDoc, pprLocErrMsg )
import BasicTypes
-import ConLike ( ConLike(..) )
+import ConLike ( ConLike(..), conLikeWrapId_maybe )
import Util
+import HscTypes (HscEnv, lookupTypeHscEnv, TypeEnv, lookupTypeEnv )
+import NameEnv (lookupNameEnv)
import FastString
import Outputable
import SrcLoc
@@ -219,12 +222,16 @@ report_unsolved mb_binds_var err_as_warn type_errors expr_holes
data Report
= Report { report_important :: [SDoc]
, report_relevant_bindings :: [SDoc]
+ , report_valid_substitutions :: [SDoc]
}
instance Outputable Report where -- Debugging only
- ppr (Report { report_important = imp, report_relevant_bindings = rel })
+ ppr (Report { report_important = imp
+ , report_relevant_bindings = rel
+ , report_valid_substitutions = val })
= vcat [ text "important:" <+> vcat imp
- , text "relevant:" <+> vcat rel ]
+ , text "relevant:" <+> vcat rel
+ , text "valid:" <+> vcat val ]
{- Note [Error report]
The idea is that error msgs are divided into three parts: the main msg, the
@@ -241,12 +248,13 @@ multiple places so they have to be in the Report.
#if __GLASGOW_HASKELL__ > 710
instance Semigroup Report where
- Report a1 b1 <> Report a2 b2 = Report (a1 ++ a2) (b1 ++ b2)
+ Report a1 b1 c1 <> Report a2 b2 c2 = Report (a1 ++ a2) (b1 ++ b2) (c1 ++ c2)
#endif
instance Monoid Report where
- mempty = Report [] []
- mappend (Report a1 b1) (Report a2 b2) = Report (a1 ++ a2) (b1 ++ b2)
+ mempty = Report [] [] []
+ mappend (Report a1 b1 c1) (Report a2 b2 c2)
+ = Report (a1 ++ a2) (b1 ++ b2) (c1 ++ c2)
-- | Put a doc into the important msgs block.
important :: SDoc -> Report
@@ -256,6 +264,10 @@ important doc = mempty { report_important = [doc] }
relevant_bindings :: SDoc -> Report
relevant_bindings doc = mempty { report_relevant_bindings = [doc] }
+-- | Put a doc into the valid substitutions block.
+valid_substitutions :: SDoc -> Report
+valid_substitutions docs = mempty { report_valid_substitutions = [docs] }
+
data TypeErrorChoice -- What to do for type errors found by the type checker
= TypeError -- A type error aborts compilation with an error message
| TypeWarn -- A type error is deferred to runtime, plus a compile-time warning
@@ -865,10 +877,10 @@ mkErrorMsgFromCt ctxt ct report
= mkErrorReport ctxt (ctLocEnv (ctLoc ct)) report
mkErrorReport :: ReportErrCtxt -> TcLclEnv -> Report -> TcM ErrMsg
-mkErrorReport ctxt tcl_env (Report important relevant_bindings)
+mkErrorReport ctxt tcl_env (Report important relevant_bindings valid_subs)
= do { context <- mkErrInfo (cec_tidy ctxt) (tcl_ctxt tcl_env)
; mkErrDocAt (RealSrcSpan (tcl_loc tcl_env))
- (errDoc important [context] relevant_bindings)
+ (errDoc important [context] (relevant_bindings ++ valid_subs))
}
type UserGiven = Implication
@@ -1051,9 +1063,11 @@ mkHoleError ctxt ct@(CHoleCan { cc_hole = hole })
= givenConstraintsMsg ctxt
| otherwise = empty
+ ; sub_msg <- validSubstitutions ct
; mkErrorMsgFromCt ctxt ct $
important hole_msg `mappend`
- relevant_bindings (binds_msg $$ constraints_msg) }
+ relevant_bindings (binds_msg $$ constraints_msg) `mappend`
+ valid_substitutions sub_msg}
where
occ = holeOcc hole
@@ -1100,6 +1114,98 @@ mkHoleError ctxt ct@(CHoleCan { cc_hole = hole })
mkHoleError _ ct = pprPanic "mkHoleError" (ppr ct)
+-- See Note [Valid substitutions include ...]
+validSubstitutions :: Ct -> TcM SDoc
+validSubstitutions ct | isExprHoleCt ct =
+ do { top_env <- getTopEnv
+ ; rdr_env <- getGlobalRdrEnv
+ ; gbl_env <- tcg_type_env <$> getGblEnv
+ ; lcl_env <- getLclTypeEnv
+ ; dflags <- getDynFlags
+ ; (discards, substitutions) <-
+ go (gbl_env, lcl_env, top_env) (maxValidSubstitutions dflags)
+ $ localsFirst $ globalRdrEnvElts rdr_env
+ ; return $ ppUnless (null substitutions) $
+ hang (text "Valid substitutions include")
+ 2 (vcat (map (ppr_sub rdr_env) substitutions)
+ $$ ppWhen discards subsDiscardMsg) }
+ where
+ hole_ty :: TcPredType
+ hole_ty = ctEvPred (ctEvidence ct)
+
+ hole_env = ctLocEnv $ ctEvLoc $ ctEvidence ct
+
+ localsFirst :: [GlobalRdrElt] -> [GlobalRdrElt]
+ localsFirst elts = lcl ++ gbl
+ where (lcl, gbl) = partition gre_lcl elts
+
+ getBndrOcc :: TcIdBinder -> OccName
+ getBndrOcc (TcIdBndr id _) = occName $ getName id
+ getBndrOcc (TcIdBndr_ExpType name _ _) = occName $ getName name
+
+ relBindSet = mkOccSet $ map getBndrOcc $ tcl_bndrs hole_env
+
+ shouldBeSkipped :: GlobalRdrElt -> Bool
+ shouldBeSkipped el = (occName $ gre_name el) `elemOccSet` relBindSet
+
+ ppr_sub :: GlobalRdrEnv -> Id -> SDoc
+ ppr_sub rdr_env id = case lookupGRE_Name rdr_env (idName id) of
+ Just elt -> sep [ idAndTy, nest 2 (parens $ pprNameProvenance elt)]
+ _ -> idAndTy
+ where name = idName id
+ ty = varType id
+ idAndTy = (pprPrefixOcc name <+> dcolon <+> pprType ty)
+
+ tyToId :: TyThing -> Maybe Id
+ tyToId (AnId i) = Just i
+ tyToId (AConLike c) = conLikeWrapId_maybe c
+ tyToId _ = Nothing
+
+ tcTyToId :: TcTyThing -> Maybe Id
+ tcTyToId (AGlobal id) = tyToId id
+ tcTyToId (ATcId id _) = Just id
+ tcTyToId _ = Nothing
+
+ substituteable :: Id -> Bool
+ substituteable = tcEqType hole_ty . varType
+
+ lookupTopId :: HscEnv -> Name -> IO (Maybe Id)
+ lookupTopId env name =
+ maybe Nothing tyToId <$> lookupTypeHscEnv env name
+
+ lookupGblId :: TypeEnv -> Name -> Maybe Id
+ lookupGblId env name = maybe Nothing tyToId $ lookupTypeEnv env name
+
+ lookupLclId :: TcTypeEnv -> Name -> Maybe Id
+ lookupLclId env name = maybe Nothing tcTyToId $ lookupNameEnv env name
+
+ go :: (TypeEnv, TcTypeEnv, HscEnv) -> Maybe Int -> [GlobalRdrElt]
+ -> TcM (Bool, [Id])
+ go = go_ []
+
+ go_ :: [Id] -> (TypeEnv, TcTypeEnv, HscEnv) -> Maybe Int -> [GlobalRdrElt]
+ -> TcM (Bool, [Id])
+ go_ subs _ _ [] = return (False, reverse subs)
+ go_ subs _ (Just 0) _ = return (True, reverse subs)
+ go_ subs envs@(gbl,lcl,top) maxleft (el:elts) =
+ if shouldBeSkipped el then discard_it
+ else do { maybeId <- liftIO lookupId
+ ; case maybeId of
+ Just id | substituteable id ->
+ go_ (id:subs) envs ((\n -> n - 1) <$> maxleft) elts
+ _ -> discard_it }
+ where name = gre_name el
+ discard_it = go_ subs envs maxleft elts
+ getTopId = lookupTopId top name
+ gbl_id = lookupGblId gbl name
+ lcl_id = lookupLclId lcl name
+ lookupId = if (isJust lcl_id) then return lcl_id
+ else if (isJust gbl_id) then return gbl_id else getTopId
+
+
+validSubstitutions _ = return empty
+
+
-- See Note [Constraints include ...]
givenConstraintsMsg :: ReportErrCtxt -> SDoc
givenConstraintsMsg ctxt =
@@ -1139,6 +1245,45 @@ mkIPErr ctxt cts
(ct1:_) = cts
{-
+Note [Valid substitutions include ...]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+`validSubstitutions` returns the "Valid substitutions include ..." message.
+For example, look at the following definitions in a file called test.hs:
+
+ ps :: String -> IO ()
+ ps = putStrLn
+
+ ps2 :: a -> IO ()
+ ps2 _ = putStrLn "hello, world"
+
+ main :: IO ()
+ main = _ "hello, world"
+
+The hole in `main` would generate the message:
+
+ Valid substitutions include
+ ps :: String -> IO () ((defined at test.hs:2:1)
+ putStrLn :: String -> IO ()
+ (imported from ‘Prelude’ at test.hs:1:1
+ (and originally defined in ‘System.IO’))
+ putStr :: String -> IO ()
+ (imported from ‘Prelude’ at test.hs:1:1
+ (and originally defined in ‘System.IO’))
+
+Valid substitutions are found by checking names in scope.
+
+Currently the implementation only looks at exact type matches, as given by
+`tcEqType`, so we DO NOT report `ps2` as a valid substitution in the example,
+even though it fits in the hole. To determine that `ps2` fits in the hole,
+we would need to check ids for subsumption, i.e. that the type of the hole is
+a subtype of the id. This can be done using `tcSubType` from `TcUnify` and
+`tcCheckSatisfiability` in `TcSimplify`. Unfortunately, `TcSimplify` uses
+`TcErrors` to report errors found during constraint checking, so checking for
+subsumption in holes would involve shuffling some code around in `TcSimplify`,
+to make a non-error reporting constraint satisfiability checker which could
+then be used for checking whether a given id satisfies the constraints imposed
+by the hole.
+
Note [Constraints include ...]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'givenConstraintsMsg' returns the "Constraints include ..." message enabled by
@@ -2787,6 +2932,11 @@ discardMsg :: SDoc
discardMsg = text "(Some bindings suppressed;" <+>
text "use -fmax-relevant-binds=N or -fno-max-relevant-binds)"
+subsDiscardMsg :: SDoc
+subsDiscardMsg =
+ text "(Some substitutions suppressed;" <+>
+ text "use -fmax-valid-substitutions=N or -fno-max-valid-substitutions)"
+
-----------------------
warnDefaulting :: [Ct] -> Type -> TcM ()
warnDefaulting wanteds default_ty
diff --git a/docs/users_guide/using-optimisation.rst b/docs/users_guide/using-optimisation.rst
index fb2f2847d4..d52ed04d86 100644
--- a/docs/users_guide/using-optimisation.rst
+++ b/docs/users_guide/using-optimisation.rst
@@ -395,6 +395,16 @@ list.
they may be numerous), but ``-fno-max-relevant-bindings`` includes
them too.
+.. ghc-flag:: -fmax-valid-substitutions=<n>
+ -fno-max-valid-substitutions
+
+ :default: 6
+
+ The type checker sometimes displays a list of valid substitutions
+ for typed holes in error messages, but only up to some maximum number,
+ set by this flag. Turning it off with
+ ``-fno-max-valid-substitutions`` gives an unlimited number.
+
.. ghc-flag:: -fmax-uncovered-patterns=<n>
:default: 4
diff --git a/testsuite/tests/ghci/scripts/T8353.stderr b/testsuite/tests/ghci/scripts/T8353.stderr
index e525c22162..863a64fc4e 100644
--- a/testsuite/tests/ghci/scripts/T8353.stderr
+++ b/testsuite/tests/ghci/scripts/T8353.stderr
@@ -9,6 +9,7 @@ Defer03.hs:7:5: warning: [-Wtyped-holes (in -Wdefault)]
• In the expression: _
In an equation for ‘f’: f = _
• Relevant bindings include f :: Int (bound at Defer03.hs:7:1)
+ Valid substitutions include a :: Int (defined at Defer03.hs:4:1)
Defer03.hs:4:5: error:
• Couldn't match expected type ‘Int’ with actual type ‘Char’
@@ -20,6 +21,7 @@ Defer03.hs:7:5: error:
• In the expression: _
In an equation for ‘f’: f = _
• Relevant bindings include f :: Int (bound at Defer03.hs:7:1)
+ Valid substitutions include a :: Int (defined at Defer03.hs:4:1)
Defer03.hs:4:5: warning: [-Wdeferred-type-errors (in -Wdefault)]
• Couldn't match expected type ‘Int’ with actual type ‘Char’
@@ -31,6 +33,7 @@ Defer03.hs:7:5: warning: [-Wtyped-holes (in -Wdefault)]
• In the expression: _
In an equation for ‘f’: f = _
• Relevant bindings include f :: Int (bound at Defer03.hs:7:1)
+ Valid substitutions include a :: Int (defined at Defer03.hs:4:1)
Defer03.hs:4:5: error:
• Couldn't match expected type ‘Int’ with actual type ‘Char’
@@ -42,6 +45,7 @@ Defer03.hs:7:5: error:
• In the expression: _
In an equation for ‘f’: f = _
• Relevant bindings include f :: Int (bound at Defer03.hs:7:1)
+ Valid substitutions include a :: Int (defined at Defer03.hs:4:1)
Defer03.hs:4:5: warning: [-Wdeferred-type-errors (in -Wdefault)]
• Couldn't match expected type ‘Int’ with actual type ‘Char’
@@ -53,3 +57,4 @@ Defer03.hs:7:5: warning: [-Wtyped-holes (in -Wdefault)]
• In the expression: _
In an equation for ‘f’: f = _
• Relevant bindings include f :: Int (bound at Defer03.hs:7:1)
+ Valid substitutions include a :: Int (defined at Defer03.hs:4:1)
diff --git a/testsuite/tests/typecheck/should_compile/T13050.stderr b/testsuite/tests/typecheck/should_compile/T13050.stderr
index b8ccd76815..723bdf02b6 100644
--- a/testsuite/tests/typecheck/should_compile/T13050.stderr
+++ b/testsuite/tests/typecheck/should_compile/T13050.stderr
@@ -18,6 +18,8 @@ T13050.hs:5:11: warning: [-Wtyped-holes (in -Wdefault)]
y :: Int (bound at T13050.hs:5:5)
x :: Int (bound at T13050.hs:5:3)
g :: Int -> Int -> Int (bound at T13050.hs:5:1)
+ Valid substitutions include
+ f :: Int -> Int -> Int (defined at T13050.hs:4:1)
T13050.hs:6:11: warning: [-Wtyped-holes (in -Wdefault)]
• Found hole: _a :: Int -> Int -> Int
@@ -29,3 +31,6 @@ T13050.hs:6:11: warning: [-Wtyped-holes (in -Wdefault)]
y :: Int (bound at T13050.hs:6:5)
x :: Int (bound at T13050.hs:6:3)
q :: Int -> Int -> Int (bound at T13050.hs:6:1)
+ Valid substitutions include
+ f :: Int -> Int -> Int (defined at T13050.hs:4:1)
+ g :: Int -> Int -> Int (defined at T13050.hs:5:1)
diff --git a/testsuite/tests/typecheck/should_compile/ValidSubs.hs b/testsuite/tests/typecheck/should_compile/ValidSubs.hs
new file mode 100644
index 0000000000..050b317d9d
--- /dev/null
+++ b/testsuite/tests/typecheck/should_compile/ValidSubs.hs
@@ -0,0 +1,4 @@
+module ValidSubs where
+
+
+data Moo = Moo Integer
diff --git a/testsuite/tests/typecheck/should_compile/all.T b/testsuite/tests/typecheck/should_compile/all.T
index cfc4eff314..6bd98ca8c9 100644
--- a/testsuite/tests/typecheck/should_compile/all.T
+++ b/testsuite/tests/typecheck/should_compile/all.T
@@ -388,6 +388,8 @@ test('holes2', normal, compile, ['-fdefer-type-errors'])
test('holes3', normal, compile_fail, [''])
test('hole_constraints', normal, compile, ['-fdefer-type-errors'])
test('hole_constraints_nested', normal, compile, ['-fdefer-type-errors'])
+test('valid_substitutions', [extra_files(['ValidSubs.hs'])],
+ multimod_compile, ['valid_substitutions','-fdefer-type-errors'])
test('T7408', normal, compile, [''])
test('UnboxStrictPrimitiveFields', normal, compile, [''])
test('T7541', normal, compile, [''])
diff --git a/testsuite/tests/typecheck/should_compile/valid_substitutions.hs b/testsuite/tests/typecheck/should_compile/valid_substitutions.hs
new file mode 100644
index 0000000000..bae315b8e8
--- /dev/null
+++ b/testsuite/tests/typecheck/should_compile/valid_substitutions.hs
@@ -0,0 +1,19 @@
+module Foo where
+
+import Prelude hiding (putStr)
+import qualified System.IO
+import Data.Maybe
+import qualified ValidSubs
+
+ps :: String -> IO ()
+ps = putStrLn
+
+
+test :: [Maybe a] -> [a]
+test = _
+
+test2 :: Integer -> ValidSubs.Moo
+test2 = _
+
+main :: IO ()
+main = _ "hello, world"
diff --git a/testsuite/tests/typecheck/should_compile/valid_substitutions.stderr b/testsuite/tests/typecheck/should_compile/valid_substitutions.stderr
new file mode 100644
index 0000000000..a89c5f03a8
--- /dev/null
+++ b/testsuite/tests/typecheck/should_compile/valid_substitutions.stderr
@@ -0,0 +1,37 @@
+[1 of 2] Compiling ValidSubs ( ValidSubs.hs, ValidSubs.o )
+[2 of 2] Compiling Foo ( valid_substitutions.hs, valid_substitutions.o )
+
+valid_substitutions.hs:13:8: warning: [-Wtyped-holes (in -Wdefault)]
+ • Found hole: _ :: [Maybe a] -> [a]
+ Where: ‘a’ is a rigid type variable bound by
+ the type signature for:
+ test :: forall a. [Maybe a] -> [a]
+ at valid_substitutions.hs:12:1-24
+ • In the expression: _
+ In an equation for ‘test’: test = _
+ • Relevant bindings include
+ test :: [Maybe a] -> [a] (bound at valid_substitutions.hs:13:1)
+
+valid_substitutions.hs:16:9: warning: [-Wtyped-holes (in -Wdefault)]
+ • Found hole: _ :: Integer -> ValidSubs.Moo
+ • In the expression: _
+ In an equation for ‘test2’: test2 = _
+ • Relevant bindings include
+ test2 :: Integer -> ValidSubs.Moo
+ (bound at valid_substitutions.hs:16:1)
+ Valid substitutions include
+ ValidSubs.Moo :: Integer -> ValidSubs.Moo
+
+valid_substitutions.hs:19:8: warning: [-Wtyped-holes (in -Wdefault)]
+ • Found hole: _ :: [Char] -> IO ()
+ • In the expression: _
+ In the expression: _ "hello, world"
+ In an equation for ‘main’: main = _ "hello, world"
+ • Relevant bindings include
+ main :: IO () (bound at valid_substitutions.hs:19:1)
+ Valid substitutions include
+ ps :: String -> IO () (defined at valid_substitutions.hs:9:1)
+ System.IO.putStr :: String -> IO ()
+ (imported qualified from ‘System.IO’ at valid_substitutions.hs:4:1-26)
+ putStrLn :: String -> IO ()
+ (imported qualified from ‘System.IO’ at valid_substitutions.hs:4:1-26)
diff --git a/utils/mkUserGuidePart/Options/Optimizations.hs b/utils/mkUserGuidePart/Options/Optimizations.hs
index b0f9bc5ac8..992390ba3d 100644
--- a/utils/mkUserGuidePart/Options/Optimizations.hs
+++ b/utils/mkUserGuidePart/Options/Optimizations.hs
@@ -183,6 +183,13 @@ optimizationsOptions =
, flagType = DynamicFlag
, flagReverse = "-fno-max-relevant-bindings"
}
+ , flag { flagName = "-fmax-valid-substitutions=⟨n⟩"
+ , flagDescription =
+ "*default: 6.* Set the maximum number of valid substitutions for"++
+ "typed holes to display in type error messages."
+ , flagType = DynamicFlag
+ , flagReverse = "-fno-max-valid-substitutions"
+ }
, flag { flagName = "-fmax-uncovered-patterns=⟨n⟩"
, flagDescription =
"*default: 4.* Set the maximum number of patterns to display in "++