[Git][ghc/ghc][wip/aidylns/ttg-remove-hsunboundvar-via-hshole] TTG: Remove HsUnboundVar, replace with HsHole, HsUnboundVarRn/Tc

Adriaan Leijnse (@aidylns) gitlab at gitlab.haskell.org
Fri Sep 13 14:49:00 UTC 2024



Adriaan Leijnse pushed to branch wip/aidylns/ttg-remove-hsunboundvar-via-hshole at Glasgow Haskell Compiler / GHC


Commits:
7ed954d9 by Adriaan Leijnse at 2024-09-13T16:48:38+02:00
TTG: Remove HsUnboundVar, replace with HsHole, HsUnboundVarRn/Tc

This commit removes HsUnboundVar from the Language AST, which was used to parse
Holes to.  Instead it introduces a new HsHole AST constructor for this purpose.
The renaming and type checking phases keep their original HsUnboundVar
implementation using HsUnboundVarRn and HsUnboundVarTc constructors (HsHole is
turned into HsUnboundVarRn during renaming).

Also, the note explaining Holes is rewritten to reflect the current state of the
code.

- - - - -


25 changed files:

- compiler/GHC/Hs/Expr.hs
- compiler/GHC/Hs/Syn/Type.hs
- compiler/GHC/HsToCore/Expr.hs
- compiler/GHC/HsToCore/Quote.hs
- compiler/GHC/HsToCore/Ticks.hs
- compiler/GHC/Iface/Ext/Ast.hs
- compiler/GHC/Parser.y
- compiler/GHC/Parser/PostProcess.hs
- compiler/GHC/Rename/Expr.hs
- compiler/GHC/Rename/HsType.hs
- compiler/GHC/Rename/Module.hs
- compiler/GHC/Tc/Errors.hs
- compiler/GHC/Tc/Gen/App.hs
- compiler/GHC/Tc/Gen/Expr.hs
- compiler/GHC/Tc/Gen/Head.hs
- compiler/GHC/Tc/Types/Constraint.hs
- compiler/GHC/Tc/Types/Evidence.hs
- compiler/GHC/Tc/Types/Origin.hs
- compiler/GHC/Tc/Zonk/Type.hs
- compiler/Language/Haskell/Syntax/Expr.hs
- compiler/Language/Haskell/Syntax/Extension.hs
- testsuite/tests/perf/compiler/hard_hole_fits.hs
- testsuite/tests/perf/compiler/hard_hole_fits.stderr
- testsuite/tests/plugins/T20803-plugin/FixErrorsPlugin.hs
- utils/check-exact/ExactPrint.hs


Changes:

=====================================
compiler/GHC/Hs/Expr.hs
=====================================
@@ -208,9 +208,10 @@ data EpAnnHsCase = EpAnnHsCase
 instance NoAnn EpAnnHsCase where
   noAnn = EpAnnHsCase noAnn noAnn noAnn
 
-data EpAnnUnboundVar = EpAnnUnboundVar
-     { hsUnboundBackquotes :: (EpaLocation, EpaLocation)
-     , hsUnboundHole       :: EpaLocation
+-- | ExactPrint annotation for holes.
+data EpAnnHole = EpAnnHole
+     { hsHoleBackquotes :: (EpaLocation, EpaLocation)
+     , hsHoleHole       :: EpaLocation
      } deriving Data
 
 -- Record selectors at parse time are HsVar; they convert to HsRecSel
@@ -229,14 +230,6 @@ type instance XOverLabel     GhcTc = DataConCantHappen
 
 type instance XVar           (GhcPass _) = NoExtField
 
-type instance XUnboundVar    GhcPs = Maybe EpAnnUnboundVar
-type instance XUnboundVar    GhcRn = NoExtField
-type instance XUnboundVar    GhcTc = HoleExprRef
-  -- We really don't need the whole HoleExprRef; just the IORef EvTerm
-  -- would be enough. But then deriving a Data instance becomes impossible.
-  -- Much, much easier just to define HoleExprRef with a Data instance and
-  -- store the whole structure.
-
 type instance XIPVar         GhcPs = NoExtField
 type instance XIPVar         GhcRn = NoExtField
 type instance XIPVar         GhcTc = DataConCantHappen
@@ -382,6 +375,11 @@ type instance XEmbTy         GhcTc = DataConCantHappen
   -- A free-standing HsEmbTy is an error.
   -- Valid usages are immediately desugared into Type.
 
+type instance XHole          GhcPs = Maybe EpAnnHole
+-- After renaming holes are handled using HsUnboundVarRn/HsUnboundVarTc:
+type instance XHole          GhcRn = DataConCantHappen
+type instance XHole          GhcTc = DataConCantHappen
+
 type instance XForAll        GhcPs = NoExtField
 type instance XForAll        GhcRn = NoExtField
 type instance XForAll        GhcTc = DataConCantHappen
@@ -514,6 +512,10 @@ data XXExprGhcRn
                                                    -- Does not presist post renaming phase
                                                    -- See Part 3. of Note [Expanding HsDo with XXExprGhcRn]
                                                    -- in `GHC.Tc.Gen.Do`
+  | HsUnboundVarRn RdrName   -- ^ Unbound variable.
+                             -- Turned from HsVar to HsUnboundVarRn by the
+                             --   renamer, when it finds an out-of-scope
+                             --   variable.
 
 
 -- | Wrap a located expression with a `PopErrCtxt`
@@ -594,6 +596,19 @@ data XXExprGhcTc
      Int                                -- module-local tick number for True
      Int                                -- module-local tick number for False
      (LHsExpr GhcTc)                    -- sub-expression
+  | HsUnboundVarTc HoleExprRef RdrName
+                             -- ^ Unbound variable; also used for "holes"
+                             --   (_ or _x).
+                             -- In the case of expression holes, the HoleExprRef is where the
+                             -- erroring expression will be written after solving.
+                             -- See Note [Holes in expressions] in GHC.Tc.Types.Constraint.
+                             --
+                             -- We really don't need the whole HoleExprRef; just
+                             -- the IORef EvTerm would be enough. But then
+                             -- deriving a Data instance becomes impossible.
+                             -- Much, much easier just to define HoleExprRef
+                             -- with a Data instance and store the whole
+                             -- structure.
 
 -- | Build a 'XXExprGhcRn' out of an extension constructor,
 --   and the two components of the expansion: original and
@@ -654,7 +669,10 @@ ppr_lexpr e = ppr_expr (unLoc e)
 ppr_expr :: forall p. (OutputableBndrId p)
          => HsExpr (GhcPass p) -> SDoc
 ppr_expr (HsVar _ (L _ v))   = pprPrefixOcc v
-ppr_expr (HsUnboundVar _ uv) = pprPrefixOcc uv
+ppr_expr (HsHole x)          = case ghcPass @p of
+  GhcPs -> pprPrefixOcc (mkUnqual varName (fsLit "_"))
+  GhcRn -> dataConCantHappen x
+  GhcTc -> dataConCantHappen x
 ppr_expr (HsRecSel _ f)      = pprPrefixOcc f
 ppr_expr (HsIPVar _ v)       = ppr v
 ppr_expr (HsOverLabel s l) = case ghcPass @p of
@@ -879,6 +897,7 @@ instance Outputable HsThingRn where
 instance Outputable XXExprGhcRn where
   ppr (ExpandedThingRn o e) = ifPprDebug (braces $ vcat [ppr o, ppr e]) (ppr o)
   ppr (PopErrCtxt e)        = ifPprDebug (braces (text "<PopErrCtxt>" <+> ppr e)) (ppr e)
+  ppr (HsUnboundVarRn uv)   = pprPrefixOcc uv
 
 instance Outputable XXExprGhcTc where
   ppr (WrapExpr (HsWrap co_fn e))
@@ -907,11 +926,15 @@ instance Outputable XXExprGhcTc where
             ppr tickIdFalse,
             text ">(",
             ppr exp, text ")"]
