diff options
author | sheaf <sam.derbyshire@gmail.com> | 2023-03-17 12:48:21 +0100 |
---|---|---|
committer | sheaf <sam.derbyshire@gmail.com> | 2023-03-29 13:57:33 +0200 |
commit | 3f374399e2dbebcdfe5bc31f94fc502b46d0cf4f (patch) | |
tree | a5103e3d597c2d724173e070a22759ce50a9d2e7 /testsuite/tests/overloadedrecflds/ghci | |
parent | 76bb4c586084d7fdcf0e5ce52623abbfca527c55 (diff) | |
download | haskell-3f374399e2dbebcdfe5bc31f94fc502b46d0cf4f.tar.gz |
Handle records in the renamer
This patch moves the field-based logic for disambiguating record updates
to the renamer. The type-directed logic, scheduled for removal, remains
in the typechecker.
To do this properly (and fix the myriad of bugs surrounding the treatment
of duplicate record fields), we took the following main steps:
1. Create GREInfo, a renamer-level equivalent to TyThing which stores
information pertinent to the renamer.
This allows us to uniformly treat imported and local Names in the
renamer, as described in Note [GREInfo].
2. Remove GreName. Instead of a GlobalRdrElt storing GreNames, which
distinguished between normal names and field names, we now store
simple Names in GlobalRdrElt, along with the new GREInfo information
which allows us to recover the FieldLabel for record fields.
3. Add namespacing for record fields, within the OccNames themselves.
This allows us to remove the mangling of duplicate field selectors.
This change ensures we don't print mangled names to the user in
error messages, and allows us to handle duplicate record fields
in Template Haskell.
4. Move record disambiguation to the renamer, and operate on the
level of data constructors instead, to handle #21443.
The error message text for ambiguous record updates has also been
changed to reflect that type-directed disambiguation is on the way
out.
(3) means that OccEnv is now a bit more complex: we first key on the
textual name, which gives an inner map keyed on NameSpace:
OccEnv a ~ FastStringEnv (UniqFM NameSpace a)
Note that this change, along with (2), both increase the memory residency
of GlobalRdrEnv = OccEnv [GlobalRdrElt], which causes a few tests to
regress somewhat in compile-time allocation.
Even though (3) simplified a lot of code (in particular the treatment of
field selectors within Template Haskell and in error messages), it came
with one important wrinkle: in the situation of
-- M.hs-boot
module M where { data A; foo :: A -> Int }
-- M.hs
module M where { data A = MkA { foo :: Int } }
we have that M.hs-boot exports a variable foo, which is supposed to match
with the record field foo that M exports. To solve this issue, we add a
new impedance-matching binding to M
foo{var} = foo{fld}
This mimics the logic that existed already for impedance-binding DFunIds,
but getting it right was a bit tricky.
See Note [Record field impedance matching] in GHC.Tc.Module.
We also needed to be careful to avoid introducing space leaks in GHCi.
So we dehydrate the GlobalRdrEnv before storing it anywhere, e.g. in
ModIface. This means stubbing out all the GREInfo fields, with the
function forceGlobalRdrEnv.
When we read it back in, we rehydrate with rehydrateGlobalRdrEnv.
This robustly avoids any space leaks caused by retaining old type
environments.
Fixes #13352 #14848 #17381 #17551 #19664 #21443 #21444 #21720 #21898 #21946 #21959 #22125 #22160 #23010 #23062 #23063
Updates haddock submodule
-------------------------
Metric Increase:
MultiComponentModules
MultiLayerModules
MultiLayerModulesDefsGhci
MultiLayerModulesNoCode
T13701
T14697
hard_hole_fits
-------------------------
Diffstat (limited to 'testsuite/tests/overloadedrecflds/ghci')
7 files changed, 39 insertions, 17 deletions
diff --git a/testsuite/tests/overloadedrecflds/ghci/GHCiDRF.stdout b/testsuite/tests/overloadedrecflds/ghci/GHCiDRF.stdout index 08406f9387..c912c3c4ee 100644 --- a/testsuite/tests/overloadedrecflds/ghci/GHCiDRF.stdout +++ b/testsuite/tests/overloadedrecflds/ghci/GHCiDRF.stdout @@ -3,18 +3,18 @@ GHCiDRF.foo :: T -> Int <interactive>:1:1: error: Ambiguous occurrence ‘GHCiDRF.bar’ It could refer to - either the field ‘bar’ of record ‘U’, defined at GHCiDRF.hs:4:16 - or the field ‘bar’ of record ‘T’, defined at GHCiDRF.hs:3:28 + either the field ‘bar’ of record ‘T’, defined at GHCiDRF.hs:3:28 + or the field ‘bar’ of record ‘U’, defined at GHCiDRF.hs:4:16 type T :: * data T = MkT {foo :: Int, ...} -- Defined at GHCiDRF.hs:3:16 -type U :: * -data U = MkU {GHCiDRF.bar :: Bool} - -- Defined at GHCiDRF.hs:4:16 - type T :: * -data T = MkT {..., GHCiDRF.bar :: Int} +data T = MkT {..., bar :: Int} -- Defined at GHCiDRF.hs:3:28 + +type U :: * +data U = MkU {bar :: Bool} + -- Defined at GHCiDRF.hs:4:16 GHCiDRF.foo :: GHCiDRF.T -> Int <interactive>:1:1: error: diff --git a/testsuite/tests/overloadedrecflds/ghci/T19664.hs b/testsuite/tests/overloadedrecflds/ghci/T19664.hs new file mode 100644 index 0000000000..e7e38193a0 --- /dev/null +++ b/testsuite/tests/overloadedrecflds/ghci/T19664.hs @@ -0,0 +1,14 @@ +{-# LANGUAGE QuasiQuotes, TemplateHaskell, DuplicateRecordFields #-} + +module T19664 where + +import Language.Haskell.TH + +left = undefined + +([] <$) $ runIO . print =<< [d| + data Tree + = Node { left :: Tree, right :: Tree } + | Leaf { value :: Int } + deriving Show + |] diff --git a/testsuite/tests/overloadedrecflds/ghci/T19664.script b/testsuite/tests/overloadedrecflds/ghci/T19664.script new file mode 100644 index 0000000000..92f69cfe8c --- /dev/null +++ b/testsuite/tests/overloadedrecflds/ghci/T19664.script @@ -0,0 +1,2 @@ +:seti -XDuplicateRecordFields +:l T19664 diff --git a/testsuite/tests/overloadedrecflds/ghci/T19664.stdout b/testsuite/tests/overloadedrecflds/ghci/T19664.stdout new file mode 100644 index 0000000000..3742c489c8 --- /dev/null +++ b/testsuite/tests/overloadedrecflds/ghci/T19664.stdout @@ -0,0 +1 @@ +[DataD [] Tree_6989586621679019412 [] Nothing [RecC Node_6989586621679019413 [(left_6989586621679019416,Bang NoSourceUnpackedness NoSourceStrictness,ConT Tree_6989586621679019412),(right_6989586621679019415,Bang NoSourceUnpackedness NoSourceStrictness,ConT Tree_6989586621679019412)],RecC Leaf_6989586621679019414 [(value_6989586621679019417,Bang NoSourceUnpackedness NoSourceStrictness,ConT GHC.Types.Int)]] [DerivClause Nothing [ConT GHC.Show.Show]]] diff --git a/testsuite/tests/overloadedrecflds/ghci/all.T b/testsuite/tests/overloadedrecflds/ghci/all.T index 17f4f82ff5..6e775149e5 100644 --- a/testsuite/tests/overloadedrecflds/ghci/all.T +++ b/testsuite/tests/overloadedrecflds/ghci/all.T @@ -4,3 +4,4 @@ test('T13438', [expect_broken(13438), combined_output], ghci_script, ['T13438.sc test('GHCiDRF', [extra_files(['GHCiDRF.hs']), combined_output], ghci_script, ['GHCiDRF.script']) test('T19322', combined_output, ghci_script, ['T19322.script']) test('T19314', combined_output, ghci_script, ['T19314.script']) +test('T19664', [ignore_stdout, extra_files(['T19664.hs'])], ghci_script, ['T19664.script']) diff --git a/testsuite/tests/overloadedrecflds/ghci/duplicaterecfldsghci01.script b/testsuite/tests/overloadedrecflds/ghci/duplicaterecfldsghci01.script index 2aa0a15be8..cca0b8a93f 100644 --- a/testsuite/tests/overloadedrecflds/ghci/duplicaterecfldsghci01.script +++ b/testsuite/tests/overloadedrecflds/ghci/duplicaterecfldsghci01.script @@ -5,13 +5,12 @@ data T a = MkT { foo :: Bool, bar :: a -> a } let t = MkT { foo = True, bar = id } (\MkT{foo=foo} -> foo) t :info foo -:type foo -foo (MkS 42) bar (MkT True id) True :set -XNoDuplicateRecordFields -- Should be ambiguous :type foo data U = MkU { foo :: Int } -- New foo should shadow the old ones +:info foo :type foo foo (MkU 42) diff --git a/testsuite/tests/overloadedrecflds/ghci/duplicaterecfldsghci01.stdout b/testsuite/tests/overloadedrecflds/ghci/duplicaterecfldsghci01.stdout index ae87b8ea19..b34e509ecc 100644 --- a/testsuite/tests/overloadedrecflds/ghci/duplicaterecfldsghci01.stdout +++ b/testsuite/tests/overloadedrecflds/ghci/duplicaterecfldsghci01.stdout @@ -1,15 +1,20 @@ True +type S :: * +data S = MkS {foo :: Int} + -- Defined at <interactive>:3:16 + type T :: * -> * data T a = MkT {foo :: Bool, ...} -- Defined at <interactive>:4:18 -foo :: T a -> Bool - -<interactive>:9:6: error: [GHC-83865] - • Couldn't match expected type ‘T a0’ with actual type ‘S’ - • In the first argument of ‘foo’, namely ‘(MkS 42)’ - In the expression: foo (MkS 42) - In an equation for ‘it’: it = foo (MkS 42) True -foo :: T a -> Bool + +<interactive>:1:1: error: + Ambiguous occurrence ‘foo’ + It could refer to + either the field ‘foo’ of record ‘S’, defined at <interactive>:3:16 + or the field ‘foo’ of record ‘T’, defined at <interactive>:4:18 +type U :: * +data U = MkU {foo :: Int} + -- Defined at <interactive>:12:16 foo :: U -> Int 42 |