[Git][ghc/ghc][master] Add explanations for unsolved Typeable constraints
Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC Commits: c23e1acb by Mrjtjmn at 2026-07-18T17:52:45-04:00 Add explanations for unsolved Typeable constraints This commit adds explanations for unsolved 'Typeable' constraints. GHC will now provide additional explanations for an unsolved constraint of the form 'Typeable ty', explain why GHC did not solve Typeable constraint. e.g.: - 'ty' is a polymorphic type (e.g. forall a. a -> a) - 'ty' is a qualified type (e.g. Eq Int => Int) - 'ty' is an unboxed sum type - 'ty' is an unreduced type family application - 'ty' whose kind is not typeable Fixes #26532 - - - - - 11 changed files: - + changelog.d/T26532 - compiler/GHC/Tc/Errors.hs - compiler/GHC/Tc/Errors/Ppr.hs - compiler/GHC/Tc/Errors/Types.hs - compiler/GHC/Tc/Instance/Typeable.hs - testsuite/tests/typecheck/should_fail/T15067.stderr - + testsuite/tests/typecheck/should_fail/T26532.hs - + testsuite/tests/typecheck/should_fail/T26532.stderr - testsuite/tests/typecheck/should_fail/T9858b.stderr - testsuite/tests/typecheck/should_fail/TcStaticPointersFail02.stderr - testsuite/tests/typecheck/should_fail/all.T Changes: ===================================== changelog.d/T26532 ===================================== @@ -0,0 +1,8 @@ +section: compiler +issues: #26532 +mrs: !16351 +synopsis: + Add explanations for unsolved Typeable constraints +description: + GHC now provides additional explanations for an unsolved constraint of the + form ``Typeable ty``, explain why GHC did not solve ``Typeable`` constraint. ===================================== compiler/GHC/Tc/Errors.hs ===================================== @@ -12,7 +12,7 @@ module GHC.Tc.Errors( import GHC.Prelude -import GHC.Builtin.Names (hasFieldClassName) +import GHC.Builtin.Names (hasFieldClassName, typeableClassName) import GHC.Driver.Env (hsc_units) import GHC.Driver.DynFlags @@ -21,6 +21,7 @@ import GHC.Driver.Config.Diagnostic import GHC.Rename.Unbound +import GHC.Tc.Instance.Typeable (kindIsTypeable) import GHC.Tc.Types import GHC.Tc.Utils.Monad import GHC.Tc.Errors.Types @@ -2565,9 +2566,52 @@ getNoBuiltinInstMsg item = do { rdr_env <- getGlobalRdrEnv ; fam_envs <- tcGetFamInstEnvs ; mbNoHasFieldMsg <- hasFieldInfo_maybe rdr_env fam_envs item - ; return $ fmap NoBuiltinHasFieldMsg mbNoHasFieldMsg + ; mbNoTypeableMsg <- typeableInfo_maybe item + ; return $ case (mbNoHasFieldMsg, mbNoTypeableMsg) of + (Just hasFieldMsg, _) -> Just $ NoBuiltinHasFieldMsg hasFieldMsg + (_, Just typeableMsg) -> Just $ NoBuiltinTypeableMsg typeableMsg + _ -> Nothing } +-- | Try to produce an explanatory message for why GHC was not able to use +-- a built-in instance to solve a 'Typeable' constraint. +typeableInfo_maybe :: ErrorItem -> TcM (Maybe TypeableMsg) +typeableInfo_maybe item + | Just ty <- typeable_maybe (errorItemPred item) + = if -- Polymorphic types like (forall a. a -> a) are not typeable + -- see Note [No Typeable for polytypes or qualified types] in GHC.Tc.Instance.Class + | isForAllTy ty -> return $ Just $ NoTypeableForPolytype ty + + -- Qualified types like (Num a => blah) are not typeable + | Just (af,_mult_,_arg,_ret) <- splitFunTy_maybe ty + , not $ isVisibleFunArg af + -> return $ Just $ NoTypeableForQualifiedType ty + + -- Unboxed sum types like (# Int, Int #) are not typeable + | Just (tc, _tys) <- splitTyConApp_maybe ty + , isUnboxedSumTyCon tc -> return $ Just $ NoTypeableForUnboxedSumType ty + + -- Unreduced type family applications are not typeable + | Just (tc, _tys) <- splitTyConApp_maybe ty + , isTypeFamilyTyCon tc -> return $ Just $ NoTypeableForUnreducedTypeFamilyApplication ty + + -- TyCons whose kind is non-typeable, are not typeable + | Just (tc, _tys) <- splitTyConApp_maybe ty + , not (kindIsTypeable (tyConKind tc)) + -> return $ Just $ NoTypeableForTyConWithNonTypeableKind ty (tyConKind tc) + + | otherwise -> return Nothing + | otherwise = return Nothing + +-- | Is this constraint definitely a 'Typeable' constraint? +typeable_maybe :: PredType -> Maybe Type +typeable_maybe pred = + case classifyPredType pred of + ClassPred cls tys + | className cls == typeableClassName, [_k, ty] <- tys -> Just ty + _ -> Nothing + + {- Note [Error messages for unsolved HasField constraints] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The HasField type-class has special instance solving logic, implemented in @@ -2781,7 +2825,7 @@ hasFieldInfo_maybe rdr_env fam_inst_envs item -> TcM (Maybe (Either (PatSyn, SimilarName) (TyCon, SimilarName))) with_parent n = fmap (bimap (,n) (,n)) <$> get_parent n --- | Is this constraint definitely 'HasField'? +-- | Is this constraint definitely a 'HasField' constraint? hasField_maybe :: PredType -> Maybe (Type, Type, Type) hasField_maybe pred = case classifyPredType pred of ===================================== compiler/GHC/Tc/Errors/Ppr.hs ===================================== @@ -4314,15 +4314,6 @@ pprTcSolverReportMsg ctxt | any isFunTy (filterOutInvisibleTypes (classTyCon clas) tys) = text "(maybe you haven't applied a function to enough arguments?)" - -- Clarify the mysterious "No instance for (Typeable T) - | className clas == typeableClassName - , [_,ty] <- tys -- Look for (Typeable (k->*) (T k)) - , Just (tc,_) <- tcSplitTyConApp_maybe ty - , not (isTypeFamilyTyCon tc) - = hang (text "GHC can't yet do polykinded") - 2 (text "Typeable" <+> - parens (ppr ty <+> dcolon <+> ppr (typeKind ty))) - | otherwise = empty @@ -5200,6 +5191,7 @@ pprCoercibleMsg (OutOfScopeNewtypeConstructor dc import_suggs) = pprNoBuiltinInstanceMsg :: NoBuiltinInstanceMsg -> SDoc pprNoBuiltinInstanceMsg = \case NoBuiltinHasFieldMsg msg -> pprHasFieldMsg msg + NoBuiltinTypeableMsg msg -> pprTypeableMsg msg pprHasFieldMsg :: HasFieldMsg -> SDoc pprHasFieldMsg = \case @@ -5278,6 +5270,28 @@ pprHasFieldPatSynMsg fld pat_syns = in packHText occ == field_label fld +pprTypeableMsg :: TypeableMsg -> SDoc +pprTypeableMsg = \case + NoTypeableForPolytype ty -> + ppr_is ty "a polymorphic type" + NoTypeableForQualifiedType ty -> + ppr_is ty "a qualified type" + NoTypeableForUnboxedSumType ty -> + ppr_is ty "an unboxed sum type" + NoTypeableForUnreducedTypeFamilyApplication ty -> + ppr_is ty "an unreduced type family application" + NoTypeableForTyConWithNonTypeableKind ty k -> + vcat + [ text "NB:" <+> "The kind of" <+> quotes (ppr ty) + , nest 2 (quotes (ppr k)) <+> "contains foralls," + , "for which the built-in" + <+> quotes (text "Typeable") <+> text "solver cannot produce evidence." ] + where + ppr_is ty reason = + text "NB:" <+> quotes (ppr ty) <+> text "is" <+> text reason + $$ "for which the built-in" + <+> quotes (text "Typeable") <+> text "solver cannot produce evidence." + pprWhenMatching :: SolverReportErrCtxt -> WhenMatching -> SDoc pprWhenMatching ctxt (WhenMatching cty1 cty2 sub_o mb_sub_t_or_k) = sdocOption sdocPrintExplicitCoercions $ \printExplicitCoercions -> @@ -5516,6 +5530,7 @@ tcSolverReportMsgHints ctxt = \case noBuiltinInstanceHints :: NoBuiltinInstanceMsg -> [GhcHint] noBuiltinInstanceHints = \case NoBuiltinHasFieldMsg noHasFieldMsg -> hasFieldMsgHints noHasFieldMsg + NoBuiltinTypeableMsg _ -> noHints hasFieldMsgHints :: HasFieldMsg -> [GhcHint] hasFieldMsgHints = \case @@ -7998,4 +8013,3 @@ pprHsCtxt = \case ppr_stmt (TransStmt { trS_by = by, trS_using = using , trS_form = form }) = pprTransStmt by using form ppr_stmt stmt = pprStmt stmt - ===================================== compiler/GHC/Tc/Errors/Types.hs ===================================== @@ -78,6 +78,7 @@ module GHC.Tc.Errors.Types ( , CoercibleMsg(..) , NoBuiltinInstanceMsg(..) , HasFieldMsg(..) + , TypeableMsg(..) , TooFancyField(..) , PotentialInstances(..) , UnsupportedCallConvention(..) @@ -6034,9 +6035,9 @@ data CoercibleMsg -- a particular class. data NoBuiltinInstanceMsg = NoBuiltinHasFieldMsg HasFieldMsg + | NoBuiltinTypeableMsg TypeableMsg -- Other useful constructors might be: - -- NoBuiltinTypeableMsg -- explains polykinded Typeable restrictions -- NoBuiltinDataToTagMsg -- see conditions in Note [DataToTag overview] -- NoBuiltinWithDictMsg -- see Note [withDict] @@ -6066,6 +6067,20 @@ data HasFieldMsg -- | Using -XRebindableSyntax and a different 'HasField'. | CustomHasField TyCon -- ^ the custom HasField TyCon +-- | Explains why GHC wasn't able to provide a built-in 'Typeable' instance +-- for the given types. +data TypeableMsg + -- | Polymorphic types are not typeable. + = NoTypeableForPolytype Type + -- | Qualified types are not typeable. + | NoTypeableForQualifiedType Type + -- | Unboxed sum types are not typeable. + | NoTypeableForUnboxedSumType Type + -- | Unreduced Type Family Applications are not typeable. + | NoTypeableForUnreducedTypeFamilyApplication Type + -- | TyCons whose kind is not typeable are not typeable. + | NoTypeableForTyConWithNonTypeableKind Type Kind + -- | Why is a record field "too fancy" for GHC to be able to properly -- solve a 'HasField' constraint? data TooFancyField ===================================== compiler/GHC/Tc/Instance/Typeable.hs ===================================== @@ -7,7 +7,12 @@ {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE TypeFamilies #-} -module GHC.Tc.Instance.Typeable(mkTypeableBinds, tyConIsTypeable) where +module GHC.Tc.Instance.Typeable ( + mkTypeableBinds + , tyConIsTypeable + , kindIsTypeable + ) +where import GHC.Prelude import GHC.Platform ===================================== testsuite/tests/typecheck/should_fail/T15067.stderr ===================================== @@ -1,13 +1,7 @@ T15067.hs:9:14: error: [GHC-39999] • No instance for ‘Typeable (# | #)’ arising from a use of ‘typeRep’ - GHC can't yet do polykinded - Typeable ((# | #) :: * - -> * - -> TYPE - (GHC.Internal.Types.SumRep - [GHC.Internal.Types.LiftedRep, - GHC.Internal.Types.LiftedRep])) + NB: ‘(# | #)’ is an unboxed sum type + for which the built-in ‘Typeable’ solver cannot produce evidence. • In the expression: typeRep In an equation for ‘floopadoop’: floopadoop = typeRep - ===================================== testsuite/tests/typecheck/should_fail/T26532.hs ===================================== @@ -0,0 +1,35 @@ +{-# LANGUAGE ImpredicativeTypes #-} +{-# LANGUAGE UnboxedSums #-} +{-# LANGUAGE TypeFamilies #-} + +module T26532 where + +import Data.Kind +import Type.Reflection + +test1 :: TypeRep (forall a. a -> a) +test1 = typeRep + +test2 :: TypeRep (Eq Int => Int) +test2 = typeRep + +test3 :: TypeRep (((),()) => Int) +test3 = typeRep + +test4 :: TypeRep (# Int | Bool #) +test4 = typeRep + +type F :: Type -> Type +type family F a where {} + +test5 :: TypeRep (F Int) +test5 = typeRep + +type PolyDF :: forall k. Type -> k +data family PolyDF a + +type ProxyPolyDF :: (forall k. Type -> k) -> Type +data ProxyPolyDF f = MkProxy + +test6 :: TypeRep (ProxyPolyDF PolyDF) +test6 = typeRep ===================================== testsuite/tests/typecheck/should_fail/T26532.stderr ===================================== @@ -0,0 +1,50 @@ +T26532.hs:11:9: error: [GHC-39999] + • No instance for ‘Typeable (forall a. a -> a)’ + arising from a use of ‘typeRep’ + NB: ‘forall a. a -> a’ is a polymorphic type + for which the built-in ‘Typeable’ solver cannot produce evidence. + • In the expression: typeRep + In an equation for ‘test1’: test1 = typeRep + +T26532.hs:14:9: error: [GHC-39999] + • No instance for ‘Typeable (Eq Int => Int)’ + arising from a use of ‘typeRep’ + NB: ‘Eq Int => Int’ is a qualified type + for which the built-in ‘Typeable’ solver cannot produce evidence. + • In the expression: typeRep + In an equation for ‘test2’: test2 = typeRep + +T26532.hs:17:9: error: [GHC-39999] + • No instance for ‘Typeable + ((() :: Constraint, () :: Constraint) => Int)’ + arising from a use of ‘typeRep’ + NB: ‘(() :: Constraint, () :: Constraint) => + Int’ is a qualified type + for which the built-in ‘Typeable’ solver cannot produce evidence. + • In the expression: typeRep + In an equation for ‘test3’: test3 = typeRep + +T26532.hs:20:9: error: [GHC-39999] + • No instance for ‘Typeable (# | #)’ + arising from a use of ‘typeRep’ + NB: ‘(# | #)’ is an unboxed sum type + for which the built-in ‘Typeable’ solver cannot produce evidence. + • In the expression: typeRep + In an equation for ‘test4’: test4 = typeRep + +T26532.hs:26:9: error: [GHC-39999] + • No instance for ‘Typeable (F Int)’ + arising from a use of ‘typeRep’ + NB: ‘F Int’ is an unreduced type family application + for which the built-in ‘Typeable’ solver cannot produce evidence. + • In the expression: typeRep + In an equation for ‘test5’: test5 = typeRep + +T26532.hs:35:9: error: [GHC-39999] + • No instance for ‘Typeable ProxyPolyDF’ + arising from a use of ‘typeRep’ + NB: The kind of ‘ProxyPolyDF’ + ‘(forall k. * -> k) -> *’ contains foralls, + for which the built-in ‘Typeable’ solver cannot produce evidence. + • In the expression: typeRep + In an equation for ‘test6’: test6 = typeRep ===================================== testsuite/tests/typecheck/should_fail/T9858b.stderr ===================================== @@ -2,7 +2,8 @@ T9858b.hs:7:8: error: [GHC-39999] • No instance for ‘Typeable (Eq Int => Int)’ arising from a use of ‘typeRep’ - (maybe you haven't applied a function to enough arguments?) + NB: ‘Eq Int => Int’ is a qualified type + for which the built-in ‘Typeable’ solver cannot produce evidence. • In the expression: typeRep (Proxy :: Proxy (Eq Int => Int)) In an equation for ‘test’: test = typeRep (Proxy :: Proxy (Eq Int => Int)) ===================================== testsuite/tests/typecheck/should_fail/TcStaticPointersFail02.stderr ===================================== @@ -11,6 +11,7 @@ TcStaticPointersFail02.hs:12:6: error: [GHC-39999] • No instance for ‘ghc-internal-0.1.0.0:GHC.Internal.Data.Typeable.Internal.Typeable (Monad m => a -> m a)’ arising from a static form - (maybe you haven't applied a function to enough arguments?) + NB: ‘Monad m => a -> m a’ is a qualified type + for which the built-in ‘Typeable’ solver cannot produce evidence. • In the expression: static return In an equation for ‘f2’: f2 = static return ===================================== testsuite/tests/typecheck/should_fail/all.T ===================================== @@ -761,3 +761,4 @@ test('T26823', normal, compile_fail, ['']) test('T26861', normal, compile_fail, ['']) test('T26862', normal, compile_fail, ['']) test('T27210', normal, compile_fail, ['']) +test('T26532', normal, compile_fail, ['']) View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/c23e1acb6f748296a421340e2df564d3... -- View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/c23e1acb6f748296a421340e2df564d3... You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
participants (1)
-
Marge Bot (@marge-bot)