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]
|