summaryrefslogtreecommitdiff
path: root/compiler/Language/Haskell/Syntax/Expr.hs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/Language/Haskell/Syntax/Expr.hs')
-rw-r--r--compiler/Language/Haskell/Syntax/Expr.hs64
1 files changed, 56 insertions, 8 deletions
diff --git a/compiler/Language/Haskell/Syntax/Expr.hs b/compiler/Language/Haskell/Syntax/Expr.hs
index a9592304e6..6f5150a1b4 100644
--- a/compiler/Language/Haskell/Syntax/Expr.hs
+++ b/compiler/Language/Haskell/Syntax/Expr.hs
@@ -267,6 +267,55 @@ is Less Cool because
typecheck do-notation with (>>=) :: m1 a -> (a -> m2 b) -> m2 b.)
-}
+{-
+Note [Record selectors in the AST]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Here is how record selectors are expressed in GHC's AST:
+
+Example data type
+ data T = MkT { size :: Int }
+
+Record selectors:
+ | GhcPs | GhcRn | GhcTc |
+----------------------------------------------------------------------------------|
+size (assuming one | HsVar | HsRecSel | HsRecSel |
+ 'size' in scope) | | | |
+----------------------|--------------|----------------------|---------------------|
+.size (assuming | HsProjection | getField @"size" | getField @"size" |
+ OverloadedRecordDot) | | | |
+----------------------|--------------|----------------------|---------------------|
+e.size (assuming | HsGetField | getField @"size" e | getField @"size" e |
+ OverloadedRecordDot) | | | |
+
+NB 1: DuplicateRecordFields makes no difference to the first row of
+this table, except that if 'size' is a field of more than one data
+type, then a naked use of the record selector 'size' may well be
+ambiguous. You have to use a qualified name. And there is no way to do
+this if both data types are declared in the same module.
+
+NB 2: The notation getField @"size" e is short for
+HsApp (HsAppType (HsVar "getField") (HsWC (HsTyLit (HsStrTy "size")) [])) e.
+We track the original parsed syntax via HsExpanded.
+
+-}
+
+{-
+Note [Non-overloaded record field selectors]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Consider
+ data T = MkT { x,y :: Int }
+ f r x = x + y r
+
+This parses with HsVar for x, y, r on the RHS of f. Later, the renamer
+recognises that y in the RHS of f is really a record selector, and
+changes it to a HsRecSel. In contrast x is locally bound, shadowing
+the record selector, and stays as an HsVar.
+
+The renamer adds the Name of the record selector into the XCFieldOcc
+extension field, The typechecker keeps HsRecSel as HsRecSel, and
+transforms the record-selector Name to an Id.
+-}
+
-- | A Haskell expression.
data HsExpr p
= HsVar (XVar p)
@@ -285,11 +334,10 @@ data HsExpr p
-- solving. See Note [Holes] in GHC.Tc.Types.Constraint.
- | HsRecFld (XRecFld p)
- (AmbiguousFieldOcc p) -- ^ Variable pointing to record selector
- -- The parser produces HsVars
- -- The renamer renames record-field selectors to HsRecFld
- -- The typechecker preserves HsRecFld
+ | HsRecSel (XRecSel p)
+ (FieldOcc p) -- ^ Variable pointing to record selector
+ -- See Note [Non-overloaded record field selectors] and
+ -- Note [Record selectors in the AST]
| HsOverLabel (XOverLabel p) FastString
-- ^ Overloaded label (Note [Overloaded labels] in GHC.OverloadedLabels)
@@ -334,7 +382,7 @@ data HsExpr p
-- NB Bracketed ops such as (+) come out as Vars.
-- NB Sadly, we need an expr for the operator in an OpApp/Section since
- -- the renamer may turn a HsVar into HsRecFld or HsUnboundVar
+ -- the renamer may turn a HsVar into HsRecSel or HsUnboundVar
| OpApp (XOpApp p)
(LHsExpr p) -- left operand
@@ -486,7 +534,7 @@ data HsExpr p
-- - 'GHC.Parser.Annotation.AnnKeywordId' : 'GHC.Parser.Annotation.AnnDot'
--
-- This case only arises when the OverloadedRecordDot langauge
- -- extension is enabled.
+ -- extension is enabled. See Note [Record Selectors in the AST].
| HsGetField {
gf_ext :: XGetField p
@@ -500,7 +548,7 @@ data HsExpr p
-- 'GHC.Parser.Annotation.AnnDot', 'GHC.Parser.Annotation.AnnCloseP'
--
-- This case only arises when the OverloadedRecordDot langauge
- -- extensions is enabled.
+ -- extensions is enabled. See Note [Record Selectors in the AST].
| HsProjection {
proj_ext :: XProjection p