summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsheaf <sam.derbyshire@gmail.com>2023-03-17 12:48:21 +0100
committersheaf <sam.derbyshire@gmail.com>2023-03-29 13:57:33 +0200
commit3f374399e2dbebcdfe5bc31f94fc502b46d0cf4f (patch)
treea5103e3d597c2d724173e070a22759ce50a9d2e7
parent76bb4c586084d7fdcf0e5ce52623abbfca527c55 (diff)
downloadhaskell-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 -------------------------
-rw-r--r--compiler/GHC.hs75
-rw-r--r--compiler/GHC/Builtin/Names.hs23
-rw-r--r--compiler/GHC/Builtin/Names/TH.hs36
-rw-r--r--compiler/GHC/Builtin/Uniques.hs22
-rw-r--r--compiler/GHC/Builtin/Uniques.hs-boot2
-rw-r--r--compiler/GHC/Builtin/Utils.hs8
-rw-r--r--compiler/GHC/ByteCode/Linker.hs2
-rw-r--r--compiler/GHC/Core/ConLike.hs24
-rw-r--r--compiler/GHC/Core/DataCon.hs2
-rw-r--r--compiler/GHC/Core/LateCC.hs2
-rw-r--r--compiler/GHC/Core/Map/Type.hs2
-rw-r--r--compiler/GHC/Core/TyCon.hs67
-rw-r--r--compiler/GHC/Core/TyCon/Env.hs2
-rw-r--r--compiler/GHC/CoreToIface.hs15
-rw-r--r--compiler/GHC/Data/FastString/Env.hs15
-rw-r--r--compiler/GHC/Driver/Env.hs31
-rw-r--r--compiler/GHC/Hs/Decls.hs5
-rw-r--r--compiler/GHC/Hs/Expr.hs36
-rw-r--r--compiler/GHC/Hs/ImpExp.hs60
-rw-r--r--compiler/GHC/Hs/Instances.hs8
-rw-r--r--compiler/GHC/Hs/Pat.hs4
-rw-r--r--compiler/GHC/Hs/Type.hs20
-rw-r--r--compiler/GHC/Hs/Utils.hs250
-rw-r--r--compiler/GHC/HsToCore/Errors/Types.hs2
-rw-r--r--compiler/GHC/HsToCore/Expr.hs4
-rw-r--r--compiler/GHC/HsToCore/Quote.hs46
-rw-r--r--compiler/GHC/HsToCore/Ticks.hs10
-rw-r--r--compiler/GHC/Iface/Env.hs9
-rw-r--r--compiler/GHC/Iface/Ext/Ast.hs21
-rw-r--r--compiler/GHC/Iface/Load.hs2
-rw-r--r--compiler/GHC/Iface/Make.hs20
-rw-r--r--compiler/GHC/Iface/Recomp.hs15
-rw-r--r--compiler/GHC/Iface/Rename.hs21
-rw-r--r--compiler/GHC/Iface/Syntax.hs54
-rw-r--r--compiler/GHC/IfaceToCore.hs25
-rw-r--r--compiler/GHC/Parser/PostProcess.hs26
-rw-r--r--compiler/GHC/Rename/Doc.hs9
-rw-r--r--compiler/GHC/Rename/Env.hs993
-rw-r--r--compiler/GHC/Rename/Expr.hs113
-rw-r--r--compiler/GHC/Rename/Fixity.hs22
-rw-r--r--compiler/GHC/Rename/HsType.hs27
-rw-r--r--compiler/GHC/Rename/Module.hs66
-rw-r--r--compiler/GHC/Rename/Names.hs983
-rw-r--r--compiler/GHC/Rename/Pat.hs269
-rw-r--r--compiler/GHC/Rename/Splice.hs5
-rw-r--r--compiler/GHC/Rename/Unbound.hs69
-rw-r--r--compiler/GHC/Rename/Utils.hs109
-rw-r--r--compiler/GHC/Runtime/Context.hs49
-rw-r--r--compiler/GHC/Runtime/Eval.hs63
-rw-r--r--compiler/GHC/Runtime/Loader.hs19
-rw-r--r--compiler/GHC/StgToJS/Ids.hs2
-rw-r--r--compiler/GHC/Tc/Errors.hs27
-rw-r--r--compiler/GHC/Tc/Errors/Hole.hs9
-rw-r--r--compiler/GHC/Tc/Errors/Hole/FitTypes.hs6
-rw-r--r--compiler/GHC/Tc/Errors/Ppr.hs245
-rw-r--r--compiler/GHC/Tc/Errors/Types.hs222
-rw-r--r--compiler/GHC/Tc/Gen/Export.hs518
-rw-r--r--compiler/GHC/Tc/Gen/Expr.hs731
-rw-r--r--compiler/GHC/Tc/Gen/Head.hs41
-rw-r--r--compiler/GHC/Tc/Gen/HsType.hs58
-rw-r--r--compiler/GHC/Tc/Gen/Splice.hs85
-rw-r--r--compiler/GHC/Tc/Instance/Class.hs4
-rw-r--r--compiler/GHC/Tc/Module.hs245
-rw-r--r--compiler/GHC/Tc/Solver/Monad.hs2
-rw-r--r--compiler/GHC/Tc/TyCl.hs36
-rw-r--r--compiler/GHC/Tc/TyCl/Utils.hs8
-rw-r--r--compiler/GHC/Tc/Types.hs7
-rw-r--r--compiler/GHC/Tc/Types/Origin.hs2
-rw-r--r--compiler/GHC/Tc/Utils/Backpack.hs59
-rw-r--r--compiler/GHC/Tc/Utils/Env.hs24
-rw-r--r--compiler/GHC/Tc/Utils/Monad.hs7
-rw-r--r--compiler/GHC/ThToHs.hs95
-rw-r--r--compiler/GHC/Types/Avail.hs250
-rw-r--r--compiler/GHC/Types/Basic.hs84
-rw-r--r--compiler/GHC/Types/ConInfo.hs82
-rw-r--r--compiler/GHC/Types/Error/Codes.hs22
-rw-r--r--compiler/GHC/Types/FieldLabel.hs122
-rw-r--r--compiler/GHC/Types/GREInfo.hs276
-rw-r--r--compiler/GHC/Types/Id.hs16
-rw-r--r--compiler/GHC/Types/Id/Info.hs59
-rw-r--r--compiler/GHC/Types/Name.hs22
-rw-r--r--compiler/GHC/Types/Name.hs-boot3
-rw-r--r--compiler/GHC/Types/Name/Env.hs8
-rw-r--r--compiler/GHC/Types/Name/Occurrence.hs645
-rw-r--r--compiler/GHC/Types/Name/Occurrence.hs-boot1
-rw-r--r--compiler/GHC/Types/Name/Ppr.hs14
-rw-r--r--compiler/GHC/Types/Name/Reader.hs804
-rw-r--r--compiler/GHC/Types/Name/Shape.hs36
-rw-r--r--compiler/GHC/Types/TyThing.hs100
-rw-r--r--compiler/GHC/Types/TypeEnv.hs1
-rw-r--r--compiler/GHC/Types/Unique/FM.hs57
-rw-r--r--compiler/GHC/Types/Unique/Map.hs2
-rw-r--r--compiler/GHC/Types/Unique/Set.hs4
-rw-r--r--compiler/GHC/Unit/Module/Env.hs4
-rw-r--r--compiler/GHC/Unit/Module/ModIface.hs8
-rw-r--r--compiler/GHC/Utils/Binary.hs10
-rw-r--r--compiler/GHC/Utils/Monad.hs10
-rw-r--r--compiler/GHC/Utils/Outputable.hs12
-rw-r--r--compiler/Language/Haskell/Syntax/Decls.hs28
-rw-r--r--compiler/Language/Haskell/Syntax/Expr.hs17
-rw-r--r--compiler/Language/Haskell/Syntax/Extension.hs2
-rw-r--r--compiler/Language/Haskell/Syntax/ImpExp.hs2
-rw-r--r--compiler/Language/Haskell/Syntax/Pat.hs7
-rw-r--r--compiler/ghc.cabal.in2
-rw-r--r--docs/users_guide/9.6.1-notes.rst5
-rw-r--r--docs/users_guide/9.8.1-notes.rst25
-rw-r--r--ghc/GHCi/UI/Info.hs6
-rw-r--r--ghc/GHCi/UI/Monad.hs7
-rw-r--r--libraries/template-haskell/Language/Haskell/TH/Lib/Internal.hs22
-rw-r--r--libraries/template-haskell/Language/Haskell/TH/Ppr.hs17
-rw-r--r--libraries/template-haskell/Language/Haskell/TH/Syntax.hs47
-rw-r--r--libraries/template-haskell/changelog.md12
-rw-r--r--testsuite/tests/backpack/reexport/T23080a.bkp9
-rw-r--r--testsuite/tests/backpack/reexport/T23080b.bkp9
-rw-r--r--testsuite/tests/backpack/reexport/all.T2
-rw-r--r--testsuite/tests/backpack/reexport/bkpreex05.bkp30
-rw-r--r--testsuite/tests/count-deps/CountDepsAst.stdout2
-rw-r--r--testsuite/tests/count-deps/CountDepsParser.stdout2
-rw-r--r--testsuite/tests/deriving/should_compile/T13919.stderr2
-rw-r--r--testsuite/tests/gadt/T18191.stderr26
-rw-r--r--testsuite/tests/ghci.debugger/scripts/break006.stderr4
-rw-r--r--testsuite/tests/ghci.debugger/scripts/print019.stderr2
-rw-r--r--testsuite/tests/ghci/scripts/T22125.script6
-rw-r--r--testsuite/tests/ghci/scripts/T22125.stdout1
-rw-r--r--testsuite/tests/ghci/scripts/T23062.script5
-rw-r--r--testsuite/tests/ghci/scripts/T23062.stdout1
-rwxr-xr-xtestsuite/tests/ghci/scripts/all.T2
-rw-r--r--testsuite/tests/ghci/scripts/ghci065.stdout8
-rw-r--r--testsuite/tests/linters/notes.stdout41
-rw-r--r--testsuite/tests/overloadedrecflds/ghci/GHCiDRF.stdout14
-rw-r--r--testsuite/tests/overloadedrecflds/ghci/T19664.hs14
-rw-r--r--testsuite/tests/overloadedrecflds/ghci/T19664.script2
-rw-r--r--testsuite/tests/overloadedrecflds/ghci/T19664.stdout1
-rw-r--r--testsuite/tests/overloadedrecflds/ghci/all.T1
-rw-r--r--testsuite/tests/overloadedrecflds/ghci/duplicaterecfldsghci01.script3
-rw-r--r--testsuite/tests/overloadedrecflds/ghci/duplicaterecfldsghci01.stdout21
-rw-r--r--testsuite/tests/overloadedrecflds/should_compile/BootFldReexport.hs8
-rw-r--r--testsuite/tests/overloadedrecflds/should_compile/BootFldReexport.stderr11
-rw-r--r--testsuite/tests/overloadedrecflds/should_compile/BootFldReexport_B.hs5
-rw-r--r--testsuite/tests/overloadedrecflds/should_compile/BootFldReexport_N.hs5
-rw-r--r--testsuite/tests/overloadedrecflds/should_compile/BootFldReexport_N.hs-boot2
-rw-r--r--testsuite/tests/overloadedrecflds/should_compile/BootFldReexport_O.hs5
-rw-r--r--testsuite/tests/overloadedrecflds/should_compile/BootFldReexport_O.hs-boot4
-rw-r--r--testsuite/tests/overloadedrecflds/should_compile/DupFldFixity1.hs9
-rw-r--r--testsuite/tests/overloadedrecflds/should_compile/DupFldFixity2.hs12
-rw-r--r--testsuite/tests/overloadedrecflds/should_compile/DupFldFixity3.hs9
-rw-r--r--testsuite/tests/overloadedrecflds/should_compile/NoDRFModuleExport.hs6
-rw-r--r--testsuite/tests/overloadedrecflds/should_compile/NoDRFModuleExport_aux.hs4
-rw-r--r--testsuite/tests/overloadedrecflds/should_compile/OverloadedRecFlds10_A.hs5
-rw-r--r--testsuite/tests/overloadedrecflds/should_compile/OverloadedRecFlds10_B.hs6
-rw-r--r--testsuite/tests/overloadedrecflds/should_compile/OverloadedRecFlds10_C.hs6
-rw-r--r--testsuite/tests/overloadedrecflds/should_compile/T11103.hs (renamed from testsuite/tests/overloadedrecflds/should_fail/T11103.hs)6
-rw-r--r--testsuite/tests/overloadedrecflds/should_compile/T13352.hs4
-rw-r--r--testsuite/tests/overloadedrecflds/should_compile/T13352_A.hs2
-rw-r--r--testsuite/tests/overloadedrecflds/should_compile/T13352_B.hs2
-rw-r--r--testsuite/tests/overloadedrecflds/should_compile/T13352_hard.hs4
-rw-r--r--testsuite/tests/overloadedrecflds/should_compile/T13352_hard.stderr9
-rw-r--r--testsuite/tests/overloadedrecflds/should_compile/T13352_hard_A.hs3
-rw-r--r--testsuite/tests/overloadedrecflds/should_compile/T13352_hard_B.hs3
-rw-r--r--testsuite/tests/overloadedrecflds/should_compile/T14848.hs10
-rw-r--r--testsuite/tests/overloadedrecflds/should_compile/T17551.hs15
-rw-r--r--testsuite/tests/overloadedrecflds/should_compile/T21720.hs18
-rw-r--r--testsuite/tests/overloadedrecflds/should_compile/T21898.hs15
-rw-r--r--testsuite/tests/overloadedrecflds/should_compile/T22160.hs9
-rw-r--r--testsuite/tests/overloadedrecflds/should_compile/T22160_A.hs3
-rw-r--r--testsuite/tests/overloadedrecflds/should_compile/T22160_B.hs3
-rw-r--r--testsuite/tests/overloadedrecflds/should_compile/T22160_C.hs3
-rw-r--r--testsuite/tests/overloadedrecflds/should_compile/T23010.hs8
-rw-r--r--testsuite/tests/overloadedrecflds/should_compile/T23010.hs-boot7
-rw-r--r--testsuite/tests/overloadedrecflds/should_compile/T23010_aux.hs8
-rw-r--r--testsuite/tests/overloadedrecflds/should_compile/all.T35
-rw-r--r--testsuite/tests/overloadedrecflds/should_compile/overloadedrecflds10.hs7
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/DRF9156.stderr6
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/DRFHoleFits.stderr4
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/DRFUnused.stderr4
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/NFS9156.stderr6
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/NFSExport.hs2
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/NFSMixed.hs2
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/NFSMixed.stderr18
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/NoFieldSelectorsFail.stderr57
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/NoParent.stderr2
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/T11103.stderr6
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/T11167_ambiguous_fixity.stderr8
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/T13132_duplicaterecflds.stderr12
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/T14953.stderr4
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/T16745.stderr8
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/T17420.stderr8
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/T18999_NoDisambiguateRecordFields.stderr17
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/T19287.hs2
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/T19287.stderr6
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/T21946.hs11
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/T21946.stderr8
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/T21959.hs6
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/T21959.stderr3
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/T23010_fail.hs7
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/T23010_fail.hs-boot7
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/T23010_fail.stderr8
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/T23010_fail_aux.hs8
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/T23063.hs5
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/T23063.stderr12
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/T23063_aux.hs4
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/all.T13
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail01.stderr24
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail01a.hs13
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail01a.stderr6
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail01b.hs13
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail01b.stderr4
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail01c.hs (renamed from testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail01.hs)10
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail01c.stderr8
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail02.stderr6
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail05.stderr2
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail06.stderr18
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail08.stderr5
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail10.hs8
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail10.stderr24
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail11.stderr8
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail13.stderr24
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail14.stderr6
-rw-r--r--testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldswasrunnowfail06.stderr32
-rw-r--r--testsuite/tests/overloadedrecflds/should_run/T17551b.hs14
-rw-r--r--testsuite/tests/overloadedrecflds/should_run/T17551b.stdout1
-rw-r--r--testsuite/tests/overloadedrecflds/should_run/all.T1
-rw-r--r--testsuite/tests/parser/should_compile/T14189.stderr45
-rw-r--r--testsuite/tests/patsyn/should_fail/mixed-pat-syn-record-sels.stderr5
-rw-r--r--testsuite/tests/patsyn/should_fail/records-mixing-fields.stderr17
-rw-r--r--testsuite/tests/perf/compiler/Makefile1
-rw-r--r--testsuite/tests/perf/compiler/all.T9
-rwxr-xr-xtestsuite/tests/perf/compiler/genRecordUpdPerf24
-rw-r--r--testsuite/tests/perf/compiler/hard_hole_fits.stderr5
-rw-r--r--testsuite/tests/plugins/static-plugins.stdout2
-rw-r--r--testsuite/tests/rename/should_compile/T22122.hs18
-rw-r--r--testsuite/tests/rename/should_compile/T22122_aux.hs68
-rw-r--r--testsuite/tests/rename/should_compile/all.T1
-rw-r--r--testsuite/tests/rename/should_fail/T11167_ambig.stderr12
-rw-r--r--testsuite/tests/rename/should_fail/T12681.stderr3
-rw-r--r--testsuite/tests/rename/should_fail/T19843f.stderr10
-rw-r--r--testsuite/tests/rename/should_fail/T19843g.stderr6
-rw-r--r--testsuite/tests/rename/should_fail/T19843h.stderr4
-rw-r--r--testsuite/tests/rename/should_fail/T21605a.stderr5
-rw-r--r--testsuite/tests/rename/should_fail/T21605d.stderr7
-rw-r--r--testsuite/tests/rename/should_fail/T7943.hs2
-rw-r--r--testsuite/tests/rename/should_fail/T7943.stderr7
-rw-r--r--testsuite/tests/rename/should_fail/T9077.stderr2
-rw-r--r--testsuite/tests/rename/should_fail/T9156.stderr6
-rw-r--r--testsuite/tests/rename/should_fail/T9156_DF.hs10
-rw-r--r--testsuite/tests/rename/should_fail/T9156_DF.stderr3
-rw-r--r--testsuite/tests/rename/should_fail/all.T1
-rw-r--r--testsuite/tests/rename/should_fail/rn_dup.hs2
-rw-r--r--testsuite/tests/rename/should_fail/rn_dup.stderr8
-rw-r--r--testsuite/tests/rename/should_fail/rnfail054.stderr6
-rw-r--r--testsuite/tests/rep-poly/T20113.stderr7
-rw-r--r--testsuite/tests/th/T10279.stderr7
-rw-r--r--testsuite/tests/th/T10828.hs5
-rw-r--r--testsuite/tests/th/T10828b.hs3
-rw-r--r--testsuite/tests/th/T10828b.stderr2
-rw-r--r--testsuite/tests/th/T11345.hs5
-rw-r--r--testsuite/tests/th/T11941.stderr8
-rw-r--r--testsuite/tests/th/T17379a.hs8
-rw-r--r--testsuite/tests/th/T17379a.stderr4
-rw-r--r--testsuite/tests/th/T17379b.hs8
-rw-r--r--testsuite/tests/th/T17379b.stderr4
-rw-r--r--testsuite/tests/th/all.T2
-rw-r--r--testsuite/tests/typecheck/should_compile/QualifiedRecordUpdate.hs10
-rw-r--r--testsuite/tests/typecheck/should_compile/QualifiedRecordUpdate_aux.hs6
-rw-r--r--testsuite/tests/typecheck/should_compile/T21443.hs10
-rw-r--r--testsuite/tests/typecheck/should_compile/all.T6
-rw-r--r--testsuite/tests/typecheck/should_fail/T12035.hs2
-rw-r--r--testsuite/tests/typecheck/should_fail/T21444.hs8
-rw-r--r--testsuite/tests/typecheck/should_fail/T21444.stderr6
-rw-r--r--testsuite/tests/typecheck/should_fail/T7989.stderr15
-rw-r--r--testsuite/tests/typecheck/should_fail/all.T1
-rw-r--r--testsuite/tests/typecheck/should_fail/tcfail114.stderr6
-rw-r--r--testsuite/tests/warnings/should_compile/DodgyExports01.stderr3
-rw-r--r--utils/check-exact/ExactPrint.hs18
m---------utils/haddock0
275 files changed, 6237 insertions, 4222 deletions
diff --git a/compiler/GHC.hs b/compiler/GHC.hs
index a6cce31837..0182b5a2a1 100644
--- a/compiler/GHC.hs
+++ b/compiler/GHC.hs
@@ -1,7 +1,6 @@
{-# LANGUAGE CPP #-}
{-# LANGUAGE NondecreasingIndentation, ScopedTypeVariables #-}
{-# LANGUAGE TupleSections, NamedFieldPuns #-}
-{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE TypeFamilies #-}
-- -----------------------------------------------------------------------------
@@ -342,7 +341,7 @@ import GHC.Builtin.Types.Prim ( alphaTyVars )
import GHC.Data.StringBuffer
import GHC.Data.FastString
import qualified GHC.LanguageExtensions as LangExt
-import GHC.Rename.Names (renamePkgQual, renameRawPkgQual)
+import GHC.Rename.Names (renamePkgQual, renameRawPkgQual, gresFromAvails)
import GHC.Tc.Utils.Monad ( finalSafeMode, fixSafeInstances, initIfaceTcRn )
import GHC.Tc.Types
@@ -353,6 +352,7 @@ import GHC.Tc.Instance.Family
import GHC.Utils.TmpFs
import GHC.Utils.Error
+import GHC.Utils.Exception
import GHC.Utils.Monad
import GHC.Utils.Misc
import GHC.Utils.Outputable
@@ -373,6 +373,8 @@ import GHC.Core.FamInstEnv ( FamInst, famInstEnvElts, orphNamesOfFamInst )
import GHC.Core.InstEnv
import GHC.Core
+import GHC.Data.Maybe
+
import GHC.Types.Id
import GHC.Types.Name hiding ( varName )
import GHC.Types.Avail
@@ -405,29 +407,26 @@ import GHC.Unit.Module.ModSummary
import GHC.Unit.Module.Graph
import GHC.Unit.Home.ModInfo
+import Control.Applicative ((<|>))
+import Control.Concurrent
+import Control.Monad
+import Control.Monad.Catch as MC
import Data.Foldable
+import Data.IORef
+import Data.List (isPrefixOf)
+import Data.Typeable ( Typeable )
+import Data.Word ( Word8 )
+
import qualified Data.Map.Strict as Map
import Data.Set (Set)
+import qualified Data.Set as S
import qualified Data.Sequence as Seq
-import Data.Maybe
-import Data.Typeable ( Typeable )
-import Data.Word ( Word8 )
-import Control.Monad
+
+import System.Directory
+import System.Environment ( getEnv, getProgName )
import System.Exit ( exitWith, ExitCode(..) )
-import GHC.Utils.Exception
-import Data.IORef
import System.FilePath
-import Control.Concurrent
-import Control.Applicative ((<|>))
-import Control.Monad.Catch as MC
-
-import GHC.Data.Maybe
import System.IO.Error ( isDoesNotExistError )
-import System.Environment ( getEnv, getProgName )
-import System.Directory
-import Data.List (isPrefixOf)
-import qualified Data.Set as S
-
-- %************************************************************************
-- %* *
@@ -1201,6 +1200,9 @@ typecheckModule pmod = do
details <- makeSimpleDetails lcl_logger tc_gbl_env
safe <- finalSafeMode lcl_dflags tc_gbl_env
+ let !rdr_env = forceGlobalRdrEnv $ tcg_rdr_env tc_gbl_env
+ -- See Note [Forcing GREInfo] in GHC.Types.GREInfo.
+
return $
TypecheckedModule {
tm_internals_ = (tc_gbl_env, details),
@@ -1211,7 +1213,7 @@ typecheckModule pmod = do
ModuleInfo {
minf_type_env = md_types details,
minf_exports = md_exports details,
- minf_rdr_env = Just (tcg_rdr_env tc_gbl_env),
+ minf_rdr_env = Just rdr_env,
minf_instances = fixSafeInstances safe $ instEnvElts $ md_insts details,
minf_iface = Nothing,
minf_safe = safe,
@@ -1364,7 +1366,7 @@ getNamePprCtx = withSession $ \hsc_env -> do
data ModuleInfo = ModuleInfo {
minf_type_env :: TypeEnv,
minf_exports :: [AvailInfo],
- minf_rdr_env :: Maybe GlobalRdrEnv, -- Nothing for a compiled/package mod
+ minf_rdr_env :: Maybe IfGlobalRdrEnv, -- Nothing for a compiled/package mod
minf_instances :: [ClsInst],
minf_iface :: Maybe ModIface,
minf_safe :: SafeHaskellMode,
@@ -1390,40 +1392,45 @@ getPackageModuleInfo hsc_env mdl
pte = eps_PTE eps
tys = [ ty | name <- concatMap availNames avails,
Just ty <- [lookupTypeEnv pte name] ]
- --
+
+ let !rdr_env = availsToGlobalRdrEnv hsc_env (moduleName mdl) avails
+ -- See Note [Forcing GREInfo] in GHC.Types.GREInfo.
+
return (Just (ModuleInfo {
minf_type_env = mkTypeEnv tys,
minf_exports = avails,
- minf_rdr_env = Just $! availsToGlobalRdrEnv (moduleName mdl) avails,
+ minf_rdr_env = Just rdr_env,
minf_instances = error "getModuleInfo: instances for package module unimplemented",
minf_iface = Just iface,
minf_safe = getSafeMode $ mi_trust iface,
minf_modBreaks = emptyModBreaks
}))
-availsToGlobalRdrEnv :: ModuleName -> [AvailInfo] -> GlobalRdrEnv
-availsToGlobalRdrEnv mod_name avails
- = mkGlobalRdrEnv (gresFromAvails (Just imp_spec) avails)
+availsToGlobalRdrEnv :: HasDebugCallStack => HscEnv -> ModuleName -> [AvailInfo] -> IfGlobalRdrEnv
+availsToGlobalRdrEnv hsc_env mod avails
+ = forceGlobalRdrEnv rdr_env
+ -- See Note [Forcing GREInfo] in GHC.Types.GREInfo.
where
+ rdr_env = mkGlobalRdrEnv (gresFromAvails hsc_env (Just imp_spec) avails)
-- We're building a GlobalRdrEnv as if the user imported
-- all the specified modules into the global interactive module
imp_spec = ImpSpec { is_decl = decl, is_item = ImpAll}
- decl = ImpDeclSpec { is_mod = mod_name, is_as = mod_name,
+ decl = ImpDeclSpec { is_mod = mod, is_as = mod,
is_qual = False,
is_dloc = srcLocSpan interactiveSrcLoc }
-
getHomeModuleInfo :: HscEnv -> Module -> IO (Maybe ModuleInfo)
getHomeModuleInfo hsc_env mdl =
case lookupHugByModule mdl (hsc_HUG hsc_env) of
Nothing -> return Nothing
Just hmi -> do
- let details = hm_details hmi
- iface = hm_iface hmi
+ let details = hm_details hmi
+ iface = hm_iface hmi
return (Just (ModuleInfo {
minf_type_env = md_types details,
minf_exports = md_exports details,
- minf_rdr_env = mi_globals $! hm_iface hmi,
+ minf_rdr_env = mi_globals $ hm_iface hmi,
+ -- NB: already forced. See Note [Forcing GREInfo] in GHC.Types.GREInfo.
minf_instances = instEnvElts $ md_insts details,
minf_iface = Just iface,
minf_safe = getSafeMode $ mi_trust iface
@@ -1436,13 +1443,15 @@ modInfoTyThings minf = typeEnvElts (minf_type_env minf)
modInfoTopLevelScope :: ModuleInfo -> Maybe [Name]
modInfoTopLevelScope minf
- = fmap (map greMangledName . globalRdrEnvElts) (minf_rdr_env minf)
+ = fmap (map greName . globalRdrEnvElts) (minf_rdr_env minf)
+ -- NB: no need to force this again.
+ -- See Note [Forcing GREInfo] in GHC.Types.GREInfo.
modInfoExports :: ModuleInfo -> [Name]
modInfoExports minf = concatMap availNames $! minf_exports minf
modInfoExportsWithSelectors :: ModuleInfo -> [Name]
-modInfoExportsWithSelectors minf = concatMap availNamesWithSelectors $! minf_exports minf
+modInfoExportsWithSelectors minf = concatMap availNames $! minf_exports minf
-- | Returns the instances defined by the specified module.
-- Warning: currently unimplemented for package modules.
@@ -1472,7 +1481,7 @@ modInfoLookupName minf name = withSession $ \hsc_env -> do
modInfoIface :: ModuleInfo -> Maybe ModIface
modInfoIface = minf_iface
-modInfoRdrEnv :: ModuleInfo -> Maybe GlobalRdrEnv
+modInfoRdrEnv :: ModuleInfo -> Maybe IfGlobalRdrEnv
modInfoRdrEnv = minf_rdr_env
-- | Retrieve module safe haskell mode
diff --git a/compiler/GHC/Builtin/Names.hs b/compiler/GHC/Builtin/Names.hs
index 34bd17a23f..8671b5521f 100644
--- a/compiler/GHC/Builtin/Names.hs
+++ b/compiler/GHC/Builtin/Names.hs
@@ -868,10 +868,10 @@ r1DataCon_RDR = dataQual_RDR gHC_GENERICS (fsLit "R1")
prodDataCon_RDR = dataQual_RDR gHC_GENERICS (fsLit ":*:")
comp1DataCon_RDR = dataQual_RDR gHC_GENERICS (fsLit "Comp1")
-unPar1_RDR = varQual_RDR gHC_GENERICS (fsLit "unPar1")
-unRec1_RDR = varQual_RDR gHC_GENERICS (fsLit "unRec1")
-unK1_RDR = varQual_RDR gHC_GENERICS (fsLit "unK1")
-unComp1_RDR = varQual_RDR gHC_GENERICS (fsLit "unComp1")
+unPar1_RDR = fieldQual_RDR gHC_GENERICS (fsLit "Par1") (fsLit "unPar1")
+unRec1_RDR = fieldQual_RDR gHC_GENERICS (fsLit "Rec1") (fsLit "unRec1")
+unK1_RDR = fieldQual_RDR gHC_GENERICS (fsLit "K1") (fsLit "unK1")
+unComp1_RDR = fieldQual_RDR gHC_GENERICS (fsLit "Comp1") (fsLit "unComp1")
from_RDR = varQual_RDR gHC_GENERICS (fsLit "from")
from1_RDR = varQual_RDR gHC_GENERICS (fsLit "from1")
@@ -900,12 +900,12 @@ uFloatDataCon_RDR = dataQual_RDR gHC_GENERICS (fsLit "UFloat")
uIntDataCon_RDR = dataQual_RDR gHC_GENERICS (fsLit "UInt")
uWordDataCon_RDR = dataQual_RDR gHC_GENERICS (fsLit "UWord")
-uAddrHash_RDR = varQual_RDR gHC_GENERICS (fsLit "uAddr#")
-uCharHash_RDR = varQual_RDR gHC_GENERICS (fsLit "uChar#")
-uDoubleHash_RDR = varQual_RDR gHC_GENERICS (fsLit "uDouble#")
-uFloatHash_RDR = varQual_RDR gHC_GENERICS (fsLit "uFloat#")
-uIntHash_RDR = varQual_RDR gHC_GENERICS (fsLit "uInt#")
-uWordHash_RDR = varQual_RDR gHC_GENERICS (fsLit "uWord#")
+uAddrHash_RDR = fieldQual_RDR gHC_GENERICS (fsLit "UAddr") (fsLit "uAddr#")
+uCharHash_RDR = fieldQual_RDR gHC_GENERICS (fsLit "UChar") (fsLit "uChar#")
+uDoubleHash_RDR = fieldQual_RDR gHC_GENERICS (fsLit "UDouble") (fsLit "uDouble#")
+uFloatHash_RDR = fieldQual_RDR gHC_GENERICS (fsLit "UFloat") (fsLit "uFloat#")
+uIntHash_RDR = fieldQual_RDR gHC_GENERICS (fsLit "UInt") (fsLit "uInt#")
+uWordHash_RDR = fieldQual_RDR gHC_GENERICS (fsLit "UWord") (fsLit "uWord#")
fmap_RDR, replace_RDR, pure_RDR, ap_RDR, liftA2_RDR, foldable_foldr_RDR,
foldMap_RDR, null_RDR, all_RDR, traverse_RDR, mempty_RDR,
@@ -931,6 +931,9 @@ tcQual_RDR mod str = mkOrig mod (mkOccNameFS tcName str)
clsQual_RDR mod str = mkOrig mod (mkOccNameFS clsName str)
dataQual_RDR mod str = mkOrig mod (mkOccNameFS dataName str)
+fieldQual_RDR :: Module -> FastString -> FastString -> RdrName
+fieldQual_RDR mod con str = mkOrig mod (mkOccNameFS (fieldName con) str)
+
{-
************************************************************************
* *
diff --git a/compiler/GHC/Builtin/Names/TH.hs b/compiler/GHC/Builtin/Names/TH.hs
index bea3b9715f..c7e817c47e 100644
--- a/compiler/GHC/Builtin/Names/TH.hs
+++ b/compiler/GHC/Builtin/Names/TH.hs
@@ -11,9 +11,9 @@ import GHC.Prelude ()
import GHC.Builtin.Names( mk_known_key_name )
import GHC.Unit.Types
import GHC.Types.Name( Name )
-import GHC.Types.Name.Occurrence( tcName, clsName, dataName, varName )
+import GHC.Types.Name.Occurrence( tcName, clsName, dataName, varName, fieldName )
import GHC.Types.Name.Reader( RdrName, nameRdrName )
-import GHC.Types.Unique
+import GHC.Types.Unique ( Unique )
import GHC.Builtin.Uniques
import GHC.Data.FastString
@@ -31,7 +31,8 @@ templateHaskellNames :: [Name]
templateHaskellNames = [
returnQName, bindQName, sequenceQName, newNameName, liftName, liftTypedName,
- mkNameName, mkNameG_vName, mkNameG_dName, mkNameG_tcName, mkNameLName,
+ mkNameName, mkNameG_vName, mkNameG_dName, mkNameG_tcName, mkNameG_fldName,
+ mkNameLName,
mkNameSName, mkNameQName,
mkModNameName,
liftStringName,
@@ -174,14 +175,19 @@ qqLib = mkTHModule (fsLit "Language.Haskell.TH.Quote")
mkTHModule :: FastString -> Module
mkTHModule m = mkModule thUnit (mkModuleNameFS m)
-libFun, libTc, thFun, thTc, thCls, thCon, qqFun :: FastString -> Unique -> Name
+libFun, libTc, thFun, thTc, thCls, thCon :: FastString -> Unique -> Name
libFun = mk_known_key_name varName thLib
libTc = mk_known_key_name tcName thLib
thFun = mk_known_key_name varName thSyn
thTc = mk_known_key_name tcName thSyn
thCls = mk_known_key_name clsName thSyn
thCon = mk_known_key_name dataName thSyn
-qqFun = mk_known_key_name varName qqLib
+
+thFld :: FastString -> FastString -> Unique -> Name
+thFld con = mk_known_key_name (fieldName con) thSyn
+
+qqFld :: FastString -> Unique -> Name
+qqFld = mk_known_key_name (fieldName (fsLit "QuasiQuoter")) qqLib
-------------------- TH.Syntax -----------------------
liftClassName :: Name
@@ -214,7 +220,7 @@ overlapTyConName = thTc (fsLit "Overlap") overlapTyConKey
modNameTyConName = thTc (fsLit "ModName") modNameTyConKey
returnQName, bindQName, sequenceQName, newNameName, liftName,
- mkNameName, mkNameG_vName, mkNameG_dName, mkNameG_tcName,
+ mkNameName, mkNameG_vName, mkNameG_fldName, mkNameG_dName, mkNameG_tcName,
mkNameLName, mkNameSName, liftStringName, unTypeName, unTypeCodeName,
unsafeCodeCoerceName, liftTypedName, mkModNameName, mkNameQName :: Name
returnQName = thFun (fsLit "returnQ") returnQIdKey
@@ -227,11 +233,12 @@ mkNameName = thFun (fsLit "mkName") mkNameIdKey
mkNameG_vName = thFun (fsLit "mkNameG_v") mkNameG_vIdKey
mkNameG_dName = thFun (fsLit "mkNameG_d") mkNameG_dIdKey
mkNameG_tcName = thFun (fsLit "mkNameG_tc") mkNameG_tcIdKey
+mkNameG_fldName= thFun (fsLit "mkNameG_fld") mkNameG_fldIdKey
mkNameLName = thFun (fsLit "mkNameL") mkNameLIdKey
mkNameQName = thFun (fsLit "mkNameQ") mkNameQIdKey
mkNameSName = thFun (fsLit "mkNameS") mkNameSIdKey
mkModNameName = thFun (fsLit "mkModName") mkModNameIdKey
-unTypeName = thFun (fsLit "unType") unTypeIdKey
+unTypeName = thFld (fsLit "TExp") (fsLit "unType") unTypeIdKey
unTypeCodeName = thFun (fsLit "unTypeCode") unTypeCodeIdKey
unsafeCodeCoerceName = thFun (fsLit "unsafeCodeCoerce") unsafeCodeCoerceIdKey
liftTypedName = thFun (fsLit "liftTyped") liftTypedIdKey
@@ -593,10 +600,10 @@ derivStrategyTyConName = thTc (fsLit "DerivStrategy") derivStrategyTyConKey
-- quasiquoting
quoteExpName, quotePatName, quoteDecName, quoteTypeName :: Name
-quoteExpName = qqFun (fsLit "quoteExp") quoteExpKey
-quotePatName = qqFun (fsLit "quotePat") quotePatKey
-quoteDecName = qqFun (fsLit "quoteDec") quoteDecKey
-quoteTypeName = qqFun (fsLit "quoteType") quoteTypeKey
+quoteExpName = qqFld (fsLit "quoteExp") quoteExpKey
+quotePatName = qqFld (fsLit "quotePat") quotePatKey
+quoteDecName = qqFld (fsLit "quoteDec") quoteDecKey
+quoteTypeName = qqFld (fsLit "quoteType") quoteTypeKey
-- data Inline = ...
noInlineDataConName, inlineDataConName, inlinableDataConName :: Name
@@ -741,7 +748,7 @@ incoherentDataConKey = mkPreludeDataConUnique 212
-- If you want to change this, make sure you check in GHC.Builtin.Names
returnQIdKey, bindQIdKey, sequenceQIdKey, liftIdKey, newNameIdKey,
- mkNameIdKey, mkNameG_vIdKey, mkNameG_dIdKey, mkNameG_tcIdKey,
+ mkNameIdKey, mkNameG_vIdKey, mkNameG_fldIdKey, mkNameG_dIdKey, mkNameG_tcIdKey,
mkNameLIdKey, mkNameSIdKey, unTypeIdKey, unTypeCodeIdKey,
unsafeCodeCoerceIdKey, liftTypedIdKey, mkModNameIdKey, mkNameQIdKey :: Unique
returnQIdKey = mkPreludeMiscIdUnique 200
@@ -761,6 +768,7 @@ liftTypedIdKey = mkPreludeMiscIdUnique 214
mkModNameIdKey = mkPreludeMiscIdUnique 215
unsafeCodeCoerceIdKey = mkPreludeMiscIdUnique 216
mkNameQIdKey = mkPreludeMiscIdUnique 217
+mkNameG_fldIdKey = mkPreludeMiscIdUnique 218
-- data Lit = ...
@@ -1114,12 +1122,14 @@ inferredSpecKey = mkPreludeMiscIdUnique 499
************************************************************************
-}
-lift_RDR, liftTyped_RDR, mkNameG_dRDR, mkNameG_vRDR, unsafeCodeCoerce_RDR :: RdrName
+lift_RDR, liftTyped_RDR, mkNameG_dRDR, mkNameG_vRDR, mkNameG_fldRDR,
+ unsafeCodeCoerce_RDR :: RdrName
lift_RDR = nameRdrName liftName
liftTyped_RDR = nameRdrName liftTypedName
unsafeCodeCoerce_RDR = nameRdrName unsafeCodeCoerceName
mkNameG_dRDR = nameRdrName mkNameG_dName
mkNameG_vRDR = nameRdrName mkNameG_vName
+mkNameG_fldRDR = nameRdrName mkNameG_fldName
-- data Exp = ...
conE_RDR, litE_RDR, appE_RDR, infixApp_RDR :: RdrName
diff --git a/compiler/GHC/Builtin/Uniques.hs b/compiler/GHC/Builtin/Uniques.hs
index 1a440792e5..7b95c5d11e 100644
--- a/compiler/GHC/Builtin/Uniques.hs
+++ b/compiler/GHC/Builtin/Uniques.hs
@@ -31,10 +31,12 @@ module GHC.Builtin.Uniques
, mkPreludeMiscIdUnique, mkPreludeDataConUnique
, mkPreludeTyConUnique, mkPreludeClassUnique
- , mkVarOccUnique, mkDataOccUnique, mkTvOccUnique, mkTcOccUnique
, mkRegSingleUnique, mkRegPairUnique, mkRegClassUnique, mkRegSubUnique
, mkCostCentreUnique
+ , varNSUnique, dataNSUnique, tvNSUnique, tcNSUnique
+ , mkFldNSUnique, isFldNSUnique
+
, mkBuiltinUnique
, mkPseudoUniqueE
@@ -378,12 +380,18 @@ mkRegClassUnique = mkUnique 'L'
mkCostCentreUnique :: Int -> Unique
mkCostCentreUnique = mkUnique 'C'
-mkVarOccUnique, mkDataOccUnique, mkTvOccUnique, mkTcOccUnique :: FastString -> Unique
--- See Note [The Unique of an OccName] in GHC.Types.Name.Occurrence
-mkVarOccUnique fs = mkUnique 'i' (uniqueOfFS fs)
-mkDataOccUnique fs = mkUnique 'd' (uniqueOfFS fs)
-mkTvOccUnique fs = mkUnique 'v' (uniqueOfFS fs)
-mkTcOccUnique fs = mkUnique 'c' (uniqueOfFS fs)
+varNSUnique, dataNSUnique, tvNSUnique, tcNSUnique :: Unique
+varNSUnique = mkUnique 'i' 0
+dataNSUnique = mkUnique 'd' 0
+tvNSUnique = mkUnique 'v' 0
+tcNSUnique = mkUnique 'c' 0
+
+mkFldNSUnique :: FastString -> Unique
+mkFldNSUnique fs = mkUnique 'f' (uniqueOfFS fs)
+
+isFldNSUnique :: Unique -> Bool
+isFldNSUnique uniq = case unpkUnique uniq of
+ (tag, _) -> tag == 'f'
initExitJoinUnique :: Unique
initExitJoinUnique = mkUnique 's' 0
diff --git a/compiler/GHC/Builtin/Uniques.hs-boot b/compiler/GHC/Builtin/Uniques.hs-boot
index 7c012262b1..2ec48fa293 100644
--- a/compiler/GHC/Builtin/Uniques.hs-boot
+++ b/compiler/GHC/Builtin/Uniques.hs-boot
@@ -4,7 +4,6 @@ import GHC.Prelude
import GHC.Types.Unique
import {-# SOURCE #-} GHC.Types.Name
import GHC.Types.Basic
-import GHC.Data.FastString
-- Needed by GHC.Builtin.Types
knownUniqueName :: Unique -> Maybe Name
@@ -27,7 +26,6 @@ mkPreludeMiscIdUnique :: Int -> Unique
mkPseudoUniqueE, mkBuiltinUnique :: Int -> Unique
mkRegSingleUnique, mkRegPairUnique, mkRegSubUnique, mkRegClassUnique :: Int -> Unique
-mkVarOccUnique, mkDataOccUnique, mkTvOccUnique, mkTcOccUnique :: FastString -> Unique
initExitJoinUnique :: Unique
diff --git a/compiler/GHC/Builtin/Utils.hs b/compiler/GHC/Builtin/Utils.hs
index a815c5e5bb..10fb526752 100644
--- a/compiler/GHC/Builtin/Utils.hs
+++ b/compiler/GHC/Builtin/Utils.hs
@@ -239,10 +239,10 @@ sense of them in interface pragmas. It's cool, though they all have
ghcPrimExports :: [IfaceExport]
ghcPrimExports
- = map (avail . idName) ghcPrimIds ++
- map (avail . idName) allThePrimOpIds ++
- [ availTC n [n] []
- | tc <- exposedPrimTyCons, let n = tyConName tc ]
+ = map (Avail . idName) ghcPrimIds ++
+ map (Avail . idName) allThePrimOpIds ++
+ [ AvailTC n [n]
+ | tc <- exposedPrimTyCons, let n = tyConName tc ]
ghcPrimDeclDocs :: Docs
ghcPrimDeclDocs = emptyDocs { docs_decls = listToUniqMap $ mapMaybe findName primOpDocs }
diff --git a/compiler/GHC/ByteCode/Linker.hs b/compiler/GHC/ByteCode/Linker.hs
index 8a7a24ae1a..4419309788 100644
--- a/compiler/GHC/ByteCode/Linker.hs
+++ b/compiler/GHC/ByteCode/Linker.hs
@@ -194,7 +194,7 @@ nameToCLabel n suffix = mkFastString label
mod -> mod
packagePart = encodeZ (unitFS pkgKey)
modulePart = encodeZ (moduleNameFS modName)
- occPart = encodeZ (occNameFS (nameOccName n))
+ occPart = encodeZ $ occNameMangledFS (nameOccName n)
label = concat
[ if pkgKey == mainUnit then "" else packagePart ++ "_"
diff --git a/compiler/GHC/Core/ConLike.hs b/compiler/GHC/Core/ConLike.hs
index f1b147c972..e609bd4b51 100644
--- a/compiler/GHC/Core/ConLike.hs
+++ b/compiler/GHC/Core/ConLike.hs
@@ -9,9 +9,11 @@
module GHC.Core.ConLike (
ConLike(..)
+ , conLikeConLikeName
, isVanillaConLike
, conLikeArity
, conLikeFieldLabels
+ , conLikeConInfo
, conLikeInstOrigArgTys
, conLikeUserTyVarBinders
, conLikeExTyCoVars
@@ -29,16 +31,19 @@ module GHC.Core.ConLike (
import GHC.Prelude
import GHC.Core.DataCon
+import GHC.Core.Multiplicity
import GHC.Core.PatSyn
-import GHC.Utils.Outputable
+import GHC.Core.TyCo.Rep (Type, ThetaType)
+import GHC.Core.Type(mkTyConApp)
import GHC.Types.Unique
-import GHC.Utils.Misc
import GHC.Types.Name
+import GHC.Types.Name.Reader
import GHC.Types.Basic
-import GHC.Core.TyCo.Rep (Type, ThetaType)
+
+import GHC.Types.GREInfo
import GHC.Types.Var
-import GHC.Core.Type(mkTyConApp)
-import GHC.Core.Multiplicity
+import GHC.Utils.Misc
+import GHC.Utils.Outputable
import Data.Maybe( isJust )
import qualified Data.Data as Data
@@ -61,6 +66,10 @@ isVanillaConLike :: ConLike -> Bool
isVanillaConLike (RealDataCon con) = isVanillaDataCon con
isVanillaConLike (PatSynCon ps ) = isVanillaPatSyn ps
+conLikeConLikeName :: ConLike -> ConLikeName
+conLikeConLikeName (RealDataCon dc) = DataConName (dataConName dc)
+conLikeConLikeName (PatSynCon ps) = PatSynName (patSynName ps)
+
{-
************************************************************************
* *
@@ -113,6 +122,11 @@ conLikeFieldLabels :: ConLike -> [FieldLabel]
conLikeFieldLabels (RealDataCon data_con) = dataConFieldLabels data_con
conLikeFieldLabels (PatSynCon pat_syn) = patSynFieldLabels pat_syn
+-- | The 'ConInfo' (arity and field labels) associated to a 'ConLike'.
+conLikeConInfo :: ConLike -> ConInfo
+conLikeConInfo con =
+ mkConInfo (conLikeArity con) (conLikeFieldLabels con)
+
-- | Returns just the instantiated /value/ argument types of a 'ConLike',
-- (excluding dictionary args)
conLikeInstOrigArgTys :: ConLike -> [Type] -> [Scaled Type]
diff --git a/compiler/GHC/Core/DataCon.hs b/compiler/GHC/Core/DataCon.hs
index f54f42d99d..c86e2c8625 100644
--- a/compiler/GHC/Core/DataCon.hs
+++ b/compiler/GHC/Core/DataCon.hs
@@ -22,7 +22,7 @@ module GHC.Core.DataCon (
eqSpecPair, eqSpecPreds,
-- ** Field labels
- FieldLabel(..), FieldLabelString,
+ FieldLabel(..), flLabel, FieldLabelString,
-- ** Type construction
mkDataCon, fIRST_TAG,
diff --git a/compiler/GHC/Core/LateCC.hs b/compiler/GHC/Core/LateCC.hs
index 9a2d43a9cb..ba65820784 100644
--- a/compiler/GHC/Core/LateCC.hs
+++ b/compiler/GHC/Core/LateCC.hs
@@ -117,7 +117,7 @@ doBndr env bndr rhs
| otherwise = doBndr' env bndr rhs
--- We want to put the cost centra below the lambda as we only care about executions of the RHS.
+-- We want to put the cost centre below the lambda as we only care about executions of the RHS.
doBndr' :: Env -> Id -> CoreExpr -> State LateCCState CoreExpr
doBndr' env bndr (Lam b rhs) = Lam b <$> doBndr' env bndr rhs
doBndr' env bndr rhs = do
diff --git a/compiler/GHC/Core/Map/Type.hs b/compiler/GHC/Core/Map/Type.hs
index 3629bc11a9..d94f97fb19 100644
--- a/compiler/GHC/Core/Map/Type.hs
+++ b/compiler/GHC/Core/Map/Type.hs
@@ -397,7 +397,7 @@ xtTyLit l f m =
CharTyLit n -> m { tlm_char = Map.alter f n (tlm_char m) }
foldTyLit :: (a -> b -> b) -> TyLitMap a -> b -> b
-foldTyLit l m = flip (foldUFM l) (tlm_string m)
+foldTyLit l m = flip (nonDetFoldUFM l) (tlm_string m)
. flip (Map.foldr l) (tlm_number m)
. flip (Map.foldr l) (tlm_char m)
diff --git a/compiler/GHC/Core/TyCon.hs b/compiler/GHC/Core/TyCon.hs
index d251d071fd..d06565deec 100644
--- a/compiler/GHC/Core/TyCon.hs
+++ b/compiler/GHC/Core/TyCon.hs
@@ -899,7 +899,7 @@ data TyConDetails =
tctc_is_poly :: Bool, -- ^ Is this TcTyCon already generalized?
-- Used only to make zonking more efficient
- tctc_flavour :: TyConFlavour
+ tctc_flavour :: TyConFlavour TyCon
-- ^ What sort of 'TyCon' this represents.
}
@@ -1845,7 +1845,7 @@ mkTcTyCon :: Name
-> [(Name,TcTyVar)] -- ^ Scoped type variables;
-- see Note [How TcTyCons work] in GHC.Tc.TyCl
-> Bool -- ^ Is this TcTyCon generalised already?
- -> TyConFlavour -- ^ What sort of 'TyCon' this represents
+ -> TyConFlavour TyCon -- ^ What sort of 'TyCon' this represents
-> TyCon
mkTcTyCon name binders res_kind scoped_tvs poly flav
= mkTyCon name binders res_kind (constRoles binders Nominal) $
@@ -2178,12 +2178,6 @@ isTyConAssoc = isJust . tyConAssoc_maybe
tyConAssoc_maybe :: TyCon -> Maybe TyCon
tyConAssoc_maybe = tyConFlavourAssoc_maybe . tyConFlavour
--- | Get the enclosing class TyCon (if there is one) for the given TyConFlavour
-tyConFlavourAssoc_maybe :: TyConFlavour -> Maybe TyCon
-tyConFlavourAssoc_maybe (DataFamilyFlavour mb_parent) = mb_parent
-tyConFlavourAssoc_maybe (OpenTypeFamilyFlavour mb_parent) = mb_parent
-tyConFlavourAssoc_maybe _ = Nothing
-
-- The unit tycon didn't used to be classed as a tuple tycon
-- but I thought that was silly so I've undone it
-- If it can't be for some reason, it should be a AlgTyCon
@@ -2363,7 +2357,7 @@ isConcreteTyCon = isConcreteTyConFlavour . tyConFlavour
-- | Is this 'TyConFlavour' concrete (i.e. not a synonym/type family)?
--
-- Used for representation polymorphism checks.
-isConcreteTyConFlavour :: TyConFlavour -> Bool
+isConcreteTyConFlavour :: TyConFlavour tc -> Bool
isConcreteTyConFlavour = \case
ClassFlavour -> True
TupleFlavour {} -> True
@@ -2371,8 +2365,7 @@ isConcreteTyConFlavour = \case
DataTypeFlavour -> True
NewtypeFlavour -> True
AbstractTypeFlavour -> True -- See Note [Concrete types] in GHC.Tc.Utils.Concrete
- DataFamilyFlavour {} -> False
- OpenTypeFamilyFlavour {} -> False
+ OpenFamilyFlavour {} -> False
ClosedTypeFamilyFlavour -> False
TypeSynonymFlavour -> False
BuiltInTypeFlavour -> True
@@ -2725,43 +2718,7 @@ instance Outputable TyCon where
then text "[tc]"
else empty
--- | Paints a picture of what a 'TyCon' represents, in broad strokes.
--- This is used towards more informative error messages.
-data TyConFlavour
- = ClassFlavour
- | TupleFlavour Boxity
- | SumFlavour
- | DataTypeFlavour
- | NewtypeFlavour
- | AbstractTypeFlavour
- | DataFamilyFlavour (Maybe TyCon) -- Just tc <=> (tc == associated class)
- | OpenTypeFamilyFlavour (Maybe TyCon) -- Just tc <=> (tc == associated class)
- | ClosedTypeFamilyFlavour
- | TypeSynonymFlavour
- | BuiltInTypeFlavour -- ^ e.g., the @(->)@ 'TyCon'.
- | PromotedDataConFlavour
- deriving Eq
-
-instance Outputable TyConFlavour where
- ppr = text . go
- where
- go ClassFlavour = "class"
- go (TupleFlavour boxed) | isBoxed boxed = "tuple"
- | otherwise = "unboxed tuple"
- go SumFlavour = "unboxed sum"
- go DataTypeFlavour = "data type"
- go NewtypeFlavour = "newtype"
- go AbstractTypeFlavour = "abstract type"
- go (DataFamilyFlavour (Just _)) = "associated data family"
- go (DataFamilyFlavour Nothing) = "data family"
- go (OpenTypeFamilyFlavour (Just _)) = "associated type family"
- go (OpenTypeFamilyFlavour Nothing) = "type family"
- go ClosedTypeFamilyFlavour = "type family"
- go TypeSynonymFlavour = "type synonym"
- go BuiltInTypeFlavour = "built-in type"
- go PromotedDataConFlavour = "promoted data constructor"
-
-tyConFlavour :: TyCon -> TyConFlavour
+tyConFlavour :: TyCon -> TyConFlavour TyCon
tyConFlavour (TyCon { tyConDetails = details })
| AlgTyCon { algTcFlavour = parent, algTcRhs = rhs } <- details
= case parent of
@@ -2776,8 +2733,8 @@ tyConFlavour (TyCon { tyConDetails = details })
| FamilyTyCon { famTcFlav = flav, famTcParent = parent } <- details
= case flav of
- DataFamilyTyCon{} -> DataFamilyFlavour parent
- OpenSynFamilyTyCon -> OpenTypeFamilyFlavour parent
+ DataFamilyTyCon{} -> OpenFamilyFlavour IAmData parent
+ OpenSynFamilyTyCon -> OpenFamilyFlavour IAmType parent
ClosedSynFamilyTyCon{} -> ClosedTypeFamilyFlavour
AbstractClosedSynFamilyTyCon -> ClosedTypeFamilyFlavour
BuiltInSynFamTyCon{} -> ClosedTypeFamilyFlavour
@@ -2788,24 +2745,22 @@ tyConFlavour (TyCon { tyConDetails = details })
| TcTyCon { tctc_flavour = flav } <-details = flav
-- | Can this flavour of 'TyCon' appear unsaturated?
-tcFlavourMustBeSaturated :: TyConFlavour -> Bool
+tcFlavourMustBeSaturated :: TyConFlavour tc -> Bool
tcFlavourMustBeSaturated ClassFlavour = False
tcFlavourMustBeSaturated DataTypeFlavour = False
tcFlavourMustBeSaturated NewtypeFlavour = False
-tcFlavourMustBeSaturated DataFamilyFlavour{} = False
tcFlavourMustBeSaturated TupleFlavour{} = False
tcFlavourMustBeSaturated SumFlavour = False
tcFlavourMustBeSaturated AbstractTypeFlavour {} = False
tcFlavourMustBeSaturated BuiltInTypeFlavour = False
tcFlavourMustBeSaturated PromotedDataConFlavour = False
+tcFlavourMustBeSaturated (OpenFamilyFlavour td _)= case td of { IAmData -> False; IAmType -> True }
tcFlavourMustBeSaturated TypeSynonymFlavour = True
-tcFlavourMustBeSaturated OpenTypeFamilyFlavour{} = True
tcFlavourMustBeSaturated ClosedTypeFamilyFlavour = True
-- | Is this flavour of 'TyCon' an open type family or a data family?
-tcFlavourIsOpen :: TyConFlavour -> Bool
-tcFlavourIsOpen DataFamilyFlavour{} = True
-tcFlavourIsOpen OpenTypeFamilyFlavour{} = True
+tcFlavourIsOpen :: TyConFlavour tc -> Bool
+tcFlavourIsOpen OpenFamilyFlavour{} = True
tcFlavourIsOpen ClosedTypeFamilyFlavour = False
tcFlavourIsOpen ClassFlavour = False
tcFlavourIsOpen DataTypeFlavour = False
diff --git a/compiler/GHC/Core/TyCon/Env.hs b/compiler/GHC/Core/TyCon/Env.hs
index ff9b954324..3bdc0085be 100644
--- a/compiler/GHC/Core/TyCon/Env.hs
+++ b/compiler/GHC/Core/TyCon/Env.hs
@@ -100,7 +100,7 @@ extendTyConEnvList_C x y z = addListToUFM_C x y z
delFromTyConEnv x y = delFromUFM x y
delListFromTyConEnv x y = delListFromUFM x y
filterTyConEnv x y = filterUFM x y
-anyTyConEnv f x = foldUFM ((||) . f) False x
+anyTyConEnv f x = nonDetFoldUFM ((||) . f) False x
disjointTyConEnv x y = disjointUFM x y
lookupTyConEnv_NF env n = expectJust "lookupTyConEnv_NF" (lookupTyConEnv env n)
diff --git a/compiler/GHC/CoreToIface.hs b/compiler/GHC/CoreToIface.hs
index f0e2c0ad5f..e6d3fe93b7 100644
--- a/compiler/GHC/CoreToIface.hs
+++ b/compiler/GHC/CoreToIface.hs
@@ -452,14 +452,15 @@ toIfaceTopBndr id
toIfaceIdDetails :: IdDetails -> IfaceIdDetails
toIfaceIdDetails VanillaId = IfVanillaId
-toIfaceIdDetails (WorkerLikeId dmds) = IfWorkerLikeId dmds
+toIfaceIdDetails (WorkerLikeId dmds) = IfWorkerLikeId dmds
toIfaceIdDetails (DFunId {}) = IfDFunId
toIfaceIdDetails (RecSelId { sel_naughty = n
- , sel_tycon = tc }) =
- let iface = case tc of
- RecSelData ty_con -> Left (toIfaceTyCon ty_con)
- RecSelPatSyn pat_syn -> Right (patSynToIfaceDecl pat_syn)
- in IfRecSelId iface n
+ , sel_tycon = tc
+ , sel_fieldLabel = fl }) =
+ let (iface, first_con) = case tc of
+ RecSelData ty_con -> ( Left (toIfaceTyCon ty_con), dataConName $ head $ tyConDataCons ty_con)
+ RecSelPatSyn pat_syn -> ( Right (patSynToIfaceDecl pat_syn), patSynName pat_syn)
+ in IfRecSelId iface first_con n fl
-- The remaining cases are all "implicit Ids" which don't
-- appear in interface files at all
@@ -661,7 +662,7 @@ toIfaceVar v
-- Foreign calls have special syntax
| isExternalName name = IfaceExt name
- | otherwise = IfaceLcl (getOccFS name)
+ | otherwise = IfaceLcl (occNameFS $ nameOccName name)
where
name = idName v
ty = idType v
diff --git a/compiler/GHC/Data/FastString/Env.hs b/compiler/GHC/Data/FastString/Env.hs
index 05db9ace2a..7c692634f3 100644
--- a/compiler/GHC/Data/FastString/Env.hs
+++ b/compiler/GHC/Data/FastString/Env.hs
@@ -18,7 +18,8 @@ module GHC.Data.FastString.Env (
filterFsEnv,
plusFsEnv, plusFsEnv_C, alterFsEnv,
lookupFsEnv, lookupFsEnv_NF, delFromFsEnv, delListFromFsEnv,
- elemFsEnv, mapFsEnv,
+ elemFsEnv, mapFsEnv, strictMapFsEnv, mapMaybeFsEnv,
+ nonDetFoldFsEnv,
-- * Deterministic FastString environments (maps)
DFastStringEnv,
@@ -60,6 +61,7 @@ lookupFsEnv :: FastStringEnv a -> FastString -> Maybe a
lookupFsEnv_NF :: FastStringEnv a -> FastString -> a
filterFsEnv :: (elt -> Bool) -> FastStringEnv elt -> FastStringEnv elt
mapFsEnv :: (elt1 -> elt2) -> FastStringEnv elt1 -> FastStringEnv elt2
+mapMaybeFsEnv :: (elt1 -> Maybe elt2) -> FastStringEnv elt1 -> FastStringEnv elt2
emptyFsEnv = emptyUFM
unitFsEnv x y = unitUFM x y
@@ -78,9 +80,20 @@ extendFsEnvList_C x y z = addListToUFM_C x y z
delFromFsEnv x y = delFromUFM x y
delListFromFsEnv x y = delListFromUFM x y
filterFsEnv x y = filterUFM x y
+mapMaybeFsEnv f x = mapMaybeUFM f x
lookupFsEnv_NF env n = expectJust "lookupFsEnv_NF" (lookupFsEnv env n)
+strictMapFsEnv :: (a -> b) -> FastStringEnv a -> FastStringEnv b
+strictMapFsEnv = strictMapUFM
+
+-- | Fold over a 'FastStringEnv'.
+--
+-- Non-deterministic, unless the folding function is commutative
+-- (i.e. @a1 `f` ( a2 `f` b ) == a2 `f` ( a1 `f` b )@ for all @a1@, @a2@, @b@).
+nonDetFoldFsEnv :: (a -> b -> b) -> b -> FastStringEnv a -> b
+nonDetFoldFsEnv = nonDetFoldUFM
+
-- Deterministic FastStringEnv
-- See Note [Deterministic UniqFM] in GHC.Types.Unique.DFM for explanation why we need
-- DFastStringEnv.
diff --git a/compiler/GHC/Driver/Env.hs b/compiler/GHC/Driver/Env.hs
index 13898f85f4..c9967c7120 100644
--- a/compiler/GHC/Driver/Env.hs
+++ b/compiler/GHC/Driver/Env.hs
@@ -327,20 +327,23 @@ lookupType :: HscEnv -> Name -> IO (Maybe TyThing)
lookupType hsc_env name = do
eps <- liftIO $ hscEPS hsc_env
let pte = eps_PTE eps
- hpt = hsc_HUG hsc_env
-
- mod = assertPpr (isExternalName name) (ppr name) $
- if isHoleName name
- then mkHomeModule (hsc_home_unit hsc_env) (moduleName (nameModule name))
- else nameModule name
-
- !ty = if isOneShot (ghcMode (hsc_dflags hsc_env))
- -- in one-shot, we don't use the HPT
- then lookupNameEnv pte name
- else case lookupHugByModule mod hpt of
- Just hm -> lookupNameEnv (md_types (hm_details hm)) name
- Nothing -> lookupNameEnv pte name
- pure ty
+ return $ lookupTypeInPTE hsc_env pte name
+
+lookupTypeInPTE :: HscEnv -> PackageTypeEnv -> Name -> Maybe TyThing
+lookupTypeInPTE hsc_env pte name = ty
+ where
+ hpt = hsc_HUG hsc_env
+ mod = assertPpr (isExternalName name) (ppr name) $
+ if isHoleName name
+ then mkHomeModule (hsc_home_unit hsc_env) (moduleName (nameModule name))
+ else nameModule name
+
+ !ty = if isOneShot (ghcMode (hsc_dflags hsc_env))
+ -- in one-shot, we don't use the HPT
+ then lookupNameEnv pte name
+ else case lookupHugByModule mod hpt of
+ Just hm -> lookupNameEnv (md_types (hm_details hm)) name
+ Nothing -> lookupNameEnv pte name
-- | Find the 'ModIface' for a 'Module', searching in both the loaded home
-- and external package module information
diff --git a/compiler/GHC/Hs/Decls.hs b/compiler/GHC/Hs/Decls.hs
index fa62c6a49c..201adc5467 100644
--- a/compiler/GHC/Hs/Decls.hs
+++ b/compiler/GHC/Hs/Decls.hs
@@ -124,7 +124,6 @@ import GHC.Utils.Panic
import GHC.Types.SrcLoc
import GHC.Types.SourceText
import GHC.Core.Type
-import GHC.Core.TyCon (TyConFlavour(NewtypeFlavour,DataTypeFlavour))
import GHC.Types.ForeignCall
import GHC.Unit.Module.Warnings (WarningTxt(..))
@@ -704,7 +703,7 @@ ppDataDefnHeader pp_hdr HsDataDefn
| isTypeDataDefnCons condecls = text "type"
| otherwise = empty
pp_ct = case mb_ct of
- Nothing -> empty
+ Nothing -> empty
Just ct -> ppr ct
pp_sig = case mb_sig of
Nothing -> empty
@@ -935,7 +934,7 @@ instDeclDataFamInsts inst_decls
do_one (L _ (TyFamInstD {})) = []
-- | Convert a 'NewOrData' to a 'TyConFlavour'
-newOrDataToFlavour :: NewOrData -> TyConFlavour
+newOrDataToFlavour :: NewOrData -> TyConFlavour tc
newOrDataToFlavour NewType = NewtypeFlavour
newOrDataToFlavour DataType = DataTypeFlavour
diff --git a/compiler/GHC/Hs/Expr.hs b/compiler/GHC/Hs/Expr.hs
index 621848920d..4a8abe8404 100644
--- a/compiler/GHC/Hs/Expr.hs
+++ b/compiler/GHC/Hs/Expr.hs
@@ -44,6 +44,7 @@ import GHC.Parser.Annotation
-- others:
import GHC.Tc.Types.Evidence
+import GHC.Types.Id.Info ( RecSelParent )
import GHC.Types.Name
import GHC.Types.Name.Reader
import GHC.Types.Name.Set
@@ -52,7 +53,8 @@ import GHC.Types.Fixity
import GHC.Types.SourceText
import GHC.Types.SrcLoc
import GHC.Types.Tickish (CoreTickish)
-import GHC.Core.ConLike
+import GHC.Types.Unique.Set (UniqSet)
+import GHC.Core.ConLike ( conLikeName, ConLike )
import GHC.Unit.Module (ModuleName)
import GHC.Utils.Misc
import GHC.Utils.Outputable
@@ -74,6 +76,7 @@ import qualified Data.Kind
import Data.Maybe (isJust)
import Data.Foldable ( toList )
import Data.List (uncons)
+import Data.List.NonEmpty (NonEmpty)
import Data.Bifunctor (first)
{- *********************************************************************
@@ -324,6 +327,31 @@ type instance XRecordUpd GhcTc = DataConCantHappen
-- See [Handling overloaded and rebindable constructs],
-- and [Record Updates] in GHC.Tc.Gen.Expr.
+-- | Information about the parent of a record update:
+--
+-- - the parent type constructor or pattern synonym,
+-- - the relevant con-likes,
+-- - the field labels.
+data family HsRecUpdParent x
+
+data instance HsRecUpdParent GhcPs
+data instance HsRecUpdParent GhcRn
+ = RnRecUpdParent
+ { rnRecUpdLabels :: NonEmpty FieldGlobalRdrElt
+ , rnRecUpdCons :: UniqSet ConLikeName }
+data instance HsRecUpdParent GhcTc
+ = TcRecUpdParent
+ { tcRecUpdParent :: RecSelParent
+ , tcRecUpdLabels :: NonEmpty FieldGlobalRdrElt
+ , tcRecUpdCons :: UniqSet ConLike }
+
+type instance XLHsRecUpdLabels GhcPs = NoExtField
+type instance XLHsRecUpdLabels GhcRn = NonEmpty (HsRecUpdParent GhcRn)
+ -- Possible parents for the record update.
+type instance XLHsRecUpdLabels GhcTc = DataConCantHappen
+
+type instance XLHsOLRecUpdLabels p = NoExtField
+
type instance XGetField GhcPs = EpAnnCO
type instance XGetField GhcRn = NoExtField
type instance XGetField GhcTc = DataConCantHappen
@@ -625,8 +653,10 @@ ppr_expr (RecordCon { rcon_con = con, rcon_flds = rbinds })
ppr_expr (RecordUpd { rupd_expr = L _ aexp, rupd_flds = flds })
= case flds of
- Left rbinds -> hang (ppr aexp) 2 (braces (fsep (punctuate comma (map ppr rbinds))))
- Right pbinds -> hang (ppr aexp) 2 (braces (fsep (punctuate comma (map ppr pbinds))))
+ RegularRecUpdFields { recUpdFields= rbinds } ->
+ hang (ppr aexp) 2 (braces (fsep (punctuate comma (map ppr rbinds))))
+ OverloadedRecUpdFields { olRecUpdFields = pbinds } ->
+ hang (ppr aexp) 2 (braces (fsep (punctuate comma (map ppr pbinds))))
ppr_expr (HsGetField { gf_expr = L _ fexp, gf_field = field })
= ppr fexp <> dot <> ppr field
diff --git a/compiler/GHC/Hs/ImpExp.hs b/compiler/GHC/Hs/ImpExp.hs
index c25a72c079..83f5cfbb88 100644
--- a/compiler/GHC/Hs/ImpExp.hs
+++ b/compiler/GHC/Hs/ImpExp.hs
@@ -21,25 +21,26 @@ module GHC.Hs.ImpExp
, module GHC.Hs.ImpExp
) where
+import Language.Haskell.Syntax.Extension
+import Language.Haskell.Syntax.Module.Name
+import Language.Haskell.Syntax.ImpExp
+
import GHC.Prelude
import GHC.Types.SourceText ( SourceText(..) )
-import GHC.Types.FieldLabel ( FieldLabel )
-
-import GHC.Utils.Outputable
-import GHC.Utils.Panic
import GHC.Types.SrcLoc
-import GHC.Parser.Annotation
-import GHC.Hs.Extension
import GHC.Types.Name
import GHC.Types.PkgQual
+import GHC.Parser.Annotation
+import GHC.Hs.Extension
+
+import GHC.Utils.Outputable
+import GHC.Utils.Panic
+
import Data.Data
import Data.Maybe
-import Language.Haskell.Syntax.Extension
-import Language.Haskell.Syntax.Module.Name
-import Language.Haskell.Syntax.ImpExp
{-
************************************************************************
@@ -203,11 +204,7 @@ type instance XIEVar GhcTc = NoExtField
type instance XIEThingAbs (GhcPass _) = EpAnn [AddEpAnn]
type instance XIEThingAll (GhcPass _) = EpAnn [AddEpAnn]
-
--- See Note [IEThingWith]
-type instance XIEThingWith (GhcPass 'Parsed) = EpAnn [AddEpAnn]
-type instance XIEThingWith (GhcPass 'Renamed) = [Located FieldLabel]
-type instance XIEThingWith (GhcPass 'Typechecked) = NoExtField
+type instance XIEThingWith (GhcPass _) = EpAnn [AddEpAnn]
type instance XIEModuleContents GhcPs = EpAnn [AddEpAnn]
type instance XIEModuleContents GhcRn = NoExtField
@@ -220,32 +217,6 @@ type instance XXIE (GhcPass _) = DataConCantHappen
type instance Anno (LocatedA (IE (GhcPass p))) = SrcSpanAnnA
-{-
-Note [IEThingWith]
-~~~~~~~~~~~~~~~~~~
-A definition like
-
- {-# LANGUAGE DuplicateRecordFields #-}
- module M ( T(MkT, x) ) where
- data T = MkT { x :: Int }
-
-gives rise to this in the output of the parser:
-
- IEThingWith NoExtField T [MkT, x] NoIEWildcard
-
-But in the renamer we need to attach the correct field label,
-because the selector Name is mangled (see Note [FieldLabel] in
-GHC.Types.FieldLabel). Hence we change this to:
-
- IEThingWith [FieldLabel "x" True $sel:x:MkT)] T [MkT] NoIEWildcard
-
-using the TTG extension field to store the list of fields in renamed syntax
-only. (Record fields always appear in this list, regardless of whether
-DuplicateRecordFields was in use at the definition site or not.)
-
-See Note [Representing fields in AvailInfo] in GHC.Types.Avail for more details.
--}
-
ieName :: IE (GhcPass p) -> IdP (GhcPass p)
ieName (IEVar _ (L _ n)) = ieWrappedName n
ieName (IEThingAbs _ (L _ n)) = ieWrappedName n
@@ -292,9 +263,8 @@ instance OutputableBndrId p => Outputable (IE (GhcPass p)) where
ppr (IEVar _ var) = ppr (unLoc var)
ppr (IEThingAbs _ thing) = ppr (unLoc thing)
ppr (IEThingAll _ thing) = hcat [ppr (unLoc thing), text "(..)"]
- ppr (IEThingWith flds thing wc withs)
- = ppr (unLoc thing) <> parens (fsep (punctuate comma
- (ppWiths ++ ppFields) ))
+ ppr (IEThingWith _ thing wc withs)
+ = ppr (unLoc thing) <> parens (fsep (punctuate comma ppWiths))
where
ppWiths =
case wc of
@@ -303,10 +273,6 @@ instance OutputableBndrId p => Outputable (IE (GhcPass p)) where
IEWildcard pos ->
let (bs, as) = splitAt pos (map (ppr . unLoc) withs)
in bs ++ [text ".."] ++ as
- ppFields =
- case ghcPass @p of
- GhcRn -> map ppr flds
- _ -> []
ppr (IEModuleContents _ mod')
= text "module" <+> ppr mod'
ppr (IEGroup _ n _) = text ("<IEGroup: " ++ show n ++ ">")
diff --git a/compiler/GHC/Hs/Instances.hs b/compiler/GHC/Hs/Instances.hs
index 74d75fb7be..5c8e403bb3 100644
--- a/compiler/GHC/Hs/Instances.hs
+++ b/compiler/GHC/Hs/Instances.hs
@@ -287,6 +287,14 @@ deriving instance Data (FieldLabelStrings GhcPs)
deriving instance Data (FieldLabelStrings GhcRn)
deriving instance Data (FieldLabelStrings GhcTc)
+deriving instance Data (HsRecUpdParent GhcPs)
+deriving instance Data (HsRecUpdParent GhcRn)
+deriving instance Data (HsRecUpdParent GhcTc)
+
+deriving instance Data (LHsRecUpdFields GhcPs)
+deriving instance Data (LHsRecUpdFields GhcRn)
+deriving instance Data (LHsRecUpdFields GhcTc)
+
deriving instance Data (DotFieldOcc GhcPs)
deriving instance Data (DotFieldOcc GhcRn)
deriving instance Data (DotFieldOcc GhcTc)
diff --git a/compiler/GHC/Hs/Pat.hs b/compiler/GHC/Hs/Pat.hs
index bc0b51457e..2591efc732 100644
--- a/compiler/GHC/Hs/Pat.hs
+++ b/compiler/GHC/Hs/Pat.hs
@@ -244,8 +244,8 @@ data ConPatTc
hsRecFieldId :: HsRecField GhcTc arg -> Id
hsRecFieldId = hsRecFieldSel
-hsRecUpdFieldRdr :: HsRecUpdField (GhcPass p) -> Located RdrName
-hsRecUpdFieldRdr = fmap rdrNameAmbiguousFieldOcc . reLoc . hfbLHS
+hsRecUpdFieldRdr :: HsRecUpdField (GhcPass p) q -> Located RdrName
+hsRecUpdFieldRdr = fmap ambiguousFieldOccRdrName . reLoc . hfbLHS
hsRecUpdFieldId :: HsFieldBind (LAmbiguousFieldOcc GhcTc) arg -> Located Id
hsRecUpdFieldId = fmap foExt . reLoc . hsRecUpdFieldOcc
diff --git a/compiler/GHC/Hs/Type.hs b/compiler/GHC/Hs/Type.hs
index 313b8e8fe2..968fc99b73 100644
--- a/compiler/GHC/Hs/Type.hs
+++ b/compiler/GHC/Hs/Type.hs
@@ -56,7 +56,8 @@ module GHC.Hs.Type (
FieldOcc(..), LFieldOcc, mkFieldOcc,
AmbiguousFieldOcc(..), LAmbiguousFieldOcc, mkAmbiguousFieldOcc,
- rdrNameAmbiguousFieldOcc, selectorAmbiguousFieldOcc,
+ ambiguousFieldOccRdrName, ambiguousFieldOccLRdrName,
+ selectorAmbiguousFieldOcc,
unambiguousFieldOcc, ambiguousFieldOcc,
mkAnonWildCardTy, pprAnonWildCard,
@@ -104,7 +105,7 @@ import GHC.Parser.Annotation
import GHC.Types.Fixity ( LexicalFixity(..) )
import GHC.Types.Id ( Id )
import GHC.Types.SourceText
-import GHC.Types.Name( Name, NamedThing(getName), tcName, dataName )
+import GHC.Types.Name
import GHC.Types.Name.Reader ( RdrName )
import GHC.Types.Var ( VarBndr, visArgTypeLike )
import GHC.Core.TyCo.Rep ( Type(..) )
@@ -915,11 +916,11 @@ type instance XAmbiguous GhcTc = Id
type instance XXAmbiguousFieldOcc (GhcPass _) = DataConCantHappen
instance Outputable (AmbiguousFieldOcc (GhcPass p)) where
- ppr = ppr . rdrNameAmbiguousFieldOcc
+ ppr = ppr . ambiguousFieldOccRdrName
instance OutputableBndr (AmbiguousFieldOcc (GhcPass p)) where
- pprInfixOcc = pprInfixOcc . rdrNameAmbiguousFieldOcc
- pprPrefixOcc = pprPrefixOcc . rdrNameAmbiguousFieldOcc
+ pprInfixOcc = pprInfixOcc . ambiguousFieldOccRdrName
+ pprPrefixOcc = pprPrefixOcc . ambiguousFieldOccRdrName
instance OutputableBndr (Located (AmbiguousFieldOcc (GhcPass p))) where
pprInfixOcc = pprInfixOcc . unLoc
@@ -928,9 +929,12 @@ instance OutputableBndr (Located (AmbiguousFieldOcc (GhcPass p))) where
mkAmbiguousFieldOcc :: LocatedN RdrName -> AmbiguousFieldOcc GhcPs
mkAmbiguousFieldOcc rdr = Unambiguous noExtField rdr
-rdrNameAmbiguousFieldOcc :: AmbiguousFieldOcc (GhcPass p) -> RdrName
-rdrNameAmbiguousFieldOcc (Unambiguous _ (L _ rdr)) = rdr
-rdrNameAmbiguousFieldOcc (Ambiguous _ (L _ rdr)) = rdr
+ambiguousFieldOccRdrName :: AmbiguousFieldOcc (GhcPass p) -> RdrName
+ambiguousFieldOccRdrName = unLoc . ambiguousFieldOccLRdrName
+
+ambiguousFieldOccLRdrName :: AmbiguousFieldOcc (GhcPass p) -> LocatedN RdrName
+ambiguousFieldOccLRdrName (Unambiguous _ rdr) = rdr
+ambiguousFieldOccLRdrName (Ambiguous _ rdr) = rdr
selectorAmbiguousFieldOcc :: AmbiguousFieldOcc GhcTc -> Id
selectorAmbiguousFieldOcc (Unambiguous sel _) = sel
diff --git a/compiler/GHC/Hs/Utils.hs b/compiler/GHC/Hs/Utils.hs
index 5866243824..008469b458 100644
--- a/compiler/GHC/Hs/Utils.hs
+++ b/compiler/GHC/Hs/Utils.hs
@@ -1,4 +1,6 @@
{-# LANGUAGE ConstraintKinds #-}
+{-# LANGUAGE TupleSections #-}
+
{-|
Module : GHC.Hs.Utils
Description : Generic helpers for the HsSyn type.
@@ -97,6 +99,7 @@ module GHC.Hs.Utils(
collectLStmtBinders, collectStmtBinders,
CollectPass(..), CollectFlag(..),
+ TyDeclBinders(..), LConsWithFields(..),
hsLTyClDeclBinders, hsTyClForeignBinders,
hsPatSynSelectors, getPatSynBinds,
hsForeignDeclsBinders, hsGroupBinders, hsDataFamInstBinders,
@@ -113,6 +116,7 @@ import GHC.Hs.Expr
import GHC.Hs.Pat
import GHC.Hs.Type
import GHC.Hs.Lit
+import Language.Haskell.Syntax.Decls
import Language.Haskell.Syntax.Extension
import GHC.Hs.Extension
import GHC.Parser.Annotation
@@ -146,13 +150,18 @@ import GHC.Utils.Misc
import GHC.Utils.Outputable
import GHC.Utils.Panic
-import Data.Either
+import Control.Arrow ( first )
+import Data.Either ( partitionEithers )
import Data.Foldable ( toList )
-import Data.Function
-import Data.List ( partition, deleteBy )
+import Data.List ( partition )
import Data.List.NonEmpty ( nonEmpty )
import qualified Data.List.NonEmpty as NE
+import Data.IntMap ( IntMap )
+import qualified Data.IntMap.Strict as IntMap
+import Data.Map ( Map )
+import qualified Data.Map.Strict as Map
+
{-
************************************************************************
* *
@@ -1356,17 +1365,31 @@ hsTyClForeignBinders :: [TyClGroup GhcRn]
hsTyClForeignBinders tycl_decls foreign_decls
= map unLoc (hsForeignDeclsBinders foreign_decls)
++ getSelectorNames
- (foldMap (foldMap hsLTyClDeclBinders . group_tyclds) tycl_decls
+ (foldMap (foldMap (tyDeclBinders . hsLTyClDeclBinders) . group_tyclds) tycl_decls
`mappend`
- foldMap (foldMap hsLInstDeclBinders . group_instds) tycl_decls)
+ (foldMap (foldMap hsLInstDeclBinders . group_instds) tycl_decls))
where
getSelectorNames :: ([LocatedA Name], [LFieldOcc GhcRn]) -> [Name]
getSelectorNames (ns, fs) = map unLoc ns ++ map (foExt . unLoc) fs
-------------------
-hsLTyClDeclBinders :: IsPass p
+
+data TyDeclBinders p
+ = TyDeclBinders
+ { tyDeclMainBinder :: !(LocatedA (IdP (GhcPass p)), TyConFlavour ())
+ , tyDeclATs :: ![(LocatedA (IdP (GhcPass p)), TyConFlavour ())]
+ , tyDeclOpSigs :: ![LocatedA (IdP (GhcPass p))]
+ , tyDeclConsWithFields :: !(LConsWithFields p) }
+
+tyDeclBinders :: TyDeclBinders p -> ([LocatedA (IdP (GhcPass p))], [LFieldOcc (GhcPass p)])
+tyDeclBinders (TyDeclBinders main ats sigs consWithFields)
+ = (fst main : (fmap fst ats ++ sigs ++ cons), flds)
+ where
+ (cons, flds) = lconsWithFieldsBinders consWithFields
+
+hsLTyClDeclBinders :: (IsPass p, OutputableBndrId p)
=> LocatedA (TyClDecl (GhcPass p))
- -> ([LocatedA (IdP (GhcPass p))], [LFieldOcc (GhcPass p)])
+ -> TyDeclBinders p
-- ^ Returns all the /binding/ names of the decl. The first one is
-- guaranteed to be the name of the decl. The first component
-- represents all binding names except record fields; the second
@@ -1377,27 +1400,40 @@ hsLTyClDeclBinders :: IsPass p
-- See Note [SrcSpan for binders]
hsLTyClDeclBinders (L loc (FamDecl { tcdFam = FamilyDecl
- { fdLName = (L _ name) } }))
- = ([L loc name], [])
+ { fdLName = (L _ name)
+ , fdInfo = fd_info } }))
+ = TyDeclBinders
+ { tyDeclMainBinder = (L loc name, familyInfoTyConFlavour Nothing fd_info)
+ , tyDeclATs = [], tyDeclOpSigs = []
+ , tyDeclConsWithFields = emptyLConsWithFields }
hsLTyClDeclBinders (L loc (SynDecl
{ tcdLName = (L _ name) }))
- = ([L loc name], [])
+ = TyDeclBinders
+ { tyDeclMainBinder = (L loc name, TypeSynonymFlavour)
+ , tyDeclATs = [], tyDeclOpSigs = []
+ , tyDeclConsWithFields = emptyLConsWithFields }
hsLTyClDeclBinders (L loc (ClassDecl
{ tcdLName = (L _ cls_name)
, tcdSigs = sigs
, tcdATs = ats }))
- = (L loc cls_name :
- [ L fam_loc fam_name | (L fam_loc (FamilyDecl
- { fdLName = L _ fam_name })) <- ats ]
- ++
- [ L mem_loc mem_name
- | (L mem_loc (ClassOpSig _ False ns _)) <- sigs
- , (L _ mem_name) <- ns ]
- , [])
+ = TyDeclBinders
+ { tyDeclMainBinder = (L loc cls_name, ClassFlavour)
+ , tyDeclATs = [ (L fam_loc fam_name, familyInfoTyConFlavour (Just ()) fd_info)
+ | (L fam_loc (FamilyDecl { fdLName = L _ fam_name
+ , fdInfo = fd_info })) <- ats ]
+ , tyDeclOpSigs = [ L mem_loc mem_name
+ | (L mem_loc (ClassOpSig _ False ns _)) <- sigs
+ , (L _ mem_name) <- ns ]
+ , tyDeclConsWithFields = emptyLConsWithFields }
hsLTyClDeclBinders (L loc (DataDecl { tcdLName = (L _ name)
, tcdDataDefn = defn }))
- = (\ (xs, ys) -> (L loc name : xs, ys)) $ hsDataDefnBinders defn
-
+ = TyDeclBinders
+ { tyDeclMainBinder = (L loc name, flav )
+ , tyDeclATs = []
+ , tyDeclOpSigs = []
+ , tyDeclConsWithFields = hsDataDefnBinders defn }
+ where
+ flav = newOrDataToFlavour $ dataDefnConsNewOrData $ dd_cons defn
-------------------
hsForeignDeclsBinders :: forall p a. (UnXRec (GhcPass p), IsSrcSpanAnn p a)
@@ -1430,94 +1466,170 @@ getPatSynBinds binds
, (unXRec @id -> (PatSynBind _ psb)) <- bagToList lbinds ]
-------------------
-hsLInstDeclBinders :: IsPass p
+hsLInstDeclBinders :: (IsPass p, OutputableBndrId p)
=> LInstDecl (GhcPass p)
- -> ([LocatedA (IdP (GhcPass p))], [LFieldOcc (GhcPass p)])
+ -> ([(LocatedA (IdP (GhcPass p)))], [LFieldOcc (GhcPass p)])
hsLInstDeclBinders (L _ (ClsInstD
{ cid_inst = ClsInstDecl
{ cid_datafam_insts = dfis }}))
- = foldMap (hsDataFamInstBinders . unLoc) dfis
+ = foldMap (lconsWithFieldsBinders . hsDataFamInstBinders . unLoc) dfis
hsLInstDeclBinders (L _ (DataFamInstD { dfid_inst = fi }))
- = hsDataFamInstBinders fi
+ = lconsWithFieldsBinders $ hsDataFamInstBinders fi
hsLInstDeclBinders (L _ (TyFamInstD {})) = mempty
-------------------
-- | the 'SrcLoc' returned are for the whole declarations, not just the names
-hsDataFamInstBinders :: IsPass p
+hsDataFamInstBinders :: (IsPass p, OutputableBndrId p)
=> DataFamInstDecl (GhcPass p)
- -> ([LocatedA (IdP (GhcPass p))], [LFieldOcc (GhcPass p)])
+ -> LConsWithFields p
hsDataFamInstBinders (DataFamInstDecl { dfid_eqn = FamEqn { feqn_rhs = defn }})
= hsDataDefnBinders defn
-- There can't be repeated symbols because only data instances have binders
-------------------
-- | the 'SrcLoc' returned are for the whole declarations, not just the names
-hsDataDefnBinders :: IsPass p
+hsDataDefnBinders :: (IsPass p, OutputableBndrId p)
=> HsDataDefn (GhcPass p)
- -> ([LocatedA (IdP (GhcPass p))], [LFieldOcc (GhcPass p)])
+ -> LConsWithFields p
hsDataDefnBinders (HsDataDefn { dd_cons = cons })
= hsConDeclsBinders (toList cons)
-- See Note [Binders in family instances]
-------------------
-type Seen p = [LFieldOcc (GhcPass p)] -> [LFieldOcc (GhcPass p)]
- -- Filters out ones that have already been seen
-hsConDeclsBinders :: forall p. IsPass p
+{- Note [Collecting record fields in data declarations]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+When renaming a data declaration that includes record constructors, we are, in
+the end, going to to create a mapping from constructor to its field labels,
+to store in 'GREInfo' (see 'IAmConLike'). This allows us to know, in the renamer,
+which constructor has what fields.
+
+In order to achieve this, we return the constructor and field information from
+hsConDeclsBinders in the following format:
+
+ - [(ConRdrName, [Located Int])], a list of the constructors, each associated
+ with its record fields, in the form of a list of Int indices into...
+ - IntMap FieldOcc, an IntMap of record fields.
+
+(In actual fact, we use [(ConRdrName, Maybe [Located Int])], with Nothing indicating
+that the constructor has unlabelled fields: see Note [Local constructor info in the renamer]
+in GHC.Types.GREInfo.)
+
+This allows us to do the following (see GHC.Rename.Names.getLocalNonValBinders.new_tc):
+
+ - create 'Name's for each of the record fields, to get IntMap FieldLabel,
+ - create 'Name's for each of the constructors, to get [(ConName, [Int])],
+ - look up the FieldLabels of each constructor, to get [(ConName, [FieldLabel])].
+
+NB: This can be a bit tricky to get right in the presence of data types with
+duplicate constructors or fields. Storing locations allows us to report an error
+for duplicate field declarations, see test cases T9156 T9156_DF.
+Other relevant test cases: rnfail015.
+
+-}
+
+-- | A mapping from constructors to all of their fields.
+--
+-- See Note [Collecting record fields in data declarations].
+data LConsWithFields p =
+ LConsWithFields
+ { consWithFieldIndices :: [(LocatedA (IdP (GhcPass p)), Maybe [Located Int])]
+ , consFields :: IntMap (LFieldOcc (GhcPass p))
+ }
+
+lconsWithFieldsBinders :: LConsWithFields p
+ -> ([(LocatedA (IdP (GhcPass p)))], [LFieldOcc (GhcPass p)])
+lconsWithFieldsBinders (LConsWithFields cons fields)
+ = (map fst cons, IntMap.elems fields)
+
+emptyLConsWithFields :: LConsWithFields p
+emptyLConsWithFields = LConsWithFields [] IntMap.empty
+
+hsConDeclsBinders :: forall p. (IsPass p, OutputableBndrId p)
=> [LConDecl (GhcPass p)]
- -> ([LocatedA (IdP (GhcPass p))], [LFieldOcc (GhcPass p)])
- -- See hsLTyClDeclBinders for what this does
- -- The function is boringly complicated because of the records
- -- And since we only have equality, we have to be a little careful
-hsConDeclsBinders cons
- = go id cons
+ -> LConsWithFields p
+ -- The function is boringly complicated because of the records
+ -- And since we only have equality, we have to be a little careful
+hsConDeclsBinders cons = go emptyFieldIndices cons
where
- go :: Seen p -> [LConDecl (GhcPass p)]
- -> ([LocatedA (IdP (GhcPass p))], [LFieldOcc (GhcPass p)])
- go _ [] = ([], [])
- go remSeen (r:rs)
+ go :: FieldIndices p -> [LConDecl (GhcPass p)] -> LConsWithFields p
+ go seen [] = LConsWithFields [] (fields seen)
+ go seen (r:rs)
-- Don't re-mangle the location of field names, because we don't
-- have a record of the full location of the field declaration anyway
= let loc = getLoc r
in case unLoc r of
- -- remove only the first occurrence of any seen field in order to
- -- avoid circumventing detection of duplicate fields (#9156)
ConDeclGADT { con_names = names, con_g_args = args }
- -> (toList (L loc . unLoc <$> names) ++ ns, flds ++ fs)
+ -> LConsWithFields (cons ++ ns) fs
where
- (remSeen', flds) = get_flds_gadt remSeen args
- (ns, fs) = go remSeen' rs
+ cons = map ( , con_flds ) $ toList (L loc . unLoc <$> names)
+ (con_flds, seen') = get_flds_gadt seen args
+ LConsWithFields ns fs = go seen' rs
ConDeclH98 { con_name = name, con_args = args }
- -> ([L loc (unLoc name)] ++ ns, flds ++ fs)
+ -> LConsWithFields ([(L loc (unLoc name), con_flds)] ++ ns) fs
where
- (remSeen', flds) = get_flds_h98 remSeen args
- (ns, fs) = go remSeen' rs
-
- get_flds_h98 :: Seen p -> HsConDeclH98Details (GhcPass p)
- -> (Seen p, [LFieldOcc (GhcPass p)])
- get_flds_h98 remSeen (RecCon flds) = get_flds remSeen flds
- get_flds_h98 remSeen _ = (remSeen, [])
-
- get_flds_gadt :: Seen p -> HsConDeclGADTDetails (GhcPass p)
- -> (Seen p, [LFieldOcc (GhcPass p)])
- get_flds_gadt remSeen (RecConGADT flds _) = get_flds remSeen flds
- get_flds_gadt remSeen _ = (remSeen, [])
-
- get_flds :: Seen p -> LocatedL [LConDeclField (GhcPass p)]
- -> (Seen p, [LFieldOcc (GhcPass p)])
- get_flds remSeen flds = (remSeen', fld_names)
- where
- fld_names = remSeen (concatMap (cd_fld_names . unLoc) (unLoc flds))
- remSeen' = foldr (.) remSeen
- [deleteBy ((==) `on` unLoc . foLabel . unLoc) v
- | v <- fld_names]
+ (con_flds, seen') = get_flds_h98 seen args
+ LConsWithFields ns fs = go seen' rs
+
+ get_flds_h98 :: FieldIndices p -> HsConDeclH98Details (GhcPass p)
+ -> (Maybe [Located Int], FieldIndices p)
+ get_flds_h98 seen (RecCon flds) = first Just $ get_flds seen flds
+ get_flds_h98 seen (PrefixCon _ []) = (Just [], seen)
+ get_flds_h98 seen _ = (Nothing, seen)
+
+ get_flds_gadt :: FieldIndices p -> HsConDeclGADTDetails (GhcPass p)
+ -> (Maybe [Located Int], FieldIndices p)
+ get_flds_gadt seen (RecConGADT flds _) = first Just $ get_flds seen flds
+ get_flds_gadt seen (PrefixConGADT []) = (Just [], seen)
+ get_flds_gadt seen _ = (Nothing, seen)
+
+ get_flds :: FieldIndices p -> LocatedL [LConDeclField (GhcPass p)]
+ -> ([Located Int], FieldIndices p)
+ get_flds seen flds =
+ foldr add_fld ([], seen) fld_names
+ where
+ add_fld fld (is, ixs) =
+ let (i, ixs') = insertField fld ixs
+ in (i:is, ixs')
+ fld_names = concatMap (cd_fld_names . unLoc) (unLoc flds)
+
+-- | A bijection between record fields of a datatype and integers,
+-- used to implement Note [Collecting record fields in data declarations].
+data FieldIndices p =
+ FieldIndices
+ { fields :: IntMap (LFieldOcc (GhcPass p))
+ -- ^ Look up a field from its index.
+ , fieldIndices :: Map RdrName Int
+ -- ^ Look up the index of a field label in the previous 'IntMap'.
+ , newInt :: !Int
+ -- ^ An integer @i@ such that no integer @i' >= i@ appears in the 'IntMap'.
+ }
+
+emptyFieldIndices :: FieldIndices p
+emptyFieldIndices =
+ FieldIndices { fields = IntMap.empty
+ , fieldIndices = Map.empty
+ , newInt = 0 }
+
+insertField :: LFieldOcc (GhcPass p) -> FieldIndices p -> (Located Int, FieldIndices p)
+insertField new_fld fi@(FieldIndices flds idxs new_idx)
+ | Just i <- Map.lookup rdr idxs
+ = (L loc i, fi)
+ | otherwise
+ = (L loc new_idx,
+ FieldIndices (IntMap.insert new_idx new_fld flds)
+ (Map.insert rdr new_idx idxs)
+ (new_idx + 1))
+ where
+ loc = getLocA new_fld
+ rdr = unLoc . foLabel . unLoc $ new_fld
{-
Note [SrcSpan for binders]
~~~~~~~~~~~~~~~~~~~~~~~~~~
-When extracting the (Located RdrNme) for a binder, at least for the
+When extracting the (Located RdrName) for a binder, at least for the
main name (the TyCon of a type declaration etc), we want to give it
the @SrcSpan@ of the whole /declaration/, not just the name itself
(which is how it appears in the syntax tree). This SrcSpan (for the
diff --git a/compiler/GHC/HsToCore/Errors/Types.hs b/compiler/GHC/HsToCore/Errors/Types.hs
index 8f6586fb45..40fd6b7aab 100644
--- a/compiler/GHC/HsToCore/Errors/Types.hs
+++ b/compiler/GHC/HsToCore/Errors/Types.hs
@@ -154,7 +154,7 @@ newtype DsArgNum = DsArgNum Int
-- | Why TemplateHaskell rejected the splice. Used in the 'DsNotYetHandledByTH'
-- constructor of a 'DsMessage'.
data ThRejectionReason
- = ThAmbiguousRecordUpdates !(HsRecUpdField GhcRn)
+ = ThAmbiguousRecordUpdates !(HsRecUpdField GhcRn GhcRn)
| ThAbstractClosedTypeFamily !(LFamilyDecl GhcRn)
| ThForeignLabel !CLabelString
| ThForeignExport !(LForeignDecl GhcRn)
diff --git a/compiler/GHC/HsToCore/Expr.hs b/compiler/GHC/HsToCore/Expr.hs
index 63c2cee789..6a0bee9089 100644
--- a/compiler/GHC/HsToCore/Expr.hs
+++ b/compiler/GHC/HsToCore/Expr.hs
@@ -34,6 +34,7 @@ import GHC.Types.SourceText
import GHC.Types.Name
import GHC.Core.FamInstEnv( topNormaliseType )
import GHC.HsToCore.Quote
+import GHC.HsToCore.Ticks (stripTicksTopHsExpr)
import GHC.Hs
-- NB: The desugarer, which straddles the source and Core worlds, sometimes
@@ -66,7 +67,6 @@ import GHC.Utils.Panic
import GHC.Utils.Panic.Plain
import GHC.Core.PatSyn
import Control.Monad
-import GHC.HsToCore.Ticks (stripTicksTopHsExpr)
{-
************************************************************************
@@ -559,7 +559,7 @@ dsSyntaxExpr NoSyntaxExprTc _ = panic "dsSyntaxExpr"
findField :: [LHsRecField GhcTc arg] -> Name -> [arg]
findField rbinds sel
= [hfbRHS fld | L _ fld <- rbinds
- , sel == idName (hsRecFieldId fld) ]
+ , sel == idName (hsRecFieldId fld) ]
{-
%--------------------------------------------------------------------
diff --git a/compiler/GHC/HsToCore/Quote.hs b/compiler/GHC/HsToCore/Quote.hs
index 8463e9f739..3166370e14 100644
--- a/compiler/GHC/HsToCore/Quote.hs
+++ b/compiler/GHC/HsToCore/Quote.hs
@@ -3,6 +3,7 @@
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FunctionalDependencies #-}
+{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
@@ -98,7 +99,6 @@ import Data.List.NonEmpty ( NonEmpty(..) )
import Data.Function
import Control.Monad.Trans.Reader
import Control.Monad.Trans.Class
-import Data.Foldable ( toList )
import GHC.Types.Name.Reader (RdrName(..))
data MetaWrappers = MetaWrappers {
@@ -1608,15 +1608,15 @@ repE (RecordCon { rcon_con = c, rcon_flds = flds })
= do { x <- lookupLOcc c;
fs <- repFields flds;
repRecCon x fs }
-repE (RecordUpd { rupd_expr = e, rupd_flds = Left flds })
+repE (RecordUpd { rupd_expr = e, rupd_flds = RegularRecUpdFields { recUpdFields = flds } })
= do { x <- repLE e;
fs <- repUpdFields flds;
repRecUpd x fs }
-repE (RecordUpd { rupd_flds = Right _ })
+repE e@(RecordUpd { rupd_flds = OverloadedRecUpdFields {} })
= do
-- Not possible due to elimination in the renamer. See Note
-- [Handling overloaded and rebindable constructs]
- panic "The impossible has happened!"
+ pprPanic "repE: unexpected overloaded record update" $ ppr e
repE (ExprWithTySig _ e wc_ty)
= addSimpleTyVarBinds FreshNamesOnly (get_scoped_tvs_from_sig sig_ty) $
@@ -1745,10 +1745,10 @@ repFields (HsRecFields { rec_flds = flds })
; e <- repLE (hfbRHS fld)
; repFieldExp fn e }
-repUpdFields :: [LHsRecUpdField GhcRn] -> MetaM (Core [M TH.FieldExp])
+repUpdFields :: [LHsRecUpdField GhcRn GhcRn] -> MetaM (Core [M TH.FieldExp])
repUpdFields = repListM fieldExpTyConName rep_fld
where
- rep_fld :: LHsRecUpdField GhcRn -> MetaM (Core (M TH.FieldExp))
+ rep_fld :: LHsRecUpdField GhcRn GhcRn -> MetaM (Core (M TH.FieldExp))
rep_fld (L l fld) = case unLoc (hfbLHS fld) of
Unambiguous sel_name _ -> do { fn <- lookupLOcc (L l sel_name)
; e <- repLE (hfbRHS fld)
@@ -2217,20 +2217,24 @@ globalVarLocal unique name
globalVarExternal :: Module -> OccName -> DsM (Core TH.Name)
globalVarExternal mod name_occ
- = do {
-
- ; MkC mod <- coreStringLit name_mod
+ = do { MkC mod <- coreStringLit name_mod
; MkC pkg <- coreStringLit name_pkg
; MkC occ <- occNameLit name_occ
- ; rep2_nwDsM mk_varg [pkg,mod,occ] }
+ ; if | isDataOcc name_occ
+ -> rep2_nwDsM mkNameG_dName [pkg,mod,occ]
+ | isVarOcc name_occ
+ -> rep2_nwDsM mkNameG_vName [pkg,mod,occ]
+ | isTcOcc name_occ
+ -> rep2_nwDsM mkNameG_tcName [pkg,mod,occ]
+ | Just con_fs <- fieldOcc_maybe name_occ
+ -> do { MkC con <- coreStringLit con_fs
+ ; rep2_nwDsM mkNameG_fldName [pkg,mod,con,occ] }
+ | otherwise
+ -> pprPanic "GHC.HsToCore.Quote.globalVar" (ppr name_occ)
+ }
where
name_mod = moduleNameFS (moduleName mod)
name_pkg = unitFS (moduleUnit mod)
- mk_varg | isDataOcc name_occ = mkNameG_dName
- | isVarOcc name_occ = mkNameG_vName
- | isTcOcc name_occ = mkNameG_tcName
- | otherwise = pprPanic "GHC.HsToCore.Quote.globalVar" (ppr name_occ)
-
lookupType :: Name -- Name of type constructor (e.g. (M TH.Exp))
-> MetaM Type -- The type
@@ -2738,16 +2742,19 @@ repGadtDataCons :: NonEmpty (LocatedN Name)
-> LHsType GhcRn
-> MetaM (Core (M TH.Con))
repGadtDataCons cons details res_ty
- = do cons' <- mapM lookupLOcc cons -- See Note [Binders and occurrences]
+ = do ne_tycon <- lift $ dsLookupTyCon nonEmptyTyConName
+ name_tycon <- lift $ dsLookupTyCon nameTyConName
+ let mk_nonEmpty = coreListNonEmpty ne_tycon (mkTyConTy name_tycon)
+ cons' <- mapM lookupLOcc cons -- See Note [Binders and occurrences]
case details of
PrefixConGADT ps -> do
arg_tys <- repPrefixConArgs ps
res_ty' <- repLTy res_ty
- rep2 gadtCName [ unC (nonEmptyCoreList' cons'), unC arg_tys, unC res_ty']
+ rep2 gadtCName [unC (mk_nonEmpty cons'), unC arg_tys, unC res_ty']
RecConGADT ips _ -> do
arg_vtys <- repRecConArgs ips
res_ty' <- repLTy res_ty
- rep2 recGadtCName [unC (nonEmptyCoreList' cons'), unC arg_vtys,
+ rep2 recGadtCName [unC (mk_nonEmpty cons'), unC arg_vtys,
unC res_ty']
-- TH currently only supports linear constructors.
@@ -3053,9 +3060,6 @@ nonEmptyCoreList :: [Core a] -> Core [a]
nonEmptyCoreList [] = panic "coreList: empty argument"
nonEmptyCoreList xs@(MkC x:_) = MkC (mkListExpr (exprType x) (map unC xs))
-nonEmptyCoreList' :: NonEmpty (Core a) -> Core [a]
-nonEmptyCoreList' xs@(MkC x:|_) = MkC (mkListExpr (exprType x) (toList $ fmap unC xs))
-
coreStringLit :: MonadThings m => FastString -> m (Core String)
coreStringLit s = do { z <- mkStringExprFS s; return (MkC z) }
diff --git a/compiler/GHC/HsToCore/Ticks.hs b/compiler/GHC/HsToCore/Ticks.hs
index 3ccf46c4cf..8c0227df80 100644
--- a/compiler/GHC/HsToCore/Ticks.hs
+++ b/compiler/GHC/HsToCore/Ticks.hs
@@ -550,14 +550,16 @@ addTickHsExpr expr@(RecordCon { rcon_flds = rec_binds })
= do { rec_binds' <- addTickHsRecordBinds rec_binds
; return (expr { rcon_flds = rec_binds' }) }
-addTickHsExpr expr@(RecordUpd { rupd_expr = e, rupd_flds = Left flds })
+addTickHsExpr expr@(RecordUpd { rupd_expr = e
+ , rupd_flds = upd@(RegularRecUpdFields { recUpdFields = flds }) })
= do { e' <- addTickLHsExpr e
; flds' <- mapM addTickHsRecField flds
- ; return (expr { rupd_expr = e', rupd_flds = Left flds' }) }
-addTickHsExpr expr@(RecordUpd { rupd_expr = e, rupd_flds = Right flds })
+ ; return (expr { rupd_expr = e', rupd_flds = upd { recUpdFields = flds' } }) }
+addTickHsExpr expr@(RecordUpd { rupd_expr = e
+ , rupd_flds = upd@(OverloadedRecUpdFields { olRecUpdFields = flds } ) })
= do { e' <- addTickLHsExpr e
; flds' <- mapM addTickHsRecField flds
- ; return (expr { rupd_expr = e', rupd_flds = Right flds' }) }
+ ; return (expr { rupd_expr = e', rupd_flds = upd { olRecUpdFields = flds' } }) }
addTickHsExpr (ExprWithTySig x e ty) =
liftM3 ExprWithTySig
diff --git a/compiler/GHC/Iface/Env.hs b/compiler/GHC/Iface/Env.hs
index a67fdfe334..d0a1a38199 100644
--- a/compiler/GHC/Iface/Env.hs
+++ b/compiler/GHC/Iface/Env.hs
@@ -193,9 +193,12 @@ setNameModule (Just m) n =
tcIfaceLclId :: FastString -> IfL Id
tcIfaceLclId occ
= do { lcl <- getLclEnv
- ; case (lookupFsEnv (if_id_env lcl) occ) of
+ ; case lookupFsEnv (if_id_env lcl) occ of
Just ty_var -> return ty_var
- Nothing -> failIfM (text "Iface id out of scope: " <+> ppr occ)
+ Nothing -> failIfM $
+ vcat
+ [ text "Iface id out of scope: " <+> ppr occ
+ , text "env:" <+> ppr (if_id_env lcl) ]
}
extendIfaceIdEnv :: [Id] -> IfL a -> IfL a
@@ -209,7 +212,7 @@ extendIfaceIdEnv ids
tcIfaceTyVar :: FastString -> IfL TyVar
tcIfaceTyVar occ
= do { lcl <- getLclEnv
- ; case (lookupFsEnv (if_tv_env lcl) occ) of
+ ; case lookupFsEnv (if_tv_env lcl) occ of
Just ty_var -> return ty_var
Nothing -> failIfM (text "Iface type variable out of scope: " <+> ppr occ)
}
diff --git a/compiler/GHC/Iface/Ext/Ast.hs b/compiler/GHC/Iface/Ext/Ast.hs
index 8ede7bcc5f..24a68e63c4 100644
--- a/compiler/GHC/Iface/Ext/Ast.hs
+++ b/compiler/GHC/Iface/Ext/Ast.hs
@@ -41,6 +41,7 @@ import GHC.Utils.Monad ( concatMapM, MonadIO(liftIO) )
import GHC.Types.Id ( isDataConId_maybe )
import GHC.Types.Name ( Name, nameSrcSpan, nameUnique )
import GHC.Types.Name.Env ( NameEnv, emptyNameEnv, extendNameEnv, lookupNameEnv )
+import GHC.Types.Name.Reader ( RecFieldInfo(..) )
import GHC.Types.SrcLoc
import GHC.Core.Type ( Type )
import GHC.Core.Predicate
@@ -1182,11 +1183,13 @@ instance HiePass p => ToHie (LocatedA (HsExpr (GhcPass p))) where
con_name = case hiePass @p of -- Like ConPat
HieRn -> con
HieTc -> fmap conLikeName con
- RecordUpd {rupd_expr = expr, rupd_flds = Left upds}->
+ RecordUpd { rupd_expr = expr
+ , rupd_flds = RegularRecUpdFields { recUpdFields = upds } }->
[ toHie expr
, toHie $ map (RC RecFieldAssign) upds
]
- RecordUpd {rupd_expr = expr, rupd_flds = Right _}->
+ RecordUpd { rupd_expr = expr
+ , rupd_flds = OverloadedRecUpdFields {} }->
[ toHie expr
]
ExprWithTySig _ expr sig ->
@@ -2111,10 +2114,9 @@ instance ToHie (IEContext (LocatedA (IE GhcRn))) where
IEThingAll _ n ->
[ toHie $ IEC c n
]
- IEThingWith flds n _ ns ->
+ IEThingWith _ n _ ns ->
[ toHie $ IEC c n
, toHie $ map (IEC c) ns
- , toHie $ map (IEC c) flds
]
IEModuleContents _ n ->
[ toHie $ IEC c n
@@ -2135,10 +2137,10 @@ instance ToHie (IEContext (LocatedA (IEWrappedName GhcRn))) where
[ toHie $ C (IEThing c) (L l n)
]
-instance ToHie (IEContext (Located FieldLabel)) where
- toHie (IEC c (L span lbl)) = concatM
- [ makeNode lbl span
- , toHie $ C (IEThing c) $ L span (flSelector lbl)
+instance ToHie (IEContext (Located RecFieldInfo)) where
+ toHie (IEC c (L span info)) = concatM
+ [ makeNode info span
+ , toHie $ C (IEThing c) $ L span (flSelector $ recFieldLabel info)
]
instance ToHie (LocatedA (DocDecl GhcRn)) where
@@ -2149,4 +2151,5 @@ instance ToHie (LocatedA (DocDecl GhcRn)) where
DocGroup _ d -> [ toHie d ]
instance ToHie (LHsDoc GhcRn) where
- toHie (L span d@(WithHsDocIdentifiers _ ids)) = concatM $ makeNode d span : [toHie $ map (C Use) ids]
+ toHie (L span d@(WithHsDocIdentifiers _ ids)) =
+ concatM $ makeNode d span : [toHie $ map (C Use) ids]
diff --git a/compiler/GHC/Iface/Load.hs b/compiler/GHC/Iface/Load.hs
index 0786505e3a..e794c7c6d2 100644
--- a/compiler/GHC/Iface/Load.hs
+++ b/compiler/GHC/Iface/Load.hs
@@ -1160,7 +1160,7 @@ pprExport :: IfaceExport -> SDoc
pprExport (Avail n) = ppr n
pprExport (AvailTC _ []) = Outputable.empty
pprExport avail@(AvailTC n _) =
- ppr n <> mark <> pp_export (availSubordinateGreNames avail)
+ ppr n <> mark <> pp_export (availSubordinateNames avail)
where
mark | availExportsDecl avail = Outputable.empty
| otherwise = vbar
diff --git a/compiler/GHC/Iface/Make.hs b/compiler/GHC/Iface/Make.hs
index c077b28557..3f6ef4b465 100644
--- a/compiler/GHC/Iface/Make.hs
+++ b/compiler/GHC/Iface/Make.hs
@@ -23,6 +23,7 @@ import GHC.Prelude
import GHC.Hs
+import GHC.Stg.InferTags.TagSig (StgCgInfos)
import GHC.StgToCmm.Types (CmmCgInfos (..))
import GHC.Tc.Utils.TcType
@@ -98,7 +99,6 @@ import Data.Function
import Data.List ( findIndex, mapAccumL, sortBy )
import Data.Ord
import Data.IORef
-import GHC.Stg.InferTags.TagSig (StgCgInfos)
{-
@@ -307,6 +307,7 @@ mkIface_ hsc_env
trust_info = setSafeMode safe_mode
annotations = map mkIfaceAnnotation anns
icomplete_matches = map mkIfaceCompleteMatch complete_matches
+ !rdrs = maybeGlobalRdrEnv rdr_env
ModIface {
mi_module = this_mod,
@@ -329,7 +330,7 @@ mkIface_ hsc_env
mi_fixities = fixities,
mi_warns = warns,
mi_anns = annotations,
- mi_globals = maybeGlobalRdrEnv rdr_env,
+ mi_globals = rdrs,
mi_used_th = used_th,
mi_decls = decls,
mi_extra_decls = extra_decls,
@@ -357,10 +358,13 @@ mkIface_ hsc_env
-- Desugar.addExportFlagsAndRules). The mi_globals field is used
-- by GHCi to decide whether the module has its full top-level
-- scope available. (#5534)
- maybeGlobalRdrEnv :: GlobalRdrEnv -> Maybe GlobalRdrEnv
+ maybeGlobalRdrEnv :: GlobalRdrEnv -> Maybe IfGlobalRdrEnv
maybeGlobalRdrEnv rdr_env
- | backendWantsGlobalBindings (backend dflags) = Just rdr_env
- | otherwise = Nothing
+ | backendWantsGlobalBindings (backend dflags)
+ = Just $! forceGlobalRdrEnv rdr_env
+ -- See Note [Forcing GREInfo] in GHC.Types.GREInfo.
+ | otherwise
+ = Nothing
ifFamInstTcName = ifFamInstFam
@@ -402,8 +406,10 @@ mkIfaceExports exports
sort_subs (Avail n) = Avail n
sort_subs (AvailTC n []) = AvailTC n []
sort_subs (AvailTC n (m:ms))
- | NormalGreName n==m = AvailTC n (m:sortBy stableGreNameCmp ms)
- | otherwise = AvailTC n (sortBy stableGreNameCmp (m:ms))
+ | n == m
+ = AvailTC n (m:sortBy stableNameCmp ms)
+ | otherwise
+ = AvailTC n (sortBy stableNameCmp (m:ms))
-- Maintain the AvailTC Invariant
{-
diff --git a/compiler/GHC/Iface/Recomp.hs b/compiler/GHC/Iface/Recomp.hs
index 0f8748e536..ec587318f4 100644
--- a/compiler/GHC/Iface/Recomp.hs
+++ b/compiler/GHC/Iface/Recomp.hs
@@ -56,7 +56,6 @@ import GHC.Types.Annotations
import GHC.Types.Name
import GHC.Types.Name.Set
import GHC.Types.SrcLoc
-import GHC.Types.Unique
import GHC.Types.Unique.Set
import GHC.Types.Fixity.Env
import GHC.Unit.External
@@ -979,8 +978,8 @@ addFingerprints hsc_env iface0
-- This is computed by finding the free external names of each
-- declaration, including IfaceDeclExtras (things that a
-- declaration implicitly depends on).
- edges :: [ Node Unique IfaceDeclABI ]
- edges = [ DigraphNode abi (getUnique (getOccName decl)) out
+ edges :: [ Node OccName IfaceDeclABI ]
+ edges = [ DigraphNode abi (getOccName decl) out
| decl <- decls
, let abi = declABI decl
, let out = localOccs $ freeNamesDeclABI abi
@@ -988,7 +987,7 @@ addFingerprints hsc_env iface0
name_module n = assertPpr (isExternalName n) (ppr n) (nameModule n)
localOccs =
- map (getUnique . getParent . getOccName)
+ map (getParent . getOccName)
-- NB: names always use semantic module, so
-- filtering must be on the semantic module!
-- See Note [Identity versus semantic module]
@@ -1013,7 +1012,7 @@ addFingerprints hsc_env iface0
-- Strongly-connected groups of declarations, in dependency order
groups :: [SCC IfaceDeclABI]
- groups = stronglyConnCompFromEdgedVerticesUniq edges
+ groups = stronglyConnCompFromEdgedVerticesOrd edges
global_hash_fn = mkHashFun hsc_env eps
@@ -1205,7 +1204,11 @@ addFingerprints hsc_env iface0
-- This key is safe because mi_extra_decls contains tidied things.
getOcc (IfGblTopBndr b) = getOccName b
- getOcc (IfLclTopBndr fs _ _ _) = mkVarOccFS fs
+ getOcc (IfLclTopBndr fs _ _ details) =
+ case details of
+ IfRecSelId { ifRecSelFirstCon = first_con }
+ -> mkRecFieldOccFS (getOccFS first_con) fs
+ _ -> mkVarOccFS fs
binding_key (IfaceNonRec b _) = IfaceNonRec (getOcc b) ()
binding_key (IfaceRec bs) = IfaceRec (map (\(b, _) -> (getOcc b, ())) bs)
diff --git a/compiler/GHC/Iface/Rename.hs b/compiler/GHC/Iface/Rename.hs
index 922f8881ff..b372e7a1d9 100644
--- a/compiler/GHC/Iface/Rename.hs
+++ b/compiler/GHC/Iface/Rename.hs
@@ -231,14 +231,14 @@ rnModule mod = do
return (renameHoleModule unit_state hmap mod)
rnAvailInfo :: Rename AvailInfo
-rnAvailInfo (Avail c) = Avail <$> rnGreName c
+rnAvailInfo (Avail c) = Avail <$> rnIfaceGlobal c
rnAvailInfo (AvailTC n ns) = do
-- Why don't we rnIfaceGlobal the availName itself? It may not
-- actually be exported by the module it putatively is from, in
-- which case we won't be able to tell what the name actually
-- is. But for the availNames they MUST be exported, so they
-- will rename fine.
- ns' <- mapM rnGreName ns
+ ns' <- mapM rnIfaceGlobal ns
case ns' of
[] -> panic "rnAvailInfoEmpty AvailInfo"
(rep:rest) -> assertPpr (all ((== childModule rep) . childModule) rest)
@@ -246,11 +246,7 @@ rnAvailInfo (AvailTC n ns) = do
n' <- setNameModule (Just (childModule rep)) n
return (AvailTC n' ns')
where
- childModule = nameModule . greNameMangledName
-
-rnGreName :: Rename GreName
-rnGreName (NormalGreName n) = NormalGreName <$> rnIfaceGlobal n
-rnGreName (FieldGreName fl) = FieldGreName <$> rnFieldLabel fl
+ childModule = nameModule
rnFieldLabel :: Rename FieldLabel
rnFieldLabel fl = do
@@ -258,8 +254,6 @@ rnFieldLabel fl = do
return (fl { flSelector = sel' })
-
-
-- | The key function. This gets called on every Name embedded
-- inside a ModIface. Our job is to take a Name from some
-- generalized unit ID p[A=\<A>, B=\<B>], and change
@@ -704,9 +698,12 @@ rnIfaceExprs :: Rename [IfaceExpr]
rnIfaceExprs = mapM rnIfaceExpr
rnIfaceIdDetails :: Rename IfaceIdDetails
-rnIfaceIdDetails (IfRecSelId (Left tc) b) = IfRecSelId <$> fmap Left (rnIfaceTyCon tc) <*> pure b
-rnIfaceIdDetails (IfRecSelId (Right decl) b) = IfRecSelId <$> fmap Right (rnIfaceDecl decl) <*> pure b
-rnIfaceIdDetails details = pure details
+rnIfaceIdDetails (IfRecSelId (Left tc) con naughty fl)
+ = IfRecSelId <$> fmap Left (rnIfaceTyCon tc) <*> rnIfaceGlobal con <*> pure naughty <*> rnFieldLabel fl
+rnIfaceIdDetails (IfRecSelId (Right decl) con naughty fl)
+ = IfRecSelId <$> fmap Right (rnIfaceDecl decl) <*> rnIfaceGlobal con <*> pure naughty <*> rnFieldLabel fl
+rnIfaceIdDetails details
+ = pure details
rnIfaceType :: Rename IfaceType
rnIfaceType (IfaceFreeTyVar n) = pure (IfaceFreeTyVar n)
diff --git a/compiler/GHC/Iface/Syntax.hs b/compiler/GHC/Iface/Syntax.hs
index 4ff4ab7eee..71b87cb19c 100644
--- a/compiler/GHC/Iface/Syntax.hs
+++ b/compiler/GHC/Iface/Syntax.hs
@@ -35,6 +35,7 @@ module GHC.Iface.Syntax (
-- Free Names
freeNamesIfDecl, freeNamesIfRule, freeNamesIfFamInst,
+ freeNamesIfConDecls,
-- Pretty printing
pprIfaceExpr,
@@ -80,8 +81,6 @@ import GHC.Utils.Panic
import GHC.Utils.Misc( dropList, filterByList, notNull, unzipWith,
seqList, zipWithEqual )
-import Language.Haskell.Syntax.Basic (FieldLabelString(..))
-
import Control.Monad
import System.IO.Unsafe
import Control.DeepSeq
@@ -385,7 +384,11 @@ data IfGuidance
data IfaceIdDetails
= IfVanillaId
| IfWorkerLikeId [CbvMark]
- | IfRecSelId (Either IfaceTyCon IfaceDecl) Bool
+ | IfRecSelId
+ { ifRecSelIdParent :: Either IfaceTyCon IfaceDecl
+ , ifRecSelFirstCon :: IfaceTopBndr
+ , ifRecSelIdIsNaughty :: Bool
+ , ifRecSelIdFieldLabel :: FieldLabel }
| IfDFunId
-- | Iface type for LambdaFormInfo. Fields not relevant for imported Ids are
@@ -1299,7 +1302,7 @@ pprIfaceConDecl ss gadt_style tycon tc_binders parent
| otherwise = Nothing
where
sel = flSelector lbl
- occ = mkVarOccFS (field_label $ flLabel lbl)
+ occ = nameOccName sel
mk_user_con_res_ty :: IfaceEqSpec -> SDoc
-- See Note [Result type of a data family GADT]
@@ -1504,10 +1507,10 @@ instance Outputable IfaceConAlt where
instance Outputable IfaceIdDetails where
ppr IfVanillaId = Outputable.empty
ppr (IfWorkerLikeId dmd) = text "StrWork" <> parens (ppr dmd)
- ppr (IfRecSelId tc b) = text "RecSel" <+> ppr tc
- <+> if b
- then text "<naughty>"
- else Outputable.empty
+ ppr (IfRecSelId tc _c b _fl) = text "RecSel" <+> ppr tc
+ <+> if b
+ then text "<naughty>"
+ else Outputable.empty
ppr IfDFunId = text "DFunId"
instance Outputable IfaceInfoItem where
@@ -1623,9 +1626,13 @@ freeNamesIfAxBranch (IfaceAxBranch { ifaxbTyVars = tyvars
freeNamesIfType rhs
freeNamesIfIdDetails :: IfaceIdDetails -> NameSet
-freeNamesIfIdDetails (IfRecSelId tc _) =
- either freeNamesIfTc freeNamesIfDecl tc
-freeNamesIfIdDetails _ = emptyNameSet
+freeNamesIfIdDetails (IfRecSelId tc first_con _ fl) =
+ either freeNamesIfTc freeNamesIfDecl tc &&&
+ unitFV first_con &&&
+ unitFV (flSelector fl)
+freeNamesIfIdDetails IfVanillaId = emptyNameSet
+freeNamesIfIdDetails (IfWorkerLikeId {}) = emptyNameSet
+freeNamesIfIdDetails IfDFunId = emptyNameSet
-- All other changes are handled via the version info on the tycon
freeNamesIfFamFlav :: IfaceFamTyConFlav -> NameSet
@@ -1657,7 +1664,7 @@ freeNamesDM _ = emptyNameSet
freeNamesIfConDecls :: IfaceConDecls -> NameSet
freeNamesIfConDecls (IfDataTyCon _ cs) = fnList freeNamesIfConDecl cs
freeNamesIfConDecls (IfNewTyCon c) = freeNamesIfConDecl c
-freeNamesIfConDecls _ = emptyNameSet
+freeNamesIfConDecls _ = emptyNameSet
freeNamesIfConDecl :: IfaceConDecl -> NameSet
freeNamesIfConDecl (IfCon { ifConExTCvs = ex_tvs, ifConCtxt = ctxt
@@ -2264,16 +2271,25 @@ instance Binary IfaceAnnotation where
return (IfaceAnnotation a1 a2)
instance Binary IfaceIdDetails where
- put_ bh IfVanillaId = putByte bh 0
- put_ bh (IfRecSelId a b) = putByte bh 1 >> put_ bh a >> put_ bh b
+ put_ bh IfVanillaId = putByte bh 0
+ put_ bh (IfRecSelId a b c d) = do { putByte bh 1
+ ; put_ bh a
+ ; put_ bh b
+ ; put_ bh c
+ ; put_ bh d }
put_ bh (IfWorkerLikeId dmds) = putByte bh 2 >> put_ bh dmds
- put_ bh IfDFunId = putByte bh 3
+ put_ bh IfDFunId = putByte bh 3
get bh = do
h <- getByte bh
case h of
0 -> return IfVanillaId
- 1 -> do { a <- get bh; b <- get bh; return (IfRecSelId a b) }
- 2 -> do { dmds <- get bh; return (IfWorkerLikeId dmds) }
+ 1 -> do { a <- get bh
+ ; b <- get bh
+ ; c <- get bh
+ ; d <- get bh
+ ; return (IfRecSelId a b c d) }
+ 2 -> do { dmds <- get bh
+ ; return (IfWorkerLikeId dmds) }
_ -> return IfDFunId
instance Binary IfaceInfoItem where
@@ -2693,8 +2709,8 @@ instance NFData IfaceIdDetails where
rnf = \case
IfVanillaId -> ()
IfWorkerLikeId dmds -> dmds `seqList` ()
- IfRecSelId (Left tycon) b -> rnf tycon `seq` rnf b
- IfRecSelId (Right decl) b -> rnf decl `seq` rnf b
+ IfRecSelId (Left tycon) b c d -> rnf tycon `seq` rnf b `seq` rnf c `seq` rnf d
+ IfRecSelId (Right decl) b c d -> rnf decl `seq` rnf b `seq` rnf c `seq` rnf d
IfDFunId -> ()
instance NFData IfaceInfoItem where
diff --git a/compiler/GHC/IfaceToCore.hs b/compiler/GHC/IfaceToCore.hs
index 4a4c2a6cee..aaacb86b7f 100644
--- a/compiler/GHC/IfaceToCore.hs
+++ b/compiler/GHC/IfaceToCore.hs
@@ -10,6 +10,8 @@ Type checking of type signatures in interface files
{-# LANGUAGE NondecreasingIndentation #-}
{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE RecursiveDo #-}
+
{-# OPTIONS_GHC -Wno-incomplete-record-updates #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE RecordWildCards #-}
@@ -699,7 +701,7 @@ tc_iface_decl :: Maybe Class -- ^ For associated type/data family declarations
tc_iface_decl _ ignore_prags (IfaceId {ifName = name, ifType = iface_type,
ifIdDetails = details, ifIdInfo = info})
= do { ty <- tcIfaceType iface_type
- ; details <- tcIdDetails ty details
+ ; details <- tcIdDetails name ty details
; info <- tcIdInfo ignore_prags TopLevel name ty info
; return (AnId (mkGlobalId details name ty info)) }
@@ -955,10 +957,15 @@ mk_top_id (IfGblTopBndr gbl_name)
return $ mkExportedVanillaId gbl_name (mkTyConApp ioTyCon [unitTy])
| otherwise = tcIfaceExtId gbl_name
mk_top_id (IfLclTopBndr raw_name iface_type info details) = do
- name <- newIfaceName (mkVarOccFS raw_name)
ty <- tcIfaceType iface_type
+ rec { details' <- tcIdDetails name ty details
+ ; let occ = case details' of
+ RecSelId { sel_tycon = parent }
+ -> let con_fs = getOccFS $ recSelFirstConName parent
+ in mkRecFieldOccFS con_fs raw_name
+ _ -> mkVarOccFS raw_name
+ ; name <- newIfaceName occ }
info' <- tcIdInfo False TopLevel name ty info
- details' <- tcIdDetails ty details
let new_id = mkGlobalId details' name ty info'
return new_id
@@ -1691,19 +1698,19 @@ tcIfaceDataAlt mult con inst_tys arg_strs rhs
************************************************************************
-}
-tcIdDetails :: Type -> IfaceIdDetails -> IfL IdDetails
-tcIdDetails _ IfVanillaId = return VanillaId
-tcIdDetails _ (IfWorkerLikeId dmds) = return $ WorkerLikeId dmds
-tcIdDetails ty IfDFunId
+tcIdDetails :: Name -> Type -> IfaceIdDetails -> IfL IdDetails
+tcIdDetails _ _ IfVanillaId = return VanillaId
+tcIdDetails _ _ (IfWorkerLikeId dmds) = return $ WorkerLikeId dmds
+tcIdDetails _ ty IfDFunId
= return (DFunId (isNewTyCon (classTyCon cls)))
where
(_, _, cls, _) = tcSplitDFunTy ty
-tcIdDetails _ (IfRecSelId tc naughty)
+tcIdDetails nm _ (IfRecSelId tc _first_con naughty fl)
= do { tc' <- either (fmap RecSelData . tcIfaceTyCon)
(fmap (RecSelPatSyn . tyThingPatSyn) . tcIfaceDecl False)
tc
- ; return (RecSelId { sel_tycon = tc', sel_naughty = naughty }) }
+ ; return (RecSelId { sel_tycon = tc', sel_naughty = naughty, sel_fieldLabel = fl { flSelector = nm } }) }
where
tyThingPatSyn (AConLike (PatSynCon ps)) = ps
tyThingPatSyn _ = panic "tcIdDetails: expecting patsyn"
diff --git a/compiler/GHC/Parser/PostProcess.hs b/compiler/GHC/Parser/PostProcess.hs
index f505e9b59d..0b7053dcbb 100644
--- a/compiler/GHC/Parser/PostProcess.hs
+++ b/compiler/GHC/Parser/PostProcess.hs
@@ -2523,7 +2523,7 @@ mkRdrRecordUpd overloaded_on exp@(L loc _) fbinds anns = do
-- overloaded_on) is in effect because it affects the Left/Right nature
-- of the RecordUpd value we calculate.
let (fs, ps) = partitionEithers fbinds
- fs' :: [LHsRecUpdField GhcPs]
+ fs' :: [LHsRecUpdField GhcPs GhcPs]
fs' = map (fmap mk_rec_upd_field) fs
case overloaded_on of
False | not $ null ps ->
@@ -2534,19 +2534,27 @@ mkRdrRecordUpd overloaded_on exp@(L loc _) fbinds anns = do
return RecordUpd {
rupd_ext = anns
, rupd_expr = exp
- , rupd_flds = Left fs' }
+ , rupd_flds =
+ RegularRecUpdFields
+ { xRecUpdFields = noExtField
+ , recUpdFields = fs' } }
+ -- This is a RecordDotSyntax update.
True -> do
let qualifiedFields =
[ L l lbl | L _ (HsFieldBind _ (L l lbl) _ _) <- fs'
- , isQual . rdrNameAmbiguousFieldOcc $ lbl
+ , isQual . ambiguousFieldOccRdrName $ lbl
]
case qualifiedFields of
qf:_ -> addFatalError $ mkPlainErrorMsgEnvelope (getLocA qf) $
- PsErrOverloadedRecordUpdateNoQualifiedFields
- _ -> return RecordUpd -- This is a RecordDotSyntax update.
- { rupd_ext = anns
- , rupd_expr = exp
- , rupd_flds = Right (toProjUpdates fbinds) }
+ PsErrOverloadedRecordUpdateNoQualifiedFields
+ _ -> return $
+ RecordUpd
+ { rupd_ext = anns
+ , rupd_expr = exp
+ , rupd_flds =
+ OverloadedRecUpdFields
+ { xOLRecUpdFields = noExtField
+ , olRecUpdFields = toProjUpdates fbinds } }
where
toProjUpdates :: [Fbind (HsExpr GhcPs)] -> [LHsRecUpdProj GhcPs]
toProjUpdates = map (\case { Right p -> p; Left f -> recFieldToProjUpdate f })
@@ -2578,7 +2586,7 @@ mk_rec_fields fs Nothing = HsRecFields { rec_flds = fs, rec_dotdot = Nothing }
mk_rec_fields fs (Just s) = HsRecFields { rec_flds = fs
, rec_dotdot = Just (L s (RecFieldsDotDot $ length fs)) }
-mk_rec_upd_field :: HsRecField GhcPs (LHsExpr GhcPs) -> HsRecUpdField GhcPs
+mk_rec_upd_field :: HsRecField GhcPs (LHsExpr GhcPs) -> HsRecUpdField GhcPs GhcPs
mk_rec_upd_field (HsFieldBind noAnn (L loc (FieldOcc _ rdr)) arg pun)
= HsFieldBind noAnn (L loc (Unambiguous noExtField rdr)) arg pun
diff --git a/compiler/GHC/Rename/Doc.hs b/compiler/GHC/Rename/Doc.hs
index b278e02cf3..006bc2689b 100644
--- a/compiler/GHC/Rename/Doc.hs
+++ b/compiler/GHC/Rename/Doc.hs
@@ -8,7 +8,6 @@ import GHC.Types.Name.Reader
import GHC.Types.Name
import GHC.Types.SrcLoc
import GHC.Tc.Utils.Monad (getGblEnv)
-import GHC.Types.Avail
import GHC.Rename.Env
rnLHsDoc :: LHsDoc GhcPs -> RnM (LHsDoc GhcRn)
@@ -37,10 +36,10 @@ rnHsDoc (WithHsDocIdentifiers s ids) = do
pure (WithHsDocIdentifiers s (rnHsDocIdentifiers gre ids))
rnHsDocIdentifiers :: GlobalRdrEnv
- -> [Located RdrName]
- -> [Located Name]
-rnHsDocIdentifiers gre ns = concat
- [ map (L l . greNamePrintableName . gre_name) (lookupGRE_RdrName c gre)
+ -> [Located RdrName]
+ -> [Located Name]
+rnHsDocIdentifiers gre_env ns = concat
+ [ map (L l . greName) (lookupGRE_RdrName (IncludeFields WantNormal) gre_env c)
| L l rdr_name <- ns
, c <- dataTcOccs rdr_name
]
diff --git a/compiler/GHC/Rename/Env.hs b/compiler/GHC/Rename/Env.hs
index a4e1ef0a77..9155a86bf0 100644
--- a/compiler/GHC/Rename/Env.hs
+++ b/compiler/GHC/Rename/Env.hs
@@ -1,5 +1,6 @@
-{-# LANGUAGE NamedFieldPuns #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE TypeApplications #-}
{-
@@ -17,26 +18,28 @@ module GHC.Rename.Env (
lookupLocatedOccRn, lookupLocatedOccRnConstr, lookupLocatedOccRnRecField,
lookupLocatedOccRnNone,
- lookupOccRn, lookupOccRn_maybe,
+ lookupOccRn, lookupOccRn_maybe, lookupSameOccRn_maybe,
lookupLocalOccRn_maybe, lookupInfoOccRn,
lookupLocalOccThLvl_maybe, lookupLocalOccRn,
lookupTypeOccRn,
lookupGlobalOccRn, lookupGlobalOccRn_maybe,
- AmbiguousResult(..),
lookupExprOccRn,
lookupRecFieldOcc,
- lookupRecFieldOcc_update,
+ lookupRecUpdFields,
+ getFieldUpdLbl,
+ getUpdFieldLbls,
ChildLookupResult(..),
lookupSubBndrOcc_helper,
combineChildLookupResult, -- Called by lookupChildrenExport
HsSigCtxt(..), lookupLocalTcNames, lookupSigOccRn, lookupSigOccRnN,
- lookupSigCtxtOccRn, lookupSigCtxtOccRnN,
+ lookupSigCtxtOccRn,
lookupInstDeclBndr, lookupFamInstName,
lookupConstructorInfo, lookupConstructorFields,
+ lookupGREInfo,
lookupGreAvailRn,
@@ -60,7 +63,9 @@ module GHC.Rename.Env (
import GHC.Prelude
-import GHC.Iface.Load ( loadInterfaceForName, loadSrcInterface_maybe )
+import Language.Haskell.Syntax.Basic (FieldLabelString(..))
+
+import GHC.Iface.Load
import GHC.Iface.Env
import GHC.Hs
import GHC.Types.Name.Reader
@@ -71,7 +76,7 @@ import GHC.Parser.PostProcess ( setRdrNameSpace )
import GHC.Builtin.Types
import GHC.Types.Name
import GHC.Types.Name.Set
-import GHC.Types.Name.Env
+import GHC.Types.Name.Env ( lookupNameEnv )
import GHC.Types.Avail
import GHC.Types.Hint
import GHC.Types.Error
@@ -82,30 +87,35 @@ import GHC.Core.ConLike
import GHC.Core.DataCon
import GHC.Core.TyCon
import GHC.Builtin.Names( rOOT_MAIN )
-import GHC.Types.Basic ( TopLevelFlag(..), TupleSort(..) )
+import GHC.Types.Basic ( TopLevelFlag(..), TupleSort(..), tupleSortBoxity )
+import GHC.Types.TyThing ( tyThingGREInfo )
import GHC.Types.SrcLoc as SrcLoc
import GHC.Utils.Outputable as Outputable
-import GHC.Types.Unique.Set ( uniqSetAny )
+import GHC.Types.Unique.FM
+import GHC.Types.Unique.Set
import GHC.Utils.Misc
import GHC.Utils.Panic
+import GHC.Utils.Panic.Plain (assert)
import GHC.Data.Maybe
+import GHC.Driver.Env
import GHC.Driver.Session
import GHC.Data.FastString
-import Control.Monad
import GHC.Data.List.SetOps ( minusList )
import qualified GHC.LanguageExtensions as LangExt
import GHC.Rename.Unbound
import GHC.Rename.Utils
-import qualified Data.Semigroup as Semi
-import Data.Either ( partitionEithers )
-import Data.List ( find )
-import qualified Data.List.NonEmpty as NE
-import Control.Arrow ( first )
-import GHC.Types.FieldLabel
import GHC.Data.Bag
import GHC.Types.PkgQual
-import Language.Haskell.Syntax.Basic (FieldLabelString(..))
-import GHC.Types.ConInfo (ConInfo, conInfoFields, mkConInfo)
+import GHC.Types.GREInfo
+
+import Control.Arrow ( first )
+import Control.Monad
+import Data.Either ( partitionEithers )
+import Data.Function ( on )
+import Data.List ( find, partition, groupBy, sortBy )
+import qualified Data.List.NonEmpty as NE
+import qualified Data.Semigroup as Semi
+import System.IO.Unsafe ( unsafePerformIO )
{-
*********************************************************
@@ -276,17 +286,16 @@ lookupTopBndrRn :: WhatLooking -> RdrName -> RnM Name
-- A separate function (importsFromLocalDecls) reports duplicate top level
-- decls, so here it's safe just to choose an arbitrary one.
lookupTopBndrRn which_suggest rdr_name =
- lookupExactOrOrig rdr_name id $
+ lookupExactOrOrig rdr_name greName $
do { -- Check for operators in type or class declarations
-- See Note [Type and class operator definitions]
let occ = rdrNameOcc rdr_name
; when (isTcOcc occ && isSymOcc occ)
(do { op_ok <- xoptM LangExt.TypeOperators
; unless op_ok (addErr (TcRnIllegalTypeOperatorDecl rdr_name)) })
-
; env <- getGlobalRdrEnv
- ; case filter isLocalGRE (lookupGRE_RdrName rdr_name env) of
- [gre] -> return (greMangledName gre)
+ ; case filter isLocalGRE (lookupGRE_RdrName (IncludeFields WantNormal) env rdr_name) of
+ [gre] -> return (greName gre)
_ -> do -- Ambiguous (can't happen) or unbound
traceRn "lookupTopBndrRN fail" (ppr rdr_name)
unboundName (LF which_suggest WL_LocalTop) rdr_name
@@ -307,7 +316,7 @@ lookupLocatedTopBndrRnN = wrapLocMA (lookupTopBndrRn WL_Anything)
-- | Lookup an @Exact@ @RdrName@. See Note [Looking up Exact RdrNames].
-- This never adds an error, but it may return one, see
-- Note [Errors in lookup functions]
-lookupExactOcc_either :: Name -> RnM (Either NotInScopeError Name)
+lookupExactOcc_either :: Name -> RnM (Either NotInScopeError GlobalRdrElt)
lookupExactOcc_either name
| Just thing <- wiredInNameTyThing_maybe name
, Just tycon <- case thing of
@@ -321,39 +330,57 @@ lookupExactOcc_either name
UnboxedTuple -> tyConArity tycon `div` 2
_ -> tyConArity tycon
; checkTupSize tupArity
- ; return (Right name) }
+ ; let gre = (localTyConGRE (TupleFlavour $ tupleSortBoxity tupleSort) name)
+ { gre_lcl = False }
+ ; return (Right gre) }
| isExternalName name
- = return (Right name)
+ = Right <$> lookupExternalExactGRE name
| otherwise
+ = lookupLocalExactGRE name
+
+lookupExternalExactGRE :: Name -> RnM GlobalRdrElt
+lookupExternalExactGRE name
+ = do { thing <-
+ case wiredInNameTyThing_maybe name of
+ Just thing -> return thing
+ _ -> tcLookupGlobal name
+ ; return $
+ (localVanillaGRE NoParent name)
+ { gre_lcl = False, gre_info = tyThingGREInfo thing } }
+
+lookupLocalExactGRE :: Name -> RnM (Either NotInScopeError GlobalRdrElt)
+lookupLocalExactGRE name
= do { env <- getGlobalRdrEnv
- ; let -- See Note [Splicing Exact names]
- main_occ = nameOccName name
+ ; let main_occ = nameOccName name
demoted_occs = case demoteOccName main_occ of
Just occ -> [occ]
Nothing -> []
gres = [ gre | occ <- main_occ : demoted_occs
- , gre <- lookupGlobalRdrEnv env occ
- , greMangledName gre == name ]
+ , gre <- lookupGRE_OccName (IncludeFields WantBoth) env occ
+ -- We're filtering by an exact 'Name' match,
+ -- so we should look up as many potential matches as possible.
+ -- See also test case T11809.
+ , greName gre == name ]
; case gres of
- [gre] -> return (Right (greMangledName gre))
+ [gre] -> return (Right gre)
[] -> -- See Note [Splicing Exact names]
do { lcl_env <- getLocalRdrEnv
+ ; let gre = localVanillaGRE NoParent name -- LocalRdrEnv only contains Vanilla things
; if name `inLocalRdrEnvScope` lcl_env
- then return (Right name)
+ then return (Right gre)
else
do { th_topnames_var <- fmap tcg_th_topnames getGblEnv
; th_topnames <- readTcRef th_topnames_var
; if name `elemNameSet` th_topnames
- then return (Right name)
+ then return (Right gre)
else return (Left (NoExactName name))
}
}
- gres -> return (Left (SameName gres)) -- Ugh! See Note [Template Haskell ambiguity]
- }
+ gres -> return (Left (SameName gres)) } -- Ugh! See Note [Template Haskell ambiguity] }
-----------------------------------------------
lookupInstDeclBndr :: Name -> SDoc -> RdrName -> RnM Name
@@ -400,53 +427,37 @@ lookupFamInstName (Just cls) tc_rdr -- Associated type; c.f GHC.Rename.Bind.rnM
lookupFamInstName Nothing tc_rdr -- Family instance; tc_rdr is an *occurrence*
= lookupLocatedOccRnConstr tc_rdr
-lookupConstructorInfo :: Name -> RnM ConInfo
--- Look up the info for a given constructor
--- * For constructors from this module, use the record field env,
--- which is itself gathered from the (as yet un-typechecked)
--- data type decls
--- For more details, see Note [Local constructor info in the renamer]
---
--- * For constructors from imported modules, use the *type* environment
--- since imported modules are already compiled, the info is conveniently
--- right there
-
-lookupConstructorInfo con_name
- = do { this_mod <- getModule
- ; if nameIsLocalOrFrom this_mod con_name then
- do { con_env <- getConEnv
- ; let conInfo = lookupNameEnv con_env con_name
- ; traceTc "lookupCF" (ppr con_name $$ ppr conInfo $$ ppr con_env)
- -- we always info for all the constructors in the current module in GHC.Rename.mk_con_env
- -- hence we should be able to look up the constructor in tcg_con_env if it's from the current module
- ; return (conInfo `orElse` panic "GHC.Rename.Env.lookupConstructorInfo") }
- else
- do { con <- tcLookupConLike con_name
- ; traceTc "lookupCF 2" (ppr con)
- ; pure $ mkConInfo (conLikeArity con) (conLikeFieldLabels con) } }
-
-----------------------------------------------
lookupConstructorFields :: Name -> RnM [FieldLabel]
lookupConstructorFields = fmap conInfoFields . lookupConstructorInfo
+-- | Look up the arity and record fields of a constructor.
+lookupConstructorInfo :: Name -> RnM ConInfo
+lookupConstructorInfo con_name
+ = do { info <- lookupGREInfo_GRE con_name
+ ; case info of
+ IAmConLike con_info -> return con_info
+ _ -> pprPanic "lookupConstructorInfo: not a ConLike" $
+ vcat [ text "name:" <+> ppr con_name ]
+ }
-- In CPS style as `RnM r` is monadic
-- Reports an error if the name is an Exact or Orig and it can't find the name
-- Otherwise if it is not an Exact or Orig, returns k
-lookupExactOrOrig :: RdrName -> (Name -> r) -> RnM r -> RnM r
+lookupExactOrOrig :: RdrName -> (GlobalRdrElt -> r) -> RnM r -> RnM r
lookupExactOrOrig rdr_name res k
= do { men <- lookupExactOrOrig_base rdr_name
; case men of
- FoundExactOrOrig n -> return (res n)
+ FoundExactOrOrig n -> return $ res n
ExactOrOrigError e ->
do { addErr (mkTcRnNotInScope rdr_name e)
- ; return (res (mkUnboundNameRdr rdr_name)) }
+ ; return $ res (mkUnboundGRERdr rdr_name) }
NotExactOrOrig -> k }
-- Variant of 'lookupExactOrOrig' that does not report an error
-- See Note [Errors in lookup functions]
-- Calls k if the name is neither an Exact nor Orig
-lookupExactOrOrig_maybe :: RdrName -> (Maybe Name -> r) -> RnM r -> RnM r
+lookupExactOrOrig_maybe :: RdrName -> (Maybe GlobalRdrElt -> r) -> RnM r -> RnM r
lookupExactOrOrig_maybe rdr_name res k
= do { men <- lookupExactOrOrig_base rdr_name
; case men of
@@ -454,12 +465,15 @@ lookupExactOrOrig_maybe rdr_name res k
ExactOrOrigError _ -> return (res Nothing)
NotExactOrOrig -> k }
-data ExactOrOrigResult = FoundExactOrOrig Name -- ^ Found an Exact Or Orig Name
- | ExactOrOrigError NotInScopeError -- ^ The RdrName was an Exact
- -- or Orig, but there was an
- -- error looking up the Name
- | NotExactOrOrig -- ^ The RdrName is neither an Exact nor
- -- Orig
+data ExactOrOrigResult
+ = FoundExactOrOrig GlobalRdrElt
+ -- ^ Found an Exact Or Orig Name
+ | ExactOrOrigError NotInScopeError
+ -- ^ The RdrName was an Exact
+ -- or Orig, but there was an
+ -- error looking up the Name
+ | NotExactOrOrig
+ -- ^ The RdrName is neither an Exact nor Orig
-- Does the actual looking up an Exact or Orig name, see 'ExactOrOrigResult'
lookupExactOrOrig_base :: RdrName -> RnM ExactOrOrigResult
@@ -467,7 +481,16 @@ lookupExactOrOrig_base rdr_name
| Just n <- isExact_maybe rdr_name -- This happens in derived code
= cvtEither <$> lookupExactOcc_either n
| Just (rdr_mod, rdr_occ) <- isOrig_maybe rdr_name
- = FoundExactOrOrig <$> lookupOrig rdr_mod rdr_occ
+ = do { nm <- lookupOrig rdr_mod rdr_occ
+
+ ; this_mod <- getModule
+ ; mb_gre <-
+ if nameIsLocalOrFrom this_mod nm
+ then lookupLocalExactGRE nm
+ else Right <$> lookupExternalExactGRE nm
+ ; return $ case mb_gre of
+ Left err -> ExactOrOrigError err
+ Right gre -> FoundExactOrOrig gre }
| otherwise = return NotExactOrOrig
where
cvtEither (Left e) = ExactOrOrigError e
@@ -495,10 +518,10 @@ counterparts.
-----------------------------------------------
-- | Look up an occurrence of a field in record construction or pattern
--- matching (but not update). When the -XDisambiguateRecordFields
--- flag is on, take account of the data constructor name to
--- disambiguate which field to use.
+-- matching (but not update).
--
+-- If -XDisambiguateRecordFields is off, then we will pass 'Nothing' for the
+-- 'DataCon' 'Name', i.e. we don't use the data constructor for disambiguation.
-- See Note [DisambiguateRecordFields] and Note [NoFieldSelectors].
lookupRecFieldOcc :: Maybe Name -- Nothing => just look it up as usual
-- Just con => use data con to disambiguate
@@ -507,66 +530,48 @@ lookupRecFieldOcc :: Maybe Name -- Nothing => just look it up as usual
lookupRecFieldOcc mb_con rdr_name
| Just con <- mb_con
, isUnboundName con -- Avoid error cascade
- = return (mkUnboundNameRdr rdr_name)
+ = return $ mk_unbound_rec_fld con
| Just con <- mb_con
- = lookupExactOrOrig rdr_name id $ -- See Note [Record field names and Template Haskell]
- do { flds <- lookupConstructorFields con
- ; env <- getGlobalRdrEnv
- ; let lbl = FieldLabelString $ occNameFS (rdrNameOcc rdr_name)
- mb_field = do fl <- find ((== lbl) . flLabel) flds
- -- We have the label, now check it is in scope. If
- -- there is a qualifier, use pickGREs to check that
- -- the qualifier is correct, and return the filtered
- -- GRE so we get import usage right (see #17853).
- gre <- lookupGRE_FieldLabel env fl
- if isQual rdr_name
- then do gre' <- listToMaybe (pickGREs rdr_name [gre])
- return (fl, gre')
- else return (fl, gre)
- ; case mb_field of
- Just (fl, gre) -> do { addUsedGRE True gre
- ; return (flSelector fl) }
- Nothing -> do { addErr (badFieldConErr con lbl)
- ; return (mkUnboundNameRdr rdr_name) } }
+ = do { let lbl = FieldLabelString $ occNameFS (rdrNameOcc rdr_name)
+ ; res <- lookupExactOrOrig rdr_name ensure_recfld $ -- See Note [Record field names and Template Haskell]
+ do { flds <- lookupConstructorFields con
+ ; env <- getGlobalRdrEnv
+ ; let lbl = FieldLabelString $ occNameFS (rdrNameOcc rdr_name)
+ mb_gre = do fl <- find ((== lbl) . flLabel) flds
+ -- We have the label, now check it is in scope. If
+ -- there is a qualifier, use pickGREs to check that
+ -- the qualifier is correct, and return the filtered
+ -- GRE so we get import usage right (see #17853).
+ gre <- lookupGRE_FieldLabel env fl
+ if isQual rdr_name
+ then listToMaybe (pickGREs rdr_name [gre])
+ else return gre
+ ; traceRn "lookupRecFieldOcc" $
+ vcat [ text "mb_con:" <+> ppr mb_con
+ , text "rdr_name:" <+> ppr rdr_name
+ , text "flds:" <+> ppr flds
+ , text "mb_gre:" <+> ppr mb_gre ]
+ ; return mb_gre }
+ ; case res of
+ { Nothing -> do { addErr (badFieldConErr con lbl)
+ ; return $ mk_unbound_rec_fld con }
+ ; Just gre -> do { addUsedGRE True gre
+ ; return (flSelector $ fieldGRELabel gre) } } }
| otherwise -- Can't use the data constructor to disambiguate
- = lookupGlobalOccRn' WantBoth rdr_name
+ = greName <$> lookupGlobalOccRn' (IncludeFields WantField) rdr_name
-- This use of Global is right as we are looking up a selector,
-- which can only be defined at the top level.
--- | Look up an occurrence of a field in a record update, returning the selector
--- name.
---
--- Unlike construction and pattern matching with @-XDisambiguateRecordFields@
--- (see 'lookupRecFieldOcc'), there is no data constructor to help disambiguate,
--- so this may be ambiguous if the field is in scope multiple times. However we
--- ignore non-fields in scope with the same name if @-XDisambiguateRecordFields@
--- is on (see Note [DisambiguateRecordFields for updates]).
---
--- Here a field is in scope even if @NoFieldSelectors@ was enabled at its
--- definition site (see Note [NoFieldSelectors]).
-lookupRecFieldOcc_update
- :: DuplicateRecordFields
- -> RdrName
- -> RnM AmbiguousResult
-lookupRecFieldOcc_update dup_fields_ok rdr_name = do
- disambig_ok <- xoptM LangExt.DisambiguateRecordFields
- let want | disambig_ok = WantField
- | otherwise = WantBoth
- mr <- lookupGlobalOccRn_overloaded dup_fields_ok want rdr_name
- case mr of
- Just r -> return r
- Nothing -- Try again if we previously looked only for fields, see
- -- Note [DisambiguateRecordFields for updates]
- | disambig_ok -> do mr' <- lookupGlobalOccRn_overloaded dup_fields_ok WantBoth rdr_name
- case mr' of
- Just r -> return r
- Nothing -> unbound
- | otherwise -> unbound
where
- unbound = UnambiguousGre . NormalGreName
- <$> unboundName (LF WL_RecField WL_Global) rdr_name
+ -- When lookup fails, make an unbound name with the right record field
+ -- namespace, as that's what we expect to be returned
+ -- from 'lookupRecFieldOcc'. See T14307.
+ mk_unbound_rec_fld con = mkUnboundName $
+ mkRecFieldOccFS (getOccFS con) (occNameFS occ)
+ occ = rdrNameOcc rdr_name
+ ensure_recfld gre = do { guard (isRecFldGRE gre) ; return gre }
{- Note [DisambiguateRecordFields]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -622,31 +627,36 @@ data constructor name (as in Note [DisambiguateRecordFields]), provided the
For example, consider:
- module N where
- f = ()
+ module N where
+ f = ()
- {-# LANGUAGE DisambiguateRecordFields #-}
- module M where
- import N (f)
- data T = MkT { f :: Int }
- t = MkT { f = 1 } -- unambiguous because MkT determines which field we mean
- u = t { f = 2 } -- unambiguous because we ignore the non-field 'f'
+ {-# LANGUAGE DisambiguateRecordFields #-}
+ module M where
+ import N (f)
+ data T = MkT { f :: Int }
+ t = MkT { f = 1 } -- unambiguous because MkT determines which field we mean
+ u = t { f = 2 } -- unambiguous because we ignore the non-field 'f'
-This works by lookupRecFieldOcc_update using 'WantField :: FieldsOrSelectors'
-when looking up the field name, so that 'filterFieldGREs' will later ignore any
-non-fields in scope. Of course, if a record update has two fields in scope with
-the same name, it is still ambiguous.
+We filter out non-fields in lookupFieldGREs by using isRecFldGRE, which allows
+us to accept the above program.
+Of course, if a record update has two fields in scope with the same name,
+it is still ambiguous.
-If we do not find anything when looking only for fields, we try again allowing
-fields or non-fields. This leads to a better error message if the user
-mistakenly tries to use a non-field name in a record update:
+We also look up the non-fields with the same textual name
- f = ()
- e x = x { f = () }
+ 1. to throw an error if the user hasn't enabled DisambiguateRecordFields,
+ 2. in order to improve the error message when a user mistakenly tries to use
+ a non-field in a record update:
+
+ f = ()
+ e x = x { f = () }
Unlike with constructors or pattern-matching, we do not allow the module
-qualifier to be omitted, because we do not have a data constructor from which to
-determine it.
+qualifier to be omitted from the field names, because we do not have a
+data constructor to use to determine the appropriate qualifier.
+
+This is all done in the function lookupFieldGREs, which is called by
+GHC.Rename.Pat.rnHsRecUpdFields, which deals with record updates.
Note [Record field names and Template Haskell]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -674,12 +684,15 @@ lookupSubBndrOcc_helper :: Bool -> Bool -> Name -> RdrName
lookupSubBndrOcc_helper must_have_parent warn_if_deprec parent rdr_name
| isUnboundName parent
-- Avoid an error cascade
- = return (FoundChild NoParent (NormalGreName (mkUnboundNameRdr rdr_name)))
+ = return (FoundChild (mkUnboundGRERdr rdr_name))
| otherwise = do
gre_env <- getGlobalRdrEnv
- let original_gres = lookupGlobalRdrEnv gre_env (rdrNameOcc rdr_name)
+ let original_gres = lookupGRE_OccName (IncludeFields WantBoth) gre_env (rdrNameOcc rdr_name)
+ -- WantBoth: we are looking for children, so we want to include fields defined
+ -- with no field selectors, as we can export those as children. See test NFSExport.
+
-- Disambiguate the lookup based on the parent information.
-- The remaining GREs are things that we *could* export here, note that
-- this includes things which have `NoParent`. Those are sorted in
@@ -698,11 +711,10 @@ lookupSubBndrOcc_helper must_have_parent warn_if_deprec parent rdr_name
AmbiguousOccurrence gres ->
mkNameClashErr gres
where
- -- Convert into FieldLabel if necessary
checkFld :: GlobalRdrElt -> RnM ChildLookupResult
- checkFld g@GRE{gre_name,gre_par} = do
+ checkFld g = do
addUsedGRE warn_if_deprec g
- return $ FoundChild gre_par gre_name
+ return $ FoundChild g
-- Called when we find no matching GREs after disambiguation but
-- there are three situations where this happens.
@@ -720,21 +732,19 @@ lookupSubBndrOcc_helper must_have_parent warn_if_deprec parent rdr_name
dup_fields_ok <- xoptM LangExt.DuplicateRecordFields
case original_gres of
[] -> return NameNotFound
- [g] -> return $ IncorrectParent parent
- (gre_name g)
+ [g] -> return $ IncorrectParent parent g
[p | Just p <- [getParent g]]
gss@(g:gss'@(_:_)) ->
if all isRecFldGRE gss && dup_fields_ok
then return $
- IncorrectParent parent
- (gre_name g)
+ IncorrectParent parent g
[p | x <- gss, Just p <- [getParent x]]
else mkNameClashErr $ g NE.:| gss'
mkNameClashErr :: NE.NonEmpty GlobalRdrElt -> RnM ChildLookupResult
mkNameClashErr gres = do
addNameClashErrRn rdr_name gres
- return (FoundChild (gre_par (NE.head gres)) (gre_name (NE.head gres)))
+ return (FoundChild (NE.head gres))
getParent :: GlobalRdrElt -> Maybe Name
getParent (GRE { gre_par = p } ) =
@@ -805,11 +815,14 @@ instance Monoid DisambigInfo where
--
-- Records the result of looking up a child.
data ChildLookupResult
- = NameNotFound -- We couldn't find a suitable name
- | IncorrectParent Name -- Parent
- GreName -- Child we were looking for
- [Name] -- List of possible parents
- | FoundChild Parent GreName -- We resolved to a child
+ -- | We couldn't find a suitable name
+ = NameNotFound
+ -- | The child has an incorrect parent
+ | IncorrectParent Name -- ^ parent
+ GlobalRdrElt -- ^ child we were looking for
+ [Name] -- ^ list of possible parents
+ -- | We resolved to a child
+ | FoundChild GlobalRdrElt
-- | Specialised version of msum for RnM ChildLookupResult
combineChildLookupResult :: [RnM ChildLookupResult] -> RnM ChildLookupResult
@@ -822,9 +835,10 @@ combineChildLookupResult (x:xs) = do
instance Outputable ChildLookupResult where
ppr NameNotFound = text "NameNotFound"
- ppr (FoundChild p n) = text "Found:" <+> ppr p <+> ppr n
- ppr (IncorrectParent p n ns) = text "IncorrectParent"
- <+> hsep [ppr p, ppr n, ppr ns]
+ ppr (FoundChild n) = text "Found:" <+> ppr (gre_par n) <+> ppr n
+ ppr (IncorrectParent p g ns)
+ = text "IncorrectParent"
+ <+> hsep [ppr p, ppr $ greName g, ppr ns]
lookupSubBndrOcc :: Bool
-> Name -- Parent
@@ -835,12 +849,12 @@ lookupSubBndrOcc :: Bool
-- and pick the one with the right parent name
lookupSubBndrOcc warn_if_deprec the_parent doc rdr_name = do
res <-
- lookupExactOrOrig rdr_name (FoundChild NoParent . NormalGreName) $
+ lookupExactOrOrig rdr_name FoundChild $
-- This happens for built-in classes, see mod052 for example
lookupSubBndrOcc_helper True warn_if_deprec the_parent rdr_name
case res of
NameNotFound -> return (Left (UnknownSubordinate doc))
- FoundChild _p child -> return (Right (greNameMangledName child))
+ FoundChild child -> return (Right $ greName child)
IncorrectParent {}
-- See [Mismatched class methods and associated type families]
-- in TcInstDecls.
@@ -1016,9 +1030,9 @@ lookupLocalOccThLvl_maybe name
-- determine what kind of suggestions should be displayed if it is not in scope
lookupOccRn' :: WhatLooking -> RdrName -> RnM Name
lookupOccRn' which_suggest rdr_name
- = do { mb_name <- lookupOccRn_maybe rdr_name
- ; case mb_name of
- Just name -> return name
+ = do { mb_gre <- lookupOccRn_maybe rdr_name
+ ; case mb_gre of
+ Just gre -> return $ greName gre
Nothing -> reportUnboundName' which_suggest rdr_name }
-- lookupOccRn looks up an occurrence of a RdrName and displays suggestions if
@@ -1055,12 +1069,12 @@ lookupLocalOccRn rdr_name
lookupTypeOccRn :: RdrName -> RnM Name
-- see Note [Demotion]
lookupTypeOccRn rdr_name
- | isVarOcc (rdrNameOcc rdr_name) -- See Note [Promoted variables in types]
+ | (isVarOcc <||> isFieldOcc) (rdrNameOcc rdr_name) -- See Note [Promoted variables in types]
= badVarInType rdr_name
| otherwise
- = do { mb_name <- lookupOccRn_maybe rdr_name
- ; case mb_name of
- Just name -> return name
+ = do { mb_gre <- lookupOccRn_maybe rdr_name
+ ; case mb_gre of
+ Just gre -> return $ greName gre
Nothing ->
if occName rdr_name == occName eqTyCon_RDR -- See Note [eqTyCon (~) compatibility fallback]
then eqTyConName <$ addDiagnostic TcRnTypeEqualityOutOfScope
@@ -1092,7 +1106,7 @@ lookup_demoted rdr_name
then do { mb_demoted_name <- lookupOccRn_maybe demoted_rdr
; case mb_demoted_name of
Nothing -> unboundNameX looking_for rdr_name star_is_type_hints
- Just demoted_name -> return demoted_name }
+ Just demoted_name -> return $ greName demoted_name }
else do { -- We need to check if a data constructor of this name is
-- in scope to give good error messages. However, we do
-- not want to give an additional error if the data
@@ -1120,7 +1134,7 @@ lookup_demoted rdr_name
-- ^^^^^^^^^^^
report_qualified_term_in_types :: RdrName -> RdrName -> RnM Name
report_qualified_term_in_types rdr_name demoted_rdr_name =
- do { mName <- lookupGlobalOccRn_maybe demoted_rdr_name
+ do { mName <- lookupGlobalOccRn_maybe (IncludeFields WantNormal) demoted_rdr_name
; case mName of
(Just _) -> termNameInType looking_for rdr_name demoted_rdr_name []
Nothing -> unboundTermNameInTypes looking_for rdr_name demoted_rdr_name }
@@ -1131,7 +1145,7 @@ report_qualified_term_in_types rdr_name demoted_rdr_name =
-- lookup_promoted returns the corresponding type-level Name.
-- Otherwise, the function returns Nothing.
-- See Note [Promotion] below.
-lookup_promoted :: RdrName -> RnM (Maybe Name)
+lookup_promoted :: RdrName -> RnM (Maybe GlobalRdrElt)
lookup_promoted rdr_name
| Just promoted_rdr <- promoteRdrName rdr_name
= lookupOccRn_maybe promoted_rdr
@@ -1216,16 +1230,26 @@ when the user writes the following declaration
x = id Int
-}
-lookupOccRnX_maybe :: (RdrName -> RnM (Maybe r)) -> (Name -> r) -> RdrName
+lookupOccRnX_maybe :: (RdrName -> RnM (Maybe r)) -> (GlobalRdrElt -> RnM r) -> RdrName
-> RnM (Maybe r)
lookupOccRnX_maybe globalLookup wrapper rdr_name
= runMaybeT . msum . map MaybeT $
- [ fmap wrapper <$> lookupLocalOccRn_maybe rdr_name
+ [ do { res <- lookupLocalOccRn_maybe rdr_name
+ ; case res of
+ { Nothing -> return Nothing
+ ; Just nm ->
+ do { let gre = localVanillaGRE NoParent nm
+ ; Just <$> wrapper gre } } }
, globalLookup rdr_name ]
+lookupOccRn_maybe :: RdrName -> RnM (Maybe GlobalRdrElt)
+lookupOccRn_maybe =
+ lookupOccRnX_maybe (lookupGlobalOccRn_maybe $ IncludeFields WantNormal) return
+
-- Used outside this module only by TH name reification (lookupName, lookupThName_maybe)
-lookupOccRn_maybe :: RdrName -> RnM (Maybe Name)
-lookupOccRn_maybe = lookupOccRnX_maybe lookupGlobalOccRn_maybe id
+lookupSameOccRn_maybe :: RdrName -> RnM (Maybe GlobalRdrElt)
+lookupSameOccRn_maybe =
+ lookupOccRnX_maybe (lookupGlobalOccRn_maybe SameOccName) return
-- | Look up a 'RdrName' used as a variable in an expression.
--
@@ -1237,28 +1261,21 @@ lookupOccRn_maybe = lookupOccRnX_maybe lookupGlobalOccRn_maybe id
-- in scope at the type level, the lookup will succeed (so that the type-checker
-- can report a more informative error later). See Note [Promotion].
--
-lookupExprOccRn :: RdrName -> RnM (Maybe GreName)
+lookupExprOccRn :: RdrName -> RnM (Maybe GlobalRdrElt)
lookupExprOccRn rdr_name
- = do { mb_name <- lookupOccRnX_maybe global_lookup NormalGreName rdr_name
+ = do { mb_name <- lookupOccRnX_maybe
+ lookupGlobalOccRn_overloaded
+ return
+ rdr_name
; case mb_name of
- Nothing -> fmap @Maybe NormalGreName <$> lookup_promoted rdr_name
+ Nothing -> lookup_promoted rdr_name
-- See Note [Promotion].
-- We try looking up the name as a
-- type constructor or type variable, if
-- we failed to look up the name at the term level.
p -> return p }
- where
- global_lookup :: RdrName -> RnM (Maybe GreName)
- global_lookup rdr_name =
- do { mb_name <- lookupGlobalOccRn_overloaded NoDuplicateRecordFields WantNormal rdr_name
- ; case mb_name of
- Just (UnambiguousGre name) -> return (Just name)
- Just _ -> panic "GHC.Rename.Env.global_lookup: The impossible happened!"
- Nothing -> return Nothing
- }
-
-lookupGlobalOccRn_maybe :: RdrName -> RnM (Maybe Name)
+lookupGlobalOccRn_maybe :: WhichGREs GREInfo -> RdrName -> RnM (Maybe GlobalRdrElt)
-- Looks up a RdrName occurrence in the top-level
-- environment, including using lookupQualifiedNameGHCi
-- for the GHCi case, but first tries to find an Exact or Orig name.
@@ -1267,42 +1284,61 @@ lookupGlobalOccRn_maybe :: RdrName -> RnM (Maybe Name)
-- Uses addUsedRdrName to record use and deprecations
--
-- Used directly only by getLocalNonValBinders (new_assoc).
-lookupGlobalOccRn_maybe rdr_name =
- lookupExactOrOrig_maybe rdr_name id (lookupGlobalOccRn_base WantNormal rdr_name)
+lookupGlobalOccRn_maybe which_gres rdr_name =
+ lookupExactOrOrig_maybe rdr_name id $
+ lookupGlobalOccRn_base which_gres rdr_name
-lookupGlobalOccRn :: RdrName -> RnM Name
+lookupGlobalOccRn :: RdrName -> RnM GlobalRdrElt
-- lookupGlobalOccRn is like lookupOccRn, except that it looks in the global
-- environment. Adds an error message if the RdrName is not in scope.
-- You usually want to use "lookupOccRn" which also looks in the local
-- environment.
--
-- Used by exports_from_avail
-lookupGlobalOccRn = lookupGlobalOccRn' WantNormal
+lookupGlobalOccRn = lookupGlobalOccRn' (IncludeFields WantNormal)
-lookupGlobalOccRn' :: FieldsOrSelectors -> RdrName -> RnM Name
-lookupGlobalOccRn' fos rdr_name =
+lookupGlobalOccRn' :: WhichGREs GREInfo -> RdrName -> RnM GlobalRdrElt
+lookupGlobalOccRn' which_gres rdr_name =
lookupExactOrOrig rdr_name id $ do
- mn <- lookupGlobalOccRn_base fos rdr_name
+ mn <- lookupGlobalOccRn_base which_gres rdr_name
case mn of
Just n -> return n
Nothing -> do { traceRn "lookupGlobalOccRn" (ppr rdr_name)
- ; unboundName (LF which_suggest WL_Global) rdr_name }
- where which_suggest = case fos of
- WantNormal -> WL_Anything
- WantBoth -> WL_RecField
- WantField -> WL_RecField
+ ; nm <- unboundName (LF which_suggest WL_Global) rdr_name
+ ; return $ localVanillaGRE NoParent nm }
+ where which_suggest = case which_gres of
+ IncludeFields WantBoth -> WL_RecField
+ IncludeFields WantField -> WL_RecField
+ _ -> WL_Anything
-- Looks up a RdrName occurrence in the GlobalRdrEnv and with
-- lookupQualifiedNameGHCi. Does not try to find an Exact or Orig name first.
-- lookupQualifiedNameGHCi here is used when we're in GHCi and a name like
-- 'Data.Map.elems' is typed, even if you didn't import Data.Map
-lookupGlobalOccRn_base :: FieldsOrSelectors -> RdrName -> RnM (Maybe Name)
-lookupGlobalOccRn_base fos rdr_name =
- runMaybeT . msum . map MaybeT $
- [ fmap greMangledName <$> lookupGreRn_maybe fos rdr_name
- , fmap greNameMangledName <$> lookupOneQualifiedNameGHCi fos rdr_name ]
+lookupGlobalOccRn_base :: WhichGREs GREInfo -> RdrName -> RnM (Maybe GlobalRdrElt)
+lookupGlobalOccRn_base which_gres rdr_name =
+ runMaybeT . msum . map MaybeT $
+ [ lookupGreRn_maybe which_gres rdr_name
+ , lookupOneQualifiedNameGHCi fos rdr_name ]
-- This test is not expensive,
-- and only happens for failed lookups
+ where
+ fos = case which_gres of
+ IncludeFields f_or_s -> f_or_s
+ _ -> WantNormal
+
+-- | Lookup a 'Name' in the 'GlobalRdrEnv', falling back to looking up
+-- in the type environment it if fails.
+lookupGREInfo_GRE :: Name -> RnM GREInfo
+lookupGREInfo_GRE name
+ = do { rdr_env <- getGlobalRdrEnv
+ ; case lookupGRE_Name rdr_env name of
+ Just ( GRE { gre_info = info } )
+ -> return info
+ _ -> do { hsc_env <- getTopEnv
+ ; return $ lookupGREInfo hsc_env name } }
+ -- Just looking in the GlobalRdrEnv is insufficient, as we also
+ -- need to handle qualified imports in GHCi; see e.g. T9815ghci.
lookupInfoOccRn :: RdrName -> RnM [Name]
-- lookupInfoOccRn is intended for use in GHCi's ":info" command
@@ -1313,142 +1349,265 @@ lookupInfoOccRn :: RdrName -> RnM [Name]
-- at least one definition of the RdrName, not complaining about
-- multiple definitions. (See #17832)
lookupInfoOccRn rdr_name =
- lookupExactOrOrig rdr_name (:[]) $
+ lookupExactOrOrig rdr_name (\ gre -> [greName gre]) $
do { rdr_env <- getGlobalRdrEnv
- ; let ns = map greMangledName (lookupGRE_RdrName' rdr_name rdr_env)
- ; qual_ns <- map greNameMangledName <$> lookupQualifiedNameGHCi WantBoth rdr_name
- ; return (ns ++ (qual_ns `minusList` ns)) }
+ ; let ns = map greName $ lookupGRE_RdrName (IncludeFields WantBoth) rdr_env rdr_name
+ ; qual_ns <- map greName <$> lookupQualifiedNameGHCi WantBoth rdr_name
+ ; return $ ns ++ (qual_ns `minusList` ns) }
--- | Like 'lookupOccRn_maybe', but with a more informative result if
--- the 'RdrName' happens to be a record selector:
+-- | Look up all record field names, available in the 'GlobalRdrEnv',
+-- that a given 'RdrName' might refer to.
+-- (Also includes implicit qualified imports in GHCi).
--
--- * Nothing -> name not in scope (no error reported)
--- * Just (UnambiguousGre x) -> name uniquely refers to x,
--- or there is a name clash (reported)
--- * Just AmbiguousFields -> name refers to two or more record fields
--- (no error reported)
+-- Throws an error if no fields are found.
--
--- See Note [ Unbound vs Ambiguous Names ].
-lookupGlobalOccRn_overloaded :: DuplicateRecordFields -> FieldsOrSelectors -> RdrName
- -> RnM (Maybe AmbiguousResult)
-lookupGlobalOccRn_overloaded dup_fields_ok fos rdr_name =
- lookupExactOrOrig_maybe rdr_name (fmap (UnambiguousGre . NormalGreName)) $
- do { res <- lookupGreRn_helper fos rdr_name
+-- See Note [DisambiguateRecordFields for updates].
+lookupFieldGREs :: GlobalRdrEnv -> LocatedN RdrName -> RnM (NE.NonEmpty FieldGlobalRdrElt)
+lookupFieldGREs env (L loc rdr)
+ = setSrcSpanA loc
+ $ do { res <- lookupExactOrOrig rdr (\ gre -> maybeToList $ fieldGRE_maybe gre) $
+ do { let (env_fld_gres, env_var_gres) =
+ partition isRecFldGRE $
+ lookupGRE_RdrName (IncludeFields WantBoth) env rdr
+
+ -- Handle implicit qualified imports in GHCi. See T10439.
+ ; ghci_gres <- lookupQualifiedNameGHCi WantBoth rdr
+ ; let (ghci_fld_gres, ghci_var_gres) =
+ partition isRecFldGRE $
+ ghci_gres
+
+ ; let fld_gres = ghci_fld_gres ++ env_fld_gres
+ var_gres = ghci_var_gres ++ env_var_gres
+
+ -- Add an error for ambiguity when -XDisambiguateRecordFields is off.
+ --
+ -- See Note [DisambiguateRecordFields for updates].
+ ; disamb_ok <- xoptM LangExt.DisambiguateRecordFields
+ ; if | not disamb_ok
+ , gre1 : gre2 : others <- fld_gres ++ var_gres
+ -> addErrTc $ TcRnAmbiguousFieldInUpdate (gre1, gre2, others)
+ | otherwise
+ -> return ()
+ ; return fld_gres }
+
+ -- Add an error if lookup failed.
; case res of
- GreNotFound -> fmap UnambiguousGre <$> lookupOneQualifiedNameGHCi fos rdr_name
- OneNameMatch gre -> return $ Just (UnambiguousGre (gre_name gre))
- MultipleNames gres
- | all isRecFldGRE gres
- , dup_fields_ok == DuplicateRecordFields -> return $ Just AmbiguousFields
- | otherwise -> do
- addNameClashErrRn rdr_name gres
- return (Just (UnambiguousGre (gre_name (NE.head gres)))) }
-
-
--- | Result of looking up an occurrence that might be an ambiguous field.
-data AmbiguousResult
- = UnambiguousGre GreName
- -- ^ Occurrence picked out a single name, which may or may not belong to a
- -- field (or might be unbound, if an error has been reported already, per
- -- Note [ Unbound vs Ambiguous Names ]).
- | AmbiguousFields
- -- ^ Occurrence picked out two or more fields, and no non-fields. For now
- -- this is allowed by DuplicateRecordFields in certain circumstances, as the
- -- type-checker may be able to disambiguate later.
-
+ gre : gres -> return $ gre NE.:| gres
+ [] -> do { (imp_errs, hints) <-
+ unknownNameSuggestions emptyLocalRdrEnv WL_RecField rdr
+ ; failWithTc $
+ TcRnNotInScope NotARecordField rdr imp_errs hints } }
-{-
-Note [NoFieldSelectors]
-~~~~~~~~~~~~~~~~~~~~~~~
-The NoFieldSelectors extension allows record fields to be defined without
-bringing the corresponding selector functions into scope. However, such fields
-may still be used in contexts such as record construction, pattern matching or
-update. This requires us to distinguish contexts in which selectors are required
-from those in which any field may be used. For example:
-
- {-# LANGUAGE NoFieldSelectors #-}
- module M (T(foo), foo) where -- T(foo) refers to the field,
- -- unadorned foo to the value binding
- data T = MkT { foo :: Int }
- foo = ()
+-- | Look up a 'RdrName', which might refer to an overloaded record field.
+--
+-- Don't allow any ambiguity: emit a name-clash error if there are multiple
+-- matching GREs.
+lookupGlobalOccRn_overloaded :: RdrName -> RnM (Maybe GlobalRdrElt)
+lookupGlobalOccRn_overloaded rdr_name =
+ lookupExactOrOrig_maybe rdr_name id $
+ do { res <- lookupGreRn_helper (IncludeFields WantNormal) rdr_name
+ ; case res of
+ GreNotFound -> lookupOneQualifiedNameGHCi WantNormal rdr_name
+ OneNameMatch gre -> return $ Just gre
+ MultipleNames gres@(gre NE.:| _) -> do
+ addNameClashErrRn rdr_name gres
+ return (Just gre) }
- bar = foo -- refers to the value binding, field ignored
+getFieldUpdLbl :: LHsRecUpdField (GhcPass p) q -> LocatedN RdrName
+getFieldUpdLbl = ambiguousFieldOccLRdrName . unLoc . hfbLHS . unLoc
- module N where
- import M (T(..))
- baz = MkT { foo = 3 } -- refers to the field
- oops = foo -- an error: the field is in scope but the value binding is not
-
-Each 'FieldLabel' indicates (in the 'flHasFieldSelector' field) whether the
-FieldSelectors extension was enabled in the defining module. This allows them
-to be filtered out by 'filterFieldGREs'.
-
-Even when NoFieldSelectors is in use, we still generate selector functions
-internally. For example, the expression
- getField @"foo" t
-or (with dot-notation)
- t.foo
-extracts the `foo` field of t::T, and hence needs the selector function
-(see Note [HasField instances] in GHC.Tc.Instance.Class). In order to avoid
-name clashes with normal bindings reusing the names, selector names for such
-fields are mangled just as for DuplicateRecordFields (see Note [FieldLabel] in
-GHC.Types.FieldLabel).
-
-
-In many of the name lookup functions in this module we pass a FieldsOrSelectors
-value, indicating what we are looking for:
-
- * WantNormal: fields are in scope only if they have an accompanying selector
- function, e.g. we are looking up a variable in an expression
- (lookupExprOccRn).
-
- * WantBoth: any name or field will do, regardless of whether the selector
- function is available, e.g. record updates (lookupRecFieldOcc_update) with
- NoDisambiguateRecordFields.
-
- * WantField: any field will do, regardless of whether the selector function is
- available, but ignoring any non-field names, e.g. record updates
- (lookupRecFieldOcc_update) with DisambiguateRecordFields.
-
------------------------------------------------------------------------------------
- Context FieldsOrSelectors
------------------------------------------------------------------------------------
- Record construction/pattern match WantBoth if NoDisambiguateRecordFields
- e.g. MkT { foo = 3 } (DisambiguateRecordFields is separate)
-
- Record update WantBoth if NoDisambiguateRecordFields
- e.g. e { foo = 3 } WantField if DisambiguateRecordFields
-
- :info in GHCi WantBoth
-
- Variable occurrence in expression WantNormal
- Type variable, data constructor
- Pretty much everything else
------------------------------------------------------------------------------------
--}
+-- | Returns all possible collections of field labels for the given
+-- record update.
+--
+-- Example:
+--
+-- data D = MkD { fld1 :: Int, fld2 :: Bool }
+-- data E = MkE1 { fld1 :: Int, fld2 :: Bool, fld3 :: Char }
+-- | MkE2 { fld1 :: Int, fld2 :: Bool }
+-- data F = MkF1 { fld1 :: Int } | MkF2 { fld2 :: Bool }
+--
+-- f r = r { fld1 = a, fld2 = b }
+--
+-- This function will return:
+--
+-- [ [ D.fld1, D.fld2 ] -- could be a record update at type D
+-- , [ E.fld1, E.fld2 ] -- could be a record update at type E
+-- ] -- cannot be a record update at type F: no constructor has both
+-- -- of the fields fld1 and fld2
+--
+-- If there are no valid parents for the record update,
+-- throws a 'TcRnBadRecordUpdate' error.
+lookupRecUpdFields :: NE.NonEmpty (LHsRecUpdField GhcPs GhcPs)
+ -> RnM (NE.NonEmpty (HsRecUpdParent GhcRn))
+lookupRecUpdFields flds
+-- See Note [Disambiguating record updates] in GHC.Rename.Pat.
+ = do { -- Retrieve the possible GlobalRdrElts that each field could refer to.
+ ; gre_env <- getGlobalRdrEnv
+ ; fld1_gres NE.:| other_flds_gres <- mapM (lookupFieldGREs gre_env . getFieldUpdLbl) flds
+ -- Take an intersection: we are only interested in constructors
+ -- which have all of the fields.
+ ; let possible_GREs = intersect_by_cons fld1_gres other_flds_gres
+
+ ; traceRn "lookupRecUpdFields" $
+ vcat [ text "flds:" <+> ppr (fmap getFieldUpdLbl flds)
+ , text "possible_GREs:" <+>
+ ppr (map (fmap greName . rnRecUpdLabels) possible_GREs) ]
+
+ ; case possible_GREs of
+
+ -- There is at least one parent: we can proceed.
+ -- The typechecker might be able to finish disambiguating.
+ -- See Note [Type-directed record disambiguation] in GHC.Rename.Pat.
+ { p1:ps -> return (p1 NE.:| ps)
+
+ -- There are no possible parents for the record update: compute
+ -- a minimum set of fields which does not belong to any data constructor,
+ -- to report an informative error to the user.
+ ; _ ->
+ let
+ -- The constructors which have the first field.
+ fld1_cons :: UniqSet ConLikeName
+ fld1_cons = unionManyUniqSets
+ $ NE.toList
+ $ NE.map (recFieldCons . fieldGREInfo) fld1_gres
+ -- The field labels of the constructors which have the first field.
+ fld1_cons_fields :: UniqFM ConLikeName [FieldLabel]
+ fld1_cons_fields
+ = fmap (lkp_con_fields gre_env)
+ $ getUniqSet fld1_cons
+ in failWithTc $ badFieldsUpd (NE.toList flds) fld1_cons_fields } }
--- | When looking up GREs, we may or may not want to include fields that were
--- defined in modules with @NoFieldSelectors@ enabled. See Note
--- [NoFieldSelectors].
-data FieldsOrSelectors
- = WantNormal -- ^ Include normal names, and fields with selectors, but
- -- ignore fields without selectors.
- | WantBoth -- ^ Include normal names and all fields (regardless of whether
- -- they have selectors).
- | WantField -- ^ Include only fields, with or without selectors, ignoring
- -- any non-fields in scope.
- deriving Eq
-
-filterFieldGREs :: FieldsOrSelectors -> [GlobalRdrElt] -> [GlobalRdrElt]
-filterFieldGREs fos = filter (allowGreName fos . gre_name)
-
-allowGreName :: FieldsOrSelectors -> GreName -> Bool
-allowGreName WantBoth _ = True
-allowGreName WantNormal (FieldGreName fl) = flHasFieldSelector fl == FieldSelectors
-allowGreName WantNormal (NormalGreName _) = True
-allowGreName WantField (FieldGreName _) = True
-allowGreName WantField (NormalGreName _) = False
+ where
+ intersect_by_cons :: NE.NonEmpty FieldGlobalRdrElt
+ -> [NE.NonEmpty FieldGlobalRdrElt]
+ -> [HsRecUpdParent GhcRn]
+ intersect_by_cons this [] =
+ map
+ (\ fld -> RnRecUpdParent (fld NE.:| []) (recFieldCons (fieldGREInfo fld)))
+ (NE.toList this)
+ intersect_by_cons this (new : rest) =
+ [ RnRecUpdParent (this_fld NE.<| next_flds) both_cons
+ | this_fld <- NE.toList this
+ , let this_cons = recFieldCons $ fieldGREInfo this_fld
+ , RnRecUpdParent next_flds next_cons <- intersect_by_cons new rest
+ , let both_cons = next_cons `intersectUniqSets` this_cons
+ , not $ isEmptyUniqSet both_cons
+ ]
+
+ lkp_con_fields :: GlobalRdrEnv -> ConLikeName -> [FieldLabel]
+ lkp_con_fields gre_env con =
+ [ fl
+ | let nm = conLikeName_Name con
+ , gre <- maybeToList $ lookupGRE_Name gre_env nm
+ , con_info <- maybeToList $ recFieldConLike_maybe gre
+ , fl <- conInfoFields con_info ]
+
+{-**********************************************************************
+* *
+ Record field errors
+* *
+**********************************************************************-}
+
+getUpdFieldLbls :: forall p q. UnXRec (GhcPass p)
+ => [LHsRecUpdField (GhcPass p) q] -> [RdrName]
+getUpdFieldLbls
+ = map $ ambiguousFieldOccRdrName
+ . unXRec @(GhcPass p)
+ . hfbLHS
+ . unXRec @(GhcPass p)
+
+-- | Create an error message when there is no single 'ConLike' which
+-- has all of the required fields for a record update.
+--
+-- This boils down the problem to a smaller set of fields, to avoid
+-- the error message containing a lot of uninformative field names that
+-- aren't really relevant to the problem.
+--
+-- NB: this error message should only be triggered when all the field names
+-- are in scope (i.e. each individual field name does belong to some
+-- constructor in scope).
+badFieldsUpd
+ :: (OutputableBndrId p)
+ => [LHsRecUpdField (GhcPass p) q]
+ -- ^ Field names that don't belong to a single datacon
+ -> UniqFM ConLikeName [FieldLabel]
+ -- ^ The list of field labels for each constructor.
+ -- (These are the constructors in which the first field occurs.)
+ -> TcRnMessage
+badFieldsUpd rbinds fld1_cons_fields
+ = TcRnBadRecordUpdate
+ (getUpdFieldLbls rbinds)
+ (NoConstructorHasAllFields conflictingFields)
+ -- See Note [Finding the conflicting fields]
+ where
+ -- A (preferably small) set of fields such that no constructor contains
+ -- all of them. See Note [Finding the conflicting fields]
+ conflictingFields = case nonMembers of
+ -- nonMember belongs to a different type.
+ (nonMember, _) : _ -> [aMember, nonMember]
+ [] -> let
+ -- All of rbinds belong to one type. In this case, repeatedly add
+ -- a field to the set until no constructor contains the set.
+
+ -- Each field, together with a list indicating which constructors
+ -- have all the fields so far.
+ growingSets :: [(FieldLabelString, [Bool])]
+ growingSets = scanl1 combine membership
+ combine (_, setMem) (field, fldMem)
+ = (field, zipWith (&&) setMem fldMem)
+ in
+ -- Fields that don't change the membership status of the set
+ -- are redundant and can be dropped.
+ map (fst . head) $ groupBy ((==) `on` snd) growingSets
+
+ aMember = assert (not (null members) ) fst (head members)
+ (members, nonMembers) = partition (or . snd) membership
+
+ -- For each field, which constructors contain the field?
+ membership :: [(FieldLabelString, [Bool])]
+ membership
+ = sortMembership $
+ map
+ ( (\fld -> (fld, map (fld `elementOfUniqSet`) fieldLabelSets))
+ . FieldLabelString . occNameFS . rdrNameOcc . unLoc . getFieldUpdLbl )
+ rbinds
+
+ fieldLabelSets :: [UniqSet FieldLabelString]
+ fieldLabelSets = map (mkUniqSet . map flLabel) $ nonDetEltsUFM fld1_cons_fields
+
+ -- Sort in order of increasing number of True, so that a smaller
+ -- conflicting set can be found.
+ sortMembership =
+ map snd .
+ sortBy (compare `on` fst) .
+ map (\ item@(_, membershipRow) -> (countTrue membershipRow, item))
+
+ countTrue = count id
+{-
+Note [Finding the conflicting fields]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Suppose we have
+ data A = A {a0, a1 :: Int}
+ | B {b0, b1 :: Int}
+and we see a record update
+ x { a0 = 3, a1 = 2, b0 = 4, b1 = 5 }
+Then we'd like to find the smallest subset of fields that no
+constructor has all of. Here, say, {a0,b0}, or {a0,b1}, etc.
+We don't really want to report that no constructor has all of
+{a0,a1,b0,b1}, because when there are hundreds of fields it's
+hard to see what was really wrong.
+
+We may need more than two fields, though; eg
+ data T = A { x,y :: Int, v::Int }
+ | B { y,z :: Int, v::Int }
+ | C { z,x :: Int, v::Int }
+with update
+ r { x=e1, y=e2, z=e3 }, we
+
+Finding the smallest subset is hard, so the code here makes
+a decent stab, no more. See #7989.
+-}
--------------------------------------------------
-- Lookup in the Global RdrEnv of the module
@@ -1458,15 +1617,15 @@ data GreLookupResult = GreNotFound
| OneNameMatch GlobalRdrElt
| MultipleNames (NE.NonEmpty GlobalRdrElt)
-lookupGreRn_maybe :: FieldsOrSelectors -> RdrName -> RnM (Maybe GlobalRdrElt)
+lookupGreRn_maybe :: WhichGREs GREInfo -> RdrName -> RnM (Maybe GlobalRdrElt)
-- Look up the RdrName in the GlobalRdrEnv
-- Exactly one binding: records it as "used", return (Just gre)
-- No bindings: return Nothing
-- Many bindings: report "ambiguous", return an arbitrary (Just gre)
-- Uses addUsedRdrName to record use and deprecations
-lookupGreRn_maybe fos rdr_name
+lookupGreRn_maybe which_gres rdr_name
= do
- res <- lookupGreRn_helper fos rdr_name
+ res <- lookupGreRn_helper which_gres rdr_name
case res of
OneNameMatch gre -> return $ Just gre
MultipleNames gres -> do
@@ -1501,43 +1660,38 @@ is enabled then we defer the selection until the typechecker.
-}
-
-
-- Internal Function
-lookupGreRn_helper :: FieldsOrSelectors -> RdrName -> RnM GreLookupResult
-lookupGreRn_helper fos rdr_name
+lookupGreRn_helper :: WhichGREs GREInfo -> RdrName -> RnM GreLookupResult
+lookupGreRn_helper which_gres rdr_name
= do { env <- getGlobalRdrEnv
- ; case filterFieldGREs fos (lookupGRE_RdrName' rdr_name env) of
+ ; case lookupGRE_RdrName which_gres env rdr_name of
[] -> return GreNotFound
[gre] -> do { addUsedGRE True gre
; return (OneNameMatch gre) }
-- Don't record usage for ambiguous names
-- until we know which is meant
- (gre:gres) -> return (MultipleNames (gre NE.:| gres)) }
+ (gre:others) -> return (MultipleNames (gre NE.:| others)) }
-lookupGreAvailRn :: RdrName -> RnM (Name, AvailInfo)
+lookupGreAvailRn :: RdrName -> RnM (Maybe GlobalRdrElt)
-- Used in export lists
-- If not found or ambiguous, add error message, and fake with UnboundName
-- Uses addUsedRdrName to record use and deprecations
lookupGreAvailRn rdr_name
= do
- mb_gre <- lookupGreRn_helper WantNormal rdr_name
+ mb_gre <- lookupGreRn_helper (IncludeFields WantNormal) rdr_name
case mb_gre of
GreNotFound ->
do
traceRn "lookupGreAvailRn" (ppr rdr_name)
- name <- unboundName (LF WL_Anything WL_Global) rdr_name
- return (name, avail name)
+ _ <- unboundName (LF WL_Anything WL_Global) rdr_name
+ return Nothing
MultipleNames gres ->
do
addNameClashErrRn rdr_name gres
- let unbound_name = mkUnboundNameRdr rdr_name
- return (unbound_name, avail unbound_name)
- -- Returning an unbound name here prevents an error
- -- cascade
+ return Nothing
+ -- Prevent error cascade
OneNameMatch gre ->
- return (greMangledName gre, availFromGRE gre)
-
+ return $ Just gre
{-
*********************************************************
@@ -1570,7 +1724,7 @@ addUsedDataCons rdr_env tycon
| dc <- tyConDataCons tycon
, Just gre <- [lookupGRE_Name rdr_env (dataConName dc)] ]
-addUsedGRE :: Bool -> GlobalRdrElt -> RnM ()
+addUsedGRE :: Bool -> GlobalRdrElt-> RnM ()
-- Called for both local and imported things
-- Add usage *and* warn if deprecated
addUsedGRE warn_if_deprec gre
@@ -1614,7 +1768,7 @@ warnIfDeprecated gre@(GRE { gre_imp = iss })
= return ()
where
occ = greOccName gre
- name = greMangledName gre
+ name = greName gre
definedMod = moduleName $ assertPpr (isExternalName name) (ppr name) (nameModule name)
doc = text "The name" <+> quotes (ppr occ) <+> text "is mentioned explicitly"
@@ -1687,33 +1841,23 @@ ambiguity error.
-}
-
-- | Like 'lookupQualifiedNameGHCi' but returning at most one name, reporting an
-- ambiguity error if there are more than one.
-lookupOneQualifiedNameGHCi :: FieldsOrSelectors -> RdrName -> RnM (Maybe GreName)
+lookupOneQualifiedNameGHCi :: FieldsOrSelectors -> RdrName -> RnM (Maybe GlobalRdrElt)
lookupOneQualifiedNameGHCi fos rdr_name = do
- gnames <- lookupQualifiedNameGHCi fos rdr_name
- case gnames of
- [] -> return Nothing
- [gname] -> return (Just gname)
- (gname:gnames') -> do addNameClashErrRn rdr_name (toGRE gname NE.:| map toGRE gnames')
- return (Just (NormalGreName (mkUnboundNameRdr rdr_name)))
- where
- -- Fake a GRE so we can report a sensible name clash error if
- -- -fimplicit-import-qualified is used with a module that exports the same
- -- field name multiple times (see
- -- Note [DuplicateRecordFields and -fimplicit-import-qualified]).
- toGRE gname = GRE { gre_name = gname, gre_par = NoParent, gre_lcl = False, gre_imp = unitBag is }
- is = ImpSpec { is_decl = ImpDeclSpec { is_mod = mod, is_as = mod, is_qual = True, is_dloc = noSrcSpan }
- , is_item = ImpAll }
- -- If -fimplicit-import-qualified succeeded, the name must be qualified.
- (mod, _) = fromMaybe (pprPanic "lookupOneQualifiedNameGHCi" (ppr rdr_name)) (isQual_maybe rdr_name)
-
+ all_gres <- lookupQualifiedNameGHCi fos rdr_name
+ case all_gres of
+ [] -> return Nothing
+ [gre] -> return $ Just $ gre
+ (gre:gres) ->
+ do addNameClashErrRn rdr_name (gre NE.:| gres)
+ return (Just (mkUnboundGRE $ greOccName gre))
+ -- (Use mkUnboundGRE to get the correct namespace)
-- | Look up *all* the names to which the 'RdrName' may refer in GHCi (using
-- @-fimplicit-import-qualified@). This will normally be zero or one, but may
-- be more in the presence of @DuplicateRecordFields@.
-lookupQualifiedNameGHCi :: FieldsOrSelectors -> RdrName -> RnM [GreName]
+lookupQualifiedNameGHCi :: HasDebugCallStack => FieldsOrSelectors -> RdrName -> RnM [GlobalRdrElt]
lookupQualifiedNameGHCi fos rdr_name
= -- We want to behave as we would for a source file import here,
-- and respect hiddenness of modules/packages, hence loadSrcInterface.
@@ -1724,20 +1868,28 @@ lookupQualifiedNameGHCi fos rdr_name
where
go_for_it dflags is_ghci
| Just (mod,occ) <- isQual_maybe rdr_name
+ , let ns = occNameSpace occ
, is_ghci
, gopt Opt_ImplicitImportQualified dflags -- Enables this GHCi behaviour
, not (safeDirectImpsReq dflags) -- See Note [Safe Haskell and GHCi]
= do { res <- loadSrcInterface_maybe doc mod NotBoot NoPkgQual
; case res of
Succeeded iface
- -> return [ gname
- | avail <- mi_exports iface
- , gname <- availGreNames avail
- , occName gname == occ
- -- Include a field if it has a selector or we are looking for all fields;
- -- see Note [NoFieldSelectors].
- , allowGreName fos gname
- ]
+ -> do { hsc_env <- getTopEnv
+ ; let gres =
+ [ gre
+ | avail <- mi_exports iface
+ , gname <- availNames avail
+ , let lk_occ = occName gname
+ lk_ns = occNameSpace lk_occ
+ , occNameFS occ == occNameFS lk_occ
+ , ns == lk_ns || (ns == varName && isFieldNameSpace lk_ns)
+ , let gre = lookupGRE_PTE mod hsc_env gname
+ , allowGRE fos gre
+ -- Include a field if it has a selector or we are looking for all fields;
+ -- see Note [NoFieldSelectors].
+ ]
+ ; return gres }
_ -> -- Either we couldn't load the interface, or
-- we could but we didn't find the name in it
@@ -1750,6 +1902,47 @@ lookupQualifiedNameGHCi fos rdr_name
doc = text "Need to find" <+> ppr rdr_name
+ -- Lookup a Name for an implicit qualified import in GHCi
+ -- in the given PackageTypeEnv.
+ lookupGRE_PTE :: ModuleName -> HscEnv -> Name -> GlobalRdrElt
+ lookupGRE_PTE mod hsc_env nm =
+ -- Fake a GRE so we can report a sensible name clash error if
+ -- -fimplicit-import-qualified is used with a module that exports the same
+ -- field name multiple times (see
+ -- Note [DuplicateRecordFields and -fimplicit-import-qualified]).
+ GRE { gre_name = nm
+ , gre_par = NoParent
+ , gre_lcl = False
+ , gre_imp = unitBag is
+ , gre_info = info }
+ where
+ info = lookupGREInfo hsc_env nm
+ spec = ImpDeclSpec { is_mod = mod, is_as = mod, is_qual = True, is_dloc = noSrcSpan }
+ is = ImpSpec { is_decl = spec, is_item = ImpAll }
+
+-- | Look up the 'GREInfo' associated with the given 'Name'
+-- by looking up in the type environment.
+lookupGREInfo :: HasDebugCallStack => HscEnv -> Name -> GREInfo
+lookupGREInfo hsc_env nm
+ | Just ty_thing <- wiredInNameTyThing_maybe nm
+ = tyThingGREInfo ty_thing
+ | otherwise
+ -- Create a thunk which, when forced, loads the interface
+ -- and looks up the TyThing in the type environment.
+ --
+ -- See Note [Retrieving the GREInfo from interfaces] in GHC.Types.GREInfo.
+ = let lookup_res = unsafePerformIO $ do
+ let mod = nameModule nm
+ _ <- initIfaceLoad hsc_env $
+ loadInterface (text "lookupGREInfo" <+> parens (ppr nm))
+ mod ImportBySystem
+ lookupType hsc_env nm
+ in
+ case lookup_res of
+ Nothing -> pprPanic "lookupGREInfo" $
+ vcat [ text "lookup failed:" <+> ppr nm ]
+ Just ty_thing -> tyThingGREInfo ty_thing
+
{-
Note [Looking up signature names]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1822,27 +2015,14 @@ lookupSigOccRn ctxt sig = lookupSigCtxtOccRn ctxt (hsSigDoc sig)
lookupSigOccRnN :: HsSigCtxt
-> Sig GhcPs
-> LocatedN RdrName -> RnM (LocatedN Name)
-lookupSigOccRnN ctxt sig = lookupSigCtxtOccRnN ctxt (hsSigDoc sig)
-
-
--- | Lookup a name in relation to the names in a 'HsSigCtxt'
-lookupSigCtxtOccRnN :: HsSigCtxt
- -> SDoc -- ^ description of thing we're looking up,
- -- like "type family"
- -> LocatedN RdrName -> RnM (LocatedN Name)
-lookupSigCtxtOccRnN ctxt what
- = wrapLocMA $ \ rdr_name ->
- do { mb_name <- lookupBindGroupOcc ctxt what rdr_name
- ; case mb_name of
- Left err -> do { addErr (mkTcRnNotInScope rdr_name err)
- ; return (mkUnboundNameRdr rdr_name) }
- Right name -> return name }
+lookupSigOccRnN ctxt sig = lookupSigCtxtOccRn ctxt (hsSigDoc sig)
-- | Lookup a name in relation to the names in a 'HsSigCtxt'
lookupSigCtxtOccRn :: HsSigCtxt
-> SDoc -- ^ description of thing we're looking up,
-- like "type family"
- -> LocatedA RdrName -> RnM (LocatedA Name)
+ -> GenLocated (SrcSpanAnn' ann) RdrName
+ -> RnM (GenLocated (SrcSpanAnn' ann) Name)
lookupSigCtxtOccRn ctxt what
= wrapLocMA $ \ rdr_name ->
do { mb_name <- lookupBindGroupOcc ctxt what rdr_name
@@ -1860,8 +2040,9 @@ lookupBindGroupOcc :: HsSigCtxt
-- See Note [Looking up signature names]
lookupBindGroupOcc ctxt what rdr_name
| Just n <- isExact_maybe rdr_name
- = lookupExactOcc_either n -- allow for the possibility of missing Exacts;
- -- see Note [dataTcOccs and Exact Names]
+ = fmap greName <$> lookupExactOcc_either n
+ -- allow for the possibility of missing Exacts;
+ -- see Note [dataTcOccs and Exact Names]
-- Maybe we should check the side conditions
-- but it's a pain, and Exact things only show
-- up when you know what you are doing
@@ -1889,21 +2070,21 @@ lookupBindGroupOcc ctxt what rdr_name
lookup_top keep_me
= do { env <- getGlobalRdrEnv
; dflags <- getDynFlags
- ; let all_gres = lookupGlobalRdrEnv env (rdrNameOcc rdr_name)
+ ; let all_gres = lookupGRE_OccName (IncludeFields WantNormal) env (rdrNameOcc rdr_name)
names_in_scope = -- If rdr_name lacks a binding, only
-- recommend alternatives from related
-- namespaces. See #17593.
filter (\n -> nameSpacesRelated dflags WL_Anything
(rdrNameSpace rdr_name)
(nameNameSpace n))
- $ map greMangledName
+ $ map greName
$ filter isLocalGRE
$ globalRdrEnvElts env
candidates_msg = candidates names_in_scope
- ; case filter (keep_me . greMangledName) all_gres of
+ ; case filter (keep_me . greName) all_gres of
[] | null all_gres -> bale_out_with candidates_msg
| otherwise -> bale_out_with local_msg
- (gre:_) -> return (Right (greMangledName gre)) }
+ (gre:_) -> return (Right (greName gre)) }
lookup_group bound_names -- Look in the local envt (not top level)
= do { mname <- lookupLocalOccRn_maybe rdr_name
diff --git a/compiler/GHC/Rename/Expr.hs b/compiler/GHC/Rename/Expr.hs
index 47e6217f56..b68ff6a492 100644
--- a/compiler/GHC/Rename/Expr.hs
+++ b/compiler/GHC/Rename/Expr.hs
@@ -54,6 +54,7 @@ import GHC.Rename.HsType
import GHC.Rename.Pat
import GHC.Driver.Session
import GHC.Builtin.Names
+import GHC.Builtin.Types ( nilDataConName )
import GHC.Types.FieldLabel
import GHC.Types.Fixity
@@ -63,22 +64,22 @@ import GHC.Types.Name.Set
import GHC.Types.Name.Reader
import GHC.Types.Unique.Set
import GHC.Types.SourceText
+import GHC.Types.SrcLoc
import GHC.Utils.Misc
import GHC.Data.List.SetOps ( removeDupsOn )
+import GHC.Data.Maybe
import GHC.Utils.Error
import GHC.Utils.Panic
import GHC.Utils.Panic.Plain
import GHC.Utils.Outputable as Outputable
-import GHC.Types.SrcLoc
-import Control.Monad
-import GHC.Builtin.Types ( nilDataConName )
+
import qualified GHC.LanguageExtensions as LangExt
import Language.Haskell.Syntax.Basic (FieldLabelString(..))
+import Control.Monad
import Data.List (unzip4, minimumBy)
import Data.List.NonEmpty ( NonEmpty(..), nonEmpty )
-import Data.Maybe (isJust, isNothing)
import Control.Arrow (first)
import Data.Ord
import Data.Array
@@ -254,28 +255,31 @@ rnUnboundVar v = do
rnExpr (HsVar _ (L l v))
= do { dflags <- getDynFlags
- ; mb_name <- lookupExprOccRn v
-
- ; case mb_name of {
+ ; mb_gre <- lookupExprOccRn v
+ ; case mb_gre of {
Nothing -> rnUnboundVar v ;
- Just (NormalGreName name)
- | name == nilDataConName -- Treat [] as an ExplicitList, so that
- -- OverloadedLists works correctly
- -- Note [Empty lists] in GHC.Hs.Expr
- , xopt LangExt.OverloadedLists dflags
- -> rnExpr (ExplicitList noAnn [])
-
- | otherwise
- -> finishHsVar (L (na2la l) name) ;
- Just (FieldGreName fl)
- -> do { let sel_name = flSelector fl
- ; this_mod <- getModule
- ; when (nameIsLocalOrFrom this_mod sel_name) $
- checkThLocalName sel_name
- ; return ( HsRecSel noExtField (FieldOcc sel_name (L l v) ), unitFV sel_name)
- }
- }
- }
+ Just gre ->
+ do { if | Just fl <- recFieldLabel <$> recFieldInfo_maybe gre
+ -- Since GHC 9.4, such occurrences of record fields must be
+ -- unambiguous. For ambiguous occurrences, we arbitrarily pick one
+ -- matching GRE and add a name clash error
+ -- (see lookupGlobalOccRn_overloaded, called by lookupExprOccRn).
+ -> do { let sel_name = flSelector fl
+ ; this_mod <- getModule
+ ; when (nameIsLocalOrFrom this_mod sel_name) $
+ checkThLocalName sel_name
+ ; return (HsRecSel noExtField (FieldOcc sel_name (L l v) ), unitFV sel_name)
+ }
+ | greName gre == nilDataConName
+ -- Treat [] as an ExplicitList, so that
+ -- OverloadedLists works correctly
+ -- Note [Empty lists] in GHC.Hs.Expr
+ , xopt LangExt.OverloadedLists dflags
+ -> rnExpr (ExplicitList noAnn [])
+
+ | otherwise
+ -> finishHsVar (L (na2la l) $ greName gre)
+ }}}
rnExpr (HsIPVar x v)
= return (HsIPVar x v, emptyFVs)
@@ -477,29 +481,40 @@ rnExpr (RecordCon { rcon_con = con_id
rn_field (L l fld) = do { (arg', fvs) <- rnLExpr (hfbRHS fld)
; return (L l (fld { hfbRHS = arg' }), fvs) }
-rnExpr (RecordUpd { rupd_expr = expr, rupd_flds = rbinds })
- = case rbinds of
- Left flds -> -- 'OverloadedRecordUpdate' is not in effect. Regular record update.
- do { ; (e, fv_e) <- rnLExpr expr
- ; (rs, fv_rs) <- rnHsRecUpdFields flds
- ; return ( RecordUpd noExtField e (Left rs), fv_e `plusFV` fv_rs )
- }
- Right flds -> -- 'OverloadedRecordUpdate' is in effect. Record dot update desugaring.
- do { ; unlessXOptM LangExt.RebindableSyntax $
- addErr TcRnNoRebindableSyntaxRecordDot
- ; let punnedFields = [fld | (L _ fld) <- flds, hfbPun fld]
- ; punsEnabled <-xoptM LangExt.NamedFieldPuns
- ; unless (null punnedFields || punsEnabled) $
- addErr TcRnNoFieldPunsRecordDot
- ; (getField, fv_getField) <- lookupSyntaxName getFieldName
- ; (setField, fv_setField) <- lookupSyntaxName setFieldName
- ; (e, fv_e) <- rnLExpr expr
- ; (us, fv_us) <- rnHsUpdProjs flds
- ; return ( mkExpandedExpr
- (RecordUpd noExtField e (Right us))
- (mkRecordDotUpd getField setField e us)
- , plusFVs [fv_getField, fv_setField, fv_e, fv_us] )
- }
+rnExpr (RecordUpd { rupd_expr = L l expr, rupd_flds = rbinds })
+ = setSrcSpanA l $
+ case rbinds of
+
+ -- 'OverloadedRecordUpdate' is not in effect. Regular record update.
+ RegularRecUpdFields { recUpdFields = flds } ->
+ do { (e, fv_e) <- rnExpr expr
+ ; (parents, flds, fv_flds) <- rnHsRecUpdFields flds
+ ; let upd_flds =
+ RegularRecUpdFields
+ { xRecUpdFields = parents
+ , recUpdFields = flds }
+ ; return ( RecordUpd noExtField (L l e) upd_flds
+ , fv_e `plusFV` fv_flds ) }
+
+ -- 'OverloadedRecordUpdate' is in effect. Record dot update desugaring.
+ OverloadedRecUpdFields { olRecUpdFields = flds } ->
+ do { unlessXOptM LangExt.RebindableSyntax $
+ addErr TcRnNoRebindableSyntaxRecordDot
+ ; let punnedFields = [fld | (L _ fld) <- flds, hfbPun fld]
+ ; punsEnabled <- xoptM LangExt.NamedFieldPuns
+ ; unless (null punnedFields || punsEnabled) $
+ addErr TcRnNoFieldPunsRecordDot
+ ; (getField, fv_getField) <- lookupSyntaxName getFieldName
+ ; (setField, fv_setField) <- lookupSyntaxName setFieldName
+ ; (e, fv_e) <- rnExpr expr
+ ; (us, fv_us) <- rnHsUpdProjs flds
+ ; let upd_flds = OverloadedRecUpdFields
+ { xOLRecUpdFields = noExtField
+ , olRecUpdFields = us }
+ ; return ( mkExpandedExpr
+ (RecordUpd noExtField (L l e) upd_flds)
+ (mkRecordDotUpd getField setField (L l e) us)
+ , plusFVs [fv_getField, fv_setField, fv_e, fv_us] ) }
rnExpr (HsRecSel x _) = dataConCantHappen x
@@ -2775,4 +2790,4 @@ rnHsUpdProjs us = do
hfbAnn = noAnn
, hfbLHS = fmap rnFieldLabelStrings fs
, hfbRHS = arg
- , hfbPun = pun}), fv ) }
+ , hfbPun = pun }), fv ) }
diff --git a/compiler/GHC/Rename/Fixity.hs b/compiler/GHC/Rename/Fixity.hs
index 5c8fe36fcb..a4da8672af 100644
--- a/compiler/GHC/Rename/Fixity.hs
+++ b/compiler/GHC/Rename/Fixity.hs
@@ -24,7 +24,6 @@ import GHC.Unit.Module.ModIface
import GHC.Types.Fixity.Env
import GHC.Types.Name
import GHC.Types.Name.Env
-import GHC.Types.Name.Reader
import GHC.Types.Fixity
import GHC.Types.SourceText
import GHC.Types.SrcLoc
@@ -107,10 +106,7 @@ lookupFixity is a bit strange.
-}
lookupFixityRn :: Name -> RnM Fixity
-lookupFixityRn name = lookupFixityRn' name (nameOccName name)
-
-lookupFixityRn' :: Name -> OccName -> RnM Fixity
-lookupFixityRn' name = fmap snd . lookupFixityRn_help' name
+lookupFixityRn = fmap snd . lookupFixityRn_help
-- | 'lookupFixityRn_help' returns @(True, fixity)@ if it finds a 'Fixity'
-- in a local environment or from an interface file. Otherwise, it returns
@@ -118,13 +114,7 @@ lookupFixityRn' name = fmap snd . lookupFixityRn_help' name
-- user-supplied fixity declarations).
lookupFixityRn_help :: Name
-> RnM (Bool, Fixity)
-lookupFixityRn_help name =
- lookupFixityRn_help' name (nameOccName name)
-
-lookupFixityRn_help' :: Name
- -> OccName
- -> RnM (Bool, Fixity)
-lookupFixityRn_help' name occ
+lookupFixityRn_help name
| isUnboundName name
= return (False, Fixity NoSourceText minPrecedence InfixL)
-- Minimise errors from unbound names; eg
@@ -144,6 +134,7 @@ lookupFixityRn_help' name occ
then return (False, defaultFixity)
else lookup_imported } } }
where
+ occ = nameOccName name
lookup_imported
-- For imported names, we have to get their fixities by doing a
-- loadInterfaceForName, and consulting the Ifaces that comes back
@@ -180,10 +171,5 @@ lookupFixityRn_help' name occ
lookupTyFixityRn :: LocatedN Name -> RnM Fixity
lookupTyFixityRn = lookupFixityRn . unLoc
--- | Look up the fixity of an occurrence of a record field selector.
--- We use 'lookupFixityRn'' so that we can specify the 'OccName' as
--- the field label, which might be different to the 'OccName' of the
--- selector 'Name' if @DuplicateRecordFields@ is in use (#1173).
lookupFieldFixityRn :: FieldOcc GhcRn -> RnM Fixity
-lookupFieldFixityRn (FieldOcc n lrdr)
- = lookupFixityRn' n (rdrNameOcc (unLoc lrdr))
+lookupFieldFixityRn (FieldOcc n _) = lookupFixityRn n
diff --git a/compiler/GHC/Rename/HsType.hs b/compiler/GHC/Rename/HsType.hs
index f9720a53e1..d67a60efd0 100644
--- a/compiler/GHC/Rename/HsType.hs
+++ b/compiler/GHC/Rename/HsType.hs
@@ -631,11 +631,17 @@ rnHsTyKi env ty@(HsRecTy _ flds)
; return (HsRecTy noExtField flds', fvs) }
where
get_fields (ConDeclCtx names)
- = concatMapM (lookupConstructorFields . unLoc) names
- get_fields _
- = do { addErr $ mkTcRnUnknownMessage $ mkPlainError noHints $
- (hang (text "Record syntax is illegal here:") 2 (ppr ty))
- ; return [] }
+ = do res <- concatMapM (lookupConstructorFields . unLoc) names
+ if equalLength res names
+ -- Lookup can fail when the record syntax is incorrect, e.g.
+ -- data D = D Int { fld :: Bool }. See T7943.
+ then return res
+ else err
+ get_fields _ = err
+
+ err =
+ do { addErr $ TcRnIllegalRecordSyntax (Left ty)
+ ; return [] }
rnHsTyKi env (HsFunTy u mult ty1 ty2)
= do { (ty1', fvs1) <- rnLHsTyKi env ty1
@@ -1159,7 +1165,7 @@ warn_term_var_capture lVar = do
case demoteRdrNameTv $ unLoc lVar of
Nothing -> return ()
Just demoted_name -> do
- let global_vars = lookupGRE_RdrName demoted_name gbl_env
+ let global_vars = lookupGRE_RdrName SameOccName gbl_env demoted_name
let mlocal_var = lookupLocalRdrEnv local_env demoted_name
case mlocal_var of
Just name -> warnCapturedTerm lVar (Right name)
@@ -1284,10 +1290,12 @@ rnField fl_env env (L l (ConDeclField _ names ty haddock_doc))
lookupField :: FastStringEnv FieldLabel -> FieldOcc GhcPs -> FieldOcc GhcRn
lookupField fl_env (FieldOcc _ (L lr rdr)) =
- FieldOcc (flSelector fl) (L lr rdr)
+ FieldOcc sel (L lr $ mkRdrUnqual $ occName sel)
where
lbl = occNameFS $ rdrNameOcc rdr
- fl = expectJust "lookupField" $ lookupFsEnv fl_env lbl
+ sel = flSelector
+ $ expectJust "lookupField"
+ $ lookupFsEnv fl_env lbl
{-
************************************************************************
@@ -1585,8 +1593,7 @@ checkSectionPrec direction section op arg
(sectionPrecErr (get_op op, op_fix)
(arg_op, arg_fix) section)
--- | Look up the fixity for an operator name. Be careful to use
--- 'lookupFieldFixityRn' for record fields (see #13132).
+-- | Look up the fixity for an operator name.
lookupFixityOp :: OpName -> RnM Fixity
lookupFixityOp (NormalOp n) = lookupFixityRn n
lookupFixityOp NegateOp = lookupFixityRn negateName
diff --git a/compiler/GHC/Rename/Module.hs b/compiler/GHC/Rename/Module.hs
index 7b2b418d87..1602b2b92d 100644
--- a/compiler/GHC/Rename/Module.hs
+++ b/compiler/GHC/Rename/Module.hs
@@ -52,7 +52,6 @@ import GHC.Builtin.Names( applicativeClassName, pureAName, thenAName
import GHC.Types.Name
import GHC.Types.Name.Set
import GHC.Types.Name.Env
-import GHC.Types.Avail
import GHC.Utils.Outputable
import GHC.Data.Bag
import GHC.Types.Basic ( TypeOrKind(..) )
@@ -77,7 +76,7 @@ import Data.List ( mapAccumL )
import Data.List.NonEmpty ( NonEmpty(..), head )
import Data.Maybe ( isNothing, fromMaybe, mapMaybe )
import qualified Data.Set as Set ( difference, fromList, toList, null )
-import GHC.Types.ConInfo (ConInfo, mkConInfo, conInfoFields)
+import GHC.Types.GREInfo (ConInfo, mkConInfo, conInfoFields)
{- | @rnSourceDecl@ "renames" declarations.
It simultaneously performs dependency analysis and precedence parsing.
@@ -154,7 +153,7 @@ rnSrcDecls group@(HsGroup { hs_valds = val_decls,
-- Excludes pattern-synonym binders
-- They are already in scope
traceRn "rnSrcDecls" (ppr id_bndrs) ;
- tc_envs <- extendGlobalRdrEnvRn (map avail id_bndrs) local_fix_env ;
+ tc_envs <- extendGlobalRdrEnvRn (map (localVanillaGRE NoParent) id_bndrs) local_fix_env ;
restoreEnvs tc_envs $ do {
-- Now everything is in scope, as the remaining renaming assumes.
@@ -188,6 +187,8 @@ rnSrcDecls group@(HsGroup { hs_valds = val_decls,
-- Rename fixity declarations and error if we try to
-- fix something from another module (duplicates were checked in (A))
let { all_bndrs = tc_bndrs `unionNameSet` val_bndr_set } ;
+ traceRn "rnSrcDecls fixity" $
+ vcat [ text "all_bndrs:" <+> ppr all_bndrs ] ;
rn_fix_decls <- mapM (mapM (rnSrcFixityDecl (TopSigCtxt all_bndrs)))
fix_decls ;
@@ -1489,12 +1490,17 @@ rnTyClDecls tycl_ds
= do { -- Rename the type/class, instance, and role declarations
; tycls_w_fvs <- mapM (wrapLocFstMA rnTyClDecl) (tyClGroupTyClDecls tycl_ds)
; let tc_names = mkNameSet (map (tcdName . unLoc . fst) tycls_w_fvs)
+ ; traceRn "rnTyClDecls" $
+ vcat [ text "tyClGroupTyClDecls:" <+> ppr tycls_w_fvs
+ , text "tc_names:" <+> ppr tc_names ]
; kisigs_w_fvs <- rnStandaloneKindSignatures tc_names (tyClGroupKindSigs tycl_ds)
; instds_w_fvs <- mapM (wrapLocFstMA rnSrcInstDecl) (tyClGroupInstDecls tycl_ds)
; role_annots <- rnRoleAnnots tc_names (tyClGroupRoleDecls tycl_ds)
-- Do SCC analysis on the type/class decls
; rdr_env <- getGlobalRdrEnv
+ ; traceRn "rnTyClDecls SCC analysis" $
+ vcat [ text "rdr_env:" <+> ppr rdr_env ]
; let tycl_sccs = depAnalTyClDecls rdr_env kisig_fv_env tycls_w_fvs
role_annot_env = mkRoleAnnotEnv role_annots
(kisig_env, kisig_fv_env) = mkKindSig_fv_env kisigs_w_fvs
@@ -1586,7 +1592,7 @@ rnStandaloneKindSignature
rnStandaloneKindSignature tc_names (StandaloneKindSig _ v ki)
= do { standalone_ki_sig_ok <- xoptM LangExt.StandaloneKindSignatures
; unless standalone_ki_sig_ok $ addErr TcRnUnexpectedStandaloneKindSig
- ; new_v <- lookupSigCtxtOccRnN (TopSigCtxt tc_names) (text "standalone kind signature") v
+ ; new_v <- lookupSigCtxtOccRn (TopSigCtxt tc_names) (text "standalone kind signature") v
; let doc = StandaloneKindSigCtx (ppr v)
; (new_ki, fvs) <- rnHsSigType doc KindLevel ki
; return (StandaloneKindSig noExtField new_v new_ki, fvs)
@@ -1654,9 +1660,9 @@ rnRoleAnnots tc_names role_annots
rn_role_annot1 (RoleAnnotDecl _ tycon roles)
= do { -- the name is an *occurrence*, but look it up only in the
-- decls defined in this group (see #10263)
- tycon' <- lookupSigCtxtOccRnN (RoleAnnotCtxt tc_names)
- (text "role annotation")
- tycon
+ tycon' <- lookupSigCtxtOccRn (RoleAnnotCtxt tc_names)
+ (text "role annotation")
+ tycon
; return $ RoleAnnotDecl noExtField tycon' roles }
dupRoleAnnotErr :: NonEmpty (LRoleAnnotDecl GhcPs) -> RnM ()
@@ -2563,44 +2569,40 @@ extendPatSynEnv :: DuplicateRecordFields -> FieldSelectors -> HsValBinds GhcPs -
-> ([Name] -> TcRnIf TcGblEnv TcLclEnv a) -> TcM a
extendPatSynEnv dup_fields_ok has_sel val_decls local_fix_env thing = do {
names_with_fls <- new_ps val_decls
- ; let pat_syn_bndrs = concat [ name : map flSelector (conInfoFields fields)
- | (name, fields) <- names_with_fls ]
- ; let avails = map avail (map fst names_with_fls)
- ++ map availField (concatMap (conInfoFields . snd) names_with_fls)
- ; (gbl_env, lcl_env) <- extendGlobalRdrEnvRn avails local_fix_env
-
- ; let field_env' = extendNameEnvList (tcg_con_env gbl_env) names_with_fls
- final_gbl_env = gbl_env { tcg_con_env = field_env' }
- ; restoreEnvs (final_gbl_env, lcl_env) (thing pat_syn_bndrs) }
+ ; let pat_syn_bndrs = concat [ conLikeName_Name name : map flSelector flds
+ | (name, con_info) <- names_with_fls
+ , let flds = conInfoFields con_info ]
+ ; let gres = map (localConLikeGRE NoParent) names_with_fls
+ ++ localFieldGREs NoParent names_with_fls
+ -- Recall Note [Parents] in GHC.Types.Name.Reader:
+ --
+ -- pattern synonym constructors and their record fields have no parent
+ -- in the module in which they are defined.
+ ; (gbl_env, lcl_env) <- extendGlobalRdrEnvRn gres local_fix_env
+ ; restoreEnvs (gbl_env, lcl_env) (thing pat_syn_bndrs) }
where
- new_ps :: HsValBinds GhcPs -> TcM [(Name, ConInfo)]
+
+ new_ps :: HsValBinds GhcPs -> TcM [(ConLikeName, ConInfo)]
new_ps (ValBinds _ binds _) = foldrM new_ps' [] binds
new_ps _ = panic "new_ps"
new_ps' :: LHsBindLR GhcPs GhcPs
- -> [(Name, ConInfo)]
- -> TcM [(Name, ConInfo)]
+ -> [(ConLikeName, ConInfo)]
+ -> TcM [(ConLikeName, ConInfo)]
new_ps' bind names
| (L bind_loc (PatSynBind _ (PSB { psb_id = L _ n
, psb_args = RecCon as }))) <- bind
= do
bnd_name <- newTopSrcBinder (L (l2l bind_loc) n)
let field_occs = map ((\ f -> L (noAnnSrcSpan $ getLocA (foLabel f)) f) . recordPatSynField) as
- flds <- mapM (newRecordSelector dup_fields_ok has_sel [bnd_name]) field_occs
- let conInfo =
- mkConInfo
- (conDetailsArity length (RecCon as))
- flds
- return ((bnd_name, conInfo): names)
- | L bind_loc (PatSynBind _ (PSB { psb_id = L _ n
- , psb_args})) <- bind
+ flds <- mapM (newRecordFieldLabel dup_fields_ok has_sel [bnd_name]) field_occs
+ let con_info = mkConInfo (conDetailsArity length (RecCon as)) flds
+ return ((PatSynName bnd_name, con_info) : names)
+ | L bind_loc (PatSynBind _ (PSB { psb_id = L _ n, psb_args = as })) <- bind
= do
bnd_name <- newTopSrcBinder (L (la2na bind_loc) n)
- let conInfo =
- mkConInfo
- (conDetailsArity length psb_args)
- []
- return ((bnd_name, conInfo): names)
+ let con_info = mkConInfo (conDetailsArity length as) []
+ return ((PatSynName bnd_name, con_info) : names)
| otherwise
= return names
diff --git a/compiler/GHC/Rename/Names.hs b/compiler/GHC/Rename/Names.hs
index 25b1c6e8af..f5309eb174 100644
--- a/compiler/GHC/Rename/Names.hs
+++ b/compiler/GHC/Rename/Names.hs
@@ -8,11 +8,14 @@ Extracting imported and top-level names in scope
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TupleSections #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE LambdaCase #-}
+{-# OPTIONS_GHC -ddump-to-file -ddump-simpl #-}
+
module GHC.Rename.Names (
- rnImports, getLocalNonValBinders, newRecordSelector,
+ rnImports, getLocalNonValBinders, newRecordFieldLabel,
extendGlobalRdrEnvRn,
gresFromAvails,
calculateAvails,
@@ -24,7 +27,8 @@ module GHC.Rename.Names (
getMinimalImports,
printMinimalImports,
renamePkgQual, renameRawPkgQual,
- ImportDeclUsage
+ classifyGREs,
+ ImportDeclUsage,
) where
import GHC.Prelude hiding ( head, init, last, tail )
@@ -35,7 +39,7 @@ import GHC.Driver.Ppr
import GHC.Rename.Env
import GHC.Rename.Fixity
-import GHC.Rename.Utils ( warnUnusedTopBinds, mkFieldEnv )
+import GHC.Rename.Utils ( warnUnusedTopBinds )
import GHC.Tc.Errors.Types
import GHC.Tc.Utils.Env
@@ -64,13 +68,13 @@ import GHC.Types.Avail
import GHC.Types.FieldLabel
import GHC.Types.SourceFile
import GHC.Types.SrcLoc as SrcLoc
-import GHC.Types.Basic ( Arity, TopLevelFlag(..) )
+import GHC.Types.Basic ( TopLevelFlag(..) )
import GHC.Types.SourceText
import GHC.Types.Id
import GHC.Types.HpcInfo
import GHC.Types.Error
import GHC.Types.PkgQual
-import GHC.Types.ConInfo (ConInfo, mkConInfo)
+import GHC.Types.GREInfo (ConInfo(..))
import GHC.Unit
import GHC.Unit.Module.Warnings
@@ -79,28 +83,27 @@ import GHC.Unit.Module.Imported
import GHC.Unit.Module.Deps
import GHC.Unit.Env
-import GHC.Data.Maybe
+import GHC.Data.Bag
import GHC.Data.FastString
import GHC.Data.FastString.Env
-
-import Language.Haskell.Syntax.Basic (FieldLabelString(..))
+import GHC.Data.Maybe
+import GHC.Data.List.SetOps ( removeDups )
import Control.Monad
-import Data.Either ( partitionEithers )
+import Data.Foldable ( for_, toList )
+import Data.IntMap ( IntMap )
+import qualified Data.IntMap as IntMap
import Data.Map ( Map )
import qualified Data.Map as Map
import Data.Ord ( comparing )
-import Data.List ( partition, (\\), find, sortBy )
+import Data.List ( partition, find, sortBy )
import Data.List.NonEmpty (NonEmpty(..))
import qualified Data.List.NonEmpty as NE
import Data.Function ( on )
import qualified Data.Set as S
-import Data.Foldable ( toList )
-import Data.Void ( Void )
import System.FilePath ((</>))
-
import System.IO
-import GHC.Data.Bag
+
{-
************************************************************************
@@ -398,11 +401,11 @@ rnImportDecl this_mod
is_dloc = locA loc, is_as = qual_mod_name }
-- filter the imports according to the import declaration
- (new_imp_details, gres) <- filterImports iface imp_spec imp_details
+ (new_imp_details, gres) <- filterImports hsc_env iface imp_spec imp_details
-- for certain error messages, we’d like to know what could be imported
-- here, if everything were imported
- potential_gres <- mkGlobalRdrEnv . snd <$> filterImports iface imp_spec Nothing
+ potential_gres <- mkGlobalRdrEnv . snd <$> filterImports hsc_env iface imp_spec Nothing
let gbl_env = mkGlobalRdrEnv gres
@@ -682,7 +685,7 @@ top level binders specially in two ways
fields of Brack, hence the error thunks in thRnBrack.
-}
-extendGlobalRdrEnvRn :: [AvailInfo]
+extendGlobalRdrEnvRn :: [GlobalRdrElt]
-> MiniFixityEnv
-> RnM (TcGblEnv, TcLclEnv)
-- Updates both the GlobalRdrEnv and the FixityEnv
@@ -690,7 +693,7 @@ extendGlobalRdrEnvRn :: [AvailInfo]
-- delete some bindings from it;
-- see Note [Top-level Names in Template Haskell decl quotes]
-extendGlobalRdrEnvRn avails new_fixities
+extendGlobalRdrEnvRn new_gres new_fixities
= checkNoErrs $ -- See Note [Fail fast on duplicate definitions]
do { (gbl_env, lcl_env) <- getEnvs
; stage <- getStage
@@ -706,7 +709,7 @@ extendGlobalRdrEnvRn avails new_fixities
-- See Note [GlobalRdrEnv shadowing]
inBracket = isBrackStage stage
- lcl_env_TH = lcl_env { tcl_rdr = minusLocalRdrEnv (tcl_rdr lcl_env) new_occs }
+ lcl_env_TH = lcl_env { tcl_rdr = minusLocalRdrEnv (tcl_rdr lcl_env) new_gres_env }
-- See Note [GlobalRdrEnv shadowing]
lcl_env2 | inBracket = lcl_env_TH
@@ -714,12 +717,11 @@ extendGlobalRdrEnvRn avails new_fixities
-- Deal with shadowing: see Note [GlobalRdrEnv shadowing]
want_shadowing = isGHCi || inBracket
- rdr_env1 | want_shadowing = shadowNames rdr_env new_occs
+ rdr_env1 | want_shadowing = shadowNames rdr_env new_gres_env
| otherwise = rdr_env
lcl_env3 = lcl_env2 { tcl_th_bndrs = extendNameEnvList th_bndrs
- [ ( greNameMangledName n
- , (TopLevel, th_lvl) )
+ [ ( n, (TopLevel, th_lvl) )
| n <- new_names ] }
; rdr_env2 <- foldlM add_gre rdr_env1 new_gres
@@ -730,8 +732,8 @@ extendGlobalRdrEnvRn avails new_fixities
; traceRn "extendGlobalRdrEnvRn 2" (pprGlobalRdrEnv True rdr_env2)
; return (gbl_env', lcl_env3) }
where
- new_names = concatMap availGreNames avails
- new_occs = occSetToEnv (mkOccSet (map occName new_names))
+ new_names = map greName new_gres
+ new_gres_env = mkGlobalRdrEnv new_gres
-- If there is a fixity decl for the gre, add it to the fixity env
extend_fix_env fix_env gre
@@ -740,12 +742,9 @@ extendGlobalRdrEnvRn avails new_fixities
| otherwise
= fix_env
where
- name = greMangledName gre
+ name = greName gre
occ = greOccName gre
- new_gres :: [GlobalRdrElt] -- New LocalDef GREs, derived from avails
- new_gres = concatMap localGREsFromAvail avails
-
add_gre :: GlobalRdrEnv -> GlobalRdrElt -> RnM GlobalRdrEnv
-- Extend the GlobalRdrEnv with a LocalDef GRE
-- If there is already a LocalDef GRE with the same OccName,
@@ -759,15 +758,9 @@ extendGlobalRdrEnvRn avails new_fixities
= return (extendGlobalRdrEnv env gre)
where
-- See Note [Reporting duplicate local declarations]
- dups = filter isDupGRE (lookupGlobalRdrEnv env (greOccName gre))
- isDupGRE gre' = isLocalGRE gre' && not (isAllowedDup gre')
- isAllowedDup gre' =
- case (isRecFldGRE gre, isRecFldGRE gre') of
- (True, True) -> gre_name gre /= gre_name gre'
- && isDuplicateRecFldGRE gre'
- (True, False) -> isNoFieldSelectorGRE gre
- (False, True) -> isNoFieldSelectorGRE gre'
- (False, False) -> False
+ dups = filter isBadDupGRE
+ $ lookupGRE_OccName (AllNameSpaces WantBoth) env (greOccName gre)
+ isBadDupGRE old_gre = isLocalGRE old_gre && greClashesWith gre old_gre
{- Note [Fail fast on duplicate definitions]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -789,7 +782,7 @@ is checked in extendGlobalRdrEnvRn: when adding a new locally-defined GRE to the
GlobalRdrEnv we report an error if there are already duplicates in the
environment. This establishes INVARIANT 1 (see comments on GlobalRdrEnv in
GHC.Types.Name.Reader), which says that for a given OccName, all the
-GlobalRdrElts to which it maps must have distinct 'gre_name's.
+GlobalRdrElts to which it maps must have distinct 'greName's.
For example, the following will be rejected:
@@ -797,75 +790,27 @@ For example, the following will be rejected:
g x = x
f x = x -- Duplicate!
-Two GREs with the same OccName are OK iff:
--------------------------------------------------------------------
- Existing GRE | Newly-defined GRE
- | NormalGre FieldGre
--------------------------------------------------------------------
- Imported | Always Always
- |
- Local NormalGre | Never NoFieldSelectors
- |
- Local FieldGre | NoFieldSelectors DuplicateRecordFields
- | and not in same record
-------------------------------------------------------------------- -
-In this table "NoFieldSelectors" means "NoFieldSelectors was enabled at the
-definition site of the fields; ditto "DuplicateRecordFields". These facts are
-recorded in the 'FieldLabel' (but where both GREs are local, both will
-necessarily have the same extensions enabled).
-
-More precisely:
-
-* The programmer is allowed to make a new local definition that clashes with an
- imported one (although attempting to refer to either may lead to ambiguity
- errors at use sites). For example, the following definition is allowed:
-
- import M (f)
- f x = x
-
- Thus isDupGRE reports errors only if the existing GRE is a LocalDef.
-
-* When DuplicateRecordFields is enabled, the same field label may be defined in
- multiple records. For example, this is allowed:
+Users are allowed to introduce new GREs with the same OccName as an imported GRE,
+as disambiguation is possible through the module system, e.g.:
- {-# LANGUAGE DuplicateRecordFields #-}
- data S1 = MkS1 { f :: Int }
- data S2 = MkS2 { f :: Int }
-
- Even though both fields have the same OccName, this does not violate INVARIANT
- 1 of the GlobalRdrEnv, because the fields have distinct selector names, which
- form part of the gre_name (see Note [GreNames] in GHC.Types.Name.Reader).
-
-* However, we must be careful to reject the following (#9156):
-
- {-# LANGUAGE DuplicateRecordFields #-}
- data T = MkT { f :: Int, f :: Int } -- Duplicate!
-
- In this case, both 'gre_name's are the same (because the fields belong to the
- same type), and adding them both to the environment would be a violation of
- INVARIANT 1. Thus isAllowedDup checks both GREs have distinct 'gre_name's
- if they are both record fields.
-
-* With DuplicateRecordFields, we reject attempts to define a field and a
- non-field with the same OccName (#17965):
-
- {-# LANGUAGE DuplicateRecordFields #-}
+ module M where
+ import N (f)
f x = x
- data T = MkT { f :: Int}
+ g x = M.f x + N.f x
- In principle this could be supported, but the current "specification" of
- DuplicateRecordFields does not allow it. Thus isAllowedDup checks for
- DuplicateRecordFields only if *both* GREs being compared are record fields.
+If both GREs are local, the general rule is that two GREs clash if they have
+the same OccName, i.e. they share a textual name and live in the same namespace.
+However, there are additional clashes due to record fields:
-* However, with NoFieldSelectors, it is possible by design to define a field and
- a non-field with the same OccName:
+ - a new variable clashes with previously defined record fields
+ which define field selectors,
- {-# LANGUAGE NoFieldSelectors #-}
- f x = x
- data T = MkT { f :: Int}
+ - a new record field shadows:
+
+ - previously defined variables, if it defines a field selector,
+ - previously defined record fields, unless it is a duplicate record field.
- Thus isAllowedDup checks for NoFieldSelectors if either the existing or the
- new GRE are record fields. See Note [NoFieldSelectors] in GHC.Rename.Env.
+This logic is implemented in the function 'GHC.Types.Name.Reader.greClashesWith'.
See also Note [Skipping ambiguity errors at use sites of local declarations] in
GHC.Rename.Utils.
@@ -900,19 +845,19 @@ getLocalNonValBinders fixity_env
; let inst_decls = tycl_decls >>= group_instds
; dup_fields_ok <- xopt_DuplicateRecordFields <$> getDynFlags
; has_sel <- xopt_FieldSelectors <$> getDynFlags
- ; (tc_avails, tc_fldss)
- <- fmap unzip $ mapM (new_tc dup_fields_ok has_sel)
- (tyClGroupTyClDecls tycl_decls)
- ; traceRn "getLocalNonValBinders 1" (ppr tc_avails)
- ; envs <- extendGlobalRdrEnvRn tc_avails fixity_env
+ ; tc_gres
+ <- concatMapM
+ (new_tc dup_fields_ok has_sel)
+ (tyClGroupTyClDecls tycl_decls)
+ ; traceRn "getLocalNonValBinders 1" (ppr tc_gres)
+ ; envs <- extendGlobalRdrEnvRn tc_gres fixity_env
; restoreEnvs envs $ do {
-- Bring these things into scope first
-- See Note [Looking up family names in family instances]
-- Process all family instances
-- to bring new data constructors into scope
- ; (nti_availss, nti_fldss) <- mapAndUnzipM (new_assoc dup_fields_ok has_sel)
- inst_decls
+ ; nti_gress <- mapM (new_assoc dup_fields_ok has_sel) inst_decls
-- Finish off with value binders:
-- foreign decls and pattern synonyms for an ordinary module
@@ -927,24 +872,13 @@ getLocalNonValBinders fixity_env
| L decl_loc (TypeSig _ ns _) <- val_sigs, n <- ns]
_ -> panic "Non-ValBinds in hs-boot group"
| otherwise = for_hs_bndrs
- ; val_avails <- mapM new_simple val_bndrs
+ ; val_gres <- mapM new_simple val_bndrs
- ; let avails = concat nti_availss ++ val_avails
- new_bndrs = availsToNameSetWithSelectors avails `unionNameSet`
- availsToNameSetWithSelectors tc_avails
- flds = concat nti_fldss ++ concat tc_fldss
+ ; let avails = concat nti_gress ++ val_gres
+ new_bndrs = gresToNameSet avails `unionNameSet`
+ gresToNameSet tc_gres
; traceRn "getLocalNonValBinders 2" (ppr avails)
- ; (tcg_env, tcl_env) <- extendGlobalRdrEnvRn avails fixity_env
-
- -- Force the field access so that tcg_env is not retained. The
- -- selector thunk optimisation doesn't kick-in, see #20139
- ; let !old_field_env = tcg_con_env tcg_env
- -- Extend tcg_con_env with new fields (this used to be the
- -- work of extendRecordFieldEnv)
- field_env = extendNameEnvList old_field_env flds
- envs = (tcg_env { tcg_con_env = field_env }, tcl_env)
-
- ; traceRn "getLocalNonValBinders 3" (vcat [ppr flds, ppr field_env])
+ ; envs <- extendGlobalRdrEnvRn avails fixity_env
; return (envs, new_bndrs) } }
where
for_hs_bndrs :: [LocatedN RdrName]
@@ -952,101 +886,61 @@ getLocalNonValBinders fixity_env
-- the SrcSpan attached to the input should be the span of the
-- declaration, not just the name
- new_simple :: LocatedN RdrName -> RnM AvailInfo
- new_simple rdr_name = do{ nm <- newTopSrcBinder rdr_name
- ; return (avail nm) }
+ new_simple :: LocatedN RdrName -> RnM GlobalRdrElt
+ new_simple rdr_name = do { nm <- newTopSrcBinder rdr_name
+ ; return (localVanillaGRE NoParent nm) }
new_tc :: DuplicateRecordFields -> FieldSelectors -> LTyClDecl GhcPs
- -> RnM (AvailInfo, [(Name, ConInfo)])
+ -> RnM [GlobalRdrElt]
new_tc dup_fields_ok has_sel tc_decl -- NOT for type/data instances
- = do { let (bndrs, flds) = hsLTyClDeclBinders tc_decl
- ; names@(main_name : sub_names) <- mapM (newTopSrcBinder . l2n) bndrs
- ; flds' <- mapM (newRecordSelector dup_fields_ok has_sel sub_names) flds
- ; let fld_env = case unLoc tc_decl of
- DataDecl { tcdDataDefn = d } -> mk_con_env d names flds'
- _ -> []
- ; return (availTC main_name names flds', fld_env) }
-
-
- -- Calculate the mapping from constructor names to arity and fields, which
- -- will go in tcg_con_env. It's convenient to do this here where
+ = do { let TyDeclBinders (main_bndr, tc_flav) at_bndrs sig_bndrs
+ (LConsWithFields cons_with_flds flds) = hsLTyClDeclBinders tc_decl
+ ; tycon_name <- newTopSrcBinder $ l2n main_bndr
+ ; at_names <- mapM (newTopSrcBinder . l2n . fst) at_bndrs
+ ; sig_names <- mapM (newTopSrcBinder . l2n) sig_bndrs
+ ; con_names_with_flds <- mapM (\(con,flds) -> (,flds) <$> newTopSrcBinder (l2n con)) cons_with_flds
+ ; flds' <- mapM (newRecordFieldLabel dup_fields_ok has_sel $ map fst con_names_with_flds) flds
+ ; mapM_ (add_dup_fld_errs flds') con_names_with_flds
+ ; let tc_gre = localTyConGRE (fmap (const tycon_name) tc_flav) tycon_name
+ fld_env = mk_fld_env con_names_with_flds flds'
+ at_gres = zipWith (\ (_, at_flav) at_nm -> localTyConGRE (fmap (const tycon_name) at_flav) at_nm)
+ at_bndrs at_names
+ sig_gres = map (localVanillaGRE (ParentIs tycon_name)) sig_names
+ con_gres = map (localConLikeGRE (ParentIs tycon_name)) fld_env
+ fld_gres = localFieldGREs (ParentIs tycon_name) fld_env
+ sub_gres = at_gres ++ sig_gres ++ con_gres ++ fld_gres
+ ; traceRn "getLocalNonValBinders new_tc" $
+ vcat [ text "tycon:" <+> ppr tycon_name
+ , text "tc_gre:" <+> ppr tc_gre
+ , text "sub_gres:" <+> ppr sub_gres ]
+ ; return $ tc_gre : sub_gres }
+
+ -- Calculate the record field information, which feeds into the GlobalRdrElts
+ -- for DataCons and their fields. It's convenient to do this here where
-- we are working with a single datatype definition.
- -- For more details, see Note [Local constructor info in the renamer]
- mk_con_env :: HsDataDefn GhcPs -> [Name] -> [FieldLabel]
- -> [(Name, ConInfo)]
- mk_con_env d names flds = concatMap find_con_flds (dd_cons d)
- where
- find_con_flds :: GenLocated l (ConDecl GhcPs) -> [(Name, ConInfo)]
- find_con_flds (L _ (ConDeclH98 { con_name = L _ rdr
- , con_args = con_det }))
- = [( find_con_name rdr
- , con_det_con_info con_det
- )]
- find_con_flds (L _ (ConDeclGADT { con_names = rdrs
- , con_g_args = con_gadt_det }))
- = [ ( find_con_name rdr
- , gadt_det_con_info con_gadt_det
- )
- | L _ rdr <- toList rdrs ]
-
- find_con_name rdr
- = expectJust "getLocalNonValBinders/find_con_name" $
- find (\ n -> nameOccName n == rdrNameOcc rdr) names
-
- con_det_con_info
- :: HsConDetails Void (HsScaled GhcPs (GenLocated SrcSpanAnnA (HsType GhcPs))) (GenLocated SrcSpanAnnL [GenLocated SrcSpanAnnA (ConDeclField GhcPs)])
- -> ConInfo
- con_det_con_info con_det =
- let
- (arity, fields) =
- case con_det of
- PrefixCon _ args ->
- (length args, [])
- RecCon cdflds ->
- ((find_con_decl_field_arity . unLoc) cdflds, concatMap find_con_decl_flds $ unLoc cdflds)
- InfixCon _ _ ->
- (2, [])
- in
- mkConInfo
- arity
- fields
-
- gadt_det_con_info :: HsConDeclGADTDetails GhcPs -> ConInfo
- gadt_det_con_info con_gadt_det =
- let
- (arity, fields) =
- case con_gadt_det of
- PrefixConGADT args ->
- (length args, [])
- RecConGADT (L _ args) _ ->
- (find_con_decl_field_arity args, concatMap find_con_decl_flds args)
- in
- mkConInfo
- arity
- fields
-
- find_con_decl_flds :: GenLocated l (ConDeclField GhcPs) -> [FieldLabel]
- find_con_decl_flds (L _ x)
- = map find_con_decl_fld (cd_fld_names x)
-
- find_con_decl_fld (L _ (FieldOcc _ (L _ rdr)))
- = expectJust "getLocalNonValBinders/find_con_decl_fld" $
- find (\ fl -> flLabel fl == lbl) flds
- where lbl = FieldLabelString $ occNameFS (rdrNameOcc rdr)
-
- find_con_decl_field_arity :: [GenLocated SrcSpanAnnA (ConDeclField GhcPs)] -> Arity
- find_con_decl_field_arity = length . concatMap (cd_fld_names . unLoc)
+ --
+ -- The information we needed was all set up for us:
+ -- see Note [Collecting record fields in data declarations] in GHC.Hs.Utils.
+ mk_fld_env :: [(Name, Maybe [Located Int])] -> IntMap FieldLabel
+ -> [(ConLikeName, ConInfo)]
+ mk_fld_env names flds =
+ [ (DataConName con, con_info)
+ | (con, mb_fl_indxs) <- names
+ , let con_info = case fmap (map ((flds IntMap.!) . unLoc)) mb_fl_indxs of
+ Nothing -> ConHasPositionalArgs
+ Just [] -> ConIsNullary
+ Just (fld:flds) -> ConHasRecordFields $ fld NE.:| flds ]
new_assoc :: DuplicateRecordFields -> FieldSelectors -> LInstDecl GhcPs
- -> RnM ([AvailInfo], [(Name, ConInfo)])
- new_assoc _ _ (L _ (TyFamInstD {})) = return ([], [])
+ -> RnM [GlobalRdrElt]
+ new_assoc _ _ (L _ (TyFamInstD {})) = return []
-- type instances don't bind new names
new_assoc dup_fields_ok has_sel (L _ (DataFamInstD _ d))
- = do { (avail, arityAndFlds) <- new_di dup_fields_ok has_sel Nothing d
- ; return ([avail], arityAndFlds) }
- new_assoc dup_fields_ok has_sel (L _ (ClsInstD _ (ClsInstDecl { cid_poly_ty = inst_ty
- , cid_datafam_insts = adts })))
+ = new_di dup_fields_ok has_sel Nothing d
+ new_assoc dup_fields_ok has_sel
+ (L _ (ClsInstD _ (ClsInstDecl { cid_poly_ty = inst_ty
+ , cid_datafam_insts = adts })))
= do -- First, attempt to grab the name of the class from the instance.
-- This step could fail if the instance is not headed by a class,
-- such as in the following examples:
@@ -1056,57 +950,87 @@ getLocalNonValBinders fixity_env
-- (2) The class is headed by a type variable, such as in
-- `instance c` (#16385)
--
- -- If looking up the class name fails, then mb_cls_nm will
+ -- If looking up the class name fails, then mb_cls_gre will
-- be Nothing.
- mb_cls_nm <- runMaybeT $ do
+ mb_cls_gre <- runMaybeT $ do
-- See (1) above
L loc cls_rdr <- MaybeT $ pure $ getLHsInstDeclClass_maybe inst_ty
-- See (2) above
- MaybeT $ setSrcSpan (locA loc) $ lookupGlobalOccRn_maybe cls_rdr
+ MaybeT $ setSrcSpan (locA loc) $ lookupGlobalOccRn_maybe SameOccName cls_rdr
-- Assuming the previous step succeeded, process any associated data
-- family instances. If the previous step failed, bail out.
- case mb_cls_nm of
- Nothing -> pure ([], [])
- Just cls_nm -> do
- (avails, fldss)
- <- mapAndUnzipM (new_loc_di dup_fields_ok has_sel (Just cls_nm)) adts
- pure (avails, concat fldss)
-
- new_di :: DuplicateRecordFields -> FieldSelectors -> Maybe Name -> DataFamInstDecl GhcPs
- -> RnM (AvailInfo, [(Name, ConInfo)])
+ case mb_cls_gre of
+ Nothing
+ -> pure []
+ Just cls_gre
+ -> let cls_nm = greName cls_gre
+ in concatMapM (new_di dup_fields_ok has_sel (Just cls_nm) . unLoc) adts
+
+ new_di :: DuplicateRecordFields -> FieldSelectors
+ -> Maybe Name -- class name
+ -> DataFamInstDecl GhcPs
+ -> RnM [GlobalRdrElt]
new_di dup_fields_ok has_sel mb_cls dfid@(DataFamInstDecl { dfid_eqn = ti_decl })
- = do { main_name <- lookupFamInstName mb_cls (feqn_tycon ti_decl)
- ; let (bndrs, flds) = hsDataFamInstBinders dfid
- ; sub_names <- mapM (newTopSrcBinder .l2n) bndrs
- ; flds' <- mapM (newRecordSelector dup_fields_ok has_sel sub_names) flds
- ; let avail = availTC (unLoc main_name) sub_names flds'
- -- main_name is not bound here!
- fld_env = mk_con_env (feqn_rhs ti_decl) sub_names flds'
- ; return (avail, fld_env) }
-
- new_loc_di :: DuplicateRecordFields -> FieldSelectors -> Maybe Name -> LDataFamInstDecl GhcPs
- -> RnM (AvailInfo, [(Name, ConInfo)])
- new_loc_di dup_fields_ok has_sel mb_cls (L _ d) = new_di dup_fields_ok has_sel mb_cls d
-
-newRecordSelector :: DuplicateRecordFields -> FieldSelectors -> [Name] -> LFieldOcc GhcPs -> RnM FieldLabel
-newRecordSelector _ _ [] _ = error "newRecordSelector: datatype has no constructors!"
-newRecordSelector dup_fields_ok has_sel (dc:_) (L loc (FieldOcc _ (L _ fld)))
+ = do { main_name <- unLoc <$> lookupFamInstName mb_cls (feqn_tycon ti_decl)
+ ; let LConsWithFields cons_with_flds flds = hsDataFamInstBinders dfid
+ ; sub_names <- mapM (\(con,flds) -> (,flds) <$> newTopSrcBinder (l2n con)) cons_with_flds
+ ; flds' <- mapM (newRecordFieldLabel dup_fields_ok has_sel $ map fst sub_names) flds
+ ; mapM_ (add_dup_fld_errs flds') sub_names
+ ; let fld_env = mk_fld_env sub_names flds'
+ con_gres = map (localConLikeGRE (ParentIs main_name)) fld_env
+ field_gres = localFieldGREs (ParentIs main_name) fld_env
+ -- NB: the data family name is not bound here,
+ -- so we don't return a GlobalRdrElt for it here!
+ ; return $ con_gres ++ field_gres }
+
+ -- Add errors if a constructor has a duplicate record field.
+ add_dup_fld_errs :: IntMap FieldLabel
+ -> (Name, Maybe [Located Int])
+ -> IOEnv (Env TcGblEnv TcLclEnv) ()
+ add_dup_fld_errs all_flds (con, mb_con_flds)
+ | Just con_flds <- mb_con_flds
+ , let (_, dups) = removeDups (comparing unLoc) con_flds
+ = for_ dups $ \ dup_flds ->
+ -- Report the error at the location of the second occurrence
+ -- of the duplicate field.
+ let loc =
+ case dup_flds of
+ _ :| ( L loc _ : _) -> loc
+ L loc _ :| _ -> loc
+ dup_rdrs = fmap (nameRdrName . flSelector . (all_flds IntMap.!) . unLoc) dup_flds
+ in addErrAt loc $ TcRnDuplicateFieldName (RecordFieldDecl con) dup_rdrs
+ | otherwise
+ = return ()
+
+newRecordFieldLabel :: DuplicateRecordFields -> FieldSelectors -> [Name] -> LFieldOcc GhcPs -> RnM FieldLabel
+newRecordFieldLabel _ _ [] _ = error "newRecordFieldLabel: datatype has no constructors!"
+newRecordFieldLabel dup_fields_ok has_sel (dc:_) (L loc (FieldOcc _ (L _ fld)))
= do { selName <- newTopSrcBinder $ L (l2l loc) $ field
- ; return $ FieldLabel { flLabel = fieldLabelString
- , flHasDuplicateRecordFields = dup_fields_ok
+ ; return $ FieldLabel { flHasDuplicateRecordFields = dup_fields_ok
, flHasFieldSelector = has_sel
, flSelector = selName } }
where
- fieldLabelString = FieldLabelString $ occNameFS $ rdrNameOcc fld
- selOccName = fieldSelectorOccName fieldLabelString (nameOccName dc) dup_fields_ok has_sel
- field | isExact fld = fld
- -- use an Exact RdrName as is to preserve the bindings
- -- of an already renamer-resolved field and its use
- -- sites. This is needed to correctly support record
- -- selectors in Template Haskell. See Note [Binders in
- -- Template Haskell] in "GHC.ThToHs" and Note [Looking up
- -- Exact RdrNames] in "GHC.Rename.Env".
- | otherwise = mkRdrUnqual selOccName
+ fld_occ = rdrNameOcc fld
+ dc_fs = (occNameFS $ nameOccName dc)
+ field
+ -- Use an Exact RdrName as-is, to preserve the bindings
+ -- of an already renamer-resolved field and its use
+ -- sites. This is needed to correctly support record
+ -- selectors in Template Haskell. See Note [Binders in
+ -- Template Haskell] in "GHC.ThToHs" and Note [Looking up
+ -- Exact RdrNames] in "GHC.Rename.Env".
+ | isExact fld
+ = assertPpr (fieldOcc_maybe fld_occ == Just dc_fs)
+ (vcat [ text "newRecordFieldLabel: incorrect namespace for exact Name" <+> quotes (ppr fld)
+ , text "expected namespace:" <+> pprNameSpace (fieldName dc_fs)
+ , text " actual namespace:" <+> pprNameSpace (occNameSpace fld_occ) ])
+ fld
+
+ -- Field names produced by the parser are namespaced with VarName.
+ -- Here we namespace them according to the first constructor.
+ -- See Note [Record field namespacing] in GHC.Types.Name.Occurrence.
+ | otherwise
+ = mkRdrUnqual $ varToRecFieldOcc dc_fs fld_occ
{-
Note [Looking up family names in family instances]
@@ -1138,37 +1062,52 @@ available, and filters it through the import spec (if any).
Note [Dealing with imports]
~~~~~~~~~~~~~~~~~~~~~~~~~~~
-For import M( ies ), we take the mi_exports of M, and make
- imp_occ_env :: OccEnv (NameEnv (GreName, AvailInfo, Maybe Name))
-One entry for each OccName that M exports, mapping each corresponding Name to
-its GreName, the AvailInfo exported from M that exports that Name, and
-optionally a Name for an associated type's parent class. (Typically there will
-be a single Name in the NameEnv, but see Note [Importing DuplicateRecordFields]
-for why we may need more than one.)
-
-The situation is made more complicated by associated types. E.g.
- module M where
- class C a where { data T a }
- instance C Int where { data T Int = T1 | T2 }
- instance C Bool where { data T Int = T3 }
-Then M's export_avails are (recall the AvailTC invariant from Avails.hs)
+For import M( ies ), we take each AvailInfo from the mi_exports of M, and make
+
+ imp_occ_env :: OccEnv (NameEnv ImpOccItem)
+
+This map contains one entry for each OccName that M exports, mapping each OccName
+to the following information:
+
+ 1. the GlobalRdrElt corresponding to the OccName,
+ 2. whether this GlobalRdrElt was the parent in the AvailInfo we found
+ the OccName in.
+ 3. the GlobalRdrElts that were bundled together in the AvailInfo we found
+ this OccName in (not including the parent),
+
+We need (2) and (3) during the construction of the OccEnv because of associated
+types and bundled pattern synonyms, respectively.
+(3) is explained in Note [Importing PatternSynonyms].
+
+To explain (2), consider for example:
+
+ module M where
+ class C a where { data T a }
+ instance C Int where { data T Int = T1 | T2 }
+ instance C Bool where { data T Int = T3 }
+
+Here, M's exports avails are (recalling the AvailTC invariant from GHC.Types.Avail)
+
C(C,T), T(T,T1,T2,T3)
+
Notice that T appears *twice*, once as a child and once as a parent. From
-this list we construct a raw list including
- T -> (T, T( T1, T2, T3 ), Nothing)
- T -> (T, C( C, T ), Nothing)
-and we combine these (in function 'combine' in 'imp_occ_env' in
-'filterImports') to get
- T -> (T, T(T,T1,T2,T3), Just C)
-
-So the overall imp_occ_env is
- C -> (C, C(C,T), Nothing)
- T -> (T, T(T,T1,T2,T3), Just C)
- T1 -> (T1, T(T,T1,T2,T3), Nothing) -- similarly T2,T3
-
-If we say
- import M( T(T1,T2) )
-then we get *two* Avails: C(T), T(T1,T2)
+these two exports, respectively, during construction of the imp_occ_env, we begin
+by associating the following two elements with the key T:
+
+ T -> ImpOccItem { imp_item = T, imp_bundled = [C,T] , imp_is_parent = False }
+ T -> ImpOccItem { imp_item = T, imp_bundled = [T1,T2,T3], imp_is_parent = True }
+
+We combine these (in function 'combine' in 'mkImportOccEnv') by simply discarding
+the first item, to get:
+
+ T -> IE_ITem { imp_item = T, imp_bundled = [T1,T2,T3], imp_is_parent = True }
+
+So the overall imp_occ_env is:
+
+ C -> ImpOccItem { imp_item = C, imp_bundled = [T ], imp_is_parent = True }
+ T -> ImpOccItem { imp_item = T , imp_bundled = [T1,T2,T3], imp_is_parent = True }
+ T1 -> ImpOccItem { imp_item = T1, imp_bundled = [T1,T2,T3], imp_is_parent = False }
+ -- similarly for T2, T3
Note that the imp_occ_env will have entries for data constructors too,
although we never look up data constructors.
@@ -1187,12 +1126,16 @@ A simplified example, based on #11959:
data T = MkT
pattern P = MkT
-Here we have T(P) and P in export_avails, and construct both
- P -> (P, P, Nothing)
- P -> (P, T(P), Nothing)
-which are 'combine'd to leave
- P -> (P, T(P), Nothing)
-i.e. we simply discard the non-bundled Avail.
+Here we have T(P) and P in export_avails, and respectively construct both
+
+ P -> ImpOccItem { imp_item = P, imp_bundled = [P], imp_is_parent = False }
+ P -> ImpOccItem { imp_item = P, imp_bundled = [] , imp_is_parent = False }
+
+We combine these by dropping the one with no siblings, leaving us with:
+
+ P -> ImpOccItem { imp_item = P, imp_bundled = [P], imp_is_parent = False }
+
+That is, we simply discard the non-bundled Avail.
Note [Importing DuplicateRecordFields]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1202,124 +1145,117 @@ Suppose we have:
{-# LANGUAGE DuplicateRecordFields #-}
module M (S(foo), T(foo)) where
data S = MkS { foo :: Int }
- data T = mkT { foo :: Int }
+ data T = MkT { foo :: Int }
module N where
import M (foo) -- this is allowed (A)
import M (S(foo)) -- this is allowed (B)
-Here M exports the OccName 'foo' twice, so we get an imp_occ_env where 'foo'
-maps to a NameEnv containing an entry for each of the two mangled field selector
-names (see Note [FieldLabel] in GHC.Types.FieldLabel).
-
- foo -> [ $sel:foo:MkS -> (foo, S(foo), Nothing)
- , $sel:foo:MKT -> (foo, T(foo), Nothing)
- ]
-
-Then when we look up 'foo' in lookup_names for case (A) we get both entries and
-hence two Avails. Whereas in case (B) we reach the lookup_ie
-case for IEThingWith, which looks up 'S' and then finds the unique 'foo' amongst
-its children.
+Here M exports 'foo' at two different OccNames, with different namespaces for
+the two construtors MkS and MkT. Then, when we look up 'foo' in lookup_names
+for case (A), we have a variable foo but must look in all the record field
+namespaces to find the two fields (and hence two different Avails).
+Whereas in case (B) we reach the lookup_ie case for IEThingWith,
+which looks up 'S' and then finds the unique 'foo' amongst its children.
See T16745 for a test of this.
-
-}
+-- | All the 'GlobalRdrElt's associated with an 'AvailInfo'.
+gresFromAvail :: HasDebugCallStack
+ => HscEnv -> Maybe ImportSpec -> AvailInfo -> [GlobalRdrElt]
+gresFromAvail hsc_env prov avail =
+ [ mk_gre nm info
+ | nm <- availNames avail
+ , let info = lookupGREInfo hsc_env nm ]
+ where
+
+ mk_gre n info
+ = case prov of
+ -- Nothing => bound locally
+ -- Just is => imported from 'is'
+ Nothing -> GRE { gre_name = n, gre_par = mkParent n avail
+ , gre_lcl = True, gre_imp = emptyBag
+ , gre_info = info }
+ Just is -> GRE { gre_name = n, gre_par = mkParent n avail
+ , gre_lcl = False, gre_imp = unitBag is
+ , gre_info = info }
+
+-- | All the 'GlobalRdrElt's associated with a collection of 'AvailInfo's.
+gresFromAvails :: HscEnv -> Maybe ImportSpec -> [AvailInfo] -> [GlobalRdrElt]
+gresFromAvails hsc_env prov = concatMap (gresFromAvail hsc_env prov)
+
filterImports
- :: ModIface
- -> ImpDeclSpec -- The span for the entire import decl
- -> Maybe (ImportListInterpretation, LocatedL [LIE GhcPs]) -- Import spec; True => hiding
+ :: HasDebugCallStack
+ => HscEnv
+ -> ModIface
+ -> ImpDeclSpec
+ -- ^ Import spec
+ -> Maybe (ImportListInterpretation, LocatedL [LIE GhcPs])
+ -- ^ Whether this is a "hiding" import list
-> RnM (Maybe (ImportListInterpretation, LocatedL [LIE GhcRn]), -- Import spec w/ Names
[GlobalRdrElt]) -- Same again, but in GRE form
-filterImports iface decl_spec Nothing
- = return (Nothing, gresFromAvails (Just imp_spec) (mi_exports iface))
+filterImports hsc_env iface decl_spec Nothing
+ = return (Nothing, gresFromAvails hsc_env (Just imp_spec) all_avails)
where
+ all_avails = mi_exports iface
imp_spec = ImpSpec { is_decl = decl_spec, is_item = ImpAll }
-
-filterImports iface decl_spec (Just (want_hiding, L l import_items))
+filterImports hsc_env iface decl_spec (Just (want_hiding, L l import_items))
= do -- check for errors, convert RdrNames to Names
items1 <- mapM lookup_lie import_items
- let items2 :: [(LIE GhcRn, AvailInfo)]
+ let items2 :: [(LIE GhcRn, [GlobalRdrElt])]
items2 = concat items1
- -- NB the AvailInfo may have duplicates, and several items
+ -- NB we may have duplicates, and several items
-- for the same parent; e.g N(x) and N(y)
- names = availsToNameSetWithSelectors (map snd items2)
- keep n = not (n `elemNameSet` names)
- pruned_avails = filterAvails keep all_avails
- hiding_spec = ImpSpec { is_decl = decl_spec, is_item = ImpAll }
-
- gres | want_hiding == EverythingBut = gresFromAvails (Just hiding_spec) pruned_avails
- | otherwise = concatMap (gresFromIE decl_spec) items2
+ gres = case want_hiding of
+ Exactly ->
+ concatMap (gresFromIE decl_spec) items2
+ EverythingBut ->
+ let hidden_names = mkNameSet $ concatMap (map greName . snd) items2
+ keep n = not (n `elemNameSet` hidden_names)
+ all_gres = gresFromAvails hsc_env (Just hiding_spec) all_avails
+ in filter (keep . greName) all_gres
return (Just (want_hiding, L l (map fst items2)), gres)
where
all_avails = mi_exports iface
-
- -- See Note [Dealing with imports]
- imp_occ_env :: OccEnv (NameEnv (GreName, -- the name or field
- AvailInfo, -- the export item providing it
- Maybe Name)) -- the parent of associated types
- imp_occ_env = mkOccEnv_C (plusNameEnv_C combine)
- [ (occName c, mkNameEnv [(greNameMangledName c, (c, a, Nothing))])
- | a <- all_avails
- , c <- availGreNames a]
- -- See Note [Dealing with imports]
- -- 'combine' may be called for associated data types which appear
- -- twice in the all_avails. In the example, we combine
- -- T(T,T1,T2,T3) and C(C,T) to give (T, T(T,T1,T2,T3), Just C)
- -- NB: the AvailTC can have fields as well as data constructors (#12127)
- combine :: (GreName, AvailInfo, Maybe Name)
- -> (GreName, AvailInfo, Maybe Name)
- -> (GreName, AvailInfo, Maybe Name)
- combine (NormalGreName name1, a1@(AvailTC p1 _), mb1)
- (NormalGreName name2, a2@(AvailTC p2 _), mb2)
- = assertPpr (name1 == name2 && isNothing mb1 && isNothing mb2)
- (ppr name1 <+> ppr name2 <+> ppr mb1 <+> ppr mb2) $
- if p1 == name1 then (NormalGreName name1, a1, Just p2)
- else (NormalGreName name1, a2, Just p1)
- -- 'combine' may also be called for pattern synonyms which appear both
- -- unassociated and associated (see Note [Importing PatternSynonyms]).
- combine (c1, a1, mb1) (c2, a2, mb2)
- = assertPpr (c1 == c2 && isNothing mb1 && isNothing mb2
- && (isAvailTC a1 || isAvailTC a2))
- (ppr c1 <+> ppr c2 <+> ppr a1 <+> ppr a2 <+> ppr mb1 <+> ppr mb2) $
- if isAvailTC a1 then (c1, a1, Nothing)
- else (c1, a2, Nothing)
-
- isAvailTC AvailTC{} = True
- isAvailTC _ = False
+ hiding_spec = ImpSpec { is_decl = decl_spec, is_item = ImpAll }
+ imp_occ_env = mkImportOccEnv hsc_env decl_spec all_avails
-- Look up a RdrName used in an import, failing if it is ambiguous
-- (e.g. because it refers to multiple record fields)
- lookup_name :: IE GhcPs -> RdrName -> IELookupM (Name, AvailInfo, Maybe Name)
+ lookup_name :: IE GhcPs -> RdrName -> IELookupM ImpOccItem
lookup_name ie rdr = do
xs <- lookup_names ie rdr
case xs of
[cax] -> return cax
- _ -> failLookupWith (AmbiguousImport rdr (map sndOf3 xs))
+ _ -> failLookupWith (AmbiguousImport rdr (map imp_item xs))
-- Look up a RdrName used in an import, returning multiple values if there
-- are several fields with the same name exposed by the module
- lookup_names :: IE GhcPs -> RdrName -> IELookupM [(Name, AvailInfo, Maybe Name)]
+ lookup_names :: IE GhcPs -> RdrName -> IELookupM [ImpOccItem]
lookup_names ie rdr
- | isQual rdr = failLookupWith (QualImportError rdr)
- | Just succ <- mb_success = return $ map (\ (c,a,x) -> (greNameMangledName c, a, x)) (nonDetNameEnvElts succ)
- | otherwise = failLookupWith (BadImport ie)
+ | isQual rdr
+ = failLookupWith (QualImportError rdr)
+ | null lookups
+ = failLookupWith (BadImport ie)
+ | otherwise
+ = return $ concatMap nonDetNameEnvElts lookups
where
- mb_success = lookupOccEnv imp_occ_env (rdrNameOcc rdr)
+ lookups = lookupOccEnv_WithFields imp_occ_env (rdrNameOcc rdr)
- lookup_lie :: LIE GhcPs -> TcRn [(LIE GhcRn, AvailInfo)]
+ lookup_lie :: LIE GhcPs -> TcRn [(LIE GhcRn, [GlobalRdrElt])]
lookup_lie (L loc ieRdr)
= do (stuff, warns) <- setSrcSpanA loc $
liftM (fromMaybe ([],[])) $
run_lookup (lookup_ie ieRdr)
mapM_ emit_warning warns
- return [ (L loc ie, avail) | (ie,avail) <- stuff ]
+ return [ (L loc ie, gres) | (ie,gres) <- stuff ]
where
- -- Warn when importing T(..) if T was exported abstractly
+ -- Warn when importing T(..) and no children are brought in scope
emit_warning (DodgyImport n) = whenWOptM Opt_WarnDodgyImports $
addTcRnDiagnostic (TcRnDodgyImports n)
emit_warning MissingImportList = whenWOptM Opt_WarnMissingImportList $
@@ -1345,51 +1281,45 @@ filterImports iface decl_spec (Just (want_hiding, L l import_items))
AmbiguousImport rdr xs -> ambiguousImportItemErr rdr xs
-- For each import item, we convert its RdrNames to Names,
- -- and at the same time construct an AvailInfo corresponding
+ -- and at the same time compute all the GlobalRdrElt corresponding
-- to what is actually imported by this item.
-- Returns Nothing on error.
- -- We return a list here, because in the case of an import
- -- item like C, if we are hiding, then C refers to *both* a
- -- type/class and a data constructor. Moreover, when we import
- -- data constructors of an associated family, we need separate
- -- AvailInfos for the data constructors and the family (as they have
- -- different parents). See Note [Dealing with imports]
+ --
+ -- Returns a list because, with DuplicateRecordFields, a naked
+ -- import/export of a record field can correspond to multiple
+ -- different GlobalRdrElts. See Note [Importing DuplicateRecordFields].
lookup_ie :: IE GhcPs
- -> IELookupM ([(IE GhcRn, AvailInfo)], [IELookupWarning])
+ -> IELookupM ([(IE GhcRn, [GlobalRdrElt])], [IELookupWarning])
lookup_ie ie = handle_bad_import $
case ie of
IEVar _ (L l n) -> do
-- See Note [Importing DuplicateRecordFields]
xs <- lookup_names ie (ieWrappedName n)
- return ([(IEVar noExtField (L l (replaceWrappedName n name)),
- trimAvail avail name)
- | (name, avail, _) <- xs ], [])
+ return ( [ (IEVar noExtField (L l (replaceWrappedName n name)), [gre])
+ | ImpOccItem { imp_item = gre } <- xs
+ , let name = greName gre ]
+ , [] )
IEThingAll _ (L l tc) -> do
- (name, avail, mb_parent) <- lookup_name ie $ ieWrappedName tc
- let warns = case avail of
- Avail {} -- e.g. f(..)
- -> [DodgyImport $ ieWrappedName tc]
+ ImpOccItem gre child_gres _ <- lookup_name ie $ ieWrappedName tc
+ let name = greName gre
+ warns
- AvailTC _ subs
- | null (drop 1 subs) -- e.g. T(..) where T is a synonym
- -> [DodgyImport $ ieWrappedName tc]
+ | null child_gres
+ -- e.g. f(..) or T(..) where T is a type synonym
+ = [DodgyImport gre]
- | not (is_qual decl_spec) -- e.g. import M( T(..) )
- -> [MissingImportList]
+ -- e.g. import M( T(..) )
+ | not (is_qual decl_spec)
+ = [MissingImportList]
- | otherwise
- -> []
+ | otherwise
+ = []
renamed_ie = IEThingAll noAnn (L l (replaceWrappedName tc name))
- sub_avails = case avail of
- Avail {} -> []
- AvailTC name2 subs -> [(renamed_ie, AvailTC name2 (subs \\ [NormalGreName name]))]
- case mb_parent of
- Nothing -> return ([(renamed_ie, avail)], warns)
- -- non-associated ty/cls
- Just parent -> return ((renamed_ie, AvailTC parent [NormalGreName name]) : sub_avails, warns)
- -- associated type
+
+ return ([(renamed_ie, gre:child_gres)], warns)
+
IEThingAbs _ (L l tc')
| want_hiding == EverythingBut -- hiding ( C )
@@ -1401,19 +1331,18 @@ filterImports iface decl_spec (Just (want_hiding, L l import_items))
in
case catIELookupM [ tc_name, dc_name ] of
[] -> failLookupWith (BadImport ie)
- names -> return ([mkIEThingAbs tc' l name | name <- names], [])
+ names -> return ([mkIEThingAbs tc' l (imp_item name) | name <- names], [])
| otherwise
- -> do nameAvail <- lookup_name ie (ieWrappedName tc')
- return ([mkIEThingAbs tc' l nameAvail]
- , [])
+ -> do ImpOccItem { imp_item = gre } <- lookup_name ie (ieWrappedName tc')
+ return ([mkIEThingAbs tc' l gre], [])
IEThingWith xt ltc@(L l rdr_tc) wc rdr_ns -> do
- (name, avail, mb_parent)
+ ImpOccItem { imp_item = gre, imp_bundled = subnames }
<- lookup_name (IEThingAbs noAnn ltc) (ieWrappedName rdr_tc)
+ let name = greName gre
-- Look up the children in the sub-names of the parent
-- See Note [Importing DuplicateRecordFields]
- let subnames = availSubordinateGreNames avail
case lookupChildren subnames rdr_ns of
Failed rdrs -> failLookupWith (BadImport (IEThingWith xt ltc wc rdrs))
@@ -1422,36 +1351,22 @@ filterImports iface decl_spec (Just (want_hiding, L l import_items))
-- to report as failing, namely T( b, d ).
-- c.f. #15412
- Succeeded (childnames, childflds) ->
- case mb_parent of
- -- non-associated ty/cls
- Nothing
- -> return ([(IEThingWith childflds (L l name') wc childnames',
- availTC name (name:map unLoc childnames) (map unLoc childflds))],
- [])
- where name' = replaceWrappedName rdr_tc name
- childnames' = map to_ie_post_rn childnames
- -- childnames' = postrn_ies childnames
- -- associated ty
- Just parent
- -> return ([(IEThingWith childflds (L l name') wc childnames',
- availTC name (map unLoc childnames) (map unLoc childflds)),
- (IEThingWith childflds (L l name') wc childnames',
- availTC parent [name] [])],
- [])
- where name' = replaceWrappedName rdr_tc name
- childnames' = map to_ie_post_rn childnames
+ Succeeded childnames ->
+ return ([ (IEThingWith xt (L l name') wc childnames'
+ ,gre : map unLoc childnames)]
+ , [])
+
+ where name' = replaceWrappedName rdr_tc name
+ childnames' = map (to_ie_post_rn . fmap greName) childnames
_other -> failLookupWith IllegalImport
- -- could be IEModuleContents, IEGroup, IEDoc, IEDocNamed
- -- all errors.
+ -- could be IEModuleContents, IEGroup, IEDoc, IEDocNamed...
+ -- all of those constitute errors.
where
- mkIEThingAbs tc l (n, av, Nothing )
- = (IEThingAbs noAnn (L l (replaceWrappedName tc n)), trimAvail av n)
- mkIEThingAbs tc l (n, _, Just parent)
- = (IEThingAbs noAnn (L l (replaceWrappedName tc n))
- , availTC parent [n] [])
+ mkIEThingAbs tc l gre
+ = (IEThingAbs noAnn (L l (replaceWrappedName tc n)), [gre])
+ where n = greName gre
handle_bad_import m = catchIELookup m $ \err -> case err of
BadImport ie | want_hiding == EverythingBut -> return ([], [BadImportW ie])
@@ -1462,14 +1377,13 @@ type IELookupM = MaybeErr IELookupError
data IELookupWarning
= BadImportW (IE GhcPs)
| MissingImportList
- | DodgyImport RdrName
- -- NB. use the RdrName for reporting a "dodgy" import
+ | DodgyImport GlobalRdrElt
data IELookupError
= QualImportError RdrName
| BadImport (IE GhcPs)
| IllegalImport
- | AmbiguousImport RdrName [AvailInfo] -- e.g. a duplicated field name as a top-level import
+ | AmbiguousImport RdrName [GlobalRdrElt] -- e.g. a duplicated field name as a top-level import
failLookupWith :: IELookupError -> IELookupM a
failLookupWith err = Failed err
@@ -1482,6 +1396,76 @@ catchIELookup m h = case m of
catIELookupM :: [IELookupM a] -> [a]
catIELookupM ms = [ a | Succeeded a <- ms ]
+-- | Information associated to an 'AvailInfo' used in constructing
+-- an 'OccEnv' corresponding to imports.
+--
+-- See Note [Dealing with imports].
+data ImpOccItem
+ = ImpOccItem
+ { imp_item :: GlobalRdrElt
+ -- ^ The import item
+ , imp_bundled :: [GlobalRdrElt]
+ -- ^ Items bundled in the Avail this import item came from,
+ -- not including the import item itself if it is a parent.
+ , imp_is_parent :: Bool
+ -- ^ Is the import item a parent? See Note [Dealing with imports].
+ }
+
+-- | Make an 'OccEnv' of all the imports.
+--
+-- Complicated by the fact that associated data types and pattern synonyms
+-- can appear twice. See Note [Dealing with imports].
+mkImportOccEnv :: HscEnv -> ImpDeclSpec -> [IfaceExport] -> OccEnv (NameEnv ImpOccItem)
+mkImportOccEnv hsc_env decl_spec all_avails =
+ mkOccEnv_C (plusNameEnv_C combine)
+ [ (occ, mkNameEnv [(nm, ImpOccItem g bundled is_parent)])
+ | avail <- all_avails
+ , let gs = gresFromAvail hsc_env (Just hiding_spec) avail
+ , g <- gs
+ , let nm = greName g
+ occ = greOccName g
+ (is_parent, bundled) = case avail of
+ AvailTC c _
+ -> if c == nm -- (Recall the AvailTC invariant)
+ then ( True, case gs of { g0 : gs' | greName g0 == nm -> gs'; _ -> gs } )
+ else ( False, gs )
+ _ -> ( False, [] )
+ ]
+ where
+
+ hiding_spec = ImpSpec { is_decl = decl_spec, is_item = ImpAll }
+
+ -- See Note [Dealing with imports]
+ -- 'combine' may be called for associated data types which appear
+ -- twice in the all_avails. In the example, we combine
+ -- T(T,T1,T2,T3) and C(C,T) to give (T, T(T,T1,T2,T3), Just C)
+ -- NB: the AvailTC can have fields as well as data constructors (#12127)
+ combine :: ImpOccItem -> ImpOccItem -> ImpOccItem
+ combine item1@(ImpOccItem { imp_item = gre1, imp_is_parent = is_parent1 })
+ item2@(ImpOccItem { imp_item = gre2, imp_is_parent = is_parent2 })
+ | is_parent1 || is_parent2
+ , not (isRecFldGRE gre1 || isRecFldGRE gre2) -- NB: does not force GREInfo.
+ , let name1 = greName gre1
+ name2 = greName gre2
+ = assertPpr (name1 == name2)
+ (ppr name1 <+> ppr name2) $
+ if is_parent1
+ then item1
+ else item2
+ -- Discard C(C,T) in favour of T(T, T1, T2, T3).
+
+ -- 'combine' may also be called for pattern synonyms which appear both
+ -- unassociated and associated (see Note [Importing PatternSynonyms]).
+ combine item1@(ImpOccItem { imp_item = c1, imp_bundled = kids1 })
+ item2@(ImpOccItem { imp_item = c2, imp_bundled = kids2 })
+ = assertPpr (greName c1 == greName c2
+ && (not (null kids1 && null kids2)))
+ (ppr c1 <+> ppr c2 <+> ppr kids1 <+> ppr kids2) $
+ if null kids1
+ then item2
+ else item1
+ -- Discard standalone pattern P in favour of T(P).
+
{-
************************************************************************
* *
@@ -1490,20 +1474,22 @@ catIELookupM ms = [ a | Succeeded a <- ms ]
************************************************************************
-}
--- | Given an import\/export spec, construct the appropriate 'GlobalRdrElt's.
-gresFromIE :: ImpDeclSpec -> (LIE GhcRn, AvailInfo) -> [GlobalRdrElt]
-gresFromIE decl_spec (L loc ie, avail)
- = gresFromAvail prov_fn avail
+-- | Given an import\/export spec, appropriately set the @gre_imp@ field
+-- for the 'GlobalRdrElt's.
+gresFromIE :: ImpDeclSpec -> (LIE GhcRn, [GlobalRdrElt]) -> [GlobalRdrElt]
+gresFromIE decl_spec (L loc ie, gres)
+ = map set_gre_imp gres
where
is_explicit = case ie of
IEThingAll _ name -> \n -> n == lieWrappedName name
_ -> \_ -> True
prov_fn name
- = Just (ImpSpec { is_decl = decl_spec, is_item = item_spec })
+ = ImpSpec { is_decl = decl_spec, is_item = item_spec }
where
item_spec = ImpSome { is_explicit = is_explicit name
, is_iloc = locA loc }
-
+ set_gre_imp gre@( GRE { gre_name = nm } )
+ = gre { gre_imp = unitBag $ prov_fn nm }
{-
Note [Children for duplicate record fields]
@@ -1531,9 +1517,10 @@ mkChildEnv gres = foldr add emptyNameEnv gres
findChildren :: NameEnv [a] -> Name -> [a]
findChildren env n = lookupNameEnv env n `orElse` []
-lookupChildren :: [GreName] -> [LIEWrappedName GhcPs]
+lookupChildren :: [GlobalRdrElt]
+ -> [LIEWrappedName GhcPs]
-> MaybeErr [LIEWrappedName GhcPs] -- The ones for which the lookup failed
- ([LocatedA Name], [Located FieldLabel])
+ [LocatedA GlobalRdrElt]
-- (lookupChildren all_kids rdr_items) maps each rdr_item to its
-- corresponding Name all_kids, if the former exists
-- The matching is done by FastString, not OccName, so that
@@ -1543,7 +1530,7 @@ lookupChildren :: [GreName] -> [LIEWrappedName GhcPs]
-- (Really the rdr_items should be FastStrings in the first place.)
lookupChildren all_kids rdr_items
| null fails
- = Succeeded (fmap concat (partitionEithers oks))
+ = Succeeded (concat oks)
-- This 'fmap concat' trickily applies concat to the /second/ component
-- of the pair, whose type is ([LocatedA Name], [[Located FieldLabel]])
| otherwise
@@ -1552,20 +1539,23 @@ lookupChildren all_kids rdr_items
mb_xs = map doOne rdr_items
fails = [ bad_rdr | Failed bad_rdr <- mb_xs ]
oks = [ ok | Succeeded ok <- mb_xs ]
- oks :: [Either (LocatedA Name) [Located FieldLabel]]
+ oks :: [[LocatedA GlobalRdrElt]]
doOne item@(L l r)
= case (lookupFsEnv kid_env . occNameFS . rdrNameOcc . ieWrappedName) r of
- Just [NormalGreName n] -> Succeeded (Left (L l n))
- Just rs | Just fs <- traverse greNameFieldLabel rs -> Succeeded (Right (map (L (locA l)) fs))
- _ -> Failed item
+ Just [g]
+ | not $ isRecFldGRE g
+ -> Succeeded [L l g]
+ Just gs
+ | all isRecFldGRE gs
+ -> Succeeded $ map (L l) gs
+ _ -> Failed item
-- See Note [Children for duplicate record fields]
kid_env = extendFsEnvList_C (++) emptyFsEnv
[(occNameFS (occName x), [x]) | x <- all_kids]
-
-------------------------------
{-
@@ -1600,11 +1590,11 @@ reportUnusedNames gbl_env hsc_src
gre_is_used :: NameSet -> GlobalRdrElt -> Bool
gre_is_used used_names gre0
= name `elemNameSet` used_names
- || any (\ gre -> greMangledName gre `elemNameSet` used_names) (findChildren kids_env name)
+ || any (\ gre -> greName gre `elemNameSet` used_names) (findChildren kids_env name)
-- A use of C implies a use of T,
-- if C was brought into scope by T(..) or T(C)
where
- name = greMangledName gre0
+ name = greName gre0
-- Filter out the ones that are
-- (a) defined in this module, and
@@ -1621,7 +1611,8 @@ reportUnusedNames gbl_env hsc_src
in filter is_unused_local defined_but_not_used
is_unused_local :: GlobalRdrElt -> Bool
- is_unused_local gre = isLocalGRE gre && isExternalName (greMangledName gre)
+ is_unused_local gre = isLocalGRE gre
+ && isExternalName (greName gre)
{- *********************************************************************
* *
@@ -1756,7 +1747,6 @@ warnUnusedImportDecls gbl_env hsc_src
-- both for warning about unnecessary ones, and for
-- deciding the minimal ones
rdr_env = tcg_rdr_env gbl_env
- fld_env = mkFieldEnv rdr_env
; let usage :: [ImportDeclUsage]
usage = findImportUsage user_imports uses
@@ -1766,7 +1756,7 @@ warnUnusedImportDecls gbl_env hsc_src
, text "Import usage" <+> ppr usage])
; whenWOptM Opt_WarnUnusedImports $
- mapM_ (warnUnusedImport Opt_WarnUnusedImports fld_env) usage
+ mapM_ (warnUnusedImport Opt_WarnUnusedImports rdr_env) usage
; whenGOptM Opt_D_dump_minimal_imports $
printMinimalImports hsc_src usage }
@@ -1789,7 +1779,7 @@ findImportUsage imports used_gres
-- srcSpanEnd: see Note [The ImportMap]
`orElse` []
- used_names = mkNameSet (map greMangledName used_gres)
+ used_names = mkNameSet (map greName used_gres)
used_parents = mkNameSet (mapMaybe greParent_maybe used_gres)
unused_imps -- Not trivial; see eg #7454
@@ -1802,10 +1792,10 @@ findImportUsage imports used_gres
add_unused (IEVar _ n) acc = add_unused_name (lieWrappedName n) acc
add_unused (IEThingAbs _ n) acc = add_unused_name (lieWrappedName n) acc
add_unused (IEThingAll _ n) acc = add_unused_all (lieWrappedName n) acc
- add_unused (IEThingWith fs p wc ns) acc =
+ add_unused (IEThingWith _ p wc ns) acc =
add_wc_all (add_unused_with pn xs acc)
where pn = lieWrappedName p
- xs = map lieWrappedName ns ++ map (flSelector . unLoc) fs
+ xs = map lieWrappedName ns
add_wc_all = case wc of
NoIEWildcard -> id
IEWildcard _ -> add_unused_all pn
@@ -1868,9 +1858,9 @@ mkImportMap gres
best_imp_spec = bestImport (bagToList imp_specs)
add _ gres = gre : gres
-warnUnusedImport :: WarningFlag -> NameEnv (FieldLabelString, Parent)
+warnUnusedImport :: WarningFlag -> GlobalRdrEnv
-> ImportDeclUsage -> RnM ()
-warnUnusedImport flag fld_env (L loc decl, used, unused)
+warnUnusedImport flag rdr_env (L loc decl, used, unused)
-- Do not warn for 'import M()'
| Just (Exactly, L _ []) <- ideclImportList decl
@@ -1923,10 +1913,15 @@ warnUnusedImport flag fld_env (L loc decl, used, unused)
-- In warning message, pretty-print identifiers unqualified unconditionally
-- to improve the consistent for ambiguous/unambiguous identifiers.
-- See trac#14881.
- ppr_possible_field n = case lookupNameEnv fld_env n of
- Just (fld, ParentIs p) -> pprNameUnqualified p <> parens (ppr fld)
- Just (fld, NoParent) -> ppr fld
- Nothing -> pprNameUnqualified n
+ ppr_possible_field n =
+ case lookupGRE_Name rdr_env n of
+ Just (GRE { gre_par = par, gre_info = IAmRecField info }) ->
+ let fld_occ :: OccName
+ fld_occ = nameOccName $ flSelector $ recFieldLabel info
+ in case par of
+ ParentIs p -> pprNameUnqualified p <> parens (ppr fld_occ)
+ NoParent -> ppr fld_occ
+ _ -> pprNameUnqualified n
-- Print unused names in a deterministic (lexicographic) order
sort_unused :: SDoc
@@ -1957,9 +1952,11 @@ decls, and simply trim their import lists. NB that
-}
getMinimalImports :: [ImportDeclUsage] -> RnM [LImportDecl GhcRn]
-getMinimalImports = fmap combine . mapM mk_minimal
+getMinimalImports ie_decls
+ = do { rdr_env <- getGlobalRdrEnv
+ ; fmap combine $ mapM (mk_minimal rdr_env) ie_decls }
where
- mk_minimal (L l decl, used_gres, unused)
+ mk_minimal rdr_env (L l decl, used_gres, unused)
| null unused
, Just (Exactly, _) <- ideclImportList decl
= return (L l decl)
@@ -1969,42 +1966,51 @@ getMinimalImports = fmap combine . mapM mk_minimal
, ideclPkgQual = pkg_qual } = decl
; iface <- loadSrcInterface doc mod_name is_boot pkg_qual
; let used_avails = gresToAvailInfo used_gres
- lies = map (L l) (concatMap (to_ie iface) used_avails)
+ ; lies <- map (L l) <$> concatMapM (to_ie rdr_env iface) used_avails
; return (L l (decl { ideclImportList = Just (Exactly, L (l2l l) lies) })) }
where
doc = text "Compute minimal imports for" <+> ppr decl
- to_ie :: ModIface -> AvailInfo -> [IE GhcRn]
+ to_ie :: GlobalRdrEnv -> ModIface -> AvailInfo -> RnM [IE GhcRn]
-- The main trick here is that if we're importing all the constructors
-- we want to say "T(..)", but if we're importing only a subset we want
-- to say "T(A,B,C)". So we have to find out what the module exports.
- to_ie _ (Avail c) -- Note [Overloaded field import]
- = [IEVar noExtField (to_ie_post_rn $ noLocA (greNamePrintableName c))]
- to_ie _ avail@(AvailTC n [_]) -- Exporting the main decl and nothing else
- | availExportsDecl avail = [IEThingAbs noAnn (to_ie_post_rn $ noLocA n)]
- to_ie iface (AvailTC n cs)
- = case [xs | avail@(AvailTC x xs) <- mi_exports iface
- , x == n
- , availExportsDecl avail -- Note [Partial export]
- ] of
- [xs] | all_used xs ->
- [IEThingAll noAnn (to_ie_post_rn $ noLocA n)]
- | otherwise ->
- [IEThingWith (map noLoc fs) (to_ie_post_rn $ noLocA n) NoIEWildcard
- (map (to_ie_post_rn . noLocA) (filter (/= n) ns))]
- -- Note [Overloaded field import]
- _other | all_non_overloaded fs
- -> map (IEVar noExtField . to_ie_post_rn_var . noLocA) $ ns
- ++ map flSelector fs
- | otherwise ->
- [IEThingWith (map noLoc fs) (to_ie_post_rn $ noLocA n) NoIEWildcard
- (map (to_ie_post_rn . noLocA) (filter (/= n) ns))]
+ to_ie rdr_env _ (Avail c) -- Note [Overloaded field import]
+ = do { let
+ gre = expectJust "getMinimalImports Avail" $ lookupGRE_Name rdr_env c
+ ; return $ [IEVar noExtField (to_ie_post_rn $ noLocA $ greName gre)] }
+ to_ie _ _ avail@(AvailTC n [_]) -- Exporting the main decl and nothing else
+ | availExportsDecl avail
+ = return [IEThingAbs noAnn (to_ie_post_rn $ noLocA n)]
+ to_ie rdr_env iface (AvailTC n cs) =
+ case [ xs | avail@(AvailTC x xs) <- mi_exports iface
+ , x == n
+ , availExportsDecl avail -- Note [Partial export]
+ ] of
+ [xs]
+ | all_used xs
+ -> return [IEThingAll noAnn (to_ie_post_rn $ noLocA n)]
+ | otherwise
+ -> do { let ns_gres = map (expectJust "getMinimalImports AvailTC" . lookupGRE_Name rdr_env) cs
+ ns = map greName ns_gres
+ ; return [IEThingWith noAnn (to_ie_post_rn $ noLocA n) NoIEWildcard
+ (map (to_ie_post_rn . noLocA) (filter (/= n) ns))] }
+ -- Note [Overloaded field import]
+ _other
+ -> do { let infos = map (expectJust "getMinimalImports AvailTC" . lookupGRE_Name rdr_env) cs
+ (ns_gres,fs_gres) = classifyGREs infos
+ ns = map greName (ns_gres ++ fs_gres)
+ fs = map fieldGREInfo fs_gres
+ ; return $
+ if all_non_overloaded fs
+ then map (IEVar noExtField . to_ie_post_rn_var . noLocA) ns
+ else [IEThingWith noAnn (to_ie_post_rn $ noLocA n) NoIEWildcard
+ (map (to_ie_post_rn . noLocA) (filter (/= n) ns))] }
where
- (ns, fs) = partitionGreNames cs
all_used avail_cs = all (`elem` cs) avail_cs
- all_non_overloaded = all (not . flIsOverloaded)
+ all_non_overloaded = all (not . flIsOverloaded . recFieldLabel)
combine :: [LImportDecl GhcRn] -> [LImportDecl GhcRn]
combine = map merge . NE.groupAllWith getKey
@@ -2023,6 +2029,8 @@ getMinimalImports = fmap combine . mapM mk_minimal
merge decls@((L l decl) :| _) = L l (decl { ideclImportList = Just (Exactly, L (noAnnSrcSpan (locA l)) lies) })
where lies = concatMap (unLoc . snd) $ mapMaybe (ideclImportList . unLoc) $ NE.toList decls
+classifyGREs :: [GlobalRdrElt] -> ([GlobalRdrElt], [FieldGlobalRdrElt])
+classifyGREs = partition (not . isRecFldGRE)
printMinimalImports :: HscSource -> [ImportDeclUsage] -> RnM ()
-- See Note [Printing minimal imports]
@@ -2130,13 +2138,10 @@ qualImportItemErr rdr
= hang (text "Illegal qualified name in import item:")
2 (ppr rdr)
-ambiguousImportItemErr :: RdrName -> [AvailInfo] -> SDoc
-ambiguousImportItemErr rdr avails
+ambiguousImportItemErr :: RdrName -> [GlobalRdrElt] -> SDoc
+ambiguousImportItemErr rdr gres
= hang (text "Ambiguous name" <+> quotes (ppr rdr) <+> text "in import item. It could refer to:")
- 2 (vcat (map ppr_avail avails))
- where
- ppr_avail (AvailTC parent _) = ppr parent <> parens (ppr rdr)
- ppr_avail (Avail name) = ppr name
+ 2 (vcat (map (ppr . greOccName) gres))
pprImpDeclSpec :: ModIface -> ImpDeclSpec -> SDoc
pprImpDeclSpec iface decl_spec =
@@ -2181,10 +2186,10 @@ badImportItemErr iface decl_spec ie avails
where
checkIfDataCon (AvailTC _ ns) =
case find (\n -> importedFS == occNameFS (occName n)) ns of
- Just n -> isDataConName (greNameMangledName n)
+ Just n -> isDataConName n
Nothing -> False
checkIfDataCon _ = False
- availOccName = occName . availGreName
+ availOccName = occName . availName
importedFS = occNameFS . rdrNameOcc $ ieName ie
illegalImportItemErr :: SDoc
@@ -2204,9 +2209,7 @@ addDupDeclErr gres@(gre :| _)
where
sorted_names =
NE.sortBy (SrcLoc.leftmost_smallest `on` nameSrcSpan)
- (fmap greMangledName gres)
-
-
+ (fmap greName gres)
missingImportListWarn :: ModuleName -> SDoc
missingImportListWarn mod
diff --git a/compiler/GHC/Rename/Pat.hs b/compiler/GHC/Rename/Pat.hs
index ccfb77fbde..0b01f2cbcb 100644
--- a/compiler/GHC/Rename/Pat.hs
+++ b/compiler/GHC/Rename/Pat.hs
@@ -56,33 +56,35 @@ import GHC.Rename.Utils ( newLocalBndrRn, bindLocalNames
, wrapGenSpan, genHsApps, genLHsVar, genHsIntegralLit, warnForallIdentifier )
import GHC.Rename.HsType
import GHC.Builtin.Names
-import GHC.Types.Avail ( greNameMangledName )
+
import GHC.Types.Error
import GHC.Types.Name
import GHC.Types.Name.Set
import GHC.Types.Name.Reader
+import GHC.Types.Unique.Set
+
import GHC.Types.Basic
import GHC.Types.SourceText
import GHC.Utils.Misc
+import GHC.Data.FastString ( uniqCompareFS )
import GHC.Data.List.SetOps( removeDups )
import GHC.Utils.Outputable
import GHC.Utils.Panic.Plain
import GHC.Types.SrcLoc
import GHC.Types.Literal ( inCharRange )
+import GHC.Types.GREInfo ( ConInfo(..), conInfoFields )
import GHC.Builtin.Types ( nilDataCon )
import GHC.Core.DataCon
-import GHC.Driver.Session ( getDynFlags, xopt_DuplicateRecordFields )
import qualified GHC.LanguageExtensions as LangExt
import Control.Monad ( when, ap, guard, unless )
import Data.Foldable
+import Data.Function ( on )
import Data.Functor.Identity ( Identity (..) )
import qualified Data.List.NonEmpty as NE
import Data.Maybe
import Data.Ratio
-import GHC.Types.FieldLabel (DuplicateRecordFields(..))
-import Language.Haskell.Syntax.Basic (FieldLabelString(..))
-import GHC.Types.ConInfo (ConInfo(..), conInfoFields)
+
{-
*********************************************************
@@ -778,23 +780,24 @@ rnHsRecFields ctxt mk_arg (HsRecFields { rec_flds = flds, rec_dotdot = dotdot })
-> RnM (LHsRecField GhcRn (LocatedA arg))
rn_fld pun_ok parent (L l
(HsFieldBind
- { hfbLHS =
- (L loc (FieldOcc _ (L ll lbl)))
+ { hfbLHS = L loc (FieldOcc _ (L ll lbl))
, hfbRHS = arg
- , hfbPun = pun }))
+ , hfbPun = pun }))
= do { sel <- setSrcSpanA loc $ lookupRecFieldOcc parent lbl
+ ; let arg_rdr = mkRdrUnqual $ recFieldToVarOcc $ occName sel
+ -- Discard any module qualifier (#11662)
; arg' <- if pun
- then do { checkErr pun_ok (TcRnIllegalFieldPunning (L (locA loc) lbl))
- -- Discard any module qualifier (#11662)
- ; let arg_rdr = mkRdrUnqual (rdrNameOcc lbl)
- ; return (L (l2l loc) (mk_arg (locA loc) arg_rdr)) }
+ then do { checkErr pun_ok $
+ TcRnIllegalFieldPunning (L (locA loc) arg_rdr)
+ ; return $ L (l2l loc) $
+ mk_arg (locA loc) arg_rdr }
else return arg
- ; return (L l (HsFieldBind
- { hfbAnn = noAnn
- , hfbLHS = (L loc (FieldOcc sel (L ll lbl)))
- , hfbRHS = arg'
- , hfbPun = pun })) }
-
+ ; return $ L l $
+ HsFieldBind
+ { hfbAnn = noAnn
+ , hfbLHS = L loc (FieldOcc sel (L ll arg_rdr))
+ , hfbRHS = arg'
+ , hfbPun = pun } }
rn_dotdot :: Maybe (Located RecFieldsDotDot) -- See Note [DotDot fields] in GHC.Hs.Pat
-> Maybe Name -- The constructor (Nothing for an
@@ -821,16 +824,16 @@ rnHsRecFields ctxt mk_arg (HsRecFields { rec_flds = flds, rec_dotdot = dotdot })
-- f x = R { .. } -- Should expand to R {x=x}, not R{x=x,y=y}
arg_in_scope lbl = mkRdrUnqual lbl `elemLocalRdrEnv` lcl_env
- (dot_dot_fields, dot_dot_gres)
- = unzip [ (fl, gre)
- | fl <- conInfoFields conInfo
- , let lbl = mkVarOccFS (field_label $ flLabel fl)
- , not (lbl `elemOccSet` present_flds)
- , Just gre <- [lookupGRE_FieldLabel rdr_env fl]
- -- Check selector is in scope
- , case ctxt of
- HsRecFieldCon {} -> arg_in_scope lbl
- _other -> True ]
+ (dot_dot_fields, dot_dot_gres) =
+ unzip [ (fl, gre)
+ | fl <- conInfoFields conInfo
+ , let lbl = recFieldToVarOcc $ occName $ flSelector fl
+ , not (lbl `elemOccSet` present_flds)
+ , Just gre <- [lookupGRE_FieldLabel rdr_env fl]
+ -- Check selector is in scope
+ , case ctxt of
+ HsRecFieldCon {} -> arg_in_scope lbl
+ _other -> True ]
; addUsedGREs dot_dot_gres
; let locn = noAnnSrcSpan loc
@@ -839,10 +842,12 @@ rnHsRecFields ctxt mk_arg (HsRecFields { rec_flds = flds, rec_dotdot = dotdot })
, hfbLHS
= L (noAnnSrcSpan loc) (FieldOcc sel (L (noAnnSrcSpan loc) arg_rdr))
, hfbRHS = L locn (mk_arg loc arg_rdr)
- , hfbPun = False })
+ , hfbPun = False })
| fl <- dot_dot_fields
, let sel = flSelector fl
- , let arg_rdr = mkVarUnqual (field_label $ flLabel fl) ] }
+ arg_rdr = mkRdrUnqual
+ $ recFieldToVarOcc
+ $ nameOccName sel ] }
rn_dotdot _dotdot _mb_con _flds
= return []
@@ -854,67 +859,102 @@ rnHsRecFields ctxt mk_arg (HsRecFields { rec_flds = flds, rec_dotdot = dotdot })
-- Each list represents a RdrName that occurred more than once
-- (the list contains all occurrences)
-- Each list in dup_fields is non-empty
- (_, dup_flds) = removeDups compare (getFieldLbls flds)
-
-
--- NB: Consider this:
--- module Foo where { data R = R { fld :: Int } }
--- module Odd where { import Foo; fld x = x { fld = 3 } }
--- Arguably this should work, because the reference to 'fld' is
--- unambiguous because there is only one field id 'fld' in scope.
--- But currently it's rejected.
+ (_, dup_flds) = removeDups (uniqCompareFS `on` (occNameFS . rdrNameOcc)) (getFieldLbls flds)
+ -- See the same duplicate handling logic in rnHsRecUpdFields below for further context.
+-- | Rename a regular (non-overloaded) record field update,
+-- disambiguating the fields if necessary.
rnHsRecUpdFields
- :: [LHsRecUpdField GhcPs]
- -> RnM ([LHsRecUpdField GhcRn], FreeVars)
+ :: [LHsRecUpdField GhcPs GhcPs]
+ -> RnM (XLHsRecUpdLabels GhcRn, [LHsRecUpdField GhcRn GhcRn], FreeVars)
rnHsRecUpdFields flds
- = do { pun_ok <- xoptM LangExt.NamedFieldPuns
- ; dup_fields_ok <- xopt_DuplicateRecordFields <$> getDynFlags
- ; (flds1, fvss) <- mapAndUnzipM (rn_fld pun_ok dup_fields_ok) flds
- ; mapM_ (addErr . dupFieldErr HsRecFieldUpd) dup_flds
+ = do { pun_ok <- xoptM LangExt.NamedFieldPuns
- -- Check for an empty record update e {}
+ -- Check for an empty record update: e {}
-- NB: don't complain about e { .. }, because rn_dotdot has done that already
- ; when (null flds) $ addErr TcRnEmptyRecordUpdate
-
- ; return (flds1, plusFVs fvss) }
- where
- rn_fld :: Bool -> DuplicateRecordFields -> LHsRecUpdField GhcPs
- -> RnM (LHsRecUpdField GhcRn, FreeVars)
- rn_fld pun_ok dup_fields_ok (L l (HsFieldBind { hfbLHS = L loc f
- , hfbRHS = arg
- , hfbPun = pun }))
- = do { let lbl = rdrNameAmbiguousFieldOcc f
- ; mb_sel <- setSrcSpanA loc $
- -- Defer renaming of overloaded fields to the typechecker
- -- See Note [Disambiguating record fields] in GHC.Tc.Gen.Head
- lookupRecFieldOcc_update dup_fields_ok lbl
- ; arg' <- if pun
- then do { checkErr pun_ok (TcRnIllegalFieldPunning (L (locA loc) lbl))
- -- Discard any module qualifier (#11662)
- ; let arg_rdr = mkRdrUnqual (rdrNameOcc lbl)
- ; return (L (l2l loc) (HsVar noExtField
- (L (l2l loc) arg_rdr))) }
- else return arg
- ; (arg'', fvs) <- rnLExpr arg'
-
- ; let (lbl', fvs') = case mb_sel of
- UnambiguousGre gname -> let sel_name = greNameMangledName gname
- in (Unambiguous sel_name (L (l2l loc) lbl), fvs `addOneFV` sel_name)
- AmbiguousFields -> (Ambiguous noExtField (L (l2l loc) lbl), fvs)
-
- ; return (L l (HsFieldBind { hfbAnn = noAnn
- , hfbLHS = L loc lbl'
- , hfbRHS = arg''
- , hfbPun = pun }), fvs') }
-
- dup_flds :: [NE.NonEmpty RdrName]
- -- Each list represents a RdrName that occurred more than once
- -- (the list contains all occurrences)
- -- Each list in dup_fields is non-empty
- (_, dup_flds) = removeDups compare (getFieldUpdLbls flds)
-
-
+ ; case flds of
+ { [] -> failWithTc TcRnEmptyRecordUpdate
+ ; fld:other_flds ->
+ do { let dup_lbls :: [NE.NonEmpty RdrName]
+ (_, dup_lbls) = removeDups (uniqCompareFS `on` (occNameFS . rdrNameOcc))
+ (fmap (unLoc . getFieldUpdLbl) flds)
+ -- NB: we compare using the underlying field label FastString,
+ -- in order to catch duplicates involving qualified names,
+ -- as in the record update `r { fld = x, Mod.fld = y }`.
+ -- See #21959.
+ -- Note that this test doesn't correctly handle exact Names, but those
+ -- aren't handled properly by the rest of the compiler anyway. See #22122.
+ ; mapM_ (addErr . dupFieldErr HsRecFieldUpd) dup_lbls
+
+ -- See Note [Disambiguating record updates]
+ ; possible_parents <- lookupRecUpdFields (fld NE.:| other_flds)
+ ; let mb_unambig_lbls :: Maybe [FieldLabel]
+ fvs :: FreeVars
+ (mb_unambig_lbls, fvs) =
+ case possible_parents of
+ RnRecUpdParent { rnRecUpdLabels = gres } NE.:| []
+ | let lbls = map fieldGRELabel $ NE.toList gres
+ -> ( Just lbls, mkFVs $ map flSelector lbls)
+ _ -> ( Nothing
+ , plusFVs $ map (plusFVs . map pat_syn_free_vars . NE.toList . rnRecUpdLabels)
+ $ NE.toList possible_parents
+ -- See Note [Using PatSyn FreeVars]
+ )
+
+ -- Rename each field.
+ ; (upd_flds, fvs') <- rn_flds pun_ok mb_unambig_lbls flds
+ ; let all_fvs = fvs `plusFV` fvs'
+ ; return (possible_parents, upd_flds, all_fvs) } } }
+
+ where
+
+ -- For an ambiguous record update involving pattern synonym record fields,
+ -- we must add all the possibly-relevant field selector names to ensure that
+ -- we typecheck the record update **after** we typecheck the pattern synonym
+ -- definition. See Note [Using PatSyn FreeVars].
+ pat_syn_free_vars :: FieldGlobalRdrElt -> FreeVars
+ pat_syn_free_vars (GRE { gre_info = info })
+ | IAmRecField fld_info <- info
+ , RecFieldInfo { recFieldLabel = fl, recFieldCons = cons } <- fld_info
+ , uniqSetAny is_PS cons
+ = unitFV (flSelector fl)
+ pat_syn_free_vars _
+ = emptyFVs
+
+ is_PS :: ConLikeName -> Bool
+ is_PS (PatSynName {}) = True
+ is_PS (DataConName {}) = False
+
+ rn_flds :: Bool -> Maybe [FieldLabel]
+ -> [LHsRecUpdField GhcPs GhcPs]
+ -> RnM ([LHsRecUpdField GhcRn GhcRn], FreeVars)
+ rn_flds _ _ [] = return ([], emptyFVs)
+ rn_flds pun_ok mb_unambig_lbls
+ ((L l (HsFieldBind { hfbLHS = L loc f
+ , hfbRHS = arg
+ , hfbPun = pun })):flds)
+ = do { let lbl = ambiguousFieldOccRdrName f
+ ; (arg' :: LHsExpr GhcPs) <- if pun
+ then do { setSrcSpanA loc $
+ checkErr pun_ok (TcRnIllegalFieldPunning (L (locA loc) lbl))
+ -- Discard any module qualifier (#11662)
+ ; let arg_rdr = mkRdrUnqual (rdrNameOcc lbl)
+ ; return (L (l2l loc) (HsVar noExtField (L (l2l loc) arg_rdr))) }
+ else return arg
+ ; (arg'', fvs) <- rnLExpr arg'
+ ; let lbl' :: AmbiguousFieldOcc GhcRn
+ lbl' = case mb_unambig_lbls of
+ { Just (fl:_) ->
+ let sel_name = flSelector fl
+ in Unambiguous sel_name (L (l2l loc) lbl)
+ ; _ -> Ambiguous noExtField (L (l2l loc) lbl) }
+ fld' :: LHsRecUpdField GhcRn GhcRn
+ fld' = L l (HsFieldBind { hfbAnn = noAnn
+ , hfbLHS = L loc lbl'
+ , hfbRHS = arg''
+ , hfbPun = pun })
+ ; (flds', fvs') <- rn_flds pun_ok (tail <$> mb_unambig_lbls) flds
+ ; return (fld' : flds', fvs `plusFV` fvs') }
getFieldIds :: [LHsRecField GhcRn arg] -> [Name]
getFieldIds flds = map (hsRecFieldSel . unLoc) flds
@@ -923,9 +963,6 @@ getFieldLbls :: forall p arg . UnXRec p => [LHsRecField p arg] -> [RdrName]
getFieldLbls flds
= map (unXRec @p . foLabel . unXRec @p . hfbLHS . unXRec @p) flds
-getFieldUpdLbls :: [LHsRecUpdField GhcPs] -> [RdrName]
-getFieldUpdLbls flds = map (rdrNameAmbiguousFieldOcc . unLoc . hfbLHS . unLoc) flds
-
needFlagDotDot :: HsRecFieldContext -> TcRnMessage
needFlagDotDot = TcRnIllegalWildcardsInRecord . toRecordFieldPart
@@ -937,7 +974,59 @@ toRecordFieldPart (HsRecFieldCon n) = RecordFieldConstructor n
toRecordFieldPart (HsRecFieldPat n) = RecordFieldPattern n
toRecordFieldPart (HsRecFieldUpd {}) = RecordFieldUpdate
-{-
+{- Note [Disambiguating record updates]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+When the -XDuplicateRecordFields extension is used, to rename and typecheck
+a non-overloaded record update, we might need to disambiguate the field labels.
+
+Consider the following definitions:
+
+ {-# LANGUAGE DuplicateRecordFields #-}
+
+ data R = MkR1 { fld1 :: Int, fld2 :: Char }
+ | MKR2 { fld1 :: Int, fld2 :: Char, fld3 :: Bool }
+ data S = MkS1 { fld1 :: Int } | MkS2 { fld2 :: Char }
+
+In a record update, the `lookupRecUpdFields` function tries to determine
+the parent datatype by computing the parents (TyCon/PatSyn) which have
+at least one constructor (DataCon/PatSyn) with all of the fields.
+
+For example, in the (non-overloaded) record update
+
+ r { fld1 = 3, fld2 = 'x' }
+
+only the TyCon R contains at least one DataCon which has both of the fields
+being updated: in this case, MkR1 and MkR2 have both of the updated fields.
+The TyCon S also has both fields fld1 and fld2, but no single constructor
+has both of those fields, so S is not a valid parent for this record update.
+
+Note that this check is namespace-aware, so that a record update such as
+
+ import qualified M ( R (fld1, fld2) )
+ f r = r { M.fld1 = 3 }
+
+is unambiguous, as only R contains the field fld1 in the M namespace.
+(See however #22122 for issues relating to the usage of exact Names in
+record fields.)
+
+See also Note [Type-directed record disambiguation] in GHC.Tc.Gen.Expr.
+
+Note [Using PatSyn FreeVars]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+When we are disambiguating a non-overloaded record update, as per
+Note [Disambiguating record updates], and have determined that this
+record update might involve pattern synonym record fields, it is important
+to declare usage of all these pattern synonyms record fields in the returned
+FreeVars of rnHsRecUpdFields. This ensures that the typechecker sees
+that the typechecking of the record update depends on the typechecking
+of the pattern synonym, and typechecks the pattern synonyms first.
+Not doing so caused #21898.
+
+Note that this can be removed once GHC proposal #366 is implemented,
+as we will be able to fully disambiguate the record update in the renamer,
+and can immediately declare the correct used FreeVars instead of having
+to over-estimate in case of ambiguity.
+
************************************************************************
* *
\subsubsection{Literals}
diff --git a/compiler/GHC/Rename/Splice.hs b/compiler/GHC/Rename/Splice.hs
index ff52727716..d8566ec747 100644
--- a/compiler/GHC/Rename/Splice.hs
+++ b/compiler/GHC/Rename/Splice.hs
@@ -474,8 +474,9 @@ rnTypedSplice expr
; traceRn "rnTypedSplice: typed expression splice" empty
; lcl_rdr <- getLocalRdrEnv
; gbl_rdr <- getGlobalRdrEnv
- ; let gbl_names = mkNameSet [greMangledName gre | gre <- globalRdrEnvElts gbl_rdr
- , isLocalGRE gre]
+ ; let gbl_names = mkNameSet [ greName gre
+ | gre <- globalRdrEnvElts gbl_rdr
+ , isLocalGRE gre]
lcl_names = mkNameSet (localRdrEnvElts lcl_rdr)
fvs2 = lcl_names `plusFV` gbl_names
diff --git a/compiler/GHC/Rename/Unbound.hs b/compiler/GHC/Rename/Unbound.hs
index c8e77b9e87..ee9f2c82b8 100644
--- a/compiler/GHC/Rename/Unbound.hs
+++ b/compiler/GHC/Rename/Unbound.hs
@@ -9,6 +9,8 @@ unbound variables.
module GHC.Rename.Unbound
( mkUnboundName
, mkUnboundNameRdr
+ , mkUnboundGRE
+ , mkUnboundGRERdr
, isUnboundName
, reportUnboundName
, reportUnboundName'
@@ -102,6 +104,12 @@ data IsTermInTypes = UnknownTermInTypes RdrName | TermInTypes RdrName | NoTermIn
mkUnboundNameRdr :: RdrName -> Name
mkUnboundNameRdr rdr = mkUnboundName (rdrNameOcc rdr)
+mkUnboundGRE :: OccName -> GlobalRdrElt
+mkUnboundGRE occ = localVanillaGRE NoParent $ mkUnboundName occ
+
+mkUnboundGRERdr :: RdrName -> GlobalRdrElt
+mkUnboundGRERdr rdr = localVanillaGRE NoParent $ mkUnboundNameRdr rdr
+
reportUnboundName' :: WhatLooking -> RdrName -> RnM Name
reportUnboundName' what_look rdr = unboundName (LF what_look WL_Anywhere) rdr
@@ -165,11 +173,17 @@ notInScopeErr where_look rdr_name
= NotInScope
-- | Called from the typechecker ("GHC.Tc.Errors") when we find an unbound variable
-unknownNameSuggestions :: WhatLooking -> DynFlags
- -> HomePackageTable -> Module
- -> GlobalRdrEnv -> LocalRdrEnv -> ImportAvails
- -> RdrName -> ([ImportError], [GhcHint])
-unknownNameSuggestions what_look = unknownNameSuggestions_ (LF what_look WL_Anywhere)
+unknownNameSuggestions :: LocalRdrEnv -> WhatLooking -> RdrName -> RnM ([ImportError], [GhcHint])
+unknownNameSuggestions lcl_env what_look tried_rdr_name =
+ do { dflags <- getDynFlags
+ ; hpt <- getHpt
+ ; rdr_env <- getGlobalRdrEnv
+ ; imp_info <- getImports
+ ; curr_mod <- getModule
+ ; return $
+ unknownNameSuggestions_
+ (LF what_look WL_Anywhere)
+ dflags hpt curr_mod rdr_env lcl_env imp_info tried_rdr_name }
unknownNameSuggestions_ :: LookingFor -> DynFlags
-> HomePackageTable -> Module
@@ -197,8 +211,8 @@ fieldSelectorSuggestions global_env tried_rdr_name
| null gres = []
| otherwise = [RemindFieldSelectorSuppressed tried_rdr_name parents]
where
- gres = filter isNoFieldSelectorGRE $
- lookupGRE_RdrName' tried_rdr_name global_env
+ gres = filter isNoFieldSelectorGRE
+ $ lookupGRE_RdrName (IncludeFields WantField) global_env tried_rdr_name
parents = [ parent | ParentIs parent <- map gre_par gres ]
similarNameSuggestions :: LookingFor -> DynFlags
@@ -341,7 +355,7 @@ importSuggestions looking_for global_env hpt currMod imports rdr_name
helpful_imports = filter helpful interesting_imports
where helpful (_,imv)
= any (isGreOk looking_for) $
- lookupGlobalRdrEnv (imv_all_exports imv) occ_name
+ lookupGRE_OccName (AllNameSpaces WantNormal) (imv_all_exports imv) occ_name
-- Which of these do that because of an explicit hiding list resp. an
-- explicit import list
@@ -359,9 +373,9 @@ importSuggestions looking_for global_env hpt currMod imports rdr_name
hpt_uniques = map fst (udfmToList hpt)
is_last_loaded_mod modnam uniqs = lastMaybe uniqs == Just (getUnique modnam)
glob_mods = nub [ mod
- | gre <- globalRdrEnvElts global_env
- , (mod, _) <- qualsInScope gre
- ]
+ | gre <- globalRdrEnvElts global_env
+ , (mod, _) <- qualsInScope gre
+ ]
extensionSuggestions :: RdrName -> [GhcHint]
extensionSuggestions rdrName
@@ -403,12 +417,15 @@ nameSpacesRelated :: DynFlags -- ^ to find out whether -XDataKinds is enabled
-> NameSpace -- ^ Name space of a name that might have been meant
-> Bool
nameSpacesRelated dflags what_looking ns ns'
- = ns' `elem` ns : [ other_ns
- | (orig_ns, others) <- other_namespaces
- , ns == orig_ns
- , (other_ns, wls) <- others
- , what_looking `elem` WL_Anything : wls
- ]
+ | ns == ns'
+ = True
+ | otherwise
+ = or [ other_ns ns'
+ | (orig_ns, others) <- other_namespaces
+ , orig_ns ns
+ , (other_ns, wls) <- others
+ , what_looking `elem` WL_Anything : wls
+ ]
where
-- explanation:
-- [(orig_ns, [(other_ns, what_looking_possibilities)])]
@@ -416,19 +433,21 @@ nameSpacesRelated dflags what_looking ns ns'
-- and what_looking is either WL_Anything or is one of
-- what_looking_possibilities
other_namespaces =
- [ (varName , [(dataName, [WL_Constructor])])
- , (dataName , [(varName , [WL_RecField])])
- , (tvName , (tcClsName, [WL_Constructor]) : promoted_datacons)
- , (tcClsName, (tvName , []) : promoted_datacons)
+ [ (isVarNameSpace , [(isFieldNameSpace , [WL_RecField])
+ ,(isDataConNameSpace, [WL_Constructor])])
+ , (isDataConNameSpace , [(isVarNameSpace , [WL_RecField])])
+ , (isTvNameSpace , (isTcClsNameSpace , [WL_Constructor])
+ : promoted_datacons)
+ , (isTcClsNameSpace , (isTvNameSpace , [])
+ : promoted_datacons)
]
-- If -XDataKinds is enabled, the data constructor name space is also
-- related to the type-level name spaces
data_kinds = xopt LangExt.DataKinds dflags
- promoted_datacons = [(dataName, [WL_Constructor]) | data_kinds]
+ promoted_datacons = [(isDataConNameSpace, [WL_Constructor]) | data_kinds]
-{-
-Note [Related name spaces]
-~~~~~~~~~~~~~~~~~~~~~~~~~
+{- Note [Related name spaces]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Name spaces are related if there is a chance to mean the one when one writes
the other, i.e. variables <-> data constructors and type variables <-> type
constructors.
diff --git a/compiler/GHC/Rename/Utils.hs b/compiler/GHC/Rename/Utils.hs
index 91f79af520..4992ebf309 100644
--- a/compiler/GHC/Rename/Utils.hs
+++ b/compiler/GHC/Rename/Utils.hs
@@ -17,7 +17,6 @@ module GHC.Rename.Utils (
warnUnusedTopBinds, warnUnusedLocalBinds,
warnForallIdentifier,
checkUnusedRecordWildcard,
- mkFieldEnv,
badQualBndrErr, typeAppErr, badFieldConErr,
wrapGenSpan, genHsVar, genLHsVar, genHsApp, genHsApps, genAppType,
genHsIntegralLit, genHsTyLit, genSimpleConPat,
@@ -28,7 +27,7 @@ module GHC.Rename.Utils (
bindLocalNames, bindLocalNamesFV,
- addNameClashErrRn,
+ addNameClashErrRn, mkNameClashErr,
checkInferredVars,
noNestedForallsContextsErr, addNoNestedForallsContextsErr
@@ -171,7 +170,7 @@ checkShadowedOccs (global_env,local_env) get_loc_occ ns
where
(loc,occ) = get_loc_occ n
mb_local = lookupLocalRdrOcc local_env occ
- gres = lookupGRE_RdrName (mkRdrUnqual occ) global_env
+ gres = lookupGRE_RdrName (AllNameSpaces WantBoth) global_env (mkRdrUnqual occ)
-- Make an Unqualified RdrName and look that up, so that
-- we don't find any GREs that are in scope qualified-only
@@ -450,13 +449,13 @@ warnUnusedGREs gres = mapM_ warnUnusedGRE gres
-- NB the Names must not be the names of record fields!
warnUnused :: WarningFlag -> [Name] -> RnM ()
warnUnused flag names =
- mapM_ (warnUnused1 flag . NormalGreName) names
+ mapM_ (\ nm -> warnUnused1 flag nm (nameOccName nm)) names
-warnUnused1 :: WarningFlag -> GreName -> RnM ()
-warnUnused1 flag child
- = when (reportable child) $
+warnUnused1 :: WarningFlag -> Name -> OccName -> RnM ()
+warnUnused1 flag child child_occ
+ = when (reportable child child_occ) $
addUnusedWarning flag
- (occName child) (greNameSrcSpan child)
+ child_occ (nameSrcSpan child)
(text $ "Defined but not used" ++ opt_str)
where
opt_str = case flag of
@@ -465,35 +464,28 @@ warnUnused1 flag child
warnUnusedGRE :: GlobalRdrElt -> RnM ()
warnUnusedGRE gre@(GRE { gre_lcl = lcl, gre_imp = is })
- | lcl = warnUnused1 Opt_WarnUnusedTopBinds (gre_name gre)
- | otherwise = when (reportable (gre_name gre)) (mapM_ warn is)
+ | lcl = warnUnused1 Opt_WarnUnusedTopBinds 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"
--- | Make a map from selector names to field labels and parent tycon
--- names, to be used when reporting unused record fields.
-mkFieldEnv :: GlobalRdrEnv -> NameEnv (FieldLabelString, Parent)
-mkFieldEnv rdr_env = mkNameEnv [ (greMangledName gre, (flLabel fl, gre_par gre))
- | gres <- nonDetOccEnvElts rdr_env
- , gre <- gres
- , Just fl <- [greFieldLabel gre]
- ]
-
-- | Should we report the fact that this 'Name' is unused? The
-- 'OccName' may differ from 'nameOccName' due to
-- DuplicateRecordFields.
-reportable :: GreName -> Bool
-reportable child
- | NormalGreName name <- child
- , isWiredInName name = False -- Don't report unused wired-in names
- -- Otherwise we get a zillion warnings
- -- from Data.Tuple
- | otherwise = not (startsWithUnderscore (occName child))
+reportable :: Name -> OccName -> Bool
+reportable child child_occ
+ | isWiredInName child
+ = False -- Don't report unused wired-in names
+ -- Otherwise we get a zillion warnings
+ -- from Data.Tuple
+ | otherwise
+ = not (startsWithUnderscore child_occ)
addUnusedWarning :: WarningFlag -> OccName -> SrcSpan -> SDoc -> RnM ()
addUnusedWarning flag occ span msg = do
@@ -555,7 +547,23 @@ addNameClashErrRn rdr_name gres
-- already, and we don't want an error cascade.
= return ()
| otherwise
- = addErr $ mkTcRnUnknownMessage $ mkPlainError noHints $
+ = addErr $ mkNameClashErr rdr_name gres
+ where
+ -- If all the GREs are defined locally, can we skip reporting an ambiguity
+ -- error at use sites, because it will have been reported already? See
+ -- Note [Skipping ambiguity errors at use sites of local declarations]
+ can_skip = num_non_flds >= 2
+ || (num_flds >= 2 && not (isDuplicateRecFldGRE (head flds)))
+ || (num_non_flds >= 1 && num_flds >= 1
+ && not (isNoFieldSelectorGRE (head flds)))
+ (flds, non_flds) = NE.partition isRecFldGRE 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)) ])
@@ -563,7 +571,7 @@ addNameClashErrRn rdr_name gres
np1 NE.:| nps = gres
msg1 = text "either" <+> ppr_gre np1
msgs = [text " or" <+> ppr_gre np | np <- nps]
- ppr_gre gre = sep [ pp_greMangledName gre <> comma
+ ppr_gre gre = sep [ pp_gre_name gre <> comma
, pprNameProvenance gre]
-- When printing the name, take care to qualify it in the same
@@ -574,36 +582,27 @@ addNameClashErrRn rdr_name gres
-- imported from ‘Prelude’ at T15487.hs:1:8-13
-- or ...
-- See #15487
- pp_greMangledName gre@(GRE { gre_name = child, gre_par = par
- , gre_lcl = lcl, gre_imp = iss }) =
- case child of
- FieldGreName fl -> text "the field" <+> quotes (ppr fl) <+> parent_info
- NormalGreName name -> quotes (pp_qual name <> dot <> ppr (nameOccName name))
+ pp_gre_name gre
+ | isRecFldGRE gre
+ = text "the field" <+> quotes (ppr occ) <+> parent_info
+ | otherwise
+ = quotes (pp_qual <> dot <> ppr occ)
where
- parent_info = case par of
+ 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 name
- | lcl
- = ppr (nameModule name)
- | Just imp <- headMaybe iss -- This 'imp' is the one that
- -- pprNameProvenance chooses
- , ImpDeclSpec { is_as = mod } <- is_decl imp
- = ppr mod
- | otherwise
- = pprPanic "addNameClassErrRn" (ppr gre $$ ppr iss)
- -- Invariant: either 'lcl' is True or 'iss' is non-empty
-
- -- If all the GREs are defined locally, can we skip reporting an ambiguity
- -- error at use sites, because it will have been reported already? See
- -- Note [Skipping ambiguity errors at use sites of local declarations]
- can_skip = num_non_flds >= 2
- || (num_flds >= 2 && not (isDuplicateRecFldGRE (head flds)))
- || (num_non_flds >= 1 && num_flds >= 1
- && not (isNoFieldSelectorGRE (head flds)))
- (flds, non_flds) = NE.partition isRecFldGRE gres
- num_flds = length flds
- num_non_flds = length non_flds
+ 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 ()
diff --git a/compiler/GHC/Runtime/Context.hs b/compiler/GHC/Runtime/Context.hs
index 388ae69aea..929b2ca6e9 100644
--- a/compiler/GHC/Runtime/Context.hs
+++ b/compiler/GHC/Runtime/Context.hs
@@ -8,6 +8,7 @@ module GHC.Runtime.Context
, substInteractiveContext
, replaceImportEnv
, icReaderEnv
+ , icExtendGblRdrEnv
, icInteractiveModule
, icInScopeTTs
, icNamePprCtx
@@ -30,7 +31,6 @@ import GHC.Core.FamInstEnv
import GHC.Core.InstEnv
import GHC.Core.Type
-import GHC.Types.Avail
import GHC.Types.Fixity.Env
import GHC.Types.Id.Info ( IdDetails(..) )
import GHC.Types.Name
@@ -94,7 +94,7 @@ The details are a bit tricky though:
call to initTc in initTcInteractive, which in turn get the module
from it 'icInteractiveModule' field of the interactive context.
- The 'homeUnitId' field stays as 'main' (or whatever -this-unit-id says.
+ The 'homeUnitId' field stays as 'main' (or whatever -this-unit-id says).
* The main trickiness is that the type environment (tcg_type_env) and
fixity envt (tcg_fix_env), now contain entities from all the
@@ -185,9 +185,12 @@ It's exactly the same for type-family instances. See #7102
Note [icReaderEnv recalculation]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The GlobalRdrEnv describing what’s in scope at the prompts consists
-of all the imported things, followed by all the things defined on the prompt, with
-shadowing. Defining new things on the prompt is easy: we shadow as needed and then extend the environment. But changing the set of imports, which can happen later as well,
-is tricky: we need to re-apply the shadowing from all the things defined at the prompt!
+of all the imported things, followed by all the things defined on the prompt,
+with shadowing. Defining new things on the prompt is easy: we shadow as needed,
+and then extend the environment.
+
+But changing the set of imports, which can happen later as well, is tricky
+we need to re-apply the shadowing from all the things defined at the prompt!
For example:
@@ -196,22 +199,21 @@ For example:
ghci> empty -- Still gets the 'empty' defined at the prompt
True
-
-It would be correct ot re-construct the env from scratch based on
+It would be correct to re-construct the env from scratch based on
`ic_tythings`, but that'd be quite expensive if there are many entries in
`ic_tythings` that shadow each other.
-Therefore we keep around a that `GlobalRdrEnv` in `igre_prompt_env` that
-contians _just_ the things defined at the prompt, and use that in
-`replaceImportEnv` to rebuild the full env. Conveniently, `shadowNames` takes
-such an `OccEnv` to denote the set of names to shadow.
+Therefore we keep around a `GlobalRdrEnv` in `igre_prompt_env` that contains
+_just_ the things defined at the prompt, and use that in `replaceImportEnv` to
+rebuild the full env. Conveniently, `shadowNames` takes such an `OccEnv`
+to denote the set of names to shadow.
INVARIANT: Every `OccName` in `igre_prompt_env` is present unqualified as well
-(else it would not be right to use pass `igre_prompt_env` to `shadowNames`.)
+(else it would not be right to pass `igre_prompt_env` to `shadowNames`.)
+
+The definition of the IcGlobalRdrEnv type should conceptually be in this module,
+and made abstract, but it’s used in `Resume`, so it lives in GHC.Runtime.Eval.Type.
-The definition of the IcGlobalRdrEnv type should conceptually be in this module, and
-made abstract, but it’s used in `Resume`, so it lives in GHC.Runtime.Eval.Type.
--
-}
-- | Interactive context, recording information about the state of the
@@ -343,12 +345,11 @@ icInScopeTTs ictxt = filter in_scope_unqualified (ic_tythings ictxt)
where
in_scope_unqualified thing = or
[ unQualOK gre
- | avail <- tyThingAvailInfo thing
- , name <- availNames avail
+ | gre <- tyThingLocalGREs thing
+ , let name = greName gre
, Just gre <- [lookupGRE_Name (icReaderEnv ictxt) name]
]
-
-- | Get the NamePprCtx function based on the flags and this InteractiveContext
icNamePprCtx :: UnitEnv -> InteractiveContext -> NamePprCtx
icNamePprCtx unit_env ictxt = mkNamePprCtx ptc unit_env (icReaderEnv ictxt)
@@ -412,8 +413,8 @@ replaceImportEnv igre import_env = igre { igre_env = new_env }
import_env_shadowed = import_env `shadowNames` igre_prompt_env igre
new_env = import_env_shadowed `plusGlobalRdrEnv` igre_prompt_env igre
--- | Add TyThings to the GlobalRdrEnv, earlier ones in the list shadowing
--- later ones, and shadowing existing entries in the GlobalRdrEnv.
+-- | Add 'TyThings' to the 'GlobalRdrEnv', earlier ones in the list shadowing
+-- later ones, and shadowing existing entries in the 'GlobalRdrEnv'.
icExtendGblRdrEnv :: GlobalRdrEnv -> [TyThing] -> GlobalRdrEnv
icExtendGblRdrEnv env tythings
= foldr add env tythings -- Foldr makes things in the front of
@@ -424,12 +425,10 @@ icExtendGblRdrEnv env tythings
| is_sub_bndr thing
= env
| otherwise
- = foldl' extendGlobalRdrEnv env1 (concatMap localGREsFromAvail avail)
+ = foldl' extendGlobalRdrEnv env1 new_gres
where
- new_gres = concatMap availGreNames avail
- new_occs = occSetToEnv (mkOccSet (map occName new_gres))
- env1 = shadowNames env new_occs
- avail = tyThingAvailInfo thing
+ new_gres = tyThingLocalGREs thing
+ env1 = shadowNames env $ mkGlobalRdrEnv new_gres
-- Ugh! The new_tythings may include record selectors, since they
-- are not implicit-ids, and must appear in the TypeEnv. But they
diff --git a/compiler/GHC/Runtime/Eval.hs b/compiler/GHC/Runtime/Eval.hs
index b6cf935b7e..88dbe46626 100644
--- a/compiler/GHC/Runtime/Eval.hs
+++ b/compiler/GHC/Runtime/Eval.hs
@@ -66,12 +66,13 @@ import GHC.Linker.Loader as Loader
import GHC.Hs
-import GHC.Core.Predicate
-import GHC.Core.InstEnv
+import GHC.Core.Class (classTyCon)
import GHC.Core.FamInstEnv ( FamInst, orphNamesOfFamInst )
+import GHC.Core.InstEnv
+import GHC.Core.Predicate
+import GHC.Core.TyCo.Ppr
import GHC.Core.TyCon
import GHC.Core.Type hiding( typeKind )
-import GHC.Core.TyCo.Ppr
import qualified GHC.Core.Type as Type
import GHC.Iface.Env ( newInteractiveBinder )
@@ -85,12 +86,13 @@ import GHC.Data.Maybe
import GHC.Data.FastString
import GHC.Data.Bag
-import GHC.Utils.Monad
-import GHC.Utils.Panic
import GHC.Utils.Error
-import GHC.Utils.Outputable
-import GHC.Utils.Misc
+import GHC.Utils.Exception
import GHC.Utils.Logger
+import GHC.Utils.Misc
+import GHC.Utils.Monad
+import GHC.Utils.Outputable
+import GHC.Utils.Panic
import GHC.Types.RepType
import GHC.Types.Fixity.Env
@@ -114,29 +116,27 @@ import GHC.Unit.Module.ModIface
import GHC.Unit.Module.ModSummary
import GHC.Unit.Home.ModInfo
-import System.Directory
-import Data.Dynamic
-import Data.Either
-import Data.IntMap (IntMap)
-import qualified Data.IntMap as IntMap
-import Data.List (find,intercalate)
-import Data.List.NonEmpty (NonEmpty)
-import Control.Monad
-import Control.Monad.Catch as MC
-import Data.Array
-import GHC.Utils.Exception
-import Unsafe.Coerce ( unsafeCoerce )
-
import GHC.Tc.Module ( runTcInteractive, tcRnType, loadUnqualIfaces )
import GHC.Tc.Utils.Zonk ( ZonkFlexi (SkolemiseFlexi) )
-import GHC.Tc.Utils.Env (tcGetInstEnvs)
+import GHC.Tc.Utils.Env (tcGetInstEnvs, lookupGlobal)
import GHC.Tc.Utils.Instantiate (instDFunType)
import GHC.Tc.Solver (simplifyWantedsTcM)
import GHC.Tc.Utils.Monad
-import GHC.Core.Class (classTyCon)
import GHC.Unit.Env
import GHC.IfaceToCore
+import Control.Monad
+import Control.Monad.Catch as MC
+import Data.Array
+import Data.Dynamic
+import Data.Either
+import Data.IntMap (IntMap)
+import qualified Data.IntMap as IntMap
+import Data.List (find,intercalate)
+import Data.List.NonEmpty (NonEmpty)
+import System.Directory
+import Unsafe.Coerce ( unsafeCoerce )
+
-- -----------------------------------------------------------------------------
-- running a statement interactively
@@ -819,8 +819,14 @@ findGlobalRdrEnv hsc_env imports
= do { idecls_env <- hscRnImportDecls hsc_env idecls
-- This call also loads any orphan modules
; return $ case partitionEithers (map mkEnv imods) of
- ([], imods_env) -> Right (foldr plusGlobalRdrEnv idecls_env imods_env)
- (err : _, _) -> Left err }
+ (err : _, _) -> Left err
+ ([], imods_env0) ->
+ -- Need to rehydrate the 'GlobalRdrEnv' to recover the 'GREInfo's.
+ -- This is done in order to avoid space leaks.
+ -- See Note [Forcing GREInfo] in GHC.Types.GREInfo.
+ let imods_env = map (hydrateGlobalRdrEnv get_GRE_info) imods_env0
+ in Right (foldr plusGlobalRdrEnv idecls_env imods_env)
+ }
where
idecls :: [LImportDecl GhcPs]
idecls = [noLocA d | IIDecl d <- imports]
@@ -832,7 +838,9 @@ findGlobalRdrEnv hsc_env imports
Left err -> Left (mod, err)
Right env -> Right env
-mkTopLevEnv :: HomePackageTable -> ModuleName -> Either String GlobalRdrEnv
+ get_GRE_info nm = tyThingGREInfo <$> lookupGlobal hsc_env nm
+
+mkTopLevEnv :: HomePackageTable -> ModuleName -> Either String IfGlobalRdrEnv
mkTopLevEnv hpt modl
= case lookupHpt hpt modl of
Nothing -> Left "not a home module"
@@ -840,6 +848,9 @@ mkTopLevEnv hpt modl
case mi_globals (hm_iface details) of
Nothing -> Left "not interpreted"
Just env -> Right env
+ -- It's OK to be lazy here; we force the GlobalRdrEnv before storing it
+ -- in ModInfo; see GHCi.UI.Info.
+ -- See Note [Forcing GREInfo] in GHC.Types.GREInfo.
-- | Get the interactive evaluation context, consisting of a pair of the
-- set of modules from which we take the full top-level scope, and the set
@@ -895,7 +906,7 @@ getInfo allInfo name
-- | Returns all names in scope in the current interactive context
getNamesInScope :: GhcMonad m => m [Name]
getNamesInScope = withSession $ \hsc_env ->
- return (map greMangledName (globalRdrEnvElts (icReaderEnv (hsc_IC hsc_env))))
+ return $ map greName $ globalRdrEnvElts (icReaderEnv (hsc_IC hsc_env))
-- | Returns all 'RdrName's in scope in the current interactive
-- context, excluding any that are internally-generated.
diff --git a/compiler/GHC/Runtime/Loader.hs b/compiler/GHC/Runtime/Loader.hs
index b59071d5f6..ebfa7875e5 100644
--- a/compiler/GHC/Runtime/Loader.hs
+++ b/compiler/GHC/Runtime/Loader.hs
@@ -33,9 +33,10 @@ import GHC.Linker.Loader ( loadModule, loadName )
import GHC.Runtime.Interpreter ( wormhole )
import GHC.Runtime.Interpreter.Types
+import GHC.Rename.Names ( gresFromAvails )
+
import GHC.Tc.Utils.Monad ( initTcInteractive, initIfaceTcRn )
import GHC.Iface.Load ( loadPluginInterface, cannotFindModule )
-import GHC.Rename.Names ( gresFromAvails )
import GHC.Builtin.Names ( pluginTyConName, frontendPluginTyConName )
import GHC.Driver.Env
@@ -49,10 +50,7 @@ import GHC.Types.Name ( Name, nameModule_maybe )
import GHC.Types.Id ( idType )
import GHC.Types.TyThing
import GHC.Types.Name.Occurrence ( OccName, mkVarOccFS )
-import GHC.Types.Name.Reader ( RdrName, ImportSpec(..), ImpDeclSpec(..)
- , ImpItemSpec(..), mkGlobalRdrEnv, lookupGRE_RdrName
- , greMangledName, mkRdrQual )
-
+import GHC.Types.Name.Reader
import GHC.Unit.Finder ( findPluginModule, FindResult(..) )
import GHC.Driver.Config.Finder ( initFinderOpts )
import GHC.Unit.Module ( Module, ModuleName )
@@ -61,6 +59,7 @@ import GHC.Unit.Env
import GHC.Utils.Panic
import GHC.Utils.Logger
+import GHC.Utils.Misc ( HasDebugCallStack )
import GHC.Utils.Error
import GHC.Utils.Outputable
import GHC.Utils.Exception
@@ -298,7 +297,8 @@ lessUnsafeCoerce logger context what = do
-- being compiled. This was introduced by 57d6798.
--
-- Need the module as well to record information in the interface file
-lookupRdrNameInModuleForPlugins :: HscEnv -> ModuleName -> RdrName
+lookupRdrNameInModuleForPlugins :: HasDebugCallStack
+ => HscEnv -> ModuleName -> RdrName
-> IO (Maybe (Name, ModIface))
lookupRdrNameInModuleForPlugins hsc_env mod_name rdr_name = do
let dflags = hsc_dflags hsc_env
@@ -321,9 +321,10 @@ lookupRdrNameInModuleForPlugins hsc_env mod_name rdr_name = do
let decl_spec = ImpDeclSpec { is_mod = mod_name, is_as = mod_name
, is_qual = False, is_dloc = noSrcSpan }
imp_spec = ImpSpec decl_spec ImpAll
- env = mkGlobalRdrEnv (gresFromAvails (Just imp_spec) (mi_exports iface))
- case lookupGRE_RdrName rdr_name env of
- [gre] -> return (Just (greMangledName gre, iface))
+ env = mkGlobalRdrEnv
+ $ gresFromAvails hsc_env (Just imp_spec) (mi_exports iface)
+ case lookupGRE_RdrName (IncludeFields WantNormal) env rdr_name of
+ [gre] -> return (Just (greName gre, iface))
[] -> return Nothing
_ -> panic "lookupRdrNameInModule"
diff --git a/compiler/GHC/StgToJS/Ids.hs b/compiler/GHC/StgToJS/Ids.hs
index 5d28b511f6..9817b326a3 100644
--- a/compiler/GHC/StgToJS/Ids.hs
+++ b/compiler/GHC/StgToJS/Ids.hs
@@ -111,7 +111,7 @@ makeIdentForId i num id_type current_module = TxtI ident
= current_module
!ident = mkFastStringByteString $ mconcat
- [ mkJsSymbolBS exported mod (occNameFS (nameOccName name))
+ [ mkJsSymbolBS exported mod (occNameMangledFS (nameOccName name))
-------------
-- suffixes
diff --git a/compiler/GHC/Tc/Errors.hs b/compiler/GHC/Tc/Errors.hs
index 3816f31ddd..8d5ac3a227 100644
--- a/compiler/GHC/Tc/Errors.hs
+++ b/compiler/GHC/Tc/Errors.hs
@@ -1,4 +1,5 @@
+{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE ParallelListComp #-}
@@ -40,8 +41,7 @@ import GHC.Tc.Utils.Instantiate
import {-# SOURCE #-} GHC.Tc.Errors.Hole ( findValidHoleFits, getHoleFitDispConfig, pprHoleFit )
import GHC.Types.Name
-import GHC.Types.Name.Reader ( lookupGRE_Name, GlobalRdrEnv, mkRdrUnqual
- , emptyLocalRdrEnv, lookupGlobalRdrEnv , lookupLocalRdrOcc )
+import GHC.Types.Name.Reader
import GHC.Types.Id
import GHC.Types.Var
import GHC.Types.Var.Set
@@ -81,7 +81,7 @@ import Data.Function ( on )
import Data.List ( partition, sort, sortBy )
import Data.List.NonEmpty ( NonEmpty(..), nonEmpty )
import qualified Data.List.NonEmpty as NE
-import Data.Ord ( comparing )
+import Data.Ord ( comparing )
import qualified Data.Semigroup as S
{-
@@ -1303,15 +1303,9 @@ See also 'reportUnsolved'.
mkHoleError :: NameEnv Type -> [ErrorItem] -> SolverReportErrCtxt -> Hole -> TcM (MsgEnvelope TcRnMessage)
mkHoleError _ _tidy_simples ctxt hole@(Hole { hole_occ = occ, hole_loc = ct_loc })
| isOutOfScopeHole hole
- = do { dflags <- getDynFlags
- ; rdr_env <- getGlobalRdrEnv
- ; imp_info <- getImports
- ; curr_mod <- getModule
- ; hpt <- getHpt
- ; let (imp_errs, hints)
- = unknownNameSuggestions WL_Anything
- dflags hpt curr_mod rdr_env
- (tcl_rdr lcl_env) imp_info occ
+ = do { (imp_errs, hints)
+ <- unknownNameSuggestions (tcl_rdr lcl_env) WL_Anything occ
+ ; let
err = SolverReportWithCtxt ctxt (ReportHoleError hole $ OutOfScopeHole imp_errs)
report = SolverReport err [] hints
@@ -2212,15 +2206,10 @@ mk_dict_err ctxt (item, (matches, unifiers, unsafe_overlapped)) = case (NE.nonEm
; lcl_env <- getLocalRdrEnv
; if occ_name_in_scope glb_env lcl_env name
then return ([], noHints)
- else do { dflags <- getDynFlags
- ; imp_info <- getImports
- ; curr_mod <- getModule
- ; hpt <- getHpt
- ; return (unknownNameSuggestions WL_RecField dflags hpt curr_mod
- glb_env emptyLocalRdrEnv imp_info (mkRdrUnqual name)) } }
+ else unknownNameSuggestions emptyLocalRdrEnv WL_RecField (mkRdrUnqual name) }
occ_name_in_scope glb_env lcl_env occ_name = not $
- null (lookupGlobalRdrEnv glb_env occ_name) &&
+ null (lookupGRE_OccName (IncludeFields WantNormal) glb_env occ_name) &&
isNothing (lookupLocalRdrOcc lcl_env occ_name)
record_field = case orig of
diff --git a/compiler/GHC/Tc/Errors/Hole.hs b/compiler/GHC/Tc/Errors/Hole.hs
index d4ee8abef2..76929e8c11 100644
--- a/compiler/GHC/Tc/Errors/Hole.hs
+++ b/compiler/GHC/Tc/Errors/Hole.hs
@@ -42,8 +42,7 @@ import GHC.Tc.Utils.TcType
import GHC.Core.Type
import GHC.Core.DataCon
import GHC.Types.Name
-import GHC.Types.Name.Reader ( pprNameProvenance , GlobalRdrElt (..)
- , globalRdrEnvElts, greMangledName, grePrintableName )
+import GHC.Types.Name.Reader
import GHC.Builtin.Names ( gHC_ERR )
import GHC.Types.Id
import GHC.Types.Var.Set
@@ -527,7 +526,7 @@ pprHoleFit (HFDC sWrp sWrpVars sTy sProv sMs) (HoleFit {..}) =
holeDisp = if sMs then holeVs
else sep $ replicate (length hfMatches) $ text "_"
occDisp = case hfCand of
- GreHFCand gre -> pprPrefixOcc (grePrintableName gre)
+ GreHFCand gre -> pprPrefixOcc (greName gre)
NameHFCand name -> pprPrefixOcc name
IdHFCand id_ -> pprPrefixOcc id_
tyDisp = ppWhen sTy $ dcolon <+> ppr hfType
@@ -832,9 +831,9 @@ tcFilterHoleFits limit typed_hole ht@(hole_ty, _) candidates =
_ -> Nothing }
where name = case hfc of
#if __GLASGOW_HASKELL__ < 901
- IdHFCand id -> idName id
+ IdHFCand id -> idName id
#endif
- GreHFCand gre -> greMangledName gre
+ GreHFCand gre -> greName gre
NameHFCand name -> name
discard_it = go subs seen maxleft ty elts
keep_it eid eid_ty wrp ms = go (fit:subs) (extendVarSet seen eid)
diff --git a/compiler/GHC/Tc/Errors/Hole/FitTypes.hs b/compiler/GHC/Tc/Errors/Hole/FitTypes.hs
index 72cb54bec2..71dae5b672 100644
--- a/compiler/GHC/Tc/Errors/Hole/FitTypes.hs
+++ b/compiler/GHC/Tc/Errors/Hole/FitTypes.hs
@@ -48,7 +48,7 @@ data HoleFitCandidate = IdHFCand Id -- An id, like locals.
instance Eq HoleFitCandidate where
IdHFCand i1 == IdHFCand i2 = i1 == i2
NameHFCand n1 == NameHFCand n2 = n1 == n2
- GreHFCand gre1 == GreHFCand gre2 = gre_name gre1 == gre_name gre2
+ GreHFCand gre1 == GreHFCand gre2 = greName gre1 == greName gre2
_ == _ = False
instance Outputable HoleFitCandidate where
@@ -63,11 +63,11 @@ instance NamedThing HoleFitCandidate where
getName hfc = case hfc of
IdHFCand cid -> idName cid
NameHFCand cname -> cname
- GreHFCand cgre -> greMangledName cgre
+ GreHFCand cgre -> greName cgre
getOccName hfc = case hfc of
IdHFCand cid -> occName cid
NameHFCand cname -> occName cname
- GreHFCand cgre -> occName (greMangledName cgre)
+ GreHFCand cgre -> occName $ greName cgre
instance HasOccName HoleFitCandidate where
occName = getOccName
diff --git a/compiler/GHC/Tc/Errors/Ppr.hs b/compiler/GHC/Tc/Errors/Ppr.hs
index 8b4896c5cc..4f1d88aaa5 100644
--- a/compiler/GHC/Tc/Errors/Ppr.hs
+++ b/compiler/GHC/Tc/Errors/Ppr.hs
@@ -58,15 +58,15 @@ import GHC.Tc.Types.Rank (Rank(..))
import GHC.Tc.Utils.TcType
import GHC.Types.Error
-import GHC.Types.FieldLabel (flIsOverloaded)
import GHC.Types.Hint (UntickedPromotedThing(..), pprUntickedConstructor, isBareSymbol)
import GHC.Types.Hint.Ppr () -- Outputable GhcHint
import GHC.Types.Basic
import GHC.Types.Error.Codes ( constructorCode )
import GHC.Types.Id
+import GHC.Types.Id.Info ( RecSelParent(..) )
import GHC.Types.Name
-import GHC.Types.Name.Reader ( GreName(..), pprNameProvenance
- , RdrName, rdrNameOcc, greMangledName, grePrintableName )
+import GHC.Types.Name.Reader
+import GHC.Types.Name.Env
import GHC.Types.Name.Set
import GHC.Types.SrcLoc
import GHC.Types.TyThing
@@ -99,7 +99,6 @@ import Data.List ( groupBy, sortBy, tails
, partition, unfoldr )
import Data.Ord ( comparing )
import Data.Bifunctor
-import GHC.Types.Name.Env
import qualified Language.Haskell.TH as TH
import {-# SOURCE #-} GHC.Tc.Types (pprTcTyThingCategory)
@@ -150,10 +149,10 @@ instance Diagnostic TcRnMessage where
) : [errInfoContext, errInfoSupplementary]
TcRnUnusedPatternBinds bind
-> mkDecorated [hang (text "This pattern-binding binds no variables:") 2 (ppr bind)]
- TcRnDodgyImports name
- -> mkDecorated [dodgy_msg (text "import") name (dodgy_msg_insert name :: IE GhcPs)]
- TcRnDodgyExports name
- -> mkDecorated [dodgy_msg (text "export") name (dodgy_msg_insert name :: IE GhcRn)]
+ TcRnDodgyImports gre
+ -> mkDecorated [dodgy_msg (text "import") gre (dodgy_msg_insert gre)]
+ TcRnDodgyExports gre
+ -> mkDecorated [dodgy_msg (text "export") gre (dodgy_msg_insert gre)]
TcRnMissingImportList ie
-> mkDecorated [ text "The import item" <+> quotes (ppr ie) <+>
text "does not have an explicit import list"
@@ -250,9 +249,9 @@ instance Diagnostic TcRnMessage where
, nest 2 (text "e.g., deriving instance _ => Eq (Foo a)") ]
TcRnDuplicateFieldName fld_part dups
-> mkSimpleDecorated $
- hsep [text "duplicate field name",
- quotes (ppr (NE.head dups)),
- text "in record", pprRecordFieldPart fld_part]
+ hsep [ text "Duplicate field name"
+ , quotes (ppr (rdrNameOcc $ NE.head dups))
+ , text "in record", pprRecordFieldPart fld_part ]
TcRnIllegalViewPattern pat
-> mkSimpleDecorated $ vcat [text "Illegal view pattern: " <+> ppr pat]
TcRnCharLiteralOutOfRange c
@@ -535,9 +534,9 @@ instance Diagnostic TcRnMessage where
$ formatExportItemError
(ppr export_item)
"attempts to export constructors or class methods that are not visible here"
- TcRnDuplicateExport child ie1 ie2
+ TcRnDuplicateExport gre ie1 ie2
-> mkSimpleDecorated $
- hsep [ quotes (ppr child)
+ hsep [ quotes (ppr $ greName gre)
, text "is exported by", quotes (ppr ie1)
, text "and", quotes (ppr ie2) ]
TcRnExportedParentChildMismatch parent_name ty_thing child parent_names
@@ -557,33 +556,60 @@ instance Diagnostic TcRnMessage where
| isRecordSelector i = "record selector"
pp_category i = tyThingCategory i
what_is = pp_category ty_thing
- thing = ppr child
+ thing = ppr $ greOccName child
parents = map ppr parent_names
- TcRnConflictingExports occ child1 gre1 ie1 child2 gre2 ie2
+ TcRnConflictingExports occ child_gre1 ie1 child_gre2 ie2
-> mkSimpleDecorated $
vcat [ text "Conflicting exports for" <+> quotes (ppr occ) <> colon
- , ppr_export child1 gre1 ie1
- , ppr_export child2 gre2 ie2
+ , ppr_export child_gre1 ie1
+ , ppr_export child_gre2 ie2
]
where
- ppr_export child gre ie = nest 3 (hang (quotes (ppr ie) <+> text "exports" <+>
- quotes (ppr_name child))
- 2 (pprNameProvenance gre))
-
- -- DuplicateRecordFields means that nameOccName might be a
- -- mangled $sel-prefixed thing, in which case show the correct OccName
- -- alone (but otherwise show the Name so it will have a module
- -- qualifier)
- ppr_name (FieldGreName fl) | flIsOverloaded fl = ppr fl
- | otherwise = ppr (flSelector fl)
- ppr_name (NormalGreName name) = ppr name
- TcRnAmbiguousField rupd parent_type
- -> mkSimpleDecorated $
- vcat [ text "The record update" <+> ppr rupd
- <+> text "with type" <+> ppr parent_type
- <+> text "is ambiguous."
- , text "This will not be supported by -XDuplicateRecordFields in future releases of GHC."
+ ppr_export gre ie =
+ nest 3 $
+ hang (quotes (ppr ie) <+> text "exports" <+> quotes (ppr $ greName gre))
+ 2 (pprNameProvenance gre)
+ TcRnDuplicateFieldExport (gre, ie1) gres_ies ->
+ mkSimpleDecorated $
+ vcat ( hsep [ text "Duplicate record field"
+ , quotes (ppr $ greOccName gre)
+ , text "in export list" <> colon ]
+ : map ppr_export ((gre,ie1) : NE.toList gres_ies)
+ )
+ where
+ ppr_export (gre,ie) =
+ nest 3 $
+ hang (sep [ quotes (ppr ie) <+> text "exports the field" <+> quotes (ppr $ greName gre)
+ , text "belonging to the constructor" <> plural fld_cons <+> pprQuotedList fld_cons ])
+ 2 (pprNameProvenance gre)
+ where
+ fld_cons :: [ConLikeName]
+ fld_cons = nonDetEltsUniqSet $ recFieldCons $ fieldGREInfo gre
+ TcRnAmbiguousFieldInUpdate (gre1, gre2, gres)
+ -> mkSimpleDecorated $
+ vcat [ text "Ambiguous record field" <+> fld <> dot
+ , hang (text "It could refer to any of the following:")
+ 2 $ vcat (map pprSugg (gre1 : gre2 : gres))
+ ]
+ where
+ fld = quotes $ ppr (occNameFS $ greOccName gre1)
+ pprSugg gre = vcat [ bullet <+> pprGRE gre <> comma
+ , nest 2 (pprNameProvenance gre) ]
+ pprGRE gre = case gre_info gre of
+ IAmRecField {}
+ -> let parent = par_is $ gre_par gre
+ in text "record field" <+> fld <+> text "of" <+> quotes (ppr parent)
+ _ -> text "variable" <+> fld
+ TcRnAmbiguousRecordUpdate _rupd tc
+ -> mkSimpleDecorated $
+ vcat [ text "Ambiguous record update with parent" <+> what <> dot
+ , hsep [ text "This type-directed disambiguation mechanism"
+ , text "will not be supported by -XDuplicateRecordFields in future releases of GHC." ]
+ , text "Consider disambiguating using module qualification instead."
]
+ where
+ what :: SDoc
+ what = text "type constructor" <+> quotes (ppr $ RecSelData tc)
TcRnMissingFields con fields
-> mkSimpleDecorated $ vcat [header, nest 2 rest]
where
@@ -597,21 +623,6 @@ instance Diagnostic TcRnMessage where
hang (text "Record update for insufficiently polymorphic field"
<> plural prs <> colon)
2 (vcat [ ppr f <+> dcolon <+> ppr ty | (f,ty) <- prs ])
- TcRnNoConstructorHasAllFields conflictingFields
- -> mkSimpleDecorated $
- hang (text "No constructor has all these fields:")
- 2 (pprQuotedList conflictingFields)
- TcRnMixedSelectors data_name data_sels pat_name pat_syn_sels
- -> mkSimpleDecorated $
- text "Cannot use a mixture of pattern synonym and record selectors" $$
- text "Record selectors defined by"
- <+> quotes (ppr data_name)
- <> colon
- <+> pprWithCommas ppr data_sels $$
- text "Pattern synonym selectors defined by"
- <+> quotes (ppr pat_name)
- <> colon
- <+> pprWithCommas ppr pat_syn_sels
TcRnMissingStrictFields con fields
-> mkSimpleDecorated $ vcat [header, nest 2 rest]
where
@@ -622,14 +633,51 @@ instance Diagnostic TcRnMessage where
header = text "Constructor" <+> quotes (ppr con) <+>
text "does not have the required strict field(s)" <>
if null fields then empty else colon
- TcRnNoPossibleParentForFields rbinds
- -> mkSimpleDecorated $
- hang (text "No type has all these fields:")
- 2 (pprQuotedList fields)
- where fields = map (hfbLHS . unLoc) rbinds
- TcRnBadOverloadedRecordUpdate _rbinds
- -> mkSimpleDecorated $
- text "Record update is ambiguous, and requires a type signature"
+ TcRnBadRecordUpdate upd_flds reason
+ -> case reason of
+ NoConstructorHasAllFields { conflictingFields = conflicts }
+ | [fld] <- conflicts
+ -> mkSimpleDecorated $
+ vcat [ header
+ , text "No constructor in scope has the field" <+> quotes (ppr fld) ]
+ | otherwise
+ ->
+ mkSimpleDecorated $
+ vcat [ header
+ , hang (text "No constructor in scope has all of the following fields:")
+ 2 (pprQuotedList conflicts) ]
+ where
+ header :: SDoc
+ header = text "Invalid record update."
+ MultiplePossibleParents (par1, par2, pars) ->
+ mkSimpleDecorated $
+ vcat [ hang (text "Ambiguous record update with field" <> plural upd_flds)
+ 2 ppr_flds
+ , hang (thisOrThese upd_flds <+> text "field" <> plural upd_flds <+> what_parent)
+ 2 (quotedListWithAnd (map ppr (par1:par2:pars))) ]
+ where
+ ppr_flds, what_parent, which :: SDoc
+ ppr_flds = quotedListWithAnd $ map ppr upd_flds
+ what_parent = case par1 of
+ RecSelData {} -> text "appear" <> singular upd_flds
+ <+> text "in" <+> which <+> text "datatypes"
+ RecSelPatSyn {} -> isOrAre upd_flds <+> text "associated with"
+ <+> which <+> text "pattern synonyms"
+ which = case pars of
+ [] -> text "both"
+ _ -> text "all of the"
+ InvalidTyConParent tc pars ->
+ mkSimpleDecorated $
+ vcat [ hang (text "No data constructor of" <+> what $$ text "has all of the fields:")
+ 2 (pprQuotedList upd_flds)
+ , pat_syn_msg ]
+ where
+ what = text "type constructor" <+> quotes (ppr (RecSelData tc))
+ pat_syn_msg
+ | any (\case { RecSelPatSyn {} -> True; _ -> False}) pars
+ = text "NB: type-directed disambiguation is not supported for pattern synonym record fields."
+ | otherwise
+ = empty
TcRnStaticFormNotClosed name reason
-> mkSimpleDecorated $
quotes (ppr name)
@@ -861,9 +909,6 @@ instance Diagnostic TcRnMessage where
TcRnExpectedValueId thing
-> mkSimpleDecorated $
ppr thing <+> text "used where a value identifier was expected"
- TcRnNotARecordSelector field
- -> mkSimpleDecorated $
- hsep [quotes (ppr field), text "is not a record selector"]
TcRnRecSelectorEscapedTyVar lbl
-> mkSimpleDecorated $
text "Cannot use record selector" <+> quotes (ppr lbl) <+>
@@ -887,9 +932,9 @@ instance Diagnostic TcRnMessage where
HsSrcBang _ _ _ -> "strictness"
in text "Unexpected" <+> text err <+> text "annotation:" <+> ppr ty $$
text err <+> text "annotation cannot appear nested inside a type"
- TcRnIllegalRecordSyntax ty
+ TcRnIllegalRecordSyntax either_ty_ty
-> mkSimpleDecorated $
- text "Record syntax is illegal here:" <+> ppr ty
+ text "Record syntax is illegal here:" <+> either ppr ppr either_ty_ty
TcRnUnexpectedTypeSplice ty
-> mkSimpleDecorated $
text "Unexpected type splice:" <+> ppr ty
@@ -1281,7 +1326,7 @@ instance Diagnostic TcRnMessage where
text "This is not forward-compatible with a planned GHC extension, RequiredTypeArguments."
where
var_names = case shadowed_term_names of
- Left gbl_names -> vcat (map (\name -> quotes (ppr $ grePrintableName name) <+> pprNameProvenance name) gbl_names)
+ Left gbl_names -> vcat (map (\name -> quotes (ppr $ greName name) <+> pprNameProvenance name) gbl_names)
Right lcl_name -> quotes (ppr lcl_name) <+> text "defined at"
<+> ppr (nameSrcLoc lcl_name)
TcRnBindingOfExistingName name -> mkSimpleDecorated $
@@ -1681,21 +1726,19 @@ instance Diagnostic TcRnMessage where
-> ErrorWithoutFlag
TcRnConflictingExports{}
-> ErrorWithoutFlag
- TcRnAmbiguousField{}
+ TcRnDuplicateFieldExport {}
+ -> ErrorWithoutFlag
+ TcRnAmbiguousFieldInUpdate {}
+ -> ErrorWithoutFlag
+ TcRnAmbiguousRecordUpdate{}
-> WarningWithFlag Opt_WarnAmbiguousFields
TcRnMissingFields{}
-> WarningWithFlag Opt_WarnMissingFields
TcRnFieldUpdateInvalidType{}
-> ErrorWithoutFlag
- TcRnNoConstructorHasAllFields{}
- -> ErrorWithoutFlag
- TcRnMixedSelectors{}
- -> ErrorWithoutFlag
TcRnMissingStrictFields{}
-> ErrorWithoutFlag
- TcRnNoPossibleParentForFields{}
- -> ErrorWithoutFlag
- TcRnBadOverloadedRecordUpdate{}
+ TcRnBadRecordUpdate{}
-> ErrorWithoutFlag
TcRnStaticFormNotClosed{}
-> ErrorWithoutFlag
@@ -1788,8 +1831,6 @@ instance Diagnostic TcRnMessage where
-> ErrorWithoutFlag
TcRnExpectedValueId{}
-> ErrorWithoutFlag
- TcRnNotARecordSelector{}
- -> ErrorWithoutFlag
TcRnRecSelectorEscapedTyVar{}
-> ErrorWithoutFlag
TcRnPatSynNotBidirectional{}
@@ -2195,21 +2236,19 @@ instance Diagnostic TcRnMessage where
-> noHints
TcRnConflictingExports{}
-> noHints
- TcRnAmbiguousField{}
+ TcRnDuplicateFieldExport {}
+ -> [suggestExtension LangExt.DuplicateRecordFields]
+ TcRnAmbiguousFieldInUpdate {}
+ -> [suggestExtension LangExt.DisambiguateRecordFields]
+ TcRnAmbiguousRecordUpdate{}
-> noHints
TcRnMissingFields{}
-> noHints
TcRnFieldUpdateInvalidType{}
-> noHints
- TcRnNoConstructorHasAllFields{}
- -> noHints
- TcRnMixedSelectors{}
- -> noHints
TcRnMissingStrictFields{}
-> noHints
- TcRnNoPossibleParentForFields{}
- -> noHints
- TcRnBadOverloadedRecordUpdate{}
+ TcRnBadRecordUpdate{}
-> noHints
TcRnStaticFormNotClosed{}
-> noHints
@@ -2285,8 +2324,6 @@ instance Diagnostic TcRnMessage where
-> noHints
TcRnExpectedValueId{}
-> noHints
- TcRnNotARecordSelector{}
- -> noHints
TcRnRecSelectorEscapedTyVar{}
-> [SuggestPatternMatchingSyntax]
TcRnPatSynNotBidirectional{}
@@ -2623,19 +2660,27 @@ messageWithInfoDiagnosticMessage unit_state ErrInfo{..} show_ctxt important =
in (mapDecoratedSDoc (pprWithUnitState unit_state) important) `unionDecoratedSDoc`
mkDecorated err_info'
-dodgy_msg :: (Outputable a, Outputable b) => SDoc -> a -> b -> SDoc
+dodgy_msg :: Outputable ie => SDoc -> GlobalRdrElt -> ie -> SDoc
dodgy_msg kind tc ie
- = sep [ text "The" <+> kind <+> text "item"
- <+> quotes (ppr ie)
- <+> text "suggests that",
- quotes (ppr tc) <+> text "has (in-scope) constructors or class methods,",
- text "but it has none" ]
-
-dodgy_msg_insert :: forall p . (Anno (IdP (GhcPass p)) ~ SrcSpanAnnN) => IdP (GhcPass p) -> IE (GhcPass p)
-dodgy_msg_insert tc = IEThingAll noAnn ii
+ = vcat [ text "The" <+> kind <+> text "item" <+> quotes (ppr ie) <+> text "suggests that"
+ , quotes (ppr $ greName tc) <+> text "has" <+> sep rest ]
+ where
+ rest :: [SDoc]
+ rest =
+ case gre_info tc of
+ IAmTyCon ClassFlavour
+ -> [ text "(in-scope) class methods or associated types" <> comma
+ , text "but it has none" ]
+ IAmTyCon _
+ -> [ text "(in-scope) constructors or record fields" <> comma
+ , text "but it has none" ]
+ _ -> [ text "children" <> comma
+ , text "but it is not a type constructor or a class" ]
+
+dodgy_msg_insert :: GlobalRdrElt -> IE GhcRn
+dodgy_msg_insert tc_gre = IEThingAll noAnn ii
where
- ii :: LIEWrappedName (GhcPass p)
- ii = noLocA (IEName noExtField $ noLocA tc)
+ ii = noLocA (IEName noExtField $ noLocA $ greName tc_gre)
pprTypeDoesNotHaveFixedRuntimeRep :: Type -> FixedRuntimeRepProvenance -> SDoc
pprTypeDoesNotHaveFixedRuntimeRep ty prov =
@@ -2656,6 +2701,7 @@ pprField (f,ty) = ppr f <+> dcolon <+> ppr ty
pprRecordFieldPart :: RecordFieldPart -> SDoc
pprRecordFieldPart = \case
+ RecordFieldDecl {} -> text "declaration"
RecordFieldConstructor{} -> text "construction"
RecordFieldPattern{} -> text "pattern"
RecordFieldUpdate -> text "update"
@@ -3951,6 +3997,9 @@ pprScopeError rdr_name scope_err =
NotInScope {} ->
hang (text "Not in scope:")
2 (what <+> quotes (ppr rdr_name))
+ NotARecordField {} ->
+ hang (text "Not in scope:")
+ 2 (text "record field" <+> quotes (ppr rdr_name))
NoExactName name ->
text "The Name" <+> quotes (ppr name) <+> text "is not in scope."
SameName gres ->
@@ -3958,7 +4007,8 @@ pprScopeError rdr_name scope_err =
$ hang (text "Same Name in multiple name-spaces:")
2 (vcat (map pp_one sorted_names))
where
- sorted_names = sortBy (leftmost_smallest `on` nameSrcSpan) (map greMangledName gres)
+ sorted_names = sortBy (leftmost_smallest `on` nameSrcSpan)
+ $ map greName gres
pp_one name
= hang (pprNameSpace (occNameSpace (getOccName name))
<+> quotes (ppr name) <> comma)
@@ -3983,6 +4033,7 @@ scopeErrorHints :: NotInScopeError -> [GhcHint]
scopeErrorHints scope_err =
case scope_err of
NotInScope -> noHints
+ NotARecordField -> noHints
NoExactName {} -> [SuggestDumpSlices]
SameName {} -> [SuggestDumpSlices]
MissingBinding _ hints -> hints
@@ -4553,10 +4604,6 @@ pprConversionFailReason = \case
text "Implicit parameters mixed with other bindings"
InvalidCCallImpent from ->
text (show from) <+> text "is not a valid ccall impent"
- RecGadtNoCons ->
- text "RecGadtC must have at least one constructor name"
- GadtNoCons ->
- text "GadtC must have at least one constructor name"
InvalidTypeInstanceHeader tys ->
text "Invalid type instance header:"
<+> text (show tys)
diff --git a/compiler/GHC/Tc/Errors/Types.hs b/compiler/GHC/Tc/Errors/Types.hs
index 6b8d570c05..c2f19613d4 100644
--- a/compiler/GHC/Tc/Errors/Types.hs
+++ b/compiler/GHC/Tc/Errors/Types.hs
@@ -15,6 +15,7 @@ module GHC.Tc.Errors.Types (
, ShadowedNameProvenance(..)
, RecordFieldPart(..)
, IllegalNewtypeReason(..)
+ , BadRecordUpdateReason(..)
, InjectivityErrReason(..)
, HasKinds(..)
, hasKinds
@@ -114,6 +115,7 @@ import GHC.Types.Avail (AvailInfo)
import GHC.Types.Error
import GHC.Types.Hint (UntickedPromotedThing(..))
import GHC.Types.ForeignCall (CLabelString)
+import GHC.Types.Id.Info ( RecSelParent(..) )
import GHC.Types.Name (Name, OccName, getSrcLoc, getSrcSpan)
import qualified GHC.Types.Name.Occurrence as OccName
import GHC.Types.Name.Reader
@@ -132,7 +134,7 @@ import GHC.Core.FamInstEnv (FamInst)
import GHC.Core.InstEnv (LookupInstanceErrReason, ClsInst)
import GHC.Core.PatSyn (PatSyn)
import GHC.Core.Predicate (EqRel, predTypeEqRel)
-import GHC.Core.TyCon (TyCon, TyConFlavour)
+import GHC.Core.TyCon (TyCon)
import GHC.Core.Type (Kind, Type, ThetaType, PredType)
import GHC.Driver.Backend (Backend)
import GHC.Unit.State (UnitState)
@@ -327,15 +329,15 @@ data TcRnMessage where
-}
TcRnUnusedPatternBinds :: HsBind GhcRn -> TcRnMessage
{-| TcRnDodgyImports is a warning (controlled with -Wdodgy-imports) that occurs when
- a datatype 'T' is imported with all constructors, i.e. 'T(..)', but has been exported
- abstractly, i.e. 'T'.
+ an import of the form 'T(..)' or 'f(..)' does not actually import anything beside
+ 'T'/'f' itself.
Test cases: rename/should_compile/T7167
-}
- TcRnDodgyImports :: RdrName -> TcRnMessage
- {-| TcRnDodgyExports is a warning (controlled by -Wdodgy-exports) that occurs when a datatype
- 'T' is exported with all constructors, i.e. 'T(..)', but is it just a type synonym or a
- type/data family.
+ TcRnDodgyImports :: GlobalRdrElt -> TcRnMessage
+ {-| TcRnDodgyExports is a warning (controlled by -Wdodgy-exports) that occurs when
+ an export of the form 'T(..)' for a type constructor 'T' does not actually export anything
+ beside 'T' itself.
Example:
module Foo (
@@ -350,7 +352,7 @@ data TcRnMessage where
Test cases: warnings/should_compile/DodgyExports01
-}
- TcRnDodgyExports :: Name -> TcRnMessage
+ TcRnDodgyExports :: GlobalRdrElt -> TcRnMessage
{-| TcRnMissingImportList is a warning (controlled by -Wmissing-import-lists) that occurs when
an import declaration does not explicitly list all the names brought into scope.
@@ -577,13 +579,15 @@ data TcRnMessage where
-> !BadAnonWildcardContext
-> TcRnMessage
-
{-| TcRnDuplicateFieldName is an error that occurs whenever
- there are duplicate field names in a record.
+ there are duplicate field names in a single record.
- Examples(s): None.
+ Examples(s):
- Test cases: None.
+ data R = MkR { x :: Int, x :: Bool }
+ f r = r { x = 3, x = 4 }
+
+ Test cases: T21959.
-}
TcRnDuplicateFieldName :: !RecordFieldPart -> NE.NonEmpty RdrName -> TcRnMessage
@@ -1040,7 +1044,7 @@ data TcRnMessage where
Test cases: polykinds/T13267
-}
- TcRnIllegalClassInst :: !TyConFlavour -> TcRnMessage
+ TcRnIllegalClassInst :: !(TyConFlavour TyCon) -> TcRnMessage
{-| TcRnOversaturatedVisibleKindArg is an error that occurs whenever an illegal oversaturated
visible kind argument is specified.
@@ -1342,7 +1346,7 @@ data TcRnMessage where
overloadedrecflds/should_fail/DuplicateExports
patsyn/should_compile/T11959
-}
- TcRnDuplicateExport :: GreName -> IE GhcPs -> IE GhcPs -> TcRnMessage
+ TcRnDuplicateExport :: GlobalRdrElt -> IE GhcPs -> IE GhcPs -> TcRnMessage
{-| TcRnExportedParentChildMismatch is an error that occurs when an export is
bundled with a parent that it does not belong to
@@ -1358,7 +1362,10 @@ data TcRnMessage where
module/mod3
overloadedrecflds/should_fail/NoParent
-}
- TcRnExportedParentChildMismatch :: Name -> TyThing -> GreName -> [Name] -> TcRnMessage
+ TcRnExportedParentChildMismatch :: Name -- ^ parent
+ -> TyThing
+ -> GlobalRdrElt -- ^ child
+ -> [Name] -> TcRnMessage
{-| TcRnConflictingExports is an error that occurs when different identifiers that
have the same name are being exported by a module.
@@ -1385,29 +1392,50 @@ data TcRnMessage where
typecheck/should_fail/tcfail026
-}
TcRnConflictingExports
- :: OccName -- ^ Occurrence name shared by both exports
- -> GreName -- ^ Name of first export
- -> GlobalRdrElt -- ^ Provenance for definition site of first export
- -> IE GhcPs -- ^ Export decl of first export
- -> GreName -- ^ Name of second export
- -> GlobalRdrElt -- ^ Provenance for definition site of second export
- -> IE GhcPs -- ^ Export decl of second export
+ :: OccName -- ^ Occurrence name shared by both exports
+ -> GlobalRdrElt -- ^ First export
+ -> IE GhcPs -- ^ Export decl of first export
+ -> GlobalRdrElt -- ^ Second export
+ -> IE GhcPs -- ^ Export decl of second export
+ -> TcRnMessage
+
+ {-| TcRnDuplicateFieldExport is an error that occurs when a module exports
+ multiple record fields with the same name, without enabling
+ DuplicateRecordFields.
+
+ Example:
+
+ module M1 where
+ data D1 = MkD1 { foo :: Int }
+ module M2 where
+ data D2 = MkD2 { foo :: Int }
+ module M ( D1(..), D2(..) ) where
+ import module M1
+ import module M2
+
+ Test case: overloadedrecflds/should_fail/overloadedrecfldsfail10
+ -}
+ TcRnDuplicateFieldExport
+ :: (GlobalRdrElt, IE GhcPs)
+ -> NE.NonEmpty (GlobalRdrElt, IE GhcPs)
-> TcRnMessage
- {-| TcRnAmbiguousField is a warning controlled by -Wambiguous-fields occurring
- when a record update's type cannot be precisely determined. This will not
- be supported by -XDuplicateRecordFields in future releases.
+ {-| TcRnAmbiguousRecordUpdate is a warning, controlled by -Wambiguous-fields,
+ which occurs when a user relies on the type-directed disambiguation
+ mechanism to disambiguate a record update. This will not be supported by
+ -XDuplicateRecordFields in future releases.
Example(s):
- data Person = MkPerson { personId :: Int, name :: String }
- data Address = MkAddress { personId :: Int, address :: String }
- bad1 x = x { personId = 4 } :: Person -- ambiguous
- bad2 (x :: Person) = x { personId = 4 } -- ambiguous
- good x = (x :: Person) { personId = 4 } -- not ambiguous
+
+ data Person = MkPerson { personId :: Int, name :: String }
+ data Address = MkAddress { personId :: Int, address :: String }
+ bad1 x = x { personId = 4 } :: Person -- ambiguous
+ bad2 (x :: Person) = x { personId = 4 } -- ambiguous
+ good x = (x :: Person) { personId = 4 } -- not ambiguous
Test cases: overloadedrecflds/should_fail/overloadedrecfldsfail06
-}
- TcRnAmbiguousField
+ TcRnAmbiguousRecordUpdate
:: HsExpr GhcRn -- ^ Field update
-> TyCon -- ^ Record type
-> TcRnMessage
@@ -1442,38 +1470,6 @@ data TcRnMessage where
-}
TcRnFieldUpdateInvalidType :: [(FieldLabelString,TcType)] -> TcRnMessage
- {-| TcRnNoConstructorHasAllFields is an error that occurs when a record update
- has fields that no single constructor encompasses.
-
- Example(s):
- data Foo = A { x :: Bool }
- | B { y :: Int }
- foo = (A False) { x = True, y = 5 }
-
- Test cases: overloadedrecflds/should_fail/overloadedrecfldsfail08
- patsyn/should_fail/mixed-pat-syn-record-sels
- typecheck/should_fail/T7989
- -}
- TcRnNoConstructorHasAllFields :: [FieldLabelString] -> TcRnMessage
-
- {- TcRnMixedSelectors is an error for when a mixture of pattern synonym and
- record selectors are used in the same record update block.
-
- Example(s):
- data Rec = Rec { foo :: Int, bar :: String }
- pattern Pat { f1, f2 } = Rec { foo = f1, bar = f2 }
- illegal :: Rec -> Rec
- illegal r = r { f1 = 1, bar = "two" }
-
- Test cases: patsyn/should_fail/records-mixing-fields
- -}
- TcRnMixedSelectors
- :: Name -- ^ Record
- -> [Id] -- ^ Record selectors
- -> Name -- ^ Pattern synonym
- -> [Id] -- ^ Pattern selectors
- -> TcRnMessage
-
{- TcRnMissingStrictFields is an error occurring when a record field marked
as strict is omitted when constructing said record.
@@ -1487,30 +1483,54 @@ data TcRnMessage where
-}
TcRnMissingStrictFields :: ConLike -> [(FieldLabelString, TcType)] -> TcRnMessage
- {- TcRnNoPossibleParentForFields is an error thrown when the fields used in a
- record update block do not all belong to any one type.
+ {-| TcRnAmbiguousFieldInUpdate is an error that occurs when a field in a
+ record update clashes with another field or top-level function of the
+ same name, and the user hasn't enabled -XDisambiguateRecordFields.
- Example(s):
- data R1 = R1 { x :: Int, y :: Int }
- data R2 = R2 { y :: Int, z :: Int }
- update r = r { x = 1, y = 2, z = 3 }
+ Example:
+
+ {-# LANGUAGE NoFieldSelectors #-}
+ {-# LANGUAGE NoDisambiguateRecordFields #-}
+ module M where
+
+ data A = MkA { fld :: Int }
+
+ fld :: Bool
+ fld = False
+
+ f r = r { fld = 3 }
- Test cases: overloadedrecflds/should_fail/overloadedrecfldsfail01
- overloadedrecflds/should_fail/overloadedrecfldsfail14
-}
- TcRnNoPossibleParentForFields :: [LHsRecUpdField GhcRn] -> TcRnMessage
+ TcRnAmbiguousFieldInUpdate :: (GlobalRdrElt, GlobalRdrElt, [GlobalRdrElt])
+ -> TcRnMessage
+
+ {-| TcRnBadRecordUpdate is an error when a regular (non-overloaded)
+ record update cannot be pinned down to any one parent.
- {- TcRnBadOverloadedRecordUpdate is an error for a record update that cannot
- be pinned down to any one constructor and thus must be given a type signature.
+ The problem with the record update is stored in the 'BadRecordUpdateReason'
+ field.
Example(s):
- data R1 = R1 { x :: Int }
- data R2 = R2 { x :: Int }
- update r = r { x = 1 } -- needs a type signature
+
+ data R1 = R1 { x :: Int }
+ data R2 = R2 { x :: Int }
+ update r = r { x = 1 }
+ -- ambiguous
+
+ data R1 = R1 { x :: Int, y :: Int }
+ data R2 = R2 { y :: Int, z :: Int }
+ update r = r { x = 1, y = 2, z = 3 }
+ -- no parent has all the fields
Test cases: overloadedrecflds/should_fail/overloadedrecfldsfail01
+ overloadedrecflds/should_fail/overloadedrecfldsfail01
+ overloadedrecflds/should_fail/overloadedrecfldsfail14
-}
- TcRnBadOverloadedRecordUpdate :: [LHsRecUpdField GhcRn] -> TcRnMessage
+ TcRnBadRecordUpdate :: [RdrName]
+ -- ^ the fields of the record update
+ -> BadRecordUpdateReason
+ -- ^ the reason this record update was rejected
+ -> TcRnMessage
{- TcRnStaticFormNotClosed is an error pertaining to terms that are marked static
using the -XStaticPointers extension but which are not closed terms.
@@ -1932,19 +1952,6 @@ data TcRnMessage where
-}
TcRnExpectedValueId :: !TcTyThing -> TcRnMessage
- {- TcRnNotARecordSelector is an error for when something that is not a record
- selector is used in a record pattern.
-
- Example(s):
- data Rec = MkRec { field :: Int }
- r = Mkrec 1
- r' = r { notAField = 2 }
-
- Test cases: rename/should_fail/rnfail054
- typecheck/should_fail/tcfail114
- -}
- TcRnNotARecordSelector :: !Name -> TcRnMessage
-
{- TcRnRecSelectorEscapedTyVar is an error indicating that a record field selector
containing an existential type variable is used as a function rather than in
a pattern match.
@@ -2011,7 +2018,7 @@ data TcRnMessage where
Test cases: rename/should_fail/T7943
rename/should_fail/T9077
-}
- TcRnIllegalRecordSyntax :: !(HsType GhcRn) -> TcRnMessage
+ TcRnIllegalRecordSyntax :: Either (HsType GhcPs) (HsType GhcRn) -> TcRnMessage
{- TcRnUnexpectedTypeSplice is an error for a typed template haskell splice
appearing unexpectedly.
@@ -2568,8 +2575,6 @@ data TcRnMessage where
th/T16895c
th/T16895d
th/T16895e
- th/T17379a
- th/T17379b
th/T18740d
th/T2597b
th/T2674
@@ -3401,8 +3406,6 @@ data ConversionFailReason
| CasesExprWithoutAlts
| ImplicitParamsWithOtherBinds
| InvalidCCallImpent !String -- ^ Source
- | RecGadtNoCons
- | GadtNoCons
| InvalidTypeInstanceHeader !TH.Type
| InvalidTyFamInstLHS !TH.Type
| InvalidImplicitParamBinding
@@ -3438,10 +3441,30 @@ data ArgOrResult
-- | Which parts of a record field are affected by a particular error or warning.
data RecordFieldPart
- = RecordFieldConstructor !Name
+ = RecordFieldDecl !Name
+ | RecordFieldConstructor !Name
| RecordFieldPattern !Name
| RecordFieldUpdate
+-- | Why did we reject a record update?
+data BadRecordUpdateReason
+ -- | No constructor has all of the required fields.
+ = NoConstructorHasAllFields
+ { conflictingFields :: [FieldLabelString] }
+
+ -- | There are several possible parents which have all of the required fields,
+ -- and we weren't able to disambiguate in any way.
+ | MultiplePossibleParents
+ (RecSelParent, RecSelParent, [RecSelParent])
+ -- ^ The possible parents (at least 2)
+
+ -- | We used type-directed disambiguation, but this resulted in
+ -- an invalid parent (the type-directed parent is not among the
+ -- parents we computed from the field labels alone).
+ | InvalidTyConParent TyCon (NE.NonEmpty RecSelParent)
+
+ deriving Generic
+
-- | Where a shadowed name comes from
data ShadowedNameProvenance
= ShadowedNameProvenanceLocal !SrcLoc
@@ -4289,6 +4312,11 @@ data NotInScopeError
-- | A run-of-the-mill @"not in scope"@ error.
= NotInScope
+ -- | Something used in record syntax, but it isn't a record field.
+ | NotARecordField
+ -- TODO: this could be folded into NotInScope were there
+ -- a separate namespace for record fields.
+
-- | An exact 'Name' was not in scope.
--
-- This usually indicates a problem with a Template Haskell splice.
diff --git a/compiler/GHC/Tc/Gen/Export.hs b/compiler/GHC/Tc/Gen/Export.hs
index dbe9fd828c..eed125e8b0 100644
--- a/compiler/GHC/Tc/Gen/Export.hs
+++ b/compiler/GHC/Tc/Gen/Export.hs
@@ -3,17 +3,18 @@
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeFamilies #-}
-module GHC.Tc.Gen.Export (rnExports, exports_from_avail) where
+module GHC.Tc.Gen.Export (rnExports, exports_from_avail, classifyGREs) where
import GHC.Prelude
import GHC.Hs
-import GHC.Types.FieldLabel
import GHC.Builtin.Names
import GHC.Tc.Errors.Types
import GHC.Tc.Utils.Monad
import GHC.Tc.Utils.Env
+ ( TyThing(AConLike, AnId), tcLookupGlobal, tcLookupTyCon )
import GHC.Tc.Utils.TcType
+import GHC.Rename.Doc
import GHC.Rename.Names
import GHC.Rename.Env
import GHC.Rename.Unbound ( reportUnboundName )
@@ -28,6 +29,9 @@ import GHC.Core.PatSyn
import GHC.Data.Maybe
import GHC.Data.FastString (fsLit)
import GHC.Driver.Env
+import GHC.Driver.Session
+import GHC.Parser.PostProcess ( setRdrNameSpace )
+import qualified GHC.LanguageExtensions as LangExt
import GHC.Types.Unique.Set
import GHC.Types.SrcLoc as SrcLoc
@@ -40,11 +44,10 @@ import GHC.Types.Id
import GHC.Types.Id.Info
import GHC.Types.Name.Reader
-import Control.Monad
-import GHC.Driver.Session
-import GHC.Parser.PostProcess ( setRdrNameSpace )
-import Data.Either ( partitionEithers )
-import GHC.Rename.Doc
+import Control.Arrow ( first )
+import Control.Monad ( when )
+import qualified Data.List.NonEmpty as NE
+import Data.Traversable ( for )
{-
************************************************************************
@@ -147,7 +150,7 @@ accumExports f = fmap (catMaybes . snd) . mapAccumLM f' emptyExportAccum
Just (Just (acc', y)) -> (acc', Just y)
_ -> (acc, Nothing)
-type ExportOccMap = OccEnv (GreName, IE GhcPs)
+type ExportOccMap = OccEnv (Name, IE GhcPs)
-- Tracks what a particular exported OccName
-- in an export list refers to, and which item
-- it came from. It's illegal to export two distinct things
@@ -206,7 +209,7 @@ rnExports explicit_mod exports
else checkNoErrs do_it
-- Final processing
- ; let final_ns = availsToNameSetWithSelectors final_avails
+ ; let final_ns = availsToNameSet final_avails
; traceRn "rnExports: Exports:" (ppr final_avails)
@@ -249,8 +252,10 @@ exports_from_avail Nothing rdr_env _imports _this_mod
-- only data families can locally define subordinate things (`ns` here)
-- without locally defining (and instead importing) the parent (`n`)
fix_faminst avail@(AvailTC n ns)
- | availExportsDecl avail = avail
- | otherwise = AvailTC n (NormalGreName n:ns)
+ | availExportsDecl avail
+ = avail
+ | otherwise
+ = AvailTC n (n:ns)
fix_faminst avail = avail
@@ -270,8 +275,11 @@ exports_from_avail (Just (L _ rdr_items)) rdr_env imports this_mod
-- See Note [Avails of associated data families]
expand_tyty_gre :: GlobalRdrElt -> [GlobalRdrElt]
expand_tyty_gre (gre@GRE { gre_par = ParentIs p })
- | isTyConName p, isTyConName (greMangledName gre) = [gre, gre{ gre_par = NoParent }]
- expand_tyty_gre gre = [gre]
+ | isTyConName p
+ , isTyConName (greName gre)
+ = [gre, gre{ gre_par = NoParent }]
+ expand_tyty_gre gre
+ = [gre]
imported_modules = [ imv_name imv
| xs <- moduleEnvElts $ imp_mods imports
@@ -281,120 +289,133 @@ exports_from_avail (Just (L _ rdr_items)) rdr_env imports this_mod
-> RnM (Maybe (ExportAccum, (LIE GhcRn, Avails)))
exports_from_item (ExportAccum occs earlier_mods)
(L loc ie@(IEModuleContents _ lmod@(L _ mod)))
- | mod `elementOfUniqSet` earlier_mods -- Duplicate export of M
- = do { addDiagnostic (TcRnDupeModuleExport mod) ;
- return Nothing }
-
- | otherwise
- = do { let { exportValid = (mod `elem` imported_modules)
- || (moduleName this_mod == mod)
- ; gre_prs = pickGREsModExp mod (globalRdrEnvElts rdr_env)
- ; new_exports = [ availFromGRE gre'
- | (gre, _) <- gre_prs
- , gre' <- expand_tyty_gre gre ]
- ; all_gres = foldr (\(gre1,gre2) gres -> gre1 : gre2 : gres) [] gre_prs
- ; mods = addOneToUniqSet earlier_mods mod
- }
-
- ; checkErr exportValid (TcRnExportedModNotImported mod)
- ; warnIf (exportValid && null gre_prs) (TcRnNullExportedModule mod)
-
- ; traceRn "efa" (ppr mod $$ ppr all_gres)
- ; addUsedGREs all_gres
-
- ; occs' <- check_occs ie occs new_exports
- -- This check_occs not only finds conflicts
- -- between this item and others, but also
- -- internally within this item. That is, if
- -- 'M.x' is in scope in several ways, we'll have
- -- several members of mod_avails with the same
- -- OccName.
- ; traceRn "export_mod"
- (vcat [ ppr mod
- , ppr new_exports ])
-
- ; return (Just ( ExportAccum occs' mods
- , ( L loc (IEModuleContents noExtField lmod)
- , new_exports))) }
+ | mod `elementOfUniqSet` earlier_mods -- Duplicate export of M
+ = do { addDiagnostic (TcRnDupeModuleExport mod)
+ ; return Nothing}
+
+ | otherwise
+ = do { let { exportValid = (mod `elem` imported_modules)
+ || (moduleName this_mod == mod)
+ ; gre_prs = pickGREsModExp mod (globalRdrEnvElts rdr_env)
+ ; new_gres = [ gre'
+ | (gre, _) <- gre_prs
+ , gre' <- expand_tyty_gre gre ]
+ ; new_exports = map availFromGRE new_gres
+ ; all_gres = foldr (\(gre1,gre2) gres -> gre1 : gre2 : gres) [] gre_prs
+ ; mods = addOneToUniqSet earlier_mods mod
+ }
+
+ ; checkErr exportValid (TcRnExportedModNotImported mod)
+ ; warnIf (exportValid && null gre_prs) (TcRnNullExportedModule mod)
+
+ ; traceRn "efa" (ppr mod $$ ppr all_gres)
+ ; addUsedGREs all_gres
+
+ ; occs' <- check_occs occs ie new_gres
+ -- This check_occs not only finds conflicts
+ -- between this item and others, but also
+ -- internally within this item. That is, if
+ -- 'M.x' is in scope in several ways, we'll have
+ -- several members of mod_avails with the same
+ -- OccName.
+ ; traceRn "export_mod"
+ (vcat [ ppr mod
+ , ppr new_exports ])
+ ; return $ Just $
+ ( ExportAccum occs' mods
+ , ( L loc (IEModuleContents noExtField lmod)
+ , new_exports) ) }
exports_from_item acc@(ExportAccum occs mods) (L loc ie) = do
m_new_ie <- lookup_doc_ie ie
case m_new_ie of
- Just new_ie -> return (Just (acc, (L loc new_ie, [])))
+ Just new_ie -> return $ Just (acc, (L loc new_ie, []))
Nothing -> do
- (new_ie, avail) <- lookup_ie ie
- if isUnboundName (ieName new_ie)
- then return Nothing -- Avoid error cascade
- else do
-
- occs' <- check_occs ie occs [avail]
-
- return (Just ( ExportAccum occs' mods
- , (L loc new_ie, [avail])))
+ let finish (occs', new_ie, avail) = (ExportAccum occs' mods, (L loc new_ie, [avail]))
+ fmap finish <$> lookup_ie occs ie
-------------
- lookup_ie :: IE GhcPs -> RnM (IE GhcRn, AvailInfo)
- lookup_ie (IEVar _ (L l rdr))
- = do (name, avail) <- lookupGreAvailRn $ ieWrappedName rdr
- return (IEVar noExtField (L l (replaceWrappedName rdr name)), avail)
-
- lookup_ie (IEThingAbs _ (L l rdr))
- = do (name, avail) <- lookupGreAvailRn $ ieWrappedName rdr
- return (IEThingAbs noAnn (L l (replaceWrappedName rdr name))
- , avail)
-
- lookup_ie ie@(IEThingAll _ n')
+ lookup_ie :: ExportOccMap -> IE GhcPs -> RnM (Maybe (ExportOccMap, IE GhcRn, AvailInfo))
+ lookup_ie occs ie@(IEVar ann (L l rdr))
+ = do mb_gre <- lookupGreAvailRn $ ieWrappedName rdr
+ for mb_gre $ \ gre -> do
+ let avail = availFromGRE gre
+ name = greName gre
+ occs' <- check_occs occs ie [gre]
+ return (occs', IEVar ann (L l (replaceWrappedName rdr name)), avail)
+
+ lookup_ie occs ie@(IEThingAbs ann (L l rdr))
+ = do mb_gre <- lookupGreAvailRn $ ieWrappedName rdr
+ for mb_gre $ \ gre -> do
+ let avail = availFromGRE gre
+ name = greName gre
+ occs' <- check_occs occs ie [gre]
+ return ( occs'
+ , IEThingAbs ann (L l (replaceWrappedName rdr name))
+ , avail)
+
+ lookup_ie occs ie@(IEThingAll ann n')
= do
- (n, avail, flds) <- lookup_ie_all ie n'
+ (n, kids) <- lookup_ie_all ie n'
let name = unLoc n
- return (IEThingAll noAnn (replaceLWrappedName n' (unLoc n))
- , availTC name (name:avail) flds)
-
-
- lookup_ie ie@(IEThingWith _ l wc sub_rdrs)
+ avails = map greName kids
+ occs' <- check_occs occs ie kids
+ return $ Just
+ ( occs'
+ , IEThingAll ann (replaceLWrappedName n' (unLoc n))
+ , AvailTC name (name:avails))
+
+ lookup_ie occs ie@(IEThingWith ann l wc sub_rdrs)
= do
- (lname, subs, avails, flds)
+ (lname, subs, with_gres)
<- addExportErrCtxt ie $ lookup_ie_with l sub_rdrs
- (_, all_avail, all_flds) <-
+
+ (_, wc_gres) <-
case wc of
- NoIEWildcard -> return (lname, [], [])
+ NoIEWildcard -> return (lname, [])
IEWildcard _ -> lookup_ie_all ie l
+
let name = unLoc lname
- let flds' = flds ++ (map noLoc all_flds)
- return (IEThingWith flds' (replaceLWrappedName l name) wc subs,
- availTC name (name : avails ++ all_avail)
- (map unLoc flds ++ all_flds))
+ all_names = name : map greName (with_gres ++ wc_gres)
+ gres = localVanillaGRE NoParent name
+ -- localVanillaGRE might not be correct here,
+ -- but these GREs are only passed to check_occs
+ -- which only needs the correct Name for the GREs...
+ : with_gres ++ wc_gres
+ occs' <- check_occs occs ie gres
+ return $ Just $
+ ( occs'
+ , IEThingWith ann (replaceLWrappedName l name) wc subs
+ , AvailTC name all_names)
- lookup_ie _ = panic "lookup_ie" -- Other cases covered earlier
+ lookup_ie _ _ = panic "lookup_ie" -- Other cases covered earlier
lookup_ie_with :: LIEWrappedName GhcPs -> [LIEWrappedName GhcPs]
- -> RnM (Located Name, [LIEWrappedName GhcRn], [Name],
- [Located FieldLabel])
- lookup_ie_with (L l rdr) sub_rdrs
- = do name <- lookupGlobalOccRn $ ieWrappedName rdr
- (non_flds, flds) <- lookupChildrenExport name sub_rdrs
- if isUnboundName name
- then return (L (locA l) name, [], [name], [])
- else return (L (locA l) name, non_flds
- , map (ieWrappedName . unLoc) non_flds
- , flds)
+ -> RnM (Located Name, [LIEWrappedName GhcRn], [GlobalRdrElt])
+ lookup_ie_with (L l rdr) sub_rdrs =
+ do { gre <- lookupGlobalOccRn $ ieWrappedName rdr
+ ; let name = greName gre
+ ; kids <- lookupChildrenExport name sub_rdrs
+ ; if isUnboundName name
+ then return (L (locA l) name, [], [gre])
+ else return (L (locA l) name, map fst kids, map snd kids) }
lookup_ie_all :: IE GhcPs -> LIEWrappedName GhcPs
- -> RnM (Located Name, [Name], [FieldLabel])
+ -> RnM (Located Name, [GlobalRdrElt])
lookup_ie_all ie (L l rdr) =
- do name <- lookupGlobalOccRn $ ieWrappedName rdr
- let gres = findChildren kids_env name
- (non_flds, flds) = classifyGREs gres
- addUsedKids (ieWrappedName rdr) gres
- when (null gres) $
- if isTyConName name
- then addTcRnDiagnostic (TcRnDodgyExports name)
- else -- This occurs when you export T(..), but
- -- only import T abstractly, or T is a synonym.
- addErr (TcRnExportHiddenComponents ie)
- return (L (locA l) name, non_flds, flds)
+ do { gre <- lookupGlobalOccRn $ ieWrappedName rdr
+ ; let name = greName gre
+ gres = findChildren kids_env name
+ ; addUsedKids (ieWrappedName rdr) gres
+ ; when (null gres) $
+ if isTyConName name
+ then addTcRnDiagnostic (TcRnDodgyExports gre)
+ else -- This occurs when you export T(..), but
+ -- only import T abstractly, or T is a synonym.
+ addErr (TcRnExportHiddenComponents ie)
+ ; return (L (locA l) name, gres) }
-------------
lookup_doc_ie :: IE GhcPs -> RnM (Maybe (IE GhcRn))
@@ -413,9 +434,6 @@ exports_from_avail (Just (L _ rdr_items)) rdr_env imports this_mod
addUsedKids :: RdrName -> [GlobalRdrElt] -> RnM ()
addUsedKids parent_rdr kid_gres = addUsedGREs (pickGREs parent_rdr kid_gres)
-classifyGREs :: [GlobalRdrElt] -> ([Name], [FieldLabel])
-classifyGREs = partitionGreNames . map gre_name
-
-- Renaming and typechecking of exports happens after everything else has
-- been typechecked.
@@ -477,11 +495,8 @@ If the module has NO main function:
lookupChildrenExport :: Name -> [LIEWrappedName GhcPs]
- -> RnM ([LIEWrappedName GhcRn], [Located FieldLabel])
-lookupChildrenExport spec_parent rdr_items =
- do
- xs <- mapAndReportM doOne rdr_items
- return $ partitionEithers xs
+ -> RnM ([(LIEWrappedName GhcRn, GlobalRdrElt)])
+lookupChildrenExport spec_parent rdr_items = mapAndReportM doOne rdr_items
where
-- Pick out the possible namespaces in order of priority
-- This is a consequence of how the parser parses all
@@ -489,11 +504,13 @@ lookupChildrenExport spec_parent rdr_items =
choosePossibleNamespaces :: NameSpace -> [NameSpace]
choosePossibleNamespaces ns
| ns == varName = [varName, tcName]
+ -- NB: for varName, we will also end up looking in the
+ -- record field namespaces.
| ns == tcName = [dataName, tcName]
| otherwise = [ns]
-- Process an individual child
doOne :: LIEWrappedName GhcPs
- -> RnM (Either (LIEWrappedName GhcRn) (Located FieldLabel))
+ -> RnM (LIEWrappedName GhcRn, GlobalRdrElt)
doOne n = do
let bareName = (ieWrappedName . unLoc) n
@@ -507,18 +524,20 @@ lookupChildrenExport spec_parent rdr_items =
-- messages
let unboundName :: RdrName
unboundName = if rdrNameSpace bareName == varName
- then bareName
- else setRdrNameSpace bareName dataName
+ then bareName
+ else setRdrNameSpace bareName dataName
case name of
- NameNotFound -> do { ub <- reportUnboundName unboundName
- ; let l = getLoc n
- ; return (Left (L l (IEName noExtField (L (la2na l) ub))))}
- FoundChild par child -> do { checkPatSynParent spec_parent par child
- ; return $ case child of
- FieldGreName fl -> Right (L (getLocA n) fl)
- NormalGreName name -> Left (replaceLWrappedName n name)
- }
+ NameNotFound ->
+ do { ub <- reportUnboundName unboundName
+ ; let l = getLoc n
+ gre = localVanillaGRE NoParent ub
+ ; return (L l (IEName noExtField (L (la2na l) ub)), gre)}
+ FoundChild child@(GRE { gre_par = par }) ->
+ do { checkPatSynParent spec_parent par child
+ ; let child_nm = greName child
+ ; return (replaceLWrappedName n child_nm, child)
+ }
IncorrectParent p c gs -> failWithDcErr p c gs
@@ -582,30 +601,32 @@ lookupChildrenExport spec_parent rdr_items =
checkPatSynParent :: Name -- ^ Alleged parent type constructor
-- User wrote T( P, Q )
-> Parent -- The parent of P we discovered
- -> GreName -- ^ Either a
- -- a) Pattern Synonym Constructor
- -- b) A pattern synonym selector
+ -> GlobalRdrElt
+ -- ^ Either a
+ -- a) Pattern Synonym Constructor
+ -- b) A pattern synonym selector
-> TcM () -- Fails if wrong parent
checkPatSynParent _ (ParentIs {}) _
= return ()
-checkPatSynParent parent NoParent gname
+checkPatSynParent parent NoParent gre
| isUnboundName parent -- Avoid an error cascade
= return ()
| otherwise
- = do { parent_ty_con <- tcLookupTyCon parent
- ; mpat_syn_thing <- tcLookupGlobal (greNameMangledName gname)
+ = do { parent_ty_con <- tcLookupTyCon parent
+ ; let nm = greName gre
+ ; mpat_syn_thing <- tcLookupGlobal nm
-- 1. Check that the Id was actually from a thing associated with patsyns
; case mpat_syn_thing of
AnId i | isId i
, RecSelId { sel_tycon = RecSelPatSyn p } <- idDetails i
- -> handle_pat_syn (selErr gname) parent_ty_con p
+ -> handle_pat_syn (selErr nm) parent_ty_con p
AConLike (PatSynCon p) -> handle_pat_syn (psErr p) parent_ty_con p
- _ -> failWithDcErr parent gname [] }
+ _ -> failWithDcErr parent gre [] }
where
psErr = exportErrCtxt "pattern synonym"
selErr = exportErrCtxt "pattern synonym record selector"
@@ -641,73 +662,65 @@ checkPatSynParent parent NoParent gname
{-===========================================================================-}
-check_occs :: IE GhcPs -> ExportOccMap -> [AvailInfo]
- -> RnM ExportOccMap
-check_occs ie occs avails
- -- 'avails' are the entities specified by 'ie'
- = foldlM check occs children
+
+-- | Check that the each of the given 'GlobalRdrElt's does not appear multiple
+-- times in the 'ExportOccMap', as per Note [Exporting duplicate declarations].
+check_occs :: ExportOccMap -> IE GhcPs -> [GlobalRdrElt] -> RnM ExportOccMap
+check_occs occs ie gres
+ -- 'gres' are the entities specified by 'ie'
+ = do { drf <- xoptM LangExt.DuplicateRecordFields
+ ; foldlM (check drf) occs gres }
where
- children = concatMap availGreNames avails
-- Check for distinct children exported with the same OccName (an error) or
-- for duplicate exports of the same child (a warning).
- check :: ExportOccMap -> GreName -> RnM ExportOccMap
- check occs child
- = case try_insert occs child of
- Right occs' -> return occs'
+ --
+ -- See Note [Exporting duplicate declarations].
+ check :: Bool -> ExportOccMap -> GlobalRdrElt -> RnM ExportOccMap
+ check drf_enabled occs gre
+ = case try_insert occs gre of
+ Right occs'
+ -- If DuplicateRecordFields is not enabled, also make sure
+ -- that we are not exporting two fields with the same occNameFS
+ -- under different namespaces.
+ --
+ -- See Note [Exporting duplicate record fields].
+ | drf_enabled || not (isFieldOcc child_occ)
+ -> return occs'
+ | otherwise
+ -> do { let flds = filter (\(_,ie') -> not $ dupFieldExport_ok ie ie')
+ $ lookupFieldsOccEnv occs (occNameFS child_occ)
+ ; case flds of { [] -> return occs'; clash1:clashes ->
+ do { addDuplicateFieldExportErr (gre,ie) (clash1 NE.:| clashes)
+ ; return occs } } }
Left (child', ie')
- | greNameMangledName child == greNameMangledName child' -- Duplicate export
- -- But we don't want to warn if the same thing is exported
- -- by two different module exports. See ticket #4478.
- -> do { warnIf (not (dupExport_ok child ie ie')) (TcRnDuplicateExport child ie ie')
+ | child == child' -- Duplicate export of a single Name: a warning.
+ -> do { warnIf (not (dupExport_ok child ie ie')) (TcRnDuplicateExport gre ie ie')
; return occs }
- | otherwise -- Same occ name but different names: an error
- -> do { global_env <- getGlobalRdrEnv ;
- addErr (exportClashErr global_env child' child ie' ie) ;
- return occs }
+ | otherwise -- Same OccName but different Name: an error.
+ -> do { global_env <- getGlobalRdrEnv
+ ; addErr (exportClashErr global_env child' child ie' ie)
+ ; return occs }
+ where
+ child = greName gre
+ child_occ = occName child
-- Try to insert a child into the map, returning Left if there is something
- -- already exported with the same OccName
- try_insert :: ExportOccMap -> GreName -> Either (GreName, IE GhcPs) ExportOccMap
+ -- already exported with the same OccName.
+ try_insert :: ExportOccMap -> GlobalRdrElt -> Either (Name, IE GhcPs) ExportOccMap
try_insert occs child
- = case lookupOccEnv occs name_occ of
- Nothing -> Right (extendOccEnv occs name_occ (child, ie))
+ = case lookupOccEnv occs occ of
+ Nothing -> Right (extendOccEnv occs occ (greName child, ie))
Just x -> Left x
where
- -- For fields, we check for export clashes using the (OccName of the)
- -- selector Name
- name_occ = nameOccName (greNameMangledName child)
-
+ occ = greOccName child
-dupExport_ok :: GreName -> IE GhcPs -> IE GhcPs -> Bool
--- The GreName is exported by both IEs. Is that ok?
--- "No" iff the name is mentioned explicitly in both IEs
--- or one of the IEs mentions the name *alone*
--- "Yes" otherwise
---
--- Examples of "no": module M( f, f )
--- module M( fmap, Functor(..) )
--- module M( module Data.List, head )
---
--- Example of "yes"
--- module M( module A, module B ) where
--- import A( f )
--- import B( f )
+-- | Is it OK for the given name to be exported by both export items?
--
--- Example of "yes" (#2436)
--- module M( C(..), T(..) ) where
--- class C a where { data T a }
--- instance C Int where { data T Int = TInt }
---
--- Example of "yes" (#2436)
--- module Foo ( T ) where
--- data family T a
--- module Bar ( T(..), module Foo ) where
--- import Foo
--- data instance T Int = TInt
-
+-- See Note [Exporting duplicate declarations].
+dupExport_ok :: Name -> IE GhcPs -> IE GhcPs -> Bool
dupExport_ok child ie1 ie2
= not ( single ie1 || single ie2
|| (explicit_in ie1 && explicit_in ie2) )
@@ -719,8 +732,7 @@ dupExport_ok child ie1 ie2
single IEVar {} = True
single IEThingAbs {} = True
- single _ = False
-
+ single _ = False
exportErrCtxt :: Outputable o => String -> o -> SDoc
exportErrCtxt herald exp =
@@ -734,18 +746,18 @@ addExportErrCtxt ie = addErrCtxt exportCtxt
exportCtxt = text "In the export:" <+> ppr ie
-failWithDcErr :: Name -> GreName -> [Name] -> TcM a
+failWithDcErr :: Name -> GlobalRdrElt -> [Name] -> TcM a
failWithDcErr parent child parents = do
- ty_thing <- tcLookupGlobal (greNameMangledName child)
+ ty_thing <- tcLookupGlobal (greName child)
failWithTc $ TcRnExportedParentChildMismatch parent ty_thing child parents
exportClashErr :: GlobalRdrEnv
- -> GreName -> GreName
+ -> Name -> Name
-> IE GhcPs -> IE GhcPs
-> TcRnMessage
exportClashErr global_env child1 child2 ie1 ie2
- = TcRnConflictingExports occ child1' gre1' ie1' child2' gre2' ie2'
+ = TcRnConflictingExports occ gre1' ie1' gre2' ie2'
where
occ = occName child1
-- get_gre finds a GRE for the Name, so that we can show its provenance
@@ -753,9 +765,127 @@ exportClashErr global_env child1 child2 ie1 ie2
gre2 = get_gre child2
get_gre child
= fromMaybe (pprPanic "exportClashErr" (ppr child))
- (lookupGRE_GreName global_env child)
- (child1', gre1', ie1', child2', gre2', ie2') =
+ (lookupGRE_Name global_env child)
+ (gre1', ie1', gre2', ie2') =
case SrcLoc.leftmost_smallest (greSrcSpan gre1) (greSrcSpan gre2) of
- LT -> (child1, gre1, ie1, child2, gre2, ie2)
- GT -> (child2, gre2, ie2, child1, gre1, ie1)
+ LT -> (gre1, ie1, gre2, ie2)
+ GT -> (gre2, ie2, gre1, ie1)
EQ -> panic "exportClashErr: clashing exports have identical location"
+
+addDuplicateFieldExportErr :: (GlobalRdrElt, IE GhcPs)
+ -> NE.NonEmpty (Name, IE GhcPs)
+ -> RnM ()
+addDuplicateFieldExportErr gre others
+ = do { rdr_env <- getGlobalRdrEnv
+ ; let lkup = expectJust "addDuplicateFieldExportErr" . lookupGRE_Name rdr_env
+ other_gres = fmap (first lkup) others
+ ; addErr (TcRnDuplicateFieldExport gre other_gres) }
+
+-- | Is it OK to export two clashing duplicate record fields coming from the
+-- given export items, with @-XDisambiguateRecordFields@ disabled?
+--
+-- See Note [Exporting duplicate record fields].
+dupFieldExport_ok :: IE GhcPs -> IE GhcPs -> Bool
+dupFieldExport_ok ie1 ie2
+ | IEModuleContents {} <- ie1
+ , ie2 == ie1
+ = True
+ | otherwise
+ = False
+
+{- Note [Exporting duplicate declarations]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+We want to check that two different export items don't have both attempt to export
+the same thing. What do we mean precisely? There are three main situations to consider:
+
+ 1. We export two distinct Names with identical OccNames. This is an error.
+ 2. We export the same Name in two different export items. This is usually
+ a warning, but see below.
+ 3. We export a duplicate record field, and DuplicateRecordFields is not enabled.
+ See Note [Exporting duplicate record fields].
+
+Concerning (2), we sometimes want to allow a duplicate export of a given Name,
+as #4478 points out. The logic, as implemented in dupExport_ok, is that we
+do not allow a given Name to be exported by two IEs iff either:
+
+ - the Name is mentioned explicitly in both IEs, or
+ - one of the IEs mentions the name *alone*.
+
+Examples:
+
+ NOT OK: module M( f, f )
+
+ f is mentioned explicitly in both
+
+ NOT OK: module M( fmap, Functor(..) )
+ NOT OK: module M( module Data.Functor, fmap )
+
+ One of the import items mentions fmap alone, which is also
+ exported by the other export item.
+
+ OK:
+ module M( module A, module B ) where
+ import A( f )
+ import B( f )
+
+ OK: (#2436)
+ module M( C(..), T(..) ) where
+ class C a where { data T a }
+ instance C Int where { data T Int = TInt }
+
+ OK: (#2436)
+ module Foo ( T ) where
+ data family T a
+ module Bar ( T(..), module Foo ) where
+ import Foo
+ data instance T Int = TInt
+
+Note [Exporting duplicate record fields]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Record fields belonging to different datatypes belong to different namespaces,
+as explained in Note [Record field namespacing] in GHC.Types.Name.Occurrence.
+However, when the DuplicateRecordFields extension is NOT enabled, we want to
+prevent users from exporting record fields that share the same underlying occNameFS.
+
+To enforce this, in check_occs, when inserting a new record field into the ExportOccMap
+and DuplicateRecordFields is not enabled, we also look up any clashing record fields,
+and report an error.
+
+Note however that the clash check has an extra wrinkle, similar to dupExport_ok,
+as we want to allow the following:
+
+ {-# LANGUAGE DuplicateRecordFields #-}
+ module M1 where
+ data D1 = MkD1 { foo :: Int }
+ data D2 = MkD2 { foo :: Bool }
+
+ ---------------------------------------------
+
+ module M2 ( module M1 ) where
+ import M1
+
+That is, we should be allowed to re-export the whole module M1, without reporting
+any nameclashes, even though M1 exports duplicate record fields and we have not
+enabled -XDuplicateRecordFields in M2. This logic is implemented in
+dupFieldExport_ok. See test case NoDRFModuleExport.
+
+Note that this logic only applies to whole-module imports, as we don't want
+to allow the following:
+
+ module N0 where
+ data family D a
+ module N1 where
+ import N0
+ data instance D Int = MkDInt { foo :: Int }
+ module N2 where
+ import N0
+ data instance D Bool = MkDBool { foo :: Int }
+
+ module N (D(..)) where
+ import N1
+ import N2
+
+Here, the single export item D(..) of N exports both record fields,
+`$fld:MkDInt:foo` and `$fld:MkDBool:foo`, so we have to reject the program.
+See test overloadedrecfldsfail10.
+-}
diff --git a/compiler/GHC/Tc/Gen/Expr.hs b/compiler/GHC/Tc/Gen/Expr.hs
index 8ab5ad3d0d..8a7ce396bf 100644
--- a/compiler/GHC/Tc/Gen/Expr.hs
+++ b/compiler/GHC/Tc/Gen/Expr.hs
@@ -27,7 +27,10 @@ module GHC.Tc.Gen.Expr
import GHC.Prelude
-import {-# SOURCE #-} GHC.Tc.Gen.Splice( tcTypedSplice, tcTypedBracket, tcUntypedBracket )
+import Language.Haskell.Syntax.Basic (FieldLabelString(..))
+
+import {-# SOURCE #-} GHC.Tc.Gen.Splice
+ ( tcTypedSplice, tcTypedBracket, tcUntypedBracket )
import GHC.Hs
import GHC.Hs.Syn.Type
@@ -38,7 +41,9 @@ import GHC.Tc.Utils.Unify
import GHC.Types.Basic
import GHC.Types.Error
import GHC.Types.FieldLabel
-import GHC.Types.Unique.Map ( UniqMap, listToUniqMap, lookupUniqMap )
+import GHC.Types.Unique.FM
+import GHC.Types.Unique.Map
+import GHC.Types.Unique.Set
import GHC.Core.Multiplicity
import GHC.Core.UsageEnv
import GHC.Tc.Errors.Types
@@ -50,7 +55,7 @@ import GHC.Tc.Gen.Bind ( tcLocalBinds )
import GHC.Tc.Instance.Family ( tcGetFamInstEnvs )
import GHC.Core.FamInstEnv ( FamInstEnvs )
import GHC.Rename.Expr ( mkExpandedExpr )
-import GHC.Rename.Env ( addUsedGRE )
+import GHC.Rename.Env ( addUsedGRE, getUpdFieldLbls )
import GHC.Tc.Utils.Env
import GHC.Tc.Gen.Arrow
import GHC.Tc.Gen.Match
@@ -62,11 +67,11 @@ import GHC.Types.Id
import GHC.Types.Id.Info
import GHC.Core.ConLike
import GHC.Core.DataCon
-import GHC.Core.PatSyn
import GHC.Types.Name
import GHC.Types.Name.Env
import GHC.Types.Name.Set
import GHC.Types.Name.Reader
+import GHC.Core.Class(classTyCon)
import GHC.Core.TyCon
import GHC.Core.Type
import GHC.Core.Coercion( mkSymCo )
@@ -77,23 +82,16 @@ import GHC.Builtin.Uniques ( mkBuiltinUnique )
import GHC.Driver.Session
import GHC.Types.SrcLoc
import GHC.Utils.Misc
+import GHC.Data.Bag ( unitBag )
import GHC.Data.List.SetOps
import GHC.Data.Maybe
import GHC.Utils.Outputable as Outputable
import GHC.Utils.Panic
import GHC.Utils.Panic.Plain
-import Control.Monad
-import GHC.Core.Class(classTyCon)
-import GHC.Types.Unique.Set ( UniqSet, mkUniqSet, elementOfUniqSet, nonDetEltsUniqSet )
-
-import Language.Haskell.Syntax.Basic (FieldLabelString(..))
-import Data.Function
-import Data.List (partition, sortBy, intersect)
+import Control.Monad
import qualified Data.List.NonEmpty as NE
-import GHC.Data.Bag ( unitBag )
-
{-
************************************************************************
* *
@@ -515,10 +513,17 @@ tcExpr expr@(RecordCon { rcon_con = L loc con_name
-- in the renamer. See Note [Overview of record dot syntax] in
-- GHC.Hs.Expr. This is why we match on 'rupd_flds = Left rbnds' here
-- and panic otherwise.
-tcExpr expr@(RecordUpd { rupd_expr = record_expr, rupd_flds = Left rbnds }) res_ty
+tcExpr expr@(RecordUpd { rupd_expr = record_expr
+ , rupd_flds =
+ RegularRecUpdFields
+ { xRecUpdFields = possible_parents
+ , recUpdFields = rbnds }
+ })
+ res_ty
= assert (notNull rbnds) $
do { -- Desugar the record update. See Note [Record Updates].
- ; (ds_expr, ds_res_ty, err_ctxt) <- desugarRecordUpd record_expr rbnds res_ty
+ ; (ds_expr, ds_res_ty, err_ctxt)
+ <- desugarRecordUpd record_expr possible_parents rbnds res_ty
-- Typecheck the desugared expression.
; expr' <- addErrCtxt err_ctxt $
@@ -534,7 +539,8 @@ tcExpr expr@(RecordUpd { rupd_expr = record_expr, rupd_flds = Left rbnds }) res_
-- Test case: T10808.
}
-tcExpr (RecordUpd {}) _ = panic "tcExpr: unexpected overloaded-dot RecordUpd"
+tcExpr e@(RecordUpd { rupd_flds = OverloadedRecUpdFields {}}) _
+ = pprPanic "tcExpr: unexpected overloaded-dot RecordUpd" $ ppr e
{-
************************************************************************
@@ -888,141 +894,8 @@ in the other order, the extra signature in f2 is reqd.
* *
********************************************************************* -}
-{-
-Note [Type of a record update]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-The main complication with RecordUpd is that we need to explicitly
-handle the *non-updated* fields. Consider:
-
- data T a b c = MkT1 { fa :: a, fb :: (b,c) }
- | MkT2 { fa :: a, fb :: (b,c), fc :: c -> c }
- | MkT3 { fd :: a }
-
- upd :: T a b c -> (b',c) -> T a b' c
- upd t x = t { fb = x}
-
-The result type should be (T a b' c)
-not (T a b c), because 'b' *is not* mentioned in a non-updated field
-not (T a b' c'), because 'c' *is* mentioned in a non-updated field
-NB that it's not good enough to look at just one constructor; we must
-look at them all; cf #3219
-
-After all, upd should be equivalent to:
- upd t x = case t of
- MkT1 p q -> MkT1 p x
- MkT2 a b -> MkT2 p b
- MkT3 d -> error ...
-
-So we need to give a completely fresh type to the result record,
-and then constrain it by the fields that are *not* updated ("p" above).
-We call these the "fixed" type variables, and compute them in getFixedTyVars.
-
-Note that because MkT3 doesn't contain all the fields being updated,
-its RHS is simply an error, so it doesn't impose any type constraints.
-Hence the use of 'relevant_cont'.
-
-Note [Implicit type sharing]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-We also take into account any "implicit" non-update fields. For example
- data T a b where { MkT { f::a } :: T a a; ... }
-So the "real" type of MkT is: forall ab. (a~b) => a -> T a b
-
-Then consider
- upd t x = t { f=x }
-We infer the type
- upd :: T a b -> a -> T a b
- upd (t::T a b) (x::a)
- = case t of { MkT (co:a~b) (_:a) -> MkT co x }
-We can't give it the more general type
- upd :: T a b -> c -> T c b
-
-Note [Criteria for update]
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-We want to allow update for existentials etc, provided the updated
-field isn't part of the existential. For example, this should be ok.
- data T a where { MkT { f1::a, f2::b->b } :: T a }
- f :: T a -> b -> T b
- f t b = t { f1=b }
-
-The criterion we use is this:
-
- The types of the updated fields
- mention only the universally-quantified type variables
- of the data constructor
-
-NB: this is not (quite) the same as being a "naughty" record selector
-(See Note [Naughty record selectors]) in GHC.Tc.TyCl), at least
-in the case of GADTs. Consider
- data T a where { MkT :: { f :: a } :: T [a] }
-Then f is not "naughty" because it has a well-typed record selector.
-But we don't allow updates for 'f'. (One could consider trying to
-allow this, but it makes my head hurt. Badly. And no one has asked
-for it.)
-
-In principle one could go further, and allow
- g :: T a -> T a
- g t = t { f2 = \x -> x }
-because the expression is polymorphic...but that seems a bridge too far.
-
-Note [Data family example]
-~~~~~~~~~~~~~~~~~~~~~~~~~~
- data instance T (a,b) = MkT { x::a, y::b }
- --->
- data :TP a b = MkT { a::a, y::b }
- coTP a b :: T (a,b) ~ :TP a b
-
-Suppose r :: T (t1,t2), e :: t3
-Then r { x=e } :: T (t3,t1)
- --->
- case r |> co1 of
- MkT x y -> MkT e y |> co2
- where co1 :: T (t1,t2) ~ :TP t1 t2
- co2 :: :TP t3 t2 ~ T (t3,t2)
-The wrapping with co2 is done by the constructor wrapper for MkT
-
-Outgoing invariants
-~~~~~~~~~~~~~~~~~~~
-In the outgoing (HsRecordUpd scrut binds cons in_inst_tys out_inst_tys):
-
- * cons are the data constructors to be updated
-
- * in_inst_tys, out_inst_tys have same length, and instantiate the
- *representation* tycon of the data cons. In Note [Data
- family example], in_inst_tys = [t1,t2], out_inst_tys = [t3,t2]
-
-Note [Mixed Record Field Updates]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Consider the following pattern synonym.
-
- data MyRec = MyRec { foo :: Int, qux :: String }
-
- pattern HisRec{f1, f2} = MyRec{foo = f1, qux=f2}
-
-This allows updates such as the following
-
- updater :: MyRec -> MyRec
- updater a = a {f1 = 1 }
-
-It would also make sense to allow the following update (which we reject).
-
- updater a = a {f1 = 1, qux = "two" } ==? MyRec 1 "two"
-
-This leads to confusing behaviour when the selectors in fact refer the same
-field.
-
- updater a = a {f1 = 1, foo = 2} ==? ???
-
-For this reason, we reject a mixture of pattern synonym and normal record
-selectors in the same update block. Although of course we still allow the
-following.
-
- updater a = (a {f1 = 1}) {foo = 2}
-
- > updater (MyRec 0 "str")
- MyRec 2 "str"
-
-Note [Record Updates]
-~~~~~~~~~~~~~~~~~~~~~
+{- Note [Record Updates]
+~~~~~~~~~~~~~~~~~~~~~~~~
To typecheck a record update, we desugar it first. Suppose we have
data T p q = T1 { x :: Int, y :: Bool, z :: Char }
| T2 { v :: Char }
@@ -1041,74 +914,114 @@ T2, T3 and T5 should not occur, so we omit them from the match.
The critical part of desugaring is to identify T and then T1/T4.
Wrinkle [Disambiguating fields]
-As outlined above, to typecheck a record update via desugaring, we first need
-to identify the parent record `TyCon` (`T` above). This can be tricky when several
-record types share the same field (with `-XDuplicateRecordFields`).
-Currently, we use the inferred type of the record to help disambiguate the record
-fields. For example, in
+ As explained in Note [Disambiguating record updates] in GHC.Rename.Pat,
+ to typecheck a record update we first need to disambiguate the field labels,
+ in order to find a parent which has at least one constructor with all of the fields
+ being updated.
- ( mempty :: T a b ) { x = 3 }
+ As mentioned in Note [Type-directed record disambiguation], we sometimes use
+ type-directed disambiguation, although this mechanism is deprecated and
+ scheduled for removal via the implementation of GHC proposal #366
+ https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0366-no-ambiguous-field-access.rst.
-the type signature on `mempty` allows us to disambiguate the record `TyCon` to `T`,
-when there might be other datatypes with field `x :: Int`.
-This complexity is scheduled for removal via the implementation of GHC proposal #366
-https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0366-no-ambiguous-field-access.rst
-However, for the time being, we still need to disambiguate record fields using the
-inferred types. This means that, when typechecking a record update via desugaring,
-we need to do the following:
+All in all, this means that when typechecking a record update via desugaring,
+we take the following steps:
- D1. Perform a first typechecking pass on the record expression (`e` in the example above),
+ (0) Perform a first typechecking pass on the record expression (`e` in the example above),
to infer the type of the record being updated.
- D2. Desugar the record update as described above, using an HsExpansion.
- D3. Typecheck the desugared code.
-
-In (D1), we call inferRho to infer the type of the record being updated. This returns the
+ (1) Disambiguate the record fields (potentially using the type obtained in (0)).
+ (2) Desugar the record update as described above, using an HsExpansion.
+ (a) Create a let-binding to share the record update right-hand sides.
+ (b) Desugar the record update to a case expression updating all the
+ relevant constructors (those that have all of the fields being updated).
+ (3) Typecheck the desugared code.
+
+In (0), we call inferRho to infer the type of the record being updated. This returns the
inferred type of the record, together with a typechecked expression (of type HsExpr GhcTc)
and a collection of residual constraints.
We have no need for the latter two, because we will typecheck again in (D3). So, for
the time being (and until GHC proposal #366 is implemented), we simply drop them.
Wrinkle [Using IdSig]
-As noted above, we want to let-bind the updated fields to avoid code duplication:
- let { x' = e1; y' = e2 } in
- case e of
- T1 _ _ z -> T1 x' y' z
- T4 p _ _ -> T4 p y' x'
+ As noted above, we want to let-bind the updated fields to avoid code duplication:
+
+ let { x' = e1; y' = e2 } in
+ case e of
+ T1 _ _ z -> T1 x' y' z
+ T4 p _ _ -> T4 p y' x'
+
+ However, doing so in a naive way would cause difficulties for type inference.
+ For example:
+
+ data R b = MkR { f :: (forall a. a -> a) -> (Int,b), c :: Int }
+ foo r = r { f = \ k -> (k 3, k 'x') }
+
+ If we desugar to:
+
+ ds_foo r =
+ let f' = \ k -> (k 3, k 'x')
+ in case r of
+ MkR _ b -> MkR f' b
+
+ then we are unable to infer an appropriately polymorphic type for f', because we
+ never infer higher-rank types. To circumvent this problem, we proceed as follows:
-However, doing so in a naive way would cause difficulties for type inference.
-For example:
+ 1. Obtain general field types by instantiating any of the constructors
+ that contain all the necessary fields. (Note that the field type must be
+ identical across different constructors of a given data constructor).
+ 2. Let-bind an 'IdSig' with this type. This amounts to giving the let-bound
+ 'Id's a partial type signature.
- data R b = MkR { f :: (forall a. a -> a) -> (Int,b), c :: Int }
- foo r = r { f = \ k -> (k 3, k 'x') }
+ In the above example, it's as if we wrote:
-If we desugar to:
+ ds_foo r =
+ let f' :: (forall a. a -> a) -> (Int, _b)
+ f' = \ k -> (k 3, k 'x')
+ in case r of
+ MkR _ b -> MkR f' b
- ds_foo r =
- let f' = \ k -> (k 3, k 'x')
- in case r of
- MkR _ b -> MkR f' b
+ This allows us to compute the right type for f', and thus accept this record update.
-then we are unable to infer an appropriately polymorphic type for f', because we
-never infer higher-rank types. To circumvent this problem, we proceed as follows:
+Note [Type-directed record disambiguation]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+GHC currently supports an additional type-directed disambiguation
+mechanism, which is deprecated and scheduled for removal as part of
+GHC proposal #366 https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0366-no-ambiguous-field-access.rst.
- 1. Obtain general field types by instantiating any of the constructors
- that contain all the necessary fields. (Note that the field type must be
- identical across different constructors of a given data constructor).
- 2. Let-bind an 'IdSig' with this type. This amounts to giving the let-bound
- 'Id's a partial type signature.
+To perform this disambiguation, when there are multiple possible parents for
+a record update, the renamer defers to the typechecker.
+See GHC.Tc.Gen.Expr.disambiguateRecordBinds, and in particular the auxiliary
+function identifyParentLabels, which picks a parent for the record update
+using the following additional mechanisms:
-In the above example, it's as if we wrote:
+ (a) Use the type being pushed in, if it is already a TyConApp. The
+ following are valid updates at type `R`:
- ds_foo r =
- let f' :: (forall a. a -> a) -> (Int, _b)
- f' = \ k -> (k 3, k 'x')
- in case r of
- MkR _ b -> MkR f' b
+ g :: R -> R
+ g x = x { fld1 = 3 }
-This allows us to compute the right type for f', and thus accept this record update.
+ g' x = x { fld1 = 3 } :: R
+
+ (b) Use the type signature of the record expression, if it exists and
+ is a TyConApp. Thus this is valid update at type `R`:
+
+ h x = (x :: R) { fld1 = 3 }
+
+Note that this type-directed disambiguation mechanism isn't very robust,
+as it doesn't properly integrate with the rest of the typechecker.
+For example, the following updates will all be rejected as ambiguous:
+
+ let r :: R
+ r = blah
+ in r { foo = 3 }
+
+ \r. (r { foo = 3 }, r :: R)
+
+Record updates which require constraint-solving should instead use the
+-XOverloadedRecordUpdate extension, as described in Note [Overview of record dot syntax].
Note [Unifying result types in tcRecordUpd]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1165,7 +1078,10 @@ Wrinkle [GADT result type in tcRecordUpd]
-- result type of this desugared record update.
desugarRecordUpd :: LHsExpr GhcRn
-- ^ @record_expr@: expression to which the record update is applied
- -> [LHsRecUpdField GhcRn]
+ -> NE.NonEmpty (HsRecUpdParent GhcRn)
+ -- ^ Possible parent 'TyCon'/'PatSyn's for the record update,
+ -- with the associated constructors and field labels
+ -> [LHsRecUpdField GhcRn GhcRn]
-- ^ the record update fields
-> ExpRhoType
-- ^ the expected result type of the record update
@@ -1177,8 +1093,9 @@ desugarRecordUpd :: LHsExpr GhcRn
-- error context to push when typechecking
-- the desugared code
)
-desugarRecordUpd record_expr rbnds res_ty
- = do { -- STEP -2: typecheck the record_expr, the record to be updated
+desugarRecordUpd record_expr possible_parents rbnds res_ty
+ = do { -- STEP 0: typecheck the record_expr, the record to be updated.
+ --
-- Until GHC proposal #366 is implemented, we still use the type of
-- the record to disambiguate its fields, so we must infer the record
-- type here before we can desugar. See Wrinkle [Disambiguating fields]
@@ -1209,73 +1126,36 @@ desugarRecordUpd record_expr rbnds res_ty
--
-- This should definitely *not* typecheck.
- -- STEP -1 See Note [Disambiguating record fields] in GHC.Tc.Gen.Head
- -- After this we know that rbinds is unambiguous
- ; rbinds <- disambiguateRecordBinds record_expr record_rho rbnds res_ty
+ -- STEP 1: disambiguate the record update by computing a single parent
+ -- which has a constructor with all of the fields being updated.
+ --
+ -- See Note [Disambiguating record updates] in GHC.Rename.Pat.
+ ; (cons, rbinds)
+ <- disambiguateRecordBinds record_expr record_rho possible_parents rbnds res_ty
; let upd_flds = map (unLoc . hfbLHS . unLoc) rbinds
- upd_fld_occs = map (FieldLabelString . occNameFS . rdrNameOcc . rdrNameAmbiguousFieldOcc) upd_flds
sel_ids = map selectorAmbiguousFieldOcc upd_flds
upd_fld_names = map idName sel_ids
+ relevant_cons = nonDetEltsUniqSet cons
+ relevant_con = head relevant_cons
- -- STEP 0
- -- Check that the field names are really field names
- -- and they are all field names for proper records or
- -- all field names for pattern synonyms.
- ; let bad_guys = [ setSrcSpan loc $ addErrTc (notSelector fld_name)
- | fld <- rbinds,
- -- Excludes class ops
- let L loc sel_id = hsRecUpdFieldId (unLoc fld),
- not (isRecordSelector sel_id),
- let fld_name = idName sel_id ]
- ; unless (null bad_guys) (sequence bad_guys >> failM)
- -- See Note [Mixed Record Field Updates]
- ; let (data_sels, pat_syn_sels) =
- partition isDataConRecordSelector sel_ids
- ; massert (all isPatSynRecordSelector pat_syn_sels)
- ; checkTc ( null data_sels || null pat_syn_sels )
- ( mixedSelectors data_sels pat_syn_sels )
-
- -- STEP 1
- -- Figure out the tycon and data cons from the first field name
- ; let -- It's OK to use the non-tc splitters here (for a selector)
- sel_id : _ = sel_ids
- con_likes :: [ConLike]
- con_likes = case idDetails sel_id of
- RecSelId (RecSelData tc) _
- -> map RealDataCon (tyConDataCons tc)
- RecSelId (RecSelPatSyn ps) _
- -> [PatSynCon ps]
- _ -> panic "tcRecordUpd"
- -- NB: for a data type family, the tycon is the instance tycon
- relevant_cons = conLikesWithFields con_likes upd_fld_occs
- -- A constructor is only relevant to this process if
- -- it contains *all* the fields that are being updated
- -- Other ones will cause a runtime error if they occur
-
- -- STEP 2
- -- Check that at least one constructor has all the named fields
- -- i.e. has an empty set of bad fields returned by badFields
- ; case relevant_cons of
- { [] -> failWithTc (badFieldsUpd rbinds con_likes)
- ; relevant_con : _ ->
-
- -- STEP 3
- -- Create new variables for the fields we are updating,
- -- so that we can share them across constructors.
+ -- STEP 2: desugar the record update.
+ --
+ -- (a) Create new variables for the fields we are updating,
+ -- so that we can share them across constructors.
--
- -- Example:
+ -- Example:
--
- -- e { x=e1, y=e2 }
+ -- e { x=e1, y=e2 }
--
- -- We want to let-bind variables to `e1` and `e2`:
+ -- We want to let-bind variables to `e1` and `e2`:
--
- -- let x' :: Int
- -- x' = e1
- -- y' :: Bool
- -- y' = e2
- -- in ...
+ -- let x' :: Int
+ -- x' = e1
+ -- y' :: Bool
+ -- y' = e2
+ -- in ...
- do { -- Instantiate the type variables of any relevant constuctor
+ -- Instantiate the type variables of any relevant constuctor
-- with metavariables to obtain a type for each 'Id'.
-- This will allow us to have 'Id's with polymorphic types
-- by using 'IdSig'. See Wrinkle [Using IdSig] in Note [Record Updates].
@@ -1318,6 +1198,10 @@ desugarRecordUpd record_expr rbnds res_ty
(conLikeFieldLabels relevant_con)
arg_tys
+ ; traceTc "tcRecordUpd" $
+ vcat [ text "upd_fld_names:" <+> ppr upd_fld_names
+ , text "relevant_cons:" <+> ppr relevant_cons ]
+
; upd_ids <- zipWithM mk_upd_id upd_fld_names rbinds
; let updEnv :: UniqMap Name (Id, LHsExpr GhcRn)
updEnv = listToUniqMap $ upd_ids
@@ -1360,12 +1244,11 @@ desugarRecordUpd record_expr rbnds res_ty
Just (upd_id, _) -> (genWildPat, genLHsVar (idName upd_id))
-- Field is not being updated: LHS = variable pattern, RHS = that same variable.
_ -> let fld_nm = mkInternalName (mkBuiltinUnique i)
- (mkVarOccFS (field_label $ flLabel fld_lbl))
+ (nameOccName $ flSelector $ fld_lbl)
generatedSrcSpan
in (genVarPat fld_nm, genLHsVar fld_nm)
- -- STEP 4
- -- Desugar to HsCase, as per note [Record Updates]
+ -- STEP 2 (b): desugar to HsCase, as per note [Record Updates]
; let ds_expr :: HsExpr GhcRn
ds_expr = HsLet noExtField noHsTok let_binds noHsTok (L gen case_expr)
@@ -1407,7 +1290,7 @@ desugarRecordUpd record_expr rbnds res_ty
else [ text "existential variable" <> plural ex_tvs <+> pprQuotedList ex_tvs ]
err_ctxt = make_lines_msg err_lines
- ; return (ds_expr, ds_res_ty, err_ctxt) } } }
+ ; return (ds_expr, ds_res_ty, err_ctxt) }
-- | Pretty-print a collection of lines, adding commas at the end of each line,
-- and adding "and" to the start of the last line.
@@ -1421,118 +1304,144 @@ make_lines_msg (l:ls) = l <> comma $$ make_lines_msg ls
* *
Record bindings
* *
-********************************************************************* -}
+**********************************************************************-}
--- Disambiguate the fields in a record update.
--- See Note [Disambiguating record fields] in GHC.Tc.Gen.Head
+-- | Disambiguate the fields in a record update.
+--
+-- Most of the disambiguation has been done by the renamer; this function
+-- performs a final type-directed disambiguation pass, as explained in
+-- Note [Type-directed record disambiguation].
disambiguateRecordBinds :: LHsExpr GhcRn -> TcRhoType
- -> [LHsRecUpdField GhcRn] -> ExpRhoType
- -> TcM [LHsFieldBind GhcTc (LAmbiguousFieldOcc GhcTc) (LHsExpr GhcRn)]
-disambiguateRecordBinds record_expr record_rho rbnds res_ty
- -- Are all the fields unambiguous?
- = case mapM isUnambiguous rbnds of
- -- If so, just skip to looking up the Ids
- -- Always the case if DuplicateRecordFields is off
- Just rbnds' -> mapM lookupSelector rbnds'
- Nothing -> -- If not, try to identify a single parent
- do { fam_inst_envs <- tcGetFamInstEnvs
- -- Look up the possible parents for each field
- ; rbnds_with_parents <- getUpdFieldsParents
- ; let possible_parents = map (map fst . snd) rbnds_with_parents
- -- Identify a single parent
- ; p <- identifyParent fam_inst_envs possible_parents
- -- Pick the right selector with that parent for each field
- ; checkNoErrs $ mapM (pickParent p) rbnds_with_parents }
+ -> NE.NonEmpty (HsRecUpdParent GhcRn)
+ -> [LHsRecUpdField GhcRn GhcRn] -> ExpRhoType
+ -> TcM (UniqSet ConLike, [LHsRecUpdField GhcTc GhcRn])
+disambiguateRecordBinds record_expr record_rho possible_parents rbnds res_ty
+ = do { fam_inst_envs <- tcGetFamInstEnvs
+ -- Identify a single parent, using type-directed disambiguation
+ -- if necessary. (Note that type-directed disambiguation of
+ -- record field updates is is scheduled for removal, as per
+ -- Note [Type-directed record disambiguation].)
+ ; TcRecUpdParent
+ { tcRecUpdLabels = lbls
+ , tcRecUpdCons = cons }
+ <- identifyParentLabels fam_inst_envs possible_parents
+ -- Pick the right selector with that parent for each field
+ ; rbnds' <- zipWithM lookupField (NE.toList lbls) rbnds
+ ; return (cons, rbnds') }
where
- -- Extract the selector name of a field update if it is unambiguous
- isUnambiguous :: LHsRecUpdField GhcRn -> Maybe (LHsRecUpdField GhcRn,Name)
- isUnambiguous x = case unLoc (hfbLHS (unLoc x)) of
- Unambiguous sel_name _ -> Just (x, sel_name)
- Ambiguous{} -> Nothing
-
- -- Look up the possible parents and selector GREs for each field
- getUpdFieldsParents :: TcM [(LHsRecUpdField GhcRn
- , [(RecSelParent, GlobalRdrElt)])]
- getUpdFieldsParents
- = fmap (zip rbnds) $ mapM
- (lookupParents False . unLoc . hsRecUpdFieldRdr . unLoc)
- rbnds
-
- -- Given a the lists of possible parents for each field,
- -- identify a single parent
- identifyParent :: FamInstEnvs -> [[RecSelParent]] -> TcM RecSelParent
- identifyParent fam_inst_envs possible_parents
- = case foldr1 intersect possible_parents of
- -- No parents for all fields: record update is ill-typed
- [] -> failWithTc (TcRnNoPossibleParentForFields rbnds)
-
- -- Exactly one datatype with all the fields: use that
- [p] -> return p
-
- -- Multiple possible parents: try harder to disambiguate
+
+ -- Try to identify a single parent, using type-directed disambiguation.
+ --
+ -- Any non-type-directed disambiguation will have been done already.
+ -- See GHC.Rename.Env.lookupRecUpdFields.
+ identifyParentLabels :: FamInstEnvs
+ -> NE.NonEmpty (HsRecUpdParent GhcRn)
+ -> TcM (HsRecUpdParent GhcTc)
+ identifyParentLabels fam_inst_envs possible_parents
+ = case possible_parents of
+
+ -- Exactly one possible parent for the record update!
+ p NE.:| [] -> lookup_parent_flds p
+
+ -- Multiple possible parents: try harder to disambiguate.
-- Can we get a parent TyCon from the pushed-in type?
- _:_ | Just p <- tyConOfET fam_inst_envs res_ty ->
- do { reportAmbiguousField p
- ; return (RecSelData p) }
+ --
+ -- See (a) in Note [Type-directed record disambiguation] in GHC.Rename.Pat.
+ _ NE.:| _ : _
+ | Just tc <- tyConOfET fam_inst_envs res_ty
+ -> do { reportAmbiguousUpdate possible_parents tc
+ ; try_disambiguated_tycon tc possible_parents }
-- Does the expression being updated have a type signature?
- -- If so, try to extract a parent TyCon from it
- | Just {} <- obviousSig (unLoc record_expr)
- , Just tc <- tyConOf fam_inst_envs record_rho
- -> do { reportAmbiguousField tc
- ; return (RecSelData tc) }
+ -- If so, try to extract a parent TyCon from it.
+ --
+ -- See (b) inNote [Type-directed record disambiguation] in GHC.Rename.Pat.
+ | Just {} <- obviousSig (unLoc record_expr)
+ , Just tc <- tyConOf fam_inst_envs record_rho
+ -> do { reportAmbiguousUpdate possible_parents tc
+ ; try_disambiguated_tycon tc possible_parents }
-- Nothing else we can try...
- _ -> failWithTc (TcRnBadOverloadedRecordUpdate rbnds)
-
- -- Make a field unambiguous by choosing the given parent.
- -- Emits an error if the field cannot have that parent,
- -- e.g. if the user writes
- -- r { x = e } :: T
- -- where T does not have field x.
- pickParent :: RecSelParent
- -> (LHsRecUpdField GhcRn, [(RecSelParent, GlobalRdrElt)])
- -> TcM (LHsFieldBind GhcTc (LAmbiguousFieldOcc GhcTc) (LHsExpr GhcRn))
- pickParent p (upd, xs)
- = case lookup p xs of
- -- Phew! The parent is valid for this field.
- -- Previously ambiguous fields must be marked as
- -- used now that we know which one is meant, but
- -- unambiguous ones shouldn't be recorded again
- -- (giving duplicate deprecation warnings).
- Just gre -> do { unless (null (tail xs)) $ do
- let L loc _ = hfbLHS (unLoc upd)
- setSrcSpanA loc $ addUsedGRE True gre
- ; lookupSelector (upd, greMangledName gre) }
- -- The field doesn't belong to this parent, so report
- -- an error but keep going through all the fields
- Nothing -> do { addErrTc (fieldNotInType p
- (unLoc (hsRecUpdFieldRdr (unLoc upd))))
- ; lookupSelector (upd, greMangledName (snd (head xs))) }
-
- -- Given a (field update, selector name) pair, look up the
- -- selector to give a field update with an unambiguous Id
- lookupSelector :: (LHsRecUpdField GhcRn, Name)
- -> TcM (LHsFieldBind GhcRn (LAmbiguousFieldOcc GhcTc) (LHsExpr GhcRn))
- lookupSelector (L l upd, n)
- = do { i <- tcLookupId n
+ p1 NE.:| p2 : ps
+ -> do { p1 <- tcLookupRecSelParent p1
+ ; p2 <- tcLookupRecSelParent p2
+ ; ps <- mapM tcLookupRecSelParent ps
+ ; failWithTc $ TcRnBadRecordUpdate (getUpdFieldLbls rbnds)
+ $ MultiplePossibleParents (p1, p2, ps) }
+
+ -- Try to use the 'TyCon' we learned from type-directed disambiguation.
+ -- This might not work, if it doesn't match up with any of the parents we had
+ -- computed on the basis of the field labels.
+ -- (See test cases overloadedrecfields01 and T21946.)
+ try_disambiguated_tycon :: TyCon
+ -> NE.NonEmpty (HsRecUpdParent GhcRn)
+ -> TcM (HsRecUpdParent GhcTc)
+ try_disambiguated_tycon tc pars
+ = do { pars <- mapMaybeM (fmap (guard_parent tc) . lookup_parent_flds) (NE.toList pars)
+ ; case pars of
+ [par] -> return par
+ [] -> do { pars <- mapM tcLookupRecSelParent possible_parents
+ ; failWithTc $ TcRnBadRecordUpdate (getUpdFieldLbls rbnds)
+ $ InvalidTyConParent tc pars }
+ _ -> pprPanic "try_disambiguated_tycon: more than 1 valid parent"
+ (ppr $ map tcRecUpdParent pars) }
+
+ guard_parent :: TyCon -> HsRecUpdParent GhcTc -> Maybe (HsRecUpdParent GhcTc)
+ guard_parent disamb_tc cand_parent@(TcRecUpdParent { tcRecUpdParent = cand_tc })
+ = do { guard (RecSelData disamb_tc == cand_tc)
+ ; return cand_parent }
+
+ lookup_parent_flds :: HsRecUpdParent GhcRn
+ -> TcM (HsRecUpdParent GhcTc)
+ lookup_parent_flds par@(RnRecUpdParent { rnRecUpdLabels = lbls, rnRecUpdCons = cons })
+ = do { let cons' :: NonDetUniqFM ConLike ConLikeName
+ cons' = NonDetUniqFM $ unsafeCastUFMKey $ getUniqSet cons
+ ; cons <- traverse (tcLookupConLike . conLikeName_Name) cons'
+ ; tc <- tcLookupRecSelParent par
+ ; return $
+ TcRecUpdParent
+ { tcRecUpdParent = tc
+ , tcRecUpdLabels = lbls
+ , tcRecUpdCons = unsafeUFMToUniqSet $ getNonDet cons } }
+
+ lookupField :: FieldGlobalRdrElt
+ -> LHsRecUpdField GhcRn GhcRn
+ -> TcM (LHsRecUpdField GhcTc GhcRn)
+ lookupField fl (L l upd)
+ = do { let L loc af = hfbLHS upd
+ rdr = ambiguousFieldOccRdrName af
+ mb_gre = pickGREs rdr [fl]
+ -- NB: this GRE can be 'Nothing' when in GHCi.
+ -- See test T10439.
+
+ -- Mark the record fields as used, now that we have disambiguated.
+ -- There is no risk of duplicate deprecation warnings, as we have
+ -- not marked the GREs as used previously.
+ ; setSrcSpanA loc $ mapM_ (addUsedGRE True) mb_gre
+ ; sel <- tcLookupId $ flSelector $ fieldGRELabel fl
; let L loc af = hfbLHS upd
- lbl = rdrNameAmbiguousFieldOcc af
+ lbl = ambiguousFieldOccRdrName af
; return $ L l HsFieldBind
{ hfbAnn = hfbAnn upd
- , hfbLHS
- = L (l2l loc) (Unambiguous i (L (l2l loc) lbl))
+ , hfbLHS = L (l2l loc) $ Unambiguous sel (L (l2l loc) lbl)
, hfbRHS = hfbRHS upd
, hfbPun = hfbPun upd
- }
- }
-
- -- See Note [Deprecating ambiguous fields] in GHC.Tc.Gen.Head
- reportAmbiguousField :: TyCon -> TcM ()
- reportAmbiguousField parent_type =
- setSrcSpan loc $ addDiagnostic $ TcRnAmbiguousField rupd parent_type
+ } }
+
+ -- The type-directed disambiguation mechanism is scheduled for removal,
+ -- as per Note [Type-directed record disambiguation].
+ -- So we emit a warning whenever the user relies on it.
+ reportAmbiguousUpdate :: NE.NonEmpty (HsRecUpdParent GhcRn)
+ -> TyCon -> TcM ()
+ reportAmbiguousUpdate parents parent_type =
+ setSrcSpan loc $ addDiagnostic $ TcRnAmbiguousRecordUpdate rupd parent_type
where
- rupd = RecordUpd { rupd_expr = record_expr, rupd_flds = Left rbnds, rupd_ext = noExtField }
+ rupd = RecordUpd { rupd_expr = record_expr
+ , rupd_flds =
+ RegularRecUpdFields
+ { xRecUpdFields = parents
+ , recUpdFields = rbnds }
+ , rupd_ext = noExtField }
loc = getLocA (head rbnds)
{-
@@ -1574,14 +1483,15 @@ tcRecordBinds con_like arg_tys (HsRecFields rbinds dd)
= do { mb <- tcRecordField con_like flds_w_tys f rhs
; case mb of
Nothing -> return Nothing
- -- Just (f', rhs') -> return (Just (L l (fld { hfbLHS = f'
- -- , hfbRHS = rhs' }))) }
Just (f', rhs') -> return (Just (L l (HsFieldBind
{ hfbAnn = hfbAnn fld
, hfbLHS = f'
, hfbRHS = rhs'
, hfbPun = hfbPun fld}))) }
+fieldCtxt :: FieldLabelString -> SDoc
+fieldCtxt field_name
+ = text "In the" <+> quotes (ppr field_name) <+> text "field of a record"
tcRecordField :: ConLike -> Assoc Name Type
-> LFieldOcc GhcRn -> LHsExpr GhcRn
@@ -1663,103 +1573,6 @@ checkMissingFields con_like rbinds arg_tys
{-
************************************************************************
* *
-\subsection{Errors and contexts}
-* *
-************************************************************************
-
-Boring and alphabetical:
--}
-
-fieldCtxt :: FieldLabelString -> SDoc
-fieldCtxt field_name
- = text "In the" <+> quotes (ppr field_name) <+> text "field of a record"
-
-badFieldsUpd
- :: [LHsFieldBind GhcTc (LAmbiguousFieldOcc GhcTc) (LHsExpr GhcRn)]
- -- Field names that don't belong to a single datacon
- -> [ConLike] -- Data cons of the type which the first field name belongs to
- -> TcRnMessage
-badFieldsUpd rbinds data_cons
- = TcRnNoConstructorHasAllFields conflictingFields
- -- See Note [Finding the conflicting fields]
- where
- -- A (preferably small) set of fields such that no constructor contains
- -- all of them. See Note [Finding the conflicting fields]
- conflictingFields = case nonMembers of
- -- nonMember belongs to a different type.
- (nonMember, _) : _ -> [aMember, nonMember]
- [] -> let
- -- All of rbinds belong to one type. In this case, repeatedly add
- -- a field to the set until no constructor contains the set.
-
- -- Each field, together with a list indicating which constructors
- -- have all the fields so far.
- growingSets :: [(FieldLabelString, [Bool])]
- growingSets = scanl1 combine membership
- combine (_, setMem) (field, fldMem)
- = (field, zipWith (&&) setMem fldMem)
- in
- -- Fields that don't change the membership status of the set
- -- are redundant and can be dropped.
- map (fst . NE.head) $ NE.groupWith snd growingSets
-
- aMember = assert (not (null members) ) fst (head members)
- (members, nonMembers) = partition (or . snd) membership
-
- -- For each field, which constructors contain the field?
- membership :: [(FieldLabelString, [Bool])]
- membership = sortMembership $
- map (\fld -> (fld, map (fld `elementOfUniqSet`) fieldLabelSets)) $
- map (FieldLabelString . occNameFS . rdrNameOcc . rdrNameAmbiguousFieldOcc . unLoc . hfbLHS . unLoc) rbinds
-
- fieldLabelSets :: [UniqSet FieldLabelString]
- fieldLabelSets = map (mkUniqSet . map flLabel . conLikeFieldLabels) data_cons
-
- -- Sort in order of increasing number of True, so that a smaller
- -- conflicting set can be found.
- sortMembership =
- map snd .
- sortBy (compare `on` fst) .
- map (\ item@(_, membershipRow) -> (countTrue membershipRow, item))
-
- countTrue = count id
-
-{-
-Note [Finding the conflicting fields]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Suppose we have
- data A = A {a0, a1 :: Int}
- | B {b0, b1 :: Int}
-and we see a record update
- x { a0 = 3, a1 = 2, b0 = 4, b1 = 5 }
-Then we'd like to find the smallest subset of fields that no
-constructor has all of. Here, say, {a0,b0}, or {a0,b1}, etc.
-We don't really want to report that no constructor has all of
-{a0,a1,b0,b1}, because when there are hundreds of fields it's
-hard to see what was really wrong.
-
-We may need more than two fields, though; eg
- data T = A { x,y :: Int, v::Int }
- | B { y,z :: Int, v::Int }
- | C { z,x :: Int, v::Int }
-with update
- r { x=e1, y=e2, z=e3 }, we
-
-Finding the smallest subset is hard, so the code here makes
-a decent stab, no more. See #7989.
--}
-
-mixedSelectors :: [Id] -> [Id] -> TcRnMessage
-mixedSelectors data_sels@(dc_rep_id:_) pat_syn_sels@(ps_rep_id:_)
- = TcRnMixedSelectors (tyConName rep_dc) data_sels (patSynName rep_ps) pat_syn_sels
- where
- RecSelPatSyn rep_ps = recordSelectorTyCon ps_rep_id
- RecSelData rep_dc = recordSelectorTyCon dc_rep_id
-mixedSelectors _ _ = panic "GHC.Tc.Gen.Expr: mixedSelectors emptylists"
-
-{-
-************************************************************************
-* *
\subsection{Static Pointers}
* *
************************************************************************
diff --git a/compiler/GHC/Tc/Gen/Head.hs b/compiler/GHC/Tc/Gen/Head.hs
index 5154d7c98a..d5721ff5e1 100644
--- a/compiler/GHC/Tc/Gen/Head.hs
+++ b/compiler/GHC/Tc/Gen/Head.hs
@@ -26,8 +26,8 @@ module GHC.Tc.Gen.Head
, tcInferAppHead, tcInferAppHead_maybe
, tcInferId, tcCheckId
, obviousSig
- , tyConOf, tyConOfET, lookupParents, fieldNotInType
- , notSelector, nonBidirectionalErr
+ , tyConOf, tyConOfET, fieldNotInType
+ , nonBidirectionalErr
, addHeadCtxt, addExprCtxt, addFunResCtxt ) where
@@ -47,7 +47,8 @@ import GHC.Tc.Utils.Unify
import GHC.Tc.Utils.Concrete ( hasFixedRuntimeRep_syntactic )
import GHC.Tc.Utils.Instantiate
import GHC.Tc.Instance.Family ( tcLookupDataFamInst )
-import GHC.Unit.Module ( getModule )
+import GHC.Core.FamInstEnv ( FamInstEnvs )
+import GHC.Core.UsageEnv ( unitUE )
import GHC.Tc.Errors.Types
import GHC.Tc.Solver ( InferMode(..), simplifyInfer )
import GHC.Tc.Utils.Env
@@ -57,8 +58,6 @@ import GHC.Tc.Utils.TcType as TcType
import GHC.Tc.Types.Evidence
import GHC.Hs.Syn.Type
-import GHC.Core.FamInstEnv ( FamInstEnvs )
-import GHC.Core.UsageEnv ( unitUE )
import GHC.Core.PatSyn( PatSyn )
import GHC.Core.ConLike( ConLike(..) )
import GHC.Core.DataCon
@@ -860,35 +859,11 @@ tyConOf fam_inst_envs ty0
tyConOfET :: FamInstEnvs -> ExpRhoType -> Maybe TyCon
tyConOfET fam_inst_envs ty0 = tyConOf fam_inst_envs =<< checkingExpType_maybe ty0
-
--- For an ambiguous record field, find all the candidate record
--- selectors (as GlobalRdrElts) and their parents.
-lookupParents :: Bool -> RdrName -> RnM [(RecSelParent, GlobalRdrElt)]
-lookupParents is_selector rdr
- = do { env <- getGlobalRdrEnv
- -- Filter by isRecFldGRE because otherwise a non-selector variable with
- -- an overlapping name can get through when NoFieldSelectors is enabled.
- -- See Note [NoFieldSelectors] in GHC.Rename.Env.
- ; let all_gres = lookupGRE_RdrName' rdr env
- ; let gres | is_selector = filter isFieldSelectorGRE all_gres
- | otherwise = filter isRecFldGRE all_gres
- ; mapM lookupParent gres }
- where
- lookupParent :: GlobalRdrElt -> RnM (RecSelParent, GlobalRdrElt)
- lookupParent gre = do { id <- tcLookupId (greMangledName gre)
- ; case recordSelectorTyCon_maybe id of
- Just rstc -> return (rstc, gre)
- Nothing -> failWithTc (notSelector (greMangledName gre)) }
-
-
fieldNotInType :: RecSelParent -> RdrName -> TcRnMessage
fieldNotInType p rdr
= mkTcRnNotInScope rdr $
UnknownSubordinate (text "field of type" <+> quotes (ppr p))
-notSelector :: Name -> TcRnMessage
-notSelector = TcRnNotARecordSelector
-
{- *********************************************************************
* *
@@ -1108,14 +1083,8 @@ tc_infer_id id_name
get_suggestions ns = do
let occ = mkOccNameFS ns (occNameFS (occName id_name))
- dflags <- getDynFlags
- rdr_env <- getGlobalRdrEnv
lcl_env <- getLocalRdrEnv
- imp_info <- getImports
- curr_mod <- getModule
- hpt <- getHpt
- return $ unknownNameSuggestions WL_Anything dflags hpt curr_mod rdr_env
- lcl_env imp_info (mkRdrUnqual occ)
+ unknownNameSuggestions lcl_env WL_Anything (mkRdrUnqual occ)
return_id id = return (HsVar noExtField (noLocA id), idType id)
diff --git a/compiler/GHC/Tc/Gen/HsType.hs b/compiler/GHC/Tc/Gen/HsType.hs
index 0a0ec7230a..9e8375b47d 100644
--- a/compiler/GHC/Tc/Gen/HsType.hs
+++ b/compiler/GHC/Tc/Gen/HsType.hs
@@ -1144,7 +1144,7 @@ tc_hs_type _ ty@(HsBangTy _ bang _) _
tc_hs_type _ ty@(HsRecTy {}) _
-- Record types (which only show up temporarily in constructor
-- signatures) should have been removed by now
- = failWithTc $ TcRnIllegalRecordSyntax ty
+ = failWithTc $ TcRnIllegalRecordSyntax (Right ty)
-- HsSpliced is an annotation produced by 'GHC.Rename.Splice.rnSpliceType'.
-- Here we get rid of it and add the finalizers to the global environment
@@ -2315,11 +2315,11 @@ instance Outputable SAKS_or_CUSK where
-- See Note [kcCheckDeclHeader vs kcInferDeclHeader]
kcDeclHeader
:: InitialKindStrategy
- -> Name -- ^ of the thing being checked
- -> TyConFlavour -- ^ What sort of 'TyCon' is being checked
- -> LHsQTyVars GhcRn -- ^ Binders in the header
- -> TcM ContextKind -- ^ The result kind
- -> TcM TcTyCon -- ^ A suitably-kinded TcTyCon
+ -> Name -- ^ of the thing being checked
+ -> TyConFlavour TyCon -- ^ What sort of 'TyCon' is being checked
+ -> LHsQTyVars GhcRn -- ^ Binders in the header
+ -> TcM ContextKind -- ^ The result kind
+ -> TcM TcTyCon -- ^ A suitably-kinded TcTyCon
kcDeclHeader (InitialKindCheck msig) = kcCheckDeclHeader msig
kcDeclHeader InitialKindInfer = kcInferDeclHeader
@@ -2342,20 +2342,20 @@ of a type constructor.
------------------------------
kcCheckDeclHeader
:: SAKS_or_CUSK
- -> Name -- ^ of the thing being checked
- -> TyConFlavour -- ^ What sort of 'TyCon' is being checked
- -> LHsQTyVars GhcRn -- ^ Binders in the header
- -> TcM ContextKind -- ^ The result kind. AnyKind == no result signature
- -> TcM PolyTcTyCon -- ^ A suitably-kinded generalized TcTyCon
+ -> Name -- ^ of the thing being checked
+ -> TyConFlavour TyCon -- ^ What sort of 'TyCon' is being checked
+ -> LHsQTyVars GhcRn -- ^ Binders in the header
+ -> TcM ContextKind -- ^ The result kind. AnyKind == no result signature
+ -> TcM PolyTcTyCon -- ^ A suitably-kinded generalized TcTyCon
kcCheckDeclHeader (SAKS sig) = kcCheckDeclHeader_sig sig
kcCheckDeclHeader CUSK = kcCheckDeclHeader_cusk
kcCheckDeclHeader_cusk
- :: Name -- ^ of the thing being checked
- -> TyConFlavour -- ^ What sort of 'TyCon' is being checked
- -> LHsQTyVars GhcRn -- ^ Binders in the header
- -> TcM ContextKind -- ^ The result kind
- -> TcM PolyTcTyCon -- ^ A suitably-kinded generalized TcTyCon
+ :: Name -- ^ of the thing being checked
+ -> TyConFlavour TyCon -- ^ What sort of 'TyCon' is being checked
+ -> LHsQTyVars GhcRn -- ^ Binders in the header
+ -> TcM ContextKind -- ^ The result kind
+ -> TcM PolyTcTyCon -- ^ A suitably-kinded generalized TcTyCon
kcCheckDeclHeader_cusk name flav
(HsQTvs { hsq_ext = kv_ns
, hsq_explicit = hs_tvs }) kc_res_ki
@@ -2441,11 +2441,11 @@ kcCheckDeclHeader_cusk name flav
--
-- This function does not do telescope checking.
kcInferDeclHeader
- :: Name -- ^ of the thing being checked
- -> TyConFlavour -- ^ What sort of 'TyCon' is being checked
+ :: Name -- ^ of the thing being checked
+ -> TyConFlavour TyCon -- ^ What sort of 'TyCon' is being checked
-> LHsQTyVars GhcRn
- -> TcM ContextKind -- ^ The result kind
- -> TcM MonoTcTyCon -- ^ A suitably-kinded non-generalized TcTyCon
+ -> TcM ContextKind -- ^ The result kind
+ -> TcM MonoTcTyCon -- ^ A suitably-kinded non-generalized TcTyCon
kcInferDeclHeader name flav
(HsQTvs { hsq_ext = kv_ns
, hsq_explicit = hs_tvs }) kc_res_ki
@@ -2494,12 +2494,12 @@ kcInferDeclHeader name flav
-- | Kind-check a declaration header against a standalone kind signature.
-- See Note [kcCheckDeclHeader_sig]
kcCheckDeclHeader_sig
- :: Kind -- ^ Standalone kind signature, fully zonked! (zonkTcTypeToType)
- -> Name -- ^ of the thing being checked
- -> TyConFlavour -- ^ What sort of 'TyCon' is being checked
- -> LHsQTyVars GhcRn -- ^ Binders in the header
- -> TcM ContextKind -- ^ The result kind. AnyKind == no result signature
- -> TcM PolyTcTyCon -- ^ A suitably-kinded, fully generalised TcTyCon
+ :: Kind -- ^ Standalone kind signature, fully zonked! (zonkTcTypeToType)
+ -> Name -- ^ of the thing being checked
+ -> TyConFlavour TyCon -- ^ What sort of 'TyCon' is being checked
+ -> LHsQTyVars GhcRn -- ^ Binders in the header
+ -> TcM ContextKind -- ^ The result kind. AnyKind == no result signature
+ -> TcM PolyTcTyCon -- ^ A suitably-kinded, fully generalised TcTyCon
-- Postcondition to (kcCheckDeclHeader_sig sig_kind n f hs_tvs kc_res_ki):
-- kind(returned PolyTcTyCon) = sig_kind
--
@@ -3660,7 +3660,7 @@ Hence using zonked_kinds when forming tvs'.
-}
-----------------------------------
-etaExpandAlgTyCon :: TyConFlavour -> SkolemInfo
+etaExpandAlgTyCon :: TyConFlavour tc -> SkolemInfo
-> [TcTyConBinder] -> Kind
-> TcM ([TcTyConBinder], Kind)
etaExpandAlgTyCon flav skol_info tcbs res_kind
@@ -3673,7 +3673,7 @@ etaExpandAlgTyCon flav skol_info tcbs res_kind
in_scope = mkInScopeSetList tyvars
avoid_occs = map getOccName tyvars
-needsEtaExpansion :: TyConFlavour -> Bool
+needsEtaExpansion :: TyConFlavour tc -> Bool
needsEtaExpansion NewtypeFlavour = True
needsEtaExpansion DataTypeFlavour = True
needsEtaExpansion ClassFlavour = True
@@ -4337,7 +4337,7 @@ funAppCtxt fun arg arg_no
2 (quotes (ppr arg))
-- | Add a "In the data declaration for T" or some such.
-addTyConFlavCtxt :: Name -> TyConFlavour -> TcM a -> TcM a
+addTyConFlavCtxt :: Name -> TyConFlavour tc -> TcM a -> TcM a
addTyConFlavCtxt name flav
= addErrCtxt $ hsep [ text "In the", ppr flav
, text "declaration for", quotes (ppr name) ]
diff --git a/compiler/GHC/Tc/Gen/Splice.hs b/compiler/GHC/Tc/Gen/Splice.hs
index 943c8dcbd2..f3d7c3c381 100644
--- a/compiler/GHC/Tc/Gen/Splice.hs
+++ b/compiler/GHC/Tc/Gen/Splice.hs
@@ -92,7 +92,6 @@ import GHC.Core.PatSyn
import GHC.Core.ConLike
import GHC.Core.DataCon as DataCon
-import GHC.Types.FieldLabel
import GHC.Types.SrcLoc
import GHC.Types.Name.Env
import GHC.Types.Name.Set
@@ -131,7 +130,6 @@ import GHC.Data.FastString
import GHC.Data.Maybe( MaybeErr(..) )
import qualified GHC.Data.EnumSet as EnumSet
-import Language.Haskell.Syntax.Basic (FieldLabelString(..))
import qualified Language.Haskell.TH as TH
-- THSyntax gives access to internal functions and data types
import qualified Language.Haskell.TH.Syntax as TH
@@ -145,7 +143,7 @@ import Unsafe.Coerce ( unsafeCoerce )
import Control.Monad
import Data.Binary
import Data.Binary.Get
-import Data.List ( find )
+import qualified Data.List.NonEmpty as NE ( singleton )
import Data.Maybe
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as LB
@@ -1938,8 +1936,8 @@ lookupName :: Bool -- True <=> type namespace
-- False <=> value namespace
-> String -> TcM (Maybe TH.Name)
lookupName is_type_name s
- = do { mb_nm <- lookupOccRn_maybe rdr_name
- ; return (fmap reifyName mb_nm) }
+ = do { mb_gre <- lookupSameOccRn_maybe rdr_name
+ ; return (fmap (reifyName . greName) mb_gre) }
where
th_name = TH.mkName s -- Parses M.x into a base of 'x' and a module of 'M'
@@ -1975,9 +1973,10 @@ getThing th_name
-- ToDo: this tcLookup could fail, which would give a
-- rather unhelpful error message
where
- ppr_ns (TH.Name _ (TH.NameG TH.DataName _pkg _mod)) = text "data"
- ppr_ns (TH.Name _ (TH.NameG TH.TcClsName _pkg _mod)) = text "tc"
- ppr_ns (TH.Name _ (TH.NameG TH.VarName _pkg _mod)) = text "var"
+ ppr_ns (TH.Name _ (TH.NameG TH.DataName _pkg _mod)) = text "data"
+ ppr_ns (TH.Name _ (TH.NameG TH.TcClsName _pkg _mod)) = text "tc"
+ ppr_ns (TH.Name _ (TH.NameG TH.VarName _pkg _mod)) = text "var"
+ ppr_ns (TH.Name _ (TH.NameG (TH.FldName {}) _pkg _mod)) = text "fld"
ppr_ns _ = panic "reify/ppr_ns"
reify :: TH.Name -> TcM TH.Info
@@ -1996,10 +1995,17 @@ lookupThName th_name = do
lookupThName_maybe :: TH.Name -> TcM (Maybe Name)
lookupThName_maybe th_name
- = do { names <- mapMaybeM lookupOccRn_maybe (thRdrNameGuesses th_name)
+ = do { let guesses = thRdrNameGuesses th_name
+ ; case guesses of
+ { [for_sure] -> get_name $ lookupSameOccRn_maybe for_sure
+ ; _ ->
+ do { names <- mapMaybeM (get_name . lookupOccRn_maybe) guesses
-- Pick the first that works
-- E.g. reify (mkName "A") will pick the class A in preference to the data constructor A
- ; return (listToMaybe names) }
+ ; return (listToMaybe names) } } }
+ where
+ get_name :: TcM (Maybe GlobalRdrElt) -> TcM (Maybe Name)
+ get_name = fmap (fmap greName)
tcLookupTh :: Name -> TcM TcTyThing
-- This is a specialised version of GHC.Tc.Utils.Env.tcLookup; specialised mainly in that
@@ -2058,9 +2064,7 @@ reifyThing (AGlobal (AnId id))
; let v = reifyName id
; case idDetails id of
ClassOpId cls _ -> return (TH.ClassOpI v ty (reifyName cls))
- RecSelId{sel_tycon=RecSelData tc}
- -> return (TH.VarI (reifySelector id tc) ty Nothing)
- _ -> return (TH.VarI v ty Nothing)
+ _ -> return (TH.VarI v ty Nothing)
}
reifyThing (AGlobal (ATyCon tc)) = reifyTyCon tc
@@ -2231,8 +2235,8 @@ reifyDataCon isGadtDataCon tys dc
dcdBangs r_arg_tys)
| not (null fields) -> do
{ res_ty <- reifyType g_res_ty
- ; return $ TH.RecGadtC [name]
- (zip3 (map (reifyName . flSelector) fields)
+ ; return $ TH.RecGadtC (NE.singleton name)
+ (zip3 (map reifyFieldLabel fields)
dcdBangs r_arg_tys) res_ty }
-- We need to check not isGadtDataCon here because GADT
-- constructors can be declared infix.
@@ -2244,7 +2248,8 @@ reifyDataCon isGadtDataCon tys dc
; return $ TH.InfixC (s1,r_a1) name (s2,r_a2) }
| isGadtDataCon -> do
{ res_ty <- reifyType g_res_ty
- ; return $ TH.GadtC [name] (dcdBangs `zip` r_arg_tys) res_ty }
+ ; return $ TH.GadtC (NE.singleton name)
+ (dcdBangs `zip` r_arg_tys) res_ty }
| otherwise ->
return $ TH.NormalC name (dcdBangs `zip` r_arg_tys)
@@ -2734,26 +2739,12 @@ reifyName thing
mk_varg | OccName.isDataOcc occ = TH.mkNameG_d
| OccName.isVarOcc occ = TH.mkNameG_v
| OccName.isTcOcc occ = TH.mkNameG_tc
+ | Just con_fs <- OccName.fieldOcc_maybe occ
+ = \ pkg mod occ -> TH.mkNameG_fld pkg mod (unpackFS con_fs) occ
| otherwise = pprPanic "reifyName" (ppr name)
--- See Note [Reifying field labels]
reifyFieldLabel :: FieldLabel -> TH.Name
-reifyFieldLabel fl
- | flIsOverloaded fl
- = TH.Name (TH.mkOccName occ_str) (TH.NameQ (TH.mkModName mod_str))
- | otherwise = TH.mkNameG_v pkg_str mod_str occ_str
- where
- name = flSelector fl
- mod = assert (isExternalName name) $ nameModule name
- pkg_str = unitString (moduleUnit mod)
- mod_str = moduleNameString (moduleName mod)
- occ_str = unpackFS (field_label $ flLabel fl)
-
-reifySelector :: Id -> TyCon -> TH.Name
-reifySelector id tc
- = case find ((idName id ==) . flSelector) (tyConFieldLabels tc) of
- Just fl -> reifyFieldLabel fl
- Nothing -> pprPanic "reifySelector: missing field" (ppr id $$ ppr tc)
+reifyFieldLabel fl = reifyName $ flSelector fl
------------------------------
reifyFixity :: Name -> TcM (Maybe TH.Fixity)
@@ -2857,34 +2848,6 @@ noTH s d = failWithTc $ TcRnCannotRepresentType s d
ppr_th :: TH.Ppr a => a -> SDoc
ppr_th x = text (TH.pprint x)
-{-
-Note [Reifying field labels]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-When reifying a datatype declared with DuplicateRecordFields enabled, we want
-the reified names of the fields to be labels rather than selector functions.
-That is, we want (reify ''T) and (reify 'foo) to produce
-
- data T = MkT { foo :: Int }
- foo :: T -> Int
-
-rather than
-
- data T = MkT { $sel:foo:MkT :: Int }
- $sel:foo:MkT :: T -> Int
-
-because otherwise TH code that uses the field names as strings will silently do
-the wrong thing. Thus we use the field label (e.g. foo) as the OccName, rather
-than the selector (e.g. $sel:foo:MkT). Since the Orig name M.foo isn't in the
-environment, NameG can't be used to represent such fields. Instead,
-reifyFieldLabel uses NameQ.
-
-However, this means that extracting the field name from the output of reify, and
-trying to reify it again, may fail with an ambiguity error if there are multiple
-such fields defined in the module (see the test case
-overloadedrecflds/should_fail/T11103.hs). The "proper" fix requires changes to
-the TH AST to make it able to represent duplicate record fields.
--}
-
tcGetInterp :: TcM Interp
tcGetInterp = do
hsc_env <- getTopEnv
diff --git a/compiler/GHC/Tc/Instance/Class.hs b/compiler/GHC/Tc/Instance/Class.hs
index 71dd30638b..00811459c4 100644
--- a/compiler/GHC/Tc/Instance/Class.hs
+++ b/compiler/GHC/Tc/Instance/Class.hs
@@ -30,7 +30,7 @@ import GHC.Builtin.Types.Prim
import GHC.Builtin.Names
import GHC.Types.FieldLabel
-import GHC.Types.Name.Reader( lookupGRE_FieldLabel, greMangledName )
+import GHC.Types.Name.Reader
import GHC.Types.SafeHaskell
import GHC.Types.Name ( Name )
import GHC.Types.Var.Env ( VarEnv )
@@ -949,7 +949,7 @@ matchHasField dflags short_cut clas tys
; if not (isNaughtyRecordSelector sel_id) && isTauTy sel_ty
then do { -- See Note [Unused name reporting and HasField]
addUsedGRE True gre
- ; keepAlive (greMangledName gre)
+ ; keepAlive (greName gre)
; return OneInst { cir_new_theta = theta
, cir_mk_ev = mk_ev
, cir_coherence = IsCoherent
diff --git a/compiler/GHC/Tc/Module.hs b/compiler/GHC/Tc/Module.hs
index f877e006b8..c4b0e80504 100644
--- a/compiler/GHC/Tc/Module.hs
+++ b/compiler/GHC/Tc/Module.hs
@@ -96,6 +96,7 @@ import GHC.Rename.Names
import GHC.Rename.Env
import GHC.Rename.Module
import GHC.Rename.Doc
+import GHC.Rename.Utils ( mkNameClashErr )
import GHC.Iface.Syntax ( ShowSub(..), showToHeader )
import GHC.Iface.Type ( ShowForAllFlag(..) )
@@ -110,7 +111,7 @@ import GHC.Builtin.Utils
import GHC.Hs
import GHC.Hs.Dump
-import GHC.Core.PatSyn ( pprPatSynType )
+import GHC.Core.PatSyn
import GHC.Core.Predicate ( classMethodTy )
import GHC.Core.InstEnv
import GHC.Core.TyCon
@@ -157,7 +158,6 @@ import GHC.Types.SrcLoc
import GHC.Types.SourceFile
import GHC.Types.TyThing.Ppr ( pprTyThingInContext )
import GHC.Types.PkgQual
-import GHC.Types.ConInfo (mkConInfo)
import qualified GHC.LanguageExtensions as LangExt
import GHC.Unit.External
@@ -177,15 +177,18 @@ import GHC.Data.List.SetOps
import GHC.Data.Bag
import qualified GHC.Data.BooleanFormula as BF
+import Control.DeepSeq
+import Control.Monad
+import Data.Data ( Data )
import Data.Functor.Classes ( liftEq )
import Data.List ( sortBy, sort )
import Data.List.NonEmpty ( NonEmpty (..) )
import qualified Data.List.NonEmpty as NE
import Data.Ord
-import Data.Data ( Data )
import qualified Data.Set as S
-import Control.DeepSeq
-import Control.Monad
+import Data.Traversable ( for )
+
+
{-
************************************************************************
@@ -343,7 +346,7 @@ tcRnModuleTcRnM hsc_env mod_sum
-- boot_dfuns, which may be mentioned in imported
-- unfoldings.
; -- Report unused names
- -- Do this /after/ typeinference, so that when reporting
+ -- Do this /after/ type inference, so that when reporting
-- a function with no type signature we can give the
-- inferred type
; reportUnusedNames tcg_env hsc_src
@@ -786,17 +789,21 @@ checkHiBootIface tcg_env boot_info
, tcg_type_env = local_type_env
, tcg_exports = local_exports } <- tcg_env
= do { -- This code is tricky, see Note [DFun knot-tying]
- ; dfun_prs <- checkHiBootIface' local_insts local_type_env
- local_exports boot_details
+ ; imp_prs <- checkHiBootIface' local_insts local_type_env
+ local_exports boot_details
- -- Now add the boot-dfun bindings $fxblah = $fblah
+ -- Now add the impedance-matching boot bindings:
+ --
+ -- - dfun bindings $fxblah = $fblah
+ -- - record bindings fld{var} = fld{rec field of ..}
+ --
-- to (a) the type envt, and (b) the top-level bindings
- ; let boot_dfuns = map fst dfun_prs
- type_env' = extendTypeEnvWithIds local_type_env boot_dfuns
- dfun_binds = listToBag [ mkVarBind boot_dfun (nlHsVar dfun)
- | (boot_dfun, dfun) <- dfun_prs ]
+ ; let boot_impedance_bds = map fst imp_prs
+ type_env' = extendTypeEnvWithIds local_type_env boot_impedance_bds
+ impedance_binds = listToBag [ mkVarBind boot_id (nlHsVar id)
+ | (boot_id, id) <- imp_prs ]
tcg_env_w_binds
- = tcg_env { tcg_binds = binds `unionBags` dfun_binds }
+ = tcg_env { tcg_binds = binds `unionBags` impedance_binds }
; type_env' `seq`
-- Why the seq? Without, we will put a TypeEnv thunk in
@@ -828,6 +835,62 @@ In fact, the names will always differ because we always pick names
prefixed with "$fx" for boot dfuns, and "$f" for real dfuns
(so that this impedance matching is always possible).
+Note [Record field impedance matching]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+When a hs-boot file defines a function whose implementation in the hs file
+is a record selector, we have to do something similar to Note [DFun impedance matching].
+
+Example:
+
+ -- M.hs-boot
+ module M where
+ data A
+ fld :: A -> ()
+
+ -- M.hs
+ module M where
+ data A = MkA { fld :: () }
+
+Recall from Note [Record field namespacing] in GHC.Types.Name.Occurrence that
+record fields have their own namespaces. This means that M.hs exports the Id
+fld{record selector of MkA} :: A -> (), while M.hs-boot exports the Id
+fld{variable} :: A -> ().
+
+To remedy this, we add an impedance-matching binding in M.hs:
+
+ fld{variable} :: A -> ()
+ fld{variable} = fld{record selector of MkA}
+
+Note that we imperatively need to add a binding for fld{variable} in M.hs, as we
+might have an exact Name reference to it (e.g. in a module that imports M.hs-boot).
+Not doing so would cause Core Lint errors, at the very least.
+
+These bindings are returned by the check_export in checkHiBootIface', and
+added to the DFun impedance-matching bindings.
+
+[Wrinkle: exports]
+
+ We MUST NOT add fld{variable} to the export list of M.hs, as this
+ would mean that M.hs exports both a record field and variable with the same
+ occNameFS, which would cause ambiguity errors at use-sites.
+ It's OK to only export the field name even though the boot-file exported
+ the variable: name resolution will take care of that.
+
+Another situation is that we are re-exporting, e.g. (with M as above):
+
+ -- N.hs-boot
+ module N ( module M ) where
+ import {-# SOURCE #-} M
+
+ -- N.hs
+ module N ( module M where )
+ import M
+
+In this case, N.hs-boot re-exports the variable fld, and N re-exports the
+record field fld, but not the variable fld. We don't need to do anything in
+this situation; in particular, don't re-export the variable name from N.hs,
+as per [Wrinkle: exports] above.
+
Note [DFun knot-tying]
~~~~~~~~~~~~~~~~~~~~~~
The 'SelfBootInfo' that is fed into 'checkHiBootIface' comes from
@@ -860,10 +923,12 @@ checkHiBootIface'
, md_fam_insts = boot_fam_insts
, md_exports = boot_exports })
= do { traceTc "checkHiBootIface" $ vcat
- [ ppr boot_type_env, ppr boot_exports]
+ [ ppr boot_type_env, ppr boot_exports ]
+
+ ; gre_env <- getGlobalRdrEnv
-- Check the exports of the boot module, one by one
- ; mapM_ check_export boot_exports
+ ; fld_prs <- mapMaybeM (check_export gre_env) boot_exports
-- Check for no family instances
; unless (null boot_fam_insts) $
@@ -875,11 +940,11 @@ checkHiBootIface'
-- Check instance declarations
-- and generate an impedance-matching binding
- ; mb_dfun_prs <- mapM check_cls_inst boot_dfuns
+ ; dfun_prs <- mapMaybeM check_cls_inst boot_dfuns
; failIfErrsM
- ; return (catMaybes mb_dfun_prs) }
+ ; return (fld_prs ++ dfun_prs) }
where
boot_dfun_names = map idName boot_dfuns
@@ -888,46 +953,96 @@ checkHiBootIface'
-- We don't want to look at md_insts!
-- Why not? See Note [DFun knot-tying]
- check_export boot_avail -- boot_avail is exported by the boot iface
- | name `elem` boot_dfun_names = return ()
+ check_export gre_env boot_avail -- boot_avail is exported by the boot iface
+ | name `elem` boot_dfun_names
+ = return Nothing
-- Check that the actual module exports the same thing
| missing_name:_ <- missing_names
- = addErrAt (nameSrcSpan missing_name)
- (missingBootThing True missing_name "exported by")
+ = -- Lookup might have failed because the hs-boot file defines a variable
+ -- that is implemented in the hs file as a record selector, which
+ -- lives in a different namespace.
+ --
+ -- See Note [Record field impedance matching].
+ let missing_occ = nameOccName missing_name
+ mb_ok :: GlobalRdrElt -> Maybe (GlobalRdrElt, Maybe Id)
+ mb_ok gre
+ -- Ensure that this GRE refers to an Id that is exported.
+ | isNothing $ lookupNameEnv local_export_env (greName gre)
+ = Nothing
+ -- We locally define the field: create an impedance-matching
+ -- binding for the variable.
+ | Just (AnId id) <- lookupTypeEnv local_type_env (greName gre)
+ = Just (gre, Just id)
+ -- We are re-exporting the field but not the variable: not a problem,
+ -- as per [Wrinkle: exports] in Note [Record field impedance matching].
+ | otherwise
+ = Just (gre, Nothing)
+ matching_flds
+ | isVarOcc missing_occ -- (This only applies to variables.)
+ = lookupGRE_OccName (IncludeFields WantField) gre_env missing_occ
+ | otherwise
+ = []
+
+ in case mapMaybe mb_ok $ matching_flds of
+
+ -- 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)
+ return Nothing
+
+ -- Single match: resolve the issue.
+ [(_,mb_fld_id)] ->
+ -- See Note [Record field impedance matching].
+ for mb_fld_id $ \ fld_id -> do
+ let local_boot_var =
+ Id.mkExportedVanillaId missing_name (idType fld_id)
+ return (local_boot_var, fld_id)
+
+ -- Otherwise: report that the hs file does not export something
+ -- that the hs-boot file exports.
+ [] -> do
+ addErrAt (nameSrcSpan missing_name)
+ (missingBootThing True missing_name "exported by")
+ return Nothing
-- If the boot module does not *define* the thing, we are done
-- (it simply re-exports it, and names match, so nothing further to do)
- | isNothing mb_boot_thing = return ()
+ | isNothing mb_boot_thing
+ = return Nothing
-- Check that the actual module also defines the thing, and
-- then compare the definitions
| Just real_thing <- lookupTypeEnv local_type_env name,
Just boot_thing <- mb_boot_thing
- = checkBootDeclM True boot_thing real_thing
+ = do checkBootDeclM True boot_thing real_thing
+ return Nothing
| otherwise
- = addErrTc (missingBootThing True name "defined in")
+ = do addErrTc (missingBootThing True name "defined in")
+ return Nothing
where
name = availName boot_avail
mb_boot_thing = lookupTypeEnv boot_type_env name
missing_names = case lookupNameEnv local_export_env name of
Nothing -> [name]
- Just avail -> availNames boot_avail `minusList` availNames avail
+ Just avail -> availNames boot_avail
+ `minusList` availNames avail
local_export_env :: NameEnv AvailInfo
local_export_env = availsToNameEnv local_exports
- check_cls_inst :: DFunId -> TcM (Maybe (Id, Id))
+ check_cls_inst :: DFunId -> TcM (Maybe (Id,Id))
-- Returns a pair of the boot dfun in terms of the equivalent
-- real dfun. Delicate (like checkBootDecl) because it depends
-- on the types lining up precisely even to the ordering of
-- the type variables in the foralls.
check_cls_inst boot_dfun
| (real_dfun : _) <- find_real_dfun boot_dfun
- , let local_boot_dfun = Id.mkExportedVanillaId
- (idName boot_dfun) (idType real_dfun)
- = return (Just (local_boot_dfun, real_dfun))
+ , let dfun_name = idName boot_dfun
+ local_boot_dfun = Id.mkExportedVanillaId dfun_name (idType real_dfun)
+ = return $ Just (local_boot_dfun, real_dfun)
-- Two tricky points here:
--
-- * The local_boot_fun should have a Name from the /boot-file/,
@@ -943,6 +1058,8 @@ checkHiBootIface'
-- otherwise dependency analysis fails (#16038). This
-- is another reason for using mkExportedVanillaId, rather
-- that modifying boot_dfun, to make local_boot_fun.
+ --
+ -- See Note [DFun impedance matching].
| otherwise
= setSrcSpan (nameSrcSpan (getName boot_dfun)) $
@@ -1545,7 +1662,7 @@ tcTopSrcDecls (HsGroup { hs_tyclds = tycl_decls,
foe_binds
; fo_gres = fi_gres `unionBags` foe_gres
- ; fo_fvs = foldr (\gre fvs -> fvs `addOneFV` greMangledName gre)
+ ; fo_fvs = foldr (\gre fvs -> fvs `addOneFV` (greName gre))
emptyFVs fo_gres
; sig_names = mkNameSet (collectHsValBinders CollNoDictBinders hs_val_binds)
@@ -1613,11 +1730,11 @@ tcPreludeClashWarn warnFlag name = do
where
isLocalDef = gre_lcl x == True
-- Names are identical ...
- nameClashes = nameOccName (greMangledName x) == nameOccName name
+ nameClashes = nameOccName (greName x) == nameOccName name
-- ... but not the actual definitions, because we don't want to
-- warn about a bad definition of e.g. <> in Data.Semigroup, which
-- is the (only) proper place where this should be defined
- isNotInProperModule = greMangledName x /= name
+ isNotInProperModule = greName x /= name
-- List of all offending definitions
clashingElts :: [GlobalRdrElt]
@@ -1626,11 +1743,11 @@ tcPreludeClashWarn warnFlag name = do
; traceTc "tcPreludeClashWarn/prelude_functions"
(hang (ppr name) 4 (sep [ppr clashingElts]))
- ; let warn_msg x = addDiagnosticAt (nameSrcSpan (greMangledName x)) $
+ ; let warn_msg x = addDiagnosticAt (nameSrcSpan (greName x)) $
mkTcRnUnknownMessage $
mkPlainDiagnostic (WarningWithFlag warnFlag) noHints $ (hsep
[ text "Local definition of"
- , (quotes . ppr . nameOccName . greMangledName) x
+ , (quotes . ppr . nameOccName . greName) x
, text "clashes with a future Prelude name." ]
$$
text "This will become an error in a future release." )
@@ -1813,13 +1930,13 @@ checkMainType tcg_env
do { rdr_env <- getGlobalRdrEnv
; let dflags = hsc_dflags hsc_env
main_occ = getMainOcc dflags
- main_gres = lookupGlobalRdrEnv rdr_env main_occ
+ main_gres = lookupGRE_OccName SameOccName rdr_env main_occ
; case filter isLocalGRE main_gres of {
[] -> return emptyWC ;
(_:_:_) -> return emptyWC ;
[main_gre] ->
- do { let main_name = greMangledName main_gre
+ do { let main_name = greName main_gre
ctxt = FunSigCtxt main_name NoRRC
; main_id <- tcLookupId main_name
; (io_ty,_) <- getIOType
@@ -2091,23 +2208,21 @@ runTcInteractive hsc_env thing_inside
; let imports = emptyImportAvails { imp_orphs = orphs }
upd_envs (gbl_env, lcl_env) = (gbl_env', lcl_env')
+
where
- gbl_env' = gbl_env { tcg_rdr_env = icReaderEnv icxt
- , tcg_type_env = type_env
-
- , tcg_inst_env = tcg_inst_env gbl_env `unionInstEnv` ic_insts `unionInstEnv` home_insts
- , tcg_fam_inst_env = extendFamInstEnvList
- (extendFamInstEnvList (tcg_fam_inst_env gbl_env)
- ic_finsts)
- home_fam_insts
- , tcg_con_env = mkNameEnv con_fields
- -- setting tcg_con_env is necessary
- -- to make RecordWildCards work (test: ghci049)
- , tcg_fix_env = ic_fix_env icxt
- , tcg_default = ic_default icxt
- -- must calculate imp_orphs of the ImportAvails
- -- so that instance visibility is done correctly
- , tcg_imports = imports }
+ gbl_env' = gbl_env
+ { tcg_rdr_env = icReaderEnv icxt
+ , tcg_type_env = type_env
+ , tcg_inst_env = tcg_inst_env gbl_env `unionInstEnv` ic_insts `unionInstEnv` home_insts
+ , tcg_fam_inst_env = extendFamInstEnvList
+ (extendFamInstEnvList (tcg_fam_inst_env gbl_env)
+ ic_finsts)
+ home_fam_insts
+ , tcg_fix_env = ic_fix_env icxt
+ , tcg_default = ic_default icxt
+ -- must calculate imp_orphs of the ImportAvails
+ -- so that instance visibility is done correctly
+ , tcg_imports = imports }
lcl_env' = tcExtendLocalTypeEnv lcl_env lcl_ids
@@ -2132,15 +2247,11 @@ runTcInteractive hsc_env thing_inside
= Right thing
type_env1 = mkTypeEnvWithImplicits top_ty_things
- type_env = extendTypeEnvWithIds type_env1 (map instanceDFunId (instEnvElts ic_insts))
+ type_env = extendTypeEnvWithIds type_env1
+ $ map instanceDFunId (instEnvElts ic_insts)
-- Putting the dfuns in the type_env
-- is just to keep Core Lint happy
- con_fields = [ (dataConName c, mkConInfo (dataConSourceArity c) (dataConFieldLabels c))
- | ATyCon t <- top_ty_things
- , c <- tyConDataCons t ]
-
-
{- Note [Initialising the type environment for GHCi]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Most of the Ids in ic_things, defined by the user in 'let' stmts,
@@ -2551,7 +2662,7 @@ isGHCiMonad hsc_env ty
let occIO = lookupOccEnv rdrEnv (mkOccName tcName ty)
case occIO of
Just [n] -> do
- let name = greMangledName n
+ let name = greName n
ghciClass <- tcLookupClass ghciIoClassName
userTyCon <- tcLookupTyCon name
let userTy = mkTyConApp userTyCon []
@@ -2955,7 +3066,7 @@ loadUnqualIfaces hsc_env ictxt
unqual_mods = [ nameModule name
| gre <- globalRdrEnvElts (icReaderEnv ictxt)
- , let name = greMangledName gre
+ , let name = greName gre
, nameIsFromExternalPackage home_unit name
, isTcOcc (nameOccName name) -- Types and classes only
, unQualOK gre ] -- In scope unqualified
@@ -3037,12 +3148,12 @@ ppr_types debug type_env
| debug = True
| otherwise = hasTopUserName id
&& case idDetails id of
- VanillaId -> True
- WorkerLikeId{} -> True
- RecSelId {} -> True
- ClassOpId {} -> True
- FCallId {} -> True
- _ -> False
+ VanillaId -> True
+ WorkerLikeId {} -> True
+ RecSelId {} -> True
+ ClassOpId {} -> True
+ FCallId {} -> True
+ _ -> False
-- Data cons (workers and wrappers), pattern synonyms,
-- etc are suppressed (unless -dppr-debug),
-- because they appear elsewhere
diff --git a/compiler/GHC/Tc/Solver/Monad.hs b/compiler/GHC/Tc/Solver/Monad.hs
index 19b3f5089b..a22c135d18 100644
--- a/compiler/GHC/Tc/Solver/Monad.hs
+++ b/compiler/GHC/Tc/Solver/Monad.hs
@@ -1448,7 +1448,7 @@ recordUsedGREs gres
= do { wrapTcS $ TcM.addUsedGREs gre_list
-- If a newtype constructor was imported, don't warn about not
-- importing it...
- ; wrapTcS $ traverse_ (TcM.keepAlive . greMangledName) gre_list }
+ ; wrapTcS $ traverse_ (TcM.keepAlive . greName) gre_list }
-- ...and similarly, if a newtype constructor was defined in the same
-- module, don't warn about it being unused.
-- See Note [Tracking unused binding and imports] in GHC.Tc.Utils.
diff --git a/compiler/GHC/Tc/TyCl.hs b/compiler/GHC/Tc/TyCl.hs
index afb2047d63..3acfe274d7 100644
--- a/compiler/GHC/Tc/TyCl.hs
+++ b/compiler/GHC/Tc/TyCl.hs
@@ -62,7 +62,7 @@ import GHC.Builtin.Types (oneDataConTy, unitTy, makeRecoveryTyCon )
import GHC.Rename.Env( lookupConstructorFields )
import GHC.Core.Multiplicity
-import GHC.Core.FamInstEnv
+import GHC.Core.FamInstEnv ( mkBranchedCoAxiom, mkCoAxBranch )
import GHC.Core.Coercion
import GHC.Core.Type
import GHC.Core.TyCo.Rep -- for checkValidRoles
@@ -1390,7 +1390,7 @@ getInitialKind (InitialKindCheck msig) (FamDecl { tcdFam =
, fdTyVars = ktvs
, fdResultSig = unLoc -> resultSig
, fdInfo = info } } )
- = do { let flav = getFamFlav Nothing info
+ = do { let flav = familyInfoTyConFlavour Nothing info
ctxt = TyFamResKindCtxt name
; tc <- kcDeclHeader (InitialKindCheck msig) name flav ktvs $
case famResultKindSignature resultSig of
@@ -1431,7 +1431,7 @@ get_fam_decl_initial_kind mb_parent_tycon
-- by default
| otherwise -> return AnyKind
where
- flav = getFamFlav mb_parent_tycon info
+ flav = familyInfoTyConFlavour mb_parent_tycon info
ctxt = TyFamResKindCtxt name
-- See Note [Standalone kind signatures for associated types]
@@ -1451,7 +1451,7 @@ check_initial_kind_assoc_fam cls
Nothing -> return (TheKind liftedTypeKind)
where
ctxt = TyFamResKindCtxt name
- flav = getFamFlav (Just cls) info
+ flav = familyInfoTyConFlavour (Just cls) info
{- Note [Standalone kind signatures for associated types]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1536,29 +1536,6 @@ However, there are two twists:
-}
----------------------------------
-getFamFlav
- :: Maybe TcTyCon -- ^ Just cls <=> this is an associated family of class cls
- -> FamilyInfo pass
- -> TyConFlavour
-getFamFlav mb_parent_tycon info =
- case info of
- DataFamily -> DataFamilyFlavour mb_parent_tycon
- OpenTypeFamily -> OpenTypeFamilyFlavour mb_parent_tycon
- ClosedTypeFamily _ -> assert (isNothing mb_parent_tycon) -- See Note [Closed type family mb_parent_tycon]
- ClosedTypeFamilyFlavour
-
-{- Note [Closed type family mb_parent_tycon]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-There's no way to write a closed type family inside a class declaration:
-
- class C a where
- type family F a where -- error: parse error on input ‘where’
-
-In fact, it is not clear what the meaning of such a declaration would be.
-Therefore, 'mb_parent_tycon' of any closed type family has to be Nothing.
--}
-
------------------------------------------------------------------------
kcLTyClDecl :: LTyClDecl GhcRn -> TcM ()
-- See Note [Kind checking for type and class decls]
@@ -4337,8 +4314,9 @@ checkPartialRecordField all_cons fld
sep [text "Use of partial record field selector" <> colon,
nest 2 $ quotes (ppr occ_name)])
where
- loc = getSrcSpan (flSelector fld)
- occ_name = occName fld
+ sel = flSelector fld
+ loc = getSrcSpan sel
+ occ_name = nameOccName sel
(cons_with_field, cons_without_field) = partition has_field all_cons
has_field con = fld `elem` (dataConFieldLabels con)
diff --git a/compiler/GHC/Tc/TyCl/Utils.hs b/compiler/GHC/Tc/TyCl/Utils.hs
index 53e58a0e0c..b37977bb47 100644
--- a/compiler/GHC/Tc/TyCl/Utils.hs
+++ b/compiler/GHC/Tc/TyCl/Utils.hs
@@ -72,7 +72,7 @@ import GHC.Types.SourceFile
import GHC.Types.SourceText
import GHC.Types.Name
import GHC.Types.Name.Env
-import GHC.Types.Name.Reader ( mkVarUnqual )
+import GHC.Types.Name.Reader ( mkRdrUnqual )
import GHC.Types.Id
import GHC.Types.Id.Info
import GHC.Types.Var.Env
@@ -896,7 +896,9 @@ mkOneRecordSelector all_cons idDetails fl has_sel
sel_name = flSelector fl
sel_id = mkExportedLocalId rec_details sel_name sel_ty
- rec_details = RecSelId { sel_tycon = idDetails, sel_naughty = is_naughty }
+ rec_details = RecSelId { sel_tycon = idDetails
+ , sel_naughty = is_naughty
+ , sel_fieldLabel = fl }
-- Find a representative constructor, con1
cons_w_field = conLikesWithFields all_cons [lbl]
@@ -954,7 +956,7 @@ mkOneRecordSelector all_cons idDetails fl has_sel
{ hfbAnn = noAnn
, hfbLHS
= L locc (FieldOcc sel_name
- (L locn $ mkVarUnqual (field_label lbl)))
+ (L locn $ mkRdrUnqual (nameOccName sel_name)))
, hfbRHS
= L loc' (VarPat noExtField (L locn field_var))
, hfbPun = False })
diff --git a/compiler/GHC/Tc/Types.hs b/compiler/GHC/Tc/Types.hs
index acf7a0e6af..a6bab74fc0 100644
--- a/compiler/GHC/Tc/Types.hs
+++ b/compiler/GHC/Tc/Types.hs
@@ -145,7 +145,6 @@ import GHC.Types.Unique.FM
import GHC.Types.Basic
import GHC.Types.CostCentre.State
import GHC.Types.HpcInfo
-import GHC.Types.ConInfo (ConFieldEnv)
import GHC.Data.IOEnv
import GHC.Data.Bag
@@ -442,11 +441,7 @@ data TcGblEnv
tcg_default :: Maybe [Type],
-- ^ Types used for defaulting. @Nothing@ => no @default@ decl
- tcg_fix_env :: FixityEnv, -- ^ Just for things in this module
- tcg_con_env :: ConFieldEnv,
- -- ^ Just for things in this module
- -- For information on why this is necessary, see Note [Local constructor info in the renamer]
- -- See Note [The interactive package] in "GHC.Runtime.Context"
+ tcg_fix_env :: FixityEnv, -- ^ Just for things in this module
tcg_type_env :: TypeEnv,
-- ^ Global type env for the module we are compiling now. All
diff --git a/compiler/GHC/Tc/Types/Origin.hs b/compiler/GHC/Tc/Types/Origin.hs
index bc1842e368..fb64b55cde 100644
--- a/compiler/GHC/Tc/Types/Origin.hs
+++ b/compiler/GHC/Tc/Types/Origin.hs
@@ -280,7 +280,7 @@ data SkolemInfoAnon
| UnifyForAllSkol -- We are unifying two for-all types
TcType -- The instantiated type *inside* the forall
- | TyConSkol TyConFlavour Name -- bound in a type declaration of the given flavour
+ | TyConSkol (TyConFlavour TyCon) Name -- bound in a type declaration of the given flavour
| DataConSkol Name -- bound as an existential in a Haskell98 datacon decl or
-- as any variable in a GADT datacon decl
diff --git a/compiler/GHC/Tc/Utils/Backpack.hs b/compiler/GHC/Tc/Utils/Backpack.hs
index bc70d18684..20508c0fa4 100644
--- a/compiler/GHC/Tc/Utils/Backpack.hs
+++ b/compiler/GHC/Tc/Utils/Backpack.hs
@@ -47,14 +47,18 @@ import GHC.Unit.Module.ModDetails
import GHC.Unit.Module.Imported
import GHC.Unit.Module.Deps
+import GHC.Tc.Errors
import GHC.Tc.Errors.Types
+import {-# SOURCE #-} GHC.Tc.Module
import GHC.Tc.Gen.Export
import GHC.Tc.Solver
import GHC.Tc.TyCl.Utils
import GHC.Tc.Types.Constraint
import GHC.Tc.Types.Origin
+import GHC.Tc.Utils.Env
import GHC.Tc.Utils.Monad
import GHC.Tc.Utils.Instantiate
+import GHC.Tc.Utils.Unify
import GHC.Tc.Utils.TcMType
import GHC.Tc.Utils.TcType
@@ -71,11 +75,8 @@ import GHC.Iface.Syntax
import GHC.Rename.Names
import GHC.Rename.Fixity ( lookupFixityRn )
-import GHC.Tc.Utils.Env
-import GHC.Tc.Errors
-import GHC.Tc.Utils.Unify
-
import GHC.Utils.Error
+import GHC.Utils.Misc ( HasDebugCallStack )
import GHC.Utils.Outputable
import GHC.Utils.Panic
import GHC.Utils.Panic.Plain
@@ -86,8 +87,6 @@ import GHC.Data.Maybe
import Control.Monad
import Data.List (find)
-import {-# SOURCE #-} GHC.Tc.Module
-
checkHsigDeclM :: ModIface -> TyThing -> TyThing -> TcRn ()
checkHsigDeclM sig_iface sig_thing real_thing = do
let name = getName real_thing
@@ -112,7 +111,7 @@ checkHsigDeclM sig_iface sig_thing real_thing = do
-- a sufficient set of entities, since otherwise the renaming and then
-- typechecking of the signature 'ModIface' would have failed.
checkHsigIface :: TcGblEnv -> GlobalRdrEnv -> ModIface -> ModDetails -> TcRn ()
-checkHsigIface tcg_env gr sig_iface
+checkHsigIface tcg_env gre_env sig_iface
ModDetails { md_insts = sig_insts, md_fam_insts = sig_fam_insts,
md_types = sig_type_env, md_exports = sig_exports } = do
traceTc "checkHsigIface" $ vcat
@@ -120,8 +119,8 @@ checkHsigIface tcg_env gr sig_iface
mapM_ check_export (map availName sig_exports)
failIfErrsM -- See Note [Fail before checking instances in checkHsigIface]
unless (null sig_fam_insts) $
- panic ("GHC.Tc.Module.checkHsigIface: Cannot handle family " ++
- "instances in hsig files yet...")
+ panic ("GHC.Tc.Utils.Backpack.checkHsigIface: " ++
+ "Cannot handle family instances in hsig files yet...")
-- Delete instances so we don't look them up when
-- checking instance satisfiability
-- TODO: this should not be necessary
@@ -159,8 +158,8 @@ checkHsigIface tcg_env gr sig_iface
-- The hsig did NOT define this function; that means it must
-- be a reexport. In this case, make sure the 'Name' of the
-- reexport matches the 'Name exported here.
- | [gre] <- lookupGlobalRdrEnv gr (nameOccName name) = do
- let name' = greMangledName gre
+ | [gre] <- lookupGRE_OccName (AllNameSpaces WantNormal) gre_env (nameOccName name) = do
+ let name' = greName gre
when (name /= name') $ do
-- See Note [Error reporting bad reexport]
-- TODO: Actually this error swizzle doesn't work
@@ -385,7 +384,7 @@ thinModIface avails iface =
decl_pred occs decl = nameOccName (ifName decl) `elemOccSet` occs
filter_decls occs = filter (decl_pred occs . snd) (mi_decls iface)
- exported_occs = mkOccSet [ occName n
+ exported_occs = mkOccSet [ nameOccName n
| a <- avails
, n <- availNames a ]
exported_decls = filter_decls exported_occs
@@ -495,7 +494,7 @@ merge_msg mod_name reqs =
-- from 'requirementMerges' into this signature, producing
-- a final 'TcGblEnv' that matches the local signature and
-- all required signatures.
-mergeSignatures :: HsParsedModule -> TcGblEnv -> ModIface -> TcRn TcGblEnv
+mergeSignatures :: HasDebugCallStack => HsParsedModule -> TcGblEnv -> ModIface -> TcRn TcGblEnv
mergeSignatures
(HsParsedModule { hpm_module = L loc (HsModule { hsmodExports = mb_exports }),
hpm_src_files = src_files })
@@ -532,7 +531,7 @@ mergeSignatures
let outer_mod = tcg_mod tcg_env
let inner_mod = tcg_semantic_mod tcg_env
- let mod_name = moduleName (tcg_mod tcg_env)
+ let mod_name = moduleName outer_mod
let unit_state = hsc_units hsc_env
let dflags = hsc_dflags hsc_env
@@ -640,7 +639,7 @@ mergeSignatures
is_qual = False,
is_dloc = locA loc
} ImpAll
- rdr_env = mkGlobalRdrEnv (gresFromAvails (Just ispec) as1)
+ rdr_env = mkGlobalRdrEnv $ gresFromAvails hsc_env (Just ispec) as1
setGblEnv tcg_env {
tcg_rdr_env = rdr_env
} $ exports_from_avail mb_exports rdr_env
@@ -650,7 +649,7 @@ mergeSignatures
case mb_r of
Just (_, as2) -> return (thinModIface as2 ireq_iface, as2)
Nothing -> addMessages msgs >> failM
- -- We can't think signatures from non signature packages
+ -- We can't thin signatures from non-signature packages
_ -> return (ireq_iface, as1)
-- 3(c). Only identifiers from signature packages are "ok" to
-- import (that is, they are safe from a PVP perspective.)
@@ -673,7 +672,7 @@ mergeSignatures
<- foldM gen_subst (nsubst0, ok_to_use0, []) (zip reqs ireq_ifaces0)
let thinned_ifaces = reverse rev_thinned_ifaces
exports = nameShapeExports nsubst
- rdr_env = mkGlobalRdrEnv (gresFromAvails Nothing exports)
+ rdr_env = mkGlobalRdrEnv (gresFromAvails hsc_env Nothing exports)
_warn_occs = filter (not . (`elemOccSet` ok_to_use)) (exportOccs exports)
warns = NoWarnings
{-
@@ -698,7 +697,7 @@ mergeSignatures
-- reexports are picked up correctly
tcg_imports = tcg_imports orig_tcg_env,
tcg_exports = exports,
- tcg_dus = usesOnly (availsToNameSetWithSelectors exports),
+ tcg_dus = usesOnly (availsToNameSet exports),
tcg_warns = warns
} $ do
tcg_env <- getGblEnv
@@ -738,9 +737,9 @@ mergeSignatures
let ifaces = lcl_iface : ext_ifaces
-- STEP 4.1: Merge fixities (we'll verify shortly) tcg_fix_env
- let fix_env = mkNameEnv [ (greMangledName rdr_elt, FixItem occ f)
+ let fix_env = mkNameEnv [ (greName rdr_elt, FixItem occ f)
| (occ, f) <- concatMap mi_fixities ifaces
- , rdr_elt <- lookupGlobalRdrEnv rdr_env occ ]
+ , rdr_elt <- lookupGRE_OccName (AllNameSpaces WantBoth) rdr_env occ ]
-- STEP 5: Typecheck the interfaces
let type_env_var = tcg_type_env_var tcg_env
@@ -875,10 +874,10 @@ mergeSignatures
n <- newDFunName (is_cls inst) (is_tys inst) (nameSrcSpan (is_dfun_name inst))
let dfun = setVarName (is_dfun inst) n
return (dfun, inst { is_dfun_name = n, is_dfun = dfun })
- tcg_env <- return tcg_env {
- tcg_insts = map snd dfun_insts,
- tcg_type_env = extendTypeEnvWithIds (tcg_type_env tcg_env) (map fst dfun_insts)
- }
+
+ tcg_env <- return $
+ tcg_env { tcg_insts = map snd dfun_insts
+ , tcg_type_env = extendTypeEnvWithIds (tcg_type_env tcg_env) (map fst dfun_insts) }
addDependentFiles src_files
@@ -912,7 +911,7 @@ tcRnInstantiateSignature hsc_env this_mod real_loc =
logger = hsc_logger hsc_env
exportOccs :: [AvailInfo] -> [OccName]
-exportOccs = concatMap (map occName . availNames)
+exportOccs = concatMap (map nameOccName . availNames)
impl_msg :: UnitState -> Module -> InstantiatedModule -> SDoc
impl_msg unit_state impl_mod (Module req_uid req_mod_name)
@@ -924,7 +923,7 @@ impl_msg unit_state impl_mod (Module req_uid req_mod_name)
-- | Check if module implements a signature. (The signature is
-- always un-hashed, which is why its components are specified
-- explicitly.)
-checkImplements :: Module -> InstantiatedModule -> TcRn TcGblEnv
+checkImplements :: HasDebugCallStack => Module -> InstantiatedModule -> TcRn TcGblEnv
checkImplements impl_mod req_mod@(Module uid mod_name) = do
hsc_env <- getTopEnv
let unit_state = hsc_units hsc_env
@@ -942,7 +941,7 @@ checkImplements impl_mod req_mod@(Module uid mod_name) = do
impl_iface <- initIfaceTcRn $
loadSysInterface (text "checkImplements 1") impl_mod
let impl_gr = mkGlobalRdrEnv
- (gresFromAvails Nothing (mi_exports impl_iface))
+ (gresFromAvails hsc_env Nothing (mi_exports impl_iface))
nsubst = mkNameShape (moduleName impl_mod) (mi_exports impl_iface)
-- Load all the orphans, so the subsequent 'checkHsigIface' sees
@@ -952,9 +951,9 @@ checkImplements impl_mod req_mod@(Module uid mod_name) = do
let avails = calculateAvails home_unit other_home_units
impl_iface False{- safe -} NotBoot ImportedBySystem
- fix_env = mkNameEnv [ (greMangledName rdr_elt, FixItem occ f)
+ fix_env = mkNameEnv [ (greName rdr_elt, FixItem occ f)
| (occ, f) <- mi_fixities impl_iface
- , rdr_elt <- lookupGlobalRdrEnv impl_gr occ ]
+ , rdr_elt <- lookupGRE_OccName (AllNameSpaces WantBoth) impl_gr occ ]
updGblEnv (\tcg_env -> tcg_env {
-- Setting tcg_rdr_env to treat all exported entities from
-- the implementing module as in scope improves error messages,
@@ -988,7 +987,7 @@ checkImplements impl_mod req_mod@(Module uid mod_name) = do
-- STEP 3: Check that the implementing interface exports everything
-- we need. (Notice we IGNORE the Modules in the AvailInfos.)
forM_ (exportOccs (mi_exports isig_iface)) $ \occ ->
- case lookupGlobalRdrEnv impl_gr occ of
+ case lookupGRE_OccName SameOccName impl_gr occ of
[] -> addErr $ TcRnHsigMissingModuleExport occ unit_state impl_mod
_ -> return ()
failIfErrsM
diff --git a/compiler/GHC/Tc/Utils/Env.hs b/compiler/GHC/Tc/Utils/Env.hs
index 43263450ac..52bf245dc5 100644
--- a/compiler/GHC/Tc/Utils/Env.hs
+++ b/compiler/GHC/Tc/Utils/Env.hs
@@ -22,6 +22,7 @@ module GHC.Tc.Utils.Env(
tcLookupLocatedGlobal, tcLookupGlobal, tcLookupGlobalOnly,
tcLookupTyCon, tcLookupClass,
tcLookupDataCon, tcLookupPatSyn, tcLookupConLike,
+ tcLookupRecSelParent,
tcLookupLocatedGlobalId, tcLookupLocatedTyCon,
tcLookupLocatedClass, tcLookupAxiom,
lookupGlobal, lookupGlobal_maybe, ioLookupDataCon,
@@ -74,6 +75,7 @@ module GHC.Tc.Utils.Env(
import GHC.Prelude
import GHC.Driver.Env
+import GHC.Driver.Env.KnotVars
import GHC.Driver.Session
import GHC.Builtin.Names
@@ -96,7 +98,7 @@ import GHC.Tc.Types.Origin ( CtOrigin(UsageEnvironmentOf) )
import GHC.Core.UsageEnv
import GHC.Core.InstEnv
-import GHC.Core.DataCon ( DataCon, flSelector )
+import GHC.Core.DataCon ( DataCon, dataConTyCon, flSelector )
import GHC.Core.PatSyn ( PatSyn )
import GHC.Core.ConLike
import GHC.Core.TyCon
@@ -104,6 +106,7 @@ import GHC.Core.Type
import GHC.Core.Coercion.Axiom
import GHC.Core.Class
+
import GHC.Unit.Module
import GHC.Unit.Home
import GHC.Unit.External
@@ -126,17 +129,18 @@ import GHC.Types.Name
import GHC.Types.Name.Set
import GHC.Types.Name.Env
import GHC.Types.Id
+import GHC.Types.Id.Info ( RecSelParent(..) )
import GHC.Types.Var
import GHC.Types.Var.Env
import GHC.Types.Name.Reader
import GHC.Types.TyThing
+import GHC.Types.Unique.Set ( nonDetEltsUniqSet )
import qualified GHC.LanguageExtensions as LangExt
import GHC.Tc.Errors.Ppr (pprTyThingUsedWrong)
import Data.IORef
-import Data.List (intercalate)
+import Data.List ( intercalate )
import Control.Monad
-import GHC.Driver.Env.KnotVars
{- *********************************************************************
* *
@@ -292,6 +296,17 @@ tcLookupConLike name = do
AConLike cl -> return cl
_ -> wrongThingErr WrongThingConLike (AGlobal thing) name
+tcLookupRecSelParent :: HsRecUpdParent GhcRn -> TcM RecSelParent
+tcLookupRecSelParent (RnRecUpdParent { rnRecUpdCons = cons })
+ = case any_con of
+ PatSynName ps ->
+ RecSelPatSyn <$> tcLookupPatSyn ps
+ DataConName dc ->
+ RecSelData . dataConTyCon <$> tcLookupDataCon dc
+ where
+ any_con = head $ nonDetEltsUniqSet cons
+ -- Any constructor will give the same result here.
+
tcLookupClass :: Name -> TcM Class
tcLookupClass name = do
thing <- tcLookupGlobal name
@@ -508,6 +523,7 @@ tcLookupTcTyCon name = do
ATcTyCon tc -> return tc
_ -> pprPanic "tcLookupTcTyCon" (ppr name)
+
getInLocalScope :: TcM (Name -> Bool)
getInLocalScope = do { lcl_env <- getLclTypeEnv
; return (`elemNameEnv` lcl_env) }
@@ -1064,7 +1080,7 @@ newDFunName clas tys loc
= do { is_boot <- tcIsHsBootOrSig
; mod <- getModule
; let info_string = occNameString (getOccName clas) ++
- concatMap (occNameString.getDFunTyKey) tys
+ concatMap (occNameString . getDFunTyKey) tys
; dfun_occ <- chooseUniqueOccTc (mkDFunOcc info_string is_boot)
; newGlobalBinder mod dfun_occ loc }
diff --git a/compiler/GHC/Tc/Utils/Monad.hs b/compiler/GHC/Tc/Utils/Monad.hs
index a8ab977def..d713fce376 100644
--- a/compiler/GHC/Tc/Utils/Monad.hs
+++ b/compiler/GHC/Tc/Utils/Monad.hs
@@ -55,7 +55,7 @@ module GHC.Tc.Utils.Monad(
getIsGHCi, getGHCiMonad, getInteractivePrintName,
tcIsHsBootOrSig, tcIsHsig, tcSelfBootInfo, getGlobalRdrEnv,
getRdrEnvs, getImports,
- getFixityEnv, extendFixityEnv, getConEnv,
+ getFixityEnv, extendFixityEnv,
getDeclaredDefaultTys,
addDependentFiles,
@@ -209,7 +209,6 @@ import GHC.Types.Annotations
import GHC.Types.Basic( TopLevelFlag, TypeOrKind(..) )
import GHC.Types.CostCentre.State
import GHC.Types.SourceFile
-import GHC.Types.ConInfo (ConFieldEnv)
import qualified GHC.LanguageExtensions as LangExt
@@ -301,7 +300,6 @@ initTc hsc_env hsc_src keep_rn_syntax mod loc do_this
tcg_src = hsc_src,
tcg_rdr_env = emptyGlobalRdrEnv,
tcg_fix_env = emptyNameEnv,
- tcg_con_env = emptyNameEnv,
tcg_default = if moduleUnit mod == primUnit
|| moduleUnit mod == bignumUnit
then Just [] -- See Note [Default types]
@@ -943,9 +941,6 @@ extendFixityEnv new_bit
= updGblEnv (\env@(TcGblEnv { tcg_fix_env = old_fix_env }) ->
env {tcg_fix_env = extendNameEnvList old_fix_env new_bit})
-getConEnv :: TcRn ConFieldEnv
-getConEnv = do { env <- getGblEnv; return (tcg_con_env env) }
-
getDeclaredDefaultTys :: TcRn (Maybe [Type])
getDeclaredDefaultTys = do { env <- getGblEnv; return (tcg_default env) }
diff --git a/compiler/GHC/ThToHs.hs b/compiler/GHC/ThToHs.hs
index 498a17694f..09a1f4562e 100644
--- a/compiler/GHC/ThToHs.hs
+++ b/compiler/GHC/ThToHs.hs
@@ -60,6 +60,7 @@ import Control.Monad( unless, ap )
import Control.Applicative( (<|>) )
import Data.Bifunctor (first)
import Data.Foldable (for_)
+import Data.List (head)
import Data.List.NonEmpty( NonEmpty (..), nonEmpty )
import qualified Data.List.NonEmpty as NE
import Data.Maybe( catMaybes, isNothing )
@@ -69,6 +70,7 @@ import Foreign.ForeignPtr
import Foreign.Ptr
import System.IO.Unsafe
+
-------------------------------------------------------------------
-- The external interface
@@ -275,7 +277,7 @@ cvtDec (DataD ctxt tc tvs ksig constrs derivs)
cvtDec (NewtypeD ctxt tc tvs ksig constr derivs)
= do { (ctxt', tc', tvs') <- cvt_tycl_hdr ctxt tc tvs
; ksig' <- cvtKind `traverse` ksig
- ; con' <- cvtConstr cNameN constr
+ ; con' <- cvtConstr (NE.head $ get_cons_names constr) cNameN constr
; derivs' <- cvtDerivs derivs
; let defn = HsDataDefn { dd_ext = noExtField
, dd_cType = Nothing
@@ -347,7 +349,9 @@ cvtDec (DataFamilyD tc tvs kind)
cvtDec (DataInstD ctxt bndrs tys ksig constrs derivs)
= do { (ctxt', tc', bndrs', typats') <- cvt_datainst_hdr ctxt bndrs tys
; ksig' <- cvtKind `traverse` ksig
- ; cons' <- mapM (cvtConstr cNameN) constrs
+
+ ; let first_datacon = NE.head $ get_cons_names $ head constrs
+ ; cons' <- mapM (cvtConstr first_datacon cNameN) constrs
; derivs' <- cvtDerivs derivs
; let defn = HsDataDefn { dd_ext = noExtField
, dd_cType = Nothing
@@ -369,7 +373,7 @@ cvtDec (DataInstD ctxt bndrs tys ksig constrs derivs)
cvtDec (NewtypeInstD ctxt bndrs tys ksig constr derivs)
= do { (ctxt', tc', bndrs', typats') <- cvt_datainst_hdr ctxt bndrs tys
; ksig' <- cvtKind `traverse` ksig
- ; con' <- cvtConstr cNameN constr
+ ; con' <- cvtConstr (NE.head $ get_cons_names $ constr) cNameN constr
; derivs' <- cvtDerivs derivs
; let defn = HsDataDefn { dd_ext = noExtField
, dd_cType = Nothing
@@ -440,7 +444,8 @@ cvtDec (TH.PatSynD nm args dir pat)
cvtArgs (TH.PrefixPatSyn args) = Hs.PrefixCon noTypeArgs <$> mapM vNameN args
cvtArgs (TH.InfixPatSyn a1 a2) = Hs.InfixCon <$> vNameN a1 <*> vNameN a2
cvtArgs (TH.RecordPatSyn sels)
- = do { sels' <- mapM (fmap (\ (L li i) -> FieldOcc noExtField (L li i)) . vNameN) sels
+ = do { let mk_fld = fldNameN (nameBase nm)
+ ; sels' <- mapM (fmap (\ (L li i) -> FieldOcc noExtField (L li i)) . mk_fld) sels
; vars' <- mapM (vNameN . mkNameS . nameBase) sels
; return $ Hs.RecCon $ zipWith RecordPatSynField sels' vars' }
@@ -502,7 +507,10 @@ cvtGenDataDec type_data ctxt tc tvs ksig constrs derivs
(failWith KindSigsOnlyAllowedOnGADTs)
; (ctxt', tc', tvs') <- cvt_tycl_hdr ctxt tc tvs
; ksig' <- cvtKind `traverse` ksig
- ; cons' <- mapM (cvtConstr con_name) constrs
+
+ ; let first_datacon = NE.head $ get_cons_names $ head constrs
+ ; cons' <- mapM (cvtConstr first_datacon con_name) constrs
+
; derivs' <- cvtDerivs derivs
; let defn = HsDataDefn { dd_ext = noExtField
, dd_cType = Nothing
@@ -649,31 +657,32 @@ is_ip_bind decl = Right decl
-- Data types
---------------------------------------------------
-cvtConstr :: (TH.Name -> CvtM (LocatedN RdrName)) -- ^ convert constructor name
- -> TH.Con -> CvtM (LConDecl GhcPs)
+cvtConstr :: TH.Name -- ^ name of first constructor of parent type
+ -> (TH.Name -> CvtM (LocatedN RdrName)) -- ^ convert constructor name
+ -> TH.Con -> CvtM (LConDecl GhcPs)
-cvtConstr con_name (NormalC c strtys)
- = do { c' <- con_name c
+cvtConstr _ do_con_name (NormalC c strtys)
+ = do { c' <- do_con_name c
; tys' <- mapM cvt_arg strtys
; returnLA $ mkConDeclH98 noAnn c' Nothing Nothing (PrefixCon noTypeArgs (map hsLinear tys')) }
-cvtConstr con_name (RecC c varstrtys)
- = do { c' <- con_name c
- ; args' <- mapM cvt_id_arg varstrtys
+cvtConstr parent_con do_con_name (RecC c varstrtys)
+ = do { c' <- do_con_name c
+ ; args' <- mapM (cvt_id_arg parent_con) varstrtys
; con_decl <- wrapParLA (mkConDeclH98 noAnn c' Nothing Nothing . RecCon) args'
; returnLA con_decl }
-cvtConstr con_name (InfixC st1 c st2)
- = do { c' <- con_name c
+cvtConstr _ do_con_name (InfixC st1 c st2)
+ = do { c' <- do_con_name c
; st1' <- cvt_arg st1
; st2' <- cvt_arg st2
; returnLA $ mkConDeclH98 noAnn c' Nothing Nothing
(InfixCon (hsLinear st1') (hsLinear st2')) }
-cvtConstr con_name (ForallC tvs ctxt con)
+cvtConstr parent_con do_con_name (ForallC tvs ctxt con)
= do { tvs' <- cvtTvs tvs
; ctxt' <- cvtContext funPrec ctxt
- ; L _ con' <- cvtConstr con_name con
+ ; L _ con' <- cvtConstr parent_con do_con_name con
; returnLA $ add_forall tvs' ctxt' con' }
where
add_cxt lcxt Nothing = mkHsContextMaybe lcxt
@@ -701,22 +710,18 @@ cvtConstr con_name (ForallC tvs ctxt con)
where
all_tvs = tvs' ++ ex_tvs
-cvtConstr con_name (GadtC c strtys ty) = case nonEmpty c of
- Nothing -> failWith GadtNoCons
- Just c -> do
- { c' <- mapM con_name c
- ; args <- mapM cvt_arg strtys
- ; ty' <- cvtType ty
- ; mk_gadt_decl c' (PrefixConGADT $ map hsLinear args) ty'}
-
-cvtConstr con_name (RecGadtC c varstrtys ty) = case nonEmpty c of
- Nothing -> failWith RecGadtNoCons
- Just c -> do
- { c' <- mapM con_name c
- ; ty' <- cvtType ty
- ; rec_flds <- mapM cvt_id_arg varstrtys
- ; lrec_flds <- returnLA rec_flds
- ; mk_gadt_decl c' (RecConGADT lrec_flds noHsUniTok) ty' }
+cvtConstr _ do_con_name (GadtC cs strtys ty)
+ = do { cs' <- mapM do_con_name cs
+ ; args <- mapM cvt_arg strtys
+ ; ty' <- cvtType ty
+ ; mk_gadt_decl cs' (PrefixConGADT $ map hsLinear args) ty'}
+
+cvtConstr parent_con do_con_name (RecGadtC cs varstrtys ty)
+ = do { cs' <- mapM do_con_name cs
+ ; ty' <- cvtType ty
+ ; rec_flds <- mapM (cvt_id_arg parent_con) varstrtys
+ ; lrec_flds <- returnLA rec_flds
+ ; mk_gadt_decl cs' (RecConGADT lrec_flds noHsUniTok) ty' }
mk_gadt_decl :: NonEmpty (LocatedN RdrName) -> HsConDeclGADTDetails GhcPs -> LHsType GhcPs
-> CvtM (LConDecl GhcPs)
@@ -750,9 +755,10 @@ cvt_arg (Bang su ss, ty)
ss' = cvtSrcStrictness ss
; returnLA $ HsBangTy noAnn (HsSrcBang NoSourceText su' ss') ty' }
-cvt_id_arg :: (TH.Name, TH.Bang, TH.Type) -> CvtM (LConDeclField GhcPs)
-cvt_id_arg (i, str, ty)
- = do { L li i' <- vNameN i
+cvt_id_arg :: TH.Name -- ^ parent constructor name
+ -> (TH.Name, TH.Bang, TH.Type) -> CvtM (LConDeclField GhcPs)
+cvt_id_arg parent_con (i, str, ty)
+ = do { L li i' <- fldNameN (nameBase parent_con) i
; ty' <- cvt_arg (str,ty)
; returnLA $ ConDeclField
{ cd_fld_ext = noAnn
@@ -1115,7 +1121,10 @@ cvtl e = wrapLA (cvt e)
; flds'
<- mapM (cvtFld (wrapParLA mkAmbiguousFieldOcc))
flds
- ; return $ RecordUpd noAnn e' (Left flds') }
+ ; return $ RecordUpd noAnn e' $
+ RegularRecUpdFields
+ { xRecUpdFields = noExtField
+ , recUpdFields = flds' } }
cvt (StaticE e) = fmap (HsStatic noAnn) $ cvtl e
cvt (UnboundVarE s) = do -- Use of 'vcName' here instead of 'vName' is
-- important, because UnboundVarE may contain
@@ -2052,6 +2061,13 @@ tName n = cvtName OccName.tvName n
tconNameN n = wrapLN (tconName n)
tconName n = cvtName OccName.tcClsName n
+-- Field names
+fldName :: String -> TH.Name -> CvtM RdrName
+fldName con n = cvtName (OccName.fieldName $ fsLit con) n
+
+fldNameN :: String -> TH.Name -> CvtM (LocatedN RdrName)
+fldNameN con n = wrapLN (fldName con n)
+
ipName :: String -> CvtM HsIPName
ipName n
= do { unless (okVarOcc n) (failWith (IllegalOccName OccName.varName n))
@@ -2140,9 +2156,10 @@ mk_occ :: OccName.NameSpace -> String -> OccName.OccName
mk_occ ns occ = OccName.mkOccName ns occ
mk_ghc_ns :: TH.NameSpace -> OccName.NameSpace
-mk_ghc_ns TH.DataName = OccName.dataName
-mk_ghc_ns TH.TcClsName = OccName.tcClsName
-mk_ghc_ns TH.VarName = OccName.varName
+mk_ghc_ns TH.DataName = OccName.dataName
+mk_ghc_ns TH.TcClsName = OccName.tcClsName
+mk_ghc_ns TH.VarName = OccName.varName
+mk_ghc_ns (TH.FldName con) = OccName.fieldName (fsLit con)
mk_mod :: TH.ModName -> ModuleName
mk_mod mod = mkModuleName (TH.modString mod)
diff --git a/compiler/GHC/Types/Avail.hs b/compiler/GHC/Types/Avail.hs
index 346cf4236c..5b8c5fd9a2 100644
--- a/compiler/GHC/Types/Avail.hs
+++ b/compiler/GHC/Types/Avail.hs
@@ -7,33 +7,18 @@
module GHC.Types.Avail (
Avails,
AvailInfo(..),
- avail,
- availField,
- availTC,
availsToNameSet,
- availsToNameSetWithSelectors,
availsToNameEnv,
availExportsDecl,
- availName, availGreName,
- availNames, availNonFldNames,
- availNamesWithSelectors,
- availFlds,
- availGreNames,
- availSubordinateGreNames,
+ availName,
+ availNames,
+ availSubordinateNames,
stableAvailCmp,
plusAvail,
trimAvail,
filterAvail,
filterAvails,
nubAvails,
-
- GreName(..),
- greNameMangledName,
- greNamePrintableName,
- greNameSrcSpan,
- greNameFieldLabel,
- partitionGreNames,
- stableGreNameCmp,
) where
import GHC.Prelude
@@ -41,9 +26,7 @@ import GHC.Prelude
import GHC.Types.Name
import GHC.Types.Name.Env
import GHC.Types.Name.Set
-import GHC.Types.SrcLoc
-import GHC.Types.FieldLabel
import GHC.Utils.Binary
import GHC.Data.List.SetOps
import GHC.Utils.Outputable
@@ -52,10 +35,8 @@ import GHC.Utils.Constants (debugIsOn)
import Control.DeepSeq
import Data.Data ( Data )
-import Data.Either ( partitionEithers )
import Data.Functor.Classes ( liftCompare )
import Data.List ( find )
-import Data.Maybe
import qualified Data.Semigroup as S
-- -----------------------------------------------------------------------------
@@ -66,7 +47,7 @@ data AvailInfo
-- | An ordinary identifier in scope, or a field label without a parent type
-- (see Note [Representing pattern synonym fields in AvailInfo]).
- = Avail GreName
+ = Avail Name
-- | A type or class in scope
--
@@ -75,74 +56,19 @@ data AvailInfo
--
-- > AvailTC Eq [Eq, ==, \/=]
| AvailTC
- Name -- ^ The name of the type or class
- [GreName] -- ^ The available pieces of type or class
- -- (see Note [Representing fields in AvailInfo]).
+ Name -- ^ The name of the type or class
+ [Name] -- ^ The available pieces of type or class
- deriving ( Eq -- ^ Used when deciding if the interface has changed
- , Data )
+ deriving Data
-- | A collection of 'AvailInfo' - several things that are \"available\"
type Avails = [AvailInfo]
-{-
-Note [Representing fields in AvailInfo]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-See also Note [FieldLabel] in GHC.Types.FieldLabel.
-
-When -XDuplicateRecordFields is disabled (the normal case), a
-datatype like
-
- data T = MkT { foo :: Int }
-
-gives rise to the AvailInfo
-
- AvailTC T [T, MkT, FieldLabel "foo" NoDuplicateRecordFields FieldSelectors foo]
-
-whereas if -XDuplicateRecordFields is enabled it gives
-
- AvailTC T [T, MkT, FieldLabel "foo" DuplicateRecordFields FieldSelectors $sel:foo:MkT]
-
-where the label foo does not match the selector name $sel:foo:MkT.
-
-The labels in a field list are not necessarily unique:
-data families allow the same parent (the family tycon) to have
-multiple distinct fields with the same label. For example,
-
- data family F a
- data instance F Int = MkFInt { foo :: Int }
- data instance F Bool = MkFBool { foo :: Bool}
-
-gives rise to
-
- AvailTC F [ F, MkFInt, MkFBool
- , FieldLabel "foo" DuplicateRecordFields FieldSelectors $sel:foo:MkFInt
- , FieldLabel "foo" DuplicateRecordFields FieldSelectors $sel:foo:MkFBool ]
-
-Moreover, note that the flHasDuplicateRecordFields or flFieldSelectors flags
-need not be the same for all the elements of the list. In the example above,
-this occurs if the two data instances are defined in different modules, with
-different states of the `-XDuplicateRecordFields` or `-XNoFieldSelectors`
-extensions. Thus it is possible to have
-
- AvailTC F [ F, MkFInt, MkFBool
- , FieldLabel "foo" DuplicateRecordFields FieldSelectors $sel:foo:MkFInt
- , FieldLabel "foo" NoDuplicateRecordFields FieldSelectors foo ]
-
-If the two data instances are defined in different modules, both without
-`-XDuplicateRecordFields` or `-XNoFieldSelectors`, it will be impossible to
-export them from the same module (even with `-XDuplicateRecordfields` enabled),
-because they would be represented identically. The workaround here is to enable
-`-XDuplicateRecordFields` or `-XNoFieldSelectors` on the defining modules. See
-also #13352.
-
-
-Note [Representing pattern synonym fields in AvailInfo]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+{- Note [Representing pattern synonym fields in AvailInfo]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Record pattern synonym fields cannot be represented using AvailTC like fields of
-normal record types (see Note [Representing fields in AvailInfo]), because they
-do not always have a parent type constructor. So we represent them using the
-Avail constructor, with a NormalGreName that carries the underlying FieldLabel.
+normal record types, because they do not always have a parent type constructor.
+So we represent them using the Avail constructor.
Thus under -XDuplicateRecordFields -XPatternSynoynms, the declaration
@@ -150,43 +76,22 @@ Thus under -XDuplicateRecordFields -XPatternSynoynms, the declaration
gives rise to the AvailInfo
- Avail (NormalGreName MkFoo)
- Avail (FieldGreName (FieldLabel "f" True $sel:f:MkFoo))
+ Avail MkFoo, Avail f
However, if `f` is bundled with a type constructor `T` by using `T(MkFoo,f)` in
an export list, then whenever `f` is imported the parent will be `T`,
represented as
- AvailTC T [ NormalGreName T
- , NormalGreName MkFoo
- , FieldGreName (FieldLabel "f" True $sel:f:MkFoo) ]
-
-See also Note [GreNames] in GHC.Types.Name.Reader.
+ AvailTC T [ T, MkFoo, f ]
-}
-- | Compare lexicographically
stableAvailCmp :: AvailInfo -> AvailInfo -> Ordering
-stableAvailCmp (Avail c1) (Avail c2) = c1 `stableGreNameCmp` c2
+stableAvailCmp (Avail c1) (Avail c2) = c1 `stableNameCmp` c2
stableAvailCmp (Avail {}) (AvailTC {}) = LT
-stableAvailCmp (AvailTC n ns) (AvailTC m ms) = stableNameCmp n m S.<> liftCompare stableGreNameCmp ns ms
+stableAvailCmp (AvailTC n ns) (AvailTC m ms) = stableNameCmp n m S.<> liftCompare stableNameCmp ns ms
stableAvailCmp (AvailTC {}) (Avail {}) = GT
-stableGreNameCmp :: GreName -> GreName -> Ordering
-stableGreNameCmp (NormalGreName n1) (NormalGreName n2) = n1 `stableNameCmp` n2
-stableGreNameCmp (NormalGreName {}) (FieldGreName {}) = LT
-stableGreNameCmp (FieldGreName f1) (FieldGreName f2) = flSelector f1 `stableNameCmp` flSelector f2
-stableGreNameCmp (FieldGreName {}) (NormalGreName {}) = GT
-
-avail :: Name -> AvailInfo
-avail n = Avail (NormalGreName n)
-
-availField :: FieldLabel -> AvailInfo
-availField fl = Avail (FieldGreName fl)
-
-availTC :: Name -> [Name] -> [FieldLabel] -> AvailInfo
-availTC n ns fls = AvailTC n (map NormalGreName ns ++ map FieldGreName fls)
-
-
-- -----------------------------------------------------------------------------
-- Operations on AvailInfo
@@ -194,10 +99,6 @@ availsToNameSet :: [AvailInfo] -> NameSet
availsToNameSet avails = foldr add emptyNameSet avails
where add avail set = extendNameSetList set (availNames avail)
-availsToNameSetWithSelectors :: [AvailInfo] -> NameSet
-availsToNameSetWithSelectors avails = foldr add emptyNameSet avails
- where add avail set = extendNameSetList set (availNamesWithSelectors avail)
-
availsToNameEnv :: [AvailInfo] -> NameEnv AvailInfo
availsToNameEnv avails = foldr add emptyNameEnv avails
where add avail env = extendNameEnvList env
@@ -207,110 +108,29 @@ availsToNameEnv avails = foldr add emptyNameEnv avails
-- invariant that the parent is first if it appears at all.
availExportsDecl :: AvailInfo -> Bool
availExportsDecl (AvailTC ty_name names)
- | n : _ <- names = NormalGreName ty_name == n
+ | n : _ <- names = ty_name == n
| otherwise = False
availExportsDecl _ = True
-- | Just the main name made available, i.e. not the available pieces
-- of type or class brought into scope by the 'AvailInfo'
availName :: AvailInfo -> Name
-availName (Avail n) = greNameMangledName n
+availName (Avail n) = n
availName (AvailTC n _) = n
-availGreName :: AvailInfo -> GreName
-availGreName (Avail c) = c
-availGreName (AvailTC n _) = NormalGreName n
-
--- | All names made available by the availability information (excluding overloaded selectors)
-availNames :: AvailInfo -> [Name]
-availNames (Avail c) = childNonOverloadedNames c
-availNames (AvailTC _ cs) = concatMap childNonOverloadedNames cs
-
-childNonOverloadedNames :: GreName -> [Name]
-childNonOverloadedNames (NormalGreName n) = [n]
-childNonOverloadedNames (FieldGreName fl) = [ flSelector fl | not (flIsOverloaded fl) ]
-
--- | All names made available by the availability information (including overloaded selectors)
-availNamesWithSelectors :: AvailInfo -> [Name]
-availNamesWithSelectors (Avail c) = [greNameMangledName c]
-availNamesWithSelectors (AvailTC _ cs) = map greNameMangledName cs
-
--- | Names for non-fields made available by the availability information
-availNonFldNames :: AvailInfo -> [Name]
-availNonFldNames (Avail (NormalGreName n)) = [n]
-availNonFldNames (Avail (FieldGreName {})) = []
-availNonFldNames (AvailTC _ ns) = mapMaybe f ns
- where
- f (NormalGreName n) = Just n
- f (FieldGreName {}) = Nothing
-
--- | Fields made available by the availability information
-availFlds :: AvailInfo -> [FieldLabel]
-availFlds (Avail c) = maybeToList (greNameFieldLabel c)
-availFlds (AvailTC _ cs) = mapMaybe greNameFieldLabel cs
-
-- | Names and fields made available by the availability information.
-availGreNames :: AvailInfo -> [GreName]
-availGreNames (Avail c) = [c]
-availGreNames (AvailTC _ cs) = cs
+availNames :: AvailInfo -> [Name]
+availNames (Avail c) = [c]
+availNames (AvailTC _ cs) = cs
-- | Names and fields made available by the availability information, other than
-- the main decl itself.
-availSubordinateGreNames :: AvailInfo -> [GreName]
-availSubordinateGreNames (Avail {}) = []
-availSubordinateGreNames avail@(AvailTC _ ns)
+availSubordinateNames :: AvailInfo -> [Name]
+availSubordinateNames (Avail {}) = []
+availSubordinateNames avail@(AvailTC _ ns)
| availExportsDecl avail = tail ns
| otherwise = ns
-
--- | Used where we may have an ordinary name or a record field label.
--- See Note [GreNames] in GHC.Types.Name.Reader.
-data GreName = NormalGreName Name
- | FieldGreName FieldLabel
- deriving (Data, Eq)
-
-instance Outputable GreName where
- ppr (NormalGreName n) = ppr n
- ppr (FieldGreName fl) = ppr fl
-
-instance NFData GreName where
- rnf (NormalGreName n) = rnf n
- rnf (FieldGreName f) = rnf f
-
-instance HasOccName GreName where
- occName (NormalGreName n) = occName n
- occName (FieldGreName fl) = occName fl
-
-instance Ord GreName where
- compare = stableGreNameCmp
-
--- | A 'Name' for internal use, but not for output to the user. For fields, the
--- 'OccName' will be the selector. See Note [GreNames] in GHC.Types.Name.Reader.
-greNameMangledName :: GreName -> Name
-greNameMangledName (NormalGreName n) = n
-greNameMangledName (FieldGreName fl) = flSelector fl
-
--- | A 'Name' suitable for output to the user. For fields, the 'OccName' will
--- be the field label. See Note [GreNames] in GHC.Types.Name.Reader.
-greNamePrintableName :: GreName -> Name
-greNamePrintableName (NormalGreName n) = n
-greNamePrintableName (FieldGreName fl) = fieldLabelPrintableName fl
-
-greNameSrcSpan :: GreName -> SrcSpan
-greNameSrcSpan (NormalGreName n) = nameSrcSpan n
-greNameSrcSpan (FieldGreName fl) = nameSrcSpan (flSelector fl)
-
-greNameFieldLabel :: GreName -> Maybe FieldLabel
-greNameFieldLabel (NormalGreName {}) = Nothing
-greNameFieldLabel (FieldGreName fl) = Just fl
-
-partitionGreNames :: [GreName] -> ([Name], [FieldLabel])
-partitionGreNames = partitionEithers . map to_either
- where
- to_either (NormalGreName n) = Left n
- to_either (FieldGreName fl) = Right fl
-
-
-- -----------------------------------------------------------------------------
-- Utility
@@ -322,7 +142,7 @@ plusAvail a1@(Avail {}) (Avail {}) = a1
plusAvail (AvailTC _ []) a2@(AvailTC {}) = a2
plusAvail a1@(AvailTC {}) (AvailTC _ []) = a1
plusAvail (AvailTC n1 (s1:ss1)) (AvailTC n2 (s2:ss2))
- = case (NormalGreName n1==s1, NormalGreName n2==s2) of -- Maintain invariant the parent is first
+ = case (n1 == s1, n2 == s2) of -- Maintain invariant the parent is first
(True,True) -> AvailTC n1 (s1 : (ss1 `unionListsOrd` ss2))
(True,False) -> AvailTC n1 (s1 : (ss1 `unionListsOrd` (s2:ss2)))
(False,True) -> AvailTC n1 (s2 : ((s1:ss1) `unionListsOrd` ss2))
@@ -332,7 +152,7 @@ plusAvail a1 a2 = pprPanic "GHC.Rename.Env.plusAvail" (hsep [ppr a1,ppr a2])
-- | trims an 'AvailInfo' to keep only a single name
trimAvail :: AvailInfo -> Name -> AvailInfo
trimAvail avail@(Avail {}) _ = avail
-trimAvail avail@(AvailTC n ns) m = case find ((== m) . greNameMangledName) ns of
+trimAvail avail@(AvailTC n ns) m = case find (== m) ns of
Just c -> AvailTC n [c]
Nothing -> pprPanic "trimAvail" (hsep [ppr avail, ppr m])
@@ -344,10 +164,10 @@ filterAvails keep avails = foldr (filterAvail keep) [] avails
filterAvail :: (Name -> Bool) -> AvailInfo -> [AvailInfo] -> [AvailInfo]
filterAvail keep ie rest =
case ie of
- Avail c | keep (greNameMangledName c) -> ie : rest
+ Avail c | keep c -> ie : rest
| otherwise -> rest
AvailTC tc cs ->
- let cs' = filter (keep . greNameMangledName) cs
+ let cs' = filter keep cs
in if null cs' then rest else AvailTC tc cs' : rest
@@ -393,19 +213,3 @@ instance Binary AvailInfo where
instance NFData AvailInfo where
rnf (Avail n) = rnf n
rnf (AvailTC a b) = rnf a `seq` rnf b
-
-instance Binary GreName where
- put_ bh (NormalGreName aa) = do
- putByte bh 0
- put_ bh aa
- put_ bh (FieldGreName ab) = do
- putByte bh 1
- put_ bh ab
- get bh = do
- h <- getByte bh
- case h of
- 0 -> do aa <- get bh
- return (NormalGreName aa)
- _ -> do ab <- get bh
- return (FieldGreName ab)
-
diff --git a/compiler/GHC/Types/Basic.hs b/compiler/GHC/Types/Basic.hs
index 1ad6b608fc..1f73c82028 100644
--- a/compiler/GHC/Types/Basic.hs
+++ b/compiler/GHC/Types/Basic.hs
@@ -16,6 +16,7 @@ types that
{-# OPTIONS_GHC -Wno-orphans #-} -- Outputable PromotionFlag, Binary PromotionFlag, Outputable Boxity, Binay Boxity
{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
@@ -109,6 +110,8 @@ module GHC.Types.Basic (
Levity(..), mightBeLifted, mightBeUnlifted,
TypeOrConstraint(..),
+ TyConFlavour(..), TypeOrData(..), tyConFlavourAssoc_maybe,
+
NonStandardDefaultingStrategy(..),
DefaultingStrategy(..), defaultNonStandardTyVars,
@@ -124,12 +127,16 @@ import GHC.Utils.Panic
import GHC.Utils.Binary
import GHC.Types.SourceText
import qualified GHC.LanguageExtensions as LangExt
-import Data.Data
-import qualified Data.Semigroup as Semi
import {-# SOURCE #-} Language.Haskell.Syntax.Type (PromotionFlag(..), isPromoted)
import Language.Haskell.Syntax.Basic (Boxity(..), isBoxed, ConTag)
-{- *********************************************************************
+import Control.DeepSeq ( NFData(..) )
+import Data.Data
+import Data.Maybe
+import qualified Data.Semigroup as Semi
+
+{-
+************************************************************************
* *
Binary choice
* *
@@ -1970,6 +1977,77 @@ data TypeOrConstraint
{- *********************************************************************
* *
+ TyConFlavour
+* *
+********************************************************************* -}
+
+-- | Paints a picture of what a 'TyCon' represents, in broad strokes.
+-- This is used towards more informative error messages.
+data TyConFlavour tc
+ = ClassFlavour
+ | TupleFlavour Boxity
+ | SumFlavour
+ | DataTypeFlavour
+ | NewtypeFlavour
+ | AbstractTypeFlavour
+ | OpenFamilyFlavour TypeOrData (Maybe tc) -- Just tc <=> (tc == associated class)
+ | ClosedTypeFamilyFlavour
+ | TypeSynonymFlavour
+ | BuiltInTypeFlavour -- ^ e.g., the @(->)@ 'TyCon'.
+ | PromotedDataConFlavour
+ deriving (Eq, Data, Functor)
+
+instance Outputable (TyConFlavour tc) where
+ ppr = text . go
+ where
+ go ClassFlavour = "class"
+ go (TupleFlavour boxed) | isBoxed boxed = "tuple"
+ | otherwise = "unboxed tuple"
+ go SumFlavour = "unboxed sum"
+ go DataTypeFlavour = "data type"
+ go NewtypeFlavour = "newtype"
+ go AbstractTypeFlavour = "abstract type"
+ go (OpenFamilyFlavour type_or_data mb_par)
+ = assoc ++ t_or_d ++ " family"
+ where
+ assoc = if isJust mb_par then "associated " else ""
+ t_or_d = case type_or_data of { IAmType -> "type"; IAmData -> "data" }
+ go ClosedTypeFamilyFlavour = "type family"
+ go TypeSynonymFlavour = "type synonym"
+ go BuiltInTypeFlavour = "built-in type"
+ go PromotedDataConFlavour = "promoted data constructor"
+
+instance NFData tc => NFData (TyConFlavour tc) where
+ rnf ClassFlavour = ()
+ rnf (TupleFlavour !_) = ()
+ rnf SumFlavour = ()
+ rnf DataTypeFlavour = ()
+ rnf NewtypeFlavour = ()
+ rnf AbstractTypeFlavour = ()
+ rnf (OpenFamilyFlavour !_ mb_tc) = rnf mb_tc
+ rnf ClosedTypeFamilyFlavour = ()
+ rnf TypeSynonymFlavour = ()
+ rnf BuiltInTypeFlavour = ()
+ rnf PromotedDataConFlavour = ()
+
+-- | Get the enclosing class TyCon (if there is one) for the given TyConFlavour
+tyConFlavourAssoc_maybe :: TyConFlavour tc -> Maybe tc
+tyConFlavourAssoc_maybe (OpenFamilyFlavour _ mb_parent) = mb_parent
+tyConFlavourAssoc_maybe _ = Nothing
+
+-- | Whether something is a type or a data declaration,
+-- e.g. a type family or a data family.
+data TypeOrData
+ = IAmData
+ | IAmType
+ deriving (Eq, Data)
+
+instance Outputable TypeOrData where
+ ppr IAmData = text "data"
+ ppr IAmType = text "type"
+
+{- *********************************************************************
+* *
Defaulting options
* *
********************************************************************* -}
diff --git a/compiler/GHC/Types/ConInfo.hs b/compiler/GHC/Types/ConInfo.hs
deleted file mode 100644
index b89ce2632d..0000000000
--- a/compiler/GHC/Types/ConInfo.hs
+++ /dev/null
@@ -1,82 +0,0 @@
-{-# LANGUAGE DerivingStrategies #-}
-module GHC.Types.ConInfo (
- ConFieldEnv, ConInfo(..), mkConInfo, conInfoFields,
- ) where
-
-import GHC.Prelude
-import GHC.Types.Name.Env (NameEnv)
-import Data.List.NonEmpty (NonEmpty)
-import GHC.Types.FieldLabel ( FieldLabel )
-import qualified Data.List.NonEmpty as NonEmpty
-import GHC.Types.Basic (Arity)
-import GHC.Utils.Outputable (Outputable(..), text, (<+>), equals, braces, (<>))
-
-{- Note [Local constructor info in the renamer]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-During renaming, we need certain information about constructors.
-
-While we can use TypeEnv to get this info for constructors from imported modules,
-the same cannot be done for constructors defined in the module
-that we are currently renaming, as they have not been type checked yet.
-
-Hence, we use ConFieldEnv to store the minimal information required to proceed
-with renaming, getting it from the parse tree.
-
-For example, consider
- data T = T1 { x, y :: Int }
- | T2 { x :: Int }
- | T3
- | T4 Int Bool
-
-Specifically we need to know:
-* The fields of the data constructor, so that
- - We can complain if you say `T1 { v = 3 }`, where `v` is not a field of `T1`
- See the following call stack
- * GHC.Rename.Expr.rnExpr (RecordCon case)
- * GHC.Rename.Pat.rnHsRecFields
- * GHC.Rename.Env.lookupRecFieldOcc
- - Ditto if you pattern match on `T1 { v = x }`.
- See the following call stack
- * GHC.Rename.Pat.rnHsRecPatsAndThen
- * GHC.Rename.Pat.rnHsRecFields
- * GHC.Rename.Env.lookupRecFieldOcc
- - We can fill in the dots if you say `T1 {..}` in construction or pattern matching
- See GHC.Rename.Pat.rnHsRecFields.rn_dotdot
-
-* Whether the contructor is nullary.
- We need to know this to accept `T2 {..}`, and `T3 {..}`, but reject `T4 {..}`,
- in both construction and pattern matching.
- See GHC.Rename.Pat.rnHsRecFields.rn_dotdot
- and Note [Nullary constructors and empty record wildcards]
-
-Note [Nullary constructors and empty record wildcards]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-A nullary constructor is one with no arguments.
-For example, both `data T = MkT` and `data T = MkT {}` are nullary.
-
-For consistency and TH convenience, it was agreed that a `{..}`
-match or usage on nullary constructors would be accepted.
-This is done as as per https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0496-empty-record-wildcards.rst
--}
-type ConFieldEnv = NameEnv ConInfo
-
--- | See Note [Local constructor info in the renamer]
-data ConInfo
- = ConHasRecordFields (NonEmpty FieldLabel)
- | ConHasPositionalArgs
- | ConIsNullary
- deriving stock Eq
-
-mkConInfo :: Arity -> [FieldLabel] -> ConInfo
-mkConInfo 0 _ = ConIsNullary
-mkConInfo _ fields = maybe ConHasPositionalArgs ConHasRecordFields $ NonEmpty.nonEmpty fields
-
-conInfoFields :: ConInfo -> [FieldLabel]
-conInfoFields (ConHasRecordFields fields) = NonEmpty.toList fields
-conInfoFields ConHasPositionalArgs = []
-conInfoFields ConIsNullary = []
-
-instance Outputable ConInfo where
- ppr ConIsNullary = text "ConIsNullary"
- ppr ConHasPositionalArgs = text "ConHasPositionalArgs"
- ppr (ConHasRecordFields fieldLabels) = text "ConHasRecordFields" <> braces (text "fieldLabels" <+> equals <+> ppr fieldLabels)
diff --git a/compiler/GHC/Types/Error/Codes.hs b/compiler/GHC/Types/Error/Codes.hs
index 3508a218d2..aa4360908b 100644
--- a/compiler/GHC/Types/Error/Codes.hs
+++ b/compiler/GHC/Types/Error/Codes.hs
@@ -403,14 +403,12 @@ type family GhcDiagnosticCode c = n | n -> c where
GhcDiagnosticCode "TcRnDuplicateExport" = 47854
GhcDiagnosticCode "TcRnExportedParentChildMismatch" = 88993
GhcDiagnosticCode "TcRnConflictingExports" = 69158
- GhcDiagnosticCode "TcRnAmbiguousField" = 02256
+ GhcDiagnosticCode "TcRnDuplicateFieldExport" = 97219
+ GhcDiagnosticCode "TcRnAmbiguousFieldInUpdate" = 56428
+ GhcDiagnosticCode "TcRnAmbiguousRecordUpdate" = 02256
GhcDiagnosticCode "TcRnMissingFields" = 20125
GhcDiagnosticCode "TcRnFieldUpdateInvalidType" = 63055
- GhcDiagnosticCode "TcRnNoConstructorHasAllFields" = 14392
- GhcDiagnosticCode "TcRnMixedSelectors" = 40887
GhcDiagnosticCode "TcRnMissingStrictFields" = 95909
- GhcDiagnosticCode "TcRnNoPossibleParentForFields" = 33238
- GhcDiagnosticCode "TcRnBadOverloadedRecordUpdate" = 99339
GhcDiagnosticCode "TcRnStaticFormNotClosed" = 88431
GhcDiagnosticCode "TcRnUselessTypeable" = 90584
GhcDiagnosticCode "TcRnDerivingDefaults" = 20042
@@ -448,7 +446,6 @@ type family GhcDiagnosticCode c = n | n -> c where
GhcDiagnosticCode "TcRnUnsupportedCallConv" = 01245
GhcDiagnosticCode "TcRnInvalidCIdentifier" = 95774
GhcDiagnosticCode "TcRnExpectedValueId" = 01570
- GhcDiagnosticCode "TcRnNotARecordSelector" = 47535
GhcDiagnosticCode "TcRnRecSelectorEscapedTyVar" = 55876
GhcDiagnosticCode "TcRnPatSynNotBidirectional" = 16444
GhcDiagnosticCode "TcRnSplicePolymorphicLocalVar" = 06568
@@ -557,6 +554,11 @@ type family GhcDiagnosticCode c = n | n -> c where
GhcDiagnosticCode "HasExistentialTyVar" = 07525
GhcDiagnosticCode "HasStrictnessAnnotation" = 04049
+ -- TcRnBadRecordUpdate
+ GhcDiagnosticCode "NoConstructorHasAllFields" = 14392
+ GhcDiagnosticCode "MultiplePossibleParents" = 99339
+ GhcDiagnosticCode "InvalidTyConParent" = 33238
+
-- TcRnPragmaWarning
GhcDiagnosticCode "WarningTxt" = 63394
GhcDiagnosticCode "DeprecatedTxt" = 68441
@@ -577,8 +579,6 @@ type family GhcDiagnosticCode c = n | n -> c where
GhcDiagnosticCode "CasesExprWithoutAlts" = 91745
GhcDiagnosticCode "ImplicitParamsWithOtherBinds" = 42974
GhcDiagnosticCode "InvalidCCallImpent" = 60220
- GhcDiagnosticCode "RecGadtNoCons" = 18816
- GhcDiagnosticCode "GadtNoCons" = 38140
GhcDiagnosticCode "InvalidTypeInstanceHeader" = 37056
GhcDiagnosticCode "InvalidTyFamInstLHS" = 78486
GhcDiagnosticCode "InvalidImplicitParamBinding" = 51603
@@ -603,6 +603,7 @@ type family GhcDiagnosticCode c = n | n -> c where
-- Out of scope errors
GhcDiagnosticCode "NotInScope" = 76037
+ GhcDiagnosticCode "NotARecordField" = 22385
GhcDiagnosticCode "NoExactName" = 97784
GhcDiagnosticCode "SameName" = 81573
GhcDiagnosticCode "MissingBinding" = 44432
@@ -658,9 +659,11 @@ type family GhcDiagnosticCode c = n | n -> c where
-- and this includes outdated diagnostic codes for errors that GHC
-- no longer reports. These are collected below.
- GhcDiagnosticCode "Example outdated error" = 00000
GhcDiagnosticCode "TcRnNameByTemplateHaskellQuote" = 40027
GhcDiagnosticCode "TcRnIllegalBindingOfBuiltIn" = 69639
+ GhcDiagnosticCode "TcRnMixedSelectors" = 40887
+ GhcDiagnosticCode "RecGadtNoCons" = 18816
+ GhcDiagnosticCode "GadtNoCons" = 38140
{- *********************************************************************
* *
@@ -718,6 +721,7 @@ type family ConRecursInto con where
ConRecursInto "TcRnIllegalNewtype" = 'Just IllegalNewtypeReason
ConRecursInto "TcRnHsigShapeMismatch" = 'Just HsigShapeMismatchReason
ConRecursInto "TcRnPatSynInvalidRhs" = 'Just PatSynInvalidRhsReason
+ ConRecursInto "TcRnBadRecordUpdate" = 'Just BadRecordUpdateReason
--
-- TH errors
diff --git a/compiler/GHC/Types/FieldLabel.hs b/compiler/GHC/Types/FieldLabel.hs
index 89bfd4afee..9c35a3ee30 100644
--- a/compiler/GHC/Types/FieldLabel.hs
+++ b/compiler/GHC/Types/FieldLabel.hs
@@ -10,7 +10,6 @@
Note [FieldLabel]
~~~~~~~~~~~~~~~~~
-
This module defines the representation of FieldLabels as stored in
TyCons. As well as a selector name, these have some extra structure
to support the DuplicateRecordFields and NoFieldSelectors extensions.
@@ -22,60 +21,25 @@ a datatype like
has
- FieldLabel { flLabel = "foo"
- , flHasDuplicateRecordFields = NoDuplicateRecordFields
+ FieldLabel { flHasDuplicateRecordFields = NoDuplicateRecordFields
, flHasFieldSelector = FieldSelectors
, flSelector = foo }.
-In particular, the Name of the selector has the same string
-representation as the label. If DuplicateRecordFields
-is enabled, however, the same declaration instead gives
+If DuplicateRecordFields is enabled, however, the same declaration instead gives
- FieldLabel { flLabel = "foo"
- , flHasDuplicateRecordFields = DuplicateRecordFields
+ FieldLabel { flHasDuplicateRecordFields = DuplicateRecordFields
, flHasFieldSelector = FieldSelectors
- , flSelector = $sel:foo:MkT }.
-
-Similarly, the selector name will be mangled if NoFieldSelectors is used
-(whether or not DuplicateRecordFields is enabled). See Note [NoFieldSelectors]
-in GHC.Rename.Env.
-
-Now the name of the selector ($sel:foo:MkT) does not match the label of
-the field (foo). We must be careful not to show the selector name to
-the user! The point of mangling the selector name is to allow a
-module to define the same field label in different datatypes:
-
- data T = MkT { foo :: Int }
- data U = MkU { foo :: Bool }
-
-Now there will be two FieldLabel values for 'foo', one in T and one in
-U. They share the same label (FieldLabelString), but the selector
-functions differ.
-
-See also Note [Representing fields in AvailInfo] in GHC.Types.Avail.
-
-Note [Why selector names include data constructors]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-As explained above, a selector name includes the name of the first
-data constructor in the type, so that the same label can appear
-multiple times in the same module. (This is irrespective of whether
-the first constructor has that field, for simplicity.)
-
-We use a data constructor name, rather than the type constructor name,
-because data family instances do not have a representation type
-constructor name generated until relatively late in the typechecking
-process.
-
-Of course, datatypes with no constructors cannot have any fields.
+ , flSelector = foo }.
+We need to keep track of whether FieldSelectors or DuplicateRecordFields were
+enabled when a record field was defined, as they affect name resolution and
+shadowing of record fields, as explained in Note [NoFieldSelectors] in GHC.Types.Name.Reader
+and Note [Reporting duplicate local declarations] in GHC.Rename.Names.
-}
module GHC.Types.FieldLabel
( FieldLabelEnv
- , FieldLabel(..)
- , fieldSelectorOccName
- , fieldLabelPrintableName
+ , FieldLabel(..), flLabel
, DuplicateRecordFields(..)
, FieldSelectors(..)
, flIsOverloaded
@@ -84,10 +48,8 @@ where
import GHC.Prelude
-import {-# SOURCE #-} GHC.Types.Name.Occurrence
import {-# SOURCE #-} GHC.Types.Name
-import GHC.Data.FastString
import GHC.Data.FastString.Env
import GHC.Types.Unique (Uniquable(..))
import GHC.Utils.Outputable
@@ -104,20 +66,23 @@ type FieldLabelEnv = DFastStringEnv FieldLabel
-- | Fields in an algebraic record type; see Note [FieldLabel].
data FieldLabel = FieldLabel {
- flLabel :: FieldLabelString,
- -- ^ User-visible label of the field
flHasDuplicateRecordFields :: DuplicateRecordFields,
-- ^ Was @DuplicateRecordFields@ on in the defining module for this datatype?
flHasFieldSelector :: FieldSelectors,
-- ^ Was @FieldSelectors@ enabled in the defining module for this datatype?
-- See Note [NoFieldSelectors] in GHC.Rename.Env
flSelector :: Name
- -- ^ Record selector function
+ -- ^ The 'Name' of the selector function, which uniquely identifies
+ -- the field label.
}
deriving (Data, Eq)
+-- | User-visible label of a field.
+flLabel :: FieldLabel -> FieldLabelString
+flLabel = FieldLabelString . occNameFS . nameOccName . flSelector
+
instance HasOccName FieldLabel where
- occName = mkVarOccFS . field_label . flLabel
+ occName = nameOccName . flSelector
instance Outputable FieldLabel where
ppr fl = ppr (flLabel fl) <> whenPprDebug (braces (ppr (flSelector fl))
@@ -130,9 +95,6 @@ instance Outputable FieldLabelString where
instance Uniquable FieldLabelString where
getUnique (FieldLabelString fs) = getUnique fs
-instance NFData FieldLabel where
- rnf (FieldLabel a b c d) = rnf a `seq` rnf b `seq` rnf c `seq` rnf d
-
-- | Flag to indicate whether the DuplicateRecordFields extension is enabled.
data DuplicateRecordFields
= DuplicateRecordFields -- ^ Fields may be duplicated in a single module
@@ -148,7 +110,9 @@ instance Outputable DuplicateRecordFields where
ppr NoDuplicateRecordFields = text "-dup"
instance NFData DuplicateRecordFields where
- rnf x = x `seq` ()
+ rnf DuplicateRecordFields = ()
+ rnf NoDuplicateRecordFields = ()
+
-- | Flag to indicate whether the FieldSelectors extension is enabled.
data FieldSelectors
@@ -165,55 +129,27 @@ instance Outputable FieldSelectors where
ppr NoFieldSelectors = text "-sel"
instance NFData FieldSelectors where
- rnf x = x `seq` ()
+ rnf FieldSelectors = ()
+ rnf NoFieldSelectors = ()
-- | We need the @Binary Name@ constraint here even though there is an instance
-- defined in "GHC.Types.Name", because the we have a SOURCE import, so the
-- instance is not in scope. And the instance cannot be added to Name.hs-boot
-- because "GHC.Utils.Binary" itself depends on "GHC.Types.Name".
instance Binary Name => Binary FieldLabel where
- put_ bh (FieldLabel aa ab ac ad) = do
- put_ bh (field_label aa)
+ put_ bh (FieldLabel aa ab ac) = do
+ put_ bh aa
put_ bh ab
- put_ bh ac
- put_ bh ad
+ case getUserData bh of
+ UserData{ ud_put_binding_name = put_binding_name } ->
+ put_binding_name bh ac
get bh = do
aa <- get bh
ab <- get bh
ac <- get bh
- ad <- get bh
- return (FieldLabel (FieldLabelString aa) ab ac ad)
-
-
--- | Record selector OccNames are built from the underlying field name
--- and the name of the first data constructor of the type, to support
--- duplicate record field names.
--- See Note [Why selector names include data constructors].
-fieldSelectorOccName :: FieldLabelString -> OccName -> DuplicateRecordFields -> FieldSelectors -> OccName
-fieldSelectorOccName lbl dc dup_fields_ok has_sel
- | shouldMangleSelectorNames dup_fields_ok has_sel = mkRecFldSelOcc str
- | otherwise = mkVarOccFS fl
- where
- fl = field_label lbl
- str = concatFS [fsLit ":", fl, fsLit ":", occNameFS dc]
-
--- | Undo the name mangling described in Note [FieldLabel] to produce a Name
--- that has the user-visible OccName (but the selector's unique). This should
--- be used only when generating output, when we want to show the label, but may
--- need to qualify it with a module prefix.
-fieldLabelPrintableName :: FieldLabel -> Name
-fieldLabelPrintableName fl
- | flIsOverloaded fl = tidyNameOcc (flSelector fl) (mkVarOccFS (field_label $ flLabel fl))
- | otherwise = flSelector fl
-
--- | Selector name mangling should be used if either DuplicateRecordFields or
--- NoFieldSelectors is enabled, so that the OccName of the field can be used for
--- something else. See Note [FieldLabel], and Note [NoFieldSelectors] in
--- GHC.Rename.Env.
-shouldMangleSelectorNames :: DuplicateRecordFields -> FieldSelectors -> Bool
-shouldMangleSelectorNames dup_fields_ok has_sel
- = dup_fields_ok == DuplicateRecordFields || has_sel == NoFieldSelectors
+ return (FieldLabel aa ab ac)
flIsOverloaded :: FieldLabel -> Bool
flIsOverloaded fl =
- shouldMangleSelectorNames (flHasDuplicateRecordFields fl) (flHasFieldSelector fl)
+ flHasDuplicateRecordFields fl == DuplicateRecordFields
+ || flHasFieldSelector fl == NoFieldSelectors
diff --git a/compiler/GHC/Types/GREInfo.hs b/compiler/GHC/Types/GREInfo.hs
new file mode 100644
index 0000000000..23d734b7d1
--- /dev/null
+++ b/compiler/GHC/Types/GREInfo.hs
@@ -0,0 +1,276 @@
+{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE DerivingStrategies #-}
+
+-- | Renamer-level information about 'Name's.
+--
+-- Renamer equivalent of 'TyThing'.
+module GHC.Types.GREInfo where
+
+import GHC.Prelude
+
+import GHC.Types.Basic
+import GHC.Types.FieldLabel
+import GHC.Types.Name
+import GHC.Types.Unique
+import GHC.Types.Unique.Set
+import GHC.Utils.Outputable
+import GHC.Utils.Panic
+
+import Control.DeepSeq ( NFData(..), deepseq )
+
+import Data.Data ( Data )
+import Data.List.NonEmpty ( NonEmpty )
+import qualified Data.List.NonEmpty as NonEmpty
+
+{-**********************************************************************
+* *
+ GREInfo
+* *
+************************************************************************
+
+Note [GREInfo]
+~~~~~~~~~~~~~~
+In the renamer, we sometimes need a bit more information about a 'Name', e.g.
+whether it is a type constructor, class, data constructor, record field, etc.
+
+For example, when typechecking record construction, the renamer needs to look
+up the fields of the data constructor being used (see e.g. GHC.Rename.Pat.rnHsRecFields).
+Extra information also allows us to provide better error messages when a fatal
+error occurs in the renamer, as it allows us to distinguish classes, type families,
+type synonyms, etc.
+
+For imported Names, we have access to the full type information in the form of
+a TyThing (although see Note [Retrieving the GREInfo from interfaces]).
+However, for Names in the module currently being renamed, we don't
+yet have full information. Instead of using TyThing, we use the GREInfo type,
+and this information gets affixed to each element in the GlobalRdrEnv.
+
+This allows us to treat imported and local Names in a consistent manner:
+always look at the GREInfo.
+
+Note [Retrieving the GREInfo from interfaces]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+If we have a TyThing, we can easily compute the corresponding GREInfo: this is
+done in GHC.Types.TyThing.tyThingGREInfo.
+
+However, one often needs to produce GlobalRdrElts (and thus their GREInfos)
+directly after loading interface files, before they are typechecked. For example:
+
+ - GHC.Tc.Module.tcRnModuleTcRnM first calls tcRnImports, which starts off
+ calling rnImports which transitively calls filterImports. That function
+ is responsible for coughing up GlobalRdrElts (and their GREInfos) obtained
+ from interfaces, but we will only typecheck the interfaces after we have
+ finished processing the imports (see e.g. the logic at the start of tcRnImports
+ which sets eps_is_boot, which decides whether we should look in the boot
+ or non-boot interface for any particular module).
+ - GHC.Tc.Utils.Backpack.mergeSignatures first loads the relevant signature
+ interfaces to merge them, but only later on does it typecheck them.
+
+In both of these examples, what's important is that we **lazily** produce the
+GREInfo: it should only be consulted once the interfaces have been typechecked,
+which will add the necessary information to the type-level environment.
+In particular, the respective functions 'filterImports' and 'mergeSignatures'
+should NOT force the gre_info field.
+
+We delay the loading of interfaces by making the gre_info field of 'GlobalRdrElt'
+a thunk which, when forced, loads the interface, looks up the 'Name' in the type
+environment to get its associated TyThing, and computes the GREInfo from that.
+See 'GHC.Rename.Env.lookupGREInfo'.
+
+A possible alternative design would be to change the AvailInfo datatype to also
+store GREInfo. We currently don't do that, as this would mean that every time
+an interface re-exports something it has to also provide its GREInfo, which
+could lead to bloat.
+
+Note [Forcing GREInfo]
+~~~~~~~~~~~~~~~~~~~~~~
+The GREInfo field of a GlobalRdrElt needs to be lazy, as explained in
+Note [Retrieving the GREInfo from interfaces]. For imported things, this field
+is usually a thunk which looks up the GREInfo in a type environment
+(see GHC.Rename.Env.lookupGREInfo).
+
+We thus need to be careful not to introduce space leaks: such thunks could end
+up retaining old type environments, which would violate invariant (5) of
+Note [GHC Heap Invariants] in GHC.Driver.Make. This can happen, for example,
+when reloading in GHCi (see e.g. test T15369, which can trigger the ghci leak check
+if we're not careful).
+
+A naive approach is to simply deeply force the whole GlobalRdrEnv. However,
+forcing the GREInfo thunks can force the loading of interface files which we
+otherwise might not need to load, so it leads to wasted work.
+
+Instead, whenever we are about to store the GlobalRdrEnv somewhere (such as
+in ModDetails), we dehydrate it by stripping away the GREInfo field, turning it
+into (). See 'forceGlobalRdrEnv' and its cousin 'hydrateGlobalRdrEnv',
+as well as Note [IfGlobalRdrEnv] in GHC.Types.Name.Reader.
+
+Search for references to this note in the code for illustration.
+-}
+
+-- | Information about a 'Name' that is pertinent to the renamer.
+--
+-- See Note [GREInfo]
+data GREInfo
+ -- | No particular information... e.g. a function
+ = Vanilla
+ -- | 'TyCon'
+ | IAmTyCon !(TyConFlavour Name)
+ -- | 'ConLike'
+ | IAmConLike !ConInfo
+ -- ^ The constructor fields.
+ -- See Note [Local constructor info in the renamer].
+ -- | Record field
+ | IAmRecField !RecFieldInfo
+
+ deriving Data
+
+instance NFData GREInfo where
+ rnf Vanilla = ()
+ rnf (IAmTyCon tc) = rnf tc
+ rnf (IAmConLike info) = rnf info
+ rnf (IAmRecField info) = rnf info
+
+plusGREInfo :: GREInfo -> GREInfo -> GREInfo
+plusGREInfo Vanilla Vanilla = Vanilla
+plusGREInfo (IAmTyCon {}) info2@(IAmTyCon {}) = info2
+plusGREInfo (IAmConLike {}) info2@(IAmConLike {}) = info2
+plusGREInfo (IAmRecField {}) info2@(IAmRecField {}) = info2
+plusGREInfo info1 info2 = pprPanic "plusInfo" $
+ vcat [ text "info1:" <+> ppr info1
+ , text "info2:" <+> ppr info2 ]
+
+instance Outputable GREInfo where
+ ppr Vanilla = text "Vanilla"
+ ppr (IAmTyCon flav)
+ = text "TyCon" <+> ppr flav
+ ppr (IAmConLike info)
+ = text "ConLike" <+> ppr info
+ ppr (IAmRecField info)
+ = text "RecField" <+> ppr info
+
+{-**********************************************************************
+* *
+ Constructor info
+* *
+************************************************************************
+
+Note [Local constructor info in the renamer]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+As explained in Note [GREInfo], information pertinent to the renamer is
+stored using the GREInfo datatype. What information do we need about constructors?
+
+Consider the following example:
+
+ data T = T1 { x, y :: Int }
+ | T2 { x :: Int }
+ | T3
+ | T4 Int Bool
+
+We need to know:
+* The fields of the data constructor, so that
+ - We can complain if you say `T1 { v = 3 }`, where `v` is not a field of `T1`
+ See the following call stack
+ * GHC.Rename.Expr.rnExpr (RecordCon case)
+ * GHC.Rename.Pat.rnHsRecFields
+ * GHC.Rename.Env.lookupRecFieldOcc
+ - Ditto if you pattern match on `T1 { v = x }`.
+ See the following call stack
+ * GHC.Rename.Pat.rnHsRecPatsAndThen
+ * GHC.Rename.Pat.rnHsRecFields
+ * GHC.Rename.Env.lookupRecFieldOcc
+ - We can fill in the dots if you say `T1 {..}` in construction or pattern matching
+ See GHC.Rename.Pat.rnHsRecFields.rn_dotdot
+
+* Whether the contructor is nullary.
+ We need to know this to accept `T2 {..}`, and `T3 {..}`, but reject `T4 {..}`,
+ in both construction and pattern matching.
+ See GHC.Rename.Pat.rnHsRecFields.rn_dotdot
+ and Note [Nullary constructors and empty record wildcards]
+
+Note [Nullary constructors and empty record wildcards]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+A nullary constructor is one with no arguments.
+For example, both `data T = MkT` and `data T = MkT {}` are nullary.
+
+For consistency and TH convenience, it was agreed that a `{..}`
+match or usage on nullary constructors would be accepted.
+This is done as as per https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0496-empty-record-wildcards.rst
+-}
+
+-- | Information about the record fields of a constructor.
+--
+-- See Note [Local constructor info in the renamer]
+data ConInfo
+ = ConHasRecordFields (NonEmpty FieldLabel)
+ | ConHasPositionalArgs
+ | ConIsNullary
+ deriving stock Eq
+ deriving Data
+
+instance NFData ConInfo where
+ rnf ConIsNullary = ()
+ rnf ConHasPositionalArgs = ()
+ rnf (ConHasRecordFields flds) = rnf flds
+
+mkConInfo :: Arity -> [FieldLabel] -> ConInfo
+mkConInfo 0 _ = ConIsNullary
+mkConInfo _ fields = maybe ConHasPositionalArgs ConHasRecordFields
+ $ NonEmpty.nonEmpty fields
+
+conInfoFields :: ConInfo -> [FieldLabel]
+conInfoFields (ConHasRecordFields fields) = NonEmpty.toList fields
+conInfoFields ConHasPositionalArgs = []
+conInfoFields ConIsNullary = []
+
+instance Outputable ConInfo where
+ ppr ConIsNullary = text "ConIsNullary"
+ ppr ConHasPositionalArgs = text "ConHasPositionalArgs"
+ ppr (ConHasRecordFields fieldLabels) =
+ text "ConHasRecordFields" <+> braces (ppr fieldLabels)
+
+-- | The 'Name' of a 'ConLike'.
+--
+-- Useful when we are in the renamer and don't yet have a full 'DataCon' or
+-- 'PatSyn' to hand.
+data ConLikeName
+ = DataConName { conLikeName_Name :: !Name }
+ | PatSynName { conLikeName_Name :: !Name }
+ deriving (Eq, Data)
+
+instance Outputable ConLikeName where
+ ppr = ppr . conLikeName_Name
+
+instance Uniquable ConLikeName where
+ getUnique = getUnique . conLikeName_Name
+
+instance NFData ConLikeName where
+ rnf = rnf . conLikeName_Name
+
+{-**********************************************************************
+* *
+ Record field info
+* *
+**********************************************************************-}
+
+data RecFieldInfo
+ = RecFieldInfo
+ { recFieldLabel :: !FieldLabel
+ , recFieldCons :: !(UniqSet ConLikeName)
+ -- ^ The constructors which have this field label.
+ -- Always non-empty.
+ --
+ -- NB: these constructors will always share a single parent,
+ -- as the field label disambiguates between parents in the presence
+ -- of duplicate record fields.
+ }
+ deriving (Eq, Data)
+
+instance NFData RecFieldInfo where
+ rnf (RecFieldInfo lbl cons)
+ = rnf lbl `seq` nonDetStrictFoldUniqSet deepseq () cons
+
+instance Outputable RecFieldInfo where
+ ppr (RecFieldInfo { recFieldLabel = fl, recFieldCons = cons })
+ = text "RecFieldInfo" <+> braces
+ (text "recFieldLabel:" <+> ppr fl <> comma
+ <+> text "recFieldCons:" <+> pprWithCommas ppr (nonDetEltsUniqSet cons))
diff --git a/compiler/GHC/Types/Id.hs b/compiler/GHC/Types/Id.hs
index 28a220cb1d..bbfb8ce09d 100644
--- a/compiler/GHC/Types/Id.hs
+++ b/compiler/GHC/Types/Id.hs
@@ -480,15 +480,15 @@ isRecordSelector id = case Var.idDetails id of
isDataConRecordSelector id = case Var.idDetails id of
RecSelId {sel_tycon = RecSelData _} -> True
- _ -> False
+ _ -> False
isPatSynRecordSelector id = case Var.idDetails id of
RecSelId {sel_tycon = RecSelPatSyn _} -> True
- _ -> False
+ _ -> False
isNaughtyRecordSelector id = case Var.idDetails id of
RecSelId { sel_naughty = n } -> n
- _ -> False
+ _ -> False
isClassOpId id = case Var.idDetails id of
ClassOpId {} -> True
@@ -527,8 +527,8 @@ isDataConWorkId_maybe id = case Var.idDetails id of
_ -> Nothing
isDataConWrapId id = case Var.idDetails id of
- DataConWrapId _ -> True
- _ -> False
+ DataConWrapId _ -> True
+ _ -> False
isDataConWrapId_maybe id = case Var.idDetails id of
DataConWrapId con -> Just con
@@ -832,15 +832,15 @@ asNonWorkerLikeId :: Id -> Id
asNonWorkerLikeId id =
let details = case idDetails id of
WorkerLikeId{} -> Just $ VanillaId
- JoinId arity Just{} -> Just $ JoinId arity Nothing
- _ -> Nothing
+ JoinId arity Just{} -> Just $ JoinId arity Nothing
+ _ -> Nothing
in maybeModifyIdDetails details id
-- | Turn this id into a WorkerLikeId if possible.
asWorkerLikeId :: Id -> Id
asWorkerLikeId id =
let details = case idDetails id of
- WorkerLikeId{} -> Nothing
+ WorkerLikeId{} -> Nothing
JoinId _arity Just{} -> Nothing
JoinId arity Nothing -> Just (JoinId arity (Just []))
VanillaId -> Just $ WorkerLikeId []
diff --git a/compiler/GHC/Types/Id/Info.hs b/compiler/GHC/Types/Id/Info.hs
index 2b6785117d..9ee20a841a 100644
--- a/compiler/GHC/Types/Id/Info.hs
+++ b/compiler/GHC/Types/Id/Info.hs
@@ -8,9 +8,11 @@
Haskell. [WDP 94/11])
-}
-
-{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE BinaryLiterals #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE TypeFamilies #-}
{-# OPTIONS_GHC -Wno-incomplete-record-updates #-}
@@ -18,7 +20,7 @@ module GHC.Types.Id.Info (
-- * The IdDetails type
IdDetails(..), pprIdDetails, coVarDetails, isCoVarDetails,
JoinArity, isJoinIdDetails_maybe,
- RecSelParent(..),
+ RecSelParent(..), recSelParentName, recSelFirstConName,
-- * The IdInfo type
IdInfo, -- Abstract
@@ -95,6 +97,7 @@ import GHC.Types.Var.Set
import GHC.Types.Basic
import GHC.Core.DataCon
import GHC.Core.TyCon
+import GHC.Core.Type (mkTyConApp)
import GHC.Core.PatSyn
import GHC.Types.ForeignCall
import GHC.Unit.Module
@@ -105,11 +108,11 @@ import GHC.Utils.Outputable
import GHC.Utils.Panic
import GHC.Utils.Panic.Plain
import GHC.Stg.InferTags.TagSig
+import GHC.StgToCmm.Types (LambdaFormInfo)
+import Data.Data ( Data )
import Data.Word
-import GHC.StgToCmm.Types (LambdaFormInfo)
-
-- infixl so you can say (id `set` a `set` b)
infixl 1 `setRuleInfo`,
`setArityInfo`,
@@ -138,8 +141,9 @@ data IdDetails
-- | The 'Id' for a record selector
| RecSelId
- { sel_tycon :: RecSelParent
- , sel_naughty :: Bool -- True <=> a "naughty" selector which can't actually exist, for example @x@ in:
+ { sel_tycon :: RecSelParent
+ , sel_fieldLabel :: FieldLabel
+ , sel_naughty :: Bool -- True <=> a "naughty" selector which can't actually exist, for example @x@ in:
-- data T = forall a. MkT { x :: a }
} -- See Note [Naughty record selectors] in GHC.Tc.TyCl
@@ -273,17 +277,40 @@ some applied arguments as we won't inline the wrapper/apply their rule
if there are unapplied occurrences like `map f xs`.
-}
--- | Recursive Selector Parent
-data RecSelParent = RecSelData TyCon | RecSelPatSyn PatSyn deriving Eq
- -- Either `TyCon` or `PatSyn` depending
- -- on the origin of the record selector.
- -- For a data type family, this is the
- -- /instance/ 'TyCon' not the family 'TyCon'
+-- | Parent of a record selector function.
+--
+-- Either the parent 'TyCon' or 'PatSyn' depending
+-- on the origin of the record selector.
+--
+-- For a data family, this is the /instance/ 'TyCon',
+-- **not** the family 'TyCon'.
+data RecSelParent
+ -- | Parent of a data constructor record field.
+ --
+ -- For a data family, this is the /instance/ 'TyCon'.
+ = RecSelData TyCon
+ -- | Parent of a pattern synonym record field:
+ -- the 'PatSyn' itself.
+ | RecSelPatSyn PatSyn
+ deriving (Eq, Data)
+
+recSelParentName :: RecSelParent -> Name
+recSelParentName (RecSelData tc) = tyConName tc
+recSelParentName (RecSelPatSyn ps) = patSynName ps
+
+recSelFirstConName :: RecSelParent -> Name
+recSelFirstConName (RecSelData tc) = dataConName $ head $ tyConDataCons tc
+recSelFirstConName (RecSelPatSyn ps) = patSynName ps
instance Outputable RecSelParent where
ppr p = case p of
- RecSelData ty_con -> ppr ty_con
- RecSelPatSyn ps -> ppr ps
+ RecSelData tc
+ | Just (parent_tc, tys) <- tyConFamInst_maybe tc
+ -> ppr (mkTyConApp parent_tc tys)
+ | otherwise
+ -> ppr tc
+ RecSelPatSyn ps
+ -> ppr ps
-- | Just a synonym for 'CoVarId'. Written separately so it can be
-- exported in the hs-boot file.
@@ -307,7 +334,7 @@ pprIdDetails VanillaId = empty
pprIdDetails other = brackets (pp other)
where
pp VanillaId = panic "pprIdDetails"
- pp (WorkerLikeId dmds) = text "StrictWorker" <> parens (ppr dmds)
+ pp (WorkerLikeId dmds) = text "StrictWorker" <> parens (ppr dmds)
pp (DataConWorkId _) = text "DataCon"
pp (DataConWrapId _) = text "DataConWrapper"
pp (ClassOpId {}) = text "ClassOp"
diff --git a/compiler/GHC/Types/Name.hs b/compiler/GHC/Types/Name.hs
index 7d441039e9..8a2f3bbdde 100644
--- a/compiler/GHC/Types/Name.hs
+++ b/compiler/GHC/Types/Name.hs
@@ -2,6 +2,8 @@
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TypeFamilies #-}
+{-# OPTIONS_GHC -Wno-orphans #-} -- instance NFData FieldLabel
+
{-
(c) The University of Glasgow 2006
(c) The GRASP/AQUA Project, Glasgow University, 1992-1998
@@ -63,7 +65,7 @@ module GHC.Types.Name (
-- ** Predicates on 'Name's
isSystemName, isInternalName, isExternalName,
isTyVarName, isTyConName, isDataConName,
- isValName, isVarName, isDynLinkName,
+ isValName, isVarName, isDynLinkName, isFieldName,
isWiredInName, isWiredIn, isBuiltInSyntax, isTupleTyConName,
isHoleName,
wiredInNameTyThing_maybe,
@@ -91,6 +93,7 @@ import GHC.Platform
import GHC.Types.Name.Occurrence
import GHC.Unit.Module
import GHC.Unit.Home
+import GHC.Types.FieldLabel
import GHC.Types.SrcLoc
import GHC.Types.Unique
import GHC.Utils.Misc
@@ -159,6 +162,10 @@ instance Outputable NameSort where
instance NFData Name where
rnf Name{..} = rnf n_sort `seq` rnf n_occ `seq` n_uniq `seq` rnf n_loc
+-- Needs NFData Name, so the instance is here to avoid cyclic imports.
+instance NFData FieldLabel where
+ rnf (FieldLabel a b c) = rnf a `seq` rnf b `seq` rnf c
+
instance NFData NameSort where
rnf (External m) = rnf m
rnf (WiredIn m t b) = rnf m `seq` t `seq` b `seq` ()
@@ -436,6 +443,9 @@ isValName name = isValOcc (nameOccName name)
isVarName :: Name -> Bool
isVarName = isVarOcc . nameOccName
+isFieldName :: Name -> Bool
+isFieldName = isFieldOcc . nameOccName
+
isSystemName (Name {n_sort = System}) = True
isSystemName _ = False
@@ -642,13 +652,14 @@ pprName name@(Name {n_sort = sort, n_uniq = uniq, n_occ = occ})
= docWithStyle codeDoc normalDoc
where
codeDoc = case sort of
- WiredIn mod _ _ -> pprModule mod <> char '_' <> ppr_z_occ_name occ
- External mod -> pprModule mod <> char '_' <> ppr_z_occ_name occ
+ WiredIn mod _ _ -> pprModule mod <> char '_' <> z_occ
+ External mod -> pprModule mod <> char '_' <> z_occ
-- In code style, always qualify
-- ToDo: maybe we could print all wired-in things unqualified
-- in code style, to reduce symbol table bloat?
System -> pprUniqueAlways uniq
Internal -> pprUniqueAlways uniq
+ z_occ = ztext $ zEncodeFS $ occNameMangledFS occ
normalDoc sty =
getPprDebug $ \debug ->
@@ -761,11 +772,6 @@ ppr_occ_name occ = ftext (occNameFS occ)
-- Don't use pprOccName; instead, just print the string of the OccName;
-- we print the namespace in the debug stuff above
--- In code style, we Z-encode the strings. The results of Z-encoding each FastString are
--- cached behind the scenes in the FastString implementation.
-ppr_z_occ_name :: IsLine doc => OccName -> doc
-ppr_z_occ_name occ = ztext (zEncodeFS (occNameFS occ))
-
-- Prints (if mod information is available) "Defined at <loc>" or
-- "Defined in <mod>" information for a Name.
pprDefinedAt :: Name -> SDoc
diff --git a/compiler/GHC/Types/Name.hs-boot b/compiler/GHC/Types/Name.hs-boot
index e7e4cf2c7b..658fc8969f 100644
--- a/compiler/GHC/Types/Name.hs-boot
+++ b/compiler/GHC/Types/Name.hs-boot
@@ -3,7 +3,7 @@ module GHC.Types.Name (
module GHC.Types.Name.Occurrence
) where
-import GHC.Prelude (Eq)
+import GHC.Prelude (Eq, Bool)
import {-# SOURCE #-} GHC.Types.Name.Occurrence
import GHC.Types.Unique
import GHC.Utils.Outputable
@@ -28,3 +28,4 @@ nameUnique :: Name -> Unique
setNameUnique :: Name -> Unique -> Name
nameOccName :: Name -> OccName
tidyNameOcc :: Name -> OccName -> Name
+isFieldName :: Name -> Bool
diff --git a/compiler/GHC/Types/Name/Env.hs b/compiler/GHC/Types/Name/Env.hs
index 5990355426..f96d3957fb 100644
--- a/compiler/GHC/Types/Name/Env.hs
+++ b/compiler/GHC/Types/Name/Env.hs
@@ -19,7 +19,9 @@ module GHC.Types.Name.Env (
unitNameEnv, nonDetNameEnvElts,
extendNameEnv_C, extendNameEnv_Acc, extendNameEnv,
extendNameEnvList, extendNameEnvList_C,
- filterNameEnv, mapMaybeNameEnv, anyNameEnv,
+ filterNameEnv, anyNameEnv,
+ mapMaybeNameEnv,
+ extendNameEnvListWith,
plusNameEnv, plusNameEnv_C, plusNameEnv_CD, plusNameEnv_CD2, alterNameEnv,
lookupNameEnv, lookupNameEnv_NF, delFromNameEnv, delListFromNameEnv,
elemNameEnv, mapNameEnv, disjointNameEnv,
@@ -113,6 +115,7 @@ plusNameEnv_C :: (a->a->a) -> NameEnv a -> NameEnv a -> NameEnv a
plusNameEnv_CD :: (a->a->a) -> NameEnv a -> a -> NameEnv a -> a -> NameEnv a
plusNameEnv_CD2 :: (Maybe a->Maybe a->a) -> NameEnv a -> NameEnv a -> NameEnv a
extendNameEnvList :: NameEnv a -> [(Name,a)] -> NameEnv a
+extendNameEnvListWith :: (a -> Name) -> NameEnv a -> [a] -> NameEnv a
extendNameEnvList_C :: (a->a->a) -> NameEnv a -> [(Name,a)] -> NameEnv a
delFromNameEnv :: NameEnv a -> Name -> NameEnv a
delListFromNameEnv :: NameEnv a -> [Name] -> NameEnv a
@@ -133,6 +136,7 @@ isEmptyNameEnv = isNullUFM
unitNameEnv x y = unitUFM x y
extendNameEnv x y z = addToUFM x y z
extendNameEnvList x l = addListToUFM x l
+extendNameEnvListWith f x l = addListToUFM x (map (\a -> (f a, a)) l)
lookupNameEnv x y = lookupUFM x y
alterNameEnv = alterUFM
mkNameEnv l = listToUFM l
@@ -151,7 +155,7 @@ delFromNameEnv x y = delFromUFM x y
delListFromNameEnv x y = delListFromUFM x y
filterNameEnv x y = filterUFM x y
mapMaybeNameEnv x y = mapMaybeUFM x y
-anyNameEnv f x = foldUFM ((||) . f) False x
+anyNameEnv f x = nonDetFoldUFM ((||) . f) False x
disjointNameEnv x y = disjointUFM x y
seqEltsNameEnv seqElt x = seqEltsUFM seqElt x
diff --git a/compiler/GHC/Types/Name/Occurrence.hs b/compiler/GHC/Types/Name/Occurrence.hs
index e8d42eb0cf..b7d95543b0 100644
--- a/compiler/GHC/Types/Name/Occurrence.hs
+++ b/compiler/GHC/Types/Name/Occurrence.hs
@@ -3,8 +3,11 @@
(c) The GRASP/AQUA Project, Glasgow University, 1992-1998
-}
-{-# LANGUAGE DeriveDataTypeable #-}
+--{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE MagicHash #-}
{-# LANGUAGE OverloadedStrings #-}
-- |
@@ -29,7 +32,7 @@ module GHC.Types.Name.Occurrence (
-- ** Construction
-- $real_vs_source_data_constructors
- tcName, clsName, tcClsName, dataName, varName,
+ tcName, clsName, tcClsName, dataName, varName, fieldName,
tvName, srcDataName,
-- ** Pretty Printing
@@ -37,11 +40,12 @@ module GHC.Types.Name.Occurrence (
-- * The 'OccName' type
OccName, -- Abstract, instance of Outputable
- pprOccName,
+ pprOccName, occNameMangledFS,
-- ** Construction
mkOccName, mkOccNameFS,
mkVarOcc, mkVarOccFS,
+ mkRecFieldOcc, mkRecFieldOccFS,
mkDataOcc, mkDataOccFS,
mkTyVarOcc, mkTyVarOccFS,
mkTcOcc, mkTcOccFS,
@@ -51,6 +55,8 @@ module GHC.Types.Name.Occurrence (
demoteOccName,
demoteOccTvName,
promoteOccName,
+ varToRecFieldOcc,
+ recFieldToVarOcc,
HasOccName(..),
-- ** Derived 'OccName's
@@ -67,30 +73,35 @@ module GHC.Types.Name.Occurrence (
mkSuperDictSelOcc, mkSuperDictAuxOcc,
mkLocalOcc, mkMethodOcc, mkInstTyTcOcc,
mkInstTyCoOcc, mkEqPredCoOcc,
- mkRecFldSelOcc,
mkTyConRepOcc,
-- ** Deconstruction
occNameFS, occNameString, occNameSpace,
isVarOcc, isTvOcc, isTcOcc, isDataOcc, isDataSymOcc, isSymOcc, isValOcc,
+ isFieldOcc, fieldOcc_maybe,
parenSymOcc, startsWithUnderscore,
isTcClsNameSpace, isTvNameSpace, isDataConNameSpace, isVarNameSpace, isValNameSpace,
+ isFieldNameSpace, isTermVarOrFieldNameSpace,
-- * The 'OccEnv' type
- OccEnv, emptyOccEnv, unitOccEnv, extendOccEnv, mapOccEnv,
- lookupOccEnv, mkOccEnv, mkOccEnv_C, extendOccEnvList, elemOccEnv,
- nonDetOccEnvElts, foldOccEnv, plusOccEnv, plusOccEnv_C, extendOccEnv_C,
+ OccEnv, emptyOccEnv, unitOccEnv, extendOccEnv,
+ mapOccEnv, strictMapOccEnv,
+ lookupOccEnv, lookupOccEnv_WithFields, lookupFieldsOccEnv,
+ mkOccEnv, mkOccEnv_C, extendOccEnvList, elemOccEnv,
+ nonDetOccEnvElts, nonDetFoldOccEnv,
+ plusOccEnv, plusOccEnv_C,
extendOccEnv_Acc, filterOccEnv, delListFromOccEnv, delFromOccEnv,
- alterOccEnv, minusOccEnv, minusOccEnv_C, pprOccEnv,
+ alterOccEnv, minusOccEnv, minusOccEnv_C, minusOccEnv_C_Ns,
+ pprOccEnv, forceOccEnv,
+ intersectOccEnv_C,
-- * The 'OccSet' type
OccSet, emptyOccSet, unitOccSet, mkOccSet, extendOccSet,
extendOccSetList,
- unionOccSets, unionManyOccSets, minusOccSet, elemOccSet,
- isEmptyOccSet, intersectOccSet,
- filterOccSet, occSetToEnv,
+ unionOccSets, unionManyOccSets, elemOccSet,
+ isEmptyOccSet,
-- * Tidying up
TidyOccEnv, emptyTidyOccEnv, initTidyOccEnv,
@@ -102,9 +113,9 @@ module GHC.Types.Name.Occurrence (
import GHC.Prelude
+import GHC.Builtin.Uniques
import GHC.Utils.Misc
import GHC.Types.Unique
-import GHC.Builtin.Uniques
import GHC.Types.Unique.FM
import GHC.Types.Unique.Set
import GHC.Data.FastString
@@ -112,10 +123,13 @@ import GHC.Data.FastString.Env
import GHC.Utils.Outputable
import GHC.Utils.Lexeme
import GHC.Utils.Binary
+import GHC.Utils.Panic.Plain
+
import Control.DeepSeq
import Data.Char
import Data.Data
import qualified Data.Semigroup as S
+import GHC.Exts( Int(I#), dataToTag# )
{-
************************************************************************
@@ -125,32 +139,108 @@ import qualified Data.Semigroup as S
************************************************************************
-}
-data NameSpace = VarName -- Variables, including "real" data constructors
- | DataName -- "Source" data constructors
- | TvName -- Type variables
- | TcClsName -- Type constructors and classes; Haskell has them
- -- in the same name space for now.
- deriving( Eq, Ord )
+data NameSpace
+ -- | Variable name space (including "real" data constructors).
+ = VarName
+ -- | Record field namespace for the given record.
+ | FldName
+ { fldParent :: !FastString
+ -- ^ The textual name of the parent of the field.
+ --
+ -- - For a field of a datatype, this is the name of the first constructor
+ -- of the datatype (regardless of whether this constructor has this field).
+ -- - For a field of a pattern synonym, this is the name of the pattern synonym.
+ }
+ -- | "Source" data constructor namespace.
+ | DataName
+ -- | Type variable namespace.
+ | TvName
+ -- | Type constructor and class namespace.
+ | TcClsName
+ -- Haskell has type constructors and classes in the same namespace, for now.
+ deriving Eq
+
+instance Ord NameSpace where
+ compare ns1 ns2 =
+ case compare (I# (dataToTag# ns1)) (I# (dataToTag# ns2)) of
+ LT -> LT
+ GT -> GT
+ EQ
+ | FldName { fldParent = p1 } <- ns1
+ , FldName { fldParent = p2 } <- ns2
+ -> lexicalCompareFS p1 p2
+ | otherwise
+ -> EQ
+
+instance Uniquable NameSpace where
+ getUnique (FldName fs) = mkFldNSUnique fs
+ getUnique VarName = varNSUnique
+ getUnique DataName = dataNSUnique
+ getUnique TvName = tvNSUnique
+ getUnique TcClsName = tcNSUnique
+
+instance NFData NameSpace where
+ rnf VarName = ()
+ rnf (FldName par) = rnf par
+ rnf DataName = ()
+ rnf TvName = ()
+ rnf TcClsName = ()
--- Note [Data Constructors]
--- ~~~~~~~~~~~~~~~~~~~~~~~~
--- see also: Note [Data Constructor Naming] in GHC.Core.DataCon
---
--- $real_vs_source_data_constructors
--- There are two forms of data constructor:
---
--- [Source data constructors] The data constructors mentioned in Haskell source code
---
--- [Real data constructors] The data constructors of the representation type, which may not be the same as the source type
---
--- For example:
---
--- > data T = T !(Int, Int)
---
--- The source datacon has type @(Int, Int) -> T@
--- The real datacon has type @Int -> Int -> T@
---
--- GHC chooses a representation based on the strictness etc.
+{-
+Note [Data Constructors]
+~~~~~~~~~~~~~~~~~~~~~~~~
+see also: Note [Data Constructor Naming] in GHC.Core.DataCon
+
+$real_vs_source_data_constructors
+There are two forms of data constructor:
+
+ [Source data constructors] The data constructors mentioned in Haskell source code
+
+ [Real data constructors] The data constructors of the representation type, which may not be the same as the source type
+
+For example:
+
+> data T = T !(Int, Int)
+
+The source datacon has type @(Int, Int) -> T@
+The real datacon has type @Int -> Int -> T@
+
+GHC chooses a representation based on the strictness etc.
+
+Note [Record field namespacing]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Record fields have a separate namespace from variables, to support
+DuplicateRecordFields, e.g. in
+
+ data X = MkX { fld :: Int }
+ data Y = MkY { fld :: Bool }
+
+ f x = x { fld = 3 }
+ g y = y { fld = False }
+
+we want the two occurrences of "fld" to refer to the field names associated with
+the corresponding data type.
+
+The namespace for a record field is as follows:
+
+ - for a data type, it is the textual name of the first constructor of the
+ datatype, whether this constructor has this field or not;
+ - for a pattern synonym, it is the textual name of the pattern synonym itself.
+
+Record fields are initially parsed as variables, but the renamer resolves their
+namespace in GHC.Rename.Names.newRecordFieldLabel, which is called when renaming
+record data declarations and record pattern synonym declarations.
+
+To illustrate the namespacing, consider the record field "fld" in the following datatype
+
+ data instance A Int Bool Char
+ = MkA1 | MkA2 { fld :: Int } | MkA3 { bar :: Bool, fld :: Int }
+
+Its namespace is `FldName "MkA1"`. This is a convention used throughout GHC
+to circumvent the fact that we don't have a way to refer to the type constructor
+"A Int Bool Char" in the renamer, as data family instances only get given
+'Name's in the typechecker.
+-}
tcName, clsName, tcClsName :: NameSpace
dataName, srcDataName :: NameSpace
@@ -169,6 +259,9 @@ srcDataName = DataName -- Haskell-source data constructors should be
tvName = TvName
varName = VarName
+fieldName :: FastString -> NameSpace
+fieldName = FldName
+
isDataConNameSpace :: NameSpace -> Bool
isDataConNameSpace DataName = True
isDataConNameSpace _ = False
@@ -182,30 +275,44 @@ isTvNameSpace TvName = True
isTvNameSpace _ = False
isVarNameSpace :: NameSpace -> Bool -- Variables or type variables, but not constructors
-isVarNameSpace TvName = True
-isVarNameSpace VarName = True
-isVarNameSpace _ = False
+isVarNameSpace TvName = True
+isVarNameSpace VarName = True
+isVarNameSpace (FldName {}) = True
+isVarNameSpace _ = False
+
+-- | Is this a term variable or field name namespace?
+isTermVarOrFieldNameSpace :: NameSpace -> Bool
+isTermVarOrFieldNameSpace VarName = True
+isTermVarOrFieldNameSpace (FldName {}) = True
+isTermVarOrFieldNameSpace _ = False
isValNameSpace :: NameSpace -> Bool
-isValNameSpace DataName = True
-isValNameSpace VarName = True
-isValNameSpace _ = False
+isValNameSpace DataName = True
+isValNameSpace VarName = True
+isValNameSpace (FldName {}) = True
+isValNameSpace _ = False
+
+isFieldNameSpace :: NameSpace -> Bool
+isFieldNameSpace (FldName {}) = True
+isFieldNameSpace _ = False
pprNameSpace :: NameSpace -> SDoc
-pprNameSpace DataName = text "data constructor"
-pprNameSpace VarName = text "variable"
-pprNameSpace TvName = text "type variable"
-pprNameSpace TcClsName = text "type constructor or class"
+pprNameSpace DataName = text "data constructor"
+pprNameSpace VarName = text "variable"
+pprNameSpace TvName = text "type variable"
+pprNameSpace TcClsName = text "type constructor or class"
+pprNameSpace (FldName p) = text "record field of" <+> ftext p
pprNonVarNameSpace :: NameSpace -> SDoc
pprNonVarNameSpace VarName = empty
pprNonVarNameSpace ns = pprNameSpace ns
pprNameSpaceBrief :: NameSpace -> SDoc
-pprNameSpaceBrief DataName = char 'd'
-pprNameSpaceBrief VarName = char 'v'
-pprNameSpaceBrief TvName = text "tv"
-pprNameSpaceBrief TcClsName = text "tc"
+pprNameSpaceBrief DataName = char 'd'
+pprNameSpaceBrief VarName = char 'v'
+pprNameSpaceBrief TvName = text "tv"
+pprNameSpaceBrief TcClsName = text "tc"
+pprNameSpaceBrief (FldName {}) = text "fld"
-- demoteNameSpace lowers the NameSpace if possible. We can not know
-- in advance, since a TvName can appear in an HsTyVar.
@@ -215,6 +322,7 @@ demoteNameSpace VarName = Nothing
demoteNameSpace DataName = Nothing
demoteNameSpace TvName = Nothing
demoteNameSpace TcClsName = Just DataName
+demoteNameSpace (FldName {}) = Nothing
-- demoteTvNameSpace lowers the NameSpace of a type variable.
-- See Note [Demotion] in GHC.Rename.Env.
@@ -223,6 +331,7 @@ demoteTvNameSpace TvName = Just VarName
demoteTvNameSpace VarName = Nothing
demoteTvNameSpace DataName = Nothing
demoteTvNameSpace TcClsName = Nothing
+demoteTvNameSpace (FldName {}) = Nothing
-- promoteNameSpace promotes the NameSpace as follows.
-- See Note [Promotion] in GHC.Rename.Env.
@@ -231,6 +340,7 @@ promoteNameSpace DataName = Just TcClsName
promoteNameSpace VarName = Just TvName
promoteNameSpace TcClsName = Nothing
promoteNameSpace TvName = Nothing
+promoteNameSpace (FldName {}) = Nothing
{-
************************************************************************
@@ -255,7 +365,8 @@ instance Eq OccName where
instance Ord OccName where
-- Compares lexicographically, *not* by Unique of the string
- compare (OccName sp1 s1) (OccName sp2 s2) = lexicalCompareFS s1 s2 S.<> compare sp1 sp2
+ compare (OccName sp1 s1) (OccName sp2 s2) =
+ lexicalCompareFS s1 s2 S.<> compare sp1 sp2
instance Data OccName where
-- don't traverse?
@@ -287,10 +398,41 @@ instance OutputableBndr OccName where
pprOccName :: IsLine doc => OccName -> doc
pprOccName (OccName sp occ)
- = docWithStyle (ztext (zEncodeFS occ)) (\_ -> ftext occ <> whenPprDebug (braces (pprNameSpaceBrief sp)))
+ = docWithStyle (ztext (zEncodeFS occ))
+ (\_ -> ftext occ <> whenPprDebug (braces (pprNameSpaceBrief sp)))
{-# SPECIALIZE pprOccName :: OccName -> SDoc #-}
{-# SPECIALIZE pprOccName :: OccName -> HLine #-} -- see Note [SPECIALIZE to HDoc] in GHC.Utils.Outputable
+-- | Mangle field names to avoid duplicate symbols.
+--
+-- See Note [Mangling OccNames].
+occNameMangledFS :: OccName -> FastString
+occNameMangledFS (OccName ns fs) =
+ case ns of
+ -- Fields need to include the constructor, to ensure that we don't define
+ -- duplicate symbols when using DuplicateRecordFields.
+ FldName con -> concatFS [fsLit "$fld:", con, ":", fs]
+ -- Otherwise, we can ignore the namespace, as there is no risk of name
+ -- clashes.
+ _ -> fs
+
+{- Note [Mangling OccNames]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+When generating a symbol for a Name, we usually discard the NameSpace entirely
+(see GHC.Types.Name.pprName). This is because clashes are usually not possible,
+e.g. a variable and a data constructor can't clash because data constructors
+start with a capital letter or a colon, while variables never do.
+
+However, record field names, in the presence of DuplicateRecordFields, need this
+disambiguation. So, for a record field like
+
+ data A = MkA { foo :: Int }
+
+we generate the symbol $fld:MkA:foo. We use the constructor 'MkA' to disambiguate,
+and not the TyCon A as one might naively expect: this is explained in
+Note [Record field namespacing].
+-}
+
{-
************************************************************************
* *
@@ -311,6 +453,24 @@ mkVarOcc s = mkOccName varName s
mkVarOccFS :: FastString -> OccName
mkVarOccFS fs = mkOccNameFS varName fs
+mkRecFieldOcc :: FastString -> String -> OccName
+mkRecFieldOcc dc = mkOccName (fieldName dc)
+
+mkRecFieldOccFS :: FastString -> FastString -> OccName
+mkRecFieldOccFS dc = mkOccNameFS (fieldName dc)
+
+varToRecFieldOcc :: HasDebugCallStack => FastString -> OccName -> OccName
+varToRecFieldOcc dc (OccName ns s) =
+ assert makes_sense $ mkRecFieldOccFS dc s
+ where
+ makes_sense = case ns of
+ VarName -> True
+ FldName con -> con == dc
+ _ -> False
+
+recFieldToVarOcc :: HasDebugCallStack => OccName -> OccName
+recFieldToVarOcc (OccName _ns s) = mkVarOccFS s
+
mkDataOcc :: String -> OccName
mkDataOcc = mkOccName dataName
@@ -366,83 +526,273 @@ class HasOccName name where
* *
************************************************************************
-OccEnvs are used mainly for the envts in ModIfaces.
+OccEnvs are used for the GlobalRdrEnv and for the envts in ModIface.
-Note [The Unique of an OccName]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-They are efficient, because FastStrings have unique Int# keys. We assume
-this key is less than 2^24, and indeed FastStrings are allocated keys
-sequentially starting at 0.
-
-So we can make a Unique using
- mkUnique ns key :: Unique
-where 'ns' is a Char representing the name space. This in turn makes it
-easy to build an OccEnv.
--}
+Note [OccEnv]
+~~~~~~~~~~~~~
+An OccEnv is a map keyed on OccName. Recall that an OccEnv consists of two
+components:
+
+ - a namespace,
+ - a textual name (in the form of a FastString).
+
+In general, for a given textual name, there is only one appropriate namespace.
+However, sometimes we do get an occurrence that belongs to several namespaces:
+
+ - Symbolic identifiers such as (:+) can belong to both the data constructor and
+ type constructor/class namespaces.
+ - With duplicate record fields, a field name can belong to several different
+ namespaces, one for each parent datatype (or pattern synonym).
+
+So we represent an OccEnv as a nested data structure
+
+ FastStringEnv (UniqFM NameSpace a)
-instance Uniquable OccName where
- -- See Note [The Unique of an OccName]
- getUnique (OccName VarName fs) = mkVarOccUnique fs
- getUnique (OccName DataName fs) = mkDataOccUnique fs
- getUnique (OccName TvName fs) = mkTvOccUnique fs
- getUnique (OccName TcClsName fs) = mkTcOccUnique fs
+in which we can first look up the textual name, and then choose which of the
+namespaces are relevant. This supports the two main uses of OccEnvs:
-newtype OccEnv a = A (UniqFM OccName a)
- deriving Data
+ 1. One wants to look up a specific OccName in the environment, at a specific
+ namespace. One looks up the textual name, and then the namespace.
+ 2. One wants to look up something, but isn't sure in advance of the namespace.
+ So one looks up the textual name, and then can decide what to do based on
+ the returned map of namespaces.
+This data structure isn't performance critical in most situations, but some
+improvements to its performance that might be worth it are as follows:
+
+ A. Use a tailor-made data structure for a map keyed on NameSpaces.
+
+ Recall that we have:
+
+ data IntMap a = Bin !Int !Int !(IntMap a) !(IntMap a)
+ | Tip !Key a
+ | Nil
+
+ This is already pretty efficient for singletons, but we don't need the
+ empty case (as we would simply omit the parent key in the OccEnv instead
+ of storing an empty inner map).
+
+ B. Always ensure the inner map (keyed on namespaces) is evaluated, i.e.
+ is never a thunk. For this, we would need to use strict operations on
+ the outer FastStringEnv (but we'd keep using lazy operations on the inner
+ UniqFM).
+-}
+
+-- | A map keyed on 'OccName'. See Note [OccEnv].
+newtype OccEnv a = MkOccEnv (FastStringEnv (UniqFM NameSpace a))
+ deriving Functor
+
+-- | The empty 'OccEnv'.
emptyOccEnv :: OccEnv a
-unitOccEnv :: OccName -> a -> OccEnv a
+emptyOccEnv = MkOccEnv emptyFsEnv
+
+-- | A singleton 'OccEnv'.
+unitOccEnv :: OccName -> a -> OccEnv a
+unitOccEnv (OccName ns s) a = MkOccEnv $ unitFsEnv s (unitUFM ns a)
+
+-- | Add a single element to an 'OccEnv'.
extendOccEnv :: OccEnv a -> OccName -> a -> OccEnv a
+extendOccEnv (MkOccEnv as) (OccName ns s) a =
+ MkOccEnv $ extendFsEnv_C plusUFM as s (unitUFM ns a)
+
+-- | Extend an 'OccEnv' by a list.
+--
+-- 'OccName's later on in the list override earlier 'OccName's.
extendOccEnvList :: OccEnv a -> [(OccName, a)] -> OccEnv a
+extendOccEnvList = foldl' $ \ env (occ, a) -> extendOccEnv env occ a
+
+-- | Look an element up in an 'OccEnv'.
lookupOccEnv :: OccEnv a -> OccName -> Maybe a
-mkOccEnv :: [(OccName,a)] -> OccEnv a
-mkOccEnv_C :: (a -> a -> a) -> [(OccName,a)] -> OccEnv a
-elemOccEnv :: OccName -> OccEnv a -> Bool
-foldOccEnv :: (a -> b -> b) -> b -> OccEnv a -> b
-nonDetOccEnvElts :: OccEnv a -> [a]
-extendOccEnv_C :: (a->a->a) -> OccEnv a -> OccName -> a -> OccEnv a
-extendOccEnv_Acc :: (a->b->b) -> (a->b) -> OccEnv b -> OccName -> a -> OccEnv b
-plusOccEnv :: OccEnv a -> OccEnv a -> OccEnv a
-plusOccEnv_C :: (a->a->a) -> OccEnv a -> OccEnv a -> OccEnv a
-mapOccEnv :: (a->b) -> OccEnv a -> OccEnv b
-delFromOccEnv :: OccEnv a -> OccName -> OccEnv a
+lookupOccEnv (MkOccEnv as) (OccName ns s)
+ = do { m <- lookupFsEnv as s
+ ; lookupUFM m ns }
+
+-- | Lookup an element in an 'OccEnv', looking in the record field
+-- namespace for a variable.
+lookupOccEnv_WithFields :: OccEnv a -> OccName -> [a]
+lookupOccEnv_WithFields env occ =
+ case lookupOccEnv env occ of
+ Nothing -> fieldGREs
+ Just gre -> gre : fieldGREs
+ where
+ fieldGREs
+ -- If the 'OccName' is a variable, also look up
+ -- in the record field namespaces.
+ | isVarOcc occ
+ = lookupFieldsOccEnv env (occNameFS occ)
+ | otherwise
+ = []
+
+-- | Look up all the record fields that match with the given 'FastString'
+-- in an 'OccEnv'.
+lookupFieldsOccEnv :: OccEnv a -> FastString -> [a]
+lookupFieldsOccEnv (MkOccEnv as) fld =
+ case lookupFsEnv as fld of
+ Nothing -> []
+ Just flds -> nonDetEltsUFM $ filter_flds flds
+ -- NB: non-determinism is OK: in practice we will either end up resolving
+ -- to a single field or throwing an error.
+ where
+ filter_flds = filterUFM_Directly (\ uniq _ -> isFldNSUnique uniq)
+
+-- | Create an 'OccEnv' from a list.
+--
+-- 'OccName's later on in the list override earlier 'OccName's.
+mkOccEnv :: [(OccName,a)] -> OccEnv a
+mkOccEnv = extendOccEnvList emptyOccEnv
+
+-- | Create an 'OccEnv' from a list, combining different values
+-- with the same 'OccName' using the combining function.
+mkOccEnv_C :: (a -> a -> a) -- ^ old -> new -> result
+ -> [(OccName,a)]
+ -> OccEnv a
+mkOccEnv_C f elts
+ = MkOccEnv $ foldl' g emptyFsEnv elts
+ where
+ g env (OccName ns s, a) =
+ extendFsEnv_C (plusUFM_C $ flip f) env s (unitUFM ns a)
+
+-- | Compute whether there is a value keyed by the given 'OccName'.
+elemOccEnv :: OccName -> OccEnv a -> Bool
+elemOccEnv (OccName ns s) (MkOccEnv as)
+ = case lookupFsEnv as s of
+ Nothing -> False
+ Just m -> ns `elemUFM` m
+
+-- | Fold over an 'OccEnv'. Non-deterministic, unless the folding function
+-- is commutative (i.e. @a1 `f` ( a2 `f` b ) == a2 `f` ( a1 `f` b )@ for all @a1@, @a2@, @b@).
+nonDetFoldOccEnv :: (a -> b -> b) -> b -> OccEnv a -> b
+nonDetFoldOccEnv f b0 (MkOccEnv as) =
+ nonDetFoldFsEnv (flip $ nonDetFoldUFM f) b0 as
+
+-- | Obtain the elements of an 'OccEnv'.
+--
+-- The resulting order is non-deterministic.
+nonDetOccEnvElts :: OccEnv a -> [a]
+nonDetOccEnvElts = nonDetFoldOccEnv (:) []
+
+-- | Union of two 'OccEnv's, right-biased.
+plusOccEnv :: OccEnv a -> OccEnv a -> OccEnv a
+plusOccEnv (MkOccEnv env1) (MkOccEnv env2)
+ = MkOccEnv $ plusFsEnv_C plusUFM env1 env2
+
+-- | Union of two 'OccEnv's with a combining function.
+plusOccEnv_C :: (a->a->a) -> OccEnv a -> OccEnv a -> OccEnv a
+plusOccEnv_C f (MkOccEnv env1) (MkOccEnv env2)
+ = MkOccEnv $ plusFsEnv_C (plusUFM_C f) env1 env2
+
+-- | Map over an 'OccEnv' ('Functor' instance).
+mapOccEnv :: (a->b) -> OccEnv a -> OccEnv b
+mapOccEnv = fmap
+
+-- | Add a single element to an 'OccEnv', using a different function whether
+-- the 'OccName' already exists or not.
+extendOccEnv_Acc :: forall a b
+ . (a->b->b) -- ^ add to existing
+ -> (a->b) -- ^ new element
+ -> OccEnv b -- ^ old
+ -> OccName -> a -- ^ new
+ -> OccEnv b
+extendOccEnv_Acc f g (MkOccEnv env) (OccName ns s) =
+ MkOccEnv . extendFsEnv_Acc f' g' env s
+ where
+ f' :: a -> UniqFM NameSpace b -> UniqFM NameSpace b
+ f' a bs = alterUFM (Just . \ case { Nothing -> g a ; Just b -> f a b }) bs ns
+ g' a = unitUFM ns (g a)
+
+-- | Delete one element from an 'OccEnv'.
+delFromOccEnv :: forall a. OccEnv a -> OccName -> OccEnv a
+delFromOccEnv (MkOccEnv env1) (OccName ns s) =
+ MkOccEnv $ alterFsEnv f env1 s
+ where
+ f :: Maybe (UniqFM NameSpace a) -> Maybe (UniqFM NameSpace a)
+ f Nothing = Nothing
+ f (Just m) =
+ case delFromUFM m ns of
+ m' | isNullUFM m' -> Nothing
+ | otherwise -> Just m'
+
+-- | Delete multiple elements from an 'OccEnv'.
delListFromOccEnv :: OccEnv a -> [OccName] -> OccEnv a
-filterOccEnv :: (elt -> Bool) -> OccEnv elt -> OccEnv elt
-alterOccEnv :: (Maybe elt -> Maybe elt) -> OccEnv elt -> OccName -> OccEnv elt
+delListFromOccEnv = foldl' delFromOccEnv
+
+-- | Filter out all elements in an 'OccEnv' using a predicate.
+filterOccEnv :: forall a. (a -> Bool) -> OccEnv a -> OccEnv a
+filterOccEnv f (MkOccEnv env) =
+ MkOccEnv $ mapMaybeFsEnv g env
+ where
+ g :: UniqFM NameSpace a -> Maybe (UniqFM NameSpace a)
+ g ms =
+ case filterUFM f ms of
+ m' | isNullUFM m' -> Nothing
+ | otherwise -> Just m'
+
+-- | Alter an 'OccEnv', adding or removing an element at the given key.
+alterOccEnv :: forall a. (Maybe a -> Maybe a) -> OccEnv a -> OccName -> OccEnv a
+alterOccEnv f (MkOccEnv env) (OccName ns s) =
+ MkOccEnv $ alterFsEnv g env s
+ where
+ g :: Maybe (UniqFM NameSpace a) -> Maybe (UniqFM NameSpace a)
+ g Nothing = fmap (unitUFM ns) (f Nothing)
+ g (Just m) =
+ case alterUFM f m ns of
+ m' | isNullUFM m' -> Nothing
+ | otherwise -> Just m'
+
+intersectOccEnv_C :: (a -> b -> c) -> OccEnv a -> OccEnv b -> OccEnv c
+intersectOccEnv_C f (MkOccEnv as) (MkOccEnv bs)
+ = MkOccEnv $ intersectUFM_C (intersectUFM_C f) as bs
+
+-- | Remove elements of the first 'OccEnv' that appear in the second 'OccEnv'.
minusOccEnv :: OccEnv a -> OccEnv b -> OccEnv a
+minusOccEnv = minusOccEnv_C_Ns minusUFM
--- | Alters (replaces or removes) those elements of the map that are mentioned in the second map
-minusOccEnv_C :: (a -> b -> Maybe a) -> OccEnv a -> OccEnv b -> OccEnv a
-
-emptyOccEnv = A emptyUFM
-unitOccEnv x y = A $ unitUFM x y
-extendOccEnv (A x) y z = A $ addToUFM x y z
-extendOccEnvList (A x) l = A $ addListToUFM x l
-lookupOccEnv (A x) y = lookupUFM x y
-mkOccEnv l = A $ listToUFM l
-elemOccEnv x (A y) = elemUFM x y
-foldOccEnv a b (A c) = foldUFM a b c
-nonDetOccEnvElts (A x) = nonDetEltsUFM x
-plusOccEnv (A x) (A y) = A $ plusUFM x y
-plusOccEnv_C f (A x) (A y) = A $ plusUFM_C f x y
-extendOccEnv_C f (A x) y z = A $ addToUFM_C f x y z
-extendOccEnv_Acc f g (A x) y z = A $ addToUFM_Acc f g x y z
-mapOccEnv f (A x) = A $ mapUFM f x
-mkOccEnv_C comb l = A $ addListToUFM_C comb emptyUFM l
-delFromOccEnv (A x) y = A $ delFromUFM x y
-delListFromOccEnv (A x) y = A $ delListFromUFM x y
-filterOccEnv x (A y) = A $ filterUFM x y
-alterOccEnv fn (A y) k = A $ alterUFM fn y k
-minusOccEnv (A x) (A y) = A $ minusUFM x y
-minusOccEnv_C fn (A x) (A y) = A $ minusUFM_C fn x y
+-- | Alters (replaces or removes) those elements of the first 'OccEnv' that are
+-- mentioned in the second 'OccEnv'.
+--
+-- Same idea as 'Data.Map.differenceWith'.
+minusOccEnv_C :: (a -> b -> Maybe a)
+ -> OccEnv a -> OccEnv b -> OccEnv a
+minusOccEnv_C f = minusOccEnv_C_Ns (minusUFM_C f)
+
+minusOccEnv_C_Ns :: forall a b
+ . (UniqFM NameSpace a -> UniqFM NameSpace b -> UniqFM NameSpace a)
+ -> OccEnv a -> OccEnv b -> OccEnv a
+minusOccEnv_C_Ns f (MkOccEnv as) (MkOccEnv bs) =
+ MkOccEnv $ minusUFM_C g as bs
+ where
+ g :: UniqFM NameSpace a -> UniqFM NameSpace b -> Maybe (UniqFM NameSpace a)
+ g as bs =
+ let m = f as bs
+ in if isNullUFM m
+ then Nothing
+ else Just m
instance Outputable a => Outputable (OccEnv a) where
ppr x = pprOccEnv ppr x
pprOccEnv :: (a -> SDoc) -> OccEnv a -> SDoc
-pprOccEnv ppr_elt (A env) = pprUniqFM ppr_elt env
+pprOccEnv ppr_elt (MkOccEnv env)
+ = brackets $ fsep $ punctuate comma $
+ [ ppr uq <+> text ":->" <+> ppr_elt elt
+ | (uq, elts) <- nonDetUFMToList env
+ , elt <- nonDetEltsUFM elts ]
+
+instance NFData a => NFData (OccEnv a) where
+ rnf = forceOccEnv rnf
+
+-- | Map over an 'OccEnv' strictly.
+strictMapOccEnv :: (a -> b) -> OccEnv a -> OccEnv b
+strictMapOccEnv f (MkOccEnv as) =
+ MkOccEnv $ strictMapFsEnv (strictMapUFM f) as
+
+-- | Force an 'OccEnv' with the provided function.
+forceOccEnv :: (a -> ()) -> OccEnv a -> ()
+forceOccEnv nf (MkOccEnv fs) = seqEltsUFM (seqEltsUFM nf) fs
+
+--------------------------------------------------------------------------------
-type OccSet = UniqSet OccName
+type OccSet = FastStringEnv (UniqSet NameSpace)
emptyOccSet :: OccSet
unitOccSet :: OccName -> OccSet
@@ -451,27 +801,18 @@ extendOccSet :: OccSet -> OccName -> OccSet
extendOccSetList :: OccSet -> [OccName] -> OccSet
unionOccSets :: OccSet -> OccSet -> OccSet
unionManyOccSets :: [OccSet] -> OccSet
-minusOccSet :: OccSet -> OccSet -> OccSet
elemOccSet :: OccName -> OccSet -> Bool
isEmptyOccSet :: OccSet -> Bool
-intersectOccSet :: OccSet -> OccSet -> OccSet
-filterOccSet :: (OccName -> Bool) -> OccSet -> OccSet
--- | Converts an OccSet to an OccEnv (operationally the identity)
-occSetToEnv :: OccSet -> OccEnv OccName
-
-emptyOccSet = emptyUniqSet
-unitOccSet = unitUniqSet
-mkOccSet = mkUniqSet
-extendOccSet = addOneToUniqSet
-extendOccSetList = addListToUniqSet
-unionOccSets = unionUniqSets
-unionManyOccSets = unionManyUniqSets
-minusOccSet = minusUniqSet
-elemOccSet = elementOfUniqSet
-isEmptyOccSet = isEmptyUniqSet
-intersectOccSet = intersectUniqSets
-filterOccSet = filterUniqSet
-occSetToEnv = A . getUniqSet
+
+emptyOccSet = emptyFsEnv
+unitOccSet (OccName ns s) = unitFsEnv s (unitUniqSet ns)
+mkOccSet = extendOccSetList emptyOccSet
+extendOccSet occs (OccName ns s) = extendFsEnv occs s (unitUniqSet ns)
+extendOccSetList = foldl extendOccSet
+unionOccSets = plusFsEnv_C unionUniqSets
+unionManyOccSets = foldl' unionOccSets emptyOccSet
+elemOccSet (OccName ns s) occs = maybe False (elementOfUniqSet ns) $ lookupFsEnv occs s
+isEmptyOccSet = isNullUFM
{-
************************************************************************
@@ -487,7 +828,7 @@ occNameString (OccName _ s) = unpackFS s
setOccNameSpace :: NameSpace -> OccName -> OccName
setOccNameSpace sp (OccName _ occ) = OccName sp occ
-isVarOcc, isTvOcc, isTcOcc, isDataOcc :: OccName -> Bool
+isVarOcc, isTvOcc, isTcOcc, isDataOcc, isFieldOcc :: OccName -> Bool
isVarOcc (OccName VarName _) = True
isVarOcc _ = False
@@ -498,12 +839,20 @@ isTvOcc _ = False
isTcOcc (OccName TcClsName _) = True
isTcOcc _ = False
+isFieldOcc (OccName (FldName {}) _) = True
+isFieldOcc _ = False
+
+fieldOcc_maybe :: OccName -> Maybe FastString
+fieldOcc_maybe (OccName (FldName con) _) = Just con
+fieldOcc_maybe _ = Nothing
+
-- | /Value/ 'OccNames's are those that are either in
--- the variable or data constructor namespaces
+-- the variable, field name or data constructor namespaces
isValOcc :: OccName -> Bool
-isValOcc (OccName VarName _) = True
-isValOcc (OccName DataName _) = True
-isValOcc _ = False
+isValOcc (OccName VarName _) = True
+isValOcc (OccName DataName _) = True
+isValOcc (OccName (FldName {}) _) = True
+isValOcc _ = False
isDataOcc (OccName DataName _) = True
isDataOcc _ = False
@@ -518,10 +867,12 @@ isDataSymOcc _ = False
-- | Test if the 'OccName' is that for any operator (whether
-- it is a data constructor or variable or whatever)
isSymOcc :: OccName -> Bool
-isSymOcc (OccName DataName s) = isLexConSym s
-isSymOcc (OccName TcClsName s) = isLexSym s
-isSymOcc (OccName VarName s) = isLexSym s
-isSymOcc (OccName TvName s) = isLexSym s
+isSymOcc (OccName ns s) = case ns of
+ DataName -> isLexConSym s
+ TcClsName -> isLexSym s
+ VarName -> isLexSym s
+ TvName -> isLexSym s
+ FldName {} -> isLexSym s
-- Pretty inefficient!
parenSymOcc :: OccName -> SDoc -> SDoc
@@ -658,10 +1009,6 @@ mkTyConRepOcc occ = mk_simple_deriv varName prefix occ
mkGenR = mk_simple_deriv tcName "Rep_"
mkGen1R = mk_simple_deriv tcName "Rep1_"
--- Overloaded record field selectors
-mkRecFldSelOcc :: FastString -> OccName
-mkRecFldSelOcc s = mk_deriv varName "$sel" [s]
-
mk_simple_deriv :: NameSpace -> FastString -> OccName -> OccName
mk_simple_deriv sp px occ = mk_deriv sp px [occNameFS occ]
@@ -907,13 +1254,19 @@ instance Binary NameSpace where
putByte bh 2
put_ bh TcClsName =
putByte bh 3
+ put_ bh (FldName parent) = do
+ putByte bh 4
+ put_ bh parent
get bh = do
h <- getByte bh
case h of
0 -> return VarName
1 -> return DataName
2 -> return TvName
- _ -> return TcClsName
+ 3 -> return TcClsName
+ _ -> do
+ parent <- get bh
+ return $ FldName { fldParent = parent }
instance Binary OccName where
put_ bh (OccName aa ab) = do
diff --git a/compiler/GHC/Types/Name/Occurrence.hs-boot b/compiler/GHC/Types/Name/Occurrence.hs-boot
index cb39f6e679..7b76175e06 100644
--- a/compiler/GHC/Types/Name/Occurrence.hs-boot
+++ b/compiler/GHC/Types/Name/Occurrence.hs-boot
@@ -8,5 +8,4 @@ class HasOccName name where
occName :: name -> OccName
occNameFS :: OccName -> FastString
-mkRecFldSelOcc :: FastString -> OccName
mkVarOccFS :: FastString -> OccName
diff --git a/compiler/GHC/Types/Name/Ppr.hs b/compiler/GHC/Types/Name/Ppr.hs
index 206ee2e782..6ab771a9e0 100644
--- a/compiler/GHC/Types/Name/Ppr.hs
+++ b/compiler/GHC/Types/Name/Ppr.hs
@@ -68,7 +68,7 @@ with some holes, we should try to give the user some more useful information.
-- | Creates some functions that work out the best ways to format
-- names for the user according to a set of heuristics.
-mkNamePprCtx :: PromotionTickContext -> UnitEnv -> GlobalRdrEnv -> NamePprCtx
+mkNamePprCtx :: Outputable info => PromotionTickContext -> UnitEnv -> GlobalRdrEnvX info -> NamePprCtx
mkNamePprCtx ptc unit_env env
= QueryQualify
(mkQualName env)
@@ -79,7 +79,7 @@ mkNamePprCtx ptc unit_env env
unit_state = ue_units unit_env
home_unit = ue_homeUnit unit_env
-mkQualName :: GlobalRdrEnv -> QueryQualifyName
+mkQualName :: Outputable info => GlobalRdrEnvX info -> QueryQualifyName
mkQualName env = qual_name where
qual_name mod occ
| [gre] <- unqual_gres
@@ -97,7 +97,7 @@ mkQualName env = qual_name where
= NameQual (greQualModName gre)
| null qual_gres
- = if null (lookupGRE_RdrName (mkRdrQual (moduleName mod) occ) env)
+ = if null (lookupGRE_RdrName SameOccName env (mkRdrQual (moduleName mod) occ))
then NameNotInScope1
else NameNotInScope2
@@ -127,14 +127,14 @@ mkQualName env = qual_name where
right_name gre = greDefinitionModule gre == Just mod
- unqual_gres = lookupGRE_RdrName (mkRdrUnqual occ) env
- qual_gres = filter right_name (lookupGlobalRdrEnv env occ)
+ unqual_gres = lookupGRE_RdrName SameOccName env (mkRdrUnqual occ)
+ qual_gres = filter right_name (lookupGRE_OccName SameOccName env occ)
-- we can mention a module P:M without the P: qualifier iff
-- "import M" would resolve unambiguously to P:M. (if P is the
-- current package we can just assume it is unqualified).
-mkPromTick :: PromotionTickContext -> GlobalRdrEnv -> QueryPromotionTick
+mkPromTick :: PromotionTickContext -> GlobalRdrEnvX info -> QueryPromotionTick
mkPromTick ptc env
| ptcPrintRedundantPromTicks ptc = alwaysPrintPromTick
| otherwise = print_prom_tick
@@ -150,7 +150,7 @@ mkPromTick ptc env
= ptcListTuplePuns ptc
| Just occ' <- promoteOccName occ
- , [] <- lookupGRE_RdrName (mkRdrUnqual occ') env
+ , [] <- lookupGRE_RdrName SameOccName env (mkRdrUnqual occ')
= -- Could not find a corresponding type name in the environment,
-- so the data name is unambiguous. Promotion tick not needed.
False
diff --git a/compiler/GHC/Types/Name/Reader.hs b/compiler/GHC/Types/Name/Reader.hs
index 7c52a94584..4b05eedb39 100644
--- a/compiler/GHC/Types/Name/Reader.hs
+++ b/compiler/GHC/Types/Name/Reader.hs
@@ -5,6 +5,8 @@
{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE GADTs #-}
-- |
-- #name_types#
@@ -44,30 +46,50 @@ module GHC.Types.Name.Reader (
localRdrEnvElts, minusLocalRdrEnv,
-- * Global mapping of 'RdrName' to 'GlobalRdrElt's
- GlobalRdrEnv, emptyGlobalRdrEnv, mkGlobalRdrEnv, plusGlobalRdrEnv,
- lookupGlobalRdrEnv, extendGlobalRdrEnv, greOccName, shadowNames,
+ GlobalRdrEnvX, GlobalRdrEnv, IfGlobalRdrEnv,
+ emptyGlobalRdrEnv, mkGlobalRdrEnv, plusGlobalRdrEnv,
+ extendGlobalRdrEnv, greOccName,
pprGlobalRdrEnv, globalRdrEnvElts,
- lookupGRE_RdrName, lookupGRE_RdrName', lookupGRE_Name,
- lookupGRE_GreName, lookupGRE_FieldLabel,
- lookupGRE_Name_OccName,
+
+ -- ** Looking up 'GlobalRdrElt's
+ FieldsOrSelectors(..), filterFieldGREs, allowGRE,
+ WhichGREs(..), lookupGRE_OccName, lookupGRE_RdrName, lookupGRE_Name,
+ lookupGRE_FieldLabel,
getGRE_NameQualifier_maybes,
transformGREs, pickGREs, pickGREsModExp,
-- * GlobalRdrElts
- gresFromAvails, gresFromAvail, localGREsFromAvail, availFromGRE,
+ availFromGRE,
greRdrNames, greSrcSpan, greQualModName,
gresToAvailInfo,
greDefinitionModule, greDefinitionSrcSpan,
- greMangledName, grePrintableName,
- greFieldLabel,
+ greFieldLabel_maybe,
-- ** Global 'RdrName' mapping elements: 'GlobalRdrElt', 'Provenance', 'ImportSpec'
- GlobalRdrElt(..), isLocalGRE, isRecFldGRE,
+ GlobalRdrEltX(..), GlobalRdrElt, IfGlobalRdrElt, FieldGlobalRdrElt,
+ greName, forceGlobalRdrEnv, hydrateGlobalRdrEnv,
+ isLocalGRE, isRecFldGRE,
+ fieldGREInfo,
isDuplicateRecFldGRE, isNoFieldSelectorGRE, isFieldSelectorGRE,
unQualOK, qualSpecOK, unQualSpecOK,
pprNameProvenance,
- GreName(..), greNameSrcSpan,
+ vanillaGRE, localVanillaGRE, localTyConGRE,
+ localConLikeGRE, localFieldGREs,
+ gresToNameSet,
+
+ -- ** Shadowing
+ greClashesWith, shadowNames,
+
+ -- ** Information attached to a 'GlobalRdrElt'
+ ConLikeName(..),
+ GREInfo(..), RecFieldInfo(..),
+ plusGREInfo,
+ recFieldConLike_maybe, recFieldInfo_maybe,
+ fieldGRE_maybe, fieldGRELabel,
+
+ -- ** Parent information
Parent(..), greParent_maybe,
+ mkParent, availParent,
ImportSpec(..), ImpDeclSpec(..), ImpItemSpec(..),
importSpecLoc, importSpecModule, isExplicitItem, bestImport,
@@ -77,28 +99,36 @@ module GHC.Types.Name.Reader (
import GHC.Prelude
-import GHC.Unit.Module
-import GHC.Types.Name
+import GHC.Data.Bag
+import GHC.Data.FastString
+import GHC.Data.Maybe
+
import GHC.Types.Avail
+import GHC.Types.Basic
+import GHC.Types.GREInfo
+import GHC.Types.FieldLabel
+import GHC.Types.Name
+import GHC.Types.Name.Env
+ ( NameEnv, nonDetNameEnvElts, emptyNameEnv, extendNameEnv_Acc )
import GHC.Types.Name.Set
-import GHC.Data.Maybe
import GHC.Types.SrcLoc as SrcLoc
-import GHC.Data.FastString
-import GHC.Types.FieldLabel
-import GHC.Utils.Outputable
-import GHC.Types.Unique
import GHC.Types.Unique.FM
import GHC.Types.Unique.Set
+
+import GHC.Unit.Module
+
import GHC.Utils.Misc as Utils
+import GHC.Utils.Outputable
import GHC.Utils.Panic
-import GHC.Types.Name.Env
-
-import Language.Haskell.Syntax.Basic (FieldLabelString(..))
+import Control.DeepSeq
+import Control.Monad ( guard )
import Data.Data
-import Data.List( sortBy )
+import Data.List ( sortBy )
+import qualified Data.List.NonEmpty as NE
+import qualified Data.Map.Strict as Map
import qualified Data.Semigroup as S
-import GHC.Data.Bag
+import System.IO.Unsafe ( unsafePerformIO )
{-
************************************************************************
@@ -391,7 +421,7 @@ instance Outputable LocalRdrEnv where
<+> pprUFM (getUniqSet ns) (braces . pprWithCommas ppr)
] <+> char '}')
where
- ppr_elt name = parens (ppr (getUnique (nameOccName name))) <+> ppr name
+ ppr_elt name = parens (ppr (nameOccName name)) <+> ppr name
-- So we can see if the keys line up correctly
emptyLocalRdrEnv :: LocalRdrEnv
@@ -462,7 +492,7 @@ the in-scope-name-set.
-}
-- | Global Reader Environment
-type GlobalRdrEnv = OccEnv [GlobalRdrElt]
+type GlobalRdrEnv = GlobalRdrEnvX GREInfo
-- ^ Keyed by 'OccName'; when looking up a qualified name
-- we look up the 'OccName' part, and then check the 'Provenance'
-- to see if the appropriate qualification is valid. This
@@ -483,23 +513,88 @@ type GlobalRdrEnv = OccEnv [GlobalRdrElt]
--
-- INVARIANT 3: If the GlobalRdrEnv maps [occ -> gre], then
-- greOccName gre = occ
+
+-- | A 'GlobalRdrEnv' in which the 'GlobalRdrElt's don't have any 'GREInfo'
+-- attached to them. This is useful to avoid space leaks, see Note [IfGlobalRdrEnv].
+type IfGlobalRdrEnv = GlobalRdrEnvX ()
+
+-- | Parametrises 'GlobalRdrEnv' over the presence or absence of 'GREInfo'.
+--
+-- See Note [IfGlobalRdrEnv].
+type GlobalRdrEnvX info = OccEnv [GlobalRdrEltX info]
+
+-- | Global Reader Element
+--
+-- An element of the 'GlobalRdrEnv'.
+
+type GlobalRdrElt = GlobalRdrEltX GREInfo
+
+-- | A 'GlobalRdrElt' in which we stripped out the 'GREInfo' field,
+-- in order to avoid space leaks.
--
--- NB: greOccName gre is usually the same as
--- nameOccName (greMangledName gre), but not always in the
--- case of record selectors; see Note [GreNames]
+-- See Note [IfGlobalRdrEnv].
+type IfGlobalRdrElt = GlobalRdrEltX ()
-- | Global Reader Element
--
--- An element of the 'GlobalRdrEnv'
-data GlobalRdrElt
- = GRE { gre_name :: !GreName -- ^ See Note [GreNames]
- , gre_par :: !Parent -- ^ See Note [Parents]
- , gre_lcl :: !Bool -- ^ True <=> the thing was defined locally
- , gre_imp :: !(Bag ImportSpec) -- ^ In scope through these imports
+-- An element of the 'GlobalRdrEnv'.
+--
+-- Why do we parametrise over the 'gre_info' field? See Note [IfGlobalRdrEnv].
+data GlobalRdrEltX info
+ = GRE { gre_name :: !Name
+ , gre_par :: !Parent -- ^ See Note [Parents]
+ , gre_lcl :: !Bool -- ^ True <=> the thing was defined locally
+ , gre_imp :: !(Bag ImportSpec) -- ^ In scope through these imports
+ , gre_info :: info
+ -- ^ Information the renamer knows about this particular 'Name'.
+ --
+ -- Careful about forcing this field! Forcing it can trigger
+ -- the loading of interface files.
+ --
+ -- Note [Retrieving the GREInfo from interfaces] in GHC.Types.GREInfo.
} deriving (Data)
-- INVARIANT: either gre_lcl = True or gre_imp is non-empty
-- See Note [GlobalRdrElt provenance]
+{- Note [IfGlobalRdrEnv]
+~~~~~~~~~~~~~~~~~~~~~~~~
+Information pertinent to the renamer about a 'Name' is stored in the fields of
+'GlobalRdrElt'. The 'gre_info' field, described in Note [GREInfo] in GHC.Types.GREInfo,
+is a bit special: as Note [Retrieving the GREInfo from interfaces] in GHC.Types.GREInfo
+describes, for imported 'Name's it is usually obtained by a look up in a type environment,
+and forcing can cause the interface file for the module defining the 'Name' to be
+loaded. As described in Note [Forcing GREInfo] in GHC.Types.GREInfo, keeping it
+a thunk can cause space leaks, while forcing it can cause extra work to be done.
+So it's best to discard it when we don't need it, for example when we are about
+to store it in a 'ModIface'.
+
+We thus parametrise 'GlobalRdrElt' (and 'GlobalRdrEnv') over the presence or
+absence of the 'GREInfo' field.
+
+ - When we are about to stash the 'GlobalRdrElt' in a long-lived data structure,
+ e.g. a 'ModIface', we force it by setting all the 'GREInfo' fields to '()'.
+ See 'forceGlobalRdrEnv'.
+ - To go back the other way, we use 'hydrateGlobalRdrEnv', which sets the
+ 'gre_info' fields back to lazy lookups.
+
+This parametrisation also helps ensure that we don't accidentally force the
+GREInfo field (which can cause unnecessary loading of interface files).
+In particular, the 'lookupGRE_OccName' is statically guaranteed to not consult
+the 'GREInfo' field when its first argument is 'SameOccName', which is important
+as we sometimes need to use this function with an 'IfaceGlobalRdrEnv' in which
+the 'GREInfo' fields have been stripped.
+-}
+
+-- | A 'FieldGlobalRdrElt' is a 'GlobalRdrElt'
+-- in which the 'gre_info' field is 'IAmRecField'.
+type FieldGlobalRdrElt = GlobalRdrElt
+
+greName :: GlobalRdrEltX info -> Name
+greName = gre_name
+
+instance NFData IfGlobalRdrElt where
+ rnf !_ = ()
+
-- | See Note [Parents]
data Parent = NoParent
| ParentIs { par_is :: Name }
@@ -580,56 +675,12 @@ pattern synonym can be bundled with a type constructor on export, in which case
whenever the pattern synonym is imported the gre_par will be ParentIs.
Thus the gre_name and gre_par fields are independent, because a normal datatype
-introduces FieldGreNames using ParentIs, but a record pattern synonym can
-introduce FieldGreNames that use NoParent. (In the past we represented fields
-using an additional constructor of the Parent type, which could not adequately
-represent this situation.) See also
+introduces FieldGlobalRdrElts using ParentIs, but a record pattern synonym can
+introduce FieldGlobalRdrElts that use NoParent. (In the past we represented
+fields using an additional constructor of the Parent type, which could not
+adequately represent this situation.) See also
Note [Representing pattern synonym fields in AvailInfo] in GHC.Types.Avail.
-
-Note [GreNames]
-~~~~~~~~~~~~~~~
-A `GlobalRdrElt` has a field `gre_name :: GreName`, which uniquely
-identifies what the `GlobalRdrElt` describes. There are two sorts of
-`GreName` (see the data type decl):
-
-* NormalGreName Name: this is used for most entities; the Name
- uniquely identifies it. It is stored in the GlobalRdrEnv under
- the OccName of the Name.
-
-* FieldGreName FieldLabel: is used only for field labels of a
- record. With -XDuplicateRecordFields there may be many field
- labels `x` in scope; e.g.
- data T1 = MkT1 { x :: Int }
- data T2 = MkT2 { x :: Bool }
- Each has a different GlobalRdrElt with a distinct GreName.
- The two fields are uniquely identified by their record selectors,
- which are stored in the FieldLabel, and have mangled names like
- `$sel:x:MkT1`. See Note [FieldLabel] in GHC.Types.FieldLabel.
-
- These GREs are stored in the GlobalRdrEnv under the OccName of the
- field (i.e. "x" in both cases above), /not/ the OccName of the mangled
- record selector function.
-
-A GreName, and hence a GRE, has both a "printable" and a "mangled" Name. These
-are identical for normal names, but for record fields compiled with
--XDuplicateRecordFields they will differ. So we have two pairs of functions:
-
- * greNameMangledName :: GreName -> Name
- greMangledName :: GlobalRdrElt -> Name
- The "mangled" Name is the actual Name of the selector function,
- e.g. $sel:x:MkT1. This should not be displayed to the user, but is used to
- uniquely identify the field in the renamer, and later in the backend.
-
- * greNamePrintableName :: GreName -> Name
- grePrintableName :: GlobalRdrElt -> Name
- The "printable" Name is the "manged" Name with its OccName replaced with that
- of the field label. This is how the field should be output to the user.
-
-Since the right Name to use is context-dependent, we do not define a NamedThing
-instance for GREName (or GlobalRdrElt), but instead make the choice explicit.
-
-
Note [Combining parents]
~~~~~~~~~~~~~~~~~~~~~~~~
With an associated type we might have
@@ -658,73 +709,80 @@ those. For T that will mean we have
That's why plusParent picks the "best" case.
-}
--- | make a 'GlobalRdrEnv' where all the elements point to the same
--- Provenance (useful for "hiding" imports, or imports with no details).
-gresFromAvails :: Maybe ImportSpec -> [AvailInfo] -> [GlobalRdrElt]
--- prov = Nothing => locally bound
--- Just spec => imported as described by spec
-gresFromAvails prov avails
- = concatMap (gresFromAvail (const prov)) avails
-
-localGREsFromAvail :: AvailInfo -> [GlobalRdrElt]
--- Turn an Avail into a list of LocalDef GlobalRdrElts
-localGREsFromAvail = gresFromAvail (const Nothing)
-
-gresFromAvail :: (Name -> Maybe ImportSpec) -> AvailInfo -> [GlobalRdrElt]
-gresFromAvail prov_fn avail
- = map mk_gre (availNonFldNames avail) ++ map mk_fld_gre (availFlds avail)
+vanillaGRE :: (Name -> Maybe ImportSpec) -> Parent -> Name -> GlobalRdrElt
+vanillaGRE prov_fn par n =
+ case prov_fn n of
+ -- Nothing => bound locally
+ -- Just is => imported from 'is'
+ Nothing -> GRE { gre_name = n, gre_par = par
+ , gre_lcl = True, gre_imp = emptyBag
+ , gre_info = Vanilla }
+ Just is -> GRE { gre_name = n, gre_par = par
+ , gre_lcl = False, gre_imp = unitBag is
+ , gre_info = Vanilla }
+
+localVanillaGRE :: Parent -> Name -> GlobalRdrElt
+localVanillaGRE = vanillaGRE (const Nothing)
+
+-- | Create a local 'GlobalRdrElt' for a 'TyCon'.
+localTyConGRE :: TyConFlavour Name
+ -> Name
+ -> GlobalRdrElt
+localTyConGRE flav nm =
+ ( localVanillaGRE par nm )
+ { gre_info = IAmTyCon flav }
where
- mk_gre n
- = case prov_fn n of -- Nothing => bound locally
- -- Just is => imported from 'is'
- Nothing -> GRE { gre_name = NormalGreName n, gre_par = mkParent n avail
- , gre_lcl = True, gre_imp = emptyBag }
- Just is -> GRE { gre_name = NormalGreName n, gre_par = mkParent n avail
- , gre_lcl = False, gre_imp = unitBag is }
-
- mk_fld_gre fl
- = case prov_fn (flSelector fl) of -- Nothing => bound locally
- -- Just is => imported from 'is'
- Nothing -> GRE { gre_name = FieldGreName fl, gre_par = availParent avail
- , gre_lcl = True, gre_imp = emptyBag }
- Just is -> GRE { gre_name = FieldGreName fl, gre_par = availParent avail
- , gre_lcl = False, gre_imp = unitBag is }
-
-instance HasOccName GlobalRdrElt where
+ par = case tyConFlavourAssoc_maybe flav of
+ Nothing -> NoParent
+ Just p -> ParentIs p
+
+localConLikeGRE :: Parent -> (ConLikeName, ConInfo) -> GlobalRdrElt
+localConLikeGRE p (con_nm, con_info) =
+ ( localVanillaGRE p $ conLikeName_Name con_nm )
+ { gre_info = IAmConLike con_info }
+
+localFieldGREs :: Parent -> [(ConLikeName, ConInfo)] -> [GlobalRdrElt]
+localFieldGREs p cons =
+ [ ( localVanillaGRE p fld_nm )
+ { gre_info = IAmRecField fld_info }
+ | (S.Arg fld_nm fl, fl_cons) <- flds
+ , let fld_info = RecFieldInfo { recFieldLabel = fl
+ , recFieldCons = fl_cons } ]
+ where
+ -- We are given a map taking a constructor to its fields, but we want
+ -- a map taking a field to the contructors which have it.
+ -- We thus need to convert [(Con, [Field])] into [(Field, [Con])].
+ flds = Map.toList
+ $ Map.fromListWith unionUniqSets
+ [ (S.Arg (flSelector fl) fl, unitUniqSet con)
+ | (con, con_info) <- cons
+ , ConHasRecordFields fls <- [con_info]
+ , fl <- NE.toList fls ]
+
+instance HasOccName (GlobalRdrEltX info) where
occName = greOccName
--- | See Note [GreNames]
-greOccName :: GlobalRdrElt -> OccName
-greOccName = occName . gre_name
-
--- | A 'Name' for the GRE for internal use. Careful: the 'OccName' of this
--- 'Name' is not necessarily the same as the 'greOccName' (see Note [GreNames]).
-greMangledName :: GlobalRdrElt -> Name
-greMangledName = greNameMangledName . gre_name
-
--- | A 'Name' for the GRE suitable for output to the user. Its 'OccName' will
--- be the 'greOccName' (see Note [GreNames]).
-grePrintableName :: GlobalRdrElt -> Name
-grePrintableName = greNamePrintableName . gre_name
+greOccName :: GlobalRdrEltX info -> OccName
+greOccName ( GRE { gre_name = nm } ) = nameOccName nm
-- | The SrcSpan of the name pointed to by the GRE.
-greDefinitionSrcSpan :: GlobalRdrElt -> SrcSpan
-greDefinitionSrcSpan = nameSrcSpan . greMangledName
+greDefinitionSrcSpan :: GlobalRdrEltX info -> SrcSpan
+greDefinitionSrcSpan = nameSrcSpan . greName
-- | The module in which the name pointed to by the GRE is defined.
-greDefinitionModule :: GlobalRdrElt -> Maybe Module
-greDefinitionModule = nameModule_maybe . greMangledName
+greDefinitionModule :: GlobalRdrEltX info -> Maybe Module
+greDefinitionModule = nameModule_maybe . greName
-greQualModName :: GlobalRdrElt -> ModuleName
+greQualModName :: Outputable info => GlobalRdrEltX info -> ModuleName
-- Get a suitable module qualifier for the GRE
-- (used in mkPrintUnqualified)
--- Precondition: the greMangledName is always External
+-- Precondition: the gre_name is always External
greQualModName gre@(GRE { gre_lcl = lcl, gre_imp = iss })
| lcl, Just mod <- greDefinitionModule gre = moduleName mod
| Just is <- headMaybe iss = is_as (is_decl is)
| otherwise = pprPanic "greQualModName" (ppr gre)
-greRdrNames :: GlobalRdrElt -> [RdrName]
+greRdrNames :: GlobalRdrEltX info -> [RdrName]
greRdrNames gre@GRE{ gre_lcl = lcl, gre_imp = iss }
= bagToList $ (if lcl then unitBag unqual else emptyBag) `unionBags` concatMapBag do_spec (mapBag is_decl iss)
where
@@ -740,7 +798,7 @@ greRdrNames gre@GRE{ gre_lcl = lcl, gre_imp = iss }
-- definition site is used, otherwise the location of the import
-- declaration. We want to sort the export locations in
-- exportClashErr by this SrcSpan, we need to extract it:
-greSrcSpan :: GlobalRdrElt -> SrcSpan
+greSrcSpan :: Outputable info => GlobalRdrEltX info -> SrcSpan
greSrcSpan gre@(GRE { gre_lcl = lcl, gre_imp = iss } )
| lcl = greDefinitionSrcSpan gre
| Just is <- headMaybe iss = is_dloc (is_decl is)
@@ -756,16 +814,20 @@ availParent (AvailTC m _) = ParentIs m
availParent (Avail {}) = NoParent
-greParent_maybe :: GlobalRdrElt -> Maybe Name
+greParent_maybe :: GlobalRdrEltX info -> Maybe Name
greParent_maybe gre = case gre_par gre of
NoParent -> Nothing
ParentIs n -> Just n
+gresToNameSet :: [GlobalRdrEltX info] -> NameSet
+gresToNameSet gres = foldr add emptyNameSet gres
+ where add gre set = extendNameSet set (greName gre)
+
-- | Takes a list of distinct GREs and folds them
-- into AvailInfos. This is more efficient than mapping each individual
--- GRE to an AvailInfo and the folding using `plusAvail` but needs the
+-- GRE to an AvailInfo and then folding using `plusAvail`, but needs the
-- uniqueness assumption.
-gresToAvailInfo :: [GlobalRdrElt] -> [AvailInfo]
+gresToAvailInfo :: forall info. [GlobalRdrEltX info] -> [AvailInfo]
gresToAvailInfo gres
= nonDetNameEnvElts avail_env
where
@@ -773,7 +835,7 @@ gresToAvailInfo gres
(avail_env, _) = foldl' add (emptyNameEnv, emptyNameSet) gres
add :: (NameEnv AvailInfo, NameSet)
- -> GlobalRdrElt
+ -> GlobalRdrEltX info
-> (NameEnv AvailInfo, NameSet)
add (env, done) gre
| name `elemNameSet` done
@@ -782,43 +844,68 @@ gresToAvailInfo gres
= ( extendNameEnv_Acc comb availFromGRE env key gre
, done `extendNameSet` name )
where
- name = greMangledName gre
+ name = greName gre
key = case greParent_maybe gre of
Just parent -> parent
- Nothing -> greMangledName gre
+ Nothing -> greName gre
-- We want to insert the child `k` into a list of children but
-- need to maintain the invariant that the parent is first.
--
-- We also use the invariant that `k` is not already in `ns`.
- insertChildIntoChildren :: Name -> [GreName] -> GreName -> [GreName]
+ insertChildIntoChildren :: Name -> [Name] -> Name -> [Name]
insertChildIntoChildren _ [] k = [k]
insertChildIntoChildren p (n:ns) k
- | NormalGreName p == k = k:n:ns
+ | p == k = k:n:ns
| otherwise = n:k:ns
- comb :: GlobalRdrElt -> AvailInfo -> AvailInfo
+ comb :: GlobalRdrEltX info -> AvailInfo -> AvailInfo
comb _ (Avail n) = Avail n -- Duplicated name, should not happen
comb gre (AvailTC m ns)
= case gre_par gre of
- NoParent -> AvailTC m (gre_name gre:ns) -- Not sure this ever happens
- ParentIs {} -> AvailTC m (insertChildIntoChildren m ns (gre_name gre))
+ NoParent -> AvailTC m (greName gre:ns) -- Not sure this ever happens
+ ParentIs {} -> AvailTC m (insertChildIntoChildren m ns (greName gre))
-availFromGRE :: GlobalRdrElt -> AvailInfo
+availFromGRE :: GlobalRdrEltX info -> AvailInfo
availFromGRE (GRE { gre_name = child, gre_par = parent })
= case parent of
- ParentIs p -> AvailTC p [child]
- NoParent | NormalGreName me <- child, isTyConName me -> AvailTC me [child]
- | otherwise -> Avail child
+ ParentIs p
+ -> AvailTC p [child]
+ NoParent
+ | isTyConName child -- NB: don't force the GREInfo field unnecessarily.
+ -> AvailTC child [child]
+ | otherwise
+ -> Avail child
-emptyGlobalRdrEnv :: GlobalRdrEnv
+emptyGlobalRdrEnv :: GlobalRdrEnvX info
emptyGlobalRdrEnv = emptyOccEnv
-globalRdrEnvElts :: GlobalRdrEnv -> [GlobalRdrElt]
-globalRdrEnvElts env = foldOccEnv (++) [] env
+globalRdrEnvElts :: GlobalRdrEnvX info -> [GlobalRdrEltX info]
+globalRdrEnvElts env = nonDetFoldOccEnv (++) [] env
+
+-- | Drop all 'GREInfo' fields in a 'GlobalRdrEnv' in order to
+-- avoid space leaks.
+--
+-- See Note [Forcing GREInfo] in GHC.Types.GREInfo.
+forceGlobalRdrEnv :: GlobalRdrEnvX info -> IfGlobalRdrEnv
+forceGlobalRdrEnv rdrs =
+ strictMapOccEnv (strictMap (\ gre -> gre { gre_info = () })) rdrs
-instance Outputable GlobalRdrElt where
- ppr gre = hang (ppr (greMangledName gre) <+> ppr (gre_par gre))
+-- | Hydrate a previously dehydrated 'GlobalRdrEnv',
+-- by (lazily!) looking up the 'GREInfo' using the provided function.
+--
+-- See Note [Forcing GREInfo] in GHC.Types.GREInfo.
+hydrateGlobalRdrEnv :: forall info noInfo
+ . (Name -> IO info)
+ -> GlobalRdrEnvX noInfo -> GlobalRdrEnvX info
+hydrateGlobalRdrEnv f = mapOccEnv (fmap g)
+ where
+ g gre = gre { gre_info = unsafePerformIO $ f (greName gre) }
+ -- NB: use unsafePerformIO to delay the lookup until it is forced.
+ -- See also 'GHC.Rename.Env.lookupGREInfo'.
+
+instance Outputable info => Outputable (GlobalRdrEltX info) where
+ ppr gre = hang (ppr (greName gre) <+> ppr (gre_par gre) <+> ppr (gre_info gre))
2 (pprNameProvenance gre)
pprGlobalRdrEnv :: Bool -> GlobalRdrEnv -> SDoc
@@ -831,66 +918,220 @@ pprGlobalRdrEnv locals_only env
remove_locals gres | locals_only = filter isLocalGRE gres
| otherwise = gres
pp [] = empty
- pp gres@(gre:_) = hang (ppr occ
- <+> parens (text "unique" <+> ppr (getUnique occ))
- <> colon)
- 2 (vcat (map ppr gres))
+ pp gres@(gre:_) = hang (ppr occ <> colon)
+ 2 (vcat (map ppr gres))
where
- occ = nameOccName (greMangledName gre)
-
-lookupGlobalRdrEnv :: GlobalRdrEnv -> OccName -> [GlobalRdrElt]
-lookupGlobalRdrEnv env occ_name = case lookupOccEnv env occ_name of
- Nothing -> []
- Just gres -> gres
-
-lookupGRE_RdrName :: RdrName -> GlobalRdrEnv -> [GlobalRdrElt]
--- ^ Look for this 'RdrName' in the global environment. Omits record fields
--- without selector functions (see Note [NoFieldSelectors] in GHC.Rename.Env).
-lookupGRE_RdrName rdr_name env =
- filter (not . isNoFieldSelectorGRE) (lookupGRE_RdrName' rdr_name env)
-
-lookupGRE_RdrName' :: RdrName -> GlobalRdrEnv -> [GlobalRdrElt]
--- ^ Look for this 'RdrName' in the global environment. Includes record fields
--- without selector functions (see Note [NoFieldSelectors] in GHC.Rename.Env).
-lookupGRE_RdrName' rdr_name env
- = case lookupOccEnv env (rdrNameOcc rdr_name) of
- Nothing -> []
- Just gres -> pickGREs rdr_name gres
-
-lookupGRE_Name :: GlobalRdrEnv -> Name -> Maybe GlobalRdrElt
--- ^ Look for precisely this 'Name' in the environment. This tests
--- whether it is in scope, ignoring anything else that might be in
--- scope with the same 'OccName'.
-lookupGRE_Name env name
- = lookupGRE_Name_OccName env name (nameOccName name)
-
-lookupGRE_GreName :: GlobalRdrEnv -> GreName -> Maybe GlobalRdrElt
--- ^ Look for precisely this 'GreName' in the environment. This tests
--- whether it is in scope, ignoring anything else that might be in
--- scope with the same 'OccName'.
-lookupGRE_GreName env gname
- = lookupGRE_Name_OccName env (greNameMangledName gname) (occName gname)
-
-lookupGRE_FieldLabel :: GlobalRdrEnv -> FieldLabel -> Maybe GlobalRdrElt
--- ^ Look for a particular record field selector in the environment, where the
--- selector name and field label may be different: the GlobalRdrEnv is keyed on
--- the label. See Note [GreNames] for why this happens.
-lookupGRE_FieldLabel env fl
- = lookupGRE_Name_OccName env (flSelector fl) (mkVarOccFS (field_label $ flLabel fl))
-
-lookupGRE_Name_OccName :: GlobalRdrEnv -> Name -> OccName -> Maybe GlobalRdrElt
--- ^ Look for precisely this 'Name' in the environment, but with an 'OccName'
--- that might differ from that of the 'Name'. See 'lookupGRE_FieldLabel' and
--- Note [GreNames].
-lookupGRE_Name_OccName env name occ
- = case [ gre | gre <- lookupGlobalRdrEnv env occ
- , greMangledName gre == name ] of
+ occ = nameOccName (greName gre)
+
+{-
+Note [NoFieldSelectors]
+~~~~~~~~~~~~~~~~~~~~~~~
+The NoFieldSelectors extension allows record fields to be defined without
+bringing the corresponding selector functions into scope. However, such fields
+may still be used in contexts such as record construction, pattern matching or
+update. This requires us to distinguish contexts in which selectors are required
+from those in which any field may be used. For example:
+
+ {-# LANGUAGE NoFieldSelectors #-}
+ module M (T(foo), foo) where -- T(foo) refers to the field,
+ -- unadorned foo to the value binding
+ data T = MkT { foo :: Int }
+ foo = ()
+
+ bar = foo -- refers to the value binding, field ignored
+
+ module N where
+ import M (T(..))
+ baz = MkT { foo = 3 } -- refers to the field
+ oops = foo -- an error: the field is in scope but the value binding is not
+
+Each 'FieldLabel' indicates (in the 'flHasFieldSelector' field) whether the
+FieldSelectors extension was enabled in the defining module. This allows them
+to be filtered out by 'filterFieldGREs'.
+
+Even when NoFieldSelectors is in use, we still generate selector functions
+internally. For example, the expression
+ getField @"foo" t
+or (with dot-notation)
+ t.foo
+extracts the `foo` field of t::T, and hence needs the selector function
+(see Note [HasField instances] in GHC.Tc.Instance.Class).
+
+In many of the name lookup functions in this module we pass a FieldsOrSelectors
+value, indicating what we are looking for:
+
+ * WantNormal: fields are in scope only if they have an accompanying selector
+ function, e.g. we are looking up a variable in an expression
+ (lookupExprOccRn).
+
+ * WantBoth: any name or field will do, regardless of whether the selector
+ function is available, e.g. record updates (lookupRecUpdFields) with
+ NoDisambiguateRecordFields.
+
+ * WantField: any field will do, regardless of whether the selector function is
+ available, but ignoring any non-field names, e.g. record updates
+ (lookupRecUpdFields with DisambiguateRecordFields.
+
+-----------------------------------------------------------------------------------
+ Context FieldsOrSelectors
+-----------------------------------------------------------------------------------
+ Record construction/pattern match WantField, but unless DisambiguateRecordFields
+ e.g. MkT { foo = 3 } is in effect, also look up using WantBoth
+ Record update, e.g. e { foo = 3 } to report when a non-field clashes with a field.
+
+ :info in GHCi WantBoth
+
+ Variable occurrence in expression WantNormal
+ Type variable, data constructor
+ Pretty much everything else
+-----------------------------------------------------------------------------------
+-}
+
+fieldGRE_maybe :: GlobalRdrElt -> Maybe FieldGlobalRdrElt
+fieldGRE_maybe gre = do
+ guard (isRecFldGRE gre)
+ return gre
+
+fieldGRELabel :: HasDebugCallStack => FieldGlobalRdrElt -> FieldLabel
+fieldGRELabel = recFieldLabel . fieldGREInfo
+
+fieldGREInfo :: HasDebugCallStack => FieldGlobalRdrElt -> RecFieldInfo
+fieldGREInfo gre
+ = assertPpr (isRecFldGRE gre) (ppr gre) $
+ case gre_info gre of
+ IAmRecField info -> info
+ info -> pprPanic "fieldGREInfo" $
+ vcat [ text "gre_name:" <+> ppr (greName gre)
+ , text "info:" <+> ppr info ]
+
+recFieldConLike_maybe :: HasDebugCallStack => GlobalRdrElt -> Maybe ConInfo
+recFieldConLike_maybe gre =
+ case gre_info gre of
+ IAmConLike info -> Just info
+ _ -> Nothing
+
+recFieldInfo_maybe :: HasDebugCallStack => GlobalRdrElt -> Maybe RecFieldInfo
+recFieldInfo_maybe gre =
+ case gre_info gre of
+ IAmRecField info -> assertPpr (isRecFldGRE gre) (ppr gre) $ Just info
+ _ -> Nothing
+
+-- | When looking up GREs, we may or may not want to include fields that were
+-- defined in modules with @NoFieldSelectors@ enabled. See Note
+-- [NoFieldSelectors].
+data FieldsOrSelectors
+ = WantNormal -- ^ Include normal names, and fields with selectors, but
+ -- ignore fields without selectors.
+ | WantBoth -- ^ Include normal names and all fields (regardless of whether
+ -- they have selectors).
+ | WantField -- ^ Include only fields, with or without selectors, ignoring
+ -- any non-fields in scope.
+ deriving Eq
+
+filterFieldGREs :: FieldsOrSelectors -> [GlobalRdrElt] -> [GlobalRdrElt]
+filterFieldGREs WantBoth = id
+filterFieldGREs fos = filter (allowGRE fos)
+
+allowGRE :: FieldsOrSelectors -> GlobalRdrElt -> Bool
+allowGRE WantBoth _
+ = True
+allowGRE WantNormal gre
+ -- NB: we only need to consult the GREInfo for record field GREs,
+ -- to check whether they define field selectors.
+ -- By checking 'isRecFldGRE' first, which only consults the NameSpace,
+ -- we avoid forcing the GREInfo for things that aren't record fields.
+ | isRecFldGRE gre
+ = flHasFieldSelector (fieldGRELabel gre) == FieldSelectors
+ | otherwise
+ = True
+allowGRE WantField gre
+ = isRecFldGRE gre
+
+-- | How should we look up in a 'GlobalRdrEnv'? Should we only look up
+-- names with the exact same 'OccName', or do we allow different 'NameSpace's?
+--
+-- Depending on the answer, we might need more or less information from the
+-- 'GlobalRdrEnv', e.g. if we want to include matching record fields we need
+-- to know if the corresponding record fields define field selectors, for which
+-- we need to consult the 'GREInfo'. This is why this datatype is a GADT.
+--
+-- See Note [IfGlobalRdrEnv].
+data WhichGREs info where
+ -- | Look for this specific 'OccName', with the exact same 'NameSpace',
+ -- in the 'GlobalRdrEnv'.
+ SameOccName :: WhichGREs info
+ -- | If the 'OccName' is a variable, also look up in the record field namespaces.
+ --
+ -- Used to look up variables which might refer to record fields.
+ IncludeFields :: FieldsOrSelectors
+ -- ^ - Should we include record fields defined with @-XNoFieldSelectors@?
+ -- - Should we include non-fields?
+ --
+ -- See Note [NoFieldSelectors].
+ -> WhichGREs GREInfo
+ -- | Like @'IncludeFields'@, but if the 'OccName' is a field,
+ -- also look up in the variable namespace.
+ --
+ -- Used to check if there are name clashes.
+ AllNameSpaces :: FieldsOrSelectors -> WhichGREs GREInfo
+
+-- | Look for this 'OccName' in the global environment.
+--
+-- The 'WhichGREs' argument specifies which 'GlobalRdrElt's we are interested in.
+lookupGRE_OccName :: WhichGREs info -> GlobalRdrEnvX info -> OccName -> [GlobalRdrEltX info]
+lookupGRE_OccName what env occ
+ -- If the 'RdrName' is a variable, we might also need
+ -- to look up in the record field namespaces.
+ | isVarOcc occ
+ , Just flds <- mb_flds
+ = normal ++ flds
+ -- If the 'RdrName' is a record field, we might want to check
+ -- the variable namespace too.
+ | isFieldOcc occ
+ , Just flds <- mb_flds
+ = flds ++ case what of { AllNameSpaces {} -> vars; _ -> [] }
+ | otherwise
+ = normal
+
+ where
+ mb_flds =
+ case what of
+ IncludeFields fos -> Just $ filterFieldGREs fos $ concat $ lookupFieldsOccEnv env (occNameFS occ)
+ AllNameSpaces fos -> Just $ filterFieldGREs fos $ concat $ lookupFieldsOccEnv env (occNameFS occ)
+ SameOccName -> Nothing
+
+ normal = fromMaybe [] $ lookupOccEnv env occ
+ vars = fromMaybe [] $ lookupOccEnv env (recFieldToVarOcc occ)
+
+-- | Like 'lookupGRE_OccName', but for a 'RdrName'.
+lookupGRE_RdrName :: WhichGREs info -> GlobalRdrEnvX info -> RdrName -> [GlobalRdrEltX info]
+lookupGRE_RdrName what env rdr =
+ pickGREs rdr $ lookupGRE_OccName what env (rdrNameOcc rdr)
+
+-- | Look for precisely this 'Name' in the environment.
+--
+-- This tests whether it is in scope, ignoring anything
+-- else that might be in scope which doesn't have the same 'Unique'.
+lookupGRE_Name :: Outputable info => GlobalRdrEnvX info -> Name -> Maybe (GlobalRdrEltX info)
+lookupGRE_Name env name =
+ let occ = nameOccName name
+ in case [ gre | gre <- lookupGRE_OccName SameOccName env occ
+ , gre_name gre == name ] of
[] -> Nothing
[gre] -> Just gre
- gres -> pprPanic "lookupGRE_Name_OccName"
+ gres -> pprPanic "lookupGRE_Name"
(ppr name $$ ppr occ $$ ppr gres)
-- See INVARIANT 1 on GlobalRdrEnv
+-- | Look for a particular record field selector in the environment.
+lookupGRE_FieldLabel :: GlobalRdrEnv -> FieldLabel -> Maybe FieldGlobalRdrElt
+lookupGRE_FieldLabel env fl =
+ case lookupGRE_Name env (flSelector fl) of
+ Nothing -> Nothing
+ Just gre ->
+ assertPpr (isRecFldGRE gre)
+ (vcat [ text "lookupGre_FieldLabel:" <+> ppr fl ]) $
+ Just gre
getGRE_NameQualifier_maybes :: GlobalRdrEnv -> Name -> [Maybe [ModuleName]]
-- Returns all the qualifiers by which 'x' is in scope
@@ -905,35 +1146,37 @@ getGRE_NameQualifier_maybes env name
| lcl = Nothing
| otherwise = Just $ map (is_as . is_decl) (bagToList iss)
-isLocalGRE :: GlobalRdrElt -> Bool
-isLocalGRE (GRE {gre_lcl = lcl }) = lcl
+isLocalGRE :: GlobalRdrEltX info -> Bool
+isLocalGRE (GRE { gre_lcl = lcl }) = lcl
-isRecFldGRE :: GlobalRdrElt -> Bool
-isRecFldGRE = isJust . greFieldLabel
+-- | Is this a record field GRE?
+--
+-- Important: does /not/ consult the 'GreInfo' field.
+isRecFldGRE :: GlobalRdrEltX info -> Bool
+isRecFldGRE (GRE { gre_name = nm }) = isFieldName nm
isDuplicateRecFldGRE :: GlobalRdrElt -> Bool
-- ^ Is this a record field defined with DuplicateRecordFields?
--- (See Note [GreNames])
isDuplicateRecFldGRE =
- maybe False ((DuplicateRecordFields ==) . flHasDuplicateRecordFields) . greFieldLabel
+ maybe False ((DuplicateRecordFields ==) . flHasDuplicateRecordFields) . greFieldLabel_maybe
isNoFieldSelectorGRE :: GlobalRdrElt -> Bool
-- ^ Is this a record field defined with NoFieldSelectors?
-- (See Note [NoFieldSelectors] in GHC.Rename.Env)
isNoFieldSelectorGRE =
- maybe False ((NoFieldSelectors ==) . flHasFieldSelector) . greFieldLabel
+ maybe False ((NoFieldSelectors ==) . flHasFieldSelector) . greFieldLabel_maybe
isFieldSelectorGRE :: GlobalRdrElt -> Bool
-- ^ Is this a record field defined with FieldSelectors?
-- (See Note [NoFieldSelectors] in GHC.Rename.Env)
isFieldSelectorGRE =
- maybe False ((FieldSelectors ==) . flHasFieldSelector) . greFieldLabel
+ maybe False ((FieldSelectors ==) . flHasFieldSelector) . greFieldLabel_maybe
-greFieldLabel :: GlobalRdrElt -> Maybe FieldLabel
+greFieldLabel_maybe :: GlobalRdrElt -> Maybe FieldLabel
-- ^ Returns the field label of this GRE, if it has one
-greFieldLabel = greNameFieldLabel . gre_name
+greFieldLabel_maybe = fmap fieldGRELabel . fieldGRE_maybe
-unQualOK :: GlobalRdrElt -> Bool
+unQualOK :: GlobalRdrEltX info -> Bool
-- ^ Test if an unqualified version of this thing would be in scope
unQualOK (GRE {gre_lcl = lcl, gre_imp = iss })
| lcl = True
@@ -972,7 +1215,7 @@ Now the "ambiguous occurrence" message can correctly report how the
ambiguity arises.
-}
-pickGREs :: RdrName -> [GlobalRdrElt] -> [GlobalRdrElt]
+pickGREs :: RdrName -> [GlobalRdrEltX info] -> [GlobalRdrEltX info]
-- ^ Takes a list of GREs which have the right OccName 'x'
-- Pick those GREs that are in scope
-- * Qualified, as 'M.x' if want_qual is Qual M _
@@ -985,14 +1228,14 @@ pickGREs (Unqual {}) gres = mapMaybe pickUnqualGRE gres
pickGREs (Qual mod _) gres = mapMaybe (pickQualGRE mod) gres
pickGREs _ _ = [] -- I don't think this actually happens
-pickUnqualGRE :: GlobalRdrElt -> Maybe GlobalRdrElt
+pickUnqualGRE :: GlobalRdrEltX info -> Maybe (GlobalRdrEltX info)
pickUnqualGRE gre@(GRE { gre_lcl = lcl, gre_imp = iss })
| not lcl, null iss' = Nothing
| otherwise = Just (gre { gre_imp = iss' })
where
iss' = filterBag unQualSpecOK iss
-pickQualGRE :: ModuleName -> GlobalRdrElt -> Maybe GlobalRdrElt
+pickQualGRE :: ModuleName -> GlobalRdrEltX info -> Maybe (GlobalRdrEltX info)
pickQualGRE mod gre@(GRE { gre_lcl = lcl, gre_imp = iss })
| not lcl', null iss' = Nothing
| otherwise = Just (gre { gre_lcl = lcl', gre_imp = iss' })
@@ -1005,7 +1248,7 @@ pickQualGRE mod gre@(GRE { gre_lcl = lcl, gre_imp = iss })
Just n_mod -> moduleName n_mod == mod
Nothing -> False
-pickGREsModExp :: ModuleName -> [GlobalRdrElt] -> [(GlobalRdrElt,GlobalRdrElt)]
+pickGREsModExp :: ModuleName -> [GlobalRdrEltX info] -> [(GlobalRdrEltX info,GlobalRdrEltX info)]
-- ^ Pick GREs that are in scope *both* qualified *and* unqualified
-- Return each GRE that is, as a pair
-- (qual_gre, unqual_gre)
@@ -1021,12 +1264,15 @@ pickGREsModExp mod gres = mapMaybe (pickBothGRE mod) gres
-- parser will generate Exact RdrNames for them, so the
-- cluttered envt is no use. Really, it's only useful for
-- GHC.Base and GHC.Tuple.
-pickBothGRE :: ModuleName -> GlobalRdrElt -> Maybe (GlobalRdrElt, GlobalRdrElt)
+pickBothGRE :: ModuleName -> GlobalRdrEltX info -> Maybe (GlobalRdrEltX info, GlobalRdrEltX info)
pickBothGRE mod gre
- | isBuiltInSyntax (greMangledName gre) = Nothing
+ | isBuiltInSyntax (greName gre)
+ = Nothing
| Just gre1 <- pickQualGRE mod gre
- , Just gre2 <- pickUnqualGRE gre = Just (gre1, gre2)
- | otherwise = Nothing
+ , Just gre2 <- pickUnqualGRE gre
+ = Just (gre1, gre2)
+ | otherwise
+ = Nothing
-- Building GlobalRdrEnvs
@@ -1044,7 +1290,7 @@ mkGlobalRdrEnv gres
insertGRE :: GlobalRdrElt -> [GlobalRdrElt] -> [GlobalRdrElt]
insertGRE new_g [] = [new_g]
insertGRE new_g (old_g : old_gs)
- | gre_name new_g == gre_name old_g
+ | greName new_g == greName old_g
= new_g `plusGRE` old_g : old_gs
| otherwise
= old_g : insertGRE new_g old_gs
@@ -1055,7 +1301,8 @@ plusGRE g1 g2
= GRE { gre_name = gre_name g1
, gre_lcl = gre_lcl g1 || gre_lcl g2
, gre_imp = gre_imp g1 `unionBags` gre_imp g2
- , gre_par = gre_par g1 `plusParent` gre_par g2 }
+ , gre_par = gre_par g1 `plusParent` gre_par g2
+ , gre_info = gre_info g1 `plusGREInfo` gre_info g2 }
transformGREs :: (GlobalRdrElt -> GlobalRdrElt)
-> [OccName]
@@ -1077,9 +1324,10 @@ extendGlobalRdrEnv env gre
{- Note [GlobalRdrEnv shadowing]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Before adding new names to the GlobalRdrEnv we nuke some existing entries;
-this is "shadowing". The actual work is done by RdrEnv.shadowNames.
+this is "shadowing". The actual work is done by GHC.Types.Name.Reader.shadowNames.
Suppose
- env' = shadowNames env f `extendGlobalRdrEnv` M.f
+
+ env' = shadowNames env { f } `extendGlobalRdrEnv` { M.f }
Then:
* Looking up (Unqual f) in env' should succeed, returning M.f,
@@ -1147,29 +1395,61 @@ There are two reasons for shadowing:
rnSrcDecls will first call extendGlobalRdrEnvRn with C[f] from the
class decl, and *separately* extend the envt with the value binding.
At that stage, the class op 'f' will have an Internal name.
+
+Wrinkle [Shadowing namespaces]
+
+ In the following GHCi session:
+
+ > data A = MkA { foo :: Int }
+ > foo = False
+ > bar = foo
+
+ We expect the variable 'foo' to shadow the record field 'foo', even though
+ they are in separate namespaces, so that the occurrence of 'foo' in the body
+ of 'bar' is not ambiguous.
+
-}
-shadowNames :: GlobalRdrEnv -> OccEnv a -> GlobalRdrEnv
+shadowNames :: GlobalRdrEnv -> GlobalRdrEnv -> GlobalRdrEnv
-- Remove certain old GREs that share the same OccName as this new Name.
-- See Note [GlobalRdrEnv shadowing] for details
-shadowNames = minusOccEnv_C (\gres _ -> Just (mapMaybe shadow gres))
+shadowNames env new_gres =
+ minusOccEnv_C_Ns (nonDetStrictFoldUFM shadow_many) env new_gres
where
- shadow :: GlobalRdrElt -> Maybe GlobalRdrElt
- shadow
- old_gre@(GRE { gre_lcl = lcl, gre_imp = iss })
- = case greDefinitionModule old_gre of
- Nothing -> Just old_gre -- Old name is Internal; do not shadow
- Just old_mod
- | null iss' -- Nothing remains
- -> Nothing
+ shadow_many :: [GlobalRdrElt]
+ -> UniqFM NameSpace [GlobalRdrElt]
+ -> UniqFM NameSpace [GlobalRdrElt]
+ shadow_many news olds_map =
+ ( `mapMaybeUFM` olds_map ) $ \ olds ->
+ case foldl' shadow_one olds news of
+ res | null res
+ -> Nothing
| otherwise
- -> Just (old_gre { gre_lcl = False, gre_imp = iss' })
+ -> Just res
+
+ shadow_one :: [GlobalRdrElt] -> GlobalRdrElt -> [GlobalRdrElt]
+ shadow_one olds new =
+ ( `mapMaybe` olds ) $ \ old ->
+ if new `greClashesWith` old
+ then shadow old
+ else Just old
+
+ shadow :: GlobalRdrElt -> Maybe GlobalRdrElt
+ shadow old_gre@(GRE { gre_lcl = lcl, gre_imp = iss }) =
+ case greDefinitionModule old_gre of
+ Nothing -> Just old_gre -- Old name is Internal; do not shadow
+ Just old_mod
+ | null iss' -- Nothing remains
+ -> Nothing
- where
- iss' = lcl_imp `unionBags` mapMaybeBag set_qual iss
- lcl_imp | lcl = listToBag [mk_fake_imp_spec old_gre old_mod]
- | otherwise = emptyBag
+ | otherwise
+ -> Just (old_gre { gre_lcl = False, gre_imp = iss' })
+
+ where
+ iss' = lcl_imp `unionBags` mapBag set_qual iss
+ lcl_imp | lcl = unitBag $ mk_fake_imp_spec old_gre old_mod
+ | otherwise = emptyBag
mk_fake_imp_spec old_gre old_mod -- Urgh!
= ImpSpec id_spec ImpAll
@@ -1180,9 +1460,32 @@ shadowNames = minusOccEnv_C (\gres _ -> Just (mapMaybe shadow gres))
, is_qual = True
, is_dloc = greDefinitionSrcSpan old_gre }
- set_qual :: ImportSpec -> Maybe ImportSpec
- set_qual is = Just (is { is_decl = (is_decl is) { is_qual = True } })
+ set_qual :: ImportSpec -> ImportSpec
+ set_qual is = is { is_decl = (is_decl is) { is_qual = True } }
+
+
+-- | @greClashesWith gre old_gre@ computes whether @gre@ clashes with @old_gre@
+-- (assuming they both have the same underlying 'occNameFS').
+greClashesWith :: GlobalRdrElt -> (GlobalRdrElt -> Bool)
+greClashesWith gre old_gre
+ | ns == old_ns
+ = True
+ -- A new variable shadows record fields with field selectors.
+ | ns == varName
+ = isFieldSelectorGRE old_gre
+
+ -- A new record field...
+ | isFieldNameSpace ns
+ -- ... shadows variables if it defines a field selector.
+ = ( old_ns == varName && isFieldSelectorGRE gre )
+ -- ... shadows record fields unless it is a duplicate record field.
+ || ( isFieldNameSpace old_ns && not (isDuplicateRecFldGRE gre) )
+ | otherwise
+ = False
+ where
+ ns = occNameSpace $ greOccName gre
+ old_ns = occNameSpace $ greOccName old_gre
{-
************************************************************************
@@ -1336,14 +1639,13 @@ isExplicitItem :: ImpItemSpec -> Bool
isExplicitItem ImpAll = False
isExplicitItem (ImpSome {is_explicit = exp}) = exp
-pprNameProvenance :: GlobalRdrElt -> SDoc
+pprNameProvenance :: GlobalRdrEltX info -> SDoc
-- ^ Print out one place where the name was define/imported
-- (With -dppr-debug, print them all)
-pprNameProvenance gre@(GRE { gre_lcl = lcl, gre_imp = iss })
+pprNameProvenance (GRE { gre_name = name, gre_lcl = lcl, gre_imp = iss })
= ifPprDebug (vcat pp_provs)
(head pp_provs)
where
- name = greMangledName gre
pp_provs = pp_lcl ++ map pp_is (bagToList iss)
pp_lcl = if lcl then [text "defined at" <+> ppr (nameSrcLoc name)]
else []
diff --git a/compiler/GHC/Types/Name/Shape.hs b/compiler/GHC/Types/Name/Shape.hs
index 19e97ef2c6..18adadd5a0 100644
--- a/compiler/GHC/Types/Name/Shape.hs
+++ b/compiler/GHC/Types/Name/Shape.hs
@@ -17,9 +17,7 @@ import GHC.Driver.Env
import GHC.Unit.Module
-import GHC.Types.Unique.FM
import GHC.Types.Avail
-import GHC.Types.FieldLabel
import GHC.Types.Name
import GHC.Types.Name.Env
@@ -87,7 +85,7 @@ mkNameShape :: ModuleName -> [AvailInfo] -> NameShape
mkNameShape mod_name as =
NameShape mod_name as $ mkOccEnv $ do
a <- as
- n <- availName a : availNamesWithSelectors a
+ n <- availName a : availNames a
return (occName n, n)
-- | Given an existing 'NameShape', merge it with a list of 'AvailInfo's
@@ -180,24 +178,14 @@ substName env n | Just n' <- lookupNameEnv env n = n'
-- for type constructors, where it is sufficient to substitute the 'availName'
-- to induce a substitution on 'availNames'.
substNameAvailInfo :: HscEnv -> ShNameSubst -> AvailInfo -> IO AvailInfo
-substNameAvailInfo _ env (Avail (NormalGreName n)) = return (Avail (NormalGreName (substName env n)))
-substNameAvailInfo _ env (Avail (FieldGreName fl)) =
- return (Avail (FieldGreName fl { flSelector = substName env (flSelector fl) }))
+substNameAvailInfo _ env (Avail gre) =
+ return $ Avail (substName env gre)
substNameAvailInfo hsc_env env (AvailTC n ns) =
let mb_mod = fmap nameModule (lookupNameEnv env n)
- in AvailTC (substName env n) <$> mapM (setNameGreName hsc_env mb_mod) ns
+ in AvailTC (substName env n) <$> mapM (setName hsc_env mb_mod) ns
-setNameGreName :: HscEnv -> Maybe Module -> GreName -> IO GreName
-setNameGreName hsc_env mb_mod gname = case gname of
- NormalGreName n -> NormalGreName <$> initIfaceLoad hsc_env (setNameModule mb_mod n)
- FieldGreName fl -> FieldGreName <$> setNameFieldSelector hsc_env mb_mod fl
-
--- | Set the 'Module' of a 'FieldSelector'
-setNameFieldSelector :: HscEnv -> Maybe Module -> FieldLabel -> IO FieldLabel
-setNameFieldSelector _ Nothing f = return f
-setNameFieldSelector hsc_env mb_mod (FieldLabel l b has_sel sel) = do
- sel' <- initIfaceLoad hsc_env $ setNameModule mb_mod sel
- return (FieldLabel l b has_sel sel')
+setName :: HscEnv -> Maybe Module -> Name -> IO Name
+setName hsc_env mb_mod nm = initIfaceLoad hsc_env (setNameModule mb_mod nm)
{-
************************************************************************
@@ -226,19 +214,19 @@ mergeAvails as1 as2 =
-- with only name holes from @flexi@ unifiable (all other name holes rigid.)
uAvailInfos :: ModuleName -> [AvailInfo] -> [AvailInfo] -> Either HsigShapeMismatchReason ShNameSubst
uAvailInfos flexi as1 as2 = -- pprTrace "uAvailInfos" (ppr as1 $$ ppr as2) $
- let mkOE as = listToUFM $ do a <- as
- n <- availNames a
- return (nameOccName n, a)
+ let mkOE as = mkOccEnv [(nameOccName n, a) | a <- as, n <- availNames a]
in foldM (\subst (a1, a2) -> uAvailInfo flexi subst a1 a2) emptyNameEnv
- (nonDetEltsUFM (intersectUFM_C (,) (mkOE as1) (mkOE as2)))
+ (nonDetOccEnvElts $ intersectOccEnv_C (,) (mkOE as1) (mkOE as2))
-- Edward: I have to say, this is pretty clever.
-- | Unify two 'AvailInfo's, given an existing substitution @subst@,
-- with only name holes from @flexi@ unifiable (all other name holes rigid.)
uAvailInfo :: ModuleName -> ShNameSubst -> AvailInfo -> AvailInfo
-> Either HsigShapeMismatchReason ShNameSubst
-uAvailInfo flexi subst (Avail (NormalGreName n1)) (Avail (NormalGreName n2)) = uName flexi subst n1 n2
-uAvailInfo flexi subst (AvailTC n1 _) (AvailTC n2 _) = uName flexi subst n1 n2
+uAvailInfo flexi subst (Avail n1) (Avail n2)
+ = uName flexi subst n1 n2
+uAvailInfo flexi subst (AvailTC n1 _) (AvailTC n2 _)
+ = uName flexi subst n1 n2
uAvailInfo _ _ a1 a2 = Left $ HsigShapeSortMismatch a1 a2
-- | Unify two 'Name's, given an existing substitution @subst@,
diff --git a/compiler/GHC/Types/TyThing.hs b/compiler/GHC/Types/TyThing.hs
index ab400204d5..cb7b57095c 100644
--- a/compiler/GHC/Types/TyThing.hs
+++ b/compiler/GHC/Types/TyThing.hs
@@ -1,3 +1,5 @@
+{-# LANGUAGE LambdaCase #-}
+
-- | A global typecheckable-thing, essentially anything that has a name.
module GHC.Types.TyThing
( TyThing (..)
@@ -15,7 +17,7 @@ module GHC.Types.TyThing
, isImplicitTyThing
, tyThingParent_maybe
, tyThingsTyCoVars
- , tyThingAvailInfo
+ , tyThingLocalGREs, tyThingGREInfo
, tyThingTyCon
, tyThingCoAxiom
, tyThingDataCon
@@ -27,11 +29,12 @@ where
import GHC.Prelude
import GHC.Types.Name
+import GHC.Types.Name.Reader
import GHC.Types.Var
import GHC.Types.Var.Set
import GHC.Types.Id
import GHC.Types.Id.Info
-import GHC.Types.Avail
+import GHC.Types.Unique.Set
import GHC.Core.Class
import GHC.Core.DataCon
@@ -276,22 +279,83 @@ tyThingsTyCoVars tts =
Nothing -> tyCoVarsOfType $ tyConKind tc
ttToVarSet (ACoAxiom _) = emptyVarSet
--- | The Names that a TyThing should bring into scope. Used to build
--- the GlobalRdrEnv for the InteractiveContext.
-tyThingAvailInfo :: TyThing -> [AvailInfo]
-tyThingAvailInfo (ATyCon t)
- = case tyConClass_maybe t of
- Just c -> [availTC n ((n : map getName (classMethods c)
- ++ map getName (classATs c))) [] ]
- where n = getName c
- Nothing -> [availTC n (n : map getName dcs) flds]
- where n = getName t
- dcs = tyConDataCons t
- flds = tyConFieldLabels t
-tyThingAvailInfo (AConLike (PatSynCon p))
- = avail (getName p) : map availField (patSynFieldLabels p)
-tyThingAvailInfo t
- = [avail (getName t)]
+-- | The 'GlobalRdrElt's that a 'TyThing' should bring into scope.
+-- Used to build the 'GlobalRdrEnv' for the InteractiveContext.
+tyThingLocalGREs :: TyThing -> [GlobalRdrElt]
+tyThingLocalGREs ty_thing =
+ case ty_thing of
+ ATyCon t
+ | Just c <- tyConClass_maybe t
+ -> myself NoParent
+ : ( map (localVanillaGRE (ParentIs $ className c) . getName) (classMethods c)
+ ++ map tc_GRE (classATs c) )
+ | otherwise
+ -> let dcs = tyConDataCons t
+ par = ParentIs $ tyConName t
+ mk_nm = DataConName . dataConName
+ in myself NoParent
+ : map (dc_GRE par) dcs
+ ++
+ localFieldGREs par
+ [ (mk_nm dc, con_info)
+ | dc <- dcs
+ , let con_info = conLikeConInfo (RealDataCon dc) ]
+ AConLike con ->
+ let par = case con of
+ PatSynCon {} -> NoParent
+ -- NoParent for local pattern synonyms as per
+ -- Note [Parents] in GHC.Types.Name.Reader.
+ RealDataCon dc -> ParentIs $ tyConName $ dataConTyCon dc
+ in
+ myself par :
+ localFieldGREs par
+ [(conLikeConLikeName con, conLikeConInfo con)]
+ AnId id
+ | RecSelId { sel_tycon = RecSelData tc } <- idDetails id
+ -> [ myself (ParentIs $ tyConName tc) ]
+ -- Fallback to NoParent for PatSyn record selectors,
+ -- as per Note [Parents] in GHC.Types.Name.Reader.
+ _ -> [ myself NoParent ]
+ where
+ tc_GRE :: TyCon -> GlobalRdrElt
+ tc_GRE at = localTyConGRE
+ (fmap tyConName $ tyConFlavour at)
+ (tyConName at)
+ dc_GRE :: Parent -> DataCon -> GlobalRdrElt
+ dc_GRE par dc =
+ let con_info = conLikeConInfo (RealDataCon dc)
+ in localConLikeGRE par (DataConName $ dataConName dc, con_info)
+ myself :: Parent -> GlobalRdrElt
+ myself p =
+ (localVanillaGRE p (getName ty_thing))
+ { gre_info = tyThingGREInfo ty_thing }
+
+-- | Obtain information pertinent to the renamer about a particular 'TyThing'.
+--
+-- This extracts out renamer information from typechecker information.
+tyThingGREInfo :: TyThing -> GREInfo
+tyThingGREInfo = \case
+ AConLike con -> IAmConLike $ conLikeConInfo con
+ AnId id -> case idDetails id of
+ RecSelId { sel_tycon = parent, sel_fieldLabel = fl } ->
+ let relevant_cons = case parent of
+ RecSelPatSyn ps -> unitUniqSet $ PatSynName (patSynName ps)
+ RecSelData tc ->
+ let dcs = map RealDataCon $ tyConDataCons tc in
+ case conLikesWithFields dcs [flLabel fl] of
+ [] -> pprPanic "tyThingGREInfo: no DataCons with this FieldLabel" $
+ vcat [ text "id:" <+> ppr id
+ , text "fl:" <+> ppr fl
+ , text "dcs:" <+> ppr dcs ]
+ cons -> mkUniqSet $ map conLikeConLikeName cons
+ in IAmRecField $
+ RecFieldInfo
+ { recFieldLabel = fl
+ , recFieldCons = relevant_cons }
+ _ -> Vanilla
+ ATyCon tc ->
+ IAmTyCon (fmap tyConName $ tyConFlavour tc)
+ _ -> Vanilla
-- | Get the 'TyCon' from a 'TyThing' if it is a type constructor thing. Panics otherwise
tyThingTyCon :: HasDebugCallStack => TyThing -> TyCon
diff --git a/compiler/GHC/Types/TypeEnv.hs b/compiler/GHC/Types/TypeEnv.hs
index a431c3ddfc..75d6855a4c 100644
--- a/compiler/GHC/Types/TypeEnv.hs
+++ b/compiler/GHC/Types/TypeEnv.hs
@@ -93,4 +93,3 @@ extendTypeEnvWithIds env ids
plusTypeEnv :: TypeEnv -> TypeEnv -> TypeEnv
plusTypeEnv env1 env2 = plusNameEnv env1 env2
-
diff --git a/compiler/GHC/Types/Unique/FM.hs b/compiler/GHC/Types/Unique/FM.hs
index 137e985f92..bdd14156dd 100644
--- a/compiler/GHC/Types/Unique/FM.hs
+++ b/compiler/GHC/Types/Unique/FM.hs
@@ -44,7 +44,7 @@ module GHC.Types.Unique.FM (
addListToUFM,addListToUFM_C,
addToUFM_Directly,
addListToUFM_Directly,
- adjustUFM, alterUFM,
+ adjustUFM, alterUFM, alterUFM_Directly,
adjustUFM_Directly,
delFromUFM,
delFromUFM_Directly,
@@ -64,10 +64,11 @@ module GHC.Types.Unique.FM (
intersectUFM_C,
disjointUFM,
equalKeysUFM,
- nonDetStrictFoldUFM, foldUFM, nonDetStrictFoldUFM_DirectlyM,
+ nonDetStrictFoldUFM, nonDetFoldUFM, nonDetStrictFoldUFM_DirectlyM,
+ nonDetFoldWithKeyUFM,
nonDetStrictFoldUFM_Directly,
anyUFM, allUFM, seqEltsUFM,
- mapUFM, mapUFM_Directly,
+ mapUFM, mapUFM_Directly, strictMapUFM,
mapMaybeUFM,
elemUFM, elemUFM_Directly,
filterUFM, filterUFM_Directly, partitionUFM,
@@ -165,10 +166,10 @@ addToUFM_Directly (UFM m) u v = UFM (M.insert (getKey u) v m)
addToUFM_C
:: Uniquable key
- => (elt -> elt -> elt) -- old -> new -> result
- -> UniqFM key elt -- old
- -> key -> elt -- new
- -> UniqFM key elt -- result
+ => (elt -> elt -> elt) -- ^ old -> new -> result
+ -> UniqFM key elt -- ^ old
+ -> key -> elt -- ^ new
+ -> UniqFM key elt -- ^ result
-- Arguments of combining function of M.insertWith and addToUFM_C are flipped.
addToUFM_C f (UFM m) k v =
UFM (M.insertWith (flip f) (getKey $ getUnique k) v m)
@@ -177,9 +178,9 @@ addToUFM_Acc
:: Uniquable key
=> (elt -> elts -> elts) -- Add to existing
-> (elt -> elts) -- New element
- -> UniqFM key elts -- old
+ -> UniqFM key elts -- old
-> key -> elt -- new
- -> UniqFM key elts -- result
+ -> UniqFM key elts -- result
addToUFM_Acc exi new (UFM m) k v =
UFM (M.insertWith (\_new old -> exi v old) (getKey $ getUnique k) (new v) m)
@@ -188,11 +189,11 @@ addToUFM_Acc exi new (UFM m) k v =
-- otherwise compute the element to add using the passed function.
addToUFM_L
:: Uniquable key
- => (key -> elt -> elt -> elt) -- key,old,new
+ => (key -> elt -> elt -> elt) -- ^ key,old,new
-> key
-> elt -- new
-> UniqFM key elt
- -> (Maybe elt, UniqFM key elt) -- old, result
+ -> (Maybe elt, UniqFM key elt) -- ^ old, result
addToUFM_L f k v (UFM m) =
coerce $
M.insertLookupWithKey
@@ -203,12 +204,19 @@ addToUFM_L f k v (UFM m) =
alterUFM
:: Uniquable key
- => (Maybe elt -> Maybe elt) -- How to adjust
- -> UniqFM key elt -- old
- -> key -- new
- -> UniqFM key elt -- result
+ => (Maybe elt -> Maybe elt) -- ^ How to adjust
+ -> UniqFM key elt -- ^ old
+ -> key -- ^ new
+ -> UniqFM key elt -- ^ result
alterUFM f (UFM m) k = UFM (M.alter f (getKey $ getUnique k) m)
+alterUFM_Directly
+ :: (Maybe elt -> Maybe elt) -- ^ How to adjust
+ -> UniqFM key elt -- ^ old
+ -> Unique -- ^ new
+ -> UniqFM key elt -- ^ result
+alterUFM_Directly f (UFM m) k = UFM (M.alter f (getKey k) m)
+
-- | Add elements to the map, combining existing values with inserted ones using
-- the given function.
addListToUFM_C
@@ -356,8 +364,18 @@ intersectUFM_C f (UFM x) (UFM y) = UFM (M.intersectionWith f x y)
disjointUFM :: UniqFM key elt1 -> UniqFM key elt2 -> Bool
disjointUFM (UFM x) (UFM y) = M.disjoint x y
-foldUFM :: (elt -> a -> a) -> a -> UniqFM key elt -> a
-foldUFM k z (UFM m) = M.foldr k z m
+-- | Fold over a 'UniqFM'.
+--
+-- Non-deterministic, unless the folding function is commutative
+-- (i.e. @a1 `f` ( a2 `f` b ) == a2 `f` ( a1 `f` b )@ for all @a1@, @a2@, @b@).
+nonDetFoldUFM :: (elt -> a -> a) -> a -> UniqFM key elt -> a
+nonDetFoldUFM f z (UFM m) = M.foldr f z m
+
+-- | Like 'nonDetFoldUFM', but with the 'Unique' key as well.
+nonDetFoldWithKeyUFM :: (Unique -> elt -> a -> a) -> a -> UniqFM key elt -> a
+nonDetFoldWithKeyUFM f z (UFM m) = M.foldrWithKey f' z m
+ where
+ f' k e a = f (getUnique k) e a
mapUFM :: (elt1 -> elt2) -> UniqFM key elt1 -> UniqFM key elt2
mapUFM f (UFM m) = UFM (M.map f m)
@@ -368,6 +386,9 @@ mapMaybeUFM f (UFM m) = UFM (M.mapMaybe f m)
mapUFM_Directly :: (Unique -> elt1 -> elt2) -> UniqFM key elt1 -> UniqFM key elt2
mapUFM_Directly f (UFM m) = UFM (M.mapWithKey (f . getUnique) m)
+strictMapUFM :: (a -> b) -> UniqFM k a -> UniqFM k b
+strictMapUFM f (UFM a) = UFM $ MS.map f a
+
filterUFM :: (elt -> Bool) -> UniqFM key elt -> UniqFM key elt
filterUFM p (UFM m) = UFM (M.filter p m)
@@ -411,7 +432,7 @@ allUFM :: (elt -> Bool) -> UniqFM key elt -> Bool
allUFM p (UFM m) = M.foldr ((&&) . p) True m
seqEltsUFM :: (elt -> ()) -> UniqFM key elt -> ()
-seqEltsUFM seqElt = foldUFM (\v rest -> seqElt v `seq` rest) ()
+seqEltsUFM seqElt = nonDetFoldUFM (\v rest -> seqElt v `seq` rest) ()
-- See Note [Deterministic UniqFM] to learn about nondeterminism.
-- If you use this please provide a justification why it doesn't introduce
diff --git a/compiler/GHC/Types/Unique/Map.hs b/compiler/GHC/Types/Unique/Map.hs
index 4f79792811..6bfe5bb5ff 100644
--- a/compiler/GHC/Types/Unique/Map.hs
+++ b/compiler/GHC/Types/Unique/Map.hs
@@ -237,4 +237,4 @@ nonDetEltsUniqMap :: UniqMap k a -> [(k, a)]
nonDetEltsUniqMap (UniqMap m) = nonDetEltsUFM m
nonDetFoldUniqMap :: ((k, a) -> b -> b) -> b -> UniqMap k a -> b
-nonDetFoldUniqMap go z (UniqMap m) = foldUFM go z m
+nonDetFoldUniqMap go z (UniqMap m) = nonDetFoldUFM go z m
diff --git a/compiler/GHC/Types/Unique/Set.hs b/compiler/GHC/Types/Unique/Set.hs
index 88e56f9e44..56710ebe9a 100644
--- a/compiler/GHC/Types/Unique/Set.hs
+++ b/compiler/GHC/Types/Unique/Set.hs
@@ -72,7 +72,7 @@ emptyUniqSet = UniqSet emptyUFM
unitUniqSet :: Uniquable a => a -> UniqSet a
unitUniqSet x = UniqSet $ unitUFM x x
-mkUniqSet :: Uniquable a => [a] -> UniqSet a
+mkUniqSet :: Uniquable a => [a] -> UniqSet a
mkUniqSet = foldl' addOneToUniqSet emptyUniqSet
addOneToUniqSet :: Uniquable a => UniqSet a -> a -> UniqSet a
@@ -186,7 +186,7 @@ getUniqSet = getUniqSet'
-- | 'unsafeUFMToUniqSet' converts a @'UniqFM' a@ into a @'UniqSet' a@
-- assuming, without checking, that it maps each 'Unique' to a value
-- that has that 'Unique'. See Note [UniqSet invariant].
-unsafeUFMToUniqSet :: UniqFM a a -> UniqSet a
+unsafeUFMToUniqSet :: UniqFM a a -> UniqSet a
unsafeUFMToUniqSet = UniqSet
instance Outputable a => Outputable (UniqSet a) where
diff --git a/compiler/GHC/Unit/Module/Env.hs b/compiler/GHC/Unit/Module/Env.hs
index aec4add585..c982539688 100644
--- a/compiler/GHC/Unit/Module/Env.hs
+++ b/compiler/GHC/Unit/Module/Env.hs
@@ -6,6 +6,7 @@ module GHC.Unit.Module.Env
, extendModuleEnvList_C, plusModuleEnv_C
, delModuleEnvList, delModuleEnv, plusModuleEnv, lookupModuleEnv
, lookupWithDefaultModuleEnv, mapModuleEnv, mkModuleEnv, emptyModuleEnv
+ , alterModuleEnv
, partitionModuleEnv
, moduleEnvKeys, moduleEnvElts, moduleEnvToList
, unitModuleEnv, isEmptyModuleEnv
@@ -147,6 +148,9 @@ partitionModuleEnv f (ModuleEnv e) = (ModuleEnv a, ModuleEnv b)
where
(a,b) = Map.partition f e
+alterModuleEnv :: (Maybe a -> Maybe a) -> Module -> ModuleEnv a -> ModuleEnv a
+alterModuleEnv f m (ModuleEnv e) = ModuleEnv (Map.alter f (NDModule m) e)
+
mkModuleEnv :: [(Module, a)] -> ModuleEnv a
mkModuleEnv xs = ModuleEnv (Map.fromList [(NDModule k, v) | (k,v) <- xs])
diff --git a/compiler/GHC/Unit/Module/ModIface.hs b/compiler/GHC/Unit/Module/ModIface.hs
index 9838f227b9..c981a92bc2 100644
--- a/compiler/GHC/Unit/Module/ModIface.hs
+++ b/compiler/GHC/Unit/Module/ModIface.hs
@@ -206,7 +206,7 @@ data ModIface_ (phase :: ModIfacePhase)
-- combined with mi_decls allows us to restart code generation.
-- See Note [Interface Files with Core Definitions] and Note [Interface File with Core: Sharing RHSs]
- mi_globals :: !(Maybe GlobalRdrEnv),
+ mi_globals :: !(Maybe IfGlobalRdrEnv),
-- ^ Binds all the things defined at the top level in
-- the /original source/ code for this module. which
-- is NOT the same as mi_exports, nor mi_decls (which
@@ -558,7 +558,7 @@ instance ( NFData (IfaceBackendExts (phase :: ModIfacePhase))
, mi_decls, mi_extra_decls, mi_globals, mi_insts
, mi_fam_insts, mi_rules, mi_hpc, mi_trust, mi_trust_pkg
, mi_complete_matches, mi_docs, mi_final_exts
- , mi_ext_fields, mi_src_hash})
+ , mi_ext_fields, mi_src_hash })
= rnf mi_module
`seq` rnf mi_sig_of
`seq` mi_hsc_src
@@ -572,6 +572,10 @@ instance ( NFData (IfaceBackendExts (phase :: ModIfacePhase))
`seq` rnf mi_decls
`seq` rnf mi_extra_decls
`seq` mi_globals
+ -- NB: we already removed any potential space leaks in 'mi_globals' by
+ -- dehydrating, that is, by turning the 'GlobalRdrEnv' into a 'IfGlobalRdrEnv'.
+ -- This means we don't need to use 'rnf' here.
+ -- See Note [Forcing GREInfo] in GHC.Types.GREInfo.
`seq` rnf mi_insts
`seq` rnf mi_fam_insts
`seq` rnf mi_rules
diff --git a/compiler/GHC/Utils/Binary.hs b/compiler/GHC/Utils/Binary.hs
index 7d07cfeba0..7534d65918 100644
--- a/compiler/GHC/Utils/Binary.hs
+++ b/compiler/GHC/Utils/Binary.hs
@@ -1260,16 +1260,6 @@ instance Binary ModuleName where
put_ bh (ModuleName fs) = put_ bh fs
get bh = do fs <- get bh; return (ModuleName fs)
--- instance Binary FunctionOrData where
--- put_ bh IsFunction = putByte bh 0
--- put_ bh IsData = putByte bh 1
--- get bh = do
--- h <- getByte bh
--- case h of
--- 0 -> return IsFunction
--- 1 -> return IsData
--- _ -> panic "Binary FunctionOrData"
-
-- instance Binary TupleSort where
-- put_ bh BoxedTuple = putByte bh 0
-- put_ bh UnboxedTuple = putByte bh 1
diff --git a/compiler/GHC/Utils/Monad.hs b/compiler/GHC/Utils/Monad.hs
index d91570223c..e5a8007865 100644
--- a/compiler/GHC/Utils/Monad.hs
+++ b/compiler/GHC/Utils/Monad.hs
@@ -11,6 +11,7 @@ module GHC.Utils.Monad
, MonadIO(..)
, zipWith3M, zipWith3M_, zipWith4M, zipWithAndUnzipM
+ , zipWith3MNE
, mapAndUnzipM, mapAndUnzip3M, mapAndUnzip4M, mapAndUnzip5M
, mapAccumLM
, mapSndM
@@ -97,6 +98,15 @@ zipWithAndUnzipM f (x:xs) (y:ys)
; return (c:cs, d:ds) }
zipWithAndUnzipM _ _ _ = return ([], [])
+-- | 'zipWith3M' for 'NonEmpty' lists.
+zipWith3MNE :: Monad m
+ => (a -> b -> c -> m d)
+ -> NonEmpty a -> NonEmpty b -> NonEmpty c -> m (NonEmpty d)
+zipWith3MNE f ~(x :| xs) ~(y :| ys) ~(z :| zs)
+ = do { w <- f x y z
+ ; ws <- zipWith3M f xs ys zs
+ ; return $ w :| ws }
+
{-
Note [Inline @mapAndUnzipNM@ functions]
diff --git a/compiler/GHC/Utils/Outputable.hs b/compiler/GHC/Utils/Outputable.hs
index 55e2bb2a9a..f63d515b83 100644
--- a/compiler/GHC/Utils/Outputable.hs
+++ b/compiler/GHC/Utils/Outputable.hs
@@ -31,7 +31,8 @@ module GHC.Utils.Outputable (
SDoc, runSDoc, PDoc(..),
docToSDoc,
interppSP, interpp'SP, interpp'SP',
- pprQuotedList, pprWithCommas, quotedListWithOr, quotedListWithNor,
+ pprQuotedList, pprWithCommas,
+ quotedListWithOr, quotedListWithNor, quotedListWithAnd,
pprWithBars,
spaceIfSingleQuote,
isEmpty, nest,
@@ -150,6 +151,7 @@ import Numeric (showFFloat)
import Data.Graph (SCC(..))
import Data.List (intersperse)
import Data.List.NonEmpty (NonEmpty (..))
+import Data.Semigroup (Arg(..))
import qualified Data.List.NonEmpty as NEL
import Data.Time
import Data.Time.Format.ISO8601
@@ -949,6 +951,9 @@ instance (Outputable a) => Outputable [a] where
instance (Outputable a) => Outputable (NonEmpty a) where
ppr = ppr . NEL.toList
+instance (Outputable a, Outputable b) => Outputable (Arg a b) where
+ ppr (Arg a b) = text "Arg" <+> ppr a <+> ppr b
+
instance (Outputable a) => Outputable (Set a) where
ppr s = braces (pprWithCommas ppr (Set.toList s))
@@ -1383,6 +1388,11 @@ quotedListWithNor :: [SDoc] -> SDoc
quotedListWithNor xs@(_:_:_) = quotedList (init xs) <+> text "nor" <+> quotes (last xs)
quotedListWithNor xs = quotedList xs
+quotedListWithAnd :: [SDoc] -> SDoc
+-- [x,y,z] ==> `x', `y' and `z'
+quotedListWithAnd xs@(_:_:_) = quotedList (init xs) <+> text "and" <+> quotes (last xs)
+quotedListWithAnd xs = quotedList xs
+
{-
************************************************************************
* *
diff --git a/compiler/Language/Haskell/Syntax/Decls.hs b/compiler/Language/Haskell/Syntax/Decls.hs
index 0af2cfbf94..52475a9dfe 100644
--- a/compiler/Language/Haskell/Syntax/Decls.hs
+++ b/compiler/Language/Haskell/Syntax/Decls.hs
@@ -45,7 +45,7 @@ module Language.Haskell.Syntax.Decls (
FamilyDecl(..), LFamilyDecl,
-- ** Instance declarations
- InstDecl(..), LInstDecl, FamilyInfo(..),
+ InstDecl(..), LInstDecl, FamilyInfo(..), familyInfoTyConFlavour,
TyFamInstDecl(..), LTyFamInstDecl,
TyFamDefltDecl, LTyFamDefltDecl,
DataFamInstDecl(..), LDataFamInstDecl,
@@ -99,12 +99,14 @@ import Language.Haskell.Syntax.Extension
import Language.Haskell.Syntax.Type
import Language.Haskell.Syntax.Basic (Role)
-import GHC.Types.Basic (TopLevelFlag, OverlapMode, RuleName, Activation)
+import GHC.Types.Basic (TopLevelFlag, OverlapMode, RuleName, Activation
+ ,TyConFlavour(..), TypeOrData(..))
import GHC.Types.ForeignCall (CType, CCallConv, Safety, Header, CLabelString, CCallTarget, CExportSpec)
import GHC.Types.Fixity (LexicalFixity)
import GHC.Core.Type (Specificity)
import GHC.Unit.Module.Warnings (WarningTxt)
+import GHC.Utils.Panic.Plain ( assert )
import GHC.Hs.Doc (LHsDoc) -- ROMES:TODO Discuss in #21592 whether this is parsed AST or base AST
@@ -863,6 +865,28 @@ data FamilyInfo pass
-- said "type family Foo x where .."
| ClosedTypeFamily (Maybe [LTyFamInstEqn pass])
+familyInfoTyConFlavour
+ :: Maybe tc -- ^ Just cls <=> this is an associated family of class cls
+ -> FamilyInfo pass
+ -> TyConFlavour tc
+familyInfoTyConFlavour mb_parent_tycon info =
+ case info of
+ DataFamily -> OpenFamilyFlavour IAmData mb_parent_tycon
+ OpenTypeFamily -> OpenFamilyFlavour IAmType mb_parent_tycon
+ ClosedTypeFamily _ -> assert (isNothing mb_parent_tycon)
+ -- See Note [Closed type family mb_parent_tycon]
+ ClosedTypeFamilyFlavour
+
+{- Note [Closed type family mb_parent_tycon]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+There's no way to write a closed type family inside a class declaration:
+
+ class C a where
+ type family F a where -- error: parse error on input ‘where’
+
+In fact, it is not clear what the meaning of such a declaration would be.
+Therefore, 'mb_parent_tycon' of any closed type family has to be Nothing.
+-}
{- *********************************************************************
* *
diff --git a/compiler/Language/Haskell/Syntax/Expr.hs b/compiler/Language/Haskell/Syntax/Expr.hs
index 1af91044dd..46419787f8 100644
--- a/compiler/Language/Haskell/Syntax/Expr.hs
+++ b/compiler/Language/Haskell/Syntax/Expr.hs
@@ -5,6 +5,7 @@
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE GADTs #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilyDependencies #-}
{-# LANGUAGE UndecidableInstances #-} -- Wrinkle in Note [Trees That Grow]
@@ -39,7 +40,6 @@ import GHC.Data.FastString (FastString)
-- libraries:
import Data.Data hiding (Fixity(..))
import Data.Bool
-import Data.Either
import Data.Eq
import Data.Maybe
import Data.List.NonEmpty ( NonEmpty )
@@ -147,6 +147,19 @@ type LHsRecProj p arg = XRec p (RecProj p arg)
type RecUpdProj p = RecProj p (LHsExpr p)
type LHsRecUpdProj p = XRec p (RecUpdProj p)
+-- | Haskell Record Update Fields.
+data LHsRecUpdFields p where
+ -- | A regular (non-overloaded) record update.
+ RegularRecUpdFields
+ :: { xRecUpdFields :: XLHsRecUpdLabels p
+ , recUpdFields :: [LHsRecUpdField p p] }
+ -> LHsRecUpdFields p
+ -- | An overloaded record update.
+ OverloadedRecUpdFields
+ :: { xOLRecUpdFields :: XLHsOLRecUpdLabels p
+ , olRecUpdFields :: [LHsRecUpdProj p] }
+ -> LHsRecUpdFields p
+
{-
************************************************************************
* *
@@ -463,7 +476,7 @@ data HsExpr p
| RecordUpd
{ rupd_ext :: XRecordUpd p
, rupd_expr :: LHsExpr p
- , rupd_flds :: Either [LHsRecUpdField p] [LHsRecUpdProj p]
+ , rupd_flds :: LHsRecUpdFields p
}
-- For a type family, the arg types are of the *instance* tycon,
-- not the family tycon
diff --git a/compiler/Language/Haskell/Syntax/Extension.hs b/compiler/Language/Haskell/Syntax/Extension.hs
index 9ad16c0cd7..b184f1f46b 100644
--- a/compiler/Language/Haskell/Syntax/Extension.hs
+++ b/compiler/Language/Haskell/Syntax/Extension.hs
@@ -432,6 +432,8 @@ type family XDo x
type family XExplicitList x
type family XRecordCon x
type family XRecordUpd x
+type family XLHsRecUpdLabels x
+type family XLHsOLRecUpdLabels x
type family XGetField x
type family XProjection x
type family XExprWithTySig x
diff --git a/compiler/Language/Haskell/Syntax/ImpExp.hs b/compiler/Language/Haskell/Syntax/ImpExp.hs
index fcb8ede0e7..08be638003 100644
--- a/compiler/Language/Haskell/Syntax/ImpExp.hs
+++ b/compiler/Language/Haskell/Syntax/ImpExp.hs
@@ -127,7 +127,7 @@ data IE pass
-- ^ Imported or exported Thing With given imported or exported
--
-- The thing is a Class/Type and the imported or exported things are
- -- methods/constructors and record fields; see Note [IEThingWith]
+ -- its children.
-- - 'GHC.Parser.Annotation.AnnKeywordId's : 'GHC.Parser.Annotation.AnnOpen',
-- 'GHC.Parser.Annotation.AnnClose',
-- 'GHC.Parser.Annotation.AnnComma',
diff --git a/compiler/Language/Haskell/Syntax/Pat.hs b/compiler/Language/Haskell/Syntax/Pat.hs
index 66b9708bfe..5e6f12c4b8 100644
--- a/compiler/Language/Haskell/Syntax/Pat.hs
+++ b/compiler/Language/Haskell/Syntax/Pat.hs
@@ -280,13 +280,13 @@ type LHsFieldBind p id arg = XRec p (HsFieldBind id arg)
type LHsRecField p arg = XRec p (HsRecField p arg)
-- | Located Haskell Record Update Field
-type LHsRecUpdField p = XRec p (HsRecUpdField p)
+type LHsRecUpdField p q = XRec p (HsRecUpdField p q)
-- | Haskell Record Field
type HsRecField p arg = HsFieldBind (LFieldOcc p) arg
-- | Haskell Record Update Field
-type HsRecUpdField p = HsFieldBind (LAmbiguousFieldOcc p) (LHsExpr p)
+type HsRecUpdField p q = HsFieldBind (LAmbiguousFieldOcc p) (LHsExpr q)
-- | Haskell Field Binding
--
@@ -353,7 +353,7 @@ data HsFieldBind lhs rhs = HsFieldBind {
--
-- hfbLHS = Unambiguous "x" $sel:x:MkS :: AmbiguousFieldOcc Id
--
--- See also Note [Disambiguating record fields] in GHC.Tc.Gen.Head.
+-- See also Note [Disambiguating record updates] in GHC.Rename.Pat.
hsRecFields :: forall p arg.UnXRec p => HsRecFields p arg -> [XCFieldOcc p]
hsRecFields rbinds = Data.List.map (hsRecFieldSel . unXRec @p) (rec_flds rbinds)
@@ -363,4 +363,3 @@ hsRecFieldsArgs rbinds = Data.List.map (hfbRHS . unXRec @p) (rec_flds rbinds)
hsRecFieldSel :: forall p arg. UnXRec p => HsRecField p arg -> XCFieldOcc p
hsRecFieldSel = foExt . unXRec @p . hfbLHS
-
diff --git a/compiler/ghc.cabal.in b/compiler/ghc.cabal.in
index 2cf8c04bff..2f37328c39 100644
--- a/compiler/ghc.cabal.in
+++ b/compiler/ghc.cabal.in
@@ -753,7 +753,6 @@ Library
GHC.Types.Basic
GHC.Types.BreakInfo
GHC.Types.CompleteMatch
- GHC.Types.ConInfo
GHC.Types.CostCentre
GHC.Types.CostCentre.State
GHC.Types.Cpr
@@ -765,6 +764,7 @@ Library
GHC.Types.Fixity.Env
GHC.Types.ForeignCall
GHC.Types.ForeignStubs
+ GHC.Types.GREInfo
GHC.Types.Hint
GHC.Types.Hint.Ppr
GHC.Types.HpcInfo
diff --git a/docs/users_guide/9.6.1-notes.rst b/docs/users_guide/9.6.1-notes.rst
index eaed67da22..5cf40a310b 100644
--- a/docs/users_guide/9.6.1-notes.rst
+++ b/docs/users_guide/9.6.1-notes.rst
@@ -215,6 +215,11 @@ Runtime system
- Add `Foreign.C.Types.ConstPtr` was added to encode ``const``-qualified pointer return
types in foreign declarations when using ``CApiFFI`` extension.
+- The ``RecordUpd`` constructor of ``HsExpr`` now takes an ``HsRecUpdFields``
+ instead of ``Either [LHsRecUpdField p] [LHsRecUpdProj p]``.
+ Instead of ``Left ..``, use the constructor ``RegularRecUpdFields``, and instead
+ of ``Right ..``, use the constructor ``OverloadedRecUpdFields``.
+
``ghc-heap`` library
~~~~~~~~~~~~~~~~~~~~
diff --git a/docs/users_guide/9.8.1-notes.rst b/docs/users_guide/9.8.1-notes.rst
index 97d7829ce3..003e3ed78b 100644
--- a/docs/users_guide/9.8.1-notes.rst
+++ b/docs/users_guide/9.8.1-notes.rst
@@ -46,6 +46,20 @@ Compiler
A new warning group :ghc-flag:`-Wextended-warnings` includes all such warnings
regardless of category. See :ref:`warning-deprecated-pragma`.
+- GHC is now better at disambiguating record updates in the presence of duplicate
+ record fields. The following program is now accepted ::
+
+ {-# LANGUAGE DuplicateRecordFields #-}
+
+ data R = MkR1 { foo :: Int }
+ | MkR2 { bar :: Int }
+
+ data S = MkS { foo :: Int, bar :: Int }
+
+ blah x = x { foo = 5, bar = 6 }
+
+ The point is that only the type S has a constructor with both fields "foo"
+ and "bar", so this record update is unambiguous.
GHCi
~~~~
@@ -82,6 +96,17 @@ Runtime system
``ghc-heap`` library
~~~~~~~~~~~~~~~~~~~~
+``template-haskell`` library
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+- The ``GadtC`` and ``RecGadtC`` constructors of the ``Con`` datatype now take
+ non-empty lists of constructors. This means that the ``gadtC`` and ``recGadtC``
+ smart constructors also expect non-empty lists as arguments.
+
+- Record fields now belong to separate ``NameSpace``s, keyed by the parent of
+ the record field. This is the name of the first constructor of the parent type,
+ even if this constructor does not have the field in question.
+ This change enables TemplateHaskell support for ``DuplicateRecordFields``.
Included libraries
------------------
diff --git a/ghc/GHCi/UI/Info.hs b/ghc/GHCi/UI/Info.hs
index 0f78fa5075..505a1da68f 100644
--- a/ghc/GHCi/UI/Info.hs
+++ b/ghc/GHCi/UI/Info.hs
@@ -59,7 +59,7 @@ data ModInfo = ModInfo
-- ^ Generated set of information about all spans in the
-- module that correspond to some kind of identifier for
-- which there will be type info and/or location info.
- , modinfoRdrEnv :: !(Strict.Maybe GlobalRdrEnv)
+ , modinfoRdrEnv :: !(Strict.Maybe IfGlobalRdrEnv)
-- ^ What's in scope in the module.
, modinfoLastUpdate :: !UTCTime
-- ^ The timestamp of the file used to generate this record.
@@ -316,6 +316,8 @@ getModInfo name = do
module_info = tm_checked_module_info typechecked
!rdr_env = case modInfoRdrEnv module_info of
Just rdrs -> Strict.Just rdrs
+ -- NB: this has already been deeply forced; no need to do that again.
+ -- See test case T15369 and Note [Forcing GREInfo] in GHC.Types.GREInfo.
Nothing -> Strict.Nothing
ts <- liftIO $ getModificationTime $ srcFilePath m
return $
@@ -331,7 +333,7 @@ modInfo_rdrs :: ModInfo -> [Name]
modInfo_rdrs mi =
case modinfoRdrEnv mi of
Strict.Nothing -> []
- Strict.Just env -> map greMangledName $ globalRdrEnvElts env
+ Strict.Just env -> map greName $ globalRdrEnvElts env
-- | Get ALL source spans in the module.
processAllTypeCheckedModule :: TypecheckedModule -> [SpanInfo]
diff --git a/ghc/GHCi/UI/Monad.hs b/ghc/GHCi/UI/Monad.hs
index 3016dd66d5..5b360f7400 100644
--- a/ghc/GHCi/UI/Monad.hs
+++ b/ghc/GHCi/UI/Monad.hs
@@ -51,7 +51,7 @@ import GHC.Types.SafeHaskell
import GHC.Driver.Make (ModIfaceCache(..))
import GHC.Unit
import GHC.Types.Name.Reader as RdrName (mkOrig)
-import qualified GHC.Types.Name.Ppr as Ppr (mkNamePprCtx )
+import qualified GHC.Types.Name.Ppr as Ppr (mkNamePprCtx)
import GHC.Builtin.Names (gHC_GHCI_HELPERS)
import GHC.Runtime.Interpreter
import GHC.Runtime.Context
@@ -367,10 +367,11 @@ printForUserNeverQualify doc = do
printForUserModInfo :: GhcMonad m => GHC.ModuleInfo -> SDoc -> m ()
printForUserModInfo info = printForUserGlobalRdrEnv (GHC.modInfoRdrEnv info)
-printForUserGlobalRdrEnv :: GhcMonad m => Maybe GlobalRdrEnv -> SDoc -> m ()
+printForUserGlobalRdrEnv :: (GhcMonad m, Outputable info)
+ => Maybe (GlobalRdrEnvX info) -> SDoc -> m ()
printForUserGlobalRdrEnv mb_rdr_env doc = do
dflags <- GHC.getInteractiveDynFlags
- name_ppr_ctx <- mkNamePprCtxFromGlobalRdrEnv dflags mb_rdr_env
+ name_ppr_ctx <- mkNamePprCtxFromGlobalRdrEnv dflags mb_rdr_env
liftIO $ Ppr.printForUser dflags stdout name_ppr_ctx AllTheWay doc
where
mkNamePprCtxFromGlobalRdrEnv _ Nothing = GHC.getNamePprCtx
diff --git a/libraries/template-haskell/Language/Haskell/TH/Lib/Internal.hs b/libraries/template-haskell/Language/Haskell/TH/Lib/Internal.hs
index 35bca47d25..542f1e16b6 100644
--- a/libraries/template-haskell/Language/Haskell/TH/Lib/Internal.hs
+++ b/libraries/template-haskell/Language/Haskell/TH/Lib/Internal.hs
@@ -23,7 +23,7 @@ import qualified Language.Haskell.TH.Syntax as TH
import Control.Applicative(liftA, Applicative(..))
import qualified Data.Kind as Kind (Type)
import Data.Word( Word8 )
-import Data.List.NonEmpty ( NonEmpty(..) )
+import Data.List.NonEmpty ( NonEmpty(..), toList )
import GHC.Exts (TYPE)
import Prelude hiding (Applicative(..))
@@ -680,10 +680,10 @@ forallC ns ctxt con = do
con' <- con
pure $ ForallC ns' ctxt' con'
-gadtC :: Quote m => [Name] -> [m StrictType] -> m Type -> m Con
+gadtC :: Quote m => NonEmpty Name -> [m StrictType] -> m Type -> m Con
gadtC cons strtys ty = liftA2 (GadtC cons) (sequenceA strtys) ty
-recGadtC :: Quote m => [Name] -> [m VarStrictType] -> m Type -> m Con
+recGadtC :: Quote m => NonEmpty Name -> [m VarStrictType] -> m Type -> m Con
recGadtC cons varstrtys ty = liftA2 (RecGadtC cons) (sequenceA varstrtys) ty
-------------------------------------------------------------------------------
@@ -1177,7 +1177,7 @@ docCons :: (Q Con, Maybe String, [Maybe String]) -> Q ()
docCons (c, md, arg_docs) = do
c' <- c
-- Attach docs to the constructors
- sequence_ [ putDoc (DeclDoc nm) d | Just d <- [md], nm <- get_cons_names c' ]
+ sequence_ [ putDoc (DeclDoc nm) d | Just d <- [md], nm <- toList $ get_cons_names c' ]
-- Attach docs to the arguments
case c' of
-- Record selector documentation isn't stored in the argument map,
@@ -1188,18 +1188,6 @@ docCons (c, md, arg_docs) = do
]
_ ->
sequence_ [ putDoc (ArgDoc nm i) arg_doc
- | nm <- get_cons_names c'
+ | nm <- toList $ get_cons_names c'
, (i, Just arg_doc) <- zip [0..] arg_docs
]
- where
- get_cons_names :: Con -> [Name]
- get_cons_names (NormalC n _) = [n]
- get_cons_names (RecC n _) = [n]
- get_cons_names (InfixC _ n _) = [n]
- get_cons_names (ForallC _ _ cons) = get_cons_names cons
- -- GadtC can have multiple names, e.g
- -- > data Bar a where
- -- > MkBar1, MkBar2 :: a -> Bar a
- -- Will have one GadtC with [MkBar1, MkBar2] as names
- get_cons_names (GadtC ns _ _) = ns
- get_cons_names (RecGadtC ns _ _) = ns
diff --git a/libraries/template-haskell/Language/Haskell/TH/Ppr.hs b/libraries/template-haskell/Language/Haskell/TH/Ppr.hs
index cedb974976..d3101a985b 100644
--- a/libraries/template-haskell/Language/Haskell/TH/Ppr.hs
+++ b/libraries/template-haskell/Language/Haskell/TH/Ppr.hs
@@ -11,6 +11,7 @@ module Language.Haskell.TH.Ppr where
import Text.PrettyPrint (render)
import Language.Haskell.TH.PprLib
import Language.Haskell.TH.Syntax
+import qualified Data.List.NonEmpty as NE ( toList )
import Data.Word ( Word8 )
import Data.Char ( toLower, chr)
import GHC.Show ( showMultiLineString )
@@ -682,22 +683,22 @@ instance Ppr Con where
<+> pprName' Infix c
<+> pprBangType st2
- ppr (ForallC ns ctxt (GadtC c sts ty))
- = commaSepApplied c <+> dcolon <+> pprForall ns ctxt
+ ppr (ForallC ns ctxt (GadtC cs sts ty))
+ = commaSepApplied (NE.toList cs) <+> dcolon <+> pprForall ns ctxt
<+> pprGadtRHS sts ty
- ppr (ForallC ns ctxt (RecGadtC c vsts ty))
- = commaSepApplied c <+> dcolon <+> pprForall ns ctxt
+ ppr (ForallC ns ctxt (RecGadtC cs vsts ty))
+ = commaSepApplied (NE.toList cs) <+> dcolon <+> pprForall ns ctxt
<+> pprRecFields vsts ty
ppr (ForallC ns ctxt con)
= pprForall ns ctxt <+> ppr con
- ppr (GadtC c sts ty)
- = commaSepApplied c <+> dcolon <+> pprGadtRHS sts ty
+ ppr (GadtC cs sts ty)
+ = commaSepApplied (NE.toList cs) <+> dcolon <+> pprGadtRHS sts ty
- ppr (RecGadtC c vsts ty)
- = commaSepApplied c <+> dcolon <+> pprRecFields vsts ty
+ ppr (RecGadtC cs vsts ty)
+ = commaSepApplied (NE.toList cs) <+> dcolon <+> pprRecFields vsts ty
instance Ppr PatSynDir where
ppr Unidir = text "<-"
diff --git a/libraries/template-haskell/Language/Haskell/TH/Syntax.hs b/libraries/template-haskell/Language/Haskell/TH/Syntax.hs
index 8be340bf93..6668273a14 100644
--- a/libraries/template-haskell/Language/Haskell/TH/Syntax.hs
+++ b/libraries/template-haskell/Language/Haskell/TH/Syntax.hs
@@ -48,6 +48,7 @@ import System.IO ( hPutStrLn, stderr )
import Data.Char ( isAlpha, isAlphaNum, isUpper, ord )
import Data.Int
import Data.List.NonEmpty ( NonEmpty(..) )
+import qualified Data.List.NonEmpty as NE ( singleton )
import Data.Void ( Void, absurd )
import Data.Word
import Data.Ratio
@@ -1498,8 +1499,9 @@ dataToExpQ = dataToQa varOrConE litE (foldl appE)
-- See #10796.
varOrConE s =
case nameSpace s of
- Just VarName -> return (VarE s)
- Just DataName -> return (ConE s)
+ Just VarName -> return (VarE s)
+ Just (FldName {}) -> return (VarE s)
+ Just DataName -> return (ConE s)
_ -> error $ "Can't construct an expression from name "
++ showName s
appE x y = do { a <- x; b <- y; return (AppE a b)}
@@ -1675,6 +1677,14 @@ data NameSpace = VarName -- ^ Variables
| DataName -- ^ Data constructors
| TcClsName -- ^ Type constructors and classes; Haskell has them
-- in the same name space for now.
+ | FldName
+ { fldParent :: !String
+ -- ^ The textual name of the parent of the field.
+ --
+ -- - For a field of a datatype, this is the name of the first constructor
+ -- of the datatype (regardless of whether this constructor has this field).
+ -- - For a field of a pattern synonym, this is the name of the pattern synonym.
+ }
deriving( Eq, Ord, Show, Data, Generic )
-- | @Uniq@ is used by GHC to distinguish names from each other.
@@ -1834,6 +1844,13 @@ mkNameG_v = mkNameG VarName
mkNameG_tc = mkNameG TcClsName
mkNameG_d = mkNameG DataName
+mkNameG_fld :: String -- ^ package
+ -> String -- ^ module
+ -> String -- ^ parent (first constructor of parent type)
+ -> String -- ^ field name
+ -> Name
+mkNameG_fld pkg modu con occ = mkNameG (FldName con) pkg modu occ
+
data NameIs = Alone | Applied | Infix
showName :: Name -> String
@@ -1857,11 +1874,11 @@ showName' ni nm
-- We may well want to distinguish them in the end.
-- Ditto NameU and NameL
nms = case nm of
- Name occ NameS -> occString occ
- Name occ (NameQ m) -> modString m ++ "." ++ occString occ
- Name occ (NameG _ _ m) -> modString m ++ "." ++ occString occ
- Name occ (NameU u) -> occString occ ++ "_" ++ show u
- Name occ (NameL u) -> occString occ ++ "_" ++ show u
+ Name occ NameS -> occString occ
+ Name occ (NameQ m) -> modString m ++ "." ++ occString occ
+ Name occ (NameG _ _ m) -> modString m ++ "." ++ occString occ
+ Name occ (NameU u) -> occString occ ++ "_" ++ show u
+ Name occ (NameL u) -> occString occ ++ "_" ++ show u
pnam = classify nms
@@ -2705,10 +2722,10 @@ data Con = NormalC Name [BangType] -- ^ @C Int a@
| RecC Name [VarBangType] -- ^ @C { v :: Int, w :: a }@
| InfixC BangType Name BangType -- ^ @Int :+ a@
| ForallC [TyVarBndr Specificity] Cxt Con -- ^ @forall a. Eq a => C [a]@
- | GadtC [Name] [BangType]
+ | GadtC (NonEmpty Name) [BangType]
Type -- See Note [GADT return type]
-- ^ @C :: a -> b -> T b Int@
- | RecGadtC [Name] [VarBangType]
+ | RecGadtC (NonEmpty Name) [VarBangType]
Type -- See Note [GADT return type]
-- ^ @C :: { v :: Int } -> T b Int@
deriving (Show, Eq, Ord, Data, Generic)
@@ -2907,3 +2924,15 @@ cmpEq _ = False
thenCmp :: Ordering -> Ordering -> Ordering
thenCmp EQ o2 = o2
thenCmp o1 _ = o1
+
+get_cons_names :: Con -> NonEmpty Name
+get_cons_names (NormalC n _) = NE.singleton n
+get_cons_names (RecC n _) = NE.singleton n
+get_cons_names (InfixC _ n _) = NE.singleton n
+get_cons_names (ForallC _ _ con) = get_cons_names con
+-- GadtC can have multiple names, e.g
+-- > data Bar a where
+-- > MkBar1, MkBar2 :: a -> Bar a
+-- Will have one GadtC with [MkBar1, MkBar2] as names
+get_cons_names (GadtC ns _ _) = ns
+get_cons_names (RecGadtC ns _ _) = ns \ No newline at end of file
diff --git a/libraries/template-haskell/changelog.md b/libraries/template-haskell/changelog.md
index 8382efd1fc..821c776d96 100644
--- a/libraries/template-haskell/changelog.md
+++ b/libraries/template-haskell/changelog.md
@@ -1,5 +1,17 @@
# Changelog for [`template-haskell` package](http://hackage.haskell.org/package/template-haskell)
+## 2.21.0.0
+
+ * The `GadtC` and `RecGadtC` constructors of the `Con` datatype now take
+ non-empty lists of constructors. This means that the `gadtC` and `recGadtC`
+ smart constructors also expect non-empty lists as arguments.
+
+ * Record fields now belong to separate `NameSpace`s, keyed by the parent of
+ the record field. This is the name of the first constructor of the parent type,
+ even if this constructor does not have the field in question.
+
+ This change enables TemplateHaskell support for `DuplicateRecordFields`.
+
## 2.20.0.0
* The `Ppr.pprInfixT` function has gained a `Precedence` argument.
diff --git a/testsuite/tests/backpack/reexport/T23080a.bkp b/testsuite/tests/backpack/reexport/T23080a.bkp
new file mode 100644
index 0000000000..3ca2d22cda
--- /dev/null
+++ b/testsuite/tests/backpack/reexport/T23080a.bkp
@@ -0,0 +1,9 @@
+unit t23080-unit1 where
+ signature H1 where
+ data T
+unit t23080-unit2 where
+ dependency t23080-unit1[H1=<H2>]
+ module B where
+ data T = MkT
+ signature H2 (T(MkT)) where
+ import B
diff --git a/testsuite/tests/backpack/reexport/T23080b.bkp b/testsuite/tests/backpack/reexport/T23080b.bkp
new file mode 100644
index 0000000000..bb4d86ab9e
--- /dev/null
+++ b/testsuite/tests/backpack/reexport/T23080b.bkp
@@ -0,0 +1,9 @@
+unit t23080-unit1 where
+ signature H1 where
+ data T
+unit t23080-unit2 where
+ dependency t23080-unit1[H1=<H2>]
+ module B where
+ data T = MkT { fld :: T }
+ signature H2 (T(fld)) where
+ import B
diff --git a/testsuite/tests/backpack/reexport/all.T b/testsuite/tests/backpack/reexport/all.T
index f677f01f2e..5bab153169 100644
--- a/testsuite/tests/backpack/reexport/all.T
+++ b/testsuite/tests/backpack/reexport/all.T
@@ -9,3 +9,5 @@ test('bkpreex07', normal, backpack_typecheck, [''])
test('bkpreex08', normal, backpack_typecheck, [''])
test('bkpreex09', normal, backpack_typecheck, [''])
test('bkpreex10', normal, backpack_typecheck, [''])
+test('T23080a', expect_broken(23080), backpack_typecheck, [''])
+test('T23080b', expect_broken(23080), backpack_typecheck, [''])
diff --git a/testsuite/tests/backpack/reexport/bkpreex05.bkp b/testsuite/tests/backpack/reexport/bkpreex05.bkp
index e496ed76fa..811ff69b89 100644
--- a/testsuite/tests/backpack/reexport/bkpreex05.bkp
+++ b/testsuite/tests/backpack/reexport/bkpreex05.bkp
@@ -1,28 +1,28 @@
unit bar where
- signature A(bar) where
- data A = A { foo :: Int, bar :: Bool }
+ signature H1(bar) where
+ data A = MkA { foo :: Int, bar :: Bool }
unit foo where
- signature A(foo) where
- data A = A { foo :: Int, bar :: Bool }
+ signature H2(foo) where
+ data A = MkA { foo :: Int, bar :: Bool }
unit impl where
- module A1 where
- data A = A { foo :: Int, bar :: Bool }
- module A2 where
- data A = A { foo :: Int, bar :: Bool }
- module A(foo, bar) where
- import A1(foo)
- import A2(bar)
+ module M1 where
+ data A = MkA { foo :: Int, bar :: Bool }
+ module M2 where
+ data A = MkA { foo :: Int, bar :: Bool }
+ module M(foo, bar) where
+ import M1(foo)
+ import M2(bar)
-- Kind of boring test now haha
unit barimpl where
- dependency bar[A=impl:A]
+ dependency bar[H1=impl:M]
unit fooimpl where
- dependency foo[A=impl:A]
+ dependency foo[H2=impl:M]
unit foobarimpl where
- dependency foo[A=impl:A]
- dependency bar[A=impl:A]
+ dependency foo[H2=impl:M]
+ dependency bar[H1=impl:M]
diff --git a/testsuite/tests/count-deps/CountDepsAst.stdout b/testsuite/tests/count-deps/CountDepsAst.stdout
index efd58af99f..652a35a9b7 100644
--- a/testsuite/tests/count-deps/CountDepsAst.stdout
+++ b/testsuite/tests/count-deps/CountDepsAst.stdout
@@ -201,7 +201,6 @@ GHC.Types.Avail
GHC.Types.Basic
GHC.Types.BreakInfo
GHC.Types.CompleteMatch
-GHC.Types.ConInfo
GHC.Types.CostCentre
GHC.Types.CostCentre.State
GHC.Types.Cpr
@@ -213,6 +212,7 @@ GHC.Types.Fixity
GHC.Types.Fixity.Env
GHC.Types.ForeignCall
GHC.Types.ForeignStubs
+GHC.Types.GREInfo
GHC.Types.Hint
GHC.Types.Hint.Ppr
GHC.Types.HpcInfo
diff --git a/testsuite/tests/count-deps/CountDepsParser.stdout b/testsuite/tests/count-deps/CountDepsParser.stdout
index f1116f5198..4850f57f96 100644
--- a/testsuite/tests/count-deps/CountDepsParser.stdout
+++ b/testsuite/tests/count-deps/CountDepsParser.stdout
@@ -208,7 +208,6 @@ GHC.Types.Avail
GHC.Types.Basic
GHC.Types.BreakInfo
GHC.Types.CompleteMatch
-GHC.Types.ConInfo
GHC.Types.CostCentre
GHC.Types.CostCentre.State
GHC.Types.Cpr
@@ -220,6 +219,7 @@ GHC.Types.Fixity
GHC.Types.Fixity.Env
GHC.Types.ForeignCall
GHC.Types.ForeignStubs
+GHC.Types.GREInfo
GHC.Types.Hint
GHC.Types.Hint.Ppr
GHC.Types.HpcInfo
diff --git a/testsuite/tests/deriving/should_compile/T13919.stderr b/testsuite/tests/deriving/should_compile/T13919.stderr
index e57fc77371..02cfb71aaa 100644
--- a/testsuite/tests/deriving/should_compile/T13919.stderr
+++ b/testsuite/tests/deriving/should_compile/T13919.stderr
@@ -1,3 +1,3 @@
T13919.hs:13:19: warning: [-Wunused-top-binds (in -Wextra, -Wunused-binds)]
- Defined but not used: ‘bar4’
+ Defined but not used: record field of Foo4 ‘bar4’
diff --git a/testsuite/tests/gadt/T18191.stderr b/testsuite/tests/gadt/T18191.stderr
index b8c6c60bdc..ce877d0332 100644
--- a/testsuite/tests/gadt/T18191.stderr
+++ b/testsuite/tests/gadt/T18191.stderr
@@ -1,20 +1,26 @@
T18191.hs:6:11: error:
- GADT constructor type signature cannot contain nested ‘forall’s or contexts
- In the definition of data constructor ‘MkT’
+ • GADT constructor type signature cannot contain nested ‘forall’s or contexts
+ • In the definition of data constructor ‘MkT’
T18191.hs:9:11: error:
- GADT constructor type signature cannot contain nested ‘forall’s or contexts
- In the definition of data constructor ‘MkS’
+ • GADT constructor type signature cannot contain nested ‘forall’s or contexts
+ • In the definition of data constructor ‘MkS’
T18191.hs:12:11: error:
- GADT constructor type signature cannot contain nested ‘forall’s or contexts
- In the definition of data constructor ‘MkU’
+ • GADT constructor type signature cannot contain nested ‘forall’s or contexts
+ • In the definition of data constructor ‘MkU’
T18191.hs:15:21: error:
- GADT constructor type signature cannot contain nested ‘forall’s or contexts
- In the definition of data constructor ‘MkZ1’
+ • GADT constructor type signature cannot contain nested ‘forall’s or contexts
+ • In the definition of data constructor ‘MkZ1’
+
+T18191.hs:15:31: error: [GHC-89246]
+ Record syntax is illegal here: {unZ1 :: (a, b)}
T18191.hs:16:19: error:
- GADT constructor type signature cannot contain nested ‘forall’s or contexts
- In the definition of data constructor ‘MkZ2’
+ • GADT constructor type signature cannot contain nested ‘forall’s or contexts
+ • In the definition of data constructor ‘MkZ2’
+
+T18191.hs:16:27: error: [GHC-89246]
+ Record syntax is illegal here: {unZ1 :: (a, b)}
diff --git a/testsuite/tests/ghci.debugger/scripts/break006.stderr b/testsuite/tests/ghci.debugger/scripts/break006.stderr
index 80419e9f35..705e9b359c 100644
--- a/testsuite/tests/ghci.debugger/scripts/break006.stderr
+++ b/testsuite/tests/ghci.debugger/scripts/break006.stderr
@@ -8,7 +8,7 @@
instance Show Ordering -- Defined in ‘GHC.Show’
instance Show a => Show (Maybe a) -- Defined in ‘GHC.Show’
...plus 25 others
- ...plus 12 instances involving out-of-scope types
+ ...plus 13 instances involving out-of-scope types
(use -fprint-potential-instances to see them all)
• In a stmt of an interactive GHCi command: print it
@@ -21,6 +21,6 @@
instance Show Ordering -- Defined in ‘GHC.Show’
instance Show a => Show (Maybe a) -- Defined in ‘GHC.Show’
...plus 25 others
- ...plus 12 instances involving out-of-scope types
+ ...plus 13 instances involving out-of-scope types
(use -fprint-potential-instances to see them all)
• In a stmt of an interactive GHCi command: print it
diff --git a/testsuite/tests/ghci.debugger/scripts/print019.stderr b/testsuite/tests/ghci.debugger/scripts/print019.stderr
index 0febc62927..ce45768335 100644
--- a/testsuite/tests/ghci.debugger/scripts/print019.stderr
+++ b/testsuite/tests/ghci.debugger/scripts/print019.stderr
@@ -8,6 +8,6 @@
instance Show Ordering -- Defined in ‘GHC.Show’
instance Show TyCon -- Defined in ‘GHC.Show’
...plus 32 others
- ...plus 13 instances involving out-of-scope types
+ ...plus 14 instances involving out-of-scope types
(use -fprint-potential-instances to see them all)
• In a stmt of an interactive GHCi command: print it
diff --git a/testsuite/tests/ghci/scripts/T22125.script b/testsuite/tests/ghci/scripts/T22125.script
new file mode 100644
index 0000000000..166d650dd9
--- /dev/null
+++ b/testsuite/tests/ghci/scripts/T22125.script
@@ -0,0 +1,6 @@
+:seti -XTypeFamilies -XDuplicateRecordFields -XDerivingStrategies
+data family D a
+data instance D Int = MkD0 | MkDInt { x :: Int, y :: Bool } deriving Show
+data instance D Bool = MkDBool { x :: Int }
+f r = r { y = True, x = 14 }
+f (MkDInt 3 False)
diff --git a/testsuite/tests/ghci/scripts/T22125.stdout b/testsuite/tests/ghci/scripts/T22125.stdout
new file mode 100644
index 0000000000..1a6c1af6ab
--- /dev/null
+++ b/testsuite/tests/ghci/scripts/T22125.stdout
@@ -0,0 +1 @@
+MkDInt {x = 14, y = True}
diff --git a/testsuite/tests/ghci/scripts/T23062.script b/testsuite/tests/ghci/scripts/T23062.script
new file mode 100644
index 0000000000..ee46726247
--- /dev/null
+++ b/testsuite/tests/ghci/scripts/T23062.script
@@ -0,0 +1,5 @@
+:seti -XDuplicateRecordFields -XDerivingStrategies
+data A = MkA { foo :: Int, bar :: Int } deriving stock Show
+data B = MkB { foo :: Int }
+f r = r { foo = 3, bar = 4 }
+f (MkA { foo = 2, bar = 3 })
diff --git a/testsuite/tests/ghci/scripts/T23062.stdout b/testsuite/tests/ghci/scripts/T23062.stdout
new file mode 100644
index 0000000000..fe41ddb4e5
--- /dev/null
+++ b/testsuite/tests/ghci/scripts/T23062.stdout
@@ -0,0 +1 @@
+MkA {foo = 3, bar = 4}
diff --git a/testsuite/tests/ghci/scripts/all.T b/testsuite/tests/ghci/scripts/all.T
index fa22b7ae8d..90c3b05514 100755
--- a/testsuite/tests/ghci/scripts/all.T
+++ b/testsuite/tests/ghci/scripts/all.T
@@ -370,6 +370,8 @@ test('T21110', [extra_files(['T21110A.hs'])], ghci_script,
test('T17830', [filter_stdout_lines(r'======.*')], ghci_script, ['T17830.script'])
test('T21294a', normal, ghci_script, ['T21294a.script'])
test('T21507', normal, ghci_script, ['T21507.script'])
+test('T22125', normal, ghci_script, ['T22125.script'])
test('T22695', normal, ghci_script, ['T22695.script'])
test('T22817', normal, ghci_script, ['T22817.script'])
test('T22908', normal, ghci_script, ['T22908.script'])
+test('T23062', normal, ghci_script, ['T23062.script'])
diff --git a/testsuite/tests/ghci/scripts/ghci065.stdout b/testsuite/tests/ghci/scripts/ghci065.stdout
index e4048832cc..543a6caf20 100644
--- a/testsuite/tests/ghci/scripts/ghci065.stdout
+++ b/testsuite/tests/ghci/scripts/ghci065.stdout
@@ -9,13 +9,13 @@ Data3 :: * -- Type constructor defined at ghci065.hs:20:1
Data4 :: Int -> Data4
-- Data constructor defined at ghci065.hs:25:3
-- | This is the haddock comment of a data constructor for Data4.
-dupeField :: DupeFields2 -> Int
- -- Identifier defined at ghci065.hs:32:9
--- ^ This is the second haddock comment of a duplicate record field.
-
dupeField :: DupeFields1 -> Int
-- Identifier defined at ghci065.hs:28:9
-- ^ This is the first haddock comment of a duplicate record field.
+
+dupeField :: DupeFields2 -> Int
+ -- Identifier defined at ghci065.hs:32:9
+-- ^ This is the second haddock comment of a duplicate record field.
func1 :: Int -> Int -> Int
-- Identifier defined at ghci065.hs:41:1
-- | This is the haddock comment of a function declaration for func1.
diff --git a/testsuite/tests/linters/notes.stdout b/testsuite/tests/linters/notes.stdout
index 0a8b2161fe..51fef76584 100644
--- a/testsuite/tests/linters/notes.stdout
+++ b/testsuite/tests/linters/notes.stdout
@@ -6,48 +6,43 @@ ref compiler/GHC/Core/Opt/Simplify/Iteration.hs:4009:8: Note [Lambda-boun
ref compiler/GHC/Core/Opt/Simplify/Utils.hs:1343:37: Note [Gentle mode]
ref compiler/GHC/Core/Opt/Specialise.hs:1790:28: Note [Arity decrease]
ref compiler/GHC/Core/TyCo/Rep.hs:1556:31: Note [What prevents a constraint from floating]
-ref compiler/GHC/Driver/Main.hs:1761:34: Note [simpleTidyPgm - mkBootModDetailsTc]
-ref compiler/GHC/Driver/Session.hs:3976:49: Note [Eta-reduction in -O0]
-ref compiler/GHC/Hs/Expr.hs:191:63: Note [Pending Splices]
-ref compiler/GHC/Hs/Expr.hs:1706:87: Note [Lifecycle of a splice]
-ref compiler/GHC/Hs/Expr.hs:1742:7: Note [Pending Splices]
+ref compiler/GHC/Driver/Main.hs:1762:34: Note [simpleTidyPgm - mkBootModDetailsTc]
+ref compiler/GHC/Driver/Session.hs:3993:49: Note [Eta-reduction in -O0]
+ref compiler/GHC/Hs/Expr.hs:194:63: Note [Pending Splices]
+ref compiler/GHC/Hs/Expr.hs:1736:87: Note [Lifecycle of a splice]
+ref compiler/GHC/Hs/Expr.hs:1772:7: Note [Pending Splices]
ref compiler/GHC/Hs/Extension.hs:146:5: Note [Strict argument type constraints]
ref compiler/GHC/Hs/Pat.hs:143:74: Note [Lifecycle of a splice]
ref compiler/GHC/HsToCore/Pmc/Solver.hs:858:20: Note [COMPLETE sets on data families]
ref compiler/GHC/HsToCore/Quote.hs:1476:7: Note [How brackets and nested splices are handled]
-ref compiler/GHC/Rename/Pat.hs:890:29: Note [Disambiguating record fields]
ref compiler/GHC/Stg/Unarise.hs:442:32: Note [Renaming during unarisation]
ref compiler/GHC/StgToCmm.hs:106:18: Note [codegen-split-init]
ref compiler/GHC/StgToCmm.hs:109:18: Note [pipeline-split-init]
ref compiler/GHC/StgToCmm/Expr.hs:585:4: Note [case on bool]
ref compiler/GHC/StgToCmm/Expr.hs:853:3: Note [alg-alt heap check]
-ref compiler/GHC/Tc/Gen/Expr.hs:1212:23: Note [Disambiguating record fields]
-ref compiler/GHC/Tc/Gen/Expr.hs:1427:7: Note [Disambiguating record fields]
-ref compiler/GHC/Tc/Gen/Expr.hs:1530:11: Note [Deprecating ambiguous fields]
-ref compiler/GHC/Tc/Gen/HsType.hs:557:56: Note [Skolem escape prevention]
-ref compiler/GHC/Tc/Gen/HsType.hs:2622:7: Note [Matching a kind signature with a declaration]
+ref compiler/GHC/Tc/Gen/HsType.hs:556:56: Note [Skolem escape prevention]
+ref compiler/GHC/Tc/Gen/HsType.hs:2621:7: Note [Matching a kind signature with a declaration]
ref compiler/GHC/Tc/Gen/Pat.hs:176:20: Note [Typing patterns in pattern bindings]
ref compiler/GHC/Tc/Gen/Pat.hs:1127:7: Note [Matching polytyped patterns]
ref compiler/GHC/Tc/Gen/Sig.hs:81:10: Note [Overview of type signatures]
-ref compiler/GHC/Tc/Gen/Splice.hs:359:16: Note [How brackets and nested splices are handled]
-ref compiler/GHC/Tc/Gen/Splice.hs:534:35: Note [PendingRnSplice]
-ref compiler/GHC/Tc/Gen/Splice.hs:658:7: Note [How brackets and nested splices are handled]
-ref compiler/GHC/Tc/Gen/Splice.hs:891:11: Note [How brackets and nested splices are handled]
+ref compiler/GHC/Tc/Gen/Splice.hs:357:16: Note [How brackets and nested splices are handled]
+ref compiler/GHC/Tc/Gen/Splice.hs:532:35: Note [PendingRnSplice]
+ref compiler/GHC/Tc/Gen/Splice.hs:656:7: Note [How brackets and nested splices are handled]
+ref compiler/GHC/Tc/Gen/Splice.hs:889:11: Note [How brackets and nested splices are handled]
ref compiler/GHC/Tc/Instance/Family.hs:474:35: Note [Constrained family instances]
-ref compiler/GHC/Tc/Module.hs:708:15: Note [Extra dependencies from .hs-boot files]
+ref compiler/GHC/Tc/Module.hs:711:15: Note [Extra dependencies from .hs-boot files]
ref compiler/GHC/Tc/Solver/Rewrite.hs:1008:7: Note [Stability of rewriting]
-ref compiler/GHC/Tc/TyCl.hs:1119:6: Note [Unification variables need fresh Names]
-ref compiler/GHC/Tc/Types.hs:697:33: Note [Extra dependencies from .hs-boot files]
-ref compiler/GHC/Tc/Types.hs:1428:47: Note [Care with plugin imports]
-ref compiler/GHC/Tc/Types/Constraint.hs:223:34: Note [NonCanonical Semantics]
+ref compiler/GHC/Tc/TyCl.hs:1120:6: Note [Unification variables need fresh Names]
+ref compiler/GHC/Tc/Types.hs:692:33: Note [Extra dependencies from .hs-boot files]
+ref compiler/GHC/Tc/Types.hs:1423:47: Note [Care with plugin imports]
+ref compiler/GHC/Tc/Types/Constraint.hs:255:34: Note [NonCanonical Semantics]
ref compiler/GHC/Types/Demand.hs:306:25: Note [Preserving Boxity of results is rarely a win]
ref compiler/GHC/Unit/Module/Deps.hs:81:13: Note [Structure of dep_boot_mods]
-ref compiler/GHC/Utils/Monad.hs:400:34: Note [multiShotIO]
+ref compiler/GHC/Utils/Monad.hs:410:34: Note [multiShotIO]
ref compiler/Language/Haskell/Syntax/Binds.hs:200:31: Note [fun_id in Match]
-ref compiler/Language/Haskell/Syntax/Pat.hs:356:12: Note [Disambiguating record fields]
ref configure.ac:210:10: Note [Linking ghc-bin against threaded stage0 RTS]
ref docs/core-spec/core-spec.mng:177:6: Note [TyBinders]
-ref hadrian/src/Expression.hs:134:30: Note [Linking ghc-bin against threaded stage0 RTS]
+ref hadrian/src/Expression.hs:145:30: Note [Linking ghc-bin against threaded stage0 RTS]
ref linters/lint-notes/Notes.hs:32:29: Note [" <> T.unpack x <> "]
ref linters/lint-notes/Notes.hs:69:22: Note [...]
ref testsuite/config/ghc:272:10: Note [WayFlags]
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
diff --git a/testsuite/tests/overloadedrecflds/should_compile/BootFldReexport.hs b/testsuite/tests/overloadedrecflds/should_compile/BootFldReexport.hs
new file mode 100644
index 0000000000..a0e527f1b3
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_compile/BootFldReexport.hs
@@ -0,0 +1,8 @@
+module BootFldReexport where
+
+import {-# SOURCE #-} BootFldReexport_N
+ ( fld {- variable -} )
+import BootFldReexport_O
+ ( fld {- record field -} )
+
+test3 = fld
diff --git a/testsuite/tests/overloadedrecflds/should_compile/BootFldReexport.stderr b/testsuite/tests/overloadedrecflds/should_compile/BootFldReexport.stderr
new file mode 100644
index 0000000000..0830beb7fc
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_compile/BootFldReexport.stderr
@@ -0,0 +1,11 @@
+
+BootFldReexport.hs:8:9: error:
+ Ambiguous occurrence ‘fld’
+ It could refer to
+ either ‘BootFldReexport_N.fld’,
+ imported from ‘BootFldReexport_N’ at BootFldReexport.hs:4:5-7
+ (and originally defined in ‘BootFldReexport_O’
+ at BootFldReexport_O.hs-boot:4:1-13)
+ or the field ‘fld’ of record ‘BootFldReexport_O.O’,
+ imported from ‘BootFldReexport_O’ at BootFldReexport.hs:6:5-7
+ (and originally defined at BootFldReexport_O.hs:5:16-18)
diff --git a/testsuite/tests/overloadedrecflds/should_compile/BootFldReexport_B.hs b/testsuite/tests/overloadedrecflds/should_compile/BootFldReexport_B.hs
new file mode 100644
index 0000000000..8d8024313c
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_compile/BootFldReexport_B.hs
@@ -0,0 +1,5 @@
+module BootFldReexport_B where
+
+import {-# SOURCE #-} BootFldReexport_N
+
+test2 = fld
diff --git a/testsuite/tests/overloadedrecflds/should_compile/BootFldReexport_N.hs b/testsuite/tests/overloadedrecflds/should_compile/BootFldReexport_N.hs
new file mode 100644
index 0000000000..8a28e3705c
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_compile/BootFldReexport_N.hs
@@ -0,0 +1,5 @@
+module BootFldReexport_N ( module BootFldReexport_O ) where
+import BootFldReexport_O
+import BootFldReexport
+
+test1 = fld
diff --git a/testsuite/tests/overloadedrecflds/should_compile/BootFldReexport_N.hs-boot b/testsuite/tests/overloadedrecflds/should_compile/BootFldReexport_N.hs-boot
new file mode 100644
index 0000000000..49c9c7c996
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_compile/BootFldReexport_N.hs-boot
@@ -0,0 +1,2 @@
+module BootFldReexport_N ( module BootFldReexport_O ) where
+import {-# SOURCE #-} BootFldReexport_O \ No newline at end of file
diff --git a/testsuite/tests/overloadedrecflds/should_compile/BootFldReexport_O.hs b/testsuite/tests/overloadedrecflds/should_compile/BootFldReexport_O.hs
new file mode 100644
index 0000000000..733f7e3ed6
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_compile/BootFldReexport_O.hs
@@ -0,0 +1,5 @@
+module BootFldReexport_O where
+
+import BootFldReexport_B
+
+data O = MkO { fld :: O }
diff --git a/testsuite/tests/overloadedrecflds/should_compile/BootFldReexport_O.hs-boot b/testsuite/tests/overloadedrecflds/should_compile/BootFldReexport_O.hs-boot
new file mode 100644
index 0000000000..617ec6fb90
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_compile/BootFldReexport_O.hs-boot
@@ -0,0 +1,4 @@
+module BootFldReexport_O where
+
+data O
+fld :: O -> O
diff --git a/testsuite/tests/overloadedrecflds/should_compile/DupFldFixity1.hs b/testsuite/tests/overloadedrecflds/should_compile/DupFldFixity1.hs
new file mode 100644
index 0000000000..58e7afe673
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_compile/DupFldFixity1.hs
@@ -0,0 +1,9 @@
+
+
+{-# LANGUAGE DuplicateRecordFields #-}
+
+module DupFldFixity1 where
+
+data A = MkA { fld :: A -> A }
+
+infixr 4 `fld`
diff --git a/testsuite/tests/overloadedrecflds/should_compile/DupFldFixity2.hs b/testsuite/tests/overloadedrecflds/should_compile/DupFldFixity2.hs
new file mode 100644
index 0000000000..85811c3b0f
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_compile/DupFldFixity2.hs
@@ -0,0 +1,12 @@
+
+{-# LANGUAGE NoFieldSelectors #-}
+
+module DupFldFixity2 where
+
+data A = MkA { fld :: A -> A }
+data B
+
+fld :: B -> B -> B
+fld x _ = x
+
+infixr 4 `fld`
diff --git a/testsuite/tests/overloadedrecflds/should_compile/DupFldFixity3.hs b/testsuite/tests/overloadedrecflds/should_compile/DupFldFixity3.hs
new file mode 100644
index 0000000000..73d8490d57
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_compile/DupFldFixity3.hs
@@ -0,0 +1,9 @@
+
+{-# LANGUAGE DuplicateRecordFields #-}
+
+module DupFldFixity3 where
+
+data A = MkA { fld :: A -> A }
+data B = MkB { fld :: A -> A }
+
+infixr 4 `fld`
diff --git a/testsuite/tests/overloadedrecflds/should_compile/NoDRFModuleExport.hs b/testsuite/tests/overloadedrecflds/should_compile/NoDRFModuleExport.hs
new file mode 100644
index 0000000000..11a21af800
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_compile/NoDRFModuleExport.hs
@@ -0,0 +1,6 @@
+-- Test that we can re-export a module defining
+-- duplicate record fields, without ourselves enabling
+-- the DuplicateRecordFields extension.
+
+module NoDRFModuleExport ( module NoDRFModuleExport_aux ) where
+ import NoDRFModuleExport_aux
diff --git a/testsuite/tests/overloadedrecflds/should_compile/NoDRFModuleExport_aux.hs b/testsuite/tests/overloadedrecflds/should_compile/NoDRFModuleExport_aux.hs
new file mode 100644
index 0000000000..4720fdd547
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_compile/NoDRFModuleExport_aux.hs
@@ -0,0 +1,4 @@
+{-# LANGUAGE DuplicateRecordFields #-}
+module NoDRFModuleExport_aux where
+ data A = MkA { foo :: A }
+ data B = MkB { foo :: B }
diff --git a/testsuite/tests/overloadedrecflds/should_compile/OverloadedRecFlds10_A.hs b/testsuite/tests/overloadedrecflds/should_compile/OverloadedRecFlds10_A.hs
new file mode 100644
index 0000000000..ae25153621
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_compile/OverloadedRecFlds10_A.hs
@@ -0,0 +1,5 @@
+{-# LANGUAGE TypeFamilies #-}
+module OverloadedRecFlds10_A where
+
+data family F a
+data instance F Int = MkFInt { foo :: Int }
diff --git a/testsuite/tests/overloadedrecflds/should_compile/OverloadedRecFlds10_B.hs b/testsuite/tests/overloadedrecflds/should_compile/OverloadedRecFlds10_B.hs
new file mode 100644
index 0000000000..0f7be47880
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_compile/OverloadedRecFlds10_B.hs
@@ -0,0 +1,6 @@
+{-# LANGUAGE TypeFamilies #-}
+module OverloadedRecFlds10_B (F(..)) where
+
+import OverloadedRecFlds10_A hiding (foo)
+
+data instance F Bool = MkFBool { foo :: Int }
diff --git a/testsuite/tests/overloadedrecflds/should_compile/OverloadedRecFlds10_C.hs b/testsuite/tests/overloadedrecflds/should_compile/OverloadedRecFlds10_C.hs
new file mode 100644
index 0000000000..29c4863334
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_compile/OverloadedRecFlds10_C.hs
@@ -0,0 +1,6 @@
+{-# LANGUAGE DuplicateRecordFields, TypeFamilies #-}
+module OverloadedRecFlds10_C (F(..)) where
+
+import OverloadedRecFlds10_A
+
+data instance F Char = MkFChar { foo :: Char }
diff --git a/testsuite/tests/overloadedrecflds/should_fail/T11103.hs b/testsuite/tests/overloadedrecflds/should_compile/T11103.hs
index 2791dc4fca..6662b29cfa 100644
--- a/testsuite/tests/overloadedrecflds/should_fail/T11103.hs
+++ b/testsuite/tests/overloadedrecflds/should_compile/T11103.hs
@@ -1,9 +1,7 @@
--- When using DuplicateRecordFields with TemplateHaskell, it is not possible to
--- reify ambiguous names that are output by reifying field labels.
--- See also overloadedrecflds/should_run/overloadedrecfldsrun04.hs
-
{-# LANGUAGE DuplicateRecordFields, TemplateHaskell #-}
+module T11103 where
+
import Language.Haskell.TH
import Language.Haskell.TH.Syntax
diff --git a/testsuite/tests/overloadedrecflds/should_compile/T13352.hs b/testsuite/tests/overloadedrecflds/should_compile/T13352.hs
new file mode 100644
index 0000000000..9d85b725b6
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_compile/T13352.hs
@@ -0,0 +1,4 @@
+{-# LANGUAGE DuplicateRecordFields #-}
+module T13352 (S(foo), T(foo)) where
+ import T13352_A (S(..))
+ import T13352_B (T(..))
diff --git a/testsuite/tests/overloadedrecflds/should_compile/T13352_A.hs b/testsuite/tests/overloadedrecflds/should_compile/T13352_A.hs
new file mode 100644
index 0000000000..2639b4bb38
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_compile/T13352_A.hs
@@ -0,0 +1,2 @@
+module T13352_A where
+ data S = MkS { foo :: Int }
diff --git a/testsuite/tests/overloadedrecflds/should_compile/T13352_B.hs b/testsuite/tests/overloadedrecflds/should_compile/T13352_B.hs
new file mode 100644
index 0000000000..b04cd1168f
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_compile/T13352_B.hs
@@ -0,0 +1,2 @@
+module T13352_B where
+ data T = MkT { foo :: Int }
diff --git a/testsuite/tests/overloadedrecflds/should_compile/T13352_hard.hs b/testsuite/tests/overloadedrecflds/should_compile/T13352_hard.hs
new file mode 100644
index 0000000000..982305e71d
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_compile/T13352_hard.hs
@@ -0,0 +1,4 @@
+{-# LANGUAGE DuplicateRecordFields #-}
+module T13352_hard (S(foo), T(foo)) where
+ import T13352_hard_A (S(..))
+ import T13352_hard_B (T(..))
diff --git a/testsuite/tests/overloadedrecflds/should_compile/T13352_hard.stderr b/testsuite/tests/overloadedrecflds/should_compile/T13352_hard.stderr
new file mode 100644
index 0000000000..bd4bf93121
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_compile/T13352_hard.stderr
@@ -0,0 +1,9 @@
+
+T13352_hard.hs:2:29: error: [GHC-69158]
+ Conflicting exports for ‘foo’:
+ ‘S(foo)’ exports ‘T13352_hard_A.foo’
+ imported from ‘T13352_hard_A’ at T13352_hard.hs:3:25-29
+ (and originally defined at T13352_hard_A.hs:3:16-18)
+ ‘T(foo)’ exports ‘T13352_hard_B.foo’
+ imported from ‘T13352_hard_B’ at T13352_hard.hs:4:25-29
+ (and originally defined at T13352_hard_B.hs:3:16-18)
diff --git a/testsuite/tests/overloadedrecflds/should_compile/T13352_hard_A.hs b/testsuite/tests/overloadedrecflds/should_compile/T13352_hard_A.hs
new file mode 100644
index 0000000000..3fcba12280
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_compile/T13352_hard_A.hs
@@ -0,0 +1,3 @@
+{-# LANGUAGE DuplicateRecordFields #-}
+module T13352_hard_A where
+ data S = C { foo :: Int }
diff --git a/testsuite/tests/overloadedrecflds/should_compile/T13352_hard_B.hs b/testsuite/tests/overloadedrecflds/should_compile/T13352_hard_B.hs
new file mode 100644
index 0000000000..7271dda542
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_compile/T13352_hard_B.hs
@@ -0,0 +1,3 @@
+{-# LANGUAGE DuplicateRecordFields #-}
+module T13352_hard_B where
+ data T = C { foo :: Int }
diff --git a/testsuite/tests/overloadedrecflds/should_compile/T14848.hs b/testsuite/tests/overloadedrecflds/should_compile/T14848.hs
new file mode 100644
index 0000000000..f19ebbecca
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_compile/T14848.hs
@@ -0,0 +1,10 @@
+{-# language TemplateHaskell #-}
+{-# language DuplicateRecordFields #-}
+
+module T14848 where
+import Language.Haskell.TH
+import Language.Haskell.TH.Syntax
+
+data A = A {x :: Int, y :: String}
+a = A 3 "test"
+test = $([e|case a of A {x = b} -> b|])
diff --git a/testsuite/tests/overloadedrecflds/should_compile/T17551.hs b/testsuite/tests/overloadedrecflds/should_compile/T17551.hs
new file mode 100644
index 0000000000..8fe5d9f808
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_compile/T17551.hs
@@ -0,0 +1,15 @@
+{-# LANGUAGE DuplicateRecordFields #-}
+{-# LANGUAGE TemplateHaskell #-}
+
+module T17551 where
+
+import Language.Haskell.TH
+
+data Foo = Foo { foo :: Int }
+data Bar = Bar { foo :: Int }
+
+$(do
+ TyConI (DataD _ _ _ _ [RecC con [(field, _, _)]] _) <- reify ''Bar
+ reify field
+ pure []
+ )
diff --git a/testsuite/tests/overloadedrecflds/should_compile/T21720.hs b/testsuite/tests/overloadedrecflds/should_compile/T21720.hs
new file mode 100644
index 0000000000..072bde217a
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_compile/T21720.hs
@@ -0,0 +1,18 @@
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE DuplicateRecordFields #-}
+{-# OPTIONS_GHC -dcore-lint #-}
+
+module T21720 where
+
+import Language.Haskell.TH
+
+main :: IO ()
+main = pure ()
+
+$(do
+ let noBang = Bang NoSourceUnpackedness NoSourceStrictness
+ let mkData tn cn fn = DataD [] tn [] Nothing [RecC cn [(fn, noBang, ConT ''Integer)]] []
+ r1 <- mkData <$> newName "R1" <*> newName "C1" <*> newName "f"
+ r2 <- mkData <$> newName "R2" <*> newName "C2" <*> newName "f"
+ pure [r1,r2]
+ )
diff --git a/testsuite/tests/overloadedrecflds/should_compile/T21898.hs b/testsuite/tests/overloadedrecflds/should_compile/T21898.hs
new file mode 100644
index 0000000000..b7b0b051e8
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_compile/T21898.hs
@@ -0,0 +1,15 @@
+{-# LANGUAGE DuplicateRecordFields, PatternSynonyms #-}
+
+module T21898 where
+
+pattern P :: Int -> Int -> (Int, Int)
+pattern P { proj_x, proj_y } = (proj_x, proj_y)
+
+pattern Q1 :: Int -> Int
+pattern Q1 { proj_x } = proj_x
+
+pattern Q2 :: Int -> Int
+pattern Q2 { proj_y } = proj_y
+
+blah :: (Int, Int) -> (Int, Int)
+blah p = p { proj_x = 0, proj_y = 1 }
diff --git a/testsuite/tests/overloadedrecflds/should_compile/T22160.hs b/testsuite/tests/overloadedrecflds/should_compile/T22160.hs
new file mode 100644
index 0000000000..28aaa3c735
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_compile/T22160.hs
@@ -0,0 +1,9 @@
+{-# LANGUAGE DisambiguateRecordFields #-}
+
+module T22160 where
+
+import T22160_A
+import T22160_B
+import T22160_C
+
+eg r = r { x = 1, y = 1 }
diff --git a/testsuite/tests/overloadedrecflds/should_compile/T22160_A.hs b/testsuite/tests/overloadedrecflds/should_compile/T22160_A.hs
new file mode 100644
index 0000000000..341df010ba
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_compile/T22160_A.hs
@@ -0,0 +1,3 @@
+module T22160_A where
+
+data A = MkA { x :: Int }
diff --git a/testsuite/tests/overloadedrecflds/should_compile/T22160_B.hs b/testsuite/tests/overloadedrecflds/should_compile/T22160_B.hs
new file mode 100644
index 0000000000..2da5511e6c
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_compile/T22160_B.hs
@@ -0,0 +1,3 @@
+module T22160_B where
+
+data B = MkB { y :: Int }
diff --git a/testsuite/tests/overloadedrecflds/should_compile/T22160_C.hs b/testsuite/tests/overloadedrecflds/should_compile/T22160_C.hs
new file mode 100644
index 0000000000..450463e0a6
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_compile/T22160_C.hs
@@ -0,0 +1,3 @@
+module T22160_C where
+
+data C = MkC { x, y :: Int }
diff --git a/testsuite/tests/overloadedrecflds/should_compile/T23010.hs b/testsuite/tests/overloadedrecflds/should_compile/T23010.hs
new file mode 100644
index 0000000000..7ae1ff5f98
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_compile/T23010.hs
@@ -0,0 +1,8 @@
+{-# LANGUAGE DuplicateRecordFields #-}
+
+module T23010 ( A(..) ) where
+
+import T23010_aux ( X )
+
+data A = MkA { fld :: A, other :: X }
+data B = MkB { fld :: B }
diff --git a/testsuite/tests/overloadedrecflds/should_compile/T23010.hs-boot b/testsuite/tests/overloadedrecflds/should_compile/T23010.hs-boot
new file mode 100644
index 0000000000..ea72bd20f6
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_compile/T23010.hs-boot
@@ -0,0 +1,7 @@
+{-# LANGUAGE DuplicateRecordFields #-}
+
+module T23010 where
+
+data A
+
+fld :: A -> A
diff --git a/testsuite/tests/overloadedrecflds/should_compile/T23010_aux.hs b/testsuite/tests/overloadedrecflds/should_compile/T23010_aux.hs
new file mode 100644
index 0000000000..1f1280b26a
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_compile/T23010_aux.hs
@@ -0,0 +1,8 @@
+{-# LANGUAGE DuplicateRecordFields #-}
+
+module T23010_aux where
+
+import {-# SOURCE #-} T23010 ( fld )
+
+data X
+bar = fld
diff --git a/testsuite/tests/overloadedrecflds/should_compile/all.T b/testsuite/tests/overloadedrecflds/should_compile/all.T
index 9d49752f2b..000fd696e4 100644
--- a/testsuite/tests/overloadedrecflds/should_compile/all.T
+++ b/testsuite/tests/overloadedrecflds/should_compile/all.T
@@ -12,3 +12,38 @@ test('T19154', normal, compile, [''])
test('T20723', normal, compile, [''])
test('T20989', normal, compile, [''])
test('T21625', [], multimod_compile, ['T21625', '-v0'])
+test('DupFldFixity1', normal, compile, [''])
+test('DupFldFixity2', normal, compile, [''])
+test('T23010', [extra_files(['T23010.hs-boot', 'T23010_aux.hs'])]
+ , multimod_compile
+ , ['T23010', '-v0'])
+test('T14848', req_th, compile, [''])
+test('T17551', req_th, compile, [''])
+test('T11103', req_th, compile, [''])
+test('T13352'
+ , [extra_files(['T13352_A.hs', 'T13352_B.hs'])]
+ , multimod_compile, ['T13352_A T13352_B T13352', '-v0'])
+test('T13352_hard'
+ , [extra_files(['T13352_hard_A.hs', 'T13352_hard_B.hs'])]
+ , multimod_compile_fail, ['T13352_hard_A T13352_hard_B T13352_hard', '-v0'])
+test('T21720', req_th, compile, [''])
+test('T21898', normal, compile, [''])
+test('T22160', [extra_files(['T22160_A.hs', 'T22160_B.hs', 'T22160_C.hs'])]
+ , multimod_compile, ['T22160_A T22160_B T22160_C T22160', '-v0'])
+test('DupFldFixity3', normal, compile, [''])
+test('overloadedrecflds10'
+ , [extra_files(['OverloadedRecFlds10_A.hs', 'OverloadedRecFlds10_B.hs', 'OverloadedRecFlds10_C.hs'])]
+ , multimod_compile
+ , ['overloadedrecflds10', '-v0'])
+test('NoDRFModuleExport'
+ , [extra_files(['NoDRFModuleExport_aux.hs'])]
+ , multimod_compile
+ , ['NoDRFModuleExport', '-v0'])
+test('BootFldReexport'
+ , [extra_files([ 'BootFldReexport_N.hs', 'BootFldReexport_N.hs-boot'
+ , 'BootFldReexport_O.hs', 'BootFldReexport_O.hs-boot'
+ , 'BootFldReexport_B.hs' ])]
+ , multimod_compile_fail
+ # Should either pass or give an ambiguity error when compiling
+ # the final module (BootFldReexport), but not fail earlier.
+ , ['BootFldReexport', '-v0'])
diff --git a/testsuite/tests/overloadedrecflds/should_compile/overloadedrecflds10.hs b/testsuite/tests/overloadedrecflds/should_compile/overloadedrecflds10.hs
new file mode 100644
index 0000000000..c85d303d0e
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_compile/overloadedrecflds10.hs
@@ -0,0 +1,7 @@
+{-# LANGUAGE DuplicateRecordFields #-}
+module Main (main, F(..)) where
+
+import OverloadedRecFlds10_B
+import OverloadedRecFlds10_C
+
+main = return ()
diff --git a/testsuite/tests/overloadedrecflds/should_fail/DRF9156.stderr b/testsuite/tests/overloadedrecflds/should_fail/DRF9156.stderr
index ea1d10dc10..5e18bdf59a 100644
--- a/testsuite/tests/overloadedrecflds/should_fail/DRF9156.stderr
+++ b/testsuite/tests/overloadedrecflds/should_fail/DRF9156.stderr
@@ -1,5 +1,3 @@
-DRF9156.hs:4:19: error:
- Multiple declarations of ‘f1’
- Declared at: DRF9156.hs:3:15
- DRF9156.hs:4:19
+DRF9156.hs:4:19: error: [GHC-85524]
+ Duplicate field name ‘f1’ in record declaration
diff --git a/testsuite/tests/overloadedrecflds/should_fail/DRFHoleFits.stderr b/testsuite/tests/overloadedrecflds/should_fail/DRFHoleFits.stderr
index 61779352c3..1fb78b2175 100644
--- a/testsuite/tests/overloadedrecflds/should_fail/DRFHoleFits.stderr
+++ b/testsuite/tests/overloadedrecflds/should_fail/DRFHoleFits.stderr
@@ -1,5 +1,3 @@
-[1 of 2] Compiling DRFHoleFits_A ( DRFHoleFits_A.hs, DRFHoleFits_A.o )
-[2 of 2] Compiling DRFHoleFits ( DRFHoleFits.hs, DRFHoleFits.o )
DRFHoleFits.hs:7:7: error: [GHC-88464]
• Found hole: _ :: T -> Int
@@ -19,6 +17,6 @@ DRFHoleFits.hs:8:7: error: [GHC-88464]
baz :: A.S -> Int (bound at DRFHoleFits.hs:8:1)
Valid hole fits include
baz :: A.S -> Int (defined at DRFHoleFits.hs:8:1)
- DRFHoleFits_A.foo :: A.S -> Int
+ A.foo :: A.S -> Int
(imported qualified from ‘DRFHoleFits_A’ at DRFHoleFits.hs:3:1-35
(and originally defined at DRFHoleFits_A.hs:5:16-18))
diff --git a/testsuite/tests/overloadedrecflds/should_fail/DRFUnused.stderr b/testsuite/tests/overloadedrecflds/should_fail/DRFUnused.stderr
index e020e8cd82..88e9e6537f 100644
--- a/testsuite/tests/overloadedrecflds/should_fail/DRFUnused.stderr
+++ b/testsuite/tests/overloadedrecflds/should_fail/DRFUnused.stderr
@@ -2,6 +2,6 @@
DRFUnused.hs:18:5: error:
Ambiguous occurrence ‘foo’
It could refer to
- either the field ‘foo’ of record ‘U’, defined at DRFUnused.hs:12:16
+ either the field ‘foo’ of record ‘S’, defined at DRFUnused.hs:10:16
or the field ‘foo’ of record ‘T’, defined at DRFUnused.hs:11:16
- or the field ‘foo’ of record ‘S’, defined at DRFUnused.hs:10:16
+ or the field ‘foo’ of record ‘U’, defined at DRFUnused.hs:12:16
diff --git a/testsuite/tests/overloadedrecflds/should_fail/NFS9156.stderr b/testsuite/tests/overloadedrecflds/should_fail/NFS9156.stderr
index 66ab58fcbd..c735f618e8 100644
--- a/testsuite/tests/overloadedrecflds/should_fail/NFS9156.stderr
+++ b/testsuite/tests/overloadedrecflds/should_fail/NFS9156.stderr
@@ -1,5 +1,3 @@
-NFS9156.hs:4:19: error:
- Multiple declarations of ‘f1’
- Declared at: NFS9156.hs:3:15
- NFS9156.hs:4:19
+NFS9156.hs:4:19: error: [GHC-85524]
+ Duplicate field name ‘f1’ in record declaration
diff --git a/testsuite/tests/overloadedrecflds/should_fail/NFSExport.hs b/testsuite/tests/overloadedrecflds/should_fail/NFSExport.hs
index 839b32bae4..86c21c2dcf 100644
--- a/testsuite/tests/overloadedrecflds/should_fail/NFSExport.hs
+++ b/testsuite/tests/overloadedrecflds/should_fail/NFSExport.hs
@@ -1,3 +1,3 @@
{-# LANGUAGE NoFieldSelectors #-}
module NFSExport (T(foo), foo) where -- only T(foo) is supported
-data T = MkT { foo :: Bool }
+data T = MkT { foo :: T }
diff --git a/testsuite/tests/overloadedrecflds/should_fail/NFSMixed.hs b/testsuite/tests/overloadedrecflds/should_fail/NFSMixed.hs
index d2b3d8dd1b..05ddc0cd39 100644
--- a/testsuite/tests/overloadedrecflds/should_fail/NFSMixed.hs
+++ b/testsuite/tests/overloadedrecflds/should_fail/NFSMixed.hs
@@ -1,3 +1,5 @@
+{-# LANGUAGE DisambiguateRecordFields #-}
+
module NFSMixed where
import NFSMixedA
diff --git a/testsuite/tests/overloadedrecflds/should_fail/NFSMixed.stderr b/testsuite/tests/overloadedrecflds/should_fail/NFSMixed.stderr
index 0419feb764..3f50bfe597 100644
--- a/testsuite/tests/overloadedrecflds/should_fail/NFSMixed.stderr
+++ b/testsuite/tests/overloadedrecflds/should_fail/NFSMixed.stderr
@@ -1,13 +1,7 @@
-NFSMixed.hs:5:18: error:
- Ambiguous occurrence ‘foo’
- It could refer to
- either the field ‘foo’ of record ‘Foo’,
- imported from ‘NFSMixedA’ at NFSMixed.hs:3:1-16
- (and originally defined at NFSMixedA.hs:4:18-20)
- or the field ‘foo’ of record ‘Bar’,
- imported from ‘NFSMixedA’ at NFSMixed.hs:3:1-16
- (and originally defined at NFSMixedA.hs:5:18-20)
- or ‘NFSMixedA.foo’,
- imported from ‘NFSMixedA’ at NFSMixed.hs:3:1-16
- (and originally defined at NFSMixedA.hs:8:1-3)
+NFSMixed.hs:7:14: error: [GHC-99339]
+ • Ambiguous record update with field ‘foo’
+ This field appears in both datatypes ‘Foo’ and ‘Bar’
+ • In the expression: x {foo = 0}
+ In the expression: \ x -> x {foo = 0}
+ In an equation for ‘test’: test = \ x -> x {foo = 0}
diff --git a/testsuite/tests/overloadedrecflds/should_fail/NoFieldSelectorsFail.stderr b/testsuite/tests/overloadedrecflds/should_fail/NoFieldSelectorsFail.stderr
index 6810d549ff..301b6bc4b8 100644
--- a/testsuite/tests/overloadedrecflds/should_fail/NoFieldSelectorsFail.stderr
+++ b/testsuite/tests/overloadedrecflds/should_fail/NoFieldSelectorsFail.stderr
@@ -9,32 +9,35 @@ NoFieldSelectorsFail.hs:9:14: error:
imported from ‘NoFieldSelectorsFailA’ at NoFieldSelectorsFail.hs:4:1-28
(and originally defined at NoFieldSelectorsFailA.hs:6:18-20)
-NoFieldSelectorsFail.hs:12:15: error:
- Ambiguous occurrence ‘foo’
- It could refer to
- either the field ‘foo’ of record ‘Foo’,
- imported from ‘NoFieldSelectorsFailA’ at NoFieldSelectorsFail.hs:4:1-28
- (and originally defined at NoFieldSelectorsFailA.hs:5:18-20)
- or the field ‘foo’ of record ‘Bar’,
- imported from ‘NoFieldSelectorsFailA’ at NoFieldSelectorsFail.hs:4:1-28
- (and originally defined at NoFieldSelectorsFailA.hs:6:18-20)
+NoFieldSelectorsFail.hs:12:15: error: [GHC-56428]
+ Ambiguous record field ‘foo’.
+ It could refer to any of the following:
+ • record field ‘foo’ of ‘Foo’,
+ imported from ‘NoFieldSelectorsFailA’ at NoFieldSelectorsFail.hs:4:1-28
+ (and originally defined at NoFieldSelectorsFailA.hs:5:18-20)
+ • record field ‘foo’ of ‘Bar’,
+ imported from ‘NoFieldSelectorsFailA’ at NoFieldSelectorsFail.hs:4:1-28
+ (and originally defined at NoFieldSelectorsFailA.hs:6:18-20)
+ Suggested fix: Perhaps you intended to use DisambiguateRecordFields
-NoFieldSelectorsFail.hs:14:15: error:
- Ambiguous occurrence ‘foo’
- It could refer to
- either the field ‘foo’ of record ‘Foo’,
- imported from ‘NoFieldSelectorsFailA’ at NoFieldSelectorsFail.hs:4:1-28
- (and originally defined at NoFieldSelectorsFailA.hs:5:18-20)
- or the field ‘foo’ of record ‘Bar’,
- imported from ‘NoFieldSelectorsFailA’ at NoFieldSelectorsFail.hs:4:1-28
- (and originally defined at NoFieldSelectorsFailA.hs:6:18-20)
+NoFieldSelectorsFail.hs:14:15: error: [GHC-56428]
+ Ambiguous record field ‘foo’.
+ It could refer to any of the following:
+ • record field ‘foo’ of ‘Foo’,
+ imported from ‘NoFieldSelectorsFailA’ at NoFieldSelectorsFail.hs:4:1-28
+ (and originally defined at NoFieldSelectorsFailA.hs:5:18-20)
+ • record field ‘foo’ of ‘Bar’,
+ imported from ‘NoFieldSelectorsFailA’ at NoFieldSelectorsFail.hs:4:1-28
+ (and originally defined at NoFieldSelectorsFailA.hs:6:18-20)
+ Suggested fix: Perhaps you intended to use DisambiguateRecordFields
-NoFieldSelectorsFail.hs:16:15: error:
- Ambiguous occurrence ‘bar’
- It could refer to
- either the field ‘bar’ of record ‘Foo’,
- imported from ‘NoFieldSelectorsFailA’ at NoFieldSelectorsFail.hs:4:1-28
- (and originally defined at NoFieldSelectorsFailA.hs:5:30-32)
- or ‘NoFieldSelectorsFailA.bar’,
- imported from ‘NoFieldSelectorsFailA’ at NoFieldSelectorsFail.hs:4:1-28
- (and originally defined at NoFieldSelectorsFailA.hs:8:1-3)
+NoFieldSelectorsFail.hs:16:15: error: [GHC-56428]
+ Ambiguous record field ‘bar’.
+ It could refer to any of the following:
+ • record field ‘bar’ of ‘Foo’,
+ imported from ‘NoFieldSelectorsFailA’ at NoFieldSelectorsFail.hs:4:1-28
+ (and originally defined at NoFieldSelectorsFailA.hs:5:30-32)
+ • variable ‘bar’,
+ imported from ‘NoFieldSelectorsFailA’ at NoFieldSelectorsFail.hs:4:1-28
+ (and originally defined at NoFieldSelectorsFailA.hs:8:1-3)
+ Suggested fix: Perhaps you intended to use DisambiguateRecordFields
diff --git a/testsuite/tests/overloadedrecflds/should_fail/NoParent.stderr b/testsuite/tests/overloadedrecflds/should_fail/NoParent.stderr
index b75b8c1df5..a18161d2e9 100644
--- a/testsuite/tests/overloadedrecflds/should_fail/NoParent.stderr
+++ b/testsuite/tests/overloadedrecflds/should_fail/NoParent.stderr
@@ -2,5 +2,5 @@
NoParent.hs:2:18: error: [GHC-88993]
• The type constructor ‘A’ is not the parent of the record selector ‘x’.
Record selectors can only be exported with their parent type constructor.
- Parents: C, B
+ Parents: B, C
• In the export: A(x)
diff --git a/testsuite/tests/overloadedrecflds/should_fail/T11103.stderr b/testsuite/tests/overloadedrecflds/should_fail/T11103.stderr
deleted file mode 100644
index 076d067d36..0000000000
--- a/testsuite/tests/overloadedrecflds/should_fail/T11103.stderr
+++ /dev/null
@@ -1,6 +0,0 @@
-
-T11103.hs:13:2: error:
- Ambiguous occurrence ‘Main.foo’
- It could refer to
- either the field ‘foo’ of record ‘S’, defined at T11103.hs:11:16
- or the field ‘foo’ of record ‘R’, defined at T11103.hs:10:16
diff --git a/testsuite/tests/overloadedrecflds/should_fail/T11167_ambiguous_fixity.stderr b/testsuite/tests/overloadedrecflds/should_fail/T11167_ambiguous_fixity.stderr
index 709ee2312d..277a5bd0ac 100644
--- a/testsuite/tests/overloadedrecflds/should_fail/T11167_ambiguous_fixity.stderr
+++ b/testsuite/tests/overloadedrecflds/should_fail/T11167_ambiguous_fixity.stderr
@@ -5,12 +5,12 @@
T11167_ambiguous_fixity.hs:6:16: error:
Ambiguous occurrence ‘foo’
It could refer to
- either the field ‘foo’ of record ‘C’,
- imported from ‘T11167_ambiguous_fixity_A’ at T11167_ambiguous_fixity.hs:3:1-32
- (and originally defined at T11167_ambiguous_fixity_A.hs:4:16-18)
- or the field ‘foo’ of record ‘A’,
+ either the field ‘foo’ of record ‘A’,
imported from ‘T11167_ambiguous_fixity_A’ at T11167_ambiguous_fixity.hs:3:1-32
(and originally defined at T11167_ambiguous_fixity_A.hs:3:16-18)
+ or the field ‘foo’ of record ‘C’,
+ imported from ‘T11167_ambiguous_fixity_A’ at T11167_ambiguous_fixity.hs:3:1-32
+ (and originally defined at T11167_ambiguous_fixity_A.hs:4:16-18)
or the field ‘foo’ of record ‘B’,
imported from ‘T11167_ambiguous_fixity_B’ at T11167_ambiguous_fixity.hs:4:1-32
(and originally defined at T11167_ambiguous_fixity_B.hs:2:16-18)
diff --git a/testsuite/tests/overloadedrecflds/should_fail/T13132_duplicaterecflds.stderr b/testsuite/tests/overloadedrecflds/should_fail/T13132_duplicaterecflds.stderr
index a2a4428b0b..462b00416c 100644
--- a/testsuite/tests/overloadedrecflds/should_fail/T13132_duplicaterecflds.stderr
+++ b/testsuite/tests/overloadedrecflds/should_fail/T13132_duplicaterecflds.stderr
@@ -2,10 +2,10 @@
T13132_duplicaterecflds.hs:7:16: error:
Ambiguous occurrence ‘runContT’
It could refer to
- either the field ‘runContT’ of record ‘ContT2’,
- defined at T13132_duplicaterecflds.hs:5:33
- or the field ‘runContT’ of record ‘ContT’,
+ either the field ‘runContT’ of record ‘ContT’,
defined at T13132_duplicaterecflds.hs:4:31
+ or the field ‘runContT’ of record ‘ContT2’,
+ defined at T13132_duplicaterecflds.hs:5:33
T13132_duplicaterecflds.hs:9:11: error:
The operator ‘runContT’ [infixl 9] of a section
@@ -16,7 +16,7 @@ T13132_duplicaterecflds.hs:9:11: error:
T13132_duplicaterecflds.hs:9:12: error:
Ambiguous occurrence ‘runContT’
It could refer to
- either the field ‘runContT’ of record ‘ContT2’,
- defined at T13132_duplicaterecflds.hs:5:33
- or the field ‘runContT’ of record ‘ContT’,
+ either the field ‘runContT’ of record ‘ContT’,
defined at T13132_duplicaterecflds.hs:4:31
+ or the field ‘runContT’ of record ‘ContT2’,
+ defined at T13132_duplicaterecflds.hs:5:33
diff --git a/testsuite/tests/overloadedrecflds/should_fail/T14953.stderr b/testsuite/tests/overloadedrecflds/should_fail/T14953.stderr
index 144e306483..19003fc78c 100644
--- a/testsuite/tests/overloadedrecflds/should_fail/T14953.stderr
+++ b/testsuite/tests/overloadedrecflds/should_fail/T14953.stderr
@@ -4,10 +4,10 @@
T14953.hs:2:33: error: [GHC-69158]
Conflicting exports for ‘unR’:
- ‘module T14953_A’ exports ‘unR’
+ ‘module T14953_A’ exports ‘T14953_A.unR’
imported from ‘T14953_A’ at T14953.hs:3:1-15
(and originally defined at T14953_A.hs:3:13-15)
- ‘module T14953_B’ exports ‘unR’
+ ‘module T14953_B’ exports ‘T14953_B.unR’
imported from ‘T14953_B’ at T14953.hs:4:1-15
(and originally defined at T14953_B.hs:3:13-15)
diff --git a/testsuite/tests/overloadedrecflds/should_fail/T16745.stderr b/testsuite/tests/overloadedrecflds/should_fail/T16745.stderr
index 61a9567788..5969a540e0 100644
--- a/testsuite/tests/overloadedrecflds/should_fail/T16745.stderr
+++ b/testsuite/tests/overloadedrecflds/should_fail/T16745.stderr
@@ -6,9 +6,9 @@
T16745A.hs:8:9: error:
Ambiguous occurrence ‘field’
It could refer to
- either the field ‘field’ of record ‘T16745B.R’,
- imported from ‘T16745B’ at T16745A.hs:3:24-28
- (and originally defined at T16745B.hs:11:14-18)
- or ‘T16745B.field’,
+ either ‘T16745B.field’,
imported from ‘T16745B’ at T16745A.hs:3:24-28
(and originally defined in ‘T16745C’ at T16745C.hs:2:1-5)
+ or the field ‘field’ of record ‘T16745B.R’,
+ imported from ‘T16745B’ at T16745A.hs:3:24-28
+ (and originally defined at T16745B.hs:11:14-18)
diff --git a/testsuite/tests/overloadedrecflds/should_fail/T17420.stderr b/testsuite/tests/overloadedrecflds/should_fail/T17420.stderr
index 5089f19ce2..e1db5fa195 100644
--- a/testsuite/tests/overloadedrecflds/should_fail/T17420.stderr
+++ b/testsuite/tests/overloadedrecflds/should_fail/T17420.stderr
@@ -4,9 +4,9 @@
T17420.hs:6:17: error:
Ambiguous occurrence ‘name’
It could refer to
- either the field ‘name’ of record ‘Human’,
- imported from ‘T17420A’ at T17420.hs:4:1-14
- (and originally defined at T17420A.hs:5:22-25)
- or the field ‘name’ of record ‘Dog’,
+ either the field ‘name’ of record ‘Dog’,
imported from ‘T17420A’ at T17420.hs:4:1-14
(and originally defined at T17420A.hs:4:18-21)
+ or the field ‘name’ of record ‘Human’,
+ imported from ‘T17420A’ at T17420.hs:4:1-14
+ (and originally defined at T17420A.hs:5:22-25)
diff --git a/testsuite/tests/overloadedrecflds/should_fail/T18999_NoDisambiguateRecordFields.stderr b/testsuite/tests/overloadedrecflds/should_fail/T18999_NoDisambiguateRecordFields.stderr
index d271efc7f8..f462dcb187 100644
--- a/testsuite/tests/overloadedrecflds/should_fail/T18999_NoDisambiguateRecordFields.stderr
+++ b/testsuite/tests/overloadedrecflds/should_fail/T18999_NoDisambiguateRecordFields.stderr
@@ -8,11 +8,12 @@ T18999_NoDisambiguateRecordFields.hs:6:13: error:
or the field ‘not’ of record ‘Foo’,
defined at T18999_NoDisambiguateRecordFields.hs:4:18
-T18999_NoDisambiguateRecordFields.hs:8:11: error:
- Ambiguous occurrence ‘not’
- It could refer to
- either ‘Prelude.not’,
- imported from ‘Prelude’ at T18999_NoDisambiguateRecordFields.hs:2:8-40
- (and originally defined in ‘GHC.Classes’)
- or the field ‘not’ of record ‘Foo’,
- defined at T18999_NoDisambiguateRecordFields.hs:4:18
+T18999_NoDisambiguateRecordFields.hs:8:11: error: [GHC-56428]
+ Ambiguous record field ‘not’.
+ It could refer to any of the following:
+ • record field ‘not’ of ‘Foo’,
+ defined at T18999_NoDisambiguateRecordFields.hs:4:18
+ • variable ‘not’,
+ imported from ‘Prelude’ at T18999_NoDisambiguateRecordFields.hs:2:8-40
+ (and originally defined in ‘GHC.Classes’)
+ Suggested fix: Perhaps you intended to use DisambiguateRecordFields
diff --git a/testsuite/tests/overloadedrecflds/should_fail/T19287.hs b/testsuite/tests/overloadedrecflds/should_fail/T19287.hs
index f3dedbe4bc..793d0e61e7 100644
--- a/testsuite/tests/overloadedrecflds/should_fail/T19287.hs
+++ b/testsuite/tests/overloadedrecflds/should_fail/T19287.hs
@@ -1,7 +1,7 @@
{-# LANGUAGE DuplicateRecordFields #-}
module Main where
-data R a b = R { x :: a , x :: b}
+data R a b = R { x :: a , x :: b }
unsafeCoerce :: a -> b
unsafeCoerce i = case (R i i){x = i} of
diff --git a/testsuite/tests/overloadedrecflds/should_fail/T19287.stderr b/testsuite/tests/overloadedrecflds/should_fail/T19287.stderr
index c0c5a0caa9..03a88e1f78 100644
--- a/testsuite/tests/overloadedrecflds/should_fail/T19287.stderr
+++ b/testsuite/tests/overloadedrecflds/should_fail/T19287.stderr
@@ -1,5 +1,3 @@
-T19287.hs:4:27: error:
- Multiple declarations of ‘x’
- Declared at: T19287.hs:4:18
- T19287.hs:4:27
+T19287.hs:4:27: error: [GHC-85524]
+ Duplicate field name ‘x’ in record declaration
diff --git a/testsuite/tests/overloadedrecflds/should_fail/T21946.hs b/testsuite/tests/overloadedrecflds/should_fail/T21946.hs
new file mode 100644
index 0000000000..fdd0f09749
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_fail/T21946.hs
@@ -0,0 +1,11 @@
+{-# LANGUAGE DuplicateRecordFields, PatternSynonyms #-}
+
+module T21946 where
+
+pattern R1 :: Int -> Int
+pattern R1 { fld } = fld
+
+pattern R2 :: Bool -> Bool
+pattern R2 { fld } = fld
+
+f r = (r :: Int) { fld = undefined }
diff --git a/testsuite/tests/overloadedrecflds/should_fail/T21946.stderr b/testsuite/tests/overloadedrecflds/should_fail/T21946.stderr
new file mode 100644
index 0000000000..61254e3e3d
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_fail/T21946.stderr
@@ -0,0 +1,8 @@
+
+T21946.hs:11:7: error: [GHC-33238]
+ • No data constructor of type constructor ‘Int’
+ has all of the fields:
+ ‘fld’
+ NB: type-directed disambiguation is not supported for pattern synonym record fields.
+ • In the expression: (r :: Int) {fld = undefined}
+ In an equation for ‘f’: f r = (r :: Int) {fld = undefined}
diff --git a/testsuite/tests/overloadedrecflds/should_fail/T21959.hs b/testsuite/tests/overloadedrecflds/should_fail/T21959.hs
new file mode 100644
index 0000000000..b10c2a1355
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_fail/T21959.hs
@@ -0,0 +1,6 @@
+module T21959 where
+
+data R = R { fld :: Int }
+
+f :: R -> R
+f r = r { T21959.fld = 1, fld = 2 }
diff --git a/testsuite/tests/overloadedrecflds/should_fail/T21959.stderr b/testsuite/tests/overloadedrecflds/should_fail/T21959.stderr
new file mode 100644
index 0000000000..49d00962a0
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_fail/T21959.stderr
@@ -0,0 +1,3 @@
+
+T21959.hs:6:7: error: [GHC-85524]
+ Duplicate field name ‘fld’ in record update
diff --git a/testsuite/tests/overloadedrecflds/should_fail/T23010_fail.hs b/testsuite/tests/overloadedrecflds/should_fail/T23010_fail.hs
new file mode 100644
index 0000000000..83421fd2de
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_fail/T23010_fail.hs
@@ -0,0 +1,7 @@
+{-# LANGUAGE DuplicateRecordFields #-}
+
+module T23010_fail where
+
+import T23010_fail_aux ( X )
+data A = MkA { fld :: A, other :: X }
+data B = MkB { fld :: B }
diff --git a/testsuite/tests/overloadedrecflds/should_fail/T23010_fail.hs-boot b/testsuite/tests/overloadedrecflds/should_fail/T23010_fail.hs-boot
new file mode 100644
index 0000000000..699c994b1f
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_fail/T23010_fail.hs-boot
@@ -0,0 +1,7 @@
+{-# LANGUAGE DuplicateRecordFields #-}
+
+module T23010_fail where
+
+data A
+
+fld :: A -> A
diff --git a/testsuite/tests/overloadedrecflds/should_fail/T23010_fail.stderr b/testsuite/tests/overloadedrecflds/should_fail/T23010_fail.stderr
new file mode 100644
index 0000000000..61e93b95bb
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_fail/T23010_fail.stderr
@@ -0,0 +1,8 @@
+
+T23010_fail.hs-boot:7:1: error:
+ Ambiguous occurrence ‘T23010_fail.fld’
+ It could refer to
+ either the field ‘fld’ of record ‘A’,
+ defined at T23010_fail.hs:6:16
+ or the field ‘fld’ of record ‘B’,
+ defined at T23010_fail.hs:7:16
diff --git a/testsuite/tests/overloadedrecflds/should_fail/T23010_fail_aux.hs b/testsuite/tests/overloadedrecflds/should_fail/T23010_fail_aux.hs
new file mode 100644
index 0000000000..d1e5cfefb7
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_fail/T23010_fail_aux.hs
@@ -0,0 +1,8 @@
+{-# LANGUAGE DuplicateRecordFields #-}
+
+module T23010_fail_aux where
+
+import {-# SOURCE #-} T23010_fail ( fld )
+
+data X
+bar = fld
diff --git a/testsuite/tests/overloadedrecflds/should_fail/T23063.hs b/testsuite/tests/overloadedrecflds/should_fail/T23063.hs
new file mode 100644
index 0000000000..c2b57bdafd
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_fail/T23063.hs
@@ -0,0 +1,5 @@
+{-# LANGUAGE DuplicateRecordFields #-}
+module T23063 where
+import qualified T23063_aux as A
+
+baz = _ :: A.S -> Int
diff --git a/testsuite/tests/overloadedrecflds/should_fail/T23063.stderr b/testsuite/tests/overloadedrecflds/should_fail/T23063.stderr
new file mode 100644
index 0000000000..89cfdc7a2d
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_fail/T23063.stderr
@@ -0,0 +1,12 @@
+
+T23063.hs:5:7: error: [GHC-88464]
+ • Found hole: _ :: A.S -> Int
+ • In the expression: _ :: A.S -> Int
+ In an equation for ‘baz’: baz = _ :: A.S -> Int
+ • Relevant bindings include
+ baz :: A.S -> Int (bound at T23063.hs:5:1)
+ Valid hole fits include
+ baz :: A.S -> Int (defined at T23063.hs:5:1)
+ A.foo :: A.S -> Int
+ (imported qualified from ‘T23063_aux’ at T23063.hs:3:1-32
+ (and originally defined at T23063_aux.hs:4:16-18))
diff --git a/testsuite/tests/overloadedrecflds/should_fail/T23063_aux.hs b/testsuite/tests/overloadedrecflds/should_fail/T23063_aux.hs
new file mode 100644
index 0000000000..d5552ebd6d
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_fail/T23063_aux.hs
@@ -0,0 +1,4 @@
+{-# LANGUAGE DuplicateRecordFields #-}
+module T23063_aux where
+
+data S = MkS { foo :: Int }
diff --git a/testsuite/tests/overloadedrecflds/should_fail/all.T b/testsuite/tests/overloadedrecflds/should_fail/all.T
index 28ec4f7b7e..2da5c8da2f 100644
--- a/testsuite/tests/overloadedrecflds/should_fail/all.T
+++ b/testsuite/tests/overloadedrecflds/should_fail/all.T
@@ -1,4 +1,6 @@
-test('overloadedrecfldsfail01', normal, compile_fail, [''])
+test('overloadedrecfldsfail01a', normal, compile_fail, [''])
+test('overloadedrecfldsfail01b', normal, compile_fail, [''])
+test('overloadedrecfldsfail01c', normal, compile_fail, [''])
test('overloadedrecfldsfail02', normal, compile_fail, [''])
test('overloadedrecfldsfail03', normal, compile_fail, [''])
test('overloadedrecfldsfail04', [extra_files(['OverloadedRecFldsFail04_A.hs'])], multimod_compile_fail,
@@ -20,7 +22,6 @@ test('overloadedrecfldsfail14', normal, compile_fail, [''])
test('overloadedlabelsfail01', normal, compile_fail, [''])
test('overloadedlabelsfail02', normal, compile_fail, [''])
test('overloadedlabelsfail03', normal, compile_fail, [''])
-test('T11103', req_th, compile_fail, [''])
test('T11167_ambiguous_fixity', [], multimod_compile_fail,
['T11167_ambiguous_fixity', ''])
test('T13132_duplicaterecflds', normal, compile_fail, [''])
@@ -37,7 +38,7 @@ test('T17420', [extra_files(['T17420A.hs'])], multimod_compile_fail,
test('T17469', [extra_files(['T17469A.hs'])], multimod_compile_fail,
['T17469', ''])
test('T17965', normal, compile_fail, [''])
-test('DRFHoleFits', extra_files(['DRFHoleFits_A.hs']), multimod_compile_fail, ['DRFHoleFits', ''])
+test('DRFHoleFits', extra_files(['DRFHoleFits_A.hs']), multimod_compile_fail, ['DRFHoleFits', '-v0'])
test('DRFPartialFields', normal, compile_fail, [''])
test('T16745', extra_files(['T16745C.hs', 'T16745B.hs']), multimod_compile_fail, ['T16745A', ''])
test('FieldSelectors', normal, compile_fail, [''])
@@ -52,3 +53,9 @@ test('T18999_NoDisambiguateRecordFields', normal, compile_fail, [''])
test('DRFUnused', normal, compile_fail, [''])
test('T19287', normal, compile_fail, [''])
test('overloadedrecfldswasrunnowfail06', normal, compile_fail, [''])
+test('T21946', normal, compile_fail, [''])
+test('T21959', normal, compile_fail, [''])
+test('T23010_fail', [extra_files(['T23010_fail.hs-boot', 'T23010_fail_aux.hs'])]
+ , multimod_compile_fail
+ , ['T23010_fail T23010_fail_aux', '-v0'])
+test('T23063', extra_files(['T23063_aux.hs']), multimod_compile_fail, ['T23063', '-v0']) \ No newline at end of file
diff --git a/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail01.stderr b/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail01.stderr
index 66089a586e..a2cdc2bfd5 100644
--- a/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail01.stderr
+++ b/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail01.stderr
@@ -1,22 +1,4 @@
-overloadedrecfldsfail01.hs:11:10: error: [GHC-99339]
- • Record update is ambiguous, and requires a type signature
- • In the expression: r {x = 3}
- In an equation for ‘upd1’: upd1 r = r {x = 3}
-
-overloadedrecfldsfail01.hs:14:10: error: [GHC-33238]
- • No type has all these fields: ‘x’, ‘y’, ‘z’
- • In the expression: r {x = 3, y = True, z = False}
- In an equation for ‘upd2’: upd2 r = r {x = 3, y = True, z = False}
-
-overloadedrecfldsfail01.hs:17:10: error: [GHC-54721]
- • ‘x’ is not a (visible) field of type ‘U’
- • In the expression: r {w = True, x = 3, y = True} :: U
- In an equation for ‘upd3’:
- upd3 r = r {w = True, x = 3, y = True} :: U
-
-overloadedrecfldsfail01.hs:17:10: error: [GHC-54721]
- • ‘w’ is not a (visible) field of type ‘U’
- • In the expression: r {w = True, x = 3, y = True} :: U
- In an equation for ‘upd3’:
- upd3 r = r {w = True, x = 3, y = True} :: U
+overloadedrecfldsfail01.hs:14:10: error:
+ Invalid record update.
+ No constructor in scope has all of the following fields: ‘z’, ‘y’
diff --git a/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail01a.hs b/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail01a.hs
new file mode 100644
index 0000000000..be7284267e
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail01a.hs
@@ -0,0 +1,13 @@
+-- Test ambiguous updates are rejected with appropriate error messages
+
+{-# LANGUAGE DuplicateRecordFields #-}
+
+module OverloadedRecFieldsFail1a where
+
+data R = MkR { w :: Bool, x :: Int, y :: Bool }
+data S = MkS { w :: Bool, x :: Int, y :: Bool }
+data T = MkT { x :: Int, z :: Bool }
+data U = MkU { y :: Bool }
+
+-- Straightforward ambiguous update
+upd1 r = r { x = 3 }
diff --git a/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail01a.stderr b/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail01a.stderr
new file mode 100644
index 0000000000..7ac58b0e43
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail01a.stderr
@@ -0,0 +1,6 @@
+
+overloadedrecfldsfail01a.hs:13:10: error: [GHC-99339]
+ • Ambiguous record update with field ‘x’
+ This field appears in all of the datatypes ‘R’, ‘S’ and ‘T’
+ • In the expression: r {x = 3}
+ In an equation for ‘upd1’: upd1 r = r {x = 3}
diff --git a/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail01b.hs b/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail01b.hs
new file mode 100644
index 0000000000..d3e14f4056
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail01b.hs
@@ -0,0 +1,13 @@
+-- Test ambiguous updates are rejected with appropriate error messages
+
+{-# LANGUAGE DuplicateRecordFields #-}
+
+module OverloadedRecFieldsFail1b where
+
+data R = MkR { w :: Bool, x :: Int, y :: Bool }
+data S = MkS { w :: Bool, x :: Int, y :: Bool }
+data T = MkT { x :: Int, z :: Bool }
+data U = MkU { y :: Bool }
+
+-- No type has all these fields
+upd2 r = r { x = 3, y = True, z = False }
diff --git a/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail01b.stderr b/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail01b.stderr
new file mode 100644
index 0000000000..2a55c5d92b
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail01b.stderr
@@ -0,0 +1,4 @@
+
+overloadedrecfldsfail01b.hs:13:10: error: [GHC-14392]
+ Invalid record update.
+ No constructor in scope has all of the following fields: ‘z’, ‘y’
diff --git a/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail01.hs b/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail01c.hs
index 8ce9be7d47..cfa079e7b9 100644
--- a/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail01.hs
+++ b/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail01c.hs
@@ -2,18 +2,12 @@
{-# LANGUAGE DuplicateRecordFields #-}
+module OverloadedRecFieldsFail1c where
+
data R = MkR { w :: Bool, x :: Int, y :: Bool }
data S = MkS { w :: Bool, x :: Int, y :: Bool }
data T = MkT { x :: Int, z :: Bool }
data U = MkU { y :: Bool }
--- Straightforward ambiguous update
-upd1 r = r { x = 3 }
-
--- No type has all these fields
-upd2 r = r { x = 3, y = True, z = False }
-
-- User-specified type does not have these fields
upd3 r = r { w = True, x = 3, y = True } :: U
-
-main = return ()
diff --git a/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail01c.stderr b/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail01c.stderr
new file mode 100644
index 0000000000..146e364e99
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail01c.stderr
@@ -0,0 +1,8 @@
+
+overloadedrecfldsfail01c.hs:13:10: error: [GHC-33238]
+ • No data constructor of type constructor ‘U’
+ has all of the fields:
+ ‘w’, ‘x’, ‘y’
+ • In the expression: r {w = True, x = 3, y = True} :: U
+ In an equation for ‘upd3’:
+ upd3 r = r {w = True, x = 3, y = True} :: U
diff --git a/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail02.stderr b/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail02.stderr
index f6d03433fb..6a27569776 100644
--- a/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail02.stderr
+++ b/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail02.stderr
@@ -2,7 +2,7 @@
overloadedrecfldsfail02.hs:8:18: error:
Ambiguous occurrence ‘x’
It could refer to
- either the field ‘x’ of record ‘S’,
- defined at overloadedrecfldsfail02.hs:6:16
- or the field ‘x’ of record ‘R’,
+ either the field ‘x’ of record ‘R’,
defined at overloadedrecfldsfail02.hs:5:16
+ or the field ‘x’ of record ‘S’,
+ defined at overloadedrecfldsfail02.hs:6:16
diff --git a/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail05.stderr b/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail05.stderr
index 3e2e0572f1..bff9bd544f 100644
--- a/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail05.stderr
+++ b/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail05.stderr
@@ -1,3 +1,3 @@
overloadedrecfldsfail05.hs:7:16: error: [-Wunused-top-binds (in -Wextra, -Wunused-binds), Werror=unused-top-binds]
- Defined but not used: ‘foo’
+ Defined but not used: record field of MkT ‘foo’
diff --git a/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail06.stderr b/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail06.stderr
index 7567a038b4..3f0b17106a 100644
--- a/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail06.stderr
+++ b/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail06.stderr
@@ -4,14 +4,14 @@ OverloadedRecFldsFail06_A.hs:9:15: warning: [-Wunused-top-binds (in -Wextra, -Wu
Defined but not used: data constructor ‘MkUnused’
OverloadedRecFldsFail06_A.hs:9:42: warning: [-Wunused-top-binds (in -Wextra, -Wunused-binds)]
- Defined but not used: ‘unused2’
+ Defined but not used: record field of MkUnused ‘unused2’
OverloadedRecFldsFail06_A.hs:9:59: warning: [-Wunused-top-binds (in -Wextra, -Wunused-binds)]
- Defined but not used: ‘used_locally’
+ Defined but not used: record field of MkUnused ‘used_locally’
[2 of 3] Compiling Main ( overloadedrecfldsfail06.hs, overloadedrecfldsfail06.o )
overloadedrecfldsfail06.hs:7:1: error: [-Wunused-imports (in -Wextra), Werror=unused-imports]
- The import of ‘Unused(unused), V(x), U(y), MkV, Unused’
+ The import of ‘MkV, Unused, Unused(unused), V(x), U(y)’
from module ‘OverloadedRecFldsFail06_A’ is redundant
overloadedrecfldsfail06.hs:8:1: error: [-Wunused-imports (in -Wextra), Werror=unused-imports]
@@ -24,13 +24,15 @@ overloadedrecfldsfail06.hs:9:1: error: [-Wunused-imports (in -Wextra), Werror=un
from module ‘OverloadedRecFldsFail06_A’ is redundant
overloadedrecfldsfail06.hs:10:1: error: [-Wunused-imports (in -Wextra), Werror=unused-imports]
- The qualified import of ‘U(x), U’
+ The qualified import of ‘U, U(x)’
from module ‘OverloadedRecFldsFail06_A’ is redundant
overloadedrecfldsfail06.hs:15:22: error: [GHC-02256] [-Wambiguous-fields (in -Wdefault), Werror=ambiguous-fields]
- The record update u {x = True} with type U is ambiguous.
- This will not be supported by -XDuplicateRecordFields in future releases of GHC.
+ Ambiguous record update with parent type constructor ‘U’.
+ This type-directed disambiguation mechanism will not be supported by -XDuplicateRecordFields in future releases of GHC.
+ Consider disambiguating using module qualification instead.
overloadedrecfldsfail06.hs:18:28: error: [GHC-02256] [-Wambiguous-fields (in -Wdefault), Werror=ambiguous-fields]
- The record update v {P.x = 3} with type V is ambiguous.
- This will not be supported by -XDuplicateRecordFields in future releases of GHC.
+ Ambiguous record update with parent type constructor ‘V’.
+ This type-directed disambiguation mechanism will not be supported by -XDuplicateRecordFields in future releases of GHC.
+ Consider disambiguating using module qualification instead.
diff --git a/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail08.stderr b/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail08.stderr
index d364f079d8..24085ea57c 100644
--- a/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail08.stderr
+++ b/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail08.stderr
@@ -1,5 +1,4 @@
overloadedrecfldsfail08.hs:9:9: error: [GHC-14392]
- • No constructor has all these fields: ‘x’, ‘y’
- • In the expression: e {x = 3, y = True}
- In an equation for ‘foo’: foo e = e {x = 3, y = True}
+ Invalid record update.
+ No constructor in scope has all of the following fields: ‘x’, ‘y’
diff --git a/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail10.hs b/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail10.hs
index ccb25d3387..508d5a69c1 100644
--- a/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail10.hs
+++ b/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail10.hs
@@ -1,8 +1,8 @@
--- Modules A and B both declare F(foo)
--- Module C declares F($sel:foo:MkFChar) but exports A.F(foo) as well
--- Thus we can't export F(..) even with DuplicateRecordFields enabled
+-- Module A exports $fld:MkFInt:foo
+-- Module B exports $fld:MkFBool:foo
+-- Module C exports $fld:MkFChar:foo and re-exports $fld:MkFInt:foo
+-- Thus we can't export F(..) without -XDuplicateRecordFields
-{-# LANGUAGE DuplicateRecordFields #-}
module Main (main, F(..)) where
import OverloadedRecFldsFail10_B
diff --git a/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail10.stderr b/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail10.stderr
index 8b113e19ee..ad62403ddc 100644
--- a/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail10.stderr
+++ b/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail10.stderr
@@ -3,12 +3,28 @@
[3 of 5] Compiling OverloadedRecFldsFail10_C ( OverloadedRecFldsFail10_C.hs, OverloadedRecFldsFail10_C.o )
[4 of 5] Compiling Main ( overloadedrecfldsfail10.hs, overloadedrecfldsfail10.o )
-overloadedrecfldsfail10.hs:6:20: error: [GHC-69158]
- Conflicting exports for ‘foo’:
- ‘F(..)’ exports ‘OverloadedRecFldsFail10_B.foo’
+overloadedrecfldsfail10.hs:6:20: error: [GHC-97219]
+ Duplicate record field ‘foo’ in export list:
+ ‘F(..)’ exports the field ‘foo’
+ belonging to the constructor ‘MkFChar’
+ imported from ‘OverloadedRecFldsFail10_C’ at overloadedrecfldsfail10.hs:9:1-32
+ (and originally defined at OverloadedRecFldsFail10_C.hs:6:34-36)
+ ‘F(..)’ exports the field ‘foo’
+ belonging to the constructor ‘MkFInt’
+ imported from ‘OverloadedRecFldsFail10_C’ at overloadedrecfldsfail10.hs:9:1-32
+ (and originally defined in ‘OverloadedRecFldsFail10_A’
+ at OverloadedRecFldsFail10_A.hs:5:32-34)
+ Suggested fix: Perhaps you intended to use DuplicateRecordFields
+
+overloadedrecfldsfail10.hs:6:20: error: [GHC-97219]
+ Duplicate record field ‘foo’ in export list:
+ ‘F(..)’ exports the field ‘foo’
+ belonging to the constructor ‘MkFBool’
imported from ‘OverloadedRecFldsFail10_B’ at overloadedrecfldsfail10.hs:8:1-32
(and originally defined at OverloadedRecFldsFail10_B.hs:6:34-36)
- ‘F(..)’ exports ‘OverloadedRecFldsFail10_C.foo’
+ ‘F(..)’ exports the field ‘foo’
+ belonging to the constructor ‘MkFInt’
imported from ‘OverloadedRecFldsFail10_C’ at overloadedrecfldsfail10.hs:9:1-32
(and originally defined in ‘OverloadedRecFldsFail10_A’
at OverloadedRecFldsFail10_A.hs:5:32-34)
+ Suggested fix: Perhaps you intended to use DuplicateRecordFields
diff --git a/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail11.stderr b/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail11.stderr
index a146a0e9c6..54472f4293 100644
--- a/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail11.stderr
+++ b/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail11.stderr
@@ -4,9 +4,9 @@
overloadedrecfldsfail11.hs:5:15: error:
Ambiguous occurrence ‘foo’
It could refer to
- either the field ‘foo’ of record ‘T’,
- imported from ‘OverloadedRecFldsFail11_A’ at overloadedrecfldsfail11.hs:3:1-32
- (and originally defined at OverloadedRecFldsFail11_A.hs:6:16-18)
- or the field ‘foo’ of record ‘S’,
+ either the field ‘foo’ of record ‘S’,
imported from ‘OverloadedRecFldsFail11_A’ at overloadedrecfldsfail11.hs:3:1-32
(and originally defined at OverloadedRecFldsFail11_A.hs:5:16-18)
+ or the field ‘foo’ of record ‘T’,
+ imported from ‘OverloadedRecFldsFail11_A’ at overloadedrecfldsfail11.hs:3:1-32
+ (and originally defined at OverloadedRecFldsFail11_A.hs:6:16-18)
diff --git a/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail13.stderr b/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail13.stderr
index 20c9e2dd97..4fb285b327 100644
--- a/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail13.stderr
+++ b/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail13.stderr
@@ -2,31 +2,31 @@
overloadedrecfldsfail13.hs:10:5: error:
Ambiguous occurrence ‘x’
It could refer to
- either the field ‘x’ of record ‘T’,
- defined at overloadedrecfldsfail13.hs:7:16
- or the field ‘x’ of record ‘S’,
+ either the field ‘x’ of record ‘S’,
defined at overloadedrecfldsfail13.hs:6:16
+ or the field ‘x’ of record ‘T’,
+ defined at overloadedrecfldsfail13.hs:7:16
overloadedrecfldsfail13.hs:12:5: error:
Ambiguous occurrence ‘x’
It could refer to
- either the field ‘x’ of record ‘T’,
- defined at overloadedrecfldsfail13.hs:7:16
- or the field ‘x’ of record ‘S’,
+ either the field ‘x’ of record ‘S’,
defined at overloadedrecfldsfail13.hs:6:16
+ or the field ‘x’ of record ‘T’,
+ defined at overloadedrecfldsfail13.hs:7:16
overloadedrecfldsfail13.hs:15:5: error:
Ambiguous occurrence ‘x’
It could refer to
- either the field ‘x’ of record ‘T’,
- defined at overloadedrecfldsfail13.hs:7:16
- or the field ‘x’ of record ‘S’,
+ either the field ‘x’ of record ‘S’,
defined at overloadedrecfldsfail13.hs:6:16
+ or the field ‘x’ of record ‘T’,
+ defined at overloadedrecfldsfail13.hs:7:16
overloadedrecfldsfail13.hs:18:5: error:
Ambiguous occurrence ‘x’
It could refer to
- either the field ‘x’ of record ‘T’,
- defined at overloadedrecfldsfail13.hs:7:16
- or the field ‘x’ of record ‘S’,
+ either the field ‘x’ of record ‘S’,
defined at overloadedrecfldsfail13.hs:6:16
+ or the field ‘x’ of record ‘T’,
+ defined at overloadedrecfldsfail13.hs:7:16
diff --git a/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail14.stderr b/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail14.stderr
index 7b0d276a96..400a633946 100644
--- a/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail14.stderr
+++ b/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldsfail14.stderr
@@ -1,5 +1,3 @@
-overloadedrecfldsfail14.hs:12:7: error: [GHC-33238]
- • No type has all these fields: ‘x’, ‘y’
- • In the expression: r {x = 3, y = False}
- In an equation for ‘f’: f r = r {x = 3, y = False}
+overloadedrecfldsfail14.hs:12:18: error: [GHC-22385]
+ Not in scope: record field ‘y’
diff --git a/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldswasrunnowfail06.stderr b/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldswasrunnowfail06.stderr
index 789d87a6a3..c5f1e431c9 100644
--- a/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldswasrunnowfail06.stderr
+++ b/testsuite/tests/overloadedrecflds/should_fail/overloadedrecfldswasrunnowfail06.stderr
@@ -2,39 +2,39 @@
overloadedrecfldswasrunnowfail06.hs:11:11: error:
Ambiguous occurrence ‘x’
It could refer to
- either the field ‘x’ of record ‘U’,
- defined at overloadedrecfldswasrunnowfail06.hs:8:18
+ either the field ‘x’ of record ‘S’,
+ defined at overloadedrecfldswasrunnowfail06.hs:6:16
or the field ‘x’ of record ‘T’,
defined at overloadedrecfldswasrunnowfail06.hs:7:16
- or the field ‘x’ of record ‘S’,
- defined at overloadedrecfldswasrunnowfail06.hs:6:16
+ or the field ‘x’ of record ‘U’,
+ defined at overloadedrecfldswasrunnowfail06.hs:8:18
overloadedrecfldswasrunnowfail06.hs:13:11: error:
Ambiguous occurrence ‘x’
It could refer to
- either the field ‘x’ of record ‘U’,
- defined at overloadedrecfldswasrunnowfail06.hs:8:18
+ either the field ‘x’ of record ‘S’,
+ defined at overloadedrecfldswasrunnowfail06.hs:6:16
or the field ‘x’ of record ‘T’,
defined at overloadedrecfldswasrunnowfail06.hs:7:16
- or the field ‘x’ of record ‘S’,
- defined at overloadedrecfldswasrunnowfail06.hs:6:16
+ or the field ‘x’ of record ‘U’,
+ defined at overloadedrecfldswasrunnowfail06.hs:8:18
overloadedrecfldswasrunnowfail06.hs:15:13: error:
Ambiguous occurrence ‘x’
It could refer to
- either the field ‘x’ of record ‘U’,
- defined at overloadedrecfldswasrunnowfail06.hs:8:18
+ either the field ‘x’ of record ‘S’,
+ defined at overloadedrecfldswasrunnowfail06.hs:6:16
or the field ‘x’ of record ‘T’,
defined at overloadedrecfldswasrunnowfail06.hs:7:16
- or the field ‘x’ of record ‘S’,
- defined at overloadedrecfldswasrunnowfail06.hs:6:16
+ or the field ‘x’ of record ‘U’,
+ defined at overloadedrecfldswasrunnowfail06.hs:8:18
overloadedrecfldswasrunnowfail06.hs:21:20: error:
Ambiguous occurrence ‘x’
It could refer to
- either the field ‘x’ of record ‘U’,
- defined at overloadedrecfldswasrunnowfail06.hs:8:18
+ either the field ‘x’ of record ‘S’,
+ defined at overloadedrecfldswasrunnowfail06.hs:6:16
or the field ‘x’ of record ‘T’,
defined at overloadedrecfldswasrunnowfail06.hs:7:16
- or the field ‘x’ of record ‘S’,
- defined at overloadedrecfldswasrunnowfail06.hs:6:16
+ or the field ‘x’ of record ‘U’,
+ defined at overloadedrecfldswasrunnowfail06.hs:8:18
diff --git a/testsuite/tests/overloadedrecflds/should_run/T17551b.hs b/testsuite/tests/overloadedrecflds/should_run/T17551b.hs
new file mode 100644
index 0000000000..c78da2b23c
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_run/T17551b.hs
@@ -0,0 +1,14 @@
+{-# LANGUAGE DuplicateRecordFields #-}
+{-# LANGUAGE TemplateHaskell #-}
+
+module Main where
+
+data Foo = Foo { foo :: Int, biz :: Bool }
+data Bar = Bar { foo :: Int }
+
+main :: IO ()
+main = print $
+ $$( [|| \ ( Bar { foo } ) -> foo ||] ) ( Bar 3 )
+ + case $$( [|| \ r -> r { foo = 2, biz = False } ||] ) ( Foo 1 False ) of
+ Foo { foo } -> foo
+
diff --git a/testsuite/tests/overloadedrecflds/should_run/T17551b.stdout b/testsuite/tests/overloadedrecflds/should_run/T17551b.stdout
new file mode 100644
index 0000000000..7ed6ff82de
--- /dev/null
+++ b/testsuite/tests/overloadedrecflds/should_run/T17551b.stdout
@@ -0,0 +1 @@
+5
diff --git a/testsuite/tests/overloadedrecflds/should_run/all.T b/testsuite/tests/overloadedrecflds/should_run/all.T
index ce4bbfd728..b3a08e7138 100644
--- a/testsuite/tests/overloadedrecflds/should_run/all.T
+++ b/testsuite/tests/overloadedrecflds/should_run/all.T
@@ -18,3 +18,4 @@ test('hasfieldrun02', normal, compile_and_run, [''])
test('T12243', normal, compile_and_run, [''])
test('T11228', normal, compile_and_run, [''])
test('T11671_run', normal, compile_and_run, [''])
+test('T17551b', [req_th], compile_and_run, [''])
diff --git a/testsuite/tests/parser/should_compile/T14189.stderr b/testsuite/tests/parser/should_compile/T14189.stderr
index caede8b720..1bd38be52a 100644
--- a/testsuite/tests/parser/should_compile/T14189.stderr
+++ b/testsuite/tests/parser/should_compile/T14189.stderr
@@ -186,14 +186,14 @@
(L
(SrcSpanAnn (EpAnnNotUsed) { T14189.hs:3:3-15 })
(IEThingWith
- [(L
- { T14189.hs:3:11 }
- (FieldLabel
- (FieldLabelString
- {FastString: "f"})
- (NoDuplicateRecordFields)
- (FieldSelectors)
- {Name: T14189.f}))]
+ (EpAnn
+ (Anchor
+ { T14189.hs:3:3-8 }
+ (UnchangedAnchor))
+ [(AddEpAnn AnnOpenP (EpaSpan { T14189.hs:3:10 }))
+ ,(AddEpAnn AnnCloseP (EpaSpan { T14189.hs:3:15 }))]
+ (EpaComments
+ []))
(L
(SrcSpanAnn (EpAnnNotUsed) { T14189.hs:3:3-8 })
(IEName
@@ -203,6 +203,21 @@
{Name: T14189.MyType})))
(NoIEWildcard)
[(L
+ (SrcSpanAnn (EpAnn
+ (Anchor
+ { T14189.hs:3:11 }
+ (UnchangedAnchor))
+ (AnnListItem
+ [(AddCommaAnn
+ (EpaSpan { T14189.hs:3:12 }))])
+ (EpaComments
+ [])) { T14189.hs:3:11 })
+ (IEName
+ (NoExtField)
+ (L
+ (SrcSpanAnn (EpAnnNotUsed) { T14189.hs:3:11 })
+ {Name: T14189.f})))
+ ,(L
(SrcSpanAnn (EpAnnNotUsed) { T14189.hs:3:13-14 })
(IEName
(NoExtField)
@@ -211,17 +226,9 @@
{Name: T14189.NT})))]))
[(AvailTC
{Name: T14189.MyType}
- [(NormalGreName
- {Name: T14189.MyType})
- ,(NormalGreName
- {Name: T14189.NT})
- ,(FieldGreName
- (FieldLabel
- (FieldLabelString
- {FastString: "f"})
- (NoDuplicateRecordFields)
- (FieldSelectors)
- {Name: T14189.f}))])])])
+ [{Name: T14189.MyType}
+ ,{Name: T14189.f}
+ ,{Name: T14189.NT}])])])
(Nothing)))
diff --git a/testsuite/tests/patsyn/should_fail/mixed-pat-syn-record-sels.stderr b/testsuite/tests/patsyn/should_fail/mixed-pat-syn-record-sels.stderr
index 934a55a87e..3c20c90285 100644
--- a/testsuite/tests/patsyn/should_fail/mixed-pat-syn-record-sels.stderr
+++ b/testsuite/tests/patsyn/should_fail/mixed-pat-syn-record-sels.stderr
@@ -1,5 +1,4 @@
mixed-pat-syn-record-sels.hs:9:9: error: [GHC-14392]
- • No constructor has all these fields: ‘a’, ‘b’
- • In the expression: x {a = True, b = False}
- In an equation for ‘foo’: foo x = x {a = True, b = False}
+ Invalid record update.
+ No constructor in scope has all of the following fields: ‘a’, ‘b’
diff --git a/testsuite/tests/patsyn/should_fail/records-mixing-fields.stderr b/testsuite/tests/patsyn/should_fail/records-mixing-fields.stderr
index 77901b9eee..9829eef3c3 100644
--- a/testsuite/tests/patsyn/should_fail/records-mixing-fields.stderr
+++ b/testsuite/tests/patsyn/should_fail/records-mixing-fields.stderr
@@ -1,14 +1,5 @@
-records-mixing-fields.hs:10:14: error: [GHC-40887]
- • Cannot use a mixture of pattern synonym and record selectors
- Record selectors defined by ‘MyRec’: qux
- Pattern synonym selectors defined by ‘HisRec’: f1
- • In the expression: a {f1 = 1, qux = "two"}
- In an equation for ‘updater1’: updater1 a = a {f1 = 1, qux = "two"}
-
-records-mixing-fields.hs:12:14: error: [GHC-40887]
- • Cannot use a mixture of pattern synonym and record selectors
- Record selectors defined by ‘MyRec’: foo
- Pattern synonym selectors defined by ‘HisRec’: f1
- • In the expression: a {f1 = 1, foo = 2}
- In an equation for ‘updater2’: updater2 a = a {f1 = 1, foo = 2}
+records-mixing-fields.hs:10:14: error: [GHC-14392]
+ Invalid record update.
+ No constructor in scope has all of the following fields:
+ ‘f1’, ‘qux’
diff --git a/testsuite/tests/perf/compiler/Makefile b/testsuite/tests/perf/compiler/Makefile
index 33d2878db7..762883b0b4 100644
--- a/testsuite/tests/perf/compiler/Makefile
+++ b/testsuite/tests/perf/compiler/Makefile
@@ -32,4 +32,3 @@ MultiLayerModulesTH_OneShot_Prep: MultiLayerModulesTH_Make_Prep
InstanceMatching:
./genMatchingTest 0
'$(TEST_HC)' $(TEST_HC_OPTS) -fno-code -fwrite-interface Defs.hs
-
diff --git a/testsuite/tests/perf/compiler/all.T b/testsuite/tests/perf/compiler/all.T
index 96d30e8017..37a6fdb2f9 100644
--- a/testsuite/tests/perf/compiler/all.T
+++ b/testsuite/tests/perf/compiler/all.T
@@ -660,3 +660,12 @@ test ('InfiniteListFusion',
[collect_stats('bytes allocated',2), when(arch('i386'), skip), js_broken(22576)],
compile_and_run,
['-O2 -package ghc'])
+
+# Track performance of record update renaming/typechecking
+test('RecordUpdPerf',
+ [ collect_compiler_stats('bytes allocated',2),
+ pre_cmd('./genRecordUpdPerf'),
+ extra_files(['genRecordUpdPerf']),
+ ],
+ multimod_compile,
+ ['RecordUpdPerf', '-fno-code -v0'])
diff --git a/testsuite/tests/perf/compiler/genRecordUpdPerf b/testsuite/tests/perf/compiler/genRecordUpdPerf
new file mode 100755
index 0000000000..2ccbb67407
--- /dev/null
+++ b/testsuite/tests/perf/compiler/genRecordUpdPerf
@@ -0,0 +1,24 @@
+#!/usr/bin/env bash
+RECORDS=15
+FIELDS=20
+UPDATES_PER_RECORD=5
+echo "{-# LANGUAGE DuplicateRecordFields #-}" > RecordUpdPerf.hs
+echo "module RecordUpdPerf where" >> RecordUpdPerf.hs
+for r in $(seq -w 1 $RECORDS); do
+ echo "data R$r = MkR$r {" >> RecordUpdPerf.hs
+ for f in $(seq -w 1 $FIELDS); do
+ echo " r$f :: Int," >> RecordUpdPerf.hs
+ echo " s${r}_$f :: Int," >> RecordUpdPerf.hs
+ done
+ echo " t :: Bool }" >> RecordUpdPerf.hs
+done
+
+for u in $(seq -w 1 $UPDATES_PER_RECORD); do
+ for r in $(seq -w 1 $RECORDS); do
+ echo "f${r}_$u r = r {" >> RecordUpdPerf.hs
+ for f in $(seq -w 1 $FIELDS); do
+ echo " r$f = $u * $r * $f," >> RecordUpdPerf.hs
+ done
+ echo " s${r}_$FIELDS = $u + $r }" >> RecordUpdPerf.hs
+ done
+done
diff --git a/testsuite/tests/perf/compiler/hard_hole_fits.stderr b/testsuite/tests/perf/compiler/hard_hole_fits.stderr
index bfabc44219..694741f71d 100644
--- a/testsuite/tests/perf/compiler/hard_hole_fits.stderr
+++ b/testsuite/tests/perf/compiler/hard_hole_fits.stderr
@@ -492,10 +492,7 @@ hard_hole_fits.hs:38:33: warning: [GHC-88464] [-Wtyped-holes (in -Wdefault)]
• Found hole: _ :: Int
• In an equation for ‘testMe’: testMe (RecordUpd xru gl gls) = _
• Relevant bindings include
- gls :: Either
- [Language.Haskell.Syntax.Pat.LHsRecUpdField GhcPs]
- [LHsRecUpdProj GhcPs]
- (bound at hard_hole_fits.hs:38:26)
+ gls :: LHsRecUpdFields GhcPs (bound at hard_hole_fits.hs:38:26)
gl :: LHsExpr GhcPs (bound at hard_hole_fits.hs:38:23)
xru :: Language.Haskell.Syntax.Extension.XRecordUpd GhcPs
(bound at hard_hole_fits.hs:38:19)
diff --git a/testsuite/tests/plugins/static-plugins.stdout b/testsuite/tests/plugins/static-plugins.stdout
index 5da8e9bee8..98d70197cd 100644
--- a/testsuite/tests/plugins/static-plugins.stdout
+++ b/testsuite/tests/plugins/static-plugins.stdout
@@ -5,9 +5,9 @@ interfacePlugin: GHC.Base
interfacePlugin: GHC.Float
interfacePlugin: GHC.Prim.Ext
interfacePlugin: System.IO
-typeCheckPlugin (rn)
interfacePlugin: GHC.Types
interfacePlugin: GHC.Show
+typeCheckPlugin (rn)
interfacePlugin: GHC.TopHandler
typeCheckPlugin (tc)
interfacePlugin: GHC.CString
diff --git a/testsuite/tests/rename/should_compile/T22122.hs b/testsuite/tests/rename/should_compile/T22122.hs
new file mode 100644
index 0000000000..25f8377e96
--- /dev/null
+++ b/testsuite/tests/rename/should_compile/T22122.hs
@@ -0,0 +1,18 @@
+{-# LANGUAGE DuplicateRecordFields #-}
+{-# LANGUAGE NoFieldSelectors #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE TemplateHaskell #-}
+
+module T22122 where
+
+import T22122_aux ( data_decls, record_upds )
+
+-- This test checks that we can handle record declarations and updates
+-- when the field 'Name's share the same underlying string.
+
+-- data D1 = MkD1 { fld1 :: Char, fld2 :: String }
+-- data D2 = MkD2A { fld1 :: Char } | MkD2B { fld2 :: String }
+$(return data_decls)
+
+-- rec_upd r = r { fld1 = 'c', fld2 = "foo" }
+$(return record_upds)
diff --git a/testsuite/tests/rename/should_compile/T22122_aux.hs b/testsuite/tests/rename/should_compile/T22122_aux.hs
new file mode 100644
index 0000000000..b62aaa5840
--- /dev/null
+++ b/testsuite/tests/rename/should_compile/T22122_aux.hs
@@ -0,0 +1,68 @@
+{-# LANGUAGE DeriveTraversable #-}
+{-# LANGUAGE DerivingStrategies #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE TemplateHaskell #-}
+
+module T22122_aux where
+
+import Language.Haskell.TH.Syntax
+ ( Name, Type(ConT), Lit(CharL, StringL)
+ , Dec(DataD, FunD), Con(RecC), Exp(LitE, VarE, RecUpdE), Pat(VarP)
+ , Clause(Clause), Body(NormalB)
+ , Bang(..), SourceUnpackedness(..), SourceStrictness(..)
+ , newNameIO )
+import System.IO.Unsafe
+ ( unsafePerformIO )
+
+
+data Names a
+ = Names { d1_name, d2_name
+ , mkd1_name, mkd2a_name, mkd2b_name
+ , d1_fld1_name, d1_fld2_name, d2_fld1_name, d2_fld2_name
+ , upd_name, upd_var_name :: a }
+ deriving stock ( Functor, Foldable, Traversable )
+
+string_names :: Names String
+string_names =
+ Names
+ { d1_name = "D1"
+ , d2_name = "D2"
+ , mkd1_name = "MkD1"
+ , mkd2a_name = "MkD2A"
+ , mkd2b_name = "MkD2B"
+ , d1_fld1_name = "fld" -- these are deliberately the same,
+ , d1_fld2_name = "fld" -- to check that we correctly use the exact Names
+ , d2_fld1_name = "fld" -- in a record update, and not simply the
+ , d2_fld2_name = "fld" -- field label strings
+ , upd_name = "upd"
+ , upd_var_name = "r"
+ }
+
+names :: Names Name
+names = unsafePerformIO $ traverse newNameIO string_names
+
+noBang :: Bang
+noBang = Bang NoSourceUnpackedness NoSourceStrictness
+
+-- data D1 = MkD1 { fld1 :: Char, fld2 :: String }
+-- data D2 = MkD2A { fld1 :: Char } | MkD2B { fld2 :: String }
+data_decls :: [ Dec ]
+data_decls = [ d1, d2 ]
+ where
+ Names { .. } = names
+ d1 = DataD [] d1_name [] Nothing [mkd1] []
+ d2 = DataD [] d2_name [] Nothing [mkd2_a, mkd2_b] []
+ mkd1 = RecC mkd1_name [(d1_fld1_name, noBang, ConT ''Char), (d1_fld2_name, noBang, ConT ''String)]
+ mkd2_a = RecC mkd2a_name [(d2_fld1_name, noBang, ConT ''Char)]
+ mkd2_b = RecC mkd2b_name [(d2_fld2_name, noBang, ConT ''String)]
+
+-- upd r = r { fld1 = 'c', fld2 = "foo" }
+record_upds :: [ Dec ]
+record_upds = [ rec_upd ]
+ where
+ Names { .. } = names
+ rec_upd = FunD upd_name [upd_clause]
+ upd_clause = Clause [VarP upd_var_name] (NormalB rec_upd_body) []
+ rec_upd_body = RecUpdE (VarE upd_var_name)
+ [ (d1_fld1_name, LitE (CharL 'c'))
+ , (d1_fld2_name, LitE (StringL "foo")) ]
diff --git a/testsuite/tests/rename/should_compile/all.T b/testsuite/tests/rename/should_compile/all.T
index ba05c88357..55f58fcebc 100644
--- a/testsuite/tests/rename/should_compile/all.T
+++ b/testsuite/tests/rename/should_compile/all.T
@@ -208,3 +208,4 @@ test('GADTSymbolicRecordRecordWildcard', normal, compile, [''])
test('ImportNullaryRecordWildcard', [extra_files(['NullaryRecordWildcard.hs', 'NullaryRecordRecordWildcard.hs'])], multimod_compile, ['ImportNullaryRecordWildcard', '-v0'])
test('GHCINullaryRecordWildcard', combined_output, ghci_script, ['GHCINullaryRecordWildcard.script'])
test('GHCIImplicitImportNullaryRecordWildcard', combined_output, ghci_script, ['GHCIImplicitImportNullaryRecordWildcard.script'])
+test('T22122', [expect_broken(22122), extra_files(['T22122_aux.hs'])], multimod_compile, ['T22122', '-v0'])
diff --git a/testsuite/tests/rename/should_fail/T11167_ambig.stderr b/testsuite/tests/rename/should_fail/T11167_ambig.stderr
index 8c9c6a7848..74c7064414 100644
--- a/testsuite/tests/rename/should_fail/T11167_ambig.stderr
+++ b/testsuite/tests/rename/should_fail/T11167_ambig.stderr
@@ -2,15 +2,15 @@
T11167_ambig.hs:10:13: error:
Ambiguous occurrence ‘runContT’
It could refer to
- either the field ‘runContT’ of record ‘ContT'’,
- defined at T11167_ambig.hs:7:32
- or the field ‘runContT’ of record ‘ContT’,
+ either the field ‘runContT’ of record ‘ContT’,
defined at T11167_ambig.hs:6:30
+ or the field ‘runContT’ of record ‘ContT'’,
+ defined at T11167_ambig.hs:7:32
T11167_ambig.hs:17:9: error:
Ambiguous occurrence ‘runContT’
It could refer to
- either the field ‘runContT’ of record ‘ContT'’,
- defined at T11167_ambig.hs:7:32
- or the field ‘runContT’ of record ‘ContT’,
+ either the field ‘runContT’ of record ‘ContT’,
defined at T11167_ambig.hs:6:30
+ or the field ‘runContT’ of record ‘ContT'’,
+ defined at T11167_ambig.hs:7:32
diff --git a/testsuite/tests/rename/should_fail/T12681.stderr b/testsuite/tests/rename/should_fail/T12681.stderr
index 3a48d80c17..6b57b8517b 100644
--- a/testsuite/tests/rename/should_fail/T12681.stderr
+++ b/testsuite/tests/rename/should_fail/T12681.stderr
@@ -1,4 +1,5 @@
T12681.hs:4:17: error: [GHC-76037]
Not in scope: ‘a’
- Suggested fix: Perhaps use ‘T12681a.a’ (imported from T12681a)
+ Suggested fix:
+ Perhaps use record field of A ‘T12681a.a’ (imported from T12681a)
diff --git a/testsuite/tests/rename/should_fail/T19843f.stderr b/testsuite/tests/rename/should_fail/T19843f.stderr
index c7c4d5dc58..4cf8e47089 100644
--- a/testsuite/tests/rename/should_fail/T19843f.stderr
+++ b/testsuite/tests/rename/should_fail/T19843f.stderr
@@ -1,8 +1,4 @@
-T19843f.hs:8:12: error: [GHC-76037]
- Not in scope: ‘mup’
- Suggested fix: Perhaps use ‘mop’ (line 5)
-
-T19843f.hs:10:10: error: [GHC-76037]
- Not in scope: ‘mup’
- Suggested fix: Perhaps use ‘mop’ (line 5)
+T19843f.hs:8:12: error: [GHC-22385]
+ Not in scope: record field ‘mup’
+ Suggested fix: Perhaps use record field of A ‘mop’ (line 5)
diff --git a/testsuite/tests/rename/should_fail/T19843g.stderr b/testsuite/tests/rename/should_fail/T19843g.stderr
index 78ee13eadf..e6441413be 100644
--- a/testsuite/tests/rename/should_fail/T19843g.stderr
+++ b/testsuite/tests/rename/should_fail/T19843g.stderr
@@ -1,4 +1,4 @@
-T19843g.hs:10:12: error: [GHC-76037]
- Not in scope: ‘mup’
- Suggested fix: Perhaps use ‘mop’ (line 7)
+T19843g.hs:10:12: error: [GHC-22385]
+ Not in scope: record field ‘mup’
+ Suggested fix: Perhaps use record field of A ‘mop’ (line 7)
diff --git a/testsuite/tests/rename/should_fail/T19843h.stderr b/testsuite/tests/rename/should_fail/T19843h.stderr
index 43cf59befd..55d3fcdd96 100644
--- a/testsuite/tests/rename/should_fail/T19843h.stderr
+++ b/testsuite/tests/rename/should_fail/T19843h.stderr
@@ -2,7 +2,7 @@
T19843h.hs:14:7: error: [GHC-39999]
• No instance for ‘GHC.Records.HasField "mup" r4 a4’
arising from selecting the field ‘mup’
- Perhaps use ‘mop’ (line 11)
+ Perhaps use record field of A ‘mop’ (line 11)
• In the expression: undefined.mup
In an equation for ‘foo’: foo = undefined.mup
@@ -27,7 +27,7 @@ T19843h.hs:20:8: error: [GHC-39999]
T19843h.hs:24:8: error: [GHC-39999]
• No instance for ‘GHC.Records.HasField "getAll" r0 a0’
arising from selecting the field ‘getAll’
- Perhaps use ‘getAlt’ (imported from Data.Monoid)
+ Perhaps use record field of Alt ‘getAlt’ (imported from Data.Monoid)
Perhaps you want to add ‘getAll’ to the import list
in the import of ‘Data.Monoid’ (T19843h.hs:9:1-28).
• In the expression: undefined.getAll
diff --git a/testsuite/tests/rename/should_fail/T21605a.stderr b/testsuite/tests/rename/should_fail/T21605a.stderr
index 7be47098df..ce199cfb8f 100644
--- a/testsuite/tests/rename/should_fail/T21605a.stderr
+++ b/testsuite/tests/rename/should_fail/T21605a.stderr
@@ -4,7 +4,6 @@ T21605a.hs:5:13: error: [GHC-76037]
NB: the module ‘Prelude’ does not export ‘true’.
Suggested fix:
Perhaps use one of these:
+ data constructor ‘Prelude.True’ (imported from Prelude),
type constructor or class ‘Prelude.Num’ (imported from Prelude),
- type constructor or class ‘Prelude.Ord’ (imported from Prelude),
- type constructor or class ‘Prelude.Enum’ (imported from Prelude)
-
+ type constructor or class ‘Prelude.Ord’ (imported from Prelude)
diff --git a/testsuite/tests/rename/should_fail/T21605d.stderr b/testsuite/tests/rename/should_fail/T21605d.stderr
index 3db644aa93..0c0c3975af 100644
--- a/testsuite/tests/rename/should_fail/T21605d.stderr
+++ b/testsuite/tests/rename/should_fail/T21605d.stderr
@@ -1,8 +1,9 @@
-T21605d.hs:3:9: [GHC-37479]
+
+T21605d.hs:3:9: error: [GHC-37479]
‘Prelude.id’ is a term-level binding
and can not be used at the type level.
Suggested fix:
Perhaps use one of these:
+ data constructor ‘Prelude.EQ’ (imported from Prelude),
type constructor or class ‘Prelude.Eq’ (imported from Prelude),
- type constructor or class ‘Prelude.IO’ (imported from Prelude),
- type constructor or class ‘Prelude.Ord’ (imported from Prelude) \ No newline at end of file
+ data constructor ‘Prelude.GT’ (imported from Prelude)
diff --git a/testsuite/tests/rename/should_fail/T7943.hs b/testsuite/tests/rename/should_fail/T7943.hs
index a1a99d508a..335cb350c7 100644
--- a/testsuite/tests/rename/should_fail/T7943.hs
+++ b/testsuite/tests/rename/should_fail/T7943.hs
@@ -1,4 +1,4 @@
module T7943 where
data Foo = A { bar :: String }
- | B String { bar :: String }
+ | B String { bar :: String }
diff --git a/testsuite/tests/rename/should_fail/T7943.stderr b/testsuite/tests/rename/should_fail/T7943.stderr
index 3100928e51..352d4c1f40 100644
--- a/testsuite/tests/rename/should_fail/T7943.stderr
+++ b/testsuite/tests/rename/should_fail/T7943.stderr
@@ -1,6 +1,3 @@
-T7943.hs:4:22: error: [GHC-89246]
- • Record syntax is illegal here: {bar :: String}
- • In the type ‘{bar :: String}’
- In the definition of data constructor ‘B’
- In the data declaration for ‘Foo’
+T7943.hs:4:21: error: [GHC-89246]
+ Record syntax is illegal here: {bar :: String}
diff --git a/testsuite/tests/rename/should_fail/T9077.stderr b/testsuite/tests/rename/should_fail/T9077.stderr
index a3a9d49ece..c20800b12f 100644
--- a/testsuite/tests/rename/should_fail/T9077.stderr
+++ b/testsuite/tests/rename/should_fail/T9077.stderr
@@ -1,2 +1,2 @@
-T9077.hs:3:12: Record syntax is illegal here: {}
+T9077.hs:3:12: error: [GHC-89246] Record syntax is illegal here: {}
diff --git a/testsuite/tests/rename/should_fail/T9156.stderr b/testsuite/tests/rename/should_fail/T9156.stderr
index 361ed379df..1dbfb9b02e 100644
--- a/testsuite/tests/rename/should_fail/T9156.stderr
+++ b/testsuite/tests/rename/should_fail/T9156.stderr
@@ -1,5 +1,3 @@
-T9156.hs:4:19:
- Multiple declarations of ‘f1’
- Declared at: T9156.hs:3:15
- T9156.hs:4:19
+T9156.hs:4:19: error: [GHC-85524]
+ Duplicate field name ‘f1’ in record declaration
diff --git a/testsuite/tests/rename/should_fail/T9156_DF.hs b/testsuite/tests/rename/should_fail/T9156_DF.hs
new file mode 100644
index 0000000000..aa55756c71
--- /dev/null
+++ b/testsuite/tests/rename/should_fail/T9156_DF.hs
@@ -0,0 +1,10 @@
+{-# LANGUAGE TypeFamilies #-}
+
+module T9156_DF where
+
+data X = MkX
+
+data family D a
+data instance D Int
+ = D1 { f1 :: X }
+ | D2 { f1 :: X, f2 :: X, f1 :: X }
diff --git a/testsuite/tests/rename/should_fail/T9156_DF.stderr b/testsuite/tests/rename/should_fail/T9156_DF.stderr
new file mode 100644
index 0000000000..61e2af19a4
--- /dev/null
+++ b/testsuite/tests/rename/should_fail/T9156_DF.stderr
@@ -0,0 +1,3 @@
+
+T9156_DF.hs:10:29: error: [GHC-85524]
+ Duplicate field name ‘f1’ in record declaration
diff --git a/testsuite/tests/rename/should_fail/all.T b/testsuite/tests/rename/should_fail/all.T
index 2255117886..8d3029bd06 100644
--- a/testsuite/tests/rename/should_fail/all.T
+++ b/testsuite/tests/rename/should_fail/all.T
@@ -104,6 +104,7 @@ test('RnStaticPointersFail02', [], compile_fail, [''])
test('RnStaticPointersFail03', [], compile_fail, ['-dsuppress-uniques'])
test('T9006', [], multimod_compile_fail, ['T9006', '-v0'])
test('T9156', normal, compile_fail, [''])
+test('T9156_DF', normal, compile_fail, [''])
test('T9177', normal, compile_fail, [''])
test('T9177a', normal, compile_fail, [''])
test('T9436', normal, compile_fail, [''])
diff --git a/testsuite/tests/rename/should_fail/rn_dup.hs b/testsuite/tests/rename/should_fail/rn_dup.hs
index 927e15ff32..7c2fc3380e 100644
--- a/testsuite/tests/rename/should_fail/rn_dup.hs
+++ b/testsuite/tests/rename/should_fail/rn_dup.hs
@@ -12,7 +12,7 @@ data P = MkP { rf :: Int, rf :: Int }
data Q = MkQ { rf :: Int }
class C a where
- data CT a
+ data CT a
f :: CT a -> a
data CT a
f :: CT a -> a
diff --git a/testsuite/tests/rename/should_fail/rn_dup.stderr b/testsuite/tests/rename/should_fail/rn_dup.stderr
index 5c4246d8b6..907fc38fe8 100644
--- a/testsuite/tests/rename/should_fail/rn_dup.stderr
+++ b/testsuite/tests/rename/should_fail/rn_dup.stderr
@@ -9,14 +9,12 @@ rn_dup.hs:9:10: error:
Declared at: rn_dup.hs:7:10
rn_dup.hs:9:10
-rn_dup.hs:12:16: error:
- Multiple declarations of ‘rf’
- Declared at: rn_dup.hs:11:27
- rn_dup.hs:12:16
+rn_dup.hs:11:27: error: [GHC-85524]
+ Duplicate field name ‘rf’ in record declaration
rn_dup.hs:12:16: error:
Multiple declarations of ‘rf’
- Declared at: rn_dup.hs:11:16
+ Declared at: rn_dup.hs:11:27
rn_dup.hs:12:16
rn_dup.hs:17:3: error:
diff --git a/testsuite/tests/rename/should_fail/rnfail054.stderr b/testsuite/tests/rename/should_fail/rnfail054.stderr
index 04fff51118..3cb01c63da 100644
--- a/testsuite/tests/rename/should_fail/rnfail054.stderr
+++ b/testsuite/tests/rename/should_fail/rnfail054.stderr
@@ -1,5 +1,3 @@
-rnfail054.hs:6:13: error: [GHC-47535]
- • ‘foo’ is not a record selector
- • In the expression: x {foo = 1}
- In an equation for ‘foo’: foo x = x {foo = 1}
+rnfail054.hs:6:13: error: [GHC-22385]
+ Not in scope: record field ‘foo’
diff --git a/testsuite/tests/rep-poly/T20113.stderr b/testsuite/tests/rep-poly/T20113.stderr
index 3d52dbe734..1358d188ea 100644
--- a/testsuite/tests/rep-poly/T20113.stderr
+++ b/testsuite/tests/rep-poly/T20113.stderr
@@ -4,12 +4,11 @@ T20113.hs:7:35: error: [GHC-55287]
does not have a fixed runtime representation.
Its type is:
a :: TYPE rep
- • In the pattern: MkY {y_fld = $sel:y_fld:MkY}
- In an equation for ‘T20113.$sel:y_fld:MkY’:
- T20113.$sel:y_fld:MkY MkY {y_fld = $sel:y_fld:MkY} = $sel:y_fld:MkY
+ • In the pattern: MkY {y_fld = y_fld}
+ In an equation for ‘y_fld’: y_fld MkY {y_fld = y_fld} = y_fld
T20113.hs:7:35: error: [GHC-55287]
- The first pattern in the equation for ‘$sel:y_fld:MkY’
+ The first pattern in the equation for ‘y_fld’
does not have a fixed runtime representation.
Its type is:
Y a :: TYPE rep
diff --git a/testsuite/tests/th/T10279.stderr b/testsuite/tests/th/T10279.stderr
index 5993cdbf82..4a06b1d775 100644
--- a/testsuite/tests/th/T10279.stderr
+++ b/testsuite/tests/th/T10279.stderr
@@ -4,5 +4,8 @@ T10279.hs:10:9: error: [GHC-52243]
no unit id matching ‘rts-1.0.2’ was found
(This unit ID looks like the source package ID;
the real unit ID is ‘rts’)
- • In the expression: rts-1.0.2:A.Foo
- In an equation for ‘blah’: blah = (rts-1.0.2:A.Foo)
+ • In the untyped splice:
+ $(conE
+ (Name
+ (mkOccName "Foo")
+ (NameG VarName (mkPkgName "rts-1.0.2") (mkModName "A"))))
diff --git a/testsuite/tests/th/T10828.hs b/testsuite/tests/th/T10828.hs
index ffb4525f6a..d73b5015ae 100644
--- a/testsuite/tests/th/T10828.hs
+++ b/testsuite/tests/th/T10828.hs
@@ -6,6 +6,7 @@ module T10828 where
import Language.Haskell.TH hiding (Type)
import System.IO
import Data.Kind (Type)
+import qualified Data.List.NonEmpty as NE ( singleton )
$( do { decl <- [d| data family D a :: Type -> Type
data instance D Int Bool :: Type where
@@ -33,7 +34,7 @@ $( return
[ DataD [] (mkName "T")
[ PlainTV (mkName "a") () ]
(Just StarT)
- [ GadtC [(mkName "MkT")]
+ [ GadtC (NE.singleton (mkName "MkT"))
[ ( Bang NoSourceUnpackedness NoSourceStrictness
, VarT (mkName "a")
)
@@ -46,7 +47,7 @@ $( return
, ForallC [PlainTV (mkName "a") SpecifiedSpec, PlainTV (mkName "b") SpecifiedSpec]
[AppT (AppT EqualityT (VarT $ mkName "a" ) )
(ConT $ mkName "Int") ] $
- RecGadtC [(mkName "MkC")]
+ RecGadtC (NE.singleton (mkName "MkC"))
[ ( mkName "foo"
, Bang NoSourceUnpackedness NoSourceStrictness
, VarT (mkName "a")
diff --git a/testsuite/tests/th/T10828b.hs b/testsuite/tests/th/T10828b.hs
index 03706d6b7c..36e91eb11a 100644
--- a/testsuite/tests/th/T10828b.hs
+++ b/testsuite/tests/th/T10828b.hs
@@ -4,6 +4,7 @@ module T10828b where
import Language.Haskell.TH
import System.IO
+import qualified Data.List.NonEmpty as NE ( singleton )
-- attempting to mix GADT and normal constructors
$( return
@@ -23,7 +24,7 @@ $( return
[AppT (AppT EqualityT (VarT $ mkName "a" ) )
(ConT $ mkName "Int") ] $
RecGadtC
- [ (mkName "MkC")]
+ (NE.singleton (mkName "MkC"))
[ ( mkName "foo"
, Bang NoSourceUnpackedness NoSourceStrictness
, VarT (mkName "a")
diff --git a/testsuite/tests/th/T10828b.stderr b/testsuite/tests/th/T10828b.stderr
index 357c86c458..6e78ca9087 100644
--- a/testsuite/tests/th/T10828b.stderr
+++ b/testsuite/tests/th/T10828b.stderr
@@ -1,5 +1,5 @@
-T10828b.hs:9:2: error: [GHC-24104]
+T10828b.hs:10:2: error: [GHC-24104]
Cannot mix GADT constructors with Haskell 98 constructors
When splicing a TH declaration:
data T a :: *
diff --git a/testsuite/tests/th/T11345.hs b/testsuite/tests/th/T11345.hs
index 2288cdad15..11de6d8bd5 100644
--- a/testsuite/tests/th/T11345.hs
+++ b/testsuite/tests/th/T11345.hs
@@ -5,6 +5,7 @@
module Main (main) where
import Language.Haskell.TH
+import qualified Data.List.NonEmpty as NE ( singleton )
infixr 7 :***:
data GADT a where
@@ -16,11 +17,11 @@ $(do gadtName <- newName "GADT2"
infixName <- newName ":****:"
a <- newName "a"
return [ DataD [] gadtName [KindedTV a () StarT] Nothing
- [ GadtC [prefixName]
+ [ GadtC (NE.singleton prefixName)
[ (Bang NoSourceUnpackedness NoSourceStrictness,ConT ''Int)
, (Bang NoSourceUnpackedness NoSourceStrictness,ConT ''Int)
] (AppT (ConT gadtName) (ConT ''Int))
- , GadtC [infixName]
+ , GadtC (NE.singleton infixName)
[ (Bang NoSourceUnpackedness NoSourceStrictness,ConT ''Int)
, (Bang NoSourceUnpackedness NoSourceStrictness,ConT ''Int)
] (AppT (ConT gadtName) (ConT ''Int))
diff --git a/testsuite/tests/th/T11941.stderr b/testsuite/tests/th/T11941.stderr
index 39a25c7425..7a66251092 100644
--- a/testsuite/tests/th/T11941.stderr
+++ b/testsuite/tests/th/T11941.stderr
@@ -1,7 +1,7 @@
-T11941.hs:7:30: error: [GHC-76037]
- Not in scope: ‘getFrst’
+T11941.hs:7:30: error: [GHC-22385]
+ Not in scope: record field ‘getFrst’
Suggested fix:
Perhaps use one of these:
- ‘getFirst’ (imported from Data.Monoid),
- ‘getLast’ (imported from Data.Monoid)
+ record field of First ‘getFirst’ (imported from Data.Monoid),
+ record field of Last ‘getLast’ (imported from Data.Monoid)
diff --git a/testsuite/tests/th/T17379a.hs b/testsuite/tests/th/T17379a.hs
deleted file mode 100644
index 66702bb9b8..0000000000
--- a/testsuite/tests/th/T17379a.hs
+++ /dev/null
@@ -1,8 +0,0 @@
-{-# LANGUAGE TemplateHaskell #-}
-{-# LANGUAGE GADTSyntax #-}
-
-module T17379a where
-
-import Language.Haskell.TH
-
-$(let typ = mkName "T" in pure [ DataD [] typ [] Nothing [GadtC [] [] (ConT typ)] [] ])
diff --git a/testsuite/tests/th/T17379a.stderr b/testsuite/tests/th/T17379a.stderr
deleted file mode 100644
index ebb899e750..0000000000
--- a/testsuite/tests/th/T17379a.stderr
+++ /dev/null
@@ -1,4 +0,0 @@
-
-T17379a.hs:8:2: error: [GHC-38140]
- GadtC must have at least one constructor name
- When splicing a TH declaration: data T where :: T
diff --git a/testsuite/tests/th/T17379b.hs b/testsuite/tests/th/T17379b.hs
deleted file mode 100644
index c83d180d18..0000000000
--- a/testsuite/tests/th/T17379b.hs
+++ /dev/null
@@ -1,8 +0,0 @@
-{-# LANGUAGE TemplateHaskell #-}
-{-# LANGUAGE GADTSyntax #-}
-
-module T17379b where
-
-import Language.Haskell.TH
-
-$(let typ = mkName "T" in pure [ DataD [] typ [] Nothing [RecGadtC [] [] (ConT typ)] [] ])
diff --git a/testsuite/tests/th/T17379b.stderr b/testsuite/tests/th/T17379b.stderr
deleted file mode 100644
index 9a4aabc250..0000000000
--- a/testsuite/tests/th/T17379b.stderr
+++ /dev/null
@@ -1,4 +0,0 @@
-
-T17379b.hs:8:2: error: [GHC-18816]
- RecGadtC must have at least one constructor name
- When splicing a TH declaration: data T where :: {} -> T
diff --git a/testsuite/tests/th/all.T b/testsuite/tests/th/all.T
index a4f948bc76..2b792da6e2 100644
--- a/testsuite/tests/th/all.T
+++ b/testsuite/tests/th/all.T
@@ -504,8 +504,6 @@ test('T17296', normal, compile, ['-v0'])
test('T17305', normal, compile, ['-v0'])
test('T17380', normal, compile_fail, [''])
test('T17394', normal, compile, ['-v0 -ddump-splices -dsuppress-uniques'])
-test('T17379a', normal, compile_fail, [''])
-test('T17379b', normal, compile_fail, [''])
test('T17461', normal, compile, ['-v0 -ddump-splices -dsuppress-uniques'])
test('T17511', normal, compile, [''])
test('T17608', normal, compile, ['-v0 -ddump-splices -dsuppress-uniques'])
diff --git a/testsuite/tests/typecheck/should_compile/QualifiedRecordUpdate.hs b/testsuite/tests/typecheck/should_compile/QualifiedRecordUpdate.hs
new file mode 100644
index 0000000000..3657ab4463
--- /dev/null
+++ b/testsuite/tests/typecheck/should_compile/QualifiedRecordUpdate.hs
@@ -0,0 +1,10 @@
+{-# LANGUAGE DuplicateRecordFields #-}
+
+module QualifiedRecordUpdate where
+
+import QualifiedRecordUpdate_aux ( R(fld1, fld2), S(fld1, fld2) )
+import qualified QualifiedRecordUpdate_aux as B ( R(fld1, fld2), S(fld1) )
+
+-- Unambiguous record update: the only record datatype in the B namespace
+-- which contains field fld2 is R.
+f r = r { B.fld1 = 3, B.fld2 = False }
diff --git a/testsuite/tests/typecheck/should_compile/QualifiedRecordUpdate_aux.hs b/testsuite/tests/typecheck/should_compile/QualifiedRecordUpdate_aux.hs
new file mode 100644
index 0000000000..c03abe277c
--- /dev/null
+++ b/testsuite/tests/typecheck/should_compile/QualifiedRecordUpdate_aux.hs
@@ -0,0 +1,6 @@
+{-# LANGUAGE DuplicateRecordFields #-}
+
+module QualifiedRecordUpdate_aux where
+
+data R = R { fld1 :: Int, fld2 :: Bool }
+data S = S { fld1 :: Int, fld2 :: Bool, fld3 :: Char }
diff --git a/testsuite/tests/typecheck/should_compile/T21443.hs b/testsuite/tests/typecheck/should_compile/T21443.hs
new file mode 100644
index 0000000000..7dbd451c09
--- /dev/null
+++ b/testsuite/tests/typecheck/should_compile/T21443.hs
@@ -0,0 +1,10 @@
+{-# LANGUAGE DuplicateRecordFields #-}
+
+module T21443 where
+
+data R = MkR1 { foo :: Int }
+ | MkR2 { bar :: Int }
+
+data S = MkS { foo :: Int, bar :: Int }
+
+blah x = x { foo = 5, bar = 6 }
diff --git a/testsuite/tests/typecheck/should_compile/all.T b/testsuite/tests/typecheck/should_compile/all.T
index 327dd93675..4c200961f4 100644
--- a/testsuite/tests/typecheck/should_compile/all.T
+++ b/testsuite/tests/typecheck/should_compile/all.T
@@ -865,4 +865,8 @@ test('T22985a', normal, compile, ['-O'])
test('T22985b', normal, compile, [''])
test('T23018', normal, compile, [''])
test('T21909', normal, compile, [''])
-test('T21909b', normal, compile, ['']) \ No newline at end of file
+test('T21909b', normal, compile, [''])
+test('T21443', normal, compile, [''])
+test('QualifiedRecordUpdate',
+ [ extra_files(['QualifiedRecordUpdate_aux.hs']) ]
+ , multimod_compile, ['QualifiedRecordUpdate', '-v0'])
diff --git a/testsuite/tests/typecheck/should_fail/T12035.hs b/testsuite/tests/typecheck/should_fail/T12035.hs
index 87e20ff07c..cd12eee917 100644
--- a/testsuite/tests/typecheck/should_fail/T12035.hs
+++ b/testsuite/tests/typecheck/should_fail/T12035.hs
@@ -1,7 +1,7 @@
module T12035 where
import T12035a
type T = Bool
-y = f True
+--y = f True
-- This should error that 'type T = Int' doesn't match 'data T',
-- NOT that f expects argument of type T but got Bool.
diff --git a/testsuite/tests/typecheck/should_fail/T21444.hs b/testsuite/tests/typecheck/should_fail/T21444.hs
new file mode 100644
index 0000000000..28f2010dbd
--- /dev/null
+++ b/testsuite/tests/typecheck/should_fail/T21444.hs
@@ -0,0 +1,8 @@
+{-# LANGUAGE DuplicateRecordFields #-}
+
+module T21444 where
+
+data S = MkS { foo, bar, baz :: Int }
+data T = MkT { foo, bar, baz :: Int }
+
+blah x = x { foo = 1, bar = 2, baz = 3 }
diff --git a/testsuite/tests/typecheck/should_fail/T21444.stderr b/testsuite/tests/typecheck/should_fail/T21444.stderr
new file mode 100644
index 0000000000..cd4795c969
--- /dev/null
+++ b/testsuite/tests/typecheck/should_fail/T21444.stderr
@@ -0,0 +1,6 @@
+
+T21444.hs:8:10: error: [GHC-99339]
+ • Ambiguous record update with fields ‘foo’, ‘bar’ and ‘baz’
+ These fields appear in both datatypes ‘S’ and ‘T’
+ • In the expression: x {foo = 1, bar = 2, baz = 3}
+ In an equation for ‘blah’: blah x = x {foo = 1, bar = 2, baz = 3}
diff --git a/testsuite/tests/typecheck/should_fail/T7989.stderr b/testsuite/tests/typecheck/should_fail/T7989.stderr
index 7413b06648..f5271b2167 100644
--- a/testsuite/tests/typecheck/should_fail/T7989.stderr
+++ b/testsuite/tests/typecheck/should_fail/T7989.stderr
@@ -1,15 +1,4 @@
T7989.hs:6:7: error: [GHC-14392]
- • No constructor has all these fields: ‘a0’, ‘b0’
- • In the expression: x {a0 = 3, a1 = 2, b0 = 4, b1 = 5}
- In an equation for ‘f’: f x = x {a0 = 3, a1 = 2, b0 = 4, b1 = 5}
-
-T7989.hs:9:7: error: [GHC-14392]
- • No constructor has all these fields: ‘x’, ‘y’, ‘z’
- • In the expression: a {x = 0, y = 0, z = 0, v = 0}
- In an equation for ‘g’: g a = a {x = 0, y = 0, z = 0, v = 0}
-
-T7989.hs:11:7: error: [GHC-14392]
- • No constructor has all these fields: ‘x’, ‘a0’
- • In the expression: a {x = 0, a0 = 0}
- In an equation for ‘h’: h a = a {x = 0, a0 = 0}
+ Invalid record update.
+ No constructor in scope has all of the following fields: ‘a0’, ‘b0’
diff --git a/testsuite/tests/typecheck/should_fail/all.T b/testsuite/tests/typecheck/should_fail/all.T
index 209f292737..2afc480451 100644
--- a/testsuite/tests/typecheck/should_fail/all.T
+++ b/testsuite/tests/typecheck/should_fail/all.T
@@ -675,3 +675,4 @@ test('T19627', normal, compile_fail, [''])
test('PatSynExistential', normal, compile_fail, [''])
test('PatSynArity', normal, compile_fail, [''])
test('PatSynUnboundVar', normal, compile_fail, [''])
+test('T21444', normal, compile_fail, [''])
diff --git a/testsuite/tests/typecheck/should_fail/tcfail114.stderr b/testsuite/tests/typecheck/should_fail/tcfail114.stderr
index 7516ebb712..b751b31cd0 100644
--- a/testsuite/tests/typecheck/should_fail/tcfail114.stderr
+++ b/testsuite/tests/typecheck/should_fail/tcfail114.stderr
@@ -1,5 +1,3 @@
-tcfail114.hs:11:20: error: [GHC-47535]
- • ‘foo’ is not a record selector
- • In the expression: undefined {foo = ()}
- In an equation for ‘test’: test = undefined {foo = ()}
+tcfail114.hs:11:20: error: [GHC-22385]
+ Not in scope: record field ‘foo’
diff --git a/testsuite/tests/warnings/should_compile/DodgyExports01.stderr b/testsuite/tests/warnings/should_compile/DodgyExports01.stderr
index d3cae826ab..f916bcfaa4 100644
--- a/testsuite/tests/warnings/should_compile/DodgyExports01.stderr
+++ b/testsuite/tests/warnings/should_compile/DodgyExports01.stderr
@@ -1,5 +1,4 @@
DodgyExports01.hs:2:13: warning: [GHC-75356] [-Wdodgy-exports (in -Wextra)]
The export item ‘T(..)’ suggests that
- ‘T’ has (in-scope) constructors or class methods,
- but it has none
+ ‘T’ has (in-scope) constructors or record fields, but it has none
diff --git a/utils/check-exact/ExactPrint.hs b/utils/check-exact/ExactPrint.hs
index d4f1961176..04d0b831e6 100644
--- a/utils/check-exact/ExactPrint.hs
+++ b/utils/check-exact/ExactPrint.hs
@@ -3136,6 +3136,7 @@ instance (ExactPrint body)
-- ---------------------------------------------------------------------
+-- instance ExactPrint (HsRecUpdField GhcPs q) where
instance (ExactPrint (LocatedA body))
=> ExactPrint (HsFieldBind (LocatedAn NoEpAnns (AmbiguousFieldOcc GhcPs)) (LocatedA body)) where
getAnnotationEntry x = fromAnn (hfbAnn x)
@@ -3151,17 +3152,18 @@ instance (ExactPrint (LocatedA body))
return (HsFieldBind an0 f' arg' isPun)
-- ---------------------------------------------------------------------
-instance
- (ExactPrint (HsFieldBind (LocatedAn NoEpAnns (a GhcPs)) body),
- ExactPrint (HsFieldBind (LocatedAn NoEpAnns (b GhcPs)) body))
- => ExactPrint
- (Either [LocatedA (HsFieldBind (LocatedAn NoEpAnns (a GhcPs)) body)]
- [LocatedA (HsFieldBind (LocatedAn NoEpAnns (b GhcPs)) body)]) where
+instance ExactPrint (LHsRecUpdFields GhcPs) where
getAnnotationEntry = const NoEntryVal
setAnnotationAnchor a _ _ = a
- exact (Left rbinds) = Left <$> markAnnotated rbinds
- exact (Right pbinds) = Right <$> markAnnotated pbinds
+ exact flds@(RegularRecUpdFields { recUpdFields = rbinds }) = do
+ debugM $ "RegularRecUpdFields"
+ rbinds' <- markAnnotated rbinds
+ return $ flds { recUpdFields = rbinds' }
+ exact flds@(OverloadedRecUpdFields { olRecUpdFields = pbinds }) = do
+ debugM $ "OverloadedRecUpdFields"
+ pbinds' <- markAnnotated pbinds
+ return $ flds { olRecUpdFields = pbinds' }
-- ---------------------------------------------------------------------
diff --git a/utils/haddock b/utils/haddock
-Subproject 6f1b9093395f4b12298b8b785b855a637206f5f
+Subproject d19850b8046876e92dfef045d8a5558b951f165