[Git][ghc/ghc][wip/marge_bot_batch_merge_job] 2 commits: base: improve error message for Data.Char.chr
Marge Bot pushed to branch wip/marge_bot_batch_merge_job at Glasgow Haskell Compiler / GHC Commits: ba49d2eb by Andrew Lelechenko at 2026-04-06T19:26:44-04:00 base: improve error message for Data.Char.chr As per https://github.com/haskell/core-libraries-committee/issues/384 - - - - - 84c751d4 by Simon Peyton Jones at 2026-04-06T19:26:45-04:00 Refactor FunResCtxt a bit Fixes #27154 - - - - - 10 changed files: - compiler/GHC/Tc/Errors/Ppr.hs - compiler/GHC/Tc/Gen/Head.hs - compiler/GHC/Tc/Types/ErrCtxt.hs - compiler/GHC/Tc/Utils/TcType.hs - compiler/GHC/Tc/Zonk/TcType.hs - libraries/base/changelog.md - libraries/base/tests/enum01.stdout - libraries/base/tests/enum01.stdout-alpha-dec-osf3 - libraries/base/tests/enum01.stdout-ws-64 - libraries/ghc-internal/src/GHC/Internal/Char.hs Changes: ===================================== compiler/GHC/Tc/Errors/Ppr.hs ===================================== @@ -7710,12 +7710,8 @@ pprHsCtxt = \case PatSigErrCtxt sig_ty res_ty -> vcat [ hang (text "When checking that the pattern signature:") 4 (ppr sig_ty) - , nest 2 (hang (text "fits the type of its context:") 2 pp_res_ty) ] - where - -- Zonking will have turned Infer into Check - pp_res_ty = case res_ty of - Check ty -> ppr ty - Infer ir -> text "OOPS" <+> ppr ir + , nest 2 (hang (text "fits the type of its context:") + 2 (ppr (getCheckExpType res_ty))) ] PatCtxt pat -> hang (text "In the pattern:") 2 (ppr pat) @@ -7777,7 +7773,7 @@ pprHsCtxt = \case full_herald = pprExpectedFunTyHerald herald <+> speakNOf n_vis_args_in_call (text "visible argument") -- What are "visible" arguments? See Note [Visibility and arity] in GHC.Types.Basic - FunResCtxt fun n_val_args res_fun res_env n_fun n_env + FunResCtxt fun n_val_args fun_res_ty env_ty | -- Check for too few args -- fun_tau = a -> b, res_tau = Int n_fun > n_env @@ -7801,6 +7797,18 @@ pprHsCtxt = \case -> empty -- text "Debug" <+> vcat [ppr fun, ppr n_val_args, ppr res_fun, ppr res_env, ppr n_fun, ppr n_env] where + -- See Note [Splitting nested sigma types in mismatched + -- function types] + -- env_ty is an ExpRhoTy, but with simple subsumption it + -- is not /deeply/ skolemised, so still use tcSplitNestedSigmaTys + + (_,_,fun_tau) = tcSplitNestedSigmaTys fun_res_ty + (_, _, env_tau) = tcSplitNestedSigmaTys (getCheckExpType env_ty) + (args_fun, res_fun) = tcSplitFunTys fun_tau + (args_env, res_env) = tcSplitFunTys env_tau + n_fun = length args_fun + n_env = length args_env + not_fun ty -- ty is definitely not an arrow type, -- and cannot conceivably become one = case tcSplitTyConApp_maybe ty of ===================================== compiler/GHC/Tc/Gen/Head.hs ===================================== @@ -68,7 +68,6 @@ import GHC.Builtin.Names import GHC.Driver.DynFlags import GHC.Utils.Misc import GHC.Utils.Outputable as Outputable -import GHC.Utils.Panic import GHC.Data.Maybe @@ -961,7 +960,8 @@ See Note [-fno-code mode]. * * ********************************************************************* -} -addFunResCtxt :: HsExpr GhcTc -> [HsExprArg p] +addFunResCtxt :: HasDebugCallStack + => HsExpr GhcTc -> [HsExprArg p] -> TcType -> ExpRhoType -> TcM a -> TcM a -- When we have a mis-match in the return type of a function @@ -969,33 +969,10 @@ addFunResCtxt :: HsExpr GhcTc -> [HsExprArg p] -- But not in generated code, where we don't want -- to mention internal (rebindable syntax) function names addFunResCtxt fun args fun_res_ty env_ty thing_inside - = do { env_tv <- newFlexiTyVarTy liftedTypeKind - ; dumping <- doptM Opt_D_dump_tc_trace - ; msg <- mk_msg dumping env_tv - ; addErrCtxt msg thing_inside } + = addErrCtxt (FunResCtxt fun (count isValArg args) fun_res_ty env_ty) $ + thing_inside -- NB: use a landmark error context, so that an empty context -- doesn't suppress some more useful context - where - mk_msg dumping env_tv - = do { mb_env_ty <- readExpType_maybe env_ty - -- by the time the message is rendered, the ExpType - -- will be filled in (except if we're debugging) - ; env' <- case mb_env_ty of - Just env_ty -> return env_ty - Nothing -> do { massert dumping; return env_tv } - ; let -- See Note [Splitting nested sigma types in mismatched - -- function types] - (_, _, fun_tau) = tcSplitNestedSigmaTys fun_res_ty - (_, _, env_tau) = tcSplitNestedSigmaTys env' - -- env_ty is an ExpRhoTy, but with simple subsumption it - -- is not deeply skolemised, so still use tcSplitNestedSigmaTys - (args_fun, res_fun) = tcSplitFunTys fun_tau - (args_env, res_env) = tcSplitFunTys env_tau - info = - FunResCtxt fun (count isValArg args) res_fun res_env - (length args_fun) (length args_env) - ; return info } - {- Note [Splitting nested sigma types in mismatched function types] ===================================== compiler/GHC/Tc/Types/ErrCtxt.hs ===================================== @@ -251,7 +251,10 @@ data HsCtxt -- | In the instance type signature of a class method. | MethSigCtxt !Name !TcType !TcType -- | In a pattern type signature. + | PatSigErrCtxt !TcType !ExpType + -- ExpType: see Note [ExpType in HsCtxt] + -- | In a pattern. | PatCtxt !(Pat GhcRn) -- | In a pattern synonym declaration. @@ -268,7 +271,10 @@ data HsCtxt -- | In a function call. | FunTysCtxt !ExpectedFunTyCtxt !Type !Int !Int -- | In the result of a function call. - | FunResCtxt !(HsExpr GhcTc) !Int !Type !Type !Int !Int + + | FunResCtxt !(HsExpr GhcTc) !Int !TcType !ExpType + -- ExpType: see Note [ExpType in HsCtxt] + -- | In the declaration of a type constructor. | TyConDeclCtxt !Name !(TyConFlavour TyCon) -- | In a type or data family instance (or default instance). @@ -377,3 +383,14 @@ isHsCtxtLandmark (DerivBindCtxt{}) = True isHsCtxtLandmark (FunResCtxt{}) = True isHsCtxtLandmark (VDQWarningCtxt{}) = True isHsCtxtLandmark _ = False + +{- Note [ExpType in HsCtxt] +~~~~~~~~~~~~~~~~~~~~~~~~~~~ +A couple of HsCtxt constructors have ExpTypes in them. When zonking the +Infer{} case we read the hole, which should be filled in by now, and zonk +that type. Now we want to put it back: we use (Check ty') for this, so that +clients of a zonked HsCtxt don't need to be monadic. + +Result: after zonking, these ExpTypes are always (Check ty). It woudl be nice +to guarantee this statically, but it's hard to do so. +-} ===================================== compiler/GHC/Tc/Utils/TcType.hs ===================================== @@ -28,7 +28,7 @@ module GHC.Tc.Utils.TcType ( ExpType(..), ExpKind, InferResult(..), InferInstFlag(..), InferFRRFlag(..), ExpTypeFRR, ExpSigmaType, ExpSigmaTypeFRR, ExpRhoType, ExpRhoTypeFRR, - mkCheckExpType, + mkCheckExpType, getCheckExpType, checkingExpType_maybe, checkingExpType, ExpPatType(..), mkCheckExpFunPatTy, mkInvisExpPatType, @@ -440,11 +440,12 @@ data InferInstFlag -- Specifies whether the inference should return an uninstan | IIF_ShallowRho -- Trying to infer a shallow RhoType (no foralls or => at the top) -- Top-instantiate (only, regardless of DeepSubsumption) before filling the hole - -- Typically used when inferring the type of an expression + -- Used only for view patterns; see Note [View patterns and polymorphism] | IIF_DeepRho -- Trying to infer a possibly-deep RhoType (depending on DeepSubsumption) -- If DeepSubsumption is off, same as IIF_ShallowRho -- If DeepSubsumption is on, instantiate deeply before filling the hole + -- Typically used when inferring the type of an expression type ExpSigmaType = ExpType type ExpRhoType = ExpType @@ -490,6 +491,12 @@ instance Outputable InferResult where mkCheckExpType :: TcType -> ExpType mkCheckExpType = Check +getCheckExpType :: HasDebugCallStack => ExpType -> TcType +-- Expect a (Check ty). +-- See Note [ExpType in HsCtxt] in GHC.Tc.Types.ErrCtxt +getCheckExpType (Check ty) = ty +getCheckExpType (Infer ir) = pprPanic "getCheckExpType" (ppr ir) + -- | Returns the expected type when in checking mode. checkingExpType_maybe :: ExpType -> Maybe TcType checkingExpType_maybe (Check ty) = Just ty ===================================== compiler/GHC/Tc/Zonk/TcType.hs ===================================== @@ -818,19 +818,26 @@ zonkTidyHsCtxt env e@(FunAppCtxt{}) = return (env, e) zonkTidyHsCtxt env (FunTysCtxt ctxt ty i1 i2) = do (env', ty') <- zonkTidyTcType env ty return $ (env', FunTysCtxt ctxt ty' i1 i2) -zonkTidyHsCtxt env (FunResCtxt e i1 ty1 ty2 i2 i3) = do - (env', ty1') <- zonkTidyTcType env ty1 - (env', ty2') <- zonkTidyTcType env' ty2 - return $ (env', FunResCtxt e i1 ty1' ty2' i2 i3) +zonkTidyHsCtxt env (FunResCtxt e n ty1 env_ty) = do + (env', ty1') <- zonkTidyTcType env ty1 + (env', env_ty') <- zonkExpType env' env_ty + return $ (env', FunResCtxt e n ty1' env_ty') zonkTidyHsCtxt env (PatSigErrCtxt sig_ty res_ty) = do (env', sig_ty') <- zonkTidyTcType env sig_ty - (env', res_ty') <- - case res_ty of - Check ty -> zonkTidyTcType env' ty - Infer (IR {ir_ref = ref}) -> do -- inlining readExpTyp_maybe to avoid module dep loops - mb_ty <- liftIO $ readIORef ref - case mb_ty of - Nothing -> error "zonkTidyHsCtxt PatSigErrCtxt" - Just ty -> zonkTidyTcType env' ty - return (env', PatSigErrCtxt sig_ty' (Check res_ty')) + (env', res_ty') <- zonkExpType env' res_ty + return (env', PatSigErrCtxt sig_ty' res_ty') zonkTidyHsCtxt env p = return (env, p) + +zonkExpType :: TidyEnv -> ExpType -> ZonkM (TidyEnv, ExpType) +-- Zonk Infer{} to Check. The hole should have been filled in by now +zonkExpType env (Check ty) + = do { (env', ty') <- zonkTidyTcType env ty + ; return (env', Check ty') } +zonkExpType env (Infer ir@(IR { ir_ref = ref })) + = do { -- inlining readExpTyp_maybe to avoid module dep loops + ; mb_ty <- liftIO $ readIORef ref + ; case mb_ty of + Nothing -> pprPanic "zonkTidyHsCtxt PatSigErrCtxt" (ppr ir) + Just ty -> do { (env', ty') <- zonkTidyTcType env ty + ; return (env', Check ty') } } + ===================================== libraries/base/changelog.md ===================================== @@ -28,6 +28,7 @@ * Hide implementation details when throwing exceptions in throw and throwSTM. ([CLC proposal #387](https://github.com/haskell/core-libraries-committee/issues/387)) * Change `hIsReadable` and `hIsWritable` such that they always throw a respective exception when encountering a closed or semi-closed handle, not just in the case of a file handle. ([CLC proposal #371](github.com/haskell/core-libraries-committee/issues/371)) * Annotate `onException` continuation with `WhileHandling`. ([CLC Proposal #397](https://github.com/haskell/core-libraries-committee/issues/397)) + * Improve error message for `Data.Char.chr`. ([CLC Proposal #384](https://github.com/haskell/core-libraries-committee/issues/384)) ## 4.22.0.0 *TBA* * Shipped with GHC 9.14.1 ===================================== libraries/base/tests/enum01.stdout ===================================== @@ -81,7 +81,7 @@ Testing Enum Char: pred (maxBound::Char) = '\1114110' pred (minBound::Char) = error "Prelude.Enum.Char.pred: bad argument" (map (toEnum::Int->Char) [123,ord (minBound::Char), ord(maxBound::Char)]) = "{\NUL\1114111" - (toEnum::Int->Char) (minBound::Int) = error "Prelude.chr: bad argument: (-2147483648)" + (toEnum::Int->Char) (minBound::Int) = error "Data.Char.chr: argument outside Unicode range: 0..1114111: (-2147483648)" (map fromEnum ['X',minBound,maxBound]) = [88,0,1114111] (take 7 ['\NUL' .. ]) = "\NUL\SOH\STX\ETX\EOT\ENQ\ACK" (take 7 ['\250' .. ]) = "\250\251\252\253\254\255\256" ===================================== libraries/base/tests/enum01.stdout-alpha-dec-osf3 ===================================== @@ -65,7 +65,7 @@ Testing Enum Char: pred (maxBound::Char) = '\1114110' pred (minBound::Char) = error "Prelude.Enum.Char.pred: bad argument" (map (toEnum::Int->Char) [123,ord (minBound::Char), ord(maxBound::Char)]) = "{\NUL\1114111" - (toEnum::Int->Char) (minBound::Int) = error "Prelude.chr: bad argument" + (toEnum::Int->Char) (minBound::Int) = error "Data.Char.chr: argument outside Unicode range: 0..1114111:" (map fromEnum ['X',minBound,maxBound]) = [88,0,1114111] (take 7 ['\NUL' .. ]) = "\NUL\SOH\STX\ETX\EOT\ENQ\ACK" (take 7 ['\250' .. ]) = "\250\251\252\253\254\255\256" ===================================== libraries/base/tests/enum01.stdout-ws-64 ===================================== @@ -81,7 +81,7 @@ Testing Enum Char: pred (maxBound::Char) = '\1114110' pred (minBound::Char) = error "Prelude.Enum.Char.pred: bad argument" (map (toEnum::Int->Char) [123,ord (minBound::Char), ord(maxBound::Char)]) = "{\NUL\1114111" - (toEnum::Int->Char) (minBound::Int) = error "Prelude.chr: bad argument: (-9223372036854775808)" + (toEnum::Int->Char) (minBound::Int) = error "Data.Char.chr: argument outside Unicode range: 0..1114111: (-9223372036854775808)" (map fromEnum ['X',minBound,maxBound]) = [88,0,1114111] (take 7 ['\NUL' .. ]) = "\NUL\SOH\STX\ETX\EOT\ENQ\ACK" (take 7 ['\250' .. ]) = "\250\251\252\253\254\255\256" ===================================== libraries/ghc-internal/src/GHC/Internal/Char.hs ===================================== @@ -12,7 +12,7 @@ module GHC.Internal.Char import GHC.Internal.Classes (eqChar, neChar) import GHC.Internal.Base (otherwise, (++)) -import GHC.Internal.Err (errorWithoutStackTrace) +import GHC.Internal.Err (error) import GHC.Internal.Show import GHC.Internal.Prim (chr#, int2Word#, leWord#, Int#, Char#) import GHC.Internal.Types (Char(..), Int(..), isTrue#) @@ -29,4 +29,7 @@ safe_chr# i# {-# NOINLINE chr_error #-} chr_error :: Int# -> Char# -chr_error i# = errorWithoutStackTrace ("Prelude.chr: bad argument: " ++ showSignedInt (I# 9#) (I# i#) "") +chr_error i# = error ("Data.Char.chr: argument outside Unicode range: 0..1114111: " ++ showSignedInt (I# 9#) (I# i#) "") +-- It's not really "Data.Char", but we assume that +-- the majority of users will import it from "base:Data.Char" +-- and not from "ghc-internal:GHC.Internal.Char". View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/eb2d16cb2e3c13178ad709a6bd90b4f... -- View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/eb2d16cb2e3c13178ad709a6bd90b4f... You're receiving this email because of your account on gitlab.haskell.org.
participants (1)
-
Marge Bot (@marge-bot)