diff options
author | Richard Eisenberg <eir@cis.upenn.edu> | 2016-04-22 22:39:17 -0400 |
---|---|---|
committer | Richard Eisenberg <eir@cis.upenn.edu> | 2016-06-23 15:17:43 -0400 |
commit | 8035d1a5dc7290e8d3d61446ee4861e0b460214e (patch) | |
tree | 2e517feff25329abb942184ac4a7d20c9f77ba29 | |
parent | 9a34bf1985035858ece043bf38b47b6ff4b88efb (diff) | |
download | haskell-8035d1a5dc7290e8d3d61446ee4861e0b460214e.tar.gz |
Fix #10963 and #11975 by adding new cmds to GHCi.
See the user's guide entry or the Note [TcRnExprMode] in TcRnDriver.
Test cases: ghci/scripts/T{10963,11975}
-rw-r--r-- | compiler/main/GHC.hs | 2 | ||||
-rw-r--r-- | compiler/main/HscMain.hs | 8 | ||||
-rw-r--r-- | compiler/main/InteractiveEval.hs | 8 | ||||
-rw-r--r-- | compiler/typecheck/TcBinds.hs | 9 | ||||
-rw-r--r-- | compiler/typecheck/TcExpr.hs | 11 | ||||
-rw-r--r-- | compiler/typecheck/TcPatSyn.hs | 3 | ||||
-rw-r--r-- | compiler/typecheck/TcRnDriver.hs | 101 | ||||
-rw-r--r-- | compiler/typecheck/TcSimplify.hs | 93 | ||||
-rw-r--r-- | docs/users_guide/ghci.rst | 82 | ||||
-rw-r--r-- | ghc/GHCi/UI.hs | 12 | ||||
-rw-r--r-- | ghc/GHCi/UI/Info.hs | 2 | ||||
-rw-r--r-- | testsuite/tests/ghc-api/T8639_api.hs | 2 | ||||
-rw-r--r-- | testsuite/tests/ghci/scripts/T10963.script | 7 | ||||
-rw-r--r-- | testsuite/tests/ghci/scripts/T10963.stderr | 12 | ||||
-rw-r--r-- | testsuite/tests/ghci/scripts/T10963.stdout | 4 | ||||
-rw-r--r-- | testsuite/tests/ghci/scripts/T11975.script | 9 | ||||
-rw-r--r-- | testsuite/tests/ghci/scripts/T11975.stdout | 15 | ||||
-rwxr-xr-x | testsuite/tests/ghci/scripts/all.T | 2 |
18 files changed, 300 insertions, 82 deletions
diff --git a/compiler/main/GHC.hs b/compiler/main/GHC.hs index 40aa7dfa01..9dc68537d9 100644 --- a/compiler/main/GHC.hs +++ b/compiler/main/GHC.hs @@ -116,7 +116,7 @@ module GHC ( isModuleInterpreted, -- ** Inspecting types and kinds - exprType, + exprType, TcRnExprMode(..), typeKind, -- ** Looking up a Name diff --git a/compiler/main/HscMain.hs b/compiler/main/HscMain.hs index 7cbc6e711f..9c510df27b 100644 --- a/compiler/main/HscMain.hs +++ b/compiler/main/HscMain.hs @@ -65,7 +65,7 @@ module HscMain , hscTcRnLookupRdrName , hscStmt, hscStmtWithLocation, hscParsedStmt , hscDecls, hscDeclsWithLocation - , hscTcExpr, hscImport, hscKcType + , hscTcExpr, TcRnExprMode(..), hscImport, hscKcType , hscParseExpr , hscCompileCoreExpr -- * Low-level exports for hooks @@ -1609,14 +1609,14 @@ hscImport hsc_env str = runInteractiveHsc hsc_env $ do text "parse error in import declaration" -- | Typecheck an expression (but don't run it) --- Returns its most general type hscTcExpr :: HscEnv + -> TcRnExprMode -> String -- ^ The expression -> IO Type -hscTcExpr hsc_env0 expr = runInteractiveHsc hsc_env0 $ do +hscTcExpr hsc_env0 mode expr = runInteractiveHsc hsc_env0 $ do hsc_env <- getHscEnv parsed_expr <- hscParseExpr expr - ioMsgMaybe $ tcRnExpr hsc_env parsed_expr + ioMsgMaybe $ tcRnExpr hsc_env mode parsed_expr -- | Find the kind of a type -- Currently this does *not* generalise the kinds of the type diff --git a/compiler/main/InteractiveEval.hs b/compiler/main/InteractiveEval.hs index 6c95dc3bcc..9877e9a0c7 100644 --- a/compiler/main/InteractiveEval.hs +++ b/compiler/main/InteractiveEval.hs @@ -864,10 +864,10 @@ parseThing parser dflags stmt = do -- Getting the type of an expression -- | Get the type of an expression --- Returns its most general type -exprType :: GhcMonad m => String -> m Type -exprType expr = withSession $ \hsc_env -> do - ty <- liftIO $ hscTcExpr hsc_env expr +-- Returns the type as described by 'TcRnExprMode' +exprType :: GhcMonad m => TcRnExprMode -> String -> m Type +exprType mode expr = withSession $ \hsc_env -> do + ty <- liftIO $ hscTcExpr hsc_env mode expr return $ tidyType emptyTidyEnv ty -- ----------------------------------------------------------------------------- diff --git a/compiler/typecheck/TcBinds.hs b/compiler/typecheck/TcBinds.hs index 7c45ac7b59..3a931cb6f6 100644 --- a/compiler/typecheck/TcBinds.hs +++ b/compiler/typecheck/TcBinds.hs @@ -710,15 +710,16 @@ tcPolyInfer rec_tc prag_fn tc_sig_fn mono bind_list <- pushLevelAndCaptureConstraints $ tcMonoBinds rec_tc tc_sig_fn LetLclBndr bind_list - ; let name_taus = [ (mbi_poly_name info, idType (mbi_mono_id info)) - | info <- mono_infos ] - sigs = [ sig | MBI { mbi_sig = Just sig } <- mono_infos ] + ; let name_taus = [ (mbi_poly_name info, idType (mbi_mono_id info)) + | info <- mono_infos ] + sigs = [ sig | MBI { mbi_sig = Just sig } <- mono_infos ] + infer_mode = if mono then ApplyMR else NoRestrictions ; mapM_ (checkOverloadedSig mono) sigs ; traceTc "simplifyInfer call" (ppr tclvl $$ ppr name_taus $$ ppr wanted) ; (qtvs, givens, ev_binds) - <- simplifyInfer tclvl mono sigs name_taus wanted + <- simplifyInfer tclvl infer_mode sigs name_taus wanted ; let inferred_theta = map evVarPred givens ; exports <- checkNoErrs $ diff --git a/compiler/typecheck/TcExpr.hs b/compiler/typecheck/TcExpr.hs index 0e3c655f76..bb3fef7349 100644 --- a/compiler/typecheck/TcExpr.hs +++ b/compiler/typecheck/TcExpr.hs @@ -29,7 +29,7 @@ import BasicTypes import Inst import TcBinds ( chooseInferredQuantifiers, tcLocalBinds ) import TcSigs ( tcUserTypeSig, tcInstSig ) -import TcSimplify ( simplifyInfer ) +import TcSimplify ( simplifyInfer, InferMode(..) ) import FamInst ( tcGetFamInstEnvs, tcLookupDataFamInst ) import FamInstEnv ( FamInstEnvs ) import RnEnv ( addUsedGRE, addNameClashErrRn @@ -1472,10 +1472,13 @@ tcExprSig expr sig@(PartialSig { psig_name = name, sig_loc = loc }) ; return (expr', sig_inst) } -- See Note [Partial expression signatures] ; let tau = sig_inst_tau sig_inst - mr = null (sig_inst_theta sig_inst) && - isNothing (sig_inst_wcx sig_inst) + infer_mode | null (sig_inst_theta sig_inst) + , isNothing (sig_inst_wcx sig_inst) + = ApplyMR + | otherwise + = NoRestrictions ; (qtvs, givens, ev_binds) - <- simplifyInfer tclvl mr [sig_inst] [(name, tau)] wanted + <- simplifyInfer tclvl infer_mode [sig_inst] [(name, tau)] wanted ; tau <- zonkTcType tau ; let inferred_theta = map evVarPred givens tau_tvs = tyCoVarsOfType tau diff --git a/compiler/typecheck/TcPatSyn.hs b/compiler/typecheck/TcPatSyn.hs index b9a6dec0a8..e19a786b1d 100644 --- a/compiler/typecheck/TcPatSyn.hs +++ b/compiler/typecheck/TcPatSyn.hs @@ -81,7 +81,8 @@ tcInferPatSynDecl PSB{ psb_id = lname@(L _ name), psb_args = details, ; let named_taus = (name, pat_ty) : map (\arg -> (getName arg, varType arg)) args - ; (qtvs, req_dicts, ev_binds) <- simplifyInfer tclvl False [] named_taus wanted + ; (qtvs, req_dicts, ev_binds) <- simplifyInfer tclvl NoRestrictions [] + named_taus wanted ; let ((ex_tvs, ex_vars), prov_dicts) = tcCollectEx lpat' univ_tvs = filter (not . (`elemVarSet` ex_vars)) qtvs diff --git a/compiler/typecheck/TcRnDriver.hs b/compiler/typecheck/TcRnDriver.hs index 9d3bd99ab9..46d0a7b34f 100644 --- a/compiler/typecheck/TcRnDriver.hs +++ b/compiler/typecheck/TcRnDriver.hs @@ -13,7 +13,7 @@ https://ghc.haskell.org/trac/ghc/wiki/Commentary/Compiler/TypeChecker module TcRnDriver ( #ifdef GHCI - tcRnStmt, tcRnExpr, tcRnType, + tcRnStmt, tcRnExpr, TcRnExprMode(..), tcRnType, tcRnImportDecls, tcRnLookupRdrName, getModuleInterface, @@ -1972,13 +1972,17 @@ isGHCiMonad hsc_env ty Just _ -> failWithTc $ text "Ambiguous type!" Nothing -> failWithTc $ text ("Can't find type:" ++ ty) --- tcRnExpr just finds the type of an expression +-- | How should we infer a type? See Note [TcRnExprMode] +data TcRnExprMode = TM_Inst -- ^ Instantiate the type fully (:type) + | TM_NoInst -- ^ Do not instantiate the type (:type +v) + | TM_Default -- ^ Default the type eagerly (:type +d) +-- | tcRnExpr just finds the type of an expression tcRnExpr :: HscEnv + -> TcRnExprMode -> LHsExpr RdrName -> IO (Messages, Maybe Type) --- Type checks the expression and returns its most general type -tcRnExpr hsc_env rdr_expr +tcRnExpr hsc_env mode rdr_expr = runTcInteractive hsc_env $ do { @@ -1993,15 +1997,15 @@ tcRnExpr hsc_env rdr_expr (tclvl, lie, res_ty) <- pushLevelAndCaptureConstraints $ do { (_tc_expr, expr_ty) <- tcInferSigma rn_expr - ; (_wrap, res_ty) <- deeplyInstantiate orig expr_ty - -- See [Note Deeply instantiate in :type] - ; return res_ty } ; + ; if inst + then snd <$> deeplyInstantiate orig expr_ty + else return expr_ty } ; -- Generalise ((qtvs, dicts, _), lie_top) <- captureConstraints $ {-# SCC "simplifyInfer" #-} simplifyInfer tclvl - False {- No MR for now -} + infer_mode [] {- No sig vars -} [(fresh_it, res_ty)] lie ; @@ -2009,7 +2013,8 @@ tcRnExpr hsc_env rdr_expr stWC <- tcg_static_wc <$> getGblEnv >>= readTcRef ; -- Ignore the dictionary bindings - _ <- simplifyInteractive (andWC stWC lie_top) ; + _ <- perhaps_disable_default_warnings $ + simplifyInteractive (andWC stWC lie_top) ; let { all_expr_ty = mkInvForAllTys qtvs (mkLamTypes dicts res_ty) } ; ty <- zonkTcType all_expr_ty ; @@ -2022,6 +2027,12 @@ tcRnExpr hsc_env rdr_expr -- irrelevant return (snd (normaliseType fam_envs Nominal ty)) } + where + -- See Note [Deeply instantiate in :type] + (inst, infer_mode, perhaps_disable_default_warnings) = case mode of + TM_Inst -> (True, NoRestrictions, id) + TM_NoInst -> (False, NoRestrictions, id) + TM_Default -> (True, EagerDefaulting, unsetWOptM Opt_WarnTypeDefaults) -------------------------- tcRnImportDecls :: HscEnv @@ -2038,7 +2049,6 @@ tcRnImportDecls hsc_env import_decls zap_rdr_env gbl_env = gbl_env { tcg_rdr_env = emptyGlobalRdrEnv } -- tcRnType just finds the kind of a type - tcRnType :: HscEnv -> Bool -- Normalise the returned type -> LHsType RdrName @@ -2073,20 +2083,63 @@ tcRnType hsc_env normalise rdr_type ; return (ty', mkInvForAllTys kvs (typeKind ty')) } -{- Note [Deeply instantiate in :type] -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Suppose (Trac #11376) - bar :: forall a b. Show a => a -> b -> a -What should `:t bar @Int` show? - - 1. forall b. Show Int => Int -> b -> Int - 2. forall b. Int -> b -> Int - 3. forall {b}. Int -> b -> Int - 4. Int -> b -> Int - -We choose (3), which is the effect of deeply instantiating and -re-generalising. All the others seem deeply confusing. That is -why we deeply instantiate here. +{- Note [TcRnExprMode] +~~~~~~~~~~~~~~~~~~~~~~ +How should we infer a type when a user asks for the type of an expression e +at the GHCi prompt? We offer 3 different possibilities, described below. Each +considers this example, with -fprint-explicit-foralls enabled: + + foo :: forall a f b. (Show a, Num b, Foldable f) => a -> f b -> String + :type{,-spec,-def} foo @Int + +:type / TM_Inst + + In this mode, we report the type that would be inferred if a variable + were assigned to expression e, without applying the monomorphism restriction. + This means we deeply instantiate the type and then regeneralize, as discussed + in #11376. + + > :type foo @Int + forall {b} {f :: * -> *}. (Foldable f, Num b) => Int -> f b -> String + + Note that the variables and constraints are reordered here, because this + is possible during regeneralization. Also note that the variables are + reported as Invisible instead of Specified. + +:type +v / TM_NoInst + + This mode is for the benefit of users using TypeApplications. It does no + instantiation whatsoever, sometimes meaning that class constraints are not + solved. + + > :type +v foo @Int + forall f b. (Show Int, Num b, Foldable f) => Int -> f b -> String + + Note that Show Int is still reported, because the solver never got a chance + to see it. + +:type +d / TM_Default + + This mode is for the benefit of users who wish to see instantiations of + generalized types, and in particular to instantiate Foldable and Traversable. + In this mode, any type variable that can be defaulted is defaulted. Because + GHCi uses -XExtendedDefaultRules, this means that Foldable and Traversable are + defaulted. + + > :type +d foo @Int + Int -> [Integer] -> String + + Note that this mode can sometimes lead to a type error, if a type variable is + used with a defaultable class but cannot actually be defaulted: + + bar :: (Num a, Monoid a) => a -> a + > :type +d bar + ** error ** + + The error arises because GHC tries to default a but cannot find a concrete + type in the defaulting list that is both Num and Monoid. (If this list is + modified to include an element that is both Num and Monoid, the defaulting + would succeed, of course.) Note [Kind-generalise in tcRnType] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/compiler/typecheck/TcSimplify.hs b/compiler/typecheck/TcSimplify.hs index 594cc949b3..18adee8047 100644 --- a/compiler/typecheck/TcSimplify.hs +++ b/compiler/typecheck/TcSimplify.hs @@ -1,7 +1,7 @@ {-# LANGUAGE CPP #-} module TcSimplify( - simplifyInfer, + simplifyInfer, InferMode(..), growThetaTyVars, simplifyAmbiguityCheck, simplifyDefault, @@ -514,8 +514,22 @@ the let binding. -} +-- | How should we choose which constraints to quantify over? +data InferMode = ApplyMR -- ^ Apply the monomorphism restriction, + -- never quantifying over any constraints + | EagerDefaulting -- ^ See Note [TcRnExprMode] in TcRnDriver, + -- the :type +d case; this mode refuses + -- to quantify over any defaultable constraint + | NoRestrictions -- ^ Quantify over any constraint that + -- satisfies TcType.pickQuantifiablePreds + +instance Outputable InferMode where + ppr ApplyMR = text "ApplyMR" + ppr EagerDefaulting = text "EagerDefaulting" + ppr NoRestrictions = text "NoRestrictions" + simplifyInfer :: TcLevel -- Used when generating the constraints - -> Bool -- Apply monomorphism restriction + -> InferMode -> [TcIdSigInst] -- Any signatures (possibly partial) -> [(Name, TcTauType)] -- Variables to be generalised, -- and their tau-types @@ -523,7 +537,7 @@ simplifyInfer :: TcLevel -- Used when generating the constraints -> TcM ([TcTyVar], -- Quantify over these type variables [EvVar], -- ... and these constraints (fully zonked) TcEvBinds) -- ... binding these evidence variables -simplifyInfer rhs_tclvl apply_mr sigs name_taus wanteds +simplifyInfer rhs_tclvl infer_mode sigs name_taus wanteds | isEmptyWC wanteds = do { gbl_tvs <- tcGetGlobalTyCoVars ; dep_vars <- zonkTcTypesAndSplitDepVars (map snd name_taus) @@ -536,7 +550,7 @@ simplifyInfer rhs_tclvl apply_mr sigs name_taus wanteds [ text "sigs =" <+> ppr sigs , text "binds =" <+> ppr name_taus , text "rhs_tclvl =" <+> ppr rhs_tclvl - , text "apply_mr =" <+> ppr apply_mr + , text "infer_mode =" <+> ppr infer_mode , text "(unzonked) wanted =" <+> ppr wanteds ] @@ -616,7 +630,7 @@ simplifyInfer rhs_tclvl apply_mr sigs name_taus wanteds -- Decide what type variables and constraints to quantify -- NB: bound_theta are constraints we want to quantify over, -- /apart from/ the psig_theta, which we always quantify over - ; (qtvs, bound_theta) <- decideQuantification apply_mr name_taus psig_theta + ; (qtvs, bound_theta) <- decideQuantification infer_mode name_taus psig_theta quant_pred_candidates -- Promote any type variables that are free in the inferred type @@ -763,23 +777,31 @@ including all covars -- and the quantified constraints are empty/insoluble. -} decideQuantification - :: Bool -- try the MR restriction? + :: InferMode -> [(Name, TcTauType)] -- Variables to be generalised -> [PredType] -- All annotated constraints from signatures -> [PredType] -- Candidate theta -> TcM ( [TcTyVar] -- Quantify over these (skolems) , [PredType] ) -- and this context (fully zonked) -- See Note [Deciding quantification] -decideQuantification apply_mr name_taus psig_theta candidates +decideQuantification infer_mode name_taus psig_theta candidates = do { gbl_tvs <- tcGetGlobalTyCoVars ; zonked_taus <- mapM TcM.zonkTcType (psig_theta ++ taus) -- psig_theta: see Note [Quantification and partial signatures] - ; let DV { dv_kvs = zkvs, dv_tvs = ztvs} = splitDepVarsOfTypes zonked_taus + ; ovl_strings <- xoptM LangExt.OverloadedStrings + ; let DV {dv_kvs = zkvs, dv_tvs = ztvs} = splitDepVarsOfTypes zonked_taus (gbl_cand, quant_cand) -- gbl_cand = do not quantify me - = case apply_mr of -- quant_cand = try to quantify me - True -> (candidates, []) - False -> ([], candidates) - zonked_tkvs = dVarSetToVarSet zkvs `unionVarSet` dVarSetToVarSet ztvs + = case infer_mode of -- quant_cand = try to quantify me + ApplyMR -> (candidates, []) + NoRestrictions -> ([], candidates) + EagerDefaulting -> partition is_interactive_ct candidates + where + is_interactive_ct ct + | Just (cls, _) <- getClassPredTys_maybe ct + = isInteractiveClass ovl_strings cls + | otherwise + = False + eq_constraints = filter isEqPred quant_cand constrained_tvs = tyCoVarsOfTypes gbl_cand mono_tvs = growThetaTyVars eq_constraints $ @@ -804,7 +826,10 @@ decideQuantification apply_mr name_taus psig_theta candidates -- Warn about the monomorphism restriction ; warn_mono <- woptM Opt_WarnMonomorphism - ; let mr_bites = constrained_tvs `intersectsVarSet` zonked_tkvs + ; let mr_bites | ApplyMR <- infer_mode + = constrained_tvs `intersectsVarSet` tcDepVarSet dvs_plus + | otherwise + = False ; warnTc (Reason Opt_WarnMonomorphism) (warn_mono && mr_bites) $ hang (text "The Monomorphism Restriction applies to the binding" <> plural bndrs <+> text "for" <+> pp_bndrs) @@ -812,8 +837,9 @@ decideQuantification apply_mr name_taus psig_theta candidates <+> if isSingleton bndrs then pp_bndrs else text "these binders") - ; traceTc "decideQuantification 2" - (vcat [ text "gbl_cand:" <+> ppr gbl_cand + ; traceTc "decideQuantification" + (vcat [ text "infer_mode:" <+> ppr infer_mode + , text "gbl_cand:" <+> ppr gbl_cand , text "quant_cand:" <+> ppr quant_cand , text "gbl_tvs:" <+> ppr gbl_tvs , text "mono_tvs:" <+> ppr mono_tvs @@ -1676,7 +1702,7 @@ approximateWC to produce a list of candidate constraints. Then we MUST approximateWC, to restore invariant (MetaTvInv) described in Note [TcLevel and untouchable type variables] in TcType. - b) Default the kind of any meta-tyyvars that are not mentioned in + b) Default the kind of any meta-tyvars that are not mentioned in in the environment. To see (b), suppose the constraint is (C ((a :: OpenKind) -> Int)), and we @@ -1994,22 +2020,13 @@ findDefaultableGroups (default_tys, (ovl_strings, extended_defaults)) wanteds in b1 && b2 defaultable_classes clss - | extended_defaults = any isInteractiveClass clss - | otherwise = all is_std_class clss && (any is_num_class clss) - - -- In interactive mode, or with -XExtendedDefaultRules, - -- we default Show a to Show () to avoid graututious errors on "show []" - isInteractiveClass cls - = is_num_class cls || (classKey cls `elem` [showClassKey, eqClassKey - , ordClassKey, foldableClassKey - , traversableClassKey]) - - is_num_class cls = isNumericClass cls || (ovl_strings && (cls `hasKey` isStringClassKey)) - -- is_num_class adds IsString to the standard numeric classes, - -- when -foverloaded-strings is enabled + | extended_defaults = any (isInteractiveClass ovl_strings) clss + | otherwise = all is_std_class clss && (any (isNumClass ovl_strings) clss) - is_std_class cls = isStandardClass cls || (ovl_strings && (cls `hasKey` isStringClassKey)) - -- Similarly is_std_class + -- is_std_class adds IsString to the standard numeric classes, + -- when -foverloaded-strings is enabled + is_std_class cls = isStandardClass cls || + (ovl_strings && (cls `hasKey` isStringClassKey)) ------------------------------ disambigGroup :: [Type] -- The default types @@ -2061,6 +2078,20 @@ disambigGroup (default_ty:default_tys) group@(the_tv, wanteds) -- With the addition of polykinded defaulting we also want to reject -- ill-kinded defaulting attempts like (Eq []) or (Foldable Int) here. +-- In interactive mode, or with -XExtendedDefaultRules, +-- we default Show a to Show () to avoid graututious errors on "show []" +isInteractiveClass :: Bool -- -XOverloadedStrings? + -> Class -> Bool +isInteractiveClass ovl_strings cls + = isNumClass ovl_strings cls || (classKey cls `elem` interactiveClassKeys) + + -- isNumClass adds IsString to the standard numeric classes, + -- when -foverloaded-strings is enabled +isNumClass :: Bool -- -XOverloadedStrings? + -> Class -> Bool +isNumClass ovl_strings cls + = isNumericClass cls || (ovl_strings && (cls `hasKey` isStringClassKey)) + {- Note [Avoiding spurious errors] diff --git a/docs/users_guide/ghci.rst b/docs/users_guide/ghci.rst index 5404701898..783059fe17 100644 --- a/docs/users_guide/ghci.rst +++ b/docs/users_guide/ghci.rst @@ -977,6 +977,10 @@ Type defaulting in GHCi single: Type defaulting; in GHCi single: Show class +.. ghc-flag:: -XExtendedDefaultRules + + Allow defaulting to take place for more than just numeric classes. + Consider this GHCi session: .. code-block:: none @@ -1014,7 +1018,7 @@ is given, the following additional differences apply: single-parameter type classes. - Rule 3 above is relaxed this: At least one of the classes ``Ci`` is - numeric, or is ``Show``, ``Eq``, ``Ord``, ``Foldable`` or ``Traversable``. + an *interactive class* (defined below). - The unit type ``()`` and the list type ``[]`` are added to the start of the standard list of types which are tried when doing type defaulting. @@ -1044,6 +1048,38 @@ printf. See also :ref:`actions-at-prompt` for how the monad of a computational expression defaults to ``IO`` if possible. +Interactive classes +^^^^^^^^^^^^^^^^^^^ + +.. index:: + single: Interactive classes + +The interactive classes (only relevant when :ghc-flag:`-XExtendedDefaultRules` +is in effect) are: any numeric class, ``Show``, ``Eq``, ``Ord``, +``Foldable`` or ``Traversable``. + +As long as a type variable is constrained by one of these classes, defaulting +will occur, as outlined above. + +Extended rules around ``default`` declarations +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. index:: + single: default declarations + +Since the rules for defaulting are relaxed under +:ghc-flag:`-XExtendedDefaultRules`, the rules for ``default`` declarations +are also relaxed. According to Section 4.3.4 of the Haskell 2010 Report, +a ``default`` declaration looks like ``default (t1, ..., tn)`` where, for +each ``ti``, ``Num ti`` must hold. This is relaxed to say that for each +``ti``, there must exist an interactive class ``C`` such that ``C ti`` holds. +This means that type *constructors* can be allowed in these lists. +For example, the following works if you wish your ``Foldable`` constraints +to default to ``Maybe`` but your ``Num`` constraints to still default +to ``Integer`` or ``Double``: :: + + default (Maybe, Integer, Double) + .. _ghci-interactive-print: Using a custom interactive printing function @@ -2625,10 +2661,48 @@ commonly used commands. .. ghci-cmd:: :type; ⟨expression⟩ Infers and prints the type of ⟨expression⟩, including explicit - forall quantifiers for polymorphic types. The monomorphism - restriction is *not* applied to the expression during type - inference. + forall quantifiers for polymorphic types. + The type reported is the type that would be inferred + for a variable assigned to the expression, but without the + monomorphism restriction applied. + + .. code-block:: none + + *X> :type length + length :: Foldable t => t a -> Int + +.. ghci-cmd:: :type +v ⟨expression⟩ + + Infers and prints the type of ⟨expression⟩, but without fiddling + with type variables or class constraints. This is useful when you + are using :ghc-flag:`-XTypeApplications` and care about the distinction + between specified type variables (available for type application) + and inferred type variables (not available). This mode sometimes prints + constraints (such as ``Show Int``) that could readily be solved, but + solving these constraints may affect the type variables, so GHC refrains. + + .. code-block:: none + + *X> :set -fprint-explicit-foralls + *X> :type +v length + length :: forall (t :: * -> *). Foldable t => forall a. t a -> Int + +.. ghci-cmd:: :type +d ⟨expression⟩ + + Infers and prints the type of ⟨expression⟩, defaulting type variables + if possible. In this mode, if the inferred type is constrained by + any interactive class (``Num``, ``Show``, ``Eq``, ``Ord``, ``Foldable``, + or ``Traversable``), the constrained type variable(s) are defaulted + according to the rules described under :ghc-flag:`-XExtendedDefaultRules`. + This mode is quite useful when the inferred type is quite general (such + as for ``foldr``) and it may be helpful to see a more concrete + instantiation. + + .. code-block:: none + *X> :type +d length + length :: [a] -> Int + .. ghci-cmd:: :type-at; ⟨module⟩ ⟨line⟩ ⟨col⟩ ⟨end-line⟩ ⟨end-col⟩ [⟨name⟩] Reports the inferred type at the given span/position in the module, e.g.: diff --git a/ghc/GHCi/UI.hs b/ghc/GHCi/UI.hs index c04bf2d194..1e27c7a861 100644 --- a/ghc/GHCi/UI.hs +++ b/ghc/GHCi/UI.hs @@ -299,6 +299,8 @@ defFullHelpText = " :run function [<arguments> ...] run the function with the given arguments\n" ++ " :script <file> run the script <file>\n" ++ " :type <expr> show the type of <expr>\n" ++ + " :type +d <expr> show the type of <expr>, defaulting type variables\n" ++ + " :type +v <expr> show the type of <expr>, with its specified tyvars\n" ++ " :undef <cmd> undefine user-defined command :<cmd>\n" ++ " :!<command> run the shell command <command>\n" ++ "\n" ++ @@ -1811,12 +1813,16 @@ exceptT :: Applicative m => Either e a -> ExceptT e m a exceptT = ExceptT . pure ----------------------------------------------------------------------------- --- | @:type@ command +-- | @:type@ command. See also Note [TcRnExprMode] in TcRnDriver. typeOfExpr :: String -> InputT GHCi () typeOfExpr str = handleSourceError GHC.printException $ do - ty <- GHC.exprType str - printForUser $ sep [text str, nest 2 (dcolon <+> pprTypeForUser ty)] + let (mode, expr_str) = case break isSpace str of + ("+d", rest) -> (GHC.TM_Default, dropWhile isSpace rest) + ("+v", rest) -> (GHC.TM_NoInst, dropWhile isSpace rest) + _ -> (GHC.TM_Inst, str) + ty <- GHC.exprType mode expr_str + printForUser $ sep [text expr_str, nest 2 (dcolon <+> pprTypeForUser ty)] ----------------------------------------------------------------------------- -- | @:type-at@ command diff --git a/ghc/GHCi/UI/Info.hs b/ghc/GHCi/UI/Info.hs index 2c44e3f8e2..ef5e9ef207 100644 --- a/ghc/GHCi/UI/Info.hs +++ b/ghc/GHCi/UI/Info.hs @@ -215,7 +215,7 @@ findType infos span0 string = do MaybeT $ pure $ M.lookup name infos case resolveType (modinfoSpans info) (spanInfoFromRealSrcSpan' span0) of - Nothing -> (,) info <$> lift (exprType string) + Nothing -> (,) info <$> lift (exprType TM_Inst string) Just ty -> return (info, ty) where -- | Try to resolve the type display from the given span. diff --git a/testsuite/tests/ghc-api/T8639_api.hs b/testsuite/tests/ghc-api/T8639_api.hs index 36458b8eca..2b0bc7d4c6 100644 --- a/testsuite/tests/ghc-api/T8639_api.hs +++ b/testsuite/tests/ghc-api/T8639_api.hs @@ -22,6 +22,6 @@ main execStmt "putStrLn (show 3)" execOptions execStmt "hFlush stdout" execOptions - ty <- exprType "T8639_api_a.it" + ty <- exprType TM_Inst "T8639_api_a.it" liftIO (putStrLn (showPpr flags ty)) ; hFlush stdout } diff --git a/testsuite/tests/ghci/scripts/T10963.script b/testsuite/tests/ghci/scripts/T10963.script new file mode 100644 index 0000000000..357d1256ba --- /dev/null +++ b/testsuite/tests/ghci/scripts/T10963.script @@ -0,0 +1,7 @@ +:type mapM +:type +d mapM +:t +d length +let foo :: (Num a, Monoid a) => a -> a; foo = undefined +:t +d foo +instance Monoid Double where mempty = 0; mappend = (+) +:t +d foo diff --git a/testsuite/tests/ghci/scripts/T10963.stderr b/testsuite/tests/ghci/scripts/T10963.stderr new file mode 100644 index 0000000000..e20f792773 --- /dev/null +++ b/testsuite/tests/ghci/scripts/T10963.stderr @@ -0,0 +1,12 @@ + +<interactive>:1:1: error: + Ambiguous type variable ‘a0’ arising from a use of ‘foo’ + prevents the constraint ‘(Num a0)’ from being solved. + Probable fix: use a type annotation to specify what ‘a0’ should be. + These potential instances exist: + instance Num Integer -- Defined in ‘GHC.Num’ + instance Num Double -- Defined in ‘GHC.Float’ + instance Num Float -- Defined in ‘GHC.Float’ + ...plus two others + ...plus five instances involving out-of-scope types + (use -fprint-potential-instances to see them all) diff --git a/testsuite/tests/ghci/scripts/T10963.stdout b/testsuite/tests/ghci/scripts/T10963.stdout new file mode 100644 index 0000000000..bf639a8aa5 --- /dev/null +++ b/testsuite/tests/ghci/scripts/T10963.stdout @@ -0,0 +1,4 @@ +mapM :: (Monad m, Traversable t) => (a -> m b) -> t a -> m (t b) +mapM :: Monad m => (a -> m b) -> [a] -> m [b] +length :: [a] -> Int +foo :: Double -> Double diff --git a/testsuite/tests/ghci/scripts/T11975.script b/testsuite/tests/ghci/scripts/T11975.script new file mode 100644 index 0000000000..80061ef97b --- /dev/null +++ b/testsuite/tests/ghci/scripts/T11975.script @@ -0,0 +1,9 @@ +:set -fprint-explicit-foralls +:type mapM +:type +v mapM +:t +v mapM +let foo :: (Show a, Num b) => a -> b; foo = undefined +:set -XTypeApplications +:type foo @Int +:type +v foo @Int +:t +v foo @Int diff --git a/testsuite/tests/ghci/scripts/T11975.stdout b/testsuite/tests/ghci/scripts/T11975.stdout new file mode 100644 index 0000000000..23adaf02db --- /dev/null +++ b/testsuite/tests/ghci/scripts/T11975.stdout @@ -0,0 +1,15 @@ +mapM + :: forall {t :: * -> *} {b} {m :: * -> *} {a}. + (Monad m, Traversable t) => + (a -> m b) -> t a -> m (t b) +mapM + :: forall (t :: * -> *). + Traversable t => + forall (m :: * -> *) a b. Monad m => (a -> m b) -> t a -> m (t b) +mapM + :: forall (t :: * -> *). + Traversable t => + forall (m :: * -> *) a b. Monad m => (a -> m b) -> t a -> m (t b) +foo @Int :: forall {b}. Num b => Int -> b +foo @Int :: forall b. (Show Int, Num b) => Int -> b +foo @Int :: forall b. (Show Int, Num b) => Int -> b diff --git a/testsuite/tests/ghci/scripts/all.T b/testsuite/tests/ghci/scripts/all.T index dfedb39ea7..b2ea302f42 100755 --- a/testsuite/tests/ghci/scripts/all.T +++ b/testsuite/tests/ghci/scripts/all.T @@ -254,3 +254,5 @@ test('TypeAppData', normal, ghci_script, ['TypeAppData.script']) test('T11728', normal, ghci_script, ['T11728.script']) test('T11376', normal, ghci_script, ['T11376.script']) test('T12007', normal, ghci_script, ['T12007.script']) +test('T11975', normal, ghci_script, ['T11975.script']) +test('T10963', normal, ghci_script, ['T10963.script']) |