+  ppr (HsUnboundVarTc _ uv)   = pprPrefixOcc uv
 
 ppr_infix_expr :: forall p. (OutputableBndrId p) => HsExpr (GhcPass p) -> Maybe SDoc
 ppr_infix_expr (HsVar _ (L _ v))    = Just (pprInfixOcc v)
 ppr_infix_expr (HsRecSel _ f)       = Just (pprInfixOcc f)
-ppr_infix_expr (HsUnboundVar _ occ) = Just (pprInfixOcc occ)
+ppr_infix_expr (HsHole x)           = case ghcPass @p of
+  GhcPs -> Just (pprInfixOcc (mkUnqual varName (fsLit "_")))
+  GhcRn -> dataConCantHappen x
+  GhcTc -> dataConCantHappen x
 ppr_infix_expr (XExpr x)            = case ghcPass @p of
                                         GhcRn -> ppr_infix_expr_rn x
                                         GhcTc -> ppr_infix_expr_tc x
@@ -920,6 +943,7 @@ ppr_infix_expr _ = Nothing
 ppr_infix_expr_rn :: XXExprGhcRn -> Maybe SDoc
 ppr_infix_expr_rn (ExpandedThingRn thing _) = ppr_infix_hs_expansion thing
 ppr_infix_expr_rn (PopErrCtxt (L _ a)) = ppr_infix_expr a
+ppr_infix_expr_rn (HsUnboundVarRn occ) = Just (pprInfixOcc occ)
 
 ppr_infix_expr_tc :: XXExprGhcTc -> Maybe SDoc
 ppr_infix_expr_tc (WrapExpr (HsWrap _ e))    = ppr_infix_expr e
@@ -927,6 +951,7 @@ ppr_infix_expr_tc (ExpandedThingTc thing _)  = ppr_infix_hs_expansion thing
 ppr_infix_expr_tc (ConLikeTc {})             = Nothing
 ppr_infix_expr_tc (HsTick {})                = Nothing
 ppr_infix_expr_tc (HsBinTick {})             = Nothing
+ppr_infix_expr_tc (HsUnboundVarTc _ occ) = Just (pprInfixOcc occ)
 
 ppr_infix_hs_expansion :: HsThingRn -> Maybe SDoc
 ppr_infix_hs_expansion (OrigExpr e) = ppr_infix_expr e
@@ -974,7 +999,6 @@ hsExprNeedsParens prec = go
   where
     go :: HsExpr (GhcPass p) -> Bool
     go (HsVar{})                      = False
-    go (HsUnboundVar{})               = False
     go (HsIPVar{})                    = False
     go (HsOverLabel{})                = False
     go (HsLit _ l)                    = hsLitNeedsParens prec l
@@ -1017,6 +1041,7 @@ hsExprNeedsParens prec = go
     go (HsProjection{})               = True
     go (HsGetField{})                 = False
     go (HsEmbTy{})                    = prec > topPrec
+    go (HsHole{})                     = False
     go (HsForAll{})                   = prec >= funPrec
     go (HsQual{})                     = prec >= funPrec
     go (HsFunArr{})                   = prec >= funPrec
@@ -1030,10 +1055,12 @@ hsExprNeedsParens prec = go
     go_x_tc (ConLikeTc {})                   = False
     go_x_tc (HsTick _ (L _ e))               = hsExprNeedsParens prec e
     go_x_tc (HsBinTick _ _ (L _ e))          = hsExprNeedsParens prec e
+    go_x_tc (HsUnboundVarTc {})              = False
 
     go_x_rn :: XXExprGhcRn -> Bool
     go_x_rn (ExpandedThingRn thing _)    = hsExpandedNeedsParens thing
     go_x_rn (PopErrCtxt (L _ a))         = hsExprNeedsParens prec a
+    go_x_rn (HsUnboundVarRn _)           = False
 
     hsExpandedNeedsParens :: HsThingRn -> Bool
     hsExpandedNeedsParens (OrigExpr e) = hsExprNeedsParens prec e
@@ -1070,8 +1097,8 @@ isAtomicHsExpr (HsLit {})        = True
 isAtomicHsExpr (HsOverLit {})    = True
 isAtomicHsExpr (HsIPVar {})      = True
 isAtomicHsExpr (HsOverLabel {})  = True
-isAtomicHsExpr (HsUnboundVar {}) = True
 isAtomicHsExpr (HsRecSel{})      = True
+isAtomicHsExpr (HsHole{})        = True
 isAtomicHsExpr (XExpr x)
   | GhcTc <- ghcPass @p          = go_x_tc x
   | GhcRn <- ghcPass @p          = go_x_rn x
@@ -1082,10 +1109,12 @@ isAtomicHsExpr (XExpr x)
     go_x_tc (ConLikeTc {})                   = True
     go_x_tc (HsTick {}) = False
     go_x_tc (HsBinTick {}) = False
+    go_x_tc (HsUnboundVarTc {}) = True
 
     go_x_rn :: XXExprGhcRn -> Bool
     go_x_rn (ExpandedThingRn thing _)    = isAtomicExpandedThingRn thing
     go_x_rn (PopErrCtxt (L _ a))         = isAtomicHsExpr a
+    go_x_rn (HsUnboundVarRn {}) = True
 
     isAtomicExpandedThingRn :: HsThingRn -> Bool
     isAtomicExpandedThingRn (OrigExpr e) = isAtomicHsExpr e


