summaryrefslogtreecommitdiff
path: root/compiler/Language/Haskell/Syntax
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 /compiler/Language/Haskell/Syntax
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 -------------------------
Diffstat (limited to 'compiler/Language/Haskell/Syntax')
-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
5 files changed, 47 insertions, 9 deletions
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
-