Simon Peyton Jones pushed to branch wip/ani/better-expansion at Glasgow Haskell Compiler / GHC
Commits:
-
10f21fa6
by Simon Peyton Jones at 2026-03-31T21:50:22+01:00
6 changed files:
- compiler/GHC/Tc/Gen/App.hs
- + compiler/GHC/Tc/Gen/Expand.hs
- compiler/GHC/Tc/Gen/Expr.hs
- compiler/GHC/Tc/Gen/Expr.hs-boot
- compiler/GHC/Tc/Gen/Head.hs
- compiler/ghc.cabal.in
Changes:
| ... | ... | @@ -656,8 +656,8 @@ tcInstFun :: QLFlag |
| 656 | 656 | -> TcSigmaType -> [HsExprArg 'TcpRn]
|
| 657 | 657 | -> TcM ( [HsExprArg 'TcpInst]
|
| 658 | 658 | , TcSigmaType ) -- Does not instantiate trailing invisible foralls
|
| 659 | --- This crucial function implements the |-inst judgement in Fig 4, plus the
|
|
| 660 | --- modification in Fig 5, of the QL paper:
|
|
| 659 | +-- This crucial function implements the |-inst judgement in Fig 4,
|
|
| 660 | +-- plus the modification in Fig 5, of the QL paper:
|
|
| 661 | 661 | -- "A quick look at impredicativity" (ICFP'20).
|
| 662 | 662 | tcInstFun do_ql inst_final rn_head@(_, fun_lspan) tc_fun fun_sigma rn_args
|
| 663 | 663 | = do { traceTc "tcInstFun" (vcat [ text "tc_fun" <+> ppr tc_fun
|
| ... | ... | @@ -665,7 +665,8 @@ tcInstFun do_ql inst_final rn_head@(_, fun_lspan) tc_fun fun_sigma rn_args |
| 665 | 665 | , text "fun_sigma" <+> ppr fun_sigma
|
| 666 | 666 | , text "args:" <+> ppr rn_args
|
| 667 | 667 | , text "do_ql" <+> ppr do_ql])
|
| 668 | - ; res@(_, fun_ty) <- go 1 [] fun_sigma rn_args
|
|
| 668 | + ; fun_origin <- mk_origin rn_head
|
|
| 669 | + ; res@(_, fun_ty) <- go fun_origin 1 [] fun_sigma rn_args
|
|
| 669 | 670 | ; traceTc "tcInstFun:ret" (ppr fun_ty)
|
| 670 | 671 | ; return res
|
| 671 | 672 | }
|
| ... | ... | @@ -683,7 +684,7 @@ tcInstFun do_ql inst_final rn_head@(_, fun_lspan) tc_fun fun_sigma rn_args |
| 683 | 684 | = return $ exprCtOrigin rn_fun
|
| 684 | 685 | |
| 685 | 686 | | otherwise -- If the location is generated, the best we can do is to
|
| 686 | - -- approximate by looking on top of the error message stack
|
|
| 687 | + -- approximate by looking on top of the error message stack
|
|
| 687 | 688 | = do { err_ctxt_stack <- getErrCtxt
|
| 688 | 689 | ; let hs_ctxt = case err_ctxt_stack of
|
| 689 | 690 | (c:_) -> c
|
| ... | ... | @@ -692,8 +693,6 @@ tcInstFun do_ql inst_final rn_head@(_, fun_lspan) tc_fun fun_sigma rn_args |
| 692 | 693 | ; return $ hsCtxtCtOrigin hs_ctxt
|
| 693 | 694 | }
|
| 694 | 695 | |
| 695 | - |
|
| 696 | - |
|
| 697 | 696 | -- These are the type variables which must be instantiated to concrete
|
| 698 | 697 | -- types. See Note [Representation-polymorphic Ids with no binding]
|
| 699 | 698 | -- in GHC.Tc.Utils.Concrete
|
| ... | ... | @@ -725,34 +724,35 @@ tcInstFun do_ql inst_final rn_head@(_, fun_lspan) tc_fun fun_sigma rn_args |
| 725 | 724 | inst_fun _ = isInferredForAllTyFlag
|
| 726 | 725 | |
| 727 | 726 | -----------
|
| 728 | - go, go1 :: Int -- Value-argument position of next arg
|
|
| 727 | + go, go1 :: CtOrigin -- Of the function
|
|
| 728 | + -> Int -- Value-argument position of next arg
|
|
| 729 | 729 | -> [HsExprArg 'TcpInst] -- Accumulator, reversed
|
| 730 | 730 | -> TcSigmaType -> [HsExprArg 'TcpRn]
|
| 731 | 731 | -> TcM ([HsExprArg 'TcpInst], TcSigmaType)
|
| 732 | 732 | |
| 733 | 733 | -- go: If fun_ty=kappa, look it up in Theta
|
| 734 | - go pos acc fun_ty args
|
|
| 734 | + go fun_orig pos acc fun_ty args
|
|
| 735 | 735 | | Just kappa <- getTyVar_maybe fun_ty
|
| 736 | 736 | , isQLInstTyVar kappa
|
| 737 | 737 | = do { cts <- readMetaTyVar kappa
|
| 738 | 738 | ; case cts of
|
| 739 | - Indirect fun_ty' -> go pos acc fun_ty' args
|
|
| 740 | - Flexi -> go1 pos acc fun_ty args }
|
|
| 739 | + Indirect fun_ty' -> go fun_orig pos acc fun_ty' args
|
|
| 740 | + Flexi -> go1 fun_orig pos acc fun_ty args }
|
|
| 741 | 741 | | otherwise
|
| 742 | - = go1 pos acc fun_ty args
|
|
| 742 | + = go1 fun_orig pos acc fun_ty args
|
|
| 743 | 743 | |
| 744 | 744 | -- go1: fun_ty is not filled-in instantiation variable
|
| 745 | 745 | -- ('go' dealt with that case)
|
| 746 | 746 | |
| 747 | 747 | -- Handle out-of-scope functions gracefully
|
| 748 | - go1 pos acc fun_ty (arg : rest_args)
|
|
| 748 | + go1 fun_orig pos acc fun_ty (arg : rest_args)
|
|
| 749 | 749 | | fun_is_out_of_scope, looks_like_type_arg arg -- See Note [VTA for out-of-scope functions]
|
| 750 | - = go pos acc fun_ty rest_args
|
|
| 750 | + = go fun_orig pos acc fun_ty rest_args
|
|
| 751 | 751 | |
| 752 | 752 | -- Rule IALL from Fig 4 of the QL paper; applies even if args = []
|
| 753 | 753 | -- Instantiate invisible foralls and dictionaries.
|
| 754 | 754 | -- c.f. GHC.Tc.Utils.Instantiate.topInstantiate
|
| 755 | - go1 pos acc fun_ty args
|
|
| 755 | + go1 fun_orig pos acc fun_ty args
|
|
| 756 | 756 | | (tvs, body1) <- tcSplitSomeForAllTyVars (inst_fun args) fun_ty
|
| 757 | 757 | , (theta, body2) <- if inst_fun args Inferred
|
| 758 | 758 | then tcSplitPhiTy body1
|
| ... | ... | @@ -763,8 +763,7 @@ tcInstFun do_ql inst_final rn_head@(_, fun_lspan) tc_fun fun_sigma rn_args |
| 763 | 763 | , let no_tvs = null tvs
|
| 764 | 764 | no_theta = null theta
|
| 765 | 765 | , not (no_tvs && no_theta)
|
| 766 | - = do { fun_orig <- mk_origin rn_head
|
|
| 767 | - ; (wrap, fun_rho) <-
|
|
| 766 | + = do { (wrap, fun_rho) <-
|
|
| 768 | 767 | -- addHeadCtxt: important for the class constraints
|
| 769 | 768 | -- that may be emitted from instantiating fun_sigma
|
| 770 | 769 | setSrcSpan fun_lspan $
|
| ... | ... | @@ -782,12 +781,12 @@ tcInstFun do_ql inst_final rn_head@(_, fun_lspan) tc_fun fun_sigma rn_args |
| 782 | 781 | -- argument of (#,#) to @LiftedRep, but want to rule out the
|
| 783 | 782 | -- second instantiation @r.
|
| 784 | 783 | |
| 785 | - ; go pos (addArgWrap wrap acc) fun_rho args }
|
|
| 784 | + ; go fun_orig pos (addArgWrap wrap acc) fun_rho args }
|
|
| 786 | 785 | -- Going around again means we deal easily with
|
| 787 | 786 | -- nested forall a. Eq a => forall b. Show b => blah
|
| 788 | 787 | |
| 789 | 788 | -- Rule IRESULT from Fig 4 of the QL paper; no more arguments
|
| 790 | - go1 _pos acc fun_ty []
|
|
| 789 | + go1 _fun_orig _pos acc fun_ty []
|
|
| 791 | 790 | | XExpr (ConLikeTc (RealDataCon dc)) <- tc_fun
|
| 792 | 791 | , isNewDataCon dc
|
| 793 | 792 | , [Scaled _ orig_arg_ty] <- dataConOrigArgTys dc
|
| ... | ... | @@ -807,30 +806,30 @@ tcInstFun do_ql inst_final rn_head@(_, fun_lspan) tc_fun fun_sigma rn_args |
| 807 | 806 | = return (reverse acc, fun_ty)
|
| 808 | 807 | |
| 809 | 808 | -- Rule ITVDQ from the GHC Proposal #281
|
| 810 | - go1 pos acc fun_ty ((EValArg { ea_arg = arg }) : rest_args)
|
|
| 809 | + go1 fun_orig pos acc fun_ty ((EValArg { ea_arg = arg }) : rest_args)
|
|
| 811 | 810 | | Just (tvb, body) <- tcSplitForAllTyVarBinder_maybe fun_ty
|
| 812 | 811 | = assertPpr (binderFlag tvb == Required) (ppr fun_ty $$ ppr arg) $
|
| 813 | 812 | -- Any invisible binders have been instantiated by IALL above,
|
| 814 | 813 | -- so this forall must be visible (i.e. Required)
|
| 815 | 814 | do { (ty_arg, inst_body) <- tcVDQ fun_conc_tvs (tvb, body) arg
|
| 816 | 815 | ; let wrap = mkWpTyApps [ty_arg]
|
| 817 | - ; go (pos+1) (addArgWrap wrap acc) inst_body rest_args }
|
|
| 816 | + ; go fun_orig (pos+1) (addArgWrap wrap acc) inst_body rest_args }
|
|
| 818 | 817 | |
| 819 | - go1 pos acc fun_ty (EWrap w : args)
|
|
| 820 | - = go1 pos (EWrap w : acc) fun_ty args
|
|
| 818 | + go1 fun_orig pos acc fun_ty (EWrap w : args)
|
|
| 819 | + = go1 fun_orig pos (EWrap w : acc) fun_ty args
|
|
| 821 | 820 | |
| 822 | - go1 pos acc fun_ty (EPrag sp prag : args)
|
|
| 823 | - = go1 pos (EPrag sp prag : acc) fun_ty args
|
|
| 821 | + go1 fun_orig pos acc fun_ty (EPrag sp prag : args)
|
|
| 822 | + = go1 fun_orig pos (EPrag sp prag : acc) fun_ty args
|
|
| 824 | 823 | |
| 825 | 824 | -- Rule ITYARG from Fig 4 of the QL paper
|
| 826 | - go1 pos acc fun_ty ( ETypeArg { ea_loc_span = ctxt, ea_hs_ty = hs_ty }
|
|
| 827 | - : rest_args )
|
|
| 825 | + go1 fun_orig pos acc fun_ty ( ETypeArg { ea_loc_span = ctxt, ea_hs_ty = hs_ty }
|
|
| 826 | + : rest_args )
|
|
| 828 | 827 | = do { (ty_arg, inst_ty) <- tcVTA fun_conc_tvs fun_ty hs_ty
|
| 829 | 828 | ; let arg' = ETypeArg { ea_loc_span = ctxt, ea_hs_ty = hs_ty, ea_ty_arg = ty_arg }
|
| 830 | - ; go pos (arg' : acc) inst_ty rest_args }
|
|
| 829 | + ; go fun_orig pos (arg' : acc) inst_ty rest_args }
|
|
| 831 | 830 | |
| 832 | 831 | -- Rule IVAR from Fig 4 of the QL paper:
|
| 833 | - go1 pos acc fun_ty args@(EValArg {} : _)
|
|
| 832 | + go1 fun_orig pos acc fun_ty args@(EValArg {} : _)
|
|
| 834 | 833 | | Just kappa <- getTyVar_maybe fun_ty
|
| 835 | 834 | , isQLInstTyVar kappa
|
| 836 | 835 | = -- Function type was of form f :: forall a b. t1 -> t2 -> b
|
| ... | ... | @@ -846,7 +845,7 @@ tcInstFun do_ql inst_final rn_head@(_, fun_lspan) tc_fun fun_sigma rn_args |
| 846 | 845 | -- - We must be sure to actually update the variable right now,
|
| 847 | 846 | -- not defer in any way, because this is a QL instantiation variable.
|
| 848 | 847 | -- It's easier just to do the job directly here.
|
| 849 | - do { arg_tys <- zipWithM new_arg_ty (leadingValArgs args) [pos..]
|
|
| 848 | + do { arg_tys <- zipWithM (new_arg_ty fun_orig) (leadingValArgs args) [pos..]
|
|
| 850 | 849 | ; res_ty <- newOpenFlexiTyVarTyQL do_ql TauTv
|
| 851 | 850 | ; let fun_ty' = mkScaledFunTys arg_tys res_ty
|
| 852 | 851 | |
| ... | ... | @@ -862,13 +861,12 @@ tcInstFun do_ql inst_final rn_head@(_, fun_lspan) tc_fun fun_sigma rn_args |
| 862 | 861 | -- Then fun_ty :: kk, fun_ty' :: Type, kind_co :: Type ~ kk
|
| 863 | 862 | -- co_wrap :: (fun_ty' |> kind_co) ~ fun_ty'
|
| 864 | 863 | |
| 865 | - ; go pos acc' fun_ty' args }
|
|
| 864 | + ; go fun_orig pos acc' fun_ty' args }
|
|
| 866 | 865 | |
| 867 | 866 | -- Rule IARG from Fig 4 of the QL paper:
|
| 868 | - go1 pos acc fun_ty
|
|
| 867 | + go1 fun_orig pos acc fun_ty
|
|
| 869 | 868 | (EValArg { ea_arg = arg, ea_loc_span = ctxt } : rest_args)
|
| 870 | - = do { fun_orig <- mk_origin rn_head
|
|
| 871 | - ; let herald = mk_herald fun_orig tc_fun (unLoc arg)
|
|
| 869 | + = do { let herald = mk_herald fun_orig tc_fun (unLoc arg)
|
|
| 872 | 870 | ; (fun_co, arg_ty, res_ty) <-
|
| 873 | 871 | -- NB: matchActualFunTy does the rep-poly check.
|
| 874 | 872 | -- For example, suppose we have f :: forall r (a::TYPE r). a -> Int
|
| ... | ... | @@ -882,13 +880,12 @@ tcInstFun do_ql inst_final rn_head@(_, fun_lspan) tc_fun fun_sigma rn_args |
| 882 | 880 | (n_val_args, fun_sigma) fun_ty
|
| 883 | 881 | ; arg' <- quickLookArg do_ql pos ctxt rn_head arg arg_ty
|
| 884 | 882 | ; let acc' = arg' : addArgWrap (mkWpCastN fun_co) acc
|
| 885 | - ; go (pos+1) acc' res_ty rest_args }
|
|
| 883 | + ; go fun_orig (pos+1) acc' res_ty rest_args }
|
|
| 886 | 884 | |
| 887 | - new_arg_ty :: LHsExpr GhcRn -> Int -> TcM (Scaled TcType)
|
|
| 885 | + new_arg_ty :: CtOrigin -> LHsExpr GhcRn -> Int -> TcM (Scaled TcType)
|
|
| 888 | 886 | -- Make a fresh nus for each argument in rule IVAR
|
| 889 | - new_arg_ty (L _ arg) i
|
|
| 890 | - = do { fun_orig <- mk_origin rn_head
|
|
| 891 | - ; arg_nu <- newArgTyVarTyQL do_ql $
|
|
| 887 | + new_arg_ty fun_orig (L _ arg) i
|
|
| 888 | + = do { arg_nu <- newArgTyVarTyQL do_ql $
|
|
| 892 | 889 | FRRExpectedFunTy (mk_herald fun_orig tc_fun arg) i
|
| 893 | 890 | -- Following matchActualFunTy, we create nu_i :: TYPE kappa_i[conc],
|
| 894 | 891 | -- thereby ensuring that the arguments have concrete runtime representations
|
| 1 | +{-# LANGUAGE TypeFamilies #-}
|
|
| 2 | + |
|
| 3 | +{-
|
|
| 4 | +(c) The University of Glasgow 2006
|
|
| 5 | +(c) The GRASP/AQUA Project, Glasgow University, 1992-1998
|
|
| 6 | +-}
|
|
| 7 | + |
|
| 8 | +module GHC.Tc.Gen.Expand( tcExpand ) where
|
|
| 9 | + |
|
| 10 | +import GHC.Prelude
|
|
| 11 | + |
|
| 12 | +import {-# SOURCE #-} GHC.Tc.Gen.Splice( getUntypedSpliceBody )
|
|
| 13 | + |
|
| 14 | +import GHC.Hs
|
|
| 15 | + |
|
| 16 | +import GHC.Tc.Utils.Monad
|
|
| 17 | +import GHC.Tc.Types.ErrCtxt
|
|
| 18 | + |
|
| 19 | +import GHC.Rename.Utils
|
|
| 20 | + |
|
| 21 | +import GHC.Types.SrcLoc
|
|
| 22 | + |
|
| 23 | + |
|
| 24 | +{- Note [Typechecking by expansion: overview]
|
|
| 25 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 26 | +For many constructs, rather than typechecking the user-written code
|
|
| 27 | +directly, it's much easier to
|
|
| 28 | + * Expand (or desugar) the code to something simpler
|
|
| 29 | + * Typecheck that simpler expression
|
|
| 30 | + |
|
| 31 | +Example: Typechecking the do expression. The typechecker looks (somewhat) like this:
|
|
| 32 | + |
|
| 33 | + tcExpr e@(HsDo _ stmts) rho = do { hse <- expandDoStmts stmts
|
|
| 34 | + ; tcHsExpansion hse rho }
|
|
| 35 | + |
|
| 36 | +The `expandDoStmts` replaces the HsDo { x <- e1; return x }
|
|
| 37 | +with something like
|
|
| 38 | + HSE { hse_ctxt = ExprCtxt e
|
|
| 39 | + , hse_exp = e1 >>= \ x -> x }
|
|
| 40 | +and we then typecheck the expression `e1 >>= \ x -> x`
|
|
| 41 | + |
|
| 42 | +See also Note [Handling overloaded and rebindable constructs]
|
|
| 43 | + and Note [Doing XXExprGhcRn in the Renamer vs Typechecker]
|
|
| 44 | + |
|
| 45 | +The Big Question is how to ensure that error messages mention
|
|
| 46 | +only user-written source code, and never talk about the expanded code.
|
|
| 47 | +The rest of this Note explains how that is done.
|
|
| 48 | + |
|
| 49 | +* The expansion process typically takes a user written thing
|
|
| 50 | + L lspan ue
|
|
| 51 | + and returns
|
|
| 52 | + L lspan (XExpr (ExpandedThingRn (HSE { hse_ctxt = ue
|
|
| 53 | + , hse_exp = ee } ))
|
|
| 54 | + where `ee` is the expansion of the user written thing `ue`
|
|
| 55 | + |
|
| 56 | +* The type checker context has 3 key fields that describe the context:
|
|
| 57 | + TcLclCtxt { tcl_loc :: RealSrcSpan
|
|
| 58 | + , tcl_in_gen_code :: Bool
|
|
| 59 | + , tcl_err_ctxt :: ErrCtxtStack
|
|
| 60 | + , ... }
|
|
| 61 | + Note `tcl_loc` always points to a real place in the source code,
|
|
| 62 | + hence `RealSrcSpan`.
|
|
| 63 | + |
|
| 64 | + The `tcl_err_ctxt` is a stack of contexts, each saying something
|
|
| 65 | + like "In the expression: x+y" or "In second argument of `$` namely 'r { x=2 }'"
|
|
| 66 | + |
|
| 67 | + The `tcl_in_gen_code` is a boolean that keeps track of whether
|
|
| 68 | + the current expression being typechecked is compiler generated
|
|
| 69 | + or user generated.
|
|
| 70 | + |
|
| 71 | + INVARIANT: `tcl_loc` and `tcl_in_gen_code` are modified only in `setSrcSpan`.
|
|
| 72 | + |
|
| 73 | +* Now, when
|
|
| 74 | + tcMonoLExpr :: LHsExpr GhcRn -> ExpRhoType -> TcM (HsExpr GhcTc)
|
|
| 75 | + gets a located expression, it does 3 things:
|
|
| 76 | + (a) Calls `setSrcSpanA` to set the ambient source-code location
|
|
| 77 | + (b) Calls `addExprCtxt` to push a suitable `HsCtxt` on top of the `tcl_err_ctxt`.
|
|
| 78 | + (c) Calls `tcExpr` to typecheck the expression.
|
|
| 79 | + |
|
| 80 | +* In these calls, if the `span` is generated (see `isGeneratedSrcSpan`), then
|
|
| 81 | + - `setSrcSpanA` sets `tcl_in_gen_code` to `True`, and leaves `tcl_loc` unchanged
|
|
| 82 | + - `addExprCtxt` is a no-op if `tcl_in_gen_code` is True
|
|
| 83 | + The result is that `tcl_loc` has the span from the innermost /user/ tree node;
|
|
| 84 | + and the ErrCtxtStack in `tcl_err_ctxt` only has contexts arisign from user code.
|
|
| 85 | + |
|
| 86 | +* Note that inside an expansion we have sub-expressions from the original program.
|
|
| 87 | + As soon as we enter one of those, identified by a /user/ span, `setSrcSpanA` will
|
|
| 88 | + sets the `tcl_loc` to reflect that span, and switch off `tcl_in_gen_code`. Nice!
|
|
| 89 | +-}
|
|
| 90 | + |
|
| 91 | +---------------
|
|
| 92 | +tcExpand :: HsExpr GhcRn -> TcM (Maybe (HsExpansion GhcRn))
|
|
| 93 | +tcExpand e@(OpApp _ arg1 op arg2)
|
|
| 94 | + = return $ Just $
|
|
| 95 | + HSE { hse_ctxt = ExprCtxt e
|
|
| 96 | + , hse_exp = foldl ap op [arg1,arg2] }
|
|
| 97 | + where
|
|
| 98 | + ap f a = wrapGenSpan (HsApp noExtField f a)
|
|
| 99 | + |
|
| 100 | +tcExpand (XExpr (ExpandedThingRn hse))
|
|
| 101 | + = return (Just hse)
|
|
| 102 | + |
|
| 103 | +tcExpand e@(HsUntypedSplice splice_res _)
|
|
| 104 | +-- See Note [Looking through Template Haskell splices in splitHsApps]
|
|
| 105 | + = do { fun <- getUntypedSpliceBody splice_res
|
|
| 106 | + ; return $ Just $
|
|
| 107 | + HSE { hse_ctxt = ExprCtxt e -- ToDo: right?
|
|
| 108 | + , hse_exp = L noSrcSpanA fun } } -- Span?
|
|
| 109 | +{-
|
|
| 110 | + where
|
|
| 111 | + lspan' :: SrcSpan
|
|
| 112 | + lspan' = case splice of
|
|
| 113 | + HsUntypedSpliceExpr _ (L l _) -> locA l -- l :: SrcAnn AnnListItem
|
|
| 114 | + HsQuasiQuote _ _ (L l _) -> locA l -- l :: SrcAnn NoEpAnns
|
|
| 115 | + (XUntypedSplice (HsImplicitLiftSplice _ _ _ (L l _))) -> locA l
|
|
| 116 | +-}
|
|
| 117 | + |
|
| 118 | +tcExpand _ = return Nothing |
| ... | ... | @@ -19,7 +19,6 @@ module GHC.Tc.Gen.Expr |
| 19 | 19 | tcInferRhoFRR, tcInferRhoFRRNC,
|
| 20 | 20 | tcPolyLExpr, tcPolyLExprSig, tcPolyLExprNC,
|
| 21 | 21 | tcPolyExpr, tcExpr,
|
| 22 | - tcExpand,
|
|
| 23 | 22 | tcSyntaxOp, tcSyntaxOpGen, SyntaxOpType(..), synKnownType,
|
| 24 | 23 | tcCheckId,
|
| 25 | 24 | ) where
|
| ... | ... | @@ -31,10 +30,10 @@ import {-# SOURCE #-} GHC.Tc.Gen.Splice |
| 31 | 30 | |
| 32 | 31 | import GHC.Hs
|
| 33 | 32 | import GHC.Hs.Syn.Type
|
| 34 | - |
|
| 35 | 33 | import GHC.Rename.Utils
|
| 36 | 34 | import GHC.Rename.Env ( addUsedGRE, getUpdFieldLbls )
|
| 37 | 35 | |
| 36 | +import GHC.Tc.Gen.Expand( tcExpand )
|
|
| 38 | 37 | import GHC.Tc.Gen.App
|
| 39 | 38 | import GHC.Tc.Gen.Head
|
| 40 | 39 | import GHC.Tc.Gen.Do
|
| ... | ... | @@ -770,73 +769,6 @@ tcExpr e res_ty |
| 770 | 769 | ************************************************************************
|
| 771 | 770 | -}
|
| 772 | 771 | |
| 773 | -{- Note [Typechecking by expansion: overview]
|
|
| 774 | -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 775 | -For many constructs, rather than typechecking the user-written code
|
|
| 776 | -directly, it's much easier to
|
|
| 777 | - * Expand (or desugar) the code to something simpler
|
|
| 778 | - * Typecheck that simpler expression
|
|
| 779 | - |
|
| 780 | -Example: Typechecking the do expression. The typechecker looks (somewhat) like this:
|
|
| 781 | - |
|
| 782 | - tcExpr e@(HsDo _ stmts) rho = do { hse <- expandDoStmts stmts
|
|
| 783 | - ; tcHsExpansion hse rho }
|
|
| 784 | - |
|
| 785 | -The `expandDoStmts` replaces the HsDo { x <- e1; return x }
|
|
| 786 | -with something like
|
|
| 787 | - HSE { hse_ctxt = ExprCtxt e
|
|
| 788 | - , hse_exp = e1 >>= \ x -> x }
|
|
| 789 | -and we then typecheck the expression `e1 >>= \ x -> x`
|
|
| 790 | - |
|
| 791 | -See also Note [Handling overloaded and rebindable constructs]
|
|
| 792 | - and Note [Doing XXExprGhcRn in the Renamer vs Typechecker]
|
|
| 793 | - |
|
| 794 | -The Big Question is how to ensure that error messages mention
|
|
| 795 | -only user-written source code, and never talk about the expanded code.
|
|
| 796 | -The rest of this Note explains how that is done.
|
|
| 797 | - |
|
| 798 | -* The expansion process typically takes a user written thing
|
|
| 799 | - L lspan ue
|
|
| 800 | - and returns
|
|
| 801 | - L lspan (XExpr (ExpandedThingRn (HSE { hse_ctxt = ue
|
|
| 802 | - , hse_exp = ee } ))
|
|
| 803 | - where `ee` is the expansion of the user written thing `ue`
|
|
| 804 | - |
|
| 805 | -* The type checker context has 3 key fields that describe the context:
|
|
| 806 | - TcLclCtxt { tcl_loc :: RealSrcSpan
|
|
| 807 | - , tcl_in_gen_code :: Bool
|
|
| 808 | - , tcl_err_ctxt :: ErrCtxtStack
|
|
| 809 | - , ... }
|
|
| 810 | - Note `tcl_loc` always points to a real place in the source code,
|
|
| 811 | - hence `RealSrcSpan`.
|
|
| 812 | - |
|
| 813 | - The `tcl_err_ctxt` is a stack of contexts, each saying something
|
|
| 814 | - like "In the expression: x+y" or "In second argument of `$` namely 'r { x=2 }'"
|
|
| 815 | - |
|
| 816 | - The `tcl_in_gen_code` is a boolean that keeps track of whether
|
|
| 817 | - the current expression being typechecked is compiler generated
|
|
| 818 | - or user generated.
|
|
| 819 | - |
|
| 820 | - INVARIANT: `tcl_loc` and `tcl_in_gen_code` are modified only in `setSrcSpan`.
|
|
| 821 | - |
|
| 822 | -* Now, when
|
|
| 823 | - tcMonoLExpr :: LHsExpr GhcRn -> ExpRhoType -> TcM (HsExpr GhcTc)
|
|
| 824 | - gets a located expression, it does 3 things:
|
|
| 825 | - (a) Calls `setSrcSpanA` to set the ambient source-code location
|
|
| 826 | - (b) Calls `addExprCtxt` to push a suitable `HsCtxt` on top of the `tcl_err_ctxt`.
|
|
| 827 | - (c) Calls `tcExpr` to typecheck the expression.
|
|
| 828 | - |
|
| 829 | -* In these calls, if the `span` is generated (see `isGeneratedSrcSpan`), then
|
|
| 830 | - - `setSrcSpanA` sets `tcl_in_gen_code` to `True`, and leaves `tcl_loc` unchanged
|
|
| 831 | - - `addExprCtxt` is a no-op if `tcl_in_gen_code` is True
|
|
| 832 | - The result is that `tcl_loc` has the span from the innermost /user/ tree node;
|
|
| 833 | - and the ErrCtxtStack in `tcl_err_ctxt` only has contexts arisign from user code.
|
|
| 834 | - |
|
| 835 | -* Note that inside an expansion we have sub-expressions from the original program.
|
|
| 836 | - As soon as we enter one of those, identified by a /user/ span, `setSrcSpanA` will
|
|
| 837 | - sets the `tcl_loc` to reflect that span, and switch off `tcl_in_gen_code`. Nice!
|
|
| 838 | --}
|
|
| 839 | - |
|
| 840 | 772 | tcHsExpansion :: HsExpansion GhcRn -> ExpRhoType -> TcM (HsExpr GhcTc)
|
| 841 | 773 | tcHsExpansion (HSE { hse_ctxt = o, hse_exp = e }) res_ty
|
| 842 | 774 | = do { e' <- tcMonoLExpr e res_ty
|
| ... | ... | @@ -844,31 +776,6 @@ tcHsExpansion (HSE { hse_ctxt = o, hse_exp = e }) res_ty |
| 844 | 776 | HSE { hse_ctxt = o, hse_exp = e' } }
|
| 845 | 777 | |
| 846 | 778 | |
| 847 | ----------------
|
|
| 848 | -tcExpand :: HsExpr GhcRn -> TcM (Maybe (HsExpansion GhcRn))
|
|
| 849 | -tcExpand e@(OpApp _ arg1 op arg2)
|
|
| 850 | - = return (Just (HSE { hse_ctxt = ExprCtxt e
|
|
| 851 | - , hse_exp = wrapGenSpan (unLoc $ mkHsApps op [arg1,arg2]) }))
|
|
| 852 | -tcExpand (XExpr (ExpandedThingRn hse))
|
|
| 853 | - = return (Just hse)
|
|
| 854 | - |
|
| 855 | -tcExpand e@(HsUntypedSplice splice_res _)
|
|
| 856 | --- See Note [Looking through Template Haskell splices in splitHsApps]
|
|
| 857 | - = do { fun <- getUntypedSpliceBody splice_res
|
|
| 858 | - ; return $ Just $
|
|
| 859 | - HSE { hse_ctxt = ExprCtxt e -- ToDo: right?
|
|
| 860 | - , hse_exp = L noSrcSpanA fun } } -- Span?
|
|
| 861 | -{-
|
|
| 862 | - where
|
|
| 863 | - lspan' :: SrcSpan
|
|
| 864 | - lspan' = case splice of
|
|
| 865 | - HsUntypedSpliceExpr _ (L l _) -> locA l -- l :: SrcAnn AnnListItem
|
|
| 866 | - HsQuasiQuote _ _ (L l _) -> locA l -- l :: SrcAnn NoEpAnns
|
|
| 867 | - (XUntypedSplice (HsImplicitLiftSplice _ _ _ (L l _))) -> locA l
|
|
| 868 | --}
|
|
| 869 | - |
|
| 870 | -tcExpand _ = return Nothing
|
|
| 871 | - |
|
| 872 | 779 | {-
|
| 873 | 780 | ************************************************************************
|
| 874 | 781 | * *
|
| ... | ... | @@ -9,7 +9,6 @@ import GHC.Tc.Types.BasicTypes( TcCompleteSig ) |
| 9 | 9 | import GHC.Tc.Types.Origin ( CtOrigin, FixedRuntimeRepContext )
|
| 10 | 10 | import GHC.Core.Type ( Mult )
|
| 11 | 11 | import GHC.Hs.Extension ( GhcRn, GhcTc )
|
| 12 | -import Data.Maybe( Maybe )
|
|
| 13 | 12 | |
| 14 | 13 | tcCheckPolyExpr, tcCheckPolyExprNC ::
|
| 15 | 14 | LHsExpr GhcRn
|
| ... | ... | @@ -40,8 +39,6 @@ tcInferExprSigma :: HsExpr GhcRn -> TcM (HsExpr GhcTc, TcSigmaType) |
| 40 | 39 | |
| 41 | 40 | tcInferExpr :: InferInstFlag -> LHsExpr GhcRn -> TcM (LHsExpr GhcTc, TcType)
|
| 42 | 41 | |
| 43 | -tcExpand :: HsExpr GhcRn -> TcM (Maybe (HsExpansion GhcRn))
|
|
| 44 | - |
|
| 45 | 42 | tcSyntaxOp :: CtOrigin
|
| 46 | 43 | -> SyntaxExprRn
|
| 47 | 44 | -> [SyntaxOpType] -- ^ shape of syntax operator arguments
|
| ... | ... | @@ -21,13 +21,14 @@ module GHC.Tc.Gen.Head |
| 21 | 21 | |
| 22 | 22 | , pprArgInst, addFunResCtxt ) where
|
| 23 | 23 | |
| 24 | -import {-# SOURCE #-} GHC.Tc.Gen.Expr( tcExpr, tcExpand, tcCheckPolyExprNC, tcPolyLExprSig )
|
|
| 24 | +import {-# SOURCE #-} GHC.Tc.Gen.Expr( tcExpr, tcCheckPolyExprNC, tcPolyLExprSig )
|
|
| 25 | 25 | |
| 26 | 26 | import GHC.Prelude
|
| 27 | 27 | import GHC.Hs
|
| 28 | 28 | import GHC.Hs.Syn.Type
|
| 29 | 29 | |
| 30 | 30 | import GHC.Tc.Gen.HsType
|
| 31 | +import GHC.Tc.Gen.Expand( tcExpand )
|
|
| 31 | 32 | import GHC.Tc.Gen.Bind( chooseInferredQuantifiers )
|
| 32 | 33 | import GHC.Tc.Gen.Sig( tcUserTypeSig, tcInstSig )
|
| 33 | 34 | import GHC.Tc.TyCl.PatSyn( patSynBuilderOcc )
|
| ... | ... | @@ -832,6 +832,7 @@ Library |
| 832 | 832 | GHC.Tc.Gen.Bind
|
| 833 | 833 | GHC.Tc.Gen.Default
|
| 834 | 834 | GHC.Tc.Gen.Do
|
| 835 | + GHC.Tc.Gen.Expand
|
|
| 835 | 836 | GHC.Tc.Gen.Export
|
| 836 | 837 | GHC.Tc.Gen.Expr
|
| 837 | 838 | GHC.Tc.Gen.Foreign
|