diff options
author | Adam Gundry <adam@well-typed.com> | 2015-10-16 16:08:31 +0100 |
---|---|---|
committer | Adam Gundry <adam@well-typed.com> | 2015-10-16 16:27:53 +0100 |
commit | b1884b0e62f62e3c0859515c4137124ab0c9560e (patch) | |
tree | 9037ed61aeaf16b243c4b8542e3ef11f4abd7ee7 /compiler/hsSyn/HsPat.hs | |
parent | 808bbdf08058785ae5bc59b5b4f2b04951d4cbbf (diff) | |
download | haskell-b1884b0e62f62e3c0859515c4137124ab0c9560e.tar.gz |
Implement DuplicateRecordFields
This implements DuplicateRecordFields, the first part of the
OverloadedRecordFields extension, as described at
https://ghc.haskell.org/trac/ghc/wiki/Records/OverloadedRecordFields/DuplicateRecordFields
This includes fairly wide-ranging changes in order to allow multiple
records within the same module to use the same field names. Note that
it does *not* allow record selector functions to be used if they are
ambiguous, and it does not have any form of type-based disambiguation
for selectors (but it does for updates). Subsequent parts will make
overloading selectors possible using orthogonal extensions, as
described on the wiki pages. This part touches quite a lot of the
codebase, and requires changes to several GHC API datatypes in order
to distinguish between field labels (which may be overloaded) and
selector function names (which are always unique).
The Haddock submodule has been adapted to compile with the GHC API
changes, but it will need further work to properly support modules
that use the DuplicateRecordFields extension.
Test Plan: New tests added in testsuite/tests/overloadedrecflds; these
will be extended once the other parts are implemented.
Reviewers: goldfire, bgamari, simonpj, austin
Subscribers: sjcjoosten, haggholm, mpickering, bgamari, tibbe, thomie,
goldfire
Differential Revision: https://phabricator.haskell.org/D761
Diffstat (limited to 'compiler/hsSyn/HsPat.hs')
-rw-r--r-- | compiler/hsSyn/HsPat.hs | 103 |
1 files changed, 87 insertions, 16 deletions
diff --git a/compiler/hsSyn/HsPat.hs b/compiler/hsSyn/HsPat.hs index 09f669ca90..b37d836403 100644 --- a/compiler/hsSyn/HsPat.hs +++ b/compiler/hsSyn/HsPat.hs @@ -12,13 +12,18 @@ {-# LANGUAGE UndecidableInstances #-} -- Note [Pass sensitive types] -- in module PlaceHolder {-# LANGUAGE ConstraintKinds #-} +{-# LANGUAGE TypeFamilies #-} module HsPat ( Pat(..), InPat, OutPat, LPat, HsConDetails(..), HsConPatDetails, hsConPatArgs, - HsRecFields(..), HsRecField(..), LHsRecField, hsRecFields, + HsRecFields(..), HsRecField'(..), LHsRecField', + HsRecField, LHsRecField, + HsRecUpdField, LHsRecUpdField, + hsRecFields, hsRecFieldSel, hsRecFieldId, + hsRecUpdFieldId, hsRecUpdFieldOcc, hsRecUpdFieldRdr, mkPrefixConPat, mkCharLitPat, mkNilPat, @@ -34,7 +39,7 @@ import {-# SOURCE #-} HsExpr (SyntaxExpr, LHsExpr, HsSplice, pprLExpr -- friends: import HsBinds import HsLit -import PlaceHolder ( PostTc,DataId ) +import PlaceHolder -- ( PostRn,PostTc,DataId ) import HsTypes import TcEvidence import BasicTypes @@ -42,6 +47,7 @@ import BasicTypes import PprCore ( {- instance OutputableBndr TyVar -} ) import TysWiredIn import Var +import RdrName ( RdrName ) import ConLike import DataCon import TyCon @@ -49,9 +55,9 @@ import Outputable import Type import SrcLoc import FastString +import Maybes -- libraries: import Data.Data hiding (TyCon,Fixity) -import Data.Maybe type InPat id = LPat id -- No 'Out' constructors type OutPat id = LPat id -- No 'In' constructors @@ -233,7 +239,8 @@ data HsRecFields id arg -- A bunch of record fields -- Used for both expressions and patterns = HsRecFields { rec_flds :: [LHsRecField id arg], rec_dotdot :: Maybe Int } -- Note [DotDot fields] - deriving (Data, Typeable) + deriving (Typeable) +deriving instance (DataId id, Data arg) => Data (HsRecFields id arg) -- Note [DotDot fields] -- ~~~~~~~~~~~~~~~~~~~~ @@ -249,16 +256,23 @@ data HsRecFields id arg -- A bunch of record fields -- the first 'n' being the user-written ones -- and the remainder being 'filled in' implicitly -type LHsRecField id arg = Located (HsRecField id arg) --- | - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnEqual', +type LHsRecField' id arg = Located (HsRecField' id arg) +type LHsRecField id arg = Located (HsRecField id arg) +type LHsRecUpdField id = Located (HsRecUpdField id) + +type HsRecField id arg = HsRecField' (FieldOcc id) arg +type HsRecUpdField id = HsRecField' (AmbiguousFieldOcc id) (LHsExpr id) +-- | - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnEqual', +-- -- For details on above see note [Api annotations] in ApiAnnotation -data HsRecField id arg = HsRecField { - hsRecFieldId :: Located id, - hsRecFieldArg :: arg, -- Filled in by renamer - hsRecPun :: Bool -- Note [Punning] +data HsRecField' id arg = HsRecField { + hsRecFieldLbl :: Located id, + hsRecFieldArg :: arg, -- ^ Filled in by renamer when punning + hsRecPun :: Bool -- ^ Note [Punning] } deriving (Data, Typeable) + -- Note [Punning] -- ~~~~~~~~~~~~~~ -- If you write T { x, y = v+1 }, the HsRecFields will be @@ -271,8 +285,64 @@ data HsRecField id arg = HsRecField { -- If the original field was qualified, we un-qualify it, thus -- T { A.x } means T { A.x = x } -hsRecFields :: HsRecFields id arg -> [id] -hsRecFields rbinds = map (unLoc . hsRecFieldId . unLoc) (rec_flds rbinds) + +-- Note [HsRecField and HsRecUpdField] +-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +-- A HsRecField (used for record construction and pattern matching) +-- contains an unambiguous occurrence of a field (i.e. a FieldOcc). +-- We can't just store the Name, because thanks to +-- DuplicateRecordFields this may not correspond to the label the user +-- wrote. +-- +-- A HsRecUpdField (used for record update) contains a potentially +-- ambiguous occurrence of a field (an AmbiguousFieldOcc). The +-- renamer will fill in the selector function if it can, but if the +-- selector is ambiguous the renamer will defer to the typechecker. +-- After the typechecker, a unique selector will have been determined. +-- +-- The renamer produces an Unambiguous result if it can, rather than +-- just doing the lookup in the typechecker, so that completely +-- unambiguous updates can be represented by 'DsMeta.repUpdFields'. +-- +-- For example, suppose we have: +-- +-- data S = MkS { x :: Int } +-- data T = MkT { x :: Int } +-- +-- f z = (z { x = 3 }) :: S +-- +-- The parsed HsRecUpdField corresponding to the record update will have: +-- +-- hsRecFieldLbl = Unambiguous "x" PlaceHolder :: AmbiguousFieldOcc RdrName +-- +-- After the renamer, this will become: +-- +-- hsRecFieldLbl = Ambiguous "x" PlaceHolder :: AmbiguousFieldOcc Name +-- +-- (note that the Unambiguous constructor is not type-correct here). +-- The typechecker will determine the particular selector: +-- +-- hsRecFieldLbl = Unambiguous "x" $sel:x:MkS :: AmbiguousFieldOcc Id + +hsRecFields :: HsRecFields id arg -> [PostRn id id] +hsRecFields rbinds = map (unLoc . hsRecFieldSel . unLoc) (rec_flds rbinds) + +hsRecFieldSel :: HsRecField name arg -> Located (PostRn name name) +hsRecFieldSel = fmap selectorFieldOcc . hsRecFieldLbl + +hsRecFieldId :: HsRecField Id arg -> Located Id +hsRecFieldId = hsRecFieldSel + +hsRecUpdFieldRdr :: HsRecUpdField id -> Located RdrName +hsRecUpdFieldRdr = fmap rdrNameAmbiguousFieldOcc . hsRecFieldLbl + +hsRecUpdFieldId :: HsRecField' (AmbiguousFieldOcc Id) arg -> Located Id +hsRecUpdFieldId = fmap selectorFieldOcc . hsRecUpdFieldOcc + +hsRecUpdFieldOcc :: HsRecField' (AmbiguousFieldOcc Id) arg -> LFieldOcc Id +hsRecUpdFieldOcc = fmap unambiguousFieldOcc . hsRecFieldLbl + {- ************************************************************************ @@ -351,7 +421,7 @@ pprConArgs (PrefixCon pats) = sep (map pprParendLPat pats) pprConArgs (InfixCon p1 p2) = sep [pprParendLPat p1, pprParendLPat p2] pprConArgs (RecCon rpats) = ppr rpats -instance (OutputableBndr id, Outputable arg) +instance (Outputable arg) => Outputable (HsRecFields id arg) where ppr (HsRecFields { rec_flds = flds, rec_dotdot = Nothing }) = braces (fsep (punctuate comma (map ppr flds))) @@ -360,12 +430,13 @@ instance (OutputableBndr id, Outputable arg) where dotdot = ptext (sLit "..") <+> ifPprDebug (ppr (drop n flds)) -instance (OutputableBndr id, Outputable arg) - => Outputable (HsRecField id arg) where - ppr (HsRecField { hsRecFieldId = f, hsRecFieldArg = arg, +instance (Outputable id, Outputable arg) + => Outputable (HsRecField' id arg) where + ppr (HsRecField { hsRecFieldLbl = f, hsRecFieldArg = arg, hsRecPun = pun }) = ppr f <+> (ppUnless pun $ equals <+> ppr arg) + {- ************************************************************************ * * |