diff options
author | Torsten Schmits <git@tryp.io> | 2023-04-26 21:56:16 +0200 |
---|---|---|
committer | Torsten Schmits <haskell-gitlab@schmits.me> | 2023-05-05 08:43:02 +0000 |
commit | 275836d211d119cb8786a91ca3108a4daa693cb2 (patch) | |
tree | 9dfc96c90e69cd97ba2e674407be8f30bf5ac26c /compiler | |
parent | e8b72ff6e4aee1f889a9168df57bb1b00168fd21 (diff) | |
download | haskell-275836d211d119cb8786a91ca3108a4daa693cb2.tar.gz |
Add structured error messages for GHC.Rename.Utils
Tracking ticket: #20115
MR: !10350
This converts uses of `mkTcRnUnknownMessage` to newly added constructors
of `TcRnMessage`.
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/GHC/Rename/Bind.hs | 11 | ||||
-rw-r--r-- | compiler/GHC/Rename/Expr.hs | 3 | ||||
-rw-r--r-- | compiler/GHC/Rename/HsType.hs | 6 | ||||
-rw-r--r-- | compiler/GHC/Rename/Module.hs | 29 | ||||
-rw-r--r-- | compiler/GHC/Rename/Utils.hs | 213 | ||||
-rw-r--r-- | compiler/GHC/Tc/Errors/Ppr.hs | 173 | ||||
-rw-r--r-- | compiler/GHC/Tc/Errors/Types.hs | 155 | ||||
-rw-r--r-- | compiler/GHC/Tc/Module.hs | 2 | ||||
-rw-r--r-- | compiler/GHC/Types/Error/Codes.hs | 12 | ||||
-rw-r--r-- | compiler/GHC/Types/Hint.hs | 5 | ||||
-rw-r--r-- | compiler/GHC/Types/Hint/Ppr.hs | 2 |
11 files changed, 421 insertions, 190 deletions
diff --git a/compiler/GHC/Rename/Bind.hs b/compiler/GHC/Rename/Bind.hs index 661c271fb9..503e56bd57 100644 --- a/compiler/GHC/Rename/Bind.hs +++ b/compiler/GHC/Rename/Bind.hs @@ -42,7 +42,7 @@ import GHC.Rename.Names import GHC.Rename.Env import GHC.Rename.Fixity import GHC.Rename.Utils ( mapFvRn - , checkDupRdrNames, checkDupRdrNamesN + , checkDupRdrNames , warnUnusedLocalBinds , warnForallIdentifier , checkUnusedRecordWildcard @@ -719,7 +719,7 @@ rnPatSynBind sig_fn bind@(PSB { psb_id = L l name -- from the left-hand side case details of PrefixCon _ vars -> - do { checkDupRdrNamesN vars + do { checkDupRdrNames vars ; names <- mapM lookupPatSynBndr vars ; return ( (pat', PrefixCon noTypeArgs names) , mkFVs (map unLoc names)) } @@ -877,7 +877,7 @@ rnMethodBinds :: Bool -- True <=> is a class declaration -- * the default method bindings in a class decl -- * the method bindings in an instance decl rnMethodBinds is_cls_decl cls ktv_names binds sigs - = do { checkDupRdrNamesN (collectMethodBinders binds) + = do { checkDupRdrNames (collectMethodBinders binds) -- Check that the same method is not given twice in the -- same instance decl instance C T where -- f x = ... @@ -1038,18 +1038,17 @@ renameSig ctxt sig@(ClassOpSig _ is_deflt vs ty) <+> quotes (ppr v1)) renameSig _ (SpecInstSig (_, src) ty) - = do { checkInferredVars doc inf_msg ty + = do { checkInferredVars doc ty ; (new_ty, fvs) <- rnHsSigType doc TypeLevel ty -- Check if there are any nested `forall`s or contexts, which are -- illegal in the type of an instance declaration (see -- Note [No nested foralls or contexts in instance types] in -- GHC.Hs.Type). - ; addNoNestedForallsContextsErr doc (text "SPECIALISE instance type") + ; addNoNestedForallsContextsErr doc NFC_Specialize (getLHsInstDeclHead new_ty) ; return (SpecInstSig (noAnn, src) new_ty,fvs) } where doc = SpecInstSigCtx - inf_msg = Just (text "Inferred type variables are not allowed") -- {-# SPECIALISE #-} pragmas can refer to imported Ids -- so, in the top-level case (when mb_names is Nothing) diff --git a/compiler/GHC/Rename/Expr.hs b/compiler/GHC/Rename/Expr.hs index b68ff6a492..2afc0f0fa6 100644 --- a/compiler/GHC/Rename/Expr.hs +++ b/compiler/GHC/Rename/Expr.hs @@ -56,6 +56,7 @@ import GHC.Driver.Session import GHC.Builtin.Names import GHC.Builtin.Types ( nilDataConName ) +import GHC.Types.Basic (TypeOrKind (TypeLevel)) import GHC.Types.FieldLabel import GHC.Types.Fixity import GHC.Types.Id.Make @@ -324,7 +325,7 @@ rnExpr (HsApp x fun arg) rnExpr (HsAppType _ fun at arg) = do { type_app <- xoptM LangExt.TypeApplications - ; unless type_app $ addErr $ typeAppErr "type" $ hswc_body arg + ; unless type_app $ addErr $ typeAppErr TypeLevel $ hswc_body arg ; (fun',fvFun) <- rnLExpr fun ; (arg',fvArg) <- rnHsWcType HsTypeCtx arg ; return (HsAppType NoExtField fun' at arg', fvFun `plusFV` fvArg) } diff --git a/compiler/GHC/Rename/HsType.hs b/compiler/GHC/Rename/HsType.hs index 500a6f8407..049bbe2c22 100644 --- a/compiler/GHC/Rename/HsType.hs +++ b/compiler/GHC/Rename/HsType.hs @@ -49,7 +49,7 @@ import GHC.Hs import GHC.Rename.Env import GHC.Rename.Doc import GHC.Rename.Utils ( mapFvRn, bindLocalNamesFV - , typeAppErr, newLocalBndrRn, checkDupRdrNamesN + , typeAppErr, newLocalBndrRn, checkDupRdrNames , checkShadowedRdrNames, warnForallIdentifier ) import GHC.Rename.Fixity ( lookupFieldFixityRn, lookupFixityRn , lookupTyFixityRn ) @@ -686,7 +686,7 @@ rnHsTyKi env (HsAppTy _ ty1 ty2) rnHsTyKi env (HsAppKindTy _ ty at k) = do { kind_app <- xoptM LangExt.TypeApplications - ; unless kind_app (addErr (typeAppErr "kind" k)) + ; unless kind_app (addErr (typeAppErr KindLevel k)) ; (ty', fvs1) <- rnLHsTyKi env ty ; (k', fvs2) <- rnLHsTyKi (env {rtke_level = KindLevel }) k ; return (HsAppKindTy noExtField ty' at k', fvs1 `plusFV` fvs2) } @@ -1184,7 +1184,7 @@ bindLHsTyVarBndrs :: (OutputableBndrFlag flag 'Renamed) -> RnM (b, FreeVars) bindLHsTyVarBndrs doc wuf mb_assoc tv_bndrs thing_inside = do { when (isNothing mb_assoc) (checkShadowedRdrNames tv_names_w_loc) - ; checkDupRdrNamesN tv_names_w_loc + ; checkDupRdrNames tv_names_w_loc ; go tv_bndrs thing_inside } where tv_names_w_loc = map hsLTyVarLocName tv_bndrs diff --git a/compiler/GHC/Rename/Module.hs b/compiler/GHC/Rename/Module.hs index 1602b2b92d..e91749cf2d 100644 --- a/compiler/GHC/Rename/Module.hs +++ b/compiler/GHC/Rename/Module.hs @@ -30,7 +30,7 @@ import GHC.Rename.Bind import GHC.Rename.Doc import GHC.Rename.Env import GHC.Rename.Utils ( mapFvRn, bindLocalNames - , checkDupRdrNamesN, bindLocalNamesFV + , checkDupRdrNames, bindLocalNamesFV , checkShadowedRdrNames, warnUnusedTypePatterns , newLocalBndrsRn , noNestedForallsContextsErr @@ -605,7 +605,7 @@ rnClsInstDecl (ClsInstDecl { cid_poly_ty = inst_ty, cid_binds = mbinds , cid_sigs = uprags, cid_tyfam_insts = ats , cid_overlap_mode = oflag , cid_datafam_insts = adts }) - = do { checkInferredVars ctxt inf_err inst_ty + = do { checkInferredVars ctxt inst_ty ; (inst_ty', inst_fvs) <- rnHsSigType ctxt TypeLevel inst_ty ; let (ktv_names, _, head_ty') = splitLHsInstDeclTy inst_ty' -- Check if there are any nested `forall`s or contexts, which are @@ -613,7 +613,7 @@ rnClsInstDecl (ClsInstDecl { cid_poly_ty = inst_ty, cid_binds = mbinds -- Note [No nested foralls or contexts in instance types] in -- GHC.Hs.Type)... mb_nested_msg = noNestedForallsContextsErr - (text "Instance head") head_ty' + NFC_InstanceHead head_ty' -- ...then check if the instance head is actually headed by a -- class type constructor... eith_cls = case hsTyGetAppHead_maybe head_ty' of @@ -669,7 +669,6 @@ rnClsInstDecl (ClsInstDecl { cid_poly_ty = inst_ty, cid_binds = mbinds -- to remove the context). where ctxt = GenericCtx $ text "an instance declaration" - inf_err = Just (text "Inferred type variables are not allowed") -- The instance is malformed. We'd still like to make *some* progress -- (rather than failing outright), so we report an error and continue for @@ -1177,20 +1176,19 @@ rnSrcDerivDecl :: DerivDecl GhcPs -> RnM (DerivDecl GhcRn, FreeVars) rnSrcDerivDecl (DerivDecl _ ty mds overlap) = do { standalone_deriv_ok <- xoptM LangExt.StandaloneDeriving ; unless standalone_deriv_ok (addErr TcRnUnexpectedStandaloneDerivingDecl) - ; checkInferredVars ctxt inf_err nowc_ty + ; checkInferredVars ctxt nowc_ty ; (mds', ty', fvs) <- rnLDerivStrategy ctxt mds $ rnHsSigWcType ctxt ty -- Check if there are any nested `forall`s or contexts, which are -- illegal in the type of an instance declaration (see -- Note [No nested foralls or contexts in instance types] in -- GHC.Hs.Type). ; addNoNestedForallsContextsErr ctxt - (text "Standalone-derived instance head") + NFC_StandaloneDerivedInstanceHead (getLHsInstDeclHead $ dropWildCards ty') ; warnNoDerivStrat mds' loc ; return (DerivDecl noAnn ty' mds' overlap, fvs) } where ctxt = DerivDeclCtx - inf_err = Just (text "Inferred type variables are not allowed") loc = getLocA nowc_ty nowc_ty = dropWildCards ty @@ -1219,7 +1217,7 @@ rnHsRuleDecl (HsRule { rd_ext = (_, st) , rd_rhs = rhs }) = do { let rdr_names_w_loc = map (get_var . unLoc) tmvs ; mapM_ warnForallIdentifier rdr_names_w_loc - ; checkDupRdrNamesN rdr_names_w_loc + ; checkDupRdrNames rdr_names_w_loc ; checkShadowedRdrNames rdr_names_w_loc ; names <- newLocalBndrsRn rdr_names_w_loc ; let doc = RuleCtx (unLoc rule_name) @@ -1819,7 +1817,7 @@ rnTyClDecl (ClassDecl { tcdLayout = layout, ; let sig_rdr_names_w_locs = [op | L _ (ClassOpSig _ False ops _) <- sigs , op <- ops] - ; checkDupRdrNamesN sig_rdr_names_w_locs + ; checkDupRdrNames sig_rdr_names_w_locs -- Typechecker is responsible for checking that we only -- give default-method bindings for things in this class. -- The renamer *could* check this for class decls, but can't @@ -2191,14 +2189,13 @@ rnLHsDerivingClause doc rn_clause_pred :: LHsSigType GhcPs -> RnM (LHsSigType GhcRn, FreeVars) rn_clause_pred pred_ty = do - let inf_err = Just (text "Inferred type variables are not allowed") - checkInferredVars doc inf_err pred_ty + checkInferredVars doc pred_ty ret@(pred_ty', _) <- rnHsSigType doc TypeLevel pred_ty -- Check if there are any nested `forall`s, which are illegal in a -- `deriving` clause. -- See Note [No nested foralls or contexts in instance types] -- (Wrinkle: Derived instances) in GHC.Hs.Type. - addNoNestedForallsContextsErr doc (text "Derived class type") + addNoNestedForallsContextsErr doc NFC_DerivedClassType (getLHsInstDeclHead pred_ty') pure ret @@ -2233,7 +2230,7 @@ rnLDerivStrategy doc mds thing_inside AnyclassStrategy _ -> boring_case (AnyclassStrategy noExtField) NewtypeStrategy _ -> boring_case (NewtypeStrategy noExtField) ViaStrategy (XViaStrategyPs _ via_ty) -> - do checkInferredVars doc inf_err via_ty + do checkInferredVars doc via_ty (via_ty', fvs1) <- rnHsSigType doc TypeLevel via_ty let HsSig { sig_bndrs = via_outer_bndrs , sig_body = via_body } = unLoc via_ty' @@ -2243,12 +2240,10 @@ rnLDerivStrategy doc mds thing_inside -- See Note [No nested foralls or contexts in instance types] -- (Wrinkle: Derived instances) in GHC.Hs.Type. addNoNestedForallsContextsErr doc - (quotes (text "via") <+> text "type") via_body + NFC_ViaType via_body (thing, fvs2) <- bindLocalNamesFV via_tvs thing_inside pure (ViaStrategy via_ty', thing, fvs1 `plusFV` fvs2) - inf_err = Just (text "Inferred type variables are not allowed") - boring_case :: ds -> RnM (ds, a, FreeVars) boring_case ds = do (thing, fvs) <- thing_inside @@ -2501,7 +2496,7 @@ rnConDecl (ConDeclGADT { con_names = names -- Note [GADT abstract syntax] (Wrinkle: No nested foralls or contexts) -- in GHC.Hs.Type. ; addNoNestedForallsContextsErr ctxt - (text "GADT constructor type signature") new_res_ty + NFC_GadtConSig new_res_ty ; let all_fvs = fvs1 `plusFV` fvs2 `plusFV` fvs3 diff --git a/compiler/GHC/Rename/Utils.hs b/compiler/GHC/Rename/Utils.hs index a00d97dd0d..7b631edac0 100644 --- a/compiler/GHC/Rename/Utils.hs +++ b/compiler/GHC/Rename/Utils.hs @@ -9,7 +9,7 @@ This module contains miscellaneous functions related to renaming. -} module GHC.Rename.Utils ( - checkDupRdrNames, checkDupRdrNamesN, checkShadowedRdrNames, + checkDupRdrNames, checkShadowedRdrNames, checkDupNames, checkDupAndShadowedNames, dupNamesErr, checkTupSize, checkCTupSize, addFvRn, mapFvRn, mapMaybeFvRn, @@ -44,7 +44,6 @@ import GHC.Types.Name.Reader import GHC.Tc.Errors.Types -- import GHC.Tc.Utils.Env import GHC.Tc.Utils.Monad -import GHC.Types.Error import GHC.Types.Name import GHC.Types.Name.Set import GHC.Types.Name.Env @@ -53,19 +52,16 @@ import GHC.Types.SrcLoc as SrcLoc import GHC.Types.SourceFile import GHC.Types.SourceText ( SourceText(..), IntegralLit ) import GHC.Utils.Outputable -import GHC.Utils.Panic import GHC.Utils.Misc -import GHC.Types.Basic ( TopLevelFlag(..), Origin(Generated) ) +import GHC.Types.Basic ( TopLevelFlag(..), Origin(Generated), TypeOrKind ) import GHC.Data.List.SetOps ( removeDupsOn ) import GHC.Data.Maybe ( whenIsJust ) import GHC.Driver.Session import GHC.Data.FastString import Control.Monad -import Data.List (find, sortBy) import GHC.Settings.Constants ( mAX_TUPLE_SIZE, mAX_CTUPLE_SIZE ) import qualified Data.List.NonEmpty as NE import qualified GHC.LanguageExtensions as LangExt -import GHC.Data.Bag import qualified Data.List as List {- @@ -111,14 +107,7 @@ bindLocalNamesFV names enclosed_scope checkDupRdrNames :: [LocatedN RdrName] -> RnM () -- Check for duplicated names in a binding group checkDupRdrNames rdr_names_w_loc - = mapM_ (dupNamesErr getLocA) dups - where - (_, dups) = removeDupsOn unLoc rdr_names_w_loc - -checkDupRdrNamesN :: [LocatedN RdrName] -> RnM () --- Check for duplicated names in a binding group -checkDupRdrNamesN rdr_names_w_loc - = mapM_ (dupNamesErr getLocA) dups + = mapM_ (\ ns -> dupNamesErr (getLocA <$> ns) (unLoc <$> ns)) dups where (_, dups) = removeDupsOn unLoc rdr_names_w_loc @@ -129,7 +118,7 @@ checkDupNames names = check_dup_names (filterOut isSystemName names) check_dup_names :: [Name] -> RnM () check_dup_names names - = mapM_ (dupNamesErr nameSrcSpan) dups + = mapM_ (\ ns -> dupNamesErr (nameSrcSpan <$> ns) (getRdrName <$> ns)) dups where (_, dups) = removeDupsOn nameOccName names @@ -192,19 +181,15 @@ checkShadowedOccs (global_env,local_env) get_loc_occ ns -- @{a}@, but @forall a. [a] -> [a]@ would be accepted. -- See @Note [Unobservably inferred type variables]@. checkInferredVars :: HsDocContext - -> Maybe SDoc - -- ^ The error msg if the signature is not allowed to contain - -- manually written inferred variables. -> LHsSigType GhcPs -> RnM () -checkInferredVars _ Nothing _ = return () -checkInferredVars ctxt (Just msg) ty = +checkInferredVars ctxt ty = let bndrs = sig_ty_bndrs ty - in case find ((==) InferredSpec . hsTyVarBndrFlag) bndrs of - Nothing -> return () - Just _ -> addErr $ + in case filter ((==) InferredSpec . hsTyVarBndrFlag) bndrs of + [] -> return () + iv : ivs -> addErr $ TcRnWithHsDocContext ctxt $ - mkTcRnUnknownMessage $ mkPlainError noHints msg + TcRnIllegalInferredTyVars (iv NE.:| ivs) where sig_ty_bndrs :: LHsSigType GhcPs -> [HsTyVarBndr Specificity GhcPs] sig_ty_bndrs (L _ (HsSig{sig_bndrs = outer_bndrs})) @@ -287,7 +272,9 @@ Note [No nested foralls or contexts in instance types] in GHC.Hs.Type). -- "GHC.Rename.Module" and 'renameSig' in "GHC.Rename.Bind"). -- See @Note [No nested foralls or contexts in instance types]@ in -- "GHC.Hs.Type". -noNestedForallsContextsErr :: SDoc -> LHsType GhcRn -> Maybe (SrcSpan, TcRnMessage) +noNestedForallsContextsErr :: NestedForallsContextsIn + -> LHsType GhcRn + -> Maybe (SrcSpan, TcRnMessage) noNestedForallsContextsErr what lty = case ignoreParens lty of L l (HsForAllTy { hst_tele = tele }) @@ -304,12 +291,13 @@ noNestedForallsContextsErr what lty = _ -> Nothing where nested_foralls_contexts_err = - mkTcRnUnknownMessage $ mkPlainError noHints $ - what <+> text "cannot contain nested" - <+> quotes forAllLit <> text "s or contexts" + TcRnNestedForallsContexts what -- | A common way to invoke 'noNestedForallsContextsErr'. -addNoNestedForallsContextsErr :: HsDocContext -> SDoc -> LHsType GhcRn -> RnM () +addNoNestedForallsContextsErr :: HsDocContext + -> NestedForallsContextsIn + -> LHsType GhcRn + -> RnM () addNoNestedForallsContextsErr ctxt what lty = whenIsJust (noNestedForallsContextsErr what lty) $ \(l, err_msg) -> addErrAt l $ TcRnWithHsDocContext ctxt err_msg @@ -395,13 +383,7 @@ checkUnusedRecordWildcard loc fvs (Just dotdot_names) = -- -- The `..` here doesn't bind any variables as `x` is already bound. warnRedundantRecordWildcard :: RnM () -warnRedundantRecordWildcard = - whenWOptM Opt_WarnRedundantRecordWildcards $ - let msg = mkTcRnUnknownMessage $ - mkPlainDiagnostic (WarningWithFlag Opt_WarnRedundantRecordWildcards) - noHints - redundantWildcardWarning - in addDiagnostic msg +warnRedundantRecordWildcard = addDiagnostic TcRnRedundantRecordWildcard -- | Produce a warning when no variables bound by a `..` pattern are used. @@ -418,21 +400,19 @@ warnUnusedRecordWildcard :: [Name] -> FreeVars -> RnM () warnUnusedRecordWildcard ns used_names = do let used = filter (`elemNameSet` used_names) ns traceRn "warnUnused" (ppr ns $$ ppr used_names $$ ppr used) - warnIf (null used) - unusedRecordWildcardWarning + warnIf (null used) (TcRnUnusedRecordWildcard ns) warnUnusedLocalBinds, warnUnusedMatches, warnUnusedTypePatterns :: [Name] -> FreeVars -> RnM () -warnUnusedLocalBinds = check_unused Opt_WarnUnusedLocalBinds -warnUnusedMatches = check_unused Opt_WarnUnusedMatches -warnUnusedTypePatterns = check_unused Opt_WarnUnusedTypePatterns +warnUnusedLocalBinds = check_unused UnusedNameLocalBind +warnUnusedMatches = check_unused UnusedNameMatch +warnUnusedTypePatterns = check_unused UnusedNameTypePattern -check_unused :: WarningFlag -> [Name] -> FreeVars -> RnM () -check_unused flag bound_names used_names - = whenWOptM flag (warnUnused flag (filterOut (`elemNameSet` used_names) - bound_names)) +check_unused :: UnusedNameProv -> [Name] -> FreeVars -> RnM () +check_unused prov bound_names used_names + = warnUnused prov (filterOut (`elemNameSet` used_names) bound_names) warnForallIdentifier :: LocatedN RdrName -> RnM () warnForallIdentifier (L l rdr_name@(Unqual occ)) @@ -447,33 +427,30 @@ warnUnusedGREs :: [GlobalRdrElt] -> RnM () warnUnusedGREs gres = mapM_ warnUnusedGRE gres -- NB the Names must not be the names of record fields! -warnUnused :: WarningFlag -> [Name] -> RnM () -warnUnused flag names = - mapM_ (\ nm -> warnUnused1 flag nm (nameOccName nm)) names +warnUnused :: UnusedNameProv -> [Name] -> RnM () +warnUnused prov names = + mapM_ (\ nm -> warnUnused1 prov nm (nameOccName nm)) names -warnUnused1 :: WarningFlag -> Name -> OccName -> RnM () -warnUnused1 flag child child_occ +warnUnused1 :: UnusedNameProv -> Name -> OccName -> RnM () +warnUnused1 prov child child_occ = when (reportable child child_occ) $ - addUnusedWarning flag - child_occ (nameSrcSpan child) - (text $ "Defined but not used" ++ opt_str) - where - opt_str = case flag of - Opt_WarnUnusedTypePatterns -> " on the right hand side" - _ -> "" + warn_unused_name prov (nameSrcSpan child) child_occ + +warn_unused_name :: UnusedNameProv -> SrcSpan -> OccName -> RnM () +warn_unused_name prov span child_occ = + addDiagnosticAt span (TcRnUnusedName child_occ prov) warnUnusedGRE :: GlobalRdrElt -> RnM () warnUnusedGRE gre@(GRE { gre_lcl = lcl, gre_imp = is }) - | lcl = warnUnused1 Opt_WarnUnusedTopBinds nm occ + | lcl = warnUnused1 UnusedNameTopDecl nm occ | otherwise = when (reportable nm occ) (mapM_ warn is) where occ = greOccName gre nm = greName gre - warn spec = addUnusedWarning Opt_WarnUnusedTopBinds occ span msg - where - span = importSpecLoc spec - pp_mod = quotes (ppr (importSpecModule spec)) - msg = text "Imported from" <+> pp_mod <+> text "but not used" + warn spec = + warn_unused_name (UnusedNameImported (importSpecModule spec)) span occ + where + span = importSpecLoc spec -- | Should we report the fact that this 'Name' is unused? The -- 'OccName' may differ from 'nameOccName' due to @@ -487,29 +464,6 @@ reportable child child_occ | otherwise = not (startsWithUnderscore child_occ) -addUnusedWarning :: WarningFlag -> OccName -> SrcSpan -> SDoc -> RnM () -addUnusedWarning flag occ span msg = do - let diag = mkTcRnUnknownMessage $ mkPlainDiagnostic (WarningWithFlag flag) noHints $ - sep [msg <> colon, - nest 2 $ pprNonVarNameSpace (occNameSpace occ) - <+> quotes (ppr occ)] - addDiagnosticAt span diag - -unusedRecordWildcardWarning :: TcRnMessage -unusedRecordWildcardWarning = - mkTcRnUnknownMessage $ mkPlainDiagnostic (WarningWithFlag Opt_WarnUnusedRecordWildcards) noHints $ - wildcardDoc $ text "No variables bound in the record wildcard match are used" - -redundantWildcardWarning :: SDoc -redundantWildcardWarning = - wildcardDoc $ text "Record wildcard does not bind any new variables" - -wildcardDoc :: SDoc -> SDoc -wildcardDoc herald = - herald - $$ nest 2 (text "Possible fix" <> colon <+> text "omit the" - <+> quotes (text "..")) - {- Note [Skipping ambiguity errors at use sites of local declarations] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -560,78 +514,23 @@ addNameClashErrRn rdr_name gres num_flds = length flds num_non_flds = length non_flds -mkNameClashErr :: Outputable a - => a -> NE.NonEmpty GlobalRdrElt -> TcRnMessage -mkNameClashErr rdr_name gres = - mkTcRnUnknownMessage $ mkPlainError noHints $ - (vcat [ text "Ambiguous occurrence" <+> quotes (ppr rdr_name) - , text "It could refer to" - , nest 3 (vcat (msg1 : msgs)) ]) - where - np1 NE.:| nps = gres - msg1 = text "either" <+> ppr_gre np1 - msgs = [text " or" <+> ppr_gre np | np <- nps] - ppr_gre gre = sep [ pp_gre_name gre <> comma - , pprNameProvenance gre] - - -- When printing the name, take care to qualify it in the same - -- way as the provenance reported by pprNameProvenance, namely - -- the head of 'gre_imp'. Otherwise we get confusing reports like - -- Ambiguous occurrence ‘null’ - -- It could refer to either ‘T15487a.null’, - -- imported from ‘Prelude’ at T15487.hs:1:8-13 - -- or ... - -- See #15487 - pp_gre_name gre - | isRecFldGRE gre - = text "the field" <+> quotes (ppr occ) <+> parent_info - | otherwise - = quotes (pp_qual <> dot <> ppr occ) - where - occ = greOccName gre - parent_info = case gre_par gre of - NoParent -> empty - ParentIs { par_is = par_name } -> text "of record" <+> quotes (ppr par_name) - pp_qual - | gre_lcl gre - = ppr (nameModule $ greName gre) - | Just imp <- headMaybe $ gre_imp gre - -- This 'imp' is the one that - -- pprNameProvenance chooses - , ImpDeclSpec { is_as = mod } <- is_decl imp - = ppr mod - | otherwise - = pprPanic "addNameClassErrRn" (ppr gre) - -- Invariant: either 'lcl' is True or 'iss' is non-empty - - -dupNamesErr :: Outputable n => (n -> SrcSpan) -> NE.NonEmpty n -> RnM () -dupNamesErr get_loc names - = addErrAt big_loc $ mkTcRnUnknownMessage $ mkPlainError noHints $ - vcat [text "Conflicting definitions for" <+> quotes (ppr (NE.head names)), - locations] +mkNameClashErr :: RdrName -> NE.NonEmpty GlobalRdrElt -> TcRnMessage +mkNameClashErr rdr_name gres = TcRnAmbiguousName rdr_name gres + +dupNamesErr :: NE.NonEmpty SrcSpan -> NE.NonEmpty RdrName -> RnM () +dupNamesErr locs names + = addErrAt big_loc (TcRnBindingNameConflict (NE.head names) locs) where - locs = map get_loc (NE.toList names) - big_loc = foldr1 combineSrcSpans locs - locations = text "Bound at:" <+> vcat (map ppr (sortBy SrcLoc.leftmost_smallest locs)) + big_loc = foldr1 combineSrcSpans locs badQualBndrErr :: RdrName -> TcRnMessage -badQualBndrErr rdr_name - = mkTcRnUnknownMessage $ mkPlainError noHints $ - text "Qualified name in binding position:" <+> ppr rdr_name +badQualBndrErr rdr_name = TcRnQualifiedBinder rdr_name -typeAppErr :: String -> LHsType GhcPs -> TcRnMessage -typeAppErr what (L _ k) - = mkTcRnUnknownMessage $ mkPlainError noHints $ - hang (text "Illegal visible" <+> text what <+> text "application" - <+> quotes (char '@' <> ppr k)) - 2 (text "Perhaps you intended to use TypeApplications") +typeAppErr :: TypeOrKind -> LHsType GhcPs -> TcRnMessage +typeAppErr what (L _ k) = TcRnTypeApplicationsDisabled what k badFieldConErr :: Name -> FieldLabelString -> TcRnMessage -badFieldConErr con field - = mkTcRnUnknownMessage $ mkPlainError noHints $ - hsep [text "Constructor" <+> quotes (ppr con), - text "does not have field", quotes (ppr field)] +badFieldConErr con field = TcRnInvalidRecordField con field -- | Ensure that a boxed or unboxed tuple has arity no larger than -- 'mAX_TUPLE_SIZE'. @@ -640,10 +539,7 @@ checkTupSize tup_size | tup_size <= mAX_TUPLE_SIZE = return () | otherwise - = addErr $ mkTcRnUnknownMessage $ mkPlainError noHints $ - sep [text "A" <+> int tup_size <> text "-tuple is too large for GHC", - nest 2 (parens (text "max size is" <+> int mAX_TUPLE_SIZE)), - nest 2 (text "Workaround: use nested tuples or define a data type")] + = addErr (TcRnTupleTooLarge tup_size) -- | Ensure that a constraint tuple has arity no larger than 'mAX_CTUPLE_SIZE'. checkCTupSize :: Int -> TcM () @@ -651,10 +547,7 @@ checkCTupSize tup_size | tup_size <= mAX_CTUPLE_SIZE = return () | otherwise - = addErr $ mkTcRnUnknownMessage $ mkPlainError noHints $ - hang (text "Constraint tuple arity too large:" <+> int tup_size - <+> parens (text "max arity =" <+> int mAX_CTUPLE_SIZE)) - 2 (text "Instead, use a nested tuple") + = addErr (TcRnCTupleTooLarge tup_size) {- ********************************************************************* * * diff --git a/compiler/GHC/Tc/Errors/Ppr.hs b/compiler/GHC/Tc/Errors/Ppr.hs index ef00752196..751a5f7682 100644 --- a/compiler/GHC/Tc/Errors/Ppr.hs +++ b/compiler/GHC/Tc/Errors/Ppr.hs @@ -86,6 +86,7 @@ import GHC.Data.Bag import GHC.Data.FastString import GHC.Data.List.SetOps ( nubOrdBy ) import GHC.Data.Maybe +import GHC.Settings.Constants (mAX_TUPLE_SIZE, mAX_CTUPLE_SIZE) import GHC.Utils.Misc import GHC.Utils.Outputable import GHC.Utils.Panic @@ -1790,6 +1791,74 @@ instance Diagnostic TcRnMessage where TcRnIllegalDataCon name -> mkSimpleDecorated $ hsep [text "Illegal data constructor name", quotes (ppr name)] + TcRnNestedForallsContexts entity + -> mkSimpleDecorated $ + what <+> text "cannot contain nested" + <+> quotes forAllLit <> text "s or contexts" + where + what = case entity of + NFC_Specialize -> text "SPECIALISE instance type" + NFC_ViaType -> quotes (text "via") <+> text "type" + NFC_GadtConSig -> text "GADT constructor type signature" + NFC_InstanceHead -> text "Instance head" + NFC_StandaloneDerivedInstanceHead -> text "Standalone-derived instance head" + NFC_DerivedClassType -> text "Derived class type" + TcRnRedundantRecordWildcard + -> mkSimpleDecorated $ + text "Record wildcard does not bind any new variables" + TcRnUnusedRecordWildcard _ + -> mkSimpleDecorated $ + text "No variables bound in the record wildcard match are used" + TcRnUnusedName name reason + -> mkSimpleDecorated $ + pprUnusedName name reason + TcRnQualifiedBinder rdr_name + -> mkSimpleDecorated $ + text "Qualified name in binding position:" <+> ppr rdr_name + TcRnTypeApplicationsDisabled tok t + -> mkSimpleDecorated $ + text "Illegal visible" <+> text what <+> text "application" + <+> quotes (char '@' <> ppr t) + where + what = case tok of + TypeLevel -> "type" + KindLevel -> "kind" + TcRnInvalidRecordField con field + -> mkSimpleDecorated $ + hsep [text "Constructor" <+> quotes (ppr con), + text "does not have field", quotes (ppr field)] + TcRnTupleTooLarge tup_size + -> mkSimpleDecorated $ + sep [text "A" <+> int tup_size <> text "-tuple is too large for GHC", + nest 2 (parens (text "max size is" <+> int mAX_TUPLE_SIZE)), + nest 2 (text "Workaround: use nested tuples or define a data type")] + TcRnCTupleTooLarge tup_size + -> mkSimpleDecorated $ + hang (text "Constraint tuple arity too large:" <+> int tup_size + <+> parens (text "max arity =" <+> int mAX_CTUPLE_SIZE)) + 2 (text "Instead, use a nested tuple") + TcRnIllegalInferredTyVars _ + -> mkSimpleDecorated $ + text "Inferred type variables are not allowed" + TcRnAmbiguousName name gres + -> mkSimpleDecorated $ + vcat [ text "Ambiguous occurrence" <+> quotes (ppr name) + , text "It could refer to" + , nest 3 (vcat (msg1 : msgs)) ] + where + np1 NE.:| nps = gres + msg1 = text "either" <+> ppr_gre np1 + msgs = [text " or" <+> ppr_gre np | np <- nps] + ppr_gre gre = sep [ pprAmbiguousGreName gre <> comma + , pprNameProvenance gre] + TcRnBindingNameConflict name locs + -> mkSimpleDecorated $ + vcat [text "Conflicting definitions for" <+> quotes (ppr name), + locations] + where + locations = + text "Bound at:" + <+> vcat (map ppr (sortBy leftmost_smallest (NE.toList locs))) diagnosticReason = \case TcRnUnknownMessage m @@ -2386,7 +2455,35 @@ instance Diagnostic TcRnMessage where -> ErrorWithoutFlag TcRnIllegalDataCon{} -> ErrorWithoutFlag - + TcRnNestedForallsContexts{} + -> ErrorWithoutFlag + TcRnRedundantRecordWildcard + -> WarningWithFlag Opt_WarnRedundantRecordWildcards + TcRnUnusedRecordWildcard{} + -> WarningWithFlag Opt_WarnUnusedRecordWildcards + TcRnUnusedName _ prov + -> WarningWithFlag $ case prov of + UnusedNameTopDecl -> Opt_WarnUnusedTopBinds + UnusedNameImported _ -> Opt_WarnUnusedTopBinds + UnusedNameTypePattern -> Opt_WarnUnusedTypePatterns + UnusedNameMatch -> Opt_WarnUnusedMatches + UnusedNameLocalBind -> Opt_WarnUnusedLocalBinds + TcRnQualifiedBinder{} + -> ErrorWithoutFlag + TcRnTypeApplicationsDisabled{} + -> ErrorWithoutFlag + TcRnInvalidRecordField{} + -> ErrorWithoutFlag + TcRnTupleTooLarge{} + -> ErrorWithoutFlag + TcRnCTupleTooLarge{} + -> ErrorWithoutFlag + TcRnIllegalInferredTyVars{} + -> ErrorWithoutFlag + TcRnAmbiguousName{} + -> ErrorWithoutFlag + TcRnBindingNameConflict{} + -> ErrorWithoutFlag diagnosticHints = \case TcRnUnknownMessage m @@ -3024,6 +3121,30 @@ instance Diagnostic TcRnMessage where -> [suggestExtension LangExt.PackageImports] TcRnIllegalDataCon{} -> noHints + TcRnNestedForallsContexts{} + -> noHints + TcRnRedundantRecordWildcard + -> [SuggestRemoveRecordWildcard] + TcRnUnusedRecordWildcard{} + -> [SuggestRemoveRecordWildcard] + TcRnUnusedName{} + -> noHints + TcRnQualifiedBinder{} + -> noHints + TcRnTypeApplicationsDisabled{} + -> [suggestExtension LangExt.TypeApplications] + TcRnInvalidRecordField{} + -> noHints + TcRnTupleTooLarge{} + -> noHints + TcRnCTupleTooLarge{} + -> noHints + TcRnIllegalInferredTyVars{} + -> noHints + TcRnAmbiguousName{} + -> noHints + TcRnBindingNameConflict{} + -> noHints diagnosticCode :: TcRnMessage -> Maybe DiagnosticCode diagnosticCode = constructorCode @@ -5280,3 +5401,53 @@ pprUnusedImport decl = \case case par of ParentIs p -> pprNameUnqualified p <> parens (ppr fld_occ) NoParent -> ppr fld_occ + +pprUnusedName :: OccName -> UnusedNameProv -> SDoc +pprUnusedName name reason = + sep [ msg <> colon + , nest 2 $ pprNonVarNameSpace (occNameSpace name) + <+> quotes (ppr name)] + where + msg = case reason of + UnusedNameTopDecl -> + defined + UnusedNameImported mod -> + text "Imported from" <+> quotes (ppr mod) <+> text "but not used" + UnusedNameTypePattern -> + defined <+> text "on the right hand side" + UnusedNameMatch -> + defined + UnusedNameLocalBind -> + defined + defined = text "Defined but not used" + +-- When printing the name, take care to qualify it in the same +-- way as the provenance reported by pprNameProvenance, namely +-- the head of 'gre_imp'. Otherwise we get confusing reports like +-- Ambiguous occurrence ‘null’ +-- It could refer to either ‘T15487a.null’, +-- imported from ‘Prelude’ at T15487.hs:1:8-13 +-- or ... +-- See #15487 +pprAmbiguousGreName :: GlobalRdrElt -> SDoc +pprAmbiguousGreName gre + | isRecFldGRE gre + = text "the field" <+> quotes (ppr occ) <+> parent_info + | otherwise + = quotes (pp_qual <> dot <> ppr occ) + where + occ = greOccName gre + parent_info = case gre_par gre of + NoParent -> empty + ParentIs { par_is = par_name } -> text "of record" <+> quotes (ppr par_name) + pp_qual + | gre_lcl gre + = ppr (nameModule $ greName gre) + | Just imp <- headMaybe $ gre_imp gre + -- This 'imp' is the one that + -- pprNameProvenance chooses + , ImpDeclSpec { is_as = mod } <- is_decl imp + = ppr mod + | otherwise + = pprPanic "addNameClassErrRn" (ppr gre) + -- Invariant: either 'lcl' is True or 'iss' is non-empty diff --git a/compiler/GHC/Tc/Errors/Types.hs b/compiler/GHC/Tc/Errors/Types.hs index 9e017a6e52..23dc2cd3b0 100644 --- a/compiler/GHC/Tc/Errors/Types.hs +++ b/compiler/GHC/Tc/Errors/Types.hs @@ -114,6 +114,8 @@ module GHC.Tc.Errors.Types ( , ImportLookupReason (..) , UnusedImportReason (..) , UnusedImportName (..) + , NestedForallsContextsIn(..) + , UnusedNameProv(..) ) where import GHC.Prelude @@ -139,7 +141,7 @@ import qualified GHC.Types.Name.Occurrence as OccName import GHC.Types.Name.Reader import GHC.Types.SrcLoc import GHC.Types.TyThing (TyThing) -import GHC.Types.Var (Id, TyCoVar, TyVar, TcTyVar, CoVar) +import GHC.Types.Var (Id, TyCoVar, TyVar, TcTyVar, CoVar, Specificity) import GHC.Types.Var.Env (TidyEnv) import GHC.Types.Var.Set (TyVarSet, VarSet) import GHC.Unit.Types (Module) @@ -3907,6 +3909,134 @@ data TcRnMessage where TcRnIllegalDataCon :: !RdrName -- ^ The constructor name -> TcRnMessage + {-| TcRnNestedForallsContexts is an error indicating that multiple foralls or + contexts are nested/curried where this is not supported, + like @∀ x. ∀ y.@ instead of @∀ x y.@. + + Test cases: + T12087, T14320, T16114, T16394, T16427, T18191, T18240a, T18240b, T18455, T5951 + -} + TcRnNestedForallsContexts :: !NestedForallsContextsIn -> TcRnMessage + + {-| TcRnRedundantRecordWildcard is a warning indicating that a pattern uses + a record wildcard even though all of the record's fields are bound explicitly. + + Test cases: + T15957_Fail + -} + TcRnRedundantRecordWildcard :: TcRnMessage + + {-| TcRnUnusedRecordWildcard is a warning indicating that a pattern uses + a record wildcard while none of the fields bound by it are used. + + Test cases: + T15957_Fail + -} + TcRnUnusedRecordWildcard :: ![Name] -- ^ The names bound by the wildcard + -> TcRnMessage + + {-| TcRnUnusedName is a warning indicating that a defined or imported name + is not used in the module. + + Test cases: + ds053, mc10, overloadedrecfldsfail05, overloadedrecfldsfail06, prog018, + read014, rn040, rn041, rn047, rn063, T13839, T13839a, T13919, T17171b, + T17a, T17b, T17d, T17e, T18470, T1972, t22391, t22391j, T2497, T3371, + T3449, T7145b, T7336, TH_recover_warns, unused_haddock, WarningGroups, + werror + -} + TcRnUnusedName :: !OccName -- ^ The unused name + -> !UnusedNameProv -- ^ The provenance of the name + -> TcRnMessage + + {-| TcRnQualifiedBinder is an error indicating that a qualified name + was used in binding position. + + Test cases: + mod62, rnfail021, rnfail034, rnfail039, rnfail046 + -} + TcRnQualifiedBinder :: !RdrName -- ^ The name used as a binder + -> TcRnMessage + + {-| TcRnTypeApplicationsDisabled is an error indicating that a type + application was used while the extension TypeApplications was disabled. + + Test cases: + T12411, T12446, T15527, T16133, T18251c + -} + TcRnTypeApplicationsDisabled :: !TypeOrKind -- ^ Type or kind application + -> !(HsType GhcPs) -- ^ The type being applied + -> TcRnMessage + + {-| TcRnInvalidRecordField is an error indicating that a record field was + used that doesn't exist in a constructor. + + Test cases: + T13644, T13847, T17469, T8448, T8570, tcfail083, tcfail084 + -} + TcRnInvalidRecordField :: !Name -- ^ The constructor name + -> !FieldLabelString -- ^ The name of the field + -> TcRnMessage + + {-| TcRnTupleTooLarge is an error indicating that the arity of a tuple + exceeds mAX_TUPLE_SIZE. + + Test cases: + T18723a, T18723b, T18723c, T6148a, T6148b, T6148c, T6148d + -} + TcRnTupleTooLarge :: !Int -- ^ The arity of the tuple + -> TcRnMessage + + {-| TcRnCTupleTooLarge is an error indicating that the arity of a constraint + tuple exceeds mAX_CTUPLE_SIZE. + + Test cases: + T10451 + -} + TcRnCTupleTooLarge :: !Int -- ^ The arity of the constraint tuple + -> TcRnMessage + + {-| TcRnIllegalInferredTyVars is an error indicating that some type variables + were quantified as inferred (like @∀ {a}.@) in a place where this is not + allowed, like in an instance declaration. + + Test cases: + ExplicitSpecificity5, ExplicitSpecificity6, ExplicitSpecificity8, + ExplicitSpecificity9 + -} + TcRnIllegalInferredTyVars :: !(NE.NonEmpty (HsTyVarBndr Specificity GhcPs)) + -- ^ The offending type variables + -> TcRnMessage + + {-| TcRnAmbiguousName is an error indicating that an unbound name + might refer to multiple names in scope. + + Test cases: + BootFldReexport, DRFUnused, duplicaterecfldsghci01, GHCiDRF, mod110, + mod151, mod152, mod153, mod164, mod165, NoFieldSelectorsFail, + overloadedrecfldsfail02, overloadedrecfldsfail04, overloadedrecfldsfail11, + overloadedrecfldsfail12, overloadedrecfldsfail13, + overloadedrecfldswasrunnowfail06, rnfail044, T11167_ambig, + T11167_ambiguous_fixity, T13132_duplicaterecflds, T15487, T16745, T17420, + T18999_NoDisambiguateRecordFields, T19397E1, T19397E2, T23010_fail, + tcfail037 + -} + TcRnAmbiguousName :: !RdrName -- ^ The name + -> !(NE.NonEmpty GlobalRdrElt) -- ^ The possible matches + -> TcRnMessage + + {-| TcRnBindingNameConflict is an error indicating that multiple local or + top-level bindings have the same name. + + Test cases: + dsrun006, mdofail002, mdofail003, mod23, mod24, qq006, rnfail001, + rnfail004, SimpleFail6, T14114, T16110_Fail1, tcfail038, TH_spliceD1 + -} + TcRnBindingNameConflict :: !RdrName -- ^ The conflicting name + -> !(NE.NonEmpty SrcSpan) + -- ^ The locations of the duplicates + -> TcRnMessage + deriving Generic -- | Things forbidden in @type data@ declarations. @@ -5414,3 +5544,26 @@ data UnusedImportReason where UnusedImportSome :: ![UnusedImportName] -- ^ The unsed names -> UnusedImportReason deriving (Generic) + +-- | Different places in which a nested foralls/contexts error might occur. +data NestedForallsContextsIn + -- | Nested forall in @SPECIALISE instance@ + = NFC_Specialize + -- | Nested forall in @deriving via@ (via-type) + | NFC_ViaType + -- | Nested forall in the type of a GADT constructor + | NFC_GadtConSig + -- | Nested forall in an instance head + | NFC_InstanceHead + -- | Nested forall in a standalone deriving instance head + | NFC_StandaloneDerivedInstanceHead + -- | Nested forall in deriving class type + | NFC_DerivedClassType + +-- | Provenance of an unused name. +data UnusedNameProv + = UnusedNameTopDecl + | UnusedNameImported !ModuleName + | UnusedNameTypePattern + | UnusedNameMatch + | UnusedNameLocalBind diff --git a/compiler/GHC/Tc/Module.hs b/compiler/GHC/Tc/Module.hs index 1b02340061..637baba3b6 100644 --- a/compiler/GHC/Tc/Module.hs +++ b/compiler/GHC/Tc/Module.hs @@ -989,7 +989,7 @@ checkHiBootIface' -- At least 2 matches: report an ambiguity error. (gre1,_):(gre2,_):gres_ids -> do addErrAt (nameSrcSpan missing_name) $ - mkNameClashErr missing_name (gre1 NE.:| gre2 : map fst gres_ids) + mkNameClashErr (nameRdrName missing_name) (gre1 NE.:| gre2 : map fst gres_ids) return Nothing -- Single match: resolve the issue. diff --git a/compiler/GHC/Types/Error/Codes.hs b/compiler/GHC/Types/Error/Codes.hs index 46597c8e0c..cb80f713d4 100644 --- a/compiler/GHC/Types/Error/Codes.hs +++ b/compiler/GHC/Types/Error/Codes.hs @@ -586,6 +586,18 @@ type family GhcDiagnosticCode c = n | n -> c where GhcDiagnosticCode "TcRnDuplicateDecls" = 29916 GhcDiagnosticCode "TcRnPackageImportsDisabled" = 10032 GhcDiagnosticCode "TcRnIllegalDataCon" = 78448 + GhcDiagnosticCode "TcRnNestedForallsContexts" = 71492 + GhcDiagnosticCode "TcRnRedundantRecordWildcard" = 15932 + GhcDiagnosticCode "TcRnUnusedRecordWildcard" = 83475 + GhcDiagnosticCode "TcRnUnusedName" = 40910 + GhcDiagnosticCode "TcRnQualifiedBinder" = 28329 + GhcDiagnosticCode "TcRnTypeApplicationsDisabled" = 23482 + GhcDiagnosticCode "TcRnInvalidRecordField" = 53822 + GhcDiagnosticCode "TcRnTupleTooLarge" = 94803 + GhcDiagnosticCode "TcRnCTupleTooLarge" = 89347 + GhcDiagnosticCode "TcRnIllegalInferredTyVars" = 54832 + GhcDiagnosticCode "TcRnAmbiguousName" = 87543 + GhcDiagnosticCode "TcRnBindingNameConflict" = 10498 -- PatSynInvalidRhsReason GhcDiagnosticCode "PatSynNotInvertible" = 69317 diff --git a/compiler/GHC/Types/Hint.hs b/compiler/GHC/Types/Hint.hs index 4ce8d04a9d..773ed4941d 100644 --- a/compiler/GHC/Types/Hint.hs +++ b/compiler/GHC/Types/Hint.hs @@ -434,6 +434,11 @@ data GhcHint -} | SuggestSafeHaskell + {-| Suggest removing a record wildcard from a pattern when it doesn't + bind anything useful. + -} + | SuggestRemoveRecordWildcard + -- | An 'InstantiationSuggestion' for a '.hsig' file. This is generated -- by GHC in case of a 'DriverUnexpectedSignature' and suggests a way -- to instantiate a particular signature, where the first argument is diff --git a/compiler/GHC/Types/Hint/Ppr.hs b/compiler/GHC/Types/Hint/Ppr.hs index c0945f29fe..76e678bb36 100644 --- a/compiler/GHC/Types/Hint/Ppr.hs +++ b/compiler/GHC/Types/Hint/Ppr.hs @@ -232,6 +232,8 @@ instance Outputable GhcHint where pp_args = hsep (map ppr args) SuggestSafeHaskell -> text "Enable Safe Haskell through either Safe, Trustworthy or Unsafe." + SuggestRemoveRecordWildcard + -> text "Omit the" <+> quotes (text "..") perhapsAsPat :: SDoc perhapsAsPat = text "Perhaps you meant an as-pattern, which must not be surrounded by whitespace" |