summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Gundry <adam@well-typed.com>2020-04-27 23:22:59 +0100
committerMarge Bot <ben+marge-bot@smart-cactus.org>2020-05-08 15:29:41 -0400
commit7a763cff78d2d4b23d05554e68138678cb4ba627 (patch)
tree16f7aabfff8879bc7cb027971f5d15fefddb1fce
parent926d2aab83dc6068cba76f71a19b040eddc6dee9 (diff)
downloadhaskell-7a763cff78d2d4b23d05554e68138678cb4ba627.tar.gz
Reject all duplicate declarations involving DuplicateRecordFields (fixes #17965)
This fixes a bug that resulted in some programs being accepted that used the same identifier as a field label and another declaration, depending on the order they appeared in the source code.
-rw-r--r--compiler/GHC/Rename/Names.hs12
-rw-r--r--compiler/GHC/Types/Name/Reader.hs8
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/T17965.hs4
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/T17965.stderr5
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/all.T1
5 files changed, 24 insertions, 6 deletions
diff --git a/compiler/GHC/Rename/Names.hs b/compiler/GHC/Rename/Names.hs
index df39d01adb..cd39ed701d 100644
--- a/compiler/GHC/Rename/Names.hs
+++ b/compiler/GHC/Rename/Names.hs
@@ -638,9 +638,12 @@ extendGlobalRdrEnvRn avails new_fixities
| otherwise
= return (extendGlobalRdrEnv env gre)
where
- name = gre_name gre
- occ = nameOccName name
- dups = filter isLocalGRE (lookupGlobalRdrEnv env occ)
+ occ = greOccName gre
+ dups = filter isDupGRE (lookupGlobalRdrEnv env occ)
+ -- Duplicate GREs are those defined locally with the same OccName,
+ -- except cases where *both* GREs are DuplicateRecordFields (#17965).
+ isDupGRE gre' = isLocalGRE gre'
+ && not (isOverloadedRecFldGRE gre && isOverloadedRecFldGRE gre')
{- *********************************************************************
@@ -1767,14 +1770,13 @@ addDupDeclErr gres@(gre : _)
= addErrAt (getSrcSpan (last sorted_names)) $
-- Report the error at the later location
vcat [text "Multiple declarations of" <+>
- quotes (ppr (nameOccName name)),
+ quotes (ppr (greOccName gre)),
-- NB. print the OccName, not the Name, because the
-- latter might not be in scope in the RdrEnv and so will
-- be printed qualified.
text "Declared at:" <+>
vcat (map (ppr . nameSrcLoc) sorted_names)]
where
- name = gre_name gre
sorted_names =
sortBy (SrcLoc.leftmost_smallest `on` nameSrcSpan)
(map gre_name gres)
diff --git a/compiler/GHC/Types/Name/Reader.hs b/compiler/GHC/Types/Name/Reader.hs
index 5f9163bb46..c1e675a19e 100644
--- a/compiler/GHC/Types/Name/Reader.hs
+++ b/compiler/GHC/Types/Name/Reader.hs
@@ -57,7 +57,7 @@ module GHC.Types.Name.Reader (
gresToAvailInfo,
-- ** Global 'RdrName' mapping elements: 'GlobalRdrElt', 'Provenance', 'ImportSpec'
- GlobalRdrElt(..), isLocalGRE, isRecFldGRE, greLabel,
+ GlobalRdrElt(..), isLocalGRE, isRecFldGRE, isOverloadedRecFldGRE, greLabel,
unQualOK, qualSpecOK, unQualSpecOK,
pprNameProvenance,
Parent(..), greParent_maybe,
@@ -842,6 +842,12 @@ isRecFldGRE :: GlobalRdrElt -> Bool
isRecFldGRE (GRE {gre_par = FldParent{}}) = True
isRecFldGRE _ = False
+isOverloadedRecFldGRE :: GlobalRdrElt -> Bool
+-- ^ Is this a record field defined with DuplicateRecordFields?
+-- (See Note [Parents for record fields])
+isOverloadedRecFldGRE (GRE {gre_par = FldParent{par_lbl = Just _}}) = True
+isOverloadedRecFldGRE _ = False
+
-- Returns the field label of this GRE, if it has one
greLabel :: GlobalRdrElt -> Maybe FieldLabelString
greLabel (GRE{gre_par = FldParent{par_lbl = Just lbl}}) = Just lbl
diff --git a/testsuite/tests/overloadedrecflds/should_fail/T17965.hs b/testsuite/tests/overloadedrecflds/should_fail/T17965.hs
new file mode 100644
index 0000000000..b723637f23
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_fail/T17965.hs
@@ -0,0 +1,4 @@
+{-# LANGUAGE DuplicateRecordFields #-}
+main = return ()
+newtype Record a = Record { f :: a -> a }
+class C a where f :: a -> a
diff --git a/testsuite/tests/overloadedrecflds/should_fail/T17965.stderr b/testsuite/tests/overloadedrecflds/should_fail/T17965.stderr
new file mode 100644
index 0000000000..446913eda4
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_fail/T17965.stderr
@@ -0,0 +1,5 @@
+
+T17965.hs:4:17: error:
+ Multiple declarations of ‘f’
+ Declared at: T17965.hs:3:29
+ T17965.hs:4:17
diff --git a/testsuite/tests/overloadedrecflds/should_fail/all.T b/testsuite/tests/overloadedrecflds/should_fail/all.T
index 92ff1f0015..bc3c0650d2 100644
--- a/testsuite/tests/overloadedrecflds/should_fail/all.T
+++ b/testsuite/tests/overloadedrecflds/should_fail/all.T
@@ -32,3 +32,4 @@ test('hasfieldfail03', normal, compile_fail, [''])
test('T14953', [extra_files(['T14953_A.hs', 'T14953_B.hs'])],
multimod_compile_fail, ['T14953', ''])
test('DuplicateExports', normal, compile_fail, [''])
+test('T17965', normal, compile_fail, [''])