Note [RecordDotSyntax field updates]

Language/Haskell/Syntax/Expr.hs:45 compiler

The extensions @OverloadedRecordDot@ @OverloadedRecordUpdate@ together
enable record updates like @a{foo.bar.baz = 1}@. Introducing this
syntax slightly complicates parsing. This note explains how it's done.

In the event a record is being constructed or updated, it's this
production that's in play:
@
aexp1 -> aexp1 '{' fbinds '}' {
  ...
  mkHsRecordPV ... $1 (snd $3)
}
@
@fbinds@ is a list of field bindings. @mkHsRecordPV@ is a function of
the @DisambECP b@ typeclass, see Note [Ambiguous syntactic
categories].

The "normal" rules for an @fbind@ are:
@
fbind
        : qvar '=' texp
        | qvar
@
These rules compute values of @LHsRecField GhcPs (Located b)@. They
apply in the context of record construction, record updates, record
patterns and record expressions. That is, @b@ ranges over @HsExpr
GhcPs@, @HsPat GhcPs@ and @HsCmd GhcPs@.

When @OverloadedRecordDot@ and @OverloadedRecordUpdate@ are both
enabled, two additional @fbind@ rules are admitted:
@
        | field TIGHT_INFIX_PROJ fieldToUpdate '=' texp
        | field TIGHT_INFIX_PROJ fieldToUpdate
@

These rules only make sense when parsing record update expressions
(that is, patterns and commands cannot be parsed by these rules and
neither record constructions).

The results of these new rules cannot be represented by @LHsRecField
GhcPs (LHsExpr GhcPs)@ values as the type is defined today. We
minimize modifying existing code by having these new rules calculate
@LHsRecProj GhcPs (LHsExpr GhcPs)@ ("record projection") values
instead:
@
newtype FieldLabelStrings = FieldLabelStrings [XRec p (DotFieldOcc p)]
type RecProj arg = HsFieldBind FieldLabelStrings arg
type LHsRecProj p arg = XRec p (RecProj arg)
@

The @fbind@ rule is then given the type @fbind :: { forall b.
DisambECP b => PV (Fbind b) }@ accommodating both alternatives:
@
type Fbind b = Either
                  (LHsRecField GhcPs (LocatedA b))
                  ( LHsRecProj GhcPs (LocatedA b))
@

In @data HsExpr p@, the @RecordUpd@ constuctor indicates regular
updates vs. projection updates by means of the @rupd_flds@ member
type, an @Either@ instance:
@
  | RecordUpd
      { rupd_ext  :: XRecordUpd p
      , rupd_expr :: LHsExpr p
      , rupd_flds :: Either [LHsRecUpdField p] [LHsRecUpdProj p]
      }
@
Here,
@
type RecUpdProj p = RecProj p (LHsExpr p)
type LHsRecUpdProj p = XRec p (RecUpdProj p)
@
and @Left@ values indicating regular record update, @Right@ values
updates desugared to @setField@s.

If @OverloadedRecordUpdate@ is enabled, any updates parsed as
@LHsRecField GhcPs@ values are converted to @LHsRecUpdProj GhcPs@
values (see function @mkRdrRecordUpd@ in 'GHC.Parser.PostProcess').

References 0

This Note does not link to any other.

Referenced by 1