summaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
authorDaishi Nakajima <nakaji.dayo@gmail.com>2017-10-25 15:51:01 -0400
committerBen Gamari <ben@smart-cactus.org>2017-10-25 16:44:03 -0400
commitf7f270eb6ba616feda79d370336db7e66f9ab79c (patch)
treefaaea23391b1304ad54ca22aacde434d79057d03 /compiler
parentdf636682f3b8299268d189bfaf6de1d672c19a73 (diff)
downloadhaskell-f7f270eb6ba616feda79d370336db7e66f9ab79c.tar.gz
Implement `-Wpartial-fields` warning (#7169)
Warning on declaring a partial record selector. However, disable warn with field names that start with underscore. Test Plan: Added 1 test case. Reviewers: austin, bgamari, simonpj Reviewed By: bgamari, simonpj Subscribers: goldfire, simonpj, duog, rwbarton, thomie GHC Trac Issues: #7169 Differential Revision: https://phabricator.haskell.org/D4083
Diffstat (limited to 'compiler')
-rw-r--r--compiler/main/DynFlags.hs4
-rw-r--r--compiler/typecheck/TcTyClsDecls.hs42
2 files changed, 45 insertions, 1 deletions
diff --git a/compiler/main/DynFlags.hs b/compiler/main/DynFlags.hs
index 4c62a0d464..7602b719cc 100644
--- a/compiler/main/DynFlags.hs
+++ b/compiler/main/DynFlags.hs
@@ -674,6 +674,7 @@ data WarningFlag =
| Opt_WarnCPPUndef -- Since 8.2
| Opt_WarnUnbangedStrictPatterns -- Since 8.2
| Opt_WarnMissingHomeModules -- Since 8.2
+ | Opt_WarnPartialFields -- Since 8.4
deriving (Eq, Show, Enum)
data Language = Haskell98 | Haskell2010
@@ -3665,7 +3666,8 @@ wWarningFlagsDeps = [
Opt_WarnMissingPatternSynonymSignatures,
flagSpec "simplifiable-class-constraints" Opt_WarnSimplifiableClassConstraints,
flagSpec "missing-home-modules" Opt_WarnMissingHomeModules,
- flagSpec "unrecognised-warning-flags" Opt_WarnUnrecognisedWarningFlags ]
+ flagSpec "unrecognised-warning-flags" Opt_WarnUnrecognisedWarningFlags,
+ flagSpec "partial-fields" Opt_WarnPartialFields ]
-- | These @-\<blah\>@ flags can all be reversed with @-no-\<blah\>@
negatableFlagsDeps :: [(Deprecation, FlagSpec GeneralFlag)]
diff --git a/compiler/typecheck/TcTyClsDecls.hs b/compiler/typecheck/TcTyClsDecls.hs
index b4b31e3d50..cf92638b6c 100644
--- a/compiler/typecheck/TcTyClsDecls.hs
+++ b/compiler/typecheck/TcTyClsDecls.hs
@@ -2355,6 +2355,7 @@ checkValidTyCon tc
; let ex_ok = existential_ok || gadt_ok
-- Data cons can have existential context
; mapM_ (checkValidDataCon dflags ex_ok tc) data_cons
+ ; mapM_ (checkPartialRecordField data_cons) (tyConFieldLabels tc)
-- Check that fields with the same name share a type
; mapM_ check_fields groups }}
@@ -2401,6 +2402,29 @@ checkValidTyCon tc
(_, _, _, res2) = dataConSig con2
fty2 = dataConFieldType con2 lbl
+checkPartialRecordField :: [DataCon] -> FieldLabel -> TcM ()
+-- Check the partial record field selector, and warns.
+-- See Note [Checking partial record field]
+checkPartialRecordField all_cons fld
+ = setSrcSpan loc $
+ warnIfFlag Opt_WarnPartialFields
+ (not is_exhaustive && not (startsWithUnderscore occ_name))
+ (sep [text "Use of partial record field selector" <> colon,
+ nest 2 $ quotes (ppr occ_name)])
+ where
+ sel_name = flSelector fld
+ loc = getSrcSpan sel_name
+ occ_name = getOccName sel_name
+
+ (cons_with_field, cons_without_field) = partition has_field all_cons
+ has_field con = fld `elem` (dataConFieldLabels con)
+ is_exhaustive = all (dataConCannotMatch inst_tys) cons_without_field
+
+ con1 = ASSERT( not (null cons_with_field) ) head cons_with_field
+ (univ_tvs, _, eq_spec, _, _, _) = dataConFullSig con1
+ eq_subst = mkTvSubstPrs (map eqSpecPair eq_spec)
+ inst_tys = substTyVars eq_subst univ_tvs
+
checkFieldCompat :: FieldLabelString -> DataCon -> DataCon
-> Type -> Type -> Type -> Type -> TcM ()
checkFieldCompat fld con1 con2 res1 res2 fty1 fty2
@@ -2958,6 +2982,24 @@ tcSplitSigmaTy. tcSplitNestedSigmaTys will always split any foralls that it
sees until it can't go any further, so if you called it on the default type
signature for `each`, it would return (a -> f b) -> s -> f t like we desired.
+Note [Checking partial record field]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+This check checks the partial record field selector, and warns (Trac #7169).
+
+For example:
+
+ data T a = A { m1 :: a, m2 :: a } | B { m1 :: a }
+
+The function 'm2' is partial record field, and will fail when it is applied to
+'B'. The warning identifies such partial fields. The check is performed at the
+declaration of T, not at the call-sites of m2.
+
+The warning can be suppressed by prefixing the field-name with an underscore.
+For example:
+
+ data T a = A { m1 :: a, _m2 :: a } | B { m1 :: a }
+
+
************************************************************************
* *
Checking role validity