=====================================
compiler/GHC/Hs/Syn/Type.hs
=====================================
@@ -102,7 +102,6 @@ lhsExprType (L _ e) = hsExprType e
 -- | Compute the 'Type' of an @'HsExpr' 'GhcTc'@ in a pure fashion.
 hsExprType :: HsExpr GhcTc -> Type
 hsExprType (HsVar _ (L _ id)) = idType id
-hsExprType (HsUnboundVar (HER _ ty _) _) = ty
 hsExprType (HsRecSel _ (FieldOcc id _)) = idType id
 hsExprType (HsOverLabel v _) = dataConCantHappen v
 hsExprType (HsIPVar v _) = dataConCantHappen v
@@ -146,6 +145,7 @@ hsExprType (HsProc _ _ lcmd_top) = lhsCmdTopType lcmd_top
 hsExprType (HsStatic (_, ty) _s) = ty
 hsExprType (HsPragE _ _ e) = lhsExprType e
 hsExprType (HsEmbTy x _) = dataConCantHappen x
+hsExprType (HsHole x) = dataConCantHappen x
 hsExprType (HsQual x _ _) = dataConCantHappen x
 hsExprType (HsForAll x _ _) = dataConCantHappen x
 hsExprType (HsFunArr x _ _ _) = dataConCantHappen x
@@ -154,6 +154,7 @@ hsExprType (XExpr (ExpandedThingTc _ e))  = hsExprType e
 hsExprType (XExpr (ConLikeTc con _ _)) = conLikeType con
 hsExprType (XExpr (HsTick _ e)) = lhsExprType e
 hsExprType (XExpr (HsBinTick _ _ e)) = lhsExprType e
+hsExprType (XExpr (HsUnboundVarTc (HER _ ty _) _)) = ty
 
 arithSeqInfoType :: ArithSeqInfo GhcTc -> Type
 arithSeqInfoType asi = mkListTy $ case asi of


=====================================
compiler/GHC/HsToCore/Expr.hs
=====================================
@@ -292,8 +292,8 @@ dsExpr (HsRecSel _ (FieldOcc id _))
       return $ take maxConstructors cons_wo_field
 
 
-dsExpr (HsUnboundVar (HER ref _ _) _)  = dsEvTerm =<< readMutVar ref
-        -- See Note [Holes] in GHC.Tc.Types.Constraint
+dsExpr (HsHole x)            = dataConCantHappen x
+        -- Holes are handled by HsUnboundVarTc.
 
 dsExpr (HsPar _ e)            = dsLExpr e
 dsExpr (ExprWithTySig _ e _)  = dsLExpr e
@@ -336,6 +336,9 @@ dsExpr e@(XExpr ext_expr_tc)
         do { assert (exprType e2 `eqType` boolTy)
             mkBinaryTickBox ixT ixF e2
           }
+      HsUnboundVarTc (HER ref _ _) _ -> dsEvTerm =<< readMutVar ref
+      -- See Note [Holes in expressions] in GHC.Tc.Types.Constraint.
+
 
 -- Strip ticks due to #21701, need to be invariant about warnings we produce whether
 -- this is enabled or not.


=====================================
compiler/GHC/HsToCore/Quote.hs
=====================================
@@ -1674,9 +1674,6 @@ repE (HsTypedSplice n _) = rep_splice n
 repE (HsUntypedSplice (HsUntypedSpliceNested n) _)  = rep_splice n
 repE e@(HsUntypedSplice (HsUntypedSpliceTop _ _) _) = pprPanic "repE: top level splice" (ppr e)
 repE (HsStatic _ e)        = repLE e >>= rep2 staticEName . (:[]) . unC
-repE (HsUnboundVar _ uv)   = do
-                               name <- repRdrName uv
-                               repUnboundVar name
 repE (HsGetField _ e (L _ (DotFieldOcc _ (L _ (FieldLabelString f))))) = do
   e1 <- repLE e
   repGetField e1 f
@@ -1713,10 +1710,14 @@ repE e@(XExpr (ExpandedThingRn o x))
   = notHandled (ThExpressionForm e)
 
 repE (XExpr (PopErrCtxt (L _ e))) = repE e
+repE (XExpr (HsUnboundVarRn uv)) = do
+  name <- repRdrName uv
+  repUnboundVar name
 repE e@(HsPragE _ (HsPragSCC {}) _) = notHandled (ThCostCentres e)
 repE e@(HsTypedBracket{})   = notHandled (ThExpressionForm e)
 repE e@(HsUntypedBracket{}) = notHandled (ThExpressionForm e)
 repE e@(HsProc{}) = notHandled (ThExpressionForm e)
+repE e@(HsHole{}) = notHandled (ThExpressionForm e)
 
 repFunArr :: HsArrowOf (LocatedA (HsExpr GhcRn)) GhcRn -> MetaM (Core (M TH.Exp))
 repFunArr HsUnrestrictedArrow{} = repConName unrestrictedFunTyConName


=====================================
compiler/GHC/HsToCore/Ticks.hs
=====================================
@@ -475,7 +475,6 @@ addBinTickLHsExpr boxLabel e@(L pos e0)
 
 addTickHsExpr :: HsExpr GhcTc -> TM (HsExpr GhcTc)
 addTickHsExpr e@(HsVar _ (L _ id))  = do freeVar id; return e
-addTickHsExpr e@(HsUnboundVar {})   = return e
 addTickHsExpr e@(HsRecSel _ (FieldOcc id _))   = do freeVar id; return e
 
 addTickHsExpr e@(HsIPVar {})            = return e
@@ -483,6 +482,7 @@ addTickHsExpr e@(HsOverLit {})          = return e
 addTickHsExpr e@(HsOverLabel{})         = return e
 addTickHsExpr e@(HsLit {})              = return e
 addTickHsExpr e@(HsEmbTy {})            = return e
+addTickHsExpr e@(HsHole {})             = return e
 addTickHsExpr e@(HsQual {})             = return e
 addTickHsExpr e@(HsForAll {})           = return e
 addTickHsExpr e@(HsFunArr {})           = return e
@@ -603,6 +603,7 @@ addTickHsExpr (XExpr (HsTick t e)) =
         liftM (XExpr . HsTick t) (addTickLHsExprNever e)
 addTickHsExpr (XExpr (HsBinTick t0 t1 e)) =
         liftM (XExpr . HsBinTick t0 t1) (addTickLHsExprNever e)
