Simon Peyton Jones pushed to branch wip/spj-apporv-Oct24 at Glasgow Haskell Compiler / GHC Commits: 55c4f2b4 by Simon Peyton Jones at 2026-01-27T16:40:20+00:00 Wibbles - - - - - 3 changed files: - compiler/GHC/Tc/Gen/Expr.hs - compiler/GHC/Tc/Gen/Head.hs - compiler/GHC/Tc/Utils/Monad.hs Changes: ===================================== compiler/GHC/Tc/Gen/Expr.hs ===================================== @@ -762,47 +762,73 @@ tcExpr (SectionR {}) ty = pprPanic "tcExpr:SectionR" (ppr ty) ************************************************************************ -} -{- Note [Overview of Typechecking an XExpr] -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Certain constructs undergo expansion right before type checking. +{- Note [Typechecking by expansion: overview] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +For many constructs, rather than typechecking the user-written code +directly, it's much easier to + * Expand (or desugar) the code to something simpler + * Typecheck that simpler expression - tcExpr ue@(RecordUpd{}) rho = do { ee <- expand e; tcExpr ee rho } +Example: record updates. The typechecker looks like this: -See Note [Handling overloaded and rebindable constructs] and -Note [Doing XXExprGhcRn in the Renamer vs Typechecker] -for details about which constructs are expanded. + tcExpr e@(RecordUpd{}) rho = do { ee <- expandExpr e + ; tcExpr ee rho } -The expansion process typically takes a user written thing - L lspan ue -and returns - L lspan (XExpr (ExpandedThingRn { xrn_orig = ue - , xrn_expanded = ee } )) +The `expandExpr` replaces the record update (e { x = rhs }) +with something like + case e of { MkT a b _ d -> MkT a b rhs d } +and we then typecheck the latter. -where `ee` is the expansion of the user written thing `ue` +See also Note [Handling overloaded and rebindable constructs] + and Note [Doing XXExprGhcRn in the Renamer vs Typechecker] -Now, when a `tcMonoLHsExpr :: LHsExpr GhcRn -> ExpRhoType -> TcM (HsExpr GhcTc)` -gets a located expression, It does 2 things: -1. calls `addLExprCtxt` to perform error context management, and; -2. calls tcExpr to typecheck the expression. +The Big Question is how to ensure that error messages mention +only user-written source code, and never talk about the expanded code. +The rest of this Note explains how that is done. -The type checker context has 2 key fields: +* The expansion process typically takes a user written thing + L lspan ue + and returns + L lspan (XExpr (ExpandedThingRn { xrn_orig = ue + , xrn_expanded = ee } )) + where `ee` is the expansion of the user written thing `ue` - TcLclCtxt { tcl_loc :: RealSrcSpan - , tcl_err_ctxt :: [ErrCtxt] +* The type checker context has 2 key fields that describe the context: + TcLclCtxt { tcl_loc :: RealSrcSpan + , tcl_err_ctxt :: [ErrCtxt] , ... } - -When called on an XExpr, `addLExprCtxt` updates the location of `tcl_loc` with -the `lspan` above and adds an ErrCtxt on top of the `tcl_err_ctxt`. If the -`lspan` is generated, then `addLExprCtxt` is a no-op. - -The type checker error stack element `GHC.Tc.Types.ErrCtxt.ErrCtxt` has two fields - - ErrCtxt = EC CodeSrcFlag ErrCtxtMsgM - -`CodeSrcFlag` says whether we are typechecking an expanded thing, and what that expanded thing is -`ErrCtxtMsgM` stores the pre-text error message itself. When called on an `XExpr`, `addLExprCtxt`, -adds the user written thing `ue`, and the error message provided by the caller on the `ErrCtxtStack` -See Note [ErrCtxtStack Manipulation] for more details. + Note `tcl_loc` always points to a real place in the source code, + hence `RealSrcSpan`. + + The `tcl_err_ctxt` is a stack of contexts, each saying something + like "In the expression: x+y" or "In the record update: r { x=2 }" + +* Now, when + tcMonoLHsExpr :: LHsExpr GhcRn -> ExpRhoType -> TcM (HsExpr GhcTc) + gets a located expression, it does 2 things: + * Calls `addLExprCtxt` to perform error context management + * Calls `tcExpr` to typecheck the expression. + +* `addLExprCtxt span expr` + (1) updates the location of `tcl_loc` with the `span` above, + (2) adds an `ErrCtxt` on top of the `tcl_err_ctxt`. + +* However, if the `span` is generated (see `isGeneratedSrcSpan`), then + `addLExprCtxt` is a no-op. Crucially, when we generate code in `expandExpr`, + all the generated AST notes are tagged with a `GeneratedSrcSpan`. This + is how we avoid populating the TcLclCtxt with generated code. + +* The type checker error-stack element `GHC.Tc.Types.ErrCtxt.ErrCtxt` + has two fields + data ErrCtxt = EC ErrCtxt + + * `CodeSrcFlag` says whether we are typechecking an expanded thing, + and what that expanded thing is + * `ErrCtxtMsgM` stores the pre-text error message itself. + + When called on an `XExpr`, `addLExprCtxt`, adds the user written thing + `ue`, and the error message provided by the caller on the `ErrCtxtStack` See + Note [ErrCtxtStack Manipulation] for more details. -} ===================================== compiler/GHC/Tc/Gen/Head.hs ===================================== @@ -19,8 +19,7 @@ module GHC.Tc.Gen.Head , tyConOf, tyConOfET , nonBidirectionalErr - , pprArgInst - , addLExprCtxt, addFunResCtxt ) where + , pprArgInst, addFunResCtxt ) where import {-# SOURCE #-} GHC.Tc.Gen.Expr( tcExpr, tcCheckPolyExprNC, tcPolyLExprSig ) import {-# SOURCE #-} GHC.Tc.Gen.Splice( getUntypedSpliceBody ) @@ -1076,39 +1075,3 @@ Notice that tcSplitNestedSigmaTys looks through function arrows too, regardless of simple/deep subsumption. Here we are concerned only whether there is a mis-match in the number of value arguments. -} - - -{- ********************************************************************* -* * - Misc utility functions -* * -********************************************************************* -} - --- | !Caution!: Users should not call add_expr_ctxt, they ought to use addLExprCtxt -add_expr_ctxt :: HsExpr GhcRn -> TcRn a -> TcRn a -add_expr_ctxt e thing_inside - = case e of - HsHole{} -> thing_inside - -- The HsHole 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 - - ExprWithTySig _ (L _ e') _ - | XExpr (ExpandedThingRn o _) <- e' -> addExpansionErrCtxt o (ExprCtxt e) thing_inside - -- There is a special case for expressions with signatures to avoid having too verbose - -- error context. So here we flip the ErrCtxt state to expanded if the expression is expanded. - -- c.f. RecordDotSyntaxFail9 - - XExpr (ExpandedThingRn o _) -> addExpansionErrCtxt o (srcCodeOriginErrCtxMsg o) thing_inside - -- Flip error ctxt into expansion mode - - _ -> addErrCtxt (ExprCtxt e) thing_inside - - -addLExprCtxt :: SrcSpan -> HsExpr GhcRn -> TcRn a -> TcRn a -addLExprCtxt lspan e thing_inside - | not (isGeneratedSrcSpan lspan) - = setSrcSpan lspan $ add_expr_ctxt e thing_inside - | otherwise -- no op in generated code - = thing_inside ===================================== compiler/GHC/Tc/Utils/Monad.hs ===================================== @@ -88,7 +88,7 @@ module GHC.Tc.Utils.Monad( -- * Context management for the type checker getErrCtxt, setErrCtxt, addErrCtxt, addErrCtxtM, addLandmarkErrCtxt, - addExpansionErrCtxt, addExpansionErrCtxtM, + addLExprCtxt, addExpansionErrCtxt, addExpansionErrCtxtM, addLandmarkErrCtxtM, popErrCtxt, getCtLocM, setCtLocM, mkCtLocEnv, -- * Diagnostic message generation (type checker) @@ -1324,6 +1324,35 @@ relation with pattern-match checks - See Note [ErrCtxtStack Manipulation] in `GHC.Tc.Types.LclEnv` for info about `ErrCtxtStack` -} +addLExprCtxt :: SrcSpan -> HsExpr GhcRn -> TcRn a -> TcRn a +addLExprCtxt lspan e thing_inside + | not (isGeneratedSrcSpan lspan) + = setSrcSpan lspan $ add_expr_ctxt e thing_inside + | otherwise -- no op in generated code + = thing_inside + +-- | !Caution!: Users should not call add_expr_ctxt, they ought to use addLExprCtxt +add_expr_ctxt :: HsExpr GhcRn -> TcRn a -> TcRn a +add_expr_ctxt e thing_inside + = case e of + HsHole{} -> thing_inside + -- The HsHole 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 + + ExprWithTySig _ (L _ e') _ + | XExpr (ExpandedThingRn o _) <- e' -> addExpansionErrCtxt o (ExprCtxt e) thing_inside + -- There is a special case for expressions with signatures to avoid having too verbose + -- error context. So here we flip the ErrCtxt state to expanded if the expression is expanded. + -- c.f. RecordDotSyntaxFail9 + + XExpr (ExpandedThingRn o _) -> addExpansionErrCtxt o (srcCodeOriginErrCtxMsg o) thing_inside + -- Flip error ctxt into expansion mode + + _ -> addErrCtxt (ExprCtxt e) thing_inside + + getErrCtxt :: TcM [ErrCtxt] getErrCtxt = do { env <- getLclEnv; return (getLclEnvErrCtxt env) } @@ -1335,7 +1364,7 @@ setErrCtxt ctxt = updLclEnv (setLclEnvErrCtxt ctxt) -- do any tidying. -- See Note [Rebindable syntax and XXExprGhcRn] in GHC.Hs.Expr addErrCtxt :: ErrCtxtMsg -> TcM a -> TcM a -{-# INLINE addErrCtxt #-} -- Note [Inlining addErrCtxt] +o{-# INLINE addErrCtxt #-} -- Note [Inlining addErrCtxt] addErrCtxt msg = addErrCtxtM (\env -> return (env, msg)) -- See Note [ErrCtxtStack Manipulation] View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/55c4f2b41a36a96c1166721f906e0941... -- View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/55c4f2b41a36a96c1166721f906e0941... You're receiving this email because of your account on gitlab.haskell.org.