Skip to content
Snippets Groups Projects
  • sheaf's avatar
    3f374399
    Handle records in the renamer · 3f374399
    sheaf authored
    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
    -------------------------
    3f374399
    History
    Handle records in the renamer
    sheaf authored
    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
    -------------------------
Code owners
Assign users and groups as approvers for specific file changes. Learn more.