+addTickHsExpr e@(XExpr (HsUnboundVarTc {})) = return e
 
 addTickHsExpr (HsDo srcloc cxt (L l stmts))
   = do { (stmts', _) <- addTickLStmts' forQual stmts (return ())


=====================================
compiler/GHC/Iface/Ext/Ast.hs
=====================================
@@ -1176,7 +1176,6 @@ instance HiePass p => ToHie (LocatedA (HsExpr (GhcPass p))) where
         [ toHie $ C Use (L mspan var)
              -- Patch up var location since typechecker removes it
         ]
-      HsUnboundVar _ _ -> []  -- there is an unbound name here, but that causes trouble
       HsRecSel _ fld ->
         [ toHie $ RFC RecFieldOcc Nothing (L mspan fld)
         ]
@@ -1325,6 +1324,7 @@ instance HiePass p => ToHie (LocatedA (HsExpr (GhcPass p))) where
         ]
       HsGetField {} -> []
       HsProjection {} -> []
+      HsHole _ -> [] -- there is a hole here, but that causes trouble
       XExpr x
         | HieTc <- hiePass @p
         -> case x of
@@ -1341,6 +1341,7 @@ instance HiePass p => ToHie (LocatedA (HsExpr (GhcPass p))) where
              HsBinTick _ _ expr
                -> [ toHie expr
                   ]
+             HsUnboundVarTc _ _ -> []  -- there is an unbound name here, but that causes trouble
         | otherwise -> []
 
 -- NOTE: no longer have the location


=====================================
compiler/GHC/Parser.y
=====================================
@@ -3896,7 +3896,7 @@ qopm    :: { forall b. DisambInfixOp b => PV (LocatedN b) }   -- used in section
         | hole_op               { mkHsInfixHolePV $1 }
 
 hole_op :: { LocatedN (HsExpr GhcPs) }   -- used in sections
-hole_op : '`' '_' '`'           { sLLa $1 $> (hsHoleExpr (Just $ EpAnnUnboundVar (glAA $1, glAA $3) (glAA $2))) }
+hole_op : '`' '_' '`'           { sLLa $1 $> (HsHole (Just $ EpAnnHole (glAA $1, glAA $3) (glAA $2))) }
 
 qvarop :: { LocatedN RdrName }
         : qvarsym               { $1 }


=====================================
compiler/GHC/Parser/PostProcess.hs
=====================================
@@ -109,7 +109,6 @@ module GHC.Parser.PostProcess (
         withArrowParsingMode, withArrowParsingMode',
         setTelescopeBndrsNameSpace,
         PatBuilder,
-        hsHoleExpr,
 
         -- Type/datacon ambiguity resolution
         DisambTD(..),
@@ -1899,11 +1898,11 @@ instance DisambECP (HsExpr GhcPs) where
   type Body (HsExpr GhcPs) = HsExpr
   ecpFromCmd' (L l c) = do
     addError $ mkPlainErrorMsgEnvelope (locA l) $ PsErrArrowCmdInExpr c
-    return (L l (hsHoleExpr noAnn))
+    return (L l (HsHole noAnn))
   ecpFromExp' = return
   ecpFromPat' p@(L l _) = do
     addError $ mkPlainErrorMsgEnvelope (locA l) $ PsErrOrPatInExpr p
-    return (L l (hsHoleExpr noAnn))
+    return (L l (HsHole noAnn))
   mkHsProjUpdatePV l fields arg isPun anns = do
     !cs <- getCommentsFor l
     return $ mkRdrProjUpdate (EpAnn (spanAsAnchor l) noAnn cs) fields arg isPun anns
@@ -1952,7 +1951,7 @@ instance DisambECP (HsExpr GhcPs) where
   mkHsOverLitPV (L (EpAnn l an csIn) a) = do
     !cs <- getCommentsFor (locA l)
     return $ L (EpAnn  l an (cs Semi.<> csIn)) (HsOverLit NoExtField a)
-  mkHsWildCardPV l = return $ L (noAnnSrcSpan l) (hsHoleExpr noAnn)
+  mkHsWildCardPV l = return $ L (noAnnSrcSpan l) (HsHole noAnn)
   mkHsTySigPV l@(EpAnn anc an csIn) a sig anns = do
     !cs <- getCommentsFor (locA l)
     return $ L (EpAnn anc an (csIn Semi.<> cs)) (ExprWithTySig anns a (hsTypeToHsSigWcType sig))
@@ -1973,11 +1972,11 @@ instance DisambECP (HsExpr GhcPs) where
     !cs <- getCommentsFor l
     return $ L (EpAnn (spanAsAnchor l) noAnn cs) (SectionR noExtField op e)
   mkHsAsPatPV l v _ e   = addError (mkPlainErrorMsgEnvelope l $ PsErrTypeAppWithoutSpace (unLoc v) e)
-                          >> return (L (noAnnSrcSpan l) (hsHoleExpr noAnn))
+                          >> return (L (noAnnSrcSpan l) (HsHole noAnn))
   mkHsLazyPatPV l e   _ = addError (mkPlainErrorMsgEnvelope l $ PsErrLazyPatWithoutSpace e)
-                          >> return (L (noAnnSrcSpan l) (hsHoleExpr noAnn))
+                          >> return (L (noAnnSrcSpan l) (HsHole noAnn))
   mkHsBangPatPV l e   _ = addError (mkPlainErrorMsgEnvelope l $ PsErrBangPatWithoutSpace e)
-                          >> return (L (noAnnSrcSpan l) (hsHoleExpr noAnn))
+                          >> return (L (noAnnSrcSpan l) (HsHole noAnn))
   mkSumOrTuplePV = mkSumOrTupleExpr
   mkHsEmbTyPV l toktype ty =
     return $ L (noAnnSrcSpan l) $
@@ -2004,9 +2003,6 @@ instance DisambECP (HsExpr GhcPs) where
                                                          (PsErrUnallowedPragma prag)
   rejectPragmaPV _                        = return ()
 
-hsHoleExpr :: Maybe EpAnnUnboundVar -> HsExpr GhcPs
-hsHoleExpr anns = HsUnboundVar anns (mkRdrUnqual (mkVarOccFS (fsLit "_")))
-
 instance DisambECP (PatBuilder GhcPs) where
   type Body (PatBuilder GhcPs) = PatBuilder
   ecpFromCmd' (L l c)    = addFatalError $ mkPlainErrorMsgEnvelope (locA l) $ PsErrArrowCmdInPat c


=====================================
compiler/GHC/Rename/Expr.hs
=====================================
@@ -320,7 +320,7 @@ rnUnboundVar v = do
   deferOutofScopeVariables <- goptM Opt_DeferOutOfScopeVariables
   -- See Note [Reporting unbound names] for difference between qualified and unqualified names.
   unless (isUnqual v || deferOutofScopeVariables) (reportUnboundName v >> return ())
-  return (HsUnboundVar noExtField v, emptyFVs)
+  return (XExpr (HsUnboundVarRn v), emptyFVs)
 
 rnExpr (HsVar _ (L l v))
   = do { dflags <- getDynFlags
@@ -355,8 +355,8 @@ rnExpr (HsVar _ (L l v))
 rnExpr (HsIPVar x v)
   = return (HsIPVar x v, emptyFVs)
 
-rnExpr (HsUnboundVar _ v)
-  = return (HsUnboundVar noExtField v, emptyFVs)
+rnExpr (HsHole _)
+  = return (XExpr (HsUnboundVarRn (mkUnqual varName (fsLit "_"))), emptyFVs)
 
 -- HsOverLabel: see Note [Handling overloaded and rebindable constructs]
 rnExpr (HsOverLabel src v)
@@ -862,8 +862,8 @@ See #18151.
 Note [Reporting unbound names]
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Faced with an out-of-scope `RdrName` there are two courses of action
-A. Report an error immediately (and return a HsUnboundVar). This will halt GHC after the renamer is complete
-B. Return a HsUnboundVar without reporting an error.  That will allow the typechecker to run, which in turn
+A. Report an error immediately (and return a HsUnboundVarRn). This will halt GHC after the renamer is complete
+B. Return a HsUnboundVarRn without reporting an error.  That will allow the typechecker to run, which in turn
    can give a better error message, notably giving the type of the variable via the "typed holes" mechanism.
 
 When `-fdefer-out-of-scope-variables` is on we follow plan B.


=====================================
compiler/GHC/Rename/HsType.hs
=====================================
@@ -1431,10 +1431,10 @@ data NegationHandling = ReassociateNegation | KeepNegationIntact
 ----------------------------
 
 get_op :: LHsExpr GhcRn -> OpName
--- An unbound name could be either HsVar or HsUnboundVar
+-- An unbound name could be either HsVar or (XExpr (HsUnboundVarRn uv))
 -- See GHC.Rename.Expr.rnUnboundVar
 get_op (L _ (HsVar _ n))         = NormalOp (unLoc n)
-get_op (L _ (HsUnboundVar _ uv)) = UnboundOp uv
+get_op (L _ (XExpr (HsUnboundVarRn uv))) = UnboundOp uv
 get_op (L _ (HsRecSel _ fld))    = RecFldOp fld
 get_op other                     = pprPanic "get_op" (ppr other)
 


=====================================
compiler/GHC/Rename/Module.hs
=====================================
@@ -1299,7 +1299,7 @@ badRuleLhsErr name lhs bad_e
   = TcRnIllegalRuleLhs errReason name lhs bad_e
   where
     errReason = case bad_e of
-      HsUnboundVar _ uv ->
+      XExpr (HsUnboundVarRn uv) ->
         UnboundVariable uv $ notInScopeErr WL_Global uv
       _ -> IllegalExpression
 


=====================================
compiler/GHC/Tc/Errors.hs
=====================================
@@ -1550,7 +1550,7 @@ maybeAddDeferredBindings ctxt hole report = do
       when (deferringAnyBindings ctxt) $ do
         err_tm <- mkErrorTerm ctxt (hole_loc hole) ref_ty report
           -- NB: ref_ty, not hole_ty. hole_ty might be rewritten.
-          -- See Note [Holes] in GHC.Tc.Types.Constraint
+          -- See Note [Holes in expressions] in GHC.Tc.Types.Constraint
         writeMutVar ref err_tm
     _ -> pure ()
 


=====================================
compiler/GHC/Tc/Gen/App.hs
=====================================
@@ -220,7 +220,7 @@ A "head" has three special cases (for which we can infer a polytype
 using tcInferAppHead_maybe); otherwise is just any old expression (for
 which we can infer a rho-type (via tcInfer).
 
-There is no special treatment for HsUnboundVar, HsOverLit etc, because
+There is no special treatment for HsUnboundVarTc, HsOverLit etc, because
 we can't get a polytype from them.
 
 Left and right sections (e.g. (x +) and (+ x)) are not yet supported.
@@ -674,7 +674,7 @@ tcInstFun do_ql inst_final (tc_fun, fun_ctxt) fun_sigma rn_args
 
     fun_is_out_of_scope  -- See Note [VTA for out-of-scope functions]
       = case tc_fun of
-          HsUnboundVar {} -> True
+          XExpr (HsUnboundVarTc {}) -> True
           _               -> False
 
     inst_fun :: [HsExprArg 'TcpRn] -> ForAllTyFlag -> Bool
@@ -1050,7 +1050,7 @@ expr_to_type earg =
       = do { t <- go (L l e)
            ; let splice_result' = HsUntypedSpliceTop finalizers t
            ; return (L l (HsSpliceTy splice_result' splice)) }
-    go (L l (HsUnboundVar _ rdr))
+    go (L l (XExpr (HsUnboundVarRn rdr)))
       | isUnderscore occ = return (L l (HsWildCardTy noExtField))
       | startsWithUnderscore occ =
           -- See Note [Wildcards in the T2T translation]
@@ -1122,7 +1122,7 @@ This conversion is in the TcM monad because
       vfun [x | x <- xs]     Can't convert list comprehension to a type
       vfun (\x -> x)         Can't convert a lambda to a type
 * It needs to check for LangExt.NamedWildCards to generate an appropriate
-  error message for HsUnboundVar.
+  error message for HsUnboundVarRn.
      vfun _a    Not in scope: ‘_a’
                    (NamedWildCards disabled)
      vfun _a    Illegal named wildcard in a required type argument: ‘_a’
@@ -1473,7 +1473,7 @@ Note [VTA for out-of-scope functions]
 Suppose 'wurble' is not in scope, and we have
    (wurble @Int @Bool True 'x')
 
-Then the renamer will make (HsUnboundVar "wurble") for 'wurble',
+Then the renamer will make (HsUnboundVarRn "wurble") for 'wurble',
 and the typechecker will typecheck it with tcUnboundId, giving it
 a type 'alpha', and emitting a deferred Hole constraint, to
 be reported later.
@@ -1488,7 +1488,7 @@ tcUnboundId.  It later reports 'wurble' as out of scope, and tries to
 give its type.
 
 Fortunately in tcInstFun we still have access to the function, so we
-can check if it is a HsUnboundVar.  We use this info to simply skip
+can check if it is a HsUnboundVarTc.  We use this info to simply skip
 over any visible type arguments.  We'll /already/ have emitted a
 Hole constraint; failing preserves that constraint.
 


=====================================
compiler/GHC/Tc/Gen/Expr.hs
=====================================
@@ -304,17 +304,6 @@ tcExpr e@(HsOverLit _ lit) res_ty
            Just lit' -> return (HsOverLit noExtField lit')
            Nothing   -> tcApp e res_ty }
 
--- Typecheck an occurrence of an unbound Id
---
--- Some of these started life as a true expression hole "_".
--- Others might simply be variables that accidentally have no binding site
-tcExpr (HsUnboundVar _ occ) res_ty
-  = do { ty <- expTypeToType res_ty    -- Allow Int# etc (#12531)
-       ; her <- emitNewExprHole occ ty
-       ; tcEmitBindingUsage bottomUE   -- Holes fit any usage environment
-                                       -- (#18491)
-       ; return (HsUnboundVar her occ) }
-
 tcExpr e@(HsLit x lit) res_ty
   = do { let lit_ty = hsLitType lit
        ; tcWrapResult e (HsLit x (convertLit lit)) lit_ty res_ty }
@@ -700,6 +689,7 @@ tcExpr (HsUntypedSplice splice _)   res_ty
 tcExpr (HsOverLabel {})    ty = pprPanic "tcExpr:HsOverLabel"  (ppr ty)
 tcExpr (SectionL {})       ty = pprPanic "tcExpr:SectionL"    (ppr ty)
 tcExpr (SectionR {})       ty = pprPanic "tcExpr:SectionR"    (ppr ty)
+tcExpr (HsHole {})         ty = pprPanic "tcExpr:HsHole"      (ppr ty)
 
 
 {-
@@ -739,6 +729,17 @@ tcXExpr xe@(ExpandedThingRn o e') res_ty
   = setSrcSpanA loc $
        mkExpandedStmtTc ls <$> tcApp (XExpr xe) res_ty
 
+-- Typecheck an occurrence of an unbound Id
+--
+-- Some of these started life as a true expression hole "_".
+-- Others might simply be variables that accidentally have no binding site.
+tcXExpr (HsUnboundVarRn occ) res_ty
+  = do { ty <- expTypeToType res_ty    -- Allow Int# etc (#12531)
+       ; her <- emitNewExprHole occ ty
+       ; tcEmitBindingUsage bottomUE   -- Holes fit any usage environment
+                                       -- (#18491)
+       ; return (XExpr (HsUnboundVarTc her occ)) }
+
 tcXExpr xe res_ty = tcApp (XExpr xe) res_ty
 
 {-


=====================================
compiler/GHC/Tc/Gen/Head.hs
=====================================
@@ -1281,9 +1281,9 @@ addStmtCtxt stmt thing_inside
 addExprCtxt :: HsExpr GhcRn -> TcRn a -> TcRn a
 addExprCtxt e thing_inside
   = case e of
-      HsUnboundVar {} -> thing_inside
+      XExpr (HsUnboundVarRn {}) -> thing_inside
       _ -> addErrCtxt (exprCtxt e) thing_inside
-   -- The HsUnboundVar special case addresses situations like
+   -- The HsUnboundVarRn special case addresses situations like
    --    f x = _
    -- when we don't want to say "In the expression: _",
    -- because it is mentioned in the error message itself


=====================================
compiler/GHC/Tc/Types/Constraint.hs
=====================================
@@ -370,7 +370,7 @@ data DelayedError
   = DE_Hole Hole
     -- ^ A hole (in a type or in a term).
     --
-    -- See Note [Holes].
+    -- See Note [Holes in expressions].
   | DE_NotConcrete NotConcreteError
     -- ^ A type could not be ensured to be concrete.
     --
@@ -383,7 +383,7 @@ instance Outputable DelayedError where
 -- | A hole stores the information needed to report diagnostics
 -- about holes in terms (unbound identifiers or underscores) or
 -- in types (also called wildcards, as used in partial type
--- signatures). See Note [Holes].
+-- signatures). See Note [Holes in expressions] for holes in terms.
 data Hole
   = Hole { hole_sort :: HoleSort -- ^ What flavour of hole is this?
          , hole_occ  :: RdrName  -- ^ The name of this hole
@@ -673,43 +673,78 @@ of the rhs. This is necessary because these constraints are used for substitutio
 during solving. If the kinds differed, then the substitution would take a well-kinded
 type to an ill-kinded one.
 
-Note [Holes]
-~~~~~~~~~~~~
-This Note explains how GHC tracks *holes*.
-
-A hole represents one of two conditions:
- - A missing bit of an expression. Example: foo x = x + _
- - A missing bit of a type. Example: bar :: Int -> _
-
-What these have in common is that both cause GHC to emit a diagnostic to the
-user describing the bit that is left out.
-
-When a hole is encountered, a new entry of type Hole is added to the ambient
-WantedConstraints. The type (hole_ty) of the hole is then simplified during
-solving (with respect to any Givens in surrounding implications). It is
-reported with all the other errors in GHC.Tc.Errors.
-
-For expression holes, the user has the option of deferring errors until runtime
-with -fdefer-type-errors. In this case, the hole actually has evidence: this
-evidence is an erroring expression that prints an error and crashes at runtime.
-The ExprHole variant of holes stores an IORef EvTerm that will contain this evidence;
-during constraint generation, this IORef was stored in the HsUnboundVar extension
-field by the type checker. The desugarer simply dereferences to get the CoreExpr.
-
-Prior to fixing #17812, we used to invent an Id to hold the erroring
-expression, and then bind it during type-checking. But this does not support
-representation-polymorphic out-of-scope identifiers. See
-typecheck/should_compile/T17812. We thus use the mutable-CoreExpr approach
-described above.
-
-You might think that the type in the HoleExprRef is the same as the type of the
-hole. However, because the hole type (hole_ty) is rewritten with respect to
-givens, this might not be the case. That is, the hole_ty is always (~) to the
-type of the HoleExprRef, but they might not be `eqType`. We need the type of the generated
-evidence to match what is expected in the context of the hole, and so we must
-store these types separately.
-
-Type-level holes have no evidence at all.
+Note [Holes in expressions]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+This Note explains how GHC tracks "holes" in expressions.  It does not
+deal with holes in types, nor with partial type signatures.
+
+A hole represents a missing bit of an expression. Example:
+   foo x = x && _
+GHC then emits a diagnostic, describing the bit that is left out:
+  Foo.hs:5:14: error: [GHC-88464]
+    • Found hole: _ :: Bool
+    • In the second argument of ‘(&&)’, namely ‘_’
+      In the expression: x && _
+
+GHC uses the same mechanism is used to give diagnostics for out-of-scope
+variables:
+   foo x = x && y
+gives diagnostic
+  Foo.hs:5:14: error: [GHC-88464]
+    Variable not in scope: y :: Bool
+
+Here is how holes are represented in expressions:
+
+* If the user wrote "_":
+    Parser        HsHole
+    Renamer       XExpr (HsUnboundVarRn "_")
+    Typechecker   XExpr (HsUnboundVarTc ref "_")
+
+* If the user wrote "x", where `x` is not in scope
+   Parser        HsVar "x"
+   Renamer       XExpr (HsUnboundVarRn "x")
+   Typechecker   XExpr (HsUnboundVarTc ref "x")
+
+In both cases (ref::HoleExprRef) contains
+   - The type of the hole.
+   - A ref-cell that is filled in (by the typechecker) with an
+     error thunk.   With -fdefer-type errors we use this as the
+     value of the hole.
+   - A Unique (see Note [Uniques and tags]).
+
+Typechecking holes
+
+* When the typechecker encounters a `HsUnboundVarRn`, it returns
+  a `HsUnboundVarTc`, but also emits a `DelayedError` into the `WantedConstraints`.
+
+* This DelayedError later triggers the error reporting, and the filling-in of
+  the error thunk, in GHC.Tc.Errors.
+
+* The user has the option of deferring errors until runtime with
+  `-fdefer-type-errors`. In this case, the hole carries evidence in its
+  `HoleExprRef`. This evidence is an erroring expression that prints an error
+  and crashes at runtime.
+
+Desugaring holes
+
+* During desugaring, the `(HsExpr (HsUnboundVarTc ref "x"))` is desugared by
+  reading the ref-cell to find the error thunk evidence term, put there by the
+  constraint solver.
+
+Wrinkles:
+
+* Prior to fixing #17812, we used to invent an Id to hold the erroring
+  expression, and then bind it during type-checking. But this does not support
+  representation-polymorphic out-of-scope identifiers. See
+  typecheck/should_compile/T17812. We thus use the mutable-CoreExpr approach
+  described above.
+
+* You might think that the type in the HoleExprRef is the same as the type of the
+  hole. However, because the hole type (hole_ty) is rewritten with respect to
+  givens, this might not be the case. That is, the hole_ty is always (~) to the
+  type of the HoleExprRef, but they might not be `eqType`. We need the type of the generated
+  evidence to match what is expected in the context of the hole, and so we must
+  store these types separately.
 -}
 
 mkNonCanonical :: CtEvidence -> Ct


=====================================
compiler/GHC/Tc/Types/Evidence.hs
=====================================
@@ -594,7 +594,7 @@ data EvCallStack
 -}
 
 -- | Where to store evidence for expression holes
--- See Note [Holes] in GHC.Tc.Types.Constraint
+-- See Note [Holes in expressions] in GHC.Tc.Types.Constraint
 data HoleExprRef = HER (IORef EvTerm)   -- ^ where to write the erroring expression
                        TcType           -- ^ expected type of that expression
                        Unique           -- ^ for debug output only


=====================================
compiler/GHC/Tc/Types/Origin.hs
=====================================
@@ -717,7 +717,6 @@ lexprCtOrigin (L _ e) = exprCtOrigin e
 exprCtOrigin :: HsExpr GhcRn -> CtOrigin
 exprCtOrigin (HsVar _ (L _ name)) = OccurrenceOf name
 exprCtOrigin (HsGetField _ _ (L _ f)) = HasFieldOrigin (field_label $ unLoc $ dfoLabel f)
-exprCtOrigin (HsUnboundVar {})    = Shouldn'tHappenOrigin "unbound variable"
 exprCtOrigin (HsRecSel _ f)       = OccurrenceOfRecSel (unLoc $ foLabel f)
 exprCtOrigin (HsOverLabel _ l)  = OverLabelOrigin l
 exprCtOrigin (ExplicitList {})    = ListOrigin
@@ -752,12 +751,14 @@ exprCtOrigin (HsUntypedSplice {})  = Shouldn'tHappenOrigin "TH untyped splice"
 exprCtOrigin (HsProc {})         = Shouldn'tHappenOrigin "proc"
 exprCtOrigin (HsStatic {})       = Shouldn'tHappenOrigin "static expression"
 exprCtOrigin (HsEmbTy {})        = Shouldn'tHappenOrigin "type expression"
+exprCtOrigin (HsHole {})         = Shouldn'tHappenOrigin "hole expression"
 exprCtOrigin (HsForAll {})       = Shouldn'tHappenOrigin "forall telescope"    -- See Note [Types in terms]
 exprCtOrigin (HsQual {})         = Shouldn'tHappenOrigin "constraint context"  -- See Note [Types in terms]
 exprCtOrigin (HsFunArr {})       = Shouldn'tHappenOrigin "function arrow"      -- See Note [Types in terms]
 exprCtOrigin (XExpr (ExpandedThingRn thing _)) | OrigExpr a <- thing = exprCtOrigin a
                                                | OrigStmt _ <- thing = DoOrigin
                                                | OrigPat p  <- thing = DoPatOrigin p
+exprCtOrigin (XExpr (HsUnboundVarRn {})) = Shouldn'tHappenOrigin "unbound variable"
 exprCtOrigin (XExpr (PopErrCtxt {})) = Shouldn'tHappenOrigin "PopErrCtxt"
 
 -- | Extract a suitable CtOrigin from a MatchGroup


=====================================
compiler/GHC/Tc/Zonk/Type.hs
=====================================
@@ -925,9 +925,9 @@ zonkExpr (HsVar x (L l id))
   do { id' <- zonkIdOcc id
      ; return (HsVar x (L l id')) }
 
-zonkExpr (HsUnboundVar her occ)
+zonkExpr (XExpr (HsUnboundVarTc her occ))
   = do her' <- zonk_her her
-       return (HsUnboundVar her' occ)
+       return (XExpr (HsUnboundVarTc her' occ))
   where
     zonk_her :: HoleExprRef -> ZonkTcM HoleExprRef
     zonk_her (HER ref ty u)
@@ -1079,6 +1079,7 @@ zonkExpr (HsEmbTy x _) = dataConCantHappen x
 zonkExpr (HsQual x _ _) = dataConCantHappen x
 zonkExpr (HsForAll x _ _) = dataConCantHappen x
 zonkExpr (HsFunArr x _ _ _) = dataConCantHappen x
+zonkExpr (HsHole x) = dataConCantHappen x
 
 zonkExpr (XExpr (WrapExpr (HsWrap co_fn expr)))
   = runZonkBndrT (zonkCoFn co_fn) $ \ new_co_fn ->


=====================================
compiler/Language/Haskell/Syntax/Expr.hs
=====================================
@@ -41,7 +41,6 @@ import Data.Bool
 import Data.Eq
 import Data.Maybe
 import Data.List.NonEmpty ( NonEmpty )
-import GHC.Types.Name.Reader
 
 {- Note [RecordDotSyntax field updates]
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -338,19 +337,6 @@ data HsExpr p
   = HsVar     (XVar p)
               (LIdP p) -- ^ Variable
                        -- See Note [Located RdrNames]
-
-  | HsUnboundVar (XUnboundVar p)
-                 RdrName     -- ^ Unbound variable; also used for "holes"
-                             --   (_ or _x).
-                             -- Turned from HsVar to HsUnboundVar by the
-                             --   renamer, when it finds an out-of-scope
-                             --   variable or hole.
-                             -- The (XUnboundVar p) field becomes an HoleExprRef
-                             --   after typechecking; this is where the
-                             --   erroring expression will be written after
-                             --   solving. See Note [Holes] in GHC.Tc.Types.Constraint.
-
-
   | HsRecSel  (XRecSel p)
               (FieldOcc p) -- ^ Variable pointing to record selector
                            -- See Note [Non-overloaded record field selectors] and
@@ -404,7 +390,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 HsRecSel or HsUnboundVar
+  -- the renamer may turn a HsVar into HsRecSel or HsUnboundVarRn
 
   | OpApp       (XOpApp p)
                 (LHsExpr p)       -- left operand
@@ -651,6 +637,10 @@ data HsExpr p
   | HsEmbTy   (XEmbTy p)
               (LHsWcType (NoGhcTc p))
 
+   -- | Holes in expressions.
+   -- See Note [Holes in expressions] in GHC.Tc.Types.Constraint.
+  | HsHole (XHole p)
+
   -- | Forall-types @forall tvs. t@ and @forall tvs -> t at .
   -- Used with @RequiredTypeArguments@, e.g. @fn (forall a. Proxy a)@.
   -- See Note [Types in terms]


=====================================
compiler/Language/Haskell/Syntax/Extension.hs
=====================================
@@ -448,6 +448,7 @@ type family XTick           x
 type family XBinTick        x
 type family XPragE          x
 type family XEmbTy          x
+type family XHole           x
 type family XForAll         x
 type family XQual           x
 type family XFunArr         x


=====================================
testsuite/tests/perf/compiler/hard_hole_fits.hs
=====================================
@@ -12,7 +12,7 @@ import GHC (GhcPs)
 
 testMe :: HsExpr GhcPs -> Int
 testMe (HsVar a b) = _
-testMe (HsUnboundVar xuv uv) = _
+testMe (HsHole a) = _
 testMe (HsOverLabel xol m_ip) = _
 testMe (HsIPVar xv hin) = _
 testMe (HsOverLit xole hol) = _


=====================================
testsuite/tests/perf/compiler/hard_hole_fits.stderr
=====================================
@@ -17,14 +17,12 @@ hard_hole_fits.hs:14:22: warning: [GHC-88464] [-Wtyped-holes (in -Wdefault)]
           (imported from ‘Prelude’ at hard_hole_fits.hs:8:8-20
            (and originally defined in ‘GHC.Internal.Enum’))
 
-hard_hole_fits.hs:15:32: warning: [GHC-88464] [-Wtyped-holes (in -Wdefault)]
-    • Found hole: _ :: Int
-    • In an equation for ‘testMe’: testMe (HsUnboundVar xuv uv) = _
-    • Relevant bindings include
-        uv :: GHC.Types.Name.Reader.RdrName
-          (bound at hard_hole_fits.hs:15:26)
-        xuv :: Language.Haskell.Syntax.Extension.XUnboundVar GhcPs
-          (bound at hard_hole_fits.hs:15:22)
+hard_hole_fits.hs:15:21: warning: [GHC-88464] [-Wtyped-holes (in -Wdefault)]
+     Found hole: _ :: Int
+     In an equation for ‘testMe’: testMe (HsHole a) = _
+     Relevant bindings include
+        a :: Language.Haskell.Syntax.Extension.XHole GhcPs
+          (bound at hard_hole_fits.hs:15:16)
         testMe :: HsExpr GhcPs -> Int (bound at hard_hole_fits.hs:14:1)
       Valid hole fits include
         maxBound :: forall a. Bounded a => a


=====================================
testsuite/tests/plugins/T20803-plugin/FixErrorsPlugin.hs
=====================================
@@ -20,15 +20,15 @@ import Data.Maybe
 plugin :: Plugin
 plugin = defaultPlugin {parsedResultAction = parsedAction}
 
--- Replace every hole (and other unbound vars) with the given expression
+-- Replace every hole with the given expression
 replaceHoles :: forall a . Data a => HsExpr GhcPs -> a -> a
 replaceHoles new = gmapT \case
   (d :: d) -> replaceHoles new d `fromMaybe` tryHole
     where
       tryHole :: Maybe d
       tryHole = eqT @d @(HsExpr GhcPs) >>= \case
-        Eq.Refl | HsUnboundVar _ _ <- d -> Just new
-        _                               -> Nothing
+        Eq.Refl | HsHole _ <- d -> Just new
+        _                       -> Nothing
 
 parsedAction :: [CommandLineOption] -> ModSummary
              -> ParsedResult -> Hsc ParsedResult


=====================================
utils/check-exact/ExactPrint.hs
=====================================
@@ -329,7 +329,7 @@ instance HasTrailing AnnExplicitSum where
   trailing _ = []
   setTrailing a _ = a
 
-instance HasTrailing (Maybe EpAnnUnboundVar) where
+instance HasTrailing (Maybe EpAnnHole) where
   trailing _ = []
   setTrailing a _ = a
 
@@ -3042,16 +3042,16 @@ instance ExactPrint (HsExpr GhcPs) where
       then markAnnotated n
       else return n
     return (HsVar x n')
-  exact (HsUnboundVar an n) = do
+  exact x@(HsHole an) = do
     case an of
-      Just (EpAnnUnboundVar (ob,cb) l) -> do
-        ob' <-  printStringAtAA ob "`"
+      Just (EpAnnHole (ob,cb) l) -> do
+        ob' <- printStringAtAA ob "`"
         l' <- printStringAtAA l  "_"
         cb' <- printStringAtAA cb "`"
-        return (HsUnboundVar (Just (EpAnnUnboundVar (ob',cb') l')) n)
-      _ -> do
-        printStringAdvanceA "_" >> return ()
-        return (HsUnboundVar an n)
+        return (HsHole (Just (EpAnnHole (ob',cb') l')))
+      Nothing -> do
+        printStringAdvanceA "_"
+        return x
   exact x@(HsOverLabel src l) = do
     printStringAdvanceA "#" >> return ()
     case src of



View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/7ed954d99ef1a3f3798630bb46d08b404567e9d1

-- 
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/7ed954d99ef1a3f3798630bb46d08b404567e9d1
You're receiving this email because of your account on gitlab.haskell.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/ghc-commits/attachments/20240913/155550ae/attachment-0001.html>


More information about the ghc-commits mailing list