Apoorv Ingle pushed to branch wip/spj-apporv-Oct24 at Glasgow Haskell Compiler / GHC
Commits:
-
f6b42024
by Apoorv Ingle at 2025-08-11T11:02:36-05:00
-
90a013ab
by Apoorv Ingle at 2025-08-11T11:25:12-05:00
7 changed files:
- compiler/GHC/Hs/Expr.hs
- compiler/GHC/Tc/Gen/App.hs
- compiler/GHC/Tc/Gen/Do.hs
- compiler/GHC/Tc/Gen/Expr.hs
- compiler/GHC/Tc/Gen/Head.hs
- compiler/GHC/Tc/Types/LclEnv.hs
- compiler/GHC/Tc/Utils/Monad.hs
Changes:
... | ... | @@ -675,11 +675,11 @@ type instance XXExpr GhcTc = XXExprGhcTc |
675 | 675 | data SrcCodeOrigin
|
676 | 676 | = OrigExpr (HsExpr GhcRn) -- ^ The source, user written, expression
|
677 | 677 | | OrigStmt (ExprLStmt GhcRn) HsDoFlavour -- ^ which kind of do-block did this statement come from
|
678 | - | OrigPat (Pat GhcRn) -- ^ Used for failable patterns that trigger MonadFail constraints
|
|
678 | + | OrigPat (Pat GhcRn) -- ^ Used for failable patterns that trigger MonadFail constraints
|
|
679 | 679 | |
680 | 680 | data XXExprGhcRn
|
681 | - = ExpandedThingRn { xrn_orig :: SrcCodeOrigin -- The original source thing to be used for error messages
|
|
682 | - , xrn_expanded :: HsExpr GhcRn -- The compiler generated expanded thing
|
|
681 | + = ExpandedThingRn { xrn_orig :: SrcCodeOrigin -- The original source thing to be used for error messages
|
|
682 | + , xrn_expanded :: HsExpr GhcRn -- The compiler generated, expanded thing
|
|
683 | 683 | }
|
684 | 684 | |
685 | 685 | | PopErrCtxt -- A hint for typechecker to pop
|
... | ... | @@ -544,17 +544,18 @@ tcValArgs do_ql fun args = go do_ql 0 args |
544 | 544 | go do_ql pos (arg : args) =
|
545 | 545 | do { arg' <- tcValArg do_ql pos' fun arg
|
546 | 546 | ; args' <- go do_ql pos' args
|
547 | - ; return (arg' : args')
|
|
548 | - }
|
|
547 | + ; return (arg' : args') }
|
|
549 | 548 | where
|
550 | 549 | -- increment position if the argument is user written type or value argument
|
551 | 550 | pos' | EValArg{} <- arg
|
552 | 551 | = pos + 1
|
553 | 552 | | EValArgQL{} <- arg
|
554 | 553 | = pos + 1
|
555 | - | ETypeArg{ ea_ctxt = l } <- arg
|
|
556 | - , not (isGeneratedSrcSpan l) = pos + 1
|
|
557 | - | otherwise = pos
|
|
554 | + | ETypeArg{ ea_loc_span = l } <- arg
|
|
555 | + , not (isGeneratedSrcSpan l)
|
|
556 | + = pos + 1
|
|
557 | + | otherwise
|
|
558 | + = pos
|
|
558 | 559 | |
559 | 560 | |
560 | 561 | tcValArg :: QLFlag -> Int -> HsExpr GhcRn -> HsExprArg 'TcpInst -- Actual argument
|
... | ... | @@ -566,7 +567,7 @@ tcValArg do_ql _ _ (EWrap (EHsWrap w)) = do { whenQL do_ql $ qlMonoHsWrapper w |
566 | 567 | -- qlMonoHsWrapper: see Note [Monomorphise instantiation variables]
|
567 | 568 | tcValArg _ _ _ (EWrap ew) = return (EWrap ew)
|
568 | 569 | |
569 | -tcValArg do_ql pos fun (EValArg { ea_ctxt = ctxt
|
|
570 | +tcValArg do_ql pos fun (EValArg { ea_loc_span = ctxt
|
|
570 | 571 | , ea_arg = larg@(L arg_loc arg)
|
571 | 572 | , ea_arg_ty = sc_arg_ty })
|
572 | 573 | = addArgCtxt pos fun larg $
|
... | ... | @@ -594,20 +595,21 @@ tcValArg do_ql pos fun (EValArg { ea_ctxt = ctxt |
594 | 595 | tcPolyExpr arg (mkCheckExpType exp_arg_ty)
|
595 | 596 | ; traceTc "tcValArg" $ vcat [ ppr arg'
|
596 | 597 | , text "}" ]
|
597 | - ; return (EValArg { ea_ctxt = ctxt
|
|
598 | + ; return (EValArg { ea_loc_span = ctxt
|
|
598 | 599 | , ea_arg = L arg_loc arg'
|
599 | 600 | , ea_arg_ty = noExtField }) }
|
600 | 601 | |
601 | -tcValArg _ pos fun (EValArgQL { eaql_wanted = wanted
|
|
602 | - , eaql_ctxt = ctxt
|
|
603 | - , eaql_arg_ty = sc_arg_ty
|
|
604 | - , eaql_larg = larg@(L arg_loc rn_expr)
|
|
605 | - , eaql_tc_fun = tc_head
|
|
606 | - , eaql_rn_fun = rn_fun
|
|
607 | - , eaql_fun_ue = head_ue
|
|
608 | - , eaql_args = inst_args
|
|
609 | - , eaql_encl = arg_influences_enclosing_call
|
|
610 | - , eaql_res_rho = app_res_rho })
|
|
602 | +tcValArg _ pos fun (EValArgQL {
|
|
603 | + eaql_wanted = wanted
|
|
604 | + , eaql_loc_span = ctxt
|
|
605 | + , eaql_arg_ty = sc_arg_ty
|
|
606 | + , eaql_larg = larg@(L arg_loc rn_expr)
|
|
607 | + , eaql_tc_fun = tc_head
|
|
608 | + , eaql_rn_fun = rn_fun
|
|
609 | + , eaql_fun_ue = head_ue
|
|
610 | + , eaql_args = inst_args
|
|
611 | + , eaql_encl = arg_influences_enclosing_call
|
|
612 | + , eaql_res_rho = app_res_rho })
|
|
611 | 613 | = addArgCtxt pos fun larg $
|
612 | 614 | do { -- Expose QL results to tcSkolemise, as in EValArg case
|
613 | 615 | Scaled mult exp_arg_ty <- liftZonkM $ zonkScaledTcType sc_arg_ty
|
... | ... | @@ -644,7 +646,7 @@ tcValArg _ pos fun (EValArgQL { eaql_wanted = wanted |
644 | 646 | ; traceTc "tcEValArgQL }" $
|
645 | 647 | vcat [ text "app_res_rho:" <+> ppr app_res_rho ]
|
646 | 648 | |
647 | - ; return (EValArg { ea_ctxt = ctxt
|
|
649 | + ; return (EValArg { ea_loc_span = ctxt
|
|
648 | 650 | , ea_arg = L arg_loc (mkHsWrap wrap arg')
|
649 | 651 | , ea_arg_ty = noExtField }) }
|
650 | 652 | |
... | ... | @@ -814,10 +816,10 @@ tcInstFun do_ql inst_final fun_orig (tc_fun, rn_fun, fun_ctxt) fun_sigma rn_args |
814 | 816 | = go1 pos (EPrag sp prag : acc) fun_ty args
|
815 | 817 | |
816 | 818 | -- Rule ITYARG from Fig 4 of the QL paper
|
817 | - go1 pos acc fun_ty ( ETypeArg { ea_ctxt = ctxt, ea_hs_ty = hs_ty }
|
|
819 | + go1 pos acc fun_ty ( ETypeArg { ea_loc_span = ctxt, ea_hs_ty = hs_ty }
|
|
818 | 820 | : rest_args )
|
819 | 821 | = do { (ty_arg, inst_ty) <- tcVTA fun_conc_tvs fun_ty hs_ty
|
820 | - ; let arg' = ETypeArg { ea_ctxt = ctxt, ea_hs_ty = hs_ty, ea_ty_arg = ty_arg }
|
|
822 | + ; let arg' = ETypeArg { ea_loc_span = ctxt, ea_hs_ty = hs_ty, ea_ty_arg = ty_arg }
|
|
821 | 823 | ; go pos (arg' : acc) inst_ty rest_args }
|
822 | 824 | |
823 | 825 | -- Rule IVAR from Fig 4 of the QL paper:
|
... | ... | @@ -857,7 +859,7 @@ tcInstFun do_ql inst_final fun_orig (tc_fun, rn_fun, fun_ctxt) fun_sigma rn_args |
857 | 859 | |
858 | 860 | -- Rule IARG from Fig 4 of the QL paper:
|
859 | 861 | go1 pos acc fun_ty
|
860 | - (EValArg { ea_arg = arg, ea_ctxt = ctxt } : rest_args)
|
|
862 | + (EValArg { ea_arg = arg, ea_loc_span = ctxt } : rest_args)
|
|
861 | 863 | = do { let herald = mk_herald tc_fun (unLoc arg)
|
862 | 864 | ; (wrap, arg_ty, res_ty) <-
|
863 | 865 | -- NB: matchActualFunTy does the rep-poly check.
|
... | ... | @@ -924,9 +926,9 @@ addArgCtxt :: Int -> HsExpr GhcRn -> LHsExpr GhcRn |
924 | 926 | -- There are 2 cases:
|
925 | 927 | -- 1. In the normal case, we add an informative context
|
926 | 928 | -- "In the third argument of f, namely blah"
|
927 | --- 2. If we are deep inside generated code (`isGeneratedCode` is `True`)
|
|
929 | +-- 2. If we are deep inside generated code (<=> `isGeneratedCode` is `True`)
|
|
928 | 930 | -- "In the expression: arg"
|
929 | --- If the arg is also a generated thing, i.e. arg_loc is generatedSrcSpan, we would print do nothing.
|
|
931 | +-- If the arg is also a generated thing, i.e. `arg_loc` is `generatedSrcSpan`, we would print nothing.
|
|
930 | 932 | -- See Note [Rebindable syntax and XXExprGhcRn] in GHC.Hs.Expr
|
931 | 933 | -- See Note [Expanding HsDo with XXExprGhcRn] in GHC.Tc.Gen.Do
|
932 | 934 | addArgCtxt arg_no fun (L arg_loc arg) thing_inside
|
... | ... | @@ -1733,7 +1735,7 @@ quickLookArg DoQL pos ctxt fun larg orig_arg_ty |
1733 | 1735 | skipQuickLook :: SrcSpan -> LHsExpr GhcRn -> Scaled TcRhoType
|
1734 | 1736 | -> TcM (HsExprArg 'TcpInst)
|
1735 | 1737 | skipQuickLook ctxt larg arg_ty
|
1736 | - = return (EValArg { ea_ctxt = ctxt
|
|
1738 | + = return (EValArg { ea_loc_span = ctxt
|
|
1737 | 1739 | , ea_arg = larg
|
1738 | 1740 | , ea_arg_ty = arg_ty })
|
1739 | 1741 | |
... | ... | @@ -1834,16 +1836,16 @@ quickLookArg1 pos ctxt fun larg@(L _ arg) sc_arg_ty@(Scaled _ orig_arg_rho) |
1834 | 1836 | |
1835 | 1837 | ; traceTc "quickLookArg done }" (ppr rn_fun)
|
1836 | 1838 | |
1837 | - ; return (EValArgQL { eaql_ctxt = ctxt
|
|
1838 | - , eaql_arg_ty = sc_arg_ty
|
|
1839 | - , eaql_larg = larg
|
|
1840 | - , eaql_tc_fun = tc_head
|
|
1841 | - , eaql_rn_fun = rn_fun
|
|
1842 | - , eaql_fun_ue = fun_ue
|
|
1843 | - , eaql_args = inst_args
|
|
1844 | - , eaql_wanted = wanted
|
|
1845 | - , eaql_encl = arg_influences_enclosing_call
|
|
1846 | - , eaql_res_rho = app_res_rho }) }}}
|
|
1839 | + ; return (EValArgQL { eaql_loc_span = ctxt
|
|
1840 | + , eaql_arg_ty = sc_arg_ty
|
|
1841 | + , eaql_larg = larg
|
|
1842 | + , eaql_tc_fun = tc_head
|
|
1843 | + , eaql_rn_fun = rn_fun
|
|
1844 | + , eaql_fun_ue = fun_ue
|
|
1845 | + , eaql_args = inst_args
|
|
1846 | + , eaql_wanted = wanted
|
|
1847 | + , eaql_encl = arg_influences_enclosing_call
|
|
1848 | + , eaql_res_rho = app_res_rho }) }}}
|
|
1847 | 1849 | |
1848 | 1850 | {- *********************************************************************
|
1849 | 1851 | * *
|
... | ... | @@ -75,7 +75,7 @@ expand_do_stmts _ (stmt@(L _ (XStmtLR ApplicativeStmt{})): _) = |
75 | 75 | |
76 | 76 | expand_do_stmts _ [] = pprPanic "expand_do_stmts: impossible happened. Empty stmts" empty
|
77 | 77 | |
78 | -expand_do_stmts flav [stmt@(L sloc (LastStmt _ body@(L body_loc _) _ ret_expr))]
|
|
78 | +expand_do_stmts _flav [_stmt@(L _sloc (LastStmt _ body@(L body_loc _) _ ret_expr))]
|
|
79 | 79 | -- See Note [Expanding HsDo with XXExprGhcRn] Equation (5) below
|
80 | 80 | -- last statement of a list comprehension, needs to explicitly return it
|
81 | 81 | -- See `checkLastStmt` and `Syntax.Expr.StmtLR.LastStmt`
|
... | ... | @@ -83,7 +83,7 @@ expand_do_stmts flav [stmt@(L sloc (LastStmt _ body@(L body_loc _) _ ret_expr))] |
83 | 83 | -- Last statement is just body if we are not in ListComp context. See Syntax.Expr.LastStmt
|
84 | 84 | -- = return $ L sloc (mkExpandedStmt stmt flav (HsPar noExtField body))
|
85 | 85 | = return body
|
86 | - | SyntaxExprRn ret <- ret_expr
|
|
86 | + | SyntaxExprRn ret <- ret_expr -- We have unfortunately lost the location on the return function :(
|
|
87 | 87 | --
|
88 | 88 | -- ------------------------------------------------
|
89 | 89 | -- return e ~~> return e
|
... | ... | @@ -230,7 +230,7 @@ mk_fail_block _ _ _ _ = pprPanic "mk_fail_block: impossible happened" empty |
230 | 230 | |
231 | 231 | {- Note [Expanding HsDo with XXExprGhcRn]
|
232 | 232 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
233 | -We expand `do`-blocks before typechecking it, by re-using the existing `XXExprGhcRns` and `RebindableSyntax` machinery.
|
|
233 | +We expand `do`-blocks before typechecking it, by re-using the existing `XXExprGhcRn` and `RebindableSyntax` machinery.
|
|
234 | 234 | This is very similar to:
|
235 | 235 | 1. Expansions done in `GHC.Rename.Expr.rnHsIf` for expanding `HsIf`; and
|
236 | 236 | 2. `desugarRecordUpd` in `GHC.Tc.Gen.Expr.tcExpr` for expanding `RecordUpd`
|
... | ... | @@ -275,14 +275,15 @@ They capture the essence of statement expansions as implemented in `expand_do_st |
275 | 275 | |
276 | 276 | DO【 _ 】 maps a sequence of do statements and recursively converts them into expressions
|
277 | 277 | |
278 | - (1) DO【 s; ss 】 = ‹ExpansionStmt s›((>>) s (‹PopErrCtxt›DO【 ss 】))
|
|
278 | + (1) DO【 s; ss 】 = ‹ExpansionStmt s›((>>) (‹PopErrCtxt› s) (‹PopErrCtxt› DO【 ss 】))
|
|
279 | 279 | |
280 | 280 | (2) DO【 p <- e; ss 】 = if p is irrefutable
|
281 | 281 | then ‹ExpansionStmt (p <- e)›
|
282 | - (>>=) s ((\ p -> ‹PopExprCtxt› DO【 ss 】))
|
|
282 | + (>>=) (‹PopExprCtxt› s) ((\ p -> ‹PopExprCtxt› DO【 ss 】))
|
|
283 | 283 | else ‹ExpansionStmt (p <- e)›
|
284 | - (>>=) s ((\case p -> ‹PopExprCtxt› DO【 ss 】
|
|
285 | - _ -> fail "pattern p failure"))
|
|
284 | + (>>=) (‹PopExprCtxt› s)
|
|
285 | + (\case p -> ‹PopExprCtxt› DO【 ss 】
|
|
286 | + _ -> fail "pattern p failure")
|
|
286 | 287 | |
287 | 288 | (3) DO【 let x = e; ss 】
|
288 | 289 | = ‹ExpansionStmt (let x = e)› (let x = e in (‹PopErrCtxt›DO【 ss 】))
|
... | ... | @@ -313,8 +314,8 @@ The expanded version (performed by `expand_do_stmts`) looks like: |
313 | 314 | {g2} (>>) ({l2} g p)
|
314 | 315 | ({l3} return p))
|
315 | 316 | |
316 | -The {l1} etc are location/source span information stored in the AST by the parser,
|
|
317 | -{g1} are compiler generated source spans.
|
|
317 | +The {l1}, {l2}, etc. are the location/source span information stored in the AST by the parser,
|
|
318 | +{g1}, {g2}, etc. are the compiler generated source spans.
|
|
318 | 319 | |
319 | 320 | |
320 | 321 | The 3 non-obvious points to consider are:
|
... | ... | @@ -427,10 +428,10 @@ It stores the original statement (with location) and the expanded expression |
427 | 428 | ‹ExpandedThingRn do { e1; e2; e3 }› -- Original Do Expression
|
428 | 429 | -- Expanded Do Expression
|
429 | 430 | (‹ExpandedThingRn e1› -- Original Statement
|
430 | - ({(>>) e1} -- Expanded Expression
|
|
431 | - ‹PopErrCtxt› (‹ExpandedThingRn e2›
|
|
432 | - ({(>>) e2}
|
|
433 | - ‹PopErrCtxt› (‹ExpandedThingRn e3› {e3})))))
|
|
431 | + ({(>>) ‹PopErrCtxt› e1} -- Expanded Expression
|
|
432 | + ‹PopErrCtxt› (‹ExpandedThingRn e2›
|
|
433 | + ({(>>) ‹PopErrCtxt› e2}
|
|
434 | + ‹PopErrCtxt› (‹ExpandedThingRn e3› {e3})))))
|
|
434 | 435 | |
435 | 436 | * Whenever the typechecker steps through an `ExpandedThingRn`,
|
436 | 437 | we push the original statement in the error context, set the error location to the
|
... | ... | @@ -445,7 +446,7 @@ It stores the original statement (with location) and the expanded expression |
445 | 446 | as precise as possible, and not just blame the complete `do`-block.
|
446 | 447 | Thus, when we typecheck the application `(>>) e1`, we push the "In the stmt of do block e1" with
|
447 | 448 | the source location of `e1` in the error context stack as we walk inside an `ExpandedThingRn`.
|
448 | - See also Note [splitHsApps].
|
|
449 | + See also Note [splitHsApps] and Note [Error Context Stack]
|
|
449 | 450 | |
450 | 451 | * After the expanded expression of a `do`-statement is typechecked
|
451 | 452 | and before moving to the next statement of the `do`-block, we need to first pop the top
|
... | ... | @@ -648,9 +648,9 @@ tcExpr expr@(RecordUpd { rupd_expr = record_expr |
648 | 648 | res_ty
|
649 | 649 | = assert (notNull rbnds) $
|
650 | 650 | do { -- Expand the record update. See Note [Record Updates].
|
651 | - ; (ds_expr, ds_res_ty, err_ctxt)
|
|
651 | + ; (ds_expr, ds_res_ty, err_msg)
|
|
652 | 652 | <- expandRecordUpd record_expr possible_parents rbnds res_ty
|
653 | - ; addErrCtxt err_ctxt $
|
|
653 | + ; addErrCtxt err_msg $
|
|
654 | 654 | setInGeneratedCode (OrigExpr expr) $
|
655 | 655 | do { -- Typecheck the expanded expression.
|
656 | 656 | expr' <- tcExpr ds_expr (Check ds_res_ty)
|
... | ... | @@ -748,9 +748,11 @@ tcXExpr (PopErrCtxt e) res_ty |
748 | 748 | tcExpr e res_ty
|
749 | 749 | |
750 | 750 | tcXExpr (ExpandedThingRn o e) res_ty
|
751 | - = mkExpandedTc o <$> -- necessary for breakpoints
|
|
752 | - do setInGeneratedCode o $
|
|
753 | - tcExpr e res_ty
|
|
751 | + = setInGeneratedCode o $
|
|
752 | + -- e is the expanded expression of o, so we need to set the error ctxt to generated
|
|
753 | + -- see Note [Error Context Stack] in `GHC.Tc.Type.LclEnv`
|
|
754 | + mkExpandedTc o <$> -- necessary for hpc ticks
|
|
755 | + tcExpr e res_ty
|
|
754 | 756 | |
755 | 757 | -- For record selection, same as HsVar case
|
756 | 758 | tcXExpr xe res_ty = tcApp (XExpr xe) res_ty
|
... | ... | @@ -1441,7 +1443,7 @@ expandRecordUpd record_expr possible_parents rbnds res_ty |
1441 | 1443 | |
1442 | 1444 | -- STEP 2 (b): expand to HsCase, as per note [Record Updates]
|
1443 | 1445 | ; let ds_expr :: HsExpr GhcRn
|
1444 | - ds_expr = HsLet noExtField let_binds (L gen case_expr)
|
|
1446 | + ds_expr = HsLet noExtField let_binds (wrapGenSpan case_expr)
|
|
1445 | 1447 | |
1446 | 1448 | case_expr :: HsExpr GhcRn
|
1447 | 1449 | case_expr = HsCase RecUpd record_expr
|
... | ... | @@ -1456,11 +1458,10 @@ expandRecordUpd record_expr possible_parents rbnds res_ty |
1456 | 1458 | upd_ids_lhs = [ (NonRecursive, [genSimpleFunBind (idName id) [] rhs])
|
1457 | 1459 | | (_, (id, rhs)) <- upd_ids ]
|
1458 | 1460 | mk_idSig :: (Name, (Id, LHsExpr GhcRn)) -> LSig GhcRn
|
1459 | - mk_idSig (_, (id, _)) = L gen $ XSig $ IdSig id
|
|
1461 | + mk_idSig (_, (id, _)) = wrapGenSpan (XSig $ IdSig id)
|
|
1460 | 1462 | -- We let-bind variables using 'IdSig' in order to accept
|
1461 | 1463 | -- record updates involving higher-rank types.
|
1462 | 1464 | -- See Wrinkle [Using IdSig] in Note [Record Updates].
|
1463 | - gen = noAnnSrcSpan generatedSrcSpan
|
|
1464 | 1465 | |
1465 | 1466 | ; traceTc "expandRecordUpd" $
|
1466 | 1467 | vcat [ text "relevant_con:" <+> ppr relevant_con
|
... | ... | @@ -152,6 +152,7 @@ takes apart either an HsApp, or an infix OpApp, returning |
152 | 152 | innermost un-expanded head as the "error head".
|
153 | 153 | |
154 | 154 | * A list of HsExprArg, the arguments
|
155 | +* We do not look through expanded expressions (except PopErrCtxt.)
|
|
155 | 156 | -}
|
156 | 157 | |
157 | 158 | data TcPass = TcpRn -- Arguments decomposed
|
... | ... | @@ -161,14 +162,14 @@ data TcPass = TcpRn -- Arguments decomposed |
161 | 162 | data HsExprArg (p :: TcPass) where -- See Note [HsExprArg]
|
162 | 163 | |
163 | 164 | -- Data constructor EValArg represents a value argument
|
164 | - EValArg :: { ea_ctxt :: SrcSpan
|
|
165 | + EValArg :: { ea_loc_span :: SrcSpan
|
|
165 | 166 | , ea_arg_ty :: !(XEVAType p)
|
166 | 167 | , ea_arg :: LHsExpr (GhcPass (XPass p)) }
|
167 | 168 | -> HsExprArg p
|
168 | 169 | |
169 | 170 | -- Data constructor EValArgQL represents an argument that has been
|
170 | 171 | -- partly-type-checked by Quick Look; see Note [EValArgQL]
|
171 | - EValArgQL :: { eaql_ctxt :: SrcSpan
|
|
172 | + EValArgQL :: { eaql_loc_span :: SrcSpan
|
|
172 | 173 | , eaql_arg_ty :: Scaled TcSigmaType -- Argument type expected by function
|
173 | 174 | , eaql_larg :: LHsExpr GhcRn -- Original application, for
|
174 | 175 | -- location and error msgs
|
... | ... | @@ -182,7 +183,7 @@ data HsExprArg (p :: TcPass) where -- See Note [HsExprArg] |
182 | 183 | , eaql_res_rho :: TcRhoType } -- Result type of the application
|
183 | 184 | -> HsExprArg 'TcpInst -- Only exists in TcpInst phase
|
184 | 185 | |
185 | - ETypeArg :: { ea_ctxt :: SrcSpan
|
|
186 | + ETypeArg :: { ea_loc_span :: SrcSpan
|
|
186 | 187 | , ea_hs_ty :: LHsWcType GhcRn -- The type arg
|
187 | 188 | , ea_ty_arg :: !(XETAType p) } -- Kind-checked type arg
|
188 | 189 | -> HsExprArg p
|
... | ... | @@ -215,12 +216,12 @@ type family XPass (p :: TcPass) where |
215 | 216 | XPass 'TcpTc = 'Typechecked
|
216 | 217 | |
217 | 218 | mkEValArg :: SrcSpan -> LHsExpr GhcRn -> HsExprArg 'TcpRn
|
218 | -mkEValArg ctxt e = EValArg { ea_arg = e, ea_ctxt = ctxt
|
|
219 | +mkEValArg src_loc e = EValArg { ea_arg = e, ea_loc_span = src_loc
|
|
219 | 220 | , ea_arg_ty = noExtField }
|
220 | 221 | |
221 | 222 | mkETypeArg :: SrcSpan -> LHsWcType GhcRn -> HsExprArg 'TcpRn
|
222 | -mkETypeArg ctxt hs_ty =
|
|
223 | - ETypeArg { ea_ctxt = ctxt
|
|
223 | +mkETypeArg src_loc hs_ty =
|
|
224 | + ETypeArg { ea_loc_span = src_loc
|
|
224 | 225 | , ea_hs_ty = hs_ty
|
225 | 226 | , ea_ty_arg = noExtField }
|
226 | 227 | |
... | ... | @@ -291,9 +292,9 @@ rebuildHsApps :: (HsExpr GhcTc, SrcSpan) |
291 | 292 | rebuildHsApps (fun, _) [] = fun
|
292 | 293 | rebuildHsApps (fun, sloc) (arg : args)
|
293 | 294 | = case arg of
|
294 | - EValArg { ea_arg = arg, ea_ctxt = sloc' }
|
|
295 | + EValArg { ea_arg = arg, ea_loc_span = sloc' }
|
|
295 | 296 | -> rebuildHsApps (HsApp noExtField lfun arg, sloc') args
|
296 | - ETypeArg { ea_hs_ty = hs_ty, ea_ty_arg = ty, ea_ctxt = sloc' }
|
|
297 | + ETypeArg { ea_hs_ty = hs_ty, ea_ty_arg = ty, ea_loc_span = sloc' }
|
|
297 | 298 | -> rebuildHsApps (HsAppType ty lfun hs_ty, sloc') args
|
298 | 299 | EPrag sloc' p
|
299 | 300 | -> rebuildHsApps (HsPragE noExtField p lfun, sloc') args
|
... | ... | @@ -330,7 +331,7 @@ instance OutputableBndrId (XPass p) => Outputable (HsExprArg p) where |
330 | 331 | ppr (EPrag _ p) = text "EPrag" <+> ppr p
|
331 | 332 | ppr (ETypeArg { ea_hs_ty = hs_ty }) = char '@' <> ppr hs_ty
|
332 | 333 | ppr (EWrap wrap) = ppr wrap
|
333 | - ppr (EValArg { ea_arg = arg, ea_ctxt = sloc })
|
|
334 | + ppr (EValArg { ea_arg = arg, ea_loc_span = sloc })
|
|
334 | 335 | = text "EValArg" <> braces (ppr sloc) <+> ppr arg
|
335 | 336 | ppr (EValArgQL { eaql_tc_fun = fun, eaql_args = args, eaql_res_rho = ty})
|
336 | 337 | = hang (text "EValArgQL" <+> ppr fun)
|
... | ... | @@ -91,29 +91,54 @@ data TcLclEnv -- Changes as we move inside an expression |
91 | 91 | tcl_errs :: TcRef (Messages TcRnMessage) -- Place to accumulate diagnostics
|
92 | 92 | }
|
93 | 93 | |
94 | +{-
|
|
95 | +Note [Error Context Stack]
|
|
96 | +~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
97 | +This data structure keeps track of two things:
|
|
98 | +1. Are we type checking a compiler generated/non-user written code.
|
|
99 | +2. The trail of the error messages that have been added in route to the current expression
|
|
100 | + |
|
101 | +* When the `ErrCtxtStack` is a `UserCodeCtxt`,
|
|
102 | + - the current expression being typechecked is user written
|
|
103 | +* When the `ErrorCtxtStack` is a `GeneratedCodeCtxt`
|
|
104 | + - the current expression being typechecked is compiler generated;
|
|
105 | + - the original, possibly user written, source code thing is stored in `src_code_origin` field.
|
|
106 | + - the `src_code_origin` is what will be blamed in the error message
|
|
107 | + |
|
108 | +-}
|
|
109 | + |
|
94 | 110 | |
111 | +-- See Note [Error Context Stack]
|
|
95 | 112 | data ErrCtxtStack
|
96 | - = UserCodeCtxt {err_ctxt :: [ErrCtxt]}
|
|
97 | - | GeneratedCodeCtxt { src_code_origin :: SrcCodeOrigin
|
|
98 | - , err_ctxt :: [ErrCtxt] }
|
|
113 | + = UserCodeCtxt { lcl_err_ctxt :: [ErrCtxt] } -- ^ Trail of error messages
|
|
114 | + | GeneratedCodeCtxt { src_code_origin :: SrcCodeOrigin -- ^ Original, user written code
|
|
115 | + , lcl_err_ctxt :: [ErrCtxt] } -- ^ Trail of error messages
|
|
99 | 116 | |
117 | +-- | Are we in a generated context?
|
|
100 | 118 | isGeneratedCodeCtxt :: ErrCtxtStack -> Bool
|
101 | 119 | isGeneratedCodeCtxt UserCodeCtxt{} = False
|
102 | 120 | isGeneratedCodeCtxt _ = True
|
103 | 121 | |
122 | +-- | Get the original source code
|
|
104 | 123 | get_src_code_origin :: ErrCtxtStack -> Maybe SrcCodeOrigin
|
105 | 124 | get_src_code_origin (UserCodeCtxt{}) = Nothing
|
125 | + -- we are in user code, so blame the expression in hand
|
|
106 | 126 | get_src_code_origin es = Just $ src_code_origin es
|
127 | + -- we are in generated code, so extract the original expression
|
|
107 | 128 | |
129 | +-- | Modify the error context stack
|
|
130 | +-- N.B. If we are in a generated context, any updates to the context stack are ignored.
|
|
131 | +-- We want to blame the errors that appear in a generated expression
|
|
132 | +-- to the original, user written code
|
|
108 | 133 | modify_err_ctxt_stack :: ([ErrCtxt] -> [ErrCtxt]) -> ErrCtxtStack -> ErrCtxtStack
|
109 | 134 | modify_err_ctxt_stack f (UserCodeCtxt e) = UserCodeCtxt (f e)
|
110 | -modify_err_ctxt_stack _ c = c -- any updates on the err context in generated context should be ignored
|
|
135 | +modify_err_ctxt_stack _ c = c -- any updates on the err context in a generated context should be ignored
|
|
111 | 136 | |
112 | 137 | |
113 | 138 | data TcLclCtxt
|
114 | 139 | = TcLclCtxt {
|
115 | 140 | tcl_loc :: RealSrcSpan, -- Source span
|
116 | - tcl_ctxt :: ErrCtxtStack,
|
|
141 | + tcl_ctxt :: ErrCtxtStack, -- See Note [Error Context Stack]
|
|
117 | 142 | tcl_tclvl :: TcLevel,
|
118 | 143 | tcl_bndrs :: TcBinderStack, -- Used for reporting relevant bindings,
|
119 | 144 | -- and for tidying type
|
... | ... | @@ -178,7 +203,7 @@ getLclEnvLoc :: TcLclEnv -> RealSrcSpan |
178 | 203 | getLclEnvLoc = tcl_loc . tcl_lcl_ctxt
|
179 | 204 | |
180 | 205 | getLclEnvErrCtxt :: TcLclEnv -> [ErrCtxt]
|
181 | -getLclEnvErrCtxt = err_ctxt . tcl_ctxt . tcl_lcl_ctxt
|
|
206 | +getLclEnvErrCtxt = lcl_err_ctxt . tcl_ctxt . tcl_lcl_ctxt
|
|
182 | 207 | |
183 | 208 | setLclEnvErrCtxt :: [ErrCtxt] -> TcLclEnv -> TcLclEnv
|
184 | 209 | setLclEnvErrCtxt ctxt = modifyLclCtxt (\env -> env { tcl_ctxt = modify_err_ctxt_stack (\ _ -> ctxt) (tcl_ctxt env) })
|
... | ... | @@ -193,7 +218,7 @@ setLclEnvSrcCodeOrigin :: SrcCodeOrigin -> TcLclEnv -> TcLclEnv |
193 | 218 | setLclEnvSrcCodeOrigin o = modifyLclCtxt (setLclCtxtSrcCodeOrigin o)
|
194 | 219 | |
195 | 220 | setLclCtxtSrcCodeOrigin :: SrcCodeOrigin -> TcLclCtxt -> TcLclCtxt
|
196 | -setLclCtxtSrcCodeOrigin o ctxt = ctxt { tcl_ctxt = GeneratedCodeCtxt o (err_ctxt $ tcl_ctxt ctxt) }
|
|
221 | +setLclCtxtSrcCodeOrigin o ctxt = ctxt { tcl_ctxt = GeneratedCodeCtxt o (lcl_err_ctxt $ tcl_ctxt ctxt) }
|
|
197 | 222 | |
198 | 223 | lclCtxtInGeneratedCode :: TcLclCtxt -> Bool
|
199 | 224 | lclCtxtInGeneratedCode = isGeneratedCodeCtxt . tcl_ctxt
|
... | ... | @@ -974,9 +974,9 @@ inGeneratedCode = lclEnvInGeneratedCode <$> getLclEnv |
974 | 974 | |
975 | 975 | setSrcSpan :: SrcSpan -> TcRn a -> TcRn a
|
976 | 976 | -- See Note [Error contexts in generated code]
|
977 | --- for the tcl_in_gen_code manipulation
|
|
978 | 977 | setSrcSpan (RealSrcSpan loc _) thing_inside
|
979 | - = updLclCtxt (\env -> env { tcl_loc = loc, tcl_ctxt = UserCodeCtxt (err_ctxt $ tcl_ctxt env)})
|
|
978 | + = updLclCtxt (\env -> env { tcl_loc = loc
|
|
979 | + , tcl_ctxt = UserCodeCtxt (lcl_err_ctxt $ tcl_ctxt env)})
|
|
980 | 980 | thing_inside
|
981 | 981 | |
982 | 982 | setSrcSpan (UnhelpfulSpan _) thing_inside
|
... | ... | @@ -988,6 +988,7 @@ getSrcCodeOrigin = getLclEnvSrcCodeOrigin <$> getLclEnv |
988 | 988 | -- | Mark the inner computation as being done inside generated code.
|
989 | 989 | --
|
990 | 990 | -- See Note [Error contexts in generated code]
|
991 | +-- See Note [Error Context Stack]
|
|
991 | 992 | setInGeneratedCode :: SrcCodeOrigin -> TcRn a -> TcRn a
|
992 | 993 | setInGeneratedCode sco thing_inside =
|
993 | 994 | updLclCtxt (setLclCtxtSrcCodeOrigin sco) thing_inside
|
... | ... | @@ -1210,17 +1211,17 @@ problem. |
1210 | 1211 | |
1211 | 1212 | Note [Error contexts in generated code]
|
1212 | 1213 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
1213 | -* setSrcSpan sets tcl_in_gen_code to True if the SrcSpan is GeneratedSrcSpan,
|
|
1214 | - and back to False when we get a useful SrcSpan
|
|
1214 | +* If the `SrcSpan` is a `RealSrcSpan`, `setSrcSpan` updates the `tcl_loc`,
|
|
1215 | + and makes the `ErrCtxStack` a `UserCodeCtxt`
|
|
1216 | +* it is a no-op otherwise
|
|
1215 | 1217 | |
1216 | -* When tcl_in_gen_code is True, addErrCtxt becomes a no-op.
|
|
1218 | +So, it's better to do a `setSrcSpan` /before/ `addErrCtxt`.
|
|
1217 | 1219 | |
1218 | -So typically it's better to do setSrcSpan /before/ addErrCtxt.
|
|
1219 | - |
|
1220 | -See Note [Rebindable syntax and XXExprGhcRn] in GHC.Hs.Expr for
|
|
1221 | -more discussion of this fancy footwork, as well as
|
|
1222 | -Note [Generated code and pattern-match checking] in GHC.Types.Basic for the
|
|
1223 | -relation with pattern-match checks.
|
|
1220 | +- See Note [Rebindable syntax and XXExprGhcRn] in `GHC.Hs.Expr` for
|
|
1221 | +more discussion of this fancy footwork
|
|
1222 | +- See Note [Generated code and pattern-match checking] in `GHC.Types.Basic` for the
|
|
1223 | +relation with pattern-match checks
|
|
1224 | +- See Note [Error Context Stack] in `GHC.Tc.Types.LclEnv` for info about `ErrCtxtStack`
|
|
1224 | 1225 | -}
|
1225 | 1226 | |
1226 | 1227 | getErrCtxt :: TcM [ErrCtxt]
|