diff options
author | Daishi Nakajima <nakaji.dayo@gmail.com> | 2017-10-25 15:51:01 -0400 |
---|---|---|
committer | Ben Gamari <ben@smart-cactus.org> | 2017-10-25 16:44:03 -0400 |
commit | f7f270eb6ba616feda79d370336db7e66f9ab79c (patch) | |
tree | faaea23391b1304ad54ca22aacde434d79057d03 /compiler | |
parent | df636682f3b8299268d189bfaf6de1d672c19a73 (diff) | |
download | haskell-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.hs | 4 | ||||
-rw-r--r-- | compiler/typecheck/TcTyClsDecls.hs | 42 |
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 |