diff options
Diffstat (limited to 'compiler/GHC/Hs')
-rw-r--r-- | compiler/GHC/Hs/Decls.hs | 5 | ||||
-rw-r--r-- | compiler/GHC/Hs/Expr.hs | 36 | ||||
-rw-r--r-- | compiler/GHC/Hs/ImpExp.hs | 60 | ||||
-rw-r--r-- | compiler/GHC/Hs/Instances.hs | 8 | ||||
-rw-r--r-- | compiler/GHC/Hs/Pat.hs | 4 | ||||
-rw-r--r-- | compiler/GHC/Hs/Type.hs | 20 | ||||
-rw-r--r-- | compiler/GHC/Hs/Utils.hs | 250 |
7 files changed, 251 insertions, 132 deletions
